Merge tag 'for-linus-20190726' of git://git.kernel.dk/linux-block
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 26 Jul 2019 17:32:12 +0000 (10:32 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 26 Jul 2019 17:32:12 +0000 (10:32 -0700)
Pull block fixes from Jens Axboe:

 - Several io_uring fixes/improvements:
     - Blocking fix for O_DIRECT (me)
     - Latter page slowness for registered buffers (me)
     - Fix poll hang under certain conditions (me)
     - Defer sequence check fix for wrapped rings (Zhengyuan)
     - Mismatch in async inc/dec accounting (Zhengyuan)
     - Memory ordering issue that could cause stall (Zhengyuan)
      - Track sequential defer in bytes, not pages (Zhengyuan)

 - NVMe pull request from Christoph

 - Set of hang fixes for wbt (Josef)

 - Redundant error message kill for libahci (Ding)

 - Remove unused blk_mq_sched_started_request() and related ops (Marcos)

 - drbd dynamic alloc shash descriptor to reduce stack use (Arnd)

 - blkcg ->pd_stat() non-debug print (Tejun)

 - bcache memory leak fix (Wei)

 - Comment fix (Akinobu)

 - BFQ perf regression fix (Paolo)

* tag 'for-linus-20190726' of git://git.kernel.dk/linux-block: (24 commits)
  io_uring: ensure ->list is initialized for poll commands
  Revert "nvme-pci: don't create a read hctx mapping without read queues"
  nvme: fix multipath crash when ANA is deactivated
  nvme: fix memory leak caused by incorrect subsystem free
  nvme: ignore subnqn for ADATA SX6000LNP
  drbd: dynamically allocate shash descriptor
  block: blk-mq: Remove blk_mq_sched_started_request and started_request
  bcache: fix possible memory leak in bch_cached_dev_run()
  io_uring: track io length in async_list based on bytes
  io_uring: don't use iov_iter_advance() for fixed buffers
  block: properly handle IOCB_NOWAIT for async O_DIRECT IO
  blk-mq: allow REQ_NOWAIT to return an error inline
  io_uring: add a memory barrier before atomic_read
  rq-qos: use a mb for got_token
  rq-qos: set ourself TASK_UNINTERRUPTIBLE after we schedule
  rq-qos: don't reset has_sleepers on spurious wakeups
  rq-qos: fix missed wake-ups in rq_qos_throttle
  wait: add wq_has_single_sleeper helper
  block, bfq: check also in-flight I/O in dispatch plugging
  block: fix sysfs module parameters directory path in comment
  ...

3490 files changed:
.gitignore
CREDITS
Documentation/ABI/obsolete/sysfs-gpio
Documentation/ABI/removed/sysfs-class-rfkill
Documentation/ABI/stable/sysfs-class-rfkill
Documentation/ABI/stable/sysfs-devices-node
Documentation/ABI/testing/procfs-diskstats
Documentation/ABI/testing/sysfs-block
Documentation/ABI/testing/sysfs-block-device
Documentation/ABI/testing/sysfs-class-switchtec
Documentation/ABI/testing/sysfs-devices-system-cpu
Documentation/ABI/testing/sysfs-platform-asus-laptop
Documentation/ABI/testing/sysfs-platform-asus-wmi
Documentation/COPYING-logo [moved from Documentation/logo.txt with 100% similarity]
Documentation/DMA-API-HOWTO.txt
Documentation/EDID/howto.rst [deleted file]
Documentation/accelerators/ocxl.rst [deleted file]
Documentation/accounting/cgroupstats.rst [new file with mode: 0644]
Documentation/accounting/cgroupstats.txt [deleted file]
Documentation/accounting/delay-accounting.rst [new file with mode: 0644]
Documentation/accounting/delay-accounting.txt [deleted file]
Documentation/accounting/index.rst [new file with mode: 0644]
Documentation/accounting/psi.rst [new file with mode: 0644]
Documentation/accounting/psi.txt [deleted file]
Documentation/accounting/taskstats-struct.rst [new file with mode: 0644]
Documentation/accounting/taskstats-struct.txt [deleted file]
Documentation/accounting/taskstats.rst [new file with mode: 0644]
Documentation/accounting/taskstats.txt [deleted file]
Documentation/admin-guide/aoe/aoe.rst [new file with mode: 0644]
Documentation/admin-guide/aoe/autoload.sh [moved from Documentation/aoe/autoload.sh with 100% similarity]
Documentation/admin-guide/aoe/examples.rst [moved from Documentation/aoe/examples.rst with 100% similarity]
Documentation/admin-guide/aoe/index.rst [new file with mode: 0644]
Documentation/admin-guide/aoe/status.sh [moved from Documentation/aoe/status.sh with 100% similarity]
Documentation/admin-guide/aoe/todo.rst [moved from Documentation/aoe/todo.rst with 100% similarity]
Documentation/admin-guide/aoe/udev-install.sh [moved from Documentation/aoe/udev-install.sh with 100% similarity]
Documentation/admin-guide/aoe/udev.txt [new file with mode: 0644]
Documentation/admin-guide/blockdev/drbd/DRBD-8.3-data-packets.svg [moved from Documentation/blockdev/drbd/DRBD-8.3-data-packets.svg with 100% similarity]
Documentation/admin-guide/blockdev/drbd/DRBD-data-packets.svg [moved from Documentation/blockdev/drbd/DRBD-data-packets.svg with 100% similarity]
Documentation/admin-guide/blockdev/drbd/conn-states-8.dot [moved from Documentation/blockdev/drbd/conn-states-8.dot with 100% similarity]
Documentation/admin-guide/blockdev/drbd/data-structure-v9.rst [new file with mode: 0644]
Documentation/admin-guide/blockdev/drbd/disk-states-8.dot [moved from Documentation/blockdev/drbd/disk-states-8.dot with 100% similarity]
Documentation/admin-guide/blockdev/drbd/drbd-connection-state-overview.dot [moved from Documentation/blockdev/drbd/drbd-connection-state-overview.dot with 100% similarity]
Documentation/admin-guide/blockdev/drbd/figures.rst [new file with mode: 0644]
Documentation/admin-guide/blockdev/drbd/index.rst [new file with mode: 0644]
Documentation/admin-guide/blockdev/drbd/node-states-8.dot [new file with mode: 0644]
Documentation/admin-guide/blockdev/floppy.rst [new file with mode: 0644]
Documentation/admin-guide/blockdev/index.rst [new file with mode: 0644]
Documentation/admin-guide/blockdev/nbd.rst [new file with mode: 0644]
Documentation/admin-guide/blockdev/paride.rst [new file with mode: 0644]
Documentation/admin-guide/blockdev/ramdisk.rst [new file with mode: 0644]
Documentation/admin-guide/blockdev/zram.rst [new file with mode: 0644]
Documentation/admin-guide/btmrvl.rst [moved from Documentation/btmrvl.txt with 100% similarity]
Documentation/admin-guide/bug-hunting.rst
Documentation/admin-guide/cgroup-v1/blkio-controller.rst [moved from Documentation/cgroup-v1/blkio-controller.rst with 100% similarity]
Documentation/admin-guide/cgroup-v1/cgroups.rst [new file with mode: 0644]
Documentation/admin-guide/cgroup-v1/cpuacct.rst [moved from Documentation/cgroup-v1/cpuacct.rst with 100% similarity]
Documentation/admin-guide/cgroup-v1/cpusets.rst [new file with mode: 0644]
Documentation/admin-guide/cgroup-v1/devices.rst [moved from Documentation/cgroup-v1/devices.rst with 100% similarity]
Documentation/admin-guide/cgroup-v1/freezer-subsystem.rst [moved from Documentation/cgroup-v1/freezer-subsystem.rst with 100% similarity]
Documentation/admin-guide/cgroup-v1/hugetlb.rst [moved from Documentation/cgroup-v1/hugetlb.rst with 100% similarity]
Documentation/admin-guide/cgroup-v1/index.rst [new file with mode: 0644]
Documentation/admin-guide/cgroup-v1/memcg_test.rst [new file with mode: 0644]
Documentation/admin-guide/cgroup-v1/memory.rst [moved from Documentation/cgroup-v1/memory.rst with 100% similarity]
Documentation/admin-guide/cgroup-v1/net_cls.rst [moved from Documentation/cgroup-v1/net_cls.rst with 100% similarity]
Documentation/admin-guide/cgroup-v1/net_prio.rst [moved from Documentation/cgroup-v1/net_prio.rst with 100% similarity]
Documentation/admin-guide/cgroup-v1/pids.rst [moved from Documentation/cgroup-v1/pids.rst with 100% similarity]
Documentation/admin-guide/cgroup-v1/rdma.rst [moved from Documentation/cgroup-v1/rdma.rst with 100% similarity]
Documentation/admin-guide/cgroup-v2.rst
Documentation/admin-guide/clearing-warn-once.rst [moved from Documentation/clearing-warn-once.txt with 100% similarity]
Documentation/admin-guide/cpu-load.rst [moved from Documentation/cpu-load.txt with 100% similarity]
Documentation/admin-guide/cputopology.rst [moved from Documentation/cputopology.txt with 100% similarity]
Documentation/admin-guide/device-mapper/cache-policies.rst [moved from Documentation/device-mapper/cache-policies.rst with 100% similarity]
Documentation/admin-guide/device-mapper/cache.rst [moved from Documentation/device-mapper/cache.rst with 100% similarity]
Documentation/admin-guide/device-mapper/delay.rst [moved from Documentation/device-mapper/delay.rst with 100% similarity]
Documentation/admin-guide/device-mapper/dm-crypt.rst [moved from Documentation/device-mapper/dm-crypt.rst with 100% similarity]
Documentation/admin-guide/device-mapper/dm-dust.txt [moved from Documentation/device-mapper/dm-dust.txt with 100% similarity]
Documentation/admin-guide/device-mapper/dm-flakey.rst [moved from Documentation/device-mapper/dm-flakey.rst with 100% similarity]
Documentation/admin-guide/device-mapper/dm-init.rst [moved from Documentation/device-mapper/dm-init.rst with 100% similarity]
Documentation/admin-guide/device-mapper/dm-integrity.rst [moved from Documentation/device-mapper/dm-integrity.rst with 100% similarity]
Documentation/admin-guide/device-mapper/dm-io.rst [moved from Documentation/device-mapper/dm-io.rst with 100% similarity]
Documentation/admin-guide/device-mapper/dm-log.rst [moved from Documentation/device-mapper/dm-log.rst with 100% similarity]
Documentation/admin-guide/device-mapper/dm-queue-length.rst [moved from Documentation/device-mapper/dm-queue-length.rst with 100% similarity]
Documentation/admin-guide/device-mapper/dm-raid.rst [moved from Documentation/device-mapper/dm-raid.rst with 100% similarity]
Documentation/admin-guide/device-mapper/dm-service-time.rst [moved from Documentation/device-mapper/dm-service-time.rst with 100% similarity]
Documentation/admin-guide/device-mapper/dm-uevent.rst [moved from Documentation/device-mapper/dm-uevent.rst with 100% similarity]
Documentation/admin-guide/device-mapper/dm-zoned.rst [moved from Documentation/device-mapper/dm-zoned.rst with 100% similarity]
Documentation/admin-guide/device-mapper/era.rst [moved from Documentation/device-mapper/era.rst with 100% similarity]
Documentation/admin-guide/device-mapper/index.rst [new file with mode: 0644]
Documentation/admin-guide/device-mapper/kcopyd.rst [moved from Documentation/device-mapper/kcopyd.rst with 100% similarity]
Documentation/admin-guide/device-mapper/linear.rst [moved from Documentation/device-mapper/linear.rst with 100% similarity]
Documentation/admin-guide/device-mapper/log-writes.rst [moved from Documentation/device-mapper/log-writes.rst with 100% similarity]
Documentation/admin-guide/device-mapper/persistent-data.rst [moved from Documentation/device-mapper/persistent-data.rst with 100% similarity]
Documentation/admin-guide/device-mapper/snapshot.rst [moved from Documentation/device-mapper/snapshot.rst with 100% similarity]
Documentation/admin-guide/device-mapper/statistics.rst [new file with mode: 0644]
Documentation/admin-guide/device-mapper/striped.rst [moved from Documentation/device-mapper/striped.rst with 100% similarity]
Documentation/admin-guide/device-mapper/switch.rst [moved from Documentation/device-mapper/switch.rst with 100% similarity]
Documentation/admin-guide/device-mapper/thin-provisioning.rst [moved from Documentation/device-mapper/thin-provisioning.rst with 100% similarity]
Documentation/admin-guide/device-mapper/unstriped.rst [moved from Documentation/device-mapper/unstriped.rst with 100% similarity]
Documentation/admin-guide/device-mapper/verity.rst [moved from Documentation/device-mapper/verity.rst with 100% similarity]
Documentation/admin-guide/device-mapper/writecache.rst [moved from Documentation/device-mapper/writecache.rst with 100% similarity]
Documentation/admin-guide/device-mapper/zero.rst [moved from Documentation/device-mapper/zero.rst with 100% similarity]
Documentation/admin-guide/efi-stub.rst [moved from Documentation/efi-stub.txt with 100% similarity]
Documentation/admin-guide/gpio/index.rst [new file with mode: 0644]
Documentation/admin-guide/gpio/sysfs.rst [moved from Documentation/gpio/sysfs.rst with 100% similarity]
Documentation/admin-guide/highuid.rst [moved from Documentation/highuid.txt with 100% similarity]
Documentation/admin-guide/hw-vuln/l1tf.rst
Documentation/admin-guide/hw_random.rst [moved from Documentation/hw_random.txt with 100% similarity]
Documentation/admin-guide/index.rst
Documentation/admin-guide/iostats.rst [moved from Documentation/iostats.txt with 100% similarity]
Documentation/admin-guide/kdump/gdbmacros.txt [moved from Documentation/kdump/gdbmacros.txt with 100% similarity]
Documentation/admin-guide/kdump/index.rst [new file with mode: 0644]
Documentation/admin-guide/kdump/kdump.rst [moved from Documentation/kdump/kdump.rst with 100% similarity]
Documentation/admin-guide/kdump/vmcoreinfo.rst [moved from Documentation/kdump/vmcoreinfo.rst with 100% similarity]
Documentation/admin-guide/kernel-parameters.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/admin-guide/kernel-per-CPU-kthreads.rst [new file with mode: 0644]
Documentation/admin-guide/laptops/asus-laptop.rst [new file with mode: 0644]
Documentation/admin-guide/laptops/disk-shock-protection.rst [new file with mode: 0644]
Documentation/admin-guide/laptops/index.rst [new file with mode: 0644]
Documentation/admin-guide/laptops/laptop-mode.rst [new file with mode: 0644]
Documentation/admin-guide/laptops/lg-laptop.rst [new file with mode: 0644]
Documentation/admin-guide/laptops/sony-laptop.rst [new file with mode: 0644]
Documentation/admin-guide/laptops/sonypi.rst [new file with mode: 0644]
Documentation/admin-guide/laptops/thinkpad-acpi.rst [new file with mode: 0644]
Documentation/admin-guide/laptops/toshiba_haps.rst [new file with mode: 0644]
Documentation/admin-guide/lcd-panel-cgram.rst [new file with mode: 0644]
Documentation/admin-guide/ldm.rst [moved from Documentation/ldm.txt with 100% similarity]
Documentation/admin-guide/lockup-watchdogs.rst [moved from Documentation/lockup-watchdogs.txt with 100% similarity]
Documentation/admin-guide/mm/cma_debugfs.rst [new file with mode: 0644]
Documentation/admin-guide/mm/index.rst
Documentation/admin-guide/mm/ksm.rst
Documentation/admin-guide/mm/numa_memory_policy.rst
Documentation/admin-guide/namespaces/compatibility-list.rst [new file with mode: 0644]
Documentation/admin-guide/namespaces/index.rst [new file with mode: 0644]
Documentation/admin-guide/namespaces/resource-control.rst [new file with mode: 0644]
Documentation/admin-guide/numastat.rst [moved from Documentation/numastat.txt with 100% similarity]
Documentation/admin-guide/perf/arm-ccn.rst [new file with mode: 0644]
Documentation/admin-guide/perf/arm_dsu_pmu.rst [new file with mode: 0644]
Documentation/admin-guide/perf/hisi-pmu.rst [new file with mode: 0644]
Documentation/admin-guide/perf/index.rst [new file with mode: 0644]
Documentation/admin-guide/perf/qcom_l2_pmu.rst [new file with mode: 0644]
Documentation/admin-guide/perf/qcom_l3_pmu.rst [new file with mode: 0644]
Documentation/admin-guide/perf/thunderx2-pmu.rst [new file with mode: 0644]
Documentation/admin-guide/perf/xgene-pmu.rst [new file with mode: 0644]
Documentation/admin-guide/pnp.rst [moved from Documentation/pnp.txt with 100% similarity]
Documentation/admin-guide/rapidio.rst [moved from Documentation/driver-api/rapidio.rst with 100% similarity]
Documentation/admin-guide/rtc.rst [moved from Documentation/rtc.txt with 100% similarity]
Documentation/admin-guide/svga.rst [moved from Documentation/svga.txt with 100% similarity]
Documentation/admin-guide/sysctl/abi.rst [new file with mode: 0644]
Documentation/admin-guide/sysctl/fs.rst [new file with mode: 0644]
Documentation/admin-guide/sysctl/index.rst [new file with mode: 0644]
Documentation/admin-guide/sysctl/kernel.rst [new file with mode: 0644]
Documentation/admin-guide/sysctl/net.rst [new file with mode: 0644]
Documentation/admin-guide/sysctl/sunrpc.rst [new file with mode: 0644]
Documentation/admin-guide/sysctl/user.rst [new file with mode: 0644]
Documentation/admin-guide/sysctl/vm.rst [new file with mode: 0644]
Documentation/admin-guide/video-output.rst [moved from Documentation/video-output.txt with 100% similarity]
Documentation/admin-guide/xfs.rst [new file with mode: 0644]
Documentation/aoe/aoe.rst [deleted file]
Documentation/aoe/index.rst [deleted file]
Documentation/aoe/udev.txt [deleted file]
Documentation/arm/Booting [deleted file]
Documentation/arm/IXP4xx [deleted file]
Documentation/arm/Interrupts [deleted file]
Documentation/arm/Marvell/README [deleted file]
Documentation/arm/Microchip/README [deleted file]
Documentation/arm/Netwinder [deleted file]
Documentation/arm/OMAP/DSS [deleted file]
Documentation/arm/OMAP/README [deleted file]
Documentation/arm/OMAP/omap_pm [deleted file]
Documentation/arm/Porting [deleted file]
Documentation/arm/README [deleted file]
Documentation/arm/SA1100/ADSBitsy [deleted file]
Documentation/arm/SA1100/Assabet [deleted file]
Documentation/arm/SA1100/Brutus [deleted file]
Documentation/arm/SA1100/CERF [deleted file]
Documentation/arm/SA1100/FreeBird [deleted file]
Documentation/arm/SA1100/GraphicsClient [deleted file]
Documentation/arm/SA1100/GraphicsMaster [deleted file]
Documentation/arm/SA1100/HUW_WEBPANEL [deleted file]
Documentation/arm/SA1100/Itsy [deleted file]
Documentation/arm/SA1100/LART [deleted file]
Documentation/arm/SA1100/PLEB [deleted file]
Documentation/arm/SA1100/Pangolin [deleted file]
Documentation/arm/SA1100/Tifon [deleted file]
Documentation/arm/SA1100/Yopy [deleted file]
Documentation/arm/SA1100/empeg [deleted file]
Documentation/arm/SA1100/nanoEngine [deleted file]
Documentation/arm/SA1100/serial_UART [deleted file]
Documentation/arm/SPEAr/overview.txt [deleted file]
Documentation/arm/Samsung-S3C24XX/CPUfreq.txt [deleted file]
Documentation/arm/Samsung-S3C24XX/EB2410ITX.txt [deleted file]
Documentation/arm/Samsung-S3C24XX/GPIO.txt [deleted file]
Documentation/arm/Samsung-S3C24XX/H1940.txt [deleted file]
Documentation/arm/Samsung-S3C24XX/NAND.txt [deleted file]
Documentation/arm/Samsung-S3C24XX/Overview.txt [deleted file]
Documentation/arm/Samsung-S3C24XX/S3C2412.txt [deleted file]
Documentation/arm/Samsung-S3C24XX/S3C2413.txt [deleted file]
Documentation/arm/Samsung-S3C24XX/SMDK2440.txt [deleted file]
Documentation/arm/Samsung-S3C24XX/Suspend.txt [deleted file]
Documentation/arm/Samsung-S3C24XX/USB-Host.txt [deleted file]
Documentation/arm/Samsung/Bootloader-interface.txt [deleted file]
Documentation/arm/Samsung/GPIO.txt [deleted file]
Documentation/arm/Samsung/Overview.txt [deleted file]
Documentation/arm/Setup [deleted file]
Documentation/arm/VFP/release-notes.txt [deleted file]
Documentation/arm/arm.rst [new file with mode: 0644]
Documentation/arm/booting.rst [new file with mode: 0644]
Documentation/arm/cluster-pm-race-avoidance.rst [new file with mode: 0644]
Documentation/arm/cluster-pm-race-avoidance.txt [deleted file]
Documentation/arm/firmware.rst [new file with mode: 0644]
Documentation/arm/firmware.txt [deleted file]
Documentation/arm/index.rst [new file with mode: 0644]
Documentation/arm/interrupts.rst [new file with mode: 0644]
Documentation/arm/ixp4xx.rst [new file with mode: 0644]
Documentation/arm/kernel_mode_neon.rst [new file with mode: 0644]
Documentation/arm/kernel_mode_neon.txt [deleted file]
Documentation/arm/kernel_user_helpers.rst [new file with mode: 0644]
Documentation/arm/kernel_user_helpers.txt [deleted file]
Documentation/arm/keystone/Overview.txt [deleted file]
Documentation/arm/keystone/knav-qmss.rst [new file with mode: 0644]
Documentation/arm/keystone/knav-qmss.txt [deleted file]
Documentation/arm/keystone/overview.rst [new file with mode: 0644]
Documentation/arm/marvel.rst [new file with mode: 0644]
Documentation/arm/mem_alignment [deleted file]
Documentation/arm/mem_alignment.rst [new file with mode: 0644]
Documentation/arm/memory.rst [new file with mode: 0644]
Documentation/arm/memory.txt [deleted file]
Documentation/arm/microchip.rst [new file with mode: 0644]
Documentation/arm/netwinder.rst [new file with mode: 0644]
Documentation/arm/nwfpe/NOTES [deleted file]
Documentation/arm/nwfpe/README [deleted file]
Documentation/arm/nwfpe/README.FPE [deleted file]
Documentation/arm/nwfpe/TODO [deleted file]
Documentation/arm/nwfpe/index.rst [new file with mode: 0644]
Documentation/arm/nwfpe/netwinder-fpe.rst [new file with mode: 0644]
Documentation/arm/nwfpe/notes.rst [new file with mode: 0644]
Documentation/arm/nwfpe/nwfpe.rst [new file with mode: 0644]
Documentation/arm/nwfpe/todo.rst [new file with mode: 0644]
Documentation/arm/omap/dss.rst [new file with mode: 0644]
Documentation/arm/omap/index.rst [new file with mode: 0644]
Documentation/arm/omap/omap.rst [new file with mode: 0644]
Documentation/arm/omap/omap_pm.rst [new file with mode: 0644]
Documentation/arm/porting.rst [new file with mode: 0644]
Documentation/arm/pxa/mfp.rst [new file with mode: 0644]
Documentation/arm/pxa/mfp.txt [deleted file]
Documentation/arm/sa1100/adsbitsy.rst [new file with mode: 0644]
Documentation/arm/sa1100/assabet.rst [new file with mode: 0644]
Documentation/arm/sa1100/brutus.rst [new file with mode: 0644]
Documentation/arm/sa1100/cerf.rst [new file with mode: 0644]
Documentation/arm/sa1100/freebird.rst [new file with mode: 0644]
Documentation/arm/sa1100/graphicsclient.rst [new file with mode: 0644]
Documentation/arm/sa1100/graphicsmaster.rst [new file with mode: 0644]
Documentation/arm/sa1100/huw_webpanel.rst [new file with mode: 0644]
Documentation/arm/sa1100/index.rst [new file with mode: 0644]
Documentation/arm/sa1100/itsy.rst [new file with mode: 0644]
Documentation/arm/sa1100/lart.rst [new file with mode: 0644]
Documentation/arm/sa1100/nanoengine.rst [new file with mode: 0644]
Documentation/arm/sa1100/pangolin.rst [new file with mode: 0644]
Documentation/arm/sa1100/pleb.rst [new file with mode: 0644]
Documentation/arm/sa1100/serial_uart.rst [new file with mode: 0644]
Documentation/arm/sa1100/tifon.rst [new file with mode: 0644]
Documentation/arm/sa1100/yopy.rst [new file with mode: 0644]
Documentation/arm/samsung-s3c24xx/cpufreq.rst [new file with mode: 0644]
Documentation/arm/samsung-s3c24xx/eb2410itx.rst [new file with mode: 0644]
Documentation/arm/samsung-s3c24xx/gpio.rst [new file with mode: 0644]
Documentation/arm/samsung-s3c24xx/h1940.rst [new file with mode: 0644]
Documentation/arm/samsung-s3c24xx/index.rst [new file with mode: 0644]
Documentation/arm/samsung-s3c24xx/nand.rst [new file with mode: 0644]
Documentation/arm/samsung-s3c24xx/overview.rst [new file with mode: 0644]
Documentation/arm/samsung-s3c24xx/s3c2412.rst [new file with mode: 0644]
Documentation/arm/samsung-s3c24xx/s3c2413.rst [new file with mode: 0644]
Documentation/arm/samsung-s3c24xx/smdk2440.rst [new file with mode: 0644]
Documentation/arm/samsung-s3c24xx/suspend.rst [new file with mode: 0644]
Documentation/arm/samsung-s3c24xx/usb-host.rst [new file with mode: 0644]
Documentation/arm/samsung/bootloader-interface.rst [new file with mode: 0644]
Documentation/arm/samsung/clksrc-change-registers.awk [moved from Documentation/arm/Samsung/clksrc-change-registers.awk with 100% similarity]
Documentation/arm/samsung/gpio.rst [new file with mode: 0644]
Documentation/arm/samsung/index.rst [new file with mode: 0644]
Documentation/arm/samsung/overview.rst [new file with mode: 0644]
Documentation/arm/setup.rst [new file with mode: 0644]
Documentation/arm/sh-mobile/.gitignore [moved from Documentation/arm/SH-Mobile/.gitignore with 100% similarity]
Documentation/arm/spear/overview.rst [new file with mode: 0644]
Documentation/arm/sti/overview.rst [new file with mode: 0644]
Documentation/arm/sti/overview.txt [deleted file]
Documentation/arm/sti/stih407-overview.rst [new file with mode: 0644]
Documentation/arm/sti/stih407-overview.txt [deleted file]
Documentation/arm/sti/stih415-overview.rst [new file with mode: 0644]
Documentation/arm/sti/stih415-overview.txt [deleted file]
Documentation/arm/sti/stih416-overview.rst [new file with mode: 0644]
Documentation/arm/sti/stih416-overview.txt [deleted file]
Documentation/arm/sti/stih418-overview.rst [new file with mode: 0644]
Documentation/arm/sti/stih418-overview.txt [deleted file]
Documentation/arm/stm32/overview.rst
Documentation/arm/stm32/stm32f429-overview.rst
Documentation/arm/stm32/stm32f746-overview.rst
Documentation/arm/stm32/stm32f769-overview.rst
Documentation/arm/stm32/stm32h743-overview.rst
Documentation/arm/stm32/stm32mp157-overview.rst
Documentation/arm/sunxi.rst [new file with mode: 0644]
Documentation/arm/sunxi/README [deleted file]
Documentation/arm/sunxi/clocks.rst [new file with mode: 0644]
Documentation/arm/sunxi/clocks.txt [deleted file]
Documentation/arm/swp_emulation [deleted file]
Documentation/arm/swp_emulation.rst [new file with mode: 0644]
Documentation/arm/tcm.rst [new file with mode: 0644]
Documentation/arm/tcm.txt [deleted file]
Documentation/arm/uefi.rst [new file with mode: 0644]
Documentation/arm/uefi.txt [deleted file]
Documentation/arm/vfp/release-notes.rst [new file with mode: 0644]
Documentation/arm/vlocks.rst [new file with mode: 0644]
Documentation/arm/vlocks.txt [deleted file]
Documentation/arm64/index.rst
Documentation/auxdisplay/lcd-panel-cgram.txt [deleted file]
Documentation/backlight/lp855x-driver.txt [deleted file]
Documentation/block/bfq-iosched.rst [new file with mode: 0644]
Documentation/block/bfq-iosched.txt [deleted file]
Documentation/block/biodoc.rst [new file with mode: 0644]
Documentation/block/biodoc.txt [deleted file]
Documentation/block/biovecs.rst [new file with mode: 0644]
Documentation/block/biovecs.txt [deleted file]
Documentation/block/capability.rst [new file with mode: 0644]
Documentation/block/capability.txt [deleted file]
Documentation/block/cmdline-partition.rst [new file with mode: 0644]
Documentation/block/cmdline-partition.txt [deleted file]
Documentation/block/data-integrity.rst [new file with mode: 0644]
Documentation/block/data-integrity.txt [deleted file]
Documentation/block/deadline-iosched.rst [new file with mode: 0644]
Documentation/block/deadline-iosched.txt [deleted file]
Documentation/block/index.rst [new file with mode: 0644]
Documentation/block/ioprio.rst [new file with mode: 0644]
Documentation/block/ioprio.txt [deleted file]
Documentation/block/kyber-iosched.rst [new file with mode: 0644]
Documentation/block/kyber-iosched.txt [deleted file]
Documentation/block/null_blk.rst [new file with mode: 0644]
Documentation/block/null_blk.txt [deleted file]
Documentation/block/pr.rst [new file with mode: 0644]
Documentation/block/pr.txt [deleted file]
Documentation/block/queue-sysfs.rst [new file with mode: 0644]
Documentation/block/queue-sysfs.txt [deleted file]
Documentation/block/request.rst [new file with mode: 0644]
Documentation/block/request.txt [deleted file]
Documentation/block/stat.rst [new file with mode: 0644]
Documentation/block/stat.txt [deleted file]
Documentation/block/switching-sched.rst [new file with mode: 0644]
Documentation/block/switching-sched.txt [deleted file]
Documentation/block/writeback_cache_control.rst [new file with mode: 0644]
Documentation/block/writeback_cache_control.txt [deleted file]
Documentation/blockdev/drbd/README.txt [deleted file]
Documentation/blockdev/drbd/data-structure-v9.txt [deleted file]
Documentation/blockdev/drbd/node-states-8.dot [deleted file]
Documentation/blockdev/floppy.txt [deleted file]
Documentation/blockdev/nbd.txt [deleted file]
Documentation/blockdev/paride.txt [deleted file]
Documentation/blockdev/ramdisk.txt [deleted file]
Documentation/blockdev/zram.txt [deleted file]
Documentation/bus-devices/ti-gpmc.txt [deleted file]
Documentation/cdrom/index.rst
Documentation/cgroup-v1/cgroups.rst [deleted file]
Documentation/cgroup-v1/cpusets.rst [deleted file]
Documentation/cgroup-v1/index.rst [deleted file]
Documentation/cgroup-v1/memcg_test.rst [deleted file]
Documentation/cma/debugfs.txt [deleted file]
Documentation/connector/connector.txt [deleted file]
Documentation/console/console.txt [deleted file]
Documentation/core-api/gcc-plugins.rst [moved from Documentation/gcc-plugins.txt with 100% similarity]
Documentation/core-api/index.rst
Documentation/core-api/printk-formats.rst
Documentation/dev-tools/sparse.rst
Documentation/device-mapper/index.rst [deleted file]
Documentation/device-mapper/statistics.rst [deleted file]
Documentation/devicetree/bindings/arm/amlogic.txt [deleted file]
Documentation/devicetree/bindings/arm/amlogic.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/amlogic/amlogic,meson-gx-ao-secure.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/arm,scmi.txt
Documentation/devicetree/bindings/arm/atmel-at91.txt [deleted file]
Documentation/devicetree/bindings/arm/atmel-at91.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/emtrion.txt [deleted file]
Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt
Documentation/devicetree/bindings/arm/fsl.yaml
Documentation/devicetree/bindings/arm/mediatek.txt [deleted file]
Documentation/devicetree/bindings/arm/mediatek.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/mediatek/mediatek,audsys.txt
Documentation/devicetree/bindings/arm/omap/omap.txt
Documentation/devicetree/bindings/arm/renesas.yaml
Documentation/devicetree/bindings/arm/rockchip.yaml
Documentation/devicetree/bindings/arm/stm32/mlahb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/stm32/stm32.txt [deleted file]
Documentation/devicetree/bindings/arm/stm32/stm32.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/sunxi.yaml
Documentation/devicetree/bindings/arm/ti/k3.txt
Documentation/devicetree/bindings/arm/xen.txt
Documentation/devicetree/bindings/bus/allwinner,sun8i-a23-rsb.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/bus/sunxi-rsb.txt [deleted file]
Documentation/devicetree/bindings/clock/allwinner,sun4i-a10-ccu.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt
Documentation/devicetree/bindings/clock/at91-clock.txt
Documentation/devicetree/bindings/clock/brcm,bcm63xx-clocks.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/cirrus,lochnagar.txt
Documentation/devicetree/bindings/clock/mvebu-core-clock.txt
Documentation/devicetree/bindings/clock/qcom,gpucc.txt
Documentation/devicetree/bindings/clock/renesas,r9a06g032-sysctrl.txt
Documentation/devicetree/bindings/clock/silabs,si5341.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/sunxi-ccu.txt [deleted file]
Documentation/devicetree/bindings/csky/pmu.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/bridge/renesas,dw-hdmi.txt
Documentation/devicetree/bindings/dma/8250_mtk_dma.txt [deleted file]
Documentation/devicetree/bindings/dma/arm-pl330.txt
Documentation/devicetree/bindings/dma/fsl-edma.txt
Documentation/devicetree/bindings/dma/fsl-qdma.txt
Documentation/devicetree/bindings/dma/mtk-uart-apdma.txt [new file with mode: 0644]
Documentation/devicetree/bindings/dma/sun6i-dma.txt
Documentation/devicetree/bindings/gpu/arm,mali-midgard.txt
Documentation/devicetree/bindings/gpu/arm,mali-utgard.txt
Documentation/devicetree/bindings/hwlock/omap-hwspinlock.txt
Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml
Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml
Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt
Documentation/devicetree/bindings/misc/fsl,dpaa2-console.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml
Documentation/devicetree/bindings/mtd/nand-controller.yaml
Documentation/devicetree/bindings/net/can/rcar_can.txt
Documentation/devicetree/bindings/net/can/rcar_canfd.txt
Documentation/devicetree/bindings/phy/phy-bindings.txt
Documentation/devicetree/bindings/phy/phy-pxa-usb.txt
Documentation/devicetree/bindings/pinctrl/aspeed,ast2400-pinctrl.yaml
Documentation/devicetree/bindings/pinctrl/aspeed,ast2500-pinctrl.yaml
Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml
Documentation/devicetree/bindings/power/qcom,rpmpd.txt
Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/pwm-sun4i.txt [deleted file]
Documentation/devicetree/bindings/remoteproc/qcom,adsp-pil.txt [deleted file]
Documentation/devicetree/bindings/remoteproc/qcom,hexagon-v56.txt [new file with mode: 0644]
Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/reset/bitmain,bm1880-reset.txt [new file with mode: 0644]
Documentation/devicetree/bindings/reset/fsl,imx7-src.txt
Documentation/devicetree/bindings/riscv/cpus.yaml
Documentation/devicetree/bindings/rtc/allwinner,sun4i-a10-rtc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/rtc.txt
Documentation/devicetree/bindings/rtc/rtc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/sun6i-rtc.txt [deleted file]
Documentation/devicetree/bindings/rtc/sunxi-rtc.txt [deleted file]
Documentation/devicetree/bindings/rtc/trivial-rtc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/serial/omap_serial.txt
Documentation/devicetree/bindings/soc/amlogic/amlogic,canvas.txt
Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.txt [new file with mode: 0644]
Documentation/devicetree/bindings/soc/qcom/qcom,apr.txt
Documentation/devicetree/bindings/soc/qcom/qcom,glink.txt
Documentation/devicetree/bindings/spi/allwinner,sun4i-a10-spi.yaml
Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
Documentation/devicetree/bindings/timer/renesas,cmt.txt
Documentation/devicetree/bindings/usb/s3c2410-usb.txt
Documentation/devicetree/bindings/vendor-prefixes.yaml
Documentation/devicetree/bindings/virtio/iommu.txt [new file with mode: 0644]
Documentation/devicetree/bindings/virtio/mmio.txt
Documentation/devicetree/bindings/watchdog/fsl-imx-sc-wdt.txt [deleted file]
Documentation/devicetree/bindings/watchdog/renesas,wdt.txt [moved from Documentation/devicetree/bindings/watchdog/renesas-wdt.txt with 100% similarity]
Documentation/devicetree/bindings/watchdog/sunxi-wdt.txt
Documentation/devicetree/booting-without-of.txt
Documentation/dontdiff
Documentation/driver-api/backlight/lp855x-driver.rst [new file with mode: 0644]
Documentation/driver-api/bt8xxgpio.rst [moved from Documentation/bt8xxgpio.txt with 100% similarity]
Documentation/driver-api/connector.rst [new file with mode: 0644]
Documentation/driver-api/console.rst [new file with mode: 0644]
Documentation/driver-api/dcdbas.rst [moved from Documentation/dcdbas.txt with 100% similarity]
Documentation/driver-api/dell_rbu.rst [moved from Documentation/dell_rbu.txt with 100% similarity]
Documentation/driver-api/dmaengine/dmatest.rst
Documentation/driver-api/driver-model/binding.rst [moved from Documentation/driver-model/binding.rst with 100% similarity]
Documentation/driver-api/driver-model/bus.rst [moved from Documentation/driver-model/bus.rst with 100% similarity]
Documentation/driver-api/driver-model/class.rst [moved from Documentation/driver-model/class.rst with 100% similarity]
Documentation/driver-api/driver-model/design-patterns.rst [moved from Documentation/driver-model/design-patterns.rst with 100% similarity]
Documentation/driver-api/driver-model/device.rst [moved from Documentation/driver-model/device.rst with 100% similarity]
Documentation/driver-api/driver-model/devres.rst [new file with mode: 0644]
Documentation/driver-api/driver-model/driver.rst [moved from Documentation/driver-model/driver.rst with 100% similarity]
Documentation/driver-api/driver-model/index.rst [new file with mode: 0644]
Documentation/driver-api/driver-model/overview.rst [moved from Documentation/driver-model/overview.rst with 100% similarity]
Documentation/driver-api/driver-model/platform.rst [moved from Documentation/driver-model/platform.rst with 100% similarity]
Documentation/driver-api/driver-model/porting.rst [new file with mode: 0644]
Documentation/driver-api/early-userspace/buffer-format.rst [new file with mode: 0644]
Documentation/driver-api/early-userspace/early_userspace_support.rst [new file with mode: 0644]
Documentation/driver-api/early-userspace/index.rst [new file with mode: 0644]
Documentation/driver-api/edid.rst [new file with mode: 0644]
Documentation/driver-api/eisa.rst [new file with mode: 0644]
Documentation/driver-api/gpio/driver.rst
Documentation/driver-api/index.rst
Documentation/driver-api/interconnect.rst [new file with mode: 0644]
Documentation/driver-api/isa.rst [moved from Documentation/isa.txt with 100% similarity]
Documentation/driver-api/isapnp.rst [moved from Documentation/isapnp.txt with 100% similarity]
Documentation/driver-api/lightnvm-pblk.rst [moved from Documentation/lightnvm/pblk.txt with 100% similarity]
Documentation/driver-api/md/index.rst [new file with mode: 0644]
Documentation/driver-api/md/md-cluster.rst [new file with mode: 0644]
Documentation/driver-api/md/raid5-cache.rst [new file with mode: 0644]
Documentation/driver-api/md/raid5-ppl.rst [new file with mode: 0644]
Documentation/driver-api/memory-devices/index.rst [new file with mode: 0644]
Documentation/driver-api/memory-devices/ti-emif.rst [new file with mode: 0644]
Documentation/driver-api/memory-devices/ti-gpmc.rst [new file with mode: 0644]
Documentation/driver-api/men-chameleon-bus.rst [moved from Documentation/men-chameleon-bus.txt with 100% similarity]
Documentation/driver-api/mmc/index.rst [new file with mode: 0644]
Documentation/driver-api/mmc/mmc-async-req.rst [new file with mode: 0644]
Documentation/driver-api/mmc/mmc-dev-attrs.rst [new file with mode: 0644]
Documentation/driver-api/mmc/mmc-dev-parts.rst [new file with mode: 0644]
Documentation/driver-api/mmc/mmc-tools.rst [new file with mode: 0644]
Documentation/driver-api/mtd/index.rst [new file with mode: 0644]
Documentation/driver-api/mtd/intel-spi.rst [new file with mode: 0644]
Documentation/driver-api/mtd/nand_ecc.rst [new file with mode: 0644]
Documentation/driver-api/mtd/spi-nor.rst [new file with mode: 0644]
Documentation/driver-api/nfc/index.rst [new file with mode: 0644]
Documentation/driver-api/nfc/nfc-hci.rst [new file with mode: 0644]
Documentation/driver-api/nfc/nfc-pn544.rst [new file with mode: 0644]
Documentation/driver-api/ntb.rst [new file with mode: 0644]
Documentation/driver-api/nvdimm/btt.rst [new file with mode: 0644]
Documentation/driver-api/nvdimm/index.rst [new file with mode: 0644]
Documentation/driver-api/nvdimm/nvdimm.rst [new file with mode: 0644]
Documentation/driver-api/nvdimm/security.rst [new file with mode: 0644]
Documentation/driver-api/nvmem.rst [new file with mode: 0644]
Documentation/driver-api/parport-lowlevel.rst [moved from Documentation/parport-lowlevel.txt with 100% similarity]
Documentation/driver-api/phy/index.rst [new file with mode: 0644]
Documentation/driver-api/phy/phy.rst [moved from Documentation/phy.txt with 100% similarity]
Documentation/driver-api/phy/samsung-usb2.rst [new file with mode: 0644]
Documentation/driver-api/pps.rst
Documentation/driver-api/pti_intel_mid.rst [new file with mode: 0644]
Documentation/driver-api/ptp.rst
Documentation/driver-api/pwm.rst [moved from Documentation/pwm.txt with 100% similarity]
Documentation/driver-api/rapidio/index.rst [new file with mode: 0644]
Documentation/driver-api/rapidio/mport_cdev.rst [new file with mode: 0644]
Documentation/driver-api/rapidio/rapidio.rst [new file with mode: 0644]
Documentation/driver-api/rapidio/rio_cm.rst [new file with mode: 0644]
Documentation/driver-api/rapidio/sysfs.rst [new file with mode: 0644]
Documentation/driver-api/rapidio/tsi721.rst [new file with mode: 0644]
Documentation/driver-api/rfkill.rst [moved from Documentation/rfkill.txt with 100% similarity]
Documentation/driver-api/serial/cyclades_z.rst [moved from Documentation/serial/cyclades_z.rst with 100% similarity]
Documentation/driver-api/serial/driver.rst [new file with mode: 0644]
Documentation/driver-api/serial/index.rst [new file with mode: 0644]
Documentation/driver-api/serial/moxa-smartio.rst [moved from Documentation/serial/moxa-smartio.rst with 100% similarity]
Documentation/driver-api/serial/n_gsm.rst [moved from Documentation/serial/n_gsm.rst with 100% similarity]
Documentation/driver-api/serial/rocket.rst [moved from Documentation/serial/rocket.rst with 100% similarity]
Documentation/driver-api/serial/serial-iso7816.rst [moved from Documentation/serial/serial-iso7816.rst with 100% similarity]
Documentation/driver-api/serial/serial-rs485.rst [moved from Documentation/serial/serial-rs485.rst with 100% similarity]
Documentation/driver-api/serial/tty.rst [moved from Documentation/serial/tty.rst with 100% similarity]
Documentation/driver-api/sgi-ioc4.rst [moved from Documentation/sgi-ioc4.txt with 100% similarity]
Documentation/driver-api/sm501.rst [moved from Documentation/SM501.txt with 100% similarity]
Documentation/driver-api/smsc_ece1099.rst [moved from Documentation/smsc_ece1099.txt with 100% similarity]
Documentation/driver-api/switchtec.rst [new file with mode: 0644]
Documentation/driver-api/sync_file.rst [moved from Documentation/sync_file.txt with 100% similarity]
Documentation/driver-api/vfio-mediated-device.rst [new file with mode: 0644]
Documentation/driver-api/vfio.rst [moved from Documentation/vfio.txt with 100% similarity]
Documentation/driver-api/xilinx/eemi.rst [moved from Documentation/xilinx/eemi.rst with 100% similarity]
Documentation/driver-api/xilinx/index.rst [new file with mode: 0644]
Documentation/driver-api/xillybus.rst [moved from Documentation/xillybus.txt with 100% similarity]
Documentation/driver-api/zorro.rst [moved from Documentation/zorro.txt with 100% similarity]
Documentation/driver-model/devres.rst [deleted file]
Documentation/driver-model/index.rst [deleted file]
Documentation/driver-model/porting.rst [deleted file]
Documentation/early-userspace/README [deleted file]
Documentation/early-userspace/buffer-format.txt [deleted file]
Documentation/eisa.txt [deleted file]
Documentation/fault-injection/index.rst
Documentation/fb/fbcon.rst
Documentation/fb/index.rst
Documentation/fb/vesafb.rst
Documentation/filesystems/coda.txt
Documentation/filesystems/dax.txt
Documentation/filesystems/nfs/nfsroot.txt
Documentation/filesystems/porting
Documentation/filesystems/proc.txt
Documentation/filesystems/ramfs-rootfs-initramfs.txt
Documentation/filesystems/sysfs.txt
Documentation/filesystems/tmpfs.txt
Documentation/filesystems/xfs.txt [deleted file]
Documentation/firmware-guide/acpi/enumeration.rst
Documentation/fpga/index.rst
Documentation/gpio/index.rst [deleted file]
Documentation/hid/index.rst
Documentation/hwmon/k8temp.rst
Documentation/hwmon/submitting-patches.rst
Documentation/hwspinlock.txt
Documentation/ia64/IRQ-redir.txt [deleted file]
Documentation/ia64/README [deleted file]
Documentation/ia64/aliasing.rst [new file with mode: 0644]
Documentation/ia64/aliasing.txt [deleted file]
Documentation/ia64/efirtc.rst [new file with mode: 0644]
Documentation/ia64/efirtc.txt [deleted file]
Documentation/ia64/err_inject.rst [new file with mode: 0644]
Documentation/ia64/err_inject.txt [deleted file]
Documentation/ia64/fsys.rst [new file with mode: 0644]
Documentation/ia64/fsys.txt [deleted file]
Documentation/ia64/ia64.rst [new file with mode: 0644]
Documentation/ia64/index.rst [new file with mode: 0644]
Documentation/ia64/irq-redir.rst [new file with mode: 0644]
Documentation/ia64/mca.rst [new file with mode: 0644]
Documentation/ia64/mca.txt [deleted file]
Documentation/ia64/serial.rst [new file with mode: 0644]
Documentation/ia64/serial.txt [deleted file]
Documentation/ia64/xen.rst [new file with mode: 0644]
Documentation/ia64/xen.txt [deleted file]
Documentation/ide/index.rst
Documentation/iio/index.rst
Documentation/index.rst
Documentation/interconnect/interconnect.rst [deleted file]
Documentation/ioctl/botching-up-ioctls.rst [new file with mode: 0644]
Documentation/ioctl/botching-up-ioctls.txt [deleted file]
Documentation/ioctl/cdrom.rst [new file with mode: 0644]
Documentation/ioctl/cdrom.txt [deleted file]
Documentation/ioctl/hdio.rst [new file with mode: 0644]
Documentation/ioctl/hdio.txt [deleted file]
Documentation/ioctl/index.rst [new file with mode: 0644]
Documentation/ioctl/ioctl-decoding.rst [new file with mode: 0644]
Documentation/ioctl/ioctl-decoding.txt [deleted file]
Documentation/ioctl/ioctl-number.rst [new file with mode: 0644]
Documentation/ioctl/ioctl-number.txt [deleted file]
Documentation/kbuild/index.rst
Documentation/kbuild/issues.rst
Documentation/kbuild/kbuild.rst
Documentation/kbuild/kconfig-language.rst
Documentation/kbuild/kconfig.rst
Documentation/kbuild/makefiles.rst
Documentation/kdump/index.rst [deleted file]
Documentation/kernel-hacking/locking.rst
Documentation/kernel-per-CPU-kthreads.txt [deleted file]
Documentation/laptops/asus-laptop.txt [deleted file]
Documentation/laptops/disk-shock-protection.txt [deleted file]
Documentation/laptops/laptop-mode.txt [deleted file]
Documentation/laptops/lg-laptop.rst [deleted file]
Documentation/laptops/sony-laptop.txt [deleted file]
Documentation/laptops/sonypi.txt [deleted file]
Documentation/laptops/thinkpad-acpi.txt [deleted file]
Documentation/laptops/toshiba_haps.txt [deleted file]
Documentation/leds/index.rst
Documentation/livepatch/index.rst
Documentation/locking/index.rst [new file with mode: 0644]
Documentation/locking/lockdep-design.rst [new file with mode: 0644]
Documentation/locking/lockdep-design.txt [deleted file]
Documentation/locking/lockstat.rst [new file with mode: 0644]
Documentation/locking/lockstat.txt [deleted file]
Documentation/locking/locktorture.rst [new file with mode: 0644]
Documentation/locking/locktorture.txt [deleted file]
Documentation/locking/mutex-design.rst [new file with mode: 0644]
Documentation/locking/mutex-design.txt [deleted file]
Documentation/locking/rt-mutex-design.rst [new file with mode: 0644]
Documentation/locking/rt-mutex-design.txt [deleted file]
Documentation/locking/rt-mutex.rst [new file with mode: 0644]
Documentation/locking/rt-mutex.txt [deleted file]
Documentation/locking/spinlocks.rst [new file with mode: 0644]
Documentation/locking/spinlocks.txt [deleted file]
Documentation/locking/ww-mutex-design.rst [new file with mode: 0644]
Documentation/locking/ww-mutex-design.txt [deleted file]
Documentation/m68k/index.rst [new file with mode: 0644]
Documentation/m68k/kernel-options.rst [new file with mode: 0644]
Documentation/m68k/kernel-options.txt [deleted file]
Documentation/md/md-cluster.txt [deleted file]
Documentation/md/raid5-cache.txt [deleted file]
Documentation/md/raid5-ppl.txt [deleted file]
Documentation/memory-devices/ti-emif.txt [deleted file]
Documentation/mic/index.rst
Documentation/mmc/mmc-async-req.txt [deleted file]
Documentation/mmc/mmc-dev-attrs.txt [deleted file]
Documentation/mmc/mmc-dev-parts.txt [deleted file]
Documentation/mmc/mmc-tools.txt [deleted file]
Documentation/mtd/intel-spi.txt [deleted file]
Documentation/mtd/nand_ecc.txt [deleted file]
Documentation/mtd/spi-nor.txt [deleted file]
Documentation/namespaces/compatibility-list.txt [deleted file]
Documentation/namespaces/resource-control.txt [deleted file]
Documentation/netlabel/index.rst
Documentation/networking/bonding.txt
Documentation/networking/ip-sysctl.txt
Documentation/nfc/nfc-hci.txt [deleted file]
Documentation/nfc/nfc-pn544.txt [deleted file]
Documentation/ntb.txt [deleted file]
Documentation/nvdimm/btt.txt [deleted file]
Documentation/nvdimm/nvdimm.txt [deleted file]
Documentation/nvdimm/security.txt [deleted file]
Documentation/nvmem/nvmem.txt [deleted file]
Documentation/pcmcia/index.rst
Documentation/perf/arm-ccn.txt [deleted file]
Documentation/perf/arm_dsu_pmu.txt [deleted file]
Documentation/perf/hisi-pmu.txt [deleted file]
Documentation/perf/qcom_l2_pmu.txt [deleted file]
Documentation/perf/qcom_l3_pmu.txt [deleted file]
Documentation/perf/thunderx2-pmu.txt [deleted file]
Documentation/perf/xgene-pmu.txt [deleted file]
Documentation/phy/samsung-usb2.txt [deleted file]
Documentation/pi-futex.txt
Documentation/power/pm_qos_interface.rst
Documentation/powerpc/firmware-assisted-dump.txt
Documentation/process/submit-checklist.rst
Documentation/pti/pti_intel_mid.txt [deleted file]
Documentation/rapidio/mport_cdev.txt [deleted file]
Documentation/rapidio/rapidio.txt [deleted file]
Documentation/rapidio/rio_cm.txt [deleted file]
Documentation/rapidio/sysfs.txt [deleted file]
Documentation/rapidio/tsi721.txt [deleted file]
Documentation/rbtree.txt
Documentation/remoteproc.txt
Documentation/riscv/boot-image-header.txt [new file with mode: 0644]
Documentation/riscv/index.rst
Documentation/s390/debugging390.rst
Documentation/s390/index.rst
Documentation/s390/vfio-ccw.rst
Documentation/scheduler/index.rst
Documentation/scheduler/sched-deadline.rst
Documentation/scheduler/sched-design-CFS.rst
Documentation/scheduler/sched-rt-group.rst
Documentation/security/index.rst
Documentation/security/lsm-development.rst [moved from Documentation/security/LSM.rst with 100% similarity]
Documentation/security/lsm.rst [moved from Documentation/lsm.txt with 100% similarity]
Documentation/security/sak.rst [moved from Documentation/SAK.txt with 100% similarity]
Documentation/security/siphash.rst [moved from Documentation/siphash.txt with 100% similarity]
Documentation/security/tpm/index.rst
Documentation/security/tpm/xen-tpmfront.rst [new file with mode: 0644]
Documentation/security/tpm/xen-tpmfront.txt [deleted file]
Documentation/serial/driver.rst [deleted file]
Documentation/serial/index.rst [deleted file]
Documentation/sparc/index.rst
Documentation/switchtec.txt [deleted file]
Documentation/sysctl/README [deleted file]
Documentation/sysctl/abi.txt [deleted file]
Documentation/sysctl/fs.txt [deleted file]
Documentation/sysctl/kernel.txt [deleted file]
Documentation/sysctl/net.txt [deleted file]
Documentation/sysctl/sunrpc.txt [deleted file]
Documentation/sysctl/user.txt [deleted file]
Documentation/sysctl/vm.txt [deleted file]
Documentation/target/index.rst
Documentation/thermal/cpu-cooling-api.rst [new file with mode: 0644]
Documentation/thermal/cpu-cooling-api.txt [deleted file]
Documentation/thermal/exynos_thermal [deleted file]
Documentation/thermal/exynos_thermal.rst [new file with mode: 0644]
Documentation/thermal/exynos_thermal_emulation [deleted file]
Documentation/thermal/exynos_thermal_emulation.rst [new file with mode: 0644]
Documentation/thermal/index.rst [new file with mode: 0644]
Documentation/thermal/intel_powerclamp.rst [new file with mode: 0644]
Documentation/thermal/intel_powerclamp.txt [deleted file]
Documentation/thermal/nouveau_thermal [deleted file]
Documentation/thermal/nouveau_thermal.rst [new file with mode: 0644]
Documentation/thermal/power_allocator.rst [new file with mode: 0644]
Documentation/thermal/power_allocator.txt [deleted file]
Documentation/thermal/sysfs-api.rst [new file with mode: 0644]
Documentation/thermal/sysfs-api.txt [deleted file]
Documentation/thermal/x86_pkg_temperature_thermal [deleted file]
Documentation/thermal/x86_pkg_temperature_thermal.rst [new file with mode: 0644]
Documentation/timers/index.rst
Documentation/trace/kprobetrace.rst
Documentation/trace/uprobetracer.rst
Documentation/translations/it_IT/kernel-hacking/locking.rst
Documentation/translations/it_IT/process/submit-checklist.rst
Documentation/translations/zh_CN/arm/Booting
Documentation/translations/zh_CN/arm/kernel_user_helpers.txt
Documentation/translations/zh_CN/filesystems/sysfs.txt
Documentation/translations/zh_CN/gpio.txt
Documentation/translations/zh_CN/oops-tracing.txt
Documentation/translations/zh_CN/process/submit-checklist.rst
Documentation/translations/zh_CN/sparse.txt
Documentation/userspace-api/accelerators/ocxl.rst [new file with mode: 0644]
Documentation/userspace-api/index.rst
Documentation/vfio-mediated-device.txt [deleted file]
Documentation/virt/index.rst [moved from Documentation/virtual/index.rst with 100% similarity]
Documentation/virt/kvm/amd-memory-encryption.rst [moved from Documentation/virtual/kvm/amd-memory-encryption.rst with 100% similarity]
Documentation/virt/kvm/api.txt [new file with mode: 0644]
Documentation/virt/kvm/arm/hyp-abi.txt [moved from Documentation/virtual/kvm/arm/hyp-abi.txt with 100% similarity]
Documentation/virt/kvm/arm/psci.txt [moved from Documentation/virtual/kvm/arm/psci.txt with 100% similarity]
Documentation/virt/kvm/cpuid.rst [moved from Documentation/virtual/kvm/cpuid.rst with 100% similarity]
Documentation/virt/kvm/devices/README [moved from Documentation/virtual/kvm/devices/README with 100% similarity]
Documentation/virt/kvm/devices/arm-vgic-its.txt [moved from Documentation/virtual/kvm/devices/arm-vgic-its.txt with 100% similarity]
Documentation/virt/kvm/devices/arm-vgic-v3.txt [moved from Documentation/virtual/kvm/devices/arm-vgic-v3.txt with 100% similarity]
Documentation/virt/kvm/devices/arm-vgic.txt [moved from Documentation/virtual/kvm/devices/arm-vgic.txt with 100% similarity]
Documentation/virt/kvm/devices/mpic.txt [moved from Documentation/virtual/kvm/devices/mpic.txt with 100% similarity]
Documentation/virt/kvm/devices/s390_flic.txt [moved from Documentation/virtual/kvm/devices/s390_flic.txt with 100% similarity]
Documentation/virt/kvm/devices/vcpu.txt [moved from Documentation/virtual/kvm/devices/vcpu.txt with 100% similarity]
Documentation/virt/kvm/devices/vfio.txt [moved from Documentation/virtual/kvm/devices/vfio.txt with 100% similarity]
Documentation/virt/kvm/devices/vm.txt [moved from Documentation/virtual/kvm/devices/vm.txt with 100% similarity]
Documentation/virt/kvm/devices/xics.txt [moved from Documentation/virtual/kvm/devices/xics.txt with 100% similarity]
Documentation/virt/kvm/devices/xive.txt [moved from Documentation/virtual/kvm/devices/xive.txt with 100% similarity]
Documentation/virt/kvm/halt-polling.txt [moved from Documentation/virtual/kvm/halt-polling.txt with 100% similarity]
Documentation/virt/kvm/hypercalls.txt [new file with mode: 0644]
Documentation/virt/kvm/index.rst [moved from Documentation/virtual/kvm/index.rst with 100% similarity]
Documentation/virt/kvm/locking.txt [moved from Documentation/virtual/kvm/locking.txt with 100% similarity]
Documentation/virt/kvm/mmu.txt [new file with mode: 0644]
Documentation/virt/kvm/msr.txt [moved from Documentation/virtual/kvm/msr.txt with 100% similarity]
Documentation/virt/kvm/nested-vmx.txt [moved from Documentation/virtual/kvm/nested-vmx.txt with 100% similarity]
Documentation/virt/kvm/ppc-pv.txt [moved from Documentation/virtual/kvm/ppc-pv.txt with 100% similarity]
Documentation/virt/kvm/review-checklist.txt [new file with mode: 0644]
Documentation/virt/kvm/s390-diag.txt [moved from Documentation/virtual/kvm/s390-diag.txt with 100% similarity]
Documentation/virt/kvm/timekeeping.txt [moved from Documentation/virtual/kvm/timekeeping.txt with 100% similarity]
Documentation/virt/kvm/vcpu-requests.rst [moved from Documentation/virtual/kvm/vcpu-requests.rst with 100% similarity]
Documentation/virt/paravirt_ops.rst [moved from Documentation/virtual/paravirt_ops.rst with 100% similarity]
Documentation/virt/uml/UserModeLinux-HOWTO.txt [moved from Documentation/virtual/uml/UserModeLinux-HOWTO.txt with 100% similarity]
Documentation/virtual/kvm/api.txt [deleted file]
Documentation/virtual/kvm/hypercalls.txt [deleted file]
Documentation/virtual/kvm/mmu.txt [deleted file]
Documentation/virtual/kvm/review-checklist.txt [deleted file]
Documentation/vm/memory-model.rst
Documentation/vm/numa.rst
Documentation/vm/page_migration.rst
Documentation/vm/unevictable-lru.rst
Documentation/w1/w1.netlink
Documentation/watchdog/hpwdt.rst
Documentation/watchdog/index.rst
Documentation/watchdog/watchdog-parameters.rst
Documentation/x86/index.rst
Documentation/x86/intel-iommu.rst [moved from Documentation/Intel-IOMMU.txt with 100% similarity]
Documentation/x86/intel_txt.rst [moved from Documentation/intel_txt.txt with 100% similarity]
Documentation/x86/topology.rst
Documentation/x86/x86_64/fake-numa-for-cpusets.rst
Documentation/xilinx/index.rst [deleted file]
Documentation/xtensa/atomctl.rst [new file with mode: 0644]
Documentation/xtensa/atomctl.txt [deleted file]
Documentation/xtensa/booting.rst [new file with mode: 0644]
Documentation/xtensa/booting.txt [deleted file]
Documentation/xtensa/index.rst [new file with mode: 0644]
Documentation/xtensa/mmu.rst [new file with mode: 0644]
Documentation/xtensa/mmu.txt [deleted file]
MAINTAINERS
Makefile
arch/Kconfig
arch/alpha/include/asm/io.h
arch/alpha/kernel/syscalls/syscall.tbl
arch/arc/boot/dts/haps_hs.dts
arch/arc/boot/dts/hsdk.dts
arch/arc/configs/haps_hs_defconfig
arch/arc/configs/hsdk_defconfig
arch/arc/include/asm/entry-arcv2.h
arch/arc/include/asm/entry-compact.h
arch/arc/include/asm/linkage.h
arch/arc/include/asm/pgtable.h
arch/arc/kernel/asm-offsets.c
arch/arc/kernel/entry-arcv2.S
arch/arc/kernel/entry-compact.S
arch/arc/kernel/entry.S
arch/arc/kernel/unwind.c
arch/arc/mm/fault.c
arch/arc/mm/tlbex.S
arch/arc/plat-eznps/include/plat/ctop.h
arch/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/Makefile
arch/arm/boot/dts/Makefile
arch/arm/boot/dts/am335x-baltos-ir2110.dts
arch/arm/boot/dts/am335x-baltos-ir3220.dts
arch/arm/boot/dts/am335x-baltos-ir5221.dts
arch/arm/boot/dts/am335x-pcm-953.dtsi
arch/arm/boot/dts/am335x-phycore-rdk.dts
arch/arm/boot/dts/am335x-phycore-som.dtsi
arch/arm/boot/dts/am335x-regor-rdk.dts [new file with mode: 0644]
arch/arm/boot/dts/am335x-regor.dtsi [new file with mode: 0644]
arch/arm/boot/dts/am335x-wega-rdk.dts
arch/arm/boot/dts/am335x-wega.dtsi
arch/arm/boot/dts/arm-realview-eb.dtsi
arch/arm/boot/dts/arm-realview-pb1176.dts
arch/arm/boot/dts/arm-realview-pb11mp.dts
arch/arm/boot/dts/arm-realview-pbx.dtsi
arch/arm/boot/dts/armada-370-netgear-rn104.dts
arch/arm/boot/dts/aspeed-bmc-facebook-cmm.dts
arch/arm/boot/dts/aspeed-bmc-facebook-yamp.dts [new file with mode: 0644]
arch/arm/boot/dts/aspeed-bmc-inspur-fp5280g2.dts [new file with mode: 0644]
arch/arm/boot/dts/aspeed-bmc-lenovo-hr630.dts [new file with mode: 0644]
arch/arm/boot/dts/aspeed-bmc-microsoft-olympus.dts [new file with mode: 0644]
arch/arm/boot/dts/aspeed-bmc-opp-lanyang.dts
arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts
arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts
arch/arm/boot/dts/aspeed-bmc-opp-swift.dts [new file with mode: 0644]
arch/arm/boot/dts/aspeed-bmc-opp-vesnin.dts [new file with mode: 0644]
arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts
arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts
arch/arm/boot/dts/aspeed-bmc-quanta-q71l.dts
arch/arm/boot/dts/aspeed-g4.dtsi
arch/arm/boot/dts/aspeed-g5.dtsi
arch/arm/boot/dts/at91-wb50n.dtsi
arch/arm/boot/dts/at91sam9261ek.dts
arch/arm/boot/dts/at91sam9g45.dtsi
arch/arm/boot/dts/at91sam9rl.dtsi
arch/arm/boot/dts/at91sam9x5.dtsi
arch/arm/boot/dts/bcm-cygnus-clock.dtsi
arch/arm/boot/dts/bcm-cygnus.dtsi
arch/arm/boot/dts/bcm-nsp.dtsi
arch/arm/boot/dts/bcm11351.dtsi
arch/arm/boot/dts/bcm21664-garnet.dts
arch/arm/boot/dts/bcm21664.dtsi
arch/arm/boot/dts/bcm23550-sparrow.dts
arch/arm/boot/dts/bcm23550.dtsi
arch/arm/boot/dts/bcm28155-ap.dts
arch/arm/boot/dts/bcm283x.dtsi
arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts
arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts
arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
arch/arm/boot/dts/bcm4708-linksys-ea6300-v1.dts
arch/arm/boot/dts/bcm4708-linksys-ea6500-v2.dts
arch/arm/boot/dts/bcm4708-luxul-xap-1510.dts
arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
arch/arm/boot/dts/bcm4708-netgear-r6250.dts
arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts
arch/arm/boot/dts/bcm47081-luxul-xap-1410.dts
arch/arm/boot/dts/bcm47081-luxul-xwr-1200.dts
arch/arm/boot/dts/bcm47081-tplink-archer-c5-v2.dts
arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts
arch/arm/boot/dts/bcm47094-linksys-panamera.dts
arch/arm/boot/dts/bcm47094-luxul-abr-4500.dts
arch/arm/boot/dts/bcm47094-luxul-xap-1610.dts
arch/arm/boot/dts/bcm47094-luxul-xbr-4500.dts
arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts
arch/arm/boot/dts/bcm47094-luxul-xwr-3150-v1.dts
arch/arm/boot/dts/bcm47094-netgear-r8500.dts
arch/arm/boot/dts/bcm47094-phicomm-k3.dts
arch/arm/boot/dts/bcm47189-luxul-xap-1440.dts
arch/arm/boot/dts/bcm47189-luxul-xap-810.dts
arch/arm/boot/dts/bcm47189-tenda-ac9.dts
arch/arm/boot/dts/bcm5301x.dtsi
arch/arm/boot/dts/bcm53573.dtsi
arch/arm/boot/dts/bcm63138.dtsi
arch/arm/boot/dts/bcm7445-bcm97445svmb.dts
arch/arm/boot/dts/bcm7445.dtsi
arch/arm/boot/dts/bcm911360_entphn.dts
arch/arm/boot/dts/bcm947189acdbmr.dts
arch/arm/boot/dts/bcm953012er.dts
arch/arm/boot/dts/bcm953012k.dts
arch/arm/boot/dts/bcm958522er.dts
arch/arm/boot/dts/bcm958525er.dts
arch/arm/boot/dts/bcm958525xmc.dts
arch/arm/boot/dts/bcm958622hr.dts
arch/arm/boot/dts/bcm958623hr.dts
arch/arm/boot/dts/bcm958625hr.dts
arch/arm/boot/dts/bcm958625k.dts
arch/arm/boot/dts/bcm963138dvt.dts
arch/arm/boot/dts/bcm988312hr.dts
arch/arm/boot/dts/da850-evm.dts
arch/arm/boot/dts/da850-lcdk.dts
arch/arm/boot/dts/da850-lego-ev3.dts
arch/arm/boot/dts/da850.dtsi
arch/arm/boot/dts/emev2-kzm9d.dts
arch/arm/boot/dts/exynos3250-artik5.dtsi
arch/arm/boot/dts/exynos3250-monk.dts
arch/arm/boot/dts/exynos3250-rinato.dts
arch/arm/boot/dts/exynos3250.dtsi
arch/arm/boot/dts/exynos4.dtsi
arch/arm/boot/dts/exynos4210-origen.dts
arch/arm/boot/dts/exynos4210-trats.dts
arch/arm/boot/dts/exynos4210-universal_c210.dts
arch/arm/boot/dts/exynos4210.dtsi
arch/arm/boot/dts/exynos4412-galaxy-s3.dtsi
arch/arm/boot/dts/exynos4412-itop-scp-core.dtsi
arch/arm/boot/dts/exynos4412-midas.dtsi
arch/arm/boot/dts/exynos4412-odroid-common.dtsi
arch/arm/boot/dts/exynos4412-prime.dtsi
arch/arm/boot/dts/exynos4412.dtsi
arch/arm/boot/dts/exynos5410-odroidxu.dts
arch/arm/boot/dts/exynos5410.dtsi
arch/arm/boot/dts/exynos5420-arndale-octa.dts
arch/arm/boot/dts/exynos5420.dtsi
arch/arm/boot/dts/exynos5422-odroid-core.dtsi
arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi
arch/arm/boot/dts/exynos54xx.dtsi
arch/arm/boot/dts/gemini-dlink-dir-685.dts
arch/arm/boot/dts/hip04.dtsi
arch/arm/boot/dts/ibm-power9-dual.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx53-m53menlo.dts
arch/arm/boot/dts/imx53-smd.dts
arch/arm/boot/dts/imx53.dtsi
arch/arm/boot/dts/imx6dl-kontron-samx6i.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx6q-kontron-samx6i.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx6qdl-kontron-samx6i.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx6qdl-sabresd.dtsi
arch/arm/boot/dts/imx6qdl.dtsi
arch/arm/boot/dts/imx6sl-evk.dts
arch/arm/boot/dts/imx6sl.dtsi
arch/arm/boot/dts/imx6sll-evk.dts
arch/arm/boot/dts/imx6sll.dtsi
arch/arm/boot/dts/imx6sx-sdb-reva.dts
arch/arm/boot/dts/imx6sx-sdb.dts
arch/arm/boot/dts/imx6sx-udoo-neo-basic.dts
arch/arm/boot/dts/imx6sx-udoo-neo-extended.dts
arch/arm/boot/dts/imx6sx-udoo-neo-full.dts
arch/arm/boot/dts/imx6sx-udoo-neo.dtsi
arch/arm/boot/dts/imx6sx.dtsi
arch/arm/boot/dts/imx6ul-14x14-evk.dtsi
arch/arm/boot/dts/imx6ul-geam.dts
arch/arm/boot/dts/imx6ul-isiot.dtsi
arch/arm/boot/dts/imx6ul.dtsi
arch/arm/boot/dts/imx6ull-colibri-eval-v3.dtsi
arch/arm/boot/dts/imx6ull-colibri.dtsi
arch/arm/boot/dts/imx6ull.dtsi
arch/arm/boot/dts/imx7d-meerkat96.dts [new file with mode: 0644]
arch/arm/boot/dts/imx7d-sdb.dts
arch/arm/boot/dts/imx7d-zii-rpu2.dts
arch/arm/boot/dts/imx7d.dtsi
arch/arm/boot/dts/imx7s.dtsi
arch/arm/boot/dts/imx7ulp-evk.dts
arch/arm/boot/dts/imx7ulp.dtsi
arch/arm/boot/dts/integrator.dtsi
arch/arm/boot/dts/iwg20d-q7-common.dtsi
arch/arm/boot/dts/logicpd-torpedo-37xx-devkit-28.dts [new file with mode: 0644]
arch/arm/boot/dts/ls1021a-tsn.dts [new file with mode: 0644]
arch/arm/boot/dts/meson.dtsi
arch/arm/boot/dts/meson6-atv1200.dts
arch/arm/boot/dts/meson6.dtsi
arch/arm/boot/dts/meson8-minix-neo-x8.dts
arch/arm/boot/dts/meson8.dtsi
arch/arm/boot/dts/meson8b-ec100.dts
arch/arm/boot/dts/meson8b-mxq.dts
arch/arm/boot/dts/meson8b-odroidc1.dts
arch/arm/boot/dts/meson8b.dtsi
arch/arm/boot/dts/meson8m2-mxiii-plus.dts
arch/arm/boot/dts/meson8m2.dtsi
arch/arm/boot/dts/omap4-l4.dtsi
arch/arm/boot/dts/pxa300-raumfeld-common.dtsi
arch/arm/boot/dts/pxa300-raumfeld-controller.dts
arch/arm/boot/dts/pxa300-raumfeld-speaker-one.dts
arch/arm/boot/dts/pxa3xx.dtsi
arch/arm/boot/dts/qcom-apq8064.dtsi
arch/arm/boot/dts/qcom-msm8974-fairphone-fp2.dts
arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts
arch/arm/boot/dts/qcom-msm8974.dtsi
arch/arm/boot/dts/r7s72100-genmai.dts
arch/arm/boot/dts/r7s72100-rskrza1.dts
arch/arm/boot/dts/r7s72100.dtsi
arch/arm/boot/dts/r7s9210-rza2mevb.dts
arch/arm/boot/dts/r7s9210.dtsi
arch/arm/boot/dts/r8a73a4-ape6evm.dts
arch/arm/boot/dts/r8a7740-armadillo800eva.dts
arch/arm/boot/dts/r8a7743-sk-rzg1m.dts
arch/arm/boot/dts/r8a7745-iwg22d-sodimm.dts
arch/arm/boot/dts/r8a7745-sk-rzg1e.dts
arch/arm/boot/dts/r8a77470-iwg23s-sbc.dts
arch/arm/boot/dts/r8a7778-bockw.dts
arch/arm/boot/dts/r8a7779-marzen.dts
arch/arm/boot/dts/r8a7790-lager.dts
arch/arm/boot/dts/r8a7790-stout.dts
arch/arm/boot/dts/r8a7791-koelsch.dts
arch/arm/boot/dts/r8a7791-porter.dts
arch/arm/boot/dts/r8a7792-blanche.dts
arch/arm/boot/dts/r8a7792-wheat.dts
arch/arm/boot/dts/r8a7792.dtsi
arch/arm/boot/dts/r8a7793-gose.dts
arch/arm/boot/dts/r8a7794-alt.dts
arch/arm/boot/dts/r8a7794-silk.dts
arch/arm/boot/dts/rk322x.dtsi
arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi
arch/arm/boot/dts/rk3288-veyron-jaq.dts
arch/arm/boot/dts/rk3288-veyron-jerry.dts
arch/arm/boot/dts/rk3288-veyron-mickey.dts
arch/arm/boot/dts/rk3288-veyron-minnie.dts
arch/arm/boot/dts/rk3288-veyron-pinky.dts
arch/arm/boot/dts/rk3288-veyron-speedy.dts
arch/arm/boot/dts/rk3288-veyron.dtsi
arch/arm/boot/dts/rk3288.dtsi
arch/arm/boot/dts/sama5d3.dtsi
arch/arm/boot/dts/sh73a0-kzm9g.dts
arch/arm/boot/dts/socfpga_arria10.dtsi
arch/arm/boot/dts/socfpga_arria10_socdk.dtsi
arch/arm/boot/dts/stm32746g-eval.dts
arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
arch/arm/boot/dts/stm32mp157a-avenger96.dts [new file with mode: 0644]
arch/arm/boot/dts/stm32mp157a-dk1.dts
arch/arm/boot/dts/stm32mp157c-ed1.dts
arch/arm/boot/dts/stm32mp157c-ev1.dts
arch/arm/boot/dts/stm32mp157c.dtsi
arch/arm/boot/dts/stm32mp157xaa-pinctrl.dtsi [new file with mode: 0644]
arch/arm/boot/dts/stm32mp157xab-pinctrl.dtsi [new file with mode: 0644]
arch/arm/boot/dts/stm32mp157xac-pinctrl.dtsi [new file with mode: 0644]
arch/arm/boot/dts/stm32mp157xad-pinctrl.dtsi [new file with mode: 0644]
arch/arm/boot/dts/sun5i-gr8-evb.dts
arch/arm/boot/dts/sun6i-a31.dtsi
arch/arm/boot/dts/sun7i-a20-icnova-swac.dts
arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts
arch/arm/boot/dts/sun8i-a83t.dtsi
arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts
arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts
arch/arm/boot/dts/sun8i-h3-beelink-x2.dts
arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts
arch/arm/boot/dts/sun8i-r40.dtsi
arch/arm/boot/dts/sun8i-v3s.dtsi
arch/arm/boot/dts/sun8i-v40-bananapi-m2-berry.dts
arch/arm/boot/dts/sunxi-bananapi-m2-plus-v1.2.dtsi
arch/arm/boot/dts/uniphier-ld4-ref.dts
arch/arm/boot/dts/uniphier-ld4.dtsi
arch/arm/boot/dts/uniphier-ld6b-ref.dts
arch/arm/boot/dts/uniphier-pro4-ref.dts
arch/arm/boot/dts/uniphier-pro4.dtsi
arch/arm/boot/dts/uniphier-pro5.dtsi
arch/arm/boot/dts/uniphier-pxs2.dtsi
arch/arm/boot/dts/uniphier-sld8-ref.dts
arch/arm/boot/dts/uniphier-sld8.dtsi
arch/arm/boot/dts/versatile-ab.dts
arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
arch/arm/boot/dts/vexpress-v2m.dtsi
arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
arch/arm/boot/dts/vf610-zii-dev.dtsi
arch/arm/common/mcpm_entry.c
arch/arm/common/mcpm_head.S
arch/arm/common/vlock.S
arch/arm/configs/acs5k_defconfig
arch/arm/configs/acs5k_tiny_defconfig
arch/arm/configs/am200epdkit_defconfig
arch/arm/configs/aspeed_g4_defconfig
arch/arm/configs/aspeed_g5_defconfig
arch/arm/configs/at91_dt_defconfig
arch/arm/configs/axm55xx_defconfig
arch/arm/configs/cm_x2xx_defconfig
arch/arm/configs/cm_x300_defconfig
arch/arm/configs/cns3420vb_defconfig
arch/arm/configs/colibri_pxa270_defconfig
arch/arm/configs/colibri_pxa300_defconfig
arch/arm/configs/collie_defconfig
arch/arm/configs/corgi_defconfig
arch/arm/configs/davinci_all_defconfig
arch/arm/configs/dove_defconfig
arch/arm/configs/em_x270_defconfig
arch/arm/configs/ep93xx_defconfig
arch/arm/configs/eseries_pxa_defconfig
arch/arm/configs/exynos_defconfig
arch/arm/configs/ezx_defconfig
arch/arm/configs/gemini_defconfig
arch/arm/configs/h3600_defconfig
arch/arm/configs/h5000_defconfig
arch/arm/configs/imote2_defconfig
arch/arm/configs/imx_v4_v5_defconfig
arch/arm/configs/imx_v6_v7_defconfig
arch/arm/configs/integrator_defconfig
arch/arm/configs/iop13xx_defconfig
arch/arm/configs/iop32x_defconfig
arch/arm/configs/iop33x_defconfig
arch/arm/configs/ixp4xx_defconfig
arch/arm/configs/jornada720_defconfig
arch/arm/configs/keystone_defconfig
arch/arm/configs/ks8695_defconfig
arch/arm/configs/lpc18xx_defconfig
arch/arm/configs/lpc32xx_defconfig
arch/arm/configs/magician_defconfig
arch/arm/configs/mini2440_defconfig
arch/arm/configs/mmp2_defconfig
arch/arm/configs/moxart_defconfig
arch/arm/configs/multi_v5_defconfig
arch/arm/configs/multi_v7_defconfig
arch/arm/configs/mv78xx0_defconfig
arch/arm/configs/mvebu_v5_defconfig
arch/arm/configs/mvebu_v7_defconfig
arch/arm/configs/mxs_defconfig
arch/arm/configs/netx_defconfig [deleted file]
arch/arm/configs/nhk8815_defconfig
arch/arm/configs/nuc910_defconfig
arch/arm/configs/nuc950_defconfig
arch/arm/configs/nuc960_defconfig
arch/arm/configs/omap1_defconfig
arch/arm/configs/orion5x_defconfig
arch/arm/configs/palmz72_defconfig
arch/arm/configs/pcm027_defconfig
arch/arm/configs/prima2_defconfig
arch/arm/configs/pxa168_defconfig
arch/arm/configs/pxa3xx_defconfig
arch/arm/configs/pxa910_defconfig
arch/arm/configs/pxa_defconfig
arch/arm/configs/qcom_defconfig
arch/arm/configs/realview_defconfig
arch/arm/configs/s3c2410_defconfig
arch/arm/configs/s3c6400_defconfig
arch/arm/configs/s5pv210_defconfig
arch/arm/configs/sama5_defconfig
arch/arm/configs/shmobile_defconfig
arch/arm/configs/socfpga_defconfig
arch/arm/configs/spear13xx_defconfig
arch/arm/configs/spear3xx_defconfig
arch/arm/configs/spear6xx_defconfig
arch/arm/configs/spitz_defconfig
arch/arm/configs/tango4_defconfig
arch/arm/configs/tct_hammer_defconfig
arch/arm/configs/trizeps4_defconfig
arch/arm/configs/u300_defconfig
arch/arm/configs/u8500_defconfig
arch/arm/configs/versatile_defconfig
arch/arm/configs/vexpress_defconfig
arch/arm/configs/viper_defconfig
arch/arm/configs/xcep_defconfig
arch/arm/configs/zeus_defconfig
arch/arm/configs/zx_defconfig
arch/arm/include/asm/io.h
arch/arm/include/asm/setup.h
arch/arm/include/debug/netx.S [deleted file]
arch/arm/include/uapi/asm/setup.h
arch/arm/kernel/entry-armv.S
arch/arm/kernel/module.c
arch/arm/lib/Makefile
arch/arm/mach-at91/pm.c
arch/arm/mach-bcm/Kconfig
arch/arm/mach-bcm/Makefile
arch/arm/mach-bcm/bcm63xx_smp.c
arch/arm/mach-bcm/bcm_kona_smc.c
arch/arm/mach-bcm/board_bcm281xx.c
arch/arm/mach-bcm/platsmp-brcmstb.c
arch/arm/mach-davinci/board-da850-evm.c
arch/arm/mach-exynos/Kconfig
arch/arm/mach-exynos/Makefile
arch/arm/mach-exynos/common.h
arch/arm/mach-exynos/exynos-smc.S
arch/arm/mach-exynos/sleep.S
arch/arm/mach-exynos/suspend.c
arch/arm/mach-highbank/Makefile
arch/arm/mach-highbank/smc.S
arch/arm/mach-imx/cpuidle-imx6q.c
arch/arm/mach-imx/mach-imx7d.c
arch/arm/mach-ixp4xx/Kconfig
arch/arm/mach-keystone/Makefile
arch/arm/mach-keystone/smc.S
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/omap-headsmp.S
arch/arm/mach-omap2/omap-smc.S
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c
arch/arm/mach-omap2/pdata-quirks.c
arch/arm/mach-omap2/sleep33xx.S
arch/arm/mach-omap2/sleep34xx.S
arch/arm/mach-omap2/sleep43xx.S
arch/arm/mach-omap2/sleep44xx.S
arch/arm/mach-pxa/include/mach/lubbock.h
arch/arm/mach-pxa/lubbock.c
arch/arm/mach-rockchip/platsmp.c
arch/arm/mach-rockchip/pm.c
arch/arm/mach-rpc/Makefile
arch/arm/mach-rpc/dma.c
arch/arm/mach-rpc/ecard-loader.S [moved from arch/arm/lib/ecard.S with 100% similarity]
arch/arm/mach-rpc/ecard.c
arch/arm/mach-rpc/floppydma.S [moved from arch/arm/lib/floppydma.S with 100% similarity]
arch/arm/mach-rpc/include/mach/uncompress.h
arch/arm/mach-rpc/io-acorn.S [moved from arch/arm/lib/io-acorn.S with 100% similarity]
arch/arm/mach-rpc/irq.c
arch/arm/mach-rpc/time.c
arch/arm/mach-s3c24xx/pm.c
arch/arm/mach-sa1100/assabet.c
arch/arm/mach-sa1100/badge4.c
arch/arm/mach-sa1100/clock.c
arch/arm/mach-sa1100/h3xxx.c
arch/arm/mach-sa1100/hackkit.c
arch/arm/mach-sa1100/neponset.c
arch/arm/mach-shmobile/setup-rcar-gen2.c
arch/arm/mach-stm32/Kconfig
arch/arm/mach-tango/Makefile
arch/arm/mach-tango/smc.S
arch/arm/mach-versatile/versatile_dt.c
arch/arm/mm/Kconfig
arch/arm/mm/fault.c
arch/arm/plat-samsung/Kconfig
arch/arm/tools/mach-types
arch/arm/vdso/Makefile
arch/arm64/Kconfig
arch/arm64/Kconfig.platforms
arch/arm64/boot/dts/allwinner/axp803.dtsi
arch/arm64/boot/dts/allwinner/sun50i-a64-amarula-relic.dts
arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts
arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts
arch/arm64/boot/dts/allwinner/sun50i-a64-oceanic-5205-5inmfd.dts
arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts
arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts
arch/arm64/boot/dts/allwinner/sun50i-a64-teres-i.dts
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
arch/arm64/boot/dts/allwinner/sun50i-h5-emlid-neutis-n5-devboard.dts
arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo-plus2.dts
arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi
arch/arm64/boot/dts/amlogic/Makefile
arch/arm64/boot/dts/amlogic/meson-axg-s400.dts
arch/arm64/boot/dts/amlogic/meson-axg.dtsi
arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts
arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts
arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts
arch/arm64/boot/dts/amlogic/meson-g12a.dtsi
arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts [new file with mode: 0644]
arch/arm64/boot/dts/amlogic/meson-g12b.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
arch/arm64/boot/dts/amlogic/meson-gx.dtsi
arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
arch/arm64/boot/dts/amlogic/meson-gxbb-p200.dts
arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi
arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
arch/arm64/boot/dts/amlogic/meson-gxl-s805x-p241.dts
arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts
arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
arch/arm64/boot/dts/amlogic/meson-gxm-q200.dts
arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts
arch/arm64/boot/dts/arm/juno-base.dtsi
arch/arm64/boot/dts/arm/juno-cs-r1r2.dtsi
arch/arm64/boot/dts/arm/juno-motherboard.dtsi
arch/arm64/boot/dts/broadcom/stingray/stingray-usb.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/broadcom/stingray/stingray.dtsi
arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi
arch/arm64/boot/dts/exynos/exynos5433.dtsi
arch/arm64/boot/dts/exynos/exynos7-espresso.dts
arch/arm64/boot/dts/exynos/exynos7.dtsi
arch/arm64/boot/dts/freescale/Makefile
arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts
arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
arch/arm64/boot/dts/freescale/imx8mm-evk.dts
arch/arm64/boot/dts/freescale/imx8mm.dtsi
arch/arm64/boot/dts/freescale/imx8mq-evk.dts
arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8mq.dtsi
arch/arm64/boot/dts/freescale/imx8qxp.dtsi
arch/arm64/boot/dts/hisilicon/hi3660-coresight.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/hisilicon/hi3660.dtsi
arch/arm64/boot/dts/hisilicon/hi6220-coresight.dtsi
arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts
arch/arm64/boot/dts/marvell/armada-7040-db.dts
arch/arm64/boot/dts/marvell/armada-8040-clearfog-gt-8k.dts
arch/arm64/boot/dts/marvell/armada-8040-db.dts
arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi
arch/arm64/boot/dts/marvell/armada-ap806-dual.dtsi
arch/arm64/boot/dts/marvell/armada-ap806-quad.dtsi
arch/arm64/boot/dts/marvell/armada-ap806.dtsi
arch/arm64/boot/dts/marvell/armada-cp110.dtsi
arch/arm64/boot/dts/mediatek/Makefile
arch/arm64/boot/dts/mediatek/mt8183-evb.dts [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt8183.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
arch/arm64/boot/dts/nvidia/tegra186-p3310.dtsi
arch/arm64/boot/dts/nvidia/tegra186.dtsi
arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi
arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts
arch/arm64/boot/dts/nvidia/tegra194.dtsi
arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi
arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
arch/arm64/boot/dts/nvidia/tegra210.dtsi
arch/arm64/boot/dts/qcom/Makefile
arch/arm64/boot/dts/qcom/msm8916.dtsi
arch/arm64/boot/dts/qcom/msm8996.dtsi
arch/arm64/boot/dts/qcom/msm8998.dtsi
arch/arm64/boot/dts/qcom/pm8998.dtsi
arch/arm64/boot/dts/qcom/pms405.dtsi
arch/arm64/boot/dts/qcom/qcs404-evb.dtsi
arch/arm64/boot/dts/qcom/qcs404.dtsi
arch/arm64/boot/dts/qcom/sdm845-cheza-r1.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sdm845-cheza-r2.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sdm845-cheza-r3.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sdm845-db845c.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sdm845-mtp.dts
arch/arm64/boot/dts/qcom/sdm845.dtsi
arch/arm64/boot/dts/renesas/Makefile
arch/arm64/boot/dts/renesas/hihope-common.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/renesas/hihope-rzg2-ex.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/renesas/r8a774a1-hihope-rzg2m-ex.dts [new file with mode: 0644]
arch/arm64/boot/dts/renesas/r8a774a1-hihope-rzg2m.dts [new file with mode: 0644]
arch/arm64/boot/dts/renesas/r8a774a1.dtsi
arch/arm64/boot/dts/renesas/r8a774c0-cat874.dts
arch/arm64/boot/dts/renesas/r8a774c0.dtsi
arch/arm64/boot/dts/renesas/r8a7795.dtsi
arch/arm64/boot/dts/renesas/r8a7796.dtsi
arch/arm64/boot/dts/renesas/r8a77965.dtsi
arch/arm64/boot/dts/renesas/r8a77970-eagle.dts
arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts
arch/arm64/boot/dts/renesas/r8a77990.dtsi
arch/arm64/boot/dts/renesas/r8a77995-draak.dts
arch/arm64/boot/dts/renesas/r8a77995.dtsi
arch/arm64/boot/dts/renesas/salvator-common.dtsi
arch/arm64/boot/dts/renesas/ulcb-kf.dtsi
arch/arm64/boot/dts/renesas/ulcb.dtsi
arch/arm64/boot/dts/rockchip/Makefile
arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts
arch/arm64/boot/dts/rockchip/rk3328.dtsi
arch/arm64/boot/dts/rockchip/rk3399-ficus.dts
arch/arm64/boot/dts/rockchip/rk3399-hugsun-x99.dts [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3399-khadas-edge-captain.dts [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3399-khadas-edge-v.dts [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dts [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts
arch/arm64/boot/dts/rockchip/rk3399-rock960.dts
arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dts
arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi
arch/arm64/boot/dts/rockchip/rk3399.dtsi
arch/arm64/boot/dts/rockchip/rk3399pro.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/socionext/uniphier-ld11-global.dts
arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi
arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi
arch/arm64/boot/dts/socionext/uniphier-pxs3-ref.dts
arch/arm64/boot/dts/socionext/uniphier-pxs3.dtsi
arch/arm64/boot/dts/sprd/sc9836.dtsi
arch/arm64/boot/dts/sprd/sc9860.dtsi
arch/arm64/boot/dts/sprd/whale2.dtsi
arch/arm64/boot/dts/ti/Makefile
arch/arm64/boot/dts/ti/k3-am65-main.dtsi
arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi
arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi
arch/arm64/boot/dts/ti/k3-am65.dtsi
arch/arm64/boot/dts/ti/k3-am654-base-board.dts
arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts [new file with mode: 0644]
arch/arm64/boot/dts/ti/k3-j721e-main.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/ti/k3-j721e.dtsi [new file with mode: 0644]
arch/arm64/configs/defconfig
arch/arm64/include/asm/pgtable-prot.h
arch/arm64/include/asm/pgtable.h
arch/arm64/include/asm/sysreg.h
arch/arm64/kernel/kuser32.S
arch/arm64/kernel/vdso32/Makefile
arch/arm64/mm/fault.c
arch/arm64/mm/mmu.c
arch/csky/Kconfig
arch/csky/abiv1/Makefile
arch/csky/abiv1/inc/abi/ckmmu.h
arch/csky/abiv1/inc/abi/string.h
arch/csky/abiv1/memset.c [deleted file]
arch/csky/abiv1/strksyms.c
arch/csky/abiv2/inc/abi/ckmmu.h
arch/csky/include/asm/asid.h [new file with mode: 0644]
arch/csky/include/asm/mmu.h
arch/csky/include/asm/mmu_context.h
arch/csky/include/asm/pgtable.h
arch/csky/kernel/perf_event.c
arch/csky/kernel/smp.c
arch/csky/kernel/traps.c
arch/csky/mm/Makefile
arch/csky/mm/asid.c [new file with mode: 0644]
arch/csky/mm/context.c [new file with mode: 0644]
arch/csky/mm/init.c
arch/csky/mm/tlb.c
arch/h8300/include/asm/bitops.h
arch/hexagon/include/asm/pgalloc.h
arch/hexagon/include/asm/syscall.h
arch/ia64/kernel/efi.c
arch/ia64/kernel/fsys.S
arch/ia64/kernel/perfmon.c
arch/ia64/kernel/syscalls/syscall.tbl
arch/ia64/mm/fault.c
arch/ia64/mm/init.c
arch/ia64/mm/ioremap.c
arch/ia64/pci/pci.c
arch/m68k/kernel/syscalls/syscall.tbl
arch/mips/ar7/setup.c
arch/mips/ath79/setup.c
arch/mips/bcm63xx/dev-flash.c
arch/mips/bmips/setup.c
arch/mips/boot/dts/ralink/mt7628a.dtsi
arch/mips/cavium-octeon/executive/cvmx-pko.c
arch/mips/configs/ar7_defconfig
arch/mips/configs/ath25_defconfig
arch/mips/configs/ath79_defconfig
arch/mips/configs/bcm63xx_defconfig
arch/mips/configs/bigsur_defconfig
arch/mips/configs/bmips_be_defconfig
arch/mips/configs/bmips_stb_defconfig
arch/mips/configs/cavium_octeon_defconfig
arch/mips/configs/ci20_defconfig
arch/mips/configs/cobalt_defconfig
arch/mips/configs/fuloong2e_defconfig
arch/mips/configs/gpr_defconfig
arch/mips/configs/ip27_defconfig
arch/mips/configs/ip32_defconfig
arch/mips/configs/lemote2f_defconfig
arch/mips/configs/loongson1b_defconfig
arch/mips/configs/loongson1c_defconfig
arch/mips/configs/loongson3_defconfig
arch/mips/configs/malta_defconfig
arch/mips/configs/malta_kvm_defconfig
arch/mips/configs/malta_kvm_guest_defconfig
arch/mips/configs/maltaup_xpa_defconfig
arch/mips/configs/mips_paravirt_defconfig
arch/mips/configs/omega2p_defconfig
arch/mips/configs/pistachio_defconfig
arch/mips/configs/pnx8335_stb225_defconfig
arch/mips/configs/qi_lb60_defconfig
arch/mips/configs/rb532_defconfig
arch/mips/configs/rt305x_defconfig
arch/mips/configs/sb1250_swarm_defconfig
arch/mips/configs/tb0219_defconfig
arch/mips/configs/tb0226_defconfig
arch/mips/configs/tb0287_defconfig
arch/mips/configs/vocore2_defconfig
arch/mips/configs/xway_defconfig
arch/mips/include/asm/cpu.h
arch/mips/include/asm/io.h
arch/mips/include/asm/kprobes.h
arch/mips/include/asm/mach-jz4740/clock.h [deleted file]
arch/mips/include/asm/mach-ralink/pinmux.h
arch/mips/include/asm/syscall.h
arch/mips/jz4740/board-qi_lb60.c
arch/mips/jz4740/platform.c
arch/mips/jz4740/pm.c
arch/mips/jz4740/time.c
arch/mips/kernel/ftrace.c
arch/mips/kernel/kprobes.c
arch/mips/kernel/perf_event_mipsxx.c
arch/mips/kernel/syscalls/syscall_n32.tbl
arch/mips/kernel/syscalls/syscall_n64.tbl
arch/mips/kernel/syscalls/syscall_o32.tbl
arch/mips/lantiq/irq.c
arch/nds32/include/asm/syscall.h
arch/parisc/Kconfig
arch/parisc/include/asm/kprobes.h
arch/parisc/include/asm/syscall.h
arch/parisc/include/asm/unistd.h
arch/parisc/kernel/entry.S
arch/parisc/kernel/kprobes.c
arch/parisc/kernel/pacache.S
arch/parisc/kernel/ptrace.c
arch/parisc/kernel/syscalls/syscall.tbl
arch/powerpc/Kconfig
arch/powerpc/include/asm/book3s/64/pgtable.h
arch/powerpc/include/asm/hvcall.h
arch/powerpc/include/asm/pmc.h
arch/powerpc/include/asm/syscall.h
arch/powerpc/include/uapi/asm/kvm_para.h
arch/powerpc/include/uapi/asm/mman.h
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/dma-common.c [new file with mode: 0644]
arch/powerpc/kernel/signal_32.c
arch/powerpc/kernel/signal_64.c
arch/powerpc/kernel/syscalls/syscall.tbl
arch/powerpc/kvm/book3s_64_vio.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_xive.c
arch/powerpc/kvm/book3s_xive_native.c
arch/powerpc/mm/book3s64/hash_utils.c
arch/powerpc/mm/book3s64/iommu_api.c
arch/powerpc/mm/book3s64/radix_pgtable.c
arch/powerpc/mm/fault.c
arch/powerpc/mm/mem.c
arch/powerpc/platforms/powernv/memtrace.c
arch/powerpc/platforms/pseries/papr_scm.c
arch/powerpc/sysdev/xive/common.c
arch/riscv/Kconfig
arch/riscv/Kconfig.socs [new file with mode: 0644]
arch/riscv/Makefile
arch/riscv/boot/dts/sifive/Makefile
arch/riscv/boot/dts/sifive/fu540-c000.dtsi
arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
arch/riscv/configs/defconfig
arch/riscv/configs/rv32_defconfig
arch/riscv/include/asm/Kbuild
arch/riscv/include/asm/cacheflush.h
arch/riscv/include/asm/fixmap.h
arch/riscv/include/asm/hugetlb.h [new file with mode: 0644]
arch/riscv/include/asm/image.h [new file with mode: 0644]
arch/riscv/include/asm/page.h
arch/riscv/include/asm/pgtable-64.h
arch/riscv/include/asm/pgtable.h
arch/riscv/include/uapi/asm/unistd.h
arch/riscv/kernel/head.S
arch/riscv/kernel/setup.c
arch/riscv/kernel/vdso.c
arch/riscv/mm/Makefile
arch/riscv/mm/hugetlbpage.c [new file with mode: 0644]
arch/riscv/mm/init.c
arch/riscv/mm/sifive_l2_cache.c
arch/s390/Kconfig
arch/s390/appldata/appldata_base.c
arch/s390/include/asm/ctl_reg.h
arch/s390/include/asm/nmi.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/ptrace.h
arch/s390/include/asm/setup.h
arch/s390/include/asm/thread_info.h
arch/s390/kernel/syscalls/syscall.tbl
arch/s390/kernel/topology.c
arch/s390/kvm/interrupt.c
arch/s390/mm/fault.c
arch/s390/mm/init.c
arch/sh/Kconfig
arch/sh/boards/Kconfig
arch/sh/configs/ap325rxa_defconfig
arch/sh/configs/apsh4a3a_defconfig
arch/sh/configs/apsh4ad0a_defconfig
arch/sh/configs/cayman_defconfig
arch/sh/configs/dreamcast_defconfig
arch/sh/configs/ecovec24-romimage_defconfig
arch/sh/configs/ecovec24_defconfig
arch/sh/configs/edosk7760_defconfig
arch/sh/configs/espt_defconfig
arch/sh/configs/hp6xx_defconfig
arch/sh/configs/kfr2r09-romimage_defconfig
arch/sh/configs/kfr2r09_defconfig
arch/sh/configs/landisk_defconfig
arch/sh/configs/lboxre2_defconfig
arch/sh/configs/magicpanelr2_defconfig
arch/sh/configs/microdev_defconfig
arch/sh/configs/migor_defconfig
arch/sh/configs/polaris_defconfig
arch/sh/configs/r7780mp_defconfig
arch/sh/configs/r7785rp_defconfig
arch/sh/configs/rsk7201_defconfig
arch/sh/configs/rsk7203_defconfig
arch/sh/configs/rsk7264_defconfig
arch/sh/configs/rsk7269_defconfig
arch/sh/configs/rts7751r2d1_defconfig
arch/sh/configs/rts7751r2dplus_defconfig
arch/sh/configs/sdk7780_defconfig
arch/sh/configs/sdk7786_defconfig
arch/sh/configs/se7206_defconfig
arch/sh/configs/se7343_defconfig
arch/sh/configs/se7712_defconfig
arch/sh/configs/se7721_defconfig
arch/sh/configs/se7722_defconfig
arch/sh/configs/se7724_defconfig
arch/sh/configs/sh03_defconfig
arch/sh/configs/sh2007_defconfig
arch/sh/configs/sh7710voipgw_defconfig
arch/sh/configs/sh7724_generic_defconfig
arch/sh/configs/sh7757lcr_defconfig
arch/sh/configs/sh7763rdp_defconfig
arch/sh/configs/sh7770_generic_defconfig
arch/sh/configs/sh7785lcr_32bit_defconfig
arch/sh/configs/sh7785lcr_defconfig
arch/sh/configs/shx3_defconfig
arch/sh/configs/titan_defconfig
arch/sh/configs/ul2_defconfig
arch/sh/configs/urquell_defconfig
arch/sh/kernel/kprobes.c
arch/sh/kernel/syscalls/syscall.tbl
arch/sh/mm/fault.c
arch/sh/mm/init.c
arch/sparc/Kconfig
arch/sparc/include/uapi/asm/mman.h
arch/sparc/kernel/syscalls/syscall.tbl
arch/sparc/mm/fault_64.c
arch/sparc/vdso/Makefile
arch/x86/Kconfig
arch/x86/boot/compressed/eboot.c
arch/x86/boot/compressed/misc.c
arch/x86/boot/compressed/misc.h
arch/x86/boot/compressed/pgtable_64.c
arch/x86/entry/calling.h
arch/x86/entry/entry_32.S
arch/x86/entry/entry_64.S
arch/x86/entry/thunk_64.S
arch/x86/entry/vdso/Makefile
arch/x86/entry/vdso/vdso32-setup.c
arch/x86/hyperv/hv_init.c
arch/x86/ia32/sys_ia32.c
arch/x86/include/asm/apic.h
arch/x86/include/asm/hypervisor.h
arch/x86/include/asm/io.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/kvm_para.h
arch/x86/include/asm/paravirt.h
arch/x86/include/asm/paravirt_types.h
arch/x86/include/asm/pgtable.h
arch/x86/include/asm/pgtable_types.h
arch/x86/include/asm/traps.h
arch/x86/include/asm/uaccess.h
arch/x86/include/asm/x86_init.h
arch/x86/include/asm/xen/hypervisor.h
arch/x86/include/uapi/asm/kvm.h
arch/x86/kernel/apic/apic.c
arch/x86/kernel/asm-offsets.c
arch/x86/kernel/cpu/hypervisor.c
arch/x86/kernel/cpu/resctrl/rdtgroup.c
arch/x86/kernel/e820.c
arch/x86/kernel/ftrace.c
arch/x86/kernel/head_64.S
arch/x86/kernel/itmt.c
arch/x86/kernel/jailhouse.c
arch/x86/kernel/kvm.c
arch/x86/kernel/mpparse.c
arch/x86/kernel/paravirt.c
arch/x86/kernel/process_64.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/traps.c
arch/x86/kernel/x86_init.c
arch/x86/kvm/cpuid.c
arch/x86/kvm/emulate.c
arch/x86/kvm/hyperv.c
arch/x86/kvm/ioapic.c
arch/x86/kvm/lapic.c
arch/x86/kvm/lapic.h
arch/x86/kvm/mmu.c
arch/x86/kvm/pmu.c
arch/x86/kvm/svm.c
arch/x86/kvm/vmx/nested.c
arch/x86/kvm/vmx/pmu_intel.c
arch/x86/kvm/vmx/vmenter.S
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/x86.c
arch/x86/kvm/x86.h
arch/x86/lib/copy_user_64.S
arch/x86/lib/getuser.S
arch/x86/lib/putuser.S
arch/x86/lib/usercopy_64.c
arch/x86/math-emu/fpu_emu.h
arch/x86/math-emu/reg_constant.c
arch/x86/mm/fault.c
arch/x86/mm/init_32.c
arch/x86/mm/init_64.c
arch/x86/mm/ioremap.c
arch/x86/mm/mem_encrypt.c
arch/x86/xen/enlighten_hvm.c
arch/x86/xen/enlighten_pv.c
arch/x86/xen/mmu_pv.c
arch/x86/xen/spinlock.c
arch/x86/xen/xen-asm.S
arch/x86/xen/xen-asm_64.S
arch/x86/xen/xen-ops.h
arch/xtensa/boot/dts/virt.dts [new file with mode: 0644]
arch/xtensa/configs/virt_defconfig [new file with mode: 0644]
arch/xtensa/include/asm/asmmacro.h
arch/xtensa/include/asm/initialize_mmu.h
arch/xtensa/include/asm/platform.h
arch/xtensa/include/asm/types.h [deleted file]
arch/xtensa/include/uapi/asm/mman.h
arch/xtensa/kernel/coprocessor.S
arch/xtensa/kernel/entry.S
arch/xtensa/kernel/mcount.S
arch/xtensa/kernel/pci.c
arch/xtensa/kernel/platform.c
arch/xtensa/kernel/setup.c
arch/xtensa/lib/checksum.S
arch/xtensa/lib/memcopy.S
arch/xtensa/lib/memset.S
arch/xtensa/lib/strncpy_user.S
arch/xtensa/lib/strnlen_user.S
arch/xtensa/lib/usercopy.S
arch/xtensa/mm/init.c
arch/xtensa/mm/misc.S
block/Kconfig
block/Kconfig.iosched
block/bfq-iosched.c
block/blk-integrity.c
block/ioprio.c
block/mq-deadline.c
block/partitions/Kconfig
block/partitions/cmdline.c
drivers/acpi/acpi_memhotplug.c
drivers/acpi/acpi_video.c
drivers/acpi/acpica/exconfig.c
drivers/acpi/acpica/tbxfload.c
drivers/acpi/blacklist.c
drivers/acpi/nfit/core.c
drivers/atm/idt77252.c
drivers/base/devtmpfs.c
drivers/base/firmware_loader/fallback_table.c
drivers/base/memory.c
drivers/base/node.c
drivers/base/platform.c
drivers/base/power/domain.c
drivers/base/power/domain_governor.c
drivers/base/power/qos.c
drivers/base/power/runtime.c
drivers/block/Kconfig
drivers/block/floppy.c
drivers/block/rbd.c
drivers/block/rbd_types.h
drivers/block/zram/Kconfig
drivers/bus/brcmstb_gisb.c
drivers/bus/fsl-mc/dprc.c
drivers/bus/fsl-mc/fsl-mc-bus.c
drivers/bus/fsl-mc/fsl-mc-private.h
drivers/bus/ti-sysc.c
drivers/char/Kconfig
drivers/char/hw_random/core.c
drivers/clk/Kconfig
drivers/clk/Makefile
drivers/clk/at91/sckc.c
drivers/clk/bcm/Kconfig
drivers/clk/bcm/Makefile
drivers/clk/bcm/clk-bcm2835.c
drivers/clk/bcm/clk-bcm63xx-gate.c [new file with mode: 0644]
drivers/clk/bcm/clk-raspberrypi.c [new file with mode: 0644]
drivers/clk/clk-bulk.c
drivers/clk/clk-cdce706.c
drivers/clk/clk-devres.c
drivers/clk/clk-lochnagar.c
drivers/clk/clk-pwm.c
drivers/clk/clk-qoriq.c
drivers/clk/clk-si5341.c [new file with mode: 0644]
drivers/clk/clk-si544.c
drivers/clk/clk.c
drivers/clk/clk.h
drivers/clk/imx/clk-busy.c
drivers/clk/imx/clk-cpu.c
drivers/clk/imx/clk-fixup-div.c
drivers/clk/imx/clk-fixup-mux.c
drivers/clk/imx/clk-gate-exclusive.c
drivers/clk/imx/clk-gate2.c
drivers/clk/imx/clk-imx6q.c
drivers/clk/imx/clk-imx6sl.c
drivers/clk/imx/clk-imx6sll.c
drivers/clk/imx/clk-imx6sx.c
drivers/clk/imx/clk-imx6ul.c
drivers/clk/imx/clk-imx7d.c
drivers/clk/imx/clk-imx7ulp.c
drivers/clk/imx/clk-imx8mm.c
drivers/clk/imx/clk-imx8mq.c
drivers/clk/imx/clk-pfd.c
drivers/clk/imx/clk-pllv3.c
drivers/clk/imx/clk.c
drivers/clk/imx/clk.h
drivers/clk/ingenic/Makefile
drivers/clk/ingenic/cgu.c
drivers/clk/ingenic/cgu.h
drivers/clk/ingenic/jz4725b-cgu.c
drivers/clk/ingenic/jz4740-cgu.c
drivers/clk/ingenic/jz4770-cgu.c
drivers/clk/ingenic/jz4780-cgu.c
drivers/clk/ingenic/pm.c [new file with mode: 0644]
drivers/clk/ingenic/pm.h [new file with mode: 0644]
drivers/clk/keystone/Kconfig
drivers/clk/keystone/sci-clk.c
drivers/clk/mediatek/Kconfig
drivers/clk/mediatek/Makefile
drivers/clk/mediatek/clk-mt8183.c
drivers/clk/mediatek/clk-mt8516-aud.c [new file with mode: 0644]
drivers/clk/mediatek/clk-mt8516.c
drivers/clk/meson/axg.c
drivers/clk/meson/clk-mpll.c
drivers/clk/meson/clk-mpll.h
drivers/clk/meson/g12a.c
drivers/clk/meson/g12a.h
drivers/clk/meson/gxbb.c
drivers/clk/meson/meson-eeclk.c
drivers/clk/meson/meson-eeclk.h
drivers/clk/meson/meson8b.c
drivers/clk/meson/meson8b.h
drivers/clk/mmp/clk-frac.c
drivers/clk/mvebu/kirkwood.c
drivers/clk/qcom/gcc-msm8996.c
drivers/clk/qcom/gcc-qcs404.c
drivers/clk/qcom/gdsc.c
drivers/clk/renesas/clk-div6.c
drivers/clk/renesas/clk-mstp.c
drivers/clk/renesas/r8a774a1-cpg-mssr.c
drivers/clk/renesas/r8a7795-cpg-mssr.c
drivers/clk/renesas/r8a7796-cpg-mssr.c
drivers/clk/renesas/r8a77965-cpg-mssr.c
drivers/clk/renesas/r8a77990-cpg-mssr.c
drivers/clk/renesas/r8a77995-cpg-mssr.c
drivers/clk/renesas/r9a06g032-clocks.c
drivers/clk/renesas/renesas-cpg-mssr.c
drivers/clk/rockchip/clk-mmc-phase.c
drivers/clk/rockchip/clk-px30.c
drivers/clk/rockchip/clk-rk3228.c
drivers/clk/rockchip/clk-rk3288.c
drivers/clk/rockchip/clk-rk3328.c
drivers/clk/rockchip/clk-rk3368.c
drivers/clk/rockchip/clk-rk3399.c
drivers/clk/rockchip/clk.h
drivers/clk/samsung/clk-exynos4.c
drivers/clk/samsung/clk-exynos5420.c
drivers/clk/samsung/clk-exynos5433.c
drivers/clk/socfpga/clk-s10.c
drivers/clk/sprd/common.c
drivers/clk/sprd/sc9860-clk.c
drivers/clk/sunxi-ng/ccu-sun4i-a10.c
drivers/clk/sunxi-ng/ccu-sun50i-a64.c
drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
drivers/clk/sunxi-ng/ccu-sun50i-h6.c
drivers/clk/sunxi-ng/ccu-sun5i.c
drivers/clk/sunxi-ng/ccu-sun6i-a31.c
drivers/clk/sunxi-ng/ccu-sun8i-a23.c
drivers/clk/sunxi-ng/ccu-sun8i-a33.c
drivers/clk/sunxi-ng/ccu-sun8i-h3.c
drivers/clk/sunxi-ng/ccu-sun8i-r.c
drivers/clk/sunxi-ng/ccu-sun8i-r40.c
drivers/clk/sunxi-ng/ccu-sun8i-v3s.c
drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c
drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c
drivers/clk/sunxi-ng/ccu_common.c
drivers/clk/sunxi-ng/ccu_gate.h
drivers/clk/sunxi/clk-sunxi.c
drivers/clk/tegra/clk-tegra210.c
drivers/clk/ti/divider.c
drivers/clk/ti/gate.c
drivers/clk/ti/mux.c
drivers/connector/connector.c
drivers/cpufreq/bmips-cpufreq.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/davinci-cpufreq.c
drivers/cpufreq/imx-cpufreq-dt.c
drivers/cpufreq/imx6q-cpufreq.c
drivers/cpufreq/intel_pstate.c
drivers/cpufreq/kirkwood-cpufreq.c
drivers/cpufreq/loongson1-cpufreq.c
drivers/cpufreq/loongson2_cpufreq.c
drivers/cpufreq/maple-cpufreq.c
drivers/cpufreq/omap-cpufreq.c
drivers/cpufreq/pasemi-cpufreq.c
drivers/cpufreq/pmac32-cpufreq.c
drivers/cpufreq/pmac64-cpufreq.c
drivers/cpufreq/s3c2416-cpufreq.c
drivers/cpufreq/s3c64xx-cpufreq.c
drivers/cpufreq/s5pv210-cpufreq.c
drivers/cpufreq/sa1100-cpufreq.c
drivers/cpufreq/sa1110-cpufreq.c
drivers/cpufreq/spear-cpufreq.c
drivers/cpufreq/tegra20-cpufreq.c
drivers/cpuidle/governor.c
drivers/crypto/amcc/crypto4xx_trng.c
drivers/crypto/ccp/ccp-ops.c
drivers/crypto/ccp/psp-dev.c
drivers/crypto/stm32/stm32-hash.c
drivers/crypto/sunxi-ss/sun4i-ss-cipher.c
drivers/crypto/sunxi-ss/sun4i-ss-core.c
drivers/crypto/sunxi-ss/sun4i-ss-hash.c
drivers/crypto/sunxi-ss/sun4i-ss.h
drivers/dax/bus.c
drivers/dax/dax-private.h
drivers/dax/kmem.c
drivers/dax/super.c
drivers/dma-buf/Kconfig
drivers/dma-buf/dma-buf.c
drivers/dma/Kconfig
drivers/dma/Makefile
drivers/dma/amba-pl08x.c
drivers/dma/at_xdmac.c
drivers/dma/bcm-sba-raid.c
drivers/dma/coh901318.c
drivers/dma/dma-axi-dmac.c
drivers/dma/dma-jz4780.c
drivers/dma/dmaengine.c
drivers/dma/dmatest.c
drivers/dma/dw-edma/Kconfig [new file with mode: 0644]
drivers/dma/dw-edma/Makefile [new file with mode: 0644]
drivers/dma/dw-edma/dw-edma-core.c [new file with mode: 0644]
drivers/dma/dw-edma/dw-edma-core.h [new file with mode: 0644]
drivers/dma/dw-edma/dw-edma-pcie.c [new file with mode: 0644]
drivers/dma/dw-edma/dw-edma-v0-core.c [new file with mode: 0644]
drivers/dma/dw-edma/dw-edma-v0-core.h [new file with mode: 0644]
drivers/dma/dw-edma/dw-edma-v0-debugfs.c [new file with mode: 0644]
drivers/dma/dw-edma/dw-edma-v0-debugfs.h [new file with mode: 0644]
drivers/dma/dw-edma/dw-edma-v0-regs.h [new file with mode: 0644]
drivers/dma/dw/pci.c
drivers/dma/fsl-edma-common.c
drivers/dma/fsl-edma-common.h
drivers/dma/fsl-edma.c
drivers/dma/fsl-qdma.c
drivers/dma/hsu/hsu.c
drivers/dma/imx-sdma.c
drivers/dma/mcf-edma.c
drivers/dma/mediatek/Kconfig
drivers/dma/mediatek/Makefile
drivers/dma/mediatek/mtk-uart-apdma.c [new file with mode: 0644]
drivers/dma/mic_x100_dma.c
drivers/dma/mmp_tdma.c
drivers/dma/mxs-dma.c
drivers/dma/of-dma.c
drivers/dma/pl330.c
drivers/dma/pxa_dma.c
drivers/dma/qcom/hidma.h
drivers/dma/qcom/hidma_dbg.c
drivers/dma/sh/Kconfig
drivers/dma/sh/Makefile
drivers/dma/sh/rcar-dmac.c
drivers/dma/sh/sudmac.c [deleted file]
drivers/dma/sh/usb-dmac.c
drivers/dma/stm32-dma.c
drivers/dma/stm32-dmamux.c
drivers/dma/sun6i-dma.c
drivers/dma/tegra20-apb-dma.c
drivers/dma/virt-dma.c
drivers/dma/virt-dma.h
drivers/dma/xilinx/xilinx_dma.c
drivers/firmware/Kconfig
drivers/firmware/arm_scmi/clock.c
drivers/firmware/arm_scmi/sensors.c
drivers/firmware/iscsi_ibft.c
drivers/firmware/psci/psci_checker.c
drivers/firmware/raspberrypi.c
drivers/firmware/tegra/bpmp.c
drivers/firmware/ti_sci.c
drivers/firmware/ti_sci.h
drivers/fpga/dfl-afu-dma-region.c
drivers/gpio/Kconfig
drivers/gpio/gpio-cs5535.c
drivers/gpio/gpio-davinci.c
drivers/gpio/gpio-em.c
drivers/gpio/gpiolib-of.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h
drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c
drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c
drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c
drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
drivers/gpu/drm/amd/amdgpu/nv.c
drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
drivers/gpu/drm/amd/amdgpu/soc15.c
drivers/gpu/drm/amd/amdgpu/vi.c
drivers/gpu/drm/amd/amdgpu/vi_dpm.h [deleted file]
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c
drivers/gpu/drm/amd/amdkfd/kfd_priv.h
drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
drivers/gpu/drm/amd/display/Kconfig
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drivers/gpu/drm/amd/display/dc/dc_stream.h
drivers/gpu/drm/amd/display/dc/dcn20/Makefile
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
drivers/gpu/drm/amd/display/dc/dsc/Makefile
drivers/gpu/drm/amd/include/amd_shared.h
drivers/gpu/drm/amd/powerplay/amdgpu_smu.c
drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c
drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h
drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if.h
drivers/gpu/drm/amd/powerplay/navi10_ppt.c
drivers/gpu/drm/amd/powerplay/smu_v11_0.c
drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c
drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c
drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c
drivers/gpu/drm/amd/powerplay/vega20_ppt.c
drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
drivers/gpu/drm/arm/display/komeda/komeda_kms.h
drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
drivers/gpu/drm/arm/display/komeda/komeda_plane.c
drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c
drivers/gpu/drm/bochs/bochs.h
drivers/gpu/drm/bochs/bochs_hw.c
drivers/gpu/drm/bochs/bochs_kms.c
drivers/gpu/drm/drm_client_modeset.c
drivers/gpu/drm/drm_connector.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_ioctl.c
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/drm_modeset_lock.c
drivers/gpu/drm/drm_panel_orientation_quirks.c
drivers/gpu/drm/i915/i915_perf.c
drivers/gpu/drm/nouveau/Kbuild
drivers/gpu/drm/nouveau/dispnv04/Kbuild
drivers/gpu/drm/nouveau/dispnv04/cursor.c
drivers/gpu/drm/nouveau/dispnv04/disp.h
drivers/gpu/drm/nouveau/dispnv50/Kbuild
drivers/gpu/drm/nouveau/dispnv50/disp.c
drivers/gpu/drm/nouveau/dispnv50/head.c
drivers/gpu/drm/nouveau/include/nvif/cl0002.h
drivers/gpu/drm/nouveau/include/nvif/cl0046.h
drivers/gpu/drm/nouveau/include/nvif/cl006b.h
drivers/gpu/drm/nouveau/include/nvif/cl0080.h
drivers/gpu/drm/nouveau/include/nvif/cl506e.h
drivers/gpu/drm/nouveau/include/nvif/cl506f.h
drivers/gpu/drm/nouveau/include/nvif/cl5070.h
drivers/gpu/drm/nouveau/include/nvif/cl507a.h
drivers/gpu/drm/nouveau/include/nvif/cl507b.h
drivers/gpu/drm/nouveau/include/nvif/cl507c.h
drivers/gpu/drm/nouveau/include/nvif/cl507d.h
drivers/gpu/drm/nouveau/include/nvif/cl507e.h
drivers/gpu/drm/nouveau/include/nvif/cl826e.h
drivers/gpu/drm/nouveau/include/nvif/cl826f.h
drivers/gpu/drm/nouveau/include/nvif/cl906f.h
drivers/gpu/drm/nouveau/include/nvif/cl9097.h
drivers/gpu/drm/nouveau/include/nvif/cla06f.h
drivers/gpu/drm/nouveau/include/nvif/class.h
drivers/gpu/drm/nouveau/include/nvif/clc36f.h
drivers/gpu/drm/nouveau/include/nvif/clc37b.h
drivers/gpu/drm/nouveau/include/nvif/clc37e.h
drivers/gpu/drm/nouveau/include/nvif/client.h
drivers/gpu/drm/nouveau/include/nvif/device.h
drivers/gpu/drm/nouveau/include/nvif/driver.h
drivers/gpu/drm/nouveau/include/nvif/event.h
drivers/gpu/drm/nouveau/include/nvif/if0000.h
drivers/gpu/drm/nouveau/include/nvif/if0001.h
drivers/gpu/drm/nouveau/include/nvif/if0002.h
drivers/gpu/drm/nouveau/include/nvif/if0003.h
drivers/gpu/drm/nouveau/include/nvif/if0004.h
drivers/gpu/drm/nouveau/include/nvif/if0005.h
drivers/gpu/drm/nouveau/include/nvif/ioctl.h
drivers/gpu/drm/nouveau/include/nvif/notify.h
drivers/gpu/drm/nouveau/include/nvif/object.h
drivers/gpu/drm/nouveau/include/nvif/os.h
drivers/gpu/drm/nouveau/include/nvif/unpack.h
drivers/gpu/drm/nouveau/include/nvkm/core/client.h
drivers/gpu/drm/nouveau/include/nvkm/core/debug.h
drivers/gpu/drm/nouveau/include/nvkm/core/device.h
drivers/gpu/drm/nouveau/include/nvkm/core/engine.h
drivers/gpu/drm/nouveau/include/nvkm/core/enum.h
drivers/gpu/drm/nouveau/include/nvkm/core/event.h
drivers/gpu/drm/nouveau/include/nvkm/core/firmware.h
drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h
drivers/gpu/drm/nouveau/include/nvkm/core/ioctl.h
drivers/gpu/drm/nouveau/include/nvkm/core/memory.h
drivers/gpu/drm/nouveau/include/nvkm/core/mm.h
drivers/gpu/drm/nouveau/include/nvkm/core/notify.h
drivers/gpu/drm/nouveau/include/nvkm/core/object.h
drivers/gpu/drm/nouveau/include/nvkm/core/oproxy.h
drivers/gpu/drm/nouveau/include/nvkm/core/option.h
drivers/gpu/drm/nouveau/include/nvkm/core/os.h
drivers/gpu/drm/nouveau/include/nvkm/core/pci.h
drivers/gpu/drm/nouveau/include/nvkm/core/ramht.h
drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h
drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h
drivers/gpu/drm/nouveau/include/nvkm/engine/bsp.h
drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h
drivers/gpu/drm/nouveau/include/nvkm/engine/cipher.h
drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
drivers/gpu/drm/nouveau/include/nvkm/engine/dma.h
drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h
drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h
drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h
drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h
drivers/gpu/drm/nouveau/include/nvkm/engine/msenc.h
drivers/gpu/drm/nouveau/include/nvkm/engine/mspdec.h
drivers/gpu/drm/nouveau/include/nvkm/engine/msppp.h
drivers/gpu/drm/nouveau/include/nvkm/engine/msvld.h
drivers/gpu/drm/nouveau/include/nvkm/engine/nvdec.h
drivers/gpu/drm/nouveau/include/nvkm/engine/nvenc.h
drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h
drivers/gpu/drm/nouveau/include/nvkm/engine/sec.h
drivers/gpu/drm/nouveau/include/nvkm/engine/sec2.h
drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h
drivers/gpu/drm/nouveau/include/nvkm/engine/vic.h
drivers/gpu/drm/nouveau/include/nvkm/engine/vp.h
drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0203.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0205.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0209.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/P0260.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/bit.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/bmp.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/boost.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/conn.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/cstep.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/dcb.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/disp.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/dp.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/extdev.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/fan.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/gpio.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/i2c.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/iccsense.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/image.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/mxm.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/npde.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pcir.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/perf.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pll.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pmu.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/power_budget.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/rammap.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/therm.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/timing.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/vmap.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/volt.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/vpstate.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/xpio.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bus.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/fuse.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/iccsense.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/mxm.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/vga.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h
drivers/gpu/drm/nouveau/nouveau_abi16.h
drivers/gpu/drm/nouveau/nouveau_acpi.c
drivers/gpu/drm/nouveau/nouveau_acpi.h
drivers/gpu/drm/nouveau/nouveau_bo.h
drivers/gpu/drm/nouveau/nouveau_chan.h
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_debugfs.h
drivers/gpu/drm/nouveau/nouveau_display.h
drivers/gpu/drm/nouveau/nouveau_dmem.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_fence.h
drivers/gpu/drm/nouveau/nouveau_gem.h
drivers/gpu/drm/nouveau/nouveau_hwmon.c
drivers/gpu/drm/nouveau/nouveau_ioctl.h
drivers/gpu/drm/nouveau/nouveau_reg.h
drivers/gpu/drm/nouveau/nouveau_sgdma.c
drivers/gpu/drm/nouveau/nouveau_ttm.h
drivers/gpu/drm/nouveau/nouveau_usif.h
drivers/gpu/drm/nouveau/nouveau_vga.c
drivers/gpu/drm/nouveau/nouveau_vga.h
drivers/gpu/drm/nouveau/nv10_fence.h
drivers/gpu/drm/nouveau/nvif/Kbuild
drivers/gpu/drm/nouveau/nvkm/Kbuild
drivers/gpu/drm/nouveau/nvkm/core/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/bsp/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3.h
drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3.h
drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h
drivers/gpu/drm/nouveau/nvkm/engine/cipher/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.h
drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.h
drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/sortu102.c
drivers/gpu/drm/nouveau/nvkm/engine/dma/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/dma/priv.h
drivers/gpu/drm/nouveau/nvkm/engine/dma/user.h
drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h
drivers/gpu/drm/nouveau/nvkm/engine/fifo/changf100.h
drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h
drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv04.h
drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h
drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h
drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h
drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h
drivers/gpu/drm/nouveau/nvkm/engine/fifo/regsnv04.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf100.fuc3.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf100.fuc3.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf117.fuc3.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk104.fuc3.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk110.fuc3.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk208.fuc5.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgm107.fuc5.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/os.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/regs.h
drivers/gpu/drm/nouveau/nvkm/engine/mpeg/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h
drivers/gpu/drm/nouveau/nvkm/engine/mpeg/priv.h
drivers/gpu/drm/nouveau/nvkm/engine/msenc/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/mspdec/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/mspdec/priv.h
drivers/gpu/drm/nouveau/nvkm/engine/msppp/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/msppp/priv.h
drivers/gpu/drm/nouveau/nvkm/engine/msvld/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/msvld/priv.h
drivers/gpu/drm/nouveau/nvkm/engine/nvdec/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/nvdec/priv.h
drivers/gpu/drm/nouveau/nvkm/engine/nvenc/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h
drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.h
drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h
drivers/gpu/drm/nouveau/nvkm/engine/sec/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s.h
drivers/gpu/drm/nouveau/nvkm/engine/sec2/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h
drivers/gpu/drm/nouveau/nvkm/engine/sw/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h
drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h
drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.h
drivers/gpu/drm/nouveau/nvkm/engine/sw/priv.h
drivers/gpu/drm/nouveau/nvkm/engine/vic/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/vp/Kbuild
drivers/gpu/drm/nouveau/nvkm/falcon/Kbuild
drivers/gpu/drm/nouveau/nvkm/falcon/priv.h
drivers/gpu/drm/nouveau/nvkm/falcon/v1.c
drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.h
drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.h
drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/bios/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/bus/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h
drivers/gpu/drm/nouveau/nvkm/subdev/bus/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/clk/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.h
drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h
drivers/gpu/drm/nouveau/nvkm/subdev/clk/pll.h
drivers/gpu/drm/nouveau/nvkm/subdev/clk/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/clk/seq.h
drivers/gpu/drm/nouveau/nvkm/subdev/devinit/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.h
drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h
drivers/gpu/drm/nouveau/nvkm/subdev/devinit/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/fault/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h
drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h
drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h
drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h
drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.h
drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramseq.h
drivers/gpu/drm/nouveau/nvkm/subdev/fb/regsnv04.h
drivers/gpu/drm/nouveau/nvkm/subdev/fuse/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/fuse/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/gpio/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/gpio/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.h
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/ibus/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/ibus/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/instmem/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/mmu/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/mxm/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.h
drivers/gpu/drm/nouveau/nvkm/subdev/mxm/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.h
drivers/gpu/drm/nouveau/nvkm/subdev/pci/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/pmu/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h
drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf119.fuc4.h
drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h
drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h
drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/os.h
drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c
drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/secboot/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/secboot/ls_ucode_msgqueue.c
drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/timer/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/timer/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/timer/regsnv04.h
drivers/gpu/drm/nouveau/nvkm/subdev/top/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/top/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/volt/priv.h
drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
drivers/hv/vmbus_drv.c
drivers/hwmon/nct6775.c
drivers/hwmon/occ/common.c
drivers/hwmon/scmi-hwmon.c
drivers/hwspinlock/Kconfig
drivers/hwspinlock/hwspinlock_core.c
drivers/hwspinlock/omap_hwspinlock.c
drivers/hwspinlock/stm32_hwspinlock.c
drivers/infiniband/hw/qib/qib_fs.c
drivers/infiniband/ulp/iser/iscsi_iser.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/input/joystick/iforce/iforce-ff.c
drivers/input/joystick/iforce/iforce-main.c
drivers/input/joystick/iforce/iforce-packets.c
drivers/input/joystick/iforce/iforce-serio.c
drivers/input/joystick/iforce/iforce-usb.c
drivers/input/joystick/iforce/iforce.h
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/adp5589-keys.c
drivers/input/keyboard/applespi.c [new file with mode: 0644]
drivers/input/keyboard/applespi.h [new file with mode: 0644]
drivers/input/keyboard/applespi_trace.h [new file with mode: 0644]
drivers/input/keyboard/mtk-pmic-keys.c
drivers/input/keyboard/sun4i-lradc-keys.c
drivers/input/mouse/alps.c
drivers/input/mouse/synaptics.c
drivers/input/mouse/trackpoint.h
drivers/input/serio/hyperv-keyboard.c
drivers/input/tablet/gtco.c
drivers/input/touchscreen/auo-pixcir-ts.c
drivers/input/touchscreen/sun4i-ts.c
drivers/iommu/Kconfig
drivers/iommu/Makefile
drivers/iommu/amd_iommu.c
drivers/iommu/amd_iommu_init.c
drivers/iommu/amd_iommu_types.h
drivers/iommu/intel-iommu-debugfs.c
drivers/iommu/intel-iommu.c
drivers/iommu/iova.c
drivers/iommu/virtio-iommu.c [new file with mode: 0644]
drivers/isdn/hardware/mISDN/hfcsusb.c
drivers/md/Kconfig
drivers/md/dm-init.c
drivers/md/dm-kcopyd.c
drivers/md/dm-raid.c
drivers/md/dm-snap.c
drivers/md/dm-table.c
drivers/md/dm-zoned-metadata.c
drivers/md/dm-zoned.h
drivers/md/dm.c
drivers/md/dm.h
drivers/media/v4l2-core/v4l2-subdev.c
drivers/memory/.gitignore [new file with mode: 0644]
drivers/memory/Kconfig
drivers/memory/Makefile
drivers/memory/brcmstb_dpfe.c
drivers/memory/emif.c
drivers/memory/jedec_ddr.h [new file with mode: 0644]
drivers/memory/jedec_ddr_data.c [new file with mode: 0644]
drivers/memory/jz4780-nemc.c
drivers/memory/of_memory.c
drivers/memory/tegra/tegra124.c
drivers/memory/ti-emif-sram-pm.S
drivers/misc/cxl/api.c
drivers/misc/ibmasm/ibmasmfs.c
drivers/misc/pci_endpoint_test.c
drivers/misc/vmw_balloon.c
drivers/mtd/nand/raw/nand_ecc.c
drivers/net/caif/caif_hsi.c
drivers/net/ethernet/atheros/ag71xx.c
drivers/net/ethernet/atheros/atlx/atl1.c
drivers/net/ethernet/atheros/atlx/atl2.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/genet/bcmgenet.c
drivers/net/ethernet/cavium/liquidio/request_manager.c
drivers/net/ethernet/chelsio/cxgb/my3126.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
drivers/net/ethernet/chelsio/cxgb4/sched.c
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/google/gve/gve_main.c
drivers/net/ethernet/google/gve/gve_rx.c
drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c
drivers/net/ethernet/intel/ice/ice_main.c
drivers/net/ethernet/intel/igc/igc_main.c
drivers/net/ethernet/jme.c
drivers/net/ethernet/marvell/skge.c
drivers/net/ethernet/marvell/sky2.c
drivers/net/ethernet/mediatek/mtk_eth_soc.c
drivers/net/ethernet/mellanox/mlx4/eq.c
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
drivers/net/ethernet/mellanox/mlx5/core/health.c
drivers/net/ethernet/mellanox/mlxsw/pci.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
drivers/net/ethernet/mscc/ocelot_board.c
drivers/net/ethernet/mscc/ocelot_flower.c
drivers/net/ethernet/mscc/ocelot_tc.c
drivers/net/ethernet/neterion/s2io.c
drivers/net/ethernet/netronome/nfp/flower/offload.c
drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c
drivers/net/ethernet/qlogic/qed/qed_rdma.c
drivers/net/ethernet/realtek/r8169_main.c
drivers/net/ethernet/sis/sis900.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/tlan.c
drivers/net/fddi/defza.c
drivers/net/hippi/rrunner.c
drivers/net/hyperv/netvsc_drv.c
drivers/net/phy/sfp.c
drivers/net/usb/qmi_wwan.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/vrf.c
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/wil6210/cfg80211.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c
drivers/net/wireless/intel/iwlwifi/cfg/22000.c
drivers/net/wireless/intel/iwlwifi/iwl-config.h
drivers/net/wireless/intel/iwlwifi/iwl-csr.h
drivers/net/wireless/intel/iwlwifi/pcie/drv.c
drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
drivers/net/wireless/ti/wlcore/vendor_cmd.c
drivers/ntb/Kconfig
drivers/ntb/Makefile
drivers/ntb/core.c [moved from drivers/ntb/ntb.c with 100% similarity]
drivers/ntb/hw/amd/ntb_hw_amd.c
drivers/ntb/hw/intel/ntb_hw_gen3.c
drivers/ntb/hw/mscc/ntb_hw_switchtec.c
drivers/ntb/msi.c [new file with mode: 0644]
drivers/ntb/ntb_transport.c
drivers/ntb/test/Kconfig
drivers/ntb/test/Makefile
drivers/ntb/test/ntb_msi_test.c [new file with mode: 0644]
drivers/ntb/test/ntb_perf.c
drivers/nvdimm/Kconfig
drivers/nvdimm/Makefile
drivers/nvdimm/claim.c
drivers/nvdimm/dax_devs.c
drivers/nvdimm/namespace_devs.c
drivers/nvdimm/nd.h
drivers/nvdimm/nd_virtio.c [new file with mode: 0644]
drivers/nvdimm/pfn.h
drivers/nvdimm/pfn_devs.c
drivers/nvdimm/pmem.c
drivers/nvdimm/region_devs.c
drivers/nvdimm/virtio_pmem.c [new file with mode: 0644]
drivers/nvdimm/virtio_pmem.h [new file with mode: 0644]
drivers/of/base.c
drivers/oprofile/oprofilefs.c
drivers/pci/msi.c
drivers/pci/of.c
drivers/pci/switch/Kconfig
drivers/pci/switch/switchtec.c
drivers/perf/qcom_l3_pmu.c
drivers/platform/x86/Kconfig
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/dcdbas.c
drivers/platform/x86/dell_rbu.c
drivers/pnp/isapnp/Kconfig
drivers/powercap/Kconfig
drivers/powercap/Makefile
drivers/powercap/intel_rapl.c [deleted file]
drivers/powercap/intel_rapl_common.c [new file with mode: 0644]
drivers/powercap/intel_rapl_msr.c [new file with mode: 0644]
drivers/powercap/powercap_sys.c
drivers/pps/pps.c
drivers/rapidio/Kconfig
drivers/rapidio/devices/rio_mport_cdev.c
drivers/remoteproc/Kconfig
drivers/remoteproc/Makefile
drivers/remoteproc/imx_rproc.c
drivers/remoteproc/qcom_q6v5_adsp.c
drivers/remoteproc/qcom_q6v5_mss.c
drivers/remoteproc/remoteproc_core.c
drivers/remoteproc/remoteproc_elf_loader.c
drivers/remoteproc/remoteproc_internal.h
drivers/remoteproc/stm32_rproc.c [new file with mode: 0644]
drivers/reset/Kconfig
drivers/reset/core.c
drivers/reset/reset-simple.c
drivers/rpmsg/rpmsg_core.c
drivers/rtc/Kconfig
drivers/rtc/interface.c
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-ds2404.c
drivers/rtc/rtc-fm3130.c
drivers/rtc/rtc-imx-sc.c
drivers/rtc/rtc-m41t80.c
drivers/rtc/rtc-pcf2123.c
drivers/rtc/rtc-pcf8563.c
drivers/rtc/rtc-rv8803.c
drivers/rtc/rtc-rx8010.c
drivers/rtc/rtc-rx8025.c
drivers/rtc/rtc-s35390a.c
drivers/rtc/rtc-st-lpc.c
drivers/rtc/rtc-stm32.c
drivers/rtc/rtc-sun6i.c
drivers/rtc/rtc-tegra.c
drivers/rtc/rtc-test.c
drivers/rtc/rtc-tps65910.c
drivers/rtc/rtc-wm831x.c
drivers/s390/block/dcssblk.c
drivers/s390/scsi/zfcp_erp.c
drivers/s390/scsi/zfcp_fsf.c
drivers/scsi/Makefile
drivers/scsi/cxlflash/ocxl_hw.c
drivers/scsi/hosts.c
drivers/scsi/libfc/fc_exch.c
drivers/scsi/libsas/sas_scsi_host.c
drivers/scsi/lpfc/lpfc_debugfs.h
drivers/scsi/megaraid/megaraid_sas.h
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/mpt3sas/mpt3sas_scsih.c
drivers/scsi/pm8001/pm8001_sas.c
drivers/scsi/pm8001/pm80xx_hwi.c
drivers/scsi/pm8001/pm80xx_hwi.h
drivers/scsi/scsi_devinfo.c
drivers/scsi/scsi_lib.c
drivers/scsi/sd_zbc.c
drivers/scsi/storvsc_drv.c
drivers/scsi/ufs/ufshcd.c
drivers/scsi/virtio_scsi.c
drivers/soc/amlogic/meson-canvas.c
drivers/soc/aspeed/aspeed-lpc-ctrl.c
drivers/soc/fsl/Kconfig
drivers/soc/fsl/Makefile
drivers/soc/fsl/dpaa2-console.c [new file with mode: 0644]
drivers/soc/fsl/dpio/dpio-driver.c
drivers/soc/fsl/dpio/qbman-portal.c
drivers/soc/fsl/dpio/qbman-portal.h
drivers/soc/fsl/guts.c
drivers/soc/fsl/qbman/bman_portal.c
drivers/soc/fsl/qbman/qman_ccsr.c
drivers/soc/fsl/qbman/qman_portal.c
drivers/soc/fsl/qbman/qman_priv.h
drivers/soc/imx/Kconfig
drivers/soc/imx/Makefile
drivers/soc/imx/soc-imx-scu.c [new file with mode: 0644]
drivers/soc/imx/soc-imx8.c
drivers/soc/qcom/Kconfig
drivers/soc/qcom/Makefile
drivers/soc/qcom/apr.c
drivers/soc/qcom/mdt_loader.c
drivers/soc/qcom/qcom_aoss.c [new file with mode: 0644]
drivers/soc/qcom/rpmpd.c
drivers/soc/renesas/Kconfig
drivers/soc/rockchip/pm_domains.c
drivers/soc/tegra/Kconfig
drivers/soc/tegra/fuse/fuse-tegra.c
drivers/soc/tegra/fuse/fuse-tegra20.c
drivers/soc/tegra/pmc.c
drivers/soc/ti/Kconfig
drivers/soc/ti/pm33xx.c
drivers/staging/unisys/Documentation/overview.txt
drivers/thermal/fair_share.c
drivers/thermal/gov_bang_bang.c
drivers/thermal/intel/int340x_thermal/Kconfig
drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
drivers/thermal/power_allocator.c
drivers/thermal/step_wise.c
drivers/thermal/thermal_core.c
drivers/thermal/thermal_core.h
drivers/thermal/user_space.c
drivers/tty/Kconfig
drivers/tty/serial/Kconfig
drivers/tty/serial/sa1100.c
drivers/tty/serial/ucc_uart.c
drivers/tty/tty_ldisc.c
drivers/usb/gadget/legacy/inode.c
drivers/vfio/Kconfig
drivers/vfio/mdev/Kconfig
drivers/vfio/mdev/mdev_core.c
drivers/vfio/pci/vfio_pci_nvlink2.c
drivers/vfio/vfio_iommu_spapr_tce.c
drivers/vfio/vfio_iommu_type1.c
drivers/vhost/net.c
drivers/vhost/vhost.c
drivers/vhost/vhost.h
drivers/video/backlight/gpio_backlight.c
drivers/video/backlight/pwm_bl.c
drivers/virtio/Kconfig
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_mmio.c
drivers/w1/Kconfig
drivers/watchdog/Kconfig
drivers/watchdog/acquirewdt.c
drivers/watchdog/advantechwdt.c
drivers/watchdog/aspeed_wdt.c
drivers/watchdog/bcm2835_wdt.c
drivers/watchdog/bcm7038_wdt.c
drivers/watchdog/bcm_kona_wdt.c
drivers/watchdog/cadence_wdt.c
drivers/watchdog/da9052_wdt.c
drivers/watchdog/da9062_wdt.c
drivers/watchdog/davinci_wdt.c
drivers/watchdog/digicolor_wdt.c
drivers/watchdog/ebc-c384_wdt.c
drivers/watchdog/eurotechwdt.c
drivers/watchdog/ftwdt010_wdt.c
drivers/watchdog/gpio_wdt.c
drivers/watchdog/hpwdt.c
drivers/watchdog/i6300esb.c
drivers/watchdog/iTCO_vendor_support.c
drivers/watchdog/iTCO_wdt.c
drivers/watchdog/ib700wdt.c
drivers/watchdog/ie6xx_wdt.c
drivers/watchdog/imx2_wdt.c
drivers/watchdog/imx_sc_wdt.c
drivers/watchdog/intel-mid_wdt.c
drivers/watchdog/jz4740_wdt.c
drivers/watchdog/loongson1_wdt.c
drivers/watchdog/max77620_wdt.c
drivers/watchdog/mei_wdt.c
drivers/watchdog/mena21_wdt.c
drivers/watchdog/menf21bmc_wdt.c
drivers/watchdog/mpc8xxx_wdt.c
drivers/watchdog/mv64x60_wdt.c
drivers/watchdog/ni903x_wdt.c
drivers/watchdog/nic7018_wdt.c
drivers/watchdog/npcm_wdt.c
drivers/watchdog/nv_tco.h
drivers/watchdog/octeon-wdt-main.c
drivers/watchdog/of_xilinx_wdt.c
drivers/watchdog/omap_wdt.c
drivers/watchdog/omap_wdt.h
drivers/watchdog/pc87413_wdt.c
drivers/watchdog/pcwd_pci.c
drivers/watchdog/pcwd_usb.c
drivers/watchdog/pic32-dmt.c
drivers/watchdog/pic32-wdt.c
drivers/watchdog/pnx4008_wdt.c
drivers/watchdog/qcom-wdt.c
drivers/watchdog/rave-sp-wdt.c
drivers/watchdog/renesas_wdt.c
drivers/watchdog/retu_wdt.c
drivers/watchdog/s3c2410_wdt.c
drivers/watchdog/sa1100_wdt.c
drivers/watchdog/sama5d4_wdt.c
drivers/watchdog/sbc7240_wdt.c
drivers/watchdog/sbc8360.c
drivers/watchdog/sch311x_wdt.c
drivers/watchdog/softdog.c
drivers/watchdog/sp5100_tco.c
drivers/watchdog/sp805_wdt.c
drivers/watchdog/sprd_wdt.c
drivers/watchdog/st_lpc_wdt.c
drivers/watchdog/stm32_iwdg.c
drivers/watchdog/stmp3xxx_rtc_wdt.c
drivers/watchdog/tegra_wdt.c
drivers/watchdog/ts4800_wdt.c
drivers/watchdog/w83627hf_wdt.c
drivers/watchdog/wafer5823wdt.c
drivers/watchdog/watchdog_core.c
drivers/watchdog/watchdog_core.h
drivers/watchdog/watchdog_dev.c
drivers/watchdog/wd501p.h
drivers/watchdog/wdt.c
drivers/watchdog/wdt_pci.c
drivers/watchdog/wm831x_wdt.c
drivers/watchdog/xen_wdt.c
drivers/xen/Kconfig
drivers/xen/Makefile
drivers/xen/balloon.c
drivers/xen/events/events_base.c
drivers/xen/evtchn.c
drivers/xen/swiotlb-xen.c
drivers/xen/tmem.c [deleted file]
drivers/xen/xen-balloon.c
drivers/xen/xen-selfballoon.c [deleted file]
drivers/xen/xenfs/super.c
fs/Makefile
fs/adfs/adfs.h
fs/adfs/dir.c
fs/adfs/dir_f.c
fs/adfs/dir_fplus.c
fs/adfs/inode.c
fs/adfs/map.c
fs/adfs/super.c
fs/aio.c
fs/anon_inodes.c
fs/binfmt_elf.c
fs/binfmt_flat.c
fs/binfmt_misc.c
fs/block_dev.c
fs/btrfs/Kconfig
fs/btrfs/Makefile
fs/btrfs/backref.c
fs/btrfs/backref.h
fs/btrfs/block-rsv.c [new file with mode: 0644]
fs/btrfs/block-rsv.h [new file with mode: 0644]
fs/btrfs/btrfs_inode.h
fs/btrfs/check-integrity.c
fs/btrfs/compression.c
fs/btrfs/compression.h
fs/btrfs/ctree.h
fs/btrfs/delalloc-space.c [new file with mode: 0644]
fs/btrfs/delalloc-space.h [new file with mode: 0644]
fs/btrfs/delayed-ref.c
fs/btrfs/delayed-ref.h
fs/btrfs/dev-replace.c
fs/btrfs/disk-io.c
fs/btrfs/disk-io.h
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-map.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/print-tree.c
fs/btrfs/props.c
fs/btrfs/qgroup.c
fs/btrfs/raid56.h
fs/btrfs/relocation.c
fs/btrfs/root-tree.c
fs/btrfs/scrub.c
fs/btrfs/send.c
fs/btrfs/space-info.c [new file with mode: 0644]
fs/btrfs/space-info.h [new file with mode: 0644]
fs/btrfs/super.c
fs/btrfs/sysfs.c
fs/btrfs/tests/btrfs-tests.c
fs/btrfs/tests/extent-io-tests.c
fs/btrfs/tests/extent-map-tests.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h
fs/btrfs/tree-checker.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/btrfs/volumes.h
fs/ceph/Kconfig
fs/ceph/acl.c
fs/ceph/addr.c
fs/ceph/caps.c
fs/ceph/debugfs.c
fs/ceph/dir.c
fs/ceph/export.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/mds_client.c
fs/ceph/mds_client.h
fs/ceph/mdsmap.c
fs/ceph/quota.c
fs/ceph/snap.c
fs/ceph/super.c
fs/ceph/super.h
fs/ceph/xattr.c
fs/cifs/Kconfig
fs/cifs/Makefile
fs/cifs/cifs_debug.c
fs/cifs/cifs_fs_sb.h
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifsglob.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/dfs_cache.c
fs/cifs/inode.c
fs/cifs/misc.c
fs/cifs/smb1ops.c
fs/cifs/smb2file.c
fs/cifs/smb2inode.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/cifs/smb2pdu.h
fs/cifs/smb2proto.h
fs/cifs/smb2transport.c
fs/cifs/transport.c
fs/cifs/xattr.c
fs/coda/Makefile
fs/coda/cache.c
fs/coda/cnode.c
fs/coda/coda_fs_i.h
fs/coda/coda_int.h
fs/coda/coda_linux.c
fs/coda/coda_linux.h
fs/coda/coda_psdev.h [new file with mode: 0644]
fs/coda/dir.c
fs/coda/file.c
fs/coda/inode.c
fs/coda/pioctl.c
fs/coda/psdev.c
fs/coda/symlink.c
fs/coda/sysctl.c
fs/coda/upcall.c
fs/configfs/mount.c
fs/d_path.c
fs/dax.c
fs/dcache.c
fs/efivarfs/super.c
fs/eventpoll.c
fs/ext4/file.c
fs/f2fs/data.c
fs/fs_parser.c
fs/fs_pin.c
fs/fsopen.c
fs/fuse/control.c
fs/hfsplus/xattr.c
fs/hugetlbfs/inode.c
fs/internal.h
fs/io_uring.c
fs/iomap.c [deleted file]
fs/iomap/Makefile [new file with mode: 0644]
fs/iomap/apply.c [new file with mode: 0644]
fs/iomap/buffered-io.c [new file with mode: 0644]
fs/iomap/direct-io.c [new file with mode: 0644]
fs/iomap/fiemap.c [new file with mode: 0644]
fs/iomap/seek.c [new file with mode: 0644]
fs/iomap/swapfile.c [new file with mode: 0644]
fs/libfs.c
fs/mount.h
fs/namespace.c
fs/nfs/Makefile
fs/nfs/callback_proc.c
fs/nfs/client.c
fs/nfs/dir.c
fs/nfs/flexfilelayout/flexfilelayout.c
fs/nfs/flexfilelayout/flexfilelayoutdev.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/netns.h
fs/nfs/nfs2xdr.c
fs/nfs/nfs3client.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4client.c
fs/nfs/nfs4file.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4trace.c
fs/nfs/nfs4trace.h
fs/nfs/nfs4xdr.c
fs/nfs/nfstrace.h
fs/nfs/pagelist.c
fs/nfs/pnfs.c
fs/nfs/super.c
fs/nfs/sysfs.c [new file with mode: 0644]
fs/nfs/sysfs.h [new file with mode: 0644]
fs/nfs/write.c
fs/nfsd/nfsctl.c
fs/notify/inotify/inotify_user.c
fs/nsfs.c
fs/open.c
fs/openpromfs/inode.c
fs/orangefs/file.c
fs/pipe.c
fs/proc/Kconfig
fs/proc/base.c
fs/proc/inode.c
fs/proc/proc_sysctl.c
fs/proc/root.c
fs/proc/task_mmu.c
fs/proc/vmcore.c
fs/ramfs/inode.c
fs/reiserfs/journal.c
fs/select.c
fs/super.c
fs/sysfs/mount.c
fs/ubifs/file.c
fs/ufs/super.c
fs/xfs/Makefile
fs/xfs/libxfs/xfs_trans_inode.c [new file with mode: 0644]
fs/xfs/xfs_file.c
fs/xfs/xfs_trans_inode.c [deleted file]
include/Kbuild
include/asm-generic/bug.h
include/asm-generic/cacheflush.h
include/asm-generic/vmlinux.lds.h
include/drm/drm_modes.h
include/dt-bindings/clock/exynos4.h
include/dt-bindings/clock/exynos5420.h
include/dt-bindings/clock/g12a-clkc.h
include/dt-bindings/clock/imx8mm-clock.h
include/dt-bindings/clock/imx8mq-clock.h
include/dt-bindings/clock/meson8b-clkc.h
include/dt-bindings/clock/mt8516-clk.h
include/dt-bindings/clock/qcom,gcc-qcs404.h
include/dt-bindings/clock/qcom,gpucc-msm8998.h [new file with mode: 0644]
include/dt-bindings/clock/rk3228-cru.h
include/dt-bindings/clock/rk3328-cru.h
include/dt-bindings/clock/stratix10-clock.h
include/dt-bindings/gpio/tegra186-gpio.h
include/dt-bindings/power/qcom-aoss-qmp.h [new file with mode: 0644]
include/dt-bindings/power/qcom-rpmpd.h
include/dt-bindings/reset/bitmain,bm1880-reset.h [new file with mode: 0644]
include/linux/acpi.h
include/linux/bits.h
include/linux/ceph/ceph_features.h
include/linux/ceph/ceph_fs.h
include/linux/ceph/cls_lock_client.h
include/linux/ceph/decode.h
include/linux/ceph/libceph.h
include/linux/ceph/mon_client.h
include/linux/ceph/osd_client.h
include/linux/ceph/striper.h
include/linux/cgroup-defs.h
include/linux/clk-provider.h
include/linux/clk.h
include/linux/coda.h
include/linux/coda_psdev.h [deleted file]
include/linux/compat.h
include/linux/compiler-gcc.h
include/linux/compiler.h
include/linux/compiler_types.h
include/linux/connector.h
include/linux/cpufreq.h
include/linux/cred.h
include/linux/dax.h
include/linux/dcache.h
include/linux/device-mapper.h
include/linux/device.h
include/linux/dma-direct.h
include/linux/dma-mapping.h
include/linux/dma/edma.h [new file with mode: 0644]
include/linux/dmaengine.h
include/linux/filter.h
include/linux/fpga/adi-axi-common.h [new file with mode: 0644]
include/linux/fs.h
include/linux/fs_context.h
include/linux/fs_pin.h
include/linux/ftrace.h
include/linux/huge_mm.h
include/linux/hw_random.h
include/linux/hwspinlock.h
include/linux/init.h
include/linux/intel_rapl.h [new file with mode: 0644]
include/linux/io.h
include/linux/iomap.h
include/linux/iova.h
include/linux/iversion.h
include/linux/kernel.h
include/linux/kprobes.h
include/linux/kvm_host.h
include/linux/libnvdimm.h
include/linux/lockdep.h
include/linux/lz4.h
include/linux/memory.h
include/linux/memory_hotplug.h
include/linux/migrate.h
include/linux/mm.h
include/linux/mmzone.h
include/linux/moduleloader.h
include/linux/msi.h
include/linux/mutex.h
include/linux/netfilter/nf_conntrack_h323_asn1.h
include/linux/nfs4.h
include/linux/nfs_fs.h
include/linux/nfs_fs_sb.h
include/linux/node.h
include/linux/ntb.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/pfn_t.h
include/linux/pid.h
include/linux/platform_data/dma-imx.h
include/linux/platform_data/ti-sysc.h
include/linux/platform_data/video-clcd-versatile.h [deleted file]
include/linux/platform_data/x86/asus-wmi.h
include/linux/platform_device.h
include/linux/pm_qos.h
include/linux/poison.h
include/linux/pseudo_fs.h [new file with mode: 0644]
include/linux/ramfs.h
include/linux/rbtree.h
include/linux/rbtree_augmented.h
include/linux/remoteproc.h
include/linux/rwsem.h
include/linux/sched/isolation.h
include/linux/sched/signal.h
include/linux/sched/task.h
include/linux/scmi_protocol.h
include/linux/serial_core.h
include/linux/signal.h
include/linux/soc/qcom/mdt_loader.h
include/linux/soc/ti/ti_sci_protocol.h
include/linux/sudmac.h [deleted file]
include/linux/sunrpc/bc_xprt.h
include/linux/sunrpc/clnt.h
include/linux/sunrpc/metrics.h
include/linux/sunrpc/sched.h
include/linux/sunrpc/xprt.h
include/linux/sunrpc/xprtmultipath.h
include/linux/sunrpc/xprtsock.h
include/linux/swapops.h
include/linux/syscalls.h
include/linux/sysctl.h
include/linux/thermal.h
include/linux/trace_events.h
include/linux/tracehook.h
include/linux/uaccess.h
include/memory/jedec_ddr.h [deleted file]
include/net/cfg80211.h
include/net/flow_offload.h
include/net/netfilter/nf_conntrack_expect.h
include/net/netfilter/nf_conntrack_synproxy.h
include/net/netfilter/nf_tables.h
include/net/pkt_cls.h
include/net/sch_generic.h
include/net/tcp.h
include/scsi/scsi_host.h
include/soc/fsl/bman.h
include/soc/fsl/qman.h
include/sound/compress_driver.h
include/sound/hda_codec.h
include/trace/events/btrfs.h
include/trace/events/rpcrdma.h
include/uapi/asm-generic/mman-common.h
include/uapi/asm-generic/mman.h
include/uapi/asm-generic/unistd.h
include/uapi/drm/amdgpu_drm.h
include/uapi/linux/adfs_fs.h
include/uapi/linux/bpf.h
include/uapi/linux/btrfs_tree.h
include/uapi/linux/coda.h
include/uapi/linux/coda_psdev.h [deleted file]
include/uapi/linux/kvm.h
include/uapi/linux/magic.h
include/uapi/linux/nl80211.h
include/uapi/linux/pkt_sched.h
include/uapi/linux/ptrace.h
include/uapi/linux/videodev2.h
include/uapi/linux/virtio_ids.h
include/uapi/linux/virtio_iommu.h [new file with mode: 0644]
include/uapi/linux/virtio_pmem.h [new file with mode: 0644]
include/uapi/rdma/rdma_user_ioctl_cmds.h
include/xen/balloon.h
include/xen/events.h
include/xen/tmem.h [deleted file]
init/Kconfig
init/do_mounts.c
init/main.c
ipc/ipc_sysctl.c
ipc/mqueue.c
kernel/Kconfig.preempt
kernel/bpf/btf.c
kernel/bpf/core.c
kernel/bpf/verifier.c
kernel/cgroup/cgroup.c
kernel/cgroup/cpuset.c
kernel/cred.c
kernel/dma/Kconfig
kernel/dma/direct.c
kernel/dma/swiotlb.c
kernel/events/core.c
kernel/exit.c
kernel/fork.c
kernel/kprobes.c
kernel/locking/mutex.c
kernel/locking/rtmutex.c
kernel/memremap.c
kernel/module.c
kernel/padata.c
kernel/panic.c
kernel/pid.c
kernel/pid_namespace.c
kernel/ptrace.c
kernel/resource.c
kernel/sched/isolation.c
kernel/signal.c
kernel/smp.c
kernel/stacktrace.c
kernel/sysctl.c
kernel/trace/Kconfig
kernel/trace/ftrace.c
kernel/trace/ring_buffer.c
kernel/trace/trace.c
kernel/trace/trace_event_perf.c
kernel/trace/trace_events.c
kernel/trace/trace_events_filter.c
kernel/trace/trace_kprobe.c
kernel/trace/trace_output.c
kernel/trace/trace_probe.c
kernel/trace/trace_probe.h
kernel/trace/trace_probe_tmpl.h
kernel/trace/trace_uprobe.c
kernel/tracepoint.c
kernel/ucount.c
lib/Kconfig
lib/Kconfig.debug
lib/Makefile
lib/ioremap.c
lib/jedec_ddr_data.c [deleted file]
lib/mpi/longlong.h
lib/rbtree.c
lib/string.c
lib/string_helpers.c
lib/test_meminit.c [new file with mode: 0644]
lib/test_overflow.c
lib/test_string.c
mm/Kconfig
mm/cma.c
mm/gup.c
mm/huge_memory.c
mm/maccess.c
mm/memcontrol.c
mm/memory.c
mm/memory_hotplug.c
mm/migrate.c
mm/nommu.c
mm/page_alloc.c
mm/shmem.c
mm/slab_common.c
mm/sparse-vmemmap.c
mm/sparse.c
mm/swap.c
mm/util.c
mm/vmscan.c
mm/z3fold.c
mm/zsmalloc.c
net/bridge/netfilter/Kconfig
net/ceph/Makefile
net/ceph/cls_lock_client.c
net/ceph/decode.c [new file with mode: 0644]
net/ceph/messenger.c
net/ceph/mon_client.c
net/ceph/osd_client.c
net/ceph/osdmap.c
net/ceph/pagevec.c
net/ceph/striper.c
net/core/filter.c
net/core/flow_offload.c
net/core/neighbour.c
net/core/skbuff.c
net/core/sysctl_net_core.c
net/dccp/sysctl.c
net/dsa/slave.c
net/dsa/tag_sja1105.c
net/ipv4/fib_frontend.c
net/ipv4/netfilter/ipt_CLUSTERIP.c
net/ipv4/netfilter/ipt_SYNPROXY.c
net/ipv4/netfilter/ipt_rpfilter.c
net/ipv4/netfilter/nf_nat_h323.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp.c
net/ipv4/tcp_cong.c
net/ipv4/tcp_output.c
net/ipv4/udp.c
net/ipv6/addrconf.c
net/ipv6/ip6_fib.c
net/ipv6/netfilter/ip6t_SYNPROXY.c
net/ipv6/netfilter/ip6t_rpfilter.c
net/ipv6/route.c
net/ipv6/sit.c
net/ipv6/sysctl_net_ipv6.c
net/mac80211/cfg.c
net/mac80211/driver-ops.c
net/mpls/af_mpls.c
net/netfilter/Kconfig
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/ipvs/ip_vs_nfct.c
net/netfilter/nf_conntrack_amanda.c
net/netfilter/nf_conntrack_broadcast.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_conntrack_ftp.c
net/netfilter/nf_conntrack_h323_asn1.c
net/netfilter/nf_conntrack_h323_main.c
net/netfilter/nf_conntrack_irc.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_pptp.c
net/netfilter/nf_conntrack_proto_gre.c
net/netfilter/nf_conntrack_proto_icmp.c
net/netfilter/nf_conntrack_proto_tcp.c
net/netfilter/nf_conntrack_sane.c
net/netfilter/nf_conntrack_sip.c
net/netfilter/nf_conntrack_tftp.c
net/netfilter/nf_nat_amanda.c
net/netfilter/nf_nat_core.c
net/netfilter/nf_nat_ftp.c
net/netfilter/nf_nat_irc.c
net/netfilter/nf_nat_sip.c
net/netfilter/nf_nat_tftp.c
net/netfilter/nf_synproxy_core.c
net/netfilter/nf_tables_api.c
net/netfilter/nf_tables_offload.c
net/netfilter/nfnetlink.c
net/netfilter/nft_chain_filter.c
net/netfilter/nft_chain_nat.c
net/netfilter/nft_ct.c
net/netfilter/nft_hash.c
net/netfilter/nft_meta.c
net/netfilter/nft_redir.c
net/netfilter/nft_synproxy.c
net/openvswitch/flow.c
net/openvswitch/flow.h
net/openvswitch/flow_table.c
net/rds/ib.h
net/rds/ib_cm.c
net/rds/ib_frmr.c
net/rds/ib_mr.h
net/rds/ib_rdma.c
net/rxrpc/sysctl.c
net/sched/Kconfig
net/sched/cls_api.c
net/sched/cls_bpf.c
net/sched/cls_flower.c
net/sched/cls_matchall.c
net/sched/cls_u32.c
net/sched/sch_fq_codel.c
net/sched/sch_sfq.c
net/sched/sch_taprio.c
net/sctp/sm_make_chunk.c
net/sctp/sysctl.c
net/socket.c
net/sunrpc/Kconfig
net/sunrpc/backchannel_rqst.c
net/sunrpc/clnt.c
net/sunrpc/debugfs.c
net/sunrpc/rpc_pipe.c
net/sunrpc/sched.c
net/sunrpc/stats.c
net/sunrpc/svc.c
net/sunrpc/xprt.c
net/sunrpc/xprtmultipath.c
net/sunrpc/xprtrdma/backchannel.c
net/sunrpc/xprtrdma/frwr_ops.c
net/sunrpc/xprtrdma/rpc_rdma.c
net/sunrpc/xprtrdma/svc_rdma_backchannel.c
net/sunrpc/xprtrdma/svc_rdma_transport.c
net/sunrpc/xprtrdma/transport.c
net/sunrpc/xprtrdma/verbs.c
net/sunrpc/xprtrdma/xprt_rdma.h
net/sunrpc/xprtsock.c
net/tipc/node.c
net/tipc/sysctl.c
net/tipc/topsrv.c
net/xdp/xdp_umem.c
net/xdp/xsk.c
samples/Kconfig
samples/bpf/Makefile
samples/vfio-mdev/mbochs.c
samples/vfio-mdev/mtty.c
scripts/Kbuild.include
scripts/Makefile.build
scripts/Makefile.lib
scripts/Makefile.modbuiltin
scripts/Makefile.modinst
scripts/Makefile.modpost
scripts/Makefile.modsign
scripts/adjust_autoksyms.sh
scripts/checkpatch.pl
scripts/coccinelle/api/devm_platform_ioremap_resource.cocci [new file with mode: 0644]
scripts/coccinelle/free/devm_free.cocci
scripts/export_report.pl
scripts/gcc-plugins/Kconfig
scripts/gdb/linux/device.py [new file with mode: 0644]
scripts/gdb/linux/genpd.py [new file with mode: 0644]
scripts/gdb/vmlinux-gdb.py
scripts/get_maintainer.pl
scripts/kconfig/Makefile
scripts/kconfig/confdata.c
scripts/kconfig/expr.h
scripts/mod/sumversion.c
scripts/modules-check.sh
scripts/package/builddeb
scripts/package/mkdebian
scripts/package/mkspec
security/Kconfig
security/apparmor/apparmorfs.c
security/device_cgroup.c
security/inode.c
security/keys/sysctl.c
security/loadpin/loadpin.c
security/safesetid/lsm.c
security/safesetid/lsm.h
security/safesetid/securityfs.c
security/selinux/selinuxfs.c
security/smack/smackfs.c
security/yama/yama_lsm.c
sound/ac97/bus.c
sound/core/compress_offload.c
sound/core/pcm_native.c
sound/core/seq/seq_clientmgr.c
sound/pci/au88x0/au88x0_a3d.c
sound/pci/emu10k1/emu10k1x.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/lx6464es/lx6464es.c
sound/pci/rme9652/rme9652.c
sound/ppc/snd_ps3.c
sound/soc/qcom/qdsp6/q6asm.c
sound/usb/line6/podhd.c
sound/usb/line6/variax.c
tools/bpf/bpftool/main.h
tools/include/uapi/linux/bpf.h
tools/include/uapi/linux/kvm.h
tools/lib/bpf/libbpf.c
tools/lib/bpf/xsk.c
tools/objtool/arch.h
tools/objtool/arch/x86/decode.c
tools/objtool/check.c
tools/objtool/check.h
tools/objtool/elf.c
tools/objtool/elf.h
tools/perf/Documentation/perf-probe.txt
tools/perf/builtin-script.c
tools/perf/builtin-trace.c
tools/perf/builtin-version.c
tools/perf/pmu-events/arch/s390/cf_m8561/basic.json [new file with mode: 0644]
tools/perf/pmu-events/arch/s390/cf_m8561/crypto.json [new file with mode: 0644]
tools/perf/pmu-events/arch/s390/cf_m8561/crypto6.json [new file with mode: 0644]
tools/perf/pmu-events/arch/s390/cf_m8561/extended.json [new file with mode: 0644]
tools/perf/pmu-events/arch/s390/mapfile.csv
tools/perf/scripts/python/export-to-postgresql.py
tools/perf/scripts/python/export-to-sqlite.py
tools/perf/scripts/python/exported-sql-viewer.py
tools/perf/tests/builtin-test.c
tools/perf/util/Build
tools/perf/util/cs-etm.c
tools/perf/util/db-export.c
tools/perf/util/db-export.h
tools/perf/util/probe-event.c
tools/perf/util/probe-event.h
tools/perf/util/probe-file.c
tools/perf/util/probe-file.h
tools/perf/util/probe-finder.c
tools/perf/util/rlimit.c [new file with mode: 0644]
tools/perf/util/rlimit.h [new file with mode: 0644]
tools/perf/util/scripting-engines/trace-event-python.c
tools/perf/util/trace-event.h
tools/power/cpupower/debug/kernel/Makefile
tools/testing/ktest/config-bisect.pl
tools/testing/selftests/bpf/Makefile
tools/testing/selftests/bpf/bpf_helpers.h
tools/testing/selftests/bpf/prog_tests/attach_probe.c
tools/testing/selftests/bpf/prog_tests/perf_buffer.c
tools/testing/selftests/bpf/prog_tests/send_signal.c
tools/testing/selftests/bpf/progs/loop1.c
tools/testing/selftests/bpf/progs/loop2.c
tools/testing/selftests/bpf/progs/loop3.c
tools/testing/selftests/bpf/progs/test_get_stack_rawtp.c
tools/testing/selftests/bpf/progs/test_stacktrace_build_id.c
tools/testing/selftests/bpf/progs/test_stacktrace_map.c
tools/testing/selftests/bpf/progs/test_xdp_noinline.c
tools/testing/selftests/bpf/test_btf.c
tools/testing/selftests/bpf/test_progs.h
tools/testing/selftests/bpf/test_verifier.c
tools/testing/selftests/bpf/verifier/array_access.c
tools/testing/selftests/bpf/verifier/value_ptr_arith.c
tools/testing/selftests/bpf/verifier/wide_access.c [new file with mode: 0644]
tools/testing/selftests/bpf/verifier/wide_store.c [deleted file]
tools/testing/selftests/ftrace/ftracetest
tools/testing/selftests/ftrace/test.d/functions
tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_user.tc [new file with mode: 0644]
tools/testing/selftests/kvm/Makefile
tools/testing/selftests/kvm/include/kvm_util.h
tools/testing/selftests/kvm/include/s390x/processor.h [new file with mode: 0644]
tools/testing/selftests/kvm/kvm_create_max_vcpus.c [new file with mode: 0644]
tools/testing/selftests/kvm/lib/aarch64/processor.c
tools/testing/selftests/kvm/lib/kvm_util.c
tools/testing/selftests/kvm/lib/s390x/processor.c [new file with mode: 0644]
tools/testing/selftests/kvm/lib/x86_64/processor.c
tools/testing/selftests/kvm/lib/x86_64/vmx.c
tools/testing/selftests/kvm/s390x/sync_regs_test.c [new file with mode: 0644]
tools/testing/selftests/kvm/x86_64/kvm_create_max_vcpus.c [deleted file]
tools/testing/selftests/net/fib_tests.sh
tools/testing/selftests/ntb/ntb_test.sh
tools/testing/selftests/proc/.gitignore
tools/testing/selftests/proc/Makefile
tools/testing/selftests/proc/proc-pid-vm.c
tools/testing/selftests/proc/setns-sysvipc.c [new file with mode: 0644]
tools/testing/selftests/ptrace/.gitignore
tools/testing/selftests/ptrace/Makefile
tools/testing/selftests/ptrace/get_syscall_info.c [new file with mode: 0644]
tools/testing/selftests/safesetid/safesetid-test.c
tools/testing/selftests/seccomp/seccomp_bpf.c
tools/testing/selftests/x86/fsgsbase.c
tools/testing/selftests/zram/README
usr/Kconfig
usr/include/Makefile
virt/kvm/arm/arm.c
virt/kvm/arm/vgic/vgic-mmio-v3.c
virt/kvm/arm/vgic/vgic.h
virt/kvm/kvm_main.c

index 7587ef5..8f5422c 100644 (file)
@@ -30,6 +30,7 @@
 *.lz4
 *.lzma
 *.lzo
+*.mod
 *.mod.c
 *.o
 *.o.*
diff --git a/CREDITS b/CREDITS
index beac0c8..a738760 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1770,7 +1770,6 @@ S: USA
 
 N: Dave Jones
 E: davej@codemonkey.org.uk
-W: http://www.codemonkey.org.uk
 D: Assorted VIA x86 support.
 D: 2.5 AGPGART overhaul.
 D: CPUFREQ maintenance.
@@ -3120,7 +3119,7 @@ S: France
 N: Rik van Riel
 E: riel@redhat.com
 W: http://www.surriel.com/
-D: Linux-MM site, Documentation/sysctl/*, swap/mm readaround
+D: Linux-MM site, Documentation/admin-guide/sysctl/*, swap/mm readaround
 D: kswapd fixes, random kernel hacker, rmap VM,
 D: nl.linux.org administrator, minor scheduler additions
 S: Red Hat Boston
index 40d41ea..e0d4e5e 100644 (file)
@@ -11,7 +11,7 @@ Description:
   Kernel code may export it for complete or partial access.
 
   GPIOs are identified as they are inside the kernel, using integers in
-  the range 0..INT_MAX.  See Documentation/gpio for more information.
+  the range 0..INT_MAX.  See Documentation/admin-guide/gpio for more information.
 
     /sys/class/gpio
        /export ... asks the kernel to export a GPIO to userspace
index 3ce6231..9c08c7f 100644 (file)
@@ -1,6 +1,6 @@
 rfkill - radio frequency (RF) connector kill switch support
 
-For details to this subsystem look at Documentation/rfkill.txt.
+For details to this subsystem look at Documentation/driver-api/rfkill.rst.
 
 What:          /sys/class/rfkill/rfkill[0-9]+/claim
 Date:          09-Jul-2007
index 80151a4..5b154f9 100644 (file)
@@ -1,6 +1,6 @@
 rfkill - radio frequency (RF) connector kill switch support
 
-For details to this subsystem look at Documentation/rfkill.txt.
+For details to this subsystem look at Documentation/driver-api/rfkill.rst.
 
 For the deprecated /sys/class/rfkill/*/claim knobs of this interface look in
 Documentation/ABI/removed/sysfs-class-rfkill.
index f7ce68f..df8413c 100644 (file)
@@ -61,7 +61,7 @@ Date:         October 2002
 Contact:       Linux Memory Management list <linux-mm@kvack.org>
 Description:
                The node's hit/miss statistics, in units of pages.
-               See Documentation/numastat.txt
+               See Documentation/admin-guide/numastat.rst
 
 What:          /sys/devices/system/node/nodeX/distance
 Date:          October 2002
index abac31d..2c44b4f 100644 (file)
@@ -29,4 +29,4 @@ Description:
                17 - sectors discarded
                18 - time spent discarding
 
-               For more details refer to Documentation/iostats.txt
+               For more details refer to Documentation/admin-guide/iostats.rst
index dfad742..f8c7c71 100644 (file)
@@ -15,7 +15,7 @@ Description:
                 9 - I/Os currently in progress
                10 - time spent doing I/Os (ms)
                11 - weighted time spent doing I/Os (ms)
-               For more details refer Documentation/iostats.txt
+               For more details refer Documentation/admin-guide/iostats.rst
 
 
 What:          /sys/block/<disk>/<part>/stat
index 82ef6ea..17f2bc7 100644 (file)
@@ -45,7 +45,7 @@ Description:
                - Values below -2 are rejected with -EINVAL
 
                For more information, see
-               Documentation/laptops/disk-shock-protection.txt
+               Documentation/admin-guide/laptops/disk-shock-protection.rst
 
 
 What:          /sys/block/*/device/ncq_prio_enable
index 48cb4c1..76c7a66 100644 (file)
@@ -1,6 +1,6 @@
 switchtec - Microsemi Switchtec PCI Switch Management Endpoint
 
-For details on this subsystem look at Documentation/switchtec.txt.
+For details on this subsystem look at Documentation/driver-api/switchtec.rst.
 
 What:          /sys/class/switchtec
 Date:          05-Jan-2017
index d404603..5f7d7b1 100644 (file)
@@ -34,7 +34,7 @@ Description:  CPU topology files that describe kernel limits related to
                present: cpus that have been identified as being present in
                the system.
 
-               See Documentation/cputopology.txt for more information.
+               See Documentation/admin-guide/cputopology.rst for more information.
 
 
 What:          /sys/devices/system/cpu/probe
@@ -103,7 +103,7 @@ Description:        CPU topology files that describe a logical CPU's relationship
                thread_siblings_list: human-readable list of cpu#'s hardware
                threads within the same core as cpu#
 
-               See Documentation/cputopology.txt for more information.
+               See Documentation/admin-guide/cputopology.rst for more information.
 
 
 What:          /sys/devices/system/cpu/cpuidle/current_driver
index cd9d667..8b0e820 100644 (file)
@@ -31,7 +31,7 @@ Description:
                To control the LED display, use the following :
                    echo 0x0T000DDD > /sys/devices/platform/asus_laptop/
                where T control the 3 letters display, and DDD the 3 digits display.
-               The DDD table can be found in Documentation/laptops/asus-laptop.txt
+               The DDD table can be found in Documentation/admin-guide/laptops/asus-laptop.rst
 
 What:          /sys/devices/platform/asus_laptop/bluetooth
 Date:          January 2007
index 87ae5cc..9e99f29 100644 (file)
@@ -37,9 +37,9 @@ Contact:      "AceLan Kao" <acelan.kao@canonical.com>
 Description:
                Resume on lid open. 1 means on, 0 means off.
 
-What:          /sys/devices/platform/<platform>/fan_mode
-Date:          Apr 2019
-KernelVersion: 5.2
+What:          /sys/devices/platform/<platform>/fan_boost_mode
+Date:          Sep 2019
+KernelVersion: 5.3
 Contact:       "Yurii Pavlovskyi" <yurii.pavlovskyi@gmail.com>
 Description:
                Fan boost mode:
index cb712a0..358d495 100644 (file)
@@ -212,7 +212,7 @@ The standard 64-bit addressing device would do something like this::
 
 If the device only supports 32-bit addressing for descriptors in the
 coherent allocations, but supports full 64-bits for streaming mappings
-it would look like this:
+it would look like this::
 
        if (dma_set_mask(dev, DMA_BIT_MASK(64))) {
                dev_warn(dev, "mydev: No suitable DMA available\n");
diff --git a/Documentation/EDID/howto.rst b/Documentation/EDID/howto.rst
deleted file mode 100644 (file)
index 725fd49..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-:orphan:
-
-====
-EDID
-====
-
-In the good old days when graphics parameters were configured explicitly
-in a file called xorg.conf, even broken hardware could be managed.
-
-Today, with the advent of Kernel Mode Setting, a graphics board is
-either correctly working because all components follow the standards -
-or the computer is unusable, because the screen remains dark after
-booting or it displays the wrong area. Cases when this happens are:
-- The graphics board does not recognize the monitor.
-- The graphics board is unable to detect any EDID data.
-- The graphics board incorrectly forwards EDID data to the driver.
-- The monitor sends no or bogus EDID data.
-- A KVM sends its own EDID data instead of querying the connected monitor.
-Adding the kernel parameter "nomodeset" helps in most cases, but causes
-restrictions later on.
-
-As a remedy for such situations, the kernel configuration item
-CONFIG_DRM_LOAD_EDID_FIRMWARE was introduced. It allows to provide an
-individually prepared or corrected EDID data set in the /lib/firmware
-directory from where it is loaded via the firmware interface. The code
-(see drivers/gpu/drm/drm_edid_load.c) contains built-in data sets for
-commonly used screen resolutions (800x600, 1024x768, 1280x1024, 1600x1200,
-1680x1050, 1920x1080) as binary blobs, but the kernel source tree does
-not contain code to create these data. In order to elucidate the origin
-of the built-in binary EDID blobs and to facilitate the creation of
-individual data for a specific misbehaving monitor, commented sources
-and a Makefile environment are given here.
-
-To create binary EDID and C source code files from the existing data
-material, simply type "make".
-
-If you want to create your own EDID file, copy the file 1024x768.S,
-replace the settings with your own data and add a new target to the
-Makefile. Please note that the EDID data structure expects the timing
-values in a different way as compared to the standard X11 format.
-
-X11:
-  HTimings:
-    hdisp hsyncstart hsyncend htotal
-  VTimings:
-    vdisp vsyncstart vsyncend vtotal
-
-EDID::
-
-  #define XPIX hdisp
-  #define XBLANK htotal-hdisp
-  #define XOFFSET hsyncstart-hdisp
-  #define XPULSE hsyncend-hsyncstart
-
-  #define YPIX vdisp
-  #define YBLANK vtotal-vdisp
-  #define YOFFSET vsyncstart-vdisp
-  #define YPULSE vsyncend-vsyncstart
diff --git a/Documentation/accelerators/ocxl.rst b/Documentation/accelerators/ocxl.rst
deleted file mode 100644 (file)
index b1cea19..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-:orphan:
-
-========================================================
-OpenCAPI (Open Coherent Accelerator Processor Interface)
-========================================================
-
-OpenCAPI is an interface between processors and accelerators. It aims
-at being low-latency and high-bandwidth. The specification is
-developed by the `OpenCAPI Consortium <http://opencapi.org/>`_.
-
-It allows an accelerator (which could be a FPGA, ASICs, ...) to access
-the host memory coherently, using virtual addresses. An OpenCAPI
-device can also host its own memory, that can be accessed from the
-host.
-
-OpenCAPI is known in linux as 'ocxl', as the open, processor-agnostic
-evolution of 'cxl' (the driver for the IBM CAPI interface for
-powerpc), which was named that way to avoid confusion with the ISDN
-CAPI subsystem.
-
-
-High-level view
-===============
-
-OpenCAPI defines a Data Link Layer (DL) and Transaction Layer (TL), to
-be implemented on top of a physical link. Any processor or device
-implementing the DL and TL can start sharing memory.
-
-::
-
-  +-----------+                         +-------------+
-  |           |                         |             |
-  |           |                         | Accelerated |
-  | Processor |                         |  Function   |
-  |           |  +--------+             |    Unit     |  +--------+
-  |           |--| Memory |             |    (AFU)    |--| Memory |
-  |           |  +--------+             |             |  +--------+
-  +-----------+                         +-------------+
-       |                                       |
-  +-----------+                         +-------------+
-  |    TL     |                         |    TLX      |
-  +-----------+                         +-------------+
-       |                                       |
-  +-----------+                         +-------------+
-  |    DL     |                         |    DLX      |
-  +-----------+                         +-------------+
-       |                                       |
-       |                   PHY                 |
-       +---------------------------------------+
-
-
-
-Device discovery
-================
-
-OpenCAPI relies on a PCI-like configuration space, implemented on the
-device. So the host can discover AFUs by querying the config space.
-
-OpenCAPI devices in Linux are treated like PCI devices (with a few
-caveats). The firmware is expected to abstract the hardware as if it
-was a PCI link. A lot of the existing PCI infrastructure is reused:
-devices are scanned and BARs are assigned during the standard PCI
-enumeration. Commands like 'lspci' can therefore be used to see what
-devices are available.
-
-The configuration space defines the AFU(s) that can be found on the
-physical adapter, such as its name, how many memory contexts it can
-work with, the size of its MMIO areas, ...
-
-
-
-MMIO
-====
-
-OpenCAPI defines two MMIO areas for each AFU:
-
-* the global MMIO area, with registers pertinent to the whole AFU.
-* a per-process MMIO area, which has a fixed size for each context.
-
-
-
-AFU interrupts
-==============
-
-OpenCAPI includes the possibility for an AFU to send an interrupt to a
-host process. It is done through a 'intrp_req' defined in the
-Transaction Layer, specifying a 64-bit object handle which defines the
-interrupt.
-
-The driver allows a process to allocate an interrupt and obtain its
-64-bit object handle, that can be passed to the AFU.
-
-
-
-char devices
-============
-
-The driver creates one char device per AFU found on the physical
-device. A physical device may have multiple functions and each
-function can have multiple AFUs. At the time of this writing though,
-it has only been tested with devices exporting only one AFU.
-
-Char devices can be found in /dev/ocxl/ and are named as:
-/dev/ocxl/<AFU name>.<location>.<index>
-
-where <AFU name> is a max 20-character long name, as found in the
-config space of the AFU.
-<location> is added by the driver and can help distinguish devices
-when a system has more than one instance of the same OpenCAPI device.
-<index> is also to help distinguish AFUs in the unlikely case where a
-device carries multiple copies of the same AFU.
-
-
-
-Sysfs class
-===========
-
-An ocxl class is added for the devices representing the AFUs. See
-/sys/class/ocxl. The layout is described in
-Documentation/ABI/testing/sysfs-class-ocxl
-
-
-
-User API
-========
-
-open
-----
-
-Based on the AFU definition found in the config space, an AFU may
-support working with more than one memory context, in which case the
-associated char device may be opened multiple times by different
-processes.
-
-
-ioctl
------
-
-OCXL_IOCTL_ATTACH:
-
-  Attach the memory context of the calling process to the AFU so that
-  the AFU can access its memory.
-
-OCXL_IOCTL_IRQ_ALLOC:
-
-  Allocate an AFU interrupt and return an identifier.
-
-OCXL_IOCTL_IRQ_FREE:
-
-  Free a previously allocated AFU interrupt.
-
-OCXL_IOCTL_IRQ_SET_FD:
-
-  Associate an event fd to an AFU interrupt so that the user process
-  can be notified when the AFU sends an interrupt.
-
-OCXL_IOCTL_GET_METADATA:
-
-  Obtains configuration information from the card, such at the size of
-  MMIO areas, the AFU version, and the PASID for the current context.
-
-OCXL_IOCTL_ENABLE_P9_WAIT:
-
-  Allows the AFU to wake a userspace thread executing 'wait'. Returns
-  information to userspace to allow it to configure the AFU. Note that
-  this is only available on POWER9.
-
-OCXL_IOCTL_GET_FEATURES:
-
-  Reports on which CPU features that affect OpenCAPI are usable from
-  userspace.
-
-
-mmap
-----
-
-A process can mmap the per-process MMIO area for interactions with the
-AFU.
diff --git a/Documentation/accounting/cgroupstats.rst b/Documentation/accounting/cgroupstats.rst
new file mode 100644 (file)
index 0000000..b9afc48
--- /dev/null
@@ -0,0 +1,31 @@
+==================
+Control Groupstats
+==================
+
+Control Groupstats is inspired by the discussion at
+http://lkml.org/lkml/2007/4/11/187 and implements per cgroup statistics as
+suggested by Andrew Morton in http://lkml.org/lkml/2007/4/11/263.
+
+Per cgroup statistics infrastructure re-uses code from the taskstats
+interface. A new set of cgroup operations are registered with commands
+and attributes specific to cgroups. It should be very easy to
+extend per cgroup statistics, by adding members to the cgroupstats
+structure.
+
+The current model for cgroupstats is a pull, a push model (to post
+statistics on interesting events), should be very easy to add. Currently
+user space requests for statistics by passing the cgroup path.
+Statistics about the state of all the tasks in the cgroup is returned to
+user space.
+
+NOTE: We currently rely on delay accounting for extracting information
+about tasks blocked on I/O. If CONFIG_TASK_DELAY_ACCT is disabled, this
+information will not be available.
+
+To extract cgroup statistics a utility very similar to getdelays.c
+has been developed, the sample output of the utility is shown below::
+
+  ~/balbir/cgroupstats # ./getdelays  -C "/sys/fs/cgroup/a"
+  sleeping 1, blocked 0, running 1, stopped 0, uninterruptible 0
+  ~/balbir/cgroupstats # ./getdelays  -C "/sys/fs/cgroup"
+  sleeping 155, blocked 0, running 1, stopped 0, uninterruptible 2
diff --git a/Documentation/accounting/cgroupstats.txt b/Documentation/accounting/cgroupstats.txt
deleted file mode 100644 (file)
index d16a984..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-Control Groupstats is inspired by the discussion at
-http://lkml.org/lkml/2007/4/11/187 and implements per cgroup statistics as
-suggested by Andrew Morton in http://lkml.org/lkml/2007/4/11/263.
-
-Per cgroup statistics infrastructure re-uses code from the taskstats
-interface. A new set of cgroup operations are registered with commands
-and attributes specific to cgroups. It should be very easy to
-extend per cgroup statistics, by adding members to the cgroupstats
-structure.
-
-The current model for cgroupstats is a pull, a push model (to post
-statistics on interesting events), should be very easy to add. Currently
-user space requests for statistics by passing the cgroup path.
-Statistics about the state of all the tasks in the cgroup is returned to
-user space.
-
-NOTE: We currently rely on delay accounting for extracting information
-about tasks blocked on I/O. If CONFIG_TASK_DELAY_ACCT is disabled, this
-information will not be available.
-
-To extract cgroup statistics a utility very similar to getdelays.c
-has been developed, the sample output of the utility is shown below
-
-~/balbir/cgroupstats # ./getdelays  -C "/sys/fs/cgroup/a"
-sleeping 1, blocked 0, running 1, stopped 0, uninterruptible 0
-~/balbir/cgroupstats # ./getdelays  -C "/sys/fs/cgroup"
-sleeping 155, blocked 0, running 1, stopped 0, uninterruptible 2
diff --git a/Documentation/accounting/delay-accounting.rst b/Documentation/accounting/delay-accounting.rst
new file mode 100644 (file)
index 0000000..7cc7f58
--- /dev/null
@@ -0,0 +1,126 @@
+================
+Delay accounting
+================
+
+Tasks encounter delays in execution when they wait
+for some kernel resource to become available e.g. a
+runnable task may wait for a free CPU to run on.
+
+The per-task delay accounting functionality measures
+the delays experienced by a task while
+
+a) waiting for a CPU (while being runnable)
+b) completion of synchronous block I/O initiated by the task
+c) swapping in pages
+d) memory reclaim
+
+and makes these statistics available to userspace through
+the taskstats interface.
+
+Such delays provide feedback for setting a task's cpu priority,
+io priority and rss limit values appropriately. Long delays for
+important tasks could be a trigger for raising its corresponding priority.
+
+The functionality, through its use of the taskstats interface, also provides
+delay statistics aggregated for all tasks (or threads) belonging to a
+thread group (corresponding to a traditional Unix process). This is a commonly
+needed aggregation that is more efficiently done by the kernel.
+
+Userspace utilities, particularly resource management applications, can also
+aggregate delay statistics into arbitrary groups. To enable this, delay
+statistics of a task are available both during its lifetime as well as on its
+exit, ensuring continuous and complete monitoring can be done.
+
+
+Interface
+---------
+
+Delay accounting uses the taskstats interface which is described
+in detail in a separate document in this directory. Taskstats returns a
+generic data structure to userspace corresponding to per-pid and per-tgid
+statistics. The delay accounting functionality populates specific fields of
+this structure. See
+
+     include/linux/taskstats.h
+
+for a description of the fields pertaining to delay accounting.
+It will generally be in the form of counters returning the cumulative
+delay seen for cpu, sync block I/O, swapin, memory reclaim etc.
+
+Taking the difference of two successive readings of a given
+counter (say cpu_delay_total) for a task will give the delay
+experienced by the task waiting for the corresponding resource
+in that interval.
+
+When a task exits, records containing the per-task statistics
+are sent to userspace without requiring a command. If it is the last exiting
+task of a thread group, the per-tgid statistics are also sent. More details
+are given in the taskstats interface description.
+
+The getdelays.c userspace utility in tools/accounting directory allows simple
+commands to be run and the corresponding delay statistics to be displayed. It
+also serves as an example of using the taskstats interface.
+
+Usage
+-----
+
+Compile the kernel with::
+
+       CONFIG_TASK_DELAY_ACCT=y
+       CONFIG_TASKSTATS=y
+
+Delay accounting is enabled by default at boot up.
+To disable, add::
+
+   nodelayacct
+
+to the kernel boot options. The rest of the instructions
+below assume this has not been done.
+
+After the system has booted up, use a utility
+similar to  getdelays.c to access the delays
+seen by a given task or a task group (tgid).
+The utility also allows a given command to be
+executed and the corresponding delays to be
+seen.
+
+General format of the getdelays command::
+
+       getdelays [-t tgid] [-p pid] [-c cmd...]
+
+
+Get delays, since system boot, for pid 10::
+
+       # ./getdelays -p 10
+       (output similar to next case)
+
+Get sum of delays, since system boot, for all pids with tgid 5::
+
+       # ./getdelays -t 5
+
+
+       CPU     count   real total      virtual total   delay total
+               7876    92005750        100000000       24001500
+       IO      count   delay total
+               0       0
+       SWAP    count   delay total
+               0       0
+       RECLAIM count   delay total
+               0       0
+
+Get delays seen in executing a given simple command::
+
+  # ./getdelays -c ls /
+
+  bin   data1  data3  data5  dev  home  media  opt   root  srv        sys  usr
+  boot  data2  data4  data6  etc  lib   mnt    proc  sbin  subdomain  tmp  var
+
+
+  CPU  count   real total      virtual total   delay total
+       6       4000250         4000000         0
+  IO   count   delay total
+       0       0
+  SWAP count   delay total
+       0       0
+  RECLAIM      count   delay total
+       0       0
diff --git a/Documentation/accounting/delay-accounting.txt b/Documentation/accounting/delay-accounting.txt
deleted file mode 100644 (file)
index 042ea59..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-Delay accounting
-----------------
-
-Tasks encounter delays in execution when they wait
-for some kernel resource to become available e.g. a
-runnable task may wait for a free CPU to run on.
-
-The per-task delay accounting functionality measures
-the delays experienced by a task while
-
-a) waiting for a CPU (while being runnable)
-b) completion of synchronous block I/O initiated by the task
-c) swapping in pages
-d) memory reclaim
-
-and makes these statistics available to userspace through
-the taskstats interface.
-
-Such delays provide feedback for setting a task's cpu priority,
-io priority and rss limit values appropriately. Long delays for
-important tasks could be a trigger for raising its corresponding priority.
-
-The functionality, through its use of the taskstats interface, also provides
-delay statistics aggregated for all tasks (or threads) belonging to a
-thread group (corresponding to a traditional Unix process). This is a commonly
-needed aggregation that is more efficiently done by the kernel.
-
-Userspace utilities, particularly resource management applications, can also
-aggregate delay statistics into arbitrary groups. To enable this, delay
-statistics of a task are available both during its lifetime as well as on its
-exit, ensuring continuous and complete monitoring can be done.
-
-
-Interface
----------
-
-Delay accounting uses the taskstats interface which is described
-in detail in a separate document in this directory. Taskstats returns a
-generic data structure to userspace corresponding to per-pid and per-tgid
-statistics. The delay accounting functionality populates specific fields of
-this structure. See
-     include/linux/taskstats.h
-for a description of the fields pertaining to delay accounting.
-It will generally be in the form of counters returning the cumulative
-delay seen for cpu, sync block I/O, swapin, memory reclaim etc.
-
-Taking the difference of two successive readings of a given
-counter (say cpu_delay_total) for a task will give the delay
-experienced by the task waiting for the corresponding resource
-in that interval.
-
-When a task exits, records containing the per-task statistics
-are sent to userspace without requiring a command. If it is the last exiting
-task of a thread group, the per-tgid statistics are also sent. More details
-are given in the taskstats interface description.
-
-The getdelays.c userspace utility in tools/accounting directory allows simple
-commands to be run and the corresponding delay statistics to be displayed. It
-also serves as an example of using the taskstats interface.
-
-Usage
------
-
-Compile the kernel with
-       CONFIG_TASK_DELAY_ACCT=y
-       CONFIG_TASKSTATS=y
-
-Delay accounting is enabled by default at boot up.
-To disable, add
-   nodelayacct
-to the kernel boot options. The rest of the instructions
-below assume this has not been done.
-
-After the system has booted up, use a utility
-similar to  getdelays.c to access the delays
-seen by a given task or a task group (tgid).
-The utility also allows a given command to be
-executed and the corresponding delays to be
-seen.
-
-General format of the getdelays command
-
-getdelays [-t tgid] [-p pid] [-c cmd...]
-
-
-Get delays, since system boot, for pid 10
-# ./getdelays -p 10
-(output similar to next case)
-
-Get sum of delays, since system boot, for all pids with tgid 5
-# ./getdelays -t 5
-
-
-CPU    count   real total      virtual total   delay total
-       7876    92005750        100000000       24001500
-IO     count   delay total
-       0       0
-SWAP   count   delay total
-       0       0
-RECLAIM        count   delay total
-       0       0
-
-Get delays seen in executing a given simple command
-# ./getdelays -c ls /
-
-bin   data1  data3  data5  dev  home  media  opt   root  srv        sys  usr
-boot  data2  data4  data6  etc  lib   mnt    proc  sbin  subdomain  tmp  var
-
-
-CPU    count   real total      virtual total   delay total
-       6       4000250         4000000         0
-IO     count   delay total
-       0       0
-SWAP   count   delay total
-       0       0
-RECLAIM        count   delay total
-       0       0
diff --git a/Documentation/accounting/index.rst b/Documentation/accounting/index.rst
new file mode 100644 (file)
index 0000000..9369d8b
--- /dev/null
@@ -0,0 +1,14 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==========
+Accounting
+==========
+
+.. toctree::
+   :maxdepth: 1
+
+   cgroupstats
+   delay-accounting
+   psi
+   taskstats
+   taskstats-struct
diff --git a/Documentation/accounting/psi.rst b/Documentation/accounting/psi.rst
new file mode 100644 (file)
index 0000000..621111c
--- /dev/null
@@ -0,0 +1,182 @@
+================================
+PSI - Pressure Stall Information
+================================
+
+:Date: April, 2018
+:Author: Johannes Weiner <hannes@cmpxchg.org>
+
+When CPU, memory or IO devices are contended, workloads experience
+latency spikes, throughput losses, and run the risk of OOM kills.
+
+Without an accurate measure of such contention, users are forced to
+either play it safe and under-utilize their hardware resources, or
+roll the dice and frequently suffer the disruptions resulting from
+excessive overcommit.
+
+The psi feature identifies and quantifies the disruptions caused by
+such resource crunches and the time impact it has on complex workloads
+or even entire systems.
+
+Having an accurate measure of productivity losses caused by resource
+scarcity aids users in sizing workloads to hardware--or provisioning
+hardware according to workload demand.
+
+As psi aggregates this information in realtime, systems can be managed
+dynamically using techniques such as load shedding, migrating jobs to
+other systems or data centers, or strategically pausing or killing low
+priority or restartable batch jobs.
+
+This allows maximizing hardware utilization without sacrificing
+workload health or risking major disruptions such as OOM kills.
+
+Pressure interface
+==================
+
+Pressure information for each resource is exported through the
+respective file in /proc/pressure/ -- cpu, memory, and io.
+
+The format for CPU is as such::
+
+       some avg10=0.00 avg60=0.00 avg300=0.00 total=0
+
+and for memory and IO::
+
+       some avg10=0.00 avg60=0.00 avg300=0.00 total=0
+       full avg10=0.00 avg60=0.00 avg300=0.00 total=0
+
+The "some" line indicates the share of time in which at least some
+tasks are stalled on a given resource.
+
+The "full" line indicates the share of time in which all non-idle
+tasks are stalled on a given resource simultaneously. In this state
+actual CPU cycles are going to waste, and a workload that spends
+extended time in this state is considered to be thrashing. This has
+severe impact on performance, and it's useful to distinguish this
+situation from a state where some tasks are stalled but the CPU is
+still doing productive work. As such, time spent in this subset of the
+stall state is tracked separately and exported in the "full" averages.
+
+The ratios (in %) are tracked as recent trends over ten, sixty, and
+three hundred second windows, which gives insight into short term events
+as well as medium and long term trends. The total absolute stall time
+(in us) is tracked and exported as well, to allow detection of latency
+spikes which wouldn't necessarily make a dent in the time averages,
+or to average trends over custom time frames.
+
+Monitoring for pressure thresholds
+==================================
+
+Users can register triggers and use poll() to be woken up when resource
+pressure exceeds certain thresholds.
+
+A trigger describes the maximum cumulative stall time over a specific
+time window, e.g. 100ms of total stall time within any 500ms window to
+generate a wakeup event.
+
+To register a trigger user has to open psi interface file under
+/proc/pressure/ representing the resource to be monitored and write the
+desired threshold and time window. The open file descriptor should be
+used to wait for trigger events using select(), poll() or epoll().
+The following format is used::
+
+       <some|full> <stall amount in us> <time window in us>
+
+For example writing "some 150000 1000000" into /proc/pressure/memory
+would add 150ms threshold for partial memory stall measured within
+1sec time window. Writing "full 50000 1000000" into /proc/pressure/io
+would add 50ms threshold for full io stall measured within 1sec time window.
+
+Triggers can be set on more than one psi metric and more than one trigger
+for the same psi metric can be specified. However for each trigger a separate
+file descriptor is required to be able to poll it separately from others,
+therefore for each trigger a separate open() syscall should be made even
+when opening the same psi interface file.
+
+Monitors activate only when system enters stall state for the monitored
+psi metric and deactivates upon exit from the stall state. While system is
+in the stall state psi signal growth is monitored at a rate of 10 times per
+tracking window.
+
+The kernel accepts window sizes ranging from 500ms to 10s, therefore min
+monitoring update interval is 50ms and max is 1s. Min limit is set to
+prevent overly frequent polling. Max limit is chosen as a high enough number
+after which monitors are most likely not needed and psi averages can be used
+instead.
+
+When activated, psi monitor stays active for at least the duration of one
+tracking window to avoid repeated activations/deactivations when system is
+bouncing in and out of the stall state.
+
+Notifications to the userspace are rate-limited to one per tracking window.
+
+The trigger will de-register when the file descriptor used to define the
+trigger  is closed.
+
+Userspace monitor usage example
+===============================
+
+::
+
+  #include <errno.h>
+  #include <fcntl.h>
+  #include <stdio.h>
+  #include <poll.h>
+  #include <string.h>
+  #include <unistd.h>
+
+  /*
+   * Monitor memory partial stall with 1s tracking window size
+   * and 150ms threshold.
+   */
+  int main() {
+       const char trig[] = "some 150000 1000000";
+       struct pollfd fds;
+       int n;
+
+       fds.fd = open("/proc/pressure/memory", O_RDWR | O_NONBLOCK);
+       if (fds.fd < 0) {
+               printf("/proc/pressure/memory open error: %s\n",
+                       strerror(errno));
+               return 1;
+       }
+       fds.events = POLLPRI;
+
+       if (write(fds.fd, trig, strlen(trig) + 1) < 0) {
+               printf("/proc/pressure/memory write error: %s\n",
+                       strerror(errno));
+               return 1;
+       }
+
+       printf("waiting for events...\n");
+       while (1) {
+               n = poll(&fds, 1, -1);
+               if (n < 0) {
+                       printf("poll error: %s\n", strerror(errno));
+                       return 1;
+               }
+               if (fds.revents & POLLERR) {
+                       printf("got POLLERR, event source is gone\n");
+                       return 0;
+               }
+               if (fds.revents & POLLPRI) {
+                       printf("event triggered!\n");
+               } else {
+                       printf("unknown event received: 0x%x\n", fds.revents);
+                       return 1;
+               }
+       }
+
+       return 0;
+  }
+
+Cgroup2 interface
+=================
+
+In a system with a CONFIG_CGROUP=y kernel and the cgroup2 filesystem
+mounted, pressure stall information is also tracked for tasks grouped
+into cgroups. Each subdirectory in the cgroupfs mountpoint contains
+cpu.pressure, memory.pressure, and io.pressure files; the format is
+the same as the /proc/pressure/ files.
+
+Per-cgroup psi monitors can be specified and used the same way as
+system-wide ones.
diff --git a/Documentation/accounting/psi.txt b/Documentation/accounting/psi.txt
deleted file mode 100644 (file)
index 5cbe565..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-================================
-PSI - Pressure Stall Information
-================================
-
-:Date: April, 2018
-:Author: Johannes Weiner <hannes@cmpxchg.org>
-
-When CPU, memory or IO devices are contended, workloads experience
-latency spikes, throughput losses, and run the risk of OOM kills.
-
-Without an accurate measure of such contention, users are forced to
-either play it safe and under-utilize their hardware resources, or
-roll the dice and frequently suffer the disruptions resulting from
-excessive overcommit.
-
-The psi feature identifies and quantifies the disruptions caused by
-such resource crunches and the time impact it has on complex workloads
-or even entire systems.
-
-Having an accurate measure of productivity losses caused by resource
-scarcity aids users in sizing workloads to hardware--or provisioning
-hardware according to workload demand.
-
-As psi aggregates this information in realtime, systems can be managed
-dynamically using techniques such as load shedding, migrating jobs to
-other systems or data centers, or strategically pausing or killing low
-priority or restartable batch jobs.
-
-This allows maximizing hardware utilization without sacrificing
-workload health or risking major disruptions such as OOM kills.
-
-Pressure interface
-==================
-
-Pressure information for each resource is exported through the
-respective file in /proc/pressure/ -- cpu, memory, and io.
-
-The format for CPU is as such:
-
-some avg10=0.00 avg60=0.00 avg300=0.00 total=0
-
-and for memory and IO:
-
-some avg10=0.00 avg60=0.00 avg300=0.00 total=0
-full avg10=0.00 avg60=0.00 avg300=0.00 total=0
-
-The "some" line indicates the share of time in which at least some
-tasks are stalled on a given resource.
-
-The "full" line indicates the share of time in which all non-idle
-tasks are stalled on a given resource simultaneously. In this state
-actual CPU cycles are going to waste, and a workload that spends
-extended time in this state is considered to be thrashing. This has
-severe impact on performance, and it's useful to distinguish this
-situation from a state where some tasks are stalled but the CPU is
-still doing productive work. As such, time spent in this subset of the
-stall state is tracked separately and exported in the "full" averages.
-
-The ratios (in %) are tracked as recent trends over ten, sixty, and
-three hundred second windows, which gives insight into short term events
-as well as medium and long term trends. The total absolute stall time
-(in us) is tracked and exported as well, to allow detection of latency
-spikes which wouldn't necessarily make a dent in the time averages,
-or to average trends over custom time frames.
-
-Monitoring for pressure thresholds
-==================================
-
-Users can register triggers and use poll() to be woken up when resource
-pressure exceeds certain thresholds.
-
-A trigger describes the maximum cumulative stall time over a specific
-time window, e.g. 100ms of total stall time within any 500ms window to
-generate a wakeup event.
-
-To register a trigger user has to open psi interface file under
-/proc/pressure/ representing the resource to be monitored and write the
-desired threshold and time window. The open file descriptor should be
-used to wait for trigger events using select(), poll() or epoll().
-The following format is used:
-
-<some|full> <stall amount in us> <time window in us>
-
-For example writing "some 150000 1000000" into /proc/pressure/memory
-would add 150ms threshold for partial memory stall measured within
-1sec time window. Writing "full 50000 1000000" into /proc/pressure/io
-would add 50ms threshold for full io stall measured within 1sec time window.
-
-Triggers can be set on more than one psi metric and more than one trigger
-for the same psi metric can be specified. However for each trigger a separate
-file descriptor is required to be able to poll it separately from others,
-therefore for each trigger a separate open() syscall should be made even
-when opening the same psi interface file.
-
-Monitors activate only when system enters stall state for the monitored
-psi metric and deactivates upon exit from the stall state. While system is
-in the stall state psi signal growth is monitored at a rate of 10 times per
-tracking window.
-
-The kernel accepts window sizes ranging from 500ms to 10s, therefore min
-monitoring update interval is 50ms and max is 1s. Min limit is set to
-prevent overly frequent polling. Max limit is chosen as a high enough number
-after which monitors are most likely not needed and psi averages can be used
-instead.
-
-When activated, psi monitor stays active for at least the duration of one
-tracking window to avoid repeated activations/deactivations when system is
-bouncing in and out of the stall state.
-
-Notifications to the userspace are rate-limited to one per tracking window.
-
-The trigger will de-register when the file descriptor used to define the
-trigger  is closed.
-
-Userspace monitor usage example
-===============================
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <poll.h>
-#include <string.h>
-#include <unistd.h>
-
-/*
- * Monitor memory partial stall with 1s tracking window size
- * and 150ms threshold.
- */
-int main() {
-       const char trig[] = "some 150000 1000000";
-       struct pollfd fds;
-       int n;
-
-       fds.fd = open("/proc/pressure/memory", O_RDWR | O_NONBLOCK);
-       if (fds.fd < 0) {
-               printf("/proc/pressure/memory open error: %s\n",
-                       strerror(errno));
-               return 1;
-       }
-       fds.events = POLLPRI;
-
-       if (write(fds.fd, trig, strlen(trig) + 1) < 0) {
-               printf("/proc/pressure/memory write error: %s\n",
-                       strerror(errno));
-               return 1;
-       }
-
-       printf("waiting for events...\n");
-       while (1) {
-               n = poll(&fds, 1, -1);
-               if (n < 0) {
-                       printf("poll error: %s\n", strerror(errno));
-                       return 1;
-               }
-               if (fds.revents & POLLERR) {
-                       printf("got POLLERR, event source is gone\n");
-                       return 0;
-               }
-               if (fds.revents & POLLPRI) {
-                       printf("event triggered!\n");
-               } else {
-                       printf("unknown event received: 0x%x\n", fds.revents);
-                       return 1;
-               }
-       }
-
-       return 0;
-}
-
-Cgroup2 interface
-=================
-
-In a system with a CONFIG_CGROUP=y kernel and the cgroup2 filesystem
-mounted, pressure stall information is also tracked for tasks grouped
-into cgroups. Each subdirectory in the cgroupfs mountpoint contains
-cpu.pressure, memory.pressure, and io.pressure files; the format is
-the same as the /proc/pressure/ files.
-
-Per-cgroup psi monitors can be specified and used the same way as
-system-wide ones.
diff --git a/Documentation/accounting/taskstats-struct.rst b/Documentation/accounting/taskstats-struct.rst
new file mode 100644 (file)
index 0000000..ca90fd4
--- /dev/null
@@ -0,0 +1,199 @@
+====================
+The struct taskstats
+====================
+
+This document contains an explanation of the struct taskstats fields.
+
+There are three different groups of fields in the struct taskstats:
+
+1) Common and basic accounting fields
+    If CONFIG_TASKSTATS is set, the taskstats interface is enabled and
+    the common fields and basic accounting fields are collected for
+    delivery at do_exit() of a task.
+2) Delay accounting fields
+    These fields are placed between::
+
+       /* Delay accounting fields start */
+
+    and::
+
+       /* Delay accounting fields end */
+
+    Their values are collected if CONFIG_TASK_DELAY_ACCT is set.
+3) Extended accounting fields
+    These fields are placed between::
+
+       /* Extended accounting fields start */
+
+    and::
+
+       /* Extended accounting fields end */
+
+    Their values are collected if CONFIG_TASK_XACCT is set.
+
+4) Per-task and per-thread context switch count statistics
+
+5) Time accounting for SMT machines
+
+6) Extended delay accounting fields for memory reclaim
+
+Future extension should add fields to the end of the taskstats struct, and
+should not change the relative position of each field within the struct.
+
+::
+
+  struct taskstats {
+
+1) Common and basic accounting fields::
+
+       /* The version number of this struct. This field is always set to
+        * TAKSTATS_VERSION, which is defined in <linux/taskstats.h>.
+        * Each time the struct is changed, the value should be incremented.
+        */
+       __u16   version;
+
+       /* The exit code of a task. */
+       __u32   ac_exitcode;            /* Exit status */
+
+       /* The accounting flags of a task as defined in <linux/acct.h>
+        * Defined values are AFORK, ASU, ACOMPAT, ACORE, and AXSIG.
+        */
+       __u8    ac_flag;                /* Record flags */
+
+       /* The value of task_nice() of a task. */
+       __u8    ac_nice;                /* task_nice */
+
+       /* The name of the command that started this task. */
+       char    ac_comm[TS_COMM_LEN];   /* Command name */
+
+       /* The scheduling discipline as set in task->policy field. */
+       __u8    ac_sched;               /* Scheduling discipline */
+
+       __u8    ac_pad[3];
+       __u32   ac_uid;                 /* User ID */
+       __u32   ac_gid;                 /* Group ID */
+       __u32   ac_pid;                 /* Process ID */
+       __u32   ac_ppid;                /* Parent process ID */
+
+       /* The time when a task begins, in [secs] since 1970. */
+       __u32   ac_btime;               /* Begin time [sec since 1970] */
+
+       /* The elapsed time of a task, in [usec]. */
+       __u64   ac_etime;               /* Elapsed time [usec] */
+
+       /* The user CPU time of a task, in [usec]. */
+       __u64   ac_utime;               /* User CPU time [usec] */
+
+       /* The system CPU time of a task, in [usec]. */
+       __u64   ac_stime;               /* System CPU time [usec] */
+
+       /* The minor page fault count of a task, as set in task->min_flt. */
+       __u64   ac_minflt;              /* Minor Page Fault Count */
+
+       /* The major page fault count of a task, as set in task->maj_flt. */
+       __u64   ac_majflt;              /* Major Page Fault Count */
+
+
+2) Delay accounting fields::
+
+       /* Delay accounting fields start
+        *
+        * All values, until the comment "Delay accounting fields end" are
+        * available only if delay accounting is enabled, even though the last
+        * few fields are not delays
+        *
+        * xxx_count is the number of delay values recorded
+        * xxx_delay_total is the corresponding cumulative delay in nanoseconds
+        *
+        * xxx_delay_total wraps around to zero on overflow
+        * xxx_count incremented regardless of overflow
+        */
+
+       /* Delay waiting for cpu, while runnable
+        * count, delay_total NOT updated atomically
+        */
+       __u64   cpu_count;
+       __u64   cpu_delay_total;
+
+       /* Following four fields atomically updated using task->delays->lock */
+
+       /* Delay waiting for synchronous block I/O to complete
+        * does not account for delays in I/O submission
+        */
+       __u64   blkio_count;
+       __u64   blkio_delay_total;
+
+       /* Delay waiting for page fault I/O (swap in only) */
+       __u64   swapin_count;
+       __u64   swapin_delay_total;
+
+       /* cpu "wall-clock" running time
+        * On some architectures, value will adjust for cpu time stolen
+        * from the kernel in involuntary waits due to virtualization.
+        * Value is cumulative, in nanoseconds, without a corresponding count
+        * and wraps around to zero silently on overflow
+        */
+       __u64   cpu_run_real_total;
+
+       /* cpu "virtual" running time
+        * Uses time intervals seen by the kernel i.e. no adjustment
+        * for kernel's involuntary waits due to virtualization.
+        * Value is cumulative, in nanoseconds, without a corresponding count
+        * and wraps around to zero silently on overflow
+        */
+       __u64   cpu_run_virtual_total;
+       /* Delay accounting fields end */
+       /* version 1 ends here */
+
+
+3) Extended accounting fields::
+
+       /* Extended accounting fields start */
+
+       /* Accumulated RSS usage in duration of a task, in MBytes-usecs.
+        * The current rss usage is added to this counter every time
+        * a tick is charged to a task's system time. So, at the end we
+        * will have memory usage multiplied by system time. Thus an
+        * average usage per system time unit can be calculated.
+        */
+       __u64   coremem;                /* accumulated RSS usage in MB-usec */
+
+       /* Accumulated virtual memory usage in duration of a task.
+        * Same as acct_rss_mem1 above except that we keep track of VM usage.
+        */
+       __u64   virtmem;                /* accumulated VM usage in MB-usec */
+
+       /* High watermark of RSS usage in duration of a task, in KBytes. */
+       __u64   hiwater_rss;            /* High-watermark of RSS usage */
+
+       /* High watermark of VM  usage in duration of a task, in KBytes. */
+       __u64   hiwater_vm;             /* High-water virtual memory usage */
+
+       /* The following four fields are I/O statistics of a task. */
+       __u64   read_char;              /* bytes read */
+       __u64   write_char;             /* bytes written */
+       __u64   read_syscalls;          /* read syscalls */
+       __u64   write_syscalls;         /* write syscalls */
+
+       /* Extended accounting fields end */
+
+4) Per-task and per-thread statistics::
+
+       __u64   nvcsw;                  /* Context voluntary switch counter */
+       __u64   nivcsw;                 /* Context involuntary switch counter */
+
+5) Time accounting for SMT machines::
+
+       __u64   ac_utimescaled;         /* utime scaled on frequency etc */
+       __u64   ac_stimescaled;         /* stime scaled on frequency etc */
+       __u64   cpu_scaled_run_real_total; /* scaled cpu_run_real_total */
+
+6) Extended delay accounting fields for memory reclaim::
+
+       /* Delay waiting for memory reclaim */
+       __u64   freepages_count;
+       __u64   freepages_delay_total;
+
+::
+
+  }
diff --git a/Documentation/accounting/taskstats-struct.txt b/Documentation/accounting/taskstats-struct.txt
deleted file mode 100644 (file)
index e7512c0..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-The struct taskstats
---------------------
-
-This document contains an explanation of the struct taskstats fields.
-
-There are three different groups of fields in the struct taskstats:
-
-1) Common and basic accounting fields
-    If CONFIG_TASKSTATS is set, the taskstats interface is enabled and
-    the common fields and basic accounting fields are collected for
-    delivery at do_exit() of a task.
-2) Delay accounting fields
-    These fields are placed between
-    /* Delay accounting fields start */
-    and
-    /* Delay accounting fields end */
-    Their values are collected if CONFIG_TASK_DELAY_ACCT is set.
-3) Extended accounting fields
-    These fields are placed between
-    /* Extended accounting fields start */
-    and
-    /* Extended accounting fields end */
-    Their values are collected if CONFIG_TASK_XACCT is set.
-
-4) Per-task and per-thread context switch count statistics
-
-5) Time accounting for SMT machines
-
-6) Extended delay accounting fields for memory reclaim
-
-Future extension should add fields to the end of the taskstats struct, and
-should not change the relative position of each field within the struct.
-
-
-struct taskstats {
-
-1) Common and basic accounting fields:
-       /* The version number of this struct. This field is always set to
-        * TAKSTATS_VERSION, which is defined in <linux/taskstats.h>.
-        * Each time the struct is changed, the value should be incremented.
-        */
-       __u16   version;
-
-       /* The exit code of a task. */
-       __u32   ac_exitcode;            /* Exit status */
-
-       /* The accounting flags of a task as defined in <linux/acct.h>
-        * Defined values are AFORK, ASU, ACOMPAT, ACORE, and AXSIG.
-        */
-       __u8    ac_flag;                /* Record flags */
-
-       /* The value of task_nice() of a task. */
-       __u8    ac_nice;                /* task_nice */
-
-       /* The name of the command that started this task. */
-       char    ac_comm[TS_COMM_LEN];   /* Command name */
-
-       /* The scheduling discipline as set in task->policy field. */
-       __u8    ac_sched;               /* Scheduling discipline */
-
-       __u8    ac_pad[3];
-       __u32   ac_uid;                 /* User ID */
-       __u32   ac_gid;                 /* Group ID */
-       __u32   ac_pid;                 /* Process ID */
-       __u32   ac_ppid;                /* Parent process ID */
-
-       /* The time when a task begins, in [secs] since 1970. */
-       __u32   ac_btime;               /* Begin time [sec since 1970] */
-
-       /* The elapsed time of a task, in [usec]. */
-       __u64   ac_etime;               /* Elapsed time [usec] */
-
-       /* The user CPU time of a task, in [usec]. */
-       __u64   ac_utime;               /* User CPU time [usec] */
-
-       /* The system CPU time of a task, in [usec]. */
-       __u64   ac_stime;               /* System CPU time [usec] */
-
-       /* The minor page fault count of a task, as set in task->min_flt. */
-       __u64   ac_minflt;              /* Minor Page Fault Count */
-
-       /* The major page fault count of a task, as set in task->maj_flt. */
-       __u64   ac_majflt;              /* Major Page Fault Count */
-
-
-2) Delay accounting fields:
-       /* Delay accounting fields start
-        *
-        * All values, until the comment "Delay accounting fields end" are
-        * available only if delay accounting is enabled, even though the last
-        * few fields are not delays
-        *
-        * xxx_count is the number of delay values recorded
-        * xxx_delay_total is the corresponding cumulative delay in nanoseconds
-        *
-        * xxx_delay_total wraps around to zero on overflow
-        * xxx_count incremented regardless of overflow
-        */
-
-       /* Delay waiting for cpu, while runnable
-        * count, delay_total NOT updated atomically
-        */
-       __u64   cpu_count;
-       __u64   cpu_delay_total;
-
-       /* Following four fields atomically updated using task->delays->lock */
-
-       /* Delay waiting for synchronous block I/O to complete
-        * does not account for delays in I/O submission
-        */
-       __u64   blkio_count;
-       __u64   blkio_delay_total;
-
-       /* Delay waiting for page fault I/O (swap in only) */
-       __u64   swapin_count;
-       __u64   swapin_delay_total;
-
-       /* cpu "wall-clock" running time
-        * On some architectures, value will adjust for cpu time stolen
-        * from the kernel in involuntary waits due to virtualization.
-        * Value is cumulative, in nanoseconds, without a corresponding count
-        * and wraps around to zero silently on overflow
-        */
-       __u64   cpu_run_real_total;
-
-       /* cpu "virtual" running time
-        * Uses time intervals seen by the kernel i.e. no adjustment
-        * for kernel's involuntary waits due to virtualization.
-        * Value is cumulative, in nanoseconds, without a corresponding count
-        * and wraps around to zero silently on overflow
-        */
-       __u64   cpu_run_virtual_total;
-       /* Delay accounting fields end */
-       /* version 1 ends here */
-
-
-3) Extended accounting fields
-       /* Extended accounting fields start */
-
-       /* Accumulated RSS usage in duration of a task, in MBytes-usecs.
-        * The current rss usage is added to this counter every time
-        * a tick is charged to a task's system time. So, at the end we
-        * will have memory usage multiplied by system time. Thus an
-        * average usage per system time unit can be calculated.
-        */
-       __u64   coremem;                /* accumulated RSS usage in MB-usec */
-
-       /* Accumulated virtual memory usage in duration of a task.
-        * Same as acct_rss_mem1 above except that we keep track of VM usage.
-        */
-       __u64   virtmem;                /* accumulated VM usage in MB-usec */
-
-       /* High watermark of RSS usage in duration of a task, in KBytes. */
-       __u64   hiwater_rss;            /* High-watermark of RSS usage */
-
-       /* High watermark of VM  usage in duration of a task, in KBytes. */
-       __u64   hiwater_vm;             /* High-water virtual memory usage */
-
-       /* The following four fields are I/O statistics of a task. */
-       __u64   read_char;              /* bytes read */
-       __u64   write_char;             /* bytes written */
-       __u64   read_syscalls;          /* read syscalls */
-       __u64   write_syscalls;         /* write syscalls */
-
-       /* Extended accounting fields end */
-
-4) Per-task and per-thread statistics
-       __u64   nvcsw;                  /* Context voluntary switch counter */
-       __u64   nivcsw;                 /* Context involuntary switch counter */
-
-5) Time accounting for SMT machines
-       __u64   ac_utimescaled;         /* utime scaled on frequency etc */
-       __u64   ac_stimescaled;         /* stime scaled on frequency etc */
-       __u64   cpu_scaled_run_real_total; /* scaled cpu_run_real_total */
-
-6) Extended delay accounting fields for memory reclaim
-       /* Delay waiting for memory reclaim */
-       __u64   freepages_count;
-       __u64   freepages_delay_total;
-}
diff --git a/Documentation/accounting/taskstats.rst b/Documentation/accounting/taskstats.rst
new file mode 100644 (file)
index 0000000..2a28b7f
--- /dev/null
@@ -0,0 +1,180 @@
+=============================
+Per-task statistics interface
+=============================
+
+
+Taskstats is a netlink-based interface for sending per-task and
+per-process statistics from the kernel to userspace.
+
+Taskstats was designed for the following benefits:
+
+- efficiently provide statistics during lifetime of a task and on its exit
+- unified interface for multiple accounting subsystems
+- extensibility for use by future accounting patches
+
+Terminology
+-----------
+
+"pid", "tid" and "task" are used interchangeably and refer to the standard
+Linux task defined by struct task_struct.  per-pid stats are the same as
+per-task stats.
+
+"tgid", "process" and "thread group" are used interchangeably and refer to the
+tasks that share an mm_struct i.e. the traditional Unix process. Despite the
+use of tgid, there is no special treatment for the task that is thread group
+leader - a process is deemed alive as long as it has any task belonging to it.
+
+Usage
+-----
+
+To get statistics during a task's lifetime, userspace opens a unicast netlink
+socket (NETLINK_GENERIC family) and sends commands specifying a pid or a tgid.
+The response contains statistics for a task (if pid is specified) or the sum of
+statistics for all tasks of the process (if tgid is specified).
+
+To obtain statistics for tasks which are exiting, the userspace listener
+sends a register command and specifies a cpumask. Whenever a task exits on
+one of the cpus in the cpumask, its per-pid statistics are sent to the
+registered listener. Using cpumasks allows the data received by one listener
+to be limited and assists in flow control over the netlink interface and is
+explained in more detail below.
+
+If the exiting task is the last thread exiting its thread group,
+an additional record containing the per-tgid stats is also sent to userspace.
+The latter contains the sum of per-pid stats for all threads in the thread
+group, both past and present.
+
+getdelays.c is a simple utility demonstrating usage of the taskstats interface
+for reporting delay accounting statistics. Users can register cpumasks,
+send commands and process responses, listen for per-tid/tgid exit data,
+write the data received to a file and do basic flow control by increasing
+receive buffer sizes.
+
+Interface
+---------
+
+The user-kernel interface is encapsulated in include/linux/taskstats.h
+
+To avoid this documentation becoming obsolete as the interface evolves, only
+an outline of the current version is given. taskstats.h always overrides the
+description here.
+
+struct taskstats is the common accounting structure for both per-pid and
+per-tgid data. It is versioned and can be extended by each accounting subsystem
+that is added to the kernel. The fields and their semantics are defined in the
+taskstats.h file.
+
+The data exchanged between user and kernel space is a netlink message belonging
+to the NETLINK_GENERIC family and using the netlink attributes interface.
+The messages are in the format::
+
+    +----------+- - -+-------------+-------------------+
+    | nlmsghdr | Pad |  genlmsghdr | taskstats payload |
+    +----------+- - -+-------------+-------------------+
+
+
+The taskstats payload is one of the following three kinds:
+
+1. Commands: Sent from user to kernel. Commands to get data on
+a pid/tgid consist of one attribute, of type TASKSTATS_CMD_ATTR_PID/TGID,
+containing a u32 pid or tgid in the attribute payload. The pid/tgid denotes
+the task/process for which userspace wants statistics.
+
+Commands to register/deregister interest in exit data from a set of cpus
+consist of one attribute, of type
+TASKSTATS_CMD_ATTR_REGISTER/DEREGISTER_CPUMASK and contain a cpumask in the
+attribute payload. The cpumask is specified as an ascii string of
+comma-separated cpu ranges e.g. to listen to exit data from cpus 1,2,3,5,7,8
+the cpumask would be "1-3,5,7-8". If userspace forgets to deregister interest
+in cpus before closing the listening socket, the kernel cleans up its interest
+set over time. However, for the sake of efficiency, an explicit deregistration
+is advisable.
+
+2. Response for a command: sent from the kernel in response to a userspace
+command. The payload is a series of three attributes of type:
+
+a) TASKSTATS_TYPE_AGGR_PID/TGID : attribute containing no payload but indicates
+a pid/tgid will be followed by some stats.
+
+b) TASKSTATS_TYPE_PID/TGID: attribute whose payload is the pid/tgid whose stats
+are being returned.
+
+c) TASKSTATS_TYPE_STATS: attribute with a struct taskstats as payload. The
+same structure is used for both per-pid and per-tgid stats.
+
+3. New message sent by kernel whenever a task exits. The payload consists of a
+   series of attributes of the following type:
+
+a) TASKSTATS_TYPE_AGGR_PID: indicates next two attributes will be pid+stats
+b) TASKSTATS_TYPE_PID: contains exiting task's pid
+c) TASKSTATS_TYPE_STATS: contains the exiting task's per-pid stats
+d) TASKSTATS_TYPE_AGGR_TGID: indicates next two attributes will be tgid+stats
+e) TASKSTATS_TYPE_TGID: contains tgid of process to which task belongs
+f) TASKSTATS_TYPE_STATS: contains the per-tgid stats for exiting task's process
+
+
+per-tgid stats
+--------------
+
+Taskstats provides per-process stats, in addition to per-task stats, since
+resource management is often done at a process granularity and aggregating task
+stats in userspace alone is inefficient and potentially inaccurate (due to lack
+of atomicity).
+
+However, maintaining per-process, in addition to per-task stats, within the
+kernel has space and time overheads. To address this, the taskstats code
+accumulates each exiting task's statistics into a process-wide data structure.
+When the last task of a process exits, the process level data accumulated also
+gets sent to userspace (along with the per-task data).
+
+When a user queries to get per-tgid data, the sum of all other live threads in
+the group is added up and added to the accumulated total for previously exited
+threads of the same thread group.
+
+Extending taskstats
+-------------------
+
+There are two ways to extend the taskstats interface to export more
+per-task/process stats as patches to collect them get added to the kernel
+in future:
+
+1. Adding more fields to the end of the existing struct taskstats. Backward
+   compatibility is ensured by the version number within the
+   structure. Userspace will use only the fields of the struct that correspond
+   to the version its using.
+
+2. Defining separate statistic structs and using the netlink attributes
+   interface to return them. Since userspace processes each netlink attribute
+   independently, it can always ignore attributes whose type it does not
+   understand (because it is using an older version of the interface).
+
+
+Choosing between 1. and 2. is a matter of trading off flexibility and
+overhead. If only a few fields need to be added, then 1. is the preferable
+path since the kernel and userspace don't need to incur the overhead of
+processing new netlink attributes. But if the new fields expand the existing
+struct too much, requiring disparate userspace accounting utilities to
+unnecessarily receive large structures whose fields are of no interest, then
+extending the attributes structure would be worthwhile.
+
+Flow control for taskstats
+--------------------------
+
+When the rate of task exits becomes large, a listener may not be able to keep
+up with the kernel's rate of sending per-tid/tgid exit data leading to data
+loss. This possibility gets compounded when the taskstats structure gets
+extended and the number of cpus grows large.
+
+To avoid losing statistics, userspace should do one or more of the following:
+
+- increase the receive buffer sizes for the netlink sockets opened by
+  listeners to receive exit data.
+
+- create more listeners and reduce the number of cpus being listened to by
+  each listener. In the extreme case, there could be one listener for each cpu.
+  Users may also consider setting the cpu affinity of the listener to the subset
+  of cpus to which it listens, especially if they are listening to just one cpu.
+
+Despite these measures, if the userspace receives ENOBUFS error messages
+indicated overflow of receive buffers, it should take measures to handle the
+loss of data.
diff --git a/Documentation/accounting/taskstats.txt b/Documentation/accounting/taskstats.txt
deleted file mode 100644 (file)
index ff06b73..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-Per-task statistics interface
------------------------------
-
-
-Taskstats is a netlink-based interface for sending per-task and
-per-process statistics from the kernel to userspace.
-
-Taskstats was designed for the following benefits:
-
-- efficiently provide statistics during lifetime of a task and on its exit
-- unified interface for multiple accounting subsystems
-- extensibility for use by future accounting patches
-
-Terminology
------------
-
-"pid", "tid" and "task" are used interchangeably and refer to the standard
-Linux task defined by struct task_struct.  per-pid stats are the same as
-per-task stats.
-
-"tgid", "process" and "thread group" are used interchangeably and refer to the
-tasks that share an mm_struct i.e. the traditional Unix process. Despite the
-use of tgid, there is no special treatment for the task that is thread group
-leader - a process is deemed alive as long as it has any task belonging to it.
-
-Usage
------
-
-To get statistics during a task's lifetime, userspace opens a unicast netlink
-socket (NETLINK_GENERIC family) and sends commands specifying a pid or a tgid.
-The response contains statistics for a task (if pid is specified) or the sum of
-statistics for all tasks of the process (if tgid is specified).
-
-To obtain statistics for tasks which are exiting, the userspace listener
-sends a register command and specifies a cpumask. Whenever a task exits on
-one of the cpus in the cpumask, its per-pid statistics are sent to the
-registered listener. Using cpumasks allows the data received by one listener
-to be limited and assists in flow control over the netlink interface and is
-explained in more detail below.
-
-If the exiting task is the last thread exiting its thread group,
-an additional record containing the per-tgid stats is also sent to userspace.
-The latter contains the sum of per-pid stats for all threads in the thread
-group, both past and present.
-
-getdelays.c is a simple utility demonstrating usage of the taskstats interface
-for reporting delay accounting statistics. Users can register cpumasks,
-send commands and process responses, listen for per-tid/tgid exit data,
-write the data received to a file and do basic flow control by increasing
-receive buffer sizes.
-
-Interface
----------
-
-The user-kernel interface is encapsulated in include/linux/taskstats.h
-
-To avoid this documentation becoming obsolete as the interface evolves, only
-an outline of the current version is given. taskstats.h always overrides the
-description here.
-
-struct taskstats is the common accounting structure for both per-pid and
-per-tgid data. It is versioned and can be extended by each accounting subsystem
-that is added to the kernel. The fields and their semantics are defined in the
-taskstats.h file.
-
-The data exchanged between user and kernel space is a netlink message belonging
-to the NETLINK_GENERIC family and using the netlink attributes interface.
-The messages are in the format
-
-    +----------+- - -+-------------+-------------------+
-    | nlmsghdr | Pad |  genlmsghdr | taskstats payload |
-    +----------+- - -+-------------+-------------------+
-
-
-The taskstats payload is one of the following three kinds:
-
-1. Commands: Sent from user to kernel. Commands to get data on
-a pid/tgid consist of one attribute, of type TASKSTATS_CMD_ATTR_PID/TGID,
-containing a u32 pid or tgid in the attribute payload. The pid/tgid denotes
-the task/process for which userspace wants statistics.
-
-Commands to register/deregister interest in exit data from a set of cpus
-consist of one attribute, of type
-TASKSTATS_CMD_ATTR_REGISTER/DEREGISTER_CPUMASK and contain a cpumask in the
-attribute payload. The cpumask is specified as an ascii string of
-comma-separated cpu ranges e.g. to listen to exit data from cpus 1,2,3,5,7,8
-the cpumask would be "1-3,5,7-8". If userspace forgets to deregister interest
-in cpus before closing the listening socket, the kernel cleans up its interest
-set over time. However, for the sake of efficiency, an explicit deregistration
-is advisable.
-
-2. Response for a command: sent from the kernel in response to a userspace
-command. The payload is a series of three attributes of type:
-
-a) TASKSTATS_TYPE_AGGR_PID/TGID : attribute containing no payload but indicates
-a pid/tgid will be followed by some stats.
-
-b) TASKSTATS_TYPE_PID/TGID: attribute whose payload is the pid/tgid whose stats
-are being returned.
-
-c) TASKSTATS_TYPE_STATS: attribute with a struct taskstats as payload. The
-same structure is used for both per-pid and per-tgid stats.
-
-3. New message sent by kernel whenever a task exits. The payload consists of a
-   series of attributes of the following type:
-
-a) TASKSTATS_TYPE_AGGR_PID: indicates next two attributes will be pid+stats
-b) TASKSTATS_TYPE_PID: contains exiting task's pid
-c) TASKSTATS_TYPE_STATS: contains the exiting task's per-pid stats
-d) TASKSTATS_TYPE_AGGR_TGID: indicates next two attributes will be tgid+stats
-e) TASKSTATS_TYPE_TGID: contains tgid of process to which task belongs
-f) TASKSTATS_TYPE_STATS: contains the per-tgid stats for exiting task's process
-
-
-per-tgid stats
---------------
-
-Taskstats provides per-process stats, in addition to per-task stats, since
-resource management is often done at a process granularity and aggregating task
-stats in userspace alone is inefficient and potentially inaccurate (due to lack
-of atomicity).
-
-However, maintaining per-process, in addition to per-task stats, within the
-kernel has space and time overheads. To address this, the taskstats code
-accumulates each exiting task's statistics into a process-wide data structure.
-When the last task of a process exits, the process level data accumulated also
-gets sent to userspace (along with the per-task data).
-
-When a user queries to get per-tgid data, the sum of all other live threads in
-the group is added up and added to the accumulated total for previously exited
-threads of the same thread group.
-
-Extending taskstats
--------------------
-
-There are two ways to extend the taskstats interface to export more
-per-task/process stats as patches to collect them get added to the kernel
-in future:
-
-1. Adding more fields to the end of the existing struct taskstats. Backward
-   compatibility is ensured by the version number within the
-   structure. Userspace will use only the fields of the struct that correspond
-   to the version its using.
-
-2. Defining separate statistic structs and using the netlink attributes
-   interface to return them. Since userspace processes each netlink attribute
-   independently, it can always ignore attributes whose type it does not
-   understand (because it is using an older version of the interface).
-
-
-Choosing between 1. and 2. is a matter of trading off flexibility and
-overhead. If only a few fields need to be added, then 1. is the preferable
-path since the kernel and userspace don't need to incur the overhead of
-processing new netlink attributes. But if the new fields expand the existing
-struct too much, requiring disparate userspace accounting utilities to
-unnecessarily receive large structures whose fields are of no interest, then
-extending the attributes structure would be worthwhile.
-
-Flow control for taskstats
---------------------------
-
-When the rate of task exits becomes large, a listener may not be able to keep
-up with the kernel's rate of sending per-tid/tgid exit data leading to data
-loss. This possibility gets compounded when the taskstats structure gets
-extended and the number of cpus grows large.
-
-To avoid losing statistics, userspace should do one or more of the following:
-
-- increase the receive buffer sizes for the netlink sockets opened by
-listeners to receive exit data.
-
-- create more listeners and reduce the number of cpus being listened to by
-each listener. In the extreme case, there could be one listener for each cpu.
-Users may also consider setting the cpu affinity of the listener to the subset
-of cpus to which it listens, especially if they are listening to just one cpu.
-
-Despite these measures, if the userspace receives ENOBUFS error messages
-indicated overflow of receive buffers, it should take measures to handle the
-loss of data.
-
-----
diff --git a/Documentation/admin-guide/aoe/aoe.rst b/Documentation/admin-guide/aoe/aoe.rst
new file mode 100644 (file)
index 0000000..a05e751
--- /dev/null
@@ -0,0 +1,150 @@
+Introduction
+============
+
+ATA over Ethernet is a network protocol that provides simple access to
+block storage on the LAN.
+
+  http://support.coraid.com/documents/AoEr11.txt
+
+The EtherDrive (R) HOWTO for 2.6 and 3.x kernels is found at ...
+
+  http://support.coraid.com/support/linux/EtherDrive-2.6-HOWTO.html
+
+It has many tips and hints!  Please see, especially, recommended
+tunings for virtual memory:
+
+  http://support.coraid.com/support/linux/EtherDrive-2.6-HOWTO-5.html#ss5.19
+
+The aoetools are userland programs that are designed to work with this
+driver.  The aoetools are on sourceforge.
+
+  http://aoetools.sourceforge.net/
+
+The scripts in this Documentation/admin-guide/aoe directory are intended to
+document the use of the driver and are not necessary if you install
+the aoetools.
+
+
+Creating Device Nodes
+=====================
+
+  Users of udev should find the block device nodes created
+  automatically, but to create all the necessary device nodes, use the
+  udev configuration rules provided in udev.txt (in this directory).
+
+  There is a udev-install.sh script that shows how to install these
+  rules on your system.
+
+  There is also an autoload script that shows how to edit
+  /etc/modprobe.d/aoe.conf to ensure that the aoe module is loaded when
+  necessary.  Preloading the aoe module is preferable to autoloading,
+  however, because AoE discovery takes a few seconds.  It can be
+  confusing when an AoE device is not present the first time the a
+  command is run but appears a second later.
+
+Using Device Nodes
+==================
+
+  "cat /dev/etherd/err" blocks, waiting for error diagnostic output,
+  like any retransmitted packets.
+
+  "echo eth2 eth4 > /dev/etherd/interfaces" tells the aoe driver to
+  limit ATA over Ethernet traffic to eth2 and eth4.  AoE traffic from
+  untrusted networks should be ignored as a matter of security.  See
+  also the aoe_iflist driver option described below.
+
+  "echo > /dev/etherd/discover" tells the driver to find out what AoE
+  devices are available.
+
+  In the future these character devices may disappear and be replaced
+  by sysfs counterparts.  Using the commands in aoetools insulates
+  users from these implementation details.
+
+  The block devices are named like this::
+
+       e{shelf}.{slot}
+       e{shelf}.{slot}p{part}
+
+  ... so that "e0.2" is the third blade from the left (slot 2) in the
+  first shelf (shelf address zero).  That's the whole disk.  The first
+  partition on that disk would be "e0.2p1".
+
+Using sysfs
+===========
+
+  Each aoe block device in /sys/block has the extra attributes of
+  state, mac, and netif.  The state attribute is "up" when the device
+  is ready for I/O and "down" if detected but unusable.  The
+  "down,closewait" state shows that the device is still open and
+  cannot come up again until it has been closed.
+
+  The mac attribute is the ethernet address of the remote AoE device.
+  The netif attribute is the network interface on the localhost
+  through which we are communicating with the remote AoE device.
+
+  There is a script in this directory that formats this information in
+  a convenient way.  Users with aoetools should use the aoe-stat
+  command::
+
+    root@makki root# sh Documentation/admin-guide/aoe/status.sh
+       e10.0            eth3              up
+       e10.1            eth3              up
+       e10.2            eth3              up
+       e10.3            eth3              up
+       e10.4            eth3              up
+       e10.5            eth3              up
+       e10.6            eth3              up
+       e10.7            eth3              up
+       e10.8            eth3              up
+       e10.9            eth3              up
+        e4.0            eth1              up
+        e4.1            eth1              up
+        e4.2            eth1              up
+        e4.3            eth1              up
+        e4.4            eth1              up
+        e4.5            eth1              up
+        e4.6            eth1              up
+        e4.7            eth1              up
+        e4.8            eth1              up
+        e4.9            eth1              up
+
+  Use /sys/module/aoe/parameters/aoe_iflist (or better, the driver
+  option discussed below) instead of /dev/etherd/interfaces to limit
+  AoE traffic to the network interfaces in the given
+  whitespace-separated list.  Unlike the old character device, the
+  sysfs entry can be read from as well as written to.
+
+  It's helpful to trigger discovery after setting the list of allowed
+  interfaces.  The aoetools package provides an aoe-discover script
+  for this purpose.  You can also directly use the
+  /dev/etherd/discover special file described above.
+
+Driver Options
+==============
+
+  There is a boot option for the built-in aoe driver and a
+  corresponding module parameter, aoe_iflist.  Without this option,
+  all network interfaces may be used for ATA over Ethernet.  Here is a
+  usage example for the module parameter::
+
+    modprobe aoe_iflist="eth1 eth3"
+
+  The aoe_deadsecs module parameter determines the maximum number of
+  seconds that the driver will wait for an AoE device to provide a
+  response to an AoE command.  After aoe_deadsecs seconds have
+  elapsed, the AoE device will be marked as "down".  A value of zero
+  is supported for testing purposes and makes the aoe driver keep
+  trying AoE commands forever.
+
+  The aoe_maxout module parameter has a default of 128.  This is the
+  maximum number of unresponded packets that will be sent to an AoE
+  target at one time.
+
+  The aoe_dyndevs module parameter defaults to 1, meaning that the
+  driver will assign a block device minor number to a discovered AoE
+  target based on the order of its discovery.  With dynamic minor
+  device numbers in use, a greater range of AoE shelf and slot
+  addresses can be supported.  Users with udev will never have to
+  think about minor numbers.  Using aoe_dyndevs=0 allows device nodes
+  to be pre-created using a static minor-number scheme with the
+  aoe-mkshelf script in the aoetools.
diff --git a/Documentation/admin-guide/aoe/index.rst b/Documentation/admin-guide/aoe/index.rst
new file mode 100644 (file)
index 0000000..d71c5df
--- /dev/null
@@ -0,0 +1,17 @@
+=======================
+ATA over Ethernet (AoE)
+=======================
+
+.. toctree::
+    :maxdepth: 1
+
+    aoe
+    todo
+    examples
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
diff --git a/Documentation/admin-guide/aoe/udev.txt b/Documentation/admin-guide/aoe/udev.txt
new file mode 100644 (file)
index 0000000..5fb7564
--- /dev/null
@@ -0,0 +1,26 @@
+# These rules tell udev what device nodes to create for aoe support.
+# They may be installed along the following lines.  Check the section
+# 8 udev manpage to see whether your udev supports SUBSYSTEM, and
+# whether it uses one or two equal signs for SUBSYSTEM and KERNEL.
+# 
+#   ecashin@makki ~$ su
+#   Password:
+#   bash# find /etc -type f -name udev.conf
+#   /etc/udev/udev.conf
+#   bash# grep udev_rules= /etc/udev/udev.conf
+#   udev_rules="/etc/udev/rules.d/"
+#   bash# ls /etc/udev/rules.d/
+#   10-wacom.rules  50-udev.rules
+#   bash# cp /path/to/linux/Documentation/admin-guide/aoe/udev.txt \
+#           /etc/udev/rules.d/60-aoe.rules
+#  
+
+# aoe char devices
+SUBSYSTEM=="aoe", KERNEL=="discover",  NAME="etherd/%k", GROUP="disk", MODE="0220"
+SUBSYSTEM=="aoe", KERNEL=="err",       NAME="etherd/%k", GROUP="disk", MODE="0440"
+SUBSYSTEM=="aoe", KERNEL=="interfaces",        NAME="etherd/%k", GROUP="disk", MODE="0220"
+SUBSYSTEM=="aoe", KERNEL=="revalidate",        NAME="etherd/%k", GROUP="disk", MODE="0220"
+SUBSYSTEM=="aoe", KERNEL=="flush",     NAME="etherd/%k", GROUP="disk", MODE="0220"
+
+# aoe block devices     
+KERNEL=="etherd*",       GROUP="disk"
diff --git a/Documentation/admin-guide/blockdev/drbd/data-structure-v9.rst b/Documentation/admin-guide/blockdev/drbd/data-structure-v9.rst
new file mode 100644 (file)
index 0000000..66036b9
--- /dev/null
@@ -0,0 +1,42 @@
+================================
+kernel data structure for DRBD-9
+================================
+
+This describes the in kernel data structure for DRBD-9. Starting with
+Linux v3.14 we are reorganizing DRBD to use this data structure.
+
+Basic Data Structure
+====================
+
+A node has a number of DRBD resources.  Each such resource has a number of
+devices (aka volumes) and connections to other nodes ("peer nodes"). Each DRBD
+device is represented by a block device locally.
+
+The DRBD objects are interconnected to form a matrix as depicted below; a
+drbd_peer_device object sits at each intersection between a drbd_device and a
+drbd_connection::
+
+  /--------------+---------------+.....+---------------\
+  |   resource   |    device     |     |    device     |
+  +--------------+---------------+.....+---------------+
+  |  connection  |  peer_device  |     |  peer_device  |
+  +--------------+---------------+.....+---------------+
+  :              :               :     :               :
+  :              :               :     :               :
+  +--------------+---------------+.....+---------------+
+  |  connection  |  peer_device  |     |  peer_device  |
+  \--------------+---------------+.....+---------------/
+
+In this table, horizontally, devices can be accessed from resources by their
+volume number.  Likewise, peer_devices can be accessed from connections by
+their volume number.  Objects in the vertical direction are connected by double
+linked lists.  There are back pointers from peer_devices to their connections a
+devices, and from connections and devices to their resource.
+
+All resources are in the drbd_resources double-linked list.  In addition, all
+devices can be accessed by their minor device number via the drbd_devices idr.
+
+The drbd_resource, drbd_connection, and drbd_device objects are reference
+counted.  The peer_device objects only serve to establish the links between
+devices and connections; their lifetime is determined by the lifetime of the
+device and connection which they reference.
diff --git a/Documentation/admin-guide/blockdev/drbd/figures.rst b/Documentation/admin-guide/blockdev/drbd/figures.rst
new file mode 100644 (file)
index 0000000..bd9a490
--- /dev/null
@@ -0,0 +1,30 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. The here included files are intended to help understand the implementation
+
+Data flows that Relate some functions, and write packets
+========================================================
+
+.. kernel-figure:: DRBD-8.3-data-packets.svg
+    :alt:   DRBD-8.3-data-packets.svg
+    :align: center
+
+.. kernel-figure:: DRBD-data-packets.svg
+    :alt:   DRBD-data-packets.svg
+    :align: center
+
+
+Sub graphs of DRBD's state transitions
+======================================
+
+.. kernel-figure:: conn-states-8.dot
+    :alt:   conn-states-8.dot
+    :align: center
+
+.. kernel-figure:: disk-states-8.dot
+    :alt:   disk-states-8.dot
+    :align: center
+
+.. kernel-figure:: node-states-8.dot
+    :alt:   node-states-8.dot
+    :align: center
diff --git a/Documentation/admin-guide/blockdev/drbd/index.rst b/Documentation/admin-guide/blockdev/drbd/index.rst
new file mode 100644 (file)
index 0000000..68ecd5c
--- /dev/null
@@ -0,0 +1,19 @@
+==========================================
+Distributed Replicated Block Device - DRBD
+==========================================
+
+Description
+===========
+
+  DRBD is a shared-nothing, synchronously replicated block device. It
+  is designed to serve as a building block for high availability
+  clusters and in this context, is a "drop-in" replacement for shared
+  storage. Simplistically, you could see it as a network RAID 1.
+
+  Please visit http://www.drbd.org to find out more.
+
+.. toctree::
+   :maxdepth: 1
+
+   data-structure-v9
+   figures
diff --git a/Documentation/admin-guide/blockdev/drbd/node-states-8.dot b/Documentation/admin-guide/blockdev/drbd/node-states-8.dot
new file mode 100644 (file)
index 0000000..bfa54e1
--- /dev/null
@@ -0,0 +1,13 @@
+digraph node_states {
+       Secondary -> Primary           [ label = "ioctl_set_state()" ]
+       Primary   -> Secondary         [ label = "ioctl_set_state()" ]
+}
+
+digraph peer_states {
+       Secondary -> Primary           [ label = "recv state packet" ]
+       Primary   -> Secondary         [ label = "recv state packet" ]
+       Primary   -> Unknown           [ label = "connection lost" ]
+       Secondary  -> Unknown          [ label = "connection lost" ]
+       Unknown   -> Primary           [ label = "connected" ]
+       Unknown   -> Secondary         [ label = "connected" ]
+}
diff --git a/Documentation/admin-guide/blockdev/floppy.rst b/Documentation/admin-guide/blockdev/floppy.rst
new file mode 100644 (file)
index 0000000..4a8f31c
--- /dev/null
@@ -0,0 +1,255 @@
+=============
+Floppy Driver
+=============
+
+FAQ list:
+=========
+
+A FAQ list may be found in the fdutils package (see below), and also
+at <http://fdutils.linux.lu/faq.html>.
+
+
+LILO configuration options (Thinkpad users, read this)
+======================================================
+
+The floppy driver is configured using the 'floppy=' option in
+lilo. This option can be typed at the boot prompt, or entered in the
+lilo configuration file.
+
+Example: If your kernel is called linux-2.6.9, type the following line
+at the lilo boot prompt (if you have a thinkpad)::
+
+ linux-2.6.9 floppy=thinkpad
+
+You may also enter the following line in /etc/lilo.conf, in the description
+of linux-2.6.9::
+
+ append = "floppy=thinkpad"
+
+Several floppy related options may be given, example::
+
+ linux-2.6.9 floppy=daring floppy=two_fdc
+ append = "floppy=daring floppy=two_fdc"
+
+If you give options both in the lilo config file and on the boot
+prompt, the option strings of both places are concatenated, the boot
+prompt options coming last. That's why there are also options to
+restore the default behavior.
+
+
+Module configuration options
+============================
+
+If you use the floppy driver as a module, use the following syntax::
+
+       modprobe floppy floppy="<options>"
+
+Example::
+
+       modprobe floppy floppy="omnibook messages"
+
+If you need certain options enabled every time you load the floppy driver,
+you can put::
+
+       options floppy floppy="omnibook messages"
+
+in a configuration file in /etc/modprobe.d/.
+
+
+The floppy driver related options are:
+
+ floppy=asus_pci
+       Sets the bit mask to allow only units 0 and 1. (default)
+
+ floppy=daring
+       Tells the floppy driver that you have a well behaved floppy controller.
+       This allows more efficient and smoother operation, but may fail on
+       certain controllers. This may speed up certain operations.
+
+ floppy=0,daring
+       Tells the floppy driver that your floppy controller should be used
+       with caution.
+
+ floppy=one_fdc
+       Tells the floppy driver that you have only one floppy controller.
+       (default)
+
+ floppy=two_fdc / floppy=<address>,two_fdc
+       Tells the floppy driver that you have two floppy controllers.
+       The second floppy controller is assumed to be at <address>.
+       This option is not needed if the second controller is at address
+       0x370, and if you use the 'cmos' option.
+
+ floppy=thinkpad
+       Tells the floppy driver that you have a Thinkpad. Thinkpads use an
+       inverted convention for the disk change line.
+
+ floppy=0,thinkpad
+       Tells the floppy driver that you don't have a Thinkpad.
+
+ floppy=omnibook / floppy=nodma
+       Tells the floppy driver not to use Dma for data transfers.
+       This is needed on HP Omnibooks, which don't have a workable
+       DMA channel for the floppy driver. This option is also useful
+       if you frequently get "Unable to allocate DMA memory" messages.
+       Indeed, dma memory needs to be continuous in physical memory,
+       and is thus harder to find, whereas non-dma buffers may be
+       allocated in virtual memory. However, I advise against this if
+       you have an FDC without a FIFO (8272A or 82072). 82072A and
+       later are OK. You also need at least a 486 to use nodma.
+       If you use nodma mode, I suggest you also set the FIFO
+       threshold to 10 or lower, in order to limit the number of data
+       transfer interrupts.
+
+       If you have a FIFO-able FDC, the floppy driver automatically
+       falls back on non DMA mode if no DMA-able memory can be found.
+       If you want to avoid this, explicitly ask for 'yesdma'.
+
+ floppy=yesdma
+       Tells the floppy driver that a workable DMA channel is available.
+       (default)
+
+ floppy=nofifo
+       Disables the FIFO entirely. This is needed if you get "Bus
+       master arbitration error" messages from your Ethernet card (or
+       from other devices) while accessing the floppy.
+
+ floppy=usefifo
+       Enables the FIFO. (default)
+
+ floppy=<threshold>,fifo_depth
+       Sets the FIFO threshold. This is mostly relevant in DMA
+       mode. If this is higher, the floppy driver tolerates more
+       interrupt latency, but it triggers more interrupts (i.e. it
+       imposes more load on the rest of the system). If this is
+       lower, the interrupt latency should be lower too (faster
+       processor). The benefit of a lower threshold is less
+       interrupts.
+
+       To tune the fifo threshold, switch on over/underrun messages
+       using 'floppycontrol --messages'. Then access a floppy
+       disk. If you get a huge amount of "Over/Underrun - retrying"
+       messages, then the fifo threshold is too low. Try with a
+       higher value, until you only get an occasional Over/Underrun.
+       It is a good idea to compile the floppy driver as a module
+       when doing this tuning. Indeed, it allows to try different
+       fifo values without rebooting the machine for each test. Note
+       that you need to do 'floppycontrol --messages' every time you
+       re-insert the module.
+
+       Usually, tuning the fifo threshold should not be needed, as
+       the default (0xa) is reasonable.
+
+ floppy=<drive>,<type>,cmos
+       Sets the CMOS type of <drive> to <type>. This is mandatory if
+       you have more than two floppy drives (only two can be
+       described in the physical CMOS), or if your BIOS uses
+       non-standard CMOS types. The CMOS types are:
+
+              ==  ==================================
+               0  Use the value of the physical CMOS
+               1  5 1/4 DD
+               2  5 1/4 HD
+               3  3 1/2 DD
+               4  3 1/2 HD
+               5  3 1/2 ED
+               6  3 1/2 ED
+              16  unknown or not installed
+              ==  ==================================
+
+       (Note: there are two valid types for ED drives. This is because 5 was
+       initially chosen to represent floppy *tapes*, and 6 for ED drives.
+       AMI ignored this, and used 5 for ED drives. That's why the floppy
+       driver handles both.)
+
+ floppy=unexpected_interrupts
+       Print a warning message when an unexpected interrupt is received.
+       (default)
+
+ floppy=no_unexpected_interrupts / floppy=L40SX
+       Don't print a message when an unexpected interrupt is received. This
+       is needed on IBM L40SX laptops in certain video modes. (There seems
+       to be an interaction between video and floppy. The unexpected
+       interrupts affect only performance, and can be safely ignored.)
+
+ floppy=broken_dcl
+       Don't use the disk change line, but assume that the disk was
+       changed whenever the device node is reopened. Needed on some
+       boxes where the disk change line is broken or unsupported.
+       This should be regarded as a stopgap measure, indeed it makes
+       floppy operation less efficient due to unneeded cache
+       flushings, and slightly more unreliable. Please verify your
+       cable, connection and jumper settings if you have any DCL
+       problems. However, some older drives, and also some laptops
+       are known not to have a DCL.
+
+ floppy=debug
+       Print debugging messages.
+
+ floppy=messages
+       Print informational messages for some operations (disk change
+       notifications, warnings about over and underruns, and about
+       autodetection).
+
+ floppy=silent_dcl_clear
+       Uses a less noisy way to clear the disk change line (which
+       doesn't involve seeks). Implied by 'daring' option.
+
+ floppy=<nr>,irq
+       Sets the floppy IRQ to <nr> instead of 6.
+
+ floppy=<nr>,dma
+       Sets the floppy DMA channel to <nr> instead of 2.
+
+ floppy=slow
+       Use PS/2 stepping rate::
+
+          PS/2 floppies have much slower step rates than regular floppies.
+          It's been recommended that take about 1/4 of the default speed
+          in some more extreme cases.
+
+
+Supporting utilities and additional documentation:
+==================================================
+
+Additional parameters of the floppy driver can be configured at
+runtime. Utilities which do this can be found in the fdutils package.
+This package also contains a new version of mtools which allows to
+access high capacity disks (up to 1992K on a high density 3 1/2 disk!).
+It also contains additional documentation about the floppy driver.
+
+The latest version can be found at fdutils homepage:
+
+ http://fdutils.linux.lu
+
+The fdutils releases can be found at:
+
+ http://fdutils.linux.lu/download.html
+
+ http://www.tux.org/pub/knaff/fdutils/
+
+ ftp://metalab.unc.edu/pub/Linux/utils/disk-management/
+
+Reporting problems about the floppy driver
+==========================================
+
+If you have a question or a bug report about the floppy driver, mail
+me at Alain.Knaff@poboxes.com . If you post to Usenet, preferably use
+comp.os.linux.hardware. As the volume in these groups is rather high,
+be sure to include the word "floppy" (or "FLOPPY") in the subject
+line.  If the reported problem happens when mounting floppy disks, be
+sure to mention also the type of the filesystem in the subject line.
+
+Be sure to read the FAQ before mailing/posting any bug reports!
+
+Alain
+
+Changelog
+=========
+
+10-30-2004 :
+               Cleanup, updating, add reference to module configuration.
+               James Nelson <james4765@gmail.com>
+
+6-3-2000 :
+               Original Document
diff --git a/Documentation/admin-guide/blockdev/index.rst b/Documentation/admin-guide/blockdev/index.rst
new file mode 100644 (file)
index 0000000..b903cf1
--- /dev/null
@@ -0,0 +1,16 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===========================
+The Linux RapidIO Subsystem
+===========================
+
+.. toctree::
+   :maxdepth: 1
+
+   floppy
+   nbd
+   paride
+   ramdisk
+   zram
+
+   drbd/index
diff --git a/Documentation/admin-guide/blockdev/nbd.rst b/Documentation/admin-guide/blockdev/nbd.rst
new file mode 100644 (file)
index 0000000..d78dfe5
--- /dev/null
@@ -0,0 +1,31 @@
+==================================
+Network Block Device (TCP version)
+==================================
+
+1) Overview
+-----------
+
+What is it: With this compiled in the kernel (or as a module), Linux
+can use a remote server as one of its block devices. So every time
+the client computer wants to read, e.g., /dev/nb0, it sends a
+request over TCP to the server, which will reply with the data read.
+This can be used for stations with low disk space (or even diskless)
+to borrow disk space from another computer.
+Unlike NFS, it is possible to put any filesystem on it, etc.
+
+For more information, or to download the nbd-client and nbd-server
+tools, go to http://nbd.sf.net/.
+
+The nbd kernel module need only be installed on the client
+system, as the nbd-server is completely in userspace. In fact,
+the nbd-server has been successfully ported to other operating
+systems, including Windows.
+
+A) NBD parameters
+-----------------
+
+max_part
+       Number of partitions per device (default: 0).
+
+nbds_max
+       Number of block devices that should be initialized (default: 16).
diff --git a/Documentation/admin-guide/blockdev/paride.rst b/Documentation/admin-guide/blockdev/paride.rst
new file mode 100644 (file)
index 0000000..87b4278
--- /dev/null
@@ -0,0 +1,439 @@
+===================================
+Linux and parallel port IDE devices
+===================================
+
+PARIDE v1.03   (c) 1997-8  Grant Guenther <grant@torque.net>
+
+1. Introduction
+===============
+
+Owing to the simplicity and near universality of the parallel port interface
+to personal computers, many external devices such as portable hard-disk,
+CD-ROM, LS-120 and tape drives use the parallel port to connect to their
+host computer.  While some devices (notably scanners) use ad-hoc methods
+to pass commands and data through the parallel port interface, most
+external devices are actually identical to an internal model, but with
+a parallel-port adapter chip added in.  Some of the original parallel port
+adapters were little more than mechanisms for multiplexing a SCSI bus.
+(The Iomega PPA-3 adapter used in the ZIP drives is an example of this
+approach).  Most current designs, however, take a different approach.
+The adapter chip reproduces a small ISA or IDE bus in the external device
+and the communication protocol provides operations for reading and writing
+device registers, as well as data block transfer functions.  Sometimes,
+the device being addressed via the parallel cable is a standard SCSI
+controller like an NCR 5380.  The "ditto" family of external tape
+drives use the ISA replicator to interface a floppy disk controller,
+which is then connected to a floppy-tape mechanism.  The vast majority
+of external parallel port devices, however, are now based on standard
+IDE type devices, which require no intermediate controller.  If one
+were to open up a parallel port CD-ROM drive, for instance, one would
+find a standard ATAPI CD-ROM drive, a power supply, and a single adapter
+that interconnected a standard PC parallel port cable and a standard
+IDE cable.  It is usually possible to exchange the CD-ROM device with
+any other device using the IDE interface.
+
+The document describes the support in Linux for parallel port IDE
+devices.  It does not cover parallel port SCSI devices, "ditto" tape
+drives or scanners.  Many different devices are supported by the
+parallel port IDE subsystem, including:
+
+       - MicroSolutions backpack CD-ROM
+       - MicroSolutions backpack PD/CD
+       - MicroSolutions backpack hard-drives
+       - MicroSolutions backpack 8000t tape drive
+       - SyQuest EZ-135, EZ-230 & SparQ drives
+       - Avatar Shark
+       - Imation Superdisk LS-120
+       - Maxell Superdisk LS-120
+       - FreeCom Power CD
+       - Hewlett-Packard 5GB and 8GB tape drives
+       - Hewlett-Packard 7100 and 7200 CD-RW drives
+
+as well as most of the clone and no-name products on the market.
+
+To support such a wide range of devices, PARIDE, the parallel port IDE
+subsystem, is actually structured in three parts.   There is a base
+paride module which provides a registry and some common methods for
+accessing the parallel ports.  The second component is a set of
+high-level drivers for each of the different types of supported devices:
+
+       ===     =============
+       pd      IDE disk
+       pcd     ATAPI CD-ROM
+       pf      ATAPI disk
+       pt      ATAPI tape
+       pg      ATAPI generic
+       ===     =============
+
+(Currently, the pg driver is only used with CD-R drives).
+
+The high-level drivers function according to the relevant standards.
+The third component of PARIDE is a set of low-level protocol drivers
+for each of the parallel port IDE adapter chips.  Thanks to the interest
+and encouragement of Linux users from many parts of the world,
+support is available for almost all known adapter protocols:
+
+       ====    ====================================== ====
+        aten    ATEN EH-100                            (HK)
+        bpck    Microsolutions backpack                (US)
+        comm    DataStor (old-type) "commuter" adapter (TW)
+        dstr    DataStor EP-2000                       (TW)
+        epat    Shuttle EPAT                           (UK)
+        epia    Shuttle EPIA                           (UK)
+       fit2    FIT TD-2000                            (US)
+       fit3    FIT TD-3000                            (US)
+       friq    Freecom IQ cable                       (DE)
+        frpw    Freecom Power                          (DE)
+        kbic    KingByte KBIC-951A and KBIC-971A       (TW)
+       ktti    KT Technology PHd adapter              (SG)
+        on20    OnSpec 90c20                           (US)
+        on26    OnSpec 90c26                           (US)
+       ====    ====================================== ====
+
+
+2. Using the PARIDE subsystem
+=============================
+
+While configuring the Linux kernel, you may choose either to build
+the PARIDE drivers into your kernel, or to build them as modules.
+
+In either case, you will need to select "Parallel port IDE device support"
+as well as at least one of the high-level drivers and at least one
+of the parallel port communication protocols.  If you do not know
+what kind of parallel port adapter is used in your drive, you could
+begin by checking the file names and any text files on your DOS
+installation floppy.  Alternatively, you can look at the markings on
+the adapter chip itself.  That's usually sufficient to identify the
+correct device.
+
+You can actually select all the protocol modules, and allow the PARIDE
+subsystem to try them all for you.
+
+For the "brand-name" products listed above, here are the protocol
+and high-level drivers that you would use:
+
+       ================        ============    ======  ========
+       Manufacturer            Model           Driver  Protocol
+       ================        ============    ======  ========
+       MicroSolutions          CD-ROM          pcd     bpck
+       MicroSolutions          PD drive        pf      bpck
+       MicroSolutions          hard-drive      pd      bpck
+       MicroSolutions          8000t tape      pt      bpck
+       SyQuest                 EZ, SparQ       pd      epat
+       Imation                 Superdisk       pf      epat
+       Maxell                  Superdisk       pf      friq
+       Avatar                  Shark           pd      epat
+       FreeCom                 CD-ROM          pcd     frpw
+       Hewlett-Packard         5GB Tape        pt      epat
+       Hewlett-Packard         7200e (CD)      pcd     epat
+       Hewlett-Packard         7200e (CD-R)    pg      epat
+       ================        ============    ======  ========
+
+2.1  Configuring built-in drivers
+---------------------------------
+
+We recommend that you get to know how the drivers work and how to
+configure them as loadable modules, before attempting to compile a
+kernel with the drivers built-in.
+
+If you built all of your PARIDE support directly into your kernel,
+and you have just a single parallel port IDE device, your kernel should
+locate it automatically for you.  If you have more than one device,
+you may need to give some command line options to your bootloader
+(eg: LILO), how to do that is beyond the scope of this document.
+
+The high-level drivers accept a number of command line parameters, all
+of which are documented in the source files in linux/drivers/block/paride.
+By default, each driver will automatically try all parallel ports it
+can find, and all protocol types that have been installed, until it finds
+a parallel port IDE adapter.  Once it finds one, the probe stops.  So,
+if you have more than one device, you will need to tell the drivers
+how to identify them.  This requires specifying the port address, the
+protocol identification number and, for some devices, the drive's
+chain ID.  While your system is booting, a number of messages are
+displayed on the console.  Like all such messages, they can be
+reviewed with the 'dmesg' command.  Among those messages will be
+some lines like::
+
+       paride: bpck registered as protocol 0
+       paride: epat registered as protocol 1
+
+The numbers will always be the same until you build a new kernel with
+different protocol selections.  You should note these numbers as you
+will need them to identify the devices.
+
+If you happen to be using a MicroSolutions backpack device, you will
+also need to know the unit ID number for each drive.  This is usually
+the last two digits of the drive's serial number (but read MicroSolutions'
+documentation about this).
+
+As an example, let's assume that you have a MicroSolutions PD/CD drive
+with unit ID number 36 connected to the parallel port at 0x378, a SyQuest
+EZ-135 connected to the chained port on the PD/CD drive and also an
+Imation Superdisk connected to port 0x278.  You could give the following
+options on your boot command::
+
+       pd.drive0=0x378,1 pf.drive0=0x278,1 pf.drive1=0x378,0,36
+
+In the last option, pf.drive1 configures device /dev/pf1, the 0x378
+is the parallel port base address, the 0 is the protocol registration
+number and 36 is the chain ID.
+
+Please note:  while PARIDE will work both with and without the
+PARPORT parallel port sharing system that is included by the
+"Parallel port support" option, PARPORT must be included and enabled
+if you want to use chains of devices on the same parallel port.
+
+2.2  Loading and configuring PARIDE as modules
+----------------------------------------------
+
+It is much faster and simpler to get to understand the PARIDE drivers
+if you use them as loadable kernel modules.
+
+Note 1:
+       using these drivers with the "kerneld" automatic module loading
+       system is not recommended for beginners, and is not documented here.
+
+Note 2:
+       if you build PARPORT support as a loadable module, PARIDE must
+       also be built as loadable modules, and PARPORT must be loaded before
+       the PARIDE modules.
+
+To use PARIDE, you must begin by::
+
+       insmod paride
+
+this loads a base module which provides a registry for the protocols,
+among other tasks.
+
+Then, load as many of the protocol modules as you think you might need.
+As you load each module, it will register the protocols that it supports,
+and print a log message to your kernel log file and your console. For
+example::
+
+       # insmod epat
+       paride: epat registered as protocol 0
+       # insmod kbic
+       paride: k951 registered as protocol 1
+        paride: k971 registered as protocol 2
+
+Finally, you can load high-level drivers for each kind of device that
+you have connected.  By default, each driver will autoprobe for a single
+device, but you can support up to four similar devices by giving their
+individual co-ordinates when you load the driver.
+
+For example, if you had two no-name CD-ROM drives both using the
+KingByte KBIC-951A adapter, one on port 0x378 and the other on 0x3bc
+you could give the following command::
+
+       # insmod pcd drive0=0x378,1 drive1=0x3bc,1
+
+For most adapters, giving a port address and protocol number is sufficient,
+but check the source files in linux/drivers/block/paride for more
+information.  (Hopefully someone will write some man pages one day !).
+
+As another example, here's what happens when PARPORT is installed, and
+a SyQuest EZ-135 is attached to port 0x378::
+
+       # insmod paride
+       paride: version 1.0 installed
+       # insmod epat
+       paride: epat registered as protocol 0
+       # insmod pd
+       pd: pd version 1.0, major 45, cluster 64, nice 0
+       pda: Sharing parport1 at 0x378
+       pda: epat 1.0, Shuttle EPAT chip c3 at 0x378, mode 5 (EPP-32), delay 1
+       pda: SyQuest EZ135A, 262144 blocks [128M], (512/16/32), removable media
+        pda: pda1
+
+Note that the last line is the output from the generic partition table
+scanner - in this case it reports that it has found a disk with one partition.
+
+2.3  Using a PARIDE device
+--------------------------
+
+Once the drivers have been loaded, you can access PARIDE devices in the
+same way as their traditional counterparts.  You will probably need to
+create the device "special files".  Here is a simple script that you can
+cut to a file and execute::
+
+  #!/bin/bash
+  #
+  # mkd -- a script to create the device special files for the PARIDE subsystem
+  #
+  function mkdev {
+    mknod $1 $2 $3 $4 ; chmod 0660 $1 ; chown root:disk $1
+  }
+  #
+  function pd {
+    D=$( printf \\$( printf "x%03x" $[ $1 + 97 ] ) )
+    mkdev pd$D b 45 $[ $1 * 16 ]
+    for P in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+    do mkdev pd$D$P b 45 $[ $1 * 16 + $P ]
+    done
+  }
+  #
+  cd /dev
+  #
+  for u in 0 1 2 3 ; do pd $u ; done
+  for u in 0 1 2 3 ; do mkdev pcd$u b 46 $u ; done
+  for u in 0 1 2 3 ; do mkdev pf$u  b 47 $u ; done
+  for u in 0 1 2 3 ; do mkdev pt$u  c 96 $u ; done
+  for u in 0 1 2 3 ; do mkdev npt$u c 96 $[ $u + 128 ] ; done
+  for u in 0 1 2 3 ; do mkdev pg$u  c 97 $u ; done
+  #
+  # end of mkd
+
+With the device files and drivers in place, you can access PARIDE devices
+like any other Linux device.   For example, to mount a CD-ROM in pcd0, use::
+
+       mount /dev/pcd0 /cdrom
+
+If you have a fresh Avatar Shark cartridge, and the drive is pda, you
+might do something like::
+
+       fdisk /dev/pda          -- make a new partition table with
+                                  partition 1 of type 83
+
+       mke2fs /dev/pda1        -- to build the file system
+
+       mkdir /shark            -- make a place to mount the disk
+
+       mount /dev/pda1 /shark
+
+Devices like the Imation superdisk work in the same way, except that
+they do not have a partition table.  For example to make a 120MB
+floppy that you could share with a DOS system::
+
+       mkdosfs /dev/pf0
+       mount /dev/pf0 /mnt
+
+
+2.4  The pf driver
+------------------
+
+The pf driver is intended for use with parallel port ATAPI disk
+devices.  The most common devices in this category are PD drives
+and LS-120 drives.  Traditionally, media for these devices are not
+partitioned.  Consequently, the pf driver does not support partitioned
+media.  This may be changed in a future version of the driver.
+
+2.5  Using the pt driver
+------------------------
+
+The pt driver for parallel port ATAPI tape drives is a minimal driver.
+It does not yet support many of the standard tape ioctl operations.
+For best performance, a block size of 32KB should be used.  You will
+probably want to set the parallel port delay to 0, if you can.
+
+2.6  Using the pg driver
+------------------------
+
+The pg driver can be used in conjunction with the cdrecord program
+to create CD-ROMs.  Please get cdrecord version 1.6.1 or later
+from ftp://ftp.fokus.gmd.de/pub/unix/cdrecord/ .  To record CD-R media
+your parallel port should ideally be set to EPP mode, and the "port delay"
+should be set to 0.  With those settings it is possible to record at 2x
+speed without any buffer underruns.  If you cannot get the driver to work
+in EPP mode, try to use "bidirectional" or "PS/2" mode and 1x speeds only.
+
+
+3. Troubleshooting
+==================
+
+3.1  Use EPP mode if you can
+----------------------------
+
+The most common problems that people report with the PARIDE drivers
+concern the parallel port CMOS settings.  At this time, none of the
+PARIDE protocol modules support ECP mode, or any ECP combination modes.
+If you are able to do so, please set your parallel port into EPP mode
+using your CMOS setup procedure.
+
+3.2  Check the port delay
+-------------------------
+
+Some parallel ports cannot reliably transfer data at full speed.  To
+offset the errors, the PARIDE protocol modules introduce a "port
+delay" between each access to the i/o ports.  Each protocol sets
+a default value for this delay.  In most cases, the user can override
+the default and set it to 0 - resulting in somewhat higher transfer
+rates.  In some rare cases (especially with older 486 systems) the
+default delays are not long enough.  if you experience corrupt data
+transfers, or unexpected failures, you may wish to increase the
+port delay.   The delay can be programmed using the "driveN" parameters
+to each of the high-level drivers.  Please see the notes above, or
+read the comments at the beginning of the driver source files in
+linux/drivers/block/paride.
+
+3.3  Some drives need a printer reset
+-------------------------------------
+
+There appear to be a number of "noname" external drives on the market
+that do not always power up correctly.  We have noticed this with some
+drives based on OnSpec and older Freecom adapters.  In these rare cases,
+the adapter can often be reinitialised by issuing a "printer reset" on
+the parallel port.  As the reset operation is potentially disruptive in
+multiple device environments, the PARIDE drivers will not do it
+automatically.  You can however, force a printer reset by doing::
+
+       insmod lp reset=1
+       rmmod lp
+
+If you have one of these marginal cases, you should probably build
+your paride drivers as modules, and arrange to do the printer reset
+before loading the PARIDE drivers.
+
+3.4  Use the verbose option and dmesg if you need help
+------------------------------------------------------
+
+While a lot of testing has gone into these drivers to make them work
+as smoothly as possible, problems will arise.  If you do have problems,
+please check all the obvious things first:  does the drive work in
+DOS with the manufacturer's drivers ?  If that doesn't yield any useful
+clues, then please make sure that only one drive is hooked to your system,
+and that either (a) PARPORT is enabled or (b) no other device driver
+is using your parallel port (check in /proc/ioports).  Then, load the
+appropriate drivers (you can load several protocol modules if you want)
+as in::
+
+       # insmod paride
+       # insmod epat
+       # insmod bpck
+       # insmod kbic
+       ...
+       # insmod pd verbose=1
+
+(using the correct driver for the type of device you have, of course).
+The verbose=1 parameter will cause the drivers to log a trace of their
+activity as they attempt to locate your drive.
+
+Use 'dmesg' to capture a log of all the PARIDE messages (any messages
+beginning with paride:, a protocol module's name or a driver's name) and
+include that with your bug report.  You can submit a bug report in one
+of two ways.  Either send it directly to the author of the PARIDE suite,
+by e-mail to grant@torque.net, or join the linux-parport mailing list
+and post your report there.
+
+3.5  For more information or help
+---------------------------------
+
+You can join the linux-parport mailing list by sending a mail message
+to:
+
+               linux-parport-request@torque.net
+
+with the single word::
+
+               subscribe
+
+in the body of the mail message (not in the subject line).   Please be
+sure that your mail program is correctly set up when you do this,  as
+the list manager is a robot that will subscribe you using the reply
+address in your mail headers.  REMOVE any anti-spam gimmicks you may
+have in your mail headers, when sending mail to the list server.
+
+You might also find some useful information on the linux-parport
+web pages (although they are not always up to date) at
+
+       http://web.archive.org/web/%2E/http://www.torque.net/parport/
diff --git a/Documentation/admin-guide/blockdev/ramdisk.rst b/Documentation/admin-guide/blockdev/ramdisk.rst
new file mode 100644 (file)
index 0000000..b7c2268
--- /dev/null
@@ -0,0 +1,177 @@
+==========================================
+Using the RAM disk block device with Linux
+==========================================
+
+.. Contents:
+
+       1) Overview
+       2) Kernel Command Line Parameters
+       3) Using "rdev -r"
+       4) An Example of Creating a Compressed RAM Disk
+
+
+1) Overview
+-----------
+
+The RAM disk driver is a way to use main system memory as a block device.  It
+is required for initrd, an initial filesystem used if you need to load modules
+in order to access the root filesystem (see Documentation/admin-guide/initrd.rst).  It can
+also be used for a temporary filesystem for crypto work, since the contents
+are erased on reboot.
+
+The RAM disk dynamically grows as more space is required. It does this by using
+RAM from the buffer cache. The driver marks the buffers it is using as dirty
+so that the VM subsystem does not try to reclaim them later.
+
+The RAM disk supports up to 16 RAM disks by default, and can be reconfigured
+to support an unlimited number of RAM disks (at your own risk).  Just change
+the configuration symbol BLK_DEV_RAM_COUNT in the Block drivers config menu
+and (re)build the kernel.
+
+To use RAM disk support with your system, run './MAKEDEV ram' from the /dev
+directory.  RAM disks are all major number 1, and start with minor number 0
+for /dev/ram0, etc.  If used, modern kernels use /dev/ram0 for an initrd.
+
+The new RAM disk also has the ability to load compressed RAM disk images,
+allowing one to squeeze more programs onto an average installation or
+rescue floppy disk.
+
+
+2) Parameters
+---------------------------------
+
+2a) Kernel Command Line Parameters
+
+       ramdisk_size=N
+               Size of the ramdisk.
+
+This parameter tells the RAM disk driver to set up RAM disks of N k size.  The
+default is 4096 (4 MB).
+
+2b) Module parameters
+
+       rd_nr
+               /dev/ramX devices created.
+
+       max_part
+               Maximum partition number.
+
+       rd_size
+               See ramdisk_size.
+
+3) Using "rdev -r"
+------------------
+
+The usage of the word (two bytes) that "rdev -r" sets in the kernel image is
+as follows. The low 11 bits (0 -> 10) specify an offset (in 1 k blocks) of up
+to 2 MB (2^11) of where to find the RAM disk (this used to be the size). Bit
+14 indicates that a RAM disk is to be loaded, and bit 15 indicates whether a
+prompt/wait sequence is to be given before trying to read the RAM disk. Since
+the RAM disk dynamically grows as data is being written into it, a size field
+is not required. Bits 11 to 13 are not currently used and may as well be zero.
+These numbers are no magical secrets, as seen below::
+
+  ./arch/x86/kernel/setup.c:#define RAMDISK_IMAGE_START_MASK     0x07FF
+  ./arch/x86/kernel/setup.c:#define RAMDISK_PROMPT_FLAG          0x8000
+  ./arch/x86/kernel/setup.c:#define RAMDISK_LOAD_FLAG            0x4000
+
+Consider a typical two floppy disk setup, where you will have the
+kernel on disk one, and have already put a RAM disk image onto disk #2.
+
+Hence you want to set bits 0 to 13 as 0, meaning that your RAM disk
+starts at an offset of 0 kB from the beginning of the floppy.
+The command line equivalent is: "ramdisk_start=0"
+
+You want bit 14 as one, indicating that a RAM disk is to be loaded.
+The command line equivalent is: "load_ramdisk=1"
+
+You want bit 15 as one, indicating that you want a prompt/keypress
+sequence so that you have a chance to switch floppy disks.
+The command line equivalent is: "prompt_ramdisk=1"
+
+Putting that together gives 2^15 + 2^14 + 0 = 49152 for an rdev word.
+So to create disk one of the set, you would do::
+
+       /usr/src/linux# cat arch/x86/boot/zImage > /dev/fd0
+       /usr/src/linux# rdev /dev/fd0 /dev/fd0
+       /usr/src/linux# rdev -r /dev/fd0 49152
+
+If you make a boot disk that has LILO, then for the above, you would use::
+
+       append = "ramdisk_start=0 load_ramdisk=1 prompt_ramdisk=1"
+
+Since the default start = 0 and the default prompt = 1, you could use::
+
+       append = "load_ramdisk=1"
+
+
+4) An Example of Creating a Compressed RAM Disk
+-----------------------------------------------
+
+To create a RAM disk image, you will need a spare block device to
+construct it on. This can be the RAM disk device itself, or an
+unused disk partition (such as an unmounted swap partition). For this
+example, we will use the RAM disk device, "/dev/ram0".
+
+Note: This technique should not be done on a machine with less than 8 MB
+of RAM. If using a spare disk partition instead of /dev/ram0, then this
+restriction does not apply.
+
+a) Decide on the RAM disk size that you want. Say 2 MB for this example.
+   Create it by writing to the RAM disk device. (This step is not currently
+   required, but may be in the future.) It is wise to zero out the
+   area (esp. for disks) so that maximal compression is achieved for
+   the unused blocks of the image that you are about to create::
+
+       dd if=/dev/zero of=/dev/ram0 bs=1k count=2048
+
+b) Make a filesystem on it. Say ext2fs for this example::
+
+       mke2fs -vm0 /dev/ram0 2048
+
+c) Mount it, copy the files you want to it (eg: /etc/* /dev/* ...)
+   and unmount it again.
+
+d) Compress the contents of the RAM disk. The level of compression
+   will be approximately 50% of the space used by the files. Unused
+   space on the RAM disk will compress to almost nothing::
+
+       dd if=/dev/ram0 bs=1k count=2048 | gzip -v9 > /tmp/ram_image.gz
+
+e) Put the kernel onto the floppy::
+
+       dd if=zImage of=/dev/fd0 bs=1k
+
+f) Put the RAM disk image onto the floppy, after the kernel. Use an offset
+   that is slightly larger than the kernel, so that you can put another
+   (possibly larger) kernel onto the same floppy later without overlapping
+   the RAM disk image. An offset of 400 kB for kernels about 350 kB in
+   size would be reasonable. Make sure offset+size of ram_image.gz is
+   not larger than the total space on your floppy (usually 1440 kB)::
+
+       dd if=/tmp/ram_image.gz of=/dev/fd0 bs=1k seek=400
+
+g) Use "rdev" to set the boot device, RAM disk offset, prompt flag, etc.
+   For prompt_ramdisk=1, load_ramdisk=1, ramdisk_start=400, one would
+   have 2^15 + 2^14 + 400 = 49552::
+
+       rdev /dev/fd0 /dev/fd0
+       rdev -r /dev/fd0 49552
+
+That is it. You now have your boot/root compressed RAM disk floppy. Some
+users may wish to combine steps (d) and (f) by using a pipe.
+
+
+                                               Paul Gortmaker 12/95
+
+Changelog:
+----------
+
+10-22-04 :
+               Updated to reflect changes in command line options, remove
+               obsolete references, general cleanup.
+               James Nelson (james4765@gmail.com)
+
+
+12-95 :
+               Original Document
diff --git a/Documentation/admin-guide/blockdev/zram.rst b/Documentation/admin-guide/blockdev/zram.rst
new file mode 100644 (file)
index 0000000..6eccf13
--- /dev/null
@@ -0,0 +1,422 @@
+========================================
+zram: Compressed RAM based block devices
+========================================
+
+Introduction
+============
+
+The zram module creates RAM based block devices named /dev/zram<id>
+(<id> = 0, 1, ...). Pages written to these disks are compressed and stored
+in memory itself. These disks allow very fast I/O and compression provides
+good amounts of memory savings. Some of the usecases include /tmp storage,
+use as swap disks, various caches under /var and maybe many more :)
+
+Statistics for individual zram devices are exported through sysfs nodes at
+/sys/block/zram<id>/
+
+Usage
+=====
+
+There are several ways to configure and manage zram device(-s):
+
+a) using zram and zram_control sysfs attributes
+b) using zramctl utility, provided by util-linux (util-linux@vger.kernel.org).
+
+In this document we will describe only 'manual' zram configuration steps,
+IOW, zram and zram_control sysfs attributes.
+
+In order to get a better idea about zramctl please consult util-linux
+documentation, zramctl man-page or `zramctl --help`. Please be informed
+that zram maintainers do not develop/maintain util-linux or zramctl, should
+you have any questions please contact util-linux@vger.kernel.org
+
+Following shows a typical sequence of steps for using zram.
+
+WARNING
+=======
+
+For the sake of simplicity we skip error checking parts in most of the
+examples below. However, it is your sole responsibility to handle errors.
+
+zram sysfs attributes always return negative values in case of errors.
+The list of possible return codes:
+
+========  =============================================================
+-EBUSY   an attempt to modify an attribute that cannot be changed once
+         the device has been initialised. Please reset device first;
+-ENOMEM          zram was not able to allocate enough memory to fulfil your
+         needs;
+-EINVAL          invalid input has been provided.
+========  =============================================================
+
+If you use 'echo', the returned value that is changed by 'echo' utility,
+and, in general case, something like::
+
+       echo 3 > /sys/block/zram0/max_comp_streams
+       if [ $? -ne 0 ];
+               handle_error
+       fi
+
+should suffice.
+
+1) Load Module
+==============
+
+::
+
+       modprobe zram num_devices=4
+       This creates 4 devices: /dev/zram{0,1,2,3}
+
+num_devices parameter is optional and tells zram how many devices should be
+pre-created. Default: 1.
+
+2) Set max number of compression streams
+========================================
+
+Regardless the value passed to this attribute, ZRAM will always
+allocate multiple compression streams - one per online CPUs - thus
+allowing several concurrent compression operations. The number of
+allocated compression streams goes down when some of the CPUs
+become offline. There is no single-compression-stream mode anymore,
+unless you are running a UP system or has only 1 CPU online.
+
+To find out how many streams are currently available::
+
+       cat /sys/block/zram0/max_comp_streams
+
+3) Select compression algorithm
+===============================
+
+Using comp_algorithm device attribute one can see available and
+currently selected (shown in square brackets) compression algorithms,
+change selected compression algorithm (once the device is initialised
+there is no way to change compression algorithm).
+
+Examples::
+
+       #show supported compression algorithms
+       cat /sys/block/zram0/comp_algorithm
+       lzo [lz4]
+
+       #select lzo compression algorithm
+       echo lzo > /sys/block/zram0/comp_algorithm
+
+For the time being, the `comp_algorithm` content does not necessarily
+show every compression algorithm supported by the kernel. We keep this
+list primarily to simplify device configuration and one can configure
+a new device with a compression algorithm that is not listed in
+`comp_algorithm`. The thing is that, internally, ZRAM uses Crypto API
+and, if some of the algorithms were built as modules, it's impossible
+to list all of them using, for instance, /proc/crypto or any other
+method. This, however, has an advantage of permitting the usage of
+custom crypto compression modules (implementing S/W or H/W compression).
+
+4) Set Disksize
+===============
+
+Set disk size by writing the value to sysfs node 'disksize'.
+The value can be either in bytes or you can use mem suffixes.
+Examples::
+
+       # Initialize /dev/zram0 with 50MB disksize
+       echo $((50*1024*1024)) > /sys/block/zram0/disksize
+
+       # Using mem suffixes
+       echo 256K > /sys/block/zram0/disksize
+       echo 512M > /sys/block/zram0/disksize
+       echo 1G > /sys/block/zram0/disksize
+
+Note:
+There is little point creating a zram of greater than twice the size of memory
+since we expect a 2:1 compression ratio. Note that zram uses about 0.1% of the
+size of the disk when not in use so a huge zram is wasteful.
+
+5) Set memory limit: Optional
+=============================
+
+Set memory limit by writing the value to sysfs node 'mem_limit'.
+The value can be either in bytes or you can use mem suffixes.
+In addition, you could change the value in runtime.
+Examples::
+
+       # limit /dev/zram0 with 50MB memory
+       echo $((50*1024*1024)) > /sys/block/zram0/mem_limit
+
+       # Using mem suffixes
+       echo 256K > /sys/block/zram0/mem_limit
+       echo 512M > /sys/block/zram0/mem_limit
+       echo 1G > /sys/block/zram0/mem_limit
+
+       # To disable memory limit
+       echo 0 > /sys/block/zram0/mem_limit
+
+6) Activate
+===========
+
+::
+
+       mkswap /dev/zram0
+       swapon /dev/zram0
+
+       mkfs.ext4 /dev/zram1
+       mount /dev/zram1 /tmp
+
+7) Add/remove zram devices
+==========================
+
+zram provides a control interface, which enables dynamic (on-demand) device
+addition and removal.
+
+In order to add a new /dev/zramX device, perform read operation on hot_add
+attribute. This will return either new device's device id (meaning that you
+can use /dev/zram<id>) or error code.
+
+Example::
+
+       cat /sys/class/zram-control/hot_add
+       1
+
+To remove the existing /dev/zramX device (where X is a device id)
+execute::
+
+       echo X > /sys/class/zram-control/hot_remove
+
+8) Stats
+========
+
+Per-device statistics are exported as various nodes under /sys/block/zram<id>/
+
+A brief description of exported device attributes. For more details please
+read Documentation/ABI/testing/sysfs-block-zram.
+
+======================  ======  ===============================================
+Name                   access            description
+======================  ======  ===============================================
+disksize               RW      show and set the device's disk size
+initstate              RO      shows the initialization state of the device
+reset                  WO      trigger device reset
+mem_used_max           WO      reset the `mem_used_max` counter (see later)
+mem_limit              WO      specifies the maximum amount of memory ZRAM can
+                               use to store the compressed data
+writeback_limit        WO      specifies the maximum amount of write IO zram
+                               can write out to backing device as 4KB unit
+writeback_limit_enable  RW     show and set writeback_limit feature
+max_comp_streams       RW      the number of possible concurrent compress
+                               operations
+comp_algorithm         RW      show and change the compression algorithm
+compact                WO      trigger memory compaction
+debug_stat             RO      this file is used for zram debugging purposes
+backing_dev            RW      set up backend storage for zram to write out
+idle                   WO      mark allocated slot as idle
+======================  ======  ===============================================
+
+
+User space is advised to use the following files to read the device statistics.
+
+File /sys/block/zram<id>/stat
+
+Represents block layer statistics. Read Documentation/block/stat.rst for
+details.
+
+File /sys/block/zram<id>/io_stat
+
+The stat file represents device's I/O statistics not accounted by block
+layer and, thus, not available in zram<id>/stat file. It consists of a
+single line of text and contains the following stats separated by
+whitespace:
+
+ =============    =============================================================
+ failed_reads     The number of failed reads
+ failed_writes    The number of failed writes
+ invalid_io       The number of non-page-size-aligned I/O requests
+ notify_free      Depending on device usage scenario it may account
+
+                  a) the number of pages freed because of swap slot free
+                     notifications
+                  b) the number of pages freed because of
+                     REQ_OP_DISCARD requests sent by bio. The former ones are
+                     sent to a swap block device when a swap slot is freed,
+                     which implies that this disk is being used as a swap disk.
+
+                  The latter ones are sent by filesystem mounted with
+                  discard option, whenever some data blocks are getting
+                  discarded.
+ =============    =============================================================
+
+File /sys/block/zram<id>/mm_stat
+
+The stat file represents device's mm statistics. It consists of a single
+line of text and contains the following stats separated by whitespace:
+
+ ================ =============================================================
+ orig_data_size   uncompressed size of data stored in this disk.
+                 This excludes same-element-filled pages (same_pages) since
+                 no memory is allocated for them.
+                  Unit: bytes
+ compr_data_size  compressed size of data stored in this disk
+ mem_used_total   the amount of memory allocated for this disk. This
+                  includes allocator fragmentation and metadata overhead,
+                  allocated for this disk. So, allocator space efficiency
+                  can be calculated using compr_data_size and this statistic.
+                  Unit: bytes
+ mem_limit        the maximum amount of memory ZRAM can use to store
+                  the compressed data
+ mem_used_max     the maximum amount of memory zram have consumed to
+                  store the data
+ same_pages       the number of same element filled pages written to this disk.
+                  No memory is allocated for such pages.
+ pages_compacted  the number of pages freed during compaction
+ huge_pages      the number of incompressible pages
+ ================ =============================================================
+
+File /sys/block/zram<id>/bd_stat
+
+The stat file represents device's backing device statistics. It consists of
+a single line of text and contains the following stats separated by whitespace:
+
+ ============== =============================================================
+ bd_count      size of data written in backing device.
+               Unit: 4K bytes
+ bd_reads      the number of reads from backing device
+               Unit: 4K bytes
+ bd_writes     the number of writes to backing device
+               Unit: 4K bytes
+ ============== =============================================================
+
+9) Deactivate
+=============
+
+::
+
+       swapoff /dev/zram0
+       umount /dev/zram1
+
+10) Reset
+=========
+
+       Write any positive value to 'reset' sysfs node::
+
+               echo 1 > /sys/block/zram0/reset
+               echo 1 > /sys/block/zram1/reset
+
+       This frees all the memory allocated for the given device and
+       resets the disksize to zero. You must set the disksize again
+       before reusing the device.
+
+Optional Feature
+================
+
+writeback
+---------
+
+With CONFIG_ZRAM_WRITEBACK, zram can write idle/incompressible page
+to backing storage rather than keeping it in memory.
+To use the feature, admin should set up backing device via::
+
+       echo /dev/sda5 > /sys/block/zramX/backing_dev
+
+before disksize setting. It supports only partition at this moment.
+If admin want to use incompressible page writeback, they could do via::
+
+       echo huge > /sys/block/zramX/write
+
+To use idle page writeback, first, user need to declare zram pages
+as idle::
+
+       echo all > /sys/block/zramX/idle
+
+From now on, any pages on zram are idle pages. The idle mark
+will be removed until someone request access of the block.
+IOW, unless there is access request, those pages are still idle pages.
+
+Admin can request writeback of those idle pages at right timing via::
+
+       echo idle > /sys/block/zramX/writeback
+
+With the command, zram writeback idle pages from memory to the storage.
+
+If there are lots of write IO with flash device, potentially, it has
+flash wearout problem so that admin needs to design write limitation
+to guarantee storage health for entire product life.
+
+To overcome the concern, zram supports "writeback_limit" feature.
+The "writeback_limit_enable"'s default value is 0 so that it doesn't limit
+any writeback. IOW, if admin want to apply writeback budget, he should
+enable writeback_limit_enable via::
+
+       $ echo 1 > /sys/block/zramX/writeback_limit_enable
+
+Once writeback_limit_enable is set, zram doesn't allow any writeback
+until admin set the budget via /sys/block/zramX/writeback_limit.
+
+(If admin doesn't enable writeback_limit_enable, writeback_limit's value
+assigned via /sys/block/zramX/writeback_limit is meaninless.)
+
+If admin want to limit writeback as per-day 400M, he could do it
+like below::
+
+       $ MB_SHIFT=20
+       $ 4K_SHIFT=12
+       $ echo $((400<<MB_SHIFT>>4K_SHIFT)) > \
+               /sys/block/zram0/writeback_limit.
+       $ echo 1 > /sys/block/zram0/writeback_limit_enable
+
+If admin want to allow further write again once the bugdet is exausted,
+he could do it like below::
+
+       $ echo $((400<<MB_SHIFT>>4K_SHIFT)) > \
+               /sys/block/zram0/writeback_limit
+
+If admin want to see remaining writeback budget since he set::
+
+       $ cat /sys/block/zramX/writeback_limit
+
+If admin want to disable writeback limit, he could do::
+
+       $ echo 0 > /sys/block/zramX/writeback_limit_enable
+
+The writeback_limit count will reset whenever you reset zram(e.g.,
+system reboot, echo 1 > /sys/block/zramX/reset) so keeping how many of
+writeback happened until you reset the zram to allocate extra writeback
+budget in next setting is user's job.
+
+If admin want to measure writeback count in a certain period, he could
+know it via /sys/block/zram0/bd_stat's 3rd column.
+
+memory tracking
+===============
+
+With CONFIG_ZRAM_MEMORY_TRACKING, user can know information of the
+zram block. It could be useful to catch cold or incompressible
+pages of the process with*pagemap.
+
+If you enable the feature, you could see block state via
+/sys/kernel/debug/zram/zram0/block_state". The output is as follows::
+
+         300    75.033841 .wh.
+         301    63.806904 s...
+         302    63.806919 ..hi
+
+First column
+       zram's block index.
+Second column
+       access time since the system was booted
+Third column
+       state of the block:
+
+       s:
+               same page
+       w:
+               written page to backing store
+       h:
+               huge page
+       i:
+               idle page
+
+First line of above example says 300th block is accessed at 75.033841sec
+and the block's state is huge so it is written back to the backing
+storage. It's a debugging feature so anyone shouldn't rely on it to work
+properly.
+
+Nitin Gupta
+ngupta@vflare.org
index b761aa2..44b8a4e 100644 (file)
@@ -90,9 +90,9 @@ the disk is not available then you have three options:
     run a null modem to a second machine and capture the output there
     using your favourite communication program.  Minicom works well.
 
-(3) Use Kdump (see Documentation/kdump/kdump.rst),
+(3) Use Kdump (see Documentation/admin-guide/kdump/kdump.rst),
     extract the kernel ring buffer from old memory with using dmesg
-    gdbmacro in Documentation/kdump/gdbmacros.txt.
+    gdbmacro in Documentation/admin-guide/kdump/gdbmacros.txt.
 
 Finding the bug's location
 --------------------------
diff --git a/Documentation/admin-guide/cgroup-v1/cgroups.rst b/Documentation/admin-guide/cgroup-v1/cgroups.rst
new file mode 100644 (file)
index 0000000..b068801
--- /dev/null
@@ -0,0 +1,695 @@
+==============
+Control Groups
+==============
+
+Written by Paul Menage <menage@google.com> based on
+Documentation/admin-guide/cgroup-v1/cpusets.rst
+
+Original copyright statements from cpusets.txt:
+
+Portions Copyright (C) 2004 BULL SA.
+
+Portions Copyright (c) 2004-2006 Silicon Graphics, Inc.
+
+Modified by Paul Jackson <pj@sgi.com>
+
+Modified by Christoph Lameter <cl@linux.com>
+
+.. CONTENTS:
+
+       1. Control Groups
+       1.1 What are cgroups ?
+       1.2 Why are cgroups needed ?
+       1.3 How are cgroups implemented ?
+       1.4 What does notify_on_release do ?
+       1.5 What does clone_children do ?
+       1.6 How do I use cgroups ?
+       2. Usage Examples and Syntax
+       2.1 Basic Usage
+       2.2 Attaching processes
+       2.3 Mounting hierarchies by name
+       3. Kernel API
+       3.1 Overview
+       3.2 Synchronization
+       3.3 Subsystem API
+       4. Extended attributes usage
+       5. Questions
+
+1. Control Groups
+=================
+
+1.1 What are cgroups ?
+----------------------
+
+Control Groups provide a mechanism for aggregating/partitioning sets of
+tasks, and all their future children, into hierarchical groups with
+specialized behaviour.
+
+Definitions:
+
+A *cgroup* associates a set of tasks with a set of parameters for one
+or more subsystems.
+
+A *subsystem* is a module that makes use of the task grouping
+facilities provided by cgroups to treat groups of tasks in
+particular ways. A subsystem is typically a "resource controller" that
+schedules a resource or applies per-cgroup limits, but it may be
+anything that wants to act on a group of processes, e.g. a
+virtualization subsystem.
+
+A *hierarchy* is a set of cgroups arranged in a tree, such that
+every task in the system is in exactly one of the cgroups in the
+hierarchy, and a set of subsystems; each subsystem has system-specific
+state attached to each cgroup in the hierarchy.  Each hierarchy has
+an instance of the cgroup virtual filesystem associated with it.
+
+At any one time there may be multiple active hierarchies of task
+cgroups. Each hierarchy is a partition of all tasks in the system.
+
+User-level code may create and destroy cgroups by name in an
+instance of the cgroup virtual file system, specify and query to
+which cgroup a task is assigned, and list the task PIDs assigned to
+a cgroup. Those creations and assignments only affect the hierarchy
+associated with that instance of the cgroup file system.
+
+On their own, the only use for cgroups is for simple job
+tracking. The intention is that other subsystems hook into the generic
+cgroup support to provide new attributes for cgroups, such as
+accounting/limiting the resources which processes in a cgroup can
+access. For example, cpusets (see Documentation/admin-guide/cgroup-v1/cpusets.rst) allow
+you to associate a set of CPUs and a set of memory nodes with the
+tasks in each cgroup.
+
+1.2 Why are cgroups needed ?
+----------------------------
+
+There are multiple efforts to provide process aggregations in the
+Linux kernel, mainly for resource-tracking purposes. Such efforts
+include cpusets, CKRM/ResGroups, UserBeanCounters, and virtual server
+namespaces. These all require the basic notion of a
+grouping/partitioning of processes, with newly forked processes ending
+up in the same group (cgroup) as their parent process.
+
+The kernel cgroup patch provides the minimum essential kernel
+mechanisms required to efficiently implement such groups. It has
+minimal impact on the system fast paths, and provides hooks for
+specific subsystems such as cpusets to provide additional behaviour as
+desired.
+
+Multiple hierarchy support is provided to allow for situations where
+the division of tasks into cgroups is distinctly different for
+different subsystems - having parallel hierarchies allows each
+hierarchy to be a natural division of tasks, without having to handle
+complex combinations of tasks that would be present if several
+unrelated subsystems needed to be forced into the same tree of
+cgroups.
+
+At one extreme, each resource controller or subsystem could be in a
+separate hierarchy; at the other extreme, all subsystems
+would be attached to the same hierarchy.
+
+As an example of a scenario (originally proposed by vatsa@in.ibm.com)
+that can benefit from multiple hierarchies, consider a large
+university server with various users - students, professors, system
+tasks etc. The resource planning for this server could be along the
+following lines::
+
+       CPU :          "Top cpuset"
+                       /       \
+               CPUSet1         CPUSet2
+                  |               |
+               (Professors)    (Students)
+
+               In addition (system tasks) are attached to topcpuset (so
+               that they can run anywhere) with a limit of 20%
+
+       Memory : Professors (50%), Students (30%), system (20%)
+
+       Disk : Professors (50%), Students (30%), system (20%)
+
+       Network : WWW browsing (20%), Network File System (60%), others (20%)
+                               / \
+               Professors (15%)  students (5%)
+
+Browsers like Firefox/Lynx go into the WWW network class, while (k)nfsd goes
+into the NFS network class.
+
+At the same time Firefox/Lynx will share an appropriate CPU/Memory class
+depending on who launched it (prof/student).
+
+With the ability to classify tasks differently for different resources
+(by putting those resource subsystems in different hierarchies),
+the admin can easily set up a script which receives exec notifications
+and depending on who is launching the browser he can::
+
+    # echo browser_pid > /sys/fs/cgroup/<restype>/<userclass>/tasks
+
+With only a single hierarchy, he now would potentially have to create
+a separate cgroup for every browser launched and associate it with
+appropriate network and other resource class.  This may lead to
+proliferation of such cgroups.
+
+Also let's say that the administrator would like to give enhanced network
+access temporarily to a student's browser (since it is night and the user
+wants to do online gaming :))  OR give one of the student's simulation
+apps enhanced CPU power.
+
+With ability to write PIDs directly to resource classes, it's just a
+matter of::
+
+       # echo pid > /sys/fs/cgroup/network/<new_class>/tasks
+       (after some time)
+       # echo pid > /sys/fs/cgroup/network/<orig_class>/tasks
+
+Without this ability, the administrator would have to split the cgroup into
+multiple separate ones and then associate the new cgroups with the
+new resource classes.
+
+
+
+1.3 How are cgroups implemented ?
+---------------------------------
+
+Control Groups extends the kernel as follows:
+
+ - Each task in the system has a reference-counted pointer to a
+   css_set.
+
+ - A css_set contains a set of reference-counted pointers to
+   cgroup_subsys_state objects, one for each cgroup subsystem
+   registered in the system. There is no direct link from a task to
+   the cgroup of which it's a member in each hierarchy, but this
+   can be determined by following pointers through the
+   cgroup_subsys_state objects. This is because accessing the
+   subsystem state is something that's expected to happen frequently
+   and in performance-critical code, whereas operations that require a
+   task's actual cgroup assignments (in particular, moving between
+   cgroups) are less common. A linked list runs through the cg_list
+   field of each task_struct using the css_set, anchored at
+   css_set->tasks.
+
+ - A cgroup hierarchy filesystem can be mounted for browsing and
+   manipulation from user space.
+
+ - You can list all the tasks (by PID) attached to any cgroup.
+
+The implementation of cgroups requires a few, simple hooks
+into the rest of the kernel, none in performance-critical paths:
+
+ - in init/main.c, to initialize the root cgroups and initial
+   css_set at system boot.
+
+ - in fork and exit, to attach and detach a task from its css_set.
+
+In addition, a new file system of type "cgroup" may be mounted, to
+enable browsing and modifying the cgroups presently known to the
+kernel.  When mounting a cgroup hierarchy, you may specify a
+comma-separated list of subsystems to mount as the filesystem mount
+options.  By default, mounting the cgroup filesystem attempts to
+mount a hierarchy containing all registered subsystems.
+
+If an active hierarchy with exactly the same set of subsystems already
+exists, it will be reused for the new mount. If no existing hierarchy
+matches, and any of the requested subsystems are in use in an existing
+hierarchy, the mount will fail with -EBUSY. Otherwise, a new hierarchy
+is activated, associated with the requested subsystems.
+
+It's not currently possible to bind a new subsystem to an active
+cgroup hierarchy, or to unbind a subsystem from an active cgroup
+hierarchy. This may be possible in future, but is fraught with nasty
+error-recovery issues.
+
+When a cgroup filesystem is unmounted, if there are any
+child cgroups created below the top-level cgroup, that hierarchy
+will remain active even though unmounted; if there are no
+child cgroups then the hierarchy will be deactivated.
+
+No new system calls are added for cgroups - all support for
+querying and modifying cgroups is via this cgroup file system.
+
+Each task under /proc has an added file named 'cgroup' displaying,
+for each active hierarchy, the subsystem names and the cgroup name
+as the path relative to the root of the cgroup file system.
+
+Each cgroup is represented by a directory in the cgroup file system
+containing the following files describing that cgroup:
+
+ - tasks: list of tasks (by PID) attached to that cgroup.  This list
+   is not guaranteed to be sorted.  Writing a thread ID into this file
+   moves the thread into this cgroup.
+ - cgroup.procs: list of thread group IDs in the cgroup.  This list is
+   not guaranteed to be sorted or free of duplicate TGIDs, and userspace
+   should sort/uniquify the list if this property is required.
+   Writing a thread group ID into this file moves all threads in that
+   group into this cgroup.
+ - notify_on_release flag: run the release agent on exit?
+ - release_agent: the path to use for release notifications (this file
+   exists in the top cgroup only)
+
+Other subsystems such as cpusets may add additional files in each
+cgroup dir.
+
+New cgroups are created using the mkdir system call or shell
+command.  The properties of a cgroup, such as its flags, are
+modified by writing to the appropriate file in that cgroups
+directory, as listed above.
+
+The named hierarchical structure of nested cgroups allows partitioning
+a large system into nested, dynamically changeable, "soft-partitions".
+
+The attachment of each task, automatically inherited at fork by any
+children of that task, to a cgroup allows organizing the work load
+on a system into related sets of tasks.  A task may be re-attached to
+any other cgroup, if allowed by the permissions on the necessary
+cgroup file system directories.
+
+When a task is moved from one cgroup to another, it gets a new
+css_set pointer - if there's an already existing css_set with the
+desired collection of cgroups then that group is reused, otherwise a new
+css_set is allocated. The appropriate existing css_set is located by
+looking into a hash table.
+
+To allow access from a cgroup to the css_sets (and hence tasks)
+that comprise it, a set of cg_cgroup_link objects form a lattice;
+each cg_cgroup_link is linked into a list of cg_cgroup_links for
+a single cgroup on its cgrp_link_list field, and a list of
+cg_cgroup_links for a single css_set on its cg_link_list.
+
+Thus the set of tasks in a cgroup can be listed by iterating over
+each css_set that references the cgroup, and sub-iterating over
+each css_set's task set.
+
+The use of a Linux virtual file system (vfs) to represent the
+cgroup hierarchy provides for a familiar permission and name space
+for cgroups, with a minimum of additional kernel code.
+
+1.4 What does notify_on_release do ?
+------------------------------------
+
+If the notify_on_release flag is enabled (1) in a cgroup, then
+whenever the last task in the cgroup leaves (exits or attaches to
+some other cgroup) and the last child cgroup of that cgroup
+is removed, then the kernel runs the command specified by the contents
+of the "release_agent" file in that hierarchy's root directory,
+supplying the pathname (relative to the mount point of the cgroup
+file system) of the abandoned cgroup.  This enables automatic
+removal of abandoned cgroups.  The default value of
+notify_on_release in the root cgroup at system boot is disabled
+(0).  The default value of other cgroups at creation is the current
+value of their parents' notify_on_release settings. The default value of
+a cgroup hierarchy's release_agent path is empty.
+
+1.5 What does clone_children do ?
+---------------------------------
+
+This flag only affects the cpuset controller. If the clone_children
+flag is enabled (1) in a cgroup, a new cpuset cgroup will copy its
+configuration from the parent during initialization.
+
+1.6 How do I use cgroups ?
+--------------------------
+
+To start a new job that is to be contained within a cgroup, using
+the "cpuset" cgroup subsystem, the steps are something like::
+
+ 1) mount -t tmpfs cgroup_root /sys/fs/cgroup
+ 2) mkdir /sys/fs/cgroup/cpuset
+ 3) mount -t cgroup -ocpuset cpuset /sys/fs/cgroup/cpuset
+ 4) Create the new cgroup by doing mkdir's and write's (or echo's) in
+    the /sys/fs/cgroup/cpuset virtual file system.
+ 5) Start a task that will be the "founding father" of the new job.
+ 6) Attach that task to the new cgroup by writing its PID to the
+    /sys/fs/cgroup/cpuset tasks file for that cgroup.
+ 7) fork, exec or clone the job tasks from this founding father task.
+
+For example, the following sequence of commands will setup a cgroup
+named "Charlie", containing just CPUs 2 and 3, and Memory Node 1,
+and then start a subshell 'sh' in that cgroup::
+
+  mount -t tmpfs cgroup_root /sys/fs/cgroup
+  mkdir /sys/fs/cgroup/cpuset
+  mount -t cgroup cpuset -ocpuset /sys/fs/cgroup/cpuset
+  cd /sys/fs/cgroup/cpuset
+  mkdir Charlie
+  cd Charlie
+  /bin/echo 2-3 > cpuset.cpus
+  /bin/echo 1 > cpuset.mems
+  /bin/echo $$ > tasks
+  sh
+  # The subshell 'sh' is now running in cgroup Charlie
+  # The next line should display '/Charlie'
+  cat /proc/self/cgroup
+
+2. Usage Examples and Syntax
+============================
+
+2.1 Basic Usage
+---------------
+
+Creating, modifying, using cgroups can be done through the cgroup
+virtual filesystem.
+
+To mount a cgroup hierarchy with all available subsystems, type::
+
+  # mount -t cgroup xxx /sys/fs/cgroup
+
+The "xxx" is not interpreted by the cgroup code, but will appear in
+/proc/mounts so may be any useful identifying string that you like.
+
+Note: Some subsystems do not work without some user input first.  For instance,
+if cpusets are enabled the user will have to populate the cpus and mems files
+for each new cgroup created before that group can be used.
+
+As explained in section `1.2 Why are cgroups needed?` you should create
+different hierarchies of cgroups for each single resource or group of
+resources you want to control. Therefore, you should mount a tmpfs on
+/sys/fs/cgroup and create directories for each cgroup resource or resource
+group::
+
+  # mount -t tmpfs cgroup_root /sys/fs/cgroup
+  # mkdir /sys/fs/cgroup/rg1
+
+To mount a cgroup hierarchy with just the cpuset and memory
+subsystems, type::
+
+  # mount -t cgroup -o cpuset,memory hier1 /sys/fs/cgroup/rg1
+
+While remounting cgroups is currently supported, it is not recommend
+to use it. Remounting allows changing bound subsystems and
+release_agent. Rebinding is hardly useful as it only works when the
+hierarchy is empty and release_agent itself should be replaced with
+conventional fsnotify. The support for remounting will be removed in
+the future.
+
+To Specify a hierarchy's release_agent::
+
+  # mount -t cgroup -o cpuset,release_agent="/sbin/cpuset_release_agent" \
+    xxx /sys/fs/cgroup/rg1
+
+Note that specifying 'release_agent' more than once will return failure.
+
+Note that changing the set of subsystems is currently only supported
+when the hierarchy consists of a single (root) cgroup. Supporting
+the ability to arbitrarily bind/unbind subsystems from an existing
+cgroup hierarchy is intended to be implemented in the future.
+
+Then under /sys/fs/cgroup/rg1 you can find a tree that corresponds to the
+tree of the cgroups in the system. For instance, /sys/fs/cgroup/rg1
+is the cgroup that holds the whole system.
+
+If you want to change the value of release_agent::
+
+  # echo "/sbin/new_release_agent" > /sys/fs/cgroup/rg1/release_agent
+
+It can also be changed via remount.
+
+If you want to create a new cgroup under /sys/fs/cgroup/rg1::
+
+  # cd /sys/fs/cgroup/rg1
+  # mkdir my_cgroup
+
+Now you want to do something with this cgroup:
+
+  # cd my_cgroup
+
+In this directory you can find several files::
+
+  # ls
+  cgroup.procs notify_on_release tasks
+  (plus whatever files added by the attached subsystems)
+
+Now attach your shell to this cgroup::
+
+  # /bin/echo $$ > tasks
+
+You can also create cgroups inside your cgroup by using mkdir in this
+directory::
+
+  # mkdir my_sub_cs
+
+To remove a cgroup, just use rmdir::
+
+  # rmdir my_sub_cs
+
+This will fail if the cgroup is in use (has cgroups inside, or
+has processes attached, or is held alive by other subsystem-specific
+reference).
+
+2.2 Attaching processes
+-----------------------
+
+::
+
+  # /bin/echo PID > tasks
+
+Note that it is PID, not PIDs. You can only attach ONE task at a time.
+If you have several tasks to attach, you have to do it one after another::
+
+  # /bin/echo PID1 > tasks
+  # /bin/echo PID2 > tasks
+         ...
+  # /bin/echo PIDn > tasks
+
+You can attach the current shell task by echoing 0::
+
+  # echo 0 > tasks
+
+You can use the cgroup.procs file instead of the tasks file to move all
+threads in a threadgroup at once. Echoing the PID of any task in a
+threadgroup to cgroup.procs causes all tasks in that threadgroup to be
+attached to the cgroup. Writing 0 to cgroup.procs moves all tasks
+in the writing task's threadgroup.
+
+Note: Since every task is always a member of exactly one cgroup in each
+mounted hierarchy, to remove a task from its current cgroup you must
+move it into a new cgroup (possibly the root cgroup) by writing to the
+new cgroup's tasks file.
+
+Note: Due to some restrictions enforced by some cgroup subsystems, moving
+a process to another cgroup can fail.
+
+2.3 Mounting hierarchies by name
+--------------------------------
+
+Passing the name=<x> option when mounting a cgroups hierarchy
+associates the given name with the hierarchy.  This can be used when
+mounting a pre-existing hierarchy, in order to refer to it by name
+rather than by its set of active subsystems.  Each hierarchy is either
+nameless, or has a unique name.
+
+The name should match [\w.-]+
+
+When passing a name=<x> option for a new hierarchy, you need to
+specify subsystems manually; the legacy behaviour of mounting all
+subsystems when none are explicitly specified is not supported when
+you give a subsystem a name.
+
+The name of the subsystem appears as part of the hierarchy description
+in /proc/mounts and /proc/<pid>/cgroups.
+
+
+3. Kernel API
+=============
+
+3.1 Overview
+------------
+
+Each kernel subsystem that wants to hook into the generic cgroup
+system needs to create a cgroup_subsys object. This contains
+various methods, which are callbacks from the cgroup system, along
+with a subsystem ID which will be assigned by the cgroup system.
+
+Other fields in the cgroup_subsys object include:
+
+- subsys_id: a unique array index for the subsystem, indicating which
+  entry in cgroup->subsys[] this subsystem should be managing.
+
+- name: should be initialized to a unique subsystem name. Should be
+  no longer than MAX_CGROUP_TYPE_NAMELEN.
+
+- early_init: indicate if the subsystem needs early initialization
+  at system boot.
+
+Each cgroup object created by the system has an array of pointers,
+indexed by subsystem ID; this pointer is entirely managed by the
+subsystem; the generic cgroup code will never touch this pointer.
+
+3.2 Synchronization
+-------------------
+
+There is a global mutex, cgroup_mutex, used by the cgroup
+system. This should be taken by anything that wants to modify a
+cgroup. It may also be taken to prevent cgroups from being
+modified, but more specific locks may be more appropriate in that
+situation.
+
+See kernel/cgroup.c for more details.
+
+Subsystems can take/release the cgroup_mutex via the functions
+cgroup_lock()/cgroup_unlock().
+
+Accessing a task's cgroup pointer may be done in the following ways:
+- while holding cgroup_mutex
+- while holding the task's alloc_lock (via task_lock())
+- inside an rcu_read_lock() section via rcu_dereference()
+
+3.3 Subsystem API
+-----------------
+
+Each subsystem should:
+
+- add an entry in linux/cgroup_subsys.h
+- define a cgroup_subsys object called <name>_cgrp_subsys
+
+Each subsystem may export the following methods. The only mandatory
+methods are css_alloc/free. Any others that are null are presumed to
+be successful no-ops.
+
+``struct cgroup_subsys_state *css_alloc(struct cgroup *cgrp)``
+(cgroup_mutex held by caller)
+
+Called to allocate a subsystem state object for a cgroup. The
+subsystem should allocate its subsystem state object for the passed
+cgroup, returning a pointer to the new object on success or a
+ERR_PTR() value. On success, the subsystem pointer should point to
+a structure of type cgroup_subsys_state (typically embedded in a
+larger subsystem-specific object), which will be initialized by the
+cgroup system. Note that this will be called at initialization to
+create the root subsystem state for this subsystem; this case can be
+identified by the passed cgroup object having a NULL parent (since
+it's the root of the hierarchy) and may be an appropriate place for
+initialization code.
+
+``int css_online(struct cgroup *cgrp)``
+(cgroup_mutex held by caller)
+
+Called after @cgrp successfully completed all allocations and made
+visible to cgroup_for_each_child/descendant_*() iterators. The
+subsystem may choose to fail creation by returning -errno. This
+callback can be used to implement reliable state sharing and
+propagation along the hierarchy. See the comment on
+cgroup_for_each_descendant_pre() for details.
+
+``void css_offline(struct cgroup *cgrp);``
+(cgroup_mutex held by caller)
+
+This is the counterpart of css_online() and called iff css_online()
+has succeeded on @cgrp. This signifies the beginning of the end of
+@cgrp. @cgrp is being removed and the subsystem should start dropping
+all references it's holding on @cgrp. When all references are dropped,
+cgroup removal will proceed to the next step - css_free(). After this
+callback, @cgrp should be considered dead to the subsystem.
+
+``void css_free(struct cgroup *cgrp)``
+(cgroup_mutex held by caller)
+
+The cgroup system is about to free @cgrp; the subsystem should free
+its subsystem state object. By the time this method is called, @cgrp
+is completely unused; @cgrp->parent is still valid. (Note - can also
+be called for a newly-created cgroup if an error occurs after this
+subsystem's create() method has been called for the new cgroup).
+
+``int can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)``
+(cgroup_mutex held by caller)
+
+Called prior to moving one or more tasks into a cgroup; if the
+subsystem returns an error, this will abort the attach operation.
+@tset contains the tasks to be attached and is guaranteed to have at
+least one task in it.
+
+If there are multiple tasks in the taskset, then:
+  - it's guaranteed that all are from the same thread group
+  - @tset contains all tasks from the thread group whether or not
+    they're switching cgroups
+  - the first task is the leader
+
+Each @tset entry also contains the task's old cgroup and tasks which
+aren't switching cgroup can be skipped easily using the
+cgroup_taskset_for_each() iterator. Note that this isn't called on a
+fork. If this method returns 0 (success) then this should remain valid
+while the caller holds cgroup_mutex and it is ensured that either
+attach() or cancel_attach() will be called in future.
+
+``void css_reset(struct cgroup_subsys_state *css)``
+(cgroup_mutex held by caller)
+
+An optional operation which should restore @css's configuration to the
+initial state.  This is currently only used on the unified hierarchy
+when a subsystem is disabled on a cgroup through
+"cgroup.subtree_control" but should remain enabled because other
+subsystems depend on it.  cgroup core makes such a css invisible by
+removing the associated interface files and invokes this callback so
+that the hidden subsystem can return to the initial neutral state.
+This prevents unexpected resource control from a hidden css and
+ensures that the configuration is in the initial state when it is made
+visible again later.
+
+``void cancel_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)``
+(cgroup_mutex held by caller)
+
+Called when a task attach operation has failed after can_attach() has succeeded.
+A subsystem whose can_attach() has some side-effects should provide this
+function, so that the subsystem can implement a rollback. If not, not necessary.
+This will be called only about subsystems whose can_attach() operation have
+succeeded. The parameters are identical to can_attach().
+
+``void attach(struct cgroup *cgrp, struct cgroup_taskset *tset)``
+(cgroup_mutex held by caller)
+
+Called after the task has been attached to the cgroup, to allow any
+post-attachment activity that requires memory allocations or blocking.
+The parameters are identical to can_attach().
+
+``void fork(struct task_struct *task)``
+
+Called when a task is forked into a cgroup.
+
+``void exit(struct task_struct *task)``
+
+Called during task exit.
+
+``void free(struct task_struct *task)``
+
+Called when the task_struct is freed.
+
+``void bind(struct cgroup *root)``
+(cgroup_mutex held by caller)
+
+Called when a cgroup subsystem is rebound to a different hierarchy
+and root cgroup. Currently this will only involve movement between
+the default hierarchy (which never has sub-cgroups) and a hierarchy
+that is being created/destroyed (and hence has no sub-cgroups).
+
+4. Extended attribute usage
+===========================
+
+cgroup filesystem supports certain types of extended attributes in its
+directories and files.  The current supported types are:
+
+       - Trusted (XATTR_TRUSTED)
+       - Security (XATTR_SECURITY)
+
+Both require CAP_SYS_ADMIN capability to set.
+
+Like in tmpfs, the extended attributes in cgroup filesystem are stored
+using kernel memory and it's advised to keep the usage at minimum.  This
+is the reason why user defined extended attributes are not supported, since
+any user can do it and there's no limit in the value size.
+
+The current known users for this feature are SELinux to limit cgroup usage
+in containers and systemd for assorted meta data like main PID in a cgroup
+(systemd creates a cgroup per service).
+
+5. Questions
+============
+
+::
+
+  Q: what's up with this '/bin/echo' ?
+  A: bash's builtin 'echo' command does not check calls to write() against
+     errors. If you use it in the cgroup file system, you won't be
+     able to tell whether a command succeeded or failed.
+
+  Q: When I attach processes, only the first of the line gets really attached !
+  A: We can only return one error code per call to write(). So you should also
+     put only ONE PID.
diff --git a/Documentation/admin-guide/cgroup-v1/cpusets.rst b/Documentation/admin-guide/cgroup-v1/cpusets.rst
new file mode 100644 (file)
index 0000000..86a6ae9
--- /dev/null
@@ -0,0 +1,866 @@
+=======
+CPUSETS
+=======
+
+Copyright (C) 2004 BULL SA.
+
+Written by Simon.Derr@bull.net
+
+- Portions Copyright (c) 2004-2006 Silicon Graphics, Inc.
+- Modified by Paul Jackson <pj@sgi.com>
+- Modified by Christoph Lameter <cl@linux.com>
+- Modified by Paul Menage <menage@google.com>
+- Modified by Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
+
+.. CONTENTS:
+
+   1. Cpusets
+     1.1 What are cpusets ?
+     1.2 Why are cpusets needed ?
+     1.3 How are cpusets implemented ?
+     1.4 What are exclusive cpusets ?
+     1.5 What is memory_pressure ?
+     1.6 What is memory spread ?
+     1.7 What is sched_load_balance ?
+     1.8 What is sched_relax_domain_level ?
+     1.9 How do I use cpusets ?
+   2. Usage Examples and Syntax
+     2.1 Basic Usage
+     2.2 Adding/removing cpus
+     2.3 Setting flags
+     2.4 Attaching processes
+   3. Questions
+   4. Contact
+
+1. Cpusets
+==========
+
+1.1 What are cpusets ?
+----------------------
+
+Cpusets provide a mechanism for assigning a set of CPUs and Memory
+Nodes to a set of tasks.   In this document "Memory Node" refers to
+an on-line node that contains memory.
+
+Cpusets constrain the CPU and Memory placement of tasks to only
+the resources within a task's current cpuset.  They form a nested
+hierarchy visible in a virtual file system.  These are the essential
+hooks, beyond what is already present, required to manage dynamic
+job placement on large systems.
+
+Cpusets use the generic cgroup subsystem described in
+Documentation/admin-guide/cgroup-v1/cgroups.rst.
+
+Requests by a task, using the sched_setaffinity(2) system call to
+include CPUs in its CPU affinity mask, and using the mbind(2) and
+set_mempolicy(2) system calls to include Memory Nodes in its memory
+policy, are both filtered through that task's cpuset, filtering out any
+CPUs or Memory Nodes not in that cpuset.  The scheduler will not
+schedule a task on a CPU that is not allowed in its cpus_allowed
+vector, and the kernel page allocator will not allocate a page on a
+node that is not allowed in the requesting task's mems_allowed vector.
+
+User level code may create and destroy cpusets by name in the cgroup
+virtual file system, manage the attributes and permissions of these
+cpusets and which CPUs and Memory Nodes are assigned to each cpuset,
+specify and query to which cpuset a task is assigned, and list the
+task pids assigned to a cpuset.
+
+
+1.2 Why are cpusets needed ?
+----------------------------
+
+The management of large computer systems, with many processors (CPUs),
+complex memory cache hierarchies and multiple Memory Nodes having
+non-uniform access times (NUMA) presents additional challenges for
+the efficient scheduling and memory placement of processes.
+
+Frequently more modest sized systems can be operated with adequate
+efficiency just by letting the operating system automatically share
+the available CPU and Memory resources amongst the requesting tasks.
+
+But larger systems, which benefit more from careful processor and
+memory placement to reduce memory access times and contention,
+and which typically represent a larger investment for the customer,
+can benefit from explicitly placing jobs on properly sized subsets of
+the system.
+
+This can be especially valuable on:
+
+    * Web Servers running multiple instances of the same web application,
+    * Servers running different applications (for instance, a web server
+      and a database), or
+    * NUMA systems running large HPC applications with demanding
+      performance characteristics.
+
+These subsets, or "soft partitions" must be able to be dynamically
+adjusted, as the job mix changes, without impacting other concurrently
+executing jobs. The location of the running jobs pages may also be moved
+when the memory locations are changed.
+
+The kernel cpuset patch provides the minimum essential kernel
+mechanisms required to efficiently implement such subsets.  It
+leverages existing CPU and Memory Placement facilities in the Linux
+kernel to avoid any additional impact on the critical scheduler or
+memory allocator code.
+
+
+1.3 How are cpusets implemented ?
+---------------------------------
+
+Cpusets provide a Linux kernel mechanism to constrain which CPUs and
+Memory Nodes are used by a process or set of processes.
+
+The Linux kernel already has a pair of mechanisms to specify on which
+CPUs a task may be scheduled (sched_setaffinity) and on which Memory
+Nodes it may obtain memory (mbind, set_mempolicy).
+
+Cpusets extends these two mechanisms as follows:
+
+ - Cpusets are sets of allowed CPUs and Memory Nodes, known to the
+   kernel.
+ - Each task in the system is attached to a cpuset, via a pointer
+   in the task structure to a reference counted cgroup structure.
+ - Calls to sched_setaffinity are filtered to just those CPUs
+   allowed in that task's cpuset.
+ - Calls to mbind and set_mempolicy are filtered to just
+   those Memory Nodes allowed in that task's cpuset.
+ - The root cpuset contains all the systems CPUs and Memory
+   Nodes.
+ - For any cpuset, one can define child cpusets containing a subset
+   of the parents CPU and Memory Node resources.
+ - The hierarchy of cpusets can be mounted at /dev/cpuset, for
+   browsing and manipulation from user space.
+ - A cpuset may be marked exclusive, which ensures that no other
+   cpuset (except direct ancestors and descendants) may contain
+   any overlapping CPUs or Memory Nodes.
+ - You can list all the tasks (by pid) attached to any cpuset.
+
+The implementation of cpusets requires a few, simple hooks
+into the rest of the kernel, none in performance critical paths:
+
+ - in init/main.c, to initialize the root cpuset at system boot.
+ - in fork and exit, to attach and detach a task from its cpuset.
+ - in sched_setaffinity, to mask the requested CPUs by what's
+   allowed in that task's cpuset.
+ - in sched.c migrate_live_tasks(), to keep migrating tasks within
+   the CPUs allowed by their cpuset, if possible.
+ - in the mbind and set_mempolicy system calls, to mask the requested
+   Memory Nodes by what's allowed in that task's cpuset.
+ - in page_alloc.c, to restrict memory to allowed nodes.
+ - in vmscan.c, to restrict page recovery to the current cpuset.
+
+You should mount the "cgroup" filesystem type in order to enable
+browsing and modifying the cpusets presently known to the kernel.  No
+new system calls are added for cpusets - all support for querying and
+modifying cpusets is via this cpuset file system.
+
+The /proc/<pid>/status file for each task has four added lines,
+displaying the task's cpus_allowed (on which CPUs it may be scheduled)
+and mems_allowed (on which Memory Nodes it may obtain memory),
+in the two formats seen in the following example::
+
+  Cpus_allowed:   ffffffff,ffffffff,ffffffff,ffffffff
+  Cpus_allowed_list:      0-127
+  Mems_allowed:   ffffffff,ffffffff
+  Mems_allowed_list:      0-63
+
+Each cpuset is represented by a directory in the cgroup file system
+containing (on top of the standard cgroup files) the following
+files describing that cpuset:
+
+ - cpuset.cpus: list of CPUs in that cpuset
+ - cpuset.mems: list of Memory Nodes in that cpuset
+ - cpuset.memory_migrate flag: if set, move pages to cpusets nodes
+ - cpuset.cpu_exclusive flag: is cpu placement exclusive?
+ - cpuset.mem_exclusive flag: is memory placement exclusive?
+ - cpuset.mem_hardwall flag:  is memory allocation hardwalled
+ - cpuset.memory_pressure: measure of how much paging pressure in cpuset
+ - cpuset.memory_spread_page flag: if set, spread page cache evenly on allowed nodes
+ - cpuset.memory_spread_slab flag: if set, spread slab cache evenly on allowed nodes
+ - cpuset.sched_load_balance flag: if set, load balance within CPUs on that cpuset
+ - cpuset.sched_relax_domain_level: the searching range when migrating tasks
+
+In addition, only the root cpuset has the following file:
+
+ - cpuset.memory_pressure_enabled flag: compute memory_pressure?
+
+New cpusets are created using the mkdir system call or shell
+command.  The properties of a cpuset, such as its flags, allowed
+CPUs and Memory Nodes, and attached tasks, are modified by writing
+to the appropriate file in that cpusets directory, as listed above.
+
+The named hierarchical structure of nested cpusets allows partitioning
+a large system into nested, dynamically changeable, "soft-partitions".
+
+The attachment of each task, automatically inherited at fork by any
+children of that task, to a cpuset allows organizing the work load
+on a system into related sets of tasks such that each set is constrained
+to using the CPUs and Memory Nodes of a particular cpuset.  A task
+may be re-attached to any other cpuset, if allowed by the permissions
+on the necessary cpuset file system directories.
+
+Such management of a system "in the large" integrates smoothly with
+the detailed placement done on individual tasks and memory regions
+using the sched_setaffinity, mbind and set_mempolicy system calls.
+
+The following rules apply to each cpuset:
+
+ - Its CPUs and Memory Nodes must be a subset of its parents.
+ - It can't be marked exclusive unless its parent is.
+ - If its cpu or memory is exclusive, they may not overlap any sibling.
+
+These rules, and the natural hierarchy of cpusets, enable efficient
+enforcement of the exclusive guarantee, without having to scan all
+cpusets every time any of them change to ensure nothing overlaps a
+exclusive cpuset.  Also, the use of a Linux virtual file system (vfs)
+to represent the cpuset hierarchy provides for a familiar permission
+and name space for cpusets, with a minimum of additional kernel code.
+
+The cpus and mems files in the root (top_cpuset) cpuset are
+read-only.  The cpus file automatically tracks the value of
+cpu_online_mask using a CPU hotplug notifier, and the mems file
+automatically tracks the value of node_states[N_MEMORY]--i.e.,
+nodes with memory--using the cpuset_track_online_nodes() hook.
+
+
+1.4 What are exclusive cpusets ?
+--------------------------------
+
+If a cpuset is cpu or mem exclusive, no other cpuset, other than
+a direct ancestor or descendant, may share any of the same CPUs or
+Memory Nodes.
+
+A cpuset that is cpuset.mem_exclusive *or* cpuset.mem_hardwall is "hardwalled",
+i.e. it restricts kernel allocations for page, buffer and other data
+commonly shared by the kernel across multiple users.  All cpusets,
+whether hardwalled or not, restrict allocations of memory for user
+space.  This enables configuring a system so that several independent
+jobs can share common kernel data, such as file system pages, while
+isolating each job's user allocation in its own cpuset.  To do this,
+construct a large mem_exclusive cpuset to hold all the jobs, and
+construct child, non-mem_exclusive cpusets for each individual job.
+Only a small amount of typical kernel memory, such as requests from
+interrupt handlers, is allowed to be taken outside even a
+mem_exclusive cpuset.
+
+
+1.5 What is memory_pressure ?
+-----------------------------
+The memory_pressure of a cpuset provides a simple per-cpuset metric
+of the rate that the tasks in a cpuset are attempting to free up in
+use memory on the nodes of the cpuset to satisfy additional memory
+requests.
+
+This enables batch managers monitoring jobs running in dedicated
+cpusets to efficiently detect what level of memory pressure that job
+is causing.
+
+This is useful both on tightly managed systems running a wide mix of
+submitted jobs, which may choose to terminate or re-prioritize jobs that
+are trying to use more memory than allowed on the nodes assigned to them,
+and with tightly coupled, long running, massively parallel scientific
+computing jobs that will dramatically fail to meet required performance
+goals if they start to use more memory than allowed to them.
+
+This mechanism provides a very economical way for the batch manager
+to monitor a cpuset for signs of memory pressure.  It's up to the
+batch manager or other user code to decide what to do about it and
+take action.
+
+==>
+    Unless this feature is enabled by writing "1" to the special file
+    /dev/cpuset/memory_pressure_enabled, the hook in the rebalance
+    code of __alloc_pages() for this metric reduces to simply noticing
+    that the cpuset_memory_pressure_enabled flag is zero.  So only
+    systems that enable this feature will compute the metric.
+
+Why a per-cpuset, running average:
+
+    Because this meter is per-cpuset, rather than per-task or mm,
+    the system load imposed by a batch scheduler monitoring this
+    metric is sharply reduced on large systems, because a scan of
+    the tasklist can be avoided on each set of queries.
+
+    Because this meter is a running average, instead of an accumulating
+    counter, a batch scheduler can detect memory pressure with a
+    single read, instead of having to read and accumulate results
+    for a period of time.
+
+    Because this meter is per-cpuset rather than per-task or mm,
+    the batch scheduler can obtain the key information, memory
+    pressure in a cpuset, with a single read, rather than having to
+    query and accumulate results over all the (dynamically changing)
+    set of tasks in the cpuset.
+
+A per-cpuset simple digital filter (requires a spinlock and 3 words
+of data per-cpuset) is kept, and updated by any task attached to that
+cpuset, if it enters the synchronous (direct) page reclaim code.
+
+A per-cpuset file provides an integer number representing the recent
+(half-life of 10 seconds) rate of direct page reclaims caused by
+the tasks in the cpuset, in units of reclaims attempted per second,
+times 1000.
+
+
+1.6 What is memory spread ?
+---------------------------
+There are two boolean flag files per cpuset that control where the
+kernel allocates pages for the file system buffers and related in
+kernel data structures.  They are called 'cpuset.memory_spread_page' and
+'cpuset.memory_spread_slab'.
+
+If the per-cpuset boolean flag file 'cpuset.memory_spread_page' is set, then
+the kernel will spread the file system buffers (page cache) evenly
+over all the nodes that the faulting task is allowed to use, instead
+of preferring to put those pages on the node where the task is running.
+
+If the per-cpuset boolean flag file 'cpuset.memory_spread_slab' is set,
+then the kernel will spread some file system related slab caches,
+such as for inodes and dentries evenly over all the nodes that the
+faulting task is allowed to use, instead of preferring to put those
+pages on the node where the task is running.
+
+The setting of these flags does not affect anonymous data segment or
+stack segment pages of a task.
+
+By default, both kinds of memory spreading are off, and memory
+pages are allocated on the node local to where the task is running,
+except perhaps as modified by the task's NUMA mempolicy or cpuset
+configuration, so long as sufficient free memory pages are available.
+
+When new cpusets are created, they inherit the memory spread settings
+of their parent.
+
+Setting memory spreading causes allocations for the affected page
+or slab caches to ignore the task's NUMA mempolicy and be spread
+instead.    Tasks using mbind() or set_mempolicy() calls to set NUMA
+mempolicies will not notice any change in these calls as a result of
+their containing task's memory spread settings.  If memory spreading
+is turned off, then the currently specified NUMA mempolicy once again
+applies to memory page allocations.
+
+Both 'cpuset.memory_spread_page' and 'cpuset.memory_spread_slab' are boolean flag
+files.  By default they contain "0", meaning that the feature is off
+for that cpuset.  If a "1" is written to that file, then that turns
+the named feature on.
+
+The implementation is simple.
+
+Setting the flag 'cpuset.memory_spread_page' turns on a per-process flag
+PFA_SPREAD_PAGE for each task that is in that cpuset or subsequently
+joins that cpuset.  The page allocation calls for the page cache
+is modified to perform an inline check for this PFA_SPREAD_PAGE task
+flag, and if set, a call to a new routine cpuset_mem_spread_node()
+returns the node to prefer for the allocation.
+
+Similarly, setting 'cpuset.memory_spread_slab' turns on the flag
+PFA_SPREAD_SLAB, and appropriately marked slab caches will allocate
+pages from the node returned by cpuset_mem_spread_node().
+
+The cpuset_mem_spread_node() routine is also simple.  It uses the
+value of a per-task rotor cpuset_mem_spread_rotor to select the next
+node in the current task's mems_allowed to prefer for the allocation.
+
+This memory placement policy is also known (in other contexts) as
+round-robin or interleave.
+
+This policy can provide substantial improvements for jobs that need
+to place thread local data on the corresponding node, but that need
+to access large file system data sets that need to be spread across
+the several nodes in the jobs cpuset in order to fit.  Without this
+policy, especially for jobs that might have one thread reading in the
+data set, the memory allocation across the nodes in the jobs cpuset
+can become very uneven.
+
+1.7 What is sched_load_balance ?
+--------------------------------
+
+The kernel scheduler (kernel/sched/core.c) automatically load balances
+tasks.  If one CPU is underutilized, kernel code running on that
+CPU will look for tasks on other more overloaded CPUs and move those
+tasks to itself, within the constraints of such placement mechanisms
+as cpusets and sched_setaffinity.
+
+The algorithmic cost of load balancing and its impact on key shared
+kernel data structures such as the task list increases more than
+linearly with the number of CPUs being balanced.  So the scheduler
+has support to partition the systems CPUs into a number of sched
+domains such that it only load balances within each sched domain.
+Each sched domain covers some subset of the CPUs in the system;
+no two sched domains overlap; some CPUs might not be in any sched
+domain and hence won't be load balanced.
+
+Put simply, it costs less to balance between two smaller sched domains
+than one big one, but doing so means that overloads in one of the
+two domains won't be load balanced to the other one.
+
+By default, there is one sched domain covering all CPUs, including those
+marked isolated using the kernel boot time "isolcpus=" argument. However,
+the isolated CPUs will not participate in load balancing, and will not
+have tasks running on them unless explicitly assigned.
+
+This default load balancing across all CPUs is not well suited for
+the following two situations:
+
+ 1) On large systems, load balancing across many CPUs is expensive.
+    If the system is managed using cpusets to place independent jobs
+    on separate sets of CPUs, full load balancing is unnecessary.
+ 2) Systems supporting realtime on some CPUs need to minimize
+    system overhead on those CPUs, including avoiding task load
+    balancing if that is not needed.
+
+When the per-cpuset flag "cpuset.sched_load_balance" is enabled (the default
+setting), it requests that all the CPUs in that cpusets allowed 'cpuset.cpus'
+be contained in a single sched domain, ensuring that load balancing
+can move a task (not otherwised pinned, as by sched_setaffinity)
+from any CPU in that cpuset to any other.
+
+When the per-cpuset flag "cpuset.sched_load_balance" is disabled, then the
+scheduler will avoid load balancing across the CPUs in that cpuset,
+--except-- in so far as is necessary because some overlapping cpuset
+has "sched_load_balance" enabled.
+
+So, for example, if the top cpuset has the flag "cpuset.sched_load_balance"
+enabled, then the scheduler will have one sched domain covering all
+CPUs, and the setting of the "cpuset.sched_load_balance" flag in any other
+cpusets won't matter, as we're already fully load balancing.
+
+Therefore in the above two situations, the top cpuset flag
+"cpuset.sched_load_balance" should be disabled, and only some of the smaller,
+child cpusets have this flag enabled.
+
+When doing this, you don't usually want to leave any unpinned tasks in
+the top cpuset that might use non-trivial amounts of CPU, as such tasks
+may be artificially constrained to some subset of CPUs, depending on
+the particulars of this flag setting in descendant cpusets.  Even if
+such a task could use spare CPU cycles in some other CPUs, the kernel
+scheduler might not consider the possibility of load balancing that
+task to that underused CPU.
+
+Of course, tasks pinned to a particular CPU can be left in a cpuset
+that disables "cpuset.sched_load_balance" as those tasks aren't going anywhere
+else anyway.
+
+There is an impedance mismatch here, between cpusets and sched domains.
+Cpusets are hierarchical and nest.  Sched domains are flat; they don't
+overlap and each CPU is in at most one sched domain.
+
+It is necessary for sched domains to be flat because load balancing
+across partially overlapping sets of CPUs would risk unstable dynamics
+that would be beyond our understanding.  So if each of two partially
+overlapping cpusets enables the flag 'cpuset.sched_load_balance', then we
+form a single sched domain that is a superset of both.  We won't move
+a task to a CPU outside its cpuset, but the scheduler load balancing
+code might waste some compute cycles considering that possibility.
+
+This mismatch is why there is not a simple one-to-one relation
+between which cpusets have the flag "cpuset.sched_load_balance" enabled,
+and the sched domain configuration.  If a cpuset enables the flag, it
+will get balancing across all its CPUs, but if it disables the flag,
+it will only be assured of no load balancing if no other overlapping
+cpuset enables the flag.
+
+If two cpusets have partially overlapping 'cpuset.cpus' allowed, and only
+one of them has this flag enabled, then the other may find its
+tasks only partially load balanced, just on the overlapping CPUs.
+This is just the general case of the top_cpuset example given a few
+paragraphs above.  In the general case, as in the top cpuset case,
+don't leave tasks that might use non-trivial amounts of CPU in
+such partially load balanced cpusets, as they may be artificially
+constrained to some subset of the CPUs allowed to them, for lack of
+load balancing to the other CPUs.
+
+CPUs in "cpuset.isolcpus" were excluded from load balancing by the
+isolcpus= kernel boot option, and will never be load balanced regardless
+of the value of "cpuset.sched_load_balance" in any cpuset.
+
+1.7.1 sched_load_balance implementation details.
+------------------------------------------------
+
+The per-cpuset flag 'cpuset.sched_load_balance' defaults to enabled (contrary
+to most cpuset flags.)  When enabled for a cpuset, the kernel will
+ensure that it can load balance across all the CPUs in that cpuset
+(makes sure that all the CPUs in the cpus_allowed of that cpuset are
+in the same sched domain.)
+
+If two overlapping cpusets both have 'cpuset.sched_load_balance' enabled,
+then they will be (must be) both in the same sched domain.
+
+If, as is the default, the top cpuset has 'cpuset.sched_load_balance' enabled,
+then by the above that means there is a single sched domain covering
+the whole system, regardless of any other cpuset settings.
+
+The kernel commits to user space that it will avoid load balancing
+where it can.  It will pick as fine a granularity partition of sched
+domains as it can while still providing load balancing for any set
+of CPUs allowed to a cpuset having 'cpuset.sched_load_balance' enabled.
+
+The internal kernel cpuset to scheduler interface passes from the
+cpuset code to the scheduler code a partition of the load balanced
+CPUs in the system. This partition is a set of subsets (represented
+as an array of struct cpumask) of CPUs, pairwise disjoint, that cover
+all the CPUs that must be load balanced.
+
+The cpuset code builds a new such partition and passes it to the
+scheduler sched domain setup code, to have the sched domains rebuilt
+as necessary, whenever:
+
+ - the 'cpuset.sched_load_balance' flag of a cpuset with non-empty CPUs changes,
+ - or CPUs come or go from a cpuset with this flag enabled,
+ - or 'cpuset.sched_relax_domain_level' value of a cpuset with non-empty CPUs
+   and with this flag enabled changes,
+ - or a cpuset with non-empty CPUs and with this flag enabled is removed,
+ - or a cpu is offlined/onlined.
+
+This partition exactly defines what sched domains the scheduler should
+setup - one sched domain for each element (struct cpumask) in the
+partition.
+
+The scheduler remembers the currently active sched domain partitions.
+When the scheduler routine partition_sched_domains() is invoked from
+the cpuset code to update these sched domains, it compares the new
+partition requested with the current, and updates its sched domains,
+removing the old and adding the new, for each change.
+
+
+1.8 What is sched_relax_domain_level ?
+--------------------------------------
+
+In sched domain, the scheduler migrates tasks in 2 ways; periodic load
+balance on tick, and at time of some schedule events.
+
+When a task is woken up, scheduler try to move the task on idle CPU.
+For example, if a task A running on CPU X activates another task B
+on the same CPU X, and if CPU Y is X's sibling and performing idle,
+then scheduler migrate task B to CPU Y so that task B can start on
+CPU Y without waiting task A on CPU X.
+
+And if a CPU run out of tasks in its runqueue, the CPU try to pull
+extra tasks from other busy CPUs to help them before it is going to
+be idle.
+
+Of course it takes some searching cost to find movable tasks and/or
+idle CPUs, the scheduler might not search all CPUs in the domain
+every time.  In fact, in some architectures, the searching ranges on
+events are limited in the same socket or node where the CPU locates,
+while the load balance on tick searches all.
+
+For example, assume CPU Z is relatively far from CPU X.  Even if CPU Z
+is idle while CPU X and the siblings are busy, scheduler can't migrate
+woken task B from X to Z since it is out of its searching range.
+As the result, task B on CPU X need to wait task A or wait load balance
+on the next tick.  For some applications in special situation, waiting
+1 tick may be too long.
+
+The 'cpuset.sched_relax_domain_level' file allows you to request changing
+this searching range as you like.  This file takes int value which
+indicates size of searching range in levels ideally as follows,
+otherwise initial value -1 that indicates the cpuset has no request.
+
+====== ===========================================================
+  -1   no request. use system default or follow request of others.
+   0   no search.
+   1   search siblings (hyperthreads in a core).
+   2   search cores in a package.
+   3   search cpus in a node [= system wide on non-NUMA system]
+   4   search nodes in a chunk of node [on NUMA system]
+   5   search system wide [on NUMA system]
+====== ===========================================================
+
+The system default is architecture dependent.  The system default
+can be changed using the relax_domain_level= boot parameter.
+
+This file is per-cpuset and affect the sched domain where the cpuset
+belongs to.  Therefore if the flag 'cpuset.sched_load_balance' of a cpuset
+is disabled, then 'cpuset.sched_relax_domain_level' have no effect since
+there is no sched domain belonging the cpuset.
+
+If multiple cpusets are overlapping and hence they form a single sched
+domain, the largest value among those is used.  Be careful, if one
+requests 0 and others are -1 then 0 is used.
+
+Note that modifying this file will have both good and bad effects,
+and whether it is acceptable or not depends on your situation.
+Don't modify this file if you are not sure.
+
+If your situation is:
+
+ - The migration costs between each cpu can be assumed considerably
+   small(for you) due to your special application's behavior or
+   special hardware support for CPU cache etc.
+ - The searching cost doesn't have impact(for you) or you can make
+   the searching cost enough small by managing cpuset to compact etc.
+ - The latency is required even it sacrifices cache hit rate etc.
+   then increasing 'sched_relax_domain_level' would benefit you.
+
+
+1.9 How do I use cpusets ?
+--------------------------
+
+In order to minimize the impact of cpusets on critical kernel
+code, such as the scheduler, and due to the fact that the kernel
+does not support one task updating the memory placement of another
+task directly, the impact on a task of changing its cpuset CPU
+or Memory Node placement, or of changing to which cpuset a task
+is attached, is subtle.
+
+If a cpuset has its Memory Nodes modified, then for each task attached
+to that cpuset, the next time that the kernel attempts to allocate
+a page of memory for that task, the kernel will notice the change
+in the task's cpuset, and update its per-task memory placement to
+remain within the new cpusets memory placement.  If the task was using
+mempolicy MPOL_BIND, and the nodes to which it was bound overlap with
+its new cpuset, then the task will continue to use whatever subset
+of MPOL_BIND nodes are still allowed in the new cpuset.  If the task
+was using MPOL_BIND and now none of its MPOL_BIND nodes are allowed
+in the new cpuset, then the task will be essentially treated as if it
+was MPOL_BIND bound to the new cpuset (even though its NUMA placement,
+as queried by get_mempolicy(), doesn't change).  If a task is moved
+from one cpuset to another, then the kernel will adjust the task's
+memory placement, as above, the next time that the kernel attempts
+to allocate a page of memory for that task.
+
+If a cpuset has its 'cpuset.cpus' modified, then each task in that cpuset
+will have its allowed CPU placement changed immediately.  Similarly,
+if a task's pid is written to another cpuset's 'tasks' file, then its
+allowed CPU placement is changed immediately.  If such a task had been
+bound to some subset of its cpuset using the sched_setaffinity() call,
+the task will be allowed to run on any CPU allowed in its new cpuset,
+negating the effect of the prior sched_setaffinity() call.
+
+In summary, the memory placement of a task whose cpuset is changed is
+updated by the kernel, on the next allocation of a page for that task,
+and the processor placement is updated immediately.
+
+Normally, once a page is allocated (given a physical page
+of main memory) then that page stays on whatever node it
+was allocated, so long as it remains allocated, even if the
+cpusets memory placement policy 'cpuset.mems' subsequently changes.
+If the cpuset flag file 'cpuset.memory_migrate' is set true, then when
+tasks are attached to that cpuset, any pages that task had
+allocated to it on nodes in its previous cpuset are migrated
+to the task's new cpuset. The relative placement of the page within
+the cpuset is preserved during these migration operations if possible.
+For example if the page was on the second valid node of the prior cpuset
+then the page will be placed on the second valid node of the new cpuset.
+
+Also if 'cpuset.memory_migrate' is set true, then if that cpuset's
+'cpuset.mems' file is modified, pages allocated to tasks in that
+cpuset, that were on nodes in the previous setting of 'cpuset.mems',
+will be moved to nodes in the new setting of 'mems.'
+Pages that were not in the task's prior cpuset, or in the cpuset's
+prior 'cpuset.mems' setting, will not be moved.
+
+There is an exception to the above.  If hotplug functionality is used
+to remove all the CPUs that are currently assigned to a cpuset,
+then all the tasks in that cpuset will be moved to the nearest ancestor
+with non-empty cpus.  But the moving of some (or all) tasks might fail if
+cpuset is bound with another cgroup subsystem which has some restrictions
+on task attaching.  In this failing case, those tasks will stay
+in the original cpuset, and the kernel will automatically update
+their cpus_allowed to allow all online CPUs.  When memory hotplug
+functionality for removing Memory Nodes is available, a similar exception
+is expected to apply there as well.  In general, the kernel prefers to
+violate cpuset placement, over starving a task that has had all
+its allowed CPUs or Memory Nodes taken offline.
+
+There is a second exception to the above.  GFP_ATOMIC requests are
+kernel internal allocations that must be satisfied, immediately.
+The kernel may drop some request, in rare cases even panic, if a
+GFP_ATOMIC alloc fails.  If the request cannot be satisfied within
+the current task's cpuset, then we relax the cpuset, and look for
+memory anywhere we can find it.  It's better to violate the cpuset
+than stress the kernel.
+
+To start a new job that is to be contained within a cpuset, the steps are:
+
+ 1) mkdir /sys/fs/cgroup/cpuset
+ 2) mount -t cgroup -ocpuset cpuset /sys/fs/cgroup/cpuset
+ 3) Create the new cpuset by doing mkdir's and write's (or echo's) in
+    the /sys/fs/cgroup/cpuset virtual file system.
+ 4) Start a task that will be the "founding father" of the new job.
+ 5) Attach that task to the new cpuset by writing its pid to the
+    /sys/fs/cgroup/cpuset tasks file for that cpuset.
+ 6) fork, exec or clone the job tasks from this founding father task.
+
+For example, the following sequence of commands will setup a cpuset
+named "Charlie", containing just CPUs 2 and 3, and Memory Node 1,
+and then start a subshell 'sh' in that cpuset::
+
+  mount -t cgroup -ocpuset cpuset /sys/fs/cgroup/cpuset
+  cd /sys/fs/cgroup/cpuset
+  mkdir Charlie
+  cd Charlie
+  /bin/echo 2-3 > cpuset.cpus
+  /bin/echo 1 > cpuset.mems
+  /bin/echo $$ > tasks
+  sh
+  # The subshell 'sh' is now running in cpuset Charlie
+  # The next line should display '/Charlie'
+  cat /proc/self/cpuset
+
+There are ways to query or modify cpusets:
+
+ - via the cpuset file system directly, using the various cd, mkdir, echo,
+   cat, rmdir commands from the shell, or their equivalent from C.
+ - via the C library libcpuset.
+ - via the C library libcgroup.
+   (http://sourceforge.net/projects/libcg/)
+ - via the python application cset.
+   (http://code.google.com/p/cpuset/)
+
+The sched_setaffinity calls can also be done at the shell prompt using
+SGI's runon or Robert Love's taskset.  The mbind and set_mempolicy
+calls can be done at the shell prompt using the numactl command
+(part of Andi Kleen's numa package).
+
+2. Usage Examples and Syntax
+============================
+
+2.1 Basic Usage
+---------------
+
+Creating, modifying, using the cpusets can be done through the cpuset
+virtual filesystem.
+
+To mount it, type:
+# mount -t cgroup -o cpuset cpuset /sys/fs/cgroup/cpuset
+
+Then under /sys/fs/cgroup/cpuset you can find a tree that corresponds to the
+tree of the cpusets in the system. For instance, /sys/fs/cgroup/cpuset
+is the cpuset that holds the whole system.
+
+If you want to create a new cpuset under /sys/fs/cgroup/cpuset::
+
+  # cd /sys/fs/cgroup/cpuset
+  # mkdir my_cpuset
+
+Now you want to do something with this cpuset::
+
+  # cd my_cpuset
+
+In this directory you can find several files::
+
+  # ls
+  cgroup.clone_children  cpuset.memory_pressure
+  cgroup.event_control   cpuset.memory_spread_page
+  cgroup.procs           cpuset.memory_spread_slab
+  cpuset.cpu_exclusive   cpuset.mems
+  cpuset.cpus            cpuset.sched_load_balance
+  cpuset.mem_exclusive   cpuset.sched_relax_domain_level
+  cpuset.mem_hardwall    notify_on_release
+  cpuset.memory_migrate  tasks
+
+Reading them will give you information about the state of this cpuset:
+the CPUs and Memory Nodes it can use, the processes that are using
+it, its properties.  By writing to these files you can manipulate
+the cpuset.
+
+Set some flags::
+
+  # /bin/echo 1 > cpuset.cpu_exclusive
+
+Add some cpus::
+
+  # /bin/echo 0-7 > cpuset.cpus
+
+Add some mems::
+
+  # /bin/echo 0-7 > cpuset.mems
+
+Now attach your shell to this cpuset::
+
+  # /bin/echo $$ > tasks
+
+You can also create cpusets inside your cpuset by using mkdir in this
+directory::
+
+  # mkdir my_sub_cs
+
+To remove a cpuset, just use rmdir::
+
+  # rmdir my_sub_cs
+
+This will fail if the cpuset is in use (has cpusets inside, or has
+processes attached).
+
+Note that for legacy reasons, the "cpuset" filesystem exists as a
+wrapper around the cgroup filesystem.
+
+The command::
+
+  mount -t cpuset X /sys/fs/cgroup/cpuset
+
+is equivalent to::
+
+  mount -t cgroup -ocpuset,noprefix X /sys/fs/cgroup/cpuset
+  echo "/sbin/cpuset_release_agent" > /sys/fs/cgroup/cpuset/release_agent
+
+2.2 Adding/removing cpus
+------------------------
+
+This is the syntax to use when writing in the cpus or mems files
+in cpuset directories::
+
+  # /bin/echo 1-4 > cpuset.cpus                -> set cpus list to cpus 1,2,3,4
+  # /bin/echo 1,2,3,4 > cpuset.cpus    -> set cpus list to cpus 1,2,3,4
+
+To add a CPU to a cpuset, write the new list of CPUs including the
+CPU to be added. To add 6 to the above cpuset::
+
+  # /bin/echo 1-4,6 > cpuset.cpus      -> set cpus list to cpus 1,2,3,4,6
+
+Similarly to remove a CPU from a cpuset, write the new list of CPUs
+without the CPU to be removed.
+
+To remove all the CPUs::
+
+  # /bin/echo "" > cpuset.cpus         -> clear cpus list
+
+2.3 Setting flags
+-----------------
+
+The syntax is very simple::
+
+  # /bin/echo 1 > cpuset.cpu_exclusive         -> set flag 'cpuset.cpu_exclusive'
+  # /bin/echo 0 > cpuset.cpu_exclusive         -> unset flag 'cpuset.cpu_exclusive'
+
+2.4 Attaching processes
+-----------------------
+
+::
+
+  # /bin/echo PID > tasks
+
+Note that it is PID, not PIDs. You can only attach ONE task at a time.
+If you have several tasks to attach, you have to do it one after another::
+
+  # /bin/echo PID1 > tasks
+  # /bin/echo PID2 > tasks
+       ...
+  # /bin/echo PIDn > tasks
+
+
+3. Questions
+============
+
+Q:
+   what's up with this '/bin/echo' ?
+
+A:
+   bash's builtin 'echo' command does not check calls to write() against
+   errors. If you use it in the cpuset file system, you won't be
+   able to tell whether a command succeeded or failed.
+
+Q:
+   When I attach processes, only the first of the line gets really attached !
+
+A:
+   We can only return one error code per call to write(). So you should also
+   put only ONE pid.
+
+4. Contact
+==========
+
+Web: http://www.bullopensource.org/cpuset
diff --git a/Documentation/admin-guide/cgroup-v1/index.rst b/Documentation/admin-guide/cgroup-v1/index.rst
new file mode 100644 (file)
index 0000000..10bf48b
--- /dev/null
@@ -0,0 +1,28 @@
+========================
+Control Groups version 1
+========================
+
+.. toctree::
+    :maxdepth: 1
+
+    cgroups
+
+    blkio-controller
+    cpuacct
+    cpusets
+    devices
+    freezer-subsystem
+    hugetlb
+    memcg_test
+    memory
+    net_cls
+    net_prio
+    pids
+    rdma
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
diff --git a/Documentation/admin-guide/cgroup-v1/memcg_test.rst b/Documentation/admin-guide/cgroup-v1/memcg_test.rst
new file mode 100644 (file)
index 0000000..3f7115e
--- /dev/null
@@ -0,0 +1,355 @@
+=====================================================
+Memory Resource Controller(Memcg) Implementation Memo
+=====================================================
+
+Last Updated: 2010/2
+
+Base Kernel Version: based on 2.6.33-rc7-mm(candidate for 34).
+
+Because VM is getting complex (one of reasons is memcg...), memcg's behavior
+is complex. This is a document for memcg's internal behavior.
+Please note that implementation details can be changed.
+
+(*) Topics on API should be in Documentation/admin-guide/cgroup-v1/memory.rst)
+
+0. How to record usage ?
+========================
+
+   2 objects are used.
+
+   page_cgroup ....an object per page.
+
+       Allocated at boot or memory hotplug. Freed at memory hot removal.
+
+   swap_cgroup ... an entry per swp_entry.
+
+       Allocated at swapon(). Freed at swapoff().
+
+   The page_cgroup has USED bit and double count against a page_cgroup never
+   occurs. swap_cgroup is used only when a charged page is swapped-out.
+
+1. Charge
+=========
+
+   a page/swp_entry may be charged (usage += PAGE_SIZE) at
+
+       mem_cgroup_try_charge()
+
+2. Uncharge
+===========
+
+  a page/swp_entry may be uncharged (usage -= PAGE_SIZE) by
+
+       mem_cgroup_uncharge()
+         Called when a page's refcount goes down to 0.
+
+       mem_cgroup_uncharge_swap()
+         Called when swp_entry's refcnt goes down to 0. A charge against swap
+         disappears.
+
+3. charge-commit-cancel
+=======================
+
+       Memcg pages are charged in two steps:
+
+               - mem_cgroup_try_charge()
+               - mem_cgroup_commit_charge() or mem_cgroup_cancel_charge()
+
+       At try_charge(), there are no flags to say "this page is charged".
+       at this point, usage += PAGE_SIZE.
+
+       At commit(), the page is associated with the memcg.
+
+       At cancel(), simply usage -= PAGE_SIZE.
+
+Under below explanation, we assume CONFIG_MEM_RES_CTRL_SWAP=y.
+
+4. Anonymous
+============
+
+       Anonymous page is newly allocated at
+                 - page fault into MAP_ANONYMOUS mapping.
+                 - Copy-On-Write.
+
+       4.1 Swap-in.
+       At swap-in, the page is taken from swap-cache. There are 2 cases.
+
+       (a) If the SwapCache is newly allocated and read, it has no charges.
+       (b) If the SwapCache has been mapped by processes, it has been
+           charged already.
+
+       4.2 Swap-out.
+       At swap-out, typical state transition is below.
+
+       (a) add to swap cache. (marked as SwapCache)
+           swp_entry's refcnt += 1.
+       (b) fully unmapped.
+           swp_entry's refcnt += # of ptes.
+       (c) write back to swap.
+       (d) delete from swap cache. (remove from SwapCache)
+           swp_entry's refcnt -= 1.
+
+
+       Finally, at task exit,
+       (e) zap_pte() is called and swp_entry's refcnt -=1 -> 0.
+
+5. Page Cache
+=============
+
+       Page Cache is charged at
+       - add_to_page_cache_locked().
+
+       The logic is very clear. (About migration, see below)
+
+       Note:
+         __remove_from_page_cache() is called by remove_from_page_cache()
+         and __remove_mapping().
+
+6. Shmem(tmpfs) Page Cache
+===========================
+
+       The best way to understand shmem's page state transition is to read
+       mm/shmem.c.
+
+       But brief explanation of the behavior of memcg around shmem will be
+       helpful to understand the logic.
+
+       Shmem's page (just leaf page, not direct/indirect block) can be on
+
+               - radix-tree of shmem's inode.
+               - SwapCache.
+               - Both on radix-tree and SwapCache. This happens at swap-in
+                 and swap-out,
+
+       It's charged when...
+
+       - A new page is added to shmem's radix-tree.
+       - A swp page is read. (move a charge from swap_cgroup to page_cgroup)
+
+7. Page Migration
+=================
+
+       mem_cgroup_migrate()
+
+8. LRU
+======
+        Each memcg has its own private LRU. Now, its handling is under global
+       VM's control (means that it's handled under global pgdat->lru_lock).
+       Almost all routines around memcg's LRU is called by global LRU's
+       list management functions under pgdat->lru_lock.
+
+       A special function is mem_cgroup_isolate_pages(). This scans
+       memcg's private LRU and call __isolate_lru_page() to extract a page
+       from LRU.
+
+       (By __isolate_lru_page(), the page is removed from both of global and
+       private LRU.)
+
+
+9. Typical Tests.
+=================
+
+ Tests for racy cases.
+
+9.1 Small limit to memcg.
+-------------------------
+
+       When you do test to do racy case, it's good test to set memcg's limit
+       to be very small rather than GB. Many races found in the test under
+       xKB or xxMB limits.
+
+       (Memory behavior under GB and Memory behavior under MB shows very
+       different situation.)
+
+9.2 Shmem
+---------
+
+       Historically, memcg's shmem handling was poor and we saw some amount
+       of troubles here. This is because shmem is page-cache but can be
+       SwapCache. Test with shmem/tmpfs is always good test.
+
+9.3 Migration
+-------------
+
+       For NUMA, migration is an another special case. To do easy test, cpuset
+       is useful. Following is a sample script to do migration::
+
+               mount -t cgroup -o cpuset none /opt/cpuset
+
+               mkdir /opt/cpuset/01
+               echo 1 > /opt/cpuset/01/cpuset.cpus
+               echo 0 > /opt/cpuset/01/cpuset.mems
+               echo 1 > /opt/cpuset/01/cpuset.memory_migrate
+               mkdir /opt/cpuset/02
+               echo 1 > /opt/cpuset/02/cpuset.cpus
+               echo 1 > /opt/cpuset/02/cpuset.mems
+               echo 1 > /opt/cpuset/02/cpuset.memory_migrate
+
+       In above set, when you moves a task from 01 to 02, page migration to
+       node 0 to node 1 will occur. Following is a script to migrate all
+       under cpuset.::
+
+               --
+               move_task()
+               {
+               for pid in $1
+               do
+                       /bin/echo $pid >$2/tasks 2>/dev/null
+                       echo -n $pid
+                       echo -n " "
+               done
+               echo END
+               }
+
+               G1_TASK=`cat ${G1}/tasks`
+               G2_TASK=`cat ${G2}/tasks`
+               move_task "${G1_TASK}" ${G2} &
+               --
+
+9.4 Memory hotplug
+------------------
+
+       memory hotplug test is one of good test.
+
+       to offline memory, do following::
+
+               # echo offline > /sys/devices/system/memory/memoryXXX/state
+
+       (XXX is the place of memory)
+
+       This is an easy way to test page migration, too.
+
+9.5 mkdir/rmdir
+---------------
+
+       When using hierarchy, mkdir/rmdir test should be done.
+       Use tests like the following::
+
+               echo 1 >/opt/cgroup/01/memory/use_hierarchy
+               mkdir /opt/cgroup/01/child_a
+               mkdir /opt/cgroup/01/child_b
+
+               set limit to 01.
+               add limit to 01/child_b
+               run jobs under child_a and child_b
+
+       create/delete following groups at random while jobs are running::
+
+               /opt/cgroup/01/child_a/child_aa
+               /opt/cgroup/01/child_b/child_bb
+               /opt/cgroup/01/child_c
+
+       running new jobs in new group is also good.
+
+9.6 Mount with other subsystems
+-------------------------------
+
+       Mounting with other subsystems is a good test because there is a
+       race and lock dependency with other cgroup subsystems.
+
+       example::
+
+               # mount -t cgroup none /cgroup -o cpuset,memory,cpu,devices
+
+       and do task move, mkdir, rmdir etc...under this.
+
+9.7 swapoff
+-----------
+
+       Besides management of swap is one of complicated parts of memcg,
+       call path of swap-in at swapoff is not same as usual swap-in path..
+       It's worth to be tested explicitly.
+
+       For example, test like following is good:
+
+       (Shell-A)::
+
+               # mount -t cgroup none /cgroup -o memory
+               # mkdir /cgroup/test
+               # echo 40M > /cgroup/test/memory.limit_in_bytes
+               # echo 0 > /cgroup/test/tasks
+
+       Run malloc(100M) program under this. You'll see 60M of swaps.
+
+       (Shell-B)::
+
+               # move all tasks in /cgroup/test to /cgroup
+               # /sbin/swapoff -a
+               # rmdir /cgroup/test
+               # kill malloc task.
+
+       Of course, tmpfs v.s. swapoff test should be tested, too.
+
+9.8 OOM-Killer
+--------------
+
+       Out-of-memory caused by memcg's limit will kill tasks under
+       the memcg. When hierarchy is used, a task under hierarchy
+       will be killed by the kernel.
+
+       In this case, panic_on_oom shouldn't be invoked and tasks
+       in other groups shouldn't be killed.
+
+       It's not difficult to cause OOM under memcg as following.
+
+       Case A) when you can swapoff::
+
+               #swapoff -a
+               #echo 50M > /memory.limit_in_bytes
+
+       run 51M of malloc
+
+       Case B) when you use mem+swap limitation::
+
+               #echo 50M > memory.limit_in_bytes
+               #echo 50M > memory.memsw.limit_in_bytes
+
+       run 51M of malloc
+
+9.9 Move charges at task migration
+----------------------------------
+
+       Charges associated with a task can be moved along with task migration.
+
+       (Shell-A)::
+
+               #mkdir /cgroup/A
+               #echo $$ >/cgroup/A/tasks
+
+       run some programs which uses some amount of memory in /cgroup/A.
+
+       (Shell-B)::
+
+               #mkdir /cgroup/B
+               #echo 1 >/cgroup/B/memory.move_charge_at_immigrate
+               #echo "pid of the program running in group A" >/cgroup/B/tasks
+
+       You can see charges have been moved by reading ``*.usage_in_bytes`` or
+       memory.stat of both A and B.
+
+       See 8.2 of Documentation/admin-guide/cgroup-v1/memory.rst to see what value should
+       be written to move_charge_at_immigrate.
+
+9.10 Memory thresholds
+----------------------
+
+       Memory controller implements memory thresholds using cgroups notification
+       API. You can use tools/cgroup/cgroup_event_listener.c to test it.
+
+       (Shell-A) Create cgroup and run event listener::
+
+               # mkdir /cgroup/A
+               # ./cgroup_event_listener /cgroup/A/memory.usage_in_bytes 5M
+
+       (Shell-B) Add task to cgroup and try to allocate and free memory::
+
+               # echo $$ >/cgroup/A/tasks
+               # a="$(dd if=/dev/zero bs=1M count=10)"
+               # a=
+
+       You will see message from cgroup_event_listener every time you cross
+       the thresholds.
+
+       Use /cgroup/A/memory.memsw.usage_in_bytes to test memsw thresholds.
+
+       It's good idea to test root cgroup as well.
index 8269e86..3b29005 100644 (file)
@@ -9,7 +9,7 @@ This is the authoritative documentation on the design, interface and
 conventions of cgroup v2.  It describes all userland-visible aspects
 of cgroup including core and specific controller behaviors.  All
 future changes must be reflected in this document.  Documentation for
-v1 is available under Documentation/cgroup-v1/.
+v1 is available under Documentation/admin-guide/cgroup-v1/.
 
 .. CONTENTS
 
@@ -1014,7 +1014,7 @@ All time durations are in microseconds.
        A read-only nested-key file which exists on non-root cgroups.
 
        Shows pressure stall information for CPU. See
-       Documentation/accounting/psi.txt for details.
+       Documentation/accounting/psi.rst for details.
 
 
 Memory
@@ -1355,7 +1355,7 @@ PAGE_SIZE multiple when read back.
        A read-only nested-key file which exists on non-root cgroups.
 
        Shows pressure stall information for memory. See
-       Documentation/accounting/psi.txt for details.
+       Documentation/accounting/psi.rst for details.
 
 
 Usage Guidelines
@@ -1498,7 +1498,7 @@ IO Interface Files
        A read-only nested-key file which exists on non-root cgroups.
 
        Shows pressure stall information for IO. See
-       Documentation/accounting/psi.txt for details.
+       Documentation/accounting/psi.rst for details.
 
 
 Writeback
diff --git a/Documentation/admin-guide/device-mapper/index.rst b/Documentation/admin-guide/device-mapper/index.rst
new file mode 100644 (file)
index 0000000..c77c58b
--- /dev/null
@@ -0,0 +1,42 @@
+=============
+Device Mapper
+=============
+
+.. toctree::
+    :maxdepth: 1
+
+    cache-policies
+    cache
+    delay
+    dm-crypt
+    dm-flakey
+    dm-init
+    dm-integrity
+    dm-io
+    dm-log
+    dm-queue-length
+    dm-raid
+    dm-service-time
+    dm-uevent
+    dm-zoned
+    era
+    kcopyd
+    linear
+    log-writes
+    persistent-data
+    snapshot
+    statistics
+    striped
+    switch
+    thin-provisioning
+    unstriped
+    verity
+    writecache
+    zero
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
diff --git a/Documentation/admin-guide/device-mapper/statistics.rst b/Documentation/admin-guide/device-mapper/statistics.rst
new file mode 100644 (file)
index 0000000..41ded0b
--- /dev/null
@@ -0,0 +1,225 @@
+=============
+DM statistics
+=============
+
+Device Mapper supports the collection of I/O statistics on user-defined
+regions of a DM device.         If no regions are defined no statistics are
+collected so there isn't any performance impact.  Only bio-based DM
+devices are currently supported.
+
+Each user-defined region specifies a starting sector, length and step.
+Individual statistics will be collected for each step-sized area within
+the range specified.
+
+The I/O statistics counters for each step-sized area of a region are
+in the same format as `/sys/block/*/stat` or `/proc/diskstats` (see:
+Documentation/admin-guide/iostats.rst).  But two extra counters (12 and 13) are
+provided: total time spent reading and writing.  When the histogram
+argument is used, the 14th parameter is reported that represents the
+histogram of latencies.  All these counters may be accessed by sending
+the @stats_print message to the appropriate DM device via dmsetup.
+
+The reported times are in milliseconds and the granularity depends on
+the kernel ticks.  When the option precise_timestamps is used, the
+reported times are in nanoseconds.
+
+Each region has a corresponding unique identifier, which we call a
+region_id, that is assigned when the region is created.         The region_id
+must be supplied when querying statistics about the region, deleting the
+region, etc.  Unique region_ids enable multiple userspace programs to
+request and process statistics for the same DM device without stepping
+on each other's data.
+
+The creation of DM statistics will allocate memory via kmalloc or
+fallback to using vmalloc space.  At most, 1/4 of the overall system
+memory may be allocated by DM statistics.  The admin can see how much
+memory is used by reading:
+
+       /sys/module/dm_mod/parameters/stats_current_allocated_bytes
+
+Messages
+========
+
+    @stats_create <range> <step> [<number_of_optional_arguments> <optional_arguments>...] [<program_id> [<aux_data>]]
+       Create a new region and return the region_id.
+
+       <range>
+         "-"
+               whole device
+         "<start_sector>+<length>"
+               a range of <length> 512-byte sectors
+               starting with <start_sector>.
+
+       <step>
+         "<area_size>"
+               the range is subdivided into areas each containing
+               <area_size> sectors.
+         "/<number_of_areas>"
+               the range is subdivided into the specified
+               number of areas.
+
+       <number_of_optional_arguments>
+         The number of optional arguments
+
+       <optional_arguments>
+         The following optional arguments are supported:
+
+         precise_timestamps
+               use precise timer with nanosecond resolution
+               instead of the "jiffies" variable.  When this argument is
+               used, the resulting times are in nanoseconds instead of
+               milliseconds.  Precise timestamps are a little bit slower
+               to obtain than jiffies-based timestamps.
+         histogram:n1,n2,n3,n4,...
+               collect histogram of latencies.  The
+               numbers n1, n2, etc are times that represent the boundaries
+               of the histogram.  If precise_timestamps is not used, the
+               times are in milliseconds, otherwise they are in
+               nanoseconds.  For each range, the kernel will report the
+               number of requests that completed within this range. For
+               example, if we use "histogram:10,20,30", the kernel will
+               report four numbers a:b:c:d. a is the number of requests
+               that took 0-10 ms to complete, b is the number of requests
+               that took 10-20 ms to complete, c is the number of requests
+               that took 20-30 ms to complete and d is the number of
+               requests that took more than 30 ms to complete.
+
+       <program_id>
+         An optional parameter.  A name that uniquely identifies
+         the userspace owner of the range.  This groups ranges together
+         so that userspace programs can identify the ranges they
+         created and ignore those created by others.
+         The kernel returns this string back in the output of
+         @stats_list message, but it doesn't use it for anything else.
+         If we omit the number of optional arguments, program id must not
+         be a number, otherwise it would be interpreted as the number of
+         optional arguments.
+
+       <aux_data>
+         An optional parameter.  A word that provides auxiliary data
+         that is useful to the client program that created the range.
+         The kernel returns this string back in the output of
+         @stats_list message, but it doesn't use this value for anything.
+
+    @stats_delete <region_id>
+       Delete the region with the specified id.
+
+       <region_id>
+         region_id returned from @stats_create
+
+    @stats_clear <region_id>
+       Clear all the counters except the in-flight i/o counters.
+
+       <region_id>
+         region_id returned from @stats_create
+
+    @stats_list [<program_id>]
+       List all regions registered with @stats_create.
+
+       <program_id>
+         An optional parameter.
+         If this parameter is specified, only matching regions
+         are returned.
+         If it is not specified, all regions are returned.
+
+       Output format:
+         <region_id>: <start_sector>+<length> <step> <program_id> <aux_data>
+               precise_timestamps histogram:n1,n2,n3,...
+
+       The strings "precise_timestamps" and "histogram" are printed only
+       if they were specified when creating the region.
+
+    @stats_print <region_id> [<starting_line> <number_of_lines>]
+       Print counters for each step-sized area of a region.
+
+       <region_id>
+         region_id returned from @stats_create
+
+       <starting_line>
+         The index of the starting line in the output.
+         If omitted, all lines are returned.
+
+       <number_of_lines>
+         The number of lines to include in the output.
+         If omitted, all lines are returned.
+
+       Output format for each step-sized area of a region:
+
+         <start_sector>+<length>
+               counters
+
+         The first 11 counters have the same meaning as
+         `/sys/block/*/stat or /proc/diskstats`.
+
+         Please refer to Documentation/admin-guide/iostats.rst for details.
+
+         1. the number of reads completed
+         2. the number of reads merged
+         3. the number of sectors read
+         4. the number of milliseconds spent reading
+         5. the number of writes completed
+         6. the number of writes merged
+         7. the number of sectors written
+         8. the number of milliseconds spent writing
+         9. the number of I/Os currently in progress
+         10. the number of milliseconds spent doing I/Os
+         11. the weighted number of milliseconds spent doing I/Os
+
+         Additional counters:
+
+         12. the total time spent reading in milliseconds
+         13. the total time spent writing in milliseconds
+
+    @stats_print_clear <region_id> [<starting_line> <number_of_lines>]
+       Atomically print and then clear all the counters except the
+       in-flight i/o counters.  Useful when the client consuming the
+       statistics does not want to lose any statistics (those updated
+       between printing and clearing).
+
+       <region_id>
+         region_id returned from @stats_create
+
+       <starting_line>
+         The index of the starting line in the output.
+         If omitted, all lines are printed and then cleared.
+
+       <number_of_lines>
+         The number of lines to process.
+         If omitted, all lines are printed and then cleared.
+
+    @stats_set_aux <region_id> <aux_data>
+       Store auxiliary data aux_data for the specified region.
+
+       <region_id>
+         region_id returned from @stats_create
+
+       <aux_data>
+         The string that identifies data which is useful to the client
+         program that created the range.  The kernel returns this
+         string back in the output of @stats_list message, but it
+         doesn't use this value for anything.
+
+Examples
+========
+
+Subdivide the DM device 'vol' into 100 pieces and start collecting
+statistics on them::
+
+  dmsetup message vol 0 @stats_create - /100
+
+Set the auxiliary data string to "foo bar baz" (the escape for each
+space must also be escaped, otherwise the shell will consume them)::
+
+  dmsetup message vol 0 @stats_set_aux 0 foo\\ bar\\ baz
+
+List the statistics::
+
+  dmsetup message vol 0 @stats_list
+
+Print the statistics::
+
+  dmsetup message vol 0 @stats_print 0
+
+Delete the statistics::
+
+  dmsetup message vol 0 @stats_delete 0
diff --git a/Documentation/admin-guide/gpio/index.rst b/Documentation/admin-guide/gpio/index.rst
new file mode 100644 (file)
index 0000000..a244ba4
--- /dev/null
@@ -0,0 +1,17 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+====
+gpio
+====
+
+.. toctree::
+    :maxdepth: 1
+
+    sysfs
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
index 656aee2..f83212f 100644 (file)
@@ -241,7 +241,7 @@ Guest mitigation mechanisms
    For further information about confining guests to a single or to a group
    of cores consult the cpusets documentation:
 
-   https://www.kernel.org/doc/Documentation/cgroup-v1/cpusets.rst
+   https://www.kernel.org/doc/Documentation/admin-guide/cgroup-v1/cpusets.rst
 
 .. _interrupt_isolation:
 
index 24fbe05..33feab2 100644 (file)
@@ -16,6 +16,7 @@ etc.
    README
    kernel-parameters
    devices
+   sysctl/index
 
 This section describes CPU vulnerabilities and their mitigations.
 
@@ -38,6 +39,8 @@ problems and bugs in particular.
    ramoops
    dynamic-debug-howto
    init
+   kdump/index
+   perf/index
 
 This is the beginning of a section with information of interest to
 application developers.  Documents covering various aspects of the kernel
@@ -56,11 +59,13 @@ configure specific aspects of kernel behavior to your liking.
 
    initrd
    cgroup-v2
+   cgroup-v1/index
    serial-console
    braille-console
    parport
    md
    module-signing
+   rapidio
    sysrq
    unicode
    vga-softcursor
@@ -69,14 +74,38 @@ configure specific aspects of kernel behavior to your liking.
    java
    ras
    bcache
+   blockdev/index
    ext4
    binderfs
+   xfs
    pm/index
    thunderbolt
    LSM/index
    mm/index
+   namespaces/index
    perf-security
    acpi/index
+   aoe/index
+   btmrvl
+   clearing-warn-once
+   cpu-load
+   cputopology
+   device-mapper/index
+   efi-stub
+   gpio/index
+   highuid
+   hw_random
+   iostats
+   kernel-per-CPU-kthreads
+   laptops/index
+   lcd-panel-cgram
+   ldm
+   lockup-watchdogs
+   numastat
+   pnp
+   rtc
+   svga
+   video-output
 
 .. only::  subproject and html
 
diff --git a/Documentation/admin-guide/kdump/index.rst b/Documentation/admin-guide/kdump/index.rst
new file mode 100644 (file)
index 0000000..8e2ebd0
--- /dev/null
@@ -0,0 +1,20 @@
+
+================================================================
+Documentation for Kdump - The kexec-based Crash Dumping Solution
+================================================================
+
+This document includes overview, setup and installation, and analysis
+information.
+
+.. toctree::
+    :maxdepth: 1
+
+    kdump
+    vmcoreinfo
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
index 5d29ba5..d05d531 100644 (file)
@@ -118,7 +118,7 @@ parameter is applicable::
        LOOP    Loopback device support is enabled.
        M68k    M68k architecture is enabled.
                        These options have more detailed description inside of
-                       Documentation/m68k/kernel-options.txt.
+                       Documentation/m68k/kernel-options.rst.
        MDA     MDA console support is enabled.
        MIPS    MIPS architecture is enabled.
        MOUSE   Appropriate mouse support is enabled.
index f8b6236..7ccd158 100644 (file)
 
        blkdevparts=    Manual partition parsing of block device(s) for
                        embedded devices based on command line input.
-                       See Documentation/block/cmdline-partition.txt
+                       See Documentation/block/cmdline-partition.rst
 
        boot_delay=     Milliseconds to delay each printk during boot.
                        Values larger than 10 seconds (10000) are changed to
                        [KNL, x86_64] select a region under 4G first, and
                        fall back to reserve region above 4G when '@offset'
                        hasn't been specified.
-                       See Documentation/kdump/kdump.rst for further details.
+                       See Documentation/admin-guide/kdump/kdump.rst for further details.
 
        crashkernel=range1:size1[,range2:size2,...][@offset]
                        [KNL] Same as above, but depends on the memory
                        in the running system. The syntax of range is
                        start-[end] where start and end are both
                        a memory unit (amount[KMG]). See also
-                       Documentation/kdump/kdump.rst for an example.
+                       Documentation/admin-guide/kdump/kdump.rst for an example.
 
        crashkernel=size[KMG],high
                        [KNL, x86_64] range could be above 4G. Allow kernel
                        edid/1680x1050.bin, or edid/1920x1080.bin is given
                        and no file with the same name exists. Details and
                        instructions how to build your own EDID data are
-                       available in Documentation/EDID/howto.rst. An EDID
+                       available in Documentation/driver-api/edid.rst. An EDID
                        data set will only be used for a particular connector,
                        if its name and a colon are prepended to the EDID
                        name. Each connector may use a unique EDID data
 
        elevator=       [IOSCHED]
                        Format: { "mq-deadline" | "kyber" | "bfq" }
-                       See Documentation/block/deadline-iosched.txt,
-                       Documentation/block/kyber-iosched.txt and
-                       Documentation/block/bfq-iosched.txt for details.
+                       See Documentation/block/deadline-iosched.rst,
+                       Documentation/block/kyber-iosched.rst and
+                       Documentation/block/bfq-iosched.rst for details.
 
        elfcorehdr=[size[KMG]@]offset[KMG] [IA64,PPC,SH,X86,S390]
                        Specifies physical address of start of kernel core
                        image elf header and optionally the size. Generally
                        kexec loader will pass this option to capture kernel.
-                       See Documentation/kdump/kdump.rst for details.
+                       See Documentation/admin-guide/kdump/kdump.rst for details.
 
        enable_mtrr_cleanup [X86]
                        The kernel tries to adjust MTRR layout from continuous
                        See also Documentation/fault-injection/.
 
        floppy=         [HW]
-                       See Documentation/blockdev/floppy.txt.
+                       See Documentation/admin-guide/blockdev/floppy.rst.
 
        force_pal_cache_flush
                        [IA-64] Avoid check_sal_cache_flush which may hang on
                        Built with CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y,
                        the default is off.
 
+       kprobe_event=[probe-list]
+                       [FTRACE] Add kprobe events and enable at boot time.
+                       The probe-list is a semicolon delimited list of probe
+                       definitions. Each definition is same as kprobe_events
+                       interface, but the parameters are comma delimited.
+                       For example, to add a kprobe event on vfs_read with
+                       arg1 and arg2, add to the command line;
+
+                             kprobe_event=p,vfs_read,$arg1,$arg2
+
+                       See also Documentation/trace/kprobetrace.rst "Kernel
+                       Boot Parameter" section.
+
        kpti=           [ARM64] Control page table isolation of user
                        and kernel address spaces.
                        Default: enabled on cores which need mitigation.
        memblock=debug  [KNL] Enable memblock debug messages.
 
        load_ramdisk=   [RAM] List of ramdisks to load from floppy
-                       See Documentation/blockdev/ramdisk.txt.
+                       See Documentation/admin-guide/blockdev/ramdisk.rst.
 
        lockd.nlm_grace_period=P  [NFS] Assign grace period.
                        Format: <integer>
                        mem_encrypt=on:         Activate SME
                        mem_encrypt=off:        Do not activate SME
 
-                       Refer to Documentation/virtual/kvm/amd-memory-encryption.rst
+                       Refer to Documentation/virt/kvm/amd-memory-encryption.rst
                        for details on when memory encryption can be activated.
 
        mem_sleep_default=      [SUSPEND] Default system suspend mode:
                        /sys/module/printk/parameters/console_suspend) to
                        turn on/off it dynamically.
 
+       novmcoredd      [KNL,KDUMP]
+                       Disable device dump. Device dump allows drivers to
+                       append dump data to vmcore so you can collect driver
+                       specified debug info.  Drivers can append the data
+                       without any limit and this data is stored in memory,
+                       so this may cause significant memory stress.  Disabling
+                       device dump can help save memory but the driver debug
+                       data will be no longer available.  This parameter
+                       is only available when CONFIG_PROC_VMCORE_DEVICE_DUMP
+                       is set.
+
        noaliencache    [MM, NUMA, SLAB] Disables the allocation of alien
                        caches in the slab allocator.  Saves per-node memory,
                        but will impact performance.
        numa_zonelist_order= [KNL, BOOT] Select zonelist order for NUMA.
                        'node', 'default' can be specified
                        This can be set from sysctl after boot.
-                       See Documentation/sysctl/vm.txt for details.
+                       See Documentation/admin-guide/sysctl/vm.rst for details.
 
        ohci1394_dma=early      [HW] enable debugging via the ohci1394 driver.
                        See Documentation/debugging-via-ohci1394.txt for more
 
        pcd.            [PARIDE]
                        See header of drivers/block/paride/pcd.c.
-                       See also Documentation/blockdev/paride.txt.
+                       See also Documentation/admin-guide/blockdev/paride.rst.
 
        pci=option[,option...]  [PCI] various PCI subsystem options.
 
                        needed on a platform with proper driver support.
 
        pd.             [PARIDE]
-                       See Documentation/blockdev/paride.txt.
+                       See Documentation/admin-guide/blockdev/paride.rst.
 
        pdcchassis=     [PARISC,HW] Disable/Enable PDC Chassis Status codes at
                        boot time.
                        and performance comparison.
 
        pf.             [PARIDE]
-                       See Documentation/blockdev/paride.txt.
+                       See Documentation/admin-guide/blockdev/paride.rst.
 
        pg.             [PARIDE]
-                       See Documentation/blockdev/paride.txt.
+                       See Documentation/admin-guide/blockdev/paride.rst.
 
        pirq=           [SMP,APIC] Manual mp-table setup
                        See Documentation/x86/i386/IO-APIC.rst.
 
        prompt_ramdisk= [RAM] List of RAM disks to prompt for floppy disk
                        before loading.
-                       See Documentation/blockdev/ramdisk.txt.
+                       See Documentation/admin-guide/blockdev/ramdisk.rst.
 
        psi=            [KNL] Enable or disable pressure stall information
                        tracking.
        pstore.backend= Specify the name of the pstore backend to use
 
        pt.             [PARIDE]
-                       See Documentation/blockdev/paride.txt.
+                       See Documentation/admin-guide/blockdev/paride.rst.
 
        pti=            [X86_64] Control Page Table Isolation of user and
                        kernel address spaces.  Disabling this feature
                        See Documentation/admin-guide/md.rst.
 
        ramdisk_size=   [RAM] Sizes of RAM disks in kilobytes
-                       See Documentation/blockdev/ramdisk.txt.
+                       See Documentation/admin-guide/blockdev/ramdisk.rst.
 
        random.trust_cpu={on,off}
                        [KNL] Enable or disable trusting the use of the
 
        relax_domain_level=
                        [KNL, SMP] Set scheduler's default relax_domain_level.
-                       See Documentation/cgroup-v1/cpusets.rst.
+                       See Documentation/admin-guide/cgroup-v1/cpusets.rst.
 
        reserve=        [KNL,BUGS] Force kernel to ignore I/O ports or memory
                        Format: <base1>,<size1>[,<base2>,<size2>,...]
                        Format: <integer>
 
        sonypi.*=       [HW] Sony Programmable I/O Control Device driver
-                       See Documentation/laptops/sonypi.txt
+                       See Documentation/admin-guide/laptops/sonypi.rst
 
        spectre_v2=     [X86] Control mitigation of Spectre variant 2
                        (indirect branch speculation) vulnerability.
        swapaccount=[0|1]
                        [KNL] Enable accounting of swap in memory resource
                        controller if no parameter or 1 is given or disable
-                       it if 0 is given (See Documentation/cgroup-v1/memory.rst)
+                       it if 0 is given (See Documentation/admin-guide/cgroup-v1/memory.rst)
 
        swiotlb=        [ARM,IA-64,PPC,MIPS,X86]
                        Format: { <int> | force | noforce }
                        Force threading of all interrupt handlers except those
                        marked explicitly IRQF_NO_THREAD.
 
-       tmem            [KNL,XEN]
-                       Enable the Transcendent memory driver if built-in.
-
-       tmem.cleancache=0|1 [KNL, XEN]
-                       Default is on (1). Disable the usage of the cleancache
-                       API to send anonymous pages to the hypervisor.
-
-       tmem.frontswap=0|1 [KNL, XEN]
-                       Default is on (1). Disable the usage of the frontswap
-                       API to send swap pages to the hypervisor. If disabled
-                       the selfballooning and selfshrinking are force disabled.
-
-       tmem.selfballooning=0|1 [KNL, XEN]
-                       Default is on (1). Disable the driving of swap pages
-                       to the hypervisor.
-
-       tmem.selfshrinking=0|1 [KNL, XEN]
-                       Default is on (1). Partial swapoff that immediately
-                       transfers pages from Xen hypervisor back to the
-                       kernel based on different criteria.
-
        topology=       [S390]
                        Format: {off | on}
                        Specify if the kernel should make use of the cpu
 
        vga=            [BOOT,X86-32] Select a particular video mode
                        See Documentation/x86/boot.rst and
-                       Documentation/svga.txt.
+                       Documentation/admin-guide/svga.rst.
                        Use vga=ask for menu.
                        This is actually a boot loader parameter; the value is
                        passed to the kernel using a special protocol.
        xen_nopv        [X86]
                        Disables the PV optimizations forcing the HVM guest to
                        run as generic HVM guest with no PV drivers.
+                       This option is obsoleted by the "nopv" option, which
+                       has equivalent effect for XEN platform.
 
        xen_scrub_pages=        [XEN]
                        Boolean option to control scrubbing pages before giving them back
                        improve timer resolution at the expense of processing
                        more timer interrupts.
 
+       nopv=           [X86,XEN,KVM,HYPER_V,VMWARE]
+                       Disables the PV optimizations forcing the guest to run
+                       as generic guest with no PV drivers. Currently support
+                       XEN HVM, KVM, HYPER_V and VMWARE guest.
+
        xirc2ps_cs=     [NET,PCMCIA]
                        Format:
                        <irq>,<irq_mask>,<io>,<full_duplex>,<do_sound>,<lockup_hack>[,<irq2>[,<irq3>[,<irq4>]]]
diff --git a/Documentation/admin-guide/kernel-per-CPU-kthreads.rst b/Documentation/admin-guide/kernel-per-CPU-kthreads.rst
new file mode 100644 (file)
index 0000000..4f18456
--- /dev/null
@@ -0,0 +1,356 @@
+==========================================
+Reducing OS jitter due to per-cpu kthreads
+==========================================
+
+This document lists per-CPU kthreads in the Linux kernel and presents
+options to control their OS jitter.  Note that non-per-CPU kthreads are
+not listed here.  To reduce OS jitter from non-per-CPU kthreads, bind
+them to a "housekeeping" CPU dedicated to such work.
+
+References
+==========
+
+-      Documentation/IRQ-affinity.txt:  Binding interrupts to sets of CPUs.
+
+-      Documentation/admin-guide/cgroup-v1:  Using cgroups to bind tasks to sets of CPUs.
+
+-      man taskset:  Using the taskset command to bind tasks to sets
+       of CPUs.
+
+-      man sched_setaffinity:  Using the sched_setaffinity() system
+       call to bind tasks to sets of CPUs.
+
+-      /sys/devices/system/cpu/cpuN/online:  Control CPU N's hotplug state,
+       writing "0" to offline and "1" to online.
+
+-      In order to locate kernel-generated OS jitter on CPU N:
+
+               cd /sys/kernel/debug/tracing
+               echo 1 > max_graph_depth # Increase the "1" for more detail
+               echo function_graph > current_tracer
+               # run workload
+               cat per_cpu/cpuN/trace
+
+kthreads
+========
+
+Name:
+  ehca_comp/%u
+
+Purpose:
+  Periodically process Infiniband-related work.
+
+To reduce its OS jitter, do any of the following:
+
+1.     Don't use eHCA Infiniband hardware, instead choosing hardware
+       that does not require per-CPU kthreads.  This will prevent these
+       kthreads from being created in the first place.  (This will
+       work for most people, as this hardware, though important, is
+       relatively old and is produced in relatively low unit volumes.)
+2.     Do all eHCA-Infiniband-related work on other CPUs, including
+       interrupts.
+3.     Rework the eHCA driver so that its per-CPU kthreads are
+       provisioned only on selected CPUs.
+
+
+Name:
+  irq/%d-%s
+
+Purpose:
+  Handle threaded interrupts.
+
+To reduce its OS jitter, do the following:
+
+1.     Use irq affinity to force the irq threads to execute on
+       some other CPU.
+
+Name:
+  kcmtpd_ctr_%d
+
+Purpose:
+  Handle Bluetooth work.
+
+To reduce its OS jitter, do one of the following:
+
+1.     Don't use Bluetooth, in which case these kthreads won't be
+       created in the first place.
+2.     Use irq affinity to force Bluetooth-related interrupts to
+       occur on some other CPU and furthermore initiate all
+       Bluetooth activity on some other CPU.
+
+Name:
+  ksoftirqd/%u
+
+Purpose:
+  Execute softirq handlers when threaded or when under heavy load.
+
+To reduce its OS jitter, each softirq vector must be handled
+separately as follows:
+
+TIMER_SOFTIRQ
+-------------
+
+Do all of the following:
+
+1.     To the extent possible, keep the CPU out of the kernel when it
+       is non-idle, for example, by avoiding system calls and by forcing
+       both kernel threads and interrupts to execute elsewhere.
+2.     Build with CONFIG_HOTPLUG_CPU=y.  After boot completes, force
+       the CPU offline, then bring it back online.  This forces
+       recurring timers to migrate elsewhere.  If you are concerned
+       with multiple CPUs, force them all offline before bringing the
+       first one back online.  Once you have onlined the CPUs in question,
+       do not offline any other CPUs, because doing so could force the
+       timer back onto one of the CPUs in question.
+
+NET_TX_SOFTIRQ and NET_RX_SOFTIRQ
+---------------------------------
+
+Do all of the following:
+
+1.     Force networking interrupts onto other CPUs.
+2.     Initiate any network I/O on other CPUs.
+3.     Once your application has started, prevent CPU-hotplug operations
+       from being initiated from tasks that might run on the CPU to
+       be de-jittered.  (It is OK to force this CPU offline and then
+       bring it back online before you start your application.)
+
+BLOCK_SOFTIRQ
+-------------
+
+Do all of the following:
+
+1.     Force block-device interrupts onto some other CPU.
+2.     Initiate any block I/O on other CPUs.
+3.     Once your application has started, prevent CPU-hotplug operations
+       from being initiated from tasks that might run on the CPU to
+       be de-jittered.  (It is OK to force this CPU offline and then
+       bring it back online before you start your application.)
+
+IRQ_POLL_SOFTIRQ
+----------------
+
+Do all of the following:
+
+1.     Force block-device interrupts onto some other CPU.
+2.     Initiate any block I/O and block-I/O polling on other CPUs.
+3.     Once your application has started, prevent CPU-hotplug operations
+       from being initiated from tasks that might run on the CPU to
+       be de-jittered.  (It is OK to force this CPU offline and then
+       bring it back online before you start your application.)
+
+TASKLET_SOFTIRQ
+---------------
+
+Do one or more of the following:
+
+1.     Avoid use of drivers that use tasklets.  (Such drivers will contain
+       calls to things like tasklet_schedule().)
+2.     Convert all drivers that you must use from tasklets to workqueues.
+3.     Force interrupts for drivers using tasklets onto other CPUs,
+       and also do I/O involving these drivers on other CPUs.
+
+SCHED_SOFTIRQ
+-------------
+
+Do all of the following:
+
+1.     Avoid sending scheduler IPIs to the CPU to be de-jittered,
+       for example, ensure that at most one runnable kthread is present
+       on that CPU.  If a thread that expects to run on the de-jittered
+       CPU awakens, the scheduler will send an IPI that can result in
+       a subsequent SCHED_SOFTIRQ.
+2.     CONFIG_NO_HZ_FULL=y and ensure that the CPU to be de-jittered
+       is marked as an adaptive-ticks CPU using the "nohz_full="
+       boot parameter.  This reduces the number of scheduler-clock
+       interrupts that the de-jittered CPU receives, minimizing its
+       chances of being selected to do the load balancing work that
+       runs in SCHED_SOFTIRQ context.
+3.     To the extent possible, keep the CPU out of the kernel when it
+       is non-idle, for example, by avoiding system calls and by
+       forcing both kernel threads and interrupts to execute elsewhere.
+       This further reduces the number of scheduler-clock interrupts
+       received by the de-jittered CPU.
+
+HRTIMER_SOFTIRQ
+---------------
+
+Do all of the following:
+
+1.     To the extent possible, keep the CPU out of the kernel when it
+       is non-idle.  For example, avoid system calls and force both
+       kernel threads and interrupts to execute elsewhere.
+2.     Build with CONFIG_HOTPLUG_CPU=y.  Once boot completes, force the
+       CPU offline, then bring it back online.  This forces recurring
+       timers to migrate elsewhere.  If you are concerned with multiple
+       CPUs, force them all offline before bringing the first one
+       back online.  Once you have onlined the CPUs in question, do not
+       offline any other CPUs, because doing so could force the timer
+       back onto one of the CPUs in question.
+
+RCU_SOFTIRQ
+-----------
+
+Do at least one of the following:
+
+1.     Offload callbacks and keep the CPU in either dyntick-idle or
+       adaptive-ticks state by doing all of the following:
+
+       a.      CONFIG_NO_HZ_FULL=y and ensure that the CPU to be
+               de-jittered is marked as an adaptive-ticks CPU using the
+               "nohz_full=" boot parameter.  Bind the rcuo kthreads to
+               housekeeping CPUs, which can tolerate OS jitter.
+       b.      To the extent possible, keep the CPU out of the kernel
+               when it is non-idle, for example, by avoiding system
+               calls and by forcing both kernel threads and interrupts
+               to execute elsewhere.
+
+2.     Enable RCU to do its processing remotely via dyntick-idle by
+       doing all of the following:
+
+       a.      Build with CONFIG_NO_HZ=y and CONFIG_RCU_FAST_NO_HZ=y.
+       b.      Ensure that the CPU goes idle frequently, allowing other
+               CPUs to detect that it has passed through an RCU quiescent
+               state.  If the kernel is built with CONFIG_NO_HZ_FULL=y,
+               userspace execution also allows other CPUs to detect that
+               the CPU in question has passed through a quiescent state.
+       c.      To the extent possible, keep the CPU out of the kernel
+               when it is non-idle, for example, by avoiding system
+               calls and by forcing both kernel threads and interrupts
+               to execute elsewhere.
+
+Name:
+  kworker/%u:%d%s (cpu, id, priority)
+
+Purpose:
+  Execute workqueue requests
+
+To reduce its OS jitter, do any of the following:
+
+1.     Run your workload at a real-time priority, which will allow
+       preempting the kworker daemons.
+2.     A given workqueue can be made visible in the sysfs filesystem
+       by passing the WQ_SYSFS to that workqueue's alloc_workqueue().
+       Such a workqueue can be confined to a given subset of the
+       CPUs using the ``/sys/devices/virtual/workqueue/*/cpumask`` sysfs
+       files.  The set of WQ_SYSFS workqueues can be displayed using
+       "ls sys/devices/virtual/workqueue".  That said, the workqueues
+       maintainer would like to caution people against indiscriminately
+       sprinkling WQ_SYSFS across all the workqueues.  The reason for
+       caution is that it is easy to add WQ_SYSFS, but because sysfs is
+       part of the formal user/kernel API, it can be nearly impossible
+       to remove it, even if its addition was a mistake.
+3.     Do any of the following needed to avoid jitter that your
+       application cannot tolerate:
+
+       a.      Build your kernel with CONFIG_SLUB=y rather than
+               CONFIG_SLAB=y, thus avoiding the slab allocator's periodic
+               use of each CPU's workqueues to run its cache_reap()
+               function.
+       b.      Avoid using oprofile, thus avoiding OS jitter from
+               wq_sync_buffer().
+       c.      Limit your CPU frequency so that a CPU-frequency
+               governor is not required, possibly enlisting the aid of
+               special heatsinks or other cooling technologies.  If done
+               correctly, and if you CPU architecture permits, you should
+               be able to build your kernel with CONFIG_CPU_FREQ=n to
+               avoid the CPU-frequency governor periodically running
+               on each CPU, including cs_dbs_timer() and od_dbs_timer().
+
+               WARNING:  Please check your CPU specifications to
+               make sure that this is safe on your particular system.
+       d.      As of v3.18, Christoph Lameter's on-demand vmstat workers
+               commit prevents OS jitter due to vmstat_update() on
+               CONFIG_SMP=y systems.  Before v3.18, is not possible
+               to entirely get rid of the OS jitter, but you can
+               decrease its frequency by writing a large value to
+               /proc/sys/vm/stat_interval.  The default value is HZ,
+               for an interval of one second.  Of course, larger values
+               will make your virtual-memory statistics update more
+               slowly.  Of course, you can also run your workload at
+               a real-time priority, thus preempting vmstat_update(),
+               but if your workload is CPU-bound, this is a bad idea.
+               However, there is an RFC patch from Christoph Lameter
+               (based on an earlier one from Gilad Ben-Yossef) that
+               reduces or even eliminates vmstat overhead for some
+               workloads at https://lkml.org/lkml/2013/9/4/379.
+       e.      Boot with "elevator=noop" to avoid workqueue use by
+               the block layer.
+       f.      If running on high-end powerpc servers, build with
+               CONFIG_PPC_RTAS_DAEMON=n.  This prevents the RTAS
+               daemon from running on each CPU every second or so.
+               (This will require editing Kconfig files and will defeat
+               this platform's RAS functionality.)  This avoids jitter
+               due to the rtas_event_scan() function.
+               WARNING:  Please check your CPU specifications to
+               make sure that this is safe on your particular system.
+       g.      If running on Cell Processor, build your kernel with
+               CBE_CPUFREQ_SPU_GOVERNOR=n to avoid OS jitter from
+               spu_gov_work().
+               WARNING:  Please check your CPU specifications to
+               make sure that this is safe on your particular system.
+       h.      If running on PowerMAC, build your kernel with
+               CONFIG_PMAC_RACKMETER=n to disable the CPU-meter,
+               avoiding OS jitter from rackmeter_do_timer().
+
+Name:
+  rcuc/%u
+
+Purpose:
+  Execute RCU callbacks in CONFIG_RCU_BOOST=y kernels.
+
+To reduce its OS jitter, do at least one of the following:
+
+1.     Build the kernel with CONFIG_PREEMPT=n.  This prevents these
+       kthreads from being created in the first place, and also obviates
+       the need for RCU priority boosting.  This approach is feasible
+       for workloads that do not require high degrees of responsiveness.
+2.     Build the kernel with CONFIG_RCU_BOOST=n.  This prevents these
+       kthreads from being created in the first place.  This approach
+       is feasible only if your workload never requires RCU priority
+       boosting, for example, if you ensure frequent idle time on all
+       CPUs that might execute within the kernel.
+3.     Build with CONFIG_RCU_NOCB_CPU=y and boot with the rcu_nocbs=
+       boot parameter offloading RCU callbacks from all CPUs susceptible
+       to OS jitter.  This approach prevents the rcuc/%u kthreads from
+       having any work to do, so that they are never awakened.
+4.     Ensure that the CPU never enters the kernel, and, in particular,
+       avoid initiating any CPU hotplug operations on this CPU.  This is
+       another way of preventing any callbacks from being queued on the
+       CPU, again preventing the rcuc/%u kthreads from having any work
+       to do.
+
+Name:
+  rcuop/%d and rcuos/%d
+
+Purpose:
+  Offload RCU callbacks from the corresponding CPU.
+
+To reduce its OS jitter, do at least one of the following:
+
+1.     Use affinity, cgroups, or other mechanism to force these kthreads
+       to execute on some other CPU.
+2.     Build with CONFIG_RCU_NOCB_CPU=n, which will prevent these
+       kthreads from being created in the first place.  However, please
+       note that this will not eliminate OS jitter, but will instead
+       shift it to RCU_SOFTIRQ.
+
+Name:
+  watchdog/%u
+
+Purpose:
+  Detect software lockups on each CPU.
+
+To reduce its OS jitter, do at least one of the following:
+
+1.     Build with CONFIG_LOCKUP_DETECTOR=n, which will prevent these
+       kthreads from being created in the first place.
+2.     Boot with "nosoftlockup=0", which will also prevent these kthreads
+       from being created.  Other related watchdog and softlockup boot
+       parameters may be found in Documentation/admin-guide/kernel-parameters.rst
+       and Documentation/watchdog/watchdog-parameters.rst.
+3.     Echo a zero to /proc/sys/kernel/watchdog to disable the
+       watchdog timer.
+4.     Echo a large number of /proc/sys/kernel/watchdog_thresh in
+       order to reduce the frequency of OS jitter due to the watchdog
+       timer down to a level that is acceptable for your workload.
diff --git a/Documentation/admin-guide/laptops/asus-laptop.rst b/Documentation/admin-guide/laptops/asus-laptop.rst
new file mode 100644 (file)
index 0000000..9517632
--- /dev/null
@@ -0,0 +1,271 @@
+==================
+Asus Laptop Extras
+==================
+
+Version 0.1
+
+August 6, 2009
+
+Corentin Chary <corentincj@iksaif.net>
+http://acpi4asus.sf.net/
+
+ This driver provides support for extra features of ACPI-compatible ASUS laptops.
+ It may also support some MEDION, JVC or VICTOR laptops (such as MEDION 9675 or
+ VICTOR XP7210 for example). It makes all the extra buttons generate input
+ events (like keyboards).
+
+ On some models adds support for changing the display brightness and output,
+ switching the LCD backlight on and off, and most importantly, allows you to
+ blink those fancy LEDs intended for reporting mail and wireless status.
+
+This driver supersedes the old asus_acpi driver.
+
+Requirements
+------------
+
+  Kernel 2.6.X sources, configured for your computer, with ACPI support.
+  You also need CONFIG_INPUT and CONFIG_ACPI.
+
+Status
+------
+
+ The features currently supported are the following (see below for
+ detailed description):
+
+ - Fn key combinations
+ - Bluetooth enable and disable
+ - Wlan enable and disable
+ - GPS enable and disable
+ - Video output switching
+ - Ambient Light Sensor on and off
+ - LED control
+ - LED Display control
+ - LCD brightness control
+ - LCD on and off
+
+ A compatibility table by model and feature is maintained on the web
+ site, http://acpi4asus.sf.net/.
+
+Usage
+-----
+
+  Try "modprobe asus-laptop". Check your dmesg (simply type dmesg). You should
+  see some lines like this :
+
+      Asus Laptop Extras version 0.42
+        - L2D model detected.
+
+  If it is not the output you have on your laptop, send it (and the laptop's
+  DSDT) to me.
+
+  That's all, now, all the events generated by the hotkeys of your laptop
+  should be reported via netlink events. You can check with
+  "acpi_genl monitor" (part of the acpica project).
+
+  Hotkeys are also reported as input keys (like keyboards) you can check
+  which key are supported using "xev" under X11.
+
+  You can get information on the version of your DSDT table by reading the
+  /sys/devices/platform/asus-laptop/infos entry. If you have a question or a
+  bug report to do, please include the output of this entry.
+
+LEDs
+----
+
+  You can modify LEDs be echoing values to `/sys/class/leds/asus/*/brightness`::
+
+    echo 1 >  /sys/class/leds/asus::mail/brightness
+
+  will switch the mail LED on.
+
+  You can also know if they are on/off by reading their content and use
+  kernel triggers like disk-activity or heartbeat.
+
+Backlight
+---------
+
+  You can control lcd backlight power and brightness with
+  /sys/class/backlight/asus-laptop/. Brightness Values are between 0 and 15.
+
+Wireless devices
+----------------
+
+  You can turn the internal Bluetooth adapter on/off with the bluetooth entry
+  (only on models with Bluetooth). This usually controls the associated LED.
+  Same for Wlan adapter.
+
+Display switching
+-----------------
+
+  Note: the display switching code is currently considered EXPERIMENTAL.
+
+  Switching works for the following models:
+
+    - L3800C
+    - A2500H
+    - L5800C
+    - M5200N
+    - W1000N (albeit with some glitches)
+    - M6700R
+    - A6JC
+    - F3J
+
+  Switching doesn't work for the following:
+
+    - M3700N
+    - L2X00D (locks the laptop under certain conditions)
+
+  To switch the displays, echo values from 0 to 15 to
+  /sys/devices/platform/asus-laptop/display. The significance of those values
+  is as follows:
+
+  +-------+-----+-----+-----+-----+-----+
+  | Bin   | Val | DVI | TV  | CRT | LCD |
+  +-------+-----+-----+-----+-----+-----+
+  | 0000  |   0 |     |     |     |     |
+  +-------+-----+-----+-----+-----+-----+
+  | 0001  |   1 |     |     |     |  X  |
+  +-------+-----+-----+-----+-----+-----+
+  | 0010  |   2 |     |     |  X  |     |
+  +-------+-----+-----+-----+-----+-----+
+  | 0011  |   3 |     |     |  X  |  X  |
+  +-------+-----+-----+-----+-----+-----+
+  | 0100  |   4 |     |  X  |     |     |
+  +-------+-----+-----+-----+-----+-----+
+  | 0101  |   5 |     |  X  |     | X   |
+  +-------+-----+-----+-----+-----+-----+
+  | 0110  |   6 |     |  X  |  X  |     |
+  +-------+-----+-----+-----+-----+-----+
+  | 0111  |   7 |     |  X  |  X  |  X  |
+  +-------+-----+-----+-----+-----+-----+
+  | 1000  |   8 |  X  |     |     |     |
+  +-------+-----+-----+-----+-----+-----+
+  | 1001  |   9 |  X  |     |     |  X  |
+  +-------+-----+-----+-----+-----+-----+
+  | 1010  |  10 |  X  |     |  X  |     |
+  +-------+-----+-----+-----+-----+-----+
+  | 1011  |  11 |  X  |     |  X  |  X  |
+  +-------+-----+-----+-----+-----+-----+
+  | 1100  |  12 |  X  |  X  |     |     |
+  +-------+-----+-----+-----+-----+-----+
+  | 1101  |  13 |  X  |  X  |     |  X  |
+  +-------+-----+-----+-----+-----+-----+
+  | 1110  |  14 |  X  |  X  |  X  |     |
+  +-------+-----+-----+-----+-----+-----+
+  | 1111  |  15 |  X  |  X  |  X  |  X  |
+  +-------+-----+-----+-----+-----+-----+
+
+  In most cases, the appropriate displays must be plugged in for the above
+  combinations to work. TV-Out may need to be initialized at boot time.
+
+  Debugging:
+
+  1) Check whether the Fn+F8 key:
+
+     a) does not lock the laptop (try a boot with noapic / nolapic if it does)
+     b) generates events (0x6n, where n is the value corresponding to the
+        configuration above)
+     c) actually works
+
+     Record the disp value at every configuration.
+  2) Echo values from 0 to 15 to /sys/devices/platform/asus-laptop/display.
+     Record its value, note any change. If nothing changes, try a broader range,
+     up to 65535.
+  3) Send ANY output (both positive and negative reports are needed, unless your
+     machine is already listed above) to the acpi4asus-user mailing list.
+
+  Note: on some machines (e.g. L3C), after the module has been loaded, only 0x6n
+  events are generated and no actual switching occurs. In such a case, a line
+  like::
+
+    echo $((10#$arg-60)) > /sys/devices/platform/asus-laptop/display
+
+  will usually do the trick ($arg is the 0000006n-like event passed to acpid).
+
+  Note: there is currently no reliable way to read display status on xxN
+  (Centrino) models.
+
+LED display
+-----------
+
+  Some models like the W1N have a LED display that can be used to display
+  several items of information.
+
+  LED display works for the following models:
+
+    - W1000N
+    - W1J
+
+  To control the LED display, use the following::
+
+    echo 0x0T000DDD > /sys/devices/platform/asus-laptop/
+
+  where T control the 3 letters display, and DDD the 3 digits display,
+  according to the tables below::
+
+         DDD (digits)
+         000 to 999 = display digits
+         AAA        = ---
+         BBB to FFF = turn-off
+
+         T  (type)
+         0 = off
+         1 = dvd
+         2 = vcd
+         3 = mp3
+         4 = cd
+         5 = tv
+         6 = cpu
+         7 = vol
+
+  For example "echo 0x01000001 >/sys/devices/platform/asus-laptop/ledd"
+  would display "DVD001".
+
+Driver options
+--------------
+
+ Options can be passed to the asus-laptop driver using the standard
+ module argument syntax (<param>=<value> when passing the option to the
+ module or asus-laptop.<param>=<value> on the kernel boot line when
+ asus-laptop is statically linked into the kernel).
+
+            wapf: WAPF defines the behavior of the Fn+Fx wlan key
+                  The significance of values is yet to be found, but
+                  most of the time:
+
+                  - 0x0 should do nothing
+                  - 0x1 should allow to control the device with Fn+Fx key.
+                  - 0x4 should send an ACPI event (0x88) while pressing the Fn+Fx key
+                  - 0x5 like 0x1 or 0x4
+
+ The default value is 0x1.
+
+Unsupported models
+------------------
+
+ These models will never be supported by this module, as they use a completely
+ different mechanism to handle LEDs and extra stuff (meaning we have no clue
+ how it works):
+
+ - ASUS A1300 (A1B), A1370D
+ - ASUS L7300G
+ - ASUS L8400
+
+Patches, Errors, Questions
+--------------------------
+
+ I appreciate any success or failure
+ reports, especially if they add to or correct the compatibility table.
+ Please include the following information in your report:
+
+ - Asus model name
+ - a copy of your ACPI tables, using the "acpidump" utility
+ - a copy of /sys/devices/platform/asus-laptop/infos
+ - which driver features work and which don't
+ - the observed behavior of non-working features
+
+ Any other comments or patches are also more than welcome.
+
+ acpi4asus-user@lists.sourceforge.net
+
+ http://sourceforge.net/projects/acpi4asus
diff --git a/Documentation/admin-guide/laptops/disk-shock-protection.rst b/Documentation/admin-guide/laptops/disk-shock-protection.rst
new file mode 100644 (file)
index 0000000..e97c5f7
--- /dev/null
@@ -0,0 +1,151 @@
+==========================
+Hard disk shock protection
+==========================
+
+Author: Elias Oltmanns <eo@nebensachen.de>
+
+Last modified: 2008-10-03
+
+
+.. 0. Contents
+
+   1. Intro
+   2. The interface
+   3. References
+   4. CREDITS
+
+
+1. Intro
+--------
+
+ATA/ATAPI-7 specifies the IDLE IMMEDIATE command with unload feature.
+Issuing this command should cause the drive to switch to idle mode and
+unload disk heads. This feature is being used in modern laptops in
+conjunction with accelerometers and appropriate software to implement
+a shock protection facility. The idea is to stop all I/O operations on
+the internal hard drive and park its heads on the ramp when critical
+situations are anticipated. The desire to have such a feature
+available on GNU/Linux systems has been the original motivation to
+implement a generic disk head parking interface in the Linux kernel.
+Please note, however, that other components have to be set up on your
+system in order to get disk shock protection working (see
+section 3. References below for pointers to more information about
+that).
+
+
+2. The interface
+----------------
+
+For each ATA device, the kernel exports the file
+`block/*/device/unload_heads` in sysfs (here assumed to be mounted under
+/sys). Access to `/sys/block/*/device/unload_heads` is denied with
+-EOPNOTSUPP if the device does not support the unload feature.
+Otherwise, writing an integer value to this file will take the heads
+of the respective drive off the platter and block all I/O operations
+for the specified number of milliseconds. When the timeout expires and
+no further disk head park request has been issued in the meantime,
+normal operation will be resumed. The maximal value accepted for a
+timeout is 30000 milliseconds. Exceeding this limit will return
+-EOVERFLOW, but heads will be parked anyway and the timeout will be
+set to 30 seconds. However, you can always change a timeout to any
+value between 0 and 30000 by issuing a subsequent head park request
+before the timeout of the previous one has expired. In particular, the
+total timeout can exceed 30 seconds and, more importantly, you can
+cancel a previously set timeout and resume normal operation
+immediately by specifying a timeout of 0. Values below -2 are rejected
+with -EINVAL (see below for the special meaning of -1 and -2). If the
+timeout specified for a recent head park request has not yet expired,
+reading from `/sys/block/*/device/unload_heads` will report the number
+of milliseconds remaining until normal operation will be resumed;
+otherwise, reading the unload_heads attribute will return 0.
+
+For example, do the following in order to park the heads of drive
+/dev/sda and stop all I/O operations for five seconds::
+
+       # echo 5000 > /sys/block/sda/device/unload_heads
+
+A simple::
+
+       # cat /sys/block/sda/device/unload_heads
+
+will show you how many milliseconds are left before normal operation
+will be resumed.
+
+A word of caution: The fact that the interface operates on a basis of
+milliseconds may raise expectations that cannot be satisfied in
+reality. In fact, the ATA specs clearly state that the time for an
+unload operation to complete is vendor specific. The hint in ATA-7
+that this will typically be within 500 milliseconds apparently has
+been dropped in ATA-8.
+
+There is a technical detail of this implementation that may cause some
+confusion and should be discussed here. When a head park request has
+been issued to a device successfully, all I/O operations on the
+controller port this device is attached to will be deferred. That is
+to say, any other device that may be connected to the same port will
+be affected too. The only exception is that a subsequent head unload
+request to that other device will be executed immediately. Further
+operations on that port will be deferred until the timeout specified
+for either device on the port has expired. As far as PATA (old style
+IDE) configurations are concerned, there can only be two devices
+attached to any single port. In SATA world we have port multipliers
+which means that a user-issued head parking request to one device may
+actually result in stopping I/O to a whole bunch of devices. However,
+since this feature is supposed to be used on laptops and does not seem
+to be very useful in any other environment, there will be mostly one
+device per port. Even if the CD/DVD writer happens to be connected to
+the same port as the hard drive, it generally *should* recover just
+fine from the occasional buffer under-run incurred by a head park
+request to the HD. Actually, when you are using an ide driver rather
+than its libata counterpart (i.e. your disk is called /dev/hda
+instead of /dev/sda), then parking the heads of one drive (drive X)
+will generally not affect the mode of operation of another drive
+(drive Y) on the same port as described above. It is only when a port
+reset is required to recover from an exception on drive Y that further
+I/O operations on that drive (and the reset itself) will be delayed
+until drive X is no longer in the parked state.
+
+Finally, there are some hard drives that only comply with an earlier
+version of the ATA standard than ATA-7, but do support the unload
+feature nonetheless. Unfortunately, there is no safe way Linux can
+detect these devices, so you won't be able to write to the
+unload_heads attribute. If you know that your device really does
+support the unload feature (for instance, because the vendor of your
+laptop or the hard drive itself told you so), then you can tell the
+kernel to enable the usage of this feature for that drive by writing
+the special value -1 to the unload_heads attribute::
+
+       # echo -1 > /sys/block/sda/device/unload_heads
+
+will enable the feature for /dev/sda, and giving -2 instead of -1 will
+disable it again.
+
+
+3. References
+-------------
+
+There are several laptops from different vendors featuring shock
+protection capabilities. As manufacturers have refused to support open
+source development of the required software components so far, Linux
+support for shock protection varies considerably between different
+hardware implementations. Ideally, this section should contain a list
+of pointers at different projects aiming at an implementation of shock
+protection on different systems. Unfortunately, I only know of a
+single project which, although still considered experimental, is fit
+for use. Please feel free to add projects that have been the victims
+of my ignorance.
+
+- http://www.thinkwiki.org/wiki/HDAPS
+
+  See this page for information about Linux support of the hard disk
+  active protection system as implemented in IBM/Lenovo Thinkpads.
+
+
+4. CREDITS
+----------
+
+This implementation of disk head parking has been inspired by a patch
+originally published by Jon Escombe <lists@dresco.co.uk>. My efforts
+to develop an implementation of this feature that is fit to be merged
+into mainline have been aided by various kernel developers, in
+particular by Tejun Heo and Bartlomiej Zolnierkiewicz.
diff --git a/Documentation/admin-guide/laptops/index.rst b/Documentation/admin-guide/laptops/index.rst
new file mode 100644 (file)
index 0000000..cd9a1c2
--- /dev/null
@@ -0,0 +1,17 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==============
+Laptop Drivers
+==============
+
+.. toctree::
+   :maxdepth: 1
+
+   asus-laptop
+   disk-shock-protection
+   laptop-mode
+   lg-laptop
+   sony-laptop
+   sonypi
+   thinkpad-acpi
+   toshiba_haps
diff --git a/Documentation/admin-guide/laptops/laptop-mode.rst b/Documentation/admin-guide/laptops/laptop-mode.rst
new file mode 100644 (file)
index 0000000..c984c42
--- /dev/null
@@ -0,0 +1,781 @@
+===============================================
+How to conserve battery power using laptop-mode
+===============================================
+
+Document Author: Bart Samwel (bart@samwel.tk)
+
+Date created: January 2, 2004
+
+Last modified: December 06, 2004
+
+Introduction
+------------
+
+Laptop mode is used to minimize the time that the hard disk needs to be spun up,
+to conserve battery power on laptops. It has been reported to cause significant
+power savings.
+
+.. Contents
+
+   * Introduction
+   * Installation
+   * Caveats
+   * The Details
+   * Tips & Tricks
+   * Control script
+   * ACPI integration
+   * Monitoring tool
+
+
+Installation
+------------
+
+To use laptop mode, you don't need to set any kernel configuration options
+or anything. Simply install all the files included in this document, and
+laptop mode will automatically be started when you're on battery. For
+your convenience, a tarball containing an installer can be downloaded at:
+
+       http://www.samwel.tk/laptop_mode/laptop_mode/
+
+To configure laptop mode, you need to edit the configuration file, which is
+located in /etc/default/laptop-mode on Debian-based systems, or in
+/etc/sysconfig/laptop-mode on other systems.
+
+Unfortunately, automatic enabling of laptop mode does not work for
+laptops that don't have ACPI. On those laptops, you need to start laptop
+mode manually. To start laptop mode, run "laptop_mode start", and to
+stop it, run "laptop_mode stop". (Note: The laptop mode tools package now
+has experimental support for APM, you might want to try that first.)
+
+
+Caveats
+-------
+
+* The downside of laptop mode is that you have a chance of losing up to 10
+  minutes of work. If you cannot afford this, don't use it! The supplied ACPI
+  scripts automatically turn off laptop mode when the battery almost runs out,
+  so that you won't lose any data at the end of your battery life.
+
+* Most desktop hard drives have a very limited lifetime measured in spindown
+  cycles, typically about 50.000 times (it's usually listed on the spec sheet).
+  Check your drive's rating, and don't wear down your drive's lifetime if you
+  don't need to.
+
+* If you mount some of your ext3/reiserfs filesystems with the -n option, then
+  the control script will not be able to remount them correctly. You must set
+  DO_REMOUNTS=0 in the control script, otherwise it will remount them with the
+  wrong options -- or it will fail because it cannot write to /etc/mtab.
+
+* If you have your filesystems listed as type "auto" in fstab, like I did, then
+  the control script will not recognize them as filesystems that need remounting.
+  You must list the filesystems with their true type instead.
+
+* It has been reported that some versions of the mutt mail client use file access
+  times to determine whether a folder contains new mail. If you use mutt and
+  experience this, you must disable the noatime remounting by setting the option
+  DO_REMOUNT_NOATIME to 0 in the configuration file.
+
+
+The Details
+-----------
+
+Laptop mode is controlled by the knob /proc/sys/vm/laptop_mode. This knob is
+present for all kernels that have the laptop mode patch, regardless of any
+configuration options. When the knob is set, any physical disk I/O (that might
+have caused the hard disk to spin up) causes Linux to flush all dirty blocks. The
+result of this is that after a disk has spun down, it will not be spun up
+anymore to write dirty blocks, because those blocks had already been written
+immediately after the most recent read operation. The value of the laptop_mode
+knob determines the time between the occurrence of disk I/O and when the flush
+is triggered. A sensible value for the knob is 5 seconds. Setting the knob to
+0 disables laptop mode.
+
+To increase the effectiveness of the laptop_mode strategy, the laptop_mode
+control script increases dirty_expire_centisecs and dirty_writeback_centisecs in
+/proc/sys/vm to about 10 minutes (by default), which means that pages that are
+dirtied are not forced to be written to disk as often. The control script also
+changes the dirty background ratio, so that background writeback of dirty pages
+is not done anymore. Combined with a higher commit value (also 10 minutes) for
+ext3 or ReiserFS filesystems (also done automatically by the control script),
+this results in concentration of disk activity in a small time interval which
+occurs only once every 10 minutes, or whenever the disk is forced to spin up by
+a cache miss. The disk can then be spun down in the periods of inactivity.
+
+If you want to find out which process caused the disk to spin up, you can
+gather information by setting the flag /proc/sys/vm/block_dump. When this flag
+is set, Linux reports all disk read and write operations that take place, and
+all block dirtyings done to files. This makes it possible to debug why a disk
+needs to spin up, and to increase battery life even more. The output of
+block_dump is written to the kernel output, and it can be retrieved using
+"dmesg". When you use block_dump and your kernel logging level also includes
+kernel debugging messages, you probably want to turn off klogd, otherwise
+the output of block_dump will be logged, causing disk activity that is not
+normally there.
+
+
+Configuration
+-------------
+
+The laptop mode configuration file is located in /etc/default/laptop-mode on
+Debian-based systems, or in /etc/sysconfig/laptop-mode on other systems. It
+contains the following options:
+
+MAX_AGE:
+
+Maximum time, in seconds, of hard drive spindown time that you are
+comfortable with. Worst case, it's possible that you could lose this
+amount of work if your battery fails while you're in laptop mode.
+
+MINIMUM_BATTERY_MINUTES:
+
+Automatically disable laptop mode if the remaining number of minutes of
+battery power is less than this value. Default is 10 minutes.
+
+AC_HD/BATT_HD:
+
+The idle timeout that should be set on your hard drive when laptop mode
+is active (BATT_HD) and when it is not active (AC_HD). The defaults are
+20 seconds (value 4) for BATT_HD  and 2 hours (value 244) for AC_HD. The
+possible values are those listed in the manual page for "hdparm" for the
+"-S" option.
+
+HD:
+
+The devices for which the spindown timeout should be adjusted by laptop mode.
+Default is /dev/hda. If you specify multiple devices, separate them by a space.
+
+READAHEAD:
+
+Disk readahead, in 512-byte sectors, while laptop mode is active. A large
+readahead can prevent disk accesses for things like executable pages (which are
+loaded on demand while the application executes) and sequentially accessed data
+(MP3s).
+
+DO_REMOUNTS:
+
+The control script automatically remounts any mounted journaled filesystems
+with appropriate commit interval options. When this option is set to 0, this
+feature is disabled.
+
+DO_REMOUNT_NOATIME:
+
+When remounting, should the filesystems be remounted with the noatime option?
+Normally, this is set to "1" (enabled), but there may be programs that require
+access time recording.
+
+DIRTY_RATIO:
+
+The percentage of memory that is allowed to contain "dirty" or unsaved data
+before a writeback is forced, while laptop mode is active. Corresponds to
+the /proc/sys/vm/dirty_ratio sysctl.
+
+DIRTY_BACKGROUND_RATIO:
+
+The percentage of memory that is allowed to contain "dirty" or unsaved data
+after a forced writeback is done due to an exceeding of DIRTY_RATIO. Set
+this nice and low. This corresponds to the /proc/sys/vm/dirty_background_ratio
+sysctl.
+
+Note that the behaviour of dirty_background_ratio is quite different
+when laptop mode is active and when it isn't. When laptop mode is inactive,
+dirty_background_ratio is the threshold percentage at which background writeouts
+start taking place. When laptop mode is active, however, background writeouts
+are disabled, and the dirty_background_ratio only determines how much writeback
+is done when dirty_ratio is reached.
+
+DO_CPU:
+
+Enable CPU frequency scaling when in laptop mode. (Requires CPUFreq to be setup.
+See Documentation/admin-guide/pm/cpufreq.rst for more info. Disabled by default.)
+
+CPU_MAXFREQ:
+
+When on battery, what is the maximum CPU speed that the system should use? Legal
+values are "slowest" for the slowest speed that your CPU is able to operate at,
+or a value listed in /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies.
+
+
+Tips & Tricks
+-------------
+
+* Bartek Kania reports getting up to 50 minutes of extra battery life (on top
+  of his regular 3 to 3.5 hours) using a spindown time of 5 seconds (BATT_HD=1).
+
+* You can spin down the disk while playing MP3, by setting disk readahead
+  to 8MB (READAHEAD=16384). Effectively, the disk will read a complete MP3 at
+  once, and will then spin down while the MP3 is playing. (Thanks to Bartek
+  Kania.)
+
+* Drew Scott Daniels observed: "I don't know why, but when I decrease the number
+  of colours that my display uses it consumes less battery power. I've seen
+  this on powerbooks too. I hope that this is a piece of information that
+  might be useful to the Laptop Mode patch or its users."
+
+* In syslog.conf, you can prefix entries with a dash `-` to omit syncing the
+  file after every logging. When you're using laptop-mode and your disk doesn't
+  spin down, this is a likely culprit.
+
+* Richard Atterer observed that laptop mode does not work well with noflushd
+  (http://noflushd.sourceforge.net/), it seems that noflushd prevents laptop-mode
+  from doing its thing.
+
+* If you're worried about your data, you might want to consider using a USB
+  memory stick or something like that as a "working area". (Be aware though
+  that flash memory can only handle a limited number of writes, and overuse
+  may wear out your memory stick pretty quickly. Do _not_ use journalling
+  filesystems on flash memory sticks.)
+
+
+Configuration file for control and ACPI battery scripts
+-------------------------------------------------------
+
+This allows the tunables to be changed for the scripts via an external
+configuration file
+
+It should be installed as /etc/default/laptop-mode on Debian, and as
+/etc/sysconfig/laptop-mode on Red Hat, SUSE, Mandrake, and other work-alikes.
+
+Config file::
+
+  # Maximum time, in seconds, of hard drive spindown time that you are
+  # comfortable with. Worst case, it's possible that you could lose this
+  # amount of work if your battery fails you while in laptop mode.
+  #MAX_AGE=600
+
+  # Automatically disable laptop mode when the number of minutes of battery
+  # that you have left goes below this threshold.
+  MINIMUM_BATTERY_MINUTES=10
+
+  # Read-ahead, in 512-byte sectors. You can spin down the disk while playing MP3/OGG
+  # by setting the disk readahead to 8MB (READAHEAD=16384). Effectively, the disk
+  # will read a complete MP3 at once, and will then spin down while the MP3/OGG is
+  # playing.
+  #READAHEAD=4096
+
+  # Shall we remount journaled fs. with appropriate commit interval? (1=yes)
+  #DO_REMOUNTS=1
+
+  # And shall we add the "noatime" option to that as well? (1=yes)
+  #DO_REMOUNT_NOATIME=1
+
+  # Dirty synchronous ratio.  At this percentage of dirty pages the process
+  # which
+  # calls write() does its own writeback
+  #DIRTY_RATIO=40
+
+  #
+  # Allowed dirty background ratio, in percent.  Once DIRTY_RATIO has been
+  # exceeded, the kernel will wake flusher threads which will then reduce the
+  # amount of dirty memory to dirty_background_ratio.  Set this nice and low,
+  # so once some writeout has commenced, we do a lot of it.
+  #
+  #DIRTY_BACKGROUND_RATIO=5
+
+  # kernel default dirty buffer age
+  #DEF_AGE=30
+  #DEF_UPDATE=5
+  #DEF_DIRTY_BACKGROUND_RATIO=10
+  #DEF_DIRTY_RATIO=40
+  #DEF_XFS_AGE_BUFFER=15
+  #DEF_XFS_SYNC_INTERVAL=30
+  #DEF_XFS_BUFD_INTERVAL=1
+
+  # This must be adjusted manually to the value of HZ in the running kernel
+  # on 2.4, until the XFS people change their 2.4 external interfaces to work in
+  # centisecs. This can be automated, but it's a work in progress that still
+  # needs# some fixes. On 2.6 kernels, XFS uses USER_HZ instead of HZ for
+  # external interfaces, and that is currently always set to 100. So you don't
+  # need to change this on 2.6.
+  #XFS_HZ=100
+
+  # Should the maximum CPU frequency be adjusted down while on battery?
+  # Requires CPUFreq to be setup.
+  # See Documentation/admin-guide/pm/cpufreq.rst for more info
+  #DO_CPU=0
+
+  # When on battery what is the maximum CPU speed that the system should
+  # use? Legal values are "slowest" for the slowest speed that your
+  # CPU is able to operate at, or a value listed in:
+  # /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies
+  # Only applicable if DO_CPU=1.
+  #CPU_MAXFREQ=slowest
+
+  # Idle timeout for your hard drive (man hdparm for valid values, -S option)
+  # Default is 2 hours on AC (AC_HD=244) and 20 seconds for battery (BATT_HD=4).
+  #AC_HD=244
+  #BATT_HD=4
+
+  # The drives for which to adjust the idle timeout. Separate them by a space,
+  # e.g. HD="/dev/hda /dev/hdb".
+  #HD="/dev/hda"
+
+  # Set the spindown timeout on a hard drive?
+  #DO_HD=1
+
+
+Control script
+--------------
+
+Please note that this control script works for the Linux 2.4 and 2.6 series (thanks
+to Kiko Piris).
+
+Control script::
+
+  #!/bin/bash
+
+  # start or stop laptop_mode, best run by a power management daemon when
+  # ac gets connected/disconnected from a laptop
+  #
+  # install as /sbin/laptop_mode
+  #
+  # Contributors to this script:   Kiko Piris
+  #                             Bart Samwel
+  #                             Micha Feigin
+  #                             Andrew Morton
+  #                             Herve Eychenne
+  #                             Dax Kelson
+  #
+  # Original Linux 2.4 version by: Jens Axboe
+
+  #############################################################################
+
+  # Source config
+  if [ -f /etc/default/laptop-mode ] ; then
+       # Debian
+       . /etc/default/laptop-mode
+  elif [ -f /etc/sysconfig/laptop-mode ] ; then
+       # Others
+          . /etc/sysconfig/laptop-mode
+  fi
+
+  # Don't raise an error if the config file is incomplete
+  # set defaults instead:
+
+  # Maximum time, in seconds, of hard drive spindown time that you are
+  # comfortable with. Worst case, it's possible that you could lose this
+  # amount of work if your battery fails you while in laptop mode.
+  MAX_AGE=${MAX_AGE:-'600'}
+
+  # Read-ahead, in kilobytes
+  READAHEAD=${READAHEAD:-'4096'}
+
+  # Shall we remount journaled fs. with appropriate commit interval? (1=yes)
+  DO_REMOUNTS=${DO_REMOUNTS:-'1'}
+
+  # And shall we add the "noatime" option to that as well? (1=yes)
+  DO_REMOUNT_NOATIME=${DO_REMOUNT_NOATIME:-'1'}
+
+  # Shall we adjust the idle timeout on a hard drive?
+  DO_HD=${DO_HD:-'1'}
+
+  # Adjust idle timeout on which hard drive?
+  HD="${HD:-'/dev/hda'}"
+
+  # spindown time for HD (hdparm -S values)
+  AC_HD=${AC_HD:-'244'}
+  BATT_HD=${BATT_HD:-'4'}
+
+  # Dirty synchronous ratio.  At this percentage of dirty pages the process which
+  # calls write() does its own writeback
+  DIRTY_RATIO=${DIRTY_RATIO:-'40'}
+
+  # cpu frequency scaling
+  # See Documentation/admin-guide/pm/cpufreq.rst for more info
+  DO_CPU=${CPU_MANAGE:-'0'}
+  CPU_MAXFREQ=${CPU_MAXFREQ:-'slowest'}
+
+  #
+  # Allowed dirty background ratio, in percent.  Once DIRTY_RATIO has been
+  # exceeded, the kernel will wake flusher threads which will then reduce the
+  # amount of dirty memory to dirty_background_ratio.  Set this nice and low,
+  # so once some writeout has commenced, we do a lot of it.
+  #
+  DIRTY_BACKGROUND_RATIO=${DIRTY_BACKGROUND_RATIO:-'5'}
+
+  # kernel default dirty buffer age
+  DEF_AGE=${DEF_AGE:-'30'}
+  DEF_UPDATE=${DEF_UPDATE:-'5'}
+  DEF_DIRTY_BACKGROUND_RATIO=${DEF_DIRTY_BACKGROUND_RATIO:-'10'}
+  DEF_DIRTY_RATIO=${DEF_DIRTY_RATIO:-'40'}
+  DEF_XFS_AGE_BUFFER=${DEF_XFS_AGE_BUFFER:-'15'}
+  DEF_XFS_SYNC_INTERVAL=${DEF_XFS_SYNC_INTERVAL:-'30'}
+  DEF_XFS_BUFD_INTERVAL=${DEF_XFS_BUFD_INTERVAL:-'1'}
+
+  # This must be adjusted manually to the value of HZ in the running kernel
+  # on 2.4, until the XFS people change their 2.4 external interfaces to work in
+  # centisecs. This can be automated, but it's a work in progress that still needs
+  # some fixes. On 2.6 kernels, XFS uses USER_HZ instead of HZ for external
+  # interfaces, and that is currently always set to 100. So you don't need to
+  # change this on 2.6.
+  XFS_HZ=${XFS_HZ:-'100'}
+
+  #############################################################################
+
+  KLEVEL="$(uname -r |
+               {
+              IFS='.' read a b c
+              echo $a.$b
+            }
+  )"
+  case "$KLEVEL" in
+       "2.4"|"2.6")
+               ;;
+       *)
+               echo "Unhandled kernel version: $KLEVEL ('uname -r' = '$(uname -r)')" >&2
+               exit 1
+               ;;
+  esac
+
+  if [ ! -e /proc/sys/vm/laptop_mode ] ; then
+       echo "Kernel is not patched with laptop_mode patch." >&2
+       exit 1
+  fi
+
+  if [ ! -w /proc/sys/vm/laptop_mode ] ; then
+       echo "You do not have enough privileges to enable laptop_mode." >&2
+       exit 1
+  fi
+
+  # Remove an option (the first parameter) of the form option=<number> from
+  # a mount options string (the rest of the parameters).
+  parse_mount_opts () {
+       OPT="$1"
+       shift
+       echo ",$*," | sed               \
+        -e 's/,'"$OPT"'=[0-9]*,/,/g'   \
+        -e 's/,,*/,/g'                 \
+        -e 's/^,//'                    \
+        -e 's/,$//'
+  }
+
+  # Remove an option (the first parameter) without any arguments from
+  # a mount option string (the rest of the parameters).
+  parse_nonumber_mount_opts () {
+       OPT="$1"
+       shift
+       echo ",$*," | sed               \
+        -e 's/,'"$OPT"',/,/g'          \
+        -e 's/,,*/,/g'                 \
+        -e 's/^,//'                    \
+        -e 's/,$//'
+  }
+
+  # Find out the state of a yes/no option (e.g. "atime"/"noatime") in
+  # fstab for a given filesystem, and use this state to replace the
+  # value of the option in another mount options string. The device
+  # is the first argument, the option name the second, and the default
+  # value the third. The remainder is the mount options string.
+  #
+  # Example:
+  # parse_yesno_opts_wfstab /dev/hda1 atime atime defaults,noatime
+  #
+  # If fstab contains, say, "rw" for this filesystem, then the result
+  # will be "defaults,atime".
+  parse_yesno_opts_wfstab () {
+       L_DEV="$1"
+       OPT="$2"
+       DEF_OPT="$3"
+       shift 3
+       L_OPTS="$*"
+       PARSEDOPTS1="$(parse_nonumber_mount_opts $OPT $L_OPTS)"
+       PARSEDOPTS1="$(parse_nonumber_mount_opts no$OPT $PARSEDOPTS1)"
+       # Watch for a default atime in fstab
+       FSTAB_OPTS="$(awk '$1 == "'$L_DEV'" { print $4 }' /etc/fstab)"
+       if echo "$FSTAB_OPTS" | grep "$OPT" > /dev/null ; then
+               # option specified in fstab: extract the value and use it
+               if echo "$FSTAB_OPTS" | grep "no$OPT" > /dev/null ; then
+                       echo "$PARSEDOPTS1,no$OPT"
+               else
+                       # no$OPT not found -- so we must have $OPT.
+                       echo "$PARSEDOPTS1,$OPT"
+               fi
+       else
+               # option not specified in fstab -- choose the default.
+               echo "$PARSEDOPTS1,$DEF_OPT"
+       fi
+  }
+
+  # Find out the state of a numbered option (e.g. "commit=NNN") in
+  # fstab for a given filesystem, and use this state to replace the
+  # value of the option in another mount options string. The device
+  # is the first argument, and the option name the second. The
+  # remainder is the mount options string in which the replacement
+  # must be done.
+  #
+  # Example:
+  # parse_mount_opts_wfstab /dev/hda1 commit defaults,commit=7
+  #
+  # If fstab contains, say, "commit=3,rw" for this filesystem, then the
+  # result will be "rw,commit=3".
+  parse_mount_opts_wfstab () {
+       L_DEV="$1"
+       OPT="$2"
+       shift 2
+       L_OPTS="$*"
+       PARSEDOPTS1="$(parse_mount_opts $OPT $L_OPTS)"
+       # Watch for a default commit in fstab
+       FSTAB_OPTS="$(awk '$1 == "'$L_DEV'" { print $4 }' /etc/fstab)"
+       if echo "$FSTAB_OPTS" | grep "$OPT=" > /dev/null ; then
+               # option specified in fstab: extract the value, and use it
+               echo -n "$PARSEDOPTS1,$OPT="
+               echo ",$FSTAB_OPTS," | sed \
+                -e 's/.*,'"$OPT"'=//'  \
+                -e 's/,.*//'
+       else
+               # option not specified in fstab: set it to 0
+               echo "$PARSEDOPTS1,$OPT=0"
+       fi
+  }
+
+  deduce_fstype () {
+       MP="$1"
+       # My root filesystem unfortunately has
+       # type "unknown" in /etc/mtab. If we encounter
+       # "unknown", we try to get the type from fstab.
+       cat /etc/fstab |
+       grep -v '^#' |
+       while read FSTAB_DEV FSTAB_MP FSTAB_FST FSTAB_OPTS FSTAB_DUMP FSTAB_DUMP ; do
+               if [ "$FSTAB_MP" = "$MP" ]; then
+                       echo $FSTAB_FST
+                       exit 0
+               fi
+       done
+  }
+
+  if [ $DO_REMOUNT_NOATIME -eq 1 ] ; then
+       NOATIME_OPT=",noatime"
+  fi
+
+  case "$1" in
+       start)
+               AGE=$((100*$MAX_AGE))
+               XFS_AGE=$(($XFS_HZ*$MAX_AGE))
+               echo -n "Starting laptop_mode"
+
+               if [ -d /proc/sys/vm/pagebuf ] ; then
+                       # (For 2.4 and early 2.6.)
+                       # This only needs to be set, not reset -- it is only used when
+                       # laptop mode is enabled.
+                       echo $XFS_AGE > /proc/sys/vm/pagebuf/lm_flush_age
+                       echo $XFS_AGE > /proc/sys/fs/xfs/lm_sync_interval
+               elif [ -f /proc/sys/fs/xfs/lm_age_buffer ] ; then
+                       # (A couple of early 2.6 laptop mode patches had these.)
+                       # The same goes for these.
+                       echo $XFS_AGE > /proc/sys/fs/xfs/lm_age_buffer
+                       echo $XFS_AGE > /proc/sys/fs/xfs/lm_sync_interval
+               elif [ -f /proc/sys/fs/xfs/age_buffer ] ; then
+                       # (2.6.6)
+                       # But not for these -- they are also used in normal
+                       # operation.
+                       echo $XFS_AGE > /proc/sys/fs/xfs/age_buffer
+                       echo $XFS_AGE > /proc/sys/fs/xfs/sync_interval
+               elif [ -f /proc/sys/fs/xfs/age_buffer_centisecs ] ; then
+                       # (2.6.7 upwards)
+                       # And not for these either. These are in centisecs,
+                       # not USER_HZ, so we have to use $AGE, not $XFS_AGE.
+                       echo $AGE > /proc/sys/fs/xfs/age_buffer_centisecs
+                       echo $AGE > /proc/sys/fs/xfs/xfssyncd_centisecs
+                       echo 3000 > /proc/sys/fs/xfs/xfsbufd_centisecs
+               fi
+
+               case "$KLEVEL" in
+                       "2.4")
+                               echo 1                                  > /proc/sys/vm/laptop_mode
+                               echo "30 500 0 0 $AGE $AGE 60 20 0"     > /proc/sys/vm/bdflush
+                               ;;
+                       "2.6")
+                               echo 5                                  > /proc/sys/vm/laptop_mode
+                               echo "$AGE"                             > /proc/sys/vm/dirty_writeback_centisecs
+                               echo "$AGE"                             > /proc/sys/vm/dirty_expire_centisecs
+                               echo "$DIRTY_RATIO"                     > /proc/sys/vm/dirty_ratio
+                               echo "$DIRTY_BACKGROUND_RATIO"          > /proc/sys/vm/dirty_background_ratio
+                               ;;
+               esac
+               if [ $DO_REMOUNTS -eq 1 ]; then
+                       cat /etc/mtab | while read DEV MP FST OPTS DUMP PASS ; do
+                               PARSEDOPTS="$(parse_mount_opts "$OPTS")"
+                               if [ "$FST" = 'unknown' ]; then
+                                       FST=$(deduce_fstype $MP)
+                               fi
+                               case "$FST" in
+                                       "ext3"|"reiserfs")
+                                               PARSEDOPTS="$(parse_mount_opts commit "$OPTS")"
+                                               mount $DEV -t $FST $MP -o remount,$PARSEDOPTS,commit=$MAX_AGE$NOATIME_OPT
+                                               ;;
+                                       "xfs")
+                                               mount $DEV -t $FST $MP -o remount,$OPTS$NOATIME_OPT
+                                               ;;
+                               esac
+                               if [ -b $DEV ] ; then
+                                       blockdev --setra $(($READAHEAD * 2)) $DEV
+                               fi
+                       done
+               fi
+               if [ $DO_HD -eq 1 ] ; then
+                       for THISHD in $HD ; do
+                               /sbin/hdparm -S $BATT_HD $THISHD > /dev/null 2>&1
+                               /sbin/hdparm -B 1 $THISHD > /dev/null 2>&1
+                       done
+               fi
+               if [ $DO_CPU -eq 1 -a -e /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq ]; then
+                       if [ $CPU_MAXFREQ = 'slowest' ]; then
+                               CPU_MAXFREQ=`cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq`
+                       fi
+                       echo $CPU_MAXFREQ > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
+               fi
+               echo "."
+               ;;
+       stop)
+               U_AGE=$((100*$DEF_UPDATE))
+               B_AGE=$((100*$DEF_AGE))
+               echo -n "Stopping laptop_mode"
+               echo 0 > /proc/sys/vm/laptop_mode
+               if [ -f /proc/sys/fs/xfs/age_buffer -a ! -f /proc/sys/fs/xfs/lm_age_buffer ] ; then
+                       # These need to be restored, if there are no lm_*.
+                       echo $(($XFS_HZ*$DEF_XFS_AGE_BUFFER))           > /proc/sys/fs/xfs/age_buffer
+                       echo $(($XFS_HZ*$DEF_XFS_SYNC_INTERVAL))        > /proc/sys/fs/xfs/sync_interval
+               elif [ -f /proc/sys/fs/xfs/age_buffer_centisecs ] ; then
+                       # These need to be restored as well.
+                       echo $((100*$DEF_XFS_AGE_BUFFER))       > /proc/sys/fs/xfs/age_buffer_centisecs
+                       echo $((100*$DEF_XFS_SYNC_INTERVAL))    > /proc/sys/fs/xfs/xfssyncd_centisecs
+                       echo $((100*$DEF_XFS_BUFD_INTERVAL))    > /proc/sys/fs/xfs/xfsbufd_centisecs
+               fi
+               case "$KLEVEL" in
+                       "2.4")
+                               echo "30 500 0 0 $U_AGE $B_AGE 60 20 0" > /proc/sys/vm/bdflush
+                               ;;
+                       "2.6")
+                               echo "$U_AGE"                           > /proc/sys/vm/dirty_writeback_centisecs
+                               echo "$B_AGE"                           > /proc/sys/vm/dirty_expire_centisecs
+                               echo "$DEF_DIRTY_RATIO"                 > /proc/sys/vm/dirty_ratio
+                               echo "$DEF_DIRTY_BACKGROUND_RATIO"      > /proc/sys/vm/dirty_background_ratio
+                               ;;
+               esac
+               if [ $DO_REMOUNTS -eq 1 ] ; then
+                       cat /etc/mtab | while read DEV MP FST OPTS DUMP PASS ; do
+                               # Reset commit and atime options to defaults.
+                               if [ "$FST" = 'unknown' ]; then
+                                       FST=$(deduce_fstype $MP)
+                               fi
+                               case "$FST" in
+                                       "ext3"|"reiserfs")
+                                               PARSEDOPTS="$(parse_mount_opts_wfstab $DEV commit $OPTS)"
+                                               PARSEDOPTS="$(parse_yesno_opts_wfstab $DEV atime atime $PARSEDOPTS)"
+                                               mount $DEV -t $FST $MP -o remount,$PARSEDOPTS
+                                               ;;
+                                       "xfs")
+                                               PARSEDOPTS="$(parse_yesno_opts_wfstab $DEV atime atime $OPTS)"
+                                               mount $DEV -t $FST $MP -o remount,$PARSEDOPTS
+                                               ;;
+                               esac
+                               if [ -b $DEV ] ; then
+                                       blockdev --setra 256 $DEV
+                               fi
+                       done
+               fi
+               if [ $DO_HD -eq 1 ] ; then
+                       for THISHD in $HD ; do
+                               /sbin/hdparm -S $AC_HD $THISHD > /dev/null 2>&1
+                               /sbin/hdparm -B 255 $THISHD > /dev/null 2>&1
+                       done
+               fi
+               if [ $DO_CPU -eq 1 -a -e /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq ]; then
+                       echo `cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq` > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
+               fi
+               echo "."
+               ;;
+       *)
+               echo "Usage: $0 {start|stop}" 2>&1
+               exit 1
+               ;;
+
+  esac
+
+  exit 0
+
+
+ACPI integration
+----------------
+
+Dax Kelson submitted this so that the ACPI acpid daemon will
+kick off the laptop_mode script and run hdparm. The part that
+automatically disables laptop mode when the battery is low was
+written by Jan Topinski.
+
+/etc/acpi/events/ac_adapter::
+
+       event=ac_adapter
+       action=/etc/acpi/actions/ac.sh %e
+
+/etc/acpi/events/battery::
+
+       event=battery.*
+       action=/etc/acpi/actions/battery.sh %e
+
+/etc/acpi/actions/ac.sh::
+
+  #!/bin/bash
+
+  # ac on/offline event handler
+
+  status=`awk '/^state: / { print $2 }' /proc/acpi/ac_adapter/$2/state`
+
+  case $status in
+          "on-line")
+                  /sbin/laptop_mode stop
+                  exit 0
+          ;;
+          "off-line")
+                  /sbin/laptop_mode start
+                  exit 0
+          ;;
+  esac
+
+
+/etc/acpi/actions/battery.sh::
+
+  #! /bin/bash
+
+  # Automatically disable laptop mode when the battery almost runs out.
+
+  BATT_INFO=/proc/acpi/battery/$2/state
+
+  if [[ -f /proc/sys/vm/laptop_mode ]]
+  then
+     LM=`cat /proc/sys/vm/laptop_mode`
+     if [[ $LM -gt 0 ]]
+     then
+       if [[ -f $BATT_INFO ]]
+       then
+          # Source the config file only now that we know we need
+          if [ -f /etc/default/laptop-mode ] ; then
+                  # Debian
+                  . /etc/default/laptop-mode
+          elif [ -f /etc/sysconfig/laptop-mode ] ; then
+                  # Others
+                  . /etc/sysconfig/laptop-mode
+          fi
+          MINIMUM_BATTERY_MINUTES=${MINIMUM_BATTERY_MINUTES:-'10'}
+
+          ACTION="`cat $BATT_INFO | grep charging | cut -c 26-`"
+          if [[ ACTION -eq "discharging" ]]
+          then
+             PRESENT_RATE=`cat $BATT_INFO | grep "present rate:" | sed  "s/.* \([0-9][0-9]* \).*/\1/" `
+             REMAINING=`cat $BATT_INFO | grep "remaining capacity:" | sed  "s/.* \([0-9][0-9]* \).*/\1/" `
+          fi
+          if (($REMAINING * 60 / $PRESENT_RATE < $MINIMUM_BATTERY_MINUTES))
+          then
+             /sbin/laptop_mode stop
+          fi
+       else
+         logger -p daemon.warning "You are using laptop mode and your battery interface $BATT_INFO is missing. This may lead to loss of data when the battery runs out. Check kernel ACPI support and /proc/acpi/battery folder, and edit /etc/acpi/battery.sh to set BATT_INFO to the correct path."
+       fi
+     fi
+  fi
+
+
+Monitoring tool
+---------------
+
+Bartek Kania submitted this, it can be used to measure how much time your disk
+spends spun up/down.  See tools/laptop/dslm/dslm.c
diff --git a/Documentation/admin-guide/laptops/lg-laptop.rst b/Documentation/admin-guide/laptops/lg-laptop.rst
new file mode 100644 (file)
index 0000000..ce9b146
--- /dev/null
@@ -0,0 +1,84 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+
+LG Gram laptop extra features
+=============================
+
+By Matan Ziv-Av <matan@svgalib.org>
+
+
+Hotkeys
+-------
+
+The following FN keys are ignored by the kernel without this driver:
+
+- FN-F1 (LG control panel)   - Generates F15
+- FN-F5 (Touchpad toggle)    - Generates F13
+- FN-F6 (Airplane mode)      - Generates RFKILL
+- FN-F8 (Keyboard backlight) - Generates F16.
+  This key also changes keyboard backlight mode.
+- FN-F9 (Reader mode)        - Generates F14
+
+The rest of the FN keys work without a need for a special driver.
+
+
+Reader mode
+-----------
+
+Writing 0/1 to /sys/devices/platform/lg-laptop/reader_mode disables/enables
+reader mode. In this mode the screen colors change (blue color reduced),
+and the reader mode indicator LED (on F9 key) turns on.
+
+
+FN Lock
+-------
+
+Writing 0/1 to /sys/devices/platform/lg-laptop/fn_lock disables/enables
+FN lock.
+
+
+Battery care limit
+------------------
+
+Writing 80/100 to /sys/devices/platform/lg-laptop/battery_care_limit
+sets the maximum capacity to charge the battery. Limiting the charge
+reduces battery capacity loss over time.
+
+This value is reset to 100 when the kernel boots.
+
+
+Fan mode
+--------
+
+Writing 1/0 to /sys/devices/platform/lg-laptop/fan_mode disables/enables
+the fan silent mode.
+
+
+USB charge
+----------
+
+Writing 0/1 to /sys/devices/platform/lg-laptop/usb_charge disables/enables
+charging another device from the USB port while the device is turned off.
+
+This value is reset to 0 when the kernel boots.
+
+
+LEDs
+~~~~
+
+The are two LED devices supported by the driver:
+
+Keyboard backlight
+------------------
+
+A led device named kbd_led controls the keyboard backlight. There are three
+lighting level: off (0), low (127) and high (255).
+
+The keyboard backlight is also controlled by the key combination FN-F8
+which cycles through those levels.
+
+
+Touchpad indicator LED
+----------------------
+
+On the F5 key. Controlled by led device names tpad_led.
diff --git a/Documentation/admin-guide/laptops/sony-laptop.rst b/Documentation/admin-guide/laptops/sony-laptop.rst
new file mode 100644 (file)
index 0000000..9edcc7f
--- /dev/null
@@ -0,0 +1,174 @@
+=========================================
+Sony Notebook Control Driver (SNC) Readme
+=========================================
+
+       - Copyright (C) 2004- 2005 Stelian Pop <stelian@popies.net>
+       - Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
+
+This mini-driver drives the SNC and SPIC device present in the ACPI BIOS of the
+Sony Vaio laptops. This driver mixes both devices functions under the same
+(hopefully consistent) interface. This also means that the sonypi driver is
+obsoleted by sony-laptop now.
+
+Fn keys (hotkeys):
+------------------
+
+Some models report hotkeys through the SNC or SPIC devices, such events are
+reported both through the ACPI subsystem as acpi events and through the INPUT
+subsystem. See the logs of /proc/bus/input/devices to find out what those
+events are and which input devices are created by the driver.
+Additionally, loading the driver with the debug option will report all events
+in the kernel log.
+
+The "scancodes" passed to the input system (that can be remapped with udev)
+are indexes to the table "sony_laptop_input_keycode_map" in the sony-laptop.c
+module.  For example the "FN/E" key combination (EJECTCD on some models)
+generates the scancode 20 (0x14).
+
+Backlight control:
+------------------
+If your laptop model supports it, you will find sysfs files in the
+/sys/class/backlight/sony/
+directory. You will be able to query and set the current screen
+brightness:
+
+       ======================  =========================================
+       brightness              get/set screen brightness (an integer
+                               between 0 and 7)
+       actual_brightness       reading from this file will query the HW
+                               to get real brightness value
+       max_brightness          the maximum brightness value
+       ======================  =========================================
+
+
+Platform specific:
+------------------
+Loading the sony-laptop module will create a
+/sys/devices/platform/sony-laptop/
+directory populated with some files.
+
+You then read/write integer values from/to those files by using
+standard UNIX tools.
+
+The files are:
+
+       ======================  ==========================================
+       brightness_default      screen brightness which will be set
+                               when the laptop will be rebooted
+       cdpower                 power on/off the internal CD drive
+       audiopower              power on/off the internal sound card
+       lanpower                power on/off the internal ethernet card
+                               (only in debug mode)
+       bluetoothpower          power on/off the internal bluetooth device
+       fanspeed                get/set the fan speed
+       ======================  ==========================================
+
+Note that some files may be missing if they are not supported
+by your particular laptop model.
+
+Example usage::
+
+       # echo "1" > /sys/devices/platform/sony-laptop/brightness_default
+
+sets the lowest screen brightness for the next and later reboots
+
+::
+
+       # echo "8" > /sys/devices/platform/sony-laptop/brightness_default
+
+sets the highest screen brightness for the next and later reboots
+
+::
+
+       # cat /sys/devices/platform/sony-laptop/brightness_default
+
+retrieves the value
+
+::
+
+       # echo "0" > /sys/devices/platform/sony-laptop/audiopower
+
+powers off the sound card
+
+::
+
+       # echo "1" > /sys/devices/platform/sony-laptop/audiopower
+
+powers on the sound card.
+
+
+RFkill control:
+---------------
+More recent Vaio models expose a consistent set of ACPI methods to
+control radio frequency emitting devices. If you are a lucky owner of
+such a laptop you will find the necessary rfkill devices under
+/sys/class/rfkill. Check those starting with sony-* in::
+
+       # grep . /sys/class/rfkill/*/{state,name}
+
+
+Development:
+------------
+
+If you want to help with the development of this driver (and
+you are not afraid of any side effects doing strange things with
+your ACPI BIOS could have on your laptop), load the driver and
+pass the option 'debug=1'.
+
+REPEAT:
+       **DON'T DO THIS IF YOU DON'T LIKE RISKY BUSINESS.**
+
+In your kernel logs you will find the list of all ACPI methods
+the SNC device has on your laptop.
+
+* For new models you will see a long list of meaningless method names,
+  reading the DSDT table source should reveal that:
+
+(1) the SNC device uses an internal capability lookup table
+(2) SN00 is used to find values in the lookup table
+(3) SN06 and SN07 are used to call into the real methods based on
+    offsets you can obtain iterating the table using SN00
+(4) SN02 used to enable events.
+
+Some values in the capability lookup table are more or less known, see
+the code for all sony_call_snc_handle calls, others are more obscure.
+
+* For old models you can see the GCDP/GCDP methods used to pwer on/off
+  the CD drive, but there are others and they are usually different from
+  model to model.
+
+**I HAVE NO IDEA WHAT THOSE METHODS DO.**
+
+The sony-laptop driver creates, for some of those methods (the most
+current ones found on several Vaio models), an entry under
+/sys/devices/platform/sony-laptop, just like the 'cdpower' one.
+You can create other entries corresponding to your own laptop methods by
+further editing the source (see the 'sony_nc_values' table, and add a new
+entry to this table with your get/set method names using the
+SNC_HANDLE_NAMES macro).
+
+Your mission, should you accept it, is to try finding out what
+those entries are for, by reading/writing random values from/to those
+files and find out what is the impact on your laptop.
+
+Should you find anything interesting, please report it back to me,
+I will not disavow all knowledge of your actions :)
+
+See also http://www.linux.it/~malattia/wiki/index.php/Sony_drivers for other
+useful info.
+
+Bugs/Limitations:
+-----------------
+
+* This driver is not based on official documentation from Sony
+  (because there is none), so there is no guarantee this driver
+  will work at all, or do the right thing. Although this hasn't
+  happened to me, this driver could do very bad things to your
+  laptop, including permanent damage.
+
+* The sony-laptop and sonypi drivers do not interact at all. In the
+  future, sonypi will be removed and replaced by sony-laptop.
+
+* spicctrl, which is the userspace tool used to communicate with the
+  sonypi driver (through /dev/sonypi) is deprecated as well since all
+  its features are now available under the sysfs tree via sony-laptop.
diff --git a/Documentation/admin-guide/laptops/sonypi.rst b/Documentation/admin-guide/laptops/sonypi.rst
new file mode 100644 (file)
index 0000000..c6eaaf4
--- /dev/null
@@ -0,0 +1,158 @@
+==================================================
+Sony Programmable I/O Control Device Driver Readme
+==================================================
+
+       - Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net>
+       - Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+       - Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
+       - Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
+       - Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
+       - Copyright (C) 2000 Andrew Tridgell <tridge@samba.org>
+
+This driver enables access to the Sony Programmable I/O Control Device which
+can be found in many Sony Vaio laptops. Some newer Sony laptops (seems to be
+limited to new FX series laptops, at least the FX501 and the FX702) lack a
+sonypi device and are not supported at all by this driver.
+
+It will give access (through a user space utility) to some events those laptops
+generate, like:
+
+       - jogdial events (the small wheel on the side of Vaios)
+       - capture button events (only on Vaio Picturebook series)
+       - Fn keys
+       - bluetooth button (only on C1VR model)
+       - programmable keys, back, help, zoom, thumbphrase buttons, etc.
+         (when available)
+
+Those events (see linux/sonypi.h) can be polled using the character device node
+/dev/sonypi (major 10, minor auto allocated or specified as a option).
+A simple daemon which translates the jogdial movements into mouse wheel events
+can be downloaded at: <http://popies.net/sonypi/>
+
+Another option to intercept the events is to get them directly through the
+input layer.
+
+This driver supports also some ioctl commands for setting the LCD screen
+brightness and querying the batteries charge information (some more
+commands may be added in the future).
+
+This driver can also be used to set the camera controls on Picturebook series
+(brightness, contrast etc), and is used by the video4linux driver for the
+Motion Eye camera.
+
+Please note that this driver was created by reverse engineering the Windows
+driver and the ACPI BIOS, because Sony doesn't agree to release any programming
+specs for its laptops. If someone convinces them to do so, drop me a note.
+
+Driver options:
+---------------
+
+Several options can be passed to the sonypi driver using the standard
+module argument syntax (<param>=<value> when passing the option to the
+module or sonypi.<param>=<value> on the kernel boot line when sonypi is
+statically linked into the kernel). Those options are:
+
+       =============== =======================================================
+       minor:          minor number of the misc device /dev/sonypi,
+                       default is -1 (automatic allocation, see /proc/misc
+                       or kernel logs)
+
+       camera:         if you have a PictureBook series Vaio (with the
+                       integrated MotionEye camera), set this parameter to 1
+                       in order to let the driver access to the camera
+
+       fnkeyinit:      on some Vaios (C1VE, C1VR etc), the Fn key events don't
+                       get enabled unless you set this parameter to 1.
+                       Do not use this option unless it's actually necessary,
+                       some Vaio models don't deal well with this option.
+                       This option is available only if the kernel is
+                       compiled without ACPI support (since it conflicts
+                       with it and it shouldn't be required anyway if
+                       ACPI is already enabled).
+
+       verbose:        set to 1 to print unknown events received from the
+                       sonypi device.
+                       set to 2 to print all events received from the
+                       sonypi device.
+
+       compat:         uses some compatibility code for enabling the sonypi
+                       events. If the driver worked for you in the past
+                       (prior to version 1.5) and does not work anymore,
+                       add this option and report to the author.
+
+       mask:           event mask telling the driver what events will be
+                       reported to the user. This parameter is required for
+                       some Vaio models where the hardware reuses values
+                       used in other Vaio models (like the FX series who does
+                       not have a jogdial but reuses the jogdial events for
+                       programmable keys events). The default event mask is
+                       set to 0xffffffff, meaning that all possible events
+                       will be tried. You can use the following bits to
+                       construct your own event mask (from
+                       drivers/char/sonypi.h)::
+
+                               SONYPI_JOGGER_MASK              0x0001
+                               SONYPI_CAPTURE_MASK             0x0002
+                               SONYPI_FNKEY_MASK               0x0004
+                               SONYPI_BLUETOOTH_MASK           0x0008
+                               SONYPI_PKEY_MASK                0x0010
+                               SONYPI_BACK_MASK                0x0020
+                               SONYPI_HELP_MASK                0x0040
+                               SONYPI_LID_MASK                 0x0080
+                               SONYPI_ZOOM_MASK                0x0100
+                               SONYPI_THUMBPHRASE_MASK         0x0200
+                               SONYPI_MEYE_MASK                0x0400
+                               SONYPI_MEMORYSTICK_MASK         0x0800
+                               SONYPI_BATTERY_MASK             0x1000
+                               SONYPI_WIRELESS_MASK            0x2000
+
+       useinput:       if set (which is the default) two input devices are
+                       created, one which interprets the jogdial events as
+                       mouse events, the other one which acts like a
+                       keyboard reporting the pressing of the special keys.
+       =============== =======================================================
+
+Module use:
+-----------
+
+In order to automatically load the sonypi module on use, you can put those
+lines a configuration file in /etc/modprobe.d/::
+
+       alias char-major-10-250 sonypi
+       options sonypi minor=250
+
+This supposes the use of minor 250 for the sonypi device::
+
+       # mknod /dev/sonypi c 10 250
+
+Bugs:
+-----
+
+       - several users reported that this driver disables the BIOS-managed
+         Fn-keys which put the laptop in sleeping state, or switch the
+         external monitor on/off. There is no workaround yet, since this
+         driver disables all APM management for those keys, by enabling the
+         ACPI management (and the ACPI core stuff is not complete yet). If
+         you have one of those laptops with working Fn keys and want to
+         continue to use them, don't use this driver.
+
+       - some users reported that the laptop speed is lower (dhrystone
+         tested) when using the driver with the fnkeyinit parameter. I cannot
+         reproduce it on my laptop and not all users have this problem.
+         This happens because the fnkeyinit parameter enables the ACPI
+         mode (but without additional ACPI control, like processor
+         speed handling etc). Use ACPI instead of APM if it works on your
+         laptop.
+
+       - sonypi lacks the ability to distinguish between certain key
+         events on some models.
+
+       - some models with the nvidia card (geforce go 6200 tc) uses a
+         different way to adjust the backlighting of the screen. There
+         is a userspace utility to adjust the brightness on those models,
+         which can be downloaded from
+         http://www.acc.umu.se/~erikw/program/smartdimmer-0.1.tar.bz2
+
+       - since all development was done by reverse engineering, there is
+         *absolutely no guarantee* that this driver will not crash your
+         laptop. Permanently.
diff --git a/Documentation/admin-guide/laptops/thinkpad-acpi.rst b/Documentation/admin-guide/laptops/thinkpad-acpi.rst
new file mode 100644 (file)
index 0000000..adea0bf
--- /dev/null
@@ -0,0 +1,1562 @@
+===========================
+ThinkPad ACPI Extras Driver
+===========================
+
+Version 0.25
+
+October 16th,  2013
+
+- Borislav Deianov <borislav@users.sf.net>
+- Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+
+http://ibm-acpi.sf.net/
+
+This is a Linux driver for the IBM and Lenovo ThinkPad laptops. It
+supports various features of these laptops which are accessible
+through the ACPI and ACPI EC framework, but not otherwise fully
+supported by the generic Linux ACPI drivers.
+
+This driver used to be named ibm-acpi until kernel 2.6.21 and release
+0.13-20070314.  It used to be in the drivers/acpi tree, but it was
+moved to the drivers/misc tree and renamed to thinkpad-acpi for kernel
+2.6.22, and release 0.14.  It was moved to drivers/platform/x86 for
+kernel 2.6.29 and release 0.22.
+
+The driver is named "thinkpad-acpi".  In some places, like module
+names and log messages, "thinkpad_acpi" is used because of userspace
+issues.
+
+"tpacpi" is used as a shorthand where "thinkpad-acpi" would be too
+long due to length limitations on some Linux kernel versions.
+
+Status
+------
+
+The features currently supported are the following (see below for
+detailed description):
+
+       - Fn key combinations
+       - Bluetooth enable and disable
+       - video output switching, expansion control
+       - ThinkLight on and off
+       - CMOS/UCMS control
+       - LED control
+       - ACPI sounds
+       - temperature sensors
+       - Experimental: embedded controller register dump
+       - LCD brightness control
+       - Volume control
+       - Fan control and monitoring: fan speed, fan enable/disable
+       - WAN enable and disable
+       - UWB enable and disable
+
+A compatibility table by model and feature is maintained on the web
+site, http://ibm-acpi.sf.net/. I appreciate any success or failure
+reports, especially if they add to or correct the compatibility table.
+Please include the following information in your report:
+
+       - ThinkPad model name
+       - a copy of your ACPI tables, using the "acpidump" utility
+       - a copy of the output of dmidecode, with serial numbers
+         and UUIDs masked off
+       - which driver features work and which don't
+       - the observed behavior of non-working features
+
+Any other comments or patches are also more than welcome.
+
+
+Installation
+------------
+
+If you are compiling this driver as included in the Linux kernel
+sources, look for the CONFIG_THINKPAD_ACPI Kconfig option.
+It is located on the menu path: "Device Drivers" -> "X86 Platform
+Specific Device Drivers" -> "ThinkPad ACPI Laptop Extras".
+
+
+Features
+--------
+
+The driver exports two different interfaces to userspace, which can be
+used to access the features it provides.  One is a legacy procfs-based
+interface, which will be removed at some time in the future.  The other
+is a new sysfs-based interface which is not complete yet.
+
+The procfs interface creates the /proc/acpi/ibm directory.  There is a
+file under that directory for each feature it supports.  The procfs
+interface is mostly frozen, and will change very little if at all: it
+will not be extended to add any new functionality in the driver, instead
+all new functionality will be implemented on the sysfs interface.
+
+The sysfs interface tries to blend in the generic Linux sysfs subsystems
+and classes as much as possible.  Since some of these subsystems are not
+yet ready or stabilized, it is expected that this interface will change,
+and any and all userspace programs must deal with it.
+
+
+Notes about the sysfs interface
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Unlike what was done with the procfs interface, correctness when talking
+to the sysfs interfaces will be enforced, as will correctness in the
+thinkpad-acpi's implementation of sysfs interfaces.
+
+Also, any bugs in the thinkpad-acpi sysfs driver code or in the
+thinkpad-acpi's implementation of the sysfs interfaces will be fixed for
+maximum correctness, even if that means changing an interface in
+non-compatible ways.  As these interfaces mature both in the kernel and
+in thinkpad-acpi, such changes should become quite rare.
+
+Applications interfacing to the thinkpad-acpi sysfs interfaces must
+follow all sysfs guidelines and correctly process all errors (the sysfs
+interface makes extensive use of errors).  File descriptors and open /
+close operations to the sysfs inodes must also be properly implemented.
+
+The version of thinkpad-acpi's sysfs interface is exported by the driver
+as a driver attribute (see below).
+
+Sysfs driver attributes are on the driver's sysfs attribute space,
+for 2.6.23+ this is /sys/bus/platform/drivers/thinkpad_acpi/ and
+/sys/bus/platform/drivers/thinkpad_hwmon/
+
+Sysfs device attributes are on the thinkpad_acpi device sysfs attribute
+space, for 2.6.23+ this is /sys/devices/platform/thinkpad_acpi/.
+
+Sysfs device attributes for the sensors and fan are on the
+thinkpad_hwmon device's sysfs attribute space, but you should locate it
+looking for a hwmon device with the name attribute of "thinkpad", or
+better yet, through libsensors. For 4.14+ sysfs attributes were moved to the
+hwmon device (/sys/bus/platform/devices/thinkpad_hwmon/hwmon/hwmon? or
+/sys/class/hwmon/hwmon?).
+
+Driver version
+--------------
+
+procfs: /proc/acpi/ibm/driver
+
+sysfs driver attribute: version
+
+The driver name and version. No commands can be written to this file.
+
+
+Sysfs interface version
+-----------------------
+
+sysfs driver attribute: interface_version
+
+Version of the thinkpad-acpi sysfs interface, as an unsigned long
+(output in hex format: 0xAAAABBCC), where:
+
+       AAAA
+         - major revision
+       BB
+         - minor revision
+       CC
+         - bugfix revision
+
+The sysfs interface version changelog for the driver can be found at the
+end of this document.  Changes to the sysfs interface done by the kernel
+subsystems are not documented here, nor are they tracked by this
+attribute.
+
+Changes to the thinkpad-acpi sysfs interface are only considered
+non-experimental when they are submitted to Linux mainline, at which
+point the changes in this interface are documented and interface_version
+may be updated.  If you are using any thinkpad-acpi features not yet
+sent to mainline for merging, you do so on your own risk: these features
+may disappear, or be implemented in a different and incompatible way by
+the time they are merged in Linux mainline.
+
+Changes that are backwards-compatible by nature (e.g. the addition of
+attributes that do not change the way the other attributes work) do not
+always warrant an update of interface_version.  Therefore, one must
+expect that an attribute might not be there, and deal with it properly
+(an attribute not being there *is* a valid way to make it clear that a
+feature is not available in sysfs).
+
+
+Hot keys
+--------
+
+procfs: /proc/acpi/ibm/hotkey
+
+sysfs device attribute: hotkey_*
+
+In a ThinkPad, the ACPI HKEY handler is responsible for communicating
+some important events and also keyboard hot key presses to the operating
+system.  Enabling the hotkey functionality of thinkpad-acpi signals the
+firmware that such a driver is present, and modifies how the ThinkPad
+firmware will behave in many situations.
+
+The driver enables the HKEY ("hot key") event reporting automatically
+when loaded, and disables it when it is removed.
+
+The driver will report HKEY events in the following format::
+
+       ibm/hotkey HKEY 00000080 0000xxxx
+
+Some of these events refer to hot key presses, but not all of them.
+
+The driver will generate events over the input layer for hot keys and
+radio switches, and over the ACPI netlink layer for other events.  The
+input layer support accepts the standard IOCTLs to remap the keycodes
+assigned to each hot key.
+
+The hot key bit mask allows some control over which hot keys generate
+events.  If a key is "masked" (bit set to 0 in the mask), the firmware
+will handle it.  If it is "unmasked", it signals the firmware that
+thinkpad-acpi would prefer to handle it, if the firmware would be so
+kind to allow it (and it often doesn't!).
+
+Not all bits in the mask can be modified.  Not all bits that can be
+modified do anything.  Not all hot keys can be individually controlled
+by the mask.  Some models do not support the mask at all.  The behaviour
+of the mask is, therefore, highly dependent on the ThinkPad model.
+
+The driver will filter out any unmasked hotkeys, so even if the firmware
+doesn't allow disabling an specific hotkey, the driver will not report
+events for unmasked hotkeys.
+
+Note that unmasking some keys prevents their default behavior.  For
+example, if Fn+F5 is unmasked, that key will no longer enable/disable
+Bluetooth by itself in firmware.
+
+Note also that not all Fn key combinations are supported through ACPI
+depending on the ThinkPad model and firmware version.  On those
+ThinkPads, it is still possible to support some extra hotkeys by
+polling the "CMOS NVRAM" at least 10 times per second.  The driver
+attempts to enables this functionality automatically when required.
+
+procfs notes
+^^^^^^^^^^^^
+
+The following commands can be written to the /proc/acpi/ibm/hotkey file::
+
+       echo 0xffffffff > /proc/acpi/ibm/hotkey -- enable all hot keys
+       echo 0 > /proc/acpi/ibm/hotkey -- disable all possible hot keys
+       ... any other 8-hex-digit mask ...
+       echo reset > /proc/acpi/ibm/hotkey -- restore the recommended mask
+
+The following commands have been deprecated and will cause the kernel
+to log a warning::
+
+       echo enable > /proc/acpi/ibm/hotkey -- does nothing
+       echo disable > /proc/acpi/ibm/hotkey -- returns an error
+
+The procfs interface does not support NVRAM polling control.  So as to
+maintain maximum bug-to-bug compatibility, it does not report any masks,
+nor does it allow one to manipulate the hot key mask when the firmware
+does not support masks at all, even if NVRAM polling is in use.
+
+sysfs notes
+^^^^^^^^^^^
+
+       hotkey_bios_enabled:
+               DEPRECATED, WILL BE REMOVED SOON.
+
+               Returns 0.
+
+       hotkey_bios_mask:
+               DEPRECATED, DON'T USE, WILL BE REMOVED IN THE FUTURE.
+
+               Returns the hot keys mask when thinkpad-acpi was loaded.
+               Upon module unload, the hot keys mask will be restored
+               to this value.   This is always 0x80c, because those are
+               the hotkeys that were supported by ancient firmware
+               without mask support.
+
+       hotkey_enable:
+               DEPRECATED, WILL BE REMOVED SOON.
+
+               0: returns -EPERM
+               1: does nothing
+
+       hotkey_mask:
+               bit mask to enable reporting (and depending on
+               the firmware, ACPI event generation) for each hot key
+               (see above).  Returns the current status of the hot keys
+               mask, and allows one to modify it.
+
+       hotkey_all_mask:
+               bit mask that should enable event reporting for all
+               supported hot keys, when echoed to hotkey_mask above.
+               Unless you know which events need to be handled
+               passively (because the firmware *will* handle them
+               anyway), do *not* use hotkey_all_mask.  Use
+               hotkey_recommended_mask, instead. You have been warned.
+
+       hotkey_recommended_mask:
+               bit mask that should enable event reporting for all
+               supported hot keys, except those which are always
+               handled by the firmware anyway.  Echo it to
+               hotkey_mask above, to use.  This is the default mask
+               used by the driver.
+
+       hotkey_source_mask:
+               bit mask that selects which hot keys will the driver
+               poll the NVRAM for.  This is auto-detected by the driver
+               based on the capabilities reported by the ACPI firmware,
+               but it can be overridden at runtime.
+
+               Hot keys whose bits are set in hotkey_source_mask are
+               polled for in NVRAM, and reported as hotkey events if
+               enabled in hotkey_mask.  Only a few hot keys are
+               available through CMOS NVRAM polling.
+
+               Warning: when in NVRAM mode, the volume up/down/mute
+               keys are synthesized according to changes in the mixer,
+               which uses a single volume up or volume down hotkey
+               press to unmute, as per the ThinkPad volume mixer user
+               interface.  When in ACPI event mode, volume up/down/mute
+               events are reported by the firmware and can behave
+               differently (and that behaviour changes with firmware
+               version -- not just with firmware models -- as well as
+               OSI(Linux) state).
+
+       hotkey_poll_freq:
+               frequency in Hz for hot key polling. It must be between
+               0 and 25 Hz.  Polling is only carried out when strictly
+               needed.
+
+               Setting hotkey_poll_freq to zero disables polling, and
+               will cause hot key presses that require NVRAM polling
+               to never be reported.
+
+               Setting hotkey_poll_freq too low may cause repeated
+               pressings of the same hot key to be misreported as a
+               single key press, or to not even be detected at all.
+               The recommended polling frequency is 10Hz.
+
+       hotkey_radio_sw:
+               If the ThinkPad has a hardware radio switch, this
+               attribute will read 0 if the switch is in the "radios
+               disabled" position, and 1 if the switch is in the
+               "radios enabled" position.
+
+               This attribute has poll()/select() support.
+
+       hotkey_tablet_mode:
+               If the ThinkPad has tablet capabilities, this attribute
+               will read 0 if the ThinkPad is in normal mode, and
+               1 if the ThinkPad is in tablet mode.
+
+               This attribute has poll()/select() support.
+
+       wakeup_reason:
+               Set to 1 if the system is waking up because the user
+               requested a bay ejection.  Set to 2 if the system is
+               waking up because the user requested the system to
+               undock.  Set to zero for normal wake-ups or wake-ups
+               due to unknown reasons.
+
+               This attribute has poll()/select() support.
+
+       wakeup_hotunplug_complete:
+               Set to 1 if the system was waken up because of an
+               undock or bay ejection request, and that request
+               was successfully completed.  At this point, it might
+               be useful to send the system back to sleep, at the
+               user's choice.  Refer to HKEY events 0x4003 and
+               0x3003, below.
+
+               This attribute has poll()/select() support.
+
+input layer notes
+^^^^^^^^^^^^^^^^^
+
+A Hot key is mapped to a single input layer EV_KEY event, possibly
+followed by an EV_MSC MSC_SCAN event that shall contain that key's scan
+code.  An EV_SYN event will always be generated to mark the end of the
+event block.
+
+Do not use the EV_MSC MSC_SCAN events to process keys.  They are to be
+used as a helper to remap keys, only.  They are particularly useful when
+remapping KEY_UNKNOWN keys.
+
+The events are available in an input device, with the following id:
+
+       ==============  ==============================
+       Bus             BUS_HOST
+       vendor          0x1014 (PCI_VENDOR_ID_IBM)  or
+                       0x17aa (PCI_VENDOR_ID_LENOVO)
+       product         0x5054 ("TP")
+       version         0x4101
+       ==============  ==============================
+
+The version will have its LSB incremented if the keymap changes in a
+backwards-compatible way.  The MSB shall always be 0x41 for this input
+device.  If the MSB is not 0x41, do not use the device as described in
+this section, as it is either something else (e.g. another input device
+exported by a thinkpad driver, such as HDAPS) or its functionality has
+been changed in a non-backwards compatible way.
+
+Adding other event types for other functionalities shall be considered a
+backwards-compatible change for this input device.
+
+Thinkpad-acpi Hot Key event map (version 0x4101):
+
+=======        ======= ==============  ==============================================
+ACPI   Scan
+event  code    Key             Notes
+=======        ======= ==============  ==============================================
+0x1001 0x00    FN+F1           -
+
+0x1002 0x01    FN+F2           IBM: battery (rare)
+                               Lenovo: Screen lock
+
+0x1003 0x02    FN+F3           Many IBM models always report
+                               this hot key, even with hot keys
+                               disabled or with Fn+F3 masked
+                               off
+                               IBM: screen lock, often turns
+                               off the ThinkLight as side-effect
+                               Lenovo: battery
+
+0x1004 0x03    FN+F4           Sleep button (ACPI sleep button
+                               semantics, i.e. sleep-to-RAM).
+                               It always generates some kind
+                               of event, either the hot key
+                               event or an ACPI sleep button
+                               event. The firmware may
+                               refuse to generate further FN+F4
+                               key presses until a S3 or S4 ACPI
+                               sleep cycle is performed or some
+                               time passes.
+
+0x1005 0x04    FN+F5           Radio.  Enables/disables
+                               the internal Bluetooth hardware
+                               and W-WAN card if left in control
+                               of the firmware.  Does not affect
+                               the WLAN card.
+                               Should be used to turn on/off all
+                               radios (Bluetooth+W-WAN+WLAN),
+                               really.
+
+0x1006 0x05    FN+F6           -
+
+0x1007 0x06    FN+F7           Video output cycle.
+                               Do you feel lucky today?
+
+0x1008 0x07    FN+F8           IBM: toggle screen expand
+                               Lenovo: configure UltraNav,
+                               or toggle screen expand
+
+0x1009 0x08    FN+F9           -
+
+...    ...     ...             ...
+
+0x100B 0x0A    FN+F11          -
+
+0x100C 0x0B    FN+F12          Sleep to disk.  You are always
+                               supposed to handle it yourself,
+                               either through the ACPI event,
+                               or through a hotkey event.
+                               The firmware may refuse to
+                               generate further FN+F12 key
+                               press events until a S3 or S4
+                               ACPI sleep cycle is performed,
+                               or some time passes.
+
+0x100D 0x0C    FN+BACKSPACE    -
+0x100E 0x0D    FN+INSERT       -
+0x100F 0x0E    FN+DELETE       -
+
+0x1010 0x0F    FN+HOME         Brightness up.  This key is
+                               always handled by the firmware
+                               in IBM ThinkPads, even when
+                               unmasked.  Just leave it alone.
+                               For Lenovo ThinkPads with a new
+                               BIOS, it has to be handled either
+                               by the ACPI OSI, or by userspace.
+                               The driver does the right thing,
+                               never mess with this.
+0x1011 0x10    FN+END          Brightness down.  See brightness
+                               up for details.
+
+0x1012 0x11    FN+PGUP         ThinkLight toggle.  This key is
+                               always handled by the firmware,
+                               even when unmasked.
+
+0x1013 0x12    FN+PGDOWN       -
+
+0x1014 0x13    FN+SPACE        Zoom key
+
+0x1015 0x14    VOLUME UP       Internal mixer volume up. This
+                               key is always handled by the
+                               firmware, even when unmasked.
+                               NOTE: Lenovo seems to be changing
+                               this.
+0x1016 0x15    VOLUME DOWN     Internal mixer volume up. This
+                               key is always handled by the
+                               firmware, even when unmasked.
+                               NOTE: Lenovo seems to be changing
+                               this.
+0x1017 0x16    MUTE            Mute internal mixer. This
+                               key is always handled by the
+                               firmware, even when unmasked.
+
+0x1018 0x17    THINKPAD        ThinkPad/Access IBM/Lenovo key
+
+0x1019 0x18    unknown
+
+...    ...     ...
+
+0x1020 0x1F    unknown
+=======        ======= ==============  ==============================================
+
+The ThinkPad firmware does not allow one to differentiate when most hot
+keys are pressed or released (either that, or we don't know how to, yet).
+For these keys, the driver generates a set of events for a key press and
+immediately issues the same set of events for a key release.  It is
+unknown by the driver if the ThinkPad firmware triggered these events on
+hot key press or release, but the firmware will do it for either one, not
+both.
+
+If a key is mapped to KEY_RESERVED, it generates no input events at all.
+If a key is mapped to KEY_UNKNOWN, it generates an input event that
+includes an scan code.  If a key is mapped to anything else, it will
+generate input device EV_KEY events.
+
+In addition to the EV_KEY events, thinkpad-acpi may also issue EV_SW
+events for switches:
+
+============== ==============================================
+SW_RFKILL_ALL  T60 and later hardware rfkill rocker switch
+SW_TABLET_MODE Tablet ThinkPads HKEY events 0x5009 and 0x500A
+============== ==============================================
+
+Non hotkey ACPI HKEY event map
+------------------------------
+
+Events that are never propagated by the driver:
+
+======         ==================================================
+0x2304         System is waking up from suspend to undock
+0x2305         System is waking up from suspend to eject bay
+0x2404         System is waking up from hibernation to undock
+0x2405         System is waking up from hibernation to eject bay
+0x5001         Lid closed
+0x5002         Lid opened
+0x5009         Tablet swivel: switched to tablet mode
+0x500A         Tablet swivel: switched to normal mode
+0x5010         Brightness level changed/control event
+0x6000         KEYBOARD: Numlock key pressed
+0x6005         KEYBOARD: Fn key pressed (TO BE VERIFIED)
+0x7000         Radio Switch may have changed state
+======         ==================================================
+
+
+Events that are propagated by the driver to userspace:
+
+======         =====================================================
+0x2313         ALARM: System is waking up from suspend because
+               the battery is nearly empty
+0x2413         ALARM: System is waking up from hibernation because
+               the battery is nearly empty
+0x3003         Bay ejection (see 0x2x05) complete, can sleep again
+0x3006         Bay hotplug request (hint to power up SATA link when
+               the optical drive tray is ejected)
+0x4003         Undocked (see 0x2x04), can sleep again
+0x4010         Docked into hotplug port replicator (non-ACPI dock)
+0x4011         Undocked from hotplug port replicator (non-ACPI dock)
+0x500B         Tablet pen inserted into its storage bay
+0x500C         Tablet pen removed from its storage bay
+0x6011         ALARM: battery is too hot
+0x6012         ALARM: battery is extremely hot
+0x6021         ALARM: a sensor is too hot
+0x6022         ALARM: a sensor is extremely hot
+0x6030         System thermal table changed
+0x6032         Thermal Control command set completion  (DYTC, Windows)
+0x6040         Nvidia Optimus/AC adapter related (TO BE VERIFIED)
+0x60C0         X1 Yoga 2016, Tablet mode status changed
+0x60F0         Thermal Transformation changed (GMTS, Windows)
+======         =====================================================
+
+Battery nearly empty alarms are a last resort attempt to get the
+operating system to hibernate or shutdown cleanly (0x2313), or shutdown
+cleanly (0x2413) before power is lost.  They must be acted upon, as the
+wake up caused by the firmware will have negated most safety nets...
+
+When any of the "too hot" alarms happen, according to Lenovo the user
+should suspend or hibernate the laptop (and in the case of battery
+alarms, unplug the AC adapter) to let it cool down.  These alarms do
+signal that something is wrong, they should never happen on normal
+operating conditions.
+
+The "extremely hot" alarms are emergencies.  According to Lenovo, the
+operating system is to force either an immediate suspend or hibernate
+cycle, or a system shutdown.  Obviously, something is very wrong if this
+happens.
+
+
+Brightness hotkey notes
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Don't mess with the brightness hotkeys in a Thinkpad.  If you want
+notifications for OSD, use the sysfs backlight class event support.
+
+The driver will issue KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN events
+automatically for the cases were userspace has to do something to
+implement brightness changes.  When you override these events, you will
+either fail to handle properly the ThinkPads that require explicit
+action to change backlight brightness, or the ThinkPads that require
+that no action be taken to work properly.
+
+
+Bluetooth
+---------
+
+procfs: /proc/acpi/ibm/bluetooth
+
+sysfs device attribute: bluetooth_enable (deprecated)
+
+sysfs rfkill class: switch "tpacpi_bluetooth_sw"
+
+This feature shows the presence and current state of a ThinkPad
+Bluetooth device in the internal ThinkPad CDC slot.
+
+If the ThinkPad supports it, the Bluetooth state is stored in NVRAM,
+so it is kept across reboots and power-off.
+
+Procfs notes
+^^^^^^^^^^^^
+
+If Bluetooth is installed, the following commands can be used::
+
+       echo enable > /proc/acpi/ibm/bluetooth
+       echo disable > /proc/acpi/ibm/bluetooth
+
+Sysfs notes
+^^^^^^^^^^^
+
+       If the Bluetooth CDC card is installed, it can be enabled /
+       disabled through the "bluetooth_enable" thinkpad-acpi device
+       attribute, and its current status can also be queried.
+
+       enable:
+
+               - 0: disables Bluetooth / Bluetooth is disabled
+               - 1: enables Bluetooth / Bluetooth is enabled.
+
+       Note: this interface has been superseded by the generic rfkill
+       class.  It has been deprecated, and it will be removed in year
+       2010.
+
+       rfkill controller switch "tpacpi_bluetooth_sw": refer to
+       Documentation/driver-api/rfkill.rst for details.
+
+
+Video output control -- /proc/acpi/ibm/video
+--------------------------------------------
+
+This feature allows control over the devices used for video output -
+LCD, CRT or DVI (if available). The following commands are available::
+
+       echo lcd_enable > /proc/acpi/ibm/video
+       echo lcd_disable > /proc/acpi/ibm/video
+       echo crt_enable > /proc/acpi/ibm/video
+       echo crt_disable > /proc/acpi/ibm/video
+       echo dvi_enable > /proc/acpi/ibm/video
+       echo dvi_disable > /proc/acpi/ibm/video
+       echo auto_enable > /proc/acpi/ibm/video
+       echo auto_disable > /proc/acpi/ibm/video
+       echo expand_toggle > /proc/acpi/ibm/video
+       echo video_switch > /proc/acpi/ibm/video
+
+NOTE:
+  Access to this feature is restricted to processes owning the
+  CAP_SYS_ADMIN capability for safety reasons, as it can interact badly
+  enough with some versions of X.org to crash it.
+
+Each video output device can be enabled or disabled individually.
+Reading /proc/acpi/ibm/video shows the status of each device.
+
+Automatic video switching can be enabled or disabled.  When automatic
+video switching is enabled, certain events (e.g. opening the lid,
+docking or undocking) cause the video output device to change
+automatically. While this can be useful, it also causes flickering
+and, on the X40, video corruption. By disabling automatic switching,
+the flickering or video corruption can be avoided.
+
+The video_switch command cycles through the available video outputs
+(it simulates the behavior of Fn-F7).
+
+Video expansion can be toggled through this feature. This controls
+whether the display is expanded to fill the entire LCD screen when a
+mode with less than full resolution is used. Note that the current
+video expansion status cannot be determined through this feature.
+
+Note that on many models (particularly those using Radeon graphics
+chips) the X driver configures the video card in a way which prevents
+Fn-F7 from working. This also disables the video output switching
+features of this driver, as it uses the same ACPI methods as
+Fn-F7. Video switching on the console should still work.
+
+UPDATE: refer to https://bugs.freedesktop.org/show_bug.cgi?id=2000
+
+
+ThinkLight control
+------------------
+
+procfs: /proc/acpi/ibm/light
+
+sysfs attributes: as per LED class, for the "tpacpi::thinklight" LED
+
+procfs notes
+^^^^^^^^^^^^
+
+The ThinkLight status can be read and set through the procfs interface.  A
+few models which do not make the status available will show the ThinkLight
+status as "unknown". The available commands are::
+
+       echo on  > /proc/acpi/ibm/light
+       echo off > /proc/acpi/ibm/light
+
+sysfs notes
+^^^^^^^^^^^
+
+The ThinkLight sysfs interface is documented by the LED class
+documentation, in Documentation/leds/leds-class.rst.  The ThinkLight LED name
+is "tpacpi::thinklight".
+
+Due to limitations in the sysfs LED class, if the status of the ThinkLight
+cannot be read or if it is unknown, thinkpad-acpi will report it as "off".
+It is impossible to know if the status returned through sysfs is valid.
+
+
+CMOS/UCMS control
+-----------------
+
+procfs: /proc/acpi/ibm/cmos
+
+sysfs device attribute: cmos_command
+
+This feature is mostly used internally by the ACPI firmware to keep the legacy
+CMOS NVRAM bits in sync with the current machine state, and to record this
+state so that the ThinkPad will retain such settings across reboots.
+
+Some of these commands actually perform actions in some ThinkPad models, but
+this is expected to disappear more and more in newer models.  As an example, in
+a T43 and in a X40, commands 12 and 13 still control the ThinkLight state for
+real, but commands 0 to 2 don't control the mixer anymore (they have been
+phased out) and just update the NVRAM.
+
+The range of valid cmos command numbers is 0 to 21, but not all have an
+effect and the behavior varies from model to model.  Here is the behavior
+on the X40 (tpb is the ThinkPad Buttons utility):
+
+       - 0 - Related to "Volume down" key press
+       - 1 - Related to "Volume up" key press
+       - 2 - Related to "Mute on" key press
+       - 3 - Related to "Access IBM" key press
+       - 4 - Related to "LCD brightness up" key press
+       - 5 - Related to "LCD brightness down" key press
+       - 11 - Related to "toggle screen expansion" key press/function
+       - 12 - Related to "ThinkLight on"
+       - 13 - Related to "ThinkLight off"
+       - 14 - Related to "ThinkLight" key press (toggle ThinkLight)
+
+The cmos command interface is prone to firmware split-brain problems, as
+in newer ThinkPads it is just a compatibility layer.  Do not use it, it is
+exported just as a debug tool.
+
+
+LED control
+-----------
+
+procfs: /proc/acpi/ibm/led
+sysfs attributes: as per LED class, see below for names
+
+Some of the LED indicators can be controlled through this feature.  On
+some older ThinkPad models, it is possible to query the status of the
+LED indicators as well.  Newer ThinkPads cannot query the real status
+of the LED indicators.
+
+Because misuse of the LEDs could induce an unaware user to perform
+dangerous actions (like undocking or ejecting a bay device while the
+buses are still active), or mask an important alarm (such as a nearly
+empty battery, or a broken battery), access to most LEDs is
+restricted.
+
+Unrestricted access to all LEDs requires that thinkpad-acpi be
+compiled with the CONFIG_THINKPAD_ACPI_UNSAFE_LEDS option enabled.
+Distributions must never enable this option.  Individual users that
+are aware of the consequences are welcome to enabling it.
+
+Audio mute and microphone mute LEDs are supported, but currently not
+visible to userspace. They are used by the snd-hda-intel audio driver.
+
+procfs notes
+^^^^^^^^^^^^
+
+The available commands are::
+
+       echo '<LED number> on' >/proc/acpi/ibm/led
+       echo '<LED number> off' >/proc/acpi/ibm/led
+       echo '<LED number> blink' >/proc/acpi/ibm/led
+
+The <LED number> range is 0 to 15. The set of LEDs that can be
+controlled varies from model to model. Here is the common ThinkPad
+mapping:
+
+       - 0 - power
+       - 1 - battery (orange)
+       - 2 - battery (green)
+       - 3 - UltraBase/dock
+       - 4 - UltraBay
+       - 5 - UltraBase battery slot
+       - 6 - (unknown)
+       - 7 - standby
+       - 8 - dock status 1
+       - 9 - dock status 2
+       - 10, 11 - (unknown)
+       - 12 - thinkvantage
+       - 13, 14, 15 - (unknown)
+
+All of the above can be turned on and off and can be made to blink.
+
+sysfs notes
+^^^^^^^^^^^
+
+The ThinkPad LED sysfs interface is described in detail by the LED class
+documentation, in Documentation/leds/leds-class.rst.
+
+The LEDs are named (in LED ID order, from 0 to 12):
+"tpacpi::power", "tpacpi:orange:batt", "tpacpi:green:batt",
+"tpacpi::dock_active", "tpacpi::bay_active", "tpacpi::dock_batt",
+"tpacpi::unknown_led", "tpacpi::standby", "tpacpi::dock_status1",
+"tpacpi::dock_status2", "tpacpi::unknown_led2", "tpacpi::unknown_led3",
+"tpacpi::thinkvantage".
+
+Due to limitations in the sysfs LED class, if the status of the LED
+indicators cannot be read due to an error, thinkpad-acpi will report it as
+a brightness of zero (same as LED off).
+
+If the thinkpad firmware doesn't support reading the current status,
+trying to read the current LED brightness will just return whatever
+brightness was last written to that attribute.
+
+These LEDs can blink using hardware acceleration.  To request that a
+ThinkPad indicator LED should blink in hardware accelerated mode, use the
+"timer" trigger, and leave the delay_on and delay_off parameters set to
+zero (to request hardware acceleration autodetection).
+
+LEDs that are known not to exist in a given ThinkPad model are not
+made available through the sysfs interface.  If you have a dock and you
+notice there are LEDs listed for your ThinkPad that do not exist (and
+are not in the dock), or if you notice that there are missing LEDs,
+a report to ibm-acpi-devel@lists.sourceforge.net is appreciated.
+
+
+ACPI sounds -- /proc/acpi/ibm/beep
+----------------------------------
+
+The BEEP method is used internally by the ACPI firmware to provide
+audible alerts in various situations. This feature allows the same
+sounds to be triggered manually.
+
+The commands are non-negative integer numbers::
+
+       echo <number> >/proc/acpi/ibm/beep
+
+The valid <number> range is 0 to 17. Not all numbers trigger sounds
+and the sounds vary from model to model. Here is the behavior on the
+X40:
+
+       - 0 - stop a sound in progress (but use 17 to stop 16)
+       - 2 - two beeps, pause, third beep ("low battery")
+       - 3 - single beep
+       - 4 - high, followed by low-pitched beep ("unable")
+       - 5 - single beep
+       - 6 - very high, followed by high-pitched beep ("AC/DC")
+       - 7 - high-pitched beep
+       - 9 - three short beeps
+       - 10 - very long beep
+       - 12 - low-pitched beep
+       - 15 - three high-pitched beeps repeating constantly, stop with 0
+       - 16 - one medium-pitched beep repeating constantly, stop with 17
+       - 17 - stop 16
+
+
+Temperature sensors
+-------------------
+
+procfs: /proc/acpi/ibm/thermal
+
+sysfs device attributes: (hwmon "thinkpad") temp*_input
+
+Most ThinkPads include six or more separate temperature sensors but only
+expose the CPU temperature through the standard ACPI methods.  This
+feature shows readings from up to eight different sensors on older
+ThinkPads, and up to sixteen different sensors on newer ThinkPads.
+
+For example, on the X40, a typical output may be:
+
+temperatures:
+       42 42 45 41 36 -128 33 -128
+
+On the T43/p, a typical output may be:
+
+temperatures:
+       48 48 36 52 38 -128 31 -128 48 52 48 -128 -128 -128 -128 -128
+
+The mapping of thermal sensors to physical locations varies depending on
+system-board model (and thus, on ThinkPad model).
+
+http://thinkwiki.org/wiki/Thermal_Sensors is a public wiki page that
+tries to track down these locations for various models.
+
+Most (newer?) models seem to follow this pattern:
+
+- 1:  CPU
+- 2:  (depends on model)
+- 3:  (depends on model)
+- 4:  GPU
+- 5:  Main battery: main sensor
+- 6:  Bay battery: main sensor
+- 7:  Main battery: secondary sensor
+- 8:  Bay battery: secondary sensor
+- 9-15: (depends on model)
+
+For the R51 (source: Thomas Gruber):
+
+- 2:  Mini-PCI
+- 3:  Internal HDD
+
+For the T43, T43/p (source: Shmidoax/Thinkwiki.org)
+http://thinkwiki.org/wiki/Thermal_Sensors#ThinkPad_T43.2C_T43p
+
+- 2:  System board, left side (near PCMCIA slot), reported as HDAPS temp
+- 3:  PCMCIA slot
+- 9:  MCH (northbridge) to DRAM Bus
+- 10: Clock-generator, mini-pci card and ICH (southbridge), under Mini-PCI
+      card, under touchpad
+- 11: Power regulator, underside of system board, below F2 key
+
+The A31 has a very atypical layout for the thermal sensors
+(source: Milos Popovic, http://thinkwiki.org/wiki/Thermal_Sensors#ThinkPad_A31)
+
+- 1:  CPU
+- 2:  Main Battery: main sensor
+- 3:  Power Converter
+- 4:  Bay Battery: main sensor
+- 5:  MCH (northbridge)
+- 6:  PCMCIA/ambient
+- 7:  Main Battery: secondary sensor
+- 8:  Bay Battery: secondary sensor
+
+
+Procfs notes
+^^^^^^^^^^^^
+
+       Readings from sensors that are not available return -128.
+       No commands can be written to this file.
+
+Sysfs notes
+^^^^^^^^^^^
+
+       Sensors that are not available return the ENXIO error.  This
+       status may change at runtime, as there are hotplug thermal
+       sensors, like those inside the batteries and docks.
+
+       thinkpad-acpi thermal sensors are reported through the hwmon
+       subsystem, and follow all of the hwmon guidelines at
+       Documentation/hwmon.
+
+EXPERIMENTAL: Embedded controller register dump
+-----------------------------------------------
+
+This feature is not included in the thinkpad driver anymore.
+Instead the EC can be accessed through /sys/kernel/debug/ec with
+a userspace tool which can be found here:
+ftp://ftp.suse.com/pub/people/trenn/sources/ec
+
+Use it to determine the register holding the fan
+speed on some models. To do that, do the following:
+
+       - make sure the battery is fully charged
+       - make sure the fan is running
+       - use above mentioned tool to read out the EC
+
+Often fan and temperature values vary between
+readings. Since temperatures don't change vary fast, you can take
+several quick dumps to eliminate them.
+
+You can use a similar method to figure out the meaning of other
+embedded controller registers - e.g. make sure nothing else changes
+except the charging or discharging battery to determine which
+registers contain the current battery capacity, etc. If you experiment
+with this, do send me your results (including some complete dumps with
+a description of the conditions when they were taken.)
+
+
+LCD brightness control
+----------------------
+
+procfs: /proc/acpi/ibm/brightness
+
+sysfs backlight device "thinkpad_screen"
+
+This feature allows software control of the LCD brightness on ThinkPad
+models which don't have a hardware brightness slider.
+
+It has some limitations: the LCD backlight cannot be actually turned
+on or off by this interface, it just controls the backlight brightness
+level.
+
+On IBM (and some of the earlier Lenovo) ThinkPads, the backlight control
+has eight brightness levels, ranging from 0 to 7.  Some of the levels
+may not be distinct.  Later Lenovo models that implement the ACPI
+display backlight brightness control methods have 16 levels, ranging
+from 0 to 15.
+
+For IBM ThinkPads, there are two interfaces to the firmware for direct
+brightness control, EC and UCMS (or CMOS).  To select which one should be
+used, use the brightness_mode module parameter: brightness_mode=1 selects
+EC mode, brightness_mode=2 selects UCMS mode, brightness_mode=3 selects EC
+mode with NVRAM backing (so that brightness changes are remembered across
+shutdown/reboot).
+
+The driver tries to select which interface to use from a table of
+defaults for each ThinkPad model.  If it makes a wrong choice, please
+report this as a bug, so that we can fix it.
+
+Lenovo ThinkPads only support brightness_mode=2 (UCMS).
+
+When display backlight brightness controls are available through the
+standard ACPI interface, it is best to use it instead of this direct
+ThinkPad-specific interface.  The driver will disable its native
+backlight brightness control interface if it detects that the standard
+ACPI interface is available in the ThinkPad.
+
+If you want to use the thinkpad-acpi backlight brightness control
+instead of the generic ACPI video backlight brightness control for some
+reason, you should use the acpi_backlight=vendor kernel parameter.
+
+The brightness_enable module parameter can be used to control whether
+the LCD brightness control feature will be enabled when available.
+brightness_enable=0 forces it to be disabled.  brightness_enable=1
+forces it to be enabled when available, even if the standard ACPI
+interface is also available.
+
+Procfs notes
+^^^^^^^^^^^^
+
+The available commands are::
+
+       echo up   >/proc/acpi/ibm/brightness
+       echo down >/proc/acpi/ibm/brightness
+       echo 'level <level>' >/proc/acpi/ibm/brightness
+
+Sysfs notes
+^^^^^^^^^^^
+
+The interface is implemented through the backlight sysfs class, which is
+poorly documented at this time.
+
+Locate the thinkpad_screen device under /sys/class/backlight, and inside
+it there will be the following attributes:
+
+       max_brightness:
+               Reads the maximum brightness the hardware can be set to.
+               The minimum is always zero.
+
+       actual_brightness:
+               Reads what brightness the screen is set to at this instant.
+
+       brightness:
+               Writes request the driver to change brightness to the
+               given value.  Reads will tell you what brightness the
+               driver is trying to set the display to when "power" is set
+               to zero and the display has not been dimmed by a kernel
+               power management event.
+
+       power:
+               power management mode, where 0 is "display on", and 1 to 3
+               will dim the display backlight to brightness level 0
+               because thinkpad-acpi cannot really turn the backlight
+               off.  Kernel power management events can temporarily
+               increase the current power management level, i.e. they can
+               dim the display.
+
+
+WARNING:
+
+    Whatever you do, do NOT ever call thinkpad-acpi backlight-level change
+    interface and the ACPI-based backlight level change interface
+    (available on newer BIOSes, and driven by the Linux ACPI video driver)
+    at the same time.  The two will interact in bad ways, do funny things,
+    and maybe reduce the life of the backlight lamps by needlessly kicking
+    its level up and down at every change.
+
+
+Volume control (Console Audio control)
+--------------------------------------
+
+procfs: /proc/acpi/ibm/volume
+
+ALSA: "ThinkPad Console Audio Control", default ID: "ThinkPadEC"
+
+NOTE: by default, the volume control interface operates in read-only
+mode, as it is supposed to be used for on-screen-display purposes.
+The read/write mode can be enabled through the use of the
+"volume_control=1" module parameter.
+
+NOTE: distros are urged to not enable volume_control by default, this
+should be done by the local admin only.  The ThinkPad UI is for the
+console audio control to be done through the volume keys only, and for
+the desktop environment to just provide on-screen-display feedback.
+Software volume control should be done only in the main AC97/HDA
+mixer.
+
+
+About the ThinkPad Console Audio control
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ThinkPads have a built-in amplifier and muting circuit that drives the
+console headphone and speakers.  This circuit is after the main AC97
+or HDA mixer in the audio path, and under exclusive control of the
+firmware.
+
+ThinkPads have three special hotkeys to interact with the console
+audio control: volume up, volume down and mute.
+
+It is worth noting that the normal way the mute function works (on
+ThinkPads that do not have a "mute LED") is:
+
+1. Press mute to mute.  It will *always* mute, you can press it as
+   many times as you want, and the sound will remain mute.
+
+2. Press either volume key to unmute the ThinkPad (it will _not_
+   change the volume, it will just unmute).
+
+This is a very superior design when compared to the cheap software-only
+mute-toggle solution found on normal consumer laptops:  you can be
+absolutely sure the ThinkPad will not make noise if you press the mute
+button, no matter the previous state.
+
+The IBM ThinkPads, and the earlier Lenovo ThinkPads have variable-gain
+amplifiers driving the speakers and headphone output, and the firmware
+also handles volume control for the headphone and speakers on these
+ThinkPads without any help from the operating system (this volume
+control stage exists after the main AC97 or HDA mixer in the audio
+path).
+
+The newer Lenovo models only have firmware mute control, and depend on
+the main HDA mixer to do volume control (which is done by the operating
+system).  In this case, the volume keys are filtered out for unmute
+key press (there are some firmware bugs in this area) and delivered as
+normal key presses to the operating system (thinkpad-acpi is not
+involved).
+
+
+The ThinkPad-ACPI volume control
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The preferred way to interact with the Console Audio control is the
+ALSA interface.
+
+The legacy procfs interface allows one to read the current state,
+and if volume control is enabled, accepts the following commands::
+
+       echo up   >/proc/acpi/ibm/volume
+       echo down >/proc/acpi/ibm/volume
+       echo mute >/proc/acpi/ibm/volume
+       echo unmute >/proc/acpi/ibm/volume
+       echo 'level <level>' >/proc/acpi/ibm/volume
+
+The <level> number range is 0 to 14 although not all of them may be
+distinct. To unmute the volume after the mute command, use either the
+up or down command (the level command will not unmute the volume), or
+the unmute command.
+
+You can use the volume_capabilities parameter to tell the driver
+whether your thinkpad has volume control or mute-only control:
+volume_capabilities=1 for mixers with mute and volume control,
+volume_capabilities=2 for mixers with only mute control.
+
+If the driver misdetects the capabilities for your ThinkPad model,
+please report this to ibm-acpi-devel@lists.sourceforge.net, so that we
+can update the driver.
+
+There are two strategies for volume control.  To select which one
+should be used, use the volume_mode module parameter: volume_mode=1
+selects EC mode, and volume_mode=3 selects EC mode with NVRAM backing
+(so that volume/mute changes are remembered across shutdown/reboot).
+
+The driver will operate in volume_mode=3 by default. If that does not
+work well on your ThinkPad model, please report this to
+ibm-acpi-devel@lists.sourceforge.net.
+
+The driver supports the standard ALSA module parameters.  If the ALSA
+mixer is disabled, the driver will disable all volume functionality.
+
+
+Fan control and monitoring: fan speed, fan enable/disable
+---------------------------------------------------------
+
+procfs: /proc/acpi/ibm/fan
+
+sysfs device attributes: (hwmon "thinkpad") fan1_input, pwm1, pwm1_enable, fan2_input
+
+sysfs hwmon driver attributes: fan_watchdog
+
+NOTE NOTE NOTE:
+   fan control operations are disabled by default for
+   safety reasons.  To enable them, the module parameter "fan_control=1"
+   must be given to thinkpad-acpi.
+
+This feature attempts to show the current fan speed, control mode and
+other fan data that might be available.  The speed is read directly
+from the hardware registers of the embedded controller.  This is known
+to work on later R, T, X and Z series ThinkPads but may show a bogus
+value on other models.
+
+Some Lenovo ThinkPads support a secondary fan.  This fan cannot be
+controlled separately, it shares the main fan control.
+
+Fan levels
+^^^^^^^^^^
+
+Most ThinkPad fans work in "levels" at the firmware interface.  Level 0
+stops the fan.  The higher the level, the higher the fan speed, although
+adjacent levels often map to the same fan speed.  7 is the highest
+level, where the fan reaches the maximum recommended speed.
+
+Level "auto" means the EC changes the fan level according to some
+internal algorithm, usually based on readings from the thermal sensors.
+
+There is also a "full-speed" level, also known as "disengaged" level.
+In this level, the EC disables the speed-locked closed-loop fan control,
+and drives the fan as fast as it can go, which might exceed hardware
+limits, so use this level with caution.
+
+The fan usually ramps up or down slowly from one speed to another, and
+it is normal for the EC to take several seconds to react to fan
+commands.  The full-speed level may take up to two minutes to ramp up to
+maximum speed, and in some ThinkPads, the tachometer readings go stale
+while the EC is transitioning to the full-speed level.
+
+WARNING WARNING WARNING: do not leave the fan disabled unless you are
+monitoring all of the temperature sensor readings and you are ready to
+enable it if necessary to avoid overheating.
+
+An enabled fan in level "auto" may stop spinning if the EC decides the
+ThinkPad is cool enough and doesn't need the extra airflow.  This is
+normal, and the EC will spin the fan up if the various thermal readings
+rise too much.
+
+On the X40, this seems to depend on the CPU and HDD temperatures.
+Specifically, the fan is turned on when either the CPU temperature
+climbs to 56 degrees or the HDD temperature climbs to 46 degrees.  The
+fan is turned off when the CPU temperature drops to 49 degrees and the
+HDD temperature drops to 41 degrees.  These thresholds cannot
+currently be controlled.
+
+The ThinkPad's ACPI DSDT code will reprogram the fan on its own when
+certain conditions are met.  It will override any fan programming done
+through thinkpad-acpi.
+
+The thinkpad-acpi kernel driver can be programmed to revert the fan
+level to a safe setting if userspace does not issue one of the procfs
+fan commands: "enable", "disable", "level" or "watchdog", or if there
+are no writes to pwm1_enable (or to pwm1 *if and only if* pwm1_enable is
+set to 1, manual mode) within a configurable amount of time of up to
+120 seconds.  This functionality is called fan safety watchdog.
+
+Note that the watchdog timer stops after it enables the fan.  It will be
+rearmed again automatically (using the same interval) when one of the
+above mentioned fan commands is received.  The fan watchdog is,
+therefore, not suitable to protect against fan mode changes made through
+means other than the "enable", "disable", and "level" procfs fan
+commands, or the hwmon fan control sysfs interface.
+
+Procfs notes
+^^^^^^^^^^^^
+
+The fan may be enabled or disabled with the following commands::
+
+       echo enable  >/proc/acpi/ibm/fan
+       echo disable >/proc/acpi/ibm/fan
+
+Placing a fan on level 0 is the same as disabling it.  Enabling a fan
+will try to place it in a safe level if it is too slow or disabled.
+
+The fan level can be controlled with the command::
+
+       echo 'level <level>' > /proc/acpi/ibm/fan
+
+Where <level> is an integer from 0 to 7, or one of the words "auto" or
+"full-speed" (without the quotes).  Not all ThinkPads support the "auto"
+and "full-speed" levels.  The driver accepts "disengaged" as an alias for
+"full-speed", and reports it as "disengaged" for backwards
+compatibility.
+
+On the X31 and X40 (and ONLY on those models), the fan speed can be
+controlled to a certain degree.  Once the fan is running, it can be
+forced to run faster or slower with the following command::
+
+       echo 'speed <speed>' > /proc/acpi/ibm/fan
+
+The sustainable range of fan speeds on the X40 appears to be from about
+3700 to about 7350. Values outside this range either do not have any
+effect or the fan speed eventually settles somewhere in that range.  The
+fan cannot be stopped or started with this command.  This functionality
+is incomplete, and not available through the sysfs interface.
+
+To program the safety watchdog, use the "watchdog" command::
+
+       echo 'watchdog <interval in seconds>' > /proc/acpi/ibm/fan
+
+If you want to disable the watchdog, use 0 as the interval.
+
+Sysfs notes
+^^^^^^^^^^^
+
+The sysfs interface follows the hwmon subsystem guidelines for the most
+part, and the exception is the fan safety watchdog.
+
+Writes to any of the sysfs attributes may return the EINVAL error if
+that operation is not supported in a given ThinkPad or if the parameter
+is out-of-bounds, and EPERM if it is forbidden.  They may also return
+EINTR (interrupted system call), and EIO (I/O error while trying to talk
+to the firmware).
+
+Features not yet implemented by the driver return ENOSYS.
+
+hwmon device attribute pwm1_enable:
+       - 0: PWM offline (fan is set to full-speed mode)
+       - 1: Manual PWM control (use pwm1 to set fan level)
+       - 2: Hardware PWM control (EC "auto" mode)
+       - 3: reserved (Software PWM control, not implemented yet)
+
+       Modes 0 and 2 are not supported by all ThinkPads, and the
+       driver is not always able to detect this.  If it does know a
+       mode is unsupported, it will return -EINVAL.
+
+hwmon device attribute pwm1:
+       Fan level, scaled from the firmware values of 0-7 to the hwmon
+       scale of 0-255.  0 means fan stopped, 255 means highest normal
+       speed (level 7).
+
+       This attribute only commands the fan if pmw1_enable is set to 1
+       (manual PWM control).
+
+hwmon device attribute fan1_input:
+       Fan tachometer reading, in RPM.  May go stale on certain
+       ThinkPads while the EC transitions the PWM to offline mode,
+       which can take up to two minutes.  May return rubbish on older
+       ThinkPads.
+
+hwmon device attribute fan2_input:
+       Fan tachometer reading, in RPM, for the secondary fan.
+       Available only on some ThinkPads.  If the secondary fan is
+       not installed, will always read 0.
+
+hwmon driver attribute fan_watchdog:
+       Fan safety watchdog timer interval, in seconds.  Minimum is
+       1 second, maximum is 120 seconds.  0 disables the watchdog.
+
+To stop the fan: set pwm1 to zero, and pwm1_enable to 1.
+
+To start the fan in a safe mode: set pwm1_enable to 2.  If that fails
+with EINVAL, try to set pwm1_enable to 1 and pwm1 to at least 128 (255
+would be the safest choice, though).
+
+
+WAN
+---
+
+procfs: /proc/acpi/ibm/wan
+
+sysfs device attribute: wwan_enable (deprecated)
+
+sysfs rfkill class: switch "tpacpi_wwan_sw"
+
+This feature shows the presence and current state of the built-in
+Wireless WAN device.
+
+If the ThinkPad supports it, the WWAN state is stored in NVRAM,
+so it is kept across reboots and power-off.
+
+It was tested on a Lenovo ThinkPad X60. It should probably work on other
+ThinkPad models which come with this module installed.
+
+Procfs notes
+^^^^^^^^^^^^
+
+If the W-WAN card is installed, the following commands can be used::
+
+       echo enable > /proc/acpi/ibm/wan
+       echo disable > /proc/acpi/ibm/wan
+
+Sysfs notes
+^^^^^^^^^^^
+
+       If the W-WAN card is installed, it can be enabled /
+       disabled through the "wwan_enable" thinkpad-acpi device
+       attribute, and its current status can also be queried.
+
+       enable:
+               - 0: disables WWAN card / WWAN card is disabled
+               - 1: enables WWAN card / WWAN card is enabled.
+
+       Note: this interface has been superseded by the generic rfkill
+       class.  It has been deprecated, and it will be removed in year
+       2010.
+
+       rfkill controller switch "tpacpi_wwan_sw": refer to
+       Documentation/driver-api/rfkill.rst for details.
+
+
+EXPERIMENTAL: UWB
+-----------------
+
+This feature is considered EXPERIMENTAL because it has not been extensively
+tested and validated in various ThinkPad models yet.  The feature may not
+work as expected. USE WITH CAUTION! To use this feature, you need to supply
+the experimental=1 parameter when loading the module.
+
+sysfs rfkill class: switch "tpacpi_uwb_sw"
+
+This feature exports an rfkill controller for the UWB device, if one is
+present and enabled in the BIOS.
+
+Sysfs notes
+^^^^^^^^^^^
+
+       rfkill controller switch "tpacpi_uwb_sw": refer to
+       Documentation/driver-api/rfkill.rst for details.
+
+Adaptive keyboard
+-----------------
+
+sysfs device attribute: adaptive_kbd_mode
+
+This sysfs attribute controls the keyboard "face" that will be shown on the
+Lenovo X1 Carbon 2nd gen (2014)'s adaptive keyboard. The value can be read
+and set.
+
+- 1 = Home mode
+- 2 = Web-browser mode
+- 3 = Web-conference mode
+- 4 = Function mode
+- 5 = Layflat mode
+
+For more details about which buttons will appear depending on the mode, please
+review the laptop's user guide:
+http://www.lenovo.com/shop/americas/content/user_guides/x1carbon_2_ug_en.pdf
+
+Multiple Commands, Module Parameters
+------------------------------------
+
+Multiple commands can be written to the proc files in one shot by
+separating them with commas, for example::
+
+       echo enable,0xffff > /proc/acpi/ibm/hotkey
+       echo lcd_disable,crt_enable > /proc/acpi/ibm/video
+
+Commands can also be specified when loading the thinkpad-acpi module,
+for example::
+
+       modprobe thinkpad_acpi hotkey=enable,0xffff video=auto_disable
+
+
+Enabling debugging output
+-------------------------
+
+The module takes a debug parameter which can be used to selectively
+enable various classes of debugging output, for example::
+
+        modprobe thinkpad_acpi debug=0xffff
+
+will enable all debugging output classes.  It takes a bitmask, so
+to enable more than one output class, just add their values.
+
+       =============           ======================================
+       Debug bitmask           Description
+       =============           ======================================
+       0x8000                  Disclose PID of userspace programs
+                               accessing some functions of the driver
+       0x0001                  Initialization and probing
+       0x0002                  Removal
+       0x0004                  RF Transmitter control (RFKILL)
+                               (bluetooth, WWAN, UWB...)
+       0x0008                  HKEY event interface, hotkeys
+       0x0010                  Fan control
+       0x0020                  Backlight brightness
+       0x0040                  Audio mixer/volume control
+       =============           ======================================
+
+There is also a kernel build option to enable more debugging
+information, which may be necessary to debug driver problems.
+
+The level of debugging information output by the driver can be changed
+at runtime through sysfs, using the driver attribute debug_level.  The
+attribute takes the same bitmask as the debug module parameter above.
+
+
+Force loading of module
+-----------------------
+
+If thinkpad-acpi refuses to detect your ThinkPad, you can try to specify
+the module parameter force_load=1.  Regardless of whether this works or
+not, please contact ibm-acpi-devel@lists.sourceforge.net with a report.
+
+
+Sysfs interface changelog
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+=========      ===============================================================
+0x000100:      Initial sysfs support, as a single platform driver and
+               device.
+0x000200:      Hot key support for 32 hot keys, and radio slider switch
+               support.
+0x010000:      Hot keys are now handled by default over the input
+               layer, the radio switch generates input event EV_RADIO,
+               and the driver enables hot key handling by default in
+               the firmware.
+
+0x020000:      ABI fix: added a separate hwmon platform device and
+               driver, which must be located by name (thinkpad)
+               and the hwmon class for libsensors4 (lm-sensors 3)
+               compatibility.  Moved all hwmon attributes to this
+               new platform device.
+
+0x020100:      Marker for thinkpad-acpi with hot key NVRAM polling
+               support.  If you must, use it to know you should not
+               start a userspace NVRAM poller (allows to detect when
+               NVRAM is compiled out by the user because it is
+               unneeded/undesired in the first place).
+0x020101:      Marker for thinkpad-acpi with hot key NVRAM polling
+               and proper hotkey_mask semantics (version 8 of the
+               NVRAM polling patch).  Some development snapshots of
+               0.18 had an earlier version that did strange things
+               to hotkey_mask.
+
+0x020200:      Add poll()/select() support to the following attributes:
+               hotkey_radio_sw, wakeup_hotunplug_complete, wakeup_reason
+
+0x020300:      hotkey enable/disable support removed, attributes
+               hotkey_bios_enabled and hotkey_enable deprecated and
+               marked for removal.
+
+0x020400:      Marker for 16 LEDs support.  Also, LEDs that are known
+               to not exist in a given model are not registered with
+               the LED sysfs class anymore.
+
+0x020500:      Updated hotkey driver, hotkey_mask is always available
+               and it is always able to disable hot keys.  Very old
+               thinkpads are properly supported.  hotkey_bios_mask
+               is deprecated and marked for removal.
+
+0x020600:      Marker for backlight change event support.
+
+0x020700:      Support for mute-only mixers.
+               Volume control in read-only mode by default.
+               Marker for ALSA mixer support.
+
+0x030000:      Thermal and fan sysfs attributes were moved to the hwmon
+               device instead of being attached to the backing platform
+               device.
+=========      ===============================================================
diff --git a/Documentation/admin-guide/laptops/toshiba_haps.rst b/Documentation/admin-guide/laptops/toshiba_haps.rst
new file mode 100644 (file)
index 0000000..d28b6c3
--- /dev/null
@@ -0,0 +1,87 @@
+====================================
+Toshiba HDD Active Protection Sensor
+====================================
+
+Kernel driver: toshiba_haps
+
+Author: Azael Avalos <coproscefalo@gmail.com>
+
+
+.. 0. Contents
+
+   1. Description
+   2. Interface
+   3. Accelerometer axes
+   4. Supported devices
+   5. Usage
+
+
+1. Description
+--------------
+
+This driver provides support for the accelerometer found in various Toshiba
+laptops, being called "Toshiba HDD Protection - Shock Sensor" officially,
+and detects laptops automatically with this device.
+On Windows, Toshiba provided software monitors this device and provides
+automatic HDD protection (head unload) on sudden moves or harsh vibrations,
+however, this driver only provides a notification via a sysfs file to let
+userspace tools or daemons act accordingly, as well as providing a sysfs
+file to set the desired protection level or sensor sensibility.
+
+
+2. Interface
+------------
+
+This device comes with 3 methods:
+
+====   =====================================================================
+_STA    Checks existence of the device, returning Zero if the device does not
+       exists or is not supported.
+PTLV    Sets the desired protection level.
+RSSS    Shuts down the HDD protection interface for a few seconds,
+       then restores normal operation.
+====   =====================================================================
+
+Note:
+  The presence of Solid State Drives (SSD) can make this driver to fail loading,
+  given the fact that such drives have no movable parts, and thus, not requiring
+  any "protection" as well as failing during the evaluation of the _STA method
+  found under this device.
+
+
+3. Accelerometer axes
+---------------------
+
+This device does not report any axes, however, to query the sensor position
+a couple HCI (Hardware Configuration Interface) calls (0x6D and 0xA6) are
+provided to query such information, handled by the kernel module toshiba_acpi
+since kernel version 3.15.
+
+
+4. Supported devices
+--------------------
+
+This driver binds itself to the ACPI device TOS620A, and any Toshiba laptop
+with this device is supported, given the fact that they have the presence of
+conventional HDD and not only SSD, or a combination of both HDD and SSD.
+
+
+5. Usage
+--------
+
+The sysfs files under /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS620A:00/ are:
+
+================   ============================================================
+protection_level   The protection_level is readable and writeable, and
+                  provides a way to let userspace query the current protection
+                  level, as well as set the desired protection level, the
+                  available protection levels are::
+
+                    ============   =======   ==========   ========
+                    0 - Disabled   1 - Low   2 - Medium   3 - High
+                    ============   =======   ==========   ========
+
+reset_protection   The reset_protection entry is writeable only, being "1"
+                  the only parameter it accepts, it is used to trigger
+                  a reset of the protection interface.
+================   ============================================================
diff --git a/Documentation/admin-guide/lcd-panel-cgram.rst b/Documentation/admin-guide/lcd-panel-cgram.rst
new file mode 100644 (file)
index 0000000..a3eb00c
--- /dev/null
@@ -0,0 +1,27 @@
+======================================
+Parallel port LCD/Keypad Panel support
+======================================
+
+Some LCDs allow you to define up to 8 characters, mapped to ASCII
+characters 0 to 7. The escape code to define a new character is
+'\e[LG' followed by one digit from 0 to 7, representing the character
+number, and up to 8 couples of hex digits terminated by a semi-colon
+(';'). Each couple of digits represents a line, with 1-bits for each
+illuminated pixel with LSB on the right. Lines are numbered from the
+top of the character to the bottom. On a 5x7 matrix, only the 5 lower
+bits of the 7 first bytes are used for each character. If the string
+is incomplete, only complete lines will be redefined. Here are some
+examples::
+
+  printf "\e[LG0010101050D1F0C04;"  => 0 = [enter]
+  printf "\e[LG1040E1F0000000000;"  => 1 = [up]
+  printf "\e[LG2000000001F0E0400;"  => 2 = [down]
+  printf "\e[LG3040E1F001F0E0400;"  => 3 = [up-down]
+  printf "\e[LG40002060E1E0E0602;"  => 4 = [left]
+  printf "\e[LG500080C0E0F0E0C08;"  => 5 = [right]
+  printf "\e[LG60016051516141400;"  => 6 = "IP"
+
+  printf "\e[LG00103071F1F070301;"  => big speaker
+  printf "\e[LG00002061E1E060200;"  => small speaker
+
+Willy
diff --git a/Documentation/admin-guide/mm/cma_debugfs.rst b/Documentation/admin-guide/mm/cma_debugfs.rst
new file mode 100644 (file)
index 0000000..4e06ffa
--- /dev/null
@@ -0,0 +1,25 @@
+=====================
+CMA Debugfs Interface
+=====================
+
+The CMA debugfs interface is useful to retrieve basic information out of the
+different CMA areas and to test allocation/release in each of the areas.
+
+Each CMA zone represents a directory under <debugfs>/cma/, indexed by the
+kernel's CMA index. So the first CMA zone would be:
+
+       <debugfs>/cma/cma-0
+
+The structure of the files created under that directory is as follows:
+
+ - [RO] base_pfn: The base PFN (Page Frame Number) of the zone.
+ - [RO] count: Amount of memory in the CMA area.
+ - [RO] order_per_bit: Order of pages represented by one bit.
+ - [RO] bitmap: The bitmap of page states in the zone.
+ - [WO] alloc: Allocate N pages from that CMA area. For example::
+
+       echo 5 > <debugfs>/cma/cma-2/alloc
+
+would try to allocate 5 pages from the cma-2 area.
+
+ - [WO] free: Free N pages from that CMA area, similar to the above.
index ddf8d8d..11db464 100644 (file)
@@ -11,7 +11,7 @@ processes address space and many other cool things.
 Linux memory management is a complex system with many configurable
 settings. Most of these settings are available via ``/proc``
 filesystem and can be quired and adjusted using ``sysctl``. These APIs
-are described in Documentation/sysctl/vm.txt and in `man 5 proc`_.
+are described in Documentation/admin-guide/sysctl/vm.rst and in `man 5 proc`_.
 
 .. _man 5 proc: http://man7.org/linux/man-pages/man5/proc.5.html
 
@@ -26,6 +26,7 @@ the Linux memory management.
    :maxdepth: 1
 
    concepts
+   cma_debugfs
    hugetlbpage
    idle_page_tracking
    ksm
index 9303786..874eb0c 100644 (file)
@@ -59,7 +59,7 @@ MADV_UNMERGEABLE is applied to a range which was never MADV_MERGEABLE.
 
 If a region of memory must be split into at least one new MADV_MERGEABLE
 or MADV_UNMERGEABLE region, the madvise may return ENOMEM if the process
-will exceed ``vm.max_map_count`` (see Documentation/sysctl/vm.txt).
+will exceed ``vm.max_map_count`` (see Documentation/admin-guide/sysctl/vm.rst).
 
 Like other madvise calls, they are intended for use on mapped areas of
 the user address space: they will report ENOMEM if the specified range
index 546f174..8463f55 100644 (file)
@@ -15,7 +15,7 @@ document attempts to describe the concepts and APIs of the 2.6 memory policy
 support.
 
 Memory policies should not be confused with cpusets
-(``Documentation/cgroup-v1/cpusets.rst``)
+(``Documentation/admin-guide/cgroup-v1/cpusets.rst``)
 which is an administrative mechanism for restricting the nodes from which
 memory may be allocated by a set of processes. Memory policies are a
 programming interface that a NUMA-aware application can take advantage of.  When
diff --git a/Documentation/admin-guide/namespaces/compatibility-list.rst b/Documentation/admin-guide/namespaces/compatibility-list.rst
new file mode 100644 (file)
index 0000000..318800b
--- /dev/null
@@ -0,0 +1,43 @@
+=============================
+Namespaces compatibility list
+=============================
+
+This document contains the information about the problems user
+may have when creating tasks living in different namespaces.
+
+Here's the summary. This matrix shows the known problems, that
+occur when tasks share some namespace (the columns) while living
+in different other namespaces (the rows):
+
+====   ===     ===     ===     ===     ====    ===
+-      UTS     IPC     VFS     PID     User    Net
+====   ===     ===     ===     ===     ====    ===
+UTS     X
+IPC             X       1
+VFS                     X
+PID             1       1       X
+User            2       2               X
+Net                                             X
+====   ===     ===     ===     ===     ====    ===
+
+1. Both the IPC and the PID namespaces provide IDs to address
+   object inside the kernel. E.g. semaphore with IPCID or
+   process group with pid.
+
+   In both cases, tasks shouldn't try exposing this ID to some
+   other task living in a different namespace via a shared filesystem
+   or IPC shmem/message. The fact is that this ID is only valid
+   within the namespace it was obtained in and may refer to some
+   other object in another namespace.
+
+2. Intentionally, two equal user IDs in different user namespaces
+   should not be equal from the VFS point of view. In other
+   words, user 10 in one user namespace shouldn't have the same
+   access permissions to files, belonging to user 10 in another
+   namespace.
+
+   The same is true for the IPC namespaces being shared - two users
+   from different user namespaces should not access the same IPC objects
+   even having equal UIDs.
+
+   But currently this is not so.
diff --git a/Documentation/admin-guide/namespaces/index.rst b/Documentation/admin-guide/namespaces/index.rst
new file mode 100644 (file)
index 0000000..384f2e0
--- /dev/null
@@ -0,0 +1,11 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==========
+Namespaces
+==========
+
+.. toctree::
+   :maxdepth: 1
+
+   compatibility-list
+   resource-control
diff --git a/Documentation/admin-guide/namespaces/resource-control.rst b/Documentation/admin-guide/namespaces/resource-control.rst
new file mode 100644 (file)
index 0000000..369556e
--- /dev/null
@@ -0,0 +1,18 @@
+===========================
+Namespaces research control
+===========================
+
+There are a lot of kinds of objects in the kernel that don't have
+individual limits or that have limits that are ineffective when a set
+of processes is allowed to switch user ids.  With user namespaces
+enabled in a kernel for people who don't trust their users or their
+users programs to play nice this problems becomes more acute.
+
+Therefore it is recommended that memory control groups be enabled in
+kernels that enable user namespaces, and it is further recommended
+that userspace configure memory control groups to limit how much
+memory user's they don't trust to play nice can use.
+
+Memory control groups can be configured by installing the libcgroup
+package present on most distros editing /etc/cgrules.conf,
+/etc/cgconfig.conf and setting up libpam-cgroup.
diff --git a/Documentation/admin-guide/perf/arm-ccn.rst b/Documentation/admin-guide/perf/arm-ccn.rst
new file mode 100644 (file)
index 0000000..832b0c6
--- /dev/null
@@ -0,0 +1,61 @@
+==========================
+ARM Cache Coherent Network
+==========================
+
+CCN-504 is a ring-bus interconnect consisting of 11 crosspoints
+(XPs), with each crosspoint supporting up to two device ports,
+so nodes (devices) 0 and 1 are connected to crosspoint 0,
+nodes 2 and 3 to crosspoint 1 etc.
+
+PMU (perf) driver
+-----------------
+
+The CCN driver registers a perf PMU driver, which provides
+description of available events and configuration options
+in sysfs, see /sys/bus/event_source/devices/ccn*.
+
+The "format" directory describes format of the config, config1
+and config2 fields of the perf_event_attr structure. The "events"
+directory provides configuration templates for all documented
+events, that can be used with perf tool. For example "xp_valid_flit"
+is an equivalent of "type=0x8,event=0x4". Other parameters must be
+explicitly specified.
+
+For events originating from device, "node" defines its index.
+
+Crosspoint PMU events require "xp" (index), "bus" (bus number)
+and "vc" (virtual channel ID).
+
+Crosspoint watchpoint-based events (special "event" value 0xfe)
+require "xp" and "vc" as as above plus "port" (device port index),
+"dir" (transmit/receive direction), comparator values ("cmp_l"
+and "cmp_h") and "mask", being index of the comparator mask.
+
+Masks are defined separately from the event description
+(due to limited number of the config values) in the "cmp_mask"
+directory, with first 8 configurable by user and additional
+4 hardcoded for the most frequent use cases.
+
+Cycle counter is described by a "type" value 0xff and does
+not require any other settings.
+
+The driver also provides a "cpumask" sysfs attribute, which contains
+a single CPU ID, of the processor which will be used to handle all
+the CCN PMU events. It is recommended that the user space tools
+request the events on this processor (if not, the perf_event->cpu value
+will be overwritten anyway). In case of this processor being offlined,
+the events are migrated to another one and the attribute is updated.
+
+Example of perf tool use::
+
+  / # perf list | grep ccn
+    ccn/cycles/                                        [Kernel PMU event]
+  <...>
+    ccn/xp_valid_flit,xp=?,port=?,vc=?,dir=?/          [Kernel PMU event]
+  <...>
+
+  / # perf stat -a -e ccn/cycles/,ccn/xp_valid_flit,xp=1,port=0,vc=1,dir=1/ \
+                                                                         sleep 1
+
+The driver does not support sampling, therefore "perf record" will
+not work. Per-task (without "-a") perf sessions are not supported.
diff --git a/Documentation/admin-guide/perf/arm_dsu_pmu.rst b/Documentation/admin-guide/perf/arm_dsu_pmu.rst
new file mode 100644 (file)
index 0000000..7fd34db
--- /dev/null
@@ -0,0 +1,29 @@
+==================================
+ARM DynamIQ Shared Unit (DSU) PMU
+==================================
+
+ARM DynamIQ Shared Unit integrates one or more cores with an L3 memory system,
+control logic and external interfaces to form a multicore cluster. The PMU
+allows counting the various events related to the L3 cache, Snoop Control Unit
+etc, using 32bit independent counters. It also provides a 64bit cycle counter.
+
+The PMU can only be accessed via CPU system registers and are common to the
+cores connected to the same DSU. Like most of the other uncore PMUs, DSU
+PMU doesn't support process specific events and cannot be used in sampling mode.
+
+The DSU provides a bitmap for a subset of implemented events via hardware
+registers. There is no way for the driver to determine if the other events
+are available or not. Hence the driver exposes only those events advertised
+by the DSU, in "events" directory under::
+
+  /sys/bus/event_sources/devices/arm_dsu_<N>/
+
+The user should refer to the TRM of the product to figure out the supported events
+and use the raw event code for the unlisted events.
+
+The driver also exposes the CPUs connected to the DSU instance in "associated_cpus".
+
+
+e.g usage::
+
+       perf stat -a -e arm_dsu_0/cycles/
diff --git a/Documentation/admin-guide/perf/hisi-pmu.rst b/Documentation/admin-guide/perf/hisi-pmu.rst
new file mode 100644 (file)
index 0000000..404a5c3
--- /dev/null
@@ -0,0 +1,60 @@
+======================================================
+HiSilicon SoC uncore Performance Monitoring Unit (PMU)
+======================================================
+
+The HiSilicon SoC chip includes various independent system device PMUs
+such as L3 cache (L3C), Hydra Home Agent (HHA) and DDRC. These PMUs are
+independent and have hardware logic to gather statistics and performance
+information.
+
+The HiSilicon SoC encapsulates multiple CPU and IO dies. Each CPU cluster
+(CCL) is made up of 4 cpu cores sharing one L3 cache; each CPU die is
+called Super CPU cluster (SCCL) and is made up of 6 CCLs. Each SCCL has
+two HHAs (0 - 1) and four DDRCs (0 - 3), respectively.
+
+HiSilicon SoC uncore PMU driver
+-------------------------------
+
+Each device PMU has separate registers for event counting, control and
+interrupt, and the PMU driver shall register perf PMU drivers like L3C,
+HHA and DDRC etc. The available events and configuration options shall
+be described in the sysfs, see:
+
+/sys/devices/hisi_sccl{X}_<l3c{Y}/hha{Y}/ddrc{Y}>/, or
+/sys/bus/event_source/devices/hisi_sccl{X}_<l3c{Y}/hha{Y}/ddrc{Y}>.
+The "perf list" command shall list the available events from sysfs.
+
+Each L3C, HHA and DDRC is registered as a separate PMU with perf. The PMU
+name will appear in event listing as hisi_sccl<sccl-id>_module<index-id>.
+where "sccl-id" is the identifier of the SCCL and "index-id" is the index of
+module.
+
+e.g. hisi_sccl3_l3c0/rd_hit_cpipe is READ_HIT_CPIPE event of L3C index #0 in
+SCCL ID #3.
+
+e.g. hisi_sccl1_hha0/rx_operations is RX_OPERATIONS event of HHA index #0 in
+SCCL ID #1.
+
+The driver also provides a "cpumask" sysfs attribute, which shows the CPU core
+ID used to count the uncore PMU event.
+
+Example usage of perf::
+
+  $# perf list
+  hisi_sccl3_l3c0/rd_hit_cpipe/ [kernel PMU event]
+  ------------------------------------------
+  hisi_sccl3_l3c0/wr_hit_cpipe/ [kernel PMU event]
+  ------------------------------------------
+  hisi_sccl1_l3c0/rd_hit_cpipe/ [kernel PMU event]
+  ------------------------------------------
+  hisi_sccl1_l3c0/wr_hit_cpipe/ [kernel PMU event]
+  ------------------------------------------
+
+  $# perf stat -a -e hisi_sccl3_l3c0/rd_hit_cpipe/ sleep 5
+  $# perf stat -a -e hisi_sccl3_l3c0/config=0x02/ sleep 5
+
+The current driver does not support sampling. So "perf record" is unsupported.
+Also attach to a task is unsupported as the events are all uncore.
+
+Note: Please contact the maintainer for a complete list of events supported for
+the PMU devices in the SoC and its information if needed.
diff --git a/Documentation/admin-guide/perf/index.rst b/Documentation/admin-guide/perf/index.rst
new file mode 100644 (file)
index 0000000..ee4bfd2
--- /dev/null
@@ -0,0 +1,16 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===========================
+Performance monitor support
+===========================
+
+.. toctree::
+   :maxdepth: 1
+
+   hisi-pmu
+   qcom_l2_pmu
+   qcom_l3_pmu
+   arm-ccn
+   xgene-pmu
+   arm_dsu_pmu
+   thunderx2-pmu
diff --git a/Documentation/admin-guide/perf/qcom_l2_pmu.rst b/Documentation/admin-guide/perf/qcom_l2_pmu.rst
new file mode 100644 (file)
index 0000000..c130178
--- /dev/null
@@ -0,0 +1,39 @@
+=====================================================================
+Qualcomm Technologies Level-2 Cache Performance Monitoring Unit (PMU)
+=====================================================================
+
+This driver supports the L2 cache clusters found in Qualcomm Technologies
+Centriq SoCs. There are multiple physical L2 cache clusters, each with their
+own PMU. Each cluster has one or more CPUs associated with it.
+
+There is one logical L2 PMU exposed, which aggregates the results from
+the physical PMUs.
+
+The driver provides a description of its available events and configuration
+options in sysfs, see /sys/devices/l2cache_0.
+
+The "format" directory describes the format of the events.
+
+Events can be envisioned as a 2-dimensional array. Each column represents
+a group of events. There are 8 groups. Only one entry from each
+group can be in use at a time. If multiple events from the same group
+are specified, the conflicting events cannot be counted at the same time.
+
+Events are specified as 0xCCG, where CC is 2 hex digits specifying
+the code (array row) and G specifies the group (column) 0-7.
+
+In addition there is a cycle counter event specified by the value 0xFE
+which is outside the above scheme.
+
+The driver provides a "cpumask" sysfs attribute which contains a mask
+consisting of one CPU per cluster which will be used to handle all the PMU
+events on that cluster.
+
+Examples for use with perf::
+
+  perf stat -e l2cache_0/config=0x001/,l2cache_0/config=0x042/ -a sleep 1
+
+  perf stat -e l2cache_0/config=0xfe/ -C 2 sleep 1
+
+The driver does not support sampling, therefore "perf record" will
+not work. Per-task perf sessions are not supported.
diff --git a/Documentation/admin-guide/perf/qcom_l3_pmu.rst b/Documentation/admin-guide/perf/qcom_l3_pmu.rst
new file mode 100644 (file)
index 0000000..a3d014a
--- /dev/null
@@ -0,0 +1,26 @@
+===========================================================================
+Qualcomm Datacenter Technologies L3 Cache Performance Monitoring Unit (PMU)
+===========================================================================
+
+This driver supports the L3 cache PMUs found in Qualcomm Datacenter Technologies
+Centriq SoCs. The L3 cache on these SOCs is composed of multiple slices, shared
+by all cores within a socket. Each slice is exposed as a separate uncore perf
+PMU with device name l3cache_<socket>_<instance>. User space is responsible
+for aggregating across slices.
+
+The driver provides a description of its available events and configuration
+options in sysfs, see /sys/devices/l3cache*. Given that these are uncore PMUs
+the driver also exposes a "cpumask" sysfs attribute which contains a mask
+consisting of one CPU per socket which will be used to handle all the PMU
+events on that socket.
+
+The hardware implements 32bit event counters and has a flat 8bit event space
+exposed via the "event" format attribute. In addition to the 32bit physical
+counters the driver supports virtual 64bit hardware counters by using hardware
+counter chaining. This feature is exposed via the "lc" (long counter) format
+flag. E.g.::
+
+  perf stat -e l3cache_0_0/read-miss,lc/
+
+Given that these are uncore PMUs the driver does not support sampling, therefore
+"perf record" will not work. Per-task perf sessions are not supported.
diff --git a/Documentation/admin-guide/perf/thunderx2-pmu.rst b/Documentation/admin-guide/perf/thunderx2-pmu.rst
new file mode 100644 (file)
index 0000000..08e3367
--- /dev/null
@@ -0,0 +1,42 @@
+=============================================================
+Cavium ThunderX2 SoC Performance Monitoring Unit (PMU UNCORE)
+=============================================================
+
+The ThunderX2 SoC PMU consists of independent, system-wide, per-socket
+PMUs such as the Level 3 Cache (L3C) and DDR4 Memory Controller (DMC).
+
+The DMC has 8 interleaved channels and the L3C has 16 interleaved tiles.
+Events are counted for the default channel (i.e. channel 0) and prorated
+to the total number of channels/tiles.
+
+The DMC and L3C support up to 4 counters. Counters are independently
+programmable and can be started and stopped individually. Each counter
+can be set to a different event. Counters are 32-bit and do not support
+an overflow interrupt; they are read every 2 seconds.
+
+PMU UNCORE (perf) driver:
+
+The thunderx2_pmu driver registers per-socket perf PMUs for the DMC and
+L3C devices.  Each PMU can be used to count up to 4 events
+simultaneously. The PMUs provide a description of their available events
+and configuration options under sysfs, see
+/sys/devices/uncore_<l3c_S/dmc_S/>; S is the socket id.
+
+The driver does not support sampling, therefore "perf record" will not
+work. Per-task perf sessions are also not supported.
+
+Examples::
+
+  # perf stat -a -e uncore_dmc_0/cnt_cycles/ sleep 1
+
+  # perf stat -a -e \
+  uncore_dmc_0/cnt_cycles/,\
+  uncore_dmc_0/data_transfers/,\
+  uncore_dmc_0/read_txns/,\
+  uncore_dmc_0/write_txns/ sleep 1
+
+  # perf stat -a -e \
+  uncore_l3c_0/read_request/,\
+  uncore_l3c_0/read_hit/,\
+  uncore_l3c_0/inv_request/,\
+  uncore_l3c_0/inv_hit/ sleep 1
diff --git a/Documentation/admin-guide/perf/xgene-pmu.rst b/Documentation/admin-guide/perf/xgene-pmu.rst
new file mode 100644 (file)
index 0000000..644f8ed
--- /dev/null
@@ -0,0 +1,49 @@
+================================================
+APM X-Gene SoC Performance Monitoring Unit (PMU)
+================================================
+
+X-Gene SoC PMU consists of various independent system device PMUs such as
+L3 cache(s), I/O bridge(s), memory controller bridge(s) and memory
+controller(s). These PMU devices are loosely architected to follow the
+same model as the PMU for ARM cores. The PMUs share the same top level
+interrupt and status CSR region.
+
+PMU (perf) driver
+-----------------
+
+The xgene-pmu driver registers several perf PMU drivers. Each of the perf
+driver provides description of its available events and configuration options
+in sysfs, see /sys/devices/<l3cX/iobX/mcbX/mcX>/.
+
+The "format" directory describes format of the config (event ID),
+config1 (agent ID) fields of the perf_event_attr structure. The "events"
+directory provides configuration templates for all supported event types that
+can be used with perf tool. For example, "l3c0/bank-fifo-full/" is an
+equivalent of "l3c0/config=0x0b/".
+
+Most of the SoC PMU has a specific list of agent ID used for monitoring
+performance of a specific datapath. For example, agents of a L3 cache can be
+a specific CPU or an I/O bridge. Each PMU has a set of 2 registers capable of
+masking the agents from which the request come from. If the bit with
+the bit number corresponding to the agent is set, the event is counted only if
+it is caused by a request from that agent. Each agent ID bit is inversely mapped
+to a corresponding bit in "config1" field. By default, the event will be
+counted for all agent requests (config1 = 0x0). For all the supported agents of
+each PMU, please refer to APM X-Gene User Manual.
+
+Each perf driver also provides a "cpumask" sysfs attribute, which contains a
+single CPU ID of the processor which will be used to handle all the PMU events.
+
+Example for perf tool use::
+
+ / # perf list | grep -e l3c -e iob -e mcb -e mc
+   l3c0/ackq-full/                                    [Kernel PMU event]
+ <...>
+   mcb1/mcb-csw-stall/                                [Kernel PMU event]
+
+ / # perf stat -a -e l3c0/read-miss/,mcb1/csw-write-request/ sleep 1
+
+ / # perf stat -a -e l3c0/read-miss,config1=0xfffffffffffffffe/ sleep 1
+
+The driver does not support sampling, therefore "perf record" will
+not work. Per-task (without "-a") perf sessions are not supported.
diff --git a/Documentation/admin-guide/sysctl/abi.rst b/Documentation/admin-guide/sysctl/abi.rst
new file mode 100644 (file)
index 0000000..599bcde
--- /dev/null
@@ -0,0 +1,67 @@
+================================
+Documentation for /proc/sys/abi/
+================================
+
+kernel version 2.6.0.test2
+
+Copyright (c) 2003,  Fabian Frederick <ffrederick@users.sourceforge.net>
+
+For general info: index.rst.
+
+------------------------------------------------------------------------------
+
+This path is binary emulation relevant aka personality types aka abi.
+When a process is executed, it's linked to an exec_domain whose
+personality is defined using values available from /proc/sys/abi.
+You can find further details about abi in include/linux/personality.h.
+
+Here are the files featuring in 2.6 kernel:
+
+- defhandler_coff
+- defhandler_elf
+- defhandler_lcall7
+- defhandler_libcso
+- fake_utsname
+- trace
+
+defhandler_coff
+---------------
+
+defined value:
+       PER_SCOSVR3::
+
+               0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS | SHORT_INODE
+
+defhandler_elf
+--------------
+
+defined value:
+       PER_LINUX::
+
+               0
+
+defhandler_lcall7
+-----------------
+
+defined value :
+       PER_SVR4::
+
+               0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+
+defhandler_libsco
+-----------------
+
+defined value:
+       PER_SVR4::
+
+               0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+
+fake_utsname
+------------
+
+Unused
+
+trace
+-----
+
+Unused
diff --git a/Documentation/admin-guide/sysctl/fs.rst b/Documentation/admin-guide/sysctl/fs.rst
new file mode 100644 (file)
index 0000000..2a45119
--- /dev/null
@@ -0,0 +1,384 @@
+===============================
+Documentation for /proc/sys/fs/
+===============================
+
+kernel version 2.2.10
+
+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 intro.rst.
+
+------------------------------------------------------------------------------
+
+This file contains documentation for the sysctl files in
+/proc/sys/fs/ and is valid for Linux kernel version 2.2.
+
+The files in this directory can be used to tune and monitor
+miscellaneous and general things in the operation of the Linux
+kernel. Since some of the files _can_ be used to screw up your
+system, it is advisable to read both documentation and source
+before actually making adjustments.
+
+1. /proc/sys/fs
+===============
+
+Currently, these files are in /proc/sys/fs:
+
+- aio-max-nr
+- aio-nr
+- dentry-state
+- dquot-max
+- dquot-nr
+- file-max
+- file-nr
+- inode-max
+- inode-nr
+- inode-state
+- nr_open
+- overflowuid
+- overflowgid
+- pipe-user-pages-hard
+- pipe-user-pages-soft
+- protected_fifos
+- protected_hardlinks
+- protected_regular
+- protected_symlinks
+- suid_dumpable
+- super-max
+- super-nr
+
+
+aio-nr & aio-max-nr
+-------------------
+
+aio-nr is the running total of the number of events specified on the
+io_setup system call for all currently active aio contexts.  If aio-nr
+reaches aio-max-nr then io_setup will fail with EAGAIN.  Note that
+raising aio-max-nr does not result in the pre-allocation or re-sizing
+of any kernel data structures.
+
+
+dentry-state
+------------
+
+From linux/include/linux/dcache.h::
+
+  struct dentry_stat_t dentry_stat {
+        int nr_dentry;
+        int nr_unused;
+        int age_limit;         /* age in seconds */
+        int want_pages;        /* pages requested by system */
+        int nr_negative;       /* # of unused negative dentries */
+        int dummy;             /* Reserved for future use */
+  };
+
+Dentries are dynamically allocated and deallocated.
+
+nr_dentry shows the total number of dentries allocated (active
++ unused). nr_unused shows the number of dentries that are not
+actively used, but are saved in the LRU list for future reuse.
+
+Age_limit is the age in seconds after which dcache entries
+can be reclaimed when memory is short and want_pages is
+nonzero when shrink_dcache_pages() has been called and the
+dcache isn't pruned yet.
+
+nr_negative shows the number of unused dentries that are also
+negative dentries which do not map to any files. Instead,
+they help speeding up rejection of non-existing files provided
+by the users.
+
+
+dquot-max & dquot-nr
+--------------------
+
+The file dquot-max shows the maximum number of cached disk
+quota entries.
+
+The file dquot-nr shows the number of allocated disk quota
+entries and the number of free disk quota entries.
+
+If the number of free cached disk quotas is very low and
+you have some awesome number of simultaneous system users,
+you might want to raise the limit.
+
+
+file-max & file-nr
+------------------
+
+The value in file-max denotes the maximum number of file-
+handles that the Linux kernel will allocate. When you get lots
+of error messages about running out of file handles, you might
+want to increase this limit.
+
+Historically,the kernel was able to allocate file handles
+dynamically, but not to free them again. The three values in
+file-nr denote the number of allocated file handles, the number
+of allocated but unused file handles, and the maximum number of
+file handles. Linux 2.6 always reports 0 as the number of free
+file handles -- this is not an error, it just means that the
+number of allocated file handles exactly matches the number of
+used file handles.
+
+Attempts to allocate more file descriptors than file-max are
+reported with printk, look for "VFS: file-max limit <number>
+reached".
+
+
+nr_open
+-------
+
+This denotes the maximum number of file-handles a process can
+allocate. Default value is 1024*1024 (1048576) which should be
+enough for most machines. Actual limit depends on RLIMIT_NOFILE
+resource limit.
+
+
+inode-max, inode-nr & inode-state
+---------------------------------
+
+As with file handles, the kernel allocates the inode structures
+dynamically, but can't free them yet.
+
+The value in inode-max denotes the maximum number of inode
+handlers. This value should be 3-4 times larger than the value
+in file-max, since stdin, stdout and network sockets also
+need an inode struct to handle them. When you regularly run
+out of inodes, you need to increase this value.
+
+The file inode-nr contains the first two items from
+inode-state, so we'll skip to that file...
+
+Inode-state contains three actual numbers and four dummies.
+The actual numbers are, in order of appearance, nr_inodes,
+nr_free_inodes and preshrink.
+
+Nr_inodes stands for the number of inodes the system has
+allocated, this can be slightly more than inode-max because
+Linux allocates them one pageful at a time.
+
+Nr_free_inodes represents the number of free inodes (?) and
+preshrink is nonzero when the nr_inodes > inode-max and the
+system needs to prune the inode list instead of allocating
+more.
+
+
+overflowgid & overflowuid
+-------------------------
+
+Some filesystems only support 16-bit UIDs and GIDs, although in Linux
+UIDs and GIDs are 32 bits. When one of these filesystems is mounted
+with writes enabled, any UID or GID that would exceed 65535 is translated
+to a fixed value before being written to disk.
+
+These sysctls allow you to change the value of the fixed UID and GID.
+The default is 65534.
+
+
+pipe-user-pages-hard
+--------------------
+
+Maximum total number of pages a non-privileged user may allocate for pipes.
+Once this limit is reached, no new pipes may be allocated until usage goes
+below the limit again. When set to 0, no limit is applied, which is the default
+setting.
+
+
+pipe-user-pages-soft
+--------------------
+
+Maximum total number of pages a non-privileged user may allocate for pipes
+before the pipe size gets limited to a single page. Once this limit is reached,
+new pipes will be limited to a single page in size for this user in order to
+limit total memory usage, and trying to increase them using fcntl() will be
+denied until usage goes below the limit again. The default value allows to
+allocate up to 1024 pipes at their default size. When set to 0, no limit is
+applied.
+
+
+protected_fifos
+---------------
+
+The intent of this protection is to avoid unintentional writes to
+an attacker-controlled FIFO, where a program expected to create a regular
+file.
+
+When set to "0", writing to FIFOs is unrestricted.
+
+When set to "1" don't allow O_CREAT open on FIFOs that we don't own
+in world writable sticky directories, unless they are owned by the
+owner of the directory.
+
+When set to "2" it also applies to group writable sticky directories.
+
+This protection is based on the restrictions in Openwall.
+
+
+protected_hardlinks
+--------------------
+
+A long-standing class of security issues is the hardlink-based
+time-of-check-time-of-use race, most commonly seen in world-writable
+directories like /tmp. The common method of exploitation of this flaw
+is to cross privilege boundaries when following a given hardlink (i.e. a
+root process follows a hardlink created by another user). Additionally,
+on systems without separated partitions, this stops unauthorized users
+from "pinning" vulnerable setuid/setgid files against being upgraded by
+the administrator, or linking to special files.
+
+When set to "0", hardlink creation behavior is unrestricted.
+
+When set to "1" hardlinks cannot be created by users if they do not
+already own the source file, or do not have read/write access to it.
+
+This protection is based on the restrictions in Openwall and grsecurity.
+
+
+protected_regular
+-----------------
+
+This protection is similar to protected_fifos, but it
+avoids writes to an attacker-controlled regular file, where a program
+expected to create one.
+
+When set to "0", writing to regular files is unrestricted.
+
+When set to "1" don't allow O_CREAT open on regular files that we
+don't own in world writable sticky directories, unless they are
+owned by the owner of the directory.
+
+When set to "2" it also applies to group writable sticky directories.
+
+
+protected_symlinks
+------------------
+
+A long-standing class of security issues is the symlink-based
+time-of-check-time-of-use race, most commonly seen in world-writable
+directories like /tmp. The common method of exploitation of this flaw
+is to cross privilege boundaries when following a given symlink (i.e. a
+root process follows a symlink belonging to another user). For a likely
+incomplete list of hundreds of examples across the years, please see:
+http://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=/tmp
+
+When set to "0", symlink following behavior is unrestricted.
+
+When set to "1" symlinks are permitted to be followed only when outside
+a sticky world-writable directory, or when the uid of the symlink and
+follower match, or when the directory owner matches the symlink's owner.
+
+This protection is based on the restrictions in Openwall and grsecurity.
+
+
+suid_dumpable:
+--------------
+
+This value can be used to query and set the core dump mode for setuid
+or otherwise protected/tainted binaries. The modes are
+
+=   ==========  ===============================================================
+0   (default)  traditional behaviour. Any process which has changed
+               privilege levels or is execute only will not be dumped.
+1   (debug)    all processes dump core when possible. The core dump is
+               owned by the current user and no security is applied. This is
+               intended for system debugging situations only.
+               Ptrace is unchecked.
+               This is insecure as it allows regular users to examine the
+               memory contents of privileged processes.
+2   (suidsafe) any binary which normally would not be dumped is dumped
+               anyway, but only if the "core_pattern" kernel sysctl is set to
+               either a pipe handler or a fully qualified path. (For more
+               details on this limitation, see CVE-2006-2451.) This mode is
+               appropriate when administrators are attempting to debug
+               problems in a normal environment, and either have a core dump
+               pipe handler that knows to treat privileged core dumps with
+               care, or specific directory defined for catching core dumps.
+               If a core dump happens without a pipe handler or fully
+               qualified path, a message will be emitted to syslog warning
+               about the lack of a correct setting.
+=   ==========  ===============================================================
+
+
+super-max & super-nr
+--------------------
+
+These numbers control the maximum number of superblocks, and
+thus the maximum number of mounted filesystems the kernel
+can have. You only need to increase super-max if you need to
+mount more filesystems than the current value in super-max
+allows you to.
+
+
+aio-nr & aio-max-nr
+-------------------
+
+aio-nr shows the current system-wide number of asynchronous io
+requests.  aio-max-nr allows you to change the maximum value
+aio-nr can grow to.
+
+
+mount-max
+---------
+
+This denotes the maximum number of mounts that may exist
+in a mount namespace.
+
+
+
+2. /proc/sys/fs/binfmt_misc
+===========================
+
+Documentation for the files in /proc/sys/fs/binfmt_misc is
+in Documentation/admin-guide/binfmt-misc.rst.
+
+
+3. /proc/sys/fs/mqueue - POSIX message queues filesystem
+========================================================
+
+
+The "mqueue"  filesystem provides  the necessary kernel features to enable the
+creation of a  user space  library that  implements  the  POSIX message queues
+API (as noted by the  MSG tag in the  POSIX 1003.1-2001 version  of the System
+Interfaces specification.)
+
+The "mqueue" filesystem contains values for determining/setting  the amount of
+resources used by the file system.
+
+/proc/sys/fs/mqueue/queues_max is a read/write  file for  setting/getting  the
+maximum number of message queues allowed on the system.
+
+/proc/sys/fs/mqueue/msg_max  is  a  read/write file  for  setting/getting  the
+maximum number of messages in a queue value.  In fact it is the limiting value
+for another (user) limit which is set in mq_open invocation. This attribute of
+a queue must be less or equal then msg_max.
+
+/proc/sys/fs/mqueue/msgsize_max is  a read/write  file for setting/getting the
+maximum  message size value (it is every  message queue's attribute set during
+its creation).
+
+/proc/sys/fs/mqueue/msg_default is  a read/write  file for setting/getting the
+default number of messages in a queue value if attr parameter of mq_open(2) is
+NULL. If it exceed msg_max, the default value is initialized msg_max.
+
+/proc/sys/fs/mqueue/msgsize_default is a read/write file for setting/getting
+the default message size value if attr parameter of mq_open(2) is NULL. If it
+exceed msgsize_max, the default value is initialized msgsize_max.
+
+4. /proc/sys/fs/epoll - Configuration options for the epoll interface
+=====================================================================
+
+This directory contains configuration options for the epoll(7) interface.
+
+max_user_watches
+----------------
+
+Every epoll file descriptor can store a number of files to be monitored
+for event readiness. Each one of these monitored files constitutes a "watch".
+This configuration option sets the maximum number of "watches" that are
+allowed for each user.
+Each "watch" costs roughly 90 bytes on a 32bit kernel, and roughly 160 bytes
+on a 64bit one.
+The current default value for  max_user_watches  is the 1/32 of the available
+low memory, divided for the "watch" cost in bytes.
diff --git a/Documentation/admin-guide/sysctl/index.rst b/Documentation/admin-guide/sysctl/index.rst
new file mode 100644 (file)
index 0000000..03346f9
--- /dev/null
@@ -0,0 +1,98 @@
+===========================
+Documentation for /proc/sys
+===========================
+
+Copyright (c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
+
+------------------------------------------------------------------------------
+
+'Why', I hear you ask, 'would anyone even _want_ documentation
+for them sysctl files? If anybody really needs it, it's all in
+the source...'
+
+Well, this documentation is written because some people either
+don't know they need to tweak something, or because they don't
+have the time or knowledge to read the source code.
+
+Furthermore, the programmers who built sysctl have built it to
+be actually used, not just for the fun of programming it :-)
+
+------------------------------------------------------------------------------
+
+Legal blurb:
+
+As usual, there are two main things to consider:
+
+1. you get what you pay for
+2. it's free
+
+The consequences are that I won't guarantee the correctness of
+this document, and if you come to me complaining about how you
+screwed up your system because of wrong documentation, I won't
+feel sorry for you. I might even laugh at you...
+
+But of course, if you _do_ manage to screw up your system using
+only the sysctl options used in this file, I'd like to hear of
+it. Not only to have a great laugh, but also to make sure that
+you're the last RTFMing person to screw up.
+
+In short, e-mail your suggestions, corrections and / or horror
+stories to: <riel@nl.linux.org>
+
+Rik van Riel.
+
+--------------------------------------------------------------
+
+Introduction
+============
+
+Sysctl is a means of configuring certain aspects of the kernel
+at run-time, and the /proc/sys/ directory is there so that you
+don't even need special tools to do it!
+In fact, there are only four things needed to use these config
+facilities:
+
+- a running Linux system
+- root access
+- common sense (this is especially hard to come by these days)
+- knowledge of what all those values mean
+
+As a quick 'ls /proc/sys' will show, the directory consists of
+several (arch-dependent?) subdirs. Each subdir is mainly about
+one part of the kernel, so you can do configuration on a piece
+by piece basis, or just some 'thematic frobbing'.
+
+This documentation is about:
+
+=============== ===============================================================
+abi/           execution domains & personalities
+debug/         <empty>
+dev/           device specific information (eg dev/cdrom/info)
+fs/            specific filesystems
+               filehandle, inode, dentry and quota tuning
+               binfmt_misc <Documentation/admin-guide/binfmt-misc.rst>
+kernel/                global kernel info / tuning
+               miscellaneous stuff
+net/           networking stuff, for documentation look in:
+               <Documentation/networking/>
+proc/          <empty>
+sunrpc/                SUN Remote Procedure Call (NFS)
+vm/            memory management tuning
+               buffer and cache management
+user/          Per user per user namespace limits
+=============== ===============================================================
+
+These are the subdirs I have on my system. There might be more
+or other subdirs in another setup. If you see another dir, I'd
+really like to hear about it :-)
+
+.. toctree::
+   :maxdepth: 1
+
+   abi
+   fs
+   kernel
+   net
+   sunrpc
+   user
+   vm
diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst
new file mode 100644 (file)
index 0000000..032c7cd
--- /dev/null
@@ -0,0 +1,1177 @@
+===================================
+Documentation for /proc/sys/kernel/
+===================================
+
+kernel version 2.2.10
+
+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 index.rst.
+
+------------------------------------------------------------------------------
+
+This file contains documentation for the sysctl files in
+/proc/sys/kernel/ and is valid for Linux kernel version 2.2.
+
+The files in this directory can be used to tune and monitor
+miscellaneous and general things in the operation of the Linux
+kernel. Since some of the files _can_ be used to screw up your
+system, it is advisable to read both documentation and source
+before actually making adjustments.
+
+Currently, these files might (depending on your configuration)
+show up in /proc/sys/kernel:
+
+- acct
+- acpi_video_flags
+- auto_msgmni
+- bootloader_type           [ X86 only ]
+- bootloader_version        [ X86 only ]
+- cap_last_cap
+- core_pattern
+- core_pipe_limit
+- core_uses_pid
+- ctrl-alt-del
+- dmesg_restrict
+- domainname
+- hostname
+- hotplug
+- hardlockup_all_cpu_backtrace
+- hardlockup_panic
+- hung_task_panic
+- hung_task_check_count
+- hung_task_timeout_secs
+- hung_task_check_interval_secs
+- hung_task_warnings
+- hyperv_record_panic_msg
+- kexec_load_disabled
+- kptr_restrict
+- l2cr                        [ PPC only ]
+- modprobe                    ==> Documentation/debugging-modules.txt
+- modules_disabled
+- msg_next_id                [ sysv ipc ]
+- msgmax
+- msgmnb
+- msgmni
+- nmi_watchdog
+- osrelease
+- ostype
+- overflowgid
+- overflowuid
+- panic
+- panic_on_oops
+- panic_on_stackoverflow
+- panic_on_unrecovered_nmi
+- panic_on_warn
+- panic_print
+- panic_on_rcu_stall
+- perf_cpu_time_max_percent
+- perf_event_paranoid
+- perf_event_max_stack
+- perf_event_mlock_kb
+- perf_event_max_contexts_per_stack
+- pid_max
+- powersave-nap               [ PPC only ]
+- printk
+- printk_delay
+- printk_ratelimit
+- printk_ratelimit_burst
+- pty                         ==> Documentation/filesystems/devpts.txt
+- randomize_va_space
+- real-root-dev               ==> Documentation/admin-guide/initrd.rst
+- reboot-cmd                  [ SPARC only ]
+- rtsig-max
+- rtsig-nr
+- sched_energy_aware
+- seccomp/                    ==> Documentation/userspace-api/seccomp_filter.rst
+- sem
+- sem_next_id                [ sysv ipc ]
+- sg-big-buff                 [ generic SCSI device (sg) ]
+- shm_next_id                [ sysv ipc ]
+- shm_rmid_forced
+- shmall
+- shmmax                      [ sysv ipc ]
+- shmmni
+- softlockup_all_cpu_backtrace
+- soft_watchdog
+- stack_erasing
+- stop-a                      [ SPARC only ]
+- sysrq                       ==> Documentation/admin-guide/sysrq.rst
+- sysctl_writes_strict
+- tainted                     ==> Documentation/admin-guide/tainted-kernels.rst
+- threads-max
+- unknown_nmi_panic
+- watchdog
+- watchdog_thresh
+- version
+
+
+acct:
+=====
+
+highwater lowwater frequency
+
+If BSD-style process accounting is enabled these values control
+its behaviour. If free space on filesystem where the log lives
+goes below <lowwater>% accounting suspends. If free space gets
+above <highwater>% accounting resumes. <Frequency> determines
+how often do we check the amount of free space (value is in
+seconds). Default:
+4 2 30
+That is, suspend accounting if there left <= 2% free; resume it
+if we got >=4%; consider information about amount of free space
+valid for 30 seconds.
+
+
+acpi_video_flags:
+=================
+
+flags
+
+See Doc*/kernel/power/video.txt, it allows mode of video boot to be
+set during run time.
+
+
+auto_msgmni:
+============
+
+This variable has no effect and may be removed in future kernel
+releases. Reading it always returns 0.
+Up to Linux 3.17, it enabled/disabled automatic recomputing of msgmni
+upon memory add/remove or upon ipc namespace creation/removal.
+Echoing "1" into this file enabled msgmni automatic recomputing.
+Echoing "0" turned it off. auto_msgmni default value was 1.
+
+
+bootloader_type:
+================
+
+x86 bootloader identification
+
+This gives the bootloader type number as indicated by the bootloader,
+shifted left by 4, and OR'd with the low four bits of the bootloader
+version.  The reason for this encoding is that this used to match the
+type_of_loader field in the kernel header; the encoding is kept for
+backwards compatibility.  That is, if the full bootloader type number
+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
+Documentation/x86/boot.rst for additional information.
+
+
+bootloader_version:
+===================
+
+x86 bootloader version
+
+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
+Documentation/x86/boot.rst for additional information.
+
+
+cap_last_cap:
+=============
+
+Highest valid capability of the running kernel.  Exports
+CAP_LAST_CAP from the kernel.
+
+
+core_pattern:
+=============
+
+core_pattern is used to specify a core dumpfile pattern name.
+
+* max length 127 characters; default value is "core"
+* core_pattern is used as a pattern template for the output filename;
+  certain string patterns (beginning with '%') are substituted with
+  their actual values.
+* backward compatibility with core_uses_pid:
+
+       If core_pattern does not include "%p" (default does not)
+       and core_uses_pid is set, then .PID will be appended to
+       the filename.
+
+* corename format specifiers::
+
+       %<NUL>  '%' is dropped
+       %%      output one '%'
+       %p      pid
+       %P      global pid (init PID namespace)
+       %i      tid
+       %I      global tid (init PID namespace)
+       %u      uid (in initial user namespace)
+       %g      gid (in initial user namespace)
+       %d      dump mode, matches PR_SET_DUMPABLE and
+               /proc/sys/fs/suid_dumpable
+       %s      signal number
+       %t      UNIX time of dump
+       %h      hostname
+       %e      executable filename (may be shortened)
+       %E      executable path
+       %<OTHER> both are dropped
+
+* If the first character of the pattern is a '|', the kernel will treat
+  the rest of the pattern as a command to run.  The core dump will be
+  written to the standard input of that program instead of to a file.
+
+
+core_pipe_limit:
+================
+
+This sysctl is only applicable when core_pattern is configured to pipe
+core files to a user space helper (when the first character of
+core_pattern is a '|', see above).  When collecting cores via a pipe
+to an application, it is occasionally useful for the collecting
+application to gather data about the crashing process from its
+/proc/pid directory.  In order to do this safely, the kernel must wait
+for the collecting process to exit, so as not to remove the crashing
+processes proc files prematurely.  This in turn creates the
+possibility that a misbehaving userspace collecting process can block
+the reaping of a crashed process simply by never exiting.  This sysctl
+defends against that.  It defines how many concurrent crashing
+processes may be piped to user space applications in parallel.  If
+this value is exceeded, then those crashing processes above that value
+are noted via the kernel log and their cores are skipped.  0 is a
+special value, indicating that unlimited processes may be captured in
+parallel, but that no waiting will take place (i.e. the collecting
+process is not guaranteed access to /proc/<crashing pid>/).  This
+value defaults to 0.
+
+
+core_uses_pid:
+==============
+
+The default coredump filename is "core".  By setting
+core_uses_pid to 1, the coredump filename becomes core.PID.
+If core_pattern does not include "%p" (default does not)
+and core_uses_pid is set, then .PID will be appended to
+the filename.
+
+
+ctrl-alt-del:
+=============
+
+When the value in this file is 0, ctrl-alt-del is trapped and
+sent to the init(1) program to handle a graceful restart.
+When, however, the value is > 0, Linux's reaction to a Vulcan
+Nerve Pinch (tm) will be an immediate reboot, without even
+syncing its dirty buffers.
+
+Note:
+  when a program (like dosemu) has the keyboard in 'raw'
+  mode, the ctrl-alt-del is intercepted by the program before it
+  ever reaches the kernel tty layer, and it's up to the program
+  to decide what to do with it.
+
+
+dmesg_restrict:
+===============
+
+This toggle indicates whether unprivileged users are prevented
+from using dmesg(8) to view messages from the kernel's log buffer.
+When dmesg_restrict is set to (0) there are no restrictions. When
+dmesg_restrict is set set to (1), users must have CAP_SYSLOG to use
+dmesg(8).
+
+The kernel config option CONFIG_SECURITY_DMESG_RESTRICT sets the
+default value of dmesg_restrict.
+
+
+domainname & hostname:
+======================
+
+These files can be used to set the NIS/YP domainname and the
+hostname of your box in exactly the same way as the commands
+domainname and hostname, i.e.::
+
+       # echo "darkstar" > /proc/sys/kernel/hostname
+       # echo "mydomain" > /proc/sys/kernel/domainname
+
+has the same effect as::
+
+       # hostname "darkstar"
+       # domainname "mydomain"
+
+Note, however, that the classic darkstar.frop.org has the
+hostname "darkstar" and DNS (Internet Domain Name Server)
+domainname "frop.org", not to be confused with the NIS (Network
+Information Service) or YP (Yellow Pages) domainname. These two
+domain names are in general different. For a detailed discussion
+see the hostname(1) man page.
+
+
+hardlockup_all_cpu_backtrace:
+=============================
+
+This value controls the hard lockup detector behavior when a hard
+lockup condition is detected as to whether or not to gather further
+debug information. If enabled, arch-specific all-CPU stack dumping
+will be initiated.
+
+0: do nothing. This is the default behavior.
+
+1: on detection capture more debug information.
+
+
+hardlockup_panic:
+=================
+
+This parameter can be used to control whether the kernel panics
+when a hard lockup is detected.
+
+   0 - don't panic on hard lockup
+   1 - panic on hard lockup
+
+See Documentation/admin-guide/lockup-watchdogs.rst for more information.  This can
+also be set using the nmi_watchdog kernel parameter.
+
+
+hotplug:
+========
+
+Path for the hotplug policy agent.
+Default value is "/sbin/hotplug".
+
+
+hung_task_panic:
+================
+
+Controls the kernel's behavior when a hung task is detected.
+This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
+
+0: continue operation. This is the default behavior.
+
+1: panic immediately.
+
+
+hung_task_check_count:
+======================
+
+The upper bound on the number of tasks that are checked.
+This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
+
+
+hung_task_timeout_secs:
+=======================
+
+When a task in D state did not get scheduled
+for more than this value report a warning.
+This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
+
+0: means infinite timeout - no checking done.
+
+Possible values to set are in range {0..LONG_MAX/HZ}.
+
+
+hung_task_check_interval_secs:
+==============================
+
+Hung task check interval. If hung task checking is enabled
+(see hung_task_timeout_secs), the check is done every
+hung_task_check_interval_secs seconds.
+This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
+
+0 (default): means use hung_task_timeout_secs as checking interval.
+Possible values to set are in range {0..LONG_MAX/HZ}.
+
+
+hung_task_warnings:
+===================
+
+The maximum number of warnings to report. During a check interval
+if a hung task is detected, this value is decreased by 1.
+When this value reaches 0, no more warnings will be reported.
+This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
+
+-1: report an infinite number of warnings.
+
+
+hyperv_record_panic_msg:
+========================
+
+Controls whether the panic kmsg data should be reported to Hyper-V.
+
+0: do not report panic kmsg data.
+
+1: report the panic kmsg data. This is the default behavior.
+
+
+kexec_load_disabled:
+====================
+
+A toggle indicating if the kexec_load syscall has been disabled. This
+value defaults to 0 (false: kexec_load enabled), but can be set to 1
+(true: kexec_load disabled). Once true, kexec can no longer be used, and
+the toggle cannot be set back to false. This allows a kexec image to be
+loaded before disabling the syscall, allowing a system to set up (and
+later use) an image without it being altered. Generally used together
+with the "modules_disabled" sysctl.
+
+
+kptr_restrict:
+==============
+
+This toggle indicates whether restrictions are placed on
+exposing kernel addresses via /proc and other interfaces.
+
+When kptr_restrict is set to 0 (the default) the address is hashed before
+printing. (This is the equivalent to %p.)
+
+When kptr_restrict is set to (1), kernel pointers printed using the %pK
+format specifier will be replaced with 0's unless the user has CAP_SYSLOG
+and effective user and group ids are equal to the real ids. This is
+because %pK checks are done at read() time rather than open() time, so
+if permissions are elevated between the open() and the read() (e.g via
+a setuid binary) then %pK will not leak kernel pointers to unprivileged
+users. Note, this is a temporary solution only. The correct long-term
+solution is to do the permission checks at open() time. Consider removing
+world read permissions from files that use %pK, and using dmesg_restrict
+to protect against uses of %pK in dmesg(8) if leaking kernel pointer
+values to unprivileged users is a concern.
+
+When kptr_restrict is set to (2), kernel pointers printed using
+%pK will be replaced with 0's regardless of privileges.
+
+
+l2cr: (PPC only)
+================
+
+This flag controls the L2 cache of G3 processor boards. If
+0, the cache is disabled. Enabled if nonzero.
+
+
+modules_disabled:
+=================
+
+A toggle value indicating if modules are allowed to be loaded
+in an otherwise modular kernel.  This toggle defaults to off
+(0), but can be set true (1).  Once true, modules can be
+neither loaded nor unloaded, and the toggle cannot be set back
+to false.  Generally used with the "kexec_load_disabled" toggle.
+
+
+msg_next_id, sem_next_id, and shm_next_id:
+==========================================
+
+These three toggles allows to specify desired id for next allocated IPC
+object: message, semaphore or shared memory respectively.
+
+By default they are equal to -1, which means generic allocation logic.
+Possible values to set are in range {0..INT_MAX}.
+
+Notes:
+  1) kernel doesn't guarantee, that new object will have desired id. So,
+     it's up to userspace, how to handle an object with "wrong" id.
+  2) Toggle with non-default value will be set back to -1 by kernel after
+     successful IPC object allocation. If an IPC object allocation syscall
+     fails, it is undefined if the value remains unmodified or is reset to -1.
+
+
+nmi_watchdog:
+=============
+
+This parameter can be used to control the NMI watchdog
+(i.e. the hard lockup detector) on x86 systems.
+
+0 - disable the hard lockup detector
+
+1 - enable the hard lockup detector
+
+The hard lockup detector monitors each CPU for its ability to respond to
+timer interrupts. The mechanism utilizes CPU performance counter registers
+that are programmed to generate Non-Maskable Interrupts (NMIs) periodically
+while a CPU is busy. Hence, the alternative name 'NMI watchdog'.
+
+The NMI watchdog is disabled by default if the kernel is running as a guest
+in a KVM virtual machine. This default can be overridden by adding::
+
+   nmi_watchdog=1
+
+to the guest kernel command line (see Documentation/admin-guide/kernel-parameters.rst).
+
+
+numa_balancing:
+===============
+
+Enables/disables automatic page fault based NUMA memory
+balancing. Memory is moved automatically to nodes
+that access it often.
+
+Enables/disables automatic NUMA memory balancing. On NUMA machines, there
+is a performance penalty if remote memory is accessed by a CPU. When this
+feature is enabled the kernel samples what task thread is accessing memory
+by periodically unmapping pages and later trapping a page fault. At the
+time of the page fault, it is determined if the data being accessed should
+be migrated to a local memory node.
+
+The unmapping of pages and trapping faults incur additional overhead that
+ideally is offset by improved memory locality but there is no universal
+guarantee. If the target workload is already bound to NUMA nodes then this
+feature should be disabled. Otherwise, if the system overhead from the
+feature is too high then the rate the kernel samples for NUMA hinting
+faults may be controlled by the numa_balancing_scan_period_min_ms,
+numa_balancing_scan_delay_ms, numa_balancing_scan_period_max_ms,
+numa_balancing_scan_size_mb, and numa_balancing_settle_count sysctls.
+
+numa_balancing_scan_period_min_ms, numa_balancing_scan_delay_ms, numa_balancing_scan_period_max_ms, numa_balancing_scan_size_mb
+===============================================================================================================================
+
+
+Automatic NUMA balancing scans tasks address space and unmaps pages to
+detect if pages are properly placed or if the data should be migrated to a
+memory node local to where the task is running.  Every "scan delay" the task
+scans the next "scan size" number of pages in its address space. When the
+end of the address space is reached the scanner restarts from the beginning.
+
+In combination, the "scan delay" and "scan size" determine the scan rate.
+When "scan delay" decreases, the scan rate increases.  The scan delay and
+hence the scan rate of every task is adaptive and depends on historical
+behaviour. If pages are properly placed then the scan delay increases,
+otherwise the scan delay decreases.  The "scan size" is not adaptive but
+the higher the "scan size", the higher the scan rate.
+
+Higher scan rates incur higher system overhead as page faults must be
+trapped and potentially data must be migrated. However, the higher the scan
+rate, the more quickly a tasks memory is migrated to a local node if the
+workload pattern changes and minimises performance impact due to remote
+memory accesses. These sysctls control the thresholds for scan delays and
+the number of pages scanned.
+
+numa_balancing_scan_period_min_ms is the minimum time in milliseconds to
+scan a tasks virtual memory. It effectively controls the maximum scanning
+rate for each task.
+
+numa_balancing_scan_delay_ms is the starting "scan delay" used for a task
+when it initially forks.
+
+numa_balancing_scan_period_max_ms is the maximum time in milliseconds to
+scan a tasks virtual memory. It effectively controls the minimum scanning
+rate for each task.
+
+numa_balancing_scan_size_mb is how many megabytes worth of pages are
+scanned for a given scan.
+
+
+osrelease, ostype & version:
+============================
+
+::
+
+  # cat osrelease
+  2.1.88
+  # cat ostype
+  Linux
+  # cat version
+  #5 Wed Feb 25 21:49:24 MET 1998
+
+The files osrelease and ostype should be clear enough. Version
+needs a little more clarification however. The '#5' means that
+this is the fifth kernel built from this source base and the
+date behind it indicates the time the kernel was built.
+The only way to tune these values is to rebuild the kernel :-)
+
+
+overflowgid & overflowuid:
+==========================
+
+if your architecture did not always support 32-bit UIDs (i.e. arm,
+i386, m68k, sh, and sparc32), a fixed UID and GID will be returned to
+applications that use the old 16-bit UID/GID system calls, if the
+actual UID or GID would exceed 65535.
+
+These sysctls allow you to change the value of the fixed UID and GID.
+The default is 65534.
+
+
+panic:
+======
+
+The value in this file represents the number of seconds the kernel
+waits before rebooting on a panic. When you use the software watchdog,
+the recommended setting is 60.
+
+
+panic_on_io_nmi:
+================
+
+Controls the kernel's behavior when a CPU receives an NMI caused by
+an IO error.
+
+0: try to continue operation (default)
+
+1: panic immediately. The IO error triggered an NMI. This indicates a
+   serious system condition which could result in IO data corruption.
+   Rather than continuing, panicking might be a better choice. Some
+   servers issue this sort of NMI when the dump button is pushed,
+   and you can use this option to take a crash dump.
+
+
+panic_on_oops:
+==============
+
+Controls the kernel's behaviour when an oops or BUG is encountered.
+
+0: try to continue operation
+
+1: panic immediately.  If the `panic` sysctl is also non-zero then the
+   machine will be rebooted.
+
+
+panic_on_stackoverflow:
+=======================
+
+Controls the kernel's behavior when detecting the overflows of
+kernel, IRQ and exception stacks except a user stack.
+This file shows up if CONFIG_DEBUG_STACKOVERFLOW is enabled.
+
+0: try to continue operation.
+
+1: panic immediately.
+
+
+panic_on_unrecovered_nmi:
+=========================
+
+The default Linux behaviour on an NMI of either memory or unknown is
+to continue operation. For many environments such as scientific
+computing it is preferable that the box is taken out and the error
+dealt with than an uncorrected parity/ECC error get propagated.
+
+A small number of systems do generate NMI's for bizarre random reasons
+such as power management so the default is off. That sysctl works like
+the existing panic controls already in that directory.
+
+
+panic_on_warn:
+==============
+
+Calls panic() in the WARN() path when set to 1.  This is useful to avoid
+a kernel rebuild when attempting to kdump at the location of a WARN().
+
+0: only WARN(), default behaviour.
+
+1: call panic() after printing out WARN() location.
+
+
+panic_print:
+============
+
+Bitmask for printing system info when panic happens. User can chose
+combination of the following bits:
+
+=====  ========================================
+bit 0  print all tasks info
+bit 1  print system memory info
+bit 2  print timer info
+bit 3  print locks info if CONFIG_LOCKDEP is on
+bit 4  print ftrace buffer
+=====  ========================================
+
+So for example to print tasks and memory info on panic, user can::
+
+  echo 3 > /proc/sys/kernel/panic_print
+
+
+panic_on_rcu_stall:
+===================
+
+When set to 1, calls panic() after RCU stall detection messages. This
+is useful to define the root cause of RCU stalls using a vmcore.
+
+0: do not panic() when RCU stall takes place, default behavior.
+
+1: panic() after printing RCU stall messages.
+
+
+perf_cpu_time_max_percent:
+==========================
+
+Hints to the kernel how much CPU time it should be allowed to
+use to handle perf sampling events.  If the perf subsystem
+is informed that its samples are exceeding this limit, it
+will drop its sampling frequency to attempt to reduce its CPU
+usage.
+
+Some perf sampling happens in NMIs.  If these samples
+unexpectedly take too long to execute, the NMIs can become
+stacked up next to each other so much that nothing else is
+allowed to execute.
+
+0:
+   disable the mechanism.  Do not monitor or correct perf's
+   sampling rate no matter how CPU time it takes.
+
+1-100:
+   attempt to throttle perf's sample rate to this
+   percentage of CPU.  Note: the kernel calculates an
+   "expected" length of each sample event.  100 here means
+   100% of that expected length.  Even if this is set to
+   100, you may still see sample throttling if this
+   length is exceeded.  Set to 0 if you truly do not care
+   how much CPU is consumed.
+
+
+perf_event_paranoid:
+====================
+
+Controls use of the performance events system by unprivileged
+users (without CAP_SYS_ADMIN).  The default value is 2.
+
+===  ==================================================================
+ -1  Allow use of (almost) all events by all users
+
+     Ignore mlock limit after perf_event_mlock_kb without CAP_IPC_LOCK
+
+>=0  Disallow ftrace function tracepoint by users without CAP_SYS_ADMIN
+
+     Disallow raw tracepoint access by users without CAP_SYS_ADMIN
+
+>=1  Disallow CPU event access by users without CAP_SYS_ADMIN
+
+>=2  Disallow kernel profiling by users without CAP_SYS_ADMIN
+===  ==================================================================
+
+
+perf_event_max_stack:
+=====================
+
+Controls maximum number of stack frames to copy for (attr.sample_type &
+PERF_SAMPLE_CALLCHAIN) configured events, for instance, when using
+'perf record -g' or 'perf trace --call-graph fp'.
+
+This can only be done when no events are in use that have callchains
+enabled, otherwise writing to this file will return -EBUSY.
+
+The default value is 127.
+
+
+perf_event_mlock_kb:
+====================
+
+Control size of per-cpu ring buffer not counted agains mlock limit.
+
+The default value is 512 + 1 page
+
+
+perf_event_max_contexts_per_stack:
+==================================
+
+Controls maximum number of stack frame context entries for
+(attr.sample_type & PERF_SAMPLE_CALLCHAIN) configured events, for
+instance, when using 'perf record -g' or 'perf trace --call-graph fp'.
+
+This can only be done when no events are in use that have callchains
+enabled, otherwise writing to this file will return -EBUSY.
+
+The default value is 8.
+
+
+pid_max:
+========
+
+PID allocation wrap value.  When the kernel's next PID value
+reaches this value, it wraps back to a minimum PID value.
+PIDs of value pid_max or larger are not allocated.
+
+
+ns_last_pid:
+============
+
+The last pid allocated in the current (the one task using this sysctl
+lives in) pid namespace. When selecting a pid for a next task on fork
+kernel tries to allocate a number starting from this one.
+
+
+powersave-nap: (PPC only)
+=========================
+
+If set, Linux-PPC will use the 'nap' mode of powersaving,
+otherwise the 'doze' mode will be used.
+
+==============================================================
+
+printk:
+=======
+
+The four values in printk denote: console_loglevel,
+default_message_loglevel, minimum_console_loglevel and
+default_console_loglevel respectively.
+
+These values influence printk() behavior when printing or
+logging error messages. See 'man 2 syslog' for more info on
+the different loglevels.
+
+- console_loglevel:
+       messages with a higher priority than
+       this will be printed to the console
+- default_message_loglevel:
+       messages without an explicit priority
+       will be printed with this priority
+- minimum_console_loglevel:
+       minimum (highest) value to which
+       console_loglevel can be set
+- default_console_loglevel:
+       default value for console_loglevel
+
+
+printk_delay:
+=============
+
+Delay each printk message in printk_delay milliseconds
+
+Value from 0 - 10000 is allowed.
+
+
+printk_ratelimit:
+=================
+
+Some warning messages are rate limited. printk_ratelimit specifies
+the minimum length of time between these messages (in jiffies), by
+default we allow one every 5 seconds.
+
+A value of 0 will disable rate limiting.
+
+
+printk_ratelimit_burst:
+=======================
+
+While long term we enforce one message per printk_ratelimit
+seconds, we do allow a burst of messages to pass through.
+printk_ratelimit_burst specifies the number of messages we can
+send before ratelimiting kicks in.
+
+
+printk_devkmsg:
+===============
+
+Control the logging to /dev/kmsg from userspace:
+
+ratelimit:
+       default, ratelimited
+
+on: unlimited logging to /dev/kmsg from userspace
+
+off: logging to /dev/kmsg disabled
+
+The kernel command line parameter printk.devkmsg= overrides this and is
+a one-time setting until next reboot: once set, it cannot be changed by
+this sysctl interface anymore.
+
+
+randomize_va_space:
+===================
+
+This option can be used to select the type of process address
+space randomization that is used in the system, for architectures
+that support this feature.
+
+==  ===========================================================================
+0   Turn the process address space randomization off.  This is the
+    default for architectures that do not support this feature anyways,
+    and kernels that are booted with the "norandmaps" parameter.
+
+1   Make the addresses of mmap base, stack and VDSO page randomized.
+    This, among other things, implies that shared libraries will be
+    loaded to random addresses.  Also for PIE-linked binaries, the
+    location of code start is randomized.  This is the default if the
+    CONFIG_COMPAT_BRK option is enabled.
+
+2   Additionally enable heap randomization.  This is the default if
+    CONFIG_COMPAT_BRK is disabled.
+
+    There are a few legacy applications out there (such as some ancient
+    versions of libc.so.5 from 1996) that assume that brk area starts
+    just after the end of the code+bss.  These applications break when
+    start of the brk area is randomized.  There are however no known
+    non-legacy applications that would be broken this way, so for most
+    systems it is safe to choose full randomization.
+
+    Systems with ancient and/or broken binaries should be configured
+    with CONFIG_COMPAT_BRK enabled, which excludes the heap from process
+    address space randomization.
+==  ===========================================================================
+
+
+reboot-cmd: (Sparc only)
+========================
+
+??? This seems to be a way to give an argument to the Sparc
+ROM/Flash boot loader. Maybe to tell it what to do after
+rebooting. ???
+
+
+rtsig-max & rtsig-nr:
+=====================
+
+The file rtsig-max can be used to tune the maximum number
+of POSIX realtime (queued) signals that can be outstanding
+in the system.
+
+rtsig-nr shows the number of RT signals currently queued.
+
+
+sched_energy_aware:
+===================
+
+Enables/disables Energy Aware Scheduling (EAS). EAS starts
+automatically on platforms where it can run (that is,
+platforms with asymmetric CPU topologies and having an Energy
+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.
+
+
+sched_schedstats:
+=================
+
+Enables/disables scheduler statistics. Enabling this feature
+incurs a small amount of overhead in the scheduler but is
+useful for debugging and performance tuning.
+
+
+sg-big-buff:
+============
+
+This file shows the size of the generic SCSI (sg) buffer.
+You can't tune it just yet, but you could change it on
+compile time by editing include/scsi/sg.h and changing
+the value of SG_BIG_BUFF.
+
+There shouldn't be any reason to change this value. If
+you can come up with one, you probably know what you
+are doing anyway :)
+
+
+shmall:
+=======
+
+This parameter sets the total amount of shared memory pages that
+can be used system wide. Hence, SHMALL should always be at least
+ceil(shmmax/PAGE_SIZE).
+
+If you are not sure what the default PAGE_SIZE is on your Linux
+system, you can run the following command:
+
+       # getconf PAGE_SIZE
+
+
+shmmax:
+=======
+
+This value can be used to query and set the run time limit
+on the maximum shared memory segment size that can be created.
+Shared memory segments up to 1Gb are now supported in the
+kernel.  This value defaults to SHMMAX.
+
+
+shm_rmid_forced:
+================
+
+Linux lets you set resource limits, including how much memory one
+process can consume, via setrlimit(2).  Unfortunately, shared memory
+segments are allowed to exist without association with any process, and
+thus might not be counted against any resource limits.  If enabled,
+shared memory segments are automatically destroyed when their attach
+count becomes zero after a detach or a process termination.  It will
+also destroy segments that were created, but never attached to, on exit
+from the process.  The only use left for IPC_RMID is to immediately
+destroy an unattached segment.  Of course, this breaks the way things are
+defined, so some applications might stop working.  Note that this
+feature will do you no good unless you also configure your resource
+limits (in particular, RLIMIT_AS and RLIMIT_NPROC).  Most systems don't
+need this.
+
+Note that if you change this from 0 to 1, already created segments
+without users and with a dead originative process will be destroyed.
+
+
+sysctl_writes_strict:
+=====================
+
+Control how file position affects the behavior of updating sysctl values
+via the /proc/sys interface:
+
+  ==   ======================================================================
+  -1   Legacy per-write sysctl value handling, with no printk warnings.
+       Each write syscall must fully contain the sysctl value to be
+       written, and multiple writes on the same sysctl file descriptor
+       will rewrite the sysctl value, regardless of file position.
+   0   Same behavior as above, but warn about processes that perform writes
+       to a sysctl file descriptor when the file position is not 0.
+   1   (default) Respect file position when writing sysctl strings. Multiple
+       writes will append to the sysctl value buffer. Anything past the max
+       length of the sysctl value buffer will be ignored. Writes to numeric
+       sysctl entries must always be at file position 0 and the value must
+       be fully contained in the buffer sent in the write syscall.
+  ==   ======================================================================
+
+
+softlockup_all_cpu_backtrace:
+=============================
+
+This value controls the soft lockup detector thread's behavior
+when a soft lockup condition is detected as to whether or not
+to gather further debug information. If enabled, each cpu will
+be issued an NMI and instructed to capture stack trace.
+
+This feature is only applicable for architectures which support
+NMI.
+
+0: do nothing. This is the default behavior.
+
+1: on detection capture more debug information.
+
+
+soft_watchdog:
+==============
+
+This parameter can be used to control the soft lockup detector.
+
+   0 - disable the soft lockup detector
+
+   1 - enable the soft lockup detector
+
+The soft lockup detector monitors CPUs for threads that are hogging the CPUs
+without rescheduling voluntarily, and thus prevent the 'watchdog/N' threads
+from running. The mechanism depends on the CPUs ability to respond to timer
+interrupts which are needed for the 'watchdog/N' threads to be woken up by
+the watchdog timer function, otherwise the NMI watchdog - if enabled - can
+detect a hard lockup condition.
+
+
+stack_erasing:
+==============
+
+This parameter can be used to control kernel stack erasing at the end
+of syscalls for kernels built with CONFIG_GCC_PLUGIN_STACKLEAK.
+
+That erasing reduces the information which kernel stack leak bugs
+can reveal and blocks some uninitialized stack variable attacks.
+The tradeoff is the performance impact: on a single CPU system kernel
+compilation sees a 1% slowdown, other systems and workloads may vary.
+
+  0: kernel stack erasing is disabled, STACKLEAK_METRICS are not updated.
+
+  1: kernel stack erasing is enabled (default), it is performed before
+     returning to the userspace at the end of syscalls.
+
+
+tainted
+=======
+
+Non-zero if the kernel has been tainted. Numeric values, which can be
+ORed together. The letters are seen in "Tainted" line of Oops reports.
+
+======  =====  ==============================================================
+     1  `(P)`  proprietary module was loaded
+     2  `(F)`  module was force loaded
+     4  `(S)`  SMP kernel oops on an officially SMP incapable processor
+     8  `(R)`  module was force unloaded
+    16  `(M)`  processor reported a Machine Check Exception (MCE)
+    32  `(B)`  bad page referenced or some unexpected page flags
+    64  `(U)`  taint requested by userspace application
+   128  `(D)`  kernel died recently, i.e. there was an OOPS or BUG
+   256  `(A)`  an ACPI table was overridden by user
+   512  `(W)`  kernel issued warning
+  1024  `(C)`  staging driver was loaded
+  2048  `(I)`  workaround for bug in platform firmware applied
+  4096  `(O)`  externally-built ("out-of-tree") module was loaded
+  8192  `(E)`  unsigned module was loaded
+ 16384  `(L)`  soft lockup occurred
+ 32768  `(K)`  kernel has been live patched
+ 65536  `(X)`  Auxiliary taint, defined and used by for distros
+131072  `(T)`  The kernel was built with the struct randomization plugin
+======  =====  ==============================================================
+
+See Documentation/admin-guide/tainted-kernels.rst for more information.
+
+
+threads-max:
+============
+
+This value controls the maximum number of threads that can be created
+using fork().
+
+During initialization the kernel sets this value such that even if the
+maximum number of threads is created, the thread structures occupy only
+a part (1/8th) of the available RAM pages.
+
+The minimum value that can be written to threads-max is 20.
+
+The maximum value that can be written to threads-max is given by the
+constant FUTEX_TID_MASK (0x3fffffff).
+
+If a value outside of this range is written to threads-max an error
+EINVAL occurs.
+
+The value written is checked against the available RAM pages. If the
+thread structures would occupy too much (more than 1/8th) of the
+available RAM pages threads-max is reduced accordingly.
+
+
+unknown_nmi_panic:
+==================
+
+The value in this file affects behavior of handling NMI. When the
+value is non-zero, unknown NMI is trapped and then panic occurs. At
+that time, kernel debugging information is displayed on console.
+
+NMI switch that most IA32 servers have fires unknown NMI up, for
+example.  If a system hangs up, try pressing the NMI switch.
+
+
+watchdog:
+=========
+
+This parameter can be used to disable or enable the soft lockup detector
+_and_ the NMI watchdog (i.e. the hard lockup detector) at the same time.
+
+   0 - disable both lockup detectors
+
+   1 - enable both lockup detectors
+
+The soft lockup detector and the NMI watchdog can also be disabled or
+enabled individually, using the soft_watchdog and nmi_watchdog parameters.
+If the watchdog parameter is read, for example by executing::
+
+   cat /proc/sys/kernel/watchdog
+
+the output of this command (0 or 1) shows the logical OR of soft_watchdog
+and nmi_watchdog.
+
+
+watchdog_cpumask:
+=================
+
+This value can be used to control on which cpus the watchdog may run.
+The default cpumask is all possible cores, but if NO_HZ_FULL is
+enabled in the kernel config, and cores are specified with the
+nohz_full= boot argument, those cores are excluded by default.
+Offline cores can be included in this mask, and if the core is later
+brought online, the watchdog will be started based on the mask value.
+
+Typically this value would only be touched in the nohz_full case
+to re-enable cores that by default were not running the watchdog,
+if a kernel lockup was suspected on those cores.
+
+The argument value is the standard cpulist format for cpumasks,
+so for example to enable the watchdog on cores 0, 2, 3, and 4 you
+might say::
+
+  echo 0,2-4 > /proc/sys/kernel/watchdog_cpumask
+
+
+watchdog_thresh:
+================
+
+This value can be used to control the frequency of hrtimer and NMI
+events and the soft and hard lockup thresholds. The default threshold
+is 10 seconds.
+
+The softlockup threshold is (2 * watchdog_thresh). Setting this
+tunable to zero will disable lockup detection altogether.
diff --git a/Documentation/admin-guide/sysctl/net.rst b/Documentation/admin-guide/sysctl/net.rst
new file mode 100644 (file)
index 0000000..a7d44e7
--- /dev/null
@@ -0,0 +1,461 @@
+================================
+Documentation for /proc/sys/net/
+================================
+
+Copyright
+
+Copyright (c) 1999
+
+       - Terrehon Bowden <terrehon@pacbell.net>
+       - Bodo Bauer <bb@ricochet.net>
+
+Copyright (c) 2000
+
+       - Jorge Nerin <comandante@zaralinux.com>
+
+Copyright (c) 2009
+
+       - Shen Feng <shen@cn.fujitsu.com>
+
+For general info and legal blurb, please look in index.rst.
+
+------------------------------------------------------------------------------
+
+This file contains the documentation for the sysctl files in
+/proc/sys/net
+
+The interface  to  the  networking  parts  of  the  kernel  is  located  in
+/proc/sys/net. The following table shows all possible subdirectories.  You may
+see only some of them, depending on your kernel's configuration.
+
+
+Table : Subdirectories in /proc/sys/net
+
+ ========= =================== = ========== ==================
+ Directory Content               Directory  Content
+ ========= =================== = ========== ==================
+ core      General parameter     appletalk  Appletalk protocol
+ unix      Unix domain sockets   netrom     NET/ROM
+ 802       E802 protocol         ax25       AX25
+ ethernet  Ethernet protocol     rose       X.25 PLP layer
+ ipv4      IP version 4          x25        X.25 protocol
+ ipx       IPX                   token-ring IBM token ring
+ bridge    Bridging              decnet     DEC net
+ ipv6      IP version 6          tipc       TIPC
+ ========= =================== = ========== ==================
+
+1. /proc/sys/net/core - Network core options
+============================================
+
+bpf_jit_enable
+--------------
+
+This enables the BPF Just in Time (JIT) compiler. BPF is a flexible
+and efficient infrastructure allowing to execute bytecode at various
+hook points. It is used in a number of Linux kernel subsystems such
+as networking (e.g. XDP, tc), tracing (e.g. kprobes, uprobes, tracepoints)
+and security (e.g. seccomp). LLVM has a BPF back end that can compile
+restricted C into a sequence of BPF instructions. After program load
+through bpf(2) and passing a verifier in the kernel, a JIT will then
+translate these BPF proglets into native CPU instructions. There are
+two flavors of JITs, the newer eBPF JIT currently supported on:
+
+  - x86_64
+  - x86_32
+  - arm64
+  - arm32
+  - ppc64
+  - sparc64
+  - mips64
+  - s390x
+  - riscv
+
+And the older cBPF JIT supported on the following archs:
+
+  - mips
+  - ppc
+  - sparc
+
+eBPF JITs are a superset of cBPF JITs, meaning the kernel will
+migrate cBPF instructions into eBPF instructions and then JIT
+compile them transparently. Older cBPF JITs can only translate
+tcpdump filters, seccomp rules, etc, but not mentioned eBPF
+programs loaded through bpf(2).
+
+Values:
+
+       - 0 - disable the JIT (default value)
+       - 1 - enable the JIT
+       - 2 - enable the JIT and ask the compiler to emit traces on kernel log.
+
+bpf_jit_harden
+--------------
+
+This enables hardening for the BPF JIT compiler. Supported are eBPF
+JIT backends. Enabling hardening trades off performance, but can
+mitigate JIT spraying.
+
+Values:
+
+       - 0 - disable JIT hardening (default value)
+       - 1 - enable JIT hardening for unprivileged users only
+       - 2 - enable JIT hardening for all users
+
+bpf_jit_kallsyms
+----------------
+
+When BPF JIT compiler is enabled, then compiled images are unknown
+addresses to the kernel, meaning they neither show up in traces nor
+in /proc/kallsyms. This enables export of these addresses, which can
+be used for debugging/tracing. If bpf_jit_harden is enabled, this
+feature is disabled.
+
+Values :
+
+       - 0 - disable JIT kallsyms export (default value)
+       - 1 - enable JIT kallsyms export for privileged users only
+
+bpf_jit_limit
+-------------
+
+This enforces a global limit for memory allocations to the BPF JIT
+compiler in order to reject unprivileged JIT requests once it has
+been surpassed. bpf_jit_limit contains the value of the global limit
+in bytes.
+
+dev_weight
+----------
+
+The maximum number of packets that kernel can handle on a NAPI interrupt,
+it's a Per-CPU variable. For drivers that support LRO or GRO_HW, a hardware
+aggregated packet is counted as one packet in this context.
+
+Default: 64
+
+dev_weight_rx_bias
+------------------
+
+RPS (e.g. RFS, aRFS) processing is competing with the registered NAPI poll function
+of the driver for the per softirq cycle netdev_budget. This parameter influences
+the proportion of the configured netdev_budget that is spent on RPS based packet
+processing during RX softirq cycles. It is further meant for making current
+dev_weight adaptable for asymmetric CPU needs on RX/TX side of the network stack.
+(see dev_weight_tx_bias) It is effective on a per CPU basis. Determination is based
+on dev_weight and is calculated multiplicative (dev_weight * dev_weight_rx_bias).
+
+Default: 1
+
+dev_weight_tx_bias
+------------------
+
+Scales the maximum number of packets that can be processed during a TX softirq cycle.
+Effective on a per CPU basis. Allows scaling of current dev_weight for asymmetric
+net stack processing needs. Be careful to avoid making TX softirq processing a CPU hog.
+
+Calculation is based on dev_weight (dev_weight * dev_weight_tx_bias).
+
+Default: 1
+
+default_qdisc
+-------------
+
+The default queuing discipline to use for network devices. This allows
+overriding the default of pfifo_fast with an alternative. Since the default
+queuing discipline is created without additional parameters so is best suited
+to queuing disciplines that work well without configuration like stochastic
+fair queue (sfq), CoDel (codel) or fair queue CoDel (fq_codel). Don't use
+queuing disciplines like Hierarchical Token Bucket or Deficit Round Robin
+which require setting up classes and bandwidths. Note that physical multiqueue
+interfaces still use mq as root qdisc, which in turn uses this default for its
+leaves. Virtual devices (like e.g. lo or veth) ignore this setting and instead
+default to noqueue.
+
+Default: pfifo_fast
+
+busy_read
+---------
+
+Low latency busy poll timeout for socket reads. (needs CONFIG_NET_RX_BUSY_POLL)
+Approximate time in us to busy loop waiting for packets on the device queue.
+This sets the default value of the SO_BUSY_POLL socket option.
+Can be set or overridden per socket by setting socket option SO_BUSY_POLL,
+which is the preferred method of enabling. If you need to enable the feature
+globally via sysctl, a value of 50 is recommended.
+
+Will increase power usage.
+
+Default: 0 (off)
+
+busy_poll
+----------------
+Low latency busy poll timeout for poll and select. (needs CONFIG_NET_RX_BUSY_POLL)
+Approximate time in us to busy loop waiting for events.
+Recommended value depends on the number of sockets you poll on.
+For several sockets 50, for several hundreds 100.
+For more than that you probably want to use epoll.
+Note that only sockets with SO_BUSY_POLL set will be busy polled,
+so you want to either selectively set SO_BUSY_POLL on those sockets or set
+sysctl.net.busy_read globally.
+
+Will increase power usage.
+
+Default: 0 (off)
+
+rmem_default
+------------
+
+The default setting of the socket receive buffer in bytes.
+
+rmem_max
+--------
+
+The maximum receive socket buffer size in bytes.
+
+tstamp_allow_data
+-----------------
+Allow processes to receive tx timestamps looped together with the original
+packet contents. If disabled, transmit timestamp requests from unprivileged
+processes are dropped unless socket option SOF_TIMESTAMPING_OPT_TSONLY is set.
+
+Default: 1 (on)
+
+
+wmem_default
+------------
+
+The default setting (in bytes) of the socket send buffer.
+
+wmem_max
+--------
+
+The maximum send socket buffer size in bytes.
+
+message_burst and message_cost
+------------------------------
+
+These parameters  are used to limit the warning messages written to the kernel
+log from  the  networking  code.  They  enforce  a  rate  limit  to  make  a
+denial-of-service attack  impossible. A higher message_cost factor, results in
+fewer messages that will be written. Message_burst controls when messages will
+be dropped.  The  default  settings  limit  warning messages to one every five
+seconds.
+
+warnings
+--------
+
+This sysctl is now unused.
+
+This was used to control console messages from the networking stack that
+occur because of problems on the network like duplicate address or bad
+checksums.
+
+These messages are now emitted at KERN_DEBUG and can generally be enabled
+and controlled by the dynamic_debug facility.
+
+netdev_budget
+-------------
+
+Maximum number of packets taken from all interfaces in one polling cycle (NAPI
+poll). In one polling cycle interfaces which are registered to polling are
+probed in a round-robin manner. Also, a polling cycle may not exceed
+netdev_budget_usecs microseconds, even if netdev_budget has not been
+exhausted.
+
+netdev_budget_usecs
+---------------------
+
+Maximum number of microseconds in one NAPI polling cycle. Polling
+will exit when either netdev_budget_usecs have elapsed during the
+poll cycle or the number of packets processed reaches netdev_budget.
+
+netdev_max_backlog
+------------------
+
+Maximum number  of  packets,  queued  on  the  INPUT  side, when the interface
+receives packets faster than kernel can process them.
+
+netdev_rss_key
+--------------
+
+RSS (Receive Side Scaling) enabled drivers use a 40 bytes host key that is
+randomly generated.
+Some user space might need to gather its content even if drivers do not
+provide ethtool -x support yet.
+
+::
+
+  myhost:~# cat /proc/sys/net/core/netdev_rss_key
+  84:50:f4:00:a8:15:d1:a7:e9:7f:1d:60:35:c7:47:25:42:97:74:ca:56:bb:b6:a1:d8: ... (52 bytes total)
+
+File contains nul bytes if no driver ever called netdev_rss_key_fill() function.
+
+Note:
+  /proc/sys/net/core/netdev_rss_key contains 52 bytes of key,
+  but most drivers only use 40 bytes of it.
+
+::
+
+  myhost:~# ethtool -x eth0
+  RX flow hash indirection table for eth0 with 8 RX ring(s):
+      0:    0     1     2     3     4     5     6     7
+  RSS hash key:
+  84:50:f4:00:a8:15:d1:a7:e9:7f:1d:60:35:c7:47:25:42:97:74:ca:56:bb:b6:a1:d8:43:e3:c9:0c:fd:17:55:c2:3a:4d:69:ed:f1:42:89
+
+netdev_tstamp_prequeue
+----------------------
+
+If set to 0, RX packet timestamps can be sampled after RPS processing, when
+the target CPU processes packets. It might give some delay on timestamps, but
+permit to distribute the load on several cpus.
+
+If set to 1 (default), timestamps are sampled as soon as possible, before
+queueing.
+
+optmem_max
+----------
+
+Maximum ancillary buffer size allowed per socket. Ancillary data is a sequence
+of struct cmsghdr structures with appended data.
+
+fb_tunnels_only_for_init_net
+----------------------------
+
+Controls if fallback tunnels (like tunl0, gre0, gretap0, erspan0,
+sit0, ip6tnl0, ip6gre0) are automatically created when a new
+network namespace is created, if corresponding tunnel is present
+in initial network namespace.
+If set to 1, these devices are not automatically created, and
+user space is responsible for creating them if needed.
+
+Default : 0  (for compatibility reasons)
+
+devconf_inherit_init_net
+------------------------
+
+Controls if a new network namespace should inherit all current
+settings under /proc/sys/net/{ipv4,ipv6}/conf/{all,default}/. By
+default, we keep the current behavior: for IPv4 we inherit all current
+settings from init_net and for IPv6 we reset all settings to default.
+
+If set to 1, both IPv4 and IPv6 settings are forced to inherit from
+current ones in init_net. If set to 2, both IPv4 and IPv6 settings are
+forced to reset to their default values.
+
+Default : 0  (for compatibility reasons)
+
+2. /proc/sys/net/unix - Parameters for Unix domain sockets
+----------------------------------------------------------
+
+There is only one file in this directory.
+unix_dgram_qlen limits the max number of datagrams queued in Unix domain
+socket's buffer. It will not take effect unless PF_UNIX flag is specified.
+
+
+3. /proc/sys/net/ipv4 - IPV4 settings
+-------------------------------------
+Please see: Documentation/networking/ip-sysctl.txt and ipvs-sysctl.txt for
+descriptions of these entries.
+
+
+4. Appletalk
+------------
+
+The /proc/sys/net/appletalk  directory  holds the Appletalk configuration data
+when Appletalk is loaded. The configurable parameters are:
+
+aarp-expiry-time
+----------------
+
+The amount  of  time  we keep an ARP entry before expiring it. Used to age out
+old hosts.
+
+aarp-resolve-time
+-----------------
+
+The amount of time we will spend trying to resolve an Appletalk address.
+
+aarp-retransmit-limit
+---------------------
+
+The number of times we will retransmit a query before giving up.
+
+aarp-tick-time
+--------------
+
+Controls the rate at which expires are checked.
+
+The directory  /proc/net/appletalk  holds the list of active Appletalk sockets
+on a machine.
+
+The fields  indicate  the DDP type, the local address (in network:node format)
+the remote  address,  the  size of the transmit pending queue, the size of the
+received queue  (bytes waiting for applications to read) the state and the uid
+owning the socket.
+
+/proc/net/atalk_iface lists  all  the  interfaces  configured for appletalk.It
+shows the  name  of the interface, its Appletalk address, the network range on
+that address  (or  network number for phase 1 networks), and the status of the
+interface.
+
+/proc/net/atalk_route lists  each  known  network  route.  It lists the target
+(network) that the route leads to, the router (may be directly connected), the
+route flags, and the device the route is using.
+
+
+5. IPX
+------
+
+The IPX protocol has no tunable values in proc/sys/net.
+
+The IPX  protocol  does,  however,  provide  proc/net/ipx. This lists each IPX
+socket giving  the  local  and  remote  addresses  in  Novell  format (that is
+network:node:port). In  accordance  with  the  strange  Novell  tradition,
+everything but the port is in hex. Not_Connected is displayed for sockets that
+are not  tied to a specific remote address. The Tx and Rx queue sizes indicate
+the number  of  bytes  pending  for  transmission  and  reception.  The  state
+indicates the  state  the  socket  is  in and the uid is the owning uid of the
+socket.
+
+The /proc/net/ipx_interface  file lists all IPX interfaces. For each interface
+it gives  the network number, the node number, and indicates if the network is
+the primary  network.  It  also  indicates  which  device  it  is bound to (or
+Internal for  internal  networks)  and  the  Frame  Type if appropriate. Linux
+supports 802.3,  802.2,  802.2  SNAP  and DIX (Blue Book) ethernet framing for
+IPX.
+
+The /proc/net/ipx_route  table  holds  a list of IPX routes. For each route it
+gives the  destination  network, the router node (or Directly) and the network
+address of the router (or Connected) for internal networks.
+
+6. TIPC
+-------
+
+tipc_rmem
+---------
+
+The TIPC protocol now has a tunable for the receive memory, similar to the
+tcp_rmem - i.e. a vector of 3 INTEGERs: (min, default, max)
+
+::
+
+    # cat /proc/sys/net/tipc/tipc_rmem
+    4252725 34021800        68043600
+    #
+
+The max value is set to CONN_OVERLOAD_LIMIT, and the default and min values
+are scaled (shifted) versions of that same value.  Note that the min value
+is not at this point in time used in any meaningful way, but the triplet is
+preserved in order to be consistent with things like tcp_rmem.
+
+named_timeout
+-------------
+
+TIPC name table updates are distributed asynchronously in a cluster, without
+any form of transaction handling. This means that different race scenarios are
+possible. One such is that a name withdrawal sent out by one node and received
+by another node may arrive after a second, overlapping name publication already
+has been accepted from a third node, although the conflicting updates
+originally may have been issued in the correct sequential order.
+If named_timeout is nonzero, failed topology updates will be placed on a defer
+queue until another event arrives that clears the error, or until the timeout
+expires. Value is in milliseconds.
diff --git a/Documentation/admin-guide/sysctl/sunrpc.rst b/Documentation/admin-guide/sysctl/sunrpc.rst
new file mode 100644 (file)
index 0000000..09780a6
--- /dev/null
@@ -0,0 +1,25 @@
+===================================
+Documentation for /proc/sys/sunrpc/
+===================================
+
+kernel version 2.2.10
+
+Copyright (c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
+
+For general info and legal blurb, please look in index.rst.
+
+------------------------------------------------------------------------------
+
+This file contains the documentation for the sysctl files in
+/proc/sys/sunrpc and is valid for Linux kernel version 2.2.
+
+The files in this directory can be used to (re)set the debug
+flags of the SUN Remote Procedure Call (RPC) subsystem in
+the Linux kernel. This stuff is used for NFS, KNFSD and
+maybe a few other things as well.
+
+The files in there are used to control the debugging flags:
+rpc_debug, nfs_debug, nfsd_debug and nlm_debug.
+
+These flags are for kernel hackers only. You should read the
+source code in net/sunrpc/ for more information.
diff --git a/Documentation/admin-guide/sysctl/user.rst b/Documentation/admin-guide/sysctl/user.rst
new file mode 100644 (file)
index 0000000..650eaa0
--- /dev/null
@@ -0,0 +1,78 @@
+=================================
+Documentation for /proc/sys/user/
+=================================
+
+kernel version 4.9.0
+
+Copyright (c) 2016             Eric Biederman <ebiederm@xmission.com>
+
+------------------------------------------------------------------------------
+
+This file contains the documentation for the sysctl files in
+/proc/sys/user.
+
+The files in this directory can be used to override the default
+limits on the number of namespaces and other objects that have
+per user per user namespace limits.
+
+The primary purpose of these limits is to stop programs that
+malfunction and attempt to create a ridiculous number of objects,
+before the malfunction becomes a system wide problem.  It is the
+intention that the defaults of these limits are set high enough that
+no program in normal operation should run into these limits.
+
+The creation of per user per user namespace objects are charged to
+the user in the user namespace who created the object and
+verified to be below the per user limit in that user namespace.
+
+The creation of objects is also charged to all of the users
+who created user namespaces the creation of the object happens
+in (user namespaces can be nested) and verified to be below the per user
+limits in the user namespaces of those users.
+
+This recursive counting of created objects ensures that creating a
+user namespace does not allow a user to escape their current limits.
+
+Currently, these files are in /proc/sys/user:
+
+max_cgroup_namespaces
+=====================
+
+  The maximum number of cgroup namespaces that any user in the current
+  user namespace may create.
+
+max_ipc_namespaces
+==================
+
+  The maximum number of ipc namespaces that any user in the current
+  user namespace may create.
+
+max_mnt_namespaces
+==================
+
+  The maximum number of mount namespaces that any user in the current
+  user namespace may create.
+
+max_net_namespaces
+==================
+
+  The maximum number of network namespaces that any user in the
+  current user namespace may create.
+
+max_pid_namespaces
+==================
+
+  The maximum number of pid namespaces that any user in the current
+  user namespace may create.
+
+max_user_namespaces
+===================
+
+  The maximum number of user namespaces that any user in the current
+  user namespace may create.
+
+max_uts_namespaces
+==================
+
+  The maximum number of user namespaces that any user in the current
+  user namespace may create.
diff --git a/Documentation/admin-guide/sysctl/vm.rst b/Documentation/admin-guide/sysctl/vm.rst
new file mode 100644 (file)
index 0000000..64aeee1
--- /dev/null
@@ -0,0 +1,964 @@
+===============================
+Documentation for /proc/sys/vm/
+===============================
+
+kernel version 2.6.29
+
+Copyright (c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
+
+Copyright (c) 2008         Peter W. Morreale <pmorreale@novell.com>
+
+For general info and legal blurb, please look in index.rst.
+
+------------------------------------------------------------------------------
+
+This file contains the documentation for the sysctl files in
+/proc/sys/vm and is valid for Linux kernel version 2.6.29.
+
+The files in this directory can be used to tune the operation
+of the virtual memory (VM) subsystem of the Linux kernel and
+the writeout of dirty data to disk.
+
+Default values and initialization routines for most of these
+files can be found in mm/swap.c.
+
+Currently, these files are in /proc/sys/vm:
+
+- admin_reserve_kbytes
+- block_dump
+- compact_memory
+- compact_unevictable_allowed
+- dirty_background_bytes
+- dirty_background_ratio
+- dirty_bytes
+- dirty_expire_centisecs
+- dirty_ratio
+- dirtytime_expire_seconds
+- dirty_writeback_centisecs
+- drop_caches
+- extfrag_threshold
+- hugetlb_shm_group
+- laptop_mode
+- legacy_va_layout
+- lowmem_reserve_ratio
+- max_map_count
+- memory_failure_early_kill
+- memory_failure_recovery
+- min_free_kbytes
+- min_slab_ratio
+- min_unmapped_ratio
+- mmap_min_addr
+- mmap_rnd_bits
+- mmap_rnd_compat_bits
+- nr_hugepages
+- nr_hugepages_mempolicy
+- nr_overcommit_hugepages
+- nr_trim_pages         (only if CONFIG_MMU=n)
+- numa_zonelist_order
+- oom_dump_tasks
+- oom_kill_allocating_task
+- overcommit_kbytes
+- overcommit_memory
+- overcommit_ratio
+- page-cluster
+- panic_on_oom
+- percpu_pagelist_fraction
+- stat_interval
+- stat_refresh
+- numa_stat
+- swappiness
+- unprivileged_userfaultfd
+- user_reserve_kbytes
+- vfs_cache_pressure
+- watermark_boost_factor
+- watermark_scale_factor
+- zone_reclaim_mode
+
+
+admin_reserve_kbytes
+====================
+
+The amount of free memory in the system that should be reserved for users
+with the capability cap_sys_admin.
+
+admin_reserve_kbytes defaults to min(3% of free pages, 8MB)
+
+That should provide enough for the admin to log in and kill a process,
+if necessary, under the default overcommit 'guess' mode.
+
+Systems running under overcommit 'never' should increase this to account
+for the full Virtual Memory Size of programs used to recover. Otherwise,
+root may not be able to log in to recover the system.
+
+How do you calculate a minimum useful reserve?
+
+sshd or login + bash (or some other shell) + top (or ps, kill, etc.)
+
+For overcommit 'guess', we can sum resident set sizes (RSS).
+On x86_64 this is about 8MB.
+
+For overcommit 'never', we can take the max of their virtual sizes (VSZ)
+and add the sum of their RSS.
+On x86_64 this is about 128MB.
+
+Changing this takes effect whenever an application requests memory.
+
+
+block_dump
+==========
+
+block_dump enables block I/O debugging when set to a nonzero value. More
+information on block I/O debugging is in Documentation/admin-guide/laptops/laptop-mode.rst.
+
+
+compact_memory
+==============
+
+Available only when CONFIG_COMPACTION is set. When 1 is written to the file,
+all zones are compacted such that free memory is available in contiguous
+blocks where possible. This can be important for example in the allocation of
+huge pages although processes will also directly compact memory as required.
+
+
+compact_unevictable_allowed
+===========================
+
+Available only when CONFIG_COMPACTION is set. When set to 1, compaction is
+allowed to examine the unevictable lru (mlocked pages) for pages to compact.
+This should be used on systems where stalls for minor page faults are an
+acceptable trade for large contiguous free memory.  Set to 0 to prevent
+compaction from moving pages that are unevictable.  Default value is 1.
+
+
+dirty_background_bytes
+======================
+
+Contains the amount of dirty memory at which the background kernel
+flusher threads will start writeback.
+
+Note:
+  dirty_background_bytes is the counterpart of dirty_background_ratio. Only
+  one of them may be specified at a time. When one sysctl is written it is
+  immediately taken into account to evaluate the dirty memory limits and the
+  other appears as 0 when read.
+
+
+dirty_background_ratio
+======================
+
+Contains, as a percentage of total available memory that contains free pages
+and reclaimable pages, the number of pages at which the background kernel
+flusher threads will start writing out dirty data.
+
+The total available memory is not equal to total system memory.
+
+
+dirty_bytes
+===========
+
+Contains the amount of dirty memory at which a process generating disk writes
+will itself start writeback.
+
+Note: dirty_bytes is the counterpart of dirty_ratio. Only one of them may be
+specified at a time. When one sysctl is written it is immediately taken into
+account to evaluate the dirty memory limits and the other appears as 0 when
+read.
+
+Note: the minimum value allowed for dirty_bytes is two pages (in bytes); any
+value lower than this limit will be ignored and the old configuration will be
+retained.
+
+
+dirty_expire_centisecs
+======================
+
+This tunable is used to define when dirty data is old enough to be eligible
+for writeout by the kernel flusher threads.  It is expressed in 100'ths
+of a second.  Data which has been dirty in-memory for longer than this
+interval will be written out next time a flusher thread wakes up.
+
+
+dirty_ratio
+===========
+
+Contains, as a percentage of total available memory that contains free pages
+and reclaimable pages, the number of pages at which a process which is
+generating disk writes will itself start writing out dirty data.
+
+The total available memory is not equal to total system memory.
+
+
+dirtytime_expire_seconds
+========================
+
+When a lazytime inode is constantly having its pages dirtied, the inode with
+an updated timestamp will never get chance to be written out.  And, if the
+only thing that has happened on the file system is a dirtytime inode caused
+by an atime update, a worker will be scheduled to make sure that inode
+eventually gets pushed out to disk.  This tunable is used to define when dirty
+inode is old enough to be eligible for writeback by the kernel flusher threads.
+And, it is also used as the interval to wakeup dirtytime_writeback thread.
+
+
+dirty_writeback_centisecs
+=========================
+
+The kernel flusher threads will periodically wake up and write `old` data
+out to disk.  This tunable expresses the interval between those wakeups, in
+100'ths of a second.
+
+Setting this to zero disables periodic writeback altogether.
+
+
+drop_caches
+===========
+
+Writing to this will cause the kernel to drop clean caches, as well as
+reclaimable slab objects like dentries and inodes.  Once dropped, their
+memory becomes free.
+
+To free pagecache::
+
+       echo 1 > /proc/sys/vm/drop_caches
+
+To free reclaimable slab objects (includes dentries and inodes)::
+
+       echo 2 > /proc/sys/vm/drop_caches
+
+To free slab objects and pagecache::
+
+       echo 3 > /proc/sys/vm/drop_caches
+
+This is a non-destructive operation and will not free any dirty objects.
+To increase the number of objects freed by this operation, the user may run
+`sync` prior to writing to /proc/sys/vm/drop_caches.  This will minimize the
+number of dirty objects on the system and create more candidates to be
+dropped.
+
+This file is not a means to control the growth of the various kernel caches
+(inodes, dentries, pagecache, etc...)  These objects are automatically
+reclaimed by the kernel when memory is needed elsewhere on the system.
+
+Use of this file can cause performance problems.  Since it discards cached
+objects, it may cost a significant amount of I/O and CPU to recreate the
+dropped objects, especially if they were under heavy use.  Because of this,
+use outside of a testing or debugging environment is not recommended.
+
+You may see informational messages in your kernel log when this file is
+used::
+
+       cat (1234): drop_caches: 3
+
+These are informational only.  They do not mean that anything is wrong
+with your system.  To disable them, echo 4 (bit 2) into drop_caches.
+
+
+extfrag_threshold
+=================
+
+This parameter affects whether the kernel will compact memory or direct
+reclaim to satisfy a high-order allocation. The extfrag/extfrag_index file in
+debugfs shows what the fragmentation index for each order is in each zone in
+the system. Values tending towards 0 imply allocations would fail due to lack
+of memory, values towards 1000 imply failures are due to fragmentation and -1
+implies that the allocation will succeed as long as watermarks are met.
+
+The kernel will not compact memory in a zone if the
+fragmentation index is <= extfrag_threshold. The default value is 500.
+
+
+highmem_is_dirtyable
+====================
+
+Available only for systems with CONFIG_HIGHMEM enabled (32b systems).
+
+This parameter controls whether the high memory is considered for dirty
+writers throttling.  This is not the case by default which means that
+only the amount of memory directly visible/usable by the kernel can
+be dirtied. As a result, on systems with a large amount of memory and
+lowmem basically depleted writers might be throttled too early and
+streaming writes can get very slow.
+
+Changing the value to non zero would allow more memory to be dirtied
+and thus allow writers to write more data which can be flushed to the
+storage more effectively. Note this also comes with a risk of pre-mature
+OOM killer because some writers (e.g. direct block device writes) can
+only use the low memory and they can fill it up with dirty data without
+any throttling.
+
+
+hugetlb_shm_group
+=================
+
+hugetlb_shm_group contains group id that is allowed to create SysV
+shared memory segment using hugetlb page.
+
+
+laptop_mode
+===========
+
+laptop_mode is a knob that controls "laptop mode". All the things that are
+controlled by this knob are discussed in Documentation/admin-guide/laptops/laptop-mode.rst.
+
+
+legacy_va_layout
+================
+
+If non-zero, this sysctl disables the new 32-bit mmap layout - the kernel
+will use the legacy (2.4) layout for all processes.
+
+
+lowmem_reserve_ratio
+====================
+
+For some specialised workloads on highmem machines it is dangerous for
+the kernel to allow process memory to be allocated from the "lowmem"
+zone.  This is because that memory could then be pinned via the mlock()
+system call, or by unavailability of swapspace.
+
+And on large highmem machines this lack of reclaimable lowmem memory
+can be fatal.
+
+So the Linux page allocator has a mechanism which prevents allocations
+which *could* use highmem from using too much lowmem.  This means that
+a certain amount of lowmem is defended from the possibility of being
+captured into pinned user memory.
+
+(The same argument applies to the old 16 megabyte ISA DMA region.  This
+mechanism will also defend that region from allocations which could use
+highmem or lowmem).
+
+The `lowmem_reserve_ratio` tunable determines how aggressive the kernel is
+in defending these lower zones.
+
+If you have a machine which uses highmem or ISA DMA and your
+applications are using mlock(), or if you are running with no swap then
+you probably should change the lowmem_reserve_ratio setting.
+
+The lowmem_reserve_ratio is an array. You can see them by reading this file::
+
+       % cat /proc/sys/vm/lowmem_reserve_ratio
+       256     256     32
+
+But, these values are not used directly. The kernel calculates # of protection
+pages for each zones from them. These are shown as array of protection pages
+in /proc/zoneinfo like followings. (This is an example of x86-64 box).
+Each zone has an array of protection pages like this::
+
+  Node 0, zone      DMA
+    pages free     1355
+          min      3
+          low      3
+          high     4
+       :
+       :
+      numa_other   0
+          protection: (0, 2004, 2004, 2004)
+       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    pagesets
+      cpu: 0 pcp: 0
+          :
+
+These protections are added to score to judge whether this zone should be used
+for page allocation or should be reclaimed.
+
+In this example, if normal pages (index=2) are required to this DMA zone and
+watermark[WMARK_HIGH] is used for watermark, the kernel judges this zone should
+not be used because pages_free(1355) is smaller than watermark + protection[2]
+(4 + 2004 = 2008). If this protection value is 0, this zone would be used for
+normal page requirement. If requirement is DMA zone(index=0), protection[0]
+(=0) is used.
+
+zone[i]'s protection[j] is calculated by following expression::
+
+  (i < j):
+    zone[i]->protection[j]
+    = (total sums of managed_pages from zone[i+1] to zone[j] on the node)
+      / lowmem_reserve_ratio[i];
+  (i = j):
+     (should not be protected. = 0;
+  (i > j):
+     (not necessary, but looks 0)
+
+The default values of lowmem_reserve_ratio[i] are
+
+    === ====================================
+    256 (if zone[i] means DMA or DMA32 zone)
+    32  (others)
+    === ====================================
+
+As above expression, they are reciprocal number of ratio.
+256 means 1/256. # of protection pages becomes about "0.39%" of total managed
+pages of higher zones on the node.
+
+If you would like to protect more pages, smaller values are effective.
+The minimum value is 1 (1/1 -> 100%). The value less than 1 completely
+disables protection of the pages.
+
+
+max_map_count:
+==============
+
+This file contains the maximum number of memory map areas a process
+may have. Memory map areas are used as a side-effect of calling
+malloc, directly by mmap, mprotect, and madvise, and also when loading
+shared libraries.
+
+While most applications need less than a thousand maps, certain
+programs, particularly malloc debuggers, may consume lots of them,
+e.g., up to one or two maps per allocation.
+
+The default value is 65536.
+
+
+memory_failure_early_kill:
+==========================
+
+Control how to kill processes when uncorrected memory error (typically
+a 2bit error in a memory module) is detected in the background by hardware
+that cannot be handled by the kernel. In some cases (like the page
+still having a valid copy on disk) the kernel will handle the failure
+transparently without affecting any applications. But if there is
+no other uptodate copy of the data it will kill to prevent any data
+corruptions from propagating.
+
+1: Kill all processes that have the corrupted and not reloadable page mapped
+as soon as the corruption is detected.  Note this is not supported
+for a few types of pages, like kernel internally allocated data or
+the swap cache, but works for the majority of user pages.
+
+0: Only unmap the corrupted page from all processes and only kill a process
+who tries to access it.
+
+The kill is done using a catchable SIGBUS with BUS_MCEERR_AO, so processes can
+handle this if they want to.
+
+This is only active on architectures/platforms with advanced machine
+check handling and depends on the hardware capabilities.
+
+Applications can override this setting individually with the PR_MCE_KILL prctl
+
+
+memory_failure_recovery
+=======================
+
+Enable memory failure recovery (when supported by the platform)
+
+1: Attempt recovery.
+
+0: Always panic on a memory failure.
+
+
+min_free_kbytes
+===============
+
+This is used to force the Linux VM to keep a minimum number
+of kilobytes free.  The VM uses this number to compute a
+watermark[WMARK_MIN] value for each lowmem zone in the system.
+Each lowmem zone gets a number of reserved free pages based
+proportionally on its size.
+
+Some minimal amount of memory is needed to satisfy PF_MEMALLOC
+allocations; if you set this to lower than 1024KB, your system will
+become subtly broken, and prone to deadlock under high loads.
+
+Setting this too high will OOM your machine instantly.
+
+
+min_slab_ratio
+==============
+
+This is available only on NUMA kernels.
+
+A percentage of the total pages in each zone.  On Zone reclaim
+(fallback from the local zone occurs) slabs will be reclaimed if more
+than this percentage of pages in a zone are reclaimable slab pages.
+This insures that the slab growth stays under control even in NUMA
+systems that rarely perform global reclaim.
+
+The default is 5 percent.
+
+Note that slab reclaim is triggered in a per zone / node fashion.
+The process of reclaiming slab memory is currently not node specific
+and may not be fast.
+
+
+min_unmapped_ratio
+==================
+
+This is available only on NUMA kernels.
+
+This is a percentage of the total pages in each zone. Zone reclaim will
+only occur if more than this percentage of pages are in a state that
+zone_reclaim_mode allows to be reclaimed.
+
+If zone_reclaim_mode has the value 4 OR'd, then the percentage is compared
+against all file-backed unmapped pages including swapcache pages and tmpfs
+files. Otherwise, only unmapped pages backed by normal files but not tmpfs
+files and similar are considered.
+
+The default is 1 percent.
+
+
+mmap_min_addr
+=============
+
+This file indicates the amount of address space  which a user process will
+be restricted from mmapping.  Since kernel null dereference bugs could
+accidentally operate based on the information in the first couple of pages
+of memory userspace processes should not be allowed to write to them.  By
+default this value is set to 0 and no protections will be enforced by the
+security module.  Setting this value to something like 64k will allow the
+vast majority of applications to work correctly and provide defense in depth
+against future potential kernel bugs.
+
+
+mmap_rnd_bits
+=============
+
+This value can be used to select the number of bits to use to
+determine the random offset to the base address of vma regions
+resulting from mmap allocations on architectures which support
+tuning address space randomization.  This value will be bounded
+by the architecture's minimum and maximum supported values.
+
+This value can be changed after boot using the
+/proc/sys/vm/mmap_rnd_bits tunable
+
+
+mmap_rnd_compat_bits
+====================
+
+This value can be used to select the number of bits to use to
+determine the random offset to the base address of vma regions
+resulting from mmap allocations for applications run in
+compatibility mode on architectures which support tuning address
+space randomization.  This value will be bounded by the
+architecture's minimum and maximum supported values.
+
+This value can be changed after boot using the
+/proc/sys/vm/mmap_rnd_compat_bits tunable
+
+
+nr_hugepages
+============
+
+Change the minimum size of the hugepage pool.
+
+See Documentation/admin-guide/mm/hugetlbpage.rst
+
+
+nr_hugepages_mempolicy
+======================
+
+Change the size of the hugepage pool at run-time on a specific
+set of NUMA nodes.
+
+See Documentation/admin-guide/mm/hugetlbpage.rst
+
+
+nr_overcommit_hugepages
+=======================
+
+Change the maximum size of the hugepage pool. The maximum is
+nr_hugepages + nr_overcommit_hugepages.
+
+See Documentation/admin-guide/mm/hugetlbpage.rst
+
+
+nr_trim_pages
+=============
+
+This is available only on NOMMU kernels.
+
+This value adjusts the excess page trimming behaviour of power-of-2 aligned
+NOMMU mmap allocations.
+
+A value of 0 disables trimming of allocations entirely, while a value of 1
+trims excess pages aggressively. Any value >= 1 acts as the watermark where
+trimming of allocations is initiated.
+
+The default value is 1.
+
+See Documentation/nommu-mmap.txt for more information.
+
+
+numa_zonelist_order
+===================
+
+This sysctl is only for NUMA and it is deprecated. Anything but
+Node order will fail!
+
+'where the memory is allocated from' is controlled by zonelists.
+
+(This documentation ignores ZONE_HIGHMEM/ZONE_DMA32 for simple explanation.
+you may be able to read ZONE_DMA as ZONE_DMA32...)
+
+In non-NUMA case, a zonelist for GFP_KERNEL is ordered as following.
+ZONE_NORMAL -> ZONE_DMA
+This means that a memory allocation request for GFP_KERNEL will
+get memory from ZONE_DMA only when ZONE_NORMAL is not available.
+
+In NUMA case, you can think of following 2 types of order.
+Assume 2 node NUMA and below is zonelist of Node(0)'s GFP_KERNEL::
+
+  (A) Node(0) ZONE_NORMAL -> Node(0) ZONE_DMA -> Node(1) ZONE_NORMAL
+  (B) Node(0) ZONE_NORMAL -> Node(1) ZONE_NORMAL -> Node(0) ZONE_DMA.
+
+Type(A) offers the best locality for processes on Node(0), but ZONE_DMA
+will be used before ZONE_NORMAL exhaustion. This increases possibility of
+out-of-memory(OOM) of ZONE_DMA because ZONE_DMA is tend to be small.
+
+Type(B) cannot offer the best locality but is more robust against OOM of
+the DMA zone.
+
+Type(A) is called as "Node" order. Type (B) is "Zone" order.
+
+"Node order" orders the zonelists by node, then by zone within each node.
+Specify "[Nn]ode" for node order
+
+"Zone Order" orders the zonelists by zone type, then by node within each
+zone.  Specify "[Zz]one" for zone order.
+
+Specify "[Dd]efault" to request automatic configuration.
+
+On 32-bit, the Normal zone needs to be preserved for allocations accessible
+by the kernel, so "zone" order will be selected.
+
+On 64-bit, devices that require DMA32/DMA are relatively rare, so "node"
+order will be selected.
+
+Default order is recommended unless this is causing problems for your
+system/application.
+
+
+oom_dump_tasks
+==============
+
+Enables a system-wide task dump (excluding kernel threads) to be produced
+when the kernel performs an OOM-killing and includes such information as
+pid, uid, tgid, vm size, rss, pgtables_bytes, swapents, oom_score_adj
+score, and name.  This is helpful to determine why the OOM killer was
+invoked, to identify the rogue task that caused it, and to determine why
+the OOM killer chose the task it did to kill.
+
+If this is set to zero, this information is suppressed.  On very
+large systems with thousands of tasks it may not be feasible to dump
+the memory state information for each one.  Such systems should not
+be forced to incur a performance penalty in OOM conditions when the
+information may not be desired.
+
+If this is set to non-zero, this information is shown whenever the
+OOM killer actually kills a memory-hogging task.
+
+The default value is 1 (enabled).
+
+
+oom_kill_allocating_task
+========================
+
+This enables or disables killing the OOM-triggering task in
+out-of-memory situations.
+
+If this is set to zero, the OOM killer will scan through the entire
+tasklist and select a task based on heuristics to kill.  This normally
+selects a rogue memory-hogging task that frees up a large amount of
+memory when killed.
+
+If this is set to non-zero, the OOM killer simply kills the task that
+triggered the out-of-memory condition.  This avoids the expensive
+tasklist scan.
+
+If panic_on_oom is selected, it takes precedence over whatever value
+is used in oom_kill_allocating_task.
+
+The default value is 0.
+
+
+overcommit_kbytes
+=================
+
+When overcommit_memory is set to 2, the committed address space is not
+permitted to exceed swap plus this amount of physical RAM. See below.
+
+Note: overcommit_kbytes is the counterpart of overcommit_ratio. Only one
+of them may be specified at a time. Setting one disables the other (which
+then appears as 0 when read).
+
+
+overcommit_memory
+=================
+
+This value contains a flag that enables memory overcommitment.
+
+When this flag is 0, the kernel attempts to estimate the amount
+of free memory left when userspace requests more memory.
+
+When this flag is 1, the kernel pretends there is always enough
+memory until it actually runs out.
+
+When this flag is 2, the kernel uses a "never overcommit"
+policy that attempts to prevent any overcommit of memory.
+Note that user_reserve_kbytes affects this policy.
+
+This feature can be very useful because there are a lot of
+programs that malloc() huge amounts of memory "just-in-case"
+and don't use much of it.
+
+The default value is 0.
+
+See Documentation/vm/overcommit-accounting.rst and
+mm/util.c::__vm_enough_memory() for more information.
+
+
+overcommit_ratio
+================
+
+When overcommit_memory is set to 2, the committed address
+space is not permitted to exceed swap plus this percentage
+of physical RAM.  See above.
+
+
+page-cluster
+============
+
+page-cluster controls the number of pages up to which consecutive pages
+are read in from swap in a single attempt. This is the swap counterpart
+to page cache readahead.
+The mentioned consecutivity is not in terms of virtual/physical addresses,
+but consecutive on swap space - that means they were swapped out together.
+
+It is a logarithmic value - setting it to zero means "1 page", setting
+it to 1 means "2 pages", setting it to 2 means "4 pages", etc.
+Zero disables swap readahead completely.
+
+The default value is three (eight pages at a time).  There may be some
+small benefits in tuning this to a different value if your workload is
+swap-intensive.
+
+Lower values mean lower latencies for initial faults, but at the same time
+extra faults and I/O delays for following faults if they would have been part of
+that consecutive pages readahead would have brought in.
+
+
+panic_on_oom
+============
+
+This enables or disables panic on out-of-memory feature.
+
+If this is set to 0, the kernel will kill some rogue process,
+called oom_killer.  Usually, oom_killer can kill rogue processes and
+system will survive.
+
+If this is set to 1, the kernel panics when out-of-memory happens.
+However, if a process limits using nodes by mempolicy/cpusets,
+and those nodes become memory exhaustion status, one process
+may be killed by oom-killer. No panic occurs in this case.
+Because other nodes' memory may be free. This means system total status
+may be not fatal yet.
+
+If this is set to 2, the kernel panics compulsorily even on the
+above-mentioned. Even oom happens under memory cgroup, the whole
+system panics.
+
+The default value is 0.
+
+1 and 2 are for failover of clustering. Please select either
+according to your policy of failover.
+
+panic_on_oom=2+kdump gives you very strong tool to investigate
+why oom happens. You can get snapshot.
+
+
+percpu_pagelist_fraction
+========================
+
+This is the fraction of pages at most (high mark pcp->high) in each zone that
+are allocated for each per cpu page list.  The min value for this is 8.  It
+means that we don't allow more than 1/8th of pages in each zone to be
+allocated in any single per_cpu_pagelist.  This entry only changes the value
+of hot per cpu pagelists.  User can specify a number like 100 to allocate
+1/100th of each zone to each per cpu page list.
+
+The batch value of each per cpu pagelist is also updated as a result.  It is
+set to pcp->high/4.  The upper limit of batch is (PAGE_SHIFT * 8)
+
+The initial value is zero.  Kernel does not use this value at boot time to set
+the high water marks for each per cpu page list.  If the user writes '0' to this
+sysctl, it will revert to this default behavior.
+
+
+stat_interval
+=============
+
+The time interval between which vm statistics are updated.  The default
+is 1 second.
+
+
+stat_refresh
+============
+
+Any read or write (by root only) flushes all the per-cpu vm statistics
+into their global totals, for more accurate reports when testing
+e.g. cat /proc/sys/vm/stat_refresh /proc/meminfo
+
+As a side-effect, it also checks for negative totals (elsewhere reported
+as 0) and "fails" with EINVAL if any are found, with a warning in dmesg.
+(At time of writing, a few stats are known sometimes to be found negative,
+with no ill effects: errors and warnings on these stats are suppressed.)
+
+
+numa_stat
+=========
+
+This interface allows runtime configuration of numa statistics.
+
+When page allocation performance becomes a bottleneck and you can tolerate
+some possible tool breakage and decreased numa counter precision, you can
+do::
+
+       echo 0 > /proc/sys/vm/numa_stat
+
+When page allocation performance is not a bottleneck and you want all
+tooling to work, you can do::
+
+       echo 1 > /proc/sys/vm/numa_stat
+
+
+swappiness
+==========
+
+This control is used to define how aggressive the kernel will swap
+memory pages.  Higher values will increase aggressiveness, lower values
+decrease the amount of swap.  A value of 0 instructs the kernel not to
+initiate swap until the amount of free and file-backed pages is less
+than the high water mark in a zone.
+
+The default value is 60.
+
+
+unprivileged_userfaultfd
+========================
+
+This flag controls whether unprivileged users can use the userfaultfd
+system calls.  Set this to 1 to allow unprivileged users to use the
+userfaultfd system calls, or set this to 0 to restrict userfaultfd to only
+privileged users (with SYS_CAP_PTRACE capability).
+
+The default value is 1.
+
+
+user_reserve_kbytes
+===================
+
+When overcommit_memory is set to 2, "never overcommit" mode, reserve
+min(3% of current process size, user_reserve_kbytes) of free memory.
+This is intended to prevent a user from starting a single memory hogging
+process, such that they cannot recover (kill the hog).
+
+user_reserve_kbytes defaults to min(3% of the current process size, 128MB).
+
+If this is reduced to zero, then the user will be allowed to allocate
+all free memory with a single process, minus admin_reserve_kbytes.
+Any subsequent attempts to execute a command will result in
+"fork: Cannot allocate memory".
+
+Changing this takes effect whenever an application requests memory.
+
+
+vfs_cache_pressure
+==================
+
+This percentage value controls the tendency of the kernel to reclaim
+the memory which is used for caching of directory and inode objects.
+
+At the default value of vfs_cache_pressure=100 the kernel will attempt to
+reclaim dentries and inodes at a "fair" rate with respect to pagecache and
+swapcache reclaim.  Decreasing vfs_cache_pressure causes the kernel to prefer
+to retain dentry and inode caches. When vfs_cache_pressure=0, the kernel will
+never reclaim dentries and inodes due to memory pressure and this can easily
+lead to out-of-memory conditions. Increasing vfs_cache_pressure beyond 100
+causes the kernel to prefer to reclaim dentries and inodes.
+
+Increasing vfs_cache_pressure significantly beyond 100 may have negative
+performance impact. Reclaim code needs to take various locks to find freeable
+directory and inode objects. With vfs_cache_pressure=1000, it will look for
+ten times more freeable objects than there are.
+
+
+watermark_boost_factor
+======================
+
+This factor controls the level of reclaim when memory is being fragmented.
+It defines the percentage of the high watermark of a zone that will be
+reclaimed if pages of different mobility are being mixed within pageblocks.
+The intent is that compaction has less work to do in the future and to
+increase the success rate of future high-order allocations such as SLUB
+allocations, THP and hugetlbfs pages.
+
+To make it sensible with respect to the watermark_scale_factor
+parameter, the unit is in fractions of 10,000. The default value of
+15,000 on !DISCONTIGMEM configurations means that up to 150% of the high
+watermark will be reclaimed in the event of a pageblock being mixed due
+to fragmentation. The level of reclaim is determined by the number of
+fragmentation events that occurred in the recent past. If this value is
+smaller than a pageblock then a pageblocks worth of pages will be reclaimed
+(e.g.  2MB on 64-bit x86). A boost factor of 0 will disable the feature.
+
+
+watermark_scale_factor
+======================
+
+This factor controls the aggressiveness of kswapd. It defines the
+amount of memory left in a node/system before kswapd is woken up and
+how much memory needs to be free before kswapd goes back to sleep.
+
+The unit is in fractions of 10,000. The default value of 10 means the
+distances between watermarks are 0.1% of the available memory in the
+node/system. The maximum value is 1000, or 10% of memory.
+
+A high rate of threads entering direct reclaim (allocstall) or kswapd
+going to sleep prematurely (kswapd_low_wmark_hit_quickly) can indicate
+that the number of free pages kswapd maintains for latency reasons is
+too small for the allocation bursts occurring in the system. This knob
+can then be used to tune kswapd aggressiveness accordingly.
+
+
+zone_reclaim_mode
+=================
+
+Zone_reclaim_mode allows someone to set more or less aggressive approaches to
+reclaim memory when a zone runs out of memory. If it is set to zero then no
+zone reclaim occurs. Allocations will be satisfied from other zones / nodes
+in the system.
+
+This is value OR'ed together of
+
+=      ===================================
+1      Zone reclaim on
+2      Zone reclaim writes dirty pages out
+4      Zone reclaim swaps pages
+=      ===================================
+
+zone_reclaim_mode is disabled by default.  For file servers or workloads
+that benefit from having their data cached, zone_reclaim_mode should be
+left disabled as the caching effect is likely to be more important than
+data locality.
+
+zone_reclaim may be enabled if it's known that the workload is partitioned
+such that each partition fits within a NUMA node and that accessing remote
+memory would cause a measurable performance reduction.  The page allocator
+will then reclaim easily reusable pages (those page cache pages that are
+currently not used) before allocating off node pages.
+
+Allowing zone reclaim to write out pages stops processes that are
+writing large amounts of data from dirtying pages on other nodes. Zone
+reclaim will write out dirty pages if a zone fills up and so effectively
+throttle the process. This may decrease the performance of a single process
+since it cannot use all of system memory to buffer the outgoing writes
+anymore but it preserve the memory on other nodes so that the performance
+of other processes running on other nodes will not be affected.
+
+Allowing regular swap effectively restricts allocations to the local
+node unless explicitly overridden by memory policies or cpuset
+configurations.
diff --git a/Documentation/admin-guide/xfs.rst b/Documentation/admin-guide/xfs.rst
new file mode 100644 (file)
index 0000000..e76665a
--- /dev/null
@@ -0,0 +1,466 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+======================
+The SGI XFS Filesystem
+======================
+
+XFS is a high performance journaling filesystem which originated
+on the SGI IRIX platform.  It is completely multi-threaded, can
+support large files and large filesystems, extended attributes,
+variable block sizes, is extent based, and makes extensive use of
+Btrees (directories, extents, free space) to aid both performance
+and scalability.
+
+Refer to the documentation at https://xfs.wiki.kernel.org/
+for further details.  This implementation is on-disk compatible
+with the IRIX version of XFS.
+
+
+Mount Options
+=============
+
+When mounting an XFS filesystem, the following options are accepted.
+
+  allocsize=size
+       Sets the buffered I/O end-of-file preallocation size when
+       doing delayed allocation writeout (default size is 64KiB).
+       Valid values for this option are page size (typically 4KiB)
+       through to 1GiB, inclusive, in power-of-2 increments.
+
+       The default behaviour is for dynamic end-of-file
+       preallocation size, which uses a set of heuristics to
+       optimise the preallocation size based on the current
+       allocation patterns within the file and the access patterns
+       to the file. Specifying a fixed ``allocsize`` value turns off
+       the dynamic behaviour.
+
+  attr2 or noattr2
+       The options enable/disable an "opportunistic" improvement to
+       be made in the way inline extended attributes are stored
+       on-disk.  When the new form is used for the first time when
+       ``attr2`` is selected (either when setting or removing extended
+       attributes) the on-disk superblock feature bit field will be
+       updated to reflect this format being in use.
+
+       The default behaviour is determined by the on-disk feature
+       bit indicating that ``attr2`` behaviour is active. If either
+       mount option is set, then that becomes the new default used
+       by the filesystem.
+
+       CRC enabled filesystems always use the ``attr2`` format, and so
+       will reject the ``noattr2`` mount option if it is set.
+
+  discard or nodiscard (default)
+       Enable/disable the issuing of commands to let the block
+       device reclaim space freed by the filesystem.  This is
+       useful for SSD devices, thinly provisioned LUNs and virtual
+       machine images, but may have a performance impact.
+
+       Note: It is currently recommended that you use the ``fstrim``
+       application to ``discard`` unused blocks rather than the ``discard``
+       mount option because the performance impact of this option
+       is quite severe.
+
+  grpid/bsdgroups or nogrpid/sysvgroups (default)
+       These options define what group ID a newly created file
+       gets.  When ``grpid`` is set, it takes the group ID of the
+       directory in which it is created; otherwise it takes the
+       ``fsgid`` of the current process, unless the directory has the
+       ``setgid`` bit set, in which case it takes the ``gid`` from the
+       parent directory, and also gets the ``setgid`` bit set if it is
+       a directory itself.
+
+  filestreams
+       Make the data allocator use the filestreams allocation mode
+       across the entire filesystem rather than just on directories
+       configured to use it.
+
+  ikeep or noikeep (default)
+       When ``ikeep`` is specified, XFS does not delete empty inode
+       clusters and keeps them around on disk.  When ``noikeep`` is
+       specified, empty inode clusters are returned to the free
+       space pool.
+
+  inode32 or inode64 (default)
+       When ``inode32`` is specified, it indicates that XFS limits
+       inode creation to locations which will not result in inode
+       numbers with more than 32 bits of significance.
+
+       When ``inode64`` is specified, it indicates that XFS is allowed
+       to create inodes at any location in the filesystem,
+       including those which will result in inode numbers occupying
+       more than 32 bits of significance.
+
+       ``inode32`` is provided for backwards compatibility with older
+       systems and applications, since 64 bits inode numbers might
+       cause problems for some applications that cannot handle
+       large inode numbers.  If applications are in use which do
+       not handle inode numbers bigger than 32 bits, the ``inode32``
+       option should be specified.
+
+  largeio or nolargeio (default)
+       If ``nolargeio`` is specified, the optimal I/O reported in
+       ``st_blksize`` by **stat(2)** will be as small as possible to allow
+       user applications to avoid inefficient read/modify/write
+       I/O.  This is typically the page size of the machine, as
+       this is the granularity of the page cache.
+
+       If ``largeio`` is specified, a filesystem that was created with a
+       ``swidth`` specified will return the ``swidth`` value (in bytes)
+       in ``st_blksize``. If the filesystem does not have a ``swidth``
+       specified but does specify an ``allocsize`` then ``allocsize``
+       (in bytes) will be returned instead. Otherwise the behaviour
+       is the same as if ``nolargeio`` was specified.
+
+  logbufs=value
+       Set the number of in-memory log buffers.  Valid numbers
+       range from 2-8 inclusive.
+
+       The default value is 8 buffers.
+
+       If the memory cost of 8 log buffers is too high on small
+       systems, then it may be reduced at some cost to performance
+       on metadata intensive workloads. The ``logbsize`` option below
+       controls the size of each buffer and so is also relevant to
+       this case.
+
+  logbsize=value
+       Set the size of each in-memory log buffer.  The size may be
+       specified in bytes, or in kilobytes with a "k" suffix.
+       Valid sizes for version 1 and version 2 logs are 16384 (16k)
+       and 32768 (32k).  Valid sizes for version 2 logs also
+       include 65536 (64k), 131072 (128k) and 262144 (256k). The
+       logbsize must be an integer multiple of the log
+       stripe unit configured at **mkfs(8)** time.
+
+       The default value for for version 1 logs is 32768, while the
+       default value for version 2 logs is MAX(32768, log_sunit).
+
+  logdev=device and rtdev=device
+       Use an external log (metadata journal) and/or real-time device.
+       An XFS filesystem has up to three parts: a data section, a log
+       section, and a real-time section.  The real-time section is
+       optional, and the log section can be separate from the data
+       section or contained within it.
+
+  noalign
+       Data allocations will not be aligned at stripe unit
+       boundaries. This is only relevant to filesystems created
+       with non-zero data alignment parameters (``sunit``, ``swidth``) by
+       **mkfs(8)**.
+
+  norecovery
+       The filesystem will be mounted without running log recovery.
+       If the filesystem was not cleanly unmounted, it is likely to
+       be inconsistent when mounted in ``norecovery`` mode.
+       Some files or directories may not be accessible because of this.
+       Filesystems mounted ``norecovery`` must be mounted read-only or
+       the mount will fail.
+
+  nouuid
+       Don't check for double mounted file systems using the file
+       system ``uuid``.  This is useful to mount LVM snapshot volumes,
+       and often used in combination with ``norecovery`` for mounting
+       read-only snapshots.
+
+  noquota
+       Forcibly turns off all quota accounting and enforcement
+       within the filesystem.
+
+  uquota/usrquota/uqnoenforce/quota
+       User disk quota accounting enabled, and limits (optionally)
+       enforced.  Refer to **xfs_quota(8)** for further details.
+
+  gquota/grpquota/gqnoenforce
+       Group disk quota accounting enabled and limits (optionally)
+       enforced.  Refer to **xfs_quota(8)** for further details.
+
+  pquota/prjquota/pqnoenforce
+       Project disk quota accounting enabled and limits (optionally)
+       enforced.  Refer to **xfs_quota(8)** for further details.
+
+  sunit=value and swidth=value
+       Used to specify the stripe unit and width for a RAID device
+       or a stripe volume.  "value" must be specified in 512-byte
+       block units. These options are only relevant to filesystems
+       that were created with non-zero data alignment parameters.
+
+       The ``sunit`` and ``swidth`` parameters specified must be compatible
+       with the existing filesystem alignment characteristics.  In
+       general, that means the only valid changes to ``sunit`` are
+       increasing it by a power-of-2 multiple. Valid ``swidth`` values
+       are any integer multiple of a valid ``sunit`` value.
+
+       Typically the only time these mount options are necessary if
+       after an underlying RAID device has had it's geometry
+       modified, such as adding a new disk to a RAID5 lun and
+       reshaping it.
+
+  swalloc
+       Data allocations will be rounded up to stripe width boundaries
+       when the current end of file is being extended and the file
+       size is larger than the stripe width size.
+
+  wsync
+       When specified, all filesystem namespace operations are
+       executed synchronously. This ensures that when the namespace
+       operation (create, unlink, etc) completes, the change to the
+       namespace is on stable storage. This is useful in HA setups
+       where failover must not result in clients seeing
+       inconsistent namespace presentation during or after a
+       failover event.
+
+
+Deprecated Mount Options
+========================
+
+===========================     ================
+  Name                         Removal Schedule
+===========================     ================
+===========================     ================
+
+
+Removed Mount Options
+=====================
+
+===========================     =======
+  Name                         Removed
+===========================    =======
+  delaylog/nodelaylog          v4.0
+  ihashsize                    v4.0
+  irixsgid                     v4.0
+  osyncisdsync/osyncisosync    v4.0
+  barrier                      v4.19
+  nobarrier                    v4.19
+===========================     =======
+
+sysctls
+=======
+
+The following sysctls are available for the XFS filesystem:
+
+  fs.xfs.stats_clear           (Min: 0  Default: 0  Max: 1)
+       Setting this to "1" clears accumulated XFS statistics
+       in /proc/fs/xfs/stat.  It then immediately resets to "0".
+
+  fs.xfs.xfssyncd_centisecs    (Min: 100  Default: 3000  Max: 720000)
+       The interval at which the filesystem flushes metadata
+       out to disk and runs internal cache cleanup routines.
+
+  fs.xfs.filestream_centisecs  (Min: 1  Default: 3000  Max: 360000)
+       The interval at which the filesystem ages filestreams cache
+       references and returns timed-out AGs back to the free stream
+       pool.
+
+  fs.xfs.speculative_prealloc_lifetime
+               (Units: seconds   Min: 1  Default: 300  Max: 86400)
+       The interval at which the background scanning for inodes
+       with unused speculative preallocation runs. The scan
+       removes unused preallocation from clean inodes and releases
+       the unused space back to the free pool.
+
+  fs.xfs.error_level           (Min: 0  Default: 3  Max: 11)
+       A volume knob for error reporting when internal errors occur.
+       This will generate detailed messages & backtraces for filesystem
+       shutdowns, for example.  Current threshold values are:
+
+               XFS_ERRLEVEL_OFF:       0
+               XFS_ERRLEVEL_LOW:       1
+               XFS_ERRLEVEL_HIGH:      5
+
+  fs.xfs.panic_mask            (Min: 0  Default: 0  Max: 256)
+       Causes certain error conditions to call BUG(). Value is a bitmask;
+       OR together the tags which represent errors which should cause panics:
+
+               XFS_NO_PTAG                     0
+               XFS_PTAG_IFLUSH                 0x00000001
+               XFS_PTAG_LOGRES                 0x00000002
+               XFS_PTAG_AILDELETE              0x00000004
+               XFS_PTAG_ERROR_REPORT           0x00000008
+               XFS_PTAG_SHUTDOWN_CORRUPT       0x00000010
+               XFS_PTAG_SHUTDOWN_IOERROR       0x00000020
+               XFS_PTAG_SHUTDOWN_LOGERROR      0x00000040
+               XFS_PTAG_FSBLOCK_ZERO           0x00000080
+               XFS_PTAG_VERIFIER_ERROR         0x00000100
+
+       This option is intended for debugging only.
+
+  fs.xfs.irix_symlink_mode     (Min: 0  Default: 0  Max: 1)
+       Controls whether symlinks are created with mode 0777 (default)
+       or whether their mode is affected by the umask (irix mode).
+
+  fs.xfs.irix_sgid_inherit     (Min: 0  Default: 0  Max: 1)
+       Controls files created in SGID directories.
+       If the group ID of the new file does not match the effective group
+       ID or one of the supplementary group IDs of the parent dir, the
+       ISGID bit is cleared if the irix_sgid_inherit compatibility sysctl
+       is set.
+
+  fs.xfs.inherit_sync          (Min: 0  Default: 1  Max: 1)
+       Setting this to "1" will cause the "sync" flag set
+       by the **xfs_io(8)** chattr command on a directory to be
+       inherited by files in that directory.
+
+  fs.xfs.inherit_nodump                (Min: 0  Default: 1  Max: 1)
+       Setting this to "1" will cause the "nodump" flag set
+       by the **xfs_io(8)** chattr command on a directory to be
+       inherited by files in that directory.
+
+  fs.xfs.inherit_noatime       (Min: 0  Default: 1  Max: 1)
+       Setting this to "1" will cause the "noatime" flag set
+       by the **xfs_io(8)** chattr command on a directory to be
+       inherited by files in that directory.
+
+  fs.xfs.inherit_nosymlinks    (Min: 0  Default: 1  Max: 1)
+       Setting this to "1" will cause the "nosymlinks" flag set
+       by the **xfs_io(8)** chattr command on a directory to be
+       inherited by files in that directory.
+
+  fs.xfs.inherit_nodefrag      (Min: 0  Default: 1  Max: 1)
+       Setting this to "1" will cause the "nodefrag" flag set
+       by the **xfs_io(8)** chattr command on a directory to be
+       inherited by files in that directory.
+
+  fs.xfs.rotorstep             (Min: 1  Default: 1  Max: 256)
+       In "inode32" allocation mode, this option determines how many
+       files the allocator attempts to allocate in the same allocation
+       group before moving to the next allocation group.  The intent
+       is to control the rate at which the allocator moves between
+       allocation groups when allocating extents for new files.
+
+Deprecated Sysctls
+==================
+
+None at present.
+
+
+Removed Sysctls
+===============
+
+  Name                         Removed
+  ----                         -------
+  fs.xfs.xfsbufd_centisec      v4.0
+  fs.xfs.age_buffer_centisecs  v4.0
+
+
+Error handling
+==============
+
+XFS can act differently according to the type of error found during its
+operation. The implementation introduces the following concepts to the error
+handler:
+
+ -failure speed:
+       Defines how fast XFS should propagate an error upwards when a specific
+       error is found during the filesystem operation. It can propagate
+       immediately, after a defined number of retries, after a set time period,
+       or simply retry forever.
+
+ -error classes:
+       Specifies the subsystem the error configuration will apply to, such as
+       metadata IO or memory allocation. Different subsystems will have
+       different error handlers for which behaviour can be configured.
+
+ -error handlers:
+       Defines the behavior for a specific error.
+
+The filesystem behavior during an error can be set via ``sysfs`` files. Each
+error handler works independently - the first condition met by an error handler
+for a specific class will cause the error to be propagated rather than reset and
+retried.
+
+The action taken by the filesystem when the error is propagated is context
+dependent - it may cause a shut down in the case of an unrecoverable error,
+it may be reported back to userspace, or it may even be ignored because
+there's nothing useful we can with the error or anyone we can report it to (e.g.
+during unmount).
+
+The configuration files are organized into the following hierarchy for each
+mounted filesystem:
+
+  /sys/fs/xfs/<dev>/error/<class>/<error>/
+
+Where:
+  <dev>
+       The short device name of the mounted filesystem. This is the same device
+       name that shows up in XFS kernel error messages as "XFS(<dev>): ..."
+
+  <class>
+       The subsystem the error configuration belongs to. As of 4.9, the defined
+       classes are:
+
+               - "metadata": applies metadata buffer write IO
+
+  <error>
+       The individual error handler configurations.
+
+
+Each filesystem has "global" error configuration options defined in their top
+level directory:
+
+  /sys/fs/xfs/<dev>/error/
+
+  fail_at_unmount              (Min:  0  Default:  1  Max: 1)
+       Defines the filesystem error behavior at unmount time.
+
+       If set to a value of 1, XFS will override all other error configurations
+       during unmount and replace them with "immediate fail" characteristics.
+       i.e. no retries, no retry timeout. This will always allow unmount to
+       succeed when there are persistent errors present.
+
+       If set to 0, the configured retry behaviour will continue until all
+       retries and/or timeouts have been exhausted. This will delay unmount
+       completion when there are persistent errors, and it may prevent the
+       filesystem from ever unmounting fully in the case of "retry forever"
+       handler configurations.
+
+       Note: there is no guarantee that fail_at_unmount can be set while an
+       unmount is in progress. It is possible that the ``sysfs`` entries are
+       removed by the unmounting filesystem before a "retry forever" error
+       handler configuration causes unmount to hang, and hence the filesystem
+       must be configured appropriately before unmount begins to prevent
+       unmount hangs.
+
+Each filesystem has specific error class handlers that define the error
+propagation behaviour for specific errors. There is also a "default" error
+handler defined, which defines the behaviour for all errors that don't have
+specific handlers defined. Where multiple retry constraints are configured for
+a single error, the first retry configuration that expires will cause the error
+to be propagated. The handler configurations are found in the directory:
+
+  /sys/fs/xfs/<dev>/error/<class>/<error>/
+
+  max_retries                  (Min: -1  Default: Varies  Max: INTMAX)
+       Defines the allowed number of retries of a specific error before
+       the filesystem will propagate the error. The retry count for a given
+       error context (e.g. a specific metadata buffer) is reset every time
+       there is a successful completion of the operation.
+
+       Setting the value to "-1" will cause XFS to retry forever for this
+       specific error.
+
+       Setting the value to "0" will cause XFS to fail immediately when the
+       specific error is reported.
+
+       Setting the value to "N" (where 0 < N < Max) will make XFS retry the
+       operation "N" times before propagating the error.
+
+  retry_timeout_seconds                (Min:  -1  Default:  Varies  Max: 1 day)
+       Define the amount of time (in seconds) that the filesystem is
+       allowed to retry its operations when the specific error is
+       found.
+
+       Setting the value to "-1" will allow XFS to retry forever for this
+       specific error.
+
+       Setting the value to "0" will cause XFS to fail immediately when the
+       specific error is reported.
+
+       Setting the value to "N" (where 0 < N < Max) will allow XFS to retry the
+       operation for up to "N" seconds before propagating the error.
+
+**Note:** The default behaviour for a specific error handler is dependent on both
+the class and error context. For example, the default values for
+"metadata/ENODEV" are "0" rather than "-1" so that this error handler defaults
+to "fail immediately" behaviour. This is done because ENODEV is a fatal,
+unrecoverable error no matter how many times the metadata IO is retried.
diff --git a/Documentation/aoe/aoe.rst b/Documentation/aoe/aoe.rst
deleted file mode 100644 (file)
index 58747ec..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-Introduction
-============
-
-ATA over Ethernet is a network protocol that provides simple access to
-block storage on the LAN.
-
-  http://support.coraid.com/documents/AoEr11.txt
-
-The EtherDrive (R) HOWTO for 2.6 and 3.x kernels is found at ...
-
-  http://support.coraid.com/support/linux/EtherDrive-2.6-HOWTO.html
-
-It has many tips and hints!  Please see, especially, recommended
-tunings for virtual memory:
-
-  http://support.coraid.com/support/linux/EtherDrive-2.6-HOWTO-5.html#ss5.19
-
-The aoetools are userland programs that are designed to work with this
-driver.  The aoetools are on sourceforge.
-
-  http://aoetools.sourceforge.net/
-
-The scripts in this Documentation/aoe directory are intended to
-document the use of the driver and are not necessary if you install
-the aoetools.
-
-
-Creating Device Nodes
-=====================
-
-  Users of udev should find the block device nodes created
-  automatically, but to create all the necessary device nodes, use the
-  udev configuration rules provided in udev.txt (in this directory).
-
-  There is a udev-install.sh script that shows how to install these
-  rules on your system.
-
-  There is also an autoload script that shows how to edit
-  /etc/modprobe.d/aoe.conf to ensure that the aoe module is loaded when
-  necessary.  Preloading the aoe module is preferable to autoloading,
-  however, because AoE discovery takes a few seconds.  It can be
-  confusing when an AoE device is not present the first time the a
-  command is run but appears a second later.
-
-Using Device Nodes
-==================
-
-  "cat /dev/etherd/err" blocks, waiting for error diagnostic output,
-  like any retransmitted packets.
-
-  "echo eth2 eth4 > /dev/etherd/interfaces" tells the aoe driver to
-  limit ATA over Ethernet traffic to eth2 and eth4.  AoE traffic from
-  untrusted networks should be ignored as a matter of security.  See
-  also the aoe_iflist driver option described below.
-
-  "echo > /dev/etherd/discover" tells the driver to find out what AoE
-  devices are available.
-
-  In the future these character devices may disappear and be replaced
-  by sysfs counterparts.  Using the commands in aoetools insulates
-  users from these implementation details.
-
-  The block devices are named like this::
-
-       e{shelf}.{slot}
-       e{shelf}.{slot}p{part}
-
-  ... so that "e0.2" is the third blade from the left (slot 2) in the
-  first shelf (shelf address zero).  That's the whole disk.  The first
-  partition on that disk would be "e0.2p1".
-
-Using sysfs
-===========
-
-  Each aoe block device in /sys/block has the extra attributes of
-  state, mac, and netif.  The state attribute is "up" when the device
-  is ready for I/O and "down" if detected but unusable.  The
-  "down,closewait" state shows that the device is still open and
-  cannot come up again until it has been closed.
-
-  The mac attribute is the ethernet address of the remote AoE device.
-  The netif attribute is the network interface on the localhost
-  through which we are communicating with the remote AoE device.
-
-  There is a script in this directory that formats this information in
-  a convenient way.  Users with aoetools should use the aoe-stat
-  command::
-
-    root@makki root# sh Documentation/aoe/status.sh
-       e10.0            eth3              up
-       e10.1            eth3              up
-       e10.2            eth3              up
-       e10.3            eth3              up
-       e10.4            eth3              up
-       e10.5            eth3              up
-       e10.6            eth3              up
-       e10.7            eth3              up
-       e10.8            eth3              up
-       e10.9            eth3              up
-        e4.0            eth1              up
-        e4.1            eth1              up
-        e4.2            eth1              up
-        e4.3            eth1              up
-        e4.4            eth1              up
-        e4.5            eth1              up
-        e4.6            eth1              up
-        e4.7            eth1              up
-        e4.8            eth1              up
-        e4.9            eth1              up
-
-  Use /sys/module/aoe/parameters/aoe_iflist (or better, the driver
-  option discussed below) instead of /dev/etherd/interfaces to limit
-  AoE traffic to the network interfaces in the given
-  whitespace-separated list.  Unlike the old character device, the
-  sysfs entry can be read from as well as written to.
-
-  It's helpful to trigger discovery after setting the list of allowed
-  interfaces.  The aoetools package provides an aoe-discover script
-  for this purpose.  You can also directly use the
-  /dev/etherd/discover special file described above.
-
-Driver Options
-==============
-
-  There is a boot option for the built-in aoe driver and a
-  corresponding module parameter, aoe_iflist.  Without this option,
-  all network interfaces may be used for ATA over Ethernet.  Here is a
-  usage example for the module parameter::
-
-    modprobe aoe_iflist="eth1 eth3"
-
-  The aoe_deadsecs module parameter determines the maximum number of
-  seconds that the driver will wait for an AoE device to provide a
-  response to an AoE command.  After aoe_deadsecs seconds have
-  elapsed, the AoE device will be marked as "down".  A value of zero
-  is supported for testing purposes and makes the aoe driver keep
-  trying AoE commands forever.
-
-  The aoe_maxout module parameter has a default of 128.  This is the
-  maximum number of unresponded packets that will be sent to an AoE
-  target at one time.
-
-  The aoe_dyndevs module parameter defaults to 1, meaning that the
-  driver will assign a block device minor number to a discovered AoE
-  target based on the order of its discovery.  With dynamic minor
-  device numbers in use, a greater range of AoE shelf and slot
-  addresses can be supported.  Users with udev will never have to
-  think about minor numbers.  Using aoe_dyndevs=0 allows device nodes
-  to be pre-created using a static minor-number scheme with the
-  aoe-mkshelf script in the aoetools.
diff --git a/Documentation/aoe/index.rst b/Documentation/aoe/index.rst
deleted file mode 100644 (file)
index 4394b9b..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-:orphan:
-
-=======================
-ATA over Ethernet (AoE)
-=======================
-
-.. toctree::
-    :maxdepth: 1
-
-    aoe
-    todo
-    examples
-
-.. only::  subproject and html
-
-   Indices
-   =======
-
-   * :ref:`genindex`
diff --git a/Documentation/aoe/udev.txt b/Documentation/aoe/udev.txt
deleted file mode 100644 (file)
index 54feda5..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-# These rules tell udev what device nodes to create for aoe support.
-# They may be installed along the following lines.  Check the section
-# 8 udev manpage to see whether your udev supports SUBSYSTEM, and
-# whether it uses one or two equal signs for SUBSYSTEM and KERNEL.
-# 
-#   ecashin@makki ~$ su
-#   Password:
-#   bash# find /etc -type f -name udev.conf
-#   /etc/udev/udev.conf
-#   bash# grep udev_rules= /etc/udev/udev.conf
-#   udev_rules="/etc/udev/rules.d/"
-#   bash# ls /etc/udev/rules.d/
-#   10-wacom.rules  50-udev.rules
-#   bash# cp /path/to/linux/Documentation/aoe/udev.txt \
-#           /etc/udev/rules.d/60-aoe.rules
-#  
-
-# aoe char devices
-SUBSYSTEM=="aoe", KERNEL=="discover",  NAME="etherd/%k", GROUP="disk", MODE="0220"
-SUBSYSTEM=="aoe", KERNEL=="err",       NAME="etherd/%k", GROUP="disk", MODE="0440"
-SUBSYSTEM=="aoe", KERNEL=="interfaces",        NAME="etherd/%k", GROUP="disk", MODE="0220"
-SUBSYSTEM=="aoe", KERNEL=="revalidate",        NAME="etherd/%k", GROUP="disk", MODE="0220"
-SUBSYSTEM=="aoe", KERNEL=="flush",     NAME="etherd/%k", GROUP="disk", MODE="0220"
-
-# aoe block devices     
-KERNEL=="etherd*",       GROUP="disk"
diff --git a/Documentation/arm/Booting b/Documentation/arm/Booting
deleted file mode 100644 (file)
index f1f965c..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-                       Booting ARM Linux
-                       =================
-
-Author:        Russell King
-Date  : 18 May 2002
-
-The following documentation is relevant to 2.4.18-rmk6 and beyond.
-
-In order to boot ARM Linux, you require a boot loader, which is a small
-program that runs before the main kernel.  The boot loader is expected
-to initialise various devices, and eventually call the Linux kernel,
-passing information to the kernel.
-
-Essentially, the boot loader should provide (as a minimum) the
-following:
-
-1. Setup and initialise the RAM.
-2. Initialise one serial port.
-3. Detect the machine type.
-4. Setup the kernel tagged list.
-5. Load initramfs.
-6. Call the kernel image.
-
-
-1. Setup and initialise RAM
----------------------------
-
-Existing boot loaders:         MANDATORY
-New boot loaders:              MANDATORY
-
-The boot loader is expected to find and initialise all RAM that the
-kernel will use for volatile data storage in the system.  It performs
-this in a machine dependent manner.  (It may use internal algorithms
-to automatically locate and size all RAM, or it may use knowledge of
-the RAM in the machine, or any other method the boot loader designer
-sees fit.)
-
-
-2. Initialise one serial port
------------------------------
-
-Existing boot loaders:         OPTIONAL, RECOMMENDED
-New boot loaders:              OPTIONAL, RECOMMENDED
-
-The boot loader should initialise and enable one serial port on the
-target.  This allows the kernel serial driver to automatically detect
-which serial port it should use for the kernel console (generally
-used for debugging purposes, or communication with the target.)
-
-As an alternative, the boot loader can pass the relevant 'console='
-option to the kernel via the tagged lists specifying the port, and
-serial format options as described in
-
-       Documentation/admin-guide/kernel-parameters.rst.
-
-
-3. Detect the machine type
---------------------------
-
-Existing boot loaders:         OPTIONAL
-New boot loaders:              MANDATORY except for DT-only platforms
-
-The boot loader should detect the machine type its running on by some
-method.  Whether this is a hard coded value or some algorithm that
-looks at the connected hardware is beyond the scope of this document.
-The boot loader must ultimately be able to provide a MACH_TYPE_xxx
-value to the kernel. (see linux/arch/arm/tools/mach-types).  This
-should be passed to the kernel in register r1.
-
-For DT-only platforms, the machine type will be determined by device
-tree.  set the machine type to all ones (~0).  This is not strictly
-necessary, but assures that it will not match any existing types.
-
-4. Setup boot data
-------------------
-
-Existing boot loaders:         OPTIONAL, HIGHLY RECOMMENDED
-New boot loaders:              MANDATORY
-
-The boot loader must provide either a tagged list or a dtb image for
-passing configuration data to the kernel.  The physical address of the
-boot data is passed to the kernel in register r2.
-
-4a. Setup the kernel tagged list
---------------------------------
-
-The boot loader must create and initialise the kernel tagged list.
-A valid tagged list starts with ATAG_CORE and ends with ATAG_NONE.
-The ATAG_CORE tag may or may not be empty.  An empty ATAG_CORE tag
-has the size field set to '2' (0x00000002).  The ATAG_NONE must set
-the size field to zero.
-
-Any number of tags can be placed in the list.  It is undefined
-whether a repeated tag appends to the information carried by the
-previous tag, or whether it replaces the information in its
-entirety; some tags behave as the former, others the latter.
-
-The boot loader must pass at a minimum the size and location of
-the system memory, and root filesystem location.  Therefore, the
-minimum tagged list should look:
-
-       +-----------+
-base ->        | ATAG_CORE |  |
-       +-----------+  |
-       | ATAG_MEM  |  | increasing address
-       +-----------+  |
-       | ATAG_NONE |  |
-       +-----------+  v
-
-The tagged list should be stored in system RAM.
-
-The tagged list must be placed in a region of memory where neither
-the kernel decompressor nor initrd 'bootp' program will overwrite
-it.  The recommended placement is in the first 16KiB of RAM.
-
-4b. Setup the device tree
--------------------------
-
-The boot loader must load a device tree image (dtb) into system ram
-at a 64bit aligned address and initialize it with the boot data.  The
-dtb format is documented in Documentation/devicetree/booting-without-of.txt.
-The kernel will look for the dtb magic value of 0xd00dfeed at the dtb
-physical address to determine if a dtb has been passed instead of a
-tagged list.
-
-The boot loader must pass at a minimum the size and location of the
-system memory, and the root filesystem location.  The dtb must be
-placed in a region of memory where the kernel decompressor will not
-overwrite it, while remaining within the region which will be covered
-by the kernel's low-memory mapping.
-
-A safe location is just above the 128MiB boundary from start of RAM.
-
-5. Load initramfs.
-------------------
-
-Existing boot loaders:         OPTIONAL
-New boot loaders:              OPTIONAL
-
-If an initramfs is in use then, as with the dtb, it must be placed in
-a region of memory where the kernel decompressor will not overwrite it
-while also with the region which will be covered by the kernel's
-low-memory mapping.
-
-A safe location is just above the device tree blob which itself will
-be loaded just above the 128MiB boundary from the start of RAM as
-recommended above.
-
-6. Calling the kernel image
----------------------------
-
-Existing boot loaders:         MANDATORY
-New boot loaders:              MANDATORY
-
-There are two options for calling the kernel zImage.  If the zImage
-is stored in flash, and is linked correctly to be run from flash,
-then it is legal for the boot loader to call the zImage in flash
-directly.
-
-The zImage may also be placed in system RAM and called there.  The
-kernel should be placed in the first 128MiB of RAM.  It is recommended
-that it is loaded above 32MiB in order to avoid the need to relocate
-prior to decompression, which will make the boot process slightly
-faster.
-
-When booting a raw (non-zImage) kernel the constraints are tighter.
-In this case the kernel must be loaded at an offset into system equal
-to TEXT_OFFSET - PAGE_OFFSET.
-
-In any case, the following conditions must be met:
-
-- Quiesce all DMA capable devices so that memory does not get
-  corrupted by bogus network packets or disk data. This will save
-  you many hours of debug.
-
-- CPU register settings
-  r0 = 0,
-  r1 = machine type number discovered in (3) above.
-  r2 = physical address of tagged list in system RAM, or
-       physical address of device tree block (dtb) in system RAM
-
-- CPU mode
-  All forms of interrupts must be disabled (IRQs and FIQs)
-
-  For CPUs which do not include the ARM virtualization extensions, the
-  CPU must be in SVC mode.  (A special exception exists for Angel)
-
-  CPUs which include support for the virtualization extensions can be
-  entered in HYP mode in order to enable the kernel to make full use of
-  these extensions.  This is the recommended boot method for such CPUs,
-  unless the virtualisations are already in use by a pre-installed
-  hypervisor.
-
-  If the kernel is not entered in HYP mode for any reason, it must be
-  entered in SVC mode.
-
-- Caches, MMUs
-  The MMU must be off.
-  Instruction cache may be on or off.
-  Data cache must be off.
-
-  If the kernel is entered in HYP mode, the above requirements apply to
-  the HYP mode configuration in addition to the ordinary PL1 (privileged
-  kernel modes) configuration.  In addition, all traps into the
-  hypervisor must be disabled, and PL1 access must be granted for all
-  peripherals and CPU resources for which this is architecturally
-  possible.  Except for entering in HYP mode, the system configuration
-  should be such that a kernel which does not include support for the
-  virtualization extensions can boot correctly without extra help.
-
-- The boot loader is expected to call the kernel image by jumping
-  directly to the first instruction of the kernel image.
-
-  On CPUs supporting the ARM instruction set, the entry must be
-  made in ARM state, even for a Thumb-2 kernel.
-
-  On CPUs supporting only the Thumb instruction set such as
-  Cortex-M class CPUs, the entry must be made in Thumb state.
diff --git a/Documentation/arm/IXP4xx b/Documentation/arm/IXP4xx
deleted file mode 100644 (file)
index e48b74d..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-
--------------------------------------------------------------------------
-Release Notes for Linux on Intel's IXP4xx Network Processor
-
-Maintained by Deepak Saxena <dsaxena@plexity.net>
--------------------------------------------------------------------------
-
-1. Overview
-
-Intel's IXP4xx network processor is a highly integrated SOC that
-is targeted for network applications, though it has become popular 
-in industrial control and other areas due to low cost and power
-consumption. The IXP4xx family currently consists of several processors
-that support different network offload functions such as encryption,
-routing, firewalling, etc. The IXP46x family is an updated version which
-supports faster speeds, new memory and flash configurations, and more
-integration such as an on-chip I2C controller.
-
-For more information on the various versions of the CPU, see:
-
-   http://developer.intel.com/design/network/products/npfamily/ixp4xx.htm
-
-Intel also made the IXCP1100 CPU for sometime which is an IXP4xx 
-stripped of much of the network intelligence.
-
-2. Linux Support
-
-Linux currently supports the following features on the IXP4xx chips:
-
-- Dual serial ports
-- PCI interface
-- Flash access (MTD/JFFS)
-- I2C through GPIO on IXP42x
-- GPIO for input/output/interrupts 
-  See arch/arm/mach-ixp4xx/include/mach/platform.h for access functions.
-- Timers (watchdog, OS)
-
-The following components of the chips are not supported by Linux and
-require the use of Intel's proprietary CSR software:
-
-- USB device interface
-- Network interfaces (HSS, Utopia, NPEs, etc)
-- Network offload functionality
-
-If you need to use any of the above, you need to download Intel's
-software from:
-
-   http://developer.intel.com/design/network/products/npfamily/ixp425.htm    
-
-DO NOT POST QUESTIONS TO THE LINUX MAILING LISTS REGARDING THE PROPRIETARY
-SOFTWARE.
-
-There are several websites that provide directions/pointers on using
-Intel's software:
-
-   http://sourceforge.net/projects/ixp4xx-osdg/
-   Open Source Developer's Guide for using uClinux and the Intel libraries 
-
-http://gatewaymaker.sourceforge.net/ 
-   Simple one page summary of building a gateway using an IXP425 and Linux
-
-http://ixp425.sourceforge.net/
-   ATM device driver for IXP425 that relies on Intel's libraries
-
-3. Known Issues/Limitations
-
-3a. Limited inbound PCI window
-
-The IXP4xx family allows for up to 256MB of memory but the PCI interface
-can only expose 64MB of that memory to the PCI bus. This means that if
-you are running with > 64MB, all PCI buffers outside of the accessible
-range will be bounced using the routines in arch/arm/common/dmabounce.c.
-   
-3b. Limited outbound PCI window
-
-IXP4xx provides two methods of accessing PCI memory space:
-
-1) A direct mapped window from 0x48000000 to 0x4bffffff (64MB).
-   To access PCI via this space, we simply ioremap() the BAR
-   into the kernel and we can use the standard read[bwl]/write[bwl]
-   macros. This is the preffered method due to speed but it
-   limits the system to just 64MB of PCI memory. This can be 
-   problamatic if using video cards and other memory-heavy devices.
-          
-2) If > 64MB of memory space is required, the IXP4xx can be 
-   configured to use indirect registers to access PCI This allows 
-   for up to 128MB (0x48000000 to 0x4fffffff) of memory on the bus. 
-   The disadvantage of this is that every PCI access requires 
-   three local register accesses plus a spinlock, but in some 
-   cases the performance hit is acceptable. In addition, you cannot 
-   mmap() PCI devices in this case due to the indirect nature
-   of the PCI window.
-
-By default, the direct method is used for performance reasons. If
-you need more PCI memory, enable the IXP4XX_INDIRECT_PCI config option.
-
-3c. GPIO as Interrupts
-
-Currently the code only handles level-sensitive GPIO interrupts 
-
-4. Supported platforms
-
-ADI Engineering Coyote Gateway Reference Platform
-http://www.adiengineering.com/productsCoyote.html
-
-   The ADI Coyote platform is reference design for those building 
-   small residential/office gateways. One NPE is connected to a 10/100
-   interface, one to 4-port 10/100 switch, and the third to and ADSL
-   interface. In addition, it also supports to POTs interfaces connected
-   via SLICs. Note that those are not supported by Linux ATM. Finally,
-   the platform has two mini-PCI slots used for 802.11[bga] cards.
-   Finally, there is an IDE port hanging off the expansion bus.
-
-Gateworks Avila Network Platform
-http://www.gateworks.com/support/overview.php
-
-   The Avila platform is basically and IXDP425 with the 4 PCI slots
-   replaced with mini-PCI slots and a CF IDE interface hanging off
-   the expansion bus.
-
-Intel IXDP425 Development Platform
-http://www.intel.com/design/network/products/npfamily/ixdpg425.htm  
-
-   This is Intel's standard reference platform for the IXDP425 and is 
-   also known as the Richfield board. It contains 4 PCI slots, 16MB
-   of flash, two 10/100 ports and one ADSL port.
-
-Intel IXDP465 Development Platform
-http://www.intel.com/design/network/products/npfamily/ixdp465.htm
-
-   This is basically an IXDP425 with an IXP465 and 32M of flash instead
-   of just 16.
-
-Intel IXDPG425 Development Platform
-
-   This is basically and ADI Coyote board with a NEC EHCI controller
-   added. One issue with this board is that the mini-PCI slots only
-   have the 3.3v line connected, so you can't use a PCI to mini-PCI
-   adapter with an E100 card. So to NFS root you need to use either
-   the CSR or a WiFi card and a ramdisk that BOOTPs and then does
-   a pivot_root to NFS.
-
-Motorola PrPMC1100 Processor Mezanine Card
-http://www.fountainsys.com
-
-   The PrPMC1100 is based on the IXCP1100 and is meant to plug into
-   and IXP2400/2800 system to act as the system controller. It simply
-   contains a CPU and 16MB of flash on the board and needs to be
-   plugged into a carrier board to function. Currently Linux only
-   supports the Motorola PrPMC carrier board for this platform.
-
-5. TODO LIST
-
-- Add support for Coyote IDE
-- Add support for edge-based GPIO interrupts
-- Add support for CF IDE on expansion bus
-
-6. Thanks
-
-The IXP4xx work has been funded by Intel Corp. and MontaVista Software, Inc.
-
-The following people have contributed patches/comments/etc:
-
-Lennerty Buytenhek
-Lutz Jaenicke
-Justin Mayfield
-Robert E. Ranslam
-[I know I've forgotten others, please email me to be added] 
-
--------------------------------------------------------------------------
-
-Last Update: 01/04/2005
diff --git a/Documentation/arm/Interrupts b/Documentation/arm/Interrupts
deleted file mode 100644 (file)
index f09ab1b..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-2.5.2-rmk5
-----------
-
-This is the first kernel that contains a major shake up of some of the
-major architecture-specific subsystems.
-
-Firstly, it contains some pretty major changes to the way we handle the
-MMU TLB.  Each MMU TLB variant is now handled completely separately -
-we have TLB v3, TLB v4 (without write buffer), TLB v4 (with write buffer),
-and finally TLB v4 (with write buffer, with I TLB invalidate entry).
-There is more assembly code inside each of these functions, mainly to
-allow more flexible TLB handling for the future.
-
-Secondly, the IRQ subsystem.
-
-The 2.5 kernels will be having major changes to the way IRQs are handled.
-Unfortunately, this means that machine types that touch the irq_desc[]
-array (basically all machine types) will break, and this means every
-machine type that we currently have.
-
-Lets take an example.  On the Assabet with Neponset, we have:
-
-                  GPIO25                 IRR:2
-        SA1100 ------------> Neponset -----------> SA1111
-                                         IIR:1
-                                      -----------> USAR
-                                         IIR:0
-                                      -----------> SMC9196
-
-The way stuff currently works, all SA1111 interrupts are mutually
-exclusive of each other - if you're processing one interrupt from the
-SA1111 and another comes in, you have to wait for that interrupt to
-finish processing before you can service the new interrupt.  Eg, an
-IDE PIO-based interrupt on the SA1111 excludes all other SA1111 and
-SMC9196 interrupts until it has finished transferring its multi-sector
-data, which can be a long time.  Note also that since we loop in the
-SA1111 IRQ handler, SA1111 IRQs can hold off SMC9196 IRQs indefinitely.
-
-
-The new approach brings several new ideas...
-
-We introduce the concept of a "parent" and a "child".  For example,
-to the Neponset handler, the "parent" is GPIO25, and the "children"d
-are SA1111, SMC9196 and USAR.
-
-We also bring the idea of an IRQ "chip" (mainly to reduce the size of
-the irqdesc array).  This doesn't have to be a real "IC"; indeed the
-SA11x0 IRQs are handled by two separate "chip" structures, one for
-GPIO0-10, and another for all the rest.  It is just a container for
-the various operations (maybe this'll change to a better name).
-This structure has the following operations:
-
-struct irqchip {
-        /*
-         * Acknowledge the IRQ.
-         * If this is a level-based IRQ, then it is expected to mask the IRQ
-         * as well.
-         */
-        void (*ack)(unsigned int irq);
-        /*
-         * Mask the IRQ in hardware.
-         */
-        void (*mask)(unsigned int irq);
-        /*
-         * Unmask the IRQ in hardware.
-         */
-        void (*unmask)(unsigned int irq);
-        /*
-         * Re-run the IRQ
-         */
-        void (*rerun)(unsigned int irq);
-        /*
-         * Set the type of the IRQ.
-         */
-        int (*type)(unsigned int irq, unsigned int, type);
-};
-
-ack    - required.  May be the same function as mask for IRQs
-         handled by do_level_IRQ.
-mask   - required.
-unmask - required.
-rerun  - optional.  Not required if you're using do_level_IRQ for all
-         IRQs that use this 'irqchip'.  Generally expected to re-trigger
-         the hardware IRQ if possible.  If not, may call the handler
-        directly.
-type   - optional.  If you don't support changing the type of an IRQ,
-         it should be null so people can detect if they are unable to
-         set the IRQ type.
-
-For each IRQ, we keep the following information:
-
-        - "disable" depth (number of disable_irq()s without enable_irq()s)
-        - flags indicating what we can do with this IRQ (valid, probe,
-          noautounmask) as before
-        - status of the IRQ (probing, enable, etc)
-        - chip
-        - per-IRQ handler
-        - irqaction structure list
-
-The handler can be one of the 3 standard handlers - "level", "edge" and
-"simple", or your own specific handler if you need to do something special.
-
-The "level" handler is what we currently have - its pretty simple.
-"edge" knows about the brokenness of such IRQ implementations - that you
-need to leave the hardware IRQ enabled while processing it, and queueing
-further IRQ events should the IRQ happen again while processing.  The
-"simple" handler is very basic, and does not perform any hardware
-manipulation, nor state tracking.  This is useful for things like the
-SMC9196 and USAR above.
-
-So, what's changed?
-
-1. Machine implementations must not write to the irqdesc array.
-
-2. New functions to manipulate the irqdesc array.  The first 4 are expected
-   to be useful only to machine specific code.  The last is recommended to
-   only be used by machine specific code, but may be used in drivers if
-   absolutely necessary.
-
-        set_irq_chip(irq,chip)
-
-                Set the mask/unmask methods for handling this IRQ
-
-        set_irq_handler(irq,handler)
-
-                Set the handler for this IRQ (level, edge, simple)
-
-        set_irq_chained_handler(irq,handler)
-
-                Set a "chained" handler for this IRQ - automatically
-                enables this IRQ (eg, Neponset and SA1111 handlers).
-
-        set_irq_flags(irq,flags)
-
-                Set the valid/probe/noautoenable flags.
-
-        set_irq_type(irq,type)
-
-                Set active the IRQ edge(s)/level.  This replaces the
-                SA1111 INTPOL manipulation, and the set_GPIO_IRQ_edge()
-                function.  Type should be one of IRQ_TYPE_xxx defined in
-               <linux/irq.h>
-
-3. set_GPIO_IRQ_edge() is obsolete, and should be replaced by set_irq_type.
-
-4. Direct access to SA1111 INTPOL is deprecated.  Use set_irq_type instead.
-
-5. A handler is expected to perform any necessary acknowledgement of the
-   parent IRQ via the correct chip specific function.  For instance, if
-   the SA1111 is directly connected to a SA1110 GPIO, then you should
-   acknowledge the SA1110 IRQ each time you re-read the SA1111 IRQ status.
-
-6. For any child which doesn't have its own IRQ enable/disable controls
-   (eg, SMC9196), the handler must mask or acknowledge the parent IRQ
-   while the child handler is called, and the child handler should be the
-   "simple" handler (not "edge" nor "level").  After the handler completes,
-   the parent IRQ should be unmasked, and the status of all children must
-   be re-checked for pending events.  (see the Neponset IRQ handler for
-   details).
-
-7. fixup_irq() is gone, as is arch/arm/mach-*/include/mach/irq.h
-
-Please note that this will not solve all problems - some of them are
-hardware based.  Mixing level-based and edge-based IRQs on the same
-parent signal (eg neponset) is one such area where a software based
-solution can't provide the full answer to low IRQ latency.
-
diff --git a/Documentation/arm/Marvell/README b/Documentation/arm/Marvell/README
deleted file mode 100644 (file)
index 56ada27..0000000
+++ /dev/null
@@ -1,395 +0,0 @@
-ARM Marvell SoCs
-================
-
-This document lists all the ARM Marvell SoCs that are currently
-supported in mainline by the Linux kernel. As the Marvell families of
-SoCs are large and complex, it is hard to understand where the support
-for a particular SoC is available in the Linux kernel. This document
-tries to help in understanding where those SoCs are supported, and to
-match them with their corresponding public datasheet, when available.
-
-Orion family
-------------
-
-  Flavors:
-        88F5082
-        88F5181
-        88F5181L
-        88F5182
-               Datasheet               : http://www.embeddedarm.com/documentation/third-party/MV88F5182-datasheet.pdf
-               Programmer's User Guide : http://www.embeddedarm.com/documentation/third-party/MV88F5182-opensource-manual.pdf
-               User Manual             : http://www.embeddedarm.com/documentation/third-party/MV88F5182-usermanual.pdf
-        88F5281
-               Datasheet               : http://www.ocmodshop.com/images/reviews/networking/qnap_ts409u/marvel_88f5281_data_sheet.pdf
-        88F6183
-  Core: Feroceon 88fr331 (88f51xx) or 88fr531-vd (88f52xx) ARMv5 compatible
-  Linux kernel mach directory: arch/arm/mach-orion5x
-  Linux kernel plat directory: arch/arm/plat-orion
-
-Kirkwood family
----------------
-
-  Flavors:
-        88F6282 a.k.a Armada 300
-                Product Brief  : http://www.marvell.com/embedded-processors/armada-300/assets/armada_310.pdf
-        88F6283 a.k.a Armada 310
-                Product Brief  : http://www.marvell.com/embedded-processors/armada-300/assets/armada_310.pdf
-        88F6190
-                Product Brief  : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6190-003_WEB.pdf
-                Hardware Spec  : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F619x_OpenSource.pdf
-                Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf
-        88F6192
-                Product Brief  : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6192-003_ver1.pdf
-                Hardware Spec  : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F619x_OpenSource.pdf
-                Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf
-        88F6182
-        88F6180
-                Product Brief  : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6180-003_ver1.pdf
-                Hardware Spec  : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F6180_OpenSource.pdf
-                Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf
-        88F6281
-                Product Brief  : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6281-004_ver1.pdf
-                Hardware Spec  : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F6281_OpenSource.pdf
-                Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf
-  Homepage: http://www.marvell.com/embedded-processors/kirkwood/
-  Core: Feroceon 88fr131 ARMv5 compatible
-  Linux kernel mach directory: arch/arm/mach-mvebu
-  Linux kernel plat directory: none
-
-Discovery family
-----------------
-
-  Flavors:
-        MV78100
-                Product Brief  : http://www.marvell.com/embedded-processors/discovery-innovation/assets/MV78100-003_WEB.pdf
-                Hardware Spec  : http://www.marvell.com/embedded-processors/discovery-innovation/assets/HW_MV78100_OpenSource.pdf
-                Functional Spec: http://www.marvell.com/embedded-processors/discovery-innovation/assets/FS_MV76100_78100_78200_OpenSource.pdf
-        MV78200
-                Product Brief  : http://www.marvell.com/embedded-processors/discovery-innovation/assets/MV78200-002_WEB.pdf
-                Hardware Spec  : http://www.marvell.com/embedded-processors/discovery-innovation/assets/HW_MV78200_OpenSource.pdf
-                Functional Spec: http://www.marvell.com/embedded-processors/discovery-innovation/assets/FS_MV76100_78100_78200_OpenSource.pdf
-        MV76100
-                Not supported by the Linux kernel.
-
-  Core: Feroceon 88fr571-vd ARMv5 compatible
-
-  Linux kernel mach directory: arch/arm/mach-mv78xx0
-  Linux kernel plat directory: arch/arm/plat-orion
-
-EBU Armada family
------------------
-
-  Armada 370 Flavors:
-        88F6710
-        88F6707
-        88F6W11
-    Product Brief:   http://www.marvell.com/embedded-processors/armada-300/assets/Marvell_ARMADA_370_SoC.pdf
-    Hardware Spec:   http://www.marvell.com/embedded-processors/armada-300/assets/ARMADA370-datasheet.pdf
-    Functional Spec: http://www.marvell.com/embedded-processors/armada-300/assets/ARMADA370-FunctionalSpec-datasheet.pdf
-    Core: Sheeva ARMv7 compatible PJ4B
-
-  Armada 375 Flavors:
-       88F6720
-    Product Brief: http://www.marvell.com/embedded-processors/armada-300/assets/ARMADA_375_SoC-01_product_brief.pdf
-    Core: ARM Cortex-A9
-
-  Armada 38x Flavors:
-       88F6810 Armada 380
-       88F6820 Armada 385
-       88F6828 Armada 388
-    Product infos:   http://www.marvell.com/embedded-processors/armada-38x/
-    Functional Spec: https://marvellcorp.wufoo.com/forms/marvell-armada-38x-functional-specifications/
-    Core: ARM Cortex-A9
-
-  Armada 39x Flavors:
-       88F6920 Armada 390
-       88F6928 Armada 398
-    Product infos: http://www.marvell.com/embedded-processors/armada-39x/
-    Core: ARM Cortex-A9
-
-  Armada XP Flavors:
-        MV78230
-        MV78260
-        MV78460
-    NOTE: not to be confused with the non-SMP 78xx0 SoCs
-    Product Brief: http://www.marvell.com/embedded-processors/armada-xp/assets/Marvell-ArmadaXP-SoC-product%20brief.pdf
-    Functional Spec: http://www.marvell.com/embedded-processors/armada-xp/assets/ARMADA-XP-Functional-SpecDatasheet.pdf
-    Hardware Specs:
-      http://www.marvell.com/embedded-processors/armada-xp/assets/HW_MV78230_OS.PDF
-      http://www.marvell.com/embedded-processors/armada-xp/assets/HW_MV78260_OS.PDF
-      http://www.marvell.com/embedded-processors/armada-xp/assets/HW_MV78460_OS.PDF
-    Core: Sheeva ARMv7 compatible Dual-core or Quad-core PJ4B-MP
-
-  Linux kernel mach directory: arch/arm/mach-mvebu
-  Linux kernel plat directory: none
-
-EBU Armada family ARMv8
------------------------
-
-  Armada 3710/3720 Flavors:
-       88F3710
-       88F3720
-       Core: ARM Cortex A53 (ARMv8)
-
-       Homepage: http://www.marvell.com/embedded-processors/armada-3700/
-       Product Brief: http://www.marvell.com/embedded-processors/assets/PB-88F3700-FNL.pdf
-       Device tree files: arch/arm64/boot/dts/marvell/armada-37*
-
-  Armada 7K Flavors:
-       88F7020 (AP806 Dual + one CP110)
-       88F7040 (AP806 Quad + one CP110)
-       Core: ARM Cortex A72
-
-       Homepage: http://www.marvell.com/embedded-processors/armada-70xx/
-       Product Brief: http://www.marvell.com/embedded-processors/assets/Armada7020PB-Jan2016.pdf
-                      http://www.marvell.com/embedded-processors/assets/Armada7040PB-Jan2016.pdf
-       Device tree files: arch/arm64/boot/dts/marvell/armada-70*
-
-  Armada 8K Flavors:
-       88F8020 (AP806 Dual + two CP110)
-       88F8040 (AP806 Quad + two CP110)
-       Core: ARM Cortex A72
-
-       Homepage: http://www.marvell.com/embedded-processors/armada-80xx/
-       Product Brief: http://www.marvell.com/embedded-processors/assets/Armada8020PB-Jan2016.pdf
-                      http://www.marvell.com/embedded-processors/assets/Armada8040PB-Jan2016.pdf
-       Device tree files: arch/arm64/boot/dts/marvell/armada-80*
-
-Avanta family
--------------
-
-  Flavors:
-       88F6510
-       88F6530P
-       88F6550
-       88F6560
-  Homepage     : http://www.marvell.com/broadband/
-  Product Brief: http://www.marvell.com/broadband/assets/Marvell_Avanta_88F6510_305_060-001_product_brief.pdf
-  No public datasheet available.
-
-  Core: ARMv5 compatible
-
-  Linux kernel mach directory: no code in mainline yet, planned for the future
-  Linux kernel plat directory: no code in mainline yet, planned for the future
-
-Storage family
---------------
-
-  Armada SP:
-       88RC1580
-    Product infos: http://www.marvell.com/storage/armada-sp/
-    Core: Sheeva ARMv7 comatible Quad-core PJ4C
-    (not supported in upstream Linux kernel)
-
-Dove family (application processor)
------------------------------------
-
-  Flavors:
-        88AP510 a.k.a Armada 510
-                Product Brief   : http://www.marvell.com/application-processors/armada-500/assets/Marvell_Armada510_SoC.pdf
-                Hardware Spec   : http://www.marvell.com/application-processors/armada-500/assets/Armada-510-Hardware-Spec.pdf
-                Functional Spec : http://www.marvell.com/application-processors/armada-500/assets/Armada-510-Functional-Spec.pdf
-  Homepage: http://www.marvell.com/application-processors/armada-500/
-  Core: ARMv7 compatible
-
-  Directory: arch/arm/mach-mvebu (DT enabled platforms)
-             arch/arm/mach-dove (non-DT enabled platforms)
-
-PXA 2xx/3xx/93x/95x family
---------------------------
-
-  Flavors:
-        PXA21x, PXA25x, PXA26x
-             Application processor only
-             Core: ARMv5 XScale1 core
-        PXA270, PXA271, PXA272
-             Product Brief         : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_pb.pdf
-             Design guide          : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_design_guide.pdf
-             Developers manual     : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_dev_man.pdf
-             Specification         : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_emts.pdf
-             Specification update  : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_spec_update.pdf
-             Application processor only
-             Core: ARMv5 XScale2 core
-        PXA300, PXA310, PXA320
-             PXA 300 Product Brief : http://www.marvell.com/application-processors/pxa-family/assets/PXA300_PB_R4.pdf
-             PXA 310 Product Brief : http://www.marvell.com/application-processors/pxa-family/assets/PXA310_PB_R4.pdf
-             PXA 320 Product Brief : http://www.marvell.com/application-processors/pxa-family/assets/PXA320_PB_R4.pdf
-             Design guide          : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_Design_Guide.pdf
-             Developers manual     : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_Developers_Manual.zip
-             Specifications        : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_EMTS.pdf
-             Specification Update  : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_Spec_Update.zip
-             Reference Manual      : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_TavorP_BootROM_Ref_Manual.pdf
-             Application processor only
-             Core: ARMv5 XScale3 core
-        PXA930, PXA935
-             Application processor with Communication processor
-             Core: ARMv5 XScale3 core
-        PXA955
-             Application processor with Communication processor
-             Core: ARMv7 compatible Sheeva PJ4 core
-
-   Comments:
-
-    * This line of SoCs originates from the XScale family developed by
-      Intel and acquired by Marvell in ~2006. The PXA21x, PXA25x,
-      PXA26x, PXA27x, PXA3xx and PXA93x were developed by Intel, while
-      the later PXA95x were developed by Marvell.
-
-    * Due to their XScale origin, these SoCs have virtually nothing in
-      common with the other (Kirkwood, Dove, etc.) families of Marvell
-      SoCs, except with the MMP/MMP2 family of SoCs.
-
-   Linux kernel mach directory: arch/arm/mach-pxa
-   Linux kernel plat directory: arch/arm/plat-pxa
-
-MMP/MMP2/MMP3 family (communication processor)
------------------------------------------
-
-   Flavors:
-        PXA168, a.k.a Armada 168
-             Homepage             : http://www.marvell.com/application-processors/armada-100/armada-168.jsp
-             Product brief        : http://www.marvell.com/application-processors/armada-100/assets/pxa_168_pb.pdf
-             Hardware manual      : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_datasheet.pdf
-             Software manual      : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_software_manual.pdf
-             Specification update : http://www.marvell.com/application-processors/armada-100/assets/ARMADA16x_Spec_update.pdf
-             Boot ROM manual      : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_ref_manual.pdf
-             App node package     : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_app_note_package.pdf
-             Application processor only
-             Core: ARMv5 compatible Marvell PJ1 88sv331 (Mohawk)
-        PXA910/PXA920
-             Homepage             : http://www.marvell.com/communication-processors/pxa910/
-             Product Brief        : http://www.marvell.com/communication-processors/pxa910/assets/Marvell_PXA910_Platform-001_PB_final.pdf
-             Application processor with Communication processor
-             Core: ARMv5 compatible Marvell PJ1 88sv331 (Mohawk)
-        PXA688, a.k.a. MMP2, a.k.a Armada 610
-             Product Brief        : http://www.marvell.com/application-processors/armada-600/assets/armada610_pb.pdf
-             Application processor only
-             Core: ARMv7 compatible Sheeva PJ4 88sv581x core
-       PXA2128, a.k.a. MMP3 (OLPC XO4, Linux support not upstream)
-            Product Brief        : http://www.marvell.com/application-processors/armada/pxa2128/assets/Marvell-ARMADA-PXA2128-SoC-PB.pdf
-            Application processor only
-            Core: Dual-core ARMv7 compatible Sheeva PJ4C core
-       PXA960/PXA968/PXA978 (Linux support not upstream)
-            Application processor with Communication Processor
-            Core: ARMv7 compatible Sheeva PJ4 core
-       PXA986/PXA988 (Linux support not upstream)
-            Application processor with Communication Processor
-            Core: Dual-core ARMv7 compatible Sheeva PJ4B-MP core
-       PXA1088/PXA1920 (Linux support not upstream)
-            Application processor with Communication Processor
-            Core: quad-core ARMv7 Cortex-A7
-       PXA1908/PXA1928/PXA1936
-            Application processor with Communication Processor
-            Core: multi-core ARMv8 Cortex-A53
-
-   Comments:
-
-    * This line of SoCs originates from the XScale family developed by
-      Intel and acquired by Marvell in ~2006. All the processors of
-      this MMP/MMP2 family were developed by Marvell.
-
-    * Due to their XScale origin, these SoCs have virtually nothing in
-      common with the other (Kirkwood, Dove, etc.) families of Marvell
-      SoCs, except with the PXA family of SoCs listed above.
-
-   Linux kernel mach directory: arch/arm/mach-mmp
-   Linux kernel plat directory: arch/arm/plat-pxa
-
-Berlin family (Multimedia Solutions)
--------------------------------------
-
-  Flavors:
-       88DE3010, Armada 1000 (no Linux support)
-               Core:           Marvell PJ1 (ARMv5TE), Dual-core
-               Product Brief:  http://www.marvell.com.cn/digital-entertainment/assets/armada_1000_pb.pdf
-       88DE3005, Armada 1500 Mini
-               Design name:    BG2CD
-               Core:           ARM Cortex-A9, PL310 L2CC
-       88DE3006, Armada 1500 Mini Plus
-               Design name:    BG2CDP
-               Core:           Dual Core ARM Cortex-A7
-       88DE3100, Armada 1500
-               Design name:    BG2
-               Core:           Marvell PJ4B-MP (ARMv7), Tauros3 L2CC
-       88DE3114, Armada 1500 Pro
-               Design name:    BG2Q
-               Core:           Quad Core ARM Cortex-A9, PL310 L2CC
-       88DE3214, Armada 1500 Pro 4K
-               Design name:    BG3
-               Core:           ARM Cortex-A15, CA15 integrated L2CC
-       88DE3218, ARMADA 1500 Ultra
-               Core:           ARM Cortex-A53
-
-  Homepage: https://www.synaptics.com/products/multimedia-solutions
-  Directory: arch/arm/mach-berlin
-
-  Comments:
-
-   * This line of SoCs is based on Marvell Sheeva or ARM Cortex CPUs
-     with Synopsys DesignWare (IRQ, GPIO, Timers, ...) and PXA IP (SDHCI, USB, ETH, ...).
-
-   * The Berlin family was acquired by Synaptics from Marvell in 2017.
-
-CPU Cores
----------
-
-The XScale cores were designed by Intel, and shipped by Marvell in the older
-PXA processors. Feroceon is a Marvell designed core that developed in-house,
-and that evolved into Sheeva. The XScale and Feroceon cores were phased out
-over time and replaced with Sheeva cores in later products, which subsequently
-got replaced with licensed ARM Cortex-A cores.
-
-  XScale 1
-       CPUID 0x69052xxx
-       ARMv5, iWMMXt
-  XScale 2
-       CPUID 0x69054xxx
-       ARMv5, iWMMXt
-  XScale 3
-       CPUID 0x69056xxx or 0x69056xxx
-       ARMv5, iWMMXt
-  Feroceon-1850 88fr331 "Mohawk"
-       CPUID 0x5615331x or 0x41xx926x
-       ARMv5TE, single issue
-  Feroceon-2850 88fr531-vd "Jolteon"
-       CPUID 0x5605531x or 0x41xx926x
-       ARMv5TE, VFP, dual-issue
-  Feroceon 88fr571-vd "Jolteon"
-       CPUID 0x5615571x
-       ARMv5TE, VFP, dual-issue
-  Feroceon 88fr131 "Mohawk-D"
-       CPUID 0x5625131x
-       ARMv5TE, single-issue in-order
-  Sheeva PJ1 88sv331 "Mohawk"
-       CPUID 0x561584xx
-       ARMv5, single-issue iWMMXt v2
-  Sheeva PJ4 88sv581x "Flareon"
-       CPUID 0x560f581x
-       ARMv7, idivt, optional iWMMXt v2
-  Sheeva PJ4B 88sv581x
-       CPUID 0x561f581x
-       ARMv7, idivt, optional iWMMXt v2
-  Sheeva PJ4B-MP / PJ4C
-       CPUID 0x562f584x
-       ARMv7, idivt/idiva, LPAE, optional iWMMXt v2 and/or NEON
-
-Long-term plans
----------------
-
- * Unify the mach-dove/, mach-mv78xx0/, mach-orion5x/ into the
-   mach-mvebu/ to support all SoCs from the Marvell EBU (Engineering
-   Business Unit) in a single mach-<foo> directory. The plat-orion/
-   would therefore disappear.
-
- * Unify the mach-mmp/ and mach-pxa/ into the same mach-pxa
-   directory. The plat-pxa/ would therefore disappear.
-
-Credits
--------
-
- Maen Suleiman <maen@marvell.com>
- Lior Amsalem <alior@marvell.com>
- Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
- Andrew Lunn <andrew@lunn.ch>
- Nicolas Pitre <nico@fluxnic.net>
- Eric Miao <eric.y.miao@gmail.com>
diff --git a/Documentation/arm/Microchip/README b/Documentation/arm/Microchip/README
deleted file mode 100644 (file)
index a366f37..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-ARM Microchip SoCs (aka AT91)
-=============================
-
-
-Introduction
-------------
-This document gives useful information about the ARM Microchip SoCs that are
-currently supported in Linux Mainline (you know, the one on kernel.org).
-
-It is important to note that the Microchip (previously Atmel) ARM-based MPU
-product line is historically named "AT91" or "at91" throughout the Linux kernel
-development process even if this product prefix has completely disappeared from
-the official Microchip product name. Anyway, files, directories, git trees,
-git branches/tags and email subject always contain this "at91" sub-string.
-
-
-AT91 SoCs
----------
-Documentation and detailed datasheet for each product are available on
-the Microchip website: http://www.microchip.com.
-
-  Flavors:
-    * ARM 920 based SoC
-      - at91rm9200
-        + Datasheet
-          http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-1768-32-bit-ARM920T-Embedded-Microprocessor-AT91RM9200_Datasheet.pdf
-
-    * ARM 926 based SoCs
-      - at91sam9260
-        + Datasheet
-          http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-6221-32-bit-ARM926EJ-S-Embedded-Microprocessor-SAM9260_Datasheet.pdf
-
-      - at91sam9xe
-        + Datasheet
-          http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-6254-32-bit-ARM926EJ-S-Embedded-Microprocessor-SAM9XE_Datasheet.pdf
-
-      - at91sam9261
-        + Datasheet
-          http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-6062-ARM926EJ-S-Microprocessor-SAM9261_Datasheet.pdf
-
-      - at91sam9263
-        + Datasheet
-          http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-6249-32-bit-ARM926EJ-S-Embedded-Microprocessor-SAM9263_Datasheet.pdf
-
-      - at91sam9rl
-        + Datasheet
-          http://ww1.microchip.com/downloads/en/DeviceDoc/doc6289.pdf
-
-      - at91sam9g20
-        + Datasheet
-          http://ww1.microchip.com/downloads/en/DeviceDoc/DS60001516A.pdf
-
-      - at91sam9g45 family
-        - at91sam9g45
-        - at91sam9g46
-        - at91sam9m10
-        - at91sam9m11 (device superset)
-        + Datasheet
-          http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-6437-32-bit-ARM926-Embedded-Microprocessor-SAM9M11_Datasheet.pdf
-
-      - at91sam9x5 family (aka "The 5 series")
-        - at91sam9g15
-        - at91sam9g25
-        - at91sam9g35
-        - at91sam9x25
-        - at91sam9x35
-        + Datasheet (can be considered as covering the whole family)
-          http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11055-32-bit-ARM926EJ-S-Microcontroller-SAM9X35_Datasheet.pdf
-
-      - at91sam9n12
-        + Datasheet
-          http://ww1.microchip.com/downloads/en/DeviceDoc/DS60001517A.pdf
-
-    * ARM Cortex-A5 based SoCs
-      - sama5d3 family
-        - sama5d31
-        - sama5d33
-        - sama5d34
-        - sama5d35
-        - sama5d36 (device superset)
-        + Datasheet
-          http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11121-32-bit-Cortex-A5-Microcontroller-SAMA5D3_Datasheet.pdf
-
-    * ARM Cortex-A5 + NEON based SoCs
-      - sama5d4 family
-        - sama5d41
-        - sama5d42
-        - sama5d43
-        - sama5d44 (device superset)
-        + Datasheet
-          http://ww1.microchip.com/downloads/en/DeviceDoc/60001525A.pdf
-
-      - sama5d2 family
-        - sama5d21
-        - sama5d22
-        - sama5d23
-        - sama5d24
-        - sama5d26
-        - sama5d27 (device superset)
-        - sama5d28 (device superset + environmental monitors)
-        + Datasheet
-          http://ww1.microchip.com/downloads/en/DeviceDoc/DS60001476B.pdf
-
-    * ARM Cortex-M7 MCUs
-      - sams70 family
-        - sams70j19
-        - sams70j20
-        - sams70j21
-        - sams70n19
-        - sams70n20
-        - sams70n21
-        - sams70q19
-        - sams70q20
-        - sams70q21
-
-      - samv70 family
-        - samv70j19
-        - samv70j20
-        - samv70n19
-        - samv70n20
-        - samv70q19
-        - samv70q20
-
-      - samv71 family
-        - samv71j19
-        - samv71j20
-        - samv71j21
-        - samv71n19
-        - samv71n20
-        - samv71n21
-        - samv71q19
-        - samv71q20
-        - samv71q21
-
-        + Datasheet
-          http://ww1.microchip.com/downloads/en/DeviceDoc/60001527A.pdf
-
-
-Linux kernel information
-------------------------
-Linux kernel mach directory: arch/arm/mach-at91
-MAINTAINERS entry is: "ARM/Microchip (AT91) SoC support"
-
-
-Device Tree for AT91 SoCs and boards
-------------------------------------
-All AT91 SoCs are converted to Device Tree. Since Linux 3.19, these products
-must use this method to boot the Linux kernel.
-
-Work In Progress statement:
-Device Tree files and Device Tree bindings that apply to AT91 SoCs and boards are
-considered as "Unstable". To be completely clear, any at91 binding can change at
-any time. So, be sure to use a Device Tree Binary and a Kernel Image generated from
-the same source tree.
-Please refer to the Documentation/devicetree/bindings/ABI.txt file for a
-definition of a "Stable" binding/ABI.
-This statement will be removed by AT91 MAINTAINERS when appropriate.
-
-Naming conventions and best practice:
-- SoCs Device Tree Source Include files are named after the official name of
-  the product (at91sam9g20.dtsi or sama5d33.dtsi for instance).
-- Device Tree Source Include files (.dtsi) are used to collect common nodes that can be
-  shared across SoCs or boards (sama5d3.dtsi or at91sam9x5cm.dtsi for instance).
-  When collecting nodes for a particular peripheral or topic, the identifier have to
-  be placed at the end of the file name, separated with a "_" (at91sam9x5_can.dtsi
-  or sama5d3_gmac.dtsi for example).
-- board Device Tree Source files (.dts) are prefixed by the string "at91-" so
-  that they can be identified easily. Note that some files are historical exceptions
-  to this rule (sama5d3[13456]ek.dts, usb_a9g20.dts or animeo_ip.dts for example).
diff --git a/Documentation/arm/Netwinder b/Documentation/arm/Netwinder
deleted file mode 100644 (file)
index f1b457f..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-NetWinder specific documentation
-================================
-
-The NetWinder is a small low-power computer, primarily designed
-to run Linux.  It is based around the StrongARM RISC processor,
-DC21285 PCI bridge, with PC-type hardware glued around it.
-
-Port usage
-==========
-
-Min    - Max   Description
----------------------------
-0x0000 - 0x000f        DMA1
-0x0020 - 0x0021        PIC1
-0x0060 - 0x006f        Keyboard
-0x0070 - 0x007f        RTC
-0x0080 - 0x0087        DMA1
-0x0088 - 0x008f        DMA2
-0x00a0 - 0x00a3        PIC2
-0x00c0 - 0x00df        DMA2
-0x0180 - 0x0187        IRDA
-0x01f0 - 0x01f6        ide0
-0x0201         Game port
-0x0203         RWA010 configuration read
-0x0220 - ?     SoundBlaster
-0x0250 - ?     WaveArtist
-0x0279         RWA010 configuration index
-0x02f8 - 0x02ff        Serial ttyS1
-0x0300 - 0x031f        Ether10
-0x0338         GPIO1
-0x033a         GPIO2
-0x0370 - 0x0371        W83977F configuration registers
-0x0388 - ?     AdLib
-0x03c0 - 0x03df        VGA
-0x03f6         ide0
-0x03f8 - 0x03ff        Serial ttyS0
-0x0400 - 0x0408        DC21143
-0x0480 - 0x0487        DMA1
-0x0488 - 0x048f        DMA2
-0x0a79         RWA010 configuration write
-0xe800 - 0xe80f        ide0/ide1 BM DMA
-
-
-Interrupt usage
-===============
-
-IRQ    type    Description
----------------------------
- 0     ISA     100Hz timer
- 1     ISA     Keyboard
- 2     ISA     cascade
- 3     ISA     Serial ttyS1
- 4     ISA     Serial ttyS0
- 5     ISA     PS/2 mouse
- 6     ISA     IRDA
- 7     ISA     Printer
- 8     ISA     RTC alarm
- 9     ISA
-10     ISA     GP10 (Orange reset button)
-11     ISA
-12     ISA     WaveArtist
-13     ISA
-14     ISA     hda1
-15     ISA
-
-DMA usage
-=========
-
-DMA    type    Description
----------------------------
- 0     ISA     IRDA
- 1     ISA
- 2     ISA     cascade
- 3     ISA     WaveArtist
- 4     ISA
- 5     ISA
- 6     ISA
- 7     ISA     WaveArtist
diff --git a/Documentation/arm/OMAP/DSS b/Documentation/arm/OMAP/DSS
deleted file mode 100644 (file)
index 4484e02..0000000
+++ /dev/null
@@ -1,362 +0,0 @@
-OMAP2/3 Display Subsystem
--------------------------
-
-This is an almost total rewrite of the OMAP FB driver in drivers/video/omap
-(let's call it DSS1). The main differences between DSS1 and DSS2 are DSI,
-TV-out and multiple display support, but there are lots of small improvements
-also.
-
-The DSS2 driver (omapdss module) is in arch/arm/plat-omap/dss/, and the FB,
-panel and controller drivers are in drivers/video/omap2/. DSS1 and DSS2 live
-currently side by side, you can choose which one to use.
-
-Features
---------
-
-Working and tested features include:
-
-- MIPI DPI (parallel) output
-- MIPI DSI output in command mode
-- MIPI DBI (RFBI) output
-- SDI output
-- TV output
-- All pieces can be compiled as a module or inside kernel
-- Use DISPC to update any of the outputs
-- Use CPU to update RFBI or DSI output
-- OMAP DISPC planes
-- RGB16, RGB24 packed, RGB24 unpacked
-- YUV2, UYVY
-- Scaling
-- Adjusting DSS FCK to find a good pixel clock
-- Use DSI DPLL to create DSS FCK
-
-Tested boards include:
-- OMAP3 SDP board
-- Beagle board
-- N810
-
-omapdss driver
---------------
-
-The DSS driver does not itself have any support for Linux framebuffer, V4L or
-such like the current ones, but it has an internal kernel API that upper level
-drivers can use.
-
-The DSS driver models OMAP's overlays, overlay managers and displays in a
-flexible way to enable non-common multi-display configuration. In addition to
-modelling the hardware overlays, omapdss supports virtual overlays and overlay
-managers. These can be used when updating a display with CPU or system DMA.
-
-omapdss driver support for audio
---------------------------------
-There exist several display technologies and standards that support audio as
-well. Hence, it is relevant to update the DSS device driver to provide an audio
-interface that may be used by an audio driver or any other driver interested in
-the functionality.
-
-The audio_enable function is intended to prepare the relevant
-IP for playback (e.g., enabling an audio FIFO, taking in/out of reset
-some IP, enabling companion chips, etc). It is intended to be called before
-audio_start. The audio_disable function performs the reverse operation and is
-intended to be called after audio_stop.
-
-While a given DSS device driver may support audio, it is possible that for
-certain configurations audio is not supported (e.g., an HDMI display using a
-VESA video timing). The audio_supported function is intended to query whether
-the current configuration of the display supports audio.
-
-The audio_config function is intended to configure all the relevant audio
-parameters of the display. In order to make the function independent of any
-specific DSS device driver, a struct omap_dss_audio is defined. Its purpose
-is to contain all the required parameters for audio configuration. At the
-moment, such structure contains pointers to IEC-60958 channel status word
-and CEA-861 audio infoframe structures. This should be enough to support
-HDMI and DisplayPort, as both are based on CEA-861 and IEC-60958.
-
-The audio_enable/disable, audio_config and audio_supported functions could be
-implemented as functions that may sleep. Hence, they should not be called
-while holding a spinlock or a readlock.
-
-The audio_start/audio_stop function is intended to effectively start/stop audio
-playback after the configuration has taken place. These functions are designed
-to be used in an atomic context. Hence, audio_start should return quickly and be
-called only after all the needed resources for audio playback (audio FIFOs,
-DMA channels, companion chips, etc) have been enabled to begin data transfers.
-audio_stop is designed to only stop the audio transfers. The resources used
-for playback are released using audio_disable.
-
-The enum omap_dss_audio_state may be used to help the implementations of
-the interface to keep track of the audio state. The initial state is _DISABLED;
-then, the state transitions to _CONFIGURED, and then, when it is ready to
-play audio, to _ENABLED. The state _PLAYING is used when the audio is being
-rendered.
-
-
-Panel and controller drivers
-----------------------------
-
-The drivers implement panel or controller specific functionality and are not
-usually visible to users except through omapfb driver.  They register
-themselves to the DSS driver.
-
-omapfb driver
--------------
-
-The omapfb driver implements arbitrary number of standard linux framebuffers.
-These framebuffers can be routed flexibly to any overlays, thus allowing very
-dynamic display architecture.
-
-The driver exports some omapfb specific ioctls, which are compatible with the
-ioctls in the old driver.
-
-The rest of the non standard features are exported via sysfs. Whether the final
-implementation will use sysfs, or ioctls, is still open.
-
-V4L2 drivers
-------------
-
-V4L2 is being implemented in TI.
-
-From omapdss point of view the V4L2 drivers should be similar to framebuffer
-driver.
-
-Architecture
---------------------
-
-Some clarification what the different components do:
-
-    - Framebuffer is a memory area inside OMAP's SRAM/SDRAM that contains the
-      pixel data for the image. Framebuffer has width and height and color
-      depth.
-    - Overlay defines where the pixels are read from and where they go on the
-      screen. The overlay may be smaller than framebuffer, thus displaying only
-      part of the framebuffer. The position of the overlay may be changed if
-      the overlay is smaller than the display.
-    - Overlay manager combines the overlays in to one image and feeds them to
-      display.
-    - Display is the actual physical display device.
-
-A framebuffer can be connected to multiple overlays to show the same pixel data
-on all of the overlays. Note that in this case the overlay input sizes must be
-the same, but, in case of video overlays, the output size can be different. Any
-framebuffer can be connected to any overlay.
-
-An overlay can be connected to one overlay manager. Also DISPC overlays can be
-connected only to DISPC overlay managers, and virtual overlays can be only
-connected to virtual overlays.
-
-An overlay manager can be connected to one display. There are certain
-restrictions which kinds of displays an overlay manager can be connected:
-
-    - DISPC TV overlay manager can be only connected to TV display.
-    - Virtual overlay managers can only be connected to DBI or DSI displays.
-    - DISPC LCD overlay manager can be connected to all displays, except TV
-      display.
-
-Sysfs
------
-The sysfs interface is mainly used for testing. I don't think sysfs
-interface is the best for this in the final version, but I don't quite know
-what would be the best interfaces for these things.
-
-The sysfs interface is divided to two parts: DSS and FB.
-
-/sys/class/graphics/fb? directory:
-mirror         0=off, 1=on
-rotate         Rotation 0-3 for 0, 90, 180, 270 degrees
-rotate_type    0 = DMA rotation, 1 = VRFB rotation
-overlays       List of overlay numbers to which framebuffer pixels go
-phys_addr      Physical address of the framebuffer
-virt_addr      Virtual address of the framebuffer
-size           Size of the framebuffer
-
-/sys/devices/platform/omapdss/overlay? directory:
-enabled                0=off, 1=on
-input_size     width,height (ie. the framebuffer size)
-manager                Destination overlay manager name
-name
-output_size    width,height
-position       x,y
-screen_width   width
-global_alpha           global alpha 0-255 0=transparent 255=opaque
-
-/sys/devices/platform/omapdss/manager? directory:
-display                                Destination display
-name
-alpha_blending_enabled         0=off, 1=on
-trans_key_enabled              0=off, 1=on
-trans_key_type                 gfx-destination, video-source
-trans_key_value                        transparency color key (RGB24)
-default_color                  default background color (RGB24)
-
-/sys/devices/platform/omapdss/display? directory:
-ctrl_name      Controller name
-mirror         0=off, 1=on
-update_mode    0=off, 1=auto, 2=manual
-enabled                0=off, 1=on
-name
-rotate         Rotation 0-3 for 0, 90, 180, 270 degrees
-timings                Display timings (pixclock,xres/hfp/hbp/hsw,yres/vfp/vbp/vsw)
-               When writing, two special timings are accepted for tv-out:
-               "pal" and "ntsc"
-panel_name
-tear_elim      Tearing elimination 0=off, 1=on
-output_type    Output type (video encoder only): "composite" or "svideo"
-
-There are also some debugfs files at <debugfs>/omapdss/ which show information
-about clocks and registers.
-
-Examples
---------
-
-The following definitions have been made for the examples below:
-
-ovl0=/sys/devices/platform/omapdss/overlay0
-ovl1=/sys/devices/platform/omapdss/overlay1
-ovl2=/sys/devices/platform/omapdss/overlay2
-
-mgr0=/sys/devices/platform/omapdss/manager0
-mgr1=/sys/devices/platform/omapdss/manager1
-
-lcd=/sys/devices/platform/omapdss/display0
-dvi=/sys/devices/platform/omapdss/display1
-tv=/sys/devices/platform/omapdss/display2
-
-fb0=/sys/class/graphics/fb0
-fb1=/sys/class/graphics/fb1
-fb2=/sys/class/graphics/fb2
-
-Default setup on OMAP3 SDP
---------------------------
-
-Here's the default setup on OMAP3 SDP board. All planes go to LCD. DVI
-and TV-out are not in use. The columns from left to right are:
-framebuffers, overlays, overlay managers, displays. Framebuffers are
-handled by omapfb, and the rest by the DSS.
-
-FB0 --- GFX  -\            DVI
-FB1 --- VID1 --+- LCD ---- LCD
-FB2 --- VID2 -/   TV ----- TV
-
-Example: Switch from LCD to DVI
-----------------------
-
-w=`cat $dvi/timings | cut -d "," -f 2 | cut -d "/" -f 1`
-h=`cat $dvi/timings | cut -d "," -f 3 | cut -d "/" -f 1`
-
-echo "0" > $lcd/enabled
-echo "" > $mgr0/display
-fbset -fb /dev/fb0 -xres $w -yres $h -vxres $w -vyres $h
-# at this point you have to switch the dvi/lcd dip-switch from the omap board
-echo "dvi" > $mgr0/display
-echo "1" > $dvi/enabled
-
-After this the configuration looks like:
-
-FB0 --- GFX  -\         -- DVI
-FB1 --- VID1 --+- LCD -/   LCD
-FB2 --- VID2 -/   TV ----- TV
-
-Example: Clone GFX overlay to LCD and TV
--------------------------------
-
-w=`cat $tv/timings | cut -d "," -f 2 | cut -d "/" -f 1`
-h=`cat $tv/timings | cut -d "," -f 3 | cut -d "/" -f 1`
-
-echo "0" > $ovl0/enabled
-echo "0" > $ovl1/enabled
-
-echo "" > $fb1/overlays
-echo "0,1" > $fb0/overlays
-
-echo "$w,$h" > $ovl1/output_size
-echo "tv" > $ovl1/manager
-
-echo "1" > $ovl0/enabled
-echo "1" > $ovl1/enabled
-
-echo "1" > $tv/enabled
-
-After this the configuration looks like (only relevant parts shown):
-
-FB0 +-- GFX  ---- LCD ---- LCD
-     \- VID1 ---- TV  ---- TV
-
-Misc notes
-----------
-
-OMAP FB allocates the framebuffer memory using the standard dma allocator. You
-can enable Contiguous Memory Allocator (CONFIG_CMA) to improve the dma
-allocator, and if CMA is enabled, you use "cma=" kernel parameter to increase
-the global memory area for CMA.
-
-Using DSI DPLL to generate pixel clock it is possible produce the pixel clock
-of 86.5MHz (max possible), and with that you get 1280x1024@57 output from DVI.
-
-Rotation and mirroring currently only supports RGB565 and RGB8888 modes. VRFB
-does not support mirroring.
-
-VRFB rotation requires much more memory than non-rotated framebuffer, so you
-probably need to increase your vram setting before using VRFB rotation. Also,
-many applications may not work with VRFB if they do not pay attention to all
-framebuffer parameters.
-
-Kernel boot arguments
----------------------
-
-omapfb.mode=<display>:<mode>[,...]
-       - Default video mode for specified displays. For example,
-         "dvi:800x400MR-24@60".  See drivers/video/modedb.c.
-         There are also two special modes: "pal" and "ntsc" that
-         can be used to tv out.
-
-omapfb.vram=<fbnum>:<size>[@<physaddr>][,...]
-       - VRAM allocated for a framebuffer. Normally omapfb allocates vram
-         depending on the display size. With this you can manually allocate
-         more or define the physical address of each framebuffer. For example,
-         "1:4M" to allocate 4M for fb1.
-
-omapfb.debug=<y|n>
-       - Enable debug printing. You have to have OMAPFB debug support enabled
-         in kernel config.
-
-omapfb.test=<y|n>
-       - Draw test pattern to framebuffer whenever framebuffer settings change.
-         You need to have OMAPFB debug support enabled in kernel config.
-
-omapfb.vrfb=<y|n>
-       - Use VRFB rotation for all framebuffers.
-
-omapfb.rotate=<angle>
-       - Default rotation applied to all framebuffers.
-         0 - 0 degree rotation
-         1 - 90 degree rotation
-         2 - 180 degree rotation
-         3 - 270 degree rotation
-
-omapfb.mirror=<y|n>
-       - Default mirror for all framebuffers. Only works with DMA rotation.
-
-omapdss.def_disp=<display>
-       - Name of default display, to which all overlays will be connected.
-         Common examples are "lcd" or "tv".
-
-omapdss.debug=<y|n>
-       - Enable debug printing. You have to have DSS debug support enabled in
-         kernel config.
-
-TODO
-----
-
-DSS locking
-
-Error checking
-- Lots of checks are missing or implemented just as BUG()
-
-System DMA update for DSI
-- Can be used for RGB16 and RGB24P modes. Probably not for RGB24U (how
-  to skip the empty byte?)
-
-OMAP1 support
-- Not sure if needed
-
diff --git a/Documentation/arm/OMAP/README b/Documentation/arm/OMAP/README
deleted file mode 100644 (file)
index 90c6c57..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-This file contains documentation for running mainline
-kernel on omaps.
-
-KERNEL         NEW DEPENDENCIES
-v4.3+          Update is needed for custom .config files to make sure
-               CONFIG_REGULATOR_PBIAS is enabled for MMC1 to work
-               properly.
-
-v4.18+         Update is needed for custom .config files to make sure
-               CONFIG_MMC_SDHCI_OMAP is enabled for all MMC instances
-               to work in DRA7 and K2G based boards.
diff --git a/Documentation/arm/OMAP/omap_pm b/Documentation/arm/OMAP/omap_pm
deleted file mode 100644 (file)
index 4ae915a..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-
-The OMAP PM interface
-=====================
-
-This document describes the temporary OMAP PM interface.  Driver
-authors use these functions to communicate minimum latency or
-throughput constraints to the kernel power management code.
-Over time, the intention is to merge features from the OMAP PM
-interface into the Linux PM QoS code.
-
-Drivers need to express PM parameters which:
-
-- support the range of power management parameters present in the TI SRF;
-
-- separate the drivers from the underlying PM parameter
-  implementation, whether it is the TI SRF or Linux PM QoS or Linux
-  latency framework or something else;
-
-- specify PM parameters in terms of fundamental units, such as
-  latency and throughput, rather than units which are specific to OMAP
-  or to particular OMAP variants;
-
-- allow drivers which are shared with other architectures (e.g.,
-  DaVinci) to add these constraints in a way which won't affect non-OMAP
-  systems,
-
-- can be implemented immediately with minimal disruption of other
-  architectures.
-
-
-This document proposes the OMAP PM interface, including the following
-five power management functions for driver code:
-
-1. Set the maximum MPU wakeup latency:
-   (*pdata->set_max_mpu_wakeup_lat)(struct device *dev, unsigned long t)
-
-2. Set the maximum device wakeup latency:
-   (*pdata->set_max_dev_wakeup_lat)(struct device *dev, unsigned long t)
-
-3. Set the maximum system DMA transfer start latency (CORE pwrdm):
-   (*pdata->set_max_sdma_lat)(struct device *dev, long t)
-
-4. Set the minimum bus throughput needed by a device:
-   (*pdata->set_min_bus_tput)(struct device *dev, u8 agent_id, unsigned long r)
-
-5. Return the number of times the device has lost context
-   (*pdata->get_dev_context_loss_count)(struct device *dev)
-
-
-Further documentation for all OMAP PM interface functions can be
-found in arch/arm/plat-omap/include/mach/omap-pm.h.
-
-
-The OMAP PM layer is intended to be temporary
----------------------------------------------
-
-The intention is that eventually the Linux PM QoS layer should support
-the range of power management features present in OMAP3.  As this
-happens, existing drivers using the OMAP PM interface can be modified
-to use the Linux PM QoS code; and the OMAP PM interface can disappear.
-
-
-Driver usage of the OMAP PM functions
--------------------------------------
-
-As the 'pdata' in the above examples indicates, these functions are
-exposed to drivers through function pointers in driver .platform_data
-structures.  The function pointers are initialized by the board-*.c
-files to point to the corresponding OMAP PM functions:
-.set_max_dev_wakeup_lat will point to
-omap_pm_set_max_dev_wakeup_lat(), etc.  Other architectures which do
-not support these functions should leave these function pointers set
-to NULL.  Drivers should use the following idiom:
-
-        if (pdata->set_max_dev_wakeup_lat)
-            (*pdata->set_max_dev_wakeup_lat)(dev, t);
-
-The most common usage of these functions will probably be to specify
-the maximum time from when an interrupt occurs, to when the device
-becomes accessible.  To accomplish this, driver writers should use the
-set_max_mpu_wakeup_lat() function to constrain the MPU wakeup
-latency, and the set_max_dev_wakeup_lat() function to constrain the
-device wakeup latency (from clk_enable() to accessibility).  For
-example,
-
-        /* Limit MPU wakeup latency */
-        if (pdata->set_max_mpu_wakeup_lat)
-            (*pdata->set_max_mpu_wakeup_lat)(dev, tc);
-
-        /* Limit device powerdomain wakeup latency */
-        if (pdata->set_max_dev_wakeup_lat)
-            (*pdata->set_max_dev_wakeup_lat)(dev, td);
-
-        /* total wakeup latency in this example: (tc + td) */
-
-The PM parameters can be overwritten by calling the function again
-with the new value.  The settings can be removed by calling the
-function with a t argument of -1 (except in the case of
-set_max_bus_tput(), which should be called with an r argument of 0).
-
-The fifth function above, omap_pm_get_dev_context_loss_count(),
-is intended as an optimization to allow drivers to determine whether the
-device has lost its internal context.  If context has been lost, the
-driver must restore its internal context before proceeding.
-
-
-Other specialized interface functions
--------------------------------------
-
-The five functions listed above are intended to be usable by any
-device driver.  DSPBridge and CPUFreq have a few special requirements.
-DSPBridge expresses target DSP performance levels in terms of OPP IDs.
-CPUFreq expresses target MPU performance levels in terms of MPU
-frequency.  The OMAP PM interface contains functions for these
-specialized cases to convert that input information (OPPs/MPU
-frequency) into the form that the underlying power management
-implementation needs:
-
-6. (*pdata->dsp_get_opp_table)(void)
-
-7. (*pdata->dsp_set_min_opp)(u8 opp_id)
-
-8. (*pdata->dsp_get_opp)(void)
-
-9. (*pdata->cpu_get_freq_table)(void)
-
-10. (*pdata->cpu_set_freq)(unsigned long f)
-
-11. (*pdata->cpu_get_freq)(void)
-
-Customizing OPP for platform
-============================
-Defining CONFIG_PM should enable OPP layer for the silicon
-and the registration of OPP table should take place automatically.
-However, in special cases, the default OPP table may need to be
-tweaked, for e.g.:
- * enable default OPPs which are disabled by default, but which
-   could be enabled on a platform
- * Disable an unsupported OPP on the platform
- * Define and add a custom opp table entry
-in these cases, the board file needs to do additional steps as follows:
-arch/arm/mach-omapx/board-xyz.c
-       #include "pm.h"
-       ....
-       static void __init omap_xyz_init_irq(void)
-       {
-               ....
-               /* Initialize the default table */
-               omapx_opp_init();
-               /* Do customization to the defaults */
-               ....
-       }
-NOTE: omapx_opp_init will be omap3_opp_init or as required
-based on the omap family.
diff --git a/Documentation/arm/Porting b/Documentation/arm/Porting
deleted file mode 100644 (file)
index a492233..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-Taken from list archive at http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2001-July/004064.html
-
-Initial definitions
--------------------
-
-The following symbol definitions rely on you knowing the translation that
-__virt_to_phys() does for your machine.  This macro converts the passed
-virtual address to a physical address.  Normally, it is simply:
-
-               phys = virt - PAGE_OFFSET + PHYS_OFFSET
-
-
-Decompressor Symbols
---------------------
-
-ZTEXTADDR
-       Start address of decompressor.  There's no point in talking about
-       virtual or physical addresses here, since the MMU will be off at
-       the time when you call the decompressor code.  You normally call
-       the kernel at this address to start it booting.  This doesn't have
-       to be located in RAM, it can be in flash or other read-only or
-       read-write addressable medium.
-
-ZBSSADDR
-       Start address of zero-initialised work area for the decompressor.
-       This must be pointing at RAM.  The decompressor will zero initialise
-       this for you.  Again, the MMU will be off.
-
-ZRELADDR
-       This is the address where the decompressed kernel will be written,
-       and eventually executed.  The following constraint must be valid:
-
-               __virt_to_phys(TEXTADDR) == ZRELADDR
-
-       The initial part of the kernel is carefully coded to be position
-       independent.
-
-INITRD_PHYS
-       Physical address to place the initial RAM disk.  Only relevant if
-       you are using the bootpImage stuff (which only works on the old
-       struct param_struct).
-
-INITRD_VIRT
-       Virtual address of the initial RAM disk.  The following  constraint
-       must be valid:
-
-               __virt_to_phys(INITRD_VIRT) == INITRD_PHYS
-
-PARAMS_PHYS
-       Physical address of the struct param_struct or tag list, giving the
-       kernel various parameters about its execution environment.
-
-
-Kernel Symbols
---------------
-
-PHYS_OFFSET
-       Physical start address of the first bank of RAM.
-
-PAGE_OFFSET
-       Virtual start address of the first bank of RAM.  During the kernel
-       boot phase, virtual address PAGE_OFFSET will be mapped to physical
-       address PHYS_OFFSET, along with any other mappings you supply.
-       This should be the same value as TASK_SIZE.
-
-TASK_SIZE
-       The maximum size of a user process in bytes.  Since user space
-       always starts at zero, this is the maximum address that a user
-       process can access+1.  The user space stack grows down from this
-       address.
-
-       Any virtual address below TASK_SIZE is deemed to be user process
-       area, and therefore managed dynamically on a process by process
-       basis by the kernel.  I'll call this the user segment.
-
-       Anything above TASK_SIZE is common to all processes.  I'll call
-       this the kernel segment.
-
-       (In other words, you can't put IO mappings below TASK_SIZE, and
-       hence PAGE_OFFSET).
-
-TEXTADDR
-       Virtual start address of kernel, normally PAGE_OFFSET + 0x8000.
-       This is where the kernel image ends up.  With the latest kernels,
-       it must be located at 32768 bytes into a 128MB region.  Previous
-       kernels placed a restriction of 256MB here.
-
-DATAADDR
-       Virtual address for the kernel data segment.  Must not be defined
-       when using the decompressor.
-
-VMALLOC_START
-VMALLOC_END
-       Virtual addresses bounding the vmalloc() area.  There must not be
-       any static mappings in this area; vmalloc will overwrite them.
-       The addresses must also be in the kernel segment (see above).
-       Normally, the vmalloc() area starts VMALLOC_OFFSET bytes above the
-       last virtual RAM address (found using variable high_memory).
-
-VMALLOC_OFFSET
-       Offset normally incorporated into VMALLOC_START to provide a hole
-       between virtual RAM and the vmalloc area.  We do this to allow
-       out of bounds memory accesses (eg, something writing off the end
-       of the mapped memory map) to be caught.  Normally set to 8MB.
-
-Architecture Specific Macros
-----------------------------
-
-BOOT_MEM(pram,pio,vio)
-       `pram' specifies the physical start address of RAM.  Must always
-       be present, and should be the same as PHYS_OFFSET.
-
-       `pio' is the physical address of an 8MB region containing IO for
-       use with the debugging macros in arch/arm/kernel/debug-armv.S.
-
-       `vio' is the virtual address of the 8MB debugging region.
-
-       It is expected that the debugging region will be re-initialised
-       by the architecture specific code later in the code (via the
-       MAPIO function).
-
-BOOT_PARAMS
-       Same as, and see PARAMS_PHYS.
-
-FIXUP(func)
-       Machine specific fixups, run before memory subsystems have been
-       initialised.
-
-MAPIO(func)
-       Machine specific function to map IO areas (including the debug
-       region above).
-
-INITIRQ(func)
-       Machine specific function to initialise interrupts.
-
diff --git a/Documentation/arm/README b/Documentation/arm/README
deleted file mode 100644 (file)
index 9d1e5b2..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-                          ARM Linux 2.6
-                          =============
-
-    Please check <ftp://ftp.arm.linux.org.uk/pub/armlinux> for
-    updates.
-
-Compilation of kernel
----------------------
-
-  In order to compile ARM Linux, you will need a compiler capable of
-  generating ARM ELF code with GNU extensions.  GCC 3.3 is known to be
-  a good compiler.  Fortunately, you needn't guess.  The kernel will report
-  an error if your compiler is a recognized offender.
-
-  To build ARM Linux natively, you shouldn't have to alter the ARCH = line
-  in the top level Makefile.  However, if you don't have the ARM Linux ELF
-  tools installed as default, then you should change the CROSS_COMPILE
-  line as detailed below.
-
-  If you wish to cross-compile, then alter the following lines in the top
-  level make file:
-
-    ARCH = <whatever>
-       with
-    ARCH = arm
-
-       and
-
-    CROSS_COMPILE=
-       to
-    CROSS_COMPILE=<your-path-to-your-compiler-without-gcc>
-       eg.
-    CROSS_COMPILE=arm-linux-
-
-  Do a 'make config', followed by 'make Image' to build the kernel 
-  (arch/arm/boot/Image).  A compressed image can be built by doing a 
-  'make zImage' instead of 'make Image'.
-
-
-Bug reports etc
----------------
-
-  Please send patches to the patch system.  For more information, see
-  http://www.arm.linux.org.uk/developer/patches/info.php Always include some
-  explanation as to what the patch does and why it is needed.
-
-  Bug reports should be sent to linux-arm-kernel@lists.arm.linux.org.uk,
-  or submitted through the web form at
-  http://www.arm.linux.org.uk/developer/ 
-
-  When sending bug reports, please ensure that they contain all relevant
-  information, eg. the kernel messages that were printed before/during
-  the problem, what you were doing, etc.
-
-
-Include files
--------------
-
-  Several new include directories have been created under include/asm-arm,
-  which are there to reduce the clutter in the top-level directory.  These
-  directories, and their purpose is listed below:
-
-   arch-*      machine/platform specific header files
-   hardware    driver-internal ARM specific data structures/definitions
-   mach                descriptions of generic ARM to specific machine interfaces
-   proc-*      processor dependent header files (currently only two
-               categories)
-
-
-Machine/Platform support
-------------------------
-
-  The ARM tree contains support for a lot of different machine types.  To
-  continue supporting these differences, it has become necessary to split
-  machine-specific parts by directory.  For this, the machine category is
-  used to select which directories and files get included (we will use
-  $(MACHINE) to refer to the category)
-
-  To this end, we now have arch/arm/mach-$(MACHINE) directories which are
-  designed to house the non-driver files for a particular machine (eg, PCI,
-  memory management, architecture definitions etc).  For all future
-  machines, there should be a corresponding arch/arm/mach-$(MACHINE)/include/mach
-  directory.
-
-
-Modules
--------
-
-  Although modularisation is supported (and required for the FP emulator),
-  each module on an ARM2/ARM250/ARM3 machine when is loaded will take
-  memory up to the next 32k boundary due to the size of the pages.
-  Therefore, is modularisation on these machines really worth it?
-
-  However, ARM6 and up machines allow modules to take multiples of 4k, and
-  as such Acorn RiscPCs and other architectures using these processors can
-  make good use of modularisation.
-
-
-ADFS Image files
-----------------
-
-  You can access image files on your ADFS partitions by mounting the ADFS
-  partition, and then using the loopback device driver.  You must have
-  losetup installed.
-
-  Please note that the PCEmulator DOS partitions have a partition table at
-  the start, and as such, you will have to give '-o offset' to losetup.
-
-
-Request to developers
----------------------
-
-  When writing device drivers which include a separate assembler file, please
-  include it in with the C file, and not the arch/arm/lib directory.  This
-  allows the driver to be compiled as a loadable module without requiring
-  half the code to be compiled into the kernel image.
-
-  In general, try to avoid using assembler unless it is really necessary.  It
-  makes drivers far less easy to port to other hardware.
-
-
-ST506 hard drives
------------------
-
-  The ST506 hard drive controllers seem to be working fine (if a little
-  slowly).  At the moment they will only work off the controllers on an
-  A4x0's motherboard, but for it to work off a Podule just requires
-  someone with a podule to add the addresses for the IRQ mask and the
-  HDC base to the source.
-
-  As of 31/3/96 it works with two drives (you should get the ADFS
-  *configure harddrive set to 2). I've got an internal 20MB and a great
-  big external 5.25" FH 64MB drive (who could ever want more :-) ).
-
-  I've just got 240K/s off it (a dd with bs=128k); thats about half of what
-  RiscOS gets; but it's a heck of a lot better than the 50K/s I was getting
-  last week :-)
-
-  Known bug: Drive data errors can cause a hang; including cases where
-  the controller has fixed the error using ECC. (Possibly ONLY
-  in that case...hmm).
-
-
-1772 Floppy
------------
-  This also seems to work OK, but hasn't been stressed much lately.  It
-  hasn't got any code for disc change detection in there at the moment which
-  could be a bit of a problem!  Suggestions on the correct way to do this
-  are welcome.
-
-
-CONFIG_MACH_ and CONFIG_ARCH_
------------------------------
-  A change was made in 2003 to the macro names for new machines.
-  Historically, CONFIG_ARCH_ was used for the bonafide architecture,
-  e.g. SA1100, as well as implementations of the architecture,
-  e.g. Assabet.  It was decided to change the implementation macros
-  to read CONFIG_MACH_ for clarity.  Moreover, a retroactive fixup has
-  not been made because it would complicate patching.
-
-  Previous registrations may be found online.
-
-    <http://www.arm.linux.org.uk/developer/machines/>
-
-Kernel entry (head.S)
---------------------------
-  The initial entry into the kernel is via head.S, which uses machine
-  independent code.  The machine is selected by the value of 'r1' on
-  entry, which must be kept unique.
-
-  Due to the large number of machines which the ARM port of Linux provides
-  for, we have a method to manage this which ensures that we don't end up
-  duplicating large amounts of code.
-
-  We group machine (or platform) support code into machine classes.  A
-  class typically based around one or more system on a chip devices, and
-  acts as a natural container around the actual implementations.  These
-  classes are given directories - arch/arm/mach-<class> and
-  arch/arm/mach-<class> - which contain the source files to/include/mach
-  support the machine class.  This directories also contain any machine
-  specific supporting code.
-
-  For example, the SA1100 class is based upon the SA1100 and SA1110 SoC
-  devices, and contains the code to support the way the on-board and off-
-  board devices are used, or the device is setup, and provides that
-  machine specific "personality."
-
-  For platforms that support device tree (DT), the machine selection is
-  controlled at runtime by passing the device tree blob to the kernel.  At
-  compile-time, support for the machine type must be selected.  This allows for
-  a single multiplatform kernel build to be used for several machine types.
-
-  For platforms that do not use device tree, this machine selection is
-  controlled by the machine type ID, which acts both as a run-time and a
-  compile-time code selection method.  You can register a new machine via the
-  web site at:
-
-    <http://www.arm.linux.org.uk/developer/machines/>
-
-  Note: Please do not register a machine type for DT-only platforms.  If your
-  platform is DT-only, you do not need a registered machine type.
-
----
-Russell King (15/03/2004)
diff --git a/Documentation/arm/SA1100/ADSBitsy b/Documentation/arm/SA1100/ADSBitsy
deleted file mode 100644 (file)
index f9f62e8..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-ADS Bitsy Single Board Computer
-(It is different from Bitsy(iPAQ) of Compaq)
-
-For more details, contact Applied Data Systems or see
-http://www.applieddata.net/products.html
-
-The Linux support for this product has been provided by
-Woojung Huh <whuh@applieddata.net>
-
-Use 'make adsbitsy_config' before any 'make config'.
-This will set up defaults for ADS Bitsy support.
-
-The kernel zImage is linked to be loaded and executed at 0xc0400000.
-
-Linux can  be used with the ADS BootLoader that ships with the
-newer rev boards. See their documentation on how to load Linux.
-
-Supported peripherals:
-- SA1100 LCD frame buffer (8/16bpp...sort of)
-- SA1111 USB Master
-- SA1100 serial port
-- pcmcia, compact flash
-- touchscreen(ucb1200)
-- console on LCD screen
-- serial ports (ttyS[0-2])
-  - ttyS0 is default for serial console
-
-To do:
-- everything else!  :-)
-
-Notes:
-
-- The flash on board is divided into 3 partitions.
-  You should be careful to use flash on board.
-  Its partition is different from GraphicsClient Plus and GraphicsMaster
-
-- 16bpp mode requires a different cable than what ships with the board.
-  Contact ADS or look through the manual to wire your own. Currently,
-  if you compile with 16bit mode support and switch into a lower bpp
-  mode, the timing is off so the image is corrupted.  This will be
-  fixed soon.
-
-Any contribution can be sent to nico@fluxnic.net and will be greatly welcome!
diff --git a/Documentation/arm/SA1100/Assabet b/Documentation/arm/SA1100/Assabet
deleted file mode 100644 (file)
index e08a673..0000000
+++ /dev/null
@@ -1,300 +0,0 @@
-The Intel Assabet (SA-1110 evaluation) board
-============================================
-
-Please see:
-http://developer.intel.com
-
-Also some notes from John G Dorsey <jd5q@andrew.cmu.edu>:
-http://www.cs.cmu.edu/~wearable/software/assabet.html
-
-
-Building the kernel
--------------------
-
-To build the kernel with current defaults:
-
-       make assabet_config
-       make oldconfig
-       make zImage
-
-The resulting kernel image should be available in linux/arch/arm/boot/zImage.
-
-
-Installing a bootloader
------------------------
-
-A couple of bootloaders able to boot Linux on Assabet are available:
-
-BLOB (http://www.lartmaker.nl/lartware/blob/)
-
-   BLOB is a bootloader used within the LART project.  Some contributed
-   patches were merged into BLOB to add support for Assabet.
-
-Compaq's Bootldr + John Dorsey's patch for Assabet support
-(http://www.handhelds.org/Compaq/bootldr.html)
-(http://www.wearablegroup.org/software/bootldr/)
-
-   Bootldr is the bootloader developed by Compaq for the iPAQ Pocket PC.
-   John Dorsey has produced add-on patches to add support for Assabet and
-   the JFFS filesystem.
-
-RedBoot (http://sources.redhat.com/redboot/)
-
-   RedBoot is a bootloader developed by Red Hat based on the eCos RTOS
-   hardware abstraction layer.  It supports Assabet amongst many other
-   hardware platforms.
-
-RedBoot is currently the recommended choice since it's the only one to have
-networking support, and is the most actively maintained.
-
-Brief examples on how to boot Linux with RedBoot are shown below.  But first
-you need to have RedBoot installed in your flash memory.  A known to work
-precompiled RedBoot binary is available from the following location:
-
-ftp://ftp.netwinder.org/users/n/nico/
-ftp://ftp.arm.linux.org.uk/pub/linux/arm/people/nico/
-ftp://ftp.handhelds.org/pub/linux/arm/sa-1100-patches/
-
-Look for redboot-assabet*.tgz.  Some installation infos are provided in
-redboot-assabet*.txt.
-
-
-Initial RedBoot configuration
------------------------------
-
-The commands used here are explained in The RedBoot User's Guide available
-on-line at http://sources.redhat.com/ecos/docs.html.
-Please refer to it for explanations.
-
-If you have a CF network card (my Assabet kit contained a CF+ LP-E from
-Socket Communications Inc.), you should strongly consider using it for TFTP
-file transfers.  You must insert it before RedBoot runs since it can't detect
-it dynamically.
-
-To initialize the flash directory:
-
-       fis init -f
-
-To initialize the non-volatile settings, like whether you want to use BOOTP or
-a static IP address, etc, use this command:
-
-       fconfig -i
-
-
-Writing a kernel image into flash
----------------------------------
-
-First, the kernel image must be loaded into RAM.  If you have the zImage file
-available on a TFTP server:
-
-       load zImage -r -b 0x100000
-
-If you rather want to use Y-Modem upload over the serial port:
-
-       load -m ymodem -r -b 0x100000
-
-To write it to flash:
-
-       fis create "Linux kernel" -b 0x100000 -l 0xc0000
-
-
-Booting the kernel
-------------------
-
-The kernel still requires a filesystem to boot.  A ramdisk image can be loaded
-as follows:
-
-       load ramdisk_image.gz -r -b 0x800000
-
-Again, Y-Modem upload can be used instead of TFTP by replacing the file name
-by '-y ymodem'.
-
-Now the kernel can be retrieved from flash like this:
-
-       fis load "Linux kernel"
-
-or loaded as described previously.  To boot the kernel:
-
-       exec -b 0x100000 -l 0xc0000
-
-The ramdisk image could be stored into flash as well, but there are better
-solutions for on-flash filesystems as mentioned below.
-
-
-Using JFFS2
------------
-
-Using JFFS2 (the Second Journalling Flash File System) is probably the most
-convenient way to store a writable filesystem into flash.  JFFS2 is used in
-conjunction with the MTD layer which is responsible for low-level flash
-management.  More information on the Linux MTD can be found on-line at:
-http://www.linux-mtd.infradead.org/.  A JFFS howto with some infos about
-creating JFFS/JFFS2 images is available from the same site.
-
-For instance, a sample JFFS2 image can be retrieved from the same FTP sites
-mentioned below for the precompiled RedBoot image.
-
-To load this file:
-
-       load sample_img.jffs2 -r -b 0x100000
-
-The result should look like:
-
-RedBoot> load sample_img.jffs2 -r -b 0x100000
-Raw file loaded 0x00100000-0x00377424
-
-Now we must know the size of the unallocated flash:
-
-       fis free
-
-Result:
-
-RedBoot> fis free
-  0x500E0000 .. 0x503C0000
-
-The values above may be different depending on the size of the filesystem and
-the type of flash.  See their usage below as an example and take care of
-substituting yours appropriately.
-
-We must determine some values:
-
-size of unallocated flash:     0x503c0000 - 0x500e0000 = 0x2e0000
-size of the filesystem image:  0x00377424 - 0x00100000 = 0x277424
-
-We want to fit the filesystem image of course, but we also want to give it all
-the remaining flash space as well.  To write it:
-
-       fis unlock -f 0x500E0000 -l 0x2e0000
-       fis erase -f 0x500E0000 -l 0x2e0000
-       fis write -b 0x100000 -l 0x277424 -f 0x500E0000
-       fis create "JFFS2" -n -f 0x500E0000 -l 0x2e0000
-
-Now the filesystem is associated to a MTD "partition" once Linux has discovered
-what they are in the boot process.  From Redboot, the 'fis list' command
-displays them:
-
-RedBoot> fis list
-Name              FLASH addr  Mem addr    Length      Entry point
-RedBoot           0x50000000  0x50000000  0x00020000  0x00000000
-RedBoot config    0x503C0000  0x503C0000  0x00020000  0x00000000
-FIS directory     0x503E0000  0x503E0000  0x00020000  0x00000000
-Linux kernel      0x50020000  0x00100000  0x000C0000  0x00000000
-JFFS2             0x500E0000  0x500E0000  0x002E0000  0x00000000
-
-However Linux should display something like:
-
-SA1100 flash: probing 32-bit flash bus
-SA1100 flash: Found 2 x16 devices at 0x0 in 32-bit mode
-Using RedBoot partition definition
-Creating 5 MTD partitions on "SA1100 flash":
-0x00000000-0x00020000 : "RedBoot"
-0x00020000-0x000e0000 : "Linux kernel"
-0x000e0000-0x003c0000 : "JFFS2"
-0x003c0000-0x003e0000 : "RedBoot config"
-0x003e0000-0x00400000 : "FIS directory"
-
-What's important here is the position of the partition we are interested in,
-which is the third one.  Within Linux, this correspond to /dev/mtdblock2.
-Therefore to boot Linux with the kernel and its root filesystem in flash, we
-need this RedBoot command:
-
-       fis load "Linux kernel"
-       exec -b 0x100000 -l 0xc0000 -c "root=/dev/mtdblock2"
-
-Of course other filesystems than JFFS might be used, like cramfs for example.
-You might want to boot with a root filesystem over NFS, etc.  It is also
-possible, and sometimes more convenient, to flash a filesystem directly from
-within Linux while booted from a ramdisk or NFS.  The Linux MTD repository has
-many tools to deal with flash memory as well, to erase it for example.  JFFS2
-can then be mounted directly on a freshly erased partition and files can be
-copied over directly.  Etc...
-
-
-RedBoot scripting
------------------
-
-All the commands above aren't so useful if they have to be typed in every
-time the Assabet is rebooted.  Therefore it's possible to automate the boot
-process using RedBoot's scripting capability.
-
-For example, I use this to boot Linux with both the kernel and the ramdisk
-images retrieved from a TFTP server on the network:
-
-RedBoot> fconfig
-Run script at boot: false true
-Boot script:
-Enter script, terminate with empty line
->> load zImage -r -b 0x100000
->> load ramdisk_ks.gz -r -b 0x800000
->> exec -b 0x100000 -l 0xc0000
->>
-Boot script timeout (1000ms resolution): 3
-Use BOOTP for network configuration: true
-GDB connection port: 9000
-Network debug at boot time: false
-Update RedBoot non-volatile configuration - are you sure (y/n)? y
-
-Then, rebooting the Assabet is just a matter of waiting for the login prompt.
-
-
-
-Nicolas Pitre
-nico@fluxnic.net
-June 12, 2001
-
-
-Status of peripherals in -rmk tree (updated 14/10/2001)
--------------------------------------------------------
-
-Assabet:
- Serial ports:
-  Radio:               TX, RX, CTS, DSR, DCD, RI
-   PM:                 Not tested.
-  COM:                 TX, RX, CTS, DSR, DCD, RTS, DTR, PM
-   PM:                 Not tested.
-  I2C:                 Implemented, not fully tested.
-  L3:                  Fully tested, pass.
-   PM:                 Not tested.
-
- Video:
-  LCD:                 Fully tested.  PM
-                       (LCD doesn't like being blanked with
-                        neponset connected)
-  Video out:           Not fully
-
- Audio:
-  UDA1341:
-   Playback:           Fully tested, pass.
-   Record:             Implemented, not tested.
-   PM:                 Not tested.
-
-  UCB1200:
-   Audio play:         Implemented, not heavily tested.
-   Audio rec:          Implemented, not heavily tested.
-   Telco audio play:   Implemented, not heavily tested.
-   Telco audio rec:    Implemented, not heavily tested.
-   POTS control:       No
-   Touchscreen:                Yes
-   PM:                 Not tested.
-
- Other:
-  PCMCIA:
-   LPE:                        Fully tested, pass.
-  USB:                 No
-  IRDA:
-   SIR:                        Fully tested, pass.
-   FIR:                        Fully tested, pass.
-   PM:                 Not tested.
-
-Neponset:
- Serial ports:
-  COM1,2:      TX, RX, CTS, DSR, DCD, RTS, DTR
-   PM:                 Not tested.
-  USB:                 Implemented, not heavily tested.
-  PCMCIA:              Implemented, not heavily tested.
-   PM:                 Not tested.
-  CF:                  Implemented, not heavily tested.
-   PM:                 Not tested.
-
-More stuff can be found in the -np (Nicolas Pitre's) tree.
-
diff --git a/Documentation/arm/SA1100/Brutus b/Documentation/arm/SA1100/Brutus
deleted file mode 100644 (file)
index 6a3aa95..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-Brutus is an evaluation platform for the SA1100 manufactured by Intel.  
-For more details, see:
-
-http://developer.intel.com
-
-To compile for Brutus, you must issue the following commands:
-
-       make brutus_config
-       make config
-       [accept all the defaults]
-       make zImage
-
-The resulting kernel will end up in linux/arch/arm/boot/zImage.  This file
-must be loaded at 0xc0008000 in Brutus's memory and execution started at
-0xc0008000 as well with the value of registers r0 = 0 and r1 = 16 upon
-entry.
-
-But prior to execute the kernel, a ramdisk image must also be loaded in
-memory.  Use memory address 0xd8000000 for this.  Note that the file 
-containing the (compressed) ramdisk image must not exceed 4 MB.
-
-Typically, you'll need angelboot to load the kernel.
-The following angelboot.opt file should be used:
-
------ begin angelboot.opt -----
-base 0xc0008000
-entry 0xc0008000
-r0 0x00000000
-r1 0x00000010
-device /dev/ttyS0
-options "9600 8N1"
-baud 115200
-otherfile ramdisk_img.gz
-otherbase 0xd8000000
------ end angelboot.opt -----
-
-Then load the kernel and ramdisk with:
-
-       angelboot -f angelboot.opt zImage
-
-The first Brutus serial port (assumed to be linked to /dev/ttyS0 on your
-host PC) is used by angel to load the kernel and ramdisk image. The serial
-console is provided through the second Brutus serial port. To access it,
-you may use minicom configured with /dev/ttyS1, 9600 baud, 8N1, no flow
-control.
-
-Currently supported:
-       - RS232 serial ports
-       - audio output
-       - LCD screen
-       - keyboard
-       
-The actual Brutus support may not be complete without extra patches. 
-If such patches exist, they should be found from 
-ftp.netwinder.org/users/n/nico.
-
-A full PCMCIA support is still missing, although it's possible to hack
-some drivers in order to drive already inserted cards at boot time with
-little modifications.
-
-Any contribution is welcome.
-
-Please send patches to nico@fluxnic.net
-
-Have Fun !
-
diff --git a/Documentation/arm/SA1100/CERF b/Documentation/arm/SA1100/CERF
deleted file mode 100644 (file)
index b3d8453..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-*** The StrongARM version of the CerfBoard/Cube has been discontinued ***
-
-The Intrinsyc CerfBoard is a StrongARM 1110-based computer on a board
-that measures approximately 2" square. It includes an Ethernet
-controller, an RS232-compatible serial port, a USB function port, and
-one CompactFlash+ slot on the back. Pictures can be found at the
-Intrinsyc website, http://www.intrinsyc.com.
-
-This document describes the support in the Linux kernel for the
-Intrinsyc CerfBoard.
-
-Supported in this version:
-   - CompactFlash+ slot (select PCMCIA in General Setup and any options
-     that may be required)
-   - Onboard Crystal CS8900 Ethernet controller (Cerf CS8900A support in
-     Network Devices)
-   - Serial ports with a serial console (hardcoded to 38400 8N1)
-
-In order to get this kernel onto your Cerf, you need a server that runs
-both BOOTP and TFTP. Detailed instructions should have come with your
-evaluation kit on how to use the bootloader. This series of commands
-will suffice:
-
-   make ARCH=arm CROSS_COMPILE=arm-linux- cerfcube_defconfig
-   make ARCH=arm CROSS_COMPILE=arm-linux- zImage
-   make ARCH=arm CROSS_COMPILE=arm-linux- modules
-   cp arch/arm/boot/zImage <TFTP directory>
-
-support@intrinsyc.com
diff --git a/Documentation/arm/SA1100/FreeBird b/Documentation/arm/SA1100/FreeBird
deleted file mode 100644 (file)
index ab91936..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-Freebird-1.1 is produced by Legend(C), Inc.
-http://web.archive.org/web/*/http://www.legend.com.cn
-and software/linux maintained by Coventive(C), Inc.
-(http://www.coventive.com)
-
-Based on the Nicolas's strongarm kernel tree.
-
-===============================================================
-Maintainer:
-
-Chester Kuo <chester@coventive.com>
-           <chester@linux.org.tw>
-
-Author :
-Tim wu <timwu@coventive.com>
-CIH <cih@coventive.com>
-Eric Peng <ericpeng@coventive.com>
-Jeff Lee <jeff_lee@coventive.com>
-Allen Cheng
-Tony Liu <tonyliu@coventive.com>
-
diff --git a/Documentation/arm/SA1100/GraphicsClient b/Documentation/arm/SA1100/GraphicsClient
deleted file mode 100644 (file)
index 867bb35..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-ADS GraphicsClient Plus Single Board Computer
-
-For more details, contact Applied Data Systems or see
-http://www.applieddata.net/products.html
-
-The original Linux support for this product has been provided by 
-Nicolas Pitre <nico@fluxnic.net>. Continued development work by
-Woojung Huh <whuh@applieddata.net>
-
-It's currently possible to mount a root filesystem via NFS providing a
-complete Linux environment.  Otherwise a ramdisk image may be used.  The
-board supports MTD/JFFS, so you could also mount something on there.
-
-Use 'make graphicsclient_config' before any 'make config'.  This will set up
-defaults for GraphicsClient Plus support.
-
-The kernel zImage is linked to be loaded and executed at 0xc0200000.  
-Also the following registers should have the specified values upon entry:
-
-       r0 = 0
-       r1 = 29 (this is the GraphicsClient architecture number)
-
-Linux can  be used with the ADS BootLoader that ships with the
-newer rev boards. See their documentation on how to load Linux.
-Angel is not available for the GraphicsClient Plus AFAIK.
-
-There is a  board known as just the GraphicsClient that ADS used to
-produce but has end of lifed. This code will not work on the older
-board with the ADS bootloader, but should still work with Angel,
-as outlined below.  In any case, if you're planning on deploying
-something en masse, you should probably get the newer board.
-
-If using Angel on the older boards, here is a typical angel.opt option file
-if the kernel is loaded through the Angel Debug Monitor:
-
------ begin angelboot.opt -----
-base 0xc0200000
-entry 0xc0200000
-r0 0x00000000
-r1 0x0000001d
-device /dev/ttyS1
-options "38400 8N1"
-baud 115200
-#otherfile ramdisk.gz
-#otherbase 0xc0800000
-exec minicom
------ end angelboot.opt -----
-
-Then the kernel (and ramdisk if otherfile/otherbase lines above are
-uncommented) would be loaded with:
-
-       angelboot -f angelboot.opt zImage
-
-Here it is assumed that the board is connected to ttyS1 on your PC
-and that minicom is preconfigured with /dev/ttyS1, 38400 baud, 8N1, no flow
-control by default.
-
-If any other bootloader is used, ensure it accomplish the same, especially
-for r0/r1 register values before jumping into the kernel.
-
-
-Supported peripherals:
-- SA1100 LCD frame buffer (8/16bpp...sort of)
-- on-board SMC 92C96 ethernet NIC
-- SA1100 serial port
-- flash memory access (MTD/JFFS)
-- pcmcia
-- touchscreen(ucb1200)
-- ps/2 keyboard
-- console on LCD screen
-- serial ports (ttyS[0-2])
-  - ttyS0 is default for serial console
-- Smart I/O (ADC, keypad, digital inputs, etc)
-  See http://www.eurotech-inc.com/linux-sbc.asp for IOCTL documentation
-  and example user space code. ps/2 keybd is multiplexed through this driver
-
-To do:
-- UCB1200 audio with new ucb_generic layer
-- everything else!  :-)
-
-Notes:
-
-- The flash on board is divided into 3 partitions.  mtd0 is where
-  the ADS boot ROM and zImage is stored.  It's been marked as
-  read-only to keep you from blasting over the bootloader. :)  mtd1 is
-  for the ramdisk.gz image.  mtd2 is user flash space and can be
-  utilized for either JFFS or if you're feeling crazy, running ext2
-  on top of it. If you're not using the ADS bootloader, you're
-  welcome to blast over the mtd1 partition also.
-
-- 16bpp mode requires a different cable than what ships with the board.
-  Contact ADS or look through the manual to wire your own. Currently,
-  if you compile with 16bit mode support and switch into a lower bpp
-  mode, the timing is off so the image is corrupted.  This will be
-  fixed soon.
-
-Any contribution can be sent to nico@fluxnic.net and will be greatly welcome!
-
diff --git a/Documentation/arm/SA1100/GraphicsMaster b/Documentation/arm/SA1100/GraphicsMaster
deleted file mode 100644 (file)
index 9145088..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-ADS GraphicsMaster Single Board Computer
-
-For more details, contact Applied Data Systems or see
-http://www.applieddata.net/products.html
-
-The original Linux support for this product has been provided by
-Nicolas Pitre <nico@fluxnic.net>. Continued development work by
-Woojung Huh <whuh@applieddata.net>
-
-Use 'make graphicsmaster_config' before any 'make config'.
-This will set up defaults for GraphicsMaster support.
-
-The kernel zImage is linked to be loaded and executed at 0xc0400000.
-
-Linux can  be used with the ADS BootLoader that ships with the
-newer rev boards. See their documentation on how to load Linux.
-
-Supported peripherals:
-- SA1100 LCD frame buffer (8/16bpp...sort of)
-- SA1111 USB Master
-- on-board SMC 92C96 ethernet NIC
-- SA1100 serial port
-- flash memory access (MTD/JFFS)
-- pcmcia, compact flash
-- touchscreen(ucb1200)
-- ps/2 keyboard
-- console on LCD screen
-- serial ports (ttyS[0-2])
-  - ttyS0 is default for serial console
-- Smart I/O (ADC, keypad, digital inputs, etc)
-  See http://www.eurotech-inc.com/linux-sbc.asp for IOCTL documentation
-  and example user space code. ps/2 keybd is multiplexed through this driver
-
-To do:
-- everything else!  :-)
-
-Notes:
-
-- The flash on board is divided into 3 partitions.  mtd0 is where
-  the zImage is stored.  It's been marked as read-only to keep you
-  from blasting over the bootloader. :)  mtd1 is
-  for the ramdisk.gz image.  mtd2 is user flash space and can be
-  utilized for either JFFS or if you're feeling crazy, running ext2
-  on top of it. If you're not using the ADS bootloader, you're
-  welcome to blast over the mtd1 partition also.
-
-- 16bpp mode requires a different cable than what ships with the board.
-  Contact ADS or look through the manual to wire your own. Currently,
-  if you compile with 16bit mode support and switch into a lower bpp
-  mode, the timing is off so the image is corrupted.  This will be
-  fixed soon.
-
-Any contribution can be sent to nico@fluxnic.net and will be greatly welcome!
diff --git a/Documentation/arm/SA1100/HUW_WEBPANEL b/Documentation/arm/SA1100/HUW_WEBPANEL
deleted file mode 100644 (file)
index fd56b48..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-The HUW_WEBPANEL is a product of the german company Hoeft & Wessel AG
-
-If you want more information, please visit
-http://www.hoeft-wessel.de
-
-To build the kernel:
-       make huw_webpanel_config
-       make oldconfig
-       [accept all defaults]
-       make zImage
-
-Mostly of the work is done by:
-Roman Jordan         jor@hoeft-wessel.de
-Christoph Schulz    schu@hoeft-wessel.de
-
-2000/12/18/
-
diff --git a/Documentation/arm/SA1100/Itsy b/Documentation/arm/SA1100/Itsy
deleted file mode 100644 (file)
index 44b9499..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-Itsy is a research project done by the Western Research Lab, and Systems
-Research Center in Palo Alto, CA. The Itsy project is one of several
-research projects at Compaq that are related to pocket computing.
-
-For more information, see:
-
-       http://www.hpl.hp.com/downloads/crl/itsy/
-
-Notes on initial 2.4 Itsy support (8/27/2000) :
-The port was done on an Itsy version 1.5 machine with a daughtercard with
-64 Meg of DRAM and 32 Meg of Flash. The initial work includes support for
-serial console (to see what you're doing).  No other devices have been
-enabled.
-
-To build, do a "make menuconfig" (or xmenuconfig) and select Itsy support.
-Disable Flash and LCD support. and then do a make zImage.
-Finally, you will need to cd to arch/arm/boot/tools and execute a make there
-to build the params-itsy program used to boot the kernel.
-
-In order to install the port of 2.4 to the itsy, You will need to set the
-configuration parameters in the monitor as follows:
-Arg 1:0x08340000, Arg2: 0xC0000000, Arg3:18 (0x12), Arg4:0
-Make sure the start-routine address is set to 0x00060000.
-
-Next, flash the params-itsy program to 0x00060000 ("p 1 0x00060000" in the
-flash menu)  Flash the kernel in arch/arm/boot/zImage into 0x08340000
-("p 1 0x00340000").  Finally flash an initial ramdisk into 0xC8000000
-("p 2 0x0")  We used ramdisk-2-30.gz from the 0.11 version directory on
-handhelds.org.
-
-The serial connection we established was at:
- 8-bit data, no parity, 1 stop bit(s), 115200.00 b/s. in the monitor, in the
-params-itsy program, and in the kernel itself.  This can be changed, but
-not easily. The monitor parameters are easily changed, the params program
-setup is assembly outl's, and the kernel is a configuration item specific to
-the itsy. (i.e. grep for CONFIG_SA1100_ITSY and you'll find where it is.)
-
-
-This should get you a properly booting 2.4 kernel on the itsy.
diff --git a/Documentation/arm/SA1100/LART b/Documentation/arm/SA1100/LART
deleted file mode 100644 (file)
index 6d412b6..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-Linux Advanced Radio Terminal (LART)
-------------------------------------
-
-The LART is a small (7.5 x 10cm) SA-1100 board, designed for embedded
-applications. It has 32 MB DRAM, 4MB Flash ROM, double RS232 and all
-other StrongARM-gadgets. Almost all SA signals are directly accessible
-through a number of connectors. The powersupply accepts voltages
-between 3.5V and 16V and is overdimensioned to support a range of
-daughterboards. A quad Ethernet / IDE / PS2 / sound daughterboard
-is under development, with plenty of others in different stages of
-planning.
-
-The hardware designs for this board have been released under an open license;
-see the LART page at http://www.lartmaker.nl/ for more information.
diff --git a/Documentation/arm/SA1100/PLEB b/Documentation/arm/SA1100/PLEB
deleted file mode 100644 (file)
index b9c8a63..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-The PLEB project was started as a student initiative at the School of
-Computer Science and Engineering, University of New South Wales to make a
-pocket computer capable of running the Linux Kernel.
-
-PLEB support has yet to be fully integrated.
-
-For more information, see:
-
-       http://www.cse.unsw.edu.au
-
-
diff --git a/Documentation/arm/SA1100/Pangolin b/Documentation/arm/SA1100/Pangolin
deleted file mode 100644 (file)
index 077a612..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-Pangolin is a StrongARM 1110-based evaluation platform produced
-by Dialogue Technology (http://www.dialogue.com.tw/).
-It has EISA slots for ease of configuration with SDRAM/Flash
-memory card, USB/Serial/Audio card, Compact Flash card,
-PCMCIA/IDE card and TFT-LCD card.
-
-To compile for Pangolin, you must issue the following commands:
-
-       make pangolin_config
-       make oldconfig
-       make zImage
-
-Supported peripherals:
-- SA1110 serial port (UART1/UART2/UART3)
-- flash memory access
-- compact flash driver
-- UDA1341 sound driver
-- SA1100 LCD controller for 800x600 16bpp TFT-LCD
-- MQ-200 driver for 800x600 16bpp TFT-LCD
-- Penmount(touch panel) driver
-- PCMCIA driver
-- SMC91C94 LAN driver
-- IDE driver (experimental)
diff --git a/Documentation/arm/SA1100/Tifon b/Documentation/arm/SA1100/Tifon
deleted file mode 100644 (file)
index dd1934d..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Tifon
------
-
-More info has to come...
-
-Contact: Peter Danielsson <peter.danielsson@era-t.ericsson.se>
-
diff --git a/Documentation/arm/SA1100/Yopy b/Documentation/arm/SA1100/Yopy
deleted file mode 100644 (file)
index e14f16d..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-See http://www.yopydeveloper.org for more.
-
diff --git a/Documentation/arm/SA1100/empeg b/Documentation/arm/SA1100/empeg
deleted file mode 100644 (file)
index 4ece484..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-See ../empeg/README
-
diff --git a/Documentation/arm/SA1100/nanoEngine b/Documentation/arm/SA1100/nanoEngine
deleted file mode 100644 (file)
index 48a7934..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-nanoEngine
-----------
-
-"nanoEngine" is a SA1110 based single board computer from 
-Bright Star Engineering Inc.  See www.brightstareng.com/arm
-for more info.
-(Ref: Stuart Adams <sja@brightstareng.com>)
-
-Also visit Larry Doolittle's "Linux for the nanoEngine" site:
-http://www.brightstareng.com/arm/nanoeng.htm
-
diff --git a/Documentation/arm/SA1100/serial_UART b/Documentation/arm/SA1100/serial_UART
deleted file mode 100644 (file)
index a63966f..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-The SA1100 serial port had its major/minor numbers officially assigned:
-
-> Date: Sun, 24 Sep 2000 21:40:27 -0700
-> From: H. Peter Anvin <hpa@transmeta.com>
-> To: Nicolas Pitre <nico@CAM.ORG>
-> Cc: Device List Maintainer <device@lanana.org>
-> Subject: Re: device
-> 
-> Okay.  Note that device numbers 204 and 205 are used for "low density
-> serial devices", so you will have a range of minors on those majors (the
-> tty device layer handles this just fine, so you don't have to worry about
-> doing anything special.)
-> 
-> So your assignments are:
-> 
-> 204 char        Low-density serial ports
->                   5 = /dev/ttySA0               SA1100 builtin serial port 0
->                   6 = /dev/ttySA1               SA1100 builtin serial port 1
->                   7 = /dev/ttySA2               SA1100 builtin serial port 2
-> 
-> 205 char        Low-density serial ports (alternate device)
->                   5 = /dev/cusa0                Callout device for ttySA0
->                   6 = /dev/cusa1                Callout device for ttySA1
->                   7 = /dev/cusa2                Callout device for ttySA2
->
-
-You must create those inodes in /dev on the root filesystem used
-by your SA1100-based device:
-
-       mknod ttySA0 c 204 5
-       mknod ttySA1 c 204 6
-       mknod ttySA2 c 204 7
-       mknod cusa0 c 205 5
-       mknod cusa1 c 205 6
-       mknod cusa2 c 205 7
-
-In addition to the creation of the appropriate device nodes above, you
-must ensure your user space applications make use of the correct device
-name. The classic example is the content of the /etc/inittab file where
-you might have a getty process started on ttyS0.  In this case:
-
-- replace occurrences of ttyS0 with ttySA0, ttyS1 with ttySA1, etc.
-
-- don't forget to add 'ttySA0', 'console', or the appropriate tty name
-  in /etc/securetty for root to be allowed to login as well.
-
-
diff --git a/Documentation/arm/SPEAr/overview.txt b/Documentation/arm/SPEAr/overview.txt
deleted file mode 100644 (file)
index 1b049be..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-                       SPEAr ARM Linux Overview
-                       ==========================
-
-Introduction
-------------
-
-  SPEAr (Structured Processor Enhanced Architecture).
-  weblink : http://www.st.com/spear
-
-  The ST Microelectronics SPEAr range of ARM9/CortexA9 System-on-Chip CPUs are
-  supported by the 'spear' platform of ARM Linux. Currently SPEAr1310,
-  SPEAr1340, SPEAr300, SPEAr310, SPEAr320 and SPEAr600 SOCs are supported.
-
-  Hierarchy in SPEAr is as follows:
-
-  SPEAr (Platform)
-       - SPEAr3XX (3XX SOC series, based on ARM9)
-               - SPEAr300 (SOC)
-                       - SPEAr300 Evaluation Board
-               - SPEAr310 (SOC)
-                       - SPEAr310 Evaluation Board
-               - SPEAr320 (SOC)
-                       - SPEAr320 Evaluation Board
-       - SPEAr6XX (6XX SOC series, based on ARM9)
-               - SPEAr600 (SOC)
-                       - SPEAr600 Evaluation Board
-       - SPEAr13XX (13XX SOC series, based on ARM CORTEXA9)
-               - SPEAr1310 (SOC)
-                       - SPEAr1310 Evaluation Board
-               - SPEAr1340 (SOC)
-                       - SPEAr1340 Evaluation Board
-
-  Configuration
-  -------------
-
-  A generic configuration is provided for each machine, and can be used as the
-  default by
-       make spear13xx_defconfig
-       make spear3xx_defconfig
-       make spear6xx_defconfig
-
-  Layout
-  ------
-
-  The common files for multiple machine families (SPEAr3xx, SPEAr6xx and
-  SPEAr13xx) are located in the platform code contained in arch/arm/plat-spear
-  with headers in plat/.
-
-  Each machine series have a directory with name arch/arm/mach-spear followed by
-  series name. Like mach-spear3xx, mach-spear6xx and mach-spear13xx.
-
-  Common file for machines of spear3xx family is mach-spear3xx/spear3xx.c, for
-  spear6xx is mach-spear6xx/spear6xx.c and for spear13xx family is
-  mach-spear13xx/spear13xx.c. mach-spear* also contain soc/machine specific
-  files, like spear1310.c, spear1340.c spear300.c, spear310.c, spear320.c and
-  spear600.c.  mach-spear* doesn't contains board specific files as they fully
-  support Flattened Device Tree.
-
-
-  Document Author
-  ---------------
-
-  Viresh Kumar <vireshk@kernel.org>, (c) 2010-2012 ST Microelectronics
diff --git a/Documentation/arm/Samsung-S3C24XX/CPUfreq.txt b/Documentation/arm/Samsung-S3C24XX/CPUfreq.txt
deleted file mode 100644 (file)
index fa968aa..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-               S3C24XX CPUfreq support
-               =======================
-
-Introduction
-------------
-
- The S3C24XX series support a number of power saving systems, such as
- the ability to change the core, memory and peripheral operating
- frequencies. The core control is exported via the CPUFreq driver
- which has a number of different manual or automatic controls over the
- rate the core is running at.
-
- There are two forms of the driver depending on the specific CPU and
- how the clocks are arranged. The first implementation used as single
- PLL to feed the ARM, memory and peripherals via a series of dividers
- and muxes and this is the implementation that is documented here. A
- newer version where there is a separate PLL and clock divider for the
- ARM core is available as a separate driver.
-
-
-Layout
-------
-
- The code core manages the CPU specific drivers, any data that they
- need to register and the interface to the generic drivers/cpufreq
- system. Each CPU registers a driver to control the PLL, clock dividers
- and anything else associated with it. Any board that wants to use this
- framework needs to supply at least basic details of what is required.
-
- The core registers with drivers/cpufreq at init time if all the data
- necessary has been supplied.
-
-
-CPU support
------------
-
- The support for each CPU depends on the facilities provided by the
- SoC and the driver as each device has different PLL and clock chains
- associated with it.
-
-
-Slow Mode
----------
-
- The SLOW mode where the PLL is turned off altogether and the
- system is fed by the external crystal input is currently not
- supported.
-
-
-sysfs
------
-
- The core code exports extra information via sysfs in the directory
- devices/system/cpu/cpu0/arch-freq.
-
-
-Board Support
--------------
-
- Each board that wants to use the cpufreq code must register some basic
- information with the core driver to provide information about what the
- board requires and any restrictions being placed on it.
-
- The board needs to supply information about whether it needs the IO bank
- timings changing, any maximum frequency limits and information about the
- SDRAM refresh rate.
-
-
-
-
-Document Author
----------------
-
-Ben Dooks, Copyright 2009 Simtec Electronics
-Licensed under GPLv2
diff --git a/Documentation/arm/Samsung-S3C24XX/EB2410ITX.txt b/Documentation/arm/Samsung-S3C24XX/EB2410ITX.txt
deleted file mode 100644 (file)
index b87292e..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-               Simtec Electronics EB2410ITX (BAST)
-               ===================================
-
-       http://www.simtec.co.uk/products/EB2410ITX/
-
-Introduction
-------------
-
-  The EB2410ITX is a S3C2410 based development board with a variety of
-  peripherals and expansion connectors. This board is also known by
-  the shortened name of Bast.
-
-
-Configuration
--------------
-
-  To set the default configuration, use `make bast_defconfig` which
-  supports the commonly used features of this board.
-
-
-Support
--------
-
-  Official support information can be found on the Simtec Electronics
-  website, at the product page http://www.simtec.co.uk/products/EB2410ITX/
-
-  Useful links:
-
-    - Resources Page http://www.simtec.co.uk/products/EB2410ITX/resources.html
-
-    - Board FAQ at http://www.simtec.co.uk/products/EB2410ITX/faq.html
-
-    - Bootloader info http://www.simtec.co.uk/products/SWABLE/resources.html
-      and FAQ http://www.simtec.co.uk/products/SWABLE/faq.html
-
-
-MTD
----
-
-  The NAND and NOR support has been merged from the linux-mtd project.
-  Any problems, see http://www.linux-mtd.infradead.org/ for more
-  information or up-to-date versions of linux-mtd.
-
-
-IDE
----
-
-  Both onboard IDE ports are supported, however there is no support for
-  changing speed of devices, PIO Mode 4 capable drives should be used.
-
-
-Maintainers
------------
-
-  This board is maintained by Simtec Electronics.
-
-
-Copyright 2004 Ben Dooks, Simtec Electronics
diff --git a/Documentation/arm/Samsung-S3C24XX/GPIO.txt b/Documentation/arm/Samsung-S3C24XX/GPIO.txt
deleted file mode 100644 (file)
index e8f918b..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-                       S3C24XX GPIO Control
-                       ====================
-
-Introduction
-------------
-
-  The s3c2410 kernel provides an interface to configure and
-  manipulate the state of the GPIO pins, and find out other
-  information about them.
-
-  There are a number of conditions attached to the configuration
-  of the s3c2410 GPIO system, please read the Samsung provided
-  data-sheet/users manual to find out the complete list.
-
-  See Documentation/arm/Samsung/GPIO.txt for the core implementation.
-
-
-GPIOLIB
--------
-
-  With the event of the GPIOLIB in drivers/gpio, support for some
-  of the GPIO functions such as reading and writing a pin will
-  be removed in favour of this common access method.
-
-  Once all the extant drivers have been converted, the functions
-  listed below will be removed (they may be marked as __deprecated
-  in the near future).
-
-  The following functions now either have a s3c_ specific variant
-  or are merged into gpiolib. See the definitions in
-  arch/arm/plat-samsung/include/plat/gpio-cfg.h:
-
-  s3c2410_gpio_setpin()                gpio_set_value() or gpio_direction_output()
-  s3c2410_gpio_getpin()                gpio_get_value() or gpio_direction_input()
-  s3c2410_gpio_getirq()                gpio_to_irq()
-  s3c2410_gpio_cfgpin()                s3c_gpio_cfgpin()
-  s3c2410_gpio_getcfg()                s3c_gpio_getcfg()
-  s3c2410_gpio_pullup()                s3c_gpio_setpull()
-
-
-GPIOLIB conversion
-------------------
-
-If you need to convert your board or driver to use gpiolib from the phased
-out s3c2410 API, then here are some notes on the process.
-
-1) If your board is exclusively using an GPIO, say to control peripheral
-   power, then it will require to claim the gpio with gpio_request() before
-   it can use it.
-
-   It is recommended to check the return value, with at least WARN_ON()
-   during initialisation.
-
-2) The s3c2410_gpio_cfgpin() can be directly replaced with s3c_gpio_cfgpin()
-   as they have the same arguments, and can either take the pin specific
-   values, or the more generic special-function-number arguments.
-
-3) s3c2410_gpio_pullup() changes have the problem that while the
-   s3c2410_gpio_pullup(x, 1) can be easily translated to the
-   s3c_gpio_setpull(x, S3C_GPIO_PULL_NONE), the s3c2410_gpio_pullup(x, 0)
-   are not so easy.
-
-   The s3c2410_gpio_pullup(x, 0) case enables the pull-up (or in the case
-   of some of the devices, a pull-down) and as such the new API distinguishes
-   between the UP and DOWN case. There is currently no 'just turn on' setting
-   which may be required if this becomes a problem.
-
-4) s3c2410_gpio_setpin() can be replaced by gpio_set_value(), the old call
-   does not implicitly configure the relevant gpio to output. The gpio
-   direction should be changed before using gpio_set_value().
-
-5) s3c2410_gpio_getpin() is replaceable by gpio_get_value() if the pin
-   has been set to input. It is currently unknown what the behaviour is
-   when using gpio_get_value() on an output pin (s3c2410_gpio_getpin
-   would return the value the pin is supposed to be outputting).
-
-6) s3c2410_gpio_getirq() should be directly replaceable with the
-   gpio_to_irq() call.
-
-The s3c2410_gpio and gpio_ calls have always operated on the same gpio
-numberspace, so there is no problem with converting the gpio numbering
-between the calls.
-
-
-Headers
--------
-
-  See arch/arm/mach-s3c24xx/include/mach/regs-gpio.h for the list
-  of GPIO pins, and the configuration values for them. This
-  is included by using #include <mach/regs-gpio.h>
-
-
-PIN Numbers
------------
-
-  Each pin has an unique number associated with it in regs-gpio.h,
-  e.g. S3C2410_GPA(0) or S3C2410_GPF(1). These defines are used to tell
-  the GPIO functions which pin is to be used.
-
-  With the conversion to gpiolib, there is no longer a direct conversion
-  from gpio pin number to register base address as in earlier kernels. This
-  is due to the number space required for newer SoCs where the later
-  GPIOs are not contiguous.
-
-
-Configuring a pin
------------------
-
-  The following function allows the configuration of a given pin to
-  be changed.
-
-    void s3c_gpio_cfgpin(unsigned int pin, unsigned int function);
-
-  e.g.:
-
-     s3c_gpio_cfgpin(S3C2410_GPA(0), S3C_GPIO_SFN(1));
-     s3c_gpio_cfgpin(S3C2410_GPE(8), S3C_GPIO_SFN(2));
-
-   which would turn GPA(0) into the lowest Address line A0, and set
-   GPE(8) to be connected to the SDIO/MMC controller's SDDAT1 line.
-
-
-Reading the current configuration
----------------------------------
-
-  The current configuration of a pin can be read by using standard
-  gpiolib function:
-
-  s3c_gpio_getcfg(unsigned int pin);
-
-  The return value will be from the same set of values which can be
-  passed to s3c_gpio_cfgpin().
-
-
-Configuring a pull-up resistor
-------------------------------
-
-  A large proportion of the GPIO pins on the S3C2410 can have weak
-  pull-up resistors enabled. This can be configured by the following
-  function:
-
-    void s3c_gpio_setpull(unsigned int pin, unsigned int to);
-
-  Where the to value is S3C_GPIO_PULL_NONE to set the pull-up off,
-  and S3C_GPIO_PULL_UP to enable the specified pull-up. Any other
-  values are currently undefined.
-
-
-Getting and setting the state of a PIN
---------------------------------------
-
-  These calls are now implemented by the relevant gpiolib calls, convert
-  your board or driver to use gpiolib.
-
-
-Getting the IRQ number associated with a PIN
---------------------------------------------
-
-  A standard gpiolib function can map the given pin number to an IRQ
-  number to pass to the IRQ system.
-
-   int gpio_to_irq(unsigned int pin);
-
-  Note, not all pins have an IRQ.
-
-
-Author
--------
-
-Ben Dooks, 03 October 2004
-Copyright 2004 Ben Dooks, Simtec Electronics
diff --git a/Documentation/arm/Samsung-S3C24XX/H1940.txt b/Documentation/arm/Samsung-S3C24XX/H1940.txt
deleted file mode 100644 (file)
index b738859..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-               HP IPAQ H1940
-               =============
-
-http://www.handhelds.org/projects/h1940.html
-
-Introduction
-------------
-
-  The HP H1940 is a S3C2410 based handheld device, with
-  bluetooth connectivity.
-
-
-Support
--------
-
-  A variety of information is available
-
-  handhelds.org project page:
-
-    http://www.handhelds.org/projects/h1940.html
-
-  handhelds.org wiki page:
-
-    http://handhelds.org/moin/moin.cgi/HpIpaqH1940
-
-  Herbert Pötzl pages:
-
-    http://vserver.13thfloor.at/H1940/
-
-
-Maintainers
------------
-
-  This project is being maintained and developed by a variety
-  of people, including Ben Dooks, Arnaud Patard, and Herbert Pötzl.
-
-  Thanks to the many others who have also provided support.
-
-
-(c) 2005 Ben Dooks
diff --git a/Documentation/arm/Samsung-S3C24XX/NAND.txt b/Documentation/arm/Samsung-S3C24XX/NAND.txt
deleted file mode 100644 (file)
index bc478a3..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-                       S3C24XX NAND Support
-                       ====================
-
-Introduction
-------------
-
-Small Page NAND
----------------
-
-The driver uses a 512 byte (1 page) ECC code for this setup. The
-ECC code is not directly compatible with the default kernel ECC
-code, so the driver enforces its own OOB layout and ECC parameters
-
-Large Page NAND
----------------
-
-The driver is capable of handling NAND flash with a 2KiB page
-size, with support for hardware ECC generation and correction.
-
-Unlike the 512byte page mode, the driver generates ECC data for
-each 256 byte block in an 2KiB page. This means that more than
-one error in a page can be rectified. It also means that the
-OOB layout remains the default kernel layout for these flashes.
-
-
-Document Author
----------------
-
-Ben Dooks, Copyright 2007 Simtec Electronics
-
diff --git a/Documentation/arm/Samsung-S3C24XX/Overview.txt b/Documentation/arm/Samsung-S3C24XX/Overview.txt
deleted file mode 100644 (file)
index 00d3c31..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-                       S3C24XX ARM Linux Overview
-                       ==========================
-
-
-
-Introduction
-------------
-
-  The Samsung S3C24XX range of ARM9 System-on-Chip CPUs are supported
-  by the 's3c2410' architecture of ARM Linux. Currently the S3C2410,
-  S3C2412, S3C2413, S3C2416, S3C2440, S3C2442, S3C2443 and S3C2450 devices
-  are supported.
-
-  Support for the S3C2400 and S3C24A0 series was never completed and the
-  corresponding code has been removed after a while.  If someone wishes to
-  revive this effort, partial support can be retrieved from earlier Linux
-  versions.
-
-  The S3C2416 and S3C2450 devices are very similar and S3C2450 support is
-  included under the arch/arm/mach-s3c2416 directory. Note, while core
-  support for these SoCs is in, work on some of the extra peripherals
-  and extra interrupts is still ongoing.
-
-
-Configuration
--------------
-
-  A generic S3C2410 configuration is provided, and can be used as the
-  default by `make s3c2410_defconfig`. This configuration has support
-  for all the machines, and the commonly used features on them.
-
-  Certain machines may have their own default configurations as well,
-  please check the machine specific documentation.
-
-
-Layout
-------
-
-  The core support files are located in the platform code contained in
-  arch/arm/plat-s3c24xx with headers in include/asm-arm/plat-s3c24xx.
-  This directory should be kept to items shared between the platform
-  code (arch/arm/plat-s3c24xx) and the arch/arm/mach-s3c24* code.
-
-  Each cpu has a directory with the support files for it, and the
-  machines that carry the device. For example S3C2410 is contained
-  in arch/arm/mach-s3c2410 and S3C2440 in arch/arm/mach-s3c2440
-
-  Register, kernel and platform data definitions are held in the
-  arch/arm/mach-s3c2410 directory./include/mach
-
-arch/arm/plat-s3c24xx:
-
-  Files in here are either common to all the s3c24xx family,
-  or are common to only some of them with names to indicate this
-  status. The files that are not common to all are generally named
-  with the initial cpu they support in the series to ensure a short
-  name without any possibility of confusion with newer devices.
-
-  As an example, initially s3c244x would cover s3c2440 and s3c2442, but
-  with the s3c2443 which does not share many of the same drivers in
-  this directory, the name becomes invalid. We stick to s3c2440-<x>
-  to indicate a driver that is s3c2440 and s3c2442 compatible.
-
-  This does mean that to find the status of any given SoC, a number
-  of directories may need to be searched.
-
-
-Machines
---------
-
-  The currently supported machines are as follows:
-
-  Simtec Electronics EB2410ITX (BAST)
-
-    A general purpose development board, see EB2410ITX.txt for further
-    details
-
-  Simtec Electronics IM2440D20 (Osiris)
-
-    CPU Module from Simtec Electronics, with a S3C2440A CPU, nand flash
-    and a PCMCIA controller.
-
-  Samsung SMDK2410
-
-    Samsung's own development board, geared for PDA work.
-
-  Samsung/Aiji SMDK2412
-
-    The S3C2412 version of the SMDK2440.
-
-  Samsung/Aiji SMDK2413
-
-    The S3C2412 version of the SMDK2440.
-
-  Samsung/Meritech SMDK2440
-
-    The S3C2440 compatible version of the SMDK2440, which has the
-    option of an S3C2440 or S3C2442 CPU module.
-
-  Thorcom VR1000
-
-    Custom embedded board
-
-  HP IPAQ 1940
-
-    Handheld (IPAQ), available in several varieties
-
-  HP iPAQ rx3715
-
-    S3C2440 based IPAQ, with a number of variations depending on
-    features shipped.
-
-  Acer N30
-
-    A S3C2410 based PDA from Acer.  There is a Wiki page at
-    http://handhelds.org/moin/moin.cgi/AcerN30Documentation .
-
-  AML M5900
-
-    American Microsystems' M5900
-
-  Nex Vision Nexcoder
-  Nex Vision Otom
-
-    Two machines by Nex Vision
-
-
-Adding New Machines
--------------------
-
-  The architecture has been designed to support as many machines as can
-  be configured for it in one kernel build, and any future additions
-  should keep this in mind before altering items outside of their own
-  machine files.
-
-  Machine definitions should be kept in linux/arch/arm/mach-s3c2410,
-  and there are a number of examples that can be looked at.
-
-  Read the kernel patch submission policies as well as the
-  Documentation/arm directory before submitting patches. The
-  ARM kernel series is managed by Russell King, and has a patch system
-  located at http://www.arm.linux.org.uk/developer/patches/
-  as well as mailing lists that can be found from the same site.
-
-  As a courtesy, please notify <ben-linux@fluff.org> of any new
-  machines or other modifications.
-
-  Any large scale modifications, or new drivers should be discussed
-  on the ARM kernel mailing list (linux-arm-kernel) before being
-  attempted. See http://www.arm.linux.org.uk/mailinglists/ for the
-  mailing list information.
-
-
-I2C
----
-
-  The hardware I2C core in the CPU is supported in single master
-  mode, and can be configured via platform data.
-
-
-RTC
----
-
-  Support for the onboard RTC unit, including alarm function.
-
-  This has recently been upgraded to use the new RTC core,
-  and the module has been renamed to rtc-s3c to fit in with
-  the new rtc naming scheme.
-
-
-Watchdog
---------
-
-  The onchip watchdog is available via the standard watchdog
-  interface.
-
-
-NAND
-----
-
-  The current kernels now have support for the s3c2410 NAND
-  controller. If there are any problems the latest linux-mtd
-  code can be found from http://www.linux-mtd.infradead.org/
-
-  For more information see Documentation/arm/Samsung-S3C24XX/NAND.txt
-
-
-SD/MMC
-------
-
-  The SD/MMC hardware pre S3C2443 is supported in the current
-  kernel, the driver is drivers/mmc/host/s3cmci.c and supports
-  1 and 4 bit SD or MMC cards.
-
-  The SDIO behaviour of this driver has not been fully tested. There is no
-  current support for hardware SDIO interrupts.
-
-
-Serial
-------
-
-  The s3c2410 serial driver provides support for the internal
-  serial ports. These devices appear as /dev/ttySAC0 through 3.
-
-  To create device nodes for these, use the following commands
-
-    mknod ttySAC0 c 204 64
-    mknod ttySAC1 c 204 65
-    mknod ttySAC2 c 204 66
-
-
-GPIO
-----
-
-  The core contains support for manipulating the GPIO, see the
-  documentation in GPIO.txt in the same directory as this file.
-
-  Newer kernels carry GPIOLIB, and support is being moved towards
-  this with some of the older support in line to be removed.
-
-  As of v2.6.34, the move towards using gpiolib support is almost
-  complete, and very little of the old calls are left.
-
-  See Documentation/arm/Samsung-S3C24XX/GPIO.txt for the S3C24XX specific
-  support and Documentation/arm/Samsung/GPIO.txt for the core Samsung
-  implementation.
-
-
-Clock Management
-----------------
-
-  The core provides the interface defined in the header file
-  include/asm-arm/hardware/clock.h, to allow control over the
-  various clock units
-
-
-Suspend to RAM
---------------
-
-  For boards that provide support for suspend to RAM, the
-  system can be placed into low power suspend.
-
-  See Suspend.txt for more information.
-
-
-SPI
----
-
-  SPI drivers are available for both the in-built hardware
-  (although there is no DMA support yet) and a generic
-  GPIO based solution.
-
-
-LEDs
-----
-
-  There is support for GPIO based LEDs via a platform driver
-  in the LED subsystem.
-
-
-Platform Data
--------------
-
-  Whenever a device has platform specific data that is specified
-  on a per-machine basis, care should be taken to ensure the
-  following:
-
-    1) that default data is not left in the device to confuse the
-       driver if a machine does not set it at startup
-
-    2) the data should (if possible) be marked as __initdata,
-       to ensure that the data is thrown away if the machine is
-       not the one currently in use.
-
-       The best way of doing this is to make a function that
-       kmalloc()s an area of memory, and copies the __initdata
-       and then sets the relevant device's platform data. Making
-       the function `__init` takes care of ensuring it is discarded
-       with the rest of the initialisation code
-
-       static __init void s3c24xx_xxx_set_platdata(struct xxx_data *pd)
-       {
-           struct s3c2410_xxx_mach_info *npd;
-
-          npd = kmalloc(sizeof(struct s3c2410_xxx_mach_info), GFP_KERNEL);
-          if (npd) {
-             memcpy(npd, pd, sizeof(struct s3c2410_xxx_mach_info));
-             s3c_device_xxx.dev.platform_data = npd;
-          } else {
-              printk(KERN_ERR "no memory for xxx platform data\n");
-          }
-       }
-
-       Note, since the code is marked as __init, it should not be
-       exported outside arch/arm/mach-s3c2410/, or exported to
-       modules via EXPORT_SYMBOL() and related functions.
-
-
-Port Contributors
------------------
-
-  Ben Dooks (BJD)
-  Vincent Sanders
-  Herbert Potzl
-  Arnaud Patard (RTP)
-  Roc Wu
-  Klaus Fetscher
-  Dimitry Andric
-  Shannon Holland
-  Guillaume Gourat (NexVision)
-  Christer Weinigel (wingel) (Acer N30)
-  Lucas Correia Villa Real (S3C2400 port)
-
-
-Document Author
----------------
-
-Ben Dooks, Copyright 2004-2006 Simtec Electronics
diff --git a/Documentation/arm/Samsung-S3C24XX/S3C2412.txt b/Documentation/arm/Samsung-S3C24XX/S3C2412.txt
deleted file mode 100644 (file)
index dc1fd36..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-               S3C2412 ARM Linux Overview
-               ==========================
-
-Introduction
-------------
-
-  The S3C2412 is part of the S3C24XX range of ARM9 System-on-Chip CPUs
-  from Samsung. This part has an ARM926-EJS core, capable of running up
-  to 266MHz (see data-sheet for more information)
-
-
-Clock
------
-
-  The core clock code provides a set of clocks to the drivers, and allows
-  for source selection and a number of other features.
-
-
-Power
------
-
-  No support for suspend/resume to RAM in the current system.
-
-
-DMA
----
-
-  No current support for DMA.
-
-
-GPIO
-----
-
-  There is support for setting the GPIO to input/output/special function
-  and reading or writing to them.
-
-
-UART
-----
-
-  The UART hardware is similar to the S3C2440, and is supported by the
-  s3c2410 driver in the drivers/serial directory.
-
-
-NAND
-----
-
-  The NAND hardware is similar to the S3C2440, and is supported by the
-  s3c2410 driver in the drivers/mtd/nand/raw directory.
-
-
-USB Host
---------
-
-  The USB hardware is similar to the S3C2410, with extended clock source
-  control. The OHCI portion is supported by the ohci-s3c2410 driver, and
-  the clock control selection is supported by the core clock code.
-
-
-USB Device
-----------
-
-  No current support in the kernel
-
-
-IRQs
-----
-
-  All the standard, and external interrupt sources are supported. The
-  extra sub-sources are not yet supported.
-
-
-RTC
----
-
-  The RTC hardware is similar to the S3C2410, and is supported by the
-  s3c2410-rtc driver.
-
-
-Watchdog
---------
-
-  The watchdog hardware is the same as the S3C2410, and is supported by
-  the s3c2410_wdt driver.
-
-
-MMC/SD/SDIO
------------
-
-  No current support for the MMC/SD/SDIO block.
-
-IIC
----
-
-  The IIC hardware is the same as the S3C2410, and is supported by the
-  i2c-s3c24xx driver.
-
-
-IIS
----
-
-  No current support for the IIS interface.
-
-
-SPI
----
-
-  No current support for the SPI interfaces.
-
-
-ATA
----
-
-  No current support for the on-board ATA block.
-
-
-Document Author
----------------
-
-Ben Dooks, Copyright 2006 Simtec Electronics
diff --git a/Documentation/arm/Samsung-S3C24XX/S3C2413.txt b/Documentation/arm/Samsung-S3C24XX/S3C2413.txt
deleted file mode 100644 (file)
index 909bdc7..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-               S3C2413 ARM Linux Overview
-               ==========================
-
-Introduction
-------------
-
-  The S3C2413 is an extended version of the S3C2412, with an camera
-  interface and mobile DDR memory support. See the S3C2412 support
-  documentation for more information.
-
-
-Camera Interface
----------------
-
-  This block is currently not supported.
-
-
-Document Author
----------------
-
-Ben Dooks, Copyright 2006 Simtec Electronics
diff --git a/Documentation/arm/Samsung-S3C24XX/SMDK2440.txt b/Documentation/arm/Samsung-S3C24XX/SMDK2440.txt
deleted file mode 100644 (file)
index 429390b..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-               Samsung/Meritech SMDK2440
-               =========================
-
-Introduction
-------------
-
-  The SMDK2440 is a two part evaluation board for the Samsung S3C2440
-  processor. It includes support for LCD, SmartMedia, Audio, SD and
-  10MBit Ethernet, and expansion headers for various signals, including
-  the camera and unused GPIO.
-
-
-Configuration
--------------
-
-  To set the default configuration, use `make smdk2440_defconfig` which
-  will configure the common features of this board, or use
-  `make s3c2410_config` to include support for all s3c2410/s3c2440 machines
-
-
-Support
--------
-
-  Ben Dooks' SMDK2440 site at http://www.fluff.org/ben/smdk2440/ which
-  includes linux based USB download tools.
-
-  Some of the h1940 patches that can be found from the H1940 project
-  site at http://www.handhelds.org/projects/h1940.html can also be
-  applied to this board.
-
-
-Peripherals
------------
-
-  There is no current support for any of the extra peripherals on the
-  base-board itself.
-
-
-MTD
----
-
-  The NAND flash should be supported by the in kernel MTD NAND support,
-  NOR flash will be added later.
-
-
-Maintainers
------------
-
-  This board is being maintained by Ben Dooks, for more info, see
-  http://www.fluff.org/ben/smdk2440/
-
-  Many thanks to Dimitry Andric of TomTom for the loan of the SMDK2440,
-  and to Simtec Electronics for allowing me time to work on this.
-
-
-(c) 2004 Ben Dooks
diff --git a/Documentation/arm/Samsung-S3C24XX/Suspend.txt b/Documentation/arm/Samsung-S3C24XX/Suspend.txt
deleted file mode 100644 (file)
index cb4f0c0..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-                       S3C24XX Suspend Support
-                       =======================
-
-
-Introduction
-------------
-
-  The S3C24XX supports a low-power suspend mode, where the SDRAM is kept
-  in Self-Refresh mode, and all but the essential peripheral blocks are
-  powered down. For more information on how this works, please look
-  at the relevant CPU datasheet from Samsung.
-
-
-Requirements
-------------
-
-  1) A bootloader that can support the necessary resume operation
-
-  2) Support for at least 1 source for resume
-
-  3) CONFIG_PM enabled in the kernel
-
-  4) Any peripherals that are going to be powered down at the same
-     time require suspend/resume support.
-
-
-Resuming
---------
-
-  The S3C2410 user manual defines the process of sending the CPU to
-  sleep and how it resumes. The default behaviour of the Linux code
-  is to set the GSTATUS3 register to the physical address of the
-  code to resume Linux operation.
-
-  GSTATUS4 is currently left alone by the sleep code, and is free to
-  use for any other purposes (for example, the EB2410ITX uses this to
-  save memory configuration in).
-
-
-Machine Support
----------------
-
-  The machine specific functions must call the s3c_pm_init() function
-  to say that its bootloader is capable of resuming. This can be as
-  simple as adding the following to the machine's definition:
-
-  INITMACHINE(s3c_pm_init)
-
-  A board can do its own setup before calling s3c_pm_init, if it
-  needs to setup anything else for power management support.
-
-  There is currently no support for over-riding the default method of
-  saving the resume address, if your board requires it, then contact
-  the maintainer and discuss what is required.
-
-  Note, the original method of adding an late_initcall() is wrong,
-  and will end up initialising all compiled machines' pm init!
-
-  The following is an example of code used for testing wakeup from
-  an falling edge on IRQ_EINT0:
-
-
-static irqreturn_t button_irq(int irq, void *pw)
-{
-       return IRQ_HANDLED;
-}
-
-statuc void __init machine_init(void)
-{
-       ...
-
-       request_irq(IRQ_EINT0, button_irq, IRQF_TRIGGER_FALLING,
-                  "button-irq-eint0", NULL);
-
-       enable_irq_wake(IRQ_EINT0);
-
-       s3c_pm_init();
-}
-
-
-Debugging
----------
-
-  There are several important things to remember when using PM suspend:
-
-  1) The uart drivers will disable the clocks to the UART blocks when
-     suspending, which means that use of printascii() or similar direct
-     access to the UARTs will cause the debug to stop.
-
-  2) While the pm code itself will attempt to re-enable the UART clocks,
-     care should be taken that any external clock sources that the UARTs
-     rely on are still enabled at that point.
-
-  3) If any debugging is placed in the resume path, then it must have the
-     relevant clocks and peripherals setup before use (ie, bootloader).
-
-     For example, if you transmit a character from the UART, the baud
-     rate and uart controls must be setup beforehand.
-
-
-Configuration
--------------
-
-  The S3C2410 specific configuration in `System Type` defines various
-  aspects of how the S3C2410 suspend and resume support is configured
-
-  `S3C2410 PM Suspend debug`
-
-    This option prints messages to the serial console before and after
-    the actual suspend, giving detailed information on what is
-    happening
-
-
-  `S3C2410 PM Suspend Memory CRC`
-
-    Allows the entire memory to be checksummed before and after the
-    suspend to see if there has been any corruption of the contents.
-
-    Note, the time to calculate the CRC is dependent on the CPU speed
-    and the size of memory. For an 64Mbyte RAM area on an 200MHz
-    S3C2410, this can take approximately 4 seconds to complete.
-
-    This support requires the CRC32 function to be enabled.
-
-
-  `S3C2410 PM Suspend CRC Chunksize (KiB)`
-
-    Defines the size of memory each CRC chunk covers. A smaller value
-    will mean that the CRC data block will take more memory, but will
-    identify any faults with better precision
-
-
-Document Author
----------------
-
-Ben Dooks, Copyright 2004 Simtec Electronics
-
diff --git a/Documentation/arm/Samsung-S3C24XX/USB-Host.txt b/Documentation/arm/Samsung-S3C24XX/USB-Host.txt
deleted file mode 100644 (file)
index f82b1fa..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-                       S3C24XX USB Host support
-                       ========================
-
-
-
-Introduction
-------------
-
-  This document details the S3C2410/S3C2440 in-built OHCI USB host support.
-
-Configuration
--------------
-
-  Enable at least the following kernel options:
-
-  menuconfig:
-
-   Device Drivers  --->
-     USB support  --->
-       <*> Support for Host-side USB
-       <*>   OHCI HCD support
-
-
-  .config:
-    CONFIG_USB
-    CONFIG_USB_OHCI_HCD
-
-
-  Once these options are configured, the standard set of USB device
-  drivers can be configured and used.
-
-
-Board Support
--------------
-
-  The driver attaches to a platform device, which will need to be
-  added by the board specific support file in linux/arch/arm/mach-s3c2410,
-  such as mach-bast.c or mach-smdk2410.c
-
-  The platform device's platform_data field is only needed if the
-  board implements extra power control or over-current monitoring.
-
-  The OHCI driver does not ensure the state of the S3C2410's MISCCTRL
-  register, so if both ports are to be used for the host, then it is
-  the board support file's responsibility to ensure that the second
-  port is configured to be connected to the OHCI core.
-
-
-Platform Data
--------------
-
-  See arch/arm/mach-s3c2410/include/mach/usb-control.h for the
-  descriptions of the platform device data. An implementation
-  can be found in linux/arch/arm/mach-s3c2410/usb-simtec.c .
-
-  The `struct s3c2410_hcd_info` contains a pair of functions
-  that get called to enable over-current detection, and to
-  control the port power status.
-
-  The ports are numbered 0 and 1.
-
-  power_control:
-
-    Called to enable or disable the power on the port.
-
-  enable_oc:
-
-    Called to enable or disable the over-current monitoring.
-    This should claim or release the resources being used to
-    check the power condition on the port, such as an IRQ.
-
-  report_oc:
-
-    The OHCI driver fills this field in for the over-current code
-    to call when there is a change to the over-current state on
-    an port. The ports argument is a bitmask of 1 bit per port,
-    with bit X being 1 for an over-current on port X.
-
-    The function s3c2410_usb_report_oc() has been provided to
-    ensure this is called correctly.
-
-  port[x]:
-
-    This is struct describes each port, 0 or 1. The platform driver
-    should set the flags field of each port to S3C_HCDFLG_USED if
-    the port is enabled.
-
-
-
-Document Author
----------------
-
-Ben Dooks, Copyright 2005 Simtec Electronics
diff --git a/Documentation/arm/Samsung/Bootloader-interface.txt b/Documentation/arm/Samsung/Bootloader-interface.txt
deleted file mode 100644 (file)
index d17ed51..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-      Interface between kernel and boot loaders on Exynos boards
-      ==========================================================
-
-Author: Krzysztof Kozlowski
-Date  : 6 June 2015
-
-The document tries to describe currently used interface between Linux kernel
-and boot loaders on Samsung Exynos based boards. This is not a definition
-of interface but rather a description of existing state, a reference
-for information purpose only.
-
-In the document "boot loader" means any of following: U-boot, proprietary
-SBOOT or any other firmware for ARMv7 and ARMv8 initializing the board before
-executing kernel.
-
-
-1. Non-Secure mode
-
-Address:      sysram_ns_base_addr
-Offset        Value                                        Purpose
-=============================================================================
-0x08          exynos_cpu_resume_ns, mcpm_entry_point       System suspend
-0x0c          0x00000bad (Magic cookie)                    System suspend
-0x1c          exynos4_secondary_startup                    Secondary CPU boot
-0x1c + 4*cpu  exynos4_secondary_startup (Exynos4412)       Secondary CPU boot
-0x20          0xfcba0d10 (Magic cookie)                    AFTR
-0x24          exynos_cpu_resume_ns                         AFTR
-0x28 + 4*cpu  0x8 (Magic cookie, Exynos3250)               AFTR
-0x28          0x0 or last value during resume (Exynos542x) System suspend
-
-
-2. Secure mode
-
-Address:      sysram_base_addr
-Offset        Value                                        Purpose
-=============================================================================
-0x00          exynos4_secondary_startup                    Secondary CPU boot
-0x04          exynos4_secondary_startup (Exynos542x)       Secondary CPU boot
-4*cpu         exynos4_secondary_startup (Exynos4412)       Secondary CPU boot
-0x20          exynos_cpu_resume (Exynos4210 r1.0)          AFTR
-0x24          0xfcba0d10 (Magic cookie, Exynos4210 r1.0)   AFTR
-
-Address:      pmu_base_addr
-Offset        Value                                        Purpose
-=============================================================================
-0x0800        exynos_cpu_resume                            AFTR, suspend
-0x0800        mcpm_entry_point (Exynos542x with MCPM)      AFTR, suspend
-0x0804        0xfcba0d10 (Magic cookie)                    AFTR
-0x0804        0x00000bad (Magic cookie)                    System suspend
-0x0814        exynos4_secondary_startup (Exynos4210 r1.1)  Secondary CPU boot
-0x0818        0xfcba0d10 (Magic cookie, Exynos4210 r1.1)   AFTR
-0x081C        exynos_cpu_resume (Exynos4210 r1.1)          AFTR
-
-
-3. Other (regardless of secure/non-secure mode)
-
-Address:      pmu_base_addr
-Offset        Value                           Purpose
-=============================================================================
-0x0908        Non-zero                        Secondary CPU boot up indicator
-                                              on Exynos3250 and Exynos542x
-
-
-4. Glossary
-
-AFTR - ARM Off Top Running, a low power mode, Cortex cores and many other
-modules are power gated, except the TOP modules
-MCPM - Multi-Cluster Power Management
diff --git a/Documentation/arm/Samsung/GPIO.txt b/Documentation/arm/Samsung/GPIO.txt
deleted file mode 100644 (file)
index 795adfd..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-               Samsung GPIO implementation
-               ===========================
-
-Introduction
-------------
-
-This outlines the Samsung GPIO implementation and the architecture
-specific calls provided alongside the drivers/gpio core.
-
-
-S3C24XX (Legacy)
-----------------
-
-See Documentation/arm/Samsung-S3C24XX/GPIO.txt for more information
-about these devices. Their implementation has been brought into line
-with the core samsung implementation described in this document.
-
-
-GPIOLIB integration
--------------------
-
-The gpio implementation uses gpiolib as much as possible, only providing
-specific calls for the items that require Samsung specific handling, such
-as pin special-function or pull resistor control.
-
-GPIO numbering is synchronised between the Samsung and gpiolib system.
-
-
-PIN configuration
------------------
-
-Pin configuration is specific to the Samsung architecture, with each SoC
-registering the necessary information for the core gpio configuration
-implementation to configure pins as necessary.
-
-The s3c_gpio_cfgpin() and s3c_gpio_setpull() provide the means for a
-driver or machine to change gpio configuration.
-
-See arch/arm/plat-samsung/include/plat/gpio-cfg.h for more information
-on these functions.
diff --git a/Documentation/arm/Samsung/Overview.txt b/Documentation/arm/Samsung/Overview.txt
deleted file mode 100644 (file)
index 8f7309b..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-               Samsung ARM Linux Overview
-               ==========================
-
-Introduction
-------------
-
-  The Samsung range of ARM SoCs spans many similar devices, from the initial
-  ARM9 through to the newest ARM cores. This document shows an overview of
-  the current kernel support, how to use it and where to find the code
-  that supports this.
-
-  The currently supported SoCs are:
-
-  - S3C24XX: See Documentation/arm/Samsung-S3C24XX/Overview.txt for full list
-  - S3C64XX: S3C6400 and S3C6410
-  - S5PC110 / S5PV210
-
-
-S3C24XX Systems
----------------
-
-  There is still documentation in Documnetation/arm/Samsung-S3C24XX/ which
-  deals with the architecture and drivers specific to these devices.
-
-  See Documentation/arm/Samsung-S3C24XX/Overview.txt for more information
-  on the implementation details and specific support.
-
-
-Configuration
--------------
-
-  A number of configurations are supplied, as there is no current way of
-  unifying all the SoCs into one kernel.
-
-  s5pc110_defconfig - S5PC110 specific default configuration
-  s5pv210_defconfig - S5PV210 specific default configuration
-
-
-Layout
-------
-
-  The directory layout is currently being restructured, and consists of
-  several platform directories and then the machine specific directories
-  of the CPUs being built for.
-
-  plat-samsung provides the base for all the implementations, and is the
-  last in the line of include directories that are processed for the build
-  specific information. It contains the base clock, GPIO and device definitions
-  to get the system running.
-
-  plat-s3c24xx is for s3c24xx specific builds, see the S3C24XX docs.
-
-  plat-s5p is for s5p specific builds, and contains common support for the
-  S5P specific systems. Not all S5Ps use all the features in this directory
-  due to differences in the hardware.
-
-
-Layout changes
---------------
-
-  The old plat-s3c and plat-s5pc1xx directories have been removed, with
-  support moved to either plat-samsung or plat-s5p as necessary. These moves
-  where to simplify the include and dependency issues involved with having
-  so many different platform directories.
-
-
-Port Contributors
------------------
-
-  Ben Dooks (BJD)
-  Vincent Sanders
-  Herbert Potzl
-  Arnaud Patard (RTP)
-  Roc Wu
-  Klaus Fetscher
-  Dimitry Andric
-  Shannon Holland
-  Guillaume Gourat (NexVision)
-  Christer Weinigel (wingel) (Acer N30)
-  Lucas Correia Villa Real (S3C2400 port)
-
-
-Document Author
----------------
-
-Copyright 2009-2010 Ben Dooks <ben-linux@fluff.org>
diff --git a/Documentation/arm/Setup b/Documentation/arm/Setup
deleted file mode 100644 (file)
index 0cb1e64..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-Kernel initialisation parameters on ARM Linux
----------------------------------------------
-
-The following document describes the kernel initialisation parameter
-structure, otherwise known as 'struct param_struct' which is used
-for most ARM Linux architectures.
-
-This structure is used to pass initialisation parameters from the
-kernel loader to the Linux kernel proper, and may be short lived
-through the kernel initialisation process.  As a general rule, it
-should not be referenced outside of arch/arm/kernel/setup.c:setup_arch().
-
-There are a lot of parameters listed in there, and they are described
-below:
-
- page_size
-
-   This parameter must be set to the page size of the machine, and
-   will be checked by the kernel.
-
- nr_pages
-
-   This is the total number of pages of memory in the system.  If
-   the memory is banked, then this should contain the total number
-   of pages in the system.
-
-   If the system contains separate VRAM, this value should not
-   include this information.
-
- ramdisk_size
-
-   This is now obsolete, and should not be used.
-
- flags
-
-   Various kernel flags, including:
-    bit 0 - 1 = mount root read only
-    bit 1 - unused
-    bit 2 - 0 = load ramdisk
-    bit 3 - 0 = prompt for ramdisk
-
- rootdev
-
-   major/minor number pair of device to mount as the root filesystem.
-
- video_num_cols
- video_num_rows
-
-   These two together describe the character size of the dummy console,
-   or VGA console character size.  They should not be used for any other
-   purpose.
-
-   It's generally a good idea to set these to be either standard VGA, or
-   the equivalent character size of your fbcon display.  This then allows
-   all the bootup messages to be displayed correctly.
-
- video_x
- video_y
-
-   This describes the character position of cursor on VGA console, and
-   is otherwise unused. (should not be used for other console types, and
-   should not be used for other purposes).
-
- memc_control_reg
-
-   MEMC chip control register for Acorn Archimedes and Acorn A5000
-   based machines.  May be used differently by different architectures.
-
- sounddefault
-
-   Default sound setting on Acorn machines.  May be used differently by
-   different architectures.
-
- adfsdrives
-
-   Number of ADFS/MFM disks.  May be used differently by different
-   architectures.
-
- bytes_per_char_h
- bytes_per_char_v
-
-   These are now obsolete, and should not be used.
-
- pages_in_bank[4]
-
-   Number of pages in each bank of the systems memory (used for RiscPC).
-   This is intended to be used on systems where the physical memory
-   is non-contiguous from the processors point of view.
-
- pages_in_vram
-
-   Number of pages in VRAM (used on Acorn RiscPC).  This value may also
-   be used by loaders if the size of the video RAM can't be obtained
-   from the hardware.
-
- initrd_start
- initrd_size
-
-   This describes the kernel virtual start address and size of the
-   initial ramdisk.
-
- rd_start
-
-   Start address in sectors of the ramdisk image on a floppy disk.
-
- system_rev
-
-   system revision number.
-
- system_serial_low
- system_serial_high
-
-   system 64-bit serial number
-
- mem_fclk_21285
-
-   The speed of the external oscillator to the 21285 (footbridge),
-   which control's the speed of the memory bus, timer & serial port.
-   Depending upon the speed of the cpu its value can be between
-   0-66 MHz. If no params are passed or a value of zero is passed,
-   then a value of 50 Mhz is the default on 21285 architectures.
-
- paths[8][128]
-
-   These are now obsolete, and should not be used.
-
- commandline
-
-   Kernel command line parameters.  Details can be found elsewhere.
diff --git a/Documentation/arm/VFP/release-notes.txt b/Documentation/arm/VFP/release-notes.txt
deleted file mode 100644 (file)
index 28a2795..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-Release notes for Linux Kernel VFP support code
------------------------------------------------
-
-Date:  20 May 2004
-Author:        Russell King
-
-This is the first release of the Linux Kernel VFP support code.  It
-provides support for the exceptions bounced from VFP hardware found
-on ARM926EJ-S.
-
-This release has been validated against the SoftFloat-2b library by
-John R. Hauser using the TestFloat-2a test suite.  Details of this
-library and test suite can be found at:
-
-   http://www.jhauser.us/arithmetic/SoftFloat.html
-
-The operations which have been tested with this package are:
-
- - fdiv
- - fsub
- - fadd
- - fmul
- - fcmp
- - fcmpe
- - fcvtd
- - fcvts
- - fsito
- - ftosi
- - fsqrt
-
-All the above pass softfloat tests with the following exceptions:
-
-- fadd/fsub shows some differences in the handling of +0 / -0 results
-  when input operands differ in signs.
-- the handling of underflow exceptions is slightly different.  If a
-  result underflows before rounding, but becomes a normalised number
-  after rounding, we do not signal an underflow exception.
-
-Other operations which have been tested by basic assembly-only tests
-are:
-
- - fcpy
- - fabs
- - fneg
- - ftoui
- - ftosiz
- - ftouiz
-
-The combination operations have not been tested:
-
- - fmac
- - fnmac
- - fmsc
- - fnmsc
- - fnmul
diff --git a/Documentation/arm/arm.rst b/Documentation/arm/arm.rst
new file mode 100644 (file)
index 0000000..2edc509
--- /dev/null
@@ -0,0 +1,214 @@
+=======================
+ARM Linux 2.6 and upper
+=======================
+
+    Please check <ftp://ftp.arm.linux.org.uk/pub/armlinux> for
+    updates.
+
+Compilation of kernel
+---------------------
+
+  In order to compile ARM Linux, you will need a compiler capable of
+  generating ARM ELF code with GNU extensions.  GCC 3.3 is known to be
+  a good compiler.  Fortunately, you needn't guess.  The kernel will report
+  an error if your compiler is a recognized offender.
+
+  To build ARM Linux natively, you shouldn't have to alter the ARCH = line
+  in the top level Makefile.  However, if you don't have the ARM Linux ELF
+  tools installed as default, then you should change the CROSS_COMPILE
+  line as detailed below.
+
+  If you wish to cross-compile, then alter the following lines in the top
+  level make file::
+
+    ARCH = <whatever>
+
+  with::
+
+    ARCH = arm
+
+  and::
+
+    CROSS_COMPILE=
+
+  to::
+
+    CROSS_COMPILE=<your-path-to-your-compiler-without-gcc>
+
+  eg.::
+
+    CROSS_COMPILE=arm-linux-
+
+  Do a 'make config', followed by 'make Image' to build the kernel
+  (arch/arm/boot/Image).  A compressed image can be built by doing a
+  'make zImage' instead of 'make Image'.
+
+
+Bug reports etc
+---------------
+
+  Please send patches to the patch system.  For more information, see
+  http://www.arm.linux.org.uk/developer/patches/info.php Always include some
+  explanation as to what the patch does and why it is needed.
+
+  Bug reports should be sent to linux-arm-kernel@lists.arm.linux.org.uk,
+  or submitted through the web form at
+  http://www.arm.linux.org.uk/developer/
+
+  When sending bug reports, please ensure that they contain all relevant
+  information, eg. the kernel messages that were printed before/during
+  the problem, what you were doing, etc.
+
+
+Include files
+-------------
+
+  Several new include directories have been created under include/asm-arm,
+  which are there to reduce the clutter in the top-level directory.  These
+  directories, and their purpose is listed below:
+
+  ============= ==========================================================
+   `arch-*`    machine/platform specific header files
+   `hardware`  driver-internal ARM specific data structures/definitions
+   `mach`      descriptions of generic ARM to specific machine interfaces
+   `proc-*`    processor dependent header files (currently only two
+               categories)
+  ============= ==========================================================
+
+
+Machine/Platform support
+------------------------
+
+  The ARM tree contains support for a lot of different machine types.  To
+  continue supporting these differences, it has become necessary to split
+  machine-specific parts by directory.  For this, the machine category is
+  used to select which directories and files get included (we will use
+  $(MACHINE) to refer to the category)
+
+  To this end, we now have arch/arm/mach-$(MACHINE) directories which are
+  designed to house the non-driver files for a particular machine (eg, PCI,
+  memory management, architecture definitions etc).  For all future
+  machines, there should be a corresponding arch/arm/mach-$(MACHINE)/include/mach
+  directory.
+
+
+Modules
+-------
+
+  Although modularisation is supported (and required for the FP emulator),
+  each module on an ARM2/ARM250/ARM3 machine when is loaded will take
+  memory up to the next 32k boundary due to the size of the pages.
+  Therefore, is modularisation on these machines really worth it?
+
+  However, ARM6 and up machines allow modules to take multiples of 4k, and
+  as such Acorn RiscPCs and other architectures using these processors can
+  make good use of modularisation.
+
+
+ADFS Image files
+----------------
+
+  You can access image files on your ADFS partitions by mounting the ADFS
+  partition, and then using the loopback device driver.  You must have
+  losetup installed.
+
+  Please note that the PCEmulator DOS partitions have a partition table at
+  the start, and as such, you will have to give '-o offset' to losetup.
+
+
+Request to developers
+---------------------
+
+  When writing device drivers which include a separate assembler file, please
+  include it in with the C file, and not the arch/arm/lib directory.  This
+  allows the driver to be compiled as a loadable module without requiring
+  half the code to be compiled into the kernel image.
+
+  In general, try to avoid using assembler unless it is really necessary.  It
+  makes drivers far less easy to port to other hardware.
+
+
+ST506 hard drives
+-----------------
+
+  The ST506 hard drive controllers seem to be working fine (if a little
+  slowly).  At the moment they will only work off the controllers on an
+  A4x0's motherboard, but for it to work off a Podule just requires
+  someone with a podule to add the addresses for the IRQ mask and the
+  HDC base to the source.
+
+  As of 31/3/96 it works with two drives (you should get the ADFS
+  `*configure` harddrive set to 2). I've got an internal 20MB and a great
+  big external 5.25" FH 64MB drive (who could ever want more :-) ).
+
+  I've just got 240K/s off it (a dd with bs=128k); thats about half of what
+  RiscOS gets; but it's a heck of a lot better than the 50K/s I was getting
+  last week :-)
+
+  Known bug: Drive data errors can cause a hang; including cases where
+  the controller has fixed the error using ECC. (Possibly ONLY
+  in that case...hmm).
+
+
+1772 Floppy
+-----------
+  This also seems to work OK, but hasn't been stressed much lately.  It
+  hasn't got any code for disc change detection in there at the moment which
+  could be a bit of a problem!  Suggestions on the correct way to do this
+  are welcome.
+
+
+`CONFIG_MACH_` and `CONFIG_ARCH_`
+---------------------------------
+  A change was made in 2003 to the macro names for new machines.
+  Historically, `CONFIG_ARCH_` was used for the bonafide architecture,
+  e.g. SA1100, as well as implementations of the architecture,
+  e.g. Assabet.  It was decided to change the implementation macros
+  to read `CONFIG_MACH_` for clarity.  Moreover, a retroactive fixup has
+  not been made because it would complicate patching.
+
+  Previous registrations may be found online.
+
+    <http://www.arm.linux.org.uk/developer/machines/>
+
+Kernel entry (head.S)
+---------------------
+  The initial entry into the kernel is via head.S, which uses machine
+  independent code.  The machine is selected by the value of 'r1' on
+  entry, which must be kept unique.
+
+  Due to the large number of machines which the ARM port of Linux provides
+  for, we have a method to manage this which ensures that we don't end up
+  duplicating large amounts of code.
+
+  We group machine (or platform) support code into machine classes.  A
+  class typically based around one or more system on a chip devices, and
+  acts as a natural container around the actual implementations.  These
+  classes are given directories - arch/arm/mach-<class> and
+  arch/arm/mach-<class> - which contain the source files to/include/mach
+  support the machine class.  This directories also contain any machine
+  specific supporting code.
+
+  For example, the SA1100 class is based upon the SA1100 and SA1110 SoC
+  devices, and contains the code to support the way the on-board and off-
+  board devices are used, or the device is setup, and provides that
+  machine specific "personality."
+
+  For platforms that support device tree (DT), the machine selection is
+  controlled at runtime by passing the device tree blob to the kernel.  At
+  compile-time, support for the machine type must be selected.  This allows for
+  a single multiplatform kernel build to be used for several machine types.
+
+  For platforms that do not use device tree, this machine selection is
+  controlled by the machine type ID, which acts both as a run-time and a
+  compile-time code selection method.  You can register a new machine via the
+  web site at:
+
+    <http://www.arm.linux.org.uk/developer/machines/>
+
+  Note: Please do not register a machine type for DT-only platforms.  If your
+  platform is DT-only, you do not need a registered machine type.
+
+---
+
+Russell King (15/03/2004)
diff --git a/Documentation/arm/booting.rst b/Documentation/arm/booting.rst
new file mode 100644 (file)
index 0000000..4babb6c
--- /dev/null
@@ -0,0 +1,237 @@
+=================
+Booting ARM Linux
+=================
+
+Author:        Russell King
+
+Date  : 18 May 2002
+
+The following documentation is relevant to 2.4.18-rmk6 and beyond.
+
+In order to boot ARM Linux, you require a boot loader, which is a small
+program that runs before the main kernel.  The boot loader is expected
+to initialise various devices, and eventually call the Linux kernel,
+passing information to the kernel.
+
+Essentially, the boot loader should provide (as a minimum) the
+following:
+
+1. Setup and initialise the RAM.
+2. Initialise one serial port.
+3. Detect the machine type.
+4. Setup the kernel tagged list.
+5. Load initramfs.
+6. Call the kernel image.
+
+
+1. Setup and initialise RAM
+---------------------------
+
+Existing boot loaders:
+       MANDATORY
+New boot loaders:
+       MANDATORY
+
+The boot loader is expected to find and initialise all RAM that the
+kernel will use for volatile data storage in the system.  It performs
+this in a machine dependent manner.  (It may use internal algorithms
+to automatically locate and size all RAM, or it may use knowledge of
+the RAM in the machine, or any other method the boot loader designer
+sees fit.)
+
+
+2. Initialise one serial port
+-----------------------------
+
+Existing boot loaders:
+       OPTIONAL, RECOMMENDED
+New boot loaders:
+       OPTIONAL, RECOMMENDED
+
+The boot loader should initialise and enable one serial port on the
+target.  This allows the kernel serial driver to automatically detect
+which serial port it should use for the kernel console (generally
+used for debugging purposes, or communication with the target.)
+
+As an alternative, the boot loader can pass the relevant 'console='
+option to the kernel via the tagged lists specifying the port, and
+serial format options as described in
+
+       Documentation/admin-guide/kernel-parameters.rst.
+
+
+3. Detect the machine type
+--------------------------
+
+Existing boot loaders:
+       OPTIONAL
+New boot loaders:
+       MANDATORY except for DT-only platforms
+
+The boot loader should detect the machine type its running on by some
+method.  Whether this is a hard coded value or some algorithm that
+looks at the connected hardware is beyond the scope of this document.
+The boot loader must ultimately be able to provide a MACH_TYPE_xxx
+value to the kernel. (see linux/arch/arm/tools/mach-types).  This
+should be passed to the kernel in register r1.
+
+For DT-only platforms, the machine type will be determined by device
+tree.  set the machine type to all ones (~0).  This is not strictly
+necessary, but assures that it will not match any existing types.
+
+4. Setup boot data
+------------------
+
+Existing boot loaders:
+       OPTIONAL, HIGHLY RECOMMENDED
+New boot loaders:
+       MANDATORY
+
+The boot loader must provide either a tagged list or a dtb image for
+passing configuration data to the kernel.  The physical address of the
+boot data is passed to the kernel in register r2.
+
+4a. Setup the kernel tagged list
+--------------------------------
+
+The boot loader must create and initialise the kernel tagged list.
+A valid tagged list starts with ATAG_CORE and ends with ATAG_NONE.
+The ATAG_CORE tag may or may not be empty.  An empty ATAG_CORE tag
+has the size field set to '2' (0x00000002).  The ATAG_NONE must set
+the size field to zero.
+
+Any number of tags can be placed in the list.  It is undefined
+whether a repeated tag appends to the information carried by the
+previous tag, or whether it replaces the information in its
+entirety; some tags behave as the former, others the latter.
+
+The boot loader must pass at a minimum the size and location of
+the system memory, and root filesystem location.  Therefore, the
+minimum tagged list should look::
+
+               +-----------+
+  base ->      | ATAG_CORE |  |
+               +-----------+  |
+               | ATAG_MEM  |  | increasing address
+               +-----------+  |
+               | ATAG_NONE |  |
+               +-----------+  v
+
+The tagged list should be stored in system RAM.
+
+The tagged list must be placed in a region of memory where neither
+the kernel decompressor nor initrd 'bootp' program will overwrite
+it.  The recommended placement is in the first 16KiB of RAM.
+
+4b. Setup the device tree
+-------------------------
+
+The boot loader must load a device tree image (dtb) into system ram
+at a 64bit aligned address and initialize it with the boot data.  The
+dtb format is documented in Documentation/devicetree/booting-without-of.txt.
+The kernel will look for the dtb magic value of 0xd00dfeed at the dtb
+physical address to determine if a dtb has been passed instead of a
+tagged list.
+
+The boot loader must pass at a minimum the size and location of the
+system memory, and the root filesystem location.  The dtb must be
+placed in a region of memory where the kernel decompressor will not
+overwrite it, while remaining within the region which will be covered
+by the kernel's low-memory mapping.
+
+A safe location is just above the 128MiB boundary from start of RAM.
+
+5. Load initramfs.
+------------------
+
+Existing boot loaders:
+       OPTIONAL
+New boot loaders:
+       OPTIONAL
+
+If an initramfs is in use then, as with the dtb, it must be placed in
+a region of memory where the kernel decompressor will not overwrite it
+while also with the region which will be covered by the kernel's
+low-memory mapping.
+
+A safe location is just above the device tree blob which itself will
+be loaded just above the 128MiB boundary from the start of RAM as
+recommended above.
+
+6. Calling the kernel image
+---------------------------
+
+Existing boot loaders:
+       MANDATORY
+New boot loaders:
+       MANDATORY
+
+There are two options for calling the kernel zImage.  If the zImage
+is stored in flash, and is linked correctly to be run from flash,
+then it is legal for the boot loader to call the zImage in flash
+directly.
+
+The zImage may also be placed in system RAM and called there.  The
+kernel should be placed in the first 128MiB of RAM.  It is recommended
+that it is loaded above 32MiB in order to avoid the need to relocate
+prior to decompression, which will make the boot process slightly
+faster.
+
+When booting a raw (non-zImage) kernel the constraints are tighter.
+In this case the kernel must be loaded at an offset into system equal
+to TEXT_OFFSET - PAGE_OFFSET.
+
+In any case, the following conditions must be met:
+
+- Quiesce all DMA capable devices so that memory does not get
+  corrupted by bogus network packets or disk data. This will save
+  you many hours of debug.
+
+- CPU register settings
+
+  - r0 = 0,
+  - r1 = machine type number discovered in (3) above.
+  - r2 = physical address of tagged list in system RAM, or
+    physical address of device tree block (dtb) in system RAM
+
+- CPU mode
+
+  All forms of interrupts must be disabled (IRQs and FIQs)
+
+  For CPUs which do not include the ARM virtualization extensions, the
+  CPU must be in SVC mode.  (A special exception exists for Angel)
+
+  CPUs which include support for the virtualization extensions can be
+  entered in HYP mode in order to enable the kernel to make full use of
+  these extensions.  This is the recommended boot method for such CPUs,
+  unless the virtualisations are already in use by a pre-installed
+  hypervisor.
+
+  If the kernel is not entered in HYP mode for any reason, it must be
+  entered in SVC mode.
+
+- Caches, MMUs
+
+  The MMU must be off.
+
+  Instruction cache may be on or off.
+
+  Data cache must be off.
+
+  If the kernel is entered in HYP mode, the above requirements apply to
+  the HYP mode configuration in addition to the ordinary PL1 (privileged
+  kernel modes) configuration.  In addition, all traps into the
+  hypervisor must be disabled, and PL1 access must be granted for all
+  peripherals and CPU resources for which this is architecturally
+  possible.  Except for entering in HYP mode, the system configuration
+  should be such that a kernel which does not include support for the
+  virtualization extensions can boot correctly without extra help.
+
+- The boot loader is expected to call the kernel image by jumping
+  directly to the first instruction of the kernel image.
+
+  On CPUs supporting the ARM instruction set, the entry must be
+  made in ARM state, even for a Thumb-2 kernel.
+
+  On CPUs supporting only the Thumb instruction set such as
+  Cortex-M class CPUs, the entry must be made in Thumb state.
diff --git a/Documentation/arm/cluster-pm-race-avoidance.rst b/Documentation/arm/cluster-pm-race-avoidance.rst
new file mode 100644 (file)
index 0000000..aa58603
--- /dev/null
@@ -0,0 +1,533 @@
+=========================================================
+Cluster-wide Power-up/power-down race avoidance algorithm
+=========================================================
+
+This file documents the algorithm which is used to coordinate CPU and
+cluster setup and teardown operations and to manage hardware coherency
+controls safely.
+
+The section "Rationale" explains what the algorithm is for and why it is
+needed.  "Basic model" explains general concepts using a simplified view
+of the system.  The other sections explain the actual details of the
+algorithm in use.
+
+
+Rationale
+---------
+
+In a system containing multiple CPUs, it is desirable to have the
+ability to turn off individual CPUs when the system is idle, reducing
+power consumption and thermal dissipation.
+
+In a system containing multiple clusters of CPUs, it is also desirable
+to have the ability to turn off entire clusters.
+
+Turning entire clusters off and on is a risky business, because it
+involves performing potentially destructive operations affecting a group
+of independently running CPUs, while the OS continues to run.  This
+means that we need some coordination in order to ensure that critical
+cluster-level operations are only performed when it is truly safe to do
+so.
+
+Simple locking may not be sufficient to solve this problem, because
+mechanisms like Linux spinlocks may rely on coherency mechanisms which
+are not immediately enabled when a cluster powers up.  Since enabling or
+disabling those mechanisms may itself be a non-atomic operation (such as
+writing some hardware registers and invalidating large caches), other
+methods of coordination are required in order to guarantee safe
+power-down and power-up at the cluster level.
+
+The mechanism presented in this document describes a coherent memory
+based protocol for performing the needed coordination.  It aims to be as
+lightweight as possible, while providing the required safety properties.
+
+
+Basic model
+-----------
+
+Each cluster and CPU is assigned a state, as follows:
+
+       - DOWN
+       - COMING_UP
+       - UP
+       - GOING_DOWN
+
+::
+
+           +---------> UP ----------+
+           |                        v
+
+       COMING_UP                GOING_DOWN
+
+           ^                        |
+           +--------- DOWN <--------+
+
+
+DOWN:
+       The CPU or cluster is not coherent, and is either powered off or
+       suspended, or is ready to be powered off or suspended.
+
+COMING_UP:
+       The CPU or cluster has committed to moving to the UP state.
+       It may be part way through the process of initialisation and
+       enabling coherency.
+
+UP:
+       The CPU or cluster is active and coherent at the hardware
+       level.  A CPU in this state is not necessarily being used
+       actively by the kernel.
+
+GOING_DOWN:
+       The CPU or cluster has committed to moving to the DOWN
+       state.  It may be part way through the process of teardown and
+       coherency exit.
+
+
+Each CPU has one of these states assigned to it at any point in time.
+The CPU states are described in the "CPU state" section, below.
+
+Each cluster is also assigned a state, but it is necessary to split the
+state value into two parts (the "cluster" state and "inbound" state) and
+to introduce additional states in order to avoid races between different
+CPUs in the cluster simultaneously modifying the state.  The cluster-
+level states are described in the "Cluster state" section.
+
+To help distinguish the CPU states from cluster states in this
+discussion, the state names are given a `CPU_` prefix for the CPU states,
+and a `CLUSTER_` or `INBOUND_` prefix for the cluster states.
+
+
+CPU state
+---------
+
+In this algorithm, each individual core in a multi-core processor is
+referred to as a "CPU".  CPUs are assumed to be single-threaded:
+therefore, a CPU can only be doing one thing at a single point in time.
+
+This means that CPUs fit the basic model closely.
+
+The algorithm defines the following states for each CPU in the system:
+
+       - CPU_DOWN
+       - CPU_COMING_UP
+       - CPU_UP
+       - CPU_GOING_DOWN
+
+::
+
+        cluster setup and
+       CPU setup complete          policy decision
+             +-----------> CPU_UP ------------+
+             |                                v
+
+       CPU_COMING_UP                   CPU_GOING_DOWN
+
+             ^                                |
+             +----------- CPU_DOWN <----------+
+        policy decision           CPU teardown complete
+       or hardware event
+
+
+The definitions of the four states correspond closely to the states of
+the basic model.
+
+Transitions between states occur as follows.
+
+A trigger event (spontaneous) means that the CPU can transition to the
+next state as a result of making local progress only, with no
+requirement for any external event to happen.
+
+
+CPU_DOWN:
+       A CPU reaches the CPU_DOWN state when it is ready for
+       power-down.  On reaching this state, the CPU will typically
+       power itself down or suspend itself, via a WFI instruction or a
+       firmware call.
+
+       Next state:
+               CPU_COMING_UP
+       Conditions:
+               none
+
+       Trigger events:
+               a) an explicit hardware power-up operation, resulting
+                  from a policy decision on another CPU;
+
+               b) a hardware event, such as an interrupt.
+
+
+CPU_COMING_UP:
+       A CPU cannot start participating in hardware coherency until the
+       cluster is set up and coherent.  If the cluster is not ready,
+       then the CPU will wait in the CPU_COMING_UP state until the
+       cluster has been set up.
+
+       Next state:
+               CPU_UP
+       Conditions:
+               The CPU's parent cluster must be in CLUSTER_UP.
+       Trigger events:
+               Transition of the parent cluster to CLUSTER_UP.
+
+       Refer to the "Cluster state" section for a description of the
+       CLUSTER_UP state.
+
+
+CPU_UP:
+       When a CPU reaches the CPU_UP state, it is safe for the CPU to
+       start participating in local coherency.
+
+       This is done by jumping to the kernel's CPU resume code.
+
+       Note that the definition of this state is slightly different
+       from the basic model definition: CPU_UP does not mean that the
+       CPU is coherent yet, but it does mean that it is safe to resume
+       the kernel.  The kernel handles the rest of the resume
+       procedure, so the remaining steps are not visible as part of the
+       race avoidance algorithm.
+
+       The CPU remains in this state until an explicit policy decision
+       is made to shut down or suspend the CPU.
+
+       Next state:
+               CPU_GOING_DOWN
+       Conditions:
+               none
+       Trigger events:
+               explicit policy decision
+
+
+CPU_GOING_DOWN:
+       While in this state, the CPU exits coherency, including any
+       operations required to achieve this (such as cleaning data
+       caches).
+
+       Next state:
+               CPU_DOWN
+       Conditions:
+               local CPU teardown complete
+       Trigger events:
+               (spontaneous)
+
+
+Cluster state
+-------------
+
+A cluster is a group of connected CPUs with some common resources.
+Because a cluster contains multiple CPUs, it can be doing multiple
+things at the same time.  This has some implications.  In particular, a
+CPU can start up while another CPU is tearing the cluster down.
+
+In this discussion, the "outbound side" is the view of the cluster state
+as seen by a CPU tearing the cluster down.  The "inbound side" is the
+view of the cluster state as seen by a CPU setting the CPU up.
+
+In order to enable safe coordination in such situations, it is important
+that a CPU which is setting up the cluster can advertise its state
+independently of the CPU which is tearing down the cluster.  For this
+reason, the cluster state is split into two parts:
+
+       "cluster" state: The global state of the cluster; or the state
+       on the outbound side:
+
+               - CLUSTER_DOWN
+               - CLUSTER_UP
+               - CLUSTER_GOING_DOWN
+
+       "inbound" state: The state of the cluster on the inbound side.
+
+               - INBOUND_NOT_COMING_UP
+               - INBOUND_COMING_UP
+
+
+       The different pairings of these states results in six possible
+       states for the cluster as a whole::
+
+                                   CLUSTER_UP
+                 +==========> INBOUND_NOT_COMING_UP -------------+
+                 #                                               |
+                                                                 |
+            CLUSTER_UP     <----+                                |
+         INBOUND_COMING_UP      |                                v
+
+                 ^             CLUSTER_GOING_DOWN       CLUSTER_GOING_DOWN
+                 #              INBOUND_COMING_UP <=== INBOUND_NOT_COMING_UP
+
+           CLUSTER_DOWN         |                                |
+         INBOUND_COMING_UP <----+                                |
+                                                                 |
+                 ^                                               |
+                 +===========     CLUSTER_DOWN      <------------+
+                              INBOUND_NOT_COMING_UP
+
+       Transitions -----> can only be made by the outbound CPU, and
+       only involve changes to the "cluster" state.
+
+       Transitions ===##> can only be made by the inbound CPU, and only
+       involve changes to the "inbound" state, except where there is no
+       further transition possible on the outbound side (i.e., the
+       outbound CPU has put the cluster into the CLUSTER_DOWN state).
+
+       The race avoidance algorithm does not provide a way to determine
+       which exact CPUs within the cluster play these roles.  This must
+       be decided in advance by some other means.  Refer to the section
+       "Last man and first man selection" for more explanation.
+
+
+       CLUSTER_DOWN/INBOUND_NOT_COMING_UP is the only state where the
+       cluster can actually be powered down.
+
+       The parallelism of the inbound and outbound CPUs is observed by
+       the existence of two different paths from CLUSTER_GOING_DOWN/
+       INBOUND_NOT_COMING_UP (corresponding to GOING_DOWN in the basic
+       model) to CLUSTER_DOWN/INBOUND_COMING_UP (corresponding to
+       COMING_UP in the basic model).  The second path avoids cluster
+       teardown completely.
+
+       CLUSTER_UP/INBOUND_COMING_UP is equivalent to UP in the basic
+       model.  The final transition to CLUSTER_UP/INBOUND_NOT_COMING_UP
+       is trivial and merely resets the state machine ready for the
+       next cycle.
+
+       Details of the allowable transitions follow.
+
+       The next state in each case is notated
+
+               <cluster state>/<inbound state> (<transitioner>)
+
+       where the <transitioner> is the side on which the transition
+       can occur; either the inbound or the outbound side.
+
+
+CLUSTER_DOWN/INBOUND_NOT_COMING_UP:
+       Next state:
+               CLUSTER_DOWN/INBOUND_COMING_UP (inbound)
+       Conditions:
+               none
+
+       Trigger events:
+               a) an explicit hardware power-up operation, resulting
+                  from a policy decision on another CPU;
+
+               b) a hardware event, such as an interrupt.
+
+
+CLUSTER_DOWN/INBOUND_COMING_UP:
+
+       In this state, an inbound CPU sets up the cluster, including
+       enabling of hardware coherency at the cluster level and any
+       other operations (such as cache invalidation) which are required
+       in order to achieve this.
+
+       The purpose of this state is to do sufficient cluster-level
+       setup to enable other CPUs in the cluster to enter coherency
+       safely.
+
+       Next state:
+               CLUSTER_UP/INBOUND_COMING_UP (inbound)
+       Conditions:
+               cluster-level setup and hardware coherency complete
+       Trigger events:
+               (spontaneous)
+
+
+CLUSTER_UP/INBOUND_COMING_UP:
+
+       Cluster-level setup is complete and hardware coherency is
+       enabled for the cluster.  Other CPUs in the cluster can safely
+       enter coherency.
+
+       This is a transient state, leading immediately to
+       CLUSTER_UP/INBOUND_NOT_COMING_UP.  All other CPUs on the cluster
+       should consider treat these two states as equivalent.
+
+       Next state:
+               CLUSTER_UP/INBOUND_NOT_COMING_UP (inbound)
+       Conditions:
+               none
+       Trigger events:
+               (spontaneous)
+
+
+CLUSTER_UP/INBOUND_NOT_COMING_UP:
+
+       Cluster-level setup is complete and hardware coherency is
+       enabled for the cluster.  Other CPUs in the cluster can safely
+       enter coherency.
+
+       The cluster will remain in this state until a policy decision is
+       made to power the cluster down.
+
+       Next state:
+               CLUSTER_GOING_DOWN/INBOUND_NOT_COMING_UP (outbound)
+       Conditions:
+               none
+       Trigger events:
+               policy decision to power down the cluster
+
+
+CLUSTER_GOING_DOWN/INBOUND_NOT_COMING_UP:
+
+       An outbound CPU is tearing the cluster down.  The selected CPU
+       must wait in this state until all CPUs in the cluster are in the
+       CPU_DOWN state.
+
+       When all CPUs are in the CPU_DOWN state, the cluster can be torn
+       down, for example by cleaning data caches and exiting
+       cluster-level coherency.
+
+       To avoid wasteful unnecessary teardown operations, the outbound
+       should check the inbound cluster state for asynchronous
+       transitions to INBOUND_COMING_UP.  Alternatively, individual
+       CPUs can be checked for entry into CPU_COMING_UP or CPU_UP.
+
+
+       Next states:
+
+       CLUSTER_DOWN/INBOUND_NOT_COMING_UP (outbound)
+               Conditions:
+                       cluster torn down and ready to power off
+               Trigger events:
+                       (spontaneous)
+
+       CLUSTER_GOING_DOWN/INBOUND_COMING_UP (inbound)
+               Conditions:
+                       none
+
+               Trigger events:
+                       a) an explicit hardware power-up operation,
+                          resulting from a policy decision on another
+                          CPU;
+
+                       b) a hardware event, such as an interrupt.
+
+
+CLUSTER_GOING_DOWN/INBOUND_COMING_UP:
+
+       The cluster is (or was) being torn down, but another CPU has
+       come online in the meantime and is trying to set up the cluster
+       again.
+
+       If the outbound CPU observes this state, it has two choices:
+
+               a) back out of teardown, restoring the cluster to the
+                  CLUSTER_UP state;
+
+               b) finish tearing the cluster down and put the cluster
+                  in the CLUSTER_DOWN state; the inbound CPU will
+                  set up the cluster again from there.
+
+       Choice (a) permits the removal of some latency by avoiding
+       unnecessary teardown and setup operations in situations where
+       the cluster is not really going to be powered down.
+
+
+       Next states:
+
+       CLUSTER_UP/INBOUND_COMING_UP (outbound)
+               Conditions:
+                               cluster-level setup and hardware
+                               coherency complete
+
+               Trigger events:
+                               (spontaneous)
+
+       CLUSTER_DOWN/INBOUND_COMING_UP (outbound)
+               Conditions:
+                       cluster torn down and ready to power off
+
+               Trigger events:
+                       (spontaneous)
+
+
+Last man and First man selection
+--------------------------------
+
+The CPU which performs cluster tear-down operations on the outbound side
+is commonly referred to as the "last man".
+
+The CPU which performs cluster setup on the inbound side is commonly
+referred to as the "first man".
+
+The race avoidance algorithm documented above does not provide a
+mechanism to choose which CPUs should play these roles.
+
+
+Last man:
+
+When shutting down the cluster, all the CPUs involved are initially
+executing Linux and hence coherent.  Therefore, ordinary spinlocks can
+be used to select a last man safely, before the CPUs become
+non-coherent.
+
+
+First man:
+
+Because CPUs may power up asynchronously in response to external wake-up
+events, a dynamic mechanism is needed to make sure that only one CPU
+attempts to play the first man role and do the cluster-level
+initialisation: any other CPUs must wait for this to complete before
+proceeding.
+
+Cluster-level initialisation may involve actions such as configuring
+coherency controls in the bus fabric.
+
+The current implementation in mcpm_head.S uses a separate mutual exclusion
+mechanism to do this arbitration.  This mechanism is documented in
+detail in vlocks.txt.
+
+
+Features and Limitations
+------------------------
+
+Implementation:
+
+       The current ARM-based implementation is split between
+       arch/arm/common/mcpm_head.S (low-level inbound CPU operations) and
+       arch/arm/common/mcpm_entry.c (everything else):
+
+       __mcpm_cpu_going_down() signals the transition of a CPU to the
+       CPU_GOING_DOWN state.
+
+       __mcpm_cpu_down() signals the transition of a CPU to the CPU_DOWN
+       state.
+
+       A CPU transitions to CPU_COMING_UP and then to CPU_UP via the
+       low-level power-up code in mcpm_head.S.  This could
+       involve CPU-specific setup code, but in the current
+       implementation it does not.
+
+       __mcpm_outbound_enter_critical() and __mcpm_outbound_leave_critical()
+       handle transitions from CLUSTER_UP to CLUSTER_GOING_DOWN
+       and from there to CLUSTER_DOWN or back to CLUSTER_UP (in
+       the case of an aborted cluster power-down).
+
+       These functions are more complex than the __mcpm_cpu_*()
+       functions due to the extra inter-CPU coordination which
+       is needed for safe transitions at the cluster level.
+
+       A cluster transitions from CLUSTER_DOWN back to CLUSTER_UP via
+       the low-level power-up code in mcpm_head.S.  This
+       typically involves platform-specific setup code,
+       provided by the platform-specific power_up_setup
+       function registered via mcpm_sync_init.
+
+Deep topologies:
+
+       As currently described and implemented, the algorithm does not
+       support CPU topologies involving more than two levels (i.e.,
+       clusters of clusters are not supported).  The algorithm could be
+       extended by replicating the cluster-level states for the
+       additional topological levels, and modifying the transition
+       rules for the intermediate (non-outermost) cluster levels.
+
+
+Colophon
+--------
+
+Originally created and documented by Dave Martin for Linaro Limited, in
+collaboration with Nicolas Pitre and Achin Gupta.
+
+Copyright (C) 2012-2013  Linaro Limited
+Distributed under the terms of Version 2 of the GNU General Public
+License, as defined in linux/COPYING.
diff --git a/Documentation/arm/cluster-pm-race-avoidance.txt b/Documentation/arm/cluster-pm-race-avoidance.txt
deleted file mode 100644 (file)
index 750b6fc..0000000
+++ /dev/null
@@ -1,498 +0,0 @@
-Cluster-wide Power-up/power-down race avoidance algorithm
-=========================================================
-
-This file documents the algorithm which is used to coordinate CPU and
-cluster setup and teardown operations and to manage hardware coherency
-controls safely.
-
-The section "Rationale" explains what the algorithm is for and why it is
-needed.  "Basic model" explains general concepts using a simplified view
-of the system.  The other sections explain the actual details of the
-algorithm in use.
-
-
-Rationale
----------
-
-In a system containing multiple CPUs, it is desirable to have the
-ability to turn off individual CPUs when the system is idle, reducing
-power consumption and thermal dissipation.
-
-In a system containing multiple clusters of CPUs, it is also desirable
-to have the ability to turn off entire clusters.
-
-Turning entire clusters off and on is a risky business, because it
-involves performing potentially destructive operations affecting a group
-of independently running CPUs, while the OS continues to run.  This
-means that we need some coordination in order to ensure that critical
-cluster-level operations are only performed when it is truly safe to do
-so.
-
-Simple locking may not be sufficient to solve this problem, because
-mechanisms like Linux spinlocks may rely on coherency mechanisms which
-are not immediately enabled when a cluster powers up.  Since enabling or
-disabling those mechanisms may itself be a non-atomic operation (such as
-writing some hardware registers and invalidating large caches), other
-methods of coordination are required in order to guarantee safe
-power-down and power-up at the cluster level.
-
-The mechanism presented in this document describes a coherent memory
-based protocol for performing the needed coordination.  It aims to be as
-lightweight as possible, while providing the required safety properties.
-
-
-Basic model
------------
-
-Each cluster and CPU is assigned a state, as follows:
-
-       DOWN
-       COMING_UP
-       UP
-       GOING_DOWN
-
-           +---------> UP ----------+
-           |                        v
-
-       COMING_UP                GOING_DOWN
-
-           ^                        |
-           +--------- DOWN <--------+
-
-
-DOWN:  The CPU or cluster is not coherent, and is either powered off or
-       suspended, or is ready to be powered off or suspended.
-
-COMING_UP: The CPU or cluster has committed to moving to the UP state.
-       It may be part way through the process of initialisation and
-       enabling coherency.
-
-UP:    The CPU or cluster is active and coherent at the hardware
-       level.  A CPU in this state is not necessarily being used
-       actively by the kernel.
-
-GOING_DOWN: The CPU or cluster has committed to moving to the DOWN
-       state.  It may be part way through the process of teardown and
-       coherency exit.
-
-
-Each CPU has one of these states assigned to it at any point in time.
-The CPU states are described in the "CPU state" section, below.
-
-Each cluster is also assigned a state, but it is necessary to split the
-state value into two parts (the "cluster" state and "inbound" state) and
-to introduce additional states in order to avoid races between different
-CPUs in the cluster simultaneously modifying the state.  The cluster-
-level states are described in the "Cluster state" section.
-
-To help distinguish the CPU states from cluster states in this
-discussion, the state names are given a CPU_ prefix for the CPU states,
-and a CLUSTER_ or INBOUND_ prefix for the cluster states.
-
-
-CPU state
----------
-
-In this algorithm, each individual core in a multi-core processor is
-referred to as a "CPU".  CPUs are assumed to be single-threaded:
-therefore, a CPU can only be doing one thing at a single point in time.
-
-This means that CPUs fit the basic model closely.
-
-The algorithm defines the following states for each CPU in the system:
-
-       CPU_DOWN
-       CPU_COMING_UP
-       CPU_UP
-       CPU_GOING_DOWN
-
-        cluster setup and
-       CPU setup complete          policy decision
-             +-----------> CPU_UP ------------+
-             |                                v
-
-       CPU_COMING_UP                   CPU_GOING_DOWN
-
-             ^                                |
-             +----------- CPU_DOWN <----------+
-        policy decision           CPU teardown complete
-       or hardware event
-
-
-The definitions of the four states correspond closely to the states of
-the basic model.
-
-Transitions between states occur as follows.
-
-A trigger event (spontaneous) means that the CPU can transition to the
-next state as a result of making local progress only, with no
-requirement for any external event to happen.
-
-
-CPU_DOWN:
-
-       A CPU reaches the CPU_DOWN state when it is ready for
-       power-down.  On reaching this state, the CPU will typically
-       power itself down or suspend itself, via a WFI instruction or a
-       firmware call.
-
-       Next state:     CPU_COMING_UP
-       Conditions:     none
-
-       Trigger events:
-
-               a) an explicit hardware power-up operation, resulting
-                  from a policy decision on another CPU;
-
-               b) a hardware event, such as an interrupt.
-
-
-CPU_COMING_UP:
-
-       A CPU cannot start participating in hardware coherency until the
-       cluster is set up and coherent.  If the cluster is not ready,
-       then the CPU will wait in the CPU_COMING_UP state until the
-       cluster has been set up.
-
-       Next state:     CPU_UP
-       Conditions:     The CPU's parent cluster must be in CLUSTER_UP.
-       Trigger events: Transition of the parent cluster to CLUSTER_UP.
-
-       Refer to the "Cluster state" section for a description of the
-       CLUSTER_UP state.
-
-
-CPU_UP:
-       When a CPU reaches the CPU_UP state, it is safe for the CPU to
-       start participating in local coherency.
-
-       This is done by jumping to the kernel's CPU resume code.
-
-       Note that the definition of this state is slightly different
-       from the basic model definition: CPU_UP does not mean that the
-       CPU is coherent yet, but it does mean that it is safe to resume
-       the kernel.  The kernel handles the rest of the resume
-       procedure, so the remaining steps are not visible as part of the
-       race avoidance algorithm.
-
-       The CPU remains in this state until an explicit policy decision
-       is made to shut down or suspend the CPU.
-
-       Next state:     CPU_GOING_DOWN
-       Conditions:     none
-       Trigger events: explicit policy decision
-
-
-CPU_GOING_DOWN:
-
-       While in this state, the CPU exits coherency, including any
-       operations required to achieve this (such as cleaning data
-       caches).
-
-       Next state:     CPU_DOWN
-       Conditions:     local CPU teardown complete
-       Trigger events: (spontaneous)
-
-
-Cluster state
--------------
-
-A cluster is a group of connected CPUs with some common resources.
-Because a cluster contains multiple CPUs, it can be doing multiple
-things at the same time.  This has some implications.  In particular, a
-CPU can start up while another CPU is tearing the cluster down.
-
-In this discussion, the "outbound side" is the view of the cluster state
-as seen by a CPU tearing the cluster down.  The "inbound side" is the
-view of the cluster state as seen by a CPU setting the CPU up.
-
-In order to enable safe coordination in such situations, it is important
-that a CPU which is setting up the cluster can advertise its state
-independently of the CPU which is tearing down the cluster.  For this
-reason, the cluster state is split into two parts:
-
-       "cluster" state: The global state of the cluster; or the state
-               on the outbound side:
-
-               CLUSTER_DOWN
-               CLUSTER_UP
-               CLUSTER_GOING_DOWN
-
-       "inbound" state: The state of the cluster on the inbound side.
-
-               INBOUND_NOT_COMING_UP
-               INBOUND_COMING_UP
-
-
-       The different pairings of these states results in six possible
-       states for the cluster as a whole:
-
-                                   CLUSTER_UP
-                 +==========> INBOUND_NOT_COMING_UP -------------+
-                 #                                               |
-                                                                 |
-            CLUSTER_UP     <----+                                |
-         INBOUND_COMING_UP      |                                v
-
-                 ^             CLUSTER_GOING_DOWN       CLUSTER_GOING_DOWN
-                 #              INBOUND_COMING_UP <=== INBOUND_NOT_COMING_UP
-
-           CLUSTER_DOWN         |                                |
-         INBOUND_COMING_UP <----+                                |
-                                                                 |
-                 ^                                               |
-                 +===========     CLUSTER_DOWN      <------------+
-                              INBOUND_NOT_COMING_UP
-
-       Transitions -----> can only be made by the outbound CPU, and
-       only involve changes to the "cluster" state.
-
-       Transitions ===##> can only be made by the inbound CPU, and only
-       involve changes to the "inbound" state, except where there is no
-       further transition possible on the outbound side (i.e., the
-       outbound CPU has put the cluster into the CLUSTER_DOWN state).
-
-       The race avoidance algorithm does not provide a way to determine
-       which exact CPUs within the cluster play these roles.  This must
-       be decided in advance by some other means.  Refer to the section
-       "Last man and first man selection" for more explanation.
-
-
-       CLUSTER_DOWN/INBOUND_NOT_COMING_UP is the only state where the
-       cluster can actually be powered down.
-
-       The parallelism of the inbound and outbound CPUs is observed by
-       the existence of two different paths from CLUSTER_GOING_DOWN/
-       INBOUND_NOT_COMING_UP (corresponding to GOING_DOWN in the basic
-       model) to CLUSTER_DOWN/INBOUND_COMING_UP (corresponding to
-       COMING_UP in the basic model).  The second path avoids cluster
-       teardown completely.
-
-       CLUSTER_UP/INBOUND_COMING_UP is equivalent to UP in the basic
-       model.  The final transition to CLUSTER_UP/INBOUND_NOT_COMING_UP
-       is trivial and merely resets the state machine ready for the
-       next cycle.
-
-       Details of the allowable transitions follow.
-
-       The next state in each case is notated
-
-               <cluster state>/<inbound state> (<transitioner>)
-
-       where the <transitioner> is the side on which the transition
-       can occur; either the inbound or the outbound side.
-
-
-CLUSTER_DOWN/INBOUND_NOT_COMING_UP:
-
-       Next state:     CLUSTER_DOWN/INBOUND_COMING_UP (inbound)
-       Conditions:     none
-       Trigger events:
-
-               a) an explicit hardware power-up operation, resulting
-                  from a policy decision on another CPU;
-
-               b) a hardware event, such as an interrupt.
-
-
-CLUSTER_DOWN/INBOUND_COMING_UP:
-
-       In this state, an inbound CPU sets up the cluster, including
-       enabling of hardware coherency at the cluster level and any
-       other operations (such as cache invalidation) which are required
-       in order to achieve this.
-
-       The purpose of this state is to do sufficient cluster-level
-       setup to enable other CPUs in the cluster to enter coherency
-       safely.
-
-       Next state:     CLUSTER_UP/INBOUND_COMING_UP (inbound)
-       Conditions:     cluster-level setup and hardware coherency complete
-       Trigger events: (spontaneous)
-
-
-CLUSTER_UP/INBOUND_COMING_UP:
-
-       Cluster-level setup is complete and hardware coherency is
-       enabled for the cluster.  Other CPUs in the cluster can safely
-       enter coherency.
-
-       This is a transient state, leading immediately to
-       CLUSTER_UP/INBOUND_NOT_COMING_UP.  All other CPUs on the cluster
-       should consider treat these two states as equivalent.
-
-       Next state:     CLUSTER_UP/INBOUND_NOT_COMING_UP (inbound)
-       Conditions:     none
-       Trigger events: (spontaneous)
-
-
-CLUSTER_UP/INBOUND_NOT_COMING_UP:
-
-       Cluster-level setup is complete and hardware coherency is
-       enabled for the cluster.  Other CPUs in the cluster can safely
-       enter coherency.
-
-       The cluster will remain in this state until a policy decision is
-       made to power the cluster down.
-
-       Next state:     CLUSTER_GOING_DOWN/INBOUND_NOT_COMING_UP (outbound)
-       Conditions:     none
-       Trigger events: policy decision to power down the cluster
-
-
-CLUSTER_GOING_DOWN/INBOUND_NOT_COMING_UP:
-
-       An outbound CPU is tearing the cluster down.  The selected CPU
-       must wait in this state until all CPUs in the cluster are in the
-       CPU_DOWN state.
-
-       When all CPUs are in the CPU_DOWN state, the cluster can be torn
-       down, for example by cleaning data caches and exiting
-       cluster-level coherency.
-
-       To avoid wasteful unnecessary teardown operations, the outbound
-       should check the inbound cluster state for asynchronous
-       transitions to INBOUND_COMING_UP.  Alternatively, individual
-       CPUs can be checked for entry into CPU_COMING_UP or CPU_UP.
-
-
-       Next states:
-
-       CLUSTER_DOWN/INBOUND_NOT_COMING_UP (outbound)
-               Conditions:     cluster torn down and ready to power off
-               Trigger events: (spontaneous)
-
-       CLUSTER_GOING_DOWN/INBOUND_COMING_UP (inbound)
-               Conditions:     none
-               Trigger events:
-
-                       a) an explicit hardware power-up operation,
-                          resulting from a policy decision on another
-                          CPU;
-
-                       b) a hardware event, such as an interrupt.
-
-
-CLUSTER_GOING_DOWN/INBOUND_COMING_UP:
-
-       The cluster is (or was) being torn down, but another CPU has
-       come online in the meantime and is trying to set up the cluster
-       again.
-
-       If the outbound CPU observes this state, it has two choices:
-
-               a) back out of teardown, restoring the cluster to the
-                  CLUSTER_UP state;
-
-               b) finish tearing the cluster down and put the cluster
-                  in the CLUSTER_DOWN state; the inbound CPU will
-                  set up the cluster again from there.
-
-       Choice (a) permits the removal of some latency by avoiding
-       unnecessary teardown and setup operations in situations where
-       the cluster is not really going to be powered down.
-
-
-       Next states:
-
-       CLUSTER_UP/INBOUND_COMING_UP (outbound)
-               Conditions:     cluster-level setup and hardware
-                               coherency complete
-               Trigger events: (spontaneous)
-
-       CLUSTER_DOWN/INBOUND_COMING_UP (outbound)
-               Conditions:     cluster torn down and ready to power off
-               Trigger events: (spontaneous)
-
-
-Last man and First man selection
---------------------------------
-
-The CPU which performs cluster tear-down operations on the outbound side
-is commonly referred to as the "last man".
-
-The CPU which performs cluster setup on the inbound side is commonly
-referred to as the "first man".
-
-The race avoidance algorithm documented above does not provide a
-mechanism to choose which CPUs should play these roles.
-
-
-Last man:
-
-When shutting down the cluster, all the CPUs involved are initially
-executing Linux and hence coherent.  Therefore, ordinary spinlocks can
-be used to select a last man safely, before the CPUs become
-non-coherent.
-
-
-First man:
-
-Because CPUs may power up asynchronously in response to external wake-up
-events, a dynamic mechanism is needed to make sure that only one CPU
-attempts to play the first man role and do the cluster-level
-initialisation: any other CPUs must wait for this to complete before
-proceeding.
-
-Cluster-level initialisation may involve actions such as configuring
-coherency controls in the bus fabric.
-
-The current implementation in mcpm_head.S uses a separate mutual exclusion
-mechanism to do this arbitration.  This mechanism is documented in
-detail in vlocks.txt.
-
-
-Features and Limitations
-------------------------
-
-Implementation:
-
-       The current ARM-based implementation is split between
-       arch/arm/common/mcpm_head.S (low-level inbound CPU operations) and
-       arch/arm/common/mcpm_entry.c (everything else):
-
-       __mcpm_cpu_going_down() signals the transition of a CPU to the
-               CPU_GOING_DOWN state.
-
-       __mcpm_cpu_down() signals the transition of a CPU to the CPU_DOWN
-               state.
-
-       A CPU transitions to CPU_COMING_UP and then to CPU_UP via the
-               low-level power-up code in mcpm_head.S.  This could
-               involve CPU-specific setup code, but in the current
-               implementation it does not.
-
-       __mcpm_outbound_enter_critical() and __mcpm_outbound_leave_critical()
-               handle transitions from CLUSTER_UP to CLUSTER_GOING_DOWN
-               and from there to CLUSTER_DOWN or back to CLUSTER_UP (in
-               the case of an aborted cluster power-down).
-
-               These functions are more complex than the __mcpm_cpu_*()
-               functions due to the extra inter-CPU coordination which
-               is needed for safe transitions at the cluster level.
-
-       A cluster transitions from CLUSTER_DOWN back to CLUSTER_UP via
-               the low-level power-up code in mcpm_head.S.  This
-               typically involves platform-specific setup code,
-               provided by the platform-specific power_up_setup
-               function registered via mcpm_sync_init.
-
-Deep topologies:
-
-       As currently described and implemented, the algorithm does not
-       support CPU topologies involving more than two levels (i.e.,
-       clusters of clusters are not supported).  The algorithm could be
-       extended by replicating the cluster-level states for the
-       additional topological levels, and modifying the transition
-       rules for the intermediate (non-outermost) cluster levels.
-
-
-Colophon
---------
-
-Originally created and documented by Dave Martin for Linaro Limited, in
-collaboration with Nicolas Pitre and Achin Gupta.
-
-Copyright (C) 2012-2013  Linaro Limited
-Distributed under the terms of Version 2 of the GNU General Public
-License, as defined in linux/COPYING.
diff --git a/Documentation/arm/firmware.rst b/Documentation/arm/firmware.rst
new file mode 100644 (file)
index 0000000..efd844b
--- /dev/null
@@ -0,0 +1,72 @@
+==========================================================================
+Interface for registering and calling firmware-specific operations for ARM
+==========================================================================
+
+Written by Tomasz Figa <t.figa@samsung.com>
+
+Some boards are running with secure firmware running in TrustZone secure
+world, which changes the way some things have to be initialized. This makes
+a need to provide an interface for such platforms to specify available firmware
+operations and call them when needed.
+
+Firmware operations can be specified by filling in a struct firmware_ops
+with appropriate callbacks and then registering it with register_firmware_ops()
+function::
+
+       void register_firmware_ops(const struct firmware_ops *ops)
+
+The ops pointer must be non-NULL. More information about struct firmware_ops
+and its members can be found in arch/arm/include/asm/firmware.h header.
+
+There is a default, empty set of operations provided, so there is no need to
+set anything if platform does not require firmware operations.
+
+To call a firmware operation, a helper macro is provided::
+
+       #define call_firmware_op(op, ...)                               \
+               ((firmware_ops->op) ? firmware_ops->op(__VA_ARGS__) : (-ENOSYS))
+
+the macro checks if the operation is provided and calls it or otherwise returns
+-ENOSYS to signal that given operation is not available (for example, to allow
+fallback to legacy operation).
+
+Example of registering firmware operations::
+
+       /* board file */
+
+       static int platformX_do_idle(void)
+       {
+               /* tell platformX firmware to enter idle */
+               return 0;
+       }
+
+       static int platformX_cpu_boot(int i)
+       {
+               /* tell platformX firmware to boot CPU i */
+               return 0;
+       }
+
+       static const struct firmware_ops platformX_firmware_ops = {
+               .do_idle        = exynos_do_idle,
+               .cpu_boot       = exynos_cpu_boot,
+               /* other operations not available on platformX */
+       };
+
+       /* init_early callback of machine descriptor */
+       static void __init board_init_early(void)
+       {
+               register_firmware_ops(&platformX_firmware_ops);
+       }
+
+Example of using a firmware operation::
+
+       /* some platform code, e.g. SMP initialization */
+
+       __raw_writel(__pa_symbol(exynos4_secondary_startup),
+               CPU1_BOOT_REG);
+
+       /* Call Exynos specific smc call */
+       if (call_firmware_op(cpu_boot, cpu) == -ENOSYS)
+               cpu_boot_legacy(...); /* Try legacy way */
+
+       gic_raise_softirq(cpumask_of(cpu), 1);
diff --git a/Documentation/arm/firmware.txt b/Documentation/arm/firmware.txt
deleted file mode 100644 (file)
index 7f175db..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-Interface for registering and calling firmware-specific operations for ARM.
-----
-Written by Tomasz Figa <t.figa@samsung.com>
-
-Some boards are running with secure firmware running in TrustZone secure
-world, which changes the way some things have to be initialized. This makes
-a need to provide an interface for such platforms to specify available firmware
-operations and call them when needed.
-
-Firmware operations can be specified by filling in a struct firmware_ops
-with appropriate callbacks and then registering it with register_firmware_ops()
-function.
-
-       void register_firmware_ops(const struct firmware_ops *ops)
-
-The ops pointer must be non-NULL. More information about struct firmware_ops
-and its members can be found in arch/arm/include/asm/firmware.h header.
-
-There is a default, empty set of operations provided, so there is no need to
-set anything if platform does not require firmware operations.
-
-To call a firmware operation, a helper macro is provided
-
-       #define call_firmware_op(op, ...)                               \
-               ((firmware_ops->op) ? firmware_ops->op(__VA_ARGS__) : (-ENOSYS))
-
-the macro checks if the operation is provided and calls it or otherwise returns
--ENOSYS to signal that given operation is not available (for example, to allow
-fallback to legacy operation).
-
-Example of registering firmware operations:
-
-       /* board file */
-
-       static int platformX_do_idle(void)
-       {
-               /* tell platformX firmware to enter idle */
-               return 0;
-       }
-
-       static int platformX_cpu_boot(int i)
-       {
-               /* tell platformX firmware to boot CPU i */
-               return 0;
-       }
-
-       static const struct firmware_ops platformX_firmware_ops = {
-               .do_idle        = exynos_do_idle,
-               .cpu_boot       = exynos_cpu_boot,
-               /* other operations not available on platformX */
-       };
-
-       /* init_early callback of machine descriptor */
-       static void __init board_init_early(void)
-       {
-               register_firmware_ops(&platformX_firmware_ops);
-       }
-
-Example of using a firmware operation:
-
-       /* some platform code, e.g. SMP initialization */
-
-       __raw_writel(__pa_symbol(exynos4_secondary_startup),
-               CPU1_BOOT_REG);
-
-       /* Call Exynos specific smc call */
-       if (call_firmware_op(cpu_boot, cpu) == -ENOSYS)
-               cpu_boot_legacy(...); /* Try legacy way */
-
-       gic_raise_softirq(cpumask_of(cpu), 1);
diff --git a/Documentation/arm/index.rst b/Documentation/arm/index.rst
new file mode 100644 (file)
index 0000000..5fc072d
--- /dev/null
@@ -0,0 +1,80 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+================
+ARM Architecture
+================
+
+.. toctree::
+   :maxdepth: 1
+
+   arm
+   booting
+   cluster-pm-race-avoidance
+   firmware
+   interrupts
+   kernel_mode_neon
+   kernel_user_helpers
+   memory
+   mem_alignment
+   tcm
+   setup
+   swp_emulation
+   uefi
+   vlocks
+   porting
+
+SoC-specific documents
+======================
+
+.. toctree::
+   :maxdepth: 1
+
+   ixp4xx
+
+   marvel
+   microchip
+
+   netwinder
+   nwfpe/index
+
+   keystone/overview
+   keystone/knav-qmss
+
+   omap/index
+
+   pxa/mfp
+
+
+   sa1100/index
+
+   stm32/stm32f746-overview
+   stm32/overview
+   stm32/stm32h743-overview
+   stm32/stm32f769-overview
+   stm32/stm32f429-overview
+   stm32/stm32mp157-overview
+
+   sunxi
+
+   samsung/index
+   samsung-s3c24xx/index
+
+   sunxi/clocks
+
+   spear/overview
+
+   sti/stih416-overview
+   sti/stih407-overview
+   sti/stih418-overview
+   sti/overview
+   sti/stih415-overview
+
+   vfp/release-notes
+
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
diff --git a/Documentation/arm/interrupts.rst b/Documentation/arm/interrupts.rst
new file mode 100644 (file)
index 0000000..2ae70e0
--- /dev/null
@@ -0,0 +1,169 @@
+==========
+Interrupts
+==========
+
+2.5.2-rmk5:
+  This is the first kernel that contains a major shake up of some of the
+  major architecture-specific subsystems.
+
+Firstly, it contains some pretty major changes to the way we handle the
+MMU TLB.  Each MMU TLB variant is now handled completely separately -
+we have TLB v3, TLB v4 (without write buffer), TLB v4 (with write buffer),
+and finally TLB v4 (with write buffer, with I TLB invalidate entry).
+There is more assembly code inside each of these functions, mainly to
+allow more flexible TLB handling for the future.
+
+Secondly, the IRQ subsystem.
+
+The 2.5 kernels will be having major changes to the way IRQs are handled.
+Unfortunately, this means that machine types that touch the irq_desc[]
+array (basically all machine types) will break, and this means every
+machine type that we currently have.
+
+Lets take an example.  On the Assabet with Neponset, we have::
+
+                  GPIO25                 IRR:2
+        SA1100 ------------> Neponset -----------> SA1111
+                                         IIR:1
+                                      -----------> USAR
+                                         IIR:0
+                                      -----------> SMC9196
+
+The way stuff currently works, all SA1111 interrupts are mutually
+exclusive of each other - if you're processing one interrupt from the
+SA1111 and another comes in, you have to wait for that interrupt to
+finish processing before you can service the new interrupt.  Eg, an
+IDE PIO-based interrupt on the SA1111 excludes all other SA1111 and
+SMC9196 interrupts until it has finished transferring its multi-sector
+data, which can be a long time.  Note also that since we loop in the
+SA1111 IRQ handler, SA1111 IRQs can hold off SMC9196 IRQs indefinitely.
+
+
+The new approach brings several new ideas...
+
+We introduce the concept of a "parent" and a "child".  For example,
+to the Neponset handler, the "parent" is GPIO25, and the "children"d
+are SA1111, SMC9196 and USAR.
+
+We also bring the idea of an IRQ "chip" (mainly to reduce the size of
+the irqdesc array).  This doesn't have to be a real "IC"; indeed the
+SA11x0 IRQs are handled by two separate "chip" structures, one for
+GPIO0-10, and another for all the rest.  It is just a container for
+the various operations (maybe this'll change to a better name).
+This structure has the following operations::
+
+  struct irqchip {
+          /*
+           * Acknowledge the IRQ.
+           * If this is a level-based IRQ, then it is expected to mask the IRQ
+           * as well.
+           */
+          void (*ack)(unsigned int irq);
+          /*
+           * Mask the IRQ in hardware.
+           */
+          void (*mask)(unsigned int irq);
+          /*
+           * Unmask the IRQ in hardware.
+           */
+          void (*unmask)(unsigned int irq);
+          /*
+           * Re-run the IRQ
+           */
+          void (*rerun)(unsigned int irq);
+          /*
+           * Set the type of the IRQ.
+           */
+          int (*type)(unsigned int irq, unsigned int, type);
+  };
+
+ack
+       - required.  May be the same function as mask for IRQs
+         handled by do_level_IRQ.
+mask
+       - required.
+unmask
+       - required.
+rerun
+       - optional.  Not required if you're using do_level_IRQ for all
+         IRQs that use this 'irqchip'.  Generally expected to re-trigger
+         the hardware IRQ if possible.  If not, may call the handler
+        directly.
+type
+       - optional.  If you don't support changing the type of an IRQ,
+         it should be null so people can detect if they are unable to
+         set the IRQ type.
+
+For each IRQ, we keep the following information:
+
+        - "disable" depth (number of disable_irq()s without enable_irq()s)
+        - flags indicating what we can do with this IRQ (valid, probe,
+          noautounmask) as before
+        - status of the IRQ (probing, enable, etc)
+        - chip
+        - per-IRQ handler
+        - irqaction structure list
+
+The handler can be one of the 3 standard handlers - "level", "edge" and
+"simple", or your own specific handler if you need to do something special.
+
+The "level" handler is what we currently have - its pretty simple.
+"edge" knows about the brokenness of such IRQ implementations - that you
+need to leave the hardware IRQ enabled while processing it, and queueing
+further IRQ events should the IRQ happen again while processing.  The
+"simple" handler is very basic, and does not perform any hardware
+manipulation, nor state tracking.  This is useful for things like the
+SMC9196 and USAR above.
+
+So, what's changed?
+===================
+
+1. Machine implementations must not write to the irqdesc array.
+
+2. New functions to manipulate the irqdesc array.  The first 4 are expected
+   to be useful only to machine specific code.  The last is recommended to
+   only be used by machine specific code, but may be used in drivers if
+   absolutely necessary.
+
+        set_irq_chip(irq,chip)
+                Set the mask/unmask methods for handling this IRQ
+
+        set_irq_handler(irq,handler)
+                Set the handler for this IRQ (level, edge, simple)
+
+        set_irq_chained_handler(irq,handler)
+                Set a "chained" handler for this IRQ - automatically
+                enables this IRQ (eg, Neponset and SA1111 handlers).
+
+        set_irq_flags(irq,flags)
+                Set the valid/probe/noautoenable flags.
+
+        set_irq_type(irq,type)
+                Set active the IRQ edge(s)/level.  This replaces the
+                SA1111 INTPOL manipulation, and the set_GPIO_IRQ_edge()
+                function.  Type should be one of IRQ_TYPE_xxx defined in
+               <linux/irq.h>
+
+3. set_GPIO_IRQ_edge() is obsolete, and should be replaced by set_irq_type.
+
+4. Direct access to SA1111 INTPOL is deprecated.  Use set_irq_type instead.
+
+5. A handler is expected to perform any necessary acknowledgement of the
+   parent IRQ via the correct chip specific function.  For instance, if
+   the SA1111 is directly connected to a SA1110 GPIO, then you should
+   acknowledge the SA1110 IRQ each time you re-read the SA1111 IRQ status.
+
+6. For any child which doesn't have its own IRQ enable/disable controls
+   (eg, SMC9196), the handler must mask or acknowledge the parent IRQ
+   while the child handler is called, and the child handler should be the
+   "simple" handler (not "edge" nor "level").  After the handler completes,
+   the parent IRQ should be unmasked, and the status of all children must
+   be re-checked for pending events.  (see the Neponset IRQ handler for
+   details).
+
+7. fixup_irq() is gone, as is `arch/arm/mach-*/include/mach/irq.h`
+
+Please note that this will not solve all problems - some of them are
+hardware based.  Mixing level-based and edge-based IRQs on the same
+parent signal (eg neponset) is one such area where a software based
+solution can't provide the full answer to low IRQ latency.
diff --git a/Documentation/arm/ixp4xx.rst b/Documentation/arm/ixp4xx.rst
new file mode 100644 (file)
index 0000000..a572356
--- /dev/null
@@ -0,0 +1,173 @@
+===========================================================
+Release Notes for Linux on Intel's IXP4xx Network Processor
+===========================================================
+
+Maintained by Deepak Saxena <dsaxena@plexity.net>
+-------------------------------------------------------------------------
+
+1. Overview
+
+Intel's IXP4xx network processor is a highly integrated SOC that
+is targeted for network applications, though it has become popular
+in industrial control and other areas due to low cost and power
+consumption. The IXP4xx family currently consists of several processors
+that support different network offload functions such as encryption,
+routing, firewalling, etc. The IXP46x family is an updated version which
+supports faster speeds, new memory and flash configurations, and more
+integration such as an on-chip I2C controller.
+
+For more information on the various versions of the CPU, see:
+
+   http://developer.intel.com/design/network/products/npfamily/ixp4xx.htm
+
+Intel also made the IXCP1100 CPU for sometime which is an IXP4xx
+stripped of much of the network intelligence.
+
+2. Linux Support
+
+Linux currently supports the following features on the IXP4xx chips:
+
+- Dual serial ports
+- PCI interface
+- Flash access (MTD/JFFS)
+- I2C through GPIO on IXP42x
+- GPIO for input/output/interrupts
+  See arch/arm/mach-ixp4xx/include/mach/platform.h for access functions.
+- Timers (watchdog, OS)
+
+The following components of the chips are not supported by Linux and
+require the use of Intel's proprietary CSR software:
+
+- USB device interface
+- Network interfaces (HSS, Utopia, NPEs, etc)
+- Network offload functionality
+
+If you need to use any of the above, you need to download Intel's
+software from:
+
+   http://developer.intel.com/design/network/products/npfamily/ixp425.htm
+
+DO NOT POST QUESTIONS TO THE LINUX MAILING LISTS REGARDING THE PROPRIETARY
+SOFTWARE.
+
+There are several websites that provide directions/pointers on using
+Intel's software:
+
+   - http://sourceforge.net/projects/ixp4xx-osdg/
+     Open Source Developer's Guide for using uClinux and the Intel libraries
+
+   - http://gatewaymaker.sourceforge.net/
+     Simple one page summary of building a gateway using an IXP425 and Linux
+
+   - http://ixp425.sourceforge.net/
+     ATM device driver for IXP425 that relies on Intel's libraries
+
+3. Known Issues/Limitations
+
+3a. Limited inbound PCI window
+
+The IXP4xx family allows for up to 256MB of memory but the PCI interface
+can only expose 64MB of that memory to the PCI bus. This means that if
+you are running with > 64MB, all PCI buffers outside of the accessible
+range will be bounced using the routines in arch/arm/common/dmabounce.c.
+
+3b. Limited outbound PCI window
+
+IXP4xx provides two methods of accessing PCI memory space:
+
+1) A direct mapped window from 0x48000000 to 0x4bffffff (64MB).
+   To access PCI via this space, we simply ioremap() the BAR
+   into the kernel and we can use the standard read[bwl]/write[bwl]
+   macros. This is the preffered method due to speed but it
+   limits the system to just 64MB of PCI memory. This can be
+   problamatic if using video cards and other memory-heavy devices.
+
+2) If > 64MB of memory space is required, the IXP4xx can be
+   configured to use indirect registers to access PCI This allows
+   for up to 128MB (0x48000000 to 0x4fffffff) of memory on the bus.
+   The disadvantage of this is that every PCI access requires
+   three local register accesses plus a spinlock, but in some
+   cases the performance hit is acceptable. In addition, you cannot
+   mmap() PCI devices in this case due to the indirect nature
+   of the PCI window.
+
+By default, the direct method is used for performance reasons. If
+you need more PCI memory, enable the IXP4XX_INDIRECT_PCI config option.
+
+3c. GPIO as Interrupts
+
+Currently the code only handles level-sensitive GPIO interrupts
+
+4. Supported platforms
+
+ADI Engineering Coyote Gateway Reference Platform
+http://www.adiengineering.com/productsCoyote.html
+
+   The ADI Coyote platform is reference design for those building
+   small residential/office gateways. One NPE is connected to a 10/100
+   interface, one to 4-port 10/100 switch, and the third to and ADSL
+   interface. In addition, it also supports to POTs interfaces connected
+   via SLICs. Note that those are not supported by Linux ATM. Finally,
+   the platform has two mini-PCI slots used for 802.11[bga] cards.
+   Finally, there is an IDE port hanging off the expansion bus.
+
+Gateworks Avila Network Platform
+http://www.gateworks.com/support/overview.php
+
+   The Avila platform is basically and IXDP425 with the 4 PCI slots
+   replaced with mini-PCI slots and a CF IDE interface hanging off
+   the expansion bus.
+
+Intel IXDP425 Development Platform
+http://www.intel.com/design/network/products/npfamily/ixdpg425.htm
+
+   This is Intel's standard reference platform for the IXDP425 and is
+   also known as the Richfield board. It contains 4 PCI slots, 16MB
+   of flash, two 10/100 ports and one ADSL port.
+
+Intel IXDP465 Development Platform
+http://www.intel.com/design/network/products/npfamily/ixdp465.htm
+
+   This is basically an IXDP425 with an IXP465 and 32M of flash instead
+   of just 16.
+
+Intel IXDPG425 Development Platform
+
+   This is basically and ADI Coyote board with a NEC EHCI controller
+   added. One issue with this board is that the mini-PCI slots only
+   have the 3.3v line connected, so you can't use a PCI to mini-PCI
+   adapter with an E100 card. So to NFS root you need to use either
+   the CSR or a WiFi card and a ramdisk that BOOTPs and then does
+   a pivot_root to NFS.
+
+Motorola PrPMC1100 Processor Mezanine Card
+http://www.fountainsys.com
+
+   The PrPMC1100 is based on the IXCP1100 and is meant to plug into
+   and IXP2400/2800 system to act as the system controller. It simply
+   contains a CPU and 16MB of flash on the board and needs to be
+   plugged into a carrier board to function. Currently Linux only
+   supports the Motorola PrPMC carrier board for this platform.
+
+5. TODO LIST
+
+- Add support for Coyote IDE
+- Add support for edge-based GPIO interrupts
+- Add support for CF IDE on expansion bus
+
+6. Thanks
+
+The IXP4xx work has been funded by Intel Corp. and MontaVista Software, Inc.
+
+The following people have contributed patches/comments/etc:
+
+- Lennerty Buytenhek
+- Lutz Jaenicke
+- Justin Mayfield
+- Robert E. Ranslam
+
+[I know I've forgotten others, please email me to be added]
+
+-------------------------------------------------------------------------
+
+Last Update: 01/04/2005
diff --git a/Documentation/arm/kernel_mode_neon.rst b/Documentation/arm/kernel_mode_neon.rst
new file mode 100644 (file)
index 0000000..9bfb71a
--- /dev/null
@@ -0,0 +1,124 @@
+================
+Kernel mode NEON
+================
+
+TL;DR summary
+-------------
+* Use only NEON instructions, or VFP instructions that don't rely on support
+  code
+* Isolate your NEON code in a separate compilation unit, and compile it with
+  '-march=armv7-a -mfpu=neon -mfloat-abi=softfp'
+* Put kernel_neon_begin() and kernel_neon_end() calls around the calls into your
+  NEON code
+* Don't sleep in your NEON code, and be aware that it will be executed with
+  preemption disabled
+
+
+Introduction
+------------
+It is possible to use NEON instructions (and in some cases, VFP instructions) in
+code that runs in kernel mode. However, for performance reasons, the NEON/VFP
+register file is not preserved and restored at every context switch or taken
+exception like the normal register file is, so some manual intervention is
+required. Furthermore, special care is required for code that may sleep [i.e.,
+may call schedule()], as NEON or VFP instructions will be executed in a
+non-preemptible section for reasons outlined below.
+
+
+Lazy preserve and restore
+-------------------------
+The NEON/VFP register file is managed using lazy preserve (on UP systems) and
+lazy restore (on both SMP and UP systems). This means that the register file is
+kept 'live', and is only preserved and restored when multiple tasks are
+contending for the NEON/VFP unit (or, in the SMP case, when a task migrates to
+another core). Lazy restore is implemented by disabling the NEON/VFP unit after
+every context switch, resulting in a trap when subsequently a NEON/VFP
+instruction is issued, allowing the kernel to step in and perform the restore if
+necessary.
+
+Any use of the NEON/VFP unit in kernel mode should not interfere with this, so
+it is required to do an 'eager' preserve of the NEON/VFP register file, and
+enable the NEON/VFP unit explicitly so no exceptions are generated on first
+subsequent use. This is handled by the function kernel_neon_begin(), which
+should be called before any kernel mode NEON or VFP instructions are issued.
+Likewise, the NEON/VFP unit should be disabled again after use to make sure user
+mode will hit the lazy restore trap upon next use. This is handled by the
+function kernel_neon_end().
+
+
+Interruptions in kernel mode
+----------------------------
+For reasons of performance and simplicity, it was decided that there shall be no
+preserve/restore mechanism for the kernel mode NEON/VFP register contents. This
+implies that interruptions of a kernel mode NEON section can only be allowed if
+they are guaranteed not to touch the NEON/VFP registers. For this reason, the
+following rules and restrictions apply in the kernel:
+* NEON/VFP code is not allowed in interrupt context;
+* NEON/VFP code is not allowed to sleep;
+* NEON/VFP code is executed with preemption disabled.
+
+If latency is a concern, it is possible to put back to back calls to
+kernel_neon_end() and kernel_neon_begin() in places in your code where none of
+the NEON registers are live. (Additional calls to kernel_neon_begin() should be
+reasonably cheap if no context switch occurred in the meantime)
+
+
+VFP and support code
+--------------------
+Earlier versions of VFP (prior to version 3) rely on software support for things
+like IEEE-754 compliant underflow handling etc. When the VFP unit needs such
+software assistance, it signals the kernel by raising an undefined instruction
+exception. The kernel responds by inspecting the VFP control registers and the
+current instruction and arguments, and emulates the instruction in software.
+
+Such software assistance is currently not implemented for VFP instructions
+executed in kernel mode. If such a condition is encountered, the kernel will
+fail and generate an OOPS.
+
+
+Separating NEON code from ordinary code
+---------------------------------------
+The compiler is not aware of the special significance of kernel_neon_begin() and
+kernel_neon_end(), i.e., that it is only allowed to issue NEON/VFP instructions
+between calls to these respective functions. Furthermore, GCC may generate NEON
+instructions of its own at -O3 level if -mfpu=neon is selected, and even if the
+kernel is currently compiled at -O2, future changes may result in NEON/VFP
+instructions appearing in unexpected places if no special care is taken.
+
+Therefore, the recommended and only supported way of using NEON/VFP in the
+kernel is by adhering to the following rules:
+
+* isolate the NEON code in a separate compilation unit and compile it with
+  '-march=armv7-a -mfpu=neon -mfloat-abi=softfp';
+* issue the calls to kernel_neon_begin(), kernel_neon_end() as well as the calls
+  into the unit containing the NEON code from a compilation unit which is *not*
+  built with the GCC flag '-mfpu=neon' set.
+
+As the kernel is compiled with '-msoft-float', the above will guarantee that
+both NEON and VFP instructions will only ever appear in designated compilation
+units at any optimization level.
+
+
+NEON assembler
+--------------
+NEON assembler is supported with no additional caveats as long as the rules
+above are followed.
+
+
+NEON code generated by GCC
+--------------------------
+The GCC option -ftree-vectorize (implied by -O3) tries to exploit implicit
+parallelism, and generates NEON code from ordinary C source code. This is fully
+supported as long as the rules above are followed.
+
+
+NEON intrinsics
+---------------
+NEON intrinsics are also supported. However, as code using NEON intrinsics
+relies on the GCC header <arm_neon.h>, (which #includes <stdint.h>), you should
+observe the following in addition to the rules above:
+
+* Compile the unit containing the NEON intrinsics with '-ffreestanding' so GCC
+  uses its builtin version of <stdint.h> (this is a C99 header which the kernel
+  does not supply);
+* Include <arm_neon.h> last, or at least after <linux/types.h>
diff --git a/Documentation/arm/kernel_mode_neon.txt b/Documentation/arm/kernel_mode_neon.txt
deleted file mode 100644 (file)
index b9e060c..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-Kernel mode NEON
-================
-
-TL;DR summary
--------------
-* Use only NEON instructions, or VFP instructions that don't rely on support
-  code
-* Isolate your NEON code in a separate compilation unit, and compile it with
-  '-march=armv7-a -mfpu=neon -mfloat-abi=softfp'
-* Put kernel_neon_begin() and kernel_neon_end() calls around the calls into your
-  NEON code
-* Don't sleep in your NEON code, and be aware that it will be executed with
-  preemption disabled
-
-
-Introduction
-------------
-It is possible to use NEON instructions (and in some cases, VFP instructions) in
-code that runs in kernel mode. However, for performance reasons, the NEON/VFP
-register file is not preserved and restored at every context switch or taken
-exception like the normal register file is, so some manual intervention is
-required. Furthermore, special care is required for code that may sleep [i.e.,
-may call schedule()], as NEON or VFP instructions will be executed in a
-non-preemptible section for reasons outlined below.
-
-
-Lazy preserve and restore
--------------------------
-The NEON/VFP register file is managed using lazy preserve (on UP systems) and
-lazy restore (on both SMP and UP systems). This means that the register file is
-kept 'live', and is only preserved and restored when multiple tasks are
-contending for the NEON/VFP unit (or, in the SMP case, when a task migrates to
-another core). Lazy restore is implemented by disabling the NEON/VFP unit after
-every context switch, resulting in a trap when subsequently a NEON/VFP
-instruction is issued, allowing the kernel to step in and perform the restore if
-necessary.
-
-Any use of the NEON/VFP unit in kernel mode should not interfere with this, so
-it is required to do an 'eager' preserve of the NEON/VFP register file, and
-enable the NEON/VFP unit explicitly so no exceptions are generated on first
-subsequent use. This is handled by the function kernel_neon_begin(), which
-should be called before any kernel mode NEON or VFP instructions are issued.
-Likewise, the NEON/VFP unit should be disabled again after use to make sure user
-mode will hit the lazy restore trap upon next use. This is handled by the
-function kernel_neon_end().
-
-
-Interruptions in kernel mode
-----------------------------
-For reasons of performance and simplicity, it was decided that there shall be no
-preserve/restore mechanism for the kernel mode NEON/VFP register contents. This
-implies that interruptions of a kernel mode NEON section can only be allowed if
-they are guaranteed not to touch the NEON/VFP registers. For this reason, the
-following rules and restrictions apply in the kernel:
-* NEON/VFP code is not allowed in interrupt context;
-* NEON/VFP code is not allowed to sleep;
-* NEON/VFP code is executed with preemption disabled.
-
-If latency is a concern, it is possible to put back to back calls to
-kernel_neon_end() and kernel_neon_begin() in places in your code where none of
-the NEON registers are live. (Additional calls to kernel_neon_begin() should be
-reasonably cheap if no context switch occurred in the meantime)
-
-
-VFP and support code
---------------------
-Earlier versions of VFP (prior to version 3) rely on software support for things
-like IEEE-754 compliant underflow handling etc. When the VFP unit needs such
-software assistance, it signals the kernel by raising an undefined instruction
-exception. The kernel responds by inspecting the VFP control registers and the
-current instruction and arguments, and emulates the instruction in software.
-
-Such software assistance is currently not implemented for VFP instructions
-executed in kernel mode. If such a condition is encountered, the kernel will
-fail and generate an OOPS.
-
-
-Separating NEON code from ordinary code
----------------------------------------
-The compiler is not aware of the special significance of kernel_neon_begin() and
-kernel_neon_end(), i.e., that it is only allowed to issue NEON/VFP instructions
-between calls to these respective functions. Furthermore, GCC may generate NEON
-instructions of its own at -O3 level if -mfpu=neon is selected, and even if the
-kernel is currently compiled at -O2, future changes may result in NEON/VFP
-instructions appearing in unexpected places if no special care is taken.
-
-Therefore, the recommended and only supported way of using NEON/VFP in the
-kernel is by adhering to the following rules:
-* isolate the NEON code in a separate compilation unit and compile it with
-  '-march=armv7-a -mfpu=neon -mfloat-abi=softfp';
-* issue the calls to kernel_neon_begin(), kernel_neon_end() as well as the calls
-  into the unit containing the NEON code from a compilation unit which is *not*
-  built with the GCC flag '-mfpu=neon' set.
-
-As the kernel is compiled with '-msoft-float', the above will guarantee that
-both NEON and VFP instructions will only ever appear in designated compilation
-units at any optimization level.
-
-
-NEON assembler
---------------
-NEON assembler is supported with no additional caveats as long as the rules
-above are followed.
-
-
-NEON code generated by GCC
---------------------------
-The GCC option -ftree-vectorize (implied by -O3) tries to exploit implicit
-parallelism, and generates NEON code from ordinary C source code. This is fully
-supported as long as the rules above are followed.
-
-
-NEON intrinsics
----------------
-NEON intrinsics are also supported. However, as code using NEON intrinsics
-relies on the GCC header <arm_neon.h>, (which #includes <stdint.h>), you should
-observe the following in addition to the rules above:
-* Compile the unit containing the NEON intrinsics with '-ffreestanding' so GCC
-  uses its builtin version of <stdint.h> (this is a C99 header which the kernel
-  does not supply);
-* Include <arm_neon.h> last, or at least after <linux/types.h>
diff --git a/Documentation/arm/kernel_user_helpers.rst b/Documentation/arm/kernel_user_helpers.rst
new file mode 100644 (file)
index 0000000..eb6f3d9
--- /dev/null
@@ -0,0 +1,268 @@
+============================
+Kernel-provided User Helpers
+============================
+
+These are segment of kernel provided user code reachable from user space
+at a fixed address in kernel memory.  This is used to provide user space
+with some operations which require kernel help because of unimplemented
+native feature and/or instructions in many ARM CPUs. The idea is for this
+code to be executed directly in user mode for best efficiency but which is
+too intimate with the kernel counter part to be left to user libraries.
+In fact this code might even differ from one CPU to another depending on
+the available instruction set, or whether it is a SMP systems. In other
+words, the kernel reserves the right to change this code as needed without
+warning. Only the entry points and their results as documented here are
+guaranteed to be stable.
+
+This is different from (but doesn't preclude) a full blown VDSO
+implementation, however a VDSO would prevent some assembly tricks with
+constants that allows for efficient branching to those code segments. And
+since those code segments only use a few cycles before returning to user
+code, the overhead of a VDSO indirect far call would add a measurable
+overhead to such minimalistic operations.
+
+User space is expected to bypass those helpers and implement those things
+inline (either in the code emitted directly by the compiler, or part of
+the implementation of a library call) when optimizing for a recent enough
+processor that has the necessary native support, but only if resulting
+binaries are already to be incompatible with earlier ARM processors due to
+usage of similar native instructions for other things.  In other words
+don't make binaries unable to run on earlier processors just for the sake
+of not using these kernel helpers if your compiled code is not going to
+use new instructions for other purpose.
+
+New helpers may be added over time, so an older kernel may be missing some
+helpers present in a newer kernel.  For this reason, programs must check
+the value of __kuser_helper_version (see below) before assuming that it is
+safe to call any particular helper.  This check should ideally be
+performed only once at process startup time, and execution aborted early
+if the required helpers are not provided by the kernel version that
+process is running on.
+
+kuser_helper_version
+--------------------
+
+Location:      0xffff0ffc
+
+Reference declaration::
+
+  extern int32_t __kuser_helper_version;
+
+Definition:
+
+  This field contains the number of helpers being implemented by the
+  running kernel.  User space may read this to determine the availability
+  of a particular helper.
+
+Usage example::
+
+  #define __kuser_helper_version (*(int32_t *)0xffff0ffc)
+
+  void check_kuser_version(void)
+  {
+       if (__kuser_helper_version < 2) {
+               fprintf(stderr, "can't do atomic operations, kernel too old\n");
+               abort();
+       }
+  }
+
+Notes:
+
+  User space may assume that the value of this field never changes
+  during the lifetime of any single process.  This means that this
+  field can be read once during the initialisation of a library or
+  startup phase of a program.
+
+kuser_get_tls
+-------------
+
+Location:      0xffff0fe0
+
+Reference prototype::
+
+  void * __kuser_get_tls(void);
+
+Input:
+
+  lr = return address
+
+Output:
+
+  r0 = TLS value
+
+Clobbered registers:
+
+  none
+
+Definition:
+
+  Get the TLS value as previously set via the __ARM_NR_set_tls syscall.
+
+Usage example::
+
+  typedef void * (__kuser_get_tls_t)(void);
+  #define __kuser_get_tls (*(__kuser_get_tls_t *)0xffff0fe0)
+
+  void foo()
+  {
+       void *tls = __kuser_get_tls();
+       printf("TLS = %p\n", tls);
+  }
+
+Notes:
+
+  - Valid only if __kuser_helper_version >= 1 (from kernel version 2.6.12).
+
+kuser_cmpxchg
+-------------
+
+Location:      0xffff0fc0
+
+Reference prototype::
+
+  int __kuser_cmpxchg(int32_t oldval, int32_t newval, volatile int32_t *ptr);
+
+Input:
+
+  r0 = oldval
+  r1 = newval
+  r2 = ptr
+  lr = return address
+
+Output:
+
+  r0 = success code (zero or non-zero)
+  C flag = set if r0 == 0, clear if r0 != 0
+
+Clobbered registers:
+
+  r3, ip, flags
+
+Definition:
+
+  Atomically store newval in `*ptr` only if `*ptr` is equal to oldval.
+  Return zero if `*ptr` was changed or non-zero if no exchange happened.
+  The C flag is also set if `*ptr` was changed to allow for assembly
+  optimization in the calling code.
+
+Usage example::
+
+  typedef int (__kuser_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
+  #define __kuser_cmpxchg (*(__kuser_cmpxchg_t *)0xffff0fc0)
+
+  int atomic_add(volatile int *ptr, int val)
+  {
+       int old, new;
+
+       do {
+               old = *ptr;
+               new = old + val;
+       } while(__kuser_cmpxchg(old, new, ptr));
+
+       return new;
+  }
+
+Notes:
+
+  - This routine already includes memory barriers as needed.
+
+  - Valid only if __kuser_helper_version >= 2 (from kernel version 2.6.12).
+
+kuser_memory_barrier
+--------------------
+
+Location:      0xffff0fa0
+
+Reference prototype::
+
+  void __kuser_memory_barrier(void);
+
+Input:
+
+  lr = return address
+
+Output:
+
+  none
+
+Clobbered registers:
+
+  none
+
+Definition:
+
+  Apply any needed memory barrier to preserve consistency with data modified
+  manually and __kuser_cmpxchg usage.
+
+Usage example::
+
+  typedef void (__kuser_dmb_t)(void);
+  #define __kuser_dmb (*(__kuser_dmb_t *)0xffff0fa0)
+
+Notes:
+
+  - Valid only if __kuser_helper_version >= 3 (from kernel version 2.6.15).
+
+kuser_cmpxchg64
+---------------
+
+Location:      0xffff0f60
+
+Reference prototype::
+
+  int __kuser_cmpxchg64(const int64_t *oldval,
+                        const int64_t *newval,
+                        volatile int64_t *ptr);
+
+Input:
+
+  r0 = pointer to oldval
+  r1 = pointer to newval
+  r2 = pointer to target value
+  lr = return address
+
+Output:
+
+  r0 = success code (zero or non-zero)
+  C flag = set if r0 == 0, clear if r0 != 0
+
+Clobbered registers:
+
+  r3, lr, flags
+
+Definition:
+
+  Atomically store the 64-bit value pointed by `*newval` in `*ptr` only if `*ptr`
+  is equal to the 64-bit value pointed by `*oldval`.  Return zero if `*ptr` was
+  changed or non-zero if no exchange happened.
+
+  The C flag is also set if `*ptr` was changed to allow for assembly
+  optimization in the calling code.
+
+Usage example::
+
+  typedef int (__kuser_cmpxchg64_t)(const int64_t *oldval,
+                                    const int64_t *newval,
+                                    volatile int64_t *ptr);
+  #define __kuser_cmpxchg64 (*(__kuser_cmpxchg64_t *)0xffff0f60)
+
+  int64_t atomic_add64(volatile int64_t *ptr, int64_t val)
+  {
+       int64_t old, new;
+
+       do {
+               old = *ptr;
+               new = old + val;
+       } while(__kuser_cmpxchg64(&old, &new, ptr));
+
+       return new;
+  }
+
+Notes:
+
+  - This routine already includes memory barriers as needed.
+
+  - Due to the length of this sequence, this spans 2 conventional kuser
+    "slots", therefore 0xffff0f80 is not used as a valid entry point.
+
+  - Valid only if __kuser_helper_version >= 5 (from kernel version 3.1).
diff --git a/Documentation/arm/kernel_user_helpers.txt b/Documentation/arm/kernel_user_helpers.txt
deleted file mode 100644 (file)
index 5673594..0000000
+++ /dev/null
@@ -1,267 +0,0 @@
-Kernel-provided User Helpers
-============================
-
-These are segment of kernel provided user code reachable from user space
-at a fixed address in kernel memory.  This is used to provide user space
-with some operations which require kernel help because of unimplemented
-native feature and/or instructions in many ARM CPUs. The idea is for this
-code to be executed directly in user mode for best efficiency but which is
-too intimate with the kernel counter part to be left to user libraries.
-In fact this code might even differ from one CPU to another depending on
-the available instruction set, or whether it is a SMP systems. In other
-words, the kernel reserves the right to change this code as needed without
-warning. Only the entry points and their results as documented here are
-guaranteed to be stable.
-
-This is different from (but doesn't preclude) a full blown VDSO
-implementation, however a VDSO would prevent some assembly tricks with
-constants that allows for efficient branching to those code segments. And
-since those code segments only use a few cycles before returning to user
-code, the overhead of a VDSO indirect far call would add a measurable
-overhead to such minimalistic operations.
-
-User space is expected to bypass those helpers and implement those things
-inline (either in the code emitted directly by the compiler, or part of
-the implementation of a library call) when optimizing for a recent enough
-processor that has the necessary native support, but only if resulting
-binaries are already to be incompatible with earlier ARM processors due to
-usage of similar native instructions for other things.  In other words
-don't make binaries unable to run on earlier processors just for the sake
-of not using these kernel helpers if your compiled code is not going to
-use new instructions for other purpose.
-
-New helpers may be added over time, so an older kernel may be missing some
-helpers present in a newer kernel.  For this reason, programs must check
-the value of __kuser_helper_version (see below) before assuming that it is
-safe to call any particular helper.  This check should ideally be
-performed only once at process startup time, and execution aborted early
-if the required helpers are not provided by the kernel version that
-process is running on.
-
-kuser_helper_version
---------------------
-
-Location:      0xffff0ffc
-
-Reference declaration:
-
-  extern int32_t __kuser_helper_version;
-
-Definition:
-
-  This field contains the number of helpers being implemented by the
-  running kernel.  User space may read this to determine the availability
-  of a particular helper.
-
-Usage example:
-
-#define __kuser_helper_version (*(int32_t *)0xffff0ffc)
-
-void check_kuser_version(void)
-{
-       if (__kuser_helper_version < 2) {
-               fprintf(stderr, "can't do atomic operations, kernel too old\n");
-               abort();
-       }
-}
-
-Notes:
-
-  User space may assume that the value of this field never changes
-  during the lifetime of any single process.  This means that this
-  field can be read once during the initialisation of a library or
-  startup phase of a program.
-
-kuser_get_tls
--------------
-
-Location:      0xffff0fe0
-
-Reference prototype:
-
-  void * __kuser_get_tls(void);
-
-Input:
-
-  lr = return address
-
-Output:
-
-  r0 = TLS value
-
-Clobbered registers:
-
-  none
-
-Definition:
-
-  Get the TLS value as previously set via the __ARM_NR_set_tls syscall.
-
-Usage example:
-
-typedef void * (__kuser_get_tls_t)(void);
-#define __kuser_get_tls (*(__kuser_get_tls_t *)0xffff0fe0)
-
-void foo()
-{
-       void *tls = __kuser_get_tls();
-       printf("TLS = %p\n", tls);
-}
-
-Notes:
-
-  - Valid only if __kuser_helper_version >= 1 (from kernel version 2.6.12).
-
-kuser_cmpxchg
--------------
-
-Location:      0xffff0fc0
-
-Reference prototype:
-
-  int __kuser_cmpxchg(int32_t oldval, int32_t newval, volatile int32_t *ptr);
-
-Input:
-
-  r0 = oldval
-  r1 = newval
-  r2 = ptr
-  lr = return address
-
-Output:
-
-  r0 = success code (zero or non-zero)
-  C flag = set if r0 == 0, clear if r0 != 0
-
-Clobbered registers:
-
-  r3, ip, flags
-
-Definition:
-
-  Atomically store newval in *ptr only if *ptr is equal to oldval.
-  Return zero if *ptr was changed or non-zero if no exchange happened.
-  The C flag is also set if *ptr was changed to allow for assembly
-  optimization in the calling code.
-
-Usage example:
-
-typedef int (__kuser_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
-#define __kuser_cmpxchg (*(__kuser_cmpxchg_t *)0xffff0fc0)
-
-int atomic_add(volatile int *ptr, int val)
-{
-       int old, new;
-
-       do {
-               old = *ptr;
-               new = old + val;
-       } while(__kuser_cmpxchg(old, new, ptr));
-
-       return new;
-}
-
-Notes:
-
-  - This routine already includes memory barriers as needed.
-
-  - Valid only if __kuser_helper_version >= 2 (from kernel version 2.6.12).
-
-kuser_memory_barrier
---------------------
-
-Location:      0xffff0fa0
-
-Reference prototype:
-
-  void __kuser_memory_barrier(void);
-
-Input:
-
-  lr = return address
-
-Output:
-
-  none
-
-Clobbered registers:
-
-  none
-
-Definition:
-
-  Apply any needed memory barrier to preserve consistency with data modified
-  manually and __kuser_cmpxchg usage.
-
-Usage example:
-
-typedef void (__kuser_dmb_t)(void);
-#define __kuser_dmb (*(__kuser_dmb_t *)0xffff0fa0)
-
-Notes:
-
-  - Valid only if __kuser_helper_version >= 3 (from kernel version 2.6.15).
-
-kuser_cmpxchg64
----------------
-
-Location:      0xffff0f60
-
-Reference prototype:
-
-  int __kuser_cmpxchg64(const int64_t *oldval,
-                        const int64_t *newval,
-                        volatile int64_t *ptr);
-
-Input:
-
-  r0 = pointer to oldval
-  r1 = pointer to newval
-  r2 = pointer to target value
-  lr = return address
-
-Output:
-
-  r0 = success code (zero or non-zero)
-  C flag = set if r0 == 0, clear if r0 != 0
-
-Clobbered registers:
-
-  r3, lr, flags
-
-Definition:
-
-  Atomically store the 64-bit value pointed by *newval in *ptr only if *ptr
-  is equal to the 64-bit value pointed by *oldval.  Return zero if *ptr was
-  changed or non-zero if no exchange happened.
-
-  The C flag is also set if *ptr was changed to allow for assembly
-  optimization in the calling code.
-
-Usage example:
-
-typedef int (__kuser_cmpxchg64_t)(const int64_t *oldval,
-                                  const int64_t *newval,
-                                  volatile int64_t *ptr);
-#define __kuser_cmpxchg64 (*(__kuser_cmpxchg64_t *)0xffff0f60)
-
-int64_t atomic_add64(volatile int64_t *ptr, int64_t val)
-{
-       int64_t old, new;
-
-       do {
-               old = *ptr;
-               new = old + val;
-       } while(__kuser_cmpxchg64(&old, &new, ptr));
-
-       return new;
-}
-
-Notes:
-
-  - This routine already includes memory barriers as needed.
-
-  - Due to the length of this sequence, this spans 2 conventional kuser
-    "slots", therefore 0xffff0f80 is not used as a valid entry point.
-
-  - Valid only if __kuser_helper_version >= 5 (from kernel version 3.1).
diff --git a/Documentation/arm/keystone/Overview.txt b/Documentation/arm/keystone/Overview.txt
deleted file mode 100644 (file)
index 400c0c2..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-               TI Keystone Linux Overview
-               --------------------------
-
-Introduction
-------------
-Keystone range of SoCs are based on ARM Cortex-A15 MPCore Processors
-and c66x DSP cores. This document describes essential information required
-for users to run Linux on Keystone based EVMs from Texas Instruments.
-
-Following SoCs  & EVMs are currently supported:-
-
------------- K2HK SoC and EVM --------------------------------------------------
-
-a.k.a Keystone 2 Hawking/Kepler SoC
-TCI6636K2H & TCI6636K2K: See documentation at
-       http://www.ti.com/product/tci6638k2k
-       http://www.ti.com/product/tci6638k2h
-
-EVM:
-http://www.advantech.com/Support/TI-EVM/EVMK2HX_sd.aspx
-
------------- K2E SoC and EVM ---------------------------------------------------
-
-a.k.a Keystone 2 Edison SoC
-K2E  -  66AK2E05: See documentation at
-       http://www.ti.com/product/66AK2E05/technicaldocuments
-
-EVM:
-https://www.einfochips.com/index.php/partnerships/texas-instruments/k2e-evm.html
-
------------- K2L SoC and EVM ---------------------------------------------------
-
-a.k.a Keystone 2 Lamarr SoC
-K2L  -  TCI6630K2L: See documentation at
-       http://www.ti.com/product/TCI6630K2L/technicaldocuments
-EVM:
-https://www.einfochips.com/index.php/partnerships/texas-instruments/k2l-evm.html
-
-Configuration
--------------
-
-All of the K2 SoCs/EVMs share a common defconfig, keystone_defconfig and same
-image is used to boot on individual EVMs. The platform configuration is
-specified through DTS. Following are the DTS used:-
-       K2HK EVM : k2hk-evm.dts
-       K2E EVM  : k2e-evm.dts
-       K2L EVM  : k2l-evm.dts
-
-The device tree documentation for the keystone machines are located at
-        Documentation/devicetree/bindings/arm/keystone/keystone.txt
-
-Document Author
----------------
-Murali Karicheri <m-karicheri2@ti.com>
-Copyright 2015 Texas Instruments
diff --git a/Documentation/arm/keystone/knav-qmss.rst b/Documentation/arm/keystone/knav-qmss.rst
new file mode 100644 (file)
index 0000000..7f7638d
--- /dev/null
@@ -0,0 +1,60 @@
+======================================================================
+Texas Instruments Keystone Navigator Queue Management SubSystem driver
+======================================================================
+
+Driver source code path
+  drivers/soc/ti/knav_qmss.c
+  drivers/soc/ti/knav_qmss_acc.c
+
+The QMSS (Queue Manager Sub System) found on Keystone SOCs is one of
+the main hardware sub system which forms the backbone of the Keystone
+multi-core Navigator. QMSS consist of queue managers, packed-data structure
+processors(PDSP), linking RAM, descriptor pools and infrastructure
+Packet DMA.
+The Queue Manager is a hardware module that is responsible for accelerating
+management of the packet queues. Packets are queued/de-queued by writing or
+reading descriptor address to a particular memory mapped location. The PDSPs
+perform QMSS related functions like accumulation, QoS, or event management.
+Linking RAM registers are used to link the descriptors which are stored in
+descriptor RAM. Descriptor RAM is configurable as internal or external memory.
+The QMSS driver manages the PDSP setups, linking RAM regions,
+queue pool management (allocation, push, pop and notify) and descriptor
+pool management.
+
+knav qmss driver provides a set of APIs to drivers to open/close qmss queues,
+allocate descriptor pools, map the descriptors, push/pop to queues etc. For
+details of the available APIs, please refers to include/linux/soc/ti/knav_qmss.h
+
+DT documentation is available at
+Documentation/devicetree/bindings/soc/ti/keystone-navigator-qmss.txt
+
+Accumulator QMSS queues using PDSP firmware
+============================================
+The QMSS PDSP firmware support accumulator channel that can monitor a single
+queue or multiple contiguous queues. drivers/soc/ti/knav_qmss_acc.c is the
+driver that interface with the accumulator PDSP. This configures
+accumulator channels defined in DTS (example in DT documentation) to monitor
+1 or 32 queues per channel. More description on the firmware is available in
+CPPI/QMSS Low Level Driver document (docs/CPPI_QMSS_LLD_SDS.pdf) at
+
+       git://git.ti.com/keystone-rtos/qmss-lld.git
+
+k2_qmss_pdsp_acc48_k2_le_1_0_0_9.bin firmware supports upto 48 accumulator
+channels. This firmware is available under ti-keystone folder of
+firmware.git at
+
+   git://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git
+
+To use copy the firmware image to lib/firmware folder of the initramfs or
+ubifs file system and provide a sym link to k2_qmss_pdsp_acc48_k2_le_1_0_0_9.bin
+in the file system and boot up the kernel. User would see
+
+ "firmware file ks2_qmss_pdsp_acc48.bin downloaded for PDSP"
+
+in the boot up log if loading of firmware to PDSP is successful.
+
+Use of accumulated queues requires the firmware image to be present in the
+file system. The driver doesn't acc queues to the supported queue range if
+PDSP is not running in the SoC. The API call fails if there is a queue open
+request to an acc queue and PDSP is not running. So make sure to copy firmware
+to file system before using these queue types.
diff --git a/Documentation/arm/keystone/knav-qmss.txt b/Documentation/arm/keystone/knav-qmss.txt
deleted file mode 100644 (file)
index fcdb9fd..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-* Texas Instruments Keystone Navigator Queue Management SubSystem driver
-
-Driver source code path
-  drivers/soc/ti/knav_qmss.c
-  drivers/soc/ti/knav_qmss_acc.c
-
-The QMSS (Queue Manager Sub System) found on Keystone SOCs is one of
-the main hardware sub system which forms the backbone of the Keystone
-multi-core Navigator. QMSS consist of queue managers, packed-data structure
-processors(PDSP), linking RAM, descriptor pools and infrastructure
-Packet DMA.
-The Queue Manager is a hardware module that is responsible for accelerating
-management of the packet queues. Packets are queued/de-queued by writing or
-reading descriptor address to a particular memory mapped location. The PDSPs
-perform QMSS related functions like accumulation, QoS, or event management.
-Linking RAM registers are used to link the descriptors which are stored in
-descriptor RAM. Descriptor RAM is configurable as internal or external memory.
-The QMSS driver manages the PDSP setups, linking RAM regions,
-queue pool management (allocation, push, pop and notify) and descriptor
-pool management.
-
-knav qmss driver provides a set of APIs to drivers to open/close qmss queues,
-allocate descriptor pools, map the descriptors, push/pop to queues etc. For
-details of the available APIs, please refers to include/linux/soc/ti/knav_qmss.h
-
-DT documentation is available at
-Documentation/devicetree/bindings/soc/ti/keystone-navigator-qmss.txt
-
-Accumulator QMSS queues using PDSP firmware
-============================================
-The QMSS PDSP firmware support accumulator channel that can monitor a single
-queue or multiple contiguous queues. drivers/soc/ti/knav_qmss_acc.c is the
-driver that interface with the accumulator PDSP. This configures
-accumulator channels defined in DTS (example in DT documentation) to monitor
-1 or 32 queues per channel. More description on the firmware is available in
-CPPI/QMSS Low Level Driver document (docs/CPPI_QMSS_LLD_SDS.pdf) at
-       git://git.ti.com/keystone-rtos/qmss-lld.git
-
-k2_qmss_pdsp_acc48_k2_le_1_0_0_9.bin firmware supports upto 48 accumulator
-channels. This firmware is available under ti-keystone folder of
-firmware.git at
-   git://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git
-
-To use copy the firmware image to lib/firmware folder of the initramfs or
-ubifs file system and provide a sym link to k2_qmss_pdsp_acc48_k2_le_1_0_0_9.bin
-in the file system and boot up the kernel. User would see
-
- "firmware file ks2_qmss_pdsp_acc48.bin downloaded for PDSP"
-
-in the boot up log if loading of firmware to PDSP is successful.
-
-Use of accumulated queues requires the firmware image to be present in the
-file system. The driver doesn't acc queues to the supported queue range if
-PDSP is not running in the SoC. The API call fails if there is a queue open
-request to an acc queue and PDSP is not running. So make sure to copy firmware
-to file system before using these queue types.
diff --git a/Documentation/arm/keystone/overview.rst b/Documentation/arm/keystone/overview.rst
new file mode 100644 (file)
index 0000000..cd90298
--- /dev/null
@@ -0,0 +1,74 @@
+==========================
+TI Keystone Linux Overview
+==========================
+
+Introduction
+------------
+Keystone range of SoCs are based on ARM Cortex-A15 MPCore Processors
+and c66x DSP cores. This document describes essential information required
+for users to run Linux on Keystone based EVMs from Texas Instruments.
+
+Following SoCs  & EVMs are currently supported:-
+
+K2HK SoC and EVM
+=================
+
+a.k.a Keystone 2 Hawking/Kepler SoC
+TCI6636K2H & TCI6636K2K: See documentation at
+
+       http://www.ti.com/product/tci6638k2k
+       http://www.ti.com/product/tci6638k2h
+
+EVM:
+  http://www.advantech.com/Support/TI-EVM/EVMK2HX_sd.aspx
+
+K2E SoC and EVM
+===============
+
+a.k.a Keystone 2 Edison SoC
+
+K2E  -  66AK2E05:
+
+See documentation at
+
+       http://www.ti.com/product/66AK2E05/technicaldocuments
+
+EVM:
+   https://www.einfochips.com/index.php/partnerships/texas-instruments/k2e-evm.html
+
+K2L SoC and EVM
+===============
+
+a.k.a Keystone 2 Lamarr SoC
+
+K2L  -  TCI6630K2L:
+
+See documentation at
+       http://www.ti.com/product/TCI6630K2L/technicaldocuments
+
+EVM:
+  https://www.einfochips.com/index.php/partnerships/texas-instruments/k2l-evm.html
+
+Configuration
+-------------
+
+All of the K2 SoCs/EVMs share a common defconfig, keystone_defconfig and same
+image is used to boot on individual EVMs. The platform configuration is
+specified through DTS. Following are the DTS used:
+
+       K2HK EVM:
+               k2hk-evm.dts
+       K2E EVM:
+               k2e-evm.dts
+       K2L EVM:
+               k2l-evm.dts
+
+The device tree documentation for the keystone machines are located at
+
+        Documentation/devicetree/bindings/arm/keystone/keystone.txt
+
+Document Author
+---------------
+Murali Karicheri <m-karicheri2@ti.com>
+
+Copyright 2015 Texas Instruments
diff --git a/Documentation/arm/marvel.rst b/Documentation/arm/marvel.rst
new file mode 100644 (file)
index 0000000..16ab2eb
--- /dev/null
@@ -0,0 +1,488 @@
+================
+ARM Marvell SoCs
+================
+
+This document lists all the ARM Marvell SoCs that are currently
+supported in mainline by the Linux kernel. As the Marvell families of
+SoCs are large and complex, it is hard to understand where the support
+for a particular SoC is available in the Linux kernel. This document
+tries to help in understanding where those SoCs are supported, and to
+match them with their corresponding public datasheet, when available.
+
+Orion family
+------------
+
+  Flavors:
+        - 88F5082
+        - 88F5181
+        - 88F5181L
+        - 88F5182
+
+               - Datasheet: http://www.embeddedarm.com/documentation/third-party/MV88F5182-datasheet.pdf
+               - Programmer's User Guide: http://www.embeddedarm.com/documentation/third-party/MV88F5182-opensource-manual.pdf
+               - User Manual: http://www.embeddedarm.com/documentation/third-party/MV88F5182-usermanual.pdf
+        - 88F5281
+
+               - Datasheet: http://www.ocmodshop.com/images/reviews/networking/qnap_ts409u/marvel_88f5281_data_sheet.pdf
+        - 88F6183
+  Core:
+       Feroceon 88fr331 (88f51xx) or 88fr531-vd (88f52xx) ARMv5 compatible
+  Linux kernel mach directory:
+       arch/arm/mach-orion5x
+  Linux kernel plat directory:
+       arch/arm/plat-orion
+
+Kirkwood family
+---------------
+
+  Flavors:
+        - 88F6282 a.k.a Armada 300
+
+                - Product Brief  : http://www.marvell.com/embedded-processors/armada-300/assets/armada_310.pdf
+        - 88F6283 a.k.a Armada 310
+
+                - Product Brief  : http://www.marvell.com/embedded-processors/armada-300/assets/armada_310.pdf
+        - 88F6190
+
+                - Product Brief  : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6190-003_WEB.pdf
+                - Hardware Spec  : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F619x_OpenSource.pdf
+                - Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf
+        - 88F6192
+
+                - Product Brief  : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6192-003_ver1.pdf
+                - Hardware Spec  : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F619x_OpenSource.pdf
+                - Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf
+        - 88F6182
+        - 88F6180
+
+                - Product Brief  : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6180-003_ver1.pdf
+                - Hardware Spec  : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F6180_OpenSource.pdf
+                - Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf
+        - 88F6281
+
+                - Product Brief  : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6281-004_ver1.pdf
+                - Hardware Spec  : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F6281_OpenSource.pdf
+                - Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf
+  Homepage:
+       http://www.marvell.com/embedded-processors/kirkwood/
+  Core:
+       Feroceon 88fr131 ARMv5 compatible
+  Linux kernel mach directory:
+       arch/arm/mach-mvebu
+  Linux kernel plat directory:
+       none
+
+Discovery family
+----------------
+
+  Flavors:
+        - MV78100
+
+                - Product Brief  : http://www.marvell.com/embedded-processors/discovery-innovation/assets/MV78100-003_WEB.pdf
+                - Hardware Spec  : http://www.marvell.com/embedded-processors/discovery-innovation/assets/HW_MV78100_OpenSource.pdf
+                - Functional Spec: http://www.marvell.com/embedded-processors/discovery-innovation/assets/FS_MV76100_78100_78200_OpenSource.pdf
+        - MV78200
+
+                - Product Brief  : http://www.marvell.com/embedded-processors/discovery-innovation/assets/MV78200-002_WEB.pdf
+                - Hardware Spec  : http://www.marvell.com/embedded-processors/discovery-innovation/assets/HW_MV78200_OpenSource.pdf
+                - Functional Spec: http://www.marvell.com/embedded-processors/discovery-innovation/assets/FS_MV76100_78100_78200_OpenSource.pdf
+        - MV76100
+
+                Not supported by the Linux kernel.
+
+  Core:
+       Feroceon 88fr571-vd ARMv5 compatible
+
+  Linux kernel mach directory:
+       arch/arm/mach-mv78xx0
+  Linux kernel plat directory:
+       arch/arm/plat-orion
+
+EBU Armada family
+-----------------
+
+  Armada 370 Flavors:
+        - 88F6710
+        - 88F6707
+        - 88F6W11
+
+    - Product Brief:   http://www.marvell.com/embedded-processors/armada-300/assets/Marvell_ARMADA_370_SoC.pdf
+    - Hardware Spec:   http://www.marvell.com/embedded-processors/armada-300/assets/ARMADA370-datasheet.pdf
+    - Functional Spec: http://www.marvell.com/embedded-processors/armada-300/assets/ARMADA370-FunctionalSpec-datasheet.pdf
+
+  Core:
+       Sheeva ARMv7 compatible PJ4B
+
+  Armada 375 Flavors:
+       - 88F6720
+
+    - Product Brief: http://www.marvell.com/embedded-processors/armada-300/assets/ARMADA_375_SoC-01_product_brief.pdf
+
+  Core:
+       ARM Cortex-A9
+
+  Armada 38x Flavors:
+       - 88F6810       Armada 380
+       - 88F6820 Armada 385
+       - 88F6828 Armada 388
+
+    - Product infos:   http://www.marvell.com/embedded-processors/armada-38x/
+    - Functional Spec: https://marvellcorp.wufoo.com/forms/marvell-armada-38x-functional-specifications/
+
+  Core:
+       ARM Cortex-A9
+
+  Armada 39x Flavors:
+       - 88F6920 Armada 390
+       - 88F6928 Armada 398
+
+    - Product infos: http://www.marvell.com/embedded-processors/armada-39x/
+
+  Core:
+       ARM Cortex-A9
+
+  Armada XP Flavors:
+        - MV78230
+        - MV78260
+        - MV78460
+
+    NOTE:
+       not to be confused with the non-SMP 78xx0 SoCs
+
+    Product Brief:
+       http://www.marvell.com/embedded-processors/armada-xp/assets/Marvell-ArmadaXP-SoC-product%20brief.pdf
+
+    Functional Spec:
+       http://www.marvell.com/embedded-processors/armada-xp/assets/ARMADA-XP-Functional-SpecDatasheet.pdf
+
+    - Hardware Specs:
+
+        - http://www.marvell.com/embedded-processors/armada-xp/assets/HW_MV78230_OS.PDF
+        - http://www.marvell.com/embedded-processors/armada-xp/assets/HW_MV78260_OS.PDF
+        - http://www.marvell.com/embedded-processors/armada-xp/assets/HW_MV78460_OS.PDF
+
+  Core:
+       Sheeva ARMv7 compatible Dual-core or Quad-core PJ4B-MP
+
+  Linux kernel mach directory:
+       arch/arm/mach-mvebu
+  Linux kernel plat directory:
+       none
+
+EBU Armada family ARMv8
+-----------------------
+
+  Armada 3710/3720 Flavors:
+       - 88F3710
+       - 88F3720
+
+  Core:
+       ARM Cortex A53 (ARMv8)
+
+  Homepage:
+       http://www.marvell.com/embedded-processors/armada-3700/
+
+  Product Brief:
+       http://www.marvell.com/embedded-processors/assets/PB-88F3700-FNL.pdf
+
+  Device tree files:
+       arch/arm64/boot/dts/marvell/armada-37*
+
+  Armada 7K Flavors:
+         - 88F7020 (AP806 Dual + one CP110)
+         - 88F7040 (AP806 Quad + one CP110)
+
+  Core: ARM Cortex A72
+
+  Homepage:
+       http://www.marvell.com/embedded-processors/armada-70xx/
+
+  Product Brief:
+         - http://www.marvell.com/embedded-processors/assets/Armada7020PB-Jan2016.pdf
+         - http://www.marvell.com/embedded-processors/assets/Armada7040PB-Jan2016.pdf
+
+  Device tree files:
+       arch/arm64/boot/dts/marvell/armada-70*
+
+  Armada 8K Flavors:
+       - 88F8020 (AP806 Dual + two CP110)
+       - 88F8040 (AP806 Quad + two CP110)
+  Core:
+       ARM Cortex A72
+
+  Homepage:
+       http://www.marvell.com/embedded-processors/armada-80xx/
+
+  Product Brief:
+         - http://www.marvell.com/embedded-processors/assets/Armada8020PB-Jan2016.pdf
+         - http://www.marvell.com/embedded-processors/assets/Armada8040PB-Jan2016.pdf
+
+  Device tree files:
+       arch/arm64/boot/dts/marvell/armada-80*
+
+Avanta family
+-------------
+
+  Flavors:
+       - 88F6510
+       - 88F6530P
+       - 88F6550
+       - 88F6560
+
+  Homepage:
+       http://www.marvell.com/broadband/
+
+  Product Brief:
+       http://www.marvell.com/broadband/assets/Marvell_Avanta_88F6510_305_060-001_product_brief.pdf
+
+  No public datasheet available.
+
+  Core:
+       ARMv5 compatible
+
+  Linux kernel mach directory:
+       no code in mainline yet, planned for the future
+  Linux kernel plat directory:
+       no code in mainline yet, planned for the future
+
+Storage family
+--------------
+
+  Armada SP:
+       - 88RC1580
+
+  Product infos:
+       http://www.marvell.com/storage/armada-sp/
+
+  Core:
+       Sheeva ARMv7 comatible Quad-core PJ4C
+
+  (not supported in upstream Linux kernel)
+
+Dove family (application processor)
+-----------------------------------
+
+  Flavors:
+        - 88AP510 a.k.a Armada 510
+
+   Product Brief:
+       http://www.marvell.com/application-processors/armada-500/assets/Marvell_Armada510_SoC.pdf
+
+   Hardware Spec:
+       http://www.marvell.com/application-processors/armada-500/assets/Armada-510-Hardware-Spec.pdf
+
+  Functional Spec:
+       http://www.marvell.com/application-processors/armada-500/assets/Armada-510-Functional-Spec.pdf
+
+  Homepage:
+       http://www.marvell.com/application-processors/armada-500/
+
+  Core:
+       ARMv7 compatible
+
+  Directory:
+       - arch/arm/mach-mvebu (DT enabled platforms)
+        - arch/arm/mach-dove (non-DT enabled platforms)
+
+PXA 2xx/3xx/93x/95x family
+--------------------------
+
+  Flavors:
+        - PXA21x, PXA25x, PXA26x
+             - Application processor only
+             - Core: ARMv5 XScale1 core
+        - PXA270, PXA271, PXA272
+             - Product Brief         : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_pb.pdf
+             - Design guide          : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_design_guide.pdf
+             - Developers manual     : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_dev_man.pdf
+             - Specification         : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_emts.pdf
+             - Specification update  : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_spec_update.pdf
+             - Application processor only
+             - Core: ARMv5 XScale2 core
+        - PXA300, PXA310, PXA320
+             - PXA 300 Product Brief : http://www.marvell.com/application-processors/pxa-family/assets/PXA300_PB_R4.pdf
+             - PXA 310 Product Brief : http://www.marvell.com/application-processors/pxa-family/assets/PXA310_PB_R4.pdf
+             - PXA 320 Product Brief : http://www.marvell.com/application-processors/pxa-family/assets/PXA320_PB_R4.pdf
+             - Design guide          : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_Design_Guide.pdf
+             - Developers manual     : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_Developers_Manual.zip
+             - Specifications        : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_EMTS.pdf
+             - Specification Update  : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_Spec_Update.zip
+             - Reference Manual      : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_TavorP_BootROM_Ref_Manual.pdf
+             - Application processor only
+             - Core: ARMv5 XScale3 core
+        - PXA930, PXA935
+             - Application processor with Communication processor
+             - Core: ARMv5 XScale3 core
+        - PXA955
+             - Application processor with Communication processor
+             - Core: ARMv7 compatible Sheeva PJ4 core
+
+   Comments:
+
+    * This line of SoCs originates from the XScale family developed by
+      Intel and acquired by Marvell in ~2006. The PXA21x, PXA25x,
+      PXA26x, PXA27x, PXA3xx and PXA93x were developed by Intel, while
+      the later PXA95x were developed by Marvell.
+
+    * Due to their XScale origin, these SoCs have virtually nothing in
+      common with the other (Kirkwood, Dove, etc.) families of Marvell
+      SoCs, except with the MMP/MMP2 family of SoCs.
+
+   Linux kernel mach directory:
+       arch/arm/mach-pxa
+   Linux kernel plat directory:
+       arch/arm/plat-pxa
+
+MMP/MMP2/MMP3 family (communication processor)
+----------------------------------------------
+
+   Flavors:
+        - PXA168, a.k.a Armada 168
+             - Homepage             : http://www.marvell.com/application-processors/armada-100/armada-168.jsp
+             - Product brief        : http://www.marvell.com/application-processors/armada-100/assets/pxa_168_pb.pdf
+             - Hardware manual      : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_datasheet.pdf
+             - Software manual      : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_software_manual.pdf
+             - Specification update : http://www.marvell.com/application-processors/armada-100/assets/ARMADA16x_Spec_update.pdf
+             - Boot ROM manual      : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_ref_manual.pdf
+             - App node package     : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_app_note_package.pdf
+             - Application processor only
+             - Core: ARMv5 compatible Marvell PJ1 88sv331 (Mohawk)
+        - PXA910/PXA920
+             - Homepage             : http://www.marvell.com/communication-processors/pxa910/
+             - Product Brief        : http://www.marvell.com/communication-processors/pxa910/assets/Marvell_PXA910_Platform-001_PB_final.pdf
+             - Application processor with Communication processor
+             - Core: ARMv5 compatible Marvell PJ1 88sv331 (Mohawk)
+        - PXA688, a.k.a. MMP2, a.k.a Armada 610
+             - Product Brief        : http://www.marvell.com/application-processors/armada-600/assets/armada610_pb.pdf
+             - Application processor only
+             - Core: ARMv7 compatible Sheeva PJ4 88sv581x core
+       - PXA2128, a.k.a. MMP3 (OLPC XO4, Linux support not upstream)
+            - Product Brief      : http://www.marvell.com/application-processors/armada/pxa2128/assets/Marvell-ARMADA-PXA2128-SoC-PB.pdf
+            - Application processor only
+            - Core: Dual-core ARMv7 compatible Sheeva PJ4C core
+       - PXA960/PXA968/PXA978 (Linux support not upstream)
+            - Application processor with Communication Processor
+            - Core: ARMv7 compatible Sheeva PJ4 core
+       - PXA986/PXA988 (Linux support not upstream)
+            - Application processor with Communication Processor
+            - Core: Dual-core ARMv7 compatible Sheeva PJ4B-MP core
+       - PXA1088/PXA1920 (Linux support not upstream)
+            - Application processor with Communication Processor
+            - Core: quad-core ARMv7 Cortex-A7
+       - PXA1908/PXA1928/PXA1936
+            - Application processor with Communication Processor
+            - Core: multi-core ARMv8 Cortex-A53
+
+   Comments:
+
+    * This line of SoCs originates from the XScale family developed by
+      Intel and acquired by Marvell in ~2006. All the processors of
+      this MMP/MMP2 family were developed by Marvell.
+
+    * Due to their XScale origin, these SoCs have virtually nothing in
+      common with the other (Kirkwood, Dove, etc.) families of Marvell
+      SoCs, except with the PXA family of SoCs listed above.
+
+   Linux kernel mach directory:
+       arch/arm/mach-mmp
+   Linux kernel plat directory:
+       arch/arm/plat-pxa
+
+Berlin family (Multimedia Solutions)
+-------------------------------------
+
+  - Flavors:
+       - 88DE3010, Armada 1000 (no Linux support)
+               - Core:         Marvell PJ1 (ARMv5TE), Dual-core
+               - Product Brief:        http://www.marvell.com.cn/digital-entertainment/assets/armada_1000_pb.pdf
+       - 88DE3005, Armada 1500 Mini
+               - Design name:  BG2CD
+               - Core:         ARM Cortex-A9, PL310 L2CC
+       - 88DE3006, Armada 1500 Mini Plus
+               - Design name:  BG2CDP
+               - Core:         Dual Core ARM Cortex-A7
+       - 88DE3100, Armada 1500
+               - Design name:  BG2
+               - Core:         Marvell PJ4B-MP (ARMv7), Tauros3 L2CC
+       - 88DE3114, Armada 1500 Pro
+               - Design name:  BG2Q
+               - Core:         Quad Core ARM Cortex-A9, PL310 L2CC
+       - 88DE3214, Armada 1500 Pro 4K
+               - Design name:  BG3
+               - Core:         ARM Cortex-A15, CA15 integrated L2CC
+       - 88DE3218, ARMADA 1500 Ultra
+               - Core:         ARM Cortex-A53
+
+  Homepage: https://www.synaptics.com/products/multimedia-solutions
+  Directory: arch/arm/mach-berlin
+
+  Comments:
+
+   * This line of SoCs is based on Marvell Sheeva or ARM Cortex CPUs
+     with Synopsys DesignWare (IRQ, GPIO, Timers, ...) and PXA IP (SDHCI, USB, ETH, ...).
+
+   * The Berlin family was acquired by Synaptics from Marvell in 2017.
+
+CPU Cores
+---------
+
+The XScale cores were designed by Intel, and shipped by Marvell in the older
+PXA processors. Feroceon is a Marvell designed core that developed in-house,
+and that evolved into Sheeva. The XScale and Feroceon cores were phased out
+over time and replaced with Sheeva cores in later products, which subsequently
+got replaced with licensed ARM Cortex-A cores.
+
+  XScale 1
+       CPUID 0x69052xxx
+       ARMv5, iWMMXt
+  XScale 2
+       CPUID 0x69054xxx
+       ARMv5, iWMMXt
+  XScale 3
+       CPUID 0x69056xxx or 0x69056xxx
+       ARMv5, iWMMXt
+  Feroceon-1850 88fr331 "Mohawk"
+       CPUID 0x5615331x or 0x41xx926x
+       ARMv5TE, single issue
+  Feroceon-2850 88fr531-vd "Jolteon"
+       CPUID 0x5605531x or 0x41xx926x
+       ARMv5TE, VFP, dual-issue
+  Feroceon 88fr571-vd "Jolteon"
+       CPUID 0x5615571x
+       ARMv5TE, VFP, dual-issue
+  Feroceon 88fr131 "Mohawk-D"
+       CPUID 0x5625131x
+       ARMv5TE, single-issue in-order
+  Sheeva PJ1 88sv331 "Mohawk"
+       CPUID 0x561584xx
+       ARMv5, single-issue iWMMXt v2
+  Sheeva PJ4 88sv581x "Flareon"
+       CPUID 0x560f581x
+       ARMv7, idivt, optional iWMMXt v2
+  Sheeva PJ4B 88sv581x
+       CPUID 0x561f581x
+       ARMv7, idivt, optional iWMMXt v2
+  Sheeva PJ4B-MP / PJ4C
+       CPUID 0x562f584x
+       ARMv7, idivt/idiva, LPAE, optional iWMMXt v2 and/or NEON
+
+Long-term plans
+---------------
+
+ * Unify the mach-dove/, mach-mv78xx0/, mach-orion5x/ into the
+   mach-mvebu/ to support all SoCs from the Marvell EBU (Engineering
+   Business Unit) in a single mach-<foo> directory. The plat-orion/
+   would therefore disappear.
+
+ * Unify the mach-mmp/ and mach-pxa/ into the same mach-pxa
+   directory. The plat-pxa/ would therefore disappear.
+
+Credits
+-------
+
+- Maen Suleiman <maen@marvell.com>
+- Lior Amsalem <alior@marvell.com>
+- Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+- Andrew Lunn <andrew@lunn.ch>
+- Nicolas Pitre <nico@fluxnic.net>
+- Eric Miao <eric.y.miao@gmail.com>
diff --git a/Documentation/arm/mem_alignment b/Documentation/arm/mem_alignment
deleted file mode 100644 (file)
index e110e27..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-Too many problems popped up because of unnoticed misaligned memory access in
-kernel code lately.  Therefore the alignment fixup is now unconditionally
-configured in for SA11x0 based targets.  According to Alan Cox, this is a
-bad idea to configure it out, but Russell King has some good reasons for
-doing so on some f***ed up ARM architectures like the EBSA110.  However
-this is not the case on many design I'm aware of, like all SA11x0 based
-ones.
-
-Of course this is a bad idea to rely on the alignment trap to perform
-unaligned memory access in general.  If those access are predictable, you
-are better to use the macros provided by include/asm/unaligned.h.  The
-alignment trap can fixup misaligned access for the exception cases, but at
-a high performance cost.  It better be rare.
-
-Now for user space applications, it is possible to configure the alignment
-trap to SIGBUS any code performing unaligned access (good for debugging bad
-code), or even fixup the access by software like for kernel code.  The later
-mode isn't recommended for performance reasons (just think about the
-floating point emulation that works about the same way).  Fix your code
-instead!
-
-Please note that randomly changing the behaviour without good thought is
-real bad - it changes the behaviour of all unaligned instructions in user
-space, and might cause programs to fail unexpectedly.
-
-To change the alignment trap behavior, simply echo a number into
-/proc/cpu/alignment.  The number is made up from various bits:
-
-bit            behavior when set
----            -----------------
-
-0              A user process performing an unaligned memory access
-               will cause the kernel to print a message indicating
-               process name, pid, pc, instruction, address, and the
-               fault code.
-
-1              The kernel will attempt to fix up the user process
-               performing the unaligned access.  This is of course
-               slow (think about the floating point emulator) and
-               not recommended for production use.
-
-2              The kernel will send a SIGBUS signal to the user process
-               performing the unaligned access.
-
-Note that not all combinations are supported - only values 0 through 5.
-(6 and 7 don't make sense).
-
-For example, the following will turn on the warnings, but without
-fixing up or sending SIGBUS signals:
-
-       echo 1 > /proc/cpu/alignment
-
-You can also read the content of the same file to get statistical
-information on unaligned access occurrences plus the current mode of
-operation for user space code.
-
-
-Nicolas Pitre, Mar 13, 2001.  Modified Russell King, Nov 30, 2001.
diff --git a/Documentation/arm/mem_alignment.rst b/Documentation/arm/mem_alignment.rst
new file mode 100644 (file)
index 0000000..aa22893
--- /dev/null
@@ -0,0 +1,63 @@
+================
+Memory alignment
+================
+
+Too many problems popped up because of unnoticed misaligned memory access in
+kernel code lately.  Therefore the alignment fixup is now unconditionally
+configured in for SA11x0 based targets.  According to Alan Cox, this is a
+bad idea to configure it out, but Russell King has some good reasons for
+doing so on some f***ed up ARM architectures like the EBSA110.  However
+this is not the case on many design I'm aware of, like all SA11x0 based
+ones.
+
+Of course this is a bad idea to rely on the alignment trap to perform
+unaligned memory access in general.  If those access are predictable, you
+are better to use the macros provided by include/asm/unaligned.h.  The
+alignment trap can fixup misaligned access for the exception cases, but at
+a high performance cost.  It better be rare.
+
+Now for user space applications, it is possible to configure the alignment
+trap to SIGBUS any code performing unaligned access (good for debugging bad
+code), or even fixup the access by software like for kernel code.  The later
+mode isn't recommended for performance reasons (just think about the
+floating point emulation that works about the same way).  Fix your code
+instead!
+
+Please note that randomly changing the behaviour without good thought is
+real bad - it changes the behaviour of all unaligned instructions in user
+space, and might cause programs to fail unexpectedly.
+
+To change the alignment trap behavior, simply echo a number into
+/proc/cpu/alignment.  The number is made up from various bits:
+
+===            ========================================================
+bit            behavior when set
+===            ========================================================
+0              A user process performing an unaligned memory access
+               will cause the kernel to print a message indicating
+               process name, pid, pc, instruction, address, and the
+               fault code.
+
+1              The kernel will attempt to fix up the user process
+               performing the unaligned access.  This is of course
+               slow (think about the floating point emulator) and
+               not recommended for production use.
+
+2              The kernel will send a SIGBUS signal to the user process
+               performing the unaligned access.
+===            ========================================================
+
+Note that not all combinations are supported - only values 0 through 5.
+(6 and 7 don't make sense).
+
+For example, the following will turn on the warnings, but without
+fixing up or sending SIGBUS signals::
+
+       echo 1 > /proc/cpu/alignment
+
+You can also read the content of the same file to get statistical
+information on unaligned access occurrences plus the current mode of
+operation for user space code.
+
+
+Nicolas Pitre, Mar 13, 2001.  Modified Russell King, Nov 30, 2001.
diff --git a/Documentation/arm/memory.rst b/Documentation/arm/memory.rst
new file mode 100644 (file)
index 0000000..0521b4c
--- /dev/null
@@ -0,0 +1,93 @@
+=================================
+Kernel Memory Layout on ARM Linux
+=================================
+
+               Russell King <rmk@arm.linux.org.uk>
+
+                    November 17, 2005 (2.6.15)
+
+This document describes the virtual memory layout which the Linux
+kernel uses for ARM processors.  It indicates which regions are
+free for platforms to use, and which are used by generic code.
+
+The ARM CPU is capable of addressing a maximum of 4GB virtual memory
+space, and this must be shared between user space processes, the
+kernel, and hardware devices.
+
+As the ARM architecture matures, it becomes necessary to reserve
+certain regions of VM space for use for new facilities; therefore
+this document may reserve more VM space over time.
+
+=============== =============== ===============================================
+Start          End             Use
+=============== =============== ===============================================
+ffff8000       ffffffff        copy_user_page / clear_user_page use.
+                               For SA11xx and Xscale, this is used to
+                               setup a minicache mapping.
+
+ffff4000       ffffffff        cache aliasing on ARMv6 and later CPUs.
+
+ffff1000       ffff7fff        Reserved.
+                               Platforms must not use this address range.
+
+ffff0000       ffff0fff        CPU vector page.
+                               The CPU vectors are mapped here if the
+                               CPU supports vector relocation (control
+                               register V bit.)
+
+fffe0000       fffeffff        XScale cache flush area.  This is used
+                               in proc-xscale.S to flush the whole data
+                               cache. (XScale does not have TCM.)
+
+fffe8000       fffeffff        DTCM mapping area for platforms with
+                               DTCM mounted inside the CPU.
+
+fffe0000       fffe7fff        ITCM mapping area for platforms with
+                               ITCM mounted inside the CPU.
+
+ffc00000       ffefffff        Fixmap mapping region.  Addresses provided
+                               by fix_to_virt() will be located here.
+
+fee00000       feffffff        Mapping of PCI I/O space. This is a static
+                               mapping within the vmalloc space.
+
+VMALLOC_START  VMALLOC_END-1   vmalloc() / ioremap() space.
+                               Memory returned by vmalloc/ioremap will
+                               be dynamically placed in this region.
+                               Machine specific static mappings are also
+                               located here through iotable_init().
+                               VMALLOC_START is based upon the value
+                               of the high_memory variable, and VMALLOC_END
+                               is equal to 0xff800000.
+
+PAGE_OFFSET    high_memory-1   Kernel direct-mapped RAM region.
+                               This maps the platforms RAM, and typically
+                               maps all platform RAM in a 1:1 relationship.
+
+PKMAP_BASE     PAGE_OFFSET-1   Permanent kernel mappings
+                               One way of mapping HIGHMEM pages into kernel
+                               space.
+
+MODULES_VADDR  MODULES_END-1   Kernel module space
+                               Kernel modules inserted via insmod are
+                               placed here using dynamic mappings.
+
+00001000       TASK_SIZE-1     User space mappings
+                               Per-thread mappings are placed here via
+                               the mmap() system call.
+
+00000000       00000fff        CPU vector page / null pointer trap
+                               CPUs which do not support vector remapping
+                               place their vector page here.  NULL pointer
+                               dereferences by both the kernel and user
+                               space are also caught via this mapping.
+=============== =============== ===============================================
+
+Please note that mappings which collide with the above areas may result
+in a non-bootable kernel, or may cause the kernel to (eventually) panic
+at run time.
+
+Since future CPUs may impact the kernel mapping layout, user programs
+must not access any memory which is not mapped inside their 0x0001000
+to TASK_SIZE address range.  If they wish to access these areas, they
+must set up their own mappings using open() and mmap().
diff --git a/Documentation/arm/memory.txt b/Documentation/arm/memory.txt
deleted file mode 100644 (file)
index 546a390..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-               Kernel Memory Layout on ARM Linux
-
-               Russell King <rmk@arm.linux.org.uk>
-                    November 17, 2005 (2.6.15)
-
-This document describes the virtual memory layout which the Linux
-kernel uses for ARM processors.  It indicates which regions are
-free for platforms to use, and which are used by generic code.
-
-The ARM CPU is capable of addressing a maximum of 4GB virtual memory
-space, and this must be shared between user space processes, the
-kernel, and hardware devices.
-
-As the ARM architecture matures, it becomes necessary to reserve
-certain regions of VM space for use for new facilities; therefore
-this document may reserve more VM space over time.
-
-Start          End             Use
---------------------------------------------------------------------------
-ffff8000       ffffffff        copy_user_page / clear_user_page use.
-                               For SA11xx and Xscale, this is used to
-                               setup a minicache mapping.
-
-ffff4000       ffffffff        cache aliasing on ARMv6 and later CPUs.
-
-ffff1000       ffff7fff        Reserved.
-                               Platforms must not use this address range.
-
-ffff0000       ffff0fff        CPU vector page.
-                               The CPU vectors are mapped here if the
-                               CPU supports vector relocation (control
-                               register V bit.)
-
-fffe0000       fffeffff        XScale cache flush area.  This is used
-                               in proc-xscale.S to flush the whole data
-                               cache. (XScale does not have TCM.)
-
-fffe8000       fffeffff        DTCM mapping area for platforms with
-                               DTCM mounted inside the CPU.
-
-fffe0000       fffe7fff        ITCM mapping area for platforms with
-                               ITCM mounted inside the CPU.
-
-ffc00000       ffefffff        Fixmap mapping region.  Addresses provided
-                               by fix_to_virt() will be located here.
-
-fee00000       feffffff        Mapping of PCI I/O space. This is a static
-                               mapping within the vmalloc space.
-
-VMALLOC_START  VMALLOC_END-1   vmalloc() / ioremap() space.
-                               Memory returned by vmalloc/ioremap will
-                               be dynamically placed in this region.
-                               Machine specific static mappings are also
-                               located here through iotable_init().
-                               VMALLOC_START is based upon the value
-                               of the high_memory variable, and VMALLOC_END
-                               is equal to 0xff800000.
-
-PAGE_OFFSET    high_memory-1   Kernel direct-mapped RAM region.
-                               This maps the platforms RAM, and typically
-                               maps all platform RAM in a 1:1 relationship.
-
-PKMAP_BASE     PAGE_OFFSET-1   Permanent kernel mappings
-                               One way of mapping HIGHMEM pages into kernel
-                               space.
-
-MODULES_VADDR  MODULES_END-1   Kernel module space
-                               Kernel modules inserted via insmod are
-                               placed here using dynamic mappings.
-
-00001000       TASK_SIZE-1     User space mappings
-                               Per-thread mappings are placed here via
-                               the mmap() system call.
-
-00000000       00000fff        CPU vector page / null pointer trap
-                               CPUs which do not support vector remapping
-                               place their vector page here.  NULL pointer
-                               dereferences by both the kernel and user
-                               space are also caught via this mapping.
-
-Please note that mappings which collide with the above areas may result
-in a non-bootable kernel, or may cause the kernel to (eventually) panic
-at run time.
-
-Since future CPUs may impact the kernel mapping layout, user programs
-must not access any memory which is not mapped inside their 0x0001000
-to TASK_SIZE address range.  If they wish to access these areas, they
-must set up their own mappings using open() and mmap().
diff --git a/Documentation/arm/microchip.rst b/Documentation/arm/microchip.rst
new file mode 100644 (file)
index 0000000..c9a44c9
--- /dev/null
@@ -0,0 +1,204 @@
+=============================
+ARM Microchip SoCs (aka AT91)
+=============================
+
+
+Introduction
+------------
+This document gives useful information about the ARM Microchip SoCs that are
+currently supported in Linux Mainline (you know, the one on kernel.org).
+
+It is important to note that the Microchip (previously Atmel) ARM-based MPU
+product line is historically named "AT91" or "at91" throughout the Linux kernel
+development process even if this product prefix has completely disappeared from
+the official Microchip product name. Anyway, files, directories, git trees,
+git branches/tags and email subject always contain this "at91" sub-string.
+
+
+AT91 SoCs
+---------
+Documentation and detailed datasheet for each product are available on
+the Microchip website: http://www.microchip.com.
+
+  Flavors:
+    * ARM 920 based SoC
+      - at91rm9200
+
+          * Datasheet
+
+          http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-1768-32-bit-ARM920T-Embedded-Microprocessor-AT91RM9200_Datasheet.pdf
+
+    * ARM 926 based SoCs
+      - at91sam9260
+
+          * Datasheet
+
+          http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-6221-32-bit-ARM926EJ-S-Embedded-Microprocessor-SAM9260_Datasheet.pdf
+
+      - at91sam9xe
+
+          * Datasheet
+
+          http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-6254-32-bit-ARM926EJ-S-Embedded-Microprocessor-SAM9XE_Datasheet.pdf
+
+      - at91sam9261
+
+          * Datasheet
+
+          http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-6062-ARM926EJ-S-Microprocessor-SAM9261_Datasheet.pdf
+
+      - at91sam9263
+
+          * Datasheet
+
+          http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-6249-32-bit-ARM926EJ-S-Embedded-Microprocessor-SAM9263_Datasheet.pdf
+
+      - at91sam9rl
+
+          * Datasheet
+
+          http://ww1.microchip.com/downloads/en/DeviceDoc/doc6289.pdf
+
+      - at91sam9g20
+
+          * Datasheet
+
+          http://ww1.microchip.com/downloads/en/DeviceDoc/DS60001516A.pdf
+
+      - at91sam9g45 family
+        - at91sam9g45
+        - at91sam9g46
+        - at91sam9m10
+        - at91sam9m11 (device superset)
+
+          * Datasheet
+
+          http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-6437-32-bit-ARM926-Embedded-Microprocessor-SAM9M11_Datasheet.pdf
+
+      - at91sam9x5 family (aka "The 5 series")
+        - at91sam9g15
+        - at91sam9g25
+        - at91sam9g35
+        - at91sam9x25
+        - at91sam9x35
+
+          * Datasheet (can be considered as covering the whole family)
+
+          http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11055-32-bit-ARM926EJ-S-Microcontroller-SAM9X35_Datasheet.pdf
+
+      - at91sam9n12
+
+          * Datasheet
+
+          http://ww1.microchip.com/downloads/en/DeviceDoc/DS60001517A.pdf
+
+    * ARM Cortex-A5 based SoCs
+      - sama5d3 family
+
+        - sama5d31
+        - sama5d33
+        - sama5d34
+        - sama5d35
+        - sama5d36 (device superset)
+
+          * Datasheet
+
+          http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11121-32-bit-Cortex-A5-Microcontroller-SAMA5D3_Datasheet.pdf
+
+    * ARM Cortex-A5 + NEON based SoCs
+      - sama5d4 family
+
+        - sama5d41
+        - sama5d42
+        - sama5d43
+        - sama5d44 (device superset)
+
+          * Datasheet
+
+          http://ww1.microchip.com/downloads/en/DeviceDoc/60001525A.pdf
+
+      - sama5d2 family
+
+        - sama5d21
+        - sama5d22
+        - sama5d23
+        - sama5d24
+        - sama5d26
+        - sama5d27 (device superset)
+        - sama5d28 (device superset + environmental monitors)
+
+          * Datasheet
+
+          http://ww1.microchip.com/downloads/en/DeviceDoc/DS60001476B.pdf
+
+    * ARM Cortex-M7 MCUs
+      - sams70 family
+
+        - sams70j19
+        - sams70j20
+        - sams70j21
+        - sams70n19
+        - sams70n20
+        - sams70n21
+        - sams70q19
+        - sams70q20
+        - sams70q21
+
+      - samv70 family
+
+        - samv70j19
+        - samv70j20
+        - samv70n19
+        - samv70n20
+        - samv70q19
+        - samv70q20
+
+      - samv71 family
+
+        - samv71j19
+        - samv71j20
+        - samv71j21
+        - samv71n19
+        - samv71n20
+        - samv71n21
+        - samv71q19
+        - samv71q20
+        - samv71q21
+
+          * Datasheet
+
+          http://ww1.microchip.com/downloads/en/DeviceDoc/60001527A.pdf
+
+
+Linux kernel information
+------------------------
+Linux kernel mach directory: arch/arm/mach-at91
+MAINTAINERS entry is: "ARM/Microchip (AT91) SoC support"
+
+
+Device Tree for AT91 SoCs and boards
+------------------------------------
+All AT91 SoCs are converted to Device Tree. Since Linux 3.19, these products
+must use this method to boot the Linux kernel.
+
+Work In Progress statement:
+Device Tree files and Device Tree bindings that apply to AT91 SoCs and boards are
+considered as "Unstable". To be completely clear, any at91 binding can change at
+any time. So, be sure to use a Device Tree Binary and a Kernel Image generated from
+the same source tree.
+Please refer to the Documentation/devicetree/bindings/ABI.txt file for a
+definition of a "Stable" binding/ABI.
+This statement will be removed by AT91 MAINTAINERS when appropriate.
+
+Naming conventions and best practice:
+
+- SoCs Device Tree Source Include files are named after the official name of
+  the product (at91sam9g20.dtsi or sama5d33.dtsi for instance).
+- Device Tree Source Include files (.dtsi) are used to collect common nodes that can be
+  shared across SoCs or boards (sama5d3.dtsi or at91sam9x5cm.dtsi for instance).
+  When collecting nodes for a particular peripheral or topic, the identifier have to
+  be placed at the end of the file name, separated with a "_" (at91sam9x5_can.dtsi
+  or sama5d3_gmac.dtsi for example).
+- board Device Tree Source files (.dts) are prefixed by the string "at91-" so
+  that they can be identified easily. Note that some files are historical exceptions
+  to this rule (sama5d3[13456]ek.dts, usb_a9g20.dts or animeo_ip.dts for example).
diff --git a/Documentation/arm/netwinder.rst b/Documentation/arm/netwinder.rst
new file mode 100644 (file)
index 0000000..8eab66c
--- /dev/null
@@ -0,0 +1,85 @@
+================================
+NetWinder specific documentation
+================================
+
+The NetWinder is a small low-power computer, primarily designed
+to run Linux.  It is based around the StrongARM RISC processor,
+DC21285 PCI bridge, with PC-type hardware glued around it.
+
+Port usage
+==========
+
+=======  ====== ===============================
+Min      Max   Description
+=======  ====== ===============================
+0x0000   0x000f        DMA1
+0x0020   0x0021        PIC1
+0x0060   0x006f        Keyboard
+0x0070   0x007f        RTC
+0x0080   0x0087        DMA1
+0x0088   0x008f        DMA2
+0x00a0   0x00a3        PIC2
+0x00c0   0x00df        DMA2
+0x0180   0x0187        IRDA
+0x01f0   0x01f6        ide0
+0x0201         Game port
+0x0203         RWA010 configuration read
+0x0220   ?     SoundBlaster
+0x0250   ?     WaveArtist
+0x0279         RWA010 configuration index
+0x02f8   0x02ff        Serial ttyS1
+0x0300   0x031f        Ether10
+0x0338         GPIO1
+0x033a         GPIO2
+0x0370   0x0371        W83977F configuration registers
+0x0388   ?     AdLib
+0x03c0   0x03df        VGA
+0x03f6         ide0
+0x03f8   0x03ff        Serial ttyS0
+0x0400   0x0408        DC21143
+0x0480   0x0487        DMA1
+0x0488   0x048f        DMA2
+0x0a79         RWA010 configuration write
+0xe800   0xe80f        ide0/ide1 BM DMA
+=======  ====== ===============================
+
+
+Interrupt usage
+===============
+
+======= ======= ========================
+IRQ    type    Description
+======= ======= ========================
+ 0     ISA     100Hz timer
+ 1     ISA     Keyboard
+ 2     ISA     cascade
+ 3     ISA     Serial ttyS1
+ 4     ISA     Serial ttyS0
+ 5     ISA     PS/2 mouse
+ 6     ISA     IRDA
+ 7     ISA     Printer
+ 8     ISA     RTC alarm
+ 9     ISA
+10     ISA     GP10 (Orange reset button)
+11     ISA
+12     ISA     WaveArtist
+13     ISA
+14     ISA     hda1
+15     ISA
+======= ======= ========================
+
+DMA usage
+=========
+
+======= ======= ===========
+DMA    type    Description
+======= ======= ===========
+ 0     ISA     IRDA
+ 1     ISA
+ 2     ISA     cascade
+ 3     ISA     WaveArtist
+ 4     ISA
+ 5     ISA
+ 6     ISA
+ 7     ISA     WaveArtist
+======= ======= ===========
diff --git a/Documentation/arm/nwfpe/NOTES b/Documentation/arm/nwfpe/NOTES
deleted file mode 100644 (file)
index 40577b5..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-There seems to be a problem with exp(double) and our emulator.  I haven't
-been able to track it down yet.  This does not occur with the emulator
-supplied by Russell King.
-
-I also found one oddity in the emulator.  I don't think it is serious but
-will point it out.  The ARM calling conventions require floating point
-registers f4-f7 to be preserved over a function call.  The compiler quite
-often uses an stfe instruction to save f4 on the stack upon entry to a
-function, and an ldfe instruction to restore it before returning.
-
-I was looking at some code, that calculated a double result, stored it in f4
-then made a function call. Upon return from the function call the number in
-f4 had been converted to an extended value in the emulator.
-
-This is a side effect of the stfe instruction.  The double in f4 had to be
-converted to extended, then stored.  If an lfm/sfm combination had been used,
-then no conversion would occur.  This has performance considerations.  The
-result from the function call and f4 were used in a multiplication.  If the
-emulator sees a multiply of a double and extended, it promotes the double to
-extended, then does the multiply in extended precision.
-
-This code will cause this problem:
-
-double x, y, z;
-z = log(x)/log(y);
-
-The result of log(x) (a double) will be calculated, returned in f0, then
-moved to f4 to preserve it over the log(y) call.  The division will be done
-in extended precision, due to the stfe instruction used to save f4 in log(y).
diff --git a/Documentation/arm/nwfpe/README b/Documentation/arm/nwfpe/README
deleted file mode 100644 (file)
index 771871d..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-This directory contains the version 0.92 test release of the NetWinder 
-Floating Point Emulator.
-
-The majority of the code was written by me, Scott Bambrough It is
-written in C, with a small number of routines in inline assembler
-where required.  It was written quickly, with a goal of implementing a
-working version of all the floating point instructions the compiler
-emits as the first target.  I have attempted to be as optimal as
-possible, but there remains much room for improvement.
-
-I have attempted to make the emulator as portable as possible.  One of
-the problems is with leading underscores on kernel symbols.  Elf
-kernels have no leading underscores, a.out compiled kernels do.  I
-have attempted to use the C_SYMBOL_NAME macro wherever this may be
-important.
-
-Another choice I made was in the file structure.  I have attempted to
-contain all operating system specific code in one module (fpmodule.*).
-All the other files contain emulator specific code.  This should allow
-others to port the emulator to NetBSD for instance relatively easily.
-
-The floating point operations are based on SoftFloat Release 2, by
-John Hauser.  SoftFloat is a software implementation of floating-point
-that conforms to the IEC/IEEE Standard for Binary Floating-point
-Arithmetic.  As many as four formats are supported: single precision,
-double precision, extended double precision, and quadruple precision.
-All operations required by the standard are implemented, except for
-conversions to and from decimal.  We use only the single precision,
-double precision and extended double precision formats.  The port of
-SoftFloat to the ARM was done by Phil Blundell, based on an earlier
-port of SoftFloat version 1 by Neil Carson for NetBSD/arm32.
-
-The file README.FPE contains a description of what has been implemented
-so far in the emulator.  The file TODO contains a information on what 
-remains to be done, and other ideas for the emulator.
-
-Bug reports, comments, suggestions should be directed to me at
-<scottb@netwinder.org>.  General reports of "this program doesn't
-work correctly when your emulator is installed" are useful for
-determining that bugs still exist; but are virtually useless when
-attempting to isolate the problem.  Please report them, but don't
-expect quick action.  Bugs still exist.  The problem remains in isolating
-which instruction contains the bug.  Small programs illustrating a specific
-problem are a godsend.
-
-Legal Notices
--------------
-
-The NetWinder Floating Point Emulator is free software.  Everything Rebel.com
-has written is provided under the GNU GPL.  See the file COPYING for copying
-conditions.  Excluded from the above is the SoftFloat code.  John Hauser's 
-legal notice for SoftFloat is included below.
-
--------------------------------------------------------------------------------
-SoftFloat Legal Notice
-
-SoftFloat was written by John R. Hauser.  This work was made possible in
-part by the International Computer Science Institute, located at Suite 600,
-1947 Center Street, Berkeley, California 94704.  Funding was partially
-provided by the National Science Foundation under grant MIP-9311980.  The
-original version of this code was written as part of a project to build
-a fixed-point vector processor in collaboration with the University of
-California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek.
-
-THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
-has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
-TIMES RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO
-PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
-AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
--------------------------------------------------------------------------------
diff --git a/Documentation/arm/nwfpe/README.FPE b/Documentation/arm/nwfpe/README.FPE
deleted file mode 100644 (file)
index 26f5d7b..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-The following describes the current state of the NetWinder's floating point
-emulator.
-
-In the following nomenclature is used to describe the floating point
-instructions.  It follows the conventions in the ARM manual.
-
-<S|D|E> = <single|double|extended>, no default
-{P|M|Z} = {round to +infinity,round to -infinity,round to zero},
-          default = round to nearest
-
-Note: items enclosed in {} are optional.
-
-Floating Point Coprocessor Data Transfer Instructions (CPDT)
-------------------------------------------------------------
-
-LDF/STF - load and store floating
-
-<LDF|STF>{cond}<S|D|E> Fd, Rn
-<LDF|STF>{cond}<S|D|E> Fd, [Rn, #<expression>]{!}
-<LDF|STF>{cond}<S|D|E> Fd, [Rn], #<expression>
-
-These instructions are fully implemented.
-
-LFM/SFM - load and store multiple floating
-
-Form 1 syntax:
-<LFM|SFM>{cond}<S|D|E> Fd, <count>, [Rn]
-<LFM|SFM>{cond}<S|D|E> Fd, <count>, [Rn, #<expression>]{!}
-<LFM|SFM>{cond}<S|D|E> Fd, <count>, [Rn], #<expression>
-
-Form 2 syntax:
-<LFM|SFM>{cond}<FD,EA> Fd, <count>, [Rn]{!}
-
-These instructions are fully implemented.  They store/load three words
-for each floating point register into the memory location given in the 
-instruction.  The format in memory is unlikely to be compatible with
-other implementations, in particular the actual hardware.  Specific
-mention of this is made in the ARM manuals.  
-
-Floating Point Coprocessor Register Transfer Instructions (CPRT)
-----------------------------------------------------------------
-
-Conversions, read/write status/control register instructions
-
-FLT{cond}<S,D,E>{P,M,Z} Fn, Rd          Convert integer to floating point
-FIX{cond}{P,M,Z} Rd, Fn                 Convert floating point to integer
-WFS{cond} Rd                            Write floating point status register
-RFS{cond} Rd                            Read floating point status register
-WFC{cond} Rd                            Write floating point control register
-RFC{cond} Rd                            Read floating point control register
-
-FLT/FIX are fully implemented.
-
-RFS/WFS are fully implemented.
-
-RFC/WFC are fully implemented.  RFC/WFC are supervisor only instructions, and
-presently check the CPU mode, and do an invalid instruction trap if not called
-from supervisor mode.
-
-Compare instructions
-
-CMF{cond} Fn, Fm        Compare floating
-CMFE{cond} Fn, Fm       Compare floating with exception
-CNF{cond} Fn, Fm        Compare negated floating
-CNFE{cond} Fn, Fm       Compare negated floating with exception
-
-These are fully implemented.
-
-Floating Point Coprocessor Data Instructions (CPDT)
----------------------------------------------------
-
-Dyadic operations:
-
-ADF{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - add
-SUF{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - subtract
-RSF{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - reverse subtract
-MUF{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - multiply
-DVF{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - divide
-RDV{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - reverse divide
-
-These are fully implemented.
-
-FML{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - fast multiply
-FDV{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - fast divide
-FRD{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - fast reverse divide
-
-These are fully implemented as well.  They use the same algorithm as the
-non-fast versions.  Hence, in this implementation their performance is
-equivalent to the MUF/DVF/RDV instructions.  This is acceptable according
-to the ARM manual.  The manual notes these are defined only for single
-operands, on the actual FPA11 hardware they do not work for double or
-extended precision operands.  The emulator currently does not check
-the requested permissions conditions, and performs the requested operation.
-
-RMF{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - IEEE remainder
-
-This is fully implemented.
-
-Monadic operations:
-
-MVF{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - move
-MNF{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - move negated
-
-These are fully implemented.
-
-ABS{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - absolute value
-SQT{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - square root
-RND{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - round
-
-These are fully implemented.
-
-URD{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - unnormalized round
-NRM{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - normalize
-
-These are implemented.  URD is implemented using the same code as the RND
-instruction.  Since URD cannot return a unnormalized number, NRM becomes
-a NOP.
-
-Library calls:
-
-POW{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - power
-RPW{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - reverse power
-POL{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - polar angle (arctan2)
-
-LOG{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - logarithm to base 10
-LGN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - logarithm to base e 
-EXP{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - exponent
-SIN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - sine
-COS{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - cosine
-TAN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - tangent
-ASN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - arcsine
-ACS{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - arccosine
-ATN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - arctangent
-
-These are not implemented.  They are not currently issued by the compiler,
-and are handled by routines in libc.  These are not implemented by the FPA11
-hardware, but are handled by the floating point support code.  They should 
-be implemented in future versions.
-
-Signalling:
-
-Signals are implemented.  However current ELF kernels produced by Rebel.com
-have a bug in them that prevents the module from generating a SIGFPE.  This
-is caused by a failure to alias fp_current to the kernel variable
-current_set[0] correctly.
-
-The kernel provided with this distribution (vmlinux-nwfpe-0.93) contains
-a fix for this problem and also incorporates the current version of the
-emulator directly.  It is possible to run with no floating point module
-loaded with this kernel.  It is provided as a demonstration of the 
-technology and for those who want to do floating point work that depends
-on signals.  It is not strictly necessary to use the module.
-
-A module (either the one provided by Russell King, or the one in this 
-distribution) can be loaded to replace the functionality of the emulator
-built into the kernel.
diff --git a/Documentation/arm/nwfpe/TODO b/Documentation/arm/nwfpe/TODO
deleted file mode 100644 (file)
index 8027061..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-TODO LIST
----------
-
-POW{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - power
-RPW{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - reverse power
-POL{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - polar angle (arctan2)
-
-LOG{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - logarithm to base 10
-LGN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - logarithm to base e 
-EXP{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - exponent
-SIN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - sine
-COS{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - cosine
-TAN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - tangent
-ASN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - arcsine
-ACS{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - arccosine
-ATN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - arctangent
-
-These are not implemented.  They are not currently issued by the compiler,
-and are handled by routines in libc.  These are not implemented by the FPA11
-hardware, but are handled by the floating point support code.  They should 
-be implemented in future versions.
-
-There are a couple of ways to approach the implementation of these.  One
-method would be to use accurate table methods for these routines.  I have 
-a couple of papers by S. Gal from IBM's research labs in Haifa, Israel that
-seem to promise extreme accuracy (in the order of 99.8%) and reasonable speed.
-These methods are used in GLIBC for some of the transcendental functions.
-
-Another approach, which I know little about is CORDIC.  This stands for
-Coordinate Rotation Digital Computer, and is a method of computing 
-transcendental functions using mostly shifts and adds and a few
-multiplications and divisions.  The ARM excels at shifts and adds,
-so such a method could be promising, but requires more research to 
-determine if it is feasible.
-
-Rounding Methods
-
-The IEEE standard defines 4 rounding modes.  Round to nearest is the
-default, but rounding to + or - infinity or round to zero are also allowed.
-Many architectures allow the rounding mode to be specified by modifying bits
-in a control register.  Not so with the ARM FPA11 architecture.  To change
-the rounding mode one must specify it with each instruction.
-
-This has made porting some benchmarks difficult.  It is possible to
-introduce such a capability into the emulator.  The FPCR contains 
-bits describing the rounding mode.  The emulator could be altered to 
-examine a flag, which if set forced it to ignore the rounding mode in
-the instruction, and use the mode specified in the bits in the FPCR.
-
-This would require a method of getting/setting the flag, and the bits
-in the FPCR.  This requires a kernel call in ArmLinux, as WFC/RFC are
-supervisor only instructions.  If anyone has any ideas or comments I
-would like to hear them.
-
-[NOTE: pulled out from some docs on ARM floating point, specifically
- for the Acorn FPE, but not limited to it:
-
- The floating point control register (FPCR) may only be present in some
- implementations: it is there to control the hardware in an implementation-
- specific manner, for example to disable the floating point system.  The user
- mode of the ARM is not permitted to use this register (since the right is
- reserved to alter it between implementations) and the WFC and RFC
- instructions will trap if tried in user mode.
-
- Hence, the answer is yes, you could do this, but then you will run a high
- risk of becoming isolated if and when hardware FP emulation comes out
-               -- Russell].
diff --git a/Documentation/arm/nwfpe/index.rst b/Documentation/arm/nwfpe/index.rst
new file mode 100644 (file)
index 0000000..3c4d2f9
--- /dev/null
@@ -0,0 +1,13 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===================================
+NetWinder's floating point emulator
+===================================
+
+.. toctree::
+   :maxdepth: 1
+
+   nwfpe
+   netwinder-fpe
+   notes
+   todo
diff --git a/Documentation/arm/nwfpe/netwinder-fpe.rst b/Documentation/arm/nwfpe/netwinder-fpe.rst
new file mode 100644 (file)
index 0000000..cbb3209
--- /dev/null
@@ -0,0 +1,162 @@
+=============
+Current State
+=============
+
+The following describes the current state of the NetWinder's floating point
+emulator.
+
+In the following nomenclature is used to describe the floating point
+instructions.  It follows the conventions in the ARM manual.
+
+::
+
+  <S|D|E> = <single|double|extended>, no default
+  {P|M|Z} = {round to +infinity,round to -infinity,round to zero},
+            default = round to nearest
+
+Note: items enclosed in {} are optional.
+
+Floating Point Coprocessor Data Transfer Instructions (CPDT)
+------------------------------------------------------------
+
+LDF/STF - load and store floating
+
+<LDF|STF>{cond}<S|D|E> Fd, Rn
+<LDF|STF>{cond}<S|D|E> Fd, [Rn, #<expression>]{!}
+<LDF|STF>{cond}<S|D|E> Fd, [Rn], #<expression>
+
+These instructions are fully implemented.
+
+LFM/SFM - load and store multiple floating
+
+Form 1 syntax:
+<LFM|SFM>{cond}<S|D|E> Fd, <count>, [Rn]
+<LFM|SFM>{cond}<S|D|E> Fd, <count>, [Rn, #<expression>]{!}
+<LFM|SFM>{cond}<S|D|E> Fd, <count>, [Rn], #<expression>
+
+Form 2 syntax:
+<LFM|SFM>{cond}<FD,EA> Fd, <count>, [Rn]{!}
+
+These instructions are fully implemented.  They store/load three words
+for each floating point register into the memory location given in the
+instruction.  The format in memory is unlikely to be compatible with
+other implementations, in particular the actual hardware.  Specific
+mention of this is made in the ARM manuals.
+
+Floating Point Coprocessor Register Transfer Instructions (CPRT)
+----------------------------------------------------------------
+
+Conversions, read/write status/control register instructions
+
+FLT{cond}<S,D,E>{P,M,Z} Fn, Rd          Convert integer to floating point
+FIX{cond}{P,M,Z} Rd, Fn                 Convert floating point to integer
+WFS{cond} Rd                            Write floating point status register
+RFS{cond} Rd                            Read floating point status register
+WFC{cond} Rd                            Write floating point control register
+RFC{cond} Rd                            Read floating point control register
+
+FLT/FIX are fully implemented.
+
+RFS/WFS are fully implemented.
+
+RFC/WFC are fully implemented.  RFC/WFC are supervisor only instructions, and
+presently check the CPU mode, and do an invalid instruction trap if not called
+from supervisor mode.
+
+Compare instructions
+
+CMF{cond} Fn, Fm        Compare floating
+CMFE{cond} Fn, Fm       Compare floating with exception
+CNF{cond} Fn, Fm        Compare negated floating
+CNFE{cond} Fn, Fm       Compare negated floating with exception
+
+These are fully implemented.
+
+Floating Point Coprocessor Data Instructions (CPDT)
+---------------------------------------------------
+
+Dyadic operations:
+
+ADF{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - add
+SUF{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - subtract
+RSF{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - reverse subtract
+MUF{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - multiply
+DVF{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - divide
+RDV{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - reverse divide
+
+These are fully implemented.
+
+FML{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - fast multiply
+FDV{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - fast divide
+FRD{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - fast reverse divide
+
+These are fully implemented as well.  They use the same algorithm as the
+non-fast versions.  Hence, in this implementation their performance is
+equivalent to the MUF/DVF/RDV instructions.  This is acceptable according
+to the ARM manual.  The manual notes these are defined only for single
+operands, on the actual FPA11 hardware they do not work for double or
+extended precision operands.  The emulator currently does not check
+the requested permissions conditions, and performs the requested operation.
+
+RMF{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - IEEE remainder
+
+This is fully implemented.
+
+Monadic operations:
+
+MVF{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - move
+MNF{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - move negated
+
+These are fully implemented.
+
+ABS{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - absolute value
+SQT{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - square root
+RND{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - round
+
+These are fully implemented.
+
+URD{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - unnormalized round
+NRM{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - normalize
+
+These are implemented.  URD is implemented using the same code as the RND
+instruction.  Since URD cannot return a unnormalized number, NRM becomes
+a NOP.
+
+Library calls:
+
+POW{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - power
+RPW{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - reverse power
+POL{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - polar angle (arctan2)
+
+LOG{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - logarithm to base 10
+LGN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - logarithm to base e
+EXP{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - exponent
+SIN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - sine
+COS{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - cosine
+TAN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - tangent
+ASN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - arcsine
+ACS{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - arccosine
+ATN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - arctangent
+
+These are not implemented.  They are not currently issued by the compiler,
+and are handled by routines in libc.  These are not implemented by the FPA11
+hardware, but are handled by the floating point support code.  They should
+be implemented in future versions.
+
+Signalling:
+
+Signals are implemented.  However current ELF kernels produced by Rebel.com
+have a bug in them that prevents the module from generating a SIGFPE.  This
+is caused by a failure to alias fp_current to the kernel variable
+current_set[0] correctly.
+
+The kernel provided with this distribution (vmlinux-nwfpe-0.93) contains
+a fix for this problem and also incorporates the current version of the
+emulator directly.  It is possible to run with no floating point module
+loaded with this kernel.  It is provided as a demonstration of the
+technology and for those who want to do floating point work that depends
+on signals.  It is not strictly necessary to use the module.
+
+A module (either the one provided by Russell King, or the one in this
+distribution) can be loaded to replace the functionality of the emulator
+built into the kernel.
diff --git a/Documentation/arm/nwfpe/notes.rst b/Documentation/arm/nwfpe/notes.rst
new file mode 100644 (file)
index 0000000..102e55a
--- /dev/null
@@ -0,0 +1,32 @@
+Notes
+=====
+
+There seems to be a problem with exp(double) and our emulator.  I haven't
+been able to track it down yet.  This does not occur with the emulator
+supplied by Russell King.
+
+I also found one oddity in the emulator.  I don't think it is serious but
+will point it out.  The ARM calling conventions require floating point
+registers f4-f7 to be preserved over a function call.  The compiler quite
+often uses an stfe instruction to save f4 on the stack upon entry to a
+function, and an ldfe instruction to restore it before returning.
+
+I was looking at some code, that calculated a double result, stored it in f4
+then made a function call. Upon return from the function call the number in
+f4 had been converted to an extended value in the emulator.
+
+This is a side effect of the stfe instruction.  The double in f4 had to be
+converted to extended, then stored.  If an lfm/sfm combination had been used,
+then no conversion would occur.  This has performance considerations.  The
+result from the function call and f4 were used in a multiplication.  If the
+emulator sees a multiply of a double and extended, it promotes the double to
+extended, then does the multiply in extended precision.
+
+This code will cause this problem:
+
+double x, y, z;
+z = log(x)/log(y);
+
+The result of log(x) (a double) will be calculated, returned in f0, then
+moved to f4 to preserve it over the log(y) call.  The division will be done
+in extended precision, due to the stfe instruction used to save f4 in log(y).
diff --git a/Documentation/arm/nwfpe/nwfpe.rst b/Documentation/arm/nwfpe/nwfpe.rst
new file mode 100644 (file)
index 0000000..35cd90d
--- /dev/null
@@ -0,0 +1,74 @@
+Introduction
+============
+
+This directory contains the version 0.92 test release of the NetWinder
+Floating Point Emulator.
+
+The majority of the code was written by me, Scott Bambrough It is
+written in C, with a small number of routines in inline assembler
+where required.  It was written quickly, with a goal of implementing a
+working version of all the floating point instructions the compiler
+emits as the first target.  I have attempted to be as optimal as
+possible, but there remains much room for improvement.
+
+I have attempted to make the emulator as portable as possible.  One of
+the problems is with leading underscores on kernel symbols.  Elf
+kernels have no leading underscores, a.out compiled kernels do.  I
+have attempted to use the C_SYMBOL_NAME macro wherever this may be
+important.
+
+Another choice I made was in the file structure.  I have attempted to
+contain all operating system specific code in one module (fpmodule.*).
+All the other files contain emulator specific code.  This should allow
+others to port the emulator to NetBSD for instance relatively easily.
+
+The floating point operations are based on SoftFloat Release 2, by
+John Hauser.  SoftFloat is a software implementation of floating-point
+that conforms to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.  As many as four formats are supported: single precision,
+double precision, extended double precision, and quadruple precision.
+All operations required by the standard are implemented, except for
+conversions to and from decimal.  We use only the single precision,
+double precision and extended double precision formats.  The port of
+SoftFloat to the ARM was done by Phil Blundell, based on an earlier
+port of SoftFloat version 1 by Neil Carson for NetBSD/arm32.
+
+The file README.FPE contains a description of what has been implemented
+so far in the emulator.  The file TODO contains a information on what
+remains to be done, and other ideas for the emulator.
+
+Bug reports, comments, suggestions should be directed to me at
+<scottb@netwinder.org>.  General reports of "this program doesn't
+work correctly when your emulator is installed" are useful for
+determining that bugs still exist; but are virtually useless when
+attempting to isolate the problem.  Please report them, but don't
+expect quick action.  Bugs still exist.  The problem remains in isolating
+which instruction contains the bug.  Small programs illustrating a specific
+problem are a godsend.
+
+Legal Notices
+-------------
+
+The NetWinder Floating Point Emulator is free software.  Everything Rebel.com
+has written is provided under the GNU GPL.  See the file COPYING for copying
+conditions.  Excluded from the above is the SoftFloat code.  John Hauser's
+legal notice for SoftFloat is included below.
+
+-------------------------------------------------------------------------------
+
+SoftFloat Legal Notice
+
+SoftFloat was written by John R. Hauser.  This work was made possible in
+part by the International Computer Science Institute, located at Suite 600,
+1947 Center Street, Berkeley, California 94704.  Funding was partially
+provided by the National Science Foundation under grant MIP-9311980.  The
+original version of this code was written as part of a project to build
+a fixed-point vector processor in collaboration with the University of
+California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+-------------------------------------------------------------------------------
diff --git a/Documentation/arm/nwfpe/todo.rst b/Documentation/arm/nwfpe/todo.rst
new file mode 100644 (file)
index 0000000..393f11b
--- /dev/null
@@ -0,0 +1,72 @@
+TODO LIST
+=========
+
+::
+
+  POW{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - power
+  RPW{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - reverse power
+  POL{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - polar angle (arctan2)
+
+  LOG{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - logarithm to base 10
+  LGN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - logarithm to base e
+  EXP{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - exponent
+  SIN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - sine
+  COS{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - cosine
+  TAN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - tangent
+  ASN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - arcsine
+  ACS{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - arccosine
+  ATN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - arctangent
+
+These are not implemented.  They are not currently issued by the compiler,
+and are handled by routines in libc.  These are not implemented by the FPA11
+hardware, but are handled by the floating point support code.  They should
+be implemented in future versions.
+
+There are a couple of ways to approach the implementation of these.  One
+method would be to use accurate table methods for these routines.  I have
+a couple of papers by S. Gal from IBM's research labs in Haifa, Israel that
+seem to promise extreme accuracy (in the order of 99.8%) and reasonable speed.
+These methods are used in GLIBC for some of the transcendental functions.
+
+Another approach, which I know little about is CORDIC.  This stands for
+Coordinate Rotation Digital Computer, and is a method of computing
+transcendental functions using mostly shifts and adds and a few
+multiplications and divisions.  The ARM excels at shifts and adds,
+so such a method could be promising, but requires more research to
+determine if it is feasible.
+
+Rounding Methods
+----------------
+
+The IEEE standard defines 4 rounding modes.  Round to nearest is the
+default, but rounding to + or - infinity or round to zero are also allowed.
+Many architectures allow the rounding mode to be specified by modifying bits
+in a control register.  Not so with the ARM FPA11 architecture.  To change
+the rounding mode one must specify it with each instruction.
+
+This has made porting some benchmarks difficult.  It is possible to
+introduce such a capability into the emulator.  The FPCR contains
+bits describing the rounding mode.  The emulator could be altered to
+examine a flag, which if set forced it to ignore the rounding mode in
+the instruction, and use the mode specified in the bits in the FPCR.
+
+This would require a method of getting/setting the flag, and the bits
+in the FPCR.  This requires a kernel call in ArmLinux, as WFC/RFC are
+supervisor only instructions.  If anyone has any ideas or comments I
+would like to hear them.
+
+NOTE:
+ pulled out from some docs on ARM floating point, specifically
+ for the Acorn FPE, but not limited to it:
+
+ The floating point control register (FPCR) may only be present in some
+ implementations: it is there to control the hardware in an implementation-
+ specific manner, for example to disable the floating point system.  The user
+ mode of the ARM is not permitted to use this register (since the right is
+ reserved to alter it between implementations) and the WFC and RFC
+ instructions will trap if tried in user mode.
+
+ Hence, the answer is yes, you could do this, but then you will run a high
+ risk of becoming isolated if and when hardware FP emulation comes out
+
+               -- Russell.
diff --git a/Documentation/arm/omap/dss.rst b/Documentation/arm/omap/dss.rst
new file mode 100644 (file)
index 0000000..a40c4d9
--- /dev/null
@@ -0,0 +1,372 @@
+=========================
+OMAP2/3 Display Subsystem
+=========================
+
+This is an almost total rewrite of the OMAP FB driver in drivers/video/omap
+(let's call it DSS1). The main differences between DSS1 and DSS2 are DSI,
+TV-out and multiple display support, but there are lots of small improvements
+also.
+
+The DSS2 driver (omapdss module) is in arch/arm/plat-omap/dss/, and the FB,
+panel and controller drivers are in drivers/video/omap2/. DSS1 and DSS2 live
+currently side by side, you can choose which one to use.
+
+Features
+--------
+
+Working and tested features include:
+
+- MIPI DPI (parallel) output
+- MIPI DSI output in command mode
+- MIPI DBI (RFBI) output
+- SDI output
+- TV output
+- All pieces can be compiled as a module or inside kernel
+- Use DISPC to update any of the outputs
+- Use CPU to update RFBI or DSI output
+- OMAP DISPC planes
+- RGB16, RGB24 packed, RGB24 unpacked
+- YUV2, UYVY
+- Scaling
+- Adjusting DSS FCK to find a good pixel clock
+- Use DSI DPLL to create DSS FCK
+
+Tested boards include:
+- OMAP3 SDP board
+- Beagle board
+- N810
+
+omapdss driver
+--------------
+
+The DSS driver does not itself have any support for Linux framebuffer, V4L or
+such like the current ones, but it has an internal kernel API that upper level
+drivers can use.
+
+The DSS driver models OMAP's overlays, overlay managers and displays in a
+flexible way to enable non-common multi-display configuration. In addition to
+modelling the hardware overlays, omapdss supports virtual overlays and overlay
+managers. These can be used when updating a display with CPU or system DMA.
+
+omapdss driver support for audio
+--------------------------------
+There exist several display technologies and standards that support audio as
+well. Hence, it is relevant to update the DSS device driver to provide an audio
+interface that may be used by an audio driver or any other driver interested in
+the functionality.
+
+The audio_enable function is intended to prepare the relevant
+IP for playback (e.g., enabling an audio FIFO, taking in/out of reset
+some IP, enabling companion chips, etc). It is intended to be called before
+audio_start. The audio_disable function performs the reverse operation and is
+intended to be called after audio_stop.
+
+While a given DSS device driver may support audio, it is possible that for
+certain configurations audio is not supported (e.g., an HDMI display using a
+VESA video timing). The audio_supported function is intended to query whether
+the current configuration of the display supports audio.
+
+The audio_config function is intended to configure all the relevant audio
+parameters of the display. In order to make the function independent of any
+specific DSS device driver, a struct omap_dss_audio is defined. Its purpose
+is to contain all the required parameters for audio configuration. At the
+moment, such structure contains pointers to IEC-60958 channel status word
+and CEA-861 audio infoframe structures. This should be enough to support
+HDMI and DisplayPort, as both are based on CEA-861 and IEC-60958.
+
+The audio_enable/disable, audio_config and audio_supported functions could be
+implemented as functions that may sleep. Hence, they should not be called
+while holding a spinlock or a readlock.
+
+The audio_start/audio_stop function is intended to effectively start/stop audio
+playback after the configuration has taken place. These functions are designed
+to be used in an atomic context. Hence, audio_start should return quickly and be
+called only after all the needed resources for audio playback (audio FIFOs,
+DMA channels, companion chips, etc) have been enabled to begin data transfers.
+audio_stop is designed to only stop the audio transfers. The resources used
+for playback are released using audio_disable.
+
+The enum omap_dss_audio_state may be used to help the implementations of
+the interface to keep track of the audio state. The initial state is _DISABLED;
+then, the state transitions to _CONFIGURED, and then, when it is ready to
+play audio, to _ENABLED. The state _PLAYING is used when the audio is being
+rendered.
+
+
+Panel and controller drivers
+----------------------------
+
+The drivers implement panel or controller specific functionality and are not
+usually visible to users except through omapfb driver.  They register
+themselves to the DSS driver.
+
+omapfb driver
+-------------
+
+The omapfb driver implements arbitrary number of standard linux framebuffers.
+These framebuffers can be routed flexibly to any overlays, thus allowing very
+dynamic display architecture.
+
+The driver exports some omapfb specific ioctls, which are compatible with the
+ioctls in the old driver.
+
+The rest of the non standard features are exported via sysfs. Whether the final
+implementation will use sysfs, or ioctls, is still open.
+
+V4L2 drivers
+------------
+
+V4L2 is being implemented in TI.
+
+From omapdss point of view the V4L2 drivers should be similar to framebuffer
+driver.
+
+Architecture
+--------------------
+
+Some clarification what the different components do:
+
+    - Framebuffer is a memory area inside OMAP's SRAM/SDRAM that contains the
+      pixel data for the image. Framebuffer has width and height and color
+      depth.
+    - Overlay defines where the pixels are read from and where they go on the
+      screen. The overlay may be smaller than framebuffer, thus displaying only
+      part of the framebuffer. The position of the overlay may be changed if
+      the overlay is smaller than the display.
+    - Overlay manager combines the overlays in to one image and feeds them to
+      display.
+    - Display is the actual physical display device.
+
+A framebuffer can be connected to multiple overlays to show the same pixel data
+on all of the overlays. Note that in this case the overlay input sizes must be
+the same, but, in case of video overlays, the output size can be different. Any
+framebuffer can be connected to any overlay.
+
+An overlay can be connected to one overlay manager. Also DISPC overlays can be
+connected only to DISPC overlay managers, and virtual overlays can be only
+connected to virtual overlays.
+
+An overlay manager can be connected to one display. There are certain
+restrictions which kinds of displays an overlay manager can be connected:
+
+    - DISPC TV overlay manager can be only connected to TV display.
+    - Virtual overlay managers can only be connected to DBI or DSI displays.
+    - DISPC LCD overlay manager can be connected to all displays, except TV
+      display.
+
+Sysfs
+-----
+The sysfs interface is mainly used for testing. I don't think sysfs
+interface is the best for this in the final version, but I don't quite know
+what would be the best interfaces for these things.
+
+The sysfs interface is divided to two parts: DSS and FB.
+
+/sys/class/graphics/fb? directory:
+mirror         0=off, 1=on
+rotate         Rotation 0-3 for 0, 90, 180, 270 degrees
+rotate_type    0 = DMA rotation, 1 = VRFB rotation
+overlays       List of overlay numbers to which framebuffer pixels go
+phys_addr      Physical address of the framebuffer
+virt_addr      Virtual address of the framebuffer
+size           Size of the framebuffer
+
+/sys/devices/platform/omapdss/overlay? directory:
+enabled                0=off, 1=on
+input_size     width,height (ie. the framebuffer size)
+manager                Destination overlay manager name
+name
+output_size    width,height
+position       x,y
+screen_width   width
+global_alpha           global alpha 0-255 0=transparent 255=opaque
+
+/sys/devices/platform/omapdss/manager? directory:
+display                                Destination display
+name
+alpha_blending_enabled         0=off, 1=on
+trans_key_enabled              0=off, 1=on
+trans_key_type                 gfx-destination, video-source
+trans_key_value                        transparency color key (RGB24)
+default_color                  default background color (RGB24)
+
+/sys/devices/platform/omapdss/display? directory:
+
+=============== =============================================================
+ctrl_name      Controller name
+mirror         0=off, 1=on
+update_mode    0=off, 1=auto, 2=manual
+enabled                0=off, 1=on
+name
+rotate         Rotation 0-3 for 0, 90, 180, 270 degrees
+timings                Display timings (pixclock,xres/hfp/hbp/hsw,yres/vfp/vbp/vsw)
+               When writing, two special timings are accepted for tv-out:
+               "pal" and "ntsc"
+panel_name
+tear_elim      Tearing elimination 0=off, 1=on
+output_type    Output type (video encoder only): "composite" or "svideo"
+=============== =============================================================
+
+There are also some debugfs files at <debugfs>/omapdss/ which show information
+about clocks and registers.
+
+Examples
+--------
+
+The following definitions have been made for the examples below::
+
+       ovl0=/sys/devices/platform/omapdss/overlay0
+       ovl1=/sys/devices/platform/omapdss/overlay1
+       ovl2=/sys/devices/platform/omapdss/overlay2
+
+       mgr0=/sys/devices/platform/omapdss/manager0
+       mgr1=/sys/devices/platform/omapdss/manager1
+
+       lcd=/sys/devices/platform/omapdss/display0
+       dvi=/sys/devices/platform/omapdss/display1
+       tv=/sys/devices/platform/omapdss/display2
+
+       fb0=/sys/class/graphics/fb0
+       fb1=/sys/class/graphics/fb1
+       fb2=/sys/class/graphics/fb2
+
+Default setup on OMAP3 SDP
+--------------------------
+
+Here's the default setup on OMAP3 SDP board. All planes go to LCD. DVI
+and TV-out are not in use. The columns from left to right are:
+framebuffers, overlays, overlay managers, displays. Framebuffers are
+handled by omapfb, and the rest by the DSS::
+
+       FB0 --- GFX  -\            DVI
+       FB1 --- VID1 --+- LCD ---- LCD
+       FB2 --- VID2 -/   TV ----- TV
+
+Example: Switch from LCD to DVI
+-------------------------------
+
+::
+
+       w=`cat $dvi/timings | cut -d "," -f 2 | cut -d "/" -f 1`
+       h=`cat $dvi/timings | cut -d "," -f 3 | cut -d "/" -f 1`
+
+       echo "0" > $lcd/enabled
+       echo "" > $mgr0/display
+       fbset -fb /dev/fb0 -xres $w -yres $h -vxres $w -vyres $h
+       # at this point you have to switch the dvi/lcd dip-switch from the omap board
+       echo "dvi" > $mgr0/display
+       echo "1" > $dvi/enabled
+
+After this the configuration looks like:::
+
+       FB0 --- GFX  -\         -- DVI
+       FB1 --- VID1 --+- LCD -/   LCD
+       FB2 --- VID2 -/   TV ----- TV
+
+Example: Clone GFX overlay to LCD and TV
+----------------------------------------
+
+::
+
+       w=`cat $tv/timings | cut -d "," -f 2 | cut -d "/" -f 1`
+       h=`cat $tv/timings | cut -d "," -f 3 | cut -d "/" -f 1`
+
+       echo "0" > $ovl0/enabled
+       echo "0" > $ovl1/enabled
+
+       echo "" > $fb1/overlays
+       echo "0,1" > $fb0/overlays
+
+       echo "$w,$h" > $ovl1/output_size
+       echo "tv" > $ovl1/manager
+
+       echo "1" > $ovl0/enabled
+       echo "1" > $ovl1/enabled
+
+       echo "1" > $tv/enabled
+
+After this the configuration looks like (only relevant parts shown)::
+
+       FB0 +-- GFX  ---- LCD ---- LCD
+       \- VID1 ---- TV  ---- TV
+
+Misc notes
+----------
+
+OMAP FB allocates the framebuffer memory using the standard dma allocator. You
+can enable Contiguous Memory Allocator (CONFIG_CMA) to improve the dma
+allocator, and if CMA is enabled, you use "cma=" kernel parameter to increase
+the global memory area for CMA.
+
+Using DSI DPLL to generate pixel clock it is possible produce the pixel clock
+of 86.5MHz (max possible), and with that you get 1280x1024@57 output from DVI.
+
+Rotation and mirroring currently only supports RGB565 and RGB8888 modes. VRFB
+does not support mirroring.
+
+VRFB rotation requires much more memory than non-rotated framebuffer, so you
+probably need to increase your vram setting before using VRFB rotation. Also,
+many applications may not work with VRFB if they do not pay attention to all
+framebuffer parameters.
+
+Kernel boot arguments
+---------------------
+
+omapfb.mode=<display>:<mode>[,...]
+       - Default video mode for specified displays. For example,
+         "dvi:800x400MR-24@60".  See drivers/video/modedb.c.
+         There are also two special modes: "pal" and "ntsc" that
+         can be used to tv out.
+
+omapfb.vram=<fbnum>:<size>[@<physaddr>][,...]
+       - VRAM allocated for a framebuffer. Normally omapfb allocates vram
+         depending on the display size. With this you can manually allocate
+         more or define the physical address of each framebuffer. For example,
+         "1:4M" to allocate 4M for fb1.
+
+omapfb.debug=<y|n>
+       - Enable debug printing. You have to have OMAPFB debug support enabled
+         in kernel config.
+
+omapfb.test=<y|n>
+       - Draw test pattern to framebuffer whenever framebuffer settings change.
+         You need to have OMAPFB debug support enabled in kernel config.
+
+omapfb.vrfb=<y|n>
+       - Use VRFB rotation for all framebuffers.
+
+omapfb.rotate=<angle>
+       - Default rotation applied to all framebuffers.
+         0 - 0 degree rotation
+         1 - 90 degree rotation
+         2 - 180 degree rotation
+         3 - 270 degree rotation
+
+omapfb.mirror=<y|n>
+       - Default mirror for all framebuffers. Only works with DMA rotation.
+
+omapdss.def_disp=<display>
+       - Name of default display, to which all overlays will be connected.
+         Common examples are "lcd" or "tv".
+
+omapdss.debug=<y|n>
+       - Enable debug printing. You have to have DSS debug support enabled in
+         kernel config.
+
+TODO
+----
+
+DSS locking
+
+Error checking
+
+- Lots of checks are missing or implemented just as BUG()
+
+System DMA update for DSI
+
+- Can be used for RGB16 and RGB24P modes. Probably not for RGB24U (how
+  to skip the empty byte?)
+
+OMAP1 support
+
+- Not sure if needed
diff --git a/Documentation/arm/omap/index.rst b/Documentation/arm/omap/index.rst
new file mode 100644 (file)
index 0000000..8b365b2
--- /dev/null
@@ -0,0 +1,12 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=======
+TI OMAP
+=======
+
+.. toctree::
+   :maxdepth: 1
+
+   omap
+   omap_pm
+   dss
diff --git a/Documentation/arm/omap/omap.rst b/Documentation/arm/omap/omap.rst
new file mode 100644 (file)
index 0000000..f440c0f
--- /dev/null
@@ -0,0 +1,18 @@
+============
+OMAP history
+============
+
+This file contains documentation for running mainline
+kernel on omaps.
+
+======         ======================================================
+KERNEL         NEW DEPENDENCIES
+======         ======================================================
+v4.3+          Update is needed for custom .config files to make sure
+               CONFIG_REGULATOR_PBIAS is enabled for MMC1 to work
+               properly.
+
+v4.18+         Update is needed for custom .config files to make sure
+               CONFIG_MMC_SDHCI_OMAP is enabled for all MMC instances
+               to work in DRA7 and K2G based boards.
+======         ======================================================
diff --git a/Documentation/arm/omap/omap_pm.rst b/Documentation/arm/omap/omap_pm.rst
new file mode 100644 (file)
index 0000000..a335e4c
--- /dev/null
@@ -0,0 +1,165 @@
+=====================
+The OMAP PM interface
+=====================
+
+This document describes the temporary OMAP PM interface.  Driver
+authors use these functions to communicate minimum latency or
+throughput constraints to the kernel power management code.
+Over time, the intention is to merge features from the OMAP PM
+interface into the Linux PM QoS code.
+
+Drivers need to express PM parameters which:
+
+- support the range of power management parameters present in the TI SRF;
+
+- separate the drivers from the underlying PM parameter
+  implementation, whether it is the TI SRF or Linux PM QoS or Linux
+  latency framework or something else;
+
+- specify PM parameters in terms of fundamental units, such as
+  latency and throughput, rather than units which are specific to OMAP
+  or to particular OMAP variants;
+
+- allow drivers which are shared with other architectures (e.g.,
+  DaVinci) to add these constraints in a way which won't affect non-OMAP
+  systems,
+
+- can be implemented immediately with minimal disruption of other
+  architectures.
+
+
+This document proposes the OMAP PM interface, including the following
+five power management functions for driver code:
+
+1. Set the maximum MPU wakeup latency::
+
+   (*pdata->set_max_mpu_wakeup_lat)(struct device *dev, unsigned long t)
+
+2. Set the maximum device wakeup latency::
+
+   (*pdata->set_max_dev_wakeup_lat)(struct device *dev, unsigned long t)
+
+3. Set the maximum system DMA transfer start latency (CORE pwrdm)::
+
+   (*pdata->set_max_sdma_lat)(struct device *dev, long t)
+
+4. Set the minimum bus throughput needed by a device::
+
+   (*pdata->set_min_bus_tput)(struct device *dev, u8 agent_id, unsigned long r)
+
+5. Return the number of times the device has lost context::
+
+   (*pdata->get_dev_context_loss_count)(struct device *dev)
+
+
+Further documentation for all OMAP PM interface functions can be
+found in arch/arm/plat-omap/include/mach/omap-pm.h.
+
+
+The OMAP PM layer is intended to be temporary
+---------------------------------------------
+
+The intention is that eventually the Linux PM QoS layer should support
+the range of power management features present in OMAP3.  As this
+happens, existing drivers using the OMAP PM interface can be modified
+to use the Linux PM QoS code; and the OMAP PM interface can disappear.
+
+
+Driver usage of the OMAP PM functions
+-------------------------------------
+
+As the 'pdata' in the above examples indicates, these functions are
+exposed to drivers through function pointers in driver .platform_data
+structures.  The function pointers are initialized by the `board-*.c`
+files to point to the corresponding OMAP PM functions:
+
+- set_max_dev_wakeup_lat will point to
+  omap_pm_set_max_dev_wakeup_lat(), etc.  Other architectures which do
+  not support these functions should leave these function pointers set
+  to NULL.  Drivers should use the following idiom::
+
+        if (pdata->set_max_dev_wakeup_lat)
+            (*pdata->set_max_dev_wakeup_lat)(dev, t);
+
+The most common usage of these functions will probably be to specify
+the maximum time from when an interrupt occurs, to when the device
+becomes accessible.  To accomplish this, driver writers should use the
+set_max_mpu_wakeup_lat() function to constrain the MPU wakeup
+latency, and the set_max_dev_wakeup_lat() function to constrain the
+device wakeup latency (from clk_enable() to accessibility).  For
+example::
+
+        /* Limit MPU wakeup latency */
+        if (pdata->set_max_mpu_wakeup_lat)
+            (*pdata->set_max_mpu_wakeup_lat)(dev, tc);
+
+        /* Limit device powerdomain wakeup latency */
+        if (pdata->set_max_dev_wakeup_lat)
+            (*pdata->set_max_dev_wakeup_lat)(dev, td);
+
+        /* total wakeup latency in this example: (tc + td) */
+
+The PM parameters can be overwritten by calling the function again
+with the new value.  The settings can be removed by calling the
+function with a t argument of -1 (except in the case of
+set_max_bus_tput(), which should be called with an r argument of 0).
+
+The fifth function above, omap_pm_get_dev_context_loss_count(),
+is intended as an optimization to allow drivers to determine whether the
+device has lost its internal context.  If context has been lost, the
+driver must restore its internal context before proceeding.
+
+
+Other specialized interface functions
+-------------------------------------
+
+The five functions listed above are intended to be usable by any
+device driver.  DSPBridge and CPUFreq have a few special requirements.
+DSPBridge expresses target DSP performance levels in terms of OPP IDs.
+CPUFreq expresses target MPU performance levels in terms of MPU
+frequency.  The OMAP PM interface contains functions for these
+specialized cases to convert that input information (OPPs/MPU
+frequency) into the form that the underlying power management
+implementation needs:
+
+6. `(*pdata->dsp_get_opp_table)(void)`
+
+7. `(*pdata->dsp_set_min_opp)(u8 opp_id)`
+
+8. `(*pdata->dsp_get_opp)(void)`
+
+9. `(*pdata->cpu_get_freq_table)(void)`
+
+10. `(*pdata->cpu_set_freq)(unsigned long f)`
+
+11. `(*pdata->cpu_get_freq)(void)`
+
+Customizing OPP for platform
+============================
+Defining CONFIG_PM should enable OPP layer for the silicon
+and the registration of OPP table should take place automatically.
+However, in special cases, the default OPP table may need to be
+tweaked, for e.g.:
+
+ * enable default OPPs which are disabled by default, but which
+   could be enabled on a platform
+ * Disable an unsupported OPP on the platform
+ * Define and add a custom opp table entry
+   in these cases, the board file needs to do additional steps as follows:
+
+arch/arm/mach-omapx/board-xyz.c::
+
+       #include "pm.h"
+       ....
+       static void __init omap_xyz_init_irq(void)
+       {
+               ....
+               /* Initialize the default table */
+               omapx_opp_init();
+               /* Do customization to the defaults */
+               ....
+       }
+
+NOTE:
+  omapx_opp_init will be omap3_opp_init or as required
+  based on the omap family.
diff --git a/Documentation/arm/porting.rst b/Documentation/arm/porting.rst
new file mode 100644 (file)
index 0000000..bd21958
--- /dev/null
@@ -0,0 +1,137 @@
+=======
+Porting
+=======
+
+Taken from list archive at http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2001-July/004064.html
+
+Initial definitions
+-------------------
+
+The following symbol definitions rely on you knowing the translation that
+__virt_to_phys() does for your machine.  This macro converts the passed
+virtual address to a physical address.  Normally, it is simply:
+
+               phys = virt - PAGE_OFFSET + PHYS_OFFSET
+
+
+Decompressor Symbols
+--------------------
+
+ZTEXTADDR
+       Start address of decompressor.  There's no point in talking about
+       virtual or physical addresses here, since the MMU will be off at
+       the time when you call the decompressor code.  You normally call
+       the kernel at this address to start it booting.  This doesn't have
+       to be located in RAM, it can be in flash or other read-only or
+       read-write addressable medium.
+
+ZBSSADDR
+       Start address of zero-initialised work area for the decompressor.
+       This must be pointing at RAM.  The decompressor will zero initialise
+       this for you.  Again, the MMU will be off.
+
+ZRELADDR
+       This is the address where the decompressed kernel will be written,
+       and eventually executed.  The following constraint must be valid:
+
+               __virt_to_phys(TEXTADDR) == ZRELADDR
+
+       The initial part of the kernel is carefully coded to be position
+       independent.
+
+INITRD_PHYS
+       Physical address to place the initial RAM disk.  Only relevant if
+       you are using the bootpImage stuff (which only works on the old
+       struct param_struct).
+
+INITRD_VIRT
+       Virtual address of the initial RAM disk.  The following  constraint
+       must be valid:
+
+               __virt_to_phys(INITRD_VIRT) == INITRD_PHYS
+
+PARAMS_PHYS
+       Physical address of the struct param_struct or tag list, giving the
+       kernel various parameters about its execution environment.
+
+
+Kernel Symbols
+--------------
+
+PHYS_OFFSET
+       Physical start address of the first bank of RAM.
+
+PAGE_OFFSET
+       Virtual start address of the first bank of RAM.  During the kernel
+       boot phase, virtual address PAGE_OFFSET will be mapped to physical
+       address PHYS_OFFSET, along with any other mappings you supply.
+       This should be the same value as TASK_SIZE.
+
+TASK_SIZE
+       The maximum size of a user process in bytes.  Since user space
+       always starts at zero, this is the maximum address that a user
+       process can access+1.  The user space stack grows down from this
+       address.
+
+       Any virtual address below TASK_SIZE is deemed to be user process
+       area, and therefore managed dynamically on a process by process
+       basis by the kernel.  I'll call this the user segment.
+
+       Anything above TASK_SIZE is common to all processes.  I'll call
+       this the kernel segment.
+
+       (In other words, you can't put IO mappings below TASK_SIZE, and
+       hence PAGE_OFFSET).
+
+TEXTADDR
+       Virtual start address of kernel, normally PAGE_OFFSET + 0x8000.
+       This is where the kernel image ends up.  With the latest kernels,
+       it must be located at 32768 bytes into a 128MB region.  Previous
+       kernels placed a restriction of 256MB here.
+
+DATAADDR
+       Virtual address for the kernel data segment.  Must not be defined
+       when using the decompressor.
+
+VMALLOC_START / VMALLOC_END
+       Virtual addresses bounding the vmalloc() area.  There must not be
+       any static mappings in this area; vmalloc will overwrite them.
+       The addresses must also be in the kernel segment (see above).
+       Normally, the vmalloc() area starts VMALLOC_OFFSET bytes above the
+       last virtual RAM address (found using variable high_memory).
+
+VMALLOC_OFFSET
+       Offset normally incorporated into VMALLOC_START to provide a hole
+       between virtual RAM and the vmalloc area.  We do this to allow
+       out of bounds memory accesses (eg, something writing off the end
+       of the mapped memory map) to be caught.  Normally set to 8MB.
+
+Architecture Specific Macros
+----------------------------
+
+BOOT_MEM(pram,pio,vio)
+       `pram` specifies the physical start address of RAM.  Must always
+       be present, and should be the same as PHYS_OFFSET.
+
+       `pio` is the physical address of an 8MB region containing IO for
+       use with the debugging macros in arch/arm/kernel/debug-armv.S.
+
+       `vio` is the virtual address of the 8MB debugging region.
+
+       It is expected that the debugging region will be re-initialised
+       by the architecture specific code later in the code (via the
+       MAPIO function).
+
+BOOT_PARAMS
+       Same as, and see PARAMS_PHYS.
+
+FIXUP(func)
+       Machine specific fixups, run before memory subsystems have been
+       initialised.
+
+MAPIO(func)
+       Machine specific function to map IO areas (including the debug
+       region above).
+
+INITIRQ(func)
+       Machine specific function to initialise interrupts.
diff --git a/Documentation/arm/pxa/mfp.rst b/Documentation/arm/pxa/mfp.rst
new file mode 100644 (file)
index 0000000..ac34e5d
--- /dev/null
@@ -0,0 +1,288 @@
+==============================================
+MFP Configuration for PXA2xx/PXA3xx Processors
+==============================================
+
+                       Eric Miao <eric.miao@marvell.com>
+
+MFP stands for Multi-Function Pin, which is the pin-mux logic on PXA3xx and
+later PXA series processors.  This document describes the existing MFP API,
+and how board/platform driver authors could make use of it.
+
+Basic Concept
+=============
+
+Unlike the GPIO alternate function settings on PXA25x and PXA27x, a new MFP
+mechanism is introduced from PXA3xx to completely move the pin-mux functions
+out of the GPIO controller. In addition to pin-mux configurations, the MFP
+also controls the low power state, driving strength, pull-up/down and event
+detection of each pin.  Below is a diagram of internal connections between
+the MFP logic and the remaining SoC peripherals::
+
+ +--------+
+ |        |--(GPIO19)--+
+ |  GPIO  |            |
+ |        |--(GPIO...) |
+ +--------+            |
+                       |       +---------+
+ +--------+            +------>|         |
+ |  PWM2  |--(PWM_OUT)-------->|   MFP   |
+ +--------+            +------>|         |-------> to external PAD
+                       | +---->|         |
+ +--------+            | | +-->|         |
+ |  SSP2  |---(TXD)----+ | |   +---------+
+ +--------+              | |
+                         | |
+ +--------+              | |
+ | Keypad |--(MKOUT4)----+ |
+ +--------+                |
+                           |
+ +--------+                |
+ |  UART2 |---(TXD)--------+
+ +--------+
+
+NOTE: the external pad is named as MFP_PIN_GPIO19, it doesn't necessarily
+mean it's dedicated for GPIO19, only as a hint that internally this pin
+can be routed from GPIO19 of the GPIO controller.
+
+To better understand the change from PXA25x/PXA27x GPIO alternate function
+to this new MFP mechanism, here are several key points:
+
+  1. GPIO controller on PXA3xx is now a dedicated controller, same as other
+     internal controllers like PWM, SSP and UART, with 128 internal signals
+     which can be routed to external through one or more MFPs (e.g. GPIO<0>
+     can be routed through either MFP_PIN_GPIO0 as well as MFP_PIN_GPIO0_2,
+     see arch/arm/mach-pxa/mfp-pxa300.h)
+
+  2. Alternate function configuration is removed from this GPIO controller,
+     the remaining functions are pure GPIO-specific, i.e.
+
+       - GPIO signal level control
+       - GPIO direction control
+       - GPIO level change detection
+
+  3. Low power state for each pin is now controlled by MFP, this means the
+     PGSRx registers on PXA2xx are now useless on PXA3xx
+
+  4. Wakeup detection is now controlled by MFP, PWER does not control the
+     wakeup from GPIO(s) any more, depending on the sleeping state, ADxER
+     (as defined in pxa3xx-regs.h) controls the wakeup from MFP
+
+NOTE: with such a clear separation of MFP and GPIO, by GPIO<xx> we normally
+mean it is a GPIO signal, and by MFP<xxx> or pin xxx, we mean a physical
+pad (or ball).
+
+MFP API Usage
+=============
+
+For board code writers, here are some guidelines:
+
+1. include ONE of the following header files in your <board>.c:
+
+   - #include "mfp-pxa25x.h"
+   - #include "mfp-pxa27x.h"
+   - #include "mfp-pxa300.h"
+   - #include "mfp-pxa320.h"
+   - #include "mfp-pxa930.h"
+
+   NOTE: only one file in your <board>.c, depending on the processors used,
+   because pin configuration definitions may conflict in these file (i.e.
+   same name, different meaning and settings on different processors). E.g.
+   for zylonite platform, which support both PXA300/PXA310 and PXA320, two
+   separate files are introduced: zylonite_pxa300.c and zylonite_pxa320.c
+   (in addition to handle MFP configuration differences, they also handle
+   the other differences between the two combinations).
+
+   NOTE: PXA300 and PXA310 are almost identical in pin configurations (with
+   PXA310 supporting some additional ones), thus the difference is actually
+   covered in a single mfp-pxa300.h.
+
+2. prepare an array for the initial pin configurations, e.g.::
+
+     static unsigned long mainstone_pin_config[] __initdata = {
+       /* Chip Select */
+       GPIO15_nCS_1,
+
+       /* LCD - 16bpp Active TFT */
+       GPIOxx_TFT_LCD_16BPP,
+       GPIO16_PWM0_OUT,        /* Backlight */
+
+       /* MMC */
+       GPIO32_MMC_CLK,
+       GPIO112_MMC_CMD,
+       GPIO92_MMC_DAT_0,
+       GPIO109_MMC_DAT_1,
+       GPIO110_MMC_DAT_2,
+       GPIO111_MMC_DAT_3,
+
+       ...
+
+       /* GPIO */
+       GPIO1_GPIO | WAKEUP_ON_EDGE_BOTH,
+     };
+
+   a) once the pin configurations are passed to pxa{2xx,3xx}_mfp_config(),
+   and written to the actual registers, they are useless and may discard,
+   adding '__initdata' will help save some additional bytes here.
+
+   b) when there is only one possible pin configurations for a component,
+   some simplified definitions can be used, e.g. GPIOxx_TFT_LCD_16BPP on
+   PXA25x and PXA27x processors
+
+   c) if by board design, a pin can be configured to wake up the system
+   from low power state, it can be 'OR'ed with any of:
+
+      WAKEUP_ON_EDGE_BOTH
+      WAKEUP_ON_EDGE_RISE
+      WAKEUP_ON_EDGE_FALL
+      WAKEUP_ON_LEVEL_HIGH - specifically for enabling of keypad GPIOs,
+
+   to indicate that this pin has the capability of wake-up the system,
+   and on which edge(s). This, however, doesn't necessarily mean the
+   pin _will_ wakeup the system, it will only when set_irq_wake() is
+   invoked with the corresponding GPIO IRQ (GPIO_IRQ(xx) or gpio_to_irq())
+   and eventually calls gpio_set_wake() for the actual register setting.
+
+   d) although PXA3xx MFP supports edge detection on each pin, the
+   internal logic will only wakeup the system when those specific bits
+   in ADxER registers are set, which can be well mapped to the
+   corresponding peripheral, thus set_irq_wake() can be called with
+   the peripheral IRQ to enable the wakeup.
+
+
+MFP on PXA3xx
+=============
+
+Every external I/O pad on PXA3xx (excluding those for special purpose) has
+one MFP logic associated, and is controlled by one MFP register (MFPR).
+
+The MFPR has the following bit definitions (for PXA300/PXA310/PXA320)::
+
+ 31                        16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
+  +-------------------------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+  |         RESERVED        |PS|PU|PD|  DRIVE |SS|SD|SO|EC|EF|ER|--| AF_SEL |
+  +-------------------------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+  Bit 3:   RESERVED
+  Bit 4:   EDGE_RISE_EN - enable detection of rising edge on this pin
+  Bit 5:   EDGE_FALL_EN - enable detection of falling edge on this pin
+  Bit 6:   EDGE_CLEAR   - disable edge detection on this pin
+  Bit 7:   SLEEP_OE_N   - enable outputs during low power modes
+  Bit 8:   SLEEP_DATA   - output data on the pin during low power modes
+  Bit 9:   SLEEP_SEL    - selection control for low power modes signals
+  Bit 13:  PULLDOWN_EN  - enable the internal pull-down resistor on this pin
+  Bit 14:  PULLUP_EN    - enable the internal pull-up resistor on this pin
+  Bit 15:  PULL_SEL     - pull state controlled by selected alternate function
+                          (0) or by PULL{UP,DOWN}_EN bits (1)
+
+  Bit 0 - 2: AF_SEL - alternate function selection, 8 possibilities, from 0-7
+  Bit 10-12: DRIVE  - drive strength and slew rate
+                       0b000 - fast 1mA
+                       0b001 - fast 2mA
+                       0b002 - fast 3mA
+                       0b003 - fast 4mA
+                       0b004 - slow 6mA
+                       0b005 - fast 6mA
+                       0b006 - slow 10mA
+                       0b007 - fast 10mA
+
+MFP Design for PXA2xx/PXA3xx
+============================
+
+Due to the difference of pin-mux handling between PXA2xx and PXA3xx, a unified
+MFP API is introduced to cover both series of processors.
+
+The basic idea of this design is to introduce definitions for all possible pin
+configurations, these definitions are processor and platform independent, and
+the actual API invoked to convert these definitions into register settings and
+make them effective there-after.
+
+Files Involved
+--------------
+
+  - arch/arm/mach-pxa/include/mach/mfp.h
+
+  for
+    1. Unified pin definitions - enum constants for all configurable pins
+    2. processor-neutral bit definitions for a possible MFP configuration
+
+  - arch/arm/mach-pxa/mfp-pxa3xx.h
+
+  for PXA3xx specific MFPR register bit definitions and PXA3xx common pin
+  configurations
+
+  - arch/arm/mach-pxa/mfp-pxa2xx.h
+
+  for PXA2xx specific definitions and PXA25x/PXA27x common pin configurations
+
+  - arch/arm/mach-pxa/mfp-pxa25x.h
+    arch/arm/mach-pxa/mfp-pxa27x.h
+    arch/arm/mach-pxa/mfp-pxa300.h
+    arch/arm/mach-pxa/mfp-pxa320.h
+    arch/arm/mach-pxa/mfp-pxa930.h
+
+  for processor specific definitions
+
+  - arch/arm/mach-pxa/mfp-pxa3xx.c
+  - arch/arm/mach-pxa/mfp-pxa2xx.c
+
+  for implementation of the pin configuration to take effect for the actual
+  processor.
+
+Pin Configuration
+-----------------
+
+  The following comments are copied from mfp.h (see the actual source code
+  for most updated info)::
+
+    /*
+     * a possible MFP configuration is represented by a 32-bit integer
+     *
+     * bit  0.. 9 - MFP Pin Number (1024 Pins Maximum)
+     * bit 10..12 - Alternate Function Selection
+     * bit 13..15 - Drive Strength
+     * bit 16..18 - Low Power Mode State
+     * bit 19..20 - Low Power Mode Edge Detection
+     * bit 21..22 - Run Mode Pull State
+     *
+     * to facilitate the definition, the following macros are provided
+     *
+     * MFP_CFG_DEFAULT - default MFP configuration value, with
+     *                   alternate function = 0,
+     *                   drive strength = fast 3mA (MFP_DS03X)
+     *                   low power mode = default
+     *                   edge detection = none
+     *
+     * MFP_CFG - default MFPR value with alternate function
+     * MFP_CFG_DRV     - default MFPR value with alternate function and
+     *                   pin drive strength
+     * MFP_CFG_LPM     - default MFPR value with alternate function and
+     *                   low power mode
+     * MFP_CFG_X       - default MFPR value with alternate function,
+     *                   pin drive strength and low power mode
+     */
+
+   Examples of pin configurations are::
+
+     #define GPIO94_SSP3_RXD           MFP_CFG_X(GPIO94, AF1, DS08X, FLOAT)
+
+   which reads GPIO94 can be configured as SSP3_RXD, with alternate function
+   selection of 1, driving strength of 0b101, and a float state in low power
+   modes.
+
+   NOTE: this is the default setting of this pin being configured as SSP3_RXD
+   which can be modified a bit in board code, though it is not recommended to
+   do so, simply because this default setting is usually carefully encoded,
+   and is supposed to work in most cases.
+
+Register Settings
+-----------------
+
+   Register settings on PXA3xx for a pin configuration is actually very
+   straight-forward, most bits can be converted directly into MFPR value
+   in a easier way. Two sets of MFPR values are calculated: the run-time
+   ones and the low power mode ones, to allow different settings.
+
+   The conversion from a generic pin configuration to the actual register
+   settings on PXA2xx is a bit complicated: many registers are involved,
+   including GAFRx, GPDRx, PGSRx, PWER, PKWR, PFER and PRER. Please see
+   mfp-pxa2xx.c for how the conversion is made.
diff --git a/Documentation/arm/pxa/mfp.txt b/Documentation/arm/pxa/mfp.txt
deleted file mode 100644 (file)
index 0b7cab9..0000000
+++ /dev/null
@@ -1,286 +0,0 @@
-                 MFP Configuration for PXA2xx/PXA3xx Processors
-
-                       Eric Miao <eric.miao@marvell.com>
-
-MFP stands for Multi-Function Pin, which is the pin-mux logic on PXA3xx and
-later PXA series processors.  This document describes the existing MFP API,
-and how board/platform driver authors could make use of it.
-
- Basic Concept
-===============
-
-Unlike the GPIO alternate function settings on PXA25x and PXA27x, a new MFP
-mechanism is introduced from PXA3xx to completely move the pin-mux functions
-out of the GPIO controller. In addition to pin-mux configurations, the MFP
-also controls the low power state, driving strength, pull-up/down and event
-detection of each pin.  Below is a diagram of internal connections between
-the MFP logic and the remaining SoC peripherals:
-
- +--------+
- |        |--(GPIO19)--+
- |  GPIO  |            |
- |        |--(GPIO...) |
- +--------+            |
-                       |       +---------+
- +--------+            +------>|         |
- |  PWM2  |--(PWM_OUT)-------->|   MFP   |
- +--------+            +------>|         |-------> to external PAD
-                       | +---->|         |
- +--------+            | | +-->|         |
- |  SSP2  |---(TXD)----+ | |   +---------+
- +--------+              | |
-                         | |
- +--------+              | |
- | Keypad |--(MKOUT4)----+ |
- +--------+                |
-                           |
- +--------+                |
- |  UART2 |---(TXD)--------+
- +--------+
-
-NOTE: the external pad is named as MFP_PIN_GPIO19, it doesn't necessarily
-mean it's dedicated for GPIO19, only as a hint that internally this pin
-can be routed from GPIO19 of the GPIO controller.
-
-To better understand the change from PXA25x/PXA27x GPIO alternate function
-to this new MFP mechanism, here are several key points:
-
-  1. GPIO controller on PXA3xx is now a dedicated controller, same as other
-     internal controllers like PWM, SSP and UART, with 128 internal signals
-     which can be routed to external through one or more MFPs (e.g. GPIO<0>
-     can be routed through either MFP_PIN_GPIO0 as well as MFP_PIN_GPIO0_2,
-     see arch/arm/mach-pxa/mfp-pxa300.h)
-
-  2. Alternate function configuration is removed from this GPIO controller,
-     the remaining functions are pure GPIO-specific, i.e.
-
-       - GPIO signal level control
-       - GPIO direction control
-       - GPIO level change detection
-
-  3. Low power state for each pin is now controlled by MFP, this means the
-     PGSRx registers on PXA2xx are now useless on PXA3xx
-
-  4. Wakeup detection is now controlled by MFP, PWER does not control the
-     wakeup from GPIO(s) any more, depending on the sleeping state, ADxER
-     (as defined in pxa3xx-regs.h) controls the wakeup from MFP
-
-NOTE: with such a clear separation of MFP and GPIO, by GPIO<xx> we normally
-mean it is a GPIO signal, and by MFP<xxx> or pin xxx, we mean a physical
-pad (or ball).
-
- MFP API Usage
-===============
-
-For board code writers, here are some guidelines:
-
-1. include ONE of the following header files in your <board>.c:
-
-   - #include "mfp-pxa25x.h"
-   - #include "mfp-pxa27x.h"
-   - #include "mfp-pxa300.h"
-   - #include "mfp-pxa320.h"
-   - #include "mfp-pxa930.h"
-
-   NOTE: only one file in your <board>.c, depending on the processors used,
-   because pin configuration definitions may conflict in these file (i.e.
-   same name, different meaning and settings on different processors). E.g.
-   for zylonite platform, which support both PXA300/PXA310 and PXA320, two
-   separate files are introduced: zylonite_pxa300.c and zylonite_pxa320.c
-   (in addition to handle MFP configuration differences, they also handle
-   the other differences between the two combinations).
-
-   NOTE: PXA300 and PXA310 are almost identical in pin configurations (with
-   PXA310 supporting some additional ones), thus the difference is actually
-   covered in a single mfp-pxa300.h.
-
-2. prepare an array for the initial pin configurations, e.g.:
-
-   static unsigned long mainstone_pin_config[] __initdata = {
-       /* Chip Select */
-       GPIO15_nCS_1,
-
-       /* LCD - 16bpp Active TFT */
-       GPIOxx_TFT_LCD_16BPP,
-       GPIO16_PWM0_OUT,        /* Backlight */
-
-       /* MMC */
-       GPIO32_MMC_CLK,
-       GPIO112_MMC_CMD,
-       GPIO92_MMC_DAT_0,
-       GPIO109_MMC_DAT_1,
-       GPIO110_MMC_DAT_2,
-       GPIO111_MMC_DAT_3,
-
-       ...
-
-       /* GPIO */
-       GPIO1_GPIO | WAKEUP_ON_EDGE_BOTH,
-   };
-
-   a) once the pin configurations are passed to pxa{2xx,3xx}_mfp_config(),
-   and written to the actual registers, they are useless and may discard,
-   adding '__initdata' will help save some additional bytes here.
-
-   b) when there is only one possible pin configurations for a component,
-   some simplified definitions can be used, e.g. GPIOxx_TFT_LCD_16BPP on
-   PXA25x and PXA27x processors
-
-   c) if by board design, a pin can be configured to wake up the system
-   from low power state, it can be 'OR'ed with any of:
-
-      WAKEUP_ON_EDGE_BOTH
-      WAKEUP_ON_EDGE_RISE
-      WAKEUP_ON_EDGE_FALL
-      WAKEUP_ON_LEVEL_HIGH - specifically for enabling of keypad GPIOs,
-
-   to indicate that this pin has the capability of wake-up the system,
-   and on which edge(s). This, however, doesn't necessarily mean the
-   pin _will_ wakeup the system, it will only when set_irq_wake() is
-   invoked with the corresponding GPIO IRQ (GPIO_IRQ(xx) or gpio_to_irq())
-   and eventually calls gpio_set_wake() for the actual register setting.
-
-   d) although PXA3xx MFP supports edge detection on each pin, the
-   internal logic will only wakeup the system when those specific bits
-   in ADxER registers are set, which can be well mapped to the
-   corresponding peripheral, thus set_irq_wake() can be called with 
-   the peripheral IRQ to enable the wakeup.
-
-
- MFP on PXA3xx
-===============
-
-Every external I/O pad on PXA3xx (excluding those for special purpose) has
-one MFP logic associated, and is controlled by one MFP register (MFPR).
-
-The MFPR has the following bit definitions (for PXA300/PXA310/PXA320):
-
- 31                        16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
-  +-------------------------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
-  |         RESERVED        |PS|PU|PD|  DRIVE |SS|SD|SO|EC|EF|ER|--| AF_SEL |
-  +-------------------------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
-
-  Bit 3:   RESERVED
-  Bit 4:   EDGE_RISE_EN - enable detection of rising edge on this pin
-  Bit 5:   EDGE_FALL_EN - enable detection of falling edge on this pin
-  Bit 6:   EDGE_CLEAR   - disable edge detection on this pin
-  Bit 7:   SLEEP_OE_N   - enable outputs during low power modes
-  Bit 8:   SLEEP_DATA   - output data on the pin during low power modes
-  Bit 9:   SLEEP_SEL    - selection control for low power modes signals
-  Bit 13:  PULLDOWN_EN  - enable the internal pull-down resistor on this pin
-  Bit 14:  PULLUP_EN    - enable the internal pull-up resistor on this pin
-  Bit 15:  PULL_SEL     - pull state controlled by selected alternate function
-                          (0) or by PULL{UP,DOWN}_EN bits (1)
-
-  Bit 0 - 2: AF_SEL - alternate function selection, 8 possibilities, from 0-7
-  Bit 10-12: DRIVE  - drive strength and slew rate
-                       0b000 - fast 1mA
-                       0b001 - fast 2mA
-                       0b002 - fast 3mA
-                       0b003 - fast 4mA
-                       0b004 - slow 6mA
-                       0b005 - fast 6mA
-                       0b006 - slow 10mA
-                       0b007 - fast 10mA
-
- MFP Design for PXA2xx/PXA3xx
-==============================
-
-Due to the difference of pin-mux handling between PXA2xx and PXA3xx, a unified
-MFP API is introduced to cover both series of processors.
-
-The basic idea of this design is to introduce definitions for all possible pin
-configurations, these definitions are processor and platform independent, and
-the actual API invoked to convert these definitions into register settings and
-make them effective there-after.
-
-  Files Involved
-  --------------
-
-  - arch/arm/mach-pxa/include/mach/mfp.h
-  
-  for
-    1. Unified pin definitions - enum constants for all configurable pins
-    2. processor-neutral bit definitions for a possible MFP configuration
-
-  - arch/arm/mach-pxa/mfp-pxa3xx.h
-
-  for PXA3xx specific MFPR register bit definitions and PXA3xx common pin
-  configurations
-
-  - arch/arm/mach-pxa/mfp-pxa2xx.h
-
-  for PXA2xx specific definitions and PXA25x/PXA27x common pin configurations
-
-  - arch/arm/mach-pxa/mfp-pxa25x.h
-    arch/arm/mach-pxa/mfp-pxa27x.h
-    arch/arm/mach-pxa/mfp-pxa300.h
-    arch/arm/mach-pxa/mfp-pxa320.h
-    arch/arm/mach-pxa/mfp-pxa930.h
-
-  for processor specific definitions
-
-  - arch/arm/mach-pxa/mfp-pxa3xx.c
-  - arch/arm/mach-pxa/mfp-pxa2xx.c
-
-  for implementation of the pin configuration to take effect for the actual
-  processor.
-
-  Pin Configuration
-  -----------------
-
-  The following comments are copied from mfp.h (see the actual source code
-  for most updated info)
-  
-  /*
-   * a possible MFP configuration is represented by a 32-bit integer
-   *
-   * bit  0.. 9 - MFP Pin Number (1024 Pins Maximum)
-   * bit 10..12 - Alternate Function Selection
-   * bit 13..15 - Drive Strength
-   * bit 16..18 - Low Power Mode State
-   * bit 19..20 - Low Power Mode Edge Detection
-   * bit 21..22 - Run Mode Pull State
-   *
-   * to facilitate the definition, the following macros are provided
-   *
-   * MFP_CFG_DEFAULT - default MFP configuration value, with
-   *             alternate function = 0,
-   *             drive strength = fast 3mA (MFP_DS03X)
-   *             low power mode = default
-   *             edge detection = none
-   *
-   * MFP_CFG   - default MFPR value with alternate function
-   * MFP_CFG_DRV       - default MFPR value with alternate function and
-   *             pin drive strength
-   * MFP_CFG_LPM       - default MFPR value with alternate function and
-   *             low power mode
-   * MFP_CFG_X - default MFPR value with alternate function,
-   *             pin drive strength and low power mode
-   */
-
-   Examples of pin configurations are:
-
-   #define GPIO94_SSP3_RXD             MFP_CFG_X(GPIO94, AF1, DS08X, FLOAT)
-
-   which reads GPIO94 can be configured as SSP3_RXD, with alternate function
-   selection of 1, driving strength of 0b101, and a float state in low power
-   modes.
-
-   NOTE: this is the default setting of this pin being configured as SSP3_RXD
-   which can be modified a bit in board code, though it is not recommended to
-   do so, simply because this default setting is usually carefully encoded,
-   and is supposed to work in most cases.
-
-  Register Settings
-  -----------------
-
-   Register settings on PXA3xx for a pin configuration is actually very
-   straight-forward, most bits can be converted directly into MFPR value
-   in a easier way. Two sets of MFPR values are calculated: the run-time
-   ones and the low power mode ones, to allow different settings.
-
-   The conversion from a generic pin configuration to the actual register
-   settings on PXA2xx is a bit complicated: many registers are involved,
-   including GAFRx, GPDRx, PGSRx, PWER, PKWR, PFER and PRER. Please see
-   mfp-pxa2xx.c for how the conversion is made.
diff --git a/Documentation/arm/sa1100/adsbitsy.rst b/Documentation/arm/sa1100/adsbitsy.rst
new file mode 100644 (file)
index 0000000..c179cb2
--- /dev/null
@@ -0,0 +1,51 @@
+===============================
+ADS Bitsy Single Board Computer
+===============================
+
+(It is different from Bitsy(iPAQ) of Compaq)
+
+For more details, contact Applied Data Systems or see
+http://www.applieddata.net/products.html
+
+The Linux support for this product has been provided by
+Woojung Huh <whuh@applieddata.net>
+
+Use 'make adsbitsy_config' before any 'make config'.
+This will set up defaults for ADS Bitsy support.
+
+The kernel zImage is linked to be loaded and executed at 0xc0400000.
+
+Linux can  be used with the ADS BootLoader that ships with the
+newer rev boards. See their documentation on how to load Linux.
+
+Supported peripherals
+=====================
+
+- SA1100 LCD frame buffer (8/16bpp...sort of)
+- SA1111 USB Master
+- SA1100 serial port
+- pcmcia, compact flash
+- touchscreen(ucb1200)
+- console on LCD screen
+- serial ports (ttyS[0-2])
+  - ttyS0 is default for serial console
+
+To do
+=====
+
+- everything else!  :-)
+
+Notes
+=====
+
+- The flash on board is divided into 3 partitions.
+  You should be careful to use flash on board.
+  Its partition is different from GraphicsClient Plus and GraphicsMaster
+
+- 16bpp mode requires a different cable than what ships with the board.
+  Contact ADS or look through the manual to wire your own. Currently,
+  if you compile with 16bit mode support and switch into a lower bpp
+  mode, the timing is off so the image is corrupted.  This will be
+  fixed soon.
+
+Any contribution can be sent to nico@fluxnic.net and will be greatly welcome!
diff --git a/Documentation/arm/sa1100/assabet.rst b/Documentation/arm/sa1100/assabet.rst
new file mode 100644 (file)
index 0000000..3e70483
--- /dev/null
@@ -0,0 +1,301 @@
+============================================
+The Intel Assabet (SA-1110 evaluation) board
+============================================
+
+Please see:
+http://developer.intel.com
+
+Also some notes from John G Dorsey <jd5q@andrew.cmu.edu>:
+http://www.cs.cmu.edu/~wearable/software/assabet.html
+
+
+Building the kernel
+-------------------
+
+To build the kernel with current defaults::
+
+       make assabet_config
+       make oldconfig
+       make zImage
+
+The resulting kernel image should be available in linux/arch/arm/boot/zImage.
+
+
+Installing a bootloader
+-----------------------
+
+A couple of bootloaders able to boot Linux on Assabet are available:
+
+BLOB (http://www.lartmaker.nl/lartware/blob/)
+
+   BLOB is a bootloader used within the LART project.  Some contributed
+   patches were merged into BLOB to add support for Assabet.
+
+Compaq's Bootldr + John Dorsey's patch for Assabet support
+(http://www.handhelds.org/Compaq/bootldr.html)
+(http://www.wearablegroup.org/software/bootldr/)
+
+   Bootldr is the bootloader developed by Compaq for the iPAQ Pocket PC.
+   John Dorsey has produced add-on patches to add support for Assabet and
+   the JFFS filesystem.
+
+RedBoot (http://sources.redhat.com/redboot/)
+
+   RedBoot is a bootloader developed by Red Hat based on the eCos RTOS
+   hardware abstraction layer.  It supports Assabet amongst many other
+   hardware platforms.
+
+RedBoot is currently the recommended choice since it's the only one to have
+networking support, and is the most actively maintained.
+
+Brief examples on how to boot Linux with RedBoot are shown below.  But first
+you need to have RedBoot installed in your flash memory.  A known to work
+precompiled RedBoot binary is available from the following location:
+
+- ftp://ftp.netwinder.org/users/n/nico/
+- ftp://ftp.arm.linux.org.uk/pub/linux/arm/people/nico/
+- ftp://ftp.handhelds.org/pub/linux/arm/sa-1100-patches/
+
+Look for redboot-assabet*.tgz.  Some installation infos are provided in
+redboot-assabet*.txt.
+
+
+Initial RedBoot configuration
+-----------------------------
+
+The commands used here are explained in The RedBoot User's Guide available
+on-line at http://sources.redhat.com/ecos/docs.html.
+Please refer to it for explanations.
+
+If you have a CF network card (my Assabet kit contained a CF+ LP-E from
+Socket Communications Inc.), you should strongly consider using it for TFTP
+file transfers.  You must insert it before RedBoot runs since it can't detect
+it dynamically.
+
+To initialize the flash directory::
+
+       fis init -f
+
+To initialize the non-volatile settings, like whether you want to use BOOTP or
+a static IP address, etc, use this command::
+
+       fconfig -i
+
+
+Writing a kernel image into flash
+---------------------------------
+
+First, the kernel image must be loaded into RAM.  If you have the zImage file
+available on a TFTP server::
+
+       load zImage -r -b 0x100000
+
+If you rather want to use Y-Modem upload over the serial port::
+
+       load -m ymodem -r -b 0x100000
+
+To write it to flash::
+
+       fis create "Linux kernel" -b 0x100000 -l 0xc0000
+
+
+Booting the kernel
+------------------
+
+The kernel still requires a filesystem to boot.  A ramdisk image can be loaded
+as follows::
+
+       load ramdisk_image.gz -r -b 0x800000
+
+Again, Y-Modem upload can be used instead of TFTP by replacing the file name
+by '-y ymodem'.
+
+Now the kernel can be retrieved from flash like this::
+
+       fis load "Linux kernel"
+
+or loaded as described previously.  To boot the kernel::
+
+       exec -b 0x100000 -l 0xc0000
+
+The ramdisk image could be stored into flash as well, but there are better
+solutions for on-flash filesystems as mentioned below.
+
+
+Using JFFS2
+-----------
+
+Using JFFS2 (the Second Journalling Flash File System) is probably the most
+convenient way to store a writable filesystem into flash.  JFFS2 is used in
+conjunction with the MTD layer which is responsible for low-level flash
+management.  More information on the Linux MTD can be found on-line at:
+http://www.linux-mtd.infradead.org/.  A JFFS howto with some infos about
+creating JFFS/JFFS2 images is available from the same site.
+
+For instance, a sample JFFS2 image can be retrieved from the same FTP sites
+mentioned below for the precompiled RedBoot image.
+
+To load this file::
+
+       load sample_img.jffs2 -r -b 0x100000
+
+The result should look like::
+
+       RedBoot> load sample_img.jffs2 -r -b 0x100000
+       Raw file loaded 0x00100000-0x00377424
+
+Now we must know the size of the unallocated flash::
+
+       fis free
+
+Result::
+
+       RedBoot> fis free
+         0x500E0000 .. 0x503C0000
+
+The values above may be different depending on the size of the filesystem and
+the type of flash.  See their usage below as an example and take care of
+substituting yours appropriately.
+
+We must determine some values::
+
+       size of unallocated flash:      0x503c0000 - 0x500e0000 = 0x2e0000
+       size of the filesystem image:   0x00377424 - 0x00100000 = 0x277424
+
+We want to fit the filesystem image of course, but we also want to give it all
+the remaining flash space as well.  To write it::
+
+       fis unlock -f 0x500E0000 -l 0x2e0000
+       fis erase -f 0x500E0000 -l 0x2e0000
+       fis write -b 0x100000 -l 0x277424 -f 0x500E0000
+       fis create "JFFS2" -n -f 0x500E0000 -l 0x2e0000
+
+Now the filesystem is associated to a MTD "partition" once Linux has discovered
+what they are in the boot process.  From Redboot, the 'fis list' command
+displays them::
+
+       RedBoot> fis list
+       Name              FLASH addr  Mem addr    Length      Entry point
+       RedBoot           0x50000000  0x50000000  0x00020000  0x00000000
+       RedBoot config    0x503C0000  0x503C0000  0x00020000  0x00000000
+       FIS directory     0x503E0000  0x503E0000  0x00020000  0x00000000
+       Linux kernel      0x50020000  0x00100000  0x000C0000  0x00000000
+       JFFS2             0x500E0000  0x500E0000  0x002E0000  0x00000000
+
+However Linux should display something like::
+
+       SA1100 flash: probing 32-bit flash bus
+       SA1100 flash: Found 2 x16 devices at 0x0 in 32-bit mode
+       Using RedBoot partition definition
+       Creating 5 MTD partitions on "SA1100 flash":
+       0x00000000-0x00020000 : "RedBoot"
+       0x00020000-0x000e0000 : "Linux kernel"
+       0x000e0000-0x003c0000 : "JFFS2"
+       0x003c0000-0x003e0000 : "RedBoot config"
+       0x003e0000-0x00400000 : "FIS directory"
+
+What's important here is the position of the partition we are interested in,
+which is the third one.  Within Linux, this correspond to /dev/mtdblock2.
+Therefore to boot Linux with the kernel and its root filesystem in flash, we
+need this RedBoot command::
+
+       fis load "Linux kernel"
+       exec -b 0x100000 -l 0xc0000 -c "root=/dev/mtdblock2"
+
+Of course other filesystems than JFFS might be used, like cramfs for example.
+You might want to boot with a root filesystem over NFS, etc.  It is also
+possible, and sometimes more convenient, to flash a filesystem directly from
+within Linux while booted from a ramdisk or NFS.  The Linux MTD repository has
+many tools to deal with flash memory as well, to erase it for example.  JFFS2
+can then be mounted directly on a freshly erased partition and files can be
+copied over directly.  Etc...
+
+
+RedBoot scripting
+-----------------
+
+All the commands above aren't so useful if they have to be typed in every
+time the Assabet is rebooted.  Therefore it's possible to automate the boot
+process using RedBoot's scripting capability.
+
+For example, I use this to boot Linux with both the kernel and the ramdisk
+images retrieved from a TFTP server on the network::
+
+       RedBoot> fconfig
+       Run script at boot: false true
+       Boot script:
+       Enter script, terminate with empty line
+       >> load zImage -r -b 0x100000
+       >> load ramdisk_ks.gz -r -b 0x800000
+       >> exec -b 0x100000 -l 0xc0000
+       >>
+       Boot script timeout (1000ms resolution): 3
+       Use BOOTP for network configuration: true
+       GDB connection port: 9000
+       Network debug at boot time: false
+       Update RedBoot non-volatile configuration - are you sure (y/n)? y
+
+Then, rebooting the Assabet is just a matter of waiting for the login prompt.
+
+
+
+Nicolas Pitre
+nico@fluxnic.net
+
+June 12, 2001
+
+
+Status of peripherals in -rmk tree (updated 14/10/2001)
+-------------------------------------------------------
+
+Assabet:
+ Serial ports:
+  Radio:               TX, RX, CTS, DSR, DCD, RI
+   - PM:               Not tested.
+   - COM:              TX, RX, CTS, DSR, DCD, RTS, DTR, PM
+   - PM:               Not tested.
+   - I2C:              Implemented, not fully tested.
+   - L3:               Fully tested, pass.
+   - PM:               Not tested.
+
+ Video:
+  - LCD:               Fully tested.  PM
+
+   (LCD doesn't like being blanked with neponset connected)
+
+  - Video out:         Not fully
+
+ Audio:
+  UDA1341:
+  -  Playback:         Fully tested, pass.
+  -  Record:           Implemented, not tested.
+  -  PM:                       Not tested.
+
+  UCB1200:
+  -  Audio play:       Implemented, not heavily tested.
+  -  Audio rec:                Implemented, not heavily tested.
+  -  Telco audio play: Implemented, not heavily tested.
+  -  Telco audio rec:  Implemented, not heavily tested.
+  -  POTS control:     No
+  -  Touchscreen:      Yes
+  -  PM:               Not tested.
+
+ Other:
+  - PCMCIA:
+  - LPE:               Fully tested, pass.
+  - USB:               No
+  - IRDA:
+  - SIR:               Fully tested, pass.
+  - FIR:               Fully tested, pass.
+  - PM:                        Not tested.
+
+Neponset:
+ Serial ports:
+  - COM1,2:            TX, RX, CTS, DSR, DCD, RTS, DTR
+  - PM:                        Not tested.
+  - USB:               Implemented, not heavily tested.
+  - PCMCIA:            Implemented, not heavily tested.
+  - CF:                        Implemented, not heavily tested.
+  - PM:                        Not tested.
+
+More stuff can be found in the -np (Nicolas Pitre's) tree.
diff --git a/Documentation/arm/sa1100/brutus.rst b/Documentation/arm/sa1100/brutus.rst
new file mode 100644 (file)
index 0000000..e1a23be
--- /dev/null
@@ -0,0 +1,69 @@
+======
+Brutus
+======
+
+Brutus is an evaluation platform for the SA1100 manufactured by Intel.
+For more details, see:
+
+http://developer.intel.com
+
+To compile for Brutus, you must issue the following commands::
+
+       make brutus_config
+       make config
+       [accept all the defaults]
+       make zImage
+
+The resulting kernel will end up in linux/arch/arm/boot/zImage.  This file
+must be loaded at 0xc0008000 in Brutus's memory and execution started at
+0xc0008000 as well with the value of registers r0 = 0 and r1 = 16 upon
+entry.
+
+But prior to execute the kernel, a ramdisk image must also be loaded in
+memory.  Use memory address 0xd8000000 for this.  Note that the file
+containing the (compressed) ramdisk image must not exceed 4 MB.
+
+Typically, you'll need angelboot to load the kernel.
+The following angelboot.opt file should be used::
+
+       base 0xc0008000
+       entry 0xc0008000
+       r0 0x00000000
+       r1 0x00000010
+       device /dev/ttyS0
+       options "9600 8N1"
+       baud 115200
+       otherfile ramdisk_img.gz
+       otherbase 0xd8000000
+
+Then load the kernel and ramdisk with::
+
+       angelboot -f angelboot.opt zImage
+
+The first Brutus serial port (assumed to be linked to /dev/ttyS0 on your
+host PC) is used by angel to load the kernel and ramdisk image. The serial
+console is provided through the second Brutus serial port. To access it,
+you may use minicom configured with /dev/ttyS1, 9600 baud, 8N1, no flow
+control.
+
+Currently supported
+===================
+
+       - RS232 serial ports
+       - audio output
+       - LCD screen
+       - keyboard
+
+The actual Brutus support may not be complete without extra patches.
+If such patches exist, they should be found from
+ftp.netwinder.org/users/n/nico.
+
+A full PCMCIA support is still missing, although it's possible to hack
+some drivers in order to drive already inserted cards at boot time with
+little modifications.
+
+Any contribution is welcome.
+
+Please send patches to nico@fluxnic.net
+
+Have Fun !
diff --git a/Documentation/arm/sa1100/cerf.rst b/Documentation/arm/sa1100/cerf.rst
new file mode 100644 (file)
index 0000000..7fa71b6
--- /dev/null
@@ -0,0 +1,35 @@
+==============
+CerfBoard/Cube
+==============
+
+*** The StrongARM version of the CerfBoard/Cube has been discontinued ***
+
+The Intrinsyc CerfBoard is a StrongARM 1110-based computer on a board
+that measures approximately 2" square. It includes an Ethernet
+controller, an RS232-compatible serial port, a USB function port, and
+one CompactFlash+ slot on the back. Pictures can be found at the
+Intrinsyc website, http://www.intrinsyc.com.
+
+This document describes the support in the Linux kernel for the
+Intrinsyc CerfBoard.
+
+Supported in this version
+=========================
+
+   - CompactFlash+ slot (select PCMCIA in General Setup and any options
+     that may be required)
+   - Onboard Crystal CS8900 Ethernet controller (Cerf CS8900A support in
+     Network Devices)
+   - Serial ports with a serial console (hardcoded to 38400 8N1)
+
+In order to get this kernel onto your Cerf, you need a server that runs
+both BOOTP and TFTP. Detailed instructions should have come with your
+evaluation kit on how to use the bootloader. This series of commands
+will suffice::
+
+   make ARCH=arm CROSS_COMPILE=arm-linux- cerfcube_defconfig
+   make ARCH=arm CROSS_COMPILE=arm-linux- zImage
+   make ARCH=arm CROSS_COMPILE=arm-linux- modules
+   cp arch/arm/boot/zImage <TFTP directory>
+
+support@intrinsyc.com
diff --git a/Documentation/arm/sa1100/freebird.rst b/Documentation/arm/sa1100/freebird.rst
new file mode 100644 (file)
index 0000000..81043d0
--- /dev/null
@@ -0,0 +1,25 @@
+========
+Freebird
+========
+
+Freebird-1.1 is produced by Legend(C), Inc.
+`http://web.archive.org/web/*/http://www.legend.com.cn`
+and software/linux maintained by Coventive(C), Inc.
+(http://www.coventive.com)
+
+Based on the Nicolas's strongarm kernel tree.
+
+Maintainer:
+
+Chester Kuo
+       - <chester@coventive.com>
+       - <chester@linux.org.tw>
+
+Author:
+
+- Tim wu <timwu@coventive.com>
+- CIH <cih@coventive.com>
+- Eric Peng <ericpeng@coventive.com>
+- Jeff Lee <jeff_lee@coventive.com>
+- Allen Cheng
+- Tony Liu <tonyliu@coventive.com>
diff --git a/Documentation/arm/sa1100/graphicsclient.rst b/Documentation/arm/sa1100/graphicsclient.rst
new file mode 100644 (file)
index 0000000..a73d61c
--- /dev/null
@@ -0,0 +1,102 @@
+=============================================
+ADS GraphicsClient Plus Single Board Computer
+=============================================
+
+For more details, contact Applied Data Systems or see
+http://www.applieddata.net/products.html
+
+The original Linux support for this product has been provided by
+Nicolas Pitre <nico@fluxnic.net>. Continued development work by
+Woojung Huh <whuh@applieddata.net>
+
+It's currently possible to mount a root filesystem via NFS providing a
+complete Linux environment.  Otherwise a ramdisk image may be used.  The
+board supports MTD/JFFS, so you could also mount something on there.
+
+Use 'make graphicsclient_config' before any 'make config'.  This will set up
+defaults for GraphicsClient Plus support.
+
+The kernel zImage is linked to be loaded and executed at 0xc0200000.
+Also the following registers should have the specified values upon entry::
+
+       r0 = 0
+       r1 = 29 (this is the GraphicsClient architecture number)
+
+Linux can  be used with the ADS BootLoader that ships with the
+newer rev boards. See their documentation on how to load Linux.
+Angel is not available for the GraphicsClient Plus AFAIK.
+
+There is a  board known as just the GraphicsClient that ADS used to
+produce but has end of lifed. This code will not work on the older
+board with the ADS bootloader, but should still work with Angel,
+as outlined below.  In any case, if you're planning on deploying
+something en masse, you should probably get the newer board.
+
+If using Angel on the older boards, here is a typical angel.opt option file
+if the kernel is loaded through the Angel Debug Monitor::
+
+       base 0xc0200000
+       entry 0xc0200000
+       r0 0x00000000
+       r1 0x0000001d
+       device /dev/ttyS1
+       options "38400 8N1"
+       baud 115200
+       #otherfile ramdisk.gz
+       #otherbase 0xc0800000
+       exec minicom
+
+Then the kernel (and ramdisk if otherfile/otherbase lines above are
+uncommented) would be loaded with::
+
+       angelboot -f angelboot.opt zImage
+
+Here it is assumed that the board is connected to ttyS1 on your PC
+and that minicom is preconfigured with /dev/ttyS1, 38400 baud, 8N1, no flow
+control by default.
+
+If any other bootloader is used, ensure it accomplish the same, especially
+for r0/r1 register values before jumping into the kernel.
+
+
+Supported peripherals
+=====================
+
+- SA1100 LCD frame buffer (8/16bpp...sort of)
+- on-board SMC 92C96 ethernet NIC
+- SA1100 serial port
+- flash memory access (MTD/JFFS)
+- pcmcia
+- touchscreen(ucb1200)
+- ps/2 keyboard
+- console on LCD screen
+- serial ports (ttyS[0-2])
+  - ttyS0 is default for serial console
+- Smart I/O (ADC, keypad, digital inputs, etc)
+  See http://www.eurotech-inc.com/linux-sbc.asp for IOCTL documentation
+  and example user space code. ps/2 keybd is multiplexed through this driver
+
+To do
+=====
+
+- UCB1200 audio with new ucb_generic layer
+- everything else!  :-)
+
+Notes
+=====
+
+- The flash on board is divided into 3 partitions.  mtd0 is where
+  the ADS boot ROM and zImage is stored.  It's been marked as
+  read-only to keep you from blasting over the bootloader. :)  mtd1 is
+  for the ramdisk.gz image.  mtd2 is user flash space and can be
+  utilized for either JFFS or if you're feeling crazy, running ext2
+  on top of it. If you're not using the ADS bootloader, you're
+  welcome to blast over the mtd1 partition also.
+
+- 16bpp mode requires a different cable than what ships with the board.
+  Contact ADS or look through the manual to wire your own. Currently,
+  if you compile with 16bit mode support and switch into a lower bpp
+  mode, the timing is off so the image is corrupted.  This will be
+  fixed soon.
+
+Any contribution can be sent to nico@fluxnic.net and will be greatly welcome!
diff --git a/Documentation/arm/sa1100/graphicsmaster.rst b/Documentation/arm/sa1100/graphicsmaster.rst
new file mode 100644 (file)
index 0000000..e398925
--- /dev/null
@@ -0,0 +1,60 @@
+========================================
+ADS GraphicsMaster Single Board Computer
+========================================
+
+For more details, contact Applied Data Systems or see
+http://www.applieddata.net/products.html
+
+The original Linux support for this product has been provided by
+Nicolas Pitre <nico@fluxnic.net>. Continued development work by
+Woojung Huh <whuh@applieddata.net>
+
+Use 'make graphicsmaster_config' before any 'make config'.
+This will set up defaults for GraphicsMaster support.
+
+The kernel zImage is linked to be loaded and executed at 0xc0400000.
+
+Linux can  be used with the ADS BootLoader that ships with the
+newer rev boards. See their documentation on how to load Linux.
+
+Supported peripherals
+=====================
+
+- SA1100 LCD frame buffer (8/16bpp...sort of)
+- SA1111 USB Master
+- on-board SMC 92C96 ethernet NIC
+- SA1100 serial port
+- flash memory access (MTD/JFFS)
+- pcmcia, compact flash
+- touchscreen(ucb1200)
+- ps/2 keyboard
+- console on LCD screen
+- serial ports (ttyS[0-2])
+  - ttyS0 is default for serial console
+- Smart I/O (ADC, keypad, digital inputs, etc)
+  See http://www.eurotech-inc.com/linux-sbc.asp for IOCTL documentation
+  and example user space code. ps/2 keybd is multiplexed through this driver
+
+To do
+=====
+
+- everything else!  :-)
+
+Notes
+=====
+
+- The flash on board is divided into 3 partitions.  mtd0 is where
+  the zImage is stored.  It's been marked as read-only to keep you
+  from blasting over the bootloader. :)  mtd1 is
+  for the ramdisk.gz image.  mtd2 is user flash space and can be
+  utilized for either JFFS or if you're feeling crazy, running ext2
+  on top of it. If you're not using the ADS bootloader, you're
+  welcome to blast over the mtd1 partition also.
+
+- 16bpp mode requires a different cable than what ships with the board.
+  Contact ADS or look through the manual to wire your own. Currently,
+  if you compile with 16bit mode support and switch into a lower bpp
+  mode, the timing is off so the image is corrupted.  This will be
+  fixed soon.
+
+Any contribution can be sent to nico@fluxnic.net and will be greatly welcome!
diff --git a/Documentation/arm/sa1100/huw_webpanel.rst b/Documentation/arm/sa1100/huw_webpanel.rst
new file mode 100644 (file)
index 0000000..1dc7ccb
--- /dev/null
@@ -0,0 +1,21 @@
+=======================
+Hoeft & Wessel Webpanel
+=======================
+
+The HUW_WEBPANEL is a product of the german company Hoeft & Wessel AG
+
+If you want more information, please visit
+http://www.hoeft-wessel.de
+
+To build the kernel::
+
+       make huw_webpanel_config
+       make oldconfig
+       [accept all defaults]
+       make zImage
+
+Mostly of the work is done by:
+Roman Jordan         jor@hoeft-wessel.de
+Christoph Schulz    schu@hoeft-wessel.de
+
+2000/12/18/
diff --git a/Documentation/arm/sa1100/index.rst b/Documentation/arm/sa1100/index.rst
new file mode 100644 (file)
index 0000000..68c2a28
--- /dev/null
@@ -0,0 +1,25 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+====================
+Intel StrongARM 1100
+====================
+
+.. toctree::
+    :maxdepth: 1
+
+    adsbitsy
+    assabet
+    brutus
+    cerf
+    freebird
+    graphicsclient
+    graphicsmaster
+    huw_webpanel
+    itsy
+    lart
+    nanoengine
+    pangolin
+    pleb
+    serial_uart
+    tifon
+    yopy
diff --git a/Documentation/arm/sa1100/itsy.rst b/Documentation/arm/sa1100/itsy.rst
new file mode 100644 (file)
index 0000000..f49896b
--- /dev/null
@@ -0,0 +1,47 @@
+====
+Itsy
+====
+
+Itsy is a research project done by the Western Research Lab, and Systems
+Research Center in Palo Alto, CA. The Itsy project is one of several
+research projects at Compaq that are related to pocket computing.
+
+For more information, see:
+
+       http://www.hpl.hp.com/downloads/crl/itsy/
+
+Notes on initial 2.4 Itsy support (8/27/2000) :
+
+The port was done on an Itsy version 1.5 machine with a daughtercard with
+64 Meg of DRAM and 32 Meg of Flash. The initial work includes support for
+serial console (to see what you're doing).  No other devices have been
+enabled.
+
+To build, do a "make menuconfig" (or xmenuconfig) and select Itsy support.
+Disable Flash and LCD support. and then do a make zImage.
+Finally, you will need to cd to arch/arm/boot/tools and execute a make there
+to build the params-itsy program used to boot the kernel.
+
+In order to install the port of 2.4 to the itsy, You will need to set the
+configuration parameters in the monitor as follows::
+
+       Arg 1:0x08340000, Arg2: 0xC0000000, Arg3:18 (0x12), Arg4:0
+
+Make sure the start-routine address is set to 0x00060000.
+
+Next, flash the params-itsy program to 0x00060000 ("p 1 0x00060000" in the
+flash menu)  Flash the kernel in arch/arm/boot/zImage into 0x08340000
+("p 1 0x00340000").  Finally flash an initial ramdisk into 0xC8000000
+("p 2 0x0")  We used ramdisk-2-30.gz from the 0.11 version directory on
+handhelds.org.
+
+The serial connection we established was at:
+
+8-bit data, no parity, 1 stop bit(s), 115200.00 b/s. in the monitor, in the
+params-itsy program, and in the kernel itself.  This can be changed, but
+not easily. The monitor parameters are easily changed, the params program
+setup is assembly outl's, and the kernel is a configuration item specific to
+the itsy. (i.e. grep for CONFIG_SA1100_ITSY and you'll find where it is.)
+
+
+This should get you a properly booting 2.4 kernel on the itsy.
diff --git a/Documentation/arm/sa1100/lart.rst b/Documentation/arm/sa1100/lart.rst
new file mode 100644 (file)
index 0000000..94c0568
--- /dev/null
@@ -0,0 +1,15 @@
+====================================
+Linux Advanced Radio Terminal (LART)
+====================================
+
+The LART is a small (7.5 x 10cm) SA-1100 board, designed for embedded
+applications. It has 32 MB DRAM, 4MB Flash ROM, double RS232 and all
+other StrongARM-gadgets. Almost all SA signals are directly accessible
+through a number of connectors. The powersupply accepts voltages
+between 3.5V and 16V and is overdimensioned to support a range of
+daughterboards. A quad Ethernet / IDE / PS2 / sound daughterboard
+is under development, with plenty of others in different stages of
+planning.
+
+The hardware designs for this board have been released under an open license;
+see the LART page at http://www.lartmaker.nl/ for more information.
diff --git a/Documentation/arm/sa1100/nanoengine.rst b/Documentation/arm/sa1100/nanoengine.rst
new file mode 100644 (file)
index 0000000..47f1a14
--- /dev/null
@@ -0,0 +1,11 @@
+==========
+nanoEngine
+==========
+
+"nanoEngine" is a SA1110 based single board computer from
+Bright Star Engineering Inc.  See www.brightstareng.com/arm
+for more info.
+(Ref: Stuart Adams <sja@brightstareng.com>)
+
+Also visit Larry Doolittle's "Linux for the nanoEngine" site:
+http://www.brightstareng.com/arm/nanoeng.htm
diff --git a/Documentation/arm/sa1100/pangolin.rst b/Documentation/arm/sa1100/pangolin.rst
new file mode 100644 (file)
index 0000000..f0c5c16
--- /dev/null
@@ -0,0 +1,29 @@
+========
+Pangolin
+========
+
+Pangolin is a StrongARM 1110-based evaluation platform produced
+by Dialogue Technology (http://www.dialogue.com.tw/).
+It has EISA slots for ease of configuration with SDRAM/Flash
+memory card, USB/Serial/Audio card, Compact Flash card,
+PCMCIA/IDE card and TFT-LCD card.
+
+To compile for Pangolin, you must issue the following commands::
+
+       make pangolin_config
+       make oldconfig
+       make zImage
+
+Supported peripherals
+=====================
+
+- SA1110 serial port (UART1/UART2/UART3)
+- flash memory access
+- compact flash driver
+- UDA1341 sound driver
+- SA1100 LCD controller for 800x600 16bpp TFT-LCD
+- MQ-200 driver for 800x600 16bpp TFT-LCD
+- Penmount(touch panel) driver
+- PCMCIA driver
+- SMC91C94 LAN driver
+- IDE driver (experimental)
diff --git a/Documentation/arm/sa1100/pleb.rst b/Documentation/arm/sa1100/pleb.rst
new file mode 100644 (file)
index 0000000..d5b7329
--- /dev/null
@@ -0,0 +1,13 @@
+====
+PLEB
+====
+
+The PLEB project was started as a student initiative at the School of
+Computer Science and Engineering, University of New South Wales to make a
+pocket computer capable of running the Linux Kernel.
+
+PLEB support has yet to be fully integrated.
+
+For more information, see:
+
+       http://www.cse.unsw.edu.au
diff --git a/Documentation/arm/sa1100/serial_uart.rst b/Documentation/arm/sa1100/serial_uart.rst
new file mode 100644 (file)
index 0000000..ea98364
--- /dev/null
@@ -0,0 +1,51 @@
+==================
+SA1100 serial port
+==================
+
+The SA1100 serial port had its major/minor numbers officially assigned::
+
+  > Date: Sun, 24 Sep 2000 21:40:27 -0700
+  > From: H. Peter Anvin <hpa@transmeta.com>
+  > To: Nicolas Pitre <nico@CAM.ORG>
+  > Cc: Device List Maintainer <device@lanana.org>
+  > Subject: Re: device
+  >
+  > Okay.  Note that device numbers 204 and 205 are used for "low density
+  > serial devices", so you will have a range of minors on those majors (the
+  > tty device layer handles this just fine, so you don't have to worry about
+  > doing anything special.)
+  >
+  > So your assignments are:
+  >
+  > 204 char        Low-density serial ports
+  >                   5 = /dev/ttySA0               SA1100 builtin serial port 0
+  >                   6 = /dev/ttySA1               SA1100 builtin serial port 1
+  >                   7 = /dev/ttySA2               SA1100 builtin serial port 2
+  >
+  > 205 char        Low-density serial ports (alternate device)
+  >                   5 = /dev/cusa0                Callout device for ttySA0
+  >                   6 = /dev/cusa1                Callout device for ttySA1
+  >                   7 = /dev/cusa2                Callout device for ttySA2
+  >
+
+You must create those inodes in /dev on the root filesystem used
+by your SA1100-based device::
+
+       mknod ttySA0 c 204 5
+       mknod ttySA1 c 204 6
+       mknod ttySA2 c 204 7
+       mknod cusa0 c 205 5
+       mknod cusa1 c 205 6
+       mknod cusa2 c 205 7
+
+In addition to the creation of the appropriate device nodes above, you
+must ensure your user space applications make use of the correct device
+name. The classic example is the content of the /etc/inittab file where
+you might have a getty process started on ttyS0.
+
+In this case:
+
+- replace occurrences of ttyS0 with ttySA0, ttyS1 with ttySA1, etc.
+
+- don't forget to add 'ttySA0', 'console', or the appropriate tty name
+  in /etc/securetty for root to be allowed to login as well.
diff --git a/Documentation/arm/sa1100/tifon.rst b/Documentation/arm/sa1100/tifon.rst
new file mode 100644 (file)
index 0000000..c26e910
--- /dev/null
@@ -0,0 +1,7 @@
+=====
+Tifon
+=====
+
+More info has to come...
+
+Contact: Peter Danielsson <peter.danielsson@era-t.ericsson.se>
diff --git a/Documentation/arm/sa1100/yopy.rst b/Documentation/arm/sa1100/yopy.rst
new file mode 100644 (file)
index 0000000..5b35a5f
--- /dev/null
@@ -0,0 +1,5 @@
+====
+Yopy
+====
+
+See http://www.yopydeveloper.org for more.
diff --git a/Documentation/arm/samsung-s3c24xx/cpufreq.rst b/Documentation/arm/samsung-s3c24xx/cpufreq.rst
new file mode 100644 (file)
index 0000000..2ddc26c
--- /dev/null
@@ -0,0 +1,76 @@
+=======================
+S3C24XX CPUfreq support
+=======================
+
+Introduction
+------------
+
+ The S3C24XX series support a number of power saving systems, such as
+ the ability to change the core, memory and peripheral operating
+ frequencies. The core control is exported via the CPUFreq driver
+ which has a number of different manual or automatic controls over the
+ rate the core is running at.
+
+ There are two forms of the driver depending on the specific CPU and
+ how the clocks are arranged. The first implementation used as single
+ PLL to feed the ARM, memory and peripherals via a series of dividers
+ and muxes and this is the implementation that is documented here. A
+ newer version where there is a separate PLL and clock divider for the
+ ARM core is available as a separate driver.
+
+
+Layout
+------
+
+ The code core manages the CPU specific drivers, any data that they
+ need to register and the interface to the generic drivers/cpufreq
+ system. Each CPU registers a driver to control the PLL, clock dividers
+ and anything else associated with it. Any board that wants to use this
+ framework needs to supply at least basic details of what is required.
+
+ The core registers with drivers/cpufreq at init time if all the data
+ necessary has been supplied.
+
+
+CPU support
+-----------
+
+ The support for each CPU depends on the facilities provided by the
+ SoC and the driver as each device has different PLL and clock chains
+ associated with it.
+
+
+Slow Mode
+---------
+
+ The SLOW mode where the PLL is turned off altogether and the
+ system is fed by the external crystal input is currently not
+ supported.
+
+
+sysfs
+-----
+
+ The core code exports extra information via sysfs in the directory
+ devices/system/cpu/cpu0/arch-freq.
+
+
+Board Support
+-------------
+
+ Each board that wants to use the cpufreq code must register some basic
+ information with the core driver to provide information about what the
+ board requires and any restrictions being placed on it.
+
+ The board needs to supply information about whether it needs the IO bank
+ timings changing, any maximum frequency limits and information about the
+ SDRAM refresh rate.
+
+
+
+
+Document Author
+---------------
+
+Ben Dooks, Copyright 2009 Simtec Electronics
+Licensed under GPLv2
diff --git a/Documentation/arm/samsung-s3c24xx/eb2410itx.rst b/Documentation/arm/samsung-s3c24xx/eb2410itx.rst
new file mode 100644 (file)
index 0000000..7863c93
--- /dev/null
@@ -0,0 +1,59 @@
+===================================
+Simtec Electronics EB2410ITX (BAST)
+===================================
+
+       http://www.simtec.co.uk/products/EB2410ITX/
+
+Introduction
+------------
+
+  The EB2410ITX is a S3C2410 based development board with a variety of
+  peripherals and expansion connectors. This board is also known by
+  the shortened name of Bast.
+
+
+Configuration
+-------------
+
+  To set the default configuration, use `make bast_defconfig` which
+  supports the commonly used features of this board.
+
+
+Support
+-------
+
+  Official support information can be found on the Simtec Electronics
+  website, at the product page http://www.simtec.co.uk/products/EB2410ITX/
+
+  Useful links:
+
+    - Resources Page http://www.simtec.co.uk/products/EB2410ITX/resources.html
+
+    - Board FAQ at http://www.simtec.co.uk/products/EB2410ITX/faq.html
+
+    - Bootloader info http://www.simtec.co.uk/products/SWABLE/resources.html
+      and FAQ http://www.simtec.co.uk/products/SWABLE/faq.html
+
+
+MTD
+---
+
+  The NAND and NOR support has been merged from the linux-mtd project.
+  Any problems, see http://www.linux-mtd.infradead.org/ for more
+  information or up-to-date versions of linux-mtd.
+
+
+IDE
+---
+
+  Both onboard IDE ports are supported, however there is no support for
+  changing speed of devices, PIO Mode 4 capable drives should be used.
+
+
+Maintainers
+-----------
+
+  This board is maintained by Simtec Electronics.
+
+
+Copyright 2004 Ben Dooks, Simtec Electronics
diff --git a/Documentation/arm/samsung-s3c24xx/gpio.rst b/Documentation/arm/samsung-s3c24xx/gpio.rst
new file mode 100644 (file)
index 0000000..f7c3d7d
--- /dev/null
@@ -0,0 +1,172 @@
+====================
+S3C24XX GPIO Control
+====================
+
+Introduction
+------------
+
+  The s3c2410 kernel provides an interface to configure and
+  manipulate the state of the GPIO pins, and find out other
+  information about them.
+
+  There are a number of conditions attached to the configuration
+  of the s3c2410 GPIO system, please read the Samsung provided
+  data-sheet/users manual to find out the complete list.
+
+  See Documentation/arm/samsung/gpio.rst for the core implementation.
+
+
+GPIOLIB
+-------
+
+  With the event of the GPIOLIB in drivers/gpio, support for some
+  of the GPIO functions such as reading and writing a pin will
+  be removed in favour of this common access method.
+
+  Once all the extant drivers have been converted, the functions
+  listed below will be removed (they may be marked as __deprecated
+  in the near future).
+
+  The following functions now either have a `s3c_` specific variant
+  or are merged into gpiolib. See the definitions in
+  arch/arm/plat-samsung/include/plat/gpio-cfg.h:
+
+  - s3c2410_gpio_setpin()      gpio_set_value() or gpio_direction_output()
+  - s3c2410_gpio_getpin()      gpio_get_value() or gpio_direction_input()
+  - s3c2410_gpio_getirq()      gpio_to_irq()
+  - s3c2410_gpio_cfgpin()      s3c_gpio_cfgpin()
+  - s3c2410_gpio_getcfg()      s3c_gpio_getcfg()
+  - s3c2410_gpio_pullup()      s3c_gpio_setpull()
+
+
+GPIOLIB conversion
+------------------
+
+If you need to convert your board or driver to use gpiolib from the phased
+out s3c2410 API, then here are some notes on the process.
+
+1) If your board is exclusively using an GPIO, say to control peripheral
+   power, then it will require to claim the gpio with gpio_request() before
+   it can use it.
+
+   It is recommended to check the return value, with at least WARN_ON()
+   during initialisation.
+
+2) The s3c2410_gpio_cfgpin() can be directly replaced with s3c_gpio_cfgpin()
+   as they have the same arguments, and can either take the pin specific
+   values, or the more generic special-function-number arguments.
+
+3) s3c2410_gpio_pullup() changes have the problem that while the
+   s3c2410_gpio_pullup(x, 1) can be easily translated to the
+   s3c_gpio_setpull(x, S3C_GPIO_PULL_NONE), the s3c2410_gpio_pullup(x, 0)
+   are not so easy.
+
+   The s3c2410_gpio_pullup(x, 0) case enables the pull-up (or in the case
+   of some of the devices, a pull-down) and as such the new API distinguishes
+   between the UP and DOWN case. There is currently no 'just turn on' setting
+   which may be required if this becomes a problem.
+
+4) s3c2410_gpio_setpin() can be replaced by gpio_set_value(), the old call
+   does not implicitly configure the relevant gpio to output. The gpio
+   direction should be changed before using gpio_set_value().
+
+5) s3c2410_gpio_getpin() is replaceable by gpio_get_value() if the pin
+   has been set to input. It is currently unknown what the behaviour is
+   when using gpio_get_value() on an output pin (s3c2410_gpio_getpin
+   would return the value the pin is supposed to be outputting).
+
+6) s3c2410_gpio_getirq() should be directly replaceable with the
+   gpio_to_irq() call.
+
+The s3c2410_gpio and `gpio_` calls have always operated on the same gpio
+numberspace, so there is no problem with converting the gpio numbering
+between the calls.
+
+
+Headers
+-------
+
+  See arch/arm/mach-s3c24xx/include/mach/regs-gpio.h for the list
+  of GPIO pins, and the configuration values for them. This
+  is included by using #include <mach/regs-gpio.h>
+
+
+PIN Numbers
+-----------
+
+  Each pin has an unique number associated with it in regs-gpio.h,
+  e.g. S3C2410_GPA(0) or S3C2410_GPF(1). These defines are used to tell
+  the GPIO functions which pin is to be used.
+
+  With the conversion to gpiolib, there is no longer a direct conversion
+  from gpio pin number to register base address as in earlier kernels. This
+  is due to the number space required for newer SoCs where the later
+  GPIOs are not contiguous.
+
+
+Configuring a pin
+-----------------
+
+  The following function allows the configuration of a given pin to
+  be changed.
+
+    void s3c_gpio_cfgpin(unsigned int pin, unsigned int function);
+
+  e.g.:
+
+     s3c_gpio_cfgpin(S3C2410_GPA(0), S3C_GPIO_SFN(1));
+     s3c_gpio_cfgpin(S3C2410_GPE(8), S3C_GPIO_SFN(2));
+
+   which would turn GPA(0) into the lowest Address line A0, and set
+   GPE(8) to be connected to the SDIO/MMC controller's SDDAT1 line.
+
+
+Reading the current configuration
+---------------------------------
+
+  The current configuration of a pin can be read by using standard
+  gpiolib function:
+
+  s3c_gpio_getcfg(unsigned int pin);
+
+  The return value will be from the same set of values which can be
+  passed to s3c_gpio_cfgpin().
+
+
+Configuring a pull-up resistor
+------------------------------
+
+  A large proportion of the GPIO pins on the S3C2410 can have weak
+  pull-up resistors enabled. This can be configured by the following
+  function:
+
+    void s3c_gpio_setpull(unsigned int pin, unsigned int to);
+
+  Where the to value is S3C_GPIO_PULL_NONE to set the pull-up off,
+  and S3C_GPIO_PULL_UP to enable the specified pull-up. Any other
+  values are currently undefined.
+
+
+Getting and setting the state of a PIN
+--------------------------------------
+
+  These calls are now implemented by the relevant gpiolib calls, convert
+  your board or driver to use gpiolib.
+
+
+Getting the IRQ number associated with a PIN
+--------------------------------------------
+
+  A standard gpiolib function can map the given pin number to an IRQ
+  number to pass to the IRQ system.
+
+   int gpio_to_irq(unsigned int pin);
+
+  Note, not all pins have an IRQ.
+
+
+Author
+-------
+
+Ben Dooks, 03 October 2004
+Copyright 2004 Ben Dooks, Simtec Electronics
diff --git a/Documentation/arm/samsung-s3c24xx/h1940.rst b/Documentation/arm/samsung-s3c24xx/h1940.rst
new file mode 100644 (file)
index 0000000..62a562c
--- /dev/null
@@ -0,0 +1,41 @@
+=============
+HP IPAQ H1940
+=============
+
+http://www.handhelds.org/projects/h1940.html
+
+Introduction
+------------
+
+  The HP H1940 is a S3C2410 based handheld device, with
+  bluetooth connectivity.
+
+
+Support
+-------
+
+  A variety of information is available
+
+  handhelds.org project page:
+
+    http://www.handhelds.org/projects/h1940.html
+
+  handhelds.org wiki page:
+
+    http://handhelds.org/moin/moin.cgi/HpIpaqH1940
+
+  Herbert Pötzl pages:
+
+    http://vserver.13thfloor.at/H1940/
+
+
+Maintainers
+-----------
+
+  This project is being maintained and developed by a variety
+  of people, including Ben Dooks, Arnaud Patard, and Herbert Pötzl.
+
+  Thanks to the many others who have also provided support.
+
+
+(c) 2005 Ben Dooks
diff --git a/Documentation/arm/samsung-s3c24xx/index.rst b/Documentation/arm/samsung-s3c24xx/index.rst
new file mode 100644 (file)
index 0000000..5b8a7f9
--- /dev/null
@@ -0,0 +1,20 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==========================
+Samsung S3C24XX SoC Family
+==========================
+
+.. toctree::
+   :maxdepth: 1
+
+   h1940
+   gpio
+   cpufreq
+   suspend
+   usb-host
+   s3c2412
+   eb2410itx
+   nand
+   smdk2440
+   s3c2413
+   overview
diff --git a/Documentation/arm/samsung-s3c24xx/nand.rst b/Documentation/arm/samsung-s3c24xx/nand.rst
new file mode 100644 (file)
index 0000000..9389956
--- /dev/null
@@ -0,0 +1,30 @@
+====================
+S3C24XX NAND Support
+====================
+
+Introduction
+------------
+
+Small Page NAND
+---------------
+
+The driver uses a 512 byte (1 page) ECC code for this setup. The
+ECC code is not directly compatible with the default kernel ECC
+code, so the driver enforces its own OOB layout and ECC parameters
+
+Large Page NAND
+---------------
+
+The driver is capable of handling NAND flash with a 2KiB page
+size, with support for hardware ECC generation and correction.
+
+Unlike the 512byte page mode, the driver generates ECC data for
+each 256 byte block in an 2KiB page. This means that more than
+one error in a page can be rectified. It also means that the
+OOB layout remains the default kernel layout for these flashes.
+
+
+Document Author
+---------------
+
+Ben Dooks, Copyright 2007 Simtec Electronics
diff --git a/Documentation/arm/samsung-s3c24xx/overview.rst b/Documentation/arm/samsung-s3c24xx/overview.rst
new file mode 100644 (file)
index 0000000..e9a1dc7
--- /dev/null
@@ -0,0 +1,319 @@
+==========================
+S3C24XX ARM Linux Overview
+==========================
+
+
+
+Introduction
+------------
+
+  The Samsung S3C24XX range of ARM9 System-on-Chip CPUs are supported
+  by the 's3c2410' architecture of ARM Linux. Currently the S3C2410,
+  S3C2412, S3C2413, S3C2416, S3C2440, S3C2442, S3C2443 and S3C2450 devices
+  are supported.
+
+  Support for the S3C2400 and S3C24A0 series was never completed and the
+  corresponding code has been removed after a while.  If someone wishes to
+  revive this effort, partial support can be retrieved from earlier Linux
+  versions.
+
+  The S3C2416 and S3C2450 devices are very similar and S3C2450 support is
+  included under the arch/arm/mach-s3c2416 directory. Note, while core
+  support for these SoCs is in, work on some of the extra peripherals
+  and extra interrupts is still ongoing.
+
+
+Configuration
+-------------
+
+  A generic S3C2410 configuration is provided, and can be used as the
+  default by `make s3c2410_defconfig`. This configuration has support
+  for all the machines, and the commonly used features on them.
+
+  Certain machines may have their own default configurations as well,
+  please check the machine specific documentation.
+
+
+Layout
+------
+
+  The core support files are located in the platform code contained in
+  arch/arm/plat-s3c24xx with headers in include/asm-arm/plat-s3c24xx.
+  This directory should be kept to items shared between the platform
+  code (arch/arm/plat-s3c24xx) and the arch/arm/mach-s3c24* code.
+
+  Each cpu has a directory with the support files for it, and the
+  machines that carry the device. For example S3C2410 is contained
+  in arch/arm/mach-s3c2410 and S3C2440 in arch/arm/mach-s3c2440
+
+  Register, kernel and platform data definitions are held in the
+  arch/arm/mach-s3c2410 directory./include/mach
+
+arch/arm/plat-s3c24xx:
+
+  Files in here are either common to all the s3c24xx family,
+  or are common to only some of them with names to indicate this
+  status. The files that are not common to all are generally named
+  with the initial cpu they support in the series to ensure a short
+  name without any possibility of confusion with newer devices.
+
+  As an example, initially s3c244x would cover s3c2440 and s3c2442, but
+  with the s3c2443 which does not share many of the same drivers in
+  this directory, the name becomes invalid. We stick to s3c2440-<x>
+  to indicate a driver that is s3c2440 and s3c2442 compatible.
+
+  This does mean that to find the status of any given SoC, a number
+  of directories may need to be searched.
+
+
+Machines
+--------
+
+  The currently supported machines are as follows:
+
+  Simtec Electronics EB2410ITX (BAST)
+
+    A general purpose development board, see EB2410ITX.txt for further
+    details
+
+  Simtec Electronics IM2440D20 (Osiris)
+
+    CPU Module from Simtec Electronics, with a S3C2440A CPU, nand flash
+    and a PCMCIA controller.
+
+  Samsung SMDK2410
+
+    Samsung's own development board, geared for PDA work.
+
+  Samsung/Aiji SMDK2412
+
+    The S3C2412 version of the SMDK2440.
+
+  Samsung/Aiji SMDK2413
+
+    The S3C2412 version of the SMDK2440.
+
+  Samsung/Meritech SMDK2440
+
+    The S3C2440 compatible version of the SMDK2440, which has the
+    option of an S3C2440 or S3C2442 CPU module.
+
+  Thorcom VR1000
+
+    Custom embedded board
+
+  HP IPAQ 1940
+
+    Handheld (IPAQ), available in several varieties
+
+  HP iPAQ rx3715
+
+    S3C2440 based IPAQ, with a number of variations depending on
+    features shipped.
+
+  Acer N30
+
+    A S3C2410 based PDA from Acer.  There is a Wiki page at
+    http://handhelds.org/moin/moin.cgi/AcerN30Documentation .
+
+  AML M5900
+
+    American Microsystems' M5900
+
+  Nex Vision Nexcoder
+  Nex Vision Otom
+
+    Two machines by Nex Vision
+
+
+Adding New Machines
+-------------------
+
+  The architecture has been designed to support as many machines as can
+  be configured for it in one kernel build, and any future additions
+  should keep this in mind before altering items outside of their own
+  machine files.
+
+  Machine definitions should be kept in linux/arch/arm/mach-s3c2410,
+  and there are a number of examples that can be looked at.
+
+  Read the kernel patch submission policies as well as the
+  Documentation/arm directory before submitting patches. The
+  ARM kernel series is managed by Russell King, and has a patch system
+  located at http://www.arm.linux.org.uk/developer/patches/
+  as well as mailing lists that can be found from the same site.
+
+  As a courtesy, please notify <ben-linux@fluff.org> of any new
+  machines or other modifications.
+
+  Any large scale modifications, or new drivers should be discussed
+  on the ARM kernel mailing list (linux-arm-kernel) before being
+  attempted. See http://www.arm.linux.org.uk/mailinglists/ for the
+  mailing list information.
+
+
+I2C
+---
+
+  The hardware I2C core in the CPU is supported in single master
+  mode, and can be configured via platform data.
+
+
+RTC
+---
+
+  Support for the onboard RTC unit, including alarm function.
+
+  This has recently been upgraded to use the new RTC core,
+  and the module has been renamed to rtc-s3c to fit in with
+  the new rtc naming scheme.
+
+
+Watchdog
+--------
+
+  The onchip watchdog is available via the standard watchdog
+  interface.
+
+
+NAND
+----
+
+  The current kernels now have support for the s3c2410 NAND
+  controller. If there are any problems the latest linux-mtd
+  code can be found from http://www.linux-mtd.infradead.org/
+
+  For more information see Documentation/arm/samsung-s3c24xx/nand.rst
+
+
+SD/MMC
+------
+
+  The SD/MMC hardware pre S3C2443 is supported in the current
+  kernel, the driver is drivers/mmc/host/s3cmci.c and supports
+  1 and 4 bit SD or MMC cards.
+
+  The SDIO behaviour of this driver has not been fully tested. There is no
+  current support for hardware SDIO interrupts.
+
+
+Serial
+------
+
+  The s3c2410 serial driver provides support for the internal
+  serial ports. These devices appear as /dev/ttySAC0 through 3.
+
+  To create device nodes for these, use the following commands
+
+    mknod ttySAC0 c 204 64
+    mknod ttySAC1 c 204 65
+    mknod ttySAC2 c 204 66
+
+
+GPIO
+----
+
+  The core contains support for manipulating the GPIO, see the
+  documentation in GPIO.txt in the same directory as this file.
+
+  Newer kernels carry GPIOLIB, and support is being moved towards
+  this with some of the older support in line to be removed.
+
+  As of v2.6.34, the move towards using gpiolib support is almost
+  complete, and very little of the old calls are left.
+
+  See Documentation/arm/samsung-s3c24xx/gpio.rst for the S3C24XX specific
+  support and Documentation/arm/samsung/gpio.rst for the core Samsung
+  implementation.
+
+
+Clock Management
+----------------
+
+  The core provides the interface defined in the header file
+  include/asm-arm/hardware/clock.h, to allow control over the
+  various clock units
+
+
+Suspend to RAM
+--------------
+
+  For boards that provide support for suspend to RAM, the
+  system can be placed into low power suspend.
+
+  See Suspend.txt for more information.
+
+
+SPI
+---
+
+  SPI drivers are available for both the in-built hardware
+  (although there is no DMA support yet) and a generic
+  GPIO based solution.
+
+
+LEDs
+----
+
+  There is support for GPIO based LEDs via a platform driver
+  in the LED subsystem.
+
+
+Platform Data
+-------------
+
+  Whenever a device has platform specific data that is specified
+  on a per-machine basis, care should be taken to ensure the
+  following:
+
+    1) that default data is not left in the device to confuse the
+       driver if a machine does not set it at startup
+
+    2) the data should (if possible) be marked as __initdata,
+       to ensure that the data is thrown away if the machine is
+       not the one currently in use.
+
+       The best way of doing this is to make a function that
+       kmalloc()s an area of memory, and copies the __initdata
+       and then sets the relevant device's platform data. Making
+       the function `__init` takes care of ensuring it is discarded
+       with the rest of the initialisation code::
+
+         static __init void s3c24xx_xxx_set_platdata(struct xxx_data *pd)
+         {
+             struct s3c2410_xxx_mach_info *npd;
+
+          npd = kmalloc(sizeof(struct s3c2410_xxx_mach_info), GFP_KERNEL);
+          if (npd) {
+             memcpy(npd, pd, sizeof(struct s3c2410_xxx_mach_info));
+             s3c_device_xxx.dev.platform_data = npd;
+          } else {
+                printk(KERN_ERR "no memory for xxx platform data\n");
+          }
+       }
+
+       Note, since the code is marked as __init, it should not be
+       exported outside arch/arm/mach-s3c2410/, or exported to
+       modules via EXPORT_SYMBOL() and related functions.
+
+
+Port Contributors
+-----------------
+
+  Ben Dooks (BJD)
+  Vincent Sanders
+  Herbert Potzl
+  Arnaud Patard (RTP)
+  Roc Wu
+  Klaus Fetscher
+  Dimitry Andric
+  Shannon Holland
+  Guillaume Gourat (NexVision)
+  Christer Weinigel (wingel) (Acer N30)
+  Lucas Correia Villa Real (S3C2400 port)
+
+
+Document Author
+---------------
+
+Ben Dooks, Copyright 2004-2006 Simtec Electronics
diff --git a/Documentation/arm/samsung-s3c24xx/s3c2412.rst b/Documentation/arm/samsung-s3c24xx/s3c2412.rst
new file mode 100644 (file)
index 0000000..68b985f
--- /dev/null
@@ -0,0 +1,121 @@
+==========================
+S3C2412 ARM Linux Overview
+==========================
+
+Introduction
+------------
+
+  The S3C2412 is part of the S3C24XX range of ARM9 System-on-Chip CPUs
+  from Samsung. This part has an ARM926-EJS core, capable of running up
+  to 266MHz (see data-sheet for more information)
+
+
+Clock
+-----
+
+  The core clock code provides a set of clocks to the drivers, and allows
+  for source selection and a number of other features.
+
+
+Power
+-----
+
+  No support for suspend/resume to RAM in the current system.
+
+
+DMA
+---
+
+  No current support for DMA.
+
+
+GPIO
+----
+
+  There is support for setting the GPIO to input/output/special function
+  and reading or writing to them.
+
+
+UART
+----
+
+  The UART hardware is similar to the S3C2440, and is supported by the
+  s3c2410 driver in the drivers/serial directory.
+
+
+NAND
+----
+
+  The NAND hardware is similar to the S3C2440, and is supported by the
+  s3c2410 driver in the drivers/mtd/nand/raw directory.
+
+
+USB Host
+--------
+
+  The USB hardware is similar to the S3C2410, with extended clock source
+  control. The OHCI portion is supported by the ohci-s3c2410 driver, and
+  the clock control selection is supported by the core clock code.
+
+
+USB Device
+----------
+
+  No current support in the kernel
+
+
+IRQs
+----
+
+  All the standard, and external interrupt sources are supported. The
+  extra sub-sources are not yet supported.
+
+
+RTC
+---
+
+  The RTC hardware is similar to the S3C2410, and is supported by the
+  s3c2410-rtc driver.
+
+
+Watchdog
+--------
+
+  The watchdog hardware is the same as the S3C2410, and is supported by
+  the s3c2410_wdt driver.
+
+
+MMC/SD/SDIO
+-----------
+
+  No current support for the MMC/SD/SDIO block.
+
+IIC
+---
+
+  The IIC hardware is the same as the S3C2410, and is supported by the
+  i2c-s3c24xx driver.
+
+
+IIS
+---
+
+  No current support for the IIS interface.
+
+
+SPI
+---
+
+  No current support for the SPI interfaces.
+
+
+ATA
+---
+
+  No current support for the on-board ATA block.
+
+
+Document Author
+---------------
+
+Ben Dooks, Copyright 2006 Simtec Electronics
diff --git a/Documentation/arm/samsung-s3c24xx/s3c2413.rst b/Documentation/arm/samsung-s3c24xx/s3c2413.rst
new file mode 100644 (file)
index 0000000..1f51e20
--- /dev/null
@@ -0,0 +1,22 @@
+==========================
+S3C2413 ARM Linux Overview
+==========================
+
+Introduction
+------------
+
+  The S3C2413 is an extended version of the S3C2412, with an camera
+  interface and mobile DDR memory support. See the S3C2412 support
+  documentation for more information.
+
+
+Camera Interface
+----------------
+
+  This block is currently not supported.
+
+
+Document Author
+---------------
+
+Ben Dooks, Copyright 2006 Simtec Electronics
diff --git a/Documentation/arm/samsung-s3c24xx/smdk2440.rst b/Documentation/arm/samsung-s3c24xx/smdk2440.rst
new file mode 100644 (file)
index 0000000..524fd0b
--- /dev/null
@@ -0,0 +1,57 @@
+=========================
+Samsung/Meritech SMDK2440
+=========================
+
+Introduction
+------------
+
+  The SMDK2440 is a two part evaluation board for the Samsung S3C2440
+  processor. It includes support for LCD, SmartMedia, Audio, SD and
+  10MBit Ethernet, and expansion headers for various signals, including
+  the camera and unused GPIO.
+
+
+Configuration
+-------------
+
+  To set the default configuration, use `make smdk2440_defconfig` which
+  will configure the common features of this board, or use
+  `make s3c2410_config` to include support for all s3c2410/s3c2440 machines
+
+
+Support
+-------
+
+  Ben Dooks' SMDK2440 site at http://www.fluff.org/ben/smdk2440/ which
+  includes linux based USB download tools.
+
+  Some of the h1940 patches that can be found from the H1940 project
+  site at http://www.handhelds.org/projects/h1940.html can also be
+  applied to this board.
+
+
+Peripherals
+-----------
+
+  There is no current support for any of the extra peripherals on the
+  base-board itself.
+
+
+MTD
+---
+
+  The NAND flash should be supported by the in kernel MTD NAND support,
+  NOR flash will be added later.
+
+
+Maintainers
+-----------
+
+  This board is being maintained by Ben Dooks, for more info, see
+  http://www.fluff.org/ben/smdk2440/
+
+  Many thanks to Dimitry Andric of TomTom for the loan of the SMDK2440,
+  and to Simtec Electronics for allowing me time to work on this.
+
+
+(c) 2004 Ben Dooks
diff --git a/Documentation/arm/samsung-s3c24xx/suspend.rst b/Documentation/arm/samsung-s3c24xx/suspend.rst
new file mode 100644 (file)
index 0000000..b4f3ae9
--- /dev/null
@@ -0,0 +1,137 @@
+=======================
+S3C24XX Suspend Support
+=======================
+
+
+Introduction
+------------
+
+  The S3C24XX supports a low-power suspend mode, where the SDRAM is kept
+  in Self-Refresh mode, and all but the essential peripheral blocks are
+  powered down. For more information on how this works, please look
+  at the relevant CPU datasheet from Samsung.
+
+
+Requirements
+------------
+
+  1) A bootloader that can support the necessary resume operation
+
+  2) Support for at least 1 source for resume
+
+  3) CONFIG_PM enabled in the kernel
+
+  4) Any peripherals that are going to be powered down at the same
+     time require suspend/resume support.
+
+
+Resuming
+--------
+
+  The S3C2410 user manual defines the process of sending the CPU to
+  sleep and how it resumes. The default behaviour of the Linux code
+  is to set the GSTATUS3 register to the physical address of the
+  code to resume Linux operation.
+
+  GSTATUS4 is currently left alone by the sleep code, and is free to
+  use for any other purposes (for example, the EB2410ITX uses this to
+  save memory configuration in).
+
+
+Machine Support
+---------------
+
+  The machine specific functions must call the s3c_pm_init() function
+  to say that its bootloader is capable of resuming. This can be as
+  simple as adding the following to the machine's definition:
+
+  INITMACHINE(s3c_pm_init)
+
+  A board can do its own setup before calling s3c_pm_init, if it
+  needs to setup anything else for power management support.
+
+  There is currently no support for over-riding the default method of
+  saving the resume address, if your board requires it, then contact
+  the maintainer and discuss what is required.
+
+  Note, the original method of adding an late_initcall() is wrong,
+  and will end up initialising all compiled machines' pm init!
+
+  The following is an example of code used for testing wakeup from
+  an falling edge on IRQ_EINT0::
+
+
+    static irqreturn_t button_irq(int irq, void *pw)
+    {
+       return IRQ_HANDLED;
+    }
+
+    statuc void __init machine_init(void)
+    {
+       ...
+
+       request_irq(IRQ_EINT0, button_irq, IRQF_TRIGGER_FALLING,
+                  "button-irq-eint0", NULL);
+
+       enable_irq_wake(IRQ_EINT0);
+
+       s3c_pm_init();
+    }
+
+
+Debugging
+---------
+
+  There are several important things to remember when using PM suspend:
+
+  1) The uart drivers will disable the clocks to the UART blocks when
+     suspending, which means that use of printascii() or similar direct
+     access to the UARTs will cause the debug to stop.
+
+  2) While the pm code itself will attempt to re-enable the UART clocks,
+     care should be taken that any external clock sources that the UARTs
+     rely on are still enabled at that point.
+
+  3) If any debugging is placed in the resume path, then it must have the
+     relevant clocks and peripherals setup before use (ie, bootloader).
+
+     For example, if you transmit a character from the UART, the baud
+     rate and uart controls must be setup beforehand.
+
+
+Configuration
+-------------
+
+  The S3C2410 specific configuration in `System Type` defines various
+  aspects of how the S3C2410 suspend and resume support is configured
+
+  `S3C2410 PM Suspend debug`
+
+    This option prints messages to the serial console before and after
+    the actual suspend, giving detailed information on what is
+    happening
+
+
+  `S3C2410 PM Suspend Memory CRC`
+
+    Allows the entire memory to be checksummed before and after the
+    suspend to see if there has been any corruption of the contents.
+
+    Note, the time to calculate the CRC is dependent on the CPU speed
+    and the size of memory. For an 64Mbyte RAM area on an 200MHz
+    S3C2410, this can take approximately 4 seconds to complete.
+
+    This support requires the CRC32 function to be enabled.
+
+
+  `S3C2410 PM Suspend CRC Chunksize (KiB)`
+
+    Defines the size of memory each CRC chunk covers. A smaller value
+    will mean that the CRC data block will take more memory, but will
+    identify any faults with better precision
+
+
+Document Author
+---------------
+
+Ben Dooks, Copyright 2004 Simtec Electronics
diff --git a/Documentation/arm/samsung-s3c24xx/usb-host.rst b/Documentation/arm/samsung-s3c24xx/usb-host.rst
new file mode 100644 (file)
index 0000000..c84268b
--- /dev/null
@@ -0,0 +1,91 @@
+========================
+S3C24XX USB Host support
+========================
+
+
+
+Introduction
+------------
+
+  This document details the S3C2410/S3C2440 in-built OHCI USB host support.
+
+Configuration
+-------------
+
+  Enable at least the following kernel options:
+
+  menuconfig::
+
+   Device Drivers  --->
+     USB support  --->
+       <*> Support for Host-side USB
+       <*>   OHCI HCD support
+
+
+  .config:
+
+    - CONFIG_USB
+    - CONFIG_USB_OHCI_HCD
+
+
+  Once these options are configured, the standard set of USB device
+  drivers can be configured and used.
+
+
+Board Support
+-------------
+
+  The driver attaches to a platform device, which will need to be
+  added by the board specific support file in linux/arch/arm/mach-s3c2410,
+  such as mach-bast.c or mach-smdk2410.c
+
+  The platform device's platform_data field is only needed if the
+  board implements extra power control or over-current monitoring.
+
+  The OHCI driver does not ensure the state of the S3C2410's MISCCTRL
+  register, so if both ports are to be used for the host, then it is
+  the board support file's responsibility to ensure that the second
+  port is configured to be connected to the OHCI core.
+
+
+Platform Data
+-------------
+
+  See arch/arm/mach-s3c2410/include/mach/usb-control.h for the
+  descriptions of the platform device data. An implementation
+  can be found in linux/arch/arm/mach-s3c2410/usb-simtec.c .
+
+  The `struct s3c2410_hcd_info` contains a pair of functions
+  that get called to enable over-current detection, and to
+  control the port power status.
+
+  The ports are numbered 0 and 1.
+
+  power_control:
+    Called to enable or disable the power on the port.
+
+  enable_oc:
+    Called to enable or disable the over-current monitoring.
+    This should claim or release the resources being used to
+    check the power condition on the port, such as an IRQ.
+
+  report_oc:
+    The OHCI driver fills this field in for the over-current code
+    to call when there is a change to the over-current state on
+    an port. The ports argument is a bitmask of 1 bit per port,
+    with bit X being 1 for an over-current on port X.
+
+    The function s3c2410_usb_report_oc() has been provided to
+    ensure this is called correctly.
+
+  port[x]:
+    This is struct describes each port, 0 or 1. The platform driver
+    should set the flags field of each port to S3C_HCDFLG_USED if
+    the port is enabled.
+
+
+
+Document Author
+---------------
+
+Ben Dooks, Copyright 2005 Simtec Electronics
diff --git a/Documentation/arm/samsung/bootloader-interface.rst b/Documentation/arm/samsung/bootloader-interface.rst
new file mode 100644 (file)
index 0000000..a56f325
--- /dev/null
@@ -0,0 +1,81 @@
+==========================================================
+Interface between kernel and boot loaders on Exynos boards
+==========================================================
+
+Author: Krzysztof Kozlowski
+
+Date  : 6 June 2015
+
+The document tries to describe currently used interface between Linux kernel
+and boot loaders on Samsung Exynos based boards. This is not a definition
+of interface but rather a description of existing state, a reference
+for information purpose only.
+
+In the document "boot loader" means any of following: U-boot, proprietary
+SBOOT or any other firmware for ARMv7 and ARMv8 initializing the board before
+executing kernel.
+
+
+1. Non-Secure mode
+
+Address:      sysram_ns_base_addr
+
+============= ============================================ ==================
+Offset        Value                                        Purpose
+============= ============================================ ==================
+0x08          exynos_cpu_resume_ns, mcpm_entry_point       System suspend
+0x0c          0x00000bad (Magic cookie)                    System suspend
+0x1c          exynos4_secondary_startup                    Secondary CPU boot
+0x1c + 4*cpu  exynos4_secondary_startup (Exynos4412)       Secondary CPU boot
+0x20          0xfcba0d10 (Magic cookie)                    AFTR
+0x24          exynos_cpu_resume_ns                         AFTR
+0x28 + 4*cpu  0x8 (Magic cookie, Exynos3250)               AFTR
+0x28          0x0 or last value during resume (Exynos542x) System suspend
+============= ============================================ ==================
+
+
+2. Secure mode
+
+Address:      sysram_base_addr
+
+============= ============================================ ==================
+Offset        Value                                        Purpose
+============= ============================================ ==================
+0x00          exynos4_secondary_startup                    Secondary CPU boot
+0x04          exynos4_secondary_startup (Exynos542x)       Secondary CPU boot
+4*cpu         exynos4_secondary_startup (Exynos4412)       Secondary CPU boot
+0x20          exynos_cpu_resume (Exynos4210 r1.0)          AFTR
+0x24          0xfcba0d10 (Magic cookie, Exynos4210 r1.0)   AFTR
+============= ============================================ ==================
+
+Address:      pmu_base_addr
+
+============= ============================================ ==================
+Offset        Value                                        Purpose
+============= ============================================ ==================
+0x0800        exynos_cpu_resume                            AFTR, suspend
+0x0800        mcpm_entry_point (Exynos542x with MCPM)      AFTR, suspend
+0x0804        0xfcba0d10 (Magic cookie)                    AFTR
+0x0804        0x00000bad (Magic cookie)                    System suspend
+0x0814        exynos4_secondary_startup (Exynos4210 r1.1)  Secondary CPU boot
+0x0818        0xfcba0d10 (Magic cookie, Exynos4210 r1.1)   AFTR
+0x081C        exynos_cpu_resume (Exynos4210 r1.1)          AFTR
+============= ============================================ ==================
+
+3. Other (regardless of secure/non-secure mode)
+
+Address:      pmu_base_addr
+
+============= =============================== ===============================
+Offset        Value                           Purpose
+============= =============================== ===============================
+0x0908        Non-zero                        Secondary CPU boot up indicator
+                                              on Exynos3250 and Exynos542x
+============= =============================== ===============================
+
+
+4. Glossary
+
+AFTR - ARM Off Top Running, a low power mode, Cortex cores and many other
+modules are power gated, except the TOP modules
+MCPM - Multi-Cluster Power Management
diff --git a/Documentation/arm/samsung/gpio.rst b/Documentation/arm/samsung/gpio.rst
new file mode 100644 (file)
index 0000000..5f7cadd
--- /dev/null
@@ -0,0 +1,41 @@
+===========================
+Samsung GPIO implementation
+===========================
+
+Introduction
+------------
+
+This outlines the Samsung GPIO implementation and the architecture
+specific calls provided alongside the drivers/gpio core.
+
+
+S3C24XX (Legacy)
+----------------
+
+See Documentation/arm/samsung-s3c24xx/gpio.rst for more information
+about these devices. Their implementation has been brought into line
+with the core samsung implementation described in this document.
+
+
+GPIOLIB integration
+-------------------
+
+The gpio implementation uses gpiolib as much as possible, only providing
+specific calls for the items that require Samsung specific handling, such
+as pin special-function or pull resistor control.
+
+GPIO numbering is synchronised between the Samsung and gpiolib system.
+
+
+PIN configuration
+-----------------
+
+Pin configuration is specific to the Samsung architecture, with each SoC
+registering the necessary information for the core gpio configuration
+implementation to configure pins as necessary.
+
+The s3c_gpio_cfgpin() and s3c_gpio_setpull() provide the means for a
+driver or machine to change gpio configuration.
+
+See arch/arm/plat-samsung/include/plat/gpio-cfg.h for more information
+on these functions.
diff --git a/Documentation/arm/samsung/index.rst b/Documentation/arm/samsung/index.rst
new file mode 100644 (file)
index 0000000..8142cce
--- /dev/null
@@ -0,0 +1,12 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===========
+Samsung SoC
+===========
+
+.. toctree::
+   :maxdepth: 1
+
+   gpio
+   bootloader-interface
+   overview
diff --git a/Documentation/arm/samsung/overview.rst b/Documentation/arm/samsung/overview.rst
new file mode 100644 (file)
index 0000000..e743078
--- /dev/null
@@ -0,0 +1,89 @@
+==========================
+Samsung ARM Linux Overview
+==========================
+
+Introduction
+------------
+
+  The Samsung range of ARM SoCs spans many similar devices, from the initial
+  ARM9 through to the newest ARM cores. This document shows an overview of
+  the current kernel support, how to use it and where to find the code
+  that supports this.
+
+  The currently supported SoCs are:
+
+  - S3C24XX: See Documentation/arm/samsung-s3c24xx/overview.rst for full list
+  - S3C64XX: S3C6400 and S3C6410
+  - S5PC110 / S5PV210
+
+
+S3C24XX Systems
+---------------
+
+  There is still documentation in Documnetation/arm/Samsung-S3C24XX/ which
+  deals with the architecture and drivers specific to these devices.
+
+  See Documentation/arm/samsung-s3c24xx/overview.rst for more information
+  on the implementation details and specific support.
+
+
+Configuration
+-------------
+
+  A number of configurations are supplied, as there is no current way of
+  unifying all the SoCs into one kernel.
+
+  s5pc110_defconfig
+       - S5PC110 specific default configuration
+  s5pv210_defconfig
+       - S5PV210 specific default configuration
+
+
+Layout
+------
+
+  The directory layout is currently being restructured, and consists of
+  several platform directories and then the machine specific directories
+  of the CPUs being built for.
+
+  plat-samsung provides the base for all the implementations, and is the
+  last in the line of include directories that are processed for the build
+  specific information. It contains the base clock, GPIO and device definitions
+  to get the system running.
+
+  plat-s3c24xx is for s3c24xx specific builds, see the S3C24XX docs.
+
+  plat-s5p is for s5p specific builds, and contains common support for the
+  S5P specific systems. Not all S5Ps use all the features in this directory
+  due to differences in the hardware.
+
+
+Layout changes
+--------------
+
+  The old plat-s3c and plat-s5pc1xx directories have been removed, with
+  support moved to either plat-samsung or plat-s5p as necessary. These moves
+  where to simplify the include and dependency issues involved with having
+  so many different platform directories.
+
+
+Port Contributors
+-----------------
+
+  Ben Dooks (BJD)
+  Vincent Sanders
+  Herbert Potzl
+  Arnaud Patard (RTP)
+  Roc Wu
+  Klaus Fetscher
+  Dimitry Andric
+  Shannon Holland
+  Guillaume Gourat (NexVision)
+  Christer Weinigel (wingel) (Acer N30)
+  Lucas Correia Villa Real (S3C2400 port)
+
+
+Document Author
+---------------
+
+Copyright 2009-2010 Ben Dooks <ben-linux@fluff.org>
diff --git a/Documentation/arm/setup.rst b/Documentation/arm/setup.rst
new file mode 100644 (file)
index 0000000..8e12ef3
--- /dev/null
@@ -0,0 +1,108 @@
+=============================================
+Kernel initialisation parameters on ARM Linux
+=============================================
+
+The following document describes the kernel initialisation parameter
+structure, otherwise known as 'struct param_struct' which is used
+for most ARM Linux architectures.
+
+This structure is used to pass initialisation parameters from the
+kernel loader to the Linux kernel proper, and may be short lived
+through the kernel initialisation process.  As a general rule, it
+should not be referenced outside of arch/arm/kernel/setup.c:setup_arch().
+
+There are a lot of parameters listed in there, and they are described
+below:
+
+ page_size
+   This parameter must be set to the page size of the machine, and
+   will be checked by the kernel.
+
+ nr_pages
+   This is the total number of pages of memory in the system.  If
+   the memory is banked, then this should contain the total number
+   of pages in the system.
+
+   If the system contains separate VRAM, this value should not
+   include this information.
+
+ ramdisk_size
+   This is now obsolete, and should not be used.
+
+ flags
+   Various kernel flags, including:
+
+    =====   ========================
+    bit 0   1 = mount root read only
+    bit 1   unused
+    bit 2   0 = load ramdisk
+    bit 3   0 = prompt for ramdisk
+    =====   ========================
+
+ rootdev
+   major/minor number pair of device to mount as the root filesystem.
+
+ video_num_cols / video_num_rows
+   These two together describe the character size of the dummy console,
+   or VGA console character size.  They should not be used for any other
+   purpose.
+
+   It's generally a good idea to set these to be either standard VGA, or
+   the equivalent character size of your fbcon display.  This then allows
+   all the bootup messages to be displayed correctly.
+
+ video_x / video_y
+   This describes the character position of cursor on VGA console, and
+   is otherwise unused. (should not be used for other console types, and
+   should not be used for other purposes).
+
+ memc_control_reg
+   MEMC chip control register for Acorn Archimedes and Acorn A5000
+   based machines.  May be used differently by different architectures.
+
+ sounddefault
+   Default sound setting on Acorn machines.  May be used differently by
+   different architectures.
+
+ adfsdrives
+   Number of ADFS/MFM disks.  May be used differently by different
+   architectures.
+
+ bytes_per_char_h / bytes_per_char_v
+   These are now obsolete, and should not be used.
+
+ pages_in_bank[4]
+   Number of pages in each bank of the systems memory (used for RiscPC).
+   This is intended to be used on systems where the physical memory
+   is non-contiguous from the processors point of view.
+
+ pages_in_vram
+   Number of pages in VRAM (used on Acorn RiscPC).  This value may also
+   be used by loaders if the size of the video RAM can't be obtained
+   from the hardware.
+
+ initrd_start / initrd_size
+   This describes the kernel virtual start address and size of the
+   initial ramdisk.
+
+ rd_start
+   Start address in sectors of the ramdisk image on a floppy disk.
+
+ system_rev
+   system revision number.
+
+ system_serial_low / system_serial_high
+   system 64-bit serial number
+
+ mem_fclk_21285
+   The speed of the external oscillator to the 21285 (footbridge),
+   which control's the speed of the memory bus, timer & serial port.
+   Depending upon the speed of the cpu its value can be between
+   0-66 MHz. If no params are passed or a value of zero is passed,
+   then a value of 50 Mhz is the default on 21285 architectures.
+
+ paths[8][128]
+   These are now obsolete, and should not be used.
+
+ commandline
+   Kernel command line parameters.  Details can be found elsewhere.
diff --git a/Documentation/arm/spear/overview.rst b/Documentation/arm/spear/overview.rst
new file mode 100644 (file)
index 0000000..1a77f6b
--- /dev/null
@@ -0,0 +1,66 @@
+========================
+SPEAr ARM Linux Overview
+========================
+
+Introduction
+------------
+
+  SPEAr (Structured Processor Enhanced Architecture).
+  weblink : http://www.st.com/spear
+
+  The ST Microelectronics SPEAr range of ARM9/CortexA9 System-on-Chip CPUs are
+  supported by the 'spear' platform of ARM Linux. Currently SPEAr1310,
+  SPEAr1340, SPEAr300, SPEAr310, SPEAr320 and SPEAr600 SOCs are supported.
+
+  Hierarchy in SPEAr is as follows:
+
+  SPEAr (Platform)
+
+       - SPEAr3XX (3XX SOC series, based on ARM9)
+               - SPEAr300 (SOC)
+                       - SPEAr300 Evaluation Board
+               - SPEAr310 (SOC)
+                       - SPEAr310 Evaluation Board
+               - SPEAr320 (SOC)
+                       - SPEAr320 Evaluation Board
+       - SPEAr6XX (6XX SOC series, based on ARM9)
+               - SPEAr600 (SOC)
+                       - SPEAr600 Evaluation Board
+       - SPEAr13XX (13XX SOC series, based on ARM CORTEXA9)
+               - SPEAr1310 (SOC)
+                       - SPEAr1310 Evaluation Board
+               - SPEAr1340 (SOC)
+                       - SPEAr1340 Evaluation Board
+
+Configuration
+-------------
+
+  A generic configuration is provided for each machine, and can be used as the
+  default by::
+
+       make spear13xx_defconfig
+       make spear3xx_defconfig
+       make spear6xx_defconfig
+
+Layout
+------
+
+  The common files for multiple machine families (SPEAr3xx, SPEAr6xx and
+  SPEAr13xx) are located in the platform code contained in arch/arm/plat-spear
+  with headers in plat/.
+
+  Each machine series have a directory with name arch/arm/mach-spear followed by
+  series name. Like mach-spear3xx, mach-spear6xx and mach-spear13xx.
+
+  Common file for machines of spear3xx family is mach-spear3xx/spear3xx.c, for
+  spear6xx is mach-spear6xx/spear6xx.c and for spear13xx family is
+  mach-spear13xx/spear13xx.c. mach-spear* also contain soc/machine specific
+  files, like spear1310.c, spear1340.c spear300.c, spear310.c, spear320.c and
+  spear600.c.  mach-spear* doesn't contains board specific files as they fully
+  support Flattened Device Tree.
+
+
+Document Author
+---------------
+
+  Viresh Kumar <vireshk@kernel.org>, (c) 2010-2012 ST Microelectronics
diff --git a/Documentation/arm/sti/overview.rst b/Documentation/arm/sti/overview.rst
new file mode 100644 (file)
index 0000000..7074361
--- /dev/null
@@ -0,0 +1,36 @@
+======================
+STi ARM Linux Overview
+======================
+
+Introduction
+------------
+
+  The ST Microelectronics Multimedia and Application Processors range of
+  CortexA9 System-on-Chip are supported by the 'STi' platform of
+  ARM Linux. Currently STiH415, STiH416 SOCs are supported with both
+  B2000 and B2020 Reference boards.
+
+
+configuration
+-------------
+
+  A generic configuration is provided for both STiH415/416, and can be used as the
+  default by::
+
+       make stih41x_defconfig
+
+Layout
+------
+
+  All the files for multiple machine families (STiH415, STiH416, and STiG125)
+  are located in the platform code contained in arch/arm/mach-sti
+
+  There is a generic board board-dt.c in the mach folder which support
+  Flattened Device Tree, which means, It works with any compatible board with
+  Device Trees.
+
+
+Document Author
+---------------
+
+  Srinivas Kandagatla <srinivas.kandagatla@st.com>, (c) 2013 ST Microelectronics
diff --git a/Documentation/arm/sti/overview.txt b/Documentation/arm/sti/overview.txt
deleted file mode 100644 (file)
index 1a4e93d..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-                       STi ARM Linux Overview
-                       ==========================
-
-Introduction
-------------
-
-  The ST Microelectronics Multimedia and Application Processors range of
-  CortexA9 System-on-Chip are supported by the 'STi' platform of
-  ARM Linux. Currently STiH415, STiH416 SOCs are supported with both
-  B2000 and B2020 Reference boards.
-
-
-  configuration
-  -------------
-
-  A generic configuration is provided for both STiH415/416, and can be used as the
-  default by
-       make stih41x_defconfig
-
-  Layout
-  ------
-  All the files for multiple machine families (STiH415, STiH416, and STiG125)
-  are located in the platform code contained in arch/arm/mach-sti
-
-  There is a generic board board-dt.c in the mach folder which support
-  Flattened Device Tree, which means, It works with any compatible board with
-  Device Trees.
-
-
-  Document Author
-  ---------------
-
-  Srinivas Kandagatla <srinivas.kandagatla@st.com>, (c) 2013 ST Microelectronics
diff --git a/Documentation/arm/sti/stih407-overview.rst b/Documentation/arm/sti/stih407-overview.rst
new file mode 100644 (file)
index 0000000..027e75b
--- /dev/null
@@ -0,0 +1,19 @@
+================
+STiH407 Overview
+================
+
+Introduction
+------------
+
+    The STiH407 is the new generation of SoC for Multi-HD, AVC set-top boxes
+    and server/connected client application for satellite, cable, terrestrial
+    and IP-STB markets.
+
+    Features
+    - ARM Cortex-A9 1.5 GHz dual core CPU (28nm)
+    - SATA2, USB 3.0, PCIe, Gbit Ethernet
+
+Document Author
+---------------
+
+  Maxime Coquelin <maxime.coquelin@st.com>, (c) 2014 ST Microelectronics
diff --git a/Documentation/arm/sti/stih407-overview.txt b/Documentation/arm/sti/stih407-overview.txt
deleted file mode 100644 (file)
index 3343f32..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-                       STiH407 Overview
-                       ================
-
-Introduction
-------------
-
-    The STiH407 is the new generation of SoC for Multi-HD, AVC set-top boxes
-    and server/connected client application for satellite, cable, terrestrial
-    and IP-STB markets.
-
-    Features
-    - ARM Cortex-A9 1.5 GHz dual core CPU (28nm)
-    - SATA2, USB 3.0, PCIe, Gbit Ethernet
-
-  Document Author
-  ---------------
-
-  Maxime Coquelin <maxime.coquelin@st.com>, (c) 2014 ST Microelectronics
diff --git a/Documentation/arm/sti/stih415-overview.rst b/Documentation/arm/sti/stih415-overview.rst
new file mode 100644 (file)
index 0000000..b67452d
--- /dev/null
@@ -0,0 +1,14 @@
+================
+STiH415 Overview
+================
+
+Introduction
+------------
+
+    The STiH415 is the next generation of HD, AVC set-top box processors
+    for satellite, cable, terrestrial and IP-STB markets.
+
+    Features:
+
+    - ARM Cortex-A9 1.0 GHz, dual-core CPU
+    - SATA2x2,USB 2.0x3, PCIe, Gbit Ethernet MACx2
diff --git a/Documentation/arm/sti/stih415-overview.txt b/Documentation/arm/sti/stih415-overview.txt
deleted file mode 100644 (file)
index 1383e33..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-                       STiH415 Overview
-                       ================
-
-Introduction
-------------
-
-    The STiH415 is the next generation of HD, AVC set-top box processors
-    for satellite, cable, terrestrial and IP-STB markets.
-
-    Features
-    - ARM Cortex-A9 1.0 GHz, dual-core CPU
-    - SATA2x2,USB 2.0x3, PCIe, Gbit Ethernet MACx2
diff --git a/Documentation/arm/sti/stih416-overview.rst b/Documentation/arm/sti/stih416-overview.rst
new file mode 100644 (file)
index 0000000..93f17d7
--- /dev/null
@@ -0,0 +1,13 @@
+================
+STiH416 Overview
+================
+
+Introduction
+------------
+
+    The STiH416 is the next generation of HD, AVC set-top box processors
+    for satellite, cable, terrestrial and IP-STB markets.
+
+    Features
+    - ARM Cortex-A9 1.2 GHz dual core CPU
+    - SATA2x2,USB 2.0x3, PCIe, Gbit Ethernet MACx2
diff --git a/Documentation/arm/sti/stih416-overview.txt b/Documentation/arm/sti/stih416-overview.txt
deleted file mode 100644 (file)
index 558444c..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-                       STiH416 Overview
-                       ================
-
-Introduction
-------------
-
-    The STiH416 is the next generation of HD, AVC set-top box processors
-    for satellite, cable, terrestrial and IP-STB markets.
-
-    Features
-    - ARM Cortex-A9 1.2 GHz dual core CPU
-    - SATA2x2,USB 2.0x3, PCIe, Gbit Ethernet MACx2
diff --git a/Documentation/arm/sti/stih418-overview.rst b/Documentation/arm/sti/stih418-overview.rst
new file mode 100644 (file)
index 0000000..b563c1f
--- /dev/null
@@ -0,0 +1,21 @@
+================
+STiH418 Overview
+================
+
+Introduction
+------------
+
+    The STiH418 is the new generation of SoC for UHDp60 set-top boxes
+    and server/connected client application for satellite, cable, terrestrial
+    and IP-STB markets.
+
+    Features
+    - ARM Cortex-A9 1.5 GHz quad core CPU (28nm)
+    - SATA2, USB 3.0, PCIe, Gbit Ethernet
+    - HEVC L5.1 Main 10
+    - VP9
+
+Document Author
+---------------
+
+  Maxime Coquelin <maxime.coquelin@st.com>, (c) 2015 ST Microelectronics
diff --git a/Documentation/arm/sti/stih418-overview.txt b/Documentation/arm/sti/stih418-overview.txt
deleted file mode 100644 (file)
index 1cd8fc8..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-                       STiH418 Overview
-                       ================
-
-Introduction
-------------
-
-    The STiH418 is the new generation of SoC for UHDp60 set-top boxes
-    and server/connected client application for satellite, cable, terrestrial
-    and IP-STB markets.
-
-    Features
-    - ARM Cortex-A9 1.5 GHz quad core CPU (28nm)
-    - SATA2, USB 3.0, PCIe, Gbit Ethernet
-    - HEVC L5.1 Main 10
-    - VP9
-
-  Document Author
-  ---------------
-
-  Maxime Coquelin <maxime.coquelin@st.com>, (c) 2015 ST Microelectronics
index f7e7341..85cfc84 100644 (file)
@@ -1,5 +1,3 @@
-:orphan:
-
 ========================
 STM32 ARM Linux Overview
 ========================
index 65bbb1c..a7ebe8e 100644 (file)
@@ -1,5 +1,4 @@
-:orphan:
-
+==================
 STM32F429 Overview
 ==================
 
@@ -23,6 +22,4 @@ Datasheet and reference manual are publicly available on ST website (STM32F429_)
 
 .. _STM32F429: http://www.st.com/web/en/catalog/mmc/FM141/SC1169/SS1577/LN1806?ecmp=stm32f429-439_pron_pr-ces2014_nov2013
 
-:Authors:
-
-Maxime Coquelin <mcoquelin.stm32@gmail.com>
+:Authors: Maxime Coquelin <mcoquelin.stm32@gmail.com>
index 42d5930..78befdd 100644 (file)
@@ -1,5 +1,4 @@
-:orphan:
-
+==================
 STM32F746 Overview
 ==================
 
@@ -30,6 +29,4 @@ Datasheet and reference manual are publicly available on ST website (STM32F746_)
 
 .. _STM32F746: http://www.st.com/content/st_com/en/products/microcontrollers/stm32-32-bit-arm-cortex-mcus/stm32f7-series/stm32f7x6/stm32f746ng.html
 
-:Authors:
-
-Alexandre Torgue <alexandre.torgue@st.com>
+:Authors: Alexandre Torgue <alexandre.torgue@st.com>
index f6adac8..e482980 100644 (file)
@@ -1,5 +1,4 @@
-:orphan:
-
+==================
 STM32F769 Overview
 ==================
 
@@ -32,6 +31,4 @@ Datasheet and reference manual are publicly available on ST website (STM32F769_)
 
 .. _STM32F769: http://www.st.com/content/st_com/en/products/microcontrollers/stm32-32-bit-arm-cortex-mcus/stm32-high-performance-mcus/stm32f7-series/stm32f7x9/stm32f769ni.html
 
-:Authors:
-
-Alexandre Torgue <alexandre.torgue@st.com>
+:Authors: Alexandre Torgue <alexandre.torgue@st.com>
index c525835..4e15f1a 100644 (file)
@@ -1,5 +1,4 @@
-:orphan:
-
+==================
 STM32H743 Overview
 ==================
 
@@ -31,6 +30,4 @@ Datasheet and reference manual are publicly available on ST website (STM32H743_)
 
 .. _STM32H743: http://www.st.com/en/microcontrollers/stm32h7x3.html?querycriteria=productId=LN2033
 
-:Authors:
-
-Alexandre Torgue <alexandre.torgue@st.com>
+:Authors: Alexandre Torgue <alexandre.torgue@st.com>
diff --git a/Documentation/arm/sunxi.rst b/Documentation/arm/sunxi.rst
new file mode 100644 (file)
index 0000000..b037428
--- /dev/null
@@ -0,0 +1,150 @@
+==================
+ARM Allwinner SoCs
+==================
+
+This document lists all the ARM Allwinner SoCs that are currently
+supported in mainline by the Linux kernel. This document will also
+provide links to documentation and/or datasheet for these SoCs.
+
+SunXi family
+------------
+  Linux kernel mach directory: arch/arm/mach-sunxi
+
+  Flavors:
+
+    * ARM926 based SoCs
+      - Allwinner F20 (sun3i)
+
+        * Not Supported
+
+    * ARM Cortex-A8 based SoCs
+      - Allwinner A10 (sun4i)
+
+        * Datasheet
+
+         http://dl.linux-sunxi.org/A10/A10%20Datasheet%20-%20v1.21%20%282012-04-06%29.pdf
+       * User Manual
+
+         http://dl.linux-sunxi.org/A10/A10%20User%20Manual%20-%20v1.20%20%282012-04-09%2c%20DECRYPTED%29.pdf
+
+      - Allwinner A10s (sun5i)
+
+        * Datasheet
+
+          http://dl.linux-sunxi.org/A10s/A10s%20Datasheet%20-%20v1.20%20%282012-03-27%29.pdf
+
+      - Allwinner A13 / R8 (sun5i)
+
+        * Datasheet
+
+         http://dl.linux-sunxi.org/A13/A13%20Datasheet%20-%20v1.12%20%282012-03-29%29.pdf
+        * User Manual
+
+          http://dl.linux-sunxi.org/A13/A13%20User%20Manual%20-%20v1.2%20%282013-01-08%29.pdf
+
+      - Next Thing Co GR8 (sun5i)
+
+    * Single ARM Cortex-A7 based SoCs
+      - Allwinner V3s (sun8i)
+
+        * Datasheet
+
+          http://linux-sunxi.org/File:Allwinner_V3s_Datasheet_V1.0.pdf
+
+    * Dual ARM Cortex-A7 based SoCs
+      - Allwinner A20 (sun7i)
+
+        * User Manual
+
+          http://dl.linux-sunxi.org/A20/A20%20User%20Manual%202013-03-22.pdf
+
+      - Allwinner A23 (sun8i)
+
+        * Datasheet
+
+          http://dl.linux-sunxi.org/A23/A23%20Datasheet%20V1.0%2020130830.pdf
+
+        * User Manual
+
+          http://dl.linux-sunxi.org/A23/A23%20User%20Manual%20V1.0%2020130830.pdf
+
+    * Quad ARM Cortex-A7 based SoCs
+      - Allwinner A31 (sun6i)
+
+        * Datasheet
+
+          http://dl.linux-sunxi.org/A31/A3x_release_document/A31/IC/A31%20datasheet%20V1.3%2020131106.pdf
+
+        * User Manual
+
+          http://dl.linux-sunxi.org/A31/A3x_release_document/A31/IC/A31%20user%20manual%20V1.1%2020130630.pdf
+
+      - Allwinner A31s (sun6i)
+
+        * Datasheet
+
+          http://dl.linux-sunxi.org/A31/A3x_release_document/A31s/IC/A31s%20datasheet%20V1.3%2020131106.pdf
+
+        * User Manual
+
+          http://dl.linux-sunxi.org/A31/A3x_release_document/A31s/IC/A31s%20User%20Manual%20%20V1.0%2020130322.pdf
+
+      - Allwinner A33 (sun8i)
+
+        * Datasheet
+
+          http://dl.linux-sunxi.org/A33/A33%20Datasheet%20release%201.1.pdf
+
+        * User Manual
+
+          http://dl.linux-sunxi.org/A33/A33%20user%20manual%20release%201.1.pdf
+
+      - Allwinner H2+ (sun8i)
+
+        * No document available now, but is known to be working properly with
+          H3 drivers and memory map.
+
+      - Allwinner H3 (sun8i)
+
+        * Datasheet
+
+          http://dl.linux-sunxi.org/H3/Allwinner_H3_Datasheet_V1.0.pdf
+
+      - Allwinner R40 (sun8i)
+
+        * Datasheet
+
+          https://github.com/tinalinux/docs/raw/r40-v1.y/R40_Datasheet_V1.0.pdf
+
+        * User Manual
+
+          https://github.com/tinalinux/docs/raw/r40-v1.y/Allwinner_R40_User_Manual_V1.0.pdf
+
+    * Quad ARM Cortex-A15, Quad ARM Cortex-A7 based SoCs
+      - Allwinner A80
+
+        * Datasheet
+
+         http://dl.linux-sunxi.org/A80/A80_Datasheet_Revision_1.0_0404.pdf
+
+    * Octa ARM Cortex-A7 based SoCs
+      - Allwinner A83T
+
+        * Datasheet
+
+          https://github.com/allwinner-zh/documents/raw/master/A83T/A83T_Datasheet_v1.3_20150510.pdf
+
+        * User Manual
+
+          https://github.com/allwinner-zh/documents/raw/master/A83T/A83T_User_Manual_v1.5.1_20150513.pdf
+
+    * Quad ARM Cortex-A53 based SoCs
+      - Allwinner A64
+
+        * Datasheet
+
+          http://dl.linux-sunxi.org/A64/A64_Datasheet_V1.1.pdf
+
+        * User Manual
+
+          http://dl.linux-sunxi.org/A64/Allwinner%20A64%20User%20Manual%20v1.0.pdf
diff --git a/Documentation/arm/sunxi/README b/Documentation/arm/sunxi/README
deleted file mode 100644 (file)
index f8efc21..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-ARM Allwinner SoCs
-==================
-
-This document lists all the ARM Allwinner SoCs that are currently
-supported in mainline by the Linux kernel. This document will also
-provide links to documentation and/or datasheet for these SoCs.
-
-SunXi family
-------------
-  Linux kernel mach directory: arch/arm/mach-sunxi
-
-  Flavors:
-    * ARM926 based SoCs
-      - Allwinner F20 (sun3i)
-        + Not Supported
-
-    * ARM Cortex-A8 based SoCs
-      - Allwinner A10 (sun4i)
-        + Datasheet
-         http://dl.linux-sunxi.org/A10/A10%20Datasheet%20-%20v1.21%20%282012-04-06%29.pdf
-       + User Manual
-         http://dl.linux-sunxi.org/A10/A10%20User%20Manual%20-%20v1.20%20%282012-04-09%2c%20DECRYPTED%29.pdf
-
-      - Allwinner A10s (sun5i)
-        + Datasheet
-          http://dl.linux-sunxi.org/A10s/A10s%20Datasheet%20-%20v1.20%20%282012-03-27%29.pdf
-
-      - Allwinner A13 / R8 (sun5i)
-        + Datasheet
-         http://dl.linux-sunxi.org/A13/A13%20Datasheet%20-%20v1.12%20%282012-03-29%29.pdf
-        + User Manual
-          http://dl.linux-sunxi.org/A13/A13%20User%20Manual%20-%20v1.2%20%282013-01-08%29.pdf
-
-      - Next Thing Co GR8 (sun5i)
-
-    * Single ARM Cortex-A7 based SoCs
-      - Allwinner V3s (sun8i)
-        + Datasheet
-          http://linux-sunxi.org/File:Allwinner_V3s_Datasheet_V1.0.pdf
-
-    * Dual ARM Cortex-A7 based SoCs
-      - Allwinner A20 (sun7i)
-        + User Manual
-          http://dl.linux-sunxi.org/A20/A20%20User%20Manual%202013-03-22.pdf
-
-      - Allwinner A23 (sun8i)
-        + Datasheet
-          http://dl.linux-sunxi.org/A23/A23%20Datasheet%20V1.0%2020130830.pdf
-        + User Manual
-          http://dl.linux-sunxi.org/A23/A23%20User%20Manual%20V1.0%2020130830.pdf
-
-    * Quad ARM Cortex-A7 based SoCs
-      - Allwinner A31 (sun6i)
-        + Datasheet
-          http://dl.linux-sunxi.org/A31/A3x_release_document/A31/IC/A31%20datasheet%20V1.3%2020131106.pdf
-        + User Manual
-          http://dl.linux-sunxi.org/A31/A3x_release_document/A31/IC/A31%20user%20manual%20V1.1%2020130630.pdf
-
-      - Allwinner A31s (sun6i)
-        + Datasheet
-          http://dl.linux-sunxi.org/A31/A3x_release_document/A31s/IC/A31s%20datasheet%20V1.3%2020131106.pdf
-        + User Manual
-          http://dl.linux-sunxi.org/A31/A3x_release_document/A31s/IC/A31s%20User%20Manual%20%20V1.0%2020130322.pdf
-
-      - Allwinner A33 (sun8i)
-        + Datasheet
-          http://dl.linux-sunxi.org/A33/A33%20Datasheet%20release%201.1.pdf
-        + User Manual
-          http://dl.linux-sunxi.org/A33/A33%20user%20manual%20release%201.1.pdf
-
-      - Allwinner H2+ (sun8i)
-        + No document available now, but is known to be working properly with
-          H3 drivers and memory map.
-
-      - Allwinner H3 (sun8i)
-        + Datasheet
-          http://dl.linux-sunxi.org/H3/Allwinner_H3_Datasheet_V1.0.pdf
-
-      - Allwinner R40 (sun8i)
-        + Datasheet
-          https://github.com/tinalinux/docs/raw/r40-v1.y/R40_Datasheet_V1.0.pdf
-        + User Manual
-          https://github.com/tinalinux/docs/raw/r40-v1.y/Allwinner_R40_User_Manual_V1.0.pdf
-
-    * Quad ARM Cortex-A15, Quad ARM Cortex-A7 based SoCs
-      - Allwinner A80
-        + Datasheet
-         http://dl.linux-sunxi.org/A80/A80_Datasheet_Revision_1.0_0404.pdf
-
-    * Octa ARM Cortex-A7 based SoCs
-      - Allwinner A83T
-        + Datasheet
-          https://github.com/allwinner-zh/documents/raw/master/A83T/A83T_Datasheet_v1.3_20150510.pdf
-        + User Manual
-          https://github.com/allwinner-zh/documents/raw/master/A83T/A83T_User_Manual_v1.5.1_20150513.pdf
-
-    * Quad ARM Cortex-A53 based SoCs
-      - Allwinner A64
-        + Datasheet
-          http://dl.linux-sunxi.org/A64/A64_Datasheet_V1.1.pdf
-        + User Manual
-          http://dl.linux-sunxi.org/A64/Allwinner%20A64%20User%20Manual%20v1.0.pdf
diff --git a/Documentation/arm/sunxi/clocks.rst b/Documentation/arm/sunxi/clocks.rst
new file mode 100644 (file)
index 0000000..23bd03f
--- /dev/null
@@ -0,0 +1,57 @@
+=======================================================
+Frequently asked questions about the sunxi clock system
+=======================================================
+
+This document contains useful bits of information that people tend to ask
+about the sunxi clock system, as well as accompanying ASCII art when adequate.
+
+Q: Why is the main 24MHz oscillator gatable? Wouldn't that break the
+   system?
+
+A: The 24MHz oscillator allows gating to save power. Indeed, if gated
+   carelessly the system would stop functioning, but with the right
+   steps, one can gate it and keep the system running. Consider this
+   simplified suspend example:
+
+   While the system is operational, you would see something like::
+
+      24MHz         32kHz
+       |
+      PLL1
+       \
+        \_ CPU Mux
+             |
+           [CPU]
+
+   When you are about to suspend, you switch the CPU Mux to the 32kHz
+   oscillator::
+
+      24Mhz         32kHz
+       |              |
+      PLL1            |
+                     /
+           CPU Mux _/
+             |
+           [CPU]
+
+    Finally you can gate the main oscillator::
+
+                    32kHz
+                      |
+                      |
+                     /
+           CPU Mux _/
+             |
+           [CPU]
+
+Q: Were can I learn more about the sunxi clocks?
+
+A: The linux-sunxi wiki contains a page documenting the clock registers,
+   you can find it at
+
+        http://linux-sunxi.org/A10/CCM
+
+   The authoritative source for information at this time is the ccmu driver
+   released by Allwinner, you can find it at
+
+        https://github.com/linux-sunxi/linux-sunxi/tree/sunxi-3.0/arch/arm/mach-sun4i/clock/ccmu
diff --git a/Documentation/arm/sunxi/clocks.txt b/Documentation/arm/sunxi/clocks.txt
deleted file mode 100644 (file)
index e09a88a..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-Frequently asked questions about the sunxi clock system
-=======================================================
-
-This document contains useful bits of information that people tend to ask
-about the sunxi clock system, as well as accompanying ASCII art when adequate.
-
-Q: Why is the main 24MHz oscillator gatable? Wouldn't that break the
-   system?
-
-A: The 24MHz oscillator allows gating to save power. Indeed, if gated
-   carelessly the system would stop functioning, but with the right
-   steps, one can gate it and keep the system running. Consider this
-   simplified suspend example:
-
-   While the system is operational, you would see something like
-
-      24MHz         32kHz
-       |
-      PLL1
-       \
-        \_ CPU Mux
-             |
-           [CPU]
-
-   When you are about to suspend, you switch the CPU Mux to the 32kHz
-   oscillator:
-
-      24Mhz         32kHz
-       |              |
-      PLL1            |
-                     /
-           CPU Mux _/
-             |
-           [CPU]
-
-    Finally you can gate the main oscillator
-
-                    32kHz
-                      |
-                      |
-                     /
-           CPU Mux _/
-             |
-           [CPU]
-
-Q: Were can I learn more about the sunxi clocks?
-
-A: The linux-sunxi wiki contains a page documenting the clock registers,
-   you can find it at
-
-        http://linux-sunxi.org/A10/CCM
-
-   The authoritative source for information at this time is the ccmu driver
-   released by Allwinner, you can find it at
-
-        https://github.com/linux-sunxi/linux-sunxi/tree/sunxi-3.0/arch/arm/mach-sun4i/clock/ccmu
diff --git a/Documentation/arm/swp_emulation b/Documentation/arm/swp_emulation
deleted file mode 100644 (file)
index af903d2..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-Software emulation of deprecated SWP instruction (CONFIG_SWP_EMULATE)
----------------------------------------------------------------------
-
-ARMv6 architecture deprecates use of the SWP/SWPB instructions, and recommeds
-moving to the load-locked/store-conditional instructions LDREX and STREX.
-
-ARMv7 multiprocessing extensions introduce the ability to disable these
-instructions, triggering an undefined instruction exception when executed.
-Trapped instructions are emulated using an LDREX/STREX or LDREXB/STREXB
-sequence. If a memory access fault (an abort) occurs, a segmentation fault is
-signalled to the triggering process.
-
-/proc/cpu/swp_emulation holds some statistics/information, including the PID of
-the last process to trigger the emulation to be invocated. For example:
----
-Emulated SWP:          12
-Emulated SWPB:         0
-Aborted SWP{B}:                1
-Last process:          314
----
-
-NOTE: when accessing uncached shared regions, LDREX/STREX rely on an external
-transaction monitoring block called a global monitor to maintain update
-atomicity. If your system does not implement a global monitor, this option can
-cause programs that perform SWP operations to uncached memory to deadlock, as
-the STREX operation will always fail.
-
diff --git a/Documentation/arm/swp_emulation.rst b/Documentation/arm/swp_emulation.rst
new file mode 100644 (file)
index 0000000..6a608a9
--- /dev/null
@@ -0,0 +1,27 @@
+Software emulation of deprecated SWP instruction (CONFIG_SWP_EMULATE)
+---------------------------------------------------------------------
+
+ARMv6 architecture deprecates use of the SWP/SWPB instructions, and recommeds
+moving to the load-locked/store-conditional instructions LDREX and STREX.
+
+ARMv7 multiprocessing extensions introduce the ability to disable these
+instructions, triggering an undefined instruction exception when executed.
+Trapped instructions are emulated using an LDREX/STREX or LDREXB/STREXB
+sequence. If a memory access fault (an abort) occurs, a segmentation fault is
+signalled to the triggering process.
+
+/proc/cpu/swp_emulation holds some statistics/information, including the PID of
+the last process to trigger the emulation to be invocated. For example::
+
+  Emulated SWP:                12
+  Emulated SWPB:               0
+  Aborted SWP{B}:              1
+  Last process:                314
+
+
+NOTE:
+  when accessing uncached shared regions, LDREX/STREX rely on an external
+  transaction monitoring block called a global monitor to maintain update
+  atomicity. If your system does not implement a global monitor, this option can
+  cause programs that perform SWP operations to uncached memory to deadlock, as
+  the STREX operation will always fail.
diff --git a/Documentation/arm/tcm.rst b/Documentation/arm/tcm.rst
new file mode 100644 (file)
index 0000000..effd9c7
--- /dev/null
@@ -0,0 +1,161 @@
+==================================================
+ARM TCM (Tightly-Coupled Memory) handling in Linux
+==================================================
+
+Written by Linus Walleij <linus.walleij@stericsson.com>
+
+Some ARM SoC:s have a so-called TCM (Tightly-Coupled Memory).
+This is usually just a few (4-64) KiB of RAM inside the ARM
+processor.
+
+Due to being embedded inside the CPU The TCM has a
+Harvard-architecture, so there is an ITCM (instruction TCM)
+and a DTCM (data TCM). The DTCM can not contain any
+instructions, but the ITCM can actually contain data.
+The size of DTCM or ITCM is minimum 4KiB so the typical
+minimum configuration is 4KiB ITCM and 4KiB DTCM.
+
+ARM CPU:s have special registers to read out status, physical
+location and size of TCM memories. arch/arm/include/asm/cputype.h
+defines a CPUID_TCM register that you can read out from the
+system control coprocessor. Documentation from ARM can be found
+at http://infocenter.arm.com, search for "TCM Status Register"
+to see documents for all CPUs. Reading this register you can
+determine if ITCM (bits 1-0) and/or DTCM (bit 17-16) is present
+in the machine.
+
+There is further a TCM region register (search for "TCM Region
+Registers" at the ARM site) that can report and modify the location
+size of TCM memories at runtime. This is used to read out and modify
+TCM location and size. Notice that this is not a MMU table: you
+actually move the physical location of the TCM around. At the
+place you put it, it will mask any underlying RAM from the
+CPU so it is usually wise not to overlap any physical RAM with
+the TCM.
+
+The TCM memory can then be remapped to another address again using
+the MMU, but notice that the TCM if often used in situations where
+the MMU is turned off. To avoid confusion the current Linux
+implementation will map the TCM 1 to 1 from physical to virtual
+memory in the location specified by the kernel. Currently Linux
+will map ITCM to 0xfffe0000 and on, and DTCM to 0xfffe8000 and
+on, supporting a maximum of 32KiB of ITCM and 32KiB of DTCM.
+
+Newer versions of the region registers also support dividing these
+TCMs in two separate banks, so for example an 8KiB ITCM is divided
+into two 4KiB banks with its own control registers. The idea is to
+be able to lock and hide one of the banks for use by the secure
+world (TrustZone).
+
+TCM is used for a few things:
+
+- FIQ and other interrupt handlers that need deterministic
+  timing and cannot wait for cache misses.
+
+- Idle loops where all external RAM is set to self-refresh
+  retention mode, so only on-chip RAM is accessible by
+  the CPU and then we hang inside ITCM waiting for an
+  interrupt.
+
+- Other operations which implies shutting off or reconfiguring
+  the external RAM controller.
+
+There is an interface for using TCM on the ARM architecture
+in <asm/tcm.h>. Using this interface it is possible to:
+
+- Define the physical address and size of ITCM and DTCM.
+
+- Tag functions to be compiled into ITCM.
+
+- Tag data and constants to be allocated to DTCM and ITCM.
+
+- Have the remaining TCM RAM added to a special
+  allocation pool with gen_pool_create() and gen_pool_add()
+  and provice tcm_alloc() and tcm_free() for this
+  memory. Such a heap is great for things like saving
+  device state when shutting off device power domains.
+
+A machine that has TCM memory shall select HAVE_TCM from
+arch/arm/Kconfig for itself. Code that needs to use TCM shall
+#include <asm/tcm.h>
+
+Functions to go into itcm can be tagged like this:
+int __tcmfunc foo(int bar);
+
+Since these are marked to become long_calls and you may want
+to have functions called locally inside the TCM without
+wasting space, there is also the __tcmlocalfunc prefix that
+will make the call relative.
+
+Variables to go into dtcm can be tagged like this::
+
+  int __tcmdata foo;
+
+Constants can be tagged like this::
+
+  int __tcmconst foo;
+
+To put assembler into TCM just use::
+
+  .section ".tcm.text" or .section ".tcm.data"
+
+respectively.
+
+Example code::
+
+  #include <asm/tcm.h>
+
+  /* Uninitialized data */
+  static u32 __tcmdata tcmvar;
+  /* Initialized data */
+  static u32 __tcmdata tcmassigned = 0x2BADBABEU;
+  /* Constant */
+  static const u32 __tcmconst tcmconst = 0xCAFEBABEU;
+
+  static void __tcmlocalfunc tcm_to_tcm(void)
+  {
+       int i;
+       for (i = 0; i < 100; i++)
+               tcmvar ++;
+  }
+
+  static void __tcmfunc hello_tcm(void)
+  {
+       /* Some abstract code that runs in ITCM */
+       int i;
+       for (i = 0; i < 100; i++) {
+               tcmvar ++;
+       }
+       tcm_to_tcm();
+  }
+
+  static void __init test_tcm(void)
+  {
+       u32 *tcmem;
+       int i;
+
+       hello_tcm();
+       printk("Hello TCM executed from ITCM RAM\n");
+
+       printk("TCM variable from testrun: %u @ %p\n", tcmvar, &tcmvar);
+       tcmvar = 0xDEADBEEFU;
+       printk("TCM variable: 0x%x @ %p\n", tcmvar, &tcmvar);
+
+       printk("TCM assigned variable: 0x%x @ %p\n", tcmassigned, &tcmassigned);
+
+       printk("TCM constant: 0x%x @ %p\n", tcmconst, &tcmconst);
+
+       /* Allocate some TCM memory from the pool */
+       tcmem = tcm_alloc(20);
+       if (tcmem) {
+               printk("TCM Allocated 20 bytes of TCM @ %p\n", tcmem);
+               tcmem[0] = 0xDEADBEEFU;
+               tcmem[1] = 0x2BADBABEU;
+               tcmem[2] = 0xCAFEBABEU;
+               tcmem[3] = 0xDEADBEEFU;
+               tcmem[4] = 0x2BADBABEU;
+               for (i = 0; i < 5; i++)
+                       printk("TCM tcmem[%d] = %08x\n", i, tcmem[i]);
+               tcm_free(tcmem, 20);
+       }
+  }
diff --git a/Documentation/arm/tcm.txt b/Documentation/arm/tcm.txt
deleted file mode 100644 (file)
index 7c15871..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-ARM TCM (Tightly-Coupled Memory) handling in Linux
-----
-Written by Linus Walleij <linus.walleij@stericsson.com>
-
-Some ARM SoC:s have a so-called TCM (Tightly-Coupled Memory).
-This is usually just a few (4-64) KiB of RAM inside the ARM
-processor.
-
-Due to being embedded inside the CPU The TCM has a
-Harvard-architecture, so there is an ITCM (instruction TCM)
-and a DTCM (data TCM). The DTCM can not contain any
-instructions, but the ITCM can actually contain data.
-The size of DTCM or ITCM is minimum 4KiB so the typical
-minimum configuration is 4KiB ITCM and 4KiB DTCM.
-
-ARM CPU:s have special registers to read out status, physical
-location and size of TCM memories. arch/arm/include/asm/cputype.h
-defines a CPUID_TCM register that you can read out from the
-system control coprocessor. Documentation from ARM can be found
-at http://infocenter.arm.com, search for "TCM Status Register"
-to see documents for all CPUs. Reading this register you can
-determine if ITCM (bits 1-0) and/or DTCM (bit 17-16) is present
-in the machine.
-
-There is further a TCM region register (search for "TCM Region
-Registers" at the ARM site) that can report and modify the location
-size of TCM memories at runtime. This is used to read out and modify
-TCM location and size. Notice that this is not a MMU table: you
-actually move the physical location of the TCM around. At the
-place you put it, it will mask any underlying RAM from the
-CPU so it is usually wise not to overlap any physical RAM with
-the TCM.
-
-The TCM memory can then be remapped to another address again using
-the MMU, but notice that the TCM if often used in situations where
-the MMU is turned off. To avoid confusion the current Linux
-implementation will map the TCM 1 to 1 from physical to virtual
-memory in the location specified by the kernel. Currently Linux
-will map ITCM to 0xfffe0000 and on, and DTCM to 0xfffe8000 and
-on, supporting a maximum of 32KiB of ITCM and 32KiB of DTCM.
-
-Newer versions of the region registers also support dividing these
-TCMs in two separate banks, so for example an 8KiB ITCM is divided
-into two 4KiB banks with its own control registers. The idea is to
-be able to lock and hide one of the banks for use by the secure
-world (TrustZone).
-
-TCM is used for a few things:
-
-- FIQ and other interrupt handlers that need deterministic
-  timing and cannot wait for cache misses.
-
-- Idle loops where all external RAM is set to self-refresh
-  retention mode, so only on-chip RAM is accessible by
-  the CPU and then we hang inside ITCM waiting for an
-  interrupt.
-
-- Other operations which implies shutting off or reconfiguring
-  the external RAM controller.
-
-There is an interface for using TCM on the ARM architecture
-in <asm/tcm.h>. Using this interface it is possible to:
-
-- Define the physical address and size of ITCM and DTCM.
-
-- Tag functions to be compiled into ITCM.
-
-- Tag data and constants to be allocated to DTCM and ITCM.
-
-- Have the remaining TCM RAM added to a special
-  allocation pool with gen_pool_create() and gen_pool_add()
-  and provice tcm_alloc() and tcm_free() for this
-  memory. Such a heap is great for things like saving
-  device state when shutting off device power domains.
-
-A machine that has TCM memory shall select HAVE_TCM from
-arch/arm/Kconfig for itself. Code that needs to use TCM shall
-#include <asm/tcm.h>
-
-Functions to go into itcm can be tagged like this:
-int __tcmfunc foo(int bar);
-
-Since these are marked to become long_calls and you may want
-to have functions called locally inside the TCM without
-wasting space, there is also the __tcmlocalfunc prefix that
-will make the call relative.
-
-Variables to go into dtcm can be tagged like this:
-int __tcmdata foo;
-
-Constants can be tagged like this:
-int __tcmconst foo;
-
-To put assembler into TCM just use
-.section ".tcm.text" or .section ".tcm.data"
-respectively.
-
-Example code:
-
-#include <asm/tcm.h>
-
-/* Uninitialized data */
-static u32 __tcmdata tcmvar;
-/* Initialized data */
-static u32 __tcmdata tcmassigned = 0x2BADBABEU;
-/* Constant */
-static const u32 __tcmconst tcmconst = 0xCAFEBABEU;
-
-static void __tcmlocalfunc tcm_to_tcm(void)
-{
-       int i;
-       for (i = 0; i < 100; i++)
-               tcmvar ++;
-}
-
-static void __tcmfunc hello_tcm(void)
-{
-       /* Some abstract code that runs in ITCM */
-       int i;
-       for (i = 0; i < 100; i++) {
-               tcmvar ++;
-       }
-       tcm_to_tcm();
-}
-
-static void __init test_tcm(void)
-{
-       u32 *tcmem;
-       int i;
-
-       hello_tcm();
-       printk("Hello TCM executed from ITCM RAM\n");
-
-       printk("TCM variable from testrun: %u @ %p\n", tcmvar, &tcmvar);
-       tcmvar = 0xDEADBEEFU;
-       printk("TCM variable: 0x%x @ %p\n", tcmvar, &tcmvar);
-
-       printk("TCM assigned variable: 0x%x @ %p\n", tcmassigned, &tcmassigned);
-
-       printk("TCM constant: 0x%x @ %p\n", tcmconst, &tcmconst);
-
-       /* Allocate some TCM memory from the pool */
-       tcmem = tcm_alloc(20);
-       if (tcmem) {
-               printk("TCM Allocated 20 bytes of TCM @ %p\n", tcmem);
-               tcmem[0] = 0xDEADBEEFU;
-               tcmem[1] = 0x2BADBABEU;
-               tcmem[2] = 0xCAFEBABEU;
-               tcmem[3] = 0xDEADBEEFU;
-               tcmem[4] = 0x2BADBABEU;
-               for (i = 0; i < 5; i++)
-                       printk("TCM tcmem[%d] = %08x\n", i, tcmem[i]);
-               tcm_free(tcmem, 20);
-       }
-}
diff --git a/Documentation/arm/uefi.rst b/Documentation/arm/uefi.rst
new file mode 100644 (file)
index 0000000..f868330
--- /dev/null
@@ -0,0 +1,67 @@
+================================================
+The Unified Extensible Firmware Interface (UEFI)
+================================================
+
+UEFI, the Unified Extensible Firmware Interface, is a specification
+governing the behaviours of compatible firmware interfaces. It is
+maintained by the UEFI Forum - http://www.uefi.org/.
+
+UEFI is an evolution of its predecessor 'EFI', so the terms EFI and
+UEFI are used somewhat interchangeably in this document and associated
+source code. As a rule, anything new uses 'UEFI', whereas 'EFI' refers
+to legacy code or specifications.
+
+UEFI support in Linux
+=====================
+Booting on a platform with firmware compliant with the UEFI specification
+makes it possible for the kernel to support additional features:
+
+- UEFI Runtime Services
+- Retrieving various configuration information through the standardised
+  interface of UEFI configuration tables. (ACPI, SMBIOS, ...)
+
+For actually enabling [U]EFI support, enable:
+
+- CONFIG_EFI=y
+- CONFIG_EFI_VARS=y or m
+
+The implementation depends on receiving information about the UEFI environment
+in a Flattened Device Tree (FDT) - so is only available with CONFIG_OF.
+
+UEFI stub
+=========
+The "stub" is a feature that extends the Image/zImage into a valid UEFI
+PE/COFF executable, including a loader application that makes it possible to
+load the kernel directly from the UEFI shell, boot menu, or one of the
+lightweight bootloaders like Gummiboot or rEFInd.
+
+The kernel image built with stub support remains a valid kernel image for
+booting in non-UEFI environments.
+
+UEFI kernel support on ARM
+==========================
+UEFI kernel support on the ARM architectures (arm and arm64) is only available
+when boot is performed through the stub.
+
+When booting in UEFI mode, the stub deletes any memory nodes from a provided DT.
+Instead, the kernel reads the UEFI memory map.
+
+The stub populates the FDT /chosen node with (and the kernel scans for) the
+following parameters:
+
+==========================  ======   ===========================================
+Name                        Size     Description
+==========================  ======   ===========================================
+linux,uefi-system-table     64-bit   Physical address of the UEFI System Table.
+
+linux,uefi-mmap-start       64-bit   Physical address of the UEFI memory map,
+                                     populated by the UEFI GetMemoryMap() call.
+
+linux,uefi-mmap-size        32-bit   Size in bytes of the UEFI memory map
+                                     pointed to in previous entry.
+
+linux,uefi-mmap-desc-size   32-bit   Size in bytes of each entry in the UEFI
+                                     memory map.
+
+linux,uefi-mmap-desc-ver    32-bit   Version of the mmap descriptor format.
+==========================  ======   ===========================================
diff --git a/Documentation/arm/uefi.txt b/Documentation/arm/uefi.txt
deleted file mode 100644 (file)
index 6543a0a..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-UEFI, the Unified Extensible Firmware Interface, is a specification
-governing the behaviours of compatible firmware interfaces. It is
-maintained by the UEFI Forum - http://www.uefi.org/.
-
-UEFI is an evolution of its predecessor 'EFI', so the terms EFI and
-UEFI are used somewhat interchangeably in this document and associated
-source code. As a rule, anything new uses 'UEFI', whereas 'EFI' refers
-to legacy code or specifications.
-
-UEFI support in Linux
-=====================
-Booting on a platform with firmware compliant with the UEFI specification
-makes it possible for the kernel to support additional features:
-- UEFI Runtime Services
-- Retrieving various configuration information through the standardised
-  interface of UEFI configuration tables. (ACPI, SMBIOS, ...)
-
-For actually enabling [U]EFI support, enable:
-- CONFIG_EFI=y
-- CONFIG_EFI_VARS=y or m
-
-The implementation depends on receiving information about the UEFI environment
-in a Flattened Device Tree (FDT) - so is only available with CONFIG_OF.
-
-UEFI stub
-=========
-The "stub" is a feature that extends the Image/zImage into a valid UEFI
-PE/COFF executable, including a loader application that makes it possible to
-load the kernel directly from the UEFI shell, boot menu, or one of the
-lightweight bootloaders like Gummiboot or rEFInd.
-
-The kernel image built with stub support remains a valid kernel image for
-booting in non-UEFI environments.
-
-UEFI kernel support on ARM
-==========================
-UEFI kernel support on the ARM architectures (arm and arm64) is only available
-when boot is performed through the stub.
-
-When booting in UEFI mode, the stub deletes any memory nodes from a provided DT.
-Instead, the kernel reads the UEFI memory map.
-
-The stub populates the FDT /chosen node with (and the kernel scans for) the
-following parameters:
-________________________________________________________________________________
-Name                      | Size   | Description
-================================================================================
-linux,uefi-system-table   | 64-bit | Physical address of the UEFI System Table.
---------------------------------------------------------------------------------
-linux,uefi-mmap-start     | 64-bit | Physical address of the UEFI memory map,
-                          |        | populated by the UEFI GetMemoryMap() call.
---------------------------------------------------------------------------------
-linux,uefi-mmap-size      | 32-bit | Size in bytes of the UEFI memory map
-                          |        | pointed to in previous entry.
---------------------------------------------------------------------------------
-linux,uefi-mmap-desc-size | 32-bit | Size in bytes of each entry in the UEFI
-                          |        | memory map.
---------------------------------------------------------------------------------
-linux,uefi-mmap-desc-ver  | 32-bit | Version of the mmap descriptor format.
---------------------------------------------------------------------------------
diff --git a/Documentation/arm/vfp/release-notes.rst b/Documentation/arm/vfp/release-notes.rst
new file mode 100644 (file)
index 0000000..c6b0493
--- /dev/null
@@ -0,0 +1,57 @@
+===============================================
+Release notes for Linux Kernel VFP support code
+===============================================
+
+Date:  20 May 2004
+
+Author:        Russell King
+
+This is the first release of the Linux Kernel VFP support code.  It
+provides support for the exceptions bounced from VFP hardware found
+on ARM926EJ-S.
+
+This release has been validated against the SoftFloat-2b library by
+John R. Hauser using the TestFloat-2a test suite.  Details of this
+library and test suite can be found at:
+
+   http://www.jhauser.us/arithmetic/SoftFloat.html
+
+The operations which have been tested with this package are:
+
+ - fdiv
+ - fsub
+ - fadd
+ - fmul
+ - fcmp
+ - fcmpe
+ - fcvtd
+ - fcvts
+ - fsito
+ - ftosi
+ - fsqrt
+
+All the above pass softfloat tests with the following exceptions:
+
+- fadd/fsub shows some differences in the handling of +0 / -0 results
+  when input operands differ in signs.
+- the handling of underflow exceptions is slightly different.  If a
+  result underflows before rounding, but becomes a normalised number
+  after rounding, we do not signal an underflow exception.
+
+Other operations which have been tested by basic assembly-only tests
+are:
+
+ - fcpy
+ - fabs
+ - fneg
+ - ftoui
+ - ftosiz
+ - ftouiz
+
+The combination operations have not been tested:
+
+ - fmac
+ - fnmac
+ - fmsc
+ - fnmsc
+ - fnmul
diff --git a/Documentation/arm/vlocks.rst b/Documentation/arm/vlocks.rst
new file mode 100644 (file)
index 0000000..a40a174
--- /dev/null
@@ -0,0 +1,212 @@
+======================================
+vlocks for Bare-Metal Mutual Exclusion
+======================================
+
+Voting Locks, or "vlocks" provide a simple low-level mutual exclusion
+mechanism, with reasonable but minimal requirements on the memory
+system.
+
+These are intended to be used to coordinate critical activity among CPUs
+which are otherwise non-coherent, in situations where the hardware
+provides no other mechanism to support this and ordinary spinlocks
+cannot be used.
+
+
+vlocks make use of the atomicity provided by the memory system for
+writes to a single memory location.  To arbitrate, every CPU "votes for
+itself", by storing a unique number to a common memory location.  The
+final value seen in that memory location when all the votes have been
+cast identifies the winner.
+
+In order to make sure that the election produces an unambiguous result
+in finite time, a CPU will only enter the election in the first place if
+no winner has been chosen and the election does not appear to have
+started yet.
+
+
+Algorithm
+---------
+
+The easiest way to explain the vlocks algorithm is with some pseudo-code::
+
+
+       int currently_voting[NR_CPUS] = { 0, };
+       int last_vote = -1; /* no votes yet */
+
+       bool vlock_trylock(int this_cpu)
+       {
+               /* signal our desire to vote */
+               currently_voting[this_cpu] = 1;
+               if (last_vote != -1) {
+                       /* someone already volunteered himself */
+                       currently_voting[this_cpu] = 0;
+                       return false; /* not ourself */
+               }
+
+               /* let's suggest ourself */
+               last_vote = this_cpu;
+               currently_voting[this_cpu] = 0;
+
+               /* then wait until everyone else is done voting */
+               for_each_cpu(i) {
+                       while (currently_voting[i] != 0)
+                               /* wait */;
+               }
+
+               /* result */
+               if (last_vote == this_cpu)
+                       return true; /* we won */
+               return false;
+       }
+
+       bool vlock_unlock(void)
+       {
+               last_vote = -1;
+       }
+
+
+The currently_voting[] array provides a way for the CPUs to determine
+whether an election is in progress, and plays a role analogous to the
+"entering" array in Lamport's bakery algorithm [1].
+
+However, once the election has started, the underlying memory system
+atomicity is used to pick the winner.  This avoids the need for a static
+priority rule to act as a tie-breaker, or any counters which could
+overflow.
+
+As long as the last_vote variable is globally visible to all CPUs, it
+will contain only one value that won't change once every CPU has cleared
+its currently_voting flag.
+
+
+Features and limitations
+------------------------
+
+ * vlocks are not intended to be fair.  In the contended case, it is the
+   _last_ CPU which attempts to get the lock which will be most likely
+   to win.
+
+   vlocks are therefore best suited to situations where it is necessary
+   to pick a unique winner, but it does not matter which CPU actually
+   wins.
+
+ * Like other similar mechanisms, vlocks will not scale well to a large
+   number of CPUs.
+
+   vlocks can be cascaded in a voting hierarchy to permit better scaling
+   if necessary, as in the following hypothetical example for 4096 CPUs::
+
+       /* first level: local election */
+       my_town = towns[(this_cpu >> 4) & 0xf];
+       I_won = vlock_trylock(my_town, this_cpu & 0xf);
+       if (I_won) {
+               /* we won the town election, let's go for the state */
+               my_state = states[(this_cpu >> 8) & 0xf];
+               I_won = vlock_lock(my_state, this_cpu & 0xf));
+               if (I_won) {
+                       /* and so on */
+                       I_won = vlock_lock(the_whole_country, this_cpu & 0xf];
+                       if (I_won) {
+                               /* ... */
+                       }
+                       vlock_unlock(the_whole_country);
+               }
+               vlock_unlock(my_state);
+       }
+       vlock_unlock(my_town);
+
+
+ARM implementation
+------------------
+
+The current ARM implementation [2] contains some optimisations beyond
+the basic algorithm:
+
+ * By packing the members of the currently_voting array close together,
+   we can read the whole array in one transaction (providing the number
+   of CPUs potentially contending the lock is small enough).  This
+   reduces the number of round-trips required to external memory.
+
+   In the ARM implementation, this means that we can use a single load
+   and comparison::
+
+       LDR     Rt, [Rn]
+       CMP     Rt, #0
+
+   ...in place of code equivalent to::
+
+       LDRB    Rt, [Rn]
+       CMP     Rt, #0
+       LDRBEQ  Rt, [Rn, #1]
+       CMPEQ   Rt, #0
+       LDRBEQ  Rt, [Rn, #2]
+       CMPEQ   Rt, #0
+       LDRBEQ  Rt, [Rn, #3]
+       CMPEQ   Rt, #0
+
+   This cuts down on the fast-path latency, as well as potentially
+   reducing bus contention in contended cases.
+
+   The optimisation relies on the fact that the ARM memory system
+   guarantees coherency between overlapping memory accesses of
+   different sizes, similarly to many other architectures.  Note that
+   we do not care which element of currently_voting appears in which
+   bits of Rt, so there is no need to worry about endianness in this
+   optimisation.
+
+   If there are too many CPUs to read the currently_voting array in
+   one transaction then multiple transations are still required.  The
+   implementation uses a simple loop of word-sized loads for this
+   case.  The number of transactions is still fewer than would be
+   required if bytes were loaded individually.
+
+
+   In principle, we could aggregate further by using LDRD or LDM, but
+   to keep the code simple this was not attempted in the initial
+   implementation.
+
+
+ * vlocks are currently only used to coordinate between CPUs which are
+   unable to enable their caches yet.  This means that the
+   implementation removes many of the barriers which would be required
+   when executing the algorithm in cached memory.
+
+   packing of the currently_voting array does not work with cached
+   memory unless all CPUs contending the lock are cache-coherent, due
+   to cache writebacks from one CPU clobbering values written by other
+   CPUs.  (Though if all the CPUs are cache-coherent, you should be
+   probably be using proper spinlocks instead anyway).
+
+
+ * The "no votes yet" value used for the last_vote variable is 0 (not
+   -1 as in the pseudocode).  This allows statically-allocated vlocks
+   to be implicitly initialised to an unlocked state simply by putting
+   them in .bss.
+
+   An offset is added to each CPU's ID for the purpose of setting this
+   variable, so that no CPU uses the value 0 for its ID.
+
+
+Colophon
+--------
+
+Originally created and documented by Dave Martin for Linaro Limited, for
+use in ARM-based big.LITTLE platforms, with review and input gratefully
+received from Nicolas Pitre and Achin Gupta.  Thanks to Nicolas for
+grabbing most of this text out of the relevant mail thread and writing
+up the pseudocode.
+
+Copyright (C) 2012-2013  Linaro Limited
+Distributed under the terms of Version 2 of the GNU General Public
+License, as defined in linux/COPYING.
+
+
+References
+----------
+
+[1] Lamport, L. "A New Solution of Dijkstra's Concurrent Programming
+    Problem", Communications of the ACM 17, 8 (August 1974), 453-455.
+
+    https://en.wikipedia.org/wiki/Lamport%27s_bakery_algorithm
+
+[2] linux/arch/arm/common/vlock.S, www.kernel.org.
diff --git a/Documentation/arm/vlocks.txt b/Documentation/arm/vlocks.txt
deleted file mode 100644 (file)
index 4573167..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-vlocks for Bare-Metal Mutual Exclusion
-======================================
-
-Voting Locks, or "vlocks" provide a simple low-level mutual exclusion
-mechanism, with reasonable but minimal requirements on the memory
-system.
-
-These are intended to be used to coordinate critical activity among CPUs
-which are otherwise non-coherent, in situations where the hardware
-provides no other mechanism to support this and ordinary spinlocks
-cannot be used.
-
-
-vlocks make use of the atomicity provided by the memory system for
-writes to a single memory location.  To arbitrate, every CPU "votes for
-itself", by storing a unique number to a common memory location.  The
-final value seen in that memory location when all the votes have been
-cast identifies the winner.
-
-In order to make sure that the election produces an unambiguous result
-in finite time, a CPU will only enter the election in the first place if
-no winner has been chosen and the election does not appear to have
-started yet.
-
-
-Algorithm
----------
-
-The easiest way to explain the vlocks algorithm is with some pseudo-code:
-
-
-       int currently_voting[NR_CPUS] = { 0, };
-       int last_vote = -1; /* no votes yet */
-
-       bool vlock_trylock(int this_cpu)
-       {
-               /* signal our desire to vote */
-               currently_voting[this_cpu] = 1;
-               if (last_vote != -1) {
-                       /* someone already volunteered himself */
-                       currently_voting[this_cpu] = 0;
-                       return false; /* not ourself */
-               }
-
-               /* let's suggest ourself */
-               last_vote = this_cpu;
-               currently_voting[this_cpu] = 0;
-
-               /* then wait until everyone else is done voting */
-               for_each_cpu(i) {
-                       while (currently_voting[i] != 0)
-                               /* wait */;
-               }
-
-               /* result */
-               if (last_vote == this_cpu)
-                       return true; /* we won */
-               return false;
-       }
-
-       bool vlock_unlock(void)
-       {
-               last_vote = -1;
-       }
-
-
-The currently_voting[] array provides a way for the CPUs to determine
-whether an election is in progress, and plays a role analogous to the
-"entering" array in Lamport's bakery algorithm [1].
-
-However, once the election has started, the underlying memory system
-atomicity is used to pick the winner.  This avoids the need for a static
-priority rule to act as a tie-breaker, or any counters which could
-overflow.
-
-As long as the last_vote variable is globally visible to all CPUs, it
-will contain only one value that won't change once every CPU has cleared
-its currently_voting flag.
-
-
-Features and limitations
-------------------------
-
- * vlocks are not intended to be fair.  In the contended case, it is the
-   _last_ CPU which attempts to get the lock which will be most likely
-   to win.
-
-   vlocks are therefore best suited to situations where it is necessary
-   to pick a unique winner, but it does not matter which CPU actually
-   wins.
-
- * Like other similar mechanisms, vlocks will not scale well to a large
-   number of CPUs.
-
-   vlocks can be cascaded in a voting hierarchy to permit better scaling
-   if necessary, as in the following hypothetical example for 4096 CPUs:
-
-       /* first level: local election */
-       my_town = towns[(this_cpu >> 4) & 0xf];
-       I_won = vlock_trylock(my_town, this_cpu & 0xf);
-       if (I_won) {
-               /* we won the town election, let's go for the state */
-               my_state = states[(this_cpu >> 8) & 0xf];
-               I_won = vlock_lock(my_state, this_cpu & 0xf));
-               if (I_won) {
-                       /* and so on */
-                       I_won = vlock_lock(the_whole_country, this_cpu & 0xf];
-                       if (I_won) {
-                               /* ... */
-                       }
-                       vlock_unlock(the_whole_country);
-               }
-               vlock_unlock(my_state);
-       }
-       vlock_unlock(my_town);
-
-
-ARM implementation
-------------------
-
-The current ARM implementation [2] contains some optimisations beyond
-the basic algorithm:
-
- * By packing the members of the currently_voting array close together,
-   we can read the whole array in one transaction (providing the number
-   of CPUs potentially contending the lock is small enough).  This
-   reduces the number of round-trips required to external memory.
-
-   In the ARM implementation, this means that we can use a single load
-   and comparison:
-
-       LDR     Rt, [Rn]
-       CMP     Rt, #0
-
-   ...in place of code equivalent to:
-
-       LDRB    Rt, [Rn]
-       CMP     Rt, #0
-       LDRBEQ  Rt, [Rn, #1]
-       CMPEQ   Rt, #0
-       LDRBEQ  Rt, [Rn, #2]
-       CMPEQ   Rt, #0
-       LDRBEQ  Rt, [Rn, #3]
-       CMPEQ   Rt, #0
-
-   This cuts down on the fast-path latency, as well as potentially
-   reducing bus contention in contended cases.
-
-   The optimisation relies on the fact that the ARM memory system
-   guarantees coherency between overlapping memory accesses of
-   different sizes, similarly to many other architectures.  Note that
-   we do not care which element of currently_voting appears in which
-   bits of Rt, so there is no need to worry about endianness in this
-   optimisation.
-
-   If there are too many CPUs to read the currently_voting array in
-   one transaction then multiple transations are still required.  The
-   implementation uses a simple loop of word-sized loads for this
-   case.  The number of transactions is still fewer than would be
-   required if bytes were loaded individually.
-
-
-   In principle, we could aggregate further by using LDRD or LDM, but
-   to keep the code simple this was not attempted in the initial
-   implementation.
-
-
- * vlocks are currently only used to coordinate between CPUs which are
-   unable to enable their caches yet.  This means that the
-   implementation removes many of the barriers which would be required
-   when executing the algorithm in cached memory.
-
-   packing of the currently_voting array does not work with cached
-   memory unless all CPUs contending the lock are cache-coherent, due
-   to cache writebacks from one CPU clobbering values written by other
-   CPUs.  (Though if all the CPUs are cache-coherent, you should be
-   probably be using proper spinlocks instead anyway).
-
-
- * The "no votes yet" value used for the last_vote variable is 0 (not
-   -1 as in the pseudocode).  This allows statically-allocated vlocks
-   to be implicitly initialised to an unlocked state simply by putting
-   them in .bss.
-
-   An offset is added to each CPU's ID for the purpose of setting this
-   variable, so that no CPU uses the value 0 for its ID.
-
-
-Colophon
---------
-
-Originally created and documented by Dave Martin for Linaro Limited, for
-use in ARM-based big.LITTLE platforms, with review and input gratefully
-received from Nicolas Pitre and Achin Gupta.  Thanks to Nicolas for
-grabbing most of this text out of the relevant mail thread and writing
-up the pseudocode.
-
-Copyright (C) 2012-2013  Linaro Limited
-Distributed under the terms of Version 2 of the GNU General Public
-License, as defined in linux/COPYING.
-
-
-References
-----------
-
-[1] Lamport, L. "A New Solution of Dijkstra's Concurrent Programming
-    Problem", Communications of the ACM 17, 8 (August 1974), 453-455.
-
-    https://en.wikipedia.org/wiki/Lamport%27s_bakery_algorithm
-
-[2] linux/arch/arm/common/vlock.S, www.kernel.org.
index 018b783..96b696b 100644 (file)
@@ -1,5 +1,3 @@
-:orphan:
-
 ==================
 ARM64 Architecture
 ==================
diff --git a/Documentation/auxdisplay/lcd-panel-cgram.txt b/Documentation/auxdisplay/lcd-panel-cgram.txt
deleted file mode 100644 (file)
index 7f82c90..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-Some LCDs allow you to define up to 8 characters, mapped to ASCII
-characters 0 to 7. The escape code to define a new character is
-'\e[LG' followed by one digit from 0 to 7, representing the character
-number, and up to 8 couples of hex digits terminated by a semi-colon
-(';'). Each couple of digits represents a line, with 1-bits for each
-illuminated pixel with LSB on the right. Lines are numbered from the
-top of the character to the bottom. On a 5x7 matrix, only the 5 lower
-bits of the 7 first bytes are used for each character. If the string
-is incomplete, only complete lines will be redefined. Here are some
-examples :
-
-  printf "\e[LG0010101050D1F0C04;"  => 0 = [enter]
-  printf "\e[LG1040E1F0000000000;"  => 1 = [up]
-  printf "\e[LG2000000001F0E0400;"  => 2 = [down]
-  printf "\e[LG3040E1F001F0E0400;"  => 3 = [up-down]
-  printf "\e[LG40002060E1E0E0602;"  => 4 = [left]
-  printf "\e[LG500080C0E0F0E0C08;"  => 5 = [right]
-  printf "\e[LG60016051516141400;"  => 6 = "IP"
-
-  printf "\e[LG00103071F1F070301;"  => big speaker
-  printf "\e[LG00002061E1E060200;"  => small speaker
-
-Willy
-
diff --git a/Documentation/backlight/lp855x-driver.txt b/Documentation/backlight/lp855x-driver.txt
deleted file mode 100644 (file)
index 01bce24..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-Kernel driver lp855x
-====================
-
-Backlight driver for LP855x ICs
-
-Supported chips:
-       Texas Instruments LP8550, LP8551, LP8552, LP8553, LP8555, LP8556 and
-       LP8557
-
-Author: Milo(Woogyom) Kim <milo.kim@ti.com>
-
-Description
------------
-
-* Brightness control
-
-Brightness can be controlled by the pwm input or the i2c command.
-The lp855x driver supports both cases.
-
-* Device attributes
-
-1) bl_ctl_mode
-Backlight control mode.
-Value : pwm based or register based
-
-2) chip_id
-The lp855x chip id.
-Value : lp8550/lp8551/lp8552/lp8553/lp8555/lp8556/lp8557
-
-Platform data for lp855x
-------------------------
-
-For supporting platform specific data, the lp855x platform data can be used.
-
-* name : Backlight driver name. If it is not defined, default name is set.
-* device_control : Value of DEVICE CONTROL register.
-* initial_brightness : Initial value of backlight brightness.
-* period_ns : Platform specific PWM period value. unit is nano.
-            Only valid when brightness is pwm input mode.
-* size_program : Total size of lp855x_rom_data.
-* rom_data : List of new eeprom/eprom registers.
-
-example 1) lp8552 platform data : i2c register mode with new eeprom data
-
-#define EEPROM_A5_ADDR 0xA5
-#define EEPROM_A5_VAL  0x4f    /* EN_VSYNC=0 */
-
-static struct lp855x_rom_data lp8552_eeprom_arr[] = {
-       {EEPROM_A5_ADDR, EEPROM_A5_VAL},
-};
-
-static struct lp855x_platform_data lp8552_pdata = {
-       .name = "lcd-bl",
-       .device_control = I2C_CONFIG(LP8552),
-       .initial_brightness = INITIAL_BRT,
-       .size_program = ARRAY_SIZE(lp8552_eeprom_arr),
-       .rom_data = lp8552_eeprom_arr,
-};
-
-example 2) lp8556 platform data : pwm input mode with default rom data
-
-static struct lp855x_platform_data lp8556_pdata = {
-       .device_control = PWM_CONFIG(LP8556),
-       .initial_brightness = INITIAL_BRT,
-       .period_ns = 1000000,
-};
diff --git a/Documentation/block/bfq-iosched.rst b/Documentation/block/bfq-iosched.rst
new file mode 100644 (file)
index 0000000..0d237d4
--- /dev/null
@@ -0,0 +1,597 @@
+==========================
+BFQ (Budget Fair Queueing)
+==========================
+
+BFQ is a proportional-share I/O scheduler, with some extra
+low-latency capabilities. In addition to cgroups support (blkio or io
+controllers), BFQ's main features are:
+
+- BFQ guarantees a high system and application responsiveness, and a
+  low latency for time-sensitive applications, such as audio or video
+  players;
+- BFQ distributes bandwidth, and not just time, among processes or
+  groups (switching back to time distribution when needed to keep
+  throughput high).
+
+In its default configuration, BFQ privileges latency over
+throughput. So, when needed for achieving a lower latency, BFQ builds
+schedules that may lead to a lower throughput. If your main or only
+goal, for a given device, is to achieve the maximum-possible
+throughput at all times, then do switch off all low-latency heuristics
+for that device, by setting low_latency to 0. See Section 3 for
+details on how to configure BFQ for the desired tradeoff between
+latency and throughput, or on how to maximize throughput.
+
+As every I/O scheduler, BFQ adds some overhead to per-I/O-request
+processing. To give an idea of this overhead, the total,
+single-lock-protected, per-request processing time of BFQ---i.e., the
+sum of the execution times of the request insertion, dispatch and
+completion hooks---is, e.g., 1.9 us on an Intel Core i7-2760QM@2.40GHz
+(dated CPU for notebooks; time measured with simple code
+instrumentation, and using the throughput-sync.sh script of the S
+suite [1], in performance-profiling mode). To put this result into
+context, the total, single-lock-protected, per-request execution time
+of the lightest I/O scheduler available in blk-mq, mq-deadline, is 0.7
+us (mq-deadline is ~800 LOC, against ~10500 LOC for BFQ).
+
+Scheduling overhead further limits the maximum IOPS that a CPU can
+process (already limited by the execution of the rest of the I/O
+stack). To give an idea of the limits with BFQ, on slow or average
+CPUs, here are, first, the limits of BFQ for three different CPUs, on,
+respectively, an average laptop, an old desktop, and a cheap embedded
+system, in case full hierarchical support is enabled (i.e.,
+CONFIG_BFQ_GROUP_IOSCHED is set), but CONFIG_BFQ_CGROUP_DEBUG is not
+set (Section 4-2):
+- Intel i7-4850HQ: 400 KIOPS
+- AMD A8-3850: 250 KIOPS
+- ARM CortexTM-A53 Octa-core: 80 KIOPS
+
+If CONFIG_BFQ_CGROUP_DEBUG is set (and of course full hierarchical
+support is enabled), then the sustainable throughput with BFQ
+decreases, because all blkio.bfq* statistics are created and updated
+(Section 4-2). For BFQ, this leads to the following maximum
+sustainable throughputs, on the same systems as above:
+- Intel i7-4850HQ: 310 KIOPS
+- AMD A8-3850: 200 KIOPS
+- ARM CortexTM-A53 Octa-core: 56 KIOPS
+
+BFQ works for multi-queue devices too.
+
+.. The table of contents follow. Impatients can just jump to Section 3.
+
+.. CONTENTS
+
+   1. When may BFQ be useful?
+    1-1 Personal systems
+    1-2 Server systems
+   2. How does BFQ work?
+   3. What are BFQ's tunables and how to properly configure BFQ?
+   4. BFQ group scheduling
+    4-1 Service guarantees provided
+    4-2 Interface
+
+1. When may BFQ be useful?
+==========================
+
+BFQ provides the following benefits on personal and server systems.
+
+1-1 Personal systems
+--------------------
+
+Low latency for interactive applications
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Regardless of the actual background workload, BFQ guarantees that, for
+interactive tasks, the storage device is virtually as responsive as if
+it was idle. For example, even if one or more of the following
+background workloads are being executed:
+
+- one or more large files are being read, written or copied,
+- a tree of source files is being compiled,
+- one or more virtual machines are performing I/O,
+- a software update is in progress,
+- indexing daemons are scanning filesystems and updating their
+  databases,
+
+starting an application or loading a file from within an application
+takes about the same time as if the storage device was idle. As a
+comparison, with CFQ, NOOP or DEADLINE, and in the same conditions,
+applications experience high latencies, or even become unresponsive
+until the background workload terminates (also on SSDs).
+
+Low latency for soft real-time applications
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Also soft real-time applications, such as audio and video
+players/streamers, enjoy a low latency and a low drop rate, regardless
+of the background I/O workload. As a consequence, these applications
+do not suffer from almost any glitch due to the background workload.
+
+Higher speed for code-development tasks
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If some additional workload happens to be executed in parallel, then
+BFQ executes the I/O-related components of typical code-development
+tasks (compilation, checkout, merge, ...) much more quickly than CFQ,
+NOOP or DEADLINE.
+
+High throughput
+^^^^^^^^^^^^^^^
+
+On hard disks, BFQ achieves up to 30% higher throughput than CFQ, and
+up to 150% higher throughput than DEADLINE and NOOP, with all the
+sequential workloads considered in our tests. With random workloads,
+and with all the workloads on flash-based devices, BFQ achieves,
+instead, about the same throughput as the other schedulers.
+
+Strong fairness, bandwidth and delay guarantees
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+BFQ distributes the device throughput, and not just the device time,
+among I/O-bound applications in proportion their weights, with any
+workload and regardless of the device parameters. From these bandwidth
+guarantees, it is possible to compute tight per-I/O-request delay
+guarantees by a simple formula. If not configured for strict service
+guarantees, BFQ switches to time-based resource sharing (only) for
+applications that would otherwise cause a throughput loss.
+
+1-2 Server systems
+------------------
+
+Most benefits for server systems follow from the same service
+properties as above. In particular, regardless of whether additional,
+possibly heavy workloads are being served, BFQ guarantees:
+
+* audio and video-streaming with zero or very low jitter and drop
+  rate;
+
+* fast retrieval of WEB pages and embedded objects;
+
+* real-time recording of data in live-dumping applications (e.g.,
+  packet logging);
+
+* responsiveness in local and remote access to a server.
+
+
+2. How does BFQ work?
+=====================
+
+BFQ is a proportional-share I/O scheduler, whose general structure,
+plus a lot of code, are borrowed from CFQ.
+
+- Each process doing I/O on a device is associated with a weight and a
+  `(bfq_)queue`.
+
+- BFQ grants exclusive access to the device, for a while, to one queue
+  (process) at a time, and implements this service model by
+  associating every queue with a budget, measured in number of
+  sectors.
+
+  - After a queue is granted access to the device, the budget of the
+    queue is decremented, on each request dispatch, by the size of the
+    request.
+
+  - The in-service queue is expired, i.e., its service is suspended,
+    only if one of the following events occurs: 1) the queue finishes
+    its budget, 2) the queue empties, 3) a "budget timeout" fires.
+
+    - The budget timeout prevents processes doing random I/O from
+      holding the device for too long and dramatically reducing
+      throughput.
+
+    - Actually, as in CFQ, a queue associated with a process issuing
+      sync requests may not be expired immediately when it empties. In
+      contrast, BFQ may idle the device for a short time interval,
+      giving the process the chance to go on being served if it issues
+      a new request in time. Device idling typically boosts the
+      throughput on rotational devices and on non-queueing flash-based
+      devices, if processes do synchronous and sequential I/O. In
+      addition, under BFQ, device idling is also instrumental in
+      guaranteeing the desired throughput fraction to processes
+      issuing sync requests (see the description of the slice_idle
+      tunable in this document, or [1, 2], for more details).
+
+      - With respect to idling for service guarantees, if several
+       processes are competing for the device at the same time, but
+       all processes and groups have the same weight, then BFQ
+       guarantees the expected throughput distribution without ever
+       idling the device. Throughput is thus as high as possible in
+       this common scenario.
+
+     - On flash-based storage with internal queueing of commands
+       (typically NCQ), device idling happens to be always detrimental
+       for throughput. So, with these devices, BFQ performs idling
+       only when strictly needed for service guarantees, i.e., for
+       guaranteeing low latency or fairness. In these cases, overall
+       throughput may be sub-optimal. No solution currently exists to
+       provide both strong service guarantees and optimal throughput
+       on devices with internal queueing.
+
+  - If low-latency mode is enabled (default configuration), BFQ
+    executes some special heuristics to detect interactive and soft
+    real-time applications (e.g., video or audio players/streamers),
+    and to reduce their latency. The most important action taken to
+    achieve this goal is to give to the queues associated with these
+    applications more than their fair share of the device
+    throughput. For brevity, we call just "weight-raising" the whole
+    sets of actions taken by BFQ to privilege these queues. In
+    particular, BFQ provides a milder form of weight-raising for
+    interactive applications, and a stronger form for soft real-time
+    applications.
+
+  - BFQ automatically deactivates idling for queues born in a burst of
+    queue creations. In fact, these queues are usually associated with
+    the processes of applications and services that benefit mostly
+    from a high throughput. Examples are systemd during boot, or git
+    grep.
+
+  - As CFQ, BFQ merges queues performing interleaved I/O, i.e.,
+    performing random I/O that becomes mostly sequential if
+    merged. Differently from CFQ, BFQ achieves this goal with a more
+    reactive mechanism, called Early Queue Merge (EQM). EQM is so
+    responsive in detecting interleaved I/O (cooperating processes),
+    that it enables BFQ to achieve a high throughput, by queue
+    merging, even for queues for which CFQ needs a different
+    mechanism, preemption, to get a high throughput. As such EQM is a
+    unified mechanism to achieve a high throughput with interleaved
+    I/O.
+
+  - Queues are scheduled according to a variant of WF2Q+, named
+    B-WF2Q+, and implemented using an augmented rb-tree to preserve an
+    O(log N) overall complexity.  See [2] for more details. B-WF2Q+ is
+    also ready for hierarchical scheduling, details in Section 4.
+
+  - B-WF2Q+ guarantees a tight deviation with respect to an ideal,
+    perfectly fair, and smooth service. In particular, B-WF2Q+
+    guarantees that each queue receives a fraction of the device
+    throughput proportional to its weight, even if the throughput
+    fluctuates, and regardless of: the device parameters, the current
+    workload and the budgets assigned to the queue.
+
+  - The last, budget-independence, property (although probably
+    counterintuitive in the first place) is definitely beneficial, for
+    the following reasons:
+
+    - First, with any proportional-share scheduler, the maximum
+      deviation with respect to an ideal service is proportional to
+      the maximum budget (slice) assigned to queues. As a consequence,
+      BFQ can keep this deviation tight not only because of the
+      accurate service of B-WF2Q+, but also because BFQ *does not*
+      need to assign a larger budget to a queue to let the queue
+      receive a higher fraction of the device throughput.
+
+    - Second, BFQ is free to choose, for every process (queue), the
+      budget that best fits the needs of the process, or best
+      leverages the I/O pattern of the process. In particular, BFQ
+      updates queue budgets with a simple feedback-loop algorithm that
+      allows a high throughput to be achieved, while still providing
+      tight latency guarantees to time-sensitive applications. When
+      the in-service queue expires, this algorithm computes the next
+      budget of the queue so as to:
+
+      - Let large budgets be eventually assigned to the queues
+       associated with I/O-bound applications performing sequential
+       I/O: in fact, the longer these applications are served once
+       got access to the device, the higher the throughput is.
+
+      - Let small budgets be eventually assigned to the queues
+       associated with time-sensitive applications (which typically
+       perform sporadic and short I/O), because, the smaller the
+       budget assigned to a queue waiting for service is, the sooner
+       B-WF2Q+ will serve that queue (Subsec 3.3 in [2]).
+
+- If several processes are competing for the device at the same time,
+  but all processes and groups have the same weight, then BFQ
+  guarantees the expected throughput distribution without ever idling
+  the device. It uses preemption instead. Throughput is then much
+  higher in this common scenario.
+
+- ioprio classes are served in strict priority order, i.e.,
+  lower-priority queues are not served as long as there are
+  higher-priority queues.  Among queues in the same class, the
+  bandwidth is distributed in proportion to the weight of each
+  queue. A very thin extra bandwidth is however guaranteed to
+  the Idle class, to prevent it from starving.
+
+
+3. What are BFQ's tunables and how to properly configure BFQ?
+=============================================================
+
+Most BFQ tunables affect service guarantees (basically latency and
+fairness) and throughput. For full details on how to choose the
+desired tradeoff between service guarantees and throughput, see the
+parameters slice_idle, strict_guarantees and low_latency. For details
+on how to maximise throughput, see slice_idle, timeout_sync and
+max_budget. The other performance-related parameters have been
+inherited from, and have been preserved mostly for compatibility with
+CFQ. So far, no performance improvement has been reported after
+changing the latter parameters in BFQ.
+
+In particular, the tunables back_seek-max, back_seek_penalty,
+fifo_expire_async and fifo_expire_sync below are the same as in
+CFQ. Their description is just copied from that for CFQ. Some
+considerations in the description of slice_idle are copied from CFQ
+too.
+
+per-process ioprio and weight
+-----------------------------
+
+Unless the cgroups interface is used (see "4. BFQ group scheduling"),
+weights can be assigned to processes only indirectly, through I/O
+priorities, and according to the relation:
+weight = (IOPRIO_BE_NR - ioprio) * 10.
+
+Beware that, if low-latency is set, then BFQ automatically raises the
+weight of the queues associated with interactive and soft real-time
+applications. Unset this tunable if you need/want to control weights.
+
+slice_idle
+----------
+
+This parameter specifies how long BFQ should idle for next I/O
+request, when certain sync BFQ queues become empty. By default
+slice_idle is a non-zero value. Idling has a double purpose: boosting
+throughput and making sure that the desired throughput distribution is
+respected (see the description of how BFQ works, and, if needed, the
+papers referred there).
+
+As for throughput, idling can be very helpful on highly seeky media
+like single spindle SATA/SAS disks where we can cut down on overall
+number of seeks and see improved throughput.
+
+Setting slice_idle to 0 will remove all the idling on queues and one
+should see an overall improved throughput on faster storage devices
+like multiple SATA/SAS disks in hardware RAID configuration, as well
+as flash-based storage with internal command queueing (and
+parallelism).
+
+So depending on storage and workload, it might be useful to set
+slice_idle=0.  In general for SATA/SAS disks and software RAID of
+SATA/SAS disks keeping slice_idle enabled should be useful. For any
+configurations where there are multiple spindles behind single LUN
+(Host based hardware RAID controller or for storage arrays), or with
+flash-based fast storage, setting slice_idle=0 might end up in better
+throughput and acceptable latencies.
+
+Idling is however necessary to have service guarantees enforced in
+case of differentiated weights or differentiated I/O-request lengths.
+To see why, suppose that a given BFQ queue A must get several I/O
+requests served for each request served for another queue B. Idling
+ensures that, if A makes a new I/O request slightly after becoming
+empty, then no request of B is dispatched in the middle, and thus A
+does not lose the possibility to get more than one request dispatched
+before the next request of B is dispatched. Note that idling
+guarantees the desired differentiated treatment of queues only in
+terms of I/O-request dispatches. To guarantee that the actual service
+order then corresponds to the dispatch order, the strict_guarantees
+tunable must be set too.
+
+There is an important flipside for idling: apart from the above cases
+where it is beneficial also for throughput, idling can severely impact
+throughput. One important case is random workload. Because of this
+issue, BFQ tends to avoid idling as much as possible, when it is not
+beneficial also for throughput (as detailed in Section 2). As a
+consequence of this behavior, and of further issues described for the
+strict_guarantees tunable, short-term service guarantees may be
+occasionally violated. And, in some cases, these guarantees may be
+more important than guaranteeing maximum throughput. For example, in
+video playing/streaming, a very low drop rate may be more important
+than maximum throughput. In these cases, consider setting the
+strict_guarantees parameter.
+
+slice_idle_us
+-------------
+
+Controls the same tuning parameter as slice_idle, but in microseconds.
+Either tunable can be used to set idling behavior.  Afterwards, the
+other tunable will reflect the newly set value in sysfs.
+
+strict_guarantees
+-----------------
+
+If this parameter is set (default: unset), then BFQ
+
+- always performs idling when the in-service queue becomes empty;
+
+- forces the device to serve one I/O request at a time, by dispatching a
+  new request only if there is no outstanding request.
+
+In the presence of differentiated weights or I/O-request sizes, both
+the above conditions are needed to guarantee that every BFQ queue
+receives its allotted share of the bandwidth. The first condition is
+needed for the reasons explained in the description of the slice_idle
+tunable.  The second condition is needed because all modern storage
+devices reorder internally-queued requests, which may trivially break
+the service guarantees enforced by the I/O scheduler.
+
+Setting strict_guarantees may evidently affect throughput.
+
+back_seek_max
+-------------
+
+This specifies, given in Kbytes, the maximum "distance" for backward seeking.
+The distance is the amount of space from the current head location to the
+sectors that are backward in terms of distance.
+
+This parameter allows the scheduler to anticipate requests in the "backward"
+direction and consider them as being the "next" if they are within this
+distance from the current head location.
+
+back_seek_penalty
+-----------------
+
+This parameter is used to compute the cost of backward seeking. If the
+backward distance of request is just 1/back_seek_penalty from a "front"
+request, then the seeking cost of two requests is considered equivalent.
+
+So scheduler will not bias toward one or the other request (otherwise scheduler
+will bias toward front request). Default value of back_seek_penalty is 2.
+
+fifo_expire_async
+-----------------
+
+This parameter is used to set the timeout of asynchronous requests. Default
+value of this is 248ms.
+
+fifo_expire_sync
+----------------
+
+This parameter is used to set the timeout of synchronous requests. Default
+value of this is 124ms. In case to favor synchronous requests over asynchronous
+one, this value should be decreased relative to fifo_expire_async.
+
+low_latency
+-----------
+
+This parameter is used to enable/disable BFQ's low latency mode. By
+default, low latency mode is enabled. If enabled, interactive and soft
+real-time applications are privileged and experience a lower latency,
+as explained in more detail in the description of how BFQ works.
+
+DISABLE this mode if you need full control on bandwidth
+distribution. In fact, if it is enabled, then BFQ automatically
+increases the bandwidth share of privileged applications, as the main
+means to guarantee a lower latency to them.
+
+In addition, as already highlighted at the beginning of this document,
+DISABLE this mode if your only goal is to achieve a high throughput.
+In fact, privileging the I/O of some application over the rest may
+entail a lower throughput. To achieve the highest-possible throughput
+on a non-rotational device, setting slice_idle to 0 may be needed too
+(at the cost of giving up any strong guarantee on fairness and low
+latency).
+
+timeout_sync
+------------
+
+Maximum amount of device time that can be given to a task (queue) once
+it has been selected for service. On devices with costly seeks,
+increasing this time usually increases maximum throughput. On the
+opposite end, increasing this time coarsens the granularity of the
+short-term bandwidth and latency guarantees, especially if the
+following parameter is set to zero.
+
+max_budget
+----------
+
+Maximum amount of service, measured in sectors, that can be provided
+to a BFQ queue once it is set in service (of course within the limits
+of the above timeout). According to what said in the description of
+the algorithm, larger values increase the throughput in proportion to
+the percentage of sequential I/O requests issued. The price of larger
+values is that they coarsen the granularity of short-term bandwidth
+and latency guarantees.
+
+The default value is 0, which enables auto-tuning: BFQ sets max_budget
+to the maximum number of sectors that can be served during
+timeout_sync, according to the estimated peak rate.
+
+For specific devices, some users have occasionally reported to have
+reached a higher throughput by setting max_budget explicitly, i.e., by
+setting max_budget to a higher value than 0. In particular, they have
+set max_budget to higher values than those to which BFQ would have set
+it with auto-tuning. An alternative way to achieve this goal is to
+just increase the value of timeout_sync, leaving max_budget equal to 0.
+
+weights
+-------
+
+Read-only parameter, used to show the weights of the currently active
+BFQ queues.
+
+
+4. Group scheduling with BFQ
+============================
+
+BFQ supports both cgroups-v1 and cgroups-v2 io controllers, namely
+blkio and io. In particular, BFQ supports weight-based proportional
+share. To activate cgroups support, set BFQ_GROUP_IOSCHED.
+
+4-1 Service guarantees provided
+-------------------------------
+
+With BFQ, proportional share means true proportional share of the
+device bandwidth, according to group weights. For example, a group
+with weight 200 gets twice the bandwidth, and not just twice the time,
+of a group with weight 100.
+
+BFQ supports hierarchies (group trees) of any depth. Bandwidth is
+distributed among groups and processes in the expected way: for each
+group, the children of the group share the whole bandwidth of the
+group in proportion to their weights. In particular, this implies
+that, for each leaf group, every process of the group receives the
+same share of the whole group bandwidth, unless the ioprio of the
+process is modified.
+
+The resource-sharing guarantee for a group may partially or totally
+switch from bandwidth to time, if providing bandwidth guarantees to
+the group lowers the throughput too much. This switch occurs on a
+per-process basis: if a process of a leaf group causes throughput loss
+if served in such a way to receive its share of the bandwidth, then
+BFQ switches back to just time-based proportional share for that
+process.
+
+4-2 Interface
+-------------
+
+To get proportional sharing of bandwidth with BFQ for a given device,
+BFQ must of course be the active scheduler for that device.
+
+Within each group directory, the names of the files associated with
+BFQ-specific cgroup parameters and stats begin with the "bfq."
+prefix. So, with cgroups-v1 or cgroups-v2, the full prefix for
+BFQ-specific files is "blkio.bfq." or "io.bfq." For example, the group
+parameter to set the weight of a group with BFQ is blkio.bfq.weight
+or io.bfq.weight.
+
+As for cgroups-v1 (blkio controller), the exact set of stat files
+created, and kept up-to-date by bfq, depends on whether
+CONFIG_BFQ_CGROUP_DEBUG is set. If it is set, then bfq creates all
+the stat files documented in
+Documentation/admin-guide/cgroup-v1/blkio-controller.rst. If, instead,
+CONFIG_BFQ_CGROUP_DEBUG is not set, then bfq creates only the files::
+
+  blkio.bfq.io_service_bytes
+  blkio.bfq.io_service_bytes_recursive
+  blkio.bfq.io_serviced
+  blkio.bfq.io_serviced_recursive
+
+The value of CONFIG_BFQ_CGROUP_DEBUG greatly influences the maximum
+throughput sustainable with bfq, because updating the blkio.bfq.*
+stats is rather costly, especially for some of the stats enabled by
+CONFIG_BFQ_CGROUP_DEBUG.
+
+Parameters to set
+-----------------
+
+For each group, there is only the following parameter to set.
+
+weight (namely blkio.bfq.weight or io.bfq-weight): the weight of the
+group inside its parent. Available values: 1..10000 (default 100). The
+linear mapping between ioprio and weights, described at the beginning
+of the tunable section, is still valid, but all weights higher than
+IOPRIO_BE_NR*10 are mapped to ioprio 0.
+
+Recall that, if low-latency is set, then BFQ automatically raises the
+weight of the queues associated with interactive and soft real-time
+applications. Unset this tunable if you need/want to control weights.
+
+
+[1]
+    P. Valente, A. Avanzini, "Evolution of the BFQ Storage I/O
+    Scheduler", Proceedings of the First Workshop on Mobile System
+    Technologies (MST-2015), May 2015.
+
+    http://algogroup.unimore.it/people/paolo/disk_sched/mst-2015.pdf
+
+[2]
+    P. Valente and M. Andreolini, "Improving Application
+    Responsiveness with the BFQ Disk I/O Scheduler", Proceedings of
+    the 5th Annual International Systems and Storage Conference
+    (SYSTOR '12), June 2012.
+
+    Slightly extended version:
+
+    http://algogroup.unimore.it/people/paolo/disk_sched/bfq-v1-suite-results.pdf
+
+[3]
+   https://github.com/Algodev-github/S
diff --git a/Documentation/block/bfq-iosched.txt b/Documentation/block/bfq-iosched.txt
deleted file mode 100644 (file)
index bbd6eb5..0000000
+++ /dev/null
@@ -1,583 +0,0 @@
-BFQ (Budget Fair Queueing)
-==========================
-
-BFQ is a proportional-share I/O scheduler, with some extra
-low-latency capabilities. In addition to cgroups support (blkio or io
-controllers), BFQ's main features are:
-- BFQ guarantees a high system and application responsiveness, and a
-  low latency for time-sensitive applications, such as audio or video
-  players;
-- BFQ distributes bandwidth, and not just time, among processes or
-  groups (switching back to time distribution when needed to keep
-  throughput high).
-
-In its default configuration, BFQ privileges latency over
-throughput. So, when needed for achieving a lower latency, BFQ builds
-schedules that may lead to a lower throughput. If your main or only
-goal, for a given device, is to achieve the maximum-possible
-throughput at all times, then do switch off all low-latency heuristics
-for that device, by setting low_latency to 0. See Section 3 for
-details on how to configure BFQ for the desired tradeoff between
-latency and throughput, or on how to maximize throughput.
-
-As every I/O scheduler, BFQ adds some overhead to per-I/O-request
-processing. To give an idea of this overhead, the total,
-single-lock-protected, per-request processing time of BFQ---i.e., the
-sum of the execution times of the request insertion, dispatch and
-completion hooks---is, e.g., 1.9 us on an Intel Core i7-2760QM@2.40GHz
-(dated CPU for notebooks; time measured with simple code
-instrumentation, and using the throughput-sync.sh script of the S
-suite [1], in performance-profiling mode). To put this result into
-context, the total, single-lock-protected, per-request execution time
-of the lightest I/O scheduler available in blk-mq, mq-deadline, is 0.7
-us (mq-deadline is ~800 LOC, against ~10500 LOC for BFQ).
-
-Scheduling overhead further limits the maximum IOPS that a CPU can
-process (already limited by the execution of the rest of the I/O
-stack). To give an idea of the limits with BFQ, on slow or average
-CPUs, here are, first, the limits of BFQ for three different CPUs, on,
-respectively, an average laptop, an old desktop, and a cheap embedded
-system, in case full hierarchical support is enabled (i.e.,
-CONFIG_BFQ_GROUP_IOSCHED is set), but CONFIG_BFQ_CGROUP_DEBUG is not
-set (Section 4-2):
-- Intel i7-4850HQ: 400 KIOPS
-- AMD A8-3850: 250 KIOPS
-- ARM CortexTM-A53 Octa-core: 80 KIOPS
-
-If CONFIG_BFQ_CGROUP_DEBUG is set (and of course full hierarchical
-support is enabled), then the sustainable throughput with BFQ
-decreases, because all blkio.bfq* statistics are created and updated
-(Section 4-2). For BFQ, this leads to the following maximum
-sustainable throughputs, on the same systems as above:
-- Intel i7-4850HQ: 310 KIOPS
-- AMD A8-3850: 200 KIOPS
-- ARM CortexTM-A53 Octa-core: 56 KIOPS
-
-BFQ works for multi-queue devices too.
-
-The table of contents follow. Impatients can just jump to Section 3.
-
-CONTENTS
-
-1. When may BFQ be useful?
- 1-1 Personal systems
- 1-2 Server systems
-2. How does BFQ work?
-3. What are BFQ's tunables and how to properly configure BFQ?
-4. BFQ group scheduling
- 4-1 Service guarantees provided
- 4-2 Interface
-
-1. When may BFQ be useful?
-==========================
-
-BFQ provides the following benefits on personal and server systems.
-
-1-1 Personal systems
---------------------
-
-Low latency for interactive applications
-
-Regardless of the actual background workload, BFQ guarantees that, for
-interactive tasks, the storage device is virtually as responsive as if
-it was idle. For example, even if one or more of the following
-background workloads are being executed:
-- one or more large files are being read, written or copied,
-- a tree of source files is being compiled,
-- one or more virtual machines are performing I/O,
-- a software update is in progress,
-- indexing daemons are scanning filesystems and updating their
-  databases,
-starting an application or loading a file from within an application
-takes about the same time as if the storage device was idle. As a
-comparison, with CFQ, NOOP or DEADLINE, and in the same conditions,
-applications experience high latencies, or even become unresponsive
-until the background workload terminates (also on SSDs).
-
-Low latency for soft real-time applications
-
-Also soft real-time applications, such as audio and video
-players/streamers, enjoy a low latency and a low drop rate, regardless
-of the background I/O workload. As a consequence, these applications
-do not suffer from almost any glitch due to the background workload.
-
-Higher speed for code-development tasks
-
-If some additional workload happens to be executed in parallel, then
-BFQ executes the I/O-related components of typical code-development
-tasks (compilation, checkout, merge, ...) much more quickly than CFQ,
-NOOP or DEADLINE.
-
-High throughput
-
-On hard disks, BFQ achieves up to 30% higher throughput than CFQ, and
-up to 150% higher throughput than DEADLINE and NOOP, with all the
-sequential workloads considered in our tests. With random workloads,
-and with all the workloads on flash-based devices, BFQ achieves,
-instead, about the same throughput as the other schedulers.
-
-Strong fairness, bandwidth and delay guarantees
-
-BFQ distributes the device throughput, and not just the device time,
-among I/O-bound applications in proportion their weights, with any
-workload and regardless of the device parameters. From these bandwidth
-guarantees, it is possible to compute tight per-I/O-request delay
-guarantees by a simple formula. If not configured for strict service
-guarantees, BFQ switches to time-based resource sharing (only) for
-applications that would otherwise cause a throughput loss.
-
-1-2 Server systems
-------------------
-
-Most benefits for server systems follow from the same service
-properties as above. In particular, regardless of whether additional,
-possibly heavy workloads are being served, BFQ guarantees:
-
-. audio and video-streaming with zero or very low jitter and drop
-  rate;
-
-. fast retrieval of WEB pages and embedded objects;
-
-. real-time recording of data in live-dumping applications (e.g.,
-  packet logging);
-
-. responsiveness in local and remote access to a server.
-
-
-2. How does BFQ work?
-=====================
-
-BFQ is a proportional-share I/O scheduler, whose general structure,
-plus a lot of code, are borrowed from CFQ.
-
-- Each process doing I/O on a device is associated with a weight and a
-  (bfq_)queue.
-
-- BFQ grants exclusive access to the device, for a while, to one queue
-  (process) at a time, and implements this service model by
-  associating every queue with a budget, measured in number of
-  sectors.
-
-  - After a queue is granted access to the device, the budget of the
-    queue is decremented, on each request dispatch, by the size of the
-    request.
-
-  - The in-service queue is expired, i.e., its service is suspended,
-    only if one of the following events occurs: 1) the queue finishes
-    its budget, 2) the queue empties, 3) a "budget timeout" fires.
-
-    - The budget timeout prevents processes doing random I/O from
-      holding the device for too long and dramatically reducing
-      throughput.
-
-    - Actually, as in CFQ, a queue associated with a process issuing
-      sync requests may not be expired immediately when it empties. In
-      contrast, BFQ may idle the device for a short time interval,
-      giving the process the chance to go on being served if it issues
-      a new request in time. Device idling typically boosts the
-      throughput on rotational devices and on non-queueing flash-based
-      devices, if processes do synchronous and sequential I/O. In
-      addition, under BFQ, device idling is also instrumental in
-      guaranteeing the desired throughput fraction to processes
-      issuing sync requests (see the description of the slice_idle
-      tunable in this document, or [1, 2], for more details).
-
-      - With respect to idling for service guarantees, if several
-       processes are competing for the device at the same time, but
-       all processes and groups have the same weight, then BFQ
-       guarantees the expected throughput distribution without ever
-       idling the device. Throughput is thus as high as possible in
-       this common scenario.
-
-     - On flash-based storage with internal queueing of commands
-       (typically NCQ), device idling happens to be always detrimental
-       for throughput. So, with these devices, BFQ performs idling
-       only when strictly needed for service guarantees, i.e., for
-       guaranteeing low latency or fairness. In these cases, overall
-       throughput may be sub-optimal. No solution currently exists to
-       provide both strong service guarantees and optimal throughput
-       on devices with internal queueing.
-
-  - If low-latency mode is enabled (default configuration), BFQ
-    executes some special heuristics to detect interactive and soft
-    real-time applications (e.g., video or audio players/streamers),
-    and to reduce their latency. The most important action taken to
-    achieve this goal is to give to the queues associated with these
-    applications more than their fair share of the device
-    throughput. For brevity, we call just "weight-raising" the whole
-    sets of actions taken by BFQ to privilege these queues. In
-    particular, BFQ provides a milder form of weight-raising for
-    interactive applications, and a stronger form for soft real-time
-    applications.
-
-  - BFQ automatically deactivates idling for queues born in a burst of
-    queue creations. In fact, these queues are usually associated with
-    the processes of applications and services that benefit mostly
-    from a high throughput. Examples are systemd during boot, or git
-    grep.
-
-  - As CFQ, BFQ merges queues performing interleaved I/O, i.e.,
-    performing random I/O that becomes mostly sequential if
-    merged. Differently from CFQ, BFQ achieves this goal with a more
-    reactive mechanism, called Early Queue Merge (EQM). EQM is so
-    responsive in detecting interleaved I/O (cooperating processes),
-    that it enables BFQ to achieve a high throughput, by queue
-    merging, even for queues for which CFQ needs a different
-    mechanism, preemption, to get a high throughput. As such EQM is a
-    unified mechanism to achieve a high throughput with interleaved
-    I/O.
-
-  - Queues are scheduled according to a variant of WF2Q+, named
-    B-WF2Q+, and implemented using an augmented rb-tree to preserve an
-    O(log N) overall complexity.  See [2] for more details. B-WF2Q+ is
-    also ready for hierarchical scheduling, details in Section 4.
-
-  - B-WF2Q+ guarantees a tight deviation with respect to an ideal,
-    perfectly fair, and smooth service. In particular, B-WF2Q+
-    guarantees that each queue receives a fraction of the device
-    throughput proportional to its weight, even if the throughput
-    fluctuates, and regardless of: the device parameters, the current
-    workload and the budgets assigned to the queue.
-
-  - The last, budget-independence, property (although probably
-    counterintuitive in the first place) is definitely beneficial, for
-    the following reasons:
-
-    - First, with any proportional-share scheduler, the maximum
-      deviation with respect to an ideal service is proportional to
-      the maximum budget (slice) assigned to queues. As a consequence,
-      BFQ can keep this deviation tight not only because of the
-      accurate service of B-WF2Q+, but also because BFQ *does not*
-      need to assign a larger budget to a queue to let the queue
-      receive a higher fraction of the device throughput.
-
-    - Second, BFQ is free to choose, for every process (queue), the
-      budget that best fits the needs of the process, or best
-      leverages the I/O pattern of the process. In particular, BFQ
-      updates queue budgets with a simple feedback-loop algorithm that
-      allows a high throughput to be achieved, while still providing
-      tight latency guarantees to time-sensitive applications. When
-      the in-service queue expires, this algorithm computes the next
-      budget of the queue so as to:
-
-      - Let large budgets be eventually assigned to the queues
-       associated with I/O-bound applications performing sequential
-       I/O: in fact, the longer these applications are served once
-       got access to the device, the higher the throughput is.
-
-      - Let small budgets be eventually assigned to the queues
-       associated with time-sensitive applications (which typically
-       perform sporadic and short I/O), because, the smaller the
-       budget assigned to a queue waiting for service is, the sooner
-       B-WF2Q+ will serve that queue (Subsec 3.3 in [2]).
-
-- If several processes are competing for the device at the same time,
-  but all processes and groups have the same weight, then BFQ
-  guarantees the expected throughput distribution without ever idling
-  the device. It uses preemption instead. Throughput is then much
-  higher in this common scenario.
-
-- ioprio classes are served in strict priority order, i.e.,
-  lower-priority queues are not served as long as there are
-  higher-priority queues.  Among queues in the same class, the
-  bandwidth is distributed in proportion to the weight of each
-  queue. A very thin extra bandwidth is however guaranteed to
-  the Idle class, to prevent it from starving.
-
-
-3. What are BFQ's tunables and how to properly configure BFQ?
-=============================================================
-
-Most BFQ tunables affect service guarantees (basically latency and
-fairness) and throughput. For full details on how to choose the
-desired tradeoff between service guarantees and throughput, see the
-parameters slice_idle, strict_guarantees and low_latency. For details
-on how to maximise throughput, see slice_idle, timeout_sync and
-max_budget. The other performance-related parameters have been
-inherited from, and have been preserved mostly for compatibility with
-CFQ. So far, no performance improvement has been reported after
-changing the latter parameters in BFQ.
-
-In particular, the tunables back_seek-max, back_seek_penalty,
-fifo_expire_async and fifo_expire_sync below are the same as in
-CFQ. Their description is just copied from that for CFQ. Some
-considerations in the description of slice_idle are copied from CFQ
-too.
-
-per-process ioprio and weight
------------------------------
-
-Unless the cgroups interface is used (see "4. BFQ group scheduling"),
-weights can be assigned to processes only indirectly, through I/O
-priorities, and according to the relation:
-weight = (IOPRIO_BE_NR - ioprio) * 10.
-
-Beware that, if low-latency is set, then BFQ automatically raises the
-weight of the queues associated with interactive and soft real-time
-applications. Unset this tunable if you need/want to control weights.
-
-slice_idle
-----------
-
-This parameter specifies how long BFQ should idle for next I/O
-request, when certain sync BFQ queues become empty. By default
-slice_idle is a non-zero value. Idling has a double purpose: boosting
-throughput and making sure that the desired throughput distribution is
-respected (see the description of how BFQ works, and, if needed, the
-papers referred there).
-
-As for throughput, idling can be very helpful on highly seeky media
-like single spindle SATA/SAS disks where we can cut down on overall
-number of seeks and see improved throughput.
-
-Setting slice_idle to 0 will remove all the idling on queues and one
-should see an overall improved throughput on faster storage devices
-like multiple SATA/SAS disks in hardware RAID configuration, as well
-as flash-based storage with internal command queueing (and
-parallelism).
-
-So depending on storage and workload, it might be useful to set
-slice_idle=0.  In general for SATA/SAS disks and software RAID of
-SATA/SAS disks keeping slice_idle enabled should be useful. For any
-configurations where there are multiple spindles behind single LUN
-(Host based hardware RAID controller or for storage arrays), or with
-flash-based fast storage, setting slice_idle=0 might end up in better
-throughput and acceptable latencies.
-
-Idling is however necessary to have service guarantees enforced in
-case of differentiated weights or differentiated I/O-request lengths.
-To see why, suppose that a given BFQ queue A must get several I/O
-requests served for each request served for another queue B. Idling
-ensures that, if A makes a new I/O request slightly after becoming
-empty, then no request of B is dispatched in the middle, and thus A
-does not lose the possibility to get more than one request dispatched
-before the next request of B is dispatched. Note that idling
-guarantees the desired differentiated treatment of queues only in
-terms of I/O-request dispatches. To guarantee that the actual service
-order then corresponds to the dispatch order, the strict_guarantees
-tunable must be set too.
-
-There is an important flipside for idling: apart from the above cases
-where it is beneficial also for throughput, idling can severely impact
-throughput. One important case is random workload. Because of this
-issue, BFQ tends to avoid idling as much as possible, when it is not
-beneficial also for throughput (as detailed in Section 2). As a
-consequence of this behavior, and of further issues described for the
-strict_guarantees tunable, short-term service guarantees may be
-occasionally violated. And, in some cases, these guarantees may be
-more important than guaranteeing maximum throughput. For example, in
-video playing/streaming, a very low drop rate may be more important
-than maximum throughput. In these cases, consider setting the
-strict_guarantees parameter.
-
-slice_idle_us
--------------
-
-Controls the same tuning parameter as slice_idle, but in microseconds.
-Either tunable can be used to set idling behavior.  Afterwards, the
-other tunable will reflect the newly set value in sysfs.
-
-strict_guarantees
------------------
-
-If this parameter is set (default: unset), then BFQ
-
-- always performs idling when the in-service queue becomes empty;
-
-- forces the device to serve one I/O request at a time, by dispatching a
-  new request only if there is no outstanding request.
-
-In the presence of differentiated weights or I/O-request sizes, both
-the above conditions are needed to guarantee that every BFQ queue
-receives its allotted share of the bandwidth. The first condition is
-needed for the reasons explained in the description of the slice_idle
-tunable.  The second condition is needed because all modern storage
-devices reorder internally-queued requests, which may trivially break
-the service guarantees enforced by the I/O scheduler.
-
-Setting strict_guarantees may evidently affect throughput.
-
-back_seek_max
--------------
-
-This specifies, given in Kbytes, the maximum "distance" for backward seeking.
-The distance is the amount of space from the current head location to the
-sectors that are backward in terms of distance.
-
-This parameter allows the scheduler to anticipate requests in the "backward"
-direction and consider them as being the "next" if they are within this
-distance from the current head location.
-
-back_seek_penalty
------------------
-
-This parameter is used to compute the cost of backward seeking. If the
-backward distance of request is just 1/back_seek_penalty from a "front"
-request, then the seeking cost of two requests is considered equivalent.
-
-So scheduler will not bias toward one or the other request (otherwise scheduler
-will bias toward front request). Default value of back_seek_penalty is 2.
-
-fifo_expire_async
------------------
-
-This parameter is used to set the timeout of asynchronous requests. Default
-value of this is 248ms.
-
-fifo_expire_sync
-----------------
-
-This parameter is used to set the timeout of synchronous requests. Default
-value of this is 124ms. In case to favor synchronous requests over asynchronous
-one, this value should be decreased relative to fifo_expire_async.
-
-low_latency
------------
-
-This parameter is used to enable/disable BFQ's low latency mode. By
-default, low latency mode is enabled. If enabled, interactive and soft
-real-time applications are privileged and experience a lower latency,
-as explained in more detail in the description of how BFQ works.
-
-DISABLE this mode if you need full control on bandwidth
-distribution. In fact, if it is enabled, then BFQ automatically
-increases the bandwidth share of privileged applications, as the main
-means to guarantee a lower latency to them.
-
-In addition, as already highlighted at the beginning of this document,
-DISABLE this mode if your only goal is to achieve a high throughput.
-In fact, privileging the I/O of some application over the rest may
-entail a lower throughput. To achieve the highest-possible throughput
-on a non-rotational device, setting slice_idle to 0 may be needed too
-(at the cost of giving up any strong guarantee on fairness and low
-latency).
-
-timeout_sync
-------------
-
-Maximum amount of device time that can be given to a task (queue) once
-it has been selected for service. On devices with costly seeks,
-increasing this time usually increases maximum throughput. On the
-opposite end, increasing this time coarsens the granularity of the
-short-term bandwidth and latency guarantees, especially if the
-following parameter is set to zero.
-
-max_budget
-----------
-
-Maximum amount of service, measured in sectors, that can be provided
-to a BFQ queue once it is set in service (of course within the limits
-of the above timeout). According to what said in the description of
-the algorithm, larger values increase the throughput in proportion to
-the percentage of sequential I/O requests issued. The price of larger
-values is that they coarsen the granularity of short-term bandwidth
-and latency guarantees.
-
-The default value is 0, which enables auto-tuning: BFQ sets max_budget
-to the maximum number of sectors that can be served during
-timeout_sync, according to the estimated peak rate.
-
-For specific devices, some users have occasionally reported to have
-reached a higher throughput by setting max_budget explicitly, i.e., by
-setting max_budget to a higher value than 0. In particular, they have
-set max_budget to higher values than those to which BFQ would have set
-it with auto-tuning. An alternative way to achieve this goal is to
-just increase the value of timeout_sync, leaving max_budget equal to 0.
-
-weights
--------
-
-Read-only parameter, used to show the weights of the currently active
-BFQ queues.
-
-
-4. Group scheduling with BFQ
-============================
-
-BFQ supports both cgroups-v1 and cgroups-v2 io controllers, namely
-blkio and io. In particular, BFQ supports weight-based proportional
-share. To activate cgroups support, set BFQ_GROUP_IOSCHED.
-
-4-1 Service guarantees provided
--------------------------------
-
-With BFQ, proportional share means true proportional share of the
-device bandwidth, according to group weights. For example, a group
-with weight 200 gets twice the bandwidth, and not just twice the time,
-of a group with weight 100.
-
-BFQ supports hierarchies (group trees) of any depth. Bandwidth is
-distributed among groups and processes in the expected way: for each
-group, the children of the group share the whole bandwidth of the
-group in proportion to their weights. In particular, this implies
-that, for each leaf group, every process of the group receives the
-same share of the whole group bandwidth, unless the ioprio of the
-process is modified.
-
-The resource-sharing guarantee for a group may partially or totally
-switch from bandwidth to time, if providing bandwidth guarantees to
-the group lowers the throughput too much. This switch occurs on a
-per-process basis: if a process of a leaf group causes throughput loss
-if served in such a way to receive its share of the bandwidth, then
-BFQ switches back to just time-based proportional share for that
-process.
-
-4-2 Interface
--------------
-
-To get proportional sharing of bandwidth with BFQ for a given device,
-BFQ must of course be the active scheduler for that device.
-
-Within each group directory, the names of the files associated with
-BFQ-specific cgroup parameters and stats begin with the "bfq."
-prefix. So, with cgroups-v1 or cgroups-v2, the full prefix for
-BFQ-specific files is "blkio.bfq." or "io.bfq." For example, the group
-parameter to set the weight of a group with BFQ is blkio.bfq.weight
-or io.bfq.weight.
-
-As for cgroups-v1 (blkio controller), the exact set of stat files
-created, and kept up-to-date by bfq, depends on whether
-CONFIG_BFQ_CGROUP_DEBUG is set. If it is set, then bfq creates all
-the stat files documented in
-Documentation/cgroup-v1/blkio-controller.rst. If, instead,
-CONFIG_BFQ_CGROUP_DEBUG is not set, then bfq creates only the files
-blkio.bfq.io_service_bytes
-blkio.bfq.io_service_bytes_recursive
-blkio.bfq.io_serviced
-blkio.bfq.io_serviced_recursive
-
-The value of CONFIG_BFQ_CGROUP_DEBUG greatly influences the maximum
-throughput sustainable with bfq, because updating the blkio.bfq.*
-stats is rather costly, especially for some of the stats enabled by
-CONFIG_BFQ_CGROUP_DEBUG.
-
-Parameters to set
------------------
-
-For each group, there is only the following parameter to set.
-
-weight (namely blkio.bfq.weight or io.bfq-weight): the weight of the
-group inside its parent. Available values: 1..10000 (default 100). The
-linear mapping between ioprio and weights, described at the beginning
-of the tunable section, is still valid, but all weights higher than
-IOPRIO_BE_NR*10 are mapped to ioprio 0.
-
-Recall that, if low-latency is set, then BFQ automatically raises the
-weight of the queues associated with interactive and soft real-time
-applications. Unset this tunable if you need/want to control weights.
-
-
-[1] P. Valente, A. Avanzini, "Evolution of the BFQ Storage I/O
-    Scheduler", Proceedings of the First Workshop on Mobile System
-    Technologies (MST-2015), May 2015.
-    http://algogroup.unimore.it/people/paolo/disk_sched/mst-2015.pdf
-
-[2] P. Valente and M. Andreolini, "Improving Application
-    Responsiveness with the BFQ Disk I/O Scheduler", Proceedings of
-    the 5th Annual International Systems and Storage Conference
-    (SYSTOR '12), June 2012.
-    Slightly extended version:
-    http://algogroup.unimore.it/people/paolo/disk_sched/bfq-v1-suite-
-                                                       results.pdf
-
-[3] https://github.com/Algodev-github/S
diff --git a/Documentation/block/biodoc.rst b/Documentation/block/biodoc.rst
new file mode 100644 (file)
index 0000000..b964796
--- /dev/null
@@ -0,0 +1,1164 @@
+=====================================================
+Notes on the Generic Block Layer Rewrite in Linux 2.5
+=====================================================
+
+.. note::
+
+       It seems that there are lot of outdated stuff here. This seems
+       to be written somewhat as a task list. Yet, eventually, something
+       here might still be useful.
+
+Notes Written on Jan 15, 2002:
+
+       - Jens Axboe <jens.axboe@oracle.com>
+       - Suparna Bhattacharya <suparna@in.ibm.com>
+
+Last Updated May 2, 2002
+
+September 2003: Updated I/O Scheduler portions
+       - Nick Piggin <npiggin@kernel.dk>
+
+Introduction
+============
+
+These are some notes describing some aspects of the 2.5 block layer in the
+context of the bio rewrite. The idea is to bring out some of the key
+changes and a glimpse of the rationale behind those changes.
+
+Please mail corrections & suggestions to suparna@in.ibm.com.
+
+Credits
+=======
+
+2.5 bio rewrite:
+       - Jens Axboe <jens.axboe@oracle.com>
+
+Many aspects of the generic block layer redesign were driven by and evolved
+over discussions, prior patches and the collective experience of several
+people. See sections 8 and 9 for a list of some related references.
+
+The following people helped with review comments and inputs for this
+document:
+
+       - Christoph Hellwig <hch@infradead.org>
+       - Arjan van de Ven <arjanv@redhat.com>
+       - Randy Dunlap <rdunlap@xenotime.net>
+       - Andre Hedrick <andre@linux-ide.org>
+
+The following people helped with fixes/contributions to the bio patches
+while it was still work-in-progress:
+
+       - David S. Miller <davem@redhat.com>
+
+
+.. Description of Contents:
+
+   1. Scope for tuning of logic to various needs
+     1.1 Tuning based on device or low level driver capabilities
+       - Per-queue parameters
+       - Highmem I/O support
+       - I/O scheduler modularization
+     1.2 Tuning based on high level requirements/capabilities
+       1.2.1 Request Priority/Latency
+     1.3 Direct access/bypass to lower layers for diagnostics and special
+        device operations
+       1.3.1 Pre-built commands
+   2. New flexible and generic but minimalist i/o structure or descriptor
+      (instead of using buffer heads at the i/o layer)
+     2.1 Requirements/Goals addressed
+     2.2 The bio struct in detail (multi-page io unit)
+     2.3 Changes in the request structure
+   3. Using bios
+     3.1 Setup/teardown (allocation, splitting)
+     3.2 Generic bio helper routines
+       3.2.1 Traversing segments and completion units in a request
+       3.2.2 Setting up DMA scatterlists
+       3.2.3 I/O completion
+       3.2.4 Implications for drivers that do not interpret bios (don't handle
+         multiple segments)
+     3.3 I/O submission
+   4. The I/O scheduler
+   5. Scalability related changes
+     5.1 Granular locking: Removal of io_request_lock
+     5.2 Prepare for transition to 64 bit sector_t
+   6. Other Changes/Implications
+     6.1 Partition re-mapping handled by the generic block layer
+   7. A few tips on migration of older drivers
+   8. A list of prior/related/impacted patches/ideas
+   9. Other References/Discussion Threads
+
+
+Bio Notes
+=========
+
+Let us discuss the changes in the context of how some overall goals for the
+block layer are addressed.
+
+1. Scope for tuning the generic logic to satisfy various requirements
+=====================================================================
+
+The block layer design supports adaptable abstractions to handle common
+processing with the ability to tune the logic to an appropriate extent
+depending on the nature of the device and the requirements of the caller.
+One of the objectives of the rewrite was to increase the degree of tunability
+and to enable higher level code to utilize underlying device/driver
+capabilities to the maximum extent for better i/o performance. This is
+important especially in the light of ever improving hardware capabilities
+and application/middleware software designed to take advantage of these
+capabilities.
+
+1.1 Tuning based on low level device / driver capabilities
+----------------------------------------------------------
+
+Sophisticated devices with large built-in caches, intelligent i/o scheduling
+optimizations, high memory DMA support, etc may find some of the
+generic processing an overhead, while for less capable devices the
+generic functionality is essential for performance or correctness reasons.
+Knowledge of some of the capabilities or parameters of the device should be
+used at the generic block layer to take the right decisions on
+behalf of the driver.
+
+How is this achieved ?
+
+Tuning at a per-queue level:
+
+i. Per-queue limits/values exported to the generic layer by the driver
+
+Various parameters that the generic i/o scheduler logic uses are set at
+a per-queue level (e.g maximum request size, maximum number of segments in
+a scatter-gather list, logical block size)
+
+Some parameters that were earlier available as global arrays indexed by
+major/minor are now directly associated with the queue. Some of these may
+move into the block device structure in the future. Some characteristics
+have been incorporated into a queue flags field rather than separate fields
+in themselves.  There are blk_queue_xxx functions to set the parameters,
+rather than update the fields directly
+
+Some new queue property settings:
+
+       blk_queue_bounce_limit(q, u64 dma_address)
+               Enable I/O to highmem pages, dma_address being the
+               limit. No highmem default.
+
+       blk_queue_max_sectors(q, max_sectors)
+               Sets two variables that limit the size of the request.
+
+               - The request queue's max_sectors, which is a soft size in
+                 units of 512 byte sectors, and could be dynamically varied
+                 by the core kernel.
+
+               - The request queue's max_hw_sectors, which is a hard limit
+                 and reflects the maximum size request a driver can handle
+                 in units of 512 byte sectors.
+
+               The default for both max_sectors and max_hw_sectors is
+               255. The upper limit of max_sectors is 1024.
+
+       blk_queue_max_phys_segments(q, max_segments)
+               Maximum physical segments you can handle in a request. 128
+               default (driver limit). (See 3.2.2)
+
+       blk_queue_max_hw_segments(q, max_segments)
+               Maximum dma segments the hardware can handle in a request. 128
+               default (host adapter limit, after dma remapping).
+               (See 3.2.2)
+
+       blk_queue_max_segment_size(q, max_seg_size)
+               Maximum size of a clustered segment, 64kB default.
+
+       blk_queue_logical_block_size(q, logical_block_size)
+               Lowest possible sector size that the hardware can operate
+               on, 512 bytes default.
+
+New queue flags:
+
+       - QUEUE_FLAG_CLUSTER (see 3.2.2)
+       - QUEUE_FLAG_QUEUED (see 3.2.4)
+
+
+ii. High-mem i/o capabilities are now considered the default
+
+The generic bounce buffer logic, present in 2.4, where the block layer would
+by default copyin/out i/o requests on high-memory buffers to low-memory buffers
+assuming that the driver wouldn't be able to handle it directly, has been
+changed in 2.5. The bounce logic is now applied only for memory ranges
+for which the device cannot handle i/o. A driver can specify this by
+setting the queue bounce limit for the request queue for the device
+(blk_queue_bounce_limit()). This avoids the inefficiencies of the copyin/out
+where a device is capable of handling high memory i/o.
+
+In order to enable high-memory i/o where the device is capable of supporting
+it, the pci dma mapping routines and associated data structures have now been
+modified to accomplish a direct page -> bus translation, without requiring
+a virtual address mapping (unlike the earlier scheme of virtual address
+-> bus translation). So this works uniformly for high-memory pages (which
+do not have a corresponding kernel virtual address space mapping) and
+low-memory pages.
+
+Note: Please refer to Documentation/DMA-API-HOWTO.txt for a discussion
+on PCI high mem DMA aspects and mapping of scatter gather lists, and support
+for 64 bit PCI.
+
+Special handling is required only for cases where i/o needs to happen on
+pages at physical memory addresses beyond what the device can support. In these
+cases, a bounce bio representing a buffer from the supported memory range
+is used for performing the i/o with copyin/copyout as needed depending on
+the type of the operation.  For example, in case of a read operation, the
+data read has to be copied to the original buffer on i/o completion, so a
+callback routine is set up to do this, while for write, the data is copied
+from the original buffer to the bounce buffer prior to issuing the
+operation. Since an original buffer may be in a high memory area that's not
+mapped in kernel virtual addr, a kmap operation may be required for
+performing the copy, and special care may be needed in the completion path
+as it may not be in irq context. Special care is also required (by way of
+GFP flags) when allocating bounce buffers, to avoid certain highmem
+deadlock possibilities.
+
+It is also possible that a bounce buffer may be allocated from high-memory
+area that's not mapped in kernel virtual addr, but within the range that the
+device can use directly; so the bounce page may need to be kmapped during
+copy operations. [Note: This does not hold in the current implementation,
+though]
+
+There are some situations when pages from high memory may need to
+be kmapped, even if bounce buffers are not necessary. For example a device
+may need to abort DMA operations and revert to PIO for the transfer, in
+which case a virtual mapping of the page is required. For SCSI it is also
+done in some scenarios where the low level driver cannot be trusted to
+handle a single sg entry correctly. The driver is expected to perform the
+kmaps as needed on such occasions as appropriate. A driver could also use
+the blk_queue_bounce() routine on its own to bounce highmem i/o to low
+memory for specific requests if so desired.
+
+iii. The i/o scheduler algorithm itself can be replaced/set as appropriate
+
+As in 2.4, it is possible to plugin a brand new i/o scheduler for a particular
+queue or pick from (copy) existing generic schedulers and replace/override
+certain portions of it. The 2.5 rewrite provides improved modularization
+of the i/o scheduler. There are more pluggable callbacks, e.g for init,
+add request, extract request, which makes it possible to abstract specific
+i/o scheduling algorithm aspects and details outside of the generic loop.
+It also makes it possible to completely hide the implementation details of
+the i/o scheduler from block drivers.
+
+I/O scheduler wrappers are to be used instead of accessing the queue directly.
+See section 4. The I/O scheduler for details.
+
+1.2 Tuning Based on High level code capabilities
+------------------------------------------------
+
+i. Application capabilities for raw i/o
+
+This comes from some of the high-performance database/middleware
+requirements where an application prefers to make its own i/o scheduling
+decisions based on an understanding of the access patterns and i/o
+characteristics
+
+ii. High performance filesystems or other higher level kernel code's
+capabilities
+
+Kernel components like filesystems could also take their own i/o scheduling
+decisions for optimizing performance. Journalling filesystems may need
+some control over i/o ordering.
+
+What kind of support exists at the generic block layer for this ?
+
+The flags and rw fields in the bio structure can be used for some tuning
+from above e.g indicating that an i/o is just a readahead request, or priority
+settings (currently unused). As far as user applications are concerned they
+would need an additional mechanism either via open flags or ioctls, or some
+other upper level mechanism to communicate such settings to block.
+
+1.2.1 Request Priority/Latency
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Todo/Under discussion::
+
+  Arjan's proposed request priority scheme allows higher levels some broad
+  control (high/med/low) over the priority  of an i/o request vs other pending
+  requests in the queue. For example it allows reads for bringing in an
+  executable page on demand to be given a higher priority over pending write
+  requests which haven't aged too much on the queue. Potentially this priority
+  could even be exposed to applications in some manner, providing higher level
+  tunability. Time based aging avoids starvation of lower priority
+  requests. Some bits in the bi_opf flags field in the bio structure are
+  intended to be used for this priority information.
+
+
+1.3 Direct Access to Low level Device/Driver Capabilities (Bypass mode)
+-----------------------------------------------------------------------
+
+(e.g Diagnostics, Systems Management)
+
+There are situations where high-level code needs to have direct access to
+the low level device capabilities or requires the ability to issue commands
+to the device bypassing some of the intermediate i/o layers.
+These could, for example, be special control commands issued through ioctl
+interfaces, or could be raw read/write commands that stress the drive's
+capabilities for certain kinds of fitness tests. Having direct interfaces at
+multiple levels without having to pass through upper layers makes
+it possible to perform bottom up validation of the i/o path, layer by
+layer, starting from the media.
+
+The normal i/o submission interfaces, e.g submit_bio, could be bypassed
+for specially crafted requests which such ioctl or diagnostics
+interfaces would typically use, and the elevator add_request routine
+can instead be used to directly insert such requests in the queue or preferably
+the blk_do_rq routine can be used to place the request on the queue and
+wait for completion. Alternatively, sometimes the caller might just
+invoke a lower level driver specific interface with the request as a
+parameter.
+
+If the request is a means for passing on special information associated with
+the command, then such information is associated with the request->special
+field (rather than misuse the request->buffer field which is meant for the
+request data buffer's virtual mapping).
+
+For passing request data, the caller must build up a bio descriptor
+representing the concerned memory buffer if the underlying driver interprets
+bio segments or uses the block layer end*request* functions for i/o
+completion. Alternatively one could directly use the request->buffer field to
+specify the virtual address of the buffer, if the driver expects buffer
+addresses passed in this way and ignores bio entries for the request type
+involved. In the latter case, the driver would modify and manage the
+request->buffer, request->sector and request->nr_sectors or
+request->current_nr_sectors fields itself rather than using the block layer
+end_request or end_that_request_first completion interfaces.
+(See 2.3 or Documentation/block/request.rst for a brief explanation of
+the request structure fields)
+
+::
+
+  [TBD: end_that_request_last should be usable even in this case;
+  Perhaps an end_that_direct_request_first routine could be implemented to make
+  handling direct requests easier for such drivers; Also for drivers that
+  expect bios, a helper function could be provided for setting up a bio
+  corresponding to a data buffer]
+
+  <JENS: I dont understand the above, why is end_that_request_first() not
+  usable? Or _last for that matter. I must be missing something>
+
+  <SUP: What I meant here was that if the request doesn't have a bio, then
+   end_that_request_first doesn't modify nr_sectors or current_nr_sectors,
+   and hence can't be used for advancing request state settings on the
+   completion of partial transfers. The driver has to modify these fields
+   directly by hand.
+   This is because end_that_request_first only iterates over the bio list,
+   and always returns 0 if there are none associated with the request.
+   _last works OK in this case, and is not a problem, as I mentioned earlier
+  >
+
+1.3.1 Pre-built Commands
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+A request can be created with a pre-built custom command  to be sent directly
+to the device. The cmd block in the request structure has room for filling
+in the command bytes. (i.e rq->cmd is now 16 bytes in size, and meant for
+command pre-building, and the type of the request is now indicated
+through rq->flags instead of via rq->cmd)
+
+The request structure flags can be set up to indicate the type of request
+in such cases (REQ_PC: direct packet command passed to driver, REQ_BLOCK_PC:
+packet command issued via blk_do_rq, REQ_SPECIAL: special request).
+
+It can help to pre-build device commands for requests in advance.
+Drivers can now specify a request prepare function (q->prep_rq_fn) that the
+block layer would invoke to pre-build device commands for a given request,
+or perform other preparatory processing for the request. This is routine is
+called by elv_next_request(), i.e. typically just before servicing a request.
+(The prepare function would not be called for requests that have RQF_DONTPREP
+enabled)
+
+Aside:
+  Pre-building could possibly even be done early, i.e before placing the
+  request on the queue, rather than construct the command on the fly in the
+  driver while servicing the request queue when it may affect latencies in
+  interrupt context or responsiveness in general. One way to add early
+  pre-building would be to do it whenever we fail to merge on a request.
+  Now REQ_NOMERGE is set in the request flags to skip this one in the future,
+  which means that it will not change before we feed it to the device. So
+  the pre-builder hook can be invoked there.
+
+
+2. Flexible and generic but minimalist i/o structure/descriptor
+===============================================================
+
+2.1 Reason for a new structure and requirements addressed
+---------------------------------------------------------
+
+Prior to 2.5, buffer heads were used as the unit of i/o at the generic block
+layer, and the low level request structure was associated with a chain of
+buffer heads for a contiguous i/o request. This led to certain inefficiencies
+when it came to large i/o requests and readv/writev style operations, as it
+forced such requests to be broken up into small chunks before being passed
+on to the generic block layer, only to be merged by the i/o scheduler
+when the underlying device was capable of handling the i/o in one shot.
+Also, using the buffer head as an i/o structure for i/os that didn't originate
+from the buffer cache unnecessarily added to the weight of the descriptors
+which were generated for each such chunk.
+
+The following were some of the goals and expectations considered in the
+redesign of the block i/o data structure in 2.5.
+
+1.  Should be appropriate as a descriptor for both raw and buffered i/o  -
+    avoid cache related fields which are irrelevant in the direct/page i/o path,
+    or filesystem block size alignment restrictions which may not be relevant
+    for raw i/o.
+2.  Ability to represent high-memory buffers (which do not have a virtual
+    address mapping in kernel address space).
+3.  Ability to represent large i/os w/o unnecessarily breaking them up (i.e
+    greater than PAGE_SIZE chunks in one shot)
+4.  At the same time, ability to retain independent identity of i/os from
+    different sources or i/o units requiring individual completion (e.g. for
+    latency reasons)
+5.  Ability to represent an i/o involving multiple physical memory segments
+    (including non-page aligned page fragments, as specified via readv/writev)
+    without unnecessarily breaking it up, if the underlying device is capable of
+    handling it.
+6.  Preferably should be based on a memory descriptor structure that can be
+    passed around different types of subsystems or layers, maybe even
+    networking, without duplication or extra copies of data/descriptor fields
+    themselves in the process
+7.  Ability to handle the possibility of splits/merges as the structure passes
+    through layered drivers (lvm, md, evms), with minimal overhead.
+
+The solution was to define a new structure (bio)  for the block layer,
+instead of using the buffer head structure (bh) directly, the idea being
+avoidance of some associated baggage and limitations. The bio structure
+is uniformly used for all i/o at the block layer ; it forms a part of the
+bh structure for buffered i/o, and in the case of raw/direct i/o kiobufs are
+mapped to bio structures.
+
+2.2 The bio struct
+------------------
+
+The bio structure uses a vector representation pointing to an array of tuples
+of <page, offset, len> to describe the i/o buffer, and has various other
+fields describing i/o parameters and state that needs to be maintained for
+performing the i/o.
+
+Notice that this representation means that a bio has no virtual address
+mapping at all (unlike buffer heads).
+
+::
+
+  struct bio_vec {
+       struct page     *bv_page;
+       unsigned short  bv_len;
+       unsigned short  bv_offset;
+  };
+
+  /*
+   * main unit of I/O for the block layer and lower layers (ie drivers)
+   */
+  struct bio {
+       struct bio          *bi_next;    /* request queue link */
+       struct block_device *bi_bdev;   /* target device */
+       unsigned long       bi_flags;    /* status, command, etc */
+       unsigned long       bi_opf;       /* low bits: r/w, high: priority */
+
+       unsigned int    bi_vcnt;     /* how may bio_vec's */
+       struct bvec_iter        bi_iter;        /* current index into bio_vec array */
+
+       unsigned int    bi_size;     /* total size in bytes */
+       unsigned short  bi_hw_segments; /* segments after DMA remapping */
+       unsigned int    bi_max;      /* max bio_vecs we can hold
+                                        used as index into pool */
+       struct bio_vec   *bi_io_vec;  /* the actual vec list */
+       bio_end_io_t    *bi_end_io;  /* bi_end_io (bio) */
+       atomic_t                bi_cnt;      /* pin count: free when it hits zero */
+       void             *bi_private;
+  };
+
+With this multipage bio design:
+
+- Large i/os can be sent down in one go using a bio_vec list consisting
+  of an array of <page, offset, len> fragments (similar to the way fragments
+  are represented in the zero-copy network code)
+- Splitting of an i/o request across multiple devices (as in the case of
+  lvm or raid) is achieved by cloning the bio (where the clone points to
+  the same bi_io_vec array, but with the index and size accordingly modified)
+- A linked list of bios is used as before for unrelated merges [#]_ - this
+  avoids reallocs and makes independent completions easier to handle.
+- Code that traverses the req list can find all the segments of a bio
+  by using rq_for_each_segment.  This handles the fact that a request
+  has multiple bios, each of which can have multiple segments.
+- Drivers which can't process a large bio in one shot can use the bi_iter
+  field to keep track of the next bio_vec entry to process.
+  (e.g a 1MB bio_vec needs to be handled in max 128kB chunks for IDE)
+  [TBD: Should preferably also have a bi_voffset and bi_vlen to avoid modifying
+  bi_offset an len fields]
+
+.. [#]
+
+       unrelated merges -- a request ends up containing two or more bios that
+       didn't originate from the same place.
+
+bi_end_io() i/o callback gets called on i/o completion of the entire bio.
+
+At a lower level, drivers build a scatter gather list from the merged bios.
+The scatter gather list is in the form of an array of <page, offset, len>
+entries with their corresponding dma address mappings filled in at the
+appropriate time. As an optimization, contiguous physical pages can be
+covered by a single entry where <page> refers to the first page and <len>
+covers the range of pages (up to 16 contiguous pages could be covered this
+way). There is a helper routine (blk_rq_map_sg) which drivers can use to build
+the sg list.
+
+Note: Right now the only user of bios with more than one page is ll_rw_kio,
+which in turn means that only raw I/O uses it (direct i/o may not work
+right now). The intent however is to enable clustering of pages etc to
+become possible. The pagebuf abstraction layer from SGI also uses multi-page
+bios, but that is currently not included in the stock development kernels.
+The same is true of Andrew Morton's work-in-progress multipage bio writeout
+and readahead patches.
+
+2.3 Changes in the Request Structure
+------------------------------------
+
+The request structure is the structure that gets passed down to low level
+drivers. The block layer make_request function builds up a request structure,
+places it on the queue and invokes the drivers request_fn. The driver makes
+use of block layer helper routine elv_next_request to pull the next request
+off the queue. Control or diagnostic functions might bypass block and directly
+invoke underlying driver entry points passing in a specially constructed
+request structure.
+
+Only some relevant fields (mainly those which changed or may be referred
+to in some of the discussion here) are listed below, not necessarily in
+the order in which they occur in the structure (see include/linux/blkdev.h)
+Refer to Documentation/block/request.rst for details about all the request
+structure fields and a quick reference about the layers which are
+supposed to use or modify those fields::
+
+  struct request {
+       struct list_head queuelist;  /* Not meant to be directly accessed by
+                                       the driver.
+                                       Used by q->elv_next_request_fn
+                                       rq->queue is gone
+                                       */
+       .
+       .
+       unsigned char cmd[16]; /* prebuilt command data block */
+       unsigned long flags;   /* also includes earlier rq->cmd settings */
+       .
+       .
+       sector_t sector; /* this field is now of type sector_t instead of int
+                           preparation for 64 bit sectors */
+       .
+       .
+
+       /* Number of scatter-gather DMA addr+len pairs after
+        * physical address coalescing is performed.
+        */
+       unsigned short nr_phys_segments;
+
+       /* Number of scatter-gather addr+len pairs after
+        * physical and DMA remapping hardware coalescing is performed.
+        * This is the number of scatter-gather entries the driver
+        * will actually have to deal with after DMA mapping is done.
+        */
+       unsigned short nr_hw_segments;
+
+       /* Various sector counts */
+       unsigned long nr_sectors;  /* no. of sectors left: driver modifiable */
+       unsigned long hard_nr_sectors;  /* block internal copy of above */
+       unsigned int current_nr_sectors; /* no. of sectors left in the
+                                          current segment:driver modifiable */
+       unsigned long hard_cur_sectors; /* block internal copy of the above */
+       .
+       .
+       int tag;        /* command tag associated with request */
+       void *special;  /* same as before */
+       char *buffer;   /* valid only for low memory buffers up to
+                        current_nr_sectors */
+       .
+       .
+       struct bio *bio, *biotail;  /* bio list instead of bh */
+       struct request_list *rl;
+  }
+
+See the req_ops and req_flag_bits definitions for an explanation of the various
+flags available. Some bits are used by the block layer or i/o scheduler.
+
+The behaviour of the various sector counts are almost the same as before,
+except that since we have multi-segment bios, current_nr_sectors refers
+to the numbers of sectors in the current segment being processed which could
+be one of the many segments in the current bio (i.e i/o completion unit).
+The nr_sectors value refers to the total number of sectors in the whole
+request that remain to be transferred (no change). The purpose of the
+hard_xxx values is for block to remember these counts every time it hands
+over the request to the driver. These values are updated by block on
+end_that_request_first, i.e. every time the driver completes a part of the
+transfer and invokes block end*request helpers to mark this. The
+driver should not modify these values. The block layer sets up the
+nr_sectors and current_nr_sectors fields (based on the corresponding
+hard_xxx values and the number of bytes transferred) and updates it on
+every transfer that invokes end_that_request_first. It does the same for the
+buffer, bio, bio->bi_iter fields too.
+
+The buffer field is just a virtual address mapping of the current segment
+of the i/o buffer in cases where the buffer resides in low-memory. For high
+memory i/o, this field is not valid and must not be used by drivers.
+
+Code that sets up its own request structures and passes them down to
+a driver needs to be careful about interoperation with the block layer helper
+functions which the driver uses. (Section 1.3)
+
+3. Using bios
+=============
+
+3.1 Setup/Teardown
+------------------
+
+There are routines for managing the allocation, and reference counting, and
+freeing of bios (bio_alloc, bio_get, bio_put).
+
+This makes use of Ingo Molnar's mempool implementation, which enables
+subsystems like bio to maintain their own reserve memory pools for guaranteed
+deadlock-free allocations during extreme VM load. For example, the VM
+subsystem makes use of the block layer to writeout dirty pages in order to be
+able to free up memory space, a case which needs careful handling. The
+allocation logic draws from the preallocated emergency reserve in situations
+where it cannot allocate through normal means. If the pool is empty and it
+can wait, then it would trigger action that would help free up memory or
+replenish the pool (without deadlocking) and wait for availability in the pool.
+If it is in IRQ context, and hence not in a position to do this, allocation
+could fail if the pool is empty. In general mempool always first tries to
+perform allocation without having to wait, even if it means digging into the
+pool as long it is not less that 50% full.
+
+On a free, memory is released to the pool or directly freed depending on
+the current availability in the pool. The mempool interface lets the
+subsystem specify the routines to be used for normal alloc and free. In the
+case of bio, these routines make use of the standard slab allocator.
+
+The caller of bio_alloc is expected to taken certain steps to avoid
+deadlocks, e.g. avoid trying to allocate more memory from the pool while
+already holding memory obtained from the pool.
+
+::
+
+  [TBD: This is a potential issue, though a rare possibility
+   in the bounce bio allocation that happens in the current code, since
+   it ends up allocating a second bio from the same pool while
+   holding the original bio ]
+
+Memory allocated from the pool should be released back within a limited
+amount of time (in the case of bio, that would be after the i/o is completed).
+This ensures that if part of the pool has been used up, some work (in this
+case i/o) must already be in progress and memory would be available when it
+is over. If allocating from multiple pools in the same code path, the order
+or hierarchy of allocation needs to be consistent, just the way one deals
+with multiple locks.
+
+The bio_alloc routine also needs to allocate the bio_vec_list (bvec_alloc())
+for a non-clone bio. There are the 6 pools setup for different size biovecs,
+so bio_alloc(gfp_mask, nr_iovecs) will allocate a vec_list of the
+given size from these slabs.
+
+The bio_get() routine may be used to hold an extra reference on a bio prior
+to i/o submission, if the bio fields are likely to be accessed after the
+i/o is issued (since the bio may otherwise get freed in case i/o completion
+happens in the meantime).
+
+The bio_clone_fast() routine may be used to duplicate a bio, where the clone
+shares the bio_vec_list with the original bio (i.e. both point to the
+same bio_vec_list). This would typically be used for splitting i/o requests
+in lvm or md.
+
+3.2 Generic bio helper Routines
+-------------------------------
+
+3.2.1 Traversing segments and completion units in a request
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The macro rq_for_each_segment() should be used for traversing the bios
+in the request list (drivers should avoid directly trying to do it
+themselves). Using these helpers should also make it easier to cope
+with block changes in the future.
+
+::
+
+       struct req_iterator iter;
+       rq_for_each_segment(bio_vec, rq, iter)
+               /* bio_vec is now current segment */
+
+I/O completion callbacks are per-bio rather than per-segment, so drivers
+that traverse bio chains on completion need to keep that in mind. Drivers
+which don't make a distinction between segments and completion units would
+need to be reorganized to support multi-segment bios.
+
+3.2.2 Setting up DMA scatterlists
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The blk_rq_map_sg() helper routine would be used for setting up scatter
+gather lists from a request, so a driver need not do it on its own.
+
+       nr_segments = blk_rq_map_sg(q, rq, scatterlist);
+
+The helper routine provides a level of abstraction which makes it easier
+to modify the internals of request to scatterlist conversion down the line
+without breaking drivers. The blk_rq_map_sg routine takes care of several
+things like collapsing physically contiguous segments (if QUEUE_FLAG_CLUSTER
+is set) and correct segment accounting to avoid exceeding the limits which
+the i/o hardware can handle, based on various queue properties.
+
+- Prevents a clustered segment from crossing a 4GB mem boundary
+- Avoids building segments that would exceed the number of physical
+  memory segments that the driver can handle (phys_segments) and the
+  number that the underlying hardware can handle at once, accounting for
+  DMA remapping (hw_segments)  (i.e. IOMMU aware limits).
+
+Routines which the low level driver can use to set up the segment limits:
+
+blk_queue_max_hw_segments() : Sets an upper limit of the maximum number of
+hw data segments in a request (i.e. the maximum number of address/length
+pairs the host adapter can actually hand to the device at once)
+
+blk_queue_max_phys_segments() : Sets an upper limit on the maximum number
+of physical data segments in a request (i.e. the largest sized scatter list
+a driver could handle)
+
+3.2.3 I/O completion
+^^^^^^^^^^^^^^^^^^^^
+
+The existing generic block layer helper routines end_request,
+end_that_request_first and end_that_request_last can be used for i/o
+completion (and setting things up so the rest of the i/o or the next
+request can be kicked of) as before. With the introduction of multi-page
+bio support, end_that_request_first requires an additional argument indicating
+the number of sectors completed.
+
+3.2.4 Implications for drivers that do not interpret bios
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+(don't handle multiple segments)
+
+Drivers that do not interpret bios e.g those which do not handle multiple
+segments and do not support i/o into high memory addresses (require bounce
+buffers) and expect only virtually mapped buffers, can access the rq->buffer
+field. As before the driver should use current_nr_sectors to determine the
+size of remaining data in the current segment (that is the maximum it can
+transfer in one go unless it interprets segments), and rely on the block layer
+end_request, or end_that_request_first/last to take care of all accounting
+and transparent mapping of the next bio segment when a segment boundary
+is crossed on completion of a transfer. (The end*request* functions should
+be used if only if the request has come down from block/bio path, not for
+direct access requests which only specify rq->buffer without a valid rq->bio)
+
+3.3 I/O Submission
+------------------
+
+The routine submit_bio() is used to submit a single io. Higher level i/o
+routines make use of this:
+
+(a) Buffered i/o:
+
+The routine submit_bh() invokes submit_bio() on a bio corresponding to the
+bh, allocating the bio if required. ll_rw_block() uses submit_bh() as before.
+
+(b) Kiobuf i/o (for raw/direct i/o):
+
+The ll_rw_kio() routine breaks up the kiobuf into page sized chunks and
+maps the array to one or more multi-page bios, issuing submit_bio() to
+perform the i/o on each of these.
+
+The embedded bh array in the kiobuf structure has been removed and no
+preallocation of bios is done for kiobufs. [The intent is to remove the
+blocks array as well, but it's currently in there to kludge around direct i/o.]
+Thus kiobuf allocation has switched back to using kmalloc rather than vmalloc.
+
+Todo/Observation:
+
+ A single kiobuf structure is assumed to correspond to a contiguous range
+ of data, so brw_kiovec() invokes ll_rw_kio for each kiobuf in a kiovec.
+ So right now it wouldn't work for direct i/o on non-contiguous blocks.
+ This is to be resolved.  The eventual direction is to replace kiobuf
+ by kvec's.
+
+ Badari Pulavarty has a patch to implement direct i/o correctly using
+ bio and kvec.
+
+
+(c) Page i/o:
+
+Todo/Under discussion:
+
+ Andrew Morton's multi-page bio patches attempt to issue multi-page
+ writeouts (and reads) from the page cache, by directly building up
+ large bios for submission completely bypassing the usage of buffer
+ heads. This work is still in progress.
+
+ Christoph Hellwig had some code that uses bios for page-io (rather than
+ bh). This isn't included in bio as yet. Christoph was also working on a
+ design for representing virtual/real extents as an entity and modifying
+ some of the address space ops interfaces to utilize this abstraction rather
+ than buffer_heads. (This is somewhat along the lines of the SGI XFS pagebuf
+ abstraction, but intended to be as lightweight as possible).
+
+(d) Direct access i/o:
+
+Direct access requests that do not contain bios would be submitted differently
+as discussed earlier in section 1.3.
+
+Aside:
+
+  Kvec i/o:
+
+  Ben LaHaise's aio code uses a slightly different structure instead
+  of kiobufs, called a kvec_cb. This contains an array of <page, offset, len>
+  tuples (very much like the networking code), together with a callback function
+  and data pointer. This is embedded into a brw_cb structure when passed
+  to brw_kvec_async().
+
+  Now it should be possible to directly map these kvecs to a bio. Just as while
+  cloning, in this case rather than PRE_BUILT bio_vecs, we set the bi_io_vec
+  array pointer to point to the veclet array in kvecs.
+
+  TBD: In order for this to work, some changes are needed in the way multi-page
+  bios are handled today. The values of the tuples in such a vector passed in
+  from higher level code should not be modified by the block layer in the course
+  of its request processing, since that would make it hard for the higher layer
+  to continue to use the vector descriptor (kvec) after i/o completes. Instead,
+  all such transient state should either be maintained in the request structure,
+  and passed on in some way to the endio completion routine.
+
+
+4. The I/O scheduler
+====================
+
+I/O scheduler, a.k.a. elevator, is implemented in two layers.  Generic dispatch
+queue and specific I/O schedulers.  Unless stated otherwise, elevator is used
+to refer to both parts and I/O scheduler to specific I/O schedulers.
+
+Block layer implements generic dispatch queue in `block/*.c`.
+The generic dispatch queue is responsible for requeueing, handling non-fs
+requests and all other subtleties.
+
+Specific I/O schedulers are responsible for ordering normal filesystem
+requests.  They can also choose to delay certain requests to improve
+throughput or whatever purpose.  As the plural form indicates, there are
+multiple I/O schedulers.  They can be built as modules but at least one should
+be built inside the kernel.  Each queue can choose different one and can also
+change to another one dynamically.
+
+A block layer call to the i/o scheduler follows the convention elv_xxx(). This
+calls elevator_xxx_fn in the elevator switch (block/elevator.c). Oh, xxx
+and xxx might not match exactly, but use your imagination. If an elevator
+doesn't implement a function, the switch does nothing or some minimal house
+keeping work.
+
+4.1. I/O scheduler API
+----------------------
+
+The functions an elevator may implement are: (* are mandatory)
+
+=============================== ================================================
+elevator_merge_fn              called to query requests for merge with a bio
+
+elevator_merge_req_fn          called when two requests get merged. the one
+                               which gets merged into the other one will be
+                               never seen by I/O scheduler again. IOW, after
+                               being merged, the request is gone.
+
+elevator_merged_fn             called when a request in the scheduler has been
+                               involved in a merge. It is used in the deadline
+                               scheduler for example, to reposition the request
+                               if its sorting order has changed.
+
+elevator_allow_merge_fn                called whenever the block layer determines
+                               that a bio can be merged into an existing
+                               request safely. The io scheduler may still
+                               want to stop a merge at this point if it
+                               results in some sort of conflict internally,
+                               this hook allows it to do that. Note however
+                               that two *requests* can still be merged at later
+                               time. Currently the io scheduler has no way to
+                               prevent that. It can only learn about the fact
+                               from elevator_merge_req_fn callback.
+
+elevator_dispatch_fn*          fills the dispatch queue with ready requests.
+                               I/O schedulers are free to postpone requests by
+                               not filling the dispatch queue unless @force
+                               is non-zero.  Once dispatched, I/O schedulers
+                               are not allowed to manipulate the requests -
+                               they belong to generic dispatch queue.
+
+elevator_add_req_fn*           called to add a new request into the scheduler
+
+elevator_former_req_fn
+elevator_latter_req_fn         These return the request before or after the
+                               one specified in disk sort order. Used by the
+                               block layer to find merge possibilities.
+
+elevator_completed_req_fn      called when a request is completed.
+
+elevator_set_req_fn
+elevator_put_req_fn            Must be used to allocate and free any elevator
+                               specific storage for a request.
+
+elevator_activate_req_fn       Called when device driver first sees a request.
+                               I/O schedulers can use this callback to
+                               determine when actual execution of a request
+                               starts.
+elevator_deactivate_req_fn     Called when device driver decides to delay
+                               a request by requeueing it.
+
+elevator_init_fn*
+elevator_exit_fn               Allocate and free any elevator specific storage
+                               for a queue.
+=============================== ================================================
+
+4.2 Request flows seen by I/O schedulers
+----------------------------------------
+
+All requests seen by I/O schedulers strictly follow one of the following three
+flows.
+
+ set_req_fn ->
+
+ i.   add_req_fn -> (merged_fn ->)* -> dispatch_fn -> activate_req_fn ->
+      (deactivate_req_fn -> activate_req_fn ->)* -> completed_req_fn
+ ii.  add_req_fn -> (merged_fn ->)* -> merge_req_fn
+ iii. [none]
+
+ -> put_req_fn
+
+4.3 I/O scheduler implementation
+--------------------------------
+
+The generic i/o scheduler algorithm attempts to sort/merge/batch requests for
+optimal disk scan and request servicing performance (based on generic
+principles and device capabilities), optimized for:
+
+i.   improved throughput
+ii.  improved latency
+iii. better utilization of h/w & CPU time
+
+Characteristics:
+
+i. Binary tree
+AS and deadline i/o schedulers use red black binary trees for disk position
+sorting and searching, and a fifo linked list for time-based searching. This
+gives good scalability and good availability of information. Requests are
+almost always dispatched in disk sort order, so a cache is kept of the next
+request in sort order to prevent binary tree lookups.
+
+This arrangement is not a generic block layer characteristic however, so
+elevators may implement queues as they please.
+
+ii. Merge hash
+AS and deadline use a hash table indexed by the last sector of a request. This
+enables merging code to quickly look up "back merge" candidates, even when
+multiple I/O streams are being performed at once on one disk.
+
+"Front merges", a new request being merged at the front of an existing request,
+are far less common than "back merges" due to the nature of most I/O patterns.
+Front merges are handled by the binary trees in AS and deadline schedulers.
+
+iii. Plugging the queue to batch requests in anticipation of opportunities for
+     merge/sort optimizations
+
+Plugging is an approach that the current i/o scheduling algorithm resorts to so
+that it collects up enough requests in the queue to be able to take
+advantage of the sorting/merging logic in the elevator. If the
+queue is empty when a request comes in, then it plugs the request queue
+(sort of like plugging the bath tub of a vessel to get fluid to build up)
+till it fills up with a few more requests, before starting to service
+the requests. This provides an opportunity to merge/sort the requests before
+passing them down to the device. There are various conditions when the queue is
+unplugged (to open up the flow again), either through a scheduled task or
+could be on demand. For example wait_on_buffer sets the unplugging going
+through sync_buffer() running blk_run_address_space(mapping). Or the caller
+can do it explicity through blk_unplug(bdev). So in the read case,
+the queue gets explicitly unplugged as part of waiting for completion on that
+buffer.
+
+Aside:
+  This is kind of controversial territory, as it's not clear if plugging is
+  always the right thing to do. Devices typically have their own queues,
+  and allowing a big queue to build up in software, while letting the device be
+  idle for a while may not always make sense. The trick is to handle the fine
+  balance between when to plug and when to open up. Also now that we have
+  multi-page bios being queued in one shot, we may not need to wait to merge
+  a big request from the broken up pieces coming by.
+
+4.4 I/O contexts
+----------------
+
+I/O contexts provide a dynamically allocated per process data area. They may
+be used in I/O schedulers, and in the block layer (could be used for IO statis,
+priorities for example). See `*io_context` in block/ll_rw_blk.c, and as-iosched.c
+for an example of usage in an i/o scheduler.
+
+
+5. Scalability related changes
+==============================
+
+5.1 Granular Locking: io_request_lock replaced by a per-queue lock
+------------------------------------------------------------------
+
+The global io_request_lock has been removed as of 2.5, to avoid
+the scalability bottleneck it was causing, and has been replaced by more
+granular locking. The request queue structure has a pointer to the
+lock to be used for that queue. As a result, locking can now be
+per-queue, with a provision for sharing a lock across queues if
+necessary (e.g the scsi layer sets the queue lock pointers to the
+corresponding adapter lock, which results in a per host locking
+granularity). The locking semantics are the same, i.e. locking is
+still imposed by the block layer, grabbing the lock before
+request_fn execution which it means that lots of older drivers
+should still be SMP safe. Drivers are free to drop the queue
+lock themselves, if required. Drivers that explicitly used the
+io_request_lock for serialization need to be modified accordingly.
+Usually it's as easy as adding a global lock::
+
+       static DEFINE_SPINLOCK(my_driver_lock);
+
+and passing the address to that lock to blk_init_queue().
+
+5.2 64 bit sector numbers (sector_t prepares for 64 bit support)
+----------------------------------------------------------------
+
+The sector number used in the bio structure has been changed to sector_t,
+which could be defined as 64 bit in preparation for 64 bit sector support.
+
+6. Other Changes/Implications
+=============================
+
+6.1 Partition re-mapping handled by the generic block layer
+-----------------------------------------------------------
+
+In 2.5 some of the gendisk/partition related code has been reorganized.
+Now the generic block layer performs partition-remapping early and thus
+provides drivers with a sector number relative to whole device, rather than
+having to take partition number into account in order to arrive at the true
+sector number. The routine blk_partition_remap() is invoked by
+generic_make_request even before invoking the queue specific make_request_fn,
+so the i/o scheduler also gets to operate on whole disk sector numbers. This
+should typically not require changes to block drivers, it just never gets
+to invoke its own partition sector offset calculations since all bios
+sent are offset from the beginning of the device.
+
+
+7. A Few Tips on Migration of older drivers
+===========================================
+
+Old-style drivers that just use CURRENT and ignores clustered requests,
+may not need much change.  The generic layer will automatically handle
+clustered requests, multi-page bios, etc for the driver.
+
+For a low performance driver or hardware that is PIO driven or just doesn't
+support scatter-gather changes should be minimal too.
+
+The following are some points to keep in mind when converting old drivers
+to bio.
+
+Drivers should use elv_next_request to pick up requests and are no longer
+supposed to handle looping directly over the request list.
+(struct request->queue has been removed)
+
+Now end_that_request_first takes an additional number_of_sectors argument.
+It used to handle always just the first buffer_head in a request, now
+it will loop and handle as many sectors (on a bio-segment granularity)
+as specified.
+
+Now bh->b_end_io is replaced by bio->bi_end_io, but most of the time the
+right thing to use is bio_endio(bio) instead.
+
+If the driver is dropping the io_request_lock from its request_fn strategy,
+then it just needs to replace that with q->queue_lock instead.
+
+As described in Sec 1.1, drivers can set max sector size, max segment size
+etc per queue now. Drivers that used to define their own merge functions i
+to handle things like this can now just use the blk_queue_* functions at
+blk_init_queue time.
+
+Drivers no longer have to map a {partition, sector offset} into the
+correct absolute location anymore, this is done by the block layer, so
+where a driver received a request ala this before::
+
+       rq->rq_dev = mk_kdev(3, 5);     /* /dev/hda5 */
+       rq->sector = 0;                 /* first sector on hda5 */
+
+it will now see::
+
+       rq->rq_dev = mk_kdev(3, 0);     /* /dev/hda */
+       rq->sector = 123128;            /* offset from start of disk */
+
+As mentioned, there is no virtual mapping of a bio. For DMA, this is
+not a problem as the driver probably never will need a virtual mapping.
+Instead it needs a bus mapping (dma_map_page for a single segment or
+use dma_map_sg for scatter gather) to be able to ship it to the driver. For
+PIO drivers (or drivers that need to revert to PIO transfer once in a
+while (IDE for example)), where the CPU is doing the actual data
+transfer a virtual mapping is needed. If the driver supports highmem I/O,
+(Sec 1.1, (ii) ) it needs to use kmap_atomic or similar to temporarily map
+a bio into the virtual address space.
+
+
+8. Prior/Related/Impacted patches
+=================================
+
+8.1. Earlier kiobuf patches (sct/axboe/chait/hch/mkp)
+-----------------------------------------------------
+
+- orig kiobuf & raw i/o patches (now in 2.4 tree)
+- direct kiobuf based i/o to devices (no intermediate bh's)
+- page i/o using kiobuf
+- kiobuf splitting for lvm (mkp)
+- elevator support for kiobuf request merging (axboe)
+
+8.2. Zero-copy networking (Dave Miller)
+---------------------------------------
+
+8.3. SGI XFS - pagebuf patches - use of kiobufs
+-----------------------------------------------
+8.4. Multi-page pioent patch for bio (Christoph Hellwig)
+--------------------------------------------------------
+8.5. Direct i/o implementation (Andrea Arcangeli) since 2.4.10-pre11
+--------------------------------------------------------------------
+8.6. Async i/o implementation patch (Ben LaHaise)
+-------------------------------------------------
+8.7. EVMS layering design (IBM EVMS team)
+-----------------------------------------
+8.8. Larger page cache size patch (Ben LaHaise) and Large page size (Daniel Phillips)
+-------------------------------------------------------------------------------------
+
+    => larger contiguous physical memory buffers
+
+8.9. VM reservations patch (Ben LaHaise)
+----------------------------------------
+8.10. Write clustering patches ? (Marcelo/Quintela/Riel ?)
+----------------------------------------------------------
+8.11. Block device in page cache patch (Andrea Archangeli) - now in 2.4.10+
+---------------------------------------------------------------------------
+8.12. Multiple block-size transfers for faster raw i/o (Shailabh Nagar, Badari)
+-------------------------------------------------------------------------------
+8.13  Priority based i/o scheduler - prepatches (Arjan van de Ven)
+------------------------------------------------------------------
+8.14  IDE Taskfile i/o patch (Andre Hedrick)
+--------------------------------------------
+8.15  Multi-page writeout and readahead patches (Andrew Morton)
+---------------------------------------------------------------
+8.16  Direct i/o patches for 2.5 using kvec and bio (Badari Pulavarthy)
+-----------------------------------------------------------------------
+
+9. Other References
+===================
+
+9.1 The Splice I/O Model
+------------------------
+
+Larry McVoy (and subsequent discussions on lkml, and Linus' comments - Jan 2001
+
+9.2 Discussions about kiobuf and bh design
+------------------------------------------
+
+On lkml between sct, linus, alan et al - Feb-March 2001 (many of the
+initial thoughts that led to bio were brought up in this discussion thread)
+
+9.3 Discussions on mempool on lkml - Dec 2001.
+----------------------------------------------
diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt
deleted file mode 100644 (file)
index 5a4a799..0000000
+++ /dev/null
@@ -1,1071 +0,0 @@
-       Notes on the Generic Block Layer Rewrite in Linux 2.5
-       =====================================================
-
-Notes Written on Jan 15, 2002:
-       Jens Axboe <jens.axboe@oracle.com>
-       Suparna Bhattacharya <suparna@in.ibm.com>
-
-Last Updated May 2, 2002
-September 2003: Updated I/O Scheduler portions
-       Nick Piggin <npiggin@kernel.dk>
-
-Introduction:
-
-These are some notes describing some aspects of the 2.5 block layer in the
-context of the bio rewrite. The idea is to bring out some of the key
-changes and a glimpse of the rationale behind those changes.
-
-Please mail corrections & suggestions to suparna@in.ibm.com.
-
-Credits:
----------
-
-2.5 bio rewrite:
-       Jens Axboe <jens.axboe@oracle.com>
-
-Many aspects of the generic block layer redesign were driven by and evolved
-over discussions, prior patches and the collective experience of several
-people. See sections 8 and 9 for a list of some related references.
-
-The following people helped with review comments and inputs for this
-document:
-       Christoph Hellwig <hch@infradead.org>
-       Arjan van de Ven <arjanv@redhat.com>
-       Randy Dunlap <rdunlap@xenotime.net>
-       Andre Hedrick <andre@linux-ide.org>
-
-The following people helped with fixes/contributions to the bio patches
-while it was still work-in-progress:
-       David S. Miller <davem@redhat.com>
-
-
-Description of Contents:
-------------------------
-
-1. Scope for tuning of logic to various needs
-  1.1 Tuning based on device or low level driver capabilities
-       - Per-queue parameters
-       - Highmem I/O support
-       - I/O scheduler modularization
-  1.2 Tuning based on high level requirements/capabilities
-       1.2.1 Request Priority/Latency
-  1.3 Direct access/bypass to lower layers for diagnostics and special
-      device operations
-       1.3.1 Pre-built commands
-2. New flexible and generic but minimalist i/o structure or descriptor
-   (instead of using buffer heads at the i/o layer)
-  2.1 Requirements/Goals addressed
-  2.2 The bio struct in detail (multi-page io unit)
-  2.3 Changes in the request structure
-3. Using bios
-  3.1 Setup/teardown (allocation, splitting)
-  3.2 Generic bio helper routines
-    3.2.1 Traversing segments and completion units in a request
-    3.2.2 Setting up DMA scatterlists
-    3.2.3 I/O completion
-    3.2.4 Implications for drivers that do not interpret bios (don't handle
-         multiple segments)
-  3.3 I/O submission
-4. The I/O scheduler
-5. Scalability related changes
-  5.1 Granular locking: Removal of io_request_lock
-  5.2 Prepare for transition to 64 bit sector_t
-6. Other Changes/Implications
-  6.1 Partition re-mapping handled by the generic block layer
-7. A few tips on migration of older drivers
-8. A list of prior/related/impacted patches/ideas
-9. Other References/Discussion Threads
-
----------------------------------------------------------------------------
-
-Bio Notes
---------
-
-Let us discuss the changes in the context of how some overall goals for the
-block layer are addressed.
-
-1. Scope for tuning the generic logic to satisfy various requirements
-
-The block layer design supports adaptable abstractions to handle common
-processing with the ability to tune the logic to an appropriate extent
-depending on the nature of the device and the requirements of the caller.
-One of the objectives of the rewrite was to increase the degree of tunability
-and to enable higher level code to utilize underlying device/driver
-capabilities to the maximum extent for better i/o performance. This is
-important especially in the light of ever improving hardware capabilities
-and application/middleware software designed to take advantage of these
-capabilities.
-
-1.1 Tuning based on low level device / driver capabilities
-
-Sophisticated devices with large built-in caches, intelligent i/o scheduling
-optimizations, high memory DMA support, etc may find some of the
-generic processing an overhead, while for less capable devices the
-generic functionality is essential for performance or correctness reasons.
-Knowledge of some of the capabilities or parameters of the device should be
-used at the generic block layer to take the right decisions on
-behalf of the driver.
-
-How is this achieved ?
-
-Tuning at a per-queue level:
-
-i. Per-queue limits/values exported to the generic layer by the driver
-
-Various parameters that the generic i/o scheduler logic uses are set at
-a per-queue level (e.g maximum request size, maximum number of segments in
-a scatter-gather list, logical block size)
-
-Some parameters that were earlier available as global arrays indexed by
-major/minor are now directly associated with the queue. Some of these may
-move into the block device structure in the future. Some characteristics
-have been incorporated into a queue flags field rather than separate fields
-in themselves.  There are blk_queue_xxx functions to set the parameters,
-rather than update the fields directly
-
-Some new queue property settings:
-
-       blk_queue_bounce_limit(q, u64 dma_address)
-               Enable I/O to highmem pages, dma_address being the
-               limit. No highmem default.
-
-       blk_queue_max_sectors(q, max_sectors)
-               Sets two variables that limit the size of the request.
-
-               - The request queue's max_sectors, which is a soft size in
-               units of 512 byte sectors, and could be dynamically varied
-               by the core kernel.
-
-               - The request queue's max_hw_sectors, which is a hard limit
-               and reflects the maximum size request a driver can handle
-               in units of 512 byte sectors.
-
-               The default for both max_sectors and max_hw_sectors is
-               255. The upper limit of max_sectors is 1024.
-
-       blk_queue_max_phys_segments(q, max_segments)
-               Maximum physical segments you can handle in a request. 128
-               default (driver limit). (See 3.2.2)
-
-       blk_queue_max_hw_segments(q, max_segments)
-               Maximum dma segments the hardware can handle in a request. 128
-               default (host adapter limit, after dma remapping).
-               (See 3.2.2)
-
-       blk_queue_max_segment_size(q, max_seg_size)
-               Maximum size of a clustered segment, 64kB default.
-
-       blk_queue_logical_block_size(q, logical_block_size)
-               Lowest possible sector size that the hardware can operate
-               on, 512 bytes default.
-
-New queue flags:
-
-       QUEUE_FLAG_CLUSTER (see 3.2.2)
-       QUEUE_FLAG_QUEUED (see 3.2.4)
-
-
-ii. High-mem i/o capabilities are now considered the default
-
-The generic bounce buffer logic, present in 2.4, where the block layer would
-by default copyin/out i/o requests on high-memory buffers to low-memory buffers
-assuming that the driver wouldn't be able to handle it directly, has been
-changed in 2.5. The bounce logic is now applied only for memory ranges
-for which the device cannot handle i/o. A driver can specify this by
-setting the queue bounce limit for the request queue for the device
-(blk_queue_bounce_limit()). This avoids the inefficiencies of the copyin/out
-where a device is capable of handling high memory i/o.
-
-In order to enable high-memory i/o where the device is capable of supporting
-it, the pci dma mapping routines and associated data structures have now been
-modified to accomplish a direct page -> bus translation, without requiring
-a virtual address mapping (unlike the earlier scheme of virtual address
--> bus translation). So this works uniformly for high-memory pages (which
-do not have a corresponding kernel virtual address space mapping) and
-low-memory pages.
-
-Note: Please refer to Documentation/DMA-API-HOWTO.txt for a discussion
-on PCI high mem DMA aspects and mapping of scatter gather lists, and support
-for 64 bit PCI.
-
-Special handling is required only for cases where i/o needs to happen on
-pages at physical memory addresses beyond what the device can support. In these
-cases, a bounce bio representing a buffer from the supported memory range
-is used for performing the i/o with copyin/copyout as needed depending on
-the type of the operation.  For example, in case of a read operation, the
-data read has to be copied to the original buffer on i/o completion, so a
-callback routine is set up to do this, while for write, the data is copied
-from the original buffer to the bounce buffer prior to issuing the
-operation. Since an original buffer may be in a high memory area that's not
-mapped in kernel virtual addr, a kmap operation may be required for
-performing the copy, and special care may be needed in the completion path
-as it may not be in irq context. Special care is also required (by way of
-GFP flags) when allocating bounce buffers, to avoid certain highmem
-deadlock possibilities.
-
-It is also possible that a bounce buffer may be allocated from high-memory
-area that's not mapped in kernel virtual addr, but within the range that the
-device can use directly; so the bounce page may need to be kmapped during
-copy operations. [Note: This does not hold in the current implementation,
-though]
-
-There are some situations when pages from high memory may need to
-be kmapped, even if bounce buffers are not necessary. For example a device
-may need to abort DMA operations and revert to PIO for the transfer, in
-which case a virtual mapping of the page is required. For SCSI it is also
-done in some scenarios where the low level driver cannot be trusted to
-handle a single sg entry correctly. The driver is expected to perform the
-kmaps as needed on such occasions as appropriate. A driver could also use
-the blk_queue_bounce() routine on its own to bounce highmem i/o to low
-memory for specific requests if so desired.
-
-iii. The i/o scheduler algorithm itself can be replaced/set as appropriate
-
-As in 2.4, it is possible to plugin a brand new i/o scheduler for a particular
-queue or pick from (copy) existing generic schedulers and replace/override
-certain portions of it. The 2.5 rewrite provides improved modularization
-of the i/o scheduler. There are more pluggable callbacks, e.g for init,
-add request, extract request, which makes it possible to abstract specific
-i/o scheduling algorithm aspects and details outside of the generic loop.
-It also makes it possible to completely hide the implementation details of
-the i/o scheduler from block drivers.
-
-I/O scheduler wrappers are to be used instead of accessing the queue directly.
-See section 4. The I/O scheduler for details.
-
-1.2 Tuning Based on High level code capabilities
-
-i. Application capabilities for raw i/o
-
-This comes from some of the high-performance database/middleware
-requirements where an application prefers to make its own i/o scheduling
-decisions based on an understanding of the access patterns and i/o
-characteristics
-
-ii. High performance filesystems or other higher level kernel code's
-capabilities
-
-Kernel components like filesystems could also take their own i/o scheduling
-decisions for optimizing performance. Journalling filesystems may need
-some control over i/o ordering.
-
-What kind of support exists at the generic block layer for this ?
-
-The flags and rw fields in the bio structure can be used for some tuning
-from above e.g indicating that an i/o is just a readahead request, or priority
-settings (currently unused). As far as user applications are concerned they
-would need an additional mechanism either via open flags or ioctls, or some
-other upper level mechanism to communicate such settings to block.
-
-1.2.1 Request Priority/Latency
-
-Todo/Under discussion:
-Arjan's proposed request priority scheme allows higher levels some broad
-  control (high/med/low) over the priority  of an i/o request vs other pending
-  requests in the queue. For example it allows reads for bringing in an
-  executable page on demand to be given a higher priority over pending write
-  requests which haven't aged too much on the queue. Potentially this priority
-  could even be exposed to applications in some manner, providing higher level
-  tunability. Time based aging avoids starvation of lower priority
-  requests. Some bits in the bi_opf flags field in the bio structure are
-  intended to be used for this priority information.
-
-
-1.3 Direct Access to Low level Device/Driver Capabilities (Bypass mode)
-    (e.g Diagnostics, Systems Management)
-
-There are situations where high-level code needs to have direct access to
-the low level device capabilities or requires the ability to issue commands
-to the device bypassing some of the intermediate i/o layers.
-These could, for example, be special control commands issued through ioctl
-interfaces, or could be raw read/write commands that stress the drive's
-capabilities for certain kinds of fitness tests. Having direct interfaces at
-multiple levels without having to pass through upper layers makes
-it possible to perform bottom up validation of the i/o path, layer by
-layer, starting from the media.
-
-The normal i/o submission interfaces, e.g submit_bio, could be bypassed
-for specially crafted requests which such ioctl or diagnostics
-interfaces would typically use, and the elevator add_request routine
-can instead be used to directly insert such requests in the queue or preferably
-the blk_do_rq routine can be used to place the request on the queue and
-wait for completion. Alternatively, sometimes the caller might just
-invoke a lower level driver specific interface with the request as a
-parameter.
-
-If the request is a means for passing on special information associated with
-the command, then such information is associated with the request->special
-field (rather than misuse the request->buffer field which is meant for the
-request data buffer's virtual mapping).
-
-For passing request data, the caller must build up a bio descriptor
-representing the concerned memory buffer if the underlying driver interprets
-bio segments or uses the block layer end*request* functions for i/o
-completion. Alternatively one could directly use the request->buffer field to
-specify the virtual address of the buffer, if the driver expects buffer
-addresses passed in this way and ignores bio entries for the request type
-involved. In the latter case, the driver would modify and manage the
-request->buffer, request->sector and request->nr_sectors or
-request->current_nr_sectors fields itself rather than using the block layer
-end_request or end_that_request_first completion interfaces.
-(See 2.3 or Documentation/block/request.txt for a brief explanation of
-the request structure fields)
-
-[TBD: end_that_request_last should be usable even in this case;
-Perhaps an end_that_direct_request_first routine could be implemented to make
-handling direct requests easier for such drivers; Also for drivers that
-expect bios, a helper function could be provided for setting up a bio
-corresponding to a data buffer]
-
-<JENS: I dont understand the above, why is end_that_request_first() not
-usable? Or _last for that matter. I must be missing something>
-<SUP: What I meant here was that if the request doesn't have a bio, then
- end_that_request_first doesn't modify nr_sectors or current_nr_sectors,
- and hence can't be used for advancing request state settings on the
- completion of partial transfers. The driver has to modify these fields 
- directly by hand.
- This is because end_that_request_first only iterates over the bio list,
- and always returns 0 if there are none associated with the request.
- _last works OK in this case, and is not a problem, as I mentioned earlier
->
-
-1.3.1 Pre-built Commands
-
-A request can be created with a pre-built custom command  to be sent directly
-to the device. The cmd block in the request structure has room for filling
-in the command bytes. (i.e rq->cmd is now 16 bytes in size, and meant for
-command pre-building, and the type of the request is now indicated
-through rq->flags instead of via rq->cmd)
-
-The request structure flags can be set up to indicate the type of request
-in such cases (REQ_PC: direct packet command passed to driver, REQ_BLOCK_PC:
-packet command issued via blk_do_rq, REQ_SPECIAL: special request).
-
-It can help to pre-build device commands for requests in advance.
-Drivers can now specify a request prepare function (q->prep_rq_fn) that the
-block layer would invoke to pre-build device commands for a given request,
-or perform other preparatory processing for the request. This is routine is
-called by elv_next_request(), i.e. typically just before servicing a request.
-(The prepare function would not be called for requests that have RQF_DONTPREP
-enabled)
-
-Aside:
-  Pre-building could possibly even be done early, i.e before placing the
-  request on the queue, rather than construct the command on the fly in the
-  driver while servicing the request queue when it may affect latencies in
-  interrupt context or responsiveness in general. One way to add early
-  pre-building would be to do it whenever we fail to merge on a request.
-  Now REQ_NOMERGE is set in the request flags to skip this one in the future,
-  which means that it will not change before we feed it to the device. So
-  the pre-builder hook can be invoked there.
-
-
-2. Flexible and generic but minimalist i/o structure/descriptor.
-
-2.1 Reason for a new structure and requirements addressed
-
-Prior to 2.5, buffer heads were used as the unit of i/o at the generic block
-layer, and the low level request structure was associated with a chain of
-buffer heads for a contiguous i/o request. This led to certain inefficiencies
-when it came to large i/o requests and readv/writev style operations, as it
-forced such requests to be broken up into small chunks before being passed
-on to the generic block layer, only to be merged by the i/o scheduler
-when the underlying device was capable of handling the i/o in one shot.
-Also, using the buffer head as an i/o structure for i/os that didn't originate
-from the buffer cache unnecessarily added to the weight of the descriptors
-which were generated for each such chunk.
-
-The following were some of the goals and expectations considered in the
-redesign of the block i/o data structure in 2.5.
-
-i.  Should be appropriate as a descriptor for both raw and buffered i/o  -
-    avoid cache related fields which are irrelevant in the direct/page i/o path,
-    or filesystem block size alignment restrictions which may not be relevant
-    for raw i/o.
-ii. Ability to represent high-memory buffers (which do not have a virtual
-    address mapping in kernel address space).
-iii.Ability to represent large i/os w/o unnecessarily breaking them up (i.e
-    greater than PAGE_SIZE chunks in one shot)
-iv. At the same time, ability to retain independent identity of i/os from
-    different sources or i/o units requiring individual completion (e.g. for
-    latency reasons)
-v.  Ability to represent an i/o involving multiple physical memory segments
-    (including non-page aligned page fragments, as specified via readv/writev)
-    without unnecessarily breaking it up, if the underlying device is capable of
-    handling it.
-vi. Preferably should be based on a memory descriptor structure that can be
-    passed around different types of subsystems or layers, maybe even
-    networking, without duplication or extra copies of data/descriptor fields
-    themselves in the process
-vii.Ability to handle the possibility of splits/merges as the structure passes
-    through layered drivers (lvm, md, evms), with minimal overhead.
-
-The solution was to define a new structure (bio)  for the block layer,
-instead of using the buffer head structure (bh) directly, the idea being
-avoidance of some associated baggage and limitations. The bio structure
-is uniformly used for all i/o at the block layer ; it forms a part of the
-bh structure for buffered i/o, and in the case of raw/direct i/o kiobufs are
-mapped to bio structures.
-
-2.2 The bio struct
-
-The bio structure uses a vector representation pointing to an array of tuples
-of <page, offset, len> to describe the i/o buffer, and has various other
-fields describing i/o parameters and state that needs to be maintained for
-performing the i/o.
-
-Notice that this representation means that a bio has no virtual address
-mapping at all (unlike buffer heads).
-
-struct bio_vec {
-       struct page     *bv_page;
-       unsigned short  bv_len;
-       unsigned short  bv_offset;
-};
-
-/*
- * main unit of I/O for the block layer and lower layers (ie drivers)
- */
-struct bio {
-       struct bio          *bi_next;    /* request queue link */
-       struct block_device *bi_bdev;   /* target device */
-       unsigned long       bi_flags;    /* status, command, etc */
-       unsigned long       bi_opf;       /* low bits: r/w, high: priority */
-
-       unsigned int    bi_vcnt;     /* how may bio_vec's */
-       struct bvec_iter        bi_iter;        /* current index into bio_vec array */
-
-       unsigned int    bi_size;     /* total size in bytes */
-       unsigned short  bi_hw_segments; /* segments after DMA remapping */
-       unsigned int    bi_max;      /* max bio_vecs we can hold
-                                        used as index into pool */
-       struct bio_vec   *bi_io_vec;  /* the actual vec list */
-       bio_end_io_t    *bi_end_io;  /* bi_end_io (bio) */
-       atomic_t                bi_cnt;      /* pin count: free when it hits zero */
-       void             *bi_private;
-};
-
-With this multipage bio design:
-
-- Large i/os can be sent down in one go using a bio_vec list consisting
-  of an array of <page, offset, len> fragments (similar to the way fragments
-  are represented in the zero-copy network code)
-- Splitting of an i/o request across multiple devices (as in the case of
-  lvm or raid) is achieved by cloning the bio (where the clone points to
-  the same bi_io_vec array, but with the index and size accordingly modified)
-- A linked list of bios is used as before for unrelated merges (*) - this
-  avoids reallocs and makes independent completions easier to handle.
-- Code that traverses the req list can find all the segments of a bio
-  by using rq_for_each_segment.  This handles the fact that a request
-  has multiple bios, each of which can have multiple segments.
-- Drivers which can't process a large bio in one shot can use the bi_iter
-  field to keep track of the next bio_vec entry to process.
-  (e.g a 1MB bio_vec needs to be handled in max 128kB chunks for IDE)
-  [TBD: Should preferably also have a bi_voffset and bi_vlen to avoid modifying
-   bi_offset an len fields]
-
-(*) unrelated merges -- a request ends up containing two or more bios that
-    didn't originate from the same place.
-
-bi_end_io() i/o callback gets called on i/o completion of the entire bio.
-
-At a lower level, drivers build a scatter gather list from the merged bios.
-The scatter gather list is in the form of an array of <page, offset, len>
-entries with their corresponding dma address mappings filled in at the
-appropriate time. As an optimization, contiguous physical pages can be
-covered by a single entry where <page> refers to the first page and <len>
-covers the range of pages (up to 16 contiguous pages could be covered this
-way). There is a helper routine (blk_rq_map_sg) which drivers can use to build
-the sg list.
-
-Note: Right now the only user of bios with more than one page is ll_rw_kio,
-which in turn means that only raw I/O uses it (direct i/o may not work
-right now). The intent however is to enable clustering of pages etc to
-become possible. The pagebuf abstraction layer from SGI also uses multi-page
-bios, but that is currently not included in the stock development kernels.
-The same is true of Andrew Morton's work-in-progress multipage bio writeout 
-and readahead patches.
-
-2.3 Changes in the Request Structure
-
-The request structure is the structure that gets passed down to low level
-drivers. The block layer make_request function builds up a request structure,
-places it on the queue and invokes the drivers request_fn. The driver makes
-use of block layer helper routine elv_next_request to pull the next request
-off the queue. Control or diagnostic functions might bypass block and directly
-invoke underlying driver entry points passing in a specially constructed
-request structure.
-
-Only some relevant fields (mainly those which changed or may be referred
-to in some of the discussion here) are listed below, not necessarily in
-the order in which they occur in the structure (see include/linux/blkdev.h)
-Refer to Documentation/block/request.txt for details about all the request
-structure fields and a quick reference about the layers which are
-supposed to use or modify those fields.
-
-struct request {
-       struct list_head queuelist;  /* Not meant to be directly accessed by
-                                       the driver.
-                                       Used by q->elv_next_request_fn
-                                       rq->queue is gone
-                                       */
-       .
-       .
-       unsigned char cmd[16]; /* prebuilt command data block */
-       unsigned long flags;   /* also includes earlier rq->cmd settings */
-       .
-       .
-       sector_t sector; /* this field is now of type sector_t instead of int
-                           preparation for 64 bit sectors */
-       .
-       .
-
-       /* Number of scatter-gather DMA addr+len pairs after
-        * physical address coalescing is performed.
-        */
-       unsigned short nr_phys_segments;
-
-       /* Number of scatter-gather addr+len pairs after
-        * physical and DMA remapping hardware coalescing is performed.
-        * This is the number of scatter-gather entries the driver
-        * will actually have to deal with after DMA mapping is done.
-        */
-       unsigned short nr_hw_segments;
-
-       /* Various sector counts */
-       unsigned long nr_sectors;  /* no. of sectors left: driver modifiable */
-       unsigned long hard_nr_sectors;  /* block internal copy of above */
-       unsigned int current_nr_sectors; /* no. of sectors left in the
-                                          current segment:driver modifiable */
-       unsigned long hard_cur_sectors; /* block internal copy of the above */
-       .
-       .
-       int tag;        /* command tag associated with request */
-       void *special;  /* same as before */
-       char *buffer;   /* valid only for low memory buffers up to
-                        current_nr_sectors */
-       .
-       .
-       struct bio *bio, *biotail;  /* bio list instead of bh */
-       struct request_list *rl;
-}
-       
-See the req_ops and req_flag_bits definitions for an explanation of the various
-flags available. Some bits are used by the block layer or i/o scheduler.
-       
-The behaviour of the various sector counts are almost the same as before,
-except that since we have multi-segment bios, current_nr_sectors refers
-to the numbers of sectors in the current segment being processed which could
-be one of the many segments in the current bio (i.e i/o completion unit).
-The nr_sectors value refers to the total number of sectors in the whole
-request that remain to be transferred (no change). The purpose of the
-hard_xxx values is for block to remember these counts every time it hands
-over the request to the driver. These values are updated by block on
-end_that_request_first, i.e. every time the driver completes a part of the
-transfer and invokes block end*request helpers to mark this. The
-driver should not modify these values. The block layer sets up the
-nr_sectors and current_nr_sectors fields (based on the corresponding
-hard_xxx values and the number of bytes transferred) and updates it on
-every transfer that invokes end_that_request_first. It does the same for the
-buffer, bio, bio->bi_iter fields too.
-
-The buffer field is just a virtual address mapping of the current segment
-of the i/o buffer in cases where the buffer resides in low-memory. For high
-memory i/o, this field is not valid and must not be used by drivers.
-
-Code that sets up its own request structures and passes them down to
-a driver needs to be careful about interoperation with the block layer helper
-functions which the driver uses. (Section 1.3)
-
-3. Using bios
-
-3.1 Setup/Teardown
-
-There are routines for managing the allocation, and reference counting, and
-freeing of bios (bio_alloc, bio_get, bio_put).
-
-This makes use of Ingo Molnar's mempool implementation, which enables
-subsystems like bio to maintain their own reserve memory pools for guaranteed
-deadlock-free allocations during extreme VM load. For example, the VM
-subsystem makes use of the block layer to writeout dirty pages in order to be
-able to free up memory space, a case which needs careful handling. The
-allocation logic draws from the preallocated emergency reserve in situations
-where it cannot allocate through normal means. If the pool is empty and it
-can wait, then it would trigger action that would help free up memory or
-replenish the pool (without deadlocking) and wait for availability in the pool.
-If it is in IRQ context, and hence not in a position to do this, allocation
-could fail if the pool is empty. In general mempool always first tries to
-perform allocation without having to wait, even if it means digging into the
-pool as long it is not less that 50% full.
-
-On a free, memory is released to the pool or directly freed depending on
-the current availability in the pool. The mempool interface lets the
-subsystem specify the routines to be used for normal alloc and free. In the
-case of bio, these routines make use of the standard slab allocator.
-
-The caller of bio_alloc is expected to taken certain steps to avoid
-deadlocks, e.g. avoid trying to allocate more memory from the pool while
-already holding memory obtained from the pool.
-[TBD: This is a potential issue, though a rare possibility
- in the bounce bio allocation that happens in the current code, since
- it ends up allocating a second bio from the same pool while
- holding the original bio ]
-
-Memory allocated from the pool should be released back within a limited
-amount of time (in the case of bio, that would be after the i/o is completed).
-This ensures that if part of the pool has been used up, some work (in this
-case i/o) must already be in progress and memory would be available when it
-is over. If allocating from multiple pools in the same code path, the order
-or hierarchy of allocation needs to be consistent, just the way one deals
-with multiple locks.
-
-The bio_alloc routine also needs to allocate the bio_vec_list (bvec_alloc())
-for a non-clone bio. There are the 6 pools setup for different size biovecs,
-so bio_alloc(gfp_mask, nr_iovecs) will allocate a vec_list of the
-given size from these slabs.
-
-The bio_get() routine may be used to hold an extra reference on a bio prior
-to i/o submission, if the bio fields are likely to be accessed after the
-i/o is issued (since the bio may otherwise get freed in case i/o completion
-happens in the meantime).
-
-The bio_clone_fast() routine may be used to duplicate a bio, where the clone
-shares the bio_vec_list with the original bio (i.e. both point to the
-same bio_vec_list). This would typically be used for splitting i/o requests
-in lvm or md.
-
-3.2 Generic bio helper Routines
-
-3.2.1 Traversing segments and completion units in a request
-
-The macro rq_for_each_segment() should be used for traversing the bios
-in the request list (drivers should avoid directly trying to do it
-themselves). Using these helpers should also make it easier to cope
-with block changes in the future.
-
-       struct req_iterator iter;
-       rq_for_each_segment(bio_vec, rq, iter)
-               /* bio_vec is now current segment */
-
-I/O completion callbacks are per-bio rather than per-segment, so drivers
-that traverse bio chains on completion need to keep that in mind. Drivers
-which don't make a distinction between segments and completion units would
-need to be reorganized to support multi-segment bios.
-
-3.2.2 Setting up DMA scatterlists
-
-The blk_rq_map_sg() helper routine would be used for setting up scatter
-gather lists from a request, so a driver need not do it on its own.
-
-       nr_segments = blk_rq_map_sg(q, rq, scatterlist);
-
-The helper routine provides a level of abstraction which makes it easier
-to modify the internals of request to scatterlist conversion down the line
-without breaking drivers. The blk_rq_map_sg routine takes care of several
-things like collapsing physically contiguous segments (if QUEUE_FLAG_CLUSTER
-is set) and correct segment accounting to avoid exceeding the limits which
-the i/o hardware can handle, based on various queue properties.
-
-- Prevents a clustered segment from crossing a 4GB mem boundary
-- Avoids building segments that would exceed the number of physical
-  memory segments that the driver can handle (phys_segments) and the
-  number that the underlying hardware can handle at once, accounting for
-  DMA remapping (hw_segments)  (i.e. IOMMU aware limits).
-
-Routines which the low level driver can use to set up the segment limits:
-
-blk_queue_max_hw_segments() : Sets an upper limit of the maximum number of
-hw data segments in a request (i.e. the maximum number of address/length
-pairs the host adapter can actually hand to the device at once)
-
-blk_queue_max_phys_segments() : Sets an upper limit on the maximum number
-of physical data segments in a request (i.e. the largest sized scatter list
-a driver could handle)
-
-3.2.3 I/O completion
-
-The existing generic block layer helper routines end_request,
-end_that_request_first and end_that_request_last can be used for i/o
-completion (and setting things up so the rest of the i/o or the next
-request can be kicked of) as before. With the introduction of multi-page
-bio support, end_that_request_first requires an additional argument indicating
-the number of sectors completed.
-
-3.2.4 Implications for drivers that do not interpret bios (don't handle
- multiple segments)
-
-Drivers that do not interpret bios e.g those which do not handle multiple
-segments and do not support i/o into high memory addresses (require bounce
-buffers) and expect only virtually mapped buffers, can access the rq->buffer
-field. As before the driver should use current_nr_sectors to determine the
-size of remaining data in the current segment (that is the maximum it can
-transfer in one go unless it interprets segments), and rely on the block layer
-end_request, or end_that_request_first/last to take care of all accounting
-and transparent mapping of the next bio segment when a segment boundary
-is crossed on completion of a transfer. (The end*request* functions should
-be used if only if the request has come down from block/bio path, not for
-direct access requests which only specify rq->buffer without a valid rq->bio)
-
-3.3 I/O Submission
-
-The routine submit_bio() is used to submit a single io. Higher level i/o
-routines make use of this:
-
-(a) Buffered i/o:
-The routine submit_bh() invokes submit_bio() on a bio corresponding to the
-bh, allocating the bio if required. ll_rw_block() uses submit_bh() as before.
-
-(b) Kiobuf i/o (for raw/direct i/o):
-The ll_rw_kio() routine breaks up the kiobuf into page sized chunks and
-maps the array to one or more multi-page bios, issuing submit_bio() to
-perform the i/o on each of these.
-
-The embedded bh array in the kiobuf structure has been removed and no
-preallocation of bios is done for kiobufs. [The intent is to remove the
-blocks array as well, but it's currently in there to kludge around direct i/o.]
-Thus kiobuf allocation has switched back to using kmalloc rather than vmalloc.
-
-Todo/Observation:
-
- A single kiobuf structure is assumed to correspond to a contiguous range
- of data, so brw_kiovec() invokes ll_rw_kio for each kiobuf in a kiovec.
- So right now it wouldn't work for direct i/o on non-contiguous blocks.
- This is to be resolved.  The eventual direction is to replace kiobuf
- by kvec's.
-
- Badari Pulavarty has a patch to implement direct i/o correctly using
- bio and kvec.
-
-
-(c) Page i/o:
-Todo/Under discussion:
-
- Andrew Morton's multi-page bio patches attempt to issue multi-page
- writeouts (and reads) from the page cache, by directly building up
- large bios for submission completely bypassing the usage of buffer
- heads. This work is still in progress.
-
- Christoph Hellwig had some code that uses bios for page-io (rather than
- bh). This isn't included in bio as yet. Christoph was also working on a
- design for representing virtual/real extents as an entity and modifying
- some of the address space ops interfaces to utilize this abstraction rather
- than buffer_heads. (This is somewhat along the lines of the SGI XFS pagebuf
- abstraction, but intended to be as lightweight as possible).
-
-(d) Direct access i/o:
-Direct access requests that do not contain bios would be submitted differently
-as discussed earlier in section 1.3.
-
-Aside:
-
-  Kvec i/o:
-
-  Ben LaHaise's aio code uses a slightly different structure instead
-  of kiobufs, called a kvec_cb. This contains an array of <page, offset, len>
-  tuples (very much like the networking code), together with a callback function
-  and data pointer. This is embedded into a brw_cb structure when passed
-  to brw_kvec_async().
-
-  Now it should be possible to directly map these kvecs to a bio. Just as while
-  cloning, in this case rather than PRE_BUILT bio_vecs, we set the bi_io_vec
-  array pointer to point to the veclet array in kvecs.
-
-  TBD: In order for this to work, some changes are needed in the way multi-page
-  bios are handled today. The values of the tuples in such a vector passed in
-  from higher level code should not be modified by the block layer in the course
-  of its request processing, since that would make it hard for the higher layer
-  to continue to use the vector descriptor (kvec) after i/o completes. Instead,
-  all such transient state should either be maintained in the request structure,
-  and passed on in some way to the endio completion routine.
-
-
-4. The I/O scheduler
-I/O scheduler, a.k.a. elevator, is implemented in two layers.  Generic dispatch
-queue and specific I/O schedulers.  Unless stated otherwise, elevator is used
-to refer to both parts and I/O scheduler to specific I/O schedulers.
-
-Block layer implements generic dispatch queue in block/*.c.
-The generic dispatch queue is responsible for requeueing, handling non-fs
-requests and all other subtleties.
-
-Specific I/O schedulers are responsible for ordering normal filesystem
-requests.  They can also choose to delay certain requests to improve
-throughput or whatever purpose.  As the plural form indicates, there are
-multiple I/O schedulers.  They can be built as modules but at least one should
-be built inside the kernel.  Each queue can choose different one and can also
-change to another one dynamically.
-
-A block layer call to the i/o scheduler follows the convention elv_xxx(). This
-calls elevator_xxx_fn in the elevator switch (block/elevator.c). Oh, xxx
-and xxx might not match exactly, but use your imagination. If an elevator
-doesn't implement a function, the switch does nothing or some minimal house
-keeping work.
-
-4.1. I/O scheduler API
-
-The functions an elevator may implement are: (* are mandatory)
-elevator_merge_fn              called to query requests for merge with a bio
-
-elevator_merge_req_fn          called when two requests get merged. the one
-                               which gets merged into the other one will be
-                               never seen by I/O scheduler again. IOW, after
-                               being merged, the request is gone.
-
-elevator_merged_fn             called when a request in the scheduler has been
-                               involved in a merge. It is used in the deadline
-                               scheduler for example, to reposition the request
-                               if its sorting order has changed.
-
-elevator_allow_merge_fn                called whenever the block layer determines
-                               that a bio can be merged into an existing
-                               request safely. The io scheduler may still
-                               want to stop a merge at this point if it
-                               results in some sort of conflict internally,
-                               this hook allows it to do that. Note however
-                               that two *requests* can still be merged at later
-                               time. Currently the io scheduler has no way to
-                               prevent that. It can only learn about the fact
-                               from elevator_merge_req_fn callback.
-
-elevator_dispatch_fn*          fills the dispatch queue with ready requests.
-                               I/O schedulers are free to postpone requests by
-                               not filling the dispatch queue unless @force
-                               is non-zero.  Once dispatched, I/O schedulers
-                               are not allowed to manipulate the requests -
-                               they belong to generic dispatch queue.
-
-elevator_add_req_fn*           called to add a new request into the scheduler
-
-elevator_former_req_fn
-elevator_latter_req_fn         These return the request before or after the
-                               one specified in disk sort order. Used by the
-                               block layer to find merge possibilities.
-
-elevator_completed_req_fn      called when a request is completed.
-
-elevator_set_req_fn
-elevator_put_req_fn            Must be used to allocate and free any elevator
-                               specific storage for a request.
-
-elevator_activate_req_fn       Called when device driver first sees a request.
-                               I/O schedulers can use this callback to
-                               determine when actual execution of a request
-                               starts.
-elevator_deactivate_req_fn     Called when device driver decides to delay
-                               a request by requeueing it.
-
-elevator_init_fn*
-elevator_exit_fn               Allocate and free any elevator specific storage
-                               for a queue.
-
-4.2 Request flows seen by I/O schedulers
-All requests seen by I/O schedulers strictly follow one of the following three
-flows.
-
- set_req_fn ->
-
- i.   add_req_fn -> (merged_fn ->)* -> dispatch_fn -> activate_req_fn ->
-      (deactivate_req_fn -> activate_req_fn ->)* -> completed_req_fn
- ii.  add_req_fn -> (merged_fn ->)* -> merge_req_fn
- iii. [none]
-
- -> put_req_fn
-
-4.3 I/O scheduler implementation
-The generic i/o scheduler algorithm attempts to sort/merge/batch requests for
-optimal disk scan and request servicing performance (based on generic
-principles and device capabilities), optimized for:
-i.   improved throughput
-ii.  improved latency
-iii. better utilization of h/w & CPU time
-
-Characteristics:
-
-i. Binary tree
-AS and deadline i/o schedulers use red black binary trees for disk position
-sorting and searching, and a fifo linked list for time-based searching. This
-gives good scalability and good availability of information. Requests are
-almost always dispatched in disk sort order, so a cache is kept of the next
-request in sort order to prevent binary tree lookups.
-
-This arrangement is not a generic block layer characteristic however, so
-elevators may implement queues as they please.
-
-ii. Merge hash
-AS and deadline use a hash table indexed by the last sector of a request. This
-enables merging code to quickly look up "back merge" candidates, even when
-multiple I/O streams are being performed at once on one disk.
-
-"Front merges", a new request being merged at the front of an existing request,
-are far less common than "back merges" due to the nature of most I/O patterns.
-Front merges are handled by the binary trees in AS and deadline schedulers.
-
-iii. Plugging the queue to batch requests in anticipation of opportunities for
-     merge/sort optimizations
-
-Plugging is an approach that the current i/o scheduling algorithm resorts to so
-that it collects up enough requests in the queue to be able to take
-advantage of the sorting/merging logic in the elevator. If the
-queue is empty when a request comes in, then it plugs the request queue
-(sort of like plugging the bath tub of a vessel to get fluid to build up)
-till it fills up with a few more requests, before starting to service
-the requests. This provides an opportunity to merge/sort the requests before
-passing them down to the device. There are various conditions when the queue is
-unplugged (to open up the flow again), either through a scheduled task or
-could be on demand. For example wait_on_buffer sets the unplugging going
-through sync_buffer() running blk_run_address_space(mapping). Or the caller
-can do it explicity through blk_unplug(bdev). So in the read case,
-the queue gets explicitly unplugged as part of waiting for completion on that
-buffer.
-
-Aside:
-  This is kind of controversial territory, as it's not clear if plugging is
-  always the right thing to do. Devices typically have their own queues,
-  and allowing a big queue to build up in software, while letting the device be
-  idle for a while may not always make sense. The trick is to handle the fine
-  balance between when to plug and when to open up. Also now that we have
-  multi-page bios being queued in one shot, we may not need to wait to merge
-  a big request from the broken up pieces coming by.
-
-4.4 I/O contexts
-I/O contexts provide a dynamically allocated per process data area. They may
-be used in I/O schedulers, and in the block layer (could be used for IO statis,
-priorities for example). See *io_context in block/ll_rw_blk.c, and as-iosched.c
-for an example of usage in an i/o scheduler.
-
-
-5. Scalability related changes
-
-5.1 Granular Locking: io_request_lock replaced by a per-queue lock
-
-The global io_request_lock has been removed as of 2.5, to avoid
-the scalability bottleneck it was causing, and has been replaced by more
-granular locking. The request queue structure has a pointer to the
-lock to be used for that queue. As a result, locking can now be
-per-queue, with a provision for sharing a lock across queues if
-necessary (e.g the scsi layer sets the queue lock pointers to the
-corresponding adapter lock, which results in a per host locking
-granularity). The locking semantics are the same, i.e. locking is
-still imposed by the block layer, grabbing the lock before
-request_fn execution which it means that lots of older drivers
-should still be SMP safe. Drivers are free to drop the queue
-lock themselves, if required. Drivers that explicitly used the
-io_request_lock for serialization need to be modified accordingly.
-Usually it's as easy as adding a global lock:
-
-       static DEFINE_SPINLOCK(my_driver_lock);
-
-and passing the address to that lock to blk_init_queue().
-
-5.2 64 bit sector numbers (sector_t prepares for 64 bit support)
-
-The sector number used in the bio structure has been changed to sector_t,
-which could be defined as 64 bit in preparation for 64 bit sector support.
-
-6. Other Changes/Implications
-
-6.1 Partition re-mapping handled by the generic block layer
-
-In 2.5 some of the gendisk/partition related code has been reorganized.
-Now the generic block layer performs partition-remapping early and thus
-provides drivers with a sector number relative to whole device, rather than
-having to take partition number into account in order to arrive at the true
-sector number. The routine blk_partition_remap() is invoked by
-generic_make_request even before invoking the queue specific make_request_fn,
-so the i/o scheduler also gets to operate on whole disk sector numbers. This
-should typically not require changes to block drivers, it just never gets
-to invoke its own partition sector offset calculations since all bios
-sent are offset from the beginning of the device.
-
-
-7. A Few Tips on Migration of older drivers
-
-Old-style drivers that just use CURRENT and ignores clustered requests,
-may not need much change.  The generic layer will automatically handle
-clustered requests, multi-page bios, etc for the driver.
-
-For a low performance driver or hardware that is PIO driven or just doesn't
-support scatter-gather changes should be minimal too.
-
-The following are some points to keep in mind when converting old drivers
-to bio.
-
-Drivers should use elv_next_request to pick up requests and are no longer
-supposed to handle looping directly over the request list.
-(struct request->queue has been removed)
-
-Now end_that_request_first takes an additional number_of_sectors argument.
-It used to handle always just the first buffer_head in a request, now
-it will loop and handle as many sectors (on a bio-segment granularity)
-as specified.
-
-Now bh->b_end_io is replaced by bio->bi_end_io, but most of the time the
-right thing to use is bio_endio(bio) instead.
-
-If the driver is dropping the io_request_lock from its request_fn strategy,
-then it just needs to replace that with q->queue_lock instead.
-
-As described in Sec 1.1, drivers can set max sector size, max segment size
-etc per queue now. Drivers that used to define their own merge functions i
-to handle things like this can now just use the blk_queue_* functions at
-blk_init_queue time.
-
-Drivers no longer have to map a {partition, sector offset} into the
-correct absolute location anymore, this is done by the block layer, so
-where a driver received a request ala this before:
-
-       rq->rq_dev = mk_kdev(3, 5);     /* /dev/hda5 */
-       rq->sector = 0;                 /* first sector on hda5 */
-
-  it will now see
-
-       rq->rq_dev = mk_kdev(3, 0);     /* /dev/hda */
-       rq->sector = 123128;            /* offset from start of disk */
-
-As mentioned, there is no virtual mapping of a bio. For DMA, this is
-not a problem as the driver probably never will need a virtual mapping.
-Instead it needs a bus mapping (dma_map_page for a single segment or
-use dma_map_sg for scatter gather) to be able to ship it to the driver. For
-PIO drivers (or drivers that need to revert to PIO transfer once in a
-while (IDE for example)), where the CPU is doing the actual data
-transfer a virtual mapping is needed. If the driver supports highmem I/O,
-(Sec 1.1, (ii) ) it needs to use kmap_atomic or similar to temporarily map
-a bio into the virtual address space.
-
-
-8. Prior/Related/Impacted patches
-
-8.1. Earlier kiobuf patches (sct/axboe/chait/hch/mkp)
-- orig kiobuf & raw i/o patches (now in 2.4 tree)
-- direct kiobuf based i/o to devices (no intermediate bh's)
-- page i/o using kiobuf
-- kiobuf splitting for lvm (mkp)
-- elevator support for kiobuf request merging (axboe)
-8.2. Zero-copy networking (Dave Miller)
-8.3. SGI XFS - pagebuf patches - use of kiobufs
-8.4. Multi-page pioent patch for bio (Christoph Hellwig)
-8.5. Direct i/o implementation (Andrea Arcangeli) since 2.4.10-pre11
-8.6. Async i/o implementation patch (Ben LaHaise)
-8.7. EVMS layering design (IBM EVMS team)
-8.8. Larger page cache size patch (Ben LaHaise) and
-     Large page size (Daniel Phillips)
-    => larger contiguous physical memory buffers
-8.9. VM reservations patch (Ben LaHaise)
-8.10. Write clustering patches ? (Marcelo/Quintela/Riel ?)
-8.11. Block device in page cache patch (Andrea Archangeli) - now in 2.4.10+
-8.12. Multiple block-size transfers for faster raw i/o (Shailabh Nagar,
-      Badari)
-8.13  Priority based i/o scheduler - prepatches (Arjan van de Ven)
-8.14  IDE Taskfile i/o patch (Andre Hedrick)
-8.15  Multi-page writeout and readahead patches (Andrew Morton)
-8.16  Direct i/o patches for 2.5 using kvec and bio (Badari Pulavarthy)
-
-9. Other References:
-
-9.1 The Splice I/O Model - Larry McVoy (and subsequent discussions on lkml,
-and Linus' comments - Jan 2001)
-9.2 Discussions about kiobuf and bh design on lkml between sct, linus, alan
-et al - Feb-March 2001 (many of the initial thoughts that led to bio were
-brought up in this discussion thread)
-9.3 Discussions on mempool on lkml - Dec 2001.
-
diff --git a/Documentation/block/biovecs.rst b/Documentation/block/biovecs.rst
new file mode 100644 (file)
index 0000000..86fa66c
--- /dev/null
@@ -0,0 +1,146 @@
+======================================
+Immutable biovecs and biovec iterators
+======================================
+
+Kent Overstreet <kmo@daterainc.com>
+
+As of 3.13, biovecs should never be modified after a bio has been submitted.
+Instead, we have a new struct bvec_iter which represents a range of a biovec -
+the iterator will be modified as the bio is completed, not the biovec.
+
+More specifically, old code that needed to partially complete a bio would
+update bi_sector and bi_size, and advance bi_idx to the next biovec. If it
+ended up partway through a biovec, it would increment bv_offset and decrement
+bv_len by the number of bytes completed in that biovec.
+
+In the new scheme of things, everything that must be mutated in order to
+partially complete a bio is segregated into struct bvec_iter: bi_sector,
+bi_size and bi_idx have been moved there; and instead of modifying bv_offset
+and bv_len, struct bvec_iter has bi_bvec_done, which represents the number of
+bytes completed in the current bvec.
+
+There are a bunch of new helper macros for hiding the gory details - in
+particular, presenting the illusion of partially completed biovecs so that
+normal code doesn't have to deal with bi_bvec_done.
+
+ * Driver code should no longer refer to biovecs directly; we now have
+   bio_iovec() and bio_iter_iovec() macros that return literal struct biovecs,
+   constructed from the raw biovecs but taking into account bi_bvec_done and
+   bi_size.
+
+   bio_for_each_segment() has been updated to take a bvec_iter argument
+   instead of an integer (that corresponded to bi_idx); for a lot of code the
+   conversion just required changing the types of the arguments to
+   bio_for_each_segment().
+
+ * Advancing a bvec_iter is done with bio_advance_iter(); bio_advance() is a
+   wrapper around bio_advance_iter() that operates on bio->bi_iter, and also
+   advances the bio integrity's iter if present.
+
+   There is a lower level advance function - bvec_iter_advance() - which takes
+   a pointer to a biovec, not a bio; this is used by the bio integrity code.
+
+What's all this get us?
+=======================
+
+Having a real iterator, and making biovecs immutable, has a number of
+advantages:
+
+ * Before, iterating over bios was very awkward when you weren't processing
+   exactly one bvec at a time - for example, bio_copy_data() in fs/bio.c,
+   which copies the contents of one bio into another. Because the biovecs
+   wouldn't necessarily be the same size, the old code was tricky convoluted -
+   it had to walk two different bios at the same time, keeping both bi_idx and
+   and offset into the current biovec for each.
+
+   The new code is much more straightforward - have a look. This sort of
+   pattern comes up in a lot of places; a lot of drivers were essentially open
+   coding bvec iterators before, and having common implementation considerably
+   simplifies a lot of code.
+
+ * Before, any code that might need to use the biovec after the bio had been
+   completed (perhaps to copy the data somewhere else, or perhaps to resubmit
+   it somewhere else if there was an error) had to save the entire bvec array
+   - again, this was being done in a fair number of places.
+
+ * Biovecs can be shared between multiple bios - a bvec iter can represent an
+   arbitrary range of an existing biovec, both starting and ending midway
+   through biovecs. This is what enables efficient splitting of arbitrary
+   bios. Note that this means we _only_ use bi_size to determine when we've
+   reached the end of a bio, not bi_vcnt - and the bio_iovec() macro takes
+   bi_size into account when constructing biovecs.
+
+ * Splitting bios is now much simpler. The old bio_split() didn't even work on
+   bios with more than a single bvec! Now, we can efficiently split arbitrary
+   size bios - because the new bio can share the old bio's biovec.
+
+   Care must be taken to ensure the biovec isn't freed while the split bio is
+   still using it, in case the original bio completes first, though. Using
+   bio_chain() when splitting bios helps with this.
+
+ * Submitting partially completed bios is now perfectly fine - this comes up
+   occasionally in stacking block drivers and various code (e.g. md and
+   bcache) had some ugly workarounds for this.
+
+   It used to be the case that submitting a partially completed bio would work
+   fine to _most_ devices, but since accessing the raw bvec array was the
+   norm, not all drivers would respect bi_idx and those would break. Now,
+   since all drivers _must_ go through the bvec iterator - and have been
+   audited to make sure they are - submitting partially completed bios is
+   perfectly fine.
+
+Other implications:
+===================
+
+ * Almost all usage of bi_idx is now incorrect and has been removed; instead,
+   where previously you would have used bi_idx you'd now use a bvec_iter,
+   probably passing it to one of the helper macros.
+
+   I.e. instead of using bio_iovec_idx() (or bio->bi_iovec[bio->bi_idx]), you
+   now use bio_iter_iovec(), which takes a bvec_iter and returns a
+   literal struct bio_vec - constructed on the fly from the raw biovec but
+   taking into account bi_bvec_done (and bi_size).
+
+ * bi_vcnt can't be trusted or relied upon by driver code - i.e. anything that
+   doesn't actually own the bio. The reason is twofold: firstly, it's not
+   actually needed for iterating over the bio anymore - we only use bi_size.
+   Secondly, when cloning a bio and reusing (a portion of) the original bio's
+   biovec, in order to calculate bi_vcnt for the new bio we'd have to iterate
+   over all the biovecs in the new bio - which is silly as it's not needed.
+
+   So, don't use bi_vcnt anymore.
+
+ * The current interface allows the block layer to split bios as needed, so we
+   could eliminate a lot of complexity particularly in stacked drivers. Code
+   that creates bios can then create whatever size bios are convenient, and
+   more importantly stacked drivers don't have to deal with both their own bio
+   size limitations and the limitations of the underlying devices. Thus
+   there's no need to define ->merge_bvec_fn() callbacks for individual block
+   drivers.
+
+Usage of helpers:
+=================
+
+* The following helpers whose names have the suffix of `_all` can only be used
+  on non-BIO_CLONED bio. They are usually used by filesystem code. Drivers
+  shouldn't use them because the bio may have been split before it reached the
+  driver.
+
+::
+
+       bio_for_each_segment_all()
+       bio_first_bvec_all()
+       bio_first_page_all()
+       bio_last_bvec_all()
+
+* The following helpers iterate over single-page segment. The passed 'struct
+  bio_vec' will contain a single-page IO vector during the iteration::
+
+       bio_for_each_segment()
+       bio_for_each_segment_all()
+
+* The following helpers iterate over multi-page bvec. The passed 'struct
+  bio_vec' will contain a multi-page IO vector during the iteration::
+
+       bio_for_each_bvec()
+       rq_for_each_bvec()
diff --git a/Documentation/block/biovecs.txt b/Documentation/block/biovecs.txt
deleted file mode 100644 (file)
index ce6ecca..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-
-Immutable biovecs and biovec iterators:
-=======================================
-
-Kent Overstreet <kmo@daterainc.com>
-
-As of 3.13, biovecs should never be modified after a bio has been submitted.
-Instead, we have a new struct bvec_iter which represents a range of a biovec -
-the iterator will be modified as the bio is completed, not the biovec.
-
-More specifically, old code that needed to partially complete a bio would
-update bi_sector and bi_size, and advance bi_idx to the next biovec. If it
-ended up partway through a biovec, it would increment bv_offset and decrement
-bv_len by the number of bytes completed in that biovec.
-
-In the new scheme of things, everything that must be mutated in order to
-partially complete a bio is segregated into struct bvec_iter: bi_sector,
-bi_size and bi_idx have been moved there; and instead of modifying bv_offset
-and bv_len, struct bvec_iter has bi_bvec_done, which represents the number of
-bytes completed in the current bvec.
-
-There are a bunch of new helper macros for hiding the gory details - in
-particular, presenting the illusion of partially completed biovecs so that
-normal code doesn't have to deal with bi_bvec_done.
-
- * Driver code should no longer refer to biovecs directly; we now have
-   bio_iovec() and bio_iter_iovec() macros that return literal struct biovecs,
-   constructed from the raw biovecs but taking into account bi_bvec_done and
-   bi_size.
-
-   bio_for_each_segment() has been updated to take a bvec_iter argument
-   instead of an integer (that corresponded to bi_idx); for a lot of code the
-   conversion just required changing the types of the arguments to
-   bio_for_each_segment().
-
- * Advancing a bvec_iter is done with bio_advance_iter(); bio_advance() is a
-   wrapper around bio_advance_iter() that operates on bio->bi_iter, and also
-   advances the bio integrity's iter if present.
-
-   There is a lower level advance function - bvec_iter_advance() - which takes
-   a pointer to a biovec, not a bio; this is used by the bio integrity code.
-
-What's all this get us?
-=======================
-
-Having a real iterator, and making biovecs immutable, has a number of
-advantages:
-
- * Before, iterating over bios was very awkward when you weren't processing
-   exactly one bvec at a time - for example, bio_copy_data() in fs/bio.c,
-   which copies the contents of one bio into another. Because the biovecs
-   wouldn't necessarily be the same size, the old code was tricky convoluted -
-   it had to walk two different bios at the same time, keeping both bi_idx and
-   and offset into the current biovec for each.
-
-   The new code is much more straightforward - have a look. This sort of
-   pattern comes up in a lot of places; a lot of drivers were essentially open
-   coding bvec iterators before, and having common implementation considerably
-   simplifies a lot of code.
-
- * Before, any code that might need to use the biovec after the bio had been
-   completed (perhaps to copy the data somewhere else, or perhaps to resubmit
-   it somewhere else if there was an error) had to save the entire bvec array
-   - again, this was being done in a fair number of places.
-
- * Biovecs can be shared between multiple bios - a bvec iter can represent an
-   arbitrary range of an existing biovec, both starting and ending midway
-   through biovecs. This is what enables efficient splitting of arbitrary
-   bios. Note that this means we _only_ use bi_size to determine when we've
-   reached the end of a bio, not bi_vcnt - and the bio_iovec() macro takes
-   bi_size into account when constructing biovecs.
-
- * Splitting bios is now much simpler. The old bio_split() didn't even work on
-   bios with more than a single bvec! Now, we can efficiently split arbitrary
-   size bios - because the new bio can share the old bio's biovec.
-
-   Care must be taken to ensure the biovec isn't freed while the split bio is
-   still using it, in case the original bio completes first, though. Using
-   bio_chain() when splitting bios helps with this.
-
- * Submitting partially completed bios is now perfectly fine - this comes up
-   occasionally in stacking block drivers and various code (e.g. md and
-   bcache) had some ugly workarounds for this.
-
-   It used to be the case that submitting a partially completed bio would work
-   fine to _most_ devices, but since accessing the raw bvec array was the
-   norm, not all drivers would respect bi_idx and those would break. Now,
-   since all drivers _must_ go through the bvec iterator - and have been
-   audited to make sure they are - submitting partially completed bios is
-   perfectly fine.
-
-Other implications:
-===================
-
- * Almost all usage of bi_idx is now incorrect and has been removed; instead,
-   where previously you would have used bi_idx you'd now use a bvec_iter,
-   probably passing it to one of the helper macros.
-
-   I.e. instead of using bio_iovec_idx() (or bio->bi_iovec[bio->bi_idx]), you
-   now use bio_iter_iovec(), which takes a bvec_iter and returns a
-   literal struct bio_vec - constructed on the fly from the raw biovec but
-   taking into account bi_bvec_done (and bi_size).
-
- * bi_vcnt can't be trusted or relied upon by driver code - i.e. anything that
-   doesn't actually own the bio. The reason is twofold: firstly, it's not
-   actually needed for iterating over the bio anymore - we only use bi_size.
-   Secondly, when cloning a bio and reusing (a portion of) the original bio's
-   biovec, in order to calculate bi_vcnt for the new bio we'd have to iterate
-   over all the biovecs in the new bio - which is silly as it's not needed.
-
-   So, don't use bi_vcnt anymore.
-
- * The current interface allows the block layer to split bios as needed, so we
-   could eliminate a lot of complexity particularly in stacked drivers. Code
-   that creates bios can then create whatever size bios are convenient, and
-   more importantly stacked drivers don't have to deal with both their own bio
-   size limitations and the limitations of the underlying devices. Thus
-   there's no need to define ->merge_bvec_fn() callbacks for individual block
-   drivers.
-
-Usage of helpers:
-=================
-
-* The following helpers whose names have the suffix of "_all" can only be used
-on non-BIO_CLONED bio. They are usually used by filesystem code. Drivers
-shouldn't use them because the bio may have been split before it reached the
-driver.
-
-       bio_for_each_segment_all()
-       bio_first_bvec_all()
-       bio_first_page_all()
-       bio_last_bvec_all()
-
-* The following helpers iterate over single-page segment. The passed 'struct
-bio_vec' will contain a single-page IO vector during the iteration
-
-       bio_for_each_segment()
-       bio_for_each_segment_all()
-
-* The following helpers iterate over multi-page bvec. The passed 'struct
-bio_vec' will contain a multi-page IO vector during the iteration
-
-       bio_for_each_bvec()
-       rq_for_each_bvec()
diff --git a/Documentation/block/capability.rst b/Documentation/block/capability.rst
new file mode 100644 (file)
index 0000000..2cf258d
--- /dev/null
@@ -0,0 +1,18 @@
+===============================
+Generic Block Device Capability
+===============================
+
+This file documents the sysfs file block/<disk>/capability
+
+capability is a hex word indicating which capabilities a specific disk
+supports.  For more information on bits not listed here, see
+include/linux/genhd.h
+
+GENHD_FL_MEDIA_CHANGE_NOTIFY
+----------------------------
+
+Value: 4
+
+When this bit is set, the disk supports Asynchronous Notification
+of media change events.  These events will be broadcast to user
+space via kernel uevent.
diff --git a/Documentation/block/capability.txt b/Documentation/block/capability.txt
deleted file mode 100644 (file)
index 2f17294..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-Generic Block Device Capability
-===============================================================================
-This file documents the sysfs file block/<disk>/capability
-
-capability is a hex word indicating which capabilities a specific disk
-supports.  For more information on bits not listed here, see
-include/linux/genhd.h
-
-Capability                             Value
--------------------------------------------------------------------------------
-GENHD_FL_MEDIA_CHANGE_NOTIFY           4
-       When this bit is set, the disk supports Asynchronous Notification
-       of media change events.  These events will be broadcast to user
-       space via kernel uevent.
-
diff --git a/Documentation/block/cmdline-partition.rst b/Documentation/block/cmdline-partition.rst
new file mode 100644 (file)
index 0000000..530bedf
--- /dev/null
@@ -0,0 +1,53 @@
+==============================================
+Embedded device command line partition parsing
+==============================================
+
+The "blkdevparts" command line option adds support for reading the
+block device partition table from the kernel command line.
+
+It is typically used for fixed block (eMMC) embedded devices.
+It has no MBR, so saves storage space. Bootloader can be easily accessed
+by absolute address of data on the block device.
+Users can easily change the partition.
+
+The format for the command line is just like mtdparts:
+
+blkdevparts=<blkdev-def>[;<blkdev-def>]
+  <blkdev-def> := <blkdev-id>:<partdef>[,<partdef>]
+    <partdef> := <size>[@<offset>](part-name)
+
+<blkdev-id>
+    block device disk name. Embedded device uses fixed block device.
+    Its disk name is also fixed, such as: mmcblk0, mmcblk1, mmcblk0boot0.
+
+<size>
+    partition size, in bytes, such as: 512, 1m, 1G.
+    size may contain an optional suffix of (upper or lower case):
+
+      K, M, G, T, P, E.
+
+    "-" is used to denote all remaining space.
+
+<offset>
+    partition start address, in bytes.
+    offset may contain an optional suffix of (upper or lower case):
+
+      K, M, G, T, P, E.
+
+(part-name)
+    partition name. Kernel sends uevent with "PARTNAME". Application can
+    create a link to block device partition with the name "PARTNAME".
+    User space application can access partition by partition name.
+
+Example:
+
+    eMMC disk names are "mmcblk0" and "mmcblk0boot0".
+
+  bootargs::
+
+    'blkdevparts=mmcblk0:1G(data0),1G(data1),-;mmcblk0boot0:1m(boot),-(kernel)'
+
+  dmesg::
+
+    mmcblk0: p1(data0) p2(data1) p3()
+    mmcblk0boot0: p1(boot) p2(kernel)
diff --git a/Documentation/block/cmdline-partition.txt b/Documentation/block/cmdline-partition.txt
deleted file mode 100644 (file)
index 760a3f7..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-Embedded device command line partition parsing
-=====================================================================
-
-The "blkdevparts" command line option adds support for reading the
-block device partition table from the kernel command line.
-
-It is typically used for fixed block (eMMC) embedded devices.
-It has no MBR, so saves storage space. Bootloader can be easily accessed
-by absolute address of data on the block device.
-Users can easily change the partition.
-
-The format for the command line is just like mtdparts:
-
-blkdevparts=<blkdev-def>[;<blkdev-def>]
-  <blkdev-def> := <blkdev-id>:<partdef>[,<partdef>]
-    <partdef> := <size>[@<offset>](part-name)
-
-<blkdev-id>
-    block device disk name. Embedded device uses fixed block device.
-    Its disk name is also fixed, such as: mmcblk0, mmcblk1, mmcblk0boot0.
-
-<size>
-    partition size, in bytes, such as: 512, 1m, 1G.
-    size may contain an optional suffix of (upper or lower case):
-      K, M, G, T, P, E.
-    "-" is used to denote all remaining space.
-
-<offset>
-    partition start address, in bytes.
-    offset may contain an optional suffix of (upper or lower case):
-      K, M, G, T, P, E.
-
-(part-name)
-    partition name. Kernel sends uevent with "PARTNAME". Application can
-    create a link to block device partition with the name "PARTNAME".
-    User space application can access partition by partition name.
-
-Example:
-    eMMC disk names are "mmcblk0" and "mmcblk0boot0".
-
-  bootargs:
-    'blkdevparts=mmcblk0:1G(data0),1G(data1),-;mmcblk0boot0:1m(boot),-(kernel)'
-
-  dmesg:
-    mmcblk0: p1(data0) p2(data1) p3()
-    mmcblk0boot0: p1(boot) p2(kernel)
diff --git a/Documentation/block/data-integrity.rst b/Documentation/block/data-integrity.rst
new file mode 100644 (file)
index 0000000..4f2452a
--- /dev/null
@@ -0,0 +1,291 @@
+==============
+Data Integrity
+==============
+
+1. Introduction
+===============
+
+Modern filesystems feature checksumming of data and metadata to
+protect against data corruption.  However, the detection of the
+corruption is done at read time which could potentially be months
+after the data was written.  At that point the original data that the
+application tried to write is most likely lost.
+
+The solution is to ensure that the disk is actually storing what the
+application meant it to.  Recent additions to both the SCSI family
+protocols (SBC Data Integrity Field, SCC protection proposal) as well
+as SATA/T13 (External Path Protection) try to remedy this by adding
+support for appending integrity metadata to an I/O.  The integrity
+metadata (or protection information in SCSI terminology) includes a
+checksum for each sector as well as an incrementing counter that
+ensures the individual sectors are written in the right order.  And
+for some protection schemes also that the I/O is written to the right
+place on disk.
+
+Current storage controllers and devices implement various protective
+measures, for instance checksumming and scrubbing.  But these
+technologies are working in their own isolated domains or at best
+between adjacent nodes in the I/O path.  The interesting thing about
+DIF and the other integrity extensions is that the protection format
+is well defined and every node in the I/O path can verify the
+integrity of the I/O and reject it if corruption is detected.  This
+allows not only corruption prevention but also isolation of the point
+of failure.
+
+2. The Data Integrity Extensions
+================================
+
+As written, the protocol extensions only protect the path between
+controller and storage device.  However, many controllers actually
+allow the operating system to interact with the integrity metadata
+(IMD).  We have been working with several FC/SAS HBA vendors to enable
+the protection information to be transferred to and from their
+controllers.
+
+The SCSI Data Integrity Field works by appending 8 bytes of protection
+information to each sector.  The data + integrity metadata is stored
+in 520 byte sectors on disk.  Data + IMD are interleaved when
+transferred between the controller and target.  The T13 proposal is
+similar.
+
+Because it is highly inconvenient for operating systems to deal with
+520 (and 4104) byte sectors, we approached several HBA vendors and
+encouraged them to allow separation of the data and integrity metadata
+scatter-gather lists.
+
+The controller will interleave the buffers on write and split them on
+read.  This means that Linux can DMA the data buffers to and from
+host memory without changes to the page cache.
+
+Also, the 16-bit CRC checksum mandated by both the SCSI and SATA specs
+is somewhat heavy to compute in software.  Benchmarks found that
+calculating this checksum had a significant impact on system
+performance for a number of workloads.  Some controllers allow a
+lighter-weight checksum to be used when interfacing with the operating
+system.  Emulex, for instance, supports the TCP/IP checksum instead.
+The IP checksum received from the OS is converted to the 16-bit CRC
+when writing and vice versa.  This allows the integrity metadata to be
+generated by Linux or the application at very low cost (comparable to
+software RAID5).
+
+The IP checksum is weaker than the CRC in terms of detecting bit
+errors.  However, the strength is really in the separation of the data
+buffers and the integrity metadata.  These two distinct buffers must
+match up for an I/O to complete.
+
+The separation of the data and integrity metadata buffers as well as
+the choice in checksums is referred to as the Data Integrity
+Extensions.  As these extensions are outside the scope of the protocol
+bodies (T10, T13), Oracle and its partners are trying to standardize
+them within the Storage Networking Industry Association.
+
+3. Kernel Changes
+=================
+
+The data integrity framework in Linux enables protection information
+to be pinned to I/Os and sent to/received from controllers that
+support it.
+
+The advantage to the integrity extensions in SCSI and SATA is that
+they enable us to protect the entire path from application to storage
+device.  However, at the same time this is also the biggest
+disadvantage. It means that the protection information must be in a
+format that can be understood by the disk.
+
+Generally Linux/POSIX applications are agnostic to the intricacies of
+the storage devices they are accessing.  The virtual filesystem switch
+and the block layer make things like hardware sector size and
+transport protocols completely transparent to the application.
+
+However, this level of detail is required when preparing the
+protection information to send to a disk.  Consequently, the very
+concept of an end-to-end protection scheme is a layering violation.
+It is completely unreasonable for an application to be aware whether
+it is accessing a SCSI or SATA disk.
+
+The data integrity support implemented in Linux attempts to hide this
+from the application.  As far as the application (and to some extent
+the kernel) is concerned, the integrity metadata is opaque information
+that's attached to the I/O.
+
+The current implementation allows the block layer to automatically
+generate the protection information for any I/O.  Eventually the
+intent is to move the integrity metadata calculation to userspace for
+user data.  Metadata and other I/O that originates within the kernel
+will still use the automatic generation interface.
+
+Some storage devices allow each hardware sector to be tagged with a
+16-bit value.  The owner of this tag space is the owner of the block
+device.  I.e. the filesystem in most cases.  The filesystem can use
+this extra space to tag sectors as they see fit.  Because the tag
+space is limited, the block interface allows tagging bigger chunks by
+way of interleaving.  This way, 8*16 bits of information can be
+attached to a typical 4KB filesystem block.
+
+This also means that applications such as fsck and mkfs will need
+access to manipulate the tags from user space.  A passthrough
+interface for this is being worked on.
+
+
+4. Block Layer Implementation Details
+=====================================
+
+4.1 Bio
+-------
+
+The data integrity patches add a new field to struct bio when
+CONFIG_BLK_DEV_INTEGRITY is enabled.  bio_integrity(bio) returns a
+pointer to a struct bip which contains the bio integrity payload.
+Essentially a bip is a trimmed down struct bio which holds a bio_vec
+containing the integrity metadata and the required housekeeping
+information (bvec pool, vector count, etc.)
+
+A kernel subsystem can enable data integrity protection on a bio by
+calling bio_integrity_alloc(bio).  This will allocate and attach the
+bip to the bio.
+
+Individual pages containing integrity metadata can subsequently be
+attached using bio_integrity_add_page().
+
+bio_free() will automatically free the bip.
+
+
+4.2 Block Device
+----------------
+
+Because the format of the protection data is tied to the physical
+disk, each block device has been extended with a block integrity
+profile (struct blk_integrity).  This optional profile is registered
+with the block layer using blk_integrity_register().
+
+The profile contains callback functions for generating and verifying
+the protection data, as well as getting and setting application tags.
+The profile also contains a few constants to aid in completing,
+merging and splitting the integrity metadata.
+
+Layered block devices will need to pick a profile that's appropriate
+for all subdevices.  blk_integrity_compare() can help with that.  DM
+and MD linear, RAID0 and RAID1 are currently supported.  RAID4/5/6
+will require extra work due to the application tag.
+
+
+5.0 Block Layer Integrity API
+=============================
+
+5.1 Normal Filesystem
+---------------------
+
+    The normal filesystem is unaware that the underlying block device
+    is capable of sending/receiving integrity metadata.  The IMD will
+    be automatically generated by the block layer at submit_bio() time
+    in case of a WRITE.  A READ request will cause the I/O integrity
+    to be verified upon completion.
+
+    IMD generation and verification can be toggled using the::
+
+      /sys/block/<bdev>/integrity/write_generate
+
+    and::
+
+      /sys/block/<bdev>/integrity/read_verify
+
+    flags.
+
+
+5.2 Integrity-Aware Filesystem
+------------------------------
+
+    A filesystem that is integrity-aware can prepare I/Os with IMD
+    attached.  It can also use the application tag space if this is
+    supported by the block device.
+
+
+    `bool bio_integrity_prep(bio);`
+
+      To generate IMD for WRITE and to set up buffers for READ, the
+      filesystem must call bio_integrity_prep(bio).
+
+      Prior to calling this function, the bio data direction and start
+      sector must be set, and the bio should have all data pages
+      added.  It is up to the caller to ensure that the bio does not
+      change while I/O is in progress.
+      Complete bio with error if prepare failed for some reson.
+
+
+5.3 Passing Existing Integrity Metadata
+---------------------------------------
+
+    Filesystems that either generate their own integrity metadata or
+    are capable of transferring IMD from user space can use the
+    following calls:
+
+
+    `struct bip * bio_integrity_alloc(bio, gfp_mask, nr_pages);`
+
+      Allocates the bio integrity payload and hangs it off of the bio.
+      nr_pages indicate how many pages of protection data need to be
+      stored in the integrity bio_vec list (similar to bio_alloc()).
+
+      The integrity payload will be freed at bio_free() time.
+
+
+    `int bio_integrity_add_page(bio, page, len, offset);`
+
+      Attaches a page containing integrity metadata to an existing
+      bio.  The bio must have an existing bip,
+      i.e. bio_integrity_alloc() must have been called.  For a WRITE,
+      the integrity metadata in the pages must be in a format
+      understood by the target device with the notable exception that
+      the sector numbers will be remapped as the request traverses the
+      I/O stack.  This implies that the pages added using this call
+      will be modified during I/O!  The first reference tag in the
+      integrity metadata must have a value of bip->bip_sector.
+
+      Pages can be added using bio_integrity_add_page() as long as
+      there is room in the bip bio_vec array (nr_pages).
+
+      Upon completion of a READ operation, the attached pages will
+      contain the integrity metadata received from the storage device.
+      It is up to the receiver to process them and verify data
+      integrity upon completion.
+
+
+5.4 Registering A Block Device As Capable Of Exchanging Integrity Metadata
+--------------------------------------------------------------------------
+
+    To enable integrity exchange on a block device the gendisk must be
+    registered as capable:
+
+    `int blk_integrity_register(gendisk, blk_integrity);`
+
+      The blk_integrity struct is a template and should contain the
+      following::
+
+        static struct blk_integrity my_profile = {
+            .name                   = "STANDARDSBODY-TYPE-VARIANT-CSUM",
+            .generate_fn            = my_generate_fn,
+           .verify_fn              = my_verify_fn,
+           .tuple_size             = sizeof(struct my_tuple_size),
+           .tag_size               = <tag bytes per hw sector>,
+        };
+
+      'name' is a text string which will be visible in sysfs.  This is
+      part of the userland API so chose it carefully and never change
+      it.  The format is standards body-type-variant.
+      E.g. T10-DIF-TYPE1-IP or T13-EPP-0-CRC.
+
+      'generate_fn' generates appropriate integrity metadata (for WRITE).
+
+      'verify_fn' verifies that the data buffer matches the integrity
+      metadata.
+
+      'tuple_size' must be set to match the size of the integrity
+      metadata per sector.  I.e. 8 for DIF and EPP.
+
+      'tag_size' must be set to identify how many bytes of tag space
+      are available per hardware sector.  For DIF this is either 2 or
+      0 depending on the value of the Control Mode Page ATO bit.
+
+----------------------------------------------------------------------
+
+2007-12-24 Martin K. Petersen <martin.petersen@oracle.com>
diff --git a/Documentation/block/data-integrity.txt b/Documentation/block/data-integrity.txt
deleted file mode 100644 (file)
index 934c44e..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-----------------------------------------------------------------------
-1. INTRODUCTION
-
-Modern filesystems feature checksumming of data and metadata to
-protect against data corruption.  However, the detection of the
-corruption is done at read time which could potentially be months
-after the data was written.  At that point the original data that the
-application tried to write is most likely lost.
-
-The solution is to ensure that the disk is actually storing what the
-application meant it to.  Recent additions to both the SCSI family
-protocols (SBC Data Integrity Field, SCC protection proposal) as well
-as SATA/T13 (External Path Protection) try to remedy this by adding
-support for appending integrity metadata to an I/O.  The integrity
-metadata (or protection information in SCSI terminology) includes a
-checksum for each sector as well as an incrementing counter that
-ensures the individual sectors are written in the right order.  And
-for some protection schemes also that the I/O is written to the right
-place on disk.
-
-Current storage controllers and devices implement various protective
-measures, for instance checksumming and scrubbing.  But these
-technologies are working in their own isolated domains or at best
-between adjacent nodes in the I/O path.  The interesting thing about
-DIF and the other integrity extensions is that the protection format
-is well defined and every node in the I/O path can verify the
-integrity of the I/O and reject it if corruption is detected.  This
-allows not only corruption prevention but also isolation of the point
-of failure.
-
-----------------------------------------------------------------------
-2. THE DATA INTEGRITY EXTENSIONS
-
-As written, the protocol extensions only protect the path between
-controller and storage device.  However, many controllers actually
-allow the operating system to interact with the integrity metadata
-(IMD).  We have been working with several FC/SAS HBA vendors to enable
-the protection information to be transferred to and from their
-controllers.
-
-The SCSI Data Integrity Field works by appending 8 bytes of protection
-information to each sector.  The data + integrity metadata is stored
-in 520 byte sectors on disk.  Data + IMD are interleaved when
-transferred between the controller and target.  The T13 proposal is
-similar.
-
-Because it is highly inconvenient for operating systems to deal with
-520 (and 4104) byte sectors, we approached several HBA vendors and
-encouraged them to allow separation of the data and integrity metadata
-scatter-gather lists.
-
-The controller will interleave the buffers on write and split them on
-read.  This means that Linux can DMA the data buffers to and from
-host memory without changes to the page cache.
-
-Also, the 16-bit CRC checksum mandated by both the SCSI and SATA specs
-is somewhat heavy to compute in software.  Benchmarks found that
-calculating this checksum had a significant impact on system
-performance for a number of workloads.  Some controllers allow a
-lighter-weight checksum to be used when interfacing with the operating
-system.  Emulex, for instance, supports the TCP/IP checksum instead.
-The IP checksum received from the OS is converted to the 16-bit CRC
-when writing and vice versa.  This allows the integrity metadata to be
-generated by Linux or the application at very low cost (comparable to
-software RAID5).
-
-The IP checksum is weaker than the CRC in terms of detecting bit
-errors.  However, the strength is really in the separation of the data
-buffers and the integrity metadata.  These two distinct buffers must
-match up for an I/O to complete.
-
-The separation of the data and integrity metadata buffers as well as
-the choice in checksums is referred to as the Data Integrity
-Extensions.  As these extensions are outside the scope of the protocol
-bodies (T10, T13), Oracle and its partners are trying to standardize
-them within the Storage Networking Industry Association.
-
-----------------------------------------------------------------------
-3. KERNEL CHANGES
-
-The data integrity framework in Linux enables protection information
-to be pinned to I/Os and sent to/received from controllers that
-support it.
-
-The advantage to the integrity extensions in SCSI and SATA is that
-they enable us to protect the entire path from application to storage
-device.  However, at the same time this is also the biggest
-disadvantage. It means that the protection information must be in a
-format that can be understood by the disk.
-
-Generally Linux/POSIX applications are agnostic to the intricacies of
-the storage devices they are accessing.  The virtual filesystem switch
-and the block layer make things like hardware sector size and
-transport protocols completely transparent to the application.
-
-However, this level of detail is required when preparing the
-protection information to send to a disk.  Consequently, the very
-concept of an end-to-end protection scheme is a layering violation.
-It is completely unreasonable for an application to be aware whether
-it is accessing a SCSI or SATA disk.
-
-The data integrity support implemented in Linux attempts to hide this
-from the application.  As far as the application (and to some extent
-the kernel) is concerned, the integrity metadata is opaque information
-that's attached to the I/O.
-
-The current implementation allows the block layer to automatically
-generate the protection information for any I/O.  Eventually the
-intent is to move the integrity metadata calculation to userspace for
-user data.  Metadata and other I/O that originates within the kernel
-will still use the automatic generation interface.
-
-Some storage devices allow each hardware sector to be tagged with a
-16-bit value.  The owner of this tag space is the owner of the block
-device.  I.e. the filesystem in most cases.  The filesystem can use
-this extra space to tag sectors as they see fit.  Because the tag
-space is limited, the block interface allows tagging bigger chunks by
-way of interleaving.  This way, 8*16 bits of information can be
-attached to a typical 4KB filesystem block.
-
-This also means that applications such as fsck and mkfs will need
-access to manipulate the tags from user space.  A passthrough
-interface for this is being worked on.
-
-
-----------------------------------------------------------------------
-4. BLOCK LAYER IMPLEMENTATION DETAILS
-
-4.1 BIO
-
-The data integrity patches add a new field to struct bio when
-CONFIG_BLK_DEV_INTEGRITY is enabled.  bio_integrity(bio) returns a
-pointer to a struct bip which contains the bio integrity payload.
-Essentially a bip is a trimmed down struct bio which holds a bio_vec
-containing the integrity metadata and the required housekeeping
-information (bvec pool, vector count, etc.)
-
-A kernel subsystem can enable data integrity protection on a bio by
-calling bio_integrity_alloc(bio).  This will allocate and attach the
-bip to the bio.
-
-Individual pages containing integrity metadata can subsequently be
-attached using bio_integrity_add_page().
-
-bio_free() will automatically free the bip.
-
-
-4.2 BLOCK DEVICE
-
-Because the format of the protection data is tied to the physical
-disk, each block device has been extended with a block integrity
-profile (struct blk_integrity).  This optional profile is registered
-with the block layer using blk_integrity_register().
-
-The profile contains callback functions for generating and verifying
-the protection data, as well as getting and setting application tags.
-The profile also contains a few constants to aid in completing,
-merging and splitting the integrity metadata.
-
-Layered block devices will need to pick a profile that's appropriate
-for all subdevices.  blk_integrity_compare() can help with that.  DM
-and MD linear, RAID0 and RAID1 are currently supported.  RAID4/5/6
-will require extra work due to the application tag.
-
-
-----------------------------------------------------------------------
-5.0 BLOCK LAYER INTEGRITY API
-
-5.1 NORMAL FILESYSTEM
-
-    The normal filesystem is unaware that the underlying block device
-    is capable of sending/receiving integrity metadata.  The IMD will
-    be automatically generated by the block layer at submit_bio() time
-    in case of a WRITE.  A READ request will cause the I/O integrity
-    to be verified upon completion.
-
-    IMD generation and verification can be toggled using the
-
-      /sys/block/<bdev>/integrity/write_generate
-
-    and
-
-      /sys/block/<bdev>/integrity/read_verify
-
-    flags.
-
-
-5.2 INTEGRITY-AWARE FILESYSTEM
-
-    A filesystem that is integrity-aware can prepare I/Os with IMD
-    attached.  It can also use the application tag space if this is
-    supported by the block device.
-
-
-    bool bio_integrity_prep(bio);
-
-      To generate IMD for WRITE and to set up buffers for READ, the
-      filesystem must call bio_integrity_prep(bio).
-
-      Prior to calling this function, the bio data direction and start
-      sector must be set, and the bio should have all data pages
-      added.  It is up to the caller to ensure that the bio does not
-      change while I/O is in progress.
-      Complete bio with error if prepare failed for some reson.
-
-
-5.3 PASSING EXISTING INTEGRITY METADATA
-
-    Filesystems that either generate their own integrity metadata or
-    are capable of transferring IMD from user space can use the
-    following calls:
-
-
-    struct bip * bio_integrity_alloc(bio, gfp_mask, nr_pages);
-
-      Allocates the bio integrity payload and hangs it off of the bio.
-      nr_pages indicate how many pages of protection data need to be
-      stored in the integrity bio_vec list (similar to bio_alloc()).
-
-      The integrity payload will be freed at bio_free() time.
-
-
-    int bio_integrity_add_page(bio, page, len, offset);
-
-      Attaches a page containing integrity metadata to an existing
-      bio.  The bio must have an existing bip,
-      i.e. bio_integrity_alloc() must have been called.  For a WRITE,
-      the integrity metadata in the pages must be in a format
-      understood by the target device with the notable exception that
-      the sector numbers will be remapped as the request traverses the
-      I/O stack.  This implies that the pages added using this call
-      will be modified during I/O!  The first reference tag in the
-      integrity metadata must have a value of bip->bip_sector.
-
-      Pages can be added using bio_integrity_add_page() as long as
-      there is room in the bip bio_vec array (nr_pages).
-
-      Upon completion of a READ operation, the attached pages will
-      contain the integrity metadata received from the storage device.
-      It is up to the receiver to process them and verify data
-      integrity upon completion.
-
-
-5.4 REGISTERING A BLOCK DEVICE AS CAPABLE OF EXCHANGING INTEGRITY
-    METADATA
-
-    To enable integrity exchange on a block device the gendisk must be
-    registered as capable:
-
-    int blk_integrity_register(gendisk, blk_integrity);
-
-      The blk_integrity struct is a template and should contain the
-      following:
-
-        static struct blk_integrity my_profile = {
-            .name                   = "STANDARDSBODY-TYPE-VARIANT-CSUM",
-            .generate_fn            = my_generate_fn,
-                   .verify_fn              = my_verify_fn,
-           .tuple_size             = sizeof(struct my_tuple_size),
-           .tag_size               = <tag bytes per hw sector>,
-        };
-
-      'name' is a text string which will be visible in sysfs.  This is
-      part of the userland API so chose it carefully and never change
-      it.  The format is standards body-type-variant.
-      E.g. T10-DIF-TYPE1-IP or T13-EPP-0-CRC.
-
-      'generate_fn' generates appropriate integrity metadata (for WRITE).
-
-      'verify_fn' verifies that the data buffer matches the integrity
-      metadata.
-
-      'tuple_size' must be set to match the size of the integrity
-      metadata per sector.  I.e. 8 for DIF and EPP.
-
-      'tag_size' must be set to identify how many bytes of tag space
-      are available per hardware sector.  For DIF this is either 2 or
-      0 depending on the value of the Control Mode Page ATO bit.
-
-----------------------------------------------------------------------
-2007-12-24 Martin K. Petersen <martin.petersen@oracle.com>
diff --git a/Documentation/block/deadline-iosched.rst b/Documentation/block/deadline-iosched.rst
new file mode 100644 (file)
index 0000000..9f5c5a4
--- /dev/null
@@ -0,0 +1,72 @@
+==============================
+Deadline IO scheduler tunables
+==============================
+
+This little file attempts to document how the deadline io scheduler works.
+In particular, it will clarify the meaning of the exposed tunables that may be
+of interest to power users.
+
+Selecting IO schedulers
+-----------------------
+Refer to Documentation/block/switching-sched.rst for information on
+selecting an io scheduler on a per-device basis.
+
+------------------------------------------------------------------------------
+
+read_expire    (in ms)
+-----------------------
+
+The goal of the deadline io scheduler is to attempt to guarantee a start
+service time for a request. As we focus mainly on read latencies, this is
+tunable. When a read request first enters the io scheduler, it is assigned
+a deadline that is the current time + the read_expire value in units of
+milliseconds.
+
+
+write_expire   (in ms)
+-----------------------
+
+Similar to read_expire mentioned above, but for writes.
+
+
+fifo_batch     (number of requests)
+------------------------------------
+
+Requests are grouped into ``batches`` of a particular data direction (read or
+write) which are serviced in increasing sector order.  To limit extra seeking,
+deadline expiries are only checked between batches.  fifo_batch controls the
+maximum number of requests per batch.
+
+This parameter tunes the balance between per-request latency and aggregate
+throughput.  When low latency is the primary concern, smaller is better (where
+a value of 1 yields first-come first-served behaviour).  Increasing fifo_batch
+generally improves throughput, at the cost of latency variation.
+
+
+writes_starved (number of dispatches)
+--------------------------------------
+
+When we have to move requests from the io scheduler queue to the block
+device dispatch queue, we always give a preference to reads. However, we
+don't want to starve writes indefinitely either. So writes_starved controls
+how many times we give preference to reads over writes. When that has been
+done writes_starved number of times, we dispatch some writes based on the
+same criteria as reads.
+
+
+front_merges   (bool)
+----------------------
+
+Sometimes it happens that a request enters the io scheduler that is contiguous
+with a request that is already on the queue. Either it fits in the back of that
+request, or it fits at the front. That is called either a back merge candidate
+or a front merge candidate. Due to the way files are typically laid out,
+back merges are much more common than front merges. For some work loads, you
+may even know that it is a waste of time to spend any time attempting to
+front merge requests. Setting front_merges to 0 disables this functionality.
+Front merges may still occur due to the cached last_merge hint, but since
+that comes at basically 0 cost we leave that on. We simply disable the
+rbtree front sector lookup when the io scheduler merge function is called.
+
+
+Nov 11 2002, Jens Axboe <jens.axboe@oracle.com>
diff --git a/Documentation/block/deadline-iosched.txt b/Documentation/block/deadline-iosched.txt
deleted file mode 100644 (file)
index 2d82c80..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-Deadline IO scheduler tunables
-==============================
-
-This little file attempts to document how the deadline io scheduler works.
-In particular, it will clarify the meaning of the exposed tunables that may be
-of interest to power users.
-
-Selecting IO schedulers
------------------------
-Refer to Documentation/block/switching-sched.txt for information on
-selecting an io scheduler on a per-device basis.
-
-
-********************************************************************************
-
-
-read_expire    (in ms)
------------
-
-The goal of the deadline io scheduler is to attempt to guarantee a start
-service time for a request. As we focus mainly on read latencies, this is
-tunable. When a read request first enters the io scheduler, it is assigned
-a deadline that is the current time + the read_expire value in units of
-milliseconds.
-
-
-write_expire   (in ms)
------------
-
-Similar to read_expire mentioned above, but for writes.
-
-
-fifo_batch     (number of requests)
-----------
-
-Requests are grouped into ``batches'' of a particular data direction (read or
-write) which are serviced in increasing sector order.  To limit extra seeking,
-deadline expiries are only checked between batches.  fifo_batch controls the
-maximum number of requests per batch.
-
-This parameter tunes the balance between per-request latency and aggregate
-throughput.  When low latency is the primary concern, smaller is better (where
-a value of 1 yields first-come first-served behaviour).  Increasing fifo_batch
-generally improves throughput, at the cost of latency variation.
-
-
-writes_starved (number of dispatches)
---------------
-
-When we have to move requests from the io scheduler queue to the block
-device dispatch queue, we always give a preference to reads. However, we
-don't want to starve writes indefinitely either. So writes_starved controls
-how many times we give preference to reads over writes. When that has been
-done writes_starved number of times, we dispatch some writes based on the
-same criteria as reads.
-
-
-front_merges   (bool)
-------------
-
-Sometimes it happens that a request enters the io scheduler that is contiguous
-with a request that is already on the queue. Either it fits in the back of that
-request, or it fits at the front. That is called either a back merge candidate
-or a front merge candidate. Due to the way files are typically laid out,
-back merges are much more common than front merges. For some work loads, you
-may even know that it is a waste of time to spend any time attempting to
-front merge requests. Setting front_merges to 0 disables this functionality.
-Front merges may still occur due to the cached last_merge hint, but since
-that comes at basically 0 cost we leave that on. We simply disable the
-rbtree front sector lookup when the io scheduler merge function is called.
-
-
-Nov 11 2002, Jens Axboe <jens.axboe@oracle.com>
-
-
diff --git a/Documentation/block/index.rst b/Documentation/block/index.rst
new file mode 100644 (file)
index 0000000..3fa7a52
--- /dev/null
@@ -0,0 +1,25 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=====
+Block
+=====
+
+.. toctree::
+   :maxdepth: 1
+
+   bfq-iosched
+   biodoc
+   biovecs
+   capability
+   cmdline-partition
+   data-integrity
+   deadline-iosched
+   ioprio
+   kyber-iosched
+   null_blk
+   pr
+   queue-sysfs
+   request
+   stat
+   switching-sched
+   writeback_cache_control
diff --git a/Documentation/block/ioprio.rst b/Documentation/block/ioprio.rst
new file mode 100644 (file)
index 0000000..f72b0de
--- /dev/null
@@ -0,0 +1,182 @@
+===================
+Block io priorities
+===================
+
+
+Intro
+-----
+
+With the introduction of cfq v3 (aka cfq-ts or time sliced cfq), basic io
+priorities are supported for reads on files.  This enables users to io nice
+processes or process groups, similar to what has been possible with cpu
+scheduling for ages.  This document mainly details the current possibilities
+with cfq; other io schedulers do not support io priorities thus far.
+
+Scheduling classes
+------------------
+
+CFQ implements three generic scheduling classes that determine how io is
+served for a process.
+
+IOPRIO_CLASS_RT: This is the realtime io class. This scheduling class is given
+higher priority than any other in the system, processes from this class are
+given first access to the disk every time. Thus it needs to be used with some
+care, one io RT process can starve the entire system. Within the RT class,
+there are 8 levels of class data that determine exactly how much time this
+process needs the disk for on each service. In the future this might change
+to be more directly mappable to performance, by passing in a wanted data
+rate instead.
+
+IOPRIO_CLASS_BE: This is the best-effort scheduling class, which is the default
+for any process that hasn't set a specific io priority. The class data
+determines how much io bandwidth the process will get, it's directly mappable
+to the cpu nice levels just more coarsely implemented. 0 is the highest
+BE prio level, 7 is the lowest. The mapping between cpu nice level and io
+nice level is determined as: io_nice = (cpu_nice + 20) / 5.
+
+IOPRIO_CLASS_IDLE: This is the idle scheduling class, processes running at this
+level only get io time when no one else needs the disk. The idle class has no
+class data, since it doesn't really apply here.
+
+Tools
+-----
+
+See below for a sample ionice tool. Usage::
+
+       # ionice -c<class> -n<level> -p<pid>
+
+If pid isn't given, the current process is assumed. IO priority settings
+are inherited on fork, so you can use ionice to start the process at a given
+level::
+
+       # ionice -c2 -n0 /bin/ls
+
+will run ls at the best-effort scheduling class at the highest priority.
+For a running process, you can give the pid instead::
+
+       # ionice -c1 -n2 -p100
+
+will change pid 100 to run at the realtime scheduling class, at priority 2.
+
+ionice.c tool::
+
+  #include <stdio.h>
+  #include <stdlib.h>
+  #include <errno.h>
+  #include <getopt.h>
+  #include <unistd.h>
+  #include <sys/ptrace.h>
+  #include <asm/unistd.h>
+
+  extern int sys_ioprio_set(int, int, int);
+  extern int sys_ioprio_get(int, int);
+
+  #if defined(__i386__)
+  #define __NR_ioprio_set              289
+  #define __NR_ioprio_get              290
+  #elif defined(__ppc__)
+  #define __NR_ioprio_set              273
+  #define __NR_ioprio_get              274
+  #elif defined(__x86_64__)
+  #define __NR_ioprio_set              251
+  #define __NR_ioprio_get              252
+  #elif defined(__ia64__)
+  #define __NR_ioprio_set              1274
+  #define __NR_ioprio_get              1275
+  #else
+  #error "Unsupported arch"
+  #endif
+
+  static inline int ioprio_set(int which, int who, int ioprio)
+  {
+       return syscall(__NR_ioprio_set, which, who, ioprio);
+  }
+
+  static inline int ioprio_get(int which, int who)
+  {
+       return syscall(__NR_ioprio_get, which, who);
+  }
+
+  enum {
+       IOPRIO_CLASS_NONE,
+       IOPRIO_CLASS_RT,
+       IOPRIO_CLASS_BE,
+       IOPRIO_CLASS_IDLE,
+  };
+
+  enum {
+       IOPRIO_WHO_PROCESS = 1,
+       IOPRIO_WHO_PGRP,
+       IOPRIO_WHO_USER,
+  };
+
+  #define IOPRIO_CLASS_SHIFT   13
+
+  const char *to_prio[] = { "none", "realtime", "best-effort", "idle", };
+
+  int main(int argc, char *argv[])
+  {
+       int ioprio = 4, set = 0, ioprio_class = IOPRIO_CLASS_BE;
+       int c, pid = 0;
+
+       while ((c = getopt(argc, argv, "+n:c:p:")) != EOF) {
+               switch (c) {
+               case 'n':
+                       ioprio = strtol(optarg, NULL, 10);
+                       set = 1;
+                       break;
+               case 'c':
+                       ioprio_class = strtol(optarg, NULL, 10);
+                       set = 1;
+                       break;
+               case 'p':
+                       pid = strtol(optarg, NULL, 10);
+                       break;
+               }
+       }
+
+       switch (ioprio_class) {
+               case IOPRIO_CLASS_NONE:
+                       ioprio_class = IOPRIO_CLASS_BE;
+                       break;
+               case IOPRIO_CLASS_RT:
+               case IOPRIO_CLASS_BE:
+                       break;
+               case IOPRIO_CLASS_IDLE:
+                       ioprio = 7;
+                       break;
+               default:
+                       printf("bad prio class %d\n", ioprio_class);
+                       return 1;
+       }
+
+       if (!set) {
+               if (!pid && argv[optind])
+                       pid = strtol(argv[optind], NULL, 10);
+
+               ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid);
+
+               printf("pid=%d, %d\n", pid, ioprio);
+
+               if (ioprio == -1)
+                       perror("ioprio_get");
+               else {
+                       ioprio_class = ioprio >> IOPRIO_CLASS_SHIFT;
+                       ioprio = ioprio & 0xff;
+                       printf("%s: prio %d\n", to_prio[ioprio_class], ioprio);
+               }
+       } else {
+               if (ioprio_set(IOPRIO_WHO_PROCESS, pid, ioprio | ioprio_class << IOPRIO_CLASS_SHIFT) == -1) {
+                       perror("ioprio_set");
+                       return 1;
+               }
+
+               if (argv[optind])
+                       execvp(argv[optind], &argv[optind]);
+       }
+
+       return 0;
+  }
+
+
+March 11 2005, Jens Axboe <jens.axboe@oracle.com>
diff --git a/Documentation/block/ioprio.txt b/Documentation/block/ioprio.txt
deleted file mode 100644 (file)
index 8ed8c59..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-Block io priorities
-===================
-
-
-Intro
------
-
-With the introduction of cfq v3 (aka cfq-ts or time sliced cfq), basic io
-priorities are supported for reads on files.  This enables users to io nice
-processes or process groups, similar to what has been possible with cpu
-scheduling for ages.  This document mainly details the current possibilities
-with cfq; other io schedulers do not support io priorities thus far.
-
-Scheduling classes
-------------------
-
-CFQ implements three generic scheduling classes that determine how io is
-served for a process.
-
-IOPRIO_CLASS_RT: This is the realtime io class. This scheduling class is given
-higher priority than any other in the system, processes from this class are
-given first access to the disk every time. Thus it needs to be used with some
-care, one io RT process can starve the entire system. Within the RT class,
-there are 8 levels of class data that determine exactly how much time this
-process needs the disk for on each service. In the future this might change
-to be more directly mappable to performance, by passing in a wanted data
-rate instead.
-
-IOPRIO_CLASS_BE: This is the best-effort scheduling class, which is the default
-for any process that hasn't set a specific io priority. The class data
-determines how much io bandwidth the process will get, it's directly mappable
-to the cpu nice levels just more coarsely implemented. 0 is the highest
-BE prio level, 7 is the lowest. The mapping between cpu nice level and io
-nice level is determined as: io_nice = (cpu_nice + 20) / 5.
-
-IOPRIO_CLASS_IDLE: This is the idle scheduling class, processes running at this
-level only get io time when no one else needs the disk. The idle class has no
-class data, since it doesn't really apply here.
-
-Tools
------
-
-See below for a sample ionice tool. Usage:
-
-# ionice -c<class> -n<level> -p<pid>
-
-If pid isn't given, the current process is assumed. IO priority settings
-are inherited on fork, so you can use ionice to start the process at a given
-level:
-
-# ionice -c2 -n0 /bin/ls
-
-will run ls at the best-effort scheduling class at the highest priority.
-For a running process, you can give the pid instead:
-
-# ionice -c1 -n2 -p100
-
-will change pid 100 to run at the realtime scheduling class, at priority 2.
-
----> snip ionice.c tool <---
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <getopt.h>
-#include <unistd.h>
-#include <sys/ptrace.h>
-#include <asm/unistd.h>
-
-extern int sys_ioprio_set(int, int, int);
-extern int sys_ioprio_get(int, int);
-
-#if defined(__i386__)
-#define __NR_ioprio_set                289
-#define __NR_ioprio_get                290
-#elif defined(__ppc__)
-#define __NR_ioprio_set                273
-#define __NR_ioprio_get                274
-#elif defined(__x86_64__)
-#define __NR_ioprio_set                251
-#define __NR_ioprio_get                252
-#elif defined(__ia64__)
-#define __NR_ioprio_set                1274
-#define __NR_ioprio_get                1275
-#else
-#error "Unsupported arch"
-#endif
-
-static inline int ioprio_set(int which, int who, int ioprio)
-{
-       return syscall(__NR_ioprio_set, which, who, ioprio);
-}
-
-static inline int ioprio_get(int which, int who)
-{
-       return syscall(__NR_ioprio_get, which, who);
-}
-
-enum {
-       IOPRIO_CLASS_NONE,
-       IOPRIO_CLASS_RT,
-       IOPRIO_CLASS_BE,
-       IOPRIO_CLASS_IDLE,
-};
-
-enum {
-       IOPRIO_WHO_PROCESS = 1,
-       IOPRIO_WHO_PGRP,
-       IOPRIO_WHO_USER,
-};
-
-#define IOPRIO_CLASS_SHIFT     13
-
-const char *to_prio[] = { "none", "realtime", "best-effort", "idle", };
-
-int main(int argc, char *argv[])
-{
-       int ioprio = 4, set = 0, ioprio_class = IOPRIO_CLASS_BE;
-       int c, pid = 0;
-
-       while ((c = getopt(argc, argv, "+n:c:p:")) != EOF) {
-               switch (c) {
-               case 'n':
-                       ioprio = strtol(optarg, NULL, 10);
-                       set = 1;
-                       break;
-               case 'c':
-                       ioprio_class = strtol(optarg, NULL, 10);
-                       set = 1;
-                       break;
-               case 'p':
-                       pid = strtol(optarg, NULL, 10);
-                       break;
-               }
-       }
-
-       switch (ioprio_class) {
-               case IOPRIO_CLASS_NONE:
-                       ioprio_class = IOPRIO_CLASS_BE;
-                       break;
-               case IOPRIO_CLASS_RT:
-               case IOPRIO_CLASS_BE:
-                       break;
-               case IOPRIO_CLASS_IDLE:
-                       ioprio = 7;
-                       break;
-               default:
-                       printf("bad prio class %d\n", ioprio_class);
-                       return 1;
-       }
-
-       if (!set) {
-               if (!pid && argv[optind])
-                       pid = strtol(argv[optind], NULL, 10);
-
-               ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid);
-
-               printf("pid=%d, %d\n", pid, ioprio);
-
-               if (ioprio == -1)
-                       perror("ioprio_get");
-               else {
-                       ioprio_class = ioprio >> IOPRIO_CLASS_SHIFT;
-                       ioprio = ioprio & 0xff;
-                       printf("%s: prio %d\n", to_prio[ioprio_class], ioprio);
-               }
-       } else {
-               if (ioprio_set(IOPRIO_WHO_PROCESS, pid, ioprio | ioprio_class << IOPRIO_CLASS_SHIFT) == -1) {
-                       perror("ioprio_set");
-                       return 1;
-               }
-
-               if (argv[optind])
-                       execvp(argv[optind], &argv[optind]);
-       }
-
-       return 0;
-}
-
----> snip ionice.c tool <---
-
-
-March 11 2005, Jens Axboe <jens.axboe@oracle.com>
diff --git a/Documentation/block/kyber-iosched.rst b/Documentation/block/kyber-iosched.rst
new file mode 100644 (file)
index 0000000..3e164dd
--- /dev/null
@@ -0,0 +1,15 @@
+============================
+Kyber I/O scheduler tunables
+============================
+
+The only two tunables for the Kyber scheduler are the target latencies for
+reads and synchronous writes. Kyber will throttle requests in order to meet
+these target latencies.
+
+read_lat_nsec
+-------------
+Target latency for reads (in nanoseconds).
+
+write_lat_nsec
+--------------
+Target latency for synchronous writes (in nanoseconds).
diff --git a/Documentation/block/kyber-iosched.txt b/Documentation/block/kyber-iosched.txt
deleted file mode 100644 (file)
index e94feac..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-Kyber I/O scheduler tunables
-===========================
-
-The only two tunables for the Kyber scheduler are the target latencies for
-reads and synchronous writes. Kyber will throttle requests in order to meet
-these target latencies.
-
-read_lat_nsec
--------------
-Target latency for reads (in nanoseconds).
-
-write_lat_nsec
---------------
-Target latency for synchronous writes (in nanoseconds).
diff --git a/Documentation/block/null_blk.rst b/Documentation/block/null_blk.rst
new file mode 100644 (file)
index 0000000..31451d8
--- /dev/null
@@ -0,0 +1,126 @@
+========================
+Null block device driver
+========================
+
+1. Overview
+===========
+
+The null block device (/dev/nullb*) is used for benchmarking the various
+block-layer implementations. It emulates a block device of X gigabytes in size.
+The following instances are possible:
+
+  Single-queue block-layer
+
+    - Request-based.
+    - Single submission queue per device.
+    - Implements IO scheduling algorithms (CFQ, Deadline, noop).
+
+  Multi-queue block-layer
+
+    - Request-based.
+    - Configurable submission queues per device.
+
+  No block-layer (Known as bio-based)
+
+    - Bio-based. IO requests are submitted directly to the device driver.
+    - Directly accepts bio data structure and returns them.
+
+All of them have a completion queue for each core in the system.
+
+2. Module parameters applicable for all instances
+=================================================
+
+queue_mode=[0-2]: Default: 2-Multi-queue
+  Selects which block-layer the module should instantiate with.
+
+  =  ============
+  0  Bio-based
+  1  Single-queue
+  2  Multi-queue
+  =  ============
+
+home_node=[0--nr_nodes]: Default: NUMA_NO_NODE
+  Selects what CPU node the data structures are allocated from.
+
+gb=[Size in GB]: Default: 250GB
+  The size of the device reported to the system.
+
+bs=[Block size (in bytes)]: Default: 512 bytes
+  The block size reported to the system.
+
+nr_devices=[Number of devices]: Default: 1
+  Number of block devices instantiated. They are instantiated as /dev/nullb0,
+  etc.
+
+irqmode=[0-2]: Default: 1-Soft-irq
+  The completion mode used for completing IOs to the block-layer.
+
+  =  ===========================================================================
+  0  None.
+  1  Soft-irq. Uses IPI to complete IOs across CPU nodes. Simulates the overhead
+     when IOs are issued from another CPU node than the home the device is
+     connected to.
+  2  Timer: Waits a specific period (completion_nsec) for each IO before
+     completion.
+  =  ===========================================================================
+
+completion_nsec=[ns]: Default: 10,000ns
+  Combined with irqmode=2 (timer). The time each completion event must wait.
+
+submit_queues=[1..nr_cpus]:
+  The number of submission queues attached to the device driver. If unset, it
+  defaults to 1. For multi-queue, it is ignored when use_per_node_hctx module
+  parameter is 1.
+
+hw_queue_depth=[0..qdepth]: Default: 64
+  The hardware queue depth of the device.
+
+III: Multi-queue specific parameters
+
+use_per_node_hctx=[0/1]: Default: 0
+
+  =  =====================================================================
+  0  The number of submit queues are set to the value of the submit_queues
+     parameter.
+  1  The multi-queue block layer is instantiated with a hardware dispatch
+     queue for each CPU node in the system.
+  =  =====================================================================
+
+no_sched=[0/1]: Default: 0
+
+  =  ======================================
+  0  nullb* use default blk-mq io scheduler
+  1  nullb* doesn't use io scheduler
+  =  ======================================
+
+blocking=[0/1]: Default: 0
+
+  =  ===============================================================
+  0  Register as a non-blocking blk-mq driver device.
+  1  Register as a blocking blk-mq driver device, null_blk will set
+     the BLK_MQ_F_BLOCKING flag, indicating that it sometimes/always
+     needs to block in its ->queue_rq() function.
+  =  ===============================================================
+
+shared_tags=[0/1]: Default: 0
+
+  =  ================================================================
+  0  Tag set is not shared.
+  1  Tag set shared between devices for blk-mq. Only makes sense with
+     nr_devices > 1, otherwise there's no tag set to share.
+  =  ================================================================
+
+zoned=[0/1]: Default: 0
+
+  =  ======================================================================
+  0  Block device is exposed as a random-access block device.
+  1  Block device is exposed as a host-managed zoned block device. Requires
+     CONFIG_BLK_DEV_ZONED.
+  =  ======================================================================
+
+zone_size=[MB]: Default: 256
+  Per zone size when exposed as a zoned block device. Must be a power of two.
+
+zone_nr_conv=[nr_conv]: Default: 0
+  The number of conventional zones to create when block device is zoned.  If
+  zone_nr_conv >= nr_zones, it will be reduced to nr_zones - 1.
diff --git a/Documentation/block/null_blk.txt b/Documentation/block/null_blk.txt
deleted file mode 100644 (file)
index 41f0a3d..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-Null block device driver
-================================================================================
-
-I. Overview
-
-The null block device (/dev/nullb*) is used for benchmarking the various
-block-layer implementations. It emulates a block device of X gigabytes in size.
-The following instances are possible:
-
-  Single-queue block-layer
-    - Request-based.
-    - Single submission queue per device.
-    - Implements IO scheduling algorithms (CFQ, Deadline, noop).
-  Multi-queue block-layer
-    - Request-based.
-    - Configurable submission queues per device.
-  No block-layer (Known as bio-based)
-    - Bio-based. IO requests are submitted directly to the device driver.
-    - Directly accepts bio data structure and returns them.
-
-All of them have a completion queue for each core in the system.
-
-II. Module parameters applicable for all instances:
-
-queue_mode=[0-2]: Default: 2-Multi-queue
-  Selects which block-layer the module should instantiate with.
-
-  0: Bio-based.
-  1: Single-queue.
-  2: Multi-queue.
-
-home_node=[0--nr_nodes]: Default: NUMA_NO_NODE
-  Selects what CPU node the data structures are allocated from.
-
-gb=[Size in GB]: Default: 250GB
-  The size of the device reported to the system.
-
-bs=[Block size (in bytes)]: Default: 512 bytes
-  The block size reported to the system.
-
-nr_devices=[Number of devices]: Default: 1
-  Number of block devices instantiated. They are instantiated as /dev/nullb0,
-  etc.
-
-irqmode=[0-2]: Default: 1-Soft-irq
-  The completion mode used for completing IOs to the block-layer.
-
-  0: None.
-  1: Soft-irq. Uses IPI to complete IOs across CPU nodes. Simulates the overhead
-     when IOs are issued from another CPU node than the home the device is
-     connected to.
-  2: Timer: Waits a specific period (completion_nsec) for each IO before
-     completion.
-
-completion_nsec=[ns]: Default: 10,000ns
-  Combined with irqmode=2 (timer). The time each completion event must wait.
-
-submit_queues=[1..nr_cpus]:
-  The number of submission queues attached to the device driver. If unset, it
-  defaults to 1. For multi-queue, it is ignored when use_per_node_hctx module
-  parameter is 1.
-
-hw_queue_depth=[0..qdepth]: Default: 64
-  The hardware queue depth of the device.
-
-III: Multi-queue specific parameters
-
-use_per_node_hctx=[0/1]: Default: 0
-  0: The number of submit queues are set to the value of the submit_queues
-     parameter.
-  1: The multi-queue block layer is instantiated with a hardware dispatch
-     queue for each CPU node in the system.
-
-no_sched=[0/1]: Default: 0
-  0: nullb* use default blk-mq io scheduler.
-  1: nullb* doesn't use io scheduler.
-
-blocking=[0/1]: Default: 0
-  0: Register as a non-blocking blk-mq driver device.
-  1: Register as a blocking blk-mq driver device, null_blk will set
-     the BLK_MQ_F_BLOCKING flag, indicating that it sometimes/always
-     needs to block in its ->queue_rq() function.
-
-shared_tags=[0/1]: Default: 0
-  0: Tag set is not shared.
-  1: Tag set shared between devices for blk-mq. Only makes sense with
-     nr_devices > 1, otherwise there's no tag set to share.
-
-zoned=[0/1]: Default: 0
-  0: Block device is exposed as a random-access block device.
-  1: Block device is exposed as a host-managed zoned block device. Requires
-     CONFIG_BLK_DEV_ZONED.
-
-zone_size=[MB]: Default: 256
-  Per zone size when exposed as a zoned block device. Must be a power of two.
-
-zone_nr_conv=[nr_conv]: Default: 0
-  The number of conventional zones to create when block device is zoned.  If
-  zone_nr_conv >= nr_zones, it will be reduced to nr_zones - 1.
diff --git a/Documentation/block/pr.rst b/Documentation/block/pr.rst
new file mode 100644 (file)
index 0000000..30ea1c2
--- /dev/null
@@ -0,0 +1,119 @@
+===============================================
+Block layer support for Persistent Reservations
+===============================================
+
+The Linux kernel supports a user space interface for simplified
+Persistent Reservations which map to block devices that support
+these (like SCSI). Persistent Reservations allow restricting
+access to block devices to specific initiators in a shared storage
+setup.
+
+This document gives a general overview of the support ioctl commands.
+For a more detailed reference please refer the the SCSI Primary
+Commands standard, specifically the section on Reservations and the
+"PERSISTENT RESERVE IN" and "PERSISTENT RESERVE OUT" commands.
+
+All implementations are expected to ensure the reservations survive
+a power loss and cover all connections in a multi path environment.
+These behaviors are optional in SPC but will be automatically applied
+by Linux.
+
+
+The following types of reservations are supported:
+--------------------------------------------------
+
+ - PR_WRITE_EXCLUSIVE
+       Only the initiator that owns the reservation can write to the
+       device.  Any initiator can read from the device.
+
+ - PR_EXCLUSIVE_ACCESS
+       Only the initiator that owns the reservation can access the
+       device.
+
+ - PR_WRITE_EXCLUSIVE_REG_ONLY
+       Only initiators with a registered key can write to the device,
+       Any initiator can read from the device.
+
+ - PR_EXCLUSIVE_ACCESS_REG_ONLY
+       Only initiators with a registered key can access the device.
+
+ - PR_WRITE_EXCLUSIVE_ALL_REGS
+
+       Only initiators with a registered key can write to the device,
+       Any initiator can read from the device.
+       All initiators with a registered key are considered reservation
+       holders.
+       Please reference the SPC spec on the meaning of a reservation
+       holder if you want to use this type.
+
+ - PR_EXCLUSIVE_ACCESS_ALL_REGS
+       Only initiators with a registered key can access the device.
+       All initiators with a registered key are considered reservation
+       holders.
+       Please reference the SPC spec on the meaning of a reservation
+       holder if you want to use this type.
+
+
+The following ioctl are supported:
+----------------------------------
+
+1. IOC_PR_REGISTER
+^^^^^^^^^^^^^^^^^^
+
+This ioctl command registers a new reservation if the new_key argument
+is non-null.  If no existing reservation exists old_key must be zero,
+if an existing reservation should be replaced old_key must contain
+the old reservation key.
+
+If the new_key argument is 0 it unregisters the existing reservation passed
+in old_key.
+
+
+2. IOC_PR_RESERVE
+^^^^^^^^^^^^^^^^^
+
+This ioctl command reserves the device and thus restricts access for other
+devices based on the type argument.  The key argument must be the existing
+reservation key for the device as acquired by the IOC_PR_REGISTER,
+IOC_PR_REGISTER_IGNORE, IOC_PR_PREEMPT or IOC_PR_PREEMPT_ABORT commands.
+
+
+3. IOC_PR_RELEASE
+^^^^^^^^^^^^^^^^^
+
+This ioctl command releases the reservation specified by key and flags
+and thus removes any access restriction implied by it.
+
+
+4. IOC_PR_PREEMPT
+^^^^^^^^^^^^^^^^^
+
+This ioctl command releases the existing reservation referred to by
+old_key and replaces it with a new reservation of type for the
+reservation key new_key.
+
+
+5. IOC_PR_PREEMPT_ABORT
+^^^^^^^^^^^^^^^^^^^^^^^
+
+This ioctl command works like IOC_PR_PREEMPT except that it also aborts
+any outstanding command sent over a connection identified by old_key.
+
+6. IOC_PR_CLEAR
+^^^^^^^^^^^^^^^
+
+This ioctl command unregisters both key and any other reservation key
+registered with the device and drops any existing reservation.
+
+
+Flags
+-----
+
+All the ioctls have a flag field.  Currently only one flag is supported:
+
+ - PR_FL_IGNORE_KEY
+       Ignore the existing reservation key.  This is commonly supported for
+       IOC_PR_REGISTER, and some implementation may support the flag for
+       IOC_PR_RESERVE.
+
+For all unknown flags the kernel will return -EOPNOTSUPP.
diff --git a/Documentation/block/pr.txt b/Documentation/block/pr.txt
deleted file mode 100644 (file)
index ac9b8e7..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-
-Block layer support for Persistent Reservations
-===============================================
-
-The Linux kernel supports a user space interface for simplified
-Persistent Reservations which map to block devices that support
-these (like SCSI). Persistent Reservations allow restricting
-access to block devices to specific initiators in a shared storage
-setup.
-
-This document gives a general overview of the support ioctl commands.
-For a more detailed reference please refer the the SCSI Primary
-Commands standard, specifically the section on Reservations and the
-"PERSISTENT RESERVE IN" and "PERSISTENT RESERVE OUT" commands.
-
-All implementations are expected to ensure the reservations survive
-a power loss and cover all connections in a multi path environment.
-These behaviors are optional in SPC but will be automatically applied
-by Linux.
-
-
-The following types of reservations are supported:
---------------------------------------------------
-
- - PR_WRITE_EXCLUSIVE
-
-       Only the initiator that owns the reservation can write to the
-       device.  Any initiator can read from the device.
-
- - PR_EXCLUSIVE_ACCESS
-
-       Only the initiator that owns the reservation can access the
-       device.
-
- - PR_WRITE_EXCLUSIVE_REG_ONLY
-
-       Only initiators with a registered key can write to the device,
-       Any initiator can read from the device.
-
- - PR_EXCLUSIVE_ACCESS_REG_ONLY
-
-       Only initiators with a registered key can access the device.
-
- - PR_WRITE_EXCLUSIVE_ALL_REGS
-
-       Only initiators with a registered key can write to the device,
-       Any initiator can read from the device.
-       All initiators with a registered key are considered reservation
-       holders.
-       Please reference the SPC spec on the meaning of a reservation
-       holder if you want to use this type. 
-
- - PR_EXCLUSIVE_ACCESS_ALL_REGS
-
-       Only initiators with a registered key can access the device.
-       All initiators with a registered key are considered reservation
-       holders.
-       Please reference the SPC spec on the meaning of a reservation
-       holder if you want to use this type. 
-
-
-The following ioctl are supported:
-----------------------------------
-
-1. IOC_PR_REGISTER
-
-This ioctl command registers a new reservation if the new_key argument
-is non-null.  If no existing reservation exists old_key must be zero,
-if an existing reservation should be replaced old_key must contain
-the old reservation key.
-
-If the new_key argument is 0 it unregisters the existing reservation passed
-in old_key.
-
-
-2. IOC_PR_RESERVE
-
-This ioctl command reserves the device and thus restricts access for other
-devices based on the type argument.  The key argument must be the existing
-reservation key for the device as acquired by the IOC_PR_REGISTER,
-IOC_PR_REGISTER_IGNORE, IOC_PR_PREEMPT or IOC_PR_PREEMPT_ABORT commands.
-
-
-3. IOC_PR_RELEASE
-
-This ioctl command releases the reservation specified by key and flags
-and thus removes any access restriction implied by it.
-
-
-4. IOC_PR_PREEMPT
-
-This ioctl command releases the existing reservation referred to by
-old_key and replaces it with a new reservation of type for the
-reservation key new_key.
-
-
-5. IOC_PR_PREEMPT_ABORT
-
-This ioctl command works like IOC_PR_PREEMPT except that it also aborts
-any outstanding command sent over a connection identified by old_key.
-
-6. IOC_PR_CLEAR
-
-This ioctl command unregisters both key and any other reservation key
-registered with the device and drops any existing reservation.
-
-
-Flags
------
-
-All the ioctls have a flag field.  Currently only one flag is supported:
-
- - PR_FL_IGNORE_KEY
-
-       Ignore the existing reservation key.  This is commonly supported for
-       IOC_PR_REGISTER, and some implementation may support the flag for
-       IOC_PR_RESERVE.
-
-For all unknown flags the kernel will return -EOPNOTSUPP.
diff --git a/Documentation/block/queue-sysfs.rst b/Documentation/block/queue-sysfs.rst
new file mode 100644 (file)
index 0000000..6a8513a
--- /dev/null
@@ -0,0 +1,254 @@
+=================
+Queue sysfs files
+=================
+
+This text file will detail the queue files that are located in the sysfs tree
+for each block device. Note that stacked devices typically do not export
+any settings, since their queue merely functions are a remapping target.
+These files are the ones found in the /sys/block/xxx/queue/ directory.
+
+Files denoted with a RO postfix are readonly and the RW postfix means
+read-write.
+
+add_random (RW)
+---------------
+This file allows to turn off the disk entropy contribution. Default
+value of this file is '1'(on).
+
+chunk_sectors (RO)
+------------------
+This has different meaning depending on the type of the block device.
+For a RAID device (dm-raid), chunk_sectors indicates the size in 512B sectors
+of the RAID volume stripe segment. For a zoned block device, either host-aware
+or host-managed, chunk_sectors indicates the size in 512B sectors of the zones
+of the device, with the eventual exception of the last zone of the device which
+may be smaller.
+
+dax (RO)
+--------
+This file indicates whether the device supports Direct Access (DAX),
+used by CPU-addressable storage to bypass the pagecache.  It shows '1'
+if true, '0' if not.
+
+discard_granularity (RO)
+------------------------
+This shows the size of internal allocation of the device in bytes, if
+reported by the device. A value of '0' means device does not support
+the discard functionality.
+
+discard_max_hw_bytes (RO)
+-------------------------
+Devices that support discard functionality may have internal limits on
+the number of bytes that can be trimmed or unmapped in a single operation.
+The discard_max_bytes parameter is set by the device driver to the maximum
+number of bytes that can be discarded in a single operation. Discard
+requests issued to the device must not exceed this limit. A discard_max_bytes
+value of 0 means that the device does not support discard functionality.
+
+discard_max_bytes (RW)
+----------------------
+While discard_max_hw_bytes is the hardware limit for the device, this
+setting is the software limit. Some devices exhibit large latencies when
+large discards are issued, setting this value lower will make Linux issue
+smaller discards and potentially help reduce latencies induced by large
+discard operations.
+
+discard_zeroes_data (RO)
+------------------------
+Obsolete. Always zero.
+
+fua (RO)
+--------
+Whether or not the block driver supports the FUA flag for write requests.
+FUA stands for Force Unit Access. If the FUA flag is set that means that
+write requests must bypass the volatile cache of the storage device.
+
+hw_sector_size (RO)
+-------------------
+This is the hardware sector size of the device, in bytes.
+
+io_poll (RW)
+------------
+When read, this file shows whether polling is enabled (1) or disabled
+(0).  Writing '0' to this file will disable polling for this device.
+Writing any non-zero value will enable this feature.
+
+io_poll_delay (RW)
+------------------
+If polling is enabled, this controls what kind of polling will be
+performed. It defaults to -1, which is classic polling. In this mode,
+the CPU will repeatedly ask for completions without giving up any time.
+If set to 0, a hybrid polling mode is used, where the kernel will attempt
+to make an educated guess at when the IO will complete. Based on this
+guess, the kernel will put the process issuing IO to sleep for an amount
+of time, before entering a classic poll loop. This mode might be a
+little slower than pure classic polling, but it will be more efficient.
+If set to a value larger than 0, the kernel will put the process issuing
+IO to sleep for this amount of microseconds before entering classic
+polling.
+
+io_timeout (RW)
+---------------
+io_timeout is the request timeout in milliseconds. If a request does not
+complete in this time then the block driver timeout handler is invoked.
+That timeout handler can decide to retry the request, to fail it or to start
+a device recovery strategy.
+
+iostats (RW)
+-------------
+This file is used to control (on/off) the iostats accounting of the
+disk.
+
+logical_block_size (RO)
+-----------------------
+This is the logical block size of the device, in bytes.
+
+max_discard_segments (RO)
+-------------------------
+The maximum number of DMA scatter/gather entries in a discard request.
+
+max_hw_sectors_kb (RO)
+----------------------
+This is the maximum number of kilobytes supported in a single data transfer.
+
+max_integrity_segments (RO)
+---------------------------
+Maximum number of elements in a DMA scatter/gather list with integrity
+data that will be submitted by the block layer core to the associated
+block driver.
+
+max_sectors_kb (RW)
+-------------------
+This is the maximum number of kilobytes that the block layer will allow
+for a filesystem request. Must be smaller than or equal to the maximum
+size allowed by the hardware.
+
+max_segments (RO)
+-----------------
+Maximum number of elements in a DMA scatter/gather list that is submitted
+to the associated block driver.
+
+max_segment_size (RO)
+---------------------
+Maximum size in bytes of a single element in a DMA scatter/gather list.
+
+minimum_io_size (RO)
+--------------------
+This is the smallest preferred IO size reported by the device.
+
+nomerges (RW)
+-------------
+This enables the user to disable the lookup logic involved with IO
+merging requests in the block layer. By default (0) all merges are
+enabled. When set to 1 only simple one-hit merges will be tried. When
+set to 2 no merge algorithms will be tried (including one-hit or more
+complex tree/hash lookups).
+
+nr_requests (RW)
+----------------
+This controls how many requests may be allocated in the block layer for
+read or write requests. Note that the total allocated number may be twice
+this amount, since it applies only to reads or writes (not the accumulated
+sum).
+
+To avoid priority inversion through request starvation, a request
+queue maintains a separate request pool per each cgroup when
+CONFIG_BLK_CGROUP is enabled, and this parameter applies to each such
+per-block-cgroup request pool.  IOW, if there are N block cgroups,
+each request queue may have up to N request pools, each independently
+regulated by nr_requests.
+
+nr_zones (RO)
+-------------
+For zoned block devices (zoned attribute indicating "host-managed" or
+"host-aware"), this indicates the total number of zones of the device.
+This is always 0 for regular block devices.
+
+optimal_io_size (RO)
+--------------------
+This is the optimal IO size reported by the device.
+
+physical_block_size (RO)
+------------------------
+This is the physical block size of device, in bytes.
+
+read_ahead_kb (RW)
+------------------
+Maximum number of kilobytes to read-ahead for filesystems on this block
+device.
+
+rotational (RW)
+---------------
+This file is used to stat if the device is of rotational type or
+non-rotational type.
+
+rq_affinity (RW)
+----------------
+If this option is '1', the block layer will migrate request completions to the
+cpu "group" that originally submitted the request. For some workloads this
+provides a significant reduction in CPU cycles due to caching effects.
+
+For storage configurations that need to maximize distribution of completion
+processing setting this option to '2' forces the completion to run on the
+requesting cpu (bypassing the "group" aggregation logic).
+
+scheduler (RW)
+--------------
+When read, this file will display the current and available IO schedulers
+for this block device. The currently active IO scheduler will be enclosed
+in [] brackets. Writing an IO scheduler name to this file will switch
+control of this block device to that new IO scheduler. Note that writing
+an IO scheduler name to this file will attempt to load that IO scheduler
+module, if it isn't already present in the system.
+
+write_cache (RW)
+----------------
+When read, this file will display whether the device has write back
+caching enabled or not. It will return "write back" for the former
+case, and "write through" for the latter. Writing to this file can
+change the kernels view of the device, but it doesn't alter the
+device state. This means that it might not be safe to toggle the
+setting from "write back" to "write through", since that will also
+eliminate cache flushes issued by the kernel.
+
+write_same_max_bytes (RO)
+-------------------------
+This is the number of bytes the device can write in a single write-same
+command.  A value of '0' means write-same is not supported by this
+device.
+
+wbt_lat_usec (RW)
+-----------------
+If the device is registered for writeback throttling, then this file shows
+the target minimum read latency. If this latency is exceeded in a given
+window of time (see wb_window_usec), then the writeback throttling will start
+scaling back writes. Writing a value of '0' to this file disables the
+feature. Writing a value of '-1' to this file resets the value to the
+default setting.
+
+throttle_sample_time (RW)
+-------------------------
+This is the time window that blk-throttle samples data, in millisecond.
+blk-throttle makes decision based on the samplings. Lower time means cgroups
+have more smooth throughput, but higher CPU overhead. This exists only when
+CONFIG_BLK_DEV_THROTTLING_LOW is enabled.
+
+write_zeroes_max_bytes (RO)
+---------------------------
+For block drivers that support REQ_OP_WRITE_ZEROES, the maximum number of
+bytes that can be zeroed at once. The value 0 means that REQ_OP_WRITE_ZEROES
+is not supported.
+
+zoned (RO)
+----------
+This indicates if the device is a zoned block device and the zone model of the
+device if it is indeed zoned. The possible values indicated by zoned are
+"none" for regular block devices and "host-aware" or "host-managed" for zoned
+block devices. The characteristics of host-aware and host-managed zoned block
+devices are described in the ZBC (Zoned Block Commands) and ZAC
+(Zoned Device ATA Command Set) standards. These standards also define the
+"drive-managed" zone model. However, since drive-managed zoned block devices
+do not support zone commands, they will be treated as regular block devices
+and zoned will report "none".
+
+Jens Axboe <jens.axboe@oracle.com>, February 2009
diff --git a/Documentation/block/queue-sysfs.txt b/Documentation/block/queue-sysfs.txt
deleted file mode 100644 (file)
index b40b5b7..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-Queue sysfs files
-=================
-
-This text file will detail the queue files that are located in the sysfs tree
-for each block device. Note that stacked devices typically do not export
-any settings, since their queue merely functions are a remapping target.
-These files are the ones found in the /sys/block/xxx/queue/ directory.
-
-Files denoted with a RO postfix are readonly and the RW postfix means
-read-write.
-
-add_random (RW)
-----------------
-This file allows to turn off the disk entropy contribution. Default
-value of this file is '1'(on).
-
-chunk_sectors (RO)
-------------------
-This has different meaning depending on the type of the block device.
-For a RAID device (dm-raid), chunk_sectors indicates the size in 512B sectors
-of the RAID volume stripe segment. For a zoned block device, either host-aware
-or host-managed, chunk_sectors indicates the size in 512B sectors of the zones
-of the device, with the eventual exception of the last zone of the device which
-may be smaller.
-
-dax (RO)
---------
-This file indicates whether the device supports Direct Access (DAX),
-used by CPU-addressable storage to bypass the pagecache.  It shows '1'
-if true, '0' if not.
-
-discard_granularity (RO)
------------------------
-This shows the size of internal allocation of the device in bytes, if
-reported by the device. A value of '0' means device does not support
-the discard functionality.
-
-discard_max_hw_bytes (RO)
-----------------------
-Devices that support discard functionality may have internal limits on
-the number of bytes that can be trimmed or unmapped in a single operation.
-The discard_max_bytes parameter is set by the device driver to the maximum
-number of bytes that can be discarded in a single operation. Discard
-requests issued to the device must not exceed this limit. A discard_max_bytes
-value of 0 means that the device does not support discard functionality.
-
-discard_max_bytes (RW)
-----------------------
-While discard_max_hw_bytes is the hardware limit for the device, this
-setting is the software limit. Some devices exhibit large latencies when
-large discards are issued, setting this value lower will make Linux issue
-smaller discards and potentially help reduce latencies induced by large
-discard operations.
-
-discard_zeroes_data (RO)
-------------------------
-Obsolete. Always zero.
-
-fua (RO)
---------
-Whether or not the block driver supports the FUA flag for write requests.
-FUA stands for Force Unit Access. If the FUA flag is set that means that
-write requests must bypass the volatile cache of the storage device.
-
-hw_sector_size (RO)
--------------------
-This is the hardware sector size of the device, in bytes.
-
-io_poll (RW)
-------------
-When read, this file shows whether polling is enabled (1) or disabled
-(0).  Writing '0' to this file will disable polling for this device.
-Writing any non-zero value will enable this feature.
-
-io_poll_delay (RW)
-------------------
-If polling is enabled, this controls what kind of polling will be
-performed. It defaults to -1, which is classic polling. In this mode,
-the CPU will repeatedly ask for completions without giving up any time.
-If set to 0, a hybrid polling mode is used, where the kernel will attempt
-to make an educated guess at when the IO will complete. Based on this
-guess, the kernel will put the process issuing IO to sleep for an amount
-of time, before entering a classic poll loop. This mode might be a
-little slower than pure classic polling, but it will be more efficient.
-If set to a value larger than 0, the kernel will put the process issuing
-IO to sleep for this amount of microseconds before entering classic
-polling.
-
-io_timeout (RW)
----------------
-io_timeout is the request timeout in milliseconds. If a request does not
-complete in this time then the block driver timeout handler is invoked.
-That timeout handler can decide to retry the request, to fail it or to start
-a device recovery strategy.
-
-iostats (RW)
--------------
-This file is used to control (on/off) the iostats accounting of the
-disk.
-
-logical_block_size (RO)
------------------------
-This is the logical block size of the device, in bytes.
-
-max_discard_segments (RO)
--------------------------
-The maximum number of DMA scatter/gather entries in a discard request.
-
-max_hw_sectors_kb (RO)
-----------------------
-This is the maximum number of kilobytes supported in a single data transfer.
-
-max_integrity_segments (RO)
----------------------------
-Maximum number of elements in a DMA scatter/gather list with integrity
-data that will be submitted by the block layer core to the associated
-block driver.
-
-max_sectors_kb (RW)
--------------------
-This is the maximum number of kilobytes that the block layer will allow
-for a filesystem request. Must be smaller than or equal to the maximum
-size allowed by the hardware.
-
-max_segments (RO)
------------------
-Maximum number of elements in a DMA scatter/gather list that is submitted
-to the associated block driver.
-
-max_segment_size (RO)
----------------------
-Maximum size in bytes of a single element in a DMA scatter/gather list.
-
-minimum_io_size (RO)
---------------------
-This is the smallest preferred IO size reported by the device.
-
-nomerges (RW)
--------------
-This enables the user to disable the lookup logic involved with IO
-merging requests in the block layer. By default (0) all merges are
-enabled. When set to 1 only simple one-hit merges will be tried. When
-set to 2 no merge algorithms will be tried (including one-hit or more
-complex tree/hash lookups).
-
-nr_requests (RW)
-----------------
-This controls how many requests may be allocated in the block layer for
-read or write requests. Note that the total allocated number may be twice
-this amount, since it applies only to reads or writes (not the accumulated
-sum).
-
-To avoid priority inversion through request starvation, a request
-queue maintains a separate request pool per each cgroup when
-CONFIG_BLK_CGROUP is enabled, and this parameter applies to each such
-per-block-cgroup request pool.  IOW, if there are N block cgroups,
-each request queue may have up to N request pools, each independently
-regulated by nr_requests.
-
-nr_zones (RO)
--------------
-For zoned block devices (zoned attribute indicating "host-managed" or
-"host-aware"), this indicates the total number of zones of the device.
-This is always 0 for regular block devices.
-
-optimal_io_size (RO)
---------------------
-This is the optimal IO size reported by the device.
-
-physical_block_size (RO)
-------------------------
-This is the physical block size of device, in bytes.
-
-read_ahead_kb (RW)
-------------------
-Maximum number of kilobytes to read-ahead for filesystems on this block
-device.
-
-rotational (RW)
----------------
-This file is used to stat if the device is of rotational type or
-non-rotational type.
-
-rq_affinity (RW)
-----------------
-If this option is '1', the block layer will migrate request completions to the
-cpu "group" that originally submitted the request. For some workloads this
-provides a significant reduction in CPU cycles due to caching effects.
-
-For storage configurations that need to maximize distribution of completion
-processing setting this option to '2' forces the completion to run on the
-requesting cpu (bypassing the "group" aggregation logic).
-
-scheduler (RW)
---------------
-When read, this file will display the current and available IO schedulers
-for this block device. The currently active IO scheduler will be enclosed
-in [] brackets. Writing an IO scheduler name to this file will switch
-control of this block device to that new IO scheduler. Note that writing
-an IO scheduler name to this file will attempt to load that IO scheduler
-module, if it isn't already present in the system.
-
-write_cache (RW)
-----------------
-When read, this file will display whether the device has write back
-caching enabled or not. It will return "write back" for the former
-case, and "write through" for the latter. Writing to this file can
-change the kernels view of the device, but it doesn't alter the
-device state. This means that it might not be safe to toggle the
-setting from "write back" to "write through", since that will also
-eliminate cache flushes issued by the kernel.
-
-write_same_max_bytes (RO)
--------------------------
-This is the number of bytes the device can write in a single write-same
-command.  A value of '0' means write-same is not supported by this
-device.
-
-wbt_lat_usec (RW)
------------------
-If the device is registered for writeback throttling, then this file shows
-the target minimum read latency. If this latency is exceeded in a given
-window of time (see wb_window_usec), then the writeback throttling will start
-scaling back writes. Writing a value of '0' to this file disables the
-feature. Writing a value of '-1' to this file resets the value to the
-default setting.
-
-throttle_sample_time (RW)
--------------------------
-This is the time window that blk-throttle samples data, in millisecond.
-blk-throttle makes decision based on the samplings. Lower time means cgroups
-have more smooth throughput, but higher CPU overhead. This exists only when
-CONFIG_BLK_DEV_THROTTLING_LOW is enabled.
-
-write_zeroes_max_bytes (RO)
----------------------------
-For block drivers that support REQ_OP_WRITE_ZEROES, the maximum number of
-bytes that can be zeroed at once. The value 0 means that REQ_OP_WRITE_ZEROES
-is not supported.
-
-zoned (RO)
-----------
-This indicates if the device is a zoned block device and the zone model of the
-device if it is indeed zoned. The possible values indicated by zoned are
-"none" for regular block devices and "host-aware" or "host-managed" for zoned
-block devices. The characteristics of host-aware and host-managed zoned block
-devices are described in the ZBC (Zoned Block Commands) and ZAC
-(Zoned Device ATA Command Set) standards. These standards also define the
-"drive-managed" zone model. However, since drive-managed zoned block devices
-do not support zone commands, they will be treated as regular block devices
-and zoned will report "none".
-
-Jens Axboe <jens.axboe@oracle.com>, February 2009
diff --git a/Documentation/block/request.rst b/Documentation/block/request.rst
new file mode 100644 (file)
index 0000000..747021e
--- /dev/null
@@ -0,0 +1,99 @@
+============================
+struct request documentation
+============================
+
+Jens Axboe <jens.axboe@oracle.com> 27/05/02
+
+
+.. FIXME:
+   No idea about what does mean - seems just some noise, so comment it
+
+   1.0
+   Index
+
+   2.0 Struct request members classification
+
+       2.1 struct request members explanation
+
+   3.0
+
+
+   2.0
+
+
+
+Short explanation of request members
+====================================
+
+Classification flags:
+
+       =       ====================
+       D       driver member
+       B       block layer member
+       I       I/O scheduler member
+       =       ====================
+
+Unless an entry contains a D classification, a device driver must not access
+this member. Some members may contain D classifications, but should only be
+access through certain macros or functions (eg ->flags).
+
+<linux/blkdev.h>
+
+=============================== ======= =======================================
+Member                         Flag    Comment
+=============================== ======= =======================================
+struct list_head queuelist     BI      Organization on various internal
+                                       queues
+
+``void *elevator_private``     I       I/O scheduler private data
+
+unsigned char cmd[16]          D       Driver can use this for setting up
+                                       a cdb before execution, see
+                                       blk_queue_prep_rq
+
+unsigned long flags            DBI     Contains info about data direction,
+                                       request type, etc.
+
+int rq_status                  D       Request status bits
+
+kdev_t rq_dev                  DBI     Target device
+
+int errors                     DB      Error counts
+
+sector_t sector                        DBI     Target location
+
+unsigned long hard_nr_sectors  B       Used to keep sector sane
+
+unsigned long nr_sectors       DBI     Total number of sectors in request
+
+unsigned long hard_nr_sectors  B       Used to keep nr_sectors sane
+
+unsigned short nr_phys_segments        DB      Number of physical scatter gather
+                                       segments in a request
+
+unsigned short nr_hw_segments  DB      Number of hardware scatter gather
+                                       segments in a request
+
+unsigned int current_nr_sectors        DB      Number of sectors in first segment
+                                       of request
+
+unsigned int hard_cur_sectors  B       Used to keep current_nr_sectors sane
+
+int tag                                DB      TCQ tag, if assigned
+
+``void *special``              D       Free to be used by driver
+
+``char *buffer``               D       Map of first segment, also see
+                                       section on bouncing SECTION
+
+``struct completion *waiting`` D       Can be used by driver to get signalled
+                                       on request completion
+
+``struct bio *bio``            DBI     First bio in request
+
+``struct bio *biotail``                DBI     Last bio in request
+
+``struct request_queue *q``    DB      Request queue this request belongs to
+
+``struct request_list *rl``    B       Request list this request came from
+=============================== ======= =======================================
diff --git a/Documentation/block/request.txt b/Documentation/block/request.txt
deleted file mode 100644 (file)
index 754e104..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-
-struct request documentation
-
-Jens Axboe <jens.axboe@oracle.com> 27/05/02
-
-1.0
-Index
-
-2.0 Struct request members classification
-
-       2.1 struct request members explanation
-
-3.0
-
-
-2.0
-Short explanation of request members
-
-Classification flags:
-
-       D       driver member
-       B       block layer member
-       I       I/O scheduler member
-
-Unless an entry contains a D classification, a device driver must not access
-this member. Some members may contain D classifications, but should only be
-access through certain macros or functions (eg ->flags).
-
-<linux/blkdev.h>
-
-2.1
-Member                         Flag    Comment
-------                         ----    -------
-
-struct list_head queuelist     BI      Organization on various internal
-                                       queues
-
-void *elevator_private         I       I/O scheduler private data
-
-unsigned char cmd[16]          D       Driver can use this for setting up
-                                       a cdb before execution, see
-                                       blk_queue_prep_rq
-
-unsigned long flags            DBI     Contains info about data direction,
-                                       request type, etc.
-
-int rq_status                  D       Request status bits
-
-kdev_t rq_dev                  DBI     Target device
-
-int errors                     DB      Error counts
-
-sector_t sector                        DBI     Target location
-
-unsigned long hard_nr_sectors  B       Used to keep sector sane
-
-unsigned long nr_sectors       DBI     Total number of sectors in request
-
-unsigned long hard_nr_sectors  B       Used to keep nr_sectors sane
-
-unsigned short nr_phys_segments        DB      Number of physical scatter gather
-                                       segments in a request
-
-unsigned short nr_hw_segments  DB      Number of hardware scatter gather
-                                       segments in a request
-
-unsigned int current_nr_sectors        DB      Number of sectors in first segment
-                                       of request
-
-unsigned int hard_cur_sectors  B       Used to keep current_nr_sectors sane
-
-int tag                                DB      TCQ tag, if assigned
-
-void *special                  D       Free to be used by driver
-
-char *buffer                   D       Map of first segment, also see
-                                       section on bouncing SECTION
-
-struct completion *waiting     D       Can be used by driver to get signalled
-                                       on request completion
-
-struct bio *bio                        DBI     First bio in request
-
-struct bio *biotail            DBI     Last bio in request
-
-struct request_queue *q                DB      Request queue this request belongs to
-
-struct request_list *rl                B       Request list this request came from
diff --git a/Documentation/block/stat.rst b/Documentation/block/stat.rst
new file mode 100644 (file)
index 0000000..9c07bc2
--- /dev/null
@@ -0,0 +1,93 @@
+===============================================
+Block layer statistics in /sys/block/<dev>/stat
+===============================================
+
+This file documents the contents of the /sys/block/<dev>/stat file.
+
+The stat file provides several statistics about the state of block
+device <dev>.
+
+Q.
+   Why are there multiple statistics in a single file?  Doesn't sysfs
+   normally contain a single value per file?
+
+A.
+   By having a single file, the kernel can guarantee that the statistics
+   represent a consistent snapshot of the state of the device.  If the
+   statistics were exported as multiple files containing one statistic
+   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
+values separated by whitespace.  The fields are summarized in the
+following table, and described in more detail below.
+
+
+=============== ============= =================================================
+Name            units         description
+=============== ============= =================================================
+read I/Os       requests      number of read I/Os processed
+read merges     requests      number of read I/Os merged with in-queue I/O
+read sectors    sectors       number of sectors read
+read ticks      milliseconds  total wait time for read requests
+write I/Os      requests      number of write I/Os processed
+write merges    requests      number of write I/Os merged with in-queue I/O
+write sectors   sectors       number of sectors written
+write ticks     milliseconds  total wait time for write requests
+in_flight       requests      number of I/Os currently in flight
+io_ticks        milliseconds  total time this block device has been active
+time_in_queue   milliseconds  total wait time for all requests
+discard I/Os    requests      number of discard I/Os processed
+discard merges  requests      number of discard I/Os merged with in-queue I/O
+discard sectors sectors       number of sectors discarded
+discard ticks   milliseconds  total wait time for discard requests
+=============== ============= =================================================
+
+read I/Os, write I/Os, discard I/0s
+===================================
+
+These values increment when an I/O request completes.
+
+read merges, write merges, discard merges
+=========================================
+
+These values increment when an I/O request is merged with an
+already-queued I/O request.
+
+read sectors, write sectors, discard_sectors
+============================================
+
+These values count the number of sectors read from, written to, or
+discarded from this block device.  The "sectors" in question are the
+standard UNIX 512-byte sectors, not any device- or filesystem-specific
+block size.  The counters are incremented when the I/O completes.
+
+read ticks, write ticks, discard ticks
+======================================
+
+These values count the number of milliseconds that I/O requests have
+waited on this block device.  If there are multiple I/O requests waiting,
+these values will increase at a rate greater than 1000/second; for
+example, if 60 read requests wait for an average of 30 ms, the read_ticks
+field will increase by 60*30 = 1800.
+
+in_flight
+=========
+
+This value counts the number of I/O requests that have been issued to
+the device driver but have not yet completed.  It does not include I/O
+requests that are in the queue but not yet issued to the device driver.
+
+io_ticks
+========
+
+This value counts the number of milliseconds during which the device has
+had I/O requests queued.
+
+time_in_queue
+=============
+
+This value counts the number of milliseconds that I/O requests have waited
+on this block device.  If there are multiple I/O requests waiting, this
+value will increase as the product of the number of milliseconds times the
+number of requests waiting (see "read ticks" above for an example).
diff --git a/Documentation/block/stat.txt b/Documentation/block/stat.txt
deleted file mode 100644 (file)
index 0aace9c..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-Block layer statistics in /sys/block/<dev>/stat
-===============================================
-
-This file documents the contents of the /sys/block/<dev>/stat file.
-
-The stat file provides several statistics about the state of block
-device <dev>.
-
-Q. Why are there multiple statistics in a single file?  Doesn't sysfs
-   normally contain a single value per file?
-A. By having a single file, the kernel can guarantee that the statistics
-   represent a consistent snapshot of the state of the device.  If the
-   statistics were exported as multiple files containing one statistic
-   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
-values separated by whitespace.  The fields are summarized in the
-following table, and described in more detail below.
-
-Name            units         description
-----            -----         -----------
-read I/Os       requests      number of read I/Os processed
-read merges     requests      number of read I/Os merged with in-queue I/O
-read sectors    sectors       number of sectors read
-read ticks      milliseconds  total wait time for read requests
-write I/Os      requests      number of write I/Os processed
-write merges    requests      number of write I/Os merged with in-queue I/O
-write sectors   sectors       number of sectors written
-write ticks     milliseconds  total wait time for write requests
-in_flight       requests      number of I/Os currently in flight
-io_ticks        milliseconds  total time this block device has been active
-time_in_queue   milliseconds  total wait time for all requests
-discard I/Os    requests      number of discard I/Os processed
-discard merges  requests      number of discard I/Os merged with in-queue I/O
-discard sectors sectors       number of sectors discarded
-discard ticks   milliseconds  total wait time for discard requests
-
-read I/Os, write I/Os, discard I/0s
-===================================
-
-These values increment when an I/O request completes.
-
-read merges, write merges, discard merges
-=========================================
-
-These values increment when an I/O request is merged with an
-already-queued I/O request.
-
-read sectors, write sectors, discard_sectors
-============================================
-
-These values count the number of sectors read from, written to, or
-discarded from this block device.  The "sectors" in question are the
-standard UNIX 512-byte sectors, not any device- or filesystem-specific
-block size.  The counters are incremented when the I/O completes.
-
-read ticks, write ticks, discard ticks
-======================================
-
-These values count the number of milliseconds that I/O requests have
-waited on this block device.  If there are multiple I/O requests waiting,
-these values will increase at a rate greater than 1000/second; for
-example, if 60 read requests wait for an average of 30 ms, the read_ticks
-field will increase by 60*30 = 1800.
-
-in_flight
-=========
-
-This value counts the number of I/O requests that have been issued to
-the device driver but have not yet completed.  It does not include I/O
-requests that are in the queue but not yet issued to the device driver.
-
-io_ticks
-========
-
-This value counts the number of milliseconds during which the device has
-had I/O requests queued.
-
-time_in_queue
-=============
-
-This value counts the number of milliseconds that I/O requests have waited
-on this block device.  If there are multiple I/O requests waiting, this
-value will increase as the product of the number of milliseconds times the
-number of requests waiting (see "read ticks" above for an example).
diff --git a/Documentation/block/switching-sched.rst b/Documentation/block/switching-sched.rst
new file mode 100644 (file)
index 0000000..4204241
--- /dev/null
@@ -0,0 +1,39 @@
+===================
+Switching Scheduler
+===================
+
+To choose IO schedulers at boot time, use the argument 'elevator=deadline'.
+'noop' and 'cfq' (the default) are also available. IO schedulers are assigned
+globally at boot time only presently.
+
+Each io queue has a set of io scheduler tunables associated with it. These
+tunables control how the io scheduler works. You can find these entries
+in::
+
+       /sys/block/<device>/queue/iosched
+
+assuming that you have sysfs mounted on /sys. If you don't have sysfs mounted,
+you can do so by typing::
+
+       # mount none /sys -t sysfs
+
+It is possible to change the IO scheduler for a given block device on
+the fly to select one of mq-deadline, none, bfq, or kyber schedulers -
+which can improve that device's throughput.
+
+To set a specific scheduler, simply do this::
+
+       echo SCHEDNAME > /sys/block/DEV/queue/scheduler
+
+where SCHEDNAME is the name of a defined IO scheduler, and DEV is the
+device name (hda, hdb, sga, or whatever you happen to have).
+
+The list of defined schedulers can be found by simply doing
+a "cat /sys/block/DEV/queue/scheduler" - the list of valid names
+will be displayed, with the currently selected scheduler in brackets::
+
+  # cat /sys/block/sda/queue/scheduler
+  [mq-deadline] kyber bfq none
+  # echo none >/sys/block/sda/queue/scheduler
+  # cat /sys/block/sda/queue/scheduler
+  [none] mq-deadline kyber bfq
diff --git a/Documentation/block/switching-sched.txt b/Documentation/block/switching-sched.txt
deleted file mode 100644 (file)
index 7977f6f..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-To choose IO schedulers at boot time, use the argument 'elevator=deadline'.
-'noop' and 'cfq' (the default) are also available. IO schedulers are assigned
-globally at boot time only presently.
-
-Each io queue has a set of io scheduler tunables associated with it. These
-tunables control how the io scheduler works. You can find these entries
-in:
-
-/sys/block/<device>/queue/iosched
-
-assuming that you have sysfs mounted on /sys. If you don't have sysfs mounted,
-you can do so by typing:
-
-# mount none /sys -t sysfs
-
-It is possible to change the IO scheduler for a given block device on
-the fly to select one of mq-deadline, none, bfq, or kyber schedulers -
-which can improve that device's throughput.
-
-To set a specific scheduler, simply do this:
-
-echo SCHEDNAME > /sys/block/DEV/queue/scheduler
-
-where SCHEDNAME is the name of a defined IO scheduler, and DEV is the
-device name (hda, hdb, sga, or whatever you happen to have).
-
-The list of defined schedulers can be found by simply doing
-a "cat /sys/block/DEV/queue/scheduler" - the list of valid names
-will be displayed, with the currently selected scheduler in brackets:
-
-# cat /sys/block/sda/queue/scheduler
-[mq-deadline] kyber bfq none
-# echo none >/sys/block/sda/queue/scheduler
-# cat /sys/block/sda/queue/scheduler
-[none] mq-deadline kyber bfq
diff --git a/Documentation/block/writeback_cache_control.rst b/Documentation/block/writeback_cache_control.rst
new file mode 100644 (file)
index 0000000..2c752c5
--- /dev/null
@@ -0,0 +1,86 @@
+==========================================
+Explicit volatile write back cache control
+==========================================
+
+Introduction
+------------
+
+Many storage devices, especially in the consumer market, come with volatile
+write back caches.  That means the devices signal I/O completion to the
+operating system before data actually has hit the non-volatile storage.  This
+behavior obviously speeds up various workloads, but it means the operating
+system needs to force data out to the non-volatile storage when it performs
+a data integrity operation like fsync, sync or an unmount.
+
+The Linux block layer provides two simple mechanisms that let filesystems
+control the caching behavior of the storage device.  These mechanisms are
+a forced cache flush, and the Force Unit Access (FUA) flag for requests.
+
+
+Explicit cache flushes
+----------------------
+
+The REQ_PREFLUSH flag can be OR ed into the r/w flags of a bio submitted from
+the filesystem and will make sure the volatile cache of the storage device
+has been flushed before the actual I/O operation is started.  This explicitly
+guarantees that previously completed write requests are on non-volatile
+storage before the flagged bio starts. In addition the REQ_PREFLUSH flag can be
+set on an otherwise empty bio structure, which causes only an explicit cache
+flush without any dependent I/O.  It is recommend to use
+the blkdev_issue_flush() helper for a pure cache flush.
+
+
+Forced Unit Access
+------------------
+
+The REQ_FUA flag can be OR ed into the r/w flags of a bio submitted from the
+filesystem and will make sure that I/O completion for this request is only
+signaled after the data has been committed to non-volatile storage.
+
+
+Implementation details for filesystems
+--------------------------------------
+
+Filesystems can simply set the REQ_PREFLUSH and REQ_FUA bits and do not have to
+worry if the underlying devices need any explicit cache flushing and how
+the Forced Unit Access is implemented.  The REQ_PREFLUSH and REQ_FUA flags
+may both be set on a single bio.
+
+
+Implementation details for make_request_fn based block drivers
+--------------------------------------------------------------
+
+These drivers will always see the REQ_PREFLUSH and REQ_FUA bits as they sit
+directly below the submit_bio interface.  For remapping drivers the REQ_FUA
+bits need to be propagated to underlying devices, and a global flush needs
+to be implemented for bios with the REQ_PREFLUSH bit set.  For real device
+drivers that do not have a volatile cache the REQ_PREFLUSH and REQ_FUA bits
+on non-empty bios can simply be ignored, and REQ_PREFLUSH requests without
+data can be completed successfully without doing any work.  Drivers for
+devices with volatile caches need to implement the support for these
+flags themselves without any help from the block layer.
+
+
+Implementation details for request_fn based block drivers
+---------------------------------------------------------
+
+For devices that do not support volatile write caches there is no driver
+support required, the block layer completes empty REQ_PREFLUSH requests before
+entering the driver and strips off the REQ_PREFLUSH and REQ_FUA bits from
+requests that have a payload.  For devices with volatile write caches the
+driver needs to tell the block layer that it supports flushing caches by
+doing::
+
+       blk_queue_write_cache(sdkp->disk->queue, true, false);
+
+and handle empty REQ_OP_FLUSH requests in its prep_fn/request_fn.  Note that
+REQ_PREFLUSH requests with a payload are automatically turned into a sequence
+of an empty REQ_OP_FLUSH request followed by the actual write by the block
+layer.  For devices that also support the FUA bit the block layer needs
+to be told to pass through the REQ_FUA bit using::
+
+       blk_queue_write_cache(sdkp->disk->queue, true, true);
+
+and the driver must handle write requests that have the REQ_FUA bit set
+in prep_fn/request_fn.  If the FUA bit is not natively supported the block
+layer turns it into an empty REQ_OP_FLUSH request after the actual write.
diff --git a/Documentation/block/writeback_cache_control.txt b/Documentation/block/writeback_cache_control.txt
deleted file mode 100644 (file)
index 8a6bdad..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-
-Explicit volatile write back cache control
-=====================================
-
-Introduction
-------------
-
-Many storage devices, especially in the consumer market, come with volatile
-write back caches.  That means the devices signal I/O completion to the
-operating system before data actually has hit the non-volatile storage.  This
-behavior obviously speeds up various workloads, but it means the operating
-system needs to force data out to the non-volatile storage when it performs
-a data integrity operation like fsync, sync or an unmount.
-
-The Linux block layer provides two simple mechanisms that let filesystems
-control the caching behavior of the storage device.  These mechanisms are
-a forced cache flush, and the Force Unit Access (FUA) flag for requests.
-
-
-Explicit cache flushes
-----------------------
-
-The REQ_PREFLUSH flag can be OR ed into the r/w flags of a bio submitted from
-the filesystem and will make sure the volatile cache of the storage device
-has been flushed before the actual I/O operation is started.  This explicitly
-guarantees that previously completed write requests are on non-volatile
-storage before the flagged bio starts. In addition the REQ_PREFLUSH flag can be
-set on an otherwise empty bio structure, which causes only an explicit cache
-flush without any dependent I/O.  It is recommend to use
-the blkdev_issue_flush() helper for a pure cache flush.
-
-
-Forced Unit Access
------------------
-
-The REQ_FUA flag can be OR ed into the r/w flags of a bio submitted from the
-filesystem and will make sure that I/O completion for this request is only
-signaled after the data has been committed to non-volatile storage.
-
-
-Implementation details for filesystems
---------------------------------------
-
-Filesystems can simply set the REQ_PREFLUSH and REQ_FUA bits and do not have to
-worry if the underlying devices need any explicit cache flushing and how
-the Forced Unit Access is implemented.  The REQ_PREFLUSH and REQ_FUA flags
-may both be set on a single bio.
-
-
-Implementation details for make_request_fn based block drivers
---------------------------------------------------------------
-
-These drivers will always see the REQ_PREFLUSH and REQ_FUA bits as they sit
-directly below the submit_bio interface.  For remapping drivers the REQ_FUA
-bits need to be propagated to underlying devices, and a global flush needs
-to be implemented for bios with the REQ_PREFLUSH bit set.  For real device
-drivers that do not have a volatile cache the REQ_PREFLUSH and REQ_FUA bits
-on non-empty bios can simply be ignored, and REQ_PREFLUSH requests without
-data can be completed successfully without doing any work.  Drivers for
-devices with volatile caches need to implement the support for these
-flags themselves without any help from the block layer.
-
-
-Implementation details for request_fn based block drivers
---------------------------------------------------------------
-
-For devices that do not support volatile write caches there is no driver
-support required, the block layer completes empty REQ_PREFLUSH requests before
-entering the driver and strips off the REQ_PREFLUSH and REQ_FUA bits from
-requests that have a payload.  For devices with volatile write caches the
-driver needs to tell the block layer that it supports flushing caches by
-doing:
-
-       blk_queue_write_cache(sdkp->disk->queue, true, false);
-
-and handle empty REQ_OP_FLUSH requests in its prep_fn/request_fn.  Note that
-REQ_PREFLUSH requests with a payload are automatically turned into a sequence
-of an empty REQ_OP_FLUSH request followed by the actual write by the block
-layer.  For devices that also support the FUA bit the block layer needs
-to be told to pass through the REQ_FUA bit using:
-
-       blk_queue_write_cache(sdkp->disk->queue, true, true);
-
-and the driver must handle write requests that have the REQ_FUA bit set
-in prep_fn/request_fn.  If the FUA bit is not natively supported the block
-layer turns it into an empty REQ_OP_FLUSH request after the actual write.
diff --git a/Documentation/blockdev/drbd/README.txt b/Documentation/blockdev/drbd/README.txt
deleted file mode 100644 (file)
index 627b0a1..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-Description
-
-  DRBD is a shared-nothing, synchronously replicated block device. It
-  is designed to serve as a building block for high availability
-  clusters and in this context, is a "drop-in" replacement for shared
-  storage. Simplistically, you could see it as a network RAID 1.
-
-  Please visit http://www.drbd.org to find out more.
-
-The here included files are intended to help understand the implementation
-
-DRBD-8.3-data-packets.svg, DRBD-data-packets.svg  
-  relates some functions, and write packets.
-
-conn-states-8.dot, disk-states-8.dot, node-states-8.dot
-  The sub graphs of DRBD's state transitions
diff --git a/Documentation/blockdev/drbd/data-structure-v9.txt b/Documentation/blockdev/drbd/data-structure-v9.txt
deleted file mode 100644 (file)
index 1e52a0e..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-This describes the in kernel data structure for DRBD-9. Starting with
-Linux v3.14 we are reorganizing DRBD to use this data structure.
-
-Basic Data Structure
-====================
-
-A node has a number of DRBD resources.  Each such resource has a number of
-devices (aka volumes) and connections to other nodes ("peer nodes"). Each DRBD
-device is represented by a block device locally.
-
-The DRBD objects are interconnected to form a matrix as depicted below; a
-drbd_peer_device object sits at each intersection between a drbd_device and a
-drbd_connection:
-
-  /--------------+---------------+.....+---------------\
-  |   resource   |    device     |     |    device     |
-  +--------------+---------------+.....+---------------+
-  |  connection  |  peer_device  |     |  peer_device  |
-  +--------------+---------------+.....+---------------+
-  :              :               :     :               :
-  :              :               :     :               :
-  +--------------+---------------+.....+---------------+
-  |  connection  |  peer_device  |     |  peer_device  |
-  \--------------+---------------+.....+---------------/
-
-In this table, horizontally, devices can be accessed from resources by their
-volume number.  Likewise, peer_devices can be accessed from connections by
-their volume number.  Objects in the vertical direction are connected by double
-linked lists.  There are back pointers from peer_devices to their connections a
-devices, and from connections and devices to their resource.
-
-All resources are in the drbd_resources double-linked list.  In addition, all
-devices can be accessed by their minor device number via the drbd_devices idr.
-
-The drbd_resource, drbd_connection, and drbd_device objects are reference
-counted.  The peer_device objects only serve to establish the links between
-devices and connections; their lifetime is determined by the lifetime of the
-device and connection which they reference.
diff --git a/Documentation/blockdev/drbd/node-states-8.dot b/Documentation/blockdev/drbd/node-states-8.dot
deleted file mode 100644 (file)
index 4a2b00c..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-digraph node_states {
-       Secondary -> Primary           [ label = "ioctl_set_state()" ]
-       Primary   -> Secondary         [ label = "ioctl_set_state()" ]
-}
-
-digraph peer_states {
-       Secondary -> Primary           [ label = "recv state packet" ]
-       Primary   -> Secondary         [ label = "recv state packet" ]
-       Primary   -> Unknown           [ label = "connection lost" ]
-       Secondary  -> Unknown          [ label = "connection lost" ]
-       Unknown   -> Primary           [ label = "connected" ]
-       Unknown   -> Secondary         [ label = "connected" ]
-}
-
diff --git a/Documentation/blockdev/floppy.txt b/Documentation/blockdev/floppy.txt
deleted file mode 100644 (file)
index e2240f5..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-This file describes the floppy driver.
-
-FAQ list:
-=========
-
- A FAQ list may be found in the fdutils package (see below), and also
-at <http://fdutils.linux.lu/faq.html>.
-
-
-LILO configuration options (Thinkpad users, read this)
-======================================================
-
- The floppy driver is configured using the 'floppy=' option in
-lilo. This option can be typed at the boot prompt, or entered in the
-lilo configuration file.
-
- Example: If your kernel is called linux-2.6.9, type the following line
-at the lilo boot prompt (if you have a thinkpad):
-
- linux-2.6.9 floppy=thinkpad
-
-You may also enter the following line in /etc/lilo.conf, in the description
-of linux-2.6.9:
-
- append = "floppy=thinkpad"
-
- Several floppy related options may be given, example:
-
- linux-2.6.9 floppy=daring floppy=two_fdc
- append = "floppy=daring floppy=two_fdc"
-
- If you give options both in the lilo config file and on the boot
-prompt, the option strings of both places are concatenated, the boot
-prompt options coming last. That's why there are also options to
-restore the default behavior.
-
-
-Module configuration options
-============================
-
- If you use the floppy driver as a module, use the following syntax:
-modprobe floppy floppy="<options>"
-
-Example:
- modprobe floppy floppy="omnibook messages"
-
- If you need certain options enabled every time you load the floppy driver,
-you can put:
-
- options floppy floppy="omnibook messages"
-
-in a configuration file in /etc/modprobe.d/.
-
-
- The floppy driver related options are:
-
- floppy=asus_pci
-       Sets the bit mask to allow only units 0 and 1. (default)
-
- floppy=daring
-       Tells the floppy driver that you have a well behaved floppy controller.
-       This allows more efficient and smoother operation, but may fail on
-       certain controllers. This may speed up certain operations.
-
- floppy=0,daring
-       Tells the floppy driver that your floppy controller should be used
-       with caution.
-
- floppy=one_fdc
-       Tells the floppy driver that you have only one floppy controller.
-       (default)
-
- floppy=two_fdc
- floppy=<address>,two_fdc
-       Tells the floppy driver that you have two floppy controllers.
-       The second floppy controller is assumed to be at <address>.
-       This option is not needed if the second controller is at address
-       0x370, and if you use the 'cmos' option.
-
- floppy=thinkpad
-       Tells the floppy driver that you have a Thinkpad. Thinkpads use an
-       inverted convention for the disk change line.
-
- floppy=0,thinkpad
-       Tells the floppy driver that you don't have a Thinkpad.
-
- floppy=omnibook
- floppy=nodma
-       Tells the floppy driver not to use Dma for data transfers.
-       This is needed on HP Omnibooks, which don't have a workable
-       DMA channel for the floppy driver. This option is also useful
-       if you frequently get "Unable to allocate DMA memory" messages.
-       Indeed, dma memory needs to be continuous in physical memory,
-       and is thus harder to find, whereas non-dma buffers may be
-       allocated in virtual memory. However, I advise against this if
-       you have an FDC without a FIFO (8272A or 82072). 82072A and
-       later are OK. You also need at least a 486 to use nodma.
-       If you use nodma mode, I suggest you also set the FIFO
-       threshold to 10 or lower, in order to limit the number of data
-       transfer interrupts.
-
-       If you have a FIFO-able FDC, the floppy driver automatically
-       falls back on non DMA mode if no DMA-able memory can be found.
-       If you want to avoid this, explicitly ask for 'yesdma'.
-
- floppy=yesdma
-       Tells the floppy driver that a workable DMA channel is available.
-       (default)
-
- floppy=nofifo
-       Disables the FIFO entirely. This is needed if you get "Bus
-       master arbitration error" messages from your Ethernet card (or
-       from other devices) while accessing the floppy.
-
- floppy=usefifo
-       Enables the FIFO. (default)
-
- floppy=<threshold>,fifo_depth
-       Sets the FIFO threshold. This is mostly relevant in DMA
-       mode. If this is higher, the floppy driver tolerates more
-       interrupt latency, but it triggers more interrupts (i.e. it
-       imposes more load on the rest of the system). If this is
-       lower, the interrupt latency should be lower too (faster
-       processor). The benefit of a lower threshold is less
-       interrupts.
-
-       To tune the fifo threshold, switch on over/underrun messages
-       using 'floppycontrol --messages'. Then access a floppy
-       disk. If you get a huge amount of "Over/Underrun - retrying"
-       messages, then the fifo threshold is too low. Try with a
-       higher value, until you only get an occasional Over/Underrun.
-       It is a good idea to compile the floppy driver as a module
-       when doing this tuning. Indeed, it allows to try different
-       fifo values without rebooting the machine for each test. Note
-       that you need to do 'floppycontrol --messages' every time you
-       re-insert the module.
-
-       Usually, tuning the fifo threshold should not be needed, as
-       the default (0xa) is reasonable.
-
- floppy=<drive>,<type>,cmos
-       Sets the CMOS type of <drive> to <type>. This is mandatory if
-       you have more than two floppy drives (only two can be
-       described in the physical CMOS), or if your BIOS uses
-       non-standard CMOS types. The CMOS types are:
-
-               0 - Use the value of the physical CMOS
-               1 - 5 1/4 DD
-               2 - 5 1/4 HD
-               3 - 3 1/2 DD
-               4 - 3 1/2 HD
-               5 - 3 1/2 ED
-               6 - 3 1/2 ED
-              16 - unknown or not installed
-
-       (Note: there are two valid types for ED drives. This is because 5 was
-       initially chosen to represent floppy *tapes*, and 6 for ED drives.
-       AMI ignored this, and used 5 for ED drives. That's why the floppy
-       driver handles both.)
-
- floppy=unexpected_interrupts
-       Print a warning message when an unexpected interrupt is received.
-       (default)
-
- floppy=no_unexpected_interrupts
- floppy=L40SX
-       Don't print a message when an unexpected interrupt is received. This
-       is needed on IBM L40SX laptops in certain video modes. (There seems
-       to be an interaction between video and floppy. The unexpected
-       interrupts affect only performance, and can be safely ignored.)
-
- floppy=broken_dcl
-       Don't use the disk change line, but assume that the disk was
-       changed whenever the device node is reopened. Needed on some
-       boxes where the disk change line is broken or unsupported.
-       This should be regarded as a stopgap measure, indeed it makes
-       floppy operation less efficient due to unneeded cache
-       flushings, and slightly more unreliable. Please verify your
-       cable, connection and jumper settings if you have any DCL
-       problems. However, some older drives, and also some laptops
-       are known not to have a DCL.
-
- floppy=debug
-       Print debugging messages.
-
- floppy=messages
-       Print informational messages for some operations (disk change
-       notifications, warnings about over and underruns, and about
-       autodetection).
-
- floppy=silent_dcl_clear
-       Uses a less noisy way to clear the disk change line (which
-       doesn't involve seeks). Implied by 'daring' option.
-
- floppy=<nr>,irq
-       Sets the floppy IRQ to <nr> instead of 6.
-
- floppy=<nr>,dma
-       Sets the floppy DMA channel to <nr> instead of 2.
-
- floppy=slow
-       Use PS/2 stepping rate:
-        " PS/2 floppies have much slower step rates than regular floppies.
-          It's been recommended that take about 1/4 of the default speed
-          in some more extreme cases."
-
-
-Supporting utilities and additional documentation:
-==================================================
-
- Additional parameters of the floppy driver can be configured at
-runtime. Utilities which do this can be found in the fdutils package.
-This package also contains a new version of mtools which allows to
-access high capacity disks (up to 1992K on a high density 3 1/2 disk!).
-It also contains additional documentation about the floppy driver.
-
-The latest version can be found at fdutils homepage:
- http://fdutils.linux.lu
-
-The fdutils releases can be found at:
- http://fdutils.linux.lu/download.html
- http://www.tux.org/pub/knaff/fdutils/
- ftp://metalab.unc.edu/pub/Linux/utils/disk-management/
-
-Reporting problems about the floppy driver
-==========================================
-
- If you have a question or a bug report about the floppy driver, mail
-me at Alain.Knaff@poboxes.com . If you post to Usenet, preferably use
-comp.os.linux.hardware. As the volume in these groups is rather high,
-be sure to include the word "floppy" (or "FLOPPY") in the subject
-line.  If the reported problem happens when mounting floppy disks, be
-sure to mention also the type of the filesystem in the subject line.
-
- Be sure to read the FAQ before mailing/posting any bug reports!
-
- Alain
-
-Changelog
-=========
-
-10-30-2004 :   Cleanup, updating, add reference to module configuration.
-               James Nelson <james4765@gmail.com>
-
-6-3-2000 :     Original Document
diff --git a/Documentation/blockdev/nbd.txt b/Documentation/blockdev/nbd.txt
deleted file mode 100644 (file)
index db242ea..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-Network Block Device (TCP version)
-==================================
-
-1) Overview
------------
-
-What is it: With this compiled in the kernel (or as a module), Linux
-can use a remote server as one of its block devices. So every time
-the client computer wants to read, e.g., /dev/nb0, it sends a
-request over TCP to the server, which will reply with the data read.
-This can be used for stations with low disk space (or even diskless)
-to borrow disk space from another computer.
-Unlike NFS, it is possible to put any filesystem on it, etc.
-
-For more information, or to download the nbd-client and nbd-server
-tools, go to http://nbd.sf.net/.
-
-The nbd kernel module need only be installed on the client
-system, as the nbd-server is completely in userspace. In fact,
-the nbd-server has been successfully ported to other operating
-systems, including Windows.
-
-A) NBD parameters
------------------
-
-max_part
-       Number of partitions per device (default: 0).
-
-nbds_max
-       Number of block devices that should be initialized (default: 16).
-
diff --git a/Documentation/blockdev/paride.txt b/Documentation/blockdev/paride.txt
deleted file mode 100644 (file)
index ee6717e..0000000
+++ /dev/null
@@ -1,417 +0,0 @@
-
-               Linux and parallel port IDE devices
-
-PARIDE v1.03   (c) 1997-8  Grant Guenther <grant@torque.net>
-
-1. Introduction
-
-Owing to the simplicity and near universality of the parallel port interface
-to personal computers, many external devices such as portable hard-disk,
-CD-ROM, LS-120 and tape drives use the parallel port to connect to their
-host computer.  While some devices (notably scanners) use ad-hoc methods
-to pass commands and data through the parallel port interface, most 
-external devices are actually identical to an internal model, but with
-a parallel-port adapter chip added in.  Some of the original parallel port
-adapters were little more than mechanisms for multiplexing a SCSI bus.
-(The Iomega PPA-3 adapter used in the ZIP drives is an example of this
-approach).  Most current designs, however, take a different approach.
-The adapter chip reproduces a small ISA or IDE bus in the external device
-and the communication protocol provides operations for reading and writing
-device registers, as well as data block transfer functions.  Sometimes,
-the device being addressed via the parallel cable is a standard SCSI
-controller like an NCR 5380.  The "ditto" family of external tape
-drives use the ISA replicator to interface a floppy disk controller,
-which is then connected to a floppy-tape mechanism.  The vast majority
-of external parallel port devices, however, are now based on standard
-IDE type devices, which require no intermediate controller.  If one
-were to open up a parallel port CD-ROM drive, for instance, one would
-find a standard ATAPI CD-ROM drive, a power supply, and a single adapter
-that interconnected a standard PC parallel port cable and a standard
-IDE cable.  It is usually possible to exchange the CD-ROM device with
-any other device using the IDE interface. 
-
-The document describes the support in Linux for parallel port IDE
-devices.  It does not cover parallel port SCSI devices, "ditto" tape
-drives or scanners.  Many different devices are supported by the 
-parallel port IDE subsystem, including:
-
-       MicroSolutions backpack CD-ROM
-       MicroSolutions backpack PD/CD
-       MicroSolutions backpack hard-drives
-       MicroSolutions backpack 8000t tape drive
-       SyQuest EZ-135, EZ-230 & SparQ drives
-       Avatar Shark
-       Imation Superdisk LS-120
-       Maxell Superdisk LS-120
-       FreeCom Power CD 
-       Hewlett-Packard 5GB and 8GB tape drives
-       Hewlett-Packard 7100 and 7200 CD-RW drives
-
-as well as most of the clone and no-name products on the market.
-
-To support such a wide range of devices, PARIDE, the parallel port IDE
-subsystem, is actually structured in three parts.   There is a base
-paride module which provides a registry and some common methods for
-accessing the parallel ports.  The second component is a set of 
-high-level drivers for each of the different types of supported devices: 
-
-       pd      IDE disk
-       pcd     ATAPI CD-ROM
-       pf      ATAPI disk
-       pt      ATAPI tape
-       pg      ATAPI generic
-
-(Currently, the pg driver is only used with CD-R drives).
-
-The high-level drivers function according to the relevant standards.
-The third component of PARIDE is a set of low-level protocol drivers
-for each of the parallel port IDE adapter chips.  Thanks to the interest
-and encouragement of Linux users from many parts of the world, 
-support is available for almost all known adapter protocols:
-
-        aten    ATEN EH-100                            (HK)
-        bpck    Microsolutions backpack                (US)
-        comm    DataStor (old-type) "commuter" adapter (TW)
-        dstr    DataStor EP-2000                       (TW)
-        epat    Shuttle EPAT                           (UK)
-        epia    Shuttle EPIA                           (UK)
-       fit2    FIT TD-2000                            (US)
-       fit3    FIT TD-3000                            (US)
-       friq    Freecom IQ cable                       (DE)
-        frpw    Freecom Power                          (DE)
-        kbic    KingByte KBIC-951A and KBIC-971A       (TW)
-       ktti    KT Technology PHd adapter              (SG)
-        on20    OnSpec 90c20                           (US)
-        on26    OnSpec 90c26                           (US)
-
-
-2. Using the PARIDE subsystem
-
-While configuring the Linux kernel, you may choose either to build
-the PARIDE drivers into your kernel, or to build them as modules.
-
-In either case, you will need to select "Parallel port IDE device support"
-as well as at least one of the high-level drivers and at least one
-of the parallel port communication protocols.  If you do not know
-what kind of parallel port adapter is used in your drive, you could
-begin by checking the file names and any text files on your DOS 
-installation floppy.  Alternatively, you can look at the markings on
-the adapter chip itself.  That's usually sufficient to identify the
-correct device.  
-
-You can actually select all the protocol modules, and allow the PARIDE
-subsystem to try them all for you.
-
-For the "brand-name" products listed above, here are the protocol
-and high-level drivers that you would use:
-
-       Manufacturer            Model           Driver  Protocol
-       
-       MicroSolutions          CD-ROM          pcd     bpck
-       MicroSolutions          PD drive        pf      bpck
-       MicroSolutions          hard-drive      pd      bpck
-       MicroSolutions          8000t tape      pt      bpck
-       SyQuest                 EZ, SparQ       pd      epat
-       Imation                 Superdisk       pf      epat
-       Maxell                  Superdisk       pf      friq
-       Avatar                  Shark           pd      epat
-       FreeCom                 CD-ROM          pcd     frpw
-       Hewlett-Packard         5GB Tape        pt      epat
-       Hewlett-Packard         7200e (CD)      pcd     epat
-       Hewlett-Packard         7200e (CD-R)    pg      epat
-
-2.1  Configuring built-in drivers
-
-We recommend that you get to know how the drivers work and how to
-configure them as loadable modules, before attempting to compile a
-kernel with the drivers built-in.
-
-If you built all of your PARIDE support directly into your kernel,
-and you have just a single parallel port IDE device, your kernel should
-locate it automatically for you.  If you have more than one device,
-you may need to give some command line options to your bootloader
-(eg: LILO), how to do that is beyond the scope of this document.
-
-The high-level drivers accept a number of command line parameters, all
-of which are documented in the source files in linux/drivers/block/paride.
-By default, each driver will automatically try all parallel ports it
-can find, and all protocol types that have been installed, until it finds
-a parallel port IDE adapter.  Once it finds one, the probe stops.  So,
-if you have more than one device, you will need to tell the drivers
-how to identify them.  This requires specifying the port address, the
-protocol identification number and, for some devices, the drive's
-chain ID.  While your system is booting, a number of messages are
-displayed on the console.  Like all such messages, they can be
-reviewed with the 'dmesg' command.  Among those messages will be
-some lines like:
-
-       paride: bpck registered as protocol 0
-       paride: epat registered as protocol 1
-
-The numbers will always be the same until you build a new kernel with
-different protocol selections.  You should note these numbers as you
-will need them to identify the devices.
-
-If you happen to be using a MicroSolutions backpack device, you will
-also need to know the unit ID number for each drive.  This is usually
-the last two digits of the drive's serial number (but read MicroSolutions'
-documentation about this).
-
-As an example, let's assume that you have a MicroSolutions PD/CD drive
-with unit ID number 36 connected to the parallel port at 0x378, a SyQuest 
-EZ-135 connected to the chained port on the PD/CD drive and also an 
-Imation Superdisk connected to port 0x278.  You could give the following 
-options on your boot command:
-
-       pd.drive0=0x378,1 pf.drive0=0x278,1 pf.drive1=0x378,0,36
-
-In the last option, pf.drive1 configures device /dev/pf1, the 0x378
-is the parallel port base address, the 0 is the protocol registration
-number and 36 is the chain ID.
-
-Please note:  while PARIDE will work both with and without the 
-PARPORT parallel port sharing system that is included by the
-"Parallel port support" option, PARPORT must be included and enabled
-if you want to use chains of devices on the same parallel port.
-
-2.2  Loading and configuring PARIDE as modules
-
-It is much faster and simpler to get to understand the PARIDE drivers
-if you use them as loadable kernel modules.   
-
-Note 1:  using these drivers with the "kerneld" automatic module loading
-system is not recommended for beginners, and is not documented here.  
-
-Note 2:  if you build PARPORT support as a loadable module, PARIDE must
-also be built as loadable modules, and PARPORT must be loaded before the
-PARIDE modules.
-
-To use PARIDE, you must begin by 
-
-       insmod paride
-
-this loads a base module which provides a registry for the protocols,
-among other tasks.
-
-Then, load as many of the protocol modules as you think you might need.
-As you load each module, it will register the protocols that it supports,
-and print a log message to your kernel log file and your console. For 
-example:
-
-       # insmod epat
-       paride: epat registered as protocol 0
-       # insmod kbic
-       paride: k951 registered as protocol 1
-        paride: k971 registered as protocol 2
-
-Finally, you can load high-level drivers for each kind of device that
-you have connected.  By default, each driver will autoprobe for a single 
-device, but you can support up to four similar devices by giving their
-individual co-ordinates when you load the driver.
-
-For example, if you had two no-name CD-ROM drives both using the
-KingByte KBIC-951A adapter, one on port 0x378 and the other on 0x3bc
-you could give the following command:
-
-       # insmod pcd drive0=0x378,1 drive1=0x3bc,1
-
-For most adapters, giving a port address and protocol number is sufficient,
-but check the source files in linux/drivers/block/paride for more 
-information.  (Hopefully someone will write some man pages one day !).
-
-As another example, here's what happens when PARPORT is installed, and
-a SyQuest EZ-135 is attached to port 0x378:
-
-       # insmod paride
-       paride: version 1.0 installed
-       # insmod epat
-       paride: epat registered as protocol 0
-       # insmod pd
-       pd: pd version 1.0, major 45, cluster 64, nice 0
-       pda: Sharing parport1 at 0x378
-       pda: epat 1.0, Shuttle EPAT chip c3 at 0x378, mode 5 (EPP-32), delay 1
-       pda: SyQuest EZ135A, 262144 blocks [128M], (512/16/32), removable media
-        pda: pda1
-
-Note that the last line is the output from the generic partition table
-scanner - in this case it reports that it has found a disk with one partition.
-
-2.3  Using a PARIDE device
-
-Once the drivers have been loaded, you can access PARIDE devices in the
-same way as their traditional counterparts.  You will probably need to
-create the device "special files".  Here is a simple script that you can
-cut to a file and execute:
-
-#!/bin/bash
-#
-# mkd -- a script to create the device special files for the PARIDE subsystem
-#
-function mkdev {
-  mknod $1 $2 $3 $4 ; chmod 0660 $1 ; chown root:disk $1
-}
-#
-function pd {
-  D=$( printf \\$( printf "x%03x" $[ $1 + 97 ] ) )
-  mkdev pd$D b 45 $[ $1 * 16 ]
-  for P in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
-  do mkdev pd$D$P b 45 $[ $1 * 16 + $P ]
-  done
-}
-#
-cd /dev
-#
-for u in 0 1 2 3 ; do pd $u ; done
-for u in 0 1 2 3 ; do mkdev pcd$u b 46 $u ; done 
-for u in 0 1 2 3 ; do mkdev pf$u  b 47 $u ; done 
-for u in 0 1 2 3 ; do mkdev pt$u  c 96 $u ; done 
-for u in 0 1 2 3 ; do mkdev npt$u c 96 $[ $u + 128 ] ; done 
-for u in 0 1 2 3 ; do mkdev pg$u  c 97 $u ; done 
-#
-# end of mkd
-
-With the device files and drivers in place, you can access PARIDE devices
-like any other Linux device.   For example, to mount a CD-ROM in pcd0, use:
-
-       mount /dev/pcd0 /cdrom
-
-If you have a fresh Avatar Shark cartridge, and the drive is pda, you
-might do something like:
-
-       fdisk /dev/pda          -- make a new partition table with
-                                  partition 1 of type 83
-
-       mke2fs /dev/pda1        -- to build the file system
-
-       mkdir /shark            -- make a place to mount the disk
-
-       mount /dev/pda1 /shark
-
-Devices like the Imation superdisk work in the same way, except that
-they do not have a partition table.  For example to make a 120MB
-floppy that you could share with a DOS system:
-
-       mkdosfs /dev/pf0
-       mount /dev/pf0 /mnt
-
-
-2.4  The pf driver
-
-The pf driver is intended for use with parallel port ATAPI disk
-devices.  The most common devices in this category are PD drives
-and LS-120 drives.  Traditionally, media for these devices are not
-partitioned.  Consequently, the pf driver does not support partitioned
-media.  This may be changed in a future version of the driver. 
-
-2.5  Using the pt driver
-
-The pt driver for parallel port ATAPI tape drives is a minimal driver.
-It does not yet support many of the standard tape ioctl operations. 
-For best performance, a block size of 32KB should be used.  You will
-probably want to set the parallel port delay to 0, if you can.
-
-2.6  Using the pg driver
-
-The pg driver can be used in conjunction with the cdrecord program
-to create CD-ROMs.  Please get cdrecord version 1.6.1 or later
-from ftp://ftp.fokus.gmd.de/pub/unix/cdrecord/ .  To record CD-R media 
-your parallel port should ideally be set to EPP mode, and the "port delay" 
-should be set to 0.  With those settings it is possible to record at 2x 
-speed without any buffer underruns.  If you cannot get the driver to work
-in EPP mode, try to use "bidirectional" or "PS/2" mode and 1x speeds only.
-
-
-3. Troubleshooting
-
-3.1  Use EPP mode if you can
-
-The most common problems that people report with the PARIDE drivers
-concern the parallel port CMOS settings.  At this time, none of the
-PARIDE protocol modules support ECP mode, or any ECP combination modes.
-If you are able to do so, please set your parallel port into EPP mode
-using your CMOS setup procedure.
-
-3.2  Check the port delay
-
-Some parallel ports cannot reliably transfer data at full speed.  To
-offset the errors, the PARIDE protocol modules introduce a "port
-delay" between each access to the i/o ports.  Each protocol sets
-a default value for this delay.  In most cases, the user can override
-the default and set it to 0 - resulting in somewhat higher transfer
-rates.  In some rare cases (especially with older 486 systems) the
-default delays are not long enough.  if you experience corrupt data
-transfers, or unexpected failures, you may wish to increase the
-port delay.   The delay can be programmed using the "driveN" parameters
-to each of the high-level drivers.  Please see the notes above, or
-read the comments at the beginning of the driver source files in
-linux/drivers/block/paride.
-
-3.3  Some drives need a printer reset
-
-There appear to be a number of "noname" external drives on the market
-that do not always power up correctly.  We have noticed this with some
-drives based on OnSpec and older Freecom adapters.  In these rare cases,
-the adapter can often be reinitialised by issuing a "printer reset" on
-the parallel port.  As the reset operation is potentially disruptive in 
-multiple device environments, the PARIDE drivers will not do it 
-automatically.  You can however, force a printer reset by doing:
-
-       insmod lp reset=1
-       rmmod lp
-
-If you have one of these marginal cases, you should probably build
-your paride drivers as modules, and arrange to do the printer reset
-before loading the PARIDE drivers. 
-
-3.4  Use the verbose option and dmesg if you need help
-
-While a lot of testing has gone into these drivers to make them work
-as smoothly as possible, problems will arise.  If you do have problems,
-please check all the obvious things first:  does the drive work in
-DOS with the manufacturer's drivers ?  If that doesn't yield any useful
-clues, then please make sure that only one drive is hooked to your system,
-and that either (a) PARPORT is enabled or (b) no other device driver
-is using your parallel port (check in /proc/ioports).  Then, load the
-appropriate drivers (you can load several protocol modules if you want)
-as in:
-
-       # insmod paride
-       # insmod epat
-       # insmod bpck
-       # insmod kbic
-       ...
-       # insmod pd verbose=1
-
-(using the correct driver for the type of device you have, of course).
-The verbose=1 parameter will cause the drivers to log a trace of their
-activity as they attempt to locate your drive.
-
-Use 'dmesg' to capture a log of all the PARIDE messages (any messages
-beginning with paride:, a protocol module's name or a driver's name) and
-include that with your bug report.  You can submit a bug report in one
-of two ways.  Either send it directly to the author of the PARIDE suite,
-by e-mail to grant@torque.net, or join the linux-parport mailing list
-and post your report there.
-
-3.5  For more information or help
-
-You can join the linux-parport mailing list by sending a mail message
-to 
-               linux-parport-request@torque.net
-
-with the single word 
-
-               subscribe
-
-in the body of the mail message (not in the subject line).   Please be
-sure that your mail program is correctly set up when you do this,  as
-the list manager is a robot that will subscribe you using the reply
-address in your mail headers.  REMOVE any anti-spam gimmicks you may
-have in your mail headers, when sending mail to the list server.
-
-You might also find some useful information on the linux-parport
-web pages (although they are not always up to date) at
-
-       http://web.archive.org/web/*/http://www.torque.net/parport/
-
-
diff --git a/Documentation/blockdev/ramdisk.txt b/Documentation/blockdev/ramdisk.txt
deleted file mode 100644 (file)
index 501e12e..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-Using the RAM disk block device with Linux
-------------------------------------------
-
-Contents:
-
-       1) Overview
-       2) Kernel Command Line Parameters
-       3) Using "rdev -r"
-       4) An Example of Creating a Compressed RAM Disk
-
-
-1) Overview
------------
-
-The RAM disk driver is a way to use main system memory as a block device.  It
-is required for initrd, an initial filesystem used if you need to load modules
-in order to access the root filesystem (see Documentation/admin-guide/initrd.rst).  It can
-also be used for a temporary filesystem for crypto work, since the contents
-are erased on reboot.
-
-The RAM disk dynamically grows as more space is required. It does this by using
-RAM from the buffer cache. The driver marks the buffers it is using as dirty
-so that the VM subsystem does not try to reclaim them later.
-
-The RAM disk supports up to 16 RAM disks by default, and can be reconfigured
-to support an unlimited number of RAM disks (at your own risk).  Just change
-the configuration symbol BLK_DEV_RAM_COUNT in the Block drivers config menu
-and (re)build the kernel.
-
-To use RAM disk support with your system, run './MAKEDEV ram' from the /dev
-directory.  RAM disks are all major number 1, and start with minor number 0
-for /dev/ram0, etc.  If used, modern kernels use /dev/ram0 for an initrd.
-
-The new RAM disk also has the ability to load compressed RAM disk images,
-allowing one to squeeze more programs onto an average installation or
-rescue floppy disk.
-
-
-2) Parameters
----------------------------------
-
-2a) Kernel Command Line Parameters
-
-       ramdisk_size=N
-       ==============
-
-This parameter tells the RAM disk driver to set up RAM disks of N k size.  The
-default is 4096 (4 MB).
-
-2b) Module parameters
-
-       rd_nr
-       =====
-       /dev/ramX devices created.
-
-       max_part
-       ========
-       Maximum partition number.
-
-       rd_size
-       =======
-       See ramdisk_size.
-
-3) Using "rdev -r"
-------------------
-
-The usage of the word (two bytes) that "rdev -r" sets in the kernel image is
-as follows. The low 11 bits (0 -> 10) specify an offset (in 1 k blocks) of up
-to 2 MB (2^11) of where to find the RAM disk (this used to be the size). Bit
-14 indicates that a RAM disk is to be loaded, and bit 15 indicates whether a
-prompt/wait sequence is to be given before trying to read the RAM disk. Since
-the RAM disk dynamically grows as data is being written into it, a size field
-is not required. Bits 11 to 13 are not currently used and may as well be zero.
-These numbers are no magical secrets, as seen below:
-
-./arch/x86/kernel/setup.c:#define RAMDISK_IMAGE_START_MASK     0x07FF
-./arch/x86/kernel/setup.c:#define RAMDISK_PROMPT_FLAG          0x8000
-./arch/x86/kernel/setup.c:#define RAMDISK_LOAD_FLAG            0x4000
-
-Consider a typical two floppy disk setup, where you will have the
-kernel on disk one, and have already put a RAM disk image onto disk #2.
-
-Hence you want to set bits 0 to 13 as 0, meaning that your RAM disk
-starts at an offset of 0 kB from the beginning of the floppy.
-The command line equivalent is: "ramdisk_start=0"
-
-You want bit 14 as one, indicating that a RAM disk is to be loaded.
-The command line equivalent is: "load_ramdisk=1"
-
-You want bit 15 as one, indicating that you want a prompt/keypress
-sequence so that you have a chance to switch floppy disks.
-The command line equivalent is: "prompt_ramdisk=1"
-
-Putting that together gives 2^15 + 2^14 + 0 = 49152 for an rdev word.
-So to create disk one of the set, you would do:
-
-       /usr/src/linux# cat arch/x86/boot/zImage > /dev/fd0
-       /usr/src/linux# rdev /dev/fd0 /dev/fd0
-       /usr/src/linux# rdev -r /dev/fd0 49152
-
-If you make a boot disk that has LILO, then for the above, you would use:
-       append = "ramdisk_start=0 load_ramdisk=1 prompt_ramdisk=1"
-Since the default start = 0 and the default prompt = 1, you could use:
-       append = "load_ramdisk=1"
-
-
-4) An Example of Creating a Compressed RAM Disk
-----------------------------------------------
-
-To create a RAM disk image, you will need a spare block device to
-construct it on. This can be the RAM disk device itself, or an
-unused disk partition (such as an unmounted swap partition). For this
-example, we will use the RAM disk device, "/dev/ram0".
-
-Note: This technique should not be done on a machine with less than 8 MB
-of RAM. If using a spare disk partition instead of /dev/ram0, then this
-restriction does not apply.
-
-a) Decide on the RAM disk size that you want. Say 2 MB for this example.
-   Create it by writing to the RAM disk device. (This step is not currently
-   required, but may be in the future.) It is wise to zero out the
-   area (esp. for disks) so that maximal compression is achieved for
-   the unused blocks of the image that you are about to create.
-
-       dd if=/dev/zero of=/dev/ram0 bs=1k count=2048
-
-b) Make a filesystem on it. Say ext2fs for this example.
-
-       mke2fs -vm0 /dev/ram0 2048
-
-c) Mount it, copy the files you want to it (eg: /etc/* /dev/* ...)
-   and unmount it again.
-
-d) Compress the contents of the RAM disk. The level of compression
-   will be approximately 50% of the space used by the files. Unused
-   space on the RAM disk will compress to almost nothing.
-
-       dd if=/dev/ram0 bs=1k count=2048 | gzip -v9 > /tmp/ram_image.gz
-
-e) Put the kernel onto the floppy
-
-       dd if=zImage of=/dev/fd0 bs=1k
-
-f) Put the RAM disk image onto the floppy, after the kernel. Use an offset
-   that is slightly larger than the kernel, so that you can put another
-   (possibly larger) kernel onto the same floppy later without overlapping
-   the RAM disk image. An offset of 400 kB for kernels about 350 kB in
-   size would be reasonable. Make sure offset+size of ram_image.gz is
-   not larger than the total space on your floppy (usually 1440 kB).
-
-       dd if=/tmp/ram_image.gz of=/dev/fd0 bs=1k seek=400
-
-g) Use "rdev" to set the boot device, RAM disk offset, prompt flag, etc.
-   For prompt_ramdisk=1, load_ramdisk=1, ramdisk_start=400, one would
-   have 2^15 + 2^14 + 400 = 49552.
-
-       rdev /dev/fd0 /dev/fd0
-       rdev -r /dev/fd0 49552
-
-That is it. You now have your boot/root compressed RAM disk floppy. Some
-users may wish to combine steps (d) and (f) by using a pipe.
-
---------------------------------------------------------------------------
-                                               Paul Gortmaker 12/95
-
-Changelog:
-----------
-
-10-22-04 :     Updated to reflect changes in command line options, remove
-               obsolete references, general cleanup.
-               James Nelson (james4765@gmail.com)
-
-
-12-95 :                Original Document
diff --git a/Documentation/blockdev/zram.txt b/Documentation/blockdev/zram.txt
deleted file mode 100644 (file)
index 4df0ce2..0000000
+++ /dev/null
@@ -1,355 +0,0 @@
-zram: Compressed RAM based block devices
-----------------------------------------
-
-* Introduction
-
-The zram module creates RAM based block devices named /dev/zram<id>
-(<id> = 0, 1, ...). Pages written to these disks are compressed and stored
-in memory itself. These disks allow very fast I/O and compression provides
-good amounts of memory savings. Some of the usecases include /tmp storage,
-use as swap disks, various caches under /var and maybe many more :)
-
-Statistics for individual zram devices are exported through sysfs nodes at
-/sys/block/zram<id>/
-
-* Usage
-
-There are several ways to configure and manage zram device(-s):
-a) using zram and zram_control sysfs attributes
-b) using zramctl utility, provided by util-linux (util-linux@vger.kernel.org).
-
-In this document we will describe only 'manual' zram configuration steps,
-IOW, zram and zram_control sysfs attributes.
-
-In order to get a better idea about zramctl please consult util-linux
-documentation, zramctl man-page or `zramctl --help'. Please be informed
-that zram maintainers do not develop/maintain util-linux or zramctl, should
-you have any questions please contact util-linux@vger.kernel.org
-
-Following shows a typical sequence of steps for using zram.
-
-WARNING
-=======
-For the sake of simplicity we skip error checking parts in most of the
-examples below. However, it is your sole responsibility to handle errors.
-
-zram sysfs attributes always return negative values in case of errors.
-The list of possible return codes:
--EBUSY -- an attempt to modify an attribute that cannot be changed once
-the device has been initialised. Please reset device first;
--ENOMEM        -- zram was not able to allocate enough memory to fulfil your
-needs;
--EINVAL        -- invalid input has been provided.
-
-If you use 'echo', the returned value that is changed by 'echo' utility,
-and, in general case, something like:
-
-       echo 3 > /sys/block/zram0/max_comp_streams
-       if [ $? -ne 0 ];
-               handle_error
-       fi
-
-should suffice.
-
-1) Load Module:
-       modprobe zram num_devices=4
-       This creates 4 devices: /dev/zram{0,1,2,3}
-
-num_devices parameter is optional and tells zram how many devices should be
-pre-created. Default: 1.
-
-2) Set max number of compression streams
-Regardless the value passed to this attribute, ZRAM will always
-allocate multiple compression streams - one per online CPUs - thus
-allowing several concurrent compression operations. The number of
-allocated compression streams goes down when some of the CPUs
-become offline. There is no single-compression-stream mode anymore,
-unless you are running a UP system or has only 1 CPU online.
-
-To find out how many streams are currently available:
-       cat /sys/block/zram0/max_comp_streams
-
-3) Select compression algorithm
-Using comp_algorithm device attribute one can see available and
-currently selected (shown in square brackets) compression algorithms,
-change selected compression algorithm (once the device is initialised
-there is no way to change compression algorithm).
-
-Examples:
-       #show supported compression algorithms
-       cat /sys/block/zram0/comp_algorithm
-       lzo [lz4]
-
-       #select lzo compression algorithm
-       echo lzo > /sys/block/zram0/comp_algorithm
-
-For the time being, the `comp_algorithm' content does not necessarily
-show every compression algorithm supported by the kernel. We keep this
-list primarily to simplify device configuration and one can configure
-a new device with a compression algorithm that is not listed in
-`comp_algorithm'. The thing is that, internally, ZRAM uses Crypto API
-and, if some of the algorithms were built as modules, it's impossible
-to list all of them using, for instance, /proc/crypto or any other
-method. This, however, has an advantage of permitting the usage of
-custom crypto compression modules (implementing S/W or H/W compression).
-
-4) Set Disksize
-Set disk size by writing the value to sysfs node 'disksize'.
-The value can be either in bytes or you can use mem suffixes.
-Examples:
-       # Initialize /dev/zram0 with 50MB disksize
-       echo $((50*1024*1024)) > /sys/block/zram0/disksize
-
-       # Using mem suffixes
-       echo 256K > /sys/block/zram0/disksize
-       echo 512M > /sys/block/zram0/disksize
-       echo 1G > /sys/block/zram0/disksize
-
-Note:
-There is little point creating a zram of greater than twice the size of memory
-since we expect a 2:1 compression ratio. Note that zram uses about 0.1% of the
-size of the disk when not in use so a huge zram is wasteful.
-
-5) Set memory limit: Optional
-Set memory limit by writing the value to sysfs node 'mem_limit'.
-The value can be either in bytes or you can use mem suffixes.
-In addition, you could change the value in runtime.
-Examples:
-       # limit /dev/zram0 with 50MB memory
-       echo $((50*1024*1024)) > /sys/block/zram0/mem_limit
-
-       # Using mem suffixes
-       echo 256K > /sys/block/zram0/mem_limit
-       echo 512M > /sys/block/zram0/mem_limit
-       echo 1G > /sys/block/zram0/mem_limit
-
-       # To disable memory limit
-       echo 0 > /sys/block/zram0/mem_limit
-
-6) Activate:
-       mkswap /dev/zram0
-       swapon /dev/zram0
-
-       mkfs.ext4 /dev/zram1
-       mount /dev/zram1 /tmp
-
-7) Add/remove zram devices
-
-zram provides a control interface, which enables dynamic (on-demand) device
-addition and removal.
-
-In order to add a new /dev/zramX device, perform read operation on hot_add
-attribute. This will return either new device's device id (meaning that you
-can use /dev/zram<id>) or error code.
-
-Example:
-       cat /sys/class/zram-control/hot_add
-       1
-
-To remove the existing /dev/zramX device (where X is a device id)
-execute
-       echo X > /sys/class/zram-control/hot_remove
-
-8) Stats:
-Per-device statistics are exported as various nodes under /sys/block/zram<id>/
-
-A brief description of exported device attributes. For more details please
-read Documentation/ABI/testing/sysfs-block-zram.
-
-Name                   access            description
-----                   ------            -----------
-disksize               RW      show and set the device's disk size
-initstate              RO      shows the initialization state of the device
-reset                  WO      trigger device reset
-mem_used_max           WO      reset the `mem_used_max' counter (see later)
-mem_limit              WO      specifies the maximum amount of memory ZRAM can use
-                               to store the compressed data
-writeback_limit        WO      specifies the maximum amount of write IO zram can
-                               write out to backing device as 4KB unit
-writeback_limit_enable  RW     show and set writeback_limit feature
-max_comp_streams       RW      the number of possible concurrent compress operations
-comp_algorithm         RW      show and change the compression algorithm
-compact                WO      trigger memory compaction
-debug_stat             RO      this file is used for zram debugging purposes
-backing_dev            RW      set up backend storage for zram to write out
-idle                   WO      mark allocated slot as idle
-
-
-User space is advised to use the following files to read the device statistics.
-
-File /sys/block/zram<id>/stat
-
-Represents block layer statistics. Read Documentation/block/stat.txt for
-details.
-
-File /sys/block/zram<id>/io_stat
-
-The stat file represents device's I/O statistics not accounted by block
-layer and, thus, not available in zram<id>/stat file. It consists of a
-single line of text and contains the following stats separated by
-whitespace:
- failed_reads     the number of failed reads
- failed_writes    the number of failed writes
- invalid_io       the number of non-page-size-aligned I/O requests
- notify_free      Depending on device usage scenario it may account
-                  a) the number of pages freed because of swap slot free
-                  notifications or b) the number of pages freed because of
-                  REQ_OP_DISCARD requests sent by bio. The former ones are
-                  sent to a swap block device when a swap slot is freed,
-                  which implies that this disk is being used as a swap disk.
-                  The latter ones are sent by filesystem mounted with
-                  discard option, whenever some data blocks are getting
-                  discarded.
-
-File /sys/block/zram<id>/mm_stat
-
-The stat file represents device's mm statistics. It consists of a single
-line of text and contains the following stats separated by whitespace:
- orig_data_size   uncompressed size of data stored in this disk.
-                 This excludes same-element-filled pages (same_pages) since
-                 no memory is allocated for them.
-                  Unit: bytes
- compr_data_size  compressed size of data stored in this disk
- mem_used_total   the amount of memory allocated for this disk. This
-                  includes allocator fragmentation and metadata overhead,
-                  allocated for this disk. So, allocator space efficiency
-                  can be calculated using compr_data_size and this statistic.
-                  Unit: bytes
- mem_limit        the maximum amount of memory ZRAM can use to store
-                  the compressed data
- mem_used_max     the maximum amount of memory zram have consumed to
-                  store the data
- same_pages       the number of same element filled pages written to this disk.
-                  No memory is allocated for such pages.
- pages_compacted  the number of pages freed during compaction
- huge_pages      the number of incompressible pages
-
-File /sys/block/zram<id>/bd_stat
-
-The stat file represents device's backing device statistics. It consists of
-a single line of text and contains the following stats separated by whitespace:
- bd_count      size of data written in backing device.
-               Unit: 4K bytes
- bd_reads      the number of reads from backing device
-               Unit: 4K bytes
- bd_writes     the number of writes to backing device
-               Unit: 4K bytes
-
-9) Deactivate:
-       swapoff /dev/zram0
-       umount /dev/zram1
-
-10) Reset:
-       Write any positive value to 'reset' sysfs node
-       echo 1 > /sys/block/zram0/reset
-       echo 1 > /sys/block/zram1/reset
-
-       This frees all the memory allocated for the given device and
-       resets the disksize to zero. You must set the disksize again
-       before reusing the device.
-
-* Optional Feature
-
-= writeback
-
-With CONFIG_ZRAM_WRITEBACK, zram can write idle/incompressible page
-to backing storage rather than keeping it in memory.
-To use the feature, admin should set up backing device via
-
-       "echo /dev/sda5 > /sys/block/zramX/backing_dev"
-
-before disksize setting. It supports only partition at this moment.
-If admin want to use incompressible page writeback, they could do via
-
-       "echo huge > /sys/block/zramX/write"
-
-To use idle page writeback, first, user need to declare zram pages
-as idle.
-
-       "echo all > /sys/block/zramX/idle"
-
-From now on, any pages on zram are idle pages. The idle mark
-will be removed until someone request access of the block.
-IOW, unless there is access request, those pages are still idle pages.
-
-Admin can request writeback of those idle pages at right timing via
-
-       "echo idle > /sys/block/zramX/writeback"
-
-With the command, zram writeback idle pages from memory to the storage.
-
-If there are lots of write IO with flash device, potentially, it has
-flash wearout problem so that admin needs to design write limitation
-to guarantee storage health for entire product life.
-
-To overcome the concern, zram supports "writeback_limit" feature.
-The "writeback_limit_enable"'s default value is 0 so that it doesn't limit
-any writeback. IOW, if admin want to apply writeback budget, he should
-enable writeback_limit_enable via
-
-       $ echo 1 > /sys/block/zramX/writeback_limit_enable
-
-Once writeback_limit_enable is set, zram doesn't allow any writeback
-until admin set the budget via /sys/block/zramX/writeback_limit.
-
-(If admin doesn't enable writeback_limit_enable, writeback_limit's value
-assigned via /sys/block/zramX/writeback_limit is meaninless.)
-
-If admin want to limit writeback as per-day 400M, he could do it
-like below.
-
-       $ MB_SHIFT=20
-       $ 4K_SHIFT=12
-       $ echo $((400<<MB_SHIFT>>4K_SHIFT)) > \
-               /sys/block/zram0/writeback_limit.
-       $ echo 1 > /sys/block/zram0/writeback_limit_enable
-
-If admin want to allow further write again once the bugdet is exausted,
-he could do it like below
-
-       $ echo $((400<<MB_SHIFT>>4K_SHIFT)) > \
-               /sys/block/zram0/writeback_limit
-
-If admin want to see remaining writeback budget since he set,
-
-       $ cat /sys/block/zramX/writeback_limit
-
-If admin want to disable writeback limit, he could do
-
-       $ echo 0 > /sys/block/zramX/writeback_limit_enable
-
-The writeback_limit count will reset whenever you reset zram(e.g.,
-system reboot, echo 1 > /sys/block/zramX/reset) so keeping how many of
-writeback happened until you reset the zram to allocate extra writeback
-budget in next setting is user's job.
-
-If admin want to measure writeback count in a certain period, he could
-know it via /sys/block/zram0/bd_stat's 3rd column.
-
-= memory tracking
-
-With CONFIG_ZRAM_MEMORY_TRACKING, user can know information of the
-zram block. It could be useful to catch cold or incompressible
-pages of the process with*pagemap.
-If you enable the feature, you could see block state via
-/sys/kernel/debug/zram/zram0/block_state". The output is as follows,
-
-         300    75.033841 .wh.
-         301    63.806904 s...
-         302    63.806919 ..hi
-
-First column is zram's block index.
-Second column is access time since the system was booted
-Third column is state of the block.
-(s: same page
-w: written page to backing store
-h: huge page
-i: idle page)
-
-First line of above example says 300th block is accessed at 75.033841sec
-and the block's state is huge so it is written back to the backing
-storage. It's a debugging feature so anyone shouldn't rely on it to work
-properly.
-
-Nitin Gupta
-ngupta@vflare.org
diff --git a/Documentation/bus-devices/ti-gpmc.txt b/Documentation/bus-devices/ti-gpmc.txt
deleted file mode 100644 (file)
index cc9ce57..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-GPMC (General Purpose Memory Controller):
-=========================================
-
-GPMC is an unified memory controller dedicated to interfacing external
-memory devices like
- * Asynchronous SRAM like memories and application specific integrated
-   circuit devices.
- * Asynchronous, synchronous, and page mode burst NOR flash devices
-   NAND flash
- * Pseudo-SRAM devices
-
-GPMC is found on Texas Instruments SoC's (OMAP based)
-IP details: http://www.ti.com/lit/pdf/spruh73 section 7.1
-
-
-GPMC generic timing calculation:
-================================
-
-GPMC has certain timings that has to be programmed for proper
-functioning of the peripheral, while peripheral has another set of
-timings. To have peripheral work with gpmc, peripheral timings has to
-be translated to the form gpmc can understand. The way it has to be
-translated depends on the connected peripheral. Also there is a
-dependency for certain gpmc timings on gpmc clock frequency. Hence a
-generic timing routine was developed to achieve above requirements.
-
-Generic routine provides a generic method to calculate gpmc timings
-from gpmc peripheral timings. struct gpmc_device_timings fields has to
-be updated with timings from the datasheet of the peripheral that is
-connected to gpmc. A few of the peripheral timings can be fed either
-in time or in cycles, provision to handle this scenario has been
-provided (refer struct gpmc_device_timings definition). It may so
-happen that timing as specified by peripheral datasheet is not present
-in timing structure, in this scenario, try to correlate peripheral
-timing to the one available. If that doesn't work, try to add a new
-field as required by peripheral, educate generic timing routine to
-handle it, make sure that it does not break any of the existing.
-Then there may be cases where peripheral datasheet doesn't mention
-certain fields of struct gpmc_device_timings, zero those entries.
-
-Generic timing routine has been verified to work properly on
-multiple onenand's and tusb6010 peripherals.
-
-A word of caution: generic timing routine has been developed based
-on understanding of gpmc timings, peripheral timings, available
-custom timing routines, a kind of reverse engineering without
-most of the datasheets & hardware (to be exact none of those supported
-in mainline having custom timing routine) and by simulation.
-
-gpmc timing dependency on peripheral timings:
-[<gpmc_timing>: <peripheral timing1>, <peripheral timing2> ...]
-
-1. common
-cs_on: t_ceasu
-adv_on: t_avdasu, t_ceavd
-
-2. sync common
-sync_clk: clk
-page_burst_access: t_bacc
-clk_activation: t_ces, t_avds
-
-3. read async muxed
-adv_rd_off: t_avdp_r
-oe_on: t_oeasu, t_aavdh
-access: t_iaa, t_oe, t_ce, t_aa
-rd_cycle: t_rd_cycle, t_cez_r, t_oez
-
-4. read async non-muxed
-adv_rd_off: t_avdp_r
-oe_on: t_oeasu
-access: t_iaa, t_oe, t_ce, t_aa
-rd_cycle: t_rd_cycle, t_cez_r, t_oez
-
-5. read sync muxed
-adv_rd_off: t_avdp_r, t_avdh
-oe_on: t_oeasu, t_ach, cyc_aavdh_oe
-access: t_iaa, cyc_iaa, cyc_oe
-rd_cycle: t_cez_r, t_oez, t_ce_rdyz
-
-6. read sync non-muxed
-adv_rd_off: t_avdp_r
-oe_on: t_oeasu
-access: t_iaa, cyc_iaa, cyc_oe
-rd_cycle: t_cez_r, t_oez, t_ce_rdyz
-
-7. write async muxed
-adv_wr_off: t_avdp_w
-we_on, wr_data_mux_bus: t_weasu, t_aavdh, cyc_aavhd_we
-we_off: t_wpl
-cs_wr_off: t_wph
-wr_cycle: t_cez_w, t_wr_cycle
-
-8. write async non-muxed
-adv_wr_off: t_avdp_w
-we_on, wr_data_mux_bus: t_weasu
-we_off: t_wpl
-cs_wr_off: t_wph
-wr_cycle: t_cez_w, t_wr_cycle
-
-9. write sync muxed
-adv_wr_off: t_avdp_w, t_avdh
-we_on, wr_data_mux_bus: t_weasu, t_rdyo, t_aavdh, cyc_aavhd_we
-we_off: t_wpl, cyc_wpl
-cs_wr_off: t_wph
-wr_cycle: t_cez_w, t_ce_rdyz
-
-10. write sync non-muxed
-adv_wr_off: t_avdp_w
-we_on, wr_data_mux_bus: t_weasu, t_rdyo
-we_off: t_wpl, cyc_wpl
-cs_wr_off: t_wph
-wr_cycle: t_cez_w, t_ce_rdyz
-
-
-Note: Many of gpmc timings are dependent on other gpmc timings (a few
-gpmc timings purely dependent on other gpmc timings, a reason that
-some of the gpmc timings are missing above), and it will result in
-indirect dependency of peripheral timings to gpmc timings other than
-mentioned above, refer timing routine for more details. To know what
-these peripheral timings correspond to, please see explanations in
-struct gpmc_device_timings definition. And for gpmc timings refer
-IP details (link above).
index efbd5d1..338ad5f 100644 (file)
@@ -1,4 +1,4 @@
-:orphan:
+.. SPDX-License-Identifier: GPL-2.0
 
 =====
 cdrom
diff --git a/Documentation/cgroup-v1/cgroups.rst b/Documentation/cgroup-v1/cgroups.rst
deleted file mode 100644 (file)
index 46bbe7e..0000000
+++ /dev/null
@@ -1,695 +0,0 @@
-==============
-Control Groups
-==============
-
-Written by Paul Menage <menage@google.com> based on
-Documentation/cgroup-v1/cpusets.rst
-
-Original copyright statements from cpusets.txt:
-
-Portions Copyright (C) 2004 BULL SA.
-
-Portions Copyright (c) 2004-2006 Silicon Graphics, Inc.
-
-Modified by Paul Jackson <pj@sgi.com>
-
-Modified by Christoph Lameter <cl@linux.com>
-
-.. CONTENTS:
-
-       1. Control Groups
-       1.1 What are cgroups ?
-       1.2 Why are cgroups needed ?
-       1.3 How are cgroups implemented ?
-       1.4 What does notify_on_release do ?
-       1.5 What does clone_children do ?
-       1.6 How do I use cgroups ?
-       2. Usage Examples and Syntax
-       2.1 Basic Usage
-       2.2 Attaching processes
-       2.3 Mounting hierarchies by name
-       3. Kernel API
-       3.1 Overview
-       3.2 Synchronization
-       3.3 Subsystem API
-       4. Extended attributes usage
-       5. Questions
-
-1. Control Groups
-=================
-
-1.1 What are cgroups ?
-----------------------
-
-Control Groups provide a mechanism for aggregating/partitioning sets of
-tasks, and all their future children, into hierarchical groups with
-specialized behaviour.
-
-Definitions:
-
-A *cgroup* associates a set of tasks with a set of parameters for one
-or more subsystems.
-
-A *subsystem* is a module that makes use of the task grouping
-facilities provided by cgroups to treat groups of tasks in
-particular ways. A subsystem is typically a "resource controller" that
-schedules a resource or applies per-cgroup limits, but it may be
-anything that wants to act on a group of processes, e.g. a
-virtualization subsystem.
-
-A *hierarchy* is a set of cgroups arranged in a tree, such that
-every task in the system is in exactly one of the cgroups in the
-hierarchy, and a set of subsystems; each subsystem has system-specific
-state attached to each cgroup in the hierarchy.  Each hierarchy has
-an instance of the cgroup virtual filesystem associated with it.
-
-At any one time there may be multiple active hierarchies of task
-cgroups. Each hierarchy is a partition of all tasks in the system.
-
-User-level code may create and destroy cgroups by name in an
-instance of the cgroup virtual file system, specify and query to
-which cgroup a task is assigned, and list the task PIDs assigned to
-a cgroup. Those creations and assignments only affect the hierarchy
-associated with that instance of the cgroup file system.
-
-On their own, the only use for cgroups is for simple job
-tracking. The intention is that other subsystems hook into the generic
-cgroup support to provide new attributes for cgroups, such as
-accounting/limiting the resources which processes in a cgroup can
-access. For example, cpusets (see Documentation/cgroup-v1/cpusets.rst) allow
-you to associate a set of CPUs and a set of memory nodes with the
-tasks in each cgroup.
-
-1.2 Why are cgroups needed ?
-----------------------------
-
-There are multiple efforts to provide process aggregations in the
-Linux kernel, mainly for resource-tracking purposes. Such efforts
-include cpusets, CKRM/ResGroups, UserBeanCounters, and virtual server
-namespaces. These all require the basic notion of a
-grouping/partitioning of processes, with newly forked processes ending
-up in the same group (cgroup) as their parent process.
-
-The kernel cgroup patch provides the minimum essential kernel
-mechanisms required to efficiently implement such groups. It has
-minimal impact on the system fast paths, and provides hooks for
-specific subsystems such as cpusets to provide additional behaviour as
-desired.
-
-Multiple hierarchy support is provided to allow for situations where
-the division of tasks into cgroups is distinctly different for
-different subsystems - having parallel hierarchies allows each
-hierarchy to be a natural division of tasks, without having to handle
-complex combinations of tasks that would be present if several
-unrelated subsystems needed to be forced into the same tree of
-cgroups.
-
-At one extreme, each resource controller or subsystem could be in a
-separate hierarchy; at the other extreme, all subsystems
-would be attached to the same hierarchy.
-
-As an example of a scenario (originally proposed by vatsa@in.ibm.com)
-that can benefit from multiple hierarchies, consider a large
-university server with various users - students, professors, system
-tasks etc. The resource planning for this server could be along the
-following lines::
-
-       CPU :          "Top cpuset"
-                       /       \
-               CPUSet1         CPUSet2
-                  |               |
-               (Professors)    (Students)
-
-               In addition (system tasks) are attached to topcpuset (so
-               that they can run anywhere) with a limit of 20%
-
-       Memory : Professors (50%), Students (30%), system (20%)
-
-       Disk : Professors (50%), Students (30%), system (20%)
-
-       Network : WWW browsing (20%), Network File System (60%), others (20%)
-                               / \
-               Professors (15%)  students (5%)
-
-Browsers like Firefox/Lynx go into the WWW network class, while (k)nfsd goes
-into the NFS network class.
-
-At the same time Firefox/Lynx will share an appropriate CPU/Memory class
-depending on who launched it (prof/student).
-
-With the ability to classify tasks differently for different resources
-(by putting those resource subsystems in different hierarchies),
-the admin can easily set up a script which receives exec notifications
-and depending on who is launching the browser he can::
-
-    # echo browser_pid > /sys/fs/cgroup/<restype>/<userclass>/tasks
-
-With only a single hierarchy, he now would potentially have to create
-a separate cgroup for every browser launched and associate it with
-appropriate network and other resource class.  This may lead to
-proliferation of such cgroups.
-
-Also let's say that the administrator would like to give enhanced network
-access temporarily to a student's browser (since it is night and the user
-wants to do online gaming :))  OR give one of the student's simulation
-apps enhanced CPU power.
-
-With ability to write PIDs directly to resource classes, it's just a
-matter of::
-
-       # echo pid > /sys/fs/cgroup/network/<new_class>/tasks
-       (after some time)
-       # echo pid > /sys/fs/cgroup/network/<orig_class>/tasks
-
-Without this ability, the administrator would have to split the cgroup into
-multiple separate ones and then associate the new cgroups with the
-new resource classes.
-
-
-
-1.3 How are cgroups implemented ?
----------------------------------
-
-Control Groups extends the kernel as follows:
-
- - Each task in the system has a reference-counted pointer to a
-   css_set.
-
- - A css_set contains a set of reference-counted pointers to
-   cgroup_subsys_state objects, one for each cgroup subsystem
-   registered in the system. There is no direct link from a task to
-   the cgroup of which it's a member in each hierarchy, but this
-   can be determined by following pointers through the
-   cgroup_subsys_state objects. This is because accessing the
-   subsystem state is something that's expected to happen frequently
-   and in performance-critical code, whereas operations that require a
-   task's actual cgroup assignments (in particular, moving between
-   cgroups) are less common. A linked list runs through the cg_list
-   field of each task_struct using the css_set, anchored at
-   css_set->tasks.
-
- - A cgroup hierarchy filesystem can be mounted for browsing and
-   manipulation from user space.
-
- - You can list all the tasks (by PID) attached to any cgroup.
-
-The implementation of cgroups requires a few, simple hooks
-into the rest of the kernel, none in performance-critical paths:
-
- - in init/main.c, to initialize the root cgroups and initial
-   css_set at system boot.
-
- - in fork and exit, to attach and detach a task from its css_set.
-
-In addition, a new file system of type "cgroup" may be mounted, to
-enable browsing and modifying the cgroups presently known to the
-kernel.  When mounting a cgroup hierarchy, you may specify a
-comma-separated list of subsystems to mount as the filesystem mount
-options.  By default, mounting the cgroup filesystem attempts to
-mount a hierarchy containing all registered subsystems.
-
-If an active hierarchy with exactly the same set of subsystems already
-exists, it will be reused for the new mount. If no existing hierarchy
-matches, and any of the requested subsystems are in use in an existing
-hierarchy, the mount will fail with -EBUSY. Otherwise, a new hierarchy
-is activated, associated with the requested subsystems.
-
-It's not currently possible to bind a new subsystem to an active
-cgroup hierarchy, or to unbind a subsystem from an active cgroup
-hierarchy. This may be possible in future, but is fraught with nasty
-error-recovery issues.
-
-When a cgroup filesystem is unmounted, if there are any
-child cgroups created below the top-level cgroup, that hierarchy
-will remain active even though unmounted; if there are no
-child cgroups then the hierarchy will be deactivated.
-
-No new system calls are added for cgroups - all support for
-querying and modifying cgroups is via this cgroup file system.
-
-Each task under /proc has an added file named 'cgroup' displaying,
-for each active hierarchy, the subsystem names and the cgroup name
-as the path relative to the root of the cgroup file system.
-
-Each cgroup is represented by a directory in the cgroup file system
-containing the following files describing that cgroup:
-
- - tasks: list of tasks (by PID) attached to that cgroup.  This list
-   is not guaranteed to be sorted.  Writing a thread ID into this file
-   moves the thread into this cgroup.
- - cgroup.procs: list of thread group IDs in the cgroup.  This list is
-   not guaranteed to be sorted or free of duplicate TGIDs, and userspace
-   should sort/uniquify the list if this property is required.
-   Writing a thread group ID into this file moves all threads in that
-   group into this cgroup.
- - notify_on_release flag: run the release agent on exit?
- - release_agent: the path to use for release notifications (this file
-   exists in the top cgroup only)
-
-Other subsystems such as cpusets may add additional files in each
-cgroup dir.
-
-New cgroups are created using the mkdir system call or shell
-command.  The properties of a cgroup, such as its flags, are
-modified by writing to the appropriate file in that cgroups
-directory, as listed above.
-
-The named hierarchical structure of nested cgroups allows partitioning
-a large system into nested, dynamically changeable, "soft-partitions".
-
-The attachment of each task, automatically inherited at fork by any
-children of that task, to a cgroup allows organizing the work load
-on a system into related sets of tasks.  A task may be re-attached to
-any other cgroup, if allowed by the permissions on the necessary
-cgroup file system directories.
-
-When a task is moved from one cgroup to another, it gets a new
-css_set pointer - if there's an already existing css_set with the
-desired collection of cgroups then that group is reused, otherwise a new
-css_set is allocated. The appropriate existing css_set is located by
-looking into a hash table.
-
-To allow access from a cgroup to the css_sets (and hence tasks)
-that comprise it, a set of cg_cgroup_link objects form a lattice;
-each cg_cgroup_link is linked into a list of cg_cgroup_links for
-a single cgroup on its cgrp_link_list field, and a list of
-cg_cgroup_links for a single css_set on its cg_link_list.
-
-Thus the set of tasks in a cgroup can be listed by iterating over
-each css_set that references the cgroup, and sub-iterating over
-each css_set's task set.
-
-The use of a Linux virtual file system (vfs) to represent the
-cgroup hierarchy provides for a familiar permission and name space
-for cgroups, with a minimum of additional kernel code.
-
-1.4 What does notify_on_release do ?
-------------------------------------
-
-If the notify_on_release flag is enabled (1) in a cgroup, then
-whenever the last task in the cgroup leaves (exits or attaches to
-some other cgroup) and the last child cgroup of that cgroup
-is removed, then the kernel runs the command specified by the contents
-of the "release_agent" file in that hierarchy's root directory,
-supplying the pathname (relative to the mount point of the cgroup
-file system) of the abandoned cgroup.  This enables automatic
-removal of abandoned cgroups.  The default value of
-notify_on_release in the root cgroup at system boot is disabled
-(0).  The default value of other cgroups at creation is the current
-value of their parents' notify_on_release settings. The default value of
-a cgroup hierarchy's release_agent path is empty.
-
-1.5 What does clone_children do ?
----------------------------------
-
-This flag only affects the cpuset controller. If the clone_children
-flag is enabled (1) in a cgroup, a new cpuset cgroup will copy its
-configuration from the parent during initialization.
-
-1.6 How do I use cgroups ?
---------------------------
-
-To start a new job that is to be contained within a cgroup, using
-the "cpuset" cgroup subsystem, the steps are something like::
-
- 1) mount -t tmpfs cgroup_root /sys/fs/cgroup
- 2) mkdir /sys/fs/cgroup/cpuset
- 3) mount -t cgroup -ocpuset cpuset /sys/fs/cgroup/cpuset
- 4) Create the new cgroup by doing mkdir's and write's (or echo's) in
-    the /sys/fs/cgroup/cpuset virtual file system.
- 5) Start a task that will be the "founding father" of the new job.
- 6) Attach that task to the new cgroup by writing its PID to the
-    /sys/fs/cgroup/cpuset tasks file for that cgroup.
- 7) fork, exec or clone the job tasks from this founding father task.
-
-For example, the following sequence of commands will setup a cgroup
-named "Charlie", containing just CPUs 2 and 3, and Memory Node 1,
-and then start a subshell 'sh' in that cgroup::
-
-  mount -t tmpfs cgroup_root /sys/fs/cgroup
-  mkdir /sys/fs/cgroup/cpuset
-  mount -t cgroup cpuset -ocpuset /sys/fs/cgroup/cpuset
-  cd /sys/fs/cgroup/cpuset
-  mkdir Charlie
-  cd Charlie
-  /bin/echo 2-3 > cpuset.cpus
-  /bin/echo 1 > cpuset.mems
-  /bin/echo $$ > tasks
-  sh
-  # The subshell 'sh' is now running in cgroup Charlie
-  # The next line should display '/Charlie'
-  cat /proc/self/cgroup
-
-2. Usage Examples and Syntax
-============================
-
-2.1 Basic Usage
----------------
-
-Creating, modifying, using cgroups can be done through the cgroup
-virtual filesystem.
-
-To mount a cgroup hierarchy with all available subsystems, type::
-
-  # mount -t cgroup xxx /sys/fs/cgroup
-
-The "xxx" is not interpreted by the cgroup code, but will appear in
-/proc/mounts so may be any useful identifying string that you like.
-
-Note: Some subsystems do not work without some user input first.  For instance,
-if cpusets are enabled the user will have to populate the cpus and mems files
-for each new cgroup created before that group can be used.
-
-As explained in section `1.2 Why are cgroups needed?` you should create
-different hierarchies of cgroups for each single resource or group of
-resources you want to control. Therefore, you should mount a tmpfs on
-/sys/fs/cgroup and create directories for each cgroup resource or resource
-group::
-
-  # mount -t tmpfs cgroup_root /sys/fs/cgroup
-  # mkdir /sys/fs/cgroup/rg1
-
-To mount a cgroup hierarchy with just the cpuset and memory
-subsystems, type::
-
-  # mount -t cgroup -o cpuset,memory hier1 /sys/fs/cgroup/rg1
-
-While remounting cgroups is currently supported, it is not recommend
-to use it. Remounting allows changing bound subsystems and
-release_agent. Rebinding is hardly useful as it only works when the
-hierarchy is empty and release_agent itself should be replaced with
-conventional fsnotify. The support for remounting will be removed in
-the future.
-
-To Specify a hierarchy's release_agent::
-
-  # mount -t cgroup -o cpuset,release_agent="/sbin/cpuset_release_agent" \
-    xxx /sys/fs/cgroup/rg1
-
-Note that specifying 'release_agent' more than once will return failure.
-
-Note that changing the set of subsystems is currently only supported
-when the hierarchy consists of a single (root) cgroup. Supporting
-the ability to arbitrarily bind/unbind subsystems from an existing
-cgroup hierarchy is intended to be implemented in the future.
-
-Then under /sys/fs/cgroup/rg1 you can find a tree that corresponds to the
-tree of the cgroups in the system. For instance, /sys/fs/cgroup/rg1
-is the cgroup that holds the whole system.
-
-If you want to change the value of release_agent::
-
-  # echo "/sbin/new_release_agent" > /sys/fs/cgroup/rg1/release_agent
-
-It can also be changed via remount.
-
-If you want to create a new cgroup under /sys/fs/cgroup/rg1::
-
-  # cd /sys/fs/cgroup/rg1
-  # mkdir my_cgroup
-
-Now you want to do something with this cgroup:
-
-  # cd my_cgroup
-
-In this directory you can find several files::
-
-  # ls
-  cgroup.procs notify_on_release tasks
-  (plus whatever files added by the attached subsystems)
-
-Now attach your shell to this cgroup::
-
-  # /bin/echo $$ > tasks
-
-You can also create cgroups inside your cgroup by using mkdir in this
-directory::
-
-  # mkdir my_sub_cs
-
-To remove a cgroup, just use rmdir::
-
-  # rmdir my_sub_cs
-
-This will fail if the cgroup is in use (has cgroups inside, or
-has processes attached, or is held alive by other subsystem-specific
-reference).
-
-2.2 Attaching processes
------------------------
-
-::
-
-  # /bin/echo PID > tasks
-
-Note that it is PID, not PIDs. You can only attach ONE task at a time.
-If you have several tasks to attach, you have to do it one after another::
-
-  # /bin/echo PID1 > tasks
-  # /bin/echo PID2 > tasks
-         ...
-  # /bin/echo PIDn > tasks
-
-You can attach the current shell task by echoing 0::
-
-  # echo 0 > tasks
-
-You can use the cgroup.procs file instead of the tasks file to move all
-threads in a threadgroup at once. Echoing the PID of any task in a
-threadgroup to cgroup.procs causes all tasks in that threadgroup to be
-attached to the cgroup. Writing 0 to cgroup.procs moves all tasks
-in the writing task's threadgroup.
-
-Note: Since every task is always a member of exactly one cgroup in each
-mounted hierarchy, to remove a task from its current cgroup you must
-move it into a new cgroup (possibly the root cgroup) by writing to the
-new cgroup's tasks file.
-
-Note: Due to some restrictions enforced by some cgroup subsystems, moving
-a process to another cgroup can fail.
-
-2.3 Mounting hierarchies by name
---------------------------------
-
-Passing the name=<x> option when mounting a cgroups hierarchy
-associates the given name with the hierarchy.  This can be used when
-mounting a pre-existing hierarchy, in order to refer to it by name
-rather than by its set of active subsystems.  Each hierarchy is either
-nameless, or has a unique name.
-
-The name should match [\w.-]+
-
-When passing a name=<x> option for a new hierarchy, you need to
-specify subsystems manually; the legacy behaviour of mounting all
-subsystems when none are explicitly specified is not supported when
-you give a subsystem a name.
-
-The name of the subsystem appears as part of the hierarchy description
-in /proc/mounts and /proc/<pid>/cgroups.
-
-
-3. Kernel API
-=============
-
-3.1 Overview
-------------
-
-Each kernel subsystem that wants to hook into the generic cgroup
-system needs to create a cgroup_subsys object. This contains
-various methods, which are callbacks from the cgroup system, along
-with a subsystem ID which will be assigned by the cgroup system.
-
-Other fields in the cgroup_subsys object include:
-
-- subsys_id: a unique array index for the subsystem, indicating which
-  entry in cgroup->subsys[] this subsystem should be managing.
-
-- name: should be initialized to a unique subsystem name. Should be
-  no longer than MAX_CGROUP_TYPE_NAMELEN.
-
-- early_init: indicate if the subsystem needs early initialization
-  at system boot.
-
-Each cgroup object created by the system has an array of pointers,
-indexed by subsystem ID; this pointer is entirely managed by the
-subsystem; the generic cgroup code will never touch this pointer.
-
-3.2 Synchronization
--------------------
-
-There is a global mutex, cgroup_mutex, used by the cgroup
-system. This should be taken by anything that wants to modify a
-cgroup. It may also be taken to prevent cgroups from being
-modified, but more specific locks may be more appropriate in that
-situation.
-
-See kernel/cgroup.c for more details.
-
-Subsystems can take/release the cgroup_mutex via the functions
-cgroup_lock()/cgroup_unlock().
-
-Accessing a task's cgroup pointer may be done in the following ways:
-- while holding cgroup_mutex
-- while holding the task's alloc_lock (via task_lock())
-- inside an rcu_read_lock() section via rcu_dereference()
-
-3.3 Subsystem API
------------------
-
-Each subsystem should:
-
-- add an entry in linux/cgroup_subsys.h
-- define a cgroup_subsys object called <name>_cgrp_subsys
-
-Each subsystem may export the following methods. The only mandatory
-methods are css_alloc/free. Any others that are null are presumed to
-be successful no-ops.
-
-``struct cgroup_subsys_state *css_alloc(struct cgroup *cgrp)``
-(cgroup_mutex held by caller)
-
-Called to allocate a subsystem state object for a cgroup. The
-subsystem should allocate its subsystem state object for the passed
-cgroup, returning a pointer to the new object on success or a
-ERR_PTR() value. On success, the subsystem pointer should point to
-a structure of type cgroup_subsys_state (typically embedded in a
-larger subsystem-specific object), which will be initialized by the
-cgroup system. Note that this will be called at initialization to
-create the root subsystem state for this subsystem; this case can be
-identified by the passed cgroup object having a NULL parent (since
-it's the root of the hierarchy) and may be an appropriate place for
-initialization code.
-
-``int css_online(struct cgroup *cgrp)``
-(cgroup_mutex held by caller)
-
-Called after @cgrp successfully completed all allocations and made
-visible to cgroup_for_each_child/descendant_*() iterators. The
-subsystem may choose to fail creation by returning -errno. This
-callback can be used to implement reliable state sharing and
-propagation along the hierarchy. See the comment on
-cgroup_for_each_descendant_pre() for details.
-
-``void css_offline(struct cgroup *cgrp);``
-(cgroup_mutex held by caller)
-
-This is the counterpart of css_online() and called iff css_online()
-has succeeded on @cgrp. This signifies the beginning of the end of
-@cgrp. @cgrp is being removed and the subsystem should start dropping
-all references it's holding on @cgrp. When all references are dropped,
-cgroup removal will proceed to the next step - css_free(). After this
-callback, @cgrp should be considered dead to the subsystem.
-
-``void css_free(struct cgroup *cgrp)``
-(cgroup_mutex held by caller)
-
-The cgroup system is about to free @cgrp; the subsystem should free
-its subsystem state object. By the time this method is called, @cgrp
-is completely unused; @cgrp->parent is still valid. (Note - can also
-be called for a newly-created cgroup if an error occurs after this
-subsystem's create() method has been called for the new cgroup).
-
-``int can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)``
-(cgroup_mutex held by caller)
-
-Called prior to moving one or more tasks into a cgroup; if the
-subsystem returns an error, this will abort the attach operation.
-@tset contains the tasks to be attached and is guaranteed to have at
-least one task in it.
-
-If there are multiple tasks in the taskset, then:
-  - it's guaranteed that all are from the same thread group
-  - @tset contains all tasks from the thread group whether or not
-    they're switching cgroups
-  - the first task is the leader
-
-Each @tset entry also contains the task's old cgroup and tasks which
-aren't switching cgroup can be skipped easily using the
-cgroup_taskset_for_each() iterator. Note that this isn't called on a
-fork. If this method returns 0 (success) then this should remain valid
-while the caller holds cgroup_mutex and it is ensured that either
-attach() or cancel_attach() will be called in future.
-
-``void css_reset(struct cgroup_subsys_state *css)``
-(cgroup_mutex held by caller)
-
-An optional operation which should restore @css's configuration to the
-initial state.  This is currently only used on the unified hierarchy
-when a subsystem is disabled on a cgroup through
-"cgroup.subtree_control" but should remain enabled because other
-subsystems depend on it.  cgroup core makes such a css invisible by
-removing the associated interface files and invokes this callback so
-that the hidden subsystem can return to the initial neutral state.
-This prevents unexpected resource control from a hidden css and
-ensures that the configuration is in the initial state when it is made
-visible again later.
-
-``void cancel_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)``
-(cgroup_mutex held by caller)
-
-Called when a task attach operation has failed after can_attach() has succeeded.
-A subsystem whose can_attach() has some side-effects should provide this
-function, so that the subsystem can implement a rollback. If not, not necessary.
-This will be called only about subsystems whose can_attach() operation have
-succeeded. The parameters are identical to can_attach().
-
-``void attach(struct cgroup *cgrp, struct cgroup_taskset *tset)``
-(cgroup_mutex held by caller)
-
-Called after the task has been attached to the cgroup, to allow any
-post-attachment activity that requires memory allocations or blocking.
-The parameters are identical to can_attach().
-
-``void fork(struct task_struct *task)``
-
-Called when a task is forked into a cgroup.
-
-``void exit(struct task_struct *task)``
-
-Called during task exit.
-
-``void free(struct task_struct *task)``
-
-Called when the task_struct is freed.
-
-``void bind(struct cgroup *root)``
-(cgroup_mutex held by caller)
-
-Called when a cgroup subsystem is rebound to a different hierarchy
-and root cgroup. Currently this will only involve movement between
-the default hierarchy (which never has sub-cgroups) and a hierarchy
-that is being created/destroyed (and hence has no sub-cgroups).
-
-4. Extended attribute usage
-===========================
-
-cgroup filesystem supports certain types of extended attributes in its
-directories and files.  The current supported types are:
-
-       - Trusted (XATTR_TRUSTED)
-       - Security (XATTR_SECURITY)
-
-Both require CAP_SYS_ADMIN capability to set.
-
-Like in tmpfs, the extended attributes in cgroup filesystem are stored
-using kernel memory and it's advised to keep the usage at minimum.  This
-is the reason why user defined extended attributes are not supported, since
-any user can do it and there's no limit in the value size.
-
-The current known users for this feature are SELinux to limit cgroup usage
-in containers and systemd for assorted meta data like main PID in a cgroup
-(systemd creates a cgroup per service).
-
-5. Questions
-============
-
-::
-
-  Q: what's up with this '/bin/echo' ?
-  A: bash's builtin 'echo' command does not check calls to write() against
-     errors. If you use it in the cgroup file system, you won't be
-     able to tell whether a command succeeded or failed.
-
-  Q: When I attach processes, only the first of the line gets really attached !
-  A: We can only return one error code per call to write(). So you should also
-     put only ONE PID.
diff --git a/Documentation/cgroup-v1/cpusets.rst b/Documentation/cgroup-v1/cpusets.rst
deleted file mode 100644 (file)
index b6a42cd..0000000
+++ /dev/null
@@ -1,866 +0,0 @@
-=======
-CPUSETS
-=======
-
-Copyright (C) 2004 BULL SA.
-
-Written by Simon.Derr@bull.net
-
-- Portions Copyright (c) 2004-2006 Silicon Graphics, Inc.
-- Modified by Paul Jackson <pj@sgi.com>
-- Modified by Christoph Lameter <cl@linux.com>
-- Modified by Paul Menage <menage@google.com>
-- Modified by Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
-
-.. CONTENTS:
-
-   1. Cpusets
-     1.1 What are cpusets ?
-     1.2 Why are cpusets needed ?
-     1.3 How are cpusets implemented ?
-     1.4 What are exclusive cpusets ?
-     1.5 What is memory_pressure ?
-     1.6 What is memory spread ?
-     1.7 What is sched_load_balance ?
-     1.8 What is sched_relax_domain_level ?
-     1.9 How do I use cpusets ?
-   2. Usage Examples and Syntax
-     2.1 Basic Usage
-     2.2 Adding/removing cpus
-     2.3 Setting flags
-     2.4 Attaching processes
-   3. Questions
-   4. Contact
-
-1. Cpusets
-==========
-
-1.1 What are cpusets ?
-----------------------
-
-Cpusets provide a mechanism for assigning a set of CPUs and Memory
-Nodes to a set of tasks.   In this document "Memory Node" refers to
-an on-line node that contains memory.
-
-Cpusets constrain the CPU and Memory placement of tasks to only
-the resources within a task's current cpuset.  They form a nested
-hierarchy visible in a virtual file system.  These are the essential
-hooks, beyond what is already present, required to manage dynamic
-job placement on large systems.
-
-Cpusets use the generic cgroup subsystem described in
-Documentation/cgroup-v1/cgroups.rst.
-
-Requests by a task, using the sched_setaffinity(2) system call to
-include CPUs in its CPU affinity mask, and using the mbind(2) and
-set_mempolicy(2) system calls to include Memory Nodes in its memory
-policy, are both filtered through that task's cpuset, filtering out any
-CPUs or Memory Nodes not in that cpuset.  The scheduler will not
-schedule a task on a CPU that is not allowed in its cpus_allowed
-vector, and the kernel page allocator will not allocate a page on a
-node that is not allowed in the requesting task's mems_allowed vector.
-
-User level code may create and destroy cpusets by name in the cgroup
-virtual file system, manage the attributes and permissions of these
-cpusets and which CPUs and Memory Nodes are assigned to each cpuset,
-specify and query to which cpuset a task is assigned, and list the
-task pids assigned to a cpuset.
-
-
-1.2 Why are cpusets needed ?
-----------------------------
-
-The management of large computer systems, with many processors (CPUs),
-complex memory cache hierarchies and multiple Memory Nodes having
-non-uniform access times (NUMA) presents additional challenges for
-the efficient scheduling and memory placement of processes.
-
-Frequently more modest sized systems can be operated with adequate
-efficiency just by letting the operating system automatically share
-the available CPU and Memory resources amongst the requesting tasks.
-
-But larger systems, which benefit more from careful processor and
-memory placement to reduce memory access times and contention,
-and which typically represent a larger investment for the customer,
-can benefit from explicitly placing jobs on properly sized subsets of
-the system.
-
-This can be especially valuable on:
-
-    * Web Servers running multiple instances of the same web application,
-    * Servers running different applications (for instance, a web server
-      and a database), or
-    * NUMA systems running large HPC applications with demanding
-      performance characteristics.
-
-These subsets, or "soft partitions" must be able to be dynamically
-adjusted, as the job mix changes, without impacting other concurrently
-executing jobs. The location of the running jobs pages may also be moved
-when the memory locations are changed.
-
-The kernel cpuset patch provides the minimum essential kernel
-mechanisms required to efficiently implement such subsets.  It
-leverages existing CPU and Memory Placement facilities in the Linux
-kernel to avoid any additional impact on the critical scheduler or
-memory allocator code.
-
-
-1.3 How are cpusets implemented ?
----------------------------------
-
-Cpusets provide a Linux kernel mechanism to constrain which CPUs and
-Memory Nodes are used by a process or set of processes.
-
-The Linux kernel already has a pair of mechanisms to specify on which
-CPUs a task may be scheduled (sched_setaffinity) and on which Memory
-Nodes it may obtain memory (mbind, set_mempolicy).
-
-Cpusets extends these two mechanisms as follows:
-
- - Cpusets are sets of allowed CPUs and Memory Nodes, known to the
-   kernel.
- - Each task in the system is attached to a cpuset, via a pointer
-   in the task structure to a reference counted cgroup structure.
- - Calls to sched_setaffinity are filtered to just those CPUs
-   allowed in that task's cpuset.
- - Calls to mbind and set_mempolicy are filtered to just
-   those Memory Nodes allowed in that task's cpuset.
- - The root cpuset contains all the systems CPUs and Memory
-   Nodes.
- - For any cpuset, one can define child cpusets containing a subset
-   of the parents CPU and Memory Node resources.
- - The hierarchy of cpusets can be mounted at /dev/cpuset, for
-   browsing and manipulation from user space.
- - A cpuset may be marked exclusive, which ensures that no other
-   cpuset (except direct ancestors and descendants) may contain
-   any overlapping CPUs or Memory Nodes.
- - You can list all the tasks (by pid) attached to any cpuset.
-
-The implementation of cpusets requires a few, simple hooks
-into the rest of the kernel, none in performance critical paths:
-
- - in init/main.c, to initialize the root cpuset at system boot.
- - in fork and exit, to attach and detach a task from its cpuset.
- - in sched_setaffinity, to mask the requested CPUs by what's
-   allowed in that task's cpuset.
- - in sched.c migrate_live_tasks(), to keep migrating tasks within
-   the CPUs allowed by their cpuset, if possible.
- - in the mbind and set_mempolicy system calls, to mask the requested
-   Memory Nodes by what's allowed in that task's cpuset.
- - in page_alloc.c, to restrict memory to allowed nodes.
- - in vmscan.c, to restrict page recovery to the current cpuset.
-
-You should mount the "cgroup" filesystem type in order to enable
-browsing and modifying the cpusets presently known to the kernel.  No
-new system calls are added for cpusets - all support for querying and
-modifying cpusets is via this cpuset file system.
-
-The /proc/<pid>/status file for each task has four added lines,
-displaying the task's cpus_allowed (on which CPUs it may be scheduled)
-and mems_allowed (on which Memory Nodes it may obtain memory),
-in the two formats seen in the following example::
-
-  Cpus_allowed:   ffffffff,ffffffff,ffffffff,ffffffff
-  Cpus_allowed_list:      0-127
-  Mems_allowed:   ffffffff,ffffffff
-  Mems_allowed_list:      0-63
-
-Each cpuset is represented by a directory in the cgroup file system
-containing (on top of the standard cgroup files) the following
-files describing that cpuset:
-
- - cpuset.cpus: list of CPUs in that cpuset
- - cpuset.mems: list of Memory Nodes in that cpuset
- - cpuset.memory_migrate flag: if set, move pages to cpusets nodes
- - cpuset.cpu_exclusive flag: is cpu placement exclusive?
- - cpuset.mem_exclusive flag: is memory placement exclusive?
- - cpuset.mem_hardwall flag:  is memory allocation hardwalled
- - cpuset.memory_pressure: measure of how much paging pressure in cpuset
- - cpuset.memory_spread_page flag: if set, spread page cache evenly on allowed nodes
- - cpuset.memory_spread_slab flag: if set, spread slab cache evenly on allowed nodes
- - cpuset.sched_load_balance flag: if set, load balance within CPUs on that cpuset
- - cpuset.sched_relax_domain_level: the searching range when migrating tasks
-
-In addition, only the root cpuset has the following file:
-
- - cpuset.memory_pressure_enabled flag: compute memory_pressure?
-
-New cpusets are created using the mkdir system call or shell
-command.  The properties of a cpuset, such as its flags, allowed
-CPUs and Memory Nodes, and attached tasks, are modified by writing
-to the appropriate file in that cpusets directory, as listed above.
-
-The named hierarchical structure of nested cpusets allows partitioning
-a large system into nested, dynamically changeable, "soft-partitions".
-
-The attachment of each task, automatically inherited at fork by any
-children of that task, to a cpuset allows organizing the work load
-on a system into related sets of tasks such that each set is constrained
-to using the CPUs and Memory Nodes of a particular cpuset.  A task
-may be re-attached to any other cpuset, if allowed by the permissions
-on the necessary cpuset file system directories.
-
-Such management of a system "in the large" integrates smoothly with
-the detailed placement done on individual tasks and memory regions
-using the sched_setaffinity, mbind and set_mempolicy system calls.
-
-The following rules apply to each cpuset:
-
- - Its CPUs and Memory Nodes must be a subset of its parents.
- - It can't be marked exclusive unless its parent is.
- - If its cpu or memory is exclusive, they may not overlap any sibling.
-
-These rules, and the natural hierarchy of cpusets, enable efficient
-enforcement of the exclusive guarantee, without having to scan all
-cpusets every time any of them change to ensure nothing overlaps a
-exclusive cpuset.  Also, the use of a Linux virtual file system (vfs)
-to represent the cpuset hierarchy provides for a familiar permission
-and name space for cpusets, with a minimum of additional kernel code.
-
-The cpus and mems files in the root (top_cpuset) cpuset are
-read-only.  The cpus file automatically tracks the value of
-cpu_online_mask using a CPU hotplug notifier, and the mems file
-automatically tracks the value of node_states[N_MEMORY]--i.e.,
-nodes with memory--using the cpuset_track_online_nodes() hook.
-
-
-1.4 What are exclusive cpusets ?
---------------------------------
-
-If a cpuset is cpu or mem exclusive, no other cpuset, other than
-a direct ancestor or descendant, may share any of the same CPUs or
-Memory Nodes.
-
-A cpuset that is cpuset.mem_exclusive *or* cpuset.mem_hardwall is "hardwalled",
-i.e. it restricts kernel allocations for page, buffer and other data
-commonly shared by the kernel across multiple users.  All cpusets,
-whether hardwalled or not, restrict allocations of memory for user
-space.  This enables configuring a system so that several independent
-jobs can share common kernel data, such as file system pages, while
-isolating each job's user allocation in its own cpuset.  To do this,
-construct a large mem_exclusive cpuset to hold all the jobs, and
-construct child, non-mem_exclusive cpusets for each individual job.
-Only a small amount of typical kernel memory, such as requests from
-interrupt handlers, is allowed to be taken outside even a
-mem_exclusive cpuset.
-
-
-1.5 What is memory_pressure ?
------------------------------
-The memory_pressure of a cpuset provides a simple per-cpuset metric
-of the rate that the tasks in a cpuset are attempting to free up in
-use memory on the nodes of the cpuset to satisfy additional memory
-requests.
-
-This enables batch managers monitoring jobs running in dedicated
-cpusets to efficiently detect what level of memory pressure that job
-is causing.
-
-This is useful both on tightly managed systems running a wide mix of
-submitted jobs, which may choose to terminate or re-prioritize jobs that
-are trying to use more memory than allowed on the nodes assigned to them,
-and with tightly coupled, long running, massively parallel scientific
-computing jobs that will dramatically fail to meet required performance
-goals if they start to use more memory than allowed to them.
-
-This mechanism provides a very economical way for the batch manager
-to monitor a cpuset for signs of memory pressure.  It's up to the
-batch manager or other user code to decide what to do about it and
-take action.
-
-==>
-    Unless this feature is enabled by writing "1" to the special file
-    /dev/cpuset/memory_pressure_enabled, the hook in the rebalance
-    code of __alloc_pages() for this metric reduces to simply noticing
-    that the cpuset_memory_pressure_enabled flag is zero.  So only
-    systems that enable this feature will compute the metric.
-
-Why a per-cpuset, running average:
-
-    Because this meter is per-cpuset, rather than per-task or mm,
-    the system load imposed by a batch scheduler monitoring this
-    metric is sharply reduced on large systems, because a scan of
-    the tasklist can be avoided on each set of queries.
-
-    Because this meter is a running average, instead of an accumulating
-    counter, a batch scheduler can detect memory pressure with a
-    single read, instead of having to read and accumulate results
-    for a period of time.
-
-    Because this meter is per-cpuset rather than per-task or mm,
-    the batch scheduler can obtain the key information, memory
-    pressure in a cpuset, with a single read, rather than having to
-    query and accumulate results over all the (dynamically changing)
-    set of tasks in the cpuset.
-
-A per-cpuset simple digital filter (requires a spinlock and 3 words
-of data per-cpuset) is kept, and updated by any task attached to that
-cpuset, if it enters the synchronous (direct) page reclaim code.
-
-A per-cpuset file provides an integer number representing the recent
-(half-life of 10 seconds) rate of direct page reclaims caused by
-the tasks in the cpuset, in units of reclaims attempted per second,
-times 1000.
-
-
-1.6 What is memory spread ?
----------------------------
-There are two boolean flag files per cpuset that control where the
-kernel allocates pages for the file system buffers and related in
-kernel data structures.  They are called 'cpuset.memory_spread_page' and
-'cpuset.memory_spread_slab'.
-
-If the per-cpuset boolean flag file 'cpuset.memory_spread_page' is set, then
-the kernel will spread the file system buffers (page cache) evenly
-over all the nodes that the faulting task is allowed to use, instead
-of preferring to put those pages on the node where the task is running.
-
-If the per-cpuset boolean flag file 'cpuset.memory_spread_slab' is set,
-then the kernel will spread some file system related slab caches,
-such as for inodes and dentries evenly over all the nodes that the
-faulting task is allowed to use, instead of preferring to put those
-pages on the node where the task is running.
-
-The setting of these flags does not affect anonymous data segment or
-stack segment pages of a task.
-
-By default, both kinds of memory spreading are off, and memory
-pages are allocated on the node local to where the task is running,
-except perhaps as modified by the task's NUMA mempolicy or cpuset
-configuration, so long as sufficient free memory pages are available.
-
-When new cpusets are created, they inherit the memory spread settings
-of their parent.
-
-Setting memory spreading causes allocations for the affected page
-or slab caches to ignore the task's NUMA mempolicy and be spread
-instead.    Tasks using mbind() or set_mempolicy() calls to set NUMA
-mempolicies will not notice any change in these calls as a result of
-their containing task's memory spread settings.  If memory spreading
-is turned off, then the currently specified NUMA mempolicy once again
-applies to memory page allocations.
-
-Both 'cpuset.memory_spread_page' and 'cpuset.memory_spread_slab' are boolean flag
-files.  By default they contain "0", meaning that the feature is off
-for that cpuset.  If a "1" is written to that file, then that turns
-the named feature on.
-
-The implementation is simple.
-
-Setting the flag 'cpuset.memory_spread_page' turns on a per-process flag
-PFA_SPREAD_PAGE for each task that is in that cpuset or subsequently
-joins that cpuset.  The page allocation calls for the page cache
-is modified to perform an inline check for this PFA_SPREAD_PAGE task
-flag, and if set, a call to a new routine cpuset_mem_spread_node()
-returns the node to prefer for the allocation.
-
-Similarly, setting 'cpuset.memory_spread_slab' turns on the flag
-PFA_SPREAD_SLAB, and appropriately marked slab caches will allocate
-pages from the node returned by cpuset_mem_spread_node().
-
-The cpuset_mem_spread_node() routine is also simple.  It uses the
-value of a per-task rotor cpuset_mem_spread_rotor to select the next
-node in the current task's mems_allowed to prefer for the allocation.
-
-This memory placement policy is also known (in other contexts) as
-round-robin or interleave.
-
-This policy can provide substantial improvements for jobs that need
-to place thread local data on the corresponding node, but that need
-to access large file system data sets that need to be spread across
-the several nodes in the jobs cpuset in order to fit.  Without this
-policy, especially for jobs that might have one thread reading in the
-data set, the memory allocation across the nodes in the jobs cpuset
-can become very uneven.
-
-1.7 What is sched_load_balance ?
---------------------------------
-
-The kernel scheduler (kernel/sched/core.c) automatically load balances
-tasks.  If one CPU is underutilized, kernel code running on that
-CPU will look for tasks on other more overloaded CPUs and move those
-tasks to itself, within the constraints of such placement mechanisms
-as cpusets and sched_setaffinity.
-
-The algorithmic cost of load balancing and its impact on key shared
-kernel data structures such as the task list increases more than
-linearly with the number of CPUs being balanced.  So the scheduler
-has support to partition the systems CPUs into a number of sched
-domains such that it only load balances within each sched domain.
-Each sched domain covers some subset of the CPUs in the system;
-no two sched domains overlap; some CPUs might not be in any sched
-domain and hence won't be load balanced.
-
-Put simply, it costs less to balance between two smaller sched domains
-than one big one, but doing so means that overloads in one of the
-two domains won't be load balanced to the other one.
-
-By default, there is one sched domain covering all CPUs, including those
-marked isolated using the kernel boot time "isolcpus=" argument. However,
-the isolated CPUs will not participate in load balancing, and will not
-have tasks running on them unless explicitly assigned.
-
-This default load balancing across all CPUs is not well suited for
-the following two situations:
-
- 1) On large systems, load balancing across many CPUs is expensive.
-    If the system is managed using cpusets to place independent jobs
-    on separate sets of CPUs, full load balancing is unnecessary.
- 2) Systems supporting realtime on some CPUs need to minimize
-    system overhead on those CPUs, including avoiding task load
-    balancing if that is not needed.
-
-When the per-cpuset flag "cpuset.sched_load_balance" is enabled (the default
-setting), it requests that all the CPUs in that cpusets allowed 'cpuset.cpus'
-be contained in a single sched domain, ensuring that load balancing
-can move a task (not otherwised pinned, as by sched_setaffinity)
-from any CPU in that cpuset to any other.
-
-When the per-cpuset flag "cpuset.sched_load_balance" is disabled, then the
-scheduler will avoid load balancing across the CPUs in that cpuset,
---except-- in so far as is necessary because some overlapping cpuset
-has "sched_load_balance" enabled.
-
-So, for example, if the top cpuset has the flag "cpuset.sched_load_balance"
-enabled, then the scheduler will have one sched domain covering all
-CPUs, and the setting of the "cpuset.sched_load_balance" flag in any other
-cpusets won't matter, as we're already fully load balancing.
-
-Therefore in the above two situations, the top cpuset flag
-"cpuset.sched_load_balance" should be disabled, and only some of the smaller,
-child cpusets have this flag enabled.
-
-When doing this, you don't usually want to leave any unpinned tasks in
-the top cpuset that might use non-trivial amounts of CPU, as such tasks
-may be artificially constrained to some subset of CPUs, depending on
-the particulars of this flag setting in descendant cpusets.  Even if
-such a task could use spare CPU cycles in some other CPUs, the kernel
-scheduler might not consider the possibility of load balancing that
-task to that underused CPU.
-
-Of course, tasks pinned to a particular CPU can be left in a cpuset
-that disables "cpuset.sched_load_balance" as those tasks aren't going anywhere
-else anyway.
-
-There is an impedance mismatch here, between cpusets and sched domains.
-Cpusets are hierarchical and nest.  Sched domains are flat; they don't
-overlap and each CPU is in at most one sched domain.
-
-It is necessary for sched domains to be flat because load balancing
-across partially overlapping sets of CPUs would risk unstable dynamics
-that would be beyond our understanding.  So if each of two partially
-overlapping cpusets enables the flag 'cpuset.sched_load_balance', then we
-form a single sched domain that is a superset of both.  We won't move
-a task to a CPU outside its cpuset, but the scheduler load balancing
-code might waste some compute cycles considering that possibility.
-
-This mismatch is why there is not a simple one-to-one relation
-between which cpusets have the flag "cpuset.sched_load_balance" enabled,
-and the sched domain configuration.  If a cpuset enables the flag, it
-will get balancing across all its CPUs, but if it disables the flag,
-it will only be assured of no load balancing if no other overlapping
-cpuset enables the flag.
-
-If two cpusets have partially overlapping 'cpuset.cpus' allowed, and only
-one of them has this flag enabled, then the other may find its
-tasks only partially load balanced, just on the overlapping CPUs.
-This is just the general case of the top_cpuset example given a few
-paragraphs above.  In the general case, as in the top cpuset case,
-don't leave tasks that might use non-trivial amounts of CPU in
-such partially load balanced cpusets, as they may be artificially
-constrained to some subset of the CPUs allowed to them, for lack of
-load balancing to the other CPUs.
-
-CPUs in "cpuset.isolcpus" were excluded from load balancing by the
-isolcpus= kernel boot option, and will never be load balanced regardless
-of the value of "cpuset.sched_load_balance" in any cpuset.
-
-1.7.1 sched_load_balance implementation details.
-------------------------------------------------
-
-The per-cpuset flag 'cpuset.sched_load_balance' defaults to enabled (contrary
-to most cpuset flags.)  When enabled for a cpuset, the kernel will
-ensure that it can load balance across all the CPUs in that cpuset
-(makes sure that all the CPUs in the cpus_allowed of that cpuset are
-in the same sched domain.)
-
-If two overlapping cpusets both have 'cpuset.sched_load_balance' enabled,
-then they will be (must be) both in the same sched domain.
-
-If, as is the default, the top cpuset has 'cpuset.sched_load_balance' enabled,
-then by the above that means there is a single sched domain covering
-the whole system, regardless of any other cpuset settings.
-
-The kernel commits to user space that it will avoid load balancing
-where it can.  It will pick as fine a granularity partition of sched
-domains as it can while still providing load balancing for any set
-of CPUs allowed to a cpuset having 'cpuset.sched_load_balance' enabled.
-
-The internal kernel cpuset to scheduler interface passes from the
-cpuset code to the scheduler code a partition of the load balanced
-CPUs in the system. This partition is a set of subsets (represented
-as an array of struct cpumask) of CPUs, pairwise disjoint, that cover
-all the CPUs that must be load balanced.
-
-The cpuset code builds a new such partition and passes it to the
-scheduler sched domain setup code, to have the sched domains rebuilt
-as necessary, whenever:
-
- - the 'cpuset.sched_load_balance' flag of a cpuset with non-empty CPUs changes,
- - or CPUs come or go from a cpuset with this flag enabled,
- - or 'cpuset.sched_relax_domain_level' value of a cpuset with non-empty CPUs
-   and with this flag enabled changes,
- - or a cpuset with non-empty CPUs and with this flag enabled is removed,
- - or a cpu is offlined/onlined.
-
-This partition exactly defines what sched domains the scheduler should
-setup - one sched domain for each element (struct cpumask) in the
-partition.
-
-The scheduler remembers the currently active sched domain partitions.
-When the scheduler routine partition_sched_domains() is invoked from
-the cpuset code to update these sched domains, it compares the new
-partition requested with the current, and updates its sched domains,
-removing the old and adding the new, for each change.
-
-
-1.8 What is sched_relax_domain_level ?
---------------------------------------
-
-In sched domain, the scheduler migrates tasks in 2 ways; periodic load
-balance on tick, and at time of some schedule events.
-
-When a task is woken up, scheduler try to move the task on idle CPU.
-For example, if a task A running on CPU X activates another task B
-on the same CPU X, and if CPU Y is X's sibling and performing idle,
-then scheduler migrate task B to CPU Y so that task B can start on
-CPU Y without waiting task A on CPU X.
-
-And if a CPU run out of tasks in its runqueue, the CPU try to pull
-extra tasks from other busy CPUs to help them before it is going to
-be idle.
-
-Of course it takes some searching cost to find movable tasks and/or
-idle CPUs, the scheduler might not search all CPUs in the domain
-every time.  In fact, in some architectures, the searching ranges on
-events are limited in the same socket or node where the CPU locates,
-while the load balance on tick searches all.
-
-For example, assume CPU Z is relatively far from CPU X.  Even if CPU Z
-is idle while CPU X and the siblings are busy, scheduler can't migrate
-woken task B from X to Z since it is out of its searching range.
-As the result, task B on CPU X need to wait task A or wait load balance
-on the next tick.  For some applications in special situation, waiting
-1 tick may be too long.
-
-The 'cpuset.sched_relax_domain_level' file allows you to request changing
-this searching range as you like.  This file takes int value which
-indicates size of searching range in levels ideally as follows,
-otherwise initial value -1 that indicates the cpuset has no request.
-
-====== ===========================================================
-  -1   no request. use system default or follow request of others.
-   0   no search.
-   1   search siblings (hyperthreads in a core).
-   2   search cores in a package.
-   3   search cpus in a node [= system wide on non-NUMA system]
-   4   search nodes in a chunk of node [on NUMA system]
-   5   search system wide [on NUMA system]
-====== ===========================================================
-
-The system default is architecture dependent.  The system default
-can be changed using the relax_domain_level= boot parameter.
-
-This file is per-cpuset and affect the sched domain where the cpuset
-belongs to.  Therefore if the flag 'cpuset.sched_load_balance' of a cpuset
-is disabled, then 'cpuset.sched_relax_domain_level' have no effect since
-there is no sched domain belonging the cpuset.
-
-If multiple cpusets are overlapping and hence they form a single sched
-domain, the largest value among those is used.  Be careful, if one
-requests 0 and others are -1 then 0 is used.
-
-Note that modifying this file will have both good and bad effects,
-and whether it is acceptable or not depends on your situation.
-Don't modify this file if you are not sure.
-
-If your situation is:
-
- - The migration costs between each cpu can be assumed considerably
-   small(for you) due to your special application's behavior or
-   special hardware support for CPU cache etc.
- - The searching cost doesn't have impact(for you) or you can make
-   the searching cost enough small by managing cpuset to compact etc.
- - The latency is required even it sacrifices cache hit rate etc.
-   then increasing 'sched_relax_domain_level' would benefit you.
-
-
-1.9 How do I use cpusets ?
---------------------------
-
-In order to minimize the impact of cpusets on critical kernel
-code, such as the scheduler, and due to the fact that the kernel
-does not support one task updating the memory placement of another
-task directly, the impact on a task of changing its cpuset CPU
-or Memory Node placement, or of changing to which cpuset a task
-is attached, is subtle.
-
-If a cpuset has its Memory Nodes modified, then for each task attached
-to that cpuset, the next time that the kernel attempts to allocate
-a page of memory for that task, the kernel will notice the change
-in the task's cpuset, and update its per-task memory placement to
-remain within the new cpusets memory placement.  If the task was using
-mempolicy MPOL_BIND, and the nodes to which it was bound overlap with
-its new cpuset, then the task will continue to use whatever subset
-of MPOL_BIND nodes are still allowed in the new cpuset.  If the task
-was using MPOL_BIND and now none of its MPOL_BIND nodes are allowed
-in the new cpuset, then the task will be essentially treated as if it
-was MPOL_BIND bound to the new cpuset (even though its NUMA placement,
-as queried by get_mempolicy(), doesn't change).  If a task is moved
-from one cpuset to another, then the kernel will adjust the task's
-memory placement, as above, the next time that the kernel attempts
-to allocate a page of memory for that task.
-
-If a cpuset has its 'cpuset.cpus' modified, then each task in that cpuset
-will have its allowed CPU placement changed immediately.  Similarly,
-if a task's pid is written to another cpuset's 'tasks' file, then its
-allowed CPU placement is changed immediately.  If such a task had been
-bound to some subset of its cpuset using the sched_setaffinity() call,
-the task will be allowed to run on any CPU allowed in its new cpuset,
-negating the effect of the prior sched_setaffinity() call.
-
-In summary, the memory placement of a task whose cpuset is changed is
-updated by the kernel, on the next allocation of a page for that task,
-and the processor placement is updated immediately.
-
-Normally, once a page is allocated (given a physical page
-of main memory) then that page stays on whatever node it
-was allocated, so long as it remains allocated, even if the
-cpusets memory placement policy 'cpuset.mems' subsequently changes.
-If the cpuset flag file 'cpuset.memory_migrate' is set true, then when
-tasks are attached to that cpuset, any pages that task had
-allocated to it on nodes in its previous cpuset are migrated
-to the task's new cpuset. The relative placement of the page within
-the cpuset is preserved during these migration operations if possible.
-For example if the page was on the second valid node of the prior cpuset
-then the page will be placed on the second valid node of the new cpuset.
-
-Also if 'cpuset.memory_migrate' is set true, then if that cpuset's
-'cpuset.mems' file is modified, pages allocated to tasks in that
-cpuset, that were on nodes in the previous setting of 'cpuset.mems',
-will be moved to nodes in the new setting of 'mems.'
-Pages that were not in the task's prior cpuset, or in the cpuset's
-prior 'cpuset.mems' setting, will not be moved.
-
-There is an exception to the above.  If hotplug functionality is used
-to remove all the CPUs that are currently assigned to a cpuset,
-then all the tasks in that cpuset will be moved to the nearest ancestor
-with non-empty cpus.  But the moving of some (or all) tasks might fail if
-cpuset is bound with another cgroup subsystem which has some restrictions
-on task attaching.  In this failing case, those tasks will stay
-in the original cpuset, and the kernel will automatically update
-their cpus_allowed to allow all online CPUs.  When memory hotplug
-functionality for removing Memory Nodes is available, a similar exception
-is expected to apply there as well.  In general, the kernel prefers to
-violate cpuset placement, over starving a task that has had all
-its allowed CPUs or Memory Nodes taken offline.
-
-There is a second exception to the above.  GFP_ATOMIC requests are
-kernel internal allocations that must be satisfied, immediately.
-The kernel may drop some request, in rare cases even panic, if a
-GFP_ATOMIC alloc fails.  If the request cannot be satisfied within
-the current task's cpuset, then we relax the cpuset, and look for
-memory anywhere we can find it.  It's better to violate the cpuset
-than stress the kernel.
-
-To start a new job that is to be contained within a cpuset, the steps are:
-
- 1) mkdir /sys/fs/cgroup/cpuset
- 2) mount -t cgroup -ocpuset cpuset /sys/fs/cgroup/cpuset
- 3) Create the new cpuset by doing mkdir's and write's (or echo's) in
-    the /sys/fs/cgroup/cpuset virtual file system.
- 4) Start a task that will be the "founding father" of the new job.
- 5) Attach that task to the new cpuset by writing its pid to the
-    /sys/fs/cgroup/cpuset tasks file for that cpuset.
- 6) fork, exec or clone the job tasks from this founding father task.
-
-For example, the following sequence of commands will setup a cpuset
-named "Charlie", containing just CPUs 2 and 3, and Memory Node 1,
-and then start a subshell 'sh' in that cpuset::
-
-  mount -t cgroup -ocpuset cpuset /sys/fs/cgroup/cpuset
-  cd /sys/fs/cgroup/cpuset
-  mkdir Charlie
-  cd Charlie
-  /bin/echo 2-3 > cpuset.cpus
-  /bin/echo 1 > cpuset.mems
-  /bin/echo $$ > tasks
-  sh
-  # The subshell 'sh' is now running in cpuset Charlie
-  # The next line should display '/Charlie'
-  cat /proc/self/cpuset
-
-There are ways to query or modify cpusets:
-
- - via the cpuset file system directly, using the various cd, mkdir, echo,
-   cat, rmdir commands from the shell, or their equivalent from C.
- - via the C library libcpuset.
- - via the C library libcgroup.
-   (http://sourceforge.net/projects/libcg/)
- - via the python application cset.
-   (http://code.google.com/p/cpuset/)
-
-The sched_setaffinity calls can also be done at the shell prompt using
-SGI's runon or Robert Love's taskset.  The mbind and set_mempolicy
-calls can be done at the shell prompt using the numactl command
-(part of Andi Kleen's numa package).
-
-2. Usage Examples and Syntax
-============================
-
-2.1 Basic Usage
----------------
-
-Creating, modifying, using the cpusets can be done through the cpuset
-virtual filesystem.
-
-To mount it, type:
-# mount -t cgroup -o cpuset cpuset /sys/fs/cgroup/cpuset
-
-Then under /sys/fs/cgroup/cpuset you can find a tree that corresponds to the
-tree of the cpusets in the system. For instance, /sys/fs/cgroup/cpuset
-is the cpuset that holds the whole system.
-
-If you want to create a new cpuset under /sys/fs/cgroup/cpuset::
-
-  # cd /sys/fs/cgroup/cpuset
-  # mkdir my_cpuset
-
-Now you want to do something with this cpuset::
-
-  # cd my_cpuset
-
-In this directory you can find several files::
-
-  # ls
-  cgroup.clone_children  cpuset.memory_pressure
-  cgroup.event_control   cpuset.memory_spread_page
-  cgroup.procs           cpuset.memory_spread_slab
-  cpuset.cpu_exclusive   cpuset.mems
-  cpuset.cpus            cpuset.sched_load_balance
-  cpuset.mem_exclusive   cpuset.sched_relax_domain_level
-  cpuset.mem_hardwall    notify_on_release
-  cpuset.memory_migrate  tasks
-
-Reading them will give you information about the state of this cpuset:
-the CPUs and Memory Nodes it can use, the processes that are using
-it, its properties.  By writing to these files you can manipulate
-the cpuset.
-
-Set some flags::
-
-  # /bin/echo 1 > cpuset.cpu_exclusive
-
-Add some cpus::
-
-  # /bin/echo 0-7 > cpuset.cpus
-
-Add some mems::
-
-  # /bin/echo 0-7 > cpuset.mems
-
-Now attach your shell to this cpuset::
-
-  # /bin/echo $$ > tasks
-
-You can also create cpusets inside your cpuset by using mkdir in this
-directory::
-
-  # mkdir my_sub_cs
-
-To remove a cpuset, just use rmdir::
-
-  # rmdir my_sub_cs
-
-This will fail if the cpuset is in use (has cpusets inside, or has
-processes attached).
-
-Note that for legacy reasons, the "cpuset" filesystem exists as a
-wrapper around the cgroup filesystem.
-
-The command::
-
-  mount -t cpuset X /sys/fs/cgroup/cpuset
-
-is equivalent to::
-
-  mount -t cgroup -ocpuset,noprefix X /sys/fs/cgroup/cpuset
-  echo "/sbin/cpuset_release_agent" > /sys/fs/cgroup/cpuset/release_agent
-
-2.2 Adding/removing cpus
-------------------------
-
-This is the syntax to use when writing in the cpus or mems files
-in cpuset directories::
-
-  # /bin/echo 1-4 > cpuset.cpus                -> set cpus list to cpus 1,2,3,4
-  # /bin/echo 1,2,3,4 > cpuset.cpus    -> set cpus list to cpus 1,2,3,4
-
-To add a CPU to a cpuset, write the new list of CPUs including the
-CPU to be added. To add 6 to the above cpuset::
-
-  # /bin/echo 1-4,6 > cpuset.cpus      -> set cpus list to cpus 1,2,3,4,6
-
-Similarly to remove a CPU from a cpuset, write the new list of CPUs
-without the CPU to be removed.
-
-To remove all the CPUs::
-
-  # /bin/echo "" > cpuset.cpus         -> clear cpus list
-
-2.3 Setting flags
------------------
-
-The syntax is very simple::
-
-  # /bin/echo 1 > cpuset.cpu_exclusive         -> set flag 'cpuset.cpu_exclusive'
-  # /bin/echo 0 > cpuset.cpu_exclusive         -> unset flag 'cpuset.cpu_exclusive'
-
-2.4 Attaching processes
------------------------
-
-::
-
-  # /bin/echo PID > tasks
-
-Note that it is PID, not PIDs. You can only attach ONE task at a time.
-If you have several tasks to attach, you have to do it one after another::
-
-  # /bin/echo PID1 > tasks
-  # /bin/echo PID2 > tasks
-       ...
-  # /bin/echo PIDn > tasks
-
-
-3. Questions
-============
-
-Q:
-   what's up with this '/bin/echo' ?
-
-A:
-   bash's builtin 'echo' command does not check calls to write() against
-   errors. If you use it in the cpuset file system, you won't be
-   able to tell whether a command succeeded or failed.
-
-Q:
-   When I attach processes, only the first of the line gets really attached !
-
-A:
-   We can only return one error code per call to write(). So you should also
-   put only ONE pid.
-
-4. Contact
-==========
-
-Web: http://www.bullopensource.org/cpuset
diff --git a/Documentation/cgroup-v1/index.rst b/Documentation/cgroup-v1/index.rst
deleted file mode 100644 (file)
index fe76d42..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-:orphan:
-
-========================
-Control Groups version 1
-========================
-
-.. toctree::
-    :maxdepth: 1
-
-    cgroups
-
-    blkio-controller
-    cpuacct
-    cpusets
-    devices
-    freezer-subsystem
-    hugetlb
-    memcg_test
-    memory
-    net_cls
-    net_prio
-    pids
-    rdma
-
-.. only::  subproject and html
-
-   Indices
-   =======
-
-   * :ref:`genindex`
diff --git a/Documentation/cgroup-v1/memcg_test.rst b/Documentation/cgroup-v1/memcg_test.rst
deleted file mode 100644 (file)
index 91bd18c..0000000
+++ /dev/null
@@ -1,355 +0,0 @@
-=====================================================
-Memory Resource Controller(Memcg) Implementation Memo
-=====================================================
-
-Last Updated: 2010/2
-
-Base Kernel Version: based on 2.6.33-rc7-mm(candidate for 34).
-
-Because VM is getting complex (one of reasons is memcg...), memcg's behavior
-is complex. This is a document for memcg's internal behavior.
-Please note that implementation details can be changed.
-
-(*) Topics on API should be in Documentation/cgroup-v1/memory.rst)
-
-0. How to record usage ?
-========================
-
-   2 objects are used.
-
-   page_cgroup ....an object per page.
-
-       Allocated at boot or memory hotplug. Freed at memory hot removal.
-
-   swap_cgroup ... an entry per swp_entry.
-
-       Allocated at swapon(). Freed at swapoff().
-
-   The page_cgroup has USED bit and double count against a page_cgroup never
-   occurs. swap_cgroup is used only when a charged page is swapped-out.
-
-1. Charge
-=========
-
-   a page/swp_entry may be charged (usage += PAGE_SIZE) at
-
-       mem_cgroup_try_charge()
-
-2. Uncharge
-===========
-
-  a page/swp_entry may be uncharged (usage -= PAGE_SIZE) by
-
-       mem_cgroup_uncharge()
-         Called when a page's refcount goes down to 0.
-
-       mem_cgroup_uncharge_swap()
-         Called when swp_entry's refcnt goes down to 0. A charge against swap
-         disappears.
-
-3. charge-commit-cancel
-=======================
-
-       Memcg pages are charged in two steps:
-
-               - mem_cgroup_try_charge()
-               - mem_cgroup_commit_charge() or mem_cgroup_cancel_charge()
-
-       At try_charge(), there are no flags to say "this page is charged".
-       at this point, usage += PAGE_SIZE.
-
-       At commit(), the page is associated with the memcg.
-
-       At cancel(), simply usage -= PAGE_SIZE.
-
-Under below explanation, we assume CONFIG_MEM_RES_CTRL_SWAP=y.
-
-4. Anonymous
-============
-
-       Anonymous page is newly allocated at
-                 - page fault into MAP_ANONYMOUS mapping.
-                 - Copy-On-Write.
-
-       4.1 Swap-in.
-       At swap-in, the page is taken from swap-cache. There are 2 cases.
-
-       (a) If the SwapCache is newly allocated and read, it has no charges.
-       (b) If the SwapCache has been mapped by processes, it has been
-           charged already.
-
-       4.2 Swap-out.
-       At swap-out, typical state transition is below.
-
-       (a) add to swap cache. (marked as SwapCache)
-           swp_entry's refcnt += 1.
-       (b) fully unmapped.
-           swp_entry's refcnt += # of ptes.
-       (c) write back to swap.
-       (d) delete from swap cache. (remove from SwapCache)
-           swp_entry's refcnt -= 1.
-
-
-       Finally, at task exit,
-       (e) zap_pte() is called and swp_entry's refcnt -=1 -> 0.
-
-5. Page Cache
-=============
-
-       Page Cache is charged at
-       - add_to_page_cache_locked().
-
-       The logic is very clear. (About migration, see below)
-
-       Note:
-         __remove_from_page_cache() is called by remove_from_page_cache()
-         and __remove_mapping().
-
-6. Shmem(tmpfs) Page Cache
-===========================
-
-       The best way to understand shmem's page state transition is to read
-       mm/shmem.c.
-
-       But brief explanation of the behavior of memcg around shmem will be
-       helpful to understand the logic.
-
-       Shmem's page (just leaf page, not direct/indirect block) can be on
-
-               - radix-tree of shmem's inode.
-               - SwapCache.
-               - Both on radix-tree and SwapCache. This happens at swap-in
-                 and swap-out,
-
-       It's charged when...
-
-       - A new page is added to shmem's radix-tree.
-       - A swp page is read. (move a charge from swap_cgroup to page_cgroup)
-
-7. Page Migration
-=================
-
-       mem_cgroup_migrate()
-
-8. LRU
-======
-        Each memcg has its own private LRU. Now, its handling is under global
-       VM's control (means that it's handled under global pgdat->lru_lock).
-       Almost all routines around memcg's LRU is called by global LRU's
-       list management functions under pgdat->lru_lock.
-
-       A special function is mem_cgroup_isolate_pages(). This scans
-       memcg's private LRU and call __isolate_lru_page() to extract a page
-       from LRU.
-
-       (By __isolate_lru_page(), the page is removed from both of global and
-       private LRU.)
-
-
-9. Typical Tests.
-=================
-
- Tests for racy cases.
-
-9.1 Small limit to memcg.
--------------------------
-
-       When you do test to do racy case, it's good test to set memcg's limit
-       to be very small rather than GB. Many races found in the test under
-       xKB or xxMB limits.
-
-       (Memory behavior under GB and Memory behavior under MB shows very
-       different situation.)
-
-9.2 Shmem
----------
-
-       Historically, memcg's shmem handling was poor and we saw some amount
-       of troubles here. This is because shmem is page-cache but can be
-       SwapCache. Test with shmem/tmpfs is always good test.
-
-9.3 Migration
--------------
-
-       For NUMA, migration is an another special case. To do easy test, cpuset
-       is useful. Following is a sample script to do migration::
-
-               mount -t cgroup -o cpuset none /opt/cpuset
-
-               mkdir /opt/cpuset/01
-               echo 1 > /opt/cpuset/01/cpuset.cpus
-               echo 0 > /opt/cpuset/01/cpuset.mems
-               echo 1 > /opt/cpuset/01/cpuset.memory_migrate
-               mkdir /opt/cpuset/02
-               echo 1 > /opt/cpuset/02/cpuset.cpus
-               echo 1 > /opt/cpuset/02/cpuset.mems
-               echo 1 > /opt/cpuset/02/cpuset.memory_migrate
-
-       In above set, when you moves a task from 01 to 02, page migration to
-       node 0 to node 1 will occur. Following is a script to migrate all
-       under cpuset.::
-
-               --
-               move_task()
-               {
-               for pid in $1
-               do
-                       /bin/echo $pid >$2/tasks 2>/dev/null
-                       echo -n $pid
-                       echo -n " "
-               done
-               echo END
-               }
-
-               G1_TASK=`cat ${G1}/tasks`
-               G2_TASK=`cat ${G2}/tasks`
-               move_task "${G1_TASK}" ${G2} &
-               --
-
-9.4 Memory hotplug
-------------------
-
-       memory hotplug test is one of good test.
-
-       to offline memory, do following::
-
-               # echo offline > /sys/devices/system/memory/memoryXXX/state
-
-       (XXX is the place of memory)
-
-       This is an easy way to test page migration, too.
-
-9.5 mkdir/rmdir
----------------
-
-       When using hierarchy, mkdir/rmdir test should be done.
-       Use tests like the following::
-
-               echo 1 >/opt/cgroup/01/memory/use_hierarchy
-               mkdir /opt/cgroup/01/child_a
-               mkdir /opt/cgroup/01/child_b
-
-               set limit to 01.
-               add limit to 01/child_b
-               run jobs under child_a and child_b
-
-       create/delete following groups at random while jobs are running::
-
-               /opt/cgroup/01/child_a/child_aa
-               /opt/cgroup/01/child_b/child_bb
-               /opt/cgroup/01/child_c
-
-       running new jobs in new group is also good.
-
-9.6 Mount with other subsystems
--------------------------------
-
-       Mounting with other subsystems is a good test because there is a
-       race and lock dependency with other cgroup subsystems.
-
-       example::
-
-               # mount -t cgroup none /cgroup -o cpuset,memory,cpu,devices
-
-       and do task move, mkdir, rmdir etc...under this.
-
-9.7 swapoff
------------
-
-       Besides management of swap is one of complicated parts of memcg,
-       call path of swap-in at swapoff is not same as usual swap-in path..
-       It's worth to be tested explicitly.
-
-       For example, test like following is good:
-
-       (Shell-A)::
-
-               # mount -t cgroup none /cgroup -o memory
-               # mkdir /cgroup/test
-               # echo 40M > /cgroup/test/memory.limit_in_bytes
-               # echo 0 > /cgroup/test/tasks
-
-       Run malloc(100M) program under this. You'll see 60M of swaps.
-
-       (Shell-B)::
-
-               # move all tasks in /cgroup/test to /cgroup
-               # /sbin/swapoff -a
-               # rmdir /cgroup/test
-               # kill malloc task.
-
-       Of course, tmpfs v.s. swapoff test should be tested, too.
-
-9.8 OOM-Killer
---------------
-
-       Out-of-memory caused by memcg's limit will kill tasks under
-       the memcg. When hierarchy is used, a task under hierarchy
-       will be killed by the kernel.
-
-       In this case, panic_on_oom shouldn't be invoked and tasks
-       in other groups shouldn't be killed.
-
-       It's not difficult to cause OOM under memcg as following.
-
-       Case A) when you can swapoff::
-
-               #swapoff -a
-               #echo 50M > /memory.limit_in_bytes
-
-       run 51M of malloc
-
-       Case B) when you use mem+swap limitation::
-
-               #echo 50M > memory.limit_in_bytes
-               #echo 50M > memory.memsw.limit_in_bytes
-
-       run 51M of malloc
-
-9.9 Move charges at task migration
-----------------------------------
-
-       Charges associated with a task can be moved along with task migration.
-
-       (Shell-A)::
-
-               #mkdir /cgroup/A
-               #echo $$ >/cgroup/A/tasks
-
-       run some programs which uses some amount of memory in /cgroup/A.
-
-       (Shell-B)::
-
-               #mkdir /cgroup/B
-               #echo 1 >/cgroup/B/memory.move_charge_at_immigrate
-               #echo "pid of the program running in group A" >/cgroup/B/tasks
-
-       You can see charges have been moved by reading ``*.usage_in_bytes`` or
-       memory.stat of both A and B.
-
-       See 8.2 of Documentation/cgroup-v1/memory.rst to see what value should
-       be written to move_charge_at_immigrate.
-
-9.10 Memory thresholds
-----------------------
-
-       Memory controller implements memory thresholds using cgroups notification
-       API. You can use tools/cgroup/cgroup_event_listener.c to test it.
-
-       (Shell-A) Create cgroup and run event listener::
-
-               # mkdir /cgroup/A
-               # ./cgroup_event_listener /cgroup/A/memory.usage_in_bytes 5M
-
-       (Shell-B) Add task to cgroup and try to allocate and free memory::
-
-               # echo $$ >/cgroup/A/tasks
-               # a="$(dd if=/dev/zero bs=1M count=10)"
-               # a=
-
-       You will see message from cgroup_event_listener every time you cross
-       the thresholds.
-
-       Use /cgroup/A/memory.memsw.usage_in_bytes to test memsw thresholds.
-
-       It's good idea to test root cgroup as well.
diff --git a/Documentation/cma/debugfs.txt b/Documentation/cma/debugfs.txt
deleted file mode 100644 (file)
index 6cef20a..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-The CMA debugfs interface is useful to retrieve basic information out of the
-different CMA areas and to test allocation/release in each of the areas.
-
-Each CMA zone represents a directory under <debugfs>/cma/, indexed by the
-kernel's CMA index. So the first CMA zone would be:
-
-       <debugfs>/cma/cma-0
-
-The structure of the files created under that directory is as follows:
-
- - [RO] base_pfn: The base PFN (Page Frame Number) of the zone.
- - [RO] count: Amount of memory in the CMA area.
- - [RO] order_per_bit: Order of pages represented by one bit.
- - [RO] bitmap: The bitmap of page states in the zone.
- - [WO] alloc: Allocate N pages from that CMA area. For example:
-
-       echo 5 > <debugfs>/cma/cma-2/alloc
-
-would try to allocate 5 pages from the cma-2 area.
-
- - [WO] free: Free N pages from that CMA area, similar to the above.
diff --git a/Documentation/connector/connector.txt b/Documentation/connector/connector.txt
deleted file mode 100644 (file)
index ab7ca89..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-/*****************************************/
-Kernel Connector.
-/*****************************************/
-
-Kernel connector - new netlink based userspace <-> kernel space easy
-to use communication module.
-
-The Connector driver makes it easy to connect various agents using a
-netlink based network.  One must register a callback and an identifier.
-When the driver receives a special netlink message with the appropriate
-identifier, the appropriate callback will be called.
-
-From the userspace point of view it's quite straightforward:
-
-       socket();
-       bind();
-       send();
-       recv();
-
-But if kernelspace wants to use the full power of such connections, the
-driver writer must create special sockets, must know about struct sk_buff
-handling, etc...  The Connector driver allows any kernelspace agents to use
-netlink based networking for inter-process communication in a significantly
-easier way:
-
-int cn_add_callback(struct cb_id *id, char *name, void (*callback) (struct cn_msg *, struct netlink_skb_parms *));
-void cn_netlink_send_multi(struct cn_msg *msg, u16 len, u32 portid, u32 __group, int gfp_mask);
-void cn_netlink_send(struct cn_msg *msg, u32 portid, u32 __group, int gfp_mask);
-
-struct cb_id
-{
-       __u32                   idx;
-       __u32                   val;
-};
-
-idx and val are unique identifiers which must be registered in the
-connector.h header for in-kernel usage.  void (*callback) (void *) is a
-callback function which will be called when a message with above idx.val
-is received by the connector core.  The argument for that function must
-be dereferenced to struct cn_msg *.
-
-struct cn_msg
-{
-       struct cb_id            id;
-
-       __u32                   seq;
-       __u32                   ack;
-
-       __u32                   len;            /* Length of the following data */
-       __u8                    data[0];
-};
-
-/*****************************************/
-Connector interfaces.
-/*****************************************/
-
-int cn_add_callback(struct cb_id *id, char *name, void (*callback) (struct cn_msg *, struct netlink_skb_parms *));
-
- Registers new callback with connector core.
-
- struct cb_id *id              - unique connector's user identifier.
-                                 It must be registered in connector.h for legal in-kernel users.
- char *name                    - connector's callback symbolic name.
- void (*callback) (struct cn..)        - connector's callback.
-                                 cn_msg and the sender's credentials
-
-
-void cn_del_callback(struct cb_id *id);
-
- Unregisters new callback with connector core.
-
- struct cb_id *id              - unique connector's user identifier.
-
-
-int cn_netlink_send_multi(struct cn_msg *msg, u16 len, u32 portid, u32 __groups, int gfp_mask);
-int cn_netlink_send(struct cn_msg *msg, u32 portid, u32 __groups, int gfp_mask);
-
- Sends message to the specified groups.  It can be safely called from
- softirq context, but may silently fail under strong memory pressure.
- If there are no listeners for given group -ESRCH can be returned.
-
- struct cn_msg *               - message header(with attached data).
- u16 len                       - for *_multi multiple cn_msg messages can be sent
- u32 port                      - destination port.
-                                 If non-zero the message will be sent to the
-                                 given port, which should be set to the
-                                 original sender.
- u32 __group                   - destination group.
-                                 If port and __group is zero, then appropriate group will
-                                 be searched through all registered connector users,
-                                 and message will be delivered to the group which was
-                                 created for user with the same ID as in msg.
-                                 If __group is not zero, then message will be delivered
-                                 to the specified group.
- int gfp_mask                  - GFP mask.
-
- Note: When registering new callback user, connector core assigns
- netlink group to the user which is equal to its id.idx.
-
-/*****************************************/
-Protocol description.
-/*****************************************/
-
-The current framework offers a transport layer with fixed headers.  The
-recommended protocol which uses such a header is as following:
-
-msg->seq and msg->ack are used to determine message genealogy.  When
-someone sends a message, they use a locally unique sequence and random
-acknowledge number.  The sequence number may be copied into
-nlmsghdr->nlmsg_seq too.
-
-The sequence number is incremented with each message sent.
-
-If you expect a reply to the message, then the sequence number in the
-received message MUST be the same as in the original message, and the
-acknowledge number MUST be the same + 1.
-
-If we receive a message and its sequence number is not equal to one we
-are expecting, then it is a new message.  If we receive a message and
-its sequence number is the same as one we are expecting, but its
-acknowledge is not equal to the sequence number in the original
-message + 1, then it is a new message.
-
-Obviously, the protocol header contains the above id.
-
-The connector allows event notification in the following form: kernel
-driver or userspace process can ask connector to notify it when
-selected ids will be turned on or off (registered or unregistered its
-callback).  It is done by sending a special command to the connector
-driver (it also registers itself with id={-1, -1}).
-
-As example of this usage can be found in the cn_test.c module which
-uses the connector to request notification and to send messages.
-
-/*****************************************/
-Reliability.
-/*****************************************/
-
-Netlink itself is not a reliable protocol.  That means that messages can
-be lost due to memory pressure or process' receiving queue overflowed,
-so caller is warned that it must be prepared.  That is why the struct
-cn_msg [main connector's message header] contains u32 seq and u32 ack
-fields.
-
-/*****************************************/
-Userspace usage.
-/*****************************************/
-
-2.6.14 has a new netlink socket implementation, which by default does not
-allow people to send data to netlink groups other than 1.
-So, if you wish to use a netlink socket (for example using connector)
-with a different group number, the userspace application must subscribe to
-that group first.  It can be achieved by the following pseudocode:
-
-s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
-
-l_local.nl_family = AF_NETLINK;
-l_local.nl_groups = 12345;
-l_local.nl_pid = 0;
-
-if (bind(s, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)) == -1) {
-       perror("bind");
-       close(s);
-       return -1;
-}
-
-{
-       int on = l_local.nl_groups;
-       setsockopt(s, 270, 1, &on, sizeof(on));
-}
-
-Where 270 above is SOL_NETLINK, and 1 is a NETLINK_ADD_MEMBERSHIP socket
-option.  To drop a multicast subscription, one should call the above socket
-option with the NETLINK_DROP_MEMBERSHIP parameter which is defined as 0.
-
-2.6.14 netlink code only allows to select a group which is less or equal to
-the maximum group number, which is used at netlink_kernel_create() time.
-In case of connector it is CN_NETLINK_USERS + 0xf, so if you want to use
-group number 12345, you must increment CN_NETLINK_USERS to that number.
-Additional 0xf numbers are allocated to be used by non-in-kernel users.
-
-Due to this limitation, group 0xffffffff does not work now, so one can
-not use add/remove connector's group notifications, but as far as I know, 
-only cn_test.c test module used it.
-
-Some work in netlink area is still being done, so things can be changed in
-2.6.15 timeframe, if it will happen, documentation will be updated for that
-kernel.
-
-/*****************************************/
-Code samples
-/*****************************************/
-
-Sample code for a connector test module and user space can be found
-in samples/connector/. To build this code, enable CONFIG_CONNECTOR
-and CONFIG_SAMPLES.
diff --git a/Documentation/console/console.txt b/Documentation/console/console.txt
deleted file mode 100644 (file)
index d73c2ab..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-Console Drivers
-===============
-
-The Linux kernel has 2 general types of console drivers.  The first type is
-assigned by the kernel to all the virtual consoles during the boot process.
-This type will be called 'system driver', and only one system driver is allowed
-to exist. The system driver is persistent and it can never be unloaded, though
-it may become inactive.
-
-The second type has to be explicitly loaded and unloaded. This will be called
-'modular driver' by this document. Multiple modular drivers can coexist at
-any time with each driver sharing the console with other drivers including
-the system driver. However, modular drivers cannot take over the console
-that is currently occupied by another modular driver. (Exception: Drivers that
-call do_take_over_console() will succeed in the takeover regardless of the type
-of driver occupying the consoles.) They can only take over the console that is
-occupied by the system driver. In the same token, if the modular driver is
-released by the console, the system driver will take over.
-
-Modular drivers, from the programmer's point of view, have to call:
-
-        do_take_over_console() - load and bind driver to console layer
-        give_up_console() - unload driver; it will only work if driver
-                            is fully unbound
-
-In newer kernels, the following are also available:
-
-        do_register_con_driver()
-        do_unregister_con_driver()
-
-If sysfs is enabled, the contents of /sys/class/vtconsole can be
-examined. This shows the console backends currently registered by the
-system which are named vtcon<n> where <n> is an integer from 0 to 15. Thus:
-
-       ls /sys/class/vtconsole
-       .  ..  vtcon0  vtcon1
-
-Each directory in /sys/class/vtconsole has 3 files:
-
-     ls /sys/class/vtconsole/vtcon0
-     .  ..  bind  name  uevent
-
-What do these files signify?
-
-     1. bind - this is a read/write file. It shows the status of the driver if
-        read, or acts to bind or unbind the driver to the virtual consoles
-        when written to. The possible values are:
-
-       0 - means the driver is not bound and if echo'ed, commands the driver
-           to unbind
-
-        1 - means the driver is bound and if echo'ed, commands the driver to
-           bind
-
-     2. name - read-only file. Shows the name of the driver in this format:
-
-       cat /sys/class/vtconsole/vtcon0/name
-       (S) VGA+
-
-           '(S)' stands for a (S)ystem driver, i.e., it cannot be directly
-           commanded to bind or unbind
-
-           'VGA+' is the name of the driver
-
-       cat /sys/class/vtconsole/vtcon1/name
-       (M) frame buffer device
-
-           In this case, '(M)' stands for a (M)odular driver, one that can be
-           directly commanded to bind or unbind.
-
-     3. uevent - ignore this file
-
-When unbinding, the modular driver is detached first, and then the system
-driver takes over the consoles vacated by the driver. Binding, on the other
-hand, will bind the driver to the consoles that are currently occupied by a
-system driver.
-
-NOTE1: Binding and unbinding must be selected in Kconfig. It's under:
-
-Device Drivers -> Character devices -> Support for binding and unbinding
-console drivers
-
-NOTE2: If any of the virtual consoles are in KD_GRAPHICS mode, then binding or
-unbinding will not succeed. An example of an application that sets the console
-to KD_GRAPHICS is X.
-
-How useful is this feature? This is very useful for console driver
-developers. By unbinding the driver from the console layer, one can unload the
-driver, make changes, recompile, reload and rebind the driver without any need
-for rebooting the kernel. For regular users who may want to switch from
-framebuffer console to VGA console and vice versa, this feature also makes
-this possible. (NOTE NOTE NOTE: Please read fbcon.txt under Documentation/fb
-for more details.)
-
-Notes for developers:
-=====================
-
-do_take_over_console() is now broken up into:
-
-     do_register_con_driver()
-     do_bind_con_driver() - private function
-
-give_up_console() is a wrapper to do_unregister_con_driver(), and a driver must
-be fully unbound for this call to succeed. con_is_bound() will check if the
-driver is bound or not.
-
-Guidelines for console driver writers:
-=====================================
-
-In order for binding to and unbinding from the console to properly work,
-console drivers must follow these guidelines:
-
-1. All drivers, except system drivers, must call either do_register_con_driver()
-   or do_take_over_console(). do_register_con_driver() will just add the driver
-   to the console's internal list. It won't take over the
-   console. do_take_over_console(), as it name implies, will also take over (or
-   bind to) the console.
-
-2. All resources allocated during con->con_init() must be released in
-   con->con_deinit().
-
-3. All resources allocated in con->con_startup() must be released when the
-   driver, which was previously bound, becomes unbound.  The console layer
-   does not have a complementary call to con->con_startup() so it's up to the
-   driver to check when it's legal to release these resources. Calling
-   con_is_bound() in con->con_deinit() will help.  If the call returned
-   false(), then it's safe to release the resources.  This balance has to be
-   ensured because con->con_startup() can be called again when a request to
-   rebind the driver to the console arrives.
-
-4. Upon exit of the driver, ensure that the driver is totally unbound. If the
-   condition is satisfied, then the driver must call do_unregister_con_driver()
-   or give_up_console().
-
-5. do_unregister_con_driver() can also be called on conditions which make it
-   impossible for the driver to service console requests.  This can happen
-   with the framebuffer console that suddenly lost all of its drivers.
-
-The current crop of console drivers should still work correctly, but binding
-and unbinding them may cause problems. With minimal fixes, these drivers can
-be made to work correctly.
-
-==========================
-Antonino Daplas <adaplas@pol.net>
-
index 322ac95..da0ed97 100644 (file)
@@ -36,6 +36,7 @@ Core utilities
    memory-hotplug
    protection-keys
    ../RCU/index
+   gcc-plugins
 
 
 Interfaces for kernel debugging
index 75d2bbe..c6224d0 100644 (file)
@@ -119,7 +119,7 @@ Kernel Pointers
 
 For printing kernel pointers which should be hidden from unprivileged
 users. The behaviour of %pK depends on the kptr_restrict sysctl - see
-Documentation/sysctl/kernel.txt for more details.
+Documentation/admin-guide/sysctl/kernel.rst for more details.
 
 Unmodified Addresses
 --------------------
index c401c95..6f48705 100644 (file)
@@ -81,11 +81,6 @@ of sparse using git to clone::
 
         git://git.kernel.org/pub/scm/devel/sparse/sparse.git
 
-DaveJ has hourly generated tarballs of the git tree available at::
-
-        http://www.codemonkey.org.uk/projects/git-snapshots/sparse/
-
-
 Once you have it, just do::
 
         make
diff --git a/Documentation/device-mapper/index.rst b/Documentation/device-mapper/index.rst
deleted file mode 100644 (file)
index 105e253..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-:orphan:
-
-=============
-Device Mapper
-=============
-
-.. toctree::
-    :maxdepth: 1
-
-    cache-policies
-    cache
-    delay
-    dm-crypt
-    dm-flakey
-    dm-init
-    dm-integrity
-    dm-io
-    dm-log
-    dm-queue-length
-    dm-raid
-    dm-service-time
-    dm-uevent
-    dm-zoned
-    era
-    kcopyd
-    linear
-    log-writes
-    persistent-data
-    snapshot
-    statistics
-    striped
-    switch
-    thin-provisioning
-    unstriped
-    verity
-    writecache
-    zero
-
-.. only::  subproject and html
-
-   Indices
-   =======
-
-   * :ref:`genindex`
diff --git a/Documentation/device-mapper/statistics.rst b/Documentation/device-mapper/statistics.rst
deleted file mode 100644 (file)
index 3d80a9f..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-=============
-DM statistics
-=============
-
-Device Mapper supports the collection of I/O statistics on user-defined
-regions of a DM device.         If no regions are defined no statistics are
-collected so there isn't any performance impact.  Only bio-based DM
-devices are currently supported.
-
-Each user-defined region specifies a starting sector, length and step.
-Individual statistics will be collected for each step-sized area within
-the range specified.
-
-The I/O statistics counters for each step-sized area of a region are
-in the same format as `/sys/block/*/stat` or `/proc/diskstats` (see:
-Documentation/iostats.txt).  But two extra counters (12 and 13) are
-provided: total time spent reading and writing.  When the histogram
-argument is used, the 14th parameter is reported that represents the
-histogram of latencies.  All these counters may be accessed by sending
-the @stats_print message to the appropriate DM device via dmsetup.
-
-The reported times are in milliseconds and the granularity depends on
-the kernel ticks.  When the option precise_timestamps is used, the
-reported times are in nanoseconds.
-
-Each region has a corresponding unique identifier, which we call a
-region_id, that is assigned when the region is created.         The region_id
-must be supplied when querying statistics about the region, deleting the
-region, etc.  Unique region_ids enable multiple userspace programs to
-request and process statistics for the same DM device without stepping
-on each other's data.
-
-The creation of DM statistics will allocate memory via kmalloc or
-fallback to using vmalloc space.  At most, 1/4 of the overall system
-memory may be allocated by DM statistics.  The admin can see how much
-memory is used by reading:
-
-       /sys/module/dm_mod/parameters/stats_current_allocated_bytes
-
-Messages
-========
-
-    @stats_create <range> <step> [<number_of_optional_arguments> <optional_arguments>...] [<program_id> [<aux_data>]]
-       Create a new region and return the region_id.
-
-       <range>
-         "-"
-               whole device
-         "<start_sector>+<length>"
-               a range of <length> 512-byte sectors
-               starting with <start_sector>.
-
-       <step>
-         "<area_size>"
-               the range is subdivided into areas each containing
-               <area_size> sectors.
-         "/<number_of_areas>"
-               the range is subdivided into the specified
-               number of areas.
-
-       <number_of_optional_arguments>
-         The number of optional arguments
-
-       <optional_arguments>
-         The following optional arguments are supported:
-
-         precise_timestamps
-               use precise timer with nanosecond resolution
-               instead of the "jiffies" variable.  When this argument is
-               used, the resulting times are in nanoseconds instead of
-               milliseconds.  Precise timestamps are a little bit slower
-               to obtain than jiffies-based timestamps.
-         histogram:n1,n2,n3,n4,...
-               collect histogram of latencies.  The
-               numbers n1, n2, etc are times that represent the boundaries
-               of the histogram.  If precise_timestamps is not used, the
-               times are in milliseconds, otherwise they are in
-               nanoseconds.  For each range, the kernel will report the
-               number of requests that completed within this range. For
-               example, if we use "histogram:10,20,30", the kernel will
-               report four numbers a:b:c:d. a is the number of requests
-               that took 0-10 ms to complete, b is the number of requests
-               that took 10-20 ms to complete, c is the number of requests
-               that took 20-30 ms to complete and d is the number of
-               requests that took more than 30 ms to complete.
-
-       <program_id>
-         An optional parameter.  A name that uniquely identifies
-         the userspace owner of the range.  This groups ranges together
-         so that userspace programs can identify the ranges they
-         created and ignore those created by others.
-         The kernel returns this string back in the output of
-         @stats_list message, but it doesn't use it for anything else.
-         If we omit the number of optional arguments, program id must not
-         be a number, otherwise it would be interpreted as the number of
-         optional arguments.
-
-       <aux_data>
-         An optional parameter.  A word that provides auxiliary data
-         that is useful to the client program that created the range.
-         The kernel returns this string back in the output of
-         @stats_list message, but it doesn't use this value for anything.
-
-    @stats_delete <region_id>
-       Delete the region with the specified id.
-
-       <region_id>
-         region_id returned from @stats_create
-
-    @stats_clear <region_id>
-       Clear all the counters except the in-flight i/o counters.
-
-       <region_id>
-         region_id returned from @stats_create
-
-    @stats_list [<program_id>]
-       List all regions registered with @stats_create.
-
-       <program_id>
-         An optional parameter.
-         If this parameter is specified, only matching regions
-         are returned.
-         If it is not specified, all regions are returned.
-
-       Output format:
-         <region_id>: <start_sector>+<length> <step> <program_id> <aux_data>
-               precise_timestamps histogram:n1,n2,n3,...
-
-       The strings "precise_timestamps" and "histogram" are printed only
-       if they were specified when creating the region.
-
-    @stats_print <region_id> [<starting_line> <number_of_lines>]
-       Print counters for each step-sized area of a region.
-
-       <region_id>
-         region_id returned from @stats_create
-
-       <starting_line>
-         The index of the starting line in the output.
-         If omitted, all lines are returned.
-
-       <number_of_lines>
-         The number of lines to include in the output.
-         If omitted, all lines are returned.
-
-       Output format for each step-sized area of a region:
-
-         <start_sector>+<length>
-               counters
-
-         The first 11 counters have the same meaning as
-         `/sys/block/*/stat or /proc/diskstats`.
-
-         Please refer to Documentation/iostats.txt for details.
-
-         1. the number of reads completed
-         2. the number of reads merged
-         3. the number of sectors read
-         4. the number of milliseconds spent reading
-         5. the number of writes completed
-         6. the number of writes merged
-         7. the number of sectors written
-         8. the number of milliseconds spent writing
-         9. the number of I/Os currently in progress
-         10. the number of milliseconds spent doing I/Os
-         11. the weighted number of milliseconds spent doing I/Os
-
-         Additional counters:
-
-         12. the total time spent reading in milliseconds
-         13. the total time spent writing in milliseconds
-
-    @stats_print_clear <region_id> [<starting_line> <number_of_lines>]
-       Atomically print and then clear all the counters except the
-       in-flight i/o counters.  Useful when the client consuming the
-       statistics does not want to lose any statistics (those updated
-       between printing and clearing).
-
-       <region_id>
-         region_id returned from @stats_create
-
-       <starting_line>
-         The index of the starting line in the output.
-         If omitted, all lines are printed and then cleared.
-
-       <number_of_lines>
-         The number of lines to process.
-         If omitted, all lines are printed and then cleared.
-
-    @stats_set_aux <region_id> <aux_data>
-       Store auxiliary data aux_data for the specified region.
-
-       <region_id>
-         region_id returned from @stats_create
-
-       <aux_data>
-         The string that identifies data which is useful to the client
-         program that created the range.  The kernel returns this
-         string back in the output of @stats_list message, but it
-         doesn't use this value for anything.
-
-Examples
-========
-
-Subdivide the DM device 'vol' into 100 pieces and start collecting
-statistics on them::
-
-  dmsetup message vol 0 @stats_create - /100
-
-Set the auxiliary data string to "foo bar baz" (the escape for each
-space must also be escaped, otherwise the shell will consume them)::
-
-  dmsetup message vol 0 @stats_set_aux 0 foo\\ bar\\ baz
-
-List the statistics::
-
-  dmsetup message vol 0 @stats_list
-
-Print the statistics::
-
-  dmsetup message vol 0 @stats_print 0
-
-Delete the statistics::
-
-  dmsetup message vol 0 @stats_delete 0
diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt
deleted file mode 100644 (file)
index 061f7b9..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-Amlogic MesonX device tree bindings
--------------------------------------------
-
-Work in progress statement:
-
-Device tree files and bindings applying to Amlogic SoCs and boards are
-considered "unstable". Any Amlogic device tree binding may change at
-any time. Be sure to use a device tree binary and a kernel image
-generated from the same source tree.
-
-Please refer to Documentation/devicetree/bindings/ABI.txt for a definition of a
-stable binding/ABI.
-
----------------------------------------------------------------
-
-Boards with the Amlogic Meson6 SoC shall have the following properties:
-  Required root node property:
-    compatible: "amlogic,meson6"
-
-Boards with the Amlogic Meson8 SoC shall have the following properties:
-  Required root node property:
-    compatible: "amlogic,meson8";
-
-Boards with the Amlogic Meson8b SoC shall have the following properties:
-  Required root node property:
-    compatible: "amlogic,meson8b";
-
-Boards with the Amlogic Meson8m2 SoC shall have the following properties:
-  Required root node property:
-    compatible: "amlogic,meson8m2";
-
-Boards with the Amlogic Meson GXBaby SoC shall have the following properties:
-  Required root node property:
-    compatible: "amlogic,meson-gxbb";
-
-Boards with the Amlogic Meson GXL S905X SoC shall have the following properties:
-  Required root node property:
-    compatible: "amlogic,s905x", "amlogic,meson-gxl";
-
-Boards with the Amlogic Meson GXL S905D SoC shall have the following properties:
-  Required root node property:
-    compatible: "amlogic,s905d", "amlogic,meson-gxl";
-
-Boards with the Amlogic Meson GXL S805X SoC shall have the following properties:
-  Required root node property:
-    compatible: "amlogic,s805x", "amlogic,meson-gxl";
-
-Boards with the Amlogic Meson GXL S905W SoC shall have the following properties:
-  Required root node property:
-    compatible: "amlogic,s905w", "amlogic,meson-gxl";
-
-Boards with the Amlogic Meson GXM S912 SoC shall have the following properties:
-  Required root node property:
-    compatible: "amlogic,s912", "amlogic,meson-gxm";
-
-Boards with the Amlogic Meson AXG A113D SoC shall have the following properties:
-  Required root node property:
-    compatible: "amlogic,a113d", "amlogic,meson-axg";
-
-Boards with the Amlogic Meson G12A S905D2 SoC shall have the following properties:
-  Required root node property:
-    compatible: "amlogic,g12a";
-
-Board compatible values (alphabetically, grouped by SoC):
-
-  - "geniatech,atv1200" (Meson6)
-
-  - "minix,neo-x8" (Meson8)
-
-  - "endless,ec100" (Meson8b)
-  - "hardkernel,odroid-c1" (Meson8b)
-  - "tronfy,mxq" (Meson8b)
-
-  - "tronsmart,mxiii-plus" (Meson8m2)
-
-  - "amlogic,p200" (Meson gxbb)
-  - "amlogic,p201" (Meson gxbb)
-  - "friendlyarm,nanopi-k2" (Meson gxbb)
-  - "hardkernel,odroid-c2" (Meson gxbb)
-  - "nexbox,a95x" (Meson gxbb or Meson gxl s905x)
-  - "tronsmart,vega-s95-pro", "tronsmart,vega-s95" (Meson gxbb)
-  - "tronsmart,vega-s95-meta", "tronsmart,vega-s95" (Meson gxbb)
-  - "tronsmart,vega-s95-telos", "tronsmart,vega-s95" (Meson gxbb)
-  - "wetek,hub" (Meson gxbb)
-  - "wetek,play2" (Meson gxbb)
-
-  - "amlogic,p212" (Meson gxl s905x)
-  - "hwacom,amazetv" (Meson gxl s905x)
-  - "khadas,vim" (Meson gxl s905x)
-  - "libretech,cc" (Meson gxl s905x)
-
-  - "amlogic,p230" (Meson gxl s905d)
-  - "amlogic,p231" (Meson gxl s905d)
-  - "phicomm,n1" (Meson gxl s905d)
-
-  - "amlogic,p241" (Meson gxl s805x)
-  - "libretech,aml-s805x-ac" (Meson gxl s805x)
-
-  - "amlogic,p281" (Meson gxl s905w)
-  - "oranth,tx3-mini" (Meson gxl s905w)
-
-  - "amlogic,q200" (Meson gxm s912)
-  - "amlogic,q201" (Meson gxm s912)
-  - "khadas,vim2" (Meson gxm s912)
-  - "kingnovel,r-box-pro" (Meson gxm S912)
-  - "nexbox,a1" (Meson gxm s912)
-  - "tronsmart,vega-s96" (Meson gxm s912)
-
-  - "amlogic,s400" (Meson axg a113d)
-
-  - "amlogic,u200" (Meson g12a s905d2)
-  - "amediatech,x96-max" (Meson g12a s905x2)
-  - "seirobotics,sei510" (Meson g12a s905x2)
-
-Amlogic Meson Firmware registers Interface
-------------------------------------------
-
-The Meson SoCs have a register bank with status and data shared with the
-secure firmware.
-
-Required properties:
- - compatible: For Meson GX SoCs, must be "amlogic,meson-gx-ao-secure", "syscon"
-
-Properties should indentify components of this register interface :
-
-Meson GX SoC Information
-------------------------
-A firmware register encodes the SoC type, package and revision information on
-the Meson GX SoCs.
-If present, the following property should be added :
-
-Optional properties:
-  - amlogic,has-chip-id: If present, the interface gives the current SoC version.
-
-Example
--------
-
-ao-secure@140 {
-       compatible = "amlogic,meson-gx-ao-secure", "syscon";
-       reg = <0x0 0x140 0x0 0x140>;
-       amlogic,has-chip-id;
-};
diff --git a/Documentation/devicetree/bindings/arm/amlogic.yaml b/Documentation/devicetree/bindings/arm/amlogic.yaml
new file mode 100644 (file)
index 0000000..325c6fd
--- /dev/null
@@ -0,0 +1,144 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/amlogic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Amlogic MesonX device tree bindings
+
+maintainers:
+  - Kevin Hilman <khilman@baylibre.com>
+
+description: |+
+  Work in progress statement:
+
+  Device tree files and bindings applying to Amlogic SoCs and boards are
+  considered "unstable". Any Amlogic device tree binding may change at
+  any time. Be sure to use a device tree binary and a kernel image
+  generated from the same source tree.
+
+  Please refer to Documentation/devicetree/bindings/ABI.txt for a definition of a
+  stable binding/ABI.
+
+properties:
+  $nodename:
+    const: '/'
+  compatible:
+    oneOf:
+      - description: Boards with the Amlogic Meson6 SoC
+        items:
+          - enum:
+              - geniatech,atv1200
+          - const: amlogic,meson6
+
+      - description: Boards with the Amlogic Meson8 SoC
+        items:
+          - enum:
+              - minix,neo-x8
+          - const: amlogic,meson8
+
+      - description: Boards with the Amlogic Meson8m2 SoC
+        items:
+          - enum:
+              - tronsmart,mxiii-plus
+          - const: amlogic,meson8m2
+
+      - description: Boards with the Amlogic Meson8b SoC
+        items:
+          - enum:
+              - endless,ec100
+              - hardkernel,odroid-c1
+              - tronfy,mxq
+          - const: amlogic,meson8b
+
+      - description: Boards with the Amlogic Meson GXBaby SoC
+        items:
+          - enum:
+              - amlogic,p200
+              - amlogic,p201
+              - friendlyarm,nanopi-k2
+              - hardkernel,odroid-c2
+              - nexbox,a95x
+              - wetek,hub
+              - wetek,play2
+          - const: amlogic,meson-gxbb
+
+      - description: Tronsmart Vega S95 devices
+        items:
+          - enum:
+              - tronsmart,vega-s95-pro
+              - tronsmart,vega-s95-meta
+              - tronsmart,vega-s95-telos
+          - const: tronsmart,vega-s95
+          - const: amlogic,meson-gxbb
+
+      - description: Boards with the Amlogic Meson GXL S805X SoC
+        items:
+          - enum:
+              - amlogic,p241
+              - libretech,aml-s805x-ac
+          - const: amlogic,s805x
+          - const: amlogic,meson-gxl
+
+      - description: Boards with the Amlogic Meson GXL S905W SoC
+        items:
+          - enum:
+              - amlogic,p281
+              - oranth,tx3-mini
+          - const: amlogic,s905w
+          - const: amlogic,meson-gxl
+
+      - description: Boards with the Amlogic Meson GXL S905X SoC
+        items:
+          - enum:
+              - amediatech,x96-max
+              - amlogic,p212
+              - hwacom,amazetv
+              - khadas,vim
+              - libretech,cc
+              - nexbox,a95x
+              - seirobotics,sei510
+          - const: amlogic,s905x
+          - const: amlogic,meson-gxl
+
+      - description: Boards with the Amlogic Meson GXL S905D SoC
+        items:
+          - enum:
+              - amlogic,p230
+              - amlogic,p231
+              - phicomm,n1
+          - const: amlogic,s905d
+          - const: amlogic,meson-gxl
+
+      - description: Boards with the Amlogic Meson GXM S912 SoC
+        items:
+          - enum:
+              - amlogic,q200
+              - amlogic,q201
+              - khadas,vim2
+              - kingnovel,r-box-pro
+              - nexbox,a1
+              - tronsmart,vega-s96
+          - const: amlogic,s912
+          - const: amlogic,meson-gxm
+
+      - description: Boards with the Amlogic Meson AXG A113D SoC
+        items:
+          - enum:
+              - amlogic,s400
+          - const: amlogic,a113d
+          - const: amlogic,meson-axg
+
+      - description: Boards with the Amlogic Meson G12A S905D2 SoC
+        items:
+          - enum:
+              - amlogic,u200
+          - const: amlogic,g12a
+
+      - description: Boards with the Amlogic Meson G12B S922X SoC
+        items:
+          - enum:
+              - hardkernel,odroid-n2
+          - const: amlogic,g12b
+
+...
diff --git a/Documentation/devicetree/bindings/arm/amlogic/amlogic,meson-gx-ao-secure.txt b/Documentation/devicetree/bindings/arm/amlogic/amlogic,meson-gx-ao-secure.txt
new file mode 100644 (file)
index 0000000..c67d9f4
--- /dev/null
@@ -0,0 +1,28 @@
+Amlogic Meson Firmware registers Interface
+------------------------------------------
+
+The Meson SoCs have a register bank with status and data shared with the
+secure firmware.
+
+Required properties:
+ - compatible: For Meson GX SoCs, must be "amlogic,meson-gx-ao-secure", "syscon"
+
+Properties should indentify components of this register interface :
+
+Meson GX SoC Information
+------------------------
+A firmware register encodes the SoC type, package and revision information on
+the Meson GX SoCs.
+If present, the following property should be added :
+
+Optional properties:
+  - amlogic,has-chip-id: If present, the interface gives the current SoC version.
+
+Example
+-------
+
+ao-secure@140 {
+       compatible = "amlogic,meson-gx-ao-secure", "syscon";
+       reg = <0x0 0x140 0x0 0x140>;
+       amlogic,has-chip-id;
+};
index 5f3719a..317a2fc 100644 (file)
@@ -6,7 +6,7 @@ that are provided by the hardware platform it is running on, including power
 and performance functions.
 
 This binding is intended to define the interface the firmware implementing
-the SCMI as described in ARM document number ARM DUI 0922B ("ARM System Control
+the SCMI as described in ARM document number ARM DEN 0056A ("ARM System Control
 and Management Interface Platform Design Document")[0] provide for OSPM in
 the device tree.
 
diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt
deleted file mode 100644 (file)
index 99dee23..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-Atmel AT91 device tree bindings.
-================================
-
-Boards with a SoC of the Atmel AT91 or SMART family shall have the following
-properties:
-
-Required root node properties:
-compatible: must be one of:
- * "atmel,at91rm9200"
-
- * "atmel,at91sam9" for SoCs using an ARM926EJ-S core, shall be extended with
-   the specific SoC family or compatible:
-    o "atmel,at91sam9260"
-    o "atmel,at91sam9261"
-    o "atmel,at91sam9263"
-    o "atmel,at91sam9x5" for the 5 series, shall be extended with the specific
-      SoC compatible:
-       - "atmel,at91sam9g15"
-       - "atmel,at91sam9g25"
-       - "atmel,at91sam9g35"
-       - "atmel,at91sam9x25"
-       - "atmel,at91sam9x35"
-    o "atmel,at91sam9g20"
-    o "atmel,at91sam9g45"
-    o "atmel,at91sam9n12"
-    o "atmel,at91sam9rl"
-    o "atmel,at91sam9xe"
-    o "microchip,sam9x60"
- * "atmel,sama5" for SoCs using a Cortex-A5, shall be extended with the specific
-   SoC family:
-    o "atmel,sama5d2" shall be extended with the specific SoC compatible:
-       - "atmel,sama5d27"
-    o "atmel,sama5d3" shall be extended with the specific SoC compatible:
-       - "atmel,sama5d31"
-       - "atmel,sama5d33"
-       - "atmel,sama5d34"
-       - "atmel,sama5d35"
-       - "atmel,sama5d36"
-    o "atmel,sama5d4" shall be extended with the specific SoC compatible:
-       - "atmel,sama5d41"
-       - "atmel,sama5d42"
-       - "atmel,sama5d43"
-       - "atmel,sama5d44"
-
- * "atmel,samv7" for MCUs using a Cortex-M7, shall be extended with the specific
-   SoC family:
-    o "atmel,sams70" shall be extended with the specific MCU compatible:
-       - "atmel,sams70j19"
-       - "atmel,sams70j20"
-       - "atmel,sams70j21"
-       - "atmel,sams70n19"
-       - "atmel,sams70n20"
-       - "atmel,sams70n21"
-       - "atmel,sams70q19"
-       - "atmel,sams70q20"
-       - "atmel,sams70q21"
-    o "atmel,samv70" shall be extended with the specific MCU compatible:
-       - "atmel,samv70j19"
-       - "atmel,samv70j20"
-       - "atmel,samv70n19"
-       - "atmel,samv70n20"
-       - "atmel,samv70q19"
-       - "atmel,samv70q20"
-    o "atmel,samv71" shall be extended with the specific MCU compatible:
-       - "atmel,samv71j19"
-       - "atmel,samv71j20"
-       - "atmel,samv71j21"
-       - "atmel,samv71n19"
-       - "atmel,samv71n20"
-       - "atmel,samv71n21"
-       - "atmel,samv71q19"
-       - "atmel,samv71q20"
-       - "atmel,samv71q21"
diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.yaml b/Documentation/devicetree/bindings/arm/atmel-at91.yaml
new file mode 100644 (file)
index 0000000..6e168ab
--- /dev/null
@@ -0,0 +1,134 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/atmel-at91.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Atmel AT91 device tree bindings.
+
+maintainers:
+  - Alexandre Belloni <alexandre.belloni@bootlin.com>
+  - Ludovic Desroches <ludovic.desroches@microchip.com>
+
+description: |
+  Boards with a SoC of the Atmel AT91 or SMART family shall have the following
+
+properties:
+  $nodename:
+    const: '/'
+  compatible:
+    oneOf:
+      - items:
+          - const: atmel,at91rm9200
+      - items:
+          - enum:
+              - olimex,sam9-l9260
+          - enum:
+              - atmel,at91sam9260
+              - atmel,at91sam9261
+              - atmel,at91sam9263
+              - atmel,at91sam9g20
+              - atmel,at91sam9g45
+              - atmel,at91sam9n12
+              - atmel,at91sam9rl
+              - atmel,at91sam9xe
+              - atmel,at91sam9x60
+          - const: atmel,at91sam9
+
+      - items:
+          - enum:
+              - atmel,at91sam9g15
+              - atmel,at91sam9g25
+              - atmel,at91sam9g35
+              - atmel,at91sam9x25
+              - atmel,at91sam9x35
+          - const: atmel,at91sam9x5
+          - const: atmel,at91sam9
+
+      - items:
+          - const: atmel,sama5d27
+          - const: atmel,sama5d2
+          - const: atmel,sama5
+
+      - description: Nattis v2 board with Natte v2 power board
+        items:
+          - const: axentia,nattis-2
+          - const: axentia,natte-2
+          - const: axentia,linea
+          - const: atmel,sama5d31
+          - const: atmel,sama5d3
+          - const: atmel,sama5
+
+      - description: TSE-850 v3 board
+        items:
+          - const: axentia,tse850v3
+          - const: axentia,linea
+          - const: atmel,sama5d31
+          - const: atmel,sama5d3
+          - const: atmel,sama5
+
+      - items:
+          - const: axentia,linea
+          - const: atmel,sama5d31
+          - const: atmel,sama5d3
+          - const: atmel,sama5
+
+      - items:
+          - enum:
+              - atmel,sama5d31
+              - atmel,sama5d33
+              - atmel,sama5d34
+              - atmel,sama5d35
+              - atmel,sama5d36
+          - const: atmel,sama5d3
+          - const: atmel,sama5
+
+      - items:
+          - enum:
+              - atmel,sama5d41
+              - atmel,sama5d42
+              - atmel,sama5d43
+              - atmel,sama5d44
+          - const: atmel,sama5d4
+          - const: atmel,sama5
+
+      - items:
+          - enum:
+              - atmel,sams70j19
+              - atmel,sams70j20
+              - atmel,sams70j21
+              - atmel,sams70n19
+              - atmel,sams70n20
+              - atmel,sams70n21
+              - atmel,sams70q19
+              - atmel,sams70q20
+              - atmel,sams70q21
+          - const: atmel,sams70
+          - const: atmel,samv7
+
+      - items:
+          - enum:
+              - atmel,samv70j19
+              - atmel,samv70j20
+              - atmel,samv70n19
+              - atmel,samv70n20
+              - atmel,samv70q19
+              - atmel,samv70q20
+          - const: atmel,samv70
+          - const: atmel,samv7
+
+      - items:
+          - enum:
+              - atmel,samv71j19
+              - atmel,samv71j20
+              - atmel,samv71j21
+              - atmel,samv71n19
+              - atmel,samv71n20
+              - atmel,samv71n21
+              - atmel,samv71q19
+              - atmel,samv71q20
+              - atmel,samv71q21
+          - const: atmel,samv71
+          - const: atmel,samv7
+
+...
diff --git a/Documentation/devicetree/bindings/arm/emtrion.txt b/Documentation/devicetree/bindings/arm/emtrion.txt
deleted file mode 100644 (file)
index 83329ae..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-Emtrion Devicetree Bindings
-===========================
-
-emCON Series:
--------------
-
-Required root node properties
-       - compatible:
-       - "emtrion,emcon-mx6", "fsl,imx6q";             : emCON-MX6D or emCON-MX6Q SoM
-       - "emtrion,emcon-mx6-avari", "fsl,imx6q";       : emCON-MX6D or emCON-MX6Q SoM on Avari Base
-       - "emtrion,emcon-mx6", "fsl,imx6dl";            : emCON-MX6S or emCON-MX6DL SoM
-       - "emtrion,emcon-mx6-avari", "fsl,imx6dl";      : emCON-MX6S or emCON-MX6DL SoM on Avari Base
index f378922..a575e42 100644 (file)
@@ -145,6 +145,16 @@ Optional Child nodes:
 - Data cells of ocotp:
   Detailed bindings are described in bindings/nvmem/nvmem.txt
 
+Watchdog bindings based on SCU Message Protocol
+------------------------------------------------------------
+
+Required properties:
+- compatible: should be:
+              "fsl,imx8qxp-sc-wdt"
+              followed by "fsl,imx-sc-wdt";
+Optional properties:
+- timeout-sec: contains the watchdog timeout in seconds.
+
 Example (imx8qxp):
 -------------
 aliases {
@@ -207,6 +217,11 @@ firmware {
                rtc: rtc {
                        compatible = "fsl,imx8qxp-sc-rtc";
                };
+
+               watchdog {
+                       compatible = "fsl,imx8qxp-sc-wdt", "fsl,imx-sc-wdt";
+                       timeout-sec = <60>;
+               };
        };
 };
 
index 407138e..7294ac3 100644 (file)
@@ -15,6 +15,13 @@ properties:
     const: '/'
   compatible:
     oneOf:
+      - description: i.MX1 based Boards
+        items:
+          - enum:
+              - armadeus,imx1-apf9328
+              - fsl,imx1ads
+          - const: fsl,imx1
+
       - description: i.MX23 based Boards
         items:
           - enum:
@@ -51,6 +58,25 @@ properties:
           - const: i2se,duckbill-2
           - const: fsl,imx28
 
+      - description: i.MX31 based Boards
+        items:
+          - enum:
+              - buglabs,imx31-bug
+              - logicpd,imx31-lite
+          - const: fsl,imx31
+
+      - description: i.MX35 based Boards
+        items:
+          - enum:
+              - fsl,imx35-pdk
+          - const: fsl,imx35
+
+      - description: i.MX35 Eukrea CPUIMX35 Board
+        items:
+          - const: eukrea,mbimxsd35-baseboard
+          - const: eukrea,cpuimx35
+          - const: fsl,imx35
+
       - description: i.MX50 based Boards
         items:
           - enum:
@@ -80,6 +106,8 @@ properties:
       - description: i.MX6Q based Boards
         items:
           - enum:
+              - emtrion,emcon-mx6         # emCON-MX6D or emCON-MX6Q SoM
+              - emtrion,emcon-mx6-avari   # emCON-MX6D or emCON-MX6Q SoM on Avari Base
               - fsl,imx6q-arm2
               - fsl,imx6q-sabreauto
               - fsl,imx6q-sabrelite
@@ -99,6 +127,8 @@ properties:
         items:
           - enum:
               - eckelmann,imx6dl-ci4x10
+              - emtrion,emcon-mx6         # emCON-MX6S or emCON-MX6DL SoM
+              - emtrion,emcon-mx6-avari   # emCON-MX6S or emCON-MX6DL SoM on Avari Base
               - fsl,imx6dl-sabreauto      # i.MX6 DualLite/Solo SABRE Automotive Board
               - fsl,imx6dl-sabresd        # i.MX6 DualLite SABRE Smart Device Board
               - technologic,imx6dl-ts4900
@@ -156,6 +186,7 @@ properties:
         items:
           - enum:
               - fsl,imx7d-sdb             # i.MX7 SabreSD Board
+              - novtech,imx7d-meerkat96   # i.MX7 Meerkat96 Board
               - tq,imx7d-mba7             # i.MX7D TQ MBa7 with TQMa7D SoM
               - zii,imx7d-rpu2            # ZII RPU2 Board
           - const: fsl,imx7d
@@ -171,12 +202,25 @@ properties:
           - const: compulab,cl-som-imx7
           - const: fsl,imx7d
 
+      - description: i.MX7ULP based Boards
+        items:
+          - enum:
+              - fsl,imx7ulp-evk           # i.MX7ULP Evaluation Kit
+          - const: fsl,imx7ulp
+
       - description: i.MX8MM based Boards
         items:
           - enum:
               - fsl,imx8mm-evk            # i.MX8MM EVK Board
           - const: fsl,imx8mm
 
+      - description: i.MX8MQ based Boards
+        items:
+          - enum:
+              - fsl,imx8mq-evk            # i.MX8MQ EVK Board
+              - purism,librem5-devkit     # Purism Librem5 devkit
+          - const: fsl,imx8mq
+
       - description: i.MX8QXP based Boards
         items:
           - enum:
diff --git a/Documentation/devicetree/bindings/arm/mediatek.txt b/Documentation/devicetree/bindings/arm/mediatek.txt
deleted file mode 100644 (file)
index 56ac789..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-MediaTek SoC based Platforms Device Tree Bindings
-
-Boards with a MediaTek SoC shall have the following property:
-
-Required root node property:
-
-compatible: Must contain one of
-   "mediatek,mt2701"
-   "mediatek,mt2712"
-   "mediatek,mt6580"
-   "mediatek,mt6589"
-   "mediatek,mt6592"
-   "mediatek,mt6755"
-   "mediatek,mt6765"
-   "mediatek,mt6795"
-   "mediatek,mt6797"
-   "mediatek,mt7622"
-   "mediatek,mt7623"
-   "mediatek,mt7629"
-   "mediatek,mt8127"
-   "mediatek,mt8135"
-   "mediatek,mt8173"
-   "mediatek,mt8183"
-
-
-Supported boards:
-
-- Evaluation board for MT2701:
-    Required root node properties:
-      - compatible = "mediatek,mt2701-evb", "mediatek,mt2701";
-- Evaluation board for MT2712:
-    Required root node properties:
-      - compatible = "mediatek,mt2712-evb", "mediatek,mt2712";
-- Evaluation board for MT6580:
-    Required root node properties:
-      - compatible = "mediatek,mt6580-evbp1", "mediatek,mt6580";
-- bq Aquaris5 smart phone:
-    Required root node properties:
-      - compatible = "mundoreader,bq-aquaris5", "mediatek,mt6589";
-- Evaluation board for MT6592:
-    Required root node properties:
-      - compatible = "mediatek,mt6592-evb", "mediatek,mt6592";
-- Evaluation phone for MT6755(Helio P10):
-    Required root node properties:
-      - compatible = "mediatek,mt6755-evb", "mediatek,mt6755";
-- Evaluation board for MT6765(Helio P22):
-    Required root node properties:
-      - compatible = "mediatek,mt6765-evb", "mediatek,mt6765";
-- Evaluation board for MT6795(Helio X10):
-    Required root node properties:
-      - compatible = "mediatek,mt6795-evb", "mediatek,mt6795";
-- Evaluation board for MT6797(Helio X20):
-    Required root node properties:
-      - compatible = "mediatek,mt6797-evb", "mediatek,mt6797";
-- Mediatek X20 Development Board:
-    Required root node properties:
-      - compatible = "archermind,mt6797-x20-dev", "mediatek,mt6797";
-- Reference board variant 1 for MT7622:
-    Required root node properties:
-      - compatible = "mediatek,mt7622-rfb1", "mediatek,mt7622";
-- Bananapi BPI-R64 for MT7622:
-    Required root node properties:
-      - compatible = "bananapi,bpi-r64", "mediatek,mt7622";
-- Reference board for MT7623a with eMMC:
-    Required root node properties:
-      - compatible = "mediatek,mt7623a-rfb-emmc", "mediatek,mt7623";
-- Reference board for MT7623a with NAND:
-    Required root node properties:
-      - compatible = "mediatek,mt7623a-rfb-nand", "mediatek,mt7623";
-- Reference board for MT7623n with eMMC:
-    Required root node properties:
-      - compatible = "mediatek,mt7623n-rfb-emmc", "mediatek,mt7623";
-- Bananapi BPI-R2 board:
-      - compatible = "bananapi,bpi-r2", "mediatek,mt7623";
-- Reference board for MT7629:
-    Required root node properties:
-      - compatible = "mediatek,mt7629-rfb", "mediatek,mt7629";
-- MTK mt8127 tablet moose EVB:
-    Required root node properties:
-      - compatible = "mediatek,mt8127-moose", "mediatek,mt8127";
-- MTK mt8135 tablet EVB:
-    Required root node properties:
-      - compatible = "mediatek,mt8135-evbp1", "mediatek,mt8135";
-- MTK mt8173 tablet EVB:
-    Required root node properties:
-      - compatible = "mediatek,mt8173-evb", "mediatek,mt8173";
-- Evaluation board for MT8183:
-    Required root node properties:
-      - compatible = "mediatek,mt8183-evb", "mediatek,mt8183";
diff --git a/Documentation/devicetree/bindings/arm/mediatek.yaml b/Documentation/devicetree/bindings/arm/mediatek.yaml
new file mode 100644 (file)
index 0000000..a4ad2eb
--- /dev/null
@@ -0,0 +1,91 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/mediatek.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek SoC based Platforms Device Tree Bindings
+
+maintainers:
+  - Sean Wang <sean.wang@mediatek.com>
+  - Matthias Brugger <matthias.bgg@gmail.com>
+description: |
+  Boards with a MediaTek SoC shall have the following properties.
+
+properties:
+  $nodename:
+    const: '/'
+  compatible:
+    oneOf:
+      - items:
+          - enum:
+              - mediatek,mt2701-evb
+          - const: mediatek,mt2701
+
+      - items:
+          - enum:
+              - mediatek,mt2712-evb
+          - const: mediatek,mt2712
+      - items:
+          - enum:
+              - mediatek,mt6580-evbp1
+          - const: mediatek,mt6580
+      - items:
+          - enum:
+              - mundoreader,bq-aquaris5
+          - const: mediatek,mt6589
+      - items:
+          - enum:
+              - mediatek,mt6592-evb
+          - const: mediatek,mt6592
+      - items:
+          - enum:
+              - mediatek,mt6755-evb
+          - const: mediatek,mt6755
+      - items:
+          - enum:
+              - mediatek,mt6765-evb
+          - const: mediatek,mt6765
+      - items:
+          - enum:
+              - mediatek,mt6795-evb
+          - const: mediatek,mt6795
+      - items:
+          - enum:
+              - archermind,mt6797-x20-dev
+              - mediatek,mt6797-evb
+          - const: mediatek,mt6797
+      - items:
+          - enum:
+              - bananapi,bpi-r64
+              - mediatek,mt7622-rfb1
+          - const: mediatek,mt7622
+      - items:
+          - enum:
+              - mediatek,mt7623a-rfb-emmc
+              - mediatek,mt7623a-rfb-nand
+              - mediatek,mt7623n-rfb-emmc
+              - bananapi,bpi-r2
+          - const: mediatek,mt7623
+
+      - items:
+          - enum:
+              - mediatek,mt7629-rfb
+          - const: mediatek,mt7629
+      - items:
+          - enum:
+              - mediatek,mt8127-moose
+          - const: mediatek,mt8127
+      - items:
+          - enum:
+              - mediatek,mt8135-evbp1
+          - const: mediatek,mt8135
+      - items:
+          - enum:
+              - mediatek,mt8173-evb
+          - const: mediatek,mt8173
+      - items:
+          - enum:
+              - mediatek,mt8183-evb
+          - const: mediatek,mt8183
+...
index f3cef1a..07c9d81 100644 (file)
@@ -10,6 +10,7 @@ Required Properties:
        - "mediatek,mt7622-audsys", "syscon"
        - "mediatek,mt7623-audsys", "mediatek,mt2701-audsys", "syscon"
        - "mediatek,mt8183-audiosys", "syscon"
+       - "mediatek,mt8516-audsys", "syscon"
 - #clock-cells: Must be 1
 
 The AUDSYS controller uses the common clk binding from
index 1c1e48f..b301f75 100644 (file)
@@ -160,6 +160,9 @@ Boards:
 - AM335X phyCORE-AM335x: Development kit
   compatible = "phytec,am335x-pcm-953", "phytec,am335x-phycore-som", "ti,am33xx"
 
+- AM335x phyBOARD-REGOR: Single Board Computer
+  compatible = "phytec,am335x-regor", "phytec,am335x-phycore-som", "ti,am33xx"
+
 - AM335X UC-8100-ME-T: Communication-centric industrial computing platform
   compatible = "moxa,uc-8100-me-t", "ti,am33xx";
 
index 19f3798..08c923f 100644 (file)
@@ -106,6 +106,14 @@ properties:
 
       - description: RZ/G2M (R8A774A1)
         items:
+          - enum:
+              - hoperun,hihope-rzg2m # HopeRun HiHope RZ/G2M platform
+          - const: renesas,r8a774a1
+
+      - items:
+          - enum:
+              - hoperun,hihope-rzg2-ex # HopeRun expansion board for HiHope RZ/G2 platforms
+          - const: hoperun,hihope-rzg2m
           - const: renesas,r8a774a1
 
       - description: RZ/G2E (R8A774C0)
index 5c6bbf1..3486504 100644 (file)
@@ -316,6 +316,19 @@ properties:
           - const: haoyu,marsboard-rk3066
           - const: rockchip,rk3066a
 
+      - description: Hugsun X99 TV Box
+        items:
+          - const: hugsun,x99
+          - const: rockchip,rk3399
+
+      - description: Khadas Edge series boards
+        items:
+          - enum:
+              - khadas,edge
+              - khadas,edge-captain
+              - khadas,edge-v
+          - const: rockchip,rk3399
+
       - description: mqmaker MiQi
         items:
           - const: mqmaker,miqi
diff --git a/Documentation/devicetree/bindings/arm/stm32/mlahb.txt b/Documentation/devicetree/bindings/arm/stm32/mlahb.txt
new file mode 100644 (file)
index 0000000..25307aa
--- /dev/null
@@ -0,0 +1,37 @@
+ML-AHB interconnect bindings
+
+These bindings describe the STM32 SoCs ML-AHB interconnect bus which connects
+a Cortex-M subsystem with dedicated memories.
+The MCU SRAM and RETRAM memory parts can be accessed through different addresses
+(see "RAM aliases" in [1]) using different buses (see [2]) : balancing the
+Cortex-M firmware accesses among those ports allows to tune the system
+performance.
+
+[1]: https://www.st.com/resource/en/reference_manual/dm00327659.pdf
+[2]: https://wiki.st.com/stm32mpu/wiki/STM32MP15_RAM_mapping
+
+Required properties:
+- compatible: should be "simple-bus"
+- dma-ranges: describes memory addresses translation between the local CPU and
+          the remote Cortex-M processor. Each memory region, is declared with
+          3 parameters:
+                - param 1: device base address (Cortex-M processor address)
+                - param 2: physical base address (local CPU address)
+                - param 3: size of the memory region.
+
+The Cortex-M remote processor accessed via the mlahb interconnect is described
+by a child node.
+
+Example:
+mlahb {
+       compatible = "simple-bus";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       dma-ranges = <0x00000000 0x38000000 0x10000>,
+                    <0x10000000 0x10000000 0x60000>,
+                    <0x30000000 0x30000000 0x60000>;
+
+       m4_rproc: m4@10000000 {
+               ...
+       };
+};
diff --git a/Documentation/devicetree/bindings/arm/stm32/stm32.txt b/Documentation/devicetree/bindings/arm/stm32/stm32.txt
deleted file mode 100644 (file)
index 6808ed9..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-STMicroelectronics STM32 Platforms Device Tree Bindings
-
-Each device tree must specify which STM32 SoC it uses,
-using one of the following compatible strings:
-
-  st,stm32f429
-  st,stm32f469
-  st,stm32f746
-  st,stm32h743
-  st,stm32mp157
diff --git a/Documentation/devicetree/bindings/arm/stm32/stm32.yaml b/Documentation/devicetree/bindings/arm/stm32/stm32.yaml
new file mode 100644 (file)
index 0000000..4d194f1
--- /dev/null
@@ -0,0 +1,31 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/stm32/stm32.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STM32 Platforms Device Tree Bindings
+
+maintainers:
+  - Alexandre Torgue <alexandre.torgue@st.com>
+
+properties:
+  compatible:
+    oneOf:
+      - items:
+          - const: st,stm32f429
+
+      - items:
+          - const: st,stm32f469
+
+      - items:
+          - const: st,stm32f746
+
+      - items:
+          - const: st,stm32h743
+
+      - items:
+          - enum:
+              - arrow,stm32mp157a-avenger96 # Avenger96
+          - const: st,stm32mp157
+...
index 285f4fc..000a00d 100644 (file)
@@ -263,7 +263,7 @@ properties:
 
       - description: ICNova A20 SWAC
         items:
-          - const: swac,icnova-a20-swac
+          - const: incircuit,icnova-a20-swac
           - const: incircuit,icnova-a20
           - const: allwinner,sun7i-a20
 
index 6a059ca..333e725 100644 (file)
@@ -13,6 +13,9 @@ architecture it uses, using one of the following compatible values:
 - AM654
   compatible = "ti,am654";
 
+- J721E
+  compatible = "ti,j721e";
+
 Boards
 ------
 
index c9b9321..db5c56d 100644 (file)
@@ -54,7 +54,7 @@ hypervisor {
 };
 
 The format and meaning of the "xen,uefi-*" parameters are similar to those in
-Documentation/arm/uefi.txt, which are provided by the regular UEFI stub. However
+Documentation/arm/uefi.rst, which are provided by the regular UEFI stub. However
 they differ because they are provided by the Xen hypervisor, together with a set
 of UEFI runtime services implemented via hypercalls, see
 http://xenbits.xen.org/docs/unstable/hypercall/x86_64/include,public,platform.h.html.
diff --git a/Documentation/devicetree/bindings/bus/allwinner,sun8i-a23-rsb.yaml b/Documentation/devicetree/bindings/bus/allwinner,sun8i-a23-rsb.yaml
new file mode 100644 (file)
index 0000000..be32f08
--- /dev/null
@@ -0,0 +1,80 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/bus/allwinner,sun8i-a23-rsb.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A23 RSB Device Tree Bindings
+
+maintainers:
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <maxime.ripard@bootlin.com>
+
+properties:
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+  compatible:
+    oneOf:
+      - const: allwinner,sun8i-a23-rsb
+      - items:
+        - const: allwinner,sun8i-a83t-rsb
+        - const: allwinner,sun8i-a23-rsb
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  clock-frequency:
+    minimum: 1
+    maximum: 20000000
+
+patternProperties:
+  "^.*@[0-9a-fA-F]+$":
+    type: object
+    properties:
+      reg:
+        maxItems: 1
+
+    required:
+      - reg
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - resets
+
+examples:
+  - |
+    rsb@1f03400 {
+        compatible = "allwinner,sun8i-a23-rsb";
+        reg = <0x01f03400 0x400>;
+        interrupts = <0 39 4>;
+        clocks = <&apb0_gates 3>;
+        clock-frequency = <3000000>;
+        resets = <&apb0_rst 3>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        pmic@3e3 {
+            compatible = "...";
+            reg = <0x3e3>;
+
+            /* ... */
+        };
+    };
+
+additionalProperties: false
diff --git a/Documentation/devicetree/bindings/bus/sunxi-rsb.txt b/Documentation/devicetree/bindings/bus/sunxi-rsb.txt
deleted file mode 100644 (file)
index eb3ed62..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-Allwinner Reduced Serial Bus (RSB) controller
-
-The RSB controller found on later Allwinner SoCs is an SMBus like 2 wire
-serial bus with 1 master and up to 15 slaves. It is represented by a node
-for the controller itself, and child nodes representing the slave devices.
-
-Required properties :
-
- - reg             : Offset and length of the register set for the controller.
- - compatible      : Shall be "allwinner,sun8i-a23-rsb".
- - interrupts      : The interrupt line associated to the RSB controller.
- - clocks          : The gate clk associated to the RSB controller.
- - resets          : The reset line associated to the RSB controller.
- - #address-cells  : shall be 1
- - #size-cells     : shall be 0
-
-Optional properties :
-
- - clock-frequency : Desired RSB bus clock frequency in Hz. Maximum is 20MHz.
-                    If not set this defaults to 3MHz.
-
-Child nodes:
-
-An RSB controller node can contain zero or more child nodes representing
-slave devices on the bus.  Child 'reg' properties should contain the slave
-device's hardware address. The hardware address is hardwired in the device,
-which can normally be found in the datasheet.
-
-Example:
-
-       rsb@1f03400 {
-               compatible = "allwinner,sun8i-a23-rsb";
-               reg = <0x01f03400 0x400>;
-               interrupts = <0 39 4>;
-               clocks = <&apb0_gates 3>;
-               clock-frequency = <3000000>;
-               resets = <&apb0_rst 3>;
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               pmic@3e3 {
-                       compatible = "...";
-                       reg = <0x3e3>;
-
-                       /* ... */
-               };
-       };
diff --git a/Documentation/devicetree/bindings/clock/allwinner,sun4i-a10-ccu.yaml b/Documentation/devicetree/bindings/clock/allwinner,sun4i-a10-ccu.yaml
new file mode 100644 (file)
index 0000000..c935405
--- /dev/null
@@ -0,0 +1,141 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/allwinner,sun4i-a10-ccu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner Clock Control Unit Device Tree Bindings
+
+maintainers:
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <maxime.ripard@bootlin.com>
+
+properties:
+  "#clock-cells":
+    const: 1
+
+  "#reset-cells":
+    const: 1
+
+  compatible:
+    enum:
+      - allwinner,sun4i-a10-ccu
+      - allwinner,sun5i-a10s-ccu
+      - allwinner,sun5i-a13-ccu
+      - allwinner,sun6i-a31-ccu
+      - allwinner,sun7i-a20-ccu
+      - allwinner,sun8i-a23-ccu
+      - allwinner,sun8i-a33-ccu
+      - allwinner,sun8i-a83t-ccu
+      - allwinner,sun8i-a83t-r-ccu
+      - allwinner,sun8i-h3-ccu
+      - allwinner,sun8i-h3-r-ccu
+      - allwinner,sun8i-r40-ccu
+      - allwinner,sun8i-v3s-ccu
+      - allwinner,sun9i-a80-ccu
+      - allwinner,sun50i-a64-ccu
+      - allwinner,sun50i-a64-r-ccu
+      - allwinner,sun50i-h5-ccu
+      - allwinner,sun50i-h6-ccu
+      - allwinner,sun50i-h6-r-ccu
+      - allwinner,suniv-f1c100s-ccu
+      - nextthing,gr8-ccu
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    minItems: 2
+    maxItems: 4
+    items:
+      - description: High Frequency Oscillator (usually at 24MHz)
+      - description: Low Frequency Oscillator (usually at 32kHz)
+      - description: Internal Oscillator
+      - description: Peripherals PLL
+
+  clock-names:
+    minItems: 2
+    maxItems: 4
+    items:
+      - const: hosc
+      - const: losc
+      - const: iosc
+      - const: pll-periph
+
+required:
+  - "#clock-cells"
+  - "#reset-cells"
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+
+if:
+  properties:
+    compatible:
+      enum:
+        - allwinner,sun8i-a83t-r-ccu
+        - allwinner,sun8i-h3-r-ccu
+        - allwinner,sun50i-a64-r-ccu
+        - allwinner,sun50i-h6-r-ccu
+
+then:
+  properties:
+    clocks:
+      minItems: 4
+      maxItems: 4
+
+    clock-names:
+      minItems: 4
+      maxItems: 4
+
+else:
+  if:
+    properties:
+      compatible:
+        const: allwinner,sun50i-h6-ccu
+
+  then:
+    properties:
+      clocks:
+        minItems: 3
+        maxItems: 3
+
+      clock-names:
+        minItems: 3
+        maxItems: 3
+
+  else:
+    properties:
+      clocks:
+        minItems: 2
+        maxItems: 2
+
+      clock-names:
+        minItems: 2
+        maxItems: 2
+
+additionalProperties: false
+
+examples:
+  - |
+    ccu: clock@1c20000 {
+        compatible = "allwinner,sun8i-h3-ccu";
+        reg = <0x01c20000 0x400>;
+        clocks = <&osc24M>, <&osc32k>;
+        clock-names = "hosc", "losc";
+        #clock-cells = <1>;
+        #reset-cells = <1>;
+    };
+
+  - |
+    r_ccu: clock@1f01400 {
+        compatible = "allwinner,sun50i-a64-r-ccu";
+        reg = <0x01f01400 0x100>;
+        clocks = <&osc24M>, <&osc32k>, <&iosc>, <&ccu 11>;
+        clock-names = "hosc", "losc", "iosc", "pll-periph";
+        #clock-cells = <1>;
+        #reset-cells = <1>;
+    };
+
+...
index 5c8b105..6eaa520 100644 (file)
@@ -10,6 +10,7 @@ Required Properties:
                "amlogic,gxl-clkc" for GXL and GXM SoC,
                "amlogic,axg-clkc" for AXG SoC.
                "amlogic,g12a-clkc" for G12A SoC.
+               "amlogic,g12b-clkc" for G12B SoC.
 - clocks : list of clock phandle, one for each entry clock-names.
 - clock-names : should contain the following:
   * "xtal": the platform xtal
index b520280..13f45db 100644 (file)
@@ -9,10 +9,11 @@ Slow Clock controller:
 Required properties:
 - compatible : shall be one of the following:
        "atmel,at91sam9x5-sckc",
-       "atmel,sama5d3-sckc" or
-       "atmel,sama5d4-sckc":
+       "atmel,sama5d3-sckc",
+       "atmel,sama5d4-sckc" or
+       "microchip,sam9x60-sckc":
                at91 SCKC (Slow Clock Controller)
-- #clock-cells : shall be 0.
+- #clock-cells : shall be 1 for "microchip,sam9x60-sckc" otherwise shall be 0.
 - clocks : shall be the input parent clock phandle for the clock.
 
 Optional properties:
diff --git a/Documentation/devicetree/bindings/clock/brcm,bcm63xx-clocks.txt b/Documentation/devicetree/bindings/clock/brcm,bcm63xx-clocks.txt
new file mode 100644 (file)
index 0000000..3041657
--- /dev/null
@@ -0,0 +1,22 @@
+Gated Clock Controller Bindings for MIPS based BCM63XX SoCs
+
+Required properties:
+- compatible: must be one of:
+        "brcm,bcm3368-clocks"
+        "brcm,bcm6328-clocks"
+        "brcm,bcm6358-clocks"
+        "brcm,bcm6362-clocks"
+        "brcm,bcm6368-clocks"
+        "brcm,bcm63268-clocks"
+
+- reg: Address and length of the register set
+- #clock-cells: must be <1>
+
+
+Example:
+
+clkctl: clock-controller@10000004 {
+       compatible = "brcm,bcm6328-clocks";
+       reg = <0x10000004 0x4>;
+       #clock-cells = <1>;
+};
index b8d8ef3..52a064c 100644 (file)
@@ -40,6 +40,7 @@ Optional properties:
        input audio clocks from host system.
      - ln-psia1-mclk, ln-psia2-mclk : Optional input audio clocks from
        external connector.
+     - ln-spdif-mclk : Optional input audio clock from SPDIF.
      - ln-spdif-clkout : Optional input audio clock from SPDIF.
      - ln-adat-mclk : Optional input audio clock from ADAT.
      - ln-pmic-32k : On board fixed clock.
index 796c260..d8f5c49 100644 (file)
@@ -59,6 +59,7 @@ Required properties:
        "marvell,dove-core-clock" - for Dove SoC core clocks
        "marvell,kirkwood-core-clock" - for Kirkwood SoC (except mv88f6180)
        "marvell,mv88f6180-core-clock" - for Kirkwood MV88f6180 SoC
+       "marvell,mv98dx1135-core-clock" - for Kirkwood 98dx1135 SoC
        "marvell,mv88f5181-core-clock" - for Orion MV88F5181 SoC
        "marvell,mv88f5182-core-clock" - for Orion MV88F5182 SoC
        "marvell,mv88f5281-core-clock" - for Orion MV88F5281 SoC
index 4e5215e..269afe8 100644 (file)
@@ -2,13 +2,15 @@ Qualcomm Graphics Clock & Reset Controller Binding
 --------------------------------------------------
 
 Required properties :
-- compatible : shall contain "qcom,sdm845-gpucc"
+- compatible : shall contain "qcom,sdm845-gpucc" or "qcom,msm8998-gpucc"
 - reg : shall contain base register location and length
 - #clock-cells : from common clock binding, shall contain 1
 - #reset-cells : from common reset binding, shall contain 1
 - #power-domain-cells : from generic power domain binding, shall contain 1
 - clocks : shall contain the XO clock
+          shall contain the gpll0 out main clock (msm8998)
 - clock-names : shall be "xo"
+               shall be "gpll0" (msm8998)
 
 Example:
        gpucc: clock-controller@5090000 {
index d60b997..aed713c 100644 (file)
@@ -13,6 +13,7 @@ Required Properties:
        - external (optional) RGMII_REFCLK
   - clock-names: Must be:
         clock-names = "mclk", "rtc", "jtag", "rgmii_ref_ext";
+  - #power-domain-cells: Must be 0
 
 Examples
 --------
@@ -27,6 +28,7 @@ Examples
                clocks = <&ext_mclk>, <&ext_rtc_clk>,
                                <&ext_jtag_clk>, <&ext_rgmii_ref>;
                clock-names = "mclk", "rtc", "jtag", "rgmii_ref_ext";
+               #power-domain-cells = <0>;
        };
 
   - Other nodes can use the clocks provided by SYSCTRL as in:
@@ -38,6 +40,7 @@ Examples
                interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
                reg-shift = <2>;
                reg-io-width = <4>;
-               clocks = <&sysctrl R9A06G032_CLK_UART0>;
-               clock-names = "baudclk";
+               clocks = <&sysctrl R9A06G032_CLK_UART0>, <&sysctrl R9A06G032_HCLK_UART0>;
+               clock-names = "baudclk", "apb_pclk";
+               power-domains = <&sysctrl>;
        };
diff --git a/Documentation/devicetree/bindings/clock/silabs,si5341.txt b/Documentation/devicetree/bindings/clock/silabs,si5341.txt
new file mode 100644 (file)
index 0000000..a70c333
--- /dev/null
@@ -0,0 +1,162 @@
+Binding for Silicon Labs Si5341 and Si5340 programmable i2c clock generator.
+
+Reference
+[1] Si5341 Data Sheet
+    https://www.silabs.com/documents/public/data-sheets/Si5341-40-D-DataSheet.pdf
+[2] Si5341 Reference Manual
+    https://www.silabs.com/documents/public/reference-manuals/Si5341-40-D-RM.pdf
+
+The Si5341 and Si5340 are programmable i2c clock generators with up to 10 output
+clocks. The chip contains a PLL that sources 5 (or 4) multisynth clocks, which
+in turn can be directed to any of the 10 (or 4) outputs through a divider.
+The internal structure of the clock generators can be found in [2].
+
+The driver can be used in "as is" mode, reading the current settings from the
+chip at boot, in case you have a (pre-)programmed device. If the PLL is not
+configured when the driver probes, it assumes the driver must fully initialize
+it.
+
+The device type, speed grade and revision are determined runtime by probing.
+
+The driver currently only supports XTAL input mode, and does not support any
+fancy input configurations. They can still be programmed into the chip and
+the driver will leave them "as is".
+
+==I2C device node==
+
+Required properties:
+- compatible: shall be one of the following:
+       "silabs,si5340" - Si5340 A/B/C/D
+       "silabs,si5341" - Si5341 A/B/C/D
+- reg: i2c device address, usually 0x74
+- #clock-cells: from common clock binding; shall be set to 2.
+       The first value is "0" for outputs, "1" for synthesizers.
+       The second value is the output or synthesizer index.
+- clocks: from common clock binding; list of parent clock  handles,
+       corresponding to inputs. Use a fixed clock for the "xtal" input.
+       At least one must be present.
+- clock-names: One of: "xtal", "in0", "in1", "in2"
+- vdd-supply: Regulator node for VDD
+
+Optional properties:
+- vdda-supply: Regulator node for VDDA
+- vdds-supply: Regulator node for VDDS
+- silabs,pll-m-num, silabs,pll-m-den: Numerator and denominator for PLL
+  feedback divider. Must be such that the PLL output is in the valid range. For
+  example, to create 14GHz from a 48MHz xtal, use m-num=14000 and m-den=48. Only
+  the fraction matters, using 3500 and 12 will deliver the exact same result.
+  If these are not specified, and the PLL is not yet programmed when the driver
+  probes, the PLL will be set to 14GHz.
+- silabs,reprogram: When present, the driver will always assume the device must
+  be initialized, and always performs the soft-reset routine. Since this will
+  temporarily stop all output clocks, don't do this if the chip is generating
+  the CPU clock for example.
+- interrupts: Interrupt for INTRb pin.
+- #address-cells: shall be set to 1.
+- #size-cells: shall be set to 0.
+
+
+== Child nodes: Outputs ==
+
+The child nodes list the output clocks.
+
+Each of the clock outputs can be overwritten individually by using a child node.
+If a child node for a clock output is not set, the configuration remains
+unchanged.
+
+Required child node properties:
+- reg: number of clock output.
+
+Optional child node properties:
+- vdd-supply: Regulator node for VDD for this output. The driver selects default
+       values for common-mode and amplitude based on the voltage.
+- silabs,format: Output format, one of:
+       1 = differential (defaults to LVDS levels)
+       2 = low-power (defaults to HCSL levels)
+       4 = LVCMOS
+- silabs,common-mode: Manually override output common mode, see [2] for values
+- silabs,amplitude: Manually override output amplitude, see [2] for values
+- silabs,synth-master: boolean. If present, this output is allowed to change the
+       multisynth frequency dynamically.
+- silabs,silabs,disable-high: boolean. If set, the clock output is driven HIGH
+       when disabled, otherwise it's driven LOW.
+
+==Example==
+
+/* 48MHz reference crystal */
+ref48: ref48M {
+       compatible = "fixed-clock";
+       #clock-cells = <0>;
+       clock-frequency = <48000000>;
+};
+
+i2c-master-node {
+       /* Programmable clock (for logic) */
+       si5341: clock-generator@74 {
+               reg = <0x74>;
+               compatible = "silabs,si5341";
+               #clock-cells = <2>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               clocks = <&ref48>;
+               clock-names = "xtal";
+
+               silabs,pll-m-num = <14000>; /* PLL at 14.0 GHz */
+               silabs,pll-m-den = <48>;
+               silabs,reprogram; /* Chips are not programmed, always reset */
+
+               out@0 {
+                       reg = <0>;
+                       silabs,format = <1>; /* LVDS 3v3 */
+                       silabs,common-mode = <3>;
+                       silabs,amplitude = <3>;
+                       silabs,synth-master;
+               };
+
+               /*
+                * Output 6 configuration:
+                *  LVDS 1v8
+                */
+               out@6 {
+                       reg = <6>;
+                       silabs,format = <1>; /* LVDS 1v8 */
+                       silabs,common-mode = <13>;
+                       silabs,amplitude = <3>;
+               };
+
+               /*
+                * Output 8 configuration:
+                *  HCSL 3v3
+                */
+               out@8 {
+                       reg = <8>;
+                       silabs,format = <2>;
+                       silabs,common-mode = <11>;
+                       silabs,amplitude = <3>;
+               };
+       };
+};
+
+some-video-node {
+       /* Standard clock bindings */
+       clock-names = "pixel";
+       clocks = <&si5341 0 7>; /* Output 7 */
+
+       /* Set output 7 to use syntesizer 3 as its parent */
+       assigned-clocks = <&si5341 0 7>, <&si5341 1 3>;
+       assigned-clock-parents = <&si5341 1 3>;
+       /* Set output 7 to 148.5 MHz using a synth frequency of 594 MHz */
+       assigned-clock-rates = <148500000>, <594000000>;
+};
+
+some-audio-node {
+       clock-names = "i2s-clk";
+       clocks = <&si5341 0 0>;
+       /*
+        * since output 0 is a synth-master, the synth will be automatically set
+        * to an appropriate frequency when the audio driver requests another
+        * frequency. We give control over synth 2 to this output here.
+        */
+       assigned-clocks = <&si5341 0 0>;
+       assigned-clock-parents = <&si5341 1 2>;
+};
diff --git a/Documentation/devicetree/bindings/clock/sunxi-ccu.txt b/Documentation/devicetree/bindings/clock/sunxi-ccu.txt
deleted file mode 100644 (file)
index e3bd88a..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-Allwinner Clock Control Unit Binding
-------------------------------------
-
-Required properties :
-- compatible: must contain one of the following compatibles:
-               - "allwinner,sun4i-a10-ccu"
-               - "allwinner,sun5i-a10s-ccu"
-               - "allwinner,sun5i-a13-ccu"
-               - "allwinner,sun6i-a31-ccu"
-               - "allwinner,sun7i-a20-ccu"
-               - "allwinner,sun8i-a23-ccu"
-               - "allwinner,sun8i-a33-ccu"
-               - "allwinner,sun8i-a83t-ccu"
-               - "allwinner,sun8i-a83t-r-ccu"
-               - "allwinner,sun8i-h3-ccu"
-               - "allwinner,sun8i-h3-r-ccu"
-+              - "allwinner,sun8i-r40-ccu"
-               - "allwinner,sun8i-v3s-ccu"
-               - "allwinner,sun9i-a80-ccu"
-               - "allwinner,sun50i-a64-ccu"
-               - "allwinner,sun50i-a64-r-ccu"
-               - "allwinner,sun50i-h5-ccu"
-               - "allwinner,sun50i-h6-ccu"
-               - "allwinner,sun50i-h6-r-ccu"
-               - "allwinner,suniv-f1c100s-ccu"
-               - "nextthing,gr8-ccu"
-
-- reg: Must contain the registers base address and length
-- clocks: phandle to the oscillators feeding the CCU. Two are needed:
-  - "hosc": the high frequency oscillator (usually at 24MHz)
-  - "losc": the low frequency oscillator (usually at 32kHz)
-           On the A83T, this is the internal 16MHz oscillator divided by 512
-- clock-names: Must contain the clock names described just above
-- #clock-cells : must contain 1
-- #reset-cells : must contain 1
-
-For the main CCU on H6, one more clock is needed:
-- "iosc": the SoC's internal frequency oscillator
-
-For the PRCM CCUs on A83T/H3/A64/H6, two more clocks are needed:
-- "pll-periph": the SoC's peripheral PLL from the main CCU
-- "iosc": the SoC's internal frequency oscillator
-
-Example for generic CCU:
-ccu: clock@1c20000 {
-       compatible = "allwinner,sun8i-h3-ccu";
-       reg = <0x01c20000 0x400>;
-       clocks = <&osc24M>, <&osc32k>;
-       clock-names = "hosc", "losc";
-       #clock-cells = <1>;
-       #reset-cells = <1>;
-};
-
-Example for PRCM CCU:
-r_ccu: clock@1f01400 {
-       compatible = "allwinner,sun50i-a64-r-ccu";
-       reg = <0x01f01400 0x100>;
-       clocks = <&osc24M>, <&osc32k>, <&iosc>, <&ccu CLK_PLL_PERIPH0>;
-       clock-names = "hosc", "losc", "iosc", "pll-periph";
-       #clock-cells = <1>;
-       #reset-cells = <1>;
-};
diff --git a/Documentation/devicetree/bindings/csky/pmu.txt b/Documentation/devicetree/bindings/csky/pmu.txt
new file mode 100644 (file)
index 0000000..728d05c
--- /dev/null
@@ -0,0 +1,38 @@
+===============================
+C-SKY Performance Monitor Units
+===============================
+
+C-SKY Performance Monitor is designed for ck807/ck810/ck860 SMP soc and
+it could count cpu's events for helping analysis performance issues.
+
+============================
+PMU node bindings definition
+============================
+
+       Description: Describes PMU
+
+       PROPERTIES
+
+       - compatible
+               Usage: required
+               Value type: <string>
+               Definition: must be "csky,csky-pmu"
+       - interrupts
+               Usage: required
+               Value type: <u32 IRQ_TYPE_XXX>
+               Definition: must be pmu irq num defined by soc
+       - count-width
+               Usage: optional
+               Value type: <u32>
+               Definition: the width of pmu counter
+
+Examples:
+---------
+#include <dt-bindings/interrupt-controller/irq.h>
+
+       pmu: performace-monitor {
+               compatible = "csky,csky-pmu";
+               interrupts = <23 IRQ_TYPE_EDGE_RISING>;
+               interrupt-parent = <&intc>;
+               count-width = <48>;
+        };
index a41d280..db68041 100644 (file)
@@ -12,10 +12,12 @@ following device-specific properties.
 Required properties:
 
 - compatible : Shall contain one or more of
+  - "renesas,r8a774a1-hdmi" for R8A774A1 (RZ/G2M) compatible HDMI TX
   - "renesas,r8a7795-hdmi" for R8A7795 (R-Car H3) compatible HDMI TX
   - "renesas,r8a7796-hdmi" for R8A7796 (R-Car M3-W) compatible HDMI TX
   - "renesas,r8a77965-hdmi" for R8A77965 (R-Car M3-N) compatible HDMI TX
-  - "renesas,rcar-gen3-hdmi" for the generic R-Car Gen3 compatible HDMI TX
+  - "renesas,rcar-gen3-hdmi" for the generic R-Car Gen3 and RZ/G2 compatible
+                            HDMI TX
 
     When compatible with generic versions, nodes must list the SoC-specific
     version corresponding to the platform first, followed by the
diff --git a/Documentation/devicetree/bindings/dma/8250_mtk_dma.txt b/Documentation/devicetree/bindings/dma/8250_mtk_dma.txt
deleted file mode 100644 (file)
index 3fe0961..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-* Mediatek UART APDMA Controller
-
-Required properties:
-- compatible should contain:
-  * "mediatek,mt2712-uart-dma" for MT2712 compatible APDMA
-  * "mediatek,mt6577-uart-dma" for MT6577 and all of the above
-
-- reg: The base address of the APDMA register bank.
-
-- interrupts: A single interrupt specifier.
-
-- clocks : Must contain an entry for each entry in clock-names.
-  See ../clocks/clock-bindings.txt for details.
-- clock-names: The APDMA clock for register accesses
-
-Examples:
-
-       apdma: dma-controller@11000380 {
-               compatible = "mediatek,mt2712-uart-dma";
-               reg = <0 0x11000380 0 0x400>;
-               interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_LOW>,
-                            <GIC_SPI 64 IRQ_TYPE_LEVEL_LOW>,
-                            <GIC_SPI 65 IRQ_TYPE_LEVEL_LOW>,
-                            <GIC_SPI 66 IRQ_TYPE_LEVEL_LOW>,
-                            <GIC_SPI 67 IRQ_TYPE_LEVEL_LOW>,
-                            <GIC_SPI 68 IRQ_TYPE_LEVEL_LOW>,
-                            <GIC_SPI 69 IRQ_TYPE_LEVEL_LOW>,
-                            <GIC_SPI 70 IRQ_TYPE_LEVEL_LOW>;
-               clocks = <&pericfg CLK_PERI_AP_DMA>;
-               clock-names = "apdma";
-               #dma-cells = <1>;
-       };
-
index db7e226..2c7fd19 100644 (file)
@@ -16,6 +16,9 @@ Optional properties:
   - dma-channels: contains the total number of DMA channels supported by the DMAC
   - dma-requests: contains the total number of DMA requests supported by the DMAC
   - arm,pl330-broken-no-flushp: quirk for avoiding to execute DMAFLUSHP
+  - resets: contains an entry for each entry in reset-names.
+           See ../reset/reset.txt for details.
+  - reset-names: must contain at least "dma", and optional is "dma-ocp".
 
 Example:
 
index 97e213e..29dd3cc 100644 (file)
@@ -9,15 +9,16 @@ group, DMAMUX0 or DMAMUX1, but not both.
 Required properties:
 - compatible :
        - "fsl,vf610-edma" for eDMA used similar to that on Vybrid vf610 SoC
+       - "fsl,imx7ulp-edma" for eDMA2 used similar to that on i.mx7ulp
 - reg : Specifies base physical address(s) and size of the eDMA registers.
        The 1st region is eDMA control register's address and size.
        The 2nd and the 3rd regions are programmable channel multiplexing
        control register's address and size.
 - interrupts : A list of interrupt-specifiers, one for each entry in
-       interrupt-names.
-- interrupt-names : Should contain:
-       "edma-tx" - the transmission interrupt
-       "edma-err" - the error interrupt
+       interrupt-names on vf610 similar SoC. But for i.mx7ulp per channel
+       per transmission interrupt, total 16 channel interrupt and 1
+       error interrupt(located in the last), no interrupt-names list on
+       i.mx7ulp for clean on dts.
 - #dma-cells : Must be <2>.
        The 1st cell specifies the DMAMUX(0 for DMAMUX0 and 1 for DMAMUX1).
        Specific request source can only be multiplexed by specific channels
@@ -28,6 +29,7 @@ Required properties:
 - clock-names : A list of channel group clock names. Should contain:
        "dmamux0" - clock name of mux0 group
        "dmamux1" - clock name of mux1 group
+       Note: No dmamux0 on i.mx7ulp, but another 'dma' clk added on i.mx7ulp.
 - clocks : A list of phandle and clock-specifier pairs, one for each entry in
        clock-names.
 
@@ -35,6 +37,10 @@ Optional properties:
 - big-endian: If present registers and hardware scatter/gather descriptors
        of the eDMA are implemented in big endian mode, otherwise in little
        mode.
+- interrupt-names : Should contain the below on vf610 similar SoC but not used
+       on i.mx7ulp similar SoC:
+       "edma-tx" - the transmission interrupt
+       "edma-err" - the error interrupt
 
 
 Examples:
@@ -52,8 +58,36 @@ edma0: dma-controller@40018000 {
        clock-names = "dmamux0", "dmamux1";
        clocks = <&clks VF610_CLK_DMAMUX0>,
                <&clks VF610_CLK_DMAMUX1>;
-};
+}; /* vf610 */
 
+edma1: dma-controller@40080000 {
+       #dma-cells = <2>;
+       compatible = "fsl,imx7ulp-edma";
+       reg = <0x40080000 0x2000>,
+               <0x40210000 0x1000>;
+       dma-channels = <32>;
+       interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
+                    /* last is eDMA2-ERR interrupt */
+                    <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+       clock-names = "dma", "dmamux0";
+       clocks = <&pcc2 IMX7ULP_CLK_DMA1>,
+                <&pcc2 IMX7ULP_CLK_DMA_MUX1>;
+}; /* i.mx7ulp */
 
 * DMA clients
 DMA client drivers that uses the DMA function must use the format described
index 6a0ff90..da371c4 100644 (file)
@@ -7,6 +7,7 @@ Required properties:
 
 - compatible:          Must be one of
                         "fsl,ls1021a-qdma": for LS1021A Board
+                        "fsl,ls1028a-qdma": for LS1028A Board
                         "fsl,ls1043a-qdma": for ls1043A Board
                         "fsl,ls1046a-qdma": for ls1046A Board
 - reg:                 Should contain the register's base address and length.
diff --git a/Documentation/devicetree/bindings/dma/mtk-uart-apdma.txt b/Documentation/devicetree/bindings/dma/mtk-uart-apdma.txt
new file mode 100644 (file)
index 0000000..5d6f98c
--- /dev/null
@@ -0,0 +1,54 @@
+* Mediatek UART APDMA Controller
+
+Required properties:
+- compatible should contain:
+  * "mediatek,mt2712-uart-dma" for MT2712 compatible APDMA
+  * "mediatek,mt6577-uart-dma" for MT6577 and all of the above
+
+- reg: The base address of the APDMA register bank.
+
+- interrupts: A single interrupt specifier.
+ One interrupt per dma-requests, or 8 if no dma-requests property is present
+
+- dma-requests: The number of DMA channels
+
+- clocks : Must contain an entry for each entry in clock-names.
+  See ../clocks/clock-bindings.txt for details.
+- clock-names: The APDMA clock for register accesses
+
+- mediatek,dma-33bits: Present if the DMA requires support
+
+Examples:
+
+       apdma: dma-controller@11000400 {
+               compatible = "mediatek,mt2712-uart-dma";
+               reg = <0 0x11000400 0 0x80>,
+                     <0 0x11000480 0 0x80>,
+                     <0 0x11000500 0 0x80>,
+                     <0 0x11000580 0 0x80>,
+                     <0 0x11000600 0 0x80>,
+                     <0 0x11000680 0 0x80>,
+                     <0 0x11000700 0 0x80>,
+                     <0 0x11000780 0 0x80>,
+                     <0 0x11000800 0 0x80>,
+                     <0 0x11000880 0 0x80>,
+                     <0 0x11000900 0 0x80>,
+                     <0 0x11000980 0 0x80>;
+               interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_SPI 104 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_SPI 105 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_SPI 106 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_SPI 107 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_SPI 108 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_SPI 109 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_SPI 110 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_SPI 111 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_SPI 112 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_SPI 113 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_SPI 114 IRQ_TYPE_LEVEL_LOW>;
+               dma-requests = <12>;
+               clocks = <&pericfg CLK_PERI_AP_DMA>;
+               clock-names = "apdma";
+               mediatek,dma-33bits;
+               #dma-cells = <1>;
+       };
index 7fccc20..cae31f4 100644 (file)
@@ -28,12 +28,17 @@ Example:
        };
 
 ------------------------------------------------------------------------------
-For A64 DMA controller:
+For A64 and H6 DMA controller:
 
 Required properties:
-- compatible:  "allwinner,sun50i-a64-dma"
+- compatible:  Must be one of
+                 "allwinner,sun50i-a64-dma"
+                 "allwinner,sun50i-h6-dma"
 - dma-channels: Number of DMA channels supported by the controller.
                Refer to Documentation/devicetree/bindings/dma/dma.txt
+- clocks:      In addition to parent AHB clock, it should also contain mbus
+               clock (H6 only)
+- clock-names: Should contain "bus" and "mbus" (H6 only)
 - all properties above, i.e. reg, interrupts, clocks, resets and #dma-cells
 
 Optional properties:
index e5ad3b2..9b298ed 100644 (file)
@@ -17,6 +17,7 @@ Required properties:
   * which must be preceded by one of the following vendor specifics:
     + "allwinner,sun50i-h6-mali"
     + "amlogic,meson-gxm-mali"
+    + "samsung,exynos5433-mali"
     + "rockchip,rk3288-mali"
     + "rockchip,rk3399-mali"
 
index ae63f09..b352a68 100644 (file)
@@ -17,6 +17,7 @@ Required properties:
       + amlogic,meson8b-mali
       + amlogic,meson-gxbb-mali
       + amlogic,meson-gxl-mali
+      + samsung,exynos4210-mali
       + rockchip,rk3036-mali
       + rockchip,rk3066-mali
       + rockchip,rk3188-mali
index 2c9804f..8d365f8 100644 (file)
@@ -1,12 +1,16 @@
-OMAP4+ HwSpinlock Driver
-========================
+TI HwSpinlock for OMAP and K3 based SoCs
+=========================================
 
 Required properties:
-- compatible:          Should be "ti,omap4-hwspinlock" for
-                           OMAP44xx, OMAP54xx, AM33xx, AM43xx, DRA7xx SoCs
+- compatible:          Should be one of the following,
+                         "ti,omap4-hwspinlock" for
+                               OMAP44xx, OMAP54xx, AM33xx, AM43xx, DRA7xx SoCs
+                         "ti,am654-hwspinlock" for
+                               K3 AM65x and J721E SoCs
 - reg:                 Contains the hwspinlock module register address space
                        (base address and length)
 - ti,hwmods:           Name of the hwmod associated with the hwspinlock device
+                       (for OMAP architecture based SoCs only)
 - #hwlock-cells:       Should be 1. The OMAP hwspinlock users will use a
                        0-indexed relative hwlock number as the argument
                        specifier value for requesting a specific hwspinlock
@@ -17,10 +21,21 @@ Please look at the generic hwlock binding for usage information for consumers,
 
 Example:
 
-/* OMAP4 */
+1. OMAP4 SoCs
 hwspinlock: spinlock@4a0f6000 {
        compatible = "ti,omap4-hwspinlock";
        reg = <0x4a0f6000 0x1000>;
        ti,hwmods = "spinlock";
        #hwlock-cells = <1>;
 };
+
+2. AM65x SoCs and J721E SoCs
+&cbass_main {
+       cbass_main_navss: interconnect0 {
+               hwspinlock: spinlock@30e00000 {
+                       compatible = "ti,am654-hwspinlock";
+                       reg = <0x00 0x30e00000 0x00 0x1000>;
+                       #hwlock-cells = <1>;
+               };
+       };
+};
index cf494a0..9692b7f 100644 (file)
@@ -114,42 +114,47 @@ patternProperties:
 
 examples:
   - |
-    adc@0 {
-      compatible = "adi,ad7124-4";
-      reg = <0>;
-      spi-max-frequency = <5000000>;
-      interrupts = <25 2>;
-      interrupt-parent = <&gpio>;
-      refin1-supply = <&adc_vref>;
-      clocks = <&ad7124_mclk>;
-      clock-names = "mclk";
-
+    spi {
       #address-cells = <1>;
       #size-cells = <0>;
 
-      channel@0 {
+      adc@0 {
+        compatible = "adi,ad7124-4";
         reg = <0>;
-        diff-channels = <0 1>;
-        adi,reference-select = <0>;
-        adi,buffered-positive;
-      };
-
-      channel@1 {
-        reg = <1>;
-        bipolar;
-        diff-channels = <2 3>;
-        adi,reference-select = <0>;
-        adi,buffered-positive;
-        adi,buffered-negative;
-      };
-
-      channel@2 {
-        reg = <2>;
-        diff-channels = <4 5>;
-      };
-
-      channel@3 {
-        reg = <3>;
-        diff-channels = <6 7>;
+        spi-max-frequency = <5000000>;
+        interrupts = <25 2>;
+        interrupt-parent = <&gpio>;
+        refin1-supply = <&adc_vref>;
+        clocks = <&ad7124_mclk>;
+        clock-names = "mclk";
+
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        channel@0 {
+          reg = <0>;
+          diff-channels = <0 1>;
+          adi,reference-select = <0>;
+          adi,buffered-positive;
+        };
+
+        channel@1 {
+          reg = <1>;
+          bipolar;
+          diff-channels = <2 3>;
+          adi,reference-select = <0>;
+          adi,buffered-positive;
+          adi,buffered-negative;
+        };
+
+        channel@2 {
+          reg = <2>;
+          diff-channels = <4 5>;
+        };
+
+        channel@3 {
+          reg = <3>;
+          diff-channels = <6 7>;
+        };
       };
     };
index 8a4100c..d76ece9 100644 (file)
@@ -61,6 +61,6 @@ examples:
         compatible = "avia,hx711";
         sck-gpios = <&gpio3 10 GPIO_ACTIVE_HIGH>;
         dout-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>;
-        avdd-suppy = <&avdd>;
+        avdd-supply = <&avdd>;
         clock-frequency = <100000>;
     };
index 496125c..507b737 100644 (file)
@@ -5,6 +5,7 @@ Required properties:
  - compatible: should be one of the following string:
                "allwinner,sun4i-a10-lradc-keys"
                "allwinner,sun8i-a83t-r-lradc"
+               "allwinner,sun50i-a64-lradc", "allwinner,sun8i-a83t-r-lradc"
  - reg: mmio address range of the chip
  - interrupts: interrupt to which the chip is connected
  - vref-supply: powersupply for the lradc reference voltage
diff --git a/Documentation/devicetree/bindings/misc/fsl,dpaa2-console.txt b/Documentation/devicetree/bindings/misc/fsl,dpaa2-console.txt
new file mode 100644 (file)
index 0000000..1442ba5
--- /dev/null
@@ -0,0 +1,11 @@
+DPAA2 console support
+
+Required properties:
+
+    - compatible
+        Value type: <string>
+        Definition: Must be "fsl,dpaa2-console".
+    - reg
+        Value type: <prop-encoded-array>
+        Definition: A standard property.  Specifies the region where the MCFBA
+                    (MC firmware base address) register can be found.
index e5a4115..b5b3cf5 100644 (file)
@@ -55,6 +55,7 @@ patternProperties:
   "^pinctrl-[0-9]+$": true
 
   "^nand@[a-f0-9]+$":
+    type: object
     properties:
       reg:
         minimum: 0
index 199ba5a..d261b70 100644 (file)
@@ -40,6 +40,7 @@ properties:
 
 patternProperties:
   "^nand@[a-f0-9]$":
+    type: object
     properties:
       reg:
         description:
index 9936b9e..b463e12 100644 (file)
@@ -6,6 +6,7 @@ Required properties:
              "renesas,can-r8a7744" if CAN controller is a part of R8A7744 SoC.
              "renesas,can-r8a7745" if CAN controller is a part of R8A7745 SoC.
              "renesas,can-r8a774a1" if CAN controller is a part of R8A774A1 SoC.
+             "renesas,can-r8a774c0" if CAN controller is a part of R8A774C0 SoC.
              "renesas,can-r8a7778" if CAN controller is a part of R8A7778 SoC.
              "renesas,can-r8a7779" if CAN controller is a part of R8A7779 SoC.
              "renesas,can-r8a7790" if CAN controller is a part of R8A7790 SoC.
@@ -27,13 +28,8 @@ Required properties:
 
 - reg: physical base address and size of the R-Car CAN register map.
 - interrupts: interrupt specifier for the sole interrupt.
-- clocks: phandles and clock specifiers for 2 CAN clock inputs for RZ/G2
-         devices.
-         phandles and clock specifiers for 3 CAN clock inputs for every other
-         SoC.
-- clock-names: 2 clock input name strings for RZ/G2: "clkp1", "can_clk".
-              3 clock input name strings for every other SoC: "clkp1", "clkp2",
-              "can_clk".
+- clocks: phandles and clock specifiers for 3 CAN clock inputs.
+- clock-names: 3 clock input name strings: "clkp1", "clkp2", and "can_clk".
 - pinctrl-0: pin control group to be used for this controller.
 - pinctrl-names: must be "default".
 
@@ -49,8 +45,7 @@ using the below properties:
 Optional properties:
 - renesas,can-clock-select: R-Car CAN Clock Source Select. Valid values are:
                            <0x0> (default) : Peripheral clock (clkp1)
-                           <0x1> : Peripheral clock (clkp2) (not supported by
-                                   RZ/G2 devices)
+                           <0x1> : Peripheral clock (clkp2)
                            <0x3> : External input clock
 
 Example
index ac71daa..32f051f 100644 (file)
@@ -3,11 +3,14 @@ Renesas R-Car CAN FD controller Device Tree Bindings
 
 Required properties:
 - compatible: Must contain one or more of the following:
-  - "renesas,rcar-gen3-canfd" for R-Car Gen3 compatible controller.
+  - "renesas,rcar-gen3-canfd" for R-Car Gen3 and RZ/G2 compatible controllers.
+  - "renesas,r8a774c0-canfd" for R8A774C0 (RZ/G2E) compatible controller.
   - "renesas,r8a7795-canfd" for R8A7795 (R-Car H3) compatible controller.
   - "renesas,r8a7796-canfd" for R8A7796 (R-Car M3-W) compatible controller.
+  - "renesas,r8a77965-canfd" for R8A77965 (R-Car M3-N) compatible controller.
   - "renesas,r8a77970-canfd" for R8A77970 (R-Car V3M) compatible controller.
   - "renesas,r8a77980-canfd" for R8A77980 (R-Car V3H) compatible controller.
+  - "renesas,r8a77990-canfd" for R8A77990 (R-Car E3) compatible controller.
 
   When compatible with the generic version, nodes must list the
   SoC-specific version corresponding to the platform first, followed by the
@@ -26,12 +29,13 @@ The name of the child nodes are "channel0" and "channel1" respectively. Each
 child node supports the "status" property only, which is used to
 enable/disable the respective channel.
 
-Required properties for "renesas,r8a7795-canfd" and "renesas,r8a7796-canfd"
+Required properties for "renesas,r8a774c0-canfd", "renesas,r8a7795-canfd",
+"renesas,r8a7796-canfd", "renesas,r8a77965-canfd", and "renesas,r8a77990-canfd"
 compatible:
-In R8A7795 and R8A7796 SoCs, canfd clock is a div6 clock and can be used by both
-CAN and CAN FD controller at the same time. It needs to be scaled to maximum
-frequency if any of these controllers use it. This is done using the below
-properties:
+In R8A774C0, R8A7795, R8A7796, R8A77965, and R8A77990 SoCs, canfd clock is a
+div6 clock and can be used by both CAN and CAN FD controller at the same time.
+It needs to be scaled to maximum frequency if any of these controllers use it.
+This is done using the below properties:
 
 - assigned-clocks: phandle of canfd clock.
 - assigned-clock-rates: maximum frequency of this clock.
index a403b81..c4eb389 100644 (file)
@@ -1,5 +1,5 @@
 This document explains only the device tree data binding. For general
-information about PHY subsystem refer to Documentation/phy.txt
+information about PHY subsystem refer to Documentation/driver-api/phy/phy.rst
 
 PHY device node
 ===============
index 93fc09c..d80e36a 100644 (file)
@@ -15,4 +15,4 @@ Example:
        };
 
 This document explains the device tree binding. For general
-information about PHY subsystem refer to Documentation/phy.txt
+information about PHY subsystem refer to Documentation/driver-api/phy/phy.rst
index 61a110a..125599a 100644 (file)
@@ -22,7 +22,9 @@ description: |+
 
 properties:
   compatible:
-    enum: [ aspeed,ast2400-pinctrl, aspeed,g4-pinctrl ]
+    enum:
+      - aspeed,ast2400-pinctrl
+      - aspeed,g4-pinctrl
 
 patternProperties:
   '^.*$':
index cf561bd..3e6d853 100644 (file)
@@ -22,7 +22,9 @@ description: |+
 
 properties:
   compatible:
-    enum: [ aspeed,ast2500-pinctrl, aspeed,g5-pinctrl ]
+    enum:
+      - aspeed,ast2500-pinctrl
+      - aspeed,g5-pinctrl
   aspeed,external-nodes:
     minItems: 2
     maxItems: 2
@@ -74,9 +76,6 @@ required:
 
 examples:
   - |
-    compatible = "simple-bus";
-    ranges;
-
     apb {
         compatible = "simple-bus";
         #address-cells = <1>;
@@ -89,7 +88,7 @@ examples:
 
             pinctrl: pinctrl {
                 compatible = "aspeed,g5-pinctrl";
-                aspeed,external-nodes = <&gfx &lhc>;
+                aspeed,external-nodes = <&gfx>, <&lhc>;
 
                 pinctrl_i2c3_default: i2c3_default {
                     function = "I2C3";
index 06c4b66..91d3e78 100644 (file)
@@ -55,6 +55,7 @@ properties:
 
 patternProperties:
   '^gpio@[0-9a-f]*$':
+    type: object
     properties:
       gpio-controller: true
       '#gpio-cells':
@@ -113,8 +114,10 @@ patternProperties:
       - st,bank-name
 
   '-[0-9]*$':
+    type: object
     patternProperties:
       '^pins':
+        type: object
         description: |
           A pinctrl node should contain at least one subnode representing the
           pinctrl group available on the machine. Each subnode will list the
@@ -194,6 +197,7 @@ required:
 examples:
   - |
     #include <dt-bindings/pinctrl/stm32-pinfunc.h>
+    #include <dt-bindings/mfd/stm32f4-rcc.h>
     //Example 1
       pinctrl@40020000 {
               #address-cells = <1>;
@@ -207,6 +211,7 @@ examples:
                       #gpio-cells = <2>;
                       reg = <0x0 0x400>;
                       resets = <&reset_ahb1 0>;
+                      clocks = <&rcc 0 STM32F4_AHB1_CLOCK(GPIOA)>;
                       st,bank-name = "GPIOA";
               };
        };
@@ -224,6 +229,7 @@ examples:
                       #gpio-cells = <2>;
                       reg = <0x1000 0x400>;
                       resets = <&reset_ahb1 0>;
+                      clocks = <&rcc 0 STM32F4_AHB1_CLOCK(GPIOB)>;
                       st,bank-name = "GPIOB";
                       gpio-ranges = <&pinctrl 0 0 16>;
               };
@@ -233,6 +239,7 @@ examples:
                       #gpio-cells = <2>;
                       reg = <0x2000 0x400>;
                       resets = <&reset_ahb1 0>;
+                      clocks = <&rcc 0 STM32F4_AHB1_CLOCK(GPIOC)>;
                       st,bank-name = "GPIOC";
                       ngpios = <5>;
                       gpio-ranges = <&pinctrl 0 16 3>,
index 980e541..eb35b22 100644 (file)
@@ -6,6 +6,8 @@ which then translates it into a corresponding voltage on a rail
 Required Properties:
  - compatible: Should be one of the following
        * qcom,msm8996-rpmpd: RPM Power domain for the msm8996 family of SoC
+       * qcom,msm8998-rpmpd: RPM Power domain for the msm8998 family of SoC
+       * qcom,qcs404-rpmpd: RPM Power domain for the qcs404 family of SoC
        * qcom,sdm845-rpmhpd: RPMh Power domain for the sdm845 family of SoC
  - #power-domain-cells: number of cells in Power domain specifier
        must be 1.
diff --git a/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml b/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml
new file mode 100644 (file)
index 0000000..0ac52f8
--- /dev/null
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pwm/allwinner,sun4i-a10-pwm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A10 PWM Device Tree Bindings
+
+maintainers:
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <maxime.ripard@bootlin.com>
+
+properties:
+  "#pwm-cells":
+    const: 3
+
+  compatible:
+    oneOf:
+      - const: allwinner,sun4i-a10-pwm
+      - const: allwinner,sun5i-a10s-pwm
+      - const: allwinner,sun5i-a13-pwm
+      - const: allwinner,sun7i-a20-pwm
+      - const: allwinner,sun8i-h3-pwm
+      - items:
+          - const: allwinner,sun8i-a83t-pwm
+          - const: allwinner,sun8i-h3-pwm
+      - items:
+          - const: allwinner,sun50i-a64-pwm
+          - const: allwinner,sun5i-a13-pwm
+      - items:
+          - const: allwinner,sun50i-h5-pwm
+          - const: allwinner,sun5i-a13-pwm
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+required:
+  - "#pwm-cells"
+  - compatible
+  - reg
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    pwm: pwm@1c20e00 {
+        compatible = "allwinner,sun7i-a20-pwm";
+        reg = <0x01c20e00 0xc>;
+        clocks = <&osc24M>;
+        #pwm-cells = <3>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/pwm/pwm-sun4i.txt b/Documentation/devicetree/bindings/pwm/pwm-sun4i.txt
deleted file mode 100644 (file)
index 2a1affb..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-Allwinner sun4i and sun7i SoC PWM controller
-
-Required properties:
-  - compatible: should be one of:
-    - "allwinner,sun4i-a10-pwm"
-    - "allwinner,sun5i-a10s-pwm"
-    - "allwinner,sun5i-a13-pwm"
-    - "allwinner,sun7i-a20-pwm"
-    - "allwinner,sun8i-h3-pwm"
-    - "allwinner,sun50i-a64-pwm", "allwinner,sun5i-a13-pwm"
-    - "allwinner,sun50i-h5-pwm", "allwinner,sun5i-a13-pwm"
-  - reg: physical base address and length of the controller's registers
-  - #pwm-cells: should be 3. See pwm.txt in this directory for a description of
-    the cells format.
-  - clocks: From common clock binding, handle to the parent clock.
-
-Example:
-
-       pwm: pwm@1c20e00 {
-               compatible = "allwinner,sun7i-a20-pwm";
-               reg = <0x01c20e00 0xc>;
-               clocks = <&osc24M>;
-               #pwm-cells = <3>;
-       };
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,adsp-pil.txt b/Documentation/devicetree/bindings/remoteproc/qcom,adsp-pil.txt
deleted file mode 100644 (file)
index 66af2c3..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-Qualcomm Technology Inc. ADSP Peripheral Image Loader
-
-This document defines the binding for a component that loads and boots firmware
-on the Qualcomm Technology Inc. ADSP Hexagon core.
-
-- compatible:
-       Usage: required
-       Value type: <string>
-       Definition: must be one of:
-                   "qcom,sdm845-adsp-pil"
-
-- reg:
-       Usage: required
-       Value type: <prop-encoded-array>
-       Definition: must specify the base address and size of the qdsp6ss register
-
-- interrupts-extended:
-       Usage: required
-       Value type: <prop-encoded-array>
-       Definition: must list the watchdog, fatal IRQs ready, handover and
-                   stop-ack IRQs
-
-- interrupt-names:
-       Usage: required
-       Value type: <stringlist>
-       Definition: must be "wdog", "fatal", "ready", "handover", "stop-ack"
-
-- clocks:
-       Usage: required
-       Value type: <prop-encoded-array>
-       Definition:  List of 8 phandle and clock specifier pairs for the adsp.
-
-- clock-names:
-       Usage: required
-       Value type: <stringlist>
-       Definition: List of clock input name strings sorted in the same
-                   order as the clocks property. Definition must have
-                   "xo", "sway_cbcr", "lpass_ahbs_aon_cbcr",
-                   "lpass_ahbm_aon_cbcr", "qdsp6ss_xo", "qdsp6ss_sleep"
-                   and "qdsp6ss_core".
-
-- power-domains:
-       Usage: required
-       Value type: <phandle>
-       Definition: reference to cx power domain node.
-
-- resets:
-       Usage: required
-       Value type: <phandle>
-       Definition: reference to the list of 2 reset-controller for the adsp.
-
-- reset-names:
-        Usage: required
-        Value type: <stringlist>
-        Definition: must be "pdc_sync" and "cc_lpass"
-
-- qcom,halt-regs:
-       Usage: required
-       Value type: <prop-encoded-array>
-       Definition: a phandle reference to a syscon representing TCSR followed
-                       by the offset within syscon for lpass halt register.
-
-- memory-region:
-       Usage: required
-       Value type: <phandle>
-       Definition: reference to the reserved-memory for the ADSP
-
-- qcom,smem-states:
-       Usage: required
-       Value type: <phandle>
-       Definition: reference to the smem state for requesting the ADSP to
-                   shut down
-
-- qcom,smem-state-names:
-       Usage: required
-       Value type: <stringlist>
-       Definition: must be "stop"
-
-
-= SUBNODES
-The adsp node may have an subnode named "glink-edge" that describes the
-communication edge, channels and devices related to the ADSP.
-See ../soc/qcom/qcom,glink.txt for details on how to describe these.
-
-= EXAMPLE
-The following example describes the resources needed to boot control the
-ADSP, as it is found on SDM845 boards.
-
-       remoteproc@17300000 {
-               compatible = "qcom,sdm845-adsp-pil";
-               reg = <0x17300000 0x40c>;
-
-               interrupts-extended = <&intc GIC_SPI 162 IRQ_TYPE_EDGE_RISING>,
-                       <&adsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
-                       <&adsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
-                       <&adsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
-                       <&adsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>;
-               interrupt-names = "wdog", "fatal", "ready",
-                       "handover", "stop-ack";
-
-               clocks = <&rpmhcc RPMH_CXO_CLK>,
-                       <&gcc GCC_LPASS_SWAY_CLK>,
-                       <&lpasscc LPASS_Q6SS_AHBS_AON_CLK>,
-                       <&lpasscc LPASS_Q6SS_AHBM_AON_CLK>,
-                       <&lpasscc LPASS_QDSP6SS_XO_CLK>,
-                       <&lpasscc LPASS_QDSP6SS_SLEEP_CLK>,
-                       <&lpasscc LPASS_QDSP6SS_CORE_CLK>;
-               clock-names = "xo", "sway_cbcr",
-                       "lpass_ahbs_aon_cbcr",
-                       "lpass_ahbm_aon_cbcr", "qdsp6ss_xo",
-                       "qdsp6ss_sleep", "qdsp6ss_core";
-
-               power-domains = <&rpmhpd SDM845_CX>;
-
-               resets = <&pdc_reset PDC_AUDIO_SYNC_RESET>,
-                        <&aoss_reset AOSS_CC_LPASS_RESTART>;
-               reset-names = "pdc_sync", "cc_lpass";
-
-               qcom,halt-regs = <&tcsr_mutex_regs 0x22000>;
-
-               memory-region = <&pil_adsp_mem>;
-
-               qcom,smem-states = <&adsp_smp2p_out 0>;
-               qcom,smem-state-names = "stop";
-       };
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,hexagon-v56.txt b/Documentation/devicetree/bindings/remoteproc/qcom,hexagon-v56.txt
new file mode 100644 (file)
index 0000000..1337a3d
--- /dev/null
@@ -0,0 +1,140 @@
+Qualcomm Technology Inc. Hexagon v56 Peripheral Image Loader
+
+This document defines the binding for a component that loads and boots firmware
+on the Qualcomm Technology Inc. Hexagon v56 core.
+
+- compatible:
+       Usage: required
+       Value type: <string>
+       Definition: must be one of:
+                   "qcom,qcs404-cdsp-pil",
+                   "qcom,sdm845-adsp-pil"
+
+- reg:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: must specify the base address and size of the qdsp6ss register
+
+- interrupts-extended:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: must list the watchdog, fatal IRQs ready, handover and
+                   stop-ack IRQs
+
+- interrupt-names:
+       Usage: required
+       Value type: <stringlist>
+       Definition: must be "wdog", "fatal", "ready", "handover", "stop-ack"
+
+- clocks:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition:  List of phandles and clock specifier pairs for the Hexagon,
+                    per clock-names below.
+
+- clock-names:
+       Usage: required for SDM845 ADSP
+       Value type: <stringlist>
+       Definition: List of clock input name strings sorted in the same
+                   order as the clocks property. Definition must have
+                   "xo", "sway_cbcr", "lpass_ahbs_aon_cbcr",
+                   "lpass_ahbm_aon_cbcr", "qdsp6ss_xo", "qdsp6ss_sleep"
+                   and "qdsp6ss_core".
+
+- clock-names:
+       Usage: required for QCS404 CDSP
+       Value type: <stringlist>
+       Definition: List of clock input name strings sorted in the same
+                   order as the clocks property. Definition must have
+                   "xo", "sway", "tbu", "bimc", "ahb_aon", "q6ss_slave",
+                   "q6ss_master", "q6_axim".
+
+- power-domains:
+       Usage: required
+       Value type: <phandle>
+       Definition: reference to cx power domain node.
+
+- resets:
+       Usage: required
+       Value type: <phandle>
+       Definition: reference to the list of resets for the Hexagon.
+
+- reset-names:
+        Usage: required for SDM845 ADSP
+        Value type: <stringlist>
+        Definition: must be "pdc_sync" and "cc_lpass"
+
+- reset-names:
+        Usage: required for QCS404 CDSP
+        Value type: <stringlist>
+        Definition: must be "restart"
+
+- qcom,halt-regs:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: a phandle reference to a syscon representing TCSR followed
+                   by the offset within syscon for Hexagon halt register.
+
+- memory-region:
+       Usage: required
+       Value type: <phandle>
+       Definition: reference to the reserved-memory for the firmware
+
+- qcom,smem-states:
+       Usage: required
+       Value type: <phandle>
+       Definition: reference to the smem state for requesting the Hexagon to
+                   shut down
+
+- qcom,smem-state-names:
+       Usage: required
+       Value type: <stringlist>
+       Definition: must be "stop"
+
+
+= SUBNODES
+The adsp node may have an subnode named "glink-edge" that describes the
+communication edge, channels and devices related to the Hexagon.
+See ../soc/qcom/qcom,glink.txt for details on how to describe these.
+
+= EXAMPLE
+The following example describes the resources needed to boot control the
+ADSP, as it is found on SDM845 boards.
+
+       remoteproc@17300000 {
+               compatible = "qcom,sdm845-adsp-pil";
+               reg = <0x17300000 0x40c>;
+
+               interrupts-extended = <&intc GIC_SPI 162 IRQ_TYPE_EDGE_RISING>,
+                       <&adsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
+                       <&adsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
+                       <&adsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
+                       <&adsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>;
+               interrupt-names = "wdog", "fatal", "ready",
+                       "handover", "stop-ack";
+
+               clocks = <&rpmhcc RPMH_CXO_CLK>,
+                       <&gcc GCC_LPASS_SWAY_CLK>,
+                       <&lpasscc LPASS_Q6SS_AHBS_AON_CLK>,
+                       <&lpasscc LPASS_Q6SS_AHBM_AON_CLK>,
+                       <&lpasscc LPASS_QDSP6SS_XO_CLK>,
+                       <&lpasscc LPASS_QDSP6SS_SLEEP_CLK>,
+                       <&lpasscc LPASS_QDSP6SS_CORE_CLK>;
+               clock-names = "xo", "sway_cbcr",
+                       "lpass_ahbs_aon_cbcr",
+                       "lpass_ahbm_aon_cbcr", "qdsp6ss_xo",
+                       "qdsp6ss_sleep", "qdsp6ss_core";
+
+               power-domains = <&rpmhpd SDM845_CX>;
+
+               resets = <&pdc_reset PDC_AUDIO_SYNC_RESET>,
+                        <&aoss_reset AOSS_CC_LPASS_RESTART>;
+               reset-names = "pdc_sync", "cc_lpass";
+
+               qcom,halt-regs = <&tcsr_mutex_regs 0x22000>;
+
+               memory-region = <&pil_adsp_mem>;
+
+               qcom,smem-states = <&adsp_smp2p_out 0>;
+               qcom,smem-state-names = "stop";
+       };
diff --git a/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt b/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt
new file mode 100644 (file)
index 0000000..5fa915a
--- /dev/null
@@ -0,0 +1,63 @@
+STMicroelectronics STM32 Remoteproc
+-----------------------------------
+This document defines the binding for the remoteproc component that loads and
+boots firmwares on the ST32MP family chipset.
+
+Required properties:
+- compatible:  Must be "st,stm32mp1-m4"
+- reg:         Address ranges of the RETRAM and MCU SRAM memories used by the
+               remote processor.
+- resets:      Reference to a reset controller asserting the remote processor.
+- st,syscfg-holdboot: Reference to the system configuration which holds the
+               remote processor reset hold boot
+       1st cell: phandle of syscon block
+       2nd cell: register offset containing the hold boot setting
+       3rd cell: register bitmask for the hold boot field
+- st,syscfg-tz: Reference to the system configuration which holds the RCC trust
+               zone mode
+       1st cell: phandle to syscon block
+       2nd cell: register offset containing the RCC trust zone mode setting
+       3rd cell: register bitmask for the RCC trust zone mode bit
+
+Optional properties:
+- interrupts:  Should contain the watchdog interrupt
+- mboxes:      This property is required only if the rpmsg/virtio functionality
+               is used. List of phandle and mailbox channel specifiers:
+               - a channel (a) used to communicate through virtqueues with the
+                 remote proc.
+                 Bi-directional channel:
+                     - from local to remote = send message
+                     - from remote to local = send message ack
+               - a channel (b) working the opposite direction of channel (a)
+               - a channel (c) used by the local proc to notify the remote proc
+                 that it is about to be shut down.
+                 Unidirectional channel:
+                     - from local to remote, where ACK from the remote means
+                       that it is ready for shutdown
+- mbox-names:  This property is required if the mboxes property is used.
+               - must be "vq0" for channel (a)
+               - must be "vq1" for channel (b)
+               - must be "shutdown" for channel (c)
+- memory-region: List of phandles to the reserved memory regions associated with
+               the remoteproc device. This is variable and describes the
+               memories shared with the remote processor (eg: remoteproc
+               firmware and carveouts, rpmsg vrings, ...).
+               (see ../reserved-memory/reserved-memory.txt)
+- st,syscfg-pdds: Reference to the system configuration which holds the remote
+               processor deep sleep setting
+       1st cell: phandle to syscon block
+       2nd cell: register offset containing the deep sleep setting
+       3rd cell: register bitmask for the deep sleep bit
+- st,auto-boot:        If defined, when remoteproc is probed, it loads the default
+               firmware and starts the remote processor.
+
+Example:
+       m4_rproc: m4@10000000 {
+               compatible = "st,stm32mp1-m4";
+               reg = <0x10000000 0x40000>,
+                     <0x30000000 0x40000>,
+                     <0x38000000 0x10000>;
+               resets = <&rcc MCU_R>;
+               st,syscfg-holdboot = <&rcc 0x10C 0x1>;
+               st,syscfg-tz = <&rcc 0x000 0x1>;
+       };
diff --git a/Documentation/devicetree/bindings/reset/bitmain,bm1880-reset.txt b/Documentation/devicetree/bindings/reset/bitmain,bm1880-reset.txt
new file mode 100644 (file)
index 0000000..a6f8455
--- /dev/null
@@ -0,0 +1,18 @@
+Bitmain BM1880 SoC Reset Controller
+===================================
+
+Please also refer to reset.txt in this directory for common reset
+controller binding usage.
+
+Required properties:
+- compatible:   Should be "bitmain,bm1880-reset"
+- reg:          Offset and length of reset controller space in SCTRL.
+- #reset-cells: Must be 1.
+
+Example:
+
+        rst: reset-controller@c00 {
+                compatible = "bitmain,bm1880-reset";
+                reg = <0xc00 0x8>;
+                #reset-cells = <1>;
+        };
index 2ecf338..13e0951 100644 (file)
@@ -45,6 +45,6 @@ Example:
         };
 
 
-For list of all valid reset indicies see
+For list of all valid reset indices see
 <dt-bindings/reset/imx7-reset.h> for i.MX7 and
 <dt-bindings/reset/imx8mq-reset.h> for i.MX8MQ
index f97a4ec..c899111 100644 (file)
@@ -10,97 +10,76 @@ maintainers:
   - Paul Walmsley <paul.walmsley@sifive.com>
   - Palmer Dabbelt <palmer@sifive.com>
 
-allOf:
-  - $ref: /schemas/cpus.yaml#
-
 properties:
-  $nodename:
-    const: cpus
-    description: Container of cpu nodes
-
-  '#address-cells':
-    const: 1
-    description: |
-      A single unsigned 32-bit integer uniquely identifies each RISC-V
-      hart in a system.  (See the "reg" node under the "cpu" node,
-      below).
-
-  '#size-cells':
-    const: 0
+  compatible:
+    items:
+      - enum:
+          - sifive,rocket0
+          - sifive,e5
+          - sifive,e51
+          - sifive,u54-mc
+          - sifive,u54
+          - sifive,u5
+      - const: riscv
+    description:
+      Identifies that the hart uses the RISC-V instruction set
+      and identifies the type of the hart.
+
+  mmu-type:
+    allOf:
+      - $ref: "/schemas/types.yaml#/definitions/string"
+      - enum:
+          - riscv,sv32
+          - riscv,sv39
+          - riscv,sv48
+    description:
+      Identifies the MMU address translation mode used on this
+      hart.  These values originate from the RISC-V Privileged
+      Specification document, available from
+      https://riscv.org/specifications/
+
+  riscv,isa:
+    allOf:
+      - $ref: "/schemas/types.yaml#/definitions/string"
+      - enum:
+          - rv64imac
+          - rv64imafdc
+    description:
+      Identifies the specific RISC-V instruction set architecture
+      supported by the hart.  These are documented in the RISC-V
+      User-Level ISA document, available from
+      https://riscv.org/specifications/
+
+  timebase-frequency:
+    type: integer
+    minimum: 1
+    description:
+      Specifies the clock frequency of the system timer in Hz.
+      This value is common to all harts on a single system image.
+
+  interrupt-controller:
+    type: object
+    description: Describes the CPU's local interrupt controller
 
-patternProperties:
-  '^cpu@[0-9a-f]+$':
     properties:
-      compatible:
-        type: array
-        items:
-          - enum:
-              - sifive,rocket0
-              - sifive,e5
-              - sifive,e51
-              - sifive,u54-mc
-              - sifive,u54
-              - sifive,u5
-          - const: riscv
-        description:
-          Identifies that the hart uses the RISC-V instruction set
-          and identifies the type of the hart.
-
-      mmu-type:
-        allOf:
-          - $ref: "/schemas/types.yaml#/definitions/string"
-          - enum:
-              - riscv,sv32
-              - riscv,sv39
-              - riscv,sv48
-        description:
-          Identifies the MMU address translation mode used on this
-          hart.  These values originate from the RISC-V Privileged
-          Specification document, available from
-          https://riscv.org/specifications/
-
-      riscv,isa:
-        allOf:
-          - $ref: "/schemas/types.yaml#/definitions/string"
-          - enum:
-              - rv64imac
-              - rv64imafdc
-        description:
-          Identifies the specific RISC-V instruction set architecture
-          supported by the hart.  These are documented in the RISC-V
-          User-Level ISA document, available from
-          https://riscv.org/specifications/
+      '#interrupt-cells':
+        const: 1
 
-      timebase-frequency:
-        type: integer
-        minimum: 1
-        description:
-          Specifies the clock frequency of the system timer in Hz.
-          This value is common to all harts on a single system image.
-
-      interrupt-controller:
-        type: object
-        description: Describes the CPU's local interrupt controller
-
-        properties:
-          '#interrupt-cells':
-            const: 1
-
-          compatible:
-            const: riscv,cpu-intc
-
-          interrupt-controller: true
+      compatible:
+        const: riscv,cpu-intc
 
-        required:
-          - '#interrupt-cells'
-          - compatible
-          - interrupt-controller
+      interrupt-controller: true
 
     required:
-      - riscv,isa
-      - timebase-frequency
+      - '#interrupt-cells'
+      - compatible
       - interrupt-controller
 
+required:
+  - riscv,isa
+  - timebase-frequency
+  - interrupt-controller
+
 examples:
   - |
     // Example 1: SiFive Freedom U540G Development Kit
diff --git a/Documentation/devicetree/bindings/rtc/allwinner,sun4i-a10-rtc.yaml b/Documentation/devicetree/bindings/rtc/allwinner,sun4i-a10-rtc.yaml
new file mode 100644 (file)
index 0000000..46d69c3
--- /dev/null
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/allwinner,sun4i-a10-rtc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A10 RTC Device Tree Bindings
+
+allOf:
+  - $ref: "rtc.yaml#"
+
+maintainers:
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <maxime.ripard@bootlin.com>
+
+properties:
+  compatible:
+    enum:
+      - allwinner,sun4i-a10-rtc
+      - allwinner,sun7i-a20-rtc
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    rtc: rtc@1c20d00 {
+        compatible = "allwinner,sun4i-a10-rtc";
+        reg = <0x01c20d00 0x20>;
+        interrupts = <24>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml b/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
new file mode 100644 (file)
index 0000000..924622f
--- /dev/null
@@ -0,0 +1,134 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/allwinner,sun6i-a31-rtc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A31 RTC Device Tree Bindings
+
+maintainers:
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <maxime.ripard@bootlin.com>
+
+properties:
+  "#clock-cells":
+    const: 1
+
+  compatible:
+    oneOf:
+      - const: allwinner,sun6i-a31-rtc
+      - const: allwinner,sun8i-a23-rtc
+      - const: allwinner,sun8i-h3-rtc
+      - const: allwinner,sun8i-r40-rtc
+      - const: allwinner,sun8i-v3-rtc
+      - const: allwinner,sun50i-h5-rtc
+      - items:
+          - const: allwinner,sun50i-a64-rtc
+          - const: allwinner,sun8i-h3-rtc
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    minItems: 1
+    maxItems: 2
+    items:
+      - description: RTC Alarm 0
+      - description: RTC Alarm 1
+
+  clocks:
+    maxItems: 1
+
+  clock-output-names:
+    minItems: 1
+    maxItems: 3
+    description:
+      The RTC provides up to three clocks
+        - the Low Frequency Oscillator or LOSC, at index 0,
+        - the Low Frequency Oscillator External output (X32KFOUT in
+          the datasheet), at index 1,
+        - the Internal Oscillator, at index 2.
+
+allOf:
+  - $ref: "rtc.yaml#"
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: allwinner,sun6i-a31-rtc
+
+    then:
+      properties:
+        clock-output-names:
+          minItems: 1
+          maxItems: 1
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - allwinner,sun8i-a23-rtc
+              - allwinner,sun8i-r40-rtc
+              - allwinner,sun8i-v3-rtc
+
+    then:
+      properties:
+        clock-output-names:
+          minItems: 2
+          maxItems: 2
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - allwinner,sun8i-h3-rtc
+              - allwinner,sun50i-h5-rtc
+
+    then:
+      properties:
+        clock-output-names:
+          minItems: 3
+          maxItems: 3
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: allwinner,sun8i-r40-rtc
+
+    then:
+      properties:
+        interrupts:
+          minItems: 1
+          maxItems: 1
+
+    else:
+      properties:
+        interrupts:
+          minItems: 2
+          maxItems: 2
+
+required:
+  - "#clock-cells"
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-output-names
+
+additionalProperties: false
+
+examples:
+  - |
+    rtc: rtc@1f00000 {
+        compatible = "allwinner,sun6i-a31-rtc";
+        reg = <0x01f00000 0x400>;
+        interrupts = <0 40 4>, <0 41 4>;
+        clock-output-names = "osc32k";
+        clocks = <&ext_osc32k>;
+        #clock-cells = <1>;
+    };
+
+...
index a97fc6a..b8d36fc 100644 (file)
@@ -1,72 +1 @@
-Generic device tree bindings for Real Time Clock devices
-========================================================
-
-This document describes generic bindings which can be used to describe Real Time
-Clock devices in a device tree.
-
-Required properties
--------------------
-
-- compatible : name of RTC device following generic names recommended practice.
-
-For other required properties e.g. to describe register sets,
-clocks, etc. check the binding documentation of the specific driver.
-
-Optional properties
--------------------
-
-- start-year : if provided, the default hardware range supported by the RTC is
-               shifted so the first usable year is the specified one.
-
-The following properties may not be supported by all drivers. However, if a
-driver wants to support one of the below features, it should adapt the bindings
-below.
-- trickle-resistor-ohms :   Selected resistor for trickle charger. Should be given
-                            if trickle charger should be enabled
-- trickle-diode-disable :   Do not use internal trickle charger diode Should be
-                            given if internal trickle charger diode should be
-                            disabled
-- wakeup-source :           Enables wake up of host system on alarm
-- quartz-load-femtofarads : The capacitive load of the quartz(x-tal),
-                            expressed in femto Farad (fF).
-                            The default value shall be listed (if optional),
-                            and likewise all valid values.
-
-Trivial RTCs
-------------
-
-This is a list of trivial RTC devices that have simple device tree
-bindings, consisting only of a compatible field, an address and
-possibly an interrupt line.
-
-
-Compatible             Vendor / Chip
-==========             =============
-abracon,abb5zes3       AB-RTCMC-32.768kHz-B5ZE-S3: Real Time Clock/Calendar Module with I2C Interface
-abracon,abeoz9         AB-RTCMC-32.768kHz-EOZ9: Real Time Clock/Calendar Module with I2C Interface
-dallas,ds1374          I2C, 32-Bit Binary Counter Watchdog RTC with Trickle Charger and Reset Input/Output
-dallas,ds1672          Dallas DS1672 Real-time Clock
-dallas,ds3232          Extremely Accurate I²C RTC with Integrated Crystal and SRAM
-epson,rx8010           I2C-BUS INTERFACE REAL TIME CLOCK MODULE
-epson,rx8571           I2C-BUS INTERFACE REAL TIME CLOCK MODULE with Battery Backed RAM
-epson,rx8581           I2C-BUS INTERFACE REAL TIME CLOCK MODULE
-emmicro,em3027         EM Microelectronic EM3027 Real-time Clock
-isil,isl1208           Intersil ISL1208 Low Power RTC with Battery Backed SRAM
-isil,isl1218           Intersil ISL1218 Low Power RTC with Battery Backed SRAM
-isil,isl12022          Intersil ISL12022 Real-time Clock
-microcrystal,rv3028    Real Time Clock Module with I2C-Bus
-microcrystal,rv3029    Real Time Clock Module with I2C-Bus
-microcrystal,rv8523    Real Time Clock
-nxp,pcf2127            Real-time clock
-nxp,pcf2129            Real-time clock
-nxp,pcf8563            Real-time clock/calendar
-pericom,pt7c4338       Real-time Clock Module
-ricoh,r2025sd          I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
-ricoh,r2221tl          I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
-ricoh,rs5c372a         I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
-ricoh,rs5c372b         I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
-ricoh,rv5c386          I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
-ricoh,rv5c387a         I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
-sii,s35390a            2-wire CMOS real-time clock
-whwave,sd3078          I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
-xircom,x1205           Xircom X1205 I2C RTC
+This file has been moved to rtc.yaml.
diff --git a/Documentation/devicetree/bindings/rtc/rtc.yaml b/Documentation/devicetree/bindings/rtc/rtc.yaml
new file mode 100644 (file)
index 0000000..ee237b2
--- /dev/null
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/rtc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: RTC Generic Binding
+
+maintainers:
+  - Alexandre Belloni <alexandre.belloni@bootlin.com>
+
+description: |
+  This document describes generic bindings which can be used to
+  describe Real Time Clock devices in a device tree.
+
+properties:
+  $nodename:
+    pattern: "^rtc(@.*|-[0-9a-f])*$"
+
+  quartz-load-femtofarads:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      The capacitive load of the quartz(x-tal), expressed in femto
+      Farad (fF). The default value shall be listed (if optional),
+      and likewise all valid values.
+
+  start-year:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      If provided, the default hardware range supported by the RTC is
+      shifted so the first usable year is the specified one.
+
+  trickle-diode-disable:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      Do not use internal trickle charger diode. Should be given if
+      internal trickle charger diode should be disabled.
+
+  trickle-resistor-ohms:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Selected resistor for trickle charger. Should be given
+      if trickle charger should be enabled.
+
+  wakeup-source:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      Enables wake up of host system on alarm.
+
+...
diff --git a/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt b/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt
deleted file mode 100644 (file)
index 6b732c4..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-* sun6i Real Time Clock
-
-RTC controller for the Allwinner A31
-
-Required properties:
-- compatible   : Should be one of the following combinations:
-                   - "allwinner,sun6i-a31-rtc"
-                   - "allwinner,sun8i-a23-rtc"
-                   - "allwinner,sun8i-h3-rtc"
-                   - "allwinner,sun8i-r40-rtc", "allwinner,sun8i-h3-rtc"
-                   - "allwinner,sun8i-v3-rtc"
-                   - "allwinner,sun50i-a64-rtc", "allwinner,sun8i-h3-rtc"
-                   - "allwinner,sun50i-h5-rtc"
-
-                 Where there are two or more compatible strings, this
-                 denotes the hardware covered by the most specific one
-                 is backward-compatible with the latter ones, and the
-                 implementation for the latter ones can be used, albeit
-                 with reduced functionality.
-
-- reg          : physical base address of the controller and length of
-                 memory mapped region.
-- interrupts   : IRQ lines for the RTC alarm 0 and alarm 1, in that order.
-
-Required properties for new device trees
-- clocks       : phandle to the 32kHz external oscillator
-- clock-output-names : names of up to three clock outputs. See below.
-- #clock-cells  : must be equal to 1.
-
-The RTC provides the following clocks at the given indices:
-- 0: LOSC
-- 1: LOSC external output, known as X32KFOUT in the datasheet.
-     This clock is not available on the A31 and is deprecated for old
-     device trees still using the "allwinner,sun6i-a31-rtc" compatible.
-- 2: InternalOSC, or internal RC oscillator (A64/H3/H5 only)
-
-Example:
-
-rtc: rtc@1f00000 {
-       compatible = "allwinner,sun6i-a31-rtc";
-       reg = <0x01f00000 0x400>;
-       interrupts = <0 40 4>, <0 41 4>;
-       clock-output-names = "osc32k";
-       clocks = <&ext_osc32k>;
-       #clock-cells = <1>;
-};
diff --git a/Documentation/devicetree/bindings/rtc/sunxi-rtc.txt b/Documentation/devicetree/bindings/rtc/sunxi-rtc.txt
deleted file mode 100644 (file)
index 4a8d79c..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-* sun4i/sun7i Real Time Clock
-
-RTC controller for the Allwinner A10/A20
-
-Required properties:
-- compatible : Should be "allwinner,sun4i-a10-rtc" or "allwinner,sun7i-a20-rtc"
-- reg: physical base address of the controller and length of memory mapped
-  region.
-- interrupts: IRQ line for the RTC.
-
-Example:
-
-rtc: rtc@1c20d00 {
-       compatible = "allwinner,sun4i-a10-rtc";
-       reg = <0x01c20d00 0x20>;
-       interrupts = <24>;
-};
diff --git a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml
new file mode 100644 (file)
index 0000000..0c12ce9
--- /dev/null
@@ -0,0 +1,92 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/trivial-rtc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Trivial RTCs
+
+maintainers:
+  - Alexandre Belloni <alexandre.belloni@bootlin.com>
+
+description: |
+  This is a list of trivial RTC devices that have simple device tree
+  bindings, consisting only of a compatible field, an address and
+  possibly an interrupt line.
+
+allOf:
+  - $ref: "rtc.yaml#"
+
+properties:
+  compatible:
+    enum:
+      # AB-RTCMC-32.768kHz-B5ZE-S3: Real Time Clock/Calendar Module with I2C Interface
+      - abracon,abb5zes3
+      # AB-RTCMC-32.768kHz-EOZ9: Real Time Clock/Calendar Module with I2C Interface
+      - abracon,abeoz9
+      # I2C, 32-Bit Binary Counter Watchdog RTC with Trickle Charger and Reset Input/Output
+      - dallas,ds1374
+      # Dallas DS1672 Real-time Clock
+      - dallas,ds1672
+      # Extremely Accurate I²C RTC with Integrated Crystal and SRAM
+      - dallas,ds3232
+      # I2C-BUS INTERFACE REAL TIME CLOCK MODULE
+      - epson,rx8010
+      # I2C-BUS INTERFACE REAL TIME CLOCK MODULE with Battery Backed RAM
+      - epson,rx8571
+      # I2C-BUS INTERFACE REAL TIME CLOCK MODULE
+      - epson,rx8581
+      # Intersil ISL1208 Low Power RTC with Battery Backed SRAM
+      - isil,isl1208
+      # Intersil ISL1218 Low Power RTC with Battery Backed SRAM
+      - isil,isl1218
+      # Intersil ISL12022 Real-time Clock
+      - isil,isl12022
+      # Real Time Clock Module with I2C-Bus
+      - microcrystal,rv3028
+      # Real Time Clock Module with I2C-Bus
+      - microcrystal,rv3029
+      # Real Time Clock
+      - microcrystal,rv8523
+      # Real-time clock
+      - nxp,pcf2127
+      # Real-time clock
+      - nxp,pcf2129
+      # Real-time clock/calendar
+      - nxp,pcf8563
+      # Real-time Clock Module
+      - pericom,pt7c4338
+      # I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
+      - ricoh,r2025sd
+      # I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
+      - ricoh,r2221tl
+      # I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
+      - ricoh,rs5c372a
+      # I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
+      - ricoh,rs5c372b
+      # I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
+      - ricoh,rv5c386
+      # I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
+      - ricoh,rv5c387a
+      # 2-wire CMOS real-time clock
+      - sii,s35390a
+      # I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
+      - whwave,sd3078
+      # Xircom X1205 I2C RTC
+      - xircom,x1205
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  start-year: true
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+...
index 0a9b544..dcba86b 100644 (file)
@@ -1,6 +1,7 @@
 OMAP UART controller
 
 Required properties:
+- compatible : should be "ti,j721e-uart", "ti,am654-uart" for J721E controllers
 - compatible : should be "ti,am654-uart" for AM654 controllers
 - compatible : should be "ti,omap2-uart" for OMAP2 controllers
 - compatible : should be "ti,omap3-uart" for OMAP3 controllers
index 436d210..e876f3c 100644 (file)
@@ -2,8 +2,8 @@ Amlogic Canvas
 ================================
 
 A canvas is a collection of metadata that describes a pixel buffer.
-Those metadata include: width, height, phyaddr, wrapping, block mode
-and endianness.
+Those metadata include: width, height, phyaddr, wrapping and block mode.
+Starting with GXBB the endianness can also be described.
 
 Many IPs within Amlogic SoCs rely on canvas indexes to read/write pixel data
 rather than use the phy addresses directly. For instance, this is the case for
@@ -18,7 +18,11 @@ Video Lookup Table
 --------------------------
 
 Required properties:
-- compatible: "amlogic,canvas"
+- compatible: has to be one of:
+               - "amlogic,meson8-canvas", "amlogic,canvas" on Meson8
+               - "amlogic,meson8b-canvas", "amlogic,canvas" on Meson8b
+               - "amlogic,meson8m2-canvas", "amlogic,canvas" on Meson8m2
+               - "amlogic,canvas" on GXBB and newer
 - reg: Base physical address and size of the canvas registers.
 
 Example:
diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.txt
new file mode 100644 (file)
index 0000000..954ffee
--- /dev/null
@@ -0,0 +1,81 @@
+Qualcomm Always-On Subsystem side channel binding
+
+This binding describes the hardware component responsible for side channel
+requests to the always-on subsystem (AOSS), used for certain power management
+requests that is not handled by the standard RPMh interface. Each client in the
+SoC has it's own block of message RAM and IRQ for communication with the AOSS.
+The protocol used to communicate in the message RAM is known as Qualcomm
+Messaging Protocol (QMP)
+
+The AOSS side channel exposes control over a set of resources, used to control
+a set of debug related clocks and to affect the low power state of resources
+related to the secondary subsystems. These resources are exposed as a set of
+power-domains.
+
+- compatible:
+       Usage: required
+       Value type: <string>
+       Definition: must be "qcom,sdm845-aoss-qmp"
+
+- reg:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: the base address and size of the message RAM for this
+                   client's communication with the AOSS
+
+- interrupts:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: should specify the AOSS message IRQ for this client
+
+- mboxes:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: reference to the mailbox representing the outgoing doorbell
+                   in APCS for this client, as described in mailbox/mailbox.txt
+
+- #clock-cells:
+       Usage: optional
+       Value type: <u32>
+       Definition: must be 0
+                   The single clock represents the QDSS clock.
+
+- #power-domain-cells:
+       Usage: optional
+       Value type: <u32>
+       Definition: must be 1
+                   The provided power-domains are:
+                   CDSP state (0), LPASS state (1), modem state (2), SLPI
+                   state (3), SPSS state (4) and Venus state (5).
+
+= SUBNODES
+The AOSS side channel also provides the controls for three cooling devices,
+these are expressed as subnodes of the QMP node. The name of the node is used
+to identify the resource and must therefor be "cx", "mx" or "ebi".
+
+- #cooling-cells:
+       Usage: optional
+       Value type: <u32>
+       Definition: must be 2
+
+= EXAMPLE
+
+The following example represents the AOSS side-channel message RAM and the
+mechanism exposing the power-domains, as found in SDM845.
+
+  aoss_qmp: qmp@c300000 {
+         compatible = "qcom,sdm845-aoss-qmp";
+         reg = <0x0c300000 0x100000>;
+         interrupts = <GIC_SPI 389 IRQ_TYPE_EDGE_RISING>;
+         mboxes = <&apss_shared 0>;
+
+         #power-domain-cells = <1>;
+
+         cx_cdev: cx {
+               #cooling-cells = <2>;
+         };
+
+         mx_cdev: mx {
+               #cooling-cells = <2>;
+         };
+  };
index bcc612c..db50126 100644 (file)
@@ -9,7 +9,7 @@ used for audio/voice services on the QDSP.
        Value type: <stringlist>
        Definition: must be "qcom,apr-v<VERSION-NUMBER>", example "qcom,apr-v2"
 
-- reg
+- qcom,apr-domain
        Usage: required
        Value type: <u32>
        Definition: Destination processor ID.
@@ -49,9 +49,9 @@ by the individual bindings for the specific service
 The following example represents a QDSP based sound card on a MSM8996 device
 which uses apr as communication between Apps and QDSP.
 
-       apr@4 {
+       apr {
                compatible = "qcom,apr-v2";
-               reg = <APR_DOMAIN_ADSP>;
+               qcom,apr-domain = <APR_DOMAIN_ADSP>;
 
                q6core@3 {
                        compatible = "qcom,q6core";
index cf759e5..1214192 100644 (file)
@@ -21,6 +21,11 @@ edge.
        Definition: should specify the IRQ used by the remote processor to
                    signal this processor about communication related events
 
+- qcom,remote-pid:
+       Usage: required for glink-smem
+       Value type: <u32>
+       Definition: specifies the identifier of the remote endpoint of this edge
+
 - qcom,rpm-msg-ram:
        Usage: required for glink-rpm
        Value type: <prop-encoded-array>
index c374fd4..6d1329c 100644 (file)
@@ -50,6 +50,7 @@ properties:
 
 patternProperties:
   "^.*@[0-9a-f]+":
+    type: object
     properties:
       reg:
         items:
index bda7a5b..f36c46d 100644 (file)
@@ -55,6 +55,7 @@ properties:
 
 patternProperties:
   "^.*@[0-9a-f]+":
+    type: object
     properties:
       reg:
         items:
index c059445..c5220bc 100644 (file)
@@ -42,12 +42,18 @@ Required Properties:
     - "renesas,r8a7793-cmt1" for the 48-bit CMT1 device included in r8a7793.
     - "renesas,r8a7794-cmt0" for the 32-bit CMT0 device included in r8a7794.
     - "renesas,r8a7794-cmt1" for the 48-bit CMT1 device included in r8a7794.
+    - "renesas,r8a7795-cmt0" for the 32-bit CMT0 device included in r8a7795.
+    - "renesas,r8a7795-cmt1" for the 48-bit CMT1 device included in r8a7795.
     - "renesas,r8a7796-cmt0" for the 32-bit CMT0 device included in r8a7796.
     - "renesas,r8a7796-cmt1" for the 48-bit CMT1 device included in r8a7796.
+    - "renesas,r8a77965-cmt0" for the 32-bit CMT0 device included in r8a77965.
+    - "renesas,r8a77965-cmt1" for the 48-bit CMT1 device included in r8a77965.
     - "renesas,r8a77970-cmt0" for the 32-bit CMT0 device included in r8a77970.
     - "renesas,r8a77970-cmt1" for the 48-bit CMT1 device included in r8a77970.
     - "renesas,r8a77980-cmt0" for the 32-bit CMT0 device included in r8a77980.
     - "renesas,r8a77980-cmt1" for the 48-bit CMT1 device included in r8a77980.
+    - "renesas,r8a77990-cmt0" for the 32-bit CMT0 device included in r8a77990.
+    - "renesas,r8a77990-cmt1" for the 48-bit CMT1 device included in r8a77990.
 
     - "renesas,rcar-gen2-cmt0" for 32-bit CMT0 devices included in R-Car Gen2
                and RZ/G1.
index e45b38c..26c85af 100644 (file)
@@ -4,7 +4,7 @@ OHCI
 
 Required properties:
  - compatible: should be "samsung,s3c2410-ohci" for USB host controller
- - reg: address and lenght of the controller memory mapped region
+ - reg: address and length of the controller memory mapped region
  - interrupts: interrupt number for the USB OHCI controller
  - clocks: Should reference the bus and host clocks
  - clock-names: Should contain two strings
index eade302..6992bbb 100644 (file)
@@ -395,12 +395,16 @@ patternProperties:
     description: Holt Integrated Circuits, Inc.
   "^honeywell,.*":
     description: Honeywell
+  "^hoperun,.*":
+    description: Jiangsu HopeRun Software Co., Ltd.
   "^hp,.*":
     description: Hewlett Packard
   "^hsg,.*":
     description: HannStar Display Co.
   "^holtek,.*":
     description: Holtek Semiconductor, Inc.
+  "^hugsun,.*":
+    description: Shenzhen Hugsun Technology Co. Ltd.
   "^hwacom,.*":
     description: HwaCom Systems Inc.
   "^hyundai,.*":
@@ -735,6 +739,8 @@ patternProperties:
     description: PROBOX2 (by W2COMP Co., Ltd.)
   "^pulsedlight,.*":
     description: PulsedLight, Inc
+  "^purism,.*":
+    description: Purism, SPC
   "^qca,.*":
     description: Qualcomm Atheros, Inc.
   "^qcom,.*":
diff --git a/Documentation/devicetree/bindings/virtio/iommu.txt b/Documentation/devicetree/bindings/virtio/iommu.txt
new file mode 100644 (file)
index 0000000..2407fea
--- /dev/null
@@ -0,0 +1,66 @@
+* virtio IOMMU PCI device
+
+When virtio-iommu uses the PCI transport, its programming interface is
+discovered dynamically by the PCI probing infrastructure. However the
+device tree statically describes the relation between IOMMU and DMA
+masters. Therefore, the PCI root complex that hosts the virtio-iommu
+contains a child node representing the IOMMU device explicitly.
+
+Required properties:
+
+- compatible:  Should be "virtio,pci-iommu"
+- reg:         PCI address of the IOMMU. As defined in the PCI Bus
+               Binding reference [1], the reg property is a five-cell
+               address encoded as (phys.hi phys.mid phys.lo size.hi
+               size.lo). phys.hi should contain the device's BDF as
+               0b00000000 bbbbbbbb dddddfff 00000000. The other cells
+               should be zero.
+- #iommu-cells:        Each platform DMA master managed by the IOMMU is assigned
+               an endpoint ID, described by the "iommus" property [2].
+               For virtio-iommu, #iommu-cells must be 1.
+
+Notes:
+
+- DMA from the IOMMU device isn't managed by another IOMMU. Therefore the
+  virtio-iommu node doesn't have an "iommus" property, and is omitted from
+  the iommu-map property of the root complex.
+
+Example:
+
+pcie@10000000 {
+       compatible = "pci-host-ecam-generic";
+       ...
+
+       /* The IOMMU programming interface uses slot 00:01.0 */
+       iommu0: iommu@0008 {
+               compatible = "virtio,pci-iommu";
+               reg = <0x00000800 0 0 0 0>;
+               #iommu-cells = <1>;
+       };
+
+       /*
+        * The IOMMU manages all functions in this PCI domain except
+        * itself. Omit BDF 00:01.0.
+        */
+       iommu-map = <0x0 &iommu0 0x0 0x8>
+                   <0x9 &iommu0 0x9 0xfff7>;
+};
+
+pcie@20000000 {
+       compatible = "pci-host-ecam-generic";
+       ...
+       /*
+        * The IOMMU also manages all functions from this domain,
+        * with endpoint IDs 0x10000 - 0x1ffff
+        */
+       iommu-map = <0x0 &iommu0 0x10000 0x10000>;
+};
+
+ethernet@fe001000 {
+       ...
+       /* The IOMMU manages this platform device with endpoint ID 0x20000 */
+       iommus = <&iommu0 0x20000>;
+};
+
+[1] Documentation/devicetree/bindings/pci/pci.txt
+[2] Documentation/devicetree/bindings/iommu/iommu.txt
index 5069c1b..21af30f 100644 (file)
@@ -8,10 +8,40 @@ Required properties:
 - reg:         control registers base address and size including configuration space
 - interrupts:  interrupt generated by the device
 
+Required properties for virtio-iommu:
+
+- #iommu-cells:        When the node corresponds to a virtio-iommu device, it is
+               linked to DMA masters using the "iommus" or "iommu-map"
+               properties [1][2]. #iommu-cells specifies the size of the
+               "iommus" property. For virtio-iommu #iommu-cells must be
+               1, each cell describing a single endpoint ID.
+
+Optional properties:
+
+- iommus:      If the device accesses memory through an IOMMU, it should
+               have an "iommus" property [1]. Since virtio-iommu itself
+               does not access memory through an IOMMU, the "virtio,mmio"
+               node cannot have both an "#iommu-cells" and an "iommus"
+               property.
+
 Example:
 
        virtio_block@3000 {
                compatible = "virtio,mmio";
                reg = <0x3000 0x100>;
                interrupts = <41>;
+
+               /* Device has endpoint ID 23 */
+               iommus = <&viommu 23>
        }
+
+       viommu: iommu@3100 {
+               compatible = "virtio,mmio";
+               reg = <0x3100 0x100>;
+               interrupts = <42>;
+
+               #iommu-cells = <1>
+       }
+
+[1] Documentation/devicetree/bindings/iommu/iommu.txt
+[2] Documentation/devicetree/bindings/pci/pci-iommu.txt
diff --git a/Documentation/devicetree/bindings/watchdog/fsl-imx-sc-wdt.txt b/Documentation/devicetree/bindings/watchdog/fsl-imx-sc-wdt.txt
deleted file mode 100644 (file)
index 02b87e9..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-* Freescale i.MX System Controller Watchdog
-
-i.MX system controller watchdog is for i.MX SoCs with system controller inside,
-the watchdog is managed by system controller, users can ONLY communicate with
-system controller from secure mode for watchdog operations, so Linux i.MX system
-controller watchdog driver will call ARM SMC API and trap into ARM-Trusted-Firmware
-for watchdog operations, ARM-Trusted-Firmware is running at secure EL3 mode and
-it will request system controller to execute the watchdog operation passed from
-Linux kernel.
-
-Required properties:
-- compatible:  Should be :
-               "fsl,imx8qxp-sc-wdt"
-               followed by "fsl,imx-sc-wdt";
-
-Optional properties:
-- timeout-sec : Contains the watchdog timeout in seconds.
-
-Examples:
-
-watchdog {
-       compatible = "fsl,imx8qxp-sc-wdt", "fsl,imx-sc-wdt";
-       timeout-sec = <60>;
-};
index 4605525..e65198d 100644 (file)
@@ -6,6 +6,7 @@ Required properties:
        "allwinner,sun4i-a10-wdt"
        "allwinner,sun6i-a31-wdt"
        "allwinner,sun50i-a64-wdt","allwinner,sun6i-a31-wdt"
+       "allwinner,sun50i-h6-wdt","allwinner,sun6i-a31-wdt"
        "allwinner,suniv-f1c100s-wdt", "allwinner,sun4i-a10-wdt"
 - reg : Specifies base physical address and size of the registers.
 
index 60f8640..4660cce 100644 (file)
@@ -160,7 +160,7 @@ it with special cases.
    of the kernel image. That entry point supports two calling
    conventions.  A summary of the interface is described here.  A full
    description of the boot requirements is documented in
-   Documentation/arm/Booting
+   Documentation/arm/booting.rst
 
         a) ATAGS interface.  Minimal information is passed from firmware
         to the kernel with a tagged list of predefined parameters.
@@ -174,7 +174,7 @@ it with special cases.
         b) Entry with a flattened device-tree block.  Firmware loads the
         physical address of the flattened device tree block (dtb) into r2,
         r1 is not used, but it is considered good practice to use a valid
-        machine number as described in Documentation/arm/Booting.
+        machine number as described in Documentation/arm/booting.rst.
 
                 r0 : 0
 
index 5eba889..9f43928 100644 (file)
@@ -30,6 +30,7 @@
 *.lzo
 *.mo
 *.moc
+*.mod
 *.mod.c
 *.o
 *.o.*
diff --git a/Documentation/driver-api/backlight/lp855x-driver.rst b/Documentation/driver-api/backlight/lp855x-driver.rst
new file mode 100644 (file)
index 0000000..1e0b224
--- /dev/null
@@ -0,0 +1,81 @@
+====================
+Kernel driver lp855x
+====================
+
+Backlight driver for LP855x ICs
+
+Supported chips:
+
+       Texas Instruments LP8550, LP8551, LP8552, LP8553, LP8555, LP8556 and
+       LP8557
+
+Author: Milo(Woogyom) Kim <milo.kim@ti.com>
+
+Description
+-----------
+
+* Brightness control
+
+  Brightness can be controlled by the pwm input or the i2c command.
+  The lp855x driver supports both cases.
+
+* Device attributes
+
+  1) bl_ctl_mode
+
+  Backlight control mode.
+
+  Value: pwm based or register based
+
+  2) chip_id
+
+  The lp855x chip id.
+
+  Value: lp8550/lp8551/lp8552/lp8553/lp8555/lp8556/lp8557
+
+Platform data for lp855x
+------------------------
+
+For supporting platform specific data, the lp855x platform data can be used.
+
+* name:
+       Backlight driver name. If it is not defined, default name is set.
+* device_control:
+       Value of DEVICE CONTROL register.
+* initial_brightness:
+       Initial value of backlight brightness.
+* period_ns:
+       Platform specific PWM period value. unit is nano.
+       Only valid when brightness is pwm input mode.
+* size_program:
+       Total size of lp855x_rom_data.
+* rom_data:
+       List of new eeprom/eprom registers.
+
+Examples
+========
+
+1) lp8552 platform data: i2c register mode with new eeprom data::
+
+    #define EEPROM_A5_ADDR     0xA5
+    #define EEPROM_A5_VAL      0x4f    /* EN_VSYNC=0 */
+
+    static struct lp855x_rom_data lp8552_eeprom_arr[] = {
+       {EEPROM_A5_ADDR, EEPROM_A5_VAL},
+    };
+
+    static struct lp855x_platform_data lp8552_pdata = {
+       .name = "lcd-bl",
+       .device_control = I2C_CONFIG(LP8552),
+       .initial_brightness = INITIAL_BRT,
+       .size_program = ARRAY_SIZE(lp8552_eeprom_arr),
+       .rom_data = lp8552_eeprom_arr,
+    };
+
+2) lp8556 platform data: pwm input mode with default rom data::
+
+    static struct lp855x_platform_data lp8556_pdata = {
+       .device_control = PWM_CONFIG(LP8556),
+       .initial_brightness = INITIAL_BRT,
+       .period_ns = 1000000,
+    };
diff --git a/Documentation/driver-api/connector.rst b/Documentation/driver-api/connector.rst
new file mode 100644 (file)
index 0000000..c100c74
--- /dev/null
@@ -0,0 +1,156 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+================
+Kernel Connector
+================
+
+Kernel connector - new netlink based userspace <-> kernel space easy
+to use communication module.
+
+The Connector driver makes it easy to connect various agents using a
+netlink based network.  One must register a callback and an identifier.
+When the driver receives a special netlink message with the appropriate
+identifier, the appropriate callback will be called.
+
+From the userspace point of view it's quite straightforward:
+
+       - socket();
+       - bind();
+       - send();
+       - recv();
+
+But if kernelspace wants to use the full power of such connections, the
+driver writer must create special sockets, must know about struct sk_buff
+handling, etc...  The Connector driver allows any kernelspace agents to use
+netlink based networking for inter-process communication in a significantly
+easier way::
+
+  int cn_add_callback(struct cb_id *id, char *name, void (*callback) (struct cn_msg *, struct netlink_skb_parms *));
+  void cn_netlink_send_multi(struct cn_msg *msg, u16 len, u32 portid, u32 __group, int gfp_mask);
+  void cn_netlink_send(struct cn_msg *msg, u32 portid, u32 __group, int gfp_mask);
+
+  struct cb_id
+  {
+       __u32                   idx;
+       __u32                   val;
+  };
+
+idx and val are unique identifiers which must be registered in the
+connector.h header for in-kernel usage.  `void (*callback) (void *)` is a
+callback function which will be called when a message with above idx.val
+is received by the connector core.  The argument for that function must
+be dereferenced to `struct cn_msg *`::
+
+  struct cn_msg
+  {
+       struct cb_id            id;
+
+       __u32                   seq;
+       __u32                   ack;
+
+       __u32                   len;    /* Length of the following data */
+       __u8                    data[0];
+  };
+
+Connector interfaces
+====================
+
+ .. kernel-doc:: include/linux/connector.h
+
+ Note:
+   When registering new callback user, connector core assigns
+   netlink group to the user which is equal to its id.idx.
+
+Protocol description
+====================
+
+The current framework offers a transport layer with fixed headers.  The
+recommended protocol which uses such a header is as following:
+
+msg->seq and msg->ack are used to determine message genealogy.  When
+someone sends a message, they use a locally unique sequence and random
+acknowledge number.  The sequence number may be copied into
+nlmsghdr->nlmsg_seq too.
+
+The sequence number is incremented with each message sent.
+
+If you expect a reply to the message, then the sequence number in the
+received message MUST be the same as in the original message, and the
+acknowledge number MUST be the same + 1.
+
+If we receive a message and its sequence number is not equal to one we
+are expecting, then it is a new message.  If we receive a message and
+its sequence number is the same as one we are expecting, but its
+acknowledge is not equal to the sequence number in the original
+message + 1, then it is a new message.
+
+Obviously, the protocol header contains the above id.
+
+The connector allows event notification in the following form: kernel
+driver or userspace process can ask connector to notify it when
+selected ids will be turned on or off (registered or unregistered its
+callback).  It is done by sending a special command to the connector
+driver (it also registers itself with id={-1, -1}).
+
+As example of this usage can be found in the cn_test.c module which
+uses the connector to request notification and to send messages.
+
+Reliability
+===========
+
+Netlink itself is not a reliable protocol.  That means that messages can
+be lost due to memory pressure or process' receiving queue overflowed,
+so caller is warned that it must be prepared.  That is why the struct
+cn_msg [main connector's message header] contains u32 seq and u32 ack
+fields.
+
+Userspace usage
+===============
+
+2.6.14 has a new netlink socket implementation, which by default does not
+allow people to send data to netlink groups other than 1.
+So, if you wish to use a netlink socket (for example using connector)
+with a different group number, the userspace application must subscribe to
+that group first.  It can be achieved by the following pseudocode::
+
+  s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
+
+  l_local.nl_family = AF_NETLINK;
+  l_local.nl_groups = 12345;
+  l_local.nl_pid = 0;
+
+  if (bind(s, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)) == -1) {
+       perror("bind");
+       close(s);
+       return -1;
+  }
+
+  {
+       int on = l_local.nl_groups;
+       setsockopt(s, 270, 1, &on, sizeof(on));
+  }
+
+Where 270 above is SOL_NETLINK, and 1 is a NETLINK_ADD_MEMBERSHIP socket
+option.  To drop a multicast subscription, one should call the above socket
+option with the NETLINK_DROP_MEMBERSHIP parameter which is defined as 0.
+
+2.6.14 netlink code only allows to select a group which is less or equal to
+the maximum group number, which is used at netlink_kernel_create() time.
+In case of connector it is CN_NETLINK_USERS + 0xf, so if you want to use
+group number 12345, you must increment CN_NETLINK_USERS to that number.
+Additional 0xf numbers are allocated to be used by non-in-kernel users.
+
+Due to this limitation, group 0xffffffff does not work now, so one can
+not use add/remove connector's group notifications, but as far as I know,
+only cn_test.c test module used it.
+
+Some work in netlink area is still being done, so things can be changed in
+2.6.15 timeframe, if it will happen, documentation will be updated for that
+kernel.
+
+Code samples
+============
+
+Sample code for a connector test module and user space can be found
+in samples/connector/. To build this code, enable CONFIG_CONNECTOR
+and CONFIG_SAMPLES.
diff --git a/Documentation/driver-api/console.rst b/Documentation/driver-api/console.rst
new file mode 100644 (file)
index 0000000..8394ad7
--- /dev/null
@@ -0,0 +1,152 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===============
+Console Drivers
+===============
+
+The Linux kernel has 2 general types of console drivers.  The first type is
+assigned by the kernel to all the virtual consoles during the boot process.
+This type will be called 'system driver', and only one system driver is allowed
+to exist. The system driver is persistent and it can never be unloaded, though
+it may become inactive.
+
+The second type has to be explicitly loaded and unloaded. This will be called
+'modular driver' by this document. Multiple modular drivers can coexist at
+any time with each driver sharing the console with other drivers including
+the system driver. However, modular drivers cannot take over the console
+that is currently occupied by another modular driver. (Exception: Drivers that
+call do_take_over_console() will succeed in the takeover regardless of the type
+of driver occupying the consoles.) They can only take over the console that is
+occupied by the system driver. In the same token, if the modular driver is
+released by the console, the system driver will take over.
+
+Modular drivers, from the programmer's point of view, have to call::
+
+        do_take_over_console() - load and bind driver to console layer
+        give_up_console() - unload driver; it will only work if driver
+                            is fully unbound
+
+In newer kernels, the following are also available::
+
+        do_register_con_driver()
+        do_unregister_con_driver()
+
+If sysfs is enabled, the contents of /sys/class/vtconsole can be
+examined. This shows the console backends currently registered by the
+system which are named vtcon<n> where <n> is an integer from 0 to 15.
+Thus::
+
+       ls /sys/class/vtconsole
+       .  ..  vtcon0  vtcon1
+
+Each directory in /sys/class/vtconsole has 3 files::
+
+     ls /sys/class/vtconsole/vtcon0
+     .  ..  bind  name  uevent
+
+What do these files signify?
+
+     1. bind - this is a read/write file. It shows the status of the driver if
+        read, or acts to bind or unbind the driver to the virtual consoles
+        when written to. The possible values are:
+
+       0
+         - means the driver is not bound and if echo'ed, commands the driver
+           to unbind
+
+        1
+         - means the driver is bound and if echo'ed, commands the driver to
+           bind
+
+     2. name - read-only file. Shows the name of the driver in this format::
+
+         cat /sys/class/vtconsole/vtcon0/name
+         (S) VGA+
+
+             '(S)' stands for a (S)ystem driver, i.e., it cannot be directly
+             commanded to bind or unbind
+
+             'VGA+' is the name of the driver
+
+         cat /sys/class/vtconsole/vtcon1/name
+         (M) frame buffer device
+
+             In this case, '(M)' stands for a (M)odular driver, one that can be
+             directly commanded to bind or unbind.
+
+     3. uevent - ignore this file
+
+When unbinding, the modular driver is detached first, and then the system
+driver takes over the consoles vacated by the driver. Binding, on the other
+hand, will bind the driver to the consoles that are currently occupied by a
+system driver.
+
+NOTE1:
+  Binding and unbinding must be selected in Kconfig. It's under::
+
+    Device Drivers ->
+       Character devices ->
+               Support for binding and unbinding console drivers
+
+NOTE2:
+  If any of the virtual consoles are in KD_GRAPHICS mode, then binding or
+  unbinding will not succeed. An example of an application that sets the
+  console to KD_GRAPHICS is X.
+
+How useful is this feature? This is very useful for console driver
+developers. By unbinding the driver from the console layer, one can unload the
+driver, make changes, recompile, reload and rebind the driver without any need
+for rebooting the kernel. For regular users who may want to switch from
+framebuffer console to VGA console and vice versa, this feature also makes
+this possible. (NOTE NOTE NOTE: Please read fbcon.txt under Documentation/fb
+for more details.)
+
+Notes for developers
+====================
+
+do_take_over_console() is now broken up into::
+
+     do_register_con_driver()
+     do_bind_con_driver() - private function
+
+give_up_console() is a wrapper to do_unregister_con_driver(), and a driver must
+be fully unbound for this call to succeed. con_is_bound() will check if the
+driver is bound or not.
+
+Guidelines for console driver writers
+=====================================
+
+In order for binding to and unbinding from the console to properly work,
+console drivers must follow these guidelines:
+
+1. All drivers, except system drivers, must call either do_register_con_driver()
+   or do_take_over_console(). do_register_con_driver() will just add the driver
+   to the console's internal list. It won't take over the
+   console. do_take_over_console(), as it name implies, will also take over (or
+   bind to) the console.
+
+2. All resources allocated during con->con_init() must be released in
+   con->con_deinit().
+
+3. All resources allocated in con->con_startup() must be released when the
+   driver, which was previously bound, becomes unbound.  The console layer
+   does not have a complementary call to con->con_startup() so it's up to the
+   driver to check when it's legal to release these resources. Calling
+   con_is_bound() in con->con_deinit() will help.  If the call returned
+   false(), then it's safe to release the resources.  This balance has to be
+   ensured because con->con_startup() can be called again when a request to
+   rebind the driver to the console arrives.
+
+4. Upon exit of the driver, ensure that the driver is totally unbound. If the
+   condition is satisfied, then the driver must call do_unregister_con_driver()
+   or give_up_console().
+
+5. do_unregister_con_driver() can also be called on conditions which make it
+   impossible for the driver to service console requests.  This can happen
+   with the framebuffer console that suddenly lost all of its drivers.
+
+The current crop of console drivers should still work correctly, but binding
+and unbinding them may cause problems. With minimal fixes, these drivers can
+be made to work correctly.
+
+Antonino Daplas <adaplas@pol.net>
index e78d070..ee268d4 100644 (file)
@@ -44,7 +44,8 @@ Example of usage::
 
     dmatest.timeout=2000 dmatest.iterations=1 dmatest.channel=dma0chan0 dmatest.run=1
 
-Example of multi-channel test usage:
+Example of multi-channel test usage (new in the 5.0 kernel)::
+
     % modprobe dmatest
     % echo 2000 > /sys/module/dmatest/parameters/timeout
     % echo 1 > /sys/module/dmatest/parameters/iterations
@@ -53,15 +54,18 @@ Example of multi-channel test usage:
     % echo dma0chan2 > /sys/module/dmatest/parameters/channel
     % echo 1 > /sys/module/dmatest/parameters/run
 
-Note: the channel parameter should always be the last parameter set prior to
-running the test (setting run=1), this is because upon setting the channel
-parameter, that specific channel is requested using the dmaengine and a thread
-is created with the existing parameters. This thread is set as pending
-and will be executed once run is set to 1. Any parameters set after the thread
-is created are not applied.
+.. note::
+  For all tests, starting in the 5.0 kernel, either single- or multi-channel,
+  the channel parameter(s) must be set after all other parameters. It is at
+  that time that the existing parameter values are acquired for use by the
+  thread(s). All other parameters are shared. Therefore, if changes are made
+  to any of the other parameters, and an additional channel specified, the
+  (shared) parameters used for all threads will use the new values.
+  After the channels are specified, each thread is set as pending. All threads
+  begin execution when the run parameter is set to 1.
 
 .. hint::
-  available channel list could be extracted by running the following command::
+  A list of available channels can be found by running the following command::
 
     % ls -1 /sys/class/dma/
 
@@ -204,6 +208,7 @@ Releasing Channels
 Channels can be freed by setting run to 0.
 
 Example::
+
     % echo dma0chan1 > /sys/module/dmatest/parameters/channel
     dmatest: Added 1 threads using dma0chan1
     % cat /sys/class/dma/dma0chan1/in_use
diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst
new file mode 100644 (file)
index 0000000..a100bef
--- /dev/null
@@ -0,0 +1,418 @@
+================================
+Devres - Managed Device Resource
+================================
+
+Tejun Heo      <teheo@suse.de>
+
+First draft    10 January 2007
+
+.. contents
+
+   1. Intro                    : Huh? Devres?
+   2. Devres                   : Devres in a nutshell
+   3. Devres Group             : Group devres'es and release them together
+   4. Details                  : Life time rules, calling context, ...
+   5. Overhead                 : How much do we have to pay for this?
+   6. List of managed interfaces: Currently implemented managed interfaces
+
+
+1. Intro
+--------
+
+devres came up while trying to convert libata to use iomap.  Each
+iomapped address should be kept and unmapped on driver detach.  For
+example, a plain SFF ATA controller (that is, good old PCI IDE) in
+native mode makes use of 5 PCI BARs and all of them should be
+maintained.
+
+As with many other device drivers, libata low level drivers have
+sufficient bugs in ->remove and ->probe failure path.  Well, yes,
+that's probably because libata low level driver developers are lazy
+bunch, but aren't all low level driver developers?  After spending a
+day fiddling with braindamaged hardware with no document or
+braindamaged document, if it's finally working, well, it's working.
+
+For one reason or another, low level drivers don't receive as much
+attention or testing as core code, and bugs on driver detach or
+initialization failure don't happen often enough to be noticeable.
+Init failure path is worse because it's much less travelled while
+needs to handle multiple entry points.
+
+So, many low level drivers end up leaking resources on driver detach
+and having half broken failure path implementation in ->probe() which
+would leak resources or even cause oops when failure occurs.  iomap
+adds more to this mix.  So do msi and msix.
+
+
+2. Devres
+---------
+
+devres is basically linked list of arbitrarily sized memory areas
+associated with a struct device.  Each devres entry is associated with
+a release function.  A devres can be released in several ways.  No
+matter what, all devres entries are released on driver detach.  On
+release, the associated release function is invoked and then the
+devres entry is freed.
+
+Managed interface is created for resources commonly used by device
+drivers using devres.  For example, coherent DMA memory is acquired
+using dma_alloc_coherent().  The managed version is called
+dmam_alloc_coherent().  It is identical to dma_alloc_coherent() except
+for the DMA memory allocated using it is managed and will be
+automatically released on driver detach.  Implementation looks like
+the following::
+
+  struct dma_devres {
+       size_t          size;
+       void            *vaddr;
+       dma_addr_t      dma_handle;
+  };
+
+  static void dmam_coherent_release(struct device *dev, void *res)
+  {
+       struct dma_devres *this = res;
+
+       dma_free_coherent(dev, this->size, this->vaddr, this->dma_handle);
+  }
+
+  dmam_alloc_coherent(dev, size, dma_handle, gfp)
+  {
+       struct dma_devres *dr;
+       void *vaddr;
+
+       dr = devres_alloc(dmam_coherent_release, sizeof(*dr), gfp);
+       ...
+
+       /* alloc DMA memory as usual */
+       vaddr = dma_alloc_coherent(...);
+       ...
+
+       /* record size, vaddr, dma_handle in dr */
+       dr->vaddr = vaddr;
+       ...
+
+       devres_add(dev, dr);
+
+       return vaddr;
+  }
+
+If a driver uses dmam_alloc_coherent(), the area is guaranteed to be
+freed whether initialization fails half-way or the device gets
+detached.  If most resources are acquired using managed interface, a
+driver can have much simpler init and exit code.  Init path basically
+looks like the following::
+
+  my_init_one()
+  {
+       struct mydev *d;
+
+       d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL);
+       if (!d)
+               return -ENOMEM;
+
+       d->ring = dmam_alloc_coherent(...);
+       if (!d->ring)
+               return -ENOMEM;
+
+       if (check something)
+               return -EINVAL;
+       ...
+
+       return register_to_upper_layer(d);
+  }
+
+And exit path::
+
+  my_remove_one()
+  {
+       unregister_from_upper_layer(d);
+       shutdown_my_hardware();
+  }
+
+As shown above, low level drivers can be simplified a lot by using
+devres.  Complexity is shifted from less maintained low level drivers
+to better maintained higher layer.  Also, as init failure path is
+shared with exit path, both can get more testing.
+
+Note though that when converting current calls or assignments to
+managed devm_* versions it is up to you to check if internal operations
+like allocating memory, have failed. Managed resources pertains to the
+freeing of these resources *only* - all other checks needed are still
+on you. In some cases this may mean introducing checks that were not
+necessary before moving to the managed devm_* calls.
+
+
+3. Devres group
+---------------
+
+Devres entries can be grouped using devres group.  When a group is
+released, all contained normal devres entries and properly nested
+groups are released.  One usage is to rollback series of acquired
+resources on failure.  For example::
+
+  if (!devres_open_group(dev, NULL, GFP_KERNEL))
+       return -ENOMEM;
+
+  acquire A;
+  if (failed)
+       goto err;
+
+  acquire B;
+  if (failed)
+       goto err;
+  ...
+
+  devres_remove_group(dev, NULL);
+  return 0;
+
+ err:
+  devres_release_group(dev, NULL);
+  return err_code;
+
+As resource acquisition failure usually means probe failure, constructs
+like above are usually useful in midlayer driver (e.g. libata core
+layer) where interface function shouldn't have side effect on failure.
+For LLDs, just returning error code suffices in most cases.
+
+Each group is identified by `void *id`.  It can either be explicitly
+specified by @id argument to devres_open_group() or automatically
+created by passing NULL as @id as in the above example.  In both
+cases, devres_open_group() returns the group's id.  The returned id
+can be passed to other devres functions to select the target group.
+If NULL is given to those functions, the latest open group is
+selected.
+
+For example, you can do something like the following::
+
+  int my_midlayer_create_something()
+  {
+       if (!devres_open_group(dev, my_midlayer_create_something, GFP_KERNEL))
+               return -ENOMEM;
+
+       ...
+
+       devres_close_group(dev, my_midlayer_create_something);
+       return 0;
+  }
+
+  void my_midlayer_destroy_something()
+  {
+       devres_release_group(dev, my_midlayer_create_something);
+  }
+
+
+4. Details
+----------
+
+Lifetime of a devres entry begins on devres allocation and finishes
+when it is released or destroyed (removed and freed) - no reference
+counting.
+
+devres core guarantees atomicity to all basic devres operations and
+has support for single-instance devres types (atomic
+lookup-and-add-if-not-found).  Other than that, synchronizing
+concurrent accesses to allocated devres data is caller's
+responsibility.  This is usually non-issue because bus ops and
+resource allocations already do the job.
+
+For an example of single-instance devres type, read pcim_iomap_table()
+in lib/devres.c.
+
+All devres interface functions can be called without context if the
+right gfp mask is given.
+
+
+5. Overhead
+-----------
+
+Each devres bookkeeping info is allocated together with requested data
+area.  With debug option turned off, bookkeeping info occupies 16
+bytes on 32bit machines and 24 bytes on 64bit (three pointers rounded
+up to ull alignment).  If singly linked list is used, it can be
+reduced to two pointers (8 bytes on 32bit, 16 bytes on 64bit).
+
+Each devres group occupies 8 pointers.  It can be reduced to 6 if
+singly linked list is used.
+
+Memory space overhead on ahci controller with two ports is between 300
+and 400 bytes on 32bit machine after naive conversion (we can
+certainly invest a bit more effort into libata core layer).
+
+
+6. List of managed interfaces
+-----------------------------
+
+CLOCK
+  devm_clk_get()
+  devm_clk_get_optional()
+  devm_clk_put()
+  devm_clk_bulk_get()
+  devm_clk_bulk_get_all()
+  devm_clk_bulk_get_optional()
+  devm_get_clk_from_childl()
+  devm_clk_hw_register()
+  devm_of_clk_add_hw_provider()
+  devm_clk_hw_register_clkdev()
+
+DMA
+  dmaenginem_async_device_register()
+  dmam_alloc_coherent()
+  dmam_alloc_attrs()
+  dmam_free_coherent()
+  dmam_pool_create()
+  dmam_pool_destroy()
+
+DRM
+  devm_drm_dev_init()
+
+GPIO
+  devm_gpiod_get()
+  devm_gpiod_get_index()
+  devm_gpiod_get_index_optional()
+  devm_gpiod_get_optional()
+  devm_gpiod_put()
+  devm_gpiod_unhinge()
+  devm_gpiochip_add_data()
+  devm_gpio_request()
+  devm_gpio_request_one()
+  devm_gpio_free()
+
+I2C
+  devm_i2c_new_dummy_device()
+
+IIO
+  devm_iio_device_alloc()
+  devm_iio_device_free()
+  devm_iio_device_register()
+  devm_iio_device_unregister()
+  devm_iio_kfifo_allocate()
+  devm_iio_kfifo_free()
+  devm_iio_triggered_buffer_setup()
+  devm_iio_triggered_buffer_cleanup()
+  devm_iio_trigger_alloc()
+  devm_iio_trigger_free()
+  devm_iio_trigger_register()
+  devm_iio_trigger_unregister()
+  devm_iio_channel_get()
+  devm_iio_channel_release()
+  devm_iio_channel_get_all()
+  devm_iio_channel_release_all()
+
+INPUT
+  devm_input_allocate_device()
+
+IO region
+  devm_release_mem_region()
+  devm_release_region()
+  devm_release_resource()
+  devm_request_mem_region()
+  devm_request_region()
+  devm_request_resource()
+
+IOMAP
+  devm_ioport_map()
+  devm_ioport_unmap()
+  devm_ioremap()
+  devm_ioremap_nocache()
+  devm_ioremap_wc()
+  devm_ioremap_resource() : checks resource, requests memory region, ioremaps
+  devm_iounmap()
+  pcim_iomap()
+  pcim_iomap_regions() : do request_region() and iomap() on multiple BARs
+  pcim_iomap_table()   : array of mapped addresses indexed by BAR
+  pcim_iounmap()
+
+IRQ
+  devm_free_irq()
+  devm_request_any_context_irq()
+  devm_request_irq()
+  devm_request_threaded_irq()
+  devm_irq_alloc_descs()
+  devm_irq_alloc_desc()
+  devm_irq_alloc_desc_at()
+  devm_irq_alloc_desc_from()
+  devm_irq_alloc_descs_from()
+  devm_irq_alloc_generic_chip()
+  devm_irq_setup_generic_chip()
+  devm_irq_sim_init()
+
+LED
+  devm_led_classdev_register()
+  devm_led_classdev_unregister()
+
+MDIO
+  devm_mdiobus_alloc()
+  devm_mdiobus_alloc_size()
+  devm_mdiobus_free()
+
+MEM
+  devm_free_pages()
+  devm_get_free_pages()
+  devm_kasprintf()
+  devm_kcalloc()
+  devm_kfree()
+  devm_kmalloc()
+  devm_kmalloc_array()
+  devm_kmemdup()
+  devm_kstrdup()
+  devm_kvasprintf()
+  devm_kzalloc()
+
+MFD
+  devm_mfd_add_devices()
+
+MUX
+  devm_mux_chip_alloc()
+  devm_mux_chip_register()
+  devm_mux_control_get()
+
+PER-CPU MEM
+  devm_alloc_percpu()
+  devm_free_percpu()
+
+PCI
+  devm_pci_alloc_host_bridge()  : managed PCI host bridge allocation
+  devm_pci_remap_cfgspace()    : ioremap PCI configuration space
+  devm_pci_remap_cfg_resource()        : ioremap PCI configuration space resource
+  pcim_enable_device()         : after success, all PCI ops become managed
+  pcim_pin_device()            : keep PCI device enabled after release
+
+PHY
+  devm_usb_get_phy()
+  devm_usb_put_phy()
+
+PINCTRL
+  devm_pinctrl_get()
+  devm_pinctrl_put()
+  devm_pinctrl_register()
+  devm_pinctrl_unregister()
+
+POWER
+  devm_reboot_mode_register()
+  devm_reboot_mode_unregister()
+
+PWM
+  devm_pwm_get()
+  devm_pwm_put()
+
+REGULATOR
+  devm_regulator_bulk_get()
+  devm_regulator_get()
+  devm_regulator_put()
+  devm_regulator_register()
+
+RESET
+  devm_reset_control_get()
+  devm_reset_controller_register()
+
+SERDEV
+  devm_serdev_device_open()
+
+SLAVE DMA ENGINE
+  devm_acpi_dma_controller_register()
+
+SPI
+  devm_spi_register_master()
+
+WATCHDOG
+  devm_watchdog_register_device()
diff --git a/Documentation/driver-api/driver-model/index.rst b/Documentation/driver-api/driver-model/index.rst
new file mode 100644 (file)
index 0000000..7550164
--- /dev/null
@@ -0,0 +1,24 @@
+============
+Driver Model
+============
+
+.. toctree::
+   :maxdepth: 1
+
+   binding
+   bus
+   class
+   design-patterns
+   device
+   devres
+   driver
+   overview
+   platform
+   porting
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
diff --git a/Documentation/driver-api/driver-model/porting.rst b/Documentation/driver-api/driver-model/porting.rst
new file mode 100644 (file)
index 0000000..931ea87
--- /dev/null
@@ -0,0 +1,448 @@
+=======================================
+Porting Drivers to the New Driver Model
+=======================================
+
+Patrick Mochel
+
+7 January 2003
+
+
+Overview
+
+Please refer to `Documentation/driver-api/driver-model/*.rst` for definitions of
+various driver types and concepts.
+
+Most of the work of porting devices drivers to the new model happens
+at the bus driver layer. This was intentional, to minimize the
+negative effect on kernel drivers, and to allow a gradual transition
+of bus drivers.
+
+In a nutshell, the driver model consists of a set of objects that can
+be embedded in larger, bus-specific objects. Fields in these generic
+objects can replace fields in the bus-specific objects.
+
+The generic objects must be registered with the driver model core. By
+doing so, they will exported via the sysfs filesystem. sysfs can be
+mounted by doing::
+
+       # mount -t sysfs sysfs /sys
+
+
+
+The Process
+
+Step 0: Read include/linux/device.h for object and function definitions.
+
+Step 1: Registering the bus driver.
+
+
+- Define a struct bus_type for the bus driver::
+
+    struct bus_type pci_bus_type = {
+          .name           = "pci",
+    };
+
+
+- Register the bus type.
+
+  This should be done in the initialization function for the bus type,
+  which is usually the module_init(), or equivalent, function::
+
+    static int __init pci_driver_init(void)
+    {
+            return bus_register(&pci_bus_type);
+    }
+
+    subsys_initcall(pci_driver_init);
+
+
+  The bus type may be unregistered (if the bus driver may be compiled
+  as a module) by doing::
+
+     bus_unregister(&pci_bus_type);
+
+
+- Export the bus type for others to use.
+
+  Other code may wish to reference the bus type, so declare it in a
+  shared header file and export the symbol.
+
+From include/linux/pci.h::
+
+  extern struct bus_type pci_bus_type;
+
+
+From file the above code appears in::
+
+  EXPORT_SYMBOL(pci_bus_type);
+
+
+
+- This will cause the bus to show up in /sys/bus/pci/ with two
+  subdirectories: 'devices' and 'drivers'::
+
+    # tree -d /sys/bus/pci/
+    /sys/bus/pci/
+    |-- devices
+    `-- drivers
+
+
+
+Step 2: Registering Devices.
+
+struct device represents a single device. It mainly contains metadata
+describing the relationship the device has to other entities.
+
+
+- Embed a struct device in the bus-specific device type::
+
+
+    struct pci_dev {
+           ...
+           struct  device  dev;            /* Generic device interface */
+           ...
+    };
+
+  It is recommended that the generic device not be the first item in
+  the struct to discourage programmers from doing mindless casts
+  between the object types. Instead macros, or inline functions,
+  should be created to convert from the generic object type::
+
+
+    #define to_pci_dev(n) container_of(n, struct pci_dev, dev)
+
+    or
+
+    static inline struct pci_dev * to_pci_dev(struct kobject * kobj)
+    {
+       return container_of(n, struct pci_dev, dev);
+    }
+
+  This allows the compiler to verify type-safety of the operations
+  that are performed (which is Good).
+
+
+- Initialize the device on registration.
+
+  When devices are discovered or registered with the bus type, the
+  bus driver should initialize the generic device. The most important
+  things to initialize are the bus_id, parent, and bus fields.
+
+  The bus_id is an ASCII string that contains the device's address on
+  the bus. The format of this string is bus-specific. This is
+  necessary for representing devices in sysfs.
+
+  parent is the physical parent of the device. It is important that
+  the bus driver sets this field correctly.
+
+  The driver model maintains an ordered list of devices that it uses
+  for power management. This list must be in order to guarantee that
+  devices are shutdown before their physical parents, and vice versa.
+  The order of this list is determined by the parent of registered
+  devices.
+
+  Also, the location of the device's sysfs directory depends on a
+  device's parent. sysfs exports a directory structure that mirrors
+  the device hierarchy. Accurately setting the parent guarantees that
+  sysfs will accurately represent the hierarchy.
+
+  The device's bus field is a pointer to the bus type the device
+  belongs to. This should be set to the bus_type that was declared
+  and initialized before.
+
+  Optionally, the bus driver may set the device's name and release
+  fields.
+
+  The name field is an ASCII string describing the device, like
+
+     "ATI Technologies Inc Radeon QD"
+
+  The release field is a callback that the driver model core calls
+  when the device has been removed, and all references to it have
+  been released. More on this in a moment.
+
+
+- Register the device.
+
+  Once the generic device has been initialized, it can be registered
+  with the driver model core by doing::
+
+       device_register(&dev->dev);
+
+  It can later be unregistered by doing::
+
+       device_unregister(&dev->dev);
+
+  This should happen on buses that support hotpluggable devices.
+  If a bus driver unregisters a device, it should not immediately free
+  it. It should instead wait for the driver model core to call the
+  device's release method, then free the bus-specific object.
+  (There may be other code that is currently referencing the device
+  structure, and it would be rude to free the device while that is
+  happening).
+
+
+  When the device is registered, a directory in sysfs is created.
+  The PCI tree in sysfs looks like::
+
+    /sys/devices/pci0/
+    |-- 00:00.0
+    |-- 00:01.0
+    |   `-- 01:00.0
+    |-- 00:02.0
+    |   `-- 02:1f.0
+    |       `-- 03:00.0
+    |-- 00:1e.0
+    |   `-- 04:04.0
+    |-- 00:1f.0
+    |-- 00:1f.1
+    |   |-- ide0
+    |   |   |-- 0.0
+    |   |   `-- 0.1
+    |   `-- ide1
+    |       `-- 1.0
+    |-- 00:1f.2
+    |-- 00:1f.3
+    `-- 00:1f.5
+
+  Also, symlinks are created in the bus's 'devices' directory
+  that point to the device's directory in the physical hierarchy::
+
+    /sys/bus/pci/devices/
+    |-- 00:00.0 -> ../../../devices/pci0/00:00.0
+    |-- 00:01.0 -> ../../../devices/pci0/00:01.0
+    |-- 00:02.0 -> ../../../devices/pci0/00:02.0
+    |-- 00:1e.0 -> ../../../devices/pci0/00:1e.0
+    |-- 00:1f.0 -> ../../../devices/pci0/00:1f.0
+    |-- 00:1f.1 -> ../../../devices/pci0/00:1f.1
+    |-- 00:1f.2 -> ../../../devices/pci0/00:1f.2
+    |-- 00:1f.3 -> ../../../devices/pci0/00:1f.3
+    |-- 00:1f.5 -> ../../../devices/pci0/00:1f.5
+    |-- 01:00.0 -> ../../../devices/pci0/00:01.0/01:00.0
+    |-- 02:1f.0 -> ../../../devices/pci0/00:02.0/02:1f.0
+    |-- 03:00.0 -> ../../../devices/pci0/00:02.0/02:1f.0/03:00.0
+    `-- 04:04.0 -> ../../../devices/pci0/00:1e.0/04:04.0
+
+
+
+Step 3: Registering Drivers.
+
+struct device_driver is a simple driver structure that contains a set
+of operations that the driver model core may call.
+
+
+- Embed a struct device_driver in the bus-specific driver.
+
+  Just like with devices, do something like::
+
+    struct pci_driver {
+           ...
+           struct device_driver    driver;
+    };
+
+
+- Initialize the generic driver structure.
+
+  When the driver registers with the bus (e.g. doing pci_register_driver()),
+  initialize the necessary fields of the driver: the name and bus
+  fields.
+
+
+- Register the driver.
+
+  After the generic driver has been initialized, call::
+
+       driver_register(&drv->driver);
+
+  to register the driver with the core.
+
+  When the driver is unregistered from the bus, unregister it from the
+  core by doing::
+
+        driver_unregister(&drv->driver);
+
+  Note that this will block until all references to the driver have
+  gone away. Normally, there will not be any.
+
+
+- Sysfs representation.
+
+  Drivers are exported via sysfs in their bus's 'driver's directory.
+  For example::
+
+    /sys/bus/pci/drivers/
+    |-- 3c59x
+    |-- Ensoniq AudioPCI
+    |-- agpgart-amdk7
+    |-- e100
+    `-- serial
+
+
+Step 4: Define Generic Methods for Drivers.
+
+struct device_driver defines a set of operations that the driver model
+core calls. Most of these operations are probably similar to
+operations the bus already defines for drivers, but taking different
+parameters.
+
+It would be difficult and tedious to force every driver on a bus to
+simultaneously convert their drivers to generic format. Instead, the
+bus driver should define single instances of the generic methods that
+forward call to the bus-specific drivers. For instance::
+
+
+  static int pci_device_remove(struct device * dev)
+  {
+          struct pci_dev * pci_dev = to_pci_dev(dev);
+          struct pci_driver * drv = pci_dev->driver;
+
+          if (drv) {
+                  if (drv->remove)
+                          drv->remove(pci_dev);
+                  pci_dev->driver = NULL;
+          }
+          return 0;
+  }
+
+
+The generic driver should be initialized with these methods before it
+is registered::
+
+        /* initialize common driver fields */
+        drv->driver.name = drv->name;
+        drv->driver.bus = &pci_bus_type;
+        drv->driver.probe = pci_device_probe;
+        drv->driver.resume = pci_device_resume;
+        drv->driver.suspend = pci_device_suspend;
+        drv->driver.remove = pci_device_remove;
+
+        /* register with core */
+        driver_register(&drv->driver);
+
+
+Ideally, the bus should only initialize the fields if they are not
+already set. This allows the drivers to implement their own generic
+methods.
+
+
+Step 5: Support generic driver binding.
+
+The model assumes that a device or driver can be dynamically
+registered with the bus at any time. When registration happens,
+devices must be bound to a driver, or drivers must be bound to all
+devices that it supports.
+
+A driver typically contains a list of device IDs that it supports. The
+bus driver compares these IDs to the IDs of devices registered with it.
+The format of the device IDs, and the semantics for comparing them are
+bus-specific, so the generic model does attempt to generalize them.
+
+Instead, a bus may supply a method in struct bus_type that does the
+comparison::
+
+  int (*match)(struct device * dev, struct device_driver * drv);
+
+match should return positive value if the driver supports the device,
+and zero otherwise. It may also return error code (for example
+-EPROBE_DEFER) if determining that given driver supports the device is
+not possible.
+
+When a device is registered, the bus's list of drivers is iterated
+over. bus->match() is called for each one until a match is found.
+
+When a driver is registered, the bus's list of devices is iterated
+over. bus->match() is called for each device that is not already
+claimed by a driver.
+
+When a device is successfully bound to a driver, device->driver is
+set, the device is added to a per-driver list of devices, and a
+symlink is created in the driver's sysfs directory that points to the
+device's physical directory::
+
+  /sys/bus/pci/drivers/
+  |-- 3c59x
+  |   `-- 00:0b.0 -> ../../../../devices/pci0/00:0b.0
+  |-- Ensoniq AudioPCI
+  |-- agpgart-amdk7
+  |   `-- 00:00.0 -> ../../../../devices/pci0/00:00.0
+  |-- e100
+  |   `-- 00:0c.0 -> ../../../../devices/pci0/00:0c.0
+  `-- serial
+
+
+This driver binding should replace the existing driver binding
+mechanism the bus currently uses.
+
+
+Step 6: Supply a hotplug callback.
+
+Whenever a device is registered with the driver model core, the
+userspace program /sbin/hotplug is called to notify userspace.
+Users can define actions to perform when a device is inserted or
+removed.
+
+The driver model core passes several arguments to userspace via
+environment variables, including
+
+- ACTION: set to 'add' or 'remove'
+- DEVPATH: set to the device's physical path in sysfs.
+
+A bus driver may also supply additional parameters for userspace to
+consume. To do this, a bus must implement the 'hotplug' method in
+struct bus_type::
+
+     int (*hotplug) (struct device *dev, char **envp,
+                     int num_envp, char *buffer, int buffer_size);
+
+This is called immediately before /sbin/hotplug is executed.
+
+
+Step 7: Cleaning up the bus driver.
+
+The generic bus, device, and driver structures provide several fields
+that can replace those defined privately to the bus driver.
+
+- Device list.
+
+struct bus_type contains a list of all devices registered with the bus
+type. This includes all devices on all instances of that bus type.
+An internal list that the bus uses may be removed, in favor of using
+this one.
+
+The core provides an iterator to access these devices::
+
+  int bus_for_each_dev(struct bus_type * bus, struct device * start,
+                       void * data, int (*fn)(struct device *, void *));
+
+
+- Driver list.
+
+struct bus_type also contains a list of all drivers registered with
+it. An internal list of drivers that the bus driver maintains may
+be removed in favor of using the generic one.
+
+The drivers may be iterated over, like devices::
+
+  int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
+                       void * data, int (*fn)(struct device_driver *, void *));
+
+
+Please see drivers/base/bus.c for more information.
+
+
+- rwsem
+
+struct bus_type contains an rwsem that protects all core accesses to
+the device and driver lists. This can be used by the bus driver
+internally, and should be used when accessing the device or driver
+lists the bus maintains.
+
+
+- Device and driver fields.
+
+Some of the fields in struct device and struct device_driver duplicate
+fields in the bus-specific representations of these objects. Feel free
+to remove the bus-specific ones and favor the generic ones. Note
+though, that this will likely mean fixing up all the drivers that
+reference the bus-specific fields (though those should all be 1-line
+changes).
diff --git a/Documentation/driver-api/early-userspace/buffer-format.rst b/Documentation/driver-api/early-userspace/buffer-format.rst
new file mode 100644 (file)
index 0000000..7f74e30
--- /dev/null
@@ -0,0 +1,119 @@
+=======================
+initramfs buffer format
+=======================
+
+Al Viro, H. Peter Anvin
+
+Last revision: 2002-01-13
+
+Starting with kernel 2.5.x, the old "initial ramdisk" protocol is
+getting {replaced/complemented} with the new "initial ramfs"
+(initramfs) protocol.  The initramfs contents is passed using the same
+memory buffer protocol used by the initrd protocol, but the contents
+is different.  The initramfs buffer contains an archive which is
+expanded into a ramfs filesystem; this document details the format of
+the initramfs buffer format.
+
+The initramfs buffer format is based around the "newc" or "crc" CPIO
+formats, and can be created with the cpio(1) utility.  The cpio
+archive can be compressed using gzip(1).  One valid version of an
+initramfs buffer is thus a single .cpio.gz file.
+
+The full format of the initramfs buffer is defined by the following
+grammar, where::
+
+       *       is used to indicate "0 or more occurrences of"
+       (|)     indicates alternatives
+       +       indicates concatenation
+       GZIP()  indicates the gzip(1) of the operand
+       ALGN(n) means padding with null bytes to an n-byte boundary
+
+       initramfs  := ("\0" | cpio_archive | cpio_gzip_archive)*
+
+       cpio_gzip_archive := GZIP(cpio_archive)
+
+       cpio_archive := cpio_file* + (<nothing> | cpio_trailer)
+
+       cpio_file := ALGN(4) + cpio_header + filename + "\0" + ALGN(4) + data
+
+       cpio_trailer := ALGN(4) + cpio_header + "TRAILER!!!\0" + ALGN(4)
+
+
+In human terms, the initramfs buffer contains a collection of
+compressed and/or uncompressed cpio archives (in the "newc" or "crc"
+formats); arbitrary amounts zero bytes (for padding) can be added
+between members.
+
+The cpio "TRAILER!!!" entry (cpio end-of-archive) is optional, but is
+not ignored; see "handling of hard links" below.
+
+The structure of the cpio_header is as follows (all fields contain
+hexadecimal ASCII numbers fully padded with '0' on the left to the
+full width of the field, for example, the integer 4780 is represented
+by the ASCII string "000012ac"):
+
+============= ================== ==============================================
+Field name    Field size        Meaning
+============= ================== ==============================================
+c_magic              6 bytes            The string "070701" or "070702"
+c_ino        8 bytes            File inode number
+c_mode       8 bytes            File mode and permissions
+c_uid        8 bytes            File uid
+c_gid        8 bytes            File gid
+c_nlink              8 bytes            Number of links
+c_mtime              8 bytes            Modification time
+c_filesize    8 bytes           Size of data field
+c_maj        8 bytes            Major part of file device number
+c_min        8 bytes            Minor part of file device number
+c_rmaj       8 bytes            Major part of device node reference
+c_rmin       8 bytes            Minor part of device node reference
+c_namesize    8 bytes           Length of filename, including final \0
+c_chksum      8 bytes           Checksum of data field if c_magic is 070702;
+                                otherwise zero
+============= ================== ==============================================
+
+The c_mode field matches the contents of st_mode returned by stat(2)
+on Linux, and encodes the file type and file permissions.
+
+The c_filesize should be zero for any file which is not a regular file
+or symlink.
+
+The c_chksum field contains a simple 32-bit unsigned sum of all the
+bytes in the data field.  cpio(1) refers to this as "crc", which is
+clearly incorrect (a cyclic redundancy check is a different and
+significantly stronger integrity check), however, this is the
+algorithm used.
+
+If the filename is "TRAILER!!!" this is actually an end-of-archive
+marker; the c_filesize for an end-of-archive marker must be zero.
+
+
+Handling of hard links
+======================
+
+When a nondirectory with c_nlink > 1 is seen, the (c_maj,c_min,c_ino)
+tuple is looked up in a tuple buffer.  If not found, it is entered in
+the tuple buffer and the entry is created as usual; if found, a hard
+link rather than a second copy of the file is created.  It is not
+necessary (but permitted) to include a second copy of the file
+contents; if the file contents is not included, the c_filesize field
+should be set to zero to indicate no data section follows.  If data is
+present, the previous instance of the file is overwritten; this allows
+the data-carrying instance of a file to occur anywhere in the sequence
+(GNU cpio is reported to attach the data to the last instance of a
+file only.)
+
+c_filesize must not be zero for a symlink.
+
+When a "TRAILER!!!" end-of-archive marker is seen, the tuple buffer is
+reset.  This permits archives which are generated independently to be
+concatenated.
+
+To combine file data from different sources (without having to
+regenerate the (c_maj,c_min,c_ino) fields), therefore, either one of
+the following techniques can be used:
+
+a) Separate the different file data sources with a "TRAILER!!!"
+   end-of-archive marker, or
+
+b) Make sure c_nlink == 1 for all nondirectory entries.
diff --git a/Documentation/driver-api/early-userspace/early_userspace_support.rst b/Documentation/driver-api/early-userspace/early_userspace_support.rst
new file mode 100644 (file)
index 0000000..3deefb3
--- /dev/null
@@ -0,0 +1,154 @@
+=======================
+Early userspace support
+=======================
+
+Last update: 2004-12-20 tlh
+
+
+"Early userspace" is a set of libraries and programs that provide
+various pieces of functionality that are important enough to be
+available while a Linux kernel is coming up, but that don't need to be
+run inside the kernel itself.
+
+It consists of several major infrastructure components:
+
+- gen_init_cpio, a program that builds a cpio-format archive
+  containing a root filesystem image.  This archive is compressed, and
+  the compressed image is linked into the kernel image.
+- initramfs, a chunk of code that unpacks the compressed cpio image
+  midway through the kernel boot process.
+- klibc, a userspace C library, currently packaged separately, that is
+  optimized for correctness and small size.
+
+The cpio file format used by initramfs is the "newc" (aka "cpio -H newc")
+format, and is documented in the file "buffer-format.txt".  There are
+two ways to add an early userspace image: specify an existing cpio
+archive to be used as the image or have the kernel build process build
+the image from specifications.
+
+CPIO ARCHIVE method
+-------------------
+
+You can create a cpio archive that contains the early userspace image.
+Your cpio archive should be specified in CONFIG_INITRAMFS_SOURCE and it
+will be used directly.  Only a single cpio file may be specified in
+CONFIG_INITRAMFS_SOURCE and directory and file names are not allowed in
+combination with a cpio archive.
+
+IMAGE BUILDING method
+---------------------
+
+The kernel build process can also build an early userspace image from
+source parts rather than supplying a cpio archive.  This method provides
+a way to create images with root-owned files even though the image was
+built by an unprivileged user.
+
+The image is specified as one or more sources in
+CONFIG_INITRAMFS_SOURCE.  Sources can be either directories or files -
+cpio archives are *not* allowed when building from sources.
+
+A source directory will have it and all of its contents packaged.  The
+specified directory name will be mapped to '/'.  When packaging a
+directory, limited user and group ID translation can be performed.
+INITRAMFS_ROOT_UID can be set to a user ID that needs to be mapped to
+user root (0).  INITRAMFS_ROOT_GID can be set to a group ID that needs
+to be mapped to group root (0).
+
+A source file must be directives in the format required by the
+usr/gen_init_cpio utility (run 'usr/gen_init_cpio -h' to get the
+file format).  The directives in the file will be passed directly to
+usr/gen_init_cpio.
+
+When a combination of directories and files are specified then the
+initramfs image will be an aggregate of all of them.  In this way a user
+can create a 'root-image' directory and install all files into it.
+Because device-special files cannot be created by a unprivileged user,
+special files can be listed in a 'root-files' file.  Both 'root-image'
+and 'root-files' can be listed in CONFIG_INITRAMFS_SOURCE and a complete
+early userspace image can be built by an unprivileged user.
+
+As a technical note, when directories and files are specified, the
+entire CONFIG_INITRAMFS_SOURCE is passed to
+usr/gen_initramfs_list.sh.  This means that CONFIG_INITRAMFS_SOURCE
+can really be interpreted as any legal argument to
+gen_initramfs_list.sh.  If a directory is specified as an argument then
+the contents are scanned, uid/gid translation is performed, and
+usr/gen_init_cpio file directives are output.  If a directory is
+specified as an argument to usr/gen_initramfs_list.sh then the
+contents of the file are simply copied to the output.  All of the output
+directives from directory scanning and file contents copying are
+processed by usr/gen_init_cpio.
+
+See also 'usr/gen_initramfs_list.sh -h'.
+
+Where's this all leading?
+=========================
+
+The klibc distribution contains some of the necessary software to make
+early userspace useful.  The klibc distribution is currently
+maintained separately from the kernel.
+
+You can obtain somewhat infrequent snapshots of klibc from
+https://www.kernel.org/pub/linux/libs/klibc/
+
+For active users, you are better off using the klibc git
+repository, at http://git.kernel.org/?p=libs/klibc/klibc.git
+
+The standalone klibc distribution currently provides three components,
+in addition to the klibc library:
+
+- ipconfig, a program that configures network interfaces.  It can
+  configure them statically, or use DHCP to obtain information
+  dynamically (aka "IP autoconfiguration").
+- nfsmount, a program that can mount an NFS filesystem.
+- kinit, the "glue" that uses ipconfig and nfsmount to replace the old
+  support for IP autoconfig, mount a filesystem over NFS, and continue
+  system boot using that filesystem as root.
+
+kinit is built as a single statically linked binary to save space.
+
+Eventually, several more chunks of kernel functionality will hopefully
+move to early userspace:
+
+- Almost all of init/do_mounts* (the beginning of this is already in
+  place)
+- ACPI table parsing
+- Insert unwieldy subsystem that doesn't really need to be in kernel
+  space here
+
+If kinit doesn't meet your current needs and you've got bytes to burn,
+the klibc distribution includes a small Bourne-compatible shell (ash)
+and a number of other utilities, so you can replace kinit and build
+custom initramfs images that meet your needs exactly.
+
+For questions and help, you can sign up for the early userspace
+mailing list at http://www.zytor.com/mailman/listinfo/klibc
+
+How does it work?
+=================
+
+The kernel has currently 3 ways to mount the root filesystem:
+
+a) all required device and filesystem drivers compiled into the kernel, no
+   initrd.  init/main.c:init() will call prepare_namespace() to mount the
+   final root filesystem, based on the root= option and optional init= to run
+   some other init binary than listed at the end of init/main.c:init().
+
+b) some device and filesystem drivers built as modules and stored in an
+   initrd.  The initrd must contain a binary '/linuxrc' which is supposed to
+   load these driver modules.  It is also possible to mount the final root
+   filesystem via linuxrc and use the pivot_root syscall.  The initrd is
+   mounted and executed via prepare_namespace().
+
+c) using initramfs.  The call to prepare_namespace() must be skipped.
+   This means that a binary must do all the work.  Said binary can be stored
+   into initramfs either via modifying usr/gen_init_cpio.c or via the new
+   initrd format, an cpio archive.  It must be called "/init".  This binary
+   is responsible to do all the things prepare_namespace() would do.
+
+   To maintain backwards compatibility, the /init binary will only run if it
+   comes via an initramfs cpio archive.  If this is not the case,
+   init/main.c:init() will run prepare_namespace() to mount the final root
+   and exec one of the predefined init binaries.
+
+Bryan O'Sullivan <bos@serpentine.com>
diff --git a/Documentation/driver-api/early-userspace/index.rst b/Documentation/driver-api/early-userspace/index.rst
new file mode 100644 (file)
index 0000000..149c182
--- /dev/null
@@ -0,0 +1,18 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===============
+Early Userspace
+===============
+
+.. toctree::
+    :maxdepth: 1
+
+    early_userspace_support
+    buffer-format
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
diff --git a/Documentation/driver-api/edid.rst b/Documentation/driver-api/edid.rst
new file mode 100644 (file)
index 0000000..b1b5acd
--- /dev/null
@@ -0,0 +1,58 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+====
+EDID
+====
+
+In the good old days when graphics parameters were configured explicitly
+in a file called xorg.conf, even broken hardware could be managed.
+
+Today, with the advent of Kernel Mode Setting, a graphics board is
+either correctly working because all components follow the standards -
+or the computer is unusable, because the screen remains dark after
+booting or it displays the wrong area. Cases when this happens are:
+- The graphics board does not recognize the monitor.
+- The graphics board is unable to detect any EDID data.
+- The graphics board incorrectly forwards EDID data to the driver.
+- The monitor sends no or bogus EDID data.
+- A KVM sends its own EDID data instead of querying the connected monitor.
+Adding the kernel parameter "nomodeset" helps in most cases, but causes
+restrictions later on.
+
+As a remedy for such situations, the kernel configuration item
+CONFIG_DRM_LOAD_EDID_FIRMWARE was introduced. It allows to provide an
+individually prepared or corrected EDID data set in the /lib/firmware
+directory from where it is loaded via the firmware interface. The code
+(see drivers/gpu/drm/drm_edid_load.c) contains built-in data sets for
+commonly used screen resolutions (800x600, 1024x768, 1280x1024, 1600x1200,
+1680x1050, 1920x1080) as binary blobs, but the kernel source tree does
+not contain code to create these data. In order to elucidate the origin
+of the built-in binary EDID blobs and to facilitate the creation of
+individual data for a specific misbehaving monitor, commented sources
+and a Makefile environment are given here.
+
+To create binary EDID and C source code files from the existing data
+material, simply type "make".
+
+If you want to create your own EDID file, copy the file 1024x768.S,
+replace the settings with your own data and add a new target to the
+Makefile. Please note that the EDID data structure expects the timing
+values in a different way as compared to the standard X11 format.
+
+X11:
+  HTimings:
+    hdisp hsyncstart hsyncend htotal
+  VTimings:
+    vdisp vsyncstart vsyncend vtotal
+
+EDID::
+
+  #define XPIX hdisp
+  #define XBLANK htotal-hdisp
+  #define XOFFSET hsyncstart-hdisp
+  #define XPULSE hsyncend-hsyncstart
+
+  #define YPIX vdisp
+  #define YBLANK vtotal-vdisp
+  #define YOFFSET vsyncstart-vdisp
+  #define YPULSE vsyncend-vsyncstart
diff --git a/Documentation/driver-api/eisa.rst b/Documentation/driver-api/eisa.rst
new file mode 100644 (file)
index 0000000..c07565b
--- /dev/null
@@ -0,0 +1,230 @@
+================
+EISA bus support
+================
+
+:Author: Marc Zyngier <maz@wild-wind.fr.eu.org>
+
+This document groups random notes about porting EISA drivers to the
+new EISA/sysfs API.
+
+Starting from version 2.5.59, the EISA bus is almost given the same
+status as other much more mainstream busses such as PCI or USB. This
+has been possible through sysfs, which defines a nice enough set of
+abstractions to manage busses, devices and drivers.
+
+Although the new API is quite simple to use, converting existing
+drivers to the new infrastructure is not an easy task (mostly because
+detection code is generally also used to probe ISA cards). Moreover,
+most EISA drivers are among the oldest Linux drivers so, as you can
+imagine, some dust has settled here over the years.
+
+The EISA infrastructure is made up of three parts:
+
+    - The bus code implements most of the generic code. It is shared
+      among all the architectures that the EISA code runs on. It
+      implements bus probing (detecting EISA cards available on the bus),
+      allocates I/O resources, allows fancy naming through sysfs, and
+      offers interfaces for driver to register.
+
+    - The bus root driver implements the glue between the bus hardware
+      and the generic bus code. It is responsible for discovering the
+      device implementing the bus, and setting it up to be latter probed
+      by the bus code. This can go from something as simple as reserving
+      an I/O region on x86, to the rather more complex, like the hppa
+      EISA code. This is the part to implement in order to have EISA
+      running on an "new" platform.
+
+    - The driver offers the bus a list of devices that it manages, and
+      implements the necessary callbacks to probe and release devices
+      whenever told to.
+
+Every function/structure below lives in <linux/eisa.h>, which depends
+heavily on <linux/device.h>.
+
+Bus root driver
+===============
+
+::
+
+       int eisa_root_register (struct eisa_root_device *root);
+
+The eisa_root_register function is used to declare a device as the
+root of an EISA bus. The eisa_root_device structure holds a reference
+to this device, as well as some parameters for probing purposes::
+
+       struct eisa_root_device {
+               struct device   *dev;    /* Pointer to bridge device */
+               struct resource *res;
+               unsigned long    bus_base_addr;
+               int              slots;  /* Max slot number */
+               int              force_probe; /* Probe even when no slot 0 */
+               u64              dma_mask; /* from bridge device */
+               int              bus_nr; /* Set by eisa_root_register */
+               struct resource  eisa_root_res; /* ditto */
+       };
+
+============= ======================================================
+node          used for eisa_root_register internal purpose
+dev           pointer to the root device
+res           root device I/O resource
+bus_base_addr slot 0 address on this bus
+slots        max slot number to probe
+force_probe   Probe even when slot 0 is empty (no EISA mainboard)
+dma_mask      Default DMA mask. Usually the bridge device dma_mask.
+bus_nr       unique bus id, set by eisa_root_register
+============= ======================================================
+
+Driver
+======
+
+::
+
+       int eisa_driver_register (struct eisa_driver *edrv);
+       void eisa_driver_unregister (struct eisa_driver *edrv);
+
+Clear enough ?
+
+::
+
+       struct eisa_device_id {
+               char sig[EISA_SIG_LEN];
+               unsigned long driver_data;
+       };
+
+       struct eisa_driver {
+               const struct eisa_device_id *id_table;
+               struct device_driver         driver;
+       };
+
+=============== ====================================================
+id_table       an array of NULL terminated EISA id strings,
+               followed by an empty string. Each string can
+               optionally be paired with a driver-dependent value
+               (driver_data).
+
+driver         a generic driver, such as described in
+               Documentation/driver-api/driver-model/driver.rst. Only .name,
+               .probe and .remove members are mandatory.
+=============== ====================================================
+
+An example is the 3c59x driver::
+
+       static struct eisa_device_id vortex_eisa_ids[] = {
+               { "TCM5920", EISA_3C592_OFFSET },
+               { "TCM5970", EISA_3C597_OFFSET },
+               { "" }
+       };
+
+       static struct eisa_driver vortex_eisa_driver = {
+               .id_table = vortex_eisa_ids,
+               .driver   = {
+                       .name    = "3c59x",
+                       .probe   = vortex_eisa_probe,
+                       .remove  = vortex_eisa_remove
+               }
+       };
+
+Device
+======
+
+The sysfs framework calls .probe and .remove functions upon device
+discovery and removal (note that the .remove function is only called
+when driver is built as a module).
+
+Both functions are passed a pointer to a 'struct device', which is
+encapsulated in a 'struct eisa_device' described as follows::
+
+       struct eisa_device {
+               struct eisa_device_id id;
+               int                   slot;
+               int                   state;
+               unsigned long         base_addr;
+               struct resource       res[EISA_MAX_RESOURCES];
+               u64                   dma_mask;
+               struct device         dev; /* generic device */
+       };
+
+======== ============================================================
+id      EISA id, as read from device. id.driver_data is set from the
+        matching driver EISA id.
+slot    slot number which the device was detected on
+state    set of flags indicating the state of the device. Current
+        flags are EISA_CONFIG_ENABLED and EISA_CONFIG_FORCED.
+res     set of four 256 bytes I/O regions allocated to this device
+dma_mask DMA mask set from the parent device.
+dev     generic device (see Documentation/driver-api/driver-model/device.rst)
+======== ============================================================
+
+You can get the 'struct eisa_device' from 'struct device' using the
+'to_eisa_device' macro.
+
+Misc stuff
+==========
+
+::
+
+       void eisa_set_drvdata (struct eisa_device *edev, void *data);
+
+Stores data into the device's driver_data area.
+
+::
+
+       void *eisa_get_drvdata (struct eisa_device *edev):
+
+Gets the pointer previously stored into the device's driver_data area.
+
+::
+
+       int eisa_get_region_index (void *addr);
+
+Returns the region number (0 <= x < EISA_MAX_RESOURCES) of a given
+address.
+
+Kernel parameters
+=================
+
+eisa_bus.enable_dev
+       A comma-separated list of slots to be enabled, even if the firmware
+       set the card as disabled. The driver must be able to properly
+       initialize the device in such conditions.
+
+eisa_bus.disable_dev
+       A comma-separated list of slots to be enabled, even if the firmware
+       set the card as enabled. The driver won't be called to handle this
+       device.
+
+virtual_root.force_probe
+       Force the probing code to probe EISA slots even when it cannot find an
+       EISA compliant mainboard (nothing appears on slot 0). Defaults to 0
+       (don't force), and set to 1 (force probing) when either
+       CONFIG_ALPHA_JENSEN or CONFIG_EISA_VLB_PRIMING are set.
+
+Random notes
+============
+
+Converting an EISA driver to the new API mostly involves *deleting*
+code (since probing is now in the core EISA code). Unfortunately, most
+drivers share their probing routine between ISA, and EISA. Special
+care must be taken when ripping out the EISA code, so other busses
+won't suffer from these surgical strikes...
+
+You *must not* expect any EISA device to be detected when returning
+from eisa_driver_register, since the chances are that the bus has not
+yet been probed. In fact, that's what happens most of the time (the
+bus root driver usually kicks in rather late in the boot process).
+Unfortunately, most drivers are doing the probing by themselves, and
+expect to have explored the whole machine when they exit their probe
+routine.
+
+For example, switching your favorite EISA SCSI card to the "hotplug"
+model is "the right thing"(tm).
+
+Thanks
+======
+
+I'd like to thank the following people for their help:
+
+- Xavier Benigni for lending me a wonderful Alpha Jensen,
+- James Bottomley, Jeff Garzik for getting this stuff into the kernel,
+- Andries Brouwer for contributing numerous EISA ids,
+- Catrin Jones for coping with far too many machines at home.
index 349f2dc..921c71a 100644 (file)
@@ -399,7 +399,7 @@ symbol:
   will pass the struct gpio_chip* for the chip to all IRQ callbacks, so the
   callbacks need to embed the gpio_chip in its state container and obtain a
   pointer to the container using container_of().
-  (See Documentation/driver-model/design-patterns.rst)
+  (See Documentation/driver-api/driver-model/design-patterns.rst)
 
 - gpiochip_irqchip_add_nested(): adds a nested cascaded irqchip to a gpiochip,
   as discussed above regarding different types of cascaded irqchips. The
index 6cd750a..d12a80f 100644 (file)
@@ -14,8 +14,10 @@ available subsections can be seen below.
 .. toctree::
    :maxdepth: 2
 
+   driver-model/index
    basics
    infrastructure
+   early-userspace/index
    pm/index
    clk
    device-io
@@ -36,6 +38,7 @@ available subsections can be seen below.
    i2c
    ipmb
    i3c/index
+   interconnect
    hsi
    edac
    scsi
@@ -44,8 +47,11 @@ available subsections can be seen below.
    mtdnand
    miscellaneous
    mei/index
+   mtd/index
+   mmc/index
+   nvdimm/index
    w1
-   rapidio
+   rapidio/index
    s390-drivers
    vme
    80211/index
@@ -53,13 +59,48 @@ available subsections can be seen below.
    firmware/index
    pinctl
    gpio/index
+   md/index
    misc_devices
+   nfc/index
    dmaengine/index
    slimbus
    soundwire/index
    fpga/index
    acpi/index
+   backlight/lp855x-driver.rst
+   bt8xxgpio
+   connector
+   console
+   dcdbas
+   dell_rbu
+   edid
+   eisa
+   isa
+   isapnp
    generic-counter
+   lightnvm-pblk
+   memory-devices/index
+   men-chameleon-bus
+   ntb
+   nvmem
+   parport-lowlevel
+   pps
+   ptp
+   phy/index
+   pti_intel_mid
+   pwm
+   rfkill
+   serial/index
+   sgi-ioc4
+   sm501
+   smsc_ece1099
+   switchtec
+   sync_file
+   vfio-mediated-device
+   vfio
+   xilinx/index
+   xillybus
+   zorro
 
 .. only::  subproject and html
 
diff --git a/Documentation/driver-api/interconnect.rst b/Documentation/driver-api/interconnect.rst
new file mode 100644 (file)
index 0000000..c3e0048
--- /dev/null
@@ -0,0 +1,93 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=====================================
+GENERIC SYSTEM INTERCONNECT SUBSYSTEM
+=====================================
+
+Introduction
+------------
+
+This framework is designed to provide a standard kernel interface to control
+the settings of the interconnects on an SoC. These settings can be throughput,
+latency and priority between multiple interconnected devices or functional
+blocks. This can be controlled dynamically in order to save power or provide
+maximum performance.
+
+The interconnect bus is hardware with configurable parameters, which can be
+set on a data path according to the requests received from various drivers.
+An example of interconnect buses are the interconnects between various
+components or functional blocks in chipsets. There can be multiple interconnects
+on an SoC that can be multi-tiered.
+
+Below is a simplified diagram of a real-world SoC interconnect bus topology.
+
+::
+
+ +----------------+    +----------------+
+ | HW Accelerator |--->|      M NoC     |<---------------+
+ +----------------+    +----------------+                |
+                         |      |                    +------------+
+  +-----+  +-------------+      V       +------+     |            |
+  | DDR |  |                +--------+  | PCIe |     |            |
+  +-----+  |                | Slaves |  +------+     |            |
+    ^ ^    |                +--------+     |         |   C NoC    |
+    | |    V                               V         |            |
+ +------------------+   +------------------------+   |            |   +-----+
+ |                  |-->|                        |-->|            |-->| CPU |
+ |                  |-->|                        |<--|            |   +-----+
+ |     Mem NoC      |   |         S NoC          |   +------------+
+ |                  |<--|                        |---------+    |
+ |                  |<--|                        |<------+ |    |   +--------+
+ +------------------+   +------------------------+       | |    +-->| Slaves |
+   ^  ^    ^    ^          ^                             | |        +--------+
+   |  |    |    |          |                             | V
+ +------+  |  +-----+   +-----+  +---------+   +----------------+   +--------+
+ | CPUs |  |  | GPU |   | DSP |  | Masters |-->|       P NoC    |-->| Slaves |
+ +------+  |  +-----+   +-----+  +---------+   +----------------+   +--------+
+           |
+       +-------+
+       | Modem |
+       +-------+
+
+Terminology
+-----------
+
+Interconnect provider is the software definition of the interconnect hardware.
+The interconnect providers on the above diagram are M NoC, S NoC, C NoC, P NoC
+and Mem NoC.
+
+Interconnect node is the software definition of the interconnect hardware
+port. Each interconnect provider consists of multiple interconnect nodes,
+which are connected to other SoC components including other interconnect
+providers. The point on the diagram where the CPUs connect to the memory is
+called an interconnect node, which belongs to the Mem NoC interconnect provider.
+
+Interconnect endpoints are the first or the last element of the path. Every
+endpoint is a node, but not every node is an endpoint.
+
+Interconnect path is everything between two endpoints including all the nodes
+that have to be traversed to reach from a source to destination node. It may
+include multiple master-slave pairs across several interconnect providers.
+
+Interconnect consumers are the entities which make use of the data paths exposed
+by the providers. The consumers send requests to providers requesting various
+throughput, latency and priority. Usually the consumers are device drivers, that
+send request based on their needs. An example for a consumer is a video decoder
+that supports various formats and image sizes.
+
+Interconnect providers
+----------------------
+
+Interconnect provider is an entity that implements methods to initialize and
+configure interconnect bus hardware. The interconnect provider drivers should
+be registered with the interconnect provider core.
+
+.. kernel-doc:: include/linux/interconnect-provider.h
+
+Interconnect consumers
+----------------------
+
+Interconnect consumers are the clients which use the interconnect APIs to
+get paths between endpoints and set their bandwidth/latency/QoS requirements
+for these interconnect paths.  These interfaces are not currently
+documented.
diff --git a/Documentation/driver-api/md/index.rst b/Documentation/driver-api/md/index.rst
new file mode 100644 (file)
index 0000000..18f54a7
--- /dev/null
@@ -0,0 +1,12 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+====
+RAID
+====
+
+.. toctree::
+   :maxdepth: 1
+
+   md-cluster
+   raid5-cache
+   raid5-ppl
diff --git a/Documentation/driver-api/md/md-cluster.rst b/Documentation/driver-api/md/md-cluster.rst
new file mode 100644 (file)
index 0000000..96eb52c
--- /dev/null
@@ -0,0 +1,385 @@
+==========
+MD Cluster
+==========
+
+The cluster MD is a shared-device RAID for a cluster, it supports
+two levels: raid1 and raid10 (limited support).
+
+
+1. On-disk format
+=================
+
+Separate write-intent-bitmaps are used for each cluster node.
+The bitmaps record all writes that may have been started on that node,
+and may not yet have finished. The on-disk layout is::
+
+  0                    4k                     8k                    12k
+  -------------------------------------------------------------------
+  | idle                | md super            | bm super [0] + bits |
+  | bm bits[0, contd]   | bm super[1] + bits  | bm bits[1, contd]   |
+  | bm super[2] + bits  | bm bits [2, contd]  | bm super[3] + bits  |
+  | bm bits [3, contd]  |                     |                     |
+
+During "normal" functioning we assume the filesystem ensures that only
+one node writes to any given block at a time, so a write request will
+
+ - set the appropriate bit (if not already set)
+ - commit the write to all mirrors
+ - schedule the bit to be cleared after a timeout.
+
+Reads are just handled normally. It is up to the filesystem to ensure
+one node doesn't read from a location where another node (or the same
+node) is writing.
+
+
+2. DLM Locks for management
+===========================
+
+There are three groups of locks for managing the device:
+
+2.1 Bitmap lock resource (bm_lockres)
+-------------------------------------
+
+ The bm_lockres protects individual node bitmaps. They are named in
+ the form bitmap000 for node 1, bitmap001 for node 2 and so on. When a
+ node joins the cluster, it acquires the lock in PW mode and it stays
+ so during the lifetime the node is part of the cluster. The lock
+ resource number is based on the slot number returned by the DLM
+ subsystem. Since DLM starts node count from one and bitmap slots
+ start from zero, one is subtracted from the DLM slot number to arrive
+ at the bitmap slot number.
+
+ The LVB of the bitmap lock for a particular node records the range
+ of sectors that are being re-synced by that node.  No other
+ node may write to those sectors.  This is used when a new nodes
+ joins the cluster.
+
+2.2 Message passing locks
+-------------------------
+
+ Each node has to communicate with other nodes when starting or ending
+ resync, and for metadata superblock updates.  This communication is
+ managed through three locks: "token", "message", and "ack", together
+ with the Lock Value Block (LVB) of one of the "message" lock.
+
+2.3 new-device management
+-------------------------
+
+ A single lock: "no-new-dev" is used to co-ordinate the addition of
+ new devices - this must be synchronized across the array.
+ Normally all nodes hold a concurrent-read lock on this device.
+
+3. Communication
+================
+
+ Messages can be broadcast to all nodes, and the sender waits for all
+ other nodes to acknowledge the message before proceeding.  Only one
+ message can be processed at a time.
+
+3.1 Message Types
+-----------------
+
+ There are six types of messages which are passed:
+
+3.1.1 METADATA_UPDATED
+^^^^^^^^^^^^^^^^^^^^^^
+
+   informs other nodes that the metadata has
+   been updated, and the node must re-read the md superblock. This is
+   performed synchronously. It is primarily used to signal device
+   failure.
+
+3.1.2 RESYNCING
+^^^^^^^^^^^^^^^
+   informs other nodes that a resync is initiated or
+   ended so that each node may suspend or resume the region.  Each
+   RESYNCING message identifies a range of the devices that the
+   sending node is about to resync. This overrides any previous
+   notification from that node: only one ranged can be resynced at a
+   time per-node.
+
+3.1.3 NEWDISK
+^^^^^^^^^^^^^
+
+   informs other nodes that a device is being added to
+   the array. Message contains an identifier for that device.  See
+   below for further details.
+
+3.1.4 REMOVE
+^^^^^^^^^^^^
+
+   A failed or spare device is being removed from the
+   array. The slot-number of the device is included in the message.
+
+ 3.1.5 RE_ADD:
+
+   A failed device is being re-activated - the assumption
+   is that it has been determined to be working again.
+
+ 3.1.6 BITMAP_NEEDS_SYNC:
+
+   If a node is stopped locally but the bitmap
+   isn't clean, then another node is informed to take the ownership of
+   resync.
+
+3.2 Communication mechanism
+---------------------------
+
+ The DLM LVB is used to communicate within nodes of the cluster. There
+ are three resources used for the purpose:
+
+3.2.1 token
+^^^^^^^^^^^
+   The resource which protects the entire communication
+   system. The node having the token resource is allowed to
+   communicate.
+
+3.2.2 message
+^^^^^^^^^^^^^
+   The lock resource which carries the data to communicate.
+
+3.2.3 ack
+^^^^^^^^^
+
+   The resource, acquiring which means the message has been
+   acknowledged by all nodes in the cluster. The BAST of the resource
+   is used to inform the receiving node that a node wants to
+   communicate.
+
+The algorithm is:
+
+ 1. receive status - all nodes have concurrent-reader lock on "ack"::
+
+       sender                         receiver                 receiver
+       "ack":CR                       "ack":CR                 "ack":CR
+
+ 2. sender get EX on "token",
+    sender get EX on "message"::
+
+       sender                        receiver                 receiver
+       "token":EX                    "ack":CR                 "ack":CR
+       "message":EX
+       "ack":CR
+
+    Sender checks that it still needs to send a message. Messages
+    received or other events that happened while waiting for the
+    "token" may have made this message inappropriate or redundant.
+
+ 3. sender writes LVB
+
+    sender down-convert "message" from EX to CW
+
+    sender try to get EX of "ack"
+
+    ::
+
+      [ wait until all receivers have *processed* the "message" ]
+
+                                       [ triggered by bast of "ack" ]
+                                       receiver get CR on "message"
+                                       receiver read LVB
+                                       receiver processes the message
+                                       [ wait finish ]
+                                       receiver releases "ack"
+                                       receiver tries to get PR on "message"
+
+     sender                         receiver                  receiver
+     "token":EX                     "message":CR              "message":CR
+     "message":CW
+     "ack":EX
+
+ 4. triggered by grant of EX on "ack" (indicating all receivers
+    have processed message)
+
+    sender down-converts "ack" from EX to CR
+
+    sender releases "message"
+
+    sender releases "token"
+
+    ::
+
+                                 receiver upconvert to PR on "message"
+                                 receiver get CR of "ack"
+                                 receiver release "message"
+
+     sender                      receiver                   receiver
+     "ack":CR                    "ack":CR                   "ack":CR
+
+
+4. Handling Failures
+====================
+
+4.1 Node Failure
+----------------
+
+ When a node fails, the DLM informs the cluster with the slot
+ number. The node starts a cluster recovery thread. The cluster
+ recovery thread:
+
+       - acquires the bitmap<number> lock of the failed node
+       - opens the bitmap
+       - reads the bitmap of the failed node
+       - copies the set bitmap to local node
+       - cleans the bitmap of the failed node
+       - releases bitmap<number> lock of the failed node
+       - initiates resync of the bitmap on the current node
+         md_check_recovery is invoked within recover_bitmaps,
+         then md_check_recovery -> metadata_update_start/finish,
+         it will lock the communication by lock_comm.
+         Which means when one node is resyncing it blocks all
+         other nodes from writing anywhere on the array.
+
+ The resync process is the regular md resync. However, in a clustered
+ environment when a resync is performed, it needs to tell other nodes
+ of the areas which are suspended. Before a resync starts, the node
+ send out RESYNCING with the (lo,hi) range of the area which needs to
+ be suspended. Each node maintains a suspend_list, which contains the
+ list of ranges which are currently suspended. On receiving RESYNCING,
+ the node adds the range to the suspend_list. Similarly, when the node
+ performing resync finishes, it sends RESYNCING with an empty range to
+ other nodes and other nodes remove the corresponding entry from the
+ suspend_list.
+
+ A helper function, ->area_resyncing() can be used to check if a
+ particular I/O range should be suspended or not.
+
+4.2 Device Failure
+==================
+
+ Device failures are handled and communicated with the metadata update
+ routine.  When a node detects a device failure it does not allow
+ any further writes to that device until the failure has been
+ acknowledged by all other nodes.
+
+5. Adding a new Device
+----------------------
+
+ For adding a new device, it is necessary that all nodes "see" the new
+ device to be added. For this, the following algorithm is used:
+
+   1.  Node 1 issues mdadm --manage /dev/mdX --add /dev/sdYY which issues
+       ioctl(ADD_NEW_DISK with disc.state set to MD_DISK_CLUSTER_ADD)
+   2.  Node 1 sends a NEWDISK message with uuid and slot number
+   3.  Other nodes issue kobject_uevent_env with uuid and slot number
+       (Steps 4,5 could be a udev rule)
+   4.  In userspace, the node searches for the disk, perhaps
+       using blkid -t SUB_UUID=""
+   5.  Other nodes issue either of the following depending on whether
+       the disk was found:
+       ioctl(ADD_NEW_DISK with disc.state set to MD_DISK_CANDIDATE and
+       disc.number set to slot number)
+       ioctl(CLUSTERED_DISK_NACK)
+   6.  Other nodes drop lock on "no-new-devs" (CR) if device is found
+   7.  Node 1 attempts EX lock on "no-new-dev"
+   8.  If node 1 gets the lock, it sends METADATA_UPDATED after
+       unmarking the disk as SpareLocal
+   9.  If not (get "no-new-dev" lock), it fails the operation and sends
+       METADATA_UPDATED.
+   10. Other nodes get the information whether a disk is added or not
+       by the following METADATA_UPDATED.
+
+6. Module interface
+===================
+
+ There are 17 call-backs which the md core can make to the cluster
+ module.  Understanding these can give a good overview of the whole
+ process.
+
+6.1 join(nodes) and leave()
+---------------------------
+
+ These are called when an array is started with a clustered bitmap,
+ and when the array is stopped.  join() ensures the cluster is
+ available and initializes the various resources.
+ Only the first 'nodes' nodes in the cluster can use the array.
+
+6.2 slot_number()
+-----------------
+
+ Reports the slot number advised by the cluster infrastructure.
+ Range is from 0 to nodes-1.
+
+6.3 resync_info_update()
+------------------------
+
+ This updates the resync range that is stored in the bitmap lock.
+ The starting point is updated as the resync progresses.  The
+ end point is always the end of the array.
+ It does *not* send a RESYNCING message.
+
+6.4 resync_start(), resync_finish()
+-----------------------------------
+
+ These are called when resync/recovery/reshape starts or stops.
+ They update the resyncing range in the bitmap lock and also
+ send a RESYNCING message.  resync_start reports the whole
+ array as resyncing, resync_finish reports none of it.
+
+ resync_finish() also sends a BITMAP_NEEDS_SYNC message which
+ allows some other node to take over.
+
+6.5 metadata_update_start(), metadata_update_finish(), metadata_update_cancel()
+-------------------------------------------------------------------------------
+
+ metadata_update_start is used to get exclusive access to
+ the metadata.  If a change is still needed once that access is
+ gained, metadata_update_finish() will send a METADATA_UPDATE
+ message to all other nodes, otherwise metadata_update_cancel()
+ can be used to release the lock.
+
+6.6 area_resyncing()
+--------------------
+
+ This combines two elements of functionality.
+
+ Firstly, it will check if any node is currently resyncing
+ anything in a given range of sectors.  If any resync is found,
+ then the caller will avoid writing or read-balancing in that
+ range.
+
+ Secondly, while node recovery is happening it reports that
+ all areas are resyncing for READ requests.  This avoids races
+ between the cluster-filesystem and the cluster-RAID handling
+ a node failure.
+
+6.7 add_new_disk_start(), add_new_disk_finish(), new_disk_ack()
+---------------------------------------------------------------
+
+ These are used to manage the new-disk protocol described above.
+ When a new device is added, add_new_disk_start() is called before
+ it is bound to the array and, if that succeeds, add_new_disk_finish()
+ is called the device is fully added.
+
+ When a device is added in acknowledgement to a previous
+ request, or when the device is declared "unavailable",
+ new_disk_ack() is called.
+
+6.8 remove_disk()
+-----------------
+
+ This is called when a spare or failed device is removed from
+ the array.  It causes a REMOVE message to be send to other nodes.
+
+6.9 gather_bitmaps()
+--------------------
+
+ This sends a RE_ADD message to all other nodes and then
+ gathers bitmap information from all bitmaps.  This combined
+ bitmap is then used to recovery the re-added device.
+
+6.10 lock_all_bitmaps() and unlock_all_bitmaps()
+------------------------------------------------
+
+ These are called when change bitmap to none. If a node plans
+ to clear the cluster raid's bitmap, it need to make sure no other
+ nodes are using the raid which is achieved by lock all bitmap
+ locks within the cluster, and also those locks are unlocked
+ accordingly.
+
+7. Unsupported features
+=======================
+
+There are somethings which are not supported by cluster MD yet.
+
+- change array_sectors.
diff --git a/Documentation/driver-api/md/raid5-cache.rst b/Documentation/driver-api/md/raid5-cache.rst
new file mode 100644 (file)
index 0000000..d7a15f4
--- /dev/null
@@ -0,0 +1,111 @@
+================
+RAID 4/5/6 cache
+================
+
+Raid 4/5/6 could include an extra disk for data cache besides normal RAID
+disks. The role of RAID disks isn't changed with the cache disk. The cache disk
+caches data to the RAID disks. The cache can be in write-through (supported
+since 4.4) or write-back mode (supported since 4.10). mdadm (supported since
+3.4) has a new option '--write-journal' to create array with cache. Please
+refer to mdadm manual for details. By default (RAID array starts), the cache is
+in write-through mode. A user can switch it to write-back mode by::
+
+       echo "write-back" > /sys/block/md0/md/journal_mode
+
+And switch it back to write-through mode by::
+
+       echo "write-through" > /sys/block/md0/md/journal_mode
+
+In both modes, all writes to the array will hit cache disk first. This means
+the cache disk must be fast and sustainable.
+
+write-through mode
+==================
+
+This mode mainly fixes the 'write hole' issue. For RAID 4/5/6 array, an unclean
+shutdown can cause data in some stripes to not be in consistent state, eg, data
+and parity don't match. The reason is that a stripe write involves several RAID
+disks and it's possible the writes don't hit all RAID disks yet before the
+unclean shutdown. We call an array degraded if it has inconsistent data. MD
+tries to resync the array to bring it back to normal state. But before the
+resync completes, any system crash will expose the chance of real data
+corruption in the RAID array. This problem is called 'write hole'.
+
+The write-through cache will cache all data on cache disk first. After the data
+is safe on the cache disk, the data will be flushed onto RAID disks. The
+two-step write will guarantee MD can recover correct data after unclean
+shutdown even the array is degraded. Thus the cache can close the 'write hole'.
+
+In write-through mode, MD reports IO completion to upper layer (usually
+filesystems) after the data is safe on RAID disks, so cache disk failure
+doesn't cause data loss. Of course cache disk failure means the array is
+exposed to 'write hole' again.
+
+In write-through mode, the cache disk isn't required to be big. Several
+hundreds megabytes are enough.
+
+write-back mode
+===============
+
+write-back mode fixes the 'write hole' issue too, since all write data is
+cached on cache disk. But the main goal of 'write-back' cache is to speed up
+write. If a write crosses all RAID disks of a stripe, we call it full-stripe
+write. For non-full-stripe writes, MD must read old data before the new parity
+can be calculated. These synchronous reads hurt write throughput. Some writes
+which are sequential but not dispatched in the same time will suffer from this
+overhead too. Write-back cache will aggregate the data and flush the data to
+RAID disks only after the data becomes a full stripe write. This will
+completely avoid the overhead, so it's very helpful for some workloads. A
+typical workload which does sequential write followed by fsync is an example.
+
+In write-back mode, MD reports IO completion to upper layer (usually
+filesystems) right after the data hits cache disk. The data is flushed to raid
+disks later after specific conditions met. So cache disk failure will cause
+data loss.
+
+In write-back mode, MD also caches data in memory. The memory cache includes
+the same data stored on cache disk, so a power loss doesn't cause data loss.
+The memory cache size has performance impact for the array. It's recommended
+the size is big. A user can configure the size by::
+
+       echo "2048" > /sys/block/md0/md/stripe_cache_size
+
+Too small cache disk will make the write aggregation less efficient in this
+mode depending on the workloads. It's recommended to use a cache disk with at
+least several gigabytes size in write-back mode.
+
+The implementation
+==================
+
+The write-through and write-back cache use the same disk format. The cache disk
+is organized as a simple write log. The log consists of 'meta data' and 'data'
+pairs. The meta data describes the data. It also includes checksum and sequence
+ID for recovery identification. Data can be IO data and parity data. Data is
+checksumed too. The checksum is stored in the meta data ahead of the data. The
+checksum is an optimization because MD can write meta and data freely without
+worry about the order. MD superblock has a field pointed to the valid meta data
+of log head.
+
+The log implementation is pretty straightforward. The difficult part is the
+order in which MD writes data to cache disk and RAID disks. Specifically, in
+write-through mode, MD calculates parity for IO data, writes both IO data and
+parity to the log, writes the data and parity to RAID disks after the data and
+parity is settled down in log and finally the IO is finished. Read just reads
+from raid disks as usual.
+
+In write-back mode, MD writes IO data to the log and reports IO completion. The
+data is also fully cached in memory at that time, which means read must query
+memory cache. If some conditions are met, MD will flush the data to RAID disks.
+MD will calculate parity for the data and write parity into the log. After this
+is finished, MD will write both data and parity into RAID disks, then MD can
+release the memory cache. The flush conditions could be stripe becomes a full
+stripe write, free cache disk space is low or free in-kernel memory cache space
+is low.
+
+After an unclean shutdown, MD does recovery. MD reads all meta data and data
+from the log. The sequence ID and checksum will help us detect corrupted meta
+data and data. If MD finds a stripe with data and valid parities (1 parity for
+raid4/5 and 2 for raid6), MD will write the data and parities to RAID disks. If
+parities are incompleted, they are discarded. If part of data is corrupted,
+they are discarded too. MD then loads valid data and writes them to RAID disks
+in normal way.
diff --git a/Documentation/driver-api/md/raid5-ppl.rst b/Documentation/driver-api/md/raid5-ppl.rst
new file mode 100644 (file)
index 0000000..357e551
--- /dev/null
@@ -0,0 +1,47 @@
+==================
+Partial Parity Log
+==================
+
+Partial Parity Log (PPL) is a feature available for RAID5 arrays. The issue
+addressed by PPL is that after a dirty shutdown, parity of a particular stripe
+may become inconsistent with data on other member disks. If the array is also
+in degraded state, there is no way to recalculate parity, because one of the
+disks is missing. This can lead to silent data corruption when rebuilding the
+array or using it is as degraded - data calculated from parity for array blocks
+that have not been touched by a write request during the unclean shutdown can
+be incorrect. Such condition is known as the RAID5 Write Hole. Because of
+this, md by default does not allow starting a dirty degraded array.
+
+Partial parity for a write operation is the XOR of stripe data chunks not
+modified by this write. It is just enough data needed for recovering from the
+write hole. XORing partial parity with the modified chunks produces parity for
+the stripe, consistent with its state before the write operation, regardless of
+which chunk writes have completed. If one of the not modified data disks of
+this stripe is missing, this updated parity can be used to recover its
+contents. PPL recovery is also performed when starting an array after an
+unclean shutdown and all disks are available, eliminating the need to resync
+the array. Because of this, using write-intent bitmap and PPL together is not
+supported.
+
+When handling a write request PPL writes partial parity before new data and
+parity are dispatched to disks. PPL is a distributed log - it is stored on
+array member drives in the metadata area, on the parity drive of a particular
+stripe.  It does not require a dedicated journaling drive. Write performance is
+reduced by up to 30%-40% but it scales with the number of drives in the array
+and the journaling drive does not become a bottleneck or a single point of
+failure.
+
+Unlike raid5-cache, the other solution in md for closing the write hole, PPL is
+not a true journal. It does not protect from losing in-flight data, only from
+silent data corruption. If a dirty disk of a stripe is lost, no PPL recovery is
+performed for this stripe (parity is not updated). So it is possible to have
+arbitrary data in the written part of a stripe if that disk is lost. In such
+case the behavior is the same as in plain raid5.
+
+PPL is available for md version-1 metadata and external (specifically IMSM)
+metadata arrays. It can be enabled using mdadm option --consistency-policy=ppl.
+
+There is a limitation of maximum 64 disks in the array for PPL. It allows to
+keep data structures and implementation simple. RAID5 arrays with so many disks
+are not likely due to high risk of multiple disks failure. Such restriction
+should not be a real life limitation.
diff --git a/Documentation/driver-api/memory-devices/index.rst b/Documentation/driver-api/memory-devices/index.rst
new file mode 100644 (file)
index 0000000..2810145
--- /dev/null
@@ -0,0 +1,18 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=========================
+Memory Controller drivers
+=========================
+
+.. toctree::
+    :maxdepth: 1
+
+    ti-emif
+    ti-gpmc
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
diff --git a/Documentation/driver-api/memory-devices/ti-emif.rst b/Documentation/driver-api/memory-devices/ti-emif.rst
new file mode 100644 (file)
index 0000000..dea2ad9
--- /dev/null
@@ -0,0 +1,64 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===============================
+TI EMIF SDRAM Controller Driver
+===============================
+
+Author
+======
+Aneesh V <aneesh@ti.com>
+
+Location
+========
+driver/memory/emif.c
+
+Supported SoCs:
+===============
+TI OMAP44xx
+TI OMAP54xx
+
+Menuconfig option:
+==================
+Device Drivers
+       Memory devices
+               Texas Instruments EMIF driver
+
+Description
+===========
+This driver is for the EMIF module available in Texas Instruments
+SoCs. EMIF is an SDRAM controller that, based on its revision,
+supports one or more of DDR2, DDR3, and LPDDR2 SDRAM protocols.
+This driver takes care of only LPDDR2 memories presently. The
+functions of the driver includes re-configuring AC timing
+parameters and other settings during frequency, voltage and
+temperature changes
+
+Platform Data (see include/linux/platform_data/emif_plat.h)
+===========================================================
+DDR device details and other board dependent and SoC dependent
+information can be passed through platform data (struct emif_platform_data)
+
+- DDR device details: 'struct ddr_device_info'
+- Device AC timings: 'struct lpddr2_timings' and 'struct lpddr2_min_tck'
+- Custom configurations: customizable policy options through
+  'struct emif_custom_configs'
+- IP revision
+- PHY type
+
+Interface to the external world
+===============================
+EMIF driver registers notifiers for voltage and frequency changes
+affecting EMIF and takes appropriate actions when these are invoked.
+
+- freq_pre_notify_handling()
+- freq_post_notify_handling()
+- volt_notify_handling()
+
+Debugfs
+=======
+The driver creates two debugfs entries per device.
+
+- regcache_dump : dump of register values calculated and saved for all
+  frequencies used so far.
+- mr4 : last polled value of MR4 register in the LPDDR2 device. MR4
+  indicates the current temperature level of the device.
diff --git a/Documentation/driver-api/memory-devices/ti-gpmc.rst b/Documentation/driver-api/memory-devices/ti-gpmc.rst
new file mode 100644 (file)
index 0000000..33efcb8
--- /dev/null
@@ -0,0 +1,179 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+========================================
+GPMC (General Purpose Memory Controller)
+========================================
+
+GPMC is an unified memory controller dedicated to interfacing external
+memory devices like
+
+ * Asynchronous SRAM like memories and application specific integrated
+   circuit devices.
+ * Asynchronous, synchronous, and page mode burst NOR flash devices
+   NAND flash
+ * Pseudo-SRAM devices
+
+GPMC is found on Texas Instruments SoC's (OMAP based)
+IP details: http://www.ti.com/lit/pdf/spruh73 section 7.1
+
+
+GPMC generic timing calculation:
+================================
+
+GPMC has certain timings that has to be programmed for proper
+functioning of the peripheral, while peripheral has another set of
+timings. To have peripheral work with gpmc, peripheral timings has to
+be translated to the form gpmc can understand. The way it has to be
+translated depends on the connected peripheral. Also there is a
+dependency for certain gpmc timings on gpmc clock frequency. Hence a
+generic timing routine was developed to achieve above requirements.
+
+Generic routine provides a generic method to calculate gpmc timings
+from gpmc peripheral timings. struct gpmc_device_timings fields has to
+be updated with timings from the datasheet of the peripheral that is
+connected to gpmc. A few of the peripheral timings can be fed either
+in time or in cycles, provision to handle this scenario has been
+provided (refer struct gpmc_device_timings definition). It may so
+happen that timing as specified by peripheral datasheet is not present
+in timing structure, in this scenario, try to correlate peripheral
+timing to the one available. If that doesn't work, try to add a new
+field as required by peripheral, educate generic timing routine to
+handle it, make sure that it does not break any of the existing.
+Then there may be cases where peripheral datasheet doesn't mention
+certain fields of struct gpmc_device_timings, zero those entries.
+
+Generic timing routine has been verified to work properly on
+multiple onenand's and tusb6010 peripherals.
+
+A word of caution: generic timing routine has been developed based
+on understanding of gpmc timings, peripheral timings, available
+custom timing routines, a kind of reverse engineering without
+most of the datasheets & hardware (to be exact none of those supported
+in mainline having custom timing routine) and by simulation.
+
+gpmc timing dependency on peripheral timings:
+
+[<gpmc_timing>: <peripheral timing1>, <peripheral timing2> ...]
+
+1. common
+
+cs_on:
+       t_ceasu
+adv_on:
+       t_avdasu, t_ceavd
+
+2. sync common
+
+sync_clk:
+       clk
+page_burst_access:
+       t_bacc
+clk_activation:
+       t_ces, t_avds
+
+3. read async muxed
+
+adv_rd_off:
+       t_avdp_r
+oe_on:
+       t_oeasu, t_aavdh
+access:
+       t_iaa, t_oe, t_ce, t_aa
+rd_cycle:
+       t_rd_cycle, t_cez_r, t_oez
+
+4. read async non-muxed
+
+adv_rd_off:
+       t_avdp_r
+oe_on:
+       t_oeasu
+access:
+       t_iaa, t_oe, t_ce, t_aa
+rd_cycle:
+       t_rd_cycle, t_cez_r, t_oez
+
+5. read sync muxed
+
+adv_rd_off:
+       t_avdp_r, t_avdh
+oe_on:
+       t_oeasu, t_ach, cyc_aavdh_oe
+access:
+       t_iaa, cyc_iaa, cyc_oe
+rd_cycle:
+       t_cez_r, t_oez, t_ce_rdyz
+
+6. read sync non-muxed
+
+adv_rd_off:
+       t_avdp_r
+oe_on:
+       t_oeasu
+access:
+       t_iaa, cyc_iaa, cyc_oe
+rd_cycle:
+       t_cez_r, t_oez, t_ce_rdyz
+
+7. write async muxed
+
+adv_wr_off:
+       t_avdp_w
+we_on, wr_data_mux_bus:
+       t_weasu, t_aavdh, cyc_aavhd_we
+we_off:
+       t_wpl
+cs_wr_off:
+       t_wph
+wr_cycle:
+       t_cez_w, t_wr_cycle
+
+8. write async non-muxed
+
+adv_wr_off:
+       t_avdp_w
+we_on, wr_data_mux_bus:
+       t_weasu
+we_off:
+       t_wpl
+cs_wr_off:
+       t_wph
+wr_cycle:
+       t_cez_w, t_wr_cycle
+
+9. write sync muxed
+
+adv_wr_off:
+       t_avdp_w, t_avdh
+we_on, wr_data_mux_bus:
+       t_weasu, t_rdyo, t_aavdh, cyc_aavhd_we
+we_off:
+       t_wpl, cyc_wpl
+cs_wr_off:
+       t_wph
+wr_cycle:
+       t_cez_w, t_ce_rdyz
+
+10. write sync non-muxed
+
+adv_wr_off:
+       t_avdp_w
+we_on, wr_data_mux_bus:
+       t_weasu, t_rdyo
+we_off:
+       t_wpl, cyc_wpl
+cs_wr_off:
+       t_wph
+wr_cycle:
+       t_cez_w, t_ce_rdyz
+
+
+Note:
+  Many of gpmc timings are dependent on other gpmc timings (a few
+  gpmc timings purely dependent on other gpmc timings, a reason that
+  some of the gpmc timings are missing above), and it will result in
+  indirect dependency of peripheral timings to gpmc timings other than
+  mentioned above, refer timing routine for more details. To know what
+  these peripheral timings correspond to, please see explanations in
+  struct gpmc_device_timings definition. And for gpmc timings refer
+  IP details (link above).
diff --git a/Documentation/driver-api/mmc/index.rst b/Documentation/driver-api/mmc/index.rst
new file mode 100644 (file)
index 0000000..7339736
--- /dev/null
@@ -0,0 +1,13 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+========================
+MMC/SD/SDIO card support
+========================
+
+.. toctree::
+   :maxdepth: 1
+
+   mmc-dev-attrs
+   mmc-dev-parts
+   mmc-async-req
+   mmc-tools
diff --git a/Documentation/driver-api/mmc/mmc-async-req.rst b/Documentation/driver-api/mmc/mmc-async-req.rst
new file mode 100644 (file)
index 0000000..0f7197c
--- /dev/null
@@ -0,0 +1,98 @@
+========================
+MMC Asynchronous Request
+========================
+
+Rationale
+=========
+
+How significant is the cache maintenance overhead?
+
+It depends. Fast eMMC and multiple cache levels with speculative cache
+pre-fetch makes the cache overhead relatively significant. If the DMA
+preparations for the next request are done in parallel with the current
+transfer, the DMA preparation overhead would not affect the MMC performance.
+
+The intention of non-blocking (asynchronous) MMC requests is to minimize the
+time between when an MMC request ends and another MMC request begins.
+
+Using mmc_wait_for_req(), the MMC controller is idle while dma_map_sg and
+dma_unmap_sg are processing. Using non-blocking MMC requests makes it
+possible to prepare the caches for next job in parallel with an active
+MMC request.
+
+MMC block driver
+================
+
+The mmc_blk_issue_rw_rq() in the MMC block driver is made non-blocking.
+
+The increase in throughput is proportional to the time it takes to
+prepare (major part of preparations are dma_map_sg() and dma_unmap_sg())
+a request and how fast the memory is. The faster the MMC/SD is the
+more significant the prepare request time becomes. Roughly the expected
+performance gain is 5% for large writes and 10% on large reads on a L2 cache
+platform. In power save mode, when clocks run on a lower frequency, the DMA
+preparation may cost even more. As long as these slower preparations are run
+in parallel with the transfer performance won't be affected.
+
+Details on measurements from IOZone and mmc_test
+================================================
+
+https://wiki.linaro.org/WorkingGroups/Kernel/Specs/StoragePerfMMC-async-req
+
+MMC core API extension
+======================
+
+There is one new public function mmc_start_req().
+
+It starts a new MMC command request for a host. The function isn't
+truly non-blocking. If there is an ongoing async request it waits
+for completion of that request and starts the new one and returns. It
+doesn't wait for the new request to complete. If there is no ongoing
+request it starts the new request and returns immediately.
+
+MMC host extensions
+===================
+
+There are two optional members in the mmc_host_ops -- pre_req() and
+post_req() -- that the host driver may implement in order to move work
+to before and after the actual mmc_host_ops.request() function is called.
+
+In the DMA case pre_req() may do dma_map_sg() and prepare the DMA
+descriptor, and post_req() runs the dma_unmap_sg().
+
+Optimize for the first request
+==============================
+
+The first request in a series of requests can't be prepared in parallel
+with the previous transfer, since there is no previous request.
+
+The argument is_first_req in pre_req() indicates that there is no previous
+request. The host driver may optimize for this scenario to minimize
+the performance loss. A way to optimize for this is to split the current
+request in two chunks, prepare the first chunk and start the request,
+and finally prepare the second chunk and start the transfer.
+
+Pseudocode to handle is_first_req scenario with minimal prepare overhead::
+
+  if (is_first_req && req->size > threshold)
+     /* start MMC transfer for the complete transfer size */
+     mmc_start_command(MMC_CMD_TRANSFER_FULL_SIZE);
+
+     /*
+      * Begin to prepare DMA while cmd is being processed by MMC.
+      * The first chunk of the request should take the same time
+      * to prepare as the "MMC process command time".
+      * If prepare time exceeds MMC cmd time
+      * the transfer is delayed, guesstimate max 4k as first chunk size.
+      */
+      prepare_1st_chunk_for_dma(req);
+      /* flush pending desc to the DMAC (dmaengine.h) */
+      dma_issue_pending(req->dma_desc);
+
+      prepare_2nd_chunk_for_dma(req);
+      /*
+       * The second issue_pending should be called before MMC runs out
+       * of the first chunk. If the MMC runs out of the first data chunk
+       * before this call, the transfer is delayed.
+       */
+      dma_issue_pending(req->dma_desc);
diff --git a/Documentation/driver-api/mmc/mmc-dev-attrs.rst b/Documentation/driver-api/mmc/mmc-dev-attrs.rst
new file mode 100644 (file)
index 0000000..4f44b1b
--- /dev/null
@@ -0,0 +1,91 @@
+==================================
+SD and MMC Block Device Attributes
+==================================
+
+These attributes are defined for the block devices associated with the
+SD or MMC device.
+
+The following attributes are read/write.
+
+       ========                ===============================================
+       force_ro                Enforce read-only access even if write protect                                  switch is off.
+       ========                ===============================================
+
+SD and MMC Device Attributes
+============================
+
+All attributes are read-only.
+
+       ======================  ===============================================
+       cid                     Card Identification Register
+       csd                     Card Specific Data Register
+       scr                     SD Card Configuration Register (SD only)
+       date                    Manufacturing Date (from CID Register)
+       fwrev                   Firmware/Product Revision (from CID Register)
+                               (SD and MMCv1 only)
+       hwrev                   Hardware/Product Revision (from CID Register)
+                               (SD and MMCv1 only)
+       manfid                  Manufacturer ID (from CID Register)
+       name                    Product Name (from CID Register)
+       oemid                   OEM/Application ID (from CID Register)
+       prv                     Product Revision (from CID Register)
+                               (SD and MMCv4 only)
+       serial                  Product Serial Number (from CID Register)
+       erase_size              Erase group size
+       preferred_erase_size    Preferred erase size
+       raw_rpmb_size_mult      RPMB partition size
+       rel_sectors             Reliable write sector count
+       ocr                     Operation Conditions Register
+       dsr                     Driver Stage Register
+       cmdq_en                 Command Queue enabled:
+
+                                       1 => enabled, 0 => not enabled
+       ======================  ===============================================
+
+Note on Erase Size and Preferred Erase Size:
+
+       "erase_size" is the  minimum size, in bytes, of an erase
+       operation.  For MMC, "erase_size" is the erase group size
+       reported by the card.  Note that "erase_size" does not apply
+       to trim or secure trim operations where the minimum size is
+       always one 512 byte sector.  For SD, "erase_size" is 512
+       if the card is block-addressed, 0 otherwise.
+
+       SD/MMC cards can erase an arbitrarily large area up to and
+       including the whole card.  When erasing a large area it may
+       be desirable to do it in smaller chunks for three reasons:
+
+            1. A single erase command will make all other I/O on
+               the card wait.  This is not a problem if the whole card
+               is being erased, but erasing one partition will make
+               I/O for another partition on the same card wait for the
+               duration of the erase - which could be a several
+               minutes.
+            2. To be able to inform the user of erase progress.
+            3. The erase timeout becomes too large to be very
+               useful.  Because the erase timeout contains a margin
+               which is multiplied by the size of the erase area,
+               the value can end up being several minutes for large
+               areas.
+
+       "erase_size" is not the most efficient unit to erase
+       (especially for SD where it is just one sector),
+       hence "preferred_erase_size" provides a good chunk
+       size for erasing large areas.
+
+       For MMC, "preferred_erase_size" is the high-capacity
+       erase size if a card specifies one, otherwise it is
+       based on the capacity of the card.
+
+       For SD, "preferred_erase_size" is the allocation unit
+       size specified by the card.
+
+       "preferred_erase_size" is in bytes.
+
+Note on raw_rpmb_size_mult:
+
+       "raw_rpmb_size_mult" is a multiple of 128kB block.
+
+       RPMB size in byte is calculated by using the following equation:
+
+               RPMB partition size = 128kB x raw_rpmb_size_mult
diff --git a/Documentation/driver-api/mmc/mmc-dev-parts.rst b/Documentation/driver-api/mmc/mmc-dev-parts.rst
new file mode 100644 (file)
index 0000000..995922f
--- /dev/null
@@ -0,0 +1,41 @@
+============================
+SD and MMC Device Partitions
+============================
+
+Device partitions are additional logical block devices present on the
+SD/MMC device.
+
+As of this writing, MMC boot partitions as supported and exposed as
+/dev/mmcblkXboot0 and /dev/mmcblkXboot1, where X is the index of the
+parent /dev/mmcblkX.
+
+MMC Boot Partitions
+===================
+
+Read and write access is provided to the two MMC boot partitions. Due to
+the sensitive nature of the boot partition contents, which often store
+a bootloader or bootloader configuration tables crucial to booting the
+platform, write access is disabled by default to reduce the chance of
+accidental bricking.
+
+To enable write access to /dev/mmcblkXbootY, disable the forced read-only
+access with::
+
+       echo 0 > /sys/block/mmcblkXbootY/force_ro
+
+To re-enable read-only access::
+
+       echo 1 > /sys/block/mmcblkXbootY/force_ro
+
+The boot partitions can also be locked read only until the next power on,
+with::
+
+       echo 1 > /sys/block/mmcblkXbootY/ro_lock_until_next_power_on
+
+This is a feature of the card and not of the kernel. If the card does
+not support boot partition locking, the file will not exist. If the
+feature has been disabled on the card, the file will be read-only.
+
+The boot partitions can also be locked permanently, but this feature is
+not accessible through sysfs in order to avoid accidental or malicious
+bricking.
diff --git a/Documentation/driver-api/mmc/mmc-tools.rst b/Documentation/driver-api/mmc/mmc-tools.rst
new file mode 100644 (file)
index 0000000..5440609
--- /dev/null
@@ -0,0 +1,37 @@
+======================
+MMC tools introduction
+======================
+
+There is one MMC test tools called mmc-utils, which is maintained by Chris Ball,
+you can find it at the below public git repository:
+
+       http://git.kernel.org/cgit/linux/kernel/git/cjb/mmc-utils.git/
+
+Functions
+=========
+
+The mmc-utils tools can do the following:
+
+ - Print and parse extcsd data.
+ - Determine the eMMC writeprotect status.
+ - Set the eMMC writeprotect status.
+ - Set the eMMC data sector size to 4KB by disabling emulation.
+ - Create general purpose partition.
+ - Enable the enhanced user area.
+ - Enable write reliability per partition.
+ - Print the response to STATUS_SEND (CMD13).
+ - Enable the boot partition.
+ - Set Boot Bus Conditions.
+ - Enable the eMMC BKOPS feature.
+ - Permanently enable the eMMC H/W Reset feature.
+ - Permanently disable the eMMC H/W Reset feature.
+ - Send Sanitize command.
+ - Program authentication key for the device.
+ - Counter value for the rpmb device will be read to stdout.
+ - Read from rpmb device to output.
+ - Write to rpmb device from data file.
+ - Enable the eMMC cache feature.
+ - Disable the eMMC cache feature.
+ - Print and parse CID data.
+ - Print and parse CSD data.
+ - Print and parse SCR data.
diff --git a/Documentation/driver-api/mtd/index.rst b/Documentation/driver-api/mtd/index.rst
new file mode 100644 (file)
index 0000000..436ba5a
--- /dev/null
@@ -0,0 +1,12 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==============================
+Memory Technology Device (MTD)
+==============================
+
+.. toctree::
+   :maxdepth: 1
+
+   intel-spi
+   nand_ecc
+   spi-nor
diff --git a/Documentation/driver-api/mtd/intel-spi.rst b/Documentation/driver-api/mtd/intel-spi.rst
new file mode 100644 (file)
index 0000000..0e6d9cd
--- /dev/null
@@ -0,0 +1,90 @@
+==============================
+Upgrading BIOS using intel-spi
+==============================
+
+Many Intel CPUs like Baytrail and Braswell include SPI serial flash host
+controller which is used to hold BIOS and other platform specific data.
+Since contents of the SPI serial flash is crucial for machine to function,
+it is typically protected by different hardware protection mechanisms to
+avoid accidental (or on purpose) overwrite of the content.
+
+Not all manufacturers protect the SPI serial flash, mainly because it
+allows upgrading the BIOS image directly from an OS.
+
+The intel-spi driver makes it possible to read and write the SPI serial
+flash, if certain protection bits are not set and locked. If it finds
+any of them set, the whole MTD device is made read-only to prevent
+partial overwrites. By default the driver exposes SPI serial flash
+contents as read-only but it can be changed from kernel command line,
+passing "intel-spi.writeable=1".
+
+Please keep in mind that overwriting the BIOS image on SPI serial flash
+might render the machine unbootable and requires special equipment like
+Dediprog to revive. You have been warned!
+
+Below are the steps how to upgrade MinnowBoard MAX BIOS directly from
+Linux.
+
+ 1) Download and extract the latest Minnowboard MAX BIOS SPI image
+    [1]. At the time writing this the latest image is v92.
+
+ 2) Install mtd-utils package [2]. We need this in order to erase the SPI
+    serial flash. Distros like Debian and Fedora have this prepackaged with
+    name "mtd-utils".
+
+ 3) Add "intel-spi.writeable=1" to the kernel command line and reboot
+    the board (you can also reload the driver passing "writeable=1" as
+    module parameter to modprobe).
+
+ 4) Once the board is up and running again, find the right MTD partition
+    (it is named as "BIOS")::
+
+       # cat /proc/mtd
+       dev:    size   erasesize  name
+       mtd0: 00800000 00001000 "BIOS"
+
+    So here it will be /dev/mtd0 but it may vary.
+
+ 5) Make backup of the existing image first::
+
+       # dd if=/dev/mtd0ro of=bios.bak
+       16384+0 records in
+       16384+0 records out
+       8388608 bytes (8.4 MB) copied, 10.0269 s, 837 kB/s
+
+ 6) Verify the backup:
+
+       # sha1sum /dev/mtd0ro bios.bak
+       fdbb011920572ca6c991377c4b418a0502668b73  /dev/mtd0ro
+       fdbb011920572ca6c991377c4b418a0502668b73  bios.bak
+
+    The SHA1 sums must match. Otherwise do not continue any further!
+
+ 7) Erase the SPI serial flash. After this step, do not reboot the
+    board! Otherwise it will not start anymore::
+
+       # flash_erase /dev/mtd0 0 0
+       Erasing 4 Kibyte @ 7ff000 -- 100 % complete
+
+ 8) Once completed without errors you can write the new BIOS image:
+
+    # dd if=MNW2MAX1.X64.0092.R01.1605221712.bin of=/dev/mtd0
+
+ 9) Verify that the new content of the SPI serial flash matches the new
+    BIOS image::
+
+       # sha1sum /dev/mtd0ro MNW2MAX1.X64.0092.R01.1605221712.bin
+       9b4df9e4be2057fceec3a5529ec3d950836c87a2  /dev/mtd0ro
+       9b4df9e4be2057fceec3a5529ec3d950836c87a2 MNW2MAX1.X64.0092.R01.1605221712.bin
+
+    The SHA1 sums should match.
+
+ 10) Now you can reboot your board and observe the new BIOS starting up
+     properly.
+
+References
+----------
+
+[1] https://firmware.intel.com/sites/default/files/MinnowBoard%2EMAX_%2EX64%2E92%2ER01%2Ezip
+
+[2] http://www.linux-mtd.infradead.org/
diff --git a/Documentation/driver-api/mtd/nand_ecc.rst b/Documentation/driver-api/mtd/nand_ecc.rst
new file mode 100644 (file)
index 0000000..e8d3c53
--- /dev/null
@@ -0,0 +1,763 @@
+==========================
+NAND Error-correction Code
+==========================
+
+Introduction
+============
+
+Having looked at the linux mtd/nand driver and more specific at nand_ecc.c
+I felt there was room for optimisation. I bashed the code for a few hours
+performing tricks like table lookup removing superfluous code etc.
+After that the speed was increased by 35-40%.
+Still I was not too happy as I felt there was additional room for improvement.
+
+Bad! I was hooked.
+I decided to annotate my steps in this file. Perhaps it is useful to someone
+or someone learns something from it.
+
+
+The problem
+===========
+
+NAND flash (at least SLC one) typically has sectors of 256 bytes.
+However NAND flash is not extremely reliable so some error detection
+(and sometimes correction) is needed.
+
+This is done by means of a Hamming code. I'll try to explain it in
+laymans terms (and apologies to all the pro's in the field in case I do
+not use the right terminology, my coding theory class was almost 30
+years ago, and I must admit it was not one of my favourites).
+
+As I said before the ecc calculation is performed on sectors of 256
+bytes. This is done by calculating several parity bits over the rows and
+columns. The parity used is even parity which means that the parity bit = 1
+if the data over which the parity is calculated is 1 and the parity bit = 0
+if the data over which the parity is calculated is 0. So the total
+number of bits over the data over which the parity is calculated + the
+parity bit is even. (see wikipedia if you can't follow this).
+Parity is often calculated by means of an exclusive or operation,
+sometimes also referred to as xor. In C the operator for xor is ^
+
+Back to ecc.
+Let's give a small figure:
+
+=========  ==== ==== ==== ==== ==== ==== ==== ====   === === === === ====
+byte   0:  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0   rp0 rp2 rp4 ... rp14
+byte   1:  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0   rp1 rp2 rp4 ... rp14
+byte   2:  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0   rp0 rp3 rp4 ... rp14
+byte   3:  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0   rp1 rp3 rp4 ... rp14
+byte   4:  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0   rp0 rp2 rp5 ... rp14
+...
+byte 254:  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0   rp0 rp3 rp5 ... rp15
+byte 255:  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0   rp1 rp3 rp5 ... rp15
+           cp1  cp0  cp1  cp0  cp1  cp0  cp1  cp0
+           cp3  cp3  cp2  cp2  cp3  cp3  cp2  cp2
+           cp5  cp5  cp5  cp5  cp4  cp4  cp4  cp4
+=========  ==== ==== ==== ==== ==== ==== ==== ====   === === === === ====
+
+This figure represents a sector of 256 bytes.
+cp is my abbreviation for column parity, rp for row parity.
+
+Let's start to explain column parity.
+
+- cp0 is the parity that belongs to all bit0, bit2, bit4, bit6.
+
+  so the sum of all bit0, bit2, bit4 and bit6 values + cp0 itself is even.
+
+Similarly cp1 is the sum of all bit1, bit3, bit5 and bit7.
+
+- cp2 is the parity over bit0, bit1, bit4 and bit5
+- cp3 is the parity over bit2, bit3, bit6 and bit7.
+- cp4 is the parity over bit0, bit1, bit2 and bit3.
+- cp5 is the parity over bit4, bit5, bit6 and bit7.
+
+Note that each of cp0 .. cp5 is exactly one bit.
+
+Row parity actually works almost the same.
+
+- rp0 is the parity of all even bytes (0, 2, 4, 6, ... 252, 254)
+- rp1 is the parity of all odd bytes (1, 3, 5, 7, ..., 253, 255)
+- rp2 is the parity of all bytes 0, 1, 4, 5, 8, 9, ...
+  (so handle two bytes, then skip 2 bytes).
+- rp3 is covers the half rp2 does not cover (bytes 2, 3, 6, 7, 10, 11, ...)
+- for rp4 the rule is cover 4 bytes, skip 4 bytes, cover 4 bytes, skip 4 etc.
+
+  so rp4 calculates parity over bytes 0, 1, 2, 3, 8, 9, 10, 11, 16, ...)
+- and rp5 covers the other half, so bytes 4, 5, 6, 7, 12, 13, 14, 15, 20, ..
+
+The story now becomes quite boring. I guess you get the idea.
+
+- rp6 covers 8 bytes then skips 8 etc
+- rp7 skips 8 bytes then covers 8 etc
+- rp8 covers 16 bytes then skips 16 etc
+- rp9 skips 16 bytes then covers 16 etc
+- rp10 covers 32 bytes then skips 32 etc
+- rp11 skips 32 bytes then covers 32 etc
+- rp12 covers 64 bytes then skips 64 etc
+- rp13 skips 64 bytes then covers 64 etc
+- rp14 covers 128 bytes then skips 128
+- rp15 skips 128 bytes then covers 128
+
+In the end the parity bits are grouped together in three bytes as
+follows:
+
+=====  ===== ===== ===== ===== ===== ===== ===== =====
+ECC    Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
+=====  ===== ===== ===== ===== ===== ===== ===== =====
+ECC 0   rp07  rp06  rp05  rp04  rp03  rp02  rp01  rp00
+ECC 1   rp15  rp14  rp13  rp12  rp11  rp10  rp09  rp08
+ECC 2   cp5   cp4   cp3   cp2   cp1   cp0      1     1
+=====  ===== ===== ===== ===== ===== ===== ===== =====
+
+I detected after writing this that ST application note AN1823
+(http://www.st.com/stonline/) gives a much
+nicer picture.(but they use line parity as term where I use row parity)
+Oh well, I'm graphically challenged, so suffer with me for a moment :-)
+
+And I could not reuse the ST picture anyway for copyright reasons.
+
+
+Attempt 0
+=========
+
+Implementing the parity calculation is pretty simple.
+In C pseudocode::
+
+  for (i = 0; i < 256; i++)
+  {
+    if (i & 0x01)
+       rp1 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp1;
+    else
+       rp0 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp0;
+    if (i & 0x02)
+       rp3 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp3;
+    else
+       rp2 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp2;
+    if (i & 0x04)
+      rp5 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp5;
+    else
+      rp4 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp4;
+    if (i & 0x08)
+      rp7 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp7;
+    else
+      rp6 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp6;
+    if (i & 0x10)
+      rp9 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp9;
+    else
+      rp8 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp8;
+    if (i & 0x20)
+      rp11 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp11;
+    else
+      rp10 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp10;
+    if (i & 0x40)
+      rp13 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp13;
+    else
+      rp12 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp12;
+    if (i & 0x80)
+      rp15 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp15;
+    else
+      rp14 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp14;
+    cp0 = bit6 ^ bit4 ^ bit2 ^ bit0 ^ cp0;
+    cp1 = bit7 ^ bit5 ^ bit3 ^ bit1 ^ cp1;
+    cp2 = bit5 ^ bit4 ^ bit1 ^ bit0 ^ cp2;
+    cp3 = bit7 ^ bit6 ^ bit3 ^ bit2 ^ cp3
+    cp4 = bit3 ^ bit2 ^ bit1 ^ bit0 ^ cp4
+    cp5 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ cp5
+  }
+
+
+Analysis 0
+==========
+
+C does have bitwise operators but not really operators to do the above
+efficiently (and most hardware has no such instructions either).
+Therefore without implementing this it was clear that the code above was
+not going to bring me a Nobel prize :-)
+
+Fortunately the exclusive or operation is commutative, so we can combine
+the values in any order. So instead of calculating all the bits
+individually, let us try to rearrange things.
+For the column parity this is easy. We can just xor the bytes and in the
+end filter out the relevant bits. This is pretty nice as it will bring
+all cp calculation out of the for loop.
+
+Similarly we can first xor the bytes for the various rows.
+This leads to:
+
+
+Attempt 1
+=========
+
+::
+
+  const char parity[256] = {
+      0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+      1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+      1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+      0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+      1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+      0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+      0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+      1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+      1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+      0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+      0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+      1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+      0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+      1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+      1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+      0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0
+  };
+
+  void ecc1(const unsigned char *buf, unsigned char *code)
+  {
+      int i;
+      const unsigned char *bp = buf;
+      unsigned char cur;
+      unsigned char rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7;
+      unsigned char rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15;
+      unsigned char par;
+
+      par = 0;
+      rp0 = 0; rp1 = 0; rp2 = 0; rp3 = 0;
+      rp4 = 0; rp5 = 0; rp6 = 0; rp7 = 0;
+      rp8 = 0; rp9 = 0; rp10 = 0; rp11 = 0;
+      rp12 = 0; rp13 = 0; rp14 = 0; rp15 = 0;
+
+      for (i = 0; i < 256; i++)
+      {
+          cur = *bp++;
+          par ^= cur;
+          if (i & 0x01) rp1 ^= cur; else rp0 ^= cur;
+          if (i & 0x02) rp3 ^= cur; else rp2 ^= cur;
+          if (i & 0x04) rp5 ^= cur; else rp4 ^= cur;
+          if (i & 0x08) rp7 ^= cur; else rp6 ^= cur;
+          if (i & 0x10) rp9 ^= cur; else rp8 ^= cur;
+          if (i & 0x20) rp11 ^= cur; else rp10 ^= cur;
+          if (i & 0x40) rp13 ^= cur; else rp12 ^= cur;
+          if (i & 0x80) rp15 ^= cur; else rp14 ^= cur;
+      }
+      code[0] =
+          (parity[rp7] << 7) |
+          (parity[rp6] << 6) |
+          (parity[rp5] << 5) |
+          (parity[rp4] << 4) |
+          (parity[rp3] << 3) |
+          (parity[rp2] << 2) |
+          (parity[rp1] << 1) |
+          (parity[rp0]);
+      code[1] =
+          (parity[rp15] << 7) |
+          (parity[rp14] << 6) |
+          (parity[rp13] << 5) |
+          (parity[rp12] << 4) |
+          (parity[rp11] << 3) |
+          (parity[rp10] << 2) |
+          (parity[rp9]  << 1) |
+          (parity[rp8]);
+      code[2] =
+          (parity[par & 0xf0] << 7) |
+          (parity[par & 0x0f] << 6) |
+          (parity[par & 0xcc] << 5) |
+          (parity[par & 0x33] << 4) |
+          (parity[par & 0xaa] << 3) |
+          (parity[par & 0x55] << 2);
+      code[0] = ~code[0];
+      code[1] = ~code[1];
+      code[2] = ~code[2];
+  }
+
+Still pretty straightforward. The last three invert statements are there to
+give a checksum of 0xff 0xff 0xff for an empty flash. In an empty flash
+all data is 0xff, so the checksum then matches.
+
+I also introduced the parity lookup. I expected this to be the fastest
+way to calculate the parity, but I will investigate alternatives later
+on.
+
+
+Analysis 1
+==========
+
+The code works, but is not terribly efficient. On my system it took
+almost 4 times as much time as the linux driver code. But hey, if it was
+*that* easy this would have been done long before.
+No pain. no gain.
+
+Fortunately there is plenty of room for improvement.
+
+In step 1 we moved from bit-wise calculation to byte-wise calculation.
+However in C we can also use the unsigned long data type and virtually
+every modern microprocessor supports 32 bit operations, so why not try
+to write our code in such a way that we process data in 32 bit chunks.
+
+Of course this means some modification as the row parity is byte by
+byte. A quick analysis:
+for the column parity we use the par variable. When extending to 32 bits
+we can in the end easily calculate rp0 and rp1 from it.
+(because par now consists of 4 bytes, contributing to rp1, rp0, rp1, rp0
+respectively, from MSB to LSB)
+also rp2 and rp3 can be easily retrieved from par as rp3 covers the
+first two MSBs and rp2 covers the last two LSBs.
+
+Note that of course now the loop is executed only 64 times (256/4).
+And note that care must taken wrt byte ordering. The way bytes are
+ordered in a long is machine dependent, and might affect us.
+Anyway, if there is an issue: this code is developed on x86 (to be
+precise: a DELL PC with a D920 Intel CPU)
+
+And of course the performance might depend on alignment, but I expect
+that the I/O buffers in the nand driver are aligned properly (and
+otherwise that should be fixed to get maximum performance).
+
+Let's give it a try...
+
+
+Attempt 2
+=========
+
+::
+
+  extern const char parity[256];
+
+  void ecc2(const unsigned char *buf, unsigned char *code)
+  {
+      int i;
+      const unsigned long *bp = (unsigned long *)buf;
+      unsigned long cur;
+      unsigned long rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7;
+      unsigned long rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15;
+      unsigned long par;
+
+      par = 0;
+      rp0 = 0; rp1 = 0; rp2 = 0; rp3 = 0;
+      rp4 = 0; rp5 = 0; rp6 = 0; rp7 = 0;
+      rp8 = 0; rp9 = 0; rp10 = 0; rp11 = 0;
+      rp12 = 0; rp13 = 0; rp14 = 0; rp15 = 0;
+
+      for (i = 0; i < 64; i++)
+      {
+          cur = *bp++;
+          par ^= cur;
+          if (i & 0x01) rp5 ^= cur; else rp4 ^= cur;
+          if (i & 0x02) rp7 ^= cur; else rp6 ^= cur;
+          if (i & 0x04) rp9 ^= cur; else rp8 ^= cur;
+          if (i & 0x08) rp11 ^= cur; else rp10 ^= cur;
+          if (i & 0x10) rp13 ^= cur; else rp12 ^= cur;
+          if (i & 0x20) rp15 ^= cur; else rp14 ^= cur;
+      }
+      /*
+         we need to adapt the code generation for the fact that rp vars are now
+         long; also the column parity calculation needs to be changed.
+         we'll bring rp4 to 15 back to single byte entities by shifting and
+         xoring
+      */
+      rp4 ^= (rp4 >> 16); rp4 ^= (rp4 >> 8); rp4 &= 0xff;
+      rp5 ^= (rp5 >> 16); rp5 ^= (rp5 >> 8); rp5 &= 0xff;
+      rp6 ^= (rp6 >> 16); rp6 ^= (rp6 >> 8); rp6 &= 0xff;
+      rp7 ^= (rp7 >> 16); rp7 ^= (rp7 >> 8); rp7 &= 0xff;
+      rp8 ^= (rp8 >> 16); rp8 ^= (rp8 >> 8); rp8 &= 0xff;
+      rp9 ^= (rp9 >> 16); rp9 ^= (rp9 >> 8); rp9 &= 0xff;
+      rp10 ^= (rp10 >> 16); rp10 ^= (rp10 >> 8); rp10 &= 0xff;
+      rp11 ^= (rp11 >> 16); rp11 ^= (rp11 >> 8); rp11 &= 0xff;
+      rp12 ^= (rp12 >> 16); rp12 ^= (rp12 >> 8); rp12 &= 0xff;
+      rp13 ^= (rp13 >> 16); rp13 ^= (rp13 >> 8); rp13 &= 0xff;
+      rp14 ^= (rp14 >> 16); rp14 ^= (rp14 >> 8); rp14 &= 0xff;
+      rp15 ^= (rp15 >> 16); rp15 ^= (rp15 >> 8); rp15 &= 0xff;
+      rp3 = (par >> 16); rp3 ^= (rp3 >> 8); rp3 &= 0xff;
+      rp2 = par & 0xffff; rp2 ^= (rp2 >> 8); rp2 &= 0xff;
+      par ^= (par >> 16);
+      rp1 = (par >> 8); rp1 &= 0xff;
+      rp0 = (par & 0xff);
+      par ^= (par >> 8); par &= 0xff;
+
+      code[0] =
+          (parity[rp7] << 7) |
+          (parity[rp6] << 6) |
+          (parity[rp5] << 5) |
+          (parity[rp4] << 4) |
+          (parity[rp3] << 3) |
+          (parity[rp2] << 2) |
+          (parity[rp1] << 1) |
+          (parity[rp0]);
+      code[1] =
+          (parity[rp15] << 7) |
+          (parity[rp14] << 6) |
+          (parity[rp13] << 5) |
+          (parity[rp12] << 4) |
+          (parity[rp11] << 3) |
+          (parity[rp10] << 2) |
+          (parity[rp9]  << 1) |
+          (parity[rp8]);
+      code[2] =
+          (parity[par & 0xf0] << 7) |
+          (parity[par & 0x0f] << 6) |
+          (parity[par & 0xcc] << 5) |
+          (parity[par & 0x33] << 4) |
+          (parity[par & 0xaa] << 3) |
+          (parity[par & 0x55] << 2);
+      code[0] = ~code[0];
+      code[1] = ~code[1];
+      code[2] = ~code[2];
+  }
+
+The parity array is not shown any more. Note also that for these
+examples I kinda deviated from my regular programming style by allowing
+multiple statements on a line, not using { } in then and else blocks
+with only a single statement and by using operators like ^=
+
+
+Analysis 2
+==========
+
+The code (of course) works, and hurray: we are a little bit faster than
+the linux driver code (about 15%). But wait, don't cheer too quickly.
+There is more to be gained.
+If we look at e.g. rp14 and rp15 we see that we either xor our data with
+rp14 or with rp15. However we also have par which goes over all data.
+This means there is no need to calculate rp14 as it can be calculated from
+rp15 through rp14 = par ^ rp15, because par = rp14 ^ rp15;
+(or if desired we can avoid calculating rp15 and calculate it from
+rp14).  That is why some places refer to inverse parity.
+Of course the same thing holds for rp4/5, rp6/7, rp8/9, rp10/11 and rp12/13.
+Effectively this means we can eliminate the else clause from the if
+statements. Also we can optimise the calculation in the end a little bit
+by going from long to byte first. Actually we can even avoid the table
+lookups
+
+Attempt 3
+=========
+
+Odd replaced::
+
+          if (i & 0x01) rp5 ^= cur; else rp4 ^= cur;
+          if (i & 0x02) rp7 ^= cur; else rp6 ^= cur;
+          if (i & 0x04) rp9 ^= cur; else rp8 ^= cur;
+          if (i & 0x08) rp11 ^= cur; else rp10 ^= cur;
+          if (i & 0x10) rp13 ^= cur; else rp12 ^= cur;
+          if (i & 0x20) rp15 ^= cur; else rp14 ^= cur;
+
+with::
+
+          if (i & 0x01) rp5 ^= cur;
+          if (i & 0x02) rp7 ^= cur;
+          if (i & 0x04) rp9 ^= cur;
+          if (i & 0x08) rp11 ^= cur;
+          if (i & 0x10) rp13 ^= cur;
+          if (i & 0x20) rp15 ^= cur;
+
+and outside the loop added::
+
+          rp4  = par ^ rp5;
+          rp6  = par ^ rp7;
+          rp8  = par ^ rp9;
+          rp10  = par ^ rp11;
+          rp12  = par ^ rp13;
+          rp14  = par ^ rp15;
+
+And after that the code takes about 30% more time, although the number of
+statements is reduced. This is also reflected in the assembly code.
+
+
+Analysis 3
+==========
+
+Very weird. Guess it has to do with caching or instruction parallellism
+or so. I also tried on an eeePC (Celeron, clocked at 900 Mhz). Interesting
+observation was that this one is only 30% slower (according to time)
+executing the code as my 3Ghz D920 processor.
+
+Well, it was expected not to be easy so maybe instead move to a
+different track: let's move back to the code from attempt2 and do some
+loop unrolling. This will eliminate a few if statements. I'll try
+different amounts of unrolling to see what works best.
+
+
+Attempt 4
+=========
+
+Unrolled the loop 1, 2, 3 and 4 times.
+For 4 the code starts with::
+
+    for (i = 0; i < 4; i++)
+    {
+        cur = *bp++;
+        par ^= cur;
+        rp4 ^= cur;
+        rp6 ^= cur;
+        rp8 ^= cur;
+        rp10 ^= cur;
+        if (i & 0x1) rp13 ^= cur; else rp12 ^= cur;
+        if (i & 0x2) rp15 ^= cur; else rp14 ^= cur;
+        cur = *bp++;
+        par ^= cur;
+        rp5 ^= cur;
+        rp6 ^= cur;
+        ...
+
+
+Analysis 4
+==========
+
+Unrolling once gains about 15%
+
+Unrolling twice keeps the gain at about 15%
+
+Unrolling three times gives a gain of 30% compared to attempt 2.
+
+Unrolling four times gives a marginal improvement compared to unrolling
+three times.
+
+I decided to proceed with a four time unrolled loop anyway. It was my gut
+feeling that in the next steps I would obtain additional gain from it.
+
+The next step was triggered by the fact that par contains the xor of all
+bytes and rp4 and rp5 each contain the xor of half of the bytes.
+So in effect par = rp4 ^ rp5. But as xor is commutative we can also say
+that rp5 = par ^ rp4. So no need to keep both rp4 and rp5 around. We can
+eliminate rp5 (or rp4, but I already foresaw another optimisation).
+The same holds for rp6/7, rp8/9, rp10/11 rp12/13 and rp14/15.
+
+
+Attempt 5
+=========
+
+Effectively so all odd digit rp assignments in the loop were removed.
+This included the else clause of the if statements.
+Of course after the loop we need to correct things by adding code like::
+
+    rp5 = par ^ rp4;
+
+Also the initial assignments (rp5 = 0; etc) could be removed.
+Along the line I also removed the initialisation of rp0/1/2/3.
+
+
+Analysis 5
+==========
+
+Measurements showed this was a good move. The run-time roughly halved
+compared with attempt 4 with 4 times unrolled, and we only require 1/3rd
+of the processor time compared to the current code in the linux kernel.
+
+However, still I thought there was more. I didn't like all the if
+statements. Why not keep a running parity and only keep the last if
+statement. Time for yet another version!
+
+
+Attempt 6
+=========
+
+THe code within the for loop was changed to::
+
+    for (i = 0; i < 4; i++)
+    {
+        cur = *bp++; tmppar  = cur; rp4 ^= cur;
+        cur = *bp++; tmppar ^= cur; rp6 ^= tmppar;
+        cur = *bp++; tmppar ^= cur; rp4 ^= cur;
+        cur = *bp++; tmppar ^= cur; rp8 ^= tmppar;
+
+        cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp6 ^= cur;
+        cur = *bp++; tmppar ^= cur; rp6 ^= cur;
+        cur = *bp++; tmppar ^= cur; rp4 ^= cur;
+        cur = *bp++; tmppar ^= cur; rp10 ^= tmppar;
+
+        cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp6 ^= cur; rp8 ^= cur;
+        cur = *bp++; tmppar ^= cur; rp6 ^= cur; rp8 ^= cur;
+        cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp8 ^= cur;
+        cur = *bp++; tmppar ^= cur; rp8 ^= cur;
+
+        cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp6 ^= cur;
+        cur = *bp++; tmppar ^= cur; rp6 ^= cur;
+        cur = *bp++; tmppar ^= cur; rp4 ^= cur;
+        cur = *bp++; tmppar ^= cur;
+
+        par ^= tmppar;
+        if ((i & 0x1) == 0) rp12 ^= tmppar;
+        if ((i & 0x2) == 0) rp14 ^= tmppar;
+    }
+
+As you can see tmppar is used to accumulate the parity within a for
+iteration. In the last 3 statements is added to par and, if needed,
+to rp12 and rp14.
+
+While making the changes I also found that I could exploit that tmppar
+contains the running parity for this iteration. So instead of having:
+rp4 ^= cur; rp6 ^= cur;
+I removed the rp6 ^= cur; statement and did rp6 ^= tmppar; on next
+statement. A similar change was done for rp8 and rp10
+
+
+Analysis 6
+==========
+
+Measuring this code again showed big gain. When executing the original
+linux code 1 million times, this took about 1 second on my system.
+(using time to measure the performance). After this iteration I was back
+to 0.075 sec. Actually I had to decide to start measuring over 10
+million iterations in order not to lose too much accuracy. This one
+definitely seemed to be the jackpot!
+
+There is a little bit more room for improvement though. There are three
+places with statements::
+
+       rp4 ^= cur; rp6 ^= cur;
+
+It seems more efficient to also maintain a variable rp4_6 in the while
+loop; This eliminates 3 statements per loop. Of course after the loop we
+need to correct by adding::
+
+       rp4 ^= rp4_6;
+       rp6 ^= rp4_6
+
+Furthermore there are 4 sequential assignments to rp8. This can be
+encoded slightly more efficiently by saving tmppar before those 4 lines
+and later do rp8 = rp8 ^ tmppar ^ notrp8;
+(where notrp8 is the value of rp8 before those 4 lines).
+Again a use of the commutative property of xor.
+Time for a new test!
+
+
+Attempt 7
+=========
+
+The new code now looks like::
+
+    for (i = 0; i < 4; i++)
+    {
+        cur = *bp++; tmppar  = cur; rp4 ^= cur;
+        cur = *bp++; tmppar ^= cur; rp6 ^= tmppar;
+        cur = *bp++; tmppar ^= cur; rp4 ^= cur;
+        cur = *bp++; tmppar ^= cur; rp8 ^= tmppar;
+
+        cur = *bp++; tmppar ^= cur; rp4_6 ^= cur;
+        cur = *bp++; tmppar ^= cur; rp6 ^= cur;
+        cur = *bp++; tmppar ^= cur; rp4 ^= cur;
+        cur = *bp++; tmppar ^= cur; rp10 ^= tmppar;
+
+        notrp8 = tmppar;
+        cur = *bp++; tmppar ^= cur; rp4_6 ^= cur;
+        cur = *bp++; tmppar ^= cur; rp6 ^= cur;
+        cur = *bp++; tmppar ^= cur; rp4 ^= cur;
+        cur = *bp++; tmppar ^= cur;
+        rp8 = rp8 ^ tmppar ^ notrp8;
+
+        cur = *bp++; tmppar ^= cur; rp4_6 ^= cur;
+        cur = *bp++; tmppar ^= cur; rp6 ^= cur;
+        cur = *bp++; tmppar ^= cur; rp4 ^= cur;
+        cur = *bp++; tmppar ^= cur;
+
+        par ^= tmppar;
+        if ((i & 0x1) == 0) rp12 ^= tmppar;
+        if ((i & 0x2) == 0) rp14 ^= tmppar;
+    }
+    rp4 ^= rp4_6;
+    rp6 ^= rp4_6;
+
+
+Not a big change, but every penny counts :-)
+
+
+Analysis 7
+==========
+
+Actually this made things worse. Not very much, but I don't want to move
+into the wrong direction. Maybe something to investigate later. Could
+have to do with caching again.
+
+Guess that is what there is to win within the loop. Maybe unrolling one
+more time will help. I'll keep the optimisations from 7 for now.
+
+
+Attempt 8
+=========
+
+Unrolled the loop one more time.
+
+
+Analysis 8
+==========
+
+This makes things worse. Let's stick with attempt 6 and continue from there.
+Although it seems that the code within the loop cannot be optimised
+further there is still room to optimize the generation of the ecc codes.
+We can simply calculate the total parity. If this is 0 then rp4 = rp5
+etc. If the parity is 1, then rp4 = !rp5;
+
+But if rp4 = rp5 we do not need rp5 etc. We can just write the even bits
+in the result byte and then do something like::
+
+    code[0] |= (code[0] << 1);
+
+Lets test this.
+
+
+Attempt 9
+=========
+
+Changed the code but again this slightly degrades performance. Tried all
+kind of other things, like having dedicated parity arrays to avoid the
+shift after parity[rp7] << 7; No gain.
+Change the lookup using the parity array by using shift operators (e.g.
+replace parity[rp7] << 7 with::
+
+       rp7 ^= (rp7 << 4);
+       rp7 ^= (rp7 << 2);
+       rp7 ^= (rp7 << 1);
+       rp7 &= 0x80;
+
+No gain.
+
+The only marginal change was inverting the parity bits, so we can remove
+the last three invert statements.
+
+Ah well, pity this does not deliver more. Then again 10 million
+iterations using the linux driver code takes between 13 and 13.5
+seconds, whereas my code now takes about 0.73 seconds for those 10
+million iterations. So basically I've improved the performance by a
+factor 18 on my system. Not that bad. Of course on different hardware
+you will get different results. No warranties!
+
+But of course there is no such thing as a free lunch. The codesize almost
+tripled (from 562 bytes to 1434 bytes). Then again, it is not that much.
+
+
+Correcting errors
+=================
+
+For correcting errors I again used the ST application note as a starter,
+but I also peeked at the existing code.
+
+The algorithm itself is pretty straightforward. Just xor the given and
+the calculated ecc. If all bytes are 0 there is no problem. If 11 bits
+are 1 we have one correctable bit error. If there is 1 bit 1, we have an
+error in the given ecc code.
+
+It proved to be fastest to do some table lookups. Performance gain
+introduced by this is about a factor 2 on my system when a repair had to
+be done, and 1% or so if no repair had to be done.
+
+Code size increased from 330 bytes to 686 bytes for this function.
+(gcc 4.2, -O3)
+
+
+Conclusion
+==========
+
+The gain when calculating the ecc is tremendous. Om my development hardware
+a speedup of a factor of 18 for ecc calculation was achieved. On a test on an
+embedded system with a MIPS core a factor 7 was obtained.
+
+On a test with a Linksys NSLU2 (ARMv5TE processor) the speedup was a factor
+5 (big endian mode, gcc 4.1.2, -O3)
+
+For correction not much gain could be obtained (as bitflips are rare). Then
+again there are also much less cycles spent there.
+
+It seems there is not much more gain possible in this, at least when
+programmed in C. Of course it might be possible to squeeze something more
+out of it with an assembler program, but due to pipeline behaviour etc
+this is very tricky (at least for intel hw).
+
+Author: Frans Meulenbroeks
+
+Copyright (C) 2008 Koninklijke Philips Electronics NV.
diff --git a/Documentation/driver-api/mtd/spi-nor.rst b/Documentation/driver-api/mtd/spi-nor.rst
new file mode 100644 (file)
index 0000000..f5333e3
--- /dev/null
@@ -0,0 +1,66 @@
+=================
+SPI NOR framework
+=================
+
+Part I - Why do we need this framework?
+---------------------------------------
+
+SPI bus controllers (drivers/spi/) only deal with streams of bytes; the bus
+controller operates agnostic of the specific device attached. However, some
+controllers (such as Freescale's QuadSPI controller) cannot easily handle
+arbitrary streams of bytes, but rather are designed specifically for SPI NOR.
+
+In particular, Freescale's QuadSPI controller must know the NOR commands to
+find the right LUT sequence. Unfortunately, the SPI subsystem has no notion of
+opcodes, addresses, or data payloads; a SPI controller simply knows to send or
+receive bytes (Tx and Rx). Therefore, we must define a new layering scheme under
+which the controller driver is aware of the opcodes, addressing, and other
+details of the SPI NOR protocol.
+
+Part II - How does the framework work?
+--------------------------------------
+
+This framework just adds a new layer between the MTD and the SPI bus driver.
+With this new layer, the SPI NOR controller driver does not depend on the
+m25p80 code anymore.
+
+Before this framework, the layer is like::
+
+                   MTD
+         ------------------------
+                  m25p80
+         ------------------------
+              SPI bus driver
+         ------------------------
+               SPI NOR chip
+
+   After this framework, the layer is like:
+                   MTD
+         ------------------------
+              SPI NOR framework
+         ------------------------
+                  m25p80
+         ------------------------
+              SPI bus driver
+         ------------------------
+              SPI NOR chip
+
+  With the SPI NOR controller driver (Freescale QuadSPI), it looks like:
+                   MTD
+         ------------------------
+              SPI NOR framework
+         ------------------------
+                fsl-quadSPI
+         ------------------------
+              SPI NOR chip
+
+Part III - How can drivers use the framework?
+---------------------------------------------
+
+The main API is spi_nor_scan(). Before you call the hook, a driver should
+initialize the necessary fields for spi_nor{}. Please see
+drivers/mtd/spi-nor/spi-nor.c for detail. Please also refer to fsl-quadspi.c
+when you want to write a new driver for a SPI NOR controller.
+Another API is spi_nor_restore(), this is used to restore the status of SPI
+flash chip such as addressing mode. Call it whenever detach the driver from
+device or reboot the system.
diff --git a/Documentation/driver-api/nfc/index.rst b/Documentation/driver-api/nfc/index.rst
new file mode 100644 (file)
index 0000000..b6e9eed
--- /dev/null
@@ -0,0 +1,11 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+========================
+Near Field Communication
+========================
+
+.. toctree::
+   :maxdepth: 1
+
+   nfc-hci
+   nfc-pn544
diff --git a/Documentation/driver-api/nfc/nfc-hci.rst b/Documentation/driver-api/nfc/nfc-hci.rst
new file mode 100644 (file)
index 0000000..eb8a1a1
--- /dev/null
@@ -0,0 +1,311 @@
+========================
+HCI backend for NFC Core
+========================
+
+- Author: Eric Lapuyade, Samuel Ortiz
+- Contact: eric.lapuyade@intel.com, samuel.ortiz@intel.com
+
+General
+-------
+
+The HCI layer implements much of the ETSI TS 102 622 V10.2.0 specification. It
+enables easy writing of HCI-based NFC drivers. The HCI layer runs as an NFC Core
+backend, implementing an abstract nfc device and translating NFC Core API
+to HCI commands and events.
+
+HCI
+---
+
+HCI registers as an nfc device with NFC Core. Requests coming from userspace are
+routed through netlink sockets to NFC Core and then to HCI. From this point,
+they are translated in a sequence of HCI commands sent to the HCI layer in the
+host controller (the chip). Commands can be executed synchronously (the sending
+context blocks waiting for response) or asynchronously (the response is returned
+from HCI Rx context).
+HCI events can also be received from the host controller. They will be handled
+and a translation will be forwarded to NFC Core as needed. There are hooks to
+let the HCI driver handle proprietary events or override standard behavior.
+HCI uses 2 execution contexts:
+
+- one for executing commands : nfc_hci_msg_tx_work(). Only one command
+  can be executing at any given moment.
+- one for dispatching received events and commands : nfc_hci_msg_rx_work().
+
+HCI Session initialization
+--------------------------
+
+The Session initialization is an HCI standard which must unfortunately
+support proprietary gates. This is the reason why the driver will pass a list
+of proprietary gates that must be part of the session. HCI will ensure all
+those gates have pipes connected when the hci device is set up.
+In case the chip supports pre-opened gates and pseudo-static pipes, the driver
+can pass that information to HCI core.
+
+HCI Gates and Pipes
+-------------------
+
+A gate defines the 'port' where some service can be found. In order to access
+a service, one must create a pipe to that gate and open it. In this
+implementation, pipes are totally hidden. The public API only knows gates.
+This is consistent with the driver need to send commands to proprietary gates
+without knowing the pipe connected to it.
+
+Driver interface
+----------------
+
+A driver is generally written in two parts : the physical link management and
+the HCI management. This makes it easier to maintain a driver for a chip that
+can be connected using various phy (i2c, spi, ...)
+
+HCI Management
+--------------
+
+A driver would normally register itself with HCI and provide the following
+entry points::
+
+  struct nfc_hci_ops {
+       int (*open)(struct nfc_hci_dev *hdev);
+       void (*close)(struct nfc_hci_dev *hdev);
+       int (*hci_ready) (struct nfc_hci_dev *hdev);
+       int (*xmit) (struct nfc_hci_dev *hdev, struct sk_buff *skb);
+       int (*start_poll) (struct nfc_hci_dev *hdev,
+                          u32 im_protocols, u32 tm_protocols);
+       int (*dep_link_up)(struct nfc_hci_dev *hdev, struct nfc_target *target,
+                          u8 comm_mode, u8 *gb, size_t gb_len);
+       int (*dep_link_down)(struct nfc_hci_dev *hdev);
+       int (*target_from_gate) (struct nfc_hci_dev *hdev, u8 gate,
+                                struct nfc_target *target);
+       int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate,
+                                          struct nfc_target *target);
+       int (*im_transceive) (struct nfc_hci_dev *hdev,
+                             struct nfc_target *target, struct sk_buff *skb,
+                             data_exchange_cb_t cb, void *cb_context);
+       int (*tm_send)(struct nfc_hci_dev *hdev, struct sk_buff *skb);
+       int (*check_presence)(struct nfc_hci_dev *hdev,
+                             struct nfc_target *target);
+       int (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event,
+                             struct sk_buff *skb);
+  };
+
+- open() and close() shall turn the hardware on and off.
+- hci_ready() is an optional entry point that is called right after the hci
+  session has been set up. The driver can use it to do additional initialization
+  that must be performed using HCI commands.
+- xmit() shall simply write a frame to the physical link.
+- start_poll() is an optional entrypoint that shall set the hardware in polling
+  mode. This must be implemented only if the hardware uses proprietary gates or a
+  mechanism slightly different from the HCI standard.
+- dep_link_up() is called after a p2p target has been detected, to finish
+  the p2p connection setup with hardware parameters that need to be passed back
+  to nfc core.
+- dep_link_down() is called to bring the p2p link down.
+- target_from_gate() is an optional entrypoint to return the nfc protocols
+  corresponding to a proprietary gate.
+- complete_target_discovered() is an optional entry point to let the driver
+  perform additional proprietary processing necessary to auto activate the
+  discovered target.
+- im_transceive() must be implemented by the driver if proprietary HCI commands
+  are required to send data to the tag. Some tag types will require custom
+  commands, others can be written to using the standard HCI commands. The driver
+  can check the tag type and either do proprietary processing, or return 1 to ask
+  for standard processing. The data exchange command itself must be sent
+  asynchronously.
+- tm_send() is called to send data in the case of a p2p connection
+- check_presence() is an optional entry point that will be called regularly
+  by the core to check that an activated tag is still in the field. If this is
+  not implemented, the core will not be able to push tag_lost events to the user
+  space
+- event_received() is called to handle an event coming from the chip. Driver
+  can handle the event or return 1 to let HCI attempt standard processing.
+
+On the rx path, the driver is responsible to push incoming HCP frames to HCI
+using nfc_hci_recv_frame(). HCI will take care of re-aggregation and handling
+This must be done from a context that can sleep.
+
+PHY Management
+--------------
+
+The physical link (i2c, ...) management is defined by the following structure::
+
+  struct nfc_phy_ops {
+       int (*write)(void *dev_id, struct sk_buff *skb);
+       int (*enable)(void *dev_id);
+       void (*disable)(void *dev_id);
+  };
+
+enable():
+       turn the phy on (power on), make it ready to transfer data
+disable():
+       turn the phy off
+write():
+       Send a data frame to the chip. Note that to enable higher
+       layers such as an llc to store the frame for re-emission, this
+       function must not alter the skb. It must also not return a positive
+       result (return 0 for success, negative for failure).
+
+Data coming from the chip shall be sent directly to nfc_hci_recv_frame().
+
+LLC
+---
+
+Communication between the CPU and the chip often requires some link layer
+protocol. Those are isolated as modules managed by the HCI layer. There are
+currently two modules : nop (raw transfert) and shdlc.
+A new llc must implement the following functions::
+
+  struct nfc_llc_ops {
+       void *(*init) (struct nfc_hci_dev *hdev, xmit_to_drv_t xmit_to_drv,
+                      rcv_to_hci_t rcv_to_hci, int tx_headroom,
+                      int tx_tailroom, int *rx_headroom, int *rx_tailroom,
+                      llc_failure_t llc_failure);
+       void (*deinit) (struct nfc_llc *llc);
+       int (*start) (struct nfc_llc *llc);
+       int (*stop) (struct nfc_llc *llc);
+       void (*rcv_from_drv) (struct nfc_llc *llc, struct sk_buff *skb);
+       int (*xmit_from_hci) (struct nfc_llc *llc, struct sk_buff *skb);
+  };
+
+init():
+       allocate and init your private storage
+deinit():
+       cleanup
+start():
+       establish the logical connection
+stop ():
+       terminate the logical connection
+rcv_from_drv():
+       handle data coming from the chip, going to HCI
+xmit_from_hci():
+       handle data sent by HCI, going to the chip
+
+The llc must be registered with nfc before it can be used. Do that by
+calling::
+
+       nfc_llc_register(const char *name, struct nfc_llc_ops *ops);
+
+Again, note that the llc does not handle the physical link. It is thus very
+easy to mix any physical link with any llc for a given chip driver.
+
+Included Drivers
+----------------
+
+An HCI based driver for an NXP PN544, connected through I2C bus, and using
+shdlc is included.
+
+Execution Contexts
+------------------
+
+The execution contexts are the following:
+- IRQ handler (IRQH):
+fast, cannot sleep. sends incoming frames to HCI where they are passed to
+the current llc. In case of shdlc, the frame is queued in shdlc rx queue.
+
+- SHDLC State Machine worker (SMW)
+
+  Only when llc_shdlc is used: handles shdlc rx & tx queues.
+
+  Dispatches HCI cmd responses.
+
+- HCI Tx Cmd worker (MSGTXWQ)
+
+  Serializes execution of HCI commands.
+
+  Completes execution in case of response timeout.
+
+- HCI Rx worker (MSGRXWQ)
+
+  Dispatches incoming HCI commands or events.
+
+- Syscall context from a userspace call (SYSCALL)
+
+  Any entrypoint in HCI called from NFC Core
+
+Workflow executing an HCI command (using shdlc)
+-----------------------------------------------
+
+Executing an HCI command can easily be performed synchronously using the
+following API::
+
+  int nfc_hci_send_cmd (struct nfc_hci_dev *hdev, u8 gate, u8 cmd,
+                       const u8 *param, size_t param_len, struct sk_buff **skb)
+
+The API must be invoked from a context that can sleep. Most of the time, this
+will be the syscall context. skb will return the result that was received in
+the response.
+
+Internally, execution is asynchronous. So all this API does is to enqueue the
+HCI command, setup a local wait queue on stack, and wait_event() for completion.
+The wait is not interruptible because it is guaranteed that the command will
+complete after some short timeout anyway.
+
+MSGTXWQ context will then be scheduled and invoke nfc_hci_msg_tx_work().
+This function will dequeue the next pending command and send its HCP fragments
+to the lower layer which happens to be shdlc. It will then start a timer to be
+able to complete the command with a timeout error if no response arrive.
+
+SMW context gets scheduled and invokes nfc_shdlc_sm_work(). This function
+handles shdlc framing in and out. It uses the driver xmit to send frames and
+receives incoming frames in an skb queue filled from the driver IRQ handler.
+SHDLC I(nformation) frames payload are HCP fragments. They are aggregated to
+form complete HCI frames, which can be a response, command, or event.
+
+HCI Responses are dispatched immediately from this context to unblock
+waiting command execution. Response processing involves invoking the completion
+callback that was provided by nfc_hci_msg_tx_work() when it sent the command.
+The completion callback will then wake the syscall context.
+
+It is also possible to execute the command asynchronously using this API::
+
+  static int nfc_hci_execute_cmd_async(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
+                                      const u8 *param, size_t param_len,
+                                      data_exchange_cb_t cb, void *cb_context)
+
+The workflow is the same, except that the API call returns immediately, and
+the callback will be called with the result from the SMW context.
+
+Workflow receiving an HCI event or command
+------------------------------------------
+
+HCI commands or events are not dispatched from SMW context. Instead, they are
+queued to HCI rx_queue and will be dispatched from HCI rx worker
+context (MSGRXWQ). This is done this way to allow a cmd or event handler
+to also execute other commands (for example, handling the
+NFC_HCI_EVT_TARGET_DISCOVERED event from PN544 requires to issue an
+ANY_GET_PARAMETER to the reader A gate to get information on the target
+that was discovered).
+
+Typically, such an event will be propagated to NFC Core from MSGRXWQ context.
+
+Error management
+----------------
+
+Errors that occur synchronously with the execution of an NFC Core request are
+simply returned as the execution result of the request. These are easy.
+
+Errors that occur asynchronously (e.g. in a background protocol handling thread)
+must be reported such that upper layers don't stay ignorant that something
+went wrong below and know that expected events will probably never happen.
+Handling of these errors is done as follows:
+
+- driver (pn544) fails to deliver an incoming frame: it stores the error such
+  that any subsequent call to the driver will result in this error. Then it
+  calls the standard nfc_shdlc_recv_frame() with a NULL argument to report the
+  problem above. shdlc stores a EREMOTEIO sticky status, which will trigger
+  SMW to report above in turn.
+
+- SMW is basically a background thread to handle incoming and outgoing shdlc
+  frames. This thread will also check the shdlc sticky status and report to HCI
+  when it discovers it is not able to run anymore because of an unrecoverable
+  error that happened within shdlc or below. If the problem occurs during shdlc
+  connection, the error is reported through the connect completion.
+
+- HCI: if an internal HCI error happens (frame is lost), or HCI is reported an
+  error from a lower layer, HCI will either complete the currently executing
+  command with that error, or notify NFC Core directly if no command is
+  executing.
+
+- NFC Core: when NFC Core is notified of an error from below and polling is
+  active, it will send a tag discovered event with an empty tag list to the user
+  space to let it know that the poll operation will never be able to detect a
+  tag. If polling is not active and the error was sticky, lower levels will
+  return it at next invocation.
diff --git a/Documentation/driver-api/nfc/nfc-pn544.rst b/Documentation/driver-api/nfc/nfc-pn544.rst
new file mode 100644 (file)
index 0000000..6b2d8aa
--- /dev/null
@@ -0,0 +1,34 @@
+============================================================================
+Kernel driver for the NXP Semiconductors PN544 Near Field Communication chip
+============================================================================
+
+
+General
+-------
+
+The PN544 is an integrated transmission module for contactless
+communication. The driver goes under drives/nfc/ and is compiled as a
+module named "pn544".
+
+Host Interfaces: I2C, SPI and HSU, this driver supports currently only I2C.
+
+Protocols
+---------
+
+In the normal (HCI) mode and in the firmware update mode read and
+write functions behave a bit differently because the message formats
+or the protocols are different.
+
+In the normal (HCI) mode the protocol used is derived from the ETSI
+HCI specification. The firmware is updated using a specific protocol,
+which is different from HCI.
+
+HCI messages consist of an eight bit header and the message body. The
+header contains the message length. Maximum size for an HCI message is
+33. In HCI mode sent messages are tested for a correct
+checksum. Firmware update messages have the length in the second (MSB)
+and third (LSB) bytes of the message. The maximum FW message length is
+1024 bytes.
+
+For the ETSI HCI specification see
+http://www.etsi.org/WebSite/Technologies/ProtocolSpecification.aspx
diff --git a/Documentation/driver-api/ntb.rst b/Documentation/driver-api/ntb.rst
new file mode 100644 (file)
index 0000000..87d1372
--- /dev/null
@@ -0,0 +1,263 @@
+===========
+NTB Drivers
+===========
+
+NTB (Non-Transparent Bridge) is a type of PCI-Express bridge chip that connects
+the separate memory systems of two or more computers to the same PCI-Express
+fabric. Existing NTB hardware supports a common feature set: doorbell
+registers and memory translation windows, as well as non common features like
+scratchpad and message registers. Scratchpad registers are read-and-writable
+registers that are accessible from either side of the device, so that peers can
+exchange a small amount of information at a fixed address. Message registers can
+be utilized for the same purpose. Additionally they are provided with with
+special status bits to make sure the information isn't rewritten by another
+peer. Doorbell registers provide a way for peers to send interrupt events.
+Memory windows allow translated read and write access to the peer memory.
+
+NTB Core Driver (ntb)
+=====================
+
+The NTB core driver defines an api wrapping the common feature set, and allows
+clients interested in NTB features to discover NTB the devices supported by
+hardware drivers.  The term "client" is used here to mean an upper layer
+component making use of the NTB api.  The term "driver," or "hardware driver,"
+is used here to mean a driver for a specific vendor and model of NTB hardware.
+
+NTB Client Drivers
+==================
+
+NTB client drivers should register with the NTB core driver.  After
+registering, the client probe and remove functions will be called appropriately
+as ntb hardware, or hardware drivers, are inserted and removed.  The
+registration uses the Linux Device framework, so it should feel familiar to
+anyone who has written a pci driver.
+
+NTB Typical client driver implementation
+----------------------------------------
+
+Primary purpose of NTB is to share some peace of memory between at least two
+systems. So the NTB device features like Scratchpad/Message registers are
+mainly used to perform the proper memory window initialization. Typically
+there are two types of memory window interfaces supported by the NTB API:
+inbound translation configured on the local ntb port and outbound translation
+configured by the peer, on the peer ntb port. The first type is
+depicted on the next figure::
+
+ Inbound translation:
+
+ Memory:              Local NTB Port:      Peer NTB Port:      Peer MMIO:
+  ____________
+ | dma-mapped |-ntb_mw_set_trans(addr)  |
+ | memory     |        _v____________   |   ______________
+ | (addr)     |<======| MW xlat addr |<====| MW base addr |<== memory-mapped IO
+ |------------|       |--------------|  |  |--------------|
+
+So typical scenario of the first type memory window initialization looks:
+1) allocate a memory region, 2) put translated address to NTB config,
+3) somehow notify a peer device of performed initialization, 4) peer device
+maps corresponding outbound memory window so to have access to the shared
+memory region.
+
+The second type of interface, that implies the shared windows being
+initialized by a peer device, is depicted on the figure::
+
+ Outbound translation:
+
+ Memory:        Local NTB Port:    Peer NTB Port:      Peer MMIO:
+  ____________                      ______________
+ | dma-mapped |                |   | MW base addr |<== memory-mapped IO
+ | memory     |                |   |--------------|
+ | (addr)     |<===================| MW xlat addr |<-ntb_peer_mw_set_trans(addr)
+ |------------|                |   |--------------|
+
+Typical scenario of the second type interface initialization would be:
+1) allocate a memory region, 2) somehow deliver a translated address to a peer
+device, 3) peer puts the translated address to NTB config, 4) peer device maps
+outbound memory window so to have access to the shared memory region.
+
+As one can see the described scenarios can be combined in one portable
+algorithm.
+
+ Local device:
+  1) Allocate memory for a shared window
+  2) Initialize memory window by translated address of the allocated region
+     (it may fail if local memory window initialization is unsupported)
+  3) Send the translated address and memory window index to a peer device
+
+ Peer device:
+  1) Initialize memory window with retrieved address of the allocated
+     by another device memory region (it may fail if peer memory window
+     initialization is unsupported)
+  2) Map outbound memory window
+
+In accordance with this scenario, the NTB Memory Window API can be used as
+follows:
+
+ Local device:
+  1) ntb_mw_count(pidx) - retrieve number of memory ranges, which can
+     be allocated for memory windows between local device and peer device
+     of port with specified index.
+  2) ntb_get_align(pidx, midx) - retrieve parameters restricting the
+     shared memory region alignment and size. Then memory can be properly
+     allocated.
+  3) Allocate physically contiguous memory region in compliance with
+     restrictions retrieved in 2).
+  4) ntb_mw_set_trans(pidx, midx) - try to set translation address of
+     the memory window with specified index for the defined peer device
+     (it may fail if local translated address setting is not supported)
+  5) Send translated base address (usually together with memory window
+     number) to the peer device using, for instance, scratchpad or message
+     registers.
+
+ Peer device:
+  1) ntb_peer_mw_set_trans(pidx, midx) - try to set received from other
+     device (related to pidx) translated address for specified memory
+     window. It may fail if retrieved address, for instance, exceeds
+     maximum possible address or isn't properly aligned.
+  2) ntb_peer_mw_get_addr(widx) - retrieve MMIO address to map the memory
+     window so to have an access to the shared memory.
+
+Also it is worth to note, that method ntb_mw_count(pidx) should return the
+same value as ntb_peer_mw_count() on the peer with port index - pidx.
+
+NTB Transport Client (ntb\_transport) and NTB Netdev (ntb\_netdev)
+------------------------------------------------------------------
+
+The primary client for NTB is the Transport client, used in tandem with NTB
+Netdev.  These drivers function together to create a logical link to the peer,
+across the ntb, to exchange packets of network data.  The Transport client
+establishes a logical link to the peer, and creates queue pairs to exchange
+messages and data.  The NTB Netdev then creates an ethernet device using a
+Transport queue pair.  Network data is copied between socket buffers and the
+Transport queue pair buffer.  The Transport client may be used for other things
+besides Netdev, however no other applications have yet been written.
+
+NTB Ping Pong Test Client (ntb\_pingpong)
+-----------------------------------------
+
+The Ping Pong test client serves as a demonstration to exercise the doorbell
+and scratchpad registers of NTB hardware, and as an example simple NTB client.
+Ping Pong enables the link when started, waits for the NTB link to come up, and
+then proceeds to read and write the doorbell scratchpad registers of the NTB.
+The peers interrupt each other using a bit mask of doorbell bits, which is
+shifted by one in each round, to test the behavior of multiple doorbell bits
+and interrupt vectors.  The Ping Pong driver also reads the first local
+scratchpad, and writes the value plus one to the first peer scratchpad, each
+round before writing the peer doorbell register.
+
+Module Parameters:
+
+* unsafe - Some hardware has known issues with scratchpad and doorbell
+       registers.  By default, Ping Pong will not attempt to exercise such
+       hardware.  You may override this behavior at your own risk by setting
+       unsafe=1.
+* delay\_ms - Specify the delay between receiving a doorbell
+       interrupt event and setting the peer doorbell register for the next
+       round.
+* init\_db - Specify the doorbell bits to start new series of rounds.  A new
+       series begins once all the doorbell bits have been shifted out of
+       range.
+* dyndbg - It is suggested to specify dyndbg=+p when loading this module, and
+       then to observe debugging output on the console.
+
+NTB Tool Test Client (ntb\_tool)
+--------------------------------
+
+The Tool test client serves for debugging, primarily, ntb hardware and drivers.
+The Tool provides access through debugfs for reading, setting, and clearing the
+NTB doorbell, and reading and writing scratchpads.
+
+The Tool does not currently have any module parameters.
+
+Debugfs Files:
+
+* *debugfs*/ntb\_tool/*hw*/
+       A directory in debugfs will be created for each
+       NTB device probed by the tool.  This directory is shortened to *hw*
+       below.
+* *hw*/db
+       This file is used to read, set, and clear the local doorbell.  Not
+       all operations may be supported by all hardware.  To read the doorbell,
+       read the file.  To set the doorbell, write `s` followed by the bits to
+       set (eg: `echo 's 0x0101' > db`).  To clear the doorbell, write `c`
+       followed by the bits to clear.
+* *hw*/mask
+       This file is used to read, set, and clear the local doorbell mask.
+       See *db* for details.
+* *hw*/peer\_db
+       This file is used to read, set, and clear the peer doorbell.
+       See *db* for details.
+* *hw*/peer\_mask
+       This file is used to read, set, and clear the peer doorbell
+       mask.  See *db* for details.
+* *hw*/spad
+       This file is used to read and write local scratchpads.  To read
+       the values of all scratchpads, read the file.  To write values, write a
+       series of pairs of scratchpad number and value
+       (eg: `echo '4 0x123 7 0xabc' > spad`
+       # to set scratchpads `4` and `7` to `0x123` and `0xabc`, respectively).
+* *hw*/peer\_spad
+       This file is used to read and write peer scratchpads.  See
+       *spad* for details.
+
+NTB MSI Test Client (ntb\_msi\_test)
+------------------------------------
+
+The MSI test client serves to test and debug the MSI library which
+allows for passing MSI interrupts across NTB memory windows. The
+test client is interacted with through the debugfs filesystem:
+
+* *debugfs*/ntb\_tool/*hw*/
+       A directory in debugfs will be created for each
+       NTB device probed by the tool.  This directory is shortened to *hw*
+       below.
+* *hw*/port
+       This file describes the local port number
+* *hw*/irq*_occurrences
+       One occurrences file exists for each interrupt and, when read,
+       returns the number of times the interrupt has been triggered.
+* *hw*/peer*/port
+       This file describes the port number for each peer
+* *hw*/peer*/count
+       This file describes the number of interrupts that can be
+       triggered on each peer
+* *hw*/peer*/trigger
+       Writing an interrupt number (any number less than the value
+       specified in count) will trigger the interrupt on the
+       specified peer. That peer's interrupt's occurrence file
+       should be incremented.
+
+NTB Hardware Drivers
+====================
+
+NTB hardware drivers should register devices with the NTB core driver.  After
+registering, clients probe and remove functions will be called.
+
+NTB Intel Hardware Driver (ntb\_hw\_intel)
+------------------------------------------
+
+The Intel hardware driver supports NTB on Xeon and Atom CPUs.
+
+Module Parameters:
+
+* b2b\_mw\_idx
+       If the peer ntb is to be accessed via a memory window, then use
+       this memory window to access the peer ntb.  A value of zero or positive
+       starts from the first mw idx, and a negative value starts from the last
+       mw idx.  Both sides MUST set the same value here!  The default value is
+       `-1`.
+* b2b\_mw\_share
+       If the peer ntb is to be accessed via a memory window, and if
+       the memory window is large enough, still allow the client to use the
+       second half of the memory window for address translation to the peer.
+* xeon\_b2b\_usd\_bar2\_addr64
+       If using B2B topology on Xeon hardware, use
+       this 64 bit address on the bus between the NTB devices for the window
+       at BAR2, on the upstream side of the link.
+* xeon\_b2b\_usd\_bar4\_addr64 - See *xeon\_b2b\_bar2\_addr64*.
+* xeon\_b2b\_usd\_bar4\_addr32 - See *xeon\_b2b\_bar2\_addr64*.
+* xeon\_b2b\_usd\_bar5\_addr32 - See *xeon\_b2b\_bar2\_addr64*.
+* xeon\_b2b\_dsd\_bar2\_addr64 - See *xeon\_b2b\_bar2\_addr64*.
+* xeon\_b2b\_dsd\_bar4\_addr64 - See *xeon\_b2b\_bar2\_addr64*.
+* xeon\_b2b\_dsd\_bar4\_addr32 - See *xeon\_b2b\_bar2\_addr64*.
+* xeon\_b2b\_dsd\_bar5\_addr32 - See *xeon\_b2b\_bar2\_addr64*.
diff --git a/Documentation/driver-api/nvdimm/btt.rst b/Documentation/driver-api/nvdimm/btt.rst
new file mode 100644 (file)
index 0000000..107395c
--- /dev/null
@@ -0,0 +1,285 @@
+=============================
+BTT - Block Translation Table
+=============================
+
+
+1. Introduction
+===============
+
+Persistent memory based storage is able to perform IO at byte (or more
+accurately, cache line) granularity. However, we often want to expose such
+storage as traditional block devices. The block drivers for persistent memory
+will do exactly this. However, they do not provide any atomicity guarantees.
+Traditional SSDs typically provide protection against torn sectors in hardware,
+using stored energy in capacitors to complete in-flight block writes, or perhaps
+in firmware. We don't have this luxury with persistent memory - if a write is in
+progress, and we experience a power failure, the block will contain a mix of old
+and new data. Applications may not be prepared to handle such a scenario.
+
+The Block Translation Table (BTT) provides atomic sector update semantics for
+persistent memory devices, so that applications that rely on sector writes not
+being torn can continue to do so. The BTT manifests itself as a stacked block
+device, and reserves a portion of the underlying storage for its metadata. At
+the heart of it, is an indirection table that re-maps all the blocks on the
+volume. It can be thought of as an extremely simple file system that only
+provides atomic sector updates.
+
+
+2. Static Layout
+================
+
+The underlying storage on which a BTT can be laid out is not limited in any way.
+The BTT, however, splits the available space into chunks of up to 512 GiB,
+called "Arenas".
+
+Each arena follows the same layout for its metadata, and all references in an
+arena are internal to it (with the exception of one field that points to the
+next arena). The following depicts the "On-disk" metadata layout::
+
+
+    Backing Store     +------->  Arena
+  +---------------+   |   +------------------+
+  |               |   |   | Arena info block |
+  |    Arena 0    +---+   |       4K         |
+  |     512G      |       +------------------+
+  |               |       |                  |
+  +---------------+       |                  |
+  |               |       |                  |
+  |    Arena 1    |       |   Data Blocks    |
+  |     512G      |       |                  |
+  |               |       |                  |
+  +---------------+       |                  |
+  |       .       |       |                  |
+  |       .       |       |                  |
+  |       .       |       |                  |
+  |               |       |                  |
+  |               |       |                  |
+  +---------------+       +------------------+
+                          |                  |
+                          |     BTT Map      |
+                          |                  |
+                          |                  |
+                          +------------------+
+                          |                  |
+                          |     BTT Flog     |
+                          |                  |
+                          +------------------+
+                          | Info block copy  |
+                          |       4K         |
+                          +------------------+
+
+
+3. Theory of Operation
+======================
+
+
+a. The BTT Map
+--------------
+
+The map is a simple lookup/indirection table that maps an LBA to an internal
+block. Each map entry is 32 bits. The two most significant bits are special
+flags, and the remaining form the internal block number.
+
+======== =============================================================
+Bit      Description
+======== =============================================================
+31 - 30         Error and Zero flags - Used in the following way::
+
+          == ==  ====================================================
+          31 30  Description
+          == ==  ====================================================
+          0  0   Initial state. Reads return zeroes; Premap = Postmap
+          0  1   Zero state: Reads return zeroes
+          1  0   Error state: Reads fail; Writes clear 'E' bit
+          1  1   Normal Block – has valid postmap
+          == ==  ====================================================
+
+29 - 0  Mappings to internal 'postmap' blocks
+======== =============================================================
+
+
+Some of the terminology that will be subsequently used:
+
+============   ================================================================
+External LBA   LBA as made visible to upper layers.
+ABA            Arena Block Address - Block offset/number within an arena
+Premap ABA     The block offset into an arena, which was decided upon by range
+               checking the External LBA
+Postmap ABA    The block number in the "Data Blocks" area obtained after
+               indirection from the map
+nfree          The number of free blocks that are maintained at any given time.
+               This is the number of concurrent writes that can happen to the
+               arena.
+============   ================================================================
+
+
+For example, after adding a BTT, we surface a disk of 1024G. We get a read for
+the external LBA at 768G. This falls into the second arena, and of the 512G
+worth of blocks that this arena contributes, this block is at 256G. Thus, the
+premap ABA is 256G. We now refer to the map, and find out the mapping for block
+'X' (256G) points to block 'Y', say '64'. Thus the postmap ABA is 64.
+
+
+b. The BTT Flog
+---------------
+
+The BTT provides sector atomicity by making every write an "allocating write",
+i.e. Every write goes to a "free" block. A running list of free blocks is
+maintained in the form of the BTT flog. 'Flog' is a combination of the words
+"free list" and "log". The flog contains 'nfree' entries, and an entry contains:
+
+========  =====================================================================
+lba       The premap ABA that is being written to
+old_map   The old postmap ABA - after 'this' write completes, this will be a
+         free block.
+new_map   The new postmap ABA. The map will up updated to reflect this
+         lba->postmap_aba mapping, but we log it here in case we have to
+         recover.
+seq      Sequence number to mark which of the 2 sections of this flog entry is
+         valid/newest. It cycles between 01->10->11->01 (binary) under normal
+         operation, with 00 indicating an uninitialized state.
+lba'     alternate lba entry
+old_map'  alternate old postmap entry
+new_map'  alternate new postmap entry
+seq'     alternate sequence number.
+========  =====================================================================
+
+Each of the above fields is 32-bit, making one entry 32 bytes. Entries are also
+padded to 64 bytes to avoid cache line sharing or aliasing. Flog updates are
+done such that for any entry being written, it:
+a. overwrites the 'old' section in the entry based on sequence numbers
+b. writes the 'new' section such that the sequence number is written last.
+
+
+c. The concept of lanes
+-----------------------
+
+While 'nfree' describes the number of concurrent IOs an arena can process
+concurrently, 'nlanes' is the number of IOs the BTT device as a whole can
+process::
+
+       nlanes = min(nfree, num_cpus)
+
+A lane number is obtained at the start of any IO, and is used for indexing into
+all the on-disk and in-memory data structures for the duration of the IO. If
+there are more CPUs than the max number of available lanes, than lanes are
+protected by spinlocks.
+
+
+d. In-memory data structure: Read Tracking Table (RTT)
+------------------------------------------------------
+
+Consider a case where we have two threads, one doing reads and the other,
+writes. We can hit a condition where the writer thread grabs a free block to do
+a new IO, but the (slow) reader thread is still reading from it. In other words,
+the reader consulted a map entry, and started reading the corresponding block. A
+writer started writing to the same external LBA, and finished the write updating
+the map for that external LBA to point to its new postmap ABA. At this point the
+internal, postmap block that the reader is (still) reading has been inserted
+into the list of free blocks. If another write comes in for the same LBA, it can
+grab this free block, and start writing to it, causing the reader to read
+incorrect data. To prevent this, we introduce the RTT.
+
+The RTT is a simple, per arena table with 'nfree' entries. Every reader inserts
+into rtt[lane_number], the postmap ABA it is reading, and clears it after the
+read is complete. Every writer thread, after grabbing a free block, checks the
+RTT for its presence. If the postmap free block is in the RTT, it waits till the
+reader clears the RTT entry, and only then starts writing to it.
+
+
+e. In-memory data structure: map locks
+--------------------------------------
+
+Consider a case where two writer threads are writing to the same LBA. There can
+be a race in the following sequence of steps::
+
+       free[lane] = map[premap_aba]
+       map[premap_aba] = postmap_aba
+
+Both threads can update their respective free[lane] with the same old, freed
+postmap_aba. This has made the layout inconsistent by losing a free entry, and
+at the same time, duplicating another free entry for two lanes.
+
+To solve this, we could have a single map lock (per arena) that has to be taken
+before performing the above sequence, but we feel that could be too contentious.
+Instead we use an array of (nfree) map_locks that is indexed by
+(premap_aba modulo nfree).
+
+
+f. Reconstruction from the Flog
+-------------------------------
+
+On startup, we analyze the BTT flog to create our list of free blocks. We walk
+through all the entries, and for each lane, of the set of two possible
+'sections', we always look at the most recent one only (based on the sequence
+number). The reconstruction rules/steps are simple:
+
+- Read map[log_entry.lba].
+- If log_entry.new matches the map entry, then log_entry.old is free.
+- If log_entry.new does not match the map entry, then log_entry.new is free.
+  (This case can only be caused by power-fails/unsafe shutdowns)
+
+
+g. Summarizing - Read and Write flows
+-------------------------------------
+
+Read:
+
+1.  Convert external LBA to arena number + pre-map ABA
+2.  Get a lane (and take lane_lock)
+3.  Read map to get the entry for this pre-map ABA
+4.  Enter post-map ABA into RTT[lane]
+5.  If TRIM flag set in map, return zeroes, and end IO (go to step 8)
+6.  If ERROR flag set in map, end IO with EIO (go to step 8)
+7.  Read data from this block
+8.  Remove post-map ABA entry from RTT[lane]
+9.  Release lane (and lane_lock)
+
+Write:
+
+1.  Convert external LBA to Arena number + pre-map ABA
+2.  Get a lane (and take lane_lock)
+3.  Use lane to index into in-memory free list and obtain a new block, next flog
+    index, next sequence number
+4.  Scan the RTT to check if free block is present, and spin/wait if it is.
+5.  Write data to this free block
+6.  Read map to get the existing post-map ABA entry for this pre-map ABA
+7.  Write flog entry: [premap_aba / old postmap_aba / new postmap_aba / seq_num]
+8.  Write new post-map ABA into map.
+9.  Write old post-map entry into the free list
+10. Calculate next sequence number and write into the free list entry
+11. Release lane (and lane_lock)
+
+
+4. Error Handling
+=================
+
+An arena would be in an error state if any of the metadata is corrupted
+irrecoverably, either due to a bug or a media error. The following conditions
+indicate an error:
+
+- Info block checksum does not match (and recovering from the copy also fails)
+- All internal available blocks are not uniquely and entirely addressed by the
+  sum of mapped blocks and free blocks (from the BTT flog).
+- Rebuilding free list from the flog reveals missing/duplicate/impossible
+  entries
+- A map entry is out of bounds
+
+If any of these error conditions are encountered, the arena is put into a read
+only state using a flag in the info block.
+
+
+5. Usage
+========
+
+The BTT can be set up on any disk (namespace) exposed by the libnvdimm subsystem
+(pmem, or blk mode). The easiest way to set up such a namespace is using the
+'ndctl' utility [1]:
+
+For example, the ndctl command line to setup a btt with a 4k sector size is::
+
+    ndctl create-namespace -f -e namespace0.0 -m sector -l 4k
+
+See ndctl create-namespace --help for more options.
+
+[1]: https://github.com/pmem/ndctl
diff --git a/Documentation/driver-api/nvdimm/index.rst b/Documentation/driver-api/nvdimm/index.rst
new file mode 100644 (file)
index 0000000..a4f8f98
--- /dev/null
@@ -0,0 +1,12 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===================================
+Non-Volatile Memory Device (NVDIMM)
+===================================
+
+.. toctree::
+   :maxdepth: 1
+
+   nvdimm
+   btt
+   security
diff --git a/Documentation/driver-api/nvdimm/nvdimm.rst b/Documentation/driver-api/nvdimm/nvdimm.rst
new file mode 100644 (file)
index 0000000..08f855c
--- /dev/null
@@ -0,0 +1,887 @@
+===============================
+LIBNVDIMM: Non-Volatile Devices
+===============================
+
+libnvdimm - kernel / libndctl - userspace helper library
+
+linux-nvdimm@lists.01.org
+
+Version 13
+
+.. contents:
+
+       Glossary
+       Overview
+           Supporting Documents
+           Git Trees
+       LIBNVDIMM PMEM and BLK
+       Why BLK?
+           PMEM vs BLK
+               BLK-REGIONs, PMEM-REGIONs, Atomic Sectors, and DAX
+       Example NVDIMM Platform
+       LIBNVDIMM Kernel Device Model and LIBNDCTL Userspace API
+           LIBNDCTL: Context
+               libndctl: instantiate a new library context example
+           LIBNVDIMM/LIBNDCTL: Bus
+               libnvdimm: control class device in /sys/class
+               libnvdimm: bus
+               libndctl: bus enumeration example
+           LIBNVDIMM/LIBNDCTL: DIMM (NMEM)
+               libnvdimm: DIMM (NMEM)
+               libndctl: DIMM enumeration example
+           LIBNVDIMM/LIBNDCTL: Region
+               libnvdimm: region
+               libndctl: region enumeration example
+               Why Not Encode the Region Type into the Region Name?
+               How Do I Determine the Major Type of a Region?
+           LIBNVDIMM/LIBNDCTL: Namespace
+               libnvdimm: namespace
+               libndctl: namespace enumeration example
+               libndctl: namespace creation example
+               Why the Term "namespace"?
+           LIBNVDIMM/LIBNDCTL: Block Translation Table "btt"
+               libnvdimm: btt layout
+               libndctl: btt creation example
+       Summary LIBNDCTL Diagram
+
+
+Glossary
+========
+
+PMEM:
+  A system-physical-address range where writes are persistent.  A
+  block device composed of PMEM is capable of DAX.  A PMEM address range
+  may span an interleave of several DIMMs.
+
+BLK:
+  A set of one or more programmable memory mapped apertures provided
+  by a DIMM to access its media.  This indirection precludes the
+  performance benefit of interleaving, but enables DIMM-bounded failure
+  modes.
+
+DPA:
+  DIMM Physical Address, is a DIMM-relative offset.  With one DIMM in
+  the system there would be a 1:1 system-physical-address:DPA association.
+  Once more DIMMs are added a memory controller interleave must be
+  decoded to determine the DPA associated with a given
+  system-physical-address.  BLK capacity always has a 1:1 relationship
+  with a single-DIMM's DPA range.
+
+DAX:
+  File system extensions to bypass the page cache and block layer to
+  mmap persistent memory, from a PMEM block device, directly into a
+  process address space.
+
+DSM:
+  Device Specific Method: ACPI method to to control specific
+  device - in this case the firmware.
+
+DCR:
+  NVDIMM Control Region Structure defined in ACPI 6 Section 5.2.25.5.
+  It defines a vendor-id, device-id, and interface format for a given DIMM.
+
+BTT:
+  Block Translation Table: Persistent memory is byte addressable.
+  Existing software may have an expectation that the power-fail-atomicity
+  of writes is at least one sector, 512 bytes.  The BTT is an indirection
+  table with atomic update semantics to front a PMEM/BLK block device
+  driver and present arbitrary atomic sector sizes.
+
+LABEL:
+  Metadata stored on a DIMM device that partitions and identifies
+  (persistently names) storage between PMEM and BLK.  It also partitions
+  BLK storage to host BTTs with different parameters per BLK-partition.
+  Note that traditional partition tables, GPT/MBR, are layered on top of a
+  BLK or PMEM device.
+
+
+Overview
+========
+
+The LIBNVDIMM subsystem provides support for three types of NVDIMMs, namely,
+PMEM, BLK, and NVDIMM devices that can simultaneously support both PMEM
+and BLK mode access.  These three modes of operation are described by
+the "NVDIMM Firmware Interface Table" (NFIT) in ACPI 6.  While the LIBNVDIMM
+implementation is generic and supports pre-NFIT platforms, it was guided
+by the superset of capabilities need to support this ACPI 6 definition
+for NVDIMM resources.  The bulk of the kernel implementation is in place
+to handle the case where DPA accessible via PMEM is aliased with DPA
+accessible via BLK.  When that occurs a LABEL is needed to reserve DPA
+for exclusive access via one mode a time.
+
+Supporting Documents
+--------------------
+
+ACPI 6:
+       http://www.uefi.org/sites/default/files/resources/ACPI_6.0.pdf
+NVDIMM Namespace:
+       http://pmem.io/documents/NVDIMM_Namespace_Spec.pdf
+DSM Interface Example:
+       http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf
+Driver Writer's Guide:
+       http://pmem.io/documents/NVDIMM_Driver_Writers_Guide.pdf
+
+Git Trees
+---------
+
+LIBNVDIMM:
+       https://git.kernel.org/cgit/linux/kernel/git/djbw/nvdimm.git
+LIBNDCTL:
+       https://github.com/pmem/ndctl.git
+PMEM:
+       https://github.com/01org/prd
+
+
+LIBNVDIMM PMEM and BLK
+======================
+
+Prior to the arrival of the NFIT, non-volatile memory was described to a
+system in various ad-hoc ways.  Usually only the bare minimum was
+provided, namely, a single system-physical-address range where writes
+are expected to be durable after a system power loss.  Now, the NFIT
+specification standardizes not only the description of PMEM, but also
+BLK and platform message-passing entry points for control and
+configuration.
+
+For each NVDIMM access method (PMEM, BLK), LIBNVDIMM provides a block
+device driver:
+
+    1. PMEM (nd_pmem.ko): Drives a system-physical-address range.  This
+       range is contiguous in system memory and may be interleaved (hardware
+       memory controller striped) across multiple DIMMs.  When interleaved the
+       platform may optionally provide details of which DIMMs are participating
+       in the interleave.
+
+       Note that while LIBNVDIMM describes system-physical-address ranges that may
+       alias with BLK access as ND_NAMESPACE_PMEM ranges and those without
+       alias as ND_NAMESPACE_IO ranges, to the nd_pmem driver there is no
+       distinction.  The different device-types are an implementation detail
+       that userspace can exploit to implement policies like "only interface
+       with address ranges from certain DIMMs".  It is worth noting that when
+       aliasing is present and a DIMM lacks a label, then no block device can
+       be created by default as userspace needs to do at least one allocation
+       of DPA to the PMEM range.  In contrast ND_NAMESPACE_IO ranges, once
+       registered, can be immediately attached to nd_pmem.
+
+    2. BLK (nd_blk.ko): This driver performs I/O using a set of platform
+       defined apertures.  A set of apertures will access just one DIMM.
+       Multiple windows (apertures) allow multiple concurrent accesses, much like
+       tagged-command-queuing, and would likely be used by different threads or
+       different CPUs.
+
+       The NFIT specification defines a standard format for a BLK-aperture, but
+       the spec also allows for vendor specific layouts, and non-NFIT BLK
+       implementations may have other designs for BLK I/O.  For this reason
+       "nd_blk" calls back into platform-specific code to perform the I/O.
+
+       One such implementation is defined in the "Driver Writer's Guide" and "DSM
+       Interface Example".
+
+
+Why BLK?
+========
+
+While PMEM provides direct byte-addressable CPU-load/store access to
+NVDIMM storage, it does not provide the best system RAS (recovery,
+availability, and serviceability) model.  An access to a corrupted
+system-physical-address address causes a CPU exception while an access
+to a corrupted address through an BLK-aperture causes that block window
+to raise an error status in a register.  The latter is more aligned with
+the standard error model that host-bus-adapter attached disks present.
+
+Also, if an administrator ever wants to replace a memory it is easier to
+service a system at DIMM module boundaries.  Compare this to PMEM where
+data could be interleaved in an opaque hardware specific manner across
+several DIMMs.
+
+PMEM vs BLK
+-----------
+
+BLK-apertures solve these RAS problems, but their presence is also the
+major contributing factor to the complexity of the ND subsystem.  They
+complicate the implementation because PMEM and BLK alias in DPA space.
+Any given DIMM's DPA-range may contribute to one or more
+system-physical-address sets of interleaved DIMMs, *and* may also be
+accessed in its entirety through its BLK-aperture.  Accessing a DPA
+through a system-physical-address while simultaneously accessing the
+same DPA through a BLK-aperture has undefined results.  For this reason,
+DIMMs with this dual interface configuration include a DSM function to
+store/retrieve a LABEL.  The LABEL effectively partitions the DPA-space
+into exclusive system-physical-address and BLK-aperture accessible
+regions.  For simplicity a DIMM is allowed a PMEM "region" per each
+interleave set in which it is a member.  The remaining DPA space can be
+carved into an arbitrary number of BLK devices with discontiguous
+extents.
+
+BLK-REGIONs, PMEM-REGIONs, Atomic Sectors, and DAX
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+One of the few
+reasons to allow multiple BLK namespaces per REGION is so that each
+BLK-namespace can be configured with a BTT with unique atomic sector
+sizes.  While a PMEM device can host a BTT the LABEL specification does
+not provide for a sector size to be specified for a PMEM namespace.
+
+This is due to the expectation that the primary usage model for PMEM is
+via DAX, and the BTT is incompatible with DAX.  However, for the cases
+where an application or filesystem still needs atomic sector update
+guarantees it can register a BTT on a PMEM device or partition.  See
+LIBNVDIMM/NDCTL: Block Translation Table "btt"
+
+
+Example NVDIMM Platform
+=======================
+
+For the remainder of this document the following diagram will be
+referenced for any example sysfs layouts::
+
+
+                               (a)               (b)           DIMM   BLK-REGION
+            +-------------------+--------+--------+--------+
+  +------+  |       pm0.0       | blk2.0 | pm1.0  | blk2.1 |    0      region2
+  | imc0 +--+- - - region0- - - +--------+        +--------+
+  +--+---+  |       pm0.0       | blk3.0 | pm1.0  | blk3.1 |    1      region3
+     |      +-------------------+--------v        v--------+
+  +--+---+                               |                 |
+  | cpu0 |                                     region1
+  +--+---+                               |                 |
+     |      +----------------------------^        ^--------+
+  +--+---+  |           blk4.0           | pm1.0  | blk4.0 |    2      region4
+  | imc1 +--+----------------------------|        +--------+
+  +------+  |           blk5.0           | pm1.0  | blk5.0 |    3      region5
+            +----------------------------+--------+--------+
+
+In this platform we have four DIMMs and two memory controllers in one
+socket.  Each unique interface (BLK or PMEM) to DPA space is identified
+by a region device with a dynamically assigned id (REGION0 - REGION5).
+
+    1. The first portion of DIMM0 and DIMM1 are interleaved as REGION0. A
+       single PMEM namespace is created in the REGION0-SPA-range that spans most
+       of DIMM0 and DIMM1 with a user-specified name of "pm0.0". Some of that
+       interleaved system-physical-address range is reclaimed as BLK-aperture
+       accessed space starting at DPA-offset (a) into each DIMM.  In that
+       reclaimed space we create two BLK-aperture "namespaces" from REGION2 and
+       REGION3 where "blk2.0" and "blk3.0" are just human readable names that
+       could be set to any user-desired name in the LABEL.
+
+    2. In the last portion of DIMM0 and DIMM1 we have an interleaved
+       system-physical-address range, REGION1, that spans those two DIMMs as
+       well as DIMM2 and DIMM3.  Some of REGION1 is allocated to a PMEM namespace
+       named "pm1.0", the rest is reclaimed in 4 BLK-aperture namespaces (for
+       each DIMM in the interleave set), "blk2.1", "blk3.1", "blk4.0", and
+       "blk5.0".
+
+    3. The portion of DIMM2 and DIMM3 that do not participate in the REGION1
+       interleaved system-physical-address range (i.e. the DPA address past
+       offset (b) are also included in the "blk4.0" and "blk5.0" namespaces.
+       Note, that this example shows that BLK-aperture namespaces don't need to
+       be contiguous in DPA-space.
+
+    This bus is provided by the kernel under the device
+    /sys/devices/platform/nfit_test.0 when CONFIG_NFIT_TEST is enabled and
+    the nfit_test.ko module is loaded.  This not only test LIBNVDIMM but the
+    acpi_nfit.ko driver as well.
+
+
+LIBNVDIMM Kernel Device Model and LIBNDCTL Userspace API
+========================================================
+
+What follows is a description of the LIBNVDIMM sysfs layout and a
+corresponding object hierarchy diagram as viewed through the LIBNDCTL
+API.  The example sysfs paths and diagrams are relative to the Example
+NVDIMM Platform which is also the LIBNVDIMM bus used in the LIBNDCTL unit
+test.
+
+LIBNDCTL: Context
+-----------------
+
+Every API call in the LIBNDCTL library requires a context that holds the
+logging parameters and other library instance state.  The library is
+based on the libabc template:
+
+       https://git.kernel.org/cgit/linux/kernel/git/kay/libabc.git
+
+LIBNDCTL: instantiate a new library context example
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+::
+
+       struct ndctl_ctx *ctx;
+
+       if (ndctl_new(&ctx) == 0)
+               return ctx;
+       else
+               return NULL;
+
+LIBNVDIMM/LIBNDCTL: Bus
+-----------------------
+
+A bus has a 1:1 relationship with an NFIT.  The current expectation for
+ACPI based systems is that there is only ever one platform-global NFIT.
+That said, it is trivial to register multiple NFITs, the specification
+does not preclude it.  The infrastructure supports multiple busses and
+we use this capability to test multiple NFIT configurations in the unit
+test.
+
+LIBNVDIMM: control class device in /sys/class
+---------------------------------------------
+
+This character device accepts DSM messages to be passed to DIMM
+identified by its NFIT handle::
+
+       /sys/class/nd/ndctl0
+       |-- dev
+       |-- device -> ../../../ndbus0
+       |-- subsystem -> ../../../../../../../class/nd
+
+
+
+LIBNVDIMM: bus
+--------------
+
+::
+
+       struct nvdimm_bus *nvdimm_bus_register(struct device *parent,
+              struct nvdimm_bus_descriptor *nfit_desc);
+
+::
+
+       /sys/devices/platform/nfit_test.0/ndbus0
+       |-- commands
+       |-- nd
+       |-- nfit
+       |-- nmem0
+       |-- nmem1
+       |-- nmem2
+       |-- nmem3
+       |-- power
+       |-- provider
+       |-- region0
+       |-- region1
+       |-- region2
+       |-- region3
+       |-- region4
+       |-- region5
+       |-- uevent
+       `-- wait_probe
+
+LIBNDCTL: bus enumeration example
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Find the bus handle that describes the bus from Example NVDIMM Platform::
+
+       static struct ndctl_bus *get_bus_by_provider(struct ndctl_ctx *ctx,
+                       const char *provider)
+       {
+               struct ndctl_bus *bus;
+
+               ndctl_bus_foreach(ctx, bus)
+                       if (strcmp(provider, ndctl_bus_get_provider(bus)) == 0)
+                               return bus;
+
+               return NULL;
+       }
+
+       bus = get_bus_by_provider(ctx, "nfit_test.0");
+
+
+LIBNVDIMM/LIBNDCTL: DIMM (NMEM)
+-------------------------------
+
+The DIMM device provides a character device for sending commands to
+hardware, and it is a container for LABELs.  If the DIMM is defined by
+NFIT then an optional 'nfit' attribute sub-directory is available to add
+NFIT-specifics.
+
+Note that the kernel device name for "DIMMs" is "nmemX".  The NFIT
+describes these devices via "Memory Device to System Physical Address
+Range Mapping Structure", and there is no requirement that they actually
+be physical DIMMs, so we use a more generic name.
+
+LIBNVDIMM: DIMM (NMEM)
+^^^^^^^^^^^^^^^^^^^^^^
+
+::
+
+       struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data,
+                       const struct attribute_group **groups, unsigned long flags,
+                       unsigned long *dsm_mask);
+
+::
+
+       /sys/devices/platform/nfit_test.0/ndbus0
+       |-- nmem0
+       |   |-- available_slots
+       |   |-- commands
+       |   |-- dev
+       |   |-- devtype
+       |   |-- driver -> ../../../../../bus/nd/drivers/nvdimm
+       |   |-- modalias
+       |   |-- nfit
+       |   |   |-- device
+       |   |   |-- format
+       |   |   |-- handle
+       |   |   |-- phys_id
+       |   |   |-- rev_id
+       |   |   |-- serial
+       |   |   `-- vendor
+       |   |-- state
+       |   |-- subsystem -> ../../../../../bus/nd
+       |   `-- uevent
+       |-- nmem1
+       [..]
+
+
+LIBNDCTL: DIMM enumeration example
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Note, in this example we are assuming NFIT-defined DIMMs which are
+identified by an "nfit_handle" a 32-bit value where:
+
+   - Bit 3:0 DIMM number within the memory channel
+   - Bit 7:4 memory channel number
+   - Bit 11:8 memory controller ID
+   - Bit 15:12 socket ID (within scope of a Node controller if node
+     controller is present)
+   - Bit 27:16 Node Controller ID
+   - Bit 31:28 Reserved
+
+::
+
+       static struct ndctl_dimm *get_dimm_by_handle(struct ndctl_bus *bus,
+              unsigned int handle)
+       {
+               struct ndctl_dimm *dimm;
+
+               ndctl_dimm_foreach(bus, dimm)
+                       if (ndctl_dimm_get_handle(dimm) == handle)
+                               return dimm;
+
+               return NULL;
+       }
+
+       #define DIMM_HANDLE(n, s, i, c, d) \
+               (((n & 0xfff) << 16) | ((s & 0xf) << 12) | ((i & 0xf) << 8) \
+                | ((c & 0xf) << 4) | (d & 0xf))
+
+       dimm = get_dimm_by_handle(bus, DIMM_HANDLE(0, 0, 0, 0, 0));
+
+LIBNVDIMM/LIBNDCTL: Region
+--------------------------
+
+A generic REGION device is registered for each PMEM range or BLK-aperture
+set.  Per the example there are 6 regions: 2 PMEM and 4 BLK-aperture
+sets on the "nfit_test.0" bus.  The primary role of regions are to be a
+container of "mappings".  A mapping is a tuple of <DIMM,
+DPA-start-offset, length>.
+
+LIBNVDIMM provides a built-in driver for these REGION devices.  This driver
+is responsible for reconciling the aliased DPA mappings across all
+regions, parsing the LABEL, if present, and then emitting NAMESPACE
+devices with the resolved/exclusive DPA-boundaries for the nd_pmem or
+nd_blk device driver to consume.
+
+In addition to the generic attributes of "mapping"s, "interleave_ways"
+and "size" the REGION device also exports some convenience attributes.
+"nstype" indicates the integer type of namespace-device this region
+emits, "devtype" duplicates the DEVTYPE variable stored by udev at the
+'add' event, "modalias" duplicates the MODALIAS variable stored by udev
+at the 'add' event, and finally, the optional "spa_index" is provided in
+the case where the region is defined by a SPA.
+
+LIBNVDIMM: region::
+
+       struct nd_region *nvdimm_pmem_region_create(struct nvdimm_bus *nvdimm_bus,
+                       struct nd_region_desc *ndr_desc);
+       struct nd_region *nvdimm_blk_region_create(struct nvdimm_bus *nvdimm_bus,
+                       struct nd_region_desc *ndr_desc);
+
+::
+
+       /sys/devices/platform/nfit_test.0/ndbus0
+       |-- region0
+       |   |-- available_size
+       |   |-- btt0
+       |   |-- btt_seed
+       |   |-- devtype
+       |   |-- driver -> ../../../../../bus/nd/drivers/nd_region
+       |   |-- init_namespaces
+       |   |-- mapping0
+       |   |-- mapping1
+       |   |-- mappings
+       |   |-- modalias
+       |   |-- namespace0.0
+       |   |-- namespace_seed
+       |   |-- numa_node
+       |   |-- nfit
+       |   |   `-- spa_index
+       |   |-- nstype
+       |   |-- set_cookie
+       |   |-- size
+       |   |-- subsystem -> ../../../../../bus/nd
+       |   `-- uevent
+       |-- region1
+       [..]
+
+LIBNDCTL: region enumeration example
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Sample region retrieval routines based on NFIT-unique data like
+"spa_index" (interleave set id) for PMEM and "nfit_handle" (dimm id) for
+BLK::
+
+       static struct ndctl_region *get_pmem_region_by_spa_index(struct ndctl_bus *bus,
+                       unsigned int spa_index)
+       {
+               struct ndctl_region *region;
+
+               ndctl_region_foreach(bus, region) {
+                       if (ndctl_region_get_type(region) != ND_DEVICE_REGION_PMEM)
+                               continue;
+                       if (ndctl_region_get_spa_index(region) == spa_index)
+                               return region;
+               }
+               return NULL;
+       }
+
+       static struct ndctl_region *get_blk_region_by_dimm_handle(struct ndctl_bus *bus,
+                       unsigned int handle)
+       {
+               struct ndctl_region *region;
+
+               ndctl_region_foreach(bus, region) {
+                       struct ndctl_mapping *map;
+
+                       if (ndctl_region_get_type(region) != ND_DEVICE_REGION_BLOCK)
+                               continue;
+                       ndctl_mapping_foreach(region, map) {
+                               struct ndctl_dimm *dimm = ndctl_mapping_get_dimm(map);
+
+                               if (ndctl_dimm_get_handle(dimm) == handle)
+                                       return region;
+                       }
+               }
+               return NULL;
+       }
+
+
+Why Not Encode the Region Type into the Region Name?
+----------------------------------------------------
+
+At first glance it seems since NFIT defines just PMEM and BLK interface
+types that we should simply name REGION devices with something derived
+from those type names.  However, the ND subsystem explicitly keeps the
+REGION name generic and expects userspace to always consider the
+region-attributes for four reasons:
+
+    1. There are already more than two REGION and "namespace" types.  For
+       PMEM there are two subtypes.  As mentioned previously we have PMEM where
+       the constituent DIMM devices are known and anonymous PMEM.  For BLK
+       regions the NFIT specification already anticipates vendor specific
+       implementations.  The exact distinction of what a region contains is in
+       the region-attributes not the region-name or the region-devtype.
+
+    2. A region with zero child-namespaces is a possible configuration.  For
+       example, the NFIT allows for a DCR to be published without a
+       corresponding BLK-aperture.  This equates to a DIMM that can only accept
+       control/configuration messages, but no i/o through a descendant block
+       device.  Again, this "type" is advertised in the attributes ('mappings'
+       == 0) and the name does not tell you much.
+
+    3. What if a third major interface type arises in the future?  Outside
+       of vendor specific implementations, it's not difficult to envision a
+       third class of interface type beyond BLK and PMEM.  With a generic name
+       for the REGION level of the device-hierarchy old userspace
+       implementations can still make sense of new kernel advertised
+       region-types.  Userspace can always rely on the generic region
+       attributes like "mappings", "size", etc and the expected child devices
+       named "namespace".  This generic format of the device-model hierarchy
+       allows the LIBNVDIMM and LIBNDCTL implementations to be more uniform and
+       future-proof.
+
+    4. There are more robust mechanisms for determining the major type of a
+       region than a device name.  See the next section, How Do I Determine the
+       Major Type of a Region?
+
+How Do I Determine the Major Type of a Region?
+----------------------------------------------
+
+Outside of the blanket recommendation of "use libndctl", or simply
+looking at the kernel header (/usr/include/linux/ndctl.h) to decode the
+"nstype" integer attribute, here are some other options.
+
+1. module alias lookup
+^^^^^^^^^^^^^^^^^^^^^^
+
+    The whole point of region/namespace device type differentiation is to
+    decide which block-device driver will attach to a given LIBNVDIMM namespace.
+    One can simply use the modalias to lookup the resulting module.  It's
+    important to note that this method is robust in the presence of a
+    vendor-specific driver down the road.  If a vendor-specific
+    implementation wants to supplant the standard nd_blk driver it can with
+    minimal impact to the rest of LIBNVDIMM.
+
+    In fact, a vendor may also want to have a vendor-specific region-driver
+    (outside of nd_region).  For example, if a vendor defined its own LABEL
+    format it would need its own region driver to parse that LABEL and emit
+    the resulting namespaces.  The output from module resolution is more
+    accurate than a region-name or region-devtype.
+
+2. udev
+^^^^^^^
+
+    The kernel "devtype" is registered in the udev database::
+
+       # udevadm info --path=/devices/platform/nfit_test.0/ndbus0/region0
+       P: /devices/platform/nfit_test.0/ndbus0/region0
+       E: DEVPATH=/devices/platform/nfit_test.0/ndbus0/region0
+       E: DEVTYPE=nd_pmem
+       E: MODALIAS=nd:t2
+       E: SUBSYSTEM=nd
+
+       # udevadm info --path=/devices/platform/nfit_test.0/ndbus0/region4
+       P: /devices/platform/nfit_test.0/ndbus0/region4
+       E: DEVPATH=/devices/platform/nfit_test.0/ndbus0/region4
+       E: DEVTYPE=nd_blk
+       E: MODALIAS=nd:t3
+       E: SUBSYSTEM=nd
+
+    ...and is available as a region attribute, but keep in mind that the
+    "devtype" does not indicate sub-type variations and scripts should
+    really be understanding the other attributes.
+
+3. type specific attributes
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+    As it currently stands a BLK-aperture region will never have a
+    "nfit/spa_index" attribute, but neither will a non-NFIT PMEM region.  A
+    BLK region with a "mappings" value of 0 is, as mentioned above, a DIMM
+    that does not allow I/O.  A PMEM region with a "mappings" value of zero
+    is a simple system-physical-address range.
+
+
+LIBNVDIMM/LIBNDCTL: Namespace
+-----------------------------
+
+A REGION, after resolving DPA aliasing and LABEL specified boundaries,
+surfaces one or more "namespace" devices.  The arrival of a "namespace"
+device currently triggers either the nd_blk or nd_pmem driver to load
+and register a disk/block device.
+
+LIBNVDIMM: namespace
+^^^^^^^^^^^^^^^^^^^^
+
+Here is a sample layout from the three major types of NAMESPACE where
+namespace0.0 represents DIMM-info-backed PMEM (note that it has a 'uuid'
+attribute), namespace2.0 represents a BLK namespace (note it has a
+'sector_size' attribute) that, and namespace6.0 represents an anonymous
+PMEM namespace (note that has no 'uuid' attribute due to not support a
+LABEL)::
+
+       /sys/devices/platform/nfit_test.0/ndbus0/region0/namespace0.0
+       |-- alt_name
+       |-- devtype
+       |-- dpa_extents
+       |-- force_raw
+       |-- modalias
+       |-- numa_node
+       |-- resource
+       |-- size
+       |-- subsystem -> ../../../../../../bus/nd
+       |-- type
+       |-- uevent
+       `-- uuid
+       /sys/devices/platform/nfit_test.0/ndbus0/region2/namespace2.0
+       |-- alt_name
+       |-- devtype
+       |-- dpa_extents
+       |-- force_raw
+       |-- modalias
+       |-- numa_node
+       |-- sector_size
+       |-- size
+       |-- subsystem -> ../../../../../../bus/nd
+       |-- type
+       |-- uevent
+       `-- uuid
+       /sys/devices/platform/nfit_test.1/ndbus1/region6/namespace6.0
+       |-- block
+       |   `-- pmem0
+       |-- devtype
+       |-- driver -> ../../../../../../bus/nd/drivers/pmem
+       |-- force_raw
+       |-- modalias
+       |-- numa_node
+       |-- resource
+       |-- size
+       |-- subsystem -> ../../../../../../bus/nd
+       |-- type
+       `-- uevent
+
+LIBNDCTL: namespace enumeration example
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Namespaces are indexed relative to their parent region, example below.
+These indexes are mostly static from boot to boot, but subsystem makes
+no guarantees in this regard.  For a static namespace identifier use its
+'uuid' attribute.
+
+::
+
+  static struct ndctl_namespace
+  *get_namespace_by_id(struct ndctl_region *region, unsigned int id)
+  {
+          struct ndctl_namespace *ndns;
+
+          ndctl_namespace_foreach(region, ndns)
+                  if (ndctl_namespace_get_id(ndns) == id)
+                          return ndns;
+
+          return NULL;
+  }
+
+LIBNDCTL: namespace creation example
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Idle namespaces are automatically created by the kernel if a given
+region has enough available capacity to create a new namespace.
+Namespace instantiation involves finding an idle namespace and
+configuring it.  For the most part the setting of namespace attributes
+can occur in any order, the only constraint is that 'uuid' must be set
+before 'size'.  This enables the kernel to track DPA allocations
+internally with a static identifier::
+
+  static int configure_namespace(struct ndctl_region *region,
+                  struct ndctl_namespace *ndns,
+                  struct namespace_parameters *parameters)
+  {
+          char devname[50];
+
+          snprintf(devname, sizeof(devname), "namespace%d.%d",
+                          ndctl_region_get_id(region), paramaters->id);
+
+          ndctl_namespace_set_alt_name(ndns, devname);
+          /* 'uuid' must be set prior to setting size! */
+          ndctl_namespace_set_uuid(ndns, paramaters->uuid);
+          ndctl_namespace_set_size(ndns, paramaters->size);
+          /* unlike pmem namespaces, blk namespaces have a sector size */
+          if (parameters->lbasize)
+                  ndctl_namespace_set_sector_size(ndns, parameters->lbasize);
+          ndctl_namespace_enable(ndns);
+  }
+
+
+Why the Term "namespace"?
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+    1. Why not "volume" for instance?  "volume" ran the risk of confusing
+       ND (libnvdimm subsystem) to a volume manager like device-mapper.
+
+    2. The term originated to describe the sub-devices that can be created
+       within a NVME controller (see the nvme specification:
+       http://www.nvmexpress.org/specifications/), and NFIT namespaces are
+       meant to parallel the capabilities and configurability of
+       NVME-namespaces.
+
+
+LIBNVDIMM/LIBNDCTL: Block Translation Table "btt"
+-------------------------------------------------
+
+A BTT (design document: http://pmem.io/2014/09/23/btt.html) is a stacked
+block device driver that fronts either the whole block device or a
+partition of a block device emitted by either a PMEM or BLK NAMESPACE.
+
+LIBNVDIMM: btt layout
+^^^^^^^^^^^^^^^^^^^^^
+
+Every region will start out with at least one BTT device which is the
+seed device.  To activate it set the "namespace", "uuid", and
+"sector_size" attributes and then bind the device to the nd_pmem or
+nd_blk driver depending on the region type::
+
+       /sys/devices/platform/nfit_test.1/ndbus0/region0/btt0/
+       |-- namespace
+       |-- delete
+       |-- devtype
+       |-- modalias
+       |-- numa_node
+       |-- sector_size
+       |-- subsystem -> ../../../../../bus/nd
+       |-- uevent
+       `-- uuid
+
+LIBNDCTL: btt creation example
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Similar to namespaces an idle BTT device is automatically created per
+region.  Each time this "seed" btt device is configured and enabled a new
+seed is created.  Creating a BTT configuration involves two steps of
+finding and idle BTT and assigning it to consume a PMEM or BLK namespace::
+
+       static struct ndctl_btt *get_idle_btt(struct ndctl_region *region)
+       {
+               struct ndctl_btt *btt;
+
+               ndctl_btt_foreach(region, btt)
+                       if (!ndctl_btt_is_enabled(btt)
+                                       && !ndctl_btt_is_configured(btt))
+                               return btt;
+
+               return NULL;
+       }
+
+       static int configure_btt(struct ndctl_region *region,
+                       struct btt_parameters *parameters)
+       {
+               btt = get_idle_btt(region);
+
+               ndctl_btt_set_uuid(btt, parameters->uuid);
+               ndctl_btt_set_sector_size(btt, parameters->sector_size);
+               ndctl_btt_set_namespace(btt, parameters->ndns);
+               /* turn off raw mode device */
+               ndctl_namespace_disable(parameters->ndns);
+               /* turn on btt access */
+               ndctl_btt_enable(btt);
+       }
+
+Once instantiated a new inactive btt seed device will appear underneath
+the region.
+
+Once a "namespace" is removed from a BTT that instance of the BTT device
+will be deleted or otherwise reset to default values.  This deletion is
+only at the device model level.  In order to destroy a BTT the "info
+block" needs to be destroyed.  Note, that to destroy a BTT the media
+needs to be written in raw mode.  By default, the kernel will autodetect
+the presence of a BTT and disable raw mode.  This autodetect behavior
+can be suppressed by enabling raw mode for the namespace via the
+ndctl_namespace_set_raw_mode() API.
+
+
+Summary LIBNDCTL Diagram
+------------------------
+
+For the given example above, here is the view of the objects as seen by the
+LIBNDCTL API::
+
+              +---+
+              |CTX|    +---------+   +--------------+  +---------------+
+              +-+-+  +-> REGION0 +---> NAMESPACE0.0 +--> PMEM8 "pm0.0" |
+                |    | +---------+   +--------------+  +---------------+
+  +-------+     |    | +---------+   +--------------+  +---------------+
+  | DIMM0 <-+   |    +-> REGION1 +---> NAMESPACE1.0 +--> PMEM6 "pm1.0" |
+  +-------+ |   |    | +---------+   +--------------+  +---------------+
+  | DIMM1 <-+ +-v--+ | +---------+   +--------------+  +---------------+
+  +-------+ +-+BUS0+---> REGION2 +-+-> NAMESPACE2.0 +--> ND6  "blk2.0" |
+  | DIMM2 <-+ +----+ | +---------+ | +--------------+  +----------------------+
+  +-------+ |        |             +-> NAMESPACE2.1 +--> ND5  "blk2.1" | BTT2 |
+  | DIMM3 <-+        |               +--------------+  +----------------------+
+  +-------+          | +---------+   +--------------+  +---------------+
+                     +-> REGION3 +-+-> NAMESPACE3.0 +--> ND4  "blk3.0" |
+                     | +---------+ | +--------------+  +----------------------+
+                     |             +-> NAMESPACE3.1 +--> ND3  "blk3.1" | BTT1 |
+                     |               +--------------+  +----------------------+
+                     | +---------+   +--------------+  +---------------+
+                     +-> REGION4 +---> NAMESPACE4.0 +--> ND2  "blk4.0" |
+                     | +---------+   +--------------+  +---------------+
+                     | +---------+   +--------------+  +----------------------+
+                     +-> REGION5 +---> NAMESPACE5.0 +--> ND1  "blk5.0" | BTT0 |
+                       +---------+   +--------------+  +---------------+------+
diff --git a/Documentation/driver-api/nvdimm/security.rst b/Documentation/driver-api/nvdimm/security.rst
new file mode 100644 (file)
index 0000000..ad9dea0
--- /dev/null
@@ -0,0 +1,143 @@
+===============
+NVDIMM Security
+===============
+
+1. Introduction
+---------------
+
+With the introduction of Intel Device Specific Methods (DSM) v1.8
+specification [1], security DSMs are introduced. The spec added the following
+security DSMs: "get security state", "set passphrase", "disable passphrase",
+"unlock unit", "freeze lock", "secure erase", and "overwrite". A security_ops
+data structure has been added to struct dimm in order to support the security
+operations and generic APIs are exposed to allow vendor neutral operations.
+
+2. Sysfs Interface
+------------------
+The "security" sysfs attribute is provided in the nvdimm sysfs directory. For
+example:
+/sys/devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/nmem0/security
+
+The "show" attribute of that attribute will display the security state for
+that DIMM. The following states are available: disabled, unlocked, locked,
+frozen, and overwrite. If security is not supported, the sysfs attribute
+will not be visible.
+
+The "store" attribute takes several commands when it is being written to
+in order to support some of the security functionalities:
+update <old_keyid> <new_keyid> - enable or update passphrase.
+disable <keyid> - disable enabled security and remove key.
+freeze - freeze changing of security states.
+erase <keyid> - delete existing user encryption key.
+overwrite <keyid> - wipe the entire nvdimm.
+master_update <keyid> <new_keyid> - enable or update master passphrase.
+master_erase <keyid> - delete existing user encryption key.
+
+3. Key Management
+-----------------
+
+The key is associated to the payload by the DIMM id. For example:
+# cat /sys/devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/nmem0/nfit/id
+8089-a2-1740-00000133
+The DIMM id would be provided along with the key payload (passphrase) to
+the kernel.
+
+The security keys are managed on the basis of a single key per DIMM. The
+key "passphrase" is expected to be 32bytes long. This is similar to the ATA
+security specification [2]. A key is initially acquired via the request_key()
+kernel API call during nvdimm unlock. It is up to the user to make sure that
+all the keys are in the kernel user keyring for unlock.
+
+A nvdimm encrypted-key of format enc32 has the description format of:
+nvdimm:<bus-provider-specific-unique-id>
+
+See file ``Documentation/security/keys/trusted-encrypted.rst`` for creating
+encrypted-keys of enc32 format. TPM usage with a master trusted key is
+preferred for sealing the encrypted-keys.
+
+4. Unlocking
+------------
+When the DIMMs are being enumerated by the kernel, the kernel will attempt to
+retrieve the key from the kernel user keyring. This is the only time
+a locked DIMM can be unlocked. Once unlocked, the DIMM will remain unlocked
+until reboot. Typically an entity (i.e. shell script) will inject all the
+relevant encrypted-keys into the kernel user keyring during the initramfs phase.
+This provides the unlock function access to all the related keys that contain
+the passphrase for the respective nvdimms.  It is also recommended that the
+keys are injected before libnvdimm is loaded by modprobe.
+
+5. Update
+---------
+When doing an update, it is expected that the existing key is removed from
+the kernel user keyring and reinjected as different (old) key. It's irrelevant
+what the key description is for the old key since we are only interested in the
+keyid when doing the update operation. It is also expected that the new key
+is injected with the description format described from earlier in this
+document.  The update command written to the sysfs attribute will be with
+the format:
+update <old keyid> <new keyid>
+
+If there is no old keyid due to a security enabling, then a 0 should be
+passed in.
+
+6. Freeze
+---------
+The freeze operation does not require any keys. The security config can be
+frozen by a user with root privelege.
+
+7. Disable
+----------
+The security disable command format is:
+disable <keyid>
+
+An key with the current passphrase payload that is tied to the nvdimm should be
+in the kernel user keyring.
+
+8. Secure Erase
+---------------
+The command format for doing a secure erase is:
+erase <keyid>
+
+An key with the current passphrase payload that is tied to the nvdimm should be
+in the kernel user keyring.
+
+9. Overwrite
+------------
+The command format for doing an overwrite is:
+overwrite <keyid>
+
+Overwrite can be done without a key if security is not enabled. A key serial
+of 0 can be passed in to indicate no key.
+
+The sysfs attribute "security" can be polled to wait on overwrite completion.
+Overwrite can last tens of minutes or more depending on nvdimm size.
+
+An encrypted-key with the current user passphrase that is tied to the nvdimm
+should be injected and its keyid should be passed in via sysfs.
+
+10. Master Update
+-----------------
+The command format for doing a master update is:
+update <old keyid> <new keyid>
+
+The operating mechanism for master update is identical to update except the
+master passphrase key is passed to the kernel. The master passphrase key
+is just another encrypted-key.
+
+This command is only available when security is disabled.
+
+11. Master Erase
+----------------
+The command format for doing a master erase is:
+master_erase <current keyid>
+
+This command has the same operating mechanism as erase except the master
+passphrase key is passed to the kernel. The master passphrase key is just
+another encrypted-key.
+
+This command is only available when the master security is enabled, indicated
+by the extended security status.
+
+[1]: http://pmem.io/documents/NVDIMM_DSM_Interface-V1.8.pdf
+
+[2]: http://www.t13.org/documents/UploadedDocuments/docs2006/e05179r4-ACS-SecurityClarifications.pdf
diff --git a/Documentation/driver-api/nvmem.rst b/Documentation/driver-api/nvmem.rst
new file mode 100644 (file)
index 0000000..d9d958d
--- /dev/null
@@ -0,0 +1,189 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===============
+NVMEM Subsystem
+===============
+
+ Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+This document explains the NVMEM Framework along with the APIs provided,
+and how to use it.
+
+1. Introduction
+===============
+*NVMEM* is the abbreviation for Non Volatile Memory layer. It is used to
+retrieve configuration of SOC or Device specific data from non volatile
+memories like eeprom, efuses and so on.
+
+Before this framework existed, NVMEM drivers like eeprom were stored in
+drivers/misc, where they all had to duplicate pretty much the same code to
+register a sysfs file, allow in-kernel users to access the content of the
+devices they were driving, etc.
+
+This was also a problem as far as other in-kernel users were involved, since
+the solutions used were pretty much different from one driver to another, there
+was a rather big abstraction leak.
+
+This framework aims at solve these problems. It also introduces DT
+representation for consumer devices to go get the data they require (MAC
+Addresses, SoC/Revision ID, part numbers, and so on) from the NVMEMs. This
+framework is based on regmap, so that most of the abstraction available in
+regmap can be reused, across multiple types of buses.
+
+NVMEM Providers
++++++++++++++++
+
+NVMEM provider refers to an entity that implements methods to initialize, read
+and write the non-volatile memory.
+
+2. Registering/Unregistering the NVMEM provider
+===============================================
+
+A NVMEM provider can register with NVMEM core by supplying relevant
+nvmem configuration to nvmem_register(), on success core would return a valid
+nvmem_device pointer.
+
+nvmem_unregister(nvmem) is used to unregister a previously registered provider.
+
+For example, a simple qfprom case::
+
+  static struct nvmem_config econfig = {
+       .name = "qfprom",
+       .owner = THIS_MODULE,
+  };
+
+  static int qfprom_probe(struct platform_device *pdev)
+  {
+       ...
+       econfig.dev = &pdev->dev;
+       nvmem = nvmem_register(&econfig);
+       ...
+  }
+
+It is mandatory that the NVMEM provider has a regmap associated with its
+struct device. Failure to do would return error code from nvmem_register().
+
+Users of board files can define and register nvmem cells using the
+nvmem_cell_table struct::
+
+  static struct nvmem_cell_info foo_nvmem_cells[] = {
+       {
+               .name           = "macaddr",
+               .offset         = 0x7f00,
+               .bytes          = ETH_ALEN,
+       }
+  };
+
+  static struct nvmem_cell_table foo_nvmem_cell_table = {
+       .nvmem_name             = "i2c-eeprom",
+       .cells                  = foo_nvmem_cells,
+       .ncells                 = ARRAY_SIZE(foo_nvmem_cells),
+  };
+
+  nvmem_add_cell_table(&foo_nvmem_cell_table);
+
+Additionally it is possible to create nvmem cell lookup entries and register
+them with the nvmem framework from machine code as shown in the example below::
+
+  static struct nvmem_cell_lookup foo_nvmem_lookup = {
+       .nvmem_name             = "i2c-eeprom",
+       .cell_name              = "macaddr",
+       .dev_id                 = "foo_mac.0",
+       .con_id                 = "mac-address",
+  };
+
+  nvmem_add_cell_lookups(&foo_nvmem_lookup, 1);
+
+NVMEM Consumers
++++++++++++++++
+
+NVMEM consumers are the entities which make use of the NVMEM provider to
+read from and to NVMEM.
+
+3. NVMEM cell based consumer APIs
+=================================
+
+NVMEM cells are the data entries/fields in the NVMEM.
+The NVMEM framework provides 3 APIs to read/write NVMEM cells::
+
+  struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *name);
+  struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *name);
+
+  void nvmem_cell_put(struct nvmem_cell *cell);
+  void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell);
+
+  void *nvmem_cell_read(struct nvmem_cell *cell, ssize_t *len);
+  int nvmem_cell_write(struct nvmem_cell *cell, void *buf, ssize_t len);
+
+`*nvmem_cell_get()` apis will get a reference to nvmem cell for a given id,
+and nvmem_cell_read/write() can then read or write to the cell.
+Once the usage of the cell is finished the consumer should call
+`*nvmem_cell_put()` to free all the allocation memory for the cell.
+
+4. Direct NVMEM device based consumer APIs
+==========================================
+
+In some instances it is necessary to directly read/write the NVMEM.
+To facilitate such consumers NVMEM framework provides below apis::
+
+  struct nvmem_device *nvmem_device_get(struct device *dev, const char *name);
+  struct nvmem_device *devm_nvmem_device_get(struct device *dev,
+                                          const char *name);
+  void nvmem_device_put(struct nvmem_device *nvmem);
+  int nvmem_device_read(struct nvmem_device *nvmem, unsigned int offset,
+                     size_t bytes, void *buf);
+  int nvmem_device_write(struct nvmem_device *nvmem, unsigned int offset,
+                      size_t bytes, void *buf);
+  int nvmem_device_cell_read(struct nvmem_device *nvmem,
+                          struct nvmem_cell_info *info, void *buf);
+  int nvmem_device_cell_write(struct nvmem_device *nvmem,
+                           struct nvmem_cell_info *info, void *buf);
+
+Before the consumers can read/write NVMEM directly, it should get hold
+of nvmem_controller from one of the `*nvmem_device_get()` api.
+
+The difference between these apis and cell based apis is that these apis always
+take nvmem_device as parameter.
+
+5. Releasing a reference to the NVMEM
+=====================================
+
+When a consumer no longer needs the NVMEM, it has to release the reference
+to the NVMEM it has obtained using the APIs mentioned in the above section.
+The NVMEM framework provides 2 APIs to release a reference to the NVMEM::
+
+  void nvmem_cell_put(struct nvmem_cell *cell);
+  void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell);
+  void nvmem_device_put(struct nvmem_device *nvmem);
+  void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem);
+
+Both these APIs are used to release a reference to the NVMEM and
+devm_nvmem_cell_put and devm_nvmem_device_put destroys the devres associated
+with this NVMEM.
+
+Userspace
++++++++++
+
+6. Userspace binary interface
+==============================
+
+Userspace can read/write the raw NVMEM file located at::
+
+       /sys/bus/nvmem/devices/*/nvmem
+
+ex::
+
+  hexdump /sys/bus/nvmem/devices/qfprom0/nvmem
+
+  0000000 0000 0000 0000 0000 0000 0000 0000 0000
+  *
+  00000a0 db10 2240 0000 e000 0c00 0c00 0000 0c00
+  0000000 0000 0000 0000 0000 0000 0000 0000 0000
+  ...
+  *
+  0001000
+
+7. DeviceTree Binding
+=====================
+
+See Documentation/devicetree/bindings/nvmem/nvmem.txt
diff --git a/Documentation/driver-api/phy/index.rst b/Documentation/driver-api/phy/index.rst
new file mode 100644 (file)
index 0000000..69ba121
--- /dev/null
@@ -0,0 +1,18 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=====================
+Generic PHY Framework
+=====================
+
+.. toctree::
+
+   phy
+   samsung-usb2
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
+
diff --git a/Documentation/driver-api/phy/samsung-usb2.rst b/Documentation/driver-api/phy/samsung-usb2.rst
new file mode 100644 (file)
index 0000000..c48c8b9
--- /dev/null
@@ -0,0 +1,137 @@
+====================================
+Samsung USB 2.0 PHY adaptation layer
+====================================
+
+1. Description
+--------------
+
+The architecture of the USB 2.0 PHY module in Samsung SoCs is similar
+among many SoCs. In spite of the similarities it proved difficult to
+create a one driver that would fit all these PHY controllers. Often
+the differences were minor and were found in particular bits of the
+registers of the PHY. In some rare cases the order of register writes or
+the PHY powering up process had to be altered. This adaptation layer is
+a compromise between having separate drivers and having a single driver
+with added support for many special cases.
+
+2. Files description
+--------------------
+
+- phy-samsung-usb2.c
+   This is the main file of the adaptation layer. This file contains
+   the probe function and provides two callbacks to the Generic PHY
+   Framework. This two callbacks are used to power on and power off the
+   phy. They carry out the common work that has to be done on all version
+   of the PHY module. Depending on which SoC was chosen they execute SoC
+   specific callbacks. The specific SoC version is selected by choosing
+   the appropriate compatible string. In addition, this file contains
+   struct of_device_id definitions for particular SoCs.
+
+- phy-samsung-usb2.h
+   This is the include file. It declares the structures used by this
+   driver. In addition it should contain extern declarations for
+   structures that describe particular SoCs.
+
+3. Supporting SoCs
+------------------
+
+To support a new SoC a new file should be added to the drivers/phy
+directory. Each SoC's configuration is stored in an instance of the
+struct samsung_usb2_phy_config::
+
+  struct samsung_usb2_phy_config {
+       const struct samsung_usb2_common_phy *phys;
+       int (*rate_to_clk)(unsigned long, u32 *);
+       unsigned int num_phys;
+       bool has_mode_switch;
+  };
+
+The num_phys is the number of phys handled by the driver. `*phys` is an
+array that contains the configuration for each phy. The has_mode_switch
+property is a boolean flag that determines whether the SoC has USB host
+and device on a single pair of pins. If so, a special register has to
+be modified to change the internal routing of these pins between a USB
+device or host module.
+
+For example the configuration for Exynos 4210 is following::
+
+  const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
+       .has_mode_switch        = 0,
+       .num_phys               = EXYNOS4210_NUM_PHYS,
+       .phys                   = exynos4210_phys,
+       .rate_to_clk            = exynos4210_rate_to_clk,
+  }
+
+- `int (*rate_to_clk)(unsigned long, u32 *)`
+
+       The rate_to_clk callback is to convert the rate of the clock
+       used as the reference clock for the PHY module to the value
+       that should be written in the hardware register.
+
+The exynos4210_phys configuration array is as follows::
+
+  static const struct samsung_usb2_common_phy exynos4210_phys[] = {
+       {
+               .label          = "device",
+               .id             = EXYNOS4210_DEVICE,
+               .power_on       = exynos4210_power_on,
+               .power_off      = exynos4210_power_off,
+       },
+       {
+               .label          = "host",
+               .id             = EXYNOS4210_HOST,
+               .power_on       = exynos4210_power_on,
+               .power_off      = exynos4210_power_off,
+       },
+       {
+               .label          = "hsic0",
+               .id             = EXYNOS4210_HSIC0,
+               .power_on       = exynos4210_power_on,
+               .power_off      = exynos4210_power_off,
+       },
+       {
+               .label          = "hsic1",
+               .id             = EXYNOS4210_HSIC1,
+               .power_on       = exynos4210_power_on,
+               .power_off      = exynos4210_power_off,
+       },
+       {},
+  };
+
+- `int (*power_on)(struct samsung_usb2_phy_instance *);`
+  `int (*power_off)(struct samsung_usb2_phy_instance *);`
+
+       These two callbacks are used to power on and power off the phy
+       by modifying appropriate registers.
+
+Final change to the driver is adding appropriate compatible value to the
+phy-samsung-usb2.c file. In case of Exynos 4210 the following lines were
+added to the struct of_device_id samsung_usb2_phy_of_match[] array::
+
+  #ifdef CONFIG_PHY_EXYNOS4210_USB2
+       {
+               .compatible = "samsung,exynos4210-usb2-phy",
+               .data = &exynos4210_usb2_phy_config,
+       },
+  #endif
+
+To add further flexibility to the driver the Kconfig file enables to
+include support for selected SoCs in the compiled driver. The Kconfig
+entry for Exynos 4210 is following::
+
+  config PHY_EXYNOS4210_USB2
+       bool "Support for Exynos 4210"
+       depends on PHY_SAMSUNG_USB2
+       depends on CPU_EXYNOS4210
+       help
+         Enable USB PHY support for Exynos 4210. This option requires that
+         Samsung USB 2.0 PHY driver is enabled and means that support for this
+         particular SoC is compiled in the driver. In case of Exynos 4210 four
+         phys are available - device, host, HSCI0 and HSCI1.
+
+The newly created file that supports the new SoC has to be also added to the
+Makefile. In case of Exynos 4210 the added line is following::
+
+  obj-$(CONFIG_PHY_EXYNOS4210_USB2)       += phy-exynos4210-usb2.o
+
+After completing these steps the support for the new SoC should be ready.
index 1456d2c..2d6b997 100644 (file)
@@ -1,4 +1,4 @@
-:orphan:
+.. SPDX-License-Identifier: GPL-2.0
 
 ======================
 PPS - Pulse Per Second
diff --git a/Documentation/driver-api/pti_intel_mid.rst b/Documentation/driver-api/pti_intel_mid.rst
new file mode 100644 (file)
index 0000000..20f1cff
--- /dev/null
@@ -0,0 +1,106 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=============
+Intel MID PTI
+=============
+
+The Intel MID PTI project is HW implemented in Intel Atom
+system-on-a-chip designs based on the Parallel Trace
+Interface for MIPI P1149.7 cJTAG standard.  The kernel solution
+for this platform involves the following files::
+
+       ./include/linux/pti.h
+       ./drivers/.../n_tracesink.h
+       ./drivers/.../n_tracerouter.c
+       ./drivers/.../n_tracesink.c
+       ./drivers/.../pti.c
+
+pti.c is the driver that enables various debugging features
+popular on platforms from certain mobile manufacturers.
+n_tracerouter.c and n_tracesink.c allow extra system information to
+be collected and routed to the pti driver, such as trace
+debugging data from a modem.  Although n_tracerouter
+and n_tracesink are a part of the complete PTI solution,
+these two line disciplines can work separately from
+pti.c and route any data stream from one /dev/tty node
+to another /dev/tty node via kernel-space.  This provides
+a stable, reliable connection that will not break unless
+the user-space application shuts down (plus avoids
+kernel->user->kernel context switch overheads of routing
+data).
+
+An example debugging usage for this driver system:
+
+  * Hook /dev/ttyPTI0 to syslogd.  Opening this port will also start
+    a console device to further capture debugging messages to PTI.
+  * Hook /dev/ttyPTI1 to modem debugging data to write to PTI HW.
+    This is where n_tracerouter and n_tracesink are used.
+  * Hook /dev/pti to a user-level debugging application for writing
+    to PTI HW.
+  * `Use mipi_` Kernel Driver API in other device drivers for
+    debugging to PTI by first requesting a PTI write address via
+    mipi_request_masterchannel(1).
+
+Below is example pseudo-code on how a 'privileged' application
+can hook up n_tracerouter and n_tracesink to any tty on
+a system.  'Privileged' means the application has enough
+privileges to successfully manipulate the ldisc drivers
+but is not just blindly executing as 'root'. Keep in mind
+the use of ioctl(,TIOCSETD,) is not specific to the n_tracerouter
+and n_tracesink line discpline drivers but is a generic
+operation for a program to use a line discpline driver
+on a tty port other than the default n_tty::
+
+  /////////// To hook up n_tracerouter and n_tracesink /////////
+
+  // Note that n_tracerouter depends on n_tracesink.
+  #include <errno.h>
+  #define ONE_TTY "/dev/ttyOne"
+  #define TWO_TTY "/dev/ttyTwo"
+
+  // needed global to hand onto ldisc connection
+  static int g_fd_source = -1;
+  static int g_fd_sink  = -1;
+
+  // these two vars used to grab LDISC values from loaded ldisc drivers
+  // in OS.  Look at /proc/tty/ldiscs to get the right numbers from
+  // the ldiscs loaded in the system.
+  int source_ldisc_num, sink_ldisc_num = -1;
+  int retval;
+
+  g_fd_source = open(ONE_TTY, O_RDWR); // must be R/W
+  g_fd_sink   = open(TWO_TTY, O_RDWR); // must be R/W
+
+  if (g_fd_source <= 0) || (g_fd_sink <= 0) {
+     // doubt you'll want to use these exact error lines of code
+     printf("Error on open(). errno: %d\n",errno);
+     return errno;
+  }
+
+  retval = ioctl(g_fd_sink, TIOCSETD, &sink_ldisc_num);
+  if (retval < 0) {
+     printf("Error on ioctl().  errno: %d\n", errno);
+     return errno;
+  }
+
+  retval = ioctl(g_fd_source, TIOCSETD, &source_ldisc_num);
+  if (retval < 0) {
+     printf("Error on ioctl().  errno: %d\n", errno);
+     return errno;
+  }
+
+  /////////// To disconnect n_tracerouter and n_tracesink ////////
+
+  // First make sure data through the ldiscs has stopped.
+
+  // Second, disconnect ldiscs.  This provides a
+  // little cleaner shutdown on tty stack.
+  sink_ldisc_num = 0;
+  source_ldisc_num = 0;
+  ioctl(g_fd_uart, TIOCSETD, &sink_ldisc_num);
+  ioctl(g_fd_gadget, TIOCSETD, &source_ldisc_num);
+
+  // Three, program closes connection, and cleanup:
+  close(g_fd_uart);
+  close(g_fd_gadget);
+  g_fd_uart = g_fd_gadget = NULL;
index b6e65d6..a15192e 100644 (file)
@@ -1,4 +1,4 @@
-:orphan:
+.. SPDX-License-Identifier: GPL-2.0
 
 ===========================================
 PTP hardware clock infrastructure for Linux
diff --git a/Documentation/driver-api/rapidio/index.rst b/Documentation/driver-api/rapidio/index.rst
new file mode 100644 (file)
index 0000000..a41b424
--- /dev/null
@@ -0,0 +1,15 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===========================
+The Linux RapidIO Subsystem
+===========================
+
+.. toctree::
+   :maxdepth: 1
+
+   rapidio
+   sysfs
+
+   tsi721
+   mport_cdev
+   rio_cm
diff --git a/Documentation/driver-api/rapidio/mport_cdev.rst b/Documentation/driver-api/rapidio/mport_cdev.rst
new file mode 100644 (file)
index 0000000..df77a7f
--- /dev/null
@@ -0,0 +1,110 @@
+==================================================================
+RapidIO subsystem mport character device driver (rio_mport_cdev.c)
+==================================================================
+
+1. Overview
+===========
+
+This device driver is the result of collaboration within the RapidIO.org
+Software Task Group (STG) between Texas Instruments, Freescale,
+Prodrive Technologies, Nokia Networks, BAE and IDT.  Additional input was
+received from other members of RapidIO.org. The objective was to create a
+character mode driver interface which exposes the capabilities of RapidIO
+devices directly to applications, in a manner that allows the numerous and
+varied RapidIO implementations to interoperate.
+
+This driver (MPORT_CDEV) provides access to basic RapidIO subsystem operations
+for user-space applications. Most of RapidIO operations are supported through
+'ioctl' system calls.
+
+When loaded this device driver creates filesystem nodes named rio_mportX in /dev
+directory for each registered RapidIO mport device. 'X' in the node name matches
+to unique port ID assigned to each local mport device.
+
+Using available set of ioctl commands user-space applications can perform
+following RapidIO bus and subsystem operations:
+
+- Reads and writes from/to configuration registers of mport devices
+  (RIO_MPORT_MAINT_READ_LOCAL/RIO_MPORT_MAINT_WRITE_LOCAL)
+- Reads and writes from/to configuration registers of remote RapidIO devices.
+  This operations are defined as RapidIO Maintenance reads/writes in RIO spec.
+  (RIO_MPORT_MAINT_READ_REMOTE/RIO_MPORT_MAINT_WRITE_REMOTE)
+- Set RapidIO Destination ID for mport devices (RIO_MPORT_MAINT_HDID_SET)
+- Set RapidIO Component Tag for mport devices (RIO_MPORT_MAINT_COMPTAG_SET)
+- Query logical index of mport devices (RIO_MPORT_MAINT_PORT_IDX_GET)
+- Query capabilities and RapidIO link configuration of mport devices
+  (RIO_MPORT_GET_PROPERTIES)
+- Enable/Disable reporting of RapidIO doorbell events to user-space applications
+  (RIO_ENABLE_DOORBELL_RANGE/RIO_DISABLE_DOORBELL_RANGE)
+- Enable/Disable reporting of RIO port-write events to user-space applications
+  (RIO_ENABLE_PORTWRITE_RANGE/RIO_DISABLE_PORTWRITE_RANGE)
+- Query/Control type of events reported through this driver: doorbells,
+  port-writes or both (RIO_SET_EVENT_MASK/RIO_GET_EVENT_MASK)
+- Configure/Map mport's outbound requests window(s) for specific size,
+  RapidIO destination ID, hopcount and request type
+  (RIO_MAP_OUTBOUND/RIO_UNMAP_OUTBOUND)
+- Configure/Map mport's inbound requests window(s) for specific size,
+  RapidIO base address and local memory base address
+  (RIO_MAP_INBOUND/RIO_UNMAP_INBOUND)
+- Allocate/Free contiguous DMA coherent memory buffer for DMA data transfers
+  to/from remote RapidIO devices (RIO_ALLOC_DMA/RIO_FREE_DMA)
+- Initiate DMA data transfers to/from remote RapidIO devices (RIO_TRANSFER).
+  Supports blocking, asynchronous and posted (a.k.a 'fire-and-forget') data
+  transfer modes.
+- Check/Wait for completion of asynchronous DMA data transfer
+  (RIO_WAIT_FOR_ASYNC)
+- Manage device objects supported by RapidIO subsystem (RIO_DEV_ADD/RIO_DEV_DEL).
+  This allows implementation of various RapidIO fabric enumeration algorithms
+  as user-space applications while using remaining functionality provided by
+  kernel RapidIO subsystem.
+
+2. Hardware Compatibility
+=========================
+
+This device driver uses standard interfaces defined by kernel RapidIO subsystem
+and therefore it can be used with any mport device driver registered by RapidIO
+subsystem with limitations set by available mport implementation.
+
+At this moment the most common limitation is availability of RapidIO-specific
+DMA engine framework for specific mport device. Users should verify available
+functionality of their platform when planning to use this driver:
+
+- IDT Tsi721 PCIe-to-RapidIO bridge device and its mport device driver are fully
+  compatible with this driver.
+- Freescale SoCs 'fsl_rio' mport driver does not have implementation for RapidIO
+  specific DMA engine support and therefore DMA data transfers mport_cdev driver
+  are not available.
+
+3. Module parameters
+====================
+
+- 'dma_timeout'
+      - DMA transfer completion timeout (in msec, default value 3000).
+        This parameter set a maximum completion wait time for SYNC mode DMA
+        transfer requests and for RIO_WAIT_FOR_ASYNC ioctl requests.
+
+- 'dbg_level'
+      - This parameter allows to control amount of debug information
+        generated by this device driver. This parameter is formed by set of
+        bit masks that correspond to the specific functional blocks.
+        For mask definitions see 'drivers/rapidio/devices/rio_mport_cdev.c'
+        This parameter can be changed dynamically.
+        Use CONFIG_RAPIDIO_DEBUG=y to enable debug output at the top level.
+
+4. Known problems
+=================
+
+  None.
+
+5. User-space Applications and API
+==================================
+
+API library and applications that use this device driver are available from
+RapidIO.org.
+
+6. TODO List
+============
+
+- Add support for sending/receiving "raw" RapidIO messaging packets.
+- Add memory mapped DMA data transfers as an option when RapidIO-specific DMA
+  is not available.
diff --git a/Documentation/driver-api/rapidio/rapidio.rst b/Documentation/driver-api/rapidio/rapidio.rst
new file mode 100644 (file)
index 0000000..fb8942d
--- /dev/null
@@ -0,0 +1,362 @@
+============
+Introduction
+============
+
+The RapidIO standard is a packet-based fabric interconnect standard designed for
+use in embedded systems. Development of the RapidIO standard is directed by the
+RapidIO Trade Association (RTA). The current version of the RapidIO specification
+is publicly available for download from the RTA web-site [1].
+
+This document describes the basics of the Linux RapidIO subsystem and provides
+information on its major components.
+
+1 Overview
+==========
+
+Because the RapidIO subsystem follows the Linux device model it is integrated
+into the kernel similarly to other buses by defining RapidIO-specific device and
+bus types and registering them within the device model.
+
+The Linux RapidIO subsystem is architecture independent and therefore defines
+architecture-specific interfaces that provide support for common RapidIO
+subsystem operations.
+
+2. Core Components
+==================
+
+A typical RapidIO network is a combination of endpoints and switches.
+Each of these components is represented in the subsystem by an associated data
+structure. The core logical components of the RapidIO subsystem are defined
+in include/linux/rio.h file.
+
+2.1 Master Port
+---------------
+
+A master port (or mport) is a RapidIO interface controller that is local to the
+processor executing the Linux code. A master port generates and receives RapidIO
+packets (transactions). In the RapidIO subsystem each master port is represented
+by a rio_mport data structure. This structure contains master port specific
+resources such as mailboxes and doorbells. The rio_mport also includes a unique
+host device ID that is valid when a master port is configured as an enumerating
+host.
+
+RapidIO master ports are serviced by subsystem specific mport device drivers
+that provide functionality defined for this subsystem. To provide a hardware
+independent interface for RapidIO subsystem operations, rio_mport structure
+includes rio_ops data structure which contains pointers to hardware specific
+implementations of RapidIO functions.
+
+2.2 Device
+----------
+
+A RapidIO device is any endpoint (other than mport) or switch in the network.
+All devices are presented in the RapidIO subsystem by corresponding rio_dev data
+structure. Devices form one global device list and per-network device lists
+(depending on number of available mports and networks).
+
+2.3 Switch
+----------
+
+A RapidIO switch is a special class of device that routes packets between its
+ports towards their final destination. The packet destination port within a
+switch is defined by an internal routing table. A switch is presented in the
+RapidIO subsystem by rio_dev data structure expanded by additional rio_switch
+data structure, which contains switch specific information such as copy of the
+routing table and pointers to switch specific functions.
+
+The RapidIO subsystem defines the format and initialization method for subsystem
+specific switch drivers that are designed to provide hardware-specific
+implementation of common switch management routines.
+
+2.4 Network
+-----------
+
+A RapidIO network is a combination of interconnected endpoint and switch devices.
+Each RapidIO network known to the system is represented by corresponding rio_net
+data structure. This structure includes lists of all devices and local master
+ports that form the same network. It also contains a pointer to the default
+master port that is used to communicate with devices within the network.
+
+2.5 Device Drivers
+------------------
+
+RapidIO device-specific drivers follow Linux Kernel Driver Model and are
+intended to support specific RapidIO devices attached to the RapidIO network.
+
+2.6 Subsystem Interfaces
+------------------------
+
+RapidIO interconnect specification defines features that may be used to provide
+one or more common service layers for all participating RapidIO devices. These
+common services may act separately from device-specific drivers or be used by
+device-specific drivers. Example of such service provider is the RIONET driver
+which implements Ethernet-over-RapidIO interface. Because only one driver can be
+registered for a device, all common RapidIO services have to be registered as
+subsystem interfaces. This allows to have multiple common services attached to
+the same device without blocking attachment of a device-specific driver.
+
+3. Subsystem Initialization
+===========================
+
+In order to initialize the RapidIO subsystem, a platform must initialize and
+register at least one master port within the RapidIO network. To register mport
+within the subsystem controller driver's initialization code calls function
+rio_register_mport() for each available master port.
+
+After all active master ports are registered with a RapidIO subsystem,
+an enumeration and/or discovery routine may be called automatically or
+by user-space command.
+
+RapidIO subsystem can be configured to be built as a statically linked or
+modular component of the kernel (see details below).
+
+4. Enumeration and Discovery
+============================
+
+4.1 Overview
+------------
+
+RapidIO subsystem configuration options allow users to build enumeration and
+discovery methods as statically linked components or loadable modules.
+An enumeration/discovery method implementation and available input parameters
+define how any given method can be attached to available RapidIO mports:
+simply to all available mports OR individually to the specified mport device.
+
+Depending on selected enumeration/discovery build configuration, there are
+several methods to initiate an enumeration and/or discovery process:
+
+  (a) Statically linked enumeration and discovery process can be started
+  automatically during kernel initialization time using corresponding module
+  parameters. This was the original method used since introduction of RapidIO
+  subsystem. Now this method relies on enumerator module parameter which is
+  'rio-scan.scan' for existing basic enumeration/discovery method.
+  When automatic start of enumeration/discovery is used a user has to ensure
+  that all discovering endpoints are started before the enumerating endpoint
+  and are waiting for enumeration to be completed.
+  Configuration option CONFIG_RAPIDIO_DISC_TIMEOUT defines time that discovering
+  endpoint waits for enumeration to be completed. If the specified timeout
+  expires the discovery process is terminated without obtaining RapidIO network
+  information. NOTE: a timed out discovery process may be restarted later using
+  a user-space command as it is described below (if the given endpoint was
+  enumerated successfully).
+
+  (b) Statically linked enumeration and discovery process can be started by
+  a command from user space. This initiation method provides more flexibility
+  for a system startup compared to the option (a) above. After all participating
+  endpoints have been successfully booted, an enumeration process shall be
+  started first by issuing a user-space command, after an enumeration is
+  completed a discovery process can be started on all remaining endpoints.
+
+  (c) Modular enumeration and discovery process can be started by a command from
+  user space. After an enumeration/discovery module is loaded, a network scan
+  process can be started by issuing a user-space command.
+  Similar to the option (b) above, an enumerator has to be started first.
+
+  (d) Modular enumeration and discovery process can be started by a module
+  initialization routine. In this case an enumerating module shall be loaded
+  first.
+
+When a network scan process is started it calls an enumeration or discovery
+routine depending on the configured role of a master port: host or agent.
+
+Enumeration is performed by a master port if it is configured as a host port by
+assigning a host destination ID greater than or equal to zero. The host
+destination ID can be assigned to a master port using various methods depending
+on RapidIO subsystem build configuration:
+
+  (a) For a statically linked RapidIO subsystem core use command line parameter
+  "rapidio.hdid=" with a list of destination ID assignments in order of mport
+  device registration. For example, in a system with two RapidIO controllers
+  the command line parameter "rapidio.hdid=-1,7" will result in assignment of
+  the host destination ID=7 to the second RapidIO controller, while the first
+  one will be assigned destination ID=-1.
+
+  (b) If the RapidIO subsystem core is built as a loadable module, in addition
+  to the method shown above, the host destination ID(s) can be specified using
+  traditional methods of passing module parameter "hdid=" during its loading:
+
+  - from command line: "modprobe rapidio hdid=-1,7", or
+  - from modprobe configuration file using configuration command "options",
+    like in this example: "options rapidio hdid=-1,7". An example of modprobe
+    configuration file is provided in the section below.
+
+NOTES:
+  (i) if "hdid=" parameter is omitted all available mport will be assigned
+  destination ID = -1;
+
+  (ii) the "hdid=" parameter in systems with multiple mports can have
+  destination ID assignments omitted from the end of list (default = -1).
+
+If the host device ID for a specific master port is set to -1, the discovery
+process will be performed for it.
+
+The enumeration and discovery routines use RapidIO maintenance transactions
+to access the configuration space of devices.
+
+NOTE: If RapidIO switch-specific device drivers are built as loadable modules
+they must be loaded before enumeration/discovery process starts.
+This requirement is cased by the fact that enumeration/discovery methods invoke
+vendor-specific callbacks on early stages.
+
+4.2 Automatic Start of Enumeration and Discovery
+------------------------------------------------
+
+Automatic enumeration/discovery start method is applicable only to built-in
+enumeration/discovery RapidIO configuration selection. To enable automatic
+enumeration/discovery start by existing basic enumerator method set use boot
+command line parameter "rio-scan.scan=1".
+
+This configuration requires synchronized start of all RapidIO endpoints that
+form a network which will be enumerated/discovered. Discovering endpoints have
+to be started before an enumeration starts to ensure that all RapidIO
+controllers have been initialized and are ready to be discovered. Configuration
+parameter CONFIG_RAPIDIO_DISC_TIMEOUT defines time (in seconds) which
+a discovering endpoint will wait for enumeration to be completed.
+
+When automatic enumeration/discovery start is selected, basic method's
+initialization routine calls rio_init_mports() to perform enumeration or
+discovery for all known mport devices.
+
+Depending on RapidIO network size and configuration this automatic
+enumeration/discovery start method may be difficult to use due to the
+requirement for synchronized start of all endpoints.
+
+4.3 User-space Start of Enumeration and Discovery
+-------------------------------------------------
+
+User-space start of enumeration and discovery can be used with built-in and
+modular build configurations. For user-space controlled start RapidIO subsystem
+creates the sysfs write-only attribute file '/sys/bus/rapidio/scan'. To initiate
+an enumeration or discovery process on specific mport device, a user needs to
+write mport_ID (not RapidIO destination ID) into that file. The mport_ID is a
+sequential number (0 ... RIO_MAX_MPORTS) assigned during mport device
+registration. For example for machine with single RapidIO controller, mport_ID
+for that controller always will be 0.
+
+To initiate RapidIO enumeration/discovery on all available mports a user may
+write '-1' (or RIO_MPORT_ANY) into the scan attribute file.
+
+4.4 Basic Enumeration Method
+----------------------------
+
+This is an original enumeration/discovery method which is available since
+first release of RapidIO subsystem code. The enumeration process is
+implemented according to the enumeration algorithm outlined in the RapidIO
+Interconnect Specification: Annex I [1].
+
+This method can be configured as statically linked or loadable module.
+The method's single parameter "scan" allows to trigger the enumeration/discovery
+process from module initialization routine.
+
+This enumeration/discovery method can be started only once and does not support
+unloading if it is built as a module.
+
+The enumeration process traverses the network using a recursive depth-first
+algorithm. When a new device is found, the enumerator takes ownership of that
+device by writing into the Host Device ID Lock CSR. It does this to ensure that
+the enumerator has exclusive right to enumerate the device. If device ownership
+is successfully acquired, the enumerator allocates a new rio_dev structure and
+initializes it according to device capabilities.
+
+If the device is an endpoint, a unique device ID is assigned to it and its value
+is written into the device's Base Device ID CSR.
+
+If the device is a switch, the enumerator allocates an additional rio_switch
+structure to store switch specific information. Then the switch's vendor ID and
+device ID are queried against a table of known RapidIO switches. Each switch
+table entry contains a pointer to a switch-specific initialization routine that
+initializes pointers to the rest of switch specific operations, and performs
+hardware initialization if necessary. A RapidIO switch does not have a unique
+device ID; it relies on hopcount and routing for device ID of an attached
+endpoint if access to its configuration registers is required. If a switch (or
+chain of switches) does not have any endpoint (except enumerator) attached to
+it, a fake device ID will be assigned to configure a route to that switch.
+In the case of a chain of switches without endpoint, one fake device ID is used
+to configure a route through the entire chain and switches are differentiated by
+their hopcount value.
+
+For both endpoints and switches the enumerator writes a unique component tag
+into device's Component Tag CSR. That unique value is used by the error
+management notification mechanism to identify a device that is reporting an
+error management event.
+
+Enumeration beyond a switch is completed by iterating over each active egress
+port of that switch. For each active link, a route to a default device ID
+(0xFF for 8-bit systems and 0xFFFF for 16-bit systems) is temporarily written
+into the routing table. The algorithm recurs by calling itself with hopcount + 1
+and the default device ID in order to access the device on the active port.
+
+After the host has completed enumeration of the entire network it releases
+devices by clearing device ID locks (calls rio_clear_locks()). For each endpoint
+in the system, it sets the Discovered bit in the Port General Control CSR
+to indicate that enumeration is completed and agents are allowed to execute
+passive discovery of the network.
+
+The discovery process is performed by agents and is similar to the enumeration
+process that is described above. However, the discovery process is performed
+without changes to the existing routing because agents only gather information
+about RapidIO network structure and are building an internal map of discovered
+devices. This way each Linux-based component of the RapidIO subsystem has
+a complete view of the network. The discovery process can be performed
+simultaneously by several agents. After initializing its RapidIO master port
+each agent waits for enumeration completion by the host for the configured wait
+time period. If this wait time period expires before enumeration is completed,
+an agent skips RapidIO discovery and continues with remaining kernel
+initialization.
+
+4.5 Adding New Enumeration/Discovery Method
+-------------------------------------------
+
+RapidIO subsystem code organization allows addition of new enumeration/discovery
+methods as new configuration options without significant impact to the core
+RapidIO code.
+
+A new enumeration/discovery method has to be attached to one or more mport
+devices before an enumeration/discovery process can be started. Normally,
+method's module initialization routine calls rio_register_scan() to attach
+an enumerator to a specified mport device (or devices). The basic enumerator
+implementation demonstrates this process.
+
+4.6 Using Loadable RapidIO Switch Drivers
+-----------------------------------------
+
+In the case when RapidIO switch drivers are built as loadable modules a user
+must ensure that they are loaded before the enumeration/discovery starts.
+This process can be automated by specifying pre- or post- dependencies in the
+RapidIO-specific modprobe configuration file as shown in the example below.
+
+File /etc/modprobe.d/rapidio.conf::
+
+  # Configure RapidIO subsystem modules
+
+  # Set enumerator host destination ID (overrides kernel command line option)
+  options rapidio hdid=-1,2
+
+  # Load RapidIO switch drivers immediately after rapidio core module was loaded
+  softdep rapidio post: idt_gen2 idtcps tsi57x
+
+  # OR :
+
+  # Load RapidIO switch drivers just before rio-scan enumerator module is loaded
+  softdep rio-scan pre: idt_gen2 idtcps tsi57x
+
+  --------------------------
+
+NOTE:
+  In the example above, one of "softdep" commands must be removed or
+  commented out to keep required module loading sequence.
+
+5. References
+=============
+
+[1] RapidIO Trade Association. RapidIO Interconnect Specifications.
+    http://www.rapidio.org.
+
+[2] Rapidio TA. Technology Comparisons.
+    http://www.rapidio.org/education/technology_comparisons/
+
+[3] RapidIO support for Linux.
+    http://lwn.net/Articles/139118/
+
+[4] Matt Porter. RapidIO for Linux. Ottawa Linux Symposium, 2005
+    http://www.kernel.org/doc/ols/2005/ols2005v2-pages-43-56.pdf
diff --git a/Documentation/driver-api/rapidio/rio_cm.rst b/Documentation/driver-api/rapidio/rio_cm.rst
new file mode 100644 (file)
index 0000000..5294430
--- /dev/null
@@ -0,0 +1,135 @@
+==========================================================================
+RapidIO subsystem Channelized Messaging character device driver (rio_cm.c)
+==========================================================================
+
+
+1. Overview
+===========
+
+This device driver is the result of collaboration within the RapidIO.org
+Software Task Group (STG) between Texas Instruments, Prodrive Technologies,
+Nokia Networks, BAE and IDT.  Additional input was received from other members
+of RapidIO.org.
+
+The objective was to create a character mode driver interface which exposes
+messaging capabilities of RapidIO endpoint devices (mports) directly
+to applications, in a manner that allows the numerous and varied RapidIO
+implementations to interoperate.
+
+This driver (RIO_CM) provides to user-space applications shared access to
+RapidIO mailbox messaging resources.
+
+RapidIO specification (Part 2) defines that endpoint devices may have up to four
+messaging mailboxes in case of multi-packet message (up to 4KB) and
+up to 64 mailboxes if single-packet messages (up to 256 B) are used. In addition
+to protocol definition limitations, a particular hardware implementation can
+have reduced number of messaging mailboxes.  RapidIO aware applications must
+therefore share the messaging resources of a RapidIO endpoint.
+
+Main purpose of this device driver is to provide RapidIO mailbox messaging
+capability to large number of user-space processes by introducing socket-like
+operations using a single messaging mailbox.  This allows applications to
+use the limited RapidIO messaging hardware resources efficiently.
+
+Most of device driver's operations are supported through 'ioctl' system calls.
+
+When loaded this device driver creates a single file system node named rio_cm
+in /dev directory common for all registered RapidIO mport devices.
+
+Following ioctl commands are available to user-space applications:
+
+- RIO_CM_MPORT_GET_LIST:
+    Returns to caller list of local mport devices that
+    support messaging operations (number of entries up to RIO_MAX_MPORTS).
+    Each list entry is combination of mport's index in the system and RapidIO
+    destination ID assigned to the port.
+- RIO_CM_EP_GET_LIST_SIZE:
+    Returns number of messaging capable remote endpoints
+    in a RapidIO network associated with the specified mport device.
+- RIO_CM_EP_GET_LIST:
+    Returns list of RapidIO destination IDs for messaging
+    capable remote endpoints (peers) available in a RapidIO network associated
+    with the specified mport device.
+- RIO_CM_CHAN_CREATE:
+    Creates RapidIO message exchange channel data structure
+    with channel ID assigned automatically or as requested by a caller.
+- RIO_CM_CHAN_BIND:
+    Binds the specified channel data structure to the specified
+    mport device.
+- RIO_CM_CHAN_LISTEN:
+    Enables listening for connection requests on the specified
+    channel.
+- RIO_CM_CHAN_ACCEPT:
+    Accepts a connection request from peer on the specified
+    channel. If wait timeout for this request is specified by a caller it is
+    a blocking call. If timeout set to 0 this is non-blocking call - ioctl
+    handler checks for a pending connection request and if one is not available
+    exits with -EGAIN error status immediately.
+- RIO_CM_CHAN_CONNECT:
+    Sends a connection request to a remote peer/channel.
+- RIO_CM_CHAN_SEND:
+    Sends a data message through the specified channel.
+    The handler for this request assumes that message buffer specified by
+    a caller includes the reserved space for a packet header required by
+    this driver.
+- RIO_CM_CHAN_RECEIVE:
+    Receives a data message through a connected channel.
+    If the channel does not have an incoming message ready to return this ioctl
+    handler will wait for new message until timeout specified by a caller
+    expires. If timeout value is set to 0, ioctl handler uses a default value
+    defined by MAX_SCHEDULE_TIMEOUT.
+- RIO_CM_CHAN_CLOSE:
+    Closes a specified channel and frees associated buffers.
+    If the specified channel is in the CONNECTED state, sends close notification
+    to the remote peer.
+
+The ioctl command codes and corresponding data structures intended for use by
+user-space applications are defined in 'include/uapi/linux/rio_cm_cdev.h'.
+
+2. Hardware Compatibility
+=========================
+
+This device driver uses standard interfaces defined by kernel RapidIO subsystem
+and therefore it can be used with any mport device driver registered by RapidIO
+subsystem with limitations set by available mport HW implementation of messaging
+mailboxes.
+
+3. Module parameters
+====================
+
+- 'dbg_level'
+      - This parameter allows to control amount of debug information
+        generated by this device driver. This parameter is formed by set of
+        bit masks that correspond to the specific functional block.
+        For mask definitions see 'drivers/rapidio/devices/rio_cm.c'
+        This parameter can be changed dynamically.
+        Use CONFIG_RAPIDIO_DEBUG=y to enable debug output at the top level.
+
+- 'cmbox'
+      - Number of RapidIO mailbox to use (default value is 1).
+        This parameter allows to set messaging mailbox number that will be used
+        within entire RapidIO network. It can be used when default mailbox is
+        used by other device drivers or is not supported by some nodes in the
+        RapidIO network.
+
+- 'chstart'
+      - Start channel number for dynamic assignment. Default value - 256.
+        Allows to exclude channel numbers below this parameter from dynamic
+        allocation to avoid conflicts with software components that use
+        reserved predefined channel numbers.
+
+4. Known problems
+=================
+
+  None.
+
+5. User-space Applications and API Library
+==========================================
+
+Messaging API library and applications that use this device driver are available
+from RapidIO.org.
+
+6. TODO List
+============
+
+- Add support for system notification messages (reserved channel 0).
diff --git a/Documentation/driver-api/rapidio/sysfs.rst b/Documentation/driver-api/rapidio/sysfs.rst
new file mode 100644 (file)
index 0000000..540f726
--- /dev/null
@@ -0,0 +1,7 @@
+=============
+Sysfs entries
+=============
+
+The RapidIO sysfs files have moved to:
+Documentation/ABI/testing/sysfs-bus-rapidio and
+Documentation/ABI/testing/sysfs-class-rapidio
diff --git a/Documentation/driver-api/rapidio/tsi721.rst b/Documentation/driver-api/rapidio/tsi721.rst
new file mode 100644 (file)
index 0000000..42aea43
--- /dev/null
@@ -0,0 +1,112 @@
+=========================================================================
+RapidIO subsystem mport driver for IDT Tsi721 PCI Express-to-SRIO bridge.
+=========================================================================
+
+1. Overview
+===========
+
+This driver implements all currently defined RapidIO mport callback functions.
+It supports maintenance read and write operations, inbound and outbound RapidIO
+doorbells, inbound maintenance port-writes and RapidIO messaging.
+
+To generate SRIO maintenance transactions this driver uses one of Tsi721 DMA
+channels. This mechanism provides access to larger range of hop counts and
+destination IDs without need for changes in outbound window translation.
+
+RapidIO messaging support uses dedicated messaging channels for each mailbox.
+For inbound messages this driver uses destination ID matching to forward messages
+into the corresponding message queue. Messaging callbacks are implemented to be
+fully compatible with RIONET driver (Ethernet over RapidIO messaging services).
+
+1. Module parameters:
+
+- 'dbg_level'
+      - This parameter allows to control amount of debug information
+        generated by this device driver. This parameter is formed by set of
+        This parameter can be changed bit masks that correspond to the specific
+        functional block.
+        For mask definitions see 'drivers/rapidio/devices/tsi721.h'
+        This parameter can be changed dynamically.
+        Use CONFIG_RAPIDIO_DEBUG=y to enable debug output at the top level.
+
+- 'dma_desc_per_channel'
+      - This parameter defines number of hardware buffer
+        descriptors allocated for each registered Tsi721 DMA channel.
+        Its default value is 128.
+
+- 'dma_txqueue_sz'
+      - DMA transactions queue size. Defines number of pending
+        transaction requests that can be accepted by each DMA channel.
+        Default value is 16.
+
+- 'dma_sel'
+      - DMA channel selection mask. Bitmask that defines which hardware
+        DMA channels (0 ... 6) will be registered with DmaEngine core.
+        If bit is set to 1, the corresponding DMA channel will be registered.
+        DMA channels not selected by this mask will not be used by this device
+        driver. Default value is 0x7f (use all channels).
+
+- 'pcie_mrrs'
+      - override value for PCIe Maximum Read Request Size (MRRS).
+        This parameter gives an ability to override MRRS value set during PCIe
+        configuration process. Tsi721 supports read request sizes up to 4096B.
+        Value for this parameter must be set as defined by PCIe specification:
+        0 = 128B, 1 = 256B, 2 = 512B, 3 = 1024B, 4 = 2048B and 5 = 4096B.
+        Default value is '-1' (= keep platform setting).
+
+- 'mbox_sel'
+      - RIO messaging MBOX selection mask. This is a bitmask that defines
+        messaging MBOXes are managed by this device driver. Mask bits 0 - 3
+        correspond to MBOX0 - MBOX3. MBOX is under driver's control if the
+        corresponding bit is set to '1'. Default value is 0x0f (= all).
+
+2. Known problems
+=================
+
+  None.
+
+3. DMA Engine Support
+=====================
+
+Tsi721 mport driver supports DMA data transfers between local system memory and
+remote RapidIO devices. This functionality is implemented according to SLAVE
+mode API defined by common Linux kernel DMA Engine framework.
+
+Depending on system requirements RapidIO DMA operations can be included/excluded
+by setting CONFIG_RAPIDIO_DMA_ENGINE option. Tsi721 miniport driver uses seven
+out of eight available BDMA channels to support DMA data transfers.
+One BDMA channel is reserved for generation of maintenance read/write requests.
+
+If Tsi721 mport driver have been built with RAPIDIO_DMA_ENGINE support included,
+this driver will accept DMA-specific module parameter:
+
+  "dma_desc_per_channel"
+                        - defines number of hardware buffer descriptors used by
+                           each BDMA channel of Tsi721 (by default - 128).
+
+4. Version History
+
+  =====   ====================================================================
+  1.1.0   DMA operations re-worked to support data scatter/gather lists larger
+          than hardware buffer descriptors ring.
+  1.0.0   Initial driver release.
+  =====   ====================================================================
+
+5.  License
+===========
+
+  Copyright(c) 2011 Integrated Device Technology, Inc. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by the Free
+  Software Foundation; either version 2 of the License, or (at your option)
+  any later version.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
diff --git a/Documentation/driver-api/serial/driver.rst b/Documentation/driver-api/serial/driver.rst
new file mode 100644 (file)
index 0000000..31bd4e1
--- /dev/null
@@ -0,0 +1,549 @@
+====================
+Low Level Serial API
+====================
+
+
+This document is meant as a brief overview of some aspects of the new serial
+driver.  It is not complete, any questions you have should be directed to
+<rmk@arm.linux.org.uk>
+
+The reference implementation is contained within amba-pl011.c.
+
+
+
+Low Level Serial Hardware Driver
+--------------------------------
+
+The low level serial hardware driver is responsible for supplying port
+information (defined by uart_port) and a set of control methods (defined
+by uart_ops) to the core serial driver.  The low level driver is also
+responsible for handling interrupts for the port, and providing any
+console support.
+
+
+Console Support
+---------------
+
+The serial core provides a few helper functions.  This includes identifing
+the correct port structure (via uart_get_console) and decoding command line
+arguments (uart_parse_options).
+
+There is also a helper function (uart_console_write) which performs a
+character by character write, translating newlines to CRLF sequences.
+Driver writers are recommended to use this function rather than implementing
+their own version.
+
+
+Locking
+-------
+
+It is the responsibility of the low level hardware driver to perform the
+necessary locking using port->lock.  There are some exceptions (which
+are described in the uart_ops listing below.)
+
+There are two locks.  A per-port spinlock, and an overall semaphore.
+
+From the core driver perspective, the port->lock locks the following
+data::
+
+       port->mctrl
+       port->icount
+       port->state->xmit.head (circ_buf->head)
+       port->state->xmit.tail (circ_buf->tail)
+
+The low level driver is free to use this lock to provide any additional
+locking.
+
+The port_sem semaphore is used to protect against ports being added/
+removed or reconfigured at inappropriate times. Since v2.6.27, this
+semaphore has been the 'mutex' member of the tty_port struct, and
+commonly referred to as the port mutex.
+
+
+uart_ops
+--------
+
+The uart_ops structure is the main interface between serial_core and the
+hardware specific driver.  It contains all the methods to control the
+hardware.
+
+  tx_empty(port)
+       This function tests whether the transmitter fifo and shifter
+       for the port described by 'port' is empty.  If it is empty,
+       this function should return TIOCSER_TEMT, otherwise return 0.
+       If the port does not support this operation, then it should
+       return TIOCSER_TEMT.
+
+       Locking: none.
+
+       Interrupts: caller dependent.
+
+       This call must not sleep
+
+  set_mctrl(port, mctrl)
+       This function sets the modem control lines for port described
+       by 'port' to the state described by mctrl.  The relevant bits
+       of mctrl are:
+
+               - TIOCM_RTS     RTS signal.
+               - TIOCM_DTR     DTR signal.
+               - TIOCM_OUT1    OUT1 signal.
+               - TIOCM_OUT2    OUT2 signal.
+               - TIOCM_LOOP    Set the port into loopback mode.
+
+       If the appropriate bit is set, the signal should be driven
+       active.  If the bit is clear, the signal should be driven
+       inactive.
+
+       Locking: port->lock taken.
+
+       Interrupts: locally disabled.
+
+       This call must not sleep
+
+  get_mctrl(port)
+       Returns the current state of modem control inputs.  The state
+       of the outputs should not be returned, since the core keeps
+       track of their state.  The state information should include:
+
+               - TIOCM_CAR     state of DCD signal
+               - TIOCM_CTS     state of CTS signal
+               - TIOCM_DSR     state of DSR signal
+               - TIOCM_RI      state of RI signal
+
+       The bit is set if the signal is currently driven active.  If
+       the port does not support CTS, DCD or DSR, the driver should
+       indicate that the signal is permanently active.  If RI is
+       not available, the signal should not be indicated as active.
+
+       Locking: port->lock taken.
+
+       Interrupts: locally disabled.
+
+       This call must not sleep
+
+  stop_tx(port)
+       Stop transmitting characters.  This might be due to the CTS
+       line becoming inactive or the tty layer indicating we want
+       to stop transmission due to an XOFF character.
+
+       The driver should stop transmitting characters as soon as
+       possible.
+
+       Locking: port->lock taken.
+
+       Interrupts: locally disabled.
+
+       This call must not sleep
+
+  start_tx(port)
+       Start transmitting characters.
+
+       Locking: port->lock taken.
+
+       Interrupts: locally disabled.
+
+       This call must not sleep
+
+  throttle(port)
+       Notify the serial driver that input buffers for the line discipline are
+       close to full, and it should somehow signal that no more characters
+       should be sent to the serial port.
+       This will be called only if hardware assisted flow control is enabled.
+
+       Locking: serialized with .unthrottle() and termios modification by the
+       tty layer.
+
+  unthrottle(port)
+       Notify the serial driver that characters can now be sent to the serial
+       port without fear of overrunning the input buffers of the line
+       disciplines.
+
+       This will be called only if hardware assisted flow control is enabled.
+
+       Locking: serialized with .throttle() and termios modification by the
+       tty layer.
+
+  send_xchar(port,ch)
+       Transmit a high priority character, even if the port is stopped.
+       This is used to implement XON/XOFF flow control and tcflow().  If
+       the serial driver does not implement this function, the tty core
+       will append the character to the circular buffer and then call
+       start_tx() / stop_tx() to flush the data out.
+
+       Do not transmit if ch == '\0' (__DISABLED_CHAR).
+
+       Locking: none.
+
+       Interrupts: caller dependent.
+
+  stop_rx(port)
+       Stop receiving characters; the port is in the process of
+       being closed.
+
+       Locking: port->lock taken.
+
+       Interrupts: locally disabled.
+
+       This call must not sleep
+
+  enable_ms(port)
+       Enable the modem status interrupts.
+
+       This method may be called multiple times.  Modem status
+       interrupts should be disabled when the shutdown method is
+       called.
+
+       Locking: port->lock taken.
+
+       Interrupts: locally disabled.
+
+       This call must not sleep
+
+  break_ctl(port,ctl)
+       Control the transmission of a break signal.  If ctl is
+       nonzero, the break signal should be transmitted.  The signal
+       should be terminated when another call is made with a zero
+       ctl.
+
+       Locking: caller holds tty_port->mutex
+
+  startup(port)
+       Grab any interrupt resources and initialise any low level driver
+       state.  Enable the port for reception.  It should not activate
+       RTS nor DTR; this will be done via a separate call to set_mctrl.
+
+       This method will only be called when the port is initially opened.
+
+       Locking: port_sem taken.
+
+       Interrupts: globally disabled.
+
+  shutdown(port)
+       Disable the port, disable any break condition that may be in
+       effect, and free any interrupt resources.  It should not disable
+       RTS nor DTR; this will have already been done via a separate
+       call to set_mctrl.
+
+       Drivers must not access port->state once this call has completed.
+
+       This method will only be called when there are no more users of
+       this port.
+
+       Locking: port_sem taken.
+
+       Interrupts: caller dependent.
+
+  flush_buffer(port)
+       Flush any write buffers, reset any DMA state and stop any
+       ongoing DMA transfers.
+
+       This will be called whenever the port->state->xmit circular
+       buffer is cleared.
+
+       Locking: port->lock taken.
+
+       Interrupts: locally disabled.
+
+       This call must not sleep
+
+  set_termios(port,termios,oldtermios)
+       Change the port parameters, including word length, parity, stop
+       bits.  Update read_status_mask and ignore_status_mask to indicate
+       the types of events we are interested in receiving.  Relevant
+       termios->c_cflag bits are:
+
+               CSIZE
+                       - word size
+               CSTOPB
+                       - 2 stop bits
+               PARENB
+                       - parity enable
+               PARODD
+                       - odd parity (when PARENB is in force)
+               CREAD
+                       - enable reception of characters (if not set,
+                         still receive characters from the port, but
+                         throw them away.
+               CRTSCTS
+                       - if set, enable CTS status change reporting
+               CLOCAL
+                       - if not set, enable modem status change
+                         reporting.
+
+       Relevant termios->c_iflag bits are:
+
+               INPCK
+                       - enable frame and parity error events to be
+                         passed to the TTY layer.
+               BRKINT / PARMRK
+                       - both of these enable break events to be
+                         passed to the TTY layer.
+
+               IGNPAR
+                       - ignore parity and framing errors
+               IGNBRK
+                       - ignore break errors,  If IGNPAR is also
+                         set, ignore overrun errors as well.
+
+       The interaction of the iflag bits is as follows (parity error
+       given as an example):
+
+       =============== ======= ======  =============================
+       Parity error    INPCK   IGNPAR
+       =============== ======= ======  =============================
+       n/a             0       n/a     character received, marked as
+                                       TTY_NORMAL
+       None            1       n/a     character received, marked as
+                                       TTY_NORMAL
+       Yes             1       0       character received, marked as
+                                       TTY_PARITY
+       Yes             1       1       character discarded
+       =============== ======= ======  =============================
+
+       Other flags may be used (eg, xon/xoff characters) if your
+       hardware supports hardware "soft" flow control.
+
+       Locking: caller holds tty_port->mutex
+
+       Interrupts: caller dependent.
+
+       This call must not sleep
+
+  set_ldisc(port,termios)
+       Notifier for discipline change. See Documentation/driver-api/serial/tty.rst.
+
+       Locking: caller holds tty_port->mutex
+
+  pm(port,state,oldstate)
+       Perform any power management related activities on the specified
+       port.  State indicates the new state (defined by
+       enum uart_pm_state), oldstate indicates the previous state.
+
+       This function should not be used to grab any resources.
+
+       This will be called when the port is initially opened and finally
+       closed, except when the port is also the system console.  This
+       will occur even if CONFIG_PM is not set.
+
+       Locking: none.
+
+       Interrupts: caller dependent.
+
+  type(port)
+       Return a pointer to a string constant describing the specified
+       port, or return NULL, in which case the string 'unknown' is
+       substituted.
+
+       Locking: none.
+
+       Interrupts: caller dependent.
+
+  release_port(port)
+       Release any memory and IO region resources currently in use by
+       the port.
+
+       Locking: none.
+
+       Interrupts: caller dependent.
+
+  request_port(port)
+       Request any memory and IO region resources required by the port.
+       If any fail, no resources should be registered when this function
+       returns, and it should return -EBUSY on failure.
+
+       Locking: none.
+
+       Interrupts: caller dependent.
+
+  config_port(port,type)
+       Perform any autoconfiguration steps required for the port.  `type`
+       contains a bit mask of the required configuration.  UART_CONFIG_TYPE
+       indicates that the port requires detection and identification.
+       port->type should be set to the type found, or PORT_UNKNOWN if
+       no port was detected.
+
+       UART_CONFIG_IRQ indicates autoconfiguration of the interrupt signal,
+       which should be probed using standard kernel autoprobing techniques.
+       This is not necessary on platforms where ports have interrupts
+       internally hard wired (eg, system on a chip implementations).
+
+       Locking: none.
+
+       Interrupts: caller dependent.
+
+  verify_port(port,serinfo)
+       Verify the new serial port information contained within serinfo is
+       suitable for this port type.
+
+       Locking: none.
+
+       Interrupts: caller dependent.
+
+  ioctl(port,cmd,arg)
+       Perform any port specific IOCTLs.  IOCTL commands must be defined
+       using the standard numbering system found in <asm/ioctl.h>
+
+       Locking: none.
+
+       Interrupts: caller dependent.
+
+  poll_init(port)
+       Called by kgdb to perform the minimal hardware initialization needed
+       to support poll_put_char() and poll_get_char().  Unlike ->startup()
+       this should not request interrupts.
+
+       Locking: tty_mutex and tty_port->mutex taken.
+
+       Interrupts: n/a.
+
+  poll_put_char(port,ch)
+       Called by kgdb to write a single character directly to the serial
+       port.  It can and should block until there is space in the TX FIFO.
+
+       Locking: none.
+
+       Interrupts: caller dependent.
+
+       This call must not sleep
+
+  poll_get_char(port)
+       Called by kgdb to read a single character directly from the serial
+       port.  If data is available, it should be returned; otherwise
+       the function should return NO_POLL_CHAR immediately.
+
+       Locking: none.
+
+       Interrupts: caller dependent.
+
+       This call must not sleep
+
+Other functions
+---------------
+
+uart_update_timeout(port,cflag,baud)
+       Update the FIFO drain timeout, port->timeout, according to the
+       number of bits, parity, stop bits and baud rate.
+
+       Locking: caller is expected to take port->lock
+
+       Interrupts: n/a
+
+uart_get_baud_rate(port,termios,old,min,max)
+       Return the numeric baud rate for the specified termios, taking
+       account of the special 38400 baud "kludge".  The B0 baud rate
+       is mapped to 9600 baud.
+
+       If the baud rate is not within min..max, then if old is non-NULL,
+       the original baud rate will be tried.  If that exceeds the
+       min..max constraint, 9600 baud will be returned.  termios will
+       be updated to the baud rate in use.
+
+       Note: min..max must always allow 9600 baud to be selected.
+
+       Locking: caller dependent.
+
+       Interrupts: n/a
+
+uart_get_divisor(port,baud)
+       Return the divisor (baud_base / baud) for the specified baud
+       rate, appropriately rounded.
+
+       If 38400 baud and custom divisor is selected, return the
+       custom divisor instead.
+
+       Locking: caller dependent.
+
+       Interrupts: n/a
+
+uart_match_port(port1,port2)
+       This utility function can be used to determine whether two
+       uart_port structures describe the same port.
+
+       Locking: n/a
+
+       Interrupts: n/a
+
+uart_write_wakeup(port)
+       A driver is expected to call this function when the number of
+       characters in the transmit buffer have dropped below a threshold.
+
+       Locking: port->lock should be held.
+
+       Interrupts: n/a
+
+uart_register_driver(drv)
+       Register a uart driver with the core driver.  We in turn register
+       with the tty layer, and initialise the core driver per-port state.
+
+       drv->port should be NULL, and the per-port structures should be
+       registered using uart_add_one_port after this call has succeeded.
+
+       Locking: none
+
+       Interrupts: enabled
+
+uart_unregister_driver()
+       Remove all references to a driver from the core driver.  The low
+       level driver must have removed all its ports via the
+       uart_remove_one_port() if it registered them with uart_add_one_port().
+
+       Locking: none
+
+       Interrupts: enabled
+
+**uart_suspend_port()**
+
+**uart_resume_port()**
+
+**uart_add_one_port()**
+
+**uart_remove_one_port()**
+
+Other notes
+-----------
+
+It is intended some day to drop the 'unused' entries from uart_port, and
+allow low level drivers to register their own individual uart_port's with
+the core.  This will allow drivers to use uart_port as a pointer to a
+structure containing both the uart_port entry with their own extensions,
+thus::
+
+       struct my_port {
+               struct uart_port        port;
+               int                     my_stuff;
+       };
+
+Modem control lines via GPIO
+----------------------------
+
+Some helpers are provided in order to set/get modem control lines via GPIO.
+
+mctrl_gpio_init(port, idx):
+       This will get the {cts,rts,...}-gpios from device tree if they are
+       present and request them, set direction etc, and return an
+       allocated structure. `devm_*` functions are used, so there's no need
+       to call mctrl_gpio_free().
+       As this sets up the irq handling make sure to not handle changes to the
+       gpio input lines in your driver, too.
+
+mctrl_gpio_free(dev, gpios):
+       This will free the requested gpios in mctrl_gpio_init().
+       As `devm_*` functions are used, there's generally no need to call
+       this function.
+
+mctrl_gpio_to_gpiod(gpios, gidx)
+       This returns the gpio_desc structure associated to the modem line
+       index.
+
+mctrl_gpio_set(gpios, mctrl):
+       This will sets the gpios according to the mctrl state.
+
+mctrl_gpio_get(gpios, mctrl):
+       This will update mctrl with the gpios values.
+
+mctrl_gpio_enable_ms(gpios):
+       Enables irqs and handling of changes to the ms lines.
+
+mctrl_gpio_disable_ms(gpios):
+       Disables irqs and handling of changes to the ms lines.
diff --git a/Documentation/driver-api/serial/index.rst b/Documentation/driver-api/serial/index.rst
new file mode 100644 (file)
index 0000000..33ad10d
--- /dev/null
@@ -0,0 +1,32 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==========================
+Support for Serial devices
+==========================
+
+.. toctree::
+    :maxdepth: 1
+
+
+    driver
+    tty
+
+Serial drivers
+==============
+
+.. toctree::
+    :maxdepth: 1
+
+    cyclades_z
+    moxa-smartio
+    n_gsm
+    rocket
+    serial-iso7816
+    serial-rs485
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
diff --git a/Documentation/driver-api/switchtec.rst b/Documentation/driver-api/switchtec.rst
new file mode 100644 (file)
index 0000000..7611fdc
--- /dev/null
@@ -0,0 +1,102 @@
+========================
+Linux Switchtec Support
+========================
+
+Microsemi's "Switchtec" line of PCI switch devices is already
+supported by the kernel with standard PCI switch drivers. However, the
+Switchtec device advertises a special management endpoint which
+enables some additional functionality. This includes:
+
+* Packet and Byte Counters
+* Firmware Upgrades
+* Event and Error logs
+* Querying port link status
+* Custom user firmware commands
+
+The switchtec kernel module implements this functionality.
+
+
+Interface
+=========
+
+The primary means of communicating with the Switchtec management firmware is
+through the Memory-mapped Remote Procedure Call (MRPC) interface.
+Commands are submitted to the interface with a 4-byte command
+identifier and up to 1KB of command specific data. The firmware will
+respond with a 4-byte return code and up to 1KB of command-specific
+data. The interface only processes a single command at a time.
+
+
+Userspace Interface
+===================
+
+The MRPC interface will be exposed to userspace through a simple char
+device: /dev/switchtec#, one for each management endpoint in the system.
+
+The char device has the following semantics:
+
+* A write must consist of at least 4 bytes and no more than 1028 bytes.
+  The first 4 bytes will be interpreted as the Command ID and the
+  remainder will be used as the input data. A write will send the
+  command to the firmware to begin processing.
+
+* Each write must be followed by exactly one read. Any double write will
+  produce an error and any read that doesn't follow a write will
+  produce an error.
+
+* A read will block until the firmware completes the command and return
+  the 4-byte Command Return Value plus up to 1024 bytes of output
+  data. (The length will be specified by the size parameter of the read
+  call -- reading less than 4 bytes will produce an error.)
+
+* The poll call will also be supported for userspace applications that
+  need to do other things while waiting for the command to complete.
+
+The following IOCTLs are also supported by the device:
+
+* SWITCHTEC_IOCTL_FLASH_INFO - Retrieve firmware length and number
+  of partitions in the device.
+
+* SWITCHTEC_IOCTL_FLASH_PART_INFO - Retrieve address and lengeth for
+  any specified partition in flash.
+
+* SWITCHTEC_IOCTL_EVENT_SUMMARY - Read a structure of bitmaps
+  indicating all uncleared events.
+
+* SWITCHTEC_IOCTL_EVENT_CTL - Get the current count, clear and set flags
+  for any event. This ioctl takes in a switchtec_ioctl_event_ctl struct
+  with the event_id, index and flags set (index being the partition or PFF
+  number for non-global events). It returns whether the event has
+  occurred, the number of times and any event specific data. The flags
+  can be used to clear the count or enable and disable actions to
+  happen when the event occurs.
+  By using the SWITCHTEC_IOCTL_EVENT_FLAG_EN_POLL flag,
+  you can set an event to trigger a poll command to return with
+  POLLPRI. In this way, userspace can wait for events to occur.
+
+* SWITCHTEC_IOCTL_PFF_TO_PORT and SWITCHTEC_IOCTL_PORT_TO_PFF convert
+  between PCI Function Framework number (used by the event system)
+  and Switchtec Logic Port ID and Partition number (which is more
+  user friendly).
+
+
+Non-Transparent Bridge (NTB) Driver
+===================================
+
+An NTB hardware driver is provided for the Switchtec hardware in
+ntb_hw_switchtec. Currently, it only supports switches configured with
+exactly 2 NT partitions and zero or more non-NT partitions. It also requires
+the following configuration settings:
+
+* Both NT partitions must be able to access each other's GAS spaces.
+  Thus, the bits in the GAS Access Vector under Management Settings
+  must be set to support this.
+* Kernel configuration MUST include support for NTB (CONFIG_NTB needs
+  to be set)
+
+NT EP BAR 2 will be dynamically configured as a Direct Window, and
+the configuration file does not need to configure it explicitly.
+
+Please refer to Documentation/driver-api/ntb.rst in Linux source tree for an overall
+understanding of the Linux NTB stack. ntb_hw_switchtec works as an NTB
+Hardware Driver in this stack.
diff --git a/Documentation/driver-api/vfio-mediated-device.rst b/Documentation/driver-api/vfio-mediated-device.rst
new file mode 100644 (file)
index 0000000..25eb7d5
--- /dev/null
@@ -0,0 +1,414 @@
+.. include:: <isonum.txt>
+
+=====================
+VFIO Mediated devices
+=====================
+
+:Copyright: |copy| 2016, NVIDIA CORPORATION. All rights reserved.
+:Author: Neo Jia <cjia@nvidia.com>
+:Author: Kirti Wankhede <kwankhede@nvidia.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+
+
+Virtual Function I/O (VFIO) Mediated devices[1]
+===============================================
+
+The number of use cases for virtualizing DMA devices that do not have built-in
+SR_IOV capability is increasing. Previously, to virtualize such devices,
+developers had to create their own management interfaces and APIs, and then
+integrate them with user space software. To simplify integration with user space
+software, we have identified common requirements and a unified management
+interface for such devices.
+
+The VFIO driver framework provides unified APIs for direct device access. It is
+an IOMMU/device-agnostic framework for exposing direct device access to user
+space in a secure, IOMMU-protected environment. This framework is used for
+multiple devices, such as GPUs, network adapters, and compute accelerators. With
+direct device access, virtual machines or user space applications have direct
+access to the physical device. This framework is reused for mediated devices.
+
+The mediated core driver provides a common interface for mediated device
+management that can be used by drivers of different devices. This module
+provides a generic interface to perform these operations:
+
+* Create and destroy a mediated device
+* Add a mediated device to and remove it from a mediated bus driver
+* Add a mediated device to and remove it from an IOMMU group
+
+The mediated core driver also provides an interface to register a bus driver.
+For example, the mediated VFIO mdev driver is designed for mediated devices and
+supports VFIO APIs. The mediated bus driver adds a mediated device to and
+removes it from a VFIO group.
+
+The following high-level block diagram shows the main components and interfaces
+in the VFIO mediated driver framework. The diagram shows NVIDIA, Intel, and IBM
+devices as examples, as these devices are the first devices to use this module::
+
+     +---------------+
+     |               |
+     | +-----------+ |  mdev_register_driver() +--------------+
+     | |           | +<------------------------+              |
+     | |  mdev     | |                         |              |
+     | |  bus      | +------------------------>+ vfio_mdev.ko |<-> VFIO user
+     | |  driver   | |     probe()/remove()    |              |    APIs
+     | |           | |                         +--------------+
+     | +-----------+ |
+     |               |
+     |  MDEV CORE    |
+     |   MODULE      |
+     |   mdev.ko     |
+     | +-----------+ |  mdev_register_device() +--------------+
+     | |           | +<------------------------+              |
+     | |           | |                         |  nvidia.ko   |<-> physical
+     | |           | +------------------------>+              |    device
+     | |           | |        callbacks        +--------------+
+     | | Physical  | |
+     | |  device   | |  mdev_register_device() +--------------+
+     | | interface | |<------------------------+              |
+     | |           | |                         |  i915.ko     |<-> physical
+     | |           | +------------------------>+              |    device
+     | |           | |        callbacks        +--------------+
+     | |           | |
+     | |           | |  mdev_register_device() +--------------+
+     | |           | +<------------------------+              |
+     | |           | |                         | ccw_device.ko|<-> physical
+     | |           | +------------------------>+              |    device
+     | |           | |        callbacks        +--------------+
+     | +-----------+ |
+     +---------------+
+
+
+Registration Interfaces
+=======================
+
+The mediated core driver provides the following types of registration
+interfaces:
+
+* Registration interface for a mediated bus driver
+* Physical device driver interface
+
+Registration Interface for a Mediated Bus Driver
+------------------------------------------------
+
+The registration interface for a mediated bus driver provides the following
+structure to represent a mediated device's driver::
+
+     /*
+      * struct mdev_driver [2] - Mediated device's driver
+      * @name: driver name
+      * @probe: called when new device created
+      * @remove: called when device removed
+      * @driver: device driver structure
+      */
+     struct mdev_driver {
+            const char *name;
+            int  (*probe)  (struct device *dev);
+            void (*remove) (struct device *dev);
+            struct device_driver    driver;
+     };
+
+A mediated bus driver for mdev should use this structure in the function calls
+to register and unregister itself with the core driver:
+
+* Register::
+
+    extern int  mdev_register_driver(struct mdev_driver *drv,
+                                  struct module *owner);
+
+* Unregister::
+
+    extern void mdev_unregister_driver(struct mdev_driver *drv);
+
+The mediated bus driver is responsible for adding mediated devices to the VFIO
+group when devices are bound to the driver and removing mediated devices from
+the VFIO when devices are unbound from the driver.
+
+
+Physical Device Driver Interface
+--------------------------------
+
+The physical device driver interface provides the mdev_parent_ops[3] structure
+to define the APIs to manage work in the mediated core driver that is related
+to the physical device.
+
+The structures in the mdev_parent_ops structure are as follows:
+
+* dev_attr_groups: attributes of the parent device
+* mdev_attr_groups: attributes of the mediated device
+* supported_config: attributes to define supported configurations
+
+The functions in the mdev_parent_ops structure are as follows:
+
+* create: allocate basic resources in a driver for a mediated device
+* remove: free resources in a driver when a mediated device is destroyed
+
+(Note that mdev-core provides no implicit serialization of create/remove
+callbacks per mdev parent device, per mdev type, or any other categorization.
+Vendor drivers are expected to be fully asynchronous in this respect or
+provide their own internal resource protection.)
+
+The callbacks in the mdev_parent_ops structure are as follows:
+
+* open: open callback of mediated device
+* close: close callback of mediated device
+* ioctl: ioctl callback of mediated device
+* read : read emulation callback
+* write: write emulation callback
+* mmap: mmap emulation callback
+
+A driver should use the mdev_parent_ops structure in the function call to
+register itself with the mdev core driver::
+
+       extern int  mdev_register_device(struct device *dev,
+                                        const struct mdev_parent_ops *ops);
+
+However, the mdev_parent_ops structure is not required in the function call
+that a driver should use to unregister itself with the mdev core driver::
+
+       extern void mdev_unregister_device(struct device *dev);
+
+
+Mediated Device Management Interface Through sysfs
+==================================================
+
+The management interface through sysfs enables user space software, such as
+libvirt, to query and configure mediated devices in a hardware-agnostic fashion.
+This management interface provides flexibility to the underlying physical
+device's driver to support features such as:
+
+* Mediated device hot plug
+* Multiple mediated devices in a single virtual machine
+* Multiple mediated devices from different physical devices
+
+Links in the mdev_bus Class Directory
+-------------------------------------
+The /sys/class/mdev_bus/ directory contains links to devices that are registered
+with the mdev core driver.
+
+Directories and files under the sysfs for Each Physical Device
+--------------------------------------------------------------
+
+::
+
+  |- [parent physical device]
+  |--- Vendor-specific-attributes [optional]
+  |--- [mdev_supported_types]
+  |     |--- [<type-id>]
+  |     |   |--- create
+  |     |   |--- name
+  |     |   |--- available_instances
+  |     |   |--- device_api
+  |     |   |--- description
+  |     |   |--- [devices]
+  |     |--- [<type-id>]
+  |     |   |--- create
+  |     |   |--- name
+  |     |   |--- available_instances
+  |     |   |--- device_api
+  |     |   |--- description
+  |     |   |--- [devices]
+  |     |--- [<type-id>]
+  |          |--- create
+  |          |--- name
+  |          |--- available_instances
+  |          |--- device_api
+  |          |--- description
+  |          |--- [devices]
+
+* [mdev_supported_types]
+
+  The list of currently supported mediated device types and their details.
+
+  [<type-id>], device_api, and available_instances are mandatory attributes
+  that should be provided by vendor driver.
+
+* [<type-id>]
+
+  The [<type-id>] name is created by adding the device driver string as a prefix
+  to the string provided by the vendor driver. This format of this name is as
+  follows::
+
+       sprintf(buf, "%s-%s", dev_driver_string(parent->dev), group->name);
+
+  (or using mdev_parent_dev(mdev) to arrive at the parent device outside
+  of the core mdev code)
+
+* device_api
+
+  This attribute should show which device API is being created, for example,
+  "vfio-pci" for a PCI device.
+
+* available_instances
+
+  This attribute should show the number of devices of type <type-id> that can be
+  created.
+
+* [device]
+
+  This directory contains links to the devices of type <type-id> that have been
+  created.
+
+* name
+
+  This attribute should show human readable name. This is optional attribute.
+
+* description
+
+  This attribute should show brief features/description of the type. This is
+  optional attribute.
+
+Directories and Files Under the sysfs for Each mdev Device
+----------------------------------------------------------
+
+::
+
+  |- [parent phy device]
+  |--- [$MDEV_UUID]
+         |--- remove
+         |--- mdev_type {link to its type}
+         |--- vendor-specific-attributes [optional]
+
+* remove (write only)
+
+Writing '1' to the 'remove' file destroys the mdev device. The vendor driver can
+fail the remove() callback if that device is active and the vendor driver
+doesn't support hot unplug.
+
+Example::
+
+       # echo 1 > /sys/bus/mdev/devices/$mdev_UUID/remove
+
+Mediated device Hot plug
+------------------------
+
+Mediated devices can be created and assigned at runtime. The procedure to hot
+plug a mediated device is the same as the procedure to hot plug a PCI device.
+
+Translation APIs for Mediated Devices
+=====================================
+
+The following APIs are provided for translating user pfn to host pfn in a VFIO
+driver::
+
+       extern int vfio_pin_pages(struct device *dev, unsigned long *user_pfn,
+                                 int npage, int prot, unsigned long *phys_pfn);
+
+       extern int vfio_unpin_pages(struct device *dev, unsigned long *user_pfn,
+                                   int npage);
+
+These functions call back into the back-end IOMMU module by using the pin_pages
+and unpin_pages callbacks of the struct vfio_iommu_driver_ops[4]. Currently
+these callbacks are supported in the TYPE1 IOMMU module. To enable them for
+other IOMMU backend modules, such as PPC64 sPAPR module, they need to provide
+these two callback functions.
+
+Using the Sample Code
+=====================
+
+mtty.c in samples/vfio-mdev/ directory is a sample driver program to
+demonstrate how to use the mediated device framework.
+
+The sample driver creates an mdev device that simulates a serial port over a PCI
+card.
+
+1. Build and load the mtty.ko module.
+
+   This step creates a dummy device, /sys/devices/virtual/mtty/mtty/
+
+   Files in this device directory in sysfs are similar to the following::
+
+     # tree /sys/devices/virtual/mtty/mtty/
+        /sys/devices/virtual/mtty/mtty/
+        |-- mdev_supported_types
+        |   |-- mtty-1
+        |   |   |-- available_instances
+        |   |   |-- create
+        |   |   |-- device_api
+        |   |   |-- devices
+        |   |   `-- name
+        |   `-- mtty-2
+        |       |-- available_instances
+        |       |-- create
+        |       |-- device_api
+        |       |-- devices
+        |       `-- name
+        |-- mtty_dev
+        |   `-- sample_mtty_dev
+        |-- power
+        |   |-- autosuspend_delay_ms
+        |   |-- control
+        |   |-- runtime_active_time
+        |   |-- runtime_status
+        |   `-- runtime_suspended_time
+        |-- subsystem -> ../../../../class/mtty
+        `-- uevent
+
+2. Create a mediated device by using the dummy device that you created in the
+   previous step::
+
+     # echo "83b8f4f2-509f-382f-3c1e-e6bfe0fa1001" >   \
+              /sys/devices/virtual/mtty/mtty/mdev_supported_types/mtty-2/create
+
+3. Add parameters to qemu-kvm::
+
+     -device vfio-pci,\
+      sysfsdev=/sys/bus/mdev/devices/83b8f4f2-509f-382f-3c1e-e6bfe0fa1001
+
+4. Boot the VM.
+
+   In the Linux guest VM, with no hardware on the host, the device appears
+   as  follows::
+
+     # lspci -s 00:05.0 -xxvv
+     00:05.0 Serial controller: Device 4348:3253 (rev 10) (prog-if 02 [16550])
+             Subsystem: Device 4348:3253
+             Physical Slot: 5
+             Control: I/O+ Mem- BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr-
+     Stepping- SERR- FastB2B- DisINTx-
+             Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort-
+     <TAbort- <MAbort- >SERR- <PERR- INTx-
+             Interrupt: pin A routed to IRQ 10
+             Region 0: I/O ports at c150 [size=8]
+             Region 1: I/O ports at c158 [size=8]
+             Kernel driver in use: serial
+     00: 48 43 53 32 01 00 00 02 10 02 00 07 00 00 00 00
+     10: 51 c1 00 00 59 c1 00 00 00 00 00 00 00 00 00 00
+     20: 00 00 00 00 00 00 00 00 00 00 00 00 48 43 53 32
+     30: 00 00 00 00 00 00 00 00 00 00 00 00 0a 01 00 00
+
+     In the Linux guest VM, dmesg output for the device is as follows:
+
+     serial 0000:00:05.0: PCI INT A -> Link[LNKA] -> GSI 10 (level, high) -> IRQ 10
+     0000:00:05.0: ttyS1 at I/O 0xc150 (irq = 10) is a 16550A
+     0000:00:05.0: ttyS2 at I/O 0xc158 (irq = 10) is a 16550A
+
+
+5. In the Linux guest VM, check the serial ports::
+
+     # setserial -g /dev/ttyS*
+     /dev/ttyS0, UART: 16550A, Port: 0x03f8, IRQ: 4
+     /dev/ttyS1, UART: 16550A, Port: 0xc150, IRQ: 10
+     /dev/ttyS2, UART: 16550A, Port: 0xc158, IRQ: 10
+
+6. Using minicom or any terminal emulation program, open port /dev/ttyS1 or
+   /dev/ttyS2 with hardware flow control disabled.
+
+7. Type data on the minicom terminal or send data to the terminal emulation
+   program and read the data.
+
+   Data is loop backed from hosts mtty driver.
+
+8. Destroy the mediated device that you created::
+
+     # echo 1 > /sys/bus/mdev/devices/83b8f4f2-509f-382f-3c1e-e6bfe0fa1001/remove
+
+References
+==========
+
+1. See Documentation/driver-api/vfio.rst for more information on VFIO.
+2. struct mdev_driver in include/linux/mdev.h
+3. struct mdev_parent_ops in include/linux/mdev.h
+4. struct vfio_iommu_driver_ops in include/linux/vfio.h
diff --git a/Documentation/driver-api/xilinx/index.rst b/Documentation/driver-api/xilinx/index.rst
new file mode 100644 (file)
index 0000000..13f7589
--- /dev/null
@@ -0,0 +1,16 @@
+
+===========
+Xilinx FPGA
+===========
+
+.. toctree::
+    :maxdepth: 1
+
+    eemi
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
diff --git a/Documentation/driver-model/devres.rst b/Documentation/driver-model/devres.rst
deleted file mode 100644 (file)
index 4ac9912..0000000
+++ /dev/null
@@ -1,414 +0,0 @@
-================================
-Devres - Managed Device Resource
-================================
-
-Tejun Heo      <teheo@suse.de>
-
-First draft    10 January 2007
-
-.. contents
-
-   1. Intro                    : Huh? Devres?
-   2. Devres                   : Devres in a nutshell
-   3. Devres Group             : Group devres'es and release them together
-   4. Details                  : Life time rules, calling context, ...
-   5. Overhead                 : How much do we have to pay for this?
-   6. List of managed interfaces: Currently implemented managed interfaces
-
-
-1. Intro
---------
-
-devres came up while trying to convert libata to use iomap.  Each
-iomapped address should be kept and unmapped on driver detach.  For
-example, a plain SFF ATA controller (that is, good old PCI IDE) in
-native mode makes use of 5 PCI BARs and all of them should be
-maintained.
-
-As with many other device drivers, libata low level drivers have
-sufficient bugs in ->remove and ->probe failure path.  Well, yes,
-that's probably because libata low level driver developers are lazy
-bunch, but aren't all low level driver developers?  After spending a
-day fiddling with braindamaged hardware with no document or
-braindamaged document, if it's finally working, well, it's working.
-
-For one reason or another, low level drivers don't receive as much
-attention or testing as core code, and bugs on driver detach or
-initialization failure don't happen often enough to be noticeable.
-Init failure path is worse because it's much less travelled while
-needs to handle multiple entry points.
-
-So, many low level drivers end up leaking resources on driver detach
-and having half broken failure path implementation in ->probe() which
-would leak resources or even cause oops when failure occurs.  iomap
-adds more to this mix.  So do msi and msix.
-
-
-2. Devres
----------
-
-devres is basically linked list of arbitrarily sized memory areas
-associated with a struct device.  Each devres entry is associated with
-a release function.  A devres can be released in several ways.  No
-matter what, all devres entries are released on driver detach.  On
-release, the associated release function is invoked and then the
-devres entry is freed.
-
-Managed interface is created for resources commonly used by device
-drivers using devres.  For example, coherent DMA memory is acquired
-using dma_alloc_coherent().  The managed version is called
-dmam_alloc_coherent().  It is identical to dma_alloc_coherent() except
-for the DMA memory allocated using it is managed and will be
-automatically released on driver detach.  Implementation looks like
-the following::
-
-  struct dma_devres {
-       size_t          size;
-       void            *vaddr;
-       dma_addr_t      dma_handle;
-  };
-
-  static void dmam_coherent_release(struct device *dev, void *res)
-  {
-       struct dma_devres *this = res;
-
-       dma_free_coherent(dev, this->size, this->vaddr, this->dma_handle);
-  }
-
-  dmam_alloc_coherent(dev, size, dma_handle, gfp)
-  {
-       struct dma_devres *dr;
-       void *vaddr;
-
-       dr = devres_alloc(dmam_coherent_release, sizeof(*dr), gfp);
-       ...
-
-       /* alloc DMA memory as usual */
-       vaddr = dma_alloc_coherent(...);
-       ...
-
-       /* record size, vaddr, dma_handle in dr */
-       dr->vaddr = vaddr;
-       ...
-
-       devres_add(dev, dr);
-
-       return vaddr;
-  }
-
-If a driver uses dmam_alloc_coherent(), the area is guaranteed to be
-freed whether initialization fails half-way or the device gets
-detached.  If most resources are acquired using managed interface, a
-driver can have much simpler init and exit code.  Init path basically
-looks like the following::
-
-  my_init_one()
-  {
-       struct mydev *d;
-
-       d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL);
-       if (!d)
-               return -ENOMEM;
-
-       d->ring = dmam_alloc_coherent(...);
-       if (!d->ring)
-               return -ENOMEM;
-
-       if (check something)
-               return -EINVAL;
-       ...
-
-       return register_to_upper_layer(d);
-  }
-
-And exit path::
-
-  my_remove_one()
-  {
-       unregister_from_upper_layer(d);
-       shutdown_my_hardware();
-  }
-
-As shown above, low level drivers can be simplified a lot by using
-devres.  Complexity is shifted from less maintained low level drivers
-to better maintained higher layer.  Also, as init failure path is
-shared with exit path, both can get more testing.
-
-Note though that when converting current calls or assignments to
-managed devm_* versions it is up to you to check if internal operations
-like allocating memory, have failed. Managed resources pertains to the
-freeing of these resources *only* - all other checks needed are still
-on you. In some cases this may mean introducing checks that were not
-necessary before moving to the managed devm_* calls.
-
-
-3. Devres group
----------------
-
-Devres entries can be grouped using devres group.  When a group is
-released, all contained normal devres entries and properly nested
-groups are released.  One usage is to rollback series of acquired
-resources on failure.  For example::
-
-  if (!devres_open_group(dev, NULL, GFP_KERNEL))
-       return -ENOMEM;
-
-  acquire A;
-  if (failed)
-       goto err;
-
-  acquire B;
-  if (failed)
-       goto err;
-  ...
-
-  devres_remove_group(dev, NULL);
-  return 0;
-
- err:
-  devres_release_group(dev, NULL);
-  return err_code;
-
-As resource acquisition failure usually means probe failure, constructs
-like above are usually useful in midlayer driver (e.g. libata core
-layer) where interface function shouldn't have side effect on failure.
-For LLDs, just returning error code suffices in most cases.
-
-Each group is identified by `void *id`.  It can either be explicitly
-specified by @id argument to devres_open_group() or automatically
-created by passing NULL as @id as in the above example.  In both
-cases, devres_open_group() returns the group's id.  The returned id
-can be passed to other devres functions to select the target group.
-If NULL is given to those functions, the latest open group is
-selected.
-
-For example, you can do something like the following::
-
-  int my_midlayer_create_something()
-  {
-       if (!devres_open_group(dev, my_midlayer_create_something, GFP_KERNEL))
-               return -ENOMEM;
-
-       ...
-
-       devres_close_group(dev, my_midlayer_create_something);
-       return 0;
-  }
-
-  void my_midlayer_destroy_something()
-  {
-       devres_release_group(dev, my_midlayer_create_something);
-  }
-
-
-4. Details
-----------
-
-Lifetime of a devres entry begins on devres allocation and finishes
-when it is released or destroyed (removed and freed) - no reference
-counting.
-
-devres core guarantees atomicity to all basic devres operations and
-has support for single-instance devres types (atomic
-lookup-and-add-if-not-found).  Other than that, synchronizing
-concurrent accesses to allocated devres data is caller's
-responsibility.  This is usually non-issue because bus ops and
-resource allocations already do the job.
-
-For an example of single-instance devres type, read pcim_iomap_table()
-in lib/devres.c.
-
-All devres interface functions can be called without context if the
-right gfp mask is given.
-
-
-5. Overhead
------------
-
-Each devres bookkeeping info is allocated together with requested data
-area.  With debug option turned off, bookkeeping info occupies 16
-bytes on 32bit machines and 24 bytes on 64bit (three pointers rounded
-up to ull alignment).  If singly linked list is used, it can be
-reduced to two pointers (8 bytes on 32bit, 16 bytes on 64bit).
-
-Each devres group occupies 8 pointers.  It can be reduced to 6 if
-singly linked list is used.
-
-Memory space overhead on ahci controller with two ports is between 300
-and 400 bytes on 32bit machine after naive conversion (we can
-certainly invest a bit more effort into libata core layer).
-
-
-6. List of managed interfaces
------------------------------
-
-CLOCK
-  devm_clk_get()
-  devm_clk_get_optional()
-  devm_clk_put()
-  devm_clk_hw_register()
-  devm_of_clk_add_hw_provider()
-  devm_clk_hw_register_clkdev()
-
-DMA
-  dmaenginem_async_device_register()
-  dmam_alloc_coherent()
-  dmam_alloc_attrs()
-  dmam_free_coherent()
-  dmam_pool_create()
-  dmam_pool_destroy()
-
-DRM
-  devm_drm_dev_init()
-
-GPIO
-  devm_gpiod_get()
-  devm_gpiod_get_index()
-  devm_gpiod_get_index_optional()
-  devm_gpiod_get_optional()
-  devm_gpiod_put()
-  devm_gpiod_unhinge()
-  devm_gpiochip_add_data()
-  devm_gpio_request()
-  devm_gpio_request_one()
-  devm_gpio_free()
-
-I2C
-  devm_i2c_new_dummy_device()
-
-IIO
-  devm_iio_device_alloc()
-  devm_iio_device_free()
-  devm_iio_device_register()
-  devm_iio_device_unregister()
-  devm_iio_kfifo_allocate()
-  devm_iio_kfifo_free()
-  devm_iio_triggered_buffer_setup()
-  devm_iio_triggered_buffer_cleanup()
-  devm_iio_trigger_alloc()
-  devm_iio_trigger_free()
-  devm_iio_trigger_register()
-  devm_iio_trigger_unregister()
-  devm_iio_channel_get()
-  devm_iio_channel_release()
-  devm_iio_channel_get_all()
-  devm_iio_channel_release_all()
-
-INPUT
-  devm_input_allocate_device()
-
-IO region
-  devm_release_mem_region()
-  devm_release_region()
-  devm_release_resource()
-  devm_request_mem_region()
-  devm_request_region()
-  devm_request_resource()
-
-IOMAP
-  devm_ioport_map()
-  devm_ioport_unmap()
-  devm_ioremap()
-  devm_ioremap_nocache()
-  devm_ioremap_wc()
-  devm_ioremap_resource() : checks resource, requests memory region, ioremaps
-  devm_iounmap()
-  pcim_iomap()
-  pcim_iomap_regions() : do request_region() and iomap() on multiple BARs
-  pcim_iomap_table()   : array of mapped addresses indexed by BAR
-  pcim_iounmap()
-
-IRQ
-  devm_free_irq()
-  devm_request_any_context_irq()
-  devm_request_irq()
-  devm_request_threaded_irq()
-  devm_irq_alloc_descs()
-  devm_irq_alloc_desc()
-  devm_irq_alloc_desc_at()
-  devm_irq_alloc_desc_from()
-  devm_irq_alloc_descs_from()
-  devm_irq_alloc_generic_chip()
-  devm_irq_setup_generic_chip()
-  devm_irq_sim_init()
-
-LED
-  devm_led_classdev_register()
-  devm_led_classdev_unregister()
-
-MDIO
-  devm_mdiobus_alloc()
-  devm_mdiobus_alloc_size()
-  devm_mdiobus_free()
-
-MEM
-  devm_free_pages()
-  devm_get_free_pages()
-  devm_kasprintf()
-  devm_kcalloc()
-  devm_kfree()
-  devm_kmalloc()
-  devm_kmalloc_array()
-  devm_kmemdup()
-  devm_kstrdup()
-  devm_kvasprintf()
-  devm_kzalloc()
-
-MFD
-  devm_mfd_add_devices()
-
-MUX
-  devm_mux_chip_alloc()
-  devm_mux_chip_register()
-  devm_mux_control_get()
-
-PER-CPU MEM
-  devm_alloc_percpu()
-  devm_free_percpu()
-
-PCI
-  devm_pci_alloc_host_bridge()  : managed PCI host bridge allocation
-  devm_pci_remap_cfgspace()    : ioremap PCI configuration space
-  devm_pci_remap_cfg_resource()        : ioremap PCI configuration space resource
-  pcim_enable_device()         : after success, all PCI ops become managed
-  pcim_pin_device()            : keep PCI device enabled after release
-
-PHY
-  devm_usb_get_phy()
-  devm_usb_put_phy()
-
-PINCTRL
-  devm_pinctrl_get()
-  devm_pinctrl_put()
-  devm_pinctrl_register()
-  devm_pinctrl_unregister()
-
-POWER
-  devm_reboot_mode_register()
-  devm_reboot_mode_unregister()
-
-PWM
-  devm_pwm_get()
-  devm_pwm_put()
-
-REGULATOR
-  devm_regulator_bulk_get()
-  devm_regulator_get()
-  devm_regulator_put()
-  devm_regulator_register()
-
-RESET
-  devm_reset_control_get()
-  devm_reset_controller_register()
-
-SERDEV
-  devm_serdev_device_open()
-
-SLAVE DMA ENGINE
-  devm_acpi_dma_controller_register()
-
-SPI
-  devm_spi_register_master()
-
-WATCHDOG
-  devm_watchdog_register_device()
diff --git a/Documentation/driver-model/index.rst b/Documentation/driver-model/index.rst
deleted file mode 100644 (file)
index 9f85d57..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-:orphan:
-
-============
-Driver Model
-============
-
-.. toctree::
-   :maxdepth: 1
-
-   binding
-   bus
-   class
-   design-patterns
-   device
-   devres
-   driver
-   overview
-   platform
-   porting
-
-.. only::  subproject and html
-
-   Indices
-   =======
-
-   * :ref:`genindex`
diff --git a/Documentation/driver-model/porting.rst b/Documentation/driver-model/porting.rst
deleted file mode 100644 (file)
index ae4bf84..0000000
+++ /dev/null
@@ -1,448 +0,0 @@
-=======================================
-Porting Drivers to the New Driver Model
-=======================================
-
-Patrick Mochel
-
-7 January 2003
-
-
-Overview
-
-Please refer to `Documentation/driver-model/*.rst` for definitions of
-various driver types and concepts.
-
-Most of the work of porting devices drivers to the new model happens
-at the bus driver layer. This was intentional, to minimize the
-negative effect on kernel drivers, and to allow a gradual transition
-of bus drivers.
-
-In a nutshell, the driver model consists of a set of objects that can
-be embedded in larger, bus-specific objects. Fields in these generic
-objects can replace fields in the bus-specific objects.
-
-The generic objects must be registered with the driver model core. By
-doing so, they will exported via the sysfs filesystem. sysfs can be
-mounted by doing::
-
-       # mount -t sysfs sysfs /sys
-
-
-
-The Process
-
-Step 0: Read include/linux/device.h for object and function definitions.
-
-Step 1: Registering the bus driver.
-
-
-- Define a struct bus_type for the bus driver::
-
-    struct bus_type pci_bus_type = {
-          .name           = "pci",
-    };
-
-
-- Register the bus type.
-
-  This should be done in the initialization function for the bus type,
-  which is usually the module_init(), or equivalent, function::
-
-    static int __init pci_driver_init(void)
-    {
-            return bus_register(&pci_bus_type);
-    }
-
-    subsys_initcall(pci_driver_init);
-
-
-  The bus type may be unregistered (if the bus driver may be compiled
-  as a module) by doing::
-
-     bus_unregister(&pci_bus_type);
-
-
-- Export the bus type for others to use.
-
-  Other code may wish to reference the bus type, so declare it in a
-  shared header file and export the symbol.
-
-From include/linux/pci.h::
-
-  extern struct bus_type pci_bus_type;
-
-
-From file the above code appears in::
-
-  EXPORT_SYMBOL(pci_bus_type);
-
-
-
-- This will cause the bus to show up in /sys/bus/pci/ with two
-  subdirectories: 'devices' and 'drivers'::
-
-    # tree -d /sys/bus/pci/
-    /sys/bus/pci/
-    |-- devices
-    `-- drivers
-
-
-
-Step 2: Registering Devices.
-
-struct device represents a single device. It mainly contains metadata
-describing the relationship the device has to other entities.
-
-
-- Embed a struct device in the bus-specific device type::
-
-
-    struct pci_dev {
-           ...
-           struct  device  dev;            /* Generic device interface */
-           ...
-    };
-
-  It is recommended that the generic device not be the first item in
-  the struct to discourage programmers from doing mindless casts
-  between the object types. Instead macros, or inline functions,
-  should be created to convert from the generic object type::
-
-
-    #define to_pci_dev(n) container_of(n, struct pci_dev, dev)
-
-    or
-
-    static inline struct pci_dev * to_pci_dev(struct kobject * kobj)
-    {
-       return container_of(n, struct pci_dev, dev);
-    }
-
-  This allows the compiler to verify type-safety of the operations
-  that are performed (which is Good).
-
-
-- Initialize the device on registration.
-
-  When devices are discovered or registered with the bus type, the
-  bus driver should initialize the generic device. The most important
-  things to initialize are the bus_id, parent, and bus fields.
-
-  The bus_id is an ASCII string that contains the device's address on
-  the bus. The format of this string is bus-specific. This is
-  necessary for representing devices in sysfs.
-
-  parent is the physical parent of the device. It is important that
-  the bus driver sets this field correctly.
-
-  The driver model maintains an ordered list of devices that it uses
-  for power management. This list must be in order to guarantee that
-  devices are shutdown before their physical parents, and vice versa.
-  The order of this list is determined by the parent of registered
-  devices.
-
-  Also, the location of the device's sysfs directory depends on a
-  device's parent. sysfs exports a directory structure that mirrors
-  the device hierarchy. Accurately setting the parent guarantees that
-  sysfs will accurately represent the hierarchy.
-
-  The device's bus field is a pointer to the bus type the device
-  belongs to. This should be set to the bus_type that was declared
-  and initialized before.
-
-  Optionally, the bus driver may set the device's name and release
-  fields.
-
-  The name field is an ASCII string describing the device, like
-
-     "ATI Technologies Inc Radeon QD"
-
-  The release field is a callback that the driver model core calls
-  when the device has been removed, and all references to it have
-  been released. More on this in a moment.
-
-
-- Register the device.
-
-  Once the generic device has been initialized, it can be registered
-  with the driver model core by doing::
-
-       device_register(&dev->dev);
-
-  It can later be unregistered by doing::
-
-       device_unregister(&dev->dev);
-
-  This should happen on buses that support hotpluggable devices.
-  If a bus driver unregisters a device, it should not immediately free
-  it. It should instead wait for the driver model core to call the
-  device's release method, then free the bus-specific object.
-  (There may be other code that is currently referencing the device
-  structure, and it would be rude to free the device while that is
-  happening).
-
-
-  When the device is registered, a directory in sysfs is created.
-  The PCI tree in sysfs looks like::
-
-    /sys/devices/pci0/
-    |-- 00:00.0
-    |-- 00:01.0
-    |   `-- 01:00.0
-    |-- 00:02.0
-    |   `-- 02:1f.0
-    |       `-- 03:00.0
-    |-- 00:1e.0
-    |   `-- 04:04.0
-    |-- 00:1f.0
-    |-- 00:1f.1
-    |   |-- ide0
-    |   |   |-- 0.0
-    |   |   `-- 0.1
-    |   `-- ide1
-    |       `-- 1.0
-    |-- 00:1f.2
-    |-- 00:1f.3
-    `-- 00:1f.5
-
-  Also, symlinks are created in the bus's 'devices' directory
-  that point to the device's directory in the physical hierarchy::
-
-    /sys/bus/pci/devices/
-    |-- 00:00.0 -> ../../../devices/pci0/00:00.0
-    |-- 00:01.0 -> ../../../devices/pci0/00:01.0
-    |-- 00:02.0 -> ../../../devices/pci0/00:02.0
-    |-- 00:1e.0 -> ../../../devices/pci0/00:1e.0
-    |-- 00:1f.0 -> ../../../devices/pci0/00:1f.0
-    |-- 00:1f.1 -> ../../../devices/pci0/00:1f.1
-    |-- 00:1f.2 -> ../../../devices/pci0/00:1f.2
-    |-- 00:1f.3 -> ../../../devices/pci0/00:1f.3
-    |-- 00:1f.5 -> ../../../devices/pci0/00:1f.5
-    |-- 01:00.0 -> ../../../devices/pci0/00:01.0/01:00.0
-    |-- 02:1f.0 -> ../../../devices/pci0/00:02.0/02:1f.0
-    |-- 03:00.0 -> ../../../devices/pci0/00:02.0/02:1f.0/03:00.0
-    `-- 04:04.0 -> ../../../devices/pci0/00:1e.0/04:04.0
-
-
-
-Step 3: Registering Drivers.
-
-struct device_driver is a simple driver structure that contains a set
-of operations that the driver model core may call.
-
-
-- Embed a struct device_driver in the bus-specific driver.
-
-  Just like with devices, do something like::
-
-    struct pci_driver {
-           ...
-           struct device_driver    driver;
-    };
-
-
-- Initialize the generic driver structure.
-
-  When the driver registers with the bus (e.g. doing pci_register_driver()),
-  initialize the necessary fields of the driver: the name and bus
-  fields.
-
-
-- Register the driver.
-
-  After the generic driver has been initialized, call::
-
-       driver_register(&drv->driver);
-
-  to register the driver with the core.
-
-  When the driver is unregistered from the bus, unregister it from the
-  core by doing::
-
-        driver_unregister(&drv->driver);
-
-  Note that this will block until all references to the driver have
-  gone away. Normally, there will not be any.
-
-
-- Sysfs representation.
-
-  Drivers are exported via sysfs in their bus's 'driver's directory.
-  For example::
-
-    /sys/bus/pci/drivers/
-    |-- 3c59x
-    |-- Ensoniq AudioPCI
-    |-- agpgart-amdk7
-    |-- e100
-    `-- serial
-
-
-Step 4: Define Generic Methods for Drivers.
-
-struct device_driver defines a set of operations that the driver model
-core calls. Most of these operations are probably similar to
-operations the bus already defines for drivers, but taking different
-parameters.
-
-It would be difficult and tedious to force every driver on a bus to
-simultaneously convert their drivers to generic format. Instead, the
-bus driver should define single instances of the generic methods that
-forward call to the bus-specific drivers. For instance::
-
-
-  static int pci_device_remove(struct device * dev)
-  {
-          struct pci_dev * pci_dev = to_pci_dev(dev);
-          struct pci_driver * drv = pci_dev->driver;
-
-          if (drv) {
-                  if (drv->remove)
-                          drv->remove(pci_dev);
-                  pci_dev->driver = NULL;
-          }
-          return 0;
-  }
-
-
-The generic driver should be initialized with these methods before it
-is registered::
-
-        /* initialize common driver fields */
-        drv->driver.name = drv->name;
-        drv->driver.bus = &pci_bus_type;
-        drv->driver.probe = pci_device_probe;
-        drv->driver.resume = pci_device_resume;
-        drv->driver.suspend = pci_device_suspend;
-        drv->driver.remove = pci_device_remove;
-
-        /* register with core */
-        driver_register(&drv->driver);
-
-
-Ideally, the bus should only initialize the fields if they are not
-already set. This allows the drivers to implement their own generic
-methods.
-
-
-Step 5: Support generic driver binding.
-
-The model assumes that a device or driver can be dynamically
-registered with the bus at any time. When registration happens,
-devices must be bound to a driver, or drivers must be bound to all
-devices that it supports.
-
-A driver typically contains a list of device IDs that it supports. The
-bus driver compares these IDs to the IDs of devices registered with it.
-The format of the device IDs, and the semantics for comparing them are
-bus-specific, so the generic model does attempt to generalize them.
-
-Instead, a bus may supply a method in struct bus_type that does the
-comparison::
-
-  int (*match)(struct device * dev, struct device_driver * drv);
-
-match should return positive value if the driver supports the device,
-and zero otherwise. It may also return error code (for example
--EPROBE_DEFER) if determining that given driver supports the device is
-not possible.
-
-When a device is registered, the bus's list of drivers is iterated
-over. bus->match() is called for each one until a match is found.
-
-When a driver is registered, the bus's list of devices is iterated
-over. bus->match() is called for each device that is not already
-claimed by a driver.
-
-When a device is successfully bound to a driver, device->driver is
-set, the device is added to a per-driver list of devices, and a
-symlink is created in the driver's sysfs directory that points to the
-device's physical directory::
-
-  /sys/bus/pci/drivers/
-  |-- 3c59x
-  |   `-- 00:0b.0 -> ../../../../devices/pci0/00:0b.0
-  |-- Ensoniq AudioPCI
-  |-- agpgart-amdk7
-  |   `-- 00:00.0 -> ../../../../devices/pci0/00:00.0
-  |-- e100
-  |   `-- 00:0c.0 -> ../../../../devices/pci0/00:0c.0
-  `-- serial
-
-
-This driver binding should replace the existing driver binding
-mechanism the bus currently uses.
-
-
-Step 6: Supply a hotplug callback.
-
-Whenever a device is registered with the driver model core, the
-userspace program /sbin/hotplug is called to notify userspace.
-Users can define actions to perform when a device is inserted or
-removed.
-
-The driver model core passes several arguments to userspace via
-environment variables, including
-
-- ACTION: set to 'add' or 'remove'
-- DEVPATH: set to the device's physical path in sysfs.
-
-A bus driver may also supply additional parameters for userspace to
-consume. To do this, a bus must implement the 'hotplug' method in
-struct bus_type::
-
-     int (*hotplug) (struct device *dev, char **envp,
-                     int num_envp, char *buffer, int buffer_size);
-
-This is called immediately before /sbin/hotplug is executed.
-
-
-Step 7: Cleaning up the bus driver.
-
-The generic bus, device, and driver structures provide several fields
-that can replace those defined privately to the bus driver.
-
-- Device list.
-
-struct bus_type contains a list of all devices registered with the bus
-type. This includes all devices on all instances of that bus type.
-An internal list that the bus uses may be removed, in favor of using
-this one.
-
-The core provides an iterator to access these devices::
-
-  int bus_for_each_dev(struct bus_type * bus, struct device * start,
-                       void * data, int (*fn)(struct device *, void *));
-
-
-- Driver list.
-
-struct bus_type also contains a list of all drivers registered with
-it. An internal list of drivers that the bus driver maintains may
-be removed in favor of using the generic one.
-
-The drivers may be iterated over, like devices::
-
-  int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
-                       void * data, int (*fn)(struct device_driver *, void *));
-
-
-Please see drivers/base/bus.c for more information.
-
-
-- rwsem
-
-struct bus_type contains an rwsem that protects all core accesses to
-the device and driver lists. This can be used by the bus driver
-internally, and should be used when accessing the device or driver
-lists the bus maintains.
-
-
-- Device and driver fields.
-
-Some of the fields in struct device and struct device_driver duplicate
-fields in the bus-specific representations of these objects. Feel free
-to remove the bus-specific ones and favor the generic ones. Note
-though, that this will likely mean fixing up all the drivers that
-reference the bus-specific fields (though those should all be 1-line
-changes).
diff --git a/Documentation/early-userspace/README b/Documentation/early-userspace/README
deleted file mode 100644 (file)
index 955d667..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-Early userspace support
-=======================
-
-Last update: 2004-12-20 tlh
-
-
-"Early userspace" is a set of libraries and programs that provide
-various pieces of functionality that are important enough to be
-available while a Linux kernel is coming up, but that don't need to be
-run inside the kernel itself.
-
-It consists of several major infrastructure components:
-
-- gen_init_cpio, a program that builds a cpio-format archive
-  containing a root filesystem image.  This archive is compressed, and
-  the compressed image is linked into the kernel image.
-- initramfs, a chunk of code that unpacks the compressed cpio image
-  midway through the kernel boot process.
-- klibc, a userspace C library, currently packaged separately, that is
-  optimized for correctness and small size.
-
-The cpio file format used by initramfs is the "newc" (aka "cpio -H newc")
-format, and is documented in the file "buffer-format.txt".  There are
-two ways to add an early userspace image: specify an existing cpio
-archive to be used as the image or have the kernel build process build
-the image from specifications.
-
-CPIO ARCHIVE method
-
-You can create a cpio archive that contains the early userspace image.
-Your cpio archive should be specified in CONFIG_INITRAMFS_SOURCE and it
-will be used directly.  Only a single cpio file may be specified in
-CONFIG_INITRAMFS_SOURCE and directory and file names are not allowed in
-combination with a cpio archive.
-
-IMAGE BUILDING method
-
-The kernel build process can also build an early userspace image from
-source parts rather than supplying a cpio archive.  This method provides
-a way to create images with root-owned files even though the image was
-built by an unprivileged user.
-
-The image is specified as one or more sources in
-CONFIG_INITRAMFS_SOURCE.  Sources can be either directories or files -
-cpio archives are *not* allowed when building from sources.
-
-A source directory will have it and all of its contents packaged.  The
-specified directory name will be mapped to '/'.  When packaging a
-directory, limited user and group ID translation can be performed.
-INITRAMFS_ROOT_UID can be set to a user ID that needs to be mapped to
-user root (0).  INITRAMFS_ROOT_GID can be set to a group ID that needs
-to be mapped to group root (0).
-
-A source file must be directives in the format required by the
-usr/gen_init_cpio utility (run 'usr/gen_init_cpio -h' to get the
-file format).  The directives in the file will be passed directly to
-usr/gen_init_cpio.
-
-When a combination of directories and files are specified then the
-initramfs image will be an aggregate of all of them.  In this way a user
-can create a 'root-image' directory and install all files into it.
-Because device-special files cannot be created by a unprivileged user,
-special files can be listed in a 'root-files' file.  Both 'root-image'
-and 'root-files' can be listed in CONFIG_INITRAMFS_SOURCE and a complete
-early userspace image can be built by an unprivileged user.
-
-As a technical note, when directories and files are specified, the
-entire CONFIG_INITRAMFS_SOURCE is passed to
-usr/gen_initramfs_list.sh.  This means that CONFIG_INITRAMFS_SOURCE
-can really be interpreted as any legal argument to
-gen_initramfs_list.sh.  If a directory is specified as an argument then
-the contents are scanned, uid/gid translation is performed, and
-usr/gen_init_cpio file directives are output.  If a directory is
-specified as an argument to usr/gen_initramfs_list.sh then the
-contents of the file are simply copied to the output.  All of the output
-directives from directory scanning and file contents copying are
-processed by usr/gen_init_cpio.
-
-See also 'usr/gen_initramfs_list.sh -h'.
-
-Where's this all leading?
-=========================
-
-The klibc distribution contains some of the necessary software to make
-early userspace useful.  The klibc distribution is currently
-maintained separately from the kernel.
-
-You can obtain somewhat infrequent snapshots of klibc from
-https://www.kernel.org/pub/linux/libs/klibc/
-
-For active users, you are better off using the klibc git
-repository, at http://git.kernel.org/?p=libs/klibc/klibc.git
-
-The standalone klibc distribution currently provides three components,
-in addition to the klibc library:
-
-- ipconfig, a program that configures network interfaces.  It can
-  configure them statically, or use DHCP to obtain information
-  dynamically (aka "IP autoconfiguration").
-- nfsmount, a program that can mount an NFS filesystem.
-- kinit, the "glue" that uses ipconfig and nfsmount to replace the old
-  support for IP autoconfig, mount a filesystem over NFS, and continue
-  system boot using that filesystem as root.
-
-kinit is built as a single statically linked binary to save space.
-
-Eventually, several more chunks of kernel functionality will hopefully
-move to early userspace:
-
-- Almost all of init/do_mounts* (the beginning of this is already in
-  place)
-- ACPI table parsing
-- Insert unwieldy subsystem that doesn't really need to be in kernel
-  space here
-
-If kinit doesn't meet your current needs and you've got bytes to burn,
-the klibc distribution includes a small Bourne-compatible shell (ash)
-and a number of other utilities, so you can replace kinit and build
-custom initramfs images that meet your needs exactly.
-
-For questions and help, you can sign up for the early userspace
-mailing list at http://www.zytor.com/mailman/listinfo/klibc
-
-How does it work?
-=================
-
-The kernel has currently 3 ways to mount the root filesystem:
-
-a) all required device and filesystem drivers compiled into the kernel, no
-   initrd.  init/main.c:init() will call prepare_namespace() to mount the
-   final root filesystem, based on the root= option and optional init= to run
-   some other init binary than listed at the end of init/main.c:init().
-
-b) some device and filesystem drivers built as modules and stored in an
-   initrd.  The initrd must contain a binary '/linuxrc' which is supposed to
-   load these driver modules.  It is also possible to mount the final root
-   filesystem via linuxrc and use the pivot_root syscall.  The initrd is
-   mounted and executed via prepare_namespace().
-
-c) using initramfs.  The call to prepare_namespace() must be skipped.
-   This means that a binary must do all the work.  Said binary can be stored
-   into initramfs either via modifying usr/gen_init_cpio.c or via the new
-   initrd format, an cpio archive.  It must be called "/init".  This binary
-   is responsible to do all the things prepare_namespace() would do.
-
-   To maintain backwards compatibility, the /init binary will only run if it
-   comes via an initramfs cpio archive.  If this is not the case,
-   init/main.c:init() will run prepare_namespace() to mount the final root
-   and exec one of the predefined init binaries.
-
-Bryan O'Sullivan <bos@serpentine.com>
diff --git a/Documentation/early-userspace/buffer-format.txt b/Documentation/early-userspace/buffer-format.txt
deleted file mode 100644 (file)
index e1fd7f9..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-                      initramfs buffer format
-                      -----------------------
-
-                      Al Viro, H. Peter Anvin
-                     Last revision: 2002-01-13
-
-Starting with kernel 2.5.x, the old "initial ramdisk" protocol is
-getting {replaced/complemented} with the new "initial ramfs"
-(initramfs) protocol.  The initramfs contents is passed using the same
-memory buffer protocol used by the initrd protocol, but the contents
-is different.  The initramfs buffer contains an archive which is
-expanded into a ramfs filesystem; this document details the format of
-the initramfs buffer format.
-
-The initramfs buffer format is based around the "newc" or "crc" CPIO
-formats, and can be created with the cpio(1) utility.  The cpio
-archive can be compressed using gzip(1).  One valid version of an
-initramfs buffer is thus a single .cpio.gz file.
-
-The full format of the initramfs buffer is defined by the following
-grammar, where:
-       *       is used to indicate "0 or more occurrences of"
-       (|)     indicates alternatives
-       +       indicates concatenation
-       GZIP()  indicates the gzip(1) of the operand
-       ALGN(n) means padding with null bytes to an n-byte boundary
-
-       initramfs  := ("\0" | cpio_archive | cpio_gzip_archive)*
-
-       cpio_gzip_archive := GZIP(cpio_archive)
-
-       cpio_archive := cpio_file* + (<nothing> | cpio_trailer)
-
-       cpio_file := ALGN(4) + cpio_header + filename + "\0" + ALGN(4) + data
-
-       cpio_trailer := ALGN(4) + cpio_header + "TRAILER!!!\0" + ALGN(4)
-
-
-In human terms, the initramfs buffer contains a collection of
-compressed and/or uncompressed cpio archives (in the "newc" or "crc"
-formats); arbitrary amounts zero bytes (for padding) can be added
-between members.
-
-The cpio "TRAILER!!!" entry (cpio end-of-archive) is optional, but is
-not ignored; see "handling of hard links" below.
-
-The structure of the cpio_header is as follows (all fields contain
-hexadecimal ASCII numbers fully padded with '0' on the left to the
-full width of the field, for example, the integer 4780 is represented
-by the ASCII string "000012ac"):
-
-Field name    Field size        Meaning
-c_magic              6 bytes            The string "070701" or "070702"
-c_ino        8 bytes            File inode number
-c_mode       8 bytes            File mode and permissions
-c_uid        8 bytes            File uid
-c_gid        8 bytes            File gid
-c_nlink              8 bytes            Number of links
-c_mtime              8 bytes            Modification time
-c_filesize    8 bytes           Size of data field
-c_maj        8 bytes            Major part of file device number
-c_min        8 bytes            Minor part of file device number
-c_rmaj       8 bytes            Major part of device node reference
-c_rmin       8 bytes            Minor part of device node reference
-c_namesize    8 bytes           Length of filename, including final \0
-c_chksum      8 bytes           Checksum of data field if c_magic is 070702;
-                                otherwise zero
-
-The c_mode field matches the contents of st_mode returned by stat(2)
-on Linux, and encodes the file type and file permissions.
-
-The c_filesize should be zero for any file which is not a regular file
-or symlink.
-
-The c_chksum field contains a simple 32-bit unsigned sum of all the
-bytes in the data field.  cpio(1) refers to this as "crc", which is
-clearly incorrect (a cyclic redundancy check is a different and
-significantly stronger integrity check), however, this is the
-algorithm used.
-
-If the filename is "TRAILER!!!" this is actually an end-of-archive
-marker; the c_filesize for an end-of-archive marker must be zero.
-
-
-*** Handling of hard links
-
-When a nondirectory with c_nlink > 1 is seen, the (c_maj,c_min,c_ino)
-tuple is looked up in a tuple buffer.  If not found, it is entered in
-the tuple buffer and the entry is created as usual; if found, a hard
-link rather than a second copy of the file is created.  It is not
-necessary (but permitted) to include a second copy of the file
-contents; if the file contents is not included, the c_filesize field
-should be set to zero to indicate no data section follows.  If data is
-present, the previous instance of the file is overwritten; this allows
-the data-carrying instance of a file to occur anywhere in the sequence
-(GNU cpio is reported to attach the data to the last instance of a
-file only.)
-
-c_filesize must not be zero for a symlink.
-
-When a "TRAILER!!!" end-of-archive marker is seen, the tuple buffer is
-reset.  This permits archives which are generated independently to be
-concatenated.
-
-To combine file data from different sources (without having to
-regenerate the (c_maj,c_min,c_ino) fields), therefore, either one of
-the following techniques can be used:
-
-a) Separate the different file data sources with a "TRAILER!!!"
-   end-of-archive marker, or
-
-b) Make sure c_nlink == 1 for all nondirectory entries.
diff --git a/Documentation/eisa.txt b/Documentation/eisa.txt
deleted file mode 100644 (file)
index f388545..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-================
-EISA bus support
-================
-
-:Author: Marc Zyngier <maz@wild-wind.fr.eu.org>
-
-This document groups random notes about porting EISA drivers to the
-new EISA/sysfs API.
-
-Starting from version 2.5.59, the EISA bus is almost given the same
-status as other much more mainstream busses such as PCI or USB. This
-has been possible through sysfs, which defines a nice enough set of
-abstractions to manage busses, devices and drivers.
-
-Although the new API is quite simple to use, converting existing
-drivers to the new infrastructure is not an easy task (mostly because
-detection code is generally also used to probe ISA cards). Moreover,
-most EISA drivers are among the oldest Linux drivers so, as you can
-imagine, some dust has settled here over the years.
-
-The EISA infrastructure is made up of three parts:
-
-    - The bus code implements most of the generic code. It is shared
-      among all the architectures that the EISA code runs on. It
-      implements bus probing (detecting EISA cards available on the bus),
-      allocates I/O resources, allows fancy naming through sysfs, and
-      offers interfaces for driver to register.
-
-    - The bus root driver implements the glue between the bus hardware
-      and the generic bus code. It is responsible for discovering the
-      device implementing the bus, and setting it up to be latter probed
-      by the bus code. This can go from something as simple as reserving
-      an I/O region on x86, to the rather more complex, like the hppa
-      EISA code. This is the part to implement in order to have EISA
-      running on an "new" platform.
-
-    - The driver offers the bus a list of devices that it manages, and
-      implements the necessary callbacks to probe and release devices
-      whenever told to.
-
-Every function/structure below lives in <linux/eisa.h>, which depends
-heavily on <linux/device.h>.
-
-Bus root driver
-===============
-
-::
-
-       int eisa_root_register (struct eisa_root_device *root);
-
-The eisa_root_register function is used to declare a device as the
-root of an EISA bus. The eisa_root_device structure holds a reference
-to this device, as well as some parameters for probing purposes::
-
-       struct eisa_root_device {
-               struct device   *dev;    /* Pointer to bridge device */
-               struct resource *res;
-               unsigned long    bus_base_addr;
-               int              slots;  /* Max slot number */
-               int              force_probe; /* Probe even when no slot 0 */
-               u64              dma_mask; /* from bridge device */
-               int              bus_nr; /* Set by eisa_root_register */
-               struct resource  eisa_root_res; /* ditto */
-       };
-
-============= ======================================================
-node          used for eisa_root_register internal purpose
-dev           pointer to the root device
-res           root device I/O resource
-bus_base_addr slot 0 address on this bus
-slots        max slot number to probe
-force_probe   Probe even when slot 0 is empty (no EISA mainboard)
-dma_mask      Default DMA mask. Usually the bridge device dma_mask.
-bus_nr       unique bus id, set by eisa_root_register
-============= ======================================================
-
-Driver
-======
-
-::
-
-       int eisa_driver_register (struct eisa_driver *edrv);
-       void eisa_driver_unregister (struct eisa_driver *edrv);
-
-Clear enough ?
-
-::
-
-       struct eisa_device_id {
-               char sig[EISA_SIG_LEN];
-               unsigned long driver_data;
-       };
-
-       struct eisa_driver {
-               const struct eisa_device_id *id_table;
-               struct device_driver         driver;
-       };
-
-=============== ====================================================
-id_table       an array of NULL terminated EISA id strings,
-               followed by an empty string. Each string can
-               optionally be paired with a driver-dependent value
-               (driver_data).
-
-driver         a generic driver, such as described in
-               Documentation/driver-model/driver.rst. Only .name,
-               .probe and .remove members are mandatory.
-=============== ====================================================
-
-An example is the 3c59x driver::
-
-       static struct eisa_device_id vortex_eisa_ids[] = {
-               { "TCM5920", EISA_3C592_OFFSET },
-               { "TCM5970", EISA_3C597_OFFSET },
-               { "" }
-       };
-
-       static struct eisa_driver vortex_eisa_driver = {
-               .id_table = vortex_eisa_ids,
-               .driver   = {
-                       .name    = "3c59x",
-                       .probe   = vortex_eisa_probe,
-                       .remove  = vortex_eisa_remove
-               }
-       };
-
-Device
-======
-
-The sysfs framework calls .probe and .remove functions upon device
-discovery and removal (note that the .remove function is only called
-when driver is built as a module).
-
-Both functions are passed a pointer to a 'struct device', which is
-encapsulated in a 'struct eisa_device' described as follows::
-
-       struct eisa_device {
-               struct eisa_device_id id;
-               int                   slot;
-               int                   state;
-               unsigned long         base_addr;
-               struct resource       res[EISA_MAX_RESOURCES];
-               u64                   dma_mask;
-               struct device         dev; /* generic device */
-       };
-
-======== ============================================================
-id      EISA id, as read from device. id.driver_data is set from the
-        matching driver EISA id.
-slot    slot number which the device was detected on
-state    set of flags indicating the state of the device. Current
-        flags are EISA_CONFIG_ENABLED and EISA_CONFIG_FORCED.
-res     set of four 256 bytes I/O regions allocated to this device
-dma_mask DMA mask set from the parent device.
-dev     generic device (see Documentation/driver-model/device.rst)
-======== ============================================================
-
-You can get the 'struct eisa_device' from 'struct device' using the
-'to_eisa_device' macro.
-
-Misc stuff
-==========
-
-::
-
-       void eisa_set_drvdata (struct eisa_device *edev, void *data);
-
-Stores data into the device's driver_data area.
-
-::
-
-       void *eisa_get_drvdata (struct eisa_device *edev):
-
-Gets the pointer previously stored into the device's driver_data area.
-
-::
-
-       int eisa_get_region_index (void *addr);
-
-Returns the region number (0 <= x < EISA_MAX_RESOURCES) of a given
-address.
-
-Kernel parameters
-=================
-
-eisa_bus.enable_dev
-       A comma-separated list of slots to be enabled, even if the firmware
-       set the card as disabled. The driver must be able to properly
-       initialize the device in such conditions.
-
-eisa_bus.disable_dev
-       A comma-separated list of slots to be enabled, even if the firmware
-       set the card as enabled. The driver won't be called to handle this
-       device.
-
-virtual_root.force_probe
-       Force the probing code to probe EISA slots even when it cannot find an
-       EISA compliant mainboard (nothing appears on slot 0). Defaults to 0
-       (don't force), and set to 1 (force probing) when either
-       CONFIG_ALPHA_JENSEN or CONFIG_EISA_VLB_PRIMING are set.
-
-Random notes
-============
-
-Converting an EISA driver to the new API mostly involves *deleting*
-code (since probing is now in the core EISA code). Unfortunately, most
-drivers share their probing routine between ISA, and EISA. Special
-care must be taken when ripping out the EISA code, so other busses
-won't suffer from these surgical strikes...
-
-You *must not* expect any EISA device to be detected when returning
-from eisa_driver_register, since the chances are that the bus has not
-yet been probed. In fact, that's what happens most of the time (the
-bus root driver usually kicks in rather late in the boot process).
-Unfortunately, most drivers are doing the probing by themselves, and
-expect to have explored the whole machine when they exit their probe
-routine.
-
-For example, switching your favorite EISA SCSI card to the "hotplug"
-model is "the right thing"(tm).
-
-Thanks
-======
-
-I'd like to thank the following people for their help:
-
-- Xavier Benigni for lending me a wonderful Alpha Jensen,
-- James Bottomley, Jeff Garzik for getting this stuff into the kernel,
-- Andries Brouwer for contributing numerous EISA ids,
-- Catrin Jones for coping with far too many machines at home.
index 92b5639..8408a8a 100644 (file)
@@ -1,4 +1,4 @@
-:orphan:
+.. SPDX-License-Identifier: GPL-2.0
 
 ===============
 fault-injection
index 1da65b9..ebca417 100644 (file)
@@ -187,7 +187,7 @@ the hardware. Thus, in a VGA console::
 Assuming the VGA driver can be unloaded, one must first unbind the VGA driver
 from the console layer before unloading the driver.  The VGA driver cannot be
 unloaded if it is still bound to the console layer. (See
-Documentation/console/console.txt for more information).
+Documentation/driver-api/console.rst for more information).
 
 This is more complicated in the case of the framebuffer console (fbcon),
 because fbcon is an intermediate layer between the console and the drivers::
@@ -204,7 +204,7 @@ fbcon. Thus, there is no need to explicitly unbind the fbdev drivers from
 fbcon.
 
 So, how do we unbind fbcon from the console? Part of the answer is in
-Documentation/console/console.txt. To summarize:
+Documentation/driver-api/console.rst. To summarize:
 
 Echo a value to the bind file that represents the framebuffer console
 driver. So assuming vtcon1 represents fbcon, then::
index d473137..baf0239 100644 (file)
@@ -1,4 +1,4 @@
-:orphan:
+.. SPDX-License-Identifier: GPL-2.0
 
 ============
 Frame Buffer
index 2ed0dfb..6821c87 100644 (file)
@@ -30,7 +30,7 @@ How to use it?
 ==============
 
 Switching modes is done using the vga=... boot parameter.  Read
-Documentation/svga.txt for details.
+Documentation/admin-guide/svga.rst for details.
 
 You should compile in both vgacon (for text mode) and vesafb (for
 graphics mode). Which of them takes over the console depends on
index 6131135..545262c 100644 (file)
@@ -481,7 +481,10 @@ kernel support.
 
 
 
-
+  struct coda_timespec {
+          int64_t         tv_sec;         /* seconds */
+          long            tv_nsec;        /* nanoseconds */
+  };
 
   struct coda_vattr {
           enum coda_vtype va_type;        /* vnode type (for create) */
@@ -493,9 +496,9 @@ kernel support.
           long            va_fileid;      /* file id */
           u_quad_t        va_size;        /* file size in bytes */
           long            va_blocksize;   /* blocksize preferred for i/o */
-          struct timespec va_atime;       /* time of last access */
-          struct timespec va_mtime;       /* time of last modification */
-          struct timespec va_ctime;       /* time file changed */
+          struct coda_timespec va_atime;  /* time of last access */
+          struct coda_timespec va_mtime;  /* time of last modification */
+          struct coda_timespec va_ctime;  /* time file changed */
           u_long          va_gen;         /* generation number of file */
           u_long          va_flags;       /* flags defined for file */
           dev_t           va_rdev;        /* device special file represents */
index 6d2c0d3..6797294 100644 (file)
@@ -76,7 +76,7 @@ exposure of uninitialized data through mmap.
 These filesystems may be used for inspiration:
 - ext2: see Documentation/filesystems/ext2.txt
 - ext4: see Documentation/filesystems/ext4/
-- xfs:  see Documentation/filesystems/xfs.txt
+- xfs:  see Documentation/admin-guide/xfs.rst
 
 
 Handling Media Errors
index d296312..ae43324 100644 (file)
@@ -239,7 +239,7 @@ rdinit=<executable file>
   A description of the process of mounting the root file system can be
   found in:
 
-    Documentation/early-userspace/README
+    Documentation/driver-api/early-userspace/early_userspace_support.rst
 
 
 
index 2813a19..6b7a41c 100644 (file)
@@ -428,8 +428,19 @@ release it yourself.
 --
 [mandatory]
        d_alloc_root() is gone, along with a lot of bugs caused by code
-misusing it.  Replacement: d_make_root(inode).  The difference is,
-d_make_root() drops the reference to inode if dentry allocation fails.  
+misusing it.  Replacement: d_make_root(inode).  On success d_make_root(inode)
+allocates and returns a new dentry instantiated with the passed in inode.
+On failure NULL is returned and the passed in inode is dropped so the reference
+to inode is consumed in all cases and failure handling need not do any cleanup
+for the inode.  If d_make_root(inode) is passed a NULL inode it returns NULL
+and also requires no further error handling. Typical usage is:
+
+       inode = foofs_new_inode(....);
+       s->s_root = d_make_root(inode);
+       if (!s->s_root)
+               /* Nothing needed for the inode cleanup */
+               return -ENOMEM;
+       ...
 
 --
 [mandatory]
index d750b69..99ca040 100644 (file)
@@ -486,8 +486,8 @@ replaced by copy-on-write) part of the underlying shmem object out on swap.
 "SwapPss" shows proportional swap share of this mapping. Unlike "Swap", this
 does not take into account swapped out page of underlying shmem objects.
 "Locked" indicates whether the mapping is locked in memory or not.
-"THPeligible" indicates whether the mapping is eligible for THP pages - 1 if
-true, 0 otherwise.
+"THPeligible" indicates whether the mapping is eligible for allocating THP
+pages - 1 if true, 0 otherwise. It just shows the current status.
 
 "VmFlags" field deserves a separate description. This member represents the kernel
 flags associated with the particular virtual memory area in two letter encoded
@@ -1500,7 +1500,7 @@ review the kernel documentation in the directory /usr/src/linux/Documentation.
 This chapter  is  heavily  based  on the documentation included in the pre 2.2
 kernels, and became part of it in version 2.2.1 of the Linux kernel.
 
-Please see: Documentation/sysctl/ directory for descriptions of these
+Please see: Documentation/admin-guide/sysctl/ directory for descriptions of these
 entries.
 
 ------------------------------------------------------------------------------
index 79637d2..97d42cc 100644 (file)
@@ -105,7 +105,7 @@ All this differs from the old initrd in several ways:
   - The old initrd file was a gzipped filesystem image (in some file format,
     such as ext2, that needed a driver built into the kernel), while the new
     initramfs archive is a gzipped cpio archive (like tar only simpler,
-    see cpio(1) and Documentation/early-userspace/buffer-format.txt).  The
+    see cpio(1) and Documentation/driver-api/early-userspace/buffer-format.rst).  The
     kernel's cpio extraction code is not only extremely small, it's also
     __init text and data that can be discarded during the boot process.
 
@@ -159,7 +159,7 @@ One advantage of the configuration file is that root access is not required to
 set permissions or create device nodes in the new archive.  (Note that those
 two example "file" entries expect to find files named "init.sh" and "busybox" in
 a directory called "initramfs", under the linux-2.6.* directory.  See
-Documentation/early-userspace/README for more details.)
+Documentation/driver-api/early-userspace/early_userspace_support.rst for more details.)
 
 The kernel does not depend on external cpio tools.  If you specify a
 directory instead of a configuration file, the kernel's build infrastructure
index 5b5311f..ddf15b1 100644 (file)
@@ -319,7 +319,7 @@ quick way to lookup the sysfs interface for a device from the result of
 a stat(2) operation.
 
 More information can driver-model specific features can be found in
-Documentation/driver-model/. 
+Documentation/driver-api/driver-model/.
 
 
 TODO: Finish this section.
index cad797a..5ecbc03 100644 (file)
@@ -98,7 +98,7 @@ A memory policy with a valid NodeList will be saved, as specified, for
 use at file creation time.  When a task allocates a file in the file
 system, the mount option memory policy will be applied with a NodeList,
 if any, modified by the calling task's cpuset constraints
-[See Documentation/cgroup-v1/cpusets.rst] and any optional flags, listed
+[See Documentation/admin-guide/cgroup-v1/cpusets.rst] and any optional flags, listed
 below.  If the resulting NodeLists is the empty set, the effective memory
 policy for the file will revert to "default" policy.
 
diff --git a/Documentation/filesystems/xfs.txt b/Documentation/filesystems/xfs.txt
deleted file mode 100644 (file)
index a5cbb5e..0000000
+++ /dev/null
@@ -1,470 +0,0 @@
-
-The SGI XFS Filesystem
-======================
-
-XFS is a high performance journaling filesystem which originated
-on the SGI IRIX platform.  It is completely multi-threaded, can
-support large files and large filesystems, extended attributes,
-variable block sizes, is extent based, and makes extensive use of
-Btrees (directories, extents, free space) to aid both performance
-and scalability.
-
-Refer to the documentation at https://xfs.wiki.kernel.org/
-for further details.  This implementation is on-disk compatible
-with the IRIX version of XFS.
-
-
-Mount Options
-=============
-
-When mounting an XFS filesystem, the following options are accepted.
-For boolean mount options, the names with the (*) suffix is the
-default behaviour.
-
-  allocsize=size
-       Sets the buffered I/O end-of-file preallocation size when
-       doing delayed allocation writeout (default size is 64KiB).
-       Valid values for this option are page size (typically 4KiB)
-       through to 1GiB, inclusive, in power-of-2 increments.
-
-       The default behaviour is for dynamic end-of-file
-       preallocation size, which uses a set of heuristics to
-       optimise the preallocation size based on the current
-       allocation patterns within the file and the access patterns
-       to the file. Specifying a fixed allocsize value turns off
-       the dynamic behaviour.
-
-  attr2
-  noattr2
-       The options enable/disable an "opportunistic" improvement to
-       be made in the way inline extended attributes are stored
-       on-disk.  When the new form is used for the first time when
-       attr2 is selected (either when setting or removing extended
-       attributes) the on-disk superblock feature bit field will be
-       updated to reflect this format being in use.
-
-       The default behaviour is determined by the on-disk feature
-       bit indicating that attr2 behaviour is active. If either
-       mount option it set, then that becomes the new default used
-       by the filesystem.
-
-       CRC enabled filesystems always use the attr2 format, and so
-       will reject the noattr2 mount option if it is set.
-
-  discard
-  nodiscard (*)
-       Enable/disable the issuing of commands to let the block
-       device reclaim space freed by the filesystem.  This is
-       useful for SSD devices, thinly provisioned LUNs and virtual
-       machine images, but may have a performance impact.
-
-       Note: It is currently recommended that you use the fstrim
-       application to discard unused blocks rather than the discard
-       mount option because the performance impact of this option
-       is quite severe.
-
-  grpid/bsdgroups
-  nogrpid/sysvgroups (*)
-       These options define what group ID a newly created file
-       gets.  When grpid is set, it takes the group ID of the
-       directory in which it is created; otherwise it takes the
-       fsgid of the current process, unless the directory has the
-       setgid bit set, in which case it takes the gid from the
-       parent directory, and also gets the setgid bit set if it is
-       a directory itself.
-
-  filestreams
-       Make the data allocator use the filestreams allocation mode
-       across the entire filesystem rather than just on directories
-       configured to use it.
-
-  ikeep
-  noikeep (*)
-       When ikeep is specified, XFS does not delete empty inode
-       clusters and keeps them around on disk.  When noikeep is
-       specified, empty inode clusters are returned to the free
-       space pool.
-
-  inode32
-  inode64 (*)
-       When inode32 is specified, it indicates that XFS limits
-       inode creation to locations which will not result in inode
-       numbers with more than 32 bits of significance.
-
-       When inode64 is specified, it indicates that XFS is allowed
-       to create inodes at any location in the filesystem,
-       including those which will result in inode numbers occupying
-       more than 32 bits of significance. 
-
-       inode32 is provided for backwards compatibility with older
-       systems and applications, since 64 bits inode numbers might
-       cause problems for some applications that cannot handle
-       large inode numbers.  If applications are in use which do
-       not handle inode numbers bigger than 32 bits, the inode32
-       option should be specified.
-
-
-  largeio
-  nolargeio (*)
-       If "nolargeio" is specified, the optimal I/O reported in
-       st_blksize by stat(2) will be as small as possible to allow
-       user applications to avoid inefficient read/modify/write
-       I/O.  This is typically the page size of the machine, as
-       this is the granularity of the page cache.
-
-       If "largeio" specified, a filesystem that was created with a
-       "swidth" specified will return the "swidth" value (in bytes)
-       in st_blksize. If the filesystem does not have a "swidth"
-       specified but does specify an "allocsize" then "allocsize"
-       (in bytes) will be returned instead. Otherwise the behaviour
-       is the same as if "nolargeio" was specified.
-
-  logbufs=value
-       Set the number of in-memory log buffers.  Valid numbers
-       range from 2-8 inclusive.
-
-       The default value is 8 buffers.
-
-       If the memory cost of 8 log buffers is too high on small
-       systems, then it may be reduced at some cost to performance
-       on metadata intensive workloads. The logbsize option below
-       controls the size of each buffer and so is also relevant to
-       this case.
-
-  logbsize=value
-       Set the size of each in-memory log buffer.  The size may be
-       specified in bytes, or in kilobytes with a "k" suffix.
-       Valid sizes for version 1 and version 2 logs are 16384 (16k)
-       and 32768 (32k).  Valid sizes for version 2 logs also
-       include 65536 (64k), 131072 (128k) and 262144 (256k). The
-       logbsize must be an integer multiple of the log
-       stripe unit configured at mkfs time.
-
-       The default value for for version 1 logs is 32768, while the
-       default value for version 2 logs is MAX(32768, log_sunit).
-
-  logdev=device and rtdev=device
-       Use an external log (metadata journal) and/or real-time device.
-       An XFS filesystem has up to three parts: a data section, a log
-       section, and a real-time section.  The real-time section is
-       optional, and the log section can be separate from the data
-       section or contained within it.
-
-  noalign
-       Data allocations will not be aligned at stripe unit
-       boundaries. This is only relevant to filesystems created
-       with non-zero data alignment parameters (sunit, swidth) by
-       mkfs.
-
-  norecovery
-       The filesystem will be mounted without running log recovery.
-       If the filesystem was not cleanly unmounted, it is likely to
-       be inconsistent when mounted in "norecovery" mode.
-       Some files or directories may not be accessible because of this.
-       Filesystems mounted "norecovery" must be mounted read-only or
-       the mount will fail.
-
-  nouuid
-       Don't check for double mounted file systems using the file
-       system uuid.  This is useful to mount LVM snapshot volumes,
-       and often used in combination with "norecovery" for mounting
-       read-only snapshots.
-
-  noquota
-       Forcibly turns off all quota accounting and enforcement
-       within the filesystem.
-
-  uquota/usrquota/uqnoenforce/quota
-       User disk quota accounting enabled, and limits (optionally)
-       enforced.  Refer to xfs_quota(8) for further details.
-
-  gquota/grpquota/gqnoenforce
-       Group disk quota accounting enabled and limits (optionally)
-       enforced.  Refer to xfs_quota(8) for further details.
-
-  pquota/prjquota/pqnoenforce
-       Project disk quota accounting enabled and limits (optionally)
-       enforced.  Refer to xfs_quota(8) for further details.
-
-  sunit=value and swidth=value
-       Used to specify the stripe unit and width for a RAID device
-       or a stripe volume.  "value" must be specified in 512-byte
-       block units. These options are only relevant to filesystems
-       that were created with non-zero data alignment parameters.
-
-       The sunit and swidth parameters specified must be compatible
-       with the existing filesystem alignment characteristics.  In
-       general, that means the only valid changes to sunit are
-       increasing it by a power-of-2 multiple. Valid swidth values
-       are any integer multiple of a valid sunit value.
-
-       Typically the only time these mount options are necessary if
-       after an underlying RAID device has had it's geometry
-       modified, such as adding a new disk to a RAID5 lun and
-       reshaping it.
-
-  swalloc
-       Data allocations will be rounded up to stripe width boundaries
-       when the current end of file is being extended and the file
-       size is larger than the stripe width size.
-
-  wsync
-       When specified, all filesystem namespace operations are
-       executed synchronously. This ensures that when the namespace
-       operation (create, unlink, etc) completes, the change to the
-       namespace is on stable storage. This is useful in HA setups
-       where failover must not result in clients seeing
-       inconsistent namespace presentation during or after a
-       failover event.
-
-
-Deprecated Mount Options
-========================
-
-  Name                         Removal Schedule
-  ----                         ----------------
-
-
-Removed Mount Options
-=====================
-
-  Name                         Removed
-  ----                         -------
-  delaylog/nodelaylog          v4.0
-  ihashsize                    v4.0
-  irixsgid                     v4.0
-  osyncisdsync/osyncisosync    v4.0
-  barrier                      v4.19
-  nobarrier                    v4.19
-
-
-sysctls
-=======
-
-The following sysctls are available for the XFS filesystem:
-
-  fs.xfs.stats_clear           (Min: 0  Default: 0  Max: 1)
-       Setting this to "1" clears accumulated XFS statistics
-       in /proc/fs/xfs/stat.  It then immediately resets to "0".
-
-  fs.xfs.xfssyncd_centisecs    (Min: 100  Default: 3000  Max: 720000)
-       The interval at which the filesystem flushes metadata
-       out to disk and runs internal cache cleanup routines.
-
-  fs.xfs.filestream_centisecs  (Min: 1  Default: 3000  Max: 360000)
-       The interval at which the filesystem ages filestreams cache
-       references and returns timed-out AGs back to the free stream
-       pool.
-
-  fs.xfs.speculative_prealloc_lifetime
-               (Units: seconds   Min: 1  Default: 300  Max: 86400)
-       The interval at which the background scanning for inodes
-       with unused speculative preallocation runs. The scan
-       removes unused preallocation from clean inodes and releases
-       the unused space back to the free pool.
-
-  fs.xfs.error_level           (Min: 0  Default: 3  Max: 11)
-       A volume knob for error reporting when internal errors occur.
-       This will generate detailed messages & backtraces for filesystem
-       shutdowns, for example.  Current threshold values are:
-
-               XFS_ERRLEVEL_OFF:       0
-               XFS_ERRLEVEL_LOW:       1
-               XFS_ERRLEVEL_HIGH:      5
-
-  fs.xfs.panic_mask            (Min: 0  Default: 0  Max: 256)
-       Causes certain error conditions to call BUG(). Value is a bitmask;
-       OR together the tags which represent errors which should cause panics:
-
-               XFS_NO_PTAG                     0
-               XFS_PTAG_IFLUSH                 0x00000001
-               XFS_PTAG_LOGRES                 0x00000002
-               XFS_PTAG_AILDELETE              0x00000004
-               XFS_PTAG_ERROR_REPORT           0x00000008
-               XFS_PTAG_SHUTDOWN_CORRUPT       0x00000010
-               XFS_PTAG_SHUTDOWN_IOERROR       0x00000020
-               XFS_PTAG_SHUTDOWN_LOGERROR      0x00000040
-               XFS_PTAG_FSBLOCK_ZERO           0x00000080
-               XFS_PTAG_VERIFIER_ERROR         0x00000100
-
-       This option is intended for debugging only.
-
-  fs.xfs.irix_symlink_mode     (Min: 0  Default: 0  Max: 1)
-       Controls whether symlinks are created with mode 0777 (default)
-       or whether their mode is affected by the umask (irix mode).
-
-  fs.xfs.irix_sgid_inherit     (Min: 0  Default: 0  Max: 1)
-       Controls files created in SGID directories.
-       If the group ID of the new file does not match the effective group
-       ID or one of the supplementary group IDs of the parent dir, the
-       ISGID bit is cleared if the irix_sgid_inherit compatibility sysctl
-       is set.
-
-  fs.xfs.inherit_sync          (Min: 0  Default: 1  Max: 1)
-       Setting this to "1" will cause the "sync" flag set
-       by the xfs_io(8) chattr command on a directory to be
-       inherited by files in that directory.
-
-  fs.xfs.inherit_nodump                (Min: 0  Default: 1  Max: 1)
-       Setting this to "1" will cause the "nodump" flag set
-       by the xfs_io(8) chattr command on a directory to be
-       inherited by files in that directory.
-
-  fs.xfs.inherit_noatime       (Min: 0  Default: 1  Max: 1)
-       Setting this to "1" will cause the "noatime" flag set
-       by the xfs_io(8) chattr command on a directory to be
-       inherited by files in that directory.
-
-  fs.xfs.inherit_nosymlinks    (Min: 0  Default: 1  Max: 1)
-       Setting this to "1" will cause the "nosymlinks" flag set
-       by the xfs_io(8) chattr command on a directory to be
-       inherited by files in that directory.
-
-  fs.xfs.inherit_nodefrag      (Min: 0  Default: 1  Max: 1)
-       Setting this to "1" will cause the "nodefrag" flag set
-       by the xfs_io(8) chattr command on a directory to be
-       inherited by files in that directory.
-
-  fs.xfs.rotorstep             (Min: 1  Default: 1  Max: 256)
-       In "inode32" allocation mode, this option determines how many
-       files the allocator attempts to allocate in the same allocation
-       group before moving to the next allocation group.  The intent
-       is to control the rate at which the allocator moves between
-       allocation groups when allocating extents for new files.
-
-Deprecated Sysctls
-==================
-
-None at present.
-
-
-Removed Sysctls
-===============
-
-  Name                         Removed
-  ----                         -------
-  fs.xfs.xfsbufd_centisec      v4.0
-  fs.xfs.age_buffer_centisecs  v4.0
-
-
-Error handling
-==============
-
-XFS can act differently according to the type of error found during its
-operation. The implementation introduces the following concepts to the error
-handler:
-
- -failure speed:
-       Defines how fast XFS should propagate an error upwards when a specific
-       error is found during the filesystem operation. It can propagate
-       immediately, after a defined number of retries, after a set time period,
-       or simply retry forever.
-
- -error classes:
-       Specifies the subsystem the error configuration will apply to, such as
-       metadata IO or memory allocation. Different subsystems will have
-       different error handlers for which behaviour can be configured.
-
- -error handlers:
-       Defines the behavior for a specific error.
-
-The filesystem behavior during an error can be set via sysfs files. Each
-error handler works independently - the first condition met by an error handler
-for a specific class will cause the error to be propagated rather than reset and
-retried.
-
-The action taken by the filesystem when the error is propagated is context
-dependent - it may cause a shut down in the case of an unrecoverable error,
-it may be reported back to userspace, or it may even be ignored because
-there's nothing useful we can with the error or anyone we can report it to (e.g.
-during unmount).
-
-The configuration files are organized into the following hierarchy for each
-mounted filesystem:
-
-  /sys/fs/xfs/<dev>/error/<class>/<error>/
-
-Where:
-  <dev>
-       The short device name of the mounted filesystem. This is the same device
-       name that shows up in XFS kernel error messages as "XFS(<dev>): ..."
-
-  <class>
-       The subsystem the error configuration belongs to. As of 4.9, the defined
-       classes are:
-
-               - "metadata": applies metadata buffer write IO
-
-  <error>
-       The individual error handler configurations.
-
-
-Each filesystem has "global" error configuration options defined in their top
-level directory:
-
-  /sys/fs/xfs/<dev>/error/
-
-  fail_at_unmount              (Min:  0  Default:  1  Max: 1)
-       Defines the filesystem error behavior at unmount time.
-
-       If set to a value of 1, XFS will override all other error configurations
-       during unmount and replace them with "immediate fail" characteristics.
-       i.e. no retries, no retry timeout. This will always allow unmount to
-       succeed when there are persistent errors present.
-
-       If set to 0, the configured retry behaviour will continue until all
-       retries and/or timeouts have been exhausted. This will delay unmount
-       completion when there are persistent errors, and it may prevent the
-       filesystem from ever unmounting fully in the case of "retry forever"
-       handler configurations.
-
-       Note: there is no guarantee that fail_at_unmount can be set while an
-       unmount is in progress. It is possible that the sysfs entries are
-       removed by the unmounting filesystem before a "retry forever" error
-       handler configuration causes unmount to hang, and hence the filesystem
-       must be configured appropriately before unmount begins to prevent
-       unmount hangs.
-
-Each filesystem has specific error class handlers that define the error
-propagation behaviour for specific errors. There is also a "default" error
-handler defined, which defines the behaviour for all errors that don't have
-specific handlers defined. Where multiple retry constraints are configuredi for
-a single error, the first retry configuration that expires will cause the error
-to be propagated. The handler configurations are found in the directory:
-
-  /sys/fs/xfs/<dev>/error/<class>/<error>/
-
-  max_retries                  (Min: -1  Default: Varies  Max: INTMAX)
-       Defines the allowed number of retries of a specific error before
-       the filesystem will propagate the error. The retry count for a given
-       error context (e.g. a specific metadata buffer) is reset every time
-       there is a successful completion of the operation.
-
-       Setting the value to "-1" will cause XFS to retry forever for this
-       specific error.
-
-       Setting the value to "0" will cause XFS to fail immediately when the
-       specific error is reported.
-
-       Setting the value to "N" (where 0 < N < Max) will make XFS retry the
-       operation "N" times before propagating the error.
-
-  retry_timeout_seconds                (Min:  -1  Default:  Varies  Max: 1 day)
-       Define the amount of time (in seconds) that the filesystem is
-       allowed to retry its operations when the specific error is
-       found.
-
-       Setting the value to "-1" will allow XFS to retry forever for this
-       specific error.
-
-       Setting the value to "0" will cause XFS to fail immediately when the
-       specific error is reported.
-
-       Setting the value to "N" (where 0 < N < Max) will allow XFS to retry the
-       operation for up to "N" seconds before propagating the error.
-
-Note: The default behaviour for a specific error handler is dependent on both
-the class and error context. For example, the default values for
-"metadata/ENODEV" are "0" rather than "-1" so that this error handler defaults
-to "fail immediately" behaviour. This is done because ENODEV is a fatal,
-unrecoverable error no matter how many times the metadata IO is retried.
index 1252617..0a72b63 100644 (file)
@@ -316,7 +316,7 @@ specifies the path to the controller. In order to use these GPIOs in Linux
 we need to translate them to the corresponding Linux GPIO descriptors.
 
 There is a standard GPIO API for that and is documented in
-Documentation/gpio/.
+Documentation/admin-guide/gpio/.
 
 In the above example we can get the corresponding two GPIO descriptors with
 a code like this::
index 2c87d1e..f80f956 100644 (file)
@@ -1,4 +1,4 @@
-:orphan:
+.. SPDX-License-Identifier: GPL-2.0
 
 ====
 fpga
diff --git a/Documentation/gpio/index.rst b/Documentation/gpio/index.rst
deleted file mode 100644 (file)
index 09a4a55..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-:orphan:
-
-====
-gpio
-====
-
-.. toctree::
-    :maxdepth: 1
-
-    sysfs
-
-.. only::  subproject and html
-
-   Indices
-   =======
-
-   * :ref:`genindex`
index af43249..737d66d 100644 (file)
@@ -1,4 +1,4 @@
-:orphan:
+.. SPDX-License-Identifier: GPL-2.0
 
 =============================
 Human Interface Devices (HID)
index 72da12a..fe91095 100644 (file)
@@ -9,7 +9,7 @@ Supported chips:
 
     Addresses scanned: PCI space
 
-    Datasheet: http://support.amd.com/us/Processor_TechDocs/32559.pdf
+    Datasheet: http://www.amd.com/system/files/TechDocs/32559.pdf
 
 Author: Rudolf Marek
 
index d5b05d3..452fc28 100644 (file)
@@ -89,7 +89,7 @@ increase the chances of your change being accepted.
   console. Excessive logging can seriously affect system performance.
 
 * Use devres functions whenever possible to allocate resources. For rationale
-  and supported functions, please see Documentation/driver-model/devres.rst.
+  and supported functions, please see Documentation/driver-api/driver-model/devres.rst.
   If a function is not supported by devres, consider using devm_add_action().
 
 * If the driver has a detect function, make sure it is silent. Debug messages
index ed640a2..6f03713 100644 (file)
@@ -136,6 +136,39 @@ The function will never sleep.
 
 ::
 
+  int hwspin_lock_timeout_raw(struct hwspinlock *hwlock, unsigned int timeout);
+
+Lock a previously-assigned hwspinlock with a timeout limit (specified in
+msecs). If the hwspinlock is already taken, the function will busy loop
+waiting for it to be released, but give up when the timeout elapses.
+
+Caution: User must protect the routine of getting hardware lock with mutex
+or spinlock to avoid dead-lock, that will let user can do some time-consuming
+or sleepable operations under the hardware lock.
+
+Returns 0 when successful and an appropriate error code otherwise (most
+notably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs).
+
+The function will never sleep.
+
+::
+
+  int hwspin_lock_timeout_in_atomic(struct hwspinlock *hwlock, unsigned int to);
+
+Lock a previously-assigned hwspinlock with a timeout limit (specified in
+msecs). If the hwspinlock is already taken, the function will busy loop
+waiting for it to be released, but give up when the timeout elapses.
+
+This function shall be called only from an atomic context and the timeout
+value shall not exceed a few msecs.
+
+Returns 0 when successful and an appropriate error code otherwise (most
+notably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs).
+
+The function will never sleep.
+
+::
+
   int hwspin_trylock(struct hwspinlock *hwlock);
 
 
@@ -186,6 +219,34 @@ The function will never sleep.
 
 ::
 
+  int hwspin_trylock_raw(struct hwspinlock *hwlock);
+
+Attempt to lock a previously-assigned hwspinlock, but immediately fail if
+it is already taken.
+
+Caution: User must protect the routine of getting hardware lock with mutex
+or spinlock to avoid dead-lock, that will let user can do some time-consuming
+or sleepable operations under the hardware lock.
+
+Returns 0 on success and an appropriate error code otherwise (most
+notably -EBUSY if the hwspinlock was already taken).
+The function will never sleep.
+
+::
+
+  int hwspin_trylock_in_atomic(struct hwspinlock *hwlock);
+
+Attempt to lock a previously-assigned hwspinlock, but immediately fail if
+it is already taken.
+
+This function shall be called only from an atomic context.
+
+Returns 0 on success and an appropriate error code otherwise (most
+notably -EBUSY if the hwspinlock was already taken).
+The function will never sleep.
+
+::
+
   void hwspin_unlock(struct hwspinlock *hwlock);
 
 Unlock a previously-locked hwspinlock. Always succeed, and can be called
@@ -222,6 +283,26 @@ the given flags. This function will never sleep.
 
 ::
 
+  void hwspin_unlock_raw(struct hwspinlock *hwlock);
+
+Unlock a previously-locked hwspinlock.
+
+The caller should **never** unlock an hwspinlock which is already unlocked.
+Doing so is considered a bug (there is no protection against this).
+This function will never sleep.
+
+::
+
+  void hwspin_unlock_in_atomic(struct hwspinlock *hwlock);
+
+Unlock a previously-locked hwspinlock.
+
+The caller should **never** unlock an hwspinlock which is already unlocked.
+Doing so is considered a bug (there is no protection against this).
+This function will never sleep.
+
+::
+
   int hwspin_lock_get_id(struct hwspinlock *hwlock);
 
 Retrieve id number of a given hwspinlock. This is needed when an
diff --git a/Documentation/ia64/IRQ-redir.txt b/Documentation/ia64/IRQ-redir.txt
deleted file mode 100644 (file)
index f7bd722..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-IRQ affinity on IA64 platforms
-------------------------------
-                           07.01.2002, Erich Focht <efocht@ess.nec.de>
-
-
-By writing to /proc/irq/IRQ#/smp_affinity the interrupt routing can be
-controlled. The behavior on IA64 platforms is slightly different from
-that described in Documentation/IRQ-affinity.txt for i386 systems.
-
-Because of the usage of SAPIC mode and physical destination mode the
-IRQ target is one particular CPU and cannot be a mask of several
-CPUs. Only the first non-zero bit is taken into account.
-
-
-Usage examples:
-
-The target CPU has to be specified as a hexadecimal CPU mask. The
-first non-zero bit is the selected CPU. This format has been kept for
-compatibility reasons with i386.
-
-Set the delivery mode of interrupt 41 to fixed and route the
-interrupts to CPU #3 (logical CPU number) (2^3=0x08):
-     echo "8" >/proc/irq/41/smp_affinity
-
-Set the default route for IRQ number 41 to CPU 6 in lowest priority
-delivery mode (redirectable):
-     echo "r 40" >/proc/irq/41/smp_affinity
-
-The output of the command
-     cat /proc/irq/IRQ#/smp_affinity
-gives the target CPU mask for the specified interrupt vector. If the CPU
-mask is preceded by the character "r", the interrupt is redirectable
-(i.e. lowest priority mode routing is used), otherwise its route is
-fixed.
-
-
-
-Initialization and default behavior:
-
-If the platform features IRQ redirection (info provided by SAL) all
-IO-SAPIC interrupts are initialized with CPU#0 as their default target
-and the routing is the so called "lowest priority mode" (actually
-fixed SAPIC mode with hint). The XTP chipset registers are used as hints
-for the IRQ routing. Currently in Linux XTP registers can have three
-values:
-       - minimal for an idle task,
-       - normal if any other task runs,
-       - maximal if the CPU is going to be switched off.
-The IRQ is routed to the CPU with lowest XTP register value, the
-search begins at the default CPU. Therefore most of the interrupts
-will be handled by CPU #0.
-
-If the platform doesn't feature interrupt redirection IOSAPIC fixed
-routing is used. The target CPUs are distributed in a round robin
-manner. IRQs will be routed only to the selected target CPUs. Check
-with
-        cat /proc/interrupts
-
-
-
-Comments:
-
-On large (multi-node) systems it is recommended to route the IRQs to
-the node to which the corresponding device is connected.
-For systems like the NEC AzusA we get IRQ node-affinity for free. This
-is because usually the chipsets on each node redirect the interrupts
-only to their own CPUs (as they cannot see the XTP registers on the
-other nodes).
-
diff --git a/Documentation/ia64/README b/Documentation/ia64/README
deleted file mode 100644 (file)
index aa17f21..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-        Linux kernel release 2.4.xx for the IA-64 Platform
-
-   These are the release notes for Linux version 2.4 for IA-64
-   platform.  This document provides information specific to IA-64
-   ONLY, to get additional information about the Linux kernel also
-   read the original Linux README provided with the kernel.
-
-INSTALLING the kernel:
-
- - IA-64 kernel installation is the same as the other platforms, see
-   original README for details.
-
-
-SOFTWARE REQUIREMENTS
-
-   Compiling and running this kernel requires an IA-64 compliant GCC
-   compiler.  And various software packages also compiled with an
-   IA-64 compliant GCC compiler.
-
-
-CONFIGURING the kernel:
-
-   Configuration is the same, see original README for details.
-
-
-COMPILING the kernel:
-
- - Compiling this kernel doesn't differ from other platform so read
-   the original README for details BUT make sure you have an IA-64
-   compliant GCC compiler.
-
-IA-64 SPECIFICS
-
- - General issues:
-
-    o Hardly any performance tuning has been done. Obvious targets
-      include the library routines (IP checksum, etc.). Less
-      obvious targets include making sure we don't flush the TLB
-      needlessly, etc.
-
-    o SMP locks cleanup/optimization
-
-    o IA32 support.  Currently experimental.  It mostly works.
diff --git a/Documentation/ia64/aliasing.rst b/Documentation/ia64/aliasing.rst
new file mode 100644 (file)
index 0000000..a08b36a
--- /dev/null
@@ -0,0 +1,246 @@
+==================================
+Memory Attribute Aliasing on IA-64
+==================================
+
+Bjorn Helgaas <bjorn.helgaas@hp.com>
+
+May 4, 2006
+
+
+Memory Attributes
+=================
+
+    Itanium supports several attributes for virtual memory references.
+    The attribute is part of the virtual translation, i.e., it is
+    contained in the TLB entry.  The ones of most interest to the Linux
+    kernel are:
+
+       ==              ======================
+        WB             Write-back (cacheable)
+       UC              Uncacheable
+       WC              Write-coalescing
+       ==              ======================
+
+    System memory typically uses the WB attribute.  The UC attribute is
+    used for memory-mapped I/O devices.  The WC attribute is uncacheable
+    like UC is, but writes may be delayed and combined to increase
+    performance for things like frame buffers.
+
+    The Itanium architecture requires that we avoid accessing the same
+    page with both a cacheable mapping and an uncacheable mapping[1].
+
+    The design of the chipset determines which attributes are supported
+    on which regions of the address space.  For example, some chipsets
+    support either WB or UC access to main memory, while others support
+    only WB access.
+
+Memory Map
+==========
+
+    Platform firmware describes the physical memory map and the
+    supported attributes for each region.  At boot-time, the kernel uses
+    the EFI GetMemoryMap() interface.  ACPI can also describe memory
+    devices and the attributes they support, but Linux/ia64 currently
+    doesn't use this information.
+
+    The kernel uses the efi_memmap table returned from GetMemoryMap() to
+    learn the attributes supported by each region of physical address
+    space.  Unfortunately, this table does not completely describe the
+    address space because some machines omit some or all of the MMIO
+    regions from the map.
+
+    The kernel maintains another table, kern_memmap, which describes the
+    memory Linux is actually using and the attribute for each region.
+    This contains only system memory; it does not contain MMIO space.
+
+    The kern_memmap table typically contains only a subset of the system
+    memory described by the efi_memmap.  Linux/ia64 can't use all memory
+    in the system because of constraints imposed by the identity mapping
+    scheme.
+
+    The efi_memmap table is preserved unmodified because the original
+    boot-time information is required for kexec.
+
+Kernel Identify Mappings
+========================
+
+    Linux/ia64 identity mappings are done with large pages, currently
+    either 16MB or 64MB, referred to as "granules."  Cacheable mappings
+    are speculative[2], so the processor can read any location in the
+    page at any time, independent of the programmer's intentions.  This
+    means that to avoid attribute aliasing, Linux can create a cacheable
+    identity mapping only when the entire granule supports cacheable
+    access.
+
+    Therefore, kern_memmap contains only full granule-sized regions that
+    can referenced safely by an identity mapping.
+
+    Uncacheable mappings are not speculative, so the processor will
+    generate UC accesses only to locations explicitly referenced by
+    software.  This allows UC identity mappings to cover granules that
+    are only partially populated, or populated with a combination of UC
+    and WB regions.
+
+User Mappings
+=============
+
+    User mappings are typically done with 16K or 64K pages.  The smaller
+    page size allows more flexibility because only 16K or 64K has to be
+    homogeneous with respect to memory attributes.
+
+Potential Attribute Aliasing Cases
+==================================
+
+    There are several ways the kernel creates new mappings:
+
+mmap of /dev/mem
+----------------
+
+       This uses remap_pfn_range(), which creates user mappings.  These
+       mappings may be either WB or UC.  If the region being mapped
+       happens to be in kern_memmap, meaning that it may also be mapped
+       by a kernel identity mapping, the user mapping must use the same
+       attribute as the kernel mapping.
+
+       If the region is not in kern_memmap, the user mapping should use
+       an attribute reported as being supported in the EFI memory map.
+
+       Since the EFI memory map does not describe MMIO on some
+       machines, this should use an uncacheable mapping as a fallback.
+
+mmap of /sys/class/pci_bus/.../legacy_mem
+-----------------------------------------
+
+       This is very similar to mmap of /dev/mem, except that legacy_mem
+       only allows mmap of the one megabyte "legacy MMIO" area for a
+       specific PCI bus.  Typically this is the first megabyte of
+       physical address space, but it may be different on machines with
+       several VGA devices.
+
+       "X" uses this to access VGA frame buffers.  Using legacy_mem
+       rather than /dev/mem allows multiple instances of X to talk to
+       different VGA cards.
+
+       The /dev/mem mmap constraints apply.
+
+mmap of /proc/bus/pci/.../??.?
+------------------------------
+
+       This is an MMIO mmap of PCI functions, which additionally may or
+       may not be requested as using the WC attribute.
+
+       If WC is requested, and the region in kern_memmap is either WC
+       or UC, and the EFI memory map designates the region as WC, then
+       the WC mapping is allowed.
+
+       Otherwise, the user mapping must use the same attribute as the
+       kernel mapping.
+
+read/write of /dev/mem
+----------------------
+
+       This uses copy_from_user(), which implicitly uses a kernel
+       identity mapping.  This is obviously safe for things in
+       kern_memmap.
+
+       There may be corner cases of things that are not in kern_memmap,
+       but could be accessed this way.  For example, registers in MMIO
+       space are not in kern_memmap, but could be accessed with a UC
+       mapping.  This would not cause attribute aliasing.  But
+       registers typically can be accessed only with four-byte or
+       eight-byte accesses, and the copy_from_user() path doesn't allow
+       any control over the access size, so this would be dangerous.
+
+ioremap()
+---------
+
+       This returns a mapping for use inside the kernel.
+
+       If the region is in kern_memmap, we should use the attribute
+       specified there.
+
+       If the EFI memory map reports that the entire granule supports
+       WB, we should use that (granules that are partially reserved
+       or occupied by firmware do not appear in kern_memmap).
+
+       If the granule contains non-WB memory, but we can cover the
+       region safely with kernel page table mappings, we can use
+       ioremap_page_range() as most other architectures do.
+
+       Failing all of the above, we have to fall back to a UC mapping.
+
+Past Problem Cases
+==================
+
+mmap of various MMIO regions from /dev/mem by "X" on Intel platforms
+--------------------------------------------------------------------
+
+      The EFI memory map may not report these MMIO regions.
+
+      These must be allowed so that X will work.  This means that
+      when the EFI memory map is incomplete, every /dev/mem mmap must
+      succeed.  It may create either WB or UC user mappings, depending
+      on whether the region is in kern_memmap or the EFI memory map.
+
+mmap of 0x0-0x9FFFF /dev/mem by "hwinfo" on HP sx1000 with VGA enabled
+----------------------------------------------------------------------
+
+      The EFI memory map reports the following attributes:
+
+        =============== ======= ==================
+        0x00000-0x9FFFF WB only
+        0xA0000-0xBFFFF UC only (VGA frame buffer)
+        0xC0000-0xFFFFF WB only
+        =============== ======= ==================
+
+      This mmap is done with user pages, not kernel identity mappings,
+      so it is safe to use WB mappings.
+
+      The kernel VGA driver may ioremap the VGA frame buffer at 0xA0000,
+      which uses a granule-sized UC mapping.  This granule will cover some
+      WB-only memory, but since UC is non-speculative, the processor will
+      never generate an uncacheable reference to the WB-only areas unless
+      the driver explicitly touches them.
+
+mmap of 0x0-0xFFFFF legacy_mem by "X"
+-------------------------------------
+
+      If the EFI memory map reports that the entire range supports the
+      same attributes, we can allow the mmap (and we will prefer WB if
+      supported, as is the case with HP sx[12]000 machines with VGA
+      disabled).
+
+      If EFI reports the range as partly WB and partly UC (as on sx[12]000
+      machines with VGA enabled), we must fail the mmap because there's no
+      safe attribute to use.
+
+      If EFI reports some of the range but not all (as on Intel firmware
+      that doesn't report the VGA frame buffer at all), we should fail the
+      mmap and force the user to map just the specific region of interest.
+
+mmap of 0xA0000-0xBFFFF legacy_mem by "X" on HP sx1000 with VGA disabled
+------------------------------------------------------------------------
+
+      The EFI memory map reports the following attributes::
+
+        0x00000-0xFFFFF WB only (no VGA MMIO hole)
+
+      This is a special case of the previous case, and the mmap should
+      fail for the same reason as above.
+
+read of /sys/devices/.../rom
+----------------------------
+
+      For VGA devices, this may cause an ioremap() of 0xC0000.  This
+      used to be done with a UC mapping, because the VGA frame buffer
+      at 0xA0000 prevents use of a WB granule.  The UC mapping causes
+      an MCA on HP sx[12]000 chipsets.
+
+      We should use WB page table mappings to avoid covering the VGA
+      frame buffer.
+
+Notes
+=====
+
+    [1] SDM rev 2.2, vol 2, sec 4.4.1.
+    [2] SDM rev 2.2, vol 2, sec 4.4.6.
diff --git a/Documentation/ia64/aliasing.txt b/Documentation/ia64/aliasing.txt
deleted file mode 100644 (file)
index 5a4dea6..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-                MEMORY ATTRIBUTE ALIASING ON IA-64
-
-                          Bjorn Helgaas
-                      <bjorn.helgaas@hp.com>
-                           May 4, 2006
-
-
-MEMORY ATTRIBUTES
-
-    Itanium supports several attributes for virtual memory references.
-    The attribute is part of the virtual translation, i.e., it is
-    contained in the TLB entry.  The ones of most interest to the Linux
-    kernel are:
-
-       WB              Write-back (cacheable)
-       UC              Uncacheable
-       WC              Write-coalescing
-
-    System memory typically uses the WB attribute.  The UC attribute is
-    used for memory-mapped I/O devices.  The WC attribute is uncacheable
-    like UC is, but writes may be delayed and combined to increase
-    performance for things like frame buffers.
-
-    The Itanium architecture requires that we avoid accessing the same
-    page with both a cacheable mapping and an uncacheable mapping[1].
-
-    The design of the chipset determines which attributes are supported
-    on which regions of the address space.  For example, some chipsets
-    support either WB or UC access to main memory, while others support
-    only WB access.
-
-MEMORY MAP
-
-    Platform firmware describes the physical memory map and the
-    supported attributes for each region.  At boot-time, the kernel uses
-    the EFI GetMemoryMap() interface.  ACPI can also describe memory
-    devices and the attributes they support, but Linux/ia64 currently
-    doesn't use this information.
-
-    The kernel uses the efi_memmap table returned from GetMemoryMap() to
-    learn the attributes supported by each region of physical address
-    space.  Unfortunately, this table does not completely describe the
-    address space because some machines omit some or all of the MMIO
-    regions from the map.
-
-    The kernel maintains another table, kern_memmap, which describes the
-    memory Linux is actually using and the attribute for each region.
-    This contains only system memory; it does not contain MMIO space.
-
-    The kern_memmap table typically contains only a subset of the system
-    memory described by the efi_memmap.  Linux/ia64 can't use all memory
-    in the system because of constraints imposed by the identity mapping
-    scheme.
-
-    The efi_memmap table is preserved unmodified because the original
-    boot-time information is required for kexec.
-
-KERNEL IDENTITY MAPPINGS
-
-    Linux/ia64 identity mappings are done with large pages, currently
-    either 16MB or 64MB, referred to as "granules."  Cacheable mappings
-    are speculative[2], so the processor can read any location in the
-    page at any time, independent of the programmer's intentions.  This
-    means that to avoid attribute aliasing, Linux can create a cacheable
-    identity mapping only when the entire granule supports cacheable
-    access.
-
-    Therefore, kern_memmap contains only full granule-sized regions that
-    can referenced safely by an identity mapping.
-
-    Uncacheable mappings are not speculative, so the processor will
-    generate UC accesses only to locations explicitly referenced by
-    software.  This allows UC identity mappings to cover granules that
-    are only partially populated, or populated with a combination of UC
-    and WB regions.
-
-USER MAPPINGS
-
-    User mappings are typically done with 16K or 64K pages.  The smaller
-    page size allows more flexibility because only 16K or 64K has to be
-    homogeneous with respect to memory attributes.
-
-POTENTIAL ATTRIBUTE ALIASING CASES
-
-    There are several ways the kernel creates new mappings:
-
-    mmap of /dev/mem
-
-       This uses remap_pfn_range(), which creates user mappings.  These
-       mappings may be either WB or UC.  If the region being mapped
-       happens to be in kern_memmap, meaning that it may also be mapped
-       by a kernel identity mapping, the user mapping must use the same
-       attribute as the kernel mapping.
-
-       If the region is not in kern_memmap, the user mapping should use
-       an attribute reported as being supported in the EFI memory map.
-
-       Since the EFI memory map does not describe MMIO on some
-       machines, this should use an uncacheable mapping as a fallback.
-
-    mmap of /sys/class/pci_bus/.../legacy_mem
-
-       This is very similar to mmap of /dev/mem, except that legacy_mem
-       only allows mmap of the one megabyte "legacy MMIO" area for a
-       specific PCI bus.  Typically this is the first megabyte of
-       physical address space, but it may be different on machines with
-       several VGA devices.
-
-       "X" uses this to access VGA frame buffers.  Using legacy_mem
-       rather than /dev/mem allows multiple instances of X to talk to
-       different VGA cards.
-
-       The /dev/mem mmap constraints apply.
-
-    mmap of /proc/bus/pci/.../??.?
-
-       This is an MMIO mmap of PCI functions, which additionally may or
-       may not be requested as using the WC attribute.
-
-       If WC is requested, and the region in kern_memmap is either WC
-       or UC, and the EFI memory map designates the region as WC, then
-       the WC mapping is allowed.
-
-       Otherwise, the user mapping must use the same attribute as the
-       kernel mapping.
-
-    read/write of /dev/mem
-
-       This uses copy_from_user(), which implicitly uses a kernel
-       identity mapping.  This is obviously safe for things in
-       kern_memmap.
-
-       There may be corner cases of things that are not in kern_memmap,
-       but could be accessed this way.  For example, registers in MMIO
-       space are not in kern_memmap, but could be accessed with a UC
-       mapping.  This would not cause attribute aliasing.  But
-       registers typically can be accessed only with four-byte or
-       eight-byte accesses, and the copy_from_user() path doesn't allow
-       any control over the access size, so this would be dangerous.
-
-    ioremap()
-
-       This returns a mapping for use inside the kernel.
-
-       If the region is in kern_memmap, we should use the attribute
-       specified there.
-
-       If the EFI memory map reports that the entire granule supports
-       WB, we should use that (granules that are partially reserved
-       or occupied by firmware do not appear in kern_memmap).
-
-       If the granule contains non-WB memory, but we can cover the
-       region safely with kernel page table mappings, we can use
-       ioremap_page_range() as most other architectures do.
-
-       Failing all of the above, we have to fall back to a UC mapping.
-
-PAST PROBLEM CASES
-
-    mmap of various MMIO regions from /dev/mem by "X" on Intel platforms
-
-      The EFI memory map may not report these MMIO regions.
-
-      These must be allowed so that X will work.  This means that
-      when the EFI memory map is incomplete, every /dev/mem mmap must
-      succeed.  It may create either WB or UC user mappings, depending
-      on whether the region is in kern_memmap or the EFI memory map.
-
-    mmap of 0x0-0x9FFFF /dev/mem by "hwinfo" on HP sx1000 with VGA enabled
-
-      The EFI memory map reports the following attributes:
-        0x00000-0x9FFFF WB only
-        0xA0000-0xBFFFF UC only (VGA frame buffer)
-        0xC0000-0xFFFFF WB only
-
-      This mmap is done with user pages, not kernel identity mappings,
-      so it is safe to use WB mappings.
-
-      The kernel VGA driver may ioremap the VGA frame buffer at 0xA0000,
-      which uses a granule-sized UC mapping.  This granule will cover some
-      WB-only memory, but since UC is non-speculative, the processor will
-      never generate an uncacheable reference to the WB-only areas unless
-      the driver explicitly touches them.
-
-    mmap of 0x0-0xFFFFF legacy_mem by "X"
-
-      If the EFI memory map reports that the entire range supports the
-      same attributes, we can allow the mmap (and we will prefer WB if
-      supported, as is the case with HP sx[12]000 machines with VGA
-      disabled).
-
-      If EFI reports the range as partly WB and partly UC (as on sx[12]000
-      machines with VGA enabled), we must fail the mmap because there's no
-      safe attribute to use.
-
-      If EFI reports some of the range but not all (as on Intel firmware
-      that doesn't report the VGA frame buffer at all), we should fail the
-      mmap and force the user to map just the specific region of interest.
-
-    mmap of 0xA0000-0xBFFFF legacy_mem by "X" on HP sx1000 with VGA disabled
-
-      The EFI memory map reports the following attributes:
-        0x00000-0xFFFFF WB only (no VGA MMIO hole)
-
-      This is a special case of the previous case, and the mmap should
-      fail for the same reason as above.
-
-    read of /sys/devices/.../rom
-
-      For VGA devices, this may cause an ioremap() of 0xC0000.  This
-      used to be done with a UC mapping, because the VGA frame buffer
-      at 0xA0000 prevents use of a WB granule.  The UC mapping causes
-      an MCA on HP sx[12]000 chipsets.
-
-      We should use WB page table mappings to avoid covering the VGA
-      frame buffer.
-
-NOTES
-
-    [1] SDM rev 2.2, vol 2, sec 4.4.1.
-    [2] SDM rev 2.2, vol 2, sec 4.4.6.
diff --git a/Documentation/ia64/efirtc.rst b/Documentation/ia64/efirtc.rst
new file mode 100644 (file)
index 0000000..2f7ff50
--- /dev/null
@@ -0,0 +1,144 @@
+==========================
+EFI Real Time Clock driver
+==========================
+
+S. Eranian <eranian@hpl.hp.com>
+
+March 2000
+
+1. Introduction
+===============
+
+This document describes the efirtc.c driver has provided for
+the IA-64 platform.
+
+The purpose of this driver is to supply an API for kernel and user applications
+to get access to the Time Service offered by EFI version 0.92.
+
+EFI provides 4 calls one can make once the OS is booted: GetTime(),
+SetTime(), GetWakeupTime(), SetWakeupTime() which are all supported by this
+driver. We describe those calls as well the design of the driver in the
+following sections.
+
+2. Design Decisions
+===================
+
+The original ideas was to provide a very simple driver to get access to,
+at first, the time of day service. This is required in order to access, in a
+portable way, the CMOS clock. A program like /sbin/hwclock uses such a clock
+to initialize the system view of the time during boot.
+
+Because we wanted to minimize the impact on existing user-level apps using
+the CMOS clock, we decided to expose an API that was very similar to the one
+used today with the legacy RTC driver (driver/char/rtc.c). However, because
+EFI provides a simpler services, not all ioctl() are available. Also
+new ioctl()s have been introduced for things that EFI provides but not the
+legacy.
+
+EFI uses a slightly different way of representing the time, noticeably
+the reference date is different. Year is the using the full 4-digit format.
+The Epoch is January 1st 1998. For backward compatibility reasons we don't
+expose this new way of representing time. Instead we use something very
+similar to the struct tm, i.e. struct rtc_time, as used by hwclock.
+One of the reasons for doing it this way is to allow for EFI to still evolve
+without necessarily impacting any of the user applications. The decoupling
+enables flexibility and permits writing wrapper code is ncase things change.
+
+The driver exposes two interfaces, one via the device file and a set of
+ioctl()s. The other is read-only via the /proc filesystem.
+
+As of today we don't offer a /proc/sys interface.
+
+To allow for a uniform interface between the legacy RTC and EFI time service,
+we have created the include/linux/rtc.h header file to contain only the
+"public" API of the two drivers.  The specifics of the legacy RTC are still
+in include/linux/mc146818rtc.h.
+
+
+3. Time of day service
+======================
+
+The part of the driver gives access to the time of day service of EFI.
+Two ioctl()s, compatible with the legacy RTC calls:
+
+       Read the CMOS clock::
+
+               ioctl(d, RTC_RD_TIME, &rtc);
+
+       Write the CMOS clock::
+
+               ioctl(d, RTC_SET_TIME, &rtc);
+
+The rtc is a pointer to a data structure defined in rtc.h which is close
+to a struct tm::
+
+  struct rtc_time {
+          int tm_sec;
+          int tm_min;
+          int tm_hour;
+          int tm_mday;
+          int tm_mon;
+          int tm_year;
+          int tm_wday;
+          int tm_yday;
+          int tm_isdst;
+  };
+
+The driver takes care of converting back an forth between the EFI time and
+this format.
+
+Those two ioctl()s can be exercised with the hwclock command:
+
+For reading::
+
+       # /sbin/hwclock --show
+       Mon Mar  6 15:32:32 2000  -0.910248 seconds
+
+For setting::
+
+       # /sbin/hwclock --systohc
+
+Root privileges are required to be able to set the time of day.
+
+4. Wakeup Alarm service
+=======================
+
+EFI provides an API by which one can program when a machine should wakeup,
+i.e. reboot. This is very different from the alarm provided by the legacy
+RTC which is some kind of interval timer alarm. For this reason we don't use
+the same ioctl()s to get access to the service. Instead we have
+introduced 2 news ioctl()s to the interface of an RTC.
+
+We have added 2 new ioctl()s that are specific to the EFI driver:
+
+       Read the current state of the alarm::
+
+               ioctl(d, RTC_WKLAM_RD, &wkt)
+
+       Set the alarm or change its status::
+
+               ioctl(d, RTC_WKALM_SET, &wkt)
+
+The wkt structure encapsulates a struct rtc_time + 2 extra fields to get
+status information::
+
+  struct rtc_wkalrm {
+
+          unsigned char enabled; /* =1 if alarm is enabled */
+          unsigned char pending; /* =1 if alarm is pending  */
+
+          struct rtc_time time;
+  }
+
+As of today, none of the existing user-level apps supports this feature.
+However writing such a program should be hard by simply using those two
+ioctl().
+
+Root privileges are required to be able to set the alarm.
+
+5. References
+=============
+
+Checkout the following Web site for more information on EFI:
+
+http://developer.intel.com/technology/efi/
diff --git a/Documentation/ia64/efirtc.txt b/Documentation/ia64/efirtc.txt
deleted file mode 100644 (file)
index 057e6be..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-EFI Real Time Clock driver
--------------------------------
-S. Eranian <eranian@hpl.hp.com>
-March 2000
-
-I/ Introduction
-
-This document describes the efirtc.c driver has provided for
-the IA-64 platform. 
-
-The purpose of this driver is to supply an API for kernel and user applications
-to get access to the Time Service offered by EFI version 0.92.
-
-EFI provides 4 calls one can make once the OS is booted: GetTime(),
-SetTime(), GetWakeupTime(), SetWakeupTime() which are all supported by this
-driver. We describe those calls as well the design of the driver in the
-following sections.
-
-II/ Design Decisions
-
-The original ideas was to provide a very simple driver to get access to, 
-at first, the time of day service. This is required in order to access, in a 
-portable way, the CMOS clock. A program like /sbin/hwclock uses such a clock 
-to initialize the system view of the time during boot.
-
-Because we wanted to minimize the impact on existing user-level apps using
-the CMOS clock, we decided to expose an API that was very similar to the one
-used today with the legacy RTC driver (driver/char/rtc.c). However, because 
-EFI provides a simpler services, not all ioctl() are available. Also
-new ioctl()s have been introduced for things that EFI provides but not the 
-legacy.
-
-EFI uses a slightly different way of representing the time, noticeably
-the reference date is different. Year is the using the full 4-digit format.
-The Epoch is January 1st 1998. For backward compatibility reasons we don't
-expose this new way of representing time. Instead we use something very 
-similar to the struct tm, i.e. struct rtc_time, as used by hwclock.
-One of the reasons for doing it this way is to allow for EFI to still evolve
-without necessarily impacting any of the user applications. The decoupling
-enables flexibility and permits writing wrapper code is ncase things change.
-
-The driver exposes two interfaces, one via the device file and a set of
-ioctl()s. The other is read-only via the /proc filesystem. 
-
-As of today we don't offer a /proc/sys interface.
-
-To allow for a uniform interface between the legacy RTC and EFI time service,
-we have created the include/linux/rtc.h header file to contain only the 
-"public" API of the two drivers.  The specifics of the legacy RTC are still 
-in include/linux/mc146818rtc.h.
-
-III/ Time of day service
-
-The part of the driver gives access to the time of day service of EFI.
-Two ioctl()s, compatible with the legacy RTC calls:
-
-       Read the CMOS clock: ioctl(d, RTC_RD_TIME, &rtc);
-
-       Write the CMOS clock: ioctl(d, RTC_SET_TIME, &rtc);
-
-The rtc is a pointer to a data structure defined in rtc.h which is close
-to a struct tm:
-
-struct rtc_time {
-        int tm_sec;
-        int tm_min;
-        int tm_hour;
-        int tm_mday;
-        int tm_mon;
-        int tm_year;
-        int tm_wday;
-        int tm_yday;
-        int tm_isdst;
-};
-
-The driver takes care of converting back an forth between the EFI time and
-this format.
-
-Those two ioctl()s can be exercised with the hwclock command:
-
-For reading:
-# /sbin/hwclock --show
-Mon Mar  6 15:32:32 2000  -0.910248 seconds
-
-For setting:
-# /sbin/hwclock --systohc
-
-Root privileges are required to be able to set the time of day.
-
-IV/ Wakeup Alarm service
-
-EFI provides an API by which one can program when a machine should wakeup,
-i.e. reboot. This is very different from the alarm provided by the legacy
-RTC which is some kind of interval timer alarm. For this reason we don't use
-the same ioctl()s to get access to the service. Instead we have
-introduced 2 news ioctl()s to the interface of an RTC. 
-
-We have added 2 new ioctl()s that are specific to the EFI driver:
-
-       Read the current state of the alarm
-       ioctl(d, RTC_WKLAM_RD, &wkt)
-
-       Set the alarm or change its status
-       ioctl(d, RTC_WKALM_SET, &wkt)
-
-The wkt structure encapsulates a struct rtc_time + 2 extra fields to get 
-status information:
-       
-struct rtc_wkalrm {
-
-        unsigned char enabled; /* =1 if alarm is enabled */
-        unsigned char pending; /* =1 if alarm is pending  */
-
-        struct rtc_time time;
-} 
-
-As of today, none of the existing user-level apps supports this feature.
-However writing such a program should be hard by simply using those two 
-ioctl(). 
-
-Root privileges are required to be able to set the alarm.
-
-V/ References.
-
-Checkout the following Web site for more information on EFI:
-
-http://developer.intel.com/technology/efi/
diff --git a/Documentation/ia64/err_inject.rst b/Documentation/ia64/err_inject.rst
new file mode 100644 (file)
index 0000000..900f71e
--- /dev/null
@@ -0,0 +1,1067 @@
+========================================
+IPF Machine Check (MC) error inject tool
+========================================
+
+IPF Machine Check (MC) error inject tool is used to inject MC
+errors from Linux. The tool is a test bed for IPF MC work flow including
+hardware correctable error handling, OS recoverable error handling, MC
+event logging, etc.
+
+The tool includes two parts: a kernel driver and a user application
+sample. The driver provides interface to PAL to inject error
+and query error injection capabilities. The driver code is in
+arch/ia64/kernel/err_inject.c. The application sample (shown below)
+provides a combination of various errors and calls the driver's interface
+(sysfs interface) to inject errors or query error injection capabilities.
+
+The tool can be used to test Intel IPF machine MC handling capabilities.
+It's especially useful for people who can not access hardware MC injection
+tool to inject error. It's also very useful to integrate with other
+software test suits to do stressful testing on IPF.
+
+Below is a sample application as part of the whole tool. The sample
+can be used as a working test tool. Or it can be expanded to include
+more features. It also can be a integrated into a library or other user
+application to have more thorough test.
+
+The sample application takes err.conf as error configuration input. GCC
+compiles the code. After you install err_inject driver, you can run
+this sample application to inject errors.
+
+Errata: Itanium 2 Processors Specification Update lists some errata against
+the pal_mc_error_inject PAL procedure. The following err.conf has been tested
+on latest Montecito PAL.
+
+err.conf::
+
+  #This is configuration file for err_inject_tool.
+  #The format of the each line is:
+  #cpu, loop, interval, err_type_info, err_struct_info, err_data_buffer
+  #where
+  #    cpu: logical cpu number the error will be inject in.
+  #    loop: times the error will be injected.
+  #    interval: In second. every so often one error is injected.
+  #    err_type_info, err_struct_info: PAL parameters.
+  #
+  #Note: All values are hex w/o or w/ 0x prefix.
+
+
+  #On cpu2, inject only total 0x10 errors, interval 5 seconds
+  #corrected, data cache, hier-2, physical addr(assigned by tool code).
+  #working on Montecito latest PAL.
+  2, 10, 5, 4101, 95
+
+  #On cpu4, inject and consume total 0x10 errors, interval 5 seconds
+  #corrected, data cache, hier-2, physical addr(assigned by tool code).
+  #working on Montecito latest PAL.
+  4, 10, 5, 4109, 95
+
+  #On cpu15, inject and consume total 0x10 errors, interval 5 seconds
+  #recoverable, DTR0, hier-2.
+  #working on Montecito latest PAL.
+  0xf, 0x10, 5, 4249, 15
+
+The sample application source code:
+
+err_injection_tool.c::
+
+  /*
+   * This program is free software; you can redistribute it and/or modify
+   * it under the terms of the GNU General Public License as published by
+   * the Free Software Foundation; either version 2 of the License, or
+   * (at your option) any later version.
+   *
+   * This program is distributed in the hope that it will be useful, but
+   * WITHOUT ANY WARRANTY; without even the implied warranty of
+   * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+   * NON INFRINGEMENT.  See the GNU General Public License for more
+   * details.
+   *
+   * You should have received a copy of the GNU General Public License
+   * along with this program; if not, write to the Free Software
+   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   *
+   * Copyright (C) 2006 Intel Co
+   *   Fenghua Yu <fenghua.yu@intel.com>
+   *
+   */
+  #include <sys/types.h>
+  #include <sys/stat.h>
+  #include <fcntl.h>
+  #include <stdio.h>
+  #include <sched.h>
+  #include <unistd.h>
+  #include <stdlib.h>
+  #include <stdarg.h>
+  #include <string.h>
+  #include <errno.h>
+  #include <time.h>
+  #include <sys/ipc.h>
+  #include <sys/sem.h>
+  #include <sys/wait.h>
+  #include <sys/mman.h>
+  #include <sys/shm.h>
+
+  #define MAX_FN_SIZE          256
+  #define MAX_BUF_SIZE                 256
+  #define DATA_BUF_SIZE                256
+  #define NR_CPUS              512
+  #define MAX_TASK_NUM         2048
+  #define MIN_INTERVAL         5       // seconds
+  #define      ERR_DATA_BUFFER_SIZE    3       // Three 8-byte.
+  #define PARA_FIELD_NUM               5
+  #define MASK_SIZE            (NR_CPUS/64)
+  #define PATH_FORMAT "/sys/devices/system/cpu/cpu%d/err_inject/"
+
+  int sched_setaffinity(pid_t pid, unsigned int len, unsigned long *mask);
+
+  int verbose;
+  #define vbprintf if (verbose) printf
+
+  int log_info(int cpu, const char *fmt, ...)
+  {
+       FILE *log;
+       char fn[MAX_FN_SIZE];
+       char buf[MAX_BUF_SIZE];
+       va_list args;
+
+       sprintf(fn, "%d.log", cpu);
+       log=fopen(fn, "a+");
+       if (log==NULL) {
+               perror("Error open:");
+               return -1;
+       }
+
+       va_start(args, fmt);
+       vprintf(fmt, args);
+       memset(buf, 0, MAX_BUF_SIZE);
+       vsprintf(buf, fmt, args);
+       va_end(args);
+
+       fwrite(buf, sizeof(buf), 1, log);
+       fclose(log);
+
+       return 0;
+  }
+
+  typedef unsigned long u64;
+  typedef unsigned int  u32;
+
+  typedef union err_type_info_u {
+       struct {
+               u64     mode            : 3,    /* 0-2 */
+                       err_inj         : 3,    /* 3-5 */
+                       err_sev         : 2,    /* 6-7 */
+                       err_struct      : 5,    /* 8-12 */
+                       struct_hier     : 3,    /* 13-15 */
+                       reserved        : 48;   /* 16-63 */
+       } err_type_info_u;
+       u64     err_type_info;
+  } err_type_info_t;
+
+  typedef union err_struct_info_u {
+       struct {
+               u64     siv             : 1,    /* 0     */
+                       c_t             : 2,    /* 1-2   */
+                       cl_p            : 3,    /* 3-5   */
+                       cl_id           : 3,    /* 6-8   */
+                       cl_dp           : 1,    /* 9     */
+                       reserved1       : 22,   /* 10-31 */
+                       tiv             : 1,    /* 32    */
+                       trigger         : 4,    /* 33-36 */
+                       trigger_pl      : 3,    /* 37-39 */
+                       reserved2       : 24;   /* 40-63 */
+       } err_struct_info_cache;
+       struct {
+               u64     siv             : 1,    /* 0     */
+                       tt              : 2,    /* 1-2   */
+                       tc_tr           : 2,    /* 3-4   */
+                       tr_slot         : 8,    /* 5-12  */
+                       reserved1       : 19,   /* 13-31 */
+                       tiv             : 1,    /* 32    */
+                       trigger         : 4,    /* 33-36 */
+                       trigger_pl      : 3,    /* 37-39 */
+                       reserved2       : 24;   /* 40-63 */
+       } err_struct_info_tlb;
+       struct {
+               u64     siv             : 1,    /* 0     */
+                       regfile_id      : 4,    /* 1-4   */
+                       reg_num         : 7,    /* 5-11  */
+                       reserved1       : 20,   /* 12-31 */
+                       tiv             : 1,    /* 32    */
+                       trigger         : 4,    /* 33-36 */
+                       trigger_pl      : 3,    /* 37-39 */
+                       reserved2       : 24;   /* 40-63 */
+       } err_struct_info_register;
+       struct {
+               u64     reserved;
+       } err_struct_info_bus_processor_interconnect;
+       u64     err_struct_info;
+  } err_struct_info_t;
+
+  typedef union err_data_buffer_u {
+       struct {
+               u64     trigger_addr;           /* 0-63         */
+               u64     inj_addr;               /* 64-127       */
+               u64     way             : 5,    /* 128-132      */
+                       index           : 20,   /* 133-152      */
+                                       : 39;   /* 153-191      */
+       } err_data_buffer_cache;
+       struct {
+               u64     trigger_addr;           /* 0-63         */
+               u64     inj_addr;               /* 64-127       */
+               u64     way             : 5,    /* 128-132      */
+                       index           : 20,   /* 133-152      */
+                       reserved        : 39;   /* 153-191      */
+       } err_data_buffer_tlb;
+       struct {
+               u64     trigger_addr;           /* 0-63         */
+       } err_data_buffer_register;
+       struct {
+               u64     reserved;               /* 0-63         */
+       } err_data_buffer_bus_processor_interconnect;
+       u64 err_data_buffer[ERR_DATA_BUFFER_SIZE];
+  } err_data_buffer_t;
+
+  typedef union capabilities_u {
+       struct {
+               u64     i               : 1,
+                       d               : 1,
+                       rv              : 1,
+                       tag             : 1,
+                       data            : 1,
+                       mesi            : 1,
+                       dp              : 1,
+                       reserved1       : 3,
+                       pa              : 1,
+                       va              : 1,
+                       wi              : 1,
+                       reserved2       : 20,
+                       trigger         : 1,
+                       trigger_pl      : 1,
+                       reserved3       : 30;
+       } capabilities_cache;
+       struct {
+               u64     d               : 1,
+                       i               : 1,
+                       rv              : 1,
+                       tc              : 1,
+                       tr              : 1,
+                       reserved1       : 27,
+                       trigger         : 1,
+                       trigger_pl      : 1,
+                       reserved2       : 30;
+       } capabilities_tlb;
+       struct {
+               u64     gr_b0           : 1,
+                       gr_b1           : 1,
+                       fr              : 1,
+                       br              : 1,
+                       pr              : 1,
+                       ar              : 1,
+                       cr              : 1,
+                       rr              : 1,
+                       pkr             : 1,
+                       dbr             : 1,
+                       ibr             : 1,
+                       pmc             : 1,
+                       pmd             : 1,
+                       reserved1       : 3,
+                       regnum          : 1,
+                       reserved2       : 15,
+                       trigger         : 1,
+                       trigger_pl      : 1,
+                       reserved3       : 30;
+       } capabilities_register;
+       struct {
+               u64     reserved;
+       } capabilities_bus_processor_interconnect;
+  } capabilities_t;
+
+  typedef struct resources_s {
+       u64     ibr0            : 1,
+               ibr2            : 1,
+               ibr4            : 1,
+               ibr6            : 1,
+               dbr0            : 1,
+               dbr2            : 1,
+               dbr4            : 1,
+               dbr6            : 1,
+               reserved        : 48;
+  } resources_t;
+
+
+  long get_page_size(void)
+  {
+       long page_size=sysconf(_SC_PAGESIZE);
+       return page_size;
+  }
+
+  #define PAGE_SIZE (get_page_size()==-1?0x4000:get_page_size())
+  #define SHM_SIZE (2*PAGE_SIZE*NR_CPUS)
+  #define SHM_VA 0x2000000100000000
+
+  int shmid;
+  void *shmaddr;
+
+  int create_shm(void)
+  {
+       key_t key;
+       char fn[MAX_FN_SIZE];
+
+       /* cpu0 is always existing */
+       sprintf(fn, PATH_FORMAT, 0);
+       if ((key = ftok(fn, 's')) == -1) {
+               perror("ftok");
+               return -1;
+       }
+
+       shmid = shmget(key, SHM_SIZE, 0644 | IPC_CREAT);
+       if (shmid == -1) {
+               if (errno==EEXIST) {
+                       shmid = shmget(key, SHM_SIZE, 0);
+                       if (shmid == -1) {
+                               perror("shmget");
+                               return -1;
+                       }
+               }
+               else {
+                       perror("shmget");
+                       return -1;
+               }
+       }
+       vbprintf("shmid=%d", shmid);
+
+       /* connect to the segment: */
+       shmaddr = shmat(shmid, (void *)SHM_VA, 0);
+       if (shmaddr == (void*)-1) {
+               perror("shmat");
+               return -1;
+       }
+
+       memset(shmaddr, 0, SHM_SIZE);
+       mlock(shmaddr, SHM_SIZE);
+
+       return 0;
+  }
+
+  int free_shm()
+  {
+       munlock(shmaddr, SHM_SIZE);
+          shmdt(shmaddr);
+       semctl(shmid, 0, IPC_RMID);
+
+       return 0;
+  }
+
+  #ifdef _SEM_SEMUN_UNDEFINED
+  union semun
+  {
+       int val;
+       struct semid_ds *buf;
+       unsigned short int *array;
+       struct seminfo *__buf;
+  };
+  #endif
+
+  u32 mode=1; /* 1: physical mode; 2: virtual mode. */
+  int one_lock=1;
+  key_t key[NR_CPUS];
+  int semid[NR_CPUS];
+
+  int create_sem(int cpu)
+  {
+       union semun arg;
+       char fn[MAX_FN_SIZE];
+       int sid;
+
+       sprintf(fn, PATH_FORMAT, cpu);
+       sprintf(fn, "%s/%s", fn, "err_type_info");
+       if ((key[cpu] = ftok(fn, 'e')) == -1) {
+               perror("ftok");
+               return -1;
+       }
+
+       if (semid[cpu]!=0)
+               return 0;
+
+       /* clear old semaphore */
+       if ((sid = semget(key[cpu], 1, 0)) != -1)
+               semctl(sid, 0, IPC_RMID);
+
+       /* get one semaphore */
+       if ((semid[cpu] = semget(key[cpu], 1, IPC_CREAT | IPC_EXCL)) == -1) {
+               perror("semget");
+               printf("Please remove semaphore with key=0x%lx, then run the tool.\n",
+                       (u64)key[cpu]);
+               return -1;
+       }
+
+       vbprintf("semid[%d]=0x%lx, key[%d]=%lx\n",cpu,(u64)semid[cpu],cpu,
+               (u64)key[cpu]);
+       /* initialize the semaphore to 1: */
+       arg.val = 1;
+       if (semctl(semid[cpu], 0, SETVAL, arg) == -1) {
+               perror("semctl");
+               return -1;
+       }
+
+       return 0;
+  }
+
+  static int lock(int cpu)
+  {
+       struct sembuf lock;
+
+       lock.sem_num = cpu;
+       lock.sem_op = 1;
+       semop(semid[cpu], &lock, 1);
+
+          return 0;
+  }
+
+  static int unlock(int cpu)
+  {
+       struct sembuf unlock;
+
+       unlock.sem_num = cpu;
+       unlock.sem_op = -1;
+       semop(semid[cpu], &unlock, 1);
+
+          return 0;
+  }
+
+  void free_sem(int cpu)
+  {
+       semctl(semid[cpu], 0, IPC_RMID);
+  }
+
+  int wr_multi(char *fn, unsigned long *data, int size)
+  {
+       int fd;
+       char buf[MAX_BUF_SIZE];
+       int ret;
+
+       if (size==1)
+               sprintf(buf, "%lx", *data);
+       else if (size==3)
+               sprintf(buf, "%lx,%lx,%lx", data[0], data[1], data[2]);
+       else {
+               fprintf(stderr,"write to file with wrong size!\n");
+               return -1;
+       }
+
+       fd=open(fn, O_RDWR);
+       if (!fd) {
+               perror("Error:");
+               return -1;
+       }
+       ret=write(fd, buf, sizeof(buf));
+       close(fd);
+       return ret;
+  }
+
+  int wr(char *fn, unsigned long data)
+  {
+       return wr_multi(fn, &data, 1);
+  }
+
+  int rd(char *fn, unsigned long *data)
+  {
+       int fd;
+       char buf[MAX_BUF_SIZE];
+
+       fd=open(fn, O_RDONLY);
+       if (fd<0) {
+               perror("Error:");
+               return -1;
+       }
+       read(fd, buf, MAX_BUF_SIZE);
+       *data=strtoul(buf, NULL, 16);
+       close(fd);
+       return 0;
+  }
+
+  int rd_status(char *path, int *status)
+  {
+       char fn[MAX_FN_SIZE];
+       sprintf(fn, "%s/status", path);
+       if (rd(fn, (u64*)status)<0) {
+               perror("status reading error.\n");
+               return -1;
+       }
+
+       return 0;
+  }
+
+  int rd_capabilities(char *path, u64 *capabilities)
+  {
+       char fn[MAX_FN_SIZE];
+       sprintf(fn, "%s/capabilities", path);
+       if (rd(fn, capabilities)<0) {
+               perror("capabilities reading error.\n");
+               return -1;
+       }
+
+       return 0;
+  }
+
+  int rd_all(char *path)
+  {
+       unsigned long err_type_info, err_struct_info, err_data_buffer;
+       int status;
+       unsigned long capabilities, resources;
+       char fn[MAX_FN_SIZE];
+
+       sprintf(fn, "%s/err_type_info", path);
+       if (rd(fn, &err_type_info)<0) {
+               perror("err_type_info reading error.\n");
+               return -1;
+       }
+       printf("err_type_info=%lx\n", err_type_info);
+
+       sprintf(fn, "%s/err_struct_info", path);
+       if (rd(fn, &err_struct_info)<0) {
+               perror("err_struct_info reading error.\n");
+               return -1;
+       }
+       printf("err_struct_info=%lx\n", err_struct_info);
+
+       sprintf(fn, "%s/err_data_buffer", path);
+       if (rd(fn, &err_data_buffer)<0) {
+               perror("err_data_buffer reading error.\n");
+               return -1;
+       }
+       printf("err_data_buffer=%lx\n", err_data_buffer);
+
+       sprintf(fn, "%s/status", path);
+       if (rd("status", (u64*)&status)<0) {
+               perror("status reading error.\n");
+               return -1;
+       }
+       printf("status=%d\n", status);
+
+       sprintf(fn, "%s/capabilities", path);
+       if (rd(fn,&capabilities)<0) {
+               perror("capabilities reading error.\n");
+               return -1;
+       }
+       printf("capabilities=%lx\n", capabilities);
+
+       sprintf(fn, "%s/resources", path);
+       if (rd(fn, &resources)<0) {
+               perror("resources reading error.\n");
+               return -1;
+       }
+       printf("resources=%lx\n", resources);
+
+       return 0;
+  }
+
+  int query_capabilities(char *path, err_type_info_t err_type_info,
+                       u64 *capabilities)
+  {
+       char fn[MAX_FN_SIZE];
+       err_struct_info_t err_struct_info;
+       err_data_buffer_t err_data_buffer;
+
+       err_struct_info.err_struct_info=0;
+       memset(err_data_buffer.err_data_buffer, -1, ERR_DATA_BUFFER_SIZE*8);
+
+       sprintf(fn, "%s/err_type_info", path);
+       wr(fn, err_type_info.err_type_info);
+       sprintf(fn, "%s/err_struct_info", path);
+       wr(fn, 0x0);
+       sprintf(fn, "%s/err_data_buffer", path);
+       wr_multi(fn, err_data_buffer.err_data_buffer, ERR_DATA_BUFFER_SIZE);
+
+       // Fire pal_mc_error_inject procedure.
+       sprintf(fn, "%s/call_start", path);
+       wr(fn, mode);
+
+       if (rd_capabilities(path, capabilities)<0)
+               return -1;
+
+       return 0;
+  }
+
+  int query_all_capabilities()
+  {
+       int status;
+       err_type_info_t err_type_info;
+       int err_sev, err_struct, struct_hier;
+       int cap=0;
+       u64 capabilities;
+       char path[MAX_FN_SIZE];
+
+       err_type_info.err_type_info=0;                  // Initial
+       err_type_info.err_type_info_u.mode=0;           // Query mode;
+       err_type_info.err_type_info_u.err_inj=0;
+
+       printf("All capabilities implemented in pal_mc_error_inject:\n");
+       sprintf(path, PATH_FORMAT ,0);
+       for (err_sev=0;err_sev<3;err_sev++)
+               for (err_struct=0;err_struct<5;err_struct++)
+                       for (struct_hier=0;struct_hier<5;struct_hier++)
+       {
+               status=-1;
+               capabilities=0;
+               err_type_info.err_type_info_u.err_sev=err_sev;
+               err_type_info.err_type_info_u.err_struct=err_struct;
+               err_type_info.err_type_info_u.struct_hier=struct_hier;
+
+               if (query_capabilities(path, err_type_info, &capabilities)<0)
+                       continue;
+
+               if (rd_status(path, &status)<0)
+                       continue;
+
+               if (status==0) {
+                       cap=1;
+                       printf("For err_sev=%d, err_struct=%d, struct_hier=%d: ",
+                               err_sev, err_struct, struct_hier);
+                       printf("capabilities 0x%lx\n", capabilities);
+               }
+       }
+       if (!cap) {
+               printf("No capabilities supported.\n");
+               return 0;
+       }
+
+       return 0;
+  }
+
+  int err_inject(int cpu, char *path, err_type_info_t err_type_info,
+               err_struct_info_t err_struct_info,
+               err_data_buffer_t err_data_buffer)
+  {
+       int status;
+       char fn[MAX_FN_SIZE];
+
+       log_info(cpu, "err_type_info=%lx, err_struct_info=%lx, ",
+               err_type_info.err_type_info,
+               err_struct_info.err_struct_info);
+       log_info(cpu,"err_data_buffer=[%lx,%lx,%lx]\n",
+               err_data_buffer.err_data_buffer[0],
+               err_data_buffer.err_data_buffer[1],
+               err_data_buffer.err_data_buffer[2]);
+       sprintf(fn, "%s/err_type_info", path);
+       wr(fn, err_type_info.err_type_info);
+       sprintf(fn, "%s/err_struct_info", path);
+       wr(fn, err_struct_info.err_struct_info);
+       sprintf(fn, "%s/err_data_buffer", path);
+       wr_multi(fn, err_data_buffer.err_data_buffer, ERR_DATA_BUFFER_SIZE);
+
+       // Fire pal_mc_error_inject procedure.
+       sprintf(fn, "%s/call_start", path);
+       wr(fn,mode);
+
+       if (rd_status(path, &status)<0) {
+               vbprintf("fail: read status\n");
+               return -100;
+       }
+
+       if (status!=0) {
+               log_info(cpu, "fail: status=%d\n", status);
+               return status;
+       }
+
+       return status;
+  }
+
+  static int construct_data_buf(char *path, err_type_info_t err_type_info,
+               err_struct_info_t err_struct_info,
+               err_data_buffer_t *err_data_buffer,
+               void *va1)
+  {
+       char fn[MAX_FN_SIZE];
+       u64 virt_addr=0, phys_addr=0;
+
+       vbprintf("va1=%lx\n", (u64)va1);
+       memset(&err_data_buffer->err_data_buffer_cache, 0, ERR_DATA_BUFFER_SIZE*8);
+
+       switch (err_type_info.err_type_info_u.err_struct) {
+               case 1: // Cache
+                       switch (err_struct_info.err_struct_info_cache.cl_id) {
+                               case 1: //Virtual addr
+                                       err_data_buffer->err_data_buffer_cache.inj_addr=(u64)va1;
+                                       break;
+                               case 2: //Phys addr
+                                       sprintf(fn, "%s/virtual_to_phys", path);
+                                       virt_addr=(u64)va1;
+                                       if (wr(fn,virt_addr)<0)
+                                               return -1;
+                                       rd(fn, &phys_addr);
+                                       err_data_buffer->err_data_buffer_cache.inj_addr=phys_addr;
+                                       break;
+                               default:
+                                       printf("Not supported cl_id\n");
+                                       break;
+                       }
+                       break;
+               case 2: //  TLB
+                       break;
+               case 3: //  Register file
+                       break;
+               case 4: //  Bus/system interconnect
+               default:
+                       printf("Not supported err_struct\n");
+                       break;
+       }
+
+       return 0;
+  }
+
+  typedef struct {
+       u64 cpu;
+       u64 loop;
+       u64 interval;
+       u64 err_type_info;
+       u64 err_struct_info;
+       u64 err_data_buffer[ERR_DATA_BUFFER_SIZE];
+  } parameters_t;
+
+  parameters_t line_para;
+  int para;
+
+  static int empty_data_buffer(u64 *err_data_buffer)
+  {
+       int empty=1;
+       int i;
+
+       for (i=0;i<ERR_DATA_BUFFER_SIZE; i++)
+          if (err_data_buffer[i]!=-1)
+               empty=0;
+
+       return empty;
+  }
+
+  int err_inj()
+  {
+       err_type_info_t err_type_info;
+       err_struct_info_t err_struct_info;
+       err_data_buffer_t err_data_buffer;
+       int count;
+       FILE *fp;
+       unsigned long cpu, loop, interval, err_type_info_conf, err_struct_info_conf;
+       u64 err_data_buffer_conf[ERR_DATA_BUFFER_SIZE];
+       int num;
+       int i;
+       char path[MAX_FN_SIZE];
+       parameters_t parameters[MAX_TASK_NUM]={};
+       pid_t child_pid[MAX_TASK_NUM];
+       time_t current_time;
+       int status;
+
+       if (!para) {
+           fp=fopen("err.conf", "r");
+           if (fp==NULL) {
+               perror("Error open err.conf");
+               return -1;
+           }
+
+           num=0;
+           while (!feof(fp)) {
+               char buf[256];
+               memset(buf,0,256);
+               fgets(buf, 256, fp);
+               count=sscanf(buf, "%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx\n",
+                               &cpu, &loop, &interval,&err_type_info_conf,
+                               &err_struct_info_conf,
+                               &err_data_buffer_conf[0],
+                               &err_data_buffer_conf[1],
+                               &err_data_buffer_conf[2]);
+               if (count!=PARA_FIELD_NUM+3) {
+                       err_data_buffer_conf[0]=-1;
+                       err_data_buffer_conf[1]=-1;
+                       err_data_buffer_conf[2]=-1;
+                       count=sscanf(buf, "%lx, %lx, %lx, %lx, %lx\n",
+                               &cpu, &loop, &interval,&err_type_info_conf,
+                               &err_struct_info_conf);
+                       if (count!=PARA_FIELD_NUM)
+                               continue;
+               }
+
+               parameters[num].cpu=cpu;
+               parameters[num].loop=loop;
+               parameters[num].interval= interval>MIN_INTERVAL
+                                         ?interval:MIN_INTERVAL;
+               parameters[num].err_type_info=err_type_info_conf;
+               parameters[num].err_struct_info=err_struct_info_conf;
+               memcpy(parameters[num++].err_data_buffer,
+                       err_data_buffer_conf,ERR_DATA_BUFFER_SIZE*8) ;
+
+               if (num>=MAX_TASK_NUM)
+                       break;
+           }
+       }
+       else {
+               parameters[0].cpu=line_para.cpu;
+               parameters[0].loop=line_para.loop;
+               parameters[0].interval= line_para.interval>MIN_INTERVAL
+                                         ?line_para.interval:MIN_INTERVAL;
+               parameters[0].err_type_info=line_para.err_type_info;
+               parameters[0].err_struct_info=line_para.err_struct_info;
+               memcpy(parameters[0].err_data_buffer,
+                       line_para.err_data_buffer,ERR_DATA_BUFFER_SIZE*8) ;
+
+               num=1;
+       }
+
+       /* Create semaphore: If one_lock, one semaphore for all processors.
+          Otherwise, one semaphore for each processor. */
+       if (one_lock) {
+               if (create_sem(0)) {
+                       printf("Can not create semaphore...exit\n");
+                       free_sem(0);
+                       return -1;
+               }
+       }
+       else {
+               for (i=0;i<num;i++) {
+                  if (create_sem(parameters[i].cpu)) {
+                       printf("Can not create semaphore for cpu%d...exit\n",i);
+                       free_sem(parameters[num].cpu);
+                       return -1;
+                  }
+               }
+       }
+
+       /* Create a shm segment which will be used to inject/consume errors on.*/
+       if (create_shm()==-1) {
+               printf("Error to create shm...exit\n");
+               return -1;
+       }
+
+       for (i=0;i<num;i++) {
+               pid_t pid;
+
+               current_time=time(NULL);
+               log_info(parameters[i].cpu, "\nBegine at %s", ctime(&current_time));
+               log_info(parameters[i].cpu, "Configurations:\n");
+               log_info(parameters[i].cpu,"On cpu%ld: loop=%lx, interval=%lx(s)",
+                       parameters[i].cpu,
+                       parameters[i].loop,
+                       parameters[i].interval);
+               log_info(parameters[i].cpu," err_type_info=%lx,err_struct_info=%lx\n",
+                       parameters[i].err_type_info,
+                       parameters[i].err_struct_info);
+
+               sprintf(path, PATH_FORMAT, (int)parameters[i].cpu);
+               err_type_info.err_type_info=parameters[i].err_type_info;
+               err_struct_info.err_struct_info=parameters[i].err_struct_info;
+               memcpy(err_data_buffer.err_data_buffer,
+                       parameters[i].err_data_buffer,
+                       ERR_DATA_BUFFER_SIZE*8);
+
+               pid=fork();
+               if (pid==0) {
+                       unsigned long mask[MASK_SIZE];
+                       int j, k;
+
+                       void *va1, *va2;
+
+                       /* Allocate two memory areas va1 and va2 in shm */
+                       va1=shmaddr+parameters[i].cpu*PAGE_SIZE;
+                       va2=shmaddr+parameters[i].cpu*PAGE_SIZE+PAGE_SIZE;
+
+                       vbprintf("va1=%lx, va2=%lx\n", (u64)va1, (u64)va2);
+                       memset(va1, 0x1, PAGE_SIZE);
+                       memset(va2, 0x2, PAGE_SIZE);
+
+                       if (empty_data_buffer(err_data_buffer.err_data_buffer))
+                               /* If not specified yet, construct data buffer
+                                * with va1
+                                */
+                               construct_data_buf(path, err_type_info,
+                                       err_struct_info, &err_data_buffer,va1);
+
+                       for (j=0;j<MASK_SIZE;j++)
+                               mask[j]=0;
+
+                       cpu=parameters[i].cpu;
+                       k = cpu%64;
+                       j = cpu/64;
+                       mask[j] = 1UL << k;
+
+                       if (sched_setaffinity(0, MASK_SIZE*8, mask)==-1) {
+                               perror("Error sched_setaffinity:");
+                               return -1;
+                       }
+
+                       for (j=0; j<parameters[i].loop; j++) {
+                               log_info(parameters[i].cpu,"Injection ");
+                               log_info(parameters[i].cpu,"on cpu%ld: #%d/%ld ",
+
+                                       parameters[i].cpu,j+1, parameters[i].loop);
+
+                               /* Hold the lock */
+                               if (one_lock)
+                                       lock(0);
+                               else
+                               /* Hold lock on this cpu */
+                                       lock(parameters[i].cpu);
+
+                               if ((status=err_inject(parameters[i].cpu,
+                                          path, err_type_info,
+                                          err_struct_info, err_data_buffer))
+                                          ==0) {
+                                       /* consume the error for "inject only"*/
+                                       memcpy(va2, va1, PAGE_SIZE);
+                                       memcpy(va1, va2, PAGE_SIZE);
+                                       log_info(parameters[i].cpu,
+                                               "successful\n");
+                               }
+                               else {
+                                       log_info(parameters[i].cpu,"fail:");
+                                       log_info(parameters[i].cpu,
+                                               "status=%d\n", status);
+                                       unlock(parameters[i].cpu);
+                                       break;
+                               }
+                               if (one_lock)
+                               /* Release the lock */
+                                       unlock(0);
+                               /* Release lock on this cpu */
+                               else
+                                       unlock(parameters[i].cpu);
+
+                               if (j < parameters[i].loop-1)
+                                       sleep(parameters[i].interval);
+                       }
+                       current_time=time(NULL);
+                       log_info(parameters[i].cpu, "Done at %s", ctime(&current_time));
+                       return 0;
+               }
+               else if (pid<0) {
+                       perror("Error fork:");
+                       continue;
+               }
+               child_pid[i]=pid;
+       }
+       for (i=0;i<num;i++)
+               waitpid(child_pid[i], NULL, 0);
+
+       if (one_lock)
+               free_sem(0);
+       else
+               for (i=0;i<num;i++)
+                       free_sem(parameters[i].cpu);
+
+       printf("All done.\n");
+
+       return 0;
+  }
+
+  void help()
+  {
+       printf("err_inject_tool:\n");
+       printf("\t-q: query all capabilities. default: off\n");
+       printf("\t-m: procedure mode. 1: physical 2: virtual. default: 1\n");
+       printf("\t-i: inject errors. default: off\n");
+       printf("\t-l: one lock per cpu. default: one lock for all\n");
+       printf("\t-e: error parameters:\n");
+       printf("\t\tcpu,loop,interval,err_type_info,err_struct_info[,err_data_buffer[0],err_data_buffer[1],err_data_buffer[2]]\n");
+       printf("\t\t   cpu: logical cpu number the error will be inject in.\n");
+       printf("\t\t   loop: times the error will be injected.\n");
+       printf("\t\t   interval: In second. every so often one error is injected.\n");
+       printf("\t\t   err_type_info, err_struct_info: PAL parameters.\n");
+       printf("\t\t   err_data_buffer: PAL parameter. Optional. If not present,\n");
+       printf("\t\t                    it's constructed by tool automatically. Be\n");
+       printf("\t\t                    careful to provide err_data_buffer and make\n");
+       printf("\t\t                    sure it's working with the environment.\n");
+       printf("\t    Note:no space between error parameters.\n");
+       printf("\t    default: Take error parameters from err.conf instead of command line.\n");
+       printf("\t-v: verbose. default: off\n");
+       printf("\t-h: help\n\n");
+       printf("The tool will take err.conf file as ");
+       printf("input to inject single or multiple errors ");
+       printf("on one or multiple cpus in parallel.\n");
+  }
+
+  int main(int argc, char **argv)
+  {
+       char c;
+       int do_err_inj=0;
+       int do_query_all=0;
+       int count;
+       u32 m;
+
+       /* Default one lock for all cpu's */
+       one_lock=1;
+       while ((c = getopt(argc, argv, "m:iqvhle:")) != EOF)
+               switch (c) {
+                       case 'm':       /* Procedure mode. 1: phys 2: virt */
+                               count=sscanf(optarg, "%x", &m);
+                               if (count!=1 || (m!=1 && m!=2)) {
+                                       printf("Wrong mode number.\n");
+                                       help();
+                                       return -1;
+                               }
+                               mode=m;
+                               break;
+                       case 'i':       /* Inject errors */
+                               do_err_inj=1;
+                               break;
+                       case 'q':       /* Query */
+                               do_query_all=1;
+                               break;
+                       case 'v':       /* Verbose */
+                               verbose=1;
+                               break;
+                       case 'l':       /* One lock per cpu */
+                               one_lock=0;
+                               break;
+                       case 'e':       /* error arguments */
+                               /* Take parameters:
+                                * #cpu, loop, interval, err_type_info, err_struct_info[, err_data_buffer]
+                                * err_data_buffer is optional. Recommend not to specify
+                                * err_data_buffer. Better to use tool to generate it.
+                                */
+                               count=sscanf(optarg,
+                                       "%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx\n",
+                                       &line_para.cpu,
+                                       &line_para.loop,
+                                       &line_para.interval,
+                                       &line_para.err_type_info,
+                                       &line_para.err_struct_info,
+                                       &line_para.err_data_buffer[0],
+                                       &line_para.err_data_buffer[1],
+                                       &line_para.err_data_buffer[2]);
+                               if (count!=PARA_FIELD_NUM+3) {
+                                   line_para.err_data_buffer[0]=-1,
+                                   line_para.err_data_buffer[1]=-1,
+                                   line_para.err_data_buffer[2]=-1;
+                                   count=sscanf(optarg, "%lx, %lx, %lx, %lx, %lx\n",
+                                               &line_para.cpu,
+                                               &line_para.loop,
+                                               &line_para.interval,
+                                               &line_para.err_type_info,
+                                               &line_para.err_struct_info);
+                                   if (count!=PARA_FIELD_NUM) {
+                                       printf("Wrong error arguments.\n");
+                                       help();
+                                       return -1;
+                                   }
+                               }
+                               para=1;
+                               break;
+                       continue;
+                               break;
+                       case 'h':
+                               help();
+                               return 0;
+                       default:
+                               break;
+               }
+
+       if (do_query_all)
+               query_all_capabilities();
+       if (do_err_inj)
+               err_inj();
+
+       if (!do_query_all &&  !do_err_inj)
+               help();
+
+       return 0;
+  }
diff --git a/Documentation/ia64/err_inject.txt b/Documentation/ia64/err_inject.txt
deleted file mode 100644 (file)
index 9f651c1..0000000
+++ /dev/null
@@ -1,1068 +0,0 @@
-
-IPF Machine Check (MC) error inject tool
-========================================
-
-IPF Machine Check (MC) error inject tool is used to inject MC
-errors from Linux. The tool is a test bed for IPF MC work flow including
-hardware correctable error handling, OS recoverable error handling, MC
-event logging, etc.
-
-The tool includes two parts: a kernel driver and a user application
-sample. The driver provides interface to PAL to inject error
-and query error injection capabilities. The driver code is in
-arch/ia64/kernel/err_inject.c. The application sample (shown below)
-provides a combination of various errors and calls the driver's interface
-(sysfs interface) to inject errors or query error injection capabilities.
-
-The tool can be used to test Intel IPF machine MC handling capabilities.
-It's especially useful for people who can not access hardware MC injection
-tool to inject error. It's also very useful to integrate with other
-software test suits to do stressful testing on IPF.
-
-Below is a sample application as part of the whole tool. The sample
-can be used as a working test tool. Or it can be expanded to include
-more features. It also can be a integrated into a library or other user
-application to have more thorough test.
-
-The sample application takes err.conf as error configuration input. GCC
-compiles the code. After you install err_inject driver, you can run
-this sample application to inject errors.
-
-Errata: Itanium 2 Processors Specification Update lists some errata against
-the pal_mc_error_inject PAL procedure. The following err.conf has been tested
-on latest Montecito PAL.
-
-err.conf:
-
-#This is configuration file for err_inject_tool.
-#The format of the each line is:
-#cpu, loop, interval, err_type_info, err_struct_info, err_data_buffer
-#where
-#      cpu: logical cpu number the error will be inject in.
-#      loop: times the error will be injected.
-#      interval: In second. every so often one error is injected.
-#      err_type_info, err_struct_info: PAL parameters.
-#
-#Note: All values are hex w/o or w/ 0x prefix.
-
-
-#On cpu2, inject only total 0x10 errors, interval 5 seconds
-#corrected, data cache, hier-2, physical addr(assigned by tool code).
-#working on Montecito latest PAL.
-2, 10, 5, 4101, 95
-
-#On cpu4, inject and consume total 0x10 errors, interval 5 seconds
-#corrected, data cache, hier-2, physical addr(assigned by tool code).
-#working on Montecito latest PAL.
-4, 10, 5, 4109, 95
-
-#On cpu15, inject and consume total 0x10 errors, interval 5 seconds
-#recoverable, DTR0, hier-2.
-#working on Montecito latest PAL.
-0xf, 0x10, 5, 4249, 15
-
-The sample application source code:
-
-err_injection_tool.c:
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Copyright (C) 2006 Intel Co
- *     Fenghua Yu <fenghua.yu@intel.com>
- *
- */
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <sched.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <errno.h>
-#include <time.h>
-#include <sys/ipc.h>
-#include <sys/sem.h>
-#include <sys/wait.h>
-#include <sys/mman.h>
-#include <sys/shm.h>
-
-#define MAX_FN_SIZE            256
-#define MAX_BUF_SIZE           256
-#define DATA_BUF_SIZE          256
-#define NR_CPUS                512
-#define MAX_TASK_NUM           2048
-#define MIN_INTERVAL           5       // seconds
-#define        ERR_DATA_BUFFER_SIZE    3       // Three 8-byte.
-#define PARA_FIELD_NUM         5
-#define MASK_SIZE              (NR_CPUS/64)
-#define PATH_FORMAT "/sys/devices/system/cpu/cpu%d/err_inject/"
-
-int sched_setaffinity(pid_t pid, unsigned int len, unsigned long *mask);
-
-int verbose;
-#define vbprintf if (verbose) printf
-
-int log_info(int cpu, const char *fmt, ...)
-{
-       FILE *log;
-       char fn[MAX_FN_SIZE];
-       char buf[MAX_BUF_SIZE];
-       va_list args;
-
-       sprintf(fn, "%d.log", cpu);
-       log=fopen(fn, "a+");
-       if (log==NULL) {
-               perror("Error open:");
-               return -1;
-       }
-
-       va_start(args, fmt);
-       vprintf(fmt, args);
-       memset(buf, 0, MAX_BUF_SIZE);
-       vsprintf(buf, fmt, args);
-       va_end(args);
-
-       fwrite(buf, sizeof(buf), 1, log);
-       fclose(log);
-
-       return 0;
-}
-
-typedef unsigned long u64;
-typedef unsigned int  u32;
-
-typedef union err_type_info_u {
-       struct {
-               u64     mode            : 3,    /* 0-2 */
-                       err_inj         : 3,    /* 3-5 */
-                       err_sev         : 2,    /* 6-7 */
-                       err_struct      : 5,    /* 8-12 */
-                       struct_hier     : 3,    /* 13-15 */
-                       reserved        : 48;   /* 16-63 */
-       } err_type_info_u;
-       u64     err_type_info;
-} err_type_info_t;
-
-typedef union err_struct_info_u {
-       struct {
-               u64     siv             : 1,    /* 0     */
-                       c_t             : 2,    /* 1-2   */
-                       cl_p            : 3,    /* 3-5   */
-                       cl_id           : 3,    /* 6-8   */
-                       cl_dp           : 1,    /* 9     */
-                       reserved1       : 22,   /* 10-31 */
-                       tiv             : 1,    /* 32    */
-                       trigger         : 4,    /* 33-36 */
-                       trigger_pl      : 3,    /* 37-39 */
-                       reserved2       : 24;   /* 40-63 */
-       } err_struct_info_cache;
-       struct {
-               u64     siv             : 1,    /* 0     */
-                       tt              : 2,    /* 1-2   */
-                       tc_tr           : 2,    /* 3-4   */
-                       tr_slot         : 8,    /* 5-12  */
-                       reserved1       : 19,   /* 13-31 */
-                       tiv             : 1,    /* 32    */
-                       trigger         : 4,    /* 33-36 */
-                       trigger_pl      : 3,    /* 37-39 */
-                       reserved2       : 24;   /* 40-63 */
-       } err_struct_info_tlb;
-       struct {
-               u64     siv             : 1,    /* 0     */
-                       regfile_id      : 4,    /* 1-4   */
-                       reg_num         : 7,    /* 5-11  */
-                       reserved1       : 20,   /* 12-31 */
-                       tiv             : 1,    /* 32    */
-                       trigger         : 4,    /* 33-36 */
-                       trigger_pl      : 3,    /* 37-39 */
-                       reserved2       : 24;   /* 40-63 */
-       } err_struct_info_register;
-       struct {
-               u64     reserved;
-       } err_struct_info_bus_processor_interconnect;
-       u64     err_struct_info;
-} err_struct_info_t;
-
-typedef union err_data_buffer_u {
-       struct {
-               u64     trigger_addr;           /* 0-63         */
-               u64     inj_addr;               /* 64-127       */
-               u64     way             : 5,    /* 128-132      */
-                       index           : 20,   /* 133-152      */
-                                       : 39;   /* 153-191      */
-       } err_data_buffer_cache;
-       struct {
-               u64     trigger_addr;           /* 0-63         */
-               u64     inj_addr;               /* 64-127       */
-               u64     way             : 5,    /* 128-132      */
-                       index           : 20,   /* 133-152      */
-                       reserved        : 39;   /* 153-191      */
-       } err_data_buffer_tlb;
-       struct {
-               u64     trigger_addr;           /* 0-63         */
-       } err_data_buffer_register;
-       struct {
-               u64     reserved;               /* 0-63         */
-       } err_data_buffer_bus_processor_interconnect;
-       u64 err_data_buffer[ERR_DATA_BUFFER_SIZE];
-} err_data_buffer_t;
-
-typedef union capabilities_u {
-       struct {
-               u64     i               : 1,
-                       d               : 1,
-                       rv              : 1,
-                       tag             : 1,
-                       data            : 1,
-                       mesi            : 1,
-                       dp              : 1,
-                       reserved1       : 3,
-                       pa              : 1,
-                       va              : 1,
-                       wi              : 1,
-                       reserved2       : 20,
-                       trigger         : 1,
-                       trigger_pl      : 1,
-                       reserved3       : 30;
-       } capabilities_cache;
-       struct {
-               u64     d               : 1,
-                       i               : 1,
-                       rv              : 1,
-                       tc              : 1,
-                       tr              : 1,
-                       reserved1       : 27,
-                       trigger         : 1,
-                       trigger_pl      : 1,
-                       reserved2       : 30;
-       } capabilities_tlb;
-       struct {
-               u64     gr_b0           : 1,
-                       gr_b1           : 1,
-                       fr              : 1,
-                       br              : 1,
-                       pr              : 1,
-                       ar              : 1,
-                       cr              : 1,
-                       rr              : 1,
-                       pkr             : 1,
-                       dbr             : 1,
-                       ibr             : 1,
-                       pmc             : 1,
-                       pmd             : 1,
-                       reserved1       : 3,
-                       regnum          : 1,
-                       reserved2       : 15,
-                       trigger         : 1,
-                       trigger_pl      : 1,
-                       reserved3       : 30;
-       } capabilities_register;
-       struct {
-               u64     reserved;
-       } capabilities_bus_processor_interconnect;
-} capabilities_t;
-
-typedef struct resources_s {
-       u64     ibr0            : 1,
-               ibr2            : 1,
-               ibr4            : 1,
-               ibr6            : 1,
-               dbr0            : 1,
-               dbr2            : 1,
-               dbr4            : 1,
-               dbr6            : 1,
-               reserved        : 48;
-} resources_t;
-
-
-long get_page_size(void)
-{
-       long page_size=sysconf(_SC_PAGESIZE);
-       return page_size;
-}
-
-#define PAGE_SIZE (get_page_size()==-1?0x4000:get_page_size())
-#define SHM_SIZE (2*PAGE_SIZE*NR_CPUS)
-#define SHM_VA 0x2000000100000000
-
-int shmid;
-void *shmaddr;
-
-int create_shm(void)
-{
-       key_t key;
-       char fn[MAX_FN_SIZE];
-
-       /* cpu0 is always existing */
-       sprintf(fn, PATH_FORMAT, 0);
-       if ((key = ftok(fn, 's')) == -1) {
-               perror("ftok");
-               return -1;
-       }
-
-       shmid = shmget(key, SHM_SIZE, 0644 | IPC_CREAT);
-       if (shmid == -1) {
-               if (errno==EEXIST) {
-                       shmid = shmget(key, SHM_SIZE, 0);
-                       if (shmid == -1) {
-                               perror("shmget");
-                               return -1;
-                       }
-               }
-               else {
-                       perror("shmget");
-                       return -1;
-               }
-       }
-       vbprintf("shmid=%d", shmid);
-
-       /* connect to the segment: */
-       shmaddr = shmat(shmid, (void *)SHM_VA, 0);
-       if (shmaddr == (void*)-1) {
-               perror("shmat");
-               return -1;
-       }
-
-       memset(shmaddr, 0, SHM_SIZE);
-       mlock(shmaddr, SHM_SIZE);
-
-       return 0;
-}
-
-int free_shm()
-{
-       munlock(shmaddr, SHM_SIZE);
-        shmdt(shmaddr);
-       semctl(shmid, 0, IPC_RMID);
-
-       return 0;
-}
-
-#ifdef _SEM_SEMUN_UNDEFINED
-union semun
-{
-       int val;
-       struct semid_ds *buf;
-       unsigned short int *array;
-       struct seminfo *__buf;
-};
-#endif
-
-u32 mode=1; /* 1: physical mode; 2: virtual mode. */
-int one_lock=1;
-key_t key[NR_CPUS];
-int semid[NR_CPUS];
-
-int create_sem(int cpu)
-{
-       union semun arg;
-       char fn[MAX_FN_SIZE];
-       int sid;
-
-       sprintf(fn, PATH_FORMAT, cpu);
-       sprintf(fn, "%s/%s", fn, "err_type_info");
-       if ((key[cpu] = ftok(fn, 'e')) == -1) {
-               perror("ftok");
-               return -1;
-       }
-
-       if (semid[cpu]!=0)
-               return 0;
-
-       /* clear old semaphore */
-       if ((sid = semget(key[cpu], 1, 0)) != -1)
-               semctl(sid, 0, IPC_RMID);
-
-       /* get one semaphore */
-       if ((semid[cpu] = semget(key[cpu], 1, IPC_CREAT | IPC_EXCL)) == -1) {
-               perror("semget");
-               printf("Please remove semaphore with key=0x%lx, then run the tool.\n",
-                       (u64)key[cpu]);
-               return -1;
-       }
-
-       vbprintf("semid[%d]=0x%lx, key[%d]=%lx\n",cpu,(u64)semid[cpu],cpu,
-               (u64)key[cpu]);
-       /* initialize the semaphore to 1: */
-       arg.val = 1;
-       if (semctl(semid[cpu], 0, SETVAL, arg) == -1) {
-               perror("semctl");
-               return -1;
-       }
-
-       return 0;
-}
-
-static int lock(int cpu)
-{
-       struct sembuf lock;
-
-       lock.sem_num = cpu;
-       lock.sem_op = 1;
-       semop(semid[cpu], &lock, 1);
-
-        return 0;
-}
-
-static int unlock(int cpu)
-{
-       struct sembuf unlock;
-
-       unlock.sem_num = cpu;
-       unlock.sem_op = -1;
-       semop(semid[cpu], &unlock, 1);
-
-        return 0;
-}
-
-void free_sem(int cpu)
-{
-       semctl(semid[cpu], 0, IPC_RMID);
-}
-
-int wr_multi(char *fn, unsigned long *data, int size)
-{
-       int fd;
-       char buf[MAX_BUF_SIZE];
-       int ret;
-
-       if (size==1)
-               sprintf(buf, "%lx", *data);
-       else if (size==3)
-               sprintf(buf, "%lx,%lx,%lx", data[0], data[1], data[2]);
-       else {
-               fprintf(stderr,"write to file with wrong size!\n");
-               return -1;
-       }
-
-       fd=open(fn, O_RDWR);
-       if (!fd) {
-               perror("Error:");
-               return -1;
-       }
-       ret=write(fd, buf, sizeof(buf));
-       close(fd);
-       return ret;
-}
-
-int wr(char *fn, unsigned long data)
-{
-       return wr_multi(fn, &data, 1);
-}
-
-int rd(char *fn, unsigned long *data)
-{
-       int fd;
-       char buf[MAX_BUF_SIZE];
-
-       fd=open(fn, O_RDONLY);
-       if (fd<0) {
-               perror("Error:");
-               return -1;
-       }
-       read(fd, buf, MAX_BUF_SIZE);
-       *data=strtoul(buf, NULL, 16);
-       close(fd);
-       return 0;
-}
-
-int rd_status(char *path, int *status)
-{
-       char fn[MAX_FN_SIZE];
-       sprintf(fn, "%s/status", path);
-       if (rd(fn, (u64*)status)<0) {
-               perror("status reading error.\n");
-               return -1;
-       }
-
-       return 0;
-}
-
-int rd_capabilities(char *path, u64 *capabilities)
-{
-       char fn[MAX_FN_SIZE];
-       sprintf(fn, "%s/capabilities", path);
-       if (rd(fn, capabilities)<0) {
-               perror("capabilities reading error.\n");
-               return -1;
-       }
-
-       return 0;
-}
-
-int rd_all(char *path)
-{
-       unsigned long err_type_info, err_struct_info, err_data_buffer;
-       int status;
-       unsigned long capabilities, resources;
-       char fn[MAX_FN_SIZE];
-
-       sprintf(fn, "%s/err_type_info", path);
-       if (rd(fn, &err_type_info)<0) {
-               perror("err_type_info reading error.\n");
-               return -1;
-       }
-       printf("err_type_info=%lx\n", err_type_info);
-
-       sprintf(fn, "%s/err_struct_info", path);
-       if (rd(fn, &err_struct_info)<0) {
-               perror("err_struct_info reading error.\n");
-               return -1;
-       }
-       printf("err_struct_info=%lx\n", err_struct_info);
-
-       sprintf(fn, "%s/err_data_buffer", path);
-       if (rd(fn, &err_data_buffer)<0) {
-               perror("err_data_buffer reading error.\n");
-               return -1;
-       }
-       printf("err_data_buffer=%lx\n", err_data_buffer);
-
-       sprintf(fn, "%s/status", path);
-       if (rd("status", (u64*)&status)<0) {
-               perror("status reading error.\n");
-               return -1;
-       }
-       printf("status=%d\n", status);
-
-       sprintf(fn, "%s/capabilities", path);
-       if (rd(fn,&capabilities)<0) {
-               perror("capabilities reading error.\n");
-               return -1;
-       }
-       printf("capabilities=%lx\n", capabilities);
-
-       sprintf(fn, "%s/resources", path);
-       if (rd(fn, &resources)<0) {
-               perror("resources reading error.\n");
-               return -1;
-       }
-       printf("resources=%lx\n", resources);
-
-       return 0;
-}
-
-int query_capabilities(char *path, err_type_info_t err_type_info,
-                       u64 *capabilities)
-{
-       char fn[MAX_FN_SIZE];
-       err_struct_info_t err_struct_info;
-       err_data_buffer_t err_data_buffer;
-
-       err_struct_info.err_struct_info=0;
-       memset(err_data_buffer.err_data_buffer, -1, ERR_DATA_BUFFER_SIZE*8);
-
-       sprintf(fn, "%s/err_type_info", path);
-       wr(fn, err_type_info.err_type_info);
-       sprintf(fn, "%s/err_struct_info", path);
-       wr(fn, 0x0);
-       sprintf(fn, "%s/err_data_buffer", path);
-       wr_multi(fn, err_data_buffer.err_data_buffer, ERR_DATA_BUFFER_SIZE);
-
-       // Fire pal_mc_error_inject procedure.
-       sprintf(fn, "%s/call_start", path);
-       wr(fn, mode);
-
-       if (rd_capabilities(path, capabilities)<0)
-               return -1;
-
-       return 0;
-}
-
-int query_all_capabilities()
-{
-       int status;
-       err_type_info_t err_type_info;
-       int err_sev, err_struct, struct_hier;
-       int cap=0;
-       u64 capabilities;
-       char path[MAX_FN_SIZE];
-
-       err_type_info.err_type_info=0;                  // Initial
-       err_type_info.err_type_info_u.mode=0;           // Query mode;
-       err_type_info.err_type_info_u.err_inj=0;
-
-       printf("All capabilities implemented in pal_mc_error_inject:\n");
-       sprintf(path, PATH_FORMAT ,0);
-       for (err_sev=0;err_sev<3;err_sev++)
-               for (err_struct=0;err_struct<5;err_struct++)
-                       for (struct_hier=0;struct_hier<5;struct_hier++)
-       {
-               status=-1;
-               capabilities=0;
-               err_type_info.err_type_info_u.err_sev=err_sev;
-               err_type_info.err_type_info_u.err_struct=err_struct;
-               err_type_info.err_type_info_u.struct_hier=struct_hier;
-
-               if (query_capabilities(path, err_type_info, &capabilities)<0)
-                       continue;
-
-               if (rd_status(path, &status)<0)
-                       continue;
-
-               if (status==0) {
-                       cap=1;
-                       printf("For err_sev=%d, err_struct=%d, struct_hier=%d: ",
-                               err_sev, err_struct, struct_hier);
-                       printf("capabilities 0x%lx\n", capabilities);
-               }
-       }
-       if (!cap) {
-               printf("No capabilities supported.\n");
-               return 0;
-       }
-
-       return 0;
-}
-
-int err_inject(int cpu, char *path, err_type_info_t err_type_info,
-               err_struct_info_t err_struct_info,
-               err_data_buffer_t err_data_buffer)
-{
-       int status;
-       char fn[MAX_FN_SIZE];
-
-       log_info(cpu, "err_type_info=%lx, err_struct_info=%lx, ",
-               err_type_info.err_type_info,
-               err_struct_info.err_struct_info);
-       log_info(cpu,"err_data_buffer=[%lx,%lx,%lx]\n",
-               err_data_buffer.err_data_buffer[0],
-               err_data_buffer.err_data_buffer[1],
-               err_data_buffer.err_data_buffer[2]);
-       sprintf(fn, "%s/err_type_info", path);
-       wr(fn, err_type_info.err_type_info);
-       sprintf(fn, "%s/err_struct_info", path);
-       wr(fn, err_struct_info.err_struct_info);
-       sprintf(fn, "%s/err_data_buffer", path);
-       wr_multi(fn, err_data_buffer.err_data_buffer, ERR_DATA_BUFFER_SIZE);
-
-       // Fire pal_mc_error_inject procedure.
-       sprintf(fn, "%s/call_start", path);
-       wr(fn,mode);
-
-       if (rd_status(path, &status)<0) {
-               vbprintf("fail: read status\n");
-               return -100;
-       }
-
-       if (status!=0) {
-               log_info(cpu, "fail: status=%d\n", status);
-               return status;
-       }
-
-       return status;
-}
-
-static int construct_data_buf(char *path, err_type_info_t err_type_info,
-               err_struct_info_t err_struct_info,
-               err_data_buffer_t *err_data_buffer,
-               void *va1)
-{
-       char fn[MAX_FN_SIZE];
-       u64 virt_addr=0, phys_addr=0;
-
-       vbprintf("va1=%lx\n", (u64)va1);
-       memset(&err_data_buffer->err_data_buffer_cache, 0, ERR_DATA_BUFFER_SIZE*8);
-
-       switch (err_type_info.err_type_info_u.err_struct) {
-               case 1: // Cache
-                       switch (err_struct_info.err_struct_info_cache.cl_id) {
-                               case 1: //Virtual addr
-                                       err_data_buffer->err_data_buffer_cache.inj_addr=(u64)va1;
-                                       break;
-                               case 2: //Phys addr
-                                       sprintf(fn, "%s/virtual_to_phys", path);
-                                       virt_addr=(u64)va1;
-                                       if (wr(fn,virt_addr)<0)
-                                               return -1;
-                                       rd(fn, &phys_addr);
-                                       err_data_buffer->err_data_buffer_cache.inj_addr=phys_addr;
-                                       break;
-                               default:
-                                       printf("Not supported cl_id\n");
-                                       break;
-                       }
-                       break;
-               case 2: //  TLB
-                       break;
-               case 3: //  Register file
-                       break;
-               case 4: //  Bus/system interconnect
-               default:
-                       printf("Not supported err_struct\n");
-                       break;
-       }
-
-       return 0;
-}
-
-typedef struct {
-       u64 cpu;
-       u64 loop;
-       u64 interval;
-       u64 err_type_info;
-       u64 err_struct_info;
-       u64 err_data_buffer[ERR_DATA_BUFFER_SIZE];
-} parameters_t;
-
-parameters_t line_para;
-int para;
-
-static int empty_data_buffer(u64 *err_data_buffer)
-{
-       int empty=1;
-       int i;
-
-       for (i=0;i<ERR_DATA_BUFFER_SIZE; i++)
-          if (err_data_buffer[i]!=-1)
-               empty=0;
-
-       return empty;
-}
-
-int err_inj()
-{
-       err_type_info_t err_type_info;
-       err_struct_info_t err_struct_info;
-       err_data_buffer_t err_data_buffer;
-       int count;
-       FILE *fp;
-       unsigned long cpu, loop, interval, err_type_info_conf, err_struct_info_conf;
-       u64 err_data_buffer_conf[ERR_DATA_BUFFER_SIZE];
-       int num;
-       int i;
-       char path[MAX_FN_SIZE];
-       parameters_t parameters[MAX_TASK_NUM]={};
-       pid_t child_pid[MAX_TASK_NUM];
-       time_t current_time;
-       int status;
-
-       if (!para) {
-           fp=fopen("err.conf", "r");
-           if (fp==NULL) {
-               perror("Error open err.conf");
-               return -1;
-           }
-
-           num=0;
-           while (!feof(fp)) {
-               char buf[256];
-               memset(buf,0,256);
-               fgets(buf, 256, fp);
-               count=sscanf(buf, "%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx\n",
-                               &cpu, &loop, &interval,&err_type_info_conf,
-                               &err_struct_info_conf,
-                               &err_data_buffer_conf[0],
-                               &err_data_buffer_conf[1],
-                               &err_data_buffer_conf[2]);
-               if (count!=PARA_FIELD_NUM+3) {
-                       err_data_buffer_conf[0]=-1;
-                       err_data_buffer_conf[1]=-1;
-                       err_data_buffer_conf[2]=-1;
-                       count=sscanf(buf, "%lx, %lx, %lx, %lx, %lx\n",
-                               &cpu, &loop, &interval,&err_type_info_conf,
-                               &err_struct_info_conf);
-                       if (count!=PARA_FIELD_NUM)
-                               continue;
-               }
-
-               parameters[num].cpu=cpu;
-               parameters[num].loop=loop;
-               parameters[num].interval= interval>MIN_INTERVAL
-                                         ?interval:MIN_INTERVAL;
-               parameters[num].err_type_info=err_type_info_conf;
-               parameters[num].err_struct_info=err_struct_info_conf;
-               memcpy(parameters[num++].err_data_buffer,
-                       err_data_buffer_conf,ERR_DATA_BUFFER_SIZE*8) ;
-
-               if (num>=MAX_TASK_NUM)
-                       break;
-           }
-       }
-       else {
-               parameters[0].cpu=line_para.cpu;
-               parameters[0].loop=line_para.loop;
-               parameters[0].interval= line_para.interval>MIN_INTERVAL
-                                         ?line_para.interval:MIN_INTERVAL;
-               parameters[0].err_type_info=line_para.err_type_info;
-               parameters[0].err_struct_info=line_para.err_struct_info;
-               memcpy(parameters[0].err_data_buffer,
-                       line_para.err_data_buffer,ERR_DATA_BUFFER_SIZE*8) ;
-
-               num=1;
-       }
-
-       /* Create semaphore: If one_lock, one semaphore for all processors.
-          Otherwise, one semaphore for each processor. */
-       if (one_lock) {
-               if (create_sem(0)) {
-                       printf("Can not create semaphore...exit\n");
-                       free_sem(0);
-                       return -1;
-               }
-       }
-       else {
-               for (i=0;i<num;i++) {
-                  if (create_sem(parameters[i].cpu)) {
-                       printf("Can not create semaphore for cpu%d...exit\n",i);
-                       free_sem(parameters[num].cpu);
-                       return -1;
-                  }
-               }
-       }
-
-       /* Create a shm segment which will be used to inject/consume errors on.*/
-       if (create_shm()==-1) {
-               printf("Error to create shm...exit\n");
-               return -1;
-       }
-
-       for (i=0;i<num;i++) {
-               pid_t pid;
-
-               current_time=time(NULL);
-               log_info(parameters[i].cpu, "\nBegine at %s", ctime(&current_time));
-               log_info(parameters[i].cpu, "Configurations:\n");
-               log_info(parameters[i].cpu,"On cpu%ld: loop=%lx, interval=%lx(s)",
-                       parameters[i].cpu,
-                       parameters[i].loop,
-                       parameters[i].interval);
-               log_info(parameters[i].cpu," err_type_info=%lx,err_struct_info=%lx\n",
-                       parameters[i].err_type_info,
-                       parameters[i].err_struct_info);
-
-               sprintf(path, PATH_FORMAT, (int)parameters[i].cpu);
-               err_type_info.err_type_info=parameters[i].err_type_info;
-               err_struct_info.err_struct_info=parameters[i].err_struct_info;
-               memcpy(err_data_buffer.err_data_buffer,
-                       parameters[i].err_data_buffer,
-                       ERR_DATA_BUFFER_SIZE*8);
-
-               pid=fork();
-               if (pid==0) {
-                       unsigned long mask[MASK_SIZE];
-                       int j, k;
-
-                       void *va1, *va2;
-
-                       /* Allocate two memory areas va1 and va2 in shm */
-                       va1=shmaddr+parameters[i].cpu*PAGE_SIZE;
-                       va2=shmaddr+parameters[i].cpu*PAGE_SIZE+PAGE_SIZE;
-
-                       vbprintf("va1=%lx, va2=%lx\n", (u64)va1, (u64)va2);
-                       memset(va1, 0x1, PAGE_SIZE);
-                       memset(va2, 0x2, PAGE_SIZE);
-
-                       if (empty_data_buffer(err_data_buffer.err_data_buffer))
-                               /* If not specified yet, construct data buffer
-                                * with va1
-                                */
-                               construct_data_buf(path, err_type_info,
-                                       err_struct_info, &err_data_buffer,va1);
-
-                       for (j=0;j<MASK_SIZE;j++)
-                               mask[j]=0;
-
-                       cpu=parameters[i].cpu;
-                       k = cpu%64;
-                       j = cpu/64;
-                       mask[j] = 1UL << k;
-
-                       if (sched_setaffinity(0, MASK_SIZE*8, mask)==-1) {
-                               perror("Error sched_setaffinity:");
-                               return -1;
-                       }
-
-                       for (j=0; j<parameters[i].loop; j++) {
-                               log_info(parameters[i].cpu,"Injection ");
-                               log_info(parameters[i].cpu,"on cpu%ld: #%d/%ld ",
-
-                                       parameters[i].cpu,j+1, parameters[i].loop);
-
-                               /* Hold the lock */
-                               if (one_lock)
-                                       lock(0);
-                               else
-                               /* Hold lock on this cpu */
-                                       lock(parameters[i].cpu);
-
-                               if ((status=err_inject(parameters[i].cpu,
-                                          path, err_type_info,
-                                          err_struct_info, err_data_buffer))
-                                          ==0) {
-                                       /* consume the error for "inject only"*/
-                                       memcpy(va2, va1, PAGE_SIZE);
-                                       memcpy(va1, va2, PAGE_SIZE);
-                                       log_info(parameters[i].cpu,
-                                               "successful\n");
-                               }
-                               else {
-                                       log_info(parameters[i].cpu,"fail:");
-                                       log_info(parameters[i].cpu,
-                                               "status=%d\n", status);
-                                       unlock(parameters[i].cpu);
-                                       break;
-                               }
-                               if (one_lock)
-                               /* Release the lock */
-                                       unlock(0);
-                               /* Release lock on this cpu */
-                               else
-                                       unlock(parameters[i].cpu);
-
-                               if (j < parameters[i].loop-1)
-                                       sleep(parameters[i].interval);
-                       }
-                       current_time=time(NULL);
-                       log_info(parameters[i].cpu, "Done at %s", ctime(&current_time));
-                       return 0;
-               }
-               else if (pid<0) {
-                       perror("Error fork:");
-                       continue;
-               }
-               child_pid[i]=pid;
-       }
-       for (i=0;i<num;i++)
-               waitpid(child_pid[i], NULL, 0);
-
-       if (one_lock)
-               free_sem(0);
-       else
-               for (i=0;i<num;i++)
-                       free_sem(parameters[i].cpu);
-
-       printf("All done.\n");
-
-       return 0;
-}
-
-void help()
-{
-       printf("err_inject_tool:\n");
-       printf("\t-q: query all capabilities. default: off\n");
-       printf("\t-m: procedure mode. 1: physical 2: virtual. default: 1\n");
-       printf("\t-i: inject errors. default: off\n");
-       printf("\t-l: one lock per cpu. default: one lock for all\n");
-       printf("\t-e: error parameters:\n");
-       printf("\t\tcpu,loop,interval,err_type_info,err_struct_info[,err_data_buffer[0],err_data_buffer[1],err_data_buffer[2]]\n");
-       printf("\t\t   cpu: logical cpu number the error will be inject in.\n");
-       printf("\t\t   loop: times the error will be injected.\n");
-       printf("\t\t   interval: In second. every so often one error is injected.\n");
-       printf("\t\t   err_type_info, err_struct_info: PAL parameters.\n");
-       printf("\t\t   err_data_buffer: PAL parameter. Optional. If not present,\n");
-       printf("\t\t                    it's constructed by tool automatically. Be\n");
-       printf("\t\t                    careful to provide err_data_buffer and make\n");
-       printf("\t\t                    sure it's working with the environment.\n");
-       printf("\t    Note:no space between error parameters.\n");
-       printf("\t    default: Take error parameters from err.conf instead of command line.\n");
-       printf("\t-v: verbose. default: off\n");
-       printf("\t-h: help\n\n");
-       printf("The tool will take err.conf file as ");
-       printf("input to inject single or multiple errors ");
-       printf("on one or multiple cpus in parallel.\n");
-}
-
-int main(int argc, char **argv)
-{
-       char c;
-       int do_err_inj=0;
-       int do_query_all=0;
-       int count;
-       u32 m;
-
-       /* Default one lock for all cpu's */
-       one_lock=1;
-       while ((c = getopt(argc, argv, "m:iqvhle:")) != EOF)
-               switch (c) {
-                       case 'm':       /* Procedure mode. 1: phys 2: virt */
-                               count=sscanf(optarg, "%x", &m);
-                               if (count!=1 || (m!=1 && m!=2)) {
-                                       printf("Wrong mode number.\n");
-                                       help();
-                                       return -1;
-                               }
-                               mode=m;
-                               break;
-                       case 'i':       /* Inject errors */
-                               do_err_inj=1;
-                               break;
-                       case 'q':       /* Query */
-                               do_query_all=1;
-                               break;
-                       case 'v':       /* Verbose */
-                               verbose=1;
-                               break;
-                       case 'l':       /* One lock per cpu */
-                               one_lock=0;
-                               break;
-                       case 'e':       /* error arguments */
-                               /* Take parameters:
-                                * #cpu, loop, interval, err_type_info, err_struct_info[, err_data_buffer]
-                                * err_data_buffer is optional. Recommend not to specify
-                                * err_data_buffer. Better to use tool to generate it.
-                                */
-                               count=sscanf(optarg,
-                                       "%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx\n",
-                                       &line_para.cpu,
-                                       &line_para.loop,
-                                       &line_para.interval,
-                                       &line_para.err_type_info,
-                                       &line_para.err_struct_info,
-                                       &line_para.err_data_buffer[0],
-                                       &line_para.err_data_buffer[1],
-                                       &line_para.err_data_buffer[2]);
-                               if (count!=PARA_FIELD_NUM+3) {
-                                   line_para.err_data_buffer[0]=-1,
-                                   line_para.err_data_buffer[1]=-1,
-                                   line_para.err_data_buffer[2]=-1;
-                                   count=sscanf(optarg, "%lx, %lx, %lx, %lx, %lx\n",
-                                               &line_para.cpu,
-                                               &line_para.loop,
-                                               &line_para.interval,
-                                               &line_para.err_type_info,
-                                               &line_para.err_struct_info);
-                                   if (count!=PARA_FIELD_NUM) {
-                                       printf("Wrong error arguments.\n");
-                                       help();
-                                       return -1;
-                                   }
-                               }
-                               para=1;
-                               break;
-                       continue;
-                               break;
-                       case 'h':
-                               help();
-                               return 0;
-                       default:
-                               break;
-               }
-
-       if (do_query_all)
-               query_all_capabilities();
-       if (do_err_inj)
-               err_inj();
-
-       if (!do_query_all &&  !do_err_inj)
-               help();
-
-       return 0;
-}
-
diff --git a/Documentation/ia64/fsys.rst b/Documentation/ia64/fsys.rst
new file mode 100644 (file)
index 0000000..a702d2c
--- /dev/null
@@ -0,0 +1,303 @@
+===================================
+Light-weight System Calls for IA-64
+===================================
+
+                       Started: 13-Jan-2003
+
+                   Last update: 27-Sep-2003
+
+                     David Mosberger-Tang
+                     <davidm@hpl.hp.com>
+
+Using the "epc" instruction effectively introduces a new mode of
+execution to the ia64 linux kernel.  We call this mode the
+"fsys-mode".  To recap, the normal states of execution are:
+
+  - kernel mode:
+       Both the register stack and the memory stack have been
+       switched over to kernel memory.  The user-level state is saved
+       in a pt-regs structure at the top of the kernel memory stack.
+
+  - user mode:
+       Both the register stack and the kernel stack are in
+       user memory.  The user-level state is contained in the
+       CPU registers.
+
+  - bank 0 interruption-handling mode:
+       This is the non-interruptible state which all
+       interruption-handlers start execution in.  The user-level
+       state remains in the CPU registers and some kernel state may
+       be stored in bank 0 of registers r16-r31.
+
+In contrast, fsys-mode has the following special properties:
+
+  - execution is at privilege level 0 (most-privileged)
+
+  - CPU registers may contain a mixture of user-level and kernel-level
+    state (it is the responsibility of the kernel to ensure that no
+    security-sensitive kernel-level state is leaked back to
+    user-level)
+
+  - execution is interruptible and preemptible (an fsys-mode handler
+    can disable interrupts and avoid all other interruption-sources
+    to avoid preemption)
+
+  - neither the memory-stack nor the register-stack can be trusted while
+    in fsys-mode (they point to the user-level stacks, which may
+    be invalid, or completely bogus addresses)
+
+In summary, fsys-mode is much more similar to running in user-mode
+than it is to running in kernel-mode.  Of course, given that the
+privilege level is at level 0, this means that fsys-mode requires some
+care (see below).
+
+
+How to tell fsys-mode
+=====================
+
+Linux operates in fsys-mode when (a) the privilege level is 0 (most
+privileged) and (b) the stacks have NOT been switched to kernel memory
+yet.  For convenience, the header file <asm-ia64/ptrace.h> provides
+three macros::
+
+       user_mode(regs)
+       user_stack(task,regs)
+       fsys_mode(task,regs)
+
+The "regs" argument is a pointer to a pt_regs structure.  The "task"
+argument is a pointer to the task structure to which the "regs"
+pointer belongs to.  user_mode() returns TRUE if the CPU state pointed
+to by "regs" was executing in user mode (privilege level 3).
+user_stack() returns TRUE if the state pointed to by "regs" was
+executing on the user-level stack(s).  Finally, fsys_mode() returns
+TRUE if the CPU state pointed to by "regs" was executing in fsys-mode.
+The fsys_mode() macro is equivalent to the expression::
+
+       !user_mode(regs) && user_stack(task,regs)
+
+How to write an fsyscall handler
+================================
+
+The file arch/ia64/kernel/fsys.S contains a table of fsyscall-handlers
+(fsyscall_table).  This table contains one entry for each system call.
+By default, a system call is handled by fsys_fallback_syscall().  This
+routine takes care of entering (full) kernel mode and calling the
+normal Linux system call handler.  For performance-critical system
+calls, it is possible to write a hand-tuned fsyscall_handler.  For
+example, fsys.S contains fsys_getpid(), which is a hand-tuned version
+of the getpid() system call.
+
+The entry and exit-state of an fsyscall handler is as follows:
+
+Machine state on entry to fsyscall handler
+------------------------------------------
+
+  ========= ===============================================================
+  r10      0
+  r11      saved ar.pfs (a user-level value)
+  r15      system call number
+  r16      "current" task pointer (in normal kernel-mode, this is in r13)
+  r32-r39   system call arguments
+  b6       return address (a user-level value)
+  ar.pfs    previous frame-state (a user-level value)
+  PSR.be    cleared to zero (i.e., little-endian byte order is in effect)
+  -         all other registers may contain values passed in from user-mode
+  ========= ===============================================================
+
+Required machine state on exit to fsyscall handler
+--------------------------------------------------
+
+  ========= ===========================================================
+  r11      saved ar.pfs (as passed into the fsyscall handler)
+  r15      system call number (as passed into the fsyscall handler)
+  r32-r39   system call arguments (as passed into the fsyscall handler)
+  b6       return address (as passed into the fsyscall handler)
+  ar.pfs    previous frame-state (as passed into the fsyscall handler)
+  ========= ===========================================================
+
+Fsyscall handlers can execute with very little overhead, but with that
+speed comes a set of restrictions:
+
+ * Fsyscall-handlers MUST check for any pending work in the flags
+   member of the thread-info structure and if any of the
+   TIF_ALLWORK_MASK flags are set, the handler needs to fall back on
+   doing a full system call (by calling fsys_fallback_syscall).
+
+ * Fsyscall-handlers MUST preserve incoming arguments (r32-r39, r11,
+   r15, b6, and ar.pfs) because they will be needed in case of a
+   system call restart.  Of course, all "preserved" registers also
+   must be preserved, in accordance to the normal calling conventions.
+
+ * Fsyscall-handlers MUST check argument registers for containing a
+   NaT value before using them in any way that could trigger a
+   NaT-consumption fault.  If a system call argument is found to
+   contain a NaT value, an fsyscall-handler may return immediately
+   with r8=EINVAL, r10=-1.
+
+ * Fsyscall-handlers MUST NOT use the "alloc" instruction or perform
+   any other operation that would trigger mandatory RSE
+   (register-stack engine) traffic.
+
+ * Fsyscall-handlers MUST NOT write to any stacked registers because
+   it is not safe to assume that user-level called a handler with the
+   proper number of arguments.
+
+ * Fsyscall-handlers need to be careful when accessing per-CPU variables:
+   unless proper safe-guards are taken (e.g., interruptions are avoided),
+   execution may be pre-empted and resumed on another CPU at any given
+   time.
+
+ * Fsyscall-handlers must be careful not to leak sensitive kernel'
+   information back to user-level.  In particular, before returning to
+   user-level, care needs to be taken to clear any scratch registers
+   that could contain sensitive information (note that the current
+   task pointer is not considered sensitive: it's already exposed
+   through ar.k6).
+
+ * Fsyscall-handlers MUST NOT access user-memory without first
+   validating access-permission (this can be done typically via
+   probe.r.fault and/or probe.w.fault) and without guarding against
+   memory access exceptions (this can be done with the EX() macros
+   defined by asmmacro.h).
+
+The above restrictions may seem draconian, but remember that it's
+possible to trade off some of the restrictions by paying a slightly
+higher overhead.  For example, if an fsyscall-handler could benefit
+from the shadow register bank, it could temporarily disable PSR.i and
+PSR.ic, switch to bank 0 (bsw.0) and then use the shadow registers as
+needed.  In other words, following the above rules yields extremely
+fast system call execution (while fully preserving system call
+semantics), but there is also a lot of flexibility in handling more
+complicated cases.
+
+Signal handling
+===============
+
+The delivery of (asynchronous) signals must be delayed until fsys-mode
+is exited.  This is accomplished with the help of the lower-privilege
+transfer trap: arch/ia64/kernel/process.c:do_notify_resume_user()
+checks whether the interrupted task was in fsys-mode and, if so, sets
+PSR.lp and returns immediately.  When fsys-mode is exited via the
+"br.ret" instruction that lowers the privilege level, a trap will
+occur.  The trap handler clears PSR.lp again and returns immediately.
+The kernel exit path then checks for and delivers any pending signals.
+
+PSR Handling
+============
+
+The "epc" instruction doesn't change the contents of PSR at all.  This
+is in contrast to a regular interruption, which clears almost all
+bits.  Because of that, some care needs to be taken to ensure things
+work as expected.  The following discussion describes how each PSR bit
+is handled.
+
+======= =======================================================================
+PSR.be Cleared when entering fsys-mode.  A srlz.d instruction is used
+       to ensure the CPU is in little-endian mode before the first
+       load/store instruction is executed.  PSR.be is normally NOT
+       restored upon return from an fsys-mode handler.  In other
+       words, user-level code must not rely on PSR.be being preserved
+       across a system call.
+PSR.up Unchanged.
+PSR.ac Unchanged.
+PSR.mfl Unchanged.  Note: fsys-mode handlers must not write-registers!
+PSR.mfh        Unchanged.  Note: fsys-mode handlers must not write-registers!
+PSR.ic Unchanged.  Note: fsys-mode handlers can clear the bit, if needed.
+PSR.i  Unchanged.  Note: fsys-mode handlers can clear the bit, if needed.
+PSR.pk Unchanged.
+PSR.dt Unchanged.
+PSR.dfl        Unchanged.  Note: fsys-mode handlers must not write-registers!
+PSR.dfh        Unchanged.  Note: fsys-mode handlers must not write-registers!
+PSR.sp Unchanged.
+PSR.pp Unchanged.
+PSR.di Unchanged.
+PSR.si Unchanged.
+PSR.db Unchanged.  The kernel prevents user-level from setting a hardware
+       breakpoint that triggers at any privilege level other than
+       3 (user-mode).
+PSR.lp Unchanged.
+PSR.tb Lazy redirect.  If a taken-branch trap occurs while in
+       fsys-mode, the trap-handler modifies the saved machine state
+       such that execution resumes in the gate page at
+       syscall_via_break(), with privilege level 3.  Note: the
+       taken branch would occur on the branch invoking the
+       fsyscall-handler, at which point, by definition, a syscall
+       restart is still safe.  If the system call number is invalid,
+       the fsys-mode handler will return directly to user-level.  This
+       return will trigger a taken-branch trap, but since the trap is
+       taken _after_ restoring the privilege level, the CPU has already
+       left fsys-mode, so no special treatment is needed.
+PSR.rt Unchanged.
+PSR.cpl        Cleared to 0.
+PSR.is Unchanged (guaranteed to be 0 on entry to the gate page).
+PSR.mc Unchanged.
+PSR.it Unchanged (guaranteed to be 1).
+PSR.id Unchanged.  Note: the ia64 linux kernel never sets this bit.
+PSR.da Unchanged.  Note: the ia64 linux kernel never sets this bit.
+PSR.dd Unchanged.  Note: the ia64 linux kernel never sets this bit.
+PSR.ss Lazy redirect.  If set, "epc" will cause a Single Step Trap to
+       be taken.  The trap handler then modifies the saved machine
+       state such that execution resumes in the gate page at
+       syscall_via_break(), with privilege level 3.
+PSR.ri Unchanged.
+PSR.ed Unchanged.  Note: This bit could only have an effect if an fsys-mode
+       handler performed a speculative load that gets NaTted.  If so, this
+       would be the normal & expected behavior, so no special treatment is
+       needed.
+PSR.bn Unchanged.  Note: fsys-mode handlers may clear the bit, if needed.
+       Doing so requires clearing PSR.i and PSR.ic as well.
+PSR.ia Unchanged.  Note: the ia64 linux kernel never sets this bit.
+======= =======================================================================
+
+Using fast system calls
+=======================
+
+To use fast system calls, userspace applications need simply call
+__kernel_syscall_via_epc().  For example
+
+-- example fgettimeofday() call --
+
+-- fgettimeofday.S --
+
+::
+
+  #include <asm/asmmacro.h>
+
+  GLOBAL_ENTRY(fgettimeofday)
+  .prologue
+  .save ar.pfs, r11
+  mov r11 = ar.pfs
+  .body
+
+  mov r2 = 0xa000000000020660;;  // gate address
+                              // found by inspection of System.map for the
+                              // __kernel_syscall_via_epc() function.  See
+                              // below for how to do this for real.
+
+  mov b7 = r2
+  mov r15 = 1087                      // gettimeofday syscall
+  ;;
+  br.call.sptk.many b6 = b7
+  ;;
+
+  .restore sp
+
+  mov ar.pfs = r11
+  br.ret.sptk.many rp;;              // return to caller
+  END(fgettimeofday)
+
+-- end fgettimeofday.S --
+
+In reality, getting the gate address is accomplished by two extra
+values passed via the ELF auxiliary vector (include/asm-ia64/elf.h)
+
+ * AT_SYSINFO : is the address of __kernel_syscall_via_epc()
+ * AT_SYSINFO_EHDR : is the address of the kernel gate ELF DSO
+
+The ELF DSO is a pre-linked library that is mapped in by the kernel at
+the gate page.  It is a proper ELF shared object so, with a dynamic
+loader that recognises the library, you should be able to make calls to
+the exported functions within it as with any other shared library.
+AT_SYSINFO points into the kernel DSO at the
+__kernel_syscall_via_epc() function for historical reasons (it was
+used before the kernel DSO) and as a convenience.
diff --git a/Documentation/ia64/fsys.txt b/Documentation/ia64/fsys.txt
deleted file mode 100644 (file)
index 59dd689..0000000
+++ /dev/null
@@ -1,286 +0,0 @@
--*-Mode: outline-*-
-
-               Light-weight System Calls for IA-64
-               -----------------------------------
-
-                       Started: 13-Jan-2003
-                   Last update: 27-Sep-2003
-
-                     David Mosberger-Tang
-                     <davidm@hpl.hp.com>
-
-Using the "epc" instruction effectively introduces a new mode of
-execution to the ia64 linux kernel.  We call this mode the
-"fsys-mode".  To recap, the normal states of execution are:
-
-  - kernel mode:
-       Both the register stack and the memory stack have been
-       switched over to kernel memory.  The user-level state is saved
-       in a pt-regs structure at the top of the kernel memory stack.
-
-  - user mode:
-       Both the register stack and the kernel stack are in
-       user memory.  The user-level state is contained in the
-       CPU registers.
-
-  - bank 0 interruption-handling mode:
-       This is the non-interruptible state which all
-       interruption-handlers start execution in.  The user-level
-       state remains in the CPU registers and some kernel state may
-       be stored in bank 0 of registers r16-r31.
-
-In contrast, fsys-mode has the following special properties:
-
-  - execution is at privilege level 0 (most-privileged)
-
-  - CPU registers may contain a mixture of user-level and kernel-level
-    state (it is the responsibility of the kernel to ensure that no
-    security-sensitive kernel-level state is leaked back to
-    user-level)
-
-  - execution is interruptible and preemptible (an fsys-mode handler
-    can disable interrupts and avoid all other interruption-sources
-    to avoid preemption)
-
-  - neither the memory-stack nor the register-stack can be trusted while
-    in fsys-mode (they point to the user-level stacks, which may
-    be invalid, or completely bogus addresses)
-
-In summary, fsys-mode is much more similar to running in user-mode
-than it is to running in kernel-mode.  Of course, given that the
-privilege level is at level 0, this means that fsys-mode requires some
-care (see below).
-
-
-* How to tell fsys-mode
-
-Linux operates in fsys-mode when (a) the privilege level is 0 (most
-privileged) and (b) the stacks have NOT been switched to kernel memory
-yet.  For convenience, the header file <asm-ia64/ptrace.h> provides
-three macros:
-
-       user_mode(regs)
-       user_stack(task,regs)
-       fsys_mode(task,regs)
-
-The "regs" argument is a pointer to a pt_regs structure.  The "task"
-argument is a pointer to the task structure to which the "regs"
-pointer belongs to.  user_mode() returns TRUE if the CPU state pointed
-to by "regs" was executing in user mode (privilege level 3).
-user_stack() returns TRUE if the state pointed to by "regs" was
-executing on the user-level stack(s).  Finally, fsys_mode() returns
-TRUE if the CPU state pointed to by "regs" was executing in fsys-mode.
-The fsys_mode() macro is equivalent to the expression:
-
-       !user_mode(regs) && user_stack(task,regs)
-
-* How to write an fsyscall handler
-
-The file arch/ia64/kernel/fsys.S contains a table of fsyscall-handlers
-(fsyscall_table).  This table contains one entry for each system call.
-By default, a system call is handled by fsys_fallback_syscall().  This
-routine takes care of entering (full) kernel mode and calling the
-normal Linux system call handler.  For performance-critical system
-calls, it is possible to write a hand-tuned fsyscall_handler.  For
-example, fsys.S contains fsys_getpid(), which is a hand-tuned version
-of the getpid() system call.
-
-The entry and exit-state of an fsyscall handler is as follows:
-
-** Machine state on entry to fsyscall handler:
-
- - r10   = 0
- - r11   = saved ar.pfs (a user-level value)
- - r15   = system call number
- - r16   = "current" task pointer (in normal kernel-mode, this is in r13)
- - r32-r39 = system call arguments
- - b6    = return address (a user-level value)
- - ar.pfs = previous frame-state (a user-level value)
- - PSR.be = cleared to zero (i.e., little-endian byte order is in effect)
- - all other registers may contain values passed in from user-mode
-
-** Required machine state on exit to fsyscall handler:
-
- - r11   = saved ar.pfs (as passed into the fsyscall handler)
- - r15   = system call number (as passed into the fsyscall handler)
- - r32-r39 = system call arguments (as passed into the fsyscall handler)
- - b6    = return address (as passed into the fsyscall handler)
- - ar.pfs = previous frame-state (as passed into the fsyscall handler)
-
-Fsyscall handlers can execute with very little overhead, but with that
-speed comes a set of restrictions:
-
- o Fsyscall-handlers MUST check for any pending work in the flags
-   member of the thread-info structure and if any of the
-   TIF_ALLWORK_MASK flags are set, the handler needs to fall back on
-   doing a full system call (by calling fsys_fallback_syscall).
-
- o Fsyscall-handlers MUST preserve incoming arguments (r32-r39, r11,
-   r15, b6, and ar.pfs) because they will be needed in case of a
-   system call restart.  Of course, all "preserved" registers also
-   must be preserved, in accordance to the normal calling conventions.
-
- o Fsyscall-handlers MUST check argument registers for containing a
-   NaT value before using them in any way that could trigger a
-   NaT-consumption fault.  If a system call argument is found to
-   contain a NaT value, an fsyscall-handler may return immediately
-   with r8=EINVAL, r10=-1.
-
- o Fsyscall-handlers MUST NOT use the "alloc" instruction or perform
-   any other operation that would trigger mandatory RSE
-   (register-stack engine) traffic.
-
- o Fsyscall-handlers MUST NOT write to any stacked registers because
-   it is not safe to assume that user-level called a handler with the
-   proper number of arguments.
-
- o Fsyscall-handlers need to be careful when accessing per-CPU variables:
-   unless proper safe-guards are taken (e.g., interruptions are avoided),
-   execution may be pre-empted and resumed on another CPU at any given
-   time.
-
- o Fsyscall-handlers must be careful not to leak sensitive kernel'
-   information back to user-level.  In particular, before returning to
-   user-level, care needs to be taken to clear any scratch registers
-   that could contain sensitive information (note that the current
-   task pointer is not considered sensitive: it's already exposed
-   through ar.k6).
-
- o Fsyscall-handlers MUST NOT access user-memory without first
-   validating access-permission (this can be done typically via
-   probe.r.fault and/or probe.w.fault) and without guarding against
-   memory access exceptions (this can be done with the EX() macros
-   defined by asmmacro.h).
-
-The above restrictions may seem draconian, but remember that it's
-possible to trade off some of the restrictions by paying a slightly
-higher overhead.  For example, if an fsyscall-handler could benefit
-from the shadow register bank, it could temporarily disable PSR.i and
-PSR.ic, switch to bank 0 (bsw.0) and then use the shadow registers as
-needed.  In other words, following the above rules yields extremely
-fast system call execution (while fully preserving system call
-semantics), but there is also a lot of flexibility in handling more
-complicated cases.
-
-* Signal handling
-
-The delivery of (asynchronous) signals must be delayed until fsys-mode
-is exited.  This is accomplished with the help of the lower-privilege
-transfer trap: arch/ia64/kernel/process.c:do_notify_resume_user()
-checks whether the interrupted task was in fsys-mode and, if so, sets
-PSR.lp and returns immediately.  When fsys-mode is exited via the
-"br.ret" instruction that lowers the privilege level, a trap will
-occur.  The trap handler clears PSR.lp again and returns immediately.
-The kernel exit path then checks for and delivers any pending signals.
-
-* PSR Handling
-
-The "epc" instruction doesn't change the contents of PSR at all.  This
-is in contrast to a regular interruption, which clears almost all
-bits.  Because of that, some care needs to be taken to ensure things
-work as expected.  The following discussion describes how each PSR bit
-is handled.
-
-PSR.be Cleared when entering fsys-mode.  A srlz.d instruction is used
-       to ensure the CPU is in little-endian mode before the first
-       load/store instruction is executed.  PSR.be is normally NOT
-       restored upon return from an fsys-mode handler.  In other
-       words, user-level code must not rely on PSR.be being preserved
-       across a system call.
-PSR.up Unchanged.
-PSR.ac Unchanged.
-PSR.mfl Unchanged.  Note: fsys-mode handlers must not write-registers!
-PSR.mfh        Unchanged.  Note: fsys-mode handlers must not write-registers!
-PSR.ic Unchanged.  Note: fsys-mode handlers can clear the bit, if needed.
-PSR.i  Unchanged.  Note: fsys-mode handlers can clear the bit, if needed.
-PSR.pk Unchanged.
-PSR.dt Unchanged.
-PSR.dfl        Unchanged.  Note: fsys-mode handlers must not write-registers!
-PSR.dfh        Unchanged.  Note: fsys-mode handlers must not write-registers!
-PSR.sp Unchanged.
-PSR.pp Unchanged.
-PSR.di Unchanged.
-PSR.si Unchanged.
-PSR.db Unchanged.  The kernel prevents user-level from setting a hardware
-       breakpoint that triggers at any privilege level other than 3 (user-mode).
-PSR.lp Unchanged.
-PSR.tb Lazy redirect.  If a taken-branch trap occurs while in
-       fsys-mode, the trap-handler modifies the saved machine state
-       such that execution resumes in the gate page at
-       syscall_via_break(), with privilege level 3.  Note: the
-       taken branch would occur on the branch invoking the
-       fsyscall-handler, at which point, by definition, a syscall
-       restart is still safe.  If the system call number is invalid,
-       the fsys-mode handler will return directly to user-level.  This
-       return will trigger a taken-branch trap, but since the trap is
-       taken _after_ restoring the privilege level, the CPU has already
-       left fsys-mode, so no special treatment is needed.
-PSR.rt Unchanged.
-PSR.cpl        Cleared to 0.
-PSR.is Unchanged (guaranteed to be 0 on entry to the gate page).
-PSR.mc Unchanged.
-PSR.it Unchanged (guaranteed to be 1).
-PSR.id Unchanged.  Note: the ia64 linux kernel never sets this bit.
-PSR.da Unchanged.  Note: the ia64 linux kernel never sets this bit.
-PSR.dd Unchanged.  Note: the ia64 linux kernel never sets this bit.
-PSR.ss Lazy redirect.  If set, "epc" will cause a Single Step Trap to
-       be taken.  The trap handler then modifies the saved machine
-       state such that execution resumes in the gate page at
-       syscall_via_break(), with privilege level 3.
-PSR.ri Unchanged.
-PSR.ed Unchanged.  Note: This bit could only have an effect if an fsys-mode
-       handler performed a speculative load that gets NaTted.  If so, this
-       would be the normal & expected behavior, so no special treatment is
-       needed.
-PSR.bn Unchanged.  Note: fsys-mode handlers may clear the bit, if needed.
-       Doing so requires clearing PSR.i and PSR.ic as well.
-PSR.ia Unchanged.  Note: the ia64 linux kernel never sets this bit.
-
-* Using fast system calls
-
-To use fast system calls, userspace applications need simply call
-__kernel_syscall_via_epc().  For example
-
--- example fgettimeofday() call --
--- fgettimeofday.S --
-
-#include <asm/asmmacro.h>
-
-GLOBAL_ENTRY(fgettimeofday)
-.prologue
-.save ar.pfs, r11
-mov r11 = ar.pfs
-.body 
-
-mov r2 = 0xa000000000020660;;  // gate address 
-                              // found by inspection of System.map for the 
-                              // __kernel_syscall_via_epc() function.  See
-                              // below for how to do this for real.
-
-mov b7 = r2
-mov r15 = 1087                // gettimeofday syscall
-;;
-br.call.sptk.many b6 = b7
-;;
-
-.restore sp
-
-mov ar.pfs = r11
-br.ret.sptk.many rp;;        // return to caller
-END(fgettimeofday)
-
--- end fgettimeofday.S --
-
-In reality, getting the gate address is accomplished by two extra
-values passed via the ELF auxiliary vector (include/asm-ia64/elf.h)
-
- o AT_SYSINFO : is the address of __kernel_syscall_via_epc()
- o AT_SYSINFO_EHDR : is the address of the kernel gate ELF DSO
-
-The ELF DSO is a pre-linked library that is mapped in by the kernel at
-the gate page.  It is a proper ELF shared object so, with a dynamic
-loader that recognises the library, you should be able to make calls to
-the exported functions within it as with any other shared library.
-AT_SYSINFO points into the kernel DSO at the
-__kernel_syscall_via_epc() function for historical reasons (it was
-used before the kernel DSO) and as a convenience.
diff --git a/Documentation/ia64/ia64.rst b/Documentation/ia64/ia64.rst
new file mode 100644 (file)
index 0000000..b725019
--- /dev/null
@@ -0,0 +1,49 @@
+===========================================
+Linux kernel release for the IA-64 Platform
+===========================================
+
+   These are the release notes for Linux since version 2.4 for IA-64
+   platform.  This document provides information specific to IA-64
+   ONLY, to get additional information about the Linux kernel also
+   read the original Linux README provided with the kernel.
+
+Installing the Kernel
+=====================
+
+ - IA-64 kernel installation is the same as the other platforms, see
+   original README for details.
+
+
+Software Requirements
+=====================
+
+   Compiling and running this kernel requires an IA-64 compliant GCC
+   compiler.  And various software packages also compiled with an
+   IA-64 compliant GCC compiler.
+
+
+Configuring the Kernel
+======================
+
+   Configuration is the same, see original README for details.
+
+
+Compiling the Kernel:
+
+ - Compiling this kernel doesn't differ from other platform so read
+   the original README for details BUT make sure you have an IA-64
+   compliant GCC compiler.
+
+IA-64 Specifics
+===============
+
+ - General issues:
+
+    * Hardly any performance tuning has been done. Obvious targets
+      include the library routines (IP checksum, etc.). Less
+      obvious targets include making sure we don't flush the TLB
+      needlessly, etc.
+
+    * SMP locks cleanup/optimization
+
+    * IA32 support.  Currently experimental.  It mostly works.
diff --git a/Documentation/ia64/index.rst b/Documentation/ia64/index.rst
new file mode 100644 (file)
index 0000000..0436e10
--- /dev/null
@@ -0,0 +1,18 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==================
+IA-64 Architecture
+==================
+
+.. toctree::
+   :maxdepth: 1
+
+   ia64
+   aliasing
+   efirtc
+   err_inject
+   fsys
+   irq-redir
+   mca
+   serial
+   xen
diff --git a/Documentation/ia64/irq-redir.rst b/Documentation/ia64/irq-redir.rst
new file mode 100644 (file)
index 0000000..39bf944
--- /dev/null
@@ -0,0 +1,80 @@
+==============================
+IRQ affinity on IA64 platforms
+==============================
+
+07.01.2002, Erich Focht <efocht@ess.nec.de>
+
+
+By writing to /proc/irq/IRQ#/smp_affinity the interrupt routing can be
+controlled. The behavior on IA64 platforms is slightly different from
+that described in Documentation/IRQ-affinity.txt for i386 systems.
+
+Because of the usage of SAPIC mode and physical destination mode the
+IRQ target is one particular CPU and cannot be a mask of several
+CPUs. Only the first non-zero bit is taken into account.
+
+
+Usage examples
+==============
+
+The target CPU has to be specified as a hexadecimal CPU mask. The
+first non-zero bit is the selected CPU. This format has been kept for
+compatibility reasons with i386.
+
+Set the delivery mode of interrupt 41 to fixed and route the
+interrupts to CPU #3 (logical CPU number) (2^3=0x08)::
+
+     echo "8" >/proc/irq/41/smp_affinity
+
+Set the default route for IRQ number 41 to CPU 6 in lowest priority
+delivery mode (redirectable)::
+
+     echo "r 40" >/proc/irq/41/smp_affinity
+
+The output of the command::
+
+     cat /proc/irq/IRQ#/smp_affinity
+
+gives the target CPU mask for the specified interrupt vector. If the CPU
+mask is preceded by the character "r", the interrupt is redirectable
+(i.e. lowest priority mode routing is used), otherwise its route is
+fixed.
+
+
+
+Initialization and default behavior
+===================================
+
+If the platform features IRQ redirection (info provided by SAL) all
+IO-SAPIC interrupts are initialized with CPU#0 as their default target
+and the routing is the so called "lowest priority mode" (actually
+fixed SAPIC mode with hint). The XTP chipset registers are used as hints
+for the IRQ routing. Currently in Linux XTP registers can have three
+values:
+
+       - minimal for an idle task,
+       - normal if any other task runs,
+       - maximal if the CPU is going to be switched off.
+
+The IRQ is routed to the CPU with lowest XTP register value, the
+search begins at the default CPU. Therefore most of the interrupts
+will be handled by CPU #0.
+
+If the platform doesn't feature interrupt redirection IOSAPIC fixed
+routing is used. The target CPUs are distributed in a round robin
+manner. IRQs will be routed only to the selected target CPUs. Check
+with::
+
+        cat /proc/interrupts
+
+
+
+Comments
+========
+
+On large (multi-node) systems it is recommended to route the IRQs to
+the node to which the corresponding device is connected.
+For systems like the NEC AzusA we get IRQ node-affinity for free. This
+is because usually the chipsets on each node redirect the interrupts
+only to their own CPUs (as they cannot see the XTP registers on the
+other nodes).
diff --git a/Documentation/ia64/mca.rst b/Documentation/ia64/mca.rst
new file mode 100644 (file)
index 0000000..08270bb
--- /dev/null
@@ -0,0 +1,198 @@
+=============================================================
+An ad-hoc collection of notes on IA64 MCA and INIT processing
+=============================================================
+
+Feel free to update it with notes about any area that is not clear.
+
+---
+
+MCA/INIT are completely asynchronous.  They can occur at any time, when
+the OS is in any state.  Including when one of the cpus is already
+holding a spinlock.  Trying to get any lock from MCA/INIT state is
+asking for deadlock.  Also the state of structures that are protected
+by locks is indeterminate, including linked lists.
+
+---
+
+The complicated ia64 MCA process.  All of this is mandated by Intel's
+specification for ia64 SAL, error recovery and unwind, it is not as
+if we have a choice here.
+
+* MCA occurs on one cpu, usually due to a double bit memory error.
+  This is the monarch cpu.
+
+* SAL sends an MCA rendezvous interrupt (which is a normal interrupt)
+  to all the other cpus, the slaves.
+
+* Slave cpus that receive the MCA interrupt call down into SAL, they
+  end up spinning disabled while the MCA is being serviced.
+
+* If any slave cpu was already spinning disabled when the MCA occurred
+  then it cannot service the MCA interrupt.  SAL waits ~20 seconds then
+  sends an unmaskable INIT event to the slave cpus that have not
+  already rendezvoused.
+
+* Because MCA/INIT can be delivered at any time, including when the cpu
+  is down in PAL in physical mode, the registers at the time of the
+  event are _completely_ undefined.  In particular the MCA/INIT
+  handlers cannot rely on the thread pointer, PAL physical mode can
+  (and does) modify TP.  It is allowed to do that as long as it resets
+  TP on return.  However MCA/INIT events expose us to these PAL
+  internal TP changes.  Hence curr_task().
+
+* If an MCA/INIT event occurs while the kernel was running (not user
+  space) and the kernel has called PAL then the MCA/INIT handler cannot
+  assume that the kernel stack is in a fit state to be used.  Mainly
+  because PAL may or may not maintain the stack pointer internally.
+  Because the MCA/INIT handlers cannot trust the kernel stack, they
+  have to use their own, per-cpu stacks.  The MCA/INIT stacks are
+  preformatted with just enough task state to let the relevant handlers
+  do their job.
+
+* Unlike most other architectures, the ia64 struct task is embedded in
+  the kernel stack[1].  So switching to a new kernel stack means that
+  we switch to a new task as well.  Because various bits of the kernel
+  assume that current points into the struct task, switching to a new
+  stack also means a new value for current.
+
+* Once all slaves have rendezvoused and are spinning disabled, the
+  monarch is entered.  The monarch now tries to diagnose the problem
+  and decide if it can recover or not.
+
+* Part of the monarch's job is to look at the state of all the other
+  tasks.  The only way to do that on ia64 is to call the unwinder,
+  as mandated by Intel.
+
+* The starting point for the unwind depends on whether a task is
+  running or not.  That is, whether it is on a cpu or is blocked.  The
+  monarch has to determine whether or not a task is on a cpu before it
+  knows how to start unwinding it.  The tasks that received an MCA or
+  INIT event are no longer running, they have been converted to blocked
+  tasks.  But (and its a big but), the cpus that received the MCA
+  rendezvous interrupt are still running on their normal kernel stacks!
+
+* To distinguish between these two cases, the monarch must know which
+  tasks are on a cpu and which are not.  Hence each slave cpu that
+  switches to an MCA/INIT stack, registers its new stack using
+  set_curr_task(), so the monarch can tell that the _original_ task is
+  no longer running on that cpu.  That gives us a decent chance of
+  getting a valid backtrace of the _original_ task.
+
+* MCA/INIT can be nested, to a depth of 2 on any cpu.  In the case of a
+  nested error, we want diagnostics on the MCA/INIT handler that
+  failed, not on the task that was originally running.  Again this
+  requires set_curr_task() so the MCA/INIT handlers can register their
+  own stack as running on that cpu.  Then a recursive error gets a
+  trace of the failing handler's "task".
+
+[1]
+    My (Keith Owens) original design called for ia64 to separate its
+    struct task and the kernel stacks.  Then the MCA/INIT data would be
+    chained stacks like i386 interrupt stacks.  But that required
+    radical surgery on the rest of ia64, plus extra hard wired TLB
+    entries with its associated performance degradation.  David
+    Mosberger vetoed that approach.  Which meant that separate kernel
+    stacks meant separate "tasks" for the MCA/INIT handlers.
+
+---
+
+INIT is less complicated than MCA.  Pressing the nmi button or using
+the equivalent command on the management console sends INIT to all
+cpus.  SAL picks one of the cpus as the monarch and the rest are
+slaves.  All the OS INIT handlers are entered at approximately the same
+time.  The OS monarch prints the state of all tasks and returns, after
+which the slaves return and the system resumes.
+
+At least that is what is supposed to happen.  Alas there are broken
+versions of SAL out there.  Some drive all the cpus as monarchs.  Some
+drive them all as slaves.  Some drive one cpu as monarch, wait for that
+cpu to return from the OS then drive the rest as slaves.  Some versions
+of SAL cannot even cope with returning from the OS, they spin inside
+SAL on resume.  The OS INIT code has workarounds for some of these
+broken SAL symptoms, but some simply cannot be fixed from the OS side.
+
+---
+
+The scheduler hooks used by ia64 (curr_task, set_curr_task) are layer
+violations.  Unfortunately MCA/INIT start off as massive layer
+violations (can occur at _any_ time) and they build from there.
+
+At least ia64 makes an attempt at recovering from hardware errors, but
+it is a difficult problem because of the asynchronous nature of these
+errors.  When processing an unmaskable interrupt we sometimes need
+special code to cope with our inability to take any locks.
+
+---
+
+How is ia64 MCA/INIT different from x86 NMI?
+
+* x86 NMI typically gets delivered to one cpu.  MCA/INIT gets sent to
+  all cpus.
+
+* x86 NMI cannot be nested.  MCA/INIT can be nested, to a depth of 2
+  per cpu.
+
+* x86 has a separate struct task which points to one of multiple kernel
+  stacks.  ia64 has the struct task embedded in the single kernel
+  stack, so switching stack means switching task.
+
+* x86 does not call the BIOS so the NMI handler does not have to worry
+  about any registers having changed.  MCA/INIT can occur while the cpu
+  is in PAL in physical mode, with undefined registers and an undefined
+  kernel stack.
+
+* i386 backtrace is not very sensitive to whether a process is running
+  or not.  ia64 unwind is very, very sensitive to whether a process is
+  running or not.
+
+---
+
+What happens when MCA/INIT is delivered what a cpu is running user
+space code?
+
+The user mode registers are stored in the RSE area of the MCA/INIT on
+entry to the OS and are restored from there on return to SAL, so user
+mode registers are preserved across a recoverable MCA/INIT.  Since the
+OS has no idea what unwind data is available for the user space stack,
+MCA/INIT never tries to backtrace user space.  Which means that the OS
+does not bother making the user space process look like a blocked task,
+i.e. the OS does not copy pt_regs and switch_stack to the user space
+stack.  Also the OS has no idea how big the user space RSE and memory
+stacks are, which makes it too risky to copy the saved state to a user
+mode stack.
+
+---
+
+How do we get a backtrace on the tasks that were running when MCA/INIT
+was delivered?
+
+mca.c:::ia64_mca_modify_original_stack().  That identifies and
+verifies the original kernel stack, copies the dirty registers from
+the MCA/INIT stack's RSE to the original stack's RSE, copies the
+skeleton struct pt_regs and switch_stack to the original stack, fills
+in the skeleton structures from the PAL minstate area and updates the
+original stack's thread.ksp.  That makes the original stack look
+exactly like any other blocked task, i.e. it now appears to be
+sleeping.  To get a backtrace, just start with thread.ksp for the
+original task and unwind like any other sleeping task.
+
+---
+
+How do we identify the tasks that were running when MCA/INIT was
+delivered?
+
+If the previous task has been verified and converted to a blocked
+state, then sos->prev_task on the MCA/INIT stack is updated to point to
+the previous task.  You can look at that field in dumps or debuggers.
+To help distinguish between the handler and the original tasks,
+handlers have _TIF_MCA_INIT set in thread_info.flags.
+
+The sos data is always in the MCA/INIT handler stack, at offset
+MCA_SOS_OFFSET.  You can get that value from mca_asm.h or calculate it
+as KERNEL_STACK_SIZE - sizeof(struct pt_regs) - sizeof(struct
+ia64_sal_os_state), with 16 byte alignment for all structures.
+
+Also the comm field of the MCA/INIT task is modified to include the pid
+of the original task, for humans to use.  For example, a comm field of
+'MCA 12159' means that pid 12159 was running when the MCA was
+delivered.
diff --git a/Documentation/ia64/mca.txt b/Documentation/ia64/mca.txt
deleted file mode 100644 (file)
index f097c60..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-An ad-hoc collection of notes on IA64 MCA and INIT processing.  Feel
-free to update it with notes about any area that is not clear.
-
----
-
-MCA/INIT are completely asynchronous.  They can occur at any time, when
-the OS is in any state.  Including when one of the cpus is already
-holding a spinlock.  Trying to get any lock from MCA/INIT state is
-asking for deadlock.  Also the state of structures that are protected
-by locks is indeterminate, including linked lists.
-
----
-
-The complicated ia64 MCA process.  All of this is mandated by Intel's
-specification for ia64 SAL, error recovery and unwind, it is not as
-if we have a choice here.
-
-* MCA occurs on one cpu, usually due to a double bit memory error.
-  This is the monarch cpu.
-
-* SAL sends an MCA rendezvous interrupt (which is a normal interrupt)
-  to all the other cpus, the slaves.
-
-* Slave cpus that receive the MCA interrupt call down into SAL, they
-  end up spinning disabled while the MCA is being serviced.
-
-* If any slave cpu was already spinning disabled when the MCA occurred
-  then it cannot service the MCA interrupt.  SAL waits ~20 seconds then
-  sends an unmaskable INIT event to the slave cpus that have not
-  already rendezvoused.
-
-* Because MCA/INIT can be delivered at any time, including when the cpu
-  is down in PAL in physical mode, the registers at the time of the
-  event are _completely_ undefined.  In particular the MCA/INIT
-  handlers cannot rely on the thread pointer, PAL physical mode can
-  (and does) modify TP.  It is allowed to do that as long as it resets
-  TP on return.  However MCA/INIT events expose us to these PAL
-  internal TP changes.  Hence curr_task().
-
-* If an MCA/INIT event occurs while the kernel was running (not user
-  space) and the kernel has called PAL then the MCA/INIT handler cannot
-  assume that the kernel stack is in a fit state to be used.  Mainly
-  because PAL may or may not maintain the stack pointer internally.
-  Because the MCA/INIT handlers cannot trust the kernel stack, they
-  have to use their own, per-cpu stacks.  The MCA/INIT stacks are
-  preformatted with just enough task state to let the relevant handlers
-  do their job.
-
-* Unlike most other architectures, the ia64 struct task is embedded in
-  the kernel stack[1].  So switching to a new kernel stack means that
-  we switch to a new task as well.  Because various bits of the kernel
-  assume that current points into the struct task, switching to a new
-  stack also means a new value for current.
-
-* Once all slaves have rendezvoused and are spinning disabled, the
-  monarch is entered.  The monarch now tries to diagnose the problem
-  and decide if it can recover or not.
-
-* Part of the monarch's job is to look at the state of all the other
-  tasks.  The only way to do that on ia64 is to call the unwinder,
-  as mandated by Intel.
-
-* The starting point for the unwind depends on whether a task is
-  running or not.  That is, whether it is on a cpu or is blocked.  The
-  monarch has to determine whether or not a task is on a cpu before it
-  knows how to start unwinding it.  The tasks that received an MCA or
-  INIT event are no longer running, they have been converted to blocked
-  tasks.  But (and its a big but), the cpus that received the MCA
-  rendezvous interrupt are still running on their normal kernel stacks!
-
-* To distinguish between these two cases, the monarch must know which
-  tasks are on a cpu and which are not.  Hence each slave cpu that
-  switches to an MCA/INIT stack, registers its new stack using
-  set_curr_task(), so the monarch can tell that the _original_ task is
-  no longer running on that cpu.  That gives us a decent chance of
-  getting a valid backtrace of the _original_ task.
-
-* MCA/INIT can be nested, to a depth of 2 on any cpu.  In the case of a
-  nested error, we want diagnostics on the MCA/INIT handler that
-  failed, not on the task that was originally running.  Again this
-  requires set_curr_task() so the MCA/INIT handlers can register their
-  own stack as running on that cpu.  Then a recursive error gets a
-  trace of the failing handler's "task".
-
-[1] My (Keith Owens) original design called for ia64 to separate its
-    struct task and the kernel stacks.  Then the MCA/INIT data would be
-    chained stacks like i386 interrupt stacks.  But that required
-    radical surgery on the rest of ia64, plus extra hard wired TLB
-    entries with its associated performance degradation.  David
-    Mosberger vetoed that approach.  Which meant that separate kernel
-    stacks meant separate "tasks" for the MCA/INIT handlers.
-
----
-
-INIT is less complicated than MCA.  Pressing the nmi button or using
-the equivalent command on the management console sends INIT to all
-cpus.  SAL picks one of the cpus as the monarch and the rest are
-slaves.  All the OS INIT handlers are entered at approximately the same
-time.  The OS monarch prints the state of all tasks and returns, after
-which the slaves return and the system resumes.
-
-At least that is what is supposed to happen.  Alas there are broken
-versions of SAL out there.  Some drive all the cpus as monarchs.  Some
-drive them all as slaves.  Some drive one cpu as monarch, wait for that
-cpu to return from the OS then drive the rest as slaves.  Some versions
-of SAL cannot even cope with returning from the OS, they spin inside
-SAL on resume.  The OS INIT code has workarounds for some of these
-broken SAL symptoms, but some simply cannot be fixed from the OS side.
-
----
-
-The scheduler hooks used by ia64 (curr_task, set_curr_task) are layer
-violations.  Unfortunately MCA/INIT start off as massive layer
-violations (can occur at _any_ time) and they build from there.
-
-At least ia64 makes an attempt at recovering from hardware errors, but
-it is a difficult problem because of the asynchronous nature of these
-errors.  When processing an unmaskable interrupt we sometimes need
-special code to cope with our inability to take any locks.
-
----
-
-How is ia64 MCA/INIT different from x86 NMI?
-
-* x86 NMI typically gets delivered to one cpu.  MCA/INIT gets sent to
-  all cpus.
-
-* x86 NMI cannot be nested.  MCA/INIT can be nested, to a depth of 2
-  per cpu.
-
-* x86 has a separate struct task which points to one of multiple kernel
-  stacks.  ia64 has the struct task embedded in the single kernel
-  stack, so switching stack means switching task.
-
-* x86 does not call the BIOS so the NMI handler does not have to worry
-  about any registers having changed.  MCA/INIT can occur while the cpu
-  is in PAL in physical mode, with undefined registers and an undefined
-  kernel stack.
-
-* i386 backtrace is not very sensitive to whether a process is running
-  or not.  ia64 unwind is very, very sensitive to whether a process is
-  running or not.
-
----
-
-What happens when MCA/INIT is delivered what a cpu is running user
-space code?
-
-The user mode registers are stored in the RSE area of the MCA/INIT on
-entry to the OS and are restored from there on return to SAL, so user
-mode registers are preserved across a recoverable MCA/INIT.  Since the
-OS has no idea what unwind data is available for the user space stack,
-MCA/INIT never tries to backtrace user space.  Which means that the OS
-does not bother making the user space process look like a blocked task,
-i.e. the OS does not copy pt_regs and switch_stack to the user space
-stack.  Also the OS has no idea how big the user space RSE and memory
-stacks are, which makes it too risky to copy the saved state to a user
-mode stack.
-
----
-
-How do we get a backtrace on the tasks that were running when MCA/INIT
-was delivered?
-
-mca.c:::ia64_mca_modify_original_stack().  That identifies and
-verifies the original kernel stack, copies the dirty registers from
-the MCA/INIT stack's RSE to the original stack's RSE, copies the
-skeleton struct pt_regs and switch_stack to the original stack, fills
-in the skeleton structures from the PAL minstate area and updates the
-original stack's thread.ksp.  That makes the original stack look
-exactly like any other blocked task, i.e. it now appears to be
-sleeping.  To get a backtrace, just start with thread.ksp for the
-original task and unwind like any other sleeping task.
-
----
-
-How do we identify the tasks that were running when MCA/INIT was
-delivered?
-
-If the previous task has been verified and converted to a blocked
-state, then sos->prev_task on the MCA/INIT stack is updated to point to
-the previous task.  You can look at that field in dumps or debuggers.
-To help distinguish between the handler and the original tasks,
-handlers have _TIF_MCA_INIT set in thread_info.flags.
-
-The sos data is always in the MCA/INIT handler stack, at offset
-MCA_SOS_OFFSET.  You can get that value from mca_asm.h or calculate it
-as KERNEL_STACK_SIZE - sizeof(struct pt_regs) - sizeof(struct
-ia64_sal_os_state), with 16 byte alignment for all structures.
-
-Also the comm field of the MCA/INIT task is modified to include the pid
-of the original task, for humans to use.  For example, a comm field of
-'MCA 12159' means that pid 12159 was running when the MCA was
-delivered.
diff --git a/Documentation/ia64/serial.rst b/Documentation/ia64/serial.rst
new file mode 100644 (file)
index 0000000..1de70c3
--- /dev/null
@@ -0,0 +1,165 @@
+==============
+Serial Devices
+==============
+
+Serial Device Naming
+====================
+
+    As of 2.6.10, serial devices on ia64 are named based on the
+    order of ACPI and PCI enumeration.  The first device in the
+    ACPI namespace (if any) becomes /dev/ttyS0, the second becomes
+    /dev/ttyS1, etc., and PCI devices are named sequentially
+    starting after the ACPI devices.
+
+    Prior to 2.6.10, there were confusing exceptions to this:
+
+       - Firmware on some machines (mostly from HP) provides an HCDP
+         table[1] that tells the kernel about devices that can be used
+         as a serial console.  If the user specified "console=ttyS0"
+         or the EFI ConOut path contained only UART devices, the
+         kernel registered the device described by the HCDP as
+         /dev/ttyS0.
+
+       - If there was no HCDP, we assumed there were UARTs at the
+         legacy COM port addresses (I/O ports 0x3f8 and 0x2f8), so
+         the kernel registered those as /dev/ttyS0 and /dev/ttyS1.
+
+    Any additional ACPI or PCI devices were registered sequentially
+    after /dev/ttyS0 as they were discovered.
+
+    With an HCDP, device names changed depending on EFI configuration
+    and "console=" arguments.  Without an HCDP, device names didn't
+    change, but we registered devices that might not really exist.
+
+    For example, an HP rx1600 with a single built-in serial port
+    (described in the ACPI namespace) plus an MP[2] (a PCI device) has
+    these ports:
+
+      ==========  ==========     ============    ============   =======
+      Type        MMIO           pre-2.6.10      pre-2.6.10     2.6.10+
+                 address
+                                (EFI console    (EFI console
+                                 on builtin)     on MP port)
+      ==========  ==========     ============    ============   =======
+      builtin     0xff5e0000        ttyS0           ttyS1         ttyS0
+      MP UPS      0xf8031000        ttyS1           ttyS2         ttyS1
+      MP Console  0xf8030000        ttyS2           ttyS0         ttyS2
+      MP 2        0xf8030010        ttyS3           ttyS3         ttyS3
+      MP 3        0xf8030038        ttyS4           ttyS4         ttyS4
+      ==========  ==========     ============    ============   =======
+
+Console Selection
+=================
+
+    EFI knows what your console devices are, but it doesn't tell the
+    kernel quite enough to actually locate them.  The DIG64 HCDP
+    table[1] does tell the kernel where potential serial console
+    devices are, but not all firmware supplies it.  Also, EFI supports
+    multiple simultaneous consoles and doesn't tell the kernel which
+    should be the "primary" one.
+
+    So how do you tell Linux which console device to use?
+
+       - If your firmware supplies the HCDP, it is simplest to
+         configure EFI with a single device (either a UART or a VGA
+         card) as the console.  Then you don't need to tell Linux
+         anything; the kernel will automatically use the EFI console.
+
+         (This works only in 2.6.6 or later; prior to that you had
+         to specify "console=ttyS0" to get a serial console.)
+
+       - Without an HCDP, Linux defaults to a VGA console unless you
+         specify a "console=" argument.
+
+    NOTE: Don't assume that a serial console device will be /dev/ttyS0.
+    It might be ttyS1, ttyS2, etc.  Make sure you have the appropriate
+    entries in /etc/inittab (for getty) and /etc/securetty (to allow
+    root login).
+
+Early Serial Console
+====================
+
+    The kernel can't start using a serial console until it knows where
+    the device lives.  Normally this happens when the driver enumerates
+    all the serial devices, which can happen a minute or more after the
+    kernel starts booting.
+
+    2.6.10 and later kernels have an "early uart" driver that works
+    very early in the boot process.  The kernel will automatically use
+    this if the user supplies an argument like "console=uart,io,0x3f8",
+    or if the EFI console path contains only a UART device and the
+    firmware supplies an HCDP.
+
+Troubleshooting Serial Console Problems
+=======================================
+
+    No kernel output after elilo prints "Uncompressing Linux... done":
+
+       - You specified "console=ttyS0" but Linux changed the device
+         to which ttyS0 refers.  Configure exactly one EFI console
+         device[3] and remove the "console=" option.
+
+       - The EFI console path contains both a VGA device and a UART.
+         EFI and elilo use both, but Linux defaults to VGA.  Remove
+         the VGA device from the EFI console path[3].
+
+       - Multiple UARTs selected as EFI console devices.  EFI and
+         elilo use all selected devices, but Linux uses only one.
+         Make sure only one UART is selected in the EFI console
+         path[3].
+
+       - You're connected to an HP MP port[2] but have a non-MP UART
+         selected as EFI console device.  EFI uses the MP as a
+         console device even when it isn't explicitly selected.
+         Either move the console cable to the non-MP UART, or change
+         the EFI console path[3] to the MP UART.
+
+    Long pause (60+ seconds) between "Uncompressing Linux... done" and
+    start of kernel output:
+
+       - No early console because you used "console=ttyS<n>".  Remove
+         the "console=" option if your firmware supplies an HCDP.
+
+       - If you don't have an HCDP, the kernel doesn't know where
+         your console lives until the driver discovers serial
+         devices.  Use "console=uart,io,0x3f8" (or appropriate
+         address for your machine).
+
+    Kernel and init script output works fine, but no "login:" prompt:
+
+       - Add getty entry to /etc/inittab for console tty.  Look for
+         the "Adding console on ttyS<n>" message that tells you which
+         device is the console.
+
+    "login:" prompt, but can't login as root:
+
+       - Add entry to /etc/securetty for console tty.
+
+    No ACPI serial devices found in 2.6.17 or later:
+
+       - Turn on CONFIG_PNP and CONFIG_PNPACPI.  Prior to 2.6.17, ACPI
+         serial devices were discovered by 8250_acpi.  In 2.6.17,
+         8250_acpi was replaced by the combination of 8250_pnp and
+         CONFIG_PNPACPI.
+
+
+
+[1]
+    http://www.dig64.org/specifications/agreement
+    The table was originally defined as the "HCDP" for "Headless
+    Console/Debug Port."  The current version is the "PCDP" for
+    "Primary Console and Debug Port Devices."
+
+[2]
+    The HP MP (management processor) is a PCI device that provides
+    several UARTs.  One of the UARTs is often used as a console; the
+    EFI Boot Manager identifies it as "Acpi(HWP0002,700)/Pci(...)/Uart".
+    The external connection is usually a 25-pin connector, and a
+    special dongle converts that to three 9-pin connectors, one of
+    which is labelled "Console."
+
+[3]
+    EFI console devices are configured using the EFI Boot Manager
+    "Boot option maintenance" menu.  You may have to interrupt the
+    boot sequence to use this menu, and you will have to reset the
+    box after changing console configuration.
diff --git a/Documentation/ia64/serial.txt b/Documentation/ia64/serial.txt
deleted file mode 100644 (file)
index a63d2c5..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-SERIAL DEVICE NAMING
-
-    As of 2.6.10, serial devices on ia64 are named based on the
-    order of ACPI and PCI enumeration.  The first device in the
-    ACPI namespace (if any) becomes /dev/ttyS0, the second becomes
-    /dev/ttyS1, etc., and PCI devices are named sequentially
-    starting after the ACPI devices.
-
-    Prior to 2.6.10, there were confusing exceptions to this:
-
-       - Firmware on some machines (mostly from HP) provides an HCDP
-         table[1] that tells the kernel about devices that can be used
-         as a serial console.  If the user specified "console=ttyS0"
-         or the EFI ConOut path contained only UART devices, the
-         kernel registered the device described by the HCDP as
-         /dev/ttyS0.
-
-       - If there was no HCDP, we assumed there were UARTs at the
-         legacy COM port addresses (I/O ports 0x3f8 and 0x2f8), so
-         the kernel registered those as /dev/ttyS0 and /dev/ttyS1.
-
-    Any additional ACPI or PCI devices were registered sequentially
-    after /dev/ttyS0 as they were discovered.
-
-    With an HCDP, device names changed depending on EFI configuration
-    and "console=" arguments.  Without an HCDP, device names didn't
-    change, but we registered devices that might not really exist.
-
-    For example, an HP rx1600 with a single built-in serial port
-    (described in the ACPI namespace) plus an MP[2] (a PCI device) has
-    these ports:
-
-                                  pre-2.6.10      pre-2.6.10
-                    MMIO         (EFI console    (EFI console
-                   address        on builtin)     on MP port)    2.6.10
-                  ==========      ==========      ==========     ======
-      builtin     0xff5e0000        ttyS0           ttyS1         ttyS0
-      MP UPS      0xf8031000        ttyS1           ttyS2         ttyS1
-      MP Console  0xf8030000        ttyS2           ttyS0         ttyS2
-      MP 2        0xf8030010        ttyS3           ttyS3         ttyS3
-      MP 3        0xf8030038        ttyS4           ttyS4         ttyS4
-
-CONSOLE SELECTION
-
-    EFI knows what your console devices are, but it doesn't tell the
-    kernel quite enough to actually locate them.  The DIG64 HCDP
-    table[1] does tell the kernel where potential serial console
-    devices are, but not all firmware supplies it.  Also, EFI supports
-    multiple simultaneous consoles and doesn't tell the kernel which
-    should be the "primary" one.
-
-    So how do you tell Linux which console device to use?
-
-       - If your firmware supplies the HCDP, it is simplest to
-         configure EFI with a single device (either a UART or a VGA
-         card) as the console.  Then you don't need to tell Linux
-         anything; the kernel will automatically use the EFI console.
-
-         (This works only in 2.6.6 or later; prior to that you had
-         to specify "console=ttyS0" to get a serial console.)
-
-       - Without an HCDP, Linux defaults to a VGA console unless you
-         specify a "console=" argument.
-
-    NOTE: Don't assume that a serial console device will be /dev/ttyS0.
-    It might be ttyS1, ttyS2, etc.  Make sure you have the appropriate
-    entries in /etc/inittab (for getty) and /etc/securetty (to allow
-    root login).
-
-EARLY SERIAL CONSOLE
-
-    The kernel can't start using a serial console until it knows where
-    the device lives.  Normally this happens when the driver enumerates
-    all the serial devices, which can happen a minute or more after the
-    kernel starts booting.
-
-    2.6.10 and later kernels have an "early uart" driver that works
-    very early in the boot process.  The kernel will automatically use
-    this if the user supplies an argument like "console=uart,io,0x3f8",
-    or if the EFI console path contains only a UART device and the
-    firmware supplies an HCDP.
-
-TROUBLESHOOTING SERIAL CONSOLE PROBLEMS
-
-    No kernel output after elilo prints "Uncompressing Linux... done":
-
-       - You specified "console=ttyS0" but Linux changed the device
-         to which ttyS0 refers.  Configure exactly one EFI console
-         device[3] and remove the "console=" option.
-
-       - The EFI console path contains both a VGA device and a UART.
-         EFI and elilo use both, but Linux defaults to VGA.  Remove
-         the VGA device from the EFI console path[3].
-
-       - Multiple UARTs selected as EFI console devices.  EFI and
-         elilo use all selected devices, but Linux uses only one.
-         Make sure only one UART is selected in the EFI console
-         path[3].
-
-       - You're connected to an HP MP port[2] but have a non-MP UART
-         selected as EFI console device.  EFI uses the MP as a
-         console device even when it isn't explicitly selected.
-         Either move the console cable to the non-MP UART, or change
-         the EFI console path[3] to the MP UART.
-
-    Long pause (60+ seconds) between "Uncompressing Linux... done" and
-    start of kernel output:
-
-       - No early console because you used "console=ttyS<n>".  Remove
-         the "console=" option if your firmware supplies an HCDP.
-
-       - If you don't have an HCDP, the kernel doesn't know where
-         your console lives until the driver discovers serial
-         devices.  Use "console=uart,io,0x3f8" (or appropriate
-         address for your machine).
-
-    Kernel and init script output works fine, but no "login:" prompt:
-
-       - Add getty entry to /etc/inittab for console tty.  Look for
-         the "Adding console on ttyS<n>" message that tells you which
-         device is the console.
-
-    "login:" prompt, but can't login as root:
-
-       - Add entry to /etc/securetty for console tty.
-
-    No ACPI serial devices found in 2.6.17 or later:
-
-       - Turn on CONFIG_PNP and CONFIG_PNPACPI.  Prior to 2.6.17, ACPI
-         serial devices were discovered by 8250_acpi.  In 2.6.17,
-         8250_acpi was replaced by the combination of 8250_pnp and
-         CONFIG_PNPACPI.
-
-
-
-[1] http://www.dig64.org/specifications/agreement 
-    The table was originally defined as the "HCDP" for "Headless
-    Console/Debug Port."  The current version is the "PCDP" for
-    "Primary Console and Debug Port Devices."
-
-[2] The HP MP (management processor) is a PCI device that provides
-    several UARTs.  One of the UARTs is often used as a console; the
-    EFI Boot Manager identifies it as "Acpi(HWP0002,700)/Pci(...)/Uart".
-    The external connection is usually a 25-pin connector, and a
-    special dongle converts that to three 9-pin connectors, one of
-    which is labelled "Console."
-
-[3] EFI console devices are configured using the EFI Boot Manager
-    "Boot option maintenance" menu.  You may have to interrupt the
-    boot sequence to use this menu, and you will have to reset the
-    box after changing console configuration.
diff --git a/Documentation/ia64/xen.rst b/Documentation/ia64/xen.rst
new file mode 100644 (file)
index 0000000..831339c
--- /dev/null
@@ -0,0 +1,206 @@
+********************************************************
+Recipe for getting/building/running Xen/ia64 with pv_ops
+********************************************************
+This recipe describes how to get xen-ia64 source and build it,
+and run domU with pv_ops.
+
+Requirements
+============
+
+  - python
+  - mercurial
+    it (aka "hg") is an open-source source code
+    management software. See the below.
+    http://www.selenic.com/mercurial/wiki/
+  - git
+  - bridge-utils
+
+Getting and Building Xen and Dom0
+=================================
+
+  My environment is:
+
+    - Machine  : Tiger4
+    - Domain0 OS  : RHEL5
+    - DomainU OS  : RHEL5
+
+ 1. Download source::
+
+       # hg clone http://xenbits.xensource.com/ext/ia64/xen-unstable.hg
+       # cd xen-unstable.hg
+       # hg clone http://xenbits.xensource.com/ext/ia64/linux-2.6.18-xen.hg
+
+ 2. # make world
+
+ 3. # make install-tools
+
+ 4. copy kernels and xen::
+
+       # cp xen/xen.gz /boot/efi/efi/redhat/
+       # cp build-linux-2.6.18-xen_ia64/vmlinux.gz \
+       /boot/efi/efi/redhat/vmlinuz-2.6.18.8-xen
+
+ 5. make initrd for Dom0/DomU::
+
+       # make -C linux-2.6.18-xen.hg ARCH=ia64 modules_install \
+          O=$(pwd)/build-linux-2.6.18-xen_ia64
+       # mkinitrd -f /boot/efi/efi/redhat/initrd-2.6.18.8-xen.img \
+         2.6.18.8-xen --builtin mptspi --builtin mptbase \
+         --builtin mptscsih --builtin uhci-hcd --builtin ohci-hcd \
+         --builtin ehci-hcd
+
+Making a disk image for guest OS
+================================
+
+ 1. make file::
+
+      # dd if=/dev/zero of=/root/rhel5.img bs=1M seek=4096 count=0
+      # mke2fs -F -j /root/rhel5.img
+      # mount -o loop /root/rhel5.img /mnt
+      # cp -ax /{dev,var,etc,usr,bin,sbin,lib} /mnt
+      # mkdir /mnt/{root,proc,sys,home,tmp}
+
+      Note: You may miss some device files. If so, please create them
+      with mknod. Or you can use tar instead of cp.
+
+ 2. modify DomU's fstab::
+
+      # vi /mnt/etc/fstab
+         /dev/xvda1  /            ext3    defaults        1 1
+         none        /dev/pts     devpts  gid=5,mode=620  0 0
+         none        /dev/shm     tmpfs   defaults        0 0
+         none        /proc        proc    defaults        0 0
+         none        /sys         sysfs   defaults        0 0
+
+ 3. modify inittab
+
+    set runlevel to 3 to avoid X trying to start::
+
+      # vi /mnt/etc/inittab
+         id:3:initdefault:
+
+    Start a getty on the hvc0 console::
+
+       X0:2345:respawn:/sbin/mingetty hvc0
+
+    tty1-6 mingetty can be commented out
+
+ 4. add hvc0 into /etc/securetty::
+
+      # vi /mnt/etc/securetty (add hvc0)
+
+ 5. umount::
+
+      # umount /mnt
+
+FYI, virt-manager can also make a disk image for guest OS.
+It's GUI tools and easy to make it.
+
+Boot Xen & Domain0
+==================
+
+ 1. replace elilo
+    elilo of RHEL5 can boot Xen and Dom0.
+    If you use old elilo (e.g RHEL4), please download from the below
+    http://elilo.sourceforge.net/cgi-bin/blosxom
+    and copy into /boot/efi/efi/redhat/::
+
+      # cp elilo-3.6-ia64.efi /boot/efi/efi/redhat/elilo.efi
+
+ 2. modify elilo.conf (like the below)::
+
+      # vi /boot/efi/efi/redhat/elilo.conf
+      prompt
+      timeout=20
+      default=xen
+      relocatable
+
+      image=vmlinuz-2.6.18.8-xen
+             label=xen
+             vmm=xen.gz
+             initrd=initrd-2.6.18.8-xen.img
+             read-only
+             append=" -- rhgb root=/dev/sda2"
+
+The append options before "--" are for xen hypervisor,
+the options after "--" are for dom0.
+
+FYI, your machine may need console options like
+"com1=19200,8n1 console=vga,com1". For example,
+append="com1=19200,8n1 console=vga,com1 -- rhgb console=tty0 \
+console=ttyS0 root=/dev/sda2"
+
+Getting and Building domU with pv_ops
+=====================================
+
+ 1. get pv_ops tree::
+
+      # git clone http://people.valinux.co.jp/~yamahata/xen-ia64/linux-2.6-xen-ia64.git/
+
+ 2. git branch (if necessary)::
+
+      # cd linux-2.6-xen-ia64/
+      # git checkout -b your_branch origin/xen-ia64-domu-minimal-2008may19
+
+   Note:
+     The current branch is xen-ia64-domu-minimal-2008may19.
+     But you would find the new branch. You can see with
+     "git branch -r" to get the branch lists.
+
+       http://people.valinux.co.jp/~yamahata/xen-ia64/for_eagl/linux-2.6-ia64-pv-ops.git/
+
+     is also available.
+
+     The tree is based on
+
+      git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6 test)
+
+ 3. copy .config for pv_ops of domU::
+
+      # cp arch/ia64/configs/xen_domu_wip_defconfig .config
+
+ 4. make kernel with pv_ops::
+
+      # make oldconfig
+      # make
+
+ 5. install the kernel and initrd::
+
+      # cp vmlinux.gz /boot/efi/efi/redhat/vmlinuz-2.6-pv_ops-xenU
+      # make modules_install
+      # mkinitrd -f /boot/efi/efi/redhat/initrd-2.6-pv_ops-xenU.img \
+        2.6.26-rc3xen-ia64-08941-g1b12161 --builtin mptspi \
+        --builtin mptbase --builtin mptscsih --builtin uhci-hcd \
+        --builtin ohci-hcd --builtin ehci-hcd
+
+Boot DomainU with pv_ops
+========================
+
+ 1. make config of DomU::
+
+     # vi /etc/xen/rhel5
+       kernel = "/boot/efi/efi/redhat/vmlinuz-2.6-pv_ops-xenU"
+       ramdisk = "/boot/efi/efi/redhat/initrd-2.6-pv_ops-xenU.img"
+       vcpus = 1
+       memory = 512
+       name = "rhel5"
+       disk = [ 'file:/root/rhel5.img,xvda1,w' ]
+       root = "/dev/xvda1 ro"
+       extra= "rhgb console=hvc0"
+
+ 2. After boot xen and dom0, start xend::
+
+       # /etc/init.d/xend start
+
+   ( In the debugging case, `# XEND_DEBUG=1 xend trace_start` )
+
+ 3. start domU::
+
+       # xm create -c rhel5
+
+Reference
+=========
+- Wiki of Xen/IA64 upstream merge
+  http://wiki.xensource.com/xenwiki/XenIA64/UpstreamMerge
+
+Written by Akio Takebe <takebe_akio@jp.fujitsu.com> on 28 May 2008
diff --git a/Documentation/ia64/xen.txt b/Documentation/ia64/xen.txt
deleted file mode 100644 (file)
index a12c74c..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-       Recipe for getting/building/running Xen/ia64 with pv_ops
-       --------------------------------------------------------
-
-This recipe describes how to get xen-ia64 source and build it,
-and run domU with pv_ops.
-
-============
-Requirements
-============
-
-  - python
-  - mercurial
-    it (aka "hg") is an open-source source code
-    management software. See the below.
-    http://www.selenic.com/mercurial/wiki/
-  - git
-  - bridge-utils
-
-=================================
-Getting and Building Xen and Dom0
-=================================
-
-  My environment is;
-    Machine  : Tiger4
-    Domain0 OS  : RHEL5
-    DomainU OS  : RHEL5
-
- 1. Download source
-    # hg clone http://xenbits.xensource.com/ext/ia64/xen-unstable.hg
-    # cd xen-unstable.hg
-    # hg clone http://xenbits.xensource.com/ext/ia64/linux-2.6.18-xen.hg
-
- 2. # make world
-
- 3. # make install-tools
-
- 4. copy kernels and xen
-    # cp xen/xen.gz /boot/efi/efi/redhat/
-    # cp build-linux-2.6.18-xen_ia64/vmlinux.gz \
-      /boot/efi/efi/redhat/vmlinuz-2.6.18.8-xen
-
- 5. make initrd for Dom0/DomU
-    # make -C linux-2.6.18-xen.hg ARCH=ia64 modules_install \
-      O=$(pwd)/build-linux-2.6.18-xen_ia64
-    # mkinitrd -f /boot/efi/efi/redhat/initrd-2.6.18.8-xen.img \
-      2.6.18.8-xen --builtin mptspi --builtin mptbase \
-      --builtin mptscsih --builtin uhci-hcd --builtin ohci-hcd \
-      --builtin ehci-hcd
-
-================================
-Making a disk image for guest OS
-================================
-
- 1. make file
-    # dd if=/dev/zero of=/root/rhel5.img bs=1M seek=4096 count=0
-    # mke2fs -F -j /root/rhel5.img
-    # mount -o loop /root/rhel5.img /mnt
-    # cp -ax /{dev,var,etc,usr,bin,sbin,lib} /mnt
-    # mkdir /mnt/{root,proc,sys,home,tmp}
-
-    Note: You may miss some device files. If so, please create them
-    with mknod. Or you can use tar instead of cp.
-
- 2. modify DomU's fstab
-    # vi /mnt/etc/fstab
-       /dev/xvda1  /            ext3    defaults        1 1
-       none        /dev/pts     devpts  gid=5,mode=620  0 0
-       none        /dev/shm     tmpfs   defaults        0 0
-       none        /proc        proc    defaults        0 0
-       none        /sys         sysfs   defaults        0 0
-
- 3. modify inittab
-    set runlevel to 3 to avoid X trying to start
-    # vi /mnt/etc/inittab
-       id:3:initdefault:
-    Start a getty on the hvc0 console
-       X0:2345:respawn:/sbin/mingetty hvc0
-    tty1-6 mingetty can be commented out
-
- 4. add hvc0 into /etc/securetty
-    # vi /mnt/etc/securetty (add hvc0)
-
- 5. umount
-    # umount /mnt
-
-FYI, virt-manager can also make a disk image for guest OS.
-It's GUI tools and easy to make it.
-
-==================
-Boot Xen & Domain0
-==================
-
- 1. replace elilo
-    elilo of RHEL5 can boot Xen and Dom0.
-    If you use old elilo (e.g RHEL4), please download from the below
-    http://elilo.sourceforge.net/cgi-bin/blosxom
-    and copy into /boot/efi/efi/redhat/
-    # cp elilo-3.6-ia64.efi /boot/efi/efi/redhat/elilo.efi
-
- 2. modify elilo.conf (like the below)
-    # vi /boot/efi/efi/redhat/elilo.conf
-     prompt
-     timeout=20
-     default=xen
-     relocatable
-
-     image=vmlinuz-2.6.18.8-xen
-             label=xen
-             vmm=xen.gz
-             initrd=initrd-2.6.18.8-xen.img
-             read-only
-             append=" -- rhgb root=/dev/sda2"
-
-The append options before "--" are for xen hypervisor,
-the options after "--" are for dom0.
-
-FYI, your machine may need console options like
-"com1=19200,8n1 console=vga,com1". For example,
-append="com1=19200,8n1 console=vga,com1 -- rhgb console=tty0 \
-console=ttyS0 root=/dev/sda2"
-
-=====================================
-Getting and Building domU with pv_ops
-=====================================
-
- 1. get pv_ops tree
-    # git clone http://people.valinux.co.jp/~yamahata/xen-ia64/linux-2.6-xen-ia64.git/
-
- 2. git branch (if necessary)
-    # cd linux-2.6-xen-ia64/
-    # git checkout -b your_branch origin/xen-ia64-domu-minimal-2008may19
-    (Note: The current branch is xen-ia64-domu-minimal-2008may19.
-    But you would find the new branch. You can see with
-    "git branch -r" to get the branch lists.
-    http://people.valinux.co.jp/~yamahata/xen-ia64/for_eagl/linux-2.6-ia64-pv-ops.git/
-    is also available. The tree is based on
-    git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6 test)
-
-
- 3. copy .config for pv_ops of domU
-    # cp arch/ia64/configs/xen_domu_wip_defconfig .config
-
- 4. make kernel with pv_ops
-    # make oldconfig
-    # make
-
- 5. install the kernel and initrd
-    # cp vmlinux.gz /boot/efi/efi/redhat/vmlinuz-2.6-pv_ops-xenU
-    # make modules_install
-    # mkinitrd -f /boot/efi/efi/redhat/initrd-2.6-pv_ops-xenU.img \
-      2.6.26-rc3xen-ia64-08941-g1b12161 --builtin mptspi \
-      --builtin mptbase --builtin mptscsih --builtin uhci-hcd \
-      --builtin ohci-hcd --builtin ehci-hcd
-
-========================
-Boot DomainU with pv_ops
-========================
-
- 1. make config of DomU
-   # vi /etc/xen/rhel5
-     kernel = "/boot/efi/efi/redhat/vmlinuz-2.6-pv_ops-xenU"
-     ramdisk = "/boot/efi/efi/redhat/initrd-2.6-pv_ops-xenU.img"
-     vcpus = 1
-     memory = 512
-     name = "rhel5"
-     disk = [ 'file:/root/rhel5.img,xvda1,w' ]
-     root = "/dev/xvda1 ro"
-     extra= "rhgb console=hvc0"
-
- 2. After boot xen and dom0, start xend
-   # /etc/init.d/xend start
-   ( In the debugging case, # XEND_DEBUG=1 xend trace_start )
-
- 3. start domU
-   # xm create -c rhel5
-
-=========
-Reference
-=========
-- Wiki of Xen/IA64 upstream merge
-  http://wiki.xensource.com/xenwiki/XenIA64/UpstreamMerge
-
-Written by Akio Takebe <takebe_akio@jp.fujitsu.com> on 28 May 2008
index 45bc12d..813dfe6 100644 (file)
@@ -1,4 +1,4 @@
-:orphan:
+.. SPDX-License-Identifier: GPL-2.0
 
 ==================================
 Integrated Drive Electronics (IDE)
index 0593dca..58b7a4e 100644 (file)
@@ -1,4 +1,4 @@
-:orphan:
+.. SPDX-License-Identifier: GPL-2.0
 
 ==============
 Industrial I/O
index 00a0fe4..70ae148 100644 (file)
@@ -1,3 +1,4 @@
+
 .. The Linux Kernel documentation master file, created by
    sphinx-quickstart on Fri Feb 12 13:51:46 2016.
    You can adapt this file completely to your liking, but it should at least
@@ -34,6 +35,7 @@ trying to get it to work optimally on a given system.
    :maxdepth: 2
 
    admin-guide/index
+   kbuild/index
 
 Firmware-related documentation
 ------------------------------
@@ -55,6 +57,7 @@ the kernel interface as seen by application developers.
    :maxdepth: 2
 
    userspace-api/index
+   ioctl/index
 
 
 Introduction to kernel development
@@ -75,6 +78,9 @@ merged much easier.
    kernel-hacking/index
    trace/index
    maintainer/index
+   fault-injection/index
+   livepatch/index
+
 
 Kernel API documentation
 ------------------------
@@ -90,9 +96,24 @@ needed).
 
    driver-api/index
    core-api/index
+   locking/index
+   accounting/index
+   block/index
+   cdrom/index
+   ide/index
+   fb/index
+   fpga/index
+   hid/index
+   iio/index
    infiniband/index
+   leds/index
    media/index
+   netlabel/index
    networking/index
+   pcmcia/index
+   target/index
+   timers/index
+   watchdog/index
    input/index
    hwmon/index
    gpu/index
@@ -105,6 +126,8 @@ needed).
    usb/index
    PCI/index
    misc-devices/index
+   mic/index
+   scheduler/index
 
 Architecture-specific documentation
 -----------------------------------
@@ -116,7 +139,16 @@ implementation.
    :maxdepth: 2
 
    sh/index
+   arm/index
+   arm64/index
+   ia64/index
+   m68k/index
+   riscv/index
+   s390/index
+   sh/index
+   sparc/index
    x86/index
+   xtensa/index
 
 Filesystem Documentation
 ------------------------
diff --git a/Documentation/interconnect/interconnect.rst b/Documentation/interconnect/interconnect.rst
deleted file mode 100644 (file)
index 56e331d..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-
-:orphan:
-
-=====================================
-GENERIC SYSTEM INTERCONNECT SUBSYSTEM
-=====================================
-
-Introduction
-------------
-
-This framework is designed to provide a standard kernel interface to control
-the settings of the interconnects on an SoC. These settings can be throughput,
-latency and priority between multiple interconnected devices or functional
-blocks. This can be controlled dynamically in order to save power or provide
-maximum performance.
-
-The interconnect bus is hardware with configurable parameters, which can be
-set on a data path according to the requests received from various drivers.
-An example of interconnect buses are the interconnects between various
-components or functional blocks in chipsets. There can be multiple interconnects
-on an SoC that can be multi-tiered.
-
-Below is a simplified diagram of a real-world SoC interconnect bus topology.
-
-::
-
- +----------------+    +----------------+
- | HW Accelerator |--->|      M NoC     |<---------------+
- +----------------+    +----------------+                |
-                         |      |                    +------------+
-  +-----+  +-------------+      V       +------+     |            |
-  | DDR |  |                +--------+  | PCIe |     |            |
-  +-----+  |                | Slaves |  +------+     |            |
-    ^ ^    |                +--------+     |         |   C NoC    |
-    | |    V                               V         |            |
- +------------------+   +------------------------+   |            |   +-----+
- |                  |-->|                        |-->|            |-->| CPU |
- |                  |-->|                        |<--|            |   +-----+
- |     Mem NoC      |   |         S NoC          |   +------------+
- |                  |<--|                        |---------+    |
- |                  |<--|                        |<------+ |    |   +--------+
- +------------------+   +------------------------+       | |    +-->| Slaves |
-   ^  ^    ^    ^          ^                             | |        +--------+
-   |  |    |    |          |                             | V
- +------+  |  +-----+   +-----+  +---------+   +----------------+   +--------+
- | CPUs |  |  | GPU |   | DSP |  | Masters |-->|       P NoC    |-->| Slaves |
- +------+  |  +-----+   +-----+  +---------+   +----------------+   +--------+
-           |
-       +-------+
-       | Modem |
-       +-------+
-
-Terminology
------------
-
-Interconnect provider is the software definition of the interconnect hardware.
-The interconnect providers on the above diagram are M NoC, S NoC, C NoC, P NoC
-and Mem NoC.
-
-Interconnect node is the software definition of the interconnect hardware
-port. Each interconnect provider consists of multiple interconnect nodes,
-which are connected to other SoC components including other interconnect
-providers. The point on the diagram where the CPUs connect to the memory is
-called an interconnect node, which belongs to the Mem NoC interconnect provider.
-
-Interconnect endpoints are the first or the last element of the path. Every
-endpoint is a node, but not every node is an endpoint.
-
-Interconnect path is everything between two endpoints including all the nodes
-that have to be traversed to reach from a source to destination node. It may
-include multiple master-slave pairs across several interconnect providers.
-
-Interconnect consumers are the entities which make use of the data paths exposed
-by the providers. The consumers send requests to providers requesting various
-throughput, latency and priority. Usually the consumers are device drivers, that
-send request based on their needs. An example for a consumer is a video decoder
-that supports various formats and image sizes.
-
-Interconnect providers
-----------------------
-
-Interconnect provider is an entity that implements methods to initialize and
-configure interconnect bus hardware. The interconnect provider drivers should
-be registered with the interconnect provider core.
-
-.. kernel-doc:: include/linux/interconnect-provider.h
-
-Interconnect consumers
-----------------------
-
-Interconnect consumers are the clients which use the interconnect APIs to
-get paths between endpoints and set their bandwidth/latency/QoS requirements
-for these interconnect paths.  These interfaces are not currently
-documented.
diff --git a/Documentation/ioctl/botching-up-ioctls.rst b/Documentation/ioctl/botching-up-ioctls.rst
new file mode 100644 (file)
index 0000000..ac697fe
--- /dev/null
@@ -0,0 +1,225 @@
+=================================
+(How to avoid) Botching up ioctls
+=================================
+
+From: http://blog.ffwll.ch/2013/11/botching-up-ioctls.html
+
+By: Daniel Vetter, Copyright © 2013 Intel Corporation
+
+One clear insight kernel graphics hackers gained in the past few years is that
+trying to come up with a unified interface to manage the execution units and
+memory on completely different GPUs is a futile effort. So nowadays every
+driver has its own set of ioctls to allocate memory and submit work to the GPU.
+Which is nice, since there's no more insanity in the form of fake-generic, but
+actually only used once interfaces. But the clear downside is that there's much
+more potential to screw things up.
+
+To avoid repeating all the same mistakes again I've written up some of the
+lessons learned while botching the job for the drm/i915 driver. Most of these
+only cover technicalities and not the big-picture issues like what the command
+submission ioctl exactly should look like. Learning these lessons is probably
+something every GPU driver has to do on its own.
+
+
+Prerequisites
+-------------
+
+First the prerequisites. Without these you have already failed, because you
+will need to add a 32-bit compat layer:
+
+ * Only use fixed sized integers. To avoid conflicts with typedefs in userspace
+   the kernel has special types like __u32, __s64. Use them.
+
+ * Align everything to the natural size and use explicit padding. 32-bit
+   platforms don't necessarily align 64-bit values to 64-bit boundaries, but
+   64-bit platforms do. So we always need padding to the natural size to get
+   this right.
+
+ * Pad the entire struct to a multiple of 64-bits if the structure contains
+   64-bit types - the structure size will otherwise differ on 32-bit versus
+   64-bit. Having a different structure size hurts when passing arrays of
+   structures to the kernel, or if the kernel checks the structure size, which
+   e.g. the drm core does.
+
+ * Pointers are __u64, cast from/to a uintprt_t on the userspace side and
+   from/to a void __user * in the kernel. Try really hard not to delay this
+   conversion or worse, fiddle the raw __u64 through your code since that
+   diminishes the checking tools like sparse can provide. The macro
+   u64_to_user_ptr can be used in the kernel to avoid warnings about integers
+   and pointres of different sizes.
+
+
+Basics
+------
+
+With the joys of writing a compat layer avoided we can take a look at the basic
+fumbles. Neglecting these will make backward and forward compatibility a real
+pain. And since getting things wrong on the first attempt is guaranteed you
+will have a second iteration or at least an extension for any given interface.
+
+ * Have a clear way for userspace to figure out whether your new ioctl or ioctl
+   extension is supported on a given kernel. If you can't rely on old kernels
+   rejecting the new flags/modes or ioctls (since doing that was botched in the
+   past) then you need a driver feature flag or revision number somewhere.
+
+ * Have a plan for extending ioctls with new flags or new fields at the end of
+   the structure. The drm core checks the passed-in size for each ioctl call
+   and zero-extends any mismatches between kernel and userspace. That helps,
+   but isn't a complete solution since newer userspace on older kernels won't
+   notice that the newly added fields at the end get ignored. So this still
+   needs a new driver feature flags.
+
+ * Check all unused fields and flags and all the padding for whether it's 0,
+   and reject the ioctl if that's not the case. Otherwise your nice plan for
+   future extensions is going right down the gutters since someone will submit
+   an ioctl struct with random stack garbage in the yet unused parts. Which
+   then bakes in the ABI that those fields can never be used for anything else
+   but garbage. This is also the reason why you must explicitly pad all
+   structures, even if you never use them in an array - the padding the compiler
+   might insert could contain garbage.
+
+ * Have simple testcases for all of the above.
+
+
+Fun with Error Paths
+--------------------
+
+Nowadays we don't have any excuse left any more for drm drivers being neat
+little root exploits. This means we both need full input validation and solid
+error handling paths - GPUs will die eventually in the oddmost corner cases
+anyway:
+
+ * The ioctl must check for array overflows. Also it needs to check for
+   over/underflows and clamping issues of integer values in general. The usual
+   example is sprite positioning values fed directly into the hardware with the
+   hardware just having 12 bits or so. Works nicely until some odd display
+   server doesn't bother with clamping itself and the cursor wraps around the
+   screen.
+
+ * Have simple testcases for every input validation failure case in your ioctl.
+   Check that the error code matches your expectations. And finally make sure
+   that you only test for one single error path in each subtest by submitting
+   otherwise perfectly valid data. Without this an earlier check might reject
+   the ioctl already and shadow the codepath you actually want to test, hiding
+   bugs and regressions.
+
+ * Make all your ioctls restartable. First X really loves signals and second
+   this will allow you to test 90% of all error handling paths by just
+   interrupting your main test suite constantly with signals. Thanks to X's
+   love for signal you'll get an excellent base coverage of all your error
+   paths pretty much for free for graphics drivers. Also, be consistent with
+   how you handle ioctl restarting - e.g. drm has a tiny drmIoctl helper in its
+   userspace library. The i915 driver botched this with the set_tiling ioctl,
+   now we're stuck forever with some arcane semantics in both the kernel and
+   userspace.
+
+ * If you can't make a given codepath restartable make a stuck task at least
+   killable. GPUs just die and your users won't like you more if you hang their
+   entire box (by means of an unkillable X process). If the state recovery is
+   still too tricky have a timeout or hangcheck safety net as a last-ditch
+   effort in case the hardware has gone bananas.
+
+ * Have testcases for the really tricky corner cases in your error recovery code
+   - it's way too easy to create a deadlock between your hangcheck code and
+   waiters.
+
+
+Time, Waiting and Missing it
+----------------------------
+
+GPUs do most everything asynchronously, so we have a need to time operations and
+wait for outstanding ones. This is really tricky business; at the moment none of
+the ioctls supported by the drm/i915 get this fully right, which means there's
+still tons more lessons to learn here.
+
+ * Use CLOCK_MONOTONIC as your reference time, always. It's what alsa, drm and
+   v4l use by default nowadays. But let userspace know which timestamps are
+   derived from different clock domains like your main system clock (provided
+   by the kernel) or some independent hardware counter somewhere else. Clocks
+   will mismatch if you look close enough, but if performance measuring tools
+   have this information they can at least compensate. If your userspace can
+   get at the raw values of some clocks (e.g. through in-command-stream
+   performance counter sampling instructions) consider exposing those also.
+
+ * Use __s64 seconds plus __u64 nanoseconds to specify time. It's not the most
+   convenient time specification, but it's mostly the standard.
+
+ * Check that input time values are normalized and reject them if not. Note
+   that the kernel native struct ktime has a signed integer for both seconds
+   and nanoseconds, so beware here.
+
+ * For timeouts, use absolute times. If you're a good fellow and made your
+   ioctl restartable relative timeouts tend to be too coarse and can
+   indefinitely extend your wait time due to rounding on each restart.
+   Especially if your reference clock is something really slow like the display
+   frame counter. With a spec lawyer hat on this isn't a bug since timeouts can
+   always be extended - but users will surely hate you if their neat animations
+   starts to stutter due to this.
+
+ * Consider ditching any synchronous wait ioctls with timeouts and just deliver
+   an asynchronous event on a pollable file descriptor. It fits much better
+   into event driven applications' main loop.
+
+ * Have testcases for corner-cases, especially whether the return values for
+   already-completed events, successful waits and timed-out waits are all sane
+   and suiting to your needs.
+
+
+Leaking Resources, Not
+----------------------
+
+A full-blown drm driver essentially implements a little OS, but specialized to
+the given GPU platforms. This means a driver needs to expose tons of handles
+for different objects and other resources to userspace. Doing that right
+entails its own little set of pitfalls:
+
+ * Always attach the lifetime of your dynamically created resources to the
+   lifetime of a file descriptor. Consider using a 1:1 mapping if your resource
+   needs to be shared across processes -  fd-passing over unix domain sockets
+   also simplifies lifetime management for userspace.
+
+ * Always have O_CLOEXEC support.
+
+ * Ensure that you have sufficient insulation between different clients. By
+   default pick a private per-fd namespace which forces any sharing to be done
+   explicitly. Only go with a more global per-device namespace if the objects
+   are truly device-unique. One counterexample in the drm modeset interfaces is
+   that the per-device modeset objects like connectors share a namespace with
+   framebuffer objects, which mostly are not shared at all. A separate
+   namespace, private by default, for framebuffers would have been more
+   suitable.
+
+ * Think about uniqueness requirements for userspace handles. E.g. for most drm
+   drivers it's a userspace bug to submit the same object twice in the same
+   command submission ioctl. But then if objects are shareable userspace needs
+   to know whether it has seen an imported object from a different process
+   already or not. I haven't tried this myself yet due to lack of a new class
+   of objects, but consider using inode numbers on your shared file descriptors
+   as unique identifiers - it's how real files are told apart, too.
+   Unfortunately this requires a full-blown virtual filesystem in the kernel.
+
+
+Last, but not Least
+-------------------
+
+Not every problem needs a new ioctl:
+
+ * Think hard whether you really want a driver-private interface. Of course
+   it's much quicker to push a driver-private interface than engaging in
+   lengthy discussions for a more generic solution. And occasionally doing a
+   private interface to spearhead a new concept is what's required. But in the
+   end, once the generic interface comes around you'll end up maintainer two
+   interfaces. Indefinitely.
+
+ * Consider other interfaces than ioctls. A sysfs attribute is much better for
+   per-device settings, or for child objects with fairly static lifetimes (like
+   output connectors in drm with all the detection override attributes). Or
+   maybe only your testsuite needs this interface, and then debugfs with its
+   disclaimer of not having a stable ABI would be better.
+
+Finally, the name of the game is to get it right on the first attempt, since if
+your driver proves popular and your hardware platforms long-lived then you'll
+be stuck with a given ioctl essentially forever. You can try to deprecate
+horrible ioctls on newer iterations of your hardware, but generally it takes
+years to accomplish this. And then again years until the last user able to
+complain about regressions disappears, too.
diff --git a/Documentation/ioctl/botching-up-ioctls.txt b/Documentation/ioctl/botching-up-ioctls.txt
deleted file mode 100644 (file)
index 883fb03..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-(How to avoid) Botching up ioctls
-=================================
-
-From: http://blog.ffwll.ch/2013/11/botching-up-ioctls.html
-
-By: Daniel Vetter, Copyright © 2013 Intel Corporation
-
-One clear insight kernel graphics hackers gained in the past few years is that
-trying to come up with a unified interface to manage the execution units and
-memory on completely different GPUs is a futile effort. So nowadays every
-driver has its own set of ioctls to allocate memory and submit work to the GPU.
-Which is nice, since there's no more insanity in the form of fake-generic, but
-actually only used once interfaces. But the clear downside is that there's much
-more potential to screw things up.
-
-To avoid repeating all the same mistakes again I've written up some of the
-lessons learned while botching the job for the drm/i915 driver. Most of these
-only cover technicalities and not the big-picture issues like what the command
-submission ioctl exactly should look like. Learning these lessons is probably
-something every GPU driver has to do on its own.
-
-
-Prerequisites
--------------
-
-First the prerequisites. Without these you have already failed, because you
-will need to add a 32-bit compat layer:
-
- * Only use fixed sized integers. To avoid conflicts with typedefs in userspace
-   the kernel has special types like __u32, __s64. Use them.
-
- * Align everything to the natural size and use explicit padding. 32-bit
-   platforms don't necessarily align 64-bit values to 64-bit boundaries, but
-   64-bit platforms do. So we always need padding to the natural size to get
-   this right.
-
- * Pad the entire struct to a multiple of 64-bits if the structure contains
-   64-bit types - the structure size will otherwise differ on 32-bit versus
-   64-bit. Having a different structure size hurts when passing arrays of
-   structures to the kernel, or if the kernel checks the structure size, which
-   e.g. the drm core does.
-
- * Pointers are __u64, cast from/to a uintprt_t on the userspace side and
-   from/to a void __user * in the kernel. Try really hard not to delay this
-   conversion or worse, fiddle the raw __u64 through your code since that
-   diminishes the checking tools like sparse can provide. The macro
-   u64_to_user_ptr can be used in the kernel to avoid warnings about integers
-   and pointres of different sizes.
-
-
-Basics
-------
-
-With the joys of writing a compat layer avoided we can take a look at the basic
-fumbles. Neglecting these will make backward and forward compatibility a real
-pain. And since getting things wrong on the first attempt is guaranteed you
-will have a second iteration or at least an extension for any given interface.
-
- * Have a clear way for userspace to figure out whether your new ioctl or ioctl
-   extension is supported on a given kernel. If you can't rely on old kernels
-   rejecting the new flags/modes or ioctls (since doing that was botched in the
-   past) then you need a driver feature flag or revision number somewhere.
-
- * Have a plan for extending ioctls with new flags or new fields at the end of
-   the structure. The drm core checks the passed-in size for each ioctl call
-   and zero-extends any mismatches between kernel and userspace. That helps,
-   but isn't a complete solution since newer userspace on older kernels won't
-   notice that the newly added fields at the end get ignored. So this still
-   needs a new driver feature flags.
-
- * Check all unused fields and flags and all the padding for whether it's 0,
-   and reject the ioctl if that's not the case. Otherwise your nice plan for
-   future extensions is going right down the gutters since someone will submit
-   an ioctl struct with random stack garbage in the yet unused parts. Which
-   then bakes in the ABI that those fields can never be used for anything else
-   but garbage. This is also the reason why you must explicitly pad all
-   structures, even if you never use them in an array - the padding the compiler
-   might insert could contain garbage.
-
- * Have simple testcases for all of the above.
-
-
-Fun with Error Paths
---------------------
-
-Nowadays we don't have any excuse left any more for drm drivers being neat
-little root exploits. This means we both need full input validation and solid
-error handling paths - GPUs will die eventually in the oddmost corner cases
-anyway:
-
- * The ioctl must check for array overflows. Also it needs to check for
-   over/underflows and clamping issues of integer values in general. The usual
-   example is sprite positioning values fed directly into the hardware with the
-   hardware just having 12 bits or so. Works nicely until some odd display
-   server doesn't bother with clamping itself and the cursor wraps around the
-   screen.
-
- * Have simple testcases for every input validation failure case in your ioctl.
-   Check that the error code matches your expectations. And finally make sure
-   that you only test for one single error path in each subtest by submitting
-   otherwise perfectly valid data. Without this an earlier check might reject
-   the ioctl already and shadow the codepath you actually want to test, hiding
-   bugs and regressions.
-
- * Make all your ioctls restartable. First X really loves signals and second
-   this will allow you to test 90% of all error handling paths by just
-   interrupting your main test suite constantly with signals. Thanks to X's
-   love for signal you'll get an excellent base coverage of all your error
-   paths pretty much for free for graphics drivers. Also, be consistent with
-   how you handle ioctl restarting - e.g. drm has a tiny drmIoctl helper in its
-   userspace library. The i915 driver botched this with the set_tiling ioctl,
-   now we're stuck forever with some arcane semantics in both the kernel and
-   userspace.
-
- * If you can't make a given codepath restartable make a stuck task at least
-   killable. GPUs just die and your users won't like you more if you hang their
-   entire box (by means of an unkillable X process). If the state recovery is
-   still too tricky have a timeout or hangcheck safety net as a last-ditch
-   effort in case the hardware has gone bananas.
-
- * Have testcases for the really tricky corner cases in your error recovery code
-   - it's way too easy to create a deadlock between your hangcheck code and
-   waiters.
-
-
-Time, Waiting and Missing it
-----------------------------
-
-GPUs do most everything asynchronously, so we have a need to time operations and
-wait for outstanding ones. This is really tricky business; at the moment none of
-the ioctls supported by the drm/i915 get this fully right, which means there's
-still tons more lessons to learn here.
-
- * Use CLOCK_MONOTONIC as your reference time, always. It's what alsa, drm and
-   v4l use by default nowadays. But let userspace know which timestamps are
-   derived from different clock domains like your main system clock (provided
-   by the kernel) or some independent hardware counter somewhere else. Clocks
-   will mismatch if you look close enough, but if performance measuring tools
-   have this information they can at least compensate. If your userspace can
-   get at the raw values of some clocks (e.g. through in-command-stream
-   performance counter sampling instructions) consider exposing those also.
-
- * Use __s64 seconds plus __u64 nanoseconds to specify time. It's not the most
-   convenient time specification, but it's mostly the standard.
-
- * Check that input time values are normalized and reject them if not. Note
-   that the kernel native struct ktime has a signed integer for both seconds
-   and nanoseconds, so beware here.
-
- * For timeouts, use absolute times. If you're a good fellow and made your
-   ioctl restartable relative timeouts tend to be too coarse and can
-   indefinitely extend your wait time due to rounding on each restart.
-   Especially if your reference clock is something really slow like the display
-   frame counter. With a spec lawyer hat on this isn't a bug since timeouts can
-   always be extended - but users will surely hate you if their neat animations
-   starts to stutter due to this.
-
- * Consider ditching any synchronous wait ioctls with timeouts and just deliver
-   an asynchronous event on a pollable file descriptor. It fits much better
-   into event driven applications' main loop.
-
- * Have testcases for corner-cases, especially whether the return values for
-   already-completed events, successful waits and timed-out waits are all sane
-   and suiting to your needs.
-
-
-Leaking Resources, Not
-----------------------
-
-A full-blown drm driver essentially implements a little OS, but specialized to
-the given GPU platforms. This means a driver needs to expose tons of handles
-for different objects and other resources to userspace. Doing that right
-entails its own little set of pitfalls:
-
- * Always attach the lifetime of your dynamically created resources to the
-   lifetime of a file descriptor. Consider using a 1:1 mapping if your resource
-   needs to be shared across processes -  fd-passing over unix domain sockets
-   also simplifies lifetime management for userspace.
-
- * Always have O_CLOEXEC support.
-
- * Ensure that you have sufficient insulation between different clients. By
-   default pick a private per-fd namespace which forces any sharing to be done
-   explicitly. Only go with a more global per-device namespace if the objects
-   are truly device-unique. One counterexample in the drm modeset interfaces is
-   that the per-device modeset objects like connectors share a namespace with
-   framebuffer objects, which mostly are not shared at all. A separate
-   namespace, private by default, for framebuffers would have been more
-   suitable.
-
- * Think about uniqueness requirements for userspace handles. E.g. for most drm
-   drivers it's a userspace bug to submit the same object twice in the same
-   command submission ioctl. But then if objects are shareable userspace needs
-   to know whether it has seen an imported object from a different process
-   already or not. I haven't tried this myself yet due to lack of a new class
-   of objects, but consider using inode numbers on your shared file descriptors
-   as unique identifiers - it's how real files are told apart, too.
-   Unfortunately this requires a full-blown virtual filesystem in the kernel.
-
-
-Last, but not Least
--------------------
-
-Not every problem needs a new ioctl:
-
- * Think hard whether you really want a driver-private interface. Of course
-   it's much quicker to push a driver-private interface than engaging in
-   lengthy discussions for a more generic solution. And occasionally doing a
-   private interface to spearhead a new concept is what's required. But in the
-   end, once the generic interface comes around you'll end up maintainer two
-   interfaces. Indefinitely.
-
- * Consider other interfaces than ioctls. A sysfs attribute is much better for
-   per-device settings, or for child objects with fairly static lifetimes (like
-   output connectors in drm with all the detection override attributes). Or
-   maybe only your testsuite needs this interface, and then debugfs with its
-   disclaimer of not having a stable ABI would be better.
-
-Finally, the name of the game is to get it right on the first attempt, since if
-your driver proves popular and your hardware platforms long-lived then you'll
-be stuck with a given ioctl essentially forever. You can try to deprecate
-horrible ioctls on newer iterations of your hardware, but generally it takes
-years to accomplish this. And then again years until the last user able to
-complain about regressions disappears, too.
diff --git a/Documentation/ioctl/cdrom.rst b/Documentation/ioctl/cdrom.rst
new file mode 100644 (file)
index 0000000..3b4c050
--- /dev/null
@@ -0,0 +1,1233 @@
+============================
+Summary of CDROM ioctl calls
+============================
+
+- Edward A. Falk <efalk@google.com>
+
+November, 2004
+
+This document attempts to describe the ioctl(2) calls supported by
+the CDROM layer.  These are by-and-large implemented (as of Linux 2.6)
+in drivers/cdrom/cdrom.c and drivers/block/scsi_ioctl.c
+
+ioctl values are listed in <linux/cdrom.h>.  As of this writing, they
+are as follows:
+
+       ======================  ===============================================
+       CDROMPAUSE              Pause Audio Operation
+       CDROMRESUME             Resume paused Audio Operation
+       CDROMPLAYMSF            Play Audio MSF (struct cdrom_msf)
+       CDROMPLAYTRKIND         Play Audio Track/index (struct cdrom_ti)
+       CDROMREADTOCHDR         Read TOC header (struct cdrom_tochdr)
+       CDROMREADTOCENTRY       Read TOC entry (struct cdrom_tocentry)
+       CDROMSTOP               Stop the cdrom drive
+       CDROMSTART              Start the cdrom drive
+       CDROMEJECT              Ejects the cdrom media
+       CDROMVOLCTRL            Control output volume (struct cdrom_volctrl)
+       CDROMSUBCHNL            Read subchannel data (struct cdrom_subchnl)
+       CDROMREADMODE2          Read CDROM mode 2 data (2336 Bytes)
+                               (struct cdrom_read)
+       CDROMREADMODE1          Read CDROM mode 1 data (2048 Bytes)
+                               (struct cdrom_read)
+       CDROMREADAUDIO          (struct cdrom_read_audio)
+       CDROMEJECT_SW           enable(1)/disable(0) auto-ejecting
+       CDROMMULTISESSION       Obtain the start-of-last-session
+                               address of multi session disks
+                               (struct cdrom_multisession)
+       CDROM_GET_MCN           Obtain the "Universal Product Code"
+                               if available (struct cdrom_mcn)
+       CDROM_GET_UPC           Deprecated, use CDROM_GET_MCN instead.
+       CDROMRESET              hard-reset the drive
+       CDROMVOLREAD            Get the drive's volume setting
+                               (struct cdrom_volctrl)
+       CDROMREADRAW            read data in raw mode (2352 Bytes)
+                               (struct cdrom_read)
+       CDROMREADCOOKED         read data in cooked mode
+       CDROMSEEK               seek msf address
+       CDROMPLAYBLK            scsi-cd only, (struct cdrom_blk)
+       CDROMREADALL            read all 2646 bytes
+       CDROMGETSPINDOWN        return 4-bit spindown value
+       CDROMSETSPINDOWN        set 4-bit spindown value
+       CDROMCLOSETRAY          pendant of CDROMEJECT
+       CDROM_SET_OPTIONS       Set behavior options
+       CDROM_CLEAR_OPTIONS     Clear behavior options
+       CDROM_SELECT_SPEED      Set the CD-ROM speed
+       CDROM_SELECT_DISC       Select disc (for juke-boxes)
+       CDROM_MEDIA_CHANGED     Check is media changed
+       CDROM_DRIVE_STATUS      Get tray position, etc.
+       CDROM_DISC_STATUS       Get disc type, etc.
+       CDROM_CHANGER_NSLOTS    Get number of slots
+       CDROM_LOCKDOOR          lock or unlock door
+       CDROM_DEBUG             Turn debug messages on/off
+       CDROM_GET_CAPABILITY    get capabilities
+       CDROMAUDIOBUFSIZ        set the audio buffer size
+       DVD_READ_STRUCT         Read structure
+       DVD_WRITE_STRUCT        Write structure
+       DVD_AUTH                Authentication
+       CDROM_SEND_PACKET       send a packet to the drive
+       CDROM_NEXT_WRITABLE     get next writable block
+       CDROM_LAST_WRITTEN      get last block written on disc
+       ======================  ===============================================
+
+
+The information that follows was determined from reading kernel source
+code.  It is likely that some corrections will be made over time.
+
+------------------------------------------------------------------------------
+
+General:
+
+       Unless otherwise specified, all ioctl calls return 0 on success
+       and -1 with errno set to an appropriate value on error.  (Some
+       ioctls return non-negative data values.)
+
+       Unless otherwise specified, all ioctl calls return -1 and set
+       errno to EFAULT on a failed attempt to copy data to or from user
+       address space.
+
+       Individual drivers may return error codes not listed here.
+
+       Unless otherwise specified, all data structures and constants
+       are defined in <linux/cdrom.h>
+
+------------------------------------------------------------------------------
+
+
+CDROMPAUSE
+       Pause Audio Operation
+
+
+       usage::
+
+         ioctl(fd, CDROMPAUSE, 0);
+
+
+       inputs:
+               none
+
+
+       outputs:
+               none
+
+
+       error return:
+         - ENOSYS      cd drive not audio-capable.
+
+
+CDROMRESUME
+       Resume paused Audio Operation
+
+
+       usage::
+
+         ioctl(fd, CDROMRESUME, 0);
+
+
+       inputs:
+               none
+
+
+       outputs:
+               none
+
+
+       error return:
+         - ENOSYS      cd drive not audio-capable.
+
+
+CDROMPLAYMSF
+       Play Audio MSF
+
+       (struct cdrom_msf)
+
+
+       usage::
+
+         struct cdrom_msf msf;
+
+         ioctl(fd, CDROMPLAYMSF, &msf);
+
+       inputs:
+               cdrom_msf structure, describing a segment of music to play
+
+
+       outputs:
+               none
+
+
+       error return:
+         - ENOSYS      cd drive not audio-capable.
+
+       notes:
+               - MSF stands for minutes-seconds-frames
+               - LBA stands for logical block address
+               - Segment is described as start and end times, where each time
+                 is described as minutes:seconds:frames.
+                 A frame is 1/75 of a second.
+
+
+CDROMPLAYTRKIND
+       Play Audio Track/index
+
+       (struct cdrom_ti)
+
+
+       usage::
+
+         struct cdrom_ti ti;
+
+         ioctl(fd, CDROMPLAYTRKIND, &ti);
+
+       inputs:
+               cdrom_ti structure, describing a segment of music to play
+
+
+       outputs:
+               none
+
+
+       error return:
+         - ENOSYS      cd drive not audio-capable.
+
+       notes:
+               - Segment is described as start and end times, where each time
+                 is described as a track and an index.
+
+
+
+CDROMREADTOCHDR
+       Read TOC header
+
+       (struct cdrom_tochdr)
+
+
+       usage::
+
+         cdrom_tochdr header;
+
+         ioctl(fd, CDROMREADTOCHDR, &header);
+
+       inputs:
+               cdrom_tochdr structure
+
+
+       outputs:
+               cdrom_tochdr structure
+
+
+       error return:
+         - ENOSYS      cd drive not audio-capable.
+
+
+
+CDROMREADTOCENTRY
+       Read TOC entry
+
+       (struct cdrom_tocentry)
+
+
+       usage::
+
+         struct cdrom_tocentry entry;
+
+         ioctl(fd, CDROMREADTOCENTRY, &entry);
+
+       inputs:
+               cdrom_tocentry structure
+
+
+       outputs:
+               cdrom_tocentry structure
+
+
+       error return:
+         - ENOSYS      cd drive not audio-capable.
+         - EINVAL      entry.cdte_format not CDROM_MSF or CDROM_LBA
+         - EINVAL      requested track out of bounds
+         - EIO         I/O error reading TOC
+
+       notes:
+               - TOC stands for Table Of Contents
+               - MSF stands for minutes-seconds-frames
+               - LBA stands for logical block address
+
+
+
+CDROMSTOP
+       Stop the cdrom drive
+
+
+       usage::
+
+         ioctl(fd, CDROMSTOP, 0);
+
+
+       inputs:
+               none
+
+
+       outputs:
+               none
+
+
+       error return:
+         - ENOSYS      cd drive not audio-capable.
+
+       notes:
+         - Exact interpretation of this ioctl depends on the device,
+           but most seem to spin the drive down.
+
+
+CDROMSTART
+       Start the cdrom drive
+
+
+       usage::
+
+         ioctl(fd, CDROMSTART, 0);
+
+
+       inputs:
+               none
+
+
+       outputs:
+               none
+
+
+       error return:
+         - ENOSYS      cd drive not audio-capable.
+
+       notes:
+         - Exact interpretation of this ioctl depends on the device,
+           but most seem to spin the drive up and/or close the tray.
+           Other devices ignore the ioctl completely.
+
+
+CDROMEJECT
+       - Ejects the cdrom media
+
+
+       usage::
+
+         ioctl(fd, CDROMEJECT, 0);
+
+
+       inputs:
+               none
+
+
+       outputs:
+               none
+
+
+       error returns:
+         - ENOSYS      cd drive not capable of ejecting
+         - EBUSY       other processes are accessing drive, or door is locked
+
+       notes:
+               - See CDROM_LOCKDOOR, below.
+
+
+
+
+CDROMCLOSETRAY
+       pendant of CDROMEJECT
+
+
+       usage::
+
+         ioctl(fd, CDROMCLOSETRAY, 0);
+
+
+       inputs:
+               none
+
+
+       outputs:
+               none
+
+
+       error returns:
+         - ENOSYS      cd drive not capable of closing the tray
+         - EBUSY       other processes are accessing drive, or door is locked
+
+       notes:
+               - See CDROM_LOCKDOOR, below.
+
+
+
+
+CDROMVOLCTRL
+       Control output volume (struct cdrom_volctrl)
+
+
+       usage::
+
+         struct cdrom_volctrl volume;
+
+         ioctl(fd, CDROMVOLCTRL, &volume);
+
+       inputs:
+               cdrom_volctrl structure containing volumes for up to 4
+               channels.
+
+       outputs:
+               none
+
+
+       error return:
+         - ENOSYS      cd drive not audio-capable.
+
+
+
+CDROMVOLREAD
+       Get the drive's volume setting
+
+       (struct cdrom_volctrl)
+
+
+       usage::
+
+         struct cdrom_volctrl volume;
+
+         ioctl(fd, CDROMVOLREAD, &volume);
+
+       inputs:
+               none
+
+
+       outputs:
+               The current volume settings.
+
+
+       error return:
+         - ENOSYS      cd drive not audio-capable.
+
+
+
+CDROMSUBCHNL
+       Read subchannel data
+
+       (struct cdrom_subchnl)
+
+
+       usage::
+
+         struct cdrom_subchnl q;
+
+         ioctl(fd, CDROMSUBCHNL, &q);
+
+       inputs:
+               cdrom_subchnl structure
+
+
+       outputs:
+               cdrom_subchnl structure
+
+
+       error return:
+         - ENOSYS      cd drive not audio-capable.
+         - EINVAL      format not CDROM_MSF or CDROM_LBA
+
+       notes:
+               - Format is converted to CDROM_MSF or CDROM_LBA
+                 as per user request on return
+
+
+
+CDROMREADRAW
+       read data in raw mode (2352 Bytes)
+
+       (struct cdrom_read)
+
+       usage::
+
+         union {
+
+           struct cdrom_msf msf;               /* input */
+           char buffer[CD_FRAMESIZE_RAW];      /* return */
+         } arg;
+         ioctl(fd, CDROMREADRAW, &arg);
+
+       inputs:
+               cdrom_msf structure indicating an address to read.
+
+               Only the start values are significant.
+
+       outputs:
+               Data written to address provided by user.
+
+
+       error return:
+         - EINVAL      address less than 0, or msf less than 0:2:0
+         - ENOMEM      out of memory
+
+       notes:
+               - As of 2.6.8.1, comments in <linux/cdrom.h> indicate that this
+                 ioctl accepts a cdrom_read structure, but actual source code
+                 reads a cdrom_msf structure and writes a buffer of data to
+                 the same address.
+
+               - MSF values are converted to LBA values via this formula::
+
+                   lba = (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET;
+
+
+
+
+CDROMREADMODE1
+       Read CDROM mode 1 data (2048 Bytes)
+
+       (struct cdrom_read)
+
+       notes:
+               Identical to CDROMREADRAW except that block size is
+               CD_FRAMESIZE (2048) bytes
+
+
+
+CDROMREADMODE2
+       Read CDROM mode 2 data (2336 Bytes)
+
+       (struct cdrom_read)
+
+       notes:
+               Identical to CDROMREADRAW except that block size is
+               CD_FRAMESIZE_RAW0 (2336) bytes
+
+
+
+CDROMREADAUDIO
+       (struct cdrom_read_audio)
+
+       usage::
+
+         struct cdrom_read_audio ra;
+
+         ioctl(fd, CDROMREADAUDIO, &ra);
+
+       inputs:
+               cdrom_read_audio structure containing read start
+               point and length
+
+       outputs:
+               audio data, returned to buffer indicated by ra
+
+
+       error return:
+         - EINVAL      format not CDROM_MSF or CDROM_LBA
+         - EINVAL      nframes not in range [1 75]
+         - ENXIO       drive has no queue (probably means invalid fd)
+         - ENOMEM      out of memory
+
+
+CDROMEJECT_SW
+       enable(1)/disable(0) auto-ejecting
+
+
+       usage::
+
+         int val;
+
+         ioctl(fd, CDROMEJECT_SW, val);
+
+       inputs:
+               Flag specifying auto-eject flag.
+
+
+       outputs:
+               none
+
+
+       error return:
+         - ENOSYS      Drive is not capable of ejecting.
+         - EBUSY       Door is locked
+
+
+
+
+CDROMMULTISESSION
+       Obtain the start-of-last-session address of multi session disks
+
+       (struct cdrom_multisession)
+
+       usage::
+
+         struct cdrom_multisession ms_info;
+
+         ioctl(fd, CDROMMULTISESSION, &ms_info);
+
+       inputs:
+               cdrom_multisession structure containing desired
+
+         format.
+
+       outputs:
+               cdrom_multisession structure is filled with last_session
+               information.
+
+       error return:
+         - EINVAL      format not CDROM_MSF or CDROM_LBA
+
+
+CDROM_GET_MCN
+       Obtain the "Universal Product Code"
+       if available
+
+       (struct cdrom_mcn)
+
+
+       usage::
+
+         struct cdrom_mcn mcn;
+
+         ioctl(fd, CDROM_GET_MCN, &mcn);
+
+       inputs:
+               none
+
+
+       outputs:
+               Universal Product Code
+
+
+       error return:
+         - ENOSYS      Drive is not capable of reading MCN data.
+
+       notes:
+               - Source code comments state::
+
+                   The following function is implemented, although very few
+                   audio discs give Universal Product Code information, which
+                   should just be the Medium Catalog Number on the box.  Note,
+                   that the way the code is written on the CD is /not/ uniform
+                   across all discs!
+
+
+
+
+CDROM_GET_UPC
+       CDROM_GET_MCN  (deprecated)
+
+
+       Not implemented, as of 2.6.8.1
+
+
+
+CDROMRESET
+       hard-reset the drive
+
+
+       usage::
+
+         ioctl(fd, CDROMRESET, 0);
+
+
+       inputs:
+               none
+
+
+       outputs:
+               none
+
+
+       error return:
+         - EACCES      Access denied:  requires CAP_SYS_ADMIN
+         - ENOSYS      Drive is not capable of resetting.
+
+
+
+
+CDROMREADCOOKED
+       read data in cooked mode
+
+
+       usage::
+
+         u8 buffer[CD_FRAMESIZE]
+
+         ioctl(fd, CDROMREADCOOKED, buffer);
+
+       inputs:
+               none
+
+
+       outputs:
+               2048 bytes of data, "cooked" mode.
+
+
+       notes:
+               Not implemented on all drives.
+
+
+
+
+
+CDROMREADALL
+       read all 2646 bytes
+
+
+       Same as CDROMREADCOOKED, but reads 2646 bytes.
+
+
+
+CDROMSEEK
+       seek msf address
+
+
+       usage::
+
+         struct cdrom_msf msf;
+
+         ioctl(fd, CDROMSEEK, &msf);
+
+       inputs:
+               MSF address to seek to.
+
+
+       outputs:
+               none
+
+
+
+
+CDROMPLAYBLK
+       scsi-cd only
+
+       (struct cdrom_blk)
+
+
+       usage::
+
+         struct cdrom_blk blk;
+
+         ioctl(fd, CDROMPLAYBLK, &blk);
+
+       inputs:
+               Region to play
+
+
+       outputs:
+               none
+
+
+
+
+CDROMGETSPINDOWN
+       usage::
+
+         char spindown;
+
+         ioctl(fd, CDROMGETSPINDOWN, &spindown);
+
+       inputs:
+               none
+
+
+       outputs:
+               The value of the current 4-bit spindown value.
+
+
+
+
+
+CDROMSETSPINDOWN
+       usage::
+
+         char spindown
+
+         ioctl(fd, CDROMSETSPINDOWN, &spindown);
+
+       inputs:
+               4-bit value used to control spindown (TODO: more detail here)
+
+
+       outputs:
+               none
+
+
+
+
+
+
+CDROM_SET_OPTIONS
+       Set behavior options
+
+
+       usage::
+
+         int options;
+
+         ioctl(fd, CDROM_SET_OPTIONS, options);
+
+       inputs:
+               New values for drive options.  The logical 'or' of:
+
+           ==============      ==================================
+           CDO_AUTO_CLOSE      close tray on first open(2)
+           CDO_AUTO_EJECT      open tray on last release
+           CDO_USE_FFLAGS      use O_NONBLOCK information on open
+           CDO_LOCK            lock tray on open files
+           CDO_CHECK_TYPE      check type on open for data
+           ==============      ==================================
+
+       outputs:
+               Returns the resulting options settings in the
+               ioctl return value.  Returns -1 on error.
+
+       error return:
+         - ENOSYS      selected option(s) not supported by drive.
+
+
+
+
+CDROM_CLEAR_OPTIONS
+       Clear behavior options
+
+
+       Same as CDROM_SET_OPTIONS, except that selected options are
+       turned off.
+
+
+
+CDROM_SELECT_SPEED
+       Set the CD-ROM speed
+
+
+       usage::
+
+         int speed;
+
+         ioctl(fd, CDROM_SELECT_SPEED, speed);
+
+       inputs:
+               New drive speed.
+
+
+       outputs:
+               none
+
+
+       error return:
+         - ENOSYS      speed selection not supported by drive.
+
+
+
+CDROM_SELECT_DISC
+       Select disc (for juke-boxes)
+
+
+       usage::
+
+         int disk;
+
+         ioctl(fd, CDROM_SELECT_DISC, disk);
+
+       inputs:
+               Disk to load into drive.
+
+
+       outputs:
+               none
+
+
+       error return:
+         - EINVAL      Disk number beyond capacity of drive
+
+
+
+CDROM_MEDIA_CHANGED
+       Check is media changed
+
+
+       usage::
+
+         int slot;
+
+         ioctl(fd, CDROM_MEDIA_CHANGED, slot);
+
+       inputs:
+               Slot number to be tested, always zero except for jukeboxes.
+
+               May also be special values CDSL_NONE or CDSL_CURRENT
+
+       outputs:
+               Ioctl return value is 0 or 1 depending on whether the media
+
+         has been changed, or -1 on error.
+
+       error returns:
+         - ENOSYS      Drive can't detect media change
+         - EINVAL      Slot number beyond capacity of drive
+         - ENOMEM      Out of memory
+
+
+
+CDROM_DRIVE_STATUS
+       Get tray position, etc.
+
+
+       usage::
+
+         int slot;
+
+         ioctl(fd, CDROM_DRIVE_STATUS, slot);
+
+       inputs:
+               Slot number to be tested, always zero except for jukeboxes.
+
+               May also be special values CDSL_NONE or CDSL_CURRENT
+
+       outputs:
+               Ioctl return value will be one of the following values
+
+         from <linux/cdrom.h>:
+
+           =================== ==========================
+           CDS_NO_INFO         Information not available.
+           CDS_NO_DISC
+           CDS_TRAY_OPEN
+           CDS_DRIVE_NOT_READY
+           CDS_DISC_OK
+           -1                  error
+           =================== ==========================
+
+       error returns:
+         - ENOSYS      Drive can't detect drive status
+         - EINVAL      Slot number beyond capacity of drive
+         - ENOMEM      Out of memory
+
+
+
+
+CDROM_DISC_STATUS
+       Get disc type, etc.
+
+
+       usage::
+
+         ioctl(fd, CDROM_DISC_STATUS, 0);
+
+
+       inputs:
+               none
+
+
+       outputs:
+               Ioctl return value will be one of the following values
+
+         from <linux/cdrom.h>:
+
+           - CDS_NO_INFO
+           - CDS_AUDIO
+           - CDS_MIXED
+           - CDS_XA_2_2
+           - CDS_XA_2_1
+           - CDS_DATA_1
+
+       error returns:
+               none at present
+
+       notes:
+           - Source code comments state::
+
+
+               Ok, this is where problems start.  The current interface for
+               the CDROM_DISC_STATUS ioctl is flawed.  It makes the false
+               assumption that CDs are all CDS_DATA_1 or all CDS_AUDIO, etc.
+               Unfortunately, while this is often the case, it is also
+               very common for CDs to have some tracks with data, and some
+               tracks with audio.      Just because I feel like it, I declare
+               the following to be the best way to cope.  If the CD has
+               ANY data tracks on it, it will be returned as a data CD.
+               If it has any XA tracks, I will return it as that.      Now I
+               could simplify this interface by combining these returns with
+               the above, but this more clearly demonstrates the problem
+               with the current interface.  Too bad this wasn't designed
+               to use bitmasks...             -Erik
+
+               Well, now we have the option CDS_MIXED: a mixed-type CD.
+               User level programmers might feel the ioctl is not very
+               useful.
+                               ---david
+
+
+
+
+CDROM_CHANGER_NSLOTS
+       Get number of slots
+
+
+       usage::
+
+         ioctl(fd, CDROM_CHANGER_NSLOTS, 0);
+
+
+       inputs:
+               none
+
+
+       outputs:
+               The ioctl return value will be the number of slots in a
+               CD changer.  Typically 1 for non-multi-disk devices.
+
+       error returns:
+               none
+
+
+
+CDROM_LOCKDOOR
+       lock or unlock door
+
+
+       usage::
+
+         int lock;
+
+         ioctl(fd, CDROM_LOCKDOOR, lock);
+
+       inputs:
+               Door lock flag, 1=lock, 0=unlock
+
+
+       outputs:
+               none
+
+
+       error returns:
+         - EDRIVE_CANT_DO_THIS
+
+                               Door lock function not supported.
+         - EBUSY
+
+                               Attempt to unlock when multiple users
+                               have the drive open and not CAP_SYS_ADMIN
+
+       notes:
+               As of 2.6.8.1, the lock flag is a global lock, meaning that
+               all CD drives will be locked or unlocked together.  This is
+               probably a bug.
+
+               The EDRIVE_CANT_DO_THIS value is defined in <linux/cdrom.h>
+               and is currently (2.6.8.1) the same as EOPNOTSUPP
+
+
+
+CDROM_DEBUG
+       Turn debug messages on/off
+
+
+       usage::
+
+         int debug;
+
+         ioctl(fd, CDROM_DEBUG, debug);
+
+       inputs:
+               Cdrom debug flag, 0=disable, 1=enable
+
+
+       outputs:
+               The ioctl return value will be the new debug flag.
+
+
+       error return:
+         - EACCES      Access denied:  requires CAP_SYS_ADMIN
+
+
+
+CDROM_GET_CAPABILITY
+       get capabilities
+
+
+       usage::
+
+         ioctl(fd, CDROM_GET_CAPABILITY, 0);
+
+
+       inputs:
+               none
+
+
+       outputs:
+               The ioctl return value is the current device capability
+               flags.  See CDC_CLOSE_TRAY, CDC_OPEN_TRAY, etc.
+
+
+
+CDROMAUDIOBUFSIZ
+       set the audio buffer size
+
+
+       usage::
+
+         int arg;
+
+         ioctl(fd, CDROMAUDIOBUFSIZ, val);
+
+       inputs:
+               New audio buffer size
+
+
+       outputs:
+               The ioctl return value is the new audio buffer size, or -1
+               on error.
+
+       error return:
+         - ENOSYS      Not supported by this driver.
+
+       notes:
+               Not supported by all drivers.
+
+
+
+
+DVD_READ_STRUCT                        Read structure
+
+       usage::
+
+         dvd_struct s;
+
+         ioctl(fd, DVD_READ_STRUCT, &s);
+
+       inputs:
+               dvd_struct structure, containing:
+
+           =================== ==========================================
+           type                specifies the information desired, one of
+                               DVD_STRUCT_PHYSICAL, DVD_STRUCT_COPYRIGHT,
+                               DVD_STRUCT_DISCKEY, DVD_STRUCT_BCA,
+                               DVD_STRUCT_MANUFACT
+           physical.layer_num  desired layer, indexed from 0
+           copyright.layer_num desired layer, indexed from 0
+           disckey.agid
+           =================== ==========================================
+
+       outputs:
+               dvd_struct structure, containing:
+
+           =================== ================================
+           physical            for type == DVD_STRUCT_PHYSICAL
+           copyright           for type == DVD_STRUCT_COPYRIGHT
+           disckey.value       for type == DVD_STRUCT_DISCKEY
+           bca.{len,value}     for type == DVD_STRUCT_BCA
+           manufact.{len,valu} for type == DVD_STRUCT_MANUFACT
+           =================== ================================
+
+       error returns:
+         - EINVAL      physical.layer_num exceeds number of layers
+         - EIO         Received invalid response from drive
+
+
+
+DVD_WRITE_STRUCT               Write structure
+
+       Not implemented, as of 2.6.8.1
+
+
+
+DVD_AUTH                       Authentication
+
+       usage::
+
+         dvd_authinfo ai;
+
+         ioctl(fd, DVD_AUTH, &ai);
+
+       inputs:
+               dvd_authinfo structure.  See <linux/cdrom.h>
+
+
+       outputs:
+               dvd_authinfo structure.
+
+
+       error return:
+         - ENOTTY      ai.type not recognized.
+
+
+
+CDROM_SEND_PACKET
+       send a packet to the drive
+
+
+       usage::
+
+         struct cdrom_generic_command cgc;
+
+         ioctl(fd, CDROM_SEND_PACKET, &cgc);
+
+       inputs:
+               cdrom_generic_command structure containing the packet to send.
+
+
+       outputs:
+               none
+
+         cdrom_generic_command structure containing results.
+
+       error return:
+         - EIO
+
+                       command failed.
+         - EPERM
+
+                       Operation not permitted, either because a
+                       write command was attempted on a drive which
+                       is opened read-only, or because the command
+                       requires CAP_SYS_RAWIO
+         - EINVAL
+
+                       cgc.data_direction not set
+
+
+
+CDROM_NEXT_WRITABLE
+       get next writable block
+
+
+       usage::
+
+         long next;
+
+         ioctl(fd, CDROM_NEXT_WRITABLE, &next);
+
+       inputs:
+               none
+
+
+       outputs:
+               The next writable block.
+
+
+       notes:
+               If the device does not support this ioctl directly, the
+
+         ioctl will return CDROM_LAST_WRITTEN + 7.
+
+
+
+CDROM_LAST_WRITTEN
+       get last block written on disc
+
+
+       usage::
+
+         long last;
+
+         ioctl(fd, CDROM_LAST_WRITTEN, &last);
+
+       inputs:
+               none
+
+
+       outputs:
+               The last block written on disc
+
+
+       notes:
+               If the device does not support this ioctl directly, the
+               result is derived from the disc's table of contents.  If the
+               table of contents can't be read, this ioctl returns an
+               error.
diff --git a/Documentation/ioctl/cdrom.txt b/Documentation/ioctl/cdrom.txt
deleted file mode 100644 (file)
index a4d62a9..0000000
+++ /dev/null
@@ -1,967 +0,0 @@
-               Summary of CDROM ioctl calls.
-               ============================
-
-               Edward A. Falk <efalk@google.com>
-
-               November, 2004
-
-This document attempts to describe the ioctl(2) calls supported by
-the CDROM layer.  These are by-and-large implemented (as of Linux 2.6)
-in drivers/cdrom/cdrom.c and drivers/block/scsi_ioctl.c
-
-ioctl values are listed in <linux/cdrom.h>.  As of this writing, they
-are as follows:
-
-       CDROMPAUSE              Pause Audio Operation
-       CDROMRESUME             Resume paused Audio Operation
-       CDROMPLAYMSF            Play Audio MSF (struct cdrom_msf)
-       CDROMPLAYTRKIND         Play Audio Track/index (struct cdrom_ti)
-       CDROMREADTOCHDR         Read TOC header (struct cdrom_tochdr)
-       CDROMREADTOCENTRY       Read TOC entry (struct cdrom_tocentry)
-       CDROMSTOP               Stop the cdrom drive
-       CDROMSTART              Start the cdrom drive
-       CDROMEJECT              Ejects the cdrom media
-       CDROMVOLCTRL            Control output volume (struct cdrom_volctrl)
-       CDROMSUBCHNL            Read subchannel data (struct cdrom_subchnl)
-       CDROMREADMODE2          Read CDROM mode 2 data (2336 Bytes)
-                                          (struct cdrom_read)
-       CDROMREADMODE1          Read CDROM mode 1 data (2048 Bytes)
-                                          (struct cdrom_read)
-       CDROMREADAUDIO          (struct cdrom_read_audio)
-       CDROMEJECT_SW           enable(1)/disable(0) auto-ejecting
-       CDROMMULTISESSION       Obtain the start-of-last-session
-                                 address of multi session disks
-                                 (struct cdrom_multisession)
-       CDROM_GET_MCN           Obtain the "Universal Product Code"
-                                  if available (struct cdrom_mcn)
-       CDROM_GET_UPC           Deprecated, use CDROM_GET_MCN instead.
-       CDROMRESET              hard-reset the drive
-       CDROMVOLREAD            Get the drive's volume setting
-                                         (struct cdrom_volctrl)
-       CDROMREADRAW            read data in raw mode (2352 Bytes)
-                                          (struct cdrom_read)
-       CDROMREADCOOKED         read data in cooked mode
-       CDROMSEEK               seek msf address
-       CDROMPLAYBLK            scsi-cd only, (struct cdrom_blk)
-       CDROMREADALL            read all 2646 bytes
-       CDROMGETSPINDOWN        return 4-bit spindown value
-       CDROMSETSPINDOWN        set 4-bit spindown value
-       CDROMCLOSETRAY          pendant of CDROMEJECT
-       CDROM_SET_OPTIONS       Set behavior options
-       CDROM_CLEAR_OPTIONS     Clear behavior options
-       CDROM_SELECT_SPEED      Set the CD-ROM speed
-       CDROM_SELECT_DISC       Select disc (for juke-boxes)
-       CDROM_MEDIA_CHANGED     Check is media changed
-       CDROM_DRIVE_STATUS      Get tray position, etc.
-       CDROM_DISC_STATUS       Get disc type, etc.
-       CDROM_CHANGER_NSLOTS    Get number of slots
-       CDROM_LOCKDOOR          lock or unlock door
-       CDROM_DEBUG             Turn debug messages on/off
-       CDROM_GET_CAPABILITY    get capabilities
-       CDROMAUDIOBUFSIZ        set the audio buffer size
-       DVD_READ_STRUCT         Read structure
-       DVD_WRITE_STRUCT        Write structure
-       DVD_AUTH                Authentication
-       CDROM_SEND_PACKET       send a packet to the drive
-       CDROM_NEXT_WRITABLE     get next writable block
-       CDROM_LAST_WRITTEN      get last block written on disc
-
-
-The information that follows was determined from reading kernel source
-code.  It is likely that some corrections will be made over time.
-
-
-
-
-
-
-
-General:
-
-       Unless otherwise specified, all ioctl calls return 0 on success
-       and -1 with errno set to an appropriate value on error.  (Some
-       ioctls return non-negative data values.)
-
-       Unless otherwise specified, all ioctl calls return -1 and set
-       errno to EFAULT on a failed attempt to copy data to or from user
-       address space.
-
-       Individual drivers may return error codes not listed here.
-
-       Unless otherwise specified, all data structures and constants
-       are defined in <linux/cdrom.h>
-
-
-
-
-CDROMPAUSE                     Pause Audio Operation
-
-       usage:
-
-         ioctl(fd, CDROMPAUSE, 0);
-
-       inputs:         none
-
-       outputs:        none
-
-       error return:
-         ENOSYS        cd drive not audio-capable.
-
-
-CDROMRESUME                    Resume paused Audio Operation
-
-       usage:
-
-         ioctl(fd, CDROMRESUME, 0);
-
-       inputs:         none
-
-       outputs:        none
-
-       error return:
-         ENOSYS        cd drive not audio-capable.
-
-
-CDROMPLAYMSF                   Play Audio MSF (struct cdrom_msf)
-
-       usage:
-
-         struct cdrom_msf msf;
-         ioctl(fd, CDROMPLAYMSF, &msf);
-
-       inputs:
-         cdrom_msf structure, describing a segment of music to play
-
-       outputs:        none
-
-       error return:
-         ENOSYS        cd drive not audio-capable.
-
-       notes:
-         MSF stands for minutes-seconds-frames
-         LBA stands for logical block address
-
-         Segment is described as start and end times, where each time
-         is described as minutes:seconds:frames.  A frame is 1/75 of
-         a second.
-
-
-CDROMPLAYTRKIND                        Play Audio Track/index (struct cdrom_ti)
-
-       usage:
-
-         struct cdrom_ti ti;
-         ioctl(fd, CDROMPLAYTRKIND, &ti);
-
-       inputs:
-         cdrom_ti structure, describing a segment of music to play
-
-       outputs:        none
-
-       error return:
-         ENOSYS        cd drive not audio-capable.
-
-       notes:
-         Segment is described as start and end times, where each time
-         is described as a track and an index.
-
-
-
-CDROMREADTOCHDR                        Read TOC header (struct cdrom_tochdr)
-
-       usage:
-
-         cdrom_tochdr header;
-         ioctl(fd, CDROMREADTOCHDR, &header);
-
-       inputs:
-         cdrom_tochdr structure
-
-       outputs:
-         cdrom_tochdr structure
-
-       error return:
-         ENOSYS        cd drive not audio-capable.
-
-
-
-CDROMREADTOCENTRY              Read TOC entry (struct cdrom_tocentry)
-
-       usage:
-
-         struct cdrom_tocentry entry;
-         ioctl(fd, CDROMREADTOCENTRY, &entry);
-
-       inputs:
-         cdrom_tocentry structure
-
-       outputs:
-         cdrom_tocentry structure
-
-       error return:
-         ENOSYS        cd drive not audio-capable.
-         EINVAL        entry.cdte_format not CDROM_MSF or CDROM_LBA
-         EINVAL        requested track out of bounds
-         EIO           I/O error reading TOC
-
-       notes:
-         TOC stands for Table Of Contents
-         MSF stands for minutes-seconds-frames
-         LBA stands for logical block address
-
-
-
-CDROMSTOP                      Stop the cdrom drive
-
-       usage:
-
-         ioctl(fd, CDROMSTOP, 0);
-
-       inputs:         none
-
-       outputs:        none
-
-       error return:
-         ENOSYS        cd drive not audio-capable.
-
-       notes:
-         Exact interpretation of this ioctl depends on the device,
-         but most seem to spin the drive down.
-
-
-CDROMSTART                     Start the cdrom drive
-
-       usage:
-
-         ioctl(fd, CDROMSTART, 0);
-
-       inputs:         none
-
-       outputs:        none
-
-       error return:
-         ENOSYS        cd drive not audio-capable.
-
-       notes:
-         Exact interpretation of this ioctl depends on the device,
-         but most seem to spin the drive up and/or close the tray.
-         Other devices ignore the ioctl completely.
-
-
-CDROMEJECT                     Ejects the cdrom media
-
-       usage:
-
-         ioctl(fd, CDROMEJECT, 0);
-
-       inputs:         none
-
-       outputs:        none
-
-       error returns:
-         ENOSYS        cd drive not capable of ejecting
-         EBUSY         other processes are accessing drive, or door is locked
-
-       notes:
-         See CDROM_LOCKDOOR, below.
-
-
-
-CDROMCLOSETRAY                 pendant of CDROMEJECT
-
-       usage:
-
-         ioctl(fd, CDROMCLOSETRAY, 0);
-
-       inputs:         none
-
-       outputs:        none
-
-       error returns:
-         ENOSYS        cd drive not capable of closing the tray
-         EBUSY         other processes are accessing drive, or door is locked
-
-       notes:
-         See CDROM_LOCKDOOR, below.
-
-
-
-CDROMVOLCTRL                   Control output volume (struct cdrom_volctrl)
-
-       usage:
-
-         struct cdrom_volctrl volume;
-         ioctl(fd, CDROMVOLCTRL, &volume);
-
-       inputs:
-         cdrom_volctrl structure containing volumes for up to 4
-         channels.
-
-       outputs:        none
-
-       error return:
-         ENOSYS        cd drive not audio-capable.
-
-
-
-CDROMVOLREAD                   Get the drive's volume setting
-                                         (struct cdrom_volctrl)
-
-       usage:
-
-         struct cdrom_volctrl volume;
-         ioctl(fd, CDROMVOLREAD, &volume);
-
-       inputs:         none
-
-       outputs:
-         The current volume settings.
-
-       error return:
-         ENOSYS        cd drive not audio-capable.
-
-
-
-CDROMSUBCHNL                   Read subchannel data (struct cdrom_subchnl)
-
-       usage:
-
-         struct cdrom_subchnl q;
-         ioctl(fd, CDROMSUBCHNL, &q);
-
-       inputs:
-         cdrom_subchnl structure
-
-       outputs:
-         cdrom_subchnl structure
-
-       error return:
-         ENOSYS        cd drive not audio-capable.
-         EINVAL        format not CDROM_MSF or CDROM_LBA
-
-       notes:
-         Format is converted to CDROM_MSF or CDROM_LBA
-         as per user request on return
-
-
-
-CDROMREADRAW                   read data in raw mode (2352 Bytes)
-                                          (struct cdrom_read)
-
-       usage:
-
-         union {
-           struct cdrom_msf msf;               /* input */
-           char buffer[CD_FRAMESIZE_RAW];      /* return */
-         } arg;
-         ioctl(fd, CDROMREADRAW, &arg);
-
-       inputs:
-         cdrom_msf structure indicating an address to read.
-         Only the start values are significant.
-
-       outputs:
-         Data written to address provided by user.
-
-       error return:
-         EINVAL        address less than 0, or msf less than 0:2:0
-         ENOMEM        out of memory
-
-       notes:
-         As of 2.6.8.1, comments in <linux/cdrom.h> indicate that this
-         ioctl accepts a cdrom_read structure, but actual source code
-         reads a cdrom_msf structure and writes a buffer of data to
-         the same address.
-
-         MSF values are converted to LBA values via this formula:
-
-           lba = (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET;
-
-
-
-
-CDROMREADMODE1                 Read CDROM mode 1 data (2048 Bytes)
-                                          (struct cdrom_read)
-
-       notes:
-         Identical to CDROMREADRAW except that block size is
-         CD_FRAMESIZE (2048) bytes
-
-
-
-CDROMREADMODE2                 Read CDROM mode 2 data (2336 Bytes)
-                                          (struct cdrom_read)
-
-       notes:
-         Identical to CDROMREADRAW except that block size is
-         CD_FRAMESIZE_RAW0 (2336) bytes
-
-
-
-CDROMREADAUDIO                 (struct cdrom_read_audio)
-
-       usage:
-
-         struct cdrom_read_audio ra;
-         ioctl(fd, CDROMREADAUDIO, &ra);
-
-       inputs:
-         cdrom_read_audio structure containing read start
-         point and length
-
-       outputs:
-         audio data, returned to buffer indicated by ra
-
-       error return:
-         EINVAL        format not CDROM_MSF or CDROM_LBA
-         EINVAL        nframes not in range [1 75]
-         ENXIO         drive has no queue (probably means invalid fd)
-         ENOMEM        out of memory
-
-
-CDROMEJECT_SW                  enable(1)/disable(0) auto-ejecting
-
-       usage:
-
-         int val;
-         ioctl(fd, CDROMEJECT_SW, val);
-
-       inputs:
-         Flag specifying auto-eject flag.
-
-       outputs:        none
-
-       error return:
-         ENOSYS        Drive is not capable of ejecting.
-         EBUSY         Door is locked
-
-
-
-
-CDROMMULTISESSION              Obtain the start-of-last-session
-                                 address of multi session disks
-                                 (struct cdrom_multisession)
-       usage:
-
-         struct cdrom_multisession ms_info;
-         ioctl(fd, CDROMMULTISESSION, &ms_info);
-
-       inputs:
-         cdrom_multisession structure containing desired
-         format.
-
-       outputs:
-         cdrom_multisession structure is filled with last_session
-         information.
-
-       error return:
-         EINVAL        format not CDROM_MSF or CDROM_LBA
-
-
-CDROM_GET_MCN                  Obtain the "Universal Product Code"
-                                  if available (struct cdrom_mcn)
-
-       usage:
-
-         struct cdrom_mcn mcn;
-         ioctl(fd, CDROM_GET_MCN, &mcn);
-
-       inputs:         none
-
-       outputs:
-         Universal Product Code
-
-       error return:
-         ENOSYS        Drive is not capable of reading MCN data.
-
-       notes:
-         Source code comments state:
-
-           The following function is implemented, although very few
-           audio discs give Universal Product Code information, which
-           should just be the Medium Catalog Number on the box.  Note,
-           that the way the code is written on the CD is /not/ uniform
-           across all discs!
-
-
-
-
-CDROM_GET_UPC                  CDROM_GET_MCN  (deprecated)
-
-       Not implemented, as of 2.6.8.1
-
-
-
-CDROMRESET                     hard-reset the drive
-
-       usage:
-
-         ioctl(fd, CDROMRESET, 0);
-
-       inputs:         none
-
-       outputs:        none
-
-       error return:
-         EACCES        Access denied:  requires CAP_SYS_ADMIN
-         ENOSYS        Drive is not capable of resetting.
-
-
-
-
-CDROMREADCOOKED                        read data in cooked mode
-
-       usage:
-
-         u8 buffer[CD_FRAMESIZE]
-         ioctl(fd, CDROMREADCOOKED, buffer);
-
-       inputs:         none
-
-       outputs:
-         2048 bytes of data, "cooked" mode.
-
-       notes:
-         Not implemented on all drives.
-
-
-
-
-CDROMREADALL                   read all 2646 bytes
-
-       Same as CDROMREADCOOKED, but reads 2646 bytes.
-
-
-
-CDROMSEEK                      seek msf address
-
-       usage:
-
-         struct cdrom_msf msf;
-         ioctl(fd, CDROMSEEK, &msf);
-
-       inputs:
-         MSF address to seek to.
-
-       outputs:        none
-
-
-
-CDROMPLAYBLK                   scsi-cd only, (struct cdrom_blk)
-
-       usage:
-
-         struct cdrom_blk blk;
-         ioctl(fd, CDROMPLAYBLK, &blk);
-
-       inputs:
-         Region to play
-
-       outputs:        none
-
-
-
-CDROMGETSPINDOWN
-
-       usage:
-
-         char spindown;
-         ioctl(fd, CDROMGETSPINDOWN, &spindown);
-
-       inputs:         none
-
-       outputs:
-         The value of the current 4-bit spindown value.
-
-
-
-
-CDROMSETSPINDOWN
-
-       usage:
-
-         char spindown
-         ioctl(fd, CDROMSETSPINDOWN, &spindown);
-
-       inputs:
-         4-bit value used to control spindown (TODO: more detail here)
-
-       outputs:        none
-
-
-
-
-
-CDROM_SET_OPTIONS              Set behavior options
-
-       usage:
-
-         int options;
-         ioctl(fd, CDROM_SET_OPTIONS, options);
-
-       inputs:
-         New values for drive options.  The logical 'or' of:
-           CDO_AUTO_CLOSE      close tray on first open(2)
-           CDO_AUTO_EJECT      open tray on last release
-           CDO_USE_FFLAGS      use O_NONBLOCK information on open
-           CDO_LOCK            lock tray on open files
-           CDO_CHECK_TYPE      check type on open for data
-
-       outputs:
-         Returns the resulting options settings in the
-         ioctl return value.  Returns -1 on error.
-
-       error return:
-         ENOSYS        selected option(s) not supported by drive.
-
-
-
-
-CDROM_CLEAR_OPTIONS            Clear behavior options
-
-       Same as CDROM_SET_OPTIONS, except that selected options are
-       turned off.
-
-
-
-CDROM_SELECT_SPEED             Set the CD-ROM speed
-
-       usage:
-
-         int speed;
-         ioctl(fd, CDROM_SELECT_SPEED, speed);
-
-       inputs:
-         New drive speed.
-
-       outputs:        none
-
-       error return:
-         ENOSYS        speed selection not supported by drive.
-
-
-
-CDROM_SELECT_DISC              Select disc (for juke-boxes)
-
-       usage:
-
-         int disk;
-         ioctl(fd, CDROM_SELECT_DISC, disk);
-
-       inputs:
-         Disk to load into drive.
-
-       outputs:        none
-
-       error return:
-         EINVAL        Disk number beyond capacity of drive
-
-
-
-CDROM_MEDIA_CHANGED            Check is media changed
-
-       usage:
-
-         int slot;
-         ioctl(fd, CDROM_MEDIA_CHANGED, slot);
-
-       inputs:
-         Slot number to be tested, always zero except for jukeboxes.
-         May also be special values CDSL_NONE or CDSL_CURRENT
-
-       outputs:
-         Ioctl return value is 0 or 1 depending on whether the media
-         has been changed, or -1 on error.
-
-       error returns:
-         ENOSYS        Drive can't detect media change
-         EINVAL        Slot number beyond capacity of drive
-         ENOMEM        Out of memory
-
-
-
-CDROM_DRIVE_STATUS             Get tray position, etc.
-
-       usage:
-
-         int slot;
-         ioctl(fd, CDROM_DRIVE_STATUS, slot);
-
-       inputs:
-         Slot number to be tested, always zero except for jukeboxes.
-         May also be special values CDSL_NONE or CDSL_CURRENT
-
-       outputs:
-         Ioctl return value will be one of the following values
-         from <linux/cdrom.h>:
-
-           CDS_NO_INFO         Information not available.
-           CDS_NO_DISC
-           CDS_TRAY_OPEN
-           CDS_DRIVE_NOT_READY
-           CDS_DISC_OK
-           -1                  error
-
-       error returns:
-         ENOSYS        Drive can't detect drive status
-         EINVAL        Slot number beyond capacity of drive
-         ENOMEM        Out of memory
-
-
-
-
-CDROM_DISC_STATUS              Get disc type, etc.
-
-       usage:
-
-         ioctl(fd, CDROM_DISC_STATUS, 0);
-
-       inputs:         none
-
-       outputs:
-         Ioctl return value will be one of the following values
-         from <linux/cdrom.h>:
-           CDS_NO_INFO
-           CDS_AUDIO
-           CDS_MIXED
-           CDS_XA_2_2
-           CDS_XA_2_1
-           CDS_DATA_1
-
-       error returns:  none at present
-
-       notes:
-         Source code comments state:
-
-           Ok, this is where problems start.  The current interface for
-           the CDROM_DISC_STATUS ioctl is flawed.  It makes the false
-           assumption that CDs are all CDS_DATA_1 or all CDS_AUDIO, etc.
-           Unfortunately, while this is often the case, it is also
-           very common for CDs to have some tracks with data, and some
-           tracks with audio.  Just because I feel like it, I declare
-           the following to be the best way to cope.  If the CD has
-           ANY data tracks on it, it will be returned as a data CD.
-           If it has any XA tracks, I will return it as that.  Now I
-           could simplify this interface by combining these returns with
-           the above, but this more clearly demonstrates the problem
-           with the current interface.  Too bad this wasn't designed
-           to use bitmasks...         -Erik
-
-           Well, now we have the option CDS_MIXED: a mixed-type CD.
-           User level programmers might feel the ioctl is not very
-           useful.
-                       ---david
-
-
-
-
-CDROM_CHANGER_NSLOTS           Get number of slots
-
-       usage:
-
-         ioctl(fd, CDROM_CHANGER_NSLOTS, 0);
-
-       inputs:         none
-
-       outputs:
-         The ioctl return value will be the number of slots in a
-         CD changer.  Typically 1 for non-multi-disk devices.
-
-       error returns:  none
-
-
-
-CDROM_LOCKDOOR                 lock or unlock door
-
-       usage:
-
-         int lock;
-         ioctl(fd, CDROM_LOCKDOOR, lock);
-
-       inputs:
-         Door lock flag, 1=lock, 0=unlock
-
-       outputs:        none
-
-       error returns:
-         EDRIVE_CANT_DO_THIS   Door lock function not supported.
-         EBUSY                 Attempt to unlock when multiple users
-                               have the drive open and not CAP_SYS_ADMIN
-
-       notes:
-         As of 2.6.8.1, the lock flag is a global lock, meaning that
-         all CD drives will be locked or unlocked together.  This is
-         probably a bug.
-
-         The EDRIVE_CANT_DO_THIS value is defined in <linux/cdrom.h>
-         and is currently (2.6.8.1) the same as EOPNOTSUPP
-
-
-
-CDROM_DEBUG                    Turn debug messages on/off
-
-       usage:
-
-         int debug;
-         ioctl(fd, CDROM_DEBUG, debug);
-
-       inputs:
-         Cdrom debug flag, 0=disable, 1=enable
-
-       outputs:
-         The ioctl return value will be the new debug flag.
-
-       error return:
-         EACCES        Access denied:  requires CAP_SYS_ADMIN
-
-
-
-CDROM_GET_CAPABILITY           get capabilities
-
-       usage:
-
-         ioctl(fd, CDROM_GET_CAPABILITY, 0);
-
-       inputs:         none
-
-       outputs:
-         The ioctl return value is the current device capability
-         flags.  See CDC_CLOSE_TRAY, CDC_OPEN_TRAY, etc.
-
-
-
-CDROMAUDIOBUFSIZ               set the audio buffer size
-
-       usage:
-
-         int arg;
-         ioctl(fd, CDROMAUDIOBUFSIZ, val);
-
-       inputs:
-         New audio buffer size
-
-       outputs:
-         The ioctl return value is the new audio buffer size, or -1
-         on error.
-
-       error return:
-         ENOSYS        Not supported by this driver.
-
-       notes:
-         Not supported by all drivers.
-
-
-
-DVD_READ_STRUCT                        Read structure
-
-       usage:
-
-         dvd_struct s;
-         ioctl(fd, DVD_READ_STRUCT, &s);
-
-       inputs:
-         dvd_struct structure, containing:
-           type                specifies the information desired, one of
-                               DVD_STRUCT_PHYSICAL, DVD_STRUCT_COPYRIGHT,
-                               DVD_STRUCT_DISCKEY, DVD_STRUCT_BCA,
-                               DVD_STRUCT_MANUFACT
-           physical.layer_num  desired layer, indexed from 0
-           copyright.layer_num desired layer, indexed from 0
-           disckey.agid
-
-       outputs:
-         dvd_struct structure, containing:
-           physical            for type == DVD_STRUCT_PHYSICAL
-           copyright           for type == DVD_STRUCT_COPYRIGHT
-           disckey.value       for type == DVD_STRUCT_DISCKEY
-           bca.{len,value}     for type == DVD_STRUCT_BCA
-           manufact.{len,valu} for type == DVD_STRUCT_MANUFACT
-
-       error returns:
-         EINVAL        physical.layer_num exceeds number of layers
-         EIO           Received invalid response from drive
-
-
-
-DVD_WRITE_STRUCT               Write structure
-
-       Not implemented, as of 2.6.8.1
-
-
-
-DVD_AUTH                       Authentication
-
-       usage:
-
-         dvd_authinfo ai;
-         ioctl(fd, DVD_AUTH, &ai);
-
-       inputs:
-         dvd_authinfo structure.  See <linux/cdrom.h>
-
-       outputs:
-         dvd_authinfo structure.
-
-       error return:
-         ENOTTY        ai.type not recognized.
-
-
-
-CDROM_SEND_PACKET              send a packet to the drive
-
-       usage:
-
-         struct cdrom_generic_command cgc;
-         ioctl(fd, CDROM_SEND_PACKET, &cgc);
-
-       inputs:
-         cdrom_generic_command structure containing the packet to send.
-
-       outputs:        none
-         cdrom_generic_command structure containing results.
-
-       error return:
-         EIO           command failed.
-         EPERM         Operation not permitted, either because a
-                       write command was attempted on a drive which
-                       is opened read-only, or because the command
-                       requires CAP_SYS_RAWIO
-         EINVAL        cgc.data_direction not set
-
-
-
-CDROM_NEXT_WRITABLE            get next writable block
-
-       usage:
-
-         long next;
-         ioctl(fd, CDROM_NEXT_WRITABLE, &next);
-
-       inputs:         none
-
-       outputs:
-         The next writable block.
-
-       notes:
-         If the device does not support this ioctl directly, the
-         ioctl will return CDROM_LAST_WRITTEN + 7.
-
-
-
-CDROM_LAST_WRITTEN             get last block written on disc
-
-       usage:
-
-         long last;
-         ioctl(fd, CDROM_LAST_WRITTEN, &last);
-
-       inputs:         none
-
-       outputs:
-         The last block written on disc
-
-       notes:
-         If the device does not support this ioctl directly, the
-         result is derived from the disc's table of contents.  If the
-         table of contents can't be read, this ioctl returns an
-         error.
diff --git a/Documentation/ioctl/hdio.rst b/Documentation/ioctl/hdio.rst
new file mode 100644 (file)
index 0000000..e822e3d
--- /dev/null
@@ -0,0 +1,1342 @@
+==============================
+Summary of `HDIO_` ioctl calls
+==============================
+
+- Edward A. Falk <efalk@google.com>
+
+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
+
+ioctl values are listed in <linux/hdreg.h>.  As of this writing, they
+are as follows:
+
+    ioctls that pass argument pointers to user space:
+
+       ======================= =======================================
+       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
+       ======================= =======================================
+
+
+The information that follows was determined from reading kernel source
+code.  It is likely that some corrections will be made over time.
+
+------------------------------------------------------------------------------
+
+General:
+
+       Unless otherwise specified, all ioctl calls return 0 on success
+       and -1 with errno set to an appropriate value on error.
+
+       Unless otherwise specified, all ioctl calls return -1 and set
+       errno to EFAULT on a failed attempt to copy data to or from user
+       address space.
+
+       Unless otherwise specified, all data structures and constants
+       are defined in <linux/hdreg.h>
+
+------------------------------------------------------------------------------
+
+HDIO_GETGEO
+       get device geometry
+
+
+       usage::
+
+         struct hd_geometry geom;
+
+         ioctl(fd, HDIO_GETGEO, &geom);
+
+
+       inputs:
+               none
+
+
+
+       outputs:
+               hd_geometry structure containing:
+
+
+           =========   ==================================
+           heads       number of heads
+           sectors     number of sectors/track
+           cylinders   number of cylinders, mod 65536
+           start       starting sector of this partition.
+           =========   ==================================
+
+
+       error returns:
+         - EINVAL
+
+                       if the device is not a disk drive or floppy drive,
+                       or if the user passes a null pointer
+
+
+       notes:
+               Not particularly useful with modern disk drives, whose geometry
+               is a polite fiction anyway.  Modern drives are addressed
+               purely by sector number nowadays (lba addressing), and the
+               drive geometry is an abstraction which is actually subject
+               to change.  Currently (as of Nov 2004), the geometry values
+               are the "bios" values -- presumably the values the drive had
+               when Linux first booted.
+
+               In addition, the cylinders field of the hd_geometry is an
+               unsigned short, meaning that on most architectures, this
+               ioctl will not return a meaningful value on drives with more
+               than 65535 tracks.
+
+               The start field is unsigned long, meaning that it will not
+               contain a meaningful value for disks over 219 Gb in size.
+
+
+
+
+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      (bdev != bdev->bd_contains) (not sure what this means)
+         - 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      (bdev != bdev->bd_contains) (not sure what this means)
+         - 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      (bdev != bdev->bd_contains) (not sure what this means)
+         - 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      (bdev != bdev->bd_contains) (not sure what this means)
+         - 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
+
+
+       usage::
+
+         int state;
+
+         ...
+         ioctl(fd, HDIO_SCAN_HWIF, state);
+
+       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
+
+
+
+
+HDIO_TRISTATE_HWIF
+       execute a channel tristate
+
+
+       Not implemented, as of 2.6.8.1.  See HDIO_SET_BUSSTATE
+
+
+
+HDIO_DRIVE_RESET
+       execute a device reset
+
+
+       usage::
+
+         int args[3]
+
+         ...
+         ioctl(fd, HDIO_DRIVE_RESET, args);
+
+       inputs:
+               none
+
+
+
+       outputs:
+               none
+
+
+
+       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.
+
+
+
+HDIO_DRIVE_TASKFILE
+       execute raw taskfile
+
+
+       Note:
+               If you don't have a copy of the ANSI ATA specification
+               handy, you should probably ignore this ioctl.
+
+       - Execute an ATA disk command directly by writing the "taskfile"
+         registers of the drive.  Requires ADMIN and RAWIO access
+         privileges.
+
+       usage::
+
+         struct {
+
+           ide_task_request_t req_task;
+           u8 outbuf[OUTPUT_SIZE];
+           u8 inbuf[INPUT_SIZE];
+         } task;
+         memset(&task.req_task, 0, sizeof(task.req_task));
+         task.req_task.out_size = sizeof(task.outbuf);
+         task.req_task.in_size = sizeof(task.inbuf);
+         ...
+         ioctl(fd, HDIO_DRIVE_TASKFILE, &task);
+         ...
+
+       inputs:
+
+         (See below for details on memory area passed to ioctl.)
+
+         ============  ===================================================
+         io_ports[8]   values to be written to taskfile registers
+         hob_ports[8]  high-order bytes, for extended commands.
+         out_flags     flags indicating which registers are valid
+         in_flags      flags indicating which registers should be returned
+         data_phase    see below
+         req_cmd       command type to be executed
+         out_size      size of output buffer
+         outbuf        buffer of data to be transmitted to disk
+         inbuf         buffer of data to be received from disk (see [1])
+         ============  ===================================================
+
+       outputs:
+
+         ===========   ====================================================
+         io_ports[]    values returned in the taskfile registers
+         hob_ports[]   high-order bytes, for extended commands.
+         out_flags     flags indicating which registers are valid (see [2])
+         in_flags      flags indicating which registers should be returned
+         outbuf        buffer of data to be transmitted to disk (see [1])
+         inbuf         buffer of data to be received from disk
+         ===========   ====================================================
+
+       error returns:
+         - EACCES      CAP_SYS_ADMIN or CAP_SYS_RAWIO privilege not set.
+         - ENOMSG      Device is not a disk drive.
+         - ENOMEM      Unable to allocate memory for task
+         - EFAULT      req_cmd == TASKFILE_IN_OUT (not implemented as of 2.6.8)
+         - EPERM
+
+                       req_cmd == TASKFILE_MULTI_OUT and drive
+                       multi-count not yet set.
+         - EIO         Drive failed the command.
+
+       notes:
+
+         [1] READ THE FOLLOWING NOTES *CAREFULLY*.  THIS IOCTL IS
+         FULL OF GOTCHAS.  Extreme caution should be used with using
+         this ioctl.  A mistake can easily corrupt data or hang the
+         system.
+
+         [2] Both the input and output buffers are copied from the
+         user and written back to the user, even when not used.
+
+         [3] If one or more bits are set in out_flags and in_flags is
+         zero, the following values are used for in_flags.all and
+         written back into in_flags on completion.
+
+          * IDE_TASKFILE_STD_IN_FLAGS | (IDE_HOB_STD_IN_FLAGS << 8)
+            if LBA48 addressing is enabled for the drive
+          * IDE_TASKFILE_STD_IN_FLAGS
+            if CHS/LBA28
+
+         The association between in_flags.all and each enable
+         bitfield flips depending on endianness; fortunately, TASKFILE
+         only uses inflags.b.data bit and ignores all other bits.
+         The end result is that, on any endian machines, it has no
+         effect other than modifying in_flags on completion.
+
+         [4] The default value of SELECT is (0xa0|DEV_bit|LBA_bit)
+         except for four drives per port chipsets.  For four drives
+         per port chipsets, it's (0xa0|DEV_bit|LBA_bit) for the first
+         pair and (0x80|DEV_bit|LBA_bit) for the second pair.
+
+         [5] The argument to the ioctl is a pointer to a region of
+         memory containing a ide_task_request_t structure, followed
+         by an optional buffer of data to be transmitted to the
+         drive, followed by an optional buffer to receive data from
+         the drive.
+
+         Command is passed to the disk drive via the ide_task_request_t
+         structure, which contains these fields:
+
+           ============        ===============================================
+           io_ports[8]         values for the taskfile registers
+           hob_ports[8]        high-order bytes, for extended commands
+           out_flags           flags indicating which entries in the
+                               io_ports[] and hob_ports[] arrays
+                               contain valid values.  Type ide_reg_valid_t.
+           in_flags            flags indicating which entries in the
+                               io_ports[] and hob_ports[] arrays
+                               are expected to contain valid values
+                               on return.
+           data_phase          See below
+           req_cmd             Command type, see below
+           out_size            output (user->drive) buffer size, bytes
+           in_size             input (drive->user) buffer size, bytes
+           ============        ===============================================
+
+         When out_flags is zero, the following registers are loaded.
+
+           ============        ===============================================
+           HOB_FEATURE         If the drive supports LBA48
+           HOB_NSECTOR         If the drive supports LBA48
+           HOB_SECTOR          If the drive supports LBA48
+           HOB_LCYL            If the drive supports LBA48
+           HOB_HCYL            If the drive supports LBA48
+           FEATURE
+           NSECTOR
+           SECTOR
+           LCYL
+           HCYL
+           SELECT              First, masked with 0xE0 if LBA48, 0xEF
+                               otherwise; then, or'ed with the default
+                               value of SELECT.
+           ============        ===============================================
+
+         If any bit in out_flags is set, the following registers are loaded.
+
+           ============        ===============================================
+           HOB_DATA            If out_flags.b.data is set.  HOB_DATA will
+                               travel on DD8-DD15 on little endian machines
+                               and on DD0-DD7 on big endian machines.
+           DATA                If out_flags.b.data is set.  DATA will
+                               travel on DD0-DD7 on little endian machines
+                               and on DD8-DD15 on big endian machines.
+           HOB_NSECTOR         If out_flags.b.nsector_hob is set
+           HOB_SECTOR          If out_flags.b.sector_hob is set
+           HOB_LCYL            If out_flags.b.lcyl_hob is set
+           HOB_HCYL            If out_flags.b.hcyl_hob is set
+           FEATURE             If out_flags.b.feature is set
+           NSECTOR             If out_flags.b.nsector is set
+           SECTOR              If out_flags.b.sector is set
+           LCYL                If out_flags.b.lcyl is set
+           HCYL                If out_flags.b.hcyl is set
+           SELECT              Or'ed with the default value of SELECT and
+                               loaded regardless of out_flags.b.select.
+           ============        ===============================================
+
+         Taskfile registers are read back from the drive into
+         {io|hob}_ports[] after the command completes iff one of the
+         following conditions is met; otherwise, the original values
+         will be written back, unchanged.
+
+           1. The drive fails the command (EIO).
+           2. One or more than one bits are set in out_flags.
+           3. The requested data_phase is TASKFILE_NO_DATA.
+
+           ============        ===============================================
+           HOB_DATA            If in_flags.b.data is set.  It will contain
+                               DD8-DD15 on little endian machines and
+                               DD0-DD7 on big endian machines.
+           DATA                If in_flags.b.data is set.  It will contain
+                               DD0-DD7 on little endian machines and
+                               DD8-DD15 on big endian machines.
+           HOB_FEATURE         If the drive supports LBA48
+           HOB_NSECTOR         If the drive supports LBA48
+           HOB_SECTOR          If the drive supports LBA48
+           HOB_LCYL            If the drive supports LBA48
+           HOB_HCYL            If the drive supports LBA48
+           NSECTOR
+           SECTOR
+           LCYL
+           HCYL
+           ============        ===============================================
+
+         The data_phase field describes the data transfer to be
+         performed.  Value is one of:
+
+           ===================        ========================================
+           TASKFILE_IN
+           TASKFILE_MULTI_IN
+           TASKFILE_OUT
+           TASKFILE_MULTI_OUT
+           TASKFILE_IN_OUT
+           TASKFILE_IN_DMA
+           TASKFILE_IN_DMAQ            == IN_DMA (queueing not supported)
+           TASKFILE_OUT_DMA
+           TASKFILE_OUT_DMAQ           == OUT_DMA (queueing not supported)
+           TASKFILE_P_IN               unimplemented
+           TASKFILE_P_IN_DMA           unimplemented
+           TASKFILE_P_IN_DMAQ          unimplemented
+           TASKFILE_P_OUT              unimplemented
+           TASKFILE_P_OUT_DMA          unimplemented
+           TASKFILE_P_OUT_DMAQ         unimplemented
+           ===================        ========================================
+
+         The req_cmd field classifies the command type.  It may be
+         one of:
+
+           ========================    =======================================
+           IDE_DRIVE_TASK_NO_DATA
+           IDE_DRIVE_TASK_SET_XFER     unimplemented
+           IDE_DRIVE_TASK_IN
+           IDE_DRIVE_TASK_OUT          unimplemented
+           IDE_DRIVE_TASK_RAW_WRITE
+           ========================    =======================================
+
+         [6] Do not access {in|out}_flags->all except for resetting
+         all the bits.  Always access individual bit fields.  ->all
+         value will flip depending on endianness.  For the same
+         reason, do not use IDE_{TASKFILE|HOB}_STD_{OUT|IN}_FLAGS
+         constants defined in hdreg.h.
+
+
+
+HDIO_DRIVE_CMD
+       execute a special drive command
+
+
+       Note:  If you don't have a copy of the ANSI ATA specification
+       handy, you should probably ignore this ioctl.
+
+       usage::
+
+         u8 args[4+XFER_SIZE];
+
+         ...
+         ioctl(fd, HDIO_DRIVE_CMD, args);
+
+       inputs:
+           Commands other than WIN_SMART:
+
+           =======     =======
+           args[0]     COMMAND
+           args[1]     NSECTOR
+           args[2]     FEATURE
+           args[3]     NSECTOR
+           =======     =======
+
+           WIN_SMART:
+
+           =======     =======
+           args[0]     COMMAND
+           args[1]     SECTOR
+           args[2]     FEATURE
+           args[3]     NSECTOR
+           =======     =======
+
+       outputs:
+               args[] buffer is filled with register values followed by any
+
+
+         data returned by the disk.
+
+           ========    ====================================================
+           args[0]     status
+           args[1]     error
+           args[2]     NSECTOR
+           args[3]     undefined
+           args[4+]    NSECTOR * 512 bytes of data returned by the command.
+           ========    ====================================================
+
+       error returns:
+         - EACCES      Access denied:  requires CAP_SYS_RAWIO
+         - ENOMEM      Unable to allocate memory for task
+         - EIO         Drive reports error
+
+       notes:
+
+         [1] For commands other than WIN_SMART, args[1] should equal
+         args[3].  SECTOR, LCYL and HCYL are undefined.  For
+         WIN_SMART, 0x4f and 0xc2 are loaded into LCYL and HCYL
+         respectively.  In both cases SELECT will contain the default
+         value for the drive.  Please refer to HDIO_DRIVE_TASKFILE
+         notes for the default value of SELECT.
+
+         [2] If NSECTOR value is greater than zero and the drive sets
+         DRQ when interrupting for the command, NSECTOR * 512 bytes
+         are read from the device into the area following NSECTOR.
+         In the above example, the area would be
+         args[4..4+XFER_SIZE].  16bit PIO is used regardless of
+         HDIO_SET_32BIT setting.
+
+         [3] If COMMAND == WIN_SETFEATURES && FEATURE == SETFEATURES_XFER
+         && NSECTOR >= XFER_SW_DMA_0 && the drive supports any DMA
+         mode, IDE driver will try to tune the transfer mode of the
+         drive accordingly.
+
+
+
+HDIO_DRIVE_TASK
+       execute task and special drive command
+
+
+       Note:  If you don't have a copy of the ANSI ATA specification
+       handy, you should probably ignore this ioctl.
+
+       usage::
+
+         u8 args[7];
+
+         ...
+         ioctl(fd, HDIO_DRIVE_TASK, args);
+
+       inputs:
+           Taskfile register values:
+
+           =======     =======
+           args[0]     COMMAND
+           args[1]     FEATURE
+           args[2]     NSECTOR
+           args[3]     SECTOR
+           args[4]     LCYL
+           args[5]     HCYL
+           args[6]     SELECT
+           =======     =======
+
+       outputs:
+           Taskfile register values:
+
+
+           =======     =======
+           args[0]     status
+           args[1]     error
+           args[2]     NSECTOR
+           args[3]     SECTOR
+           args[4]     LCYL
+           args[5]     HCYL
+           args[6]     SELECT
+           =======     =======
+
+       error returns:
+         - EACCES      Access denied:  requires CAP_SYS_RAWIO
+         - ENOMEM      Unable to allocate memory for task
+         - ENOMSG      Device is not a disk drive.
+         - EIO         Drive failed the command.
+
+       notes:
+
+         [1] DEV bit (0x10) of SELECT register is ignored and the
+         appropriate value for the drive is used.  All other bits
+         are used unaltered.
+
+
+
+HDIO_DRIVE_CMD_AEB
+       HDIO_DRIVE_TASK
+
+
+       Not implemented, as of 2.6.8.1
+
+
+
+HDIO_SET_32BIT
+       change io_32bit flags
+
+
+       usage::
+
+         int val;
+
+         ioctl(fd, HDIO_SET_32BIT, val);
+
+       inputs:
+               New value for io_32bit flag
+
+
+
+       outputs:
+               none
+
+
+
+       error return:
+         - EINVAL      (bdev != bdev->bd_contains) (not sure what this means)
+         - 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      (bdev != bdev->bd_contains) (not sure what this means)
+         - 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      (bdev != bdev->bd_contains) (not sure what this means)
+         - 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      (bdev != bdev->bd_contains) (not sure what this means)
+         - 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      (bdev != bdev->bd_contains) (not sure what this means)
+         - 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      (bdev != bdev->bd_contains) (not sure what this means)
+         - 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      (bdev != bdev->bd_contains) (not sure what this means)
+         - 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      (bdev != bdev->bd_contains) (not sure what this means)
+         - 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
diff --git a/Documentation/ioctl/hdio.txt b/Documentation/ioctl/hdio.txt
deleted file mode 100644 (file)
index 18eb98c..0000000
+++ /dev/null
@@ -1,1071 +0,0 @@
-               Summary of HDIO_ ioctl calls.
-               ============================
-
-               Edward A. Falk <efalk@google.com>
-
-               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
-
-ioctl values are listed in <linux/hdreg.h>.  As of this writing, they
-are as follows:
-
-    ioctls that pass argument pointers to user space:
-
-       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
-
-
-The information that follows was determined from reading kernel source
-code.  It is likely that some corrections will be made over time.
-
-
-
-
-
-
-
-General:
-
-       Unless otherwise specified, all ioctl calls return 0 on success
-       and -1 with errno set to an appropriate value on error.
-
-       Unless otherwise specified, all ioctl calls return -1 and set
-       errno to EFAULT on a failed attempt to copy data to or from user
-       address space.
-
-       Unless otherwise specified, all data structures and constants
-       are defined in <linux/hdreg.h>
-
-
-
-HDIO_GETGEO                    get device geometry
-
-       usage:
-
-         struct hd_geometry geom;
-         ioctl(fd, HDIO_GETGEO, &geom);
-
-
-       inputs:         none
-
-       outputs:
-
-         hd_geometry structure containing:
-
-           heads       number of heads
-           sectors     number of sectors/track
-           cylinders   number of cylinders, mod 65536
-           start       starting sector of this partition.
-
-
-       error returns:
-         EINVAL        if the device is not a disk drive or floppy drive,
-                       or if the user passes a null pointer
-
-
-       notes:
-
-         Not particularly useful with modern disk drives, whose geometry
-         is a polite fiction anyway.  Modern drives are addressed
-         purely by sector number nowadays (lba addressing), and the
-         drive geometry is an abstraction which is actually subject
-         to change.  Currently (as of Nov 2004), the geometry values
-         are the "bios" values -- presumably the values the drive had
-         when Linux first booted.
-
-         In addition, the cylinders field of the hd_geometry is an
-         unsigned short, meaning that on most architectures, this
-         ioctl will not return a meaningful value on drives with more
-         than 65535 tracks.
-
-         The start field is unsigned long, meaning that it will not
-         contain a meaningful value for disks over 219 Gb in size.
-
-
-
-
-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        (bdev != bdev->bd_contains) (not sure what this means)
-         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        (bdev != bdev->bd_contains) (not sure what this means)
-         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        (bdev != bdev->bd_contains) (not sure what this means)
-         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        (bdev != bdev->bd_contains) (not sure what this means)
-         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
-
-       usage:
-
-         int state;
-         ...
-         ioctl(fd, HDIO_SCAN_HWIF, state);
-
-       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
-
-
-
-
-HDIO_TRISTATE_HWIF             execute a channel tristate
-
-       Not implemented, as of 2.6.8.1.  See HDIO_SET_BUSSTATE
-
-
-
-HDIO_DRIVE_RESET               execute a device reset
-
-       usage:
-
-         int args[3]
-         ...
-         ioctl(fd, HDIO_DRIVE_RESET, args);
-
-       inputs:         none
-
-       outputs:        none
-
-       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.
-
-
-
-HDIO_DRIVE_TASKFILE            execute raw taskfile
-
-       Note:  If you don't have a copy of the ANSI ATA specification
-       handy, you should probably ignore this ioctl.
-
-       Execute an ATA disk command directly by writing the "taskfile"
-       registers of the drive.  Requires ADMIN and RAWIO access
-       privileges.
-
-       usage:
-
-         struct {
-           ide_task_request_t req_task;
-           u8 outbuf[OUTPUT_SIZE];
-           u8 inbuf[INPUT_SIZE];
-         } task;
-         memset(&task.req_task, 0, sizeof(task.req_task));
-         task.req_task.out_size = sizeof(task.outbuf);
-         task.req_task.in_size = sizeof(task.inbuf);
-         ...
-         ioctl(fd, HDIO_DRIVE_TASKFILE, &task);
-         ...
-
-       inputs:
-
-         (See below for details on memory area passed to ioctl.)
-
-         io_ports[8]   values to be written to taskfile registers
-         hob_ports[8]  high-order bytes, for extended commands.
-         out_flags     flags indicating which registers are valid
-         in_flags      flags indicating which registers should be returned
-         data_phase    see below
-         req_cmd       command type to be executed
-         out_size      size of output buffer
-         outbuf        buffer of data to be transmitted to disk
-         inbuf         buffer of data to be received from disk (see [1])
-
-       outputs:
-
-         io_ports[]    values returned in the taskfile registers
-         hob_ports[]   high-order bytes, for extended commands.
-         out_flags     flags indicating which registers are valid (see [2])
-         in_flags      flags indicating which registers should be returned
-         outbuf        buffer of data to be transmitted to disk (see [1])
-         inbuf         buffer of data to be received from disk
-
-       error returns:
-         EACCES        CAP_SYS_ADMIN or CAP_SYS_RAWIO privilege not set.
-         ENOMSG        Device is not a disk drive.
-         ENOMEM        Unable to allocate memory for task
-         EFAULT        req_cmd == TASKFILE_IN_OUT (not implemented as of 2.6.8)
-         EPERM         req_cmd == TASKFILE_MULTI_OUT and drive
-                       multi-count not yet set.
-         EIO           Drive failed the command.
-
-       notes:
-
-         [1] READ THE FOLLOWING NOTES *CAREFULLY*.  THIS IOCTL IS
-         FULL OF GOTCHAS.  Extreme caution should be used with using
-         this ioctl.  A mistake can easily corrupt data or hang the
-         system.
-
-         [2] Both the input and output buffers are copied from the
-         user and written back to the user, even when not used.
-
-         [3] If one or more bits are set in out_flags and in_flags is
-         zero, the following values are used for in_flags.all and
-         written back into in_flags on completion.
-
-          * IDE_TASKFILE_STD_IN_FLAGS | (IDE_HOB_STD_IN_FLAGS << 8)
-            if LBA48 addressing is enabled for the drive
-          * IDE_TASKFILE_STD_IN_FLAGS
-            if CHS/LBA28
-
-         The association between in_flags.all and each enable
-         bitfield flips depending on endianness; fortunately, TASKFILE
-         only uses inflags.b.data bit and ignores all other bits.
-         The end result is that, on any endian machines, it has no
-         effect other than modifying in_flags on completion.
-
-         [4] The default value of SELECT is (0xa0|DEV_bit|LBA_bit)
-         except for four drives per port chipsets.  For four drives
-         per port chipsets, it's (0xa0|DEV_bit|LBA_bit) for the first
-         pair and (0x80|DEV_bit|LBA_bit) for the second pair.
-
-         [5] The argument to the ioctl is a pointer to a region of
-         memory containing a ide_task_request_t structure, followed
-         by an optional buffer of data to be transmitted to the
-         drive, followed by an optional buffer to receive data from
-         the drive.
-
-         Command is passed to the disk drive via the ide_task_request_t
-         structure, which contains these fields:
-
-           io_ports[8]         values for the taskfile registers
-           hob_ports[8]        high-order bytes, for extended commands
-           out_flags           flags indicating which entries in the
-                               io_ports[] and hob_ports[] arrays
-                               contain valid values.  Type ide_reg_valid_t.
-           in_flags            flags indicating which entries in the
-                               io_ports[] and hob_ports[] arrays
-                               are expected to contain valid values
-                               on return.
-           data_phase          See below
-           req_cmd             Command type, see below
-           out_size            output (user->drive) buffer size, bytes
-           in_size             input (drive->user) buffer size, bytes
-
-         When out_flags is zero, the following registers are loaded.
-
-           HOB_FEATURE         If the drive supports LBA48
-           HOB_NSECTOR         If the drive supports LBA48
-           HOB_SECTOR          If the drive supports LBA48
-           HOB_LCYL            If the drive supports LBA48
-           HOB_HCYL            If the drive supports LBA48
-           FEATURE
-           NSECTOR
-           SECTOR
-           LCYL
-           HCYL
-           SELECT              First, masked with 0xE0 if LBA48, 0xEF
-                               otherwise; then, or'ed with the default
-                               value of SELECT.
-
-         If any bit in out_flags is set, the following registers are loaded.
-
-           HOB_DATA            If out_flags.b.data is set.  HOB_DATA will
-                               travel on DD8-DD15 on little endian machines
-                               and on DD0-DD7 on big endian machines.
-           DATA                If out_flags.b.data is set.  DATA will
-                               travel on DD0-DD7 on little endian machines
-                               and on DD8-DD15 on big endian machines.
-           HOB_NSECTOR         If out_flags.b.nsector_hob is set
-           HOB_SECTOR          If out_flags.b.sector_hob is set
-           HOB_LCYL            If out_flags.b.lcyl_hob is set
-           HOB_HCYL            If out_flags.b.hcyl_hob is set
-           FEATURE             If out_flags.b.feature is set
-           NSECTOR             If out_flags.b.nsector is set
-           SECTOR              If out_flags.b.sector is set
-           LCYL                If out_flags.b.lcyl is set
-           HCYL                If out_flags.b.hcyl is set
-           SELECT              Or'ed with the default value of SELECT and
-                               loaded regardless of out_flags.b.select.
-
-         Taskfile registers are read back from the drive into
-         {io|hob}_ports[] after the command completes iff one of the
-         following conditions is met; otherwise, the original values
-         will be written back, unchanged.
-
-           1. The drive fails the command (EIO).
-           2. One or more than one bits are set in out_flags.
-           3. The requested data_phase is TASKFILE_NO_DATA.
-
-           HOB_DATA            If in_flags.b.data is set.  It will contain
-                               DD8-DD15 on little endian machines and
-                               DD0-DD7 on big endian machines.
-           DATA                If in_flags.b.data is set.  It will contain
-                               DD0-DD7 on little endian machines and
-                               DD8-DD15 on big endian machines.
-           HOB_FEATURE         If the drive supports LBA48
-           HOB_NSECTOR         If the drive supports LBA48
-           HOB_SECTOR          If the drive supports LBA48
-           HOB_LCYL            If the drive supports LBA48
-           HOB_HCYL            If the drive supports LBA48
-           NSECTOR
-           SECTOR
-           LCYL
-           HCYL
-
-         The data_phase field describes the data transfer to be
-         performed.  Value is one of:
-
-           TASKFILE_IN
-           TASKFILE_MULTI_IN
-           TASKFILE_OUT
-           TASKFILE_MULTI_OUT
-           TASKFILE_IN_OUT
-           TASKFILE_IN_DMA
-           TASKFILE_IN_DMAQ            == IN_DMA (queueing not supported)
-           TASKFILE_OUT_DMA
-           TASKFILE_OUT_DMAQ           == OUT_DMA (queueing not supported)
-           TASKFILE_P_IN               unimplemented
-           TASKFILE_P_IN_DMA           unimplemented
-           TASKFILE_P_IN_DMAQ          unimplemented
-           TASKFILE_P_OUT              unimplemented
-           TASKFILE_P_OUT_DMA          unimplemented
-           TASKFILE_P_OUT_DMAQ         unimplemented
-
-         The req_cmd field classifies the command type.  It may be
-         one of:
-
-           IDE_DRIVE_TASK_NO_DATA
-           IDE_DRIVE_TASK_SET_XFER     unimplemented
-           IDE_DRIVE_TASK_IN
-           IDE_DRIVE_TASK_OUT          unimplemented
-           IDE_DRIVE_TASK_RAW_WRITE
-
-         [6] Do not access {in|out}_flags->all except for resetting
-         all the bits.  Always access individual bit fields.  ->all
-         value will flip depending on endianness.  For the same
-         reason, do not use IDE_{TASKFILE|HOB}_STD_{OUT|IN}_FLAGS
-         constants defined in hdreg.h.
-
-
-
-HDIO_DRIVE_CMD                 execute a special drive command
-
-       Note:  If you don't have a copy of the ANSI ATA specification
-       handy, you should probably ignore this ioctl.
-
-       usage:
-
-         u8 args[4+XFER_SIZE];
-         ...
-         ioctl(fd, HDIO_DRIVE_CMD, args);
-
-       inputs:
-
-         Commands other than WIN_SMART
-           args[0]     COMMAND
-           args[1]     NSECTOR
-           args[2]     FEATURE
-           args[3]     NSECTOR
-
-         WIN_SMART
-           args[0]     COMMAND
-           args[1]     SECTOR
-           args[2]     FEATURE
-           args[3]     NSECTOR
-
-       outputs:
-
-         args[] buffer is filled with register values followed by any
-         data returned by the disk.
-           args[0]     status
-           args[1]     error
-           args[2]     NSECTOR
-           args[3]     undefined
-           args[4+]    NSECTOR * 512 bytes of data returned by the command.
-
-       error returns:
-         EACCES        Access denied:  requires CAP_SYS_RAWIO
-         ENOMEM        Unable to allocate memory for task
-         EIO           Drive reports error
-
-       notes:
-
-         [1] For commands other than WIN_SMART, args[1] should equal
-         args[3].  SECTOR, LCYL and HCYL are undefined.  For
-         WIN_SMART, 0x4f and 0xc2 are loaded into LCYL and HCYL
-         respectively.  In both cases SELECT will contain the default
-         value for the drive.  Please refer to HDIO_DRIVE_TASKFILE
-         notes for the default value of SELECT.
-
-         [2] If NSECTOR value is greater than zero and the drive sets
-         DRQ when interrupting for the command, NSECTOR * 512 bytes
-         are read from the device into the area following NSECTOR.
-         In the above example, the area would be
-         args[4..4+XFER_SIZE].  16bit PIO is used regardless of
-         HDIO_SET_32BIT setting.
-
-         [3] If COMMAND == WIN_SETFEATURES && FEATURE == SETFEATURES_XFER
-         && NSECTOR >= XFER_SW_DMA_0 && the drive supports any DMA
-         mode, IDE driver will try to tune the transfer mode of the
-         drive accordingly.
-
-
-
-HDIO_DRIVE_TASK                        execute task and special drive command
-
-       Note:  If you don't have a copy of the ANSI ATA specification
-       handy, you should probably ignore this ioctl.
-
-       usage:
-
-         u8 args[7];
-         ...
-         ioctl(fd, HDIO_DRIVE_TASK, args);
-
-       inputs:
-
-         Taskfile register values:
-           args[0]     COMMAND
-           args[1]     FEATURE
-           args[2]     NSECTOR
-           args[3]     SECTOR
-           args[4]     LCYL
-           args[5]     HCYL
-           args[6]     SELECT
-
-       outputs:
-
-         Taskfile register values:
-           args[0]     status
-           args[1]     error
-           args[2]     NSECTOR
-           args[3]     SECTOR
-           args[4]     LCYL
-           args[5]     HCYL
-           args[6]     SELECT
-
-       error returns:
-         EACCES        Access denied:  requires CAP_SYS_RAWIO
-         ENOMEM        Unable to allocate memory for task
-         ENOMSG        Device is not a disk drive.
-         EIO           Drive failed the command.
-
-       notes:
-
-         [1] DEV bit (0x10) of SELECT register is ignored and the
-         appropriate value for the drive is used.  All other bits
-         are used unaltered.
-
-
-
-HDIO_DRIVE_CMD_AEB             HDIO_DRIVE_TASK
-
-       Not implemented, as of 2.6.8.1
-
-
-
-HDIO_SET_32BIT                 change io_32bit flags
-
-       usage:
-
-         int val;
-         ioctl(fd, HDIO_SET_32BIT, val);
-
-       inputs:
-         New value for io_32bit flag
-
-       outputs:        none
-
-       error return:
-         EINVAL        (bdev != bdev->bd_contains) (not sure what this means)
-         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        (bdev != bdev->bd_contains) (not sure what this means)
-         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        (bdev != bdev->bd_contains) (not sure what this means)
-         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        (bdev != bdev->bd_contains) (not sure what this means)
-         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        (bdev != bdev->bd_contains) (not sure what this means)
-         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        (bdev != bdev->bd_contains) (not sure what this means)
-         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        (bdev != bdev->bd_contains) (not sure what this means)
-         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        (bdev != bdev->bd_contains) (not sure what this means)
-         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
-
-
diff --git a/Documentation/ioctl/index.rst b/Documentation/ioctl/index.rst
new file mode 100644 (file)
index 0000000..0f0a857
--- /dev/null
@@ -0,0 +1,16 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+======
+IOCTLs
+======
+
+.. toctree::
+   :maxdepth: 1
+
+   ioctl-number
+
+   botching-up-ioctls
+   ioctl-decoding
+
+   cdrom
+   hdio
diff --git a/Documentation/ioctl/ioctl-decoding.rst b/Documentation/ioctl/ioctl-decoding.rst
new file mode 100644 (file)
index 0000000..380d6bb
--- /dev/null
@@ -0,0 +1,31 @@
+==============================
+Decoding an IOCTL Magic Number
+==============================
+
+To decode a hex IOCTL code:
+
+Most architectures use this generic format, but check
+include/ARCH/ioctl.h for specifics, e.g. powerpc
+uses 3 bits to encode read/write and 13 bits for size.
+
+ ====== ==================================
+ bits   meaning
+ ====== ==================================
+ 31-30 00 - no parameters: uses _IO macro
+       10 - read: _IOR
+       01 - write: _IOW
+       11 - read/write: _IOWR
+
+ 29-16 size of arguments
+
+ 15-8  ascii character supposedly
+       unique to each driver
+
+ 7-0   function #
+ ====== ==================================
+
+
+So for example 0x82187201 is a read with arg length of 0x218,
+character 'r' function 1. Grepping the source reveals this is::
+
+       #define VFAT_IOCTL_READDIR_BOTH         _IOR('r', 1, struct dirent [2])
diff --git a/Documentation/ioctl/ioctl-decoding.txt b/Documentation/ioctl/ioctl-decoding.txt
deleted file mode 100644 (file)
index e35efb0..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-To decode a hex IOCTL code:
-
-Most architectures use this generic format, but check
-include/ARCH/ioctl.h for specifics, e.g. powerpc
-uses 3 bits to encode read/write and 13 bits for size.
-
- bits    meaning
- 31-30 00 - no parameters: uses _IO macro
-       10 - read: _IOR
-       01 - write: _IOW
-       11 - read/write: _IOWR
-
- 29-16 size of arguments
-
- 15-8  ascii character supposedly
-       unique to each driver
-
- 7-0   function #
-
-
-So for example 0x82187201 is a read with arg length of 0x218,
-character 'r' function 1. Grepping the source reveals this is:
-
-#define VFAT_IOCTL_READDIR_BOTH         _IOR('r', 1, struct dirent [2])
diff --git a/Documentation/ioctl/ioctl-number.rst b/Documentation/ioctl/ioctl-number.rst
new file mode 100644 (file)
index 0000000..7f8dcae
--- /dev/null
@@ -0,0 +1,361 @@
+=============
+Ioctl Numbers
+=============
+
+19 October 1999
+
+Michael Elizabeth Chastain
+<mec@shout.net>
+
+If you are adding new ioctl's to the kernel, you should use the _IO
+macros defined in <linux/ioctl.h>:
+
+    ====== == ============================================
+    _IO    an ioctl with no parameters
+    _IOW   an ioctl with write parameters (copy_from_user)
+    _IOR   an ioctl with read parameters  (copy_to_user)
+    _IOWR  an ioctl with both write and read parameters.
+    ====== == ============================================
+
+'Write' and 'read' are from the user's point of view, just like the
+system calls 'write' and 'read'.  For example, a SET_FOO ioctl would
+be _IOW, although the kernel would actually read data from user space;
+a GET_FOO ioctl would be _IOR, although the kernel would actually write
+data to user space.
+
+The first argument to _IO, _IOW, _IOR, or _IOWR is an identifying letter
+or number from the table below.  Because of the large number of drivers,
+many drivers share a partial letter with other drivers.
+
+If you are writing a driver for a new device and need a letter, pick an
+unused block with enough room for expansion: 32 to 256 ioctl commands.
+You can register the block by patching this file and submitting the
+patch to Linus Torvalds.  Or you can e-mail me at <mec@shout.net> and
+I'll register one for you.
+
+The second argument to _IO, _IOW, _IOR, or _IOWR is a sequence number
+to distinguish ioctls from each other.  The third argument to _IOW,
+_IOR, or _IOWR is the type of the data going into the kernel or coming
+out of the kernel (e.g.  'int' or 'struct foo').  NOTE!  Do NOT use
+sizeof(arg) as the third argument as this results in your ioctl thinking
+it passes an argument of type size_t.
+
+Some devices use their major number as the identifier; this is OK, as
+long as it is unique.  Some devices are irregular and don't follow any
+convention at all.
+
+Following this convention is good because:
+
+(1) Keeping the ioctl's globally unique helps error checking:
+    if a program calls an ioctl on the wrong device, it will get an
+    error rather than some unexpected behaviour.
+
+(2) The 'strace' build procedure automatically finds ioctl numbers
+    defined with _IO, _IOW, _IOR, or _IOWR.
+
+(3) 'strace' can decode numbers back into useful names when the
+    numbers are unique.
+
+(4) People looking for ioctls can grep for them more easily when
+    this convention is used to define the ioctl numbers.
+
+(5) When following the convention, the driver code can use generic
+    code to copy the parameters between user and kernel space.
+
+This table lists ioctls visible from user land for Linux/x86.  It contains
+most drivers up to 2.6.31, but I know I am missing some.  There has been
+no attempt to list non-X86 architectures or ioctls from drivers/staging/.
+
+====  =====  ======================================================= ================================================================
+Code  Seq#    Include File                                           Comments
+      (hex)
+====  =====  ======================================================= ================================================================
+0x00  00-1F  linux/fs.h                                              conflict!
+0x00  00-1F  scsi/scsi_ioctl.h                                       conflict!
+0x00  00-1F  linux/fb.h                                              conflict!
+0x00  00-1F  linux/wavefront.h                                       conflict!
+0x02  all    linux/fd.h
+0x03  all    linux/hdreg.h
+0x04  D2-DC  linux/umsdos_fs.h                                       Dead since 2.6.11, but don't reuse these.
+0x06  all    linux/lp.h
+0x09  all    linux/raid/md_u.h
+0x10  00-0F  drivers/char/s390/vmcp.h
+0x10  10-1F  arch/s390/include/uapi/sclp_ctl.h
+0x10  20-2F  arch/s390/include/uapi/asm/hypfs.h
+0x12  all    linux/fs.h
+             linux/blkpg.h
+0x1b  all                                                            InfiniBand Subsystem
+                                                                     <http://infiniband.sourceforge.net/>
+0x20  all    drivers/cdrom/cm206.h
+0x22  all    scsi/sg.h
+'!'   00-1F  uapi/linux/seccomp.h
+'#'   00-3F                                                          IEEE 1394 Subsystem
+                                                                     Block for the entire subsystem
+'$'   00-0F  linux/perf_counter.h, linux/perf_event.h
+'%'   00-0F  include/uapi/linux/stm.h                                System Trace Module subsystem
+                                                                     <mailto:alexander.shishkin@linux.intel.com>
+'&'   00-07  drivers/firewire/nosy-user.h
+'1'   00-1F  linux/timepps.h                                         PPS kit from Ulrich Windl
+                                                                     <ftp://ftp.de.kernel.org/pub/linux/daemons/ntp/PPS/>
+'2'   01-04  linux/i2o.h
+'3'   00-0F  drivers/s390/char/raw3270.h                             conflict!
+'3'   00-1F  linux/suspend_ioctls.h,                                 conflict!
+             kernel/power/user.c
+'8'   all                                                            SNP8023 advanced NIC card
+                                                                     <mailto:mcr@solidum.com>
+';'   64-7F  linux/vfio.h
+'@'   00-0F  linux/radeonfb.h                                        conflict!
+'@'   00-0F  drivers/video/aty/aty128fb.c                            conflict!
+'A'   00-1F  linux/apm_bios.h                                        conflict!
+'A'   00-0F  linux/agpgart.h,                                        conflict!
+             drivers/char/agp/compat_ioctl.h
+'A'   00-7F  sound/asound.h                                          conflict!
+'B'   00-1F  linux/cciss_ioctl.h                                     conflict!
+'B'   00-0F  include/linux/pmu.h                                     conflict!
+'B'   C0-FF  advanced bbus                                           <mailto:maassen@uni-freiburg.de>
+'C'   all    linux/soundcard.h                                       conflict!
+'C'   01-2F  linux/capi.h                                            conflict!
+'C'   F0-FF  drivers/net/wan/cosa.h                                  conflict!
+'D'   all    arch/s390/include/asm/dasd.h
+'D'   40-5F  drivers/scsi/dpt/dtpi_ioctl.h
+'D'   05     drivers/scsi/pmcraid.h
+'E'   all    linux/input.h                                           conflict!
+'E'   00-0F  xen/evtchn.h                                            conflict!
+'F'   all    linux/fb.h                                              conflict!
+'F'   01-02  drivers/scsi/pmcraid.h                                  conflict!
+'F'   20     drivers/video/fsl-diu-fb.h                              conflict!
+'F'   20     drivers/video/intelfb/intelfb.h                         conflict!
+'F'   20     linux/ivtvfb.h                                          conflict!
+'F'   20     linux/matroxfb.h                                        conflict!
+'F'   20     drivers/video/aty/atyfb_base.c                          conflict!
+'F'   00-0F  video/da8xx-fb.h                                        conflict!
+'F'   80-8F  linux/arcfb.h                                           conflict!
+'F'   DD     video/sstfb.h                                           conflict!
+'G'   00-3F  drivers/misc/sgi-gru/grulib.h                           conflict!
+'G'   00-0F  linux/gigaset_dev.h                                     conflict!
+'H'   00-7F  linux/hiddev.h                                          conflict!
+'H'   00-0F  linux/hidraw.h                                          conflict!
+'H'   01     linux/mei.h                                             conflict!
+'H'   02     linux/mei.h                                             conflict!
+'H'   03     linux/mei.h                                             conflict!
+'H'   00-0F  sound/asound.h                                          conflict!
+'H'   20-40  sound/asound_fm.h                                       conflict!
+'H'   80-8F  sound/sfnt_info.h                                       conflict!
+'H'   10-8F  sound/emu10k1.h                                         conflict!
+'H'   10-1F  sound/sb16_csp.h                                        conflict!
+'H'   10-1F  sound/hda_hwdep.h                                       conflict!
+'H'   40-4F  sound/hdspm.h                                           conflict!
+'H'   40-4F  sound/hdsp.h                                            conflict!
+'H'   90     sound/usb/usx2y/usb_stream.h
+'H'   A0     uapi/linux/usb/cdc-wdm.h
+'H'   C0-F0  net/bluetooth/hci.h                                     conflict!
+'H'   C0-DF  net/bluetooth/hidp/hidp.h                               conflict!
+'H'   C0-DF  net/bluetooth/cmtp/cmtp.h                               conflict!
+'H'   C0-DF  net/bluetooth/bnep/bnep.h                               conflict!
+'H'   F1     linux/hid-roccat.h                                      <mailto:erazor_de@users.sourceforge.net>
+'H'   F8-FA  sound/firewire.h
+'I'   all    linux/isdn.h                                            conflict!
+'I'   00-0F  drivers/isdn/divert/isdn_divert.h                       conflict!
+'I'   40-4F  linux/mISDNif.h                                         conflict!
+'J'   00-1F  drivers/scsi/gdth_ioctl.h
+'K'   all    linux/kd.h
+'L'   00-1F  linux/loop.h                                            conflict!
+'L'   10-1F  drivers/scsi/mpt3sas/mpt3sas_ctl.h                      conflict!
+'L'   20-2F  linux/lightnvm.h
+'L'   E0-FF  linux/ppdd.h                                            encrypted disk device driver
+                                                                     <http://linux01.gwdg.de/~alatham/ppdd.html>
+'M'   all    linux/soundcard.h                                       conflict!
+'M'   01-16  mtd/mtd-abi.h                                           conflict!
+      and    drivers/mtd/mtdchar.c
+'M'   01-03  drivers/scsi/megaraid/megaraid_sas.h
+'M'   00-0F  drivers/video/fsl-diu-fb.h                              conflict!
+'N'   00-1F  drivers/usb/scanner.h
+'N'   40-7F  drivers/block/nvme.c
+'O'   00-06  mtd/ubi-user.h                                          UBI
+'P'   all    linux/soundcard.h                                       conflict!
+'P'   60-6F  sound/sscape_ioctl.h                                    conflict!
+'P'   00-0F  drivers/usb/class/usblp.c                               conflict!
+'P'   01-09  drivers/misc/pci_endpoint_test.c                        conflict!
+'Q'   all    linux/soundcard.h
+'R'   00-1F  linux/random.h                                          conflict!
+'R'   01     linux/rfkill.h                                          conflict!
+'R'   C0-DF  net/bluetooth/rfcomm.h
+'S'   all    linux/cdrom.h                                           conflict!
+'S'   80-81  scsi/scsi_ioctl.h                                       conflict!
+'S'   82-FF  scsi/scsi.h                                             conflict!
+'S'   00-7F  sound/asequencer.h                                      conflict!
+'T'   all    linux/soundcard.h                                       conflict!
+'T'   00-AF  sound/asound.h                                          conflict!
+'T'   all    arch/x86/include/asm/ioctls.h                           conflict!
+'T'   C0-DF  linux/if_tun.h                                          conflict!
+'U'   all    sound/asound.h                                          conflict!
+'U'   00-CF  linux/uinput.h                                          conflict!
+'U'   00-EF  linux/usbdevice_fs.h
+'U'   C0-CF  drivers/bluetooth/hci_uart.h
+'V'   all    linux/vt.h                                              conflict!
+'V'   all    linux/videodev2.h                                       conflict!
+'V'   C0     linux/ivtvfb.h                                          conflict!
+'V'   C0     linux/ivtv.h                                            conflict!
+'V'   C0     media/davinci/vpfe_capture.h                            conflict!
+'V'   C0     media/si4713.h                                          conflict!
+'W'   00-1F  linux/watchdog.h                                        conflict!
+'W'   00-1F  linux/wanrouter.h                                       conflict! (pre 3.9)
+'W'   00-3F  sound/asound.h                                          conflict!
+'W'   40-5F  drivers/pci/switch/switchtec.c
+'X'   all    fs/xfs/xfs_fs.h,                                        conflict!
+             fs/xfs/linux-2.6/xfs_ioctl32.h,
+             include/linux/falloc.h,
+             linux/fs.h,
+'X'   all    fs/ocfs2/ocfs_fs.h                                      conflict!
+'X'   01     linux/pktcdvd.h                                         conflict!
+'Y'   all    linux/cyclades.h
+'Z'   14-15  drivers/message/fusion/mptctl.h
+'['   00-3F  linux/usb/tmc.h                                         USB Test and Measurement Devices
+                                                                     <mailto:gregkh@linuxfoundation.org>
+'a'   all    linux/atm*.h, linux/sonet.h                             ATM on linux
+                                                                     <http://lrcwww.epfl.ch/>
+'a'   00-0F  drivers/crypto/qat/qat_common/adf_cfg_common.h          conflict! qat driver
+'b'   00-FF                                                          conflict! bit3 vme host bridge
+                                                                     <mailto:natalia@nikhefk.nikhef.nl>
+'c'   all    linux/cm4000_cs.h                                       conflict!
+'c'   00-7F  linux/comstats.h                                        conflict!
+'c'   00-7F  linux/coda.h                                            conflict!
+'c'   00-1F  linux/chio.h                                            conflict!
+'c'   80-9F  arch/s390/include/asm/chsc.h                            conflict!
+'c'   A0-AF  arch/x86/include/asm/msr.h conflict!
+'d'   00-FF  linux/char/drm/drm.h                                    conflict!
+'d'   02-40  pcmcia/ds.h                                             conflict!
+'d'   F0-FF  linux/digi1.h
+'e'   all    linux/digi1.h                                           conflict!
+'f'   00-1F  linux/ext2_fs.h                                         conflict!
+'f'   00-1F  linux/ext3_fs.h                                         conflict!
+'f'   00-0F  fs/jfs/jfs_dinode.h                                     conflict!
+'f'   00-0F  fs/ext4/ext4.h                                          conflict!
+'f'   00-0F  linux/fs.h                                              conflict!
+'f'   00-0F  fs/ocfs2/ocfs2_fs.h                                     conflict!
+'g'   00-0F  linux/usb/gadgetfs.h
+'g'   20-2F  linux/usb/g_printer.h
+'h'   00-7F                                                          conflict! Charon filesystem
+                                                                     <mailto:zapman@interlan.net>
+'h'   00-1F  linux/hpet.h                                            conflict!
+'h'   80-8F  fs/hfsplus/ioctl.c
+'i'   00-3F  linux/i2o-dev.h                                         conflict!
+'i'   0B-1F  linux/ipmi.h                                            conflict!
+'i'   80-8F  linux/i8k.h
+'j'   00-3F  linux/joystick.h
+'k'   00-0F  linux/spi/spidev.h                                      conflict!
+'k'   00-05  video/kyro.h                                            conflict!
+'k'   10-17  linux/hsi/hsi_char.h                                    HSI character device
+'l'   00-3F  linux/tcfs_fs.h                                         transparent cryptographic file system
+                                                                     <http://web.archive.org/web/%2A/http://mikonos.dia.unisa.it/tcfs>
+'l'   40-7F  linux/udf_fs_i.h                                        in development:
+                                                                     <http://sourceforge.net/projects/linux-udf/>
+'m'   00-09  linux/mmtimer.h                                         conflict!
+'m'   all    linux/mtio.h                                            conflict!
+'m'   all    linux/soundcard.h                                       conflict!
+'m'   all    linux/synclink.h                                        conflict!
+'m'   00-19  drivers/message/fusion/mptctl.h                         conflict!
+'m'   00     drivers/scsi/megaraid/megaraid_ioctl.h                  conflict!
+'n'   00-7F  linux/ncp_fs.h and fs/ncpfs/ioctl.c
+'n'   80-8F  uapi/linux/nilfs2_api.h                                 NILFS2
+'n'   E0-FF  linux/matroxfb.h                                        matroxfb
+'o'   00-1F  fs/ocfs2/ocfs2_fs.h                                     OCFS2
+'o'   00-03  mtd/ubi-user.h                                          conflict! (OCFS2 and UBI overlaps)
+'o'   40-41  mtd/ubi-user.h                                          UBI
+'o'   01-A1  `linux/dvb/*.h`                                         DVB
+'p'   00-0F  linux/phantom.h                                         conflict! (OpenHaptics needs this)
+'p'   00-1F  linux/rtc.h                                             conflict!
+'p'   00-3F  linux/mc146818rtc.h                                     conflict!
+'p'   40-7F  linux/nvram.h
+'p'   80-9F  linux/ppdev.h                                           user-space parport
+                                                                     <mailto:tim@cyberelk.net>
+'p'   A1-A5  linux/pps.h                                             LinuxPPS
+                                                                     <mailto:giometti@linux.it>
+'q'   00-1F  linux/serio.h
+'q'   80-FF  linux/telephony.h                                       Internet PhoneJACK, Internet LineJACK
+             linux/ixjuser.h                                         <http://web.archive.org/web/%2A/http://www.quicknet.net>
+'r'   00-1F  linux/msdos_fs.h and fs/fat/dir.c
+'s'   all    linux/cdk.h
+'t'   00-7F  linux/ppp-ioctl.h
+'t'   80-8F  linux/isdn_ppp.h
+'t'   90-91  linux/toshiba.h                                         toshiba and toshiba_acpi SMM
+'u'   00-1F  linux/smb_fs.h                                          gone
+'u'   20-3F  linux/uvcvideo.h                                        USB video class host driver
+'u'   40-4f  linux/udmabuf.h                                         userspace dma-buf misc device
+'v'   00-1F  linux/ext2_fs.h                                         conflict!
+'v'   00-1F  linux/fs.h                                              conflict!
+'v'   00-0F  linux/sonypi.h                                          conflict!
+'v'   00-0F  media/v4l2-subdev.h                                     conflict!
+'v'   C0-FF  linux/meye.h                                            conflict!
+'w'   all                                                            CERN SCI driver
+'y'   00-1F                                                          packet based user level communications
+                                                                     <mailto:zapman@interlan.net>
+'z'   00-3F                                                          CAN bus card conflict!
+                                                                     <mailto:hdstich@connectu.ulm.circular.de>
+'z'   40-7F                                                          CAN bus card conflict!
+                                                                     <mailto:oe@port.de>
+'z'   10-4F  drivers/s390/crypto/zcrypt_api.h                        conflict!
+'|'   00-7F  linux/media.h
+0x80  00-1F  linux/fb.h
+0x89  00-06  arch/x86/include/asm/sockios.h
+0x89  0B-DF  linux/sockios.h
+0x89  E0-EF  linux/sockios.h                                         SIOCPROTOPRIVATE range
+0x89  E0-EF  linux/dn.h                                              PROTOPRIVATE range
+0x89  F0-FF  linux/sockios.h                                         SIOCDEVPRIVATE range
+0x8B  all    linux/wireless.h
+0x8C  00-3F                                                          WiNRADiO driver
+                                                                     <http://www.winradio.com.au/>
+0x90  00     drivers/cdrom/sbpcd.h
+0x92  00-0F  drivers/usb/mon/mon_bin.c
+0x93  60-7F  linux/auto_fs.h
+0x94  all    fs/btrfs/ioctl.h                                        Btrfs filesystem
+             and linux/fs.h                                          some lifted to vfs/generic
+0x97  00-7F  fs/ceph/ioctl.h                                         Ceph file system
+0x99  00-0F                                                          537-Addinboard driver
+                                                                     <mailto:buk@buks.ipn.de>
+0xA0  all    linux/sdp/sdp.h                                         Industrial Device Project
+                                                                     <mailto:kenji@bitgate.com>
+0xA1  0      linux/vtpm_proxy.h                                      TPM Emulator Proxy Driver
+0xA3  80-8F                                                          Port ACL  in development:
+                                                                     <mailto:tlewis@mindspring.com>
+0xA3  90-9F  linux/dtlk.h
+0xA4  00-1F  uapi/linux/tee.h                                        Generic TEE subsystem
+0xAA  00-3F  linux/uapi/linux/userfaultfd.h
+0xAB  00-1F  linux/nbd.h
+0xAC  00-1F  linux/raw.h
+0xAD  00                                                             Netfilter device in development:
+                                                                     <mailto:rusty@rustcorp.com.au>
+0xAE  all    linux/kvm.h                                             Kernel-based Virtual Machine
+                                                                     <mailto:kvm@vger.kernel.org>
+0xAF  00-1F  linux/fsl_hypervisor.h                                  Freescale hypervisor
+0xB0  all                                                            RATIO devices in development:
+                                                                     <mailto:vgo@ratio.de>
+0xB1  00-1F                                                          PPPoX
+                                                                     <mailto:mostrows@styx.uwaterloo.ca>
+0xB3  00     linux/mmc/ioctl.h
+0xB4  00-0F  linux/gpio.h                                            <mailto:linux-gpio@vger.kernel.org>
+0xB5  00-0F  uapi/linux/rpmsg.h                                      <mailto:linux-remoteproc@vger.kernel.org>
+0xB6  all    linux/fpga-dfl.h
+0xC0  00-0F  linux/usb/iowarrior.h
+0xCA  00-0F  uapi/misc/cxl.h
+0xCA  10-2F  uapi/misc/ocxl.h
+0xCA  80-BF  uapi/scsi/cxlflash_ioctl.h
+0xCB  00-1F                                                          CBM serial IEC bus in development:
+                                                                     <mailto:michael.klein@puffin.lb.shuttle.de>
+0xCC  00-0F  drivers/misc/ibmvmc.h                                   pseries VMC driver
+0xCD  01     linux/reiserfs_fs.h
+0xCF  02     fs/cifs/ioctl.c
+0xDB  00-0F  drivers/char/mwave/mwavepub.h
+0xDD  00-3F                                                          ZFCP device driver see drivers/s390/scsi/
+                                                                     <mailto:aherrman@de.ibm.com>
+0xE5  00-3F  linux/fuse.h
+0xEC  00-01  drivers/platform/chrome/cros_ec_dev.h                   ChromeOS EC driver
+0xF3  00-3F  drivers/usb/misc/sisusbvga/sisusb.h                     sisfb (in development)
+                                                                     <mailto:thomas@winischhofer.net>
+0xF4  00-1F  video/mbxfb.h                                           mbxfb
+                                                                     <mailto:raph@8d.com>
+0xF6  all                                                            LTTng Linux Trace Toolkit Next Generation
+                                                                     <mailto:mathieu.desnoyers@efficios.com>
+0xFD  all    linux/dm-ioctl.h
+0xFE  all    linux/isst_if.h
+====  =====  ======================================================= ================================================================
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
deleted file mode 100644 (file)
index ab0b3f6..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-Ioctl Numbers
-19 October 1999
-Michael Elizabeth Chastain
-<mec@shout.net>
-
-If you are adding new ioctl's to the kernel, you should use the _IO
-macros defined in <linux/ioctl.h>:
-
-    _IO    an ioctl with no parameters
-    _IOW   an ioctl with write parameters (copy_from_user)
-    _IOR   an ioctl with read parameters  (copy_to_user)
-    _IOWR  an ioctl with both write and read parameters.
-
-'Write' and 'read' are from the user's point of view, just like the
-system calls 'write' and 'read'.  For example, a SET_FOO ioctl would
-be _IOW, although the kernel would actually read data from user space;
-a GET_FOO ioctl would be _IOR, although the kernel would actually write
-data to user space.
-
-The first argument to _IO, _IOW, _IOR, or _IOWR is an identifying letter
-or number from the table below.  Because of the large number of drivers,
-many drivers share a partial letter with other drivers.
-
-If you are writing a driver for a new device and need a letter, pick an
-unused block with enough room for expansion: 32 to 256 ioctl commands.
-You can register the block by patching this file and submitting the
-patch to Linus Torvalds.  Or you can e-mail me at <mec@shout.net> and
-I'll register one for you.
-
-The second argument to _IO, _IOW, _IOR, or _IOWR is a sequence number
-to distinguish ioctls from each other.  The third argument to _IOW,
-_IOR, or _IOWR is the type of the data going into the kernel or coming
-out of the kernel (e.g.  'int' or 'struct foo').  NOTE!  Do NOT use
-sizeof(arg) as the third argument as this results in your ioctl thinking
-it passes an argument of type size_t.
-
-Some devices use their major number as the identifier; this is OK, as
-long as it is unique.  Some devices are irregular and don't follow any
-convention at all.
-
-Following this convention is good because:
-
-(1) Keeping the ioctl's globally unique helps error checking:
-    if a program calls an ioctl on the wrong device, it will get an
-    error rather than some unexpected behaviour.
-
-(2) The 'strace' build procedure automatically finds ioctl numbers
-    defined with _IO, _IOW, _IOR, or _IOWR.
-
-(3) 'strace' can decode numbers back into useful names when the
-    numbers are unique.
-
-(4) People looking for ioctls can grep for them more easily when
-    this convention is used to define the ioctl numbers.
-
-(5) When following the convention, the driver code can use generic
-    code to copy the parameters between user and kernel space.
-
-This table lists ioctls visible from user land for Linux/x86.  It contains
-most drivers up to 2.6.31, but I know I am missing some.  There has been
-no attempt to list non-X86 architectures or ioctls from drivers/staging/.
-
-Code  Seq#(hex)        Include File            Comments
-========================================================
-0x00   00-1F   linux/fs.h              conflict!
-0x00   00-1F   scsi/scsi_ioctl.h       conflict!
-0x00   00-1F   linux/fb.h              conflict!
-0x00   00-1F   linux/wavefront.h       conflict!
-0x02   all     linux/fd.h
-0x03   all     linux/hdreg.h
-0x04   D2-DC   linux/umsdos_fs.h       Dead since 2.6.11, but don't reuse these.
-0x06   all     linux/lp.h
-0x09   all     linux/raid/md_u.h
-0x10   00-0F   drivers/char/s390/vmcp.h
-0x10   10-1F   arch/s390/include/uapi/sclp_ctl.h
-0x10   20-2F   arch/s390/include/uapi/asm/hypfs.h
-0x12   all     linux/fs.h
-               linux/blkpg.h
-0x1b   all     InfiniBand Subsystem    <http://infiniband.sourceforge.net/>
-0x20   all     drivers/cdrom/cm206.h
-0x22   all     scsi/sg.h
-'!'    00-1F   uapi/linux/seccomp.h
-'#'    00-3F   IEEE 1394 Subsystem     Block for the entire subsystem
-'$'    00-0F   linux/perf_counter.h, linux/perf_event.h
-'%'    00-0F   include/uapi/linux/stm.h
-                                       System Trace Module subsystem
-                                       <mailto:alexander.shishkin@linux.intel.com>
-'&'    00-07   drivers/firewire/nosy-user.h
-'1'    00-1F   <linux/timepps.h>       PPS kit from Ulrich Windl
-                                       <ftp://ftp.de.kernel.org/pub/linux/daemons/ntp/PPS/>
-'2'    01-04   linux/i2o.h
-'3'    00-0F   drivers/s390/char/raw3270.h     conflict!
-'3'    00-1F   linux/suspend_ioctls.h  conflict!
-               and kernel/power/user.c
-'8'    all                             SNP8023 advanced NIC card
-                                       <mailto:mcr@solidum.com>
-';'    64-7F   linux/vfio.h
-'@'    00-0F   linux/radeonfb.h        conflict!
-'@'    00-0F   drivers/video/aty/aty128fb.c    conflict!
-'A'    00-1F   linux/apm_bios.h        conflict!
-'A'    00-0F   linux/agpgart.h         conflict!
-               and drivers/char/agp/compat_ioctl.h
-'A'    00-7F   sound/asound.h          conflict!
-'B'    00-1F   linux/cciss_ioctl.h     conflict!
-'B'    00-0F   include/linux/pmu.h     conflict!
-'B'    C0-FF                           advanced bbus
-                                       <mailto:maassen@uni-freiburg.de>
-'C'    all     linux/soundcard.h       conflict!
-'C'    01-2F   linux/capi.h            conflict!
-'C'    F0-FF   drivers/net/wan/cosa.h  conflict!
-'D'    all     arch/s390/include/asm/dasd.h
-'D'    40-5F   drivers/scsi/dpt/dtpi_ioctl.h
-'D'    05      drivers/scsi/pmcraid.h
-'E'    all     linux/input.h           conflict!
-'E'    00-0F   xen/evtchn.h            conflict!
-'F'    all     linux/fb.h              conflict!
-'F'    01-02   drivers/scsi/pmcraid.h  conflict!
-'F'    20      drivers/video/fsl-diu-fb.h      conflict!
-'F'    20      drivers/video/intelfb/intelfb.h conflict!
-'F'    20      linux/ivtvfb.h          conflict!
-'F'    20      linux/matroxfb.h        conflict!
-'F'    20      drivers/video/aty/atyfb_base.c  conflict!
-'F'    00-0F   video/da8xx-fb.h        conflict!
-'F'    80-8F   linux/arcfb.h           conflict!
-'F'    DD      video/sstfb.h           conflict!
-'G'    00-3F   drivers/misc/sgi-gru/grulib.h   conflict!
-'G'    00-0F   linux/gigaset_dev.h     conflict!
-'H'    00-7F   linux/hiddev.h          conflict!
-'H'    00-0F   linux/hidraw.h          conflict!
-'H'    01      linux/mei.h             conflict!
-'H'    02      linux/mei.h             conflict!
-'H'    03      linux/mei.h             conflict!
-'H'    00-0F   sound/asound.h          conflict!
-'H'    20-40   sound/asound_fm.h       conflict!
-'H'    80-8F   sound/sfnt_info.h       conflict!
-'H'    10-8F   sound/emu10k1.h         conflict!
-'H'    10-1F   sound/sb16_csp.h        conflict!
-'H'    10-1F   sound/hda_hwdep.h       conflict!
-'H'    40-4F   sound/hdspm.h           conflict!
-'H'    40-4F   sound/hdsp.h            conflict!
-'H'    90      sound/usb/usx2y/usb_stream.h
-'H'    A0      uapi/linux/usb/cdc-wdm.h
-'H'    C0-F0   net/bluetooth/hci.h     conflict!
-'H'    C0-DF   net/bluetooth/hidp/hidp.h       conflict!
-'H'    C0-DF   net/bluetooth/cmtp/cmtp.h       conflict!
-'H'    C0-DF   net/bluetooth/bnep/bnep.h       conflict!
-'H'    F1      linux/hid-roccat.h      <mailto:erazor_de@users.sourceforge.net>
-'H'    F8-FA   sound/firewire.h
-'I'    all     linux/isdn.h            conflict!
-'I'    00-0F   drivers/isdn/divert/isdn_divert.h       conflict!
-'I'    40-4F   linux/mISDNif.h         conflict!
-'J'    00-1F   drivers/scsi/gdth_ioctl.h
-'K'    all     linux/kd.h
-'L'    00-1F   linux/loop.h            conflict!
-'L'    10-1F   drivers/scsi/mpt3sas/mpt3sas_ctl.h      conflict!
-'L'    20-2F   linux/lightnvm.h
-'L'    E0-FF   linux/ppdd.h            encrypted disk device driver
-                                       <http://linux01.gwdg.de/~alatham/ppdd.html>
-'M'    all     linux/soundcard.h       conflict!
-'M'    01-16   mtd/mtd-abi.h           conflict!
-               and drivers/mtd/mtdchar.c
-'M'    01-03   drivers/scsi/megaraid/megaraid_sas.h
-'M'    00-0F   drivers/video/fsl-diu-fb.h      conflict!
-'N'    00-1F   drivers/usb/scanner.h
-'N'    40-7F   drivers/block/nvme.c
-'O'     00-06   mtd/ubi-user.h         UBI
-'P'    all     linux/soundcard.h       conflict!
-'P'    60-6F   sound/sscape_ioctl.h    conflict!
-'P'    00-0F   drivers/usb/class/usblp.c       conflict!
-'P'    01-09   drivers/misc/pci_endpoint_test.c        conflict!
-'Q'    all     linux/soundcard.h
-'R'    00-1F   linux/random.h          conflict!
-'R'    01      linux/rfkill.h          conflict!
-'R'    C0-DF   net/bluetooth/rfcomm.h
-'S'    all     linux/cdrom.h           conflict!
-'S'    80-81   scsi/scsi_ioctl.h       conflict!
-'S'    82-FF   scsi/scsi.h             conflict!
-'S'    00-7F   sound/asequencer.h      conflict!
-'T'    all     linux/soundcard.h       conflict!
-'T'    00-AF   sound/asound.h          conflict!
-'T'    all     arch/x86/include/asm/ioctls.h   conflict!
-'T'    C0-DF   linux/if_tun.h          conflict!
-'U'    all     sound/asound.h          conflict!
-'U'    00-CF   linux/uinput.h          conflict!
-'U'    00-EF   linux/usbdevice_fs.h
-'U'    C0-CF   drivers/bluetooth/hci_uart.h
-'V'    all     linux/vt.h              conflict!
-'V'    all     linux/videodev2.h       conflict!
-'V'    C0      linux/ivtvfb.h          conflict!
-'V'    C0      linux/ivtv.h            conflict!
-'V'    C0      media/davinci/vpfe_capture.h    conflict!
-'V'    C0      media/si4713.h          conflict!
-'W'    00-1F   linux/watchdog.h        conflict!
-'W'    00-1F   linux/wanrouter.h       conflict!               (pre 3.9)
-'W'    00-3F   sound/asound.h          conflict!
-'W'    40-5F   drivers/pci/switch/switchtec.c
-'X'    all     fs/xfs/xfs_fs.h         conflict!
-               and fs/xfs/linux-2.6/xfs_ioctl32.h
-               and include/linux/falloc.h
-               and linux/fs.h
-'X'    all     fs/ocfs2/ocfs_fs.h      conflict!
-'X'    01      linux/pktcdvd.h         conflict!
-'Y'    all     linux/cyclades.h
-'Z'    14-15   drivers/message/fusion/mptctl.h
-'['    00-3F   linux/usb/tmc.h         USB Test and Measurement Devices
-                                       <mailto:gregkh@linuxfoundation.org>
-'a'    all     linux/atm*.h, linux/sonet.h     ATM on linux
-                                       <http://lrcwww.epfl.ch/>
-'a'    00-0F   drivers/crypto/qat/qat_common/adf_cfg_common.h  conflict! qat driver
-'b'    00-FF                           conflict! bit3 vme host bridge
-                                       <mailto:natalia@nikhefk.nikhef.nl>
-'c'    all     linux/cm4000_cs.h       conflict!
-'c'    00-7F   linux/comstats.h        conflict!
-'c'    00-7F   linux/coda.h            conflict!
-'c'    00-1F   linux/chio.h            conflict!
-'c'    80-9F   arch/s390/include/asm/chsc.h    conflict!
-'c'    A0-AF   arch/x86/include/asm/msr.h      conflict!
-'d'    00-FF   linux/char/drm/drm.h    conflict!
-'d'    02-40   pcmcia/ds.h             conflict!
-'d'    F0-FF   linux/digi1.h
-'e'    all     linux/digi1.h           conflict!
-'f'    00-1F   linux/ext2_fs.h         conflict!
-'f'    00-1F   linux/ext3_fs.h         conflict!
-'f'    00-0F   fs/jfs/jfs_dinode.h     conflict!
-'f'    00-0F   fs/ext4/ext4.h          conflict!
-'f'    00-0F   linux/fs.h              conflict!
-'f'    00-0F   fs/ocfs2/ocfs2_fs.h     conflict!
-'g'    00-0F   linux/usb/gadgetfs.h
-'g'    20-2F   linux/usb/g_printer.h
-'h'    00-7F                           conflict! Charon filesystem
-                                       <mailto:zapman@interlan.net>
-'h'    00-1F   linux/hpet.h            conflict!
-'h'    80-8F   fs/hfsplus/ioctl.c
-'i'    00-3F   linux/i2o-dev.h         conflict!
-'i'    0B-1F   linux/ipmi.h            conflict!
-'i'    80-8F   linux/i8k.h
-'j'    00-3F   linux/joystick.h
-'k'    00-0F   linux/spi/spidev.h      conflict!
-'k'    00-05   video/kyro.h            conflict!
-'k'    10-17   linux/hsi/hsi_char.h    HSI character device
-'l'    00-3F   linux/tcfs_fs.h         transparent cryptographic file system
-                                       <http://web.archive.org/web/*/http://mikonos.dia.unisa.it/tcfs>
-'l'    40-7F   linux/udf_fs_i.h        in development:
-                                       <http://sourceforge.net/projects/linux-udf/>
-'m'    00-09   linux/mmtimer.h         conflict!
-'m'    all     linux/mtio.h            conflict!
-'m'    all     linux/soundcard.h       conflict!
-'m'    all     linux/synclink.h        conflict!
-'m'    00-19   drivers/message/fusion/mptctl.h conflict!
-'m'    00      drivers/scsi/megaraid/megaraid_ioctl.h  conflict!
-'n'    00-7F   linux/ncp_fs.h and fs/ncpfs/ioctl.c
-'n'    80-8F   uapi/linux/nilfs2_api.h NILFS2
-'n'    E0-FF   linux/matroxfb.h        matroxfb
-'o'    00-1F   fs/ocfs2/ocfs2_fs.h     OCFS2
-'o'     00-03   mtd/ubi-user.h         conflict! (OCFS2 and UBI overlaps)
-'o'     40-41   mtd/ubi-user.h         UBI
-'o'     01-A1   linux/dvb/*.h          DVB
-'p'    00-0F   linux/phantom.h         conflict! (OpenHaptics needs this)
-'p'    00-1F   linux/rtc.h             conflict!
-'p'    00-3F   linux/mc146818rtc.h     conflict!
-'p'    40-7F   linux/nvram.h
-'p'    80-9F   linux/ppdev.h           user-space parport
-                                       <mailto:tim@cyberelk.net>
-'p'    A1-A5   linux/pps.h             LinuxPPS
-                                       <mailto:giometti@linux.it>
-'q'    00-1F   linux/serio.h
-'q'    80-FF   linux/telephony.h       Internet PhoneJACK, Internet LineJACK
-               linux/ixjuser.h         <http://web.archive.org/web/*/http://www.quicknet.net>
-'r'    00-1F   linux/msdos_fs.h and fs/fat/dir.c
-'s'    all     linux/cdk.h
-'t'    00-7F   linux/ppp-ioctl.h
-'t'    80-8F   linux/isdn_ppp.h
-'t'    90-91   linux/toshiba.h         toshiba and toshiba_acpi SMM
-'u'    00-1F   linux/smb_fs.h          gone
-'u'    20-3F   linux/uvcvideo.h        USB video class host driver
-'u'    40-4f   linux/udmabuf.h         userspace dma-buf misc device
-'v'    00-1F   linux/ext2_fs.h         conflict!
-'v'    00-1F   linux/fs.h              conflict!
-'v'    00-0F   linux/sonypi.h          conflict!
-'v'    00-0F   media/v4l2-subdev.h     conflict!
-'v'    C0-FF   linux/meye.h            conflict!
-'w'    all                             CERN SCI driver
-'y'    00-1F                           packet based user level communications
-                                       <mailto:zapman@interlan.net>
-'z'    00-3F                           CAN bus card    conflict!
-                                       <mailto:hdstich@connectu.ulm.circular.de>
-'z'    40-7F                           CAN bus card    conflict!
-                                       <mailto:oe@port.de>
-'z'    10-4F   drivers/s390/crypto/zcrypt_api.h        conflict!
-'|'    00-7F   linux/media.h
-0x80   00-1F   linux/fb.h
-0x89   00-06   arch/x86/include/asm/sockios.h
-0x89   0B-DF   linux/sockios.h
-0x89   E0-EF   linux/sockios.h         SIOCPROTOPRIVATE range
-0x89   E0-EF   linux/dn.h              PROTOPRIVATE range
-0x89   F0-FF   linux/sockios.h         SIOCDEVPRIVATE range
-0x8B   all     linux/wireless.h
-0x8C   00-3F                           WiNRADiO driver
-                                       <http://www.winradio.com.au/>
-0x90   00      drivers/cdrom/sbpcd.h
-0x92   00-0F   drivers/usb/mon/mon_bin.c
-0x93   60-7F   linux/auto_fs.h
-0x94   all     fs/btrfs/ioctl.h        Btrfs filesystem
-               and linux/fs.h          some lifted to vfs/generic
-0x97   00-7F   fs/ceph/ioctl.h         Ceph file system
-0x99   00-0F                           537-Addinboard driver
-                                       <mailto:buk@buks.ipn.de>
-0xA0   all     linux/sdp/sdp.h         Industrial Device Project
-                                       <mailto:kenji@bitgate.com>
-0xA1   0       linux/vtpm_proxy.h      TPM Emulator Proxy Driver
-0xA3   80-8F   Port ACL                in development:
-                                       <mailto:tlewis@mindspring.com>
-0xA3   90-9F   linux/dtlk.h
-0xA4   00-1F   uapi/linux/tee.h        Generic TEE subsystem
-0xAA   00-3F   linux/uapi/linux/userfaultfd.h
-0xAB   00-1F   linux/nbd.h
-0xAC   00-1F   linux/raw.h
-0xAD   00      Netfilter device        in development:
-                                       <mailto:rusty@rustcorp.com.au>
-0xAE   all     linux/kvm.h             Kernel-based Virtual Machine
-                                       <mailto:kvm@vger.kernel.org>
-0xAF   00-1F   linux/fsl_hypervisor.h  Freescale hypervisor
-0xB0   all     RATIO devices           in development:
-                                       <mailto:vgo@ratio.de>
-0xB1   00-1F   PPPoX                   <mailto:mostrows@styx.uwaterloo.ca>
-0xB3   00      linux/mmc/ioctl.h
-0xB4   00-0F   linux/gpio.h            <mailto:linux-gpio@vger.kernel.org>
-0xB5   00-0F   uapi/linux/rpmsg.h      <mailto:linux-remoteproc@vger.kernel.org>
-0xB6   all     linux/fpga-dfl.h
-0xC0   00-0F   linux/usb/iowarrior.h
-0xCA   00-0F   uapi/misc/cxl.h
-0xCA   10-2F   uapi/misc/ocxl.h
-0xCA   80-BF   uapi/scsi/cxlflash_ioctl.h
-0xCB   00-1F   CBM serial IEC bus      in development:
-                                       <mailto:michael.klein@puffin.lb.shuttle.de>
-0xCC   00-0F   drivers/misc/ibmvmc.h    pseries VMC driver
-0xCD   01      linux/reiserfs_fs.h
-0xCF   02      fs/cifs/ioctl.c
-0xDB   00-0F   drivers/char/mwave/mwavepub.h
-0xDD   00-3F   ZFCP device driver      see drivers/s390/scsi/
-                                       <mailto:aherrman@de.ibm.com>
-0xE5   00-3F   linux/fuse.h
-0xEC   00-01   drivers/platform/chrome/cros_ec_dev.h   ChromeOS EC driver
-0xF3   00-3F   drivers/usb/misc/sisusbvga/sisusb.h     sisfb (in development)
-                                       <mailto:thomas@winischhofer.net>
-0xF4   00-1F   video/mbxfb.h           mbxfb
-                                       <mailto:raph@8d.com>
-0xF6   all     LTTng                   Linux Trace Toolkit Next Generation
-                                       <mailto:mathieu.desnoyers@efficios.com>
-0xFD   all     linux/dm-ioctl.h
-0xFE   all     linux/isst_if.h
index 42d4cbe..e323a3f 100644 (file)
@@ -1,4 +1,4 @@
-:orphan:
+.. SPDX-License-Identifier: GPL-2.0
 
 ===================
 Kernel Build System
index 9fdded4..bdab01f 100644 (file)
@@ -1,11 +1,15 @@
-Recursion issue #1
-------------------
+================
+Recursion issues
+================
 
- .. include:: Kconfig.recursion-issue-01
-    :literal:
+issue #1
+--------
 
-Recursion issue #2
-------------------
+.. literalinclude:: Kconfig.recursion-issue-01
+   :language: kconfig
 
- .. include:: Kconfig.recursion-issue-02
-    :literal:
+issue #2
+--------
+
+.. literalinclude:: Kconfig.recursion-issue-02
+   :language: kconfig
index b255489..61b2181 100644 (file)
@@ -18,7 +18,7 @@ This file lists all modules that are built into the kernel. This is used
 by modprobe to not fail when trying to load something builtin.
 
 modules.builtin.modinfo
---------------------------------------------------
+-----------------------
 This file contains modinfo from all modules that are built into the kernel.
 Unlike modinfo of a separate module, all fields are prefixed with module name.
 
@@ -38,12 +38,11 @@ Additional options to the assembler (for built-in and modules).
 
 AFLAGS_MODULE
 -------------
-Additional module specific options to use for $(AS).
+Additional assembler options for modules.
 
 AFLAGS_KERNEL
 -------------
-Additional options for $(AS) when used for assembler
-code for code that is compiled as built-in.
+Additional assembler options for built-in.
 
 KCFLAGS
 -------
@@ -153,6 +152,7 @@ Install script called when using "make install".
 The default name is "installkernel".
 
 The script will be called with the following arguments:
+
    - $1 - kernel version
    - $2 - kernel image file
    - $3 - kernel map file
index 2bc8a78..74bef19 100644 (file)
@@ -53,6 +53,7 @@ A menu entry can have a number of attributes. Not all of them are
 applicable everywhere (see syntax).
 
 - type definition: "bool"/"tristate"/"string"/"hex"/"int"
+
   Every config option must have a type. There are only two basic types:
   tristate and string; the other types are based on these two. The type
   definition optionally accepts an input prompt, so these two examples
@@ -66,11 +67,13 @@ applicable everywhere (see syntax).
        prompt "Networking support"
 
 - input prompt: "prompt" <prompt> ["if" <expr>]
+
   Every menu entry can have at most one prompt, which is used to display
   to the user. Optionally dependencies only for this prompt can be added
   with "if".
 
 - default value: "default" <expr> ["if" <expr>]
+
   A config option can have any number of default values. If multiple
   default values are visible, only the first defined one is active.
   Default values are not limited to the menu entry where they are
@@ -112,6 +115,7 @@ applicable everywhere (see syntax).
   Optionally dependencies for this default value can be added with "if".
 
 - dependencies: "depends on" <expr>
+
   This defines a dependency for this menu entry. If multiple
   dependencies are defined, they are connected with '&&'. Dependencies
   are applied to all other options within this menu entry (which also
@@ -127,6 +131,7 @@ applicable everywhere (see syntax).
        default y
 
 - reverse dependencies: "select" <symbol> ["if" <expr>]
+
   While normal dependencies reduce the upper limit of a symbol (see
   below), reverse dependencies can be used to force a lower limit of
   another symbol. The value of the current menu symbol is used as the
@@ -146,6 +151,7 @@ applicable everywhere (see syntax).
        the illegal configurations all over.
 
 - weak reverse dependencies: "imply" <symbol> ["if" <expr>]
+
   This is similar to "select" as it enforces a lower limit on another
   symbol except that the "implied" symbol's value may still be set to n
   from a direct dependency or with a visible prompt.
@@ -176,6 +182,7 @@ applicable everywhere (see syntax).
   configure that subsystem out without also having to unset these drivers.
 
 - limiting menu display: "visible if" <expr>
+
   This attribute is only applicable to menu blocks, if the condition is
   false, the menu block is not displayed to the user (the symbols
   contained there can still be selected by other symbols, though). It is
@@ -183,12 +190,14 @@ applicable everywhere (see syntax).
   entries. Default value of "visible" is true.
 
 - numerical ranges: "range" <symbol> <symbol> ["if" <expr>]
+
   This allows to limit the range of possible input values for int
   and hex symbols. The user can only input a value which is larger than
   or equal to the first symbol and smaller than or equal to the second
   symbol.
 
 - help text: "help" or "---help---"
+
   This defines a help text. The end of the help text is determined by
   the indentation level, this means it ends at the first line which has
   a smaller indentation than the first line of the help text.
@@ -197,6 +206,7 @@ applicable everywhere (see syntax).
   the file as an aid to developers.
 
 - misc options: "option" <symbol>[=<value>]
+
   Various less common options can be defined via this option syntax,
   which can modify the behaviour of the menu entry and its config
   symbol. These options are currently possible:
@@ -325,6 +335,7 @@ end a menu entry:
 The first five also start the definition of a menu entry.
 
 config::
+
        "config" <symbol>
        <config options>
 
@@ -332,6 +343,7 @@ This defines a config symbol <symbol> and accepts any of above
 attributes as options.
 
 menuconfig::
+
        "menuconfig" <symbol>
        <config options>
 
index 88129af..a9a855f 100644 (file)
@@ -264,6 +264,7 @@ NCONFIG_MODE
 This mode shows all sub-menus in one large tree.
 
 Example::
+
        make NCONFIG_MODE=single_menu nconfig
 
 ----------------------------------------------------------------------
@@ -277,9 +278,12 @@ Searching in xconfig:
        names, so you have to know something close to what you are
        looking for.
 
-       Example:
+       Example::
+
                Ctrl-F hotplug
-       or
+
+       or::
+
                Menu: File, Search, hotplug
 
        lists all config symbol entries that contain "hotplug" in
index 093f2d7..f4f0f7f 100644 (file)
@@ -328,7 +328,7 @@ more details, with real examples.
        variable $(KBUILD_CFLAGS) and uses it for compilation flags for the
        entire tree.
 
-       asflags-y specifies options for assembling with $(AS).
+       asflags-y specifies assembler options.
 
        Example::
 
@@ -384,6 +384,7 @@ more details, with real examples.
 -----------------------
 
        Kbuild tracks dependencies on the following:
+
        1) All prerequisite files (both `*.c` and `*.h`)
        2) `CONFIG_` options used in all prerequisite files
        3) Command-line used to compile target
@@ -489,7 +490,7 @@ more details, with real examples.
        as-instr checks if the assembler reports a specific instruction
        and then outputs either option1 or option2
        C escapes are supported in the test instruction
-       Note: as-instr-option uses KBUILD_AFLAGS for $(AS) options
+       Note: as-instr-option uses KBUILD_AFLAGS for assembler options
 
     cc-option
        cc-option is used to check if $(CC) supports a given option, and if
@@ -905,7 +906,7 @@ When kbuild executes, the following steps are followed (roughly):
        vmlinux. The usage of $(call if_changed,xxx) will be described later.
 
     KBUILD_AFLAGS
-       $(AS) assembler flags
+       Assembler flags
 
        Default value - see top level Makefile
        Append or modify as required per architecture.
@@ -948,16 +949,16 @@ When kbuild executes, the following steps are followed (roughly):
        to 'y' when selected.
 
     KBUILD_AFLAGS_KERNEL
-       $(AS) options specific for built-in
+       Assembler options specific for built-in
 
        $(KBUILD_AFLAGS_KERNEL) contains extra C compiler flags used to compile
        resident kernel code.
 
     KBUILD_AFLAGS_MODULE
-       Options for $(AS) when building modules
+       Assembler options specific for modules
 
        $(KBUILD_AFLAGS_MODULE) is used to add arch-specific options that
-       are used for $(AS).
+       are used for assembler.
 
        From commandline AFLAGS_MODULE shall be used (see kbuild.txt).
 
diff --git a/Documentation/kdump/index.rst b/Documentation/kdump/index.rst
deleted file mode 100644 (file)
index 2b17fcf..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-:orphan:
-
-================================================================
-Documentation for Kdump - The kexec-based Crash Dumping Solution
-================================================================
-
-This document includes overview, setup and installation, and analysis
-information.
-
-.. toctree::
-    :maxdepth: 1
-
-    kdump
-    vmcoreinfo
-
-.. only::  subproject and html
-
-   Indices
-   =======
-
-   * :ref:`genindex`
index dc698ea..a8518ac 100644 (file)
@@ -1364,7 +1364,7 @@ Futex API reference
 Further reading
 ===============
 
--  ``Documentation/locking/spinlocks.txt``: Linus Torvalds' spinlocking
+-  ``Documentation/locking/spinlocks.rst``: Linus Torvalds' spinlocking
    tutorial in the kernel sources.
 
 -  Unix Systems for Modern Architectures: Symmetric Multiprocessing and
diff --git a/Documentation/kernel-per-CPU-kthreads.txt b/Documentation/kernel-per-CPU-kthreads.txt
deleted file mode 100644 (file)
index 5623b99..0000000
+++ /dev/null
@@ -1,356 +0,0 @@
-==========================================
-Reducing OS jitter due to per-cpu kthreads
-==========================================
-
-This document lists per-CPU kthreads in the Linux kernel and presents
-options to control their OS jitter.  Note that non-per-CPU kthreads are
-not listed here.  To reduce OS jitter from non-per-CPU kthreads, bind
-them to a "housekeeping" CPU dedicated to such work.
-
-References
-==========
-
--      Documentation/IRQ-affinity.txt:  Binding interrupts to sets of CPUs.
-
--      Documentation/cgroup-v1:  Using cgroups to bind tasks to sets of CPUs.
-
--      man taskset:  Using the taskset command to bind tasks to sets
-       of CPUs.
-
--      man sched_setaffinity:  Using the sched_setaffinity() system
-       call to bind tasks to sets of CPUs.
-
--      /sys/devices/system/cpu/cpuN/online:  Control CPU N's hotplug state,
-       writing "0" to offline and "1" to online.
-
--      In order to locate kernel-generated OS jitter on CPU N:
-
-               cd /sys/kernel/debug/tracing
-               echo 1 > max_graph_depth # Increase the "1" for more detail
-               echo function_graph > current_tracer
-               # run workload
-               cat per_cpu/cpuN/trace
-
-kthreads
-========
-
-Name:
-  ehca_comp/%u
-
-Purpose:
-  Periodically process Infiniband-related work.
-
-To reduce its OS jitter, do any of the following:
-
-1.     Don't use eHCA Infiniband hardware, instead choosing hardware
-       that does not require per-CPU kthreads.  This will prevent these
-       kthreads from being created in the first place.  (This will
-       work for most people, as this hardware, though important, is
-       relatively old and is produced in relatively low unit volumes.)
-2.     Do all eHCA-Infiniband-related work on other CPUs, including
-       interrupts.
-3.     Rework the eHCA driver so that its per-CPU kthreads are
-       provisioned only on selected CPUs.
-
-
-Name:
-  irq/%d-%s
-
-Purpose:
-  Handle threaded interrupts.
-
-To reduce its OS jitter, do the following:
-
-1.     Use irq affinity to force the irq threads to execute on
-       some other CPU.
-
-Name:
-  kcmtpd_ctr_%d
-
-Purpose:
-  Handle Bluetooth work.
-
-To reduce its OS jitter, do one of the following:
-
-1.     Don't use Bluetooth, in which case these kthreads won't be
-       created in the first place.
-2.     Use irq affinity to force Bluetooth-related interrupts to
-       occur on some other CPU and furthermore initiate all
-       Bluetooth activity on some other CPU.
-
-Name:
-  ksoftirqd/%u
-
-Purpose:
-  Execute softirq handlers when threaded or when under heavy load.
-
-To reduce its OS jitter, each softirq vector must be handled
-separately as follows:
-
-TIMER_SOFTIRQ
--------------
-
-Do all of the following:
-
-1.     To the extent possible, keep the CPU out of the kernel when it
-       is non-idle, for example, by avoiding system calls and by forcing
-       both kernel threads and interrupts to execute elsewhere.
-2.     Build with CONFIG_HOTPLUG_CPU=y.  After boot completes, force
-       the CPU offline, then bring it back online.  This forces
-       recurring timers to migrate elsewhere.  If you are concerned
-       with multiple CPUs, force them all offline before bringing the
-       first one back online.  Once you have onlined the CPUs in question,
-       do not offline any other CPUs, because doing so could force the
-       timer back onto one of the CPUs in question.
-
-NET_TX_SOFTIRQ and NET_RX_SOFTIRQ
----------------------------------
-
-Do all of the following:
-
-1.     Force networking interrupts onto other CPUs.
-2.     Initiate any network I/O on other CPUs.
-3.     Once your application has started, prevent CPU-hotplug operations
-       from being initiated from tasks that might run on the CPU to
-       be de-jittered.  (It is OK to force this CPU offline and then
-       bring it back online before you start your application.)
-
-BLOCK_SOFTIRQ
--------------
-
-Do all of the following:
-
-1.     Force block-device interrupts onto some other CPU.
-2.     Initiate any block I/O on other CPUs.
-3.     Once your application has started, prevent CPU-hotplug operations
-       from being initiated from tasks that might run on the CPU to
-       be de-jittered.  (It is OK to force this CPU offline and then
-       bring it back online before you start your application.)
-
-IRQ_POLL_SOFTIRQ
-----------------
-
-Do all of the following:
-
-1.     Force block-device interrupts onto some other CPU.
-2.     Initiate any block I/O and block-I/O polling on other CPUs.
-3.     Once your application has started, prevent CPU-hotplug operations
-       from being initiated from tasks that might run on the CPU to
-       be de-jittered.  (It is OK to force this CPU offline and then
-       bring it back online before you start your application.)
-
-TASKLET_SOFTIRQ
----------------
-
-Do one or more of the following:
-
-1.     Avoid use of drivers that use tasklets.  (Such drivers will contain
-       calls to things like tasklet_schedule().)
-2.     Convert all drivers that you must use from tasklets to workqueues.
-3.     Force interrupts for drivers using tasklets onto other CPUs,
-       and also do I/O involving these drivers on other CPUs.
-
-SCHED_SOFTIRQ
--------------
-
-Do all of the following:
-
-1.     Avoid sending scheduler IPIs to the CPU to be de-jittered,
-       for example, ensure that at most one runnable kthread is present
-       on that CPU.  If a thread that expects to run on the de-jittered
-       CPU awakens, the scheduler will send an IPI that can result in
-       a subsequent SCHED_SOFTIRQ.
-2.     CONFIG_NO_HZ_FULL=y and ensure that the CPU to be de-jittered
-       is marked as an adaptive-ticks CPU using the "nohz_full="
-       boot parameter.  This reduces the number of scheduler-clock
-       interrupts that the de-jittered CPU receives, minimizing its
-       chances of being selected to do the load balancing work that
-       runs in SCHED_SOFTIRQ context.
-3.     To the extent possible, keep the CPU out of the kernel when it
-       is non-idle, for example, by avoiding system calls and by
-       forcing both kernel threads and interrupts to execute elsewhere.
-       This further reduces the number of scheduler-clock interrupts
-       received by the de-jittered CPU.
-
-HRTIMER_SOFTIRQ
----------------
-
-Do all of the following:
-
-1.     To the extent possible, keep the CPU out of the kernel when it
-       is non-idle.  For example, avoid system calls and force both
-       kernel threads and interrupts to execute elsewhere.
-2.     Build with CONFIG_HOTPLUG_CPU=y.  Once boot completes, force the
-       CPU offline, then bring it back online.  This forces recurring
-       timers to migrate elsewhere.  If you are concerned with multiple
-       CPUs, force them all offline before bringing the first one
-       back online.  Once you have onlined the CPUs in question, do not
-       offline any other CPUs, because doing so could force the timer
-       back onto one of the CPUs in question.
-
-RCU_SOFTIRQ
------------
-
-Do at least one of the following:
-
-1.     Offload callbacks and keep the CPU in either dyntick-idle or
-       adaptive-ticks state by doing all of the following:
-
-       a.      CONFIG_NO_HZ_FULL=y and ensure that the CPU to be
-               de-jittered is marked as an adaptive-ticks CPU using the
-               "nohz_full=" boot parameter.  Bind the rcuo kthreads to
-               housekeeping CPUs, which can tolerate OS jitter.
-       b.      To the extent possible, keep the CPU out of the kernel
-               when it is non-idle, for example, by avoiding system
-               calls and by forcing both kernel threads and interrupts
-               to execute elsewhere.
-
-2.     Enable RCU to do its processing remotely via dyntick-idle by
-       doing all of the following:
-
-       a.      Build with CONFIG_NO_HZ=y and CONFIG_RCU_FAST_NO_HZ=y.
-       b.      Ensure that the CPU goes idle frequently, allowing other
-               CPUs to detect that it has passed through an RCU quiescent
-               state.  If the kernel is built with CONFIG_NO_HZ_FULL=y,
-               userspace execution also allows other CPUs to detect that
-               the CPU in question has passed through a quiescent state.
-       c.      To the extent possible, keep the CPU out of the kernel
-               when it is non-idle, for example, by avoiding system
-               calls and by forcing both kernel threads and interrupts
-               to execute elsewhere.
-
-Name:
-  kworker/%u:%d%s (cpu, id, priority)
-
-Purpose:
-  Execute workqueue requests
-
-To reduce its OS jitter, do any of the following:
-
-1.     Run your workload at a real-time priority, which will allow
-       preempting the kworker daemons.
-2.     A given workqueue can be made visible in the sysfs filesystem
-       by passing the WQ_SYSFS to that workqueue's alloc_workqueue().
-       Such a workqueue can be confined to a given subset of the
-       CPUs using the ``/sys/devices/virtual/workqueue/*/cpumask`` sysfs
-       files.  The set of WQ_SYSFS workqueues can be displayed using
-       "ls sys/devices/virtual/workqueue".  That said, the workqueues
-       maintainer would like to caution people against indiscriminately
-       sprinkling WQ_SYSFS across all the workqueues.  The reason for
-       caution is that it is easy to add WQ_SYSFS, but because sysfs is
-       part of the formal user/kernel API, it can be nearly impossible
-       to remove it, even if its addition was a mistake.
-3.     Do any of the following needed to avoid jitter that your
-       application cannot tolerate:
-
-       a.      Build your kernel with CONFIG_SLUB=y rather than
-               CONFIG_SLAB=y, thus avoiding the slab allocator's periodic
-               use of each CPU's workqueues to run its cache_reap()
-               function.
-       b.      Avoid using oprofile, thus avoiding OS jitter from
-               wq_sync_buffer().
-       c.      Limit your CPU frequency so that a CPU-frequency
-               governor is not required, possibly enlisting the aid of
-               special heatsinks or other cooling technologies.  If done
-               correctly, and if you CPU architecture permits, you should
-               be able to build your kernel with CONFIG_CPU_FREQ=n to
-               avoid the CPU-frequency governor periodically running
-               on each CPU, including cs_dbs_timer() and od_dbs_timer().
-
-               WARNING:  Please check your CPU specifications to
-               make sure that this is safe on your particular system.
-       d.      As of v3.18, Christoph Lameter's on-demand vmstat workers
-               commit prevents OS jitter due to vmstat_update() on
-               CONFIG_SMP=y systems.  Before v3.18, is not possible
-               to entirely get rid of the OS jitter, but you can
-               decrease its frequency by writing a large value to
-               /proc/sys/vm/stat_interval.  The default value is HZ,
-               for an interval of one second.  Of course, larger values
-               will make your virtual-memory statistics update more
-               slowly.  Of course, you can also run your workload at
-               a real-time priority, thus preempting vmstat_update(),
-               but if your workload is CPU-bound, this is a bad idea.
-               However, there is an RFC patch from Christoph Lameter
-               (based on an earlier one from Gilad Ben-Yossef) that
-               reduces or even eliminates vmstat overhead for some
-               workloads at https://lkml.org/lkml/2013/9/4/379.
-       e.      Boot with "elevator=noop" to avoid workqueue use by
-               the block layer.
-       f.      If running on high-end powerpc servers, build with
-               CONFIG_PPC_RTAS_DAEMON=n.  This prevents the RTAS
-               daemon from running on each CPU every second or so.
-               (This will require editing Kconfig files and will defeat
-               this platform's RAS functionality.)  This avoids jitter
-               due to the rtas_event_scan() function.
-               WARNING:  Please check your CPU specifications to
-               make sure that this is safe on your particular system.
-       g.      If running on Cell Processor, build your kernel with
-               CBE_CPUFREQ_SPU_GOVERNOR=n to avoid OS jitter from
-               spu_gov_work().
-               WARNING:  Please check your CPU specifications to
-               make sure that this is safe on your particular system.
-       h.      If running on PowerMAC, build your kernel with
-               CONFIG_PMAC_RACKMETER=n to disable the CPU-meter,
-               avoiding OS jitter from rackmeter_do_timer().
-
-Name:
-  rcuc/%u
-
-Purpose:
-  Execute RCU callbacks in CONFIG_RCU_BOOST=y kernels.
-
-To reduce its OS jitter, do at least one of the following:
-
-1.     Build the kernel with CONFIG_PREEMPT=n.  This prevents these
-       kthreads from being created in the first place, and also obviates
-       the need for RCU priority boosting.  This approach is feasible
-       for workloads that do not require high degrees of responsiveness.
-2.     Build the kernel with CONFIG_RCU_BOOST=n.  This prevents these
-       kthreads from being created in the first place.  This approach
-       is feasible only if your workload never requires RCU priority
-       boosting, for example, if you ensure frequent idle time on all
-       CPUs that might execute within the kernel.
-3.     Build with CONFIG_RCU_NOCB_CPU=y and boot with the rcu_nocbs=
-       boot parameter offloading RCU callbacks from all CPUs susceptible
-       to OS jitter.  This approach prevents the rcuc/%u kthreads from
-       having any work to do, so that they are never awakened.
-4.     Ensure that the CPU never enters the kernel, and, in particular,
-       avoid initiating any CPU hotplug operations on this CPU.  This is
-       another way of preventing any callbacks from being queued on the
-       CPU, again preventing the rcuc/%u kthreads from having any work
-       to do.
-
-Name:
-  rcuop/%d and rcuos/%d
-
-Purpose:
-  Offload RCU callbacks from the corresponding CPU.
-
-To reduce its OS jitter, do at least one of the following:
-
-1.     Use affinity, cgroups, or other mechanism to force these kthreads
-       to execute on some other CPU.
-2.     Build with CONFIG_RCU_NOCB_CPU=n, which will prevent these
-       kthreads from being created in the first place.  However, please
-       note that this will not eliminate OS jitter, but will instead
-       shift it to RCU_SOFTIRQ.
-
-Name:
-  watchdog/%u
-
-Purpose:
-  Detect software lockups on each CPU.
-
-To reduce its OS jitter, do at least one of the following:
-
-1.     Build with CONFIG_LOCKUP_DETECTOR=n, which will prevent these
-       kthreads from being created in the first place.
-2.     Boot with "nosoftlockup=0", which will also prevent these kthreads
-       from being created.  Other related watchdog and softlockup boot
-       parameters may be found in Documentation/admin-guide/kernel-parameters.rst
-       and Documentation/watchdog/watchdog-parameters.rst.
-3.     Echo a zero to /proc/sys/kernel/watchdog to disable the
-       watchdog timer.
-4.     Echo a large number of /proc/sys/kernel/watchdog_thresh in
-       order to reduce the frequency of OS jitter due to the watchdog
-       timer down to a level that is acceptable for your workload.
diff --git a/Documentation/laptops/asus-laptop.txt b/Documentation/laptops/asus-laptop.txt
deleted file mode 100644 (file)
index 5f28587..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-Asus Laptop Extras
-
-Version 0.1
-August 6, 2009
-
-Corentin Chary <corentincj@iksaif.net>
-http://acpi4asus.sf.net/
-
- This driver provides support for extra features of ACPI-compatible ASUS laptops.
- It may also support some MEDION, JVC or VICTOR laptops (such as MEDION 9675 or
- VICTOR XP7210 for example). It makes all the extra buttons generate input
- events (like keyboards).
- On some models adds support for changing the display brightness and output,
- switching the LCD backlight on and off, and most importantly, allows you to
- blink those fancy LEDs intended for reporting mail and wireless status.
-
-This driver supercedes the old asus_acpi driver.
-
-Requirements
-------------
-
-  Kernel 2.6.X sources, configured for your computer, with ACPI support.
-  You also need CONFIG_INPUT and CONFIG_ACPI.
-
-Status
-------
-
- The features currently supported are the following (see below for
- detailed description):
-
- - Fn key combinations
- - Bluetooth enable and disable
- - Wlan enable and disable
- - GPS enable and disable
- - Video output switching
- - Ambient Light Sensor on and off
- - LED control
- - LED Display control
- - LCD brightness control
- - LCD on and off
-
- A compatibility table by model and feature is maintained on the web
- site, http://acpi4asus.sf.net/.
-
-Usage
------
-
-  Try "modprobe asus-laptop". Check your dmesg (simply type dmesg). You should
-  see some lines like this :
-
-      Asus Laptop Extras version 0.42
-        L2D model detected.
-
-  If it is not the output you have on your laptop, send it (and the laptop's
-  DSDT) to me.
-
-  That's all, now, all the events generated by the hotkeys of your laptop
-  should be reported via netlink events. You can check with
-  "acpi_genl monitor" (part of the acpica project).
-
-  Hotkeys are also reported as input keys (like keyboards) you can check
-  which key are supported using "xev" under X11.
-
-  You can get information on the version of your DSDT table by reading the
-  /sys/devices/platform/asus-laptop/infos entry. If you have a question or a
-  bug report to do, please include the output of this entry.
-
-LEDs
-----
-
-  You can modify LEDs be echoing values to /sys/class/leds/asus::*/brightness :
-    echo 1 >  /sys/class/leds/asus::mail/brightness
-  will switch the mail LED on.
-  You can also know if they are on/off by reading their content and use
-  kernel triggers like disk-activity or heartbeat.
-
-Backlight
----------
-
-  You can control lcd backlight power and brightness with
-  /sys/class/backlight/asus-laptop/. Brightness Values are between 0 and 15.
-
-Wireless devices
----------------
-
-  You can turn the internal Bluetooth adapter on/off with the bluetooth entry
-  (only on models with Bluetooth). This usually controls the associated LED.
-  Same for Wlan adapter.
-
-Display switching
------------------
-
-  Note: the display switching code is currently considered EXPERIMENTAL.
-
-  Switching works for the following models:
-    L3800C
-    A2500H
-    L5800C
-    M5200N
-    W1000N (albeit with some glitches)
-    M6700R
-    A6JC
-    F3J
-
-  Switching doesn't work for the following:
-    M3700N
-    L2X00D (locks the laptop under certain conditions)
-
-  To switch the displays, echo values from 0 to 15 to
-  /sys/devices/platform/asus-laptop/display. The significance of those values
-  is as follows:
-
-  +-------+-----+-----+-----+-----+-----+
-  | Bin   | Val | DVI | TV  | CRT | LCD |
-  +-------+-----+-----+-----+-----+-----+
-  + 0000  +   0 +     +     +     +     +
-  +-------+-----+-----+-----+-----+-----+
-  + 0001  +   1 +     +     +     +  X  +
-  +-------+-----+-----+-----+-----+-----+
-  + 0010  +   2 +     +     +  X  +     +
-  +-------+-----+-----+-----+-----+-----+
-  + 0011  +   3 +     +     +  X  +  X  +
-  +-------+-----+-----+-----+-----+-----+
-  + 0100  +   4 +     +  X  +     +     +
-  +-------+-----+-----+-----+-----+-----+
-  + 0101  +   5 +     +  X  +     + X   +
-  +-------+-----+-----+-----+-----+-----+
-  + 0110  +   6 +     +  X  +  X  +     +
-  +-------+-----+-----+-----+-----+-----+
-  + 0111  +   7 +     +  X  +  X  +  X  +
-  +-------+-----+-----+-----+-----+-----+
-  + 1000  +   8 +  X  +     +     +     +
-  +-------+-----+-----+-----+-----+-----+
-  + 1001  +   9 +  X  +     +     +  X  +
-  +-------+-----+-----+-----+-----+-----+
-  + 1010  +  10 +  X  +     +  X  +     +
-  +-------+-----+-----+-----+-----+-----+
-  + 1011  +  11 +  X  +     +  X  +  X  +
-  +-------+-----+-----+-----+-----+-----+
-  + 1100  +  12 +  X  +  X  +     +     +
-  +-------+-----+-----+-----+-----+-----+
-  + 1101  +  13 +  X  +  X  +     +  X  +
-  +-------+-----+-----+-----+-----+-----+
-  + 1110  +  14 +  X  +  X  +  X  +     +
-  +-------+-----+-----+-----+-----+-----+
-  + 1111  +  15 +  X  +  X  +  X  +  X  +
-  +-------+-----+-----+-----+-----+-----+
-
-  In most cases, the appropriate displays must be plugged in for the above
-  combinations to work. TV-Out may need to be initialized at boot time.
-
-  Debugging:
-  1) Check whether the Fn+F8 key:
-     a) does not lock the laptop (try a boot with noapic / nolapic if it does)
-     b) generates events (0x6n, where n is the value corresponding to the
-        configuration above)
-     c) actually works
-     Record the disp value at every configuration.
-  2) Echo values from 0 to 15 to /sys/devices/platform/asus-laptop/display.
-     Record its value, note any change. If nothing changes, try a broader range,
-     up to 65535.
-  3) Send ANY output (both positive and negative reports are needed, unless your
-     machine is already listed above) to the acpi4asus-user mailing list.
-
-  Note: on some machines (e.g. L3C), after the module has been loaded, only 0x6n
-  events are generated and no actual switching occurs. In such a case, a line
-  like:
-
-    echo $((10#$arg-60)) > /sys/devices/platform/asus-laptop/display
-
-  will usually do the trick ($arg is the 0000006n-like event passed to acpid).
-
-  Note: there is currently no reliable way to read display status on xxN
-  (Centrino) models.
-
-LED display
------------
-
-  Some models like the W1N have a LED display that can be used to display
-  several items of information.
-
-  LED display works for the following models:
-    W1000N
-    W1J
-
-  To control the LED display, use the following :
-
-    echo 0x0T000DDD > /sys/devices/platform/asus-laptop/
-
-  where T control the 3 letters display, and DDD the 3 digits display,
-  according to the tables below.
-
-         DDD (digits)
-         000 to 999 = display digits
-         AAA        = ---
-         BBB to FFF = turn-off
-
-         T  (type)
-         0 = off
-         1 = dvd
-         2 = vcd
-         3 = mp3
-         4 = cd
-         5 = tv
-         6 = cpu
-         7 = vol
-
-  For example "echo 0x01000001 >/sys/devices/platform/asus-laptop/ledd"
-  would display "DVD001".
-
-Driver options:
----------------
-
- Options can be passed to the asus-laptop driver using the standard
- module argument syntax (<param>=<value> when passing the option to the
- module or asus-laptop.<param>=<value> on the kernel boot line when
- asus-laptop is statically linked into the kernel).
-
-            wapf: WAPF defines the behavior of the Fn+Fx wlan key
-                  The significance of values is yet to be found, but
-                  most of the time:
-                  - 0x0 should do nothing
-                  - 0x1 should allow to control the device with Fn+Fx key.
-                  - 0x4 should send an ACPI event (0x88) while pressing the Fn+Fx key
-                  - 0x5 like 0x1 or 0x4
-
- The default value is 0x1.
-
-Unsupported models
-------------------
-
- These models will never be supported by this module, as they use a completely
- different mechanism to handle LEDs and extra stuff (meaning we have no clue
- how it works):
-
- - ASUS A1300 (A1B), A1370D
- - ASUS L7300G
- - ASUS L8400
-
-Patches, Errors, Questions:
---------------------------
-
- I appreciate any success or failure
- reports, especially if they add to or correct the compatibility table.
- Please include the following information in your report:
-
- - Asus model name
- - a copy of your ACPI tables, using the "acpidump" utility
- - a copy of /sys/devices/platform/asus-laptop/infos
- - which driver features work and which don't
- - the observed behavior of non-working features
-
- Any other comments or patches are also more than welcome.
-
- acpi4asus-user@lists.sourceforge.net
- http://sourceforge.net/projects/acpi4asus
-
diff --git a/Documentation/laptops/disk-shock-protection.txt b/Documentation/laptops/disk-shock-protection.txt
deleted file mode 100644 (file)
index 0e6ba26..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-Hard disk shock protection
-==========================
-
-Author: Elias Oltmanns <eo@nebensachen.de>
-Last modified: 2008-10-03
-
-
-0. Contents
------------
-
-1. Intro
-2. The interface
-3. References
-4. CREDITS
-
-
-1. Intro
---------
-
-ATA/ATAPI-7 specifies the IDLE IMMEDIATE command with unload feature.
-Issuing this command should cause the drive to switch to idle mode and
-unload disk heads. This feature is being used in modern laptops in
-conjunction with accelerometers and appropriate software to implement
-a shock protection facility. The idea is to stop all I/O operations on
-the internal hard drive and park its heads on the ramp when critical
-situations are anticipated. The desire to have such a feature
-available on GNU/Linux systems has been the original motivation to
-implement a generic disk head parking interface in the Linux kernel.
-Please note, however, that other components have to be set up on your
-system in order to get disk shock protection working (see
-section 3. References below for pointers to more information about
-that).
-
-
-2. The interface
-----------------
-
-For each ATA device, the kernel exports the file
-block/*/device/unload_heads in sysfs (here assumed to be mounted under
-/sys). Access to /sys/block/*/device/unload_heads is denied with
--EOPNOTSUPP if the device does not support the unload feature.
-Otherwise, writing an integer value to this file will take the heads
-of the respective drive off the platter and block all I/O operations
-for the specified number of milliseconds. When the timeout expires and
-no further disk head park request has been issued in the meantime,
-normal operation will be resumed. The maximal value accepted for a
-timeout is 30000 milliseconds. Exceeding this limit will return
--EOVERFLOW, but heads will be parked anyway and the timeout will be
-set to 30 seconds. However, you can always change a timeout to any
-value between 0 and 30000 by issuing a subsequent head park request
-before the timeout of the previous one has expired. In particular, the
-total timeout can exceed 30 seconds and, more importantly, you can
-cancel a previously set timeout and resume normal operation
-immediately by specifying a timeout of 0. Values below -2 are rejected
-with -EINVAL (see below for the special meaning of -1 and -2). If the
-timeout specified for a recent head park request has not yet expired,
-reading from /sys/block/*/device/unload_heads will report the number
-of milliseconds remaining until normal operation will be resumed;
-otherwise, reading the unload_heads attribute will return 0.
-
-For example, do the following in order to park the heads of drive
-/dev/sda and stop all I/O operations for five seconds:
-
-# echo 5000 > /sys/block/sda/device/unload_heads
-
-A simple
-
-# cat /sys/block/sda/device/unload_heads
-
-will show you how many milliseconds are left before normal operation
-will be resumed.
-
-A word of caution: The fact that the interface operates on a basis of
-milliseconds may raise expectations that cannot be satisfied in
-reality. In fact, the ATA specs clearly state that the time for an
-unload operation to complete is vendor specific. The hint in ATA-7
-that this will typically be within 500 milliseconds apparently has
-been dropped in ATA-8.
-
-There is a technical detail of this implementation that may cause some
-confusion and should be discussed here. When a head park request has
-been issued to a device successfully, all I/O operations on the
-controller port this device is attached to will be deferred. That is
-to say, any other device that may be connected to the same port will
-be affected too. The only exception is that a subsequent head unload
-request to that other device will be executed immediately. Further
-operations on that port will be deferred until the timeout specified
-for either device on the port has expired. As far as PATA (old style
-IDE) configurations are concerned, there can only be two devices
-attached to any single port. In SATA world we have port multipliers
-which means that a user-issued head parking request to one device may
-actually result in stopping I/O to a whole bunch of devices. However,
-since this feature is supposed to be used on laptops and does not seem
-to be very useful in any other environment, there will be mostly one
-device per port. Even if the CD/DVD writer happens to be connected to
-the same port as the hard drive, it generally *should* recover just
-fine from the occasional buffer under-run incurred by a head park
-request to the HD. Actually, when you are using an ide driver rather
-than its libata counterpart (i.e. your disk is called /dev/hda
-instead of /dev/sda), then parking the heads of one drive (drive X)
-will generally not affect the mode of operation of another drive
-(drive Y) on the same port as described above. It is only when a port
-reset is required to recover from an exception on drive Y that further
-I/O operations on that drive (and the reset itself) will be delayed
-until drive X is no longer in the parked state.
-
-Finally, there are some hard drives that only comply with an earlier
-version of the ATA standard than ATA-7, but do support the unload
-feature nonetheless. Unfortunately, there is no safe way Linux can
-detect these devices, so you won't be able to write to the
-unload_heads attribute. If you know that your device really does
-support the unload feature (for instance, because the vendor of your
-laptop or the hard drive itself told you so), then you can tell the
-kernel to enable the usage of this feature for that drive by writing
-the special value -1 to the unload_heads attribute:
-
-# echo -1 > /sys/block/sda/device/unload_heads
-
-will enable the feature for /dev/sda, and giving -2 instead of -1 will
-disable it again.
-
-
-3. References
--------------
-
-There are several laptops from different vendors featuring shock
-protection capabilities. As manufacturers have refused to support open
-source development of the required software components so far, Linux
-support for shock protection varies considerably between different
-hardware implementations. Ideally, this section should contain a list
-of pointers at different projects aiming at an implementation of shock
-protection on different systems. Unfortunately, I only know of a
-single project which, although still considered experimental, is fit
-for use. Please feel free to add projects that have been the victims
-of my ignorance.
-
-- http://www.thinkwiki.org/wiki/HDAPS
-  See this page for information about Linux support of the hard disk
-  active protection system as implemented in IBM/Lenovo Thinkpads.
-
-
-4. CREDITS
-----------
-
-This implementation of disk head parking has been inspired by a patch
-originally published by Jon Escombe <lists@dresco.co.uk>. My efforts
-to develop an implementation of this feature that is fit to be merged
-into mainline have been aided by various kernel developers, in
-particular by Tejun Heo and Bartlomiej Zolnierkiewicz.
diff --git a/Documentation/laptops/laptop-mode.txt b/Documentation/laptops/laptop-mode.txt
deleted file mode 100644 (file)
index 1c707fc..0000000
+++ /dev/null
@@ -1,782 +0,0 @@
-How to conserve battery power using laptop-mode
------------------------------------------------
-
-Document Author: Bart Samwel (bart@samwel.tk)
-Date created: January 2, 2004
-Last modified: December 06, 2004
-
-Introduction
-------------
-
-Laptop mode is used to minimize the time that the hard disk needs to be spun up,
-to conserve battery power on laptops. It has been reported to cause significant
-power savings.
-
-Contents
---------
-
-* Introduction
-* Installation
-* Caveats
-* The Details
-* Tips & Tricks
-* Control script
-* ACPI integration
-* Monitoring tool
-
-
-Installation
-------------
-
-To use laptop mode, you don't need to set any kernel configuration options
-or anything. Simply install all the files included in this document, and
-laptop mode will automatically be started when you're on battery. For
-your convenience, a tarball containing an installer can be downloaded at:
-
-http://www.samwel.tk/laptop_mode/laptop_mode/
-
-To configure laptop mode, you need to edit the configuration file, which is
-located in /etc/default/laptop-mode on Debian-based systems, or in
-/etc/sysconfig/laptop-mode on other systems.
-
-Unfortunately, automatic enabling of laptop mode does not work for
-laptops that don't have ACPI. On those laptops, you need to start laptop
-mode manually. To start laptop mode, run "laptop_mode start", and to
-stop it, run "laptop_mode stop". (Note: The laptop mode tools package now
-has experimental support for APM, you might want to try that first.)
-
-
-Caveats
--------
-
-* The downside of laptop mode is that you have a chance of losing up to 10
-  minutes of work. If you cannot afford this, don't use it! The supplied ACPI
-  scripts automatically turn off laptop mode when the battery almost runs out,
-  so that you won't lose any data at the end of your battery life.
-
-* Most desktop hard drives have a very limited lifetime measured in spindown
-  cycles, typically about 50.000 times (it's usually listed on the spec sheet).
-  Check your drive's rating, and don't wear down your drive's lifetime if you
-  don't need to.
-
-* If you mount some of your ext3/reiserfs filesystems with the -n option, then
-  the control script will not be able to remount them correctly. You must set
-  DO_REMOUNTS=0 in the control script, otherwise it will remount them with the
-  wrong options -- or it will fail because it cannot write to /etc/mtab.
-
-* If you have your filesystems listed as type "auto" in fstab, like I did, then
-  the control script will not recognize them as filesystems that need remounting.
-  You must list the filesystems with their true type instead.
-
-* It has been reported that some versions of the mutt mail client use file access
-  times to determine whether a folder contains new mail. If you use mutt and
-  experience this, you must disable the noatime remounting by setting the option
-  DO_REMOUNT_NOATIME to 0 in the configuration file.
-
-
-The Details
------------
-
-Laptop mode is controlled by the knob /proc/sys/vm/laptop_mode. This knob is
-present for all kernels that have the laptop mode patch, regardless of any
-configuration options. When the knob is set, any physical disk I/O (that might
-have caused the hard disk to spin up) causes Linux to flush all dirty blocks. The
-result of this is that after a disk has spun down, it will not be spun up
-anymore to write dirty blocks, because those blocks had already been written
-immediately after the most recent read operation. The value of the laptop_mode
-knob determines the time between the occurrence of disk I/O and when the flush
-is triggered. A sensible value for the knob is 5 seconds. Setting the knob to
-0 disables laptop mode.
-
-To increase the effectiveness of the laptop_mode strategy, the laptop_mode
-control script increases dirty_expire_centisecs and dirty_writeback_centisecs in
-/proc/sys/vm to about 10 minutes (by default), which means that pages that are
-dirtied are not forced to be written to disk as often. The control script also
-changes the dirty background ratio, so that background writeback of dirty pages
-is not done anymore. Combined with a higher commit value (also 10 minutes) for
-ext3 or ReiserFS filesystems (also done automatically by the control script),
-this results in concentration of disk activity in a small time interval which
-occurs only once every 10 minutes, or whenever the disk is forced to spin up by
-a cache miss. The disk can then be spun down in the periods of inactivity.
-
-If you want to find out which process caused the disk to spin up, you can
-gather information by setting the flag /proc/sys/vm/block_dump. When this flag
-is set, Linux reports all disk read and write operations that take place, and
-all block dirtyings done to files. This makes it possible to debug why a disk
-needs to spin up, and to increase battery life even more. The output of
-block_dump is written to the kernel output, and it can be retrieved using
-"dmesg". When you use block_dump and your kernel logging level also includes
-kernel debugging messages, you probably want to turn off klogd, otherwise
-the output of block_dump will be logged, causing disk activity that is not
-normally there.
-
-
-Configuration
--------------
-
-The laptop mode configuration file is located in /etc/default/laptop-mode on
-Debian-based systems, or in /etc/sysconfig/laptop-mode on other systems. It
-contains the following options:
-
-MAX_AGE:
-
-Maximum time, in seconds, of hard drive spindown time that you are
-comfortable with. Worst case, it's possible that you could lose this
-amount of work if your battery fails while you're in laptop mode.
-
-MINIMUM_BATTERY_MINUTES:
-
-Automatically disable laptop mode if the remaining number of minutes of
-battery power is less than this value. Default is 10 minutes.
-
-AC_HD/BATT_HD:
-
-The idle timeout that should be set on your hard drive when laptop mode
-is active (BATT_HD) and when it is not active (AC_HD). The defaults are
-20 seconds (value 4) for BATT_HD  and 2 hours (value 244) for AC_HD. The
-possible values are those listed in the manual page for "hdparm" for the
-"-S" option.
-
-HD:
-
-The devices for which the spindown timeout should be adjusted by laptop mode.
-Default is /dev/hda. If you specify multiple devices, separate them by a space.
-
-READAHEAD:
-
-Disk readahead, in 512-byte sectors, while laptop mode is active. A large
-readahead can prevent disk accesses for things like executable pages (which are
-loaded on demand while the application executes) and sequentially accessed data
-(MP3s).
-
-DO_REMOUNTS:
-
-The control script automatically remounts any mounted journaled filesystems
-with appropriate commit interval options. When this option is set to 0, this
-feature is disabled.
-
-DO_REMOUNT_NOATIME:
-
-When remounting, should the filesystems be remounted with the noatime option?
-Normally, this is set to "1" (enabled), but there may be programs that require
-access time recording.
-
-DIRTY_RATIO:
-
-The percentage of memory that is allowed to contain "dirty" or unsaved data
-before a writeback is forced, while laptop mode is active. Corresponds to
-the /proc/sys/vm/dirty_ratio sysctl.
-
-DIRTY_BACKGROUND_RATIO:
-
-The percentage of memory that is allowed to contain "dirty" or unsaved data
-after a forced writeback is done due to an exceeding of DIRTY_RATIO. Set
-this nice and low. This corresponds to the /proc/sys/vm/dirty_background_ratio
-sysctl.
-
-Note that the behaviour of dirty_background_ratio is quite different
-when laptop mode is active and when it isn't. When laptop mode is inactive,
-dirty_background_ratio is the threshold percentage at which background writeouts
-start taking place. When laptop mode is active, however, background writeouts
-are disabled, and the dirty_background_ratio only determines how much writeback
-is done when dirty_ratio is reached.
-
-DO_CPU:
-
-Enable CPU frequency scaling when in laptop mode. (Requires CPUFreq to be setup.
-See Documentation/admin-guide/pm/cpufreq.rst for more info. Disabled by default.)
-
-CPU_MAXFREQ:
-
-When on battery, what is the maximum CPU speed that the system should use? Legal
-values are "slowest" for the slowest speed that your CPU is able to operate at,
-or a value listed in /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies.
-
-
-Tips & Tricks
--------------
-
-* Bartek Kania reports getting up to 50 minutes of extra battery life (on top
-  of his regular 3 to 3.5 hours) using a spindown time of 5 seconds (BATT_HD=1).
-
-* You can spin down the disk while playing MP3, by setting disk readahead
-  to 8MB (READAHEAD=16384). Effectively, the disk will read a complete MP3 at
-  once, and will then spin down while the MP3 is playing. (Thanks to Bartek
-  Kania.)
-
-* Drew Scott Daniels observed: "I don't know why, but when I decrease the number
-  of colours that my display uses it consumes less battery power. I've seen
-  this on powerbooks too. I hope that this is a piece of information that
-  might be useful to the Laptop Mode patch or its users."
-
-* In syslog.conf, you can prefix entries with a dash ``-'' to omit syncing the
-  file after every logging. When you're using laptop-mode and your disk doesn't
-  spin down, this is a likely culprit.
-
-* Richard Atterer observed that laptop mode does not work well with noflushd
-  (http://noflushd.sourceforge.net/), it seems that noflushd prevents laptop-mode
-  from doing its thing.
-
-* If you're worried about your data, you might want to consider using a USB
-  memory stick or something like that as a "working area". (Be aware though
-  that flash memory can only handle a limited number of writes, and overuse
-  may wear out your memory stick pretty quickly. Do _not_ use journalling
-  filesystems on flash memory sticks.)
-
-
-Configuration file for control and ACPI battery scripts
--------------------------------------------------------
-
-This allows the tunables to be changed for the scripts via an external
-configuration file
-
-It should be installed as /etc/default/laptop-mode on Debian, and as
-/etc/sysconfig/laptop-mode on Red Hat, SUSE, Mandrake, and other work-alikes.
-
---------------------CONFIG FILE BEGIN-------------------------------------------
-# Maximum time, in seconds, of hard drive spindown time that you are
-# comfortable with. Worst case, it's possible that you could lose this
-# amount of work if your battery fails you while in laptop mode.
-#MAX_AGE=600
-
-# Automatically disable laptop mode when the number of minutes of battery
-# that you have left goes below this threshold.
-MINIMUM_BATTERY_MINUTES=10
-
-# Read-ahead, in 512-byte sectors. You can spin down the disk while playing MP3/OGG
-# by setting the disk readahead to 8MB (READAHEAD=16384). Effectively, the disk
-# will read a complete MP3 at once, and will then spin down while the MP3/OGG is
-# playing.
-#READAHEAD=4096
-
-# Shall we remount journaled fs. with appropriate commit interval? (1=yes)
-#DO_REMOUNTS=1
-
-# And shall we add the "noatime" option to that as well? (1=yes)
-#DO_REMOUNT_NOATIME=1
-
-# Dirty synchronous ratio.  At this percentage of dirty pages the process
-# which
-# calls write() does its own writeback
-#DIRTY_RATIO=40
-
-#
-# Allowed dirty background ratio, in percent.  Once DIRTY_RATIO has been
-# exceeded, the kernel will wake flusher threads which will then reduce the
-# amount of dirty memory to dirty_background_ratio.  Set this nice and low,
-# so once some writeout has commenced, we do a lot of it.
-#
-#DIRTY_BACKGROUND_RATIO=5
-
-# kernel default dirty buffer age
-#DEF_AGE=30
-#DEF_UPDATE=5
-#DEF_DIRTY_BACKGROUND_RATIO=10
-#DEF_DIRTY_RATIO=40
-#DEF_XFS_AGE_BUFFER=15
-#DEF_XFS_SYNC_INTERVAL=30
-#DEF_XFS_BUFD_INTERVAL=1
-
-# This must be adjusted manually to the value of HZ in the running kernel
-# on 2.4, until the XFS people change their 2.4 external interfaces to work in
-# centisecs. This can be automated, but it's a work in progress that still
-# needs# some fixes. On 2.6 kernels, XFS uses USER_HZ instead of HZ for
-# external interfaces, and that is currently always set to 100. So you don't
-# need to change this on 2.6.
-#XFS_HZ=100
-
-# Should the maximum CPU frequency be adjusted down while on battery?
-# Requires CPUFreq to be setup.
-# See Documentation/admin-guide/pm/cpufreq.rst for more info
-#DO_CPU=0
-
-# When on battery what is the maximum CPU speed that the system should
-# use? Legal values are "slowest" for the slowest speed that your
-# CPU is able to operate at, or a value listed in:
-# /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies
-# Only applicable if DO_CPU=1.
-#CPU_MAXFREQ=slowest
-
-# Idle timeout for your hard drive (man hdparm for valid values, -S option)
-# Default is 2 hours on AC (AC_HD=244) and 20 seconds for battery (BATT_HD=4).
-#AC_HD=244
-#BATT_HD=4
-
-# The drives for which to adjust the idle timeout. Separate them by a space,
-# e.g. HD="/dev/hda /dev/hdb".
-#HD="/dev/hda"
-
-# Set the spindown timeout on a hard drive?
-#DO_HD=1
-
---------------------CONFIG FILE END---------------------------------------------
-
-
-Control script
---------------
-
-Please note that this control script works for the Linux 2.4 and 2.6 series (thanks
-to Kiko Piris).
-
---------------------CONTROL SCRIPT BEGIN----------------------------------------
-#!/bin/bash
-
-# start or stop laptop_mode, best run by a power management daemon when
-# ac gets connected/disconnected from a laptop
-#
-# install as /sbin/laptop_mode
-#
-# Contributors to this script:   Kiko Piris
-#                               Bart Samwel
-#                               Micha Feigin
-#                               Andrew Morton
-#                               Herve Eychenne
-#                               Dax Kelson
-#
-# Original Linux 2.4 version by: Jens Axboe
-
-#############################################################################
-
-# Source config
-if [ -f /etc/default/laptop-mode ] ; then
-       # Debian
-       . /etc/default/laptop-mode
-elif [ -f /etc/sysconfig/laptop-mode ] ; then
-       # Others
-        . /etc/sysconfig/laptop-mode
-fi
-
-# Don't raise an error if the config file is incomplete
-# set defaults instead:
-
-# Maximum time, in seconds, of hard drive spindown time that you are
-# comfortable with. Worst case, it's possible that you could lose this
-# amount of work if your battery fails you while in laptop mode.
-MAX_AGE=${MAX_AGE:-'600'}
-
-# Read-ahead, in kilobytes
-READAHEAD=${READAHEAD:-'4096'}
-
-# Shall we remount journaled fs. with appropriate commit interval? (1=yes)
-DO_REMOUNTS=${DO_REMOUNTS:-'1'}
-
-# And shall we add the "noatime" option to that as well? (1=yes)
-DO_REMOUNT_NOATIME=${DO_REMOUNT_NOATIME:-'1'}
-
-# Shall we adjust the idle timeout on a hard drive?
-DO_HD=${DO_HD:-'1'}
-
-# Adjust idle timeout on which hard drive?
-HD="${HD:-'/dev/hda'}"
-
-# spindown time for HD (hdparm -S values)
-AC_HD=${AC_HD:-'244'}
-BATT_HD=${BATT_HD:-'4'}
-
-# Dirty synchronous ratio.  At this percentage of dirty pages the process which
-# calls write() does its own writeback
-DIRTY_RATIO=${DIRTY_RATIO:-'40'}
-
-# cpu frequency scaling
-# See Documentation/admin-guide/pm/cpufreq.rst for more info
-DO_CPU=${CPU_MANAGE:-'0'}
-CPU_MAXFREQ=${CPU_MAXFREQ:-'slowest'}
-
-#
-# Allowed dirty background ratio, in percent.  Once DIRTY_RATIO has been
-# exceeded, the kernel will wake flusher threads which will then reduce the
-# amount of dirty memory to dirty_background_ratio.  Set this nice and low,
-# so once some writeout has commenced, we do a lot of it.
-#
-DIRTY_BACKGROUND_RATIO=${DIRTY_BACKGROUND_RATIO:-'5'}
-
-# kernel default dirty buffer age
-DEF_AGE=${DEF_AGE:-'30'}
-DEF_UPDATE=${DEF_UPDATE:-'5'}
-DEF_DIRTY_BACKGROUND_RATIO=${DEF_DIRTY_BACKGROUND_RATIO:-'10'}
-DEF_DIRTY_RATIO=${DEF_DIRTY_RATIO:-'40'}
-DEF_XFS_AGE_BUFFER=${DEF_XFS_AGE_BUFFER:-'15'}
-DEF_XFS_SYNC_INTERVAL=${DEF_XFS_SYNC_INTERVAL:-'30'}
-DEF_XFS_BUFD_INTERVAL=${DEF_XFS_BUFD_INTERVAL:-'1'}
-
-# This must be adjusted manually to the value of HZ in the running kernel
-# on 2.4, until the XFS people change their 2.4 external interfaces to work in
-# centisecs. This can be automated, but it's a work in progress that still needs
-# some fixes. On 2.6 kernels, XFS uses USER_HZ instead of HZ for external
-# interfaces, and that is currently always set to 100. So you don't need to
-# change this on 2.6.
-XFS_HZ=${XFS_HZ:-'100'}
-
-#############################################################################
-
-KLEVEL="$(uname -r |
-             {
-              IFS='.' read a b c
-              echo $a.$b
-            }
-)"
-case "$KLEVEL" in
-       "2.4"|"2.6")
-               ;;
-       *)
-               echo "Unhandled kernel version: $KLEVEL ('uname -r' = '$(uname -r)')" >&2
-               exit 1
-               ;;
-esac
-
-if [ ! -e /proc/sys/vm/laptop_mode ] ; then
-       echo "Kernel is not patched with laptop_mode patch." >&2
-       exit 1
-fi
-
-if [ ! -w /proc/sys/vm/laptop_mode ] ; then
-       echo "You do not have enough privileges to enable laptop_mode." >&2
-       exit 1
-fi
-
-# Remove an option (the first parameter) of the form option=<number> from
-# a mount options string (the rest of the parameters).
-parse_mount_opts () {
-       OPT="$1"
-       shift
-       echo ",$*," | sed               \
-        -e 's/,'"$OPT"'=[0-9]*,/,/g'   \
-        -e 's/,,*/,/g'                 \
-        -e 's/^,//'                    \
-        -e 's/,$//'
-}
-
-# Remove an option (the first parameter) without any arguments from
-# a mount option string (the rest of the parameters).
-parse_nonumber_mount_opts () {
-       OPT="$1"
-       shift
-       echo ",$*," | sed               \
-        -e 's/,'"$OPT"',/,/g'          \
-        -e 's/,,*/,/g'                 \
-        -e 's/^,//'                    \
-        -e 's/,$//'
-}
-
-# Find out the state of a yes/no option (e.g. "atime"/"noatime") in
-# fstab for a given filesystem, and use this state to replace the
-# value of the option in another mount options string. The device
-# is the first argument, the option name the second, and the default
-# value the third. The remainder is the mount options string.
-#
-# Example:
-# parse_yesno_opts_wfstab /dev/hda1 atime atime defaults,noatime
-#
-# If fstab contains, say, "rw" for this filesystem, then the result
-# will be "defaults,atime".
-parse_yesno_opts_wfstab () {
-       L_DEV="$1"
-       OPT="$2"
-       DEF_OPT="$3"
-       shift 3
-       L_OPTS="$*"
-       PARSEDOPTS1="$(parse_nonumber_mount_opts $OPT $L_OPTS)"
-       PARSEDOPTS1="$(parse_nonumber_mount_opts no$OPT $PARSEDOPTS1)"
-       # Watch for a default atime in fstab
-       FSTAB_OPTS="$(awk '$1 == "'$L_DEV'" { print $4 }' /etc/fstab)"
-       if echo "$FSTAB_OPTS" | grep "$OPT" > /dev/null ; then
-               # option specified in fstab: extract the value and use it
-               if echo "$FSTAB_OPTS" | grep "no$OPT" > /dev/null ; then
-                       echo "$PARSEDOPTS1,no$OPT"
-               else
-                       # no$OPT not found -- so we must have $OPT.
-                       echo "$PARSEDOPTS1,$OPT"
-               fi
-       else
-               # option not specified in fstab -- choose the default.
-               echo "$PARSEDOPTS1,$DEF_OPT"
-       fi
-}
-
-# Find out the state of a numbered option (e.g. "commit=NNN") in
-# fstab for a given filesystem, and use this state to replace the
-# value of the option in another mount options string. The device
-# is the first argument, and the option name the second. The
-# remainder is the mount options string in which the replacement
-# must be done.
-#
-# Example:
-# parse_mount_opts_wfstab /dev/hda1 commit defaults,commit=7
-#
-# If fstab contains, say, "commit=3,rw" for this filesystem, then the
-# result will be "rw,commit=3".
-parse_mount_opts_wfstab () {
-       L_DEV="$1"
-       OPT="$2"
-       shift 2
-       L_OPTS="$*"
-       PARSEDOPTS1="$(parse_mount_opts $OPT $L_OPTS)"
-       # Watch for a default commit in fstab
-       FSTAB_OPTS="$(awk '$1 == "'$L_DEV'" { print $4 }' /etc/fstab)"
-       if echo "$FSTAB_OPTS" | grep "$OPT=" > /dev/null ; then
-               # option specified in fstab: extract the value, and use it
-               echo -n "$PARSEDOPTS1,$OPT="
-               echo ",$FSTAB_OPTS," | sed \
-                -e 's/.*,'"$OPT"'=//'  \
-                -e 's/,.*//'
-       else
-               # option not specified in fstab: set it to 0
-               echo "$PARSEDOPTS1,$OPT=0"
-       fi
-}
-
-deduce_fstype () {
-       MP="$1"
-       # My root filesystem unfortunately has
-       # type "unknown" in /etc/mtab. If we encounter
-       # "unknown", we try to get the type from fstab.
-       cat /etc/fstab |
-       grep -v '^#' |
-       while read FSTAB_DEV FSTAB_MP FSTAB_FST FSTAB_OPTS FSTAB_DUMP FSTAB_DUMP ; do
-               if [ "$FSTAB_MP" = "$MP" ]; then
-                       echo $FSTAB_FST
-                       exit 0
-               fi
-       done
-}
-
-if [ $DO_REMOUNT_NOATIME -eq 1 ] ; then
-       NOATIME_OPT=",noatime"
-fi
-
-case "$1" in
-       start)
-               AGE=$((100*$MAX_AGE))
-               XFS_AGE=$(($XFS_HZ*$MAX_AGE))
-               echo -n "Starting laptop_mode"
-
-               if [ -d /proc/sys/vm/pagebuf ] ; then
-                       # (For 2.4 and early 2.6.)
-                       # This only needs to be set, not reset -- it is only used when
-                       # laptop mode is enabled.
-                       echo $XFS_AGE > /proc/sys/vm/pagebuf/lm_flush_age
-                       echo $XFS_AGE > /proc/sys/fs/xfs/lm_sync_interval
-               elif [ -f /proc/sys/fs/xfs/lm_age_buffer ] ; then
-                       # (A couple of early 2.6 laptop mode patches had these.)
-                       # The same goes for these.
-                       echo $XFS_AGE > /proc/sys/fs/xfs/lm_age_buffer
-                       echo $XFS_AGE > /proc/sys/fs/xfs/lm_sync_interval
-               elif [ -f /proc/sys/fs/xfs/age_buffer ] ; then
-                       # (2.6.6)
-                       # But not for these -- they are also used in normal
-                       # operation.
-                       echo $XFS_AGE > /proc/sys/fs/xfs/age_buffer
-                       echo $XFS_AGE > /proc/sys/fs/xfs/sync_interval
-               elif [ -f /proc/sys/fs/xfs/age_buffer_centisecs ] ; then
-                       # (2.6.7 upwards)
-                       # And not for these either. These are in centisecs,
-                       # not USER_HZ, so we have to use $AGE, not $XFS_AGE.
-                       echo $AGE > /proc/sys/fs/xfs/age_buffer_centisecs
-                       echo $AGE > /proc/sys/fs/xfs/xfssyncd_centisecs
-                       echo 3000 > /proc/sys/fs/xfs/xfsbufd_centisecs
-               fi
-
-               case "$KLEVEL" in
-                       "2.4")
-                               echo 1                                  > /proc/sys/vm/laptop_mode
-                               echo "30 500 0 0 $AGE $AGE 60 20 0"     > /proc/sys/vm/bdflush
-                               ;;
-                       "2.6")
-                               echo 5                                  > /proc/sys/vm/laptop_mode
-                               echo "$AGE"                             > /proc/sys/vm/dirty_writeback_centisecs
-                               echo "$AGE"                             > /proc/sys/vm/dirty_expire_centisecs
-                               echo "$DIRTY_RATIO"                     > /proc/sys/vm/dirty_ratio
-                               echo "$DIRTY_BACKGROUND_RATIO"          > /proc/sys/vm/dirty_background_ratio
-                               ;;
-               esac
-               if [ $DO_REMOUNTS -eq 1 ]; then
-                       cat /etc/mtab | while read DEV MP FST OPTS DUMP PASS ; do
-                               PARSEDOPTS="$(parse_mount_opts "$OPTS")"
-                               if [ "$FST" = 'unknown' ]; then
-                                       FST=$(deduce_fstype $MP)
-                               fi
-                               case "$FST" in
-                                       "ext3"|"reiserfs")
-                                               PARSEDOPTS="$(parse_mount_opts commit "$OPTS")"
-                                               mount $DEV -t $FST $MP -o remount,$PARSEDOPTS,commit=$MAX_AGE$NOATIME_OPT
-                                               ;;
-                                       "xfs")
-                                               mount $DEV -t $FST $MP -o remount,$OPTS$NOATIME_OPT
-                                               ;;
-                               esac
-                               if [ -b $DEV ] ; then
-                                       blockdev --setra $(($READAHEAD * 2)) $DEV
-                               fi
-                       done
-               fi
-               if [ $DO_HD -eq 1 ] ; then
-                       for THISHD in $HD ; do
-                               /sbin/hdparm -S $BATT_HD $THISHD > /dev/null 2>&1
-                               /sbin/hdparm -B 1 $THISHD > /dev/null 2>&1
-                       done
-               fi
-               if [ $DO_CPU -eq 1 -a -e /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq ]; then
-                       if [ $CPU_MAXFREQ = 'slowest' ]; then
-                               CPU_MAXFREQ=`cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq`
-                       fi
-                       echo $CPU_MAXFREQ > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
-               fi
-               echo "."
-               ;;
-       stop)
-               U_AGE=$((100*$DEF_UPDATE))
-               B_AGE=$((100*$DEF_AGE))
-               echo -n "Stopping laptop_mode"
-               echo 0 > /proc/sys/vm/laptop_mode
-               if [ -f /proc/sys/fs/xfs/age_buffer -a ! -f /proc/sys/fs/xfs/lm_age_buffer ] ; then
-                       # These need to be restored, if there are no lm_*.
-                       echo $(($XFS_HZ*$DEF_XFS_AGE_BUFFER))           > /proc/sys/fs/xfs/age_buffer
-                       echo $(($XFS_HZ*$DEF_XFS_SYNC_INTERVAL))        > /proc/sys/fs/xfs/sync_interval
-               elif [ -f /proc/sys/fs/xfs/age_buffer_centisecs ] ; then
-                       # These need to be restored as well.
-                       echo $((100*$DEF_XFS_AGE_BUFFER))       > /proc/sys/fs/xfs/age_buffer_centisecs
-                       echo $((100*$DEF_XFS_SYNC_INTERVAL))    > /proc/sys/fs/xfs/xfssyncd_centisecs
-                       echo $((100*$DEF_XFS_BUFD_INTERVAL))    > /proc/sys/fs/xfs/xfsbufd_centisecs
-               fi
-               case "$KLEVEL" in
-                       "2.4")
-                               echo "30 500 0 0 $U_AGE $B_AGE 60 20 0" > /proc/sys/vm/bdflush
-                               ;;
-                       "2.6")
-                               echo "$U_AGE"                           > /proc/sys/vm/dirty_writeback_centisecs
-                               echo "$B_AGE"                           > /proc/sys/vm/dirty_expire_centisecs
-                               echo "$DEF_DIRTY_RATIO"                 > /proc/sys/vm/dirty_ratio
-                               echo "$DEF_DIRTY_BACKGROUND_RATIO"      > /proc/sys/vm/dirty_background_ratio
-                               ;;
-               esac
-               if [ $DO_REMOUNTS -eq 1 ] ; then
-                       cat /etc/mtab | while read DEV MP FST OPTS DUMP PASS ; do
-                               # Reset commit and atime options to defaults.
-                               if [ "$FST" = 'unknown' ]; then
-                                       FST=$(deduce_fstype $MP)
-                               fi
-                               case "$FST" in
-                                       "ext3"|"reiserfs")
-                                               PARSEDOPTS="$(parse_mount_opts_wfstab $DEV commit $OPTS)"
-                                               PARSEDOPTS="$(parse_yesno_opts_wfstab $DEV atime atime $PARSEDOPTS)"
-                                               mount $DEV -t $FST $MP -o remount,$PARSEDOPTS
-                                               ;;
-                                       "xfs")
-                                               PARSEDOPTS="$(parse_yesno_opts_wfstab $DEV atime atime $OPTS)"
-                                               mount $DEV -t $FST $MP -o remount,$PARSEDOPTS
-                                               ;;
-                               esac
-                               if [ -b $DEV ] ; then
-                                       blockdev --setra 256 $DEV
-                               fi
-                       done
-               fi
-               if [ $DO_HD -eq 1 ] ; then
-                       for THISHD in $HD ; do
-                               /sbin/hdparm -S $AC_HD $THISHD > /dev/null 2>&1
-                               /sbin/hdparm -B 255 $THISHD > /dev/null 2>&1
-                       done
-               fi
-               if [ $DO_CPU -eq 1 -a -e /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq ]; then
-                       echo `cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq` > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
-               fi
-               echo "."
-               ;;
-       *)
-               echo "Usage: $0 {start|stop}" 2>&1
-               exit 1
-               ;;
-
-esac
-
-exit 0
---------------------CONTROL SCRIPT END------------------------------------------
-
-
-ACPI integration
-----------------
-
-Dax Kelson submitted this so that the ACPI acpid daemon will
-kick off the laptop_mode script and run hdparm. The part that
-automatically disables laptop mode when the battery is low was
-written by Jan Topinski.
-
------------------/etc/acpi/events/ac_adapter BEGIN------------------------------
-event=ac_adapter
-action=/etc/acpi/actions/ac.sh %e
-----------------/etc/acpi/events/ac_adapter END---------------------------------
-
-
------------------/etc/acpi/events/battery BEGIN---------------------------------
-event=battery.*
-action=/etc/acpi/actions/battery.sh %e
-----------------/etc/acpi/events/battery END------------------------------------
-
-
-----------------/etc/acpi/actions/ac.sh BEGIN-----------------------------------
-#!/bin/bash
-
-# ac on/offline event handler
-
-status=`awk '/^state: / { print $2 }' /proc/acpi/ac_adapter/$2/state`
-
-case $status in
-        "on-line")
-                /sbin/laptop_mode stop
-                exit 0
-        ;;
-        "off-line")
-                /sbin/laptop_mode start
-                exit 0
-        ;;
-esac
----------------------------/etc/acpi/actions/ac.sh END--------------------------
-
-
----------------------------/etc/acpi/actions/battery.sh BEGIN-------------------
-#! /bin/bash
-
-# Automatically disable laptop mode when the battery almost runs out.
-
-BATT_INFO=/proc/acpi/battery/$2/state
-
-if [[ -f /proc/sys/vm/laptop_mode ]]
-then
-   LM=`cat /proc/sys/vm/laptop_mode`
-   if [[ $LM -gt 0 ]]
-   then
-     if [[ -f $BATT_INFO ]]
-     then
-        # Source the config file only now that we know we need
-        if [ -f /etc/default/laptop-mode ] ; then
-                # Debian
-                . /etc/default/laptop-mode
-        elif [ -f /etc/sysconfig/laptop-mode ] ; then
-                # Others
-                . /etc/sysconfig/laptop-mode
-        fi
-        MINIMUM_BATTERY_MINUTES=${MINIMUM_BATTERY_MINUTES:-'10'}
-
-        ACTION="`cat $BATT_INFO | grep charging | cut -c 26-`"
-        if [[ ACTION -eq "discharging" ]]
-        then
-           PRESENT_RATE=`cat $BATT_INFO | grep "present rate:" | sed  "s/.* \([0-9][0-9]* \).*/\1/" `
-           REMAINING=`cat $BATT_INFO | grep "remaining capacity:" | sed  "s/.* \([0-9][0-9]* \).*/\1/" `
-        fi
-        if (($REMAINING * 60 / $PRESENT_RATE < $MINIMUM_BATTERY_MINUTES))
-        then
-           /sbin/laptop_mode stop
-        fi
-     else
-       logger -p daemon.warning "You are using laptop mode and your battery interface $BATT_INFO is missing. This may lead to loss of data when the battery runs out. Check kernel ACPI support and /proc/acpi/battery folder, and edit /etc/acpi/battery.sh to set BATT_INFO to the correct path."
-     fi
-   fi
-fi
----------------------------/etc/acpi/actions/battery.sh END--------------------
-
-
-Monitoring tool
----------------
-
-Bartek Kania submitted this, it can be used to measure how much time your disk
-spends spun up/down.  See tools/laptop/dslm/dslm.c
diff --git a/Documentation/laptops/lg-laptop.rst b/Documentation/laptops/lg-laptop.rst
deleted file mode 100644 (file)
index f2c2ffe..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0+
-
-:orphan:
-
-LG Gram laptop extra features
-=============================
-
-By Matan Ziv-Av <matan@svgalib.org>
-
-
-Hotkeys
--------
-
-The following FN keys are ignored by the kernel without this driver:
-
-- FN-F1 (LG control panel)   - Generates F15
-- FN-F5 (Touchpad toggle)    - Generates F13
-- FN-F6 (Airplane mode)      - Generates RFKILL
-- FN-F8 (Keyboard backlight) - Generates F16.
-  This key also changes keyboard backlight mode.
-- FN-F9 (Reader mode)        - Generates F14
-
-The rest of the FN keys work without a need for a special driver.
-
-
-Reader mode
------------
-
-Writing 0/1 to /sys/devices/platform/lg-laptop/reader_mode disables/enables
-reader mode. In this mode the screen colors change (blue color reduced),
-and the reader mode indicator LED (on F9 key) turns on.
-
-
-FN Lock
--------
-
-Writing 0/1 to /sys/devices/platform/lg-laptop/fn_lock disables/enables
-FN lock.
-
-
-Battery care limit
-------------------
-
-Writing 80/100 to /sys/devices/platform/lg-laptop/battery_care_limit
-sets the maximum capacity to charge the battery. Limiting the charge
-reduces battery capacity loss over time.
-
-This value is reset to 100 when the kernel boots.
-
-
-Fan mode
---------
-
-Writing 1/0 to /sys/devices/platform/lg-laptop/fan_mode disables/enables
-the fan silent mode.
-
-
-USB charge
-----------
-
-Writing 0/1 to /sys/devices/platform/lg-laptop/usb_charge disables/enables
-charging another device from the USB port while the device is turned off.
-
-This value is reset to 0 when the kernel boots.
-
-
-LEDs
-~~~~
-
-The are two LED devices supported by the driver:
-
-Keyboard backlight
-------------------
-
-A led device named kbd_led controls the keyboard backlight. There are three
-lighting level: off (0), low (127) and high (255).
-
-The keyboard backlight is also controlled by the key combination FN-F8
-which cycles through those levels.
-
-
-Touchpad indicator LED
-----------------------
-
-On the F5 key. Controlled by led device names tpad_led.
diff --git a/Documentation/laptops/sony-laptop.txt b/Documentation/laptops/sony-laptop.txt
deleted file mode 100644 (file)
index 978b1e6..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-Sony Notebook Control Driver (SNC) Readme
------------------------------------------
-       Copyright (C) 2004- 2005 Stelian Pop <stelian@popies.net>
-       Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
-
-This mini-driver drives the SNC and SPIC device present in the ACPI BIOS of the
-Sony Vaio laptops. This driver mixes both devices functions under the same
-(hopefully consistent) interface. This also means that the sonypi driver is
-obsoleted by sony-laptop now.
-
-Fn keys (hotkeys):
-------------------
-Some models report hotkeys through the SNC or SPIC devices, such events are
-reported both through the ACPI subsystem as acpi events and through the INPUT
-subsystem. See the logs of /proc/bus/input/devices to find out what those
-events are and which input devices are created by the driver.
-Additionally, loading the driver with the debug option will report all events
-in the kernel log.
-
-The "scancodes" passed to the input system (that can be remapped with udev)
-are indexes to the table "sony_laptop_input_keycode_map" in the sony-laptop.c
-module.  For example the "FN/E" key combination (EJECTCD on some models)
-generates the scancode 20 (0x14).
-
-Backlight control:
-------------------
-If your laptop model supports it, you will find sysfs files in the
-/sys/class/backlight/sony/
-directory. You will be able to query and set the current screen
-brightness:
-       brightness              get/set screen brightness (an integer
-                               between 0 and 7)
-       actual_brightness       reading from this file will query the HW
-                               to get real brightness value
-       max_brightness          the maximum brightness value
-
-
-Platform specific:
-------------------
-Loading the sony-laptop module will create a
-/sys/devices/platform/sony-laptop/
-directory populated with some files.
-
-You then read/write integer values from/to those files by using
-standard UNIX tools.
-
-The files are:
-       brightness_default      screen brightness which will be set
-                               when the laptop will be rebooted
-       cdpower                 power on/off the internal CD drive
-       audiopower              power on/off the internal sound card
-       lanpower                power on/off the internal ethernet card
-                               (only in debug mode)
-       bluetoothpower          power on/off the internal bluetooth device
-       fanspeed                get/set the fan speed
-
-Note that some files may be missing if they are not supported
-by your particular laptop model.
-
-Example usage:
-       # echo "1" > /sys/devices/platform/sony-laptop/brightness_default
-sets the lowest screen brightness for the next and later reboots,
-       # echo "8" > /sys/devices/platform/sony-laptop/brightness_default
-sets the highest screen brightness for the next and later reboots,
-       # cat /sys/devices/platform/sony-laptop/brightness_default
-retrieves the value.
-
-       # echo "0" > /sys/devices/platform/sony-laptop/audiopower
-powers off the sound card,
-       # echo "1" > /sys/devices/platform/sony-laptop/audiopower
-powers on the sound card.
-
-
-RFkill control:
----------------
-More recent Vaio models expose a consistent set of ACPI methods to
-control radio frequency emitting devices. If you are a lucky owner of
-such a laptop you will find the necessary rfkill devices under
-/sys/class/rfkill. Check those starting with sony-* in
-       # grep . /sys/class/rfkill/*/{state,name}
-
-
-Development:
-------------
-
-If you want to help with the development of this driver (and
-you are not afraid of any side effects doing strange things with
-your ACPI BIOS could have on your laptop), load the driver and
-pass the option 'debug=1'.
-
-REPEAT: DON'T DO THIS IF YOU DON'T LIKE RISKY BUSINESS.
-
-In your kernel logs you will find the list of all ACPI methods
-the SNC device has on your laptop.
-
-* For new models you will see a long list of meaningless method names,
-reading the DSDT table source should reveal that:
-(1) the SNC device uses an internal capability lookup table
-(2) SN00 is used to find values in the lookup table
-(3) SN06 and SN07 are used to call into the real methods based on
-    offsets you can obtain iterating the table using SN00
-(4) SN02 used to enable events.
-Some values in the capability lookup table are more or less known, see
-the code for all sony_call_snc_handle calls, others are more obscure.
-
-* For old models you can see the GCDP/GCDP methods used to pwer on/off
-the CD drive, but there are others and they are usually different from
-model to model.
-
-I HAVE NO IDEA WHAT THOSE METHODS DO.
-
-The sony-laptop driver creates, for some of those methods (the most
-current ones found on several Vaio models), an entry under
-/sys/devices/platform/sony-laptop, just like the 'cdpower' one.
-You can create other entries corresponding to your own laptop methods by
-further editing the source (see the 'sony_nc_values' table, and add a new
-entry to this table with your get/set method names using the
-SNC_HANDLE_NAMES macro).
-
-Your mission, should you accept it, is to try finding out what
-those entries are for, by reading/writing random values from/to those
-files and find out what is the impact on your laptop.
-
-Should you find anything interesting, please report it back to me,
-I will not disavow all knowledge of your actions :)
-
-See also http://www.linux.it/~malattia/wiki/index.php/Sony_drivers for other
-useful info.
-
-Bugs/Limitations:
------------------
-
-* This driver is not based on official documentation from Sony
-  (because there is none), so there is no guarantee this driver
-  will work at all, or do the right thing. Although this hasn't
-  happened to me, this driver could do very bad things to your
-  laptop, including permanent damage.
-
-* The sony-laptop and sonypi drivers do not interact at all. In the
-  future, sonypi will be removed and replaced by sony-laptop.
-
-* spicctrl, which is the userspace tool used to communicate with the
-  sonypi driver (through /dev/sonypi) is deprecated as well since all
-  its features are now available under the sysfs tree via sony-laptop.
diff --git a/Documentation/laptops/sonypi.txt b/Documentation/laptops/sonypi.txt
deleted file mode 100644 (file)
index 606bdb9..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-Sony Programmable I/O Control Device Driver Readme
---------------------------------------------------
-       Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net>
-       Copyright (C) 2001-2002 Alcôve <www.alcove.com>
-       Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
-       Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
-       Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
-       Copyright (C) 2000 Andrew Tridgell <tridge@samba.org>
-
-This driver enables access to the Sony Programmable I/O Control Device which
-can be found in many Sony Vaio laptops. Some newer Sony laptops (seems to be
-limited to new FX series laptops, at least the FX501 and the FX702) lack a
-sonypi device and are not supported at all by this driver.
-
-It will give access (through a user space utility) to some events those laptops
-generate, like:
-       - jogdial events (the small wheel on the side of Vaios)
-       - capture button events (only on Vaio Picturebook series)
-       - Fn keys
-       - bluetooth button (only on C1VR model)
-       - programmable keys, back, help, zoom, thumbphrase buttons, etc.
-         (when available)
-
-Those events (see linux/sonypi.h) can be polled using the character device node
-/dev/sonypi (major 10, minor auto allocated or specified as a option).
-A simple daemon which translates the jogdial movements into mouse wheel events
-can be downloaded at: <http://popies.net/sonypi/>
-
-Another option to intercept the events is to get them directly through the
-input layer.
-
-This driver supports also some ioctl commands for setting the LCD screen
-brightness and querying the batteries charge information (some more
-commands may be added in the future).
-
-This driver can also be used to set the camera controls on Picturebook series
-(brightness, contrast etc), and is used by the video4linux driver for the
-Motion Eye camera.
-
-Please note that this driver was created by reverse engineering the Windows
-driver and the ACPI BIOS, because Sony doesn't agree to release any programming
-specs for its laptops. If someone convinces them to do so, drop me a note.
-
-Driver options:
----------------
-
-Several options can be passed to the sonypi driver using the standard
-module argument syntax (<param>=<value> when passing the option to the
-module or sonypi.<param>=<value> on the kernel boot line when sonypi is
-statically linked into the kernel). Those options are:
-
-       minor:          minor number of the misc device /dev/sonypi,
-                       default is -1 (automatic allocation, see /proc/misc
-                       or kernel logs)
-
-       camera:         if you have a PictureBook series Vaio (with the
-                       integrated MotionEye camera), set this parameter to 1
-                       in order to let the driver access to the camera
-
-       fnkeyinit:      on some Vaios (C1VE, C1VR etc), the Fn key events don't
-                       get enabled unless you set this parameter to 1.
-                       Do not use this option unless it's actually necessary,
-                       some Vaio models don't deal well with this option.
-                       This option is available only if the kernel is
-                       compiled without ACPI support (since it conflicts
-                       with it and it shouldn't be required anyway if
-                       ACPI is already enabled).
-
-       verbose:        set to 1 to print unknown events received from the
-                       sonypi device.
-                       set to 2 to print all events received from the
-                       sonypi device.
-
-       compat:         uses some compatibility code for enabling the sonypi
-                       events. If the driver worked for you in the past
-                       (prior to version 1.5) and does not work anymore,
-                       add this option and report to the author.
-
-       mask:           event mask telling the driver what events will be
-                       reported to the user. This parameter is required for
-                       some Vaio models where the hardware reuses values
-                       used in other Vaio models (like the FX series who does
-                       not have a jogdial but reuses the jogdial events for
-                       programmable keys events). The default event mask is
-                       set to 0xffffffff, meaning that all possible events
-                       will be tried. You can use the following bits to
-                       construct your own event mask (from
-                       drivers/char/sonypi.h):
-                               SONYPI_JOGGER_MASK              0x0001
-                               SONYPI_CAPTURE_MASK             0x0002
-                               SONYPI_FNKEY_MASK               0x0004
-                               SONYPI_BLUETOOTH_MASK           0x0008
-                               SONYPI_PKEY_MASK                0x0010
-                               SONYPI_BACK_MASK                0x0020
-                               SONYPI_HELP_MASK                0x0040
-                               SONYPI_LID_MASK                 0x0080
-                               SONYPI_ZOOM_MASK                0x0100
-                               SONYPI_THUMBPHRASE_MASK         0x0200
-                               SONYPI_MEYE_MASK                0x0400
-                               SONYPI_MEMORYSTICK_MASK         0x0800
-                               SONYPI_BATTERY_MASK             0x1000
-                               SONYPI_WIRELESS_MASK            0x2000
-
-       useinput:       if set (which is the default) two input devices are
-                       created, one which interprets the jogdial events as
-                       mouse events, the other one which acts like a
-                       keyboard reporting the pressing of the special keys.
-
-Module use:
------------
-
-In order to automatically load the sonypi module on use, you can put those
-lines a configuration file in /etc/modprobe.d/:
-
-       alias char-major-10-250 sonypi
-       options sonypi minor=250
-
-This supposes the use of minor 250 for the sonypi device:
-
-       # mknod /dev/sonypi c 10 250
-
-Bugs:
------
-
-       - several users reported that this driver disables the BIOS-managed
-         Fn-keys which put the laptop in sleeping state, or switch the
-         external monitor on/off. There is no workaround yet, since this
-         driver disables all APM management for those keys, by enabling the
-         ACPI management (and the ACPI core stuff is not complete yet). If
-         you have one of those laptops with working Fn keys and want to
-         continue to use them, don't use this driver.
-
-       - some users reported that the laptop speed is lower (dhrystone
-         tested) when using the driver with the fnkeyinit parameter. I cannot
-         reproduce it on my laptop and not all users have this problem.
-         This happens because the fnkeyinit parameter enables the ACPI
-         mode (but without additional ACPI control, like processor
-         speed handling etc). Use ACPI instead of APM if it works on your
-         laptop.
-
-       - sonypi lacks the ability to distinguish between certain key
-         events on some models.
-
-       - some models with the nvidia card (geforce go 6200 tc) uses a
-         different way to adjust the backlighting of the screen. There
-         is a userspace utility to adjust the brightness on those models,
-         which can be downloaded from
-         http://www.acc.umu.se/~erikw/program/smartdimmer-0.1.tar.bz2
-
-       - since all development was done by reverse engineering, there is
-         _absolutely no guarantee_ that this driver will not crash your
-         laptop. Permanently.
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
deleted file mode 100644 (file)
index 75ef063..0000000
+++ /dev/null
@@ -1,1487 +0,0 @@
-                    ThinkPad ACPI Extras Driver
-
-                            Version 0.25
-                        October 16th,  2013
-
-               Borislav Deianov <borislav@users.sf.net>
-             Henrique de Moraes Holschuh <hmh@hmh.eng.br>
-                      http://ibm-acpi.sf.net/
-
-
-This is a Linux driver for the IBM and Lenovo ThinkPad laptops. It
-supports various features of these laptops which are accessible
-through the ACPI and ACPI EC framework, but not otherwise fully
-supported by the generic Linux ACPI drivers.
-
-This driver used to be named ibm-acpi until kernel 2.6.21 and release
-0.13-20070314.  It used to be in the drivers/acpi tree, but it was
-moved to the drivers/misc tree and renamed to thinkpad-acpi for kernel
-2.6.22, and release 0.14.  It was moved to drivers/platform/x86 for
-kernel 2.6.29 and release 0.22.
-
-The driver is named "thinkpad-acpi".  In some places, like module
-names and log messages, "thinkpad_acpi" is used because of userspace
-issues.
-
-"tpacpi" is used as a shorthand where "thinkpad-acpi" would be too
-long due to length limitations on some Linux kernel versions.
-
-Status
-------
-
-The features currently supported are the following (see below for
-detailed description):
-
-       - Fn key combinations
-       - Bluetooth enable and disable
-       - video output switching, expansion control
-       - ThinkLight on and off
-       - CMOS/UCMS control
-       - LED control
-       - ACPI sounds
-       - temperature sensors
-       - Experimental: embedded controller register dump
-       - LCD brightness control
-       - Volume control
-       - Fan control and monitoring: fan speed, fan enable/disable
-       - WAN enable and disable
-       - UWB enable and disable
-
-A compatibility table by model and feature is maintained on the web
-site, http://ibm-acpi.sf.net/. I appreciate any success or failure
-reports, especially if they add to or correct the compatibility table.
-Please include the following information in your report:
-
-       - ThinkPad model name
-       - a copy of your ACPI tables, using the "acpidump" utility
-       - a copy of the output of dmidecode, with serial numbers
-         and UUIDs masked off
-       - which driver features work and which don't
-       - the observed behavior of non-working features
-
-Any other comments or patches are also more than welcome.
-
-
-Installation
-------------
-
-If you are compiling this driver as included in the Linux kernel
-sources, look for the CONFIG_THINKPAD_ACPI Kconfig option.
-It is located on the menu path: "Device Drivers" -> "X86 Platform
-Specific Device Drivers" -> "ThinkPad ACPI Laptop Extras".
-
-
-Features
---------
-
-The driver exports two different interfaces to userspace, which can be
-used to access the features it provides.  One is a legacy procfs-based
-interface, which will be removed at some time in the future.  The other
-is a new sysfs-based interface which is not complete yet.
-
-The procfs interface creates the /proc/acpi/ibm directory.  There is a
-file under that directory for each feature it supports.  The procfs
-interface is mostly frozen, and will change very little if at all: it
-will not be extended to add any new functionality in the driver, instead
-all new functionality will be implemented on the sysfs interface.
-
-The sysfs interface tries to blend in the generic Linux sysfs subsystems
-and classes as much as possible.  Since some of these subsystems are not
-yet ready or stabilized, it is expected that this interface will change,
-and any and all userspace programs must deal with it.
-
-
-Notes about the sysfs interface:
-
-Unlike what was done with the procfs interface, correctness when talking
-to the sysfs interfaces will be enforced, as will correctness in the
-thinkpad-acpi's implementation of sysfs interfaces.
-
-Also, any bugs in the thinkpad-acpi sysfs driver code or in the
-thinkpad-acpi's implementation of the sysfs interfaces will be fixed for
-maximum correctness, even if that means changing an interface in
-non-compatible ways.  As these interfaces mature both in the kernel and
-in thinkpad-acpi, such changes should become quite rare.
-
-Applications interfacing to the thinkpad-acpi sysfs interfaces must
-follow all sysfs guidelines and correctly process all errors (the sysfs
-interface makes extensive use of errors).  File descriptors and open /
-close operations to the sysfs inodes must also be properly implemented.
-
-The version of thinkpad-acpi's sysfs interface is exported by the driver
-as a driver attribute (see below).
-
-Sysfs driver attributes are on the driver's sysfs attribute space,
-for 2.6.23+ this is /sys/bus/platform/drivers/thinkpad_acpi/ and
-/sys/bus/platform/drivers/thinkpad_hwmon/
-
-Sysfs device attributes are on the thinkpad_acpi device sysfs attribute
-space, for 2.6.23+ this is /sys/devices/platform/thinkpad_acpi/.
-
-Sysfs device attributes for the sensors and fan are on the
-thinkpad_hwmon device's sysfs attribute space, but you should locate it
-looking for a hwmon device with the name attribute of "thinkpad", or
-better yet, through libsensors. For 4.14+ sysfs attributes were moved to the
-hwmon device (/sys/bus/platform/devices/thinkpad_hwmon/hwmon/hwmon? or
-/sys/class/hwmon/hwmon?).
-
-Driver version
---------------
-
-procfs: /proc/acpi/ibm/driver
-sysfs driver attribute: version
-
-The driver name and version. No commands can be written to this file.
-
-
-Sysfs interface version
------------------------
-
-sysfs driver attribute: interface_version
-
-Version of the thinkpad-acpi sysfs interface, as an unsigned long
-(output in hex format: 0xAAAABBCC), where:
-       AAAA - major revision
-       BB - minor revision
-       CC - bugfix revision
-
-The sysfs interface version changelog for the driver can be found at the
-end of this document.  Changes to the sysfs interface done by the kernel
-subsystems are not documented here, nor are they tracked by this
-attribute.
-
-Changes to the thinkpad-acpi sysfs interface are only considered
-non-experimental when they are submitted to Linux mainline, at which
-point the changes in this interface are documented and interface_version
-may be updated.  If you are using any thinkpad-acpi features not yet
-sent to mainline for merging, you do so on your own risk: these features
-may disappear, or be implemented in a different and incompatible way by
-the time they are merged in Linux mainline.
-
-Changes that are backwards-compatible by nature (e.g. the addition of
-attributes that do not change the way the other attributes work) do not
-always warrant an update of interface_version.  Therefore, one must
-expect that an attribute might not be there, and deal with it properly
-(an attribute not being there *is* a valid way to make it clear that a
-feature is not available in sysfs).
-
-
-Hot keys
---------
-
-procfs: /proc/acpi/ibm/hotkey
-sysfs device attribute: hotkey_*
-
-In a ThinkPad, the ACPI HKEY handler is responsible for communicating
-some important events and also keyboard hot key presses to the operating
-system.  Enabling the hotkey functionality of thinkpad-acpi signals the
-firmware that such a driver is present, and modifies how the ThinkPad
-firmware will behave in many situations.
-
-The driver enables the HKEY ("hot key") event reporting automatically
-when loaded, and disables it when it is removed.
-
-The driver will report HKEY events in the following format:
-
-       ibm/hotkey HKEY 00000080 0000xxxx
-
-Some of these events refer to hot key presses, but not all of them.
-
-The driver will generate events over the input layer for hot keys and
-radio switches, and over the ACPI netlink layer for other events.  The
-input layer support accepts the standard IOCTLs to remap the keycodes
-assigned to each hot key.
-
-The hot key bit mask allows some control over which hot keys generate
-events.  If a key is "masked" (bit set to 0 in the mask), the firmware
-will handle it.  If it is "unmasked", it signals the firmware that
-thinkpad-acpi would prefer to handle it, if the firmware would be so
-kind to allow it (and it often doesn't!).
-
-Not all bits in the mask can be modified.  Not all bits that can be
-modified do anything.  Not all hot keys can be individually controlled
-by the mask.  Some models do not support the mask at all.  The behaviour
-of the mask is, therefore, highly dependent on the ThinkPad model.
-
-The driver will filter out any unmasked hotkeys, so even if the firmware
-doesn't allow disabling an specific hotkey, the driver will not report
-events for unmasked hotkeys.
-
-Note that unmasking some keys prevents their default behavior.  For
-example, if Fn+F5 is unmasked, that key will no longer enable/disable
-Bluetooth by itself in firmware.
-
-Note also that not all Fn key combinations are supported through ACPI
-depending on the ThinkPad model and firmware version.  On those
-ThinkPads, it is still possible to support some extra hotkeys by
-polling the "CMOS NVRAM" at least 10 times per second.  The driver
-attempts to enables this functionality automatically when required.
-
-procfs notes:
-
-The following commands can be written to the /proc/acpi/ibm/hotkey file:
-
-       echo 0xffffffff > /proc/acpi/ibm/hotkey -- enable all hot keys
-       echo 0 > /proc/acpi/ibm/hotkey -- disable all possible hot keys
-       ... any other 8-hex-digit mask ...
-       echo reset > /proc/acpi/ibm/hotkey -- restore the recommended mask
-
-The following commands have been deprecated and will cause the kernel
-to log a warning:
-
-       echo enable > /proc/acpi/ibm/hotkey -- does nothing
-       echo disable > /proc/acpi/ibm/hotkey -- returns an error
-
-The procfs interface does not support NVRAM polling control.  So as to
-maintain maximum bug-to-bug compatibility, it does not report any masks,
-nor does it allow one to manipulate the hot key mask when the firmware
-does not support masks at all, even if NVRAM polling is in use.
-
-sysfs notes:
-
-       hotkey_bios_enabled:
-               DEPRECATED, WILL BE REMOVED SOON.
-
-               Returns 0.
-
-       hotkey_bios_mask:
-               DEPRECATED, DON'T USE, WILL BE REMOVED IN THE FUTURE.
-
-               Returns the hot keys mask when thinkpad-acpi was loaded.
-               Upon module unload, the hot keys mask will be restored
-               to this value.   This is always 0x80c, because those are
-               the hotkeys that were supported by ancient firmware
-               without mask support.
-
-       hotkey_enable:
-               DEPRECATED, WILL BE REMOVED SOON.
-
-               0: returns -EPERM
-               1: does nothing
-
-       hotkey_mask:
-               bit mask to enable reporting (and depending on
-               the firmware, ACPI event generation) for each hot key
-               (see above).  Returns the current status of the hot keys
-               mask, and allows one to modify it.
-
-       hotkey_all_mask:
-               bit mask that should enable event reporting for all
-               supported hot keys, when echoed to hotkey_mask above.
-               Unless you know which events need to be handled
-               passively (because the firmware *will* handle them
-               anyway), do *not* use hotkey_all_mask.  Use
-               hotkey_recommended_mask, instead. You have been warned.
-
-       hotkey_recommended_mask:
-               bit mask that should enable event reporting for all
-               supported hot keys, except those which are always
-               handled by the firmware anyway.  Echo it to
-               hotkey_mask above, to use.  This is the default mask
-               used by the driver.
-
-       hotkey_source_mask:
-               bit mask that selects which hot keys will the driver
-               poll the NVRAM for.  This is auto-detected by the driver
-               based on the capabilities reported by the ACPI firmware,
-               but it can be overridden at runtime.
-
-               Hot keys whose bits are set in hotkey_source_mask are
-               polled for in NVRAM, and reported as hotkey events if
-               enabled in hotkey_mask.  Only a few hot keys are
-               available through CMOS NVRAM polling.
-
-               Warning: when in NVRAM mode, the volume up/down/mute
-               keys are synthesized according to changes in the mixer,
-               which uses a single volume up or volume down hotkey
-               press to unmute, as per the ThinkPad volume mixer user
-               interface.  When in ACPI event mode, volume up/down/mute
-               events are reported by the firmware and can behave
-               differently (and that behaviour changes with firmware
-               version -- not just with firmware models -- as well as
-               OSI(Linux) state).
-
-       hotkey_poll_freq:
-               frequency in Hz for hot key polling. It must be between
-               0 and 25 Hz.  Polling is only carried out when strictly
-               needed.
-
-               Setting hotkey_poll_freq to zero disables polling, and
-               will cause hot key presses that require NVRAM polling
-               to never be reported.
-
-               Setting hotkey_poll_freq too low may cause repeated
-               pressings of the same hot key to be misreported as a
-               single key press, or to not even be detected at all.
-               The recommended polling frequency is 10Hz.
-
-       hotkey_radio_sw:
-               If the ThinkPad has a hardware radio switch, this
-               attribute will read 0 if the switch is in the "radios
-               disabled" position, and 1 if the switch is in the
-               "radios enabled" position.
-
-               This attribute has poll()/select() support.
-
-       hotkey_tablet_mode:
-               If the ThinkPad has tablet capabilities, this attribute
-               will read 0 if the ThinkPad is in normal mode, and
-               1 if the ThinkPad is in tablet mode.
-
-               This attribute has poll()/select() support.
-
-       wakeup_reason:
-               Set to 1 if the system is waking up because the user
-               requested a bay ejection.  Set to 2 if the system is
-               waking up because the user requested the system to
-               undock.  Set to zero for normal wake-ups or wake-ups
-               due to unknown reasons.
-
-               This attribute has poll()/select() support.
-
-       wakeup_hotunplug_complete:
-               Set to 1 if the system was waken up because of an
-               undock or bay ejection request, and that request
-               was successfully completed.  At this point, it might
-               be useful to send the system back to sleep, at the
-               user's choice.  Refer to HKEY events 0x4003 and
-               0x3003, below.
-
-               This attribute has poll()/select() support.
-
-input layer notes:
-
-A Hot key is mapped to a single input layer EV_KEY event, possibly
-followed by an EV_MSC MSC_SCAN event that shall contain that key's scan
-code.  An EV_SYN event will always be generated to mark the end of the
-event block.
-
-Do not use the EV_MSC MSC_SCAN events to process keys.  They are to be
-used as a helper to remap keys, only.  They are particularly useful when
-remapping KEY_UNKNOWN keys.
-
-The events are available in an input device, with the following id:
-
-       Bus:            BUS_HOST
-       vendor:         0x1014 (PCI_VENDOR_ID_IBM)  or
-                       0x17aa (PCI_VENDOR_ID_LENOVO)
-       product:        0x5054 ("TP")
-       version:        0x4101
-
-The version will have its LSB incremented if the keymap changes in a
-backwards-compatible way.  The MSB shall always be 0x41 for this input
-device.  If the MSB is not 0x41, do not use the device as described in
-this section, as it is either something else (e.g. another input device
-exported by a thinkpad driver, such as HDAPS) or its functionality has
-been changed in a non-backwards compatible way.
-
-Adding other event types for other functionalities shall be considered a
-backwards-compatible change for this input device.
-
-Thinkpad-acpi Hot Key event map (version 0x4101):
-
-ACPI   Scan
-event  code    Key             Notes
-
-0x1001 0x00    FN+F1           -
-
-0x1002 0x01    FN+F2           IBM: battery (rare)
-                               Lenovo: Screen lock
-
-0x1003 0x02    FN+F3           Many IBM models always report
-                               this hot key, even with hot keys
-                               disabled or with Fn+F3 masked
-                               off
-                               IBM: screen lock, often turns
-                               off the ThinkLight as side-effect
-                               Lenovo: battery
-
-0x1004 0x03    FN+F4           Sleep button (ACPI sleep button
-                               semantics, i.e. sleep-to-RAM).
-                               It always generates some kind
-                               of event, either the hot key
-                               event or an ACPI sleep button
-                               event. The firmware may
-                               refuse to generate further FN+F4
-                               key presses until a S3 or S4 ACPI
-                               sleep cycle is performed or some
-                               time passes.
-
-0x1005 0x04    FN+F5           Radio.  Enables/disables
-                               the internal Bluetooth hardware
-                               and W-WAN card if left in control
-                               of the firmware.  Does not affect
-                               the WLAN card.
-                               Should be used to turn on/off all
-                               radios (Bluetooth+W-WAN+WLAN),
-                               really.
-
-0x1006 0x05    FN+F6           -
-
-0x1007 0x06    FN+F7           Video output cycle.
-                               Do you feel lucky today?
-
-0x1008 0x07    FN+F8           IBM: toggle screen expand
-                               Lenovo: configure UltraNav,
-                               or toggle screen expand
-
-0x1009 0x08    FN+F9           -
-       ..      ..              ..
-0x100B 0x0A    FN+F11          -
-
-0x100C 0x0B    FN+F12          Sleep to disk.  You are always
-                               supposed to handle it yourself,
-                               either through the ACPI event,
-                               or through a hotkey event.
-                               The firmware may refuse to
-                               generate further FN+F12 key
-                               press events until a S3 or S4
-                               ACPI sleep cycle is performed,
-                               or some time passes.
-
-0x100D 0x0C    FN+BACKSPACE    -
-0x100E 0x0D    FN+INSERT       -
-0x100F 0x0E    FN+DELETE       -
-
-0x1010 0x0F    FN+HOME         Brightness up.  This key is
-                               always handled by the firmware
-                               in IBM ThinkPads, even when
-                               unmasked.  Just leave it alone.
-                               For Lenovo ThinkPads with a new
-                               BIOS, it has to be handled either
-                               by the ACPI OSI, or by userspace.
-                               The driver does the right thing,
-                               never mess with this.
-0x1011 0x10    FN+END          Brightness down.  See brightness
-                               up for details.
-
-0x1012 0x11    FN+PGUP         ThinkLight toggle.  This key is
-                               always handled by the firmware,
-                               even when unmasked.
-
-0x1013 0x12    FN+PGDOWN       -
-
-0x1014 0x13    FN+SPACE        Zoom key
-
-0x1015 0x14    VOLUME UP       Internal mixer volume up. This
-                               key is always handled by the
-                               firmware, even when unmasked.
-                               NOTE: Lenovo seems to be changing
-                               this.
-0x1016 0x15    VOLUME DOWN     Internal mixer volume up. This
-                               key is always handled by the
-                               firmware, even when unmasked.
-                               NOTE: Lenovo seems to be changing
-                               this.
-0x1017 0x16    MUTE            Mute internal mixer. This
-                               key is always handled by the
-                               firmware, even when unmasked.
-
-0x1018 0x17    THINKPAD        ThinkPad/Access IBM/Lenovo key
-
-0x1019 0x18    unknown
-..     ..      ..
-0x1020 0x1F    unknown
-
-The ThinkPad firmware does not allow one to differentiate when most hot
-keys are pressed or released (either that, or we don't know how to, yet).
-For these keys, the driver generates a set of events for a key press and
-immediately issues the same set of events for a key release.  It is
-unknown by the driver if the ThinkPad firmware triggered these events on
-hot key press or release, but the firmware will do it for either one, not
-both.
-
-If a key is mapped to KEY_RESERVED, it generates no input events at all.
-If a key is mapped to KEY_UNKNOWN, it generates an input event that
-includes an scan code.  If a key is mapped to anything else, it will
-generate input device EV_KEY events.
-
-In addition to the EV_KEY events, thinkpad-acpi may also issue EV_SW
-events for switches:
-
-SW_RFKILL_ALL  T60 and later hardware rfkill rocker switch
-SW_TABLET_MODE Tablet ThinkPads HKEY events 0x5009 and 0x500A
-
-Non hotkey ACPI HKEY event map:
--------------------------------
-
-Events that are never propagated by the driver:
-
-0x2304         System is waking up from suspend to undock
-0x2305         System is waking up from suspend to eject bay
-0x2404         System is waking up from hibernation to undock
-0x2405         System is waking up from hibernation to eject bay
-0x5001         Lid closed
-0x5002         Lid opened
-0x5009         Tablet swivel: switched to tablet mode
-0x500A         Tablet swivel: switched to normal mode
-0x5010         Brightness level changed/control event
-0x6000         KEYBOARD: Numlock key pressed
-0x6005         KEYBOARD: Fn key pressed (TO BE VERIFIED)
-0x7000         Radio Switch may have changed state
-
-
-Events that are propagated by the driver to userspace:
-
-0x2313         ALARM: System is waking up from suspend because
-               the battery is nearly empty
-0x2413         ALARM: System is waking up from hibernation because
-               the battery is nearly empty
-0x3003         Bay ejection (see 0x2x05) complete, can sleep again
-0x3006         Bay hotplug request (hint to power up SATA link when
-               the optical drive tray is ejected)
-0x4003         Undocked (see 0x2x04), can sleep again
-0x4010         Docked into hotplug port replicator (non-ACPI dock)
-0x4011         Undocked from hotplug port replicator (non-ACPI dock)
-0x500B         Tablet pen inserted into its storage bay
-0x500C         Tablet pen removed from its storage bay
-0x6011         ALARM: battery is too hot
-0x6012         ALARM: battery is extremely hot
-0x6021         ALARM: a sensor is too hot
-0x6022         ALARM: a sensor is extremely hot
-0x6030         System thermal table changed
-0x6032         Thermal Control command set completion  (DYTC, Windows)
-0x6040         Nvidia Optimus/AC adapter related (TO BE VERIFIED)
-0x60C0         X1 Yoga 2016, Tablet mode status changed
-0x60F0         Thermal Transformation changed (GMTS, Windows)
-
-Battery nearly empty alarms are a last resort attempt to get the
-operating system to hibernate or shutdown cleanly (0x2313), or shutdown
-cleanly (0x2413) before power is lost.  They must be acted upon, as the
-wake up caused by the firmware will have negated most safety nets...
-
-When any of the "too hot" alarms happen, according to Lenovo the user
-should suspend or hibernate the laptop (and in the case of battery
-alarms, unplug the AC adapter) to let it cool down.  These alarms do
-signal that something is wrong, they should never happen on normal
-operating conditions.
-
-The "extremely hot" alarms are emergencies.  According to Lenovo, the
-operating system is to force either an immediate suspend or hibernate
-cycle, or a system shutdown.  Obviously, something is very wrong if this
-happens.
-
-
-Brightness hotkey notes:
-
-Don't mess with the brightness hotkeys in a Thinkpad.  If you want
-notifications for OSD, use the sysfs backlight class event support.
-
-The driver will issue KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN events
-automatically for the cases were userspace has to do something to
-implement brightness changes.  When you override these events, you will
-either fail to handle properly the ThinkPads that require explicit
-action to change backlight brightness, or the ThinkPads that require
-that no action be taken to work properly.
-
-
-Bluetooth
----------
-
-procfs: /proc/acpi/ibm/bluetooth
-sysfs device attribute: bluetooth_enable (deprecated)
-sysfs rfkill class: switch "tpacpi_bluetooth_sw"
-
-This feature shows the presence and current state of a ThinkPad
-Bluetooth device in the internal ThinkPad CDC slot.
-
-If the ThinkPad supports it, the Bluetooth state is stored in NVRAM,
-so it is kept across reboots and power-off.
-
-Procfs notes:
-
-If Bluetooth is installed, the following commands can be used:
-
-       echo enable > /proc/acpi/ibm/bluetooth
-       echo disable > /proc/acpi/ibm/bluetooth
-
-Sysfs notes:
-
-       If the Bluetooth CDC card is installed, it can be enabled /
-       disabled through the "bluetooth_enable" thinkpad-acpi device
-       attribute, and its current status can also be queried.
-
-       enable:
-               0: disables Bluetooth / Bluetooth is disabled
-               1: enables Bluetooth / Bluetooth is enabled.
-
-       Note: this interface has been superseded by the generic rfkill
-       class.  It has been deprecated, and it will be removed in year
-       2010.
-
-       rfkill controller switch "tpacpi_bluetooth_sw": refer to
-       Documentation/rfkill.txt for details.
-
-
-Video output control -- /proc/acpi/ibm/video
---------------------------------------------
-
-This feature allows control over the devices used for video output -
-LCD, CRT or DVI (if available). The following commands are available:
-
-       echo lcd_enable > /proc/acpi/ibm/video
-       echo lcd_disable > /proc/acpi/ibm/video
-       echo crt_enable > /proc/acpi/ibm/video
-       echo crt_disable > /proc/acpi/ibm/video
-       echo dvi_enable > /proc/acpi/ibm/video
-       echo dvi_disable > /proc/acpi/ibm/video
-       echo auto_enable > /proc/acpi/ibm/video
-       echo auto_disable > /proc/acpi/ibm/video
-       echo expand_toggle > /proc/acpi/ibm/video
-       echo video_switch > /proc/acpi/ibm/video
-
-NOTE: Access to this feature is restricted to processes owning the
-CAP_SYS_ADMIN capability for safety reasons, as it can interact badly
-enough with some versions of X.org to crash it.
-
-Each video output device can be enabled or disabled individually.
-Reading /proc/acpi/ibm/video shows the status of each device.
-
-Automatic video switching can be enabled or disabled.  When automatic
-video switching is enabled, certain events (e.g. opening the lid,
-docking or undocking) cause the video output device to change
-automatically. While this can be useful, it also causes flickering
-and, on the X40, video corruption. By disabling automatic switching,
-the flickering or video corruption can be avoided.
-
-The video_switch command cycles through the available video outputs
-(it simulates the behavior of Fn-F7).
-
-Video expansion can be toggled through this feature. This controls
-whether the display is expanded to fill the entire LCD screen when a
-mode with less than full resolution is used. Note that the current
-video expansion status cannot be determined through this feature.
-
-Note that on many models (particularly those using Radeon graphics
-chips) the X driver configures the video card in a way which prevents
-Fn-F7 from working. This also disables the video output switching
-features of this driver, as it uses the same ACPI methods as
-Fn-F7. Video switching on the console should still work.
-
-UPDATE: refer to https://bugs.freedesktop.org/show_bug.cgi?id=2000
-
-
-ThinkLight control
-------------------
-
-procfs: /proc/acpi/ibm/light
-sysfs attributes: as per LED class, for the "tpacpi::thinklight" LED
-
-procfs notes:
-
-The ThinkLight status can be read and set through the procfs interface.  A
-few models which do not make the status available will show the ThinkLight
-status as "unknown". The available commands are:
-
-       echo on  > /proc/acpi/ibm/light
-       echo off > /proc/acpi/ibm/light
-
-sysfs notes:
-
-The ThinkLight sysfs interface is documented by the LED class
-documentation, in Documentation/leds/leds-class.rst.  The ThinkLight LED name
-is "tpacpi::thinklight".
-
-Due to limitations in the sysfs LED class, if the status of the ThinkLight
-cannot be read or if it is unknown, thinkpad-acpi will report it as "off".
-It is impossible to know if the status returned through sysfs is valid.
-
-
-CMOS/UCMS control
------------------
-
-procfs: /proc/acpi/ibm/cmos
-sysfs device attribute: cmos_command
-
-This feature is mostly used internally by the ACPI firmware to keep the legacy
-CMOS NVRAM bits in sync with the current machine state, and to record this
-state so that the ThinkPad will retain such settings across reboots.
-
-Some of these commands actually perform actions in some ThinkPad models, but
-this is expected to disappear more and more in newer models.  As an example, in
-a T43 and in a X40, commands 12 and 13 still control the ThinkLight state for
-real, but commands 0 to 2 don't control the mixer anymore (they have been
-phased out) and just update the NVRAM.
-
-The range of valid cmos command numbers is 0 to 21, but not all have an
-effect and the behavior varies from model to model.  Here is the behavior
-on the X40 (tpb is the ThinkPad Buttons utility):
-
-       0 - Related to "Volume down" key press
-       1 - Related to "Volume up" key press
-       2 - Related to "Mute on" key press
-       3 - Related to "Access IBM" key press
-       4 - Related to "LCD brightness up" key press
-       5 - Related to "LCD brightness down" key press
-       11 - Related to "toggle screen expansion" key press/function
-       12 - Related to "ThinkLight on"
-       13 - Related to "ThinkLight off"
-       14 - Related to "ThinkLight" key press (toggle ThinkLight)
-
-The cmos command interface is prone to firmware split-brain problems, as
-in newer ThinkPads it is just a compatibility layer.  Do not use it, it is
-exported just as a debug tool.
-
-
-LED control
------------
-
-procfs: /proc/acpi/ibm/led
-sysfs attributes: as per LED class, see below for names
-
-Some of the LED indicators can be controlled through this feature.  On
-some older ThinkPad models, it is possible to query the status of the
-LED indicators as well.  Newer ThinkPads cannot query the real status
-of the LED indicators.
-
-Because misuse of the LEDs could induce an unaware user to perform
-dangerous actions (like undocking or ejecting a bay device while the
-buses are still active), or mask an important alarm (such as a nearly
-empty battery, or a broken battery), access to most LEDs is
-restricted.
-
-Unrestricted access to all LEDs requires that thinkpad-acpi be
-compiled with the CONFIG_THINKPAD_ACPI_UNSAFE_LEDS option enabled.
-Distributions must never enable this option.  Individual users that
-are aware of the consequences are welcome to enabling it.
-
-Audio mute and microphone mute LEDs are supported, but currently not
-visible to userspace. They are used by the snd-hda-intel audio driver.
-
-procfs notes:
-
-The available commands are:
-
-       echo '<LED number> on' >/proc/acpi/ibm/led
-       echo '<LED number> off' >/proc/acpi/ibm/led
-       echo '<LED number> blink' >/proc/acpi/ibm/led
-
-The <LED number> range is 0 to 15. The set of LEDs that can be
-controlled varies from model to model. Here is the common ThinkPad
-mapping:
-
-       0 - power
-       1 - battery (orange)
-       2 - battery (green)
-       3 - UltraBase/dock
-       4 - UltraBay
-       5 - UltraBase battery slot
-       6 - (unknown)
-       7 - standby
-       8 - dock status 1
-       9 - dock status 2
-       10, 11 - (unknown)
-       12 - thinkvantage
-       13, 14, 15 - (unknown)
-
-All of the above can be turned on and off and can be made to blink.
-
-sysfs notes:
-
-The ThinkPad LED sysfs interface is described in detail by the LED class
-documentation, in Documentation/leds/leds-class.rst.
-
-The LEDs are named (in LED ID order, from 0 to 12):
-"tpacpi::power", "tpacpi:orange:batt", "tpacpi:green:batt",
-"tpacpi::dock_active", "tpacpi::bay_active", "tpacpi::dock_batt",
-"tpacpi::unknown_led", "tpacpi::standby", "tpacpi::dock_status1",
-"tpacpi::dock_status2", "tpacpi::unknown_led2", "tpacpi::unknown_led3",
-"tpacpi::thinkvantage".
-
-Due to limitations in the sysfs LED class, if the status of the LED
-indicators cannot be read due to an error, thinkpad-acpi will report it as
-a brightness of zero (same as LED off).
-
-If the thinkpad firmware doesn't support reading the current status,
-trying to read the current LED brightness will just return whatever
-brightness was last written to that attribute.
-
-These LEDs can blink using hardware acceleration.  To request that a
-ThinkPad indicator LED should blink in hardware accelerated mode, use the
-"timer" trigger, and leave the delay_on and delay_off parameters set to
-zero (to request hardware acceleration autodetection).
-
-LEDs that are known not to exist in a given ThinkPad model are not
-made available through the sysfs interface.  If you have a dock and you
-notice there are LEDs listed for your ThinkPad that do not exist (and
-are not in the dock), or if you notice that there are missing LEDs,
-a report to ibm-acpi-devel@lists.sourceforge.net is appreciated.
-
-
-ACPI sounds -- /proc/acpi/ibm/beep
-----------------------------------
-
-The BEEP method is used internally by the ACPI firmware to provide
-audible alerts in various situations. This feature allows the same
-sounds to be triggered manually.
-
-The commands are non-negative integer numbers:
-
-       echo <number> >/proc/acpi/ibm/beep
-
-The valid <number> range is 0 to 17. Not all numbers trigger sounds
-and the sounds vary from model to model. Here is the behavior on the
-X40:
-
-       0 - stop a sound in progress (but use 17 to stop 16)
-       2 - two beeps, pause, third beep ("low battery")
-       3 - single beep
-       4 - high, followed by low-pitched beep ("unable")
-       5 - single beep
-       6 - very high, followed by high-pitched beep ("AC/DC")
-       7 - high-pitched beep
-       9 - three short beeps
-       10 - very long beep
-       12 - low-pitched beep
-       15 - three high-pitched beeps repeating constantly, stop with 0
-       16 - one medium-pitched beep repeating constantly, stop with 17
-       17 - stop 16
-
-
-Temperature sensors
--------------------
-
-procfs: /proc/acpi/ibm/thermal
-sysfs device attributes: (hwmon "thinkpad") temp*_input
-
-Most ThinkPads include six or more separate temperature sensors but only
-expose the CPU temperature through the standard ACPI methods.  This
-feature shows readings from up to eight different sensors on older
-ThinkPads, and up to sixteen different sensors on newer ThinkPads.
-
-For example, on the X40, a typical output may be:
-temperatures:   42 42 45 41 36 -128 33 -128
-
-On the T43/p, a typical output may be:
-temperatures:   48 48 36 52 38 -128 31 -128 48 52 48 -128 -128 -128 -128 -128
-
-The mapping of thermal sensors to physical locations varies depending on
-system-board model (and thus, on ThinkPad model).
-
-http://thinkwiki.org/wiki/Thermal_Sensors is a public wiki page that
-tries to track down these locations for various models.
-
-Most (newer?) models seem to follow this pattern:
-
-1:  CPU
-2:  (depends on model)
-3:  (depends on model)
-4:  GPU
-5:  Main battery: main sensor
-6:  Bay battery: main sensor
-7:  Main battery: secondary sensor
-8:  Bay battery: secondary sensor
-9-15: (depends on model)
-
-For the R51 (source: Thomas Gruber):
-2:  Mini-PCI
-3:  Internal HDD
-
-For the T43, T43/p (source: Shmidoax/Thinkwiki.org)
-http://thinkwiki.org/wiki/Thermal_Sensors#ThinkPad_T43.2C_T43p
-2:  System board, left side (near PCMCIA slot), reported as HDAPS temp
-3:  PCMCIA slot
-9:  MCH (northbridge) to DRAM Bus
-10: Clock-generator, mini-pci card and ICH (southbridge), under Mini-PCI
-    card, under touchpad
-11: Power regulator, underside of system board, below F2 key
-
-The A31 has a very atypical layout for the thermal sensors
-(source: Milos Popovic, http://thinkwiki.org/wiki/Thermal_Sensors#ThinkPad_A31)
-1:  CPU
-2:  Main Battery: main sensor
-3:  Power Converter
-4:  Bay Battery: main sensor
-5:  MCH (northbridge)
-6:  PCMCIA/ambient
-7:  Main Battery: secondary sensor
-8:  Bay Battery: secondary sensor
-
-
-Procfs notes:
-       Readings from sensors that are not available return -128.
-       No commands can be written to this file.
-
-Sysfs notes:
-       Sensors that are not available return the ENXIO error.  This
-       status may change at runtime, as there are hotplug thermal
-       sensors, like those inside the batteries and docks.
-
-       thinkpad-acpi thermal sensors are reported through the hwmon
-       subsystem, and follow all of the hwmon guidelines at
-       Documentation/hwmon.
-
-EXPERIMENTAL: Embedded controller register dump
------------------------------------------------
-
-This feature is not included in the thinkpad driver anymore.
-Instead the EC can be accessed through /sys/kernel/debug/ec with
-a userspace tool which can be found here:
-ftp://ftp.suse.com/pub/people/trenn/sources/ec
-
-Use it to determine the register holding the fan
-speed on some models. To do that, do the following:
-       - make sure the battery is fully charged
-       - make sure the fan is running
-       - use above mentioned tool to read out the EC
-
-Often fan and temperature values vary between
-readings. Since temperatures don't change vary fast, you can take
-several quick dumps to eliminate them.
-
-You can use a similar method to figure out the meaning of other
-embedded controller registers - e.g. make sure nothing else changes
-except the charging or discharging battery to determine which
-registers contain the current battery capacity, etc. If you experiment
-with this, do send me your results (including some complete dumps with
-a description of the conditions when they were taken.)
-
-
-LCD brightness control
-----------------------
-
-procfs: /proc/acpi/ibm/brightness
-sysfs backlight device "thinkpad_screen"
-
-This feature allows software control of the LCD brightness on ThinkPad
-models which don't have a hardware brightness slider.
-
-It has some limitations: the LCD backlight cannot be actually turned
-on or off by this interface, it just controls the backlight brightness
-level.
-
-On IBM (and some of the earlier Lenovo) ThinkPads, the backlight control
-has eight brightness levels, ranging from 0 to 7.  Some of the levels
-may not be distinct.  Later Lenovo models that implement the ACPI
-display backlight brightness control methods have 16 levels, ranging
-from 0 to 15.
-
-For IBM ThinkPads, there are two interfaces to the firmware for direct
-brightness control, EC and UCMS (or CMOS).  To select which one should be
-used, use the brightness_mode module parameter: brightness_mode=1 selects
-EC mode, brightness_mode=2 selects UCMS mode, brightness_mode=3 selects EC
-mode with NVRAM backing (so that brightness changes are remembered across
-shutdown/reboot).
-
-The driver tries to select which interface to use from a table of
-defaults for each ThinkPad model.  If it makes a wrong choice, please
-report this as a bug, so that we can fix it.
-
-Lenovo ThinkPads only support brightness_mode=2 (UCMS).
-
-When display backlight brightness controls are available through the
-standard ACPI interface, it is best to use it instead of this direct
-ThinkPad-specific interface.  The driver will disable its native
-backlight brightness control interface if it detects that the standard
-ACPI interface is available in the ThinkPad.
-
-If you want to use the thinkpad-acpi backlight brightness control
-instead of the generic ACPI video backlight brightness control for some
-reason, you should use the acpi_backlight=vendor kernel parameter.
-
-The brightness_enable module parameter can be used to control whether
-the LCD brightness control feature will be enabled when available.
-brightness_enable=0 forces it to be disabled.  brightness_enable=1
-forces it to be enabled when available, even if the standard ACPI
-interface is also available.
-
-Procfs notes:
-
-       The available commands are:
-
-       echo up   >/proc/acpi/ibm/brightness
-       echo down >/proc/acpi/ibm/brightness
-       echo 'level <level>' >/proc/acpi/ibm/brightness
-
-Sysfs notes:
-
-The interface is implemented through the backlight sysfs class, which is
-poorly documented at this time.
-
-Locate the thinkpad_screen device under /sys/class/backlight, and inside
-it there will be the following attributes:
-
-       max_brightness:
-               Reads the maximum brightness the hardware can be set to.
-               The minimum is always zero.
-
-       actual_brightness:
-               Reads what brightness the screen is set to at this instant.
-
-       brightness:
-               Writes request the driver to change brightness to the
-               given value.  Reads will tell you what brightness the
-               driver is trying to set the display to when "power" is set
-               to zero and the display has not been dimmed by a kernel
-               power management event.
-
-       power:
-               power management mode, where 0 is "display on", and 1 to 3
-               will dim the display backlight to brightness level 0
-               because thinkpad-acpi cannot really turn the backlight
-               off.  Kernel power management events can temporarily
-               increase the current power management level, i.e. they can
-               dim the display.
-
-
-WARNING:
-
-    Whatever you do, do NOT ever call thinkpad-acpi backlight-level change
-    interface and the ACPI-based backlight level change interface
-    (available on newer BIOSes, and driven by the Linux ACPI video driver)
-    at the same time.  The two will interact in bad ways, do funny things,
-    and maybe reduce the life of the backlight lamps by needlessly kicking
-    its level up and down at every change.
-
-
-Volume control (Console Audio control)
---------------------------------------
-
-procfs: /proc/acpi/ibm/volume
-ALSA: "ThinkPad Console Audio Control", default ID: "ThinkPadEC"
-
-NOTE: by default, the volume control interface operates in read-only
-mode, as it is supposed to be used for on-screen-display purposes.
-The read/write mode can be enabled through the use of the
-"volume_control=1" module parameter.
-
-NOTE: distros are urged to not enable volume_control by default, this
-should be done by the local admin only.  The ThinkPad UI is for the
-console audio control to be done through the volume keys only, and for
-the desktop environment to just provide on-screen-display feedback.
-Software volume control should be done only in the main AC97/HDA
-mixer.
-
-
-About the ThinkPad Console Audio control:
-
-ThinkPads have a built-in amplifier and muting circuit that drives the
-console headphone and speakers.  This circuit is after the main AC97
-or HDA mixer in the audio path, and under exclusive control of the
-firmware.
-
-ThinkPads have three special hotkeys to interact with the console
-audio control: volume up, volume down and mute.
-
-It is worth noting that the normal way the mute function works (on
-ThinkPads that do not have a "mute LED") is:
-
-1. Press mute to mute.  It will *always* mute, you can press it as
-   many times as you want, and the sound will remain mute.
-
-2. Press either volume key to unmute the ThinkPad (it will _not_
-   change the volume, it will just unmute).
-
-This is a very superior design when compared to the cheap software-only
-mute-toggle solution found on normal consumer laptops:  you can be
-absolutely sure the ThinkPad will not make noise if you press the mute
-button, no matter the previous state.
-
-The IBM ThinkPads, and the earlier Lenovo ThinkPads have variable-gain
-amplifiers driving the speakers and headphone output, and the firmware
-also handles volume control for the headphone and speakers on these
-ThinkPads without any help from the operating system (this volume
-control stage exists after the main AC97 or HDA mixer in the audio
-path).
-
-The newer Lenovo models only have firmware mute control, and depend on
-the main HDA mixer to do volume control (which is done by the operating
-system).  In this case, the volume keys are filtered out for unmute
-key press (there are some firmware bugs in this area) and delivered as
-normal key presses to the operating system (thinkpad-acpi is not
-involved).
-
-
-The ThinkPad-ACPI volume control:
-
-The preferred way to interact with the Console Audio control is the
-ALSA interface.
-
-The legacy procfs interface allows one to read the current state,
-and if volume control is enabled, accepts the following commands:
-
-       echo up   >/proc/acpi/ibm/volume
-       echo down >/proc/acpi/ibm/volume
-       echo mute >/proc/acpi/ibm/volume
-       echo unmute >/proc/acpi/ibm/volume
-       echo 'level <level>' >/proc/acpi/ibm/volume
-
-The <level> number range is 0 to 14 although not all of them may be
-distinct. To unmute the volume after the mute command, use either the
-up or down command (the level command will not unmute the volume), or
-the unmute command.
-
-You can use the volume_capabilities parameter to tell the driver
-whether your thinkpad has volume control or mute-only control:
-volume_capabilities=1 for mixers with mute and volume control,
-volume_capabilities=2 for mixers with only mute control.
-
-If the driver misdetects the capabilities for your ThinkPad model,
-please report this to ibm-acpi-devel@lists.sourceforge.net, so that we
-can update the driver.
-
-There are two strategies for volume control.  To select which one
-should be used, use the volume_mode module parameter: volume_mode=1
-selects EC mode, and volume_mode=3 selects EC mode with NVRAM backing
-(so that volume/mute changes are remembered across shutdown/reboot).
-
-The driver will operate in volume_mode=3 by default. If that does not
-work well on your ThinkPad model, please report this to
-ibm-acpi-devel@lists.sourceforge.net.
-
-The driver supports the standard ALSA module parameters.  If the ALSA
-mixer is disabled, the driver will disable all volume functionality.
-
-
-Fan control and monitoring: fan speed, fan enable/disable
----------------------------------------------------------
-
-procfs: /proc/acpi/ibm/fan
-sysfs device attributes: (hwmon "thinkpad") fan1_input, pwm1,
-                         pwm1_enable, fan2_input
-sysfs hwmon driver attributes: fan_watchdog
-
-NOTE NOTE NOTE: fan control operations are disabled by default for
-safety reasons.  To enable them, the module parameter "fan_control=1"
-must be given to thinkpad-acpi.
-
-This feature attempts to show the current fan speed, control mode and
-other fan data that might be available.  The speed is read directly
-from the hardware registers of the embedded controller.  This is known
-to work on later R, T, X and Z series ThinkPads but may show a bogus
-value on other models.
-
-Some Lenovo ThinkPads support a secondary fan.  This fan cannot be
-controlled separately, it shares the main fan control.
-
-Fan levels:
-
-Most ThinkPad fans work in "levels" at the firmware interface.  Level 0
-stops the fan.  The higher the level, the higher the fan speed, although
-adjacent levels often map to the same fan speed.  7 is the highest
-level, where the fan reaches the maximum recommended speed.
-
-Level "auto" means the EC changes the fan level according to some
-internal algorithm, usually based on readings from the thermal sensors.
-
-There is also a "full-speed" level, also known as "disengaged" level.
-In this level, the EC disables the speed-locked closed-loop fan control,
-and drives the fan as fast as it can go, which might exceed hardware
-limits, so use this level with caution.
-
-The fan usually ramps up or down slowly from one speed to another, and
-it is normal for the EC to take several seconds to react to fan
-commands.  The full-speed level may take up to two minutes to ramp up to
-maximum speed, and in some ThinkPads, the tachometer readings go stale
-while the EC is transitioning to the full-speed level.
-
-WARNING WARNING WARNING: do not leave the fan disabled unless you are
-monitoring all of the temperature sensor readings and you are ready to
-enable it if necessary to avoid overheating.
-
-An enabled fan in level "auto" may stop spinning if the EC decides the
-ThinkPad is cool enough and doesn't need the extra airflow.  This is
-normal, and the EC will spin the fan up if the various thermal readings
-rise too much.
-
-On the X40, this seems to depend on the CPU and HDD temperatures.
-Specifically, the fan is turned on when either the CPU temperature
-climbs to 56 degrees or the HDD temperature climbs to 46 degrees.  The
-fan is turned off when the CPU temperature drops to 49 degrees and the
-HDD temperature drops to 41 degrees.  These thresholds cannot
-currently be controlled.
-
-The ThinkPad's ACPI DSDT code will reprogram the fan on its own when
-certain conditions are met.  It will override any fan programming done
-through thinkpad-acpi.
-
-The thinkpad-acpi kernel driver can be programmed to revert the fan
-level to a safe setting if userspace does not issue one of the procfs
-fan commands: "enable", "disable", "level" or "watchdog", or if there
-are no writes to pwm1_enable (or to pwm1 *if and only if* pwm1_enable is
-set to 1, manual mode) within a configurable amount of time of up to
-120 seconds.  This functionality is called fan safety watchdog.
-
-Note that the watchdog timer stops after it enables the fan.  It will be
-rearmed again automatically (using the same interval) when one of the
-above mentioned fan commands is received.  The fan watchdog is,
-therefore, not suitable to protect against fan mode changes made through
-means other than the "enable", "disable", and "level" procfs fan
-commands, or the hwmon fan control sysfs interface.
-
-Procfs notes:
-
-The fan may be enabled or disabled with the following commands:
-
-       echo enable  >/proc/acpi/ibm/fan
-       echo disable >/proc/acpi/ibm/fan
-
-Placing a fan on level 0 is the same as disabling it.  Enabling a fan
-will try to place it in a safe level if it is too slow or disabled.
-
-The fan level can be controlled with the command:
-
-       echo 'level <level>' > /proc/acpi/ibm/fan
-
-Where <level> is an integer from 0 to 7, or one of the words "auto" or
-"full-speed" (without the quotes).  Not all ThinkPads support the "auto"
-and "full-speed" levels.  The driver accepts "disengaged" as an alias for
-"full-speed", and reports it as "disengaged" for backwards
-compatibility.
-
-On the X31 and X40 (and ONLY on those models), the fan speed can be
-controlled to a certain degree.  Once the fan is running, it can be
-forced to run faster or slower with the following command:
-
-       echo 'speed <speed>' > /proc/acpi/ibm/fan
-
-The sustainable range of fan speeds on the X40 appears to be from about
-3700 to about 7350. Values outside this range either do not have any
-effect or the fan speed eventually settles somewhere in that range.  The
-fan cannot be stopped or started with this command.  This functionality
-is incomplete, and not available through the sysfs interface.
-
-To program the safety watchdog, use the "watchdog" command.
-
-       echo 'watchdog <interval in seconds>' > /proc/acpi/ibm/fan
-
-If you want to disable the watchdog, use 0 as the interval.
-
-Sysfs notes:
-
-The sysfs interface follows the hwmon subsystem guidelines for the most
-part, and the exception is the fan safety watchdog.
-
-Writes to any of the sysfs attributes may return the EINVAL error if
-that operation is not supported in a given ThinkPad or if the parameter
-is out-of-bounds, and EPERM if it is forbidden.  They may also return
-EINTR (interrupted system call), and EIO (I/O error while trying to talk
-to the firmware).
-
-Features not yet implemented by the driver return ENOSYS.
-
-hwmon device attribute pwm1_enable:
-       0: PWM offline (fan is set to full-speed mode)
-       1: Manual PWM control (use pwm1 to set fan level)
-       2: Hardware PWM control (EC "auto" mode)
-       3: reserved (Software PWM control, not implemented yet)
-
-       Modes 0 and 2 are not supported by all ThinkPads, and the
-       driver is not always able to detect this.  If it does know a
-       mode is unsupported, it will return -EINVAL.
-
-hwmon device attribute pwm1:
-       Fan level, scaled from the firmware values of 0-7 to the hwmon
-       scale of 0-255.  0 means fan stopped, 255 means highest normal
-       speed (level 7).
-
-       This attribute only commands the fan if pmw1_enable is set to 1
-       (manual PWM control).
-
-hwmon device attribute fan1_input:
-       Fan tachometer reading, in RPM.  May go stale on certain
-       ThinkPads while the EC transitions the PWM to offline mode,
-       which can take up to two minutes.  May return rubbish on older
-       ThinkPads.
-
-hwmon device attribute fan2_input:
-       Fan tachometer reading, in RPM, for the secondary fan.
-       Available only on some ThinkPads.  If the secondary fan is
-       not installed, will always read 0.
-
-hwmon driver attribute fan_watchdog:
-       Fan safety watchdog timer interval, in seconds.  Minimum is
-       1 second, maximum is 120 seconds.  0 disables the watchdog.
-
-To stop the fan: set pwm1 to zero, and pwm1_enable to 1.
-
-To start the fan in a safe mode: set pwm1_enable to 2.  If that fails
-with EINVAL, try to set pwm1_enable to 1 and pwm1 to at least 128 (255
-would be the safest choice, though).
-
-
-WAN
----
-
-procfs: /proc/acpi/ibm/wan
-sysfs device attribute: wwan_enable (deprecated)
-sysfs rfkill class: switch "tpacpi_wwan_sw"
-
-This feature shows the presence and current state of the built-in
-Wireless WAN device.
-
-If the ThinkPad supports it, the WWAN state is stored in NVRAM,
-so it is kept across reboots and power-off.
-
-It was tested on a Lenovo ThinkPad X60. It should probably work on other
-ThinkPad models which come with this module installed.
-
-Procfs notes:
-
-If the W-WAN card is installed, the following commands can be used:
-
-       echo enable > /proc/acpi/ibm/wan
-       echo disable > /proc/acpi/ibm/wan
-
-Sysfs notes:
-
-       If the W-WAN card is installed, it can be enabled /
-       disabled through the "wwan_enable" thinkpad-acpi device
-       attribute, and its current status can also be queried.
-
-       enable:
-               0: disables WWAN card / WWAN card is disabled
-               1: enables WWAN card / WWAN card is enabled.
-
-       Note: this interface has been superseded by the generic rfkill
-       class.  It has been deprecated, and it will be removed in year
-       2010.
-
-       rfkill controller switch "tpacpi_wwan_sw": refer to
-       Documentation/rfkill.txt for details.
-
-
-EXPERIMENTAL: UWB
------------------
-
-This feature is considered EXPERIMENTAL because it has not been extensively
-tested and validated in various ThinkPad models yet.  The feature may not
-work as expected. USE WITH CAUTION! To use this feature, you need to supply
-the experimental=1 parameter when loading the module.
-
-sysfs rfkill class: switch "tpacpi_uwb_sw"
-
-This feature exports an rfkill controller for the UWB device, if one is
-present and enabled in the BIOS.
-
-Sysfs notes:
-
-       rfkill controller switch "tpacpi_uwb_sw": refer to
-       Documentation/rfkill.txt for details.
-
-Adaptive keyboard
------------------
-
-sysfs device attribute: adaptive_kbd_mode
-
-This sysfs attribute controls the keyboard "face" that will be shown on the
-Lenovo X1 Carbon 2nd gen (2014)'s adaptive keyboard. The value can be read
-and set.
-
-1 = Home mode
-2 = Web-browser mode
-3 = Web-conference mode
-4 = Function mode
-5 = Layflat mode
-
-For more details about which buttons will appear depending on the mode, please
-review the laptop's user guide:
-http://www.lenovo.com/shop/americas/content/user_guides/x1carbon_2_ug_en.pdf
-
-Multiple Commands, Module Parameters
-------------------------------------
-
-Multiple commands can be written to the proc files in one shot by
-separating them with commas, for example:
-
-       echo enable,0xffff > /proc/acpi/ibm/hotkey
-       echo lcd_disable,crt_enable > /proc/acpi/ibm/video
-
-Commands can also be specified when loading the thinkpad-acpi module,
-for example:
-
-       modprobe thinkpad_acpi hotkey=enable,0xffff video=auto_disable
-
-
-Enabling debugging output
--------------------------
-
-The module takes a debug parameter which can be used to selectively
-enable various classes of debugging output, for example:
-
-        modprobe thinkpad_acpi debug=0xffff
-
-will enable all debugging output classes.  It takes a bitmask, so
-to enable more than one output class, just add their values.
-
-       Debug bitmask           Description
-       0x8000                  Disclose PID of userspace programs
-                               accessing some functions of the driver
-       0x0001                  Initialization and probing
-       0x0002                  Removal
-       0x0004                  RF Transmitter control (RFKILL)
-                               (bluetooth, WWAN, UWB...)
-       0x0008                  HKEY event interface, hotkeys
-       0x0010                  Fan control
-       0x0020                  Backlight brightness
-       0x0040                  Audio mixer/volume control
-
-There is also a kernel build option to enable more debugging
-information, which may be necessary to debug driver problems.
-
-The level of debugging information output by the driver can be changed
-at runtime through sysfs, using the driver attribute debug_level.  The
-attribute takes the same bitmask as the debug module parameter above.
-
-
-Force loading of module
------------------------
-
-If thinkpad-acpi refuses to detect your ThinkPad, you can try to specify
-the module parameter force_load=1.  Regardless of whether this works or
-not, please contact ibm-acpi-devel@lists.sourceforge.net with a report.
-
-
-Sysfs interface changelog:
-
-0x000100:      Initial sysfs support, as a single platform driver and
-               device.
-0x000200:      Hot key support for 32 hot keys, and radio slider switch
-               support.
-0x010000:      Hot keys are now handled by default over the input
-               layer, the radio switch generates input event EV_RADIO,
-               and the driver enables hot key handling by default in
-               the firmware.
-
-0x020000:      ABI fix: added a separate hwmon platform device and
-               driver, which must be located by name (thinkpad)
-               and the hwmon class for libsensors4 (lm-sensors 3)
-               compatibility.  Moved all hwmon attributes to this
-               new platform device.
-
-0x020100:      Marker for thinkpad-acpi with hot key NVRAM polling
-               support.  If you must, use it to know you should not
-               start a userspace NVRAM poller (allows to detect when
-               NVRAM is compiled out by the user because it is
-               unneeded/undesired in the first place).
-0x020101:      Marker for thinkpad-acpi with hot key NVRAM polling
-               and proper hotkey_mask semantics (version 8 of the
-               NVRAM polling patch).  Some development snapshots of
-               0.18 had an earlier version that did strange things
-               to hotkey_mask.
-
-0x020200:      Add poll()/select() support to the following attributes:
-               hotkey_radio_sw, wakeup_hotunplug_complete, wakeup_reason
-
-0x020300:      hotkey enable/disable support removed, attributes
-               hotkey_bios_enabled and hotkey_enable deprecated and
-               marked for removal.
-
-0x020400:      Marker for 16 LEDs support.  Also, LEDs that are known
-               to not exist in a given model are not registered with
-               the LED sysfs class anymore.
-
-0x020500:      Updated hotkey driver, hotkey_mask is always available
-               and it is always able to disable hot keys.  Very old
-               thinkpads are properly supported.  hotkey_bios_mask
-               is deprecated and marked for removal.
-
-0x020600:      Marker for backlight change event support.
-
-0x020700:      Support for mute-only mixers.
-               Volume control in read-only mode by default.
-               Marker for ALSA mixer support.
-
-0x030000:      Thermal and fan sysfs attributes were moved to the hwmon
-               device instead of being attached to the backing platform
-               device.
diff --git a/Documentation/laptops/toshiba_haps.txt b/Documentation/laptops/toshiba_haps.txt
deleted file mode 100644 (file)
index 0c1d88d..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-Kernel driver toshiba_haps
-Toshiba HDD Active Protection Sensor
-====================================
-
-Author: Azael Avalos <coproscefalo@gmail.com>
-
-
-0. Contents
------------
-
-1. Description
-2. Interface
-3. Accelerometer axes
-4. Supported devices
-5. Usage
-
-
-1. Description
---------------
-
-This driver provides support for the accelerometer found in various Toshiba
-laptops, being called "Toshiba HDD Protection - Shock Sensor" officially,
-and detects laptops automatically with this device.
-On Windows, Toshiba provided software monitors this device and provides
-automatic HDD protection (head unload) on sudden moves or harsh vibrations,
-however, this driver only provides a notification via a sysfs file to let
-userspace tools or daemons act accordingly, as well as providing a sysfs
-file to set the desired protection level or sensor sensibility.
-
-
-2. Interface
-------------
-
-This device comes with 3 methods:
-_STA -  Checks existence of the device, returning Zero if the device does not
-       exists or is not supported.
-PTLV -  Sets the desired protection level.
-RSSS -  Shuts down the HDD protection interface for a few seconds,
-       then restores normal operation.
-
-Note:
-The presence of Solid State Drives (SSD) can make this driver to fail loading,
-given the fact that such drives have no movable parts, and thus, not requiring
-any "protection" as well as failing during the evaluation of the _STA method
-found under this device.
-
-
-3. Accelerometer axes
----------------------
-
-This device does not report any axes, however, to query the sensor position
-a couple HCI (Hardware Configuration Interface) calls (0x6D and 0xA6) are
-provided to query such information, handled by the kernel module toshiba_acpi
-since kernel version 3.15.
-
-
-4. Supported devices
---------------------
-
-This driver binds itself to the ACPI device TOS620A, and any Toshiba laptop
-with this device is supported, given the fact that they have the presence of
-conventional HDD and not only SSD, or a combination of both HDD and SSD.
-
-
-5. Usage
---------
-
-The sysfs files under /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS620A:00/ are:
-protection_level - The protection_level is readable and writeable, and
-                  provides a way to let userspace query the current protection
-                  level, as well as set the desired protection level, the
-                  available protection levels are:
-                  0 - Disabled | 1 - Low | 2 - Medium | 3 - High
-reset_protection - The reset_protection entry is writeable only, being "1"
-                  the only parameter it accepts, it is used to trigger
-                  a reset of the protection interface.
index 9885f7c..060f4e4 100644 (file)
@@ -1,4 +1,4 @@
-:orphan:
+.. SPDX-License-Identifier: GPL-2.0
 
 ====
 LEDs
index edd291d..17674a9 100644 (file)
@@ -1,4 +1,4 @@
-:orphan:
+.. SPDX-License-Identifier: GPL-2.0
 
 ===================
 Kernel Livepatching
diff --git a/Documentation/locking/index.rst b/Documentation/locking/index.rst
new file mode 100644 (file)
index 0000000..626a463
--- /dev/null
@@ -0,0 +1,24 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=======
+locking
+=======
+
+.. toctree::
+    :maxdepth: 1
+
+    lockdep-design
+    lockstat
+    locktorture
+    mutex-design
+    rt-mutex-design
+    rt-mutex
+    spinlocks
+    ww-mutex-design
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
diff --git a/Documentation/locking/lockdep-design.rst b/Documentation/locking/lockdep-design.rst
new file mode 100644 (file)
index 0000000..23fcbc4
--- /dev/null
@@ -0,0 +1,394 @@
+Runtime locking correctness validator
+=====================================
+
+started by Ingo Molnar <mingo@redhat.com>
+
+additions by Arjan van de Ven <arjan@linux.intel.com>
+
+Lock-class
+----------
+
+The basic object the validator operates upon is a 'class' of locks.
+
+A class of locks is a group of locks that are logically the same with
+respect to locking rules, even if the locks may have multiple (possibly
+tens of thousands of) instantiations. For example a lock in the inode
+struct is one class, while each inode has its own instantiation of that
+lock class.
+
+The validator tracks the 'usage state' of lock-classes, and it tracks
+the dependencies between different lock-classes. Lock usage indicates
+how a lock is used with regard to its IRQ contexts, while lock
+dependency can be understood as lock order, where L1 -> L2 suggests that
+a task is attempting to acquire L2 while holding L1. From lockdep's
+perspective, the two locks (L1 and L2) are not necessarily related; that
+dependency just means the order ever happened. The validator maintains a
+continuing effort to prove lock usages and dependencies are correct or
+the validator will shoot a splat if incorrect.
+
+A lock-class's behavior is constructed by its instances collectively:
+when the first instance of a lock-class is used after bootup the class
+gets registered, then all (subsequent) instances will be mapped to the
+class and hence their usages and dependecies will contribute to those of
+the class. A lock-class does not go away when a lock instance does, but
+it can be removed if the memory space of the lock class (static or
+dynamic) is reclaimed, this happens for example when a module is
+unloaded or a workqueue is destroyed.
+
+State
+-----
+
+The validator tracks lock-class usage history and divides the usage into
+(4 usages * n STATEs + 1) categories:
+
+where the 4 usages can be:
+- 'ever held in STATE context'
+- 'ever held as readlock in STATE context'
+- 'ever held with STATE enabled'
+- 'ever held as readlock with STATE enabled'
+
+where the n STATEs are coded in kernel/locking/lockdep_states.h and as of
+now they include:
+- hardirq
+- softirq
+
+where the last 1 category is:
+- 'ever used'                                       [ == !unused        ]
+
+When locking rules are violated, these usage bits are presented in the
+locking error messages, inside curlies, with a total of 2 * n STATEs bits.
+A contrived example::
+
+   modprobe/2287 is trying to acquire lock:
+    (&sio_locks[i].lock){-.-.}, at: [<c02867fd>] mutex_lock+0x21/0x24
+
+   but task is already holding lock:
+    (&sio_locks[i].lock){-.-.}, at: [<c02867fd>] mutex_lock+0x21/0x24
+
+
+For a given lock, the bit positions from left to right indicate the usage
+of the lock and readlock (if exists), for each of the n STATEs listed
+above respectively, and the character displayed at each bit position
+indicates:
+
+   ===  ===================================================
+   '.'  acquired while irqs disabled and not in irq context
+   '-'  acquired in irq context
+   '+'  acquired with irqs enabled
+   '?'  acquired in irq context with irqs enabled.
+   ===  ===================================================
+
+The bits are illustrated with an example::
+
+    (&sio_locks[i].lock){-.-.}, at: [<c02867fd>] mutex_lock+0x21/0x24
+                         ||||
+                         ||| \-> softirq disabled and not in softirq context
+                         || \--> acquired in softirq context
+                         | \---> hardirq disabled and not in hardirq context
+                          \----> acquired in hardirq context
+
+
+For a given STATE, whether the lock is ever acquired in that STATE
+context and whether that STATE is enabled yields four possible cases as
+shown in the table below. The bit character is able to indicate which
+exact case is for the lock as of the reporting time.
+
+  +--------------+-------------+--------------+
+  |              | irq enabled | irq disabled |
+  +--------------+-------------+--------------+
+  | ever in irq  |      ?      |       -      |
+  +--------------+-------------+--------------+
+  | never in irq |      +      |       .      |
+  +--------------+-------------+--------------+
+
+The character '-' suggests irq is disabled because if otherwise the
+charactor '?' would have been shown instead. Similar deduction can be
+applied for '+' too.
+
+Unused locks (e.g., mutexes) cannot be part of the cause of an error.
+
+
+Single-lock state rules:
+------------------------
+
+A lock is irq-safe means it was ever used in an irq context, while a lock
+is irq-unsafe means it was ever acquired with irq enabled.
+
+A softirq-unsafe lock-class is automatically hardirq-unsafe as well. The
+following states must be exclusive: only one of them is allowed to be set
+for any lock-class based on its usage::
+
+ <hardirq-safe> or <hardirq-unsafe>
+ <softirq-safe> or <softirq-unsafe>
+
+This is because if a lock can be used in irq context (irq-safe) then it
+cannot be ever acquired with irq enabled (irq-unsafe). Otherwise, a
+deadlock may happen. For example, in the scenario that after this lock
+was acquired but before released, if the context is interrupted this
+lock will be attempted to acquire twice, which creates a deadlock,
+referred to as lock recursion deadlock.
+
+The validator detects and reports lock usage that violates these
+single-lock state rules.
+
+Multi-lock dependency rules:
+----------------------------
+
+The same lock-class must not be acquired twice, because this could lead
+to lock recursion deadlocks.
+
+Furthermore, two locks can not be taken in inverse order::
+
+ <L1> -> <L2>
+ <L2> -> <L1>
+
+because this could lead to a deadlock - referred to as lock inversion
+deadlock - as attempts to acquire the two locks form a circle which
+could lead to the two contexts waiting for each other permanently. The
+validator will find such dependency circle in arbitrary complexity,
+i.e., there can be any other locking sequence between the acquire-lock
+operations; the validator will still find whether these locks can be
+acquired in a circular fashion.
+
+Furthermore, the following usage based lock dependencies are not allowed
+between any two lock-classes::
+
+   <hardirq-safe>   ->  <hardirq-unsafe>
+   <softirq-safe>   ->  <softirq-unsafe>
+
+The first rule comes from the fact that a hardirq-safe lock could be
+taken by a hardirq context, interrupting a hardirq-unsafe lock - and
+thus could result in a lock inversion deadlock. Likewise, a softirq-safe
+lock could be taken by an softirq context, interrupting a softirq-unsafe
+lock.
+
+The above rules are enforced for any locking sequence that occurs in the
+kernel: when acquiring a new lock, the validator checks whether there is
+any rule violation between the new lock and any of the held locks.
+
+When a lock-class changes its state, the following aspects of the above
+dependency rules are enforced:
+
+- if a new hardirq-safe lock is discovered, we check whether it
+  took any hardirq-unsafe lock in the past.
+
+- if a new softirq-safe lock is discovered, we check whether it took
+  any softirq-unsafe lock in the past.
+
+- if a new hardirq-unsafe lock is discovered, we check whether any
+  hardirq-safe lock took it in the past.
+
+- if a new softirq-unsafe lock is discovered, we check whether any
+  softirq-safe lock took it in the past.
+
+(Again, we do these checks too on the basis that an interrupt context
+could interrupt _any_ of the irq-unsafe or hardirq-unsafe locks, which
+could lead to a lock inversion deadlock - even if that lock scenario did
+not trigger in practice yet.)
+
+Exception: Nested data dependencies leading to nested locking
+-------------------------------------------------------------
+
+There are a few cases where the Linux kernel acquires more than one
+instance of the same lock-class. Such cases typically happen when there
+is some sort of hierarchy within objects of the same type. In these
+cases there is an inherent "natural" ordering between the two objects
+(defined by the properties of the hierarchy), and the kernel grabs the
+locks in this fixed order on each of the objects.
+
+An example of such an object hierarchy that results in "nested locking"
+is that of a "whole disk" block-dev object and a "partition" block-dev
+object; the partition is "part of" the whole device and as long as one
+always takes the whole disk lock as a higher lock than the partition
+lock, the lock ordering is fully correct. The validator does not
+automatically detect this natural ordering, as the locking rule behind
+the ordering is not static.
+
+In order to teach the validator about this correct usage model, new
+versions of the various locking primitives were added that allow you to
+specify a "nesting level". An example call, for the block device mutex,
+looks like this::
+
+  enum bdev_bd_mutex_lock_class
+  {
+       BD_MUTEX_NORMAL,
+       BD_MUTEX_WHOLE,
+       BD_MUTEX_PARTITION
+  };
+
+mutex_lock_nested(&bdev->bd_contains->bd_mutex, BD_MUTEX_PARTITION);
+
+In this case the locking is done on a bdev object that is known to be a
+partition.
+
+The validator treats a lock that is taken in such a nested fashion as a
+separate (sub)class for the purposes of validation.
+
+Note: When changing code to use the _nested() primitives, be careful and
+check really thoroughly that the hierarchy is correctly mapped; otherwise
+you can get false positives or false negatives.
+
+Annotations
+-----------
+
+Two constructs can be used to annotate and check where and if certain locks
+must be held: lockdep_assert_held*(&lock) and lockdep_*pin_lock(&lock).
+
+As the name suggests, lockdep_assert_held* family of macros assert that a
+particular lock is held at a certain time (and generate a WARN() otherwise).
+This annotation is largely used all over the kernel, e.g. kernel/sched/
+core.c::
+
+  void update_rq_clock(struct rq *rq)
+  {
+       s64 delta;
+
+       lockdep_assert_held(&rq->lock);
+       [...]
+  }
+
+where holding rq->lock is required to safely update a rq's clock.
+
+The other family of macros is lockdep_*pin_lock(), which is admittedly only
+used for rq->lock ATM. Despite their limited adoption these annotations
+generate a WARN() if the lock of interest is "accidentally" unlocked. This turns
+out to be especially helpful to debug code with callbacks, where an upper
+layer assumes a lock remains taken, but a lower layer thinks it can maybe drop
+and reacquire the lock ("unwittingly" introducing races). lockdep_pin_lock()
+returns a 'struct pin_cookie' that is then used by lockdep_unpin_lock() to check
+that nobody tampered with the lock, e.g. kernel/sched/sched.h::
+
+  static inline void rq_pin_lock(struct rq *rq, struct rq_flags *rf)
+  {
+       rf->cookie = lockdep_pin_lock(&rq->lock);
+       [...]
+  }
+
+  static inline void rq_unpin_lock(struct rq *rq, struct rq_flags *rf)
+  {
+       [...]
+       lockdep_unpin_lock(&rq->lock, rf->cookie);
+  }
+
+While comments about locking requirements might provide useful information,
+the runtime checks performed by annotations are invaluable when debugging
+locking problems and they carry the same level of details when inspecting
+code.  Always prefer annotations when in doubt!
+
+Proof of 100% correctness:
+--------------------------
+
+The validator achieves perfect, mathematical 'closure' (proof of locking
+correctness) in the sense that for every simple, standalone single-task
+locking sequence that occurred at least once during the lifetime of the
+kernel, the validator proves it with a 100% certainty that no
+combination and timing of these locking sequences can cause any class of
+lock related deadlock. [1]_
+
+I.e. complex multi-CPU and multi-task locking scenarios do not have to
+occur in practice to prove a deadlock: only the simple 'component'
+locking chains have to occur at least once (anytime, in any
+task/context) for the validator to be able to prove correctness. (For
+example, complex deadlocks that would normally need more than 3 CPUs and
+a very unlikely constellation of tasks, irq-contexts and timings to
+occur, can be detected on a plain, lightly loaded single-CPU system as
+well!)
+
+This radically decreases the complexity of locking related QA of the
+kernel: what has to be done during QA is to trigger as many "simple"
+single-task locking dependencies in the kernel as possible, at least
+once, to prove locking correctness - instead of having to trigger every
+possible combination of locking interaction between CPUs, combined with
+every possible hardirq and softirq nesting scenario (which is impossible
+to do in practice).
+
+.. [1]
+
+    assuming that the validator itself is 100% correct, and no other
+    part of the system corrupts the state of the validator in any way.
+    We also assume that all NMI/SMM paths [which could interrupt
+    even hardirq-disabled codepaths] are correct and do not interfere
+    with the validator. We also assume that the 64-bit 'chain hash'
+    value is unique for every lock-chain in the system. Also, lock
+    recursion must not be higher than 20.
+
+Performance:
+------------
+
+The above rules require **massive** amounts of runtime checking. If we did
+that for every lock taken and for every irqs-enable event, it would
+render the system practically unusably slow. The complexity of checking
+is O(N^2), so even with just a few hundred lock-classes we'd have to do
+tens of thousands of checks for every event.
+
+This problem is solved by checking any given 'locking scenario' (unique
+sequence of locks taken after each other) only once. A simple stack of
+held locks is maintained, and a lightweight 64-bit hash value is
+calculated, which hash is unique for every lock chain. The hash value,
+when the chain is validated for the first time, is then put into a hash
+table, which hash-table can be checked in a lockfree manner. If the
+locking chain occurs again later on, the hash table tells us that we
+don't have to validate the chain again.
+
+Troubleshooting:
+----------------
+
+The validator tracks a maximum of MAX_LOCKDEP_KEYS number of lock classes.
+Exceeding this number will trigger the following lockdep warning:
+
+       (DEBUG_LOCKS_WARN_ON(id >= MAX_LOCKDEP_KEYS))
+
+By default, MAX_LOCKDEP_KEYS is currently set to 8191, and typical
+desktop systems have less than 1,000 lock classes, so this warning
+normally results from lock-class leakage or failure to properly
+initialize locks.  These two problems are illustrated below:
+
+1.     Repeated module loading and unloading while running the validator
+       will result in lock-class leakage.  The issue here is that each
+       load of the module will create a new set of lock classes for
+       that module's locks, but module unloading does not remove old
+       classes (see below discussion of reuse of lock classes for why).
+       Therefore, if that module is loaded and unloaded repeatedly,
+       the number of lock classes will eventually reach the maximum.
+
+2.     Using structures such as arrays that have large numbers of
+       locks that are not explicitly initialized.  For example,
+       a hash table with 8192 buckets where each bucket has its own
+       spinlock_t will consume 8192 lock classes -unless- each spinlock
+       is explicitly initialized at runtime, for example, using the
+       run-time spin_lock_init() as opposed to compile-time initializers
+       such as __SPIN_LOCK_UNLOCKED().  Failure to properly initialize
+       the per-bucket spinlocks would guarantee lock-class overflow.
+       In contrast, a loop that called spin_lock_init() on each lock
+       would place all 8192 locks into a single lock class.
+
+       The moral of this story is that you should always explicitly
+       initialize your locks.
+
+One might argue that the validator should be modified to allow
+lock classes to be reused.  However, if you are tempted to make this
+argument, first review the code and think through the changes that would
+be required, keeping in mind that the lock classes to be removed are
+likely to be linked into the lock-dependency graph.  This turns out to
+be harder to do than to say.
+
+Of course, if you do run out of lock classes, the next thing to do is
+to find the offending lock classes.  First, the following command gives
+you the number of lock classes currently in use along with the maximum::
+
+       grep "lock-classes" /proc/lockdep_stats
+
+This command produces the following output on a modest system::
+
+       lock-classes:                          748 [max: 8191]
+
+If the number allocated (748 above) increases continually over time,
+then there is likely a leak.  The following command can be used to
+identify the leaking lock classes::
+
+       grep "BD" /proc/lockdep
+
+Run the command and save the output, then compare against the output from
+a later run of this command to identify the leakers.  This same output
+can also help you find situations where runtime lock initialization has
+been omitted.
diff --git a/Documentation/locking/lockdep-design.txt b/Documentation/locking/lockdep-design.txt
deleted file mode 100644 (file)
index f189d13..0000000
+++ /dev/null
@@ -1,389 +0,0 @@
-Runtime locking correctness validator
-=====================================
-
-started by Ingo Molnar <mingo@redhat.com>
-additions by Arjan van de Ven <arjan@linux.intel.com>
-
-Lock-class
-----------
-
-The basic object the validator operates upon is a 'class' of locks.
-
-A class of locks is a group of locks that are logically the same with
-respect to locking rules, even if the locks may have multiple (possibly
-tens of thousands of) instantiations. For example a lock in the inode
-struct is one class, while each inode has its own instantiation of that
-lock class.
-
-The validator tracks the 'usage state' of lock-classes, and it tracks
-the dependencies between different lock-classes. Lock usage indicates
-how a lock is used with regard to its IRQ contexts, while lock
-dependency can be understood as lock order, where L1 -> L2 suggests that
-a task is attempting to acquire L2 while holding L1. From lockdep's
-perspective, the two locks (L1 and L2) are not necessarily related; that
-dependency just means the order ever happened. The validator maintains a
-continuing effort to prove lock usages and dependencies are correct or
-the validator will shoot a splat if incorrect.
-
-A lock-class's behavior is constructed by its instances collectively:
-when the first instance of a lock-class is used after bootup the class
-gets registered, then all (subsequent) instances will be mapped to the
-class and hence their usages and dependecies will contribute to those of
-the class. A lock-class does not go away when a lock instance does, but
-it can be removed if the memory space of the lock class (static or
-dynamic) is reclaimed, this happens for example when a module is
-unloaded or a workqueue is destroyed.
-
-State
------
-
-The validator tracks lock-class usage history and divides the usage into
-(4 usages * n STATEs + 1) categories:
-
-where the 4 usages can be:
-- 'ever held in STATE context'
-- 'ever held as readlock in STATE context'
-- 'ever held with STATE enabled'
-- 'ever held as readlock with STATE enabled'
-
-where the n STATEs are coded in kernel/locking/lockdep_states.h and as of
-now they include:
-- hardirq
-- softirq
-
-where the last 1 category is:
-- 'ever used'                                       [ == !unused        ]
-
-When locking rules are violated, these usage bits are presented in the
-locking error messages, inside curlies, with a total of 2 * n STATEs bits.
-A contrived example:
-
-   modprobe/2287 is trying to acquire lock:
-    (&sio_locks[i].lock){-.-.}, at: [<c02867fd>] mutex_lock+0x21/0x24
-
-   but task is already holding lock:
-    (&sio_locks[i].lock){-.-.}, at: [<c02867fd>] mutex_lock+0x21/0x24
-
-
-For a given lock, the bit positions from left to right indicate the usage
-of the lock and readlock (if exists), for each of the n STATEs listed
-above respectively, and the character displayed at each bit position
-indicates:
-
-   '.'  acquired while irqs disabled and not in irq context
-   '-'  acquired in irq context
-   '+'  acquired with irqs enabled
-   '?'  acquired in irq context with irqs enabled.
-
-The bits are illustrated with an example:
-
-    (&sio_locks[i].lock){-.-.}, at: [<c02867fd>] mutex_lock+0x21/0x24
-                         ||||
-                         ||| \-> softirq disabled and not in softirq context
-                         || \--> acquired in softirq context
-                         | \---> hardirq disabled and not in hardirq context
-                          \----> acquired in hardirq context
-
-
-For a given STATE, whether the lock is ever acquired in that STATE
-context and whether that STATE is enabled yields four possible cases as
-shown in the table below. The bit character is able to indicate which
-exact case is for the lock as of the reporting time.
-
-   -------------------------------------------
-  |              | irq enabled | irq disabled |
-  |-------------------------------------------|
-  | ever in irq  |      ?      |       -      |
-  |-------------------------------------------|
-  | never in irq |      +      |       .      |
-   -------------------------------------------
-
-The character '-' suggests irq is disabled because if otherwise the
-charactor '?' would have been shown instead. Similar deduction can be
-applied for '+' too.
-
-Unused locks (e.g., mutexes) cannot be part of the cause of an error.
-
-
-Single-lock state rules:
-------------------------
-
-A lock is irq-safe means it was ever used in an irq context, while a lock
-is irq-unsafe means it was ever acquired with irq enabled.
-
-A softirq-unsafe lock-class is automatically hardirq-unsafe as well. The
-following states must be exclusive: only one of them is allowed to be set
-for any lock-class based on its usage:
-
- <hardirq-safe> or <hardirq-unsafe>
- <softirq-safe> or <softirq-unsafe>
-
-This is because if a lock can be used in irq context (irq-safe) then it
-cannot be ever acquired with irq enabled (irq-unsafe). Otherwise, a
-deadlock may happen. For example, in the scenario that after this lock
-was acquired but before released, if the context is interrupted this
-lock will be attempted to acquire twice, which creates a deadlock,
-referred to as lock recursion deadlock.
-
-The validator detects and reports lock usage that violates these
-single-lock state rules.
-
-Multi-lock dependency rules:
-----------------------------
-
-The same lock-class must not be acquired twice, because this could lead
-to lock recursion deadlocks.
-
-Furthermore, two locks can not be taken in inverse order:
-
- <L1> -> <L2>
- <L2> -> <L1>
-
-because this could lead to a deadlock - referred to as lock inversion
-deadlock - as attempts to acquire the two locks form a circle which
-could lead to the two contexts waiting for each other permanently. The
-validator will find such dependency circle in arbitrary complexity,
-i.e., there can be any other locking sequence between the acquire-lock
-operations; the validator will still find whether these locks can be
-acquired in a circular fashion.
-
-Furthermore, the following usage based lock dependencies are not allowed
-between any two lock-classes:
-
-   <hardirq-safe>   ->  <hardirq-unsafe>
-   <softirq-safe>   ->  <softirq-unsafe>
-
-The first rule comes from the fact that a hardirq-safe lock could be
-taken by a hardirq context, interrupting a hardirq-unsafe lock - and
-thus could result in a lock inversion deadlock. Likewise, a softirq-safe
-lock could be taken by an softirq context, interrupting a softirq-unsafe
-lock.
-
-The above rules are enforced for any locking sequence that occurs in the
-kernel: when acquiring a new lock, the validator checks whether there is
-any rule violation between the new lock and any of the held locks.
-
-When a lock-class changes its state, the following aspects of the above
-dependency rules are enforced:
-
-- if a new hardirq-safe lock is discovered, we check whether it
-  took any hardirq-unsafe lock in the past.
-
-- if a new softirq-safe lock is discovered, we check whether it took
-  any softirq-unsafe lock in the past.
-
-- if a new hardirq-unsafe lock is discovered, we check whether any
-  hardirq-safe lock took it in the past.
-
-- if a new softirq-unsafe lock is discovered, we check whether any
-  softirq-safe lock took it in the past.
-
-(Again, we do these checks too on the basis that an interrupt context
-could interrupt _any_ of the irq-unsafe or hardirq-unsafe locks, which
-could lead to a lock inversion deadlock - even if that lock scenario did
-not trigger in practice yet.)
-
-Exception: Nested data dependencies leading to nested locking
--------------------------------------------------------------
-
-There are a few cases where the Linux kernel acquires more than one
-instance of the same lock-class. Such cases typically happen when there
-is some sort of hierarchy within objects of the same type. In these
-cases there is an inherent "natural" ordering between the two objects
-(defined by the properties of the hierarchy), and the kernel grabs the
-locks in this fixed order on each of the objects.
-
-An example of such an object hierarchy that results in "nested locking"
-is that of a "whole disk" block-dev object and a "partition" block-dev
-object; the partition is "part of" the whole device and as long as one
-always takes the whole disk lock as a higher lock than the partition
-lock, the lock ordering is fully correct. The validator does not
-automatically detect this natural ordering, as the locking rule behind
-the ordering is not static.
-
-In order to teach the validator about this correct usage model, new
-versions of the various locking primitives were added that allow you to
-specify a "nesting level". An example call, for the block device mutex,
-looks like this:
-
-enum bdev_bd_mutex_lock_class
-{
-       BD_MUTEX_NORMAL,
-       BD_MUTEX_WHOLE,
-       BD_MUTEX_PARTITION
-};
-
- mutex_lock_nested(&bdev->bd_contains->bd_mutex, BD_MUTEX_PARTITION);
-
-In this case the locking is done on a bdev object that is known to be a
-partition.
-
-The validator treats a lock that is taken in such a nested fashion as a
-separate (sub)class for the purposes of validation.
-
-Note: When changing code to use the _nested() primitives, be careful and
-check really thoroughly that the hierarchy is correctly mapped; otherwise
-you can get false positives or false negatives.
-
-Annotations
------------
-
-Two constructs can be used to annotate and check where and if certain locks
-must be held: lockdep_assert_held*(&lock) and lockdep_*pin_lock(&lock).
-
-As the name suggests, lockdep_assert_held* family of macros assert that a
-particular lock is held at a certain time (and generate a WARN() otherwise).
-This annotation is largely used all over the kernel, e.g. kernel/sched/
-core.c
-
-  void update_rq_clock(struct rq *rq)
-  {
-       s64 delta;
-
-       lockdep_assert_held(&rq->lock);
-       [...]
-  }
-
-where holding rq->lock is required to safely update a rq's clock.
-
-The other family of macros is lockdep_*pin_lock(), which is admittedly only
-used for rq->lock ATM. Despite their limited adoption these annotations
-generate a WARN() if the lock of interest is "accidentally" unlocked. This turns
-out to be especially helpful to debug code with callbacks, where an upper
-layer assumes a lock remains taken, but a lower layer thinks it can maybe drop
-and reacquire the lock ("unwittingly" introducing races). lockdep_pin_lock()
-returns a 'struct pin_cookie' that is then used by lockdep_unpin_lock() to check
-that nobody tampered with the lock, e.g. kernel/sched/sched.h
-
-  static inline void rq_pin_lock(struct rq *rq, struct rq_flags *rf)
-  {
-       rf->cookie = lockdep_pin_lock(&rq->lock);
-       [...]
-  }
-
-  static inline void rq_unpin_lock(struct rq *rq, struct rq_flags *rf)
-  {
-       [...]
-       lockdep_unpin_lock(&rq->lock, rf->cookie);
-  }
-
-While comments about locking requirements might provide useful information,
-the runtime checks performed by annotations are invaluable when debugging
-locking problems and they carry the same level of details when inspecting
-code.  Always prefer annotations when in doubt!
-
-Proof of 100% correctness:
---------------------------
-
-The validator achieves perfect, mathematical 'closure' (proof of locking
-correctness) in the sense that for every simple, standalone single-task
-locking sequence that occurred at least once during the lifetime of the
-kernel, the validator proves it with a 100% certainty that no
-combination and timing of these locking sequences can cause any class of
-lock related deadlock. [*]
-
-I.e. complex multi-CPU and multi-task locking scenarios do not have to
-occur in practice to prove a deadlock: only the simple 'component'
-locking chains have to occur at least once (anytime, in any
-task/context) for the validator to be able to prove correctness. (For
-example, complex deadlocks that would normally need more than 3 CPUs and
-a very unlikely constellation of tasks, irq-contexts and timings to
-occur, can be detected on a plain, lightly loaded single-CPU system as
-well!)
-
-This radically decreases the complexity of locking related QA of the
-kernel: what has to be done during QA is to trigger as many "simple"
-single-task locking dependencies in the kernel as possible, at least
-once, to prove locking correctness - instead of having to trigger every
-possible combination of locking interaction between CPUs, combined with
-every possible hardirq and softirq nesting scenario (which is impossible
-to do in practice).
-
-[*] assuming that the validator itself is 100% correct, and no other
-    part of the system corrupts the state of the validator in any way.
-    We also assume that all NMI/SMM paths [which could interrupt
-    even hardirq-disabled codepaths] are correct and do not interfere
-    with the validator. We also assume that the 64-bit 'chain hash'
-    value is unique for every lock-chain in the system. Also, lock
-    recursion must not be higher than 20.
-
-Performance:
-------------
-
-The above rules require _massive_ amounts of runtime checking. If we did
-that for every lock taken and for every irqs-enable event, it would
-render the system practically unusably slow. The complexity of checking
-is O(N^2), so even with just a few hundred lock-classes we'd have to do
-tens of thousands of checks for every event.
-
-This problem is solved by checking any given 'locking scenario' (unique
-sequence of locks taken after each other) only once. A simple stack of
-held locks is maintained, and a lightweight 64-bit hash value is
-calculated, which hash is unique for every lock chain. The hash value,
-when the chain is validated for the first time, is then put into a hash
-table, which hash-table can be checked in a lockfree manner. If the
-locking chain occurs again later on, the hash table tells us that we
-don't have to validate the chain again.
-
-Troubleshooting:
-----------------
-
-The validator tracks a maximum of MAX_LOCKDEP_KEYS number of lock classes.
-Exceeding this number will trigger the following lockdep warning:
-
-       (DEBUG_LOCKS_WARN_ON(id >= MAX_LOCKDEP_KEYS))
-
-By default, MAX_LOCKDEP_KEYS is currently set to 8191, and typical
-desktop systems have less than 1,000 lock classes, so this warning
-normally results from lock-class leakage or failure to properly
-initialize locks.  These two problems are illustrated below:
-
-1.     Repeated module loading and unloading while running the validator
-       will result in lock-class leakage.  The issue here is that each
-       load of the module will create a new set of lock classes for
-       that module's locks, but module unloading does not remove old
-       classes (see below discussion of reuse of lock classes for why).
-       Therefore, if that module is loaded and unloaded repeatedly,
-       the number of lock classes will eventually reach the maximum.
-
-2.     Using structures such as arrays that have large numbers of
-       locks that are not explicitly initialized.  For example,
-       a hash table with 8192 buckets where each bucket has its own
-       spinlock_t will consume 8192 lock classes -unless- each spinlock
-       is explicitly initialized at runtime, for example, using the
-       run-time spin_lock_init() as opposed to compile-time initializers
-       such as __SPIN_LOCK_UNLOCKED().  Failure to properly initialize
-       the per-bucket spinlocks would guarantee lock-class overflow.
-       In contrast, a loop that called spin_lock_init() on each lock
-       would place all 8192 locks into a single lock class.
-
-       The moral of this story is that you should always explicitly
-       initialize your locks.
-
-One might argue that the validator should be modified to allow
-lock classes to be reused.  However, if you are tempted to make this
-argument, first review the code and think through the changes that would
-be required, keeping in mind that the lock classes to be removed are
-likely to be linked into the lock-dependency graph.  This turns out to
-be harder to do than to say.
-
-Of course, if you do run out of lock classes, the next thing to do is
-to find the offending lock classes.  First, the following command gives
-you the number of lock classes currently in use along with the maximum:
-
-       grep "lock-classes" /proc/lockdep_stats
-
-This command produces the following output on a modest system:
-
-        lock-classes:                          748 [max: 8191]
-
-If the number allocated (748 above) increases continually over time,
-then there is likely a leak.  The following command can be used to
-identify the leaking lock classes:
-
-       grep "BD" /proc/lockdep
-
-Run the command and save the output, then compare against the output from
-a later run of this command to identify the leakers.  This same output
-can also help you find situations where runtime lock initialization has
-been omitted.
diff --git a/Documentation/locking/lockstat.rst b/Documentation/locking/lockstat.rst
new file mode 100644 (file)
index 0000000..536eab8
--- /dev/null
@@ -0,0 +1,204 @@
+===============
+Lock Statistics
+===============
+
+What
+====
+
+As the name suggests, it provides statistics on locks.
+
+
+Why
+===
+
+Because things like lock contention can severely impact performance.
+
+How
+===
+
+Lockdep already has hooks in the lock functions and maps lock instances to
+lock classes. We build on that (see Documentation/locking/lockdep-design.rst).
+The graph below shows the relation between the lock functions and the various
+hooks therein::
+
+        __acquire
+            |
+           lock _____
+            |        \
+            |    __contended
+            |         |
+            |       <wait>
+            | _______/
+            |/
+            |
+       __acquired
+            |
+            .
+          <hold>
+            .
+            |
+       __release
+            |
+         unlock
+
+  lock, unlock - the regular lock functions
+  __*          - the hooks
+  <>           - states
+
+With these hooks we provide the following statistics:
+
+ con-bounces
+       - number of lock contention that involved x-cpu data
+ contentions
+       - number of lock acquisitions that had to wait
+ wait time
+     min
+       - shortest (non-0) time we ever had to wait for a lock
+     max
+       - longest time we ever had to wait for a lock
+     total
+       - total time we spend waiting on this lock
+     avg
+       - average time spent waiting on this lock
+ acq-bounces
+       - number of lock acquisitions that involved x-cpu data
+ acquisitions
+       - number of times we took the lock
+ hold time
+     min
+       - shortest (non-0) time we ever held the lock
+     max
+       - longest time we ever held the lock
+     total
+       - total time this lock was held
+     avg
+       - average time this lock was held
+
+These numbers are gathered per lock class, per read/write state (when
+applicable).
+
+It also tracks 4 contention points per class. A contention point is a call site
+that had to wait on lock acquisition.
+
+Configuration
+-------------
+
+Lock statistics are enabled via CONFIG_LOCK_STAT.
+
+Usage
+-----
+
+Enable collection of statistics::
+
+       # echo 1 >/proc/sys/kernel/lock_stat
+
+Disable collection of statistics::
+
+       # echo 0 >/proc/sys/kernel/lock_stat
+
+Look at the current lock statistics::
+
+  ( line numbers not part of actual output, done for clarity in the explanation
+    below )
+
+  # less /proc/lock_stat
+
+  01 lock_stat version 0.4
+  02-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+  03                              class name    con-bounces    contentions   waittime-min   waittime-max waittime-total   waittime-avg    acq-bounces   acquisitions   holdtime-min   holdtime-max holdtime-total   holdtime-avg
+  04-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+  05
+  06                         &mm->mmap_sem-W:            46             84           0.26         939.10       16371.53         194.90          47291        2922365           0.16     2220301.69 17464026916.32        5975.99
+  07                         &mm->mmap_sem-R:            37            100           1.31      299502.61      325629.52        3256.30         212344       34316685           0.10        7744.91    95016910.20           2.77
+  08                         ---------------
+  09                           &mm->mmap_sem              1          [<ffffffff811502a7>] khugepaged_scan_mm_slot+0x57/0x280
+  10                           &mm->mmap_sem             96          [<ffffffff815351c4>] __do_page_fault+0x1d4/0x510
+  11                           &mm->mmap_sem             34          [<ffffffff81113d77>] vm_mmap_pgoff+0x87/0xd0
+  12                           &mm->mmap_sem             17          [<ffffffff81127e71>] vm_munmap+0x41/0x80
+  13                         ---------------
+  14                           &mm->mmap_sem              1          [<ffffffff81046fda>] dup_mmap+0x2a/0x3f0
+  15                           &mm->mmap_sem             60          [<ffffffff81129e29>] SyS_mprotect+0xe9/0x250
+  16                           &mm->mmap_sem             41          [<ffffffff815351c4>] __do_page_fault+0x1d4/0x510
+  17                           &mm->mmap_sem             68          [<ffffffff81113d77>] vm_mmap_pgoff+0x87/0xd0
+  18
+  19.............................................................................................................................................................................................................................
+  20
+  21                         unix_table_lock:           110            112           0.21          49.24         163.91           1.46          21094          66312           0.12         624.42       31589.81           0.48
+  22                         ---------------
+  23                         unix_table_lock             45          [<ffffffff8150ad8e>] unix_create1+0x16e/0x1b0
+  24                         unix_table_lock             47          [<ffffffff8150b111>] unix_release_sock+0x31/0x250
+  25                         unix_table_lock             15          [<ffffffff8150ca37>] unix_find_other+0x117/0x230
+  26                         unix_table_lock              5          [<ffffffff8150a09f>] unix_autobind+0x11f/0x1b0
+  27                         ---------------
+  28                         unix_table_lock             39          [<ffffffff8150b111>] unix_release_sock+0x31/0x250
+  29                         unix_table_lock             49          [<ffffffff8150ad8e>] unix_create1+0x16e/0x1b0
+  30                         unix_table_lock             20          [<ffffffff8150ca37>] unix_find_other+0x117/0x230
+  31                         unix_table_lock              4          [<ffffffff8150a09f>] unix_autobind+0x11f/0x1b0
+
+
+This excerpt shows the first two lock class statistics. Line 01 shows the
+output version - each time the format changes this will be updated. Line 02-04
+show the header with column descriptions. Lines 05-18 and 20-31 show the actual
+statistics. These statistics come in two parts; the actual stats separated by a
+short separator (line 08, 13) from the contention points.
+
+Lines 09-12 show the first 4 recorded contention points (the code
+which tries to get the lock) and lines 14-17 show the first 4 recorded
+contended points (the lock holder). It is possible that the max
+con-bounces point is missing in the statistics.
+
+The first lock (05-18) is a read/write lock, and shows two lines above the
+short separator. The contention points don't match the column descriptors,
+they have two: contentions and [<IP>] symbol. The second set of contention
+points are the points we're contending with.
+
+The integer part of the time values is in us.
+
+Dealing with nested locks, subclasses may appear::
+
+  32...........................................................................................................................................................................................................................
+  33
+  34                               &rq->lock:       13128          13128           0.43         190.53      103881.26           7.91          97454        3453404           0.00         401.11    13224683.11           3.82
+  35                               ---------
+  36                               &rq->lock          645          [<ffffffff8103bfc4>] task_rq_lock+0x43/0x75
+  37                               &rq->lock          297          [<ffffffff8104ba65>] try_to_wake_up+0x127/0x25a
+  38                               &rq->lock          360          [<ffffffff8103c4c5>] select_task_rq_fair+0x1f0/0x74a
+  39                               &rq->lock          428          [<ffffffff81045f98>] scheduler_tick+0x46/0x1fb
+  40                               ---------
+  41                               &rq->lock           77          [<ffffffff8103bfc4>] task_rq_lock+0x43/0x75
+  42                               &rq->lock          174          [<ffffffff8104ba65>] try_to_wake_up+0x127/0x25a
+  43                               &rq->lock         4715          [<ffffffff8103ed4b>] double_rq_lock+0x42/0x54
+  44                               &rq->lock          893          [<ffffffff81340524>] schedule+0x157/0x7b8
+  45
+  46...........................................................................................................................................................................................................................
+  47
+  48                             &rq->lock/1:        1526          11488           0.33         388.73      136294.31          11.86          21461          38404           0.00          37.93      109388.53           2.84
+  49                             -----------
+  50                             &rq->lock/1        11526          [<ffffffff8103ed58>] double_rq_lock+0x4f/0x54
+  51                             -----------
+  52                             &rq->lock/1         5645          [<ffffffff8103ed4b>] double_rq_lock+0x42/0x54
+  53                             &rq->lock/1         1224          [<ffffffff81340524>] schedule+0x157/0x7b8
+  54                             &rq->lock/1         4336          [<ffffffff8103ed58>] double_rq_lock+0x4f/0x54
+  55                             &rq->lock/1          181          [<ffffffff8104ba65>] try_to_wake_up+0x127/0x25a
+
+Line 48 shows statistics for the second subclass (/1) of &rq->lock class
+(subclass starts from 0), since in this case, as line 50 suggests,
+double_rq_lock actually acquires a nested lock of two spinlocks.
+
+View the top contending locks::
+
+  # grep : /proc/lock_stat | head
+                       clockevents_lock:       2926159        2947636           0.15       46882.81  1784540466.34         605.41        3381345        3879161           0.00        2260.97    53178395.68          13.71
+                    tick_broadcast_lock:        346460         346717           0.18        2257.43    39364622.71         113.54        3642919        4242696           0.00        2263.79    49173646.60          11.59
+                 &mapping->i_mmap_mutex:        203896         203899           3.36      645530.05 31767507988.39      155800.21        3361776        8893984           0.17        2254.15    14110121.02           1.59
+                              &rq->lock:        135014         136909           0.18         606.09      842160.68           6.15        1540728       10436146           0.00         728.72    17606683.41           1.69
+              &(&zone->lru_lock)->rlock:         93000          94934           0.16          59.18      188253.78           1.98        1199912        3809894           0.15         391.40     3559518.81           0.93
+                        tasklist_lock-W:         40667          41130           0.23        1189.42      428980.51          10.43         270278         510106           0.16         653.51     3939674.91           7.72
+                        tasklist_lock-R:         21298          21305           0.20        1310.05      215511.12          10.12         186204         241258           0.14        1162.33     1179779.23           4.89
+                             rcu_node_1:         47656          49022           0.16         635.41      193616.41           3.95         844888        1865423           0.00         764.26     1656226.96           0.89
+       &(&dentry->d_lockref.lock)->rlock:         39791          40179           0.15        1302.08       88851.96           2.21        2790851       12527025           0.10        1910.75     3379714.27           0.27
+                             rcu_node_0:         29203          30064           0.16         786.55     1555573.00          51.74          88963         244254           0.00         398.87      428872.51           1.76
+
+Clear the statistics::
+
+  # echo 0 > /proc/lock_stat
diff --git a/Documentation/locking/lockstat.txt b/Documentation/locking/lockstat.txt
deleted file mode 100644 (file)
index fdbeb0c..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-
-LOCK STATISTICS
-
-- WHAT
-
-As the name suggests, it provides statistics on locks.
-
-- WHY
-
-Because things like lock contention can severely impact performance.
-
-- HOW
-
-Lockdep already has hooks in the lock functions and maps lock instances to
-lock classes. We build on that (see Documentation/locking/lockdep-design.txt).
-The graph below shows the relation between the lock functions and the various
-hooks therein.
-
-        __acquire
-            |
-           lock _____
-            |        \
-            |    __contended
-            |         |
-            |       <wait>
-            | _______/
-            |/
-            |
-       __acquired
-            |
-            .
-          <hold>
-            .
-            |
-       __release
-            |
-         unlock
-
-lock, unlock   - the regular lock functions
-__*            - the hooks
-<>             - states
-
-With these hooks we provide the following statistics:
-
- con-bounces       - number of lock contention that involved x-cpu data
- contentions       - number of lock acquisitions that had to wait
- wait time min     - shortest (non-0) time we ever had to wait for a lock
-           max     - longest time we ever had to wait for a lock
-          total   - total time we spend waiting on this lock
-          avg     - average time spent waiting on this lock
- acq-bounces       - number of lock acquisitions that involved x-cpu data
- acquisitions      - number of times we took the lock
- hold time min     - shortest (non-0) time we ever held the lock
-          max     - longest time we ever held the lock
-          total   - total time this lock was held
-          avg     - average time this lock was held
-
-These numbers are gathered per lock class, per read/write state (when
-applicable).
-
-It also tracks 4 contention points per class. A contention point is a call site
-that had to wait on lock acquisition.
-
- - CONFIGURATION
-
-Lock statistics are enabled via CONFIG_LOCK_STAT.
-
- - USAGE
-
-Enable collection of statistics:
-
-# echo 1 >/proc/sys/kernel/lock_stat
-
-Disable collection of statistics:
-
-# echo 0 >/proc/sys/kernel/lock_stat
-
-Look at the current lock statistics:
-
-( line numbers not part of actual output, done for clarity in the explanation
-  below )
-
-# less /proc/lock_stat
-
-01 lock_stat version 0.4
-02-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-03                              class name    con-bounces    contentions   waittime-min   waittime-max waittime-total   waittime-avg    acq-bounces   acquisitions   holdtime-min   holdtime-max holdtime-total   holdtime-avg
-04-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-05
-06                         &mm->mmap_sem-W:            46             84           0.26         939.10       16371.53         194.90          47291        2922365           0.16     2220301.69 17464026916.32        5975.99
-07                         &mm->mmap_sem-R:            37            100           1.31      299502.61      325629.52        3256.30         212344       34316685           0.10        7744.91    95016910.20           2.77
-08                         ---------------
-09                           &mm->mmap_sem              1          [<ffffffff811502a7>] khugepaged_scan_mm_slot+0x57/0x280
-10                           &mm->mmap_sem             96          [<ffffffff815351c4>] __do_page_fault+0x1d4/0x510
-11                           &mm->mmap_sem             34          [<ffffffff81113d77>] vm_mmap_pgoff+0x87/0xd0
-12                           &mm->mmap_sem             17          [<ffffffff81127e71>] vm_munmap+0x41/0x80
-13                         ---------------
-14                           &mm->mmap_sem              1          [<ffffffff81046fda>] dup_mmap+0x2a/0x3f0
-15                           &mm->mmap_sem             60          [<ffffffff81129e29>] SyS_mprotect+0xe9/0x250
-16                           &mm->mmap_sem             41          [<ffffffff815351c4>] __do_page_fault+0x1d4/0x510
-17                           &mm->mmap_sem             68          [<ffffffff81113d77>] vm_mmap_pgoff+0x87/0xd0
-18
-19.............................................................................................................................................................................................................................
-20
-21                         unix_table_lock:           110            112           0.21          49.24         163.91           1.46          21094          66312           0.12         624.42       31589.81           0.48
-22                         ---------------
-23                         unix_table_lock             45          [<ffffffff8150ad8e>] unix_create1+0x16e/0x1b0
-24                         unix_table_lock             47          [<ffffffff8150b111>] unix_release_sock+0x31/0x250
-25                         unix_table_lock             15          [<ffffffff8150ca37>] unix_find_other+0x117/0x230
-26                         unix_table_lock              5          [<ffffffff8150a09f>] unix_autobind+0x11f/0x1b0
-27                         ---------------
-28                         unix_table_lock             39          [<ffffffff8150b111>] unix_release_sock+0x31/0x250
-29                         unix_table_lock             49          [<ffffffff8150ad8e>] unix_create1+0x16e/0x1b0
-30                         unix_table_lock             20          [<ffffffff8150ca37>] unix_find_other+0x117/0x230
-31                         unix_table_lock              4          [<ffffffff8150a09f>] unix_autobind+0x11f/0x1b0
-
-
-This excerpt shows the first two lock class statistics. Line 01 shows the
-output version - each time the format changes this will be updated. Line 02-04
-show the header with column descriptions. Lines 05-18 and 20-31 show the actual
-statistics. These statistics come in two parts; the actual stats separated by a
-short separator (line 08, 13) from the contention points.
-
-Lines 09-12 show the first 4 recorded contention points (the code
-which tries to get the lock) and lines 14-17 show the first 4 recorded
-contended points (the lock holder). It is possible that the max
-con-bounces point is missing in the statistics.
-
-The first lock (05-18) is a read/write lock, and shows two lines above the
-short separator. The contention points don't match the column descriptors,
-they have two: contentions and [<IP>] symbol. The second set of contention
-points are the points we're contending with.
-
-The integer part of the time values is in us.
-
-Dealing with nested locks, subclasses may appear:
-
-32...........................................................................................................................................................................................................................
-33
-34                               &rq->lock:       13128          13128           0.43         190.53      103881.26           7.91          97454        3453404           0.00         401.11    13224683.11           3.82
-35                               ---------
-36                               &rq->lock          645          [<ffffffff8103bfc4>] task_rq_lock+0x43/0x75
-37                               &rq->lock          297          [<ffffffff8104ba65>] try_to_wake_up+0x127/0x25a
-38                               &rq->lock          360          [<ffffffff8103c4c5>] select_task_rq_fair+0x1f0/0x74a
-39                               &rq->lock          428          [<ffffffff81045f98>] scheduler_tick+0x46/0x1fb
-40                               ---------
-41                               &rq->lock           77          [<ffffffff8103bfc4>] task_rq_lock+0x43/0x75
-42                               &rq->lock          174          [<ffffffff8104ba65>] try_to_wake_up+0x127/0x25a
-43                               &rq->lock         4715          [<ffffffff8103ed4b>] double_rq_lock+0x42/0x54
-44                               &rq->lock          893          [<ffffffff81340524>] schedule+0x157/0x7b8
-45
-46...........................................................................................................................................................................................................................
-47
-48                             &rq->lock/1:        1526          11488           0.33         388.73      136294.31          11.86          21461          38404           0.00          37.93      109388.53           2.84
-49                             -----------
-50                             &rq->lock/1        11526          [<ffffffff8103ed58>] double_rq_lock+0x4f/0x54
-51                             -----------
-52                             &rq->lock/1         5645          [<ffffffff8103ed4b>] double_rq_lock+0x42/0x54
-53                             &rq->lock/1         1224          [<ffffffff81340524>] schedule+0x157/0x7b8
-54                             &rq->lock/1         4336          [<ffffffff8103ed58>] double_rq_lock+0x4f/0x54
-55                             &rq->lock/1          181          [<ffffffff8104ba65>] try_to_wake_up+0x127/0x25a
-
-Line 48 shows statistics for the second subclass (/1) of &rq->lock class
-(subclass starts from 0), since in this case, as line 50 suggests,
-double_rq_lock actually acquires a nested lock of two spinlocks.
-
-View the top contending locks:
-
-# grep : /proc/lock_stat | head
-                       clockevents_lock:       2926159        2947636           0.15       46882.81  1784540466.34         605.41        3381345        3879161           0.00        2260.97    53178395.68          13.71
-                    tick_broadcast_lock:        346460         346717           0.18        2257.43    39364622.71         113.54        3642919        4242696           0.00        2263.79    49173646.60          11.59
-                 &mapping->i_mmap_mutex:        203896         203899           3.36      645530.05 31767507988.39      155800.21        3361776        8893984           0.17        2254.15    14110121.02           1.59
-                              &rq->lock:        135014         136909           0.18         606.09      842160.68           6.15        1540728       10436146           0.00         728.72    17606683.41           1.69
-              &(&zone->lru_lock)->rlock:         93000          94934           0.16          59.18      188253.78           1.98        1199912        3809894           0.15         391.40     3559518.81           0.93
-                        tasklist_lock-W:         40667          41130           0.23        1189.42      428980.51          10.43         270278         510106           0.16         653.51     3939674.91           7.72
-                        tasklist_lock-R:         21298          21305           0.20        1310.05      215511.12          10.12         186204         241258           0.14        1162.33     1179779.23           4.89
-                             rcu_node_1:         47656          49022           0.16         635.41      193616.41           3.95         844888        1865423           0.00         764.26     1656226.96           0.89
-       &(&dentry->d_lockref.lock)->rlock:         39791          40179           0.15        1302.08       88851.96           2.21        2790851       12527025           0.10        1910.75     3379714.27           0.27
-                             rcu_node_0:         29203          30064           0.16         786.55     1555573.00          51.74          88963         244254           0.00         398.87      428872.51           1.76
-
-Clear the statistics:
-
-# echo 0 > /proc/lock_stat
diff --git a/Documentation/locking/locktorture.rst b/Documentation/locking/locktorture.rst
new file mode 100644 (file)
index 0000000..e79eeec
--- /dev/null
@@ -0,0 +1,170 @@
+==================================
+Kernel Lock Torture Test Operation
+==================================
+
+CONFIG_LOCK_TORTURE_TEST
+========================
+
+The CONFIG LOCK_TORTURE_TEST config option provides a kernel module
+that runs torture tests on core kernel locking primitives. The kernel
+module, 'locktorture', may be built after the fact on the running
+kernel to be tested, if desired. The tests periodically output status
+messages via printk(), which can be examined via the dmesg (perhaps
+grepping for "torture").  The test is started when the module is loaded,
+and stops when the module is unloaded. This program is based on how RCU
+is tortured, via rcutorture.
+
+This torture test consists of creating a number of kernel threads which
+acquire the lock and hold it for specific amount of time, thus simulating
+different critical region behaviors. The amount of contention on the lock
+can be simulated by either enlarging this critical region hold time and/or
+creating more kthreads.
+
+
+Module Parameters
+=================
+
+This module has the following parameters:
+
+
+Locktorture-specific
+--------------------
+
+nwriters_stress
+                 Number of kernel threads that will stress exclusive lock
+                 ownership (writers). The default value is twice the number
+                 of online CPUs.
+
+nreaders_stress
+                 Number of kernel threads that will stress shared lock
+                 ownership (readers). The default is the same amount of writer
+                 locks. If the user did not specify nwriters_stress, then
+                 both readers and writers be the amount of online CPUs.
+
+torture_type
+                 Type of lock to torture. By default, only spinlocks will
+                 be tortured. This module can torture the following locks,
+                 with string values as follows:
+
+                    - "lock_busted":
+                               Simulates a buggy lock implementation.
+
+                    - "spin_lock":
+                               spin_lock() and spin_unlock() pairs.
+
+                    - "spin_lock_irq":
+                               spin_lock_irq() and spin_unlock_irq() pairs.
+
+                    - "rw_lock":
+                               read/write lock() and unlock() rwlock pairs.
+
+                    - "rw_lock_irq":
+                               read/write lock_irq() and unlock_irq()
+                               rwlock pairs.
+
+                    - "mutex_lock":
+                               mutex_lock() and mutex_unlock() pairs.
+
+                    - "rtmutex_lock":
+                               rtmutex_lock() and rtmutex_unlock() pairs.
+                               Kernel must have CONFIG_RT_MUTEX=y.
+
+                    - "rwsem_lock":
+                               read/write down() and up() semaphore pairs.
+
+
+Torture-framework (RCU + locking)
+---------------------------------
+
+shutdown_secs
+                 The number of seconds to run the test before terminating
+                 the test and powering off the system.  The default is
+                 zero, which disables test termination and system shutdown.
+                 This capability is useful for automated testing.
+
+onoff_interval
+                 The number of seconds between each attempt to execute a
+                 randomly selected CPU-hotplug operation.  Defaults
+                 to zero, which disables CPU hotplugging.  In
+                 CONFIG_HOTPLUG_CPU=n kernels, locktorture will silently
+                 refuse to do any CPU-hotplug operations regardless of
+                 what value is specified for onoff_interval.
+
+onoff_holdoff
+                 The number of seconds to wait until starting CPU-hotplug
+                 operations.  This would normally only be used when
+                 locktorture was built into the kernel and started
+                 automatically at boot time, in which case it is useful
+                 in order to avoid confusing boot-time code with CPUs
+                 coming and going. This parameter is only useful if
+                 CONFIG_HOTPLUG_CPU is enabled.
+
+stat_interval
+                 Number of seconds between statistics-related printk()s.
+                 By default, locktorture will report stats every 60 seconds.
+                 Setting the interval to zero causes the statistics to
+                 be printed -only- when the module is unloaded, and this
+                 is the default.
+
+stutter
+                 The length of time to run the test before pausing for this
+                 same period of time.  Defaults to "stutter=5", so as
+                 to run and pause for (roughly) five-second intervals.
+                 Specifying "stutter=0" causes the test to run continuously
+                 without pausing, which is the old default behavior.
+
+shuffle_interval
+                 The number of seconds to keep the test threads affinitied
+                 to a particular subset of the CPUs, defaults to 3 seconds.
+                 Used in conjunction with test_no_idle_hz.
+
+verbose
+                 Enable verbose debugging printing, via printk(). Enabled
+                 by default. This extra information is mostly related to
+                 high-level errors and reports from the main 'torture'
+                 framework.
+
+
+Statistics
+==========
+
+Statistics are printed in the following format::
+
+  spin_lock-torture: Writes:  Total: 93746064  Max/Min: 0/0   Fail: 0
+     (A)                   (B)            (C)            (D)          (E)
+
+  (A): Lock type that is being tortured -- torture_type parameter.
+
+  (B): Number of writer lock acquisitions. If dealing with a read/write
+       primitive a second "Reads" statistics line is printed.
+
+  (C): Number of times the lock was acquired.
+
+  (D): Min and max number of times threads failed to acquire the lock.
+
+  (E): true/false values if there were errors acquiring the lock. This should
+       -only- be positive if there is a bug in the locking primitive's
+       implementation. Otherwise a lock should never fail (i.e., spin_lock()).
+       Of course, the same applies for (C), above. A dummy example of this is
+       the "lock_busted" type.
+
+Usage
+=====
+
+The following script may be used to torture locks::
+
+       #!/bin/sh
+
+       modprobe locktorture
+       sleep 3600
+       rmmod locktorture
+       dmesg | grep torture:
+
+The output can be manually inspected for the error flag of "!!!".
+One could of course create a more elaborate script that automatically
+checked for such errors.  The "rmmod" command forces a "SUCCESS",
+"FAILURE", or "RCU_HOTPLUG" indication to be printk()ed.  The first
+two are self-explanatory, while the last indicates that while there
+were no locking failures, CPU-hotplug problems were detected.
+
+Also see: Documentation/RCU/torture.txt
diff --git a/Documentation/locking/locktorture.txt b/Documentation/locking/locktorture.txt
deleted file mode 100644 (file)
index 6a8df4c..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-Kernel Lock Torture Test Operation
-
-CONFIG_LOCK_TORTURE_TEST
-
-The CONFIG LOCK_TORTURE_TEST config option provides a kernel module
-that runs torture tests on core kernel locking primitives. The kernel
-module, 'locktorture', may be built after the fact on the running
-kernel to be tested, if desired. The tests periodically output status
-messages via printk(), which can be examined via the dmesg (perhaps
-grepping for "torture").  The test is started when the module is loaded,
-and stops when the module is unloaded. This program is based on how RCU
-is tortured, via rcutorture.
-
-This torture test consists of creating a number of kernel threads which
-acquire the lock and hold it for specific amount of time, thus simulating
-different critical region behaviors. The amount of contention on the lock
-can be simulated by either enlarging this critical region hold time and/or
-creating more kthreads.
-
-
-MODULE PARAMETERS
-
-This module has the following parameters:
-
-
-           ** Locktorture-specific **
-
-nwriters_stress   Number of kernel threads that will stress exclusive lock
-                 ownership (writers). The default value is twice the number
-                 of online CPUs.
-
-nreaders_stress   Number of kernel threads that will stress shared lock
-                 ownership (readers). The default is the same amount of writer
-                 locks. If the user did not specify nwriters_stress, then
-                 both readers and writers be the amount of online CPUs.
-
-torture_type     Type of lock to torture. By default, only spinlocks will
-                 be tortured. This module can torture the following locks,
-                 with string values as follows:
-
-                    o "lock_busted": Simulates a buggy lock implementation.
-
-                    o "spin_lock": spin_lock() and spin_unlock() pairs.
-
-                    o "spin_lock_irq": spin_lock_irq() and spin_unlock_irq()
-                                       pairs.
-
-                    o "rw_lock": read/write lock() and unlock() rwlock pairs.
-
-                    o "rw_lock_irq": read/write lock_irq() and unlock_irq()
-                                     rwlock pairs.
-
-                    o "mutex_lock": mutex_lock() and mutex_unlock() pairs.
-
-                    o "rtmutex_lock": rtmutex_lock() and rtmutex_unlock()
-                                      pairs. Kernel must have CONFIG_RT_MUTEX=y.
-
-                    o "rwsem_lock": read/write down() and up() semaphore pairs.
-
-
-           ** Torture-framework (RCU + locking) **
-
-shutdown_secs    The number of seconds to run the test before terminating
-                 the test and powering off the system.  The default is
-                 zero, which disables test termination and system shutdown.
-                 This capability is useful for automated testing.
-
-onoff_interval   The number of seconds between each attempt to execute a
-                 randomly selected CPU-hotplug operation.  Defaults
-                 to zero, which disables CPU hotplugging.  In
-                 CONFIG_HOTPLUG_CPU=n kernels, locktorture will silently
-                 refuse to do any CPU-hotplug operations regardless of
-                 what value is specified for onoff_interval.
-
-onoff_holdoff    The number of seconds to wait until starting CPU-hotplug
-                 operations.  This would normally only be used when
-                 locktorture was built into the kernel and started
-                 automatically at boot time, in which case it is useful
-                 in order to avoid confusing boot-time code with CPUs
-                 coming and going. This parameter is only useful if
-                 CONFIG_HOTPLUG_CPU is enabled.
-
-stat_interval    Number of seconds between statistics-related printk()s.
-                 By default, locktorture will report stats every 60 seconds.
-                 Setting the interval to zero causes the statistics to
-                 be printed -only- when the module is unloaded, and this
-                 is the default.
-
-stutter                  The length of time to run the test before pausing for this
-                 same period of time.  Defaults to "stutter=5", so as
-                 to run and pause for (roughly) five-second intervals.
-                 Specifying "stutter=0" causes the test to run continuously
-                 without pausing, which is the old default behavior.
-
-shuffle_interval  The number of seconds to keep the test threads affinitied
-                 to a particular subset of the CPUs, defaults to 3 seconds.
-                 Used in conjunction with test_no_idle_hz.
-
-verbose                  Enable verbose debugging printing, via printk(). Enabled
-                 by default. This extra information is mostly related to
-                 high-level errors and reports from the main 'torture'
-                 framework.
-
-
-STATISTICS
-
-Statistics are printed in the following format:
-
-spin_lock-torture: Writes:  Total: 93746064  Max/Min: 0/0   Fail: 0
-   (A)             (B)            (C)            (D)          (E)
-
-(A): Lock type that is being tortured -- torture_type parameter.
-
-(B): Number of writer lock acquisitions. If dealing with a read/write primitive
-     a second "Reads" statistics line is printed.
-
-(C): Number of times the lock was acquired.
-
-(D): Min and max number of times threads failed to acquire the lock.
-
-(E): true/false values if there were errors acquiring the lock. This should
-     -only- be positive if there is a bug in the locking primitive's
-     implementation. Otherwise a lock should never fail (i.e., spin_lock()).
-     Of course, the same applies for (C), above. A dummy example of this is
-     the "lock_busted" type.
-
-USAGE
-
-The following script may be used to torture locks:
-
-       #!/bin/sh
-
-       modprobe locktorture
-       sleep 3600
-       rmmod locktorture
-       dmesg | grep torture:
-
-The output can be manually inspected for the error flag of "!!!".
-One could of course create a more elaborate script that automatically
-checked for such errors.  The "rmmod" command forces a "SUCCESS",
-"FAILURE", or "RCU_HOTPLUG" indication to be printk()ed.  The first
-two are self-explanatory, while the last indicates that while there
-were no locking failures, CPU-hotplug problems were detected.
-
-Also see: Documentation/RCU/torture.txt
diff --git a/Documentation/locking/mutex-design.rst b/Documentation/locking/mutex-design.rst
new file mode 100644 (file)
index 0000000..4d8236b
--- /dev/null
@@ -0,0 +1,152 @@
+=======================
+Generic Mutex Subsystem
+=======================
+
+started by Ingo Molnar <mingo@redhat.com>
+
+updated by Davidlohr Bueso <davidlohr@hp.com>
+
+What are mutexes?
+-----------------
+
+In the Linux kernel, mutexes refer to a particular locking primitive
+that enforces serialization on shared memory systems, and not only to
+the generic term referring to 'mutual exclusion' found in academia
+or similar theoretical text books. Mutexes are sleeping locks which
+behave similarly to binary semaphores, and were introduced in 2006[1]
+as an alternative to these. This new data structure provided a number
+of advantages, including simpler interfaces, and at that time smaller
+code (see Disadvantages).
+
+[1] http://lwn.net/Articles/164802/
+
+Implementation
+--------------
+
+Mutexes are represented by 'struct mutex', defined in include/linux/mutex.h
+and implemented in kernel/locking/mutex.c. These locks use an atomic variable
+(->owner) to keep track of the lock state during its lifetime.  Field owner
+actually contains `struct task_struct *` to the current lock owner and it is
+therefore NULL if not currently owned. Since task_struct pointers are aligned
+at at least L1_CACHE_BYTES, low bits (3) are used to store extra state (e.g.,
+if waiter list is non-empty).  In its most basic form it also includes a
+wait-queue and a spinlock that serializes access to it. Furthermore,
+CONFIG_MUTEX_SPIN_ON_OWNER=y systems use a spinner MCS lock (->osq), described
+below in (ii).
+
+When acquiring a mutex, there are three possible paths that can be
+taken, depending on the state of the lock:
+
+(i) fastpath: tries to atomically acquire the lock by cmpxchg()ing the owner with
+    the current task. This only works in the uncontended case (cmpxchg() checks
+    against 0UL, so all 3 state bits above have to be 0). If the lock is
+    contended it goes to the next possible path.
+
+(ii) midpath: aka optimistic spinning, tries to spin for acquisition
+     while the lock owner is running and there are no other tasks ready
+     to run that have higher priority (need_resched). The rationale is
+     that if the lock owner is running, it is likely to release the lock
+     soon. The mutex spinners are queued up using MCS lock so that only
+     one spinner can compete for the mutex.
+
+     The MCS lock (proposed by Mellor-Crummey and Scott) is a simple spinlock
+     with the desirable properties of being fair and with each cpu trying
+     to acquire the lock spinning on a local variable. It avoids expensive
+     cacheline bouncing that common test-and-set spinlock implementations
+     incur. An MCS-like lock is specially tailored for optimistic spinning
+     for sleeping lock implementation. An important feature of the customized
+     MCS lock is that it has the extra property that spinners are able to exit
+     the MCS spinlock queue when they need to reschedule. This further helps
+     avoid situations where MCS spinners that need to reschedule would continue
+     waiting to spin on mutex owner, only to go directly to slowpath upon
+     obtaining the MCS lock.
+
+
+(iii) slowpath: last resort, if the lock is still unable to be acquired,
+      the task is added to the wait-queue and sleeps until woken up by the
+      unlock path. Under normal circumstances it blocks as TASK_UNINTERRUPTIBLE.
+
+While formally kernel mutexes are sleepable locks, it is path (ii) that
+makes them more practically a hybrid type. By simply not interrupting a
+task and busy-waiting for a few cycles instead of immediately sleeping,
+the performance of this lock has been seen to significantly improve a
+number of workloads. Note that this technique is also used for rw-semaphores.
+
+Semantics
+---------
+
+The mutex subsystem checks and enforces the following rules:
+
+    - Only one task can hold the mutex at a time.
+    - Only the owner can unlock the mutex.
+    - Multiple unlocks are not permitted.
+    - Recursive locking/unlocking is not permitted.
+    - A mutex must only be initialized via the API (see below).
+    - A task may not exit with a mutex held.
+    - Memory areas where held locks reside must not be freed.
+    - Held mutexes must not be reinitialized.
+    - Mutexes may not be used in hardware or software interrupt
+      contexts such as tasklets and timers.
+
+These semantics are fully enforced when CONFIG DEBUG_MUTEXES is enabled.
+In addition, the mutex debugging code also implements a number of other
+features that make lock debugging easier and faster:
+
+    - Uses symbolic names of mutexes, whenever they are printed
+      in debug output.
+    - Point-of-acquire tracking, symbolic lookup of function names,
+      list of all locks held in the system, printout of them.
+    - Owner tracking.
+    - Detects self-recursing locks and prints out all relevant info.
+    - Detects multi-task circular deadlocks and prints out all affected
+      locks and tasks (and only those tasks).
+
+
+Interfaces
+----------
+Statically define the mutex::
+
+   DEFINE_MUTEX(name);
+
+Dynamically initialize the mutex::
+
+   mutex_init(mutex);
+
+Acquire the mutex, uninterruptible::
+
+   void mutex_lock(struct mutex *lock);
+   void mutex_lock_nested(struct mutex *lock, unsigned int subclass);
+   int  mutex_trylock(struct mutex *lock);
+
+Acquire the mutex, interruptible::
+
+   int mutex_lock_interruptible_nested(struct mutex *lock,
+                                      unsigned int subclass);
+   int mutex_lock_interruptible(struct mutex *lock);
+
+Acquire the mutex, interruptible, if dec to 0::
+
+   int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock);
+
+Unlock the mutex::
+
+   void mutex_unlock(struct mutex *lock);
+
+Test if the mutex is taken::
+
+   int mutex_is_locked(struct mutex *lock);
+
+Disadvantages
+-------------
+
+Unlike its original design and purpose, 'struct mutex' is among the largest
+locks in the kernel. E.g: on x86-64 it is 32 bytes, where 'struct semaphore'
+is 24 bytes and rw_semaphore is 40 bytes. Larger structure sizes mean more CPU
+cache and memory footprint.
+
+When to use mutexes
+-------------------
+
+Unless the strict semantics of mutexes are unsuitable and/or the critical
+region prevents the lock from being shared, always prefer them to any other
+locking primitive.
diff --git a/Documentation/locking/mutex-design.txt b/Documentation/locking/mutex-design.txt
deleted file mode 100644 (file)
index 818aca1..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-Generic Mutex Subsystem
-
-started by Ingo Molnar <mingo@redhat.com>
-updated by Davidlohr Bueso <davidlohr@hp.com>
-
-What are mutexes?
------------------
-
-In the Linux kernel, mutexes refer to a particular locking primitive
-that enforces serialization on shared memory systems, and not only to
-the generic term referring to 'mutual exclusion' found in academia
-or similar theoretical text books. Mutexes are sleeping locks which
-behave similarly to binary semaphores, and were introduced in 2006[1]
-as an alternative to these. This new data structure provided a number
-of advantages, including simpler interfaces, and at that time smaller
-code (see Disadvantages).
-
-[1] http://lwn.net/Articles/164802/
-
-Implementation
---------------
-
-Mutexes are represented by 'struct mutex', defined in include/linux/mutex.h
-and implemented in kernel/locking/mutex.c. These locks use an atomic variable
-(->owner) to keep track of the lock state during its lifetime.  Field owner
-actually contains 'struct task_struct *' to the current lock owner and it is
-therefore NULL if not currently owned. Since task_struct pointers are aligned
-at at least L1_CACHE_BYTES, low bits (3) are used to store extra state (e.g.,
-if waiter list is non-empty).  In its most basic form it also includes a
-wait-queue and a spinlock that serializes access to it. Furthermore,
-CONFIG_MUTEX_SPIN_ON_OWNER=y systems use a spinner MCS lock (->osq), described
-below in (ii).
-
-When acquiring a mutex, there are three possible paths that can be
-taken, depending on the state of the lock:
-
-(i) fastpath: tries to atomically acquire the lock by cmpxchg()ing the owner with
-    the current task. This only works in the uncontended case (cmpxchg() checks
-    against 0UL, so all 3 state bits above have to be 0). If the lock is
-    contended it goes to the next possible path.
-
-(ii) midpath: aka optimistic spinning, tries to spin for acquisition
-     while the lock owner is running and there are no other tasks ready
-     to run that have higher priority (need_resched). The rationale is
-     that if the lock owner is running, it is likely to release the lock
-     soon. The mutex spinners are queued up using MCS lock so that only
-     one spinner can compete for the mutex.
-
-     The MCS lock (proposed by Mellor-Crummey and Scott) is a simple spinlock
-     with the desirable properties of being fair and with each cpu trying
-     to acquire the lock spinning on a local variable. It avoids expensive
-     cacheline bouncing that common test-and-set spinlock implementations
-     incur. An MCS-like lock is specially tailored for optimistic spinning
-     for sleeping lock implementation. An important feature of the customized
-     MCS lock is that it has the extra property that spinners are able to exit
-     the MCS spinlock queue when they need to reschedule. This further helps
-     avoid situations where MCS spinners that need to reschedule would continue
-     waiting to spin on mutex owner, only to go directly to slowpath upon
-     obtaining the MCS lock.
-
-
-(iii) slowpath: last resort, if the lock is still unable to be acquired,
-      the task is added to the wait-queue and sleeps until woken up by the
-      unlock path. Under normal circumstances it blocks as TASK_UNINTERRUPTIBLE.
-
-While formally kernel mutexes are sleepable locks, it is path (ii) that
-makes them more practically a hybrid type. By simply not interrupting a
-task and busy-waiting for a few cycles instead of immediately sleeping,
-the performance of this lock has been seen to significantly improve a
-number of workloads. Note that this technique is also used for rw-semaphores.
-
-Semantics
----------
-
-The mutex subsystem checks and enforces the following rules:
-
-    - Only one task can hold the mutex at a time.
-    - Only the owner can unlock the mutex.
-    - Multiple unlocks are not permitted.
-    - Recursive locking/unlocking is not permitted.
-    - A mutex must only be initialized via the API (see below).
-    - A task may not exit with a mutex held.
-    - Memory areas where held locks reside must not be freed.
-    - Held mutexes must not be reinitialized.
-    - Mutexes may not be used in hardware or software interrupt
-      contexts such as tasklets and timers.
-
-These semantics are fully enforced when CONFIG DEBUG_MUTEXES is enabled.
-In addition, the mutex debugging code also implements a number of other
-features that make lock debugging easier and faster:
-
-    - Uses symbolic names of mutexes, whenever they are printed
-      in debug output.
-    - Point-of-acquire tracking, symbolic lookup of function names,
-      list of all locks held in the system, printout of them.
-    - Owner tracking.
-    - Detects self-recursing locks and prints out all relevant info.
-    - Detects multi-task circular deadlocks and prints out all affected
-      locks and tasks (and only those tasks).
-
-
-Interfaces
-----------
-Statically define the mutex:
-   DEFINE_MUTEX(name);
-
-Dynamically initialize the mutex:
-   mutex_init(mutex);
-
-Acquire the mutex, uninterruptible:
-   void mutex_lock(struct mutex *lock);
-   void mutex_lock_nested(struct mutex *lock, unsigned int subclass);
-   int  mutex_trylock(struct mutex *lock);
-
-Acquire the mutex, interruptible:
-   int mutex_lock_interruptible_nested(struct mutex *lock,
-                                      unsigned int subclass);
-   int mutex_lock_interruptible(struct mutex *lock);
-
-Acquire the mutex, interruptible, if dec to 0:
-   int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock);
-
-Unlock the mutex:
-   void mutex_unlock(struct mutex *lock);
-
-Test if the mutex is taken:
-   int mutex_is_locked(struct mutex *lock);
-
-Disadvantages
--------------
-
-Unlike its original design and purpose, 'struct mutex' is among the largest
-locks in the kernel. E.g: on x86-64 it is 32 bytes, where 'struct semaphore'
-is 24 bytes and rw_semaphore is 40 bytes. Larger structure sizes mean more CPU
-cache and memory footprint.
-
-When to use mutexes
--------------------
-
-Unless the strict semantics of mutexes are unsuitable and/or the critical
-region prevents the lock from being shared, always prefer them to any other
-locking primitive.
diff --git a/Documentation/locking/rt-mutex-design.rst b/Documentation/locking/rt-mutex-design.rst
new file mode 100644 (file)
index 0000000..59c2a64
--- /dev/null
@@ -0,0 +1,574 @@
+==============================
+RT-mutex implementation design
+==============================
+
+Copyright (c) 2006 Steven Rostedt
+
+Licensed under the GNU Free Documentation License, Version 1.2
+
+
+This document tries to describe the design of the rtmutex.c implementation.
+It doesn't describe the reasons why rtmutex.c exists. For that please see
+Documentation/locking/rt-mutex.rst.  Although this document does explain problems
+that happen without this code, but that is in the concept to understand
+what the code actually is doing.
+
+The goal of this document is to help others understand the priority
+inheritance (PI) algorithm that is used, as well as reasons for the
+decisions that were made to implement PI in the manner that was done.
+
+
+Unbounded Priority Inversion
+----------------------------
+
+Priority inversion is when a lower priority process executes while a higher
+priority process wants to run.  This happens for several reasons, and
+most of the time it can't be helped.  Anytime a high priority process wants
+to use a resource that a lower priority process has (a mutex for example),
+the high priority process must wait until the lower priority process is done
+with the resource.  This is a priority inversion.  What we want to prevent
+is something called unbounded priority inversion.  That is when the high
+priority process is prevented from running by a lower priority process for
+an undetermined amount of time.
+
+The classic example of unbounded priority inversion is where you have three
+processes, let's call them processes A, B, and C, where A is the highest
+priority process, C is the lowest, and B is in between. A tries to grab a lock
+that C owns and must wait and lets C run to release the lock. But in the
+meantime, B executes, and since B is of a higher priority than C, it preempts C,
+but by doing so, it is in fact preempting A which is a higher priority process.
+Now there's no way of knowing how long A will be sleeping waiting for C
+to release the lock, because for all we know, B is a CPU hog and will
+never give C a chance to release the lock.  This is called unbounded priority
+inversion.
+
+Here's a little ASCII art to show the problem::
+
+     grab lock L1 (owned by C)
+       |
+  A ---+
+          C preempted by B
+            |
+  C    +----+
+
+  B         +-------->
+                  B now keeps A from running.
+
+
+Priority Inheritance (PI)
+-------------------------
+
+There are several ways to solve this issue, but other ways are out of scope
+for this document.  Here we only discuss PI.
+
+PI is where a process inherits the priority of another process if the other
+process blocks on a lock owned by the current process.  To make this easier
+to understand, let's use the previous example, with processes A, B, and C again.
+
+This time, when A blocks on the lock owned by C, C would inherit the priority
+of A.  So now if B becomes runnable, it would not preempt C, since C now has
+the high priority of A.  As soon as C releases the lock, it loses its
+inherited priority, and A then can continue with the resource that C had.
+
+Terminology
+-----------
+
+Here I explain some terminology that is used in this document to help describe
+the design that is used to implement PI.
+
+PI chain
+         - The PI chain is an ordered series of locks and processes that cause
+           processes to inherit priorities from a previous process that is
+           blocked on one of its locks.  This is described in more detail
+           later in this document.
+
+mutex
+         - In this document, to differentiate from locks that implement
+           PI and spin locks that are used in the PI code, from now on
+           the PI locks will be called a mutex.
+
+lock
+         - In this document from now on, I will use the term lock when
+           referring to spin locks that are used to protect parts of the PI
+           algorithm.  These locks disable preemption for UP (when
+           CONFIG_PREEMPT is enabled) and on SMP prevents multiple CPUs from
+           entering critical sections simultaneously.
+
+spin lock
+         - Same as lock above.
+
+waiter
+         - A waiter is a struct that is stored on the stack of a blocked
+           process.  Since the scope of the waiter is within the code for
+           a process being blocked on the mutex, it is fine to allocate
+           the waiter on the process's stack (local variable).  This
+           structure holds a pointer to the task, as well as the mutex that
+           the task is blocked on.  It also has rbtree node structures to
+           place the task in the waiters rbtree of a mutex as well as the
+           pi_waiters rbtree of a mutex owner task (described below).
+
+           waiter is sometimes used in reference to the task that is waiting
+           on a mutex. This is the same as waiter->task.
+
+waiters
+         - A list of processes that are blocked on a mutex.
+
+top waiter
+         - The highest priority process waiting on a specific mutex.
+
+top pi waiter
+              - The highest priority process waiting on one of the mutexes
+                that a specific process owns.
+
+Note:
+       task and process are used interchangeably in this document, mostly to
+       differentiate between two processes that are being described together.
+
+
+PI chain
+--------
+
+The PI chain is a list of processes and mutexes that may cause priority
+inheritance to take place.  Multiple chains may converge, but a chain
+would never diverge, since a process can't be blocked on more than one
+mutex at a time.
+
+Example::
+
+   Process:  A, B, C, D, E
+   Mutexes:  L1, L2, L3, L4
+
+   A owns: L1
+           B blocked on L1
+           B owns L2
+                  C blocked on L2
+                  C owns L3
+                         D blocked on L3
+                         D owns L4
+                                E blocked on L4
+
+The chain would be::
+
+   E->L4->D->L3->C->L2->B->L1->A
+
+To show where two chains merge, we could add another process F and
+another mutex L5 where B owns L5 and F is blocked on mutex L5.
+
+The chain for F would be::
+
+   F->L5->B->L1->A
+
+Since a process may own more than one mutex, but never be blocked on more than
+one, the chains merge.
+
+Here we show both chains::
+
+   E->L4->D->L3->C->L2-+
+                       |
+                       +->B->L1->A
+                       |
+                 F->L5-+
+
+For PI to work, the processes at the right end of these chains (or we may
+also call it the Top of the chain) must be equal to or higher in priority
+than the processes to the left or below in the chain.
+
+Also since a mutex may have more than one process blocked on it, we can
+have multiple chains merge at mutexes.  If we add another process G that is
+blocked on mutex L2::
+
+  G->L2->B->L1->A
+
+And once again, to show how this can grow I will show the merging chains
+again::
+
+   E->L4->D->L3->C-+
+                   +->L2-+
+                   |     |
+                 G-+     +->B->L1->A
+                         |
+                   F->L5-+
+
+If process G has the highest priority in the chain, then all the tasks up
+the chain (A and B in this example), must have their priorities increased
+to that of G.
+
+Mutex Waiters Tree
+------------------
+
+Every mutex keeps track of all the waiters that are blocked on itself. The
+mutex has a rbtree to store these waiters by priority.  This tree is protected
+by a spin lock that is located in the struct of the mutex. This lock is called
+wait_lock.
+
+
+Task PI Tree
+------------
+
+To keep track of the PI chains, each process has its own PI rbtree.  This is
+a tree of all top waiters of the mutexes that are owned by the process.
+Note that this tree only holds the top waiters and not all waiters that are
+blocked on mutexes owned by the process.
+
+The top of the task's PI tree is always the highest priority task that
+is waiting on a mutex that is owned by the task.  So if the task has
+inherited a priority, it will always be the priority of the task that is
+at the top of this tree.
+
+This tree is stored in the task structure of a process as a rbtree called
+pi_waiters.  It is protected by a spin lock also in the task structure,
+called pi_lock.  This lock may also be taken in interrupt context, so when
+locking the pi_lock, interrupts must be disabled.
+
+
+Depth of the PI Chain
+---------------------
+
+The maximum depth of the PI chain is not dynamic, and could actually be
+defined.  But is very complex to figure it out, since it depends on all
+the nesting of mutexes.  Let's look at the example where we have 3 mutexes,
+L1, L2, and L3, and four separate functions func1, func2, func3 and func4.
+The following shows a locking order of L1->L2->L3, but may not actually
+be directly nested that way::
+
+  void func1(void)
+  {
+       mutex_lock(L1);
+
+       /* do anything */
+
+       mutex_unlock(L1);
+  }
+
+  void func2(void)
+  {
+       mutex_lock(L1);
+       mutex_lock(L2);
+
+       /* do something */
+
+       mutex_unlock(L2);
+       mutex_unlock(L1);
+  }
+
+  void func3(void)
+  {
+       mutex_lock(L2);
+       mutex_lock(L3);
+
+       /* do something else */
+
+       mutex_unlock(L3);
+       mutex_unlock(L2);
+  }
+
+  void func4(void)
+  {
+       mutex_lock(L3);
+
+       /* do something again */
+
+       mutex_unlock(L3);
+  }
+
+Now we add 4 processes that run each of these functions separately.
+Processes A, B, C, and D which run functions func1, func2, func3 and func4
+respectively, and such that D runs first and A last.  With D being preempted
+in func4 in the "do something again" area, we have a locking that follows::
+
+  D owns L3
+         C blocked on L3
+         C owns L2
+                B blocked on L2
+                B owns L1
+                       A blocked on L1
+
+  And thus we have the chain A->L1->B->L2->C->L3->D.
+
+This gives us a PI depth of 4 (four processes), but looking at any of the
+functions individually, it seems as though they only have at most a locking
+depth of two.  So, although the locking depth is defined at compile time,
+it still is very difficult to find the possibilities of that depth.
+
+Now since mutexes can be defined by user-land applications, we don't want a DOS
+type of application that nests large amounts of mutexes to create a large
+PI chain, and have the code holding spin locks while looking at a large
+amount of data.  So to prevent this, the implementation not only implements
+a maximum lock depth, but also only holds at most two different locks at a
+time, as it walks the PI chain.  More about this below.
+
+
+Mutex owner and flags
+---------------------
+
+The mutex structure contains a pointer to the owner of the mutex.  If the
+mutex is not owned, this owner is set to NULL.  Since all architectures
+have the task structure on at least a two byte alignment (and if this is
+not true, the rtmutex.c code will be broken!), this allows for the least
+significant bit to be used as a flag.  Bit 0 is used as the "Has Waiters"
+flag. It's set whenever there are waiters on a mutex.
+
+See Documentation/locking/rt-mutex.rst for further details.
+
+cmpxchg Tricks
+--------------
+
+Some architectures implement an atomic cmpxchg (Compare and Exchange).  This
+is used (when applicable) to keep the fast path of grabbing and releasing
+mutexes short.
+
+cmpxchg is basically the following function performed atomically::
+
+  unsigned long _cmpxchg(unsigned long *A, unsigned long *B, unsigned long *C)
+  {
+       unsigned long T = *A;
+       if (*A == *B) {
+               *A = *C;
+       }
+       return T;
+  }
+  #define cmpxchg(a,b,c) _cmpxchg(&a,&b,&c)
+
+This is really nice to have, since it allows you to only update a variable
+if the variable is what you expect it to be.  You know if it succeeded if
+the return value (the old value of A) is equal to B.
+
+The macro rt_mutex_cmpxchg is used to try to lock and unlock mutexes. If
+the architecture does not support CMPXCHG, then this macro is simply set
+to fail every time.  But if CMPXCHG is supported, then this will
+help out extremely to keep the fast path short.
+
+The use of rt_mutex_cmpxchg with the flags in the owner field help optimize
+the system for architectures that support it.  This will also be explained
+later in this document.
+
+
+Priority adjustments
+--------------------
+
+The implementation of the PI code in rtmutex.c has several places that a
+process must adjust its priority.  With the help of the pi_waiters of a
+process this is rather easy to know what needs to be adjusted.
+
+The functions implementing the task adjustments are rt_mutex_adjust_prio
+and rt_mutex_setprio. rt_mutex_setprio is only used in rt_mutex_adjust_prio.
+
+rt_mutex_adjust_prio examines the priority of the task, and the highest
+priority process that is waiting any of mutexes owned by the task. Since
+the pi_waiters of a task holds an order by priority of all the top waiters
+of all the mutexes that the task owns, we simply need to compare the top
+pi waiter to its own normal/deadline priority and take the higher one.
+Then rt_mutex_setprio is called to adjust the priority of the task to the
+new priority. Note that rt_mutex_setprio is defined in kernel/sched/core.c
+to implement the actual change in priority.
+
+Note:
+       For the "prio" field in task_struct, the lower the number, the
+       higher the priority. A "prio" of 5 is of higher priority than a
+       "prio" of 10.
+
+It is interesting to note that rt_mutex_adjust_prio can either increase
+or decrease the priority of the task.  In the case that a higher priority
+process has just blocked on a mutex owned by the task, rt_mutex_adjust_prio
+would increase/boost the task's priority.  But if a higher priority task
+were for some reason to leave the mutex (timeout or signal), this same function
+would decrease/unboost the priority of the task.  That is because the pi_waiters
+always contains the highest priority task that is waiting on a mutex owned
+by the task, so we only need to compare the priority of that top pi waiter
+to the normal priority of the given task.
+
+
+High level overview of the PI chain walk
+----------------------------------------
+
+The PI chain walk is implemented by the function rt_mutex_adjust_prio_chain.
+
+The implementation has gone through several iterations, and has ended up
+with what we believe is the best.  It walks the PI chain by only grabbing
+at most two locks at a time, and is very efficient.
+
+The rt_mutex_adjust_prio_chain can be used either to boost or lower process
+priorities.
+
+rt_mutex_adjust_prio_chain is called with a task to be checked for PI
+(de)boosting (the owner of a mutex that a process is blocking on), a flag to
+check for deadlocking, the mutex that the task owns, a pointer to a waiter
+that is the process's waiter struct that is blocked on the mutex (although this
+parameter may be NULL for deboosting), a pointer to the mutex on which the task
+is blocked, and a top_task as the top waiter of the mutex.
+
+For this explanation, I will not mention deadlock detection. This explanation
+will try to stay at a high level.
+
+When this function is called, there are no locks held.  That also means
+that the state of the owner and lock can change when entered into this function.
+
+Before this function is called, the task has already had rt_mutex_adjust_prio
+performed on it.  This means that the task is set to the priority that it
+should be at, but the rbtree nodes of the task's waiter have not been updated
+with the new priorities, and this task may not be in the proper locations
+in the pi_waiters and waiters trees that the task is blocked on. This function
+solves all that.
+
+The main operation of this function is summarized by Thomas Gleixner in
+rtmutex.c. See the 'Chain walk basics and protection scope' comment for further
+details.
+
+Taking of a mutex (The walk through)
+------------------------------------
+
+OK, now let's take a look at the detailed walk through of what happens when
+taking a mutex.
+
+The first thing that is tried is the fast taking of the mutex.  This is
+done when we have CMPXCHG enabled (otherwise the fast taking automatically
+fails).  Only when the owner field of the mutex is NULL can the lock be
+taken with the CMPXCHG and nothing else needs to be done.
+
+If there is contention on the lock, we go about the slow path
+(rt_mutex_slowlock).
+
+The slow path function is where the task's waiter structure is created on
+the stack.  This is because the waiter structure is only needed for the
+scope of this function.  The waiter structure holds the nodes to store
+the task on the waiters tree of the mutex, and if need be, the pi_waiters
+tree of the owner.
+
+The wait_lock of the mutex is taken since the slow path of unlocking the
+mutex also takes this lock.
+
+We then call try_to_take_rt_mutex.  This is where the architecture that
+does not implement CMPXCHG would always grab the lock (if there's no
+contention).
+
+try_to_take_rt_mutex is used every time the task tries to grab a mutex in the
+slow path.  The first thing that is done here is an atomic setting of
+the "Has Waiters" flag of the mutex's owner field. By setting this flag
+now, the current owner of the mutex being contended for can't release the mutex
+without going into the slow unlock path, and it would then need to grab the
+wait_lock, which this code currently holds. So setting the "Has Waiters" flag
+forces the current owner to synchronize with this code.
+
+The lock is taken if the following are true:
+
+   1) The lock has no owner
+   2) The current task is the highest priority against all other
+      waiters of the lock
+
+If the task succeeds to acquire the lock, then the task is set as the
+owner of the lock, and if the lock still has waiters, the top_waiter
+(highest priority task waiting on the lock) is added to this task's
+pi_waiters tree.
+
+If the lock is not taken by try_to_take_rt_mutex(), then the
+task_blocks_on_rt_mutex() function is called. This will add the task to
+the lock's waiter tree and propagate the pi chain of the lock as well
+as the lock's owner's pi_waiters tree. This is described in the next
+section.
+
+Task blocks on mutex
+--------------------
+
+The accounting of a mutex and process is done with the waiter structure of
+the process.  The "task" field is set to the process, and the "lock" field
+to the mutex.  The rbtree node of waiter are initialized to the processes
+current priority.
+
+Since the wait_lock was taken at the entry of the slow lock, we can safely
+add the waiter to the task waiter tree.  If the current process is the
+highest priority process currently waiting on this mutex, then we remove the
+previous top waiter process (if it exists) from the pi_waiters of the owner,
+and add the current process to that tree.  Since the pi_waiter of the owner
+has changed, we call rt_mutex_adjust_prio on the owner to see if the owner
+should adjust its priority accordingly.
+
+If the owner is also blocked on a lock, and had its pi_waiters changed
+(or deadlock checking is on), we unlock the wait_lock of the mutex and go ahead
+and run rt_mutex_adjust_prio_chain on the owner, as described earlier.
+
+Now all locks are released, and if the current process is still blocked on a
+mutex (waiter "task" field is not NULL), then we go to sleep (call schedule).
+
+Waking up in the loop
+---------------------
+
+The task can then wake up for a couple of reasons:
+  1) The previous lock owner released the lock, and the task now is top_waiter
+  2) we received a signal or timeout
+
+In both cases, the task will try again to acquire the lock. If it
+does, then it will take itself off the waiters tree and set itself back
+to the TASK_RUNNING state.
+
+In first case, if the lock was acquired by another task before this task
+could get the lock, then it will go back to sleep and wait to be woken again.
+
+The second case is only applicable for tasks that are grabbing a mutex
+that can wake up before getting the lock, either due to a signal or
+a timeout (i.e. rt_mutex_timed_futex_lock()). When woken, it will try to
+take the lock again, if it succeeds, then the task will return with the
+lock held, otherwise it will return with -EINTR if the task was woken
+by a signal, or -ETIMEDOUT if it timed out.
+
+
+Unlocking the Mutex
+-------------------
+
+The unlocking of a mutex also has a fast path for those architectures with
+CMPXCHG.  Since the taking of a mutex on contention always sets the
+"Has Waiters" flag of the mutex's owner, we use this to know if we need to
+take the slow path when unlocking the mutex.  If the mutex doesn't have any
+waiters, the owner field of the mutex would equal the current process and
+the mutex can be unlocked by just replacing the owner field with NULL.
+
+If the owner field has the "Has Waiters" bit set (or CMPXCHG is not available),
+the slow unlock path is taken.
+
+The first thing done in the slow unlock path is to take the wait_lock of the
+mutex.  This synchronizes the locking and unlocking of the mutex.
+
+A check is made to see if the mutex has waiters or not.  On architectures that
+do not have CMPXCHG, this is the location that the owner of the mutex will
+determine if a waiter needs to be awoken or not.  On architectures that
+do have CMPXCHG, that check is done in the fast path, but it is still needed
+in the slow path too.  If a waiter of a mutex woke up because of a signal
+or timeout between the time the owner failed the fast path CMPXCHG check and
+the grabbing of the wait_lock, the mutex may not have any waiters, thus the
+owner still needs to make this check. If there are no waiters then the mutex
+owner field is set to NULL, the wait_lock is released and nothing more is
+needed.
+
+If there are waiters, then we need to wake one up.
+
+On the wake up code, the pi_lock of the current owner is taken.  The top
+waiter of the lock is found and removed from the waiters tree of the mutex
+as well as the pi_waiters tree of the current owner. The "Has Waiters" bit is
+marked to prevent lower priority tasks from stealing the lock.
+
+Finally we unlock the pi_lock of the pending owner and wake it up.
+
+
+Contact
+-------
+
+For updates on this document, please email Steven Rostedt <rostedt@goodmis.org>
+
+
+Credits
+-------
+
+Author:  Steven Rostedt <rostedt@goodmis.org>
+
+Updated: Alex Shi <alex.shi@linaro.org>        - 7/6/2017
+
+Original Reviewers:
+                    Ingo Molnar, Thomas Gleixner, Thomas Duetsch, and
+                    Randy Dunlap
+
+Update (7/6/2017) Reviewers: Steven Rostedt and Sebastian Siewior
+
+Updates
+-------
+
+This document was originally written for 2.6.17-rc3-mm1
+was updated on 4.12
diff --git a/Documentation/locking/rt-mutex-design.txt b/Documentation/locking/rt-mutex-design.txt
deleted file mode 100644 (file)
index 3d7b865..0000000
+++ /dev/null
@@ -1,559 +0,0 @@
-#
-# Copyright (c) 2006 Steven Rostedt
-# Licensed under the GNU Free Documentation License, Version 1.2
-#
-
-RT-mutex implementation design
-------------------------------
-
-This document tries to describe the design of the rtmutex.c implementation.
-It doesn't describe the reasons why rtmutex.c exists. For that please see
-Documentation/locking/rt-mutex.txt.  Although this document does explain problems
-that happen without this code, but that is in the concept to understand
-what the code actually is doing.
-
-The goal of this document is to help others understand the priority
-inheritance (PI) algorithm that is used, as well as reasons for the
-decisions that were made to implement PI in the manner that was done.
-
-
-Unbounded Priority Inversion
-----------------------------
-
-Priority inversion is when a lower priority process executes while a higher
-priority process wants to run.  This happens for several reasons, and
-most of the time it can't be helped.  Anytime a high priority process wants
-to use a resource that a lower priority process has (a mutex for example),
-the high priority process must wait until the lower priority process is done
-with the resource.  This is a priority inversion.  What we want to prevent
-is something called unbounded priority inversion.  That is when the high
-priority process is prevented from running by a lower priority process for
-an undetermined amount of time.
-
-The classic example of unbounded priority inversion is where you have three
-processes, let's call them processes A, B, and C, where A is the highest
-priority process, C is the lowest, and B is in between. A tries to grab a lock
-that C owns and must wait and lets C run to release the lock. But in the
-meantime, B executes, and since B is of a higher priority than C, it preempts C,
-but by doing so, it is in fact preempting A which is a higher priority process.
-Now there's no way of knowing how long A will be sleeping waiting for C
-to release the lock, because for all we know, B is a CPU hog and will
-never give C a chance to release the lock.  This is called unbounded priority
-inversion.
-
-Here's a little ASCII art to show the problem.
-
-   grab lock L1 (owned by C)
-     |
-A ---+
-        C preempted by B
-          |
-C    +----+
-
-B         +-------->
-                B now keeps A from running.
-
-
-Priority Inheritance (PI)
--------------------------
-
-There are several ways to solve this issue, but other ways are out of scope
-for this document.  Here we only discuss PI.
-
-PI is where a process inherits the priority of another process if the other
-process blocks on a lock owned by the current process.  To make this easier
-to understand, let's use the previous example, with processes A, B, and C again.
-
-This time, when A blocks on the lock owned by C, C would inherit the priority
-of A.  So now if B becomes runnable, it would not preempt C, since C now has
-the high priority of A.  As soon as C releases the lock, it loses its
-inherited priority, and A then can continue with the resource that C had.
-
-Terminology
------------
-
-Here I explain some terminology that is used in this document to help describe
-the design that is used to implement PI.
-
-PI chain - The PI chain is an ordered series of locks and processes that cause
-           processes to inherit priorities from a previous process that is
-           blocked on one of its locks.  This is described in more detail
-           later in this document.
-
-mutex    - In this document, to differentiate from locks that implement
-           PI and spin locks that are used in the PI code, from now on
-           the PI locks will be called a mutex.
-
-lock     - In this document from now on, I will use the term lock when
-           referring to spin locks that are used to protect parts of the PI
-           algorithm.  These locks disable preemption for UP (when
-           CONFIG_PREEMPT is enabled) and on SMP prevents multiple CPUs from
-           entering critical sections simultaneously.
-
-spin lock - Same as lock above.
-
-waiter   - A waiter is a struct that is stored on the stack of a blocked
-           process.  Since the scope of the waiter is within the code for
-           a process being blocked on the mutex, it is fine to allocate
-           the waiter on the process's stack (local variable).  This
-           structure holds a pointer to the task, as well as the mutex that
-           the task is blocked on.  It also has rbtree node structures to
-           place the task in the waiters rbtree of a mutex as well as the
-           pi_waiters rbtree of a mutex owner task (described below).
-
-           waiter is sometimes used in reference to the task that is waiting
-           on a mutex. This is the same as waiter->task.
-
-waiters  - A list of processes that are blocked on a mutex.
-
-top waiter - The highest priority process waiting on a specific mutex.
-
-top pi waiter - The highest priority process waiting on one of the mutexes
-                that a specific process owns.
-
-Note:  task and process are used interchangeably in this document, mostly to
-       differentiate between two processes that are being described together.
-
-
-PI chain
---------
-
-The PI chain is a list of processes and mutexes that may cause priority
-inheritance to take place.  Multiple chains may converge, but a chain
-would never diverge, since a process can't be blocked on more than one
-mutex at a time.
-
-Example:
-
-   Process:  A, B, C, D, E
-   Mutexes:  L1, L2, L3, L4
-
-   A owns: L1
-           B blocked on L1
-           B owns L2
-                  C blocked on L2
-                  C owns L3
-                         D blocked on L3
-                         D owns L4
-                                E blocked on L4
-
-The chain would be:
-
-   E->L4->D->L3->C->L2->B->L1->A
-
-To show where two chains merge, we could add another process F and
-another mutex L5 where B owns L5 and F is blocked on mutex L5.
-
-The chain for F would be:
-
-   F->L5->B->L1->A
-
-Since a process may own more than one mutex, but never be blocked on more than
-one, the chains merge.
-
-Here we show both chains:
-
-   E->L4->D->L3->C->L2-+
-                       |
-                       +->B->L1->A
-                       |
-                 F->L5-+
-
-For PI to work, the processes at the right end of these chains (or we may
-also call it the Top of the chain) must be equal to or higher in priority
-than the processes to the left or below in the chain.
-
-Also since a mutex may have more than one process blocked on it, we can
-have multiple chains merge at mutexes.  If we add another process G that is
-blocked on mutex L2:
-
-  G->L2->B->L1->A
-
-And once again, to show how this can grow I will show the merging chains
-again.
-
-   E->L4->D->L3->C-+
-                   +->L2-+
-                   |     |
-                 G-+     +->B->L1->A
-                         |
-                   F->L5-+
-
-If process G has the highest priority in the chain, then all the tasks up
-the chain (A and B in this example), must have their priorities increased
-to that of G.
-
-Mutex Waiters Tree
------------------
-
-Every mutex keeps track of all the waiters that are blocked on itself. The
-mutex has a rbtree to store these waiters by priority.  This tree is protected
-by a spin lock that is located in the struct of the mutex. This lock is called
-wait_lock.
-
-
-Task PI Tree
-------------
-
-To keep track of the PI chains, each process has its own PI rbtree.  This is
-a tree of all top waiters of the mutexes that are owned by the process.
-Note that this tree only holds the top waiters and not all waiters that are
-blocked on mutexes owned by the process.
-
-The top of the task's PI tree is always the highest priority task that
-is waiting on a mutex that is owned by the task.  So if the task has
-inherited a priority, it will always be the priority of the task that is
-at the top of this tree.
-
-This tree is stored in the task structure of a process as a rbtree called
-pi_waiters.  It is protected by a spin lock also in the task structure,
-called pi_lock.  This lock may also be taken in interrupt context, so when
-locking the pi_lock, interrupts must be disabled.
-
-
-Depth of the PI Chain
----------------------
-
-The maximum depth of the PI chain is not dynamic, and could actually be
-defined.  But is very complex to figure it out, since it depends on all
-the nesting of mutexes.  Let's look at the example where we have 3 mutexes,
-L1, L2, and L3, and four separate functions func1, func2, func3 and func4.
-The following shows a locking order of L1->L2->L3, but may not actually
-be directly nested that way.
-
-void func1(void)
-{
-       mutex_lock(L1);
-
-       /* do anything */
-
-       mutex_unlock(L1);
-}
-
-void func2(void)
-{
-       mutex_lock(L1);
-       mutex_lock(L2);
-
-       /* do something */
-
-       mutex_unlock(L2);
-       mutex_unlock(L1);
-}
-
-void func3(void)
-{
-       mutex_lock(L2);
-       mutex_lock(L3);
-
-       /* do something else */
-
-       mutex_unlock(L3);
-       mutex_unlock(L2);
-}
-
-void func4(void)
-{
-       mutex_lock(L3);
-
-       /* do something again */
-
-       mutex_unlock(L3);
-}
-
-Now we add 4 processes that run each of these functions separately.
-Processes A, B, C, and D which run functions func1, func2, func3 and func4
-respectively, and such that D runs first and A last.  With D being preempted
-in func4 in the "do something again" area, we have a locking that follows:
-
-D owns L3
-       C blocked on L3
-       C owns L2
-              B blocked on L2
-              B owns L1
-                     A blocked on L1
-
-And thus we have the chain A->L1->B->L2->C->L3->D.
-
-This gives us a PI depth of 4 (four processes), but looking at any of the
-functions individually, it seems as though they only have at most a locking
-depth of two.  So, although the locking depth is defined at compile time,
-it still is very difficult to find the possibilities of that depth.
-
-Now since mutexes can be defined by user-land applications, we don't want a DOS
-type of application that nests large amounts of mutexes to create a large
-PI chain, and have the code holding spin locks while looking at a large
-amount of data.  So to prevent this, the implementation not only implements
-a maximum lock depth, but also only holds at most two different locks at a
-time, as it walks the PI chain.  More about this below.
-
-
-Mutex owner and flags
----------------------
-
-The mutex structure contains a pointer to the owner of the mutex.  If the
-mutex is not owned, this owner is set to NULL.  Since all architectures
-have the task structure on at least a two byte alignment (and if this is
-not true, the rtmutex.c code will be broken!), this allows for the least
-significant bit to be used as a flag.  Bit 0 is used as the "Has Waiters"
-flag. It's set whenever there are waiters on a mutex.
-
-See Documentation/locking/rt-mutex.txt for further details.
-
-cmpxchg Tricks
---------------
-
-Some architectures implement an atomic cmpxchg (Compare and Exchange).  This
-is used (when applicable) to keep the fast path of grabbing and releasing
-mutexes short.
-
-cmpxchg is basically the following function performed atomically:
-
-unsigned long _cmpxchg(unsigned long *A, unsigned long *B, unsigned long *C)
-{
-       unsigned long T = *A;
-       if (*A == *B) {
-               *A = *C;
-       }
-       return T;
-}
-#define cmpxchg(a,b,c) _cmpxchg(&a,&b,&c)
-
-This is really nice to have, since it allows you to only update a variable
-if the variable is what you expect it to be.  You know if it succeeded if
-the return value (the old value of A) is equal to B.
-
-The macro rt_mutex_cmpxchg is used to try to lock and unlock mutexes. If
-the architecture does not support CMPXCHG, then this macro is simply set
-to fail every time.  But if CMPXCHG is supported, then this will
-help out extremely to keep the fast path short.
-
-The use of rt_mutex_cmpxchg with the flags in the owner field help optimize
-the system for architectures that support it.  This will also be explained
-later in this document.
-
-
-Priority adjustments
---------------------
-
-The implementation of the PI code in rtmutex.c has several places that a
-process must adjust its priority.  With the help of the pi_waiters of a
-process this is rather easy to know what needs to be adjusted.
-
-The functions implementing the task adjustments are rt_mutex_adjust_prio
-and rt_mutex_setprio. rt_mutex_setprio is only used in rt_mutex_adjust_prio.
-
-rt_mutex_adjust_prio examines the priority of the task, and the highest
-priority process that is waiting any of mutexes owned by the task. Since
-the pi_waiters of a task holds an order by priority of all the top waiters
-of all the mutexes that the task owns, we simply need to compare the top
-pi waiter to its own normal/deadline priority and take the higher one.
-Then rt_mutex_setprio is called to adjust the priority of the task to the
-new priority. Note that rt_mutex_setprio is defined in kernel/sched/core.c
-to implement the actual change in priority.
-
-(Note:  For the "prio" field in task_struct, the lower the number, the
-       higher the priority. A "prio" of 5 is of higher priority than a
-       "prio" of 10.)
-
-It is interesting to note that rt_mutex_adjust_prio can either increase
-or decrease the priority of the task.  In the case that a higher priority
-process has just blocked on a mutex owned by the task, rt_mutex_adjust_prio
-would increase/boost the task's priority.  But if a higher priority task
-were for some reason to leave the mutex (timeout or signal), this same function
-would decrease/unboost the priority of the task.  That is because the pi_waiters
-always contains the highest priority task that is waiting on a mutex owned
-by the task, so we only need to compare the priority of that top pi waiter
-to the normal priority of the given task.
-
-
-High level overview of the PI chain walk
-----------------------------------------
-
-The PI chain walk is implemented by the function rt_mutex_adjust_prio_chain.
-
-The implementation has gone through several iterations, and has ended up
-with what we believe is the best.  It walks the PI chain by only grabbing
-at most two locks at a time, and is very efficient.
-
-The rt_mutex_adjust_prio_chain can be used either to boost or lower process
-priorities.
-
-rt_mutex_adjust_prio_chain is called with a task to be checked for PI
-(de)boosting (the owner of a mutex that a process is blocking on), a flag to
-check for deadlocking, the mutex that the task owns, a pointer to a waiter
-that is the process's waiter struct that is blocked on the mutex (although this
-parameter may be NULL for deboosting), a pointer to the mutex on which the task
-is blocked, and a top_task as the top waiter of the mutex.
-
-For this explanation, I will not mention deadlock detection. This explanation
-will try to stay at a high level.
-
-When this function is called, there are no locks held.  That also means
-that the state of the owner and lock can change when entered into this function.
-
-Before this function is called, the task has already had rt_mutex_adjust_prio
-performed on it.  This means that the task is set to the priority that it
-should be at, but the rbtree nodes of the task's waiter have not been updated
-with the new priorities, and this task may not be in the proper locations
-in the pi_waiters and waiters trees that the task is blocked on. This function
-solves all that.
-
-The main operation of this function is summarized by Thomas Gleixner in
-rtmutex.c. See the 'Chain walk basics and protection scope' comment for further
-details.
-
-Taking of a mutex (The walk through)
-------------------------------------
-
-OK, now let's take a look at the detailed walk through of what happens when
-taking a mutex.
-
-The first thing that is tried is the fast taking of the mutex.  This is
-done when we have CMPXCHG enabled (otherwise the fast taking automatically
-fails).  Only when the owner field of the mutex is NULL can the lock be
-taken with the CMPXCHG and nothing else needs to be done.
-
-If there is contention on the lock, we go about the slow path
-(rt_mutex_slowlock).
-
-The slow path function is where the task's waiter structure is created on
-the stack.  This is because the waiter structure is only needed for the
-scope of this function.  The waiter structure holds the nodes to store
-the task on the waiters tree of the mutex, and if need be, the pi_waiters
-tree of the owner.
-
-The wait_lock of the mutex is taken since the slow path of unlocking the
-mutex also takes this lock.
-
-We then call try_to_take_rt_mutex.  This is where the architecture that
-does not implement CMPXCHG would always grab the lock (if there's no
-contention).
-
-try_to_take_rt_mutex is used every time the task tries to grab a mutex in the
-slow path.  The first thing that is done here is an atomic setting of
-the "Has Waiters" flag of the mutex's owner field. By setting this flag
-now, the current owner of the mutex being contended for can't release the mutex
-without going into the slow unlock path, and it would then need to grab the
-wait_lock, which this code currently holds. So setting the "Has Waiters" flag
-forces the current owner to synchronize with this code.
-
-The lock is taken if the following are true:
-   1) The lock has no owner
-   2) The current task is the highest priority against all other
-      waiters of the lock
-
-If the task succeeds to acquire the lock, then the task is set as the
-owner of the lock, and if the lock still has waiters, the top_waiter
-(highest priority task waiting on the lock) is added to this task's
-pi_waiters tree.
-
-If the lock is not taken by try_to_take_rt_mutex(), then the
-task_blocks_on_rt_mutex() function is called. This will add the task to
-the lock's waiter tree and propagate the pi chain of the lock as well
-as the lock's owner's pi_waiters tree. This is described in the next
-section.
-
-Task blocks on mutex
---------------------
-
-The accounting of a mutex and process is done with the waiter structure of
-the process.  The "task" field is set to the process, and the "lock" field
-to the mutex.  The rbtree node of waiter are initialized to the processes
-current priority.
-
-Since the wait_lock was taken at the entry of the slow lock, we can safely
-add the waiter to the task waiter tree.  If the current process is the
-highest priority process currently waiting on this mutex, then we remove the
-previous top waiter process (if it exists) from the pi_waiters of the owner,
-and add the current process to that tree.  Since the pi_waiter of the owner
-has changed, we call rt_mutex_adjust_prio on the owner to see if the owner
-should adjust its priority accordingly.
-
-If the owner is also blocked on a lock, and had its pi_waiters changed
-(or deadlock checking is on), we unlock the wait_lock of the mutex and go ahead
-and run rt_mutex_adjust_prio_chain on the owner, as described earlier.
-
-Now all locks are released, and if the current process is still blocked on a
-mutex (waiter "task" field is not NULL), then we go to sleep (call schedule).
-
-Waking up in the loop
----------------------
-
-The task can then wake up for a couple of reasons:
-  1) The previous lock owner released the lock, and the task now is top_waiter
-  2) we received a signal or timeout
-
-In both cases, the task will try again to acquire the lock. If it
-does, then it will take itself off the waiters tree and set itself back
-to the TASK_RUNNING state.
-
-In first case, if the lock was acquired by another task before this task
-could get the lock, then it will go back to sleep and wait to be woken again.
-
-The second case is only applicable for tasks that are grabbing a mutex
-that can wake up before getting the lock, either due to a signal or
-a timeout (i.e. rt_mutex_timed_futex_lock()). When woken, it will try to
-take the lock again, if it succeeds, then the task will return with the
-lock held, otherwise it will return with -EINTR if the task was woken
-by a signal, or -ETIMEDOUT if it timed out.
-
-
-Unlocking the Mutex
--------------------
-
-The unlocking of a mutex also has a fast path for those architectures with
-CMPXCHG.  Since the taking of a mutex on contention always sets the
-"Has Waiters" flag of the mutex's owner, we use this to know if we need to
-take the slow path when unlocking the mutex.  If the mutex doesn't have any
-waiters, the owner field of the mutex would equal the current process and
-the mutex can be unlocked by just replacing the owner field with NULL.
-
-If the owner field has the "Has Waiters" bit set (or CMPXCHG is not available),
-the slow unlock path is taken.
-
-The first thing done in the slow unlock path is to take the wait_lock of the
-mutex.  This synchronizes the locking and unlocking of the mutex.
-
-A check is made to see if the mutex has waiters or not.  On architectures that
-do not have CMPXCHG, this is the location that the owner of the mutex will
-determine if a waiter needs to be awoken or not.  On architectures that
-do have CMPXCHG, that check is done in the fast path, but it is still needed
-in the slow path too.  If a waiter of a mutex woke up because of a signal
-or timeout between the time the owner failed the fast path CMPXCHG check and
-the grabbing of the wait_lock, the mutex may not have any waiters, thus the
-owner still needs to make this check. If there are no waiters then the mutex
-owner field is set to NULL, the wait_lock is released and nothing more is
-needed.
-
-If there are waiters, then we need to wake one up.
-
-On the wake up code, the pi_lock of the current owner is taken.  The top
-waiter of the lock is found and removed from the waiters tree of the mutex
-as well as the pi_waiters tree of the current owner. The "Has Waiters" bit is
-marked to prevent lower priority tasks from stealing the lock.
-
-Finally we unlock the pi_lock of the pending owner and wake it up.
-
-
-Contact
--------
-
-For updates on this document, please email Steven Rostedt <rostedt@goodmis.org>
-
-
-Credits
--------
-
-Author:  Steven Rostedt <rostedt@goodmis.org>
-Updated: Alex Shi <alex.shi@linaro.org>        - 7/6/2017
-
-Original Reviewers:  Ingo Molnar, Thomas Gleixner, Thomas Duetsch, and
-                    Randy Dunlap
-Update (7/6/2017) Reviewers: Steven Rostedt and Sebastian Siewior
-
-Updates
--------
-
-This document was originally written for 2.6.17-rc3-mm1
-was updated on 4.12
diff --git a/Documentation/locking/rt-mutex.rst b/Documentation/locking/rt-mutex.rst
new file mode 100644 (file)
index 0000000..c365dc3
--- /dev/null
@@ -0,0 +1,77 @@
+==================================
+RT-mutex subsystem with PI support
+==================================
+
+RT-mutexes with priority inheritance are used to support PI-futexes,
+which enable pthread_mutex_t priority inheritance attributes
+(PTHREAD_PRIO_INHERIT). [See Documentation/pi-futex.txt for more details
+about PI-futexes.]
+
+This technology was developed in the -rt tree and streamlined for
+pthread_mutex support.
+
+Basic principles:
+-----------------
+
+RT-mutexes extend the semantics of simple mutexes by the priority
+inheritance protocol.
+
+A low priority owner of a rt-mutex inherits the priority of a higher
+priority waiter until the rt-mutex is released. If the temporarily
+boosted owner blocks on a rt-mutex itself it propagates the priority
+boosting to the owner of the other rt_mutex it gets blocked on. The
+priority boosting is immediately removed once the rt_mutex has been
+unlocked.
+
+This approach allows us to shorten the block of high-prio tasks on
+mutexes which protect shared resources. Priority inheritance is not a
+magic bullet for poorly designed applications, but it allows
+well-designed applications to use userspace locks in critical parts of
+an high priority thread, without losing determinism.
+
+The enqueueing of the waiters into the rtmutex waiter tree is done in
+priority order. For same priorities FIFO order is chosen. For each
+rtmutex, only the top priority waiter is enqueued into the owner's
+priority waiters tree. This tree too queues in priority order. Whenever
+the top priority waiter of a task changes (for example it timed out or
+got a signal), the priority of the owner task is readjusted. The
+priority enqueueing is handled by "pi_waiters".
+
+RT-mutexes are optimized for fastpath operations and have no internal
+locking overhead when locking an uncontended mutex or unlocking a mutex
+without waiters. The optimized fastpath operations require cmpxchg
+support. [If that is not available then the rt-mutex internal spinlock
+is used]
+
+The state of the rt-mutex is tracked via the owner field of the rt-mutex
+structure:
+
+lock->owner holds the task_struct pointer of the owner. Bit 0 is used to
+keep track of the "lock has waiters" state:
+
+ ============ ======= ================================================
+ owner        bit0    Notes
+ ============ ======= ================================================
+ NULL         0       lock is free (fast acquire possible)
+ NULL         1       lock is free and has waiters and the top waiter
+                     is going to take the lock [1]_
+ taskpointer  0       lock is held (fast release possible)
+ taskpointer  1       lock is held and has waiters [2]_
+ ============ ======= ================================================
+
+The fast atomic compare exchange based acquire and release is only
+possible when bit 0 of lock->owner is 0.
+
+.. [1] It also can be a transitional state when grabbing the lock
+       with ->wait_lock is held. To prevent any fast path cmpxchg to the lock,
+       we need to set the bit0 before looking at the lock, and the owner may
+       be NULL in this small time, hence this can be a transitional state.
+
+.. [2] There is a small time when bit 0 is set but there are no
+       waiters. This can happen when grabbing the lock in the slow path.
+       To prevent a cmpxchg of the owner releasing the lock, we need to
+       set this bit before looking at the lock.
+
+BTW, there is still technically a "Pending Owner", it's just not called
+that anymore. The pending owner happens to be the top_waiter of a lock
+that has no owner and has been woken up to grab the lock.
diff --git a/Documentation/locking/rt-mutex.txt b/Documentation/locking/rt-mutex.txt
deleted file mode 100644 (file)
index 35793e0..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-RT-mutex subsystem with PI support
-----------------------------------
-
-RT-mutexes with priority inheritance are used to support PI-futexes,
-which enable pthread_mutex_t priority inheritance attributes
-(PTHREAD_PRIO_INHERIT). [See Documentation/pi-futex.txt for more details
-about PI-futexes.]
-
-This technology was developed in the -rt tree and streamlined for
-pthread_mutex support.
-
-Basic principles:
------------------
-
-RT-mutexes extend the semantics of simple mutexes by the priority
-inheritance protocol.
-
-A low priority owner of a rt-mutex inherits the priority of a higher
-priority waiter until the rt-mutex is released. If the temporarily
-boosted owner blocks on a rt-mutex itself it propagates the priority
-boosting to the owner of the other rt_mutex it gets blocked on. The
-priority boosting is immediately removed once the rt_mutex has been
-unlocked.
-
-This approach allows us to shorten the block of high-prio tasks on
-mutexes which protect shared resources. Priority inheritance is not a
-magic bullet for poorly designed applications, but it allows
-well-designed applications to use userspace locks in critical parts of
-an high priority thread, without losing determinism.
-
-The enqueueing of the waiters into the rtmutex waiter tree is done in
-priority order. For same priorities FIFO order is chosen. For each
-rtmutex, only the top priority waiter is enqueued into the owner's
-priority waiters tree. This tree too queues in priority order. Whenever
-the top priority waiter of a task changes (for example it timed out or
-got a signal), the priority of the owner task is readjusted. The
-priority enqueueing is handled by "pi_waiters".
-
-RT-mutexes are optimized for fastpath operations and have no internal
-locking overhead when locking an uncontended mutex or unlocking a mutex
-without waiters. The optimized fastpath operations require cmpxchg
-support. [If that is not available then the rt-mutex internal spinlock
-is used]
-
-The state of the rt-mutex is tracked via the owner field of the rt-mutex
-structure:
-
-lock->owner holds the task_struct pointer of the owner. Bit 0 is used to
-keep track of the "lock has waiters" state.
-
- owner        bit0
- NULL         0       lock is free (fast acquire possible)
- NULL         1       lock is free and has waiters and the top waiter
-                       is going to take the lock*
- taskpointer  0       lock is held (fast release possible)
- taskpointer  1       lock is held and has waiters**
-
-The fast atomic compare exchange based acquire and release is only
-possible when bit 0 of lock->owner is 0.
-
-(*) It also can be a transitional state when grabbing the lock
-with ->wait_lock is held. To prevent any fast path cmpxchg to the lock,
-we need to set the bit0 before looking at the lock, and the owner may be
-NULL in this small time, hence this can be a transitional state.
-
-(**) There is a small time when bit 0 is set but there are no
-waiters. This can happen when grabbing the lock in the slow path.
-To prevent a cmpxchg of the owner releasing the lock, we need to
-set this bit before looking at the lock.
-
-BTW, there is still technically a "Pending Owner", it's just not called
-that anymore. The pending owner happens to be the top_waiter of a lock
-that has no owner and has been woken up to grab the lock.
diff --git a/Documentation/locking/spinlocks.rst b/Documentation/locking/spinlocks.rst
new file mode 100644 (file)
index 0000000..098107f
--- /dev/null
@@ -0,0 +1,177 @@
+===============
+Locking lessons
+===============
+
+Lesson 1: Spin locks
+====================
+
+The most basic primitive for locking is spinlock::
+
+  static DEFINE_SPINLOCK(xxx_lock);
+
+       unsigned long flags;
+
+       spin_lock_irqsave(&xxx_lock, flags);
+       ... critical section here ..
+       spin_unlock_irqrestore(&xxx_lock, flags);
+
+The above is always safe. It will disable interrupts _locally_, but the
+spinlock itself will guarantee the global lock, so it will guarantee that
+there is only one thread-of-control within the region(s) protected by that
+lock. This works well even under UP also, so the code does _not_ need to
+worry about UP vs SMP issues: the spinlocks work correctly under both.
+
+   NOTE! Implications of spin_locks for memory are further described in:
+
+     Documentation/memory-barriers.txt
+
+       (5) LOCK operations.
+
+       (6) UNLOCK operations.
+
+The above is usually pretty simple (you usually need and want only one
+spinlock for most things - using more than one spinlock can make things a
+lot more complex and even slower and is usually worth it only for
+sequences that you **know** need to be split up: avoid it at all cost if you
+aren't sure).
+
+This is really the only really hard part about spinlocks: once you start
+using spinlocks they tend to expand to areas you might not have noticed
+before, because you have to make sure the spinlocks correctly protect the
+shared data structures **everywhere** they are used. The spinlocks are most
+easily added to places that are completely independent of other code (for
+example, internal driver data structures that nobody else ever touches).
+
+   NOTE! The spin-lock is safe only when you **also** use the lock itself
+   to do locking across CPU's, which implies that EVERYTHING that
+   touches a shared variable has to agree about the spinlock they want
+   to use.
+
+----
+
+Lesson 2: reader-writer spinlocks.
+==================================
+
+If your data accesses have a very natural pattern where you usually tend
+to mostly read from the shared variables, the reader-writer locks
+(rw_lock) versions of the spinlocks are sometimes useful. They allow multiple
+readers to be in the same critical region at once, but if somebody wants
+to change the variables it has to get an exclusive write lock.
+
+   NOTE! reader-writer locks require more atomic memory operations than
+   simple spinlocks.  Unless the reader critical section is long, you
+   are better off just using spinlocks.
+
+The routines look the same as above::
+
+   rwlock_t xxx_lock = __RW_LOCK_UNLOCKED(xxx_lock);
+
+       unsigned long flags;
+
+       read_lock_irqsave(&xxx_lock, flags);
+       .. critical section that only reads the info ...
+       read_unlock_irqrestore(&xxx_lock, flags);
+
+       write_lock_irqsave(&xxx_lock, flags);
+       .. read and write exclusive access to the info ...
+       write_unlock_irqrestore(&xxx_lock, flags);
+
+The above kind of lock may be useful for complex data structures like
+linked lists, especially searching for entries without changing the list
+itself.  The read lock allows many concurrent readers.  Anything that
+**changes** the list will have to get the write lock.
+
+   NOTE! RCU is better for list traversal, but requires careful
+   attention to design detail (see Documentation/RCU/listRCU.txt).
+
+Also, you cannot "upgrade" a read-lock to a write-lock, so if you at _any_
+time need to do any changes (even if you don't do it every time), you have
+to get the write-lock at the very beginning.
+
+   NOTE! We are working hard to remove reader-writer spinlocks in most
+   cases, so please don't add a new one without consensus.  (Instead, see
+   Documentation/RCU/rcu.txt for complete information.)
+
+----
+
+Lesson 3: spinlocks revisited.
+==============================
+
+The single spin-lock primitives above are by no means the only ones. They
+are the most safe ones, and the ones that work under all circumstances,
+but partly **because** they are safe they are also fairly slow. They are slower
+than they'd need to be, because they do have to disable interrupts
+(which is just a single instruction on a x86, but it's an expensive one -
+and on other architectures it can be worse).
+
+If you have a case where you have to protect a data structure across
+several CPU's and you want to use spinlocks you can potentially use
+cheaper versions of the spinlocks. IFF you know that the spinlocks are
+never used in interrupt handlers, you can use the non-irq versions::
+
+       spin_lock(&lock);
+       ...
+       spin_unlock(&lock);
+
+(and the equivalent read-write versions too, of course). The spinlock will
+guarantee the same kind of exclusive access, and it will be much faster.
+This is useful if you know that the data in question is only ever
+manipulated from a "process context", ie no interrupts involved.
+
+The reasons you mustn't use these versions if you have interrupts that
+play with the spinlock is that you can get deadlocks::
+
+       spin_lock(&lock);
+       ...
+               <- interrupt comes in:
+                       spin_lock(&lock);
+
+where an interrupt tries to lock an already locked variable. This is ok if
+the other interrupt happens on another CPU, but it is _not_ ok if the
+interrupt happens on the same CPU that already holds the lock, because the
+lock will obviously never be released (because the interrupt is waiting
+for the lock, and the lock-holder is interrupted by the interrupt and will
+not continue until the interrupt has been processed).
+
+(This is also the reason why the irq-versions of the spinlocks only need
+to disable the _local_ interrupts - it's ok to use spinlocks in interrupts
+on other CPU's, because an interrupt on another CPU doesn't interrupt the
+CPU that holds the lock, so the lock-holder can continue and eventually
+releases the lock).
+
+Note that you can be clever with read-write locks and interrupts. For
+example, if you know that the interrupt only ever gets a read-lock, then
+you can use a non-irq version of read locks everywhere - because they
+don't block on each other (and thus there is no dead-lock wrt interrupts.
+But when you do the write-lock, you have to use the irq-safe version.
+
+For an example of being clever with rw-locks, see the "waitqueue_lock"
+handling in kernel/sched/core.c - nothing ever _changes_ a wait-queue from
+within an interrupt, they only read the queue in order to know whom to
+wake up. So read-locks are safe (which is good: they are very common
+indeed), while write-locks need to protect themselves against interrupts.
+
+               Linus
+
+----
+
+Reference information:
+======================
+
+For dynamic initialization, use spin_lock_init() or rwlock_init() as
+appropriate::
+
+   spinlock_t xxx_lock;
+   rwlock_t xxx_rw_lock;
+
+   static int __init xxx_init(void)
+   {
+       spin_lock_init(&xxx_lock);
+       rwlock_init(&xxx_rw_lock);
+       ...
+   }
+
+   module_init(xxx_init);
+
+For static initialization, use DEFINE_SPINLOCK() / DEFINE_RWLOCK() or
+__SPIN_LOCK_UNLOCKED() / __RW_LOCK_UNLOCKED() as appropriate.
diff --git a/Documentation/locking/spinlocks.txt b/Documentation/locking/spinlocks.txt
deleted file mode 100644 (file)
index ff35e40..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-Lesson 1: Spin locks
-
-The most basic primitive for locking is spinlock.
-
-static DEFINE_SPINLOCK(xxx_lock);
-
-       unsigned long flags;
-
-       spin_lock_irqsave(&xxx_lock, flags);
-       ... critical section here ..
-       spin_unlock_irqrestore(&xxx_lock, flags);
-
-The above is always safe. It will disable interrupts _locally_, but the
-spinlock itself will guarantee the global lock, so it will guarantee that
-there is only one thread-of-control within the region(s) protected by that
-lock. This works well even under UP also, so the code does _not_ need to
-worry about UP vs SMP issues: the spinlocks work correctly under both.
-
-   NOTE! Implications of spin_locks for memory are further described in:
-
-     Documentation/memory-barriers.txt
-       (5) LOCK operations.
-       (6) UNLOCK operations.
-
-The above is usually pretty simple (you usually need and want only one
-spinlock for most things - using more than one spinlock can make things a
-lot more complex and even slower and is usually worth it only for
-sequences that you _know_ need to be split up: avoid it at all cost if you
-aren't sure).
-
-This is really the only really hard part about spinlocks: once you start
-using spinlocks they tend to expand to areas you might not have noticed
-before, because you have to make sure the spinlocks correctly protect the
-shared data structures _everywhere_ they are used. The spinlocks are most
-easily added to places that are completely independent of other code (for
-example, internal driver data structures that nobody else ever touches).
-
-   NOTE! The spin-lock is safe only when you _also_ use the lock itself
-   to do locking across CPU's, which implies that EVERYTHING that
-   touches a shared variable has to agree about the spinlock they want
-   to use.
-
-----
-
-Lesson 2: reader-writer spinlocks.
-
-If your data accesses have a very natural pattern where you usually tend
-to mostly read from the shared variables, the reader-writer locks
-(rw_lock) versions of the spinlocks are sometimes useful. They allow multiple
-readers to be in the same critical region at once, but if somebody wants
-to change the variables it has to get an exclusive write lock.
-
-   NOTE! reader-writer locks require more atomic memory operations than
-   simple spinlocks.  Unless the reader critical section is long, you
-   are better off just using spinlocks.
-
-The routines look the same as above:
-
-   rwlock_t xxx_lock = __RW_LOCK_UNLOCKED(xxx_lock);
-
-       unsigned long flags;
-
-       read_lock_irqsave(&xxx_lock, flags);
-       .. critical section that only reads the info ...
-       read_unlock_irqrestore(&xxx_lock, flags);
-
-       write_lock_irqsave(&xxx_lock, flags);
-       .. read and write exclusive access to the info ...
-       write_unlock_irqrestore(&xxx_lock, flags);
-
-The above kind of lock may be useful for complex data structures like
-linked lists, especially searching for entries without changing the list
-itself.  The read lock allows many concurrent readers.  Anything that
-_changes_ the list will have to get the write lock.
-
-   NOTE! RCU is better for list traversal, but requires careful
-   attention to design detail (see Documentation/RCU/listRCU.txt).
-
-Also, you cannot "upgrade" a read-lock to a write-lock, so if you at _any_
-time need to do any changes (even if you don't do it every time), you have
-to get the write-lock at the very beginning.
-
-   NOTE! We are working hard to remove reader-writer spinlocks in most
-   cases, so please don't add a new one without consensus.  (Instead, see
-   Documentation/RCU/rcu.txt for complete information.)
-
-----
-
-Lesson 3: spinlocks revisited.
-
-The single spin-lock primitives above are by no means the only ones. They
-are the most safe ones, and the ones that work under all circumstances,
-but partly _because_ they are safe they are also fairly slow. They are slower
-than they'd need to be, because they do have to disable interrupts
-(which is just a single instruction on a x86, but it's an expensive one -
-and on other architectures it can be worse).
-
-If you have a case where you have to protect a data structure across
-several CPU's and you want to use spinlocks you can potentially use
-cheaper versions of the spinlocks. IFF you know that the spinlocks are
-never used in interrupt handlers, you can use the non-irq versions:
-
-       spin_lock(&lock);
-       ...
-       spin_unlock(&lock);
-
-(and the equivalent read-write versions too, of course). The spinlock will
-guarantee the same kind of exclusive access, and it will be much faster.
-This is useful if you know that the data in question is only ever
-manipulated from a "process context", ie no interrupts involved.
-
-The reasons you mustn't use these versions if you have interrupts that
-play with the spinlock is that you can get deadlocks:
-
-       spin_lock(&lock);
-       ...
-               <- interrupt comes in:
-                       spin_lock(&lock);
-
-where an interrupt tries to lock an already locked variable. This is ok if
-the other interrupt happens on another CPU, but it is _not_ ok if the
-interrupt happens on the same CPU that already holds the lock, because the
-lock will obviously never be released (because the interrupt is waiting
-for the lock, and the lock-holder is interrupted by the interrupt and will
-not continue until the interrupt has been processed).
-
-(This is also the reason why the irq-versions of the spinlocks only need
-to disable the _local_ interrupts - it's ok to use spinlocks in interrupts
-on other CPU's, because an interrupt on another CPU doesn't interrupt the
-CPU that holds the lock, so the lock-holder can continue and eventually
-releases the lock).
-
-Note that you can be clever with read-write locks and interrupts. For
-example, if you know that the interrupt only ever gets a read-lock, then
-you can use a non-irq version of read locks everywhere - because they
-don't block on each other (and thus there is no dead-lock wrt interrupts.
-But when you do the write-lock, you have to use the irq-safe version.
-
-For an example of being clever with rw-locks, see the "waitqueue_lock"
-handling in kernel/sched/core.c - nothing ever _changes_ a wait-queue from
-within an interrupt, they only read the queue in order to know whom to
-wake up. So read-locks are safe (which is good: they are very common
-indeed), while write-locks need to protect themselves against interrupts.
-
-               Linus
-
-----
-
-Reference information:
-
-For dynamic initialization, use spin_lock_init() or rwlock_init() as
-appropriate:
-
-   spinlock_t xxx_lock;
-   rwlock_t xxx_rw_lock;
-
-   static int __init xxx_init(void)
-   {
-       spin_lock_init(&xxx_lock);
-       rwlock_init(&xxx_rw_lock);
-       ...
-   }
-
-   module_init(xxx_init);
-
-For static initialization, use DEFINE_SPINLOCK() / DEFINE_RWLOCK() or
-__SPIN_LOCK_UNLOCKED() / __RW_LOCK_UNLOCKED() as appropriate.
diff --git a/Documentation/locking/ww-mutex-design.rst b/Documentation/locking/ww-mutex-design.rst
new file mode 100644 (file)
index 0000000..1846c19
--- /dev/null
@@ -0,0 +1,393 @@
+======================================
+Wound/Wait Deadlock-Proof Mutex Design
+======================================
+
+Please read mutex-design.txt first, as it applies to wait/wound mutexes too.
+
+Motivation for WW-Mutexes
+-------------------------
+
+GPU's do operations that commonly involve many buffers.  Those buffers
+can be shared across contexts/processes, exist in different memory
+domains (for example VRAM vs system memory), and so on.  And with
+PRIME / dmabuf, they can even be shared across devices.  So there are
+a handful of situations where the driver needs to wait for buffers to
+become ready.  If you think about this in terms of waiting on a buffer
+mutex for it to become available, this presents a problem because
+there is no way to guarantee that buffers appear in a execbuf/batch in
+the same order in all contexts.  That is directly under control of
+userspace, and a result of the sequence of GL calls that an application
+makes. Which results in the potential for deadlock.  The problem gets
+more complex when you consider that the kernel may need to migrate the
+buffer(s) into VRAM before the GPU operates on the buffer(s), which
+may in turn require evicting some other buffers (and you don't want to
+evict other buffers which are already queued up to the GPU), but for a
+simplified understanding of the problem you can ignore this.
+
+The algorithm that the TTM graphics subsystem came up with for dealing with
+this problem is quite simple.  For each group of buffers (execbuf) that need
+to be locked, the caller would be assigned a unique reservation id/ticket,
+from a global counter.  In case of deadlock while locking all the buffers
+associated with a execbuf, the one with the lowest reservation ticket (i.e.
+the oldest task) wins, and the one with the higher reservation id (i.e. the
+younger task) unlocks all of the buffers that it has already locked, and then
+tries again.
+
+In the RDBMS literature, a reservation ticket is associated with a transaction.
+and the deadlock handling approach is called Wait-Die. The name is based on
+the actions of a locking thread when it encounters an already locked mutex.
+If the transaction holding the lock is younger, the locking transaction waits.
+If the transaction holding the lock is older, the locking transaction backs off
+and dies. Hence Wait-Die.
+There is also another algorithm called Wound-Wait:
+If the transaction holding the lock is younger, the locking transaction
+wounds the transaction holding the lock, requesting it to die.
+If the transaction holding the lock is older, it waits for the other
+transaction. Hence Wound-Wait.
+The two algorithms are both fair in that a transaction will eventually succeed.
+However, the Wound-Wait algorithm is typically stated to generate fewer backoffs
+compared to Wait-Die, but is, on the other hand, associated with more work than
+Wait-Die when recovering from a backoff. Wound-Wait is also a preemptive
+algorithm in that transactions are wounded by other transactions, and that
+requires a reliable way to pick up up the wounded condition and preempt the
+running transaction. Note that this is not the same as process preemption. A
+Wound-Wait transaction is considered preempted when it dies (returning
+-EDEADLK) following a wound.
+
+Concepts
+--------
+
+Compared to normal mutexes two additional concepts/objects show up in the lock
+interface for w/w mutexes:
+
+Acquire context: To ensure eventual forward progress it is important the a task
+trying to acquire locks doesn't grab a new reservation id, but keeps the one it
+acquired when starting the lock acquisition. This ticket is stored in the
+acquire context. Furthermore the acquire context keeps track of debugging state
+to catch w/w mutex interface abuse. An acquire context is representing a
+transaction.
+
+W/w class: In contrast to normal mutexes the lock class needs to be explicit for
+w/w mutexes, since it is required to initialize the acquire context. The lock
+class also specifies what algorithm to use, Wound-Wait or Wait-Die.
+
+Furthermore there are three different class of w/w lock acquire functions:
+
+* Normal lock acquisition with a context, using ww_mutex_lock.
+
+* Slowpath lock acquisition on the contending lock, used by the task that just
+  killed its transaction after having dropped all already acquired locks.
+  These functions have the _slow postfix.
+
+  From a simple semantics point-of-view the _slow functions are not strictly
+  required, since simply calling the normal ww_mutex_lock functions on the
+  contending lock (after having dropped all other already acquired locks) will
+  work correctly. After all if no other ww mutex has been acquired yet there's
+  no deadlock potential and hence the ww_mutex_lock call will block and not
+  prematurely return -EDEADLK. The advantage of the _slow functions is in
+  interface safety:
+
+  - ww_mutex_lock has a __must_check int return type, whereas ww_mutex_lock_slow
+    has a void return type. Note that since ww mutex code needs loops/retries
+    anyway the __must_check doesn't result in spurious warnings, even though the
+    very first lock operation can never fail.
+  - When full debugging is enabled ww_mutex_lock_slow checks that all acquired
+    ww mutex have been released (preventing deadlocks) and makes sure that we
+    block on the contending lock (preventing spinning through the -EDEADLK
+    slowpath until the contended lock can be acquired).
+
+* Functions to only acquire a single w/w mutex, which results in the exact same
+  semantics as a normal mutex. This is done by calling ww_mutex_lock with a NULL
+  context.
+
+  Again this is not strictly required. But often you only want to acquire a
+  single lock in which case it's pointless to set up an acquire context (and so
+  better to avoid grabbing a deadlock avoidance ticket).
+
+Of course, all the usual variants for handling wake-ups due to signals are also
+provided.
+
+Usage
+-----
+
+The algorithm (Wait-Die vs Wound-Wait) is chosen by using either
+DEFINE_WW_CLASS() (Wound-Wait) or DEFINE_WD_CLASS() (Wait-Die)
+As a rough rule of thumb, use Wound-Wait iff you
+expect the number of simultaneous competing transactions to be typically small,
+and you want to reduce the number of rollbacks.
+
+Three different ways to acquire locks within the same w/w class. Common
+definitions for methods #1 and #2::
+
+  static DEFINE_WW_CLASS(ww_class);
+
+  struct obj {
+       struct ww_mutex lock;
+       /* obj data */
+  };
+
+  struct obj_entry {
+       struct list_head head;
+       struct obj *obj;
+  };
+
+Method 1, using a list in execbuf->buffers that's not allowed to be reordered.
+This is useful if a list of required objects is already tracked somewhere.
+Furthermore the lock helper can use propagate the -EALREADY return code back to
+the caller as a signal that an object is twice on the list. This is useful if
+the list is constructed from userspace input and the ABI requires userspace to
+not have duplicate entries (e.g. for a gpu commandbuffer submission ioctl)::
+
+  int lock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
+  {
+       struct obj *res_obj = NULL;
+       struct obj_entry *contended_entry = NULL;
+       struct obj_entry *entry;
+
+       ww_acquire_init(ctx, &ww_class);
+
+  retry:
+       list_for_each_entry (entry, list, head) {
+               if (entry->obj == res_obj) {
+                       res_obj = NULL;
+                       continue;
+               }
+               ret = ww_mutex_lock(&entry->obj->lock, ctx);
+               if (ret < 0) {
+                       contended_entry = entry;
+                       goto err;
+               }
+       }
+
+       ww_acquire_done(ctx);
+       return 0;
+
+  err:
+       list_for_each_entry_continue_reverse (entry, list, head)
+               ww_mutex_unlock(&entry->obj->lock);
+
+       if (res_obj)
+               ww_mutex_unlock(&res_obj->lock);
+
+       if (ret == -EDEADLK) {
+               /* we lost out in a seqno race, lock and retry.. */
+               ww_mutex_lock_slow(&contended_entry->obj->lock, ctx);
+               res_obj = contended_entry->obj;
+               goto retry;
+       }
+       ww_acquire_fini(ctx);
+
+       return ret;
+  }
+
+Method 2, using a list in execbuf->buffers that can be reordered. Same semantics
+of duplicate entry detection using -EALREADY as method 1 above. But the
+list-reordering allows for a bit more idiomatic code::
+
+  int lock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
+  {
+       struct obj_entry *entry, *entry2;
+
+       ww_acquire_init(ctx, &ww_class);
+
+       list_for_each_entry (entry, list, head) {
+               ret = ww_mutex_lock(&entry->obj->lock, ctx);
+               if (ret < 0) {
+                       entry2 = entry;
+
+                       list_for_each_entry_continue_reverse (entry2, list, head)
+                               ww_mutex_unlock(&entry2->obj->lock);
+
+                       if (ret != -EDEADLK) {
+                               ww_acquire_fini(ctx);
+                               return ret;
+                       }
+
+                       /* we lost out in a seqno race, lock and retry.. */
+                       ww_mutex_lock_slow(&entry->obj->lock, ctx);
+
+                       /*
+                        * Move buf to head of the list, this will point
+                        * buf->next to the first unlocked entry,
+                        * restarting the for loop.
+                        */
+                       list_del(&entry->head);
+                       list_add(&entry->head, list);
+               }
+       }
+
+       ww_acquire_done(ctx);
+       return 0;
+  }
+
+Unlocking works the same way for both methods #1 and #2::
+
+  void unlock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
+  {
+       struct obj_entry *entry;
+
+       list_for_each_entry (entry, list, head)
+               ww_mutex_unlock(&entry->obj->lock);
+
+       ww_acquire_fini(ctx);
+  }
+
+Method 3 is useful if the list of objects is constructed ad-hoc and not upfront,
+e.g. when adjusting edges in a graph where each node has its own ww_mutex lock,
+and edges can only be changed when holding the locks of all involved nodes. w/w
+mutexes are a natural fit for such a case for two reasons:
+
+- They can handle lock-acquisition in any order which allows us to start walking
+  a graph from a starting point and then iteratively discovering new edges and
+  locking down the nodes those edges connect to.
+- Due to the -EALREADY return code signalling that a given objects is already
+  held there's no need for additional book-keeping to break cycles in the graph
+  or keep track off which looks are already held (when using more than one node
+  as a starting point).
+
+Note that this approach differs in two important ways from the above methods:
+
+- Since the list of objects is dynamically constructed (and might very well be
+  different when retrying due to hitting the -EDEADLK die condition) there's
+  no need to keep any object on a persistent list when it's not locked. We can
+  therefore move the list_head into the object itself.
+- On the other hand the dynamic object list construction also means that the -EALREADY return
+  code can't be propagated.
+
+Note also that methods #1 and #2 and method #3 can be combined, e.g. to first lock a
+list of starting nodes (passed in from userspace) using one of the above
+methods. And then lock any additional objects affected by the operations using
+method #3 below. The backoff/retry procedure will be a bit more involved, since
+when the dynamic locking step hits -EDEADLK we also need to unlock all the
+objects acquired with the fixed list. But the w/w mutex debug checks will catch
+any interface misuse for these cases.
+
+Also, method 3 can't fail the lock acquisition step since it doesn't return
+-EALREADY. Of course this would be different when using the _interruptible
+variants, but that's outside of the scope of these examples here::
+
+  struct obj {
+       struct ww_mutex ww_mutex;
+       struct list_head locked_list;
+  };
+
+  static DEFINE_WW_CLASS(ww_class);
+
+  void __unlock_objs(struct list_head *list)
+  {
+       struct obj *entry, *temp;
+
+       list_for_each_entry_safe (entry, temp, list, locked_list) {
+               /* need to do that before unlocking, since only the current lock holder is
+               allowed to use object */
+               list_del(&entry->locked_list);
+               ww_mutex_unlock(entry->ww_mutex)
+       }
+  }
+
+  void lock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
+  {
+       struct obj *obj;
+
+       ww_acquire_init(ctx, &ww_class);
+
+  retry:
+       /* re-init loop start state */
+       loop {
+               /* magic code which walks over a graph and decides which objects
+                * to lock */
+
+               ret = ww_mutex_lock(obj->ww_mutex, ctx);
+               if (ret == -EALREADY) {
+                       /* we have that one already, get to the next object */
+                       continue;
+               }
+               if (ret == -EDEADLK) {
+                       __unlock_objs(list);
+
+                       ww_mutex_lock_slow(obj, ctx);
+                       list_add(&entry->locked_list, list);
+                       goto retry;
+               }
+
+               /* locked a new object, add it to the list */
+               list_add_tail(&entry->locked_list, list);
+       }
+
+       ww_acquire_done(ctx);
+       return 0;
+  }
+
+  void unlock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
+  {
+       __unlock_objs(list);
+       ww_acquire_fini(ctx);
+  }
+
+Method 4: Only lock one single objects. In that case deadlock detection and
+prevention is obviously overkill, since with grabbing just one lock you can't
+produce a deadlock within just one class. To simplify this case the w/w mutex
+api can be used with a NULL context.
+
+Implementation Details
+----------------------
+
+Design:
+^^^^^^^
+
+  ww_mutex currently encapsulates a struct mutex, this means no extra overhead for
+  normal mutex locks, which are far more common. As such there is only a small
+  increase in code size if wait/wound mutexes are not used.
+
+  We maintain the following invariants for the wait list:
+
+  (1) Waiters with an acquire context are sorted by stamp order; waiters
+      without an acquire context are interspersed in FIFO order.
+  (2) For Wait-Die, among waiters with contexts, only the first one can have
+      other locks acquired already (ctx->acquired > 0). Note that this waiter
+      may come after other waiters without contexts in the list.
+
+  The Wound-Wait preemption is implemented with a lazy-preemption scheme:
+  The wounded status of the transaction is checked only when there is
+  contention for a new lock and hence a true chance of deadlock. In that
+  situation, if the transaction is wounded, it backs off, clears the
+  wounded status and retries. A great benefit of implementing preemption in
+  this way is that the wounded transaction can identify a contending lock to
+  wait for before restarting the transaction. Just blindly restarting the
+  transaction would likely make the transaction end up in a situation where
+  it would have to back off again.
+
+  In general, not much contention is expected. The locks are typically used to
+  serialize access to resources for devices, and optimization focus should
+  therefore be directed towards the uncontended cases.
+
+Lockdep:
+^^^^^^^^
+
+  Special care has been taken to warn for as many cases of api abuse
+  as possible. Some common api abuses will be caught with
+  CONFIG_DEBUG_MUTEXES, but CONFIG_PROVE_LOCKING is recommended.
+
+  Some of the errors which will be warned about:
+   - Forgetting to call ww_acquire_fini or ww_acquire_init.
+   - Attempting to lock more mutexes after ww_acquire_done.
+   - Attempting to lock the wrong mutex after -EDEADLK and
+     unlocking all mutexes.
+   - Attempting to lock the right mutex after -EDEADLK,
+     before unlocking all mutexes.
+
+   - Calling ww_mutex_lock_slow before -EDEADLK was returned.
+
+   - Unlocking mutexes with the wrong unlock function.
+   - Calling one of the ww_acquire_* twice on the same context.
+   - Using a different ww_class for the mutex than for the ww_acquire_ctx.
+   - Normal lockdep errors that can result in deadlocks.
+
+  Some of the lockdep errors that can result in deadlocks:
+   - Calling ww_acquire_init to initialize a second ww_acquire_ctx before
+     having called ww_acquire_fini on the first.
+   - 'normal' deadlocks that can occur.
+
+FIXME:
+  Update this section once we have the TASK_DEADLOCK task state flag magic
+  implemented.
diff --git a/Documentation/locking/ww-mutex-design.txt b/Documentation/locking/ww-mutex-design.txt
deleted file mode 100644 (file)
index f0ed7c3..0000000
+++ /dev/null
@@ -1,383 +0,0 @@
-Wound/Wait Deadlock-Proof Mutex Design
-======================================
-
-Please read mutex-design.txt first, as it applies to wait/wound mutexes too.
-
-Motivation for WW-Mutexes
--------------------------
-
-GPU's do operations that commonly involve many buffers.  Those buffers
-can be shared across contexts/processes, exist in different memory
-domains (for example VRAM vs system memory), and so on.  And with
-PRIME / dmabuf, they can even be shared across devices.  So there are
-a handful of situations where the driver needs to wait for buffers to
-become ready.  If you think about this in terms of waiting on a buffer
-mutex for it to become available, this presents a problem because
-there is no way to guarantee that buffers appear in a execbuf/batch in
-the same order in all contexts.  That is directly under control of
-userspace, and a result of the sequence of GL calls that an application
-makes. Which results in the potential for deadlock.  The problem gets
-more complex when you consider that the kernel may need to migrate the
-buffer(s) into VRAM before the GPU operates on the buffer(s), which
-may in turn require evicting some other buffers (and you don't want to
-evict other buffers which are already queued up to the GPU), but for a
-simplified understanding of the problem you can ignore this.
-
-The algorithm that the TTM graphics subsystem came up with for dealing with
-this problem is quite simple.  For each group of buffers (execbuf) that need
-to be locked, the caller would be assigned a unique reservation id/ticket,
-from a global counter.  In case of deadlock while locking all the buffers
-associated with a execbuf, the one with the lowest reservation ticket (i.e.
-the oldest task) wins, and the one with the higher reservation id (i.e. the
-younger task) unlocks all of the buffers that it has already locked, and then
-tries again.
-
-In the RDBMS literature, a reservation ticket is associated with a transaction.
-and the deadlock handling approach is called Wait-Die. The name is based on
-the actions of a locking thread when it encounters an already locked mutex.
-If the transaction holding the lock is younger, the locking transaction waits.
-If the transaction holding the lock is older, the locking transaction backs off
-and dies. Hence Wait-Die.
-There is also another algorithm called Wound-Wait:
-If the transaction holding the lock is younger, the locking transaction
-wounds the transaction holding the lock, requesting it to die.
-If the transaction holding the lock is older, it waits for the other
-transaction. Hence Wound-Wait.
-The two algorithms are both fair in that a transaction will eventually succeed.
-However, the Wound-Wait algorithm is typically stated to generate fewer backoffs
-compared to Wait-Die, but is, on the other hand, associated with more work than
-Wait-Die when recovering from a backoff. Wound-Wait is also a preemptive
-algorithm in that transactions are wounded by other transactions, and that
-requires a reliable way to pick up up the wounded condition and preempt the
-running transaction. Note that this is not the same as process preemption. A
-Wound-Wait transaction is considered preempted when it dies (returning
--EDEADLK) following a wound.
-
-Concepts
---------
-
-Compared to normal mutexes two additional concepts/objects show up in the lock
-interface for w/w mutexes:
-
-Acquire context: To ensure eventual forward progress it is important the a task
-trying to acquire locks doesn't grab a new reservation id, but keeps the one it
-acquired when starting the lock acquisition. This ticket is stored in the
-acquire context. Furthermore the acquire context keeps track of debugging state
-to catch w/w mutex interface abuse. An acquire context is representing a
-transaction.
-
-W/w class: In contrast to normal mutexes the lock class needs to be explicit for
-w/w mutexes, since it is required to initialize the acquire context. The lock
-class also specifies what algorithm to use, Wound-Wait or Wait-Die.
-
-Furthermore there are three different class of w/w lock acquire functions:
-
-* Normal lock acquisition with a context, using ww_mutex_lock.
-
-* Slowpath lock acquisition on the contending lock, used by the task that just
-  killed its transaction after having dropped all already acquired locks.
-  These functions have the _slow postfix.
-
-  From a simple semantics point-of-view the _slow functions are not strictly
-  required, since simply calling the normal ww_mutex_lock functions on the
-  contending lock (after having dropped all other already acquired locks) will
-  work correctly. After all if no other ww mutex has been acquired yet there's
-  no deadlock potential and hence the ww_mutex_lock call will block and not
-  prematurely return -EDEADLK. The advantage of the _slow functions is in
-  interface safety:
-  - ww_mutex_lock has a __must_check int return type, whereas ww_mutex_lock_slow
-    has a void return type. Note that since ww mutex code needs loops/retries
-    anyway the __must_check doesn't result in spurious warnings, even though the
-    very first lock operation can never fail.
-  - When full debugging is enabled ww_mutex_lock_slow checks that all acquired
-    ww mutex have been released (preventing deadlocks) and makes sure that we
-    block on the contending lock (preventing spinning through the -EDEADLK
-    slowpath until the contended lock can be acquired).
-
-* Functions to only acquire a single w/w mutex, which results in the exact same
-  semantics as a normal mutex. This is done by calling ww_mutex_lock with a NULL
-  context.
-
-  Again this is not strictly required. But often you only want to acquire a
-  single lock in which case it's pointless to set up an acquire context (and so
-  better to avoid grabbing a deadlock avoidance ticket).
-
-Of course, all the usual variants for handling wake-ups due to signals are also
-provided.
-
-Usage
------
-
-The algorithm (Wait-Die vs Wound-Wait) is chosen by using either
-DEFINE_WW_CLASS() (Wound-Wait) or DEFINE_WD_CLASS() (Wait-Die)
-As a rough rule of thumb, use Wound-Wait iff you
-expect the number of simultaneous competing transactions to be typically small,
-and you want to reduce the number of rollbacks.
-
-Three different ways to acquire locks within the same w/w class. Common
-definitions for methods #1 and #2:
-
-static DEFINE_WW_CLASS(ww_class);
-
-struct obj {
-       struct ww_mutex lock;
-       /* obj data */
-};
-
-struct obj_entry {
-       struct list_head head;
-       struct obj *obj;
-};
-
-Method 1, using a list in execbuf->buffers that's not allowed to be reordered.
-This is useful if a list of required objects is already tracked somewhere.
-Furthermore the lock helper can use propagate the -EALREADY return code back to
-the caller as a signal that an object is twice on the list. This is useful if
-the list is constructed from userspace input and the ABI requires userspace to
-not have duplicate entries (e.g. for a gpu commandbuffer submission ioctl).
-
-int lock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
-{
-       struct obj *res_obj = NULL;
-       struct obj_entry *contended_entry = NULL;
-       struct obj_entry *entry;
-
-       ww_acquire_init(ctx, &ww_class);
-
-retry:
-       list_for_each_entry (entry, list, head) {
-               if (entry->obj == res_obj) {
-                       res_obj = NULL;
-                       continue;
-               }
-               ret = ww_mutex_lock(&entry->obj->lock, ctx);
-               if (ret < 0) {
-                       contended_entry = entry;
-                       goto err;
-               }
-       }
-
-       ww_acquire_done(ctx);
-       return 0;
-
-err:
-       list_for_each_entry_continue_reverse (entry, list, head)
-               ww_mutex_unlock(&entry->obj->lock);
-
-       if (res_obj)
-               ww_mutex_unlock(&res_obj->lock);
-
-       if (ret == -EDEADLK) {
-               /* we lost out in a seqno race, lock and retry.. */
-               ww_mutex_lock_slow(&contended_entry->obj->lock, ctx);
-               res_obj = contended_entry->obj;
-               goto retry;
-       }
-       ww_acquire_fini(ctx);
-
-       return ret;
-}
-
-Method 2, using a list in execbuf->buffers that can be reordered. Same semantics
-of duplicate entry detection using -EALREADY as method 1 above. But the
-list-reordering allows for a bit more idiomatic code.
-
-int lock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
-{
-       struct obj_entry *entry, *entry2;
-
-       ww_acquire_init(ctx, &ww_class);
-
-       list_for_each_entry (entry, list, head) {
-               ret = ww_mutex_lock(&entry->obj->lock, ctx);
-               if (ret < 0) {
-                       entry2 = entry;
-
-                       list_for_each_entry_continue_reverse (entry2, list, head)
-                               ww_mutex_unlock(&entry2->obj->lock);
-
-                       if (ret != -EDEADLK) {
-                               ww_acquire_fini(ctx);
-                               return ret;
-                       }
-
-                       /* we lost out in a seqno race, lock and retry.. */
-                       ww_mutex_lock_slow(&entry->obj->lock, ctx);
-
-                       /*
-                        * Move buf to head of the list, this will point
-                        * buf->next to the first unlocked entry,
-                        * restarting the for loop.
-                        */
-                       list_del(&entry->head);
-                       list_add(&entry->head, list);
-               }
-       }
-
-       ww_acquire_done(ctx);
-       return 0;
-}
-
-Unlocking works the same way for both methods #1 and #2:
-
-void unlock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
-{
-       struct obj_entry *entry;
-
-       list_for_each_entry (entry, list, head)
-               ww_mutex_unlock(&entry->obj->lock);
-
-       ww_acquire_fini(ctx);
-}
-
-Method 3 is useful if the list of objects is constructed ad-hoc and not upfront,
-e.g. when adjusting edges in a graph where each node has its own ww_mutex lock,
-and edges can only be changed when holding the locks of all involved nodes. w/w
-mutexes are a natural fit for such a case for two reasons:
-- They can handle lock-acquisition in any order which allows us to start walking
-  a graph from a starting point and then iteratively discovering new edges and
-  locking down the nodes those edges connect to.
-- Due to the -EALREADY return code signalling that a given objects is already
-  held there's no need for additional book-keeping to break cycles in the graph
-  or keep track off which looks are already held (when using more than one node
-  as a starting point).
-
-Note that this approach differs in two important ways from the above methods:
-- Since the list of objects is dynamically constructed (and might very well be
-  different when retrying due to hitting the -EDEADLK die condition) there's
-  no need to keep any object on a persistent list when it's not locked. We can
-  therefore move the list_head into the object itself.
-- On the other hand the dynamic object list construction also means that the -EALREADY return
-  code can't be propagated.
-
-Note also that methods #1 and #2 and method #3 can be combined, e.g. to first lock a
-list of starting nodes (passed in from userspace) using one of the above
-methods. And then lock any additional objects affected by the operations using
-method #3 below. The backoff/retry procedure will be a bit more involved, since
-when the dynamic locking step hits -EDEADLK we also need to unlock all the
-objects acquired with the fixed list. But the w/w mutex debug checks will catch
-any interface misuse for these cases.
-
-Also, method 3 can't fail the lock acquisition step since it doesn't return
--EALREADY. Of course this would be different when using the _interruptible
-variants, but that's outside of the scope of these examples here.
-
-struct obj {
-       struct ww_mutex ww_mutex;
-       struct list_head locked_list;
-};
-
-static DEFINE_WW_CLASS(ww_class);
-
-void __unlock_objs(struct list_head *list)
-{
-       struct obj *entry, *temp;
-
-       list_for_each_entry_safe (entry, temp, list, locked_list) {
-               /* need to do that before unlocking, since only the current lock holder is
-               allowed to use object */
-               list_del(&entry->locked_list);
-               ww_mutex_unlock(entry->ww_mutex)
-       }
-}
-
-void lock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
-{
-       struct obj *obj;
-
-       ww_acquire_init(ctx, &ww_class);
-
-retry:
-       /* re-init loop start state */
-       loop {
-               /* magic code which walks over a graph and decides which objects
-                * to lock */
-
-               ret = ww_mutex_lock(obj->ww_mutex, ctx);
-               if (ret == -EALREADY) {
-                       /* we have that one already, get to the next object */
-                       continue;
-               }
-               if (ret == -EDEADLK) {
-                       __unlock_objs(list);
-
-                       ww_mutex_lock_slow(obj, ctx);
-                       list_add(&entry->locked_list, list);
-                       goto retry;
-               }
-
-               /* locked a new object, add it to the list */
-               list_add_tail(&entry->locked_list, list);
-       }
-
-       ww_acquire_done(ctx);
-       return 0;
-}
-
-void unlock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
-{
-       __unlock_objs(list);
-       ww_acquire_fini(ctx);
-}
-
-Method 4: Only lock one single objects. In that case deadlock detection and
-prevention is obviously overkill, since with grabbing just one lock you can't
-produce a deadlock within just one class. To simplify this case the w/w mutex
-api can be used with a NULL context.
-
-Implementation Details
-----------------------
-
-Design:
-  ww_mutex currently encapsulates a struct mutex, this means no extra overhead for
-  normal mutex locks, which are far more common. As such there is only a small
-  increase in code size if wait/wound mutexes are not used.
-
-  We maintain the following invariants for the wait list:
-  (1) Waiters with an acquire context are sorted by stamp order; waiters
-      without an acquire context are interspersed in FIFO order.
-  (2) For Wait-Die, among waiters with contexts, only the first one can have
-      other locks acquired already (ctx->acquired > 0). Note that this waiter
-      may come after other waiters without contexts in the list.
-
-  The Wound-Wait preemption is implemented with a lazy-preemption scheme:
-  The wounded status of the transaction is checked only when there is
-  contention for a new lock and hence a true chance of deadlock. In that
-  situation, if the transaction is wounded, it backs off, clears the
-  wounded status and retries. A great benefit of implementing preemption in
-  this way is that the wounded transaction can identify a contending lock to
-  wait for before restarting the transaction. Just blindly restarting the
-  transaction would likely make the transaction end up in a situation where
-  it would have to back off again.
-
-  In general, not much contention is expected. The locks are typically used to
-  serialize access to resources for devices, and optimization focus should
-  therefore be directed towards the uncontended cases.
-
-Lockdep:
-  Special care has been taken to warn for as many cases of api abuse
-  as possible. Some common api abuses will be caught with
-  CONFIG_DEBUG_MUTEXES, but CONFIG_PROVE_LOCKING is recommended.
-
-  Some of the errors which will be warned about:
-   - Forgetting to call ww_acquire_fini or ww_acquire_init.
-   - Attempting to lock more mutexes after ww_acquire_done.
-   - Attempting to lock the wrong mutex after -EDEADLK and
-     unlocking all mutexes.
-   - Attempting to lock the right mutex after -EDEADLK,
-     before unlocking all mutexes.
-
-   - Calling ww_mutex_lock_slow before -EDEADLK was returned.
-
-   - Unlocking mutexes with the wrong unlock function.
-   - Calling one of the ww_acquire_* twice on the same context.
-   - Using a different ww_class for the mutex than for the ww_acquire_ctx.
-   - Normal lockdep errors that can result in deadlocks.
-
-  Some of the lockdep errors that can result in deadlocks:
-   - Calling ww_acquire_init to initialize a second ww_acquire_ctx before
-     having called ww_acquire_fini on the first.
-   - 'normal' deadlocks that can occur.
-
-FIXME: Update this section once we have the TASK_DEADLOCK task state flag magic
-implemented.
diff --git a/Documentation/m68k/index.rst b/Documentation/m68k/index.rst
new file mode 100644 (file)
index 0000000..3a5ba7f
--- /dev/null
@@ -0,0 +1,17 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=================
+m68k Architecture
+=================
+
+.. toctree::
+   :maxdepth: 2
+
+   kernel-options
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
diff --git a/Documentation/m68k/kernel-options.rst b/Documentation/m68k/kernel-options.rst
new file mode 100644 (file)
index 0000000..cabd941
--- /dev/null
@@ -0,0 +1,911 @@
+===================================
+Command Line Options for Linux/m68k
+===================================
+
+Last Update: 2 May 1999
+
+Linux/m68k version: 2.2.6
+
+Author: Roman.Hodek@informatik.uni-erlangen.de (Roman Hodek)
+
+Update: jds@kom.auc.dk (Jes Sorensen) and faq@linux-m68k.org (Chris Lawrence)
+
+0) Introduction
+===============
+
+Often I've been asked which command line options the Linux/m68k
+kernel understands, or how the exact syntax for the ... option is, or
+... about the option ... . I hope, this document supplies all the
+answers...
+
+Note that some options might be outdated, their descriptions being
+incomplete or missing. Please update the information and send in the
+patches.
+
+
+1) Overview of the Kernel's Option Processing
+=============================================
+
+The kernel knows three kinds of options on its command line:
+
+  1) kernel options
+  2) environment settings
+  3) arguments for init
+
+To which of these classes an argument belongs is determined as
+follows: If the option is known to the kernel itself, i.e. if the name
+(the part before the '=') or, in some cases, the whole argument string
+is known to the kernel, it belongs to class 1. Otherwise, if the
+argument contains an '=', it is of class 2, and the definition is put
+into init's environment. All other arguments are passed to init as
+command line options.
+
+This document describes the valid kernel options for Linux/m68k in
+the version mentioned at the start of this file. Later revisions may
+add new such options, and some may be missing in older versions.
+
+In general, the value (the part after the '=') of an option is a
+list of values separated by commas. The interpretation of these values
+is up to the driver that "owns" the option. This association of
+options with drivers is also the reason that some are further
+subdivided.
+
+
+2) General Kernel Options
+=========================
+
+2.1) root=
+----------
+
+:Syntax: root=/dev/<device>
+:or:     root=<hex_number>
+
+This tells the kernel which device it should mount as the root
+filesystem. The device must be a block device with a valid filesystem
+on it.
+
+The first syntax gives the device by name. These names are converted
+into a major/minor number internally in the kernel in an unusual way.
+Normally, this "conversion" is done by the device files in /dev, but
+this isn't possible here, because the root filesystem (with /dev)
+isn't mounted yet... So the kernel parses the name itself, with some
+hardcoded name to number mappings. The name must always be a
+combination of two or three letters, followed by a decimal number.
+Valid names are::
+
+  /dev/ram: -> 0x0100 (initial ramdisk)
+  /dev/hda: -> 0x0300 (first IDE disk)
+  /dev/hdb: -> 0x0340 (second IDE disk)
+  /dev/sda: -> 0x0800 (first SCSI disk)
+  /dev/sdb: -> 0x0810 (second SCSI disk)
+  /dev/sdc: -> 0x0820 (third SCSI disk)
+  /dev/sdd: -> 0x0830 (forth SCSI disk)
+  /dev/sde: -> 0x0840 (fifth SCSI disk)
+  /dev/fd : -> 0x0200 (floppy disk)
+
+The name must be followed by a decimal number, that stands for the
+partition number. Internally, the value of the number is just
+added to the device number mentioned in the table above. The
+exceptions are /dev/ram and /dev/fd, where /dev/ram refers to an
+initial ramdisk loaded by your bootstrap program (please consult the
+instructions for your bootstrap program to find out how to load an
+initial ramdisk). As of kernel version 2.0.18 you must specify
+/dev/ram as the root device if you want to boot from an initial
+ramdisk. For the floppy devices, /dev/fd, the number stands for the
+floppy drive number (there are no partitions on floppy disks). I.e.,
+/dev/fd0 stands for the first drive, /dev/fd1 for the second, and so
+on. Since the number is just added, you can also force the disk format
+by adding a number greater than 3. If you look into your /dev
+directory, use can see the /dev/fd0D720 has major 2 and minor 16. You
+can specify this device for the root FS by writing "root=/dev/fd16" on
+the kernel command line.
+
+[Strange and maybe uninteresting stuff ON]
+
+This unusual translation of device names has some strange
+consequences: If, for example, you have a symbolic link from /dev/fd
+to /dev/fd0D720 as an abbreviation for floppy driver #0 in DD format,
+you cannot use this name for specifying the root device, because the
+kernel cannot see this symlink before mounting the root FS and it
+isn't in the table above. If you use it, the root device will not be
+set at all, without an error message. Another example: You cannot use a
+partition on e.g. the sixth SCSI disk as the root filesystem, if you
+want to specify it by name. This is, because only the devices up to
+/dev/sde are in the table above, but not /dev/sdf. Although, you can
+use the sixth SCSI disk for the root FS, but you have to specify the
+device by number... (see below). Or, even more strange, you can use the
+fact that there is no range checking of the partition number, and your
+knowledge that each disk uses 16 minors, and write "root=/dev/sde17"
+(for /dev/sdf1).
+
+[Strange and maybe uninteresting stuff OFF]
+
+If the device containing your root partition isn't in the table
+above, you can also specify it by major and minor numbers. These are
+written in hex, with no prefix and no separator between. E.g., if you
+have a CD with contents appropriate as a root filesystem in the first
+SCSI CD-ROM drive, you boot from it by "root=0b00". Here, hex "0b" =
+decimal 11 is the major of SCSI CD-ROMs, and the minor 0 stands for
+the first of these. You can find out all valid major numbers by
+looking into include/linux/major.h.
+
+In addition to major and minor numbers, if the device containing your
+root partition uses a partition table format with unique partition
+identifiers, then you may use them.  For instance,
+"root=PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF".  It is also
+possible to reference another partition on the same device using a
+known partition UUID as the starting point.  For example,
+if partition 5 of the device has the UUID of
+00112233-4455-6677-8899-AABBCCDDEEFF then partition 3 may be found as
+follows:
+
+  PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF/PARTNROFF=-2
+
+Authoritative information can be found in
+"Documentation/admin-guide/kernel-parameters.rst".
+
+
+2.2) ro, rw
+-----------
+
+:Syntax: ro
+:or:     rw
+
+These two options tell the kernel whether it should mount the root
+filesystem read-only or read-write. The default is read-only, except
+for ramdisks, which default to read-write.
+
+
+2.3) debug
+----------
+
+:Syntax: debug
+
+This raises the kernel log level to 10 (the default is 7). This is the
+same level as set by the "dmesg" command, just that the maximum level
+selectable by dmesg is 8.
+
+
+2.4) debug=
+-----------
+
+:Syntax: debug=<device>
+
+This option causes certain kernel messages be printed to the selected
+debugging device. This can aid debugging the kernel, since the
+messages can be captured and analyzed on some other machine. Which
+devices are possible depends on the machine type. There are no checks
+for the validity of the device name. If the device isn't implemented,
+nothing happens.
+
+Messages logged this way are in general stack dumps after kernel
+memory faults or bad kernel traps, and kernel panics. To be exact: all
+messages of level 0 (panic messages) and all messages printed while
+the log level is 8 or more (their level doesn't matter). Before stack
+dumps, the kernel sets the log level to 10 automatically. A level of
+at least 8 can also be set by the "debug" command line option (see
+2.3) and at run time with "dmesg -n 8".
+
+Devices possible for Amiga:
+
+ - "ser":
+         built-in serial port; parameters: 9600bps, 8N1
+ - "mem":
+         Save the messages to a reserved area in chip mem. After
+          rebooting, they can be read under AmigaOS with the tool
+          'dmesg'.
+
+Devices possible for Atari:
+
+ - "ser1":
+          ST-MFP serial port ("Modem1"); parameters: 9600bps, 8N1
+ - "ser2":
+          SCC channel B serial port ("Modem2"); parameters: 9600bps, 8N1
+ - "ser" :
+          default serial port
+           This is "ser2" for a Falcon, and "ser1" for any other machine
+ - "midi":
+          The MIDI port; parameters: 31250bps, 8N1
+ - "par" :
+          parallel port
+
+           The printing routine for this implements a timeout for the
+           case there's no printer connected (else the kernel would
+           lock up). The timeout is not exact, but usually a few
+           seconds.
+
+
+2.6) ramdisk_size=
+------------------
+
+:Syntax: ramdisk_size=<size>
+
+This option instructs the kernel to set up a ramdisk of the given
+size in KBytes. Do not use this option if the ramdisk contents are
+passed by bootstrap! In this case, the size is selected automatically
+and should not be overwritten.
+
+The only application is for root filesystems on floppy disks, that
+should be loaded into memory. To do that, select the corresponding
+size of the disk as ramdisk size, and set the root device to the disk
+drive (with "root=").
+
+
+2.7) swap=
+
+  I can't find any sign of this option in 2.2.6.
+
+2.8) buff=
+-----------
+
+  I can't find any sign of this option in 2.2.6.
+
+
+3) General Device Options (Amiga and Atari)
+===========================================
+
+3.1) ether=
+-----------
+
+:Syntax: ether=[<irq>[,<base_addr>[,<mem_start>[,<mem_end>]]]],<dev-name>
+
+<dev-name> is the name of a net driver, as specified in
+drivers/net/Space.c in the Linux source. Most prominent are eth0, ...
+eth3, sl0, ... sl3, ppp0, ..., ppp3, dummy, and lo.
+
+The non-ethernet drivers (sl, ppp, dummy, lo) obviously ignore the
+settings by this options. Also, the existing ethernet drivers for
+Linux/m68k (ariadne, a2065, hydra) don't use them because Zorro boards
+are really Plug-'n-Play, so the "ether=" option is useless altogether
+for Linux/m68k.
+
+
+3.2) hd=
+--------
+
+:Syntax: hd=<cylinders>,<heads>,<sectors>
+
+This option sets the disk geometry of an IDE disk. The first hd=
+option is for the first IDE disk, the second for the second one.
+(I.e., you can give this option twice.) In most cases, you won't have
+to use this option, since the kernel can obtain the geometry data
+itself. It exists just for the case that this fails for one of your
+disks.
+
+
+3.3) max_scsi_luns=
+-------------------
+
+:Syntax: max_scsi_luns=<n>
+
+Sets the maximum number of LUNs (logical units) of SCSI devices to
+be scanned. Valid values for <n> are between 1 and 8. Default is 8 if
+"Probe all LUNs on each SCSI device" was selected during the kernel
+configuration, else 1.
+
+
+3.4) st=
+--------
+
+:Syntax: st=<buffer_size>,[<write_thres>,[<max_buffers>]]
+
+Sets several parameters of the SCSI tape driver. <buffer_size> is
+the number of 512-byte buffers reserved for tape operations for each
+device. <write_thres> sets the number of blocks which must be filled
+to start an actual write operation to the tape. Maximum value is the
+total number of buffers. <max_buffer> limits the total number of
+buffers allocated for all tape devices.
+
+
+3.5) dmasound=
+--------------
+
+:Syntax: dmasound=[<buffers>,<buffer-size>[,<catch-radius>]]
+
+This option controls some configurations of the Linux/m68k DMA sound
+driver (Amiga and Atari): <buffers> is the number of buffers you want
+to use (minimum 4, default 4), <buffer-size> is the size of each
+buffer in kilobytes (minimum 4, default 32) and <catch-radius> says
+how much percent of error will be tolerated when setting a frequency
+(maximum 10, default 0). For example with 3% you can play 8000Hz
+AU-Files on the Falcon with its hardware frequency of 8195Hz and thus
+don't need to expand the sound.
+
+
+
+4) Options for Atari Only
+=========================
+
+4.1) video=
+-----------
+
+:Syntax: video=<fbname>:<sub-options...>
+
+The <fbname> parameter specifies the name of the frame buffer,
+eg. most atari users will want to specify `atafb` here. The
+<sub-options> is a comma-separated list of the sub-options listed
+below.
+
+NB:
+    Please notice that this option was renamed from `atavideo` to
+    `video` during the development of the 1.3.x kernels, thus you
+    might need to update your boot-scripts if upgrading to 2.x from
+    an 1.2.x kernel.
+
+NBB:
+    The behavior of video= was changed in 2.1.57 so the recommended
+    option is to specify the name of the frame buffer.
+
+4.1.1) Video Mode
+-----------------
+
+This sub-option may be any of the predefined video modes, as listed
+in atari/atafb.c in the Linux/m68k source tree. The kernel will
+activate the given video mode at boot time and make it the default
+mode, if the hardware allows. Currently defined names are:
+
+ - stlow           : 320x200x4
+ - stmid, default5 : 640x200x2
+ - sthigh, default4: 640x400x1
+ - ttlow           : 320x480x8, TT only
+ - ttmid, default1 : 640x480x4, TT only
+ - tthigh, default2: 1280x960x1, TT only
+ - vga2            : 640x480x1, Falcon only
+ - vga4            : 640x480x2, Falcon only
+ - vga16, default3 : 640x480x4, Falcon only
+ - vga256          : 640x480x8, Falcon only
+ - falh2           : 896x608x1, Falcon only
+ - falh16          : 896x608x4, Falcon only
+
+If no video mode is given on the command line, the kernel tries the
+modes names "default<n>" in turn, until one is possible with the
+hardware in use.
+
+A video mode setting doesn't make sense, if the external driver is
+activated by a "external:" sub-option.
+
+4.1.2) inverse
+--------------
+
+Invert the display. This affects both, text (consoles) and graphics
+(X) display. Usually, the background is chosen to be black. With this
+option, you can make the background white.
+
+4.1.3) font
+-----------
+
+:Syntax: font:<fontname>
+
+Specify the font to use in text modes. Currently you can choose only
+between `VGA8x8`, `VGA8x16` and `PEARL8x8`. `VGA8x8` is default, if the
+vertical size of the display is less than 400 pixel rows. Otherwise, the
+`VGA8x16` font is the default.
+
+4.1.4) `hwscroll_`
+------------------
+
+:Syntax: `hwscroll_<n>`
+
+The number of additional lines of video memory to reserve for
+speeding up the scrolling ("hardware scrolling"). Hardware scrolling
+is possible only if the kernel can set the video base address in steps
+fine enough. This is true for STE, MegaSTE, TT, and Falcon. It is not
+possible with plain STs and graphics cards (The former because the
+base address must be on a 256 byte boundary there, the latter because
+the kernel doesn't know how to set the base address at all.)
+
+By default, <n> is set to the number of visible text lines on the
+display. Thus, the amount of video memory is doubled, compared to no
+hardware scrolling. You can turn off the hardware scrolling altogether
+by setting <n> to 0.
+
+4.1.5) internal:
+----------------
+
+:Syntax: internal:<xres>;<yres>[;<xres_max>;<yres_max>;<offset>]
+
+This option specifies the capabilities of some extended internal video
+hardware, like e.g. OverScan. <xres> and <yres> give the (extended)
+dimensions of the screen.
+
+If your OverScan needs a black border, you have to write the last
+three arguments of the "internal:". <xres_max> is the maximum line
+length the hardware allows, <yres_max> the maximum number of lines.
+<offset> is the offset of the visible part of the screen memory to its
+physical start, in bytes.
+
+Often, extended interval video hardware has to be activated somehow.
+For this, see the "sw_*" options below.
+
+4.1.6) external:
+----------------
+
+:Syntax:
+  external:<xres>;<yres>;<depth>;<org>;<scrmem>[;<scrlen>[;<vgabase>
+  [;<colw>[;<coltype>[;<xres_virtual>]]]]]
+
+.. I had to break this line...
+
+This is probably the most complicated parameter... It specifies that
+you have some external video hardware (a graphics board), and how to
+use it under Linux/m68k. The kernel cannot know more about the hardware
+than you tell it here! The kernel also is unable to set or change any
+video modes, since it doesn't know about any board internal. So, you
+have to switch to that video mode before you start Linux, and cannot
+switch to another mode once Linux has started.
+
+The first 3 parameters of this sub-option should be obvious: <xres>,
+<yres> and <depth> give the dimensions of the screen and the number of
+planes (depth). The depth is the logarithm to base 2 of the number
+of colors possible. (Or, the other way round: The number of colors is
+2^depth).
+
+You have to tell the kernel furthermore how the video memory is
+organized. This is done by a letter as <org> parameter:
+
+ 'n':
+      "normal planes", i.e. one whole plane after another
+ 'i':
+      "interleaved planes", i.e. 16 bit of the first plane, than 16 bit
+      of the next, and so on... This mode is used only with the
+      built-in Atari video modes, I think there is no card that
+      supports this mode.
+ 'p':
+      "packed pixels", i.e. <depth> consecutive bits stand for all
+      planes of one pixel; this is the most common mode for 8 planes
+      (256 colors) on graphic cards
+ 't':
+      "true color" (more or less packed pixels, but without a color
+      lookup table); usually depth is 24
+
+For monochrome modes (i.e., <depth> is 1), the <org> letter has a
+different meaning:
+
+ 'n':
+      normal colors, i.e. 0=white, 1=black
+ 'i':
+      inverted colors, i.e. 0=black, 1=white
+
+The next important information about the video hardware is the base
+address of the video memory. That is given in the <scrmem> parameter,
+as a hexadecimal number with a "0x" prefix. You have to find out this
+address in the documentation of your hardware.
+
+The next parameter, <scrlen>, tells the kernel about the size of the
+video memory. If it's missing, the size is calculated from <xres>,
+<yres>, and <depth>. For now, it is not useful to write a value here.
+It would be used only for hardware scrolling (which isn't possible
+with the external driver, because the kernel cannot set the video base
+address), or for virtual resolutions under X (which the X server
+doesn't support yet). So, it's currently best to leave this field
+empty, either by ending the "external:" after the video address or by
+writing two consecutive semicolons, if you want to give a <vgabase>
+(it is allowed to leave this parameter empty).
+
+The <vgabase> parameter is optional. If it is not given, the kernel
+cannot read or write any color registers of the video hardware, and
+thus you have to set appropriate colors before you start Linux. But if
+your card is somehow VGA compatible, you can tell the kernel the base
+address of the VGA register set, so it can change the color lookup
+table. You have to look up this address in your board's documentation.
+To avoid misunderstandings: <vgabase> is the _base_ address, i.e. a 4k
+aligned address. For read/writing the color registers, the kernel
+uses the addresses vgabase+0x3c7...vgabase+0x3c9. The <vgabase>
+parameter is written in hexadecimal with a "0x" prefix, just as
+<scrmem>.
+
+<colw> is meaningful only if <vgabase> is specified. It tells the
+kernel how wide each of the color register is, i.e. the number of bits
+per single color (red/green/blue). Default is 6, another quite usual
+value is 8.
+
+Also <coltype> is used together with <vgabase>. It tells the kernel
+about the color register model of your gfx board. Currently, the types
+"vga" (which is also the default) and "mv300" (SANG MV300) are
+implemented.
+
+Parameter <xres_virtual> is required for ProMST or ET4000 cards where
+the physical linelength differs from the visible length. With ProMST,
+xres_virtual must be set to 2048. For ET4000, xres_virtual depends on the
+initialisation of the video-card.
+If you're missing a corresponding yres_virtual: the external part is legacy,
+therefore we don't support hardware-dependent functions like hardware-scroll,
+panning or blanking.
+
+4.1.7) eclock:
+--------------
+
+The external pixel clock attached to the Falcon VIDEL shifter. This
+currently works only with the ScreenWonder!
+
+4.1.8) monitorcap:
+-------------------
+
+:Syntax: monitorcap:<vmin>;<vmax>;<hmin>;<hmax>
+
+This describes the capabilities of a multisync monitor. Don't use it
+with a fixed-frequency monitor! For now, only the Falcon frame buffer
+uses the settings of "monitorcap:".
+
+<vmin> and <vmax> are the minimum and maximum, resp., vertical frequencies
+your monitor can work with, in Hz. <hmin> and <hmax> are the same for
+the horizontal frequency, in kHz.
+
+  The defaults are 58;62;31;32 (VGA compatible).
+
+  The defaults for TV/SC1224/SC1435 cover both PAL and NTSC standards.
+
+4.1.9) keep
+------------
+
+If this option is given, the framebuffer device doesn't do any video
+mode calculations and settings on its own. The only Atari fb device
+that does this currently is the Falcon.
+
+What you reach with this: Settings for unknown video extensions
+aren't overridden by the driver, so you can still use the mode found
+when booting, when the driver doesn't know to set this mode itself.
+But this also means, that you can't switch video modes anymore...
+
+An example where you may want to use "keep" is the ScreenBlaster for
+the Falcon.
+
+
+4.2) atamouse=
+--------------
+
+:Syntax: atamouse=<x-threshold>,[<y-threshold>]
+
+With this option, you can set the mouse movement reporting threshold.
+This is the number of pixels of mouse movement that have to accumulate
+before the IKBD sends a new mouse packet to the kernel. Higher values
+reduce the mouse interrupt load and thus reduce the chance of keyboard
+overruns. Lower values give a slightly faster mouse responses and
+slightly better mouse tracking.
+
+You can set the threshold in x and y separately, but usually this is
+of little practical use. If there's just one number in the option, it
+is used for both dimensions. The default value is 2 for both
+thresholds.
+
+
+4.3) ataflop=
+-------------
+
+:Syntax: ataflop=<drive type>[,<trackbuffering>[,<steprateA>[,<steprateB>]]]
+
+   The drive type may be 0, 1, or 2, for DD, HD, and ED, resp. This
+   setting affects how many buffers are reserved and which formats are
+   probed (see also below). The default is 1 (HD). Only one drive type
+   can be selected. If you have two disk drives, select the "better"
+   type.
+
+   The second parameter <trackbuffer> tells the kernel whether to use
+   track buffering (1) or not (0). The default is machine-dependent:
+   no for the Medusa and yes for all others.
+
+   With the two following parameters, you can change the default
+   steprate used for drive A and B, resp.
+
+
+4.4) atascsi=
+-------------
+
+:Syntax: atascsi=<can_queue>[,<cmd_per_lun>[,<scat-gat>[,<host-id>[,<tagged>]]]]
+
+This option sets some parameters for the Atari native SCSI driver.
+Generally, any number of arguments can be omitted from the end. And
+for each of the numbers, a negative value means "use default". The
+defaults depend on whether TT-style or Falcon-style SCSI is used.
+Below, defaults are noted as n/m, where the first value refers to
+TT-SCSI and the latter to Falcon-SCSI. If an illegal value is given
+for one parameter, an error message is printed and that one setting is
+ignored (others aren't affected).
+
+  <can_queue>:
+    This is the maximum number of SCSI commands queued internally to the
+    Atari SCSI driver. A value of 1 effectively turns off the driver
+    internal multitasking (if it causes problems). Legal values are >=
+    1. <can_queue> can be as high as you like, but values greater than
+    <cmd_per_lun> times the number of SCSI targets (LUNs) you have
+    don't make sense. Default: 16/8.
+
+  <cmd_per_lun>:
+    Maximum number of SCSI commands issued to the driver for one
+    logical unit (LUN, usually one SCSI target). Legal values start
+    from 1. If tagged queuing (see below) is not used, values greater
+    than 2 don't make sense, but waste memory. Otherwise, the maximum
+    is the number of command tags available to the driver (currently
+    32). Default: 8/1. (Note: Values > 1 seem to cause problems on a
+    Falcon, cause not yet known.)
+
+    The <cmd_per_lun> value at a great part determines the amount of
+    memory SCSI reserves for itself. The formula is rather
+    complicated, but I can give you some hints:
+
+      no scatter-gather:
+       cmd_per_lun * 232 bytes
+      full scatter-gather:
+       cmd_per_lun * approx. 17 Kbytes
+
+  <scat-gat>:
+    Size of the scatter-gather table, i.e. the number of requests
+    consecutive on the disk that can be merged into one SCSI command.
+    Legal values are between 0 and 255. Default: 255/0. Note: This
+    value is forced to 0 on a Falcon, since scatter-gather isn't
+    possible with the ST-DMA. Not using scatter-gather hurts
+    performance significantly.
+
+  <host-id>:
+    The SCSI ID to be used by the initiator (your Atari). This is
+    usually 7, the highest possible ID. Every ID on the SCSI bus must
+    be unique. Default: determined at run time: If the NV-RAM checksum
+    is valid, and bit 7 in byte 30 of the NV-RAM is set, the lower 3
+    bits of this byte are used as the host ID. (This method is defined
+    by Atari and also used by some TOS HD drivers.) If the above
+    isn't given, the default ID is 7. (both, TT and Falcon).
+
+  <tagged>:
+    0 means turn off tagged queuing support, all other values > 0 mean
+    use tagged queuing for targets that support it. Default: currently
+    off, but this may change when tagged queuing handling has been
+    proved to be reliable.
+
+    Tagged queuing means that more than one command can be issued to
+    one LUN, and the SCSI device itself orders the requests so they
+    can be performed in optimal order. Not all SCSI devices support
+    tagged queuing (:-().
+
+4.5 switches=
+-------------
+
+:Syntax: switches=<list of switches>
+
+With this option you can switch some hardware lines that are often
+used to enable/disable certain hardware extensions. Examples are
+OverScan, overclocking, ...
+
+The <list of switches> is a comma-separated list of the following
+items:
+
+  ikbd:
+       set RTS of the keyboard ACIA high
+  midi:
+       set RTS of the MIDI ACIA high
+  snd6:
+       set bit 6 of the PSG port A
+  snd7:
+       set bit 6 of the PSG port A
+
+It doesn't make sense to mention a switch more than once (no
+difference to only once), but you can give as many switches as you
+want to enable different features. The switch lines are set as early
+as possible during kernel initialization (even before determining the
+present hardware.)
+
+All of the items can also be prefixed with `ov_`, i.e. `ov_ikbd`,
+`ov_midi`, ... These options are meant for switching on an OverScan
+video extension. The difference to the bare option is that the
+switch-on is done after video initialization, and somehow synchronized
+to the HBLANK. A speciality is that ov_ikbd and ov_midi are switched
+off before rebooting, so that OverScan is disabled and TOS boots
+correctly.
+
+If you give an option both, with and without the `ov_` prefix, the
+earlier initialization (`ov_`-less) takes precedence. But the
+switching-off on reset still happens in this case.
+
+5) Options for Amiga Only:
+==========================
+
+5.1) video=
+-----------
+
+:Syntax: video=<fbname>:<sub-options...>
+
+The <fbname> parameter specifies the name of the frame buffer, valid
+options are `amifb`, `cyber`, 'virge', `retz3` and `clgen`, provided
+that the respective frame buffer devices have been compiled into the
+kernel (or compiled as loadable modules). The behavior of the <fbname>
+option was changed in 2.1.57 so it is now recommended to specify this
+option.
+
+The <sub-options> is a comma-separated list of the sub-options listed
+below. This option is organized similar to the Atari version of the
+"video"-option (4.1), but knows fewer sub-options.
+
+5.1.1) video mode
+-----------------
+
+Again, similar to the video mode for the Atari (see 4.1.1). Predefined
+modes depend on the used frame buffer device.
+
+OCS, ECS and AGA machines all use the color frame buffer. The following
+predefined video modes are available:
+
+NTSC modes:
+ - ntsc            : 640x200, 15 kHz, 60 Hz
+ - ntsc-lace       : 640x400, 15 kHz, 60 Hz interlaced
+
+PAL modes:
+ - pal             : 640x256, 15 kHz, 50 Hz
+ - pal-lace        : 640x512, 15 kHz, 50 Hz interlaced
+
+ECS modes:
+ - multiscan       : 640x480, 29 kHz, 57 Hz
+ - multiscan-lace  : 640x960, 29 kHz, 57 Hz interlaced
+ - euro36          : 640x200, 15 kHz, 72 Hz
+ - euro36-lace     : 640x400, 15 kHz, 72 Hz interlaced
+ - euro72          : 640x400, 29 kHz, 68 Hz
+ - euro72-lace     : 640x800, 29 kHz, 68 Hz interlaced
+ - super72         : 800x300, 23 kHz, 70 Hz
+ - super72-lace    : 800x600, 23 kHz, 70 Hz interlaced
+ - dblntsc-ff      : 640x400, 27 kHz, 57 Hz
+ - dblntsc-lace    : 640x800, 27 kHz, 57 Hz interlaced
+ - dblpal-ff       : 640x512, 27 kHz, 47 Hz
+ - dblpal-lace     : 640x1024, 27 kHz, 47 Hz interlaced
+ - dblntsc         : 640x200, 27 kHz, 57 Hz doublescan
+ - dblpal          : 640x256, 27 kHz, 47 Hz doublescan
+
+VGA modes:
+ - vga             : 640x480, 31 kHz, 60 Hz
+ - vga70           : 640x400, 31 kHz, 70 Hz
+
+Please notice that the ECS and VGA modes require either an ECS or AGA
+chipset, and that these modes are limited to 2-bit color for the ECS
+chipset and 8-bit color for the AGA chipset.
+
+5.1.2) depth
+------------
+
+:Syntax: depth:<nr. of bit-planes>
+
+Specify the number of bit-planes for the selected video-mode.
+
+5.1.3) inverse
+--------------
+
+Use inverted display (black on white). Functionally the same as the
+"inverse" sub-option for the Atari.
+
+5.1.4) font
+-----------
+
+:Syntax: font:<fontname>
+
+Specify the font to use in text modes. Functionally the same as the
+"font" sub-option for the Atari, except that `PEARL8x8` is used instead
+of `VGA8x8` if the vertical size of the display is less than 400 pixel
+rows.
+
+5.1.5) monitorcap:
+-------------------
+
+:Syntax: monitorcap:<vmin>;<vmax>;<hmin>;<hmax>
+
+This describes the capabilities of a multisync monitor. For now, only
+the color frame buffer uses the settings of "monitorcap:".
+
+<vmin> and <vmax> are the minimum and maximum, resp., vertical frequencies
+your monitor can work with, in Hz. <hmin> and <hmax> are the same for
+the horizontal frequency, in kHz.
+
+The defaults are 50;90;15;38 (Generic Amiga multisync monitor).
+
+
+5.2) fd_def_df0=
+----------------
+
+:Syntax: fd_def_df0=<value>
+
+Sets the df0 value for "silent" floppy drives. The value should be in
+hexadecimal with "0x" prefix.
+
+
+5.3) wd33c93=
+-------------
+
+:Syntax: wd33c93=<sub-options...>
+
+These options affect the A590/A2091, A3000 and GVP Series II SCSI
+controllers.
+
+The <sub-options> is a comma-separated list of the sub-options listed
+below.
+
+5.3.1) nosync
+-------------
+
+:Syntax: nosync:bitmask
+
+bitmask is a byte where the 1st 7 bits correspond with the 7
+possible SCSI devices. Set a bit to prevent sync negotiation on that
+device. To maintain backwards compatibility, a command-line such as
+"wd33c93=255" will be automatically translated to
+"wd33c93=nosync:0xff". The default is to disable sync negotiation for
+all devices, eg. nosync:0xff.
+
+5.3.2) period
+-------------
+
+:Syntax: period:ns
+
+`ns` is the minimum # of nanoseconds in a SCSI data transfer
+period. Default is 500; acceptable values are 250 - 1000.
+
+5.3.3) disconnect
+-----------------
+
+:Syntax: disconnect:x
+
+Specify x = 0 to never allow disconnects, 2 to always allow them.
+x = 1 does 'adaptive' disconnects, which is the default and generally
+the best choice.
+
+5.3.4) debug
+------------
+
+:Syntax: debug:x
+
+If `DEBUGGING_ON` is defined, x is a bit mask that causes various
+types of debug output to printed - see the DB_xxx defines in
+wd33c93.h.
+
+5.3.5) clock
+------------
+
+:Syntax: clock:x
+
+x = clock input in MHz for WD33c93 chip. Normal values would be from
+8 through 20. The default value depends on your hostadapter(s),
+default for the A3000 internal controller is 14, for the A2091 it's 8
+and for the GVP hostadapters it's either 8 or 14, depending on the
+hostadapter and the SCSI-clock jumper present on some GVP
+hostadapters.
+
+5.3.6) next
+-----------
+
+No argument. Used to separate blocks of keywords when there's more
+than one wd33c93-based host adapter in the system.
+
+5.3.7) nodma
+------------
+
+:Syntax: nodma:x
+
+If x is 1 (or if the option is just written as "nodma"), the WD33c93
+controller will not use DMA (= direct memory access) to access the
+Amiga's memory.  This is useful for some systems (like A3000's and
+A4000's with the A3640 accelerator, revision 3.0) that have problems
+using DMA to chip memory.  The default is 0, i.e. to use DMA if
+possible.
+
+
+5.4) gvp11=
+-----------
+
+:Syntax: gvp11=<addr-mask>
+
+The earlier versions of the GVP driver did not handle DMA
+address-mask settings correctly which made it necessary for some
+people to use this option, in order to get their GVP controller
+running under Linux. These problems have hopefully been solved and the
+use of this option is now highly unrecommended!
+
+Incorrect use can lead to unpredictable behavior, so please only use
+this option if you *know* what you are doing and have a reason to do
+so. In any case if you experience problems and need to use this
+option, please inform us about it by mailing to the Linux/68k kernel
+mailing list.
+
+The address mask set by this option specifies which addresses are
+valid for DMA with the GVP Series II SCSI controller. An address is
+valid, if no bits are set except the bits that are set in the mask,
+too.
+
+Some versions of the GVP can only DMA into a 24 bit address range,
+some can address a 25 bit address range while others can use the whole
+32 bit address range for DMA. The correct setting depends on your
+controller and should be autodetected by the driver. An example is the
+24 bit region which is specified by a mask of 0x00fffffe.
diff --git a/Documentation/m68k/kernel-options.txt b/Documentation/m68k/kernel-options.txt
deleted file mode 100644 (file)
index 79d2124..0000000
+++ /dev/null
@@ -1,884 +0,0 @@
-
-
-                                 Command Line Options for Linux/m68k
-                                 ===================================
-
-Last Update: 2 May 1999
-Linux/m68k version: 2.2.6
-Author: Roman.Hodek@informatik.uni-erlangen.de (Roman Hodek)
-Update: jds@kom.auc.dk (Jes Sorensen) and faq@linux-m68k.org (Chris Lawrence)
-
-0) Introduction
-===============
-
-  Often I've been asked which command line options the Linux/m68k
-kernel understands, or how the exact syntax for the ... option is, or
-... about the option ... . I hope, this document supplies all the
-answers...
-
-  Note that some options might be outdated, their descriptions being
-incomplete or missing. Please update the information and send in the
-patches.
-
-
-1) Overview of the Kernel's Option Processing
-=============================================
-
-The kernel knows three kinds of options on its command line:
-
-  1) kernel options
-  2) environment settings
-  3) arguments for init
-
-To which of these classes an argument belongs is determined as
-follows: If the option is known to the kernel itself, i.e. if the name
-(the part before the '=') or, in some cases, the whole argument string
-is known to the kernel, it belongs to class 1. Otherwise, if the
-argument contains an '=', it is of class 2, and the definition is put
-into init's environment. All other arguments are passed to init as
-command line options.
-
-  This document describes the valid kernel options for Linux/m68k in
-the version mentioned at the start of this file. Later revisions may
-add new such options, and some may be missing in older versions.
-
-  In general, the value (the part after the '=') of an option is a
-list of values separated by commas. The interpretation of these values
-is up to the driver that "owns" the option. This association of
-options with drivers is also the reason that some are further
-subdivided.
-
-
-2) General Kernel Options
-=========================
-
-2.1) root=
-----------
-
-Syntax: root=/dev/<device>
-    or: root=<hex_number>
-
-This tells the kernel which device it should mount as the root
-filesystem. The device must be a block device with a valid filesystem
-on it.
-
-  The first syntax gives the device by name. These names are converted
-into a major/minor number internally in the kernel in an unusual way.
-Normally, this "conversion" is done by the device files in /dev, but
-this isn't possible here, because the root filesystem (with /dev)
-isn't mounted yet... So the kernel parses the name itself, with some
-hardcoded name to number mappings. The name must always be a
-combination of two or three letters, followed by a decimal number.
-Valid names are:
-
-  /dev/ram: -> 0x0100 (initial ramdisk)
-  /dev/hda: -> 0x0300 (first IDE disk)
-  /dev/hdb: -> 0x0340 (second IDE disk)
-  /dev/sda: -> 0x0800 (first SCSI disk)
-  /dev/sdb: -> 0x0810 (second SCSI disk)
-  /dev/sdc: -> 0x0820 (third SCSI disk)
-  /dev/sdd: -> 0x0830 (forth SCSI disk)
-  /dev/sde: -> 0x0840 (fifth SCSI disk)
-  /dev/fd : -> 0x0200 (floppy disk)
-
-  The name must be followed by a decimal number, that stands for the
-partition number. Internally, the value of the number is just
-added to the device number mentioned in the table above. The
-exceptions are /dev/ram and /dev/fd, where /dev/ram refers to an
-initial ramdisk loaded by your bootstrap program (please consult the
-instructions for your bootstrap program to find out how to load an
-initial ramdisk). As of kernel version 2.0.18 you must specify
-/dev/ram as the root device if you want to boot from an initial
-ramdisk. For the floppy devices, /dev/fd, the number stands for the
-floppy drive number (there are no partitions on floppy disks). I.e.,
-/dev/fd0 stands for the first drive, /dev/fd1 for the second, and so
-on. Since the number is just added, you can also force the disk format
-by adding a number greater than 3. If you look into your /dev
-directory, use can see the /dev/fd0D720 has major 2 and minor 16. You
-can specify this device for the root FS by writing "root=/dev/fd16" on
-the kernel command line.
-
-[Strange and maybe uninteresting stuff ON]
-
-  This unusual translation of device names has some strange
-consequences: If, for example, you have a symbolic link from /dev/fd
-to /dev/fd0D720 as an abbreviation for floppy driver #0 in DD format,
-you cannot use this name for specifying the root device, because the
-kernel cannot see this symlink before mounting the root FS and it
-isn't in the table above. If you use it, the root device will not be 
-set at all, without an error message. Another example: You cannot use a
-partition on e.g. the sixth SCSI disk as the root filesystem, if you
-want to specify it by name. This is, because only the devices up to
-/dev/sde are in the table above, but not /dev/sdf. Although, you can
-use the sixth SCSI disk for the root FS, but you have to specify the
-device by number... (see below). Or, even more strange, you can use the
-fact that there is no range checking of the partition number, and your
-knowledge that each disk uses 16 minors, and write "root=/dev/sde17"
-(for /dev/sdf1).
-
-[Strange and maybe uninteresting stuff OFF]
-
-  If the device containing your root partition isn't in the table
-above, you can also specify it by major and minor numbers. These are
-written in hex, with no prefix and no separator between. E.g., if you
-have a CD with contents appropriate as a root filesystem in the first
-SCSI CD-ROM drive, you boot from it by "root=0b00". Here, hex "0b" =
-decimal 11 is the major of SCSI CD-ROMs, and the minor 0 stands for
-the first of these. You can find out all valid major numbers by
-looking into include/linux/major.h.
-
-In addition to major and minor numbers, if the device containing your
-root partition uses a partition table format with unique partition
-identifiers, then you may use them.  For instance,
-"root=PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF".  It is also
-possible to reference another partition on the same device using a
-known partition UUID as the starting point.  For example,
-if partition 5 of the device has the UUID of
-00112233-4455-6677-8899-AABBCCDDEEFF then partition 3 may be found as
-follows:
-  PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF/PARTNROFF=-2
-
-Authoritative information can be found in
-"Documentation/admin-guide/kernel-parameters.rst".
-
-
-2.2) ro, rw
------------
-
-Syntax: ro
-    or: rw
-
-These two options tell the kernel whether it should mount the root
-filesystem read-only or read-write. The default is read-only, except
-for ramdisks, which default to read-write.
-
-
-2.3) debug
-----------
-
-Syntax: debug
-
-This raises the kernel log level to 10 (the default is 7). This is the
-same level as set by the "dmesg" command, just that the maximum level
-selectable by dmesg is 8.
-
-
-2.4) debug=
------------
-
-Syntax: debug=<device>
-
-This option causes certain kernel messages be printed to the selected
-debugging device. This can aid debugging the kernel, since the
-messages can be captured and analyzed on some other machine. Which
-devices are possible depends on the machine type. There are no checks
-for the validity of the device name. If the device isn't implemented,
-nothing happens.
-
-  Messages logged this way are in general stack dumps after kernel
-memory faults or bad kernel traps, and kernel panics. To be exact: all
-messages of level 0 (panic messages) and all messages printed while
-the log level is 8 or more (their level doesn't matter). Before stack
-dumps, the kernel sets the log level to 10 automatically. A level of
-at least 8 can also be set by the "debug" command line option (see
-2.3) and at run time with "dmesg -n 8".
-
-Devices possible for Amiga:
-
- - "ser": built-in serial port; parameters: 9600bps, 8N1
- - "mem": Save the messages to a reserved area in chip mem. After
-          rebooting, they can be read under AmigaOS with the tool
-          'dmesg'.
-
-Devices possible for Atari:
-
- - "ser1": ST-MFP serial port ("Modem1"); parameters: 9600bps, 8N1
- - "ser2": SCC channel B serial port ("Modem2"); parameters: 9600bps, 8N1
- - "ser" : default serial port
-           This is "ser2" for a Falcon, and "ser1" for any other machine
- - "midi": The MIDI port; parameters: 31250bps, 8N1
- - "par" : parallel port
-           The printing routine for this implements a timeout for the
-           case there's no printer connected (else the kernel would
-           lock up). The timeout is not exact, but usually a few
-           seconds.
-
-
-2.6) ramdisk_size=
--------------
-
-Syntax: ramdisk_size=<size>
-
-  This option instructs the kernel to set up a ramdisk of the given
-size in KBytes. Do not use this option if the ramdisk contents are
-passed by bootstrap! In this case, the size is selected automatically
-and should not be overwritten.
-
-  The only application is for root filesystems on floppy disks, that
-should be loaded into memory. To do that, select the corresponding
-size of the disk as ramdisk size, and set the root device to the disk
-drive (with "root=").
-
-
-2.7) swap=
-2.8) buff=
------------
-
-  I can't find any sign of these options in 2.2.6.
-
-
-3) General Device Options (Amiga and Atari)
-===========================================
-
-3.1) ether=
------------
-
-Syntax: ether=[<irq>[,<base_addr>[,<mem_start>[,<mem_end>]]]],<dev-name>
-
-  <dev-name> is the name of a net driver, as specified in
-drivers/net/Space.c in the Linux source. Most prominent are eth0, ...
-eth3, sl0, ... sl3, ppp0, ..., ppp3, dummy, and lo.
-
-  The non-ethernet drivers (sl, ppp, dummy, lo) obviously ignore the
-settings by this options. Also, the existing ethernet drivers for
-Linux/m68k (ariadne, a2065, hydra) don't use them because Zorro boards
-are really Plug-'n-Play, so the "ether=" option is useless altogether
-for Linux/m68k.
-
-
-3.2) hd=
---------
-
-Syntax: hd=<cylinders>,<heads>,<sectors>
-
-  This option sets the disk geometry of an IDE disk. The first hd=
-option is for the first IDE disk, the second for the second one.
-(I.e., you can give this option twice.) In most cases, you won't have
-to use this option, since the kernel can obtain the geometry data
-itself. It exists just for the case that this fails for one of your
-disks.
-
-
-3.3) max_scsi_luns=
--------------------
-
-Syntax: max_scsi_luns=<n>
-
-  Sets the maximum number of LUNs (logical units) of SCSI devices to
-be scanned. Valid values for <n> are between 1 and 8. Default is 8 if
-"Probe all LUNs on each SCSI device" was selected during the kernel
-configuration, else 1.
-
-
-3.4) st=
---------
-
-Syntax: st=<buffer_size>,[<write_thres>,[<max_buffers>]]
-
-  Sets several parameters of the SCSI tape driver. <buffer_size> is
-the number of 512-byte buffers reserved for tape operations for each
-device. <write_thres> sets the number of blocks which must be filled
-to start an actual write operation to the tape. Maximum value is the
-total number of buffers. <max_buffer> limits the total number of
-buffers allocated for all tape devices.
-
-
-3.5) dmasound=
---------------
-
-Syntax: dmasound=[<buffers>,<buffer-size>[,<catch-radius>]]
-
-  This option controls some configurations of the Linux/m68k DMA sound
-driver (Amiga and Atari): <buffers> is the number of buffers you want
-to use (minimum 4, default 4), <buffer-size> is the size of each
-buffer in kilobytes (minimum 4, default 32) and <catch-radius> says
-how much percent of error will be tolerated when setting a frequency
-(maximum 10, default 0). For example with 3% you can play 8000Hz
-AU-Files on the Falcon with its hardware frequency of 8195Hz and thus
-don't need to expand the sound.
-
-
-
-4) Options for Atari Only
-=========================
-
-4.1) video=
------------
-
-Syntax: video=<fbname>:<sub-options...>
-
-The <fbname> parameter specifies the name of the frame buffer,
-eg. most atari users will want to specify `atafb' here. The
-<sub-options> is a comma-separated list of the sub-options listed
-below.
-
-NB: Please notice that this option was renamed from `atavideo' to
-    `video' during the development of the 1.3.x kernels, thus you
-    might need to update your boot-scripts if upgrading to 2.x from
-    an 1.2.x kernel.
-
-NBB: The behavior of video= was changed in 2.1.57 so the recommended
-option is to specify the name of the frame buffer.
-
-4.1.1) Video Mode
------------------
-
-This sub-option may be any of the predefined video modes, as listed
-in atari/atafb.c in the Linux/m68k source tree. The kernel will
-activate the given video mode at boot time and make it the default
-mode, if the hardware allows. Currently defined names are:
-
- - stlow           : 320x200x4
- - stmid, default5 : 640x200x2
- - sthigh, default4: 640x400x1
- - ttlow           : 320x480x8, TT only
- - ttmid, default1 : 640x480x4, TT only
- - tthigh, default2: 1280x960x1, TT only
- - vga2            : 640x480x1, Falcon only
- - vga4            : 640x480x2, Falcon only
- - vga16, default3 : 640x480x4, Falcon only
- - vga256          : 640x480x8, Falcon only
- - falh2           : 896x608x1, Falcon only
- - falh16          : 896x608x4, Falcon only
-
-  If no video mode is given on the command line, the kernel tries the
-modes names "default<n>" in turn, until one is possible with the
-hardware in use.
-
-  A video mode setting doesn't make sense, if the external driver is
-activated by a "external:" sub-option.
-
-4.1.2) inverse
---------------
-
-Invert the display. This affects both, text (consoles) and graphics
-(X) display. Usually, the background is chosen to be black. With this
-option, you can make the background white.
-
-4.1.3) font
------------
-
-Syntax: font:<fontname>
-
-Specify the font to use in text modes. Currently you can choose only
-between `VGA8x8', `VGA8x16' and `PEARL8x8'. `VGA8x8' is default, if the
-vertical size of the display is less than 400 pixel rows. Otherwise, the
-`VGA8x16' font is the default.
-
-4.1.4) hwscroll_
-----------------
-
-Syntax: hwscroll_<n>
-
-The number of additional lines of video memory to reserve for
-speeding up the scrolling ("hardware scrolling"). Hardware scrolling
-is possible only if the kernel can set the video base address in steps
-fine enough. This is true for STE, MegaSTE, TT, and Falcon. It is not
-possible with plain STs and graphics cards (The former because the
-base address must be on a 256 byte boundary there, the latter because
-the kernel doesn't know how to set the base address at all.)
-
-  By default, <n> is set to the number of visible text lines on the
-display. Thus, the amount of video memory is doubled, compared to no
-hardware scrolling. You can turn off the hardware scrolling altogether
-by setting <n> to 0.
-
-4.1.5) internal:
-----------------
-
-Syntax: internal:<xres>;<yres>[;<xres_max>;<yres_max>;<offset>]
-
-This option specifies the capabilities of some extended internal video
-hardware, like e.g. OverScan. <xres> and <yres> give the (extended)
-dimensions of the screen.
-
-  If your OverScan needs a black border, you have to write the last
-three arguments of the "internal:". <xres_max> is the maximum line
-length the hardware allows, <yres_max> the maximum number of lines.
-<offset> is the offset of the visible part of the screen memory to its
-physical start, in bytes.
-
-  Often, extended interval video hardware has to be activated somehow.
-For this, see the "sw_*" options below.
-
-4.1.6) external:
-----------------
-
-Syntax:
-  external:<xres>;<yres>;<depth>;<org>;<scrmem>[;<scrlen>[;<vgabase>\
-           [;<colw>[;<coltype>[;<xres_virtual>]]]]]
-
-[I had to break this line...]
-
-  This is probably the most complicated parameter... It specifies that
-you have some external video hardware (a graphics board), and how to
-use it under Linux/m68k. The kernel cannot know more about the hardware
-than you tell it here! The kernel also is unable to set or change any
-video modes, since it doesn't know about any board internal. So, you
-have to switch to that video mode before you start Linux, and cannot
-switch to another mode once Linux has started.
-
-  The first 3 parameters of this sub-option should be obvious: <xres>,
-<yres> and <depth> give the dimensions of the screen and the number of
-planes (depth). The depth is the logarithm to base 2 of the number
-of colors possible. (Or, the other way round: The number of colors is
-2^depth).
-
-  You have to tell the kernel furthermore how the video memory is
-organized. This is done by a letter as <org> parameter:
-
- 'n': "normal planes", i.e. one whole plane after another
- 'i': "interleaved planes", i.e. 16 bit of the first plane, than 16 bit
-      of the next, and so on... This mode is used only with the
-         built-in Atari video modes, I think there is no card that
-         supports this mode.
- 'p': "packed pixels", i.e. <depth> consecutive bits stand for all
-         planes of one pixel; this is the most common mode for 8 planes
-         (256 colors) on graphic cards
- 't': "true color" (more or less packed pixels, but without a color
-         lookup table); usually depth is 24
-
-For monochrome modes (i.e., <depth> is 1), the <org> letter has a
-different meaning:
-
- 'n': normal colors, i.e. 0=white, 1=black
- 'i': inverted colors, i.e. 0=black, 1=white
-
-  The next important information about the video hardware is the base
-address of the video memory. That is given in the <scrmem> parameter,
-as a hexadecimal number with a "0x" prefix. You have to find out this
-address in the documentation of your hardware.
-
-  The next parameter, <scrlen>, tells the kernel about the size of the
-video memory. If it's missing, the size is calculated from <xres>,
-<yres>, and <depth>. For now, it is not useful to write a value here.
-It would be used only for hardware scrolling (which isn't possible
-with the external driver, because the kernel cannot set the video base
-address), or for virtual resolutions under X (which the X server
-doesn't support yet). So, it's currently best to leave this field
-empty, either by ending the "external:" after the video address or by
-writing two consecutive semicolons, if you want to give a <vgabase>
-(it is allowed to leave this parameter empty).
-
-  The <vgabase> parameter is optional. If it is not given, the kernel
-cannot read or write any color registers of the video hardware, and
-thus you have to set appropriate colors before you start Linux. But if
-your card is somehow VGA compatible, you can tell the kernel the base
-address of the VGA register set, so it can change the color lookup
-table. You have to look up this address in your board's documentation.
-To avoid misunderstandings: <vgabase> is the _base_ address, i.e. a 4k
-aligned address. For read/writing the color registers, the kernel
-uses the addresses vgabase+0x3c7...vgabase+0x3c9. The <vgabase>
-parameter is written in hexadecimal with a "0x" prefix, just as
-<scrmem>.
-
-  <colw> is meaningful only if <vgabase> is specified. It tells the
-kernel how wide each of the color register is, i.e. the number of bits
-per single color (red/green/blue). Default is 6, another quite usual
-value is 8.
-
-  Also <coltype> is used together with <vgabase>. It tells the kernel
-about the color register model of your gfx board. Currently, the types
-"vga" (which is also the default) and "mv300" (SANG MV300) are
-implemented.
-
-  Parameter <xres_virtual> is required for ProMST or ET4000 cards where
-the physical linelength differs from the visible length. With ProMST, 
-xres_virtual must be set to 2048. For ET4000, xres_virtual depends on the
-initialisation of the video-card.
-If you're missing a corresponding yres_virtual: the external part is legacy,
-therefore we don't support hardware-dependent functions like hardware-scroll,
-panning or blanking.
-
-4.1.7) eclock:
---------------
-
-The external pixel clock attached to the Falcon VIDEL shifter. This
-currently works only with the ScreenWonder!
-
-4.1.8) monitorcap:
--------------------
-
-Syntax: monitorcap:<vmin>;<vmax>;<hmin>;<hmax>
-
-This describes the capabilities of a multisync monitor. Don't use it
-with a fixed-frequency monitor! For now, only the Falcon frame buffer
-uses the settings of "monitorcap:".
-
-  <vmin> and <vmax> are the minimum and maximum, resp., vertical frequencies
-your monitor can work with, in Hz. <hmin> and <hmax> are the same for
-the horizontal frequency, in kHz.
-
-  The defaults are 58;62;31;32 (VGA compatible).
-
-  The defaults for TV/SC1224/SC1435 cover both PAL and NTSC standards.
-
-4.1.9) keep
-------------
-
-If this option is given, the framebuffer device doesn't do any video
-mode calculations and settings on its own. The only Atari fb device
-that does this currently is the Falcon.
-
-  What you reach with this: Settings for unknown video extensions
-aren't overridden by the driver, so you can still use the mode found
-when booting, when the driver doesn't know to set this mode itself.
-But this also means, that you can't switch video modes anymore...
-
-  An example where you may want to use "keep" is the ScreenBlaster for
-the Falcon.
-
-
-4.2) atamouse=
---------------
-
-Syntax: atamouse=<x-threshold>,[<y-threshold>]
-
-  With this option, you can set the mouse movement reporting threshold.
-This is the number of pixels of mouse movement that have to accumulate
-before the IKBD sends a new mouse packet to the kernel. Higher values
-reduce the mouse interrupt load and thus reduce the chance of keyboard
-overruns. Lower values give a slightly faster mouse responses and
-slightly better mouse tracking.
-
-  You can set the threshold in x and y separately, but usually this is
-of little practical use. If there's just one number in the option, it
-is used for both dimensions. The default value is 2 for both
-thresholds.
-
-
-4.3) ataflop=
--------------
-
-Syntax: ataflop=<drive type>[,<trackbuffering>[,<steprateA>[,<steprateB>]]]
-
-   The drive type may be 0, 1, or 2, for DD, HD, and ED, resp. This
-   setting affects how many buffers are reserved and which formats are
-   probed (see also below). The default is 1 (HD). Only one drive type
-   can be selected. If you have two disk drives, select the "better"
-   type.
-
-   The second parameter <trackbuffer> tells the kernel whether to use
-   track buffering (1) or not (0). The default is machine-dependent:
-   no for the Medusa and yes for all others.
-
-   With the two following parameters, you can change the default
-   steprate used for drive A and B, resp. 
-
-
-4.4) atascsi=
--------------
-
-Syntax: atascsi=<can_queue>[,<cmd_per_lun>[,<scat-gat>[,<host-id>[,<tagged>]]]]
-
-  This option sets some parameters for the Atari native SCSI driver.
-Generally, any number of arguments can be omitted from the end. And
-for each of the numbers, a negative value means "use default". The
-defaults depend on whether TT-style or Falcon-style SCSI is used.
-Below, defaults are noted as n/m, where the first value refers to
-TT-SCSI and the latter to Falcon-SCSI. If an illegal value is given
-for one parameter, an error message is printed and that one setting is
-ignored (others aren't affected).
-
-  <can_queue>:
-    This is the maximum number of SCSI commands queued internally to the
-    Atari SCSI driver. A value of 1 effectively turns off the driver
-    internal multitasking (if it causes problems). Legal values are >=
-    1. <can_queue> can be as high as you like, but values greater than
-    <cmd_per_lun> times the number of SCSI targets (LUNs) you have
-    don't make sense. Default: 16/8.
-
-  <cmd_per_lun>:
-    Maximum number of SCSI commands issued to the driver for one
-    logical unit (LUN, usually one SCSI target). Legal values start
-    from 1. If tagged queuing (see below) is not used, values greater
-    than 2 don't make sense, but waste memory. Otherwise, the maximum
-    is the number of command tags available to the driver (currently
-    32). Default: 8/1. (Note: Values > 1 seem to cause problems on a
-    Falcon, cause not yet known.)
-
-      The <cmd_per_lun> value at a great part determines the amount of
-    memory SCSI reserves for itself. The formula is rather
-    complicated, but I can give you some hints:
-      no scatter-gather  : cmd_per_lun * 232 bytes
-      full scatter-gather: cmd_per_lun * approx. 17 Kbytes
-
-  <scat-gat>:
-    Size of the scatter-gather table, i.e. the number of requests
-    consecutive on the disk that can be merged into one SCSI command.
-    Legal values are between 0 and 255. Default: 255/0. Note: This
-    value is forced to 0 on a Falcon, since scatter-gather isn't
-    possible with the ST-DMA. Not using scatter-gather hurts
-    performance significantly.
-
-  <host-id>:
-    The SCSI ID to be used by the initiator (your Atari). This is
-    usually 7, the highest possible ID. Every ID on the SCSI bus must
-    be unique. Default: determined at run time: If the NV-RAM checksum
-    is valid, and bit 7 in byte 30 of the NV-RAM is set, the lower 3
-    bits of this byte are used as the host ID. (This method is defined
-    by Atari and also used by some TOS HD drivers.) If the above
-    isn't given, the default ID is 7. (both, TT and Falcon).
-
-  <tagged>:
-    0 means turn off tagged queuing support, all other values > 0 mean
-    use tagged queuing for targets that support it. Default: currently
-    off, but this may change when tagged queuing handling has been
-    proved to be reliable.
-
-    Tagged queuing means that more than one command can be issued to
-    one LUN, and the SCSI device itself orders the requests so they
-    can be performed in optimal order. Not all SCSI devices support
-    tagged queuing (:-().
-
-4.5 switches=
--------------
-
-Syntax: switches=<list of switches>
-
-  With this option you can switch some hardware lines that are often
-used to enable/disable certain hardware extensions. Examples are
-OverScan, overclocking, ...
-
-  The <list of switches> is a comma-separated list of the following
-items:
-
-  ikbd: set RTS of the keyboard ACIA high
-  midi: set RTS of the MIDI ACIA high
-  snd6: set bit 6 of the PSG port A
-  snd7: set bit 6 of the PSG port A
-
-It doesn't make sense to mention a switch more than once (no
-difference to only once), but you can give as many switches as you
-want to enable different features. The switch lines are set as early
-as possible during kernel initialization (even before determining the
-present hardware.)
-
-  All of the items can also be prefixed with "ov_", i.e. "ov_ikbd",
-"ov_midi", ... These options are meant for switching on an OverScan
-video extension. The difference to the bare option is that the
-switch-on is done after video initialization, and somehow synchronized
-to the HBLANK. A speciality is that ov_ikbd and ov_midi are switched
-off before rebooting, so that OverScan is disabled and TOS boots
-correctly.
-
-  If you give an option both, with and without the "ov_" prefix, the
-earlier initialization ("ov_"-less) takes precedence. But the
-switching-off on reset still happens in this case.
-
-5) Options for Amiga Only:
-==========================
-
-5.1) video=
------------
-
-Syntax: video=<fbname>:<sub-options...>
-
-The <fbname> parameter specifies the name of the frame buffer, valid
-options are `amifb', `cyber', 'virge', `retz3' and `clgen', provided
-that the respective frame buffer devices have been compiled into the
-kernel (or compiled as loadable modules). The behavior of the <fbname>
-option was changed in 2.1.57 so it is now recommended to specify this
-option.
-
-The <sub-options> is a comma-separated list of the sub-options listed
-below. This option is organized similar to the Atari version of the
-"video"-option (4.1), but knows fewer sub-options.
-
-5.1.1) video mode
------------------
-
-Again, similar to the video mode for the Atari (see 4.1.1). Predefined
-modes depend on the used frame buffer device.
-
-OCS, ECS and AGA machines all use the color frame buffer. The following
-predefined video modes are available:
-
-NTSC modes:
- - ntsc            : 640x200, 15 kHz, 60 Hz
- - ntsc-lace       : 640x400, 15 kHz, 60 Hz interlaced
-PAL modes:
- - pal             : 640x256, 15 kHz, 50 Hz
- - pal-lace        : 640x512, 15 kHz, 50 Hz interlaced
-ECS modes:
- - multiscan       : 640x480, 29 kHz, 57 Hz
- - multiscan-lace  : 640x960, 29 kHz, 57 Hz interlaced
- - euro36          : 640x200, 15 kHz, 72 Hz
- - euro36-lace     : 640x400, 15 kHz, 72 Hz interlaced
- - euro72          : 640x400, 29 kHz, 68 Hz
- - euro72-lace     : 640x800, 29 kHz, 68 Hz interlaced
- - super72         : 800x300, 23 kHz, 70 Hz
- - super72-lace    : 800x600, 23 kHz, 70 Hz interlaced
- - dblntsc-ff      : 640x400, 27 kHz, 57 Hz
- - dblntsc-lace    : 640x800, 27 kHz, 57 Hz interlaced
- - dblpal-ff       : 640x512, 27 kHz, 47 Hz
- - dblpal-lace     : 640x1024, 27 kHz, 47 Hz interlaced
- - dblntsc         : 640x200, 27 kHz, 57 Hz doublescan
- - dblpal          : 640x256, 27 kHz, 47 Hz doublescan
-VGA modes:
- - vga             : 640x480, 31 kHz, 60 Hz
- - vga70           : 640x400, 31 kHz, 70 Hz
-
-Please notice that the ECS and VGA modes require either an ECS or AGA
-chipset, and that these modes are limited to 2-bit color for the ECS
-chipset and 8-bit color for the AGA chipset.
-
-5.1.2) depth
-------------
-
-Syntax: depth:<nr. of bit-planes>
-
-Specify the number of bit-planes for the selected video-mode.
-
-5.1.3) inverse
---------------
-
-Use inverted display (black on white). Functionally the same as the
-"inverse" sub-option for the Atari.
-
-5.1.4) font
------------
-
-Syntax: font:<fontname>
-
-Specify the font to use in text modes. Functionally the same as the
-"font" sub-option for the Atari, except that `PEARL8x8' is used instead
-of `VGA8x8' if the vertical size of the display is less than 400 pixel
-rows.
-
-5.1.5) monitorcap:
--------------------
-
-Syntax: monitorcap:<vmin>;<vmax>;<hmin>;<hmax>
-
-This describes the capabilities of a multisync monitor. For now, only
-the color frame buffer uses the settings of "monitorcap:".
-
-  <vmin> and <vmax> are the minimum and maximum, resp., vertical frequencies
-your monitor can work with, in Hz. <hmin> and <hmax> are the same for
-the horizontal frequency, in kHz.
-
-  The defaults are 50;90;15;38 (Generic Amiga multisync monitor).
-
-
-5.2) fd_def_df0=
-----------------
-
-Syntax: fd_def_df0=<value>
-
-Sets the df0 value for "silent" floppy drives. The value should be in
-hexadecimal with "0x" prefix.
-
-
-5.3) wd33c93=
--------------
-
-Syntax: wd33c93=<sub-options...>
-
-These options affect the A590/A2091, A3000 and GVP Series II SCSI
-controllers.
-
-The <sub-options> is a comma-separated list of the sub-options listed
-below.
-
-5.3.1) nosync
--------------
-
-Syntax: nosync:bitmask
-
-  bitmask is a byte where the 1st 7 bits correspond with the 7
-possible SCSI devices. Set a bit to prevent sync negotiation on that
-device. To maintain backwards compatibility, a command-line such as
-"wd33c93=255" will be automatically translated to
-"wd33c93=nosync:0xff". The default is to disable sync negotiation for
-all devices, eg. nosync:0xff.
-
-5.3.2) period
--------------
-
-Syntax: period:ns
-
-  `ns' is the minimum # of nanoseconds in a SCSI data transfer
-period. Default is 500; acceptable values are 250 - 1000.
-
-5.3.3) disconnect
------------------
-
-Syntax: disconnect:x
-
-  Specify x = 0 to never allow disconnects, 2 to always allow them.
-x = 1 does 'adaptive' disconnects, which is the default and generally
-the best choice.
-
-5.3.4) debug
-------------
-
-Syntax: debug:x
-
-  If `DEBUGGING_ON' is defined, x is a bit mask that causes various
-types of debug output to printed - see the DB_xxx defines in
-wd33c93.h.
-
-5.3.5) clock
-------------
-
-Syntax: clock:x
-
-  x = clock input in MHz for WD33c93 chip. Normal values would be from
-8 through 20. The default value depends on your hostadapter(s),
-default for the A3000 internal controller is 14, for the A2091 it's 8
-and for the GVP hostadapters it's either 8 or 14, depending on the
-hostadapter and the SCSI-clock jumper present on some GVP
-hostadapters.
-
-5.3.6) next
------------
-
-  No argument. Used to separate blocks of keywords when there's more
-than one wd33c93-based host adapter in the system.
-
-5.3.7) nodma
-------------
-
-Syntax: nodma:x
-
-  If x is 1 (or if the option is just written as "nodma"), the WD33c93
-controller will not use DMA (= direct memory access) to access the
-Amiga's memory.  This is useful for some systems (like A3000's and
-A4000's with the A3640 accelerator, revision 3.0) that have problems
-using DMA to chip memory.  The default is 0, i.e. to use DMA if
-possible.
-
-
-5.4) gvp11=
------------
-
-Syntax: gvp11=<addr-mask>
-
-  The earlier versions of the GVP driver did not handle DMA
-address-mask settings correctly which made it necessary for some
-people to use this option, in order to get their GVP controller
-running under Linux. These problems have hopefully been solved and the
-use of this option is now highly unrecommended!
-
-  Incorrect use can lead to unpredictable behavior, so please only use
-this option if you *know* what you are doing and have a reason to do
-so. In any case if you experience problems and need to use this
-option, please inform us about it by mailing to the Linux/68k kernel
-mailing list.
-
-  The address mask set by this option specifies which addresses are
-valid for DMA with the GVP Series II SCSI controller. An address is
-valid, if no bits are set except the bits that are set in the mask,
-too.
-
-  Some versions of the GVP can only DMA into a 24 bit address range,
-some can address a 25 bit address range while others can use the whole
-32 bit address range for DMA. The correct setting depends on your
-controller and should be autodetected by the driver. An example is the
-24 bit region which is specified by a mask of 0x00fffffe.
-
-
-/* Local Variables: */
-/* mode: text       */
-/* End:             */
diff --git a/Documentation/md/md-cluster.txt b/Documentation/md/md-cluster.txt
deleted file mode 100644 (file)
index e1055f1..0000000
+++ /dev/null
@@ -1,325 +0,0 @@
-The cluster MD is a shared-device RAID for a cluster, it supports
-two levels: raid1 and raid10 (limited support).
-
-
-1. On-disk format
-
-Separate write-intent-bitmaps are used for each cluster node.
-The bitmaps record all writes that may have been started on that node,
-and may not yet have finished. The on-disk layout is:
-
-0                    4k                     8k                    12k
--------------------------------------------------------------------
-| idle                | md super            | bm super [0] + bits |
-| bm bits[0, contd]   | bm super[1] + bits  | bm bits[1, contd]   |
-| bm super[2] + bits  | bm bits [2, contd]  | bm super[3] + bits  |
-| bm bits [3, contd]  |                     |                     |
-
-During "normal" functioning we assume the filesystem ensures that only
-one node writes to any given block at a time, so a write request will
-
- - set the appropriate bit (if not already set)
- - commit the write to all mirrors
- - schedule the bit to be cleared after a timeout.
-
-Reads are just handled normally. It is up to the filesystem to ensure
-one node doesn't read from a location where another node (or the same
-node) is writing.
-
-
-2. DLM Locks for management
-
-There are three groups of locks for managing the device:
-
-2.1 Bitmap lock resource (bm_lockres)
-
- The bm_lockres protects individual node bitmaps. They are named in
- the form bitmap000 for node 1, bitmap001 for node 2 and so on. When a
- node joins the cluster, it acquires the lock in PW mode and it stays
- so during the lifetime the node is part of the cluster. The lock
- resource number is based on the slot number returned by the DLM
- subsystem. Since DLM starts node count from one and bitmap slots
- start from zero, one is subtracted from the DLM slot number to arrive
- at the bitmap slot number.
-
- The LVB of the bitmap lock for a particular node records the range
- of sectors that are being re-synced by that node.  No other
- node may write to those sectors.  This is used when a new nodes
- joins the cluster.
-
-2.2 Message passing locks
-
- Each node has to communicate with other nodes when starting or ending
- resync, and for metadata superblock updates.  This communication is
- managed through three locks: "token", "message", and "ack", together
- with the Lock Value Block (LVB) of one of the "message" lock.
-
-2.3 new-device management
-
- A single lock: "no-new-dev" is used to co-ordinate the addition of
- new devices - this must be synchronized across the array.
- Normally all nodes hold a concurrent-read lock on this device.
-
-3. Communication
-
- Messages can be broadcast to all nodes, and the sender waits for all
- other nodes to acknowledge the message before proceeding.  Only one
- message can be processed at a time.
-
-3.1 Message Types
-
- There are six types of messages which are passed:
-
- 3.1.1 METADATA_UPDATED: informs other nodes that the metadata has
-   been updated, and the node must re-read the md superblock. This is
-   performed synchronously. It is primarily used to signal device
-   failure.
-
- 3.1.2 RESYNCING: informs other nodes that a resync is initiated or
-   ended so that each node may suspend or resume the region.  Each
-   RESYNCING message identifies a range of the devices that the
-   sending node is about to resync. This overrides any previous
-   notification from that node: only one ranged can be resynced at a
-   time per-node.
-
- 3.1.3 NEWDISK: informs other nodes that a device is being added to
-   the array. Message contains an identifier for that device.  See
-   below for further details.
-
- 3.1.4 REMOVE: A failed or spare device is being removed from the
-   array. The slot-number of the device is included in the message.
-
- 3.1.5 RE_ADD: A failed device is being re-activated - the assumption
-   is that it has been determined to be working again.
-
- 3.1.6 BITMAP_NEEDS_SYNC: if a node is stopped locally but the bitmap
-   isn't clean, then another node is informed to take the ownership of
-   resync.
-
-3.2 Communication mechanism
-
- The DLM LVB is used to communicate within nodes of the cluster. There
- are three resources used for the purpose:
-
-  3.2.1 token: The resource which protects the entire communication
-   system. The node having the token resource is allowed to
-   communicate.
-
-  3.2.2 message: The lock resource which carries the data to
-   communicate.
-
-  3.2.3 ack: The resource, acquiring which means the message has been
-   acknowledged by all nodes in the cluster. The BAST of the resource
-   is used to inform the receiving node that a node wants to
-   communicate.
-
-The algorithm is:
-
- 1. receive status - all nodes have concurrent-reader lock on "ack".
-
-   sender                         receiver                 receiver
-   "ack":CR                       "ack":CR                 "ack":CR
-
- 2. sender get EX on "token"
-    sender get EX on "message"
-    sender                        receiver                 receiver
-    "token":EX                    "ack":CR                 "ack":CR
-    "message":EX
-    "ack":CR
-
-    Sender checks that it still needs to send a message. Messages
-    received or other events that happened while waiting for the
-    "token" may have made this message inappropriate or redundant.
-
- 3. sender writes LVB.
-    sender down-convert "message" from EX to CW
-    sender try to get EX of "ack"
-    [ wait until all receivers have *processed* the "message" ]
-
-                                     [ triggered by bast of "ack" ]
-                                     receiver get CR on "message"
-                                     receiver read LVB
-                                     receiver processes the message
-                                     [ wait finish ]
-                                     receiver releases "ack"
-                                     receiver tries to get PR on "message"
-
-   sender                         receiver                  receiver
-   "token":EX                     "message":CR              "message":CR
-   "message":CW
-   "ack":EX
-
- 4. triggered by grant of EX on "ack" (indicating all receivers
-    have processed message)
-    sender down-converts "ack" from EX to CR
-    sender releases "message"
-    sender releases "token"
-                               receiver upconvert to PR on "message"
-                               receiver get CR of "ack"
-                               receiver release "message"
-
-   sender                      receiver                   receiver
-   "ack":CR                    "ack":CR                   "ack":CR
-
-
-4. Handling Failures
-
-4.1 Node Failure
-
- When a node fails, the DLM informs the cluster with the slot
- number. The node starts a cluster recovery thread. The cluster
- recovery thread:
-
-       - acquires the bitmap<number> lock of the failed node
-       - opens the bitmap
-       - reads the bitmap of the failed node
-       - copies the set bitmap to local node
-       - cleans the bitmap of the failed node
-       - releases bitmap<number> lock of the failed node
-       - initiates resync of the bitmap on the current node
-               md_check_recovery is invoked within recover_bitmaps,
-               then md_check_recovery -> metadata_update_start/finish,
-               it will lock the communication by lock_comm.
-               Which means when one node is resyncing it blocks all
-               other nodes from writing anywhere on the array.
-
- The resync process is the regular md resync. However, in a clustered
- environment when a resync is performed, it needs to tell other nodes
- of the areas which are suspended. Before a resync starts, the node
- send out RESYNCING with the (lo,hi) range of the area which needs to
- be suspended. Each node maintains a suspend_list, which contains the
- list of ranges which are currently suspended. On receiving RESYNCING,
- the node adds the range to the suspend_list. Similarly, when the node
- performing resync finishes, it sends RESYNCING with an empty range to
- other nodes and other nodes remove the corresponding entry from the
- suspend_list.
-
- A helper function, ->area_resyncing() can be used to check if a
- particular I/O range should be suspended or not.
-
-4.2 Device Failure
-
- Device failures are handled and communicated with the metadata update
- routine.  When a node detects a device failure it does not allow
- any further writes to that device until the failure has been
- acknowledged by all other nodes.
-
-5. Adding a new Device
-
- For adding a new device, it is necessary that all nodes "see" the new
- device to be added. For this, the following algorithm is used:
-
-    1. Node 1 issues mdadm --manage /dev/mdX --add /dev/sdYY which issues
-       ioctl(ADD_NEW_DISK with disc.state set to MD_DISK_CLUSTER_ADD)
-    2. Node 1 sends a NEWDISK message with uuid and slot number
-    3. Other nodes issue kobject_uevent_env with uuid and slot number
-       (Steps 4,5 could be a udev rule)
-    4. In userspace, the node searches for the disk, perhaps
-       using blkid -t SUB_UUID=""
-    5. Other nodes issue either of the following depending on whether
-       the disk was found:
-       ioctl(ADD_NEW_DISK with disc.state set to MD_DISK_CANDIDATE and
-             disc.number set to slot number)
-       ioctl(CLUSTERED_DISK_NACK)
-    6. Other nodes drop lock on "no-new-devs" (CR) if device is found
-    7. Node 1 attempts EX lock on "no-new-dev"
-    8. If node 1 gets the lock, it sends METADATA_UPDATED after
-       unmarking the disk as SpareLocal
-    9. If not (get "no-new-dev" lock), it fails the operation and sends
-       METADATA_UPDATED.
-   10. Other nodes get the information whether a disk is added or not
-       by the following METADATA_UPDATED.
-
-6. Module interface.
-
- There are 17 call-backs which the md core can make to the cluster
- module.  Understanding these can give a good overview of the whole
- process.
-
-6.1 join(nodes) and leave()
-
- These are called when an array is started with a clustered bitmap,
- and when the array is stopped.  join() ensures the cluster is
- available and initializes the various resources.
- Only the first 'nodes' nodes in the cluster can use the array.
-
-6.2 slot_number()
-
- Reports the slot number advised by the cluster infrastructure.
- Range is from 0 to nodes-1.
-
-6.3 resync_info_update()
-
- This updates the resync range that is stored in the bitmap lock.
- The starting point is updated as the resync progresses.  The
- end point is always the end of the array.
- It does *not* send a RESYNCING message.
-
-6.4 resync_start(), resync_finish()
-
- These are called when resync/recovery/reshape starts or stops.
- They update the resyncing range in the bitmap lock and also
- send a RESYNCING message.  resync_start reports the whole
- array as resyncing, resync_finish reports none of it.
-
- resync_finish() also sends a BITMAP_NEEDS_SYNC message which
- allows some other node to take over.
-
-6.5 metadata_update_start(), metadata_update_finish(),
-    metadata_update_cancel().
-
- metadata_update_start is used to get exclusive access to
- the metadata.  If a change is still needed once that access is
- gained, metadata_update_finish() will send a METADATA_UPDATE
- message to all other nodes, otherwise metadata_update_cancel()
- can be used to release the lock.
-
-6.6 area_resyncing()
-
- This combines two elements of functionality.
-
- Firstly, it will check if any node is currently resyncing
- anything in a given range of sectors.  If any resync is found,
- then the caller will avoid writing or read-balancing in that
- range.
-
- Secondly, while node recovery is happening it reports that
- all areas are resyncing for READ requests.  This avoids races
- between the cluster-filesystem and the cluster-RAID handling
- a node failure.
-
-6.7 add_new_disk_start(), add_new_disk_finish(), new_disk_ack()
-
- These are used to manage the new-disk protocol described above.
- When a new device is added, add_new_disk_start() is called before
- it is bound to the array and, if that succeeds, add_new_disk_finish()
- is called the device is fully added.
-
- When a device is added in acknowledgement to a previous
- request, or when the device is declared "unavailable",
- new_disk_ack() is called.
-
-6.8 remove_disk()
-
- This is called when a spare or failed device is removed from
- the array.  It causes a REMOVE message to be send to other nodes.
-
-6.9 gather_bitmaps()
-
- This sends a RE_ADD message to all other nodes and then
- gathers bitmap information from all bitmaps.  This combined
- bitmap is then used to recovery the re-added device.
-
-6.10 lock_all_bitmaps() and unlock_all_bitmaps()
-
- These are called when change bitmap to none. If a node plans
- to clear the cluster raid's bitmap, it need to make sure no other
- nodes are using the raid which is achieved by lock all bitmap
- locks within the cluster, and also those locks are unlocked
- accordingly.
-
-7. Unsupported features
-
-There are somethings which are not supported by cluster MD yet.
-
-- change array_sectors.
diff --git a/Documentation/md/raid5-cache.txt b/Documentation/md/raid5-cache.txt
deleted file mode 100644 (file)
index 2b210f2..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-RAID5 cache
-
-Raid 4/5/6 could include an extra disk for data cache besides normal RAID
-disks. The role of RAID disks isn't changed with the cache disk. The cache disk
-caches data to the RAID disks. The cache can be in write-through (supported
-since 4.4) or write-back mode (supported since 4.10). mdadm (supported since
-3.4) has a new option '--write-journal' to create array with cache. Please
-refer to mdadm manual for details. By default (RAID array starts), the cache is
-in write-through mode. A user can switch it to write-back mode by:
-
-echo "write-back" > /sys/block/md0/md/journal_mode
-
-And switch it back to write-through mode by:
-
-echo "write-through" > /sys/block/md0/md/journal_mode
-
-In both modes, all writes to the array will hit cache disk first. This means
-the cache disk must be fast and sustainable.
-
--------------------------------------
-write-through mode:
-
-This mode mainly fixes the 'write hole' issue. For RAID 4/5/6 array, an unclean
-shutdown can cause data in some stripes to not be in consistent state, eg, data
-and parity don't match. The reason is that a stripe write involves several RAID
-disks and it's possible the writes don't hit all RAID disks yet before the
-unclean shutdown. We call an array degraded if it has inconsistent data. MD
-tries to resync the array to bring it back to normal state. But before the
-resync completes, any system crash will expose the chance of real data
-corruption in the RAID array. This problem is called 'write hole'.
-
-The write-through cache will cache all data on cache disk first. After the data
-is safe on the cache disk, the data will be flushed onto RAID disks. The
-two-step write will guarantee MD can recover correct data after unclean
-shutdown even the array is degraded. Thus the cache can close the 'write hole'.
-
-In write-through mode, MD reports IO completion to upper layer (usually
-filesystems) after the data is safe on RAID disks, so cache disk failure
-doesn't cause data loss. Of course cache disk failure means the array is
-exposed to 'write hole' again.
-
-In write-through mode, the cache disk isn't required to be big. Several
-hundreds megabytes are enough.
-
---------------------------------------
-write-back mode:
-
-write-back mode fixes the 'write hole' issue too, since all write data is
-cached on cache disk. But the main goal of 'write-back' cache is to speed up
-write. If a write crosses all RAID disks of a stripe, we call it full-stripe
-write. For non-full-stripe writes, MD must read old data before the new parity
-can be calculated. These synchronous reads hurt write throughput. Some writes
-which are sequential but not dispatched in the same time will suffer from this
-overhead too. Write-back cache will aggregate the data and flush the data to
-RAID disks only after the data becomes a full stripe write. This will
-completely avoid the overhead, so it's very helpful for some workloads. A
-typical workload which does sequential write followed by fsync is an example.
-
-In write-back mode, MD reports IO completion to upper layer (usually
-filesystems) right after the data hits cache disk. The data is flushed to raid
-disks later after specific conditions met. So cache disk failure will cause
-data loss.
-
-In write-back mode, MD also caches data in memory. The memory cache includes
-the same data stored on cache disk, so a power loss doesn't cause data loss.
-The memory cache size has performance impact for the array. It's recommended
-the size is big. A user can configure the size by:
-
-echo "2048" > /sys/block/md0/md/stripe_cache_size
-
-Too small cache disk will make the write aggregation less efficient in this
-mode depending on the workloads. It's recommended to use a cache disk with at
-least several gigabytes size in write-back mode.
-
---------------------------------------
-The implementation:
-
-The write-through and write-back cache use the same disk format. The cache disk
-is organized as a simple write log. The log consists of 'meta data' and 'data'
-pairs. The meta data describes the data. It also includes checksum and sequence
-ID for recovery identification. Data can be IO data and parity data. Data is
-checksumed too. The checksum is stored in the meta data ahead of the data. The
-checksum is an optimization because MD can write meta and data freely without
-worry about the order. MD superblock has a field pointed to the valid meta data
-of log head.
-
-The log implementation is pretty straightforward. The difficult part is the
-order in which MD writes data to cache disk and RAID disks. Specifically, in
-write-through mode, MD calculates parity for IO data, writes both IO data and
-parity to the log, writes the data and parity to RAID disks after the data and
-parity is settled down in log and finally the IO is finished. Read just reads
-from raid disks as usual.
-
-In write-back mode, MD writes IO data to the log and reports IO completion. The
-data is also fully cached in memory at that time, which means read must query
-memory cache. If some conditions are met, MD will flush the data to RAID disks.
-MD will calculate parity for the data and write parity into the log. After this
-is finished, MD will write both data and parity into RAID disks, then MD can
-release the memory cache. The flush conditions could be stripe becomes a full
-stripe write, free cache disk space is low or free in-kernel memory cache space
-is low.
-
-After an unclean shutdown, MD does recovery. MD reads all meta data and data
-from the log. The sequence ID and checksum will help us detect corrupted meta
-data and data. If MD finds a stripe with data and valid parities (1 parity for
-raid4/5 and 2 for raid6), MD will write the data and parities to RAID disks. If
-parities are incompleted, they are discarded. If part of data is corrupted,
-they are discarded too. MD then loads valid data and writes them to RAID disks
-in normal way.
diff --git a/Documentation/md/raid5-ppl.txt b/Documentation/md/raid5-ppl.txt
deleted file mode 100644 (file)
index bfa0925..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-Partial Parity Log
-
-Partial Parity Log (PPL) is a feature available for RAID5 arrays. The issue
-addressed by PPL is that after a dirty shutdown, parity of a particular stripe
-may become inconsistent with data on other member disks. If the array is also
-in degraded state, there is no way to recalculate parity, because one of the
-disks is missing. This can lead to silent data corruption when rebuilding the
-array or using it is as degraded - data calculated from parity for array blocks
-that have not been touched by a write request during the unclean shutdown can
-be incorrect. Such condition is known as the RAID5 Write Hole. Because of
-this, md by default does not allow starting a dirty degraded array.
-
-Partial parity for a write operation is the XOR of stripe data chunks not
-modified by this write. It is just enough data needed for recovering from the
-write hole. XORing partial parity with the modified chunks produces parity for
-the stripe, consistent with its state before the write operation, regardless of
-which chunk writes have completed. If one of the not modified data disks of
-this stripe is missing, this updated parity can be used to recover its
-contents. PPL recovery is also performed when starting an array after an
-unclean shutdown and all disks are available, eliminating the need to resync
-the array. Because of this, using write-intent bitmap and PPL together is not
-supported.
-
-When handling a write request PPL writes partial parity before new data and
-parity are dispatched to disks. PPL is a distributed log - it is stored on
-array member drives in the metadata area, on the parity drive of a particular
-stripe.  It does not require a dedicated journaling drive. Write performance is
-reduced by up to 30%-40% but it scales with the number of drives in the array
-and the journaling drive does not become a bottleneck or a single point of
-failure.
-
-Unlike raid5-cache, the other solution in md for closing the write hole, PPL is
-not a true journal. It does not protect from losing in-flight data, only from
-silent data corruption. If a dirty disk of a stripe is lost, no PPL recovery is
-performed for this stripe (parity is not updated). So it is possible to have
-arbitrary data in the written part of a stripe if that disk is lost. In such
-case the behavior is the same as in plain raid5.
-
-PPL is available for md version-1 metadata and external (specifically IMSM)
-metadata arrays. It can be enabled using mdadm option --consistency-policy=ppl.
-
-There is a limitation of maximum 64 disks in the array for PPL. It allows to
-keep data structures and implementation simple. RAID5 arrays with so many disks
-are not likely due to high risk of multiple disks failure. Such restriction
-should not be a real life limitation.
diff --git a/Documentation/memory-devices/ti-emif.txt b/Documentation/memory-devices/ti-emif.txt
deleted file mode 100644 (file)
index f4ad9a7..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-TI EMIF SDRAM Controller Driver:
-
-Author
-========
-Aneesh V <aneesh@ti.com>
-
-Location
-============
-driver/memory/emif.c
-
-Supported SoCs:
-===================
-TI OMAP44xx
-TI OMAP54xx
-
-Menuconfig option:
-==========================
-Device Drivers
-       Memory devices
-               Texas Instruments EMIF driver
-
-Description
-===========
-This driver is for the EMIF module available in Texas Instruments
-SoCs. EMIF is an SDRAM controller that, based on its revision,
-supports one or more of DDR2, DDR3, and LPDDR2 SDRAM protocols.
-This driver takes care of only LPDDR2 memories presently. The
-functions of the driver includes re-configuring AC timing
-parameters and other settings during frequency, voltage and
-temperature changes
-
-Platform Data (see include/linux/platform_data/emif_plat.h):
-=====================================================================
-DDR device details and other board dependent and SoC dependent
-information can be passed through platform data (struct emif_platform_data)
-- DDR device details: 'struct ddr_device_info'
-- Device AC timings: 'struct lpddr2_timings' and 'struct lpddr2_min_tck'
-- Custom configurations: customizable policy options through
-  'struct emif_custom_configs'
-- IP revision
-- PHY type
-
-Interface to the external world:
-================================
-EMIF driver registers notifiers for voltage and frequency changes
-affecting EMIF and takes appropriate actions when these are invoked.
-- freq_pre_notify_handling()
-- freq_post_notify_handling()
-- volt_notify_handling()
-
-Debugfs
-========
-The driver creates two debugfs entries per device.
-- regcache_dump : dump of register values calculated and saved for all
-  frequencies used so far.
-- mr4 : last polled value of MR4 register in the LPDDR2 device. MR4
-  indicates the current temperature level of the device.
index 082fa8f..3a8d063 100644 (file)
@@ -1,5 +1,3 @@
-:orphan:
-
 =============================================
 Intel Many Integrated Core (MIC) architecture
 =============================================
diff --git a/Documentation/mmc/mmc-async-req.txt b/Documentation/mmc/mmc-async-req.txt
deleted file mode 100644 (file)
index ae1907b..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-Rationale
-=========
-
-How significant is the cache maintenance overhead?
-It depends. Fast eMMC and multiple cache levels with speculative cache
-pre-fetch makes the cache overhead relatively significant. If the DMA
-preparations for the next request are done in parallel with the current
-transfer, the DMA preparation overhead would not affect the MMC performance.
-The intention of non-blocking (asynchronous) MMC requests is to minimize the
-time between when an MMC request ends and another MMC request begins.
-Using mmc_wait_for_req(), the MMC controller is idle while dma_map_sg and
-dma_unmap_sg are processing. Using non-blocking MMC requests makes it
-possible to prepare the caches for next job in parallel with an active
-MMC request.
-
-MMC block driver
-================
-
-The mmc_blk_issue_rw_rq() in the MMC block driver is made non-blocking.
-The increase in throughput is proportional to the time it takes to
-prepare (major part of preparations are dma_map_sg() and dma_unmap_sg())
-a request and how fast the memory is. The faster the MMC/SD is the
-more significant the prepare request time becomes. Roughly the expected
-performance gain is 5% for large writes and 10% on large reads on a L2 cache
-platform. In power save mode, when clocks run on a lower frequency, the DMA
-preparation may cost even more. As long as these slower preparations are run
-in parallel with the transfer performance won't be affected.
-
-Details on measurements from IOZone and mmc_test
-================================================
-
-https://wiki.linaro.org/WorkingGroups/Kernel/Specs/StoragePerfMMC-async-req
-
-MMC core API extension
-======================
-
-There is one new public function mmc_start_req().
-It starts a new MMC command request for a host. The function isn't
-truly non-blocking. If there is an ongoing async request it waits
-for completion of that request and starts the new one and returns. It
-doesn't wait for the new request to complete. If there is no ongoing
-request it starts the new request and returns immediately.
-
-MMC host extensions
-===================
-
-There are two optional members in the mmc_host_ops -- pre_req() and
-post_req() -- that the host driver may implement in order to move work
-to before and after the actual mmc_host_ops.request() function is called.
-In the DMA case pre_req() may do dma_map_sg() and prepare the DMA
-descriptor, and post_req() runs the dma_unmap_sg().
-
-Optimize for the first request
-==============================
-
-The first request in a series of requests can't be prepared in parallel
-with the previous transfer, since there is no previous request.
-The argument is_first_req in pre_req() indicates that there is no previous
-request. The host driver may optimize for this scenario to minimize
-the performance loss. A way to optimize for this is to split the current
-request in two chunks, prepare the first chunk and start the request,
-and finally prepare the second chunk and start the transfer.
-
-Pseudocode to handle is_first_req scenario with minimal prepare overhead:
-
-if (is_first_req && req->size > threshold)
-   /* start MMC transfer for the complete transfer size */
-   mmc_start_command(MMC_CMD_TRANSFER_FULL_SIZE);
-
-   /*
-    * Begin to prepare DMA while cmd is being processed by MMC.
-    * The first chunk of the request should take the same time
-    * to prepare as the "MMC process command time".
-    * If prepare time exceeds MMC cmd time
-    * the transfer is delayed, guesstimate max 4k as first chunk size.
-    */
-    prepare_1st_chunk_for_dma(req);
-    /* flush pending desc to the DMAC (dmaengine.h) */
-    dma_issue_pending(req->dma_desc);
-
-    prepare_2nd_chunk_for_dma(req);
-    /*
-     * The second issue_pending should be called before MMC runs out
-     * of the first chunk. If the MMC runs out of the first data chunk
-     * before this call, the transfer is delayed.
-     */
-    dma_issue_pending(req->dma_desc);
diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt
deleted file mode 100644 (file)
index 4ad0bb1..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-SD and MMC Block Device Attributes
-==================================
-
-These attributes are defined for the block devices associated with the
-SD or MMC device.
-
-The following attributes are read/write.
-
-       force_ro                Enforce read-only access even if write protect switch is off.
-
-SD and MMC Device Attributes
-============================
-
-All attributes are read-only.
-
-       cid                     Card Identification Register
-       csd                     Card Specific Data Register
-       scr                     SD Card Configuration Register (SD only)
-       date                    Manufacturing Date (from CID Register)
-       fwrev                   Firmware/Product Revision (from CID Register) (SD and MMCv1 only)
-       hwrev                   Hardware/Product Revision (from CID Register) (SD and MMCv1 only)
-       manfid                  Manufacturer ID (from CID Register)
-       name                    Product Name (from CID Register)
-       oemid                   OEM/Application ID (from CID Register)
-       prv                     Product Revision (from CID Register) (SD and MMCv4 only)
-       serial                  Product Serial Number (from CID Register)
-       erase_size              Erase group size
-       preferred_erase_size    Preferred erase size
-       raw_rpmb_size_mult      RPMB partition size
-       rel_sectors             Reliable write sector count
-       ocr                     Operation Conditions Register
-       dsr                     Driver Stage Register
-       cmdq_en                 Command Queue enabled: 1 => enabled, 0 => not enabled
-
-Note on Erase Size and Preferred Erase Size:
-
-       "erase_size" is the  minimum size, in bytes, of an erase
-       operation.  For MMC, "erase_size" is the erase group size
-       reported by the card.  Note that "erase_size" does not apply
-       to trim or secure trim operations where the minimum size is
-       always one 512 byte sector.  For SD, "erase_size" is 512
-       if the card is block-addressed, 0 otherwise.
-
-       SD/MMC cards can erase an arbitrarily large area up to and
-       including the whole card.  When erasing a large area it may
-       be desirable to do it in smaller chunks for three reasons:
-               1. A single erase command will make all other I/O on
-               the card wait.  This is not a problem if the whole card
-               is being erased, but erasing one partition will make
-               I/O for another partition on the same card wait for the
-               duration of the erase - which could be a several
-               minutes.
-               2. To be able to inform the user of erase progress.
-               3. The erase timeout becomes too large to be very
-               useful.  Because the erase timeout contains a margin
-               which is multiplied by the size of the erase area,
-               the value can end up being several minutes for large
-               areas.
-
-       "erase_size" is not the most efficient unit to erase
-       (especially for SD where it is just one sector),
-       hence "preferred_erase_size" provides a good chunk
-       size for erasing large areas.
-
-       For MMC, "preferred_erase_size" is the high-capacity
-       erase size if a card specifies one, otherwise it is
-       based on the capacity of the card.
-
-       For SD, "preferred_erase_size" is the allocation unit
-       size specified by the card.
-
-       "preferred_erase_size" is in bytes.
-
-Note on raw_rpmb_size_mult:
-       "raw_rpmb_size_mult" is a multiple of 128kB block.
-       RPMB size in byte is calculated by using the following equation:
-       RPMB partition size = 128kB x raw_rpmb_size_mult
diff --git a/Documentation/mmc/mmc-dev-parts.txt b/Documentation/mmc/mmc-dev-parts.txt
deleted file mode 100644 (file)
index f08d078..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-SD and MMC Device Partitions
-============================
-
-Device partitions are additional logical block devices present on the
-SD/MMC device.
-
-As of this writing, MMC boot partitions as supported and exposed as
-/dev/mmcblkXboot0 and /dev/mmcblkXboot1, where X is the index of the
-parent /dev/mmcblkX.
-
-MMC Boot Partitions
-===================
-
-Read and write access is provided to the two MMC boot partitions. Due to
-the sensitive nature of the boot partition contents, which often store
-a bootloader or bootloader configuration tables crucial to booting the
-platform, write access is disabled by default to reduce the chance of
-accidental bricking.
-
-To enable write access to /dev/mmcblkXbootY, disable the forced read-only
-access with:
-
-echo 0 > /sys/block/mmcblkXbootY/force_ro
-
-To re-enable read-only access:
-
-echo 1 > /sys/block/mmcblkXbootY/force_ro
-
-The boot partitions can also be locked read only until the next power on,
-with:
-
-echo 1 > /sys/block/mmcblkXbootY/ro_lock_until_next_power_on
-
-This is a feature of the card and not of the kernel. If the card does
-not support boot partition locking, the file will not exist. If the
-feature has been disabled on the card, the file will be read-only.
-
-The boot partitions can also be locked permanently, but this feature is
-not accessible through sysfs in order to avoid accidental or malicious
-bricking.
diff --git a/Documentation/mmc/mmc-tools.txt b/Documentation/mmc/mmc-tools.txt
deleted file mode 100644 (file)
index 735509c..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-MMC tools introduction
-======================
-
-There is one MMC test tools called mmc-utils, which is maintained by Chris Ball,
-you can find it at the below public git repository:
-http://git.kernel.org/cgit/linux/kernel/git/cjb/mmc-utils.git/
-
-Functions
-=========
-
-The mmc-utils tools can do the following:
- - Print and parse extcsd data.
- - Determine the eMMC writeprotect status.
- - Set the eMMC writeprotect status.
- - Set the eMMC data sector size to 4KB by disabling emulation.
- - Create general purpose partition.
- - Enable the enhanced user area.
- - Enable write reliability per partition.
- - Print the response to STATUS_SEND (CMD13).
- - Enable the boot partition.
- - Set Boot Bus Conditions.
- - Enable the eMMC BKOPS feature.
- - Permanently enable the eMMC H/W Reset feature.
- - Permanently disable the eMMC H/W Reset feature.
- - Send Sanitize command.
- - Program authentication key for the device.
- - Counter value for the rpmb device will be read to stdout.
- - Read from rpmb device to output.
- - Write to rpmb device from data file.
- - Enable the eMMC cache feature.
- - Disable the eMMC cache feature.
- - Print and parse CID data.
- - Print and parse CSD data.
- - Print and parse SCR data.
diff --git a/Documentation/mtd/intel-spi.txt b/Documentation/mtd/intel-spi.txt
deleted file mode 100644 (file)
index bc35772..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-Upgrading BIOS using intel-spi
-------------------------------
-
-Many Intel CPUs like Baytrail and Braswell include SPI serial flash host
-controller which is used to hold BIOS and other platform specific data.
-Since contents of the SPI serial flash is crucial for machine to function,
-it is typically protected by different hardware protection mechanisms to
-avoid accidental (or on purpose) overwrite of the content.
-
-Not all manufacturers protect the SPI serial flash, mainly because it
-allows upgrading the BIOS image directly from an OS.
-
-The intel-spi driver makes it possible to read and write the SPI serial
-flash, if certain protection bits are not set and locked. If it finds
-any of them set, the whole MTD device is made read-only to prevent
-partial overwrites. By default the driver exposes SPI serial flash
-contents as read-only but it can be changed from kernel command line,
-passing "intel-spi.writeable=1".
-
-Please keep in mind that overwriting the BIOS image on SPI serial flash
-might render the machine unbootable and requires special equipment like
-Dediprog to revive. You have been warned!
-
-Below are the steps how to upgrade MinnowBoard MAX BIOS directly from
-Linux.
-
- 1) Download and extract the latest Minnowboard MAX BIOS SPI image
-    [1]. At the time writing this the latest image is v92.
-
- 2) Install mtd-utils package [2]. We need this in order to erase the SPI
-    serial flash. Distros like Debian and Fedora have this prepackaged with
-    name "mtd-utils".
-
- 3) Add "intel-spi.writeable=1" to the kernel command line and reboot
-    the board (you can also reload the driver passing "writeable=1" as
-    module parameter to modprobe).
-
- 4) Once the board is up and running again, find the right MTD partition
-    (it is named as "BIOS"):
-
-    # cat /proc/mtd
-    dev:    size   erasesize  name
-    mtd0: 00800000 00001000 "BIOS"
-
-    So here it will be /dev/mtd0 but it may vary.
-
- 5) Make backup of the existing image first:
-
-    # dd if=/dev/mtd0ro of=bios.bak
-    16384+0 records in
-    16384+0 records out
-    8388608 bytes (8.4 MB) copied, 10.0269 s, 837 kB/s
-
- 6) Verify the backup
-
-    # sha1sum /dev/mtd0ro bios.bak
-    fdbb011920572ca6c991377c4b418a0502668b73  /dev/mtd0ro
-    fdbb011920572ca6c991377c4b418a0502668b73  bios.bak
-
-    The SHA1 sums must match. Otherwise do not continue any further!
-
- 7) Erase the SPI serial flash. After this step, do not reboot the
-    board! Otherwise it will not start anymore.
-
-    # flash_erase /dev/mtd0 0 0
-    Erasing 4 Kibyte @ 7ff000 -- 100 % complete
-
- 8) Once completed without errors you can write the new BIOS image:
-
-    # dd if=MNW2MAX1.X64.0092.R01.1605221712.bin of=/dev/mtd0
-
- 9) Verify that the new content of the SPI serial flash matches the new
-    BIOS image:
-
-    # sha1sum /dev/mtd0ro MNW2MAX1.X64.0092.R01.1605221712.bin
-    9b4df9e4be2057fceec3a5529ec3d950836c87a2  /dev/mtd0ro
-    9b4df9e4be2057fceec3a5529ec3d950836c87a2 MNW2MAX1.X64.0092.R01.1605221712.bin
-
-    The SHA1 sums should match.
-
- 10) Now you can reboot your board and observe the new BIOS starting up
-     properly.
-
-References
-----------
-
-[1] https://firmware.intel.com/sites/default/files/MinnowBoard.MAX_.X64.92.R01.zip
-[2] http://www.linux-mtd.infradead.org/
diff --git a/Documentation/mtd/nand_ecc.txt b/Documentation/mtd/nand_ecc.txt
deleted file mode 100644 (file)
index f8c3284..0000000
+++ /dev/null
@@ -1,714 +0,0 @@
-Introduction
-============
-
-Having looked at the linux mtd/nand driver and more specific at nand_ecc.c
-I felt there was room for optimisation. I bashed the code for a few hours
-performing tricks like table lookup removing superfluous code etc.
-After that the speed was increased by 35-40%.
-Still I was not too happy as I felt there was additional room for improvement.
-
-Bad! I was hooked.
-I decided to annotate my steps in this file. Perhaps it is useful to someone
-or someone learns something from it.
-
-
-The problem
-===========
-
-NAND flash (at least SLC one) typically has sectors of 256 bytes.
-However NAND flash is not extremely reliable so some error detection
-(and sometimes correction) is needed.
-
-This is done by means of a Hamming code. I'll try to explain it in
-laymans terms (and apologies to all the pro's in the field in case I do
-not use the right terminology, my coding theory class was almost 30
-years ago, and I must admit it was not one of my favourites).
-
-As I said before the ecc calculation is performed on sectors of 256
-bytes. This is done by calculating several parity bits over the rows and
-columns. The parity used is even parity which means that the parity bit = 1
-if the data over which the parity is calculated is 1 and the parity bit = 0
-if the data over which the parity is calculated is 0. So the total
-number of bits over the data over which the parity is calculated + the
-parity bit is even. (see wikipedia if you can't follow this).
-Parity is often calculated by means of an exclusive or operation,
-sometimes also referred to as xor. In C the operator for xor is ^
-
-Back to ecc.
-Let's give a small figure:
-
-byte   0:  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0   rp0 rp2 rp4 ... rp14
-byte   1:  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0   rp1 rp2 rp4 ... rp14
-byte   2:  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0   rp0 rp3 rp4 ... rp14
-byte   3:  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0   rp1 rp3 rp4 ... rp14
-byte   4:  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0   rp0 rp2 rp5 ... rp14
-....
-byte 254:  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0   rp0 rp3 rp5 ... rp15
-byte 255:  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0   rp1 rp3 rp5 ... rp15
-           cp1  cp0  cp1  cp0  cp1  cp0  cp1  cp0
-           cp3  cp3  cp2  cp2  cp3  cp3  cp2  cp2
-           cp5  cp5  cp5  cp5  cp4  cp4  cp4  cp4
-
-This figure represents a sector of 256 bytes.
-cp is my abbreviation for column parity, rp for row parity.
-
-Let's start to explain column parity.
-cp0 is the parity that belongs to all bit0, bit2, bit4, bit6.
-so the sum of all bit0, bit2, bit4 and bit6 values + cp0 itself is even.
-Similarly cp1 is the sum of all bit1, bit3, bit5 and bit7.
-cp2 is the parity over bit0, bit1, bit4 and bit5
-cp3 is the parity over bit2, bit3, bit6 and bit7.
-cp4 is the parity over bit0, bit1, bit2 and bit3.
-cp5 is the parity over bit4, bit5, bit6 and bit7.
-Note that each of cp0 .. cp5 is exactly one bit.
-
-Row parity actually works almost the same.
-rp0 is the parity of all even bytes (0, 2, 4, 6, ... 252, 254)
-rp1 is the parity of all odd bytes (1, 3, 5, 7, ..., 253, 255)
-rp2 is the parity of all bytes 0, 1, 4, 5, 8, 9, ...
-(so handle two bytes, then skip 2 bytes).
-rp3 is covers the half rp2 does not cover (bytes 2, 3, 6, 7, 10, 11, ...)
-for rp4 the rule is cover 4 bytes, skip 4 bytes, cover 4 bytes, skip 4 etc.
-so rp4 calculates parity over bytes 0, 1, 2, 3, 8, 9, 10, 11, 16, ...)
-and rp5 covers the other half, so bytes 4, 5, 6, 7, 12, 13, 14, 15, 20, ..
-The story now becomes quite boring. I guess you get the idea.
-rp6 covers 8 bytes then skips 8 etc
-rp7 skips 8 bytes then covers 8 etc
-rp8 covers 16 bytes then skips 16 etc
-rp9 skips 16 bytes then covers 16 etc
-rp10 covers 32 bytes then skips 32 etc
-rp11 skips 32 bytes then covers 32 etc
-rp12 covers 64 bytes then skips 64 etc
-rp13 skips 64 bytes then covers 64 etc
-rp14 covers 128 bytes then skips 128
-rp15 skips 128 bytes then covers 128
-
-In the end the parity bits are grouped together in three bytes as
-follows:
-ECC    Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
-ECC 0   rp07  rp06  rp05  rp04  rp03  rp02  rp01  rp00
-ECC 1   rp15  rp14  rp13  rp12  rp11  rp10  rp09  rp08
-ECC 2   cp5   cp4   cp3   cp2   cp1   cp0      1     1
-
-I detected after writing this that ST application note AN1823
-(http://www.st.com/stonline/) gives a much
-nicer picture.(but they use line parity as term where I use row parity)
-Oh well, I'm graphically challenged, so suffer with me for a moment :-)
-And I could not reuse the ST picture anyway for copyright reasons.
-
-
-Attempt 0
-=========
-
-Implementing the parity calculation is pretty simple.
-In C pseudocode:
-for (i = 0; i < 256; i++)
-{
-    if (i & 0x01)
-       rp1 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp1;
-    else
-       rp0 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp0;
-    if (i & 0x02)
-       rp3 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp3;
-    else
-       rp2 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp2;
-    if (i & 0x04)
-      rp5 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp5;
-    else
-      rp4 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp4;
-    if (i & 0x08)
-      rp7 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp7;
-    else
-      rp6 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp6;
-    if (i & 0x10)
-      rp9 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp9;
-    else
-      rp8 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp8;
-    if (i & 0x20)
-      rp11 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp11;
-    else
-      rp10 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp10;
-    if (i & 0x40)
-      rp13 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp13;
-    else
-      rp12 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp12;
-    if (i & 0x80)
-      rp15 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp15;
-    else
-      rp14 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp14;
-    cp0 = bit6 ^ bit4 ^ bit2 ^ bit0 ^ cp0;
-    cp1 = bit7 ^ bit5 ^ bit3 ^ bit1 ^ cp1;
-    cp2 = bit5 ^ bit4 ^ bit1 ^ bit0 ^ cp2;
-    cp3 = bit7 ^ bit6 ^ bit3 ^ bit2 ^ cp3
-    cp4 = bit3 ^ bit2 ^ bit1 ^ bit0 ^ cp4
-    cp5 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ cp5
-}
-
-
-Analysis 0
-==========
-
-C does have bitwise operators but not really operators to do the above
-efficiently (and most hardware has no such instructions either).
-Therefore without implementing this it was clear that the code above was
-not going to bring me a Nobel prize :-)
-
-Fortunately the exclusive or operation is commutative, so we can combine
-the values in any order. So instead of calculating all the bits
-individually, let us try to rearrange things.
-For the column parity this is easy. We can just xor the bytes and in the
-end filter out the relevant bits. This is pretty nice as it will bring
-all cp calculation out of the for loop.
-
-Similarly we can first xor the bytes for the various rows.
-This leads to:
-
-
-Attempt 1
-=========
-
-const char parity[256] = {
-    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0
-};
-
-void ecc1(const unsigned char *buf, unsigned char *code)
-{
-    int i;
-    const unsigned char *bp = buf;
-    unsigned char cur;
-    unsigned char rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7;
-    unsigned char rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15;
-    unsigned char par;
-
-    par = 0;
-    rp0 = 0; rp1 = 0; rp2 = 0; rp3 = 0;
-    rp4 = 0; rp5 = 0; rp6 = 0; rp7 = 0;
-    rp8 = 0; rp9 = 0; rp10 = 0; rp11 = 0;
-    rp12 = 0; rp13 = 0; rp14 = 0; rp15 = 0;
-
-    for (i = 0; i < 256; i++)
-    {
-        cur = *bp++;
-        par ^= cur;
-        if (i & 0x01) rp1 ^= cur; else rp0 ^= cur;
-        if (i & 0x02) rp3 ^= cur; else rp2 ^= cur;
-        if (i & 0x04) rp5 ^= cur; else rp4 ^= cur;
-        if (i & 0x08) rp7 ^= cur; else rp6 ^= cur;
-        if (i & 0x10) rp9 ^= cur; else rp8 ^= cur;
-        if (i & 0x20) rp11 ^= cur; else rp10 ^= cur;
-        if (i & 0x40) rp13 ^= cur; else rp12 ^= cur;
-        if (i & 0x80) rp15 ^= cur; else rp14 ^= cur;
-    }
-    code[0] =
-        (parity[rp7] << 7) |
-        (parity[rp6] << 6) |
-        (parity[rp5] << 5) |
-        (parity[rp4] << 4) |
-        (parity[rp3] << 3) |
-        (parity[rp2] << 2) |
-        (parity[rp1] << 1) |
-        (parity[rp0]);
-    code[1] =
-        (parity[rp15] << 7) |
-        (parity[rp14] << 6) |
-        (parity[rp13] << 5) |
-        (parity[rp12] << 4) |
-        (parity[rp11] << 3) |
-        (parity[rp10] << 2) |
-        (parity[rp9]  << 1) |
-        (parity[rp8]);
-    code[2] =
-        (parity[par & 0xf0] << 7) |
-        (parity[par & 0x0f] << 6) |
-        (parity[par & 0xcc] << 5) |
-        (parity[par & 0x33] << 4) |
-        (parity[par & 0xaa] << 3) |
-        (parity[par & 0x55] << 2);
-    code[0] = ~code[0];
-    code[1] = ~code[1];
-    code[2] = ~code[2];
-}
-
-Still pretty straightforward. The last three invert statements are there to
-give a checksum of 0xff 0xff 0xff for an empty flash. In an empty flash
-all data is 0xff, so the checksum then matches.
-
-I also introduced the parity lookup. I expected this to be the fastest
-way to calculate the parity, but I will investigate alternatives later
-on.
-
-
-Analysis 1
-==========
-
-The code works, but is not terribly efficient. On my system it took
-almost 4 times as much time as the linux driver code. But hey, if it was
-*that* easy this would have been done long before.
-No pain. no gain.
-
-Fortunately there is plenty of room for improvement.
-
-In step 1 we moved from bit-wise calculation to byte-wise calculation.
-However in C we can also use the unsigned long data type and virtually
-every modern microprocessor supports 32 bit operations, so why not try
-to write our code in such a way that we process data in 32 bit chunks.
-
-Of course this means some modification as the row parity is byte by
-byte. A quick analysis:
-for the column parity we use the par variable. When extending to 32 bits
-we can in the end easily calculate rp0 and rp1 from it.
-(because par now consists of 4 bytes, contributing to rp1, rp0, rp1, rp0
-respectively, from MSB to LSB)
-also rp2 and rp3 can be easily retrieved from par as rp3 covers the
-first two MSBs and rp2 covers the last two LSBs.
-
-Note that of course now the loop is executed only 64 times (256/4).
-And note that care must taken wrt byte ordering. The way bytes are
-ordered in a long is machine dependent, and might affect us.
-Anyway, if there is an issue: this code is developed on x86 (to be
-precise: a DELL PC with a D920 Intel CPU)
-
-And of course the performance might depend on alignment, but I expect
-that the I/O buffers in the nand driver are aligned properly (and
-otherwise that should be fixed to get maximum performance).
-
-Let's give it a try...
-
-
-Attempt 2
-=========
-
-extern const char parity[256];
-
-void ecc2(const unsigned char *buf, unsigned char *code)
-{
-    int i;
-    const unsigned long *bp = (unsigned long *)buf;
-    unsigned long cur;
-    unsigned long rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7;
-    unsigned long rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15;
-    unsigned long par;
-
-    par = 0;
-    rp0 = 0; rp1 = 0; rp2 = 0; rp3 = 0;
-    rp4 = 0; rp5 = 0; rp6 = 0; rp7 = 0;
-    rp8 = 0; rp9 = 0; rp10 = 0; rp11 = 0;
-    rp12 = 0; rp13 = 0; rp14 = 0; rp15 = 0;
-
-    for (i = 0; i < 64; i++)
-    {
-        cur = *bp++;
-        par ^= cur;
-        if (i & 0x01) rp5 ^= cur; else rp4 ^= cur;
-        if (i & 0x02) rp7 ^= cur; else rp6 ^= cur;
-        if (i & 0x04) rp9 ^= cur; else rp8 ^= cur;
-        if (i & 0x08) rp11 ^= cur; else rp10 ^= cur;
-        if (i & 0x10) rp13 ^= cur; else rp12 ^= cur;
-        if (i & 0x20) rp15 ^= cur; else rp14 ^= cur;
-    }
-    /*
-       we need to adapt the code generation for the fact that rp vars are now
-       long; also the column parity calculation needs to be changed.
-       we'll bring rp4 to 15 back to single byte entities by shifting and
-       xoring
-    */
-    rp4 ^= (rp4 >> 16); rp4 ^= (rp4 >> 8); rp4 &= 0xff;
-    rp5 ^= (rp5 >> 16); rp5 ^= (rp5 >> 8); rp5 &= 0xff;
-    rp6 ^= (rp6 >> 16); rp6 ^= (rp6 >> 8); rp6 &= 0xff;
-    rp7 ^= (rp7 >> 16); rp7 ^= (rp7 >> 8); rp7 &= 0xff;
-    rp8 ^= (rp8 >> 16); rp8 ^= (rp8 >> 8); rp8 &= 0xff;
-    rp9 ^= (rp9 >> 16); rp9 ^= (rp9 >> 8); rp9 &= 0xff;
-    rp10 ^= (rp10 >> 16); rp10 ^= (rp10 >> 8); rp10 &= 0xff;
-    rp11 ^= (rp11 >> 16); rp11 ^= (rp11 >> 8); rp11 &= 0xff;
-    rp12 ^= (rp12 >> 16); rp12 ^= (rp12 >> 8); rp12 &= 0xff;
-    rp13 ^= (rp13 >> 16); rp13 ^= (rp13 >> 8); rp13 &= 0xff;
-    rp14 ^= (rp14 >> 16); rp14 ^= (rp14 >> 8); rp14 &= 0xff;
-    rp15 ^= (rp15 >> 16); rp15 ^= (rp15 >> 8); rp15 &= 0xff;
-    rp3 = (par >> 16); rp3 ^= (rp3 >> 8); rp3 &= 0xff;
-    rp2 = par & 0xffff; rp2 ^= (rp2 >> 8); rp2 &= 0xff;
-    par ^= (par >> 16);
-    rp1 = (par >> 8); rp1 &= 0xff;
-    rp0 = (par & 0xff);
-    par ^= (par >> 8); par &= 0xff;
-
-    code[0] =
-        (parity[rp7] << 7) |
-        (parity[rp6] << 6) |
-        (parity[rp5] << 5) |
-        (parity[rp4] << 4) |
-        (parity[rp3] << 3) |
-        (parity[rp2] << 2) |
-        (parity[rp1] << 1) |
-        (parity[rp0]);
-    code[1] =
-        (parity[rp15] << 7) |
-        (parity[rp14] << 6) |
-        (parity[rp13] << 5) |
-        (parity[rp12] << 4) |
-        (parity[rp11] << 3) |
-        (parity[rp10] << 2) |
-        (parity[rp9]  << 1) |
-        (parity[rp8]);
-    code[2] =
-        (parity[par & 0xf0] << 7) |
-        (parity[par & 0x0f] << 6) |
-        (parity[par & 0xcc] << 5) |
-        (parity[par & 0x33] << 4) |
-        (parity[par & 0xaa] << 3) |
-        (parity[par & 0x55] << 2);
-    code[0] = ~code[0];
-    code[1] = ~code[1];
-    code[2] = ~code[2];
-}
-
-The parity array is not shown any more. Note also that for these
-examples I kinda deviated from my regular programming style by allowing
-multiple statements on a line, not using { } in then and else blocks
-with only a single statement and by using operators like ^=
-
-
-Analysis 2
-==========
-
-The code (of course) works, and hurray: we are a little bit faster than
-the linux driver code (about 15%). But wait, don't cheer too quickly.
-There is more to be gained.
-If we look at e.g. rp14 and rp15 we see that we either xor our data with
-rp14 or with rp15. However we also have par which goes over all data.
-This means there is no need to calculate rp14 as it can be calculated from
-rp15 through rp14 = par ^ rp15, because par = rp14 ^ rp15;
-(or if desired we can avoid calculating rp15 and calculate it from
-rp14).  That is why some places refer to inverse parity.
-Of course the same thing holds for rp4/5, rp6/7, rp8/9, rp10/11 and rp12/13.
-Effectively this means we can eliminate the else clause from the if
-statements. Also we can optimise the calculation in the end a little bit
-by going from long to byte first. Actually we can even avoid the table
-lookups
-
-Attempt 3
-=========
-
-Odd replaced:
-        if (i & 0x01) rp5 ^= cur; else rp4 ^= cur;
-        if (i & 0x02) rp7 ^= cur; else rp6 ^= cur;
-        if (i & 0x04) rp9 ^= cur; else rp8 ^= cur;
-        if (i & 0x08) rp11 ^= cur; else rp10 ^= cur;
-        if (i & 0x10) rp13 ^= cur; else rp12 ^= cur;
-        if (i & 0x20) rp15 ^= cur; else rp14 ^= cur;
-with
-        if (i & 0x01) rp5 ^= cur;
-        if (i & 0x02) rp7 ^= cur;
-        if (i & 0x04) rp9 ^= cur;
-        if (i & 0x08) rp11 ^= cur;
-        if (i & 0x10) rp13 ^= cur;
-        if (i & 0x20) rp15 ^= cur;
-
-        and outside the loop added:
-        rp4  = par ^ rp5;
-        rp6  = par ^ rp7;
-        rp8  = par ^ rp9;
-        rp10  = par ^ rp11;
-        rp12  = par ^ rp13;
-        rp14  = par ^ rp15;
-
-And after that the code takes about 30% more time, although the number of
-statements is reduced. This is also reflected in the assembly code.
-
-
-Analysis 3
-==========
-
-Very weird. Guess it has to do with caching or instruction parallellism
-or so. I also tried on an eeePC (Celeron, clocked at 900 Mhz). Interesting
-observation was that this one is only 30% slower (according to time)
-executing the code as my 3Ghz D920 processor.
-
-Well, it was expected not to be easy so maybe instead move to a
-different track: let's move back to the code from attempt2 and do some
-loop unrolling. This will eliminate a few if statements. I'll try
-different amounts of unrolling to see what works best.
-
-
-Attempt 4
-=========
-
-Unrolled the loop 1, 2, 3 and 4 times.
-For 4 the code starts with:
-
-    for (i = 0; i < 4; i++)
-    {
-        cur = *bp++;
-        par ^= cur;
-        rp4 ^= cur;
-        rp6 ^= cur;
-        rp8 ^= cur;
-        rp10 ^= cur;
-        if (i & 0x1) rp13 ^= cur; else rp12 ^= cur;
-        if (i & 0x2) rp15 ^= cur; else rp14 ^= cur;
-        cur = *bp++;
-        par ^= cur;
-        rp5 ^= cur;
-        rp6 ^= cur;
-        ...
-
-
-Analysis 4
-==========
-
-Unrolling once gains about 15%
-Unrolling twice keeps the gain at about 15%
-Unrolling three times gives a gain of 30% compared to attempt 2.
-Unrolling four times gives a marginal improvement compared to unrolling
-three times.
-
-I decided to proceed with a four time unrolled loop anyway. It was my gut
-feeling that in the next steps I would obtain additional gain from it.
-
-The next step was triggered by the fact that par contains the xor of all
-bytes and rp4 and rp5 each contain the xor of half of the bytes.
-So in effect par = rp4 ^ rp5. But as xor is commutative we can also say
-that rp5 = par ^ rp4. So no need to keep both rp4 and rp5 around. We can
-eliminate rp5 (or rp4, but I already foresaw another optimisation).
-The same holds for rp6/7, rp8/9, rp10/11 rp12/13 and rp14/15.
-
-
-Attempt 5
-=========
-
-Effectively so all odd digit rp assignments in the loop were removed.
-This included the else clause of the if statements.
-Of course after the loop we need to correct things by adding code like:
-    rp5 = par ^ rp4;
-Also the initial assignments (rp5 = 0; etc) could be removed.
-Along the line I also removed the initialisation of rp0/1/2/3.
-
-
-Analysis 5
-==========
-
-Measurements showed this was a good move. The run-time roughly halved
-compared with attempt 4 with 4 times unrolled, and we only require 1/3rd
-of the processor time compared to the current code in the linux kernel.
-
-However, still I thought there was more. I didn't like all the if
-statements. Why not keep a running parity and only keep the last if
-statement. Time for yet another version!
-
-
-Attempt 6
-=========
-
-THe code within the for loop was changed to:
-
-    for (i = 0; i < 4; i++)
-    {
-        cur = *bp++; tmppar  = cur; rp4 ^= cur;
-        cur = *bp++; tmppar ^= cur; rp6 ^= tmppar;
-        cur = *bp++; tmppar ^= cur; rp4 ^= cur;
-        cur = *bp++; tmppar ^= cur; rp8 ^= tmppar;
-
-        cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp6 ^= cur;
-        cur = *bp++; tmppar ^= cur; rp6 ^= cur;
-        cur = *bp++; tmppar ^= cur; rp4 ^= cur;
-        cur = *bp++; tmppar ^= cur; rp10 ^= tmppar;
-
-        cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp6 ^= cur; rp8 ^= cur;
-        cur = *bp++; tmppar ^= cur; rp6 ^= cur; rp8 ^= cur;
-        cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp8 ^= cur;
-        cur = *bp++; tmppar ^= cur; rp8 ^= cur;
-
-        cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp6 ^= cur;
-        cur = *bp++; tmppar ^= cur; rp6 ^= cur;
-        cur = *bp++; tmppar ^= cur; rp4 ^= cur;
-        cur = *bp++; tmppar ^= cur;
-
-        par ^= tmppar;
-        if ((i & 0x1) == 0) rp12 ^= tmppar;
-        if ((i & 0x2) == 0) rp14 ^= tmppar;
-    }
-
-As you can see tmppar is used to accumulate the parity within a for
-iteration. In the last 3 statements is added to par and, if needed,
-to rp12 and rp14.
-
-While making the changes I also found that I could exploit that tmppar
-contains the running parity for this iteration. So instead of having:
-rp4 ^= cur; rp6 ^= cur;
-I removed the rp6 ^= cur; statement and did rp6 ^= tmppar; on next
-statement. A similar change was done for rp8 and rp10
-
-
-Analysis 6
-==========
-
-Measuring this code again showed big gain. When executing the original
-linux code 1 million times, this took about 1 second on my system.
-(using time to measure the performance). After this iteration I was back
-to 0.075 sec. Actually I had to decide to start measuring over 10
-million iterations in order not to lose too much accuracy. This one
-definitely seemed to be the jackpot!
-
-There is a little bit more room for improvement though. There are three
-places with statements:
-rp4 ^= cur; rp6 ^= cur;
-It seems more efficient to also maintain a variable rp4_6 in the while
-loop; This eliminates 3 statements per loop. Of course after the loop we
-need to correct by adding:
-    rp4 ^= rp4_6;
-    rp6 ^= rp4_6
-Furthermore there are 4 sequential assignments to rp8. This can be
-encoded slightly more efficiently by saving tmppar before those 4 lines
-and later do rp8 = rp8 ^ tmppar ^ notrp8;
-(where notrp8 is the value of rp8 before those 4 lines).
-Again a use of the commutative property of xor.
-Time for a new test!
-
-
-Attempt 7
-=========
-
-The new code now looks like:
-
-    for (i = 0; i < 4; i++)
-    {
-        cur = *bp++; tmppar  = cur; rp4 ^= cur;
-        cur = *bp++; tmppar ^= cur; rp6 ^= tmppar;
-        cur = *bp++; tmppar ^= cur; rp4 ^= cur;
-        cur = *bp++; tmppar ^= cur; rp8 ^= tmppar;
-
-        cur = *bp++; tmppar ^= cur; rp4_6 ^= cur;
-        cur = *bp++; tmppar ^= cur; rp6 ^= cur;
-        cur = *bp++; tmppar ^= cur; rp4 ^= cur;
-        cur = *bp++; tmppar ^= cur; rp10 ^= tmppar;
-
-        notrp8 = tmppar;
-        cur = *bp++; tmppar ^= cur; rp4_6 ^= cur;
-        cur = *bp++; tmppar ^= cur; rp6 ^= cur;
-        cur = *bp++; tmppar ^= cur; rp4 ^= cur;
-        cur = *bp++; tmppar ^= cur;
-        rp8 = rp8 ^ tmppar ^ notrp8;
-
-        cur = *bp++; tmppar ^= cur; rp4_6 ^= cur;
-        cur = *bp++; tmppar ^= cur; rp6 ^= cur;
-        cur = *bp++; tmppar ^= cur; rp4 ^= cur;
-        cur = *bp++; tmppar ^= cur;
-
-        par ^= tmppar;
-        if ((i & 0x1) == 0) rp12 ^= tmppar;
-        if ((i & 0x2) == 0) rp14 ^= tmppar;
-    }
-    rp4 ^= rp4_6;
-    rp6 ^= rp4_6;
-
-
-Not a big change, but every penny counts :-)
-
-
-Analysis 7
-==========
-
-Actually this made things worse. Not very much, but I don't want to move
-into the wrong direction. Maybe something to investigate later. Could
-have to do with caching again.
-
-Guess that is what there is to win within the loop. Maybe unrolling one
-more time will help. I'll keep the optimisations from 7 for now.
-
-
-Attempt 8
-=========
-
-Unrolled the loop one more time.
-
-
-Analysis 8
-==========
-
-This makes things worse. Let's stick with attempt 6 and continue from there.
-Although it seems that the code within the loop cannot be optimised
-further there is still room to optimize the generation of the ecc codes.
-We can simply calculate the total parity. If this is 0 then rp4 = rp5
-etc. If the parity is 1, then rp4 = !rp5;
-But if rp4 = rp5 we do not need rp5 etc. We can just write the even bits
-in the result byte and then do something like
-    code[0] |= (code[0] << 1);
-Lets test this.
-
-
-Attempt 9
-=========
-
-Changed the code but again this slightly degrades performance. Tried all
-kind of other things, like having dedicated parity arrays to avoid the
-shift after parity[rp7] << 7; No gain.
-Change the lookup using the parity array by using shift operators (e.g.
-replace parity[rp7] << 7 with:
-rp7 ^= (rp7 << 4);
-rp7 ^= (rp7 << 2);
-rp7 ^= (rp7 << 1);
-rp7 &= 0x80;
-No gain.
-
-The only marginal change was inverting the parity bits, so we can remove
-the last three invert statements.
-
-Ah well, pity this does not deliver more. Then again 10 million
-iterations using the linux driver code takes between 13 and 13.5
-seconds, whereas my code now takes about 0.73 seconds for those 10
-million iterations. So basically I've improved the performance by a
-factor 18 on my system. Not that bad. Of course on different hardware
-you will get different results. No warranties!
-
-But of course there is no such thing as a free lunch. The codesize almost
-tripled (from 562 bytes to 1434 bytes). Then again, it is not that much.
-
-
-Correcting errors
-=================
-
-For correcting errors I again used the ST application note as a starter,
-but I also peeked at the existing code.
-The algorithm itself is pretty straightforward. Just xor the given and
-the calculated ecc. If all bytes are 0 there is no problem. If 11 bits
-are 1 we have one correctable bit error. If there is 1 bit 1, we have an
-error in the given ecc code.
-It proved to be fastest to do some table lookups. Performance gain
-introduced by this is about a factor 2 on my system when a repair had to
-be done, and 1% or so if no repair had to be done.
-Code size increased from 330 bytes to 686 bytes for this function.
-(gcc 4.2, -O3)
-
-
-Conclusion
-==========
-
-The gain when calculating the ecc is tremendous. Om my development hardware
-a speedup of a factor of 18 for ecc calculation was achieved. On a test on an
-embedded system with a MIPS core a factor 7 was obtained.
-On a test with a Linksys NSLU2 (ARMv5TE processor) the speedup was a factor
-5 (big endian mode, gcc 4.1.2, -O3)
-For correction not much gain could be obtained (as bitflips are rare). Then
-again there are also much less cycles spent there.
-
-It seems there is not much more gain possible in this, at least when
-programmed in C. Of course it might be possible to squeeze something more
-out of it with an assembler program, but due to pipeline behaviour etc
-this is very tricky (at least for intel hw).
-
-Author: Frans Meulenbroeks
-Copyright (C) 2008 Koninklijke Philips Electronics NV.
diff --git a/Documentation/mtd/spi-nor.txt b/Documentation/mtd/spi-nor.txt
deleted file mode 100644 (file)
index da1fbff..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-                          SPI NOR framework
-               ============================================
-
-Part I - Why do we need this framework?
----------------------------------------
-
-SPI bus controllers (drivers/spi/) only deal with streams of bytes; the bus
-controller operates agnostic of the specific device attached. However, some
-controllers (such as Freescale's QuadSPI controller) cannot easily handle
-arbitrary streams of bytes, but rather are designed specifically for SPI NOR.
-
-In particular, Freescale's QuadSPI controller must know the NOR commands to
-find the right LUT sequence. Unfortunately, the SPI subsystem has no notion of
-opcodes, addresses, or data payloads; a SPI controller simply knows to send or
-receive bytes (Tx and Rx). Therefore, we must define a new layering scheme under
-which the controller driver is aware of the opcodes, addressing, and other
-details of the SPI NOR protocol.
-
-Part II - How does the framework work?
---------------------------------------
-
-This framework just adds a new layer between the MTD and the SPI bus driver.
-With this new layer, the SPI NOR controller driver does not depend on the
-m25p80 code anymore.
-
-   Before this framework, the layer is like:
-
-                   MTD
-         ------------------------
-                  m25p80
-         ------------------------
-              SPI bus driver
-         ------------------------
-               SPI NOR chip
-
-   After this framework, the layer is like:
-                   MTD
-         ------------------------
-              SPI NOR framework
-         ------------------------
-                  m25p80
-         ------------------------
-              SPI bus driver
-         ------------------------
-              SPI NOR chip
-
-  With the SPI NOR controller driver (Freescale QuadSPI), it looks like:
-                   MTD
-         ------------------------
-              SPI NOR framework
-         ------------------------
-                fsl-quadSPI
-         ------------------------
-              SPI NOR chip
-
-Part III - How can drivers use the framework?
----------------------------------------------
-
-The main API is spi_nor_scan(). Before you call the hook, a driver should
-initialize the necessary fields for spi_nor{}. Please see
-drivers/mtd/spi-nor/spi-nor.c for detail. Please also refer to fsl-quadspi.c
-when you want to write a new driver for a SPI NOR controller.
-Another API is spi_nor_restore(), this is used to restore the status of SPI
-flash chip such as addressing mode. Call it whenever detach the driver from
-device or reboot the system.
diff --git a/Documentation/namespaces/compatibility-list.txt b/Documentation/namespaces/compatibility-list.txt
deleted file mode 100644 (file)
index defc558..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-       Namespaces compatibility list
-
-This document contains the information about the problems user
-may have when creating tasks living in different namespaces.
-
-Here's the summary. This matrix shows the known problems, that
-occur when tasks share some namespace (the columns) while living
-in different other namespaces (the rows):
-
-       UTS     IPC     VFS     PID     User    Net
-UTS     X
-IPC             X       1
-VFS                     X
-PID             1       1       X
-User            2       2               X
-Net                                             X
-
-1. Both the IPC and the PID namespaces provide IDs to address
-   object inside the kernel. E.g. semaphore with IPCID or
-   process group with pid.
-
-   In both cases, tasks shouldn't try exposing this ID to some
-   other task living in a different namespace via a shared filesystem
-   or IPC shmem/message. The fact is that this ID is only valid
-   within the namespace it was obtained in and may refer to some
-   other object in another namespace.
-
-2. Intentionally, two equal user IDs in different user namespaces
-   should not be equal from the VFS point of view. In other
-   words, user 10 in one user namespace shouldn't have the same
-   access permissions to files, belonging to user 10 in another
-   namespace.
-
-   The same is true for the IPC namespaces being shared - two users
-   from different user namespaces should not access the same IPC objects
-   even having equal UIDs.
-
-   But currently this is not so.
-
diff --git a/Documentation/namespaces/resource-control.txt b/Documentation/namespaces/resource-control.txt
deleted file mode 100644 (file)
index abc13c3..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-There are a lot of kinds of objects in the kernel that don't have
-individual limits or that have limits that are ineffective when a set
-of processes is allowed to switch user ids.  With user namespaces
-enabled in a kernel for people who don't trust their users or their
-users programs to play nice this problems becomes more acute.
-
-Therefore it is recommended that memory control groups be enabled in
-kernels that enable user namespaces, and it is further recommended
-that userspace configure memory control groups to limit how much
-memory user's they don't trust to play nice can use.
-
-Memory control groups can be configured by installing the libcgroup
-package present on most distros editing /etc/cgrules.conf,
-/etc/cgconfig.conf and setting up libpam-cgroup.
index 47f1e0e..984e1b1 100644 (file)
@@ -1,4 +1,4 @@
-:orphan:
+.. SPDX-License-Identifier: GPL-2.0
 
 ========
 NetLabel
index d3e5dd2..e3abfbd 100644 (file)
@@ -706,9 +706,9 @@ num_unsol_na
        unsolicited IPv6 Neighbor Advertisements) to be issued after a
        failover event.  As soon as the link is up on the new slave
        (possibly immediately) a peer notification is sent on the
-       bonding device and each VLAN sub-device.  This is repeated at
-       each link monitor interval (arp_interval or miimon, whichever
-       is active) if the number is greater than 1.
+       bonding device and each VLAN sub-device. This is repeated at
+       the rate specified by peer_notif_delay if the number is
+       greater than 1.
 
        The valid range is 0 - 255; the default value is 1.  These options
        affect only the active-backup mode.  These options were added for
@@ -727,6 +727,16 @@ packets_per_slave
        The valid range is 0 - 65535; the default value is 1. This option
        has effect only in balance-rr mode.
 
+peer_notif_delay
+
+        Specify the delay, in milliseconds, between each peer
+        notification (gratuitous ARP and unsolicited IPv6 Neighbor
+        Advertisement) when they are issued after a failover event.
+        This delay should be a multiple of the link monitor interval
+        (arp_interval or miimon, whichever is active). The default
+        value is 0 which means to match the value of the link monitor
+        interval.
+
 primary
 
        A string (eth0, eth2, etc) specifying which slave is the
index 48c79e7..df33674 100644 (file)
@@ -2287,7 +2287,7 @@ addr_scope_policy - INTEGER
 
 
 /proc/sys/net/core/*
-       Please see: Documentation/sysctl/net.txt for descriptions of these entries.
+       Please see: Documentation/admin-guide/sysctl/net.rst for descriptions of these entries.
 
 
 /proc/sys/net/unix/*
diff --git a/Documentation/nfc/nfc-hci.txt b/Documentation/nfc/nfc-hci.txt
deleted file mode 100644 (file)
index 0dc078c..0000000
+++ /dev/null
@@ -1,290 +0,0 @@
-HCI backend for NFC Core
-
-Author: Eric Lapuyade, Samuel Ortiz
-Contact: eric.lapuyade@intel.com, samuel.ortiz@intel.com
-
-General
--------
-
-The HCI layer implements much of the ETSI TS 102 622 V10.2.0 specification. It
-enables easy writing of HCI-based NFC drivers. The HCI layer runs as an NFC Core
-backend, implementing an abstract nfc device and translating NFC Core API
-to HCI commands and events.
-
-HCI
----
-
-HCI registers as an nfc device with NFC Core. Requests coming from userspace are
-routed through netlink sockets to NFC Core and then to HCI. From this point,
-they are translated in a sequence of HCI commands sent to the HCI layer in the
-host controller (the chip). Commands can be executed synchronously (the sending
-context blocks waiting for response) or asynchronously (the response is returned
-from HCI Rx context).
-HCI events can also be received from the host controller. They will be handled
-and a translation will be forwarded to NFC Core as needed. There are hooks to
-let the HCI driver handle proprietary events or override standard behavior.
-HCI uses 2 execution contexts:
-- one for executing commands : nfc_hci_msg_tx_work(). Only one command
-can be executing at any given moment.
-- one for dispatching received events and commands : nfc_hci_msg_rx_work().
-
-HCI Session initialization:
----------------------------
-
-The Session initialization is an HCI standard which must unfortunately
-support proprietary gates. This is the reason why the driver will pass a list
-of proprietary gates that must be part of the session. HCI will ensure all
-those gates have pipes connected when the hci device is set up.
-In case the chip supports pre-opened gates and pseudo-static pipes, the driver
-can pass that information to HCI core.
-
-HCI Gates and Pipes
--------------------
-
-A gate defines the 'port' where some service can be found. In order to access
-a service, one must create a pipe to that gate and open it. In this
-implementation, pipes are totally hidden. The public API only knows gates.
-This is consistent with the driver need to send commands to proprietary gates
-without knowing the pipe connected to it.
-
-Driver interface
-----------------
-
-A driver is generally written in two parts : the physical link management and
-the HCI management. This makes it easier to maintain a driver for a chip that
-can be connected using various phy (i2c, spi, ...)
-
-HCI Management
---------------
-
-A driver would normally register itself with HCI and provide the following
-entry points:
-
-struct nfc_hci_ops {
-       int (*open)(struct nfc_hci_dev *hdev);
-       void (*close)(struct nfc_hci_dev *hdev);
-       int (*hci_ready) (struct nfc_hci_dev *hdev);
-       int (*xmit) (struct nfc_hci_dev *hdev, struct sk_buff *skb);
-       int (*start_poll) (struct nfc_hci_dev *hdev,
-                          u32 im_protocols, u32 tm_protocols);
-       int (*dep_link_up)(struct nfc_hci_dev *hdev, struct nfc_target *target,
-                          u8 comm_mode, u8 *gb, size_t gb_len);
-       int (*dep_link_down)(struct nfc_hci_dev *hdev);
-       int (*target_from_gate) (struct nfc_hci_dev *hdev, u8 gate,
-                                struct nfc_target *target);
-       int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate,
-                                          struct nfc_target *target);
-       int (*im_transceive) (struct nfc_hci_dev *hdev,
-                             struct nfc_target *target, struct sk_buff *skb,
-                             data_exchange_cb_t cb, void *cb_context);
-       int (*tm_send)(struct nfc_hci_dev *hdev, struct sk_buff *skb);
-       int (*check_presence)(struct nfc_hci_dev *hdev,
-                             struct nfc_target *target);
-       int (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event,
-                             struct sk_buff *skb);
-};
-
-- open() and close() shall turn the hardware on and off.
-- hci_ready() is an optional entry point that is called right after the hci
-session has been set up. The driver can use it to do additional initialization
-that must be performed using HCI commands.
-- xmit() shall simply write a frame to the physical link.
-- start_poll() is an optional entrypoint that shall set the hardware in polling
-mode. This must be implemented only if the hardware uses proprietary gates or a
-mechanism slightly different from the HCI standard.
-- dep_link_up() is called after a p2p target has been detected, to finish
-the p2p connection setup with hardware parameters that need to be passed back
-to nfc core.
-- dep_link_down() is called to bring the p2p link down.
-- target_from_gate() is an optional entrypoint to return the nfc protocols
-corresponding to a proprietary gate.
-- complete_target_discovered() is an optional entry point to let the driver
-perform additional proprietary processing necessary to auto activate the
-discovered target.
-- im_transceive() must be implemented by the driver if proprietary HCI commands
-are required to send data to the tag. Some tag types will require custom
-commands, others can be written to using the standard HCI commands. The driver
-can check the tag type and either do proprietary processing, or return 1 to ask
-for standard processing. The data exchange command itself must be sent
-asynchronously.
-- tm_send() is called to send data in the case of a p2p connection
-- check_presence() is an optional entry point that will be called regularly
-by the core to check that an activated tag is still in the field. If this is
-not implemented, the core will not be able to push tag_lost events to the user
-space
-- event_received() is called to handle an event coming from the chip. Driver
-can handle the event or return 1 to let HCI attempt standard processing.
-
-On the rx path, the driver is responsible to push incoming HCP frames to HCI
-using nfc_hci_recv_frame(). HCI will take care of re-aggregation and handling
-This must be done from a context that can sleep.
-
-PHY Management
---------------
-
-The physical link (i2c, ...) management is defined by the following structure:
-
-struct nfc_phy_ops {
-       int (*write)(void *dev_id, struct sk_buff *skb);
-       int (*enable)(void *dev_id);
-       void (*disable)(void *dev_id);
-};
-
-enable(): turn the phy on (power on), make it ready to transfer data
-disable(): turn the phy off
-write(): Send a data frame to the chip. Note that to enable higher
-layers such as an llc to store the frame for re-emission, this function must
-not alter the skb. It must also not return a positive result (return 0 for
-success, negative for failure).
-
-Data coming from the chip shall be sent directly to nfc_hci_recv_frame().
-
-LLC
----
-
-Communication between the CPU and the chip often requires some link layer
-protocol. Those are isolated as modules managed by the HCI layer. There are
-currently two modules : nop (raw transfert) and shdlc.
-A new llc must implement the following functions:
-
-struct nfc_llc_ops {
-       void *(*init) (struct nfc_hci_dev *hdev, xmit_to_drv_t xmit_to_drv,
-                      rcv_to_hci_t rcv_to_hci, int tx_headroom,
-                      int tx_tailroom, int *rx_headroom, int *rx_tailroom,
-                      llc_failure_t llc_failure);
-       void (*deinit) (struct nfc_llc *llc);
-       int (*start) (struct nfc_llc *llc);
-       int (*stop) (struct nfc_llc *llc);
-       void (*rcv_from_drv) (struct nfc_llc *llc, struct sk_buff *skb);
-       int (*xmit_from_hci) (struct nfc_llc *llc, struct sk_buff *skb);
-};
-
-- init() : allocate and init your private storage
-- deinit() : cleanup
-- start() : establish the logical connection
-- stop () : terminate the logical connection
-- rcv_from_drv() : handle data coming from the chip, going to HCI
-- xmit_from_hci() : handle data sent by HCI, going to the chip
-
-The llc must be registered with nfc before it can be used. Do that by
-calling nfc_llc_register(const char *name, struct nfc_llc_ops *ops);
-
-Again, note that the llc does not handle the physical link. It is thus very
-easy to mix any physical link with any llc for a given chip driver.
-
-Included Drivers
-----------------
-
-An HCI based driver for an NXP PN544, connected through I2C bus, and using
-shdlc is included.
-
-Execution Contexts
-------------------
-
-The execution contexts are the following:
-- IRQ handler (IRQH):
-fast, cannot sleep. sends incoming frames to HCI where they are passed to
-the current llc. In case of shdlc, the frame is queued in shdlc rx queue.
-
-- SHDLC State Machine worker (SMW)
-Only when llc_shdlc is used: handles shdlc rx & tx queues.
-Dispatches HCI cmd responses.
-
-- HCI Tx Cmd worker (MSGTXWQ)
-Serializes execution of HCI commands. Completes execution in case of response
-timeout.
-
-- HCI Rx worker (MSGRXWQ)
-Dispatches incoming HCI commands or events.
-
-- Syscall context from a userspace call (SYSCALL)
-Any entrypoint in HCI called from NFC Core
-
-Workflow executing an HCI command (using shdlc)
------------------------------------------------
-
-Executing an HCI command can easily be performed synchronously using the
-following API:
-
-int nfc_hci_send_cmd (struct nfc_hci_dev *hdev, u8 gate, u8 cmd,
-                       const u8 *param, size_t param_len, struct sk_buff **skb)
-
-The API must be invoked from a context that can sleep. Most of the time, this
-will be the syscall context. skb will return the result that was received in
-the response.
-
-Internally, execution is asynchronous. So all this API does is to enqueue the
-HCI command, setup a local wait queue on stack, and wait_event() for completion.
-The wait is not interruptible because it is guaranteed that the command will
-complete after some short timeout anyway.
-
-MSGTXWQ context will then be scheduled and invoke nfc_hci_msg_tx_work().
-This function will dequeue the next pending command and send its HCP fragments
-to the lower layer which happens to be shdlc. It will then start a timer to be
-able to complete the command with a timeout error if no response arrive.
-
-SMW context gets scheduled and invokes nfc_shdlc_sm_work(). This function
-handles shdlc framing in and out. It uses the driver xmit to send frames and
-receives incoming frames in an skb queue filled from the driver IRQ handler.
-SHDLC I(nformation) frames payload are HCP fragments. They are aggregated to
-form complete HCI frames, which can be a response, command, or event.
-
-HCI Responses are dispatched immediately from this context to unblock
-waiting command execution. Response processing involves invoking the completion
-callback that was provided by nfc_hci_msg_tx_work() when it sent the command.
-The completion callback will then wake the syscall context.
-
-It is also possible to execute the command asynchronously using this API:
-
-static int nfc_hci_execute_cmd_async(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
-                              const u8 *param, size_t param_len,
-                              data_exchange_cb_t cb, void *cb_context)
-
-The workflow is the same, except that the API call returns immediately, and
-the callback will be called with the result from the SMW context.
-
-Workflow receiving an HCI event or command
-------------------------------------------
-
-HCI commands or events are not dispatched from SMW context. Instead, they are
-queued to HCI rx_queue and will be dispatched from HCI rx worker
-context (MSGRXWQ). This is done this way to allow a cmd or event handler
-to also execute other commands (for example, handling the
-NFC_HCI_EVT_TARGET_DISCOVERED event from PN544 requires to issue an
-ANY_GET_PARAMETER to the reader A gate to get information on the target
-that was discovered).
-
-Typically, such an event will be propagated to NFC Core from MSGRXWQ context.
-
-Error management
-----------------
-
-Errors that occur synchronously with the execution of an NFC Core request are
-simply returned as the execution result of the request. These are easy.
-
-Errors that occur asynchronously (e.g. in a background protocol handling thread)
-must be reported such that upper layers don't stay ignorant that something
-went wrong below and know that expected events will probably never happen.
-Handling of these errors is done as follows:
-
-- driver (pn544) fails to deliver an incoming frame: it stores the error such
-that any subsequent call to the driver will result in this error. Then it calls
-the standard nfc_shdlc_recv_frame() with a NULL argument to report the problem
-above. shdlc stores a EREMOTEIO sticky status, which will trigger SMW to
-report above in turn.
-
-- SMW is basically a background thread to handle incoming and outgoing shdlc
-frames. This thread will also check the shdlc sticky status and report to HCI
-when it discovers it is not able to run anymore because of an unrecoverable
-error that happened within shdlc or below. If the problem occurs during shdlc
-connection, the error is reported through the connect completion.
-
-- HCI: if an internal HCI error happens (frame is lost), or HCI is reported an
-error from a lower layer, HCI will either complete the currently executing
-command with that error, or notify NFC Core directly if no command is executing.
-
-- NFC Core: when NFC Core is notified of an error from below and polling is
-active, it will send a tag discovered event with an empty tag list to the user
-space to let it know that the poll operation will never be able to detect a tag.
-If polling is not active and the error was sticky, lower levels will return it
-at next invocation.
diff --git a/Documentation/nfc/nfc-pn544.txt b/Documentation/nfc/nfc-pn544.txt
deleted file mode 100644 (file)
index b36ca14..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-Kernel driver for the NXP Semiconductors PN544 Near Field
-Communication chip
-
-General
--------
-
-The PN544 is an integrated transmission module for contactless
-communication. The driver goes under drives/nfc/ and is compiled as a
-module named "pn544".
-
-Host Interfaces: I2C, SPI and HSU, this driver supports currently only I2C.
-
-Protocols
----------
-
-In the normal (HCI) mode and in the firmware update mode read and
-write functions behave a bit differently because the message formats
-or the protocols are different.
-
-In the normal (HCI) mode the protocol used is derived from the ETSI
-HCI specification. The firmware is updated using a specific protocol,
-which is different from HCI.
-
-HCI messages consist of an eight bit header and the message body. The
-header contains the message length. Maximum size for an HCI message is
-33. In HCI mode sent messages are tested for a correct
-checksum. Firmware update messages have the length in the second (MSB)
-and third (LSB) bytes of the message. The maximum FW message length is
-1024 bytes.
-
-For the ETSI HCI specification see
-http://www.etsi.org/WebSite/Technologies/ProtocolSpecification.aspx
diff --git a/Documentation/ntb.txt b/Documentation/ntb.txt
deleted file mode 100644 (file)
index 074a423..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-===========
-NTB Drivers
-===========
-
-NTB (Non-Transparent Bridge) is a type of PCI-Express bridge chip that connects
-the separate memory systems of two or more computers to the same PCI-Express
-fabric. Existing NTB hardware supports a common feature set: doorbell
-registers and memory translation windows, as well as non common features like
-scratchpad and message registers. Scratchpad registers are read-and-writable
-registers that are accessible from either side of the device, so that peers can
-exchange a small amount of information at a fixed address. Message registers can
-be utilized for the same purpose. Additionally they are provided with with
-special status bits to make sure the information isn't rewritten by another
-peer. Doorbell registers provide a way for peers to send interrupt events.
-Memory windows allow translated read and write access to the peer memory.
-
-NTB Core Driver (ntb)
-=====================
-
-The NTB core driver defines an api wrapping the common feature set, and allows
-clients interested in NTB features to discover NTB the devices supported by
-hardware drivers.  The term "client" is used here to mean an upper layer
-component making use of the NTB api.  The term "driver," or "hardware driver,"
-is used here to mean a driver for a specific vendor and model of NTB hardware.
-
-NTB Client Drivers
-==================
-
-NTB client drivers should register with the NTB core driver.  After
-registering, the client probe and remove functions will be called appropriately
-as ntb hardware, or hardware drivers, are inserted and removed.  The
-registration uses the Linux Device framework, so it should feel familiar to
-anyone who has written a pci driver.
-
-NTB Typical client driver implementation
-----------------------------------------
-
-Primary purpose of NTB is to share some peace of memory between at least two
-systems. So the NTB device features like Scratchpad/Message registers are
-mainly used to perform the proper memory window initialization. Typically
-there are two types of memory window interfaces supported by the NTB API:
-inbound translation configured on the local ntb port and outbound translation
-configured by the peer, on the peer ntb port. The first type is
-depicted on the next figure::
-
- Inbound translation:
-
- Memory:              Local NTB Port:      Peer NTB Port:      Peer MMIO:
-  ____________
- | dma-mapped |-ntb_mw_set_trans(addr)  |
- | memory     |        _v____________   |   ______________
- | (addr)     |<======| MW xlat addr |<====| MW base addr |<== memory-mapped IO
- |------------|       |--------------|  |  |--------------|
-
-So typical scenario of the first type memory window initialization looks:
-1) allocate a memory region, 2) put translated address to NTB config,
-3) somehow notify a peer device of performed initialization, 4) peer device
-maps corresponding outbound memory window so to have access to the shared
-memory region.
-
-The second type of interface, that implies the shared windows being
-initialized by a peer device, is depicted on the figure::
-
- Outbound translation:
-
- Memory:        Local NTB Port:    Peer NTB Port:      Peer MMIO:
-  ____________                      ______________
- | dma-mapped |                |   | MW base addr |<== memory-mapped IO
- | memory     |                |   |--------------|
- | (addr)     |<===================| MW xlat addr |<-ntb_peer_mw_set_trans(addr)
- |------------|                |   |--------------|
-
-Typical scenario of the second type interface initialization would be:
-1) allocate a memory region, 2) somehow deliver a translated address to a peer
-device, 3) peer puts the translated address to NTB config, 4) peer device maps
-outbound memory window so to have access to the shared memory region.
-
-As one can see the described scenarios can be combined in one portable
-algorithm.
-
- Local device:
-  1) Allocate memory for a shared window
-  2) Initialize memory window by translated address of the allocated region
-     (it may fail if local memory window initialization is unsupported)
-  3) Send the translated address and memory window index to a peer device
-
- Peer device:
-  1) Initialize memory window with retrieved address of the allocated
-     by another device memory region (it may fail if peer memory window
-     initialization is unsupported)
-  2) Map outbound memory window
-
-In accordance with this scenario, the NTB Memory Window API can be used as
-follows:
-
- Local device:
-  1) ntb_mw_count(pidx) - retrieve number of memory ranges, which can
-     be allocated for memory windows between local device and peer device
-     of port with specified index.
-  2) ntb_get_align(pidx, midx) - retrieve parameters restricting the
-     shared memory region alignment and size. Then memory can be properly
-     allocated.
-  3) Allocate physically contiguous memory region in compliance with
-     restrictions retrieved in 2).
-  4) ntb_mw_set_trans(pidx, midx) - try to set translation address of
-     the memory window with specified index for the defined peer device
-     (it may fail if local translated address setting is not supported)
-  5) Send translated base address (usually together with memory window
-     number) to the peer device using, for instance, scratchpad or message
-     registers.
-
- Peer device:
-  1) ntb_peer_mw_set_trans(pidx, midx) - try to set received from other
-     device (related to pidx) translated address for specified memory
-     window. It may fail if retrieved address, for instance, exceeds
-     maximum possible address or isn't properly aligned.
-  2) ntb_peer_mw_get_addr(widx) - retrieve MMIO address to map the memory
-     window so to have an access to the shared memory.
-
-Also it is worth to note, that method ntb_mw_count(pidx) should return the
-same value as ntb_peer_mw_count() on the peer with port index - pidx.
-
-NTB Transport Client (ntb\_transport) and NTB Netdev (ntb\_netdev)
-------------------------------------------------------------------
-
-The primary client for NTB is the Transport client, used in tandem with NTB
-Netdev.  These drivers function together to create a logical link to the peer,
-across the ntb, to exchange packets of network data.  The Transport client
-establishes a logical link to the peer, and creates queue pairs to exchange
-messages and data.  The NTB Netdev then creates an ethernet device using a
-Transport queue pair.  Network data is copied between socket buffers and the
-Transport queue pair buffer.  The Transport client may be used for other things
-besides Netdev, however no other applications have yet been written.
-
-NTB Ping Pong Test Client (ntb\_pingpong)
------------------------------------------
-
-The Ping Pong test client serves as a demonstration to exercise the doorbell
-and scratchpad registers of NTB hardware, and as an example simple NTB client.
-Ping Pong enables the link when started, waits for the NTB link to come up, and
-then proceeds to read and write the doorbell scratchpad registers of the NTB.
-The peers interrupt each other using a bit mask of doorbell bits, which is
-shifted by one in each round, to test the behavior of multiple doorbell bits
-and interrupt vectors.  The Ping Pong driver also reads the first local
-scratchpad, and writes the value plus one to the first peer scratchpad, each
-round before writing the peer doorbell register.
-
-Module Parameters:
-
-* unsafe - Some hardware has known issues with scratchpad and doorbell
-       registers.  By default, Ping Pong will not attempt to exercise such
-       hardware.  You may override this behavior at your own risk by setting
-       unsafe=1.
-* delay\_ms - Specify the delay between receiving a doorbell
-       interrupt event and setting the peer doorbell register for the next
-       round.
-* init\_db - Specify the doorbell bits to start new series of rounds.  A new
-       series begins once all the doorbell bits have been shifted out of
-       range.
-* dyndbg - It is suggested to specify dyndbg=+p when loading this module, and
-       then to observe debugging output on the console.
-
-NTB Tool Test Client (ntb\_tool)
---------------------------------
-
-The Tool test client serves for debugging, primarily, ntb hardware and drivers.
-The Tool provides access through debugfs for reading, setting, and clearing the
-NTB doorbell, and reading and writing scratchpads.
-
-The Tool does not currently have any module parameters.
-
-Debugfs Files:
-
-* *debugfs*/ntb\_tool/*hw*/
-       A directory in debugfs will be created for each
-       NTB device probed by the tool.  This directory is shortened to *hw*
-       below.
-* *hw*/db
-       This file is used to read, set, and clear the local doorbell.  Not
-       all operations may be supported by all hardware.  To read the doorbell,
-       read the file.  To set the doorbell, write `s` followed by the bits to
-       set (eg: `echo 's 0x0101' > db`).  To clear the doorbell, write `c`
-       followed by the bits to clear.
-* *hw*/mask
-       This file is used to read, set, and clear the local doorbell mask.
-       See *db* for details.
-* *hw*/peer\_db
-       This file is used to read, set, and clear the peer doorbell.
-       See *db* for details.
-* *hw*/peer\_mask
-       This file is used to read, set, and clear the peer doorbell
-       mask.  See *db* for details.
-* *hw*/spad
-       This file is used to read and write local scratchpads.  To read
-       the values of all scratchpads, read the file.  To write values, write a
-       series of pairs of scratchpad number and value
-       (eg: `echo '4 0x123 7 0xabc' > spad`
-       # to set scratchpads `4` and `7` to `0x123` and `0xabc`, respectively).
-* *hw*/peer\_spad
-       This file is used to read and write peer scratchpads.  See
-       *spad* for details.
-
-NTB Hardware Drivers
-====================
-
-NTB hardware drivers should register devices with the NTB core driver.  After
-registering, clients probe and remove functions will be called.
-
-NTB Intel Hardware Driver (ntb\_hw\_intel)
-------------------------------------------
-
-The Intel hardware driver supports NTB on Xeon and Atom CPUs.
-
-Module Parameters:
-
-* b2b\_mw\_idx
-       If the peer ntb is to be accessed via a memory window, then use
-       this memory window to access the peer ntb.  A value of zero or positive
-       starts from the first mw idx, and a negative value starts from the last
-       mw idx.  Both sides MUST set the same value here!  The default value is
-       `-1`.
-* b2b\_mw\_share
-       If the peer ntb is to be accessed via a memory window, and if
-       the memory window is large enough, still allow the client to use the
-       second half of the memory window for address translation to the peer.
-* xeon\_b2b\_usd\_bar2\_addr64
-       If using B2B topology on Xeon hardware, use
-       this 64 bit address on the bus between the NTB devices for the window
-       at BAR2, on the upstream side of the link.
-* xeon\_b2b\_usd\_bar4\_addr64 - See *xeon\_b2b\_bar2\_addr64*.
-* xeon\_b2b\_usd\_bar4\_addr32 - See *xeon\_b2b\_bar2\_addr64*.
-* xeon\_b2b\_usd\_bar5\_addr32 - See *xeon\_b2b\_bar2\_addr64*.
-* xeon\_b2b\_dsd\_bar2\_addr64 - See *xeon\_b2b\_bar2\_addr64*.
-* xeon\_b2b\_dsd\_bar4\_addr64 - See *xeon\_b2b\_bar2\_addr64*.
-* xeon\_b2b\_dsd\_bar4\_addr32 - See *xeon\_b2b\_bar2\_addr64*.
-* xeon\_b2b\_dsd\_bar5\_addr32 - See *xeon\_b2b\_bar2\_addr64*.
diff --git a/Documentation/nvdimm/btt.txt b/Documentation/nvdimm/btt.txt
deleted file mode 100644 (file)
index e293fb6..0000000
+++ /dev/null
@@ -1,273 +0,0 @@
-BTT - Block Translation Table
-=============================
-
-
-1. Introduction
----------------
-
-Persistent memory based storage is able to perform IO at byte (or more
-accurately, cache line) granularity. However, we often want to expose such
-storage as traditional block devices. The block drivers for persistent memory
-will do exactly this. However, they do not provide any atomicity guarantees.
-Traditional SSDs typically provide protection against torn sectors in hardware,
-using stored energy in capacitors to complete in-flight block writes, or perhaps
-in firmware. We don't have this luxury with persistent memory - if a write is in
-progress, and we experience a power failure, the block will contain a mix of old
-and new data. Applications may not be prepared to handle such a scenario.
-
-The Block Translation Table (BTT) provides atomic sector update semantics for
-persistent memory devices, so that applications that rely on sector writes not
-being torn can continue to do so. The BTT manifests itself as a stacked block
-device, and reserves a portion of the underlying storage for its metadata. At
-the heart of it, is an indirection table that re-maps all the blocks on the
-volume. It can be thought of as an extremely simple file system that only
-provides atomic sector updates.
-
-
-2. Static Layout
-----------------
-
-The underlying storage on which a BTT can be laid out is not limited in any way.
-The BTT, however, splits the available space into chunks of up to 512 GiB,
-called "Arenas".
-
-Each arena follows the same layout for its metadata, and all references in an
-arena are internal to it (with the exception of one field that points to the
-next arena). The following depicts the "On-disk" metadata layout:
-
-
-  Backing Store     +------->  Arena
-+---------------+   |   +------------------+
-|               |   |   | Arena info block |
-|    Arena 0    +---+   |       4K         |
-|     512G      |       +------------------+
-|               |       |                  |
-+---------------+       |                  |
-|               |       |                  |
-|    Arena 1    |       |   Data Blocks    |
-|     512G      |       |                  |
-|               |       |                  |
-+---------------+       |                  |
-|       .       |       |                  |
-|       .       |       |                  |
-|       .       |       |                  |
-|               |       |                  |
-|               |       |                  |
-+---------------+       +------------------+
-                        |                  |
-                        |     BTT Map      |
-                        |                  |
-                        |                  |
-                        +------------------+
-                        |                  |
-                        |     BTT Flog     |
-                        |                  |
-                        +------------------+
-                        | Info block copy  |
-                        |       4K         |
-                        +------------------+
-
-
-3. Theory of Operation
-----------------------
-
-
-a. The BTT Map
---------------
-
-The map is a simple lookup/indirection table that maps an LBA to an internal
-block. Each map entry is 32 bits. The two most significant bits are special
-flags, and the remaining form the internal block number.
-
-Bit      Description
-31 - 30        : Error and Zero flags - Used in the following way:
-        Bit                  Description
-       31 30
-       -----------------------------------------------------------------------
-        00     Initial state. Reads return zeroes; Premap = Postmap
-        01     Zero state: Reads return zeroes
-        10     Error state: Reads fail; Writes clear 'E' bit
-        11     Normal Block – has valid postmap
-
-
-29 - 0 : Mappings to internal 'postmap' blocks
-
-
-Some of the terminology that will be subsequently used:
-
-External LBA  : LBA as made visible to upper layers.
-ABA           : Arena Block Address - Block offset/number within an arena
-Premap ABA    : The block offset into an arena, which was decided upon by range
-               checking the External LBA
-Postmap ABA   : The block number in the "Data Blocks" area obtained after
-               indirection from the map
-nfree        : The number of free blocks that are maintained at any given time.
-               This is the number of concurrent writes that can happen to the
-               arena.
-
-
-For example, after adding a BTT, we surface a disk of 1024G. We get a read for
-the external LBA at 768G. This falls into the second arena, and of the 512G
-worth of blocks that this arena contributes, this block is at 256G. Thus, the
-premap ABA is 256G. We now refer to the map, and find out the mapping for block
-'X' (256G) points to block 'Y', say '64'. Thus the postmap ABA is 64.
-
-
-b. The BTT Flog
----------------
-
-The BTT provides sector atomicity by making every write an "allocating write",
-i.e. Every write goes to a "free" block. A running list of free blocks is
-maintained in the form of the BTT flog. 'Flog' is a combination of the words
-"free list" and "log". The flog contains 'nfree' entries, and an entry contains:
-
-lba     : The premap ABA that is being written to
-old_map : The old postmap ABA - after 'this' write completes, this will be a
-         free block.
-new_map : The new postmap ABA. The map will up updated to reflect this
-         lba->postmap_aba mapping, but we log it here in case we have to
-         recover.
-seq    : Sequence number to mark which of the 2 sections of this flog entry is
-         valid/newest. It cycles between 01->10->11->01 (binary) under normal
-         operation, with 00 indicating an uninitialized state.
-lba'   : alternate lba entry
-old_map': alternate old postmap entry
-new_map': alternate new postmap entry
-seq'   : alternate sequence number.
-
-Each of the above fields is 32-bit, making one entry 32 bytes. Entries are also
-padded to 64 bytes to avoid cache line sharing or aliasing. Flog updates are
-done such that for any entry being written, it:
-a. overwrites the 'old' section in the entry based on sequence numbers
-b. writes the 'new' section such that the sequence number is written last.
-
-
-c. The concept of lanes
------------------------
-
-While 'nfree' describes the number of concurrent IOs an arena can process
-concurrently, 'nlanes' is the number of IOs the BTT device as a whole can
-process.
- nlanes = min(nfree, num_cpus)
-A lane number is obtained at the start of any IO, and is used for indexing into
-all the on-disk and in-memory data structures for the duration of the IO. If
-there are more CPUs than the max number of available lanes, than lanes are
-protected by spinlocks.
-
-
-d. In-memory data structure: Read Tracking Table (RTT)
-------------------------------------------------------
-
-Consider a case where we have two threads, one doing reads and the other,
-writes. We can hit a condition where the writer thread grabs a free block to do
-a new IO, but the (slow) reader thread is still reading from it. In other words,
-the reader consulted a map entry, and started reading the corresponding block. A
-writer started writing to the same external LBA, and finished the write updating
-the map for that external LBA to point to its new postmap ABA. At this point the
-internal, postmap block that the reader is (still) reading has been inserted
-into the list of free blocks. If another write comes in for the same LBA, it can
-grab this free block, and start writing to it, causing the reader to read
-incorrect data. To prevent this, we introduce the RTT.
-
-The RTT is a simple, per arena table with 'nfree' entries. Every reader inserts
-into rtt[lane_number], the postmap ABA it is reading, and clears it after the
-read is complete. Every writer thread, after grabbing a free block, checks the
-RTT for its presence. If the postmap free block is in the RTT, it waits till the
-reader clears the RTT entry, and only then starts writing to it.
-
-
-e. In-memory data structure: map locks
---------------------------------------
-
-Consider a case where two writer threads are writing to the same LBA. There can
-be a race in the following sequence of steps:
-
-free[lane] = map[premap_aba]
-map[premap_aba] = postmap_aba
-
-Both threads can update their respective free[lane] with the same old, freed
-postmap_aba. This has made the layout inconsistent by losing a free entry, and
-at the same time, duplicating another free entry for two lanes.
-
-To solve this, we could have a single map lock (per arena) that has to be taken
-before performing the above sequence, but we feel that could be too contentious.
-Instead we use an array of (nfree) map_locks that is indexed by
-(premap_aba modulo nfree).
-
-
-f. Reconstruction from the Flog
--------------------------------
-
-On startup, we analyze the BTT flog to create our list of free blocks. We walk
-through all the entries, and for each lane, of the set of two possible
-'sections', we always look at the most recent one only (based on the sequence
-number). The reconstruction rules/steps are simple:
-- Read map[log_entry.lba].
-- If log_entry.new matches the map entry, then log_entry.old is free.
-- If log_entry.new does not match the map entry, then log_entry.new is free.
-  (This case can only be caused by power-fails/unsafe shutdowns)
-
-
-g. Summarizing - Read and Write flows
--------------------------------------
-
-Read:
-
-1.  Convert external LBA to arena number + pre-map ABA
-2.  Get a lane (and take lane_lock)
-3.  Read map to get the entry for this pre-map ABA
-4.  Enter post-map ABA into RTT[lane]
-5.  If TRIM flag set in map, return zeroes, and end IO (go to step 8)
-6.  If ERROR flag set in map, end IO with EIO (go to step 8)
-7.  Read data from this block
-8.  Remove post-map ABA entry from RTT[lane]
-9.  Release lane (and lane_lock)
-
-Write:
-
-1.  Convert external LBA to Arena number + pre-map ABA
-2.  Get a lane (and take lane_lock)
-3.  Use lane to index into in-memory free list and obtain a new block, next flog
-        index, next sequence number
-4.  Scan the RTT to check if free block is present, and spin/wait if it is.
-5.  Write data to this free block
-6.  Read map to get the existing post-map ABA entry for this pre-map ABA
-7.  Write flog entry: [premap_aba / old postmap_aba / new postmap_aba / seq_num]
-8.  Write new post-map ABA into map.
-9.  Write old post-map entry into the free list
-10. Calculate next sequence number and write into the free list entry
-11. Release lane (and lane_lock)
-
-
-4. Error Handling
-=================
-
-An arena would be in an error state if any of the metadata is corrupted
-irrecoverably, either due to a bug or a media error. The following conditions
-indicate an error:
-- Info block checksum does not match (and recovering from the copy also fails)
-- All internal available blocks are not uniquely and entirely addressed by the
-  sum of mapped blocks and free blocks (from the BTT flog).
-- Rebuilding free list from the flog reveals missing/duplicate/impossible
-  entries
-- A map entry is out of bounds
-
-If any of these error conditions are encountered, the arena is put into a read
-only state using a flag in the info block.
-
-
-5. Usage
-========
-
-The BTT can be set up on any disk (namespace) exposed by the libnvdimm subsystem
-(pmem, or blk mode). The easiest way to set up such a namespace is using the
-'ndctl' utility [1]:
-
-For example, the ndctl command line to setup a btt with a 4k sector size is:
-
-    ndctl create-namespace -f -e namespace0.0 -m sector -l 4k
-
-See ndctl create-namespace --help for more options.
-
-[1]: https://github.com/pmem/ndctl
-
diff --git a/Documentation/nvdimm/nvdimm.txt b/Documentation/nvdimm/nvdimm.txt
deleted file mode 100644 (file)
index 1669f62..0000000
+++ /dev/null
@@ -1,815 +0,0 @@
-                         LIBNVDIMM: Non-Volatile Devices
-             libnvdimm - kernel / libndctl - userspace helper library
-                          linux-nvdimm@lists.01.org
-                                     v13
-
-
-       Glossary
-       Overview
-           Supporting Documents
-           Git Trees
-       LIBNVDIMM PMEM and BLK
-       Why BLK?
-           PMEM vs BLK
-               BLK-REGIONs, PMEM-REGIONs, Atomic Sectors, and DAX
-       Example NVDIMM Platform
-       LIBNVDIMM Kernel Device Model and LIBNDCTL Userspace API
-           LIBNDCTL: Context
-               libndctl: instantiate a new library context example
-           LIBNVDIMM/LIBNDCTL: Bus
-               libnvdimm: control class device in /sys/class
-               libnvdimm: bus
-               libndctl: bus enumeration example
-           LIBNVDIMM/LIBNDCTL: DIMM (NMEM)
-               libnvdimm: DIMM (NMEM)
-               libndctl: DIMM enumeration example
-           LIBNVDIMM/LIBNDCTL: Region
-               libnvdimm: region
-               libndctl: region enumeration example
-               Why Not Encode the Region Type into the Region Name?
-               How Do I Determine the Major Type of a Region?
-           LIBNVDIMM/LIBNDCTL: Namespace
-               libnvdimm: namespace
-               libndctl: namespace enumeration example
-               libndctl: namespace creation example
-               Why the Term "namespace"?
-           LIBNVDIMM/LIBNDCTL: Block Translation Table "btt"
-               libnvdimm: btt layout
-               libndctl: btt creation example
-       Summary LIBNDCTL Diagram
-
-
-Glossary
---------
-
-PMEM: A system-physical-address range where writes are persistent.  A
-block device composed of PMEM is capable of DAX.  A PMEM address range
-may span an interleave of several DIMMs.
-
-BLK: A set of one or more programmable memory mapped apertures provided
-by a DIMM to access its media.  This indirection precludes the
-performance benefit of interleaving, but enables DIMM-bounded failure
-modes.
-
-DPA: DIMM Physical Address, is a DIMM-relative offset.  With one DIMM in
-the system there would be a 1:1 system-physical-address:DPA association.
-Once more DIMMs are added a memory controller interleave must be
-decoded to determine the DPA associated with a given
-system-physical-address.  BLK capacity always has a 1:1 relationship
-with a single-DIMM's DPA range.
-
-DAX: File system extensions to bypass the page cache and block layer to
-mmap persistent memory, from a PMEM block device, directly into a
-process address space.
-
-DSM: Device Specific Method: ACPI method to to control specific
-device - in this case the firmware.
-
-DCR: NVDIMM Control Region Structure defined in ACPI 6 Section 5.2.25.5.
-It defines a vendor-id, device-id, and interface format for a given DIMM.
-
-BTT: Block Translation Table: Persistent memory is byte addressable.
-Existing software may have an expectation that the power-fail-atomicity
-of writes is at least one sector, 512 bytes.  The BTT is an indirection
-table with atomic update semantics to front a PMEM/BLK block device
-driver and present arbitrary atomic sector sizes.
-
-LABEL: Metadata stored on a DIMM device that partitions and identifies
-(persistently names) storage between PMEM and BLK.  It also partitions
-BLK storage to host BTTs with different parameters per BLK-partition.
-Note that traditional partition tables, GPT/MBR, are layered on top of a
-BLK or PMEM device.
-
-
-Overview
---------
-
-The LIBNVDIMM subsystem provides support for three types of NVDIMMs, namely,
-PMEM, BLK, and NVDIMM devices that can simultaneously support both PMEM
-and BLK mode access.  These three modes of operation are described by
-the "NVDIMM Firmware Interface Table" (NFIT) in ACPI 6.  While the LIBNVDIMM
-implementation is generic and supports pre-NFIT platforms, it was guided
-by the superset of capabilities need to support this ACPI 6 definition
-for NVDIMM resources.  The bulk of the kernel implementation is in place
-to handle the case where DPA accessible via PMEM is aliased with DPA
-accessible via BLK.  When that occurs a LABEL is needed to reserve DPA
-for exclusive access via one mode a time.
-
-Supporting Documents
-ACPI 6: http://www.uefi.org/sites/default/files/resources/ACPI_6.0.pdf
-NVDIMM Namespace: http://pmem.io/documents/NVDIMM_Namespace_Spec.pdf
-DSM Interface Example: http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf
-Driver Writer's Guide: http://pmem.io/documents/NVDIMM_Driver_Writers_Guide.pdf
-
-Git Trees
-LIBNVDIMM: https://git.kernel.org/cgit/linux/kernel/git/djbw/nvdimm.git
-LIBNDCTL: https://github.com/pmem/ndctl.git
-PMEM: https://github.com/01org/prd
-
-
-LIBNVDIMM PMEM and BLK
-------------------
-
-Prior to the arrival of the NFIT, non-volatile memory was described to a
-system in various ad-hoc ways.  Usually only the bare minimum was
-provided, namely, a single system-physical-address range where writes
-are expected to be durable after a system power loss.  Now, the NFIT
-specification standardizes not only the description of PMEM, but also
-BLK and platform message-passing entry points for control and
-configuration.
-
-For each NVDIMM access method (PMEM, BLK), LIBNVDIMM provides a block
-device driver:
-
-    1. PMEM (nd_pmem.ko): Drives a system-physical-address range.  This
-    range is contiguous in system memory and may be interleaved (hardware
-    memory controller striped) across multiple DIMMs.  When interleaved the
-    platform may optionally provide details of which DIMMs are participating
-    in the interleave.
-
-    Note that while LIBNVDIMM describes system-physical-address ranges that may
-    alias with BLK access as ND_NAMESPACE_PMEM ranges and those without
-    alias as ND_NAMESPACE_IO ranges, to the nd_pmem driver there is no
-    distinction.  The different device-types are an implementation detail
-    that userspace can exploit to implement policies like "only interface
-    with address ranges from certain DIMMs".  It is worth noting that when
-    aliasing is present and a DIMM lacks a label, then no block device can
-    be created by default as userspace needs to do at least one allocation
-    of DPA to the PMEM range.  In contrast ND_NAMESPACE_IO ranges, once
-    registered, can be immediately attached to nd_pmem.
-
-    2. BLK (nd_blk.ko): This driver performs I/O using a set of platform
-    defined apertures.  A set of apertures will access just one DIMM.
-    Multiple windows (apertures) allow multiple concurrent accesses, much like
-    tagged-command-queuing, and would likely be used by different threads or
-    different CPUs.
-
-    The NFIT specification defines a standard format for a BLK-aperture, but
-    the spec also allows for vendor specific layouts, and non-NFIT BLK
-    implementations may have other designs for BLK I/O.  For this reason
-    "nd_blk" calls back into platform-specific code to perform the I/O.
-    One such implementation is defined in the "Driver Writer's Guide" and "DSM
-    Interface Example".
-
-
-Why BLK?
---------
-
-While PMEM provides direct byte-addressable CPU-load/store access to
-NVDIMM storage, it does not provide the best system RAS (recovery,
-availability, and serviceability) model.  An access to a corrupted
-system-physical-address address causes a CPU exception while an access
-to a corrupted address through an BLK-aperture causes that block window
-to raise an error status in a register.  The latter is more aligned with
-the standard error model that host-bus-adapter attached disks present.
-Also, if an administrator ever wants to replace a memory it is easier to
-service a system at DIMM module boundaries.  Compare this to PMEM where
-data could be interleaved in an opaque hardware specific manner across
-several DIMMs.
-
-PMEM vs BLK
-BLK-apertures solve these RAS problems, but their presence is also the
-major contributing factor to the complexity of the ND subsystem.  They
-complicate the implementation because PMEM and BLK alias in DPA space.
-Any given DIMM's DPA-range may contribute to one or more
-system-physical-address sets of interleaved DIMMs, *and* may also be
-accessed in its entirety through its BLK-aperture.  Accessing a DPA
-through a system-physical-address while simultaneously accessing the
-same DPA through a BLK-aperture has undefined results.  For this reason,
-DIMMs with this dual interface configuration include a DSM function to
-store/retrieve a LABEL.  The LABEL effectively partitions the DPA-space
-into exclusive system-physical-address and BLK-aperture accessible
-regions.  For simplicity a DIMM is allowed a PMEM "region" per each
-interleave set in which it is a member.  The remaining DPA space can be
-carved into an arbitrary number of BLK devices with discontiguous
-extents.
-
-BLK-REGIONs, PMEM-REGIONs, Atomic Sectors, and DAX
---------------------------------------------------
-
-One of the few
-reasons to allow multiple BLK namespaces per REGION is so that each
-BLK-namespace can be configured with a BTT with unique atomic sector
-sizes.  While a PMEM device can host a BTT the LABEL specification does
-not provide for a sector size to be specified for a PMEM namespace.
-This is due to the expectation that the primary usage model for PMEM is
-via DAX, and the BTT is incompatible with DAX.  However, for the cases
-where an application or filesystem still needs atomic sector update
-guarantees it can register a BTT on a PMEM device or partition.  See
-LIBNVDIMM/NDCTL: Block Translation Table "btt"
-
-
-Example NVDIMM Platform
------------------------
-
-For the remainder of this document the following diagram will be
-referenced for any example sysfs layouts.
-
-
-                             (a)               (b)           DIMM   BLK-REGION
-          +-------------------+--------+--------+--------+
-+------+  |       pm0.0       | blk2.0 | pm1.0  | blk2.1 |    0      region2
-| imc0 +--+- - - region0- - - +--------+        +--------+
-+--+---+  |       pm0.0       | blk3.0 | pm1.0  | blk3.1 |    1      region3
-   |      +-------------------+--------v        v--------+
-+--+---+                               |                 |
-| cpu0 |                                     region1
-+--+---+                               |                 |
-   |      +----------------------------^        ^--------+
-+--+---+  |           blk4.0           | pm1.0  | blk4.0 |    2      region4
-| imc1 +--+----------------------------|        +--------+
-+------+  |           blk5.0           | pm1.0  | blk5.0 |    3      region5
-          +----------------------------+--------+--------+
-
-In this platform we have four DIMMs and two memory controllers in one
-socket.  Each unique interface (BLK or PMEM) to DPA space is identified
-by a region device with a dynamically assigned id (REGION0 - REGION5).
-
-    1. The first portion of DIMM0 and DIMM1 are interleaved as REGION0. A
-    single PMEM namespace is created in the REGION0-SPA-range that spans most
-    of DIMM0 and DIMM1 with a user-specified name of "pm0.0". Some of that
-    interleaved system-physical-address range is reclaimed as BLK-aperture
-    accessed space starting at DPA-offset (a) into each DIMM.  In that
-    reclaimed space we create two BLK-aperture "namespaces" from REGION2 and
-    REGION3 where "blk2.0" and "blk3.0" are just human readable names that
-    could be set to any user-desired name in the LABEL.
-
-    2. In the last portion of DIMM0 and DIMM1 we have an interleaved
-    system-physical-address range, REGION1, that spans those two DIMMs as
-    well as DIMM2 and DIMM3.  Some of REGION1 is allocated to a PMEM namespace
-    named "pm1.0", the rest is reclaimed in 4 BLK-aperture namespaces (for
-    each DIMM in the interleave set), "blk2.1", "blk3.1", "blk4.0", and
-    "blk5.0".
-
-    3. The portion of DIMM2 and DIMM3 that do not participate in the REGION1
-    interleaved system-physical-address range (i.e. the DPA address past
-    offset (b) are also included in the "blk4.0" and "blk5.0" namespaces.
-    Note, that this example shows that BLK-aperture namespaces don't need to
-    be contiguous in DPA-space.
-
-    This bus is provided by the kernel under the device
-    /sys/devices/platform/nfit_test.0 when CONFIG_NFIT_TEST is enabled and
-    the nfit_test.ko module is loaded.  This not only test LIBNVDIMM but the
-    acpi_nfit.ko driver as well.
-
-
-LIBNVDIMM Kernel Device Model and LIBNDCTL Userspace API
-----------------------------------------------------
-
-What follows is a description of the LIBNVDIMM sysfs layout and a
-corresponding object hierarchy diagram as viewed through the LIBNDCTL
-API.  The example sysfs paths and diagrams are relative to the Example
-NVDIMM Platform which is also the LIBNVDIMM bus used in the LIBNDCTL unit
-test.
-
-LIBNDCTL: Context
-Every API call in the LIBNDCTL library requires a context that holds the
-logging parameters and other library instance state.  The library is
-based on the libabc template:
-https://git.kernel.org/cgit/linux/kernel/git/kay/libabc.git
-
-LIBNDCTL: instantiate a new library context example
-
-       struct ndctl_ctx *ctx;
-
-       if (ndctl_new(&ctx) == 0)
-               return ctx;
-       else
-               return NULL;
-
-LIBNVDIMM/LIBNDCTL: Bus
--------------------
-
-A bus has a 1:1 relationship with an NFIT.  The current expectation for
-ACPI based systems is that there is only ever one platform-global NFIT.
-That said, it is trivial to register multiple NFITs, the specification
-does not preclude it.  The infrastructure supports multiple busses and
-we use this capability to test multiple NFIT configurations in the unit
-test.
-
-LIBNVDIMM: control class device in /sys/class
-
-This character device accepts DSM messages to be passed to DIMM
-identified by its NFIT handle.
-
-       /sys/class/nd/ndctl0
-       |-- dev
-       |-- device -> ../../../ndbus0
-       |-- subsystem -> ../../../../../../../class/nd
-
-
-
-LIBNVDIMM: bus
-
-       struct nvdimm_bus *nvdimm_bus_register(struct device *parent,
-              struct nvdimm_bus_descriptor *nfit_desc);
-
-       /sys/devices/platform/nfit_test.0/ndbus0
-       |-- commands
-       |-- nd
-       |-- nfit
-       |-- nmem0
-       |-- nmem1
-       |-- nmem2
-       |-- nmem3
-       |-- power
-       |-- provider
-       |-- region0
-       |-- region1
-       |-- region2
-       |-- region3
-       |-- region4
-       |-- region5
-       |-- uevent
-       `-- wait_probe
-
-LIBNDCTL: bus enumeration example
-Find the bus handle that describes the bus from Example NVDIMM Platform
-
-       static struct ndctl_bus *get_bus_by_provider(struct ndctl_ctx *ctx,
-                       const char *provider)
-       {
-               struct ndctl_bus *bus;
-
-               ndctl_bus_foreach(ctx, bus)
-                       if (strcmp(provider, ndctl_bus_get_provider(bus)) == 0)
-                               return bus;
-
-               return NULL;
-       }
-
-       bus = get_bus_by_provider(ctx, "nfit_test.0");
-
-
-LIBNVDIMM/LIBNDCTL: DIMM (NMEM)
----------------------------
-
-The DIMM device provides a character device for sending commands to
-hardware, and it is a container for LABELs.  If the DIMM is defined by
-NFIT then an optional 'nfit' attribute sub-directory is available to add
-NFIT-specifics.
-
-Note that the kernel device name for "DIMMs" is "nmemX".  The NFIT
-describes these devices via "Memory Device to System Physical Address
-Range Mapping Structure", and there is no requirement that they actually
-be physical DIMMs, so we use a more generic name.
-
-LIBNVDIMM: DIMM (NMEM)
-
-       struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data,
-                       const struct attribute_group **groups, unsigned long flags,
-                       unsigned long *dsm_mask);
-
-       /sys/devices/platform/nfit_test.0/ndbus0
-       |-- nmem0
-       |   |-- available_slots
-       |   |-- commands
-       |   |-- dev
-       |   |-- devtype
-       |   |-- driver -> ../../../../../bus/nd/drivers/nvdimm
-       |   |-- modalias
-       |   |-- nfit
-       |   |   |-- device
-       |   |   |-- format
-       |   |   |-- handle
-       |   |   |-- phys_id
-       |   |   |-- rev_id
-       |   |   |-- serial
-       |   |   `-- vendor
-       |   |-- state
-       |   |-- subsystem -> ../../../../../bus/nd
-       |   `-- uevent
-       |-- nmem1
-       [..]
-
-
-LIBNDCTL: DIMM enumeration example
-
-Note, in this example we are assuming NFIT-defined DIMMs which are
-identified by an "nfit_handle" a 32-bit value where:
-Bit 3:0 DIMM number within the memory channel
-Bit 7:4 memory channel number
-Bit 11:8 memory controller ID
-Bit 15:12 socket ID (within scope of a Node controller if node controller is present)
-Bit 27:16 Node Controller ID
-Bit 31:28 Reserved
-
-       static struct ndctl_dimm *get_dimm_by_handle(struct ndctl_bus *bus,
-              unsigned int handle)
-       {
-               struct ndctl_dimm *dimm;
-
-               ndctl_dimm_foreach(bus, dimm)
-                       if (ndctl_dimm_get_handle(dimm) == handle)
-                               return dimm;
-
-               return NULL;
-       }
-
-       #define DIMM_HANDLE(n, s, i, c, d) \
-               (((n & 0xfff) << 16) | ((s & 0xf) << 12) | ((i & 0xf) << 8) \
-                | ((c & 0xf) << 4) | (d & 0xf))
-
-       dimm = get_dimm_by_handle(bus, DIMM_HANDLE(0, 0, 0, 0, 0));
-
-LIBNVDIMM/LIBNDCTL: Region
-----------------------
-
-A generic REGION device is registered for each PMEM range or BLK-aperture
-set.  Per the example there are 6 regions: 2 PMEM and 4 BLK-aperture
-sets on the "nfit_test.0" bus.  The primary role of regions are to be a
-container of "mappings".  A mapping is a tuple of <DIMM,
-DPA-start-offset, length>.
-
-LIBNVDIMM provides a built-in driver for these REGION devices.  This driver
-is responsible for reconciling the aliased DPA mappings across all
-regions, parsing the LABEL, if present, and then emitting NAMESPACE
-devices with the resolved/exclusive DPA-boundaries for the nd_pmem or
-nd_blk device driver to consume.
-
-In addition to the generic attributes of "mapping"s, "interleave_ways"
-and "size" the REGION device also exports some convenience attributes.
-"nstype" indicates the integer type of namespace-device this region
-emits, "devtype" duplicates the DEVTYPE variable stored by udev at the
-'add' event, "modalias" duplicates the MODALIAS variable stored by udev
-at the 'add' event, and finally, the optional "spa_index" is provided in
-the case where the region is defined by a SPA.
-
-LIBNVDIMM: region
-
-       struct nd_region *nvdimm_pmem_region_create(struct nvdimm_bus *nvdimm_bus,
-                       struct nd_region_desc *ndr_desc);
-       struct nd_region *nvdimm_blk_region_create(struct nvdimm_bus *nvdimm_bus,
-                       struct nd_region_desc *ndr_desc);
-
-       /sys/devices/platform/nfit_test.0/ndbus0
-       |-- region0
-       |   |-- available_size
-       |   |-- btt0
-       |   |-- btt_seed
-       |   |-- devtype
-       |   |-- driver -> ../../../../../bus/nd/drivers/nd_region
-       |   |-- init_namespaces
-       |   |-- mapping0
-       |   |-- mapping1
-       |   |-- mappings
-       |   |-- modalias
-       |   |-- namespace0.0
-       |   |-- namespace_seed
-       |   |-- numa_node
-       |   |-- nfit
-       |   |   `-- spa_index
-       |   |-- nstype
-       |   |-- set_cookie
-       |   |-- size
-       |   |-- subsystem -> ../../../../../bus/nd
-       |   `-- uevent
-       |-- region1
-       [..]
-
-LIBNDCTL: region enumeration example
-
-Sample region retrieval routines based on NFIT-unique data like
-"spa_index" (interleave set id) for PMEM and "nfit_handle" (dimm id) for
-BLK.
-
-       static struct ndctl_region *get_pmem_region_by_spa_index(struct ndctl_bus *bus,
-                       unsigned int spa_index)
-       {
-               struct ndctl_region *region;
-
-               ndctl_region_foreach(bus, region) {
-                       if (ndctl_region_get_type(region) != ND_DEVICE_REGION_PMEM)
-                               continue;
-                       if (ndctl_region_get_spa_index(region) == spa_index)
-                               return region;
-               }
-               return NULL;
-       }
-
-       static struct ndctl_region *get_blk_region_by_dimm_handle(struct ndctl_bus *bus,
-                       unsigned int handle)
-       {
-               struct ndctl_region *region;
-
-               ndctl_region_foreach(bus, region) {
-                       struct ndctl_mapping *map;
-
-                       if (ndctl_region_get_type(region) != ND_DEVICE_REGION_BLOCK)
-                               continue;
-                       ndctl_mapping_foreach(region, map) {
-                               struct ndctl_dimm *dimm = ndctl_mapping_get_dimm(map);
-
-                               if (ndctl_dimm_get_handle(dimm) == handle)
-                                       return region;
-                       }
-               }
-               return NULL;
-       }
-
-
-Why Not Encode the Region Type into the Region Name?
-----------------------------------------------------
-
-At first glance it seems since NFIT defines just PMEM and BLK interface
-types that we should simply name REGION devices with something derived
-from those type names.  However, the ND subsystem explicitly keeps the
-REGION name generic and expects userspace to always consider the
-region-attributes for four reasons:
-
-    1. There are already more than two REGION and "namespace" types.  For
-    PMEM there are two subtypes.  As mentioned previously we have PMEM where
-    the constituent DIMM devices are known and anonymous PMEM.  For BLK
-    regions the NFIT specification already anticipates vendor specific
-    implementations.  The exact distinction of what a region contains is in
-    the region-attributes not the region-name or the region-devtype.
-
-    2. A region with zero child-namespaces is a possible configuration.  For
-    example, the NFIT allows for a DCR to be published without a
-    corresponding BLK-aperture.  This equates to a DIMM that can only accept
-    control/configuration messages, but no i/o through a descendant block
-    device.  Again, this "type" is advertised in the attributes ('mappings'
-    == 0) and the name does not tell you much.
-
-    3. What if a third major interface type arises in the future?  Outside
-    of vendor specific implementations, it's not difficult to envision a
-    third class of interface type beyond BLK and PMEM.  With a generic name
-    for the REGION level of the device-hierarchy old userspace
-    implementations can still make sense of new kernel advertised
-    region-types.  Userspace can always rely on the generic region
-    attributes like "mappings", "size", etc and the expected child devices
-    named "namespace".  This generic format of the device-model hierarchy
-    allows the LIBNVDIMM and LIBNDCTL implementations to be more uniform and
-    future-proof.
-
-    4. There are more robust mechanisms for determining the major type of a
-    region than a device name.  See the next section, How Do I Determine the
-    Major Type of a Region?
-
-How Do I Determine the Major Type of a Region?
-----------------------------------------------
-
-Outside of the blanket recommendation of "use libndctl", or simply
-looking at the kernel header (/usr/include/linux/ndctl.h) to decode the
-"nstype" integer attribute, here are some other options.
-
-    1. module alias lookup:
-
-    The whole point of region/namespace device type differentiation is to
-    decide which block-device driver will attach to a given LIBNVDIMM namespace.
-    One can simply use the modalias to lookup the resulting module.  It's
-    important to note that this method is robust in the presence of a
-    vendor-specific driver down the road.  If a vendor-specific
-    implementation wants to supplant the standard nd_blk driver it can with
-    minimal impact to the rest of LIBNVDIMM.
-
-    In fact, a vendor may also want to have a vendor-specific region-driver
-    (outside of nd_region).  For example, if a vendor defined its own LABEL
-    format it would need its own region driver to parse that LABEL and emit
-    the resulting namespaces.  The output from module resolution is more
-    accurate than a region-name or region-devtype.
-
-    2. udev:
-
-    The kernel "devtype" is registered in the udev database
-    # udevadm info --path=/devices/platform/nfit_test.0/ndbus0/region0
-    P: /devices/platform/nfit_test.0/ndbus0/region0
-    E: DEVPATH=/devices/platform/nfit_test.0/ndbus0/region0
-    E: DEVTYPE=nd_pmem
-    E: MODALIAS=nd:t2
-    E: SUBSYSTEM=nd
-
-    # udevadm info --path=/devices/platform/nfit_test.0/ndbus0/region4
-    P: /devices/platform/nfit_test.0/ndbus0/region4
-    E: DEVPATH=/devices/platform/nfit_test.0/ndbus0/region4
-    E: DEVTYPE=nd_blk
-    E: MODALIAS=nd:t3
-    E: SUBSYSTEM=nd
-
-    ...and is available as a region attribute, but keep in mind that the
-    "devtype" does not indicate sub-type variations and scripts should
-    really be understanding the other attributes.
-
-    3. type specific attributes:
-
-    As it currently stands a BLK-aperture region will never have a
-    "nfit/spa_index" attribute, but neither will a non-NFIT PMEM region.  A
-    BLK region with a "mappings" value of 0 is, as mentioned above, a DIMM
-    that does not allow I/O.  A PMEM region with a "mappings" value of zero
-    is a simple system-physical-address range.
-
-
-LIBNVDIMM/LIBNDCTL: Namespace
--------------------------
-
-A REGION, after resolving DPA aliasing and LABEL specified boundaries,
-surfaces one or more "namespace" devices.  The arrival of a "namespace"
-device currently triggers either the nd_blk or nd_pmem driver to load
-and register a disk/block device.
-
-LIBNVDIMM: namespace
-Here is a sample layout from the three major types of NAMESPACE where
-namespace0.0 represents DIMM-info-backed PMEM (note that it has a 'uuid'
-attribute), namespace2.0 represents a BLK namespace (note it has a
-'sector_size' attribute) that, and namespace6.0 represents an anonymous
-PMEM namespace (note that has no 'uuid' attribute due to not support a
-LABEL).
-
-       /sys/devices/platform/nfit_test.0/ndbus0/region0/namespace0.0
-       |-- alt_name
-       |-- devtype
-       |-- dpa_extents
-       |-- force_raw
-       |-- modalias
-       |-- numa_node
-       |-- resource
-       |-- size
-       |-- subsystem -> ../../../../../../bus/nd
-       |-- type
-       |-- uevent
-       `-- uuid
-       /sys/devices/platform/nfit_test.0/ndbus0/region2/namespace2.0
-       |-- alt_name
-       |-- devtype
-       |-- dpa_extents
-       |-- force_raw
-       |-- modalias
-       |-- numa_node
-       |-- sector_size
-       |-- size
-       |-- subsystem -> ../../../../../../bus/nd
-       |-- type
-       |-- uevent
-       `-- uuid
-       /sys/devices/platform/nfit_test.1/ndbus1/region6/namespace6.0
-       |-- block
-       |   `-- pmem0
-       |-- devtype
-       |-- driver -> ../../../../../../bus/nd/drivers/pmem
-       |-- force_raw
-       |-- modalias
-       |-- numa_node
-       |-- resource
-       |-- size
-       |-- subsystem -> ../../../../../../bus/nd
-       |-- type
-       `-- uevent
-
-LIBNDCTL: namespace enumeration example
-Namespaces are indexed relative to their parent region, example below.
-These indexes are mostly static from boot to boot, but subsystem makes
-no guarantees in this regard.  For a static namespace identifier use its
-'uuid' attribute.
-
-static struct ndctl_namespace *get_namespace_by_id(struct ndctl_region *region,
-                unsigned int id)
-{
-        struct ndctl_namespace *ndns;
-
-        ndctl_namespace_foreach(region, ndns)
-                if (ndctl_namespace_get_id(ndns) == id)
-                        return ndns;
-
-        return NULL;
-}
-
-LIBNDCTL: namespace creation example
-Idle namespaces are automatically created by the kernel if a given
-region has enough available capacity to create a new namespace.
-Namespace instantiation involves finding an idle namespace and
-configuring it.  For the most part the setting of namespace attributes
-can occur in any order, the only constraint is that 'uuid' must be set
-before 'size'.  This enables the kernel to track DPA allocations
-internally with a static identifier.
-
-static int configure_namespace(struct ndctl_region *region,
-                struct ndctl_namespace *ndns,
-                struct namespace_parameters *parameters)
-{
-        char devname[50];
-
-        snprintf(devname, sizeof(devname), "namespace%d.%d",
-                        ndctl_region_get_id(region), paramaters->id);
-
-        ndctl_namespace_set_alt_name(ndns, devname);
-        /* 'uuid' must be set prior to setting size! */
-        ndctl_namespace_set_uuid(ndns, paramaters->uuid);
-        ndctl_namespace_set_size(ndns, paramaters->size);
-        /* unlike pmem namespaces, blk namespaces have a sector size */
-        if (parameters->lbasize)
-                ndctl_namespace_set_sector_size(ndns, parameters->lbasize);
-        ndctl_namespace_enable(ndns);
-}
-
-
-Why the Term "namespace"?
-
-    1. Why not "volume" for instance?  "volume" ran the risk of confusing
-    ND (libnvdimm subsystem) to a volume manager like device-mapper.
-
-    2. The term originated to describe the sub-devices that can be created
-    within a NVME controller (see the nvme specification:
-    http://www.nvmexpress.org/specifications/), and NFIT namespaces are
-    meant to parallel the capabilities and configurability of
-    NVME-namespaces.
-
-
-LIBNVDIMM/LIBNDCTL: Block Translation Table "btt"
----------------------------------------------
-
-A BTT (design document: http://pmem.io/2014/09/23/btt.html) is a stacked
-block device driver that fronts either the whole block device or a
-partition of a block device emitted by either a PMEM or BLK NAMESPACE.
-
-LIBNVDIMM: btt layout
-Every region will start out with at least one BTT device which is the
-seed device.  To activate it set the "namespace", "uuid", and
-"sector_size" attributes and then bind the device to the nd_pmem or
-nd_blk driver depending on the region type.
-
-       /sys/devices/platform/nfit_test.1/ndbus0/region0/btt0/
-       |-- namespace
-       |-- delete
-       |-- devtype
-       |-- modalias
-       |-- numa_node
-       |-- sector_size
-       |-- subsystem -> ../../../../../bus/nd
-       |-- uevent
-       `-- uuid
-
-LIBNDCTL: btt creation example
-Similar to namespaces an idle BTT device is automatically created per
-region.  Each time this "seed" btt device is configured and enabled a new
-seed is created.  Creating a BTT configuration involves two steps of
-finding and idle BTT and assigning it to consume a PMEM or BLK namespace.
-
-       static struct ndctl_btt *get_idle_btt(struct ndctl_region *region)
-       {
-               struct ndctl_btt *btt;
-
-               ndctl_btt_foreach(region, btt)
-                       if (!ndctl_btt_is_enabled(btt)
-                                       && !ndctl_btt_is_configured(btt))
-                               return btt;
-
-               return NULL;
-       }
-
-       static int configure_btt(struct ndctl_region *region,
-                       struct btt_parameters *parameters)
-       {
-               btt = get_idle_btt(region);
-
-               ndctl_btt_set_uuid(btt, parameters->uuid);
-               ndctl_btt_set_sector_size(btt, parameters->sector_size);
-               ndctl_btt_set_namespace(btt, parameters->ndns);
-               /* turn off raw mode device */
-               ndctl_namespace_disable(parameters->ndns);
-               /* turn on btt access */
-               ndctl_btt_enable(btt);
-       }
-
-Once instantiated a new inactive btt seed device will appear underneath
-the region.
-
-Once a "namespace" is removed from a BTT that instance of the BTT device
-will be deleted or otherwise reset to default values.  This deletion is
-only at the device model level.  In order to destroy a BTT the "info
-block" needs to be destroyed.  Note, that to destroy a BTT the media
-needs to be written in raw mode.  By default, the kernel will autodetect
-the presence of a BTT and disable raw mode.  This autodetect behavior
-can be suppressed by enabling raw mode for the namespace via the
-ndctl_namespace_set_raw_mode() API.
-
-
-Summary LIBNDCTL Diagram
-------------------------
-
-For the given example above, here is the view of the objects as seen by the
-LIBNDCTL API:
-            +---+
-            |CTX|    +---------+   +--------------+  +---------------+
-            +-+-+  +-> REGION0 +---> NAMESPACE0.0 +--> PMEM8 "pm0.0" |
-              |    | +---------+   +--------------+  +---------------+
-+-------+     |    | +---------+   +--------------+  +---------------+
-| DIMM0 <-+   |    +-> REGION1 +---> NAMESPACE1.0 +--> PMEM6 "pm1.0" |
-+-------+ |   |    | +---------+   +--------------+  +---------------+
-| DIMM1 <-+ +-v--+ | +---------+   +--------------+  +---------------+
-+-------+ +-+BUS0+---> REGION2 +-+-> NAMESPACE2.0 +--> ND6  "blk2.0" |
-| DIMM2 <-+ +----+ | +---------+ | +--------------+  +----------------------+
-+-------+ |        |             +-> NAMESPACE2.1 +--> ND5  "blk2.1" | BTT2 |
-| DIMM3 <-+        |               +--------------+  +----------------------+
-+-------+          | +---------+   +--------------+  +---------------+
-                   +-> REGION3 +-+-> NAMESPACE3.0 +--> ND4  "blk3.0" |
-                   | +---------+ | +--------------+  +----------------------+
-                   |             +-> NAMESPACE3.1 +--> ND3  "blk3.1" | BTT1 |
-                   |               +--------------+  +----------------------+
-                   | +---------+   +--------------+  +---------------+
-                   +-> REGION4 +---> NAMESPACE4.0 +--> ND2  "blk4.0" |
-                   | +---------+   +--------------+  +---------------+
-                   | +---------+   +--------------+  +----------------------+
-                   +-> REGION5 +---> NAMESPACE5.0 +--> ND1  "blk5.0" | BTT0 |
-                     +---------+   +--------------+  +---------------+------+
-
-
diff --git a/Documentation/nvdimm/security.txt b/Documentation/nvdimm/security.txt
deleted file mode 100644 (file)
index 4c36c05..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-NVDIMM SECURITY
-===============
-
-1. Introduction
----------------
-
-With the introduction of Intel Device Specific Methods (DSM) v1.8
-specification [1], security DSMs are introduced. The spec added the following
-security DSMs: "get security state", "set passphrase", "disable passphrase",
-"unlock unit", "freeze lock", "secure erase", and "overwrite". A security_ops
-data structure has been added to struct dimm in order to support the security
-operations and generic APIs are exposed to allow vendor neutral operations.
-
-2. Sysfs Interface
-------------------
-The "security" sysfs attribute is provided in the nvdimm sysfs directory. For
-example:
-/sys/devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/nmem0/security
-
-The "show" attribute of that attribute will display the security state for
-that DIMM. The following states are available: disabled, unlocked, locked,
-frozen, and overwrite. If security is not supported, the sysfs attribute
-will not be visible.
-
-The "store" attribute takes several commands when it is being written to
-in order to support some of the security functionalities:
-update <old_keyid> <new_keyid> - enable or update passphrase.
-disable <keyid> - disable enabled security and remove key.
-freeze - freeze changing of security states.
-erase <keyid> - delete existing user encryption key.
-overwrite <keyid> - wipe the entire nvdimm.
-master_update <keyid> <new_keyid> - enable or update master passphrase.
-master_erase <keyid> - delete existing user encryption key.
-
-3. Key Management
------------------
-
-The key is associated to the payload by the DIMM id. For example:
-# cat /sys/devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/nmem0/nfit/id
-8089-a2-1740-00000133
-The DIMM id would be provided along with the key payload (passphrase) to
-the kernel.
-
-The security keys are managed on the basis of a single key per DIMM. The
-key "passphrase" is expected to be 32bytes long. This is similar to the ATA
-security specification [2]. A key is initially acquired via the request_key()
-kernel API call during nvdimm unlock. It is up to the user to make sure that
-all the keys are in the kernel user keyring for unlock.
-
-A nvdimm encrypted-key of format enc32 has the description format of:
-nvdimm:<bus-provider-specific-unique-id>
-
-See file ``Documentation/security/keys/trusted-encrypted.rst`` for creating
-encrypted-keys of enc32 format. TPM usage with a master trusted key is
-preferred for sealing the encrypted-keys.
-
-4. Unlocking
-------------
-When the DIMMs are being enumerated by the kernel, the kernel will attempt to
-retrieve the key from the kernel user keyring. This is the only time
-a locked DIMM can be unlocked. Once unlocked, the DIMM will remain unlocked
-until reboot. Typically an entity (i.e. shell script) will inject all the
-relevant encrypted-keys into the kernel user keyring during the initramfs phase.
-This provides the unlock function access to all the related keys that contain
-the passphrase for the respective nvdimms.  It is also recommended that the
-keys are injected before libnvdimm is loaded by modprobe.
-
-5. Update
----------
-When doing an update, it is expected that the existing key is removed from
-the kernel user keyring and reinjected as different (old) key. It's irrelevant
-what the key description is for the old key since we are only interested in the
-keyid when doing the update operation. It is also expected that the new key
-is injected with the description format described from earlier in this
-document.  The update command written to the sysfs attribute will be with
-the format:
-update <old keyid> <new keyid>
-
-If there is no old keyid due to a security enabling, then a 0 should be
-passed in.
-
-6. Freeze
----------
-The freeze operation does not require any keys. The security config can be
-frozen by a user with root privelege.
-
-7. Disable
-----------
-The security disable command format is:
-disable <keyid>
-
-An key with the current passphrase payload that is tied to the nvdimm should be
-in the kernel user keyring.
-
-8. Secure Erase
----------------
-The command format for doing a secure erase is:
-erase <keyid>
-
-An key with the current passphrase payload that is tied to the nvdimm should be
-in the kernel user keyring.
-
-9. Overwrite
-------------
-The command format for doing an overwrite is:
-overwrite <keyid>
-
-Overwrite can be done without a key if security is not enabled. A key serial
-of 0 can be passed in to indicate no key.
-
-The sysfs attribute "security" can be polled to wait on overwrite completion.
-Overwrite can last tens of minutes or more depending on nvdimm size.
-
-An encrypted-key with the current user passphrase that is tied to the nvdimm
-should be injected and its keyid should be passed in via sysfs.
-
-10. Master Update
------------------
-The command format for doing a master update is:
-update <old keyid> <new keyid>
-
-The operating mechanism for master update is identical to update except the
-master passphrase key is passed to the kernel. The master passphrase key
-is just another encrypted-key.
-
-This command is only available when security is disabled.
-
-11. Master Erase
-----------------
-The command format for doing a master erase is:
-master_erase <current keyid>
-
-This command has the same operating mechanism as erase except the master
-passphrase key is passed to the kernel. The master passphrase key is just
-another encrypted-key.
-
-This command is only available when the master security is enabled, indicated
-by the extended security status.
-
-[1]: http://pmem.io/documents/NVDIMM_DSM_Interface-V1.8.pdf
-[2]: http://www.t13.org/documents/UploadedDocuments/docs2006/e05179r4-ACS-SecurityClarifications.pdf
diff --git a/Documentation/nvmem/nvmem.txt b/Documentation/nvmem/nvmem.txt
deleted file mode 100644 (file)
index fc2fe4b..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-                           NVMEM SUBSYSTEM
-         Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
-
-This document explains the NVMEM Framework along with the APIs provided,
-and how to use it.
-
-1. Introduction
-===============
-*NVMEM* is the abbreviation for Non Volatile Memory layer. It is used to
-retrieve configuration of SOC or Device specific data from non volatile
-memories like eeprom, efuses and so on.
-
-Before this framework existed, NVMEM drivers like eeprom were stored in
-drivers/misc, where they all had to duplicate pretty much the same code to
-register a sysfs file, allow in-kernel users to access the content of the
-devices they were driving, etc.
-
-This was also a problem as far as other in-kernel users were involved, since
-the solutions used were pretty much different from one driver to another, there
-was a rather big abstraction leak.
-
-This framework aims at solve these problems. It also introduces DT
-representation for consumer devices to go get the data they require (MAC
-Addresses, SoC/Revision ID, part numbers, and so on) from the NVMEMs. This
-framework is based on regmap, so that most of the abstraction available in
-regmap can be reused, across multiple types of buses.
-
-NVMEM Providers
-+++++++++++++++
-
-NVMEM provider refers to an entity that implements methods to initialize, read
-and write the non-volatile memory.
-
-2. Registering/Unregistering the NVMEM provider
-===============================================
-
-A NVMEM provider can register with NVMEM core by supplying relevant
-nvmem configuration to nvmem_register(), on success core would return a valid
-nvmem_device pointer.
-
-nvmem_unregister(nvmem) is used to unregister a previously registered provider.
-
-For example, a simple qfprom case:
-
-static struct nvmem_config econfig = {
-       .name = "qfprom",
-       .owner = THIS_MODULE,
-};
-
-static int qfprom_probe(struct platform_device *pdev)
-{
-       ...
-       econfig.dev = &pdev->dev;
-       nvmem = nvmem_register(&econfig);
-       ...
-}
-
-It is mandatory that the NVMEM provider has a regmap associated with its
-struct device. Failure to do would return error code from nvmem_register().
-
-Users of board files can define and register nvmem cells using the
-nvmem_cell_table struct:
-
-static struct nvmem_cell_info foo_nvmem_cells[] = {
-       {
-               .name           = "macaddr",
-               .offset         = 0x7f00,
-               .bytes          = ETH_ALEN,
-       }
-};
-
-static struct nvmem_cell_table foo_nvmem_cell_table = {
-       .nvmem_name             = "i2c-eeprom",
-       .cells                  = foo_nvmem_cells,
-       .ncells                 = ARRAY_SIZE(foo_nvmem_cells),
-};
-
-nvmem_add_cell_table(&foo_nvmem_cell_table);
-
-Additionally it is possible to create nvmem cell lookup entries and register
-them with the nvmem framework from machine code as shown in the example below:
-
-static struct nvmem_cell_lookup foo_nvmem_lookup = {
-       .nvmem_name             = "i2c-eeprom",
-       .cell_name              = "macaddr",
-       .dev_id                 = "foo_mac.0",
-       .con_id                 = "mac-address",
-};
-
-nvmem_add_cell_lookups(&foo_nvmem_lookup, 1);
-
-NVMEM Consumers
-+++++++++++++++
-
-NVMEM consumers are the entities which make use of the NVMEM provider to
-read from and to NVMEM.
-
-3. NVMEM cell based consumer APIs
-=================================
-
-NVMEM cells are the data entries/fields in the NVMEM.
-The NVMEM framework provides 3 APIs to read/write NVMEM cells.
-
-struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *name);
-struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *name);
-
-void nvmem_cell_put(struct nvmem_cell *cell);
-void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell);
-
-void *nvmem_cell_read(struct nvmem_cell *cell, ssize_t *len);
-int nvmem_cell_write(struct nvmem_cell *cell, void *buf, ssize_t len);
-
-*nvmem_cell_get() apis will get a reference to nvmem cell for a given id,
-and nvmem_cell_read/write() can then read or write to the cell.
-Once the usage of the cell is finished the consumer should call *nvmem_cell_put()
-to free all the allocation memory for the cell.
-
-4. Direct NVMEM device based consumer APIs
-==========================================
-
-In some instances it is necessary to directly read/write the NVMEM.
-To facilitate such consumers NVMEM framework provides below apis.
-
-struct nvmem_device *nvmem_device_get(struct device *dev, const char *name);
-struct nvmem_device *devm_nvmem_device_get(struct device *dev,
-                                          const char *name);
-void nvmem_device_put(struct nvmem_device *nvmem);
-int nvmem_device_read(struct nvmem_device *nvmem, unsigned int offset,
-                     size_t bytes, void *buf);
-int nvmem_device_write(struct nvmem_device *nvmem, unsigned int offset,
-                      size_t bytes, void *buf);
-int nvmem_device_cell_read(struct nvmem_device *nvmem,
-                          struct nvmem_cell_info *info, void *buf);
-int nvmem_device_cell_write(struct nvmem_device *nvmem,
-                           struct nvmem_cell_info *info, void *buf);
-
-Before the consumers can read/write NVMEM directly, it should get hold
-of nvmem_controller from one of the *nvmem_device_get() api.
-
-The difference between these apis and cell based apis is that these apis always
-take nvmem_device as parameter.
-
-5. Releasing a reference to the NVMEM
-=====================================
-
-When a consumer no longer needs the NVMEM, it has to release the reference
-to the NVMEM it has obtained using the APIs mentioned in the above section.
-The NVMEM framework provides 2 APIs to release a reference to the NVMEM.
-
-void nvmem_cell_put(struct nvmem_cell *cell);
-void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell);
-void nvmem_device_put(struct nvmem_device *nvmem);
-void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem);
-
-Both these APIs are used to release a reference to the NVMEM and
-devm_nvmem_cell_put and devm_nvmem_device_put destroys the devres associated
-with this NVMEM.
-
-Userspace
-+++++++++
-
-6. Userspace binary interface
-==============================
-
-Userspace can read/write the raw NVMEM file located at
-/sys/bus/nvmem/devices/*/nvmem
-
-ex:
-
-hexdump /sys/bus/nvmem/devices/qfprom0/nvmem
-
-0000000 0000 0000 0000 0000 0000 0000 0000 0000
-*
-00000a0 db10 2240 0000 e000 0c00 0c00 0000 0c00
-0000000 0000 0000 0000 0000 0000 0000 0000 0000
-...
-*
-0001000
-
-7. DeviceTree Binding
-=====================
-
-See Documentation/devicetree/bindings/nvmem/nvmem.txt
index 779c852..7ae1f62 100644 (file)
@@ -1,4 +1,4 @@
-:orphan:
+.. SPDX-License-Identifier: GPL-2.0
 
 ======
 pcmcia
diff --git a/Documentation/perf/arm-ccn.txt b/Documentation/perf/arm-ccn.txt
deleted file mode 100644 (file)
index 15cdb7b..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-ARM Cache Coherent Network
-==========================
-
-CCN-504 is a ring-bus interconnect consisting of 11 crosspoints
-(XPs), with each crosspoint supporting up to two device ports,
-so nodes (devices) 0 and 1 are connected to crosspoint 0,
-nodes 2 and 3 to crosspoint 1 etc.
-
-PMU (perf) driver
------------------
-
-The CCN driver registers a perf PMU driver, which provides
-description of available events and configuration options
-in sysfs, see /sys/bus/event_source/devices/ccn*.
-
-The "format" directory describes format of the config, config1
-and config2 fields of the perf_event_attr structure. The "events"
-directory provides configuration templates for all documented
-events, that can be used with perf tool. For example "xp_valid_flit"
-is an equivalent of "type=0x8,event=0x4". Other parameters must be
-explicitly specified.
-
-For events originating from device, "node" defines its index.
-
-Crosspoint PMU events require "xp" (index), "bus" (bus number)
-and "vc" (virtual channel ID).
-
-Crosspoint watchpoint-based events (special "event" value 0xfe)
-require "xp" and "vc" as as above plus "port" (device port index),
-"dir" (transmit/receive direction), comparator values ("cmp_l"
-and "cmp_h") and "mask", being index of the comparator mask.
-Masks are defined separately from the event description
-(due to limited number of the config values) in the "cmp_mask"
-directory, with first 8 configurable by user and additional
-4 hardcoded for the most frequent use cases.
-
-Cycle counter is described by a "type" value 0xff and does
-not require any other settings.
-
-The driver also provides a "cpumask" sysfs attribute, which contains
-a single CPU ID, of the processor which will be used to handle all
-the CCN PMU events. It is recommended that the user space tools
-request the events on this processor (if not, the perf_event->cpu value
-will be overwritten anyway). In case of this processor being offlined,
-the events are migrated to another one and the attribute is updated.
-
-Example of perf tool use:
-
-/ # perf list | grep ccn
-  ccn/cycles/                                        [Kernel PMU event]
-<...>
-  ccn/xp_valid_flit,xp=?,port=?,vc=?,dir=?/          [Kernel PMU event]
-<...>
-
-/ # perf stat -a -e ccn/cycles/,ccn/xp_valid_flit,xp=1,port=0,vc=1,dir=1/ \
-                                                                       sleep 1
-
-The driver does not support sampling, therefore "perf record" will
-not work. Per-task (without "-a") perf sessions are not supported.
diff --git a/Documentation/perf/arm_dsu_pmu.txt b/Documentation/perf/arm_dsu_pmu.txt
deleted file mode 100644 (file)
index d611e15..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-ARM DynamIQ Shared Unit (DSU) PMU
-==================================
-
-ARM DynamIQ Shared Unit integrates one or more cores with an L3 memory system,
-control logic and external interfaces to form a multicore cluster. The PMU
-allows counting the various events related to the L3 cache, Snoop Control Unit
-etc, using 32bit independent counters. It also provides a 64bit cycle counter.
-
-The PMU can only be accessed via CPU system registers and are common to the
-cores connected to the same DSU. Like most of the other uncore PMUs, DSU
-PMU doesn't support process specific events and cannot be used in sampling mode.
-
-The DSU provides a bitmap for a subset of implemented events via hardware
-registers. There is no way for the driver to determine if the other events
-are available or not. Hence the driver exposes only those events advertised
-by the DSU, in "events" directory under :
-
-  /sys/bus/event_sources/devices/arm_dsu_<N>/
-
-The user should refer to the TRM of the product to figure out the supported events
-and use the raw event code for the unlisted events.
-
-The driver also exposes the CPUs connected to the DSU instance in "associated_cpus".
-
-
-e.g usage :
-
-       perf stat -a -e arm_dsu_0/cycles/
diff --git a/Documentation/perf/hisi-pmu.txt b/Documentation/perf/hisi-pmu.txt
deleted file mode 100644 (file)
index 267a028..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-HiSilicon SoC uncore Performance Monitoring Unit (PMU)
-======================================================
-The HiSilicon SoC chip includes various independent system device PMUs
-such as L3 cache (L3C), Hydra Home Agent (HHA) and DDRC. These PMUs are
-independent and have hardware logic to gather statistics and performance
-information.
-
-The HiSilicon SoC encapsulates multiple CPU and IO dies. Each CPU cluster
-(CCL) is made up of 4 cpu cores sharing one L3 cache; each CPU die is
-called Super CPU cluster (SCCL) and is made up of 6 CCLs. Each SCCL has
-two HHAs (0 - 1) and four DDRCs (0 - 3), respectively.
-
-HiSilicon SoC uncore PMU driver
----------------------------------------
-Each device PMU has separate registers for event counting, control and
-interrupt, and the PMU driver shall register perf PMU drivers like L3C,
-HHA and DDRC etc. The available events and configuration options shall
-be described in the sysfs, see :
-/sys/devices/hisi_sccl{X}_<l3c{Y}/hha{Y}/ddrc{Y}>/, or
-/sys/bus/event_source/devices/hisi_sccl{X}_<l3c{Y}/hha{Y}/ddrc{Y}>.
-The "perf list" command shall list the available events from sysfs.
-
-Each L3C, HHA and DDRC is registered as a separate PMU with perf. The PMU
-name will appear in event listing as hisi_sccl<sccl-id>_module<index-id>.
-where "sccl-id" is the identifier of the SCCL and "index-id" is the index of
-module.
-e.g. hisi_sccl3_l3c0/rd_hit_cpipe is READ_HIT_CPIPE event of L3C index #0 in
-SCCL ID #3.
-e.g. hisi_sccl1_hha0/rx_operations is RX_OPERATIONS event of HHA index #0 in
-SCCL ID #1.
-
-The driver also provides a "cpumask" sysfs attribute, which shows the CPU core
-ID used to count the uncore PMU event.
-
-Example usage of perf:
-$# perf list
-hisi_sccl3_l3c0/rd_hit_cpipe/ [kernel PMU event]
-------------------------------------------
-hisi_sccl3_l3c0/wr_hit_cpipe/ [kernel PMU event]
-------------------------------------------
-hisi_sccl1_l3c0/rd_hit_cpipe/ [kernel PMU event]
-------------------------------------------
-hisi_sccl1_l3c0/wr_hit_cpipe/ [kernel PMU event]
-------------------------------------------
-
-$# perf stat -a -e hisi_sccl3_l3c0/rd_hit_cpipe/ sleep 5
-$# perf stat -a -e hisi_sccl3_l3c0/config=0x02/ sleep 5
-
-The current driver does not support sampling. So "perf record" is unsupported.
-Also attach to a task is unsupported as the events are all uncore.
-
-Note: Please contact the maintainer for a complete list of events supported for
-the PMU devices in the SoC and its information if needed.
diff --git a/Documentation/perf/qcom_l2_pmu.txt b/Documentation/perf/qcom_l2_pmu.txt
deleted file mode 100644 (file)
index b25b976..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-Qualcomm Technologies Level-2 Cache Performance Monitoring Unit (PMU)
-=====================================================================
-
-This driver supports the L2 cache clusters found in Qualcomm Technologies
-Centriq SoCs. There are multiple physical L2 cache clusters, each with their
-own PMU. Each cluster has one or more CPUs associated with it.
-
-There is one logical L2 PMU exposed, which aggregates the results from
-the physical PMUs.
-
-The driver provides a description of its available events and configuration
-options in sysfs, see /sys/devices/l2cache_0.
-
-The "format" directory describes the format of the events.
-
-Events can be envisioned as a 2-dimensional array. Each column represents
-a group of events. There are 8 groups. Only one entry from each
-group can be in use at a time. If multiple events from the same group
-are specified, the conflicting events cannot be counted at the same time.
-
-Events are specified as 0xCCG, where CC is 2 hex digits specifying
-the code (array row) and G specifies the group (column) 0-7.
-
-In addition there is a cycle counter event specified by the value 0xFE
-which is outside the above scheme.
-
-The driver provides a "cpumask" sysfs attribute which contains a mask
-consisting of one CPU per cluster which will be used to handle all the PMU
-events on that cluster.
-
-Examples for use with perf:
-
-  perf stat -e l2cache_0/config=0x001/,l2cache_0/config=0x042/ -a sleep 1
-
-  perf stat -e l2cache_0/config=0xfe/ -C 2 sleep 1
-
-The driver does not support sampling, therefore "perf record" will
-not work. Per-task perf sessions are not supported.
diff --git a/Documentation/perf/qcom_l3_pmu.txt b/Documentation/perf/qcom_l3_pmu.txt
deleted file mode 100644 (file)
index 96b3a94..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-Qualcomm Datacenter Technologies L3 Cache Performance Monitoring Unit (PMU)
-===========================================================================
-
-This driver supports the L3 cache PMUs found in Qualcomm Datacenter Technologies
-Centriq SoCs. The L3 cache on these SOCs is composed of multiple slices, shared
-by all cores within a socket. Each slice is exposed as a separate uncore perf
-PMU with device name l3cache_<socket>_<instance>. User space is responsible
-for aggregating across slices.
-
-The driver provides a description of its available events and configuration
-options in sysfs, see /sys/devices/l3cache*. Given that these are uncore PMUs
-the driver also exposes a "cpumask" sysfs attribute which contains a mask
-consisting of one CPU per socket which will be used to handle all the PMU
-events on that socket.
-
-The hardware implements 32bit event counters and has a flat 8bit event space
-exposed via the "event" format attribute. In addition to the 32bit physical
-counters the driver supports virtual 64bit hardware counters by using hardware
-counter chaining. This feature is exposed via the "lc" (long counter) format
-flag. E.g.:
-
-  perf stat -e l3cache_0_0/read-miss,lc/
-
-Given that these are uncore PMUs the driver does not support sampling, therefore
-"perf record" will not work. Per-task perf sessions are not supported.
diff --git a/Documentation/perf/thunderx2-pmu.txt b/Documentation/perf/thunderx2-pmu.txt
deleted file mode 100644 (file)
index dffc571..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-Cavium ThunderX2 SoC Performance Monitoring Unit (PMU UNCORE)
-=============================================================
-
-The ThunderX2 SoC PMU consists of independent, system-wide, per-socket
-PMUs such as the Level 3 Cache (L3C) and DDR4 Memory Controller (DMC).
-
-The DMC has 8 interleaved channels and the L3C has 16 interleaved tiles.
-Events are counted for the default channel (i.e. channel 0) and prorated
-to the total number of channels/tiles.
-
-The DMC and L3C support up to 4 counters. Counters are independently
-programmable and can be started and stopped individually. Each counter
-can be set to a different event. Counters are 32-bit and do not support
-an overflow interrupt; they are read every 2 seconds.
-
-PMU UNCORE (perf) driver:
-
-The thunderx2_pmu driver registers per-socket perf PMUs for the DMC and
-L3C devices.  Each PMU can be used to count up to 4 events
-simultaneously. The PMUs provide a description of their available events
-and configuration options under sysfs, see
-/sys/devices/uncore_<l3c_S/dmc_S/>; S is the socket id.
-
-The driver does not support sampling, therefore "perf record" will not
-work. Per-task perf sessions are also not supported.
-
-Examples:
-
-# perf stat -a -e uncore_dmc_0/cnt_cycles/ sleep 1
-
-# perf stat -a -e \
-uncore_dmc_0/cnt_cycles/,\
-uncore_dmc_0/data_transfers/,\
-uncore_dmc_0/read_txns/,\
-uncore_dmc_0/write_txns/ sleep 1
-
-# perf stat -a -e \
-uncore_l3c_0/read_request/,\
-uncore_l3c_0/read_hit/,\
-uncore_l3c_0/inv_request/,\
-uncore_l3c_0/inv_hit/ sleep 1
diff --git a/Documentation/perf/xgene-pmu.txt b/Documentation/perf/xgene-pmu.txt
deleted file mode 100644 (file)
index d7cff44..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-APM X-Gene SoC Performance Monitoring Unit (PMU)
-================================================
-
-X-Gene SoC PMU consists of various independent system device PMUs such as
-L3 cache(s), I/O bridge(s), memory controller bridge(s) and memory
-controller(s). These PMU devices are loosely architected to follow the
-same model as the PMU for ARM cores. The PMUs share the same top level
-interrupt and status CSR region.
-
-PMU (perf) driver
------------------
-
-The xgene-pmu driver registers several perf PMU drivers. Each of the perf
-driver provides description of its available events and configuration options
-in sysfs, see /sys/devices/<l3cX/iobX/mcbX/mcX>/.
-
-The "format" directory describes format of the config (event ID),
-config1 (agent ID) fields of the perf_event_attr structure. The "events"
-directory provides configuration templates for all supported event types that
-can be used with perf tool. For example, "l3c0/bank-fifo-full/" is an
-equivalent of "l3c0/config=0x0b/".
-
-Most of the SoC PMU has a specific list of agent ID used for monitoring
-performance of a specific datapath. For example, agents of a L3 cache can be
-a specific CPU or an I/O bridge. Each PMU has a set of 2 registers capable of
-masking the agents from which the request come from. If the bit with
-the bit number corresponding to the agent is set, the event is counted only if
-it is caused by a request from that agent. Each agent ID bit is inversely mapped
-to a corresponding bit in "config1" field. By default, the event will be
-counted for all agent requests (config1 = 0x0). For all the supported agents of
-each PMU, please refer to APM X-Gene User Manual.
-
-Each perf driver also provides a "cpumask" sysfs attribute, which contains a
-single CPU ID of the processor which will be used to handle all the PMU events.
-
-Example for perf tool use:
-
- / # perf list | grep -e l3c -e iob -e mcb -e mc
-   l3c0/ackq-full/                                    [Kernel PMU event]
- <...>
-   mcb1/mcb-csw-stall/                                [Kernel PMU event]
-
- / # perf stat -a -e l3c0/read-miss/,mcb1/csw-write-request/ sleep 1
-
- / # perf stat -a -e l3c0/read-miss,config1=0xfffffffffffffffe/ sleep 1
-
-The driver does not support sampling, therefore "perf record" will
-not work. Per-task (without "-a") perf sessions are not supported.
diff --git a/Documentation/phy/samsung-usb2.txt b/Documentation/phy/samsung-usb2.txt
deleted file mode 100644 (file)
index ed12d43..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-.------------------------------------------------------------------------------+
-|                      Samsung USB 2.0 PHY adaptation layer                   |
-+-----------------------------------------------------------------------------+'
-
-| 1. Description
-+----------------
-
-The architecture of the USB 2.0 PHY module in Samsung SoCs is similar
-among many SoCs. In spite of the similarities it proved difficult to
-create a one driver that would fit all these PHY controllers. Often
-the differences were minor and were found in particular bits of the
-registers of the PHY. In some rare cases the order of register writes or
-the PHY powering up process had to be altered. This adaptation layer is
-a compromise between having separate drivers and having a single driver
-with added support for many special cases.
-
-| 2. Files description
-+----------------------
-
-- phy-samsung-usb2.c
-   This is the main file of the adaptation layer. This file contains
-   the probe function and provides two callbacks to the Generic PHY
-   Framework. This two callbacks are used to power on and power off the
-   phy. They carry out the common work that has to be done on all version
-   of the PHY module. Depending on which SoC was chosen they execute SoC
-   specific callbacks. The specific SoC version is selected by choosing
-   the appropriate compatible string. In addition, this file contains
-   struct of_device_id definitions for particular SoCs.
-
-- phy-samsung-usb2.h
-   This is the include file. It declares the structures used by this
-   driver. In addition it should contain extern declarations for
-   structures that describe particular SoCs.
-
-| 3. Supporting SoCs
-+--------------------
-
-To support a new SoC a new file should be added to the drivers/phy
-directory. Each SoC's configuration is stored in an instance of the
-struct samsung_usb2_phy_config.
-
-struct samsung_usb2_phy_config {
-       const struct samsung_usb2_common_phy *phys;
-       int (*rate_to_clk)(unsigned long, u32 *);
-       unsigned int num_phys;
-       bool has_mode_switch;
-};
-
-The num_phys is the number of phys handled by the driver. *phys is an
-array that contains the configuration for each phy. The has_mode_switch
-property is a boolean flag that determines whether the SoC has USB host
-and device on a single pair of pins. If so, a special register has to
-be modified to change the internal routing of these pins between a USB
-device or host module.
-
-For example the configuration for Exynos 4210 is following:
-
-const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
-       .has_mode_switch        = 0,
-       .num_phys               = EXYNOS4210_NUM_PHYS,
-       .phys                   = exynos4210_phys,
-       .rate_to_clk            = exynos4210_rate_to_clk,
-}
-
-- int (*rate_to_clk)(unsigned long, u32 *)
-       The rate_to_clk callback is to convert the rate of the clock
-       used as the reference clock for the PHY module to the value
-       that should be written in the hardware register.
-
-The exynos4210_phys configuration array is as follows:
-
-static const struct samsung_usb2_common_phy exynos4210_phys[] = {
-       {
-               .label          = "device",
-               .id             = EXYNOS4210_DEVICE,
-               .power_on       = exynos4210_power_on,
-               .power_off      = exynos4210_power_off,
-       },
-       {
-               .label          = "host",
-               .id             = EXYNOS4210_HOST,
-               .power_on       = exynos4210_power_on,
-               .power_off      = exynos4210_power_off,
-       },
-       {
-               .label          = "hsic0",
-               .id             = EXYNOS4210_HSIC0,
-               .power_on       = exynos4210_power_on,
-               .power_off      = exynos4210_power_off,
-       },
-       {
-               .label          = "hsic1",
-               .id             = EXYNOS4210_HSIC1,
-               .power_on       = exynos4210_power_on,
-               .power_off      = exynos4210_power_off,
-       },
-       {},
-};
-
-- int (*power_on)(struct samsung_usb2_phy_instance *);
-- int (*power_off)(struct samsung_usb2_phy_instance *);
-       These two callbacks are used to power on and power off the phy
-       by modifying appropriate registers.
-
-Final change to the driver is adding appropriate compatible value to the
-phy-samsung-usb2.c file. In case of Exynos 4210 the following lines were
-added to the struct of_device_id samsung_usb2_phy_of_match[] array:
-
-#ifdef CONFIG_PHY_EXYNOS4210_USB2
-       {
-               .compatible = "samsung,exynos4210-usb2-phy",
-               .data = &exynos4210_usb2_phy_config,
-       },
-#endif
-
-To add further flexibility to the driver the Kconfig file enables to
-include support for selected SoCs in the compiled driver. The Kconfig
-entry for Exynos 4210 is following:
-
-config PHY_EXYNOS4210_USB2
-       bool "Support for Exynos 4210"
-       depends on PHY_SAMSUNG_USB2
-       depends on CPU_EXYNOS4210
-       help
-         Enable USB PHY support for Exynos 4210. This option requires that
-         Samsung USB 2.0 PHY driver is enabled and means that support for this
-         particular SoC is compiled in the driver. In case of Exynos 4210 four
-         phys are available - device, host, HSCI0 and HSCI1.
-
-The newly created file that supports the new SoC has to be also added to the
-Makefile. In case of Exynos 4210 the added line is following:
-
-obj-$(CONFIG_PHY_EXYNOS4210_USB2)       += phy-exynos4210-usb2.o
-
-After completing these steps the support for the new SoC should be ready.
index b154f6c..c33ba2b 100644 (file)
@@ -119,4 +119,4 @@ properties of futexes, and all four combinations are possible: futex,
 robust-futex, PI-futex, robust+PI-futex.
 
 More details about priority inheritance can be found in
-Documentation/locking/rt-mutex.txt.
+Documentation/locking/rt-mutex.rst.
index 945fc6d..69921f0 100644 (file)
@@ -129,7 +129,7 @@ int dev_pm_qos_remove_request(handle):
   and call the notification trees if the target was changed as a result of
   removing the request.
 
-s32 dev_pm_qos_read_value(device):
+s32 dev_pm_qos_read_value(device, type):
   Returns the aggregated value for a given device's constraints list.
 
 enum pm_qos_flags_status dev_pm_qos_flags(device, mask)
@@ -176,12 +176,14 @@ Notification mechanisms:
 
 The per-device PM QoS framework has a per-device notification tree.
 
-int dev_pm_qos_add_notifier(device, notifier):
-  Adds a notification callback function for the device.
+int dev_pm_qos_add_notifier(device, notifier, type):
+  Adds a notification callback function for the device for a particular request
+  type.
+
   The callback is called when the aggregated value of the device constraints list
-  is changed (for resume latency device PM QoS only).
+  is changed.
 
-int dev_pm_qos_remove_notifier(device, notifier):
+int dev_pm_qos_remove_notifier(device, notifier, type):
   Removes the notification callback function for the device.
 
 
index 0c41d6d..10e7f4d 100644 (file)
@@ -59,7 +59,7 @@ as follows:
          the default calculated size. Use this option if default
          boot memory size is not sufficient for second kernel to
          boot successfully. For syntax of crashkernel= parameter,
-         refer to Documentation/kdump/kdump.rst. If any offset is
+         refer to Documentation/admin-guide/kdump/kdump.rst. If any offset is
          provided in crashkernel= parameter, it will be ignored
          as fadump uses a predefined offset to reserve memory
          for boot memory dump preservation in case of a crash.
index 365efc9..8e56337 100644 (file)
@@ -107,7 +107,7 @@ and elsewhere regarding submitting Linux kernel patches.
     and why.
 
 26) If any ioctl's are added by the patch, then also update
-    ``Documentation/ioctl/ioctl-number.txt``.
+    ``Documentation/ioctl/ioctl-number.rst``.
 
 27) If your modified source code depends on or uses any of the kernel
     APIs or features that are related to the following ``Kconfig`` symbols,
diff --git a/Documentation/pti/pti_intel_mid.txt b/Documentation/pti/pti_intel_mid.txt
deleted file mode 100644 (file)
index e7a5b6d..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-The Intel MID PTI project is HW implemented in Intel Atom
-system-on-a-chip designs based on the Parallel Trace
-Interface for MIPI P1149.7 cJTAG standard.  The kernel solution
-for this platform involves the following files:
-
-./include/linux/pti.h
-./drivers/.../n_tracesink.h
-./drivers/.../n_tracerouter.c
-./drivers/.../n_tracesink.c
-./drivers/.../pti.c
-
-pti.c is the driver that enables various debugging features
-popular on platforms from certain mobile manufacturers.
-n_tracerouter.c and n_tracesink.c allow extra system information to
-be collected and routed to the pti driver, such as trace
-debugging data from a modem.  Although n_tracerouter
-and n_tracesink are a part of the complete PTI solution,
-these two line disciplines can work separately from
-pti.c and route any data stream from one /dev/tty node
-to another /dev/tty node via kernel-space.  This provides
-a stable, reliable connection that will not break unless
-the user-space application shuts down (plus avoids
-kernel->user->kernel context switch overheads of routing
-data).
-
-An example debugging usage for this driver system:
-   *Hook /dev/ttyPTI0 to syslogd.  Opening this port will also start
-    a console device to further capture debugging messages to PTI.
-   *Hook /dev/ttyPTI1 to modem debugging data to write to PTI HW.
-    This is where n_tracerouter and n_tracesink are used.
-   *Hook /dev/pti to a user-level debugging application for writing
-    to PTI HW.
-   *Use mipi_* Kernel Driver API in other device drivers for
-    debugging to PTI by first requesting a PTI write address via
-    mipi_request_masterchannel(1).
-
-Below is example pseudo-code on how a 'privileged' application
-can hook up n_tracerouter and n_tracesink to any tty on
-a system.  'Privileged' means the application has enough
-privileges to successfully manipulate the ldisc drivers
-but is not just blindly executing as 'root'. Keep in mind
-the use of ioctl(,TIOCSETD,) is not specific to the n_tracerouter
-and n_tracesink line discpline drivers but is a generic
-operation for a program to use a line discpline driver
-on a tty port other than the default n_tty.
-
-/////////// To hook up n_tracerouter and n_tracesink /////////
-
-// Note that n_tracerouter depends on n_tracesink.
-#include <errno.h>
-#define ONE_TTY "/dev/ttyOne"
-#define TWO_TTY "/dev/ttyTwo"
-
-// needed global to hand onto ldisc connection
-static int g_fd_source = -1;
-static int g_fd_sink  = -1;
-
-// these two vars used to grab LDISC values from loaded ldisc drivers
-// in OS.  Look at /proc/tty/ldiscs to get the right numbers from
-// the ldiscs loaded in the system.
-int source_ldisc_num, sink_ldisc_num = -1;
-int retval;
-
-g_fd_source = open(ONE_TTY, O_RDWR); // must be R/W
-g_fd_sink   = open(TWO_TTY, O_RDWR); // must be R/W
-
-if (g_fd_source <= 0) || (g_fd_sink <= 0) {
-   // doubt you'll want to use these exact error lines of code
-   printf("Error on open(). errno: %d\n",errno);
-   return errno;
-}
-
-retval = ioctl(g_fd_sink, TIOCSETD, &sink_ldisc_num);
-if (retval < 0) {
-   printf("Error on ioctl().  errno: %d\n", errno);
-   return errno;
-}
-
-retval = ioctl(g_fd_source, TIOCSETD, &source_ldisc_num);
-if (retval < 0) {
-   printf("Error on ioctl().  errno: %d\n", errno);
-   return errno;
-}
-
-/////////// To disconnect n_tracerouter and n_tracesink ////////
-
-// First make sure data through the ldiscs has stopped.
-
-// Second, disconnect ldiscs.  This provides a
-// little cleaner shutdown on tty stack.
-sink_ldisc_num = 0;
-source_ldisc_num = 0;
-ioctl(g_fd_uart, TIOCSETD, &sink_ldisc_num);
-ioctl(g_fd_gadget, TIOCSETD, &source_ldisc_num);
-
-// Three, program closes connection, and cleanup:
-close(g_fd_uart);
-close(g_fd_gadget);
-g_fd_uart = g_fd_gadget = NULL;
diff --git a/Documentation/rapidio/mport_cdev.txt b/Documentation/rapidio/mport_cdev.txt
deleted file mode 100644 (file)
index a53f786..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-RapidIO subsystem mport character device driver (rio_mport_cdev.c)
-==================================================================
-
-Version History:
-----------------
-  1.0.0 - Initial driver release.
-
-==================================================================
-
-I. Overview
-
-This device driver is the result of collaboration within the RapidIO.org
-Software Task Group (STG) between Texas Instruments, Freescale,
-Prodrive Technologies, Nokia Networks, BAE and IDT.  Additional input was
-received from other members of RapidIO.org. The objective was to create a
-character mode driver interface which exposes the capabilities of RapidIO
-devices directly to applications, in a manner that allows the numerous and
-varied RapidIO implementations to interoperate.
-
-This driver (MPORT_CDEV) provides access to basic RapidIO subsystem operations
-for user-space applications. Most of RapidIO operations are supported through
-'ioctl' system calls.
-
-When loaded this device driver creates filesystem nodes named rio_mportX in /dev
-directory for each registered RapidIO mport device. 'X' in the node name matches
-to unique port ID assigned to each local mport device.
-
-Using available set of ioctl commands user-space applications can perform
-following RapidIO bus and subsystem operations:
-
-- Reads and writes from/to configuration registers of mport devices
-    (RIO_MPORT_MAINT_READ_LOCAL/RIO_MPORT_MAINT_WRITE_LOCAL)
-- Reads and writes from/to configuration registers of remote RapidIO devices.
-  This operations are defined as RapidIO Maintenance reads/writes in RIO spec.
-    (RIO_MPORT_MAINT_READ_REMOTE/RIO_MPORT_MAINT_WRITE_REMOTE)
-- Set RapidIO Destination ID for mport devices (RIO_MPORT_MAINT_HDID_SET)
-- Set RapidIO Component Tag for mport devices (RIO_MPORT_MAINT_COMPTAG_SET)
-- Query logical index of mport devices (RIO_MPORT_MAINT_PORT_IDX_GET)
-- Query capabilities and RapidIO link configuration of mport devices
-    (RIO_MPORT_GET_PROPERTIES)
-- Enable/Disable reporting of RapidIO doorbell events to user-space applications
-    (RIO_ENABLE_DOORBELL_RANGE/RIO_DISABLE_DOORBELL_RANGE)
-- Enable/Disable reporting of RIO port-write events to user-space applications
-    (RIO_ENABLE_PORTWRITE_RANGE/RIO_DISABLE_PORTWRITE_RANGE)
-- Query/Control type of events reported through this driver: doorbells,
-  port-writes or both (RIO_SET_EVENT_MASK/RIO_GET_EVENT_MASK)
-- Configure/Map mport's outbound requests window(s) for specific size,
-  RapidIO destination ID, hopcount and request type
-    (RIO_MAP_OUTBOUND/RIO_UNMAP_OUTBOUND)
-- Configure/Map mport's inbound requests window(s) for specific size,
-  RapidIO base address and local memory base address
-    (RIO_MAP_INBOUND/RIO_UNMAP_INBOUND)
-- Allocate/Free contiguous DMA coherent memory buffer for DMA data transfers
-  to/from remote RapidIO devices (RIO_ALLOC_DMA/RIO_FREE_DMA)
-- Initiate DMA data transfers to/from remote RapidIO devices (RIO_TRANSFER).
-  Supports blocking, asynchronous and posted (a.k.a 'fire-and-forget') data
-  transfer modes.
-- Check/Wait for completion of asynchronous DMA data transfer
-    (RIO_WAIT_FOR_ASYNC)
-- Manage device objects supported by RapidIO subsystem (RIO_DEV_ADD/RIO_DEV_DEL).
-  This allows implementation of various RapidIO fabric enumeration algorithms
-  as user-space applications while using remaining functionality provided by
-  kernel RapidIO subsystem.
-
-II. Hardware Compatibility
-
-This device driver uses standard interfaces defined by kernel RapidIO subsystem
-and therefore it can be used with any mport device driver registered by RapidIO
-subsystem with limitations set by available mport implementation.
-
-At this moment the most common limitation is availability of RapidIO-specific
-DMA engine framework for specific mport device. Users should verify available
-functionality of their platform when planning to use this driver:
-
-- IDT Tsi721 PCIe-to-RapidIO bridge device and its mport device driver are fully
-  compatible with this driver.
-- Freescale SoCs 'fsl_rio' mport driver does not have implementation for RapidIO
-  specific DMA engine support and therefore DMA data transfers mport_cdev driver
-  are not available.
-
-III. Module parameters
-
-- 'dma_timeout' - DMA transfer completion timeout (in msec, default value 3000).
-        This parameter set a maximum completion wait time for SYNC mode DMA
-        transfer requests and for RIO_WAIT_FOR_ASYNC ioctl requests.
-
-- 'dbg_level' - This parameter allows to control amount of debug information
-        generated by this device driver. This parameter is formed by set of
-        bit masks that correspond to the specific functional blocks.
-        For mask definitions see 'drivers/rapidio/devices/rio_mport_cdev.c'
-        This parameter can be changed dynamically.
-        Use CONFIG_RAPIDIO_DEBUG=y to enable debug output at the top level.
-
-IV. Known problems
-
-  None.
-
-V. User-space Applications and API
-
-API library and applications that use this device driver are available from
-RapidIO.org.
-
-VI. TODO List
-
-- Add support for sending/receiving "raw" RapidIO messaging packets.
-- Add memory mapped DMA data transfers as an option when RapidIO-specific DMA
-  is not available.
diff --git a/Documentation/rapidio/rapidio.txt b/Documentation/rapidio/rapidio.txt
deleted file mode 100644 (file)
index 28fbd87..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-                          The Linux RapidIO Subsystem
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The RapidIO standard is a packet-based fabric interconnect standard designed for
-use in embedded systems. Development of the RapidIO standard is directed by the
-RapidIO Trade Association (RTA). The current version of the RapidIO specification
-is publicly available for download from the RTA web-site [1].
-
-This document describes the basics of the Linux RapidIO subsystem and provides
-information on its major components.
-
-1 Overview
-----------
-
-Because the RapidIO subsystem follows the Linux device model it is integrated
-into the kernel similarly to other buses by defining RapidIO-specific device and
-bus types and registering them within the device model.
-
-The Linux RapidIO subsystem is architecture independent and therefore defines
-architecture-specific interfaces that provide support for common RapidIO
-subsystem operations.
-
-2. Core Components
-------------------
-
-A typical RapidIO network is a combination of endpoints and switches.
-Each of these components is represented in the subsystem by an associated data
-structure. The core logical components of the RapidIO subsystem are defined
-in include/linux/rio.h file.
-
-2.1 Master Port
-
-A master port (or mport) is a RapidIO interface controller that is local to the
-processor executing the Linux code. A master port generates and receives RapidIO
-packets (transactions). In the RapidIO subsystem each master port is represented
-by a rio_mport data structure. This structure contains master port specific
-resources such as mailboxes and doorbells. The rio_mport also includes a unique
-host device ID that is valid when a master port is configured as an enumerating
-host.
-
-RapidIO master ports are serviced by subsystem specific mport device drivers
-that provide functionality defined for this subsystem. To provide a hardware
-independent interface for RapidIO subsystem operations, rio_mport structure
-includes rio_ops data structure which contains pointers to hardware specific
-implementations of RapidIO functions.
-
-2.2 Device
-
-A RapidIO device is any endpoint (other than mport) or switch in the network.
-All devices are presented in the RapidIO subsystem by corresponding rio_dev data
-structure. Devices form one global device list and per-network device lists
-(depending on number of available mports and networks).
-
-2.3 Switch
-
-A RapidIO switch is a special class of device that routes packets between its
-ports towards their final destination. The packet destination port within a
-switch is defined by an internal routing table. A switch is presented in the
-RapidIO subsystem by rio_dev data structure expanded by additional rio_switch
-data structure, which contains switch specific information such as copy of the
-routing table and pointers to switch specific functions.
-
-The RapidIO subsystem defines the format and initialization method for subsystem
-specific switch drivers that are designed to provide hardware-specific
-implementation of common switch management routines.
-
-2.4 Network
-
-A RapidIO network is a combination of interconnected endpoint and switch devices.
-Each RapidIO network known to the system is represented by corresponding rio_net
-data structure. This structure includes lists of all devices and local master
-ports that form the same network. It also contains a pointer to the default
-master port that is used to communicate with devices within the network.
-
-2.5 Device Drivers
-
-RapidIO device-specific drivers follow Linux Kernel Driver Model and are
-intended to support specific RapidIO devices attached to the RapidIO network.
-
-2.6 Subsystem Interfaces
-
-RapidIO interconnect specification defines features that may be used to provide
-one or more common service layers for all participating RapidIO devices. These
-common services may act separately from device-specific drivers or be used by
-device-specific drivers. Example of such service provider is the RIONET driver
-which implements Ethernet-over-RapidIO interface. Because only one driver can be
-registered for a device, all common RapidIO services have to be registered as
-subsystem interfaces. This allows to have multiple common services attached to
-the same device without blocking attachment of a device-specific driver.
-
-3. Subsystem Initialization
----------------------------
-
-In order to initialize the RapidIO subsystem, a platform must initialize and
-register at least one master port within the RapidIO network. To register mport
-within the subsystem controller driver's initialization code calls function
-rio_register_mport() for each available master port.
-
-After all active master ports are registered with a RapidIO subsystem,
-an enumeration and/or discovery routine may be called automatically or
-by user-space command.
-
-RapidIO subsystem can be configured to be built as a statically linked or
-modular component of the kernel (see details below).
-
-4. Enumeration and Discovery
-----------------------------
-
-4.1 Overview
-------------
-
-RapidIO subsystem configuration options allow users to build enumeration and
-discovery methods as statically linked components or loadable modules.
-An enumeration/discovery method implementation and available input parameters
-define how any given method can be attached to available RapidIO mports:
-simply to all available mports OR individually to the specified mport device.
-
-Depending on selected enumeration/discovery build configuration, there are
-several methods to initiate an enumeration and/or discovery process:
-
-  (a) Statically linked enumeration and discovery process can be started
-  automatically during kernel initialization time using corresponding module
-  parameters. This was the original method used since introduction of RapidIO
-  subsystem. Now this method relies on enumerator module parameter which is
-  'rio-scan.scan' for existing basic enumeration/discovery method.
-  When automatic start of enumeration/discovery is used a user has to ensure
-  that all discovering endpoints are started before the enumerating endpoint
-  and are waiting for enumeration to be completed.
-  Configuration option CONFIG_RAPIDIO_DISC_TIMEOUT defines time that discovering
-  endpoint waits for enumeration to be completed. If the specified timeout
-  expires the discovery process is terminated without obtaining RapidIO network
-  information. NOTE: a timed out discovery process may be restarted later using
-  a user-space command as it is described below (if the given endpoint was
-  enumerated successfully).
-
-  (b) Statically linked enumeration and discovery process can be started by
-  a command from user space. This initiation method provides more flexibility
-  for a system startup compared to the option (a) above. After all participating
-  endpoints have been successfully booted, an enumeration process shall be
-  started first by issuing a user-space command, after an enumeration is
-  completed a discovery process can be started on all remaining endpoints.
-
-  (c) Modular enumeration and discovery process can be started by a command from
-  user space. After an enumeration/discovery module is loaded, a network scan
-  process can be started by issuing a user-space command.
-  Similar to the option (b) above, an enumerator has to be started first.
-
-  (d) Modular enumeration and discovery process can be started by a module
-  initialization routine. In this case an enumerating module shall be loaded
-  first.
-
-When a network scan process is started it calls an enumeration or discovery
-routine depending on the configured role of a master port: host or agent.
-
-Enumeration is performed by a master port if it is configured as a host port by
-assigning a host destination ID greater than or equal to zero. The host
-destination ID can be assigned to a master port using various methods depending
-on RapidIO subsystem build configuration:
-
-  (a) For a statically linked RapidIO subsystem core use command line parameter
-  "rapidio.hdid=" with a list of destination ID assignments in order of mport
-  device registration. For example, in a system with two RapidIO controllers
-  the command line parameter "rapidio.hdid=-1,7" will result in assignment of
-  the host destination ID=7 to the second RapidIO controller, while the first
-  one will be assigned destination ID=-1.
-
-  (b) If the RapidIO subsystem core is built as a loadable module, in addition
-  to the method shown above, the host destination ID(s) can be specified using
-  traditional methods of passing module parameter "hdid=" during its loading:
-  - from command line: "modprobe rapidio hdid=-1,7", or
-  - from modprobe configuration file using configuration command "options",
-    like in this example: "options rapidio hdid=-1,7". An example of modprobe
-    configuration file is provided in the section below.
-
-  NOTES:
-  (i) if "hdid=" parameter is omitted all available mport will be assigned
-  destination ID = -1;
-  (ii) the "hdid=" parameter in systems with multiple mports can have
-  destination ID assignments omitted from the end of list (default = -1).
-
-If the host device ID for a specific master port is set to -1, the discovery
-process will be performed for it.
-
-The enumeration and discovery routines use RapidIO maintenance transactions
-to access the configuration space of devices.
-
-NOTE: If RapidIO switch-specific device drivers are built as loadable modules
-they must be loaded before enumeration/discovery process starts.
-This requirement is cased by the fact that enumeration/discovery methods invoke
-vendor-specific callbacks on early stages.
-
-4.2 Automatic Start of Enumeration and Discovery
-------------------------------------------------
-
-Automatic enumeration/discovery start method is applicable only to built-in
-enumeration/discovery RapidIO configuration selection. To enable automatic
-enumeration/discovery start by existing basic enumerator method set use boot
-command line parameter "rio-scan.scan=1".
-
-This configuration requires synchronized start of all RapidIO endpoints that
-form a network which will be enumerated/discovered. Discovering endpoints have
-to be started before an enumeration starts to ensure that all RapidIO
-controllers have been initialized and are ready to be discovered. Configuration
-parameter CONFIG_RAPIDIO_DISC_TIMEOUT defines time (in seconds) which
-a discovering endpoint will wait for enumeration to be completed.
-
-When automatic enumeration/discovery start is selected, basic method's
-initialization routine calls rio_init_mports() to perform enumeration or
-discovery for all known mport devices.
-
-Depending on RapidIO network size and configuration this automatic
-enumeration/discovery start method may be difficult to use due to the
-requirement for synchronized start of all endpoints.
-
-4.3 User-space Start of Enumeration and Discovery
--------------------------------------------------
-
-User-space start of enumeration and discovery can be used with built-in and
-modular build configurations. For user-space controlled start RapidIO subsystem
-creates the sysfs write-only attribute file '/sys/bus/rapidio/scan'. To initiate
-an enumeration or discovery process on specific mport device, a user needs to
-write mport_ID (not RapidIO destination ID) into that file. The mport_ID is a
-sequential number (0 ... RIO_MAX_MPORTS) assigned during mport device
-registration. For example for machine with single RapidIO controller, mport_ID
-for that controller always will be 0.
-
-To initiate RapidIO enumeration/discovery on all available mports a user may
-write '-1' (or RIO_MPORT_ANY) into the scan attribute file.
-
-4.4 Basic Enumeration Method
-----------------------------
-
-This is an original enumeration/discovery method which is available since
-first release of RapidIO subsystem code. The enumeration process is
-implemented according to the enumeration algorithm outlined in the RapidIO
-Interconnect Specification: Annex I [1].
-
-This method can be configured as statically linked or loadable module.
-The method's single parameter "scan" allows to trigger the enumeration/discovery
-process from module initialization routine.
-
-This enumeration/discovery method can be started only once and does not support
-unloading if it is built as a module.
-
-The enumeration process traverses the network using a recursive depth-first
-algorithm. When a new device is found, the enumerator takes ownership of that
-device by writing into the Host Device ID Lock CSR. It does this to ensure that
-the enumerator has exclusive right to enumerate the device. If device ownership
-is successfully acquired, the enumerator allocates a new rio_dev structure and
-initializes it according to device capabilities.
-
-If the device is an endpoint, a unique device ID is assigned to it and its value
-is written into the device's Base Device ID CSR.
-
-If the device is a switch, the enumerator allocates an additional rio_switch
-structure to store switch specific information. Then the switch's vendor ID and
-device ID are queried against a table of known RapidIO switches. Each switch
-table entry contains a pointer to a switch-specific initialization routine that
-initializes pointers to the rest of switch specific operations, and performs
-hardware initialization if necessary. A RapidIO switch does not have a unique
-device ID; it relies on hopcount and routing for device ID of an attached
-endpoint if access to its configuration registers is required. If a switch (or
-chain of switches) does not have any endpoint (except enumerator) attached to
-it, a fake device ID will be assigned to configure a route to that switch.
-In the case of a chain of switches without endpoint, one fake device ID is used
-to configure a route through the entire chain and switches are differentiated by
-their hopcount value.
-
-For both endpoints and switches the enumerator writes a unique component tag
-into device's Component Tag CSR. That unique value is used by the error
-management notification mechanism to identify a device that is reporting an
-error management event.
-
-Enumeration beyond a switch is completed by iterating over each active egress
-port of that switch. For each active link, a route to a default device ID
-(0xFF for 8-bit systems and 0xFFFF for 16-bit systems) is temporarily written
-into the routing table. The algorithm recurs by calling itself with hopcount + 1
-and the default device ID in order to access the device on the active port.
-
-After the host has completed enumeration of the entire network it releases
-devices by clearing device ID locks (calls rio_clear_locks()). For each endpoint
-in the system, it sets the Discovered bit in the Port General Control CSR
-to indicate that enumeration is completed and agents are allowed to execute
-passive discovery of the network.
-
-The discovery process is performed by agents and is similar to the enumeration
-process that is described above. However, the discovery process is performed
-without changes to the existing routing because agents only gather information
-about RapidIO network structure and are building an internal map of discovered
-devices. This way each Linux-based component of the RapidIO subsystem has
-a complete view of the network. The discovery process can be performed
-simultaneously by several agents. After initializing its RapidIO master port
-each agent waits for enumeration completion by the host for the configured wait
-time period. If this wait time period expires before enumeration is completed,
-an agent skips RapidIO discovery and continues with remaining kernel
-initialization.
-
-4.5 Adding New Enumeration/Discovery Method
--------------------------------------------
-
-RapidIO subsystem code organization allows addition of new enumeration/discovery
-methods as new configuration options without significant impact to the core
-RapidIO code.
-
-A new enumeration/discovery method has to be attached to one or more mport
-devices before an enumeration/discovery process can be started. Normally,
-method's module initialization routine calls rio_register_scan() to attach
-an enumerator to a specified mport device (or devices). The basic enumerator
-implementation demonstrates this process.
-
-4.6 Using Loadable RapidIO Switch Drivers
------------------------------------------
-
-In the case when RapidIO switch drivers are built as loadable modules a user
-must ensure that they are loaded before the enumeration/discovery starts.
-This process can be automated by specifying pre- or post- dependencies in the
-RapidIO-specific modprobe configuration file as shown in the example below.
-
-  File /etc/modprobe.d/rapidio.conf:
-  ----------------------------------
-
-  # Configure RapidIO subsystem modules
-
-  # Set enumerator host destination ID (overrides kernel command line option)
-  options rapidio hdid=-1,2
-
-  # Load RapidIO switch drivers immediately after rapidio core module was loaded
-  softdep rapidio post: idt_gen2 idtcps tsi57x
-
-  # OR :
-
-  # Load RapidIO switch drivers just before rio-scan enumerator module is loaded
-  softdep rio-scan pre: idt_gen2 idtcps tsi57x
-
-  --------------------------
-
-NOTE: In the example above, one of "softdep" commands must be removed or
-commented out to keep required module loading sequence.
-
-A. References
--------------
-
-[1] RapidIO Trade Association. RapidIO Interconnect Specifications.
-    http://www.rapidio.org.
-[2] Rapidio TA. Technology Comparisons.
-    http://www.rapidio.org/education/technology_comparisons/
-[3] RapidIO support for Linux.
-    http://lwn.net/Articles/139118/
-[4] Matt Porter. RapidIO for Linux. Ottawa Linux Symposium, 2005
-    http://www.kernel.org/doc/ols/2005/ols2005v2-pages-43-56.pdf
diff --git a/Documentation/rapidio/rio_cm.txt b/Documentation/rapidio/rio_cm.txt
deleted file mode 100644 (file)
index 27aa401..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-RapidIO subsystem Channelized Messaging character device driver (rio_cm.c)
-==========================================================================
-
-Version History:
-----------------
-  1.0.0 - Initial driver release.
-
-==========================================================================
-
-I. Overview
-
-This device driver is the result of collaboration within the RapidIO.org
-Software Task Group (STG) between Texas Instruments, Prodrive Technologies,
-Nokia Networks, BAE and IDT.  Additional input was received from other members
-of RapidIO.org.
-
-The objective was to create a character mode driver interface which exposes
-messaging capabilities of RapidIO endpoint devices (mports) directly
-to applications, in a manner that allows the numerous and varied RapidIO
-implementations to interoperate.
-
-This driver (RIO_CM) provides to user-space applications shared access to
-RapidIO mailbox messaging resources.
-
-RapidIO specification (Part 2) defines that endpoint devices may have up to four
-messaging mailboxes in case of multi-packet message (up to 4KB) and
-up to 64 mailboxes if single-packet messages (up to 256 B) are used. In addition
-to protocol definition limitations, a particular hardware implementation can
-have reduced number of messaging mailboxes.  RapidIO aware applications must
-therefore share the messaging resources of a RapidIO endpoint.
-
-Main purpose of this device driver is to provide RapidIO mailbox messaging
-capability to large number of user-space processes by introducing socket-like
-operations using a single messaging mailbox.  This allows applications to
-use the limited RapidIO messaging hardware resources efficiently.
-
-Most of device driver's operations are supported through 'ioctl' system calls.
-
-When loaded this device driver creates a single file system node named rio_cm
-in /dev directory common for all registered RapidIO mport devices.
-
-Following ioctl commands are available to user-space applications:
-
-- RIO_CM_MPORT_GET_LIST : Returns to caller list of local mport devices that
-    support messaging operations (number of entries up to RIO_MAX_MPORTS).
-    Each list entry is combination of mport's index in the system and RapidIO
-    destination ID assigned to the port.
-- RIO_CM_EP_GET_LIST_SIZE : Returns number of messaging capable remote endpoints
-    in a RapidIO network associated with the specified mport device.
-- RIO_CM_EP_GET_LIST : Returns list of RapidIO destination IDs for messaging
-    capable remote endpoints (peers) available in a RapidIO network associated
-    with the specified mport device.
-- RIO_CM_CHAN_CREATE : Creates RapidIO message exchange channel data structure
-    with channel ID assigned automatically or as requested by a caller.
-- RIO_CM_CHAN_BIND : Binds the specified channel data structure to the specified
-    mport device.
-- RIO_CM_CHAN_LISTEN : Enables listening for connection requests on the specified
-    channel.
-- RIO_CM_CHAN_ACCEPT : Accepts a connection request from peer on the specified
-    channel. If wait timeout for this request is specified by a caller it is
-    a blocking call. If timeout set to 0 this is non-blocking call - ioctl
-    handler checks for a pending connection request and if one is not available
-    exits with -EGAIN error status immediately.
-- RIO_CM_CHAN_CONNECT : Sends a connection request to a remote peer/channel.
-- RIO_CM_CHAN_SEND : Sends a data message through the specified channel.
-    The handler for this request assumes that message buffer specified by
-    a caller includes the reserved space for a packet header required by
-    this driver.
-- RIO_CM_CHAN_RECEIVE : Receives a data message through a connected channel.
-    If the channel does not have an incoming message ready to return this ioctl
-    handler will wait for new message until timeout specified by a caller
-    expires. If timeout value is set to 0, ioctl handler uses a default value
-    defined by MAX_SCHEDULE_TIMEOUT.
-- RIO_CM_CHAN_CLOSE : Closes a specified channel and frees associated buffers.
-    If the specified channel is in the CONNECTED state, sends close notification
-    to the remote peer.
-
-The ioctl command codes and corresponding data structures intended for use by
-user-space applications are defined in 'include/uapi/linux/rio_cm_cdev.h'.
-
-II. Hardware Compatibility
-
-This device driver uses standard interfaces defined by kernel RapidIO subsystem
-and therefore it can be used with any mport device driver registered by RapidIO
-subsystem with limitations set by available mport HW implementation of messaging
-mailboxes.
-
-III. Module parameters
-
-- 'dbg_level' - This parameter allows to control amount of debug information
-        generated by this device driver. This parameter is formed by set of
-        bit masks that correspond to the specific functional block.
-        For mask definitions see 'drivers/rapidio/devices/rio_cm.c'
-        This parameter can be changed dynamically.
-        Use CONFIG_RAPIDIO_DEBUG=y to enable debug output at the top level.
-
-- 'cmbox' - Number of RapidIO mailbox to use (default value is 1).
-        This parameter allows to set messaging mailbox number that will be used
-        within entire RapidIO network. It can be used when default mailbox is
-        used by other device drivers or is not supported by some nodes in the
-        RapidIO network.
-
-- 'chstart' - Start channel number for dynamic assignment. Default value - 256.
-        Allows to exclude channel numbers below this parameter from dynamic
-        allocation to avoid conflicts with software components that use
-        reserved predefined channel numbers.
-
-IV. Known problems
-
-  None.
-
-V. User-space Applications and API Library
-
-Messaging API library and applications that use this device driver are available
-from RapidIO.org.
-
-VI. TODO List
-
-- Add support for system notification messages (reserved channel 0).
diff --git a/Documentation/rapidio/sysfs.txt b/Documentation/rapidio/sysfs.txt
deleted file mode 100644 (file)
index a1adac8..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-The RapidIO sysfs files have moved to:
-Documentation/ABI/testing/sysfs-bus-rapidio and
-Documentation/ABI/testing/sysfs-class-rapidio
diff --git a/Documentation/rapidio/tsi721.txt b/Documentation/rapidio/tsi721.txt
deleted file mode 100644 (file)
index cd2a293..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-RapidIO subsystem mport driver for IDT Tsi721 PCI Express-to-SRIO bridge.
-=========================================================================
-
-I. Overview
-
-This driver implements all currently defined RapidIO mport callback functions.
-It supports maintenance read and write operations, inbound and outbound RapidIO
-doorbells, inbound maintenance port-writes and RapidIO messaging.
-
-To generate SRIO maintenance transactions this driver uses one of Tsi721 DMA
-channels. This mechanism provides access to larger range of hop counts and
-destination IDs without need for changes in outbound window translation.
-
-RapidIO messaging support uses dedicated messaging channels for each mailbox.
-For inbound messages this driver uses destination ID matching to forward messages
-into the corresponding message queue. Messaging callbacks are implemented to be
-fully compatible with RIONET driver (Ethernet over RapidIO messaging services).
-
-1. Module parameters:
-- 'dbg_level' - This parameter allows to control amount of debug information
-        generated by this device driver. This parameter is formed by set of
-        This parameter can be changed bit masks that correspond to the specific
-        functional block.
-        For mask definitions see 'drivers/rapidio/devices/tsi721.h'
-        This parameter can be changed dynamically.
-        Use CONFIG_RAPIDIO_DEBUG=y to enable debug output at the top level.
-
-- 'dma_desc_per_channel' - This parameter defines number of hardware buffer
-        descriptors allocated for each registered Tsi721 DMA channel.
-        Its default value is 128.
-
-- 'dma_txqueue_sz' - DMA transactions queue size. Defines number of pending
-        transaction requests that can be accepted by each DMA channel.
-        Default value is 16.
-
-- 'dma_sel' - DMA channel selection mask. Bitmask that defines which hardware
-        DMA channels (0 ... 6) will be registered with DmaEngine core.
-        If bit is set to 1, the corresponding DMA channel will be registered.
-        DMA channels not selected by this mask will not be used by this device
-        driver. Default value is 0x7f (use all channels).
-
-- 'pcie_mrrs' - override value for PCIe Maximum Read Request Size (MRRS).
-        This parameter gives an ability to override MRRS value set during PCIe
-        configuration process. Tsi721 supports read request sizes up to 4096B.
-        Value for this parameter must be set as defined by PCIe specification:
-        0 = 128B, 1 = 256B, 2 = 512B, 3 = 1024B, 4 = 2048B and 5 = 4096B.
-        Default value is '-1' (= keep platform setting).
-
-- 'mbox_sel' - RIO messaging MBOX selection mask. This is a bitmask that defines
-        messaging MBOXes are managed by this device driver. Mask bits 0 - 3
-        correspond to MBOX0 - MBOX3. MBOX is under driver's control if the
-        corresponding bit is set to '1'. Default value is 0x0f (= all).
-
-II. Known problems
-
-  None.
-
-III. DMA Engine Support
-
-Tsi721 mport driver supports DMA data transfers between local system memory and
-remote RapidIO devices. This functionality is implemented according to SLAVE
-mode API defined by common Linux kernel DMA Engine framework.
-
-Depending on system requirements RapidIO DMA operations can be included/excluded
-by setting CONFIG_RAPIDIO_DMA_ENGINE option. Tsi721 miniport driver uses seven
-out of eight available BDMA channels to support DMA data transfers.
-One BDMA channel is reserved for generation of maintenance read/write requests.
-
-If Tsi721 mport driver have been built with RAPIDIO_DMA_ENGINE support included,
-this driver will accept DMA-specific module parameter:
-  "dma_desc_per_channel" - defines number of hardware buffer descriptors used by
-                           each BDMA channel of Tsi721 (by default - 128).
-
-IV. Version History
-
-  1.1.0 - DMA operations re-worked to support data scatter/gather lists larger
-          than hardware buffer descriptors ring.
-  1.0.0 - Initial driver release.
-
-V.  License
------------------------------------------------
-
-  Copyright(c) 2011 Integrated Device Technology, Inc. All rights reserved.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by the Free
-  Software Foundation; either version 2 of the License, or (at your option)
-  any later version.
-
-  This program is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
index c42a21b..523d54b 100644 (file)
@@ -204,21 +204,21 @@ potentially expensive tree iterations. This is done at negligible runtime
 overhead for maintanence; albeit larger memory footprint.
 
 Similar to the rb_root structure, cached rbtrees are initialized to be
-empty via:
+empty via::
 
   struct rb_root_cached mytree = RB_ROOT_CACHED;
 
 Cached rbtree is simply a regular rb_root with an extra pointer to cache the
 leftmost node. This allows rb_root_cached to exist wherever rb_root does,
 which permits augmented trees to be supported as well as only a few extra
-interfaces:
+interfaces::
 
   struct rb_node *rb_first_cached(struct rb_root_cached *tree);
   void rb_insert_color_cached(struct rb_node *, struct rb_root_cached *, bool);
   void rb_erase_cached(struct rb_node *node, struct rb_root_cached *);
 
 Both insert and erase calls have their respective counterpart of augmented
-trees:
+trees::
 
   void rb_insert_augmented_cached(struct rb_node *node, struct rb_root_cached *,
                                  bool, struct rb_augment_callbacks *);
index 77fb03a..03c3d2e 100644 (file)
@@ -314,6 +314,8 @@ Here are the various resource types that are currently supported::
    * @RSC_VDEV:       declare support for a virtio device, and serve as its
    *               virtio header.
    * @RSC_LAST:       just keep this one at the end
+   * @RSC_VENDOR_START:        start of the vendor specific resource types range
+   * @RSC_VENDOR_END:  end of the vendor specific resource types range
    *
    * Please note that these values are used as indices to the rproc_handle_rsc
    * lookup table, so please keep them sane. Moreover, @RSC_LAST is used to
@@ -321,11 +323,13 @@ Here are the various resource types that are currently supported::
    * please update it as needed.
    */
   enum fw_resource_type {
-       RSC_CARVEOUT    = 0,
-       RSC_DEVMEM      = 1,
-       RSC_TRACE       = 2,
-       RSC_VDEV        = 3,
-       RSC_LAST        = 4,
+       RSC_CARVEOUT            = 0,
+       RSC_DEVMEM              = 1,
+       RSC_TRACE               = 2,
+       RSC_VDEV                = 3,
+       RSC_LAST                = 4,
+       RSC_VENDOR_START        = 128,
+       RSC_VENDOR_END          = 512,
   };
 
 For more details regarding a specific resource type, please see its
diff --git a/Documentation/riscv/boot-image-header.txt b/Documentation/riscv/boot-image-header.txt
new file mode 100644 (file)
index 0000000..1b73fea
--- /dev/null
@@ -0,0 +1,50 @@
+                               Boot image header in RISC-V Linux
+                       =============================================
+
+Author: Atish Patra <atish.patra@wdc.com>
+Date  : 20 May 2019
+
+This document only describes the boot image header details for RISC-V Linux.
+The complete booting guide will be available at Documentation/riscv/booting.txt.
+
+The following 64-byte header is present in decompressed Linux kernel image.
+
+       u32 code0;                /* Executable code */
+       u32 code1;                /* Executable code */
+       u64 text_offset;          /* Image load offset, little endian */
+       u64 image_size;           /* Effective Image size, little endian */
+       u64 flags;                /* kernel flags, little endian */
+       u32 version;              /* Version of this header */
+       u32 res1  = 0;            /* Reserved */
+       u64 res2  = 0;            /* Reserved */
+       u64 magic = 0x5643534952; /* Magic number, little endian, "RISCV" */
+       u32 res3;                 /* Reserved for additional RISC-V specific header */
+       u32 res4;                 /* Reserved for PE COFF offset */
+
+This header format is compliant with PE/COFF header and largely inspired from
+ARM64 header. Thus, both ARM64 & RISC-V header can be combined into one common
+header in future.
+
+Notes:
+- This header can also be reused to support EFI stub for RISC-V in future. EFI
+  specification needs PE/COFF image header in the beginning of the kernel image
+  in order to load it as an EFI application. In order to support EFI stub,
+  code0 should be replaced with "MZ" magic string and res5(at offset 0x3c) should
+  point to the rest of the PE/COFF header.
+
+- version field indicate header version number.
+       Bits 0:15  - Minor version
+       Bits 16:31 - Major version
+
+  This preserves compatibility across newer and older version of the header.
+  The current version is defined as 0.1.
+
+- res3 is reserved for offset to any other additional fields. This makes the
+  header extendible in future. One example would be to accommodate ISA
+  extension for RISC-V in future. For current version, it is set to be zero.
+
+- In current header, the flag field has only one field.
+       Bit 0: Kernel endianness. 1 if BE, 0 if LE.
+
+- Image size is mandatory for boot loader to load kernel image. Booting will
+  fail otherwise.
index c4b906d..e3ca092 100644 (file)
@@ -1,5 +1,3 @@
-:orphan:
-
 ===================
 RISC-V architecture
 ===================
index d49305f..73ad0b0 100644 (file)
@@ -170,7 +170,7 @@ currently running at.
 |        +----------------+-------------------------------------------------+
 |        |    32          | Basic Addressing Mode                           |
 |        |                |                                                 |
-|        |                | Used to set addressing mode                     |
+|        |                | Used to set addressing mode::                   |
 |        |                |                                                 |
 |        |                |    +---------+----------+----------+            |
 |        |                |    | PSW 31  | PSW 32   |          |            |
index 1a914da..4602312 100644 (file)
@@ -1,5 +1,3 @@
-:orphan:
-
 =================
 s390 Architecture
 =================
index 1f6d0b5..1e210c6 100644 (file)
@@ -38,7 +38,7 @@ every detail. More information/reference could be found here:
   qemu/hw/s390x/css.c
 
 For vfio mediated device framework:
-- Documentation/vfio-mediated-device.txt
+- Documentation/driver-api/vfio-mediated-device.rst
 
 Motivation of vfio-ccw
 ----------------------
@@ -322,5 +322,5 @@ Reference
 2. ESA/390 Common I/O Device Commands manual (IBM Form. No. SA22-7204)
 3. https://en.wikipedia.org/wiki/Channel_I/O
 4. Documentation/s390/cds.rst
-5. Documentation/vfio.txt
-6. Documentation/vfio-mediated-device.txt
+5. Documentation/driver-api/vfio.rst
+6. Documentation/driver-api/vfio-mediated-device.rst
index 058be77..69074e5 100644 (file)
@@ -1,5 +1,3 @@
-:orphan:
-
 ===============
 Linux Scheduler
 ===============
index 3391e86..14a2f7b 100644 (file)
@@ -669,7 +669,7 @@ Deadline Task Scheduling
 
  -deadline tasks cannot have an affinity mask smaller that the entire
  root_domain they are created on. However, affinities can be specified
- through the cpuset facility (Documentation/cgroup-v1/cpusets.rst).
+ through the cpuset facility (Documentation/admin-guide/cgroup-v1/cpusets.rst).
 
 5.1 SCHED_DEADLINE and cpusets HOWTO
 ------------------------------------
index 53b30d1..a96c726 100644 (file)
@@ -222,7 +222,7 @@ SCHED_BATCH) tasks.
 
    These options need CONFIG_CGROUPS to be defined, and let the administrator
    create arbitrary groups of tasks, using the "cgroup" pseudo filesystem.  See
-   Documentation/cgroup-v1/cgroups.rst for more information about this filesystem.
+   Documentation/admin-guide/cgroup-v1/cgroups.rst for more information about this filesystem.
 
 When CONFIG_FAIR_GROUP_SCHED is defined, a "cpu.shares" file is created for each
 group created using the pseudo filesystem.  See example steps below to create
index d27d3f3..655a096 100644 (file)
@@ -133,7 +133,7 @@ This uses the cgroup virtual file system and "<cgroup>/cpu.rt_runtime_us"
 to control the CPU time reserved for each control group.
 
 For more information on working with control groups, you should read
-Documentation/cgroup-v1/cgroups.rst as well.
+Documentation/admin-guide/cgroup-v1/cgroups.rst as well.
 
 Group settings are checked against the following limits in order to keep the
 configuration schedulable:
index aad6d92..fc503dd 100644 (file)
@@ -8,7 +8,10 @@ Security Documentation
    credentials
    IMA-templates
    keys/index
-   LSM
+   lsm
+   lsm-development
+   sak
    SCTP
    self-protection
+   siphash
    tpm/index
index af77a7b..3296533 100644 (file)
@@ -5,3 +5,4 @@ Trusted Platform Module documentation
 .. toctree::
 
    tpm_vtpm_proxy
+   xen-tpmfront
diff --git a/Documentation/security/tpm/xen-tpmfront.rst b/Documentation/security/tpm/xen-tpmfront.rst
new file mode 100644 (file)
index 0000000..00d5b1d
--- /dev/null
@@ -0,0 +1,124 @@
+=============================
+Virtual TPM interface for Xen
+=============================
+
+Authors: Matthew Fioravante (JHUAPL), Daniel De Graaf (NSA)
+
+This document describes the virtual Trusted Platform Module (vTPM) subsystem for
+Xen. The reader is assumed to have familiarity with building and installing Xen,
+Linux, and a basic understanding of the TPM and vTPM concepts.
+
+Introduction
+------------
+
+The goal of this work is to provide a TPM functionality to a virtual guest
+operating system (in Xen terms, a DomU).  This allows programs to interact with
+a TPM in a virtual system the same way they interact with a TPM on the physical
+system.  Each guest gets its own unique, emulated, software TPM.  However, each
+of the vTPM's secrets (Keys, NVRAM, etc) are managed by a vTPM Manager domain,
+which seals the secrets to the Physical TPM.  If the process of creating each of
+these domains (manager, vTPM, and guest) is trusted, the vTPM subsystem extends
+the chain of trust rooted in the hardware TPM to virtual machines in Xen. Each
+major component of vTPM is implemented as a separate domain, providing secure
+separation guaranteed by the hypervisor. The vTPM domains are implemented in
+mini-os to reduce memory and processor overhead.
+
+This mini-os vTPM subsystem was built on top of the previous vTPM work done by
+IBM and Intel corporation.
+
+
+Design Overview
+---------------
+
+The architecture of vTPM is described below::
+
+  +------------------+
+  |    Linux DomU    | ...
+  |       |  ^       |
+  |       v  |       |
+  |   xen-tpmfront   |
+  +------------------+
+          |  ^
+          v  |
+  +------------------+
+  | mini-os/tpmback  |
+  |       |  ^       |
+  |       v  |       |
+  |  vtpm-stubdom    | ...
+  |       |  ^       |
+  |       v  |       |
+  | mini-os/tpmfront |
+  +------------------+
+          |  ^
+          v  |
+  +------------------+
+  | mini-os/tpmback  |
+  |       |  ^       |
+  |       v  |       |
+  | vtpmmgr-stubdom  |
+  |       |  ^       |
+  |       v  |       |
+  | mini-os/tpm_tis  |
+  +------------------+
+          |  ^
+          v  |
+  +------------------+
+  |   Hardware TPM   |
+  +------------------+
+
+* Linux DomU:
+              The Linux based guest that wants to use a vTPM. There may be
+              more than one of these.
+
+* xen-tpmfront.ko:
+                   Linux kernel virtual TPM frontend driver. This driver
+                    provides vTPM access to a Linux-based DomU.
+
+* mini-os/tpmback:
+                   Mini-os TPM backend driver. The Linux frontend driver
+                   connects to this backend driver to facilitate communications
+                   between the Linux DomU and its vTPM. This driver is also
+                   used by vtpmmgr-stubdom to communicate with vtpm-stubdom.
+
+* vtpm-stubdom:
+                A mini-os stub domain that implements a vTPM. There is a
+                one to one mapping between running vtpm-stubdom instances and
+                 logical vtpms on the system. The vTPM Platform Configuration
+                 Registers (PCRs) are normally all initialized to zero.
+
+* mini-os/tpmfront:
+                    Mini-os TPM frontend driver. The vTPM mini-os domain
+                    vtpm-stubdom uses this driver to communicate with
+                    vtpmmgr-stubdom. This driver is also used in mini-os
+                    domains such as pv-grub that talk to the vTPM domain.
+
+* vtpmmgr-stubdom:
+                   A mini-os domain that implements the vTPM manager. There is
+                   only one vTPM manager and it should be running during the
+                   entire lifetime of the machine.  This domain regulates
+                   access to the physical TPM on the system and secures the
+                   persistent state of each vTPM.
+
+* mini-os/tpm_tis:
+                   Mini-os TPM version 1.2 TPM Interface Specification (TIS)
+                    driver. This driver used by vtpmmgr-stubdom to talk directly to
+                    the hardware TPM. Communication is facilitated by mapping
+                    hardware memory pages into vtpmmgr-stubdom.
+
+* Hardware TPM:
+               The physical TPM that is soldered onto the motherboard.
+
+
+Integration With Xen
+--------------------
+
+Support for the vTPM driver was added in Xen using the libxl toolstack in Xen
+4.3.  See the Xen documentation (docs/misc/vtpm.txt) for details on setting up
+the vTPM and vTPM Manager stub domains.  Once the stub domains are running, a
+vTPM device is set up in the same manner as a disk or network device in the
+domain's configuration file.
+
+In order to use features such as IMA that require a TPM to be loaded prior to
+the initrd, the xen-tpmfront driver must be compiled in to the kernel.  If not
+using such features, the driver can be compiled as a module and will be loaded
+as usual.
diff --git a/Documentation/security/tpm/xen-tpmfront.txt b/Documentation/security/tpm/xen-tpmfront.txt
deleted file mode 100644 (file)
index 69346de..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-Virtual TPM interface for Xen
-
-Authors: Matthew Fioravante (JHUAPL), Daniel De Graaf (NSA)
-
-This document describes the virtual Trusted Platform Module (vTPM) subsystem for
-Xen. The reader is assumed to have familiarity with building and installing Xen,
-Linux, and a basic understanding of the TPM and vTPM concepts.
-
-INTRODUCTION
-
-The goal of this work is to provide a TPM functionality to a virtual guest
-operating system (in Xen terms, a DomU).  This allows programs to interact with
-a TPM in a virtual system the same way they interact with a TPM on the physical
-system.  Each guest gets its own unique, emulated, software TPM.  However, each
-of the vTPM's secrets (Keys, NVRAM, etc) are managed by a vTPM Manager domain,
-which seals the secrets to the Physical TPM.  If the process of creating each of
-these domains (manager, vTPM, and guest) is trusted, the vTPM subsystem extends
-the chain of trust rooted in the hardware TPM to virtual machines in Xen. Each
-major component of vTPM is implemented as a separate domain, providing secure
-separation guaranteed by the hypervisor. The vTPM domains are implemented in
-mini-os to reduce memory and processor overhead.
-
-This mini-os vTPM subsystem was built on top of the previous vTPM work done by
-IBM and Intel corporation.
-
-
-DESIGN OVERVIEW
----------------
-
-The architecture of vTPM is described below:
-
-+------------------+
-|    Linux DomU    | ...
-|       |  ^       |
-|       v  |       |
-|   xen-tpmfront   |
-+------------------+
-        |  ^
-        v  |
-+------------------+
-| mini-os/tpmback  |
-|       |  ^       |
-|       v  |       |
-|  vtpm-stubdom    | ...
-|       |  ^       |
-|       v  |       |
-| mini-os/tpmfront |
-+------------------+
-        |  ^
-        v  |
-+------------------+
-| mini-os/tpmback  |
-|       |  ^       |
-|       v  |       |
-| vtpmmgr-stubdom  |
-|       |  ^       |
-|       v  |       |
-| mini-os/tpm_tis  |
-+------------------+
-        |  ^
-        v  |
-+------------------+
-|   Hardware TPM   |
-+------------------+
-
- * Linux DomU: The Linux based guest that wants to use a vTPM. There may be
-              more than one of these.
-
- * xen-tpmfront.ko: Linux kernel virtual TPM frontend driver. This driver
-                    provides vTPM access to a Linux-based DomU.
-
- * mini-os/tpmback: Mini-os TPM backend driver. The Linux frontend driver
-                   connects to this backend driver to facilitate communications
-                   between the Linux DomU and its vTPM. This driver is also
-                   used by vtpmmgr-stubdom to communicate with vtpm-stubdom.
-
- * vtpm-stubdom: A mini-os stub domain that implements a vTPM. There is a
-                one to one mapping between running vtpm-stubdom instances and
-                 logical vtpms on the system. The vTPM Platform Configuration
-                 Registers (PCRs) are normally all initialized to zero.
-
- * mini-os/tpmfront: Mini-os TPM frontend driver. The vTPM mini-os domain
-                    vtpm-stubdom uses this driver to communicate with
-                    vtpmmgr-stubdom. This driver is also used in mini-os
-                    domains such as pv-grub that talk to the vTPM domain.
-
- * vtpmmgr-stubdom: A mini-os domain that implements the vTPM manager. There is
-                   only one vTPM manager and it should be running during the
-                   entire lifetime of the machine.  This domain regulates
-                   access to the physical TPM on the system and secures the
-                   persistent state of each vTPM.
-
- * mini-os/tpm_tis: Mini-os TPM version 1.2 TPM Interface Specification (TIS)
-                    driver. This driver used by vtpmmgr-stubdom to talk directly to
-                    the hardware TPM. Communication is facilitated by mapping
-                    hardware memory pages into vtpmmgr-stubdom.
-
- * Hardware TPM: The physical TPM that is soldered onto the motherboard.
-
-
-INTEGRATION WITH XEN
---------------------
-
-Support for the vTPM driver was added in Xen using the libxl toolstack in Xen
-4.3.  See the Xen documentation (docs/misc/vtpm.txt) for details on setting up
-the vTPM and vTPM Manager stub domains.  Once the stub domains are running, a
-vTPM device is set up in the same manner as a disk or network device in the
-domain's configuration file.
-
-In order to use features such as IMA that require a TPM to be loaded prior to
-the initrd, the xen-tpmfront driver must be compiled in to the kernel.  If not
-using such features, the driver can be compiled as a module and will be loaded
-as usual.
diff --git a/Documentation/serial/driver.rst b/Documentation/serial/driver.rst
deleted file mode 100644 (file)
index 4537119..0000000
+++ /dev/null
@@ -1,549 +0,0 @@
-====================
-Low Level Serial API
-====================
-
-
-This document is meant as a brief overview of some aspects of the new serial
-driver.  It is not complete, any questions you have should be directed to
-<rmk@arm.linux.org.uk>
-
-The reference implementation is contained within amba-pl011.c.
-
-
-
-Low Level Serial Hardware Driver
---------------------------------
-
-The low level serial hardware driver is responsible for supplying port
-information (defined by uart_port) and a set of control methods (defined
-by uart_ops) to the core serial driver.  The low level driver is also
-responsible for handling interrupts for the port, and providing any
-console support.
-
-
-Console Support
----------------
-
-The serial core provides a few helper functions.  This includes identifing
-the correct port structure (via uart_get_console) and decoding command line
-arguments (uart_parse_options).
-
-There is also a helper function (uart_console_write) which performs a
-character by character write, translating newlines to CRLF sequences.
-Driver writers are recommended to use this function rather than implementing
-their own version.
-
-
-Locking
--------
-
-It is the responsibility of the low level hardware driver to perform the
-necessary locking using port->lock.  There are some exceptions (which
-are described in the uart_ops listing below.)
-
-There are two locks.  A per-port spinlock, and an overall semaphore.
-
-From the core driver perspective, the port->lock locks the following
-data::
-
-       port->mctrl
-       port->icount
-       port->state->xmit.head (circ_buf->head)
-       port->state->xmit.tail (circ_buf->tail)
-
-The low level driver is free to use this lock to provide any additional
-locking.
-
-The port_sem semaphore is used to protect against ports being added/
-removed or reconfigured at inappropriate times. Since v2.6.27, this
-semaphore has been the 'mutex' member of the tty_port struct, and
-commonly referred to as the port mutex.
-
-
-uart_ops
---------
-
-The uart_ops structure is the main interface between serial_core and the
-hardware specific driver.  It contains all the methods to control the
-hardware.
-
-  tx_empty(port)
-       This function tests whether the transmitter fifo and shifter
-       for the port described by 'port' is empty.  If it is empty,
-       this function should return TIOCSER_TEMT, otherwise return 0.
-       If the port does not support this operation, then it should
-       return TIOCSER_TEMT.
-
-       Locking: none.
-
-       Interrupts: caller dependent.
-
-       This call must not sleep
-
-  set_mctrl(port, mctrl)
-       This function sets the modem control lines for port described
-       by 'port' to the state described by mctrl.  The relevant bits
-       of mctrl are:
-
-               - TIOCM_RTS     RTS signal.
-               - TIOCM_DTR     DTR signal.
-               - TIOCM_OUT1    OUT1 signal.
-               - TIOCM_OUT2    OUT2 signal.
-               - TIOCM_LOOP    Set the port into loopback mode.
-
-       If the appropriate bit is set, the signal should be driven
-       active.  If the bit is clear, the signal should be driven
-       inactive.
-
-       Locking: port->lock taken.
-
-       Interrupts: locally disabled.
-
-       This call must not sleep
-
-  get_mctrl(port)
-       Returns the current state of modem control inputs.  The state
-       of the outputs should not be returned, since the core keeps
-       track of their state.  The state information should include:
-
-               - TIOCM_CAR     state of DCD signal
-               - TIOCM_CTS     state of CTS signal
-               - TIOCM_DSR     state of DSR signal
-               - TIOCM_RI      state of RI signal
-
-       The bit is set if the signal is currently driven active.  If
-       the port does not support CTS, DCD or DSR, the driver should
-       indicate that the signal is permanently active.  If RI is
-       not available, the signal should not be indicated as active.
-
-       Locking: port->lock taken.
-
-       Interrupts: locally disabled.
-
-       This call must not sleep
-
-  stop_tx(port)
-       Stop transmitting characters.  This might be due to the CTS
-       line becoming inactive or the tty layer indicating we want
-       to stop transmission due to an XOFF character.
-
-       The driver should stop transmitting characters as soon as
-       possible.
-
-       Locking: port->lock taken.
-
-       Interrupts: locally disabled.
-
-       This call must not sleep
-
-  start_tx(port)
-       Start transmitting characters.
-
-       Locking: port->lock taken.
-
-       Interrupts: locally disabled.
-
-       This call must not sleep
-
-  throttle(port)
-       Notify the serial driver that input buffers for the line discipline are
-       close to full, and it should somehow signal that no more characters
-       should be sent to the serial port.
-       This will be called only if hardware assisted flow control is enabled.
-
-       Locking: serialized with .unthrottle() and termios modification by the
-       tty layer.
-
-  unthrottle(port)
-       Notify the serial driver that characters can now be sent to the serial
-       port without fear of overrunning the input buffers of the line
-       disciplines.
-
-       This will be called only if hardware assisted flow control is enabled.
-
-       Locking: serialized with .throttle() and termios modification by the
-       tty layer.
-
-  send_xchar(port,ch)
-       Transmit a high priority character, even if the port is stopped.
-       This is used to implement XON/XOFF flow control and tcflow().  If
-       the serial driver does not implement this function, the tty core
-       will append the character to the circular buffer and then call
-       start_tx() / stop_tx() to flush the data out.
-
-       Do not transmit if ch == '\0' (__DISABLED_CHAR).
-
-       Locking: none.
-
-       Interrupts: caller dependent.
-
-  stop_rx(port)
-       Stop receiving characters; the port is in the process of
-       being closed.
-
-       Locking: port->lock taken.
-
-       Interrupts: locally disabled.
-
-       This call must not sleep
-
-  enable_ms(port)
-       Enable the modem status interrupts.
-
-       This method may be called multiple times.  Modem status
-       interrupts should be disabled when the shutdown method is
-       called.
-
-       Locking: port->lock taken.
-
-       Interrupts: locally disabled.
-
-       This call must not sleep
-
-  break_ctl(port,ctl)
-       Control the transmission of a break signal.  If ctl is
-       nonzero, the break signal should be transmitted.  The signal
-       should be terminated when another call is made with a zero
-       ctl.
-
-       Locking: caller holds tty_port->mutex
-
-  startup(port)
-       Grab any interrupt resources and initialise any low level driver
-       state.  Enable the port for reception.  It should not activate
-       RTS nor DTR; this will be done via a separate call to set_mctrl.
-
-       This method will only be called when the port is initially opened.
-
-       Locking: port_sem taken.
-
-       Interrupts: globally disabled.
-
-  shutdown(port)
-       Disable the port, disable any break condition that may be in
-       effect, and free any interrupt resources.  It should not disable
-       RTS nor DTR; this will have already been done via a separate
-       call to set_mctrl.
-
-       Drivers must not access port->state once this call has completed.
-
-       This method will only be called when there are no more users of
-       this port.
-
-       Locking: port_sem taken.
-
-       Interrupts: caller dependent.
-
-  flush_buffer(port)
-       Flush any write buffers, reset any DMA state and stop any
-       ongoing DMA transfers.
-
-       This will be called whenever the port->state->xmit circular
-       buffer is cleared.
-
-       Locking: port->lock taken.
-
-       Interrupts: locally disabled.
-
-       This call must not sleep
-
-  set_termios(port,termios,oldtermios)
-       Change the port parameters, including word length, parity, stop
-       bits.  Update read_status_mask and ignore_status_mask to indicate
-       the types of events we are interested in receiving.  Relevant
-       termios->c_cflag bits are:
-
-               CSIZE
-                       - word size
-               CSTOPB
-                       - 2 stop bits
-               PARENB
-                       - parity enable
-               PARODD
-                       - odd parity (when PARENB is in force)
-               CREAD
-                       - enable reception of characters (if not set,
-                         still receive characters from the port, but
-                         throw them away.
-               CRTSCTS
-                       - if set, enable CTS status change reporting
-               CLOCAL
-                       - if not set, enable modem status change
-                         reporting.
-
-       Relevant termios->c_iflag bits are:
-
-               INPCK
-                       - enable frame and parity error events to be
-                         passed to the TTY layer.
-               BRKINT / PARMRK
-                       - both of these enable break events to be
-                         passed to the TTY layer.
-
-               IGNPAR
-                       - ignore parity and framing errors
-               IGNBRK
-                       - ignore break errors,  If IGNPAR is also
-                         set, ignore overrun errors as well.
-
-       The interaction of the iflag bits is as follows (parity error
-       given as an example):
-
-       =============== ======= ======  =============================
-       Parity error    INPCK   IGNPAR
-       =============== ======= ======  =============================
-       n/a             0       n/a     character received, marked as
-                                       TTY_NORMAL
-       None            1       n/a     character received, marked as
-                                       TTY_NORMAL
-       Yes             1       0       character received, marked as
-                                       TTY_PARITY
-       Yes             1       1       character discarded
-       =============== ======= ======  =============================
-
-       Other flags may be used (eg, xon/xoff characters) if your
-       hardware supports hardware "soft" flow control.
-
-       Locking: caller holds tty_port->mutex
-
-       Interrupts: caller dependent.
-
-       This call must not sleep
-
-  set_ldisc(port,termios)
-       Notifier for discipline change. See Documentation/serial/tty.rst.
-
-       Locking: caller holds tty_port->mutex
-
-  pm(port,state,oldstate)
-       Perform any power management related activities on the specified
-       port.  State indicates the new state (defined by
-       enum uart_pm_state), oldstate indicates the previous state.
-
-       This function should not be used to grab any resources.
-
-       This will be called when the port is initially opened and finally
-       closed, except when the port is also the system console.  This
-       will occur even if CONFIG_PM is not set.
-
-       Locking: none.
-
-       Interrupts: caller dependent.
-
-  type(port)
-       Return a pointer to a string constant describing the specified
-       port, or return NULL, in which case the string 'unknown' is
-       substituted.
-
-       Locking: none.
-
-       Interrupts: caller dependent.
-
-  release_port(port)
-       Release any memory and IO region resources currently in use by
-       the port.
-
-       Locking: none.
-
-       Interrupts: caller dependent.
-
-  request_port(port)
-       Request any memory and IO region resources required by the port.
-       If any fail, no resources should be registered when this function
-       returns, and it should return -EBUSY on failure.
-
-       Locking: none.
-
-       Interrupts: caller dependent.
-
-  config_port(port,type)
-       Perform any autoconfiguration steps required for the port.  `type`
-       contains a bit mask of the required configuration.  UART_CONFIG_TYPE
-       indicates that the port requires detection and identification.
-       port->type should be set to the type found, or PORT_UNKNOWN if
-       no port was detected.
-
-       UART_CONFIG_IRQ indicates autoconfiguration of the interrupt signal,
-       which should be probed using standard kernel autoprobing techniques.
-       This is not necessary on platforms where ports have interrupts
-       internally hard wired (eg, system on a chip implementations).
-
-       Locking: none.
-
-       Interrupts: caller dependent.
-
-  verify_port(port,serinfo)
-       Verify the new serial port information contained within serinfo is
-       suitable for this port type.
-
-       Locking: none.
-
-       Interrupts: caller dependent.
-
-  ioctl(port,cmd,arg)
-       Perform any port specific IOCTLs.  IOCTL commands must be defined
-       using the standard numbering system found in <asm/ioctl.h>
-
-       Locking: none.
-
-       Interrupts: caller dependent.
-
-  poll_init(port)
-       Called by kgdb to perform the minimal hardware initialization needed
-       to support poll_put_char() and poll_get_char().  Unlike ->startup()
-       this should not request interrupts.
-
-       Locking: tty_mutex and tty_port->mutex taken.
-
-       Interrupts: n/a.
-
-  poll_put_char(port,ch)
-       Called by kgdb to write a single character directly to the serial
-       port.  It can and should block until there is space in the TX FIFO.
-
-       Locking: none.
-
-       Interrupts: caller dependent.
-
-       This call must not sleep
-
-  poll_get_char(port)
-       Called by kgdb to read a single character directly from the serial
-       port.  If data is available, it should be returned; otherwise
-       the function should return NO_POLL_CHAR immediately.
-
-       Locking: none.
-
-       Interrupts: caller dependent.
-
-       This call must not sleep
-
-Other functions
----------------
-
-uart_update_timeout(port,cflag,baud)
-       Update the FIFO drain timeout, port->timeout, according to the
-       number of bits, parity, stop bits and baud rate.
-
-       Locking: caller is expected to take port->lock
-
-       Interrupts: n/a
-
-uart_get_baud_rate(port,termios,old,min,max)
-       Return the numeric baud rate for the specified termios, taking
-       account of the special 38400 baud "kludge".  The B0 baud rate
-       is mapped to 9600 baud.
-
-       If the baud rate is not within min..max, then if old is non-NULL,
-       the original baud rate will be tried.  If that exceeds the
-       min..max constraint, 9600 baud will be returned.  termios will
-       be updated to the baud rate in use.
-
-       Note: min..max must always allow 9600 baud to be selected.
-
-       Locking: caller dependent.
-
-       Interrupts: n/a
-
-uart_get_divisor(port,baud)
-       Return the divisor (baud_base / baud) for the specified baud
-       rate, appropriately rounded.
-
-       If 38400 baud and custom divisor is selected, return the
-       custom divisor instead.
-
-       Locking: caller dependent.
-
-       Interrupts: n/a
-
-uart_match_port(port1,port2)
-       This utility function can be used to determine whether two
-       uart_port structures describe the same port.
-
-       Locking: n/a
-
-       Interrupts: n/a
-
-uart_write_wakeup(port)
-       A driver is expected to call this function when the number of
-       characters in the transmit buffer have dropped below a threshold.
-
-       Locking: port->lock should be held.
-
-       Interrupts: n/a
-
-uart_register_driver(drv)
-       Register a uart driver with the core driver.  We in turn register
-       with the tty layer, and initialise the core driver per-port state.
-
-       drv->port should be NULL, and the per-port structures should be
-       registered using uart_add_one_port after this call has succeeded.
-
-       Locking: none
-
-       Interrupts: enabled
-
-uart_unregister_driver()
-       Remove all references to a driver from the core driver.  The low
-       level driver must have removed all its ports via the
-       uart_remove_one_port() if it registered them with uart_add_one_port().
-
-       Locking: none
-
-       Interrupts: enabled
-
-**uart_suspend_port()**
-
-**uart_resume_port()**
-
-**uart_add_one_port()**
-
-**uart_remove_one_port()**
-
-Other notes
------------
-
-It is intended some day to drop the 'unused' entries from uart_port, and
-allow low level drivers to register their own individual uart_port's with
-the core.  This will allow drivers to use uart_port as a pointer to a
-structure containing both the uart_port entry with their own extensions,
-thus::
-
-       struct my_port {
-               struct uart_port        port;
-               int                     my_stuff;
-       };
-
-Modem control lines via GPIO
-----------------------------
-
-Some helpers are provided in order to set/get modem control lines via GPIO.
-
-mctrl_gpio_init(port, idx):
-       This will get the {cts,rts,...}-gpios from device tree if they are
-       present and request them, set direction etc, and return an
-       allocated structure. `devm_*` functions are used, so there's no need
-       to call mctrl_gpio_free().
-       As this sets up the irq handling make sure to not handle changes to the
-       gpio input lines in your driver, too.
-
-mctrl_gpio_free(dev, gpios):
-       This will free the requested gpios in mctrl_gpio_init().
-       As `devm_*` functions are used, there's generally no need to call
-       this function.
-
-mctrl_gpio_to_gpiod(gpios, gidx)
-       This returns the gpio_desc structure associated to the modem line
-       index.
-
-mctrl_gpio_set(gpios, mctrl):
-       This will sets the gpios according to the mctrl state.
-
-mctrl_gpio_get(gpios, mctrl):
-       This will update mctrl with the gpios values.
-
-mctrl_gpio_enable_ms(gpios):
-       Enables irqs and handling of changes to the ms lines.
-
-mctrl_gpio_disable_ms(gpios):
-       Disables irqs and handling of changes to the ms lines.
diff --git a/Documentation/serial/index.rst b/Documentation/serial/index.rst
deleted file mode 100644 (file)
index d0ba22e..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-:orphan:
-
-==========================
-Support for Serial devices
-==========================
-
-.. toctree::
-    :maxdepth: 1
-
-
-    driver
-    tty
-
-Serial drivers
-==============
-
-.. toctree::
-    :maxdepth: 1
-
-    cyclades_z
-    moxa-smartio
-    n_gsm
-    rocket
-    serial-iso7816
-    serial-rs485
-
-.. only::  subproject and html
-
-   Indices
-   =======
-
-   * :ref:`genindex`
index 91f7d66..71cff62 100644 (file)
@@ -1,5 +1,3 @@
-:orphan:
-
 ==================
 Sparc Architecture
 ==================
diff --git a/Documentation/switchtec.txt b/Documentation/switchtec.txt
deleted file mode 100644 (file)
index 30d6a64..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-========================
-Linux Switchtec Support
-========================
-
-Microsemi's "Switchtec" line of PCI switch devices is already
-supported by the kernel with standard PCI switch drivers. However, the
-Switchtec device advertises a special management endpoint which
-enables some additional functionality. This includes:
-
-* Packet and Byte Counters
-* Firmware Upgrades
-* Event and Error logs
-* Querying port link status
-* Custom user firmware commands
-
-The switchtec kernel module implements this functionality.
-
-
-Interface
-=========
-
-The primary means of communicating with the Switchtec management firmware is
-through the Memory-mapped Remote Procedure Call (MRPC) interface.
-Commands are submitted to the interface with a 4-byte command
-identifier and up to 1KB of command specific data. The firmware will
-respond with a 4-byte return code and up to 1KB of command-specific
-data. The interface only processes a single command at a time.
-
-
-Userspace Interface
-===================
-
-The MRPC interface will be exposed to userspace through a simple char
-device: /dev/switchtec#, one for each management endpoint in the system.
-
-The char device has the following semantics:
-
-* A write must consist of at least 4 bytes and no more than 1028 bytes.
-  The first 4 bytes will be interpreted as the Command ID and the
-  remainder will be used as the input data. A write will send the
-  command to the firmware to begin processing.
-
-* Each write must be followed by exactly one read. Any double write will
-  produce an error and any read that doesn't follow a write will
-  produce an error.
-
-* A read will block until the firmware completes the command and return
-  the 4-byte Command Return Value plus up to 1024 bytes of output
-  data. (The length will be specified by the size parameter of the read
-  call -- reading less than 4 bytes will produce an error.)
-
-* The poll call will also be supported for userspace applications that
-  need to do other things while waiting for the command to complete.
-
-The following IOCTLs are also supported by the device:
-
-* SWITCHTEC_IOCTL_FLASH_INFO - Retrieve firmware length and number
-  of partitions in the device.
-
-* SWITCHTEC_IOCTL_FLASH_PART_INFO - Retrieve address and lengeth for
-  any specified partition in flash.
-
-* SWITCHTEC_IOCTL_EVENT_SUMMARY - Read a structure of bitmaps
-  indicating all uncleared events.
-
-* SWITCHTEC_IOCTL_EVENT_CTL - Get the current count, clear and set flags
-  for any event. This ioctl takes in a switchtec_ioctl_event_ctl struct
-  with the event_id, index and flags set (index being the partition or PFF
-  number for non-global events). It returns whether the event has
-  occurred, the number of times and any event specific data. The flags
-  can be used to clear the count or enable and disable actions to
-  happen when the event occurs.
-  By using the SWITCHTEC_IOCTL_EVENT_FLAG_EN_POLL flag,
-  you can set an event to trigger a poll command to return with
-  POLLPRI. In this way, userspace can wait for events to occur.
-
-* SWITCHTEC_IOCTL_PFF_TO_PORT and SWITCHTEC_IOCTL_PORT_TO_PFF convert
-  between PCI Function Framework number (used by the event system)
-  and Switchtec Logic Port ID and Partition number (which is more
-  user friendly).
-
-
-Non-Transparent Bridge (NTB) Driver
-===================================
-
-An NTB hardware driver is provided for the Switchtec hardware in
-ntb_hw_switchtec. Currently, it only supports switches configured with
-exactly 2 NT partitions and zero or more non-NT partitions. It also requires
-the following configuration settings:
-
-* Both NT partitions must be able to access each other's GAS spaces.
-  Thus, the bits in the GAS Access Vector under Management Settings
-  must be set to support this.
-* Kernel configuration MUST include support for NTB (CONFIG_NTB needs
-  to be set)
-
-NT EP BAR 2 will be dynamically configured as a Direct Window, and
-the configuration file does not need to configure it explicitly.
-
-Please refer to Documentation/ntb.txt in Linux source tree for an overall
-understanding of the Linux NTB stack. ntb_hw_switchtec works as an NTB
-Hardware Driver in this stack.
diff --git a/Documentation/sysctl/README b/Documentation/sysctl/README
deleted file mode 100644 (file)
index d5f24ab..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-Documentation for /proc/sys/           kernel version 2.2.10
-       (c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
-
-'Why', I hear you ask, 'would anyone even _want_ documentation
-for them sysctl files? If anybody really needs it, it's all in
-the source...'
-
-Well, this documentation is written because some people either
-don't know they need to tweak something, or because they don't
-have the time or knowledge to read the source code.
-
-Furthermore, the programmers who built sysctl have built it to
-be actually used, not just for the fun of programming it :-)
-
-==============================================================
-
-Legal blurb:
-
-As usual, there are two main things to consider:
-1. you get what you pay for
-2. it's free
-
-The consequences are that I won't guarantee the correctness of
-this document, and if you come to me complaining about how you
-screwed up your system because of wrong documentation, I won't
-feel sorry for you. I might even laugh at you...
-
-But of course, if you _do_ manage to screw up your system using
-only the sysctl options used in this file, I'd like to hear of
-it. Not only to have a great laugh, but also to make sure that
-you're the last RTFMing person to screw up.
-
-In short, e-mail your suggestions, corrections and / or horror
-stories to: <riel@nl.linux.org>
-
-Rik van Riel.
-
-==============================================================
-
-Introduction:
-
-Sysctl is a means of configuring certain aspects of the kernel
-at run-time, and the /proc/sys/ directory is there so that you
-don't even need special tools to do it!
-In fact, there are only four things needed to use these config
-facilities:
-- a running Linux system
-- root access
-- common sense (this is especially hard to come by these days)
-- knowledge of what all those values mean
-
-As a quick 'ls /proc/sys' will show, the directory consists of
-several (arch-dependent?) subdirs. Each subdir is mainly about
-one part of the kernel, so you can do configuration on a piece
-by piece basis, or just some 'thematic frobbing'.
-
-The subdirs are about:
-abi/           execution domains & personalities
-debug/         <empty>
-dev/           device specific information (eg dev/cdrom/info)
-fs/            specific filesystems
-               filehandle, inode, dentry and quota tuning
-               binfmt_misc <Documentation/admin-guide/binfmt-misc.rst>
-kernel/                global kernel info / tuning
-               miscellaneous stuff
-net/           networking stuff, for documentation look in:
-               <Documentation/networking/>
-proc/          <empty>
-sunrpc/                SUN Remote Procedure Call (NFS)
-vm/            memory management tuning
-               buffer and cache management
-user/          Per user per user namespace limits
-
-These are the subdirs I have on my system. There might be more
-or other subdirs in another setup. If you see another dir, I'd
-really like to hear about it :-)
diff --git a/Documentation/sysctl/abi.txt b/Documentation/sysctl/abi.txt
deleted file mode 100644 (file)
index 63f4ebc..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-Documentation for /proc/sys/abi/* kernel version 2.6.0.test2
-       (c) 2003,  Fabian Frederick <ffrederick@users.sourceforge.net>
-
-For general info : README.
-
-==============================================================
-
-This path is binary emulation relevant aka personality types aka abi.
-When a process is executed, it's linked to an exec_domain whose
-personality is defined using values available from /proc/sys/abi.
-You can find further details about abi in include/linux/personality.h.
-
-Here are the files featuring in 2.6 kernel :
-
-- defhandler_coff
-- defhandler_elf
-- defhandler_lcall7
-- defhandler_libcso
-- fake_utsname
-- trace
-
-===========================================================
-defhandler_coff:
-defined value :
-PER_SCOSVR3
-0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS | SHORT_INODE
-
-===========================================================
-defhandler_elf:
-defined value :
-PER_LINUX
-0
-
-===========================================================
-defhandler_lcall7:
-defined value :
-PER_SVR4
-0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
-
-===========================================================
-defhandler_libsco:
-defined value:
-PER_SVR4
-0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
-
-===========================================================
-fake_utsname:
-Unused
-
-===========================================================
-trace:
-Unused
-
-===========================================================
diff --git a/Documentation/sysctl/fs.txt b/Documentation/sysctl/fs.txt
deleted file mode 100644 (file)
index ebc679b..0000000
+++ /dev/null
@@ -1,374 +0,0 @@
-Documentation for /proc/sys/fs/*       kernel version 2.2.10
-       (c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
-       (c) 2009,        Shen Feng<shen@cn.fujitsu.com>
-
-For general info and legal blurb, please look in README.
-
-==============================================================
-
-This file contains documentation for the sysctl files in
-/proc/sys/fs/ and is valid for Linux kernel version 2.2.
-
-The files in this directory can be used to tune and monitor
-miscellaneous and general things in the operation of the Linux
-kernel. Since some of the files _can_ be used to screw up your
-system, it is advisable to read both documentation and source
-before actually making adjustments.
-
-1. /proc/sys/fs
-----------------------------------------------------------
-
-Currently, these files are in /proc/sys/fs:
-- aio-max-nr
-- aio-nr
-- dentry-state
-- dquot-max
-- dquot-nr
-- file-max
-- file-nr
-- inode-max
-- inode-nr
-- inode-state
-- nr_open
-- overflowuid
-- overflowgid
-- pipe-user-pages-hard
-- pipe-user-pages-soft
-- protected_fifos
-- protected_hardlinks
-- protected_regular
-- protected_symlinks
-- suid_dumpable
-- super-max
-- super-nr
-
-==============================================================
-
-aio-nr & aio-max-nr:
-
-aio-nr is the running total of the number of events specified on the
-io_setup system call for all currently active aio contexts.  If aio-nr
-reaches aio-max-nr then io_setup will fail with EAGAIN.  Note that
-raising aio-max-nr does not result in the pre-allocation or re-sizing
-of any kernel data structures.
-
-==============================================================
-
-dentry-state:
-
-From linux/include/linux/dcache.h:
---------------------------------------------------------------
-struct dentry_stat_t dentry_stat {
-        int nr_dentry;
-        int nr_unused;
-        int age_limit;         /* age in seconds */
-        int want_pages;        /* pages requested by system */
-        int nr_negative;       /* # of unused negative dentries */
-        int dummy;             /* Reserved for future use */
-};
---------------------------------------------------------------
-
-Dentries are dynamically allocated and deallocated.
-
-nr_dentry shows the total number of dentries allocated (active
-+ unused). nr_unused shows the number of dentries that are not
-actively used, but are saved in the LRU list for future reuse.
-
-Age_limit is the age in seconds after which dcache entries
-can be reclaimed when memory is short and want_pages is
-nonzero when shrink_dcache_pages() has been called and the
-dcache isn't pruned yet.
-
-nr_negative shows the number of unused dentries that are also
-negative dentries which do not map to any files. Instead,
-they help speeding up rejection of non-existing files provided
-by the users.
-
-==============================================================
-
-dquot-max & dquot-nr:
-
-The file dquot-max shows the maximum number of cached disk
-quota entries.
-
-The file dquot-nr shows the number of allocated disk quota
-entries and the number of free disk quota entries.
-
-If the number of free cached disk quotas is very low and
-you have some awesome number of simultaneous system users,
-you might want to raise the limit.
-
-==============================================================
-
-file-max & file-nr:
-
-The value in file-max denotes the maximum number of file-
-handles that the Linux kernel will allocate. When you get lots
-of error messages about running out of file handles, you might
-want to increase this limit.
-
-Historically,the kernel was able to allocate file handles
-dynamically, but not to free them again. The three values in
-file-nr denote the number of allocated file handles, the number
-of allocated but unused file handles, and the maximum number of
-file handles. Linux 2.6 always reports 0 as the number of free
-file handles -- this is not an error, it just means that the
-number of allocated file handles exactly matches the number of
-used file handles.
-
-Attempts to allocate more file descriptors than file-max are
-reported with printk, look for "VFS: file-max limit <number>
-reached".
-==============================================================
-
-nr_open:
-
-This denotes the maximum number of file-handles a process can
-allocate. Default value is 1024*1024 (1048576) which should be
-enough for most machines. Actual limit depends on RLIMIT_NOFILE
-resource limit.
-
-==============================================================
-
-inode-max, inode-nr & inode-state:
-
-As with file handles, the kernel allocates the inode structures
-dynamically, but can't free them yet.
-
-The value in inode-max denotes the maximum number of inode
-handlers. This value should be 3-4 times larger than the value
-in file-max, since stdin, stdout and network sockets also
-need an inode struct to handle them. When you regularly run
-out of inodes, you need to increase this value.
-
-The file inode-nr contains the first two items from
-inode-state, so we'll skip to that file...
-
-Inode-state contains three actual numbers and four dummies.
-The actual numbers are, in order of appearance, nr_inodes,
-nr_free_inodes and preshrink.
-
-Nr_inodes stands for the number of inodes the system has
-allocated, this can be slightly more than inode-max because
-Linux allocates them one pageful at a time.
-
-Nr_free_inodes represents the number of free inodes (?) and
-preshrink is nonzero when the nr_inodes > inode-max and the
-system needs to prune the inode list instead of allocating
-more.
-
-==============================================================
-
-overflowgid & overflowuid:
-
-Some filesystems only support 16-bit UIDs and GIDs, although in Linux
-UIDs and GIDs are 32 bits. When one of these filesystems is mounted
-with writes enabled, any UID or GID that would exceed 65535 is translated
-to a fixed value before being written to disk.
-
-These sysctls allow you to change the value of the fixed UID and GID.
-The default is 65534.
-
-==============================================================
-
-pipe-user-pages-hard:
-
-Maximum total number of pages a non-privileged user may allocate for pipes.
-Once this limit is reached, no new pipes may be allocated until usage goes
-below the limit again. When set to 0, no limit is applied, which is the default
-setting.
-
-==============================================================
-
-pipe-user-pages-soft:
-
-Maximum total number of pages a non-privileged user may allocate for pipes
-before the pipe size gets limited to a single page. Once this limit is reached,
-new pipes will be limited to a single page in size for this user in order to
-limit total memory usage, and trying to increase them using fcntl() will be
-denied until usage goes below the limit again. The default value allows to
-allocate up to 1024 pipes at their default size. When set to 0, no limit is
-applied.
-
-==============================================================
-
-protected_fifos:
-
-The intent of this protection is to avoid unintentional writes to
-an attacker-controlled FIFO, where a program expected to create a regular
-file.
-
-When set to "0", writing to FIFOs is unrestricted.
-
-When set to "1" don't allow O_CREAT open on FIFOs that we don't own
-in world writable sticky directories, unless they are owned by the
-owner of the directory.
-
-When set to "2" it also applies to group writable sticky directories.
-
-This protection is based on the restrictions in Openwall.
-
-==============================================================
-
-protected_hardlinks:
-
-A long-standing class of security issues is the hardlink-based
-time-of-check-time-of-use race, most commonly seen in world-writable
-directories like /tmp. The common method of exploitation of this flaw
-is to cross privilege boundaries when following a given hardlink (i.e. a
-root process follows a hardlink created by another user). Additionally,
-on systems without separated partitions, this stops unauthorized users
-from "pinning" vulnerable setuid/setgid files against being upgraded by
-the administrator, or linking to special files.
-
-When set to "0", hardlink creation behavior is unrestricted.
-
-When set to "1" hardlinks cannot be created by users if they do not
-already own the source file, or do not have read/write access to it.
-
-This protection is based on the restrictions in Openwall and grsecurity.
-
-==============================================================
-
-protected_regular:
-
-This protection is similar to protected_fifos, but it
-avoids writes to an attacker-controlled regular file, where a program
-expected to create one.
-
-When set to "0", writing to regular files is unrestricted.
-
-When set to "1" don't allow O_CREAT open on regular files that we
-don't own in world writable sticky directories, unless they are
-owned by the owner of the directory.
-
-When set to "2" it also applies to group writable sticky directories.
-
-==============================================================
-
-protected_symlinks:
-
-A long-standing class of security issues is the symlink-based
-time-of-check-time-of-use race, most commonly seen in world-writable
-directories like /tmp. The common method of exploitation of this flaw
-is to cross privilege boundaries when following a given symlink (i.e. a
-root process follows a symlink belonging to another user). For a likely
-incomplete list of hundreds of examples across the years, please see:
-http://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=/tmp
-
-When set to "0", symlink following behavior is unrestricted.
-
-When set to "1" symlinks are permitted to be followed only when outside
-a sticky world-writable directory, or when the uid of the symlink and
-follower match, or when the directory owner matches the symlink's owner.
-
-This protection is based on the restrictions in Openwall and grsecurity.
-
-==============================================================
-
-suid_dumpable:
-
-This value can be used to query and set the core dump mode for setuid
-or otherwise protected/tainted binaries. The modes are
-
-0 - (default) - traditional behaviour. Any process which has changed
-       privilege levels or is execute only will not be dumped.
-1 - (debug) - all processes dump core when possible. The core dump is
-       owned by the current user and no security is applied. This is
-       intended for system debugging situations only. Ptrace is unchecked.
-       This is insecure as it allows regular users to examine the memory
-       contents of privileged processes.
-2 - (suidsafe) - any binary which normally would not be dumped is dumped
-       anyway, but only if the "core_pattern" kernel sysctl is set to
-       either a pipe handler or a fully qualified path. (For more details
-       on this limitation, see CVE-2006-2451.) This mode is appropriate
-       when administrators are attempting to debug problems in a normal
-       environment, and either have a core dump pipe handler that knows
-       to treat privileged core dumps with care, or specific directory
-       defined for catching core dumps. If a core dump happens without
-       a pipe handler or fully qualifid path, a message will be emitted
-       to syslog warning about the lack of a correct setting.
-
-==============================================================
-
-super-max & super-nr:
-
-These numbers control the maximum number of superblocks, and
-thus the maximum number of mounted filesystems the kernel
-can have. You only need to increase super-max if you need to
-mount more filesystems than the current value in super-max
-allows you to.
-
-==============================================================
-
-aio-nr & aio-max-nr:
-
-aio-nr shows the current system-wide number of asynchronous io
-requests.  aio-max-nr allows you to change the maximum value
-aio-nr can grow to.
-
-==============================================================
-
-mount-max:
-
-This denotes the maximum number of mounts that may exist
-in a mount namespace.
-
-==============================================================
-
-
-2. /proc/sys/fs/binfmt_misc
-----------------------------------------------------------
-
-Documentation for the files in /proc/sys/fs/binfmt_misc is
-in Documentation/admin-guide/binfmt-misc.rst.
-
-
-3. /proc/sys/fs/mqueue - POSIX message queues filesystem
-----------------------------------------------------------
-
-The "mqueue"  filesystem provides  the necessary kernel features to enable the
-creation of a  user space  library that  implements  the  POSIX message queues
-API (as noted by the  MSG tag in the  POSIX 1003.1-2001 version  of the System
-Interfaces specification.)
-
-The "mqueue" filesystem contains values for determining/setting  the amount of
-resources used by the file system.
-
-/proc/sys/fs/mqueue/queues_max is a read/write  file for  setting/getting  the
-maximum number of message queues allowed on the system.
-
-/proc/sys/fs/mqueue/msg_max  is  a  read/write file  for  setting/getting  the
-maximum number of messages in a queue value.  In fact it is the limiting value
-for another (user) limit which is set in mq_open invocation. This attribute of
-a queue must be less or equal then msg_max.
-
-/proc/sys/fs/mqueue/msgsize_max is  a read/write  file for setting/getting the
-maximum  message size value (it is every  message queue's attribute set during
-its creation).
-
-/proc/sys/fs/mqueue/msg_default is  a read/write  file for setting/getting the
-default number of messages in a queue value if attr parameter of mq_open(2) is
-NULL. If it exceed msg_max, the default value is initialized msg_max.
-
-/proc/sys/fs/mqueue/msgsize_default is a read/write file for setting/getting
-the default message size value if attr parameter of mq_open(2) is NULL. If it
-exceed msgsize_max, the default value is initialized msgsize_max.
-
-4. /proc/sys/fs/epoll - Configuration options for the epoll interface
---------------------------------------------------------
-
-This directory contains configuration options for the epoll(7) interface.
-
-max_user_watches
-----------------
-
-Every epoll file descriptor can store a number of files to be monitored
-for event readiness. Each one of these monitored files constitutes a "watch".
-This configuration option sets the maximum number of "watches" that are
-allowed for each user.
-Each "watch" costs roughly 90 bytes on a 32bit kernel, and roughly 160 bytes
-on a 64bit one.
-The current default value for  max_user_watches  is the 1/32 of the available
-low memory, divided for the "watch" cost in bytes.
-
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
deleted file mode 100644 (file)
index 1b2fe17..0000000
+++ /dev/null
@@ -1,1129 +0,0 @@
-Documentation for /proc/sys/kernel/*   kernel version 2.2.10
-       (c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
-       (c) 2009,        Shen Feng<shen@cn.fujitsu.com>
-
-For general info and legal blurb, please look in README.
-
-==============================================================
-
-This file contains documentation for the sysctl files in
-/proc/sys/kernel/ and is valid for Linux kernel version 2.2.
-
-The files in this directory can be used to tune and monitor
-miscellaneous and general things in the operation of the Linux
-kernel. Since some of the files _can_ be used to screw up your
-system, it is advisable to read both documentation and source
-before actually making adjustments.
-
-Currently, these files might (depending on your configuration)
-show up in /proc/sys/kernel:
-
-- acct
-- acpi_video_flags
-- auto_msgmni
-- bootloader_type           [ X86 only ]
-- bootloader_version        [ X86 only ]
-- cap_last_cap
-- core_pattern
-- core_pipe_limit
-- core_uses_pid
-- ctrl-alt-del
-- dmesg_restrict
-- domainname
-- hostname
-- hotplug
-- hardlockup_all_cpu_backtrace
-- hardlockup_panic
-- hung_task_panic
-- hung_task_check_count
-- hung_task_timeout_secs
-- hung_task_check_interval_secs
-- hung_task_warnings
-- hyperv_record_panic_msg
-- kexec_load_disabled
-- kptr_restrict
-- l2cr                        [ PPC only ]
-- modprobe                    ==> Documentation/debugging-modules.txt
-- modules_disabled
-- msg_next_id                [ sysv ipc ]
-- msgmax
-- msgmnb
-- msgmni
-- nmi_watchdog
-- osrelease
-- ostype
-- overflowgid
-- overflowuid
-- panic
-- panic_on_oops
-- panic_on_stackoverflow
-- panic_on_unrecovered_nmi
-- panic_on_warn
-- panic_print
-- panic_on_rcu_stall
-- perf_cpu_time_max_percent
-- perf_event_paranoid
-- perf_event_max_stack
-- perf_event_mlock_kb
-- perf_event_max_contexts_per_stack
-- pid_max
-- powersave-nap               [ PPC only ]
-- printk
-- printk_delay
-- printk_ratelimit
-- printk_ratelimit_burst
-- pty                         ==> Documentation/filesystems/devpts.txt
-- randomize_va_space
-- real-root-dev               ==> Documentation/admin-guide/initrd.rst
-- reboot-cmd                  [ SPARC only ]
-- rtsig-max
-- rtsig-nr
-- sched_energy_aware
-- seccomp/                    ==> Documentation/userspace-api/seccomp_filter.rst
-- sem
-- sem_next_id                [ sysv ipc ]
-- sg-big-buff                 [ generic SCSI device (sg) ]
-- shm_next_id                [ sysv ipc ]
-- shm_rmid_forced
-- shmall
-- shmmax                      [ sysv ipc ]
-- shmmni
-- softlockup_all_cpu_backtrace
-- soft_watchdog
-- stack_erasing
-- stop-a                      [ SPARC only ]
-- sysrq                       ==> Documentation/admin-guide/sysrq.rst
-- sysctl_writes_strict
-- tainted                     ==> Documentation/admin-guide/tainted-kernels.rst
-- threads-max
-- unknown_nmi_panic
-- watchdog
-- watchdog_thresh
-- version
-
-==============================================================
-
-acct:
-
-highwater lowwater frequency
-
-If BSD-style process accounting is enabled these values control
-its behaviour. If free space on filesystem where the log lives
-goes below <lowwater>% accounting suspends. If free space gets
-above <highwater>% accounting resumes. <Frequency> determines
-how often do we check the amount of free space (value is in
-seconds). Default:
-4 2 30
-That is, suspend accounting if there left <= 2% free; resume it
-if we got >=4%; consider information about amount of free space
-valid for 30 seconds.
-
-==============================================================
-
-acpi_video_flags:
-
-flags
-
-See Doc*/kernel/power/video.txt, it allows mode of video boot to be
-set during run time.
-
-==============================================================
-
-auto_msgmni:
-
-This variable has no effect and may be removed in future kernel
-releases. Reading it always returns 0.
-Up to Linux 3.17, it enabled/disabled automatic recomputing of msgmni
-upon memory add/remove or upon ipc namespace creation/removal.
-Echoing "1" into this file enabled msgmni automatic recomputing.
-Echoing "0" turned it off. auto_msgmni default value was 1.
-
-
-==============================================================
-
-bootloader_type:
-
-x86 bootloader identification
-
-This gives the bootloader type number as indicated by the bootloader,
-shifted left by 4, and OR'd with the low four bits of the bootloader
-version.  The reason for this encoding is that this used to match the
-type_of_loader field in the kernel header; the encoding is kept for
-backwards compatibility.  That is, if the full bootloader type number
-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
-Documentation/x86/boot.rst for additional information.
-
-==============================================================
-
-bootloader_version:
-
-x86 bootloader version
-
-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
-Documentation/x86/boot.rst for additional information.
-
-==============================================================
-
-cap_last_cap
-
-Highest valid capability of the running kernel.  Exports
-CAP_LAST_CAP from the kernel.
-
-==============================================================
-
-core_pattern:
-
-core_pattern is used to specify a core dumpfile pattern name.
-. max length 127 characters; default value is "core"
-. core_pattern is used as a pattern template for the output filename;
-  certain string patterns (beginning with '%') are substituted with
-  their actual values.
-. backward compatibility with core_uses_pid:
-       If core_pattern does not include "%p" (default does not)
-       and core_uses_pid is set, then .PID will be appended to
-       the filename.
-. corename format specifiers:
-       %<NUL>  '%' is dropped
-       %%      output one '%'
-       %p      pid
-       %P      global pid (init PID namespace)
-       %i      tid
-       %I      global tid (init PID namespace)
-       %u      uid (in initial user namespace)
-       %g      gid (in initial user namespace)
-       %d      dump mode, matches PR_SET_DUMPABLE and
-               /proc/sys/fs/suid_dumpable
-       %s      signal number
-       %t      UNIX time of dump
-       %h      hostname
-       %e      executable filename (may be shortened)
-       %E      executable path
-       %<OTHER> both are dropped
-. If the first character of the pattern is a '|', the kernel will treat
-  the rest of the pattern as a command to run.  The core dump will be
-  written to the standard input of that program instead of to a file.
-
-==============================================================
-
-core_pipe_limit:
-
-This sysctl is only applicable when core_pattern is configured to pipe
-core files to a user space helper (when the first character of
-core_pattern is a '|', see above).  When collecting cores via a pipe
-to an application, it is occasionally useful for the collecting
-application to gather data about the crashing process from its
-/proc/pid directory.  In order to do this safely, the kernel must wait
-for the collecting process to exit, so as not to remove the crashing
-processes proc files prematurely.  This in turn creates the
-possibility that a misbehaving userspace collecting process can block
-the reaping of a crashed process simply by never exiting.  This sysctl
-defends against that.  It defines how many concurrent crashing
-processes may be piped to user space applications in parallel.  If
-this value is exceeded, then those crashing processes above that value
-are noted via the kernel log and their cores are skipped.  0 is a
-special value, indicating that unlimited processes may be captured in
-parallel, but that no waiting will take place (i.e. the collecting
-process is not guaranteed access to /proc/<crashing pid>/).  This
-value defaults to 0.
-
-==============================================================
-
-core_uses_pid:
-
-The default coredump filename is "core".  By setting
-core_uses_pid to 1, the coredump filename becomes core.PID.
-If core_pattern does not include "%p" (default does not)
-and core_uses_pid is set, then .PID will be appended to
-the filename.
-
-==============================================================
-
-ctrl-alt-del:
-
-When the value in this file is 0, ctrl-alt-del is trapped and
-sent to the init(1) program to handle a graceful restart.
-When, however, the value is > 0, Linux's reaction to a Vulcan
-Nerve Pinch (tm) will be an immediate reboot, without even
-syncing its dirty buffers.
-
-Note: when a program (like dosemu) has the keyboard in 'raw'
-mode, the ctrl-alt-del is intercepted by the program before it
-ever reaches the kernel tty layer, and it's up to the program
-to decide what to do with it.
-
-==============================================================
-
-dmesg_restrict:
-
-This toggle indicates whether unprivileged users are prevented
-from using dmesg(8) to view messages from the kernel's log buffer.
-When dmesg_restrict is set to (0) there are no restrictions. When
-dmesg_restrict is set set to (1), users must have CAP_SYSLOG to use
-dmesg(8).
-
-The kernel config option CONFIG_SECURITY_DMESG_RESTRICT sets the
-default value of dmesg_restrict.
-
-==============================================================
-
-domainname & hostname:
-
-These files can be used to set the NIS/YP domainname and the
-hostname of your box in exactly the same way as the commands
-domainname and hostname, i.e.:
-# echo "darkstar" > /proc/sys/kernel/hostname
-# echo "mydomain" > /proc/sys/kernel/domainname
-has the same effect as
-# hostname "darkstar"
-# domainname "mydomain"
-
-Note, however, that the classic darkstar.frop.org has the
-hostname "darkstar" and DNS (Internet Domain Name Server)
-domainname "frop.org", not to be confused with the NIS (Network
-Information Service) or YP (Yellow Pages) domainname. These two
-domain names are in general different. For a detailed discussion
-see the hostname(1) man page.
-
-==============================================================
-hardlockup_all_cpu_backtrace:
-
-This value controls the hard lockup detector behavior when a hard
-lockup condition is detected as to whether or not to gather further
-debug information. If enabled, arch-specific all-CPU stack dumping
-will be initiated.
-
-0: do nothing. This is the default behavior.
-
-1: on detection capture more debug information.
-==============================================================
-
-hardlockup_panic:
-
-This parameter can be used to control whether the kernel panics
-when a hard lockup is detected.
-
-   0 - don't panic on hard lockup
-   1 - panic on hard lockup
-
-See Documentation/lockup-watchdogs.txt for more information.  This can
-also be set using the nmi_watchdog kernel parameter.
-
-==============================================================
-
-hotplug:
-
-Path for the hotplug policy agent.
-Default value is "/sbin/hotplug".
-
-==============================================================
-
-hung_task_panic:
-
-Controls the kernel's behavior when a hung task is detected.
-This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
-
-0: continue operation. This is the default behavior.
-
-1: panic immediately.
-
-==============================================================
-
-hung_task_check_count:
-
-The upper bound on the number of tasks that are checked.
-This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
-
-==============================================================
-
-hung_task_timeout_secs:
-
-When a task in D state did not get scheduled
-for more than this value report a warning.
-This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
-
-0: means infinite timeout - no checking done.
-Possible values to set are in range {0..LONG_MAX/HZ}.
-
-==============================================================
-
-hung_task_check_interval_secs:
-
-Hung task check interval. If hung task checking is enabled
-(see hung_task_timeout_secs), the check is done every
-hung_task_check_interval_secs seconds.
-This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
-
-0 (default): means use hung_task_timeout_secs as checking interval.
-Possible values to set are in range {0..LONG_MAX/HZ}.
-
-==============================================================
-
-hung_task_warnings:
-
-The maximum number of warnings to report. During a check interval
-if a hung task is detected, this value is decreased by 1.
-When this value reaches 0, no more warnings will be reported.
-This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
-
--1: report an infinite number of warnings.
-
-==============================================================
-
-hyperv_record_panic_msg:
-
-Controls whether the panic kmsg data should be reported to Hyper-V.
-
-0: do not report panic kmsg data.
-
-1: report the panic kmsg data. This is the default behavior.
-
-==============================================================
-
-kexec_load_disabled:
-
-A toggle indicating if the kexec_load syscall has been disabled. This
-value defaults to 0 (false: kexec_load enabled), but can be set to 1
-(true: kexec_load disabled). Once true, kexec can no longer be used, and
-the toggle cannot be set back to false. This allows a kexec image to be
-loaded before disabling the syscall, allowing a system to set up (and
-later use) an image without it being altered. Generally used together
-with the "modules_disabled" sysctl.
-
-==============================================================
-
-kptr_restrict:
-
-This toggle indicates whether restrictions are placed on
-exposing kernel addresses via /proc and other interfaces.
-
-When kptr_restrict is set to 0 (the default) the address is hashed before
-printing. (This is the equivalent to %p.)
-
-When kptr_restrict is set to (1), kernel pointers printed using the %pK
-format specifier will be replaced with 0's unless the user has CAP_SYSLOG
-and effective user and group ids are equal to the real ids. This is
-because %pK checks are done at read() time rather than open() time, so
-if permissions are elevated between the open() and the read() (e.g via
-a setuid binary) then %pK will not leak kernel pointers to unprivileged
-users. Note, this is a temporary solution only. The correct long-term
-solution is to do the permission checks at open() time. Consider removing
-world read permissions from files that use %pK, and using dmesg_restrict
-to protect against uses of %pK in dmesg(8) if leaking kernel pointer
-values to unprivileged users is a concern.
-
-When kptr_restrict is set to (2), kernel pointers printed using
-%pK will be replaced with 0's regardless of privileges.
-
-==============================================================
-
-l2cr: (PPC only)
-
-This flag controls the L2 cache of G3 processor boards. If
-0, the cache is disabled. Enabled if nonzero.
-
-==============================================================
-
-modules_disabled:
-
-A toggle value indicating if modules are allowed to be loaded
-in an otherwise modular kernel.  This toggle defaults to off
-(0), but can be set true (1).  Once true, modules can be
-neither loaded nor unloaded, and the toggle cannot be set back
-to false.  Generally used with the "kexec_load_disabled" toggle.
-
-==============================================================
-
-msg_next_id, sem_next_id, and shm_next_id:
-
-These three toggles allows to specify desired id for next allocated IPC
-object: message, semaphore or shared memory respectively.
-
-By default they are equal to -1, which means generic allocation logic.
-Possible values to set are in range {0..INT_MAX}.
-
-Notes:
-1) kernel doesn't guarantee, that new object will have desired id. So,
-it's up to userspace, how to handle an object with "wrong" id.
-2) Toggle with non-default value will be set back to -1 by kernel after
-successful IPC object allocation. If an IPC object allocation syscall
-fails, it is undefined if the value remains unmodified or is reset to -1.
-
-==============================================================
-
-nmi_watchdog:
-
-This parameter can be used to control the NMI watchdog
-(i.e. the hard lockup detector) on x86 systems.
-
-   0 - disable the hard lockup detector
-   1 - enable the hard lockup detector
-
-The hard lockup detector monitors each CPU for its ability to respond to
-timer interrupts. The mechanism utilizes CPU performance counter registers
-that are programmed to generate Non-Maskable Interrupts (NMIs) periodically
-while a CPU is busy. Hence, the alternative name 'NMI watchdog'.
-
-The NMI watchdog is disabled by default if the kernel is running as a guest
-in a KVM virtual machine. This default can be overridden by adding
-
-   nmi_watchdog=1
-
-to the guest kernel command line (see Documentation/admin-guide/kernel-parameters.rst).
-
-==============================================================
-
-numa_balancing
-
-Enables/disables automatic page fault based NUMA memory
-balancing. Memory is moved automatically to nodes
-that access it often.
-
-Enables/disables automatic NUMA memory balancing. On NUMA machines, there
-is a performance penalty if remote memory is accessed by a CPU. When this
-feature is enabled the kernel samples what task thread is accessing memory
-by periodically unmapping pages and later trapping a page fault. At the
-time of the page fault, it is determined if the data being accessed should
-be migrated to a local memory node.
-
-The unmapping of pages and trapping faults incur additional overhead that
-ideally is offset by improved memory locality but there is no universal
-guarantee. If the target workload is already bound to NUMA nodes then this
-feature should be disabled. Otherwise, if the system overhead from the
-feature is too high then the rate the kernel samples for NUMA hinting
-faults may be controlled by the numa_balancing_scan_period_min_ms,
-numa_balancing_scan_delay_ms, numa_balancing_scan_period_max_ms,
-numa_balancing_scan_size_mb, and numa_balancing_settle_count sysctls.
-
-==============================================================
-
-numa_balancing_scan_period_min_ms, numa_balancing_scan_delay_ms,
-numa_balancing_scan_period_max_ms, numa_balancing_scan_size_mb
-
-Automatic NUMA balancing scans tasks address space and unmaps pages to
-detect if pages are properly placed or if the data should be migrated to a
-memory node local to where the task is running.  Every "scan delay" the task
-scans the next "scan size" number of pages in its address space. When the
-end of the address space is reached the scanner restarts from the beginning.
-
-In combination, the "scan delay" and "scan size" determine the scan rate.
-When "scan delay" decreases, the scan rate increases.  The scan delay and
-hence the scan rate of every task is adaptive and depends on historical
-behaviour. If pages are properly placed then the scan delay increases,
-otherwise the scan delay decreases.  The "scan size" is not adaptive but
-the higher the "scan size", the higher the scan rate.
-
-Higher scan rates incur higher system overhead as page faults must be
-trapped and potentially data must be migrated. However, the higher the scan
-rate, the more quickly a tasks memory is migrated to a local node if the
-workload pattern changes and minimises performance impact due to remote
-memory accesses. These sysctls control the thresholds for scan delays and
-the number of pages scanned.
-
-numa_balancing_scan_period_min_ms is the minimum time in milliseconds to
-scan a tasks virtual memory. It effectively controls the maximum scanning
-rate for each task.
-
-numa_balancing_scan_delay_ms is the starting "scan delay" used for a task
-when it initially forks.
-
-numa_balancing_scan_period_max_ms is the maximum time in milliseconds to
-scan a tasks virtual memory. It effectively controls the minimum scanning
-rate for each task.
-
-numa_balancing_scan_size_mb is how many megabytes worth of pages are
-scanned for a given scan.
-
-==============================================================
-
-osrelease, ostype & version:
-
-# cat osrelease
-2.1.88
-# cat ostype
-Linux
-# cat version
-#5 Wed Feb 25 21:49:24 MET 1998
-
-The files osrelease and ostype should be clear enough. Version
-needs a little more clarification however. The '#5' means that
-this is the fifth kernel built from this source base and the
-date behind it indicates the time the kernel was built.
-The only way to tune these values is to rebuild the kernel :-)
-
-==============================================================
-
-overflowgid & overflowuid:
-
-if your architecture did not always support 32-bit UIDs (i.e. arm,
-i386, m68k, sh, and sparc32), a fixed UID and GID will be returned to
-applications that use the old 16-bit UID/GID system calls, if the
-actual UID or GID would exceed 65535.
-
-These sysctls allow you to change the value of the fixed UID and GID.
-The default is 65534.
-
-==============================================================
-
-panic:
-
-The value in this file represents the number of seconds the kernel
-waits before rebooting on a panic. When you use the software watchdog,
-the recommended setting is 60.
-
-==============================================================
-
-panic_on_io_nmi:
-
-Controls the kernel's behavior when a CPU receives an NMI caused by
-an IO error.
-
-0: try to continue operation (default)
-
-1: panic immediately. The IO error triggered an NMI. This indicates a
-   serious system condition which could result in IO data corruption.
-   Rather than continuing, panicking might be a better choice. Some
-   servers issue this sort of NMI when the dump button is pushed,
-   and you can use this option to take a crash dump.
-
-==============================================================
-
-panic_on_oops:
-
-Controls the kernel's behaviour when an oops or BUG is encountered.
-
-0: try to continue operation
-
-1: panic immediately.  If the `panic' sysctl is also non-zero then the
-   machine will be rebooted.
-
-==============================================================
-
-panic_on_stackoverflow:
-
-Controls the kernel's behavior when detecting the overflows of
-kernel, IRQ and exception stacks except a user stack.
-This file shows up if CONFIG_DEBUG_STACKOVERFLOW is enabled.
-
-0: try to continue operation.
-
-1: panic immediately.
-
-==============================================================
-
-panic_on_unrecovered_nmi:
-
-The default Linux behaviour on an NMI of either memory or unknown is
-to continue operation. For many environments such as scientific
-computing it is preferable that the box is taken out and the error
-dealt with than an uncorrected parity/ECC error get propagated.
-
-A small number of systems do generate NMI's for bizarre random reasons
-such as power management so the default is off. That sysctl works like
-the existing panic controls already in that directory.
-
-==============================================================
-
-panic_on_warn:
-
-Calls panic() in the WARN() path when set to 1.  This is useful to avoid
-a kernel rebuild when attempting to kdump at the location of a WARN().
-
-0: only WARN(), default behaviour.
-
-1: call panic() after printing out WARN() location.
-
-==============================================================
-
-panic_print:
-
-Bitmask for printing system info when panic happens. User can chose
-combination of the following bits:
-
-bit 0: print all tasks info
-bit 1: print system memory info
-bit 2: print timer info
-bit 3: print locks info if CONFIG_LOCKDEP is on
-bit 4: print ftrace buffer
-
-So for example to print tasks and memory info on panic, user can:
-  echo 3 > /proc/sys/kernel/panic_print
-
-==============================================================
-
-panic_on_rcu_stall:
-
-When set to 1, calls panic() after RCU stall detection messages. This
-is useful to define the root cause of RCU stalls using a vmcore.
-
-0: do not panic() when RCU stall takes place, default behavior.
-
-1: panic() after printing RCU stall messages.
-
-==============================================================
-
-perf_cpu_time_max_percent:
-
-Hints to the kernel how much CPU time it should be allowed to
-use to handle perf sampling events.  If the perf subsystem
-is informed that its samples are exceeding this limit, it
-will drop its sampling frequency to attempt to reduce its CPU
-usage.
-
-Some perf sampling happens in NMIs.  If these samples
-unexpectedly take too long to execute, the NMIs can become
-stacked up next to each other so much that nothing else is
-allowed to execute.
-
-0: disable the mechanism.  Do not monitor or correct perf's
-   sampling rate no matter how CPU time it takes.
-
-1-100: attempt to throttle perf's sample rate to this
-   percentage of CPU.  Note: the kernel calculates an
-   "expected" length of each sample event.  100 here means
-   100% of that expected length.  Even if this is set to
-   100, you may still see sample throttling if this
-   length is exceeded.  Set to 0 if you truly do not care
-   how much CPU is consumed.
-
-==============================================================
-
-perf_event_paranoid:
-
-Controls use of the performance events system by unprivileged
-users (without CAP_SYS_ADMIN).  The default value is 2.
-
- -1: Allow use of (almost) all events by all users
-     Ignore mlock limit after perf_event_mlock_kb without CAP_IPC_LOCK
->=0: Disallow ftrace function tracepoint by users without CAP_SYS_ADMIN
-     Disallow raw tracepoint access by users without CAP_SYS_ADMIN
->=1: Disallow CPU event access by users without CAP_SYS_ADMIN
->=2: Disallow kernel profiling by users without CAP_SYS_ADMIN
-
-==============================================================
-
-perf_event_max_stack:
-
-Controls maximum number of stack frames to copy for (attr.sample_type &
-PERF_SAMPLE_CALLCHAIN) configured events, for instance, when using
-'perf record -g' or 'perf trace --call-graph fp'.
-
-This can only be done when no events are in use that have callchains
-enabled, otherwise writing to this file will return -EBUSY.
-
-The default value is 127.
-
-==============================================================
-
-perf_event_mlock_kb:
-
-Control size of per-cpu ring buffer not counted agains mlock limit.
-
-The default value is 512 + 1 page
-
-==============================================================
-
-perf_event_max_contexts_per_stack:
-
-Controls maximum number of stack frame context entries for
-(attr.sample_type & PERF_SAMPLE_CALLCHAIN) configured events, for
-instance, when using 'perf record -g' or 'perf trace --call-graph fp'.
-
-This can only be done when no events are in use that have callchains
-enabled, otherwise writing to this file will return -EBUSY.
-
-The default value is 8.
-
-==============================================================
-
-pid_max:
-
-PID allocation wrap value.  When the kernel's next PID value
-reaches this value, it wraps back to a minimum PID value.
-PIDs of value pid_max or larger are not allocated.
-
-==============================================================
-
-ns_last_pid:
-
-The last pid allocated in the current (the one task using this sysctl
-lives in) pid namespace. When selecting a pid for a next task on fork
-kernel tries to allocate a number starting from this one.
-
-==============================================================
-
-powersave-nap: (PPC only)
-
-If set, Linux-PPC will use the 'nap' mode of powersaving,
-otherwise the 'doze' mode will be used.
-
-==============================================================
-
-printk:
-
-The four values in printk denote: console_loglevel,
-default_message_loglevel, minimum_console_loglevel and
-default_console_loglevel respectively.
-
-These values influence printk() behavior when printing or
-logging error messages. See 'man 2 syslog' for more info on
-the different loglevels.
-
-- console_loglevel: messages with a higher priority than
-  this will be printed to the console
-- default_message_loglevel: messages without an explicit priority
-  will be printed with this priority
-- minimum_console_loglevel: minimum (highest) value to which
-  console_loglevel can be set
-- default_console_loglevel: default value for console_loglevel
-
-==============================================================
-
-printk_delay:
-
-Delay each printk message in printk_delay milliseconds
-
-Value from 0 - 10000 is allowed.
-
-==============================================================
-
-printk_ratelimit:
-
-Some warning messages are rate limited. printk_ratelimit specifies
-the minimum length of time between these messages (in jiffies), by
-default we allow one every 5 seconds.
-
-A value of 0 will disable rate limiting.
-
-==============================================================
-
-printk_ratelimit_burst:
-
-While long term we enforce one message per printk_ratelimit
-seconds, we do allow a burst of messages to pass through.
-printk_ratelimit_burst specifies the number of messages we can
-send before ratelimiting kicks in.
-
-==============================================================
-
-printk_devkmsg:
-
-Control the logging to /dev/kmsg from userspace:
-
-ratelimit: default, ratelimited
-on: unlimited logging to /dev/kmsg from userspace
-off: logging to /dev/kmsg disabled
-
-The kernel command line parameter printk.devkmsg= overrides this and is
-a one-time setting until next reboot: once set, it cannot be changed by
-this sysctl interface anymore.
-
-==============================================================
-
-randomize_va_space:
-
-This option can be used to select the type of process address
-space randomization that is used in the system, for architectures
-that support this feature.
-
-0 - Turn the process address space randomization off.  This is the
-    default for architectures that do not support this feature anyways,
-    and kernels that are booted with the "norandmaps" parameter.
-
-1 - Make the addresses of mmap base, stack and VDSO page randomized.
-    This, among other things, implies that shared libraries will be
-    loaded to random addresses.  Also for PIE-linked binaries, the
-    location of code start is randomized.  This is the default if the
-    CONFIG_COMPAT_BRK option is enabled.
-
-2 - Additionally enable heap randomization.  This is the default if
-    CONFIG_COMPAT_BRK is disabled.
-
-    There are a few legacy applications out there (such as some ancient
-    versions of libc.so.5 from 1996) that assume that brk area starts
-    just after the end of the code+bss.  These applications break when
-    start of the brk area is randomized.  There are however no known
-    non-legacy applications that would be broken this way, so for most
-    systems it is safe to choose full randomization.
-
-    Systems with ancient and/or broken binaries should be configured
-    with CONFIG_COMPAT_BRK enabled, which excludes the heap from process
-    address space randomization.
-
-==============================================================
-
-reboot-cmd: (Sparc only)
-
-??? This seems to be a way to give an argument to the Sparc
-ROM/Flash boot loader. Maybe to tell it what to do after
-rebooting. ???
-
-==============================================================
-
-rtsig-max & rtsig-nr:
-
-The file rtsig-max can be used to tune the maximum number
-of POSIX realtime (queued) signals that can be outstanding
-in the system.
-
-rtsig-nr shows the number of RT signals currently queued.
-
-==============================================================
-
-sched_energy_aware:
-
-Enables/disables Energy Aware Scheduling (EAS). EAS starts
-automatically on platforms where it can run (that is,
-platforms with asymmetric CPU topologies and having an Energy
-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.
-
-==============================================================
-
-sched_schedstats:
-
-Enables/disables scheduler statistics. Enabling this feature
-incurs a small amount of overhead in the scheduler but is
-useful for debugging and performance tuning.
-
-==============================================================
-
-sg-big-buff:
-
-This file shows the size of the generic SCSI (sg) buffer.
-You can't tune it just yet, but you could change it on
-compile time by editing include/scsi/sg.h and changing
-the value of SG_BIG_BUFF.
-
-There shouldn't be any reason to change this value. If
-you can come up with one, you probably know what you
-are doing anyway :)
-
-==============================================================
-
-shmall:
-
-This parameter sets the total amount of shared memory pages that
-can be used system wide. Hence, SHMALL should always be at least
-ceil(shmmax/PAGE_SIZE).
-
-If you are not sure what the default PAGE_SIZE is on your Linux
-system, you can run the following command:
-
-# getconf PAGE_SIZE
-
-==============================================================
-
-shmmax:
-
-This value can be used to query and set the run time limit
-on the maximum shared memory segment size that can be created.
-Shared memory segments up to 1Gb are now supported in the
-kernel.  This value defaults to SHMMAX.
-
-==============================================================
-
-shm_rmid_forced:
-
-Linux lets you set resource limits, including how much memory one
-process can consume, via setrlimit(2).  Unfortunately, shared memory
-segments are allowed to exist without association with any process, and
-thus might not be counted against any resource limits.  If enabled,
-shared memory segments are automatically destroyed when their attach
-count becomes zero after a detach or a process termination.  It will
-also destroy segments that were created, but never attached to, on exit
-from the process.  The only use left for IPC_RMID is to immediately
-destroy an unattached segment.  Of course, this breaks the way things are
-defined, so some applications might stop working.  Note that this
-feature will do you no good unless you also configure your resource
-limits (in particular, RLIMIT_AS and RLIMIT_NPROC).  Most systems don't
-need this.
-
-Note that if you change this from 0 to 1, already created segments
-without users and with a dead originative process will be destroyed.
-
-==============================================================
-
-sysctl_writes_strict:
-
-Control how file position affects the behavior of updating sysctl values
-via the /proc/sys interface:
-
-  -1 - Legacy per-write sysctl value handling, with no printk warnings.
-       Each write syscall must fully contain the sysctl value to be
-       written, and multiple writes on the same sysctl file descriptor
-       will rewrite the sysctl value, regardless of file position.
-   0 - Same behavior as above, but warn about processes that perform writes
-       to a sysctl file descriptor when the file position is not 0.
-   1 - (default) Respect file position when writing sysctl strings. Multiple
-       writes will append to the sysctl value buffer. Anything past the max
-       length of the sysctl value buffer will be ignored. Writes to numeric
-       sysctl entries must always be at file position 0 and the value must
-       be fully contained in the buffer sent in the write syscall.
-
-==============================================================
-
-softlockup_all_cpu_backtrace:
-
-This value controls the soft lockup detector thread's behavior
-when a soft lockup condition is detected as to whether or not
-to gather further debug information. If enabled, each cpu will
-be issued an NMI and instructed to capture stack trace.
-
-This feature is only applicable for architectures which support
-NMI.
-
-0: do nothing. This is the default behavior.
-
-1: on detection capture more debug information.
-
-==============================================================
-
-soft_watchdog
-
-This parameter can be used to control the soft lockup detector.
-
-   0 - disable the soft lockup detector
-   1 - enable the soft lockup detector
-
-The soft lockup detector monitors CPUs for threads that are hogging the CPUs
-without rescheduling voluntarily, and thus prevent the 'watchdog/N' threads
-from running. The mechanism depends on the CPUs ability to respond to timer
-interrupts which are needed for the 'watchdog/N' threads to be woken up by
-the watchdog timer function, otherwise the NMI watchdog - if enabled - can
-detect a hard lockup condition.
-
-==============================================================
-
-stack_erasing
-
-This parameter can be used to control kernel stack erasing at the end
-of syscalls for kernels built with CONFIG_GCC_PLUGIN_STACKLEAK.
-
-That erasing reduces the information which kernel stack leak bugs
-can reveal and blocks some uninitialized stack variable attacks.
-The tradeoff is the performance impact: on a single CPU system kernel
-compilation sees a 1% slowdown, other systems and workloads may vary.
-
-  0: kernel stack erasing is disabled, STACKLEAK_METRICS are not updated.
-
-  1: kernel stack erasing is enabled (default), it is performed before
-     returning to the userspace at the end of syscalls.
-==============================================================
-
-tainted
-
-Non-zero if the kernel has been tainted. Numeric values, which can be
-ORed together. The letters are seen in "Tainted" line of Oops reports.
-
-     1 (P): proprietary module was loaded
-     2 (F): module was force loaded
-     4 (S): SMP kernel oops on an officially SMP incapable processor
-     8 (R): module was force unloaded
-    16 (M): processor reported a Machine Check Exception (MCE)
-    32 (B): bad page referenced or some unexpected page flags
-    64 (U): taint requested by userspace application
-   128 (D): kernel died recently, i.e. there was an OOPS or BUG
-   256 (A): an ACPI table was overridden by user
-   512 (W): kernel issued warning
-  1024 (C): staging driver was loaded
-  2048 (I): workaround for bug in platform firmware applied
-  4096 (O): externally-built ("out-of-tree") module was loaded
-  8192 (E): unsigned module was loaded
- 16384 (L): soft lockup occurred
- 32768 (K): kernel has been live patched
- 65536 (X): Auxiliary taint, defined and used by for distros
-131072 (T): The kernel was built with the struct randomization plugin
-
-See Documentation/admin-guide/tainted-kernels.rst for more information.
-
-==============================================================
-
-threads-max
-
-This value controls the maximum number of threads that can be created
-using fork().
-
-During initialization the kernel sets this value such that even if the
-maximum number of threads is created, the thread structures occupy only
-a part (1/8th) of the available RAM pages.
-
-The minimum value that can be written to threads-max is 20.
-The maximum value that can be written to threads-max is given by the
-constant FUTEX_TID_MASK (0x3fffffff).
-If a value outside of this range is written to threads-max an error
-EINVAL occurs.
-
-The value written is checked against the available RAM pages. If the
-thread structures would occupy too much (more than 1/8th) of the
-available RAM pages threads-max is reduced accordingly.
-
-==============================================================
-
-unknown_nmi_panic:
-
-The value in this file affects behavior of handling NMI. When the
-value is non-zero, unknown NMI is trapped and then panic occurs. At
-that time, kernel debugging information is displayed on console.
-
-NMI switch that most IA32 servers have fires unknown NMI up, for
-example.  If a system hangs up, try pressing the NMI switch.
-
-==============================================================
-
-watchdog:
-
-This parameter can be used to disable or enable the soft lockup detector
-_and_ the NMI watchdog (i.e. the hard lockup detector) at the same time.
-
-   0 - disable both lockup detectors
-   1 - enable both lockup detectors
-
-The soft lockup detector and the NMI watchdog can also be disabled or
-enabled individually, using the soft_watchdog and nmi_watchdog parameters.
-If the watchdog parameter is read, for example by executing
-
-   cat /proc/sys/kernel/watchdog
-
-the output of this command (0 or 1) shows the logical OR of soft_watchdog
-and nmi_watchdog.
-
-==============================================================
-
-watchdog_cpumask:
-
-This value can be used to control on which cpus the watchdog may run.
-The default cpumask is all possible cores, but if NO_HZ_FULL is
-enabled in the kernel config, and cores are specified with the
-nohz_full= boot argument, those cores are excluded by default.
-Offline cores can be included in this mask, and if the core is later
-brought online, the watchdog will be started based on the mask value.
-
-Typically this value would only be touched in the nohz_full case
-to re-enable cores that by default were not running the watchdog,
-if a kernel lockup was suspected on those cores.
-
-The argument value is the standard cpulist format for cpumasks,
-so for example to enable the watchdog on cores 0, 2, 3, and 4 you
-might say:
-
-  echo 0,2-4 > /proc/sys/kernel/watchdog_cpumask
-
-==============================================================
-
-watchdog_thresh:
-
-This value can be used to control the frequency of hrtimer and NMI
-events and the soft and hard lockup thresholds. The default threshold
-is 10 seconds.
-
-The softlockup threshold is (2 * watchdog_thresh). Setting this
-tunable to zero will disable lockup detection altogether.
-
-==============================================================
diff --git a/Documentation/sysctl/net.txt b/Documentation/sysctl/net.txt
deleted file mode 100644 (file)
index 2ae91d3..0000000
+++ /dev/null
@@ -1,422 +0,0 @@
-Documentation for /proc/sys/net/*
-       (c) 1999                Terrehon Bowden <terrehon@pacbell.net>
-                               Bodo Bauer <bb@ricochet.net>
-       (c) 2000                Jorge Nerin <comandante@zaralinux.com>
-       (c) 2009                Shen Feng <shen@cn.fujitsu.com>
-
-For general info and legal blurb, please look in README.
-
-==============================================================
-
-This file contains the documentation for the sysctl files in
-/proc/sys/net
-
-The interface  to  the  networking  parts  of  the  kernel  is  located  in
-/proc/sys/net. The following table shows all possible subdirectories.  You may
-see only some of them, depending on your kernel's configuration.
-
-
-Table : Subdirectories in /proc/sys/net
-..............................................................................
- Directory Content             Directory  Content
- core      General parameter   appletalk  Appletalk protocol
- unix      Unix domain sockets netrom     NET/ROM
- 802       E802 protocol       ax25       AX25
- ethernet  Ethernet protocol   rose       X.25 PLP layer
- ipv4      IP version 4        x25        X.25 protocol
- ipx       IPX                 token-ring IBM token ring
- bridge    Bridging            decnet     DEC net
- ipv6      IP version 6        tipc       TIPC
-..............................................................................
-
-1. /proc/sys/net/core - Network core options
--------------------------------------------------------
-
-bpf_jit_enable
---------------
-
-This enables the BPF Just in Time (JIT) compiler. BPF is a flexible
-and efficient infrastructure allowing to execute bytecode at various
-hook points. It is used in a number of Linux kernel subsystems such
-as networking (e.g. XDP, tc), tracing (e.g. kprobes, uprobes, tracepoints)
-and security (e.g. seccomp). LLVM has a BPF back end that can compile
-restricted C into a sequence of BPF instructions. After program load
-through bpf(2) and passing a verifier in the kernel, a JIT will then
-translate these BPF proglets into native CPU instructions. There are
-two flavors of JITs, the newer eBPF JIT currently supported on:
-  - x86_64
-  - x86_32
-  - arm64
-  - arm32
-  - ppc64
-  - sparc64
-  - mips64
-  - s390x
-  - riscv
-
-And the older cBPF JIT supported on the following archs:
-  - mips
-  - ppc
-  - sparc
-
-eBPF JITs are a superset of cBPF JITs, meaning the kernel will
-migrate cBPF instructions into eBPF instructions and then JIT
-compile them transparently. Older cBPF JITs can only translate
-tcpdump filters, seccomp rules, etc, but not mentioned eBPF
-programs loaded through bpf(2).
-
-Values :
-       0 - disable the JIT (default value)
-       1 - enable the JIT
-       2 - enable the JIT and ask the compiler to emit traces on kernel log.
-
-bpf_jit_harden
---------------
-
-This enables hardening for the BPF JIT compiler. Supported are eBPF
-JIT backends. Enabling hardening trades off performance, but can
-mitigate JIT spraying.
-Values :
-       0 - disable JIT hardening (default value)
-       1 - enable JIT hardening for unprivileged users only
-       2 - enable JIT hardening for all users
-
-bpf_jit_kallsyms
-----------------
-
-When BPF JIT compiler is enabled, then compiled images are unknown
-addresses to the kernel, meaning they neither show up in traces nor
-in /proc/kallsyms. This enables export of these addresses, which can
-be used for debugging/tracing. If bpf_jit_harden is enabled, this
-feature is disabled.
-Values :
-       0 - disable JIT kallsyms export (default value)
-       1 - enable JIT kallsyms export for privileged users only
-
-bpf_jit_limit
--------------
-
-This enforces a global limit for memory allocations to the BPF JIT
-compiler in order to reject unprivileged JIT requests once it has
-been surpassed. bpf_jit_limit contains the value of the global limit
-in bytes.
-
-dev_weight
---------------
-
-The maximum number of packets that kernel can handle on a NAPI interrupt,
-it's a Per-CPU variable. For drivers that support LRO or GRO_HW, a hardware
-aggregated packet is counted as one packet in this context.
-
-Default: 64
-
-dev_weight_rx_bias
---------------
-
-RPS (e.g. RFS, aRFS) processing is competing with the registered NAPI poll function
-of the driver for the per softirq cycle netdev_budget. This parameter influences
-the proportion of the configured netdev_budget that is spent on RPS based packet
-processing during RX softirq cycles. It is further meant for making current
-dev_weight adaptable for asymmetric CPU needs on RX/TX side of the network stack.
-(see dev_weight_tx_bias) It is effective on a per CPU basis. Determination is based
-on dev_weight and is calculated multiplicative (dev_weight * dev_weight_rx_bias).
-Default: 1
-
-dev_weight_tx_bias
---------------
-
-Scales the maximum number of packets that can be processed during a TX softirq cycle.
-Effective on a per CPU basis. Allows scaling of current dev_weight for asymmetric
-net stack processing needs. Be careful to avoid making TX softirq processing a CPU hog.
-Calculation is based on dev_weight (dev_weight * dev_weight_tx_bias).
-Default: 1
-
-default_qdisc
---------------
-
-The default queuing discipline to use for network devices. This allows
-overriding the default of pfifo_fast with an alternative. Since the default
-queuing discipline is created without additional parameters so is best suited
-to queuing disciplines that work well without configuration like stochastic
-fair queue (sfq), CoDel (codel) or fair queue CoDel (fq_codel). Don't use
-queuing disciplines like Hierarchical Token Bucket or Deficit Round Robin
-which require setting up classes and bandwidths. Note that physical multiqueue
-interfaces still use mq as root qdisc, which in turn uses this default for its
-leaves. Virtual devices (like e.g. lo or veth) ignore this setting and instead
-default to noqueue.
-Default: pfifo_fast
-
-busy_read
-----------------
-Low latency busy poll timeout for socket reads. (needs CONFIG_NET_RX_BUSY_POLL)
-Approximate time in us to busy loop waiting for packets on the device queue.
-This sets the default value of the SO_BUSY_POLL socket option.
-Can be set or overridden per socket by setting socket option SO_BUSY_POLL,
-which is the preferred method of enabling. If you need to enable the feature
-globally via sysctl, a value of 50 is recommended.
-Will increase power usage.
-Default: 0 (off)
-
-busy_poll
-----------------
-Low latency busy poll timeout for poll and select. (needs CONFIG_NET_RX_BUSY_POLL)
-Approximate time in us to busy loop waiting for events.
-Recommended value depends on the number of sockets you poll on.
-For several sockets 50, for several hundreds 100.
-For more than that you probably want to use epoll.
-Note that only sockets with SO_BUSY_POLL set will be busy polled,
-so you want to either selectively set SO_BUSY_POLL on those sockets or set
-sysctl.net.busy_read globally.
-Will increase power usage.
-Default: 0 (off)
-
-rmem_default
-------------
-
-The default setting of the socket receive buffer in bytes.
-
-rmem_max
---------
-
-The maximum receive socket buffer size in bytes.
-
-tstamp_allow_data
------------------
-Allow processes to receive tx timestamps looped together with the original
-packet contents. If disabled, transmit timestamp requests from unprivileged
-processes are dropped unless socket option SOF_TIMESTAMPING_OPT_TSONLY is set.
-Default: 1 (on)
-
-
-wmem_default
-------------
-
-The default setting (in bytes) of the socket send buffer.
-
-wmem_max
---------
-
-The maximum send socket buffer size in bytes.
-
-message_burst and message_cost
-------------------------------
-
-These parameters  are used to limit the warning messages written to the kernel
-log from  the  networking  code.  They  enforce  a  rate  limit  to  make  a
-denial-of-service attack  impossible. A higher message_cost factor, results in
-fewer messages that will be written. Message_burst controls when messages will
-be dropped.  The  default  settings  limit  warning messages to one every five
-seconds.
-
-warnings
---------
-
-This sysctl is now unused.
-
-This was used to control console messages from the networking stack that
-occur because of problems on the network like duplicate address or bad
-checksums.
-
-These messages are now emitted at KERN_DEBUG and can generally be enabled
-and controlled by the dynamic_debug facility.
-
-netdev_budget
--------------
-
-Maximum number of packets taken from all interfaces in one polling cycle (NAPI
-poll). In one polling cycle interfaces which are registered to polling are
-probed in a round-robin manner. Also, a polling cycle may not exceed
-netdev_budget_usecs microseconds, even if netdev_budget has not been
-exhausted.
-
-netdev_budget_usecs
----------------------
-
-Maximum number of microseconds in one NAPI polling cycle. Polling
-will exit when either netdev_budget_usecs have elapsed during the
-poll cycle or the number of packets processed reaches netdev_budget.
-
-netdev_max_backlog
-------------------
-
-Maximum number  of  packets,  queued  on  the  INPUT  side, when the interface
-receives packets faster than kernel can process them.
-
-netdev_rss_key
---------------
-
-RSS (Receive Side Scaling) enabled drivers use a 40 bytes host key that is
-randomly generated.
-Some user space might need to gather its content even if drivers do not
-provide ethtool -x support yet.
-
-myhost:~# cat /proc/sys/net/core/netdev_rss_key
-84:50:f4:00:a8:15:d1:a7:e9:7f:1d:60:35:c7:47:25:42:97:74:ca:56:bb:b6:a1:d8: ... (52 bytes total)
-
-File contains nul bytes if no driver ever called netdev_rss_key_fill() function.
-Note:
-/proc/sys/net/core/netdev_rss_key contains 52 bytes of key,
-but most drivers only use 40 bytes of it.
-
-myhost:~# ethtool -x eth0
-RX flow hash indirection table for eth0 with 8 RX ring(s):
-    0:    0     1     2     3     4     5     6     7
-RSS hash key:
-84:50:f4:00:a8:15:d1:a7:e9:7f:1d:60:35:c7:47:25:42:97:74:ca:56:bb:b6:a1:d8:43:e3:c9:0c:fd:17:55:c2:3a:4d:69:ed:f1:42:89
-
-netdev_tstamp_prequeue
-----------------------
-
-If set to 0, RX packet timestamps can be sampled after RPS processing, when
-the target CPU processes packets. It might give some delay on timestamps, but
-permit to distribute the load on several cpus.
-
-If set to 1 (default), timestamps are sampled as soon as possible, before
-queueing.
-
-optmem_max
-----------
-
-Maximum ancillary buffer size allowed per socket. Ancillary data is a sequence
-of struct cmsghdr structures with appended data.
-
-fb_tunnels_only_for_init_net
-----------------------------
-
-Controls if fallback tunnels (like tunl0, gre0, gretap0, erspan0,
-sit0, ip6tnl0, ip6gre0) are automatically created when a new
-network namespace is created, if corresponding tunnel is present
-in initial network namespace.
-If set to 1, these devices are not automatically created, and
-user space is responsible for creating them if needed.
-
-Default : 0  (for compatibility reasons)
-
-devconf_inherit_init_net
-----------------------------
-
-Controls if a new network namespace should inherit all current
-settings under /proc/sys/net/{ipv4,ipv6}/conf/{all,default}/. By
-default, we keep the current behavior: for IPv4 we inherit all current
-settings from init_net and for IPv6 we reset all settings to default.
-
-If set to 1, both IPv4 and IPv6 settings are forced to inherit from
-current ones in init_net. If set to 2, both IPv4 and IPv6 settings are
-forced to reset to their default values.
-
-Default : 0  (for compatibility reasons)
-
-2. /proc/sys/net/unix - Parameters for Unix domain sockets
--------------------------------------------------------
-
-There is only one file in this directory.
-unix_dgram_qlen limits the max number of datagrams queued in Unix domain
-socket's buffer. It will not take effect unless PF_UNIX flag is specified.
-
-
-3. /proc/sys/net/ipv4 - IPV4 settings
--------------------------------------------------------
-Please see: Documentation/networking/ip-sysctl.txt and ipvs-sysctl.txt for
-descriptions of these entries.
-
-
-4. Appletalk
--------------------------------------------------------
-
-The /proc/sys/net/appletalk  directory  holds the Appletalk configuration data
-when Appletalk is loaded. The configurable parameters are:
-
-aarp-expiry-time
-----------------
-
-The amount  of  time  we keep an ARP entry before expiring it. Used to age out
-old hosts.
-
-aarp-resolve-time
------------------
-
-The amount of time we will spend trying to resolve an Appletalk address.
-
-aarp-retransmit-limit
----------------------
-
-The number of times we will retransmit a query before giving up.
-
-aarp-tick-time
---------------
-
-Controls the rate at which expires are checked.
-
-The directory  /proc/net/appletalk  holds the list of active Appletalk sockets
-on a machine.
-
-The fields  indicate  the DDP type, the local address (in network:node format)
-the remote  address,  the  size of the transmit pending queue, the size of the
-received queue  (bytes waiting for applications to read) the state and the uid
-owning the socket.
-
-/proc/net/atalk_iface lists  all  the  interfaces  configured for appletalk.It
-shows the  name  of the interface, its Appletalk address, the network range on
-that address  (or  network number for phase 1 networks), and the status of the
-interface.
-
-/proc/net/atalk_route lists  each  known  network  route.  It lists the target
-(network) that the route leads to, the router (may be directly connected), the
-route flags, and the device the route is using.
-
-
-5. IPX
--------------------------------------------------------
-
-The IPX protocol has no tunable values in proc/sys/net.
-
-The IPX  protocol  does,  however,  provide  proc/net/ipx. This lists each IPX
-socket giving  the  local  and  remote  addresses  in  Novell  format (that is
-network:node:port). In  accordance  with  the  strange  Novell  tradition,
-everything but the port is in hex. Not_Connected is displayed for sockets that
-are not  tied to a specific remote address. The Tx and Rx queue sizes indicate
-the number  of  bytes  pending  for  transmission  and  reception.  The  state
-indicates the  state  the  socket  is  in and the uid is the owning uid of the
-socket.
-
-The /proc/net/ipx_interface  file lists all IPX interfaces. For each interface
-it gives  the network number, the node number, and indicates if the network is
-the primary  network.  It  also  indicates  which  device  it  is bound to (or
-Internal for  internal  networks)  and  the  Frame  Type if appropriate. Linux
-supports 802.3,  802.2,  802.2  SNAP  and DIX (Blue Book) ethernet framing for
-IPX.
-
-The /proc/net/ipx_route  table  holds  a list of IPX routes. For each route it
-gives the  destination  network, the router node (or Directly) and the network
-address of the router (or Connected) for internal networks.
-
-6. TIPC
--------------------------------------------------------
-
-tipc_rmem
-----------
-
-The TIPC protocol now has a tunable for the receive memory, similar to the
-tcp_rmem - i.e. a vector of 3 INTEGERs: (min, default, max)
-
-    # cat /proc/sys/net/tipc/tipc_rmem
-    4252725 34021800        68043600
-    #
-
-The max value is set to CONN_OVERLOAD_LIMIT, and the default and min values
-are scaled (shifted) versions of that same value.  Note that the min value
-is not at this point in time used in any meaningful way, but the triplet is
-preserved in order to be consistent with things like tcp_rmem.
-
-named_timeout
---------------
-
-TIPC name table updates are distributed asynchronously in a cluster, without
-any form of transaction handling. This means that different race scenarios are
-possible. One such is that a name withdrawal sent out by one node and received
-by another node may arrive after a second, overlapping name publication already
-has been accepted from a third node, although the conflicting updates
-originally may have been issued in the correct sequential order.
-If named_timeout is nonzero, failed topology updates will be placed on a defer
-queue until another event arrives that clears the error, or until the timeout
-expires. Value is in milliseconds.
diff --git a/Documentation/sysctl/sunrpc.txt b/Documentation/sysctl/sunrpc.txt
deleted file mode 100644 (file)
index ae1ecac..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-Documentation for /proc/sys/sunrpc/*   kernel version 2.2.10
-       (c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
-
-For general info and legal blurb, please look in README.
-
-==============================================================
-
-This file contains the documentation for the sysctl files in
-/proc/sys/sunrpc and is valid for Linux kernel version 2.2.
-
-The files in this directory can be used to (re)set the debug
-flags of the SUN Remote Procedure Call (RPC) subsystem in
-the Linux kernel. This stuff is used for NFS, KNFSD and
-maybe a few other things as well.
-
-The files in there are used to control the debugging flags:
-rpc_debug, nfs_debug, nfsd_debug and nlm_debug.
-
-These flags are for kernel hackers only. You should read the
-source code in net/sunrpc/ for more information.
diff --git a/Documentation/sysctl/user.txt b/Documentation/sysctl/user.txt
deleted file mode 100644 (file)
index a588286..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-Documentation for /proc/sys/user/*     kernel version 4.9.0
-       (c) 2016                Eric Biederman <ebiederm@xmission.com>
-
-==============================================================
-
-This file contains the documentation for the sysctl files in
-/proc/sys/user.
-
-The files in this directory can be used to override the default
-limits on the number of namespaces and other objects that have
-per user per user namespace limits.
-
-The primary purpose of these limits is to stop programs that
-malfunction and attempt to create a ridiculous number of objects,
-before the malfunction becomes a system wide problem.  It is the
-intention that the defaults of these limits are set high enough that
-no program in normal operation should run into these limits.
-
-The creation of per user per user namespace objects are charged to
-the user in the user namespace who created the object and
-verified to be below the per user limit in that user namespace.
-
-The creation of objects is also charged to all of the users
-who created user namespaces the creation of the object happens
-in (user namespaces can be nested) and verified to be below the per user
-limits in the user namespaces of those users.
-
-This recursive counting of created objects ensures that creating a
-user namespace does not allow a user to escape their current limits.
-
-Currently, these files are in /proc/sys/user:
-
-- max_cgroup_namespaces
-
-  The maximum number of cgroup namespaces that any user in the current
-  user namespace may create.
-
-- max_ipc_namespaces
-
-  The maximum number of ipc namespaces that any user in the current
-  user namespace may create.
-
-- max_mnt_namespaces
-
-  The maximum number of mount namespaces that any user in the current
-  user namespace may create.
-
-- max_net_namespaces
-
-  The maximum number of network namespaces that any user in the
-  current user namespace may create.
-
-- max_pid_namespaces
-
-  The maximum number of pid namespaces that any user in the current
-  user namespace may create.
-
-- max_user_namespaces
-
-  The maximum number of user namespaces that any user in the current
-  user namespace may create.
-
-- max_uts_namespaces
-
-  The maximum number of user namespaces that any user in the current
-  user namespace may create.
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
deleted file mode 100644 (file)
index 7493220..0000000
+++ /dev/null
@@ -1,946 +0,0 @@
-Documentation for /proc/sys/vm/*       kernel version 2.6.29
-       (c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
-       (c) 2008         Peter W. Morreale <pmorreale@novell.com>
-
-For general info and legal blurb, please look in README.
-
-==============================================================
-
-This file contains the documentation for the sysctl files in
-/proc/sys/vm and is valid for Linux kernel version 2.6.29.
-
-The files in this directory can be used to tune the operation
-of the virtual memory (VM) subsystem of the Linux kernel and
-the writeout of dirty data to disk.
-
-Default values and initialization routines for most of these
-files can be found in mm/swap.c.
-
-Currently, these files are in /proc/sys/vm:
-
-- admin_reserve_kbytes
-- block_dump
-- compact_memory
-- compact_unevictable_allowed
-- dirty_background_bytes
-- dirty_background_ratio
-- dirty_bytes
-- dirty_expire_centisecs
-- dirty_ratio
-- dirtytime_expire_seconds
-- dirty_writeback_centisecs
-- drop_caches
-- extfrag_threshold
-- hugetlb_shm_group
-- laptop_mode
-- legacy_va_layout
-- lowmem_reserve_ratio
-- max_map_count
-- memory_failure_early_kill
-- memory_failure_recovery
-- min_free_kbytes
-- min_slab_ratio
-- min_unmapped_ratio
-- mmap_min_addr
-- mmap_rnd_bits
-- mmap_rnd_compat_bits
-- nr_hugepages
-- nr_hugepages_mempolicy
-- nr_overcommit_hugepages
-- nr_trim_pages         (only if CONFIG_MMU=n)
-- numa_zonelist_order
-- oom_dump_tasks
-- oom_kill_allocating_task
-- overcommit_kbytes
-- overcommit_memory
-- overcommit_ratio
-- page-cluster
-- panic_on_oom
-- percpu_pagelist_fraction
-- stat_interval
-- stat_refresh
-- numa_stat
-- swappiness
-- unprivileged_userfaultfd
-- user_reserve_kbytes
-- vfs_cache_pressure
-- watermark_boost_factor
-- watermark_scale_factor
-- zone_reclaim_mode
-
-==============================================================
-
-admin_reserve_kbytes
-
-The amount of free memory in the system that should be reserved for users
-with the capability cap_sys_admin.
-
-admin_reserve_kbytes defaults to min(3% of free pages, 8MB)
-
-That should provide enough for the admin to log in and kill a process,
-if necessary, under the default overcommit 'guess' mode.
-
-Systems running under overcommit 'never' should increase this to account
-for the full Virtual Memory Size of programs used to recover. Otherwise,
-root may not be able to log in to recover the system.
-
-How do you calculate a minimum useful reserve?
-
-sshd or login + bash (or some other shell) + top (or ps, kill, etc.)
-
-For overcommit 'guess', we can sum resident set sizes (RSS).
-On x86_64 this is about 8MB.
-
-For overcommit 'never', we can take the max of their virtual sizes (VSZ)
-and add the sum of their RSS.
-On x86_64 this is about 128MB.
-
-Changing this takes effect whenever an application requests memory.
-
-==============================================================
-
-block_dump
-
-block_dump enables block I/O debugging when set to a nonzero value. More
-information on block I/O debugging is in Documentation/laptops/laptop-mode.txt.
-
-==============================================================
-
-compact_memory
-
-Available only when CONFIG_COMPACTION is set. When 1 is written to the file,
-all zones are compacted such that free memory is available in contiguous
-blocks where possible. This can be important for example in the allocation of
-huge pages although processes will also directly compact memory as required.
-
-==============================================================
-
-compact_unevictable_allowed
-
-Available only when CONFIG_COMPACTION is set. When set to 1, compaction is
-allowed to examine the unevictable lru (mlocked pages) for pages to compact.
-This should be used on systems where stalls for minor page faults are an
-acceptable trade for large contiguous free memory.  Set to 0 to prevent
-compaction from moving pages that are unevictable.  Default value is 1.
-
-==============================================================
-
-dirty_background_bytes
-
-Contains the amount of dirty memory at which the background kernel
-flusher threads will start writeback.
-
-Note: dirty_background_bytes is the counterpart of dirty_background_ratio. Only
-one of them may be specified at a time. When one sysctl is written it is
-immediately taken into account to evaluate the dirty memory limits and the
-other appears as 0 when read.
-
-==============================================================
-
-dirty_background_ratio
-
-Contains, as a percentage of total available memory that contains free pages
-and reclaimable pages, the number of pages at which the background kernel
-flusher threads will start writing out dirty data.
-
-The total available memory is not equal to total system memory.
-
-==============================================================
-
-dirty_bytes
-
-Contains the amount of dirty memory at which a process generating disk writes
-will itself start writeback.
-
-Note: dirty_bytes is the counterpart of dirty_ratio. Only one of them may be
-specified at a time. When one sysctl is written it is immediately taken into
-account to evaluate the dirty memory limits and the other appears as 0 when
-read.
-
-Note: the minimum value allowed for dirty_bytes is two pages (in bytes); any
-value lower than this limit will be ignored and the old configuration will be
-retained.
-
-==============================================================
-
-dirty_expire_centisecs
-
-This tunable is used to define when dirty data is old enough to be eligible
-for writeout by the kernel flusher threads.  It is expressed in 100'ths
-of a second.  Data which has been dirty in-memory for longer than this
-interval will be written out next time a flusher thread wakes up.
-
-==============================================================
-
-dirty_ratio
-
-Contains, as a percentage of total available memory that contains free pages
-and reclaimable pages, the number of pages at which a process which is
-generating disk writes will itself start writing out dirty data.
-
-The total available memory is not equal to total system memory.
-
-==============================================================
-
-dirtytime_expire_seconds
-
-When a lazytime inode is constantly having its pages dirtied, the inode with
-an updated timestamp will never get chance to be written out.  And, if the
-only thing that has happened on the file system is a dirtytime inode caused
-by an atime update, a worker will be scheduled to make sure that inode
-eventually gets pushed out to disk.  This tunable is used to define when dirty
-inode is old enough to be eligible for writeback by the kernel flusher threads.
-And, it is also used as the interval to wakeup dirtytime_writeback thread.
-
-==============================================================
-
-dirty_writeback_centisecs
-
-The kernel flusher threads will periodically wake up and write `old' data
-out to disk.  This tunable expresses the interval between those wakeups, in
-100'ths of a second.
-
-Setting this to zero disables periodic writeback altogether.
-
-==============================================================
-
-drop_caches
-
-Writing to this will cause the kernel to drop clean caches, as well as
-reclaimable slab objects like dentries and inodes.  Once dropped, their
-memory becomes free.
-
-To free pagecache:
-       echo 1 > /proc/sys/vm/drop_caches
-To free reclaimable slab objects (includes dentries and inodes):
-       echo 2 > /proc/sys/vm/drop_caches
-To free slab objects and pagecache:
-       echo 3 > /proc/sys/vm/drop_caches
-
-This is a non-destructive operation and will not free any dirty objects.
-To increase the number of objects freed by this operation, the user may run
-`sync' prior to writing to /proc/sys/vm/drop_caches.  This will minimize the
-number of dirty objects on the system and create more candidates to be
-dropped.
-
-This file is not a means to control the growth of the various kernel caches
-(inodes, dentries, pagecache, etc...)  These objects are automatically
-reclaimed by the kernel when memory is needed elsewhere on the system.
-
-Use of this file can cause performance problems.  Since it discards cached
-objects, it may cost a significant amount of I/O and CPU to recreate the
-dropped objects, especially if they were under heavy use.  Because of this,
-use outside of a testing or debugging environment is not recommended.
-
-You may see informational messages in your kernel log when this file is
-used:
-
-       cat (1234): drop_caches: 3
-
-These are informational only.  They do not mean that anything is wrong
-with your system.  To disable them, echo 4 (bit 2) into drop_caches.
-
-==============================================================
-
-extfrag_threshold
-
-This parameter affects whether the kernel will compact memory or direct
-reclaim to satisfy a high-order allocation. The extfrag/extfrag_index file in
-debugfs shows what the fragmentation index for each order is in each zone in
-the system. Values tending towards 0 imply allocations would fail due to lack
-of memory, values towards 1000 imply failures are due to fragmentation and -1
-implies that the allocation will succeed as long as watermarks are met.
-
-The kernel will not compact memory in a zone if the
-fragmentation index is <= extfrag_threshold. The default value is 500.
-
-==============================================================
-
-highmem_is_dirtyable
-
-Available only for systems with CONFIG_HIGHMEM enabled (32b systems).
-
-This parameter controls whether the high memory is considered for dirty
-writers throttling.  This is not the case by default which means that
-only the amount of memory directly visible/usable by the kernel can
-be dirtied. As a result, on systems with a large amount of memory and
-lowmem basically depleted writers might be throttled too early and
-streaming writes can get very slow.
-
-Changing the value to non zero would allow more memory to be dirtied
-and thus allow writers to write more data which can be flushed to the
-storage more effectively. Note this also comes with a risk of pre-mature
-OOM killer because some writers (e.g. direct block device writes) can
-only use the low memory and they can fill it up with dirty data without
-any throttling.
-
-==============================================================
-
-hugetlb_shm_group
-
-hugetlb_shm_group contains group id that is allowed to create SysV
-shared memory segment using hugetlb page.
-
-==============================================================
-
-laptop_mode
-
-laptop_mode is a knob that controls "laptop mode". All the things that are
-controlled by this knob are discussed in Documentation/laptops/laptop-mode.txt.
-
-==============================================================
-
-legacy_va_layout
-
-If non-zero, this sysctl disables the new 32-bit mmap layout - the kernel
-will use the legacy (2.4) layout for all processes.
-
-==============================================================
-
-lowmem_reserve_ratio
-
-For some specialised workloads on highmem machines it is dangerous for
-the kernel to allow process memory to be allocated from the "lowmem"
-zone.  This is because that memory could then be pinned via the mlock()
-system call, or by unavailability of swapspace.
-
-And on large highmem machines this lack of reclaimable lowmem memory
-can be fatal.
-
-So the Linux page allocator has a mechanism which prevents allocations
-which _could_ use highmem from using too much lowmem.  This means that
-a certain amount of lowmem is defended from the possibility of being
-captured into pinned user memory.
-
-(The same argument applies to the old 16 megabyte ISA DMA region.  This
-mechanism will also defend that region from allocations which could use
-highmem or lowmem).
-
-The `lowmem_reserve_ratio' tunable determines how aggressive the kernel is
-in defending these lower zones.
-
-If you have a machine which uses highmem or ISA DMA and your
-applications are using mlock(), or if you are running with no swap then
-you probably should change the lowmem_reserve_ratio setting.
-
-The lowmem_reserve_ratio is an array. You can see them by reading this file.
--
-% cat /proc/sys/vm/lowmem_reserve_ratio
-256     256     32
--
-
-But, these values are not used directly. The kernel calculates # of protection
-pages for each zones from them. These are shown as array of protection pages
-in /proc/zoneinfo like followings. (This is an example of x86-64 box).
-Each zone has an array of protection pages like this.
-
--
-Node 0, zone      DMA
-  pages free     1355
-        min      3
-        low      3
-        high     4
-       :
-       :
-    numa_other   0
-        protection: (0, 2004, 2004, 2004)
-       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-  pagesets
-    cpu: 0 pcp: 0
-        :
--
-These protections are added to score to judge whether this zone should be used
-for page allocation or should be reclaimed.
-
-In this example, if normal pages (index=2) are required to this DMA zone and
-watermark[WMARK_HIGH] is used for watermark, the kernel judges this zone should
-not be used because pages_free(1355) is smaller than watermark + protection[2]
-(4 + 2004 = 2008). If this protection value is 0, this zone would be used for
-normal page requirement. If requirement is DMA zone(index=0), protection[0]
-(=0) is used.
-
-zone[i]'s protection[j] is calculated by following expression.
-
-(i < j):
-  zone[i]->protection[j]
-  = (total sums of managed_pages from zone[i+1] to zone[j] on the node)
-    / lowmem_reserve_ratio[i];
-(i = j):
-   (should not be protected. = 0;
-(i > j):
-   (not necessary, but looks 0)
-
-The default values of lowmem_reserve_ratio[i] are
-    256 (if zone[i] means DMA or DMA32 zone)
-    32  (others).
-As above expression, they are reciprocal number of ratio.
-256 means 1/256. # of protection pages becomes about "0.39%" of total managed
-pages of higher zones on the node.
-
-If you would like to protect more pages, smaller values are effective.
-The minimum value is 1 (1/1 -> 100%). The value less than 1 completely
-disables protection of the pages.
-
-==============================================================
-
-max_map_count:
-
-This file contains the maximum number of memory map areas a process
-may have. Memory map areas are used as a side-effect of calling
-malloc, directly by mmap, mprotect, and madvise, and also when loading
-shared libraries.
-
-While most applications need less than a thousand maps, certain
-programs, particularly malloc debuggers, may consume lots of them,
-e.g., up to one or two maps per allocation.
-
-The default value is 65536.
-
-=============================================================
-
-memory_failure_early_kill:
-
-Control how to kill processes when uncorrected memory error (typically
-a 2bit error in a memory module) is detected in the background by hardware
-that cannot be handled by the kernel. In some cases (like the page
-still having a valid copy on disk) the kernel will handle the failure
-transparently without affecting any applications. But if there is
-no other uptodate copy of the data it will kill to prevent any data
-corruptions from propagating.
-
-1: Kill all processes that have the corrupted and not reloadable page mapped
-as soon as the corruption is detected.  Note this is not supported
-for a few types of pages, like kernel internally allocated data or
-the swap cache, but works for the majority of user pages.
-
-0: Only unmap the corrupted page from all processes and only kill a process
-who tries to access it.
-
-The kill is done using a catchable SIGBUS with BUS_MCEERR_AO, so processes can
-handle this if they want to.
-
-This is only active on architectures/platforms with advanced machine
-check handling and depends on the hardware capabilities.
-
-Applications can override this setting individually with the PR_MCE_KILL prctl
-
-==============================================================
-
-memory_failure_recovery
-
-Enable memory failure recovery (when supported by the platform)
-
-1: Attempt recovery.
-
-0: Always panic on a memory failure.
-
-==============================================================
-
-min_free_kbytes:
-
-This is used to force the Linux VM to keep a minimum number
-of kilobytes free.  The VM uses this number to compute a
-watermark[WMARK_MIN] value for each lowmem zone in the system.
-Each lowmem zone gets a number of reserved free pages based
-proportionally on its size.
-
-Some minimal amount of memory is needed to satisfy PF_MEMALLOC
-allocations; if you set this to lower than 1024KB, your system will
-become subtly broken, and prone to deadlock under high loads.
-
-Setting this too high will OOM your machine instantly.
-
-=============================================================
-
-min_slab_ratio:
-
-This is available only on NUMA kernels.
-
-A percentage of the total pages in each zone.  On Zone reclaim
-(fallback from the local zone occurs) slabs will be reclaimed if more
-than this percentage of pages in a zone are reclaimable slab pages.
-This insures that the slab growth stays under control even in NUMA
-systems that rarely perform global reclaim.
-
-The default is 5 percent.
-
-Note that slab reclaim is triggered in a per zone / node fashion.
-The process of reclaiming slab memory is currently not node specific
-and may not be fast.
-
-=============================================================
-
-min_unmapped_ratio:
-
-This is available only on NUMA kernels.
-
-This is a percentage of the total pages in each zone. Zone reclaim will
-only occur if more than this percentage of pages are in a state that
-zone_reclaim_mode allows to be reclaimed.
-
-If zone_reclaim_mode has the value 4 OR'd, then the percentage is compared
-against all file-backed unmapped pages including swapcache pages and tmpfs
-files. Otherwise, only unmapped pages backed by normal files but not tmpfs
-files and similar are considered.
-
-The default is 1 percent.
-
-==============================================================
-
-mmap_min_addr
-
-This file indicates the amount of address space  which a user process will
-be restricted from mmapping.  Since kernel null dereference bugs could
-accidentally operate based on the information in the first couple of pages
-of memory userspace processes should not be allowed to write to them.  By
-default this value is set to 0 and no protections will be enforced by the
-security module.  Setting this value to something like 64k will allow the
-vast majority of applications to work correctly and provide defense in depth
-against future potential kernel bugs.
-
-==============================================================
-
-mmap_rnd_bits:
-
-This value can be used to select the number of bits to use to
-determine the random offset to the base address of vma regions
-resulting from mmap allocations on architectures which support
-tuning address space randomization.  This value will be bounded
-by the architecture's minimum and maximum supported values.
-
-This value can be changed after boot using the
-/proc/sys/vm/mmap_rnd_bits tunable
-
-==============================================================
-
-mmap_rnd_compat_bits:
-
-This value can be used to select the number of bits to use to
-determine the random offset to the base address of vma regions
-resulting from mmap allocations for applications run in
-compatibility mode on architectures which support tuning address
-space randomization.  This value will be bounded by the
-architecture's minimum and maximum supported values.
-
-This value can be changed after boot using the
-/proc/sys/vm/mmap_rnd_compat_bits tunable
-
-==============================================================
-
-nr_hugepages
-
-Change the minimum size of the hugepage pool.
-
-See Documentation/admin-guide/mm/hugetlbpage.rst
-
-==============================================================
-
-nr_hugepages_mempolicy
-
-Change the size of the hugepage pool at run-time on a specific
-set of NUMA nodes.
-
-See Documentation/admin-guide/mm/hugetlbpage.rst
-
-==============================================================
-
-nr_overcommit_hugepages
-
-Change the maximum size of the hugepage pool. The maximum is
-nr_hugepages + nr_overcommit_hugepages.
-
-See Documentation/admin-guide/mm/hugetlbpage.rst
-
-==============================================================
-
-nr_trim_pages
-
-This is available only on NOMMU kernels.
-
-This value adjusts the excess page trimming behaviour of power-of-2 aligned
-NOMMU mmap allocations.
-
-A value of 0 disables trimming of allocations entirely, while a value of 1
-trims excess pages aggressively. Any value >= 1 acts as the watermark where
-trimming of allocations is initiated.
-
-The default value is 1.
-
-See Documentation/nommu-mmap.txt for more information.
-
-==============================================================
-
-numa_zonelist_order
-
-This sysctl is only for NUMA and it is deprecated. Anything but
-Node order will fail!
-
-'where the memory is allocated from' is controlled by zonelists.
-(This documentation ignores ZONE_HIGHMEM/ZONE_DMA32 for simple explanation.
- you may be able to read ZONE_DMA as ZONE_DMA32...)
-
-In non-NUMA case, a zonelist for GFP_KERNEL is ordered as following.
-ZONE_NORMAL -> ZONE_DMA
-This means that a memory allocation request for GFP_KERNEL will
-get memory from ZONE_DMA only when ZONE_NORMAL is not available.
-
-In NUMA case, you can think of following 2 types of order.
-Assume 2 node NUMA and below is zonelist of Node(0)'s GFP_KERNEL
-
-(A) Node(0) ZONE_NORMAL -> Node(0) ZONE_DMA -> Node(1) ZONE_NORMAL
-(B) Node(0) ZONE_NORMAL -> Node(1) ZONE_NORMAL -> Node(0) ZONE_DMA.
-
-Type(A) offers the best locality for processes on Node(0), but ZONE_DMA
-will be used before ZONE_NORMAL exhaustion. This increases possibility of
-out-of-memory(OOM) of ZONE_DMA because ZONE_DMA is tend to be small.
-
-Type(B) cannot offer the best locality but is more robust against OOM of
-the DMA zone.
-
-Type(A) is called as "Node" order. Type (B) is "Zone" order.
-
-"Node order" orders the zonelists by node, then by zone within each node.
-Specify "[Nn]ode" for node order
-
-"Zone Order" orders the zonelists by zone type, then by node within each
-zone.  Specify "[Zz]one" for zone order.
-
-Specify "[Dd]efault" to request automatic configuration.
-
-On 32-bit, the Normal zone needs to be preserved for allocations accessible
-by the kernel, so "zone" order will be selected.
-
-On 64-bit, devices that require DMA32/DMA are relatively rare, so "node"
-order will be selected.
-
-Default order is recommended unless this is causing problems for your
-system/application.
-
-==============================================================
-
-oom_dump_tasks
-
-Enables a system-wide task dump (excluding kernel threads) to be produced
-when the kernel performs an OOM-killing and includes such information as
-pid, uid, tgid, vm size, rss, pgtables_bytes, swapents, oom_score_adj
-score, and name.  This is helpful to determine why the OOM killer was
-invoked, to identify the rogue task that caused it, and to determine why
-the OOM killer chose the task it did to kill.
-
-If this is set to zero, this information is suppressed.  On very
-large systems with thousands of tasks it may not be feasible to dump
-the memory state information for each one.  Such systems should not
-be forced to incur a performance penalty in OOM conditions when the
-information may not be desired.
-
-If this is set to non-zero, this information is shown whenever the
-OOM killer actually kills a memory-hogging task.
-
-The default value is 1 (enabled).
-
-==============================================================
-
-oom_kill_allocating_task
-
-This enables or disables killing the OOM-triggering task in
-out-of-memory situations.
-
-If this is set to zero, the OOM killer will scan through the entire
-tasklist and select a task based on heuristics to kill.  This normally
-selects a rogue memory-hogging task that frees up a large amount of
-memory when killed.
-
-If this is set to non-zero, the OOM killer simply kills the task that
-triggered the out-of-memory condition.  This avoids the expensive
-tasklist scan.
-
-If panic_on_oom is selected, it takes precedence over whatever value
-is used in oom_kill_allocating_task.
-
-The default value is 0.
-
-==============================================================
-
-overcommit_kbytes:
-
-When overcommit_memory is set to 2, the committed address space is not
-permitted to exceed swap plus this amount of physical RAM. See below.
-
-Note: overcommit_kbytes is the counterpart of overcommit_ratio. Only one
-of them may be specified at a time. Setting one disables the other (which
-then appears as 0 when read).
-
-==============================================================
-
-overcommit_memory:
-
-This value contains a flag that enables memory overcommitment.
-
-When this flag is 0, the kernel attempts to estimate the amount
-of free memory left when userspace requests more memory.
-
-When this flag is 1, the kernel pretends there is always enough
-memory until it actually runs out.
-
-When this flag is 2, the kernel uses a "never overcommit"
-policy that attempts to prevent any overcommit of memory.
-Note that user_reserve_kbytes affects this policy.
-
-This feature can be very useful because there are a lot of
-programs that malloc() huge amounts of memory "just-in-case"
-and don't use much of it.
-
-The default value is 0.
-
-See Documentation/vm/overcommit-accounting.rst and
-mm/util.c::__vm_enough_memory() for more information.
-
-==============================================================
-
-overcommit_ratio:
-
-When overcommit_memory is set to 2, the committed address
-space is not permitted to exceed swap plus this percentage
-of physical RAM.  See above.
-
-==============================================================
-
-page-cluster
-
-page-cluster controls the number of pages up to which consecutive pages
-are read in from swap in a single attempt. This is the swap counterpart
-to page cache readahead.
-The mentioned consecutivity is not in terms of virtual/physical addresses,
-but consecutive on swap space - that means they were swapped out together.
-
-It is a logarithmic value - setting it to zero means "1 page", setting
-it to 1 means "2 pages", setting it to 2 means "4 pages", etc.
-Zero disables swap readahead completely.
-
-The default value is three (eight pages at a time).  There may be some
-small benefits in tuning this to a different value if your workload is
-swap-intensive.
-
-Lower values mean lower latencies for initial faults, but at the same time
-extra faults and I/O delays for following faults if they would have been part of
-that consecutive pages readahead would have brought in.
-
-=============================================================
-
-panic_on_oom
-
-This enables or disables panic on out-of-memory feature.
-
-If this is set to 0, the kernel will kill some rogue process,
-called oom_killer.  Usually, oom_killer can kill rogue processes and
-system will survive.
-
-If this is set to 1, the kernel panics when out-of-memory happens.
-However, if a process limits using nodes by mempolicy/cpusets,
-and those nodes become memory exhaustion status, one process
-may be killed by oom-killer. No panic occurs in this case.
-Because other nodes' memory may be free. This means system total status
-may be not fatal yet.
-
-If this is set to 2, the kernel panics compulsorily even on the
-above-mentioned. Even oom happens under memory cgroup, the whole
-system panics.
-
-The default value is 0.
-1 and 2 are for failover of clustering. Please select either
-according to your policy of failover.
-panic_on_oom=2+kdump gives you very strong tool to investigate
-why oom happens. You can get snapshot.
-
-=============================================================
-
-percpu_pagelist_fraction
-
-This is the fraction of pages at most (high mark pcp->high) in each zone that
-are allocated for each per cpu page list.  The min value for this is 8.  It
-means that we don't allow more than 1/8th of pages in each zone to be
-allocated in any single per_cpu_pagelist.  This entry only changes the value
-of hot per cpu pagelists.  User can specify a number like 100 to allocate
-1/100th of each zone to each per cpu page list.
-
-The batch value of each per cpu pagelist is also updated as a result.  It is
-set to pcp->high/4.  The upper limit of batch is (PAGE_SHIFT * 8)
-
-The initial value is zero.  Kernel does not use this value at boot time to set
-the high water marks for each per cpu page list.  If the user writes '0' to this
-sysctl, it will revert to this default behavior.
-
-==============================================================
-
-stat_interval
-
-The time interval between which vm statistics are updated.  The default
-is 1 second.
-
-==============================================================
-
-stat_refresh
-
-Any read or write (by root only) flushes all the per-cpu vm statistics
-into their global totals, for more accurate reports when testing
-e.g. cat /proc/sys/vm/stat_refresh /proc/meminfo
-
-As a side-effect, it also checks for negative totals (elsewhere reported
-as 0) and "fails" with EINVAL if any are found, with a warning in dmesg.
-(At time of writing, a few stats are known sometimes to be found negative,
-with no ill effects: errors and warnings on these stats are suppressed.)
-
-==============================================================
-
-numa_stat
-
-This interface allows runtime configuration of numa statistics.
-
-When page allocation performance becomes a bottleneck and you can tolerate
-some possible tool breakage and decreased numa counter precision, you can
-do:
-       echo 0 > /proc/sys/vm/numa_stat
-
-When page allocation performance is not a bottleneck and you want all
-tooling to work, you can do:
-       echo 1 > /proc/sys/vm/numa_stat
-
-==============================================================
-
-swappiness
-
-This control is used to define how aggressive the kernel will swap
-memory pages.  Higher values will increase aggressiveness, lower values
-decrease the amount of swap.  A value of 0 instructs the kernel not to
-initiate swap until the amount of free and file-backed pages is less
-than the high water mark in a zone.
-
-The default value is 60.
-
-==============================================================
-
-unprivileged_userfaultfd
-
-This flag controls whether unprivileged users can use the userfaultfd
-system calls.  Set this to 1 to allow unprivileged users to use the
-userfaultfd system calls, or set this to 0 to restrict userfaultfd to only
-privileged users (with SYS_CAP_PTRACE capability).
-
-The default value is 1.
-
-==============================================================
-
-- user_reserve_kbytes
-
-When overcommit_memory is set to 2, "never overcommit" mode, reserve
-min(3% of current process size, user_reserve_kbytes) of free memory.
-This is intended to prevent a user from starting a single memory hogging
-process, such that they cannot recover (kill the hog).
-
-user_reserve_kbytes defaults to min(3% of the current process size, 128MB).
-
-If this is reduced to zero, then the user will be allowed to allocate
-all free memory with a single process, minus admin_reserve_kbytes.
-Any subsequent attempts to execute a command will result in
-"fork: Cannot allocate memory".
-
-Changing this takes effect whenever an application requests memory.
-
-==============================================================
-
-vfs_cache_pressure
-------------------
-
-This percentage value controls the tendency of the kernel to reclaim
-the memory which is used for caching of directory and inode objects.
-
-At the default value of vfs_cache_pressure=100 the kernel will attempt to
-reclaim dentries and inodes at a "fair" rate with respect to pagecache and
-swapcache reclaim.  Decreasing vfs_cache_pressure causes the kernel to prefer
-to retain dentry and inode caches. When vfs_cache_pressure=0, the kernel will
-never reclaim dentries and inodes due to memory pressure and this can easily
-lead to out-of-memory conditions. Increasing vfs_cache_pressure beyond 100
-causes the kernel to prefer to reclaim dentries and inodes.
-
-Increasing vfs_cache_pressure significantly beyond 100 may have negative
-performance impact. Reclaim code needs to take various locks to find freeable
-directory and inode objects. With vfs_cache_pressure=1000, it will look for
-ten times more freeable objects than there are.
-
-=============================================================
-
-watermark_boost_factor:
-
-This factor controls the level of reclaim when memory is being fragmented.
-It defines the percentage of the high watermark of a zone that will be
-reclaimed if pages of different mobility are being mixed within pageblocks.
-The intent is that compaction has less work to do in the future and to
-increase the success rate of future high-order allocations such as SLUB
-allocations, THP and hugetlbfs pages.
-
-To make it sensible with respect to the watermark_scale_factor
-parameter, the unit is in fractions of 10,000. The default value of
-15,000 on !DISCONTIGMEM configurations means that up to 150% of the high
-watermark will be reclaimed in the event of a pageblock being mixed due
-to fragmentation. The level of reclaim is determined by the number of
-fragmentation events that occurred in the recent past. If this value is
-smaller than a pageblock then a pageblocks worth of pages will be reclaimed
-(e.g.  2MB on 64-bit x86). A boost factor of 0 will disable the feature.
-
-=============================================================
-
-watermark_scale_factor:
-
-This factor controls the aggressiveness of kswapd. It defines the
-amount of memory left in a node/system before kswapd is woken up and
-how much memory needs to be free before kswapd goes back to sleep.
-
-The unit is in fractions of 10,000. The default value of 10 means the
-distances between watermarks are 0.1% of the available memory in the
-node/system. The maximum value is 1000, or 10% of memory.
-
-A high rate of threads entering direct reclaim (allocstall) or kswapd
-going to sleep prematurely (kswapd_low_wmark_hit_quickly) can indicate
-that the number of free pages kswapd maintains for latency reasons is
-too small for the allocation bursts occurring in the system. This knob
-can then be used to tune kswapd aggressiveness accordingly.
-
-==============================================================
-
-zone_reclaim_mode:
-
-Zone_reclaim_mode allows someone to set more or less aggressive approaches to
-reclaim memory when a zone runs out of memory. If it is set to zero then no
-zone reclaim occurs. Allocations will be satisfied from other zones / nodes
-in the system.
-
-This is value ORed together of
-
-1      = Zone reclaim on
-2      = Zone reclaim writes dirty pages out
-4      = Zone reclaim swaps pages
-
-zone_reclaim_mode is disabled by default.  For file servers or workloads
-that benefit from having their data cached, zone_reclaim_mode should be
-left disabled as the caching effect is likely to be more important than
-data locality.
-
-zone_reclaim may be enabled if it's known that the workload is partitioned
-such that each partition fits within a NUMA node and that accessing remote
-memory would cause a measurable performance reduction.  The page allocator
-will then reclaim easily reusable pages (those page cache pages that are
-currently not used) before allocating off node pages.
-
-Allowing zone reclaim to write out pages stops processes that are
-writing large amounts of data from dirtying pages on other nodes. Zone
-reclaim will write out dirty pages if a zone fills up and so effectively
-throttle the process. This may decrease the performance of a single process
-since it cannot use all of system memory to buffer the outgoing writes
-anymore but it preserve the memory on other nodes so that the performance
-of other processes running on other nodes will not be affected.
-
-Allowing regular swap effectively restricts allocations to the local
-node unless explicitly overridden by memory policies or cpuset
-configurations.
-
-============ End of Document =================================
index b68f489..4b24f81 100644 (file)
@@ -1,4 +1,4 @@
-:orphan:
+.. SPDX-License-Identifier: GPL-2.0
 
 ==================
 TCM Virtual Device
diff --git a/Documentation/thermal/cpu-cooling-api.rst b/Documentation/thermal/cpu-cooling-api.rst
new file mode 100644 (file)
index 0000000..645d914
--- /dev/null
@@ -0,0 +1,107 @@
+=======================
+CPU cooling APIs How To
+=======================
+
+Written by Amit Daniel Kachhap <amit.kachhap@linaro.org>
+
+Updated: 6 Jan 2015
+
+Copyright (c)  2012 Samsung Electronics Co., Ltd(http://www.samsung.com)
+
+0. Introduction
+===============
+
+The generic cpu cooling(freq clipping) provides registration/unregistration APIs
+to the caller. The binding of the cooling devices to the trip point is left for
+the user. The registration APIs returns the cooling device pointer.
+
+1. cpu cooling APIs
+===================
+
+1.1 cpufreq registration/unregistration APIs
+--------------------------------------------
+
+    ::
+
+       struct thermal_cooling_device
+       *cpufreq_cooling_register(struct cpumask *clip_cpus)
+
+    This interface function registers the cpufreq cooling device with the name
+    "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
+    cooling devices.
+
+   clip_cpus:
+       cpumask of cpus where the frequency constraints will happen.
+
+    ::
+
+       struct thermal_cooling_device
+       *of_cpufreq_cooling_register(struct cpufreq_policy *policy)
+
+    This interface function registers the cpufreq cooling device with
+    the name "thermal-cpufreq-%x" linking it with a device tree node, in
+    order to bind it via the thermal DT code. This api can support multiple
+    instances of cpufreq cooling devices.
+
+    policy:
+       CPUFreq policy.
+
+
+    ::
+
+       void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
+
+    This interface function unregisters the "thermal-cpufreq-%x" cooling device.
+
+    cdev: Cooling device pointer which has to be unregistered.
+
+2. Power models
+===============
+
+The power API registration functions provide a simple power model for
+CPUs.  The current power is calculated as dynamic power (static power isn't
+supported currently).  This power model requires that the operating-points of
+the CPUs are registered using the kernel's opp library and the
+`cpufreq_frequency_table` is assigned to the `struct device` of the
+cpu.  If you are using CONFIG_CPUFREQ_DT then the
+`cpufreq_frequency_table` should already be assigned to the cpu
+device.
+
+The dynamic power consumption of a processor depends on many factors.
+For a given processor implementation the primary factors are:
+
+- The time the processor spends running, consuming dynamic power, as
+  compared to the time in idle states where dynamic consumption is
+  negligible.  Herein we refer to this as 'utilisation'.
+- The voltage and frequency levels as a result of DVFS.  The DVFS
+  level is a dominant factor governing power consumption.
+- In running time the 'execution' behaviour (instruction types, memory
+  access patterns and so forth) causes, in most cases, a second order
+  variation.  In pathological cases this variation can be significant,
+  but typically it is of a much lesser impact than the factors above.
+
+A high level dynamic power consumption model may then be represented as::
+
+       Pdyn = f(run) * Voltage^2 * Frequency * Utilisation
+
+f(run) here represents the described execution behaviour and its
+result has a units of Watts/Hz/Volt^2 (this often expressed in
+mW/MHz/uVolt^2)
+
+The detailed behaviour for f(run) could be modelled on-line.  However,
+in practice, such an on-line model has dependencies on a number of
+implementation specific processor support and characterisation
+factors.  Therefore, in initial implementation that contribution is
+represented as a constant coefficient.  This is a simplification
+consistent with the relative contribution to overall power variation.
+
+In this simplified representation our model becomes::
+
+       Pdyn = Capacitance * Voltage^2 * Frequency * Utilisation
+
+Where `capacitance` is a constant that represents an indicative
+running time dynamic power coefficient in fundamental units of
+mW/MHz/uVolt^2.  Typical values for mobile CPUs might lie in range
+from 100 to 500.  For reference, the approximate values for the SoC in
+ARM's Juno Development Platform are 530 for the Cortex-A57 cluster and
+140 for the Cortex-A53 cluster.
diff --git a/Documentation/thermal/cpu-cooling-api.txt b/Documentation/thermal/cpu-cooling-api.txt
deleted file mode 100644 (file)
index 7df567e..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-CPU cooling APIs How To
-===================================
-
-Written by Amit Daniel Kachhap <amit.kachhap@linaro.org>
-
-Updated: 6 Jan 2015
-
-Copyright (c)  2012 Samsung Electronics Co., Ltd(http://www.samsung.com)
-
-0. Introduction
-
-The generic cpu cooling(freq clipping) provides registration/unregistration APIs
-to the caller. The binding of the cooling devices to the trip point is left for
-the user. The registration APIs returns the cooling device pointer.
-
-1. cpu cooling APIs
-
-1.1 cpufreq registration/unregistration APIs
-1.1.1 struct thermal_cooling_device *cpufreq_cooling_register(
-       struct cpumask *clip_cpus)
-
-    This interface function registers the cpufreq cooling device with the name
-    "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
-    cooling devices.
-
-   clip_cpus: cpumask of cpus where the frequency constraints will happen.
-
-1.1.2 struct thermal_cooling_device *of_cpufreq_cooling_register(
-                                       struct cpufreq_policy *policy)
-
-    This interface function registers the cpufreq cooling device with
-    the name "thermal-cpufreq-%x" linking it with a device tree node, in
-    order to bind it via the thermal DT code. This api can support multiple
-    instances of cpufreq cooling devices.
-
-    policy: CPUFreq policy.
-
-1.1.3 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
-
-    This interface function unregisters the "thermal-cpufreq-%x" cooling device.
-
-    cdev: Cooling device pointer which has to be unregistered.
-
-2. Power models
-
-The power API registration functions provide a simple power model for
-CPUs.  The current power is calculated as dynamic power (static power isn't
-supported currently).  This power model requires that the operating-points of
-the CPUs are registered using the kernel's opp library and the
-`cpufreq_frequency_table` is assigned to the `struct device` of the
-cpu.  If you are using CONFIG_CPUFREQ_DT then the
-`cpufreq_frequency_table` should already be assigned to the cpu
-device.
-
-The dynamic power consumption of a processor depends on many factors.
-For a given processor implementation the primary factors are:
-
-- The time the processor spends running, consuming dynamic power, as
-  compared to the time in idle states where dynamic consumption is
-  negligible.  Herein we refer to this as 'utilisation'.
-- The voltage and frequency levels as a result of DVFS.  The DVFS
-  level is a dominant factor governing power consumption.
-- In running time the 'execution' behaviour (instruction types, memory
-  access patterns and so forth) causes, in most cases, a second order
-  variation.  In pathological cases this variation can be significant,
-  but typically it is of a much lesser impact than the factors above.
-
-A high level dynamic power consumption model may then be represented as:
-
-Pdyn = f(run) * Voltage^2 * Frequency * Utilisation
-
-f(run) here represents the described execution behaviour and its
-result has a units of Watts/Hz/Volt^2 (this often expressed in
-mW/MHz/uVolt^2)
-
-The detailed behaviour for f(run) could be modelled on-line.  However,
-in practice, such an on-line model has dependencies on a number of
-implementation specific processor support and characterisation
-factors.  Therefore, in initial implementation that contribution is
-represented as a constant coefficient.  This is a simplification
-consistent with the relative contribution to overall power variation.
-
-In this simplified representation our model becomes:
-
-Pdyn = Capacitance * Voltage^2 * Frequency * Utilisation
-
-Where `capacitance` is a constant that represents an indicative
-running time dynamic power coefficient in fundamental units of
-mW/MHz/uVolt^2.  Typical values for mobile CPUs might lie in range
-from 100 to 500.  For reference, the approximate values for the SoC in
-ARM's Juno Development Platform are 530 for the Cortex-A57 cluster and
-140 for the Cortex-A53 cluster.
diff --git a/Documentation/thermal/exynos_thermal b/Documentation/thermal/exynos_thermal
deleted file mode 100644 (file)
index 9010c44..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-Kernel driver exynos_tmu
-=================
-
-Supported chips:
-* ARM SAMSUNG EXYNOS4, EXYNOS5 series of SoC
-  Datasheet: Not publicly available
-
-Authors: Donggeun Kim <dg77.kim@samsung.com>
-Authors: Amit Daniel <amit.daniel@samsung.com>
-
-TMU controller Description:
----------------------------
-
-This driver allows to read temperature inside SAMSUNG EXYNOS4/5 series of SoC.
-
-The chip only exposes the measured 8-bit temperature code value
-through a register.
-Temperature can be taken from the temperature code.
-There are three equations converting from temperature to temperature code.
-
-The three equations are:
-  1. Two point trimming
-       Tc = (T - 25) * (TI2 - TI1) / (85 - 25) + TI1
-
-  2. One point trimming
-       Tc = T + TI1 - 25
-
-  3. No trimming
-       Tc = T + 50
-
-  Tc: Temperature code, T: Temperature,
-  TI1: Trimming info for 25 degree Celsius (stored at TRIMINFO register)
-       Temperature code measured at 25 degree Celsius which is unchanged
-  TI2: Trimming info for 85 degree Celsius (stored at TRIMINFO register)
-       Temperature code measured at 85 degree Celsius which is unchanged
-
-TMU(Thermal Management Unit) in EXYNOS4/5 generates interrupt
-when temperature exceeds pre-defined levels.
-The maximum number of configurable threshold is five.
-The threshold levels are defined as follows:
-  Level_0: current temperature > trigger_level_0 + threshold
-  Level_1: current temperature > trigger_level_1 + threshold
-  Level_2: current temperature > trigger_level_2 + threshold
-  Level_3: current temperature > trigger_level_3 + threshold
-
-  The threshold and each trigger_level are set
-  through the corresponding registers.
-
-When an interrupt occurs, this driver notify kernel thermal framework
-with the function exynos_report_trigger.
-Although an interrupt condition for level_0 can be set,
-it can be used to synchronize the cooling action.
-
-TMU driver description:
------------------------
-
-The exynos thermal driver is structured as,
-
-                                       Kernel Core thermal framework
-                               (thermal_core.c, step_wise.c, cpu_cooling.c)
-                                                               ^
-                                                               |
-                                                               |
-TMU configuration data -------> TMU Driver  <------> Exynos Core thermal wrapper
-(exynos_tmu_data.c)          (exynos_tmu.c)       (exynos_thermal_common.c)
-(exynos_tmu_data.h)          (exynos_tmu.h)       (exynos_thermal_common.h)
-
-a) TMU configuration data: This consist of TMU register offsets/bitfields
-               described through structure exynos_tmu_registers. Also several
-               other platform data (struct exynos_tmu_platform_data) members
-               are used to configure the TMU.
-b) TMU driver: This component initialises the TMU controller and sets different
-               thresholds. It invokes core thermal implementation with the call
-               exynos_report_trigger.
-c) Exynos Core thermal wrapper: This provides 3 wrapper function to use the
-               Kernel core thermal framework. They are exynos_unregister_thermal,
-               exynos_register_thermal and exynos_report_trigger.
diff --git a/Documentation/thermal/exynos_thermal.rst b/Documentation/thermal/exynos_thermal.rst
new file mode 100644 (file)
index 0000000..5bd5565
--- /dev/null
@@ -0,0 +1,90 @@
+========================
+Kernel driver exynos_tmu
+========================
+
+Supported chips:
+
+* ARM SAMSUNG EXYNOS4, EXYNOS5 series of SoC
+
+  Datasheet: Not publicly available
+
+Authors: Donggeun Kim <dg77.kim@samsung.com>
+Authors: Amit Daniel <amit.daniel@samsung.com>
+
+TMU controller Description:
+---------------------------
+
+This driver allows to read temperature inside SAMSUNG EXYNOS4/5 series of SoC.
+
+The chip only exposes the measured 8-bit temperature code value
+through a register.
+Temperature can be taken from the temperature code.
+There are three equations converting from temperature to temperature code.
+
+The three equations are:
+  1. Two point trimming::
+
+       Tc = (T - 25) * (TI2 - TI1) / (85 - 25) + TI1
+
+  2. One point trimming::
+
+       Tc = T + TI1 - 25
+
+  3. No trimming::
+
+       Tc = T + 50
+
+  Tc:
+       Temperature code, T: Temperature,
+  TI1:
+       Trimming info for 25 degree Celsius (stored at TRIMINFO register)
+       Temperature code measured at 25 degree Celsius which is unchanged
+  TI2:
+       Trimming info for 85 degree Celsius (stored at TRIMINFO register)
+       Temperature code measured at 85 degree Celsius which is unchanged
+
+TMU(Thermal Management Unit) in EXYNOS4/5 generates interrupt
+when temperature exceeds pre-defined levels.
+The maximum number of configurable threshold is five.
+The threshold levels are defined as follows::
+
+  Level_0: current temperature > trigger_level_0 + threshold
+  Level_1: current temperature > trigger_level_1 + threshold
+  Level_2: current temperature > trigger_level_2 + threshold
+  Level_3: current temperature > trigger_level_3 + threshold
+
+The threshold and each trigger_level are set
+through the corresponding registers.
+
+When an interrupt occurs, this driver notify kernel thermal framework
+with the function exynos_report_trigger.
+Although an interrupt condition for level_0 can be set,
+it can be used to synchronize the cooling action.
+
+TMU driver description:
+-----------------------
+
+The exynos thermal driver is structured as::
+
+                                       Kernel Core thermal framework
+                               (thermal_core.c, step_wise.c, cpu_cooling.c)
+                                                               ^
+                                                               |
+                                                               |
+  TMU configuration data -----> TMU Driver  <----> Exynos Core thermal wrapper
+  (exynos_tmu_data.c)        (exynos_tmu.c)       (exynos_thermal_common.c)
+  (exynos_tmu_data.h)        (exynos_tmu.h)       (exynos_thermal_common.h)
+
+a) TMU configuration data:
+               This consist of TMU register offsets/bitfields
+               described through structure exynos_tmu_registers. Also several
+               other platform data (struct exynos_tmu_platform_data) members
+               are used to configure the TMU.
+b) TMU driver:
+               This component initialises the TMU controller and sets different
+               thresholds. It invokes core thermal implementation with the call
+               exynos_report_trigger.
+c) Exynos Core thermal wrapper:
+               This provides 3 wrapper function to use the
+               Kernel core thermal framework. They are exynos_unregister_thermal,
+               exynos_register_thermal and exynos_report_trigger.
diff --git a/Documentation/thermal/exynos_thermal_emulation b/Documentation/thermal/exynos_thermal_emulation
deleted file mode 100644 (file)
index b15efec..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-EXYNOS EMULATION MODE
-========================
-
-Copyright (C) 2012 Samsung Electronics
-
-Written by Jonghwa Lee <jonghwa3.lee@samsung.com>
-
-Description
------------
-
-Exynos 4x12 (4212, 4412) and 5 series provide emulation mode for thermal management unit.
-Thermal emulation mode supports software debug for TMU's operation. User can set temperature
-manually with software code and TMU will read current temperature from user value not from
-sensor's value.
-
-Enabling CONFIG_THERMAL_EMULATION option will make this support available.
-When it's enabled, sysfs node will be created as
-/sys/devices/virtual/thermal/thermal_zone'zone id'/emul_temp.
-
-The sysfs node, 'emul_node', will contain value 0 for the initial state. When you input any
-temperature you want to update to sysfs node, it automatically enable emulation mode and
-current temperature will be changed into it.
-(Exynos also supports user changeable delay time which would be used to delay of
- changing temperature. However, this node only uses same delay of real sensing time, 938us.)
-
-Exynos emulation mode requires synchronous of value changing and enabling. It means when you
-want to update the any value of delay or next temperature, then you have to enable emulation
-mode at the same time. (Or you have to keep the mode enabling.) If you don't, it fails to
-change the value to updated one and just use last succeessful value repeatedly. That's why
-this node gives users the right to change termerpature only. Just one interface makes it more
-simply to use.
-
-Disabling emulation mode only requires writing value 0 to sysfs node.
-
-
-TEMP   120 |
-           |
-       100 |
-           |
-        80 |
-           |                            +-----------
-        60 |                            |          |
-           |              +-------------|          |
-        40 |              |             |          |
-           |              |             |          |
-        20 |              |             |          +----------
-           |              |             |          |          |
-         0 |______________|_____________|__________|__________|_________
-                  A             A          A                  A     TIME
-                  |<----->|     |<----->|  |<----->|          |
-                  | 938us |     |       |  |       |          |
-emulation    :  0  50     |     70      |  20      |          0
-current temp :   sensor   50            70         20        sensor
diff --git a/Documentation/thermal/exynos_thermal_emulation.rst b/Documentation/thermal/exynos_thermal_emulation.rst
new file mode 100644 (file)
index 0000000..c21d108
--- /dev/null
@@ -0,0 +1,61 @@
+=====================
+Exynos Emulation Mode
+=====================
+
+Copyright (C) 2012 Samsung Electronics
+
+Written by Jonghwa Lee <jonghwa3.lee@samsung.com>
+
+Description
+-----------
+
+Exynos 4x12 (4212, 4412) and 5 series provide emulation mode for thermal
+management unit. Thermal emulation mode supports software debug for
+TMU's operation. User can set temperature manually with software code
+and TMU will read current temperature from user value not from sensor's
+value.
+
+Enabling CONFIG_THERMAL_EMULATION option will make this support
+available. When it's enabled, sysfs node will be created as
+/sys/devices/virtual/thermal/thermal_zone'zone id'/emul_temp.
+
+The sysfs node, 'emul_node', will contain value 0 for the initial state.
+When you input any temperature you want to update to sysfs node, it
+automatically enable emulation mode and current temperature will be
+changed into it.
+
+(Exynos also supports user changeable delay time which would be used to
+delay of changing temperature. However, this node only uses same delay
+of real sensing time, 938us.)
+
+Exynos emulation mode requires synchronous of value changing and
+enabling. It means when you want to update the any value of delay or
+next temperature, then you have to enable emulation mode at the same
+time. (Or you have to keep the mode enabling.) If you don't, it fails to
+change the value to updated one and just use last succeessful value
+repeatedly. That's why this node gives users the right to change
+termerpature only. Just one interface makes it more simply to use.
+
+Disabling emulation mode only requires writing value 0 to sysfs node.
+
+::
+
+
+  TEMP 120 |
+           |
+       100 |
+           |
+        80 |
+           |                            +-----------
+        60 |                            |          |
+           |              +-------------|          |
+        40 |              |             |          |
+           |              |             |          |
+        20 |              |             |          +----------
+           |              |             |          |          |
+         0 |______________|_____________|__________|__________|_________
+                  A             A          A                  A     TIME
+                  |<----->|     |<----->|  |<----->|          |
+                  | 938us |     |       |  |       |          |
+  emulation   : 0  50     |     70      |  20      |          0
+  current temp:   sensor   50           70         20        sensor
diff --git a/Documentation/thermal/index.rst b/Documentation/thermal/index.rst
new file mode 100644 (file)
index 0000000..8c1c001
--- /dev/null
@@ -0,0 +1,18 @@
+:orphan:
+
+=======
+Thermal
+=======
+
+.. toctree::
+   :maxdepth: 1
+
+   cpu-cooling-api
+   sysfs-api
+   power_allocator
+
+   exynos_thermal
+   exynos_thermal_emulation
+   intel_powerclamp
+   nouveau_thermal
+   x86_pkg_temperature_thermal
diff --git a/Documentation/thermal/intel_powerclamp.rst b/Documentation/thermal/intel_powerclamp.rst
new file mode 100644 (file)
index 0000000..3f6dfb0
--- /dev/null
@@ -0,0 +1,320 @@
+=======================
+Intel Powerclamp Driver
+=======================
+
+By:
+  - Arjan van de Ven <arjan@linux.intel.com>
+  - Jacob Pan <jacob.jun.pan@linux.intel.com>
+
+.. Contents:
+
+       (*) Introduction
+           - Goals and Objectives
+
+       (*) Theory of Operation
+           - Idle Injection
+           - Calibration
+
+       (*) Performance Analysis
+           - Effectiveness and Limitations
+           - Power vs Performance
+           - Scalability
+           - Calibration
+           - Comparison with Alternative Techniques
+
+       (*) Usage and Interfaces
+           - Generic Thermal Layer (sysfs)
+           - Kernel APIs (TBD)
+
+INTRODUCTION
+============
+
+Consider the situation where a system’s power consumption must be
+reduced at runtime, due to power budget, thermal constraint, or noise
+level, and where active cooling is not preferred. Software managed
+passive power reduction must be performed to prevent the hardware
+actions that are designed for catastrophic scenarios.
+
+Currently, P-states, T-states (clock modulation), and CPU offlining
+are used for CPU throttling.
+
+On Intel CPUs, C-states provide effective power reduction, but so far
+they’re only used opportunistically, based on workload. With the
+development of intel_powerclamp driver, the method of synchronizing
+idle injection across all online CPU threads was introduced. The goal
+is to achieve forced and controllable C-state residency.
+
+Test/Analysis has been made in the areas of power, performance,
+scalability, and user experience. In many cases, clear advantage is
+shown over taking the CPU offline or modulating the CPU clock.
+
+
+THEORY OF OPERATION
+===================
+
+Idle Injection
+--------------
+
+On modern Intel processors (Nehalem or later), package level C-state
+residency is available in MSRs, thus also available to the kernel.
+
+These MSRs are::
+
+      #define MSR_PKG_C2_RESIDENCY      0x60D
+      #define MSR_PKG_C3_RESIDENCY      0x3F8
+      #define MSR_PKG_C6_RESIDENCY      0x3F9
+      #define MSR_PKG_C7_RESIDENCY      0x3FA
+
+If the kernel can also inject idle time to the system, then a
+closed-loop control system can be established that manages package
+level C-state. The intel_powerclamp driver is conceived as such a
+control system, where the target set point is a user-selected idle
+ratio (based on power reduction), and the error is the difference
+between the actual package level C-state residency ratio and the target idle
+ratio.
+
+Injection is controlled by high priority kernel threads, spawned for
+each online CPU.
+
+These kernel threads, with SCHED_FIFO class, are created to perform
+clamping actions of controlled duty ratio and duration. Each per-CPU
+thread synchronizes its idle time and duration, based on the rounding
+of jiffies, so accumulated errors can be prevented to avoid a jittery
+effect. Threads are also bound to the CPU such that they cannot be
+migrated, unless the CPU is taken offline. In this case, threads
+belong to the offlined CPUs will be terminated immediately.
+
+Running as SCHED_FIFO and relatively high priority, also allows such
+scheme to work for both preemptable and non-preemptable kernels.
+Alignment of idle time around jiffies ensures scalability for HZ
+values. This effect can be better visualized using a Perf timechart.
+The following diagram shows the behavior of kernel thread
+kidle_inject/cpu. During idle injection, it runs monitor/mwait idle
+for a given "duration", then relinquishes the CPU to other tasks,
+until the next time interval.
+
+The NOHZ schedule tick is disabled during idle time, but interrupts
+are not masked. Tests show that the extra wakeups from scheduler tick
+have a dramatic impact on the effectiveness of the powerclamp driver
+on large scale systems (Westmere system with 80 processors).
+
+::
+
+  CPU0
+                   ____________          ____________
+  kidle_inject/0   |   sleep    |  mwait |  sleep     |
+         _________|            |________|            |_______
+                                duration
+  CPU1
+                   ____________          ____________
+  kidle_inject/1   |   sleep    |  mwait |  sleep     |
+         _________|            |________|            |_______
+                               ^
+                               |
+                               |
+                               roundup(jiffies, interval)
+
+Only one CPU is allowed to collect statistics and update global
+control parameters. This CPU is referred to as the controlling CPU in
+this document. The controlling CPU is elected at runtime, with a
+policy that favors BSP, taking into account the possibility of a CPU
+hot-plug.
+
+In terms of dynamics of the idle control system, package level idle
+time is considered largely as a non-causal system where its behavior
+cannot be based on the past or current input. Therefore, the
+intel_powerclamp driver attempts to enforce the desired idle time
+instantly as given input (target idle ratio). After injection,
+powerclamp monitors the actual idle for a given time window and adjust
+the next injection accordingly to avoid over/under correction.
+
+When used in a causal control system, such as a temperature control,
+it is up to the user of this driver to implement algorithms where
+past samples and outputs are included in the feedback. For example, a
+PID-based thermal controller can use the powerclamp driver to
+maintain a desired target temperature, based on integral and
+derivative gains of the past samples.
+
+
+
+Calibration
+-----------
+During scalability testing, it is observed that synchronized actions
+among CPUs become challenging as the number of cores grows. This is
+also true for the ability of a system to enter package level C-states.
+
+To make sure the intel_powerclamp driver scales well, online
+calibration is implemented. The goals for doing such a calibration
+are:
+
+a) determine the effective range of idle injection ratio
+b) determine the amount of compensation needed at each target ratio
+
+Compensation to each target ratio consists of two parts:
+
+       a) steady state error compensation
+       This is to offset the error occurring when the system can
+       enter idle without extra wakeups (such as external interrupts).
+
+       b) dynamic error compensation
+       When an excessive amount of wakeups occurs during idle, an
+       additional idle ratio can be added to quiet interrupts, by
+       slowing down CPU activities.
+
+A debugfs file is provided for the user to examine compensation
+progress and results, such as on a Westmere system::
+
+  [jacob@nex01 ~]$ cat
+  /sys/kernel/debug/intel_powerclamp/powerclamp_calib
+  controlling cpu: 0
+  pct confidence steady dynamic (compensation)
+  0       0       0       0
+  1       1       0       0
+  2       1       1       0
+  3       3       1       0
+  4       3       1       0
+  5       3       1       0
+  6       3       1       0
+  7       3       1       0
+  8       3       1       0
+  ...
+  30      3       2       0
+  31      3       2       0
+  32      3       1       0
+  33      3       2       0
+  34      3       1       0
+  35      3       2       0
+  36      3       1       0
+  37      3       2       0
+  38      3       1       0
+  39      3       2       0
+  40      3       3       0
+  41      3       1       0
+  42      3       2       0
+  43      3       1       0
+  44      3       1       0
+  45      3       2       0
+  46      3       3       0
+  47      3       0       0
+  48      3       2       0
+  49      3       3       0
+
+Calibration occurs during runtime. No offline method is available.
+Steady state compensation is used only when confidence levels of all
+adjacent ratios have reached satisfactory level. A confidence level
+is accumulated based on clean data collected at runtime. Data
+collected during a period without extra interrupts is considered
+clean.
+
+To compensate for excessive amounts of wakeup during idle, additional
+idle time is injected when such a condition is detected. Currently,
+we have a simple algorithm to double the injection ratio. A possible
+enhancement might be to throttle the offending IRQ, such as delaying
+EOI for level triggered interrupts. But it is a challenge to be
+non-intrusive to the scheduler or the IRQ core code.
+
+
+CPU Online/Offline
+------------------
+Per-CPU kernel threads are started/stopped upon receiving
+notifications of CPU hotplug activities. The intel_powerclamp driver
+keeps track of clamping kernel threads, even after they are migrated
+to other CPUs, after a CPU offline event.
+
+
+Performance Analysis
+====================
+This section describes the general performance data collected on
+multiple systems, including Westmere (80P) and Ivy Bridge (4P, 8P).
+
+Effectiveness and Limitations
+-----------------------------
+The maximum range that idle injection is allowed is capped at 50
+percent. As mentioned earlier, since interrupts are allowed during
+forced idle time, excessive interrupts could result in less
+effectiveness. The extreme case would be doing a ping -f to generated
+flooded network interrupts without much CPU acknowledgement. In this
+case, little can be done from the idle injection threads. In most
+normal cases, such as scp a large file, applications can be throttled
+by the powerclamp driver, since slowing down the CPU also slows down
+network protocol processing, which in turn reduces interrupts.
+
+When control parameters change at runtime by the controlling CPU, it
+may take an additional period for the rest of the CPUs to catch up
+with the changes. During this time, idle injection is out of sync,
+thus not able to enter package C- states at the expected ratio. But
+this effect is minor, in that in most cases change to the target
+ratio is updated much less frequently than the idle injection
+frequency.
+
+Scalability
+-----------
+Tests also show a minor, but measurable, difference between the 4P/8P
+Ivy Bridge system and the 80P Westmere server under 50% idle ratio.
+More compensation is needed on Westmere for the same amount of
+target idle ratio. The compensation also increases as the idle ratio
+gets larger. The above reason constitutes the need for the
+calibration code.
+
+On the IVB 8P system, compared to an offline CPU, powerclamp can
+achieve up to 40% better performance per watt. (measured by a spin
+counter summed over per CPU counting threads spawned for all running
+CPUs).
+
+Usage and Interfaces
+====================
+The powerclamp driver is registered to the generic thermal layer as a
+cooling device. Currently, it’s not bound to any thermal zones::
+
+  jacob@chromoly:/sys/class/thermal/cooling_device14$ grep . *
+  cur_state:0
+  max_state:50
+  type:intel_powerclamp
+
+cur_state allows user to set the desired idle percentage. Writing 0 to
+cur_state will stop idle injection. Writing a value between 1 and
+max_state will start the idle injection. Reading cur_state returns the
+actual and current idle percentage. This may not be the same value
+set by the user in that current idle percentage depends on workload
+and includes natural idle. When idle injection is disabled, reading
+cur_state returns value -1 instead of 0 which is to avoid confusing
+100% busy state with the disabled state.
+
+Example usage:
+- To inject 25% idle time::
+
+       $ sudo sh -c "echo 25 > /sys/class/thermal/cooling_device80/cur_state
+
+If the system is not busy and has more than 25% idle time already,
+then the powerclamp driver will not start idle injection. Using Top
+will not show idle injection kernel threads.
+
+If the system is busy (spin test below) and has less than 25% natural
+idle time, powerclamp kernel threads will do idle injection. Forced
+idle time is accounted as normal idle in that common code path is
+taken as the idle task.
+
+In this example, 24.1% idle is shown. This helps the system admin or
+user determine the cause of slowdown, when a powerclamp driver is in action::
+
+
+  Tasks: 197 total,   1 running, 196 sleeping,   0 stopped,   0 zombie
+  Cpu(s): 71.2%us,  4.7%sy,  0.0%ni, 24.1%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
+  Mem:   3943228k total,  1689632k used,  2253596k free,    74960k buffers
+  Swap:  4087804k total,        0k used,  4087804k free,   945336k cached
+
+    PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
+   3352 jacob     20   0  262m  644  428 S  286  0.0   0:17.16 spin
+   3341 root     -51   0     0    0    0 D   25  0.0   0:01.62 kidle_inject/0
+   3344 root     -51   0     0    0    0 D   25  0.0   0:01.60 kidle_inject/3
+   3342 root     -51   0     0    0    0 D   25  0.0   0:01.61 kidle_inject/1
+   3343 root     -51   0     0    0    0 D   25  0.0   0:01.60 kidle_inject/2
+   2935 jacob     20   0  696m 125m  35m S    5  3.3   0:31.11 firefox
+   1546 root      20   0  158m  20m 6640 S    3  0.5   0:26.97 Xorg
+   2100 jacob     20   0 1223m  88m  30m S    3  2.3   0:23.68 compiz
+
+Tests have shown that by using the powerclamp driver as a cooling
+device, a PID based userspace thermal controller can manage to
+control CPU temperature effectively, when no other thermal influence
+is added. For example, a UltraBook user can compile the kernel under
+certain temperature (below most active trip points).
diff --git a/Documentation/thermal/intel_powerclamp.txt b/Documentation/thermal/intel_powerclamp.txt
deleted file mode 100644 (file)
index b5df211..0000000
+++ /dev/null
@@ -1,317 +0,0 @@
-                        =======================
-                        INTEL POWERCLAMP DRIVER
-                        =======================
-By: Arjan van de Ven <arjan@linux.intel.com>
-    Jacob Pan <jacob.jun.pan@linux.intel.com>
-
-Contents:
-       (*) Introduction
-           - Goals and Objectives
-
-       (*) Theory of Operation
-           - Idle Injection
-           - Calibration
-
-       (*) Performance Analysis
-           - Effectiveness and Limitations
-           - Power vs Performance
-           - Scalability
-           - Calibration
-           - Comparison with Alternative Techniques
-
-       (*) Usage and Interfaces
-           - Generic Thermal Layer (sysfs)
-           - Kernel APIs (TBD)
-
-============
-INTRODUCTION
-============
-
-Consider the situation where a system’s power consumption must be
-reduced at runtime, due to power budget, thermal constraint, or noise
-level, and where active cooling is not preferred. Software managed
-passive power reduction must be performed to prevent the hardware
-actions that are designed for catastrophic scenarios.
-
-Currently, P-states, T-states (clock modulation), and CPU offlining
-are used for CPU throttling.
-
-On Intel CPUs, C-states provide effective power reduction, but so far
-they’re only used opportunistically, based on workload. With the
-development of intel_powerclamp driver, the method of synchronizing
-idle injection across all online CPU threads was introduced. The goal
-is to achieve forced and controllable C-state residency.
-
-Test/Analysis has been made in the areas of power, performance,
-scalability, and user experience. In many cases, clear advantage is
-shown over taking the CPU offline or modulating the CPU clock.
-
-
-===================
-THEORY OF OPERATION
-===================
-
-Idle Injection
---------------
-
-On modern Intel processors (Nehalem or later), package level C-state
-residency is available in MSRs, thus also available to the kernel.
-
-These MSRs are:
-      #define MSR_PKG_C2_RESIDENCY     0x60D
-      #define MSR_PKG_C3_RESIDENCY     0x3F8
-      #define MSR_PKG_C6_RESIDENCY     0x3F9
-      #define MSR_PKG_C7_RESIDENCY     0x3FA
-
-If the kernel can also inject idle time to the system, then a
-closed-loop control system can be established that manages package
-level C-state. The intel_powerclamp driver is conceived as such a
-control system, where the target set point is a user-selected idle
-ratio (based on power reduction), and the error is the difference
-between the actual package level C-state residency ratio and the target idle
-ratio.
-
-Injection is controlled by high priority kernel threads, spawned for
-each online CPU.
-
-These kernel threads, with SCHED_FIFO class, are created to perform
-clamping actions of controlled duty ratio and duration. Each per-CPU
-thread synchronizes its idle time and duration, based on the rounding
-of jiffies, so accumulated errors can be prevented to avoid a jittery
-effect. Threads are also bound to the CPU such that they cannot be
-migrated, unless the CPU is taken offline. In this case, threads
-belong to the offlined CPUs will be terminated immediately.
-
-Running as SCHED_FIFO and relatively high priority, also allows such
-scheme to work for both preemptable and non-preemptable kernels.
-Alignment of idle time around jiffies ensures scalability for HZ
-values. This effect can be better visualized using a Perf timechart.
-The following diagram shows the behavior of kernel thread
-kidle_inject/cpu. During idle injection, it runs monitor/mwait idle
-for a given "duration", then relinquishes the CPU to other tasks,
-until the next time interval.
-
-The NOHZ schedule tick is disabled during idle time, but interrupts
-are not masked. Tests show that the extra wakeups from scheduler tick
-have a dramatic impact on the effectiveness of the powerclamp driver
-on large scale systems (Westmere system with 80 processors).
-
-CPU0
-                 ____________          ____________
-kidle_inject/0   |   sleep    |  mwait |  sleep     |
-       _________|            |________|            |_______
-                              duration
-CPU1
-                 ____________          ____________
-kidle_inject/1   |   sleep    |  mwait |  sleep     |
-       _________|            |________|            |_______
-                             ^
-                             |
-                             |
-                             roundup(jiffies, interval)
-
-Only one CPU is allowed to collect statistics and update global
-control parameters. This CPU is referred to as the controlling CPU in
-this document. The controlling CPU is elected at runtime, with a
-policy that favors BSP, taking into account the possibility of a CPU
-hot-plug.
-
-In terms of dynamics of the idle control system, package level idle
-time is considered largely as a non-causal system where its behavior
-cannot be based on the past or current input. Therefore, the
-intel_powerclamp driver attempts to enforce the desired idle time
-instantly as given input (target idle ratio). After injection,
-powerclamp monitors the actual idle for a given time window and adjust
-the next injection accordingly to avoid over/under correction.
-
-When used in a causal control system, such as a temperature control,
-it is up to the user of this driver to implement algorithms where
-past samples and outputs are included in the feedback. For example, a
-PID-based thermal controller can use the powerclamp driver to
-maintain a desired target temperature, based on integral and
-derivative gains of the past samples.
-
-
-
-Calibration
------------
-During scalability testing, it is observed that synchronized actions
-among CPUs become challenging as the number of cores grows. This is
-also true for the ability of a system to enter package level C-states.
-
-To make sure the intel_powerclamp driver scales well, online
-calibration is implemented. The goals for doing such a calibration
-are:
-
-a) determine the effective range of idle injection ratio
-b) determine the amount of compensation needed at each target ratio
-
-Compensation to each target ratio consists of two parts:
-
-        a) steady state error compensation
-       This is to offset the error occurring when the system can
-       enter idle without extra wakeups (such as external interrupts).
-
-       b) dynamic error compensation
-       When an excessive amount of wakeups occurs during idle, an
-       additional idle ratio can be added to quiet interrupts, by
-       slowing down CPU activities.
-
-A debugfs file is provided for the user to examine compensation
-progress and results, such as on a Westmere system.
-[jacob@nex01 ~]$ cat
-/sys/kernel/debug/intel_powerclamp/powerclamp_calib
-controlling cpu: 0
-pct confidence steady dynamic (compensation)
-0      0       0       0
-1      1       0       0
-2      1       1       0
-3      3       1       0
-4      3       1       0
-5      3       1       0
-6      3       1       0
-7      3       1       0
-8      3       1       0
-...
-30     3       2       0
-31     3       2       0
-32     3       1       0
-33     3       2       0
-34     3       1       0
-35     3       2       0
-36     3       1       0
-37     3       2       0
-38     3       1       0
-39     3       2       0
-40     3       3       0
-41     3       1       0
-42     3       2       0
-43     3       1       0
-44     3       1       0
-45     3       2       0
-46     3       3       0
-47     3       0       0
-48     3       2       0
-49     3       3       0
-
-Calibration occurs during runtime. No offline method is available.
-Steady state compensation is used only when confidence levels of all
-adjacent ratios have reached satisfactory level. A confidence level
-is accumulated based on clean data collected at runtime. Data
-collected during a period without extra interrupts is considered
-clean.
-
-To compensate for excessive amounts of wakeup during idle, additional
-idle time is injected when such a condition is detected. Currently,
-we have a simple algorithm to double the injection ratio. A possible
-enhancement might be to throttle the offending IRQ, such as delaying
-EOI for level triggered interrupts. But it is a challenge to be
-non-intrusive to the scheduler or the IRQ core code.
-
-
-CPU Online/Offline
-------------------
-Per-CPU kernel threads are started/stopped upon receiving
-notifications of CPU hotplug activities. The intel_powerclamp driver
-keeps track of clamping kernel threads, even after they are migrated
-to other CPUs, after a CPU offline event.
-
-
-=====================
-Performance Analysis
-=====================
-This section describes the general performance data collected on
-multiple systems, including Westmere (80P) and Ivy Bridge (4P, 8P).
-
-Effectiveness and Limitations
------------------------------
-The maximum range that idle injection is allowed is capped at 50
-percent. As mentioned earlier, since interrupts are allowed during
-forced idle time, excessive interrupts could result in less
-effectiveness. The extreme case would be doing a ping -f to generated
-flooded network interrupts without much CPU acknowledgement. In this
-case, little can be done from the idle injection threads. In most
-normal cases, such as scp a large file, applications can be throttled
-by the powerclamp driver, since slowing down the CPU also slows down
-network protocol processing, which in turn reduces interrupts.
-
-When control parameters change at runtime by the controlling CPU, it
-may take an additional period for the rest of the CPUs to catch up
-with the changes. During this time, idle injection is out of sync,
-thus not able to enter package C- states at the expected ratio. But
-this effect is minor, in that in most cases change to the target
-ratio is updated much less frequently than the idle injection
-frequency.
-
-Scalability
------------
-Tests also show a minor, but measurable, difference between the 4P/8P
-Ivy Bridge system and the 80P Westmere server under 50% idle ratio.
-More compensation is needed on Westmere for the same amount of
-target idle ratio. The compensation also increases as the idle ratio
-gets larger. The above reason constitutes the need for the
-calibration code.
-
-On the IVB 8P system, compared to an offline CPU, powerclamp can
-achieve up to 40% better performance per watt. (measured by a spin
-counter summed over per CPU counting threads spawned for all running
-CPUs).
-
-====================
-Usage and Interfaces
-====================
-The powerclamp driver is registered to the generic thermal layer as a
-cooling device. Currently, it’s not bound to any thermal zones.
-
-jacob@chromoly:/sys/class/thermal/cooling_device14$ grep . *
-cur_state:0
-max_state:50
-type:intel_powerclamp
-
-cur_state allows user to set the desired idle percentage. Writing 0 to
-cur_state will stop idle injection. Writing a value between 1 and
-max_state will start the idle injection. Reading cur_state returns the
-actual and current idle percentage. This may not be the same value
-set by the user in that current idle percentage depends on workload
-and includes natural idle. When idle injection is disabled, reading
-cur_state returns value -1 instead of 0 which is to avoid confusing
-100% busy state with the disabled state.
-
-Example usage:
-- To inject 25% idle time
-$ sudo sh -c "echo 25 > /sys/class/thermal/cooling_device80/cur_state
-"
-
-If the system is not busy and has more than 25% idle time already,
-then the powerclamp driver will not start idle injection. Using Top
-will not show idle injection kernel threads.
-
-If the system is busy (spin test below) and has less than 25% natural
-idle time, powerclamp kernel threads will do idle injection. Forced
-idle time is accounted as normal idle in that common code path is
-taken as the idle task.
-
-In this example, 24.1% idle is shown. This helps the system admin or
-user determine the cause of slowdown, when a powerclamp driver is in action.
-
-
-Tasks: 197 total,   1 running, 196 sleeping,   0 stopped,   0 zombie
-Cpu(s): 71.2%us,  4.7%sy,  0.0%ni, 24.1%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
-Mem:   3943228k total,  1689632k used,  2253596k free,    74960k buffers
-Swap:  4087804k total,        0k used,  4087804k free,   945336k cached
-
-  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
- 3352 jacob     20   0  262m  644  428 S  286  0.0   0:17.16 spin
- 3341 root     -51   0     0    0    0 D   25  0.0   0:01.62 kidle_inject/0
- 3344 root     -51   0     0    0    0 D   25  0.0   0:01.60 kidle_inject/3
- 3342 root     -51   0     0    0    0 D   25  0.0   0:01.61 kidle_inject/1
- 3343 root     -51   0     0    0    0 D   25  0.0   0:01.60 kidle_inject/2
- 2935 jacob     20   0  696m 125m  35m S    5  3.3   0:31.11 firefox
- 1546 root      20   0  158m  20m 6640 S    3  0.5   0:26.97 Xorg
- 2100 jacob     20   0 1223m  88m  30m S    3  2.3   0:23.68 compiz
-
-Tests have shown that by using the powerclamp driver as a cooling
-device, a PID based userspace thermal controller can manage to
-control CPU temperature effectively, when no other thermal influence
-is added. For example, a UltraBook user can compile the kernel under
-certain temperature (below most active trip points).
diff --git a/Documentation/thermal/nouveau_thermal b/Documentation/thermal/nouveau_thermal
deleted file mode 100644 (file)
index 6e17a11..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-Kernel driver nouveau
-===================
-
-Supported chips:
-* NV43+
-
-Authors: Martin Peres (mupuf) <martin.peres@free.fr>
-
-Description
----------
-
-This driver allows to read the GPU core temperature, drive the GPU fan and
-set temperature alarms.
-
-Currently, due to the absence of in-kernel API to access HWMON drivers, Nouveau
-cannot access any of the i2c external monitoring chips it may find. If you
-have one of those, temperature and/or fan management through Nouveau's HWMON
-interface is likely not to work. This document may then not cover your situation
-entirely.
-
-Temperature management
---------------------
-
-Temperature is exposed under as a read-only HWMON attribute temp1_input.
-
-In order to protect the GPU from overheating, Nouveau supports 4 configurable
-temperature thresholds:
-
- * Fan_boost: Fan speed is set to 100% when reaching this temperature;
- * Downclock: The GPU will be downclocked to reduce its power dissipation;
- * Critical: The GPU is put on hold to further lower power dissipation;
- * Shutdown: Shut the computer down to protect your GPU.
-
-WARNING: Some of these thresholds may not be used by Nouveau depending
-on your chipset.
-
-The default value for these thresholds comes from the GPU's vbios. These
-thresholds can be configured thanks to the following HWMON attributes:
-
- * Fan_boost: temp1_auto_point1_temp and temp1_auto_point1_temp_hyst;
- * Downclock: temp1_max and temp1_max_hyst;
- * Critical: temp1_crit and temp1_crit_hyst;
- * Shutdown: temp1_emergency and temp1_emergency_hyst.
-
-NOTE: Remember that the values are stored as milli degrees Celsius. Don't forget
-to multiply!
-
-Fan management
-------------
-
-Not all cards have a drivable fan. If you do, then the following HWMON
-attributes should be available:
-
- * pwm1_enable: Current fan management mode (NONE, MANUAL or AUTO);
- * pwm1: Current PWM value (power percentage);
- * pwm1_min: The minimum PWM speed allowed;
- * pwm1_max: The maximum PWM speed allowed (bypassed when hitting Fan_boost);
-
-You may also have the following attribute:
-
- * fan1_input: Speed in RPM of your fan.
-
-Your fan can be driven in different modes:
-
- * 0: The fan is left untouched;
- * 1: The fan can be driven in manual (use pwm1 to change the speed);
- * 2; The fan is driven automatically depending on the temperature.
-
-NOTE: Be sure to use the manual mode if you want to drive the fan speed manually
-
-NOTE2: When operating in manual mode outside the vbios-defined
-[PWM_min, PWM_max] range, the reported fan speed (RPM) may not be accurate
-depending on your hardware.
-
-Bug reports
----------
-
-Thermal management on Nouveau is new and may not work on all cards. If you have
-inquiries, please ping mupuf on IRC (#nouveau, freenode).
-
-Bug reports should be filled on Freedesktop's bug tracker. Please follow
-http://nouveau.freedesktop.org/wiki/Bugs
diff --git a/Documentation/thermal/nouveau_thermal.rst b/Documentation/thermal/nouveau_thermal.rst
new file mode 100644 (file)
index 0000000..37255fd
--- /dev/null
@@ -0,0 +1,96 @@
+=====================
+Kernel driver nouveau
+=====================
+
+Supported chips:
+
+* NV43+
+
+Authors: Martin Peres (mupuf) <martin.peres@free.fr>
+
+Description
+-----------
+
+This driver allows to read the GPU core temperature, drive the GPU fan and
+set temperature alarms.
+
+Currently, due to the absence of in-kernel API to access HWMON drivers, Nouveau
+cannot access any of the i2c external monitoring chips it may find. If you
+have one of those, temperature and/or fan management through Nouveau's HWMON
+interface is likely not to work. This document may then not cover your situation
+entirely.
+
+Temperature management
+----------------------
+
+Temperature is exposed under as a read-only HWMON attribute temp1_input.
+
+In order to protect the GPU from overheating, Nouveau supports 4 configurable
+temperature thresholds:
+
+ * Fan_boost:
+       Fan speed is set to 100% when reaching this temperature;
+ * Downclock:
+       The GPU will be downclocked to reduce its power dissipation;
+ * Critical:
+       The GPU is put on hold to further lower power dissipation;
+ * Shutdown:
+       Shut the computer down to protect your GPU.
+
+WARNING:
+       Some of these thresholds may not be used by Nouveau depending
+       on your chipset.
+
+The default value for these thresholds comes from the GPU's vbios. These
+thresholds can be configured thanks to the following HWMON attributes:
+
+ * Fan_boost: temp1_auto_point1_temp and temp1_auto_point1_temp_hyst;
+ * Downclock: temp1_max and temp1_max_hyst;
+ * Critical: temp1_crit and temp1_crit_hyst;
+ * Shutdown: temp1_emergency and temp1_emergency_hyst.
+
+NOTE: Remember that the values are stored as milli degrees Celsius. Don't forget
+to multiply!
+
+Fan management
+--------------
+
+Not all cards have a drivable fan. If you do, then the following HWMON
+attributes should be available:
+
+ * pwm1_enable:
+       Current fan management mode (NONE, MANUAL or AUTO);
+ * pwm1:
+       Current PWM value (power percentage);
+ * pwm1_min:
+       The minimum PWM speed allowed;
+ * pwm1_max:
+       The maximum PWM speed allowed (bypassed when hitting Fan_boost);
+
+You may also have the following attribute:
+
+ * fan1_input:
+       Speed in RPM of your fan.
+
+Your fan can be driven in different modes:
+
+ * 0: The fan is left untouched;
+ * 1: The fan can be driven in manual (use pwm1 to change the speed);
+ * 2; The fan is driven automatically depending on the temperature.
+
+NOTE:
+  Be sure to use the manual mode if you want to drive the fan speed manually
+
+NOTE2:
+  When operating in manual mode outside the vbios-defined
+  [PWM_min, PWM_max] range, the reported fan speed (RPM) may not be accurate
+  depending on your hardware.
+
+Bug reports
+-----------
+
+Thermal management on Nouveau is new and may not work on all cards. If you have
+inquiries, please ping mupuf on IRC (#nouveau, freenode).
+
+Bug reports should be filled on Freedesktop's bug tracker. Please follow
+http://nouveau.freedesktop.org/wiki/Bugs
diff --git a/Documentation/thermal/power_allocator.rst b/Documentation/thermal/power_allocator.rst
new file mode 100644 (file)
index 0000000..67b6a32
--- /dev/null
@@ -0,0 +1,271 @@
+=================================
+Power allocator governor tunables
+=================================
+
+Trip points
+-----------
+
+The governor works optimally with the following two passive trip points:
+
+1.  "switch on" trip point: temperature above which the governor
+    control loop starts operating.  This is the first passive trip
+    point of the thermal zone.
+
+2.  "desired temperature" trip point: it should be higher than the
+    "switch on" trip point.  This the target temperature the governor
+    is controlling for.  This is the last passive trip point of the
+    thermal zone.
+
+PID Controller
+--------------
+
+The power allocator governor implements a
+Proportional-Integral-Derivative controller (PID controller) with
+temperature as the control input and power as the controlled output:
+
+    P_max = k_p * e + k_i * err_integral + k_d * diff_err + sustainable_power
+
+where
+   -  e = desired_temperature - current_temperature
+   -  err_integral is the sum of previous errors
+   -  diff_err = e - previous_error
+
+It is similar to the one depicted below::
+
+                                     k_d
+                                      |
+  current_temp                         |
+       |                               v
+       |              +----------+   +---+
+       |       +----->| diff_err |-->| X |------+
+       |       |      +----------+   +---+      |
+       |       |                                |      tdp        actor
+       |       |                      k_i       |       |  get_requested_power()
+       |       |                       |        |       |        |     |
+       |       |                       |        |       |        |     | ...
+       v       |                       v        v       v        v     v
+     +---+     |      +-------+      +---+    +---+   +---+   +----------+
+     | S |-----+----->| sum e |----->| X |--->| S |-->| S |-->|power     |
+     +---+     |      +-------+      +---+    +---+   +---+   |allocation|
+       ^       |                                ^             +----------+
+       |       |                                |                |     |
+       |       |        +---+                   |                |     |
+       |       +------->| X |-------------------+                v     v
+       |                +---+                               granted performance
+  desired_temperature     ^
+                         |
+                         |
+                     k_po/k_pu
+
+Sustainable power
+-----------------
+
+An estimate of the sustainable dissipatable power (in mW) should be
+provided while registering the thermal zone.  This estimates the
+sustained power that can be dissipated at the desired control
+temperature.  This is the maximum sustained power for allocation at
+the desired maximum temperature.  The actual sustained power can vary
+for a number of reasons.  The closed loop controller will take care of
+variations such as environmental conditions, and some factors related
+to the speed-grade of the silicon.  `sustainable_power` is therefore
+simply an estimate, and may be tuned to affect the aggressiveness of
+the thermal ramp. For reference, the sustainable power of a 4" phone
+is typically 2000mW, while on a 10" tablet is around 4500mW (may vary
+depending on screen size).
+
+If you are using device tree, do add it as a property of the
+thermal-zone.  For example::
+
+       thermal-zones {
+               soc_thermal {
+                       polling-delay = <1000>;
+                       polling-delay-passive = <100>;
+                       sustainable-power = <2500>;
+                       ...
+
+Instead, if the thermal zone is registered from the platform code, pass a
+`thermal_zone_params` that has a `sustainable_power`.  If no
+`thermal_zone_params` were being passed, then something like below
+will suffice::
+
+       static const struct thermal_zone_params tz_params = {
+               .sustainable_power = 3500,
+       };
+
+and then pass `tz_params` as the 5th parameter to
+`thermal_zone_device_register()`
+
+k_po and k_pu
+-------------
+
+The implementation of the PID controller in the power allocator
+thermal governor allows the configuration of two proportional term
+constants: `k_po` and `k_pu`.  `k_po` is the proportional term
+constant during temperature overshoot periods (current temperature is
+above "desired temperature" trip point).  Conversely, `k_pu` is the
+proportional term constant during temperature undershoot periods
+(current temperature below "desired temperature" trip point).
+
+These controls are intended as the primary mechanism for configuring
+the permitted thermal "ramp" of the system.  For instance, a lower
+`k_pu` value will provide a slower ramp, at the cost of capping
+available capacity at a low temperature.  On the other hand, a high
+value of `k_pu` will result in the governor granting very high power
+while temperature is low, and may lead to temperature overshooting.
+
+The default value for `k_pu` is::
+
+    2 * sustainable_power / (desired_temperature - switch_on_temp)
+
+This means that at `switch_on_temp` the output of the controller's
+proportional term will be 2 * `sustainable_power`.  The default value
+for `k_po` is::
+
+    sustainable_power / (desired_temperature - switch_on_temp)
+
+Focusing on the proportional and feed forward values of the PID
+controller equation we have::
+
+    P_max = k_p * e + sustainable_power
+
+The proportional term is proportional to the difference between the
+desired temperature and the current one.  When the current temperature
+is the desired one, then the proportional component is zero and
+`P_max` = `sustainable_power`.  That is, the system should operate in
+thermal equilibrium under constant load.  `sustainable_power` is only
+an estimate, which is the reason for closed-loop control such as this.
+
+Expanding `k_pu` we get::
+
+    P_max = 2 * sustainable_power * (T_set - T) / (T_set - T_on) +
+       sustainable_power
+
+where:
+
+    - T_set is the desired temperature
+    - T is the current temperature
+    - T_on is the switch on temperature
+
+When the current temperature is the switch_on temperature, the above
+formula becomes::
+
+    P_max = 2 * sustainable_power * (T_set - T_on) / (T_set - T_on) +
+       sustainable_power = 2 * sustainable_power + sustainable_power =
+       3 * sustainable_power
+
+Therefore, the proportional term alone linearly decreases power from
+3 * `sustainable_power` to `sustainable_power` as the temperature
+rises from the switch on temperature to the desired temperature.
+
+k_i and integral_cutoff
+-----------------------
+
+`k_i` configures the PID loop's integral term constant.  This term
+allows the PID controller to compensate for long term drift and for
+the quantized nature of the output control: cooling devices can't set
+the exact power that the governor requests.  When the temperature
+error is below `integral_cutoff`, errors are accumulated in the
+integral term.  This term is then multiplied by `k_i` and the result
+added to the output of the controller.  Typically `k_i` is set low (1
+or 2) and `integral_cutoff` is 0.
+
+k_d
+---
+
+`k_d` configures the PID loop's derivative term constant.  It's
+recommended to leave it as the default: 0.
+
+Cooling device power API
+========================
+
+Cooling devices controlled by this governor must supply the additional
+"power" API in their `cooling_device_ops`.  It consists on three ops:
+
+1. ::
+
+    int get_requested_power(struct thermal_cooling_device *cdev,
+                           struct thermal_zone_device *tz, u32 *power);
+
+
+@cdev:
+       The `struct thermal_cooling_device` pointer
+@tz:
+       thermal zone in which we are currently operating
+@power:
+       pointer in which to store the calculated power
+
+`get_requested_power()` calculates the power requested by the device
+in milliwatts and stores it in @power .  It should return 0 on
+success, -E* on failure.  This is currently used by the power
+allocator governor to calculate how much power to give to each cooling
+device.
+
+2. ::
+
+       int state2power(struct thermal_cooling_device *cdev, struct
+                       thermal_zone_device *tz, unsigned long state,
+                       u32 *power);
+
+@cdev:
+       The `struct thermal_cooling_device` pointer
+@tz:
+       thermal zone in which we are currently operating
+@state:
+       A cooling device state
+@power:
+       pointer in which to store the equivalent power
+
+Convert cooling device state @state into power consumption in
+milliwatts and store it in @power.  It should return 0 on success, -E*
+on failure.  This is currently used by thermal core to calculate the
+maximum power that an actor can consume.
+
+3. ::
+
+       int power2state(struct thermal_cooling_device *cdev, u32 power,
+                       unsigned long *state);
+
+@cdev:
+       The `struct thermal_cooling_device` pointer
+@power:
+       power in milliwatts
+@state:
+       pointer in which to store the resulting state
+
+Calculate a cooling device state that would make the device consume at
+most @power mW and store it in @state.  It should return 0 on success,
+-E* on failure.  This is currently used by the thermal core to convert
+a given power set by the power allocator governor to a state that the
+cooling device can set.  It is a function because this conversion may
+depend on external factors that may change so this function should the
+best conversion given "current circumstances".
+
+Cooling device weights
+----------------------
+
+Weights are a mechanism to bias the allocation among cooling
+devices.  They express the relative power efficiency of different
+cooling devices.  Higher weight can be used to express higher power
+efficiency.  Weighting is relative such that if each cooling device
+has a weight of one they are considered equal.  This is particularly
+useful in heterogeneous systems where two cooling devices may perform
+the same kind of compute, but with different efficiency.  For example,
+a system with two different types of processors.
+
+If the thermal zone is registered using
+`thermal_zone_device_register()` (i.e., platform code), then weights
+are passed as part of the thermal zone's `thermal_bind_parameters`.
+If the platform is registered using device tree, then they are passed
+as the `contribution` property of each map in the `cooling-maps` node.
+
+Limitations of the power allocator governor
+===========================================
+
+The power allocator governor's PID controller works best if there is a
+periodic tick.  If you have a driver that calls
+`thermal_zone_device_update()` (or anything that ends up calling the
+governor's `throttle()` function) repetitively, the governor response
+won't be very good.  Note that this is not particular to this
+governor, step-wise will also misbehave if you call its throttle()
+faster than the normal thermal framework tick (due to interrupts for
+example) as it will overreact.
diff --git a/Documentation/thermal/power_allocator.txt b/Documentation/thermal/power_allocator.txt
deleted file mode 100644 (file)
index 9fb0ff0..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-Power allocator governor tunables
-=================================
-
-Trip points
------------
-
-The governor works optimally with the following two passive trip points:
-
-1.  "switch on" trip point: temperature above which the governor
-    control loop starts operating.  This is the first passive trip
-    point of the thermal zone.
-
-2.  "desired temperature" trip point: it should be higher than the
-    "switch on" trip point.  This the target temperature the governor
-    is controlling for.  This is the last passive trip point of the
-    thermal zone.
-
-PID Controller
---------------
-
-The power allocator governor implements a
-Proportional-Integral-Derivative controller (PID controller) with
-temperature as the control input and power as the controlled output:
-
-    P_max = k_p * e + k_i * err_integral + k_d * diff_err + sustainable_power
-
-where
-    e = desired_temperature - current_temperature
-    err_integral is the sum of previous errors
-    diff_err = e - previous_error
-
-It is similar to the one depicted below:
-
-                                      k_d
-                                       |
-current_temp                           |
-     |                                 v
-     |                +----------+   +---+
-     |         +----->| diff_err |-->| X |------+
-     |         |      +----------+   +---+      |
-     |         |                                |      tdp        actor
-     |         |                      k_i       |       |  get_requested_power()
-     |         |                       |        |       |        |     |
-     |         |                       |        |       |        |     | ...
-     v         |                       v        v       v        v     v
-   +---+       |      +-------+      +---+    +---+   +---+   +----------+
-   | S |-------+----->| sum e |----->| X |--->| S |-->| S |-->|power     |
-   +---+       |      +-------+      +---+    +---+   +---+   |allocation|
-     ^         |                                ^             +----------+
-     |         |                                |                |     |
-     |         |        +---+                   |                |     |
-     |         +------->| X |-------------------+                v     v
-     |                  +---+                               granted performance
-desired_temperature       ^
-                          |
-                          |
-                      k_po/k_pu
-
-Sustainable power
------------------
-
-An estimate of the sustainable dissipatable power (in mW) should be
-provided while registering the thermal zone.  This estimates the
-sustained power that can be dissipated at the desired control
-temperature.  This is the maximum sustained power for allocation at
-the desired maximum temperature.  The actual sustained power can vary
-for a number of reasons.  The closed loop controller will take care of
-variations such as environmental conditions, and some factors related
-to the speed-grade of the silicon.  `sustainable_power` is therefore
-simply an estimate, and may be tuned to affect the aggressiveness of
-the thermal ramp. For reference, the sustainable power of a 4" phone
-is typically 2000mW, while on a 10" tablet is around 4500mW (may vary
-depending on screen size).
-
-If you are using device tree, do add it as a property of the
-thermal-zone.  For example:
-
-       thermal-zones {
-               soc_thermal {
-                       polling-delay = <1000>;
-                       polling-delay-passive = <100>;
-                       sustainable-power = <2500>;
-                       ...
-
-Instead, if the thermal zone is registered from the platform code, pass a
-`thermal_zone_params` that has a `sustainable_power`.  If no
-`thermal_zone_params` were being passed, then something like below
-will suffice:
-
-       static const struct thermal_zone_params tz_params = {
-               .sustainable_power = 3500,
-       };
-
-and then pass `tz_params` as the 5th parameter to
-`thermal_zone_device_register()`
-
-k_po and k_pu
--------------
-
-The implementation of the PID controller in the power allocator
-thermal governor allows the configuration of two proportional term
-constants: `k_po` and `k_pu`.  `k_po` is the proportional term
-constant during temperature overshoot periods (current temperature is
-above "desired temperature" trip point).  Conversely, `k_pu` is the
-proportional term constant during temperature undershoot periods
-(current temperature below "desired temperature" trip point).
-
-These controls are intended as the primary mechanism for configuring
-the permitted thermal "ramp" of the system.  For instance, a lower
-`k_pu` value will provide a slower ramp, at the cost of capping
-available capacity at a low temperature.  On the other hand, a high
-value of `k_pu` will result in the governor granting very high power
-while temperature is low, and may lead to temperature overshooting.
-
-The default value for `k_pu` is:
-
-    2 * sustainable_power / (desired_temperature - switch_on_temp)
-
-This means that at `switch_on_temp` the output of the controller's
-proportional term will be 2 * `sustainable_power`.  The default value
-for `k_po` is:
-
-    sustainable_power / (desired_temperature - switch_on_temp)
-
-Focusing on the proportional and feed forward values of the PID
-controller equation we have:
-
-    P_max = k_p * e + sustainable_power
-
-The proportional term is proportional to the difference between the
-desired temperature and the current one.  When the current temperature
-is the desired one, then the proportional component is zero and
-`P_max` = `sustainable_power`.  That is, the system should operate in
-thermal equilibrium under constant load.  `sustainable_power` is only
-an estimate, which is the reason for closed-loop control such as this.
-
-Expanding `k_pu` we get:
-    P_max = 2 * sustainable_power * (T_set - T) / (T_set - T_on) +
-        sustainable_power
-
-where
-    T_set is the desired temperature
-    T is the current temperature
-    T_on is the switch on temperature
-
-When the current temperature is the switch_on temperature, the above
-formula becomes:
-
-    P_max = 2 * sustainable_power * (T_set - T_on) / (T_set - T_on) +
-        sustainable_power = 2 * sustainable_power + sustainable_power =
-        3 * sustainable_power
-
-Therefore, the proportional term alone linearly decreases power from
-3 * `sustainable_power` to `sustainable_power` as the temperature
-rises from the switch on temperature to the desired temperature.
-
-k_i and integral_cutoff
------------------------
-
-`k_i` configures the PID loop's integral term constant.  This term
-allows the PID controller to compensate for long term drift and for
-the quantized nature of the output control: cooling devices can't set
-the exact power that the governor requests.  When the temperature
-error is below `integral_cutoff`, errors are accumulated in the
-integral term.  This term is then multiplied by `k_i` and the result
-added to the output of the controller.  Typically `k_i` is set low (1
-or 2) and `integral_cutoff` is 0.
-
-k_d
----
-
-`k_d` configures the PID loop's derivative term constant.  It's
-recommended to leave it as the default: 0.
-
-Cooling device power API
-========================
-
-Cooling devices controlled by this governor must supply the additional
-"power" API in their `cooling_device_ops`.  It consists on three ops:
-
-1. int get_requested_power(struct thermal_cooling_device *cdev,
-       struct thermal_zone_device *tz, u32 *power);
-@cdev: The `struct thermal_cooling_device` pointer
-@tz: thermal zone in which we are currently operating
-@power: pointer in which to store the calculated power
-
-`get_requested_power()` calculates the power requested by the device
-in milliwatts and stores it in @power .  It should return 0 on
-success, -E* on failure.  This is currently used by the power
-allocator governor to calculate how much power to give to each cooling
-device.
-
-2. int state2power(struct thermal_cooling_device *cdev, struct
-        thermal_zone_device *tz, unsigned long state, u32 *power);
-@cdev: The `struct thermal_cooling_device` pointer
-@tz: thermal zone in which we are currently operating
-@state: A cooling device state
-@power: pointer in which to store the equivalent power
-
-Convert cooling device state @state into power consumption in
-milliwatts and store it in @power.  It should return 0 on success, -E*
-on failure.  This is currently used by thermal core to calculate the
-maximum power that an actor can consume.
-
-3. int power2state(struct thermal_cooling_device *cdev, u32 power,
-       unsigned long *state);
-@cdev: The `struct thermal_cooling_device` pointer
-@power: power in milliwatts
-@state: pointer in which to store the resulting state
-
-Calculate a cooling device state that would make the device consume at
-most @power mW and store it in @state.  It should return 0 on success,
--E* on failure.  This is currently used by the thermal core to convert
-a given power set by the power allocator governor to a state that the
-cooling device can set.  It is a function because this conversion may
-depend on external factors that may change so this function should the
-best conversion given "current circumstances".
-
-Cooling device weights
-----------------------
-
-Weights are a mechanism to bias the allocation among cooling
-devices.  They express the relative power efficiency of different
-cooling devices.  Higher weight can be used to express higher power
-efficiency.  Weighting is relative such that if each cooling device
-has a weight of one they are considered equal.  This is particularly
-useful in heterogeneous systems where two cooling devices may perform
-the same kind of compute, but with different efficiency.  For example,
-a system with two different types of processors.
-
-If the thermal zone is registered using
-`thermal_zone_device_register()` (i.e., platform code), then weights
-are passed as part of the thermal zone's `thermal_bind_parameters`.
-If the platform is registered using device tree, then they are passed
-as the `contribution` property of each map in the `cooling-maps` node.
-
-Limitations of the power allocator governor
-===========================================
-
-The power allocator governor's PID controller works best if there is a
-periodic tick.  If you have a driver that calls
-`thermal_zone_device_update()` (or anything that ends up calling the
-governor's `throttle()` function) repetitively, the governor response
-won't be very good.  Note that this is not particular to this
-governor, step-wise will also misbehave if you call its throttle()
-faster than the normal thermal framework tick (due to interrupts for
-example) as it will overreact.
diff --git a/Documentation/thermal/sysfs-api.rst b/Documentation/thermal/sysfs-api.rst
new file mode 100644 (file)
index 0000000..e493076
--- /dev/null
@@ -0,0 +1,798 @@
+===================================
+Generic Thermal Sysfs driver How To
+===================================
+
+Written by Sujith Thomas <sujith.thomas@intel.com>, Zhang Rui <rui.zhang@intel.com>
+
+Updated: 2 January 2008
+
+Copyright (c)  2008 Intel Corporation
+
+
+0. Introduction
+===============
+
+The generic thermal sysfs provides a set of interfaces for thermal zone
+devices (sensors) and thermal cooling devices (fan, processor...) to register
+with the thermal management solution and to be a part of it.
+
+This how-to focuses on enabling new thermal zone and cooling devices to
+participate in thermal management.
+This solution is platform independent and any type of thermal zone devices
+and cooling devices should be able to make use of the infrastructure.
+
+The main task of the thermal sysfs driver is to expose thermal zone attributes
+as well as cooling device attributes to the user space.
+An intelligent thermal management application can make decisions based on
+inputs from thermal zone attributes (the current temperature and trip point
+temperature) and throttle appropriate devices.
+
+- `[0-*]`      denotes any positive number starting from 0
+- `[1-*]`      denotes any positive number starting from 1
+
+1. thermal sysfs driver interface functions
+===========================================
+
+1.1 thermal zone device interface
+---------------------------------
+
+    ::
+
+       struct thermal_zone_device
+       *thermal_zone_device_register(char *type,
+                                     int trips, int mask, void *devdata,
+                                     struct thermal_zone_device_ops *ops,
+                                     const struct thermal_zone_params *tzp,
+                                     int passive_delay, int polling_delay))
+
+    This interface function adds a new thermal zone device (sensor) to
+    /sys/class/thermal folder as `thermal_zone[0-*]`. It tries to bind all the
+    thermal cooling devices registered at the same time.
+
+    type:
+       the thermal zone type.
+    trips:
+       the total number of trip points this thermal zone supports.
+    mask:
+       Bit string: If 'n'th bit is set, then trip point 'n' is writeable.
+    devdata:
+       device private data
+    ops:
+       thermal zone device call-backs.
+
+       .bind:
+               bind the thermal zone device with a thermal cooling device.
+       .unbind:
+               unbind the thermal zone device with a thermal cooling device.
+       .get_temp:
+               get the current temperature of the thermal zone.
+       .set_trips:
+                   set the trip points window. Whenever the current temperature
+                   is updated, the trip points immediately below and above the
+                   current temperature are found.
+       .get_mode:
+                  get the current mode (enabled/disabled) of the thermal zone.
+
+                       - "enabled" means the kernel thermal management is
+                         enabled.
+                       - "disabled" will prevent kernel thermal driver action
+                         upon trip points so that user applications can take
+                         charge of thermal management.
+       .set_mode:
+               set the mode (enabled/disabled) of the thermal zone.
+       .get_trip_type:
+               get the type of certain trip point.
+       .get_trip_temp:
+                       get the temperature above which the certain trip point
+                       will be fired.
+       .set_emul_temp:
+                       set the emulation temperature which helps in debugging
+                       different threshold temperature points.
+    tzp:
+       thermal zone platform parameters.
+    passive_delay:
+       number of milliseconds to wait between polls when
+       performing passive cooling.
+    polling_delay:
+       number of milliseconds to wait between polls when checking
+       whether trip points have been crossed (0 for interrupt driven systems).
+
+    ::
+
+       void thermal_zone_device_unregister(struct thermal_zone_device *tz)
+
+    This interface function removes the thermal zone device.
+    It deletes the corresponding entry from /sys/class/thermal folder and
+    unbinds all the thermal cooling devices it uses.
+
+       ::
+
+          struct thermal_zone_device
+          *thermal_zone_of_sensor_register(struct device *dev, int sensor_id,
+                               void *data,
+                               const struct thermal_zone_of_device_ops *ops)
+
+       This interface adds a new sensor to a DT thermal zone.
+       This function will search the list of thermal zones described in
+       device tree and look for the zone that refer to the sensor device
+       pointed by dev->of_node as temperature providers. For the zone
+       pointing to the sensor node, the sensor will be added to the DT
+       thermal zone device.
+
+       The parameters for this interface are:
+
+       dev:
+                       Device node of sensor containing valid node pointer in
+                       dev->of_node.
+       sensor_id:
+                       a sensor identifier, in case the sensor IP has more
+                       than one sensors
+       data:
+                       a private pointer (owned by the caller) that will be
+                       passed back, when a temperature reading is needed.
+       ops:
+                       `struct thermal_zone_of_device_ops *`.
+
+                       ==============  =======================================
+                       get_temp        a pointer to a function that reads the
+                                       sensor temperature. This is mandatory
+                                       callback provided by sensor driver.
+                       set_trips       a pointer to a function that sets a
+                                       temperature window. When this window is
+                                       left the driver must inform the thermal
+                                       core via thermal_zone_device_update.
+                       get_trend       a pointer to a function that reads the
+                                       sensor temperature trend.
+                       set_emul_temp   a pointer to a function that sets
+                                       sensor emulated temperature.
+                       ==============  =======================================
+
+       The thermal zone temperature is provided by the get_temp() function
+       pointer of thermal_zone_of_device_ops. When called, it will
+       have the private pointer @data back.
+
+       It returns error pointer if fails otherwise valid thermal zone device
+       handle. Caller should check the return handle with IS_ERR() for finding
+       whether success or not.
+
+       ::
+
+           void thermal_zone_of_sensor_unregister(struct device *dev,
+                                                  struct thermal_zone_device *tzd)
+
+       This interface unregisters a sensor from a DT thermal zone which was
+       successfully added by interface thermal_zone_of_sensor_register().
+       This function removes the sensor callbacks and private data from the
+       thermal zone device registered with thermal_zone_of_sensor_register()
+       interface. It will also silent the zone by remove the .get_temp() and
+       get_trend() thermal zone device callbacks.
+
+       ::
+
+         struct thermal_zone_device
+         *devm_thermal_zone_of_sensor_register(struct device *dev,
+                               int sensor_id,
+                               void *data,
+                               const struct thermal_zone_of_device_ops *ops)
+
+       This interface is resource managed version of
+       thermal_zone_of_sensor_register().
+
+       All details of thermal_zone_of_sensor_register() described in
+       section 1.1.3 is applicable here.
+
+       The benefit of using this interface to register sensor is that it
+       is not require to explicitly call thermal_zone_of_sensor_unregister()
+       in error path or during driver unbinding as this is done by driver
+       resource manager.
+
+       ::
+
+               void devm_thermal_zone_of_sensor_unregister(struct device *dev,
+                                               struct thermal_zone_device *tzd)
+
+       This interface is resource managed version of
+       thermal_zone_of_sensor_unregister().
+       All details of thermal_zone_of_sensor_unregister() described in
+       section 1.1.4 is applicable here.
+       Normally this function will not need to be called and the resource
+       management code will ensure that the resource is freed.
+
+       ::
+
+               int thermal_zone_get_slope(struct thermal_zone_device *tz)
+
+       This interface is used to read the slope attribute value
+       for the thermal zone device, which might be useful for platform
+       drivers for temperature calculations.
+
+       ::
+
+               int thermal_zone_get_offset(struct thermal_zone_device *tz)
+
+       This interface is used to read the offset attribute value
+       for the thermal zone device, which might be useful for platform
+       drivers for temperature calculations.
+
+1.2 thermal cooling device interface
+------------------------------------
+
+
+    ::
+
+       struct thermal_cooling_device
+       *thermal_cooling_device_register(char *name,
+                       void *devdata, struct thermal_cooling_device_ops *)
+
+    This interface function adds a new thermal cooling device (fan/processor/...)
+    to /sys/class/thermal/ folder as `cooling_device[0-*]`. It tries to bind itself
+    to all the thermal zone devices registered at the same time.
+
+    name:
+       the cooling device name.
+    devdata:
+       device private data.
+    ops:
+       thermal cooling devices call-backs.
+
+       .get_max_state:
+               get the Maximum throttle state of the cooling device.
+       .get_cur_state:
+               get the Currently requested throttle state of the
+               cooling device.
+       .set_cur_state:
+               set the Current throttle state of the cooling device.
+
+    ::
+
+       void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
+
+    This interface function removes the thermal cooling device.
+    It deletes the corresponding entry from /sys/class/thermal folder and
+    unbinds itself from all the thermal zone devices using it.
+
+1.3 interface for binding a thermal zone device with a thermal cooling device
+-----------------------------------------------------------------------------
+
+    ::
+
+       int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
+               int trip, struct thermal_cooling_device *cdev,
+               unsigned long upper, unsigned long lower, unsigned int weight);
+
+    This interface function binds a thermal cooling device to a particular trip
+    point of a thermal zone device.
+
+    This function is usually called in the thermal zone device .bind callback.
+
+    tz:
+         the thermal zone device
+    cdev:
+         thermal cooling device
+    trip:
+         indicates which trip point in this thermal zone the cooling device
+         is associated with.
+    upper:
+         the Maximum cooling state for this trip point.
+         THERMAL_NO_LIMIT means no upper limit,
+         and the cooling device can be in max_state.
+    lower:
+         the Minimum cooling state can be used for this trip point.
+         THERMAL_NO_LIMIT means no lower limit,
+         and the cooling device can be in cooling state 0.
+    weight:
+         the influence of this cooling device in this thermal
+         zone.  See 1.4.1 below for more information.
+
+    ::
+
+       int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
+                               int trip, struct thermal_cooling_device *cdev);
+
+    This interface function unbinds a thermal cooling device from a particular
+    trip point of a thermal zone device. This function is usually called in
+    the thermal zone device .unbind callback.
+
+    tz:
+       the thermal zone device
+    cdev:
+       thermal cooling device
+    trip:
+       indicates which trip point in this thermal zone the cooling device
+       is associated with.
+
+1.4 Thermal Zone Parameters
+---------------------------
+
+    ::
+
+       struct thermal_bind_params
+
+    This structure defines the following parameters that are used to bind
+    a zone with a cooling device for a particular trip point.
+
+    .cdev:
+            The cooling device pointer
+    .weight:
+            The 'influence' of a particular cooling device on this
+            zone. This is relative to the rest of the cooling
+            devices. For example, if all cooling devices have a
+            weight of 1, then they all contribute the same. You can
+            use percentages if you want, but it's not mandatory. A
+            weight of 0 means that this cooling device doesn't
+            contribute to the cooling of this zone unless all cooling
+            devices have a weight of 0. If all weights are 0, then
+            they all contribute the same.
+    .trip_mask:
+              This is a bit mask that gives the binding relation between
+              this thermal zone and cdev, for a particular trip point.
+              If nth bit is set, then the cdev and thermal zone are bound
+              for trip point n.
+    .binding_limits:
+                    This is an array of cooling state limits. Must have
+                    exactly 2 * thermal_zone.number_of_trip_points. It is an
+                    array consisting of tuples <lower-state upper-state> of
+                    state limits. Each trip will be associated with one state
+                    limit tuple when binding. A NULL pointer means
+                    <THERMAL_NO_LIMITS THERMAL_NO_LIMITS> on all trips.
+                    These limits are used when binding a cdev to a trip point.
+    .match:
+           This call back returns success(0) if the 'tz and cdev' need to
+           be bound, as per platform data.
+
+    ::
+
+       struct thermal_zone_params
+
+    This structure defines the platform level parameters for a thermal zone.
+    This data, for each thermal zone should come from the platform layer.
+    This is an optional feature where some platforms can choose not to
+    provide this data.
+
+    .governor_name:
+              Name of the thermal governor used for this zone
+    .no_hwmon:
+              a boolean to indicate if the thermal to hwmon sysfs interface
+              is required. when no_hwmon == false, a hwmon sysfs interface
+              will be created. when no_hwmon == true, nothing will be done.
+              In case the thermal_zone_params is NULL, the hwmon interface
+              will be created (for backward compatibility).
+    .num_tbps:
+              Number of thermal_bind_params entries for this zone
+    .tbp:
+              thermal_bind_params entries
+
+2. sysfs attributes structure
+=============================
+
+==     ================
+RO     read only value
+WO     write only value
+RW     read/write value
+==     ================
+
+Thermal sysfs attributes will be represented under /sys/class/thermal.
+Hwmon sysfs I/F extension is also available under /sys/class/hwmon
+if hwmon is compiled in or built as a module.
+
+Thermal zone device sys I/F, created once it's registered::
+
+  /sys/class/thermal/thermal_zone[0-*]:
+    |---type:                  Type of the thermal zone
+    |---temp:                  Current temperature
+    |---mode:                  Working mode of the thermal zone
+    |---policy:                        Thermal governor used for this zone
+    |---available_policies:    Available thermal governors for this zone
+    |---trip_point_[0-*]_temp: Trip point temperature
+    |---trip_point_[0-*]_type: Trip point type
+    |---trip_point_[0-*]_hyst: Hysteresis value for this trip point
+    |---emul_temp:             Emulated temperature set node
+    |---sustainable_power:      Sustainable dissipatable power
+    |---k_po:                   Proportional term during temperature overshoot
+    |---k_pu:                   Proportional term during temperature undershoot
+    |---k_i:                    PID's integral term in the power allocator gov
+    |---k_d:                    PID's derivative term in the power allocator
+    |---integral_cutoff:        Offset above which errors are accumulated
+    |---slope:                  Slope constant applied as linear extrapolation
+    |---offset:                 Offset constant applied as linear extrapolation
+
+Thermal cooling device sys I/F, created once it's registered::
+
+  /sys/class/thermal/cooling_device[0-*]:
+    |---type:                  Type of the cooling device(processor/fan/...)
+    |---max_state:             Maximum cooling state of the cooling device
+    |---cur_state:             Current cooling state of the cooling device
+    |---stats:                 Directory containing cooling device's statistics
+    |---stats/reset:           Writing any value resets the statistics
+    |---stats/time_in_state_ms:        Time (msec) spent in various cooling states
+    |---stats/total_trans:     Total number of times cooling state is changed
+    |---stats/trans_table:     Cooing state transition table
+
+
+Then next two dynamic attributes are created/removed in pairs. They represent
+the relationship between a thermal zone and its associated cooling device.
+They are created/removed for each successful execution of
+thermal_zone_bind_cooling_device/thermal_zone_unbind_cooling_device.
+
+::
+
+  /sys/class/thermal/thermal_zone[0-*]:
+    |---cdev[0-*]:             [0-*]th cooling device in current thermal zone
+    |---cdev[0-*]_trip_point:  Trip point that cdev[0-*] is associated with
+    |---cdev[0-*]_weight:       Influence of the cooling device in
+                               this thermal zone
+
+Besides the thermal zone device sysfs I/F and cooling device sysfs I/F,
+the generic thermal driver also creates a hwmon sysfs I/F for each _type_
+of thermal zone device. E.g. the generic thermal driver registers one hwmon
+class device and build the associated hwmon sysfs I/F for all the registered
+ACPI thermal zones.
+
+::
+
+  /sys/class/hwmon/hwmon[0-*]:
+    |---name:                  The type of the thermal zone devices
+    |---temp[1-*]_input:       The current temperature of thermal zone [1-*]
+    |---temp[1-*]_critical:    The critical trip point of thermal zone [1-*]
+
+Please read Documentation/hwmon/sysfs-interface.rst for additional information.
+
+Thermal zone attributes
+-----------------------
+
+type
+       Strings which represent the thermal zone type.
+       This is given by thermal zone driver as part of registration.
+       E.g: "acpitz" indicates it's an ACPI thermal device.
+       In order to keep it consistent with hwmon sys attribute; this should
+       be a short, lowercase string, not containing spaces nor dashes.
+       RO, Required
+
+temp
+       Current temperature as reported by thermal zone (sensor).
+       Unit: millidegree Celsius
+       RO, Required
+
+mode
+       One of the predefined values in [enabled, disabled].
+       This file gives information about the algorithm that is currently
+       managing the thermal zone. It can be either default kernel based
+       algorithm or user space application.
+
+       enabled
+                         enable Kernel Thermal management.
+       disabled
+                         Preventing kernel thermal zone driver actions upon
+                         trip points so that user application can take full
+                         charge of the thermal management.
+
+       RW, Optional
+
+policy
+       One of the various thermal governors used for a particular zone.
+
+       RW, Required
+
+available_policies
+       Available thermal governors which can be used for a particular zone.
+
+       RO, Required
+
+`trip_point_[0-*]_temp`
+       The temperature above which trip point will be fired.
+
+       Unit: millidegree Celsius
+
+       RO, Optional
+
+`trip_point_[0-*]_type`
+       Strings which indicate the type of the trip point.
+
+       E.g. it can be one of critical, hot, passive, `active[0-*]` for ACPI
+       thermal zone.
+
+       RO, Optional
+
+`trip_point_[0-*]_hyst`
+       The hysteresis value for a trip point, represented as an integer
+       Unit: Celsius
+       RW, Optional
+
+`cdev[0-*]`
+       Sysfs link to the thermal cooling device node where the sys I/F
+       for cooling device throttling control represents.
+
+       RO, Optional
+
+`cdev[0-*]_trip_point`
+       The trip point in this thermal zone which `cdev[0-*]` is associated
+       with; -1 means the cooling device is not associated with any trip
+       point.
+
+       RO, Optional
+
+`cdev[0-*]_weight`
+       The influence of `cdev[0-*]` in this thermal zone. This value
+       is relative to the rest of cooling devices in the thermal
+       zone. For example, if a cooling device has a weight double
+       than that of other, it's twice as effective in cooling the
+       thermal zone.
+
+       RW, Optional
+
+passive
+       Attribute is only present for zones in which the passive cooling
+       policy is not supported by native thermal driver. Default is zero
+       and can be set to a temperature (in millidegrees) to enable a
+       passive trip point for the zone. Activation is done by polling with
+       an interval of 1 second.
+
+       Unit: millidegrees Celsius
+
+       Valid values: 0 (disabled) or greater than 1000
+
+       RW, Optional
+
+emul_temp
+       Interface to set the emulated temperature method in thermal zone
+       (sensor). After setting this temperature, the thermal zone may pass
+       this temperature to platform emulation function if registered or
+       cache it locally. This is useful in debugging different temperature
+       threshold and its associated cooling action. This is write only node
+       and writing 0 on this node should disable emulation.
+       Unit: millidegree Celsius
+
+       WO, Optional
+
+         WARNING:
+           Be careful while enabling this option on production systems,
+           because userland can easily disable the thermal policy by simply
+           flooding this sysfs node with low temperature values.
+
+sustainable_power
+       An estimate of the sustained power that can be dissipated by
+       the thermal zone. Used by the power allocator governor. For
+       more information see Documentation/thermal/power_allocator.rst
+
+       Unit: milliwatts
+
+       RW, Optional
+
+k_po
+       The proportional term of the power allocator governor's PID
+       controller during temperature overshoot. Temperature overshoot
+       is when the current temperature is above the "desired
+       temperature" trip point. For more information see
+       Documentation/thermal/power_allocator.rst
+
+       RW, Optional
+
+k_pu
+       The proportional term of the power allocator governor's PID
+       controller during temperature undershoot. Temperature undershoot
+       is when the current temperature is below the "desired
+       temperature" trip point. For more information see
+       Documentation/thermal/power_allocator.rst
+
+       RW, Optional
+
+k_i
+       The integral term of the power allocator governor's PID
+       controller. This term allows the PID controller to compensate
+       for long term drift. For more information see
+       Documentation/thermal/power_allocator.rst
+
+       RW, Optional
+
+k_d
+       The derivative term of the power allocator governor's PID
+       controller. For more information see
+       Documentation/thermal/power_allocator.rst
+
+       RW, Optional
+
+integral_cutoff
+       Temperature offset from the desired temperature trip point
+       above which the integral term of the power allocator
+       governor's PID controller starts accumulating errors. For
+       example, if integral_cutoff is 0, then the integral term only
+       accumulates error when temperature is above the desired
+       temperature trip point. For more information see
+       Documentation/thermal/power_allocator.rst
+
+       Unit: millidegree Celsius
+
+       RW, Optional
+
+slope
+       The slope constant used in a linear extrapolation model
+       to determine a hotspot temperature based off the sensor's
+       raw readings. It is up to the device driver to determine
+       the usage of these values.
+
+       RW, Optional
+
+offset
+       The offset constant used in a linear extrapolation model
+       to determine a hotspot temperature based off the sensor's
+       raw readings. It is up to the device driver to determine
+       the usage of these values.
+
+       RW, Optional
+
+Cooling device attributes
+-------------------------
+
+type
+       String which represents the type of device, e.g:
+
+       - for generic ACPI: should be "Fan", "Processor" or "LCD"
+       - for memory controller device on intel_menlow platform:
+         should be "Memory controller".
+
+       RO, Required
+
+max_state
+       The maximum permissible cooling state of this cooling device.
+
+       RO, Required
+
+cur_state
+       The current cooling state of this cooling device.
+       The value can any integer numbers between 0 and max_state:
+
+       - cur_state == 0 means no cooling
+       - cur_state == max_state means the maximum cooling.
+
+       RW, Required
+
+stats/reset
+       Writing any value resets the cooling device's statistics.
+       WO, Required
+
+stats/time_in_state_ms:
+       The amount of time spent by the cooling device in various cooling
+       states. The output will have "<state> <time>" pair in each line, which
+       will mean this cooling device spent <time> msec of time at <state>.
+       Output will have one line for each of the supported states.  usertime
+       units here is 10mS (similar to other time exported in /proc).
+       RO, Required
+
+
+stats/total_trans:
+       A single positive value showing the total number of times the state of a
+       cooling device is changed.
+
+       RO, Required
+
+stats/trans_table:
+       This gives fine grained information about all the cooling state
+       transitions. The cat output here is a two dimensional matrix, where an
+       entry <i,j> (row i, column j) represents the number of transitions from
+       State_i to State_j. If the transition table is bigger than PAGE_SIZE,
+       reading this will return an -EFBIG error.
+       RO, Required
+
+3. A simple implementation
+==========================
+
+ACPI thermal zone may support multiple trip points like critical, hot,
+passive, active. If an ACPI thermal zone supports critical, passive,
+active[0] and active[1] at the same time, it may register itself as a
+thermal_zone_device (thermal_zone1) with 4 trip points in all.
+It has one processor and one fan, which are both registered as
+thermal_cooling_device. Both are considered to have the same
+effectiveness in cooling the thermal zone.
+
+If the processor is listed in _PSL method, and the fan is listed in _AL0
+method, the sys I/F structure will be built like this::
+
+ /sys/class/thermal:
+  |thermal_zone1:
+    |---type:                  acpitz
+    |---temp:                  37000
+    |---mode:                  enabled
+    |---policy:                        step_wise
+    |---available_policies:    step_wise fair_share
+    |---trip_point_0_temp:     100000
+    |---trip_point_0_type:     critical
+    |---trip_point_1_temp:     80000
+    |---trip_point_1_type:     passive
+    |---trip_point_2_temp:     70000
+    |---trip_point_2_type:     active0
+    |---trip_point_3_temp:     60000
+    |---trip_point_3_type:     active1
+    |---cdev0:                 --->/sys/class/thermal/cooling_device0
+    |---cdev0_trip_point:      1       /* cdev0 can be used for passive */
+    |---cdev0_weight:           1024
+    |---cdev1:                 --->/sys/class/thermal/cooling_device3
+    |---cdev1_trip_point:      2       /* cdev1 can be used for active[0]*/
+    |---cdev1_weight:           1024
+
+  |cooling_device0:
+    |---type:                  Processor
+    |---max_state:             8
+    |---cur_state:             0
+
+  |cooling_device3:
+    |---type:                  Fan
+    |---max_state:             2
+    |---cur_state:             0
+
+ /sys/class/hwmon:
+  |hwmon0:
+    |---name:                  acpitz
+    |---temp1_input:           37000
+    |---temp1_crit:            100000
+
+4. Event Notification
+=====================
+
+The framework includes a simple notification mechanism, in the form of a
+netlink event. Netlink socket initialization is done during the _init_
+of the framework. Drivers which intend to use the notification mechanism
+just need to call thermal_generate_netlink_event() with two arguments viz
+(originator, event). The originator is a pointer to struct thermal_zone_device
+from where the event has been originated. An integer which represents the
+thermal zone device will be used in the message to identify the zone. The
+event will be one of:{THERMAL_AUX0, THERMAL_AUX1, THERMAL_CRITICAL,
+THERMAL_DEV_FAULT}. Notification can be sent when the current temperature
+crosses any of the configured thresholds.
+
+5. Export Symbol APIs
+=====================
+
+5.1. get_tz_trend
+-----------------
+
+This function returns the trend of a thermal zone, i.e the rate of change
+of temperature of the thermal zone. Ideally, the thermal sensor drivers
+are supposed to implement the callback. If they don't, the thermal
+framework calculated the trend by comparing the previous and the current
+temperature values.
+
+5.2. get_thermal_instance
+-------------------------
+
+This function returns the thermal_instance corresponding to a given
+{thermal_zone, cooling_device, trip_point} combination. Returns NULL
+if such an instance does not exist.
+
+5.3. thermal_notify_framework
+-----------------------------
+
+This function handles the trip events from sensor drivers. It starts
+throttling the cooling devices according to the policy configured.
+For CRITICAL and HOT trip points, this notifies the respective drivers,
+and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
+The throttling policy is based on the configured platform data; if no
+platform data is provided, this uses the step_wise throttling policy.
+
+5.4. thermal_cdev_update
+------------------------
+
+This function serves as an arbitrator to set the state of a cooling
+device. It sets the cooling device to the deepest cooling state if
+possible.
+
+6. 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.
+
+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.
+
+If set to 0 emergency poweroff will not be supported. So a carefully
+profiled non-zero positive value is a must for emergerncy poweroff to be
+triggered.
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
deleted file mode 100644 (file)
index c3fa500..0000000
+++ /dev/null
@@ -1,636 +0,0 @@
-Generic Thermal Sysfs driver How To
-===================================
-
-Written by Sujith Thomas <sujith.thomas@intel.com>, Zhang Rui <rui.zhang@intel.com>
-
-Updated: 2 January 2008
-
-Copyright (c)  2008 Intel Corporation
-
-
-0. Introduction
-
-The generic thermal sysfs provides a set of interfaces for thermal zone
-devices (sensors) and thermal cooling devices (fan, processor...) to register
-with the thermal management solution and to be a part of it.
-
-This how-to focuses on enabling new thermal zone and cooling devices to
-participate in thermal management.
-This solution is platform independent and any type of thermal zone devices
-and cooling devices should be able to make use of the infrastructure.
-
-The main task of the thermal sysfs driver is to expose thermal zone attributes
-as well as cooling device attributes to the user space.
-An intelligent thermal management application can make decisions based on
-inputs from thermal zone attributes (the current temperature and trip point
-temperature) and throttle appropriate devices.
-
-[0-*]  denotes any positive number starting from 0
-[1-*]  denotes any positive number starting from 1
-
-1. thermal sysfs driver interface functions
-
-1.1 thermal zone device interface
-1.1.1 struct thermal_zone_device *thermal_zone_device_register(char *type,
-               int trips, int mask, void *devdata,
-               struct thermal_zone_device_ops *ops,
-               const struct thermal_zone_params *tzp,
-               int passive_delay, int polling_delay))
-
-    This interface function adds a new thermal zone device (sensor) to
-    /sys/class/thermal folder as thermal_zone[0-*]. It tries to bind all the
-    thermal cooling devices registered at the same time.
-
-    type: the thermal zone type.
-    trips: the total number of trip points this thermal zone supports.
-    mask: Bit string: If 'n'th bit is set, then trip point 'n' is writeable.
-    devdata: device private data
-    ops: thermal zone device call-backs.
-       .bind: bind the thermal zone device with a thermal cooling device.
-       .unbind: unbind the thermal zone device with a thermal cooling device.
-       .get_temp: get the current temperature of the thermal zone.
-       .set_trips: set the trip points window. Whenever the current temperature
-                   is updated, the trip points immediately below and above the
-                   current temperature are found.
-       .get_mode: get the current mode (enabled/disabled) of the thermal zone.
-           - "enabled" means the kernel thermal management is enabled.
-           - "disabled" will prevent kernel thermal driver action upon trip points
-             so that user applications can take charge of thermal management.
-       .set_mode: set the mode (enabled/disabled) of the thermal zone.
-       .get_trip_type: get the type of certain trip point.
-       .get_trip_temp: get the temperature above which the certain trip point
-                       will be fired.
-       .set_emul_temp: set the emulation temperature which helps in debugging
-                       different threshold temperature points.
-    tzp: thermal zone platform parameters.
-    passive_delay: number of milliseconds to wait between polls when
-       performing passive cooling.
-    polling_delay: number of milliseconds to wait between polls when checking
-       whether trip points have been crossed (0 for interrupt driven systems).
-
-
-1.1.2 void thermal_zone_device_unregister(struct thermal_zone_device *tz)
-
-    This interface function removes the thermal zone device.
-    It deletes the corresponding entry from /sys/class/thermal folder and
-    unbinds all the thermal cooling devices it uses.
-
-1.1.3 struct thermal_zone_device *thermal_zone_of_sensor_register(
-               struct device *dev, int sensor_id, void *data,
-               const struct thermal_zone_of_device_ops *ops)
-
-       This interface adds a new sensor to a DT thermal zone.
-       This function will search the list of thermal zones described in
-       device tree and look for the zone that refer to the sensor device
-       pointed by dev->of_node as temperature providers. For the zone
-       pointing to the sensor node, the sensor will be added to the DT
-       thermal zone device.
-
-       The parameters for this interface are:
-       dev:            Device node of sensor containing valid node pointer in
-                       dev->of_node.
-       sensor_id:      a sensor identifier, in case the sensor IP has more
-                       than one sensors
-       data:           a private pointer (owned by the caller) that will be
-                       passed back, when a temperature reading is needed.
-       ops:            struct thermal_zone_of_device_ops *.
-
-                       get_temp:       a pointer to a function that reads the
-                                       sensor temperature. This is mandatory
-                                       callback provided by sensor driver.
-                       set_trips:      a pointer to a function that sets a
-                                       temperature window. When this window is
-                                       left the driver must inform the thermal
-                                       core via thermal_zone_device_update.
-                       get_trend:      a pointer to a function that reads the
-                                       sensor temperature trend.
-                       set_emul_temp:  a pointer to a function that sets
-                                       sensor emulated temperature.
-       The thermal zone temperature is provided by the get_temp() function
-       pointer of thermal_zone_of_device_ops. When called, it will
-       have the private pointer @data back.
-
-       It returns error pointer if fails otherwise valid thermal zone device
-       handle. Caller should check the return handle with IS_ERR() for finding
-       whether success or not.
-
-1.1.4 void thermal_zone_of_sensor_unregister(struct device *dev,
-               struct thermal_zone_device *tzd)
-
-       This interface unregisters a sensor from a DT thermal zone which was
-       successfully added by interface thermal_zone_of_sensor_register().
-       This function removes the sensor callbacks and private data from the
-       thermal zone device registered with thermal_zone_of_sensor_register()
-       interface. It will also silent the zone by remove the .get_temp() and
-       get_trend() thermal zone device callbacks.
-
-1.1.5 struct thermal_zone_device *devm_thermal_zone_of_sensor_register(
-               struct device *dev, int sensor_id,
-               void *data, const struct thermal_zone_of_device_ops *ops)
-
-       This interface is resource managed version of
-       thermal_zone_of_sensor_register().
-       All details of thermal_zone_of_sensor_register() described in
-       section 1.1.3 is applicable here.
-       The benefit of using this interface to register sensor is that it
-       is not require to explicitly call thermal_zone_of_sensor_unregister()
-       in error path or during driver unbinding as this is done by driver
-       resource manager.
-
-1.1.6 void devm_thermal_zone_of_sensor_unregister(struct device *dev,
-               struct thermal_zone_device *tzd)
-
-       This interface is resource managed version of
-       thermal_zone_of_sensor_unregister().
-       All details of thermal_zone_of_sensor_unregister() described in
-       section 1.1.4 is applicable here.
-       Normally this function will not need to be called and the resource
-       management code will ensure that the resource is freed.
-
-1.1.7 int thermal_zone_get_slope(struct thermal_zone_device *tz)
-
-       This interface is used to read the slope attribute value
-       for the thermal zone device, which might be useful for platform
-       drivers for temperature calculations.
-
-1.1.8 int thermal_zone_get_offset(struct thermal_zone_device *tz)
-
-       This interface is used to read the offset attribute value
-       for the thermal zone device, which might be useful for platform
-       drivers for temperature calculations.
-
-1.2 thermal cooling device interface
-1.2.1 struct thermal_cooling_device *thermal_cooling_device_register(char *name,
-               void *devdata, struct thermal_cooling_device_ops *)
-
-    This interface function adds a new thermal cooling device (fan/processor/...)
-    to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself
-    to all the thermal zone devices registered at the same time.
-    name: the cooling device name.
-    devdata: device private data.
-    ops: thermal cooling devices call-backs.
-       .get_max_state: get the Maximum throttle state of the cooling device.
-       .get_cur_state: get the Currently requested throttle state of the cooling device.
-       .set_cur_state: set the Current throttle state of the cooling device.
-
-1.2.2 void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
-
-    This interface function removes the thermal cooling device.
-    It deletes the corresponding entry from /sys/class/thermal folder and
-    unbinds itself from all the thermal zone devices using it.
-
-1.3 interface for binding a thermal zone device with a thermal cooling device
-1.3.1 int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
-       int trip, struct thermal_cooling_device *cdev,
-       unsigned long upper, unsigned long lower, unsigned int weight);
-
-    This interface function binds a thermal cooling device to a particular trip
-    point of a thermal zone device.
-    This function is usually called in the thermal zone device .bind callback.
-    tz: the thermal zone device
-    cdev: thermal cooling device
-    trip: indicates which trip point in this thermal zone the cooling device
-          is associated with.
-    upper:the Maximum cooling state for this trip point.
-          THERMAL_NO_LIMIT means no upper limit,
-         and the cooling device can be in max_state.
-    lower:the Minimum cooling state can be used for this trip point.
-          THERMAL_NO_LIMIT means no lower limit,
-         and the cooling device can be in cooling state 0.
-    weight: the influence of this cooling device in this thermal
-            zone.  See 1.4.1 below for more information.
-
-1.3.2 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
-               int trip, struct thermal_cooling_device *cdev);
-
-    This interface function unbinds a thermal cooling device from a particular
-    trip point of a thermal zone device. This function is usually called in
-    the thermal zone device .unbind callback.
-    tz: the thermal zone device
-    cdev: thermal cooling device
-    trip: indicates which trip point in this thermal zone the cooling device
-          is associated with.
-
-1.4 Thermal Zone Parameters
-1.4.1 struct thermal_bind_params
-    This structure defines the following parameters that are used to bind
-    a zone with a cooling device for a particular trip point.
-    .cdev: The cooling device pointer
-    .weight: The 'influence' of a particular cooling device on this
-             zone. This is relative to the rest of the cooling
-             devices. For example, if all cooling devices have a
-             weight of 1, then they all contribute the same. You can
-             use percentages if you want, but it's not mandatory. A
-             weight of 0 means that this cooling device doesn't
-             contribute to the cooling of this zone unless all cooling
-             devices have a weight of 0. If all weights are 0, then
-             they all contribute the same.
-    .trip_mask:This is a bit mask that gives the binding relation between
-               this thermal zone and cdev, for a particular trip point.
-               If nth bit is set, then the cdev and thermal zone are bound
-               for trip point n.
-    .binding_limits: This is an array of cooling state limits. Must have
-                     exactly 2 * thermal_zone.number_of_trip_points. It is an
-                     array consisting of tuples <lower-state upper-state> of
-                     state limits. Each trip will be associated with one state
-                     limit tuple when binding. A NULL pointer means
-                     <THERMAL_NO_LIMITS THERMAL_NO_LIMITS> on all trips.
-                     These limits are used when binding a cdev to a trip point.
-    .match: This call back returns success(0) if the 'tz and cdev' need to
-           be bound, as per platform data.
-1.4.2 struct thermal_zone_params
-    This structure defines the platform level parameters for a thermal zone.
-    This data, for each thermal zone should come from the platform layer.
-    This is an optional feature where some platforms can choose not to
-    provide this data.
-    .governor_name: Name of the thermal governor used for this zone
-    .no_hwmon: a boolean to indicate if the thermal to hwmon sysfs interface
-               is required. when no_hwmon == false, a hwmon sysfs interface
-               will be created. when no_hwmon == true, nothing will be done.
-               In case the thermal_zone_params is NULL, the hwmon interface
-               will be created (for backward compatibility).
-    .num_tbps: Number of thermal_bind_params entries for this zone
-    .tbp: thermal_bind_params entries
-
-2. sysfs attributes structure
-
-RO     read only value
-WO     write only value
-RW     read/write value
-
-Thermal sysfs attributes will be represented under /sys/class/thermal.
-Hwmon sysfs I/F extension is also available under /sys/class/hwmon
-if hwmon is compiled in or built as a module.
-
-Thermal zone device sys I/F, created once it's registered:
-/sys/class/thermal/thermal_zone[0-*]:
-    |---type:                  Type of the thermal zone
-    |---temp:                  Current temperature
-    |---mode:                  Working mode of the thermal zone
-    |---policy:                        Thermal governor used for this zone
-    |---available_policies:    Available thermal governors for this zone
-    |---trip_point_[0-*]_temp: Trip point temperature
-    |---trip_point_[0-*]_type: Trip point type
-    |---trip_point_[0-*]_hyst: Hysteresis value for this trip point
-    |---emul_temp:             Emulated temperature set node
-    |---sustainable_power:      Sustainable dissipatable power
-    |---k_po:                   Proportional term during temperature overshoot
-    |---k_pu:                   Proportional term during temperature undershoot
-    |---k_i:                    PID's integral term in the power allocator gov
-    |---k_d:                    PID's derivative term in the power allocator
-    |---integral_cutoff:        Offset above which errors are accumulated
-    |---slope:                  Slope constant applied as linear extrapolation
-    |---offset:                 Offset constant applied as linear extrapolation
-
-Thermal cooling device sys I/F, created once it's registered:
-/sys/class/thermal/cooling_device[0-*]:
-    |---type:                  Type of the cooling device(processor/fan/...)
-    |---max_state:             Maximum cooling state of the cooling device
-    |---cur_state:             Current cooling state of the cooling device
-    |---stats:                 Directory containing cooling device's statistics
-    |---stats/reset:           Writing any value resets the statistics
-    |---stats/time_in_state_ms:        Time (msec) spent in various cooling states
-    |---stats/total_trans:     Total number of times cooling state is changed
-    |---stats/trans_table:     Cooing state transition table
-
-
-Then next two dynamic attributes are created/removed in pairs. They represent
-the relationship between a thermal zone and its associated cooling device.
-They are created/removed for each successful execution of
-thermal_zone_bind_cooling_device/thermal_zone_unbind_cooling_device.
-
-/sys/class/thermal/thermal_zone[0-*]:
-    |---cdev[0-*]:             [0-*]th cooling device in current thermal zone
-    |---cdev[0-*]_trip_point:  Trip point that cdev[0-*] is associated with
-    |---cdev[0-*]_weight:       Influence of the cooling device in
-                                this thermal zone
-
-Besides the thermal zone device sysfs I/F and cooling device sysfs I/F,
-the generic thermal driver also creates a hwmon sysfs I/F for each _type_
-of thermal zone device. E.g. the generic thermal driver registers one hwmon
-class device and build the associated hwmon sysfs I/F for all the registered
-ACPI thermal zones.
-
-/sys/class/hwmon/hwmon[0-*]:
-    |---name:                  The type of the thermal zone devices
-    |---temp[1-*]_input:       The current temperature of thermal zone [1-*]
-    |---temp[1-*]_critical:    The critical trip point of thermal zone [1-*]
-
-Please read Documentation/hwmon/sysfs-interface.rst for additional information.
-
-***************************
-* Thermal zone attributes *
-***************************
-
-type
-       Strings which represent the thermal zone type.
-       This is given by thermal zone driver as part of registration.
-       E.g: "acpitz" indicates it's an ACPI thermal device.
-       In order to keep it consistent with hwmon sys attribute; this should
-       be a short, lowercase string, not containing spaces nor dashes.
-       RO, Required
-
-temp
-       Current temperature as reported by thermal zone (sensor).
-       Unit: millidegree Celsius
-       RO, Required
-
-mode
-       One of the predefined values in [enabled, disabled].
-       This file gives information about the algorithm that is currently
-       managing the thermal zone. It can be either default kernel based
-       algorithm or user space application.
-       enabled         = enable Kernel Thermal management.
-       disabled        = Preventing kernel thermal zone driver actions upon
-                         trip points so that user application can take full
-                         charge of the thermal management.
-       RW, Optional
-
-policy
-       One of the various thermal governors used for a particular zone.
-       RW, Required
-
-available_policies
-       Available thermal governors which can be used for a particular zone.
-       RO, Required
-
-trip_point_[0-*]_temp
-       The temperature above which trip point will be fired.
-       Unit: millidegree Celsius
-       RO, Optional
-
-trip_point_[0-*]_type
-       Strings which indicate the type of the trip point.
-       E.g. it can be one of critical, hot, passive, active[0-*] for ACPI
-       thermal zone.
-       RO, Optional
-
-trip_point_[0-*]_hyst
-       The hysteresis value for a trip point, represented as an integer
-       Unit: Celsius
-       RW, Optional
-
-cdev[0-*]
-       Sysfs link to the thermal cooling device node where the sys I/F
-       for cooling device throttling control represents.
-       RO, Optional
-
-cdev[0-*]_trip_point
-       The trip point in this thermal zone which cdev[0-*] is associated
-       with; -1 means the cooling device is not associated with any trip
-       point.
-       RO, Optional
-
-cdev[0-*]_weight
-        The influence of cdev[0-*] in this thermal zone. This value
-        is relative to the rest of cooling devices in the thermal
-        zone. For example, if a cooling device has a weight double
-        than that of other, it's twice as effective in cooling the
-        thermal zone.
-        RW, Optional
-
-passive
-       Attribute is only present for zones in which the passive cooling
-       policy is not supported by native thermal driver. Default is zero
-       and can be set to a temperature (in millidegrees) to enable a
-       passive trip point for the zone. Activation is done by polling with
-       an interval of 1 second.
-       Unit: millidegrees Celsius
-       Valid values: 0 (disabled) or greater than 1000
-       RW, Optional
-
-emul_temp
-       Interface to set the emulated temperature method in thermal zone
-       (sensor). After setting this temperature, the thermal zone may pass
-       this temperature to platform emulation function if registered or
-       cache it locally. This is useful in debugging different temperature
-       threshold and its associated cooling action. This is write only node
-       and writing 0 on this node should disable emulation.
-       Unit: millidegree Celsius
-       WO, Optional
-
-         WARNING: Be careful while enabling this option on production systems,
-         because userland can easily disable the thermal policy by simply
-         flooding this sysfs node with low temperature values.
-
-sustainable_power
-       An estimate of the sustained power that can be dissipated by
-       the thermal zone. Used by the power allocator governor. For
-       more information see Documentation/thermal/power_allocator.txt
-       Unit: milliwatts
-       RW, Optional
-
-k_po
-       The proportional term of the power allocator governor's PID
-       controller during temperature overshoot. Temperature overshoot
-       is when the current temperature is above the "desired
-       temperature" trip point. For more information see
-       Documentation/thermal/power_allocator.txt
-       RW, Optional
-
-k_pu
-       The proportional term of the power allocator governor's PID
-       controller during temperature undershoot. Temperature undershoot
-       is when the current temperature is below the "desired
-       temperature" trip point. For more information see
-       Documentation/thermal/power_allocator.txt
-       RW, Optional
-
-k_i
-       The integral term of the power allocator governor's PID
-       controller. This term allows the PID controller to compensate
-       for long term drift. For more information see
-       Documentation/thermal/power_allocator.txt
-       RW, Optional
-
-k_d
-       The derivative term of the power allocator governor's PID
-       controller. For more information see
-       Documentation/thermal/power_allocator.txt
-       RW, Optional
-
-integral_cutoff
-       Temperature offset from the desired temperature trip point
-       above which the integral term of the power allocator
-       governor's PID controller starts accumulating errors. For
-       example, if integral_cutoff is 0, then the integral term only
-       accumulates error when temperature is above the desired
-       temperature trip point. For more information see
-       Documentation/thermal/power_allocator.txt
-       Unit: millidegree Celsius
-       RW, Optional
-
-slope
-       The slope constant used in a linear extrapolation model
-       to determine a hotspot temperature based off the sensor's
-       raw readings. It is up to the device driver to determine
-       the usage of these values.
-       RW, Optional
-
-offset
-       The offset constant used in a linear extrapolation model
-       to determine a hotspot temperature based off the sensor's
-       raw readings. It is up to the device driver to determine
-       the usage of these values.
-       RW, Optional
-
-*****************************
-* Cooling device attributes *
-*****************************
-
-type
-       String which represents the type of device, e.g:
-       - for generic ACPI: should be "Fan", "Processor" or "LCD"
-       - for memory controller device on intel_menlow platform:
-         should be "Memory controller".
-       RO, Required
-
-max_state
-       The maximum permissible cooling state of this cooling device.
-       RO, Required
-
-cur_state
-       The current cooling state of this cooling device.
-       The value can any integer numbers between 0 and max_state:
-       - cur_state == 0 means no cooling
-       - cur_state == max_state means the maximum cooling.
-       RW, Required
-
-stats/reset
-       Writing any value resets the cooling device's statistics.
-       WO, Required
-
-stats/time_in_state_ms:
-       The amount of time spent by the cooling device in various cooling
-       states. The output will have "<state> <time>" pair in each line, which
-       will mean this cooling device spent <time> msec of time at <state>.
-       Output will have one line for each of the supported states.  usertime
-       units here is 10mS (similar to other time exported in /proc).
-       RO, Required
-
-stats/total_trans:
-       A single positive value showing the total number of times the state of a
-       cooling device is changed.
-       RO, Required
-
-stats/trans_table:
-       This gives fine grained information about all the cooling state
-       transitions. The cat output here is a two dimensional matrix, where an
-       entry <i,j> (row i, column j) represents the number of transitions from
-       State_i to State_j. If the transition table is bigger than PAGE_SIZE,
-       reading this will return an -EFBIG error.
-       RO, Required
-
-3. A simple implementation
-
-ACPI thermal zone may support multiple trip points like critical, hot,
-passive, active. If an ACPI thermal zone supports critical, passive,
-active[0] and active[1] at the same time, it may register itself as a
-thermal_zone_device (thermal_zone1) with 4 trip points in all.
-It has one processor and one fan, which are both registered as
-thermal_cooling_device. Both are considered to have the same
-effectiveness in cooling the thermal zone.
-
-If the processor is listed in _PSL method, and the fan is listed in _AL0
-method, the sys I/F structure will be built like this:
-
-/sys/class/thermal:
-
-|thermal_zone1:
-    |---type:                  acpitz
-    |---temp:                  37000
-    |---mode:                  enabled
-    |---policy:                        step_wise
-    |---available_policies:    step_wise fair_share
-    |---trip_point_0_temp:     100000
-    |---trip_point_0_type:     critical
-    |---trip_point_1_temp:     80000
-    |---trip_point_1_type:     passive
-    |---trip_point_2_temp:     70000
-    |---trip_point_2_type:     active0
-    |---trip_point_3_temp:     60000
-    |---trip_point_3_type:     active1
-    |---cdev0:                 --->/sys/class/thermal/cooling_device0
-    |---cdev0_trip_point:      1       /* cdev0 can be used for passive */
-    |---cdev0_weight:           1024
-    |---cdev1:                 --->/sys/class/thermal/cooling_device3
-    |---cdev1_trip_point:      2       /* cdev1 can be used for active[0]*/
-    |---cdev1_weight:           1024
-
-|cooling_device0:
-    |---type:                  Processor
-    |---max_state:             8
-    |---cur_state:             0
-
-|cooling_device3:
-    |---type:                  Fan
-    |---max_state:             2
-    |---cur_state:             0
-
-/sys/class/hwmon:
-
-|hwmon0:
-    |---name:                  acpitz
-    |---temp1_input:           37000
-    |---temp1_crit:            100000
-
-4. Event Notification
-
-The framework includes a simple notification mechanism, in the form of a
-netlink event. Netlink socket initialization is done during the _init_
-of the framework. Drivers which intend to use the notification mechanism
-just need to call thermal_generate_netlink_event() with two arguments viz
-(originator, event). The originator is a pointer to struct thermal_zone_device
-from where the event has been originated. An integer which represents the
-thermal zone device will be used in the message to identify the zone. The
-event will be one of:{THERMAL_AUX0, THERMAL_AUX1, THERMAL_CRITICAL,
-THERMAL_DEV_FAULT}. Notification can be sent when the current temperature
-crosses any of the configured thresholds.
-
-5. Export Symbol APIs:
-
-5.1: get_tz_trend:
-This function returns the trend of a thermal zone, i.e the rate of change
-of temperature of the thermal zone. Ideally, the thermal sensor drivers
-are supposed to implement the callback. If they don't, the thermal
-framework calculated the trend by comparing the previous and the current
-temperature values.
-
-5.2:get_thermal_instance:
-This function returns the thermal_instance corresponding to a given
-{thermal_zone, cooling_device, trip_point} combination. Returns NULL
-if such an instance does not exist.
-
-5.3:thermal_notify_framework:
-This function handles the trip events from sensor drivers. It starts
-throttling the cooling devices according to the policy configured.
-For CRITICAL and HOT trip points, this notifies the respective drivers,
-and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
-The throttling policy is based on the configured platform data; if no
-platform data is provided, this uses the step_wise throttling policy.
-
-5.4:thermal_cdev_update:
-This function serves as an arbitrator to set the state of a cooling
-device. It sets the cooling device to the deepest cooling state if
-possible.
-
-6. 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.
-
-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.
-
-If set to 0 emergency poweroff will not be supported. So a carefully
-profiled non-zero positive value is a must for emergerncy poweroff to be
-triggered.
diff --git a/Documentation/thermal/x86_pkg_temperature_thermal b/Documentation/thermal/x86_pkg_temperature_thermal
deleted file mode 100644 (file)
index 17a3a4c..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-Kernel driver: x86_pkg_temp_thermal
-===================
-
-Supported chips:
-* x86: with package level thermal management
-(Verify using: CPUID.06H:EAX[bit 6] =1)
-
-Authors: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
-
-Reference
----
-Intel® 64 and IA-32 Architectures Software Developer’s Manual (Jan, 2013):
-Chapter 14.6: PACKAGE LEVEL THERMAL MANAGEMENT
-
-Description
----------
-
-This driver register CPU digital temperature package level sensor as a thermal
-zone with maximum two user mode configurable trip points. Number of trip points
-depends on the capability of the package. Once the trip point is violated,
-user mode can receive notification via thermal notification mechanism and can
-take any action to control temperature.
-
-
-Threshold management
---------------------
-Each package will register as a thermal zone under /sys/class/thermal.
-Example:
-/sys/class/thermal/thermal_zone1
-
-This contains two trip points:
-- trip_point_0_temp
-- trip_point_1_temp
-
-User can set any temperature between 0 to TJ-Max temperature. Temperature units
-are in milli-degree Celsius. Refer to "Documentation/thermal/sysfs-api.txt" for
-thermal sys-fs details.
-
-Any value other than 0 in these trip points, can trigger thermal notifications.
-Setting 0, stops sending thermal notifications.
-
-Thermal notifications: To get kobject-uevent notifications, set the thermal zone
-policy to "user_space". For example: echo -n "user_space" > policy
-
-
-
-
diff --git a/Documentation/thermal/x86_pkg_temperature_thermal.rst b/Documentation/thermal/x86_pkg_temperature_thermal.rst
new file mode 100644 (file)
index 0000000..f134dbd
--- /dev/null
@@ -0,0 +1,55 @@
+===================================
+Kernel driver: x86_pkg_temp_thermal
+===================================
+
+Supported chips:
+
+* x86: with package level thermal management
+
+(Verify using: CPUID.06H:EAX[bit 6] =1)
+
+Authors: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+
+Reference
+---------
+
+Intel® 64 and IA-32 Architectures Software Developer’s Manual (Jan, 2013):
+Chapter 14.6: PACKAGE LEVEL THERMAL MANAGEMENT
+
+Description
+-----------
+
+This driver register CPU digital temperature package level sensor as a thermal
+zone with maximum two user mode configurable trip points. Number of trip points
+depends on the capability of the package. Once the trip point is violated,
+user mode can receive notification via thermal notification mechanism and can
+take any action to control temperature.
+
+
+Threshold management
+--------------------
+Each package will register as a thermal zone under /sys/class/thermal.
+
+Example::
+
+       /sys/class/thermal/thermal_zone1
+
+This contains two trip points:
+
+- trip_point_0_temp
+- trip_point_1_temp
+
+User can set any temperature between 0 to TJ-Max temperature. Temperature units
+are in milli-degree Celsius. Refer to "Documentation/thermal/sysfs-api.rst" for
+thermal sys-fs details.
+
+Any value other than 0 in these trip points, can trigger thermal notifications.
+Setting 0, stops sending thermal notifications.
+
+Thermal notifications:
+To get kobject-uevent notifications, set the thermal zone
+policy to "user_space".
+
+For example::
+
+       echo -n "user_space" > policy
index 91f6f82..df510ad 100644 (file)
@@ -1,4 +1,4 @@
-:orphan:
+.. SPDX-License-Identifier: GPL-2.0
 
 ======
 timers
index 7d2b017..fbb314b 100644 (file)
@@ -51,15 +51,17 @@ Synopsis of kprobe_events
   $argN                : Fetch the Nth function argument. (N >= 1) (\*1)
   $retval      : Fetch return value.(\*2)
   $comm                : Fetch current task comm.
-  +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(\*3)
+  +|-[u]OFFS(FETCHARG) : Fetch memory at FETCHARG +|- OFFS address.(\*3)(\*4)
   NAME=FETCHARG : Set NAME as the argument name of FETCHARG.
   FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types
                  (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types
-                 (x8/x16/x32/x64), "string" and bitfield are supported.
+                 (x8/x16/x32/x64), "string", "ustring" and bitfield
+                 are supported.
 
   (\*1) only for the probe on function entry (offs == 0).
   (\*2) only for return probe.
   (\*3) this is useful for fetching a field of data structures.
+  (\*4) "u" means user-space dereference. See :ref:`user_mem_access`.
 
 Types
 -----
@@ -77,7 +79,8 @@ apply it to registers/stack-entries etc. (for example, '$stack1:x8[8]' is
 wrong, but '+8($stack):x8[8]' is OK.)
 String type is a special type, which fetches a "null-terminated" string from
 kernel space. This means it will fail and store NULL if the string container
-has been paged out.
+has been paged out. "ustring" type is an alternative of string for user-space.
+See :ref:`user_mem_access` for more info..
 The string array type is a bit different from other types. For other base
 types, <base-type>[1] is equal to <base-type> (e.g. +0(%di):x32[1] is same
 as +0(%di):x32.) But string[1] is not equal to string. The string type itself
@@ -92,6 +95,25 @@ Symbol type('symbol') is an alias of u32 or u64 type (depends on BITS_PER_LONG)
 which shows given pointer in "symbol+offset" style.
 For $comm, the default type is "string"; any other type is invalid.
 
+.. _user_mem_access:
+User Memory Access
+------------------
+Kprobe events supports user-space memory access. For that purpose, you can use
+either user-space dereference syntax or 'ustring' type.
+
+The user-space dereference syntax allows you to access a field of a data
+structure in user-space. This is done by adding the "u" prefix to the
+dereference syntax. For example, +u4(%si) means it will read memory from the
+address in the register %si offset by 4, and the memory is expected to be in
+user-space. You can use this for strings too, e.g. +u0(%si):string will read
+a string from the address in the register %si that is expected to be in user-
+space. 'ustring' is a shortcut way of performing the same task. That is,
++0(%si):ustring is equivalent to +u0(%si):string.
+
+Note that kprobe-event provides the user-memory access syntax but it doesn't
+use it transparently. This means if you use normal dereference or string type
+for user memory, it might fail, and may always fail on some archs. The user
+has to carefully check if the target data is in kernel or user space.
 
 Per-Probe Event Filtering
 -------------------------
@@ -124,6 +146,20 @@ You can check the total number of probe hits and probe miss-hits via
 The first column is event name, the second is the number of probe hits,
 the third is the number of probe miss-hits.
 
+Kernel Boot Parameter
+---------------------
+You can add and enable new kprobe events when booting up the kernel by
+"kprobe_event=" parameter. The parameter accepts a semicolon-delimited
+kprobe events, which format is similar to the kprobe_events.
+The difference is that the probe definition parameters are comma-delimited
+instead of space. For example, adding myprobe event on do_sys_open like below
+
+  p:myprobe do_sys_open dfd=%ax filename=%dx flags=%cx mode=+4($stack)
+
+should be below for kernel boot parameter (just replace spaces with comma)
+
+  p:myprobe,do_sys_open,dfd=%ax,filename=%dx,flags=%cx,mode=+4($stack)
+
 
 Usage examples
 --------------
index 0b21305..6e75a6c 100644 (file)
@@ -42,16 +42,18 @@ Synopsis of uprobe_tracer
    @+OFFSET    : Fetch memory at OFFSET (OFFSET from same file as PATH)
    $stackN     : Fetch Nth entry of stack (N >= 0)
    $stack      : Fetch stack address.
-   $retval     : Fetch return value.(*)
+   $retval     : Fetch return value.(\*1)
    $comm       : Fetch current task comm.
-   +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(**)
+   +|-[u]OFFS(FETCHARG) : Fetch memory at FETCHARG +|- OFFS address.(\*2)(\*3)
    NAME=FETCHARG     : Set NAME as the argument name of FETCHARG.
    FETCHARG:TYPE     : Set TYPE as the type of FETCHARG. Currently, basic types
                       (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types
                       (x8/x16/x32/x64), "string" and bitfield are supported.
 
-  (*) only for return probe.
-  (**) this is useful for fetching a field of data structures.
+  (\*1) only for return probe.
+  (\*2) this is useful for fetching a field of data structures.
+  (\*3) Unlike kprobe event, "u" prefix will just be ignored, becuse uprobe
+        events can access only user-space memory.
 
 Types
 -----
index 5fd8a1a..b9a6be4 100644 (file)
@@ -1404,7 +1404,7 @@ Riferimento per l'API dei Futex
 Approfondimenti
 ===============
 
--  ``Documentation/locking/spinlocks.txt``: la guida di Linus Torvalds agli
+-  ``Documentation/locking/spinlocks.rst``: la guida di Linus Torvalds agli
    spinlock del kernel.
 
 -  Unix Systems for Modern Architectures: Symmetric Multiprocessing and
index ea74cae..995ee69 100644 (file)
@@ -117,7 +117,7 @@ sottomissione delle patch, in particolare
     sorgenti che ne spieghi la logica: cosa fanno e perché.
 
 25) Se la patch aggiunge nuove chiamate ioctl, allora aggiornate
-    ``Documentation/ioctl/ioctl-number.txt``.
+    ``Documentation/ioctl/ioctl-number.rst``.
 
 26) Se il codice che avete modificato dipende o usa una qualsiasi interfaccia o
     funzionalità del kernel che è associata a uno dei seguenti simboli
index 1fe866f..562e9a2 100644 (file)
@@ -1,4 +1,4 @@
-Chinese translated version of Documentation/arm/Booting
+Chinese translated version of Documentation/arm/booting.rst
 
 If you have any comment or update to the content, please contact the
 original document maintainer directly.  However, if you have a problem
@@ -9,7 +9,7 @@ or if there is a problem with the translation.
 Maintainer: Russell King <linux@arm.linux.org.uk>
 Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
 ---------------------------------------------------------------------
-Documentation/arm/Booting 的中文翻译
+Documentation/arm/booting.rst 的中文翻译
 
 如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
 交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
index cd7fc8f..99af436 100644 (file)
@@ -1,4 +1,4 @@
-Chinese translated version of Documentation/arm/kernel_user_helpers.txt
+Chinese translated version of Documentation/arm/kernel_user_helpers.rst
 
 If you have any comment or update to the content, please contact the
 original document maintainer directly.  However, if you have a problem
@@ -10,7 +10,7 @@ Maintainer: Nicolas Pitre <nicolas.pitre@linaro.org>
                Dave Martin <dave.martin@linaro.org>
 Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
 ---------------------------------------------------------------------
-Documentation/arm/kernel_user_helpers.txt 的中文翻译
+Documentation/arm/kernel_user_helpers.rst 的中文翻译
 
 如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
 交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
index 452271d..ee1f37d 100644 (file)
@@ -288,7 +288,7 @@ dev/ 包含两个子目录: char/ 和 block/。在这两个子目录中,有
 中相应的设备。/sys/dev 提供一个通过一个 stat(2) 操作结果,查找
 设备 sysfs 接口快捷的方法。
 
-更多有关 driver-model 的特性信息可以在 Documentation/driver-model/
+更多有关 driver-model 的特性信息可以在 Documentation/driver-api/driver-model/
 中找到。
 
 
index 4cb1ba8..a23ee14 100644 (file)
@@ -1,4 +1,4 @@
-Chinese translated version of Documentation/gpio
+Chinese translated version of Documentation/admin-guide/gpio
 
 If you have any comment or update to the content, please contact the
 original document maintainer directly.  However, if you have a problem
@@ -10,7 +10,7 @@ Maintainer: Grant Likely <grant.likely@secretlab.ca>
                Linus Walleij <linus.walleij@linaro.org>
 Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
 ---------------------------------------------------------------------
-Documentation/gpio 的中文翻译
+Documentation/admin-guide/gpio 的中文翻译
 
 如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
 交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
index 368ddd0..c5f3bda 100644 (file)
@@ -53,8 +53,8 @@ cat /proc/kmsg > file, 然而你必须介入中止传输, kmsg是一个“
 (2)用串口终端启动(请参看Documentation/admin-guide/serial-console.rst),运行一个null
 modem到另一台机器并用你喜欢的通讯工具获取输出。Minicom工作地很好。
 
-(3)使用Kdump(请参看Documentation/kdump/kdump.rst),
-使用在Documentation/kdump/gdbmacros.txt中定义的dmesg gdb宏,从旧的内存中提取内核
+(3)使用Kdump(请参看Documentation/admin-guide/kdump/kdump.rst),
+使用在Documentation/admin-guide/kdump/gdbmacros.txt中定义的dmesg gdb宏,从旧的内存中提取内核
 环形缓冲区。
 
 完整信息
index f4785d2..8738c55 100644 (file)
@@ -97,7 +97,7 @@ Linux内核补丁提交清单
 24) 所有内存屏障例如 ``barrier()``, ``rmb()``, ``wmb()`` 都需要源代码中的注
     释来解释它们正在执行的操作及其原因的逻辑。
 
-25) 如果补丁添加了任何ioctl,那么也要更新 ``Documentation/ioctl/ioctl-number.txt``
+25) 如果补丁添加了任何ioctl,那么也要更新 ``Documentation/ioctl/ioctl-number.rst``
 
 26) 如果修改后的源代码依赖或使用与以下 ``Kconfig`` 符号相关的任何内核API或
     功能,则在禁用相关 ``Kconfig`` 符号和/或 ``=m`` (如果该选项可用)的情况
index 47fc4a0..0f444b8 100644 (file)
@@ -73,10 +73,6 @@ __bitwise"类型。
 
        git://git.kernel.org/pub/scm/linux/kernel/git/josh/sparse.git
 
-DaveJ 把每小时自动生成的 git 源码树 tar 包放在以下地址:
-
-       http://www.codemonkey.org.uk/projects/git-snapshots/sparse/
-
 一旦你下载了源码,只要以普通用户身份运行:
 
        make
diff --git a/Documentation/userspace-api/accelerators/ocxl.rst b/Documentation/userspace-api/accelerators/ocxl.rst
new file mode 100644 (file)
index 0000000..14cefc0
--- /dev/null
@@ -0,0 +1,176 @@
+========================================================
+OpenCAPI (Open Coherent Accelerator Processor Interface)
+========================================================
+
+OpenCAPI is an interface between processors and accelerators. It aims
+at being low-latency and high-bandwidth. The specification is
+developed by the `OpenCAPI Consortium <http://opencapi.org/>`_.
+
+It allows an accelerator (which could be a FPGA, ASICs, ...) to access
+the host memory coherently, using virtual addresses. An OpenCAPI
+device can also host its own memory, that can be accessed from the
+host.
+
+OpenCAPI is known in linux as 'ocxl', as the open, processor-agnostic
+evolution of 'cxl' (the driver for the IBM CAPI interface for
+powerpc), which was named that way to avoid confusion with the ISDN
+CAPI subsystem.
+
+
+High-level view
+===============
+
+OpenCAPI defines a Data Link Layer (DL) and Transaction Layer (TL), to
+be implemented on top of a physical link. Any processor or device
+implementing the DL and TL can start sharing memory.
+
+::
+
+  +-----------+                         +-------------+
+  |           |                         |             |
+  |           |                         | Accelerated |
+  | Processor |                         |  Function   |
+  |           |  +--------+             |    Unit     |  +--------+
+  |           |--| Memory |             |    (AFU)    |--| Memory |
+  |           |  +--------+             |             |  +--------+
+  +-----------+                         +-------------+
+       |                                       |
+  +-----------+                         +-------------+
+  |    TL     |                         |    TLX      |
+  +-----------+                         +-------------+
+       |                                       |
+  +-----------+                         +-------------+
+  |    DL     |                         |    DLX      |
+  +-----------+                         +-------------+
+       |                                       |
+       |                   PHY                 |
+       +---------------------------------------+
+
+
+
+Device discovery
+================
+
+OpenCAPI relies on a PCI-like configuration space, implemented on the
+device. So the host can discover AFUs by querying the config space.
+
+OpenCAPI devices in Linux are treated like PCI devices (with a few
+caveats). The firmware is expected to abstract the hardware as if it
+was a PCI link. A lot of the existing PCI infrastructure is reused:
+devices are scanned and BARs are assigned during the standard PCI
+enumeration. Commands like 'lspci' can therefore be used to see what
+devices are available.
+
+The configuration space defines the AFU(s) that can be found on the
+physical adapter, such as its name, how many memory contexts it can
+work with, the size of its MMIO areas, ...
+
+
+
+MMIO
+====
+
+OpenCAPI defines two MMIO areas for each AFU:
+
+* the global MMIO area, with registers pertinent to the whole AFU.
+* a per-process MMIO area, which has a fixed size for each context.
+
+
+
+AFU interrupts
+==============
+
+OpenCAPI includes the possibility for an AFU to send an interrupt to a
+host process. It is done through a 'intrp_req' defined in the
+Transaction Layer, specifying a 64-bit object handle which defines the
+interrupt.
+
+The driver allows a process to allocate an interrupt and obtain its
+64-bit object handle, that can be passed to the AFU.
+
+
+
+char devices
+============
+
+The driver creates one char device per AFU found on the physical
+device. A physical device may have multiple functions and each
+function can have multiple AFUs. At the time of this writing though,
+it has only been tested with devices exporting only one AFU.
+
+Char devices can be found in /dev/ocxl/ and are named as:
+/dev/ocxl/<AFU name>.<location>.<index>
+
+where <AFU name> is a max 20-character long name, as found in the
+config space of the AFU.
+<location> is added by the driver and can help distinguish devices
+when a system has more than one instance of the same OpenCAPI device.
+<index> is also to help distinguish AFUs in the unlikely case where a
+device carries multiple copies of the same AFU.
+
+
+
+Sysfs class
+===========
+
+An ocxl class is added for the devices representing the AFUs. See
+/sys/class/ocxl. The layout is described in
+Documentation/ABI/testing/sysfs-class-ocxl
+
+
+
+User API
+========
+
+open
+----
+
+Based on the AFU definition found in the config space, an AFU may
+support working with more than one memory context, in which case the
+associated char device may be opened multiple times by different
+processes.
+
+
+ioctl
+-----
+
+OCXL_IOCTL_ATTACH:
+
+  Attach the memory context of the calling process to the AFU so that
+  the AFU can access its memory.
+
+OCXL_IOCTL_IRQ_ALLOC:
+
+  Allocate an AFU interrupt and return an identifier.
+
+OCXL_IOCTL_IRQ_FREE:
+
+  Free a previously allocated AFU interrupt.
+
+OCXL_IOCTL_IRQ_SET_FD:
+
+  Associate an event fd to an AFU interrupt so that the user process
+  can be notified when the AFU sends an interrupt.
+
+OCXL_IOCTL_GET_METADATA:
+
+  Obtains configuration information from the card, such at the size of
+  MMIO areas, the AFU version, and the PASID for the current context.
+
+OCXL_IOCTL_ENABLE_P9_WAIT:
+
+  Allows the AFU to wake a userspace thread executing 'wait'. Returns
+  information to userspace to allow it to configure the AFU. Note that
+  this is only available on POWER9.
+
+OCXL_IOCTL_GET_FEATURES:
+
+  Reports on which CPU features that affect OpenCAPI are usable from
+  userspace.
+
+
+mmap
+----
+
+A process can mmap the per-process MMIO area for interactions with the
+AFU.
index a3233da..ad494da 100644 (file)
@@ -20,6 +20,7 @@ place where this information is gathered.
    seccomp_filter
    unshare
    spec_ctrl
+   accelerators/ocxl
 
 .. only::  subproject and html
 
diff --git a/Documentation/vfio-mediated-device.txt b/Documentation/vfio-mediated-device.txt
deleted file mode 100644 (file)
index c3f69bc..0000000
+++ /dev/null
@@ -1,414 +0,0 @@
-.. include:: <isonum.txt>
-
-=====================
-VFIO Mediated devices
-=====================
-
-:Copyright: |copy| 2016, NVIDIA CORPORATION. All rights reserved.
-:Author: Neo Jia <cjia@nvidia.com>
-:Author: Kirti Wankhede <kwankhede@nvidia.com>
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License version 2 as
-published by the Free Software Foundation.
-
-
-Virtual Function I/O (VFIO) Mediated devices[1]
-===============================================
-
-The number of use cases for virtualizing DMA devices that do not have built-in
-SR_IOV capability is increasing. Previously, to virtualize such devices,
-developers had to create their own management interfaces and APIs, and then
-integrate them with user space software. To simplify integration with user space
-software, we have identified common requirements and a unified management
-interface for such devices.
-
-The VFIO driver framework provides unified APIs for direct device access. It is
-an IOMMU/device-agnostic framework for exposing direct device access to user
-space in a secure, IOMMU-protected environment. This framework is used for
-multiple devices, such as GPUs, network adapters, and compute accelerators. With
-direct device access, virtual machines or user space applications have direct
-access to the physical device. This framework is reused for mediated devices.
-
-The mediated core driver provides a common interface for mediated device
-management that can be used by drivers of different devices. This module
-provides a generic interface to perform these operations:
-
-* Create and destroy a mediated device
-* Add a mediated device to and remove it from a mediated bus driver
-* Add a mediated device to and remove it from an IOMMU group
-
-The mediated core driver also provides an interface to register a bus driver.
-For example, the mediated VFIO mdev driver is designed for mediated devices and
-supports VFIO APIs. The mediated bus driver adds a mediated device to and
-removes it from a VFIO group.
-
-The following high-level block diagram shows the main components and interfaces
-in the VFIO mediated driver framework. The diagram shows NVIDIA, Intel, and IBM
-devices as examples, as these devices are the first devices to use this module::
-
-     +---------------+
-     |               |
-     | +-----------+ |  mdev_register_driver() +--------------+
-     | |           | +<------------------------+              |
-     | |  mdev     | |                         |              |
-     | |  bus      | +------------------------>+ vfio_mdev.ko |<-> VFIO user
-     | |  driver   | |     probe()/remove()    |              |    APIs
-     | |           | |                         +--------------+
-     | +-----------+ |
-     |               |
-     |  MDEV CORE    |
-     |   MODULE      |
-     |   mdev.ko     |
-     | +-----------+ |  mdev_register_device() +--------------+
-     | |           | +<------------------------+              |
-     | |           | |                         |  nvidia.ko   |<-> physical
-     | |           | +------------------------>+              |    device
-     | |           | |        callbacks        +--------------+
-     | | Physical  | |
-     | |  device   | |  mdev_register_device() +--------------+
-     | | interface | |<------------------------+              |
-     | |           | |                         |  i915.ko     |<-> physical
-     | |           | +------------------------>+              |    device
-     | |           | |        callbacks        +--------------+
-     | |           | |
-     | |           | |  mdev_register_device() +--------------+
-     | |           | +<------------------------+              |
-     | |           | |                         | ccw_device.ko|<-> physical
-     | |           | +------------------------>+              |    device
-     | |           | |        callbacks        +--------------+
-     | +-----------+ |
-     +---------------+
-
-
-Registration Interfaces
-=======================
-
-The mediated core driver provides the following types of registration
-interfaces:
-
-* Registration interface for a mediated bus driver
-* Physical device driver interface
-
-Registration Interface for a Mediated Bus Driver
-------------------------------------------------
-
-The registration interface for a mediated bus driver provides the following
-structure to represent a mediated device's driver::
-
-     /*
-      * struct mdev_driver [2] - Mediated device's driver
-      * @name: driver name
-      * @probe: called when new device created
-      * @remove: called when device removed
-      * @driver: device driver structure
-      */
-     struct mdev_driver {
-            const char *name;
-            int  (*probe)  (struct device *dev);
-            void (*remove) (struct device *dev);
-            struct device_driver    driver;
-     };
-
-A mediated bus driver for mdev should use this structure in the function calls
-to register and unregister itself with the core driver:
-
-* Register::
-
-    extern int  mdev_register_driver(struct mdev_driver *drv,
-                                  struct module *owner);
-
-* Unregister::
-
-    extern void mdev_unregister_driver(struct mdev_driver *drv);
-
-The mediated bus driver is responsible for adding mediated devices to the VFIO
-group when devices are bound to the driver and removing mediated devices from
-the VFIO when devices are unbound from the driver.
-
-
-Physical Device Driver Interface
---------------------------------
-
-The physical device driver interface provides the mdev_parent_ops[3] structure
-to define the APIs to manage work in the mediated core driver that is related
-to the physical device.
-
-The structures in the mdev_parent_ops structure are as follows:
-
-* dev_attr_groups: attributes of the parent device
-* mdev_attr_groups: attributes of the mediated device
-* supported_config: attributes to define supported configurations
-
-The functions in the mdev_parent_ops structure are as follows:
-
-* create: allocate basic resources in a driver for a mediated device
-* remove: free resources in a driver when a mediated device is destroyed
-
-(Note that mdev-core provides no implicit serialization of create/remove
-callbacks per mdev parent device, per mdev type, or any other categorization.
-Vendor drivers are expected to be fully asynchronous in this respect or
-provide their own internal resource protection.)
-
-The callbacks in the mdev_parent_ops structure are as follows:
-
-* open: open callback of mediated device
-* close: close callback of mediated device
-* ioctl: ioctl callback of mediated device
-* read : read emulation callback
-* write: write emulation callback
-* mmap: mmap emulation callback
-
-A driver should use the mdev_parent_ops structure in the function call to
-register itself with the mdev core driver::
-
-       extern int  mdev_register_device(struct device *dev,
-                                        const struct mdev_parent_ops *ops);
-
-However, the mdev_parent_ops structure is not required in the function call
-that a driver should use to unregister itself with the mdev core driver::
-
-       extern void mdev_unregister_device(struct device *dev);
-
-
-Mediated Device Management Interface Through sysfs
-==================================================
-
-The management interface through sysfs enables user space software, such as
-libvirt, to query and configure mediated devices in a hardware-agnostic fashion.
-This management interface provides flexibility to the underlying physical
-device's driver to support features such as:
-
-* Mediated device hot plug
-* Multiple mediated devices in a single virtual machine
-* Multiple mediated devices from different physical devices
-
-Links in the mdev_bus Class Directory
--------------------------------------
-The /sys/class/mdev_bus/ directory contains links to devices that are registered
-with the mdev core driver.
-
-Directories and files under the sysfs for Each Physical Device
---------------------------------------------------------------
-
-::
-
-  |- [parent physical device]
-  |--- Vendor-specific-attributes [optional]
-  |--- [mdev_supported_types]
-  |     |--- [<type-id>]
-  |     |   |--- create
-  |     |   |--- name
-  |     |   |--- available_instances
-  |     |   |--- device_api
-  |     |   |--- description
-  |     |   |--- [devices]
-  |     |--- [<type-id>]
-  |     |   |--- create
-  |     |   |--- name
-  |     |   |--- available_instances
-  |     |   |--- device_api
-  |     |   |--- description
-  |     |   |--- [devices]
-  |     |--- [<type-id>]
-  |          |--- create
-  |          |--- name
-  |          |--- available_instances
-  |          |--- device_api
-  |          |--- description
-  |          |--- [devices]
-
-* [mdev_supported_types]
-
-  The list of currently supported mediated device types and their details.
-
-  [<type-id>], device_api, and available_instances are mandatory attributes
-  that should be provided by vendor driver.
-
-* [<type-id>]
-
-  The [<type-id>] name is created by adding the device driver string as a prefix
-  to the string provided by the vendor driver. This format of this name is as
-  follows::
-
-       sprintf(buf, "%s-%s", dev_driver_string(parent->dev), group->name);
-
-  (or using mdev_parent_dev(mdev) to arrive at the parent device outside
-  of the core mdev code)
-
-* device_api
-
-  This attribute should show which device API is being created, for example,
-  "vfio-pci" for a PCI device.
-
-* available_instances
-
-  This attribute should show the number of devices of type <type-id> that can be
-  created.
-
-* [device]
-
-  This directory contains links to the devices of type <type-id> that have been
-  created.
-
-* name
-
-  This attribute should show human readable name. This is optional attribute.
-
-* description
-
-  This attribute should show brief features/description of the type. This is
-  optional attribute.
-
-Directories and Files Under the sysfs for Each mdev Device
-----------------------------------------------------------
-
-::
-
-  |- [parent phy device]
-  |--- [$MDEV_UUID]
-         |--- remove
-         |--- mdev_type {link to its type}
-         |--- vendor-specific-attributes [optional]
-
-* remove (write only)
-
-Writing '1' to the 'remove' file destroys the mdev device. The vendor driver can
-fail the remove() callback if that device is active and the vendor driver
-doesn't support hot unplug.
-
-Example::
-
-       # echo 1 > /sys/bus/mdev/devices/$mdev_UUID/remove
-
-Mediated device Hot plug
-------------------------
-
-Mediated devices can be created and assigned at runtime. The procedure to hot
-plug a mediated device is the same as the procedure to hot plug a PCI device.
-
-Translation APIs for Mediated Devices
-=====================================
-
-The following APIs are provided for translating user pfn to host pfn in a VFIO
-driver::
-
-       extern int vfio_pin_pages(struct device *dev, unsigned long *user_pfn,
-                                 int npage, int prot, unsigned long *phys_pfn);
-
-       extern int vfio_unpin_pages(struct device *dev, unsigned long *user_pfn,
-                                   int npage);
-
-These functions call back into the back-end IOMMU module by using the pin_pages
-and unpin_pages callbacks of the struct vfio_iommu_driver_ops[4]. Currently
-these callbacks are supported in the TYPE1 IOMMU module. To enable them for
-other IOMMU backend modules, such as PPC64 sPAPR module, they need to provide
-these two callback functions.
-
-Using the Sample Code
-=====================
-
-mtty.c in samples/vfio-mdev/ directory is a sample driver program to
-demonstrate how to use the mediated device framework.
-
-The sample driver creates an mdev device that simulates a serial port over a PCI
-card.
-
-1. Build and load the mtty.ko module.
-
-   This step creates a dummy device, /sys/devices/virtual/mtty/mtty/
-
-   Files in this device directory in sysfs are similar to the following::
-
-     # tree /sys/devices/virtual/mtty/mtty/
-        /sys/devices/virtual/mtty/mtty/
-        |-- mdev_supported_types
-        |   |-- mtty-1
-        |   |   |-- available_instances
-        |   |   |-- create
-        |   |   |-- device_api
-        |   |   |-- devices
-        |   |   `-- name
-        |   `-- mtty-2
-        |       |-- available_instances
-        |       |-- create
-        |       |-- device_api
-        |       |-- devices
-        |       `-- name
-        |-- mtty_dev
-        |   `-- sample_mtty_dev
-        |-- power
-        |   |-- autosuspend_delay_ms
-        |   |-- control
-        |   |-- runtime_active_time
-        |   |-- runtime_status
-        |   `-- runtime_suspended_time
-        |-- subsystem -> ../../../../class/mtty
-        `-- uevent
-
-2. Create a mediated device by using the dummy device that you created in the
-   previous step::
-
-     # echo "83b8f4f2-509f-382f-3c1e-e6bfe0fa1001" >   \
-              /sys/devices/virtual/mtty/mtty/mdev_supported_types/mtty-2/create
-
-3. Add parameters to qemu-kvm::
-
-     -device vfio-pci,\
-      sysfsdev=/sys/bus/mdev/devices/83b8f4f2-509f-382f-3c1e-e6bfe0fa1001
-
-4. Boot the VM.
-
-   In the Linux guest VM, with no hardware on the host, the device appears
-   as  follows::
-
-     # lspci -s 00:05.0 -xxvv
-     00:05.0 Serial controller: Device 4348:3253 (rev 10) (prog-if 02 [16550])
-             Subsystem: Device 4348:3253
-             Physical Slot: 5
-             Control: I/O+ Mem- BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr-
-     Stepping- SERR- FastB2B- DisINTx-
-             Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort-
-     <TAbort- <MAbort- >SERR- <PERR- INTx-
-             Interrupt: pin A routed to IRQ 10
-             Region 0: I/O ports at c150 [size=8]
-             Region 1: I/O ports at c158 [size=8]
-             Kernel driver in use: serial
-     00: 48 43 53 32 01 00 00 02 10 02 00 07 00 00 00 00
-     10: 51 c1 00 00 59 c1 00 00 00 00 00 00 00 00 00 00
-     20: 00 00 00 00 00 00 00 00 00 00 00 00 48 43 53 32
-     30: 00 00 00 00 00 00 00 00 00 00 00 00 0a 01 00 00
-
-     In the Linux guest VM, dmesg output for the device is as follows:
-
-     serial 0000:00:05.0: PCI INT A -> Link[LNKA] -> GSI 10 (level, high) -> IRQ 10
-     0000:00:05.0: ttyS1 at I/O 0xc150 (irq = 10) is a 16550A
-     0000:00:05.0: ttyS2 at I/O 0xc158 (irq = 10) is a 16550A
-
-
-5. In the Linux guest VM, check the serial ports::
-
-     # setserial -g /dev/ttyS*
-     /dev/ttyS0, UART: 16550A, Port: 0x03f8, IRQ: 4
-     /dev/ttyS1, UART: 16550A, Port: 0xc150, IRQ: 10
-     /dev/ttyS2, UART: 16550A, Port: 0xc158, IRQ: 10
-
-6. Using minicom or any terminal emulation program, open port /dev/ttyS1 or
-   /dev/ttyS2 with hardware flow control disabled.
-
-7. Type data on the minicom terminal or send data to the terminal emulation
-   program and read the data.
-
-   Data is loop backed from hosts mtty driver.
-
-8. Destroy the mediated device that you created::
-
-     # echo 1 > /sys/bus/mdev/devices/83b8f4f2-509f-382f-3c1e-e6bfe0fa1001/remove
-
-References
-==========
-
-1. See Documentation/vfio.txt for more information on VFIO.
-2. struct mdev_driver in include/linux/mdev.h
-3. struct mdev_parent_ops in include/linux/mdev.h
-4. struct vfio_iommu_driver_ops in include/linux/vfio.h
diff --git a/Documentation/virt/kvm/api.txt b/Documentation/virt/kvm/api.txt
new file mode 100644 (file)
index 0000000..2d06776
--- /dev/null
@@ -0,0 +1,5296 @@
+The Definitive KVM (Kernel-based Virtual Machine) API Documentation
+===================================================================
+
+1. General description
+----------------------
+
+The kvm API is a set of ioctls that are issued to control various aspects
+of a virtual machine.  The ioctls belong to three classes:
+
+ - System ioctls: These query and set global attributes which affect the
+   whole kvm subsystem.  In addition a system ioctl is used to create
+   virtual machines.
+
+ - VM ioctls: These query and set attributes that affect an entire virtual
+   machine, for example memory layout.  In addition a VM ioctl is used to
+   create virtual cpus (vcpus) and devices.
+
+   VM ioctls must be issued from the same process (address space) that was
+   used to create the VM.
+
+ - vcpu ioctls: These query and set attributes that control the operation
+   of a single virtual cpu.
+
+   vcpu ioctls should be issued from the same thread that was used to create
+   the vcpu, except for asynchronous vcpu ioctl that are marked as such in
+   the documentation.  Otherwise, the first ioctl after switching threads
+   could see a performance impact.
+
+ - device ioctls: These query and set attributes that control the operation
+   of a single device.
+
+   device ioctls must be issued from the same process (address space) that
+   was used to create the VM.
+
+2. File descriptors
+-------------------
+
+The kvm API is centered around file descriptors.  An initial
+open("/dev/kvm") obtains a handle to the kvm subsystem; this handle
+can be used to issue system ioctls.  A KVM_CREATE_VM ioctl on this
+handle will create a VM file descriptor which can be used to issue VM
+ioctls.  A KVM_CREATE_VCPU or KVM_CREATE_DEVICE ioctl on a VM fd will
+create a virtual cpu or device and return a file descriptor pointing to
+the new resource.  Finally, ioctls on a vcpu or device fd can be used
+to control the vcpu or device.  For vcpus, this includes the important
+task of actually running guest code.
+
+In general file descriptors can be migrated among processes by means
+of fork() and the SCM_RIGHTS facility of unix domain socket.  These
+kinds of tricks are explicitly not supported by kvm.  While they will
+not cause harm to the host, their actual behavior is not guaranteed by
+the API.  See "General description" for details on the ioctl usage
+model that is supported by KVM.
+
+It is important to note that althought VM ioctls may only be issued from
+the process that created the VM, a VM's lifecycle is associated with its
+file descriptor, not its creator (process).  In other words, the VM and
+its resources, *including the associated address space*, are not freed
+until the last reference to the VM's file descriptor has been released.
+For example, if fork() is issued after ioctl(KVM_CREATE_VM), the VM will
+not be freed until both the parent (original) process and its child have
+put their references to the VM's file descriptor.
+
+Because a VM's resources are not freed until the last reference to its
+file descriptor is released, creating additional references to a VM via
+via fork(), dup(), etc... without careful consideration is strongly
+discouraged and may have unwanted side effects, e.g. memory allocated
+by and on behalf of the VM's process may not be freed/unaccounted when
+the VM is shut down.
+
+
+3. Extensions
+-------------
+
+As of Linux 2.6.22, the KVM ABI has been stabilized: no backward
+incompatible change are allowed.  However, there is an extension
+facility that allows backward-compatible extensions to the API to be
+queried and used.
+
+The extension mechanism is not based on the Linux version number.
+Instead, kvm defines extension identifiers and a facility to query
+whether a particular extension identifier is available.  If it is, a
+set of ioctls is available for application use.
+
+
+4. API description
+------------------
+
+This section describes ioctls that can be used to control kvm guests.
+For each ioctl, the following information is provided along with a
+description:
+
+  Capability: which KVM extension provides this ioctl.  Can be 'basic',
+      which means that is will be provided by any kernel that supports
+      API version 12 (see section 4.1), a KVM_CAP_xyz constant, which
+      means availability needs to be checked with KVM_CHECK_EXTENSION
+      (see section 4.4), or 'none' which means that while not all kernels
+      support this ioctl, there's no capability bit to check its
+      availability: for kernels that don't support the ioctl,
+      the ioctl returns -ENOTTY.
+
+  Architectures: which instruction set architectures provide this ioctl.
+      x86 includes both i386 and x86_64.
+
+  Type: system, vm, or vcpu.
+
+  Parameters: what parameters are accepted by the ioctl.
+
+  Returns: the return value.  General error numbers (EBADF, ENOMEM, EINVAL)
+      are not detailed, but errors with specific meanings are.
+
+
+4.1 KVM_GET_API_VERSION
+
+Capability: basic
+Architectures: all
+Type: system ioctl
+Parameters: none
+Returns: the constant KVM_API_VERSION (=12)
+
+This identifies the API version as the stable kvm API. It is not
+expected that this number will change.  However, Linux 2.6.20 and
+2.6.21 report earlier versions; these are not documented and not
+supported.  Applications should refuse to run if KVM_GET_API_VERSION
+returns a value other than 12.  If this check passes, all ioctls
+described as 'basic' will be available.
+
+
+4.2 KVM_CREATE_VM
+
+Capability: basic
+Architectures: all
+Type: system ioctl
+Parameters: machine type identifier (KVM_VM_*)
+Returns: a VM fd that can be used to control the new virtual machine.
+
+The new VM has no virtual cpus and no memory.
+You probably want to use 0 as machine type.
+
+In order to create user controlled virtual machines on S390, check
+KVM_CAP_S390_UCONTROL and use the flag KVM_VM_S390_UCONTROL as
+privileged user (CAP_SYS_ADMIN).
+
+To use hardware assisted virtualization on MIPS (VZ ASE) rather than
+the default trap & emulate implementation (which changes the virtual
+memory layout to fit in user mode), check KVM_CAP_MIPS_VZ and use the
+flag KVM_VM_MIPS_VZ.
+
+
+On arm64, the physical address size for a VM (IPA Size limit) is limited
+to 40bits by default. The limit can be configured if the host supports the
+extension KVM_CAP_ARM_VM_IPA_SIZE. When supported, use
+KVM_VM_TYPE_ARM_IPA_SIZE(IPA_Bits) to set the size in the machine type
+identifier, where IPA_Bits is the maximum width of any physical
+address used by the VM. The IPA_Bits is encoded in bits[7-0] of the
+machine type identifier.
+
+e.g, to configure a guest to use 48bit physical address size :
+
+    vm_fd = ioctl(dev_fd, KVM_CREATE_VM, KVM_VM_TYPE_ARM_IPA_SIZE(48));
+
+The requested size (IPA_Bits) must be :
+  0 - Implies default size, 40bits (for backward compatibility)
+
+  or
+
+  N - Implies N bits, where N is a positive integer such that,
+      32 <= N <= Host_IPA_Limit
+
+Host_IPA_Limit is the maximum possible value for IPA_Bits on the host and
+is dependent on the CPU capability and the kernel configuration. The limit can
+be retrieved using KVM_CAP_ARM_VM_IPA_SIZE of the KVM_CHECK_EXTENSION
+ioctl() at run-time.
+
+Please note that configuring the IPA size does not affect the capability
+exposed by the guest CPUs in ID_AA64MMFR0_EL1[PARange]. It only affects
+size of the address translated by the stage2 level (guest physical to
+host physical address translations).
+
+
+4.3 KVM_GET_MSR_INDEX_LIST, KVM_GET_MSR_FEATURE_INDEX_LIST
+
+Capability: basic, KVM_CAP_GET_MSR_FEATURES for KVM_GET_MSR_FEATURE_INDEX_LIST
+Architectures: x86
+Type: system ioctl
+Parameters: struct kvm_msr_list (in/out)
+Returns: 0 on success; -1 on error
+Errors:
+  EFAULT:    the msr index list cannot be read from or written to
+  E2BIG:     the msr index list is to be to fit in the array specified by
+             the user.
+
+struct kvm_msr_list {
+       __u32 nmsrs; /* number of msrs in entries */
+       __u32 indices[0];
+};
+
+The user fills in the size of the indices array in nmsrs, and in return
+kvm adjusts nmsrs to reflect the actual number of msrs and fills in the
+indices array with their numbers.
+
+KVM_GET_MSR_INDEX_LIST returns the guest msrs that are supported.  The list
+varies by kvm version and host processor, but does not change otherwise.
+
+Note: if kvm indicates supports MCE (KVM_CAP_MCE), then the MCE bank MSRs are
+not returned in the MSR list, as different vcpus can have a different number
+of banks, as set via the KVM_X86_SETUP_MCE ioctl.
+
+KVM_GET_MSR_FEATURE_INDEX_LIST returns the list of MSRs that can be passed
+to the KVM_GET_MSRS system ioctl.  This lets userspace probe host capabilities
+and processor features that are exposed via MSRs (e.g., VMX capabilities).
+This list also varies by kvm version and host processor, but does not change
+otherwise.
+
+
+4.4 KVM_CHECK_EXTENSION
+
+Capability: basic, KVM_CAP_CHECK_EXTENSION_VM for vm ioctl
+Architectures: all
+Type: system ioctl, vm ioctl
+Parameters: extension identifier (KVM_CAP_*)
+Returns: 0 if unsupported; 1 (or some other positive integer) if supported
+
+The API allows the application to query about extensions to the core
+kvm API.  Userspace passes an extension identifier (an integer) and
+receives an integer that describes the extension availability.
+Generally 0 means no and 1 means yes, but some extensions may report
+additional information in the integer return value.
+
+Based on their initialization different VMs may have different capabilities.
+It is thus encouraged to use the vm ioctl to query for capabilities (available
+with KVM_CAP_CHECK_EXTENSION_VM on the vm fd)
+
+4.5 KVM_GET_VCPU_MMAP_SIZE
+
+Capability: basic
+Architectures: all
+Type: system ioctl
+Parameters: none
+Returns: size of vcpu mmap area, in bytes
+
+The KVM_RUN ioctl (cf.) communicates with userspace via a shared
+memory region.  This ioctl returns the size of that region.  See the
+KVM_RUN documentation for details.
+
+
+4.6 KVM_SET_MEMORY_REGION
+
+Capability: basic
+Architectures: all
+Type: vm ioctl
+Parameters: struct kvm_memory_region (in)
+Returns: 0 on success, -1 on error
+
+This ioctl is obsolete and has been removed.
+
+
+4.7 KVM_CREATE_VCPU
+
+Capability: basic
+Architectures: all
+Type: vm ioctl
+Parameters: vcpu id (apic id on x86)
+Returns: vcpu fd on success, -1 on error
+
+This API adds a vcpu to a virtual machine. No more than max_vcpus may be added.
+The vcpu id is an integer in the range [0, max_vcpu_id).
+
+The recommended max_vcpus value can be retrieved using the KVM_CAP_NR_VCPUS of
+the KVM_CHECK_EXTENSION ioctl() at run-time.
+The maximum possible value for max_vcpus can be retrieved using the
+KVM_CAP_MAX_VCPUS of the KVM_CHECK_EXTENSION ioctl() at run-time.
+
+If the KVM_CAP_NR_VCPUS does not exist, you should assume that max_vcpus is 4
+cpus max.
+If the KVM_CAP_MAX_VCPUS does not exist, you should assume that max_vcpus is
+same as the value returned from KVM_CAP_NR_VCPUS.
+
+The maximum possible value for max_vcpu_id can be retrieved using the
+KVM_CAP_MAX_VCPU_ID of the KVM_CHECK_EXTENSION ioctl() at run-time.
+
+If the KVM_CAP_MAX_VCPU_ID does not exist, you should assume that max_vcpu_id
+is the same as the value returned from KVM_CAP_MAX_VCPUS.
+
+On powerpc using book3s_hv mode, the vcpus are mapped onto virtual
+threads in one or more virtual CPU cores.  (This is because the
+hardware requires all the hardware threads in a CPU core to be in the
+same partition.)  The KVM_CAP_PPC_SMT capability indicates the number
+of vcpus per virtual core (vcore).  The vcore id is obtained by
+dividing the vcpu id by the number of vcpus per vcore.  The vcpus in a
+given vcore will always be in the same physical core as each other
+(though that might be a different physical core from time to time).
+Userspace can control the threading (SMT) mode of the guest by its
+allocation of vcpu ids.  For example, if userspace wants
+single-threaded guest vcpus, it should make all vcpu ids be a multiple
+of the number of vcpus per vcore.
+
+For virtual cpus that have been created with S390 user controlled virtual
+machines, the resulting vcpu fd can be memory mapped at page offset
+KVM_S390_SIE_PAGE_OFFSET in order to obtain a memory map of the virtual
+cpu's hardware control block.
+
+
+4.8 KVM_GET_DIRTY_LOG (vm ioctl)
+
+Capability: basic
+Architectures: all
+Type: vm ioctl
+Parameters: struct kvm_dirty_log (in/out)
+Returns: 0 on success, -1 on error
+
+/* for KVM_GET_DIRTY_LOG */
+struct kvm_dirty_log {
+       __u32 slot;
+       __u32 padding;
+       union {
+               void __user *dirty_bitmap; /* one bit per page */
+               __u64 padding;
+       };
+};
+
+Given a memory slot, return a bitmap containing any pages dirtied
+since the last call to this ioctl.  Bit 0 is the first page in the
+memory slot.  Ensure the entire structure is cleared to avoid padding
+issues.
+
+If KVM_CAP_MULTI_ADDRESS_SPACE is available, bits 16-31 specifies
+the address space for which you want to return the dirty bitmap.
+They must be less than the value that KVM_CHECK_EXTENSION returns for
+the KVM_CAP_MULTI_ADDRESS_SPACE capability.
+
+The bits in the dirty bitmap are cleared before the ioctl returns, unless
+KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 is enabled.  For more information,
+see the description of the capability.
+
+4.9 KVM_SET_MEMORY_ALIAS
+
+Capability: basic
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_memory_alias (in)
+Returns: 0 (success), -1 (error)
+
+This ioctl is obsolete and has been removed.
+
+
+4.10 KVM_RUN
+
+Capability: basic
+Architectures: all
+Type: vcpu ioctl
+Parameters: none
+Returns: 0 on success, -1 on error
+Errors:
+  EINTR:     an unmasked signal is pending
+
+This ioctl is used to run a guest virtual cpu.  While there are no
+explicit parameters, there is an implicit parameter block that can be
+obtained by mmap()ing the vcpu fd at offset 0, with the size given by
+KVM_GET_VCPU_MMAP_SIZE.  The parameter block is formatted as a 'struct
+kvm_run' (see below).
+
+
+4.11 KVM_GET_REGS
+
+Capability: basic
+Architectures: all except ARM, arm64
+Type: vcpu ioctl
+Parameters: struct kvm_regs (out)
+Returns: 0 on success, -1 on error
+
+Reads the general purpose registers from the vcpu.
+
+/* x86 */
+struct kvm_regs {
+       /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
+       __u64 rax, rbx, rcx, rdx;
+       __u64 rsi, rdi, rsp, rbp;
+       __u64 r8,  r9,  r10, r11;
+       __u64 r12, r13, r14, r15;
+       __u64 rip, rflags;
+};
+
+/* mips */
+struct kvm_regs {
+       /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
+       __u64 gpr[32];
+       __u64 hi;
+       __u64 lo;
+       __u64 pc;
+};
+
+
+4.12 KVM_SET_REGS
+
+Capability: basic
+Architectures: all except ARM, arm64
+Type: vcpu ioctl
+Parameters: struct kvm_regs (in)
+Returns: 0 on success, -1 on error
+
+Writes the general purpose registers into the vcpu.
+
+See KVM_GET_REGS for the data structure.
+
+
+4.13 KVM_GET_SREGS
+
+Capability: basic
+Architectures: x86, ppc
+Type: vcpu ioctl
+Parameters: struct kvm_sregs (out)
+Returns: 0 on success, -1 on error
+
+Reads special registers from the vcpu.
+
+/* x86 */
+struct kvm_sregs {
+       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 interrupt_bitmap[(KVM_NR_INTERRUPTS + 63) / 64];
+};
+
+/* ppc -- see arch/powerpc/include/uapi/asm/kvm.h */
+
+interrupt_bitmap is a bitmap of pending external interrupts.  At most
+one bit may be set.  This interrupt has been acknowledged by the APIC
+but not yet injected into the cpu core.
+
+
+4.14 KVM_SET_SREGS
+
+Capability: basic
+Architectures: x86, ppc
+Type: vcpu ioctl
+Parameters: struct kvm_sregs (in)
+Returns: 0 on success, -1 on error
+
+Writes special registers into the vcpu.  See KVM_GET_SREGS for the
+data structures.
+
+
+4.15 KVM_TRANSLATE
+
+Capability: basic
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_translation (in/out)
+Returns: 0 on success, -1 on error
+
+Translates a virtual address according to the vcpu's current address
+translation mode.
+
+struct kvm_translation {
+       /* in */
+       __u64 linear_address;
+
+       /* out */
+       __u64 physical_address;
+       __u8  valid;
+       __u8  writeable;
+       __u8  usermode;
+       __u8  pad[5];
+};
+
+
+4.16 KVM_INTERRUPT
+
+Capability: basic
+Architectures: x86, ppc, mips
+Type: vcpu ioctl
+Parameters: struct kvm_interrupt (in)
+Returns: 0 on success, negative on failure.
+
+Queues a hardware interrupt vector to be injected.
+
+/* for KVM_INTERRUPT */
+struct kvm_interrupt {
+       /* in */
+       __u32 irq;
+};
+
+X86:
+
+Returns: 0 on success,
+        -EEXIST if an interrupt is already enqueued
+        -EINVAL the the irq number is invalid
+        -ENXIO if the PIC is in the kernel
+        -EFAULT if the pointer is invalid
+
+Note 'irq' is an interrupt vector, not an interrupt pin or line. This
+ioctl is useful if the in-kernel PIC is not used.
+
+PPC:
+
+Queues an external interrupt to be injected. This ioctl is overleaded
+with 3 different irq values:
+
+a) KVM_INTERRUPT_SET
+
+  This injects an edge type external interrupt into the guest once it's ready
+  to receive interrupts. When injected, the interrupt is done.
+
+b) KVM_INTERRUPT_UNSET
+
+  This unsets any pending interrupt.
+
+  Only available with KVM_CAP_PPC_UNSET_IRQ.
+
+c) KVM_INTERRUPT_SET_LEVEL
+
+  This injects a level type external interrupt into the guest context. The
+  interrupt stays pending until a specific ioctl with KVM_INTERRUPT_UNSET
+  is triggered.
+
+  Only available with KVM_CAP_PPC_IRQ_LEVEL.
+
+Note that any value for 'irq' other than the ones stated above is invalid
+and incurs unexpected behavior.
+
+This is an asynchronous vcpu ioctl and can be invoked from any thread.
+
+MIPS:
+
+Queues an external interrupt to be injected into the virtual CPU. A negative
+interrupt number dequeues the interrupt.
+
+This is an asynchronous vcpu ioctl and can be invoked from any thread.
+
+
+4.17 KVM_DEBUG_GUEST
+
+Capability: basic
+Architectures: none
+Type: vcpu ioctl
+Parameters: none)
+Returns: -1 on error
+
+Support for this has been removed.  Use KVM_SET_GUEST_DEBUG instead.
+
+
+4.18 KVM_GET_MSRS
+
+Capability: basic (vcpu), KVM_CAP_GET_MSR_FEATURES (system)
+Architectures: x86
+Type: system ioctl, vcpu ioctl
+Parameters: struct kvm_msrs (in/out)
+Returns: number of msrs successfully returned;
+        -1 on error
+
+When used as a system ioctl:
+Reads the values of MSR-based features that are available for the VM.  This
+is similar to KVM_GET_SUPPORTED_CPUID, but it returns MSR indices and values.
+The list of msr-based features can be obtained using KVM_GET_MSR_FEATURE_INDEX_LIST
+in a system ioctl.
+
+When used as a vcpu ioctl:
+Reads model-specific registers from the vcpu.  Supported msr indices can
+be obtained using KVM_GET_MSR_INDEX_LIST in a system ioctl.
+
+struct kvm_msrs {
+       __u32 nmsrs; /* number of msrs in entries */
+       __u32 pad;
+
+       struct kvm_msr_entry entries[0];
+};
+
+struct kvm_msr_entry {
+       __u32 index;
+       __u32 reserved;
+       __u64 data;
+};
+
+Application code should set the 'nmsrs' member (which indicates the
+size of the entries array) and the 'index' member of each array entry.
+kvm will fill in the 'data' member.
+
+
+4.19 KVM_SET_MSRS
+
+Capability: basic
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_msrs (in)
+Returns: 0 on success, -1 on error
+
+Writes model-specific registers to the vcpu.  See KVM_GET_MSRS for the
+data structures.
+
+Application code should set the 'nmsrs' member (which indicates the
+size of the entries array), and the 'index' and 'data' members of each
+array entry.
+
+
+4.20 KVM_SET_CPUID
+
+Capability: basic
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_cpuid (in)
+Returns: 0 on success, -1 on error
+
+Defines the vcpu responses to the cpuid instruction.  Applications
+should use the KVM_SET_CPUID2 ioctl if available.
+
+
+struct kvm_cpuid_entry {
+       __u32 function;
+       __u32 eax;
+       __u32 ebx;
+       __u32 ecx;
+       __u32 edx;
+       __u32 padding;
+};
+
+/* for KVM_SET_CPUID */
+struct kvm_cpuid {
+       __u32 nent;
+       __u32 padding;
+       struct kvm_cpuid_entry entries[0];
+};
+
+
+4.21 KVM_SET_SIGNAL_MASK
+
+Capability: basic
+Architectures: all
+Type: vcpu ioctl
+Parameters: struct kvm_signal_mask (in)
+Returns: 0 on success, -1 on error
+
+Defines which signals are blocked during execution of KVM_RUN.  This
+signal mask temporarily overrides the threads signal mask.  Any
+unblocked signal received (except SIGKILL and SIGSTOP, which retain
+their traditional behaviour) will cause KVM_RUN to return with -EINTR.
+
+Note the signal will only be delivered if not blocked by the original
+signal mask.
+
+/* for KVM_SET_SIGNAL_MASK */
+struct kvm_signal_mask {
+       __u32 len;
+       __u8  sigset[0];
+};
+
+
+4.22 KVM_GET_FPU
+
+Capability: basic
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_fpu (out)
+Returns: 0 on success, -1 on error
+
+Reads the floating point state from the vcpu.
+
+/* for KVM_GET_FPU and KVM_SET_FPU */
+struct kvm_fpu {
+       __u8  fpr[8][16];
+       __u16 fcw;
+       __u16 fsw;
+       __u8  ftwx;  /* in fxsave format */
+       __u8  pad1;
+       __u16 last_opcode;
+       __u64 last_ip;
+       __u64 last_dp;
+       __u8  xmm[16][16];
+       __u32 mxcsr;
+       __u32 pad2;
+};
+
+
+4.23 KVM_SET_FPU
+
+Capability: basic
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_fpu (in)
+Returns: 0 on success, -1 on error
+
+Writes the floating point state to the vcpu.
+
+/* for KVM_GET_FPU and KVM_SET_FPU */
+struct kvm_fpu {
+       __u8  fpr[8][16];
+       __u16 fcw;
+       __u16 fsw;
+       __u8  ftwx;  /* in fxsave format */
+       __u8  pad1;
+       __u16 last_opcode;
+       __u64 last_ip;
+       __u64 last_dp;
+       __u8  xmm[16][16];
+       __u32 mxcsr;
+       __u32 pad2;
+};
+
+
+4.24 KVM_CREATE_IRQCHIP
+
+Capability: KVM_CAP_IRQCHIP, KVM_CAP_S390_IRQCHIP (s390)
+Architectures: x86, ARM, arm64, s390
+Type: vm ioctl
+Parameters: none
+Returns: 0 on success, -1 on error
+
+Creates an interrupt controller model in the kernel.
+On x86, creates a virtual ioapic, a virtual PIC (two PICs, nested), and sets up
+future vcpus to have a local APIC.  IRQ routing for GSIs 0-15 is set to both
+PIC and IOAPIC; GSI 16-23 only go to the IOAPIC.
+On ARM/arm64, a GICv2 is created. Any other GIC versions require the usage of
+KVM_CREATE_DEVICE, which also supports creating a GICv2.  Using
+KVM_CREATE_DEVICE is preferred over KVM_CREATE_IRQCHIP for GICv2.
+On s390, a dummy irq routing table is created.
+
+Note that on s390 the KVM_CAP_S390_IRQCHIP vm capability needs to be enabled
+before KVM_CREATE_IRQCHIP can be used.
+
+
+4.25 KVM_IRQ_LINE
+
+Capability: KVM_CAP_IRQCHIP
+Architectures: x86, arm, arm64
+Type: vm ioctl
+Parameters: struct kvm_irq_level
+Returns: 0 on success, -1 on error
+
+Sets the level of a GSI input to the interrupt controller model in the kernel.
+On some architectures it is required that an interrupt controller model has
+been previously created with KVM_CREATE_IRQCHIP.  Note that edge-triggered
+interrupts require the level to be set to 1 and then back to 0.
+
+On real hardware, interrupt pins can be active-low or active-high.  This
+does not matter for the level field of struct kvm_irq_level: 1 always
+means active (asserted), 0 means inactive (deasserted).
+
+x86 allows the operating system to program the interrupt polarity
+(active-low/active-high) for level-triggered interrupts, and KVM used
+to consider the polarity.  However, due to bitrot in the handling of
+active-low interrupts, the above convention is now valid on x86 too.
+This is signaled by KVM_CAP_X86_IOAPIC_POLARITY_IGNORED.  Userspace
+should not present interrupts to the guest as active-low unless this
+capability is present (or unless it is not using the in-kernel irqchip,
+of course).
+
+
+ARM/arm64 can signal an interrupt either at the CPU level, or at the
+in-kernel irqchip (GIC), and for in-kernel irqchip can tell the GIC to
+use PPIs designated for specific cpus.  The irq field is interpreted
+like this:
+
+  bits:  | 31 ... 24 | 23  ... 16 | 15    ...    0 |
+  field: | irq_type  | vcpu_index |     irq_id     |
+
+The irq_type field has the following values:
+- irq_type[0]: out-of-kernel GIC: irq_id 0 is IRQ, irq_id 1 is FIQ
+- irq_type[1]: in-kernel GIC: SPI, irq_id between 32 and 1019 (incl.)
+               (the vcpu_index field is ignored)
+- irq_type[2]: in-kernel GIC: PPI, irq_id between 16 and 31 (incl.)
+
+(The irq_id field thus corresponds nicely to the IRQ ID in the ARM GIC specs)
+
+In both cases, level is used to assert/deassert the line.
+
+struct kvm_irq_level {
+       union {
+               __u32 irq;     /* GSI */
+               __s32 status;  /* not used for KVM_IRQ_LEVEL */
+       };
+       __u32 level;           /* 0 or 1 */
+};
+
+
+4.26 KVM_GET_IRQCHIP
+
+Capability: KVM_CAP_IRQCHIP
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_irqchip (in/out)
+Returns: 0 on success, -1 on error
+
+Reads the state of a kernel interrupt controller created with
+KVM_CREATE_IRQCHIP into a buffer provided by the caller.
+
+struct kvm_irqchip {
+       __u32 chip_id;  /* 0 = PIC1, 1 = PIC2, 2 = IOAPIC */
+       __u32 pad;
+        union {
+               char dummy[512];  /* reserving space */
+               struct kvm_pic_state pic;
+               struct kvm_ioapic_state ioapic;
+       } chip;
+};
+
+
+4.27 KVM_SET_IRQCHIP
+
+Capability: KVM_CAP_IRQCHIP
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_irqchip (in)
+Returns: 0 on success, -1 on error
+
+Sets the state of a kernel interrupt controller created with
+KVM_CREATE_IRQCHIP from a buffer provided by the caller.
+
+struct kvm_irqchip {
+       __u32 chip_id;  /* 0 = PIC1, 1 = PIC2, 2 = IOAPIC */
+       __u32 pad;
+        union {
+               char dummy[512];  /* reserving space */
+               struct kvm_pic_state pic;
+               struct kvm_ioapic_state ioapic;
+       } chip;
+};
+
+
+4.28 KVM_XEN_HVM_CONFIG
+
+Capability: KVM_CAP_XEN_HVM
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_xen_hvm_config (in)
+Returns: 0 on success, -1 on error
+
+Sets the MSR that the Xen HVM guest uses to initialize its hypercall
+page, and provides the starting address and size of the hypercall
+blobs in userspace.  When the guest writes the MSR, kvm copies one
+page of a blob (32- or 64-bit, depending on the vcpu mode) to guest
+memory.
+
+struct kvm_xen_hvm_config {
+       __u32 flags;
+       __u32 msr;
+       __u64 blob_addr_32;
+       __u64 blob_addr_64;
+       __u8 blob_size_32;
+       __u8 blob_size_64;
+       __u8 pad2[30];
+};
+
+
+4.29 KVM_GET_CLOCK
+
+Capability: KVM_CAP_ADJUST_CLOCK
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_clock_data (out)
+Returns: 0 on success, -1 on error
+
+Gets the current timestamp of kvmclock as seen by the current guest. In
+conjunction with KVM_SET_CLOCK, it is used to ensure monotonicity on scenarios
+such as migration.
+
+When KVM_CAP_ADJUST_CLOCK is passed to KVM_CHECK_EXTENSION, it returns the
+set of bits that KVM can return in struct kvm_clock_data's flag member.
+
+The only flag defined now is KVM_CLOCK_TSC_STABLE.  If set, the returned
+value is the exact kvmclock value seen by all VCPUs at the instant
+when KVM_GET_CLOCK was called.  If clear, the returned value is simply
+CLOCK_MONOTONIC plus a constant offset; the offset can be modified
+with KVM_SET_CLOCK.  KVM will try to make all VCPUs follow this clock,
+but the exact value read by each VCPU could differ, because the host
+TSC is not stable.
+
+struct kvm_clock_data {
+       __u64 clock;  /* kvmclock current value */
+       __u32 flags;
+       __u32 pad[9];
+};
+
+
+4.30 KVM_SET_CLOCK
+
+Capability: KVM_CAP_ADJUST_CLOCK
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_clock_data (in)
+Returns: 0 on success, -1 on error
+
+Sets the current timestamp of kvmclock to the value specified in its parameter.
+In conjunction with KVM_GET_CLOCK, it is used to ensure monotonicity on scenarios
+such as migration.
+
+struct kvm_clock_data {
+       __u64 clock;  /* kvmclock current value */
+       __u32 flags;
+       __u32 pad[9];
+};
+
+
+4.31 KVM_GET_VCPU_EVENTS
+
+Capability: KVM_CAP_VCPU_EVENTS
+Extended by: KVM_CAP_INTR_SHADOW
+Architectures: x86, arm, arm64
+Type: vcpu ioctl
+Parameters: struct kvm_vcpu_event (out)
+Returns: 0 on success, -1 on error
+
+X86:
+
+Gets currently pending exceptions, interrupts, and NMIs as well as related
+states of the vcpu.
+
+struct kvm_vcpu_events {
+       struct {
+               __u8 injected;
+               __u8 nr;
+               __u8 has_error_code;
+               __u8 pending;
+               __u32 error_code;
+       } exception;
+       struct {
+               __u8 injected;
+               __u8 nr;
+               __u8 soft;
+               __u8 shadow;
+       } interrupt;
+       struct {
+               __u8 injected;
+               __u8 pending;
+               __u8 masked;
+               __u8 pad;
+       } nmi;
+       __u32 sipi_vector;
+       __u32 flags;
+       struct {
+               __u8 smm;
+               __u8 pending;
+               __u8 smm_inside_nmi;
+               __u8 latched_init;
+       } smi;
+       __u8 reserved[27];
+       __u8 exception_has_payload;
+       __u64 exception_payload;
+};
+
+The following bits are defined in the flags field:
+
+- KVM_VCPUEVENT_VALID_SHADOW may be set to signal that
+  interrupt.shadow contains a valid state.
+
+- KVM_VCPUEVENT_VALID_SMM may be set to signal that smi contains a
+  valid state.
+
+- KVM_VCPUEVENT_VALID_PAYLOAD may be set to signal that the
+  exception_has_payload, exception_payload, and exception.pending
+  fields contain a valid state. This bit will be set whenever
+  KVM_CAP_EXCEPTION_PAYLOAD is enabled.
+
+ARM/ARM64:
+
+If the guest accesses a device that is being emulated by the host kernel in
+such a way that a real device would generate a physical SError, KVM may make
+a virtual SError pending for that VCPU. This system error interrupt remains
+pending until the guest takes the exception by unmasking PSTATE.A.
+
+Running the VCPU may cause it to take a pending SError, or make an access that
+causes an SError to become pending. The event's description is only valid while
+the VPCU is not running.
+
+This API provides a way to read and write the pending 'event' state that is not
+visible to the guest. To save, restore or migrate a VCPU the struct representing
+the state can be read then written using this GET/SET API, along with the other
+guest-visible registers. It is not possible to 'cancel' an SError that has been
+made pending.
+
+A device being emulated in user-space may also wish to generate an SError. To do
+this the events structure can be populated by user-space. The current state
+should be read first, to ensure no existing SError is pending. If an existing
+SError is pending, the architecture's 'Multiple SError interrupts' rules should
+be followed. (2.5.3 of DDI0587.a "ARM Reliability, Availability, and
+Serviceability (RAS) Specification").
+
+SError exceptions always have an ESR value. Some CPUs have the ability to
+specify what the virtual SError's ESR value should be. These systems will
+advertise KVM_CAP_ARM_INJECT_SERROR_ESR. In this case exception.has_esr will
+always have a non-zero value when read, and the agent making an SError pending
+should specify the ISS field in the lower 24 bits of exception.serror_esr. If
+the system supports KVM_CAP_ARM_INJECT_SERROR_ESR, but user-space sets the events
+with exception.has_esr as zero, KVM will choose an ESR.
+
+Specifying exception.has_esr on a system that does not support it will return
+-EINVAL. Setting anything other than the lower 24bits of exception.serror_esr
+will return -EINVAL.
+
+struct kvm_vcpu_events {
+       struct {
+               __u8 serror_pending;
+               __u8 serror_has_esr;
+               /* Align it to 8 bytes */
+               __u8 pad[6];
+               __u64 serror_esr;
+       } exception;
+       __u32 reserved[12];
+};
+
+4.32 KVM_SET_VCPU_EVENTS
+
+Capability: KVM_CAP_VCPU_EVENTS
+Extended by: KVM_CAP_INTR_SHADOW
+Architectures: x86, arm, arm64
+Type: vcpu ioctl
+Parameters: struct kvm_vcpu_event (in)
+Returns: 0 on success, -1 on error
+
+X86:
+
+Set pending exceptions, interrupts, and NMIs as well as related states of the
+vcpu.
+
+See KVM_GET_VCPU_EVENTS for the data structure.
+
+Fields that may be modified asynchronously by running VCPUs can be excluded
+from the update. These fields are nmi.pending, sipi_vector, smi.smm,
+smi.pending. Keep the corresponding bits in the flags field cleared to
+suppress overwriting the current in-kernel state. The bits are:
+
+KVM_VCPUEVENT_VALID_NMI_PENDING - transfer nmi.pending to the kernel
+KVM_VCPUEVENT_VALID_SIPI_VECTOR - transfer sipi_vector
+KVM_VCPUEVENT_VALID_SMM         - transfer the smi sub-struct.
+
+If KVM_CAP_INTR_SHADOW is available, KVM_VCPUEVENT_VALID_SHADOW can be set in
+the flags field to signal that interrupt.shadow contains a valid state and
+shall be written into the VCPU.
+
+KVM_VCPUEVENT_VALID_SMM can only be set if KVM_CAP_X86_SMM is available.
+
+If KVM_CAP_EXCEPTION_PAYLOAD is enabled, KVM_VCPUEVENT_VALID_PAYLOAD
+can be set in the flags field to signal that the
+exception_has_payload, exception_payload, and exception.pending fields
+contain a valid state and shall be written into the VCPU.
+
+ARM/ARM64:
+
+Set the pending SError exception state for this VCPU. It is not possible to
+'cancel' an Serror that has been made pending.
+
+See KVM_GET_VCPU_EVENTS for the data structure.
+
+
+4.33 KVM_GET_DEBUGREGS
+
+Capability: KVM_CAP_DEBUGREGS
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_debugregs (out)
+Returns: 0 on success, -1 on error
+
+Reads debug registers from the vcpu.
+
+struct kvm_debugregs {
+       __u64 db[4];
+       __u64 dr6;
+       __u64 dr7;
+       __u64 flags;
+       __u64 reserved[9];
+};
+
+
+4.34 KVM_SET_DEBUGREGS
+
+Capability: KVM_CAP_DEBUGREGS
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_debugregs (in)
+Returns: 0 on success, -1 on error
+
+Writes debug registers into the vcpu.
+
+See KVM_GET_DEBUGREGS for the data structure. The flags field is unused
+yet and must be cleared on entry.
+
+
+4.35 KVM_SET_USER_MEMORY_REGION
+
+Capability: KVM_CAP_USER_MEMORY
+Architectures: all
+Type: vm ioctl
+Parameters: struct kvm_userspace_memory_region (in)
+Returns: 0 on success, -1 on error
+
+struct kvm_userspace_memory_region {
+       __u32 slot;
+       __u32 flags;
+       __u64 guest_phys_addr;
+       __u64 memory_size; /* bytes */
+       __u64 userspace_addr; /* start of the userspace allocated memory */
+};
+
+/* for kvm_memory_region::flags */
+#define KVM_MEM_LOG_DIRTY_PAGES        (1UL << 0)
+#define KVM_MEM_READONLY       (1UL << 1)
+
+This ioctl allows the user to create, modify or delete a guest physical
+memory slot.  Bits 0-15 of "slot" specify the slot id and this value
+should be less than the maximum number of user memory slots supported per
+VM.  The maximum allowed slots can be queried using KVM_CAP_NR_MEMSLOTS.
+Slots may not overlap in guest physical address space.
+
+If KVM_CAP_MULTI_ADDRESS_SPACE is available, bits 16-31 of "slot"
+specifies the address space which is being modified.  They must be
+less than the value that KVM_CHECK_EXTENSION returns for the
+KVM_CAP_MULTI_ADDRESS_SPACE capability.  Slots in separate address spaces
+are unrelated; the restriction on overlapping slots only applies within
+each address space.
+
+Deleting a slot is done by passing zero for memory_size.  When changing
+an existing slot, it may be moved in the guest physical memory space,
+or its flags may be modified, but it may not be resized.
+
+Memory for the region is taken starting at the address denoted by the
+field userspace_addr, which must point at user addressable memory for
+the entire memory slot size.  Any object may back this memory, including
+anonymous memory, ordinary files, and hugetlbfs.
+
+It is recommended that the lower 21 bits of guest_phys_addr and userspace_addr
+be identical.  This allows large pages in the guest to be backed by large
+pages in the host.
+
+The flags field supports two flags: KVM_MEM_LOG_DIRTY_PAGES and
+KVM_MEM_READONLY.  The former can be set to instruct KVM to keep track of
+writes to memory within the slot.  See KVM_GET_DIRTY_LOG ioctl to know how to
+use it.  The latter can be set, if KVM_CAP_READONLY_MEM capability allows it,
+to make a new slot read-only.  In this case, writes to this memory will be
+posted to userspace as KVM_EXIT_MMIO exits.
+
+When the KVM_CAP_SYNC_MMU capability is available, changes in the backing of
+the memory region are automatically reflected into the guest.  For example, an
+mmap() that affects the region will be made visible immediately.  Another
+example is madvise(MADV_DROP).
+
+It is recommended to use this API instead of the KVM_SET_MEMORY_REGION ioctl.
+The KVM_SET_MEMORY_REGION does not allow fine grained control over memory
+allocation and is deprecated.
+
+
+4.36 KVM_SET_TSS_ADDR
+
+Capability: KVM_CAP_SET_TSS_ADDR
+Architectures: x86
+Type: vm ioctl
+Parameters: unsigned long tss_address (in)
+Returns: 0 on success, -1 on error
+
+This ioctl defines the physical address of a three-page region in the guest
+physical address space.  The region must be within the first 4GB of the
+guest physical address space and must not conflict with any memory slot
+or any mmio address.  The guest may malfunction if it accesses this memory
+region.
+
+This ioctl is required on Intel-based hosts.  This is needed on Intel hardware
+because of a quirk in the virtualization implementation (see the internals
+documentation when it pops into existence).
+
+
+4.37 KVM_ENABLE_CAP
+
+Capability: KVM_CAP_ENABLE_CAP
+Architectures: mips, ppc, s390
+Type: vcpu ioctl
+Parameters: struct kvm_enable_cap (in)
+Returns: 0 on success; -1 on error
+
+Capability: KVM_CAP_ENABLE_CAP_VM
+Architectures: all
+Type: vcpu ioctl
+Parameters: struct kvm_enable_cap (in)
+Returns: 0 on success; -1 on error
+
++Not all extensions are enabled by default. Using this ioctl the application
+can enable an extension, making it available to the guest.
+
+On systems that do not support this ioctl, it always fails. On systems that
+do support it, it only works for extensions that are supported for enablement.
+
+To check if a capability can be enabled, the KVM_CHECK_EXTENSION ioctl should
+be used.
+
+struct kvm_enable_cap {
+       /* in */
+       __u32 cap;
+
+The capability that is supposed to get enabled.
+
+       __u32 flags;
+
+A bitfield indicating future enhancements. Has to be 0 for now.
+
+       __u64 args[4];
+
+Arguments for enabling a feature. If a feature needs initial values to
+function properly, this is the place to put them.
+
+       __u8  pad[64];
+};
+
+The vcpu ioctl should be used for vcpu-specific capabilities, the vm ioctl
+for vm-wide capabilities.
+
+4.38 KVM_GET_MP_STATE
+
+Capability: KVM_CAP_MP_STATE
+Architectures: x86, s390, arm, arm64
+Type: vcpu ioctl
+Parameters: struct kvm_mp_state (out)
+Returns: 0 on success; -1 on error
+
+struct kvm_mp_state {
+       __u32 mp_state;
+};
+
+Returns the vcpu's current "multiprocessing state" (though also valid on
+uniprocessor guests).
+
+Possible values are:
+
+ - KVM_MP_STATE_RUNNABLE:        the vcpu is currently running [x86,arm/arm64]
+ - KVM_MP_STATE_UNINITIALIZED:   the vcpu is an application processor (AP)
+                                 which has not yet received an INIT signal [x86]
+ - KVM_MP_STATE_INIT_RECEIVED:   the vcpu has received an INIT signal, and is
+                                 now ready for a SIPI [x86]
+ - KVM_MP_STATE_HALTED:          the vcpu has executed a HLT instruction and
+                                 is waiting for an interrupt [x86]
+ - KVM_MP_STATE_SIPI_RECEIVED:   the vcpu has just received a SIPI (vector
+                                 accessible via KVM_GET_VCPU_EVENTS) [x86]
+ - KVM_MP_STATE_STOPPED:         the vcpu is stopped [s390,arm/arm64]
+ - KVM_MP_STATE_CHECK_STOP:      the vcpu is in a special error state [s390]
+ - KVM_MP_STATE_OPERATING:       the vcpu is operating (running or halted)
+                                 [s390]
+ - KVM_MP_STATE_LOAD:            the vcpu is in a special load/startup state
+                                 [s390]
+
+On x86, this ioctl is only useful after KVM_CREATE_IRQCHIP. Without an
+in-kernel irqchip, the multiprocessing state must be maintained by userspace on
+these architectures.
+
+For arm/arm64:
+
+The only states that are valid are KVM_MP_STATE_STOPPED and
+KVM_MP_STATE_RUNNABLE which reflect if the vcpu is paused or not.
+
+4.39 KVM_SET_MP_STATE
+
+Capability: KVM_CAP_MP_STATE
+Architectures: x86, s390, arm, arm64
+Type: vcpu ioctl
+Parameters: struct kvm_mp_state (in)
+Returns: 0 on success; -1 on error
+
+Sets the vcpu's current "multiprocessing state"; see KVM_GET_MP_STATE for
+arguments.
+
+On x86, this ioctl is only useful after KVM_CREATE_IRQCHIP. Without an
+in-kernel irqchip, the multiprocessing state must be maintained by userspace on
+these architectures.
+
+For arm/arm64:
+
+The only states that are valid are KVM_MP_STATE_STOPPED and
+KVM_MP_STATE_RUNNABLE which reflect if the vcpu should be paused or not.
+
+4.40 KVM_SET_IDENTITY_MAP_ADDR
+
+Capability: KVM_CAP_SET_IDENTITY_MAP_ADDR
+Architectures: x86
+Type: vm ioctl
+Parameters: unsigned long identity (in)
+Returns: 0 on success, -1 on error
+
+This ioctl defines the physical address of a one-page region in the guest
+physical address space.  The region must be within the first 4GB of the
+guest physical address space and must not conflict with any memory slot
+or any mmio address.  The guest may malfunction if it accesses this memory
+region.
+
+Setting the address to 0 will result in resetting the address to its default
+(0xfffbc000).
+
+This ioctl is required on Intel-based hosts.  This is needed on Intel hardware
+because of a quirk in the virtualization implementation (see the internals
+documentation when it pops into existence).
+
+Fails if any VCPU has already been created.
+
+4.41 KVM_SET_BOOT_CPU_ID
+
+Capability: KVM_CAP_SET_BOOT_CPU_ID
+Architectures: x86
+Type: vm ioctl
+Parameters: unsigned long vcpu_id
+Returns: 0 on success, -1 on error
+
+Define which vcpu is the Bootstrap Processor (BSP).  Values are the same
+as the vcpu id in KVM_CREATE_VCPU.  If this ioctl is not called, the default
+is vcpu 0.
+
+
+4.42 KVM_GET_XSAVE
+
+Capability: KVM_CAP_XSAVE
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_xsave (out)
+Returns: 0 on success, -1 on error
+
+struct kvm_xsave {
+       __u32 region[1024];
+};
+
+This ioctl would copy current vcpu's xsave struct to the userspace.
+
+
+4.43 KVM_SET_XSAVE
+
+Capability: KVM_CAP_XSAVE
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_xsave (in)
+Returns: 0 on success, -1 on error
+
+struct kvm_xsave {
+       __u32 region[1024];
+};
+
+This ioctl would copy userspace's xsave struct to the kernel.
+
+
+4.44 KVM_GET_XCRS
+
+Capability: KVM_CAP_XCRS
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_xcrs (out)
+Returns: 0 on success, -1 on error
+
+struct kvm_xcr {
+       __u32 xcr;
+       __u32 reserved;
+       __u64 value;
+};
+
+struct kvm_xcrs {
+       __u32 nr_xcrs;
+       __u32 flags;
+       struct kvm_xcr xcrs[KVM_MAX_XCRS];
+       __u64 padding[16];
+};
+
+This ioctl would copy current vcpu's xcrs to the userspace.
+
+
+4.45 KVM_SET_XCRS
+
+Capability: KVM_CAP_XCRS
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_xcrs (in)
+Returns: 0 on success, -1 on error
+
+struct kvm_xcr {
+       __u32 xcr;
+       __u32 reserved;
+       __u64 value;
+};
+
+struct kvm_xcrs {
+       __u32 nr_xcrs;
+       __u32 flags;
+       struct kvm_xcr xcrs[KVM_MAX_XCRS];
+       __u64 padding[16];
+};
+
+This ioctl would set vcpu's xcr to the value userspace specified.
+
+
+4.46 KVM_GET_SUPPORTED_CPUID
+
+Capability: KVM_CAP_EXT_CPUID
+Architectures: x86
+Type: system ioctl
+Parameters: struct kvm_cpuid2 (in/out)
+Returns: 0 on success, -1 on error
+
+struct kvm_cpuid2 {
+       __u32 nent;
+       __u32 padding;
+       struct kvm_cpuid_entry2 entries[0];
+};
+
+#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX                BIT(0)
+#define KVM_CPUID_FLAG_STATEFUL_FUNC           BIT(1)
+#define KVM_CPUID_FLAG_STATE_READ_NEXT         BIT(2)
+
+struct kvm_cpuid_entry2 {
+       __u32 function;
+       __u32 index;
+       __u32 flags;
+       __u32 eax;
+       __u32 ebx;
+       __u32 ecx;
+       __u32 edx;
+       __u32 padding[3];
+};
+
+This ioctl returns x86 cpuid features which are supported by both the
+hardware and kvm in its default configuration.  Userspace can use the
+information returned by this ioctl to construct cpuid information (for
+KVM_SET_CPUID2) that is consistent with hardware, kernel, and
+userspace capabilities, and with user requirements (for example, the
+user may wish to constrain cpuid to emulate older hardware, or for
+feature consistency across a cluster).
+
+Note that certain capabilities, such as KVM_CAP_X86_DISABLE_EXITS, may
+expose cpuid features (e.g. MONITOR) which are not supported by kvm in
+its default configuration. If userspace enables such capabilities, it
+is responsible for modifying the results of this ioctl appropriately.
+
+Userspace invokes KVM_GET_SUPPORTED_CPUID by passing a kvm_cpuid2 structure
+with the 'nent' field indicating the number of entries in the variable-size
+array 'entries'.  If the number of entries is too low to describe the cpu
+capabilities, an error (E2BIG) is returned.  If the number is too high,
+the 'nent' field is adjusted and an error (ENOMEM) is returned.  If the
+number is just right, the 'nent' field is adjusted to the number of valid
+entries in the 'entries' array, which is then filled.
+
+The entries returned are the host cpuid as returned by the cpuid instruction,
+with unknown or unsupported features masked out.  Some features (for example,
+x2apic), may not be present in the host cpu, but are exposed by kvm if it can
+emulate them efficiently. The fields in each entry are defined as follows:
+
+  function: the eax value used to obtain the entry
+  index: the ecx value used to obtain the entry (for entries that are
+         affected by ecx)
+  flags: an OR of zero or more of the following:
+        KVM_CPUID_FLAG_SIGNIFCANT_INDEX:
+           if the index field is valid
+        KVM_CPUID_FLAG_STATEFUL_FUNC:
+           if cpuid for this function returns different values for successive
+           invocations; there will be several entries with the same function,
+           all with this flag set
+        KVM_CPUID_FLAG_STATE_READ_NEXT:
+           for KVM_CPUID_FLAG_STATEFUL_FUNC entries, set if this entry is
+           the first entry to be read by a cpu
+   eax, ebx, ecx, edx: the values returned by the cpuid instruction for
+         this function/index combination
+
+The TSC deadline timer feature (CPUID leaf 1, ecx[24]) is always returned
+as false, since the feature depends on KVM_CREATE_IRQCHIP for local APIC
+support.  Instead it is reported via
+
+  ioctl(KVM_CHECK_EXTENSION, KVM_CAP_TSC_DEADLINE_TIMER)
+
+if that returns true and you use KVM_CREATE_IRQCHIP, or if you emulate the
+feature in userspace, then you can enable the feature for KVM_SET_CPUID2.
+
+
+4.47 KVM_PPC_GET_PVINFO
+
+Capability: KVM_CAP_PPC_GET_PVINFO
+Architectures: ppc
+Type: vm ioctl
+Parameters: struct kvm_ppc_pvinfo (out)
+Returns: 0 on success, !0 on error
+
+struct kvm_ppc_pvinfo {
+       __u32 flags;
+       __u32 hcall[4];
+       __u8  pad[108];
+};
+
+This ioctl fetches PV specific information that need to be passed to the guest
+using the device tree or other means from vm context.
+
+The hcall array defines 4 instructions that make up a hypercall.
+
+If any additional field gets added to this structure later on, a bit for that
+additional piece of information will be set in the flags bitmap.
+
+The flags bitmap is defined as:
+
+   /* the host supports the ePAPR idle hcall
+   #define KVM_PPC_PVINFO_FLAGS_EV_IDLE   (1<<0)
+
+4.52 KVM_SET_GSI_ROUTING
+
+Capability: KVM_CAP_IRQ_ROUTING
+Architectures: x86 s390 arm arm64
+Type: vm ioctl
+Parameters: struct kvm_irq_routing (in)
+Returns: 0 on success, -1 on error
+
+Sets the GSI routing table entries, overwriting any previously set entries.
+
+On arm/arm64, GSI routing has the following limitation:
+- GSI routing does not apply to KVM_IRQ_LINE but only to KVM_IRQFD.
+
+struct kvm_irq_routing {
+       __u32 nr;
+       __u32 flags;
+       struct kvm_irq_routing_entry entries[0];
+};
+
+No flags are specified so far, the corresponding field must be set to zero.
+
+struct kvm_irq_routing_entry {
+       __u32 gsi;
+       __u32 type;
+       __u32 flags;
+       __u32 pad;
+       union {
+               struct kvm_irq_routing_irqchip irqchip;
+               struct kvm_irq_routing_msi msi;
+               struct kvm_irq_routing_s390_adapter adapter;
+               struct kvm_irq_routing_hv_sint hv_sint;
+               __u32 pad[8];
+       } u;
+};
+
+/* gsi routing entry types */
+#define KVM_IRQ_ROUTING_IRQCHIP 1
+#define KVM_IRQ_ROUTING_MSI 2
+#define KVM_IRQ_ROUTING_S390_ADAPTER 3
+#define KVM_IRQ_ROUTING_HV_SINT 4
+
+flags:
+- KVM_MSI_VALID_DEVID: used along with KVM_IRQ_ROUTING_MSI routing entry
+  type, specifies that the devid field contains a valid value.  The per-VM
+  KVM_CAP_MSI_DEVID capability advertises the requirement to provide
+  the device ID.  If this capability is not available, userspace should
+  never set the KVM_MSI_VALID_DEVID flag as the ioctl might fail.
+- zero otherwise
+
+struct kvm_irq_routing_irqchip {
+       __u32 irqchip;
+       __u32 pin;
+};
+
+struct kvm_irq_routing_msi {
+       __u32 address_lo;
+       __u32 address_hi;
+       __u32 data;
+       union {
+               __u32 pad;
+               __u32 devid;
+       };
+};
+
+If KVM_MSI_VALID_DEVID is set, devid contains a unique device identifier
+for the device that wrote the MSI message.  For PCI, this is usually a
+BFD identifier in the lower 16 bits.
+
+On x86, address_hi is ignored unless the KVM_X2APIC_API_USE_32BIT_IDS
+feature of KVM_CAP_X2APIC_API capability is enabled.  If it is enabled,
+address_hi bits 31-8 provide bits 31-8 of the destination id.  Bits 7-0 of
+address_hi must be zero.
+
+struct kvm_irq_routing_s390_adapter {
+       __u64 ind_addr;
+       __u64 summary_addr;
+       __u64 ind_offset;
+       __u32 summary_offset;
+       __u32 adapter_id;
+};
+
+struct kvm_irq_routing_hv_sint {
+       __u32 vcpu;
+       __u32 sint;
+};
+
+
+4.55 KVM_SET_TSC_KHZ
+
+Capability: KVM_CAP_TSC_CONTROL
+Architectures: x86
+Type: vcpu ioctl
+Parameters: virtual tsc_khz
+Returns: 0 on success, -1 on error
+
+Specifies the tsc frequency for the virtual machine. The unit of the
+frequency is KHz.
+
+
+4.56 KVM_GET_TSC_KHZ
+
+Capability: KVM_CAP_GET_TSC_KHZ
+Architectures: x86
+Type: vcpu ioctl
+Parameters: none
+Returns: virtual tsc-khz on success, negative value on error
+
+Returns the tsc frequency of the guest. The unit of the return value is
+KHz. If the host has unstable tsc this ioctl returns -EIO instead as an
+error.
+
+
+4.57 KVM_GET_LAPIC
+
+Capability: KVM_CAP_IRQCHIP
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_lapic_state (out)
+Returns: 0 on success, -1 on error
+
+#define KVM_APIC_REG_SIZE 0x400
+struct kvm_lapic_state {
+       char regs[KVM_APIC_REG_SIZE];
+};
+
+Reads the Local APIC registers and copies them into the input argument.  The
+data format and layout are the same as documented in the architecture manual.
+
+If KVM_X2APIC_API_USE_32BIT_IDS feature of KVM_CAP_X2APIC_API is
+enabled, then the format of APIC_ID register depends on the APIC mode
+(reported by MSR_IA32_APICBASE) of its VCPU.  x2APIC stores APIC ID in
+the APIC_ID register (bytes 32-35).  xAPIC only allows an 8-bit APIC ID
+which is stored in bits 31-24 of the APIC register, or equivalently in
+byte 35 of struct kvm_lapic_state's regs field.  KVM_GET_LAPIC must then
+be called after MSR_IA32_APICBASE has been set with KVM_SET_MSR.
+
+If KVM_X2APIC_API_USE_32BIT_IDS feature is disabled, struct kvm_lapic_state
+always uses xAPIC format.
+
+
+4.58 KVM_SET_LAPIC
+
+Capability: KVM_CAP_IRQCHIP
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_lapic_state (in)
+Returns: 0 on success, -1 on error
+
+#define KVM_APIC_REG_SIZE 0x400
+struct kvm_lapic_state {
+       char regs[KVM_APIC_REG_SIZE];
+};
+
+Copies the input argument into the Local APIC registers.  The data format
+and layout are the same as documented in the architecture manual.
+
+The format of the APIC ID register (bytes 32-35 of struct kvm_lapic_state's
+regs field) depends on the state of the KVM_CAP_X2APIC_API capability.
+See the note in KVM_GET_LAPIC.
+
+
+4.59 KVM_IOEVENTFD
+
+Capability: KVM_CAP_IOEVENTFD
+Architectures: all
+Type: vm ioctl
+Parameters: struct kvm_ioeventfd (in)
+Returns: 0 on success, !0 on error
+
+This ioctl attaches or detaches an ioeventfd to a legal pio/mmio address
+within the guest.  A guest write in the registered address will signal the
+provided event instead of triggering an exit.
+
+struct kvm_ioeventfd {
+       __u64 datamatch;
+       __u64 addr;        /* legal pio/mmio address */
+       __u32 len;         /* 0, 1, 2, 4, or 8 bytes    */
+       __s32 fd;
+       __u32 flags;
+       __u8  pad[36];
+};
+
+For the special case of virtio-ccw devices on s390, the ioevent is matched
+to a subchannel/virtqueue tuple instead.
+
+The following flags are defined:
+
+#define KVM_IOEVENTFD_FLAG_DATAMATCH (1 << kvm_ioeventfd_flag_nr_datamatch)
+#define KVM_IOEVENTFD_FLAG_PIO       (1 << kvm_ioeventfd_flag_nr_pio)
+#define KVM_IOEVENTFD_FLAG_DEASSIGN  (1 << kvm_ioeventfd_flag_nr_deassign)
+#define KVM_IOEVENTFD_FLAG_VIRTIO_CCW_NOTIFY \
+       (1 << kvm_ioeventfd_flag_nr_virtio_ccw_notify)
+
+If datamatch flag is set, the event will be signaled only if the written value
+to the registered address is equal to datamatch in struct kvm_ioeventfd.
+
+For virtio-ccw devices, addr contains the subchannel id and datamatch the
+virtqueue index.
+
+With KVM_CAP_IOEVENTFD_ANY_LENGTH, a zero length ioeventfd is allowed, and
+the kernel will ignore the length of guest write and may get a faster vmexit.
+The speedup may only apply to specific architectures, but the ioeventfd will
+work anyway.
+
+4.60 KVM_DIRTY_TLB
+
+Capability: KVM_CAP_SW_TLB
+Architectures: ppc
+Type: vcpu ioctl
+Parameters: struct kvm_dirty_tlb (in)
+Returns: 0 on success, -1 on error
+
+struct kvm_dirty_tlb {
+       __u64 bitmap;
+       __u32 num_dirty;
+};
+
+This must be called whenever userspace has changed an entry in the shared
+TLB, prior to calling KVM_RUN on the associated vcpu.
+
+The "bitmap" field is the userspace address of an array.  This array
+consists of a number of bits, equal to the total number of TLB entries as
+determined by the last successful call to KVM_CONFIG_TLB, rounded up to the
+nearest multiple of 64.
+
+Each bit corresponds to one TLB entry, ordered the same as in the shared TLB
+array.
+
+The array is little-endian: the bit 0 is the least significant bit of the
+first byte, bit 8 is the least significant bit of the second byte, etc.
+This avoids any complications with differing word sizes.
+
+The "num_dirty" field is a performance hint for KVM to determine whether it
+should skip processing the bitmap and just invalidate everything.  It must
+be set to the number of set bits in the bitmap.
+
+
+4.62 KVM_CREATE_SPAPR_TCE
+
+Capability: KVM_CAP_SPAPR_TCE
+Architectures: powerpc
+Type: vm ioctl
+Parameters: struct kvm_create_spapr_tce (in)
+Returns: file descriptor for manipulating the created TCE table
+
+This creates a virtual TCE (translation control entry) table, which
+is an IOMMU for PAPR-style virtual I/O.  It is used to translate
+logical addresses used in virtual I/O into guest physical addresses,
+and provides a scatter/gather capability for PAPR virtual I/O.
+
+/* for KVM_CAP_SPAPR_TCE */
+struct kvm_create_spapr_tce {
+       __u64 liobn;
+       __u32 window_size;
+};
+
+The liobn field gives the logical IO bus number for which to create a
+TCE table.  The window_size field specifies the size of the DMA window
+which this TCE table will translate - the table will contain one 64
+bit TCE entry for every 4kiB of the DMA window.
+
+When the guest issues an H_PUT_TCE hcall on a liobn for which a TCE
+table has been created using this ioctl(), the kernel will handle it
+in real mode, updating the TCE table.  H_PUT_TCE calls for other
+liobns will cause a vm exit and must be handled by userspace.
+
+The return value is a file descriptor which can be passed to mmap(2)
+to map the created TCE table into userspace.  This lets userspace read
+the entries written by kernel-handled H_PUT_TCE calls, and also lets
+userspace update the TCE table directly which is useful in some
+circumstances.
+
+
+4.63 KVM_ALLOCATE_RMA
+
+Capability: KVM_CAP_PPC_RMA
+Architectures: powerpc
+Type: vm ioctl
+Parameters: struct kvm_allocate_rma (out)
+Returns: file descriptor for mapping the allocated RMA
+
+This allocates a Real Mode Area (RMA) from the pool allocated at boot
+time by the kernel.  An RMA is a physically-contiguous, aligned region
+of memory used on older POWER processors to provide the memory which
+will be accessed by real-mode (MMU off) accesses in a KVM guest.
+POWER processors support a set of sizes for the RMA that usually
+includes 64MB, 128MB, 256MB and some larger powers of two.
+
+/* for KVM_ALLOCATE_RMA */
+struct kvm_allocate_rma {
+       __u64 rma_size;
+};
+
+The return value is a file descriptor which can be passed to mmap(2)
+to map the allocated RMA into userspace.  The mapped area can then be
+passed to the KVM_SET_USER_MEMORY_REGION ioctl to establish it as the
+RMA for a virtual machine.  The size of the RMA in bytes (which is
+fixed at host kernel boot time) is returned in the rma_size field of
+the argument structure.
+
+The KVM_CAP_PPC_RMA capability is 1 or 2 if the KVM_ALLOCATE_RMA ioctl
+is supported; 2 if the processor requires all virtual machines to have
+an RMA, or 1 if the processor can use an RMA but doesn't require it,
+because it supports the Virtual RMA (VRMA) facility.
+
+
+4.64 KVM_NMI
+
+Capability: KVM_CAP_USER_NMI
+Architectures: x86
+Type: vcpu ioctl
+Parameters: none
+Returns: 0 on success, -1 on error
+
+Queues an NMI on the thread's vcpu.  Note this is well defined only
+when KVM_CREATE_IRQCHIP has not been called, since this is an interface
+between the virtual cpu core and virtual local APIC.  After KVM_CREATE_IRQCHIP
+has been called, this interface is completely emulated within the kernel.
+
+To use this to emulate the LINT1 input with KVM_CREATE_IRQCHIP, use the
+following algorithm:
+
+  - pause the vcpu
+  - read the local APIC's state (KVM_GET_LAPIC)
+  - check whether changing LINT1 will queue an NMI (see the LVT entry for LINT1)
+  - if so, issue KVM_NMI
+  - resume the vcpu
+
+Some guests configure the LINT1 NMI input to cause a panic, aiding in
+debugging.
+
+
+4.65 KVM_S390_UCAS_MAP
+
+Capability: KVM_CAP_S390_UCONTROL
+Architectures: s390
+Type: vcpu ioctl
+Parameters: struct kvm_s390_ucas_mapping (in)
+Returns: 0 in case of success
+
+The parameter is defined like this:
+       struct kvm_s390_ucas_mapping {
+               __u64 user_addr;
+               __u64 vcpu_addr;
+               __u64 length;
+       };
+
+This ioctl maps the memory at "user_addr" with the length "length" to
+the vcpu's address space starting at "vcpu_addr". All parameters need to
+be aligned by 1 megabyte.
+
+
+4.66 KVM_S390_UCAS_UNMAP
+
+Capability: KVM_CAP_S390_UCONTROL
+Architectures: s390
+Type: vcpu ioctl
+Parameters: struct kvm_s390_ucas_mapping (in)
+Returns: 0 in case of success
+
+The parameter is defined like this:
+       struct kvm_s390_ucas_mapping {
+               __u64 user_addr;
+               __u64 vcpu_addr;
+               __u64 length;
+       };
+
+This ioctl unmaps the memory in the vcpu's address space starting at
+"vcpu_addr" with the length "length". The field "user_addr" is ignored.
+All parameters need to be aligned by 1 megabyte.
+
+
+4.67 KVM_S390_VCPU_FAULT
+
+Capability: KVM_CAP_S390_UCONTROL
+Architectures: s390
+Type: vcpu ioctl
+Parameters: vcpu absolute address (in)
+Returns: 0 in case of success
+
+This call creates a page table entry on the virtual cpu's address space
+(for user controlled virtual machines) or the virtual machine's address
+space (for regular virtual machines). This only works for minor faults,
+thus it's recommended to access subject memory page via the user page
+table upfront. This is useful to handle validity intercepts for user
+controlled virtual machines to fault in the virtual cpu's lowcore pages
+prior to calling the KVM_RUN ioctl.
+
+
+4.68 KVM_SET_ONE_REG
+
+Capability: KVM_CAP_ONE_REG
+Architectures: all
+Type: vcpu ioctl
+Parameters: struct kvm_one_reg (in)
+Returns: 0 on success, negative value on failure
+Errors:
+  ENOENT:   no such register
+  EINVAL:   invalid register ID, or no such register
+  EPERM:    (arm64) register access not allowed before vcpu finalization
+(These error codes are indicative only: do not rely on a specific error
+code being returned in a specific situation.)
+
+struct kvm_one_reg {
+       __u64 id;
+       __u64 addr;
+};
+
+Using this ioctl, a single vcpu register can be set to a specific value
+defined by user space with the passed in struct kvm_one_reg, where id
+refers to the register identifier as described below and addr is a pointer
+to a variable with the respective size. There can be architecture agnostic
+and architecture specific registers. Each have their own range of operation
+and their own constants and width. To keep track of the implemented
+registers, find a list below:
+
+  Arch  |           Register            | Width (bits)
+        |                               |
+  PPC   | KVM_REG_PPC_HIOR              | 64
+  PPC   | KVM_REG_PPC_IAC1              | 64
+  PPC   | KVM_REG_PPC_IAC2              | 64
+  PPC   | KVM_REG_PPC_IAC3              | 64
+  PPC   | KVM_REG_PPC_IAC4              | 64
+  PPC   | KVM_REG_PPC_DAC1              | 64
+  PPC   | KVM_REG_PPC_DAC2              | 64
+  PPC   | KVM_REG_PPC_DABR              | 64
+  PPC   | KVM_REG_PPC_DSCR              | 64
+  PPC   | KVM_REG_PPC_PURR              | 64
+  PPC   | KVM_REG_PPC_SPURR             | 64
+  PPC   | KVM_REG_PPC_DAR               | 64
+  PPC   | KVM_REG_PPC_DSISR             | 32
+  PPC   | KVM_REG_PPC_AMR               | 64
+  PPC   | KVM_REG_PPC_UAMOR             | 64
+  PPC   | KVM_REG_PPC_MMCR0             | 64
+  PPC   | KVM_REG_PPC_MMCR1             | 64
+  PPC   | KVM_REG_PPC_MMCRA             | 64
+  PPC   | KVM_REG_PPC_MMCR2             | 64
+  PPC   | KVM_REG_PPC_MMCRS             | 64
+  PPC   | KVM_REG_PPC_SIAR              | 64
+  PPC   | KVM_REG_PPC_SDAR              | 64
+  PPC   | KVM_REG_PPC_SIER              | 64
+  PPC   | KVM_REG_PPC_PMC1              | 32
+  PPC   | KVM_REG_PPC_PMC2              | 32
+  PPC   | KVM_REG_PPC_PMC3              | 32
+  PPC   | KVM_REG_PPC_PMC4              | 32
+  PPC   | KVM_REG_PPC_PMC5              | 32
+  PPC   | KVM_REG_PPC_PMC6              | 32
+  PPC   | KVM_REG_PPC_PMC7              | 32
+  PPC   | KVM_REG_PPC_PMC8              | 32
+  PPC   | KVM_REG_PPC_FPR0              | 64
+          ...
+  PPC   | KVM_REG_PPC_FPR31             | 64
+  PPC   | KVM_REG_PPC_VR0               | 128
+          ...
+  PPC   | KVM_REG_PPC_VR31              | 128
+  PPC   | KVM_REG_PPC_VSR0              | 128
+          ...
+  PPC   | KVM_REG_PPC_VSR31             | 128
+  PPC   | KVM_REG_PPC_FPSCR             | 64
+  PPC   | KVM_REG_PPC_VSCR              | 32
+  PPC   | KVM_REG_PPC_VPA_ADDR          | 64
+  PPC   | KVM_REG_PPC_VPA_SLB           | 128
+  PPC   | KVM_REG_PPC_VPA_DTL           | 128
+  PPC   | KVM_REG_PPC_EPCR              | 32
+  PPC   | KVM_REG_PPC_EPR               | 32
+  PPC   | KVM_REG_PPC_TCR               | 32
+  PPC   | KVM_REG_PPC_TSR               | 32
+  PPC   | KVM_REG_PPC_OR_TSR            | 32
+  PPC   | KVM_REG_PPC_CLEAR_TSR         | 32
+  PPC   | KVM_REG_PPC_MAS0              | 32
+  PPC   | KVM_REG_PPC_MAS1              | 32
+  PPC   | KVM_REG_PPC_MAS2              | 64
+  PPC   | KVM_REG_PPC_MAS7_3            | 64
+  PPC   | KVM_REG_PPC_MAS4              | 32
+  PPC   | KVM_REG_PPC_MAS6              | 32
+  PPC   | KVM_REG_PPC_MMUCFG            | 32
+  PPC   | KVM_REG_PPC_TLB0CFG           | 32
+  PPC   | KVM_REG_PPC_TLB1CFG           | 32
+  PPC   | KVM_REG_PPC_TLB2CFG           | 32
+  PPC   | KVM_REG_PPC_TLB3CFG           | 32
+  PPC   | KVM_REG_PPC_TLB0PS            | 32
+  PPC   | KVM_REG_PPC_TLB1PS            | 32
+  PPC   | KVM_REG_PPC_TLB2PS            | 32
+  PPC   | KVM_REG_PPC_TLB3PS            | 32
+  PPC   | KVM_REG_PPC_EPTCFG            | 32
+  PPC   | KVM_REG_PPC_ICP_STATE         | 64
+  PPC   | KVM_REG_PPC_VP_STATE          | 128
+  PPC   | KVM_REG_PPC_TB_OFFSET         | 64
+  PPC   | KVM_REG_PPC_SPMC1             | 32
+  PPC   | KVM_REG_PPC_SPMC2             | 32
+  PPC   | KVM_REG_PPC_IAMR              | 64
+  PPC   | KVM_REG_PPC_TFHAR             | 64
+  PPC   | KVM_REG_PPC_TFIAR             | 64
+  PPC   | KVM_REG_PPC_TEXASR            | 64
+  PPC   | KVM_REG_PPC_FSCR              | 64
+  PPC   | KVM_REG_PPC_PSPB              | 32
+  PPC   | KVM_REG_PPC_EBBHR             | 64
+  PPC   | KVM_REG_PPC_EBBRR             | 64
+  PPC   | KVM_REG_PPC_BESCR             | 64
+  PPC   | KVM_REG_PPC_TAR               | 64
+  PPC   | KVM_REG_PPC_DPDES             | 64
+  PPC   | KVM_REG_PPC_DAWR              | 64
+  PPC   | KVM_REG_PPC_DAWRX             | 64
+  PPC   | KVM_REG_PPC_CIABR             | 64
+  PPC   | KVM_REG_PPC_IC                | 64
+  PPC   | KVM_REG_PPC_VTB               | 64
+  PPC   | KVM_REG_PPC_CSIGR             | 64
+  PPC   | KVM_REG_PPC_TACR              | 64
+  PPC   | KVM_REG_PPC_TCSCR             | 64
+  PPC   | KVM_REG_PPC_PID               | 64
+  PPC   | KVM_REG_PPC_ACOP              | 64
+  PPC   | KVM_REG_PPC_VRSAVE            | 32
+  PPC   | KVM_REG_PPC_LPCR              | 32
+  PPC   | KVM_REG_PPC_LPCR_64           | 64
+  PPC   | KVM_REG_PPC_PPR               | 64
+  PPC   | KVM_REG_PPC_ARCH_COMPAT       | 32
+  PPC   | KVM_REG_PPC_DABRX             | 32
+  PPC   | KVM_REG_PPC_WORT              | 64
+  PPC  | KVM_REG_PPC_SPRG9             | 64
+  PPC  | KVM_REG_PPC_DBSR              | 32
+  PPC   | KVM_REG_PPC_TIDR              | 64
+  PPC   | KVM_REG_PPC_PSSCR             | 64
+  PPC   | KVM_REG_PPC_DEC_EXPIRY        | 64
+  PPC   | KVM_REG_PPC_PTCR              | 64
+  PPC   | KVM_REG_PPC_TM_GPR0           | 64
+          ...
+  PPC   | KVM_REG_PPC_TM_GPR31          | 64
+  PPC   | KVM_REG_PPC_TM_VSR0           | 128
+          ...
+  PPC   | KVM_REG_PPC_TM_VSR63          | 128
+  PPC   | KVM_REG_PPC_TM_CR             | 64
+  PPC   | KVM_REG_PPC_TM_LR             | 64
+  PPC   | KVM_REG_PPC_TM_CTR            | 64
+  PPC   | KVM_REG_PPC_TM_FPSCR          | 64
+  PPC   | KVM_REG_PPC_TM_AMR            | 64
+  PPC   | KVM_REG_PPC_TM_PPR            | 64
+  PPC   | KVM_REG_PPC_TM_VRSAVE         | 64
+  PPC   | KVM_REG_PPC_TM_VSCR           | 32
+  PPC   | KVM_REG_PPC_TM_DSCR           | 64
+  PPC   | KVM_REG_PPC_TM_TAR            | 64
+  PPC   | KVM_REG_PPC_TM_XER            | 64
+        |                               |
+  MIPS  | KVM_REG_MIPS_R0               | 64
+          ...
+  MIPS  | KVM_REG_MIPS_R31              | 64
+  MIPS  | KVM_REG_MIPS_HI               | 64
+  MIPS  | KVM_REG_MIPS_LO               | 64
+  MIPS  | KVM_REG_MIPS_PC               | 64
+  MIPS  | KVM_REG_MIPS_CP0_INDEX        | 32
+  MIPS  | KVM_REG_MIPS_CP0_ENTRYLO0     | 64
+  MIPS  | KVM_REG_MIPS_CP0_ENTRYLO1     | 64
+  MIPS  | KVM_REG_MIPS_CP0_CONTEXT      | 64
+  MIPS  | KVM_REG_MIPS_CP0_CONTEXTCONFIG| 32
+  MIPS  | KVM_REG_MIPS_CP0_USERLOCAL    | 64
+  MIPS  | KVM_REG_MIPS_CP0_XCONTEXTCONFIG| 64
+  MIPS  | KVM_REG_MIPS_CP0_PAGEMASK     | 32
+  MIPS  | KVM_REG_MIPS_CP0_PAGEGRAIN    | 32
+  MIPS  | KVM_REG_MIPS_CP0_SEGCTL0      | 64
+  MIPS  | KVM_REG_MIPS_CP0_SEGCTL1      | 64
+  MIPS  | KVM_REG_MIPS_CP0_SEGCTL2      | 64
+  MIPS  | KVM_REG_MIPS_CP0_PWBASE       | 64
+  MIPS  | KVM_REG_MIPS_CP0_PWFIELD      | 64
+  MIPS  | KVM_REG_MIPS_CP0_PWSIZE       | 64
+  MIPS  | KVM_REG_MIPS_CP0_WIRED        | 32
+  MIPS  | KVM_REG_MIPS_CP0_PWCTL        | 32
+  MIPS  | KVM_REG_MIPS_CP0_HWRENA       | 32
+  MIPS  | KVM_REG_MIPS_CP0_BADVADDR     | 64
+  MIPS  | KVM_REG_MIPS_CP0_BADINSTR     | 32
+  MIPS  | KVM_REG_MIPS_CP0_BADINSTRP    | 32
+  MIPS  | KVM_REG_MIPS_CP0_COUNT        | 32
+  MIPS  | KVM_REG_MIPS_CP0_ENTRYHI      | 64
+  MIPS  | KVM_REG_MIPS_CP0_COMPARE      | 32
+  MIPS  | KVM_REG_MIPS_CP0_STATUS       | 32
+  MIPS  | KVM_REG_MIPS_CP0_INTCTL       | 32
+  MIPS  | KVM_REG_MIPS_CP0_CAUSE        | 32
+  MIPS  | KVM_REG_MIPS_CP0_EPC          | 64
+  MIPS  | KVM_REG_MIPS_CP0_PRID         | 32
+  MIPS  | KVM_REG_MIPS_CP0_EBASE        | 64
+  MIPS  | KVM_REG_MIPS_CP0_CONFIG       | 32
+  MIPS  | KVM_REG_MIPS_CP0_CONFIG1      | 32
+  MIPS  | KVM_REG_MIPS_CP0_CONFIG2      | 32
+  MIPS  | KVM_REG_MIPS_CP0_CONFIG3      | 32
+  MIPS  | KVM_REG_MIPS_CP0_CONFIG4      | 32
+  MIPS  | KVM_REG_MIPS_CP0_CONFIG5      | 32
+  MIPS  | KVM_REG_MIPS_CP0_CONFIG7      | 32
+  MIPS  | KVM_REG_MIPS_CP0_XCONTEXT     | 64
+  MIPS  | KVM_REG_MIPS_CP0_ERROREPC     | 64
+  MIPS  | KVM_REG_MIPS_CP0_KSCRATCH1    | 64
+  MIPS  | KVM_REG_MIPS_CP0_KSCRATCH2    | 64
+  MIPS  | KVM_REG_MIPS_CP0_KSCRATCH3    | 64
+  MIPS  | KVM_REG_MIPS_CP0_KSCRATCH4    | 64
+  MIPS  | KVM_REG_MIPS_CP0_KSCRATCH5    | 64
+  MIPS  | KVM_REG_MIPS_CP0_KSCRATCH6    | 64
+  MIPS  | KVM_REG_MIPS_CP0_MAAR(0..63)  | 64
+  MIPS  | KVM_REG_MIPS_COUNT_CTL        | 64
+  MIPS  | KVM_REG_MIPS_COUNT_RESUME     | 64
+  MIPS  | KVM_REG_MIPS_COUNT_HZ         | 64
+  MIPS  | KVM_REG_MIPS_FPR_32(0..31)    | 32
+  MIPS  | KVM_REG_MIPS_FPR_64(0..31)    | 64
+  MIPS  | KVM_REG_MIPS_VEC_128(0..31)   | 128
+  MIPS  | KVM_REG_MIPS_FCR_IR           | 32
+  MIPS  | KVM_REG_MIPS_FCR_CSR          | 32
+  MIPS  | KVM_REG_MIPS_MSA_IR           | 32
+  MIPS  | KVM_REG_MIPS_MSA_CSR          | 32
+
+ARM registers are mapped using the lower 32 bits.  The upper 16 of that
+is the register group type, or coprocessor number:
+
+ARM core registers have the following id bit patterns:
+  0x4020 0000 0010 <index into the kvm_regs struct:16>
+
+ARM 32-bit CP15 registers have the following id bit patterns:
+  0x4020 0000 000F <zero:1> <crn:4> <crm:4> <opc1:4> <opc2:3>
+
+ARM 64-bit CP15 registers have the following id bit patterns:
+  0x4030 0000 000F <zero:1> <zero:4> <crm:4> <opc1:4> <zero:3>
+
+ARM CCSIDR registers are demultiplexed by CSSELR value:
+  0x4020 0000 0011 00 <csselr:8>
+
+ARM 32-bit VFP control registers have the following id bit patterns:
+  0x4020 0000 0012 1 <regno:12>
+
+ARM 64-bit FP registers have the following id bit patterns:
+  0x4030 0000 0012 0 <regno:12>
+
+ARM firmware pseudo-registers have the following bit pattern:
+  0x4030 0000 0014 <regno:16>
+
+
+arm64 registers are mapped using the lower 32 bits. The upper 16 of
+that is the register group type, or coprocessor number:
+
+arm64 core/FP-SIMD registers have the following id bit patterns. Note
+that the size of the access is variable, as the kvm_regs structure
+contains elements ranging from 32 to 128 bits. The index is a 32bit
+value in the kvm_regs structure seen as a 32bit array.
+  0x60x0 0000 0010 <index into the kvm_regs struct:16>
+
+Specifically:
+    Encoding            Register  Bits  kvm_regs member
+----------------------------------------------------------------
+  0x6030 0000 0010 0000 X0          64  regs.regs[0]
+  0x6030 0000 0010 0002 X1          64  regs.regs[1]
+    ...
+  0x6030 0000 0010 003c X30         64  regs.regs[30]
+  0x6030 0000 0010 003e SP          64  regs.sp
+  0x6030 0000 0010 0040 PC          64  regs.pc
+  0x6030 0000 0010 0042 PSTATE      64  regs.pstate
+  0x6030 0000 0010 0044 SP_EL1      64  sp_el1
+  0x6030 0000 0010 0046 ELR_EL1     64  elr_el1
+  0x6030 0000 0010 0048 SPSR_EL1    64  spsr[KVM_SPSR_EL1] (alias SPSR_SVC)
+  0x6030 0000 0010 004a SPSR_ABT    64  spsr[KVM_SPSR_ABT]
+  0x6030 0000 0010 004c SPSR_UND    64  spsr[KVM_SPSR_UND]
+  0x6030 0000 0010 004e SPSR_IRQ    64  spsr[KVM_SPSR_IRQ]
+  0x6060 0000 0010 0050 SPSR_FIQ    64  spsr[KVM_SPSR_FIQ]
+  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]    (*)
+  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]    (*)
+    ...
+  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]   (*)
+  0x6020 0000 0010 00d4 FPSR        32  fp_regs.fpsr
+  0x6020 0000 0010 00d5 FPCR        32  fp_regs.fpcr
+
+(*) These encodings are not accepted for SVE-enabled vcpus.  See
+    KVM_ARM_VCPU_INIT.
+
+    The equivalent register content can be accessed via bits [127:0] of
+    the corresponding SVE Zn registers instead for vcpus that have SVE
+    enabled (see below).
+
+arm64 CCSIDR registers are demultiplexed by CSSELR value:
+  0x6020 0000 0011 00 <csselr:8>
+
+arm64 system registers have the following id bit patterns:
+  0x6030 0000 0013 <op0:2> <op1:3> <crn:4> <crm:4> <op2:3>
+
+arm64 firmware pseudo-registers have the following bit pattern:
+  0x6030 0000 0014 <regno:16>
+
+arm64 SVE registers have the following bit patterns:
+  0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
+  0x6050 0000 0015 04 <n:4> <slice:5>   Pn bits[256*slice + 255 : 256*slice]
+  0x6050 0000 0015 060 <slice:5>        FFR bits[256*slice + 255 : 256*slice]
+  0x6060 0000 0015 ffff                 KVM_REG_ARM64_SVE_VLS pseudo-register
+
+Access to register IDs where 2048 * slice >= 128 * max_vq will fail with
+ENOENT.  max_vq is the vcpu's maximum supported vector length in 128-bit
+quadwords: see (**) below.
+
+These registers are only accessible on vcpus for which SVE is enabled.
+See KVM_ARM_VCPU_INIT for details.
+
+In addition, except for KVM_REG_ARM64_SVE_VLS, these registers are not
+accessible until the vcpu's SVE configuration has been finalized
+using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).  See KVM_ARM_VCPU_INIT
+and KVM_ARM_VCPU_FINALIZE for more information about this procedure.
+
+KVM_REG_ARM64_SVE_VLS is a pseudo-register that allows the set of vector
+lengths supported by the vcpu to be discovered and configured by
+userspace.  When transferred to or from user memory via KVM_GET_ONE_REG
+or KVM_SET_ONE_REG, the value of this register is of type
+__u64[KVM_ARM64_SVE_VLS_WORDS], and encodes the set of vector lengths as
+follows:
+
+__u64 vector_lengths[KVM_ARM64_SVE_VLS_WORDS];
+
+if (vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX &&
+    ((vector_lengths[(vq - KVM_ARM64_SVE_VQ_MIN) / 64] >>
+               ((vq - KVM_ARM64_SVE_VQ_MIN) % 64)) & 1))
+       /* Vector length vq * 16 bytes supported */
+else
+       /* Vector length vq * 16 bytes not supported */
+
+(**) The maximum value vq for which the above condition is true is
+max_vq.  This is the maximum vector length available to the guest on
+this vcpu, and determines which register slices are visible through
+this ioctl interface.
+
+(See Documentation/arm64/sve.rst for an explanation of the "vq"
+nomenclature.)
+
+KVM_REG_ARM64_SVE_VLS is only accessible after KVM_ARM_VCPU_INIT.
+KVM_ARM_VCPU_INIT initialises it to the best set of vector lengths that
+the host supports.
+
+Userspace may subsequently modify it if desired until the vcpu's SVE
+configuration is finalized using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).
+
+Apart from simply removing all vector lengths from the host set that
+exceed some value, support for arbitrarily chosen sets of vector lengths
+is hardware-dependent and may not be available.  Attempting to configure
+an invalid set of vector lengths via KVM_SET_ONE_REG will fail with
+EINVAL.
+
+After the vcpu's SVE configuration is finalized, further attempts to
+write this register will fail with EPERM.
+
+
+MIPS registers are mapped using the lower 32 bits.  The upper 16 of that is
+the register group type:
+
+MIPS core registers (see above) have the following id bit patterns:
+  0x7030 0000 0000 <reg:16>
+
+MIPS CP0 registers (see KVM_REG_MIPS_CP0_* above) have the following id bit
+patterns depending on whether they're 32-bit or 64-bit registers:
+  0x7020 0000 0001 00 <reg:5> <sel:3>   (32-bit)
+  0x7030 0000 0001 00 <reg:5> <sel:3>   (64-bit)
+
+Note: KVM_REG_MIPS_CP0_ENTRYLO0 and KVM_REG_MIPS_CP0_ENTRYLO1 are the MIPS64
+versions of the EntryLo registers regardless of the word size of the host
+hardware, host kernel, guest, and whether XPA is present in the guest, i.e.
+with the RI and XI bits (if they exist) in bits 63 and 62 respectively, and
+the PFNX field starting at bit 30.
+
+MIPS MAARs (see KVM_REG_MIPS_CP0_MAAR(*) above) have the following id bit
+patterns:
+  0x7030 0000 0001 01 <reg:8>
+
+MIPS KVM control registers (see above) have the following id bit patterns:
+  0x7030 0000 0002 <reg:16>
+
+MIPS FPU registers (see KVM_REG_MIPS_FPR_{32,64}() above) have the following
+id bit patterns depending on the size of the register being accessed. They are
+always accessed according to the current guest FPU mode (Status.FR and
+Config5.FRE), i.e. as the guest would see them, and they become unpredictable
+if the guest FPU mode is changed. MIPS SIMD Architecture (MSA) vector
+registers (see KVM_REG_MIPS_VEC_128() above) have similar patterns as they
+overlap the FPU registers:
+  0x7020 0000 0003 00 <0:3> <reg:5> (32-bit FPU registers)
+  0x7030 0000 0003 00 <0:3> <reg:5> (64-bit FPU registers)
+  0x7040 0000 0003 00 <0:3> <reg:5> (128-bit MSA vector registers)
+
+MIPS FPU control registers (see KVM_REG_MIPS_FCR_{IR,CSR} above) have the
+following id bit patterns:
+  0x7020 0000 0003 01 <0:3> <reg:5>
+
+MIPS MSA control registers (see KVM_REG_MIPS_MSA_{IR,CSR} above) have the
+following id bit patterns:
+  0x7020 0000 0003 02 <0:3> <reg:5>
+
+
+4.69 KVM_GET_ONE_REG
+
+Capability: KVM_CAP_ONE_REG
+Architectures: all
+Type: vcpu ioctl
+Parameters: struct kvm_one_reg (in and out)
+Returns: 0 on success, negative value on failure
+Errors include:
+  ENOENT:   no such register
+  EINVAL:   invalid register ID, or no such register
+  EPERM:    (arm64) register access not allowed before vcpu finalization
+(These error codes are indicative only: do not rely on a specific error
+code being returned in a specific situation.)
+
+This ioctl allows to receive the value of a single register implemented
+in a vcpu. The register to read is indicated by the "id" field of the
+kvm_one_reg struct passed in. On success, the register value can be found
+at the memory location pointed to by "addr".
+
+The list of registers accessible using this interface is identical to the
+list in 4.68.
+
+
+4.70 KVM_KVMCLOCK_CTRL
+
+Capability: KVM_CAP_KVMCLOCK_CTRL
+Architectures: Any that implement pvclocks (currently x86 only)
+Type: vcpu ioctl
+Parameters: None
+Returns: 0 on success, -1 on error
+
+This signals to the host kernel that the specified guest is being paused by
+userspace.  The host will set a flag in the pvclock structure that is checked
+from the soft lockup watchdog.  The flag is part of the pvclock structure that
+is shared between guest and host, specifically the second bit of the flags
+field of the pvclock_vcpu_time_info structure.  It will be set exclusively by
+the host and read/cleared exclusively by the guest.  The guest operation of
+checking and clearing the flag must an atomic operation so
+load-link/store-conditional, or equivalent must be used.  There are two cases
+where the guest will clear the flag: when the soft lockup watchdog timer resets
+itself or when a soft lockup is detected.  This ioctl can be called any time
+after pausing the vcpu, but before it is resumed.
+
+
+4.71 KVM_SIGNAL_MSI
+
+Capability: KVM_CAP_SIGNAL_MSI
+Architectures: x86 arm arm64
+Type: vm ioctl
+Parameters: struct kvm_msi (in)
+Returns: >0 on delivery, 0 if guest blocked the MSI, and -1 on error
+
+Directly inject a MSI message. Only valid with in-kernel irqchip that handles
+MSI messages.
+
+struct kvm_msi {
+       __u32 address_lo;
+       __u32 address_hi;
+       __u32 data;
+       __u32 flags;
+       __u32 devid;
+       __u8  pad[12];
+};
+
+flags: KVM_MSI_VALID_DEVID: devid contains a valid value.  The per-VM
+  KVM_CAP_MSI_DEVID capability advertises the requirement to provide
+  the device ID.  If this capability is not available, userspace
+  should never set the KVM_MSI_VALID_DEVID flag as the ioctl might fail.
+
+If KVM_MSI_VALID_DEVID is set, devid contains a unique device identifier
+for the device that wrote the MSI message.  For PCI, this is usually a
+BFD identifier in the lower 16 bits.
+
+On x86, address_hi is ignored unless the KVM_X2APIC_API_USE_32BIT_IDS
+feature of KVM_CAP_X2APIC_API capability is enabled.  If it is enabled,
+address_hi bits 31-8 provide bits 31-8 of the destination id.  Bits 7-0 of
+address_hi must be zero.
+
+
+4.71 KVM_CREATE_PIT2
+
+Capability: KVM_CAP_PIT2
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_pit_config (in)
+Returns: 0 on success, -1 on error
+
+Creates an in-kernel device model for the i8254 PIT. This call is only valid
+after enabling in-kernel irqchip support via KVM_CREATE_IRQCHIP. The following
+parameters have to be passed:
+
+struct kvm_pit_config {
+       __u32 flags;
+       __u32 pad[15];
+};
+
+Valid flags are:
+
+#define KVM_PIT_SPEAKER_DUMMY     1 /* emulate speaker port stub */
+
+PIT timer interrupts may use a per-VM kernel thread for injection. If it
+exists, this thread will have a name of the following pattern:
+
+kvm-pit/<owner-process-pid>
+
+When running a guest with elevated priorities, the scheduling parameters of
+this thread may have to be adjusted accordingly.
+
+This IOCTL replaces the obsolete KVM_CREATE_PIT.
+
+
+4.72 KVM_GET_PIT2
+
+Capability: KVM_CAP_PIT_STATE2
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_pit_state2 (out)
+Returns: 0 on success, -1 on error
+
+Retrieves the state of the in-kernel PIT model. Only valid after
+KVM_CREATE_PIT2. The state is returned in the following structure:
+
+struct kvm_pit_state2 {
+       struct kvm_pit_channel_state channels[3];
+       __u32 flags;
+       __u32 reserved[9];
+};
+
+Valid flags are:
+
+/* disable PIT in HPET legacy mode */
+#define KVM_PIT_FLAGS_HPET_LEGACY  0x00000001
+
+This IOCTL replaces the obsolete KVM_GET_PIT.
+
+
+4.73 KVM_SET_PIT2
+
+Capability: KVM_CAP_PIT_STATE2
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_pit_state2 (in)
+Returns: 0 on success, -1 on error
+
+Sets the state of the in-kernel PIT model. Only valid after KVM_CREATE_PIT2.
+See KVM_GET_PIT2 for details on struct kvm_pit_state2.
+
+This IOCTL replaces the obsolete KVM_SET_PIT.
+
+
+4.74 KVM_PPC_GET_SMMU_INFO
+
+Capability: KVM_CAP_PPC_GET_SMMU_INFO
+Architectures: powerpc
+Type: vm ioctl
+Parameters: None
+Returns: 0 on success, -1 on error
+
+This populates and returns a structure describing the features of
+the "Server" class MMU emulation supported by KVM.
+This can in turn be used by userspace to generate the appropriate
+device-tree properties for the guest operating system.
+
+The structure contains some global information, followed by an
+array of supported segment page sizes:
+
+      struct kvm_ppc_smmu_info {
+            __u64 flags;
+            __u32 slb_size;
+            __u32 pad;
+            struct kvm_ppc_one_seg_page_size sps[KVM_PPC_PAGE_SIZES_MAX_SZ];
+      };
+
+The supported flags are:
+
+    - KVM_PPC_PAGE_SIZES_REAL:
+        When that flag is set, guest page sizes must "fit" the backing
+        store page sizes. When not set, any page size in the list can
+        be used regardless of how they are backed by userspace.
+
+    - KVM_PPC_1T_SEGMENTS
+        The emulated MMU supports 1T segments in addition to the
+        standard 256M ones.
+
+    - KVM_PPC_NO_HASH
+       This flag indicates that HPT guests are not supported by KVM,
+       thus all guests must use radix MMU mode.
+
+The "slb_size" field indicates how many SLB entries are supported
+
+The "sps" array contains 8 entries indicating the supported base
+page sizes for a segment in increasing order. Each entry is defined
+as follow:
+
+   struct kvm_ppc_one_seg_page_size {
+       __u32 page_shift;       /* Base page shift of segment (or 0) */
+       __u32 slb_enc;          /* SLB encoding for BookS */
+       struct kvm_ppc_one_page_size enc[KVM_PPC_PAGE_SIZES_MAX_SZ];
+   };
+
+An entry with a "page_shift" of 0 is unused. Because the array is
+organized in increasing order, a lookup can stop when encoutering
+such an entry.
+
+The "slb_enc" field provides the encoding to use in the SLB for the
+page size. The bits are in positions such as the value can directly
+be OR'ed into the "vsid" argument of the slbmte instruction.
+
+The "enc" array is a list which for each of those segment base page
+size provides the list of supported actual page sizes (which can be
+only larger or equal to the base page size), along with the
+corresponding encoding in the hash PTE. Similarly, the array is
+8 entries sorted by increasing sizes and an entry with a "0" shift
+is an empty entry and a terminator:
+
+   struct kvm_ppc_one_page_size {
+       __u32 page_shift;       /* Page shift (or 0) */
+       __u32 pte_enc;          /* Encoding in the HPTE (>>12) */
+   };
+
+The "pte_enc" field provides a value that can OR'ed into the hash
+PTE's RPN field (ie, it needs to be shifted left by 12 to OR it
+into the hash PTE second double word).
+
+4.75 KVM_IRQFD
+
+Capability: KVM_CAP_IRQFD
+Architectures: x86 s390 arm arm64
+Type: vm ioctl
+Parameters: struct kvm_irqfd (in)
+Returns: 0 on success, -1 on error
+
+Allows setting an eventfd to directly trigger a guest interrupt.
+kvm_irqfd.fd specifies the file descriptor to use as the eventfd and
+kvm_irqfd.gsi specifies the irqchip pin toggled by this event.  When
+an event is triggered on the eventfd, an interrupt is injected into
+the guest using the specified gsi pin.  The irqfd is removed using
+the KVM_IRQFD_FLAG_DEASSIGN flag, specifying both kvm_irqfd.fd
+and kvm_irqfd.gsi.
+
+With KVM_CAP_IRQFD_RESAMPLE, KVM_IRQFD supports a de-assert and notify
+mechanism allowing emulation of level-triggered, irqfd-based
+interrupts.  When KVM_IRQFD_FLAG_RESAMPLE is set the user must pass an
+additional eventfd in the kvm_irqfd.resamplefd field.  When operating
+in resample mode, posting of an interrupt through kvm_irq.fd asserts
+the specified gsi in the irqchip.  When the irqchip is resampled, such
+as from an EOI, the gsi is de-asserted and the user is notified via
+kvm_irqfd.resamplefd.  It is the user's responsibility to re-queue
+the interrupt if the device making use of it still requires service.
+Note that closing the resamplefd is not sufficient to disable the
+irqfd.  The KVM_IRQFD_FLAG_RESAMPLE is only necessary on assignment
+and need not be specified with KVM_IRQFD_FLAG_DEASSIGN.
+
+On arm/arm64, gsi routing being supported, the following can happen:
+- in case no routing entry is associated to this gsi, injection fails
+- in case the gsi is associated to an irqchip routing entry,
+  irqchip.pin + 32 corresponds to the injected SPI ID.
+- in case the gsi is associated to an MSI routing entry, the MSI
+  message and device ID are translated into an LPI (support restricted
+  to GICv3 ITS in-kernel emulation).
+
+4.76 KVM_PPC_ALLOCATE_HTAB
+
+Capability: KVM_CAP_PPC_ALLOC_HTAB
+Architectures: powerpc
+Type: vm ioctl
+Parameters: Pointer to u32 containing hash table order (in/out)
+Returns: 0 on success, -1 on error
+
+This requests the host kernel to allocate an MMU hash table for a
+guest using the PAPR paravirtualization interface.  This only does
+anything if the kernel is configured to use the Book 3S HV style of
+virtualization.  Otherwise the capability doesn't exist and the ioctl
+returns an ENOTTY error.  The rest of this description assumes Book 3S
+HV.
+
+There must be no vcpus running when this ioctl is called; if there
+are, it will do nothing and return an EBUSY error.
+
+The parameter is a pointer to a 32-bit unsigned integer variable
+containing the order (log base 2) of the desired size of the hash
+table, which must be between 18 and 46.  On successful return from the
+ioctl, the value will not be changed by the kernel.
+
+If no hash table has been allocated when any vcpu is asked to run
+(with the KVM_RUN ioctl), the host kernel will allocate a
+default-sized hash table (16 MB).
+
+If this ioctl is called when a hash table has already been allocated,
+with a different order from the existing hash table, the existing hash
+table will be freed and a new one allocated.  If this is ioctl is
+called when a hash table has already been allocated of the same order
+as specified, the kernel will clear out the existing hash table (zero
+all HPTEs).  In either case, if the guest is using the virtualized
+real-mode area (VRMA) facility, the kernel will re-create the VMRA
+HPTEs on the next KVM_RUN of any vcpu.
+
+4.77 KVM_S390_INTERRUPT
+
+Capability: basic
+Architectures: s390
+Type: vm ioctl, vcpu ioctl
+Parameters: struct kvm_s390_interrupt (in)
+Returns: 0 on success, -1 on error
+
+Allows to inject an interrupt to the guest. Interrupts can be floating
+(vm ioctl) or per cpu (vcpu ioctl), depending on the interrupt type.
+
+Interrupt parameters are passed via kvm_s390_interrupt:
+
+struct kvm_s390_interrupt {
+       __u32 type;
+       __u32 parm;
+       __u64 parm64;
+};
+
+type can be one of the following:
+
+KVM_S390_SIGP_STOP (vcpu) - sigp stop; optional flags in parm
+KVM_S390_PROGRAM_INT (vcpu) - program check; code in parm
+KVM_S390_SIGP_SET_PREFIX (vcpu) - sigp set prefix; prefix address in parm
+KVM_S390_RESTART (vcpu) - restart
+KVM_S390_INT_CLOCK_COMP (vcpu) - clock comparator interrupt
+KVM_S390_INT_CPU_TIMER (vcpu) - CPU timer interrupt
+KVM_S390_INT_VIRTIO (vm) - virtio external interrupt; external interrupt
+                          parameters in parm and parm64
+KVM_S390_INT_SERVICE (vm) - sclp external interrupt; sclp parameter in parm
+KVM_S390_INT_EMERGENCY (vcpu) - sigp emergency; source cpu in parm
+KVM_S390_INT_EXTERNAL_CALL (vcpu) - sigp external call; source cpu in parm
+KVM_S390_INT_IO(ai,cssid,ssid,schid) (vm) - compound value to indicate an
+    I/O interrupt (ai - adapter interrupt; cssid,ssid,schid - subchannel);
+    I/O interruption parameters in parm (subchannel) and parm64 (intparm,
+    interruption subclass)
+KVM_S390_MCHK (vm, vcpu) - machine check interrupt; cr 14 bits in parm,
+                           machine check interrupt code in parm64 (note that
+                           machine checks needing further payload are not
+                           supported by this ioctl)
+
+This is an asynchronous vcpu ioctl and can be invoked from any thread.
+
+4.78 KVM_PPC_GET_HTAB_FD
+
+Capability: KVM_CAP_PPC_HTAB_FD
+Architectures: powerpc
+Type: vm ioctl
+Parameters: Pointer to struct kvm_get_htab_fd (in)
+Returns: file descriptor number (>= 0) on success, -1 on error
+
+This returns a file descriptor that can be used either to read out the
+entries in the guest's hashed page table (HPT), or to write entries to
+initialize the HPT.  The returned fd can only be written to if the
+KVM_GET_HTAB_WRITE bit is set in the flags field of the argument, and
+can only be read if that bit is clear.  The argument struct looks like
+this:
+
+/* For KVM_PPC_GET_HTAB_FD */
+struct kvm_get_htab_fd {
+       __u64   flags;
+       __u64   start_index;
+       __u64   reserved[2];
+};
+
+/* Values for kvm_get_htab_fd.flags */
+#define KVM_GET_HTAB_BOLTED_ONLY       ((__u64)0x1)
+#define KVM_GET_HTAB_WRITE             ((__u64)0x2)
+
+The `start_index' field gives the index in the HPT of the entry at
+which to start reading.  It is ignored when writing.
+
+Reads on the fd will initially supply information about all
+"interesting" HPT entries.  Interesting entries are those with the
+bolted bit set, if the KVM_GET_HTAB_BOLTED_ONLY bit is set, otherwise
+all entries.  When the end of the HPT is reached, the read() will
+return.  If read() is called again on the fd, it will start again from
+the beginning of the HPT, but will only return HPT entries that have
+changed since they were last read.
+
+Data read or written is structured as a header (8 bytes) followed by a
+series of valid HPT entries (16 bytes) each.  The header indicates how
+many valid HPT entries there are and how many invalid entries follow
+the valid entries.  The invalid entries are not represented explicitly
+in the stream.  The header format is:
+
+struct kvm_get_htab_header {
+       __u32   index;
+       __u16   n_valid;
+       __u16   n_invalid;
+};
+
+Writes to the fd create HPT entries starting at the index given in the
+header; first `n_valid' valid entries with contents from the data
+written, then `n_invalid' invalid entries, invalidating any previously
+valid entries found.
+
+4.79 KVM_CREATE_DEVICE
+
+Capability: KVM_CAP_DEVICE_CTRL
+Type: vm ioctl
+Parameters: struct kvm_create_device (in/out)
+Returns: 0 on success, -1 on error
+Errors:
+  ENODEV: The device type is unknown or unsupported
+  EEXIST: Device already created, and this type of device may not
+          be instantiated multiple times
+
+  Other error conditions may be defined by individual device types or
+  have their standard meanings.
+
+Creates an emulated device in the kernel.  The file descriptor returned
+in fd can be used with KVM_SET/GET/HAS_DEVICE_ATTR.
+
+If the KVM_CREATE_DEVICE_TEST flag is set, only test whether the
+device type is supported (not necessarily whether it can be created
+in the current vm).
+
+Individual devices should not define flags.  Attributes should be used
+for specifying any behavior that is not implied by the device type
+number.
+
+struct kvm_create_device {
+       __u32   type;   /* in: KVM_DEV_TYPE_xxx */
+       __u32   fd;     /* out: device handle */
+       __u32   flags;  /* in: KVM_CREATE_DEVICE_xxx */
+};
+
+4.80 KVM_SET_DEVICE_ATTR/KVM_GET_DEVICE_ATTR
+
+Capability: KVM_CAP_DEVICE_CTRL, KVM_CAP_VM_ATTRIBUTES for vm device,
+  KVM_CAP_VCPU_ATTRIBUTES for vcpu device
+Type: device ioctl, vm ioctl, vcpu ioctl
+Parameters: struct kvm_device_attr
+Returns: 0 on success, -1 on error
+Errors:
+  ENXIO:  The group or attribute is unknown/unsupported for this device
+          or hardware support is missing.
+  EPERM:  The attribute cannot (currently) be accessed this way
+          (e.g. read-only attribute, or attribute that only makes
+          sense when the device is in a different state)
+
+  Other error conditions may be defined by individual device types.
+
+Gets/sets a specified piece of device configuration and/or state.  The
+semantics are device-specific.  See individual device documentation in
+the "devices" directory.  As with ONE_REG, the size of the data
+transferred is defined by the particular attribute.
+
+struct kvm_device_attr {
+       __u32   flags;          /* no flags currently defined */
+       __u32   group;          /* device-defined */
+       __u64   attr;           /* group-defined */
+       __u64   addr;           /* userspace address of attr data */
+};
+
+4.81 KVM_HAS_DEVICE_ATTR
+
+Capability: KVM_CAP_DEVICE_CTRL, KVM_CAP_VM_ATTRIBUTES for vm device,
+  KVM_CAP_VCPU_ATTRIBUTES for vcpu device
+Type: device ioctl, vm ioctl, vcpu ioctl
+Parameters: struct kvm_device_attr
+Returns: 0 on success, -1 on error
+Errors:
+  ENXIO:  The group or attribute is unknown/unsupported for this device
+          or hardware support is missing.
+
+Tests whether a device supports a particular attribute.  A successful
+return indicates the attribute is implemented.  It does not necessarily
+indicate that the attribute can be read or written in the device's
+current state.  "addr" is ignored.
+
+4.82 KVM_ARM_VCPU_INIT
+
+Capability: basic
+Architectures: arm, arm64
+Type: vcpu ioctl
+Parameters: struct kvm_vcpu_init (in)
+Returns: 0 on success; -1 on error
+Errors:
+  EINVAL:    the target is unknown, or the combination of features is invalid.
+  ENOENT:    a features bit specified is unknown.
+
+This tells KVM what type of CPU to present to the guest, and what
+optional features it should have.  This will cause a reset of the cpu
+registers to their initial values.  If this is not called, KVM_RUN will
+return ENOEXEC for that vcpu.
+
+Note that because some registers reflect machine topology, all vcpus
+should be created before this ioctl is invoked.
+
+Userspace can call this function multiple times for a given vcpu, including
+after the vcpu has been run. This will reset the vcpu to its initial
+state. All calls to this function after the initial call must use the same
+target and same set of feature flags, otherwise EINVAL will be returned.
+
+Possible features:
+       - KVM_ARM_VCPU_POWER_OFF: Starts the CPU in a power-off state.
+         Depends on KVM_CAP_ARM_PSCI.  If not set, the CPU will be powered on
+         and execute guest code when KVM_RUN is called.
+       - KVM_ARM_VCPU_EL1_32BIT: Starts the CPU in a 32bit mode.
+         Depends on KVM_CAP_ARM_EL1_32BIT (arm64 only).
+       - KVM_ARM_VCPU_PSCI_0_2: Emulate PSCI v0.2 (or a future revision
+          backward compatible with v0.2) for the CPU.
+         Depends on KVM_CAP_ARM_PSCI_0_2.
+       - KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU.
+         Depends on KVM_CAP_ARM_PMU_V3.
+
+       - KVM_ARM_VCPU_PTRAUTH_ADDRESS: Enables Address Pointer authentication
+         for arm64 only.
+         Depends on KVM_CAP_ARM_PTRAUTH_ADDRESS.
+         If KVM_CAP_ARM_PTRAUTH_ADDRESS and KVM_CAP_ARM_PTRAUTH_GENERIC are
+         both present, then both KVM_ARM_VCPU_PTRAUTH_ADDRESS and
+         KVM_ARM_VCPU_PTRAUTH_GENERIC must be requested or neither must be
+         requested.
+
+       - KVM_ARM_VCPU_PTRAUTH_GENERIC: Enables Generic Pointer authentication
+         for arm64 only.
+         Depends on KVM_CAP_ARM_PTRAUTH_GENERIC.
+         If KVM_CAP_ARM_PTRAUTH_ADDRESS and KVM_CAP_ARM_PTRAUTH_GENERIC are
+         both present, then both KVM_ARM_VCPU_PTRAUTH_ADDRESS and
+         KVM_ARM_VCPU_PTRAUTH_GENERIC must be requested or neither must be
+         requested.
+
+       - KVM_ARM_VCPU_SVE: Enables SVE for the CPU (arm64 only).
+         Depends on KVM_CAP_ARM_SVE.
+         Requires KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
+
+          * After KVM_ARM_VCPU_INIT:
+
+             - KVM_REG_ARM64_SVE_VLS may be read using KVM_GET_ONE_REG: the
+               initial value of this pseudo-register indicates the best set of
+               vector lengths possible for a vcpu on this host.
+
+          * Before KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
+
+             - KVM_RUN and KVM_GET_REG_LIST are not available;
+
+             - KVM_GET_ONE_REG and KVM_SET_ONE_REG cannot be used to access
+               the scalable archietctural SVE registers
+               KVM_REG_ARM64_SVE_ZREG(), KVM_REG_ARM64_SVE_PREG() or
+               KVM_REG_ARM64_SVE_FFR;
+
+             - KVM_REG_ARM64_SVE_VLS may optionally be written using
+               KVM_SET_ONE_REG, to modify the set of vector lengths available
+               for the vcpu.
+
+          * After KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
+
+             - the KVM_REG_ARM64_SVE_VLS pseudo-register is immutable, and can
+               no longer be written using KVM_SET_ONE_REG.
+
+4.83 KVM_ARM_PREFERRED_TARGET
+
+Capability: basic
+Architectures: arm, arm64
+Type: vm ioctl
+Parameters: struct struct kvm_vcpu_init (out)
+Returns: 0 on success; -1 on error
+Errors:
+  ENODEV:    no preferred target available for the host
+
+This queries KVM for preferred CPU target type which can be emulated
+by KVM on underlying host.
+
+The ioctl returns struct kvm_vcpu_init instance containing information
+about preferred CPU target type and recommended features for it.  The
+kvm_vcpu_init->features bitmap returned will have feature bits set if
+the preferred target recommends setting these features, but this is
+not mandatory.
+
+The information returned by this ioctl can be used to prepare an instance
+of struct kvm_vcpu_init for KVM_ARM_VCPU_INIT ioctl which will result in
+in VCPU matching underlying host.
+
+
+4.84 KVM_GET_REG_LIST
+
+Capability: basic
+Architectures: arm, arm64, mips
+Type: vcpu ioctl
+Parameters: struct kvm_reg_list (in/out)
+Returns: 0 on success; -1 on error
+Errors:
+  E2BIG:     the reg index list is too big to fit in the array specified by
+             the user (the number required will be written into n).
+
+struct kvm_reg_list {
+       __u64 n; /* number of registers in reg[] */
+       __u64 reg[0];
+};
+
+This ioctl returns the guest registers that are supported for the
+KVM_GET_ONE_REG/KVM_SET_ONE_REG calls.
+
+
+4.85 KVM_ARM_SET_DEVICE_ADDR (deprecated)
+
+Capability: KVM_CAP_ARM_SET_DEVICE_ADDR
+Architectures: arm, arm64
+Type: vm ioctl
+Parameters: struct kvm_arm_device_address (in)
+Returns: 0 on success, -1 on error
+Errors:
+  ENODEV: The device id is unknown
+  ENXIO:  Device not supported on current system
+  EEXIST: Address already set
+  E2BIG:  Address outside guest physical address space
+  EBUSY:  Address overlaps with other device range
+
+struct kvm_arm_device_addr {
+       __u64 id;
+       __u64 addr;
+};
+
+Specify a device address in the guest's physical address space where guests
+can access emulated or directly exposed devices, which the host kernel needs
+to know about. The id field is an architecture specific identifier for a
+specific device.
+
+ARM/arm64 divides the id field into two parts, a device id and an
+address type id specific to the individual device.
+
+  bits:  | 63        ...       32 | 31    ...    16 | 15    ...    0 |
+  field: |        0x00000000      |     device id   |  addr type id  |
+
+ARM/arm64 currently only require this when using the in-kernel GIC
+support for the hardware VGIC features, using KVM_ARM_DEVICE_VGIC_V2
+as the device id.  When setting the base address for the guest's
+mapping of the VGIC virtual CPU and distributor interface, the ioctl
+must be called after calling KVM_CREATE_IRQCHIP, but before calling
+KVM_RUN on any of the VCPUs.  Calling this ioctl twice for any of the
+base addresses will return -EEXIST.
+
+Note, this IOCTL is deprecated and the more flexible SET/GET_DEVICE_ATTR API
+should be used instead.
+
+
+4.86 KVM_PPC_RTAS_DEFINE_TOKEN
+
+Capability: KVM_CAP_PPC_RTAS
+Architectures: ppc
+Type: vm ioctl
+Parameters: struct kvm_rtas_token_args
+Returns: 0 on success, -1 on error
+
+Defines a token value for a RTAS (Run Time Abstraction Services)
+service in order to allow it to be handled in the kernel.  The
+argument struct gives the name of the service, which must be the name
+of a service that has a kernel-side implementation.  If the token
+value is non-zero, it will be associated with that service, and
+subsequent RTAS calls by the guest specifying that token will be
+handled by the kernel.  If the token value is 0, then any token
+associated with the service will be forgotten, and subsequent RTAS
+calls by the guest for that service will be passed to userspace to be
+handled.
+
+4.87 KVM_SET_GUEST_DEBUG
+
+Capability: KVM_CAP_SET_GUEST_DEBUG
+Architectures: x86, s390, ppc, arm64
+Type: vcpu ioctl
+Parameters: struct kvm_guest_debug (in)
+Returns: 0 on success; -1 on error
+
+struct kvm_guest_debug {
+       __u32 control;
+       __u32 pad;
+       struct kvm_guest_debug_arch arch;
+};
+
+Set up the processor specific debug registers and configure vcpu for
+handling guest debug events. There are two parts to the structure, the
+first a control bitfield indicates the type of debug events to handle
+when running. Common control bits are:
+
+  - KVM_GUESTDBG_ENABLE:        guest debugging is enabled
+  - KVM_GUESTDBG_SINGLESTEP:    the next run should single-step
+
+The top 16 bits of the control field are architecture specific control
+flags which can include the following:
+
+  - KVM_GUESTDBG_USE_SW_BP:     using software breakpoints [x86, arm64]
+  - KVM_GUESTDBG_USE_HW_BP:     using hardware breakpoints [x86, s390, arm64]
+  - KVM_GUESTDBG_INJECT_DB:     inject DB type exception [x86]
+  - KVM_GUESTDBG_INJECT_BP:     inject BP type exception [x86]
+  - KVM_GUESTDBG_EXIT_PENDING:  trigger an immediate guest exit [s390]
+
+For example KVM_GUESTDBG_USE_SW_BP indicates that software breakpoints
+are enabled in memory so we need to ensure breakpoint exceptions are
+correctly trapped and the KVM run loop exits at the breakpoint and not
+running off into the normal guest vector. For KVM_GUESTDBG_USE_HW_BP
+we need to ensure the guest vCPUs architecture specific registers are
+updated to the correct (supplied) values.
+
+The second part of the structure is architecture specific and
+typically contains a set of debug registers.
+
+For arm64 the number of debug registers is implementation defined and
+can be determined by querying the KVM_CAP_GUEST_DEBUG_HW_BPS and
+KVM_CAP_GUEST_DEBUG_HW_WPS capabilities which return a positive number
+indicating the number of supported registers.
+
+When debug events exit the main run loop with the reason
+KVM_EXIT_DEBUG with the kvm_debug_exit_arch part of the kvm_run
+structure containing architecture specific debug information.
+
+4.88 KVM_GET_EMULATED_CPUID
+
+Capability: KVM_CAP_EXT_EMUL_CPUID
+Architectures: x86
+Type: system ioctl
+Parameters: struct kvm_cpuid2 (in/out)
+Returns: 0 on success, -1 on error
+
+struct kvm_cpuid2 {
+       __u32 nent;
+       __u32 flags;
+       struct kvm_cpuid_entry2 entries[0];
+};
+
+The member 'flags' is used for passing flags from userspace.
+
+#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX                BIT(0)
+#define KVM_CPUID_FLAG_STATEFUL_FUNC           BIT(1)
+#define KVM_CPUID_FLAG_STATE_READ_NEXT         BIT(2)
+
+struct kvm_cpuid_entry2 {
+       __u32 function;
+       __u32 index;
+       __u32 flags;
+       __u32 eax;
+       __u32 ebx;
+       __u32 ecx;
+       __u32 edx;
+       __u32 padding[3];
+};
+
+This ioctl returns x86 cpuid features which are emulated by
+kvm.Userspace can use the information returned by this ioctl to query
+which features are emulated by kvm instead of being present natively.
+
+Userspace invokes KVM_GET_EMULATED_CPUID by passing a kvm_cpuid2
+structure with the 'nent' field indicating the number of entries in
+the variable-size array 'entries'. If the number of entries is too low
+to describe the cpu capabilities, an error (E2BIG) is returned. If the
+number is too high, the 'nent' field is adjusted and an error (ENOMEM)
+is returned. If the number is just right, the 'nent' field is adjusted
+to the number of valid entries in the 'entries' array, which is then
+filled.
+
+The entries returned are the set CPUID bits of the respective features
+which kvm emulates, as returned by the CPUID instruction, with unknown
+or unsupported feature bits cleared.
+
+Features like x2apic, for example, may not be present in the host cpu
+but are exposed by kvm in KVM_GET_SUPPORTED_CPUID because they can be
+emulated efficiently and thus not included here.
+
+The fields in each entry are defined as follows:
+
+  function: the eax value used to obtain the entry
+  index: the ecx value used to obtain the entry (for entries that are
+         affected by ecx)
+  flags: an OR of zero or more of the following:
+        KVM_CPUID_FLAG_SIGNIFCANT_INDEX:
+           if the index field is valid
+        KVM_CPUID_FLAG_STATEFUL_FUNC:
+           if cpuid for this function returns different values for successive
+           invocations; there will be several entries with the same function,
+           all with this flag set
+        KVM_CPUID_FLAG_STATE_READ_NEXT:
+           for KVM_CPUID_FLAG_STATEFUL_FUNC entries, set if this entry is
+           the first entry to be read by a cpu
+   eax, ebx, ecx, edx: the values returned by the cpuid instruction for
+         this function/index combination
+
+4.89 KVM_S390_MEM_OP
+
+Capability: KVM_CAP_S390_MEM_OP
+Architectures: s390
+Type: vcpu ioctl
+Parameters: struct kvm_s390_mem_op (in)
+Returns: = 0 on success,
+         < 0 on generic error (e.g. -EFAULT or -ENOMEM),
+         > 0 if an exception occurred while walking the page tables
+
+Read or write data from/to the logical (virtual) memory of a VCPU.
+
+Parameters are specified via the following structure:
+
+struct kvm_s390_mem_op {
+       __u64 gaddr;            /* the guest address */
+       __u64 flags;            /* flags */
+       __u32 size;             /* amount of bytes */
+       __u32 op;               /* type of operation */
+       __u64 buf;              /* buffer in userspace */
+       __u8 ar;                /* the access register number */
+       __u8 reserved[31];      /* should be set to 0 */
+};
+
+The type of operation is specified in the "op" field. It is either
+KVM_S390_MEMOP_LOGICAL_READ for reading from logical memory space or
+KVM_S390_MEMOP_LOGICAL_WRITE for writing to logical memory space. The
+KVM_S390_MEMOP_F_CHECK_ONLY flag can be set in the "flags" field to check
+whether the corresponding memory access would create an access exception
+(without touching the data in the memory at the destination). In case an
+access exception occurred while walking the MMU tables of the guest, the
+ioctl returns a positive error number to indicate the type of exception.
+This exception is also raised directly at the corresponding VCPU if the
+flag KVM_S390_MEMOP_F_INJECT_EXCEPTION is set in the "flags" field.
+
+The start address of the memory region has to be specified in the "gaddr"
+field, and the length of the region in the "size" field. "buf" is the buffer
+supplied by the userspace application where the read data should be written
+to for KVM_S390_MEMOP_LOGICAL_READ, or where the data that should be written
+is stored for a KVM_S390_MEMOP_LOGICAL_WRITE. "buf" is unused and can be NULL
+when KVM_S390_MEMOP_F_CHECK_ONLY is specified. "ar" designates the access
+register number to be used.
+
+The "reserved" field is meant for future extensions. It is not used by
+KVM with the currently defined set of flags.
+
+4.90 KVM_S390_GET_SKEYS
+
+Capability: KVM_CAP_S390_SKEYS
+Architectures: s390
+Type: vm ioctl
+Parameters: struct kvm_s390_skeys
+Returns: 0 on success, KVM_S390_GET_KEYS_NONE if guest is not using storage
+         keys, negative value on error
+
+This ioctl is used to get guest storage key values on the s390
+architecture. The ioctl takes parameters via the kvm_s390_skeys struct.
+
+struct kvm_s390_skeys {
+       __u64 start_gfn;
+       __u64 count;
+       __u64 skeydata_addr;
+       __u32 flags;
+       __u32 reserved[9];
+};
+
+The start_gfn field is the number of the first guest frame whose storage keys
+you want to get.
+
+The count field is the number of consecutive frames (starting from start_gfn)
+whose storage keys to get. The count field must be at least 1 and the maximum
+allowed value is defined as KVM_S390_SKEYS_ALLOC_MAX. Values outside this range
+will cause the ioctl to return -EINVAL.
+
+The skeydata_addr field is the address to a buffer large enough to hold count
+bytes. This buffer will be filled with storage key data by the ioctl.
+
+4.91 KVM_S390_SET_SKEYS
+
+Capability: KVM_CAP_S390_SKEYS
+Architectures: s390
+Type: vm ioctl
+Parameters: struct kvm_s390_skeys
+Returns: 0 on success, negative value on error
+
+This ioctl is used to set guest storage key values on the s390
+architecture. The ioctl takes parameters via the kvm_s390_skeys struct.
+See section on KVM_S390_GET_SKEYS for struct definition.
+
+The start_gfn field is the number of the first guest frame whose storage keys
+you want to set.
+
+The count field is the number of consecutive frames (starting from start_gfn)
+whose storage keys to get. The count field must be at least 1 and the maximum
+allowed value is defined as KVM_S390_SKEYS_ALLOC_MAX. Values outside this range
+will cause the ioctl to return -EINVAL.
+
+The skeydata_addr field is the address to a buffer containing count bytes of
+storage keys. Each byte in the buffer will be set as the storage key for a
+single frame starting at start_gfn for count frames.
+
+Note: If any architecturally invalid key value is found in the given data then
+the ioctl will return -EINVAL.
+
+4.92 KVM_S390_IRQ
+
+Capability: KVM_CAP_S390_INJECT_IRQ
+Architectures: s390
+Type: vcpu ioctl
+Parameters: struct kvm_s390_irq (in)
+Returns: 0 on success, -1 on error
+Errors:
+  EINVAL: interrupt type is invalid
+          type is KVM_S390_SIGP_STOP and flag parameter is invalid value
+          type is KVM_S390_INT_EXTERNAL_CALL and code is bigger
+            than the maximum of VCPUs
+  EBUSY:  type is KVM_S390_SIGP_SET_PREFIX and vcpu is not stopped
+          type is KVM_S390_SIGP_STOP and a stop irq is already pending
+          type is KVM_S390_INT_EXTERNAL_CALL and an external call interrupt
+            is already pending
+
+Allows to inject an interrupt to the guest.
+
+Using struct kvm_s390_irq as a parameter allows
+to inject additional payload which is not
+possible via KVM_S390_INTERRUPT.
+
+Interrupt parameters are passed via kvm_s390_irq:
+
+struct kvm_s390_irq {
+       __u64 type;
+       union {
+               struct kvm_s390_io_info io;
+               struct kvm_s390_ext_info ext;
+               struct kvm_s390_pgm_info pgm;
+               struct kvm_s390_emerg_info emerg;
+               struct kvm_s390_extcall_info extcall;
+               struct kvm_s390_prefix_info prefix;
+               struct kvm_s390_stop_info stop;
+               struct kvm_s390_mchk_info mchk;
+               char reserved[64];
+       } u;
+};
+
+type can be one of the following:
+
+KVM_S390_SIGP_STOP - sigp stop; parameter in .stop
+KVM_S390_PROGRAM_INT - program check; parameters in .pgm
+KVM_S390_SIGP_SET_PREFIX - sigp set prefix; parameters in .prefix
+KVM_S390_RESTART - restart; no parameters
+KVM_S390_INT_CLOCK_COMP - clock comparator interrupt; no parameters
+KVM_S390_INT_CPU_TIMER - CPU timer interrupt; no parameters
+KVM_S390_INT_EMERGENCY - sigp emergency; parameters in .emerg
+KVM_S390_INT_EXTERNAL_CALL - sigp external call; parameters in .extcall
+KVM_S390_MCHK - machine check interrupt; parameters in .mchk
+
+This is an asynchronous vcpu ioctl and can be invoked from any thread.
+
+4.94 KVM_S390_GET_IRQ_STATE
+
+Capability: KVM_CAP_S390_IRQ_STATE
+Architectures: s390
+Type: vcpu ioctl
+Parameters: struct kvm_s390_irq_state (out)
+Returns: >= number of bytes copied into buffer,
+         -EINVAL if buffer size is 0,
+         -ENOBUFS if buffer size is too small to fit all pending interrupts,
+         -EFAULT if the buffer address was invalid
+
+This ioctl allows userspace to retrieve the complete state of all currently
+pending interrupts in a single buffer. Use cases include migration
+and introspection. The parameter structure contains the address of a
+userspace buffer and its length:
+
+struct kvm_s390_irq_state {
+       __u64 buf;
+       __u32 flags;        /* will stay unused for compatibility reasons */
+       __u32 len;
+       __u32 reserved[4];  /* will stay unused for compatibility reasons */
+};
+
+Userspace passes in the above struct and for each pending interrupt a
+struct kvm_s390_irq is copied to the provided buffer.
+
+The structure contains a flags and a reserved field for future extensions. As
+the kernel never checked for flags == 0 and QEMU never pre-zeroed flags and
+reserved, these fields can not be used in the future without breaking
+compatibility.
+
+If -ENOBUFS is returned the buffer provided was too small and userspace
+may retry with a bigger buffer.
+
+4.95 KVM_S390_SET_IRQ_STATE
+
+Capability: KVM_CAP_S390_IRQ_STATE
+Architectures: s390
+Type: vcpu ioctl
+Parameters: struct kvm_s390_irq_state (in)
+Returns: 0 on success,
+         -EFAULT if the buffer address was invalid,
+         -EINVAL for an invalid buffer length (see below),
+         -EBUSY if there were already interrupts pending,
+         errors occurring when actually injecting the
+          interrupt. See KVM_S390_IRQ.
+
+This ioctl allows userspace to set the complete state of all cpu-local
+interrupts currently pending for the vcpu. It is intended for restoring
+interrupt state after a migration. The input parameter is a userspace buffer
+containing a struct kvm_s390_irq_state:
+
+struct kvm_s390_irq_state {
+       __u64 buf;
+       __u32 flags;        /* will stay unused for compatibility reasons */
+       __u32 len;
+       __u32 reserved[4];  /* will stay unused for compatibility reasons */
+};
+
+The restrictions for flags and reserved apply as well.
+(see KVM_S390_GET_IRQ_STATE)
+
+The userspace memory referenced by buf contains a struct kvm_s390_irq
+for each interrupt to be injected into the guest.
+If one of the interrupts could not be injected for some reason the
+ioctl aborts.
+
+len must be a multiple of sizeof(struct kvm_s390_irq). It must be > 0
+and it must not exceed (max_vcpus + 32) * sizeof(struct kvm_s390_irq),
+which is the maximum number of possibly pending cpu-local interrupts.
+
+4.96 KVM_SMI
+
+Capability: KVM_CAP_X86_SMM
+Architectures: x86
+Type: vcpu ioctl
+Parameters: none
+Returns: 0 on success, -1 on error
+
+Queues an SMI on the thread's vcpu.
+
+4.97 KVM_CAP_PPC_MULTITCE
+
+Capability: KVM_CAP_PPC_MULTITCE
+Architectures: ppc
+Type: vm
+
+This capability means the kernel is capable of handling hypercalls
+H_PUT_TCE_INDIRECT and H_STUFF_TCE without passing those into the user
+space. This significantly accelerates DMA operations for PPC KVM guests.
+User space should expect that its handlers for these hypercalls
+are not going to be called if user space previously registered LIOBN
+in KVM (via KVM_CREATE_SPAPR_TCE or similar calls).
+
+In order to enable H_PUT_TCE_INDIRECT and H_STUFF_TCE use in the guest,
+user space might have to advertise it for the guest. For example,
+IBM pSeries (sPAPR) guest starts using them if "hcall-multi-tce" is
+present in the "ibm,hypertas-functions" device-tree property.
+
+The hypercalls mentioned above may or may not be processed successfully
+in the kernel based fast path. If they can not be handled by the kernel,
+they will get passed on to user space. So user space still has to have
+an implementation for these despite the in kernel acceleration.
+
+This capability is always enabled.
+
+4.98 KVM_CREATE_SPAPR_TCE_64
+
+Capability: KVM_CAP_SPAPR_TCE_64
+Architectures: powerpc
+Type: vm ioctl
+Parameters: struct kvm_create_spapr_tce_64 (in)
+Returns: file descriptor for manipulating the created TCE table
+
+This is an extension for KVM_CAP_SPAPR_TCE which only supports 32bit
+windows, described in 4.62 KVM_CREATE_SPAPR_TCE
+
+This capability uses extended struct in ioctl interface:
+
+/* for KVM_CAP_SPAPR_TCE_64 */
+struct kvm_create_spapr_tce_64 {
+       __u64 liobn;
+       __u32 page_shift;
+       __u32 flags;
+       __u64 offset;   /* in pages */
+       __u64 size;     /* in pages */
+};
+
+The aim of extension is to support an additional bigger DMA window with
+a variable page size.
+KVM_CREATE_SPAPR_TCE_64 receives a 64bit window size, an IOMMU page shift and
+a bus offset of the corresponding DMA window, @size and @offset are numbers
+of IOMMU pages.
+
+@flags are not used at the moment.
+
+The rest of functionality is identical to KVM_CREATE_SPAPR_TCE.
+
+4.99 KVM_REINJECT_CONTROL
+
+Capability: KVM_CAP_REINJECT_CONTROL
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_reinject_control (in)
+Returns: 0 on success,
+         -EFAULT if struct kvm_reinject_control cannot be read,
+         -ENXIO if KVM_CREATE_PIT or KVM_CREATE_PIT2 didn't succeed earlier.
+
+i8254 (PIT) has two modes, reinject and !reinject.  The default is reinject,
+where KVM queues elapsed i8254 ticks and monitors completion of interrupt from
+vector(s) that i8254 injects.  Reinject mode dequeues a tick and injects its
+interrupt whenever there isn't a pending interrupt from i8254.
+!reinject mode injects an interrupt as soon as a tick arrives.
+
+struct kvm_reinject_control {
+       __u8 pit_reinject;
+       __u8 reserved[31];
+};
+
+pit_reinject = 0 (!reinject mode) is recommended, unless running an old
+operating system that uses the PIT for timing (e.g. Linux 2.4.x).
+
+4.100 KVM_PPC_CONFIGURE_V3_MMU
+
+Capability: KVM_CAP_PPC_RADIX_MMU or KVM_CAP_PPC_HASH_MMU_V3
+Architectures: ppc
+Type: vm ioctl
+Parameters: struct kvm_ppc_mmuv3_cfg (in)
+Returns: 0 on success,
+         -EFAULT if struct kvm_ppc_mmuv3_cfg cannot be read,
+         -EINVAL if the configuration is invalid
+
+This ioctl controls whether the guest will use radix or HPT (hashed
+page table) translation, and sets the pointer to the process table for
+the guest.
+
+struct kvm_ppc_mmuv3_cfg {
+       __u64   flags;
+       __u64   process_table;
+};
+
+There are two bits that can be set in flags; KVM_PPC_MMUV3_RADIX and
+KVM_PPC_MMUV3_GTSE.  KVM_PPC_MMUV3_RADIX, if set, configures the guest
+to use radix tree translation, and if clear, to use HPT translation.
+KVM_PPC_MMUV3_GTSE, if set and if KVM permits it, configures the guest
+to be able to use the global TLB and SLB invalidation instructions;
+if clear, the guest may not use these instructions.
+
+The process_table field specifies the address and size of the guest
+process table, which is in the guest's space.  This field is formatted
+as the second doubleword of the partition table entry, as defined in
+the Power ISA V3.00, Book III section 5.7.6.1.
+
+4.101 KVM_PPC_GET_RMMU_INFO
+
+Capability: KVM_CAP_PPC_RADIX_MMU
+Architectures: ppc
+Type: vm ioctl
+Parameters: struct kvm_ppc_rmmu_info (out)
+Returns: 0 on success,
+        -EFAULT if struct kvm_ppc_rmmu_info cannot be written,
+        -EINVAL if no useful information can be returned
+
+This ioctl returns a structure containing two things: (a) a list
+containing supported radix tree geometries, and (b) a list that maps
+page sizes to put in the "AP" (actual page size) field for the tlbie
+(TLB invalidate entry) instruction.
+
+struct kvm_ppc_rmmu_info {
+       struct kvm_ppc_radix_geom {
+               __u8    page_shift;
+               __u8    level_bits[4];
+               __u8    pad[3];
+       }       geometries[8];
+       __u32   ap_encodings[8];
+};
+
+The geometries[] field gives up to 8 supported geometries for the
+radix page table, in terms of the log base 2 of the smallest page
+size, and the number of bits indexed at each level of the tree, from
+the PTE level up to the PGD level in that order.  Any unused entries
+will have 0 in the page_shift field.
+
+The ap_encodings gives the supported page sizes and their AP field
+encodings, encoded with the AP value in the top 3 bits and the log
+base 2 of the page size in the bottom 6 bits.
+
+4.102 KVM_PPC_RESIZE_HPT_PREPARE
+
+Capability: KVM_CAP_SPAPR_RESIZE_HPT
+Architectures: powerpc
+Type: vm ioctl
+Parameters: struct kvm_ppc_resize_hpt (in)
+Returns: 0 on successful completion,
+        >0 if a new HPT is being prepared, the value is an estimated
+             number of milliseconds until preparation is complete
+         -EFAULT if struct kvm_reinject_control cannot be read,
+        -EINVAL if the supplied shift or flags are invalid
+        -ENOMEM if unable to allocate the new HPT
+        -ENOSPC if there was a hash collision when moving existing
+                  HPT entries to the new HPT
+        -EIO on other error conditions
+
+Used to implement the PAPR extension for runtime resizing of a guest's
+Hashed Page Table (HPT).  Specifically this starts, stops or monitors
+the preparation of a new potential HPT for the guest, essentially
+implementing the H_RESIZE_HPT_PREPARE hypercall.
+
+If called with shift > 0 when there is no pending HPT for the guest,
+this begins preparation of a new pending HPT of size 2^(shift) bytes.
+It then returns a positive integer with the estimated number of
+milliseconds until preparation is complete.
+
+If called when there is a pending HPT whose size does not match that
+requested in the parameters, discards the existing pending HPT and
+creates a new one as above.
+
+If called when there is a pending HPT of the size requested, will:
+  * If preparation of the pending HPT is already complete, return 0
+  * If preparation of the pending HPT has failed, return an error
+    code, then discard the pending HPT.
+  * If preparation of the pending HPT is still in progress, return an
+    estimated number of milliseconds until preparation is complete.
+
+If called with shift == 0, discards any currently pending HPT and
+returns 0 (i.e. cancels any in-progress preparation).
+
+flags is reserved for future expansion, currently setting any bits in
+flags will result in an -EINVAL.
+
+Normally this will be called repeatedly with the same parameters until
+it returns <= 0.  The first call will initiate preparation, subsequent
+ones will monitor preparation until it completes or fails.
+
+struct kvm_ppc_resize_hpt {
+       __u64 flags;
+       __u32 shift;
+       __u32 pad;
+};
+
+4.103 KVM_PPC_RESIZE_HPT_COMMIT
+
+Capability: KVM_CAP_SPAPR_RESIZE_HPT
+Architectures: powerpc
+Type: vm ioctl
+Parameters: struct kvm_ppc_resize_hpt (in)
+Returns: 0 on successful completion,
+         -EFAULT if struct kvm_reinject_control cannot be read,
+        -EINVAL if the supplied shift or flags are invalid
+        -ENXIO is there is no pending HPT, or the pending HPT doesn't
+                 have the requested size
+        -EBUSY if the pending HPT is not fully prepared
+        -ENOSPC if there was a hash collision when moving existing
+                  HPT entries to the new HPT
+        -EIO on other error conditions
+
+Used to implement the PAPR extension for runtime resizing of a guest's
+Hashed Page Table (HPT).  Specifically this requests that the guest be
+transferred to working with the new HPT, essentially implementing the
+H_RESIZE_HPT_COMMIT hypercall.
+
+This should only be called after KVM_PPC_RESIZE_HPT_PREPARE has
+returned 0 with the same parameters.  In other cases
+KVM_PPC_RESIZE_HPT_COMMIT will return an error (usually -ENXIO or
+-EBUSY, though others may be possible if the preparation was started,
+but failed).
+
+This will have undefined effects on the guest if it has not already
+placed itself in a quiescent state where no vcpu will make MMU enabled
+memory accesses.
+
+On succsful completion, the pending HPT will become the guest's active
+HPT and the previous HPT will be discarded.
+
+On failure, the guest will still be operating on its previous HPT.
+
+struct kvm_ppc_resize_hpt {
+       __u64 flags;
+       __u32 shift;
+       __u32 pad;
+};
+
+4.104 KVM_X86_GET_MCE_CAP_SUPPORTED
+
+Capability: KVM_CAP_MCE
+Architectures: x86
+Type: system ioctl
+Parameters: u64 mce_cap (out)
+Returns: 0 on success, -1 on error
+
+Returns supported MCE capabilities. The u64 mce_cap parameter
+has the same format as the MSR_IA32_MCG_CAP register. Supported
+capabilities will have the corresponding bits set.
+
+4.105 KVM_X86_SETUP_MCE
+
+Capability: KVM_CAP_MCE
+Architectures: x86
+Type: vcpu ioctl
+Parameters: u64 mcg_cap (in)
+Returns: 0 on success,
+         -EFAULT if u64 mcg_cap cannot be read,
+         -EINVAL if the requested number of banks is invalid,
+         -EINVAL if requested MCE capability is not supported.
+
+Initializes MCE support for use. The u64 mcg_cap parameter
+has the same format as the MSR_IA32_MCG_CAP register and
+specifies which capabilities should be enabled. The maximum
+supported number of error-reporting banks can be retrieved when
+checking for KVM_CAP_MCE. The supported capabilities can be
+retrieved with KVM_X86_GET_MCE_CAP_SUPPORTED.
+
+4.106 KVM_X86_SET_MCE
+
+Capability: KVM_CAP_MCE
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_x86_mce (in)
+Returns: 0 on success,
+         -EFAULT if struct kvm_x86_mce cannot be read,
+         -EINVAL if the bank number is invalid,
+         -EINVAL if VAL bit is not set in status field.
+
+Inject a machine check error (MCE) into the guest. The input
+parameter is:
+
+struct kvm_x86_mce {
+       __u64 status;
+       __u64 addr;
+       __u64 misc;
+       __u64 mcg_status;
+       __u8 bank;
+       __u8 pad1[7];
+       __u64 pad2[3];
+};
+
+If the MCE being reported is an uncorrected error, KVM will
+inject it as an MCE exception into the guest. If the guest
+MCG_STATUS register reports that an MCE is in progress, KVM
+causes an KVM_EXIT_SHUTDOWN vmexit.
+
+Otherwise, if the MCE is a corrected error, KVM will just
+store it in the corresponding bank (provided this bank is
+not holding a previously reported uncorrected error).
+
+4.107 KVM_S390_GET_CMMA_BITS
+
+Capability: KVM_CAP_S390_CMMA_MIGRATION
+Architectures: s390
+Type: vm ioctl
+Parameters: struct kvm_s390_cmma_log (in, out)
+Returns: 0 on success, a negative value on error
+
+This ioctl is used to get the values of the CMMA bits on the s390
+architecture. It is meant to be used in two scenarios:
+- During live migration to save the CMMA values. Live migration needs
+  to be enabled via the KVM_REQ_START_MIGRATION VM property.
+- To non-destructively peek at the CMMA values, with the flag
+  KVM_S390_CMMA_PEEK set.
+
+The ioctl takes parameters via the kvm_s390_cmma_log struct. The desired
+values are written to a buffer whose location is indicated via the "values"
+member in the kvm_s390_cmma_log struct.  The values in the input struct are
+also updated as needed.
+Each CMMA value takes up one byte.
+
+struct kvm_s390_cmma_log {
+       __u64 start_gfn;
+       __u32 count;
+       __u32 flags;
+       union {
+               __u64 remaining;
+               __u64 mask;
+       };
+       __u64 values;
+};
+
+start_gfn is the number of the first guest frame whose CMMA values are
+to be retrieved,
+
+count is the length of the buffer in bytes,
+
+values points to the buffer where the result will be written to.
+
+If count is greater than KVM_S390_SKEYS_MAX, then it is considered to be
+KVM_S390_SKEYS_MAX. KVM_S390_SKEYS_MAX is re-used for consistency with
+other ioctls.
+
+The result is written in the buffer pointed to by the field values, and
+the values of the input parameter are updated as follows.
+
+Depending on the flags, different actions are performed. The only
+supported flag so far is KVM_S390_CMMA_PEEK.
+
+The default behaviour if KVM_S390_CMMA_PEEK is not set is:
+start_gfn will indicate the first page frame whose CMMA bits were dirty.
+It is not necessarily the same as the one passed as input, as clean pages
+are skipped.
+
+count will indicate the number of bytes actually written in the buffer.
+It can (and very often will) be smaller than the input value, since the
+buffer is only filled until 16 bytes of clean values are found (which
+are then not copied in the buffer). Since a CMMA migration block needs
+the base address and the length, for a total of 16 bytes, we will send
+back some clean data if there is some dirty data afterwards, as long as
+the size of the clean data does not exceed the size of the header. This
+allows to minimize the amount of data to be saved or transferred over
+the network at the expense of more roundtrips to userspace. The next
+invocation of the ioctl will skip over all the clean values, saving
+potentially more than just the 16 bytes we found.
+
+If KVM_S390_CMMA_PEEK is set:
+the existing storage attributes are read even when not in migration
+mode, and no other action is performed;
+
+the output start_gfn will be equal to the input start_gfn,
+
+the output count will be equal to the input count, except if the end of
+memory has been reached.
+
+In both cases:
+the field "remaining" will indicate the total number of dirty CMMA values
+still remaining, or 0 if KVM_S390_CMMA_PEEK is set and migration mode is
+not enabled.
+
+mask is unused.
+
+values points to the userspace buffer where the result will be stored.
+
+This ioctl can fail with -ENOMEM if not enough memory can be allocated to
+complete the task, with -ENXIO if CMMA is not enabled, with -EINVAL if
+KVM_S390_CMMA_PEEK is not set but migration mode was not enabled, with
+-EFAULT if the userspace address is invalid or if no page table is
+present for the addresses (e.g. when using hugepages).
+
+4.108 KVM_S390_SET_CMMA_BITS
+
+Capability: KVM_CAP_S390_CMMA_MIGRATION
+Architectures: s390
+Type: vm ioctl
+Parameters: struct kvm_s390_cmma_log (in)
+Returns: 0 on success, a negative value on error
+
+This ioctl is used to set the values of the CMMA bits on the s390
+architecture. It is meant to be used during live migration to restore
+the CMMA values, but there are no restrictions on its use.
+The ioctl takes parameters via the kvm_s390_cmma_values struct.
+Each CMMA value takes up one byte.
+
+struct kvm_s390_cmma_log {
+       __u64 start_gfn;
+       __u32 count;
+       __u32 flags;
+       union {
+               __u64 remaining;
+               __u64 mask;
+       };
+       __u64 values;
+};
+
+start_gfn indicates the starting guest frame number,
+
+count indicates how many values are to be considered in the buffer,
+
+flags is not used and must be 0.
+
+mask indicates which PGSTE bits are to be considered.
+
+remaining is not used.
+
+values points to the buffer in userspace where to store the values.
+
+This ioctl can fail with -ENOMEM if not enough memory can be allocated to
+complete the task, with -ENXIO if CMMA is not enabled, with -EINVAL if
+the count field is too large (e.g. more than KVM_S390_CMMA_SIZE_MAX) or
+if the flags field was not 0, with -EFAULT if the userspace address is
+invalid, if invalid pages are written to (e.g. after the end of memory)
+or if no page table is present for the addresses (e.g. when using
+hugepages).
+
+4.109 KVM_PPC_GET_CPU_CHAR
+
+Capability: KVM_CAP_PPC_GET_CPU_CHAR
+Architectures: powerpc
+Type: vm ioctl
+Parameters: struct kvm_ppc_cpu_char (out)
+Returns: 0 on successful completion
+        -EFAULT if struct kvm_ppc_cpu_char cannot be written
+
+This ioctl gives userspace information about certain characteristics
+of the CPU relating to speculative execution of instructions and
+possible information leakage resulting from speculative execution (see
+CVE-2017-5715, CVE-2017-5753 and CVE-2017-5754).  The information is
+returned in struct kvm_ppc_cpu_char, which looks like this:
+
+struct kvm_ppc_cpu_char {
+       __u64   character;              /* characteristics of the CPU */
+       __u64   behaviour;              /* recommended software behaviour */
+       __u64   character_mask;         /* valid bits in character */
+       __u64   behaviour_mask;         /* valid bits in behaviour */
+};
+
+For extensibility, the character_mask and behaviour_mask fields
+indicate which bits of character and behaviour have been filled in by
+the kernel.  If the set of defined bits is extended in future then
+userspace will be able to tell whether it is running on a kernel that
+knows about the new bits.
+
+The character field describes attributes of the CPU which can help
+with preventing inadvertent information disclosure - specifically,
+whether there is an instruction to flash-invalidate the L1 data cache
+(ori 30,30,0 or mtspr SPRN_TRIG2,rN), whether the L1 data cache is set
+to a mode where entries can only be used by the thread that created
+them, whether the bcctr[l] instruction prevents speculation, and
+whether a speculation barrier instruction (ori 31,31,0) is provided.
+
+The behaviour field describes actions that software should take to
+prevent inadvertent information disclosure, and thus describes which
+vulnerabilities the hardware is subject to; specifically whether the
+L1 data cache should be flushed when returning to user mode from the
+kernel, and whether a speculation barrier should be placed between an
+array bounds check and the array access.
+
+These fields use the same bit definitions as the new
+H_GET_CPU_CHARACTERISTICS hypercall.
+
+4.110 KVM_MEMORY_ENCRYPT_OP
+
+Capability: basic
+Architectures: x86
+Type: system
+Parameters: an opaque platform specific structure (in/out)
+Returns: 0 on success; -1 on error
+
+If the platform supports creating encrypted VMs then this ioctl can be used
+for issuing platform-specific memory encryption commands to manage those
+encrypted VMs.
+
+Currently, this ioctl is used for issuing Secure Encrypted Virtualization
+(SEV) commands on AMD Processors. The SEV commands are defined in
+Documentation/virt/kvm/amd-memory-encryption.rst.
+
+4.111 KVM_MEMORY_ENCRYPT_REG_REGION
+
+Capability: basic
+Architectures: x86
+Type: system
+Parameters: struct kvm_enc_region (in)
+Returns: 0 on success; -1 on error
+
+This ioctl can be used to register a guest memory region which may
+contain encrypted data (e.g. guest RAM, SMRAM etc).
+
+It is used in the SEV-enabled guest. When encryption is enabled, a guest
+memory region may contain encrypted data. The SEV memory encryption
+engine uses a tweak such that two identical plaintext pages, each at
+different locations will have differing ciphertexts. So swapping or
+moving ciphertext of those pages will not result in plaintext being
+swapped. So relocating (or migrating) physical backing pages for the SEV
+guest will require some additional steps.
+
+Note: The current SEV key management spec does not provide commands to
+swap or migrate (move) ciphertext pages. Hence, for now we pin the guest
+memory region registered with the ioctl.
+
+4.112 KVM_MEMORY_ENCRYPT_UNREG_REGION
+
+Capability: basic
+Architectures: x86
+Type: system
+Parameters: struct kvm_enc_region (in)
+Returns: 0 on success; -1 on error
+
+This ioctl can be used to unregister the guest memory region registered
+with KVM_MEMORY_ENCRYPT_REG_REGION ioctl above.
+
+4.113 KVM_HYPERV_EVENTFD
+
+Capability: KVM_CAP_HYPERV_EVENTFD
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_hyperv_eventfd (in)
+
+This ioctl (un)registers an eventfd to receive notifications from the guest on
+the specified Hyper-V connection id through the SIGNAL_EVENT hypercall, without
+causing a user exit.  SIGNAL_EVENT hypercall with non-zero event flag number
+(bits 24-31) still triggers a KVM_EXIT_HYPERV_HCALL user exit.
+
+struct kvm_hyperv_eventfd {
+       __u32 conn_id;
+       __s32 fd;
+       __u32 flags;
+       __u32 padding[3];
+};
+
+The conn_id field should fit within 24 bits:
+
+#define KVM_HYPERV_CONN_ID_MASK                0x00ffffff
+
+The acceptable values for the flags field are:
+
+#define KVM_HYPERV_EVENTFD_DEASSIGN    (1 << 0)
+
+Returns: 0 on success,
+       -EINVAL if conn_id or flags is outside the allowed range
+       -ENOENT on deassign if the conn_id isn't registered
+       -EEXIST on assign if the conn_id is already registered
+
+4.114 KVM_GET_NESTED_STATE
+
+Capability: KVM_CAP_NESTED_STATE
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_nested_state (in/out)
+Returns: 0 on success, -1 on error
+Errors:
+  E2BIG:     the total state size exceeds the value of 'size' specified by
+             the user; the size required will be written into size.
+
+struct kvm_nested_state {
+       __u16 flags;
+       __u16 format;
+       __u32 size;
+
+       union {
+               struct kvm_vmx_nested_state_hdr vmx;
+               struct kvm_svm_nested_state_hdr svm;
+
+               /* Pad the header to 128 bytes.  */
+               __u8 pad[120];
+       } hdr;
+
+       union {
+               struct kvm_vmx_nested_state_data vmx[0];
+               struct kvm_svm_nested_state_data svm[0];
+       } data;
+};
+
+#define KVM_STATE_NESTED_GUEST_MODE    0x00000001
+#define KVM_STATE_NESTED_RUN_PENDING   0x00000002
+#define KVM_STATE_NESTED_EVMCS         0x00000004
+
+#define KVM_STATE_NESTED_FORMAT_VMX            0
+#define KVM_STATE_NESTED_FORMAT_SVM            1
+
+#define KVM_STATE_NESTED_VMX_VMCS_SIZE         0x1000
+
+#define KVM_STATE_NESTED_VMX_SMM_GUEST_MODE    0x00000001
+#define KVM_STATE_NESTED_VMX_SMM_VMXON         0x00000002
+
+struct kvm_vmx_nested_state_hdr {
+       __u64 vmxon_pa;
+       __u64 vmcs12_pa;
+
+       struct {
+               __u16 flags;
+       } smm;
+};
+
+struct kvm_vmx_nested_state_data {
+       __u8 vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE];
+       __u8 shadow_vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE];
+};
+
+This ioctl copies the vcpu's nested virtualization state from the kernel to
+userspace.
+
+The maximum size of the state can be retrieved by passing KVM_CAP_NESTED_STATE
+to the KVM_CHECK_EXTENSION ioctl().
+
+4.115 KVM_SET_NESTED_STATE
+
+Capability: KVM_CAP_NESTED_STATE
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_nested_state (in)
+Returns: 0 on success, -1 on error
+
+This copies the vcpu's kvm_nested_state struct from userspace to the kernel.
+For the definition of struct kvm_nested_state, see KVM_GET_NESTED_STATE.
+
+4.116 KVM_(UN)REGISTER_COALESCED_MMIO
+
+Capability: KVM_CAP_COALESCED_MMIO (for coalesced mmio)
+           KVM_CAP_COALESCED_PIO (for coalesced pio)
+Architectures: all
+Type: vm ioctl
+Parameters: struct kvm_coalesced_mmio_zone
+Returns: 0 on success, < 0 on error
+
+Coalesced I/O is a performance optimization that defers hardware
+register write emulation so that userspace exits are avoided.  It is
+typically used to reduce the overhead of emulating frequently accessed
+hardware registers.
+
+When a hardware register is configured for coalesced I/O, write accesses
+do not exit to userspace and their value is recorded in a ring buffer
+that is shared between kernel and userspace.
+
+Coalesced I/O is used if one or more write accesses to a hardware
+register can be deferred until a read or a write to another hardware
+register on the same device.  This last access will cause a vmexit and
+userspace will process accesses from the ring buffer before emulating
+it. That will avoid exiting to userspace on repeated writes.
+
+Coalesced pio is based on coalesced mmio. There is little difference
+between coalesced mmio and pio except that coalesced pio records accesses
+to I/O ports.
+
+4.117 KVM_CLEAR_DIRTY_LOG (vm ioctl)
+
+Capability: KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2
+Architectures: x86, arm, arm64, mips
+Type: vm ioctl
+Parameters: struct kvm_dirty_log (in)
+Returns: 0 on success, -1 on error
+
+/* for KVM_CLEAR_DIRTY_LOG */
+struct kvm_clear_dirty_log {
+       __u32 slot;
+       __u32 num_pages;
+       __u64 first_page;
+       union {
+               void __user *dirty_bitmap; /* one bit per page */
+               __u64 padding;
+       };
+};
+
+The ioctl clears the dirty status of pages in a memory slot, according to
+the bitmap that is passed in struct kvm_clear_dirty_log's dirty_bitmap
+field.  Bit 0 of the bitmap corresponds to page "first_page" in the
+memory slot, and num_pages is the size in bits of the input bitmap.
+first_page must be a multiple of 64; num_pages must also be a multiple of
+64 unless first_page + num_pages is the size of the memory slot.  For each
+bit that is set in the input bitmap, the corresponding page is marked "clean"
+in KVM's dirty bitmap, and dirty tracking is re-enabled for that page
+(for example via write-protection, or by clearing the dirty bit in
+a page table entry).
+
+If KVM_CAP_MULTI_ADDRESS_SPACE is available, bits 16-31 specifies
+the address space for which you want to return the dirty bitmap.
+They must be less than the value that KVM_CHECK_EXTENSION returns for
+the KVM_CAP_MULTI_ADDRESS_SPACE capability.
+
+This ioctl is mostly useful when KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2
+is enabled; for more information, see the description of the capability.
+However, it can always be used as long as KVM_CHECK_EXTENSION confirms
+that KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 is present.
+
+4.118 KVM_GET_SUPPORTED_HV_CPUID
+
+Capability: KVM_CAP_HYPERV_CPUID
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_cpuid2 (in/out)
+Returns: 0 on success, -1 on error
+
+struct kvm_cpuid2 {
+       __u32 nent;
+       __u32 padding;
+       struct kvm_cpuid_entry2 entries[0];
+};
+
+struct kvm_cpuid_entry2 {
+       __u32 function;
+       __u32 index;
+       __u32 flags;
+       __u32 eax;
+       __u32 ebx;
+       __u32 ecx;
+       __u32 edx;
+       __u32 padding[3];
+};
+
+This ioctl returns x86 cpuid features leaves related to Hyper-V emulation in
+KVM.  Userspace can use the information returned by this ioctl to construct
+cpuid information presented to guests consuming Hyper-V enlightenments (e.g.
+Windows or Hyper-V guests).
+
+CPUID feature leaves returned by this ioctl are defined by Hyper-V Top Level
+Functional Specification (TLFS). These leaves can't be obtained with
+KVM_GET_SUPPORTED_CPUID ioctl because some of them intersect with KVM feature
+leaves (0x40000000, 0x40000001).
+
+Currently, the following list of CPUID leaves are returned:
+ HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS
+ HYPERV_CPUID_INTERFACE
+ HYPERV_CPUID_VERSION
+ HYPERV_CPUID_FEATURES
+ HYPERV_CPUID_ENLIGHTMENT_INFO
+ HYPERV_CPUID_IMPLEMENT_LIMITS
+ HYPERV_CPUID_NESTED_FEATURES
+
+HYPERV_CPUID_NESTED_FEATURES leaf is only exposed when Enlightened VMCS was
+enabled on the corresponding vCPU (KVM_CAP_HYPERV_ENLIGHTENED_VMCS).
+
+Userspace invokes KVM_GET_SUPPORTED_CPUID by passing a kvm_cpuid2 structure
+with the 'nent' field indicating the number of entries in the variable-size
+array 'entries'.  If the number of entries is too low to describe all Hyper-V
+feature leaves, an error (E2BIG) is returned. If the number is more or equal
+to the number of Hyper-V feature leaves, the 'nent' field is adjusted to the
+number of valid entries in the 'entries' array, which is then filled.
+
+'index' and 'flags' fields in 'struct kvm_cpuid_entry2' are currently reserved,
+userspace should not expect to get any particular value there.
+
+4.119 KVM_ARM_VCPU_FINALIZE
+
+Architectures: arm, arm64
+Type: vcpu ioctl
+Parameters: int feature (in)
+Returns: 0 on success, -1 on error
+Errors:
+  EPERM:     feature not enabled, needs configuration, or already finalized
+  EINVAL:    feature unknown or not present
+
+Recognised values for feature:
+  arm64      KVM_ARM_VCPU_SVE (requires KVM_CAP_ARM_SVE)
+
+Finalizes the configuration of the specified vcpu feature.
+
+The vcpu must already have been initialised, enabling the affected feature, by
+means of a successful KVM_ARM_VCPU_INIT call with the appropriate flag set in
+features[].
+
+For affected vcpu features, this is a mandatory step that must be performed
+before the vcpu is fully usable.
+
+Between KVM_ARM_VCPU_INIT and KVM_ARM_VCPU_FINALIZE, the feature may be
+configured by use of ioctls such as KVM_SET_ONE_REG.  The exact configuration
+that should be performaned and how to do it are feature-dependent.
+
+Other calls that depend on a particular feature being finalized, such as
+KVM_RUN, KVM_GET_REG_LIST, KVM_GET_ONE_REG and KVM_SET_ONE_REG, will fail with
+-EPERM unless the feature has already been finalized by means of a
+KVM_ARM_VCPU_FINALIZE call.
+
+See KVM_ARM_VCPU_INIT for details of vcpu features that require finalization
+using this ioctl.
+
+4.120 KVM_SET_PMU_EVENT_FILTER
+
+Capability: KVM_CAP_PMU_EVENT_FILTER
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_pmu_event_filter (in)
+Returns: 0 on success, -1 on error
+
+struct kvm_pmu_event_filter {
+       __u32 action;
+       __u32 nevents;
+       __u32 fixed_counter_bitmap;
+       __u32 flags;
+       __u32 pad[4];
+       __u64 events[0];
+};
+
+This ioctl restricts the set of PMU events that the guest can program.
+The argument holds a list of events which will be allowed or denied.
+The eventsel+umask of each event the guest attempts to program is compared
+against the events field to determine whether the guest should have access.
+The events field only controls general purpose counters; fixed purpose
+counters are controlled by the fixed_counter_bitmap.
+
+No flags are defined yet, the field must be zero.
+
+Valid values for 'action':
+#define KVM_PMU_EVENT_ALLOW 0
+#define KVM_PMU_EVENT_DENY 1
+
+
+5. The kvm_run structure
+------------------------
+
+Application code obtains a pointer to the kvm_run structure by
+mmap()ing a vcpu fd.  From that point, application code can control
+execution by changing fields in kvm_run prior to calling the KVM_RUN
+ioctl, and obtain information about the reason KVM_RUN returned by
+looking up structure members.
+
+struct kvm_run {
+       /* in */
+       __u8 request_interrupt_window;
+
+Request that KVM_RUN return when it becomes possible to inject external
+interrupts into the guest.  Useful in conjunction with KVM_INTERRUPT.
+
+       __u8 immediate_exit;
+
+This field is polled once when KVM_RUN starts; if non-zero, KVM_RUN
+exits immediately, returning -EINTR.  In the common scenario where a
+signal is used to "kick" a VCPU out of KVM_RUN, this field can be used
+to avoid usage of KVM_SET_SIGNAL_MASK, which has worse scalability.
+Rather than blocking the signal outside KVM_RUN, userspace can set up
+a signal handler that sets run->immediate_exit to a non-zero value.
+
+This field is ignored if KVM_CAP_IMMEDIATE_EXIT is not available.
+
+       __u8 padding1[6];
+
+       /* out */
+       __u32 exit_reason;
+
+When KVM_RUN has returned successfully (return value 0), this informs
+application code why KVM_RUN has returned.  Allowable values for this
+field are detailed below.
+
+       __u8 ready_for_interrupt_injection;
+
+If request_interrupt_window has been specified, this field indicates
+an interrupt can be injected now with KVM_INTERRUPT.
+
+       __u8 if_flag;
+
+The value of the current interrupt flag.  Only valid if in-kernel
+local APIC is not used.
+
+       __u16 flags;
+
+More architecture-specific flags detailing state of the VCPU that may
+affect the device's behavior.  The only currently defined flag is
+KVM_RUN_X86_SMM, which is valid on x86 machines and is set if the
+VCPU is in system management mode.
+
+       /* in (pre_kvm_run), out (post_kvm_run) */
+       __u64 cr8;
+
+The value of the cr8 register.  Only valid if in-kernel local APIC is
+not used.  Both input and output.
+
+       __u64 apic_base;
+
+The value of the APIC BASE msr.  Only valid if in-kernel local
+APIC is not used.  Both input and output.
+
+       union {
+               /* KVM_EXIT_UNKNOWN */
+               struct {
+                       __u64 hardware_exit_reason;
+               } hw;
+
+If exit_reason is KVM_EXIT_UNKNOWN, the vcpu has exited due to unknown
+reasons.  Further architecture-specific information is available in
+hardware_exit_reason.
+
+               /* KVM_EXIT_FAIL_ENTRY */
+               struct {
+                       __u64 hardware_entry_failure_reason;
+               } fail_entry;
+
+If exit_reason is KVM_EXIT_FAIL_ENTRY, the vcpu could not be run due
+to unknown reasons.  Further architecture-specific information is
+available in hardware_entry_failure_reason.
+
+               /* KVM_EXIT_EXCEPTION */
+               struct {
+                       __u32 exception;
+                       __u32 error_code;
+               } ex;
+
+Unused.
+
+               /* KVM_EXIT_IO */
+               struct {
+#define KVM_EXIT_IO_IN  0
+#define KVM_EXIT_IO_OUT 1
+                       __u8 direction;
+                       __u8 size; /* bytes */
+                       __u16 port;
+                       __u32 count;
+                       __u64 data_offset; /* relative to kvm_run start */
+               } io;
+
+If exit_reason is KVM_EXIT_IO, then the vcpu has
+executed a port I/O instruction which could not be satisfied by kvm.
+data_offset describes where the data is located (KVM_EXIT_IO_OUT) or
+where kvm expects application code to place the data for the next
+KVM_RUN invocation (KVM_EXIT_IO_IN).  Data format is a packed array.
+
+               /* KVM_EXIT_DEBUG */
+               struct {
+                       struct kvm_debug_exit_arch arch;
+               } debug;
+
+If the exit_reason is KVM_EXIT_DEBUG, then a vcpu is processing a debug event
+for which architecture specific information is returned.
+
+               /* KVM_EXIT_MMIO */
+               struct {
+                       __u64 phys_addr;
+                       __u8  data[8];
+                       __u32 len;
+                       __u8  is_write;
+               } mmio;
+
+If exit_reason is KVM_EXIT_MMIO, then the vcpu has
+executed a memory-mapped I/O instruction which could not be satisfied
+by kvm.  The 'data' member contains the written data if 'is_write' is
+true, and should be filled by application code otherwise.
+
+The 'data' member contains, in its first 'len' bytes, the value as it would
+appear if the VCPU performed a load or store of the appropriate width directly
+to the byte array.
+
+NOTE: For KVM_EXIT_IO, KVM_EXIT_MMIO, KVM_EXIT_OSI, KVM_EXIT_PAPR and
+      KVM_EXIT_EPR the corresponding
+operations are complete (and guest state is consistent) only after userspace
+has re-entered the kernel with KVM_RUN.  The kernel side will first finish
+incomplete operations and then check for pending signals.  Userspace
+can re-enter the guest with an unmasked signal pending to complete
+pending operations.
+
+               /* KVM_EXIT_HYPERCALL */
+               struct {
+                       __u64 nr;
+                       __u64 args[6];
+                       __u64 ret;
+                       __u32 longmode;
+                       __u32 pad;
+               } hypercall;
+
+Unused.  This was once used for 'hypercall to userspace'.  To implement
+such functionality, use KVM_EXIT_IO (x86) or KVM_EXIT_MMIO (all except s390).
+Note KVM_EXIT_IO is significantly faster than KVM_EXIT_MMIO.
+
+               /* KVM_EXIT_TPR_ACCESS */
+               struct {
+                       __u64 rip;
+                       __u32 is_write;
+                       __u32 pad;
+               } tpr_access;
+
+To be documented (KVM_TPR_ACCESS_REPORTING).
+
+               /* KVM_EXIT_S390_SIEIC */
+               struct {
+                       __u8 icptcode;
+                       __u64 mask; /* psw upper half */
+                       __u64 addr; /* psw lower half */
+                       __u16 ipa;
+                       __u32 ipb;
+               } s390_sieic;
+
+s390 specific.
+
+               /* KVM_EXIT_S390_RESET */
+#define KVM_S390_RESET_POR       1
+#define KVM_S390_RESET_CLEAR     2
+#define KVM_S390_RESET_SUBSYSTEM 4
+#define KVM_S390_RESET_CPU_INIT  8
+#define KVM_S390_RESET_IPL       16
+               __u64 s390_reset_flags;
+
+s390 specific.
+
+               /* KVM_EXIT_S390_UCONTROL */
+               struct {
+                       __u64 trans_exc_code;
+                       __u32 pgm_code;
+               } s390_ucontrol;
+
+s390 specific. A page fault has occurred for a user controlled virtual
+machine (KVM_VM_S390_UNCONTROL) on it's host page table that cannot be
+resolved by the kernel.
+The program code and the translation exception code that were placed
+in the cpu's lowcore are presented here as defined by the z Architecture
+Principles of Operation Book in the Chapter for Dynamic Address Translation
+(DAT)
+
+               /* KVM_EXIT_DCR */
+               struct {
+                       __u32 dcrn;
+                       __u32 data;
+                       __u8  is_write;
+               } dcr;
+
+Deprecated - was used for 440 KVM.
+
+               /* KVM_EXIT_OSI */
+               struct {
+                       __u64 gprs[32];
+               } osi;
+
+MOL uses a special hypercall interface it calls 'OSI'. To enable it, we catch
+hypercalls and exit with this exit struct that contains all the guest gprs.
+
+If exit_reason is KVM_EXIT_OSI, then the vcpu has triggered such a hypercall.
+Userspace can now handle the hypercall and when it's done modify the gprs as
+necessary. Upon guest entry all guest GPRs will then be replaced by the values
+in this struct.
+
+               /* KVM_EXIT_PAPR_HCALL */
+               struct {
+                       __u64 nr;
+                       __u64 ret;
+                       __u64 args[9];
+               } papr_hcall;
+
+This is used on 64-bit PowerPC when emulating a pSeries partition,
+e.g. with the 'pseries' machine type in qemu.  It occurs when the
+guest does a hypercall using the 'sc 1' instruction.  The 'nr' field
+contains the hypercall number (from the guest R3), and 'args' contains
+the arguments (from the guest R4 - R12).  Userspace should put the
+return code in 'ret' and any extra returned values in args[].
+The possible hypercalls are defined in the Power Architecture Platform
+Requirements (PAPR) document available from www.power.org (free
+developer registration required to access it).
+
+               /* KVM_EXIT_S390_TSCH */
+               struct {
+                       __u16 subchannel_id;
+                       __u16 subchannel_nr;
+                       __u32 io_int_parm;
+                       __u32 io_int_word;
+                       __u32 ipb;
+                       __u8 dequeued;
+               } s390_tsch;
+
+s390 specific. This exit occurs when KVM_CAP_S390_CSS_SUPPORT has been enabled
+and TEST SUBCHANNEL was intercepted. If dequeued is set, a pending I/O
+interrupt for the target subchannel has been dequeued and subchannel_id,
+subchannel_nr, io_int_parm and io_int_word contain the parameters for that
+interrupt. ipb is needed for instruction parameter decoding.
+
+               /* KVM_EXIT_EPR */
+               struct {
+                       __u32 epr;
+               } epr;
+
+On FSL BookE PowerPC chips, the interrupt controller has a fast patch
+interrupt acknowledge path to the core. When the core successfully
+delivers an interrupt, it automatically populates the EPR register with
+the interrupt vector number and acknowledges the interrupt inside
+the interrupt controller.
+
+In case the interrupt controller lives in user space, we need to do
+the interrupt acknowledge cycle through it to fetch the next to be
+delivered interrupt vector using this exit.
+
+It gets triggered whenever both KVM_CAP_PPC_EPR are enabled and an
+external interrupt has just been delivered into the guest. User space
+should put the acknowledged interrupt vector into the 'epr' field.
+
+               /* KVM_EXIT_SYSTEM_EVENT */
+               struct {
+#define KVM_SYSTEM_EVENT_SHUTDOWN       1
+#define KVM_SYSTEM_EVENT_RESET          2
+#define KVM_SYSTEM_EVENT_CRASH          3
+                       __u32 type;
+                       __u64 flags;
+               } system_event;
+
+If exit_reason is KVM_EXIT_SYSTEM_EVENT then the vcpu has triggered
+a system-level event using some architecture specific mechanism (hypercall
+or some special instruction). In case of ARM/ARM64, this is triggered using
+HVC instruction based PSCI call from the vcpu. The 'type' field describes
+the system-level event type. The 'flags' field describes architecture
+specific flags for the system-level event.
+
+Valid values for 'type' are:
+  KVM_SYSTEM_EVENT_SHUTDOWN -- the guest has requested a shutdown of the
+   VM. Userspace is not obliged to honour this, and if it does honour
+   this does not need to destroy the VM synchronously (ie it may call
+   KVM_RUN again before shutdown finally occurs).
+  KVM_SYSTEM_EVENT_RESET -- the guest has requested a reset of the VM.
+   As with SHUTDOWN, userspace can choose to ignore the request, or
+   to schedule the reset to occur in the future and may call KVM_RUN again.
+  KVM_SYSTEM_EVENT_CRASH -- the guest crash occurred and the guest
+   has requested a crash condition maintenance. Userspace can choose
+   to ignore the request, or to gather VM memory core dump and/or
+   reset/shutdown of the VM.
+
+               /* KVM_EXIT_IOAPIC_EOI */
+               struct {
+                       __u8 vector;
+               } eoi;
+
+Indicates that the VCPU's in-kernel local APIC received an EOI for a
+level-triggered IOAPIC interrupt.  This exit only triggers when the
+IOAPIC is implemented in userspace (i.e. KVM_CAP_SPLIT_IRQCHIP is enabled);
+the userspace IOAPIC should process the EOI and retrigger the interrupt if
+it is still asserted.  Vector is the LAPIC interrupt vector for which the
+EOI was received.
+
+               struct kvm_hyperv_exit {
+#define KVM_EXIT_HYPERV_SYNIC          1
+#define KVM_EXIT_HYPERV_HCALL          2
+                       __u32 type;
+                       union {
+                               struct {
+                                       __u32 msr;
+                                       __u64 control;
+                                       __u64 evt_page;
+                                       __u64 msg_page;
+                               } synic;
+                               struct {
+                                       __u64 input;
+                                       __u64 result;
+                                       __u64 params[2];
+                               } hcall;
+                       } u;
+               };
+               /* KVM_EXIT_HYPERV */
+                struct kvm_hyperv_exit hyperv;
+Indicates that the VCPU exits into userspace to process some tasks
+related to Hyper-V emulation.
+Valid values for 'type' are:
+       KVM_EXIT_HYPERV_SYNIC -- synchronously notify user-space about
+Hyper-V SynIC state change. Notification is used to remap SynIC
+event/message pages and to enable/disable SynIC messages/events processing
+in userspace.
+
+               /* Fix the size of the union. */
+               char padding[256];
+       };
+
+       /*
+        * shared registers between kvm and userspace.
+        * kvm_valid_regs specifies the register classes set by the host
+        * kvm_dirty_regs specified the register classes dirtied by userspace
+        * struct kvm_sync_regs is architecture specific, as well as the
+        * bits for kvm_valid_regs and kvm_dirty_regs
+        */
+       __u64 kvm_valid_regs;
+       __u64 kvm_dirty_regs;
+       union {
+               struct kvm_sync_regs regs;
+               char padding[SYNC_REGS_SIZE_BYTES];
+       } s;
+
+If KVM_CAP_SYNC_REGS is defined, these fields allow userspace to access
+certain guest registers without having to call SET/GET_*REGS. Thus we can
+avoid some system call overhead if userspace has to handle the exit.
+Userspace can query the validity of the structure by checking
+kvm_valid_regs for specific bits. These bits are architecture specific
+and usually define the validity of a groups of registers. (e.g. one bit
+ for general purpose registers)
+
+Please note that the kernel is allowed to use the kvm_run structure as the
+primary storage for certain register types. Therefore, the kernel may use the
+values in kvm_run even if the corresponding bit in kvm_dirty_regs is not set.
+
+};
+
+
+
+6. Capabilities that can be enabled on vCPUs
+--------------------------------------------
+
+There are certain capabilities that change the behavior of the virtual CPU or
+the virtual machine when enabled. To enable them, please see section 4.37.
+Below you can find a list of capabilities and what their effect on the vCPU or
+the virtual machine is when enabling them.
+
+The following information is provided along with the description:
+
+  Architectures: which instruction set architectures provide this ioctl.
+      x86 includes both i386 and x86_64.
+
+  Target: whether this is a per-vcpu or per-vm capability.
+
+  Parameters: what parameters are accepted by the capability.
+
+  Returns: the return value.  General error numbers (EBADF, ENOMEM, EINVAL)
+      are not detailed, but errors with specific meanings are.
+
+
+6.1 KVM_CAP_PPC_OSI
+
+Architectures: ppc
+Target: vcpu
+Parameters: none
+Returns: 0 on success; -1 on error
+
+This capability enables interception of OSI hypercalls that otherwise would
+be treated as normal system calls to be injected into the guest. OSI hypercalls
+were invented by Mac-on-Linux to have a standardized communication mechanism
+between the guest and the host.
+
+When this capability is enabled, KVM_EXIT_OSI can occur.
+
+
+6.2 KVM_CAP_PPC_PAPR
+
+Architectures: ppc
+Target: vcpu
+Parameters: none
+Returns: 0 on success; -1 on error
+
+This capability enables interception of PAPR hypercalls. PAPR hypercalls are
+done using the hypercall instruction "sc 1".
+
+It also sets the guest privilege level to "supervisor" mode. Usually the guest
+runs in "hypervisor" privilege mode with a few missing features.
+
+In addition to the above, it changes the semantics of SDR1. In this mode, the
+HTAB address part of SDR1 contains an HVA instead of a GPA, as PAPR keeps the
+HTAB invisible to the guest.
+
+When this capability is enabled, KVM_EXIT_PAPR_HCALL can occur.
+
+
+6.3 KVM_CAP_SW_TLB
+
+Architectures: ppc
+Target: vcpu
+Parameters: args[0] is the address of a struct kvm_config_tlb
+Returns: 0 on success; -1 on error
+
+struct kvm_config_tlb {
+       __u64 params;
+       __u64 array;
+       __u32 mmu_type;
+       __u32 array_len;
+};
+
+Configures the virtual CPU's TLB array, establishing a shared memory area
+between userspace and KVM.  The "params" and "array" fields are userspace
+addresses of mmu-type-specific data structures.  The "array_len" field is an
+safety mechanism, and should be set to the size in bytes of the memory that
+userspace has reserved for the array.  It must be at least the size dictated
+by "mmu_type" and "params".
+
+While KVM_RUN is active, the shared region is under control of KVM.  Its
+contents are undefined, and any modification by userspace results in
+boundedly undefined behavior.
+
+On return from KVM_RUN, the shared region will reflect the current state of
+the guest's TLB.  If userspace makes any changes, it must call KVM_DIRTY_TLB
+to tell KVM which entries have been changed, prior to calling KVM_RUN again
+on this vcpu.
+
+For mmu types KVM_MMU_FSL_BOOKE_NOHV and KVM_MMU_FSL_BOOKE_HV:
+ - The "params" field is of type "struct kvm_book3e_206_tlb_params".
+ - The "array" field points to an array of type "struct
+   kvm_book3e_206_tlb_entry".
+ - The array consists of all entries in the first TLB, followed by all
+   entries in the second TLB.
+ - Within a TLB, entries are ordered first by increasing set number.  Within a
+   set, entries are ordered by way (increasing ESEL).
+ - The hash for determining set number in TLB0 is: (MAS2 >> 12) & (num_sets - 1)
+   where "num_sets" is the tlb_sizes[] value divided by the tlb_ways[] value.
+ - The tsize field of mas1 shall be set to 4K on TLB0, even though the
+   hardware ignores this value for TLB0.
+
+6.4 KVM_CAP_S390_CSS_SUPPORT
+
+Architectures: s390
+Target: vcpu
+Parameters: none
+Returns: 0 on success; -1 on error
+
+This capability enables support for handling of channel I/O instructions.
+
+TEST PENDING INTERRUPTION and the interrupt portion of TEST SUBCHANNEL are
+handled in-kernel, while the other I/O instructions are passed to userspace.
+
+When this capability is enabled, KVM_EXIT_S390_TSCH will occur on TEST
+SUBCHANNEL intercepts.
+
+Note that even though this capability is enabled per-vcpu, the complete
+virtual machine is affected.
+
+6.5 KVM_CAP_PPC_EPR
+
+Architectures: ppc
+Target: vcpu
+Parameters: args[0] defines whether the proxy facility is active
+Returns: 0 on success; -1 on error
+
+This capability enables or disables the delivery of interrupts through the
+external proxy facility.
+
+When enabled (args[0] != 0), every time the guest gets an external interrupt
+delivered, it automatically exits into user space with a KVM_EXIT_EPR exit
+to receive the topmost interrupt vector.
+
+When disabled (args[0] == 0), behavior is as if this facility is unsupported.
+
+When this capability is enabled, KVM_EXIT_EPR can occur.
+
+6.6 KVM_CAP_IRQ_MPIC
+
+Architectures: ppc
+Parameters: args[0] is the MPIC device fd
+            args[1] is the MPIC CPU number for this vcpu
+
+This capability connects the vcpu to an in-kernel MPIC device.
+
+6.7 KVM_CAP_IRQ_XICS
+
+Architectures: ppc
+Target: vcpu
+Parameters: args[0] is the XICS device fd
+            args[1] is the XICS CPU number (server ID) for this vcpu
+
+This capability connects the vcpu to an in-kernel XICS device.
+
+6.8 KVM_CAP_S390_IRQCHIP
+
+Architectures: s390
+Target: vm
+Parameters: none
+
+This capability enables the in-kernel irqchip for s390. Please refer to
+"4.24 KVM_CREATE_IRQCHIP" for details.
+
+6.9 KVM_CAP_MIPS_FPU
+
+Architectures: mips
+Target: vcpu
+Parameters: args[0] is reserved for future use (should be 0).
+
+This capability allows the use of the host Floating Point Unit by the guest. It
+allows the Config1.FP bit to be set to enable the FPU in the guest. Once this is
+done the KVM_REG_MIPS_FPR_* and KVM_REG_MIPS_FCR_* registers can be accessed
+(depending on the current guest FPU register mode), and the Status.FR,
+Config5.FRE bits are accessible via the KVM API and also from the guest,
+depending on them being supported by the FPU.
+
+6.10 KVM_CAP_MIPS_MSA
+
+Architectures: mips
+Target: vcpu
+Parameters: args[0] is reserved for future use (should be 0).
+
+This capability allows the use of the MIPS SIMD Architecture (MSA) by the guest.
+It allows the Config3.MSAP bit to be set to enable the use of MSA by the guest.
+Once this is done the KVM_REG_MIPS_VEC_* and KVM_REG_MIPS_MSA_* registers can be
+accessed, and the Config5.MSAEn bit is accessible via the KVM API and also from
+the guest.
+
+6.74 KVM_CAP_SYNC_REGS
+Architectures: s390, x86
+Target: s390: always enabled, x86: vcpu
+Parameters: none
+Returns: x86: KVM_CHECK_EXTENSION returns a bit-array indicating which register
+sets are supported (bitfields defined in arch/x86/include/uapi/asm/kvm.h).
+
+As described above in the kvm_sync_regs struct info in section 5 (kvm_run):
+KVM_CAP_SYNC_REGS "allow[s] userspace to access certain guest registers
+without having to call SET/GET_*REGS". This reduces overhead by eliminating
+repeated ioctl calls for setting and/or getting register values. This is
+particularly important when userspace is making synchronous guest state
+modifications, e.g. when emulating and/or intercepting instructions in
+userspace.
+
+For s390 specifics, please refer to the source code.
+
+For x86:
+- the register sets to be copied out to kvm_run are selectable
+  by userspace (rather that all sets being copied out for every exit).
+- vcpu_events are available in addition to regs and sregs.
+
+For x86, the 'kvm_valid_regs' field of struct kvm_run is overloaded to
+function as an input bit-array field set by userspace to indicate the
+specific register sets to be copied out on the next exit.
+
+To indicate when userspace has modified values that should be copied into
+the vCPU, the all architecture bitarray field, 'kvm_dirty_regs' must be set.
+This is done using the same bitflags as for the 'kvm_valid_regs' field.
+If the dirty bit is not set, then the register set values will not be copied
+into the vCPU even if they've been modified.
+
+Unused bitfields in the bitarrays must be set to zero.
+
+struct kvm_sync_regs {
+        struct kvm_regs regs;
+        struct kvm_sregs sregs;
+        struct kvm_vcpu_events events;
+};
+
+6.75 KVM_CAP_PPC_IRQ_XIVE
+
+Architectures: ppc
+Target: vcpu
+Parameters: args[0] is the XIVE device fd
+            args[1] is the XIVE CPU number (server ID) for this vcpu
+
+This capability connects the vcpu to an in-kernel XIVE device.
+
+7. Capabilities that can be enabled on VMs
+------------------------------------------
+
+There are certain capabilities that change the behavior of the virtual
+machine when enabled. To enable them, please see section 4.37. Below
+you can find a list of capabilities and what their effect on the VM
+is when enabling them.
+
+The following information is provided along with the description:
+
+  Architectures: which instruction set architectures provide this ioctl.
+      x86 includes both i386 and x86_64.
+
+  Parameters: what parameters are accepted by the capability.
+
+  Returns: the return value.  General error numbers (EBADF, ENOMEM, EINVAL)
+      are not detailed, but errors with specific meanings are.
+
+
+7.1 KVM_CAP_PPC_ENABLE_HCALL
+
+Architectures: ppc
+Parameters: args[0] is the sPAPR hcall number
+           args[1] is 0 to disable, 1 to enable in-kernel handling
+
+This capability controls whether individual sPAPR hypercalls (hcalls)
+get handled by the kernel or not.  Enabling or disabling in-kernel
+handling of an hcall is effective across the VM.  On creation, an
+initial set of hcalls are enabled for in-kernel handling, which
+consists of those hcalls for which in-kernel handlers were implemented
+before this capability was implemented.  If disabled, the kernel will
+not to attempt to handle the hcall, but will always exit to userspace
+to handle it.  Note that it may not make sense to enable some and
+disable others of a group of related hcalls, but KVM does not prevent
+userspace from doing that.
+
+If the hcall number specified is not one that has an in-kernel
+implementation, the KVM_ENABLE_CAP ioctl will fail with an EINVAL
+error.
+
+7.2 KVM_CAP_S390_USER_SIGP
+
+Architectures: s390
+Parameters: none
+
+This capability controls which SIGP orders will be handled completely in user
+space. With this capability enabled, all fast orders will be handled completely
+in the kernel:
+- SENSE
+- SENSE RUNNING
+- EXTERNAL CALL
+- EMERGENCY SIGNAL
+- CONDITIONAL EMERGENCY SIGNAL
+
+All other orders will be handled completely in user space.
+
+Only privileged operation exceptions will be checked for in the kernel (or even
+in the hardware prior to interception). If this capability is not enabled, the
+old way of handling SIGP orders is used (partially in kernel and user space).
+
+7.3 KVM_CAP_S390_VECTOR_REGISTERS
+
+Architectures: s390
+Parameters: none
+Returns: 0 on success, negative value on error
+
+Allows use of the vector registers introduced with z13 processor, and
+provides for the synchronization between host and user space.  Will
+return -EINVAL if the machine does not support vectors.
+
+7.4 KVM_CAP_S390_USER_STSI
+
+Architectures: s390
+Parameters: none
+
+This capability allows post-handlers for the STSI instruction. After
+initial handling in the kernel, KVM exits to user space with
+KVM_EXIT_S390_STSI to allow user space to insert further data.
+
+Before exiting to userspace, kvm handlers should fill in s390_stsi field of
+vcpu->run:
+struct {
+       __u64 addr;
+       __u8 ar;
+       __u8 reserved;
+       __u8 fc;
+       __u8 sel1;
+       __u16 sel2;
+} s390_stsi;
+
+@addr - guest address of STSI SYSIB
+@fc   - function code
+@sel1 - selector 1
+@sel2 - selector 2
+@ar   - access register number
+
+KVM handlers should exit to userspace with rc = -EREMOTE.
+
+7.5 KVM_CAP_SPLIT_IRQCHIP
+
+Architectures: x86
+Parameters: args[0] - number of routes reserved for userspace IOAPICs
+Returns: 0 on success, -1 on error
+
+Create a local apic for each processor in the kernel. This can be used
+instead of KVM_CREATE_IRQCHIP if the userspace VMM wishes to emulate the
+IOAPIC and PIC (and also the PIT, even though this has to be enabled
+separately).
+
+This capability also enables in kernel routing of interrupt requests;
+when KVM_CAP_SPLIT_IRQCHIP only routes of KVM_IRQ_ROUTING_MSI type are
+used in the IRQ routing table.  The first args[0] MSI routes are reserved
+for the IOAPIC pins.  Whenever the LAPIC receives an EOI for these routes,
+a KVM_EXIT_IOAPIC_EOI vmexit will be reported to userspace.
+
+Fails if VCPU has already been created, or if the irqchip is already in the
+kernel (i.e. KVM_CREATE_IRQCHIP has already been called).
+
+7.6 KVM_CAP_S390_RI
+
+Architectures: s390
+Parameters: none
+
+Allows use of runtime-instrumentation introduced with zEC12 processor.
+Will return -EINVAL if the machine does not support runtime-instrumentation.
+Will return -EBUSY if a VCPU has already been created.
+
+7.7 KVM_CAP_X2APIC_API
+
+Architectures: x86
+Parameters: args[0] - features that should be enabled
+Returns: 0 on success, -EINVAL when args[0] contains invalid features
+
+Valid feature flags in args[0] are
+
+#define KVM_X2APIC_API_USE_32BIT_IDS            (1ULL << 0)
+#define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK  (1ULL << 1)
+
+Enabling KVM_X2APIC_API_USE_32BIT_IDS changes the behavior of
+KVM_SET_GSI_ROUTING, KVM_SIGNAL_MSI, KVM_SET_LAPIC, and KVM_GET_LAPIC,
+allowing the use of 32-bit APIC IDs.  See KVM_CAP_X2APIC_API in their
+respective sections.
+
+KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK must be enabled for x2APIC to work
+in logical mode or with more than 255 VCPUs.  Otherwise, KVM treats 0xff
+as a broadcast even in x2APIC mode in order to support physical x2APIC
+without interrupt remapping.  This is undesirable in logical mode,
+where 0xff represents CPUs 0-7 in cluster 0.
+
+7.8 KVM_CAP_S390_USER_INSTR0
+
+Architectures: s390
+Parameters: none
+
+With this capability enabled, all illegal instructions 0x0000 (2 bytes) will
+be intercepted and forwarded to user space. User space can use this
+mechanism e.g. to realize 2-byte software breakpoints. The kernel will
+not inject an operating exception for these instructions, user space has
+to take care of that.
+
+This capability can be enabled dynamically even if VCPUs were already
+created and are running.
+
+7.9 KVM_CAP_S390_GS
+
+Architectures: s390
+Parameters: none
+Returns: 0 on success; -EINVAL if the machine does not support
+        guarded storage; -EBUSY if a VCPU has already been created.
+
+Allows use of guarded storage for the KVM guest.
+
+7.10 KVM_CAP_S390_AIS
+
+Architectures: s390
+Parameters: none
+
+Allow use of adapter-interruption suppression.
+Returns: 0 on success; -EBUSY if a VCPU has already been created.
+
+7.11 KVM_CAP_PPC_SMT
+
+Architectures: ppc
+Parameters: vsmt_mode, flags
+
+Enabling this capability on a VM provides userspace with a way to set
+the desired virtual SMT mode (i.e. the number of virtual CPUs per
+virtual core).  The virtual SMT mode, vsmt_mode, must be a power of 2
+between 1 and 8.  On POWER8, vsmt_mode must also be no greater than
+the number of threads per subcore for the host.  Currently flags must
+be 0.  A successful call to enable this capability will result in
+vsmt_mode being returned when the KVM_CAP_PPC_SMT capability is
+subsequently queried for the VM.  This capability is only supported by
+HV KVM, and can only be set before any VCPUs have been created.
+The KVM_CAP_PPC_SMT_POSSIBLE capability indicates which virtual SMT
+modes are available.
+
+7.12 KVM_CAP_PPC_FWNMI
+
+Architectures: ppc
+Parameters: none
+
+With this capability a machine check exception in the guest address
+space will cause KVM to exit the guest with NMI exit reason. This
+enables QEMU to build error log and branch to guest kernel registered
+machine check handling routine. Without this capability KVM will
+branch to guests' 0x200 interrupt vector.
+
+7.13 KVM_CAP_X86_DISABLE_EXITS
+
+Architectures: x86
+Parameters: args[0] defines which exits are disabled
+Returns: 0 on success, -EINVAL when args[0] contains invalid exits
+
+Valid bits in args[0] are
+
+#define KVM_X86_DISABLE_EXITS_MWAIT            (1 << 0)
+#define KVM_X86_DISABLE_EXITS_HLT              (1 << 1)
+#define KVM_X86_DISABLE_EXITS_PAUSE            (1 << 2)
+#define KVM_X86_DISABLE_EXITS_CSTATE           (1 << 3)
+
+Enabling this capability on a VM provides userspace with a way to no
+longer intercept some instructions for improved latency in some
+workloads, and is suggested when vCPUs are associated to dedicated
+physical CPUs.  More bits can be added in the future; userspace can
+just pass the KVM_CHECK_EXTENSION result to KVM_ENABLE_CAP to disable
+all such vmexits.
+
+Do not enable KVM_FEATURE_PV_UNHALT if you disable HLT exits.
+
+7.14 KVM_CAP_S390_HPAGE_1M
+
+Architectures: s390
+Parameters: none
+Returns: 0 on success, -EINVAL if hpage module parameter was not set
+        or cmma is enabled, or the VM has the KVM_VM_S390_UCONTROL
+        flag set
+
+With this capability the KVM support for memory backing with 1m pages
+through hugetlbfs can be enabled for a VM. After the capability is
+enabled, cmma can't be enabled anymore and pfmfi and the storage key
+interpretation are disabled. If cmma has already been enabled or the
+hpage module parameter is not set to 1, -EINVAL is returned.
+
+While it is generally possible to create a huge page backed VM without
+this capability, the VM will not be able to run.
+
+7.15 KVM_CAP_MSR_PLATFORM_INFO
+
+Architectures: x86
+Parameters: args[0] whether feature should be enabled or not
+
+With this capability, a guest may read the MSR_PLATFORM_INFO MSR. Otherwise,
+a #GP would be raised when the guest tries to access. Currently, this
+capability does not enable write permissions of this MSR for the guest.
+
+7.16 KVM_CAP_PPC_NESTED_HV
+
+Architectures: ppc
+Parameters: none
+Returns: 0 on success, -EINVAL when the implementation doesn't support
+        nested-HV virtualization.
+
+HV-KVM on POWER9 and later systems allows for "nested-HV"
+virtualization, which provides a way for a guest VM to run guests that
+can run using the CPU's supervisor mode (privileged non-hypervisor
+state).  Enabling this capability on a VM depends on the CPU having
+the necessary functionality and on the facility being enabled with a
+kvm-hv module parameter.
+
+7.17 KVM_CAP_EXCEPTION_PAYLOAD
+
+Architectures: x86
+Parameters: args[0] whether feature should be enabled or not
+
+With this capability enabled, CR2 will not be modified prior to the
+emulated VM-exit when L1 intercepts a #PF exception that occurs in
+L2. Similarly, for kvm-intel only, DR6 will not be modified prior to
+the emulated VM-exit when L1 intercepts a #DB exception that occurs in
+L2. As a result, when KVM_GET_VCPU_EVENTS reports a pending #PF (or
+#DB) exception for L2, exception.has_payload will be set and the
+faulting address (or the new DR6 bits*) will be reported in the
+exception_payload field. Similarly, when userspace injects a #PF (or
+#DB) into L2 using KVM_SET_VCPU_EVENTS, it is expected to set
+exception.has_payload and to put the faulting address (or the new DR6
+bits*) in the exception_payload field.
+
+This capability also enables exception.pending in struct
+kvm_vcpu_events, which allows userspace to distinguish between pending
+and injected exceptions.
+
+
+* For the new DR6 bits, note that bit 16 is set iff the #DB exception
+  will clear DR6.RTM.
+
+7.18 KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2
+
+Architectures: x86, arm, arm64, mips
+Parameters: args[0] whether feature should be enabled or not
+
+With this capability enabled, KVM_GET_DIRTY_LOG will not automatically
+clear and write-protect all pages that are returned as dirty.
+Rather, userspace will have to do this operation separately using
+KVM_CLEAR_DIRTY_LOG.
+
+At the cost of a slightly more complicated operation, this provides better
+scalability and responsiveness for two reasons.  First,
+KVM_CLEAR_DIRTY_LOG ioctl can operate on a 64-page granularity rather
+than requiring to sync a full memslot; this ensures that KVM does not
+take spinlocks for an extended period of time.  Second, in some cases a
+large amount of time can pass between a call to KVM_GET_DIRTY_LOG and
+userspace actually using the data in the page.  Pages can be modified
+during this time, which is inefficint for both the guest and userspace:
+the guest will incur a higher penalty due to write protection faults,
+while userspace can see false reports of dirty pages.  Manual reprotection
+helps reducing this time, improving guest performance and reducing the
+number of dirty log false positives.
+
+KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 was previously available under the name
+KVM_CAP_MANUAL_DIRTY_LOG_PROTECT, but the implementation had bugs that make
+it hard or impossible to use it correctly.  The availability of
+KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 signals that those bugs are fixed.
+Userspace should not try to use KVM_CAP_MANUAL_DIRTY_LOG_PROTECT.
+
+8. Other capabilities.
+----------------------
+
+This section lists capabilities that give information about other
+features of the KVM implementation.
+
+8.1 KVM_CAP_PPC_HWRNG
+
+Architectures: ppc
+
+This capability, if KVM_CHECK_EXTENSION indicates that it is
+available, means that that the kernel has an implementation of the
+H_RANDOM hypercall backed by a hardware random-number generator.
+If present, the kernel H_RANDOM handler can be enabled for guest use
+with the KVM_CAP_PPC_ENABLE_HCALL capability.
+
+8.2 KVM_CAP_HYPERV_SYNIC
+
+Architectures: x86
+This capability, if KVM_CHECK_EXTENSION indicates that it is
+available, means that that the kernel has an implementation of the
+Hyper-V Synthetic interrupt controller(SynIC). Hyper-V SynIC is
+used to support Windows Hyper-V based guest paravirt drivers(VMBus).
+
+In order to use SynIC, it has to be activated by setting this
+capability via KVM_ENABLE_CAP ioctl on the vcpu fd. Note that this
+will disable the use of APIC hardware virtualization even if supported
+by the CPU, as it's incompatible with SynIC auto-EOI behavior.
+
+8.3 KVM_CAP_PPC_RADIX_MMU
+
+Architectures: ppc
+
+This capability, if KVM_CHECK_EXTENSION indicates that it is
+available, means that that the kernel can support guests using the
+radix MMU defined in Power ISA V3.00 (as implemented in the POWER9
+processor).
+
+8.4 KVM_CAP_PPC_HASH_MMU_V3
+
+Architectures: ppc
+
+This capability, if KVM_CHECK_EXTENSION indicates that it is
+available, means that that the kernel can support guests using the
+hashed page table MMU defined in Power ISA V3.00 (as implemented in
+the POWER9 processor), including in-memory segment tables.
+
+8.5 KVM_CAP_MIPS_VZ
+
+Architectures: mips
+
+This capability, if KVM_CHECK_EXTENSION on the main kvm handle indicates that
+it is available, means that full hardware assisted virtualization capabilities
+of the hardware are available for use through KVM. An appropriate
+KVM_VM_MIPS_* type must be passed to KVM_CREATE_VM to create a VM which
+utilises it.
+
+If KVM_CHECK_EXTENSION on a kvm VM handle indicates that this capability is
+available, it means that the VM is using full hardware assisted virtualization
+capabilities of the hardware. This is useful to check after creating a VM with
+KVM_VM_MIPS_DEFAULT.
+
+The value returned by KVM_CHECK_EXTENSION should be compared against known
+values (see below). All other values are reserved. This is to allow for the
+possibility of other hardware assisted virtualization implementations which
+may be incompatible with the MIPS VZ ASE.
+
+ 0: The trap & emulate implementation is in use to run guest code in user
+    mode. Guest virtual memory segments are rearranged to fit the guest in the
+    user mode address space.
+
+ 1: The MIPS VZ ASE is in use, providing full hardware assisted
+    virtualization, including standard guest virtual memory segments.
+
+8.6 KVM_CAP_MIPS_TE
+
+Architectures: mips
+
+This capability, if KVM_CHECK_EXTENSION on the main kvm handle indicates that
+it is available, means that the trap & emulate implementation is available to
+run guest code in user mode, even if KVM_CAP_MIPS_VZ indicates that hardware
+assisted virtualisation is also available. KVM_VM_MIPS_TE (0) must be passed
+to KVM_CREATE_VM to create a VM which utilises it.
+
+If KVM_CHECK_EXTENSION on a kvm VM handle indicates that this capability is
+available, it means that the VM is using trap & emulate.
+
+8.7 KVM_CAP_MIPS_64BIT
+
+Architectures: mips
+
+This capability indicates the supported architecture type of the guest, i.e. the
+supported register and address width.
+
+The values returned when this capability is checked by KVM_CHECK_EXTENSION on a
+kvm VM handle correspond roughly to the CP0_Config.AT register field, and should
+be checked specifically against known values (see below). All other values are
+reserved.
+
+ 0: MIPS32 or microMIPS32.
+    Both registers and addresses are 32-bits wide.
+    It will only be possible to run 32-bit guest code.
+
+ 1: MIPS64 or microMIPS64 with access only to 32-bit compatibility segments.
+    Registers are 64-bits wide, but addresses are 32-bits wide.
+    64-bit guest code may run but cannot access MIPS64 memory segments.
+    It will also be possible to run 32-bit guest code.
+
+ 2: MIPS64 or microMIPS64 with access to all address segments.
+    Both registers and addresses are 64-bits wide.
+    It will be possible to run 64-bit or 32-bit guest code.
+
+8.9 KVM_CAP_ARM_USER_IRQ
+
+Architectures: arm, arm64
+This capability, if KVM_CHECK_EXTENSION indicates that it is available, means
+that if userspace creates a VM without an in-kernel interrupt controller, it
+will be notified of changes to the output level of in-kernel emulated devices,
+which can generate virtual interrupts, presented to the VM.
+For such VMs, on every return to userspace, the kernel
+updates the vcpu's run->s.regs.device_irq_level field to represent the actual
+output level of the device.
+
+Whenever kvm detects a change in the device output level, kvm guarantees at
+least one return to userspace before running the VM.  This exit could either
+be a KVM_EXIT_INTR or any other exit event, like KVM_EXIT_MMIO. This way,
+userspace can always sample the device output level and re-compute the state of
+the userspace interrupt controller.  Userspace should always check the state
+of run->s.regs.device_irq_level on every kvm exit.
+The value in run->s.regs.device_irq_level can represent both level and edge
+triggered interrupt signals, depending on the device.  Edge triggered interrupt
+signals will exit to userspace with the bit in run->s.regs.device_irq_level
+set exactly once per edge signal.
+
+The field run->s.regs.device_irq_level is available independent of
+run->kvm_valid_regs or run->kvm_dirty_regs bits.
+
+If KVM_CAP_ARM_USER_IRQ is supported, the KVM_CHECK_EXTENSION ioctl returns a
+number larger than 0 indicating the version of this capability is implemented
+and thereby which bits in in run->s.regs.device_irq_level can signal values.
+
+Currently the following bits are defined for the device_irq_level bitmap:
+
+  KVM_CAP_ARM_USER_IRQ >= 1:
+
+    KVM_ARM_DEV_EL1_VTIMER -  EL1 virtual timer
+    KVM_ARM_DEV_EL1_PTIMER -  EL1 physical timer
+    KVM_ARM_DEV_PMU        -  ARM PMU overflow interrupt signal
+
+Future versions of kvm may implement additional events. These will get
+indicated by returning a higher number from KVM_CHECK_EXTENSION and will be
+listed above.
+
+8.10 KVM_CAP_PPC_SMT_POSSIBLE
+
+Architectures: ppc
+
+Querying this capability returns a bitmap indicating the possible
+virtual SMT modes that can be set using KVM_CAP_PPC_SMT.  If bit N
+(counting from the right) is set, then a virtual SMT mode of 2^N is
+available.
+
+8.11 KVM_CAP_HYPERV_SYNIC2
+
+Architectures: x86
+
+This capability enables a newer version of Hyper-V Synthetic interrupt
+controller (SynIC).  The only difference with KVM_CAP_HYPERV_SYNIC is that KVM
+doesn't clear SynIC message and event flags pages when they are enabled by
+writing to the respective MSRs.
+
+8.12 KVM_CAP_HYPERV_VP_INDEX
+
+Architectures: x86
+
+This capability indicates that userspace can load HV_X64_MSR_VP_INDEX msr.  Its
+value is used to denote the target vcpu for a SynIC interrupt.  For
+compatibilty, KVM initializes this msr to KVM's internal vcpu index.  When this
+capability is absent, userspace can still query this msr's value.
+
+8.13 KVM_CAP_S390_AIS_MIGRATION
+
+Architectures: s390
+Parameters: none
+
+This capability indicates if the flic device will be able to get/set the
+AIS states for migration via the KVM_DEV_FLIC_AISM_ALL attribute and allows
+to discover this without having to create a flic device.
+
+8.14 KVM_CAP_S390_PSW
+
+Architectures: s390
+
+This capability indicates that the PSW is exposed via the kvm_run structure.
+
+8.15 KVM_CAP_S390_GMAP
+
+Architectures: s390
+
+This capability indicates that the user space memory used as guest mapping can
+be anywhere in the user memory address space, as long as the memory slots are
+aligned and sized to a segment (1MB) boundary.
+
+8.16 KVM_CAP_S390_COW
+
+Architectures: s390
+
+This capability indicates that the user space memory used as guest mapping can
+use copy-on-write semantics as well as dirty pages tracking via read-only page
+tables.
+
+8.17 KVM_CAP_S390_BPB
+
+Architectures: s390
+
+This capability indicates that kvm will implement the interfaces to handle
+reset, migration and nested KVM for branch prediction blocking. The stfle
+facility 82 should not be provided to the guest without this capability.
+
+8.18 KVM_CAP_HYPERV_TLBFLUSH
+
+Architectures: x86
+
+This capability indicates that KVM supports paravirtualized Hyper-V TLB Flush
+hypercalls:
+HvFlushVirtualAddressSpace, HvFlushVirtualAddressSpaceEx,
+HvFlushVirtualAddressList, HvFlushVirtualAddressListEx.
+
+8.19 KVM_CAP_ARM_INJECT_SERROR_ESR
+
+Architectures: arm, arm64
+
+This capability indicates that userspace can specify (via the
+KVM_SET_VCPU_EVENTS ioctl) the syndrome value reported to the guest when it
+takes a virtual SError interrupt exception.
+If KVM advertises this capability, userspace can only specify the ISS field for
+the ESR syndrome. Other parts of the ESR, such as the EC are generated by the
+CPU when the exception is taken. If this virtual SError is taken to EL1 using
+AArch64, this value will be reported in the ISS field of ESR_ELx.
+
+See KVM_CAP_VCPU_EVENTS for more details.
+8.20 KVM_CAP_HYPERV_SEND_IPI
+
+Architectures: x86
+
+This capability indicates that KVM supports paravirtualized Hyper-V IPI send
+hypercalls:
+HvCallSendSyntheticClusterIpi, HvCallSendSyntheticClusterIpiEx.
diff --git a/Documentation/virt/kvm/hypercalls.txt b/Documentation/virt/kvm/hypercalls.txt
new file mode 100644 (file)
index 0000000..5f6d291
--- /dev/null
@@ -0,0 +1,154 @@
+Linux KVM Hypercall:
+===================
+X86:
+ KVM Hypercalls have a three-byte sequence of either the vmcall or the vmmcall
+ instruction. The hypervisor can replace it with instructions that are
+ guaranteed to be supported.
+
+ Up to four arguments may be passed in rbx, rcx, rdx, and rsi respectively.
+ The hypercall number should be placed in rax and the return value will be
+ placed in rax.  No other registers will be clobbered unless explicitly stated
+ by the particular hypercall.
+
+S390:
+  R2-R7 are used for parameters 1-6. In addition, R1 is used for hypercall
+  number. The return value is written to R2.
+
+  S390 uses diagnose instruction as hypercall (0x500) along with hypercall
+  number in R1.
+
+  For further information on the S390 diagnose call as supported by KVM,
+  refer to Documentation/virt/kvm/s390-diag.txt.
+
+ PowerPC:
+  It uses R3-R10 and hypercall number in R11. R4-R11 are used as output registers.
+  Return value is placed in R3.
+
+  KVM hypercalls uses 4 byte opcode, that are patched with 'hypercall-instructions'
+  property inside the device tree's /hypervisor node.
+  For more information refer to Documentation/virt/kvm/ppc-pv.txt
+
+MIPS:
+  KVM hypercalls use the HYPCALL instruction with code 0 and the hypercall
+  number in $2 (v0). Up to four arguments may be placed in $4-$7 (a0-a3) and
+  the return value is placed in $2 (v0).
+
+KVM Hypercalls Documentation
+===========================
+The template for each hypercall is:
+1. Hypercall name.
+2. Architecture(s)
+3. Status (deprecated, obsolete, active)
+4. Purpose
+
+1. KVM_HC_VAPIC_POLL_IRQ
+------------------------
+Architecture: x86
+Status: active
+Purpose: Trigger guest exit so that the host can check for pending
+interrupts on reentry.
+
+2. KVM_HC_MMU_OP
+------------------------
+Architecture: x86
+Status: deprecated.
+Purpose: Support MMU operations such as writing to PTE,
+flushing TLB, release PT.
+
+3. KVM_HC_FEATURES
+------------------------
+Architecture: PPC
+Status: active
+Purpose: Expose hypercall availability to the guest. On x86 platforms, cpuid
+used to enumerate which hypercalls are available. On PPC, either device tree
+based lookup ( which is also what EPAPR dictates) OR KVM specific enumeration
+mechanism (which is this hypercall) can be used.
+
+4. KVM_HC_PPC_MAP_MAGIC_PAGE
+------------------------
+Architecture: PPC
+Status: active
+Purpose: To enable communication between the hypervisor and guest there is a
+shared page that contains parts of supervisor visible register state.
+The guest can map this shared page to access its supervisor register through
+memory using this hypercall.
+
+5. KVM_HC_KICK_CPU
+------------------------
+Architecture: x86
+Status: active
+Purpose: Hypercall used to wakeup a vcpu from HLT state
+Usage example : A vcpu of a paravirtualized guest that is busywaiting in guest
+kernel mode for an event to occur (ex: a spinlock to become available) can
+execute HLT instruction once it has busy-waited for more than a threshold
+time-interval. Execution of HLT instruction would cause the hypervisor to put
+the vcpu to sleep until occurrence of an appropriate event. Another vcpu of the
+same guest can wakeup the sleeping vcpu by issuing KVM_HC_KICK_CPU hypercall,
+specifying APIC ID (a1) of the vcpu to be woken up. An additional argument (a0)
+is used in the hypercall for future use.
+
+
+6. KVM_HC_CLOCK_PAIRING
+------------------------
+Architecture: x86
+Status: active
+Purpose: Hypercall used to synchronize host and guest clocks.
+Usage:
+
+a0: guest physical address where host copies
+"struct kvm_clock_offset" structure.
+
+a1: clock_type, ATM only KVM_CLOCK_PAIRING_WALLCLOCK (0)
+is supported (corresponding to the host's CLOCK_REALTIME clock).
+
+               struct kvm_clock_pairing {
+                       __s64 sec;
+                       __s64 nsec;
+                       __u64 tsc;
+                       __u32 flags;
+                       __u32 pad[9];
+               };
+
+       Where:
+               * sec: seconds from clock_type clock.
+               * nsec: nanoseconds from clock_type clock.
+               * tsc: guest TSC value used to calculate sec/nsec pair
+               * flags: flags, unused (0) at the moment.
+
+The hypercall lets a guest compute a precise timestamp across
+host and guest.  The guest can use the returned TSC value to
+compute the CLOCK_REALTIME for its clock, at the same instant.
+
+Returns KVM_EOPNOTSUPP if the host does not use TSC clocksource,
+or if clock type is different than KVM_CLOCK_PAIRING_WALLCLOCK.
+
+6. KVM_HC_SEND_IPI
+------------------------
+Architecture: x86
+Status: active
+Purpose: Send IPIs to multiple vCPUs.
+
+a0: lower part of the bitmap of destination APIC IDs
+a1: higher part of the bitmap of destination APIC IDs
+a2: the lowest APIC ID in bitmap
+a3: APIC ICR
+
+The hypercall lets a guest send multicast IPIs, with at most 128
+128 destinations per hypercall in 64-bit mode and 64 vCPUs per
+hypercall in 32-bit mode.  The destinations are represented by a
+bitmap contained in the first two arguments (a0 and a1). Bit 0 of
+a0 corresponds to the APIC ID in the third argument (a2), bit 1
+corresponds to the APIC ID a2+1, and so on.
+
+Returns the number of CPUs to which the IPIs were delivered successfully.
+
+7. KVM_HC_SCHED_YIELD
+------------------------
+Architecture: x86
+Status: active
+Purpose: Hypercall used to yield if the IPI target vCPU is preempted
+
+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.
diff --git a/Documentation/virt/kvm/mmu.txt b/Documentation/virt/kvm/mmu.txt
new file mode 100644 (file)
index 0000000..1b9880d
--- /dev/null
@@ -0,0 +1,449 @@
+The x86 kvm shadow mmu
+======================
+
+The mmu (in arch/x86/kvm, files mmu.[ch] and paging_tmpl.h) is responsible
+for presenting a standard x86 mmu to the guest, while translating guest
+physical addresses to host physical addresses.
+
+The mmu code attempts to satisfy the following requirements:
+
+- correctness: the guest should not be able to determine that it is running
+               on an emulated mmu except for timing (we attempt to comply
+               with the specification, not emulate the characteristics of
+               a particular implementation such as tlb size)
+- security:    the guest must not be able to touch host memory not assigned
+               to it
+- performance: minimize the performance penalty imposed by the mmu
+- scaling:     need to scale to large memory and large vcpu guests
+- hardware:    support the full range of x86 virtualization hardware
+- integration: Linux memory management code must be in control of guest memory
+               so that swapping, page migration, page merging, transparent
+               hugepages, and similar features work without change
+- dirty tracking: report writes to guest memory to enable live migration
+               and framebuffer-based displays
+- footprint:   keep the amount of pinned kernel memory low (most memory
+               should be shrinkable)
+- reliability:  avoid multipage or GFP_ATOMIC allocations
+
+Acronyms
+========
+
+pfn   host page frame number
+hpa   host physical address
+hva   host virtual address
+gfn   guest frame number
+gpa   guest physical address
+gva   guest virtual address
+ngpa  nested guest physical address
+ngva  nested guest virtual address
+pte   page table entry (used also to refer generically to paging structure
+      entries)
+gpte  guest pte (referring to gfns)
+spte  shadow pte (referring to pfns)
+tdp   two dimensional paging (vendor neutral term for NPT and EPT)
+
+Virtual and real hardware supported
+===================================
+
+The mmu supports first-generation mmu hardware, which allows an atomic switch
+of the current paging mode and cr3 during guest entry, as well as
+two-dimensional paging (AMD's NPT and Intel's EPT).  The emulated hardware
+it exposes is the traditional 2/3/4 level x86 mmu, with support for global
+pages, pae, pse, pse36, cr0.wp, and 1GB pages. Emulated hardware also
+able to expose NPT capable hardware on NPT capable hosts.
+
+Translation
+===========
+
+The primary job of the mmu is to program the processor's mmu to translate
+addresses for the guest.  Different translations are required at different
+times:
+
+- when guest paging is disabled, we translate guest physical addresses to
+  host physical addresses (gpa->hpa)
+- when guest paging is enabled, we translate guest virtual addresses, to
+  guest physical addresses, to host physical addresses (gva->gpa->hpa)
+- when the guest launches a guest of its own, we translate nested guest
+  virtual addresses, to nested guest physical addresses, to guest physical
+  addresses, to host physical addresses (ngva->ngpa->gpa->hpa)
+
+The primary challenge is to encode between 1 and 3 translations into hardware
+that support only 1 (traditional) and 2 (tdp) translations.  When the
+number of required translations matches the hardware, the mmu operates in
+direct mode; otherwise it operates in shadow mode (see below).
+
+Memory
+======
+
+Guest memory (gpa) is part of the user address space of the process that is
+using kvm.  Userspace defines the translation between guest addresses and user
+addresses (gpa->hva); note that two gpas may alias to the same hva, but not
+vice versa.
+
+These hvas may be backed using any method available to the host: anonymous
+memory, file backed memory, and device memory.  Memory might be paged by the
+host at any time.
+
+Events
+======
+
+The mmu is driven by events, some from the guest, some from the host.
+
+Guest generated events:
+- writes to control registers (especially cr3)
+- invlpg/invlpga instruction execution
+- access to missing or protected translations
+
+Host generated events:
+- changes in the gpa->hpa translation (either through gpa->hva changes or
+  through hva->hpa changes)
+- memory pressure (the shrinker)
+
+Shadow pages
+============
+
+The principal data structure is the shadow page, 'struct kvm_mmu_page'.  A
+shadow page contains 512 sptes, which can be either leaf or nonleaf sptes.  A
+shadow page may contain a mix of leaf and nonleaf sptes.
+
+A nonleaf spte allows the hardware mmu to reach the leaf pages and
+is not related to a translation directly.  It points to other shadow pages.
+
+A leaf spte corresponds to either one or two translations encoded into
+one paging structure entry.  These are always the lowest level of the
+translation stack, with optional higher level translations left to NPT/EPT.
+Leaf ptes point at guest pages.
+
+The following table shows translations encoded by leaf ptes, with higher-level
+translations in parentheses:
+
+ Non-nested guests:
+  nonpaging:     gpa->hpa
+  paging:        gva->gpa->hpa
+  paging, tdp:   (gva->)gpa->hpa
+ Nested guests:
+  non-tdp:       ngva->gpa->hpa  (*)
+  tdp:           (ngva->)ngpa->gpa->hpa
+
+(*) the guest hypervisor will encode the ngva->gpa translation into its page
+    tables if npt is not present
+
+Shadow pages contain the following information:
+  role.level:
+    The level in the shadow paging hierarchy that this shadow page belongs to.
+    1=4k sptes, 2=2M sptes, 3=1G sptes, etc.
+  role.direct:
+    If set, leaf sptes reachable from this page are for a linear range.
+    Examples include real mode translation, large guest pages backed by small
+    host pages, and gpa->hpa translations when NPT or EPT is active.
+    The linear range starts at (gfn << PAGE_SHIFT) and its size is determined
+    by role.level (2MB for first level, 1GB for second level, 0.5TB for third
+    level, 256TB for fourth level)
+    If clear, this page corresponds to a guest page table denoted by the gfn
+    field.
+  role.quadrant:
+    When role.gpte_is_8_bytes=0, the guest uses 32-bit gptes while the host uses 64-bit
+    sptes.  That means a guest page table contains more ptes than the host,
+    so multiple shadow pages are needed to shadow one guest page.
+    For first-level shadow pages, role.quadrant can be 0 or 1 and denotes the
+    first or second 512-gpte block in the guest page table.  For second-level
+    page tables, each 32-bit gpte is converted to two 64-bit sptes
+    (since each first-level guest page is shadowed by two first-level
+    shadow pages) so role.quadrant takes values in the range 0..3.  Each
+    quadrant maps 1GB virtual address space.
+  role.access:
+    Inherited guest access permissions in the form uwx.  Note execute
+    permission is positive, not negative.
+  role.invalid:
+    The page is invalid and should not be used.  It is a root page that is
+    currently pinned (by a cpu hardware register pointing to it); once it is
+    unpinned it will be destroyed.
+  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.cr0_wp:
+    Contains the value of cr0.wp for which the page is valid.
+  role.smep_andnot_wp:
+    Contains the value of cr4.smep && !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.smap_andnot_wp:
+    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
+    shadow page; it is also used to go back from a struct kvm_mmu_page
+    to a memslot, through the kvm_memslots_for_spte_role macro and
+    __gfn_to_memslot.
+  role.ad_disabled:
+    Is 1 if the MMU instance cannot use A/D bits.  EPT did not have A/D
+    bits before Haswell; shadow EPT page tables also cannot use A/D bits
+    if the L1 hypervisor does not enable them.
+  gfn:
+    Either the guest page table containing the translations shadowed by this
+    page, or the base page frame for linear translations.  See role.direct.
+  spt:
+    A pageful of 64-bit sptes containing the translations for this page.
+    Accessed by both kvm and hardware.
+    The page pointed to by spt will have its page->private pointing back
+    at the shadow page structure.
+    sptes in spt point either at guest pages, or at lower-level shadow pages.
+    Specifically, if sp1 and sp2 are shadow pages, then sp1->spt[n] may point
+    at __pa(sp2->spt).  sp2 will point back at sp1 through parent_pte.
+    The spt array forms a DAG structure with the shadow page as a node, and
+    guest pages as leaves.
+  gfns:
+    An array of 512 guest frame numbers, one for each present pte.  Used to
+    perform a reverse map from a pte to a gfn. When role.direct is set, any
+    element of this array can be calculated from the gfn field when used, in
+    this case, the array of gfns is not allocated. See role.direct and gfn.
+  root_count:
+    A counter keeping track of how many hardware registers (guest cr3 or
+    pdptrs) are now pointing at the page.  While this counter is nonzero, the
+    page cannot be destroyed.  See role.invalid.
+  parent_ptes:
+    The reverse mapping for the pte/ptes pointing at this page's spt. If
+    parent_ptes bit 0 is zero, only one spte points at this page and
+    parent_ptes points at this single spte, otherwise, there exists multiple
+    sptes pointing at this page and (parent_ptes & ~0x1) points at a data
+    structure with a list of parent sptes.
+  unsync:
+    If true, then the translations in this page may not match the guest's
+    translation.  This is equivalent to the state of the tlb when a pte is
+    changed but before the tlb entry is flushed.  Accordingly, unsync ptes
+    are synchronized when the guest executes invlpg or flushes its tlb by
+    other means.  Valid for leaf pages.
+  unsync_children:
+    How many sptes in the page point at pages that are unsync (or have
+    unsynchronized children).
+  unsync_child_bitmap:
+    A bitmap indicating which sptes in spt point (directly or indirectly) at
+    pages that may be unsynchronized.  Used to quickly locate all unsychronized
+    pages reachable from a given page.
+  clear_spte_count:
+    Only present on 32-bit hosts, where a 64-bit spte cannot be written
+    atomically.  The reader uses this while running out of the MMU lock
+    to detect in-progress updates and retry them until the writer has
+    finished the write.
+  write_flooding_count:
+    A guest may write to a page table many times, causing a lot of
+    emulations if the page needs to be write-protected (see "Synchronized
+    and unsynchronized pages" below).  Leaf pages can be unsynchronized
+    so that they do not trigger frequent emulation, but this is not
+    possible for non-leafs.  This field counts the number of emulations
+    since the last time the page table was actually used; if emulation
+    is triggered too frequently on this page, KVM will unmap the page
+    to avoid emulation in the future.
+
+Reverse map
+===========
+
+The mmu maintains a reverse mapping whereby all ptes mapping a page can be
+reached given its gfn.  This is used, for example, when swapping out a page.
+
+Synchronized and unsynchronized pages
+=====================================
+
+The guest uses two events to synchronize its tlb and page tables: tlb flushes
+and page invalidations (invlpg).
+
+A tlb flush means that we need to synchronize all sptes reachable from the
+guest's cr3.  This is expensive, so we keep all guest page tables write
+protected, and synchronize sptes to gptes when a gpte is written.
+
+A special case is when a guest page table is reachable from the current
+guest cr3.  In this case, the guest is obliged to issue an invlpg instruction
+before using the translation.  We take advantage of that by removing write
+protection from the guest page, and allowing the guest to modify it freely.
+We synchronize modified gptes when the guest invokes invlpg.  This reduces
+the amount of emulation we have to do when the guest modifies multiple gptes,
+or when the a guest page is no longer used as a page table and is used for
+random guest data.
+
+As a side effect we have to resynchronize all reachable unsynchronized shadow
+pages on a tlb flush.
+
+
+Reaction to events
+==================
+
+- guest page fault (or npt page fault, or ept violation)
+
+This is the most complicated event.  The cause of a page fault can be:
+
+  - a true guest fault (the guest translation won't allow the access) (*)
+  - access to a missing translation
+  - access to a protected translation
+    - when logging dirty pages, memory is write protected
+    - synchronized shadow pages are write protected (*)
+  - access to untranslatable memory (mmio)
+
+  (*) not applicable in direct mode
+
+Handling a page fault is performed as follows:
+
+ - if the RSV bit of the error code is set, the page fault is caused by guest
+   accessing MMIO and cached MMIO information is available.
+   - walk shadow page table
+   - check for valid generation number in the spte (see "Fast invalidation of
+     MMIO sptes" below)
+   - cache the information to vcpu->arch.mmio_gva, vcpu->arch.access and
+     vcpu->arch.mmio_gfn, and call the emulator
+ - If both P bit and R/W bit of error code are set, this could possibly
+   be handled as a "fast page fault" (fixed without taking the MMU lock).  See
+   the description in Documentation/virt/kvm/locking.txt.
+ - if needed, walk the guest page tables to determine the guest translation
+   (gva->gpa or ngpa->gpa)
+   - if permissions are insufficient, reflect the fault back to the guest
+ - determine the host page
+   - if this is an mmio request, there is no host page; cache the info to
+     vcpu->arch.mmio_gva, vcpu->arch.access and vcpu->arch.mmio_gfn
+ - walk the shadow page table to find the spte for the translation,
+   instantiating missing intermediate page tables as necessary
+   - If this is an mmio request, cache the mmio info to the spte and set some
+     reserved bit on the spte (see callers of kvm_mmu_set_mmio_spte_mask)
+ - try to unsynchronize the page
+   - if successful, we can let the guest continue and modify the gpte
+ - emulate the instruction
+   - if failed, unshadow the page and let the guest continue
+ - update any translations that were modified by the instruction
+
+invlpg handling:
+
+  - walk the shadow page hierarchy and drop affected translations
+  - try to reinstantiate the indicated translation in the hope that the
+    guest will use it in the near future
+
+Guest control register updates:
+
+- mov to cr3
+  - look up new shadow roots
+  - synchronize newly reachable shadow pages
+
+- mov to cr0/cr4/efer
+  - set up mmu context for new paging mode
+  - look up new shadow roots
+  - synchronize newly reachable shadow pages
+
+Host translation updates:
+
+  - mmu notifier called with updated hva
+  - look up affected sptes through reverse map
+  - drop (or update) translations
+
+Emulating cr0.wp
+================
+
+If tdp is not enabled, the host must keep cr0.wp=1 so page write protection
+works for the guest kernel, not guest guest userspace.  When the guest
+cr0.wp=1, this does not present a problem.  However when the guest cr0.wp=0,
+we cannot map the permissions for gpte.u=1, gpte.w=0 to any spte (the
+semantics require allowing any guest kernel access plus user read access).
+
+We handle this by mapping the permissions to two possible sptes, depending
+on fault type:
+
+- kernel write fault: spte.u=0, spte.w=1 (allows full kernel access,
+  disallows user access)
+- read fault: spte.u=1, spte.w=0 (allows full read access, disallows kernel
+  write access)
+
+(user write faults generate a #PF)
+
+In the first case there are two additional complications:
+- if CR4.SMEP is enabled: since we've turned the page into a kernel page,
+  the kernel may now execute it.  We handle this by also setting spte.nx.
+  If we get a user fetch or read fault, we'll change spte.u=1 and
+  spte.nx=gpte.nx back.  For this to work, KVM forces EFER.NX to 1 when
+  shadow paging is in use.
+- if CR4.SMAP is disabled: since the page has been changed to a kernel
+  page, it can not be reused when CR4.SMAP is enabled. We set
+  CR4.SMAP && !CR0.WP into shadow page's role to avoid this case. Note,
+  here we do not care the case that CR4.SMAP is enabled since KVM will
+  directly inject #PF to guest due to failed permission check.
+
+To prevent an spte that was converted into a kernel page with cr0.wp=0
+from being written by the kernel after cr0.wp has changed to 1, we make
+the value of cr0.wp part of the page role.  This means that an spte created
+with one value of cr0.wp cannot be used when cr0.wp has a different value -
+it will simply be missed by the shadow page lookup code.  A similar issue
+exists when an spte created with cr0.wp=0 and cr4.smep=0 is used after
+changing cr4.smep to 1.  To avoid this, the value of !cr0.wp && cr4.smep
+is also made a part of the page role.
+
+Large pages
+===========
+
+The mmu supports all combinations of large and small guest and host pages.
+Supported page sizes include 4k, 2M, 4M, and 1G.  4M pages are treated as
+two separate 2M pages, on both guest and host, since the mmu always uses PAE
+paging.
+
+To instantiate a large spte, four constraints must be satisfied:
+
+- the spte must point to a large host page
+- the guest pte must be a large pte of at least equivalent size (if tdp is
+  enabled, there is no guest pte and this condition is satisfied)
+- if the spte will be writeable, the large page frame may not overlap any
+  write-protected pages
+- the guest page must be wholly contained by a single memory slot
+
+To check the last two conditions, the mmu maintains a ->disallow_lpage set of
+arrays for each memory slot and large page size.  Every write protected page
+causes its disallow_lpage to be incremented, thus preventing instantiation of
+a large spte.  The frames at the end of an unaligned memory slot have
+artificially inflated ->disallow_lpages so they can never be instantiated.
+
+Fast invalidation of MMIO sptes
+===============================
+
+As mentioned in "Reaction to events" above, kvm will cache MMIO
+information in leaf sptes.  When a new memslot is added or an existing
+memslot is changed, this information may become stale and needs to be
+invalidated.  This also needs to hold the MMU lock while walking all
+shadow pages, and is made more scalable with a similar technique.
+
+MMIO sptes have a few spare bits, which are used to store a
+generation number.  The global generation number is stored in
+kvm_memslots(kvm)->generation, and increased whenever guest memory info
+changes.
+
+When KVM finds an MMIO spte, it checks the generation number of the spte.
+If the generation number of the spte does not equal the global generation
+number, it will ignore the cached MMIO information and handle the page
+fault through the slow path.
+
+Since only 19 bits are used to store generation-number on mmio spte, all
+pages are zapped when there is an overflow.
+
+Unfortunately, a single memory access might access kvm_memslots(kvm) multiple
+times, the last one happening when the generation number is retrieved and
+stored into the MMIO spte.  Thus, the MMIO spte might be created based on
+out-of-date information, but with an up-to-date generation number.
+
+To avoid this, the generation number is incremented again after synchronize_srcu
+returns; thus, bit 63 of kvm_memslots(kvm)->generation set to 1 only during a
+memslot update, while some SRCU readers might be using the old copy.  We do not
+want to use an MMIO sptes created with an odd generation number, and we can do
+this without losing a bit in the MMIO spte.  The "update in-progress" bit of the
+generation is not stored in MMIO spte, and is so is implicitly zero when the
+generation is extracted out of the spte.  If KVM is unlucky and creates an MMIO
+spte while an update is in-progress, the next access to the spte will always be
+a cache miss.  For example, a subsequent access during the update window will
+miss due to the in-progress flag diverging, while an access after the update
+window closes will have a higher generation number (as compared to the spte).
+
+
+Further reading
+===============
+
+- NPT presentation from KVM Forum 2008
+  http://www.linux-kvm.org/images/c/c8/KvmForum2008%24kdf2008_21.pdf
+
diff --git a/Documentation/virt/kvm/review-checklist.txt b/Documentation/virt/kvm/review-checklist.txt
new file mode 100644 (file)
index 0000000..499af49
--- /dev/null
@@ -0,0 +1,38 @@
+Review checklist for kvm patches
+================================
+
+1.  The patch must follow Documentation/process/coding-style.rst and
+    Documentation/process/submitting-patches.rst.
+
+2.  Patches should be against kvm.git master branch.
+
+3.  If the patch introduces or modifies a new userspace API:
+    - the API must be documented in Documentation/virt/kvm/api.txt
+    - the API must be discoverable using KVM_CHECK_EXTENSION
+
+4.  New state must include support for save/restore.
+
+5.  New features must default to off (userspace should explicitly request them).
+    Performance improvements can and should default to on.
+
+6.  New cpu features should be exposed via KVM_GET_SUPPORTED_CPUID2
+
+7.  Emulator changes should be accompanied by unit tests for qemu-kvm.git
+    kvm/test directory.
+
+8.  Changes should be vendor neutral when possible.  Changes to common code
+    are better than duplicating changes to vendor code.
+
+9.  Similarly, prefer changes to arch independent code than to arch dependent
+    code.
+
+10. User/kernel interfaces and guest/host interfaces must be 64-bit clean
+    (all variables and sizes naturally aligned on 64-bit; use specific types
+    only - u64 rather than ulong).
+
+11. New guest visible features must either be documented in a hardware manual
+    or be accompanied by documentation.
+
+12. Features must be robust against reset and kexec - for example, shared
+    host/guest memory must be unshared to prevent the host from writing to
+    guest memory that the guest has not reserved for this purpose.
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
deleted file mode 100644 (file)
index 2cd6250..0000000
+++ /dev/null
@@ -1,5291 +0,0 @@
-The Definitive KVM (Kernel-based Virtual Machine) API Documentation
-===================================================================
-
-1. General description
-----------------------
-
-The kvm API is a set of ioctls that are issued to control various aspects
-of a virtual machine.  The ioctls belong to three classes:
-
- - System ioctls: These query and set global attributes which affect the
-   whole kvm subsystem.  In addition a system ioctl is used to create
-   virtual machines.
-
- - VM ioctls: These query and set attributes that affect an entire virtual
-   machine, for example memory layout.  In addition a VM ioctl is used to
-   create virtual cpus (vcpus) and devices.
-
-   VM ioctls must be issued from the same process (address space) that was
-   used to create the VM.
-
- - vcpu ioctls: These query and set attributes that control the operation
-   of a single virtual cpu.
-
-   vcpu ioctls should be issued from the same thread that was used to create
-   the vcpu, except for asynchronous vcpu ioctl that are marked as such in
-   the documentation.  Otherwise, the first ioctl after switching threads
-   could see a performance impact.
-
- - device ioctls: These query and set attributes that control the operation
-   of a single device.
-
-   device ioctls must be issued from the same process (address space) that
-   was used to create the VM.
-
-2. File descriptors
--------------------
-
-The kvm API is centered around file descriptors.  An initial
-open("/dev/kvm") obtains a handle to the kvm subsystem; this handle
-can be used to issue system ioctls.  A KVM_CREATE_VM ioctl on this
-handle will create a VM file descriptor which can be used to issue VM
-ioctls.  A KVM_CREATE_VCPU or KVM_CREATE_DEVICE ioctl on a VM fd will
-create a virtual cpu or device and return a file descriptor pointing to
-the new resource.  Finally, ioctls on a vcpu or device fd can be used
-to control the vcpu or device.  For vcpus, this includes the important
-task of actually running guest code.
-
-In general file descriptors can be migrated among processes by means
-of fork() and the SCM_RIGHTS facility of unix domain socket.  These
-kinds of tricks are explicitly not supported by kvm.  While they will
-not cause harm to the host, their actual behavior is not guaranteed by
-the API.  See "General description" for details on the ioctl usage
-model that is supported by KVM.
-
-It is important to note that althought VM ioctls may only be issued from
-the process that created the VM, a VM's lifecycle is associated with its
-file descriptor, not its creator (process).  In other words, the VM and
-its resources, *including the associated address space*, are not freed
-until the last reference to the VM's file descriptor has been released.
-For example, if fork() is issued after ioctl(KVM_CREATE_VM), the VM will
-not be freed until both the parent (original) process and its child have
-put their references to the VM's file descriptor.
-
-Because a VM's resources are not freed until the last reference to its
-file descriptor is released, creating additional references to a VM via
-via fork(), dup(), etc... without careful consideration is strongly
-discouraged and may have unwanted side effects, e.g. memory allocated
-by and on behalf of the VM's process may not be freed/unaccounted when
-the VM is shut down.
-
-
-3. Extensions
--------------
-
-As of Linux 2.6.22, the KVM ABI has been stabilized: no backward
-incompatible change are allowed.  However, there is an extension
-facility that allows backward-compatible extensions to the API to be
-queried and used.
-
-The extension mechanism is not based on the Linux version number.
-Instead, kvm defines extension identifiers and a facility to query
-whether a particular extension identifier is available.  If it is, a
-set of ioctls is available for application use.
-
-
-4. API description
-------------------
-
-This section describes ioctls that can be used to control kvm guests.
-For each ioctl, the following information is provided along with a
-description:
-
-  Capability: which KVM extension provides this ioctl.  Can be 'basic',
-      which means that is will be provided by any kernel that supports
-      API version 12 (see section 4.1), a KVM_CAP_xyz constant, which
-      means availability needs to be checked with KVM_CHECK_EXTENSION
-      (see section 4.4), or 'none' which means that while not all kernels
-      support this ioctl, there's no capability bit to check its
-      availability: for kernels that don't support the ioctl,
-      the ioctl returns -ENOTTY.
-
-  Architectures: which instruction set architectures provide this ioctl.
-      x86 includes both i386 and x86_64.
-
-  Type: system, vm, or vcpu.
-
-  Parameters: what parameters are accepted by the ioctl.
-
-  Returns: the return value.  General error numbers (EBADF, ENOMEM, EINVAL)
-      are not detailed, but errors with specific meanings are.
-
-
-4.1 KVM_GET_API_VERSION
-
-Capability: basic
-Architectures: all
-Type: system ioctl
-Parameters: none
-Returns: the constant KVM_API_VERSION (=12)
-
-This identifies the API version as the stable kvm API. It is not
-expected that this number will change.  However, Linux 2.6.20 and
-2.6.21 report earlier versions; these are not documented and not
-supported.  Applications should refuse to run if KVM_GET_API_VERSION
-returns a value other than 12.  If this check passes, all ioctls
-described as 'basic' will be available.
-
-
-4.2 KVM_CREATE_VM
-
-Capability: basic
-Architectures: all
-Type: system ioctl
-Parameters: machine type identifier (KVM_VM_*)
-Returns: a VM fd that can be used to control the new virtual machine.
-
-The new VM has no virtual cpus and no memory.
-You probably want to use 0 as machine type.
-
-In order to create user controlled virtual machines on S390, check
-KVM_CAP_S390_UCONTROL and use the flag KVM_VM_S390_UCONTROL as
-privileged user (CAP_SYS_ADMIN).
-
-To use hardware assisted virtualization on MIPS (VZ ASE) rather than
-the default trap & emulate implementation (which changes the virtual
-memory layout to fit in user mode), check KVM_CAP_MIPS_VZ and use the
-flag KVM_VM_MIPS_VZ.
-
-
-On arm64, the physical address size for a VM (IPA Size limit) is limited
-to 40bits by default. The limit can be configured if the host supports the
-extension KVM_CAP_ARM_VM_IPA_SIZE. When supported, use
-KVM_VM_TYPE_ARM_IPA_SIZE(IPA_Bits) to set the size in the machine type
-identifier, where IPA_Bits is the maximum width of any physical
-address used by the VM. The IPA_Bits is encoded in bits[7-0] of the
-machine type identifier.
-
-e.g, to configure a guest to use 48bit physical address size :
-
-    vm_fd = ioctl(dev_fd, KVM_CREATE_VM, KVM_VM_TYPE_ARM_IPA_SIZE(48));
-
-The requested size (IPA_Bits) must be :
-  0 - Implies default size, 40bits (for backward compatibility)
-
-  or
-
-  N - Implies N bits, where N is a positive integer such that,
-      32 <= N <= Host_IPA_Limit
-
-Host_IPA_Limit is the maximum possible value for IPA_Bits on the host and
-is dependent on the CPU capability and the kernel configuration. The limit can
-be retrieved using KVM_CAP_ARM_VM_IPA_SIZE of the KVM_CHECK_EXTENSION
-ioctl() at run-time.
-
-Please note that configuring the IPA size does not affect the capability
-exposed by the guest CPUs in ID_AA64MMFR0_EL1[PARange]. It only affects
-size of the address translated by the stage2 level (guest physical to
-host physical address translations).
-
-
-4.3 KVM_GET_MSR_INDEX_LIST, KVM_GET_MSR_FEATURE_INDEX_LIST
-
-Capability: basic, KVM_CAP_GET_MSR_FEATURES for KVM_GET_MSR_FEATURE_INDEX_LIST
-Architectures: x86
-Type: system ioctl
-Parameters: struct kvm_msr_list (in/out)
-Returns: 0 on success; -1 on error
-Errors:
-  EFAULT:    the msr index list cannot be read from or written to
-  E2BIG:     the msr index list is to be to fit in the array specified by
-             the user.
-
-struct kvm_msr_list {
-       __u32 nmsrs; /* number of msrs in entries */
-       __u32 indices[0];
-};
-
-The user fills in the size of the indices array in nmsrs, and in return
-kvm adjusts nmsrs to reflect the actual number of msrs and fills in the
-indices array with their numbers.
-
-KVM_GET_MSR_INDEX_LIST returns the guest msrs that are supported.  The list
-varies by kvm version and host processor, but does not change otherwise.
-
-Note: if kvm indicates supports MCE (KVM_CAP_MCE), then the MCE bank MSRs are
-not returned in the MSR list, as different vcpus can have a different number
-of banks, as set via the KVM_X86_SETUP_MCE ioctl.
-
-KVM_GET_MSR_FEATURE_INDEX_LIST returns the list of MSRs that can be passed
-to the KVM_GET_MSRS system ioctl.  This lets userspace probe host capabilities
-and processor features that are exposed via MSRs (e.g., VMX capabilities).
-This list also varies by kvm version and host processor, but does not change
-otherwise.
-
-
-4.4 KVM_CHECK_EXTENSION
-
-Capability: basic, KVM_CAP_CHECK_EXTENSION_VM for vm ioctl
-Architectures: all
-Type: system ioctl, vm ioctl
-Parameters: extension identifier (KVM_CAP_*)
-Returns: 0 if unsupported; 1 (or some other positive integer) if supported
-
-The API allows the application to query about extensions to the core
-kvm API.  Userspace passes an extension identifier (an integer) and
-receives an integer that describes the extension availability.
-Generally 0 means no and 1 means yes, but some extensions may report
-additional information in the integer return value.
-
-Based on their initialization different VMs may have different capabilities.
-It is thus encouraged to use the vm ioctl to query for capabilities (available
-with KVM_CAP_CHECK_EXTENSION_VM on the vm fd)
-
-4.5 KVM_GET_VCPU_MMAP_SIZE
-
-Capability: basic
-Architectures: all
-Type: system ioctl
-Parameters: none
-Returns: size of vcpu mmap area, in bytes
-
-The KVM_RUN ioctl (cf.) communicates with userspace via a shared
-memory region.  This ioctl returns the size of that region.  See the
-KVM_RUN documentation for details.
-
-
-4.6 KVM_SET_MEMORY_REGION
-
-Capability: basic
-Architectures: all
-Type: vm ioctl
-Parameters: struct kvm_memory_region (in)
-Returns: 0 on success, -1 on error
-
-This ioctl is obsolete and has been removed.
-
-
-4.7 KVM_CREATE_VCPU
-
-Capability: basic
-Architectures: all
-Type: vm ioctl
-Parameters: vcpu id (apic id on x86)
-Returns: vcpu fd on success, -1 on error
-
-This API adds a vcpu to a virtual machine. No more than max_vcpus may be added.
-The vcpu id is an integer in the range [0, max_vcpu_id).
-
-The recommended max_vcpus value can be retrieved using the KVM_CAP_NR_VCPUS of
-the KVM_CHECK_EXTENSION ioctl() at run-time.
-The maximum possible value for max_vcpus can be retrieved using the
-KVM_CAP_MAX_VCPUS of the KVM_CHECK_EXTENSION ioctl() at run-time.
-
-If the KVM_CAP_NR_VCPUS does not exist, you should assume that max_vcpus is 4
-cpus max.
-If the KVM_CAP_MAX_VCPUS does not exist, you should assume that max_vcpus is
-same as the value returned from KVM_CAP_NR_VCPUS.
-
-The maximum possible value for max_vcpu_id can be retrieved using the
-KVM_CAP_MAX_VCPU_ID of the KVM_CHECK_EXTENSION ioctl() at run-time.
-
-If the KVM_CAP_MAX_VCPU_ID does not exist, you should assume that max_vcpu_id
-is the same as the value returned from KVM_CAP_MAX_VCPUS.
-
-On powerpc using book3s_hv mode, the vcpus are mapped onto virtual
-threads in one or more virtual CPU cores.  (This is because the
-hardware requires all the hardware threads in a CPU core to be in the
-same partition.)  The KVM_CAP_PPC_SMT capability indicates the number
-of vcpus per virtual core (vcore).  The vcore id is obtained by
-dividing the vcpu id by the number of vcpus per vcore.  The vcpus in a
-given vcore will always be in the same physical core as each other
-(though that might be a different physical core from time to time).
-Userspace can control the threading (SMT) mode of the guest by its
-allocation of vcpu ids.  For example, if userspace wants
-single-threaded guest vcpus, it should make all vcpu ids be a multiple
-of the number of vcpus per vcore.
-
-For virtual cpus that have been created with S390 user controlled virtual
-machines, the resulting vcpu fd can be memory mapped at page offset
-KVM_S390_SIE_PAGE_OFFSET in order to obtain a memory map of the virtual
-cpu's hardware control block.
-
-
-4.8 KVM_GET_DIRTY_LOG (vm ioctl)
-
-Capability: basic
-Architectures: all
-Type: vm ioctl
-Parameters: struct kvm_dirty_log (in/out)
-Returns: 0 on success, -1 on error
-
-/* for KVM_GET_DIRTY_LOG */
-struct kvm_dirty_log {
-       __u32 slot;
-       __u32 padding;
-       union {
-               void __user *dirty_bitmap; /* one bit per page */
-               __u64 padding;
-       };
-};
-
-Given a memory slot, return a bitmap containing any pages dirtied
-since the last call to this ioctl.  Bit 0 is the first page in the
-memory slot.  Ensure the entire structure is cleared to avoid padding
-issues.
-
-If KVM_CAP_MULTI_ADDRESS_SPACE is available, bits 16-31 specifies
-the address space for which you want to return the dirty bitmap.
-They must be less than the value that KVM_CHECK_EXTENSION returns for
-the KVM_CAP_MULTI_ADDRESS_SPACE capability.
-
-The bits in the dirty bitmap are cleared before the ioctl returns, unless
-KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 is enabled.  For more information,
-see the description of the capability.
-
-4.9 KVM_SET_MEMORY_ALIAS
-
-Capability: basic
-Architectures: x86
-Type: vm ioctl
-Parameters: struct kvm_memory_alias (in)
-Returns: 0 (success), -1 (error)
-
-This ioctl is obsolete and has been removed.
-
-
-4.10 KVM_RUN
-
-Capability: basic
-Architectures: all
-Type: vcpu ioctl
-Parameters: none
-Returns: 0 on success, -1 on error
-Errors:
-  EINTR:     an unmasked signal is pending
-
-This ioctl is used to run a guest virtual cpu.  While there are no
-explicit parameters, there is an implicit parameter block that can be
-obtained by mmap()ing the vcpu fd at offset 0, with the size given by
-KVM_GET_VCPU_MMAP_SIZE.  The parameter block is formatted as a 'struct
-kvm_run' (see below).
-
-
-4.11 KVM_GET_REGS
-
-Capability: basic
-Architectures: all except ARM, arm64
-Type: vcpu ioctl
-Parameters: struct kvm_regs (out)
-Returns: 0 on success, -1 on error
-
-Reads the general purpose registers from the vcpu.
-
-/* x86 */
-struct kvm_regs {
-       /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
-       __u64 rax, rbx, rcx, rdx;
-       __u64 rsi, rdi, rsp, rbp;
-       __u64 r8,  r9,  r10, r11;
-       __u64 r12, r13, r14, r15;
-       __u64 rip, rflags;
-};
-
-/* mips */
-struct kvm_regs {
-       /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
-       __u64 gpr[32];
-       __u64 hi;
-       __u64 lo;
-       __u64 pc;
-};
-
-
-4.12 KVM_SET_REGS
-
-Capability: basic
-Architectures: all except ARM, arm64
-Type: vcpu ioctl
-Parameters: struct kvm_regs (in)
-Returns: 0 on success, -1 on error
-
-Writes the general purpose registers into the vcpu.
-
-See KVM_GET_REGS for the data structure.
-
-
-4.13 KVM_GET_SREGS
-
-Capability: basic
-Architectures: x86, ppc
-Type: vcpu ioctl
-Parameters: struct kvm_sregs (out)
-Returns: 0 on success, -1 on error
-
-Reads special registers from the vcpu.
-
-/* x86 */
-struct kvm_sregs {
-       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 interrupt_bitmap[(KVM_NR_INTERRUPTS + 63) / 64];
-};
-
-/* ppc -- see arch/powerpc/include/uapi/asm/kvm.h */
-
-interrupt_bitmap is a bitmap of pending external interrupts.  At most
-one bit may be set.  This interrupt has been acknowledged by the APIC
-but not yet injected into the cpu core.
-
-
-4.14 KVM_SET_SREGS
-
-Capability: basic
-Architectures: x86, ppc
-Type: vcpu ioctl
-Parameters: struct kvm_sregs (in)
-Returns: 0 on success, -1 on error
-
-Writes special registers into the vcpu.  See KVM_GET_SREGS for the
-data structures.
-
-
-4.15 KVM_TRANSLATE
-
-Capability: basic
-Architectures: x86
-Type: vcpu ioctl
-Parameters: struct kvm_translation (in/out)
-Returns: 0 on success, -1 on error
-
-Translates a virtual address according to the vcpu's current address
-translation mode.
-
-struct kvm_translation {
-       /* in */
-       __u64 linear_address;
-
-       /* out */
-       __u64 physical_address;
-       __u8  valid;
-       __u8  writeable;
-       __u8  usermode;
-       __u8  pad[5];
-};
-
-
-4.16 KVM_INTERRUPT
-
-Capability: basic
-Architectures: x86, ppc, mips
-Type: vcpu ioctl
-Parameters: struct kvm_interrupt (in)
-Returns: 0 on success, negative on failure.
-
-Queues a hardware interrupt vector to be injected.
-
-/* for KVM_INTERRUPT */
-struct kvm_interrupt {
-       /* in */
-       __u32 irq;
-};
-
-X86:
-
-Returns: 0 on success,
-        -EEXIST if an interrupt is already enqueued
-        -EINVAL the the irq number is invalid
-        -ENXIO if the PIC is in the kernel
-        -EFAULT if the pointer is invalid
-
-Note 'irq' is an interrupt vector, not an interrupt pin or line. This
-ioctl is useful if the in-kernel PIC is not used.
-
-PPC:
-
-Queues an external interrupt to be injected. This ioctl is overleaded
-with 3 different irq values:
-
-a) KVM_INTERRUPT_SET
-
-  This injects an edge type external interrupt into the guest once it's ready
-  to receive interrupts. When injected, the interrupt is done.
-
-b) KVM_INTERRUPT_UNSET
-
-  This unsets any pending interrupt.
-
-  Only available with KVM_CAP_PPC_UNSET_IRQ.
-
-c) KVM_INTERRUPT_SET_LEVEL
-
-  This injects a level type external interrupt into the guest context. The
-  interrupt stays pending until a specific ioctl with KVM_INTERRUPT_UNSET
-  is triggered.
-
-  Only available with KVM_CAP_PPC_IRQ_LEVEL.
-
-Note that any value for 'irq' other than the ones stated above is invalid
-and incurs unexpected behavior.
-
-This is an asynchronous vcpu ioctl and can be invoked from any thread.
-
-MIPS:
-
-Queues an external interrupt to be injected into the virtual CPU. A negative
-interrupt number dequeues the interrupt.
-
-This is an asynchronous vcpu ioctl and can be invoked from any thread.
-
-
-4.17 KVM_DEBUG_GUEST
-
-Capability: basic
-Architectures: none
-Type: vcpu ioctl
-Parameters: none)
-Returns: -1 on error
-
-Support for this has been removed.  Use KVM_SET_GUEST_DEBUG instead.
-
-
-4.18 KVM_GET_MSRS
-
-Capability: basic (vcpu), KVM_CAP_GET_MSR_FEATURES (system)
-Architectures: x86
-Type: system ioctl, vcpu ioctl
-Parameters: struct kvm_msrs (in/out)
-Returns: number of msrs successfully returned;
-        -1 on error
-
-When used as a system ioctl:
-Reads the values of MSR-based features that are available for the VM.  This
-is similar to KVM_GET_SUPPORTED_CPUID, but it returns MSR indices and values.
-The list of msr-based features can be obtained using KVM_GET_MSR_FEATURE_INDEX_LIST
-in a system ioctl.
-
-When used as a vcpu ioctl:
-Reads model-specific registers from the vcpu.  Supported msr indices can
-be obtained using KVM_GET_MSR_INDEX_LIST in a system ioctl.
-
-struct kvm_msrs {
-       __u32 nmsrs; /* number of msrs in entries */
-       __u32 pad;
-
-       struct kvm_msr_entry entries[0];
-};
-
-struct kvm_msr_entry {
-       __u32 index;
-       __u32 reserved;
-       __u64 data;
-};
-
-Application code should set the 'nmsrs' member (which indicates the
-size of the entries array) and the 'index' member of each array entry.
-kvm will fill in the 'data' member.
-
-
-4.19 KVM_SET_MSRS
-
-Capability: basic
-Architectures: x86
-Type: vcpu ioctl
-Parameters: struct kvm_msrs (in)
-Returns: 0 on success, -1 on error
-
-Writes model-specific registers to the vcpu.  See KVM_GET_MSRS for the
-data structures.
-
-Application code should set the 'nmsrs' member (which indicates the
-size of the entries array), and the 'index' and 'data' members of each
-array entry.
-
-
-4.20 KVM_SET_CPUID
-
-Capability: basic
-Architectures: x86
-Type: vcpu ioctl
-Parameters: struct kvm_cpuid (in)
-Returns: 0 on success, -1 on error
-
-Defines the vcpu responses to the cpuid instruction.  Applications
-should use the KVM_SET_CPUID2 ioctl if available.
-
-
-struct kvm_cpuid_entry {
-       __u32 function;
-       __u32 eax;
-       __u32 ebx;
-       __u32 ecx;
-       __u32 edx;
-       __u32 padding;
-};
-
-/* for KVM_SET_CPUID */
-struct kvm_cpuid {
-       __u32 nent;
-       __u32 padding;
-       struct kvm_cpuid_entry entries[0];
-};
-
-
-4.21 KVM_SET_SIGNAL_MASK
-
-Capability: basic
-Architectures: all
-Type: vcpu ioctl
-Parameters: struct kvm_signal_mask (in)
-Returns: 0 on success, -1 on error
-
-Defines which signals are blocked during execution of KVM_RUN.  This
-signal mask temporarily overrides the threads signal mask.  Any
-unblocked signal received (except SIGKILL and SIGSTOP, which retain
-their traditional behaviour) will cause KVM_RUN to return with -EINTR.
-
-Note the signal will only be delivered if not blocked by the original
-signal mask.
-
-/* for KVM_SET_SIGNAL_MASK */
-struct kvm_signal_mask {
-       __u32 len;
-       __u8  sigset[0];
-};
-
-
-4.22 KVM_GET_FPU
-
-Capability: basic
-Architectures: x86
-Type: vcpu ioctl
-Parameters: struct kvm_fpu (out)
-Returns: 0 on success, -1 on error
-
-Reads the floating point state from the vcpu.
-
-/* for KVM_GET_FPU and KVM_SET_FPU */
-struct kvm_fpu {
-       __u8  fpr[8][16];
-       __u16 fcw;
-       __u16 fsw;
-       __u8  ftwx;  /* in fxsave format */
-       __u8  pad1;
-       __u16 last_opcode;
-       __u64 last_ip;
-       __u64 last_dp;
-       __u8  xmm[16][16];
-       __u32 mxcsr;
-       __u32 pad2;
-};
-
-
-4.23 KVM_SET_FPU
-
-Capability: basic
-Architectures: x86
-Type: vcpu ioctl
-Parameters: struct kvm_fpu (in)
-Returns: 0 on success, -1 on error
-
-Writes the floating point state to the vcpu.
-
-/* for KVM_GET_FPU and KVM_SET_FPU */
-struct kvm_fpu {
-       __u8  fpr[8][16];
-       __u16 fcw;
-       __u16 fsw;
-       __u8  ftwx;  /* in fxsave format */
-       __u8  pad1;
-       __u16 last_opcode;
-       __u64 last_ip;
-       __u64 last_dp;
-       __u8  xmm[16][16];
-       __u32 mxcsr;
-       __u32 pad2;
-};
-
-
-4.24 KVM_CREATE_IRQCHIP
-
-Capability: KVM_CAP_IRQCHIP, KVM_CAP_S390_IRQCHIP (s390)
-Architectures: x86, ARM, arm64, s390
-Type: vm ioctl
-Parameters: none
-Returns: 0 on success, -1 on error
-
-Creates an interrupt controller model in the kernel.
-On x86, creates a virtual ioapic, a virtual PIC (two PICs, nested), and sets up
-future vcpus to have a local APIC.  IRQ routing for GSIs 0-15 is set to both
-PIC and IOAPIC; GSI 16-23 only go to the IOAPIC.
-On ARM/arm64, a GICv2 is created. Any other GIC versions require the usage of
-KVM_CREATE_DEVICE, which also supports creating a GICv2.  Using
-KVM_CREATE_DEVICE is preferred over KVM_CREATE_IRQCHIP for GICv2.
-On s390, a dummy irq routing table is created.
-
-Note that on s390 the KVM_CAP_S390_IRQCHIP vm capability needs to be enabled
-before KVM_CREATE_IRQCHIP can be used.
-
-
-4.25 KVM_IRQ_LINE
-
-Capability: KVM_CAP_IRQCHIP
-Architectures: x86, arm, arm64
-Type: vm ioctl
-Parameters: struct kvm_irq_level
-Returns: 0 on success, -1 on error
-
-Sets the level of a GSI input to the interrupt controller model in the kernel.
-On some architectures it is required that an interrupt controller model has
-been previously created with KVM_CREATE_IRQCHIP.  Note that edge-triggered
-interrupts require the level to be set to 1 and then back to 0.
-
-On real hardware, interrupt pins can be active-low or active-high.  This
-does not matter for the level field of struct kvm_irq_level: 1 always
-means active (asserted), 0 means inactive (deasserted).
-
-x86 allows the operating system to program the interrupt polarity
-(active-low/active-high) for level-triggered interrupts, and KVM used
-to consider the polarity.  However, due to bitrot in the handling of
-active-low interrupts, the above convention is now valid on x86 too.
-This is signaled by KVM_CAP_X86_IOAPIC_POLARITY_IGNORED.  Userspace
-should not present interrupts to the guest as active-low unless this
-capability is present (or unless it is not using the in-kernel irqchip,
-of course).
-
-
-ARM/arm64 can signal an interrupt either at the CPU level, or at the
-in-kernel irqchip (GIC), and for in-kernel irqchip can tell the GIC to
-use PPIs designated for specific cpus.  The irq field is interpreted
-like this:
-
-  bits:  | 31 ... 24 | 23  ... 16 | 15    ...    0 |
-  field: | irq_type  | vcpu_index |     irq_id     |
-
-The irq_type field has the following values:
-- irq_type[0]: out-of-kernel GIC: irq_id 0 is IRQ, irq_id 1 is FIQ
-- irq_type[1]: in-kernel GIC: SPI, irq_id between 32 and 1019 (incl.)
-               (the vcpu_index field is ignored)
-- irq_type[2]: in-kernel GIC: PPI, irq_id between 16 and 31 (incl.)
-
-(The irq_id field thus corresponds nicely to the IRQ ID in the ARM GIC specs)
-
-In both cases, level is used to assert/deassert the line.
-
-struct kvm_irq_level {
-       union {
-               __u32 irq;     /* GSI */
-               __s32 status;  /* not used for KVM_IRQ_LEVEL */
-       };
-       __u32 level;           /* 0 or 1 */
-};
-
-
-4.26 KVM_GET_IRQCHIP
-
-Capability: KVM_CAP_IRQCHIP
-Architectures: x86
-Type: vm ioctl
-Parameters: struct kvm_irqchip (in/out)
-Returns: 0 on success, -1 on error
-
-Reads the state of a kernel interrupt controller created with
-KVM_CREATE_IRQCHIP into a buffer provided by the caller.
-
-struct kvm_irqchip {
-       __u32 chip_id;  /* 0 = PIC1, 1 = PIC2, 2 = IOAPIC */
-       __u32 pad;
-        union {
-               char dummy[512];  /* reserving space */
-               struct kvm_pic_state pic;
-               struct kvm_ioapic_state ioapic;
-       } chip;
-};
-
-
-4.27 KVM_SET_IRQCHIP
-
-Capability: KVM_CAP_IRQCHIP
-Architectures: x86
-Type: vm ioctl
-Parameters: struct kvm_irqchip (in)
-Returns: 0 on success, -1 on error
-
-Sets the state of a kernel interrupt controller created with
-KVM_CREATE_IRQCHIP from a buffer provided by the caller.
-
-struct kvm_irqchip {
-       __u32 chip_id;  /* 0 = PIC1, 1 = PIC2, 2 = IOAPIC */
-       __u32 pad;
-        union {
-               char dummy[512];  /* reserving space */
-               struct kvm_pic_state pic;
-               struct kvm_ioapic_state ioapic;
-       } chip;
-};
-
-
-4.28 KVM_XEN_HVM_CONFIG
-
-Capability: KVM_CAP_XEN_HVM
-Architectures: x86
-Type: vm ioctl
-Parameters: struct kvm_xen_hvm_config (in)
-Returns: 0 on success, -1 on error
-
-Sets the MSR that the Xen HVM guest uses to initialize its hypercall
-page, and provides the starting address and size of the hypercall
-blobs in userspace.  When the guest writes the MSR, kvm copies one
-page of a blob (32- or 64-bit, depending on the vcpu mode) to guest
-memory.
-
-struct kvm_xen_hvm_config {
-       __u32 flags;
-       __u32 msr;
-       __u64 blob_addr_32;
-       __u64 blob_addr_64;
-       __u8 blob_size_32;
-       __u8 blob_size_64;
-       __u8 pad2[30];
-};
-
-
-4.29 KVM_GET_CLOCK
-
-Capability: KVM_CAP_ADJUST_CLOCK
-Architectures: x86
-Type: vm ioctl
-Parameters: struct kvm_clock_data (out)
-Returns: 0 on success, -1 on error
-
-Gets the current timestamp of kvmclock as seen by the current guest. In
-conjunction with KVM_SET_CLOCK, it is used to ensure monotonicity on scenarios
-such as migration.
-
-When KVM_CAP_ADJUST_CLOCK is passed to KVM_CHECK_EXTENSION, it returns the
-set of bits that KVM can return in struct kvm_clock_data's flag member.
-
-The only flag defined now is KVM_CLOCK_TSC_STABLE.  If set, the returned
-value is the exact kvmclock value seen by all VCPUs at the instant
-when KVM_GET_CLOCK was called.  If clear, the returned value is simply
-CLOCK_MONOTONIC plus a constant offset; the offset can be modified
-with KVM_SET_CLOCK.  KVM will try to make all VCPUs follow this clock,
-but the exact value read by each VCPU could differ, because the host
-TSC is not stable.
-
-struct kvm_clock_data {
-       __u64 clock;  /* kvmclock current value */
-       __u32 flags;
-       __u32 pad[9];
-};
-
-
-4.30 KVM_SET_CLOCK
-
-Capability: KVM_CAP_ADJUST_CLOCK
-Architectures: x86
-Type: vm ioctl
-Parameters: struct kvm_clock_data (in)
-Returns: 0 on success, -1 on error
-
-Sets the current timestamp of kvmclock to the value specified in its parameter.
-In conjunction with KVM_GET_CLOCK, it is used to ensure monotonicity on scenarios
-such as migration.
-
-struct kvm_clock_data {
-       __u64 clock;  /* kvmclock current value */
-       __u32 flags;
-       __u32 pad[9];
-};
-
-
-4.31 KVM_GET_VCPU_EVENTS
-
-Capability: KVM_CAP_VCPU_EVENTS
-Extended by: KVM_CAP_INTR_SHADOW
-Architectures: x86, arm, arm64
-Type: vcpu ioctl
-Parameters: struct kvm_vcpu_event (out)
-Returns: 0 on success, -1 on error
-
-X86:
-
-Gets currently pending exceptions, interrupts, and NMIs as well as related
-states of the vcpu.
-
-struct kvm_vcpu_events {
-       struct {
-               __u8 injected;
-               __u8 nr;
-               __u8 has_error_code;
-               __u8 pending;
-               __u32 error_code;
-       } exception;
-       struct {
-               __u8 injected;
-               __u8 nr;
-               __u8 soft;
-               __u8 shadow;
-       } interrupt;
-       struct {
-               __u8 injected;
-               __u8 pending;
-               __u8 masked;
-               __u8 pad;
-       } nmi;
-       __u32 sipi_vector;
-       __u32 flags;
-       struct {
-               __u8 smm;
-               __u8 pending;
-               __u8 smm_inside_nmi;
-               __u8 latched_init;
-       } smi;
-       __u8 reserved[27];
-       __u8 exception_has_payload;
-       __u64 exception_payload;
-};
-
-The following bits are defined in the flags field:
-
-- KVM_VCPUEVENT_VALID_SHADOW may be set to signal that
-  interrupt.shadow contains a valid state.
-
-- KVM_VCPUEVENT_VALID_SMM may be set to signal that smi contains a
-  valid state.
-
-- KVM_VCPUEVENT_VALID_PAYLOAD may be set to signal that the
-  exception_has_payload, exception_payload, and exception.pending
-  fields contain a valid state. This bit will be set whenever
-  KVM_CAP_EXCEPTION_PAYLOAD is enabled.
-
-ARM/ARM64:
-
-If the guest accesses a device that is being emulated by the host kernel in
-such a way that a real device would generate a physical SError, KVM may make
-a virtual SError pending for that VCPU. This system error interrupt remains
-pending until the guest takes the exception by unmasking PSTATE.A.
-
-Running the VCPU may cause it to take a pending SError, or make an access that
-causes an SError to become pending. The event's description is only valid while
-the VPCU is not running.
-
-This API provides a way to read and write the pending 'event' state that is not
-visible to the guest. To save, restore or migrate a VCPU the struct representing
-the state can be read then written using this GET/SET API, along with the other
-guest-visible registers. It is not possible to 'cancel' an SError that has been
-made pending.
-
-A device being emulated in user-space may also wish to generate an SError. To do
-this the events structure can be populated by user-space. The current state
-should be read first, to ensure no existing SError is pending. If an existing
-SError is pending, the architecture's 'Multiple SError interrupts' rules should
-be followed. (2.5.3 of DDI0587.a "ARM Reliability, Availability, and
-Serviceability (RAS) Specification").
-
-SError exceptions always have an ESR value. Some CPUs have the ability to
-specify what the virtual SError's ESR value should be. These systems will
-advertise KVM_CAP_ARM_INJECT_SERROR_ESR. In this case exception.has_esr will
-always have a non-zero value when read, and the agent making an SError pending
-should specify the ISS field in the lower 24 bits of exception.serror_esr. If
-the system supports KVM_CAP_ARM_INJECT_SERROR_ESR, but user-space sets the events
-with exception.has_esr as zero, KVM will choose an ESR.
-
-Specifying exception.has_esr on a system that does not support it will return
--EINVAL. Setting anything other than the lower 24bits of exception.serror_esr
-will return -EINVAL.
-
-struct kvm_vcpu_events {
-       struct {
-               __u8 serror_pending;
-               __u8 serror_has_esr;
-               /* Align it to 8 bytes */
-               __u8 pad[6];
-               __u64 serror_esr;
-       } exception;
-       __u32 reserved[12];
-};
-
-4.32 KVM_SET_VCPU_EVENTS
-
-Capability: KVM_CAP_VCPU_EVENTS
-Extended by: KVM_CAP_INTR_SHADOW
-Architectures: x86, arm, arm64
-Type: vcpu ioctl
-Parameters: struct kvm_vcpu_event (in)
-Returns: 0 on success, -1 on error
-
-X86:
-
-Set pending exceptions, interrupts, and NMIs as well as related states of the
-vcpu.
-
-See KVM_GET_VCPU_EVENTS for the data structure.
-
-Fields that may be modified asynchronously by running VCPUs can be excluded
-from the update. These fields are nmi.pending, sipi_vector, smi.smm,
-smi.pending. Keep the corresponding bits in the flags field cleared to
-suppress overwriting the current in-kernel state. The bits are:
-
-KVM_VCPUEVENT_VALID_NMI_PENDING - transfer nmi.pending to the kernel
-KVM_VCPUEVENT_VALID_SIPI_VECTOR - transfer sipi_vector
-KVM_VCPUEVENT_VALID_SMM         - transfer the smi sub-struct.
-
-If KVM_CAP_INTR_SHADOW is available, KVM_VCPUEVENT_VALID_SHADOW can be set in
-the flags field to signal that interrupt.shadow contains a valid state and
-shall be written into the VCPU.
-
-KVM_VCPUEVENT_VALID_SMM can only be set if KVM_CAP_X86_SMM is available.
-
-If KVM_CAP_EXCEPTION_PAYLOAD is enabled, KVM_VCPUEVENT_VALID_PAYLOAD
-can be set in the flags field to signal that the
-exception_has_payload, exception_payload, and exception.pending fields
-contain a valid state and shall be written into the VCPU.
-
-ARM/ARM64:
-
-Set the pending SError exception state for this VCPU. It is not possible to
-'cancel' an Serror that has been made pending.
-
-See KVM_GET_VCPU_EVENTS for the data structure.
-
-
-4.33 KVM_GET_DEBUGREGS
-
-Capability: KVM_CAP_DEBUGREGS
-Architectures: x86
-Type: vm ioctl
-Parameters: struct kvm_debugregs (out)
-Returns: 0 on success, -1 on error
-
-Reads debug registers from the vcpu.
-
-struct kvm_debugregs {
-       __u64 db[4];
-       __u64 dr6;
-       __u64 dr7;
-       __u64 flags;
-       __u64 reserved[9];
-};
-
-
-4.34 KVM_SET_DEBUGREGS
-
-Capability: KVM_CAP_DEBUGREGS
-Architectures: x86
-Type: vm ioctl
-Parameters: struct kvm_debugregs (in)
-Returns: 0 on success, -1 on error
-
-Writes debug registers into the vcpu.
-
-See KVM_GET_DEBUGREGS for the data structure. The flags field is unused
-yet and must be cleared on entry.
-
-
-4.35 KVM_SET_USER_MEMORY_REGION
-
-Capability: KVM_CAP_USER_MEMORY
-Architectures: all
-Type: vm ioctl
-Parameters: struct kvm_userspace_memory_region (in)
-Returns: 0 on success, -1 on error
-
-struct kvm_userspace_memory_region {
-       __u32 slot;
-       __u32 flags;
-       __u64 guest_phys_addr;
-       __u64 memory_size; /* bytes */
-       __u64 userspace_addr; /* start of the userspace allocated memory */
-};
-
-/* for kvm_memory_region::flags */
-#define KVM_MEM_LOG_DIRTY_PAGES        (1UL << 0)
-#define KVM_MEM_READONLY       (1UL << 1)
-
-This ioctl allows the user to create, modify or delete a guest physical
-memory slot.  Bits 0-15 of "slot" specify the slot id and this value
-should be less than the maximum number of user memory slots supported per
-VM.  The maximum allowed slots can be queried using KVM_CAP_NR_MEMSLOTS.
-Slots may not overlap in guest physical address space.
-
-If KVM_CAP_MULTI_ADDRESS_SPACE is available, bits 16-31 of "slot"
-specifies the address space which is being modified.  They must be
-less than the value that KVM_CHECK_EXTENSION returns for the
-KVM_CAP_MULTI_ADDRESS_SPACE capability.  Slots in separate address spaces
-are unrelated; the restriction on overlapping slots only applies within
-each address space.
-
-Deleting a slot is done by passing zero for memory_size.  When changing
-an existing slot, it may be moved in the guest physical memory space,
-or its flags may be modified, but it may not be resized.
-
-Memory for the region is taken starting at the address denoted by the
-field userspace_addr, which must point at user addressable memory for
-the entire memory slot size.  Any object may back this memory, including
-anonymous memory, ordinary files, and hugetlbfs.
-
-It is recommended that the lower 21 bits of guest_phys_addr and userspace_addr
-be identical.  This allows large pages in the guest to be backed by large
-pages in the host.
-
-The flags field supports two flags: KVM_MEM_LOG_DIRTY_PAGES and
-KVM_MEM_READONLY.  The former can be set to instruct KVM to keep track of
-writes to memory within the slot.  See KVM_GET_DIRTY_LOG ioctl to know how to
-use it.  The latter can be set, if KVM_CAP_READONLY_MEM capability allows it,
-to make a new slot read-only.  In this case, writes to this memory will be
-posted to userspace as KVM_EXIT_MMIO exits.
-
-When the KVM_CAP_SYNC_MMU capability is available, changes in the backing of
-the memory region are automatically reflected into the guest.  For example, an
-mmap() that affects the region will be made visible immediately.  Another
-example is madvise(MADV_DROP).
-
-It is recommended to use this API instead of the KVM_SET_MEMORY_REGION ioctl.
-The KVM_SET_MEMORY_REGION does not allow fine grained control over memory
-allocation and is deprecated.
-
-
-4.36 KVM_SET_TSS_ADDR
-
-Capability: KVM_CAP_SET_TSS_ADDR
-Architectures: x86
-Type: vm ioctl
-Parameters: unsigned long tss_address (in)
-Returns: 0 on success, -1 on error
-
-This ioctl defines the physical address of a three-page region in the guest
-physical address space.  The region must be within the first 4GB of the
-guest physical address space and must not conflict with any memory slot
-or any mmio address.  The guest may malfunction if it accesses this memory
-region.
-
-This ioctl is required on Intel-based hosts.  This is needed on Intel hardware
-because of a quirk in the virtualization implementation (see the internals
-documentation when it pops into existence).
-
-
-4.37 KVM_ENABLE_CAP
-
-Capability: KVM_CAP_ENABLE_CAP
-Architectures: mips, ppc, s390
-Type: vcpu ioctl
-Parameters: struct kvm_enable_cap (in)
-Returns: 0 on success; -1 on error
-
-Capability: KVM_CAP_ENABLE_CAP_VM
-Architectures: all
-Type: vcpu ioctl
-Parameters: struct kvm_enable_cap (in)
-Returns: 0 on success; -1 on error
-
-+Not all extensions are enabled by default. Using this ioctl the application
-can enable an extension, making it available to the guest.
-
-On systems that do not support this ioctl, it always fails. On systems that
-do support it, it only works for extensions that are supported for enablement.
-
-To check if a capability can be enabled, the KVM_CHECK_EXTENSION ioctl should
-be used.
-
-struct kvm_enable_cap {
-       /* in */
-       __u32 cap;
-
-The capability that is supposed to get enabled.
-
-       __u32 flags;
-
-A bitfield indicating future enhancements. Has to be 0 for now.
-
-       __u64 args[4];
-
-Arguments for enabling a feature. If a feature needs initial values to
-function properly, this is the place to put them.
-
-       __u8  pad[64];
-};
-
-The vcpu ioctl should be used for vcpu-specific capabilities, the vm ioctl
-for vm-wide capabilities.
-
-4.38 KVM_GET_MP_STATE
-
-Capability: KVM_CAP_MP_STATE
-Architectures: x86, s390, arm, arm64
-Type: vcpu ioctl
-Parameters: struct kvm_mp_state (out)
-Returns: 0 on success; -1 on error
-
-struct kvm_mp_state {
-       __u32 mp_state;
-};
-
-Returns the vcpu's current "multiprocessing state" (though also valid on
-uniprocessor guests).
-
-Possible values are:
-
- - KVM_MP_STATE_RUNNABLE:        the vcpu is currently running [x86,arm/arm64]
- - KVM_MP_STATE_UNINITIALIZED:   the vcpu is an application processor (AP)
-                                 which has not yet received an INIT signal [x86]
- - KVM_MP_STATE_INIT_RECEIVED:   the vcpu has received an INIT signal, and is
-                                 now ready for a SIPI [x86]
- - KVM_MP_STATE_HALTED:          the vcpu has executed a HLT instruction and
-                                 is waiting for an interrupt [x86]
- - KVM_MP_STATE_SIPI_RECEIVED:   the vcpu has just received a SIPI (vector
-                                 accessible via KVM_GET_VCPU_EVENTS) [x86]
- - KVM_MP_STATE_STOPPED:         the vcpu is stopped [s390,arm/arm64]
- - KVM_MP_STATE_CHECK_STOP:      the vcpu is in a special error state [s390]
- - KVM_MP_STATE_OPERATING:       the vcpu is operating (running or halted)
-                                 [s390]
- - KVM_MP_STATE_LOAD:            the vcpu is in a special load/startup state
-                                 [s390]
-
-On x86, this ioctl is only useful after KVM_CREATE_IRQCHIP. Without an
-in-kernel irqchip, the multiprocessing state must be maintained by userspace on
-these architectures.
-
-For arm/arm64:
-
-The only states that are valid are KVM_MP_STATE_STOPPED and
-KVM_MP_STATE_RUNNABLE which reflect if the vcpu is paused or not.
-
-4.39 KVM_SET_MP_STATE
-
-Capability: KVM_CAP_MP_STATE
-Architectures: x86, s390, arm, arm64
-Type: vcpu ioctl
-Parameters: struct kvm_mp_state (in)
-Returns: 0 on success; -1 on error
-
-Sets the vcpu's current "multiprocessing state"; see KVM_GET_MP_STATE for
-arguments.
-
-On x86, this ioctl is only useful after KVM_CREATE_IRQCHIP. Without an
-in-kernel irqchip, the multiprocessing state must be maintained by userspace on
-these architectures.
-
-For arm/arm64:
-
-The only states that are valid are KVM_MP_STATE_STOPPED and
-KVM_MP_STATE_RUNNABLE which reflect if the vcpu should be paused or not.
-
-4.40 KVM_SET_IDENTITY_MAP_ADDR
-
-Capability: KVM_CAP_SET_IDENTITY_MAP_ADDR
-Architectures: x86
-Type: vm ioctl
-Parameters: unsigned long identity (in)
-Returns: 0 on success, -1 on error
-
-This ioctl defines the physical address of a one-page region in the guest
-physical address space.  The region must be within the first 4GB of the
-guest physical address space and must not conflict with any memory slot
-or any mmio address.  The guest may malfunction if it accesses this memory
-region.
-
-Setting the address to 0 will result in resetting the address to its default
-(0xfffbc000).
-
-This ioctl is required on Intel-based hosts.  This is needed on Intel hardware
-because of a quirk in the virtualization implementation (see the internals
-documentation when it pops into existence).
-
-Fails if any VCPU has already been created.
-
-4.41 KVM_SET_BOOT_CPU_ID
-
-Capability: KVM_CAP_SET_BOOT_CPU_ID
-Architectures: x86
-Type: vm ioctl
-Parameters: unsigned long vcpu_id
-Returns: 0 on success, -1 on error
-
-Define which vcpu is the Bootstrap Processor (BSP).  Values are the same
-as the vcpu id in KVM_CREATE_VCPU.  If this ioctl is not called, the default
-is vcpu 0.
-
-
-4.42 KVM_GET_XSAVE
-
-Capability: KVM_CAP_XSAVE
-Architectures: x86
-Type: vcpu ioctl
-Parameters: struct kvm_xsave (out)
-Returns: 0 on success, -1 on error
-
-struct kvm_xsave {
-       __u32 region[1024];
-};
-
-This ioctl would copy current vcpu's xsave struct to the userspace.
-
-
-4.43 KVM_SET_XSAVE
-
-Capability: KVM_CAP_XSAVE
-Architectures: x86
-Type: vcpu ioctl
-Parameters: struct kvm_xsave (in)
-Returns: 0 on success, -1 on error
-
-struct kvm_xsave {
-       __u32 region[1024];
-};
-
-This ioctl would copy userspace's xsave struct to the kernel.
-
-
-4.44 KVM_GET_XCRS
-
-Capability: KVM_CAP_XCRS
-Architectures: x86
-Type: vcpu ioctl
-Parameters: struct kvm_xcrs (out)
-Returns: 0 on success, -1 on error
-
-struct kvm_xcr {
-       __u32 xcr;
-       __u32 reserved;
-       __u64 value;
-};
-
-struct kvm_xcrs {
-       __u32 nr_xcrs;
-       __u32 flags;
-       struct kvm_xcr xcrs[KVM_MAX_XCRS];
-       __u64 padding[16];
-};
-
-This ioctl would copy current vcpu's xcrs to the userspace.
-
-
-4.45 KVM_SET_XCRS
-
-Capability: KVM_CAP_XCRS
-Architectures: x86
-Type: vcpu ioctl
-Parameters: struct kvm_xcrs (in)
-Returns: 0 on success, -1 on error
-
-struct kvm_xcr {
-       __u32 xcr;
-       __u32 reserved;
-       __u64 value;
-};
-
-struct kvm_xcrs {
-       __u32 nr_xcrs;
-       __u32 flags;
-       struct kvm_xcr xcrs[KVM_MAX_XCRS];
-       __u64 padding[16];
-};
-
-This ioctl would set vcpu's xcr to the value userspace specified.
-
-
-4.46 KVM_GET_SUPPORTED_CPUID
-
-Capability: KVM_CAP_EXT_CPUID
-Architectures: x86
-Type: system ioctl
-Parameters: struct kvm_cpuid2 (in/out)
-Returns: 0 on success, -1 on error
-
-struct kvm_cpuid2 {
-       __u32 nent;
-       __u32 padding;
-       struct kvm_cpuid_entry2 entries[0];
-};
-
-#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX                BIT(0)
-#define KVM_CPUID_FLAG_STATEFUL_FUNC           BIT(1)
-#define KVM_CPUID_FLAG_STATE_READ_NEXT         BIT(2)
-
-struct kvm_cpuid_entry2 {
-       __u32 function;
-       __u32 index;
-       __u32 flags;
-       __u32 eax;
-       __u32 ebx;
-       __u32 ecx;
-       __u32 edx;
-       __u32 padding[3];
-};
-
-This ioctl returns x86 cpuid features which are supported by both the
-hardware and kvm in its default configuration.  Userspace can use the
-information returned by this ioctl to construct cpuid information (for
-KVM_SET_CPUID2) that is consistent with hardware, kernel, and
-userspace capabilities, and with user requirements (for example, the
-user may wish to constrain cpuid to emulate older hardware, or for
-feature consistency across a cluster).
-
-Note that certain capabilities, such as KVM_CAP_X86_DISABLE_EXITS, may
-expose cpuid features (e.g. MONITOR) which are not supported by kvm in
-its default configuration. If userspace enables such capabilities, it
-is responsible for modifying the results of this ioctl appropriately.
-
-Userspace invokes KVM_GET_SUPPORTED_CPUID by passing a kvm_cpuid2 structure
-with the 'nent' field indicating the number of entries in the variable-size
-array 'entries'.  If the number of entries is too low to describe the cpu
-capabilities, an error (E2BIG) is returned.  If the number is too high,
-the 'nent' field is adjusted and an error (ENOMEM) is returned.  If the
-number is just right, the 'nent' field is adjusted to the number of valid
-entries in the 'entries' array, which is then filled.
-
-The entries returned are the host cpuid as returned by the cpuid instruction,
-with unknown or unsupported features masked out.  Some features (for example,
-x2apic), may not be present in the host cpu, but are exposed by kvm if it can
-emulate them efficiently. The fields in each entry are defined as follows:
-
-  function: the eax value used to obtain the entry
-  index: the ecx value used to obtain the entry (for entries that are
-         affected by ecx)
-  flags: an OR of zero or more of the following:
-        KVM_CPUID_FLAG_SIGNIFCANT_INDEX:
-           if the index field is valid
-        KVM_CPUID_FLAG_STATEFUL_FUNC:
-           if cpuid for this function returns different values for successive
-           invocations; there will be several entries with the same function,
-           all with this flag set
-        KVM_CPUID_FLAG_STATE_READ_NEXT:
-           for KVM_CPUID_FLAG_STATEFUL_FUNC entries, set if this entry is
-           the first entry to be read by a cpu
-   eax, ebx, ecx, edx: the values returned by the cpuid instruction for
-         this function/index combination
-
-The TSC deadline timer feature (CPUID leaf 1, ecx[24]) is always returned
-as false, since the feature depends on KVM_CREATE_IRQCHIP for local APIC
-support.  Instead it is reported via
-
-  ioctl(KVM_CHECK_EXTENSION, KVM_CAP_TSC_DEADLINE_TIMER)
-
-if that returns true and you use KVM_CREATE_IRQCHIP, or if you emulate the
-feature in userspace, then you can enable the feature for KVM_SET_CPUID2.
-
-
-4.47 KVM_PPC_GET_PVINFO
-
-Capability: KVM_CAP_PPC_GET_PVINFO
-Architectures: ppc
-Type: vm ioctl
-Parameters: struct kvm_ppc_pvinfo (out)
-Returns: 0 on success, !0 on error
-
-struct kvm_ppc_pvinfo {
-       __u32 flags;
-       __u32 hcall[4];
-       __u8  pad[108];
-};
-
-This ioctl fetches PV specific information that need to be passed to the guest
-using the device tree or other means from vm context.
-
-The hcall array defines 4 instructions that make up a hypercall.
-
-If any additional field gets added to this structure later on, a bit for that
-additional piece of information will be set in the flags bitmap.
-
-The flags bitmap is defined as:
-
-   /* the host supports the ePAPR idle hcall
-   #define KVM_PPC_PVINFO_FLAGS_EV_IDLE   (1<<0)
-
-4.52 KVM_SET_GSI_ROUTING
-
-Capability: KVM_CAP_IRQ_ROUTING
-Architectures: x86 s390 arm arm64
-Type: vm ioctl
-Parameters: struct kvm_irq_routing (in)
-Returns: 0 on success, -1 on error
-
-Sets the GSI routing table entries, overwriting any previously set entries.
-
-On arm/arm64, GSI routing has the following limitation:
-- GSI routing does not apply to KVM_IRQ_LINE but only to KVM_IRQFD.
-
-struct kvm_irq_routing {
-       __u32 nr;
-       __u32 flags;
-       struct kvm_irq_routing_entry entries[0];
-};
-
-No flags are specified so far, the corresponding field must be set to zero.
-
-struct kvm_irq_routing_entry {
-       __u32 gsi;
-       __u32 type;
-       __u32 flags;
-       __u32 pad;
-       union {
-               struct kvm_irq_routing_irqchip irqchip;
-               struct kvm_irq_routing_msi msi;
-               struct kvm_irq_routing_s390_adapter adapter;
-               struct kvm_irq_routing_hv_sint hv_sint;
-               __u32 pad[8];
-       } u;
-};
-
-/* gsi routing entry types */
-#define KVM_IRQ_ROUTING_IRQCHIP 1
-#define KVM_IRQ_ROUTING_MSI 2
-#define KVM_IRQ_ROUTING_S390_ADAPTER 3
-#define KVM_IRQ_ROUTING_HV_SINT 4
-
-flags:
-- KVM_MSI_VALID_DEVID: used along with KVM_IRQ_ROUTING_MSI routing entry
-  type, specifies that the devid field contains a valid value.  The per-VM
-  KVM_CAP_MSI_DEVID capability advertises the requirement to provide
-  the device ID.  If this capability is not available, userspace should
-  never set the KVM_MSI_VALID_DEVID flag as the ioctl might fail.
-- zero otherwise
-
-struct kvm_irq_routing_irqchip {
-       __u32 irqchip;
-       __u32 pin;
-};
-
-struct kvm_irq_routing_msi {
-       __u32 address_lo;
-       __u32 address_hi;
-       __u32 data;
-       union {
-               __u32 pad;
-               __u32 devid;
-       };
-};
-
-If KVM_MSI_VALID_DEVID is set, devid contains a unique device identifier
-for the device that wrote the MSI message.  For PCI, this is usually a
-BFD identifier in the lower 16 bits.
-
-On x86, address_hi is ignored unless the KVM_X2APIC_API_USE_32BIT_IDS
-feature of KVM_CAP_X2APIC_API capability is enabled.  If it is enabled,
-address_hi bits 31-8 provide bits 31-8 of the destination id.  Bits 7-0 of
-address_hi must be zero.
-
-struct kvm_irq_routing_s390_adapter {
-       __u64 ind_addr;
-       __u64 summary_addr;
-       __u64 ind_offset;
-       __u32 summary_offset;
-       __u32 adapter_id;
-};
-
-struct kvm_irq_routing_hv_sint {
-       __u32 vcpu;
-       __u32 sint;
-};
-
-
-4.55 KVM_SET_TSC_KHZ
-
-Capability: KVM_CAP_TSC_CONTROL
-Architectures: x86
-Type: vcpu ioctl
-Parameters: virtual tsc_khz
-Returns: 0 on success, -1 on error
-
-Specifies the tsc frequency for the virtual machine. The unit of the
-frequency is KHz.
-
-
-4.56 KVM_GET_TSC_KHZ
-
-Capability: KVM_CAP_GET_TSC_KHZ
-Architectures: x86
-Type: vcpu ioctl
-Parameters: none
-Returns: virtual tsc-khz on success, negative value on error
-
-Returns the tsc frequency of the guest. The unit of the return value is
-KHz. If the host has unstable tsc this ioctl returns -EIO instead as an
-error.
-
-
-4.57 KVM_GET_LAPIC
-
-Capability: KVM_CAP_IRQCHIP
-Architectures: x86
-Type: vcpu ioctl
-Parameters: struct kvm_lapic_state (out)
-Returns: 0 on success, -1 on error
-
-#define KVM_APIC_REG_SIZE 0x400
-struct kvm_lapic_state {
-       char regs[KVM_APIC_REG_SIZE];
-};
-
-Reads the Local APIC registers and copies them into the input argument.  The
-data format and layout are the same as documented in the architecture manual.
-
-If KVM_X2APIC_API_USE_32BIT_IDS feature of KVM_CAP_X2APIC_API is
-enabled, then the format of APIC_ID register depends on the APIC mode
-(reported by MSR_IA32_APICBASE) of its VCPU.  x2APIC stores APIC ID in
-the APIC_ID register (bytes 32-35).  xAPIC only allows an 8-bit APIC ID
-which is stored in bits 31-24 of the APIC register, or equivalently in
-byte 35 of struct kvm_lapic_state's regs field.  KVM_GET_LAPIC must then
-be called after MSR_IA32_APICBASE has been set with KVM_SET_MSR.
-
-If KVM_X2APIC_API_USE_32BIT_IDS feature is disabled, struct kvm_lapic_state
-always uses xAPIC format.
-
-
-4.58 KVM_SET_LAPIC
-
-Capability: KVM_CAP_IRQCHIP
-Architectures: x86
-Type: vcpu ioctl
-Parameters: struct kvm_lapic_state (in)
-Returns: 0 on success, -1 on error
-
-#define KVM_APIC_REG_SIZE 0x400
-struct kvm_lapic_state {
-       char regs[KVM_APIC_REG_SIZE];
-};
-
-Copies the input argument into the Local APIC registers.  The data format
-and layout are the same as documented in the architecture manual.
-
-The format of the APIC ID register (bytes 32-35 of struct kvm_lapic_state's
-regs field) depends on the state of the KVM_CAP_X2APIC_API capability.
-See the note in KVM_GET_LAPIC.
-
-
-4.59 KVM_IOEVENTFD
-
-Capability: KVM_CAP_IOEVENTFD
-Architectures: all
-Type: vm ioctl
-Parameters: struct kvm_ioeventfd (in)
-Returns: 0 on success, !0 on error
-
-This ioctl attaches or detaches an ioeventfd to a legal pio/mmio address
-within the guest.  A guest write in the registered address will signal the
-provided event instead of triggering an exit.
-
-struct kvm_ioeventfd {
-       __u64 datamatch;
-       __u64 addr;        /* legal pio/mmio address */
-       __u32 len;         /* 0, 1, 2, 4, or 8 bytes    */
-       __s32 fd;
-       __u32 flags;
-       __u8  pad[36];
-};
-
-For the special case of virtio-ccw devices on s390, the ioevent is matched
-to a subchannel/virtqueue tuple instead.
-
-The following flags are defined:
-
-#define KVM_IOEVENTFD_FLAG_DATAMATCH (1 << kvm_ioeventfd_flag_nr_datamatch)
-#define KVM_IOEVENTFD_FLAG_PIO       (1 << kvm_ioeventfd_flag_nr_pio)
-#define KVM_IOEVENTFD_FLAG_DEASSIGN  (1 << kvm_ioeventfd_flag_nr_deassign)
-#define KVM_IOEVENTFD_FLAG_VIRTIO_CCW_NOTIFY \
-       (1 << kvm_ioeventfd_flag_nr_virtio_ccw_notify)
-
-If datamatch flag is set, the event will be signaled only if the written value
-to the registered address is equal to datamatch in struct kvm_ioeventfd.
-
-For virtio-ccw devices, addr contains the subchannel id and datamatch the
-virtqueue index.
-
-With KVM_CAP_IOEVENTFD_ANY_LENGTH, a zero length ioeventfd is allowed, and
-the kernel will ignore the length of guest write and may get a faster vmexit.
-The speedup may only apply to specific architectures, but the ioeventfd will
-work anyway.
-
-4.60 KVM_DIRTY_TLB
-
-Capability: KVM_CAP_SW_TLB
-Architectures: ppc
-Type: vcpu ioctl
-Parameters: struct kvm_dirty_tlb (in)
-Returns: 0 on success, -1 on error
-
-struct kvm_dirty_tlb {
-       __u64 bitmap;
-       __u32 num_dirty;
-};
-
-This must be called whenever userspace has changed an entry in the shared
-TLB, prior to calling KVM_RUN on the associated vcpu.
-
-The "bitmap" field is the userspace address of an array.  This array
-consists of a number of bits, equal to the total number of TLB entries as
-determined by the last successful call to KVM_CONFIG_TLB, rounded up to the
-nearest multiple of 64.
-
-Each bit corresponds to one TLB entry, ordered the same as in the shared TLB
-array.
-
-The array is little-endian: the bit 0 is the least significant bit of the
-first byte, bit 8 is the least significant bit of the second byte, etc.
-This avoids any complications with differing word sizes.
-
-The "num_dirty" field is a performance hint for KVM to determine whether it
-should skip processing the bitmap and just invalidate everything.  It must
-be set to the number of set bits in the bitmap.
-
-
-4.62 KVM_CREATE_SPAPR_TCE
-
-Capability: KVM_CAP_SPAPR_TCE
-Architectures: powerpc
-Type: vm ioctl
-Parameters: struct kvm_create_spapr_tce (in)
-Returns: file descriptor for manipulating the created TCE table
-
-This creates a virtual TCE (translation control entry) table, which
-is an IOMMU for PAPR-style virtual I/O.  It is used to translate
-logical addresses used in virtual I/O into guest physical addresses,
-and provides a scatter/gather capability for PAPR virtual I/O.
-
-/* for KVM_CAP_SPAPR_TCE */
-struct kvm_create_spapr_tce {
-       __u64 liobn;
-       __u32 window_size;
-};
-
-The liobn field gives the logical IO bus number for which to create a
-TCE table.  The window_size field specifies the size of the DMA window
-which this TCE table will translate - the table will contain one 64
-bit TCE entry for every 4kiB of the DMA window.
-
-When the guest issues an H_PUT_TCE hcall on a liobn for which a TCE
-table has been created using this ioctl(), the kernel will handle it
-in real mode, updating the TCE table.  H_PUT_TCE calls for other
-liobns will cause a vm exit and must be handled by userspace.
-
-The return value is a file descriptor which can be passed to mmap(2)
-to map the created TCE table into userspace.  This lets userspace read
-the entries written by kernel-handled H_PUT_TCE calls, and also lets
-userspace update the TCE table directly which is useful in some
-circumstances.
-
-
-4.63 KVM_ALLOCATE_RMA
-
-Capability: KVM_CAP_PPC_RMA
-Architectures: powerpc
-Type: vm ioctl
-Parameters: struct kvm_allocate_rma (out)
-Returns: file descriptor for mapping the allocated RMA
-
-This allocates a Real Mode Area (RMA) from the pool allocated at boot
-time by the kernel.  An RMA is a physically-contiguous, aligned region
-of memory used on older POWER processors to provide the memory which
-will be accessed by real-mode (MMU off) accesses in a KVM guest.
-POWER processors support a set of sizes for the RMA that usually
-includes 64MB, 128MB, 256MB and some larger powers of two.
-
-/* for KVM_ALLOCATE_RMA */
-struct kvm_allocate_rma {
-       __u64 rma_size;
-};
-
-The return value is a file descriptor which can be passed to mmap(2)
-to map the allocated RMA into userspace.  The mapped area can then be
-passed to the KVM_SET_USER_MEMORY_REGION ioctl to establish it as the
-RMA for a virtual machine.  The size of the RMA in bytes (which is
-fixed at host kernel boot time) is returned in the rma_size field of
-the argument structure.
-
-The KVM_CAP_PPC_RMA capability is 1 or 2 if the KVM_ALLOCATE_RMA ioctl
-is supported; 2 if the processor requires all virtual machines to have
-an RMA, or 1 if the processor can use an RMA but doesn't require it,
-because it supports the Virtual RMA (VRMA) facility.
-
-
-4.64 KVM_NMI
-
-Capability: KVM_CAP_USER_NMI
-Architectures: x86
-Type: vcpu ioctl
-Parameters: none
-Returns: 0 on success, -1 on error
-
-Queues an NMI on the thread's vcpu.  Note this is well defined only
-when KVM_CREATE_IRQCHIP has not been called, since this is an interface
-between the virtual cpu core and virtual local APIC.  After KVM_CREATE_IRQCHIP
-has been called, this interface is completely emulated within the kernel.
-
-To use this to emulate the LINT1 input with KVM_CREATE_IRQCHIP, use the
-following algorithm:
-
-  - pause the vcpu
-  - read the local APIC's state (KVM_GET_LAPIC)
-  - check whether changing LINT1 will queue an NMI (see the LVT entry for LINT1)
-  - if so, issue KVM_NMI
-  - resume the vcpu
-
-Some guests configure the LINT1 NMI input to cause a panic, aiding in
-debugging.
-
-
-4.65 KVM_S390_UCAS_MAP
-
-Capability: KVM_CAP_S390_UCONTROL
-Architectures: s390
-Type: vcpu ioctl
-Parameters: struct kvm_s390_ucas_mapping (in)
-Returns: 0 in case of success
-
-The parameter is defined like this:
-       struct kvm_s390_ucas_mapping {
-               __u64 user_addr;
-               __u64 vcpu_addr;
-               __u64 length;
-       };
-
-This ioctl maps the memory at "user_addr" with the length "length" to
-the vcpu's address space starting at "vcpu_addr". All parameters need to
-be aligned by 1 megabyte.
-
-
-4.66 KVM_S390_UCAS_UNMAP
-
-Capability: KVM_CAP_S390_UCONTROL
-Architectures: s390
-Type: vcpu ioctl
-Parameters: struct kvm_s390_ucas_mapping (in)
-Returns: 0 in case of success
-
-The parameter is defined like this:
-       struct kvm_s390_ucas_mapping {
-               __u64 user_addr;
-               __u64 vcpu_addr;
-               __u64 length;
-       };
-
-This ioctl unmaps the memory in the vcpu's address space starting at
-"vcpu_addr" with the length "length". The field "user_addr" is ignored.
-All parameters need to be aligned by 1 megabyte.
-
-
-4.67 KVM_S390_VCPU_FAULT
-
-Capability: KVM_CAP_S390_UCONTROL
-Architectures: s390
-Type: vcpu ioctl
-Parameters: vcpu absolute address (in)
-Returns: 0 in case of success
-
-This call creates a page table entry on the virtual cpu's address space
-(for user controlled virtual machines) or the virtual machine's address
-space (for regular virtual machines). This only works for minor faults,
-thus it's recommended to access subject memory page via the user page
-table upfront. This is useful to handle validity intercepts for user
-controlled virtual machines to fault in the virtual cpu's lowcore pages
-prior to calling the KVM_RUN ioctl.
-
-
-4.68 KVM_SET_ONE_REG
-
-Capability: KVM_CAP_ONE_REG
-Architectures: all
-Type: vcpu ioctl
-Parameters: struct kvm_one_reg (in)
-Returns: 0 on success, negative value on failure
-Errors:
-  ENOENT:   no such register
-  EINVAL:   invalid register ID, or no such register
-  EPERM:    (arm64) register access not allowed before vcpu finalization
-(These error codes are indicative only: do not rely on a specific error
-code being returned in a specific situation.)
-
-struct kvm_one_reg {
-       __u64 id;
-       __u64 addr;
-};
-
-Using this ioctl, a single vcpu register can be set to a specific value
-defined by user space with the passed in struct kvm_one_reg, where id
-refers to the register identifier as described below and addr is a pointer
-to a variable with the respective size. There can be architecture agnostic
-and architecture specific registers. Each have their own range of operation
-and their own constants and width. To keep track of the implemented
-registers, find a list below:
-
-  Arch  |           Register            | Width (bits)
-        |                               |
-  PPC   | KVM_REG_PPC_HIOR              | 64
-  PPC   | KVM_REG_PPC_IAC1              | 64
-  PPC   | KVM_REG_PPC_IAC2              | 64
-  PPC   | KVM_REG_PPC_IAC3              | 64
-  PPC   | KVM_REG_PPC_IAC4              | 64
-  PPC   | KVM_REG_PPC_DAC1              | 64
-  PPC   | KVM_REG_PPC_DAC2              | 64
-  PPC   | KVM_REG_PPC_DABR              | 64
-  PPC   | KVM_REG_PPC_DSCR              | 64
-  PPC   | KVM_REG_PPC_PURR              | 64
-  PPC   | KVM_REG_PPC_SPURR             | 64
-  PPC   | KVM_REG_PPC_DAR               | 64
-  PPC   | KVM_REG_PPC_DSISR             | 32
-  PPC   | KVM_REG_PPC_AMR               | 64
-  PPC   | KVM_REG_PPC_UAMOR             | 64
-  PPC   | KVM_REG_PPC_MMCR0             | 64
-  PPC   | KVM_REG_PPC_MMCR1             | 64
-  PPC   | KVM_REG_PPC_MMCRA             | 64
-  PPC   | KVM_REG_PPC_MMCR2             | 64
-  PPC   | KVM_REG_PPC_MMCRS             | 64
-  PPC   | KVM_REG_PPC_SIAR              | 64
-  PPC   | KVM_REG_PPC_SDAR              | 64
-  PPC   | KVM_REG_PPC_SIER              | 64
-  PPC   | KVM_REG_PPC_PMC1              | 32
-  PPC   | KVM_REG_PPC_PMC2              | 32
-  PPC   | KVM_REG_PPC_PMC3              | 32
-  PPC   | KVM_REG_PPC_PMC4              | 32
-  PPC   | KVM_REG_PPC_PMC5              | 32
-  PPC   | KVM_REG_PPC_PMC6              | 32
-  PPC   | KVM_REG_PPC_PMC7              | 32
-  PPC   | KVM_REG_PPC_PMC8              | 32
-  PPC   | KVM_REG_PPC_FPR0              | 64
-          ...
-  PPC   | KVM_REG_PPC_FPR31             | 64
-  PPC   | KVM_REG_PPC_VR0               | 128
-          ...
-  PPC   | KVM_REG_PPC_VR31              | 128
-  PPC   | KVM_REG_PPC_VSR0              | 128
-          ...
-  PPC   | KVM_REG_PPC_VSR31             | 128
-  PPC   | KVM_REG_PPC_FPSCR             | 64
-  PPC   | KVM_REG_PPC_VSCR              | 32
-  PPC   | KVM_REG_PPC_VPA_ADDR          | 64
-  PPC   | KVM_REG_PPC_VPA_SLB           | 128
-  PPC   | KVM_REG_PPC_VPA_DTL           | 128
-  PPC   | KVM_REG_PPC_EPCR              | 32
-  PPC   | KVM_REG_PPC_EPR               | 32
-  PPC   | KVM_REG_PPC_TCR               | 32
-  PPC   | KVM_REG_PPC_TSR               | 32
-  PPC   | KVM_REG_PPC_OR_TSR            | 32
-  PPC   | KVM_REG_PPC_CLEAR_TSR         | 32
-  PPC   | KVM_REG_PPC_MAS0              | 32
-  PPC   | KVM_REG_PPC_MAS1              | 32
-  PPC   | KVM_REG_PPC_MAS2              | 64
-  PPC   | KVM_REG_PPC_MAS7_3            | 64
-  PPC   | KVM_REG_PPC_MAS4              | 32
-  PPC   | KVM_REG_PPC_MAS6              | 32
-  PPC   | KVM_REG_PPC_MMUCFG            | 32
-  PPC   | KVM_REG_PPC_TLB0CFG           | 32
-  PPC   | KVM_REG_PPC_TLB1CFG           | 32
-  PPC   | KVM_REG_PPC_TLB2CFG           | 32
-  PPC   | KVM_REG_PPC_TLB3CFG           | 32
-  PPC   | KVM_REG_PPC_TLB0PS            | 32
-  PPC   | KVM_REG_PPC_TLB1PS            | 32
-  PPC   | KVM_REG_PPC_TLB2PS            | 32
-  PPC   | KVM_REG_PPC_TLB3PS            | 32
-  PPC   | KVM_REG_PPC_EPTCFG            | 32
-  PPC   | KVM_REG_PPC_ICP_STATE         | 64
-  PPC   | KVM_REG_PPC_VP_STATE          | 128
-  PPC   | KVM_REG_PPC_TB_OFFSET         | 64
-  PPC   | KVM_REG_PPC_SPMC1             | 32
-  PPC   | KVM_REG_PPC_SPMC2             | 32
-  PPC   | KVM_REG_PPC_IAMR              | 64
-  PPC   | KVM_REG_PPC_TFHAR             | 64
-  PPC   | KVM_REG_PPC_TFIAR             | 64
-  PPC   | KVM_REG_PPC_TEXASR            | 64
-  PPC   | KVM_REG_PPC_FSCR              | 64
-  PPC   | KVM_REG_PPC_PSPB              | 32
-  PPC   | KVM_REG_PPC_EBBHR             | 64
-  PPC   | KVM_REG_PPC_EBBRR             | 64
-  PPC   | KVM_REG_PPC_BESCR             | 64
-  PPC   | KVM_REG_PPC_TAR               | 64
-  PPC   | KVM_REG_PPC_DPDES             | 64
-  PPC   | KVM_REG_PPC_DAWR              | 64
-  PPC   | KVM_REG_PPC_DAWRX             | 64
-  PPC   | KVM_REG_PPC_CIABR             | 64
-  PPC   | KVM_REG_PPC_IC                | 64
-  PPC   | KVM_REG_PPC_VTB               | 64
-  PPC   | KVM_REG_PPC_CSIGR             | 64
-  PPC   | KVM_REG_PPC_TACR              | 64
-  PPC   | KVM_REG_PPC_TCSCR             | 64
-  PPC   | KVM_REG_PPC_PID               | 64
-  PPC   | KVM_REG_PPC_ACOP              | 64
-  PPC   | KVM_REG_PPC_VRSAVE            | 32
-  PPC   | KVM_REG_PPC_LPCR              | 32
-  PPC   | KVM_REG_PPC_LPCR_64           | 64
-  PPC   | KVM_REG_PPC_PPR               | 64
-  PPC   | KVM_REG_PPC_ARCH_COMPAT       | 32
-  PPC   | KVM_REG_PPC_DABRX             | 32
-  PPC   | KVM_REG_PPC_WORT              | 64
-  PPC  | KVM_REG_PPC_SPRG9             | 64
-  PPC  | KVM_REG_PPC_DBSR              | 32
-  PPC   | KVM_REG_PPC_TIDR              | 64
-  PPC   | KVM_REG_PPC_PSSCR             | 64
-  PPC   | KVM_REG_PPC_DEC_EXPIRY        | 64
-  PPC   | KVM_REG_PPC_PTCR              | 64
-  PPC   | KVM_REG_PPC_TM_GPR0           | 64
-          ...
-  PPC   | KVM_REG_PPC_TM_GPR31          | 64
-  PPC   | KVM_REG_PPC_TM_VSR0           | 128
-          ...
-  PPC   | KVM_REG_PPC_TM_VSR63          | 128
-  PPC   | KVM_REG_PPC_TM_CR             | 64
-  PPC   | KVM_REG_PPC_TM_LR             | 64
-  PPC   | KVM_REG_PPC_TM_CTR            | 64
-  PPC   | KVM_REG_PPC_TM_FPSCR          | 64
-  PPC   | KVM_REG_PPC_TM_AMR            | 64
-  PPC   | KVM_REG_PPC_TM_PPR            | 64
-  PPC   | KVM_REG_PPC_TM_VRSAVE         | 64
-  PPC   | KVM_REG_PPC_TM_VSCR           | 32
-  PPC   | KVM_REG_PPC_TM_DSCR           | 64
-  PPC   | KVM_REG_PPC_TM_TAR            | 64
-  PPC   | KVM_REG_PPC_TM_XER            | 64
-        |                               |
-  MIPS  | KVM_REG_MIPS_R0               | 64
-          ...
-  MIPS  | KVM_REG_MIPS_R31              | 64
-  MIPS  | KVM_REG_MIPS_HI               | 64
-  MIPS  | KVM_REG_MIPS_LO               | 64
-  MIPS  | KVM_REG_MIPS_PC               | 64
-  MIPS  | KVM_REG_MIPS_CP0_INDEX        | 32
-  MIPS  | KVM_REG_MIPS_CP0_ENTRYLO0     | 64
-  MIPS  | KVM_REG_MIPS_CP0_ENTRYLO1     | 64
-  MIPS  | KVM_REG_MIPS_CP0_CONTEXT      | 64
-  MIPS  | KVM_REG_MIPS_CP0_CONTEXTCONFIG| 32
-  MIPS  | KVM_REG_MIPS_CP0_USERLOCAL    | 64
-  MIPS  | KVM_REG_MIPS_CP0_XCONTEXTCONFIG| 64
-  MIPS  | KVM_REG_MIPS_CP0_PAGEMASK     | 32
-  MIPS  | KVM_REG_MIPS_CP0_PAGEGRAIN    | 32
-  MIPS  | KVM_REG_MIPS_CP0_SEGCTL0      | 64
-  MIPS  | KVM_REG_MIPS_CP0_SEGCTL1      | 64
-  MIPS  | KVM_REG_MIPS_CP0_SEGCTL2      | 64
-  MIPS  | KVM_REG_MIPS_CP0_PWBASE       | 64
-  MIPS  | KVM_REG_MIPS_CP0_PWFIELD      | 64
-  MIPS  | KVM_REG_MIPS_CP0_PWSIZE       | 64
-  MIPS  | KVM_REG_MIPS_CP0_WIRED        | 32
-  MIPS  | KVM_REG_MIPS_CP0_PWCTL        | 32
-  MIPS  | KVM_REG_MIPS_CP0_HWRENA       | 32
-  MIPS  | KVM_REG_MIPS_CP0_BADVADDR     | 64
-  MIPS  | KVM_REG_MIPS_CP0_BADINSTR     | 32
-  MIPS  | KVM_REG_MIPS_CP0_BADINSTRP    | 32
-  MIPS  | KVM_REG_MIPS_CP0_COUNT        | 32
-  MIPS  | KVM_REG_MIPS_CP0_ENTRYHI      | 64
-  MIPS  | KVM_REG_MIPS_CP0_COMPARE      | 32
-  MIPS  | KVM_REG_MIPS_CP0_STATUS       | 32
-  MIPS  | KVM_REG_MIPS_CP0_INTCTL       | 32
-  MIPS  | KVM_REG_MIPS_CP0_CAUSE        | 32
-  MIPS  | KVM_REG_MIPS_CP0_EPC          | 64
-  MIPS  | KVM_REG_MIPS_CP0_PRID         | 32
-  MIPS  | KVM_REG_MIPS_CP0_EBASE        | 64
-  MIPS  | KVM_REG_MIPS_CP0_CONFIG       | 32
-  MIPS  | KVM_REG_MIPS_CP0_CONFIG1      | 32
-  MIPS  | KVM_REG_MIPS_CP0_CONFIG2      | 32
-  MIPS  | KVM_REG_MIPS_CP0_CONFIG3      | 32
-  MIPS  | KVM_REG_MIPS_CP0_CONFIG4      | 32
-  MIPS  | KVM_REG_MIPS_CP0_CONFIG5      | 32
-  MIPS  | KVM_REG_MIPS_CP0_CONFIG7      | 32
-  MIPS  | KVM_REG_MIPS_CP0_XCONTEXT     | 64
-  MIPS  | KVM_REG_MIPS_CP0_ERROREPC     | 64
-  MIPS  | KVM_REG_MIPS_CP0_KSCRATCH1    | 64
-  MIPS  | KVM_REG_MIPS_CP0_KSCRATCH2    | 64
-  MIPS  | KVM_REG_MIPS_CP0_KSCRATCH3    | 64
-  MIPS  | KVM_REG_MIPS_CP0_KSCRATCH4    | 64
-  MIPS  | KVM_REG_MIPS_CP0_KSCRATCH5    | 64
-  MIPS  | KVM_REG_MIPS_CP0_KSCRATCH6    | 64
-  MIPS  | KVM_REG_MIPS_CP0_MAAR(0..63)  | 64
-  MIPS  | KVM_REG_MIPS_COUNT_CTL        | 64
-  MIPS  | KVM_REG_MIPS_COUNT_RESUME     | 64
-  MIPS  | KVM_REG_MIPS_COUNT_HZ         | 64
-  MIPS  | KVM_REG_MIPS_FPR_32(0..31)    | 32
-  MIPS  | KVM_REG_MIPS_FPR_64(0..31)    | 64
-  MIPS  | KVM_REG_MIPS_VEC_128(0..31)   | 128
-  MIPS  | KVM_REG_MIPS_FCR_IR           | 32
-  MIPS  | KVM_REG_MIPS_FCR_CSR          | 32
-  MIPS  | KVM_REG_MIPS_MSA_IR           | 32
-  MIPS  | KVM_REG_MIPS_MSA_CSR          | 32
-
-ARM registers are mapped using the lower 32 bits.  The upper 16 of that
-is the register group type, or coprocessor number:
-
-ARM core registers have the following id bit patterns:
-  0x4020 0000 0010 <index into the kvm_regs struct:16>
-
-ARM 32-bit CP15 registers have the following id bit patterns:
-  0x4020 0000 000F <zero:1> <crn:4> <crm:4> <opc1:4> <opc2:3>
-
-ARM 64-bit CP15 registers have the following id bit patterns:
-  0x4030 0000 000F <zero:1> <zero:4> <crm:4> <opc1:4> <zero:3>
-
-ARM CCSIDR registers are demultiplexed by CSSELR value:
-  0x4020 0000 0011 00 <csselr:8>
-
-ARM 32-bit VFP control registers have the following id bit patterns:
-  0x4020 0000 0012 1 <regno:12>
-
-ARM 64-bit FP registers have the following id bit patterns:
-  0x4030 0000 0012 0 <regno:12>
-
-ARM firmware pseudo-registers have the following bit pattern:
-  0x4030 0000 0014 <regno:16>
-
-
-arm64 registers are mapped using the lower 32 bits. The upper 16 of
-that is the register group type, or coprocessor number:
-
-arm64 core/FP-SIMD registers have the following id bit patterns. Note
-that the size of the access is variable, as the kvm_regs structure
-contains elements ranging from 32 to 128 bits. The index is a 32bit
-value in the kvm_regs structure seen as a 32bit array.
-  0x60x0 0000 0010 <index into the kvm_regs struct:16>
-
-Specifically:
-    Encoding            Register  Bits  kvm_regs member
-----------------------------------------------------------------
-  0x6030 0000 0010 0000 X0          64  regs.regs[0]
-  0x6030 0000 0010 0002 X1          64  regs.regs[1]
-    ...
-  0x6030 0000 0010 003c X30         64  regs.regs[30]
-  0x6030 0000 0010 003e SP          64  regs.sp
-  0x6030 0000 0010 0040 PC          64  regs.pc
-  0x6030 0000 0010 0042 PSTATE      64  regs.pstate
-  0x6030 0000 0010 0044 SP_EL1      64  sp_el1
-  0x6030 0000 0010 0046 ELR_EL1     64  elr_el1
-  0x6030 0000 0010 0048 SPSR_EL1    64  spsr[KVM_SPSR_EL1] (alias SPSR_SVC)
-  0x6030 0000 0010 004a SPSR_ABT    64  spsr[KVM_SPSR_ABT]
-  0x6030 0000 0010 004c SPSR_UND    64  spsr[KVM_SPSR_UND]
-  0x6030 0000 0010 004e SPSR_IRQ    64  spsr[KVM_SPSR_IRQ]
-  0x6060 0000 0010 0050 SPSR_FIQ    64  spsr[KVM_SPSR_FIQ]
-  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]    (*)
-  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]    (*)
-    ...
-  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]   (*)
-  0x6020 0000 0010 00d4 FPSR        32  fp_regs.fpsr
-  0x6020 0000 0010 00d5 FPCR        32  fp_regs.fpcr
-
-(*) These encodings are not accepted for SVE-enabled vcpus.  See
-    KVM_ARM_VCPU_INIT.
-
-    The equivalent register content can be accessed via bits [127:0] of
-    the corresponding SVE Zn registers instead for vcpus that have SVE
-    enabled (see below).
-
-arm64 CCSIDR registers are demultiplexed by CSSELR value:
-  0x6020 0000 0011 00 <csselr:8>
-
-arm64 system registers have the following id bit patterns:
-  0x6030 0000 0013 <op0:2> <op1:3> <crn:4> <crm:4> <op2:3>
-
-arm64 firmware pseudo-registers have the following bit pattern:
-  0x6030 0000 0014 <regno:16>
-
-arm64 SVE registers have the following bit patterns:
-  0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
-  0x6050 0000 0015 04 <n:4> <slice:5>   Pn bits[256*slice + 255 : 256*slice]
-  0x6050 0000 0015 060 <slice:5>        FFR bits[256*slice + 255 : 256*slice]
-  0x6060 0000 0015 ffff                 KVM_REG_ARM64_SVE_VLS pseudo-register
-
-Access to register IDs where 2048 * slice >= 128 * max_vq will fail with
-ENOENT.  max_vq is the vcpu's maximum supported vector length in 128-bit
-quadwords: see (**) below.
-
-These registers are only accessible on vcpus for which SVE is enabled.
-See KVM_ARM_VCPU_INIT for details.
-
-In addition, except for KVM_REG_ARM64_SVE_VLS, these registers are not
-accessible until the vcpu's SVE configuration has been finalized
-using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).  See KVM_ARM_VCPU_INIT
-and KVM_ARM_VCPU_FINALIZE for more information about this procedure.
-
-KVM_REG_ARM64_SVE_VLS is a pseudo-register that allows the set of vector
-lengths supported by the vcpu to be discovered and configured by
-userspace.  When transferred to or from user memory via KVM_GET_ONE_REG
-or KVM_SET_ONE_REG, the value of this register is of type
-__u64[KVM_ARM64_SVE_VLS_WORDS], and encodes the set of vector lengths as
-follows:
-
-__u64 vector_lengths[KVM_ARM64_SVE_VLS_WORDS];
-
-if (vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX &&
-    ((vector_lengths[(vq - KVM_ARM64_SVE_VQ_MIN) / 64] >>
-               ((vq - KVM_ARM64_SVE_VQ_MIN) % 64)) & 1))
-       /* Vector length vq * 16 bytes supported */
-else
-       /* Vector length vq * 16 bytes not supported */
-
-(**) The maximum value vq for which the above condition is true is
-max_vq.  This is the maximum vector length available to the guest on
-this vcpu, and determines which register slices are visible through
-this ioctl interface.
-
-(See Documentation/arm64/sve.rst for an explanation of the "vq"
-nomenclature.)
-
-KVM_REG_ARM64_SVE_VLS is only accessible after KVM_ARM_VCPU_INIT.
-KVM_ARM_VCPU_INIT initialises it to the best set of vector lengths that
-the host supports.
-
-Userspace may subsequently modify it if desired until the vcpu's SVE
-configuration is finalized using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).
-
-Apart from simply removing all vector lengths from the host set that
-exceed some value, support for arbitrarily chosen sets of vector lengths
-is hardware-dependent and may not be available.  Attempting to configure
-an invalid set of vector lengths via KVM_SET_ONE_REG will fail with
-EINVAL.
-
-After the vcpu's SVE configuration is finalized, further attempts to
-write this register will fail with EPERM.
-
-
-MIPS registers are mapped using the lower 32 bits.  The upper 16 of that is
-the register group type:
-
-MIPS core registers (see above) have the following id bit patterns:
-  0x7030 0000 0000 <reg:16>
-
-MIPS CP0 registers (see KVM_REG_MIPS_CP0_* above) have the following id bit
-patterns depending on whether they're 32-bit or 64-bit registers:
-  0x7020 0000 0001 00 <reg:5> <sel:3>   (32-bit)
-  0x7030 0000 0001 00 <reg:5> <sel:3>   (64-bit)
-
-Note: KVM_REG_MIPS_CP0_ENTRYLO0 and KVM_REG_MIPS_CP0_ENTRYLO1 are the MIPS64
-versions of the EntryLo registers regardless of the word size of the host
-hardware, host kernel, guest, and whether XPA is present in the guest, i.e.
-with the RI and XI bits (if they exist) in bits 63 and 62 respectively, and
-the PFNX field starting at bit 30.
-
-MIPS MAARs (see KVM_REG_MIPS_CP0_MAAR(*) above) have the following id bit
-patterns:
-  0x7030 0000 0001 01 <reg:8>
-
-MIPS KVM control registers (see above) have the following id bit patterns:
-  0x7030 0000 0002 <reg:16>
-
-MIPS FPU registers (see KVM_REG_MIPS_FPR_{32,64}() above) have the following
-id bit patterns depending on the size of the register being accessed. They are
-always accessed according to the current guest FPU mode (Status.FR and
-Config5.FRE), i.e. as the guest would see them, and they become unpredictable
-if the guest FPU mode is changed. MIPS SIMD Architecture (MSA) vector
-registers (see KVM_REG_MIPS_VEC_128() above) have similar patterns as they
-overlap the FPU registers:
-  0x7020 0000 0003 00 <0:3> <reg:5> (32-bit FPU registers)
-  0x7030 0000 0003 00 <0:3> <reg:5> (64-bit FPU registers)
-  0x7040 0000 0003 00 <0:3> <reg:5> (128-bit MSA vector registers)
-
-MIPS FPU control registers (see KVM_REG_MIPS_FCR_{IR,CSR} above) have the
-following id bit patterns:
-  0x7020 0000 0003 01 <0:3> <reg:5>
-
-MIPS MSA control registers (see KVM_REG_MIPS_MSA_{IR,CSR} above) have the
-following id bit patterns:
-  0x7020 0000 0003 02 <0:3> <reg:5>
-
-
-4.69 KVM_GET_ONE_REG
-
-Capability: KVM_CAP_ONE_REG
-Architectures: all
-Type: vcpu ioctl
-Parameters: struct kvm_one_reg (in and out)
-Returns: 0 on success, negative value on failure
-Errors include:
-  ENOENT:   no such register
-  EINVAL:   invalid register ID, or no such register
-  EPERM:    (arm64) register access not allowed before vcpu finalization
-(These error codes are indicative only: do not rely on a specific error
-code being returned in a specific situation.)
-
-This ioctl allows to receive the value of a single register implemented
-in a vcpu. The register to read is indicated by the "id" field of the
-kvm_one_reg struct passed in. On success, the register value can be found
-at the memory location pointed to by "addr".
-
-The list of registers accessible using this interface is identical to the
-list in 4.68.
-
-
-4.70 KVM_KVMCLOCK_CTRL
-
-Capability: KVM_CAP_KVMCLOCK_CTRL
-Architectures: Any that implement pvclocks (currently x86 only)
-Type: vcpu ioctl
-Parameters: None
-Returns: 0 on success, -1 on error
-
-This signals to the host kernel that the specified guest is being paused by
-userspace.  The host will set a flag in the pvclock structure that is checked
-from the soft lockup watchdog.  The flag is part of the pvclock structure that
-is shared between guest and host, specifically the second bit of the flags
-field of the pvclock_vcpu_time_info structure.  It will be set exclusively by
-the host and read/cleared exclusively by the guest.  The guest operation of
-checking and clearing the flag must an atomic operation so
-load-link/store-conditional, or equivalent must be used.  There are two cases
-where the guest will clear the flag: when the soft lockup watchdog timer resets
-itself or when a soft lockup is detected.  This ioctl can be called any time
-after pausing the vcpu, but before it is resumed.
-
-
-4.71 KVM_SIGNAL_MSI
-
-Capability: KVM_CAP_SIGNAL_MSI
-Architectures: x86 arm arm64
-Type: vm ioctl
-Parameters: struct kvm_msi (in)
-Returns: >0 on delivery, 0 if guest blocked the MSI, and -1 on error
-
-Directly inject a MSI message. Only valid with in-kernel irqchip that handles
-MSI messages.
-
-struct kvm_msi {
-       __u32 address_lo;
-       __u32 address_hi;
-       __u32 data;
-       __u32 flags;
-       __u32 devid;
-       __u8  pad[12];
-};
-
-flags: KVM_MSI_VALID_DEVID: devid contains a valid value.  The per-VM
-  KVM_CAP_MSI_DEVID capability advertises the requirement to provide
-  the device ID.  If this capability is not available, userspace
-  should never set the KVM_MSI_VALID_DEVID flag as the ioctl might fail.
-
-If KVM_MSI_VALID_DEVID is set, devid contains a unique device identifier
-for the device that wrote the MSI message.  For PCI, this is usually a
-BFD identifier in the lower 16 bits.
-
-On x86, address_hi is ignored unless the KVM_X2APIC_API_USE_32BIT_IDS
-feature of KVM_CAP_X2APIC_API capability is enabled.  If it is enabled,
-address_hi bits 31-8 provide bits 31-8 of the destination id.  Bits 7-0 of
-address_hi must be zero.
-
-
-4.71 KVM_CREATE_PIT2
-
-Capability: KVM_CAP_PIT2
-Architectures: x86
-Type: vm ioctl
-Parameters: struct kvm_pit_config (in)
-Returns: 0 on success, -1 on error
-
-Creates an in-kernel device model for the i8254 PIT. This call is only valid
-after enabling in-kernel irqchip support via KVM_CREATE_IRQCHIP. The following
-parameters have to be passed:
-
-struct kvm_pit_config {
-       __u32 flags;
-       __u32 pad[15];
-};
-
-Valid flags are:
-
-#define KVM_PIT_SPEAKER_DUMMY     1 /* emulate speaker port stub */
-
-PIT timer interrupts may use a per-VM kernel thread for injection. If it
-exists, this thread will have a name of the following pattern:
-
-kvm-pit/<owner-process-pid>
-
-When running a guest with elevated priorities, the scheduling parameters of
-this thread may have to be adjusted accordingly.
-
-This IOCTL replaces the obsolete KVM_CREATE_PIT.
-
-
-4.72 KVM_GET_PIT2
-
-Capability: KVM_CAP_PIT_STATE2
-Architectures: x86
-Type: vm ioctl
-Parameters: struct kvm_pit_state2 (out)
-Returns: 0 on success, -1 on error
-
-Retrieves the state of the in-kernel PIT model. Only valid after
-KVM_CREATE_PIT2. The state is returned in the following structure:
-
-struct kvm_pit_state2 {
-       struct kvm_pit_channel_state channels[3];
-       __u32 flags;
-       __u32 reserved[9];
-};
-
-Valid flags are:
-
-/* disable PIT in HPET legacy mode */
-#define KVM_PIT_FLAGS_HPET_LEGACY  0x00000001
-
-This IOCTL replaces the obsolete KVM_GET_PIT.
-
-
-4.73 KVM_SET_PIT2
-
-Capability: KVM_CAP_PIT_STATE2
-Architectures: x86
-Type: vm ioctl
-Parameters: struct kvm_pit_state2 (in)
-Returns: 0 on success, -1 on error
-
-Sets the state of the in-kernel PIT model. Only valid after KVM_CREATE_PIT2.
-See KVM_GET_PIT2 for details on struct kvm_pit_state2.
-
-This IOCTL replaces the obsolete KVM_SET_PIT.
-
-
-4.74 KVM_PPC_GET_SMMU_INFO
-
-Capability: KVM_CAP_PPC_GET_SMMU_INFO
-Architectures: powerpc
-Type: vm ioctl
-Parameters: None
-Returns: 0 on success, -1 on error
-
-This populates and returns a structure describing the features of
-the "Server" class MMU emulation supported by KVM.
-This can in turn be used by userspace to generate the appropriate
-device-tree properties for the guest operating system.
-
-The structure contains some global information, followed by an
-array of supported segment page sizes:
-
-      struct kvm_ppc_smmu_info {
-            __u64 flags;
-            __u32 slb_size;
-            __u32 pad;
-            struct kvm_ppc_one_seg_page_size sps[KVM_PPC_PAGE_SIZES_MAX_SZ];
-      };
-
-The supported flags are:
-
-    - KVM_PPC_PAGE_SIZES_REAL:
-        When that flag is set, guest page sizes must "fit" the backing
-        store page sizes. When not set, any page size in the list can
-        be used regardless of how they are backed by userspace.
-
-    - KVM_PPC_1T_SEGMENTS
-        The emulated MMU supports 1T segments in addition to the
-        standard 256M ones.
-
-    - KVM_PPC_NO_HASH
-       This flag indicates that HPT guests are not supported by KVM,
-       thus all guests must use radix MMU mode.
-
-The "slb_size" field indicates how many SLB entries are supported
-
-The "sps" array contains 8 entries indicating the supported base
-page sizes for a segment in increasing order. Each entry is defined
-as follow:
-
-   struct kvm_ppc_one_seg_page_size {
-       __u32 page_shift;       /* Base page shift of segment (or 0) */
-       __u32 slb_enc;          /* SLB encoding for BookS */
-       struct kvm_ppc_one_page_size enc[KVM_PPC_PAGE_SIZES_MAX_SZ];
-   };
-
-An entry with a "page_shift" of 0 is unused. Because the array is
-organized in increasing order, a lookup can stop when encoutering
-such an entry.
-
-The "slb_enc" field provides the encoding to use in the SLB for the
-page size. The bits are in positions such as the value can directly
-be OR'ed into the "vsid" argument of the slbmte instruction.
-
-The "enc" array is a list which for each of those segment base page
-size provides the list of supported actual page sizes (which can be
-only larger or equal to the base page size), along with the
-corresponding encoding in the hash PTE. Similarly, the array is
-8 entries sorted by increasing sizes and an entry with a "0" shift
-is an empty entry and a terminator:
-
-   struct kvm_ppc_one_page_size {
-       __u32 page_shift;       /* Page shift (or 0) */
-       __u32 pte_enc;          /* Encoding in the HPTE (>>12) */
-   };
-
-The "pte_enc" field provides a value that can OR'ed into the hash
-PTE's RPN field (ie, it needs to be shifted left by 12 to OR it
-into the hash PTE second double word).
-
-4.75 KVM_IRQFD
-
-Capability: KVM_CAP_IRQFD
-Architectures: x86 s390 arm arm64
-Type: vm ioctl
-Parameters: struct kvm_irqfd (in)
-Returns: 0 on success, -1 on error
-
-Allows setting an eventfd to directly trigger a guest interrupt.
-kvm_irqfd.fd specifies the file descriptor to use as the eventfd and
-kvm_irqfd.gsi specifies the irqchip pin toggled by this event.  When
-an event is triggered on the eventfd, an interrupt is injected into
-the guest using the specified gsi pin.  The irqfd is removed using
-the KVM_IRQFD_FLAG_DEASSIGN flag, specifying both kvm_irqfd.fd
-and kvm_irqfd.gsi.
-
-With KVM_CAP_IRQFD_RESAMPLE, KVM_IRQFD supports a de-assert and notify
-mechanism allowing emulation of level-triggered, irqfd-based
-interrupts.  When KVM_IRQFD_FLAG_RESAMPLE is set the user must pass an
-additional eventfd in the kvm_irqfd.resamplefd field.  When operating
-in resample mode, posting of an interrupt through kvm_irq.fd asserts
-the specified gsi in the irqchip.  When the irqchip is resampled, such
-as from an EOI, the gsi is de-asserted and the user is notified via
-kvm_irqfd.resamplefd.  It is the user's responsibility to re-queue
-the interrupt if the device making use of it still requires service.
-Note that closing the resamplefd is not sufficient to disable the
-irqfd.  The KVM_IRQFD_FLAG_RESAMPLE is only necessary on assignment
-and need not be specified with KVM_IRQFD_FLAG_DEASSIGN.
-
-On arm/arm64, gsi routing being supported, the following can happen:
-- in case no routing entry is associated to this gsi, injection fails
-- in case the gsi is associated to an irqchip routing entry,
-  irqchip.pin + 32 corresponds to the injected SPI ID.
-- in case the gsi is associated to an MSI routing entry, the MSI
-  message and device ID are translated into an LPI (support restricted
-  to GICv3 ITS in-kernel emulation).
-
-4.76 KVM_PPC_ALLOCATE_HTAB
-
-Capability: KVM_CAP_PPC_ALLOC_HTAB
-Architectures: powerpc
-Type: vm ioctl
-Parameters: Pointer to u32 containing hash table order (in/out)
-Returns: 0 on success, -1 on error
-
-This requests the host kernel to allocate an MMU hash table for a
-guest using the PAPR paravirtualization interface.  This only does
-anything if the kernel is configured to use the Book 3S HV style of
-virtualization.  Otherwise the capability doesn't exist and the ioctl
-returns an ENOTTY error.  The rest of this description assumes Book 3S
-HV.
-
-There must be no vcpus running when this ioctl is called; if there
-are, it will do nothing and return an EBUSY error.
-
-The parameter is a pointer to a 32-bit unsigned integer variable
-containing the order (log base 2) of the desired size of the hash
-table, which must be between 18 and 46.  On successful return from the
-ioctl, the value will not be changed by the kernel.
-
-If no hash table has been allocated when any vcpu is asked to run
-(with the KVM_RUN ioctl), the host kernel will allocate a
-default-sized hash table (16 MB).
-
-If this ioctl is called when a hash table has already been allocated,
-with a different order from the existing hash table, the existing hash
-table will be freed and a new one allocated.  If this is ioctl is
-called when a hash table has already been allocated of the same order
-as specified, the kernel will clear out the existing hash table (zero
-all HPTEs).  In either case, if the guest is using the virtualized
-real-mode area (VRMA) facility, the kernel will re-create the VMRA
-HPTEs on the next KVM_RUN of any vcpu.
-
-4.77 KVM_S390_INTERRUPT
-
-Capability: basic
-Architectures: s390
-Type: vm ioctl, vcpu ioctl
-Parameters: struct kvm_s390_interrupt (in)
-Returns: 0 on success, -1 on error
-
-Allows to inject an interrupt to the guest. Interrupts can be floating
-(vm ioctl) or per cpu (vcpu ioctl), depending on the interrupt type.
-
-Interrupt parameters are passed via kvm_s390_interrupt:
-
-struct kvm_s390_interrupt {
-       __u32 type;
-       __u32 parm;
-       __u64 parm64;
-};
-
-type can be one of the following:
-
-KVM_S390_SIGP_STOP (vcpu) - sigp stop; optional flags in parm
-KVM_S390_PROGRAM_INT (vcpu) - program check; code in parm
-KVM_S390_SIGP_SET_PREFIX (vcpu) - sigp set prefix; prefix address in parm
-KVM_S390_RESTART (vcpu) - restart
-KVM_S390_INT_CLOCK_COMP (vcpu) - clock comparator interrupt
-KVM_S390_INT_CPU_TIMER (vcpu) - CPU timer interrupt
-KVM_S390_INT_VIRTIO (vm) - virtio external interrupt; external interrupt
-                          parameters in parm and parm64
-KVM_S390_INT_SERVICE (vm) - sclp external interrupt; sclp parameter in parm
-KVM_S390_INT_EMERGENCY (vcpu) - sigp emergency; source cpu in parm
-KVM_S390_INT_EXTERNAL_CALL (vcpu) - sigp external call; source cpu in parm
-KVM_S390_INT_IO(ai,cssid,ssid,schid) (vm) - compound value to indicate an
-    I/O interrupt (ai - adapter interrupt; cssid,ssid,schid - subchannel);
-    I/O interruption parameters in parm (subchannel) and parm64 (intparm,
-    interruption subclass)
-KVM_S390_MCHK (vm, vcpu) - machine check interrupt; cr 14 bits in parm,
-                           machine check interrupt code in parm64 (note that
-                           machine checks needing further payload are not
-                           supported by this ioctl)
-
-This is an asynchronous vcpu ioctl and can be invoked from any thread.
-
-4.78 KVM_PPC_GET_HTAB_FD
-
-Capability: KVM_CAP_PPC_HTAB_FD
-Architectures: powerpc
-Type: vm ioctl
-Parameters: Pointer to struct kvm_get_htab_fd (in)
-Returns: file descriptor number (>= 0) on success, -1 on error
-
-This returns a file descriptor that can be used either to read out the
-entries in the guest's hashed page table (HPT), or to write entries to
-initialize the HPT.  The returned fd can only be written to if the
-KVM_GET_HTAB_WRITE bit is set in the flags field of the argument, and
-can only be read if that bit is clear.  The argument struct looks like
-this:
-
-/* For KVM_PPC_GET_HTAB_FD */
-struct kvm_get_htab_fd {
-       __u64   flags;
-       __u64   start_index;
-       __u64   reserved[2];
-};
-
-/* Values for kvm_get_htab_fd.flags */
-#define KVM_GET_HTAB_BOLTED_ONLY       ((__u64)0x1)
-#define KVM_GET_HTAB_WRITE             ((__u64)0x2)
-
-The `start_index' field gives the index in the HPT of the entry at
-which to start reading.  It is ignored when writing.
-
-Reads on the fd will initially supply information about all
-"interesting" HPT entries.  Interesting entries are those with the
-bolted bit set, if the KVM_GET_HTAB_BOLTED_ONLY bit is set, otherwise
-all entries.  When the end of the HPT is reached, the read() will
-return.  If read() is called again on the fd, it will start again from
-the beginning of the HPT, but will only return HPT entries that have
-changed since they were last read.
-
-Data read or written is structured as a header (8 bytes) followed by a
-series of valid HPT entries (16 bytes) each.  The header indicates how
-many valid HPT entries there are and how many invalid entries follow
-the valid entries.  The invalid entries are not represented explicitly
-in the stream.  The header format is:
-
-struct kvm_get_htab_header {
-       __u32   index;
-       __u16   n_valid;
-       __u16   n_invalid;
-};
-
-Writes to the fd create HPT entries starting at the index given in the
-header; first `n_valid' valid entries with contents from the data
-written, then `n_invalid' invalid entries, invalidating any previously
-valid entries found.
-
-4.79 KVM_CREATE_DEVICE
-
-Capability: KVM_CAP_DEVICE_CTRL
-Type: vm ioctl
-Parameters: struct kvm_create_device (in/out)
-Returns: 0 on success, -1 on error
-Errors:
-  ENODEV: The device type is unknown or unsupported
-  EEXIST: Device already created, and this type of device may not
-          be instantiated multiple times
-
-  Other error conditions may be defined by individual device types or
-  have their standard meanings.
-
-Creates an emulated device in the kernel.  The file descriptor returned
-in fd can be used with KVM_SET/GET/HAS_DEVICE_ATTR.
-
-If the KVM_CREATE_DEVICE_TEST flag is set, only test whether the
-device type is supported (not necessarily whether it can be created
-in the current vm).
-
-Individual devices should not define flags.  Attributes should be used
-for specifying any behavior that is not implied by the device type
-number.
-
-struct kvm_create_device {
-       __u32   type;   /* in: KVM_DEV_TYPE_xxx */
-       __u32   fd;     /* out: device handle */
-       __u32   flags;  /* in: KVM_CREATE_DEVICE_xxx */
-};
-
-4.80 KVM_SET_DEVICE_ATTR/KVM_GET_DEVICE_ATTR
-
-Capability: KVM_CAP_DEVICE_CTRL, KVM_CAP_VM_ATTRIBUTES for vm device,
-  KVM_CAP_VCPU_ATTRIBUTES for vcpu device
-Type: device ioctl, vm ioctl, vcpu ioctl
-Parameters: struct kvm_device_attr
-Returns: 0 on success, -1 on error
-Errors:
-  ENXIO:  The group or attribute is unknown/unsupported for this device
-          or hardware support is missing.
-  EPERM:  The attribute cannot (currently) be accessed this way
-          (e.g. read-only attribute, or attribute that only makes
-          sense when the device is in a different state)
-
-  Other error conditions may be defined by individual device types.
-
-Gets/sets a specified piece of device configuration and/or state.  The
-semantics are device-specific.  See individual device documentation in
-the "devices" directory.  As with ONE_REG, the size of the data
-transferred is defined by the particular attribute.
-
-struct kvm_device_attr {
-       __u32   flags;          /* no flags currently defined */
-       __u32   group;          /* device-defined */
-       __u64   attr;           /* group-defined */
-       __u64   addr;           /* userspace address of attr data */
-};
-
-4.81 KVM_HAS_DEVICE_ATTR
-
-Capability: KVM_CAP_DEVICE_CTRL, KVM_CAP_VM_ATTRIBUTES for vm device,
-  KVM_CAP_VCPU_ATTRIBUTES for vcpu device
-Type: device ioctl, vm ioctl, vcpu ioctl
-Parameters: struct kvm_device_attr
-Returns: 0 on success, -1 on error
-Errors:
-  ENXIO:  The group or attribute is unknown/unsupported for this device
-          or hardware support is missing.
-
-Tests whether a device supports a particular attribute.  A successful
-return indicates the attribute is implemented.  It does not necessarily
-indicate that the attribute can be read or written in the device's
-current state.  "addr" is ignored.
-
-4.82 KVM_ARM_VCPU_INIT
-
-Capability: basic
-Architectures: arm, arm64
-Type: vcpu ioctl
-Parameters: struct kvm_vcpu_init (in)
-Returns: 0 on success; -1 on error
-Errors:
-  EINVAL:    the target is unknown, or the combination of features is invalid.
-  ENOENT:    a features bit specified is unknown.
-
-This tells KVM what type of CPU to present to the guest, and what
-optional features it should have.  This will cause a reset of the cpu
-registers to their initial values.  If this is not called, KVM_RUN will
-return ENOEXEC for that vcpu.
-
-Note that because some registers reflect machine topology, all vcpus
-should be created before this ioctl is invoked.
-
-Userspace can call this function multiple times for a given vcpu, including
-after the vcpu has been run. This will reset the vcpu to its initial
-state. All calls to this function after the initial call must use the same
-target and same set of feature flags, otherwise EINVAL will be returned.
-
-Possible features:
-       - KVM_ARM_VCPU_POWER_OFF: Starts the CPU in a power-off state.
-         Depends on KVM_CAP_ARM_PSCI.  If not set, the CPU will be powered on
-         and execute guest code when KVM_RUN is called.
-       - KVM_ARM_VCPU_EL1_32BIT: Starts the CPU in a 32bit mode.
-         Depends on KVM_CAP_ARM_EL1_32BIT (arm64 only).
-       - KVM_ARM_VCPU_PSCI_0_2: Emulate PSCI v0.2 (or a future revision
-          backward compatible with v0.2) for the CPU.
-         Depends on KVM_CAP_ARM_PSCI_0_2.
-       - KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU.
-         Depends on KVM_CAP_ARM_PMU_V3.
-
-       - KVM_ARM_VCPU_PTRAUTH_ADDRESS: Enables Address Pointer authentication
-         for arm64 only.
-         Depends on KVM_CAP_ARM_PTRAUTH_ADDRESS.
-         If KVM_CAP_ARM_PTRAUTH_ADDRESS and KVM_CAP_ARM_PTRAUTH_GENERIC are
-         both present, then both KVM_ARM_VCPU_PTRAUTH_ADDRESS and
-         KVM_ARM_VCPU_PTRAUTH_GENERIC must be requested or neither must be
-         requested.
-
-       - KVM_ARM_VCPU_PTRAUTH_GENERIC: Enables Generic Pointer authentication
-         for arm64 only.
-         Depends on KVM_CAP_ARM_PTRAUTH_GENERIC.
-         If KVM_CAP_ARM_PTRAUTH_ADDRESS and KVM_CAP_ARM_PTRAUTH_GENERIC are
-         both present, then both KVM_ARM_VCPU_PTRAUTH_ADDRESS and
-         KVM_ARM_VCPU_PTRAUTH_GENERIC must be requested or neither must be
-         requested.
-
-       - KVM_ARM_VCPU_SVE: Enables SVE for the CPU (arm64 only).
-         Depends on KVM_CAP_ARM_SVE.
-         Requires KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
-
-          * After KVM_ARM_VCPU_INIT:
-
-             - KVM_REG_ARM64_SVE_VLS may be read using KVM_GET_ONE_REG: the
-               initial value of this pseudo-register indicates the best set of
-               vector lengths possible for a vcpu on this host.
-
-          * Before KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
-
-             - KVM_RUN and KVM_GET_REG_LIST are not available;
-
-             - KVM_GET_ONE_REG and KVM_SET_ONE_REG cannot be used to access
-               the scalable archietctural SVE registers
-               KVM_REG_ARM64_SVE_ZREG(), KVM_REG_ARM64_SVE_PREG() or
-               KVM_REG_ARM64_SVE_FFR;
-
-             - KVM_REG_ARM64_SVE_VLS may optionally be written using
-               KVM_SET_ONE_REG, to modify the set of vector lengths available
-               for the vcpu.
-
-          * After KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
-
-             - the KVM_REG_ARM64_SVE_VLS pseudo-register is immutable, and can
-               no longer be written using KVM_SET_ONE_REG.
-
-4.83 KVM_ARM_PREFERRED_TARGET
-
-Capability: basic
-Architectures: arm, arm64
-Type: vm ioctl
-Parameters: struct struct kvm_vcpu_init (out)
-Returns: 0 on success; -1 on error
-Errors:
-  ENODEV:    no preferred target available for the host
-
-This queries KVM for preferred CPU target type which can be emulated
-by KVM on underlying host.
-
-The ioctl returns struct kvm_vcpu_init instance containing information
-about preferred CPU target type and recommended features for it.  The
-kvm_vcpu_init->features bitmap returned will have feature bits set if
-the preferred target recommends setting these features, but this is
-not mandatory.
-
-The information returned by this ioctl can be used to prepare an instance
-of struct kvm_vcpu_init for KVM_ARM_VCPU_INIT ioctl which will result in
-in VCPU matching underlying host.
-
-
-4.84 KVM_GET_REG_LIST
-
-Capability: basic
-Architectures: arm, arm64, mips
-Type: vcpu ioctl
-Parameters: struct kvm_reg_list (in/out)
-Returns: 0 on success; -1 on error
-Errors:
-  E2BIG:     the reg index list is too big to fit in the array specified by
-             the user (the number required will be written into n).
-
-struct kvm_reg_list {
-       __u64 n; /* number of registers in reg[] */
-       __u64 reg[0];
-};
-
-This ioctl returns the guest registers that are supported for the
-KVM_GET_ONE_REG/KVM_SET_ONE_REG calls.
-
-
-4.85 KVM_ARM_SET_DEVICE_ADDR (deprecated)
-
-Capability: KVM_CAP_ARM_SET_DEVICE_ADDR
-Architectures: arm, arm64
-Type: vm ioctl
-Parameters: struct kvm_arm_device_address (in)
-Returns: 0 on success, -1 on error
-Errors:
-  ENODEV: The device id is unknown
-  ENXIO:  Device not supported on current system
-  EEXIST: Address already set
-  E2BIG:  Address outside guest physical address space
-  EBUSY:  Address overlaps with other device range
-
-struct kvm_arm_device_addr {
-       __u64 id;
-       __u64 addr;
-};
-
-Specify a device address in the guest's physical address space where guests
-can access emulated or directly exposed devices, which the host kernel needs
-to know about. The id field is an architecture specific identifier for a
-specific device.
-
-ARM/arm64 divides the id field into two parts, a device id and an
-address type id specific to the individual device.
-
-  bits:  | 63        ...       32 | 31    ...    16 | 15    ...    0 |
-  field: |        0x00000000      |     device id   |  addr type id  |
-
-ARM/arm64 currently only require this when using the in-kernel GIC
-support for the hardware VGIC features, using KVM_ARM_DEVICE_VGIC_V2
-as the device id.  When setting the base address for the guest's
-mapping of the VGIC virtual CPU and distributor interface, the ioctl
-must be called after calling KVM_CREATE_IRQCHIP, but before calling
-KVM_RUN on any of the VCPUs.  Calling this ioctl twice for any of the
-base addresses will return -EEXIST.
-
-Note, this IOCTL is deprecated and the more flexible SET/GET_DEVICE_ATTR API
-should be used instead.
-
-
-4.86 KVM_PPC_RTAS_DEFINE_TOKEN
-
-Capability: KVM_CAP_PPC_RTAS
-Architectures: ppc
-Type: vm ioctl
-Parameters: struct kvm_rtas_token_args
-Returns: 0 on success, -1 on error
-
-Defines a token value for a RTAS (Run Time Abstraction Services)
-service in order to allow it to be handled in the kernel.  The
-argument struct gives the name of the service, which must be the name
-of a service that has a kernel-side implementation.  If the token
-value is non-zero, it will be associated with that service, and
-subsequent RTAS calls by the guest specifying that token will be
-handled by the kernel.  If the token value is 0, then any token
-associated with the service will be forgotten, and subsequent RTAS
-calls by the guest for that service will be passed to userspace to be
-handled.
-
-4.87 KVM_SET_GUEST_DEBUG
-
-Capability: KVM_CAP_SET_GUEST_DEBUG
-Architectures: x86, s390, ppc, arm64
-Type: vcpu ioctl
-Parameters: struct kvm_guest_debug (in)
-Returns: 0 on success; -1 on error
-
-struct kvm_guest_debug {
-       __u32 control;
-       __u32 pad;
-       struct kvm_guest_debug_arch arch;
-};
-
-Set up the processor specific debug registers and configure vcpu for
-handling guest debug events. There are two parts to the structure, the
-first a control bitfield indicates the type of debug events to handle
-when running. Common control bits are:
-
-  - KVM_GUESTDBG_ENABLE:        guest debugging is enabled
-  - KVM_GUESTDBG_SINGLESTEP:    the next run should single-step
-
-The top 16 bits of the control field are architecture specific control
-flags which can include the following:
-
-  - KVM_GUESTDBG_USE_SW_BP:     using software breakpoints [x86, arm64]
-  - KVM_GUESTDBG_USE_HW_BP:     using hardware breakpoints [x86, s390, arm64]
-  - KVM_GUESTDBG_INJECT_DB:     inject DB type exception [x86]
-  - KVM_GUESTDBG_INJECT_BP:     inject BP type exception [x86]
-  - KVM_GUESTDBG_EXIT_PENDING:  trigger an immediate guest exit [s390]
-
-For example KVM_GUESTDBG_USE_SW_BP indicates that software breakpoints
-are enabled in memory so we need to ensure breakpoint exceptions are
-correctly trapped and the KVM run loop exits at the breakpoint and not
-running off into the normal guest vector. For KVM_GUESTDBG_USE_HW_BP
-we need to ensure the guest vCPUs architecture specific registers are
-updated to the correct (supplied) values.
-
-The second part of the structure is architecture specific and
-typically contains a set of debug registers.
-
-For arm64 the number of debug registers is implementation defined and
-can be determined by querying the KVM_CAP_GUEST_DEBUG_HW_BPS and
-KVM_CAP_GUEST_DEBUG_HW_WPS capabilities which return a positive number
-indicating the number of supported registers.
-
-When debug events exit the main run loop with the reason
-KVM_EXIT_DEBUG with the kvm_debug_exit_arch part of the kvm_run
-structure containing architecture specific debug information.
-
-4.88 KVM_GET_EMULATED_CPUID
-
-Capability: KVM_CAP_EXT_EMUL_CPUID
-Architectures: x86
-Type: system ioctl
-Parameters: struct kvm_cpuid2 (in/out)
-Returns: 0 on success, -1 on error
-
-struct kvm_cpuid2 {
-       __u32 nent;
-       __u32 flags;
-       struct kvm_cpuid_entry2 entries[0];
-};
-
-The member 'flags' is used for passing flags from userspace.
-
-#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX                BIT(0)
-#define KVM_CPUID_FLAG_STATEFUL_FUNC           BIT(1)
-#define KVM_CPUID_FLAG_STATE_READ_NEXT         BIT(2)
-
-struct kvm_cpuid_entry2 {
-       __u32 function;
-       __u32 index;
-       __u32 flags;
-       __u32 eax;
-       __u32 ebx;
-       __u32 ecx;
-       __u32 edx;
-       __u32 padding[3];
-};
-
-This ioctl returns x86 cpuid features which are emulated by
-kvm.Userspace can use the information returned by this ioctl to query
-which features are emulated by kvm instead of being present natively.
-
-Userspace invokes KVM_GET_EMULATED_CPUID by passing a kvm_cpuid2
-structure with the 'nent' field indicating the number of entries in
-the variable-size array 'entries'. If the number of entries is too low
-to describe the cpu capabilities, an error (E2BIG) is returned. If the
-number is too high, the 'nent' field is adjusted and an error (ENOMEM)
-is returned. If the number is just right, the 'nent' field is adjusted
-to the number of valid entries in the 'entries' array, which is then
-filled.
-
-The entries returned are the set CPUID bits of the respective features
-which kvm emulates, as returned by the CPUID instruction, with unknown
-or unsupported feature bits cleared.
-
-Features like x2apic, for example, may not be present in the host cpu
-but are exposed by kvm in KVM_GET_SUPPORTED_CPUID because they can be
-emulated efficiently and thus not included here.
-
-The fields in each entry are defined as follows:
-
-  function: the eax value used to obtain the entry
-  index: the ecx value used to obtain the entry (for entries that are
-         affected by ecx)
-  flags: an OR of zero or more of the following:
-        KVM_CPUID_FLAG_SIGNIFCANT_INDEX:
-           if the index field is valid
-        KVM_CPUID_FLAG_STATEFUL_FUNC:
-           if cpuid for this function returns different values for successive
-           invocations; there will be several entries with the same function,
-           all with this flag set
-        KVM_CPUID_FLAG_STATE_READ_NEXT:
-           for KVM_CPUID_FLAG_STATEFUL_FUNC entries, set if this entry is
-           the first entry to be read by a cpu
-   eax, ebx, ecx, edx: the values returned by the cpuid instruction for
-         this function/index combination
-
-4.89 KVM_S390_MEM_OP
-
-Capability: KVM_CAP_S390_MEM_OP
-Architectures: s390
-Type: vcpu ioctl
-Parameters: struct kvm_s390_mem_op (in)
-Returns: = 0 on success,
-         < 0 on generic error (e.g. -EFAULT or -ENOMEM),
-         > 0 if an exception occurred while walking the page tables
-
-Read or write data from/to the logical (virtual) memory of a VCPU.
-
-Parameters are specified via the following structure:
-
-struct kvm_s390_mem_op {
-       __u64 gaddr;            /* the guest address */
-       __u64 flags;            /* flags */
-       __u32 size;             /* amount of bytes */
-       __u32 op;               /* type of operation */
-       __u64 buf;              /* buffer in userspace */
-       __u8 ar;                /* the access register number */
-       __u8 reserved[31];      /* should be set to 0 */
-};
-
-The type of operation is specified in the "op" field. It is either
-KVM_S390_MEMOP_LOGICAL_READ for reading from logical memory space or
-KVM_S390_MEMOP_LOGICAL_WRITE for writing to logical memory space. The
-KVM_S390_MEMOP_F_CHECK_ONLY flag can be set in the "flags" field to check
-whether the corresponding memory access would create an access exception
-(without touching the data in the memory at the destination). In case an
-access exception occurred while walking the MMU tables of the guest, the
-ioctl returns a positive error number to indicate the type of exception.
-This exception is also raised directly at the corresponding VCPU if the
-flag KVM_S390_MEMOP_F_INJECT_EXCEPTION is set in the "flags" field.
-
-The start address of the memory region has to be specified in the "gaddr"
-field, and the length of the region in the "size" field. "buf" is the buffer
-supplied by the userspace application where the read data should be written
-to for KVM_S390_MEMOP_LOGICAL_READ, or where the data that should be written
-is stored for a KVM_S390_MEMOP_LOGICAL_WRITE. "buf" is unused and can be NULL
-when KVM_S390_MEMOP_F_CHECK_ONLY is specified. "ar" designates the access
-register number to be used.
-
-The "reserved" field is meant for future extensions. It is not used by
-KVM with the currently defined set of flags.
-
-4.90 KVM_S390_GET_SKEYS
-
-Capability: KVM_CAP_S390_SKEYS
-Architectures: s390
-Type: vm ioctl
-Parameters: struct kvm_s390_skeys
-Returns: 0 on success, KVM_S390_GET_KEYS_NONE if guest is not using storage
-         keys, negative value on error
-
-This ioctl is used to get guest storage key values on the s390
-architecture. The ioctl takes parameters via the kvm_s390_skeys struct.
-
-struct kvm_s390_skeys {
-       __u64 start_gfn;
-       __u64 count;
-       __u64 skeydata_addr;
-       __u32 flags;
-       __u32 reserved[9];
-};
-
-The start_gfn field is the number of the first guest frame whose storage keys
-you want to get.
-
-The count field is the number of consecutive frames (starting from start_gfn)
-whose storage keys to get. The count field must be at least 1 and the maximum
-allowed value is defined as KVM_S390_SKEYS_ALLOC_MAX. Values outside this range
-will cause the ioctl to return -EINVAL.
-
-The skeydata_addr field is the address to a buffer large enough to hold count
-bytes. This buffer will be filled with storage key data by the ioctl.
-
-4.91 KVM_S390_SET_SKEYS
-
-Capability: KVM_CAP_S390_SKEYS
-Architectures: s390
-Type: vm ioctl
-Parameters: struct kvm_s390_skeys
-Returns: 0 on success, negative value on error
-
-This ioctl is used to set guest storage key values on the s390
-architecture. The ioctl takes parameters via the kvm_s390_skeys struct.
-See section on KVM_S390_GET_SKEYS for struct definition.
-
-The start_gfn field is the number of the first guest frame whose storage keys
-you want to set.
-
-The count field is the number of consecutive frames (starting from start_gfn)
-whose storage keys to get. The count field must be at least 1 and the maximum
-allowed value is defined as KVM_S390_SKEYS_ALLOC_MAX. Values outside this range
-will cause the ioctl to return -EINVAL.
-
-The skeydata_addr field is the address to a buffer containing count bytes of
-storage keys. Each byte in the buffer will be set as the storage key for a
-single frame starting at start_gfn for count frames.
-
-Note: If any architecturally invalid key value is found in the given data then
-the ioctl will return -EINVAL.
-
-4.92 KVM_S390_IRQ
-
-Capability: KVM_CAP_S390_INJECT_IRQ
-Architectures: s390
-Type: vcpu ioctl
-Parameters: struct kvm_s390_irq (in)
-Returns: 0 on success, -1 on error
-Errors:
-  EINVAL: interrupt type is invalid
-          type is KVM_S390_SIGP_STOP and flag parameter is invalid value
-          type is KVM_S390_INT_EXTERNAL_CALL and code is bigger
-            than the maximum of VCPUs
-  EBUSY:  type is KVM_S390_SIGP_SET_PREFIX and vcpu is not stopped
-          type is KVM_S390_SIGP_STOP and a stop irq is already pending
-          type is KVM_S390_INT_EXTERNAL_CALL and an external call interrupt
-            is already pending
-
-Allows to inject an interrupt to the guest.
-
-Using struct kvm_s390_irq as a parameter allows
-to inject additional payload which is not
-possible via KVM_S390_INTERRUPT.
-
-Interrupt parameters are passed via kvm_s390_irq:
-
-struct kvm_s390_irq {
-       __u64 type;
-       union {
-               struct kvm_s390_io_info io;
-               struct kvm_s390_ext_info ext;
-               struct kvm_s390_pgm_info pgm;
-               struct kvm_s390_emerg_info emerg;
-               struct kvm_s390_extcall_info extcall;
-               struct kvm_s390_prefix_info prefix;
-               struct kvm_s390_stop_info stop;
-               struct kvm_s390_mchk_info mchk;
-               char reserved[64];
-       } u;
-};
-
-type can be one of the following:
-
-KVM_S390_SIGP_STOP - sigp stop; parameter in .stop
-KVM_S390_PROGRAM_INT - program check; parameters in .pgm
-KVM_S390_SIGP_SET_PREFIX - sigp set prefix; parameters in .prefix
-KVM_S390_RESTART - restart; no parameters
-KVM_S390_INT_CLOCK_COMP - clock comparator interrupt; no parameters
-KVM_S390_INT_CPU_TIMER - CPU timer interrupt; no parameters
-KVM_S390_INT_EMERGENCY - sigp emergency; parameters in .emerg
-KVM_S390_INT_EXTERNAL_CALL - sigp external call; parameters in .extcall
-KVM_S390_MCHK - machine check interrupt; parameters in .mchk
-
-This is an asynchronous vcpu ioctl and can be invoked from any thread.
-
-4.94 KVM_S390_GET_IRQ_STATE
-
-Capability: KVM_CAP_S390_IRQ_STATE
-Architectures: s390
-Type: vcpu ioctl
-Parameters: struct kvm_s390_irq_state (out)
-Returns: >= number of bytes copied into buffer,
-         -EINVAL if buffer size is 0,
-         -ENOBUFS if buffer size is too small to fit all pending interrupts,
-         -EFAULT if the buffer address was invalid
-
-This ioctl allows userspace to retrieve the complete state of all currently
-pending interrupts in a single buffer. Use cases include migration
-and introspection. The parameter structure contains the address of a
-userspace buffer and its length:
-
-struct kvm_s390_irq_state {
-       __u64 buf;
-       __u32 flags;        /* will stay unused for compatibility reasons */
-       __u32 len;
-       __u32 reserved[4];  /* will stay unused for compatibility reasons */
-};
-
-Userspace passes in the above struct and for each pending interrupt a
-struct kvm_s390_irq is copied to the provided buffer.
-
-The structure contains a flags and a reserved field for future extensions. As
-the kernel never checked for flags == 0 and QEMU never pre-zeroed flags and
-reserved, these fields can not be used in the future without breaking
-compatibility.
-
-If -ENOBUFS is returned the buffer provided was too small and userspace
-may retry with a bigger buffer.
-
-4.95 KVM_S390_SET_IRQ_STATE
-
-Capability: KVM_CAP_S390_IRQ_STATE
-Architectures: s390
-Type: vcpu ioctl
-Parameters: struct kvm_s390_irq_state (in)
-Returns: 0 on success,
-         -EFAULT if the buffer address was invalid,
-         -EINVAL for an invalid buffer length (see below),
-         -EBUSY if there were already interrupts pending,
-         errors occurring when actually injecting the
-          interrupt. See KVM_S390_IRQ.
-
-This ioctl allows userspace to set the complete state of all cpu-local
-interrupts currently pending for the vcpu. It is intended for restoring
-interrupt state after a migration. The input parameter is a userspace buffer
-containing a struct kvm_s390_irq_state:
-
-struct kvm_s390_irq_state {
-       __u64 buf;
-       __u32 flags;        /* will stay unused for compatibility reasons */
-       __u32 len;
-       __u32 reserved[4];  /* will stay unused for compatibility reasons */
-};
-
-The restrictions for flags and reserved apply as well.
-(see KVM_S390_GET_IRQ_STATE)
-
-The userspace memory referenced by buf contains a struct kvm_s390_irq
-for each interrupt to be injected into the guest.
-If one of the interrupts could not be injected for some reason the
-ioctl aborts.
-
-len must be a multiple of sizeof(struct kvm_s390_irq). It must be > 0
-and it must not exceed (max_vcpus + 32) * sizeof(struct kvm_s390_irq),
-which is the maximum number of possibly pending cpu-local interrupts.
-
-4.96 KVM_SMI
-
-Capability: KVM_CAP_X86_SMM
-Architectures: x86
-Type: vcpu ioctl
-Parameters: none
-Returns: 0 on success, -1 on error
-
-Queues an SMI on the thread's vcpu.
-
-4.97 KVM_CAP_PPC_MULTITCE
-
-Capability: KVM_CAP_PPC_MULTITCE
-Architectures: ppc
-Type: vm
-
-This capability means the kernel is capable of handling hypercalls
-H_PUT_TCE_INDIRECT and H_STUFF_TCE without passing those into the user
-space. This significantly accelerates DMA operations for PPC KVM guests.
-User space should expect that its handlers for these hypercalls
-are not going to be called if user space previously registered LIOBN
-in KVM (via KVM_CREATE_SPAPR_TCE or similar calls).
-
-In order to enable H_PUT_TCE_INDIRECT and H_STUFF_TCE use in the guest,
-user space might have to advertise it for the guest. For example,
-IBM pSeries (sPAPR) guest starts using them if "hcall-multi-tce" is
-present in the "ibm,hypertas-functions" device-tree property.
-
-The hypercalls mentioned above may or may not be processed successfully
-in the kernel based fast path. If they can not be handled by the kernel,
-they will get passed on to user space. So user space still has to have
-an implementation for these despite the in kernel acceleration.
-
-This capability is always enabled.
-
-4.98 KVM_CREATE_SPAPR_TCE_64
-
-Capability: KVM_CAP_SPAPR_TCE_64
-Architectures: powerpc
-Type: vm ioctl
-Parameters: struct kvm_create_spapr_tce_64 (in)
-Returns: file descriptor for manipulating the created TCE table
-
-This is an extension for KVM_CAP_SPAPR_TCE which only supports 32bit
-windows, described in 4.62 KVM_CREATE_SPAPR_TCE
-
-This capability uses extended struct in ioctl interface:
-
-/* for KVM_CAP_SPAPR_TCE_64 */
-struct kvm_create_spapr_tce_64 {
-       __u64 liobn;
-       __u32 page_shift;
-       __u32 flags;
-       __u64 offset;   /* in pages */
-       __u64 size;     /* in pages */
-};
-
-The aim of extension is to support an additional bigger DMA window with
-a variable page size.
-KVM_CREATE_SPAPR_TCE_64 receives a 64bit window size, an IOMMU page shift and
-a bus offset of the corresponding DMA window, @size and @offset are numbers
-of IOMMU pages.
-
-@flags are not used at the moment.
-
-The rest of functionality is identical to KVM_CREATE_SPAPR_TCE.
-
-4.99 KVM_REINJECT_CONTROL
-
-Capability: KVM_CAP_REINJECT_CONTROL
-Architectures: x86
-Type: vm ioctl
-Parameters: struct kvm_reinject_control (in)
-Returns: 0 on success,
-         -EFAULT if struct kvm_reinject_control cannot be read,
-         -ENXIO if KVM_CREATE_PIT or KVM_CREATE_PIT2 didn't succeed earlier.
-
-i8254 (PIT) has two modes, reinject and !reinject.  The default is reinject,
-where KVM queues elapsed i8254 ticks and monitors completion of interrupt from
-vector(s) that i8254 injects.  Reinject mode dequeues a tick and injects its
-interrupt whenever there isn't a pending interrupt from i8254.
-!reinject mode injects an interrupt as soon as a tick arrives.
-
-struct kvm_reinject_control {
-       __u8 pit_reinject;
-       __u8 reserved[31];
-};
-
-pit_reinject = 0 (!reinject mode) is recommended, unless running an old
-operating system that uses the PIT for timing (e.g. Linux 2.4.x).
-
-4.100 KVM_PPC_CONFIGURE_V3_MMU
-
-Capability: KVM_CAP_PPC_RADIX_MMU or KVM_CAP_PPC_HASH_MMU_V3
-Architectures: ppc
-Type: vm ioctl
-Parameters: struct kvm_ppc_mmuv3_cfg (in)
-Returns: 0 on success,
-         -EFAULT if struct kvm_ppc_mmuv3_cfg cannot be read,
-         -EINVAL if the configuration is invalid
-
-This ioctl controls whether the guest will use radix or HPT (hashed
-page table) translation, and sets the pointer to the process table for
-the guest.
-
-struct kvm_ppc_mmuv3_cfg {
-       __u64   flags;
-       __u64   process_table;
-};
-
-There are two bits that can be set in flags; KVM_PPC_MMUV3_RADIX and
-KVM_PPC_MMUV3_GTSE.  KVM_PPC_MMUV3_RADIX, if set, configures the guest
-to use radix tree translation, and if clear, to use HPT translation.
-KVM_PPC_MMUV3_GTSE, if set and if KVM permits it, configures the guest
-to be able to use the global TLB and SLB invalidation instructions;
-if clear, the guest may not use these instructions.
-
-The process_table field specifies the address and size of the guest
-process table, which is in the guest's space.  This field is formatted
-as the second doubleword of the partition table entry, as defined in
-the Power ISA V3.00, Book III section 5.7.6.1.
-
-4.101 KVM_PPC_GET_RMMU_INFO
-
-Capability: KVM_CAP_PPC_RADIX_MMU
-Architectures: ppc
-Type: vm ioctl
-Parameters: struct kvm_ppc_rmmu_info (out)
-Returns: 0 on success,
-        -EFAULT if struct kvm_ppc_rmmu_info cannot be written,
-        -EINVAL if no useful information can be returned
-
-This ioctl returns a structure containing two things: (a) a list
-containing supported radix tree geometries, and (b) a list that maps
-page sizes to put in the "AP" (actual page size) field for the tlbie
-(TLB invalidate entry) instruction.
-
-struct kvm_ppc_rmmu_info {
-       struct kvm_ppc_radix_geom {
-               __u8    page_shift;
-               __u8    level_bits[4];
-               __u8    pad[3];
-       }       geometries[8];
-       __u32   ap_encodings[8];
-};
-
-The geometries[] field gives up to 8 supported geometries for the
-radix page table, in terms of the log base 2 of the smallest page
-size, and the number of bits indexed at each level of the tree, from
-the PTE level up to the PGD level in that order.  Any unused entries
-will have 0 in the page_shift field.
-
-The ap_encodings gives the supported page sizes and their AP field
-encodings, encoded with the AP value in the top 3 bits and the log
-base 2 of the page size in the bottom 6 bits.
-
-4.102 KVM_PPC_RESIZE_HPT_PREPARE
-
-Capability: KVM_CAP_SPAPR_RESIZE_HPT
-Architectures: powerpc
-Type: vm ioctl
-Parameters: struct kvm_ppc_resize_hpt (in)
-Returns: 0 on successful completion,
-        >0 if a new HPT is being prepared, the value is an estimated
-             number of milliseconds until preparation is complete
-         -EFAULT if struct kvm_reinject_control cannot be read,
-        -EINVAL if the supplied shift or flags are invalid
-        -ENOMEM if unable to allocate the new HPT
-        -ENOSPC if there was a hash collision when moving existing
-                  HPT entries to the new HPT
-        -EIO on other error conditions
-
-Used to implement the PAPR extension for runtime resizing of a guest's
-Hashed Page Table (HPT).  Specifically this starts, stops or monitors
-the preparation of a new potential HPT for the guest, essentially
-implementing the H_RESIZE_HPT_PREPARE hypercall.
-
-If called with shift > 0 when there is no pending HPT for the guest,
-this begins preparation of a new pending HPT of size 2^(shift) bytes.
-It then returns a positive integer with the estimated number of
-milliseconds until preparation is complete.
-
-If called when there is a pending HPT whose size does not match that
-requested in the parameters, discards the existing pending HPT and
-creates a new one as above.
-
-If called when there is a pending HPT of the size requested, will:
-  * If preparation of the pending HPT is already complete, return 0
-  * If preparation of the pending HPT has failed, return an error
-    code, then discard the pending HPT.
-  * If preparation of the pending HPT is still in progress, return an
-    estimated number of milliseconds until preparation is complete.
-
-If called with shift == 0, discards any currently pending HPT and
-returns 0 (i.e. cancels any in-progress preparation).
-
-flags is reserved for future expansion, currently setting any bits in
-flags will result in an -EINVAL.
-
-Normally this will be called repeatedly with the same parameters until
-it returns <= 0.  The first call will initiate preparation, subsequent
-ones will monitor preparation until it completes or fails.
-
-struct kvm_ppc_resize_hpt {
-       __u64 flags;
-       __u32 shift;
-       __u32 pad;
-};
-
-4.103 KVM_PPC_RESIZE_HPT_COMMIT
-
-Capability: KVM_CAP_SPAPR_RESIZE_HPT
-Architectures: powerpc
-Type: vm ioctl
-Parameters: struct kvm_ppc_resize_hpt (in)
-Returns: 0 on successful completion,
-         -EFAULT if struct kvm_reinject_control cannot be read,
-        -EINVAL if the supplied shift or flags are invalid
-        -ENXIO is there is no pending HPT, or the pending HPT doesn't
-                 have the requested size
-        -EBUSY if the pending HPT is not fully prepared
-        -ENOSPC if there was a hash collision when moving existing
-                  HPT entries to the new HPT
-        -EIO on other error conditions
-
-Used to implement the PAPR extension for runtime resizing of a guest's
-Hashed Page Table (HPT).  Specifically this requests that the guest be
-transferred to working with the new HPT, essentially implementing the
-H_RESIZE_HPT_COMMIT hypercall.
-
-This should only be called after KVM_PPC_RESIZE_HPT_PREPARE has
-returned 0 with the same parameters.  In other cases
-KVM_PPC_RESIZE_HPT_COMMIT will return an error (usually -ENXIO or
--EBUSY, though others may be possible if the preparation was started,
-but failed).
-
-This will have undefined effects on the guest if it has not already
-placed itself in a quiescent state where no vcpu will make MMU enabled
-memory accesses.
-
-On succsful completion, the pending HPT will become the guest's active
-HPT and the previous HPT will be discarded.
-
-On failure, the guest will still be operating on its previous HPT.
-
-struct kvm_ppc_resize_hpt {
-       __u64 flags;
-       __u32 shift;
-       __u32 pad;
-};
-
-4.104 KVM_X86_GET_MCE_CAP_SUPPORTED
-
-Capability: KVM_CAP_MCE
-Architectures: x86
-Type: system ioctl
-Parameters: u64 mce_cap (out)
-Returns: 0 on success, -1 on error
-
-Returns supported MCE capabilities. The u64 mce_cap parameter
-has the same format as the MSR_IA32_MCG_CAP register. Supported
-capabilities will have the corresponding bits set.
-
-4.105 KVM_X86_SETUP_MCE
-
-Capability: KVM_CAP_MCE
-Architectures: x86
-Type: vcpu ioctl
-Parameters: u64 mcg_cap (in)
-Returns: 0 on success,
-         -EFAULT if u64 mcg_cap cannot be read,
-         -EINVAL if the requested number of banks is invalid,
-         -EINVAL if requested MCE capability is not supported.
-
-Initializes MCE support for use. The u64 mcg_cap parameter
-has the same format as the MSR_IA32_MCG_CAP register and
-specifies which capabilities should be enabled. The maximum
-supported number of error-reporting banks can be retrieved when
-checking for KVM_CAP_MCE. The supported capabilities can be
-retrieved with KVM_X86_GET_MCE_CAP_SUPPORTED.
-
-4.106 KVM_X86_SET_MCE
-
-Capability: KVM_CAP_MCE
-Architectures: x86
-Type: vcpu ioctl
-Parameters: struct kvm_x86_mce (in)
-Returns: 0 on success,
-         -EFAULT if struct kvm_x86_mce cannot be read,
-         -EINVAL if the bank number is invalid,
-         -EINVAL if VAL bit is not set in status field.
-
-Inject a machine check error (MCE) into the guest. The input
-parameter is:
-
-struct kvm_x86_mce {
-       __u64 status;
-       __u64 addr;
-       __u64 misc;
-       __u64 mcg_status;
-       __u8 bank;
-       __u8 pad1[7];
-       __u64 pad2[3];
-};
-
-If the MCE being reported is an uncorrected error, KVM will
-inject it as an MCE exception into the guest. If the guest
-MCG_STATUS register reports that an MCE is in progress, KVM
-causes an KVM_EXIT_SHUTDOWN vmexit.
-
-Otherwise, if the MCE is a corrected error, KVM will just
-store it in the corresponding bank (provided this bank is
-not holding a previously reported uncorrected error).
-
-4.107 KVM_S390_GET_CMMA_BITS
-
-Capability: KVM_CAP_S390_CMMA_MIGRATION
-Architectures: s390
-Type: vm ioctl
-Parameters: struct kvm_s390_cmma_log (in, out)
-Returns: 0 on success, a negative value on error
-
-This ioctl is used to get the values of the CMMA bits on the s390
-architecture. It is meant to be used in two scenarios:
-- During live migration to save the CMMA values. Live migration needs
-  to be enabled via the KVM_REQ_START_MIGRATION VM property.
-- To non-destructively peek at the CMMA values, with the flag
-  KVM_S390_CMMA_PEEK set.
-
-The ioctl takes parameters via the kvm_s390_cmma_log struct. The desired
-values are written to a buffer whose location is indicated via the "values"
-member in the kvm_s390_cmma_log struct.  The values in the input struct are
-also updated as needed.
-Each CMMA value takes up one byte.
-
-struct kvm_s390_cmma_log {
-       __u64 start_gfn;
-       __u32 count;
-       __u32 flags;
-       union {
-               __u64 remaining;
-               __u64 mask;
-       };
-       __u64 values;
-};
-
-start_gfn is the number of the first guest frame whose CMMA values are
-to be retrieved,
-
-count is the length of the buffer in bytes,
-
-values points to the buffer where the result will be written to.
-
-If count is greater than KVM_S390_SKEYS_MAX, then it is considered to be
-KVM_S390_SKEYS_MAX. KVM_S390_SKEYS_MAX is re-used for consistency with
-other ioctls.
-
-The result is written in the buffer pointed to by the field values, and
-the values of the input parameter are updated as follows.
-
-Depending on the flags, different actions are performed. The only
-supported flag so far is KVM_S390_CMMA_PEEK.
-
-The default behaviour if KVM_S390_CMMA_PEEK is not set is:
-start_gfn will indicate the first page frame whose CMMA bits were dirty.
-It is not necessarily the same as the one passed as input, as clean pages
-are skipped.
-
-count will indicate the number of bytes actually written in the buffer.
-It can (and very often will) be smaller than the input value, since the
-buffer is only filled until 16 bytes of clean values are found (which
-are then not copied in the buffer). Since a CMMA migration block needs
-the base address and the length, for a total of 16 bytes, we will send
-back some clean data if there is some dirty data afterwards, as long as
-the size of the clean data does not exceed the size of the header. This
-allows to minimize the amount of data to be saved or transferred over
-the network at the expense of more roundtrips to userspace. The next
-invocation of the ioctl will skip over all the clean values, saving
-potentially more than just the 16 bytes we found.
-
-If KVM_S390_CMMA_PEEK is set:
-the existing storage attributes are read even when not in migration
-mode, and no other action is performed;
-
-the output start_gfn will be equal to the input start_gfn,
-
-the output count will be equal to the input count, except if the end of
-memory has been reached.
-
-In both cases:
-the field "remaining" will indicate the total number of dirty CMMA values
-still remaining, or 0 if KVM_S390_CMMA_PEEK is set and migration mode is
-not enabled.
-
-mask is unused.
-
-values points to the userspace buffer where the result will be stored.
-
-This ioctl can fail with -ENOMEM if not enough memory can be allocated to
-complete the task, with -ENXIO if CMMA is not enabled, with -EINVAL if
-KVM_S390_CMMA_PEEK is not set but migration mode was not enabled, with
--EFAULT if the userspace address is invalid or if no page table is
-present for the addresses (e.g. when using hugepages).
-
-4.108 KVM_S390_SET_CMMA_BITS
-
-Capability: KVM_CAP_S390_CMMA_MIGRATION
-Architectures: s390
-Type: vm ioctl
-Parameters: struct kvm_s390_cmma_log (in)
-Returns: 0 on success, a negative value on error
-
-This ioctl is used to set the values of the CMMA bits on the s390
-architecture. It is meant to be used during live migration to restore
-the CMMA values, but there are no restrictions on its use.
-The ioctl takes parameters via the kvm_s390_cmma_values struct.
-Each CMMA value takes up one byte.
-
-struct kvm_s390_cmma_log {
-       __u64 start_gfn;
-       __u32 count;
-       __u32 flags;
-       union {
-               __u64 remaining;
-               __u64 mask;
-       };
-       __u64 values;
-};
-
-start_gfn indicates the starting guest frame number,
-
-count indicates how many values are to be considered in the buffer,
-
-flags is not used and must be 0.
-
-mask indicates which PGSTE bits are to be considered.
-
-remaining is not used.
-
-values points to the buffer in userspace where to store the values.
-
-This ioctl can fail with -ENOMEM if not enough memory can be allocated to
-complete the task, with -ENXIO if CMMA is not enabled, with -EINVAL if
-the count field is too large (e.g. more than KVM_S390_CMMA_SIZE_MAX) or
-if the flags field was not 0, with -EFAULT if the userspace address is
-invalid, if invalid pages are written to (e.g. after the end of memory)
-or if no page table is present for the addresses (e.g. when using
-hugepages).
-
-4.109 KVM_PPC_GET_CPU_CHAR
-
-Capability: KVM_CAP_PPC_GET_CPU_CHAR
-Architectures: powerpc
-Type: vm ioctl
-Parameters: struct kvm_ppc_cpu_char (out)
-Returns: 0 on successful completion
-        -EFAULT if struct kvm_ppc_cpu_char cannot be written
-
-This ioctl gives userspace information about certain characteristics
-of the CPU relating to speculative execution of instructions and
-possible information leakage resulting from speculative execution (see
-CVE-2017-5715, CVE-2017-5753 and CVE-2017-5754).  The information is
-returned in struct kvm_ppc_cpu_char, which looks like this:
-
-struct kvm_ppc_cpu_char {
-       __u64   character;              /* characteristics of the CPU */
-       __u64   behaviour;              /* recommended software behaviour */
-       __u64   character_mask;         /* valid bits in character */
-       __u64   behaviour_mask;         /* valid bits in behaviour */
-};
-
-For extensibility, the character_mask and behaviour_mask fields
-indicate which bits of character and behaviour have been filled in by
-the kernel.  If the set of defined bits is extended in future then
-userspace will be able to tell whether it is running on a kernel that
-knows about the new bits.
-
-The character field describes attributes of the CPU which can help
-with preventing inadvertent information disclosure - specifically,
-whether there is an instruction to flash-invalidate the L1 data cache
-(ori 30,30,0 or mtspr SPRN_TRIG2,rN), whether the L1 data cache is set
-to a mode where entries can only be used by the thread that created
-them, whether the bcctr[l] instruction prevents speculation, and
-whether a speculation barrier instruction (ori 31,31,0) is provided.
-
-The behaviour field describes actions that software should take to
-prevent inadvertent information disclosure, and thus describes which
-vulnerabilities the hardware is subject to; specifically whether the
-L1 data cache should be flushed when returning to user mode from the
-kernel, and whether a speculation barrier should be placed between an
-array bounds check and the array access.
-
-These fields use the same bit definitions as the new
-H_GET_CPU_CHARACTERISTICS hypercall.
-
-4.110 KVM_MEMORY_ENCRYPT_OP
-
-Capability: basic
-Architectures: x86
-Type: system
-Parameters: an opaque platform specific structure (in/out)
-Returns: 0 on success; -1 on error
-
-If the platform supports creating encrypted VMs then this ioctl can be used
-for issuing platform-specific memory encryption commands to manage those
-encrypted VMs.
-
-Currently, this ioctl is used for issuing Secure Encrypted Virtualization
-(SEV) commands on AMD Processors. The SEV commands are defined in
-Documentation/virtual/kvm/amd-memory-encryption.rst.
-
-4.111 KVM_MEMORY_ENCRYPT_REG_REGION
-
-Capability: basic
-Architectures: x86
-Type: system
-Parameters: struct kvm_enc_region (in)
-Returns: 0 on success; -1 on error
-
-This ioctl can be used to register a guest memory region which may
-contain encrypted data (e.g. guest RAM, SMRAM etc).
-
-It is used in the SEV-enabled guest. When encryption is enabled, a guest
-memory region may contain encrypted data. The SEV memory encryption
-engine uses a tweak such that two identical plaintext pages, each at
-different locations will have differing ciphertexts. So swapping or
-moving ciphertext of those pages will not result in plaintext being
-swapped. So relocating (or migrating) physical backing pages for the SEV
-guest will require some additional steps.
-
-Note: The current SEV key management spec does not provide commands to
-swap or migrate (move) ciphertext pages. Hence, for now we pin the guest
-memory region registered with the ioctl.
-
-4.112 KVM_MEMORY_ENCRYPT_UNREG_REGION
-
-Capability: basic
-Architectures: x86
-Type: system
-Parameters: struct kvm_enc_region (in)
-Returns: 0 on success; -1 on error
-
-This ioctl can be used to unregister the guest memory region registered
-with KVM_MEMORY_ENCRYPT_REG_REGION ioctl above.
-
-4.113 KVM_HYPERV_EVENTFD
-
-Capability: KVM_CAP_HYPERV_EVENTFD
-Architectures: x86
-Type: vm ioctl
-Parameters: struct kvm_hyperv_eventfd (in)
-
-This ioctl (un)registers an eventfd to receive notifications from the guest on
-the specified Hyper-V connection id through the SIGNAL_EVENT hypercall, without
-causing a user exit.  SIGNAL_EVENT hypercall with non-zero event flag number
-(bits 24-31) still triggers a KVM_EXIT_HYPERV_HCALL user exit.
-
-struct kvm_hyperv_eventfd {
-       __u32 conn_id;
-       __s32 fd;
-       __u32 flags;
-       __u32 padding[3];
-};
-
-The conn_id field should fit within 24 bits:
-
-#define KVM_HYPERV_CONN_ID_MASK                0x00ffffff
-
-The acceptable values for the flags field are:
-
-#define KVM_HYPERV_EVENTFD_DEASSIGN    (1 << 0)
-
-Returns: 0 on success,
-       -EINVAL if conn_id or flags is outside the allowed range
-       -ENOENT on deassign if the conn_id isn't registered
-       -EEXIST on assign if the conn_id is already registered
-
-4.114 KVM_GET_NESTED_STATE
-
-Capability: KVM_CAP_NESTED_STATE
-Architectures: x86
-Type: vcpu ioctl
-Parameters: struct kvm_nested_state (in/out)
-Returns: 0 on success, -1 on error
-Errors:
-  E2BIG:     the total state size exceeds the value of 'size' specified by
-             the user; the size required will be written into size.
-
-struct kvm_nested_state {
-       __u16 flags;
-       __u16 format;
-       __u32 size;
-
-       union {
-               struct kvm_vmx_nested_state_hdr vmx;
-               struct kvm_svm_nested_state_hdr svm;
-
-               /* Pad the header to 128 bytes.  */
-               __u8 pad[120];
-       } hdr;
-
-       union {
-               struct kvm_vmx_nested_state_data vmx[0];
-               struct kvm_svm_nested_state_data svm[0];
-       } data;
-};
-
-#define KVM_STATE_NESTED_GUEST_MODE    0x00000001
-#define KVM_STATE_NESTED_RUN_PENDING   0x00000002
-#define KVM_STATE_NESTED_EVMCS         0x00000004
-
-#define KVM_STATE_NESTED_FORMAT_VMX            0
-#define KVM_STATE_NESTED_FORMAT_SVM            1
-
-#define KVM_STATE_NESTED_VMX_VMCS_SIZE         0x1000
-
-#define KVM_STATE_NESTED_VMX_SMM_GUEST_MODE    0x00000001
-#define KVM_STATE_NESTED_VMX_SMM_VMXON         0x00000002
-
-struct kvm_vmx_nested_state_hdr {
-       __u64 vmxon_pa;
-       __u64 vmcs12_pa;
-
-       struct {
-               __u16 flags;
-       } smm;
-};
-
-struct kvm_vmx_nested_state_data {
-       __u8 vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE];
-       __u8 shadow_vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE];
-};
-
-This ioctl copies the vcpu's nested virtualization state from the kernel to
-userspace.
-
-The maximum size of the state can be retrieved by passing KVM_CAP_NESTED_STATE
-to the KVM_CHECK_EXTENSION ioctl().
-
-4.115 KVM_SET_NESTED_STATE
-
-Capability: KVM_CAP_NESTED_STATE
-Architectures: x86
-Type: vcpu ioctl
-Parameters: struct kvm_nested_state (in)
-Returns: 0 on success, -1 on error
-
-This copies the vcpu's kvm_nested_state struct from userspace to the kernel.
-For the definition of struct kvm_nested_state, see KVM_GET_NESTED_STATE.
-
-4.116 KVM_(UN)REGISTER_COALESCED_MMIO
-
-Capability: KVM_CAP_COALESCED_MMIO (for coalesced mmio)
-           KVM_CAP_COALESCED_PIO (for coalesced pio)
-Architectures: all
-Type: vm ioctl
-Parameters: struct kvm_coalesced_mmio_zone
-Returns: 0 on success, < 0 on error
-
-Coalesced I/O is a performance optimization that defers hardware
-register write emulation so that userspace exits are avoided.  It is
-typically used to reduce the overhead of emulating frequently accessed
-hardware registers.
-
-When a hardware register is configured for coalesced I/O, write accesses
-do not exit to userspace and their value is recorded in a ring buffer
-that is shared between kernel and userspace.
-
-Coalesced I/O is used if one or more write accesses to a hardware
-register can be deferred until a read or a write to another hardware
-register on the same device.  This last access will cause a vmexit and
-userspace will process accesses from the ring buffer before emulating
-it. That will avoid exiting to userspace on repeated writes.
-
-Coalesced pio is based on coalesced mmio. There is little difference
-between coalesced mmio and pio except that coalesced pio records accesses
-to I/O ports.
-
-4.117 KVM_CLEAR_DIRTY_LOG (vm ioctl)
-
-Capability: KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2
-Architectures: x86, arm, arm64, mips
-Type: vm ioctl
-Parameters: struct kvm_dirty_log (in)
-Returns: 0 on success, -1 on error
-
-/* for KVM_CLEAR_DIRTY_LOG */
-struct kvm_clear_dirty_log {
-       __u32 slot;
-       __u32 num_pages;
-       __u64 first_page;
-       union {
-               void __user *dirty_bitmap; /* one bit per page */
-               __u64 padding;
-       };
-};
-
-The ioctl clears the dirty status of pages in a memory slot, according to
-the bitmap that is passed in struct kvm_clear_dirty_log's dirty_bitmap
-field.  Bit 0 of the bitmap corresponds to page "first_page" in the
-memory slot, and num_pages is the size in bits of the input bitmap.
-first_page must be a multiple of 64; num_pages must also be a multiple of
-64 unless first_page + num_pages is the size of the memory slot.  For each
-bit that is set in the input bitmap, the corresponding page is marked "clean"
-in KVM's dirty bitmap, and dirty tracking is re-enabled for that page
-(for example via write-protection, or by clearing the dirty bit in
-a page table entry).
-
-If KVM_CAP_MULTI_ADDRESS_SPACE is available, bits 16-31 specifies
-the address space for which you want to return the dirty bitmap.
-They must be less than the value that KVM_CHECK_EXTENSION returns for
-the KVM_CAP_MULTI_ADDRESS_SPACE capability.
-
-This ioctl is mostly useful when KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2
-is enabled; for more information, see the description of the capability.
-However, it can always be used as long as KVM_CHECK_EXTENSION confirms
-that KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 is present.
-
-4.118 KVM_GET_SUPPORTED_HV_CPUID
-
-Capability: KVM_CAP_HYPERV_CPUID
-Architectures: x86
-Type: vcpu ioctl
-Parameters: struct kvm_cpuid2 (in/out)
-Returns: 0 on success, -1 on error
-
-struct kvm_cpuid2 {
-       __u32 nent;
-       __u32 padding;
-       struct kvm_cpuid_entry2 entries[0];
-};
-
-struct kvm_cpuid_entry2 {
-       __u32 function;
-       __u32 index;
-       __u32 flags;
-       __u32 eax;
-       __u32 ebx;
-       __u32 ecx;
-       __u32 edx;
-       __u32 padding[3];
-};
-
-This ioctl returns x86 cpuid features leaves related to Hyper-V emulation in
-KVM.  Userspace can use the information returned by this ioctl to construct
-cpuid information presented to guests consuming Hyper-V enlightenments (e.g.
-Windows or Hyper-V guests).
-
-CPUID feature leaves returned by this ioctl are defined by Hyper-V Top Level
-Functional Specification (TLFS). These leaves can't be obtained with
-KVM_GET_SUPPORTED_CPUID ioctl because some of them intersect with KVM feature
-leaves (0x40000000, 0x40000001).
-
-Currently, the following list of CPUID leaves are returned:
- HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS
- HYPERV_CPUID_INTERFACE
- HYPERV_CPUID_VERSION
- HYPERV_CPUID_FEATURES
- HYPERV_CPUID_ENLIGHTMENT_INFO
- HYPERV_CPUID_IMPLEMENT_LIMITS
- HYPERV_CPUID_NESTED_FEATURES
-
-HYPERV_CPUID_NESTED_FEATURES leaf is only exposed when Enlightened VMCS was
-enabled on the corresponding vCPU (KVM_CAP_HYPERV_ENLIGHTENED_VMCS).
-
-Userspace invokes KVM_GET_SUPPORTED_CPUID by passing a kvm_cpuid2 structure
-with the 'nent' field indicating the number of entries in the variable-size
-array 'entries'.  If the number of entries is too low to describe all Hyper-V
-feature leaves, an error (E2BIG) is returned. If the number is more or equal
-to the number of Hyper-V feature leaves, the 'nent' field is adjusted to the
-number of valid entries in the 'entries' array, which is then filled.
-
-'index' and 'flags' fields in 'struct kvm_cpuid_entry2' are currently reserved,
-userspace should not expect to get any particular value there.
-
-4.119 KVM_ARM_VCPU_FINALIZE
-
-Architectures: arm, arm64
-Type: vcpu ioctl
-Parameters: int feature (in)
-Returns: 0 on success, -1 on error
-Errors:
-  EPERM:     feature not enabled, needs configuration, or already finalized
-  EINVAL:    feature unknown or not present
-
-Recognised values for feature:
-  arm64      KVM_ARM_VCPU_SVE (requires KVM_CAP_ARM_SVE)
-
-Finalizes the configuration of the specified vcpu feature.
-
-The vcpu must already have been initialised, enabling the affected feature, by
-means of a successful KVM_ARM_VCPU_INIT call with the appropriate flag set in
-features[].
-
-For affected vcpu features, this is a mandatory step that must be performed
-before the vcpu is fully usable.
-
-Between KVM_ARM_VCPU_INIT and KVM_ARM_VCPU_FINALIZE, the feature may be
-configured by use of ioctls such as KVM_SET_ONE_REG.  The exact configuration
-that should be performaned and how to do it are feature-dependent.
-
-Other calls that depend on a particular feature being finalized, such as
-KVM_RUN, KVM_GET_REG_LIST, KVM_GET_ONE_REG and KVM_SET_ONE_REG, will fail with
--EPERM unless the feature has already been finalized by means of a
-KVM_ARM_VCPU_FINALIZE call.
-
-See KVM_ARM_VCPU_INIT for details of vcpu features that require finalization
-using this ioctl.
-
-4.120 KVM_SET_PMU_EVENT_FILTER
-
-Capability: KVM_CAP_PMU_EVENT_FILTER
-Architectures: x86
-Type: vm ioctl
-Parameters: struct kvm_pmu_event_filter (in)
-Returns: 0 on success, -1 on error
-
-struct kvm_pmu_event_filter {
-       __u32 action;
-       __u32 nevents;
-       __u64 events[0];
-};
-
-This ioctl restricts the set of PMU events that the guest can program.
-The argument holds a list of events which will be allowed or denied.
-The eventsel+umask of each event the guest attempts to program is compared
-against the events field to determine whether the guest should have access.
-This only affects general purpose counters; fixed purpose counters can
-be disabled by changing the perfmon CPUID leaf.
-
-Valid values for 'action':
-#define KVM_PMU_EVENT_ALLOW 0
-#define KVM_PMU_EVENT_DENY 1
-
-
-5. The kvm_run structure
-------------------------
-
-Application code obtains a pointer to the kvm_run structure by
-mmap()ing a vcpu fd.  From that point, application code can control
-execution by changing fields in kvm_run prior to calling the KVM_RUN
-ioctl, and obtain information about the reason KVM_RUN returned by
-looking up structure members.
-
-struct kvm_run {
-       /* in */
-       __u8 request_interrupt_window;
-
-Request that KVM_RUN return when it becomes possible to inject external
-interrupts into the guest.  Useful in conjunction with KVM_INTERRUPT.
-
-       __u8 immediate_exit;
-
-This field is polled once when KVM_RUN starts; if non-zero, KVM_RUN
-exits immediately, returning -EINTR.  In the common scenario where a
-signal is used to "kick" a VCPU out of KVM_RUN, this field can be used
-to avoid usage of KVM_SET_SIGNAL_MASK, which has worse scalability.
-Rather than blocking the signal outside KVM_RUN, userspace can set up
-a signal handler that sets run->immediate_exit to a non-zero value.
-
-This field is ignored if KVM_CAP_IMMEDIATE_EXIT is not available.
-
-       __u8 padding1[6];
-
-       /* out */
-       __u32 exit_reason;
-
-When KVM_RUN has returned successfully (return value 0), this informs
-application code why KVM_RUN has returned.  Allowable values for this
-field are detailed below.
-
-       __u8 ready_for_interrupt_injection;
-
-If request_interrupt_window has been specified, this field indicates
-an interrupt can be injected now with KVM_INTERRUPT.
-
-       __u8 if_flag;
-
-The value of the current interrupt flag.  Only valid if in-kernel
-local APIC is not used.
-
-       __u16 flags;
-
-More architecture-specific flags detailing state of the VCPU that may
-affect the device's behavior.  The only currently defined flag is
-KVM_RUN_X86_SMM, which is valid on x86 machines and is set if the
-VCPU is in system management mode.
-
-       /* in (pre_kvm_run), out (post_kvm_run) */
-       __u64 cr8;
-
-The value of the cr8 register.  Only valid if in-kernel local APIC is
-not used.  Both input and output.
-
-       __u64 apic_base;
-
-The value of the APIC BASE msr.  Only valid if in-kernel local
-APIC is not used.  Both input and output.
-
-       union {
-               /* KVM_EXIT_UNKNOWN */
-               struct {
-                       __u64 hardware_exit_reason;
-               } hw;
-
-If exit_reason is KVM_EXIT_UNKNOWN, the vcpu has exited due to unknown
-reasons.  Further architecture-specific information is available in
-hardware_exit_reason.
-
-               /* KVM_EXIT_FAIL_ENTRY */
-               struct {
-                       __u64 hardware_entry_failure_reason;
-               } fail_entry;
-
-If exit_reason is KVM_EXIT_FAIL_ENTRY, the vcpu could not be run due
-to unknown reasons.  Further architecture-specific information is
-available in hardware_entry_failure_reason.
-
-               /* KVM_EXIT_EXCEPTION */
-               struct {
-                       __u32 exception;
-                       __u32 error_code;
-               } ex;
-
-Unused.
-
-               /* KVM_EXIT_IO */
-               struct {
-#define KVM_EXIT_IO_IN  0
-#define KVM_EXIT_IO_OUT 1
-                       __u8 direction;
-                       __u8 size; /* bytes */
-                       __u16 port;
-                       __u32 count;
-                       __u64 data_offset; /* relative to kvm_run start */
-               } io;
-
-If exit_reason is KVM_EXIT_IO, then the vcpu has
-executed a port I/O instruction which could not be satisfied by kvm.
-data_offset describes where the data is located (KVM_EXIT_IO_OUT) or
-where kvm expects application code to place the data for the next
-KVM_RUN invocation (KVM_EXIT_IO_IN).  Data format is a packed array.
-
-               /* KVM_EXIT_DEBUG */
-               struct {
-                       struct kvm_debug_exit_arch arch;
-               } debug;
-
-If the exit_reason is KVM_EXIT_DEBUG, then a vcpu is processing a debug event
-for which architecture specific information is returned.
-
-               /* KVM_EXIT_MMIO */
-               struct {
-                       __u64 phys_addr;
-                       __u8  data[8];
-                       __u32 len;
-                       __u8  is_write;
-               } mmio;
-
-If exit_reason is KVM_EXIT_MMIO, then the vcpu has
-executed a memory-mapped I/O instruction which could not be satisfied
-by kvm.  The 'data' member contains the written data if 'is_write' is
-true, and should be filled by application code otherwise.
-
-The 'data' member contains, in its first 'len' bytes, the value as it would
-appear if the VCPU performed a load or store of the appropriate width directly
-to the byte array.
-
-NOTE: For KVM_EXIT_IO, KVM_EXIT_MMIO, KVM_EXIT_OSI, KVM_EXIT_PAPR and
-      KVM_EXIT_EPR the corresponding
-operations are complete (and guest state is consistent) only after userspace
-has re-entered the kernel with KVM_RUN.  The kernel side will first finish
-incomplete operations and then check for pending signals.  Userspace
-can re-enter the guest with an unmasked signal pending to complete
-pending operations.
-
-               /* KVM_EXIT_HYPERCALL */
-               struct {
-                       __u64 nr;
-                       __u64 args[6];
-                       __u64 ret;
-                       __u32 longmode;
-                       __u32 pad;
-               } hypercall;
-
-Unused.  This was once used for 'hypercall to userspace'.  To implement
-such functionality, use KVM_EXIT_IO (x86) or KVM_EXIT_MMIO (all except s390).
-Note KVM_EXIT_IO is significantly faster than KVM_EXIT_MMIO.
-
-               /* KVM_EXIT_TPR_ACCESS */
-               struct {
-                       __u64 rip;
-                       __u32 is_write;
-                       __u32 pad;
-               } tpr_access;
-
-To be documented (KVM_TPR_ACCESS_REPORTING).
-
-               /* KVM_EXIT_S390_SIEIC */
-               struct {
-                       __u8 icptcode;
-                       __u64 mask; /* psw upper half */
-                       __u64 addr; /* psw lower half */
-                       __u16 ipa;
-                       __u32 ipb;
-               } s390_sieic;
-
-s390 specific.
-
-               /* KVM_EXIT_S390_RESET */
-#define KVM_S390_RESET_POR       1
-#define KVM_S390_RESET_CLEAR     2
-#define KVM_S390_RESET_SUBSYSTEM 4
-#define KVM_S390_RESET_CPU_INIT  8
-#define KVM_S390_RESET_IPL       16
-               __u64 s390_reset_flags;
-
-s390 specific.
-
-               /* KVM_EXIT_S390_UCONTROL */
-               struct {
-                       __u64 trans_exc_code;
-                       __u32 pgm_code;
-               } s390_ucontrol;
-
-s390 specific. A page fault has occurred for a user controlled virtual
-machine (KVM_VM_S390_UNCONTROL) on it's host page table that cannot be
-resolved by the kernel.
-The program code and the translation exception code that were placed
-in the cpu's lowcore are presented here as defined by the z Architecture
-Principles of Operation Book in the Chapter for Dynamic Address Translation
-(DAT)
-
-               /* KVM_EXIT_DCR */
-               struct {
-                       __u32 dcrn;
-                       __u32 data;
-                       __u8  is_write;
-               } dcr;
-
-Deprecated - was used for 440 KVM.
-
-               /* KVM_EXIT_OSI */
-               struct {
-                       __u64 gprs[32];
-               } osi;
-
-MOL uses a special hypercall interface it calls 'OSI'. To enable it, we catch
-hypercalls and exit with this exit struct that contains all the guest gprs.
-
-If exit_reason is KVM_EXIT_OSI, then the vcpu has triggered such a hypercall.
-Userspace can now handle the hypercall and when it's done modify the gprs as
-necessary. Upon guest entry all guest GPRs will then be replaced by the values
-in this struct.
-
-               /* KVM_EXIT_PAPR_HCALL */
-               struct {
-                       __u64 nr;
-                       __u64 ret;
-                       __u64 args[9];
-               } papr_hcall;
-
-This is used on 64-bit PowerPC when emulating a pSeries partition,
-e.g. with the 'pseries' machine type in qemu.  It occurs when the
-guest does a hypercall using the 'sc 1' instruction.  The 'nr' field
-contains the hypercall number (from the guest R3), and 'args' contains
-the arguments (from the guest R4 - R12).  Userspace should put the
-return code in 'ret' and any extra returned values in args[].
-The possible hypercalls are defined in the Power Architecture Platform
-Requirements (PAPR) document available from www.power.org (free
-developer registration required to access it).
-
-               /* KVM_EXIT_S390_TSCH */
-               struct {
-                       __u16 subchannel_id;
-                       __u16 subchannel_nr;
-                       __u32 io_int_parm;
-                       __u32 io_int_word;
-                       __u32 ipb;
-                       __u8 dequeued;
-               } s390_tsch;
-
-s390 specific. This exit occurs when KVM_CAP_S390_CSS_SUPPORT has been enabled
-and TEST SUBCHANNEL was intercepted. If dequeued is set, a pending I/O
-interrupt for the target subchannel has been dequeued and subchannel_id,
-subchannel_nr, io_int_parm and io_int_word contain the parameters for that
-interrupt. ipb is needed for instruction parameter decoding.
-
-               /* KVM_EXIT_EPR */
-               struct {
-                       __u32 epr;
-               } epr;
-
-On FSL BookE PowerPC chips, the interrupt controller has a fast patch
-interrupt acknowledge path to the core. When the core successfully
-delivers an interrupt, it automatically populates the EPR register with
-the interrupt vector number and acknowledges the interrupt inside
-the interrupt controller.
-
-In case the interrupt controller lives in user space, we need to do
-the interrupt acknowledge cycle through it to fetch the next to be
-delivered interrupt vector using this exit.
-
-It gets triggered whenever both KVM_CAP_PPC_EPR are enabled and an
-external interrupt has just been delivered into the guest. User space
-should put the acknowledged interrupt vector into the 'epr' field.
-
-               /* KVM_EXIT_SYSTEM_EVENT */
-               struct {
-#define KVM_SYSTEM_EVENT_SHUTDOWN       1
-#define KVM_SYSTEM_EVENT_RESET          2
-#define KVM_SYSTEM_EVENT_CRASH          3
-                       __u32 type;
-                       __u64 flags;
-               } system_event;
-
-If exit_reason is KVM_EXIT_SYSTEM_EVENT then the vcpu has triggered
-a system-level event using some architecture specific mechanism (hypercall
-or some special instruction). In case of ARM/ARM64, this is triggered using
-HVC instruction based PSCI call from the vcpu. The 'type' field describes
-the system-level event type. The 'flags' field describes architecture
-specific flags for the system-level event.
-
-Valid values for 'type' are:
-  KVM_SYSTEM_EVENT_SHUTDOWN -- the guest has requested a shutdown of the
-   VM. Userspace is not obliged to honour this, and if it does honour
-   this does not need to destroy the VM synchronously (ie it may call
-   KVM_RUN again before shutdown finally occurs).
-  KVM_SYSTEM_EVENT_RESET -- the guest has requested a reset of the VM.
-   As with SHUTDOWN, userspace can choose to ignore the request, or
-   to schedule the reset to occur in the future and may call KVM_RUN again.
-  KVM_SYSTEM_EVENT_CRASH -- the guest crash occurred and the guest
-   has requested a crash condition maintenance. Userspace can choose
-   to ignore the request, or to gather VM memory core dump and/or
-   reset/shutdown of the VM.
-
-               /* KVM_EXIT_IOAPIC_EOI */
-               struct {
-                       __u8 vector;
-               } eoi;
-
-Indicates that the VCPU's in-kernel local APIC received an EOI for a
-level-triggered IOAPIC interrupt.  This exit only triggers when the
-IOAPIC is implemented in userspace (i.e. KVM_CAP_SPLIT_IRQCHIP is enabled);
-the userspace IOAPIC should process the EOI and retrigger the interrupt if
-it is still asserted.  Vector is the LAPIC interrupt vector for which the
-EOI was received.
-
-               struct kvm_hyperv_exit {
-#define KVM_EXIT_HYPERV_SYNIC          1
-#define KVM_EXIT_HYPERV_HCALL          2
-                       __u32 type;
-                       union {
-                               struct {
-                                       __u32 msr;
-                                       __u64 control;
-                                       __u64 evt_page;
-                                       __u64 msg_page;
-                               } synic;
-                               struct {
-                                       __u64 input;
-                                       __u64 result;
-                                       __u64 params[2];
-                               } hcall;
-                       } u;
-               };
-               /* KVM_EXIT_HYPERV */
-                struct kvm_hyperv_exit hyperv;
-Indicates that the VCPU exits into userspace to process some tasks
-related to Hyper-V emulation.
-Valid values for 'type' are:
-       KVM_EXIT_HYPERV_SYNIC -- synchronously notify user-space about
-Hyper-V SynIC state change. Notification is used to remap SynIC
-event/message pages and to enable/disable SynIC messages/events processing
-in userspace.
-
-               /* Fix the size of the union. */
-               char padding[256];
-       };
-
-       /*
-        * shared registers between kvm and userspace.
-        * kvm_valid_regs specifies the register classes set by the host
-        * kvm_dirty_regs specified the register classes dirtied by userspace
-        * struct kvm_sync_regs is architecture specific, as well as the
-        * bits for kvm_valid_regs and kvm_dirty_regs
-        */
-       __u64 kvm_valid_regs;
-       __u64 kvm_dirty_regs;
-       union {
-               struct kvm_sync_regs regs;
-               char padding[SYNC_REGS_SIZE_BYTES];
-       } s;
-
-If KVM_CAP_SYNC_REGS is defined, these fields allow userspace to access
-certain guest registers without having to call SET/GET_*REGS. Thus we can
-avoid some system call overhead if userspace has to handle the exit.
-Userspace can query the validity of the structure by checking
-kvm_valid_regs for specific bits. These bits are architecture specific
-and usually define the validity of a groups of registers. (e.g. one bit
- for general purpose registers)
-
-Please note that the kernel is allowed to use the kvm_run structure as the
-primary storage for certain register types. Therefore, the kernel may use the
-values in kvm_run even if the corresponding bit in kvm_dirty_regs is not set.
-
-};
-
-
-
-6. Capabilities that can be enabled on vCPUs
---------------------------------------------
-
-There are certain capabilities that change the behavior of the virtual CPU or
-the virtual machine when enabled. To enable them, please see section 4.37.
-Below you can find a list of capabilities and what their effect on the vCPU or
-the virtual machine is when enabling them.
-
-The following information is provided along with the description:
-
-  Architectures: which instruction set architectures provide this ioctl.
-      x86 includes both i386 and x86_64.
-
-  Target: whether this is a per-vcpu or per-vm capability.
-
-  Parameters: what parameters are accepted by the capability.
-
-  Returns: the return value.  General error numbers (EBADF, ENOMEM, EINVAL)
-      are not detailed, but errors with specific meanings are.
-
-
-6.1 KVM_CAP_PPC_OSI
-
-Architectures: ppc
-Target: vcpu
-Parameters: none
-Returns: 0 on success; -1 on error
-
-This capability enables interception of OSI hypercalls that otherwise would
-be treated as normal system calls to be injected into the guest. OSI hypercalls
-were invented by Mac-on-Linux to have a standardized communication mechanism
-between the guest and the host.
-
-When this capability is enabled, KVM_EXIT_OSI can occur.
-
-
-6.2 KVM_CAP_PPC_PAPR
-
-Architectures: ppc
-Target: vcpu
-Parameters: none
-Returns: 0 on success; -1 on error
-
-This capability enables interception of PAPR hypercalls. PAPR hypercalls are
-done using the hypercall instruction "sc 1".
-
-It also sets the guest privilege level to "supervisor" mode. Usually the guest
-runs in "hypervisor" privilege mode with a few missing features.
-
-In addition to the above, it changes the semantics of SDR1. In this mode, the
-HTAB address part of SDR1 contains an HVA instead of a GPA, as PAPR keeps the
-HTAB invisible to the guest.
-
-When this capability is enabled, KVM_EXIT_PAPR_HCALL can occur.
-
-
-6.3 KVM_CAP_SW_TLB
-
-Architectures: ppc
-Target: vcpu
-Parameters: args[0] is the address of a struct kvm_config_tlb
-Returns: 0 on success; -1 on error
-
-struct kvm_config_tlb {
-       __u64 params;
-       __u64 array;
-       __u32 mmu_type;
-       __u32 array_len;
-};
-
-Configures the virtual CPU's TLB array, establishing a shared memory area
-between userspace and KVM.  The "params" and "array" fields are userspace
-addresses of mmu-type-specific data structures.  The "array_len" field is an
-safety mechanism, and should be set to the size in bytes of the memory that
-userspace has reserved for the array.  It must be at least the size dictated
-by "mmu_type" and "params".
-
-While KVM_RUN is active, the shared region is under control of KVM.  Its
-contents are undefined, and any modification by userspace results in
-boundedly undefined behavior.
-
-On return from KVM_RUN, the shared region will reflect the current state of
-the guest's TLB.  If userspace makes any changes, it must call KVM_DIRTY_TLB
-to tell KVM which entries have been changed, prior to calling KVM_RUN again
-on this vcpu.
-
-For mmu types KVM_MMU_FSL_BOOKE_NOHV and KVM_MMU_FSL_BOOKE_HV:
- - The "params" field is of type "struct kvm_book3e_206_tlb_params".
- - The "array" field points to an array of type "struct
-   kvm_book3e_206_tlb_entry".
- - The array consists of all entries in the first TLB, followed by all
-   entries in the second TLB.
- - Within a TLB, entries are ordered first by increasing set number.  Within a
-   set, entries are ordered by way (increasing ESEL).
- - The hash for determining set number in TLB0 is: (MAS2 >> 12) & (num_sets - 1)
-   where "num_sets" is the tlb_sizes[] value divided by the tlb_ways[] value.
- - The tsize field of mas1 shall be set to 4K on TLB0, even though the
-   hardware ignores this value for TLB0.
-
-6.4 KVM_CAP_S390_CSS_SUPPORT
-
-Architectures: s390
-Target: vcpu
-Parameters: none
-Returns: 0 on success; -1 on error
-
-This capability enables support for handling of channel I/O instructions.
-
-TEST PENDING INTERRUPTION and the interrupt portion of TEST SUBCHANNEL are
-handled in-kernel, while the other I/O instructions are passed to userspace.
-
-When this capability is enabled, KVM_EXIT_S390_TSCH will occur on TEST
-SUBCHANNEL intercepts.
-
-Note that even though this capability is enabled per-vcpu, the complete
-virtual machine is affected.
-
-6.5 KVM_CAP_PPC_EPR
-
-Architectures: ppc
-Target: vcpu
-Parameters: args[0] defines whether the proxy facility is active
-Returns: 0 on success; -1 on error
-
-This capability enables or disables the delivery of interrupts through the
-external proxy facility.
-
-When enabled (args[0] != 0), every time the guest gets an external interrupt
-delivered, it automatically exits into user space with a KVM_EXIT_EPR exit
-to receive the topmost interrupt vector.
-
-When disabled (args[0] == 0), behavior is as if this facility is unsupported.
-
-When this capability is enabled, KVM_EXIT_EPR can occur.
-
-6.6 KVM_CAP_IRQ_MPIC
-
-Architectures: ppc
-Parameters: args[0] is the MPIC device fd
-            args[1] is the MPIC CPU number for this vcpu
-
-This capability connects the vcpu to an in-kernel MPIC device.
-
-6.7 KVM_CAP_IRQ_XICS
-
-Architectures: ppc
-Target: vcpu
-Parameters: args[0] is the XICS device fd
-            args[1] is the XICS CPU number (server ID) for this vcpu
-
-This capability connects the vcpu to an in-kernel XICS device.
-
-6.8 KVM_CAP_S390_IRQCHIP
-
-Architectures: s390
-Target: vm
-Parameters: none
-
-This capability enables the in-kernel irqchip for s390. Please refer to
-"4.24 KVM_CREATE_IRQCHIP" for details.
-
-6.9 KVM_CAP_MIPS_FPU
-
-Architectures: mips
-Target: vcpu
-Parameters: args[0] is reserved for future use (should be 0).
-
-This capability allows the use of the host Floating Point Unit by the guest. It
-allows the Config1.FP bit to be set to enable the FPU in the guest. Once this is
-done the KVM_REG_MIPS_FPR_* and KVM_REG_MIPS_FCR_* registers can be accessed
-(depending on the current guest FPU register mode), and the Status.FR,
-Config5.FRE bits are accessible via the KVM API and also from the guest,
-depending on them being supported by the FPU.
-
-6.10 KVM_CAP_MIPS_MSA
-
-Architectures: mips
-Target: vcpu
-Parameters: args[0] is reserved for future use (should be 0).
-
-This capability allows the use of the MIPS SIMD Architecture (MSA) by the guest.
-It allows the Config3.MSAP bit to be set to enable the use of MSA by the guest.
-Once this is done the KVM_REG_MIPS_VEC_* and KVM_REG_MIPS_MSA_* registers can be
-accessed, and the Config5.MSAEn bit is accessible via the KVM API and also from
-the guest.
-
-6.74 KVM_CAP_SYNC_REGS
-Architectures: s390, x86
-Target: s390: always enabled, x86: vcpu
-Parameters: none
-Returns: x86: KVM_CHECK_EXTENSION returns a bit-array indicating which register
-sets are supported (bitfields defined in arch/x86/include/uapi/asm/kvm.h).
-
-As described above in the kvm_sync_regs struct info in section 5 (kvm_run):
-KVM_CAP_SYNC_REGS "allow[s] userspace to access certain guest registers
-without having to call SET/GET_*REGS". This reduces overhead by eliminating
-repeated ioctl calls for setting and/or getting register values. This is
-particularly important when userspace is making synchronous guest state
-modifications, e.g. when emulating and/or intercepting instructions in
-userspace.
-
-For s390 specifics, please refer to the source code.
-
-For x86:
-- the register sets to be copied out to kvm_run are selectable
-  by userspace (rather that all sets being copied out for every exit).
-- vcpu_events are available in addition to regs and sregs.
-
-For x86, the 'kvm_valid_regs' field of struct kvm_run is overloaded to
-function as an input bit-array field set by userspace to indicate the
-specific register sets to be copied out on the next exit.
-
-To indicate when userspace has modified values that should be copied into
-the vCPU, the all architecture bitarray field, 'kvm_dirty_regs' must be set.
-This is done using the same bitflags as for the 'kvm_valid_regs' field.
-If the dirty bit is not set, then the register set values will not be copied
-into the vCPU even if they've been modified.
-
-Unused bitfields in the bitarrays must be set to zero.
-
-struct kvm_sync_regs {
-        struct kvm_regs regs;
-        struct kvm_sregs sregs;
-        struct kvm_vcpu_events events;
-};
-
-6.75 KVM_CAP_PPC_IRQ_XIVE
-
-Architectures: ppc
-Target: vcpu
-Parameters: args[0] is the XIVE device fd
-            args[1] is the XIVE CPU number (server ID) for this vcpu
-
-This capability connects the vcpu to an in-kernel XIVE device.
-
-7. Capabilities that can be enabled on VMs
-------------------------------------------
-
-There are certain capabilities that change the behavior of the virtual
-machine when enabled. To enable them, please see section 4.37. Below
-you can find a list of capabilities and what their effect on the VM
-is when enabling them.
-
-The following information is provided along with the description:
-
-  Architectures: which instruction set architectures provide this ioctl.
-      x86 includes both i386 and x86_64.
-
-  Parameters: what parameters are accepted by the capability.
-
-  Returns: the return value.  General error numbers (EBADF, ENOMEM, EINVAL)
-      are not detailed, but errors with specific meanings are.
-
-
-7.1 KVM_CAP_PPC_ENABLE_HCALL
-
-Architectures: ppc
-Parameters: args[0] is the sPAPR hcall number
-           args[1] is 0 to disable, 1 to enable in-kernel handling
-
-This capability controls whether individual sPAPR hypercalls (hcalls)
-get handled by the kernel or not.  Enabling or disabling in-kernel
-handling of an hcall is effective across the VM.  On creation, an
-initial set of hcalls are enabled for in-kernel handling, which
-consists of those hcalls for which in-kernel handlers were implemented
-before this capability was implemented.  If disabled, the kernel will
-not to attempt to handle the hcall, but will always exit to userspace
-to handle it.  Note that it may not make sense to enable some and
-disable others of a group of related hcalls, but KVM does not prevent
-userspace from doing that.
-
-If the hcall number specified is not one that has an in-kernel
-implementation, the KVM_ENABLE_CAP ioctl will fail with an EINVAL
-error.
-
-7.2 KVM_CAP_S390_USER_SIGP
-
-Architectures: s390
-Parameters: none
-
-This capability controls which SIGP orders will be handled completely in user
-space. With this capability enabled, all fast orders will be handled completely
-in the kernel:
-- SENSE
-- SENSE RUNNING
-- EXTERNAL CALL
-- EMERGENCY SIGNAL
-- CONDITIONAL EMERGENCY SIGNAL
-
-All other orders will be handled completely in user space.
-
-Only privileged operation exceptions will be checked for in the kernel (or even
-in the hardware prior to interception). If this capability is not enabled, the
-old way of handling SIGP orders is used (partially in kernel and user space).
-
-7.3 KVM_CAP_S390_VECTOR_REGISTERS
-
-Architectures: s390
-Parameters: none
-Returns: 0 on success, negative value on error
-
-Allows use of the vector registers introduced with z13 processor, and
-provides for the synchronization between host and user space.  Will
-return -EINVAL if the machine does not support vectors.
-
-7.4 KVM_CAP_S390_USER_STSI
-
-Architectures: s390
-Parameters: none
-
-This capability allows post-handlers for the STSI instruction. After
-initial handling in the kernel, KVM exits to user space with
-KVM_EXIT_S390_STSI to allow user space to insert further data.
-
-Before exiting to userspace, kvm handlers should fill in s390_stsi field of
-vcpu->run:
-struct {
-       __u64 addr;
-       __u8 ar;
-       __u8 reserved;
-       __u8 fc;
-       __u8 sel1;
-       __u16 sel2;
-} s390_stsi;
-
-@addr - guest address of STSI SYSIB
-@fc   - function code
-@sel1 - selector 1
-@sel2 - selector 2
-@ar   - access register number
-
-KVM handlers should exit to userspace with rc = -EREMOTE.
-
-7.5 KVM_CAP_SPLIT_IRQCHIP
-
-Architectures: x86
-Parameters: args[0] - number of routes reserved for userspace IOAPICs
-Returns: 0 on success, -1 on error
-
-Create a local apic for each processor in the kernel. This can be used
-instead of KVM_CREATE_IRQCHIP if the userspace VMM wishes to emulate the
-IOAPIC and PIC (and also the PIT, even though this has to be enabled
-separately).
-
-This capability also enables in kernel routing of interrupt requests;
-when KVM_CAP_SPLIT_IRQCHIP only routes of KVM_IRQ_ROUTING_MSI type are
-used in the IRQ routing table.  The first args[0] MSI routes are reserved
-for the IOAPIC pins.  Whenever the LAPIC receives an EOI for these routes,
-a KVM_EXIT_IOAPIC_EOI vmexit will be reported to userspace.
-
-Fails if VCPU has already been created, or if the irqchip is already in the
-kernel (i.e. KVM_CREATE_IRQCHIP has already been called).
-
-7.6 KVM_CAP_S390_RI
-
-Architectures: s390
-Parameters: none
-
-Allows use of runtime-instrumentation introduced with zEC12 processor.
-Will return -EINVAL if the machine does not support runtime-instrumentation.
-Will return -EBUSY if a VCPU has already been created.
-
-7.7 KVM_CAP_X2APIC_API
-
-Architectures: x86
-Parameters: args[0] - features that should be enabled
-Returns: 0 on success, -EINVAL when args[0] contains invalid features
-
-Valid feature flags in args[0] are
-
-#define KVM_X2APIC_API_USE_32BIT_IDS            (1ULL << 0)
-#define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK  (1ULL << 1)
-
-Enabling KVM_X2APIC_API_USE_32BIT_IDS changes the behavior of
-KVM_SET_GSI_ROUTING, KVM_SIGNAL_MSI, KVM_SET_LAPIC, and KVM_GET_LAPIC,
-allowing the use of 32-bit APIC IDs.  See KVM_CAP_X2APIC_API in their
-respective sections.
-
-KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK must be enabled for x2APIC to work
-in logical mode or with more than 255 VCPUs.  Otherwise, KVM treats 0xff
-as a broadcast even in x2APIC mode in order to support physical x2APIC
-without interrupt remapping.  This is undesirable in logical mode,
-where 0xff represents CPUs 0-7 in cluster 0.
-
-7.8 KVM_CAP_S390_USER_INSTR0
-
-Architectures: s390
-Parameters: none
-
-With this capability enabled, all illegal instructions 0x0000 (2 bytes) will
-be intercepted and forwarded to user space. User space can use this
-mechanism e.g. to realize 2-byte software breakpoints. The kernel will
-not inject an operating exception for these instructions, user space has
-to take care of that.
-
-This capability can be enabled dynamically even if VCPUs were already
-created and are running.
-
-7.9 KVM_CAP_S390_GS
-
-Architectures: s390
-Parameters: none
-Returns: 0 on success; -EINVAL if the machine does not support
-        guarded storage; -EBUSY if a VCPU has already been created.
-
-Allows use of guarded storage for the KVM guest.
-
-7.10 KVM_CAP_S390_AIS
-
-Architectures: s390
-Parameters: none
-
-Allow use of adapter-interruption suppression.
-Returns: 0 on success; -EBUSY if a VCPU has already been created.
-
-7.11 KVM_CAP_PPC_SMT
-
-Architectures: ppc
-Parameters: vsmt_mode, flags
-
-Enabling this capability on a VM provides userspace with a way to set
-the desired virtual SMT mode (i.e. the number of virtual CPUs per
-virtual core).  The virtual SMT mode, vsmt_mode, must be a power of 2
-between 1 and 8.  On POWER8, vsmt_mode must also be no greater than
-the number of threads per subcore for the host.  Currently flags must
-be 0.  A successful call to enable this capability will result in
-vsmt_mode being returned when the KVM_CAP_PPC_SMT capability is
-subsequently queried for the VM.  This capability is only supported by
-HV KVM, and can only be set before any VCPUs have been created.
-The KVM_CAP_PPC_SMT_POSSIBLE capability indicates which virtual SMT
-modes are available.
-
-7.12 KVM_CAP_PPC_FWNMI
-
-Architectures: ppc
-Parameters: none
-
-With this capability a machine check exception in the guest address
-space will cause KVM to exit the guest with NMI exit reason. This
-enables QEMU to build error log and branch to guest kernel registered
-machine check handling routine. Without this capability KVM will
-branch to guests' 0x200 interrupt vector.
-
-7.13 KVM_CAP_X86_DISABLE_EXITS
-
-Architectures: x86
-Parameters: args[0] defines which exits are disabled
-Returns: 0 on success, -EINVAL when args[0] contains invalid exits
-
-Valid bits in args[0] are
-
-#define KVM_X86_DISABLE_EXITS_MWAIT            (1 << 0)
-#define KVM_X86_DISABLE_EXITS_HLT              (1 << 1)
-#define KVM_X86_DISABLE_EXITS_PAUSE            (1 << 2)
-#define KVM_X86_DISABLE_EXITS_CSTATE           (1 << 3)
-
-Enabling this capability on a VM provides userspace with a way to no
-longer intercept some instructions for improved latency in some
-workloads, and is suggested when vCPUs are associated to dedicated
-physical CPUs.  More bits can be added in the future; userspace can
-just pass the KVM_CHECK_EXTENSION result to KVM_ENABLE_CAP to disable
-all such vmexits.
-
-Do not enable KVM_FEATURE_PV_UNHALT if you disable HLT exits.
-
-7.14 KVM_CAP_S390_HPAGE_1M
-
-Architectures: s390
-Parameters: none
-Returns: 0 on success, -EINVAL if hpage module parameter was not set
-        or cmma is enabled, or the VM has the KVM_VM_S390_UCONTROL
-        flag set
-
-With this capability the KVM support for memory backing with 1m pages
-through hugetlbfs can be enabled for a VM. After the capability is
-enabled, cmma can't be enabled anymore and pfmfi and the storage key
-interpretation are disabled. If cmma has already been enabled or the
-hpage module parameter is not set to 1, -EINVAL is returned.
-
-While it is generally possible to create a huge page backed VM without
-this capability, the VM will not be able to run.
-
-7.15 KVM_CAP_MSR_PLATFORM_INFO
-
-Architectures: x86
-Parameters: args[0] whether feature should be enabled or not
-
-With this capability, a guest may read the MSR_PLATFORM_INFO MSR. Otherwise,
-a #GP would be raised when the guest tries to access. Currently, this
-capability does not enable write permissions of this MSR for the guest.
-
-7.16 KVM_CAP_PPC_NESTED_HV
-
-Architectures: ppc
-Parameters: none
-Returns: 0 on success, -EINVAL when the implementation doesn't support
-        nested-HV virtualization.
-
-HV-KVM on POWER9 and later systems allows for "nested-HV"
-virtualization, which provides a way for a guest VM to run guests that
-can run using the CPU's supervisor mode (privileged non-hypervisor
-state).  Enabling this capability on a VM depends on the CPU having
-the necessary functionality and on the facility being enabled with a
-kvm-hv module parameter.
-
-7.17 KVM_CAP_EXCEPTION_PAYLOAD
-
-Architectures: x86
-Parameters: args[0] whether feature should be enabled or not
-
-With this capability enabled, CR2 will not be modified prior to the
-emulated VM-exit when L1 intercepts a #PF exception that occurs in
-L2. Similarly, for kvm-intel only, DR6 will not be modified prior to
-the emulated VM-exit when L1 intercepts a #DB exception that occurs in
-L2. As a result, when KVM_GET_VCPU_EVENTS reports a pending #PF (or
-#DB) exception for L2, exception.has_payload will be set and the
-faulting address (or the new DR6 bits*) will be reported in the
-exception_payload field. Similarly, when userspace injects a #PF (or
-#DB) into L2 using KVM_SET_VCPU_EVENTS, it is expected to set
-exception.has_payload and to put the faulting address (or the new DR6
-bits*) in the exception_payload field.
-
-This capability also enables exception.pending in struct
-kvm_vcpu_events, which allows userspace to distinguish between pending
-and injected exceptions.
-
-
-* For the new DR6 bits, note that bit 16 is set iff the #DB exception
-  will clear DR6.RTM.
-
-7.18 KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2
-
-Architectures: x86, arm, arm64, mips
-Parameters: args[0] whether feature should be enabled or not
-
-With this capability enabled, KVM_GET_DIRTY_LOG will not automatically
-clear and write-protect all pages that are returned as dirty.
-Rather, userspace will have to do this operation separately using
-KVM_CLEAR_DIRTY_LOG.
-
-At the cost of a slightly more complicated operation, this provides better
-scalability and responsiveness for two reasons.  First,
-KVM_CLEAR_DIRTY_LOG ioctl can operate on a 64-page granularity rather
-than requiring to sync a full memslot; this ensures that KVM does not
-take spinlocks for an extended period of time.  Second, in some cases a
-large amount of time can pass between a call to KVM_GET_DIRTY_LOG and
-userspace actually using the data in the page.  Pages can be modified
-during this time, which is inefficint for both the guest and userspace:
-the guest will incur a higher penalty due to write protection faults,
-while userspace can see false reports of dirty pages.  Manual reprotection
-helps reducing this time, improving guest performance and reducing the
-number of dirty log false positives.
-
-KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 was previously available under the name
-KVM_CAP_MANUAL_DIRTY_LOG_PROTECT, but the implementation had bugs that make
-it hard or impossible to use it correctly.  The availability of
-KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 signals that those bugs are fixed.
-Userspace should not try to use KVM_CAP_MANUAL_DIRTY_LOG_PROTECT.
-
-8. Other capabilities.
-----------------------
-
-This section lists capabilities that give information about other
-features of the KVM implementation.
-
-8.1 KVM_CAP_PPC_HWRNG
-
-Architectures: ppc
-
-This capability, if KVM_CHECK_EXTENSION indicates that it is
-available, means that that the kernel has an implementation of the
-H_RANDOM hypercall backed by a hardware random-number generator.
-If present, the kernel H_RANDOM handler can be enabled for guest use
-with the KVM_CAP_PPC_ENABLE_HCALL capability.
-
-8.2 KVM_CAP_HYPERV_SYNIC
-
-Architectures: x86
-This capability, if KVM_CHECK_EXTENSION indicates that it is
-available, means that that the kernel has an implementation of the
-Hyper-V Synthetic interrupt controller(SynIC). Hyper-V SynIC is
-used to support Windows Hyper-V based guest paravirt drivers(VMBus).
-
-In order to use SynIC, it has to be activated by setting this
-capability via KVM_ENABLE_CAP ioctl on the vcpu fd. Note that this
-will disable the use of APIC hardware virtualization even if supported
-by the CPU, as it's incompatible with SynIC auto-EOI behavior.
-
-8.3 KVM_CAP_PPC_RADIX_MMU
-
-Architectures: ppc
-
-This capability, if KVM_CHECK_EXTENSION indicates that it is
-available, means that that the kernel can support guests using the
-radix MMU defined in Power ISA V3.00 (as implemented in the POWER9
-processor).
-
-8.4 KVM_CAP_PPC_HASH_MMU_V3
-
-Architectures: ppc
-
-This capability, if KVM_CHECK_EXTENSION indicates that it is
-available, means that that the kernel can support guests using the
-hashed page table MMU defined in Power ISA V3.00 (as implemented in
-the POWER9 processor), including in-memory segment tables.
-
-8.5 KVM_CAP_MIPS_VZ
-
-Architectures: mips
-
-This capability, if KVM_CHECK_EXTENSION on the main kvm handle indicates that
-it is available, means that full hardware assisted virtualization capabilities
-of the hardware are available for use through KVM. An appropriate
-KVM_VM_MIPS_* type must be passed to KVM_CREATE_VM to create a VM which
-utilises it.
-
-If KVM_CHECK_EXTENSION on a kvm VM handle indicates that this capability is
-available, it means that the VM is using full hardware assisted virtualization
-capabilities of the hardware. This is useful to check after creating a VM with
-KVM_VM_MIPS_DEFAULT.
-
-The value returned by KVM_CHECK_EXTENSION should be compared against known
-values (see below). All other values are reserved. This is to allow for the
-possibility of other hardware assisted virtualization implementations which
-may be incompatible with the MIPS VZ ASE.
-
- 0: The trap & emulate implementation is in use to run guest code in user
-    mode. Guest virtual memory segments are rearranged to fit the guest in the
-    user mode address space.
-
- 1: The MIPS VZ ASE is in use, providing full hardware assisted
-    virtualization, including standard guest virtual memory segments.
-
-8.6 KVM_CAP_MIPS_TE
-
-Architectures: mips
-
-This capability, if KVM_CHECK_EXTENSION on the main kvm handle indicates that
-it is available, means that the trap & emulate implementation is available to
-run guest code in user mode, even if KVM_CAP_MIPS_VZ indicates that hardware
-assisted virtualisation is also available. KVM_VM_MIPS_TE (0) must be passed
-to KVM_CREATE_VM to create a VM which utilises it.
-
-If KVM_CHECK_EXTENSION on a kvm VM handle indicates that this capability is
-available, it means that the VM is using trap & emulate.
-
-8.7 KVM_CAP_MIPS_64BIT
-
-Architectures: mips
-
-This capability indicates the supported architecture type of the guest, i.e. the
-supported register and address width.
-
-The values returned when this capability is checked by KVM_CHECK_EXTENSION on a
-kvm VM handle correspond roughly to the CP0_Config.AT register field, and should
-be checked specifically against known values (see below). All other values are
-reserved.
-
- 0: MIPS32 or microMIPS32.
-    Both registers and addresses are 32-bits wide.
-    It will only be possible to run 32-bit guest code.
-
- 1: MIPS64 or microMIPS64 with access only to 32-bit compatibility segments.
-    Registers are 64-bits wide, but addresses are 32-bits wide.
-    64-bit guest code may run but cannot access MIPS64 memory segments.
-    It will also be possible to run 32-bit guest code.
-
- 2: MIPS64 or microMIPS64 with access to all address segments.
-    Both registers and addresses are 64-bits wide.
-    It will be possible to run 64-bit or 32-bit guest code.
-
-8.9 KVM_CAP_ARM_USER_IRQ
-
-Architectures: arm, arm64
-This capability, if KVM_CHECK_EXTENSION indicates that it is available, means
-that if userspace creates a VM without an in-kernel interrupt controller, it
-will be notified of changes to the output level of in-kernel emulated devices,
-which can generate virtual interrupts, presented to the VM.
-For such VMs, on every return to userspace, the kernel
-updates the vcpu's run->s.regs.device_irq_level field to represent the actual
-output level of the device.
-
-Whenever kvm detects a change in the device output level, kvm guarantees at
-least one return to userspace before running the VM.  This exit could either
-be a KVM_EXIT_INTR or any other exit event, like KVM_EXIT_MMIO. This way,
-userspace can always sample the device output level and re-compute the state of
-the userspace interrupt controller.  Userspace should always check the state
-of run->s.regs.device_irq_level on every kvm exit.
-The value in run->s.regs.device_irq_level can represent both level and edge
-triggered interrupt signals, depending on the device.  Edge triggered interrupt
-signals will exit to userspace with the bit in run->s.regs.device_irq_level
-set exactly once per edge signal.
-
-The field run->s.regs.device_irq_level is available independent of
-run->kvm_valid_regs or run->kvm_dirty_regs bits.
-
-If KVM_CAP_ARM_USER_IRQ is supported, the KVM_CHECK_EXTENSION ioctl returns a
-number larger than 0 indicating the version of this capability is implemented
-and thereby which bits in in run->s.regs.device_irq_level can signal values.
-
-Currently the following bits are defined for the device_irq_level bitmap:
-
-  KVM_CAP_ARM_USER_IRQ >= 1:
-
-    KVM_ARM_DEV_EL1_VTIMER -  EL1 virtual timer
-    KVM_ARM_DEV_EL1_PTIMER -  EL1 physical timer
-    KVM_ARM_DEV_PMU        -  ARM PMU overflow interrupt signal
-
-Future versions of kvm may implement additional events. These will get
-indicated by returning a higher number from KVM_CHECK_EXTENSION and will be
-listed above.
-
-8.10 KVM_CAP_PPC_SMT_POSSIBLE
-
-Architectures: ppc
-
-Querying this capability returns a bitmap indicating the possible
-virtual SMT modes that can be set using KVM_CAP_PPC_SMT.  If bit N
-(counting from the right) is set, then a virtual SMT mode of 2^N is
-available.
-
-8.11 KVM_CAP_HYPERV_SYNIC2
-
-Architectures: x86
-
-This capability enables a newer version of Hyper-V Synthetic interrupt
-controller (SynIC).  The only difference with KVM_CAP_HYPERV_SYNIC is that KVM
-doesn't clear SynIC message and event flags pages when they are enabled by
-writing to the respective MSRs.
-
-8.12 KVM_CAP_HYPERV_VP_INDEX
-
-Architectures: x86
-
-This capability indicates that userspace can load HV_X64_MSR_VP_INDEX msr.  Its
-value is used to denote the target vcpu for a SynIC interrupt.  For
-compatibilty, KVM initializes this msr to KVM's internal vcpu index.  When this
-capability is absent, userspace can still query this msr's value.
-
-8.13 KVM_CAP_S390_AIS_MIGRATION
-
-Architectures: s390
-Parameters: none
-
-This capability indicates if the flic device will be able to get/set the
-AIS states for migration via the KVM_DEV_FLIC_AISM_ALL attribute and allows
-to discover this without having to create a flic device.
-
-8.14 KVM_CAP_S390_PSW
-
-Architectures: s390
-
-This capability indicates that the PSW is exposed via the kvm_run structure.
-
-8.15 KVM_CAP_S390_GMAP
-
-Architectures: s390
-
-This capability indicates that the user space memory used as guest mapping can
-be anywhere in the user memory address space, as long as the memory slots are
-aligned and sized to a segment (1MB) boundary.
-
-8.16 KVM_CAP_S390_COW
-
-Architectures: s390
-
-This capability indicates that the user space memory used as guest mapping can
-use copy-on-write semantics as well as dirty pages tracking via read-only page
-tables.
-
-8.17 KVM_CAP_S390_BPB
-
-Architectures: s390
-
-This capability indicates that kvm will implement the interfaces to handle
-reset, migration and nested KVM for branch prediction blocking. The stfle
-facility 82 should not be provided to the guest without this capability.
-
-8.18 KVM_CAP_HYPERV_TLBFLUSH
-
-Architectures: x86
-
-This capability indicates that KVM supports paravirtualized Hyper-V TLB Flush
-hypercalls:
-HvFlushVirtualAddressSpace, HvFlushVirtualAddressSpaceEx,
-HvFlushVirtualAddressList, HvFlushVirtualAddressListEx.
-
-8.19 KVM_CAP_ARM_INJECT_SERROR_ESR
-
-Architectures: arm, arm64
-
-This capability indicates that userspace can specify (via the
-KVM_SET_VCPU_EVENTS ioctl) the syndrome value reported to the guest when it
-takes a virtual SError interrupt exception.
-If KVM advertises this capability, userspace can only specify the ISS field for
-the ESR syndrome. Other parts of the ESR, such as the EC are generated by the
-CPU when the exception is taken. If this virtual SError is taken to EL1 using
-AArch64, this value will be reported in the ISS field of ESR_ELx.
-
-See KVM_CAP_VCPU_EVENTS for more details.
-8.20 KVM_CAP_HYPERV_SEND_IPI
-
-Architectures: x86
-
-This capability indicates that KVM supports paravirtualized Hyper-V IPI send
-hypercalls:
-HvCallSendSyntheticClusterIpi, HvCallSendSyntheticClusterIpiEx.
diff --git a/Documentation/virtual/kvm/hypercalls.txt b/Documentation/virtual/kvm/hypercalls.txt
deleted file mode 100644 (file)
index da21065..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-Linux KVM Hypercall:
-===================
-X86:
- KVM Hypercalls have a three-byte sequence of either the vmcall or the vmmcall
- instruction. The hypervisor can replace it with instructions that are
- guaranteed to be supported.
-
- Up to four arguments may be passed in rbx, rcx, rdx, and rsi respectively.
- The hypercall number should be placed in rax and the return value will be
- placed in rax.  No other registers will be clobbered unless explicitly stated
- by the particular hypercall.
-
-S390:
-  R2-R7 are used for parameters 1-6. In addition, R1 is used for hypercall
-  number. The return value is written to R2.
-
-  S390 uses diagnose instruction as hypercall (0x500) along with hypercall
-  number in R1.
-
-  For further information on the S390 diagnose call as supported by KVM,
-  refer to Documentation/virtual/kvm/s390-diag.txt.
-
- PowerPC:
-  It uses R3-R10 and hypercall number in R11. R4-R11 are used as output registers.
-  Return value is placed in R3.
-
-  KVM hypercalls uses 4 byte opcode, that are patched with 'hypercall-instructions'
-  property inside the device tree's /hypervisor node.
-  For more information refer to Documentation/virtual/kvm/ppc-pv.txt
-
-MIPS:
-  KVM hypercalls use the HYPCALL instruction with code 0 and the hypercall
-  number in $2 (v0). Up to four arguments may be placed in $4-$7 (a0-a3) and
-  the return value is placed in $2 (v0).
-
-KVM Hypercalls Documentation
-===========================
-The template for each hypercall is:
-1. Hypercall name.
-2. Architecture(s)
-3. Status (deprecated, obsolete, active)
-4. Purpose
-
-1. KVM_HC_VAPIC_POLL_IRQ
-------------------------
-Architecture: x86
-Status: active
-Purpose: Trigger guest exit so that the host can check for pending
-interrupts on reentry.
-
-2. KVM_HC_MMU_OP
-------------------------
-Architecture: x86
-Status: deprecated.
-Purpose: Support MMU operations such as writing to PTE,
-flushing TLB, release PT.
-
-3. KVM_HC_FEATURES
-------------------------
-Architecture: PPC
-Status: active
-Purpose: Expose hypercall availability to the guest. On x86 platforms, cpuid
-used to enumerate which hypercalls are available. On PPC, either device tree
-based lookup ( which is also what EPAPR dictates) OR KVM specific enumeration
-mechanism (which is this hypercall) can be used.
-
-4. KVM_HC_PPC_MAP_MAGIC_PAGE
-------------------------
-Architecture: PPC
-Status: active
-Purpose: To enable communication between the hypervisor and guest there is a
-shared page that contains parts of supervisor visible register state.
-The guest can map this shared page to access its supervisor register through
-memory using this hypercall.
-
-5. KVM_HC_KICK_CPU
-------------------------
-Architecture: x86
-Status: active
-Purpose: Hypercall used to wakeup a vcpu from HLT state
-Usage example : A vcpu of a paravirtualized guest that is busywaiting in guest
-kernel mode for an event to occur (ex: a spinlock to become available) can
-execute HLT instruction once it has busy-waited for more than a threshold
-time-interval. Execution of HLT instruction would cause the hypervisor to put
-the vcpu to sleep until occurrence of an appropriate event. Another vcpu of the
-same guest can wakeup the sleeping vcpu by issuing KVM_HC_KICK_CPU hypercall,
-specifying APIC ID (a1) of the vcpu to be woken up. An additional argument (a0)
-is used in the hypercall for future use.
-
-
-6. KVM_HC_CLOCK_PAIRING
-------------------------
-Architecture: x86
-Status: active
-Purpose: Hypercall used to synchronize host and guest clocks.
-Usage:
-
-a0: guest physical address where host copies
-"struct kvm_clock_offset" structure.
-
-a1: clock_type, ATM only KVM_CLOCK_PAIRING_WALLCLOCK (0)
-is supported (corresponding to the host's CLOCK_REALTIME clock).
-
-               struct kvm_clock_pairing {
-                       __s64 sec;
-                       __s64 nsec;
-                       __u64 tsc;
-                       __u32 flags;
-                       __u32 pad[9];
-               };
-
-       Where:
-               * sec: seconds from clock_type clock.
-               * nsec: nanoseconds from clock_type clock.
-               * tsc: guest TSC value used to calculate sec/nsec pair
-               * flags: flags, unused (0) at the moment.
-
-The hypercall lets a guest compute a precise timestamp across
-host and guest.  The guest can use the returned TSC value to
-compute the CLOCK_REALTIME for its clock, at the same instant.
-
-Returns KVM_EOPNOTSUPP if the host does not use TSC clocksource,
-or if clock type is different than KVM_CLOCK_PAIRING_WALLCLOCK.
-
-6. KVM_HC_SEND_IPI
-------------------------
-Architecture: x86
-Status: active
-Purpose: Send IPIs to multiple vCPUs.
-
-a0: lower part of the bitmap of destination APIC IDs
-a1: higher part of the bitmap of destination APIC IDs
-a2: the lowest APIC ID in bitmap
-a3: APIC ICR
-
-The hypercall lets a guest send multicast IPIs, with at most 128
-128 destinations per hypercall in 64-bit mode and 64 vCPUs per
-hypercall in 32-bit mode.  The destinations are represented by a
-bitmap contained in the first two arguments (a0 and a1). Bit 0 of
-a0 corresponds to the APIC ID in the third argument (a2), bit 1
-corresponds to the APIC ID a2+1, and so on.
-
-Returns the number of CPUs to which the IPIs were delivered successfully.
-
-7. KVM_HC_SCHED_YIELD
-------------------------
-Architecture: x86
-Status: active
-Purpose: Hypercall used to yield if the IPI target vCPU is preempted
-
-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.
diff --git a/Documentation/virtual/kvm/mmu.txt b/Documentation/virtual/kvm/mmu.txt
deleted file mode 100644 (file)
index 2efe0ef..0000000
+++ /dev/null
@@ -1,449 +0,0 @@
-The x86 kvm shadow mmu
-======================
-
-The mmu (in arch/x86/kvm, files mmu.[ch] and paging_tmpl.h) is responsible
-for presenting a standard x86 mmu to the guest, while translating guest
-physical addresses to host physical addresses.
-
-The mmu code attempts to satisfy the following requirements:
-
-- correctness: the guest should not be able to determine that it is running
-               on an emulated mmu except for timing (we attempt to comply
-               with the specification, not emulate the characteristics of
-               a particular implementation such as tlb size)
-- security:    the guest must not be able to touch host memory not assigned
-               to it
-- performance: minimize the performance penalty imposed by the mmu
-- scaling:     need to scale to large memory and large vcpu guests
-- hardware:    support the full range of x86 virtualization hardware
-- integration: Linux memory management code must be in control of guest memory
-               so that swapping, page migration, page merging, transparent
-               hugepages, and similar features work without change
-- dirty tracking: report writes to guest memory to enable live migration
-               and framebuffer-based displays
-- footprint:   keep the amount of pinned kernel memory low (most memory
-               should be shrinkable)
-- reliability:  avoid multipage or GFP_ATOMIC allocations
-
-Acronyms
-========
-
-pfn   host page frame number
-hpa   host physical address
-hva   host virtual address
-gfn   guest frame number
-gpa   guest physical address
-gva   guest virtual address
-ngpa  nested guest physical address
-ngva  nested guest virtual address
-pte   page table entry (used also to refer generically to paging structure
-      entries)
-gpte  guest pte (referring to gfns)
-spte  shadow pte (referring to pfns)
-tdp   two dimensional paging (vendor neutral term for NPT and EPT)
-
-Virtual and real hardware supported
-===================================
-
-The mmu supports first-generation mmu hardware, which allows an atomic switch
-of the current paging mode and cr3 during guest entry, as well as
-two-dimensional paging (AMD's NPT and Intel's EPT).  The emulated hardware
-it exposes is the traditional 2/3/4 level x86 mmu, with support for global
-pages, pae, pse, pse36, cr0.wp, and 1GB pages. Emulated hardware also
-able to expose NPT capable hardware on NPT capable hosts.
-
-Translation
-===========
-
-The primary job of the mmu is to program the processor's mmu to translate
-addresses for the guest.  Different translations are required at different
-times:
-
-- when guest paging is disabled, we translate guest physical addresses to
-  host physical addresses (gpa->hpa)
-- when guest paging is enabled, we translate guest virtual addresses, to
-  guest physical addresses, to host physical addresses (gva->gpa->hpa)
-- when the guest launches a guest of its own, we translate nested guest
-  virtual addresses, to nested guest physical addresses, to guest physical
-  addresses, to host physical addresses (ngva->ngpa->gpa->hpa)
-
-The primary challenge is to encode between 1 and 3 translations into hardware
-that support only 1 (traditional) and 2 (tdp) translations.  When the
-number of required translations matches the hardware, the mmu operates in
-direct mode; otherwise it operates in shadow mode (see below).
-
-Memory
-======
-
-Guest memory (gpa) is part of the user address space of the process that is
-using kvm.  Userspace defines the translation between guest addresses and user
-addresses (gpa->hva); note that two gpas may alias to the same hva, but not
-vice versa.
-
-These hvas may be backed using any method available to the host: anonymous
-memory, file backed memory, and device memory.  Memory might be paged by the
-host at any time.
-
-Events
-======
-
-The mmu is driven by events, some from the guest, some from the host.
-
-Guest generated events:
-- writes to control registers (especially cr3)
-- invlpg/invlpga instruction execution
-- access to missing or protected translations
-
-Host generated events:
-- changes in the gpa->hpa translation (either through gpa->hva changes or
-  through hva->hpa changes)
-- memory pressure (the shrinker)
-
-Shadow pages
-============
-
-The principal data structure is the shadow page, 'struct kvm_mmu_page'.  A
-shadow page contains 512 sptes, which can be either leaf or nonleaf sptes.  A
-shadow page may contain a mix of leaf and nonleaf sptes.
-
-A nonleaf spte allows the hardware mmu to reach the leaf pages and
-is not related to a translation directly.  It points to other shadow pages.
-
-A leaf spte corresponds to either one or two translations encoded into
-one paging structure entry.  These are always the lowest level of the
-translation stack, with optional higher level translations left to NPT/EPT.
-Leaf ptes point at guest pages.
-
-The following table shows translations encoded by leaf ptes, with higher-level
-translations in parentheses:
-
- Non-nested guests:
-  nonpaging:     gpa->hpa
-  paging:        gva->gpa->hpa
-  paging, tdp:   (gva->)gpa->hpa
- Nested guests:
-  non-tdp:       ngva->gpa->hpa  (*)
-  tdp:           (ngva->)ngpa->gpa->hpa
-
-(*) the guest hypervisor will encode the ngva->gpa translation into its page
-    tables if npt is not present
-
-Shadow pages contain the following information:
-  role.level:
-    The level in the shadow paging hierarchy that this shadow page belongs to.
-    1=4k sptes, 2=2M sptes, 3=1G sptes, etc.
-  role.direct:
-    If set, leaf sptes reachable from this page are for a linear range.
-    Examples include real mode translation, large guest pages backed by small
-    host pages, and gpa->hpa translations when NPT or EPT is active.
-    The linear range starts at (gfn << PAGE_SHIFT) and its size is determined
-    by role.level (2MB for first level, 1GB for second level, 0.5TB for third
-    level, 256TB for fourth level)
-    If clear, this page corresponds to a guest page table denoted by the gfn
-    field.
-  role.quadrant:
-    When role.gpte_is_8_bytes=0, the guest uses 32-bit gptes while the host uses 64-bit
-    sptes.  That means a guest page table contains more ptes than the host,
-    so multiple shadow pages are needed to shadow one guest page.
-    For first-level shadow pages, role.quadrant can be 0 or 1 and denotes the
-    first or second 512-gpte block in the guest page table.  For second-level
-    page tables, each 32-bit gpte is converted to two 64-bit sptes
-    (since each first-level guest page is shadowed by two first-level
-    shadow pages) so role.quadrant takes values in the range 0..3.  Each
-    quadrant maps 1GB virtual address space.
-  role.access:
-    Inherited guest access permissions in the form uwx.  Note execute
-    permission is positive, not negative.
-  role.invalid:
-    The page is invalid and should not be used.  It is a root page that is
-    currently pinned (by a cpu hardware register pointing to it); once it is
-    unpinned it will be destroyed.
-  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.cr0_wp:
-    Contains the value of cr0.wp for which the page is valid.
-  role.smep_andnot_wp:
-    Contains the value of cr4.smep && !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.smap_andnot_wp:
-    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
-    shadow page; it is also used to go back from a struct kvm_mmu_page
-    to a memslot, through the kvm_memslots_for_spte_role macro and
-    __gfn_to_memslot.
-  role.ad_disabled:
-    Is 1 if the MMU instance cannot use A/D bits.  EPT did not have A/D
-    bits before Haswell; shadow EPT page tables also cannot use A/D bits
-    if the L1 hypervisor does not enable them.
-  gfn:
-    Either the guest page table containing the translations shadowed by this
-    page, or the base page frame for linear translations.  See role.direct.
-  spt:
-    A pageful of 64-bit sptes containing the translations for this page.
-    Accessed by both kvm and hardware.
-    The page pointed to by spt will have its page->private pointing back
-    at the shadow page structure.
-    sptes in spt point either at guest pages, or at lower-level shadow pages.
-    Specifically, if sp1 and sp2 are shadow pages, then sp1->spt[n] may point
-    at __pa(sp2->spt).  sp2 will point back at sp1 through parent_pte.
-    The spt array forms a DAG structure with the shadow page as a node, and
-    guest pages as leaves.
-  gfns:
-    An array of 512 guest frame numbers, one for each present pte.  Used to
-    perform a reverse map from a pte to a gfn. When role.direct is set, any
-    element of this array can be calculated from the gfn field when used, in
-    this case, the array of gfns is not allocated. See role.direct and gfn.
-  root_count:
-    A counter keeping track of how many hardware registers (guest cr3 or
-    pdptrs) are now pointing at the page.  While this counter is nonzero, the
-    page cannot be destroyed.  See role.invalid.
-  parent_ptes:
-    The reverse mapping for the pte/ptes pointing at this page's spt. If
-    parent_ptes bit 0 is zero, only one spte points at this page and
-    parent_ptes points at this single spte, otherwise, there exists multiple
-    sptes pointing at this page and (parent_ptes & ~0x1) points at a data
-    structure with a list of parent sptes.
-  unsync:
-    If true, then the translations in this page may not match the guest's
-    translation.  This is equivalent to the state of the tlb when a pte is
-    changed but before the tlb entry is flushed.  Accordingly, unsync ptes
-    are synchronized when the guest executes invlpg or flushes its tlb by
-    other means.  Valid for leaf pages.
-  unsync_children:
-    How many sptes in the page point at pages that are unsync (or have
-    unsynchronized children).
-  unsync_child_bitmap:
-    A bitmap indicating which sptes in spt point (directly or indirectly) at
-    pages that may be unsynchronized.  Used to quickly locate all unsychronized
-    pages reachable from a given page.
-  clear_spte_count:
-    Only present on 32-bit hosts, where a 64-bit spte cannot be written
-    atomically.  The reader uses this while running out of the MMU lock
-    to detect in-progress updates and retry them until the writer has
-    finished the write.
-  write_flooding_count:
-    A guest may write to a page table many times, causing a lot of
-    emulations if the page needs to be write-protected (see "Synchronized
-    and unsynchronized pages" below).  Leaf pages can be unsynchronized
-    so that they do not trigger frequent emulation, but this is not
-    possible for non-leafs.  This field counts the number of emulations
-    since the last time the page table was actually used; if emulation
-    is triggered too frequently on this page, KVM will unmap the page
-    to avoid emulation in the future.
-
-Reverse map
-===========
-
-The mmu maintains a reverse mapping whereby all ptes mapping a page can be
-reached given its gfn.  This is used, for example, when swapping out a page.
-
-Synchronized and unsynchronized pages
-=====================================
-
-The guest uses two events to synchronize its tlb and page tables: tlb flushes
-and page invalidations (invlpg).
-
-A tlb flush means that we need to synchronize all sptes reachable from the
-guest's cr3.  This is expensive, so we keep all guest page tables write
-protected, and synchronize sptes to gptes when a gpte is written.
-
-A special case is when a guest page table is reachable from the current
-guest cr3.  In this case, the guest is obliged to issue an invlpg instruction
-before using the translation.  We take advantage of that by removing write
-protection from the guest page, and allowing the guest to modify it freely.
-We synchronize modified gptes when the guest invokes invlpg.  This reduces
-the amount of emulation we have to do when the guest modifies multiple gptes,
-or when the a guest page is no longer used as a page table and is used for
-random guest data.
-
-As a side effect we have to resynchronize all reachable unsynchronized shadow
-pages on a tlb flush.
-
-
-Reaction to events
-==================
-
-- guest page fault (or npt page fault, or ept violation)
-
-This is the most complicated event.  The cause of a page fault can be:
-
-  - a true guest fault (the guest translation won't allow the access) (*)
-  - access to a missing translation
-  - access to a protected translation
-    - when logging dirty pages, memory is write protected
-    - synchronized shadow pages are write protected (*)
-  - access to untranslatable memory (mmio)
-
-  (*) not applicable in direct mode
-
-Handling a page fault is performed as follows:
-
- - if the RSV bit of the error code is set, the page fault is caused by guest
-   accessing MMIO and cached MMIO information is available.
-   - walk shadow page table
-   - check for valid generation number in the spte (see "Fast invalidation of
-     MMIO sptes" below)
-   - cache the information to vcpu->arch.mmio_gva, vcpu->arch.access and
-     vcpu->arch.mmio_gfn, and call the emulator
- - If both P bit and R/W bit of error code are set, this could possibly
-   be handled as a "fast page fault" (fixed without taking the MMU lock).  See
-   the description in Documentation/virtual/kvm/locking.txt.
- - if needed, walk the guest page tables to determine the guest translation
-   (gva->gpa or ngpa->gpa)
-   - if permissions are insufficient, reflect the fault back to the guest
- - determine the host page
-   - if this is an mmio request, there is no host page; cache the info to
-     vcpu->arch.mmio_gva, vcpu->arch.access and vcpu->arch.mmio_gfn
- - walk the shadow page table to find the spte for the translation,
-   instantiating missing intermediate page tables as necessary
-   - If this is an mmio request, cache the mmio info to the spte and set some
-     reserved bit on the spte (see callers of kvm_mmu_set_mmio_spte_mask)
- - try to unsynchronize the page
-   - if successful, we can let the guest continue and modify the gpte
- - emulate the instruction
-   - if failed, unshadow the page and let the guest continue
- - update any translations that were modified by the instruction
-
-invlpg handling:
-
-  - walk the shadow page hierarchy and drop affected translations
-  - try to reinstantiate the indicated translation in the hope that the
-    guest will use it in the near future
-
-Guest control register updates:
-
-- mov to cr3
-  - look up new shadow roots
-  - synchronize newly reachable shadow pages
-
-- mov to cr0/cr4/efer
-  - set up mmu context for new paging mode
-  - look up new shadow roots
-  - synchronize newly reachable shadow pages
-
-Host translation updates:
-
-  - mmu notifier called with updated hva
-  - look up affected sptes through reverse map
-  - drop (or update) translations
-
-Emulating cr0.wp
-================
-
-If tdp is not enabled, the host must keep cr0.wp=1 so page write protection
-works for the guest kernel, not guest guest userspace.  When the guest
-cr0.wp=1, this does not present a problem.  However when the guest cr0.wp=0,
-we cannot map the permissions for gpte.u=1, gpte.w=0 to any spte (the
-semantics require allowing any guest kernel access plus user read access).
-
-We handle this by mapping the permissions to two possible sptes, depending
-on fault type:
-
-- kernel write fault: spte.u=0, spte.w=1 (allows full kernel access,
-  disallows user access)
-- read fault: spte.u=1, spte.w=0 (allows full read access, disallows kernel
-  write access)
-
-(user write faults generate a #PF)
-
-In the first case there are two additional complications:
-- if CR4.SMEP is enabled: since we've turned the page into a kernel page,
-  the kernel may now execute it.  We handle this by also setting spte.nx.
-  If we get a user fetch or read fault, we'll change spte.u=1 and
-  spte.nx=gpte.nx back.  For this to work, KVM forces EFER.NX to 1 when
-  shadow paging is in use.
-- if CR4.SMAP is disabled: since the page has been changed to a kernel
-  page, it can not be reused when CR4.SMAP is enabled. We set
-  CR4.SMAP && !CR0.WP into shadow page's role to avoid this case. Note,
-  here we do not care the case that CR4.SMAP is enabled since KVM will
-  directly inject #PF to guest due to failed permission check.
-
-To prevent an spte that was converted into a kernel page with cr0.wp=0
-from being written by the kernel after cr0.wp has changed to 1, we make
-the value of cr0.wp part of the page role.  This means that an spte created
-with one value of cr0.wp cannot be used when cr0.wp has a different value -
-it will simply be missed by the shadow page lookup code.  A similar issue
-exists when an spte created with cr0.wp=0 and cr4.smep=0 is used after
-changing cr4.smep to 1.  To avoid this, the value of !cr0.wp && cr4.smep
-is also made a part of the page role.
-
-Large pages
-===========
-
-The mmu supports all combinations of large and small guest and host pages.
-Supported page sizes include 4k, 2M, 4M, and 1G.  4M pages are treated as
-two separate 2M pages, on both guest and host, since the mmu always uses PAE
-paging.
-
-To instantiate a large spte, four constraints must be satisfied:
-
-- the spte must point to a large host page
-- the guest pte must be a large pte of at least equivalent size (if tdp is
-  enabled, there is no guest pte and this condition is satisfied)
-- if the spte will be writeable, the large page frame may not overlap any
-  write-protected pages
-- the guest page must be wholly contained by a single memory slot
-
-To check the last two conditions, the mmu maintains a ->disallow_lpage set of
-arrays for each memory slot and large page size.  Every write protected page
-causes its disallow_lpage to be incremented, thus preventing instantiation of
-a large spte.  The frames at the end of an unaligned memory slot have
-artificially inflated ->disallow_lpages so they can never be instantiated.
-
-Fast invalidation of MMIO sptes
-===============================
-
-As mentioned in "Reaction to events" above, kvm will cache MMIO
-information in leaf sptes.  When a new memslot is added or an existing
-memslot is changed, this information may become stale and needs to be
-invalidated.  This also needs to hold the MMU lock while walking all
-shadow pages, and is made more scalable with a similar technique.
-
-MMIO sptes have a few spare bits, which are used to store a
-generation number.  The global generation number is stored in
-kvm_memslots(kvm)->generation, and increased whenever guest memory info
-changes.
-
-When KVM finds an MMIO spte, it checks the generation number of the spte.
-If the generation number of the spte does not equal the global generation
-number, it will ignore the cached MMIO information and handle the page
-fault through the slow path.
-
-Since only 19 bits are used to store generation-number on mmio spte, all
-pages are zapped when there is an overflow.
-
-Unfortunately, a single memory access might access kvm_memslots(kvm) multiple
-times, the last one happening when the generation number is retrieved and
-stored into the MMIO spte.  Thus, the MMIO spte might be created based on
-out-of-date information, but with an up-to-date generation number.
-
-To avoid this, the generation number is incremented again after synchronize_srcu
-returns; thus, bit 63 of kvm_memslots(kvm)->generation set to 1 only during a
-memslot update, while some SRCU readers might be using the old copy.  We do not
-want to use an MMIO sptes created with an odd generation number, and we can do
-this without losing a bit in the MMIO spte.  The "update in-progress" bit of the
-generation is not stored in MMIO spte, and is so is implicitly zero when the
-generation is extracted out of the spte.  If KVM is unlucky and creates an MMIO
-spte while an update is in-progress, the next access to the spte will always be
-a cache miss.  For example, a subsequent access during the update window will
-miss due to the in-progress flag diverging, while an access after the update
-window closes will have a higher generation number (as compared to the spte).
-
-
-Further reading
-===============
-
-- NPT presentation from KVM Forum 2008
-  http://www.linux-kvm.org/images/c/c8/KvmForum2008%24kdf2008_21.pdf
-
diff --git a/Documentation/virtual/kvm/review-checklist.txt b/Documentation/virtual/kvm/review-checklist.txt
deleted file mode 100644 (file)
index a83b276..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-Review checklist for kvm patches
-================================
-
-1.  The patch must follow Documentation/process/coding-style.rst and
-    Documentation/process/submitting-patches.rst.
-
-2.  Patches should be against kvm.git master branch.
-
-3.  If the patch introduces or modifies a new userspace API:
-    - the API must be documented in Documentation/virtual/kvm/api.txt
-    - the API must be discoverable using KVM_CHECK_EXTENSION
-
-4.  New state must include support for save/restore.
-
-5.  New features must default to off (userspace should explicitly request them).
-    Performance improvements can and should default to on.
-
-6.  New cpu features should be exposed via KVM_GET_SUPPORTED_CPUID2
-
-7.  Emulator changes should be accompanied by unit tests for qemu-kvm.git
-    kvm/test directory.
-
-8.  Changes should be vendor neutral when possible.  Changes to common code
-    are better than duplicating changes to vendor code.
-
-9.  Similarly, prefer changes to arch independent code than to arch dependent
-    code.
-
-10. User/kernel interfaces and guest/host interfaces must be 64-bit clean
-    (all variables and sizes naturally aligned on 64-bit; use specific types
-    only - u64 rather than ulong).
-
-11. New guest visible features must either be documented in a hardware manual
-    or be accompanied by documentation.
-
-12. Features must be robust against reset and kexec - for example, shared
-    host/guest memory must be unshared to prevent the host from writing to
-    guest memory that the guest has not reserved for this purpose.
index 382f72a..58a1237 100644 (file)
@@ -181,3 +181,43 @@ that is eventually passed to vmemmap_populate() through a long chain
 of function calls. The vmemmap_populate() implementation may use the
 `vmem_altmap` along with :c:func:`altmap_alloc_block_buf` helper to
 allocate memory map on the persistent memory device.
+
+ZONE_DEVICE
+===========
+The `ZONE_DEVICE` facility builds upon `SPARSEMEM_VMEMMAP` to offer
+`struct page` `mem_map` services for device driver identified physical
+address ranges. The "device" aspect of `ZONE_DEVICE` relates to the fact
+that the page objects for these address ranges are never marked online,
+and that a reference must be taken against the device, not just the page
+to keep the memory pinned for active use. `ZONE_DEVICE`, via
+:c:func:`devm_memremap_pages`, performs just enough memory hotplug to
+turn on :c:func:`pfn_to_page`, :c:func:`page_to_pfn`, and
+:c:func:`get_user_pages` service for the given range of pfns. Since the
+page reference count never drops below 1 the page is never tracked as
+free memory and the page's `struct list_head lru` space is repurposed
+for back referencing to the host device / driver that mapped the memory.
+
+While `SPARSEMEM` presents memory as a collection of sections,
+optionally collected into memory blocks, `ZONE_DEVICE` users have a need
+for smaller granularity of populating the `mem_map`. Given that
+`ZONE_DEVICE` memory is never marked online it is subsequently never
+subject to its memory ranges being exposed through the sysfs memory
+hotplug api on memory block boundaries. The implementation relies on
+this lack of user-api constraint to allow sub-section sized memory
+ranges to be specified to :c:func:`arch_add_memory`, the top-half of
+memory hotplug. Sub-section support allows for 2MB as the cross-arch
+common alignment granularity for :c:func:`devm_memremap_pages`.
+
+The users of `ZONE_DEVICE` are:
+
+* pmem: Map platform persistent memory to be used as a direct-I/O target
+  via DAX mappings.
+
+* hmm: Extend `ZONE_DEVICE` with `->page_fault()` and `->page_free()`
+  event callbacks to allow a device-driver to coordinate memory management
+  events related to device-memory, typically GPU memory. See
+  Documentation/vm/hmm.rst.
+
+* p2pdma: Create `struct page` objects to allow peer devices in a
+  PCI/-E topology to coordinate direct-DMA operations between themselves,
+  i.e. bypass host memory.
index 130f3cf..99fdeca 100644 (file)
@@ -67,7 +67,7 @@ nodes.  Each emulated node will manage a fraction of the underlying cells'
 physical memory.  NUMA emluation is useful for testing NUMA kernel and
 application features on non-NUMA platforms, and as a sort of memory resource
 management mechanism when used together with cpusets.
-[see Documentation/cgroup-v1/cpusets.rst]
+[see Documentation/admin-guide/cgroup-v1/cpusets.rst]
 
 For each node with memory, Linux constructs an independent memory management
 subsystem, complete with its own free page lists, in-use page lists, usage
@@ -114,7 +114,7 @@ allocation behavior using Linux NUMA memory policy. [see
 
 System administrators can restrict the CPUs and nodes' memories that a non-
 privileged user can specify in the scheduling or NUMA commands and functions
-using control groups and CPUsets.  [see Documentation/cgroup-v1/cpusets.rst]
+using control groups and CPUsets.  [see Documentation/admin-guide/cgroup-v1/cpusets.rst]
 
 On architectures that do not hide memoryless nodes, Linux will include only
 zones [nodes] with memory in the zonelists.  This means that for a memoryless
index 35bba27..1d6cd7d 100644 (file)
@@ -41,7 +41,7 @@ locations.
 Larger installations usually partition the system using cpusets into
 sections of nodes. Paul Jackson has equipped cpusets with the ability to
 move pages when a task is moved to another cpuset (See
-Documentation/cgroup-v1/cpusets.rst).
+Documentation/admin-guide/cgroup-v1/cpusets.rst).
 Cpusets allows the automation of process locality. If a task is moved to
 a new cpuset then also all its pages are moved with it so that the
 performance of the process does not sink dramatically. Also the pages
index c6d9411..17d0861 100644 (file)
@@ -98,7 +98,7 @@ Memory Control Group Interaction
 --------------------------------
 
 The unevictable LRU facility interacts with the memory control group [aka
-memory controller; see Documentation/cgroup-v1/memory.rst] by extending the
+memory controller; see Documentation/admin-guide/cgroup-v1/memory.rst] by extending the
 lru_list enum.
 
 The memory controller data structure automatically gets a per-zone unevictable
@@ -439,7 +439,7 @@ Compacting MLOCKED Pages
 
 The unevictable LRU can be scanned for compactable regions and the default
 behavior is to do so.  /proc/sys/vm/compact_unevictable_allowed controls
-this behavior (see Documentation/sysctl/vm.txt).  Once scanning of the
+this behavior (see Documentation/admin-guide/sysctl/vm.rst).  Once scanning of the
 unevictable LRU is enabled, the work of compaction is mostly handled by
 the page migration code and the same work flow as described in MIGRATING
 MLOCKED PAGES will apply.
index ef27271..94ad4c4 100644 (file)
@@ -183,7 +183,7 @@ acknowledge number is set to seq+1.
 Additional documantion, source code examples.
 ============================================
 
-1. Documentation/connector
+1. Documentation/driver-api/connector.rst
 2. http://www.ioremap.net/archive/w1
 This archive includes userspace application w1d.c which uses
 read/write/search commands for all master/slave devices found on the bus.
index 94a9637..c165d92 100644 (file)
@@ -39,6 +39,10 @@ Last reviewed: 08/20/2018
                Default value is set when compiling the kernel. If it is set
                to "Y", then there is no way of disabling the watchdog once
                it has been started.
+ kdumptimeout  Minimum timeout in seconds to apply upon receipt of an NMI
+               before calling panic. (-1) disables the watchdog.  When value
+               is > 0, the timer is reprogrammed with the greater of
+               value or current timeout value.
  ============  ================================================================
 
  NOTE:
index 33a0de6..c177645 100644 (file)
@@ -1,4 +1,4 @@
-:orphan:
+.. SPDX-License-Identifier: GPL-2.0
 
 ======================
 Linux Watchdog Support
index b121caa..a3985cc 100644 (file)
@@ -13,6 +13,17 @@ modules.
 
 -------------------------------------------------
 
+watchdog core:
+    open_timeout:
+       Maximum time, in seconds, for which the watchdog framework will take
+       care of pinging a running hardware watchdog until userspace opens the
+       corresponding /dev/watchdogN device. A value of 0 means an infinite
+       timeout. Setting this to a non-zero value can be useful to ensure that
+       either userspace comes up properly, or the board gets reset and allows
+       fallback logic in the bootloader to try something else.
+
+-------------------------------------------------
+
 acquirewdt:
     wdt_stop:
        Acquire WDT 'stop' io port (default 0x43)
index f2de1b2..af64c4b 100644 (file)
@@ -20,6 +20,8 @@ x86-specific Documentation
    mtrr
    pat
    intel_mpx
+   intel-iommu
+   intel_txt
    amd-memory-encryption
    pti
    mds
index 8e9704f..e297399 100644 (file)
@@ -9,7 +9,7 @@ representation in the kernel. Update/change when doing changes to the
 respective code.
 
 The architecture-agnostic topology definitions are in
-Documentation/cputopology.txt. This file holds x86-specific
+Documentation/admin-guide/cputopology.rst. This file holds x86-specific
 differences/specialities which must not necessarily apply to the generic
 definitions. Thus, the way to read up on Linux topology on x86 is to start
 with the generic one and look at this one in parallel for the x86 specifics.
index 3010868..ff9bcfd 100644 (file)
@@ -15,7 +15,7 @@ assign them to cpusets and their attached tasks.  This is a way of limiting the
 amount of system memory that are available to a certain class of tasks.
 
 For more information on the features of cpusets, see
-Documentation/cgroup-v1/cpusets.rst.
+Documentation/admin-guide/cgroup-v1/cpusets.rst.
 There are a number of different configurations you can use for your needs.  For
 more information on the numa=fake command line option and its various ways of
 configuring fake nodes, see Documentation/x86/x86_64/boot-options.rst.
@@ -40,7 +40,7 @@ A machine may be split as follows with "numa=fake=4*512," as reported by dmesg::
        On node 3 totalpages: 131072
 
 Now following the instructions for mounting the cpusets filesystem from
-Documentation/cgroup-v1/cpusets.rst, you can assign fake nodes (i.e. contiguous memory
+Documentation/admin-guide/cgroup-v1/cpusets.rst, you can assign fake nodes (i.e. contiguous memory
 address spaces) to individual cpusets::
 
        [root@xroads /]# mkdir exampleset
diff --git a/Documentation/xilinx/index.rst b/Documentation/xilinx/index.rst
deleted file mode 100644 (file)
index 01cc1a0..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-:orphan:
-
-===========
-Xilinx FPGA
-===========
-
-.. toctree::
-    :maxdepth: 1
-
-    eemi
-
-.. only::  subproject and html
-
-   Indices
-   =======
-
-   * :ref:`genindex`
diff --git a/Documentation/xtensa/atomctl.rst b/Documentation/xtensa/atomctl.rst
new file mode 100644 (file)
index 0000000..1ecbd0b
--- /dev/null
@@ -0,0 +1,51 @@
+===========================================
+Atomic Operation Control (ATOMCTL) Register
+===========================================
+
+We Have Atomic Operation Control (ATOMCTL) Register.
+This register determines the effect of using a S32C1I instruction
+with various combinations of:
+
+     1. With and without an Coherent Cache Controller which
+        can do Atomic Transactions to the memory internally.
+
+     2. With and without An Intelligent Memory Controller which
+        can do Atomic Transactions itself.
+
+The Core comes up with a default value of for the three types of cache ops::
+
+      0x28: (WB: Internal, WT: Internal, BY:Exception)
+
+On the FPGA Cards we typically simulate an Intelligent Memory controller
+which can implement  RCW transactions. For FPGA cards with an External
+Memory controller we let it to the atomic operations internally while
+doing a Cached (WB) transaction and use the Memory RCW for un-cached
+operations.
+
+For systems without an coherent cache controller, non-MX, we always
+use the memory controllers RCW, thought non-MX controlers likely
+support the Internal Operation.
+
+CUSTOMER-WARNING:
+   Virtually all customers buy their memory controllers from vendors that
+   don't support atomic RCW memory transactions and will likely want to
+   configure this register to not use RCW.
+
+Developers might find using RCW in Bypass mode convenient when testing
+with the cache being bypassed; for example studying cache alias problems.
+
+See Section 4.3.12.4 of ISA; Bits::
+
+                             WB     WT      BY
+                           5   4 | 3   2 | 1   0
+
+=========    ==================      ==================      ===============
+  2 Bit
+  Field
+  Values     WB - Write Back         WT - Write Thru         BY - Bypass
+=========    ==================      ==================      ===============
+    0        Exception               Exception               Exception
+    1        RCW Transaction         RCW Transaction         RCW Transaction
+    2        Internal Operation      Internal Operation      Reserved
+    3        Reserved                Reserved                Reserved
+=========    ==================      ==================      ===============
diff --git a/Documentation/xtensa/atomctl.txt b/Documentation/xtensa/atomctl.txt
deleted file mode 100644 (file)
index 1da783a..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-We Have Atomic Operation Control (ATOMCTL) Register.
-This register determines the effect of using a S32C1I instruction
-with various combinations of:
-
-     1. With and without an Coherent Cache Controller which
-        can do Atomic Transactions to the memory internally.
-
-     2. With and without An Intelligent Memory Controller which
-        can do Atomic Transactions itself.
-
-The Core comes up with a default value of for the three types of cache ops:
-
-      0x28: (WB: Internal, WT: Internal, BY:Exception)
-
-On the FPGA Cards we typically simulate an Intelligent Memory controller
-which can implement  RCW transactions. For FPGA cards with an External
-Memory controller we let it to the atomic operations internally while
-doing a Cached (WB) transaction and use the Memory RCW for un-cached
-operations.
-
-For systems without an coherent cache controller, non-MX, we always
-use the memory controllers RCW, thought non-MX controlers likely
-support the Internal Operation.
-
-CUSTOMER-WARNING:
-   Virtually all customers buy their memory controllers from vendors that
-   don't support atomic RCW memory transactions and will likely want to
-   configure this register to not use RCW.
-
-Developers might find using RCW in Bypass mode convenient when testing
-with the cache being bypassed; for example studying cache alias problems.
-
-See Section 4.3.12.4 of ISA; Bits:
-
-                             WB     WT      BY
-                           5   4 | 3   2 | 1   0
-  2 Bit
-  Field
-  Values     WB - Write Back         WT - Write Thru         BY - Bypass
----------    ---------------         -----------------     ----------------
-    0        Exception               Exception               Exception
-    1        RCW Transaction         RCW Transaction         RCW Transaction
-    2        Internal Operation      Internal Operation      Reserved
-    3        Reserved                Reserved                Reserved
diff --git a/Documentation/xtensa/booting.rst b/Documentation/xtensa/booting.rst
new file mode 100644 (file)
index 0000000..e1b8370
--- /dev/null
@@ -0,0 +1,22 @@
+=====================================
+Passing boot parameters to the kernel
+=====================================
+
+Boot parameters are represented as a TLV list in the memory. Please see
+arch/xtensa/include/asm/bootparam.h for definition of the bp_tag structure and
+tag value constants. First entry in the list must have type BP_TAG_FIRST, last
+entry must have type BP_TAG_LAST. The address of the first list entry is
+passed to the kernel in the register a2. The address type depends on MMU type:
+
+- For configurations without MMU, with region protection or with MPU the
+  address must be the physical address.
+- For configurations with region translarion MMU or with MMUv3 and CONFIG_MMU=n
+  the address must be a valid address in the current mapping. The kernel will
+  not change the mapping on its own.
+- For configurations with MMUv2 the address must be a virtual address in the
+  default virtual mapping (0xd0000000..0xffffffff).
+- For configurations with MMUv3 and CONFIG_MMU=y the address may be either a
+  virtual or physical address. In either case it must be within the default
+  virtual mapping. It is considered physical if it is within the range of
+  physical addresses covered by the default KSEG mapping (XCHAL_KSEG_PADDR..
+  XCHAL_KSEG_PADDR + XCHAL_KSEG_SIZE), otherwise it is considered virtual.
diff --git a/Documentation/xtensa/booting.txt b/Documentation/xtensa/booting.txt
deleted file mode 100644 (file)
index 402b33a..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-Passing boot parameters to the kernel.
-
-Boot parameters are represented as a TLV list in the memory. Please see
-arch/xtensa/include/asm/bootparam.h for definition of the bp_tag structure and
-tag value constants. First entry in the list must have type BP_TAG_FIRST, last
-entry must have type BP_TAG_LAST. The address of the first list entry is
-passed to the kernel in the register a2. The address type depends on MMU type:
-- For configurations without MMU, with region protection or with MPU the
-  address must be the physical address.
-- For configurations with region translarion MMU or with MMUv3 and CONFIG_MMU=n
-  the address must be a valid address in the current mapping. The kernel will
-  not change the mapping on its own.
-- For configurations with MMUv2 the address must be a virtual address in the
-  default virtual mapping (0xd0000000..0xffffffff).
-- For configurations with MMUv3 and CONFIG_MMU=y the address may be either a
-  virtual or physical address. In either case it must be within the default
-  virtual mapping. It is considered physical if it is within the range of
-  physical addresses covered by the default KSEG mapping (XCHAL_KSEG_PADDR..
-  XCHAL_KSEG_PADDR + XCHAL_KSEG_SIZE), otherwise it is considered virtual.
diff --git a/Documentation/xtensa/index.rst b/Documentation/xtensa/index.rst
new file mode 100644 (file)
index 0000000..52fa04e
--- /dev/null
@@ -0,0 +1,12 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===================
+Xtensa Architecture
+===================
+
+.. toctree::
+   :maxdepth: 1
+
+   atomctl
+   booting
+   mmu
diff --git a/Documentation/xtensa/mmu.rst b/Documentation/xtensa/mmu.rst
new file mode 100644 (file)
index 0000000..e52a129
--- /dev/null
@@ -0,0 +1,195 @@
+=============================
+MMUv3 initialization sequence
+=============================
+
+The code in the initialize_mmu macro sets up MMUv3 memory mapping
+identically to MMUv2 fixed memory mapping. Depending on
+CONFIG_INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX symbol this code is
+located in addresses it was linked for (symbol undefined), or not
+(symbol defined), so it needs to be position-independent.
+
+The code has the following assumptions:
+
+  - This code fragment is run only on an MMU v3.
+  - TLBs are in their reset state.
+  - ITLBCFG and DTLBCFG are zero (reset state).
+  - RASID is 0x04030201 (reset state).
+  - PS.RING is zero (reset state).
+  - LITBASE is zero (reset state, PC-relative literals); required to be PIC.
+
+TLB setup proceeds along the following steps.
+
+  Legend:
+
+    - VA = virtual address (two upper nibbles of it);
+    - PA = physical address (two upper nibbles of it);
+    - pc = physical range that contains this code;
+
+After step 2, we jump to virtual address in the range 0x40000000..0x5fffffff
+or 0x00000000..0x1fffffff, depending on whether the kernel was loaded below
+0x40000000 or above. That address corresponds to next instruction to execute
+in this code. After step 4, we jump to intended (linked) address of this code.
+The scheme below assumes that the kernel is loaded below 0x40000000.
+
+ ====== =====  =====  =====  =====   ====== =====  =====
+ -      Step0  Step1  Step2  Step3          Step4  Step5
+
+   VA      PA     PA     PA     PA     VA      PA     PA
+ ====== =====  =====  =====  =====   ====== =====  =====
+ E0..FF -> E0  -> E0  -> E0          F0..FF -> F0  -> F0
+ C0..DF -> C0  -> C0  -> C0          E0..EF -> F0  -> F0
+ A0..BF -> A0  -> A0  -> A0          D8..DF -> 00  -> 00
+ 80..9F -> 80  -> 80  -> 80          D0..D7 -> 00  -> 00
+ 60..7F -> 60  -> 60  -> 60
+ 40..5F -> 40         -> pc  -> pc   40..5F -> pc
+ 20..3F -> 20  -> 20  -> 20
+ 00..1F -> 00  -> 00  -> 00
+ ====== =====  =====  =====  =====   ====== =====  =====
+
+The default location of IO peripherals is above 0xf0000000. This may be changed
+using a "ranges" property in a device tree simple-bus node. See the Devicetree
+Specification, section 4.5 for details on the syntax and semantics of
+simple-bus nodes. The following limitations apply:
+
+1. Only top level simple-bus nodes are considered
+
+2. Only one (first) simple-bus node is considered
+
+3. Empty "ranges" properties are not supported
+
+4. Only the first triplet in the "ranges" property is considered
+
+5. The parent-bus-address value is rounded down to the nearest 256MB boundary
+
+6. The IO area covers the entire 256MB segment of parent-bus-address; the
+   "ranges" triplet length field is ignored
+
+
+MMUv3 address space layouts.
+============================
+
+Default MMUv2-compatible layout::
+
+                        Symbol                   VADDR       Size
+  +------------------+
+  | Userspace        |                           0x00000000  TASK_SIZE
+  +------------------+                           0x40000000
+  +------------------+
+  | Page table       |  XCHAL_PAGE_TABLE_VADDR   0x80000000  XCHAL_PAGE_TABLE_SIZE
+  +------------------+
+  | KASAN shadow map |  KASAN_SHADOW_START       0x80400000  KASAN_SHADOW_SIZE
+  +------------------+                           0x8e400000
+  +------------------+
+  | VMALLOC area     |  VMALLOC_START            0xc0000000  128MB - 64KB
+  +------------------+  VMALLOC_END
+  | Cache aliasing   |  TLBTEMP_BASE_1           0xc7ff0000  DCACHE_WAY_SIZE
+  | remap area 1     |
+  +------------------+
+  | Cache aliasing   |  TLBTEMP_BASE_2                       DCACHE_WAY_SIZE
+  | remap area 2     |
+  +------------------+
+  +------------------+
+  | KMAP area        |  PKMAP_BASE                           PTRS_PER_PTE *
+  |                  |                                       DCACHE_N_COLORS *
+  |                  |                                       PAGE_SIZE
+  |                  |                                       (4MB * DCACHE_N_COLORS)
+  +------------------+
+  | Atomic KMAP area |  FIXADDR_START                        KM_TYPE_NR *
+  |                  |                                       NR_CPUS *
+  |                  |                                       DCACHE_N_COLORS *
+  |                  |                                       PAGE_SIZE
+  +------------------+  FIXADDR_TOP              0xcffff000
+  +------------------+
+  | Cached KSEG      |  XCHAL_KSEG_CACHED_VADDR  0xd0000000  128MB
+  +------------------+
+  | Uncached KSEG    |  XCHAL_KSEG_BYPASS_VADDR  0xd8000000  128MB
+  +------------------+
+  | Cached KIO       |  XCHAL_KIO_CACHED_VADDR   0xe0000000  256MB
+  +------------------+
+  | Uncached KIO     |  XCHAL_KIO_BYPASS_VADDR   0xf0000000  256MB
+  +------------------+
+
+
+256MB cached + 256MB uncached layout::
+
+                        Symbol                   VADDR       Size
+  +------------------+
+  | Userspace        |                           0x00000000  TASK_SIZE
+  +------------------+                           0x40000000
+  +------------------+
+  | Page table       |  XCHAL_PAGE_TABLE_VADDR   0x80000000  XCHAL_PAGE_TABLE_SIZE
+  +------------------+
+  | KASAN shadow map |  KASAN_SHADOW_START       0x80400000  KASAN_SHADOW_SIZE
+  +------------------+                           0x8e400000
+  +------------------+
+  | VMALLOC area     |  VMALLOC_START            0xa0000000  128MB - 64KB
+  +------------------+  VMALLOC_END
+  | Cache aliasing   |  TLBTEMP_BASE_1           0xa7ff0000  DCACHE_WAY_SIZE
+  | remap area 1     |
+  +------------------+
+  | Cache aliasing   |  TLBTEMP_BASE_2                       DCACHE_WAY_SIZE
+  | remap area 2     |
+  +------------------+
+  +------------------+
+  | KMAP area        |  PKMAP_BASE                           PTRS_PER_PTE *
+  |                  |                                       DCACHE_N_COLORS *
+  |                  |                                       PAGE_SIZE
+  |                  |                                       (4MB * DCACHE_N_COLORS)
+  +------------------+
+  | Atomic KMAP area |  FIXADDR_START                        KM_TYPE_NR *
+  |                  |                                       NR_CPUS *
+  |                  |                                       DCACHE_N_COLORS *
+  |                  |                                       PAGE_SIZE
+  +------------------+  FIXADDR_TOP              0xaffff000
+  +------------------+
+  | Cached KSEG      |  XCHAL_KSEG_CACHED_VADDR  0xb0000000  256MB
+  +------------------+
+  | Uncached KSEG    |  XCHAL_KSEG_BYPASS_VADDR  0xc0000000  256MB
+  +------------------+
+  +------------------+
+  | Cached KIO       |  XCHAL_KIO_CACHED_VADDR   0xe0000000  256MB
+  +------------------+
+  | Uncached KIO     |  XCHAL_KIO_BYPASS_VADDR   0xf0000000  256MB
+  +------------------+
+
+
+512MB cached + 512MB uncached layout::
+
+                        Symbol                   VADDR       Size
+  +------------------+
+  | Userspace        |                           0x00000000  TASK_SIZE
+  +------------------+                           0x40000000
+  +------------------+
+  | Page table       |  XCHAL_PAGE_TABLE_VADDR   0x80000000  XCHAL_PAGE_TABLE_SIZE
+  +------------------+
+  | KASAN shadow map |  KASAN_SHADOW_START       0x80400000  KASAN_SHADOW_SIZE
+  +------------------+                           0x8e400000
+  +------------------+
+  | VMALLOC area     |  VMALLOC_START            0x90000000  128MB - 64KB
+  +------------------+  VMALLOC_END
+  | Cache aliasing   |  TLBTEMP_BASE_1           0x97ff0000  DCACHE_WAY_SIZE
+  | remap area 1     |
+  +------------------+
+  | Cache aliasing   |  TLBTEMP_BASE_2                       DCACHE_WAY_SIZE
+  | remap area 2     |
+  +------------------+
+  +------------------+
+  | KMAP area        |  PKMAP_BASE                           PTRS_PER_PTE *
+  |                  |                                       DCACHE_N_COLORS *
+  |                  |                                       PAGE_SIZE
+  |                  |                                       (4MB * DCACHE_N_COLORS)
+  +------------------+
+  | Atomic KMAP area |  FIXADDR_START                        KM_TYPE_NR *
+  |                  |                                       NR_CPUS *
+  |                  |                                       DCACHE_N_COLORS *
+  |                  |                                       PAGE_SIZE
+  +------------------+  FIXADDR_TOP              0x9ffff000
+  +------------------+
+  | Cached KSEG      |  XCHAL_KSEG_CACHED_VADDR  0xa0000000  512MB
+  +------------------+
+  | Uncached KSEG    |  XCHAL_KSEG_BYPASS_VADDR  0xc0000000  512MB
+  +------------------+
+  | Cached KIO       |  XCHAL_KIO_CACHED_VADDR   0xe0000000  256MB
+  +------------------+
+  | Uncached KIO     |  XCHAL_KIO_BYPASS_VADDR   0xf0000000  256MB
+  +------------------+
diff --git a/Documentation/xtensa/mmu.txt b/Documentation/xtensa/mmu.txt
deleted file mode 100644 (file)
index 318114d..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-MMUv3 initialization sequence.
-
-The code in the initialize_mmu macro sets up MMUv3 memory mapping
-identically to MMUv2 fixed memory mapping. Depending on
-CONFIG_INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX symbol this code is
-located in addresses it was linked for (symbol undefined), or not
-(symbol defined), so it needs to be position-independent.
-
-The code has the following assumptions:
-  This code fragment is run only on an MMU v3.
-  TLBs are in their reset state.
-  ITLBCFG and DTLBCFG are zero (reset state).
-  RASID is 0x04030201 (reset state).
-  PS.RING is zero (reset state).
-  LITBASE is zero (reset state, PC-relative literals); required to be PIC.
-
-TLB setup proceeds along the following steps.
-
-  Legend:
-    VA = virtual address (two upper nibbles of it);
-    PA = physical address (two upper nibbles of it);
-    pc = physical range that contains this code;
-
-After step 2, we jump to virtual address in the range 0x40000000..0x5fffffff
-or 0x00000000..0x1fffffff, depending on whether the kernel was loaded below
-0x40000000 or above. That address corresponds to next instruction to execute
-in this code. After step 4, we jump to intended (linked) address of this code.
-The scheme below assumes that the kernel is loaded below 0x40000000.
-
-        Step0  Step1  Step2  Step3          Step4  Step5
-        =====  =====  =====  =====          =====  =====
-   VA      PA     PA     PA     PA     VA      PA     PA
- ------    --     --     --     --   ------    --     --
- E0..FF -> E0  -> E0  -> E0          F0..FF -> F0  -> F0
- C0..DF -> C0  -> C0  -> C0          E0..EF -> F0  -> F0
- A0..BF -> A0  -> A0  -> A0          D8..DF -> 00  -> 00
- 80..9F -> 80  -> 80  -> 80          D0..D7 -> 00  -> 00
- 60..7F -> 60  -> 60  -> 60
- 40..5F -> 40         -> pc  -> pc   40..5F -> pc
- 20..3F -> 20  -> 20  -> 20
- 00..1F -> 00  -> 00  -> 00
-
-The default location of IO peripherals is above 0xf0000000. This may be changed
-using a "ranges" property in a device tree simple-bus node. See the Devicetree
-Specification, section 4.5 for details on the syntax and semantics of
-simple-bus nodes. The following limitations apply:
-
-1. Only top level simple-bus nodes are considered
-
-2. Only one (first) simple-bus node is considered
-
-3. Empty "ranges" properties are not supported
-
-4. Only the first triplet in the "ranges" property is considered
-
-5. The parent-bus-address value is rounded down to the nearest 256MB boundary
-
-6. The IO area covers the entire 256MB segment of parent-bus-address; the
-   "ranges" triplet length field is ignored
-
-
-MMUv3 address space layouts.
-============================
-
-Default MMUv2-compatible layout.
-
-                      Symbol                   VADDR       Size
-+------------------+
-| Userspace        |                           0x00000000  TASK_SIZE
-+------------------+                           0x40000000
-+------------------+
-| Page table       |  XCHAL_PAGE_TABLE_VADDR   0x80000000  XCHAL_PAGE_TABLE_SIZE
-+------------------+
-| KASAN shadow map |  KASAN_SHADOW_START       0x80400000  KASAN_SHADOW_SIZE
-+------------------+                           0x8e400000
-+------------------+
-| VMALLOC area     |  VMALLOC_START            0xc0000000  128MB - 64KB
-+------------------+  VMALLOC_END
-| Cache aliasing   |  TLBTEMP_BASE_1           0xc7ff0000  DCACHE_WAY_SIZE
-| remap area 1     |
-+------------------+
-| Cache aliasing   |  TLBTEMP_BASE_2                       DCACHE_WAY_SIZE
-| remap area 2     |
-+------------------+
-+------------------+
-| KMAP area        |  PKMAP_BASE                           PTRS_PER_PTE *
-|                  |                                       DCACHE_N_COLORS *
-|                  |                                       PAGE_SIZE
-|                  |                                       (4MB * DCACHE_N_COLORS)
-+------------------+
-| Atomic KMAP area |  FIXADDR_START                        KM_TYPE_NR *
-|                  |                                       NR_CPUS *
-|                  |                                       DCACHE_N_COLORS *
-|                  |                                       PAGE_SIZE
-+------------------+  FIXADDR_TOP              0xcffff000
-+------------------+
-| Cached KSEG      |  XCHAL_KSEG_CACHED_VADDR  0xd0000000  128MB
-+------------------+
-| Uncached KSEG    |  XCHAL_KSEG_BYPASS_VADDR  0xd8000000  128MB
-+------------------+
-| Cached KIO       |  XCHAL_KIO_CACHED_VADDR   0xe0000000  256MB
-+------------------+
-| Uncached KIO     |  XCHAL_KIO_BYPASS_VADDR   0xf0000000  256MB
-+------------------+
-
-
-256MB cached + 256MB uncached layout.
-
-                      Symbol                   VADDR       Size
-+------------------+
-| Userspace        |                           0x00000000  TASK_SIZE
-+------------------+                           0x40000000
-+------------------+
-| Page table       |  XCHAL_PAGE_TABLE_VADDR   0x80000000  XCHAL_PAGE_TABLE_SIZE
-+------------------+
-| KASAN shadow map |  KASAN_SHADOW_START       0x80400000  KASAN_SHADOW_SIZE
-+------------------+                           0x8e400000
-+------------------+
-| VMALLOC area     |  VMALLOC_START            0xa0000000  128MB - 64KB
-+------------------+  VMALLOC_END
-| Cache aliasing   |  TLBTEMP_BASE_1           0xa7ff0000  DCACHE_WAY_SIZE
-| remap area 1     |
-+------------------+
-| Cache aliasing   |  TLBTEMP_BASE_2                       DCACHE_WAY_SIZE
-| remap area 2     |
-+------------------+
-+------------------+
-| KMAP area        |  PKMAP_BASE                           PTRS_PER_PTE *
-|                  |                                       DCACHE_N_COLORS *
-|                  |                                       PAGE_SIZE
-|                  |                                       (4MB * DCACHE_N_COLORS)
-+------------------+
-| Atomic KMAP area |  FIXADDR_START                        KM_TYPE_NR *
-|                  |                                       NR_CPUS *
-|                  |                                       DCACHE_N_COLORS *
-|                  |                                       PAGE_SIZE
-+------------------+  FIXADDR_TOP              0xaffff000
-+------------------+
-| Cached KSEG      |  XCHAL_KSEG_CACHED_VADDR  0xb0000000  256MB
-+------------------+
-| Uncached KSEG    |  XCHAL_KSEG_BYPASS_VADDR  0xc0000000  256MB
-+------------------+
-+------------------+
-| Cached KIO       |  XCHAL_KIO_CACHED_VADDR   0xe0000000  256MB
-+------------------+
-| Uncached KIO     |  XCHAL_KIO_BYPASS_VADDR   0xf0000000  256MB
-+------------------+
-
-
-512MB cached + 512MB uncached layout.
-
-                      Symbol                   VADDR       Size
-+------------------+
-| Userspace        |                           0x00000000  TASK_SIZE
-+------------------+                           0x40000000
-+------------------+
-| Page table       |  XCHAL_PAGE_TABLE_VADDR   0x80000000  XCHAL_PAGE_TABLE_SIZE
-+------------------+
-| KASAN shadow map |  KASAN_SHADOW_START       0x80400000  KASAN_SHADOW_SIZE
-+------------------+                           0x8e400000
-+------------------+
-| VMALLOC area     |  VMALLOC_START            0x90000000  128MB - 64KB
-+------------------+  VMALLOC_END
-| Cache aliasing   |  TLBTEMP_BASE_1           0x97ff0000  DCACHE_WAY_SIZE
-| remap area 1     |
-+------------------+
-| Cache aliasing   |  TLBTEMP_BASE_2                       DCACHE_WAY_SIZE
-| remap area 2     |
-+------------------+
-+------------------+
-| KMAP area        |  PKMAP_BASE                           PTRS_PER_PTE *
-|                  |                                       DCACHE_N_COLORS *
-|                  |                                       PAGE_SIZE
-|                  |                                       (4MB * DCACHE_N_COLORS)
-+------------------+
-| Atomic KMAP area |  FIXADDR_START                        KM_TYPE_NR *
-|                  |                                       NR_CPUS *
-|                  |                                       DCACHE_N_COLORS *
-|                  |                                       PAGE_SIZE
-+------------------+  FIXADDR_TOP              0x9ffff000
-+------------------+
-| Cached KSEG      |  XCHAL_KSEG_CACHED_VADDR  0xa0000000  512MB
-+------------------+
-| Uncached KSEG    |  XCHAL_KSEG_BYPASS_VADDR  0xc0000000  512MB
-+------------------+
-| Cached KIO       |  XCHAL_KIO_CACHED_VADDR   0xe0000000  256MB
-+------------------+
-| Uncached KIO     |  XCHAL_KIO_BYPASS_VADDR   0xf0000000  256MB
-+------------------+
index 6debe68..4e2a525 100644 (file)
@@ -1155,7 +1155,7 @@ APPLIED MICRO (APM) X-GENE SOC PMU
 M:     Khuong Dinh <khuong@os.amperecomputing.com>
 S:     Supported
 F:     drivers/perf/xgene_pmu.c
-F:     Documentation/perf/xgene-pmu.txt
+F:     Documentation/admin-guide/perf/xgene-pmu.rst
 F:     Documentation/devicetree/bindings/perf/apm-xgene-pmu.txt
 
 APTINA CAMERA SENSOR PLL
@@ -1236,7 +1236,7 @@ M:        James (Qian) Wang <james.qian.wang@arm.com>
 M:     Liviu Dudau <liviu.dudau@arm.com>
 L:     Mali DP Maintainers <malidp@foss.arm.com>
 S:     Supported
-T:     git git://linux-arm.org/linux-ld.git for-upstream/mali-dp
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     drivers/gpu/drm/arm/display/include/
 F:     drivers/gpu/drm/arm/display/komeda/
 F:     Documentation/devicetree/bindings/display/arm,komeda.txt
@@ -1247,7 +1247,7 @@ M:        Liviu Dudau <liviu.dudau@arm.com>
 M:     Brian Starkey <brian.starkey@arm.com>
 L:     Mali DP Maintainers <malidp@foss.arm.com>
 S:     Supported
-T:     git git://linux-arm.org/linux-ld.git for-upstream/mali-dp
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     drivers/gpu/drm/arm/
 F:     Documentation/devicetree/bindings/display/arm,malidp.txt
 F:     Documentation/gpu/afbc.rst
@@ -1264,7 +1264,7 @@ F:        include/uapi/drm/panfrost_drm.h
 ARM MFM AND FLOPPY DRIVERS
 M:     Ian Molton <spyro@f2s.com>
 S:     Maintained
-F:     arch/arm/lib/floppydma.S
+F:     arch/arm/mach-rpc/floppydma.S
 F:     arch/arm/include/asm/floppy.h
 
 ARM PMU PROFILING AND DEBUGGING
@@ -1863,6 +1863,7 @@ F:        arch/arm/mach-orion5x/
 F:     arch/arm/plat-orion/
 F:     arch/arm/boot/dts/dove*
 F:     arch/arm/boot/dts/orion5x*
+T:     git git://git.infradead.org/linux-mvebu.git
 
 ARM/Marvell Kirkwood and Armada 370, 375, 38x, 39x, XP, 3700, 7K/8K SOC support
 M:     Jason Cooper <jason@lakedaemon.net>
@@ -1883,6 +1884,7 @@ F:        drivers/irqchip/irq-armada-370-xp.c
 F:     drivers/irqchip/irq-mvebu-*
 F:     drivers/pinctrl/mvebu/
 F:     drivers/rtc/rtc-armada38x.c
+T:     git git://git.infradead.org/linux-mvebu.git
 
 ARM/Mediatek RTC DRIVER
 M:     Eddie Huang <eddie.huang@mediatek.com>
@@ -2089,7 +2091,6 @@ S:        Maintained
 
 ARM/QUALCOMM SUPPORT
 M:     Andy Gross <agross@kernel.org>
-M:     David Brown <david.brown@linaro.org>
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/soc/qcom/
@@ -2111,7 +2112,7 @@ F:        drivers/i2c/busses/i2c-qup.c
 F:     drivers/i2c/busses/i2c-qcom-geni.c
 F:     drivers/mfd/ssbi.c
 F:     drivers/mmc/host/mmci_qcom*
-F:     drivers/mmc/host/sdhci_msm.c
+F:     drivers/mmc/host/sdhci-msm.c
 F:     drivers/pci/controller/dwc/pcie-qcom.c
 F:     drivers/phy/qualcomm/
 F:     drivers/power/*/msm*
@@ -2218,7 +2219,7 @@ F:        drivers/*/*s3c64xx*
 F:     drivers/*/*s5pv210*
 F:     drivers/memory/samsung/*
 F:     drivers/soc/samsung/*
-F:     Documentation/arm/Samsung/
+F:     Documentation/arm/samsung/
 F:     Documentation/devicetree/bindings/arm/samsung/
 F:     Documentation/devicetree/bindings/sram/samsung-sram.txt
 F:     Documentation/devicetree/bindings/power/pd-samsung.txt
@@ -2689,7 +2690,7 @@ ATA OVER ETHERNET (AOE) DRIVER
 M:     "Justin Sanders" <justin@coraid.com>
 W:     http://www.openaoe.org/
 S:     Supported
-F:     Documentation/aoe/
+F:     Documentation/admin-guide/aoe/
 F:     drivers/block/aoe/
 
 ATHEROS 71XX/9XXX GPIO DRIVER
@@ -2968,7 +2969,7 @@ M:        Jens Axboe <axboe@kernel.dk>
 L:     linux-block@vger.kernel.org
 S:     Maintained
 F:     block/bfq-*
-F:     Documentation/block/bfq-iosched.txt
+F:     Documentation/block/bfq-iosched.rst
 
 BFS FILE SYSTEM
 M:     "Tigran A. Aivazian" <aivazian.tigran@gmail.com>
@@ -3108,9 +3109,9 @@ S:        Maintained
 F:     arch/riscv/net/
 
 BPF JIT for S390
+M:     Ilya Leoshkevich <iii@linux.ibm.com>
 M:     Heiko Carstens <heiko.carstens@de.ibm.com>
 M:     Vasily Gorbik <gor@linux.ibm.com>
-M:     Christian Borntraeger <borntraeger@de.ibm.com>
 L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Maintained
@@ -3765,7 +3766,7 @@ F:        arch/powerpc/platforms/cell/
 
 CEPH COMMON CODE (LIBCEPH)
 M:     Ilya Dryomov <idryomov@gmail.com>
-M:     "Yan, Zheng" <zyan@redhat.com>
+M:     Jeff Layton <jlayton@kernel.org>
 M:     Sage Weil <sage@redhat.com>
 L:     ceph-devel@vger.kernel.org
 W:     http://ceph.com/
@@ -3777,7 +3778,7 @@ F:        include/linux/ceph/
 F:     include/linux/crush/
 
 CEPH DISTRIBUTED FILE SYSTEM CLIENT (CEPH)
-M:     "Yan, Zheng" <zyan@redhat.com>
+M:     Jeff Layton <jlayton@kernel.org>
 M:     Sage Weil <sage@redhat.com>
 M:     Ilya Dryomov <idryomov@gmail.com>
 L:     ceph-devel@vger.kernel.org
@@ -4158,7 +4159,7 @@ L:        cgroups@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git
 S:     Maintained
 F:     Documentation/admin-guide/cgroup-v2.rst
-F:     Documentation/cgroup-v1/
+F:     Documentation/admin-guide/cgroup-v1/
 F:     include/linux/cgroup*
 F:     kernel/cgroup/
 
@@ -4169,7 +4170,7 @@ W:        http://www.bullopensource.org/cpuset/
 W:     http://oss.sgi.com/projects/cpusets/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git
 S:     Maintained
-F:     Documentation/cgroup-v1/cpusets.rst
+F:     Documentation/admin-guide/cgroup-v1/cpusets.rst
 F:     include/linux/cpuset.h
 F:     kernel/cgroup/cpuset.c
 
@@ -4655,7 +4656,7 @@ DELL SYSTEMS MANAGEMENT BASE DRIVER (dcdbas)
 M:     Stuart Hayes <stuart.w.hayes@gmail.com>
 L:     platform-driver-x86@vger.kernel.org
 S:     Maintained
-F:     Documentation/dcdbas.txt
+F:     Documentation/driver-api/dcdbas.rst
 F:     drivers/platform/x86/dcdbas.*
 
 DELL WMI NOTIFICATIONS DRIVER
@@ -4683,6 +4684,13 @@ L:       linux-mtd@lists.infradead.org
 S:     Supported
 F:     drivers/mtd/nand/raw/denali*
 
+DESIGNWARE EDMA CORE IP DRIVER
+M:     Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+L:     dmaengine@vger.kernel.org
+S:     Maintained
+F:     drivers/dma/dw-edma/
+F:     include/linux/dma/edma.h
+
 DESIGNWARE USB2 DRD IP DRIVER
 M:     Minas Harutyunyan <hminas@synopsys.com>
 L:     linux-usb@vger.kernel.org
@@ -4748,7 +4756,7 @@ Q:        http://patchwork.kernel.org/project/dm-devel/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm.git
 T:     quilt http://people.redhat.com/agk/patches/linux/editing/
 S:     Maintained
-F:     Documentation/device-mapper/
+F:     Documentation/admin-guide/device-mapper/
 F:     drivers/md/Makefile
 F:     drivers/md/Kconfig
 F:     drivers/md/dm*
@@ -5019,7 +5027,7 @@ T:        git git://git.linbit.com/drbd-8.4.git
 S:     Supported
 F:     drivers/block/drbd/
 F:     lib/lru_cache.c
-F:     Documentation/blockdev/drbd/
+F:     Documentation/admin-guide/blockdev/
 
 DRIVER CORE, KOBJECTS, DEBUGFS AND SYSFS
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
@@ -6100,7 +6108,7 @@ M:        Ard Biesheuvel <ard.biesheuvel@linaro.org>
 L:     linux-efi@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git
 S:     Maintained
-F:     Documentation/efi-stub.txt
+F:     Documentation/admin-guide/efi-stub.rst
 F:     arch/*/kernel/efi.c
 F:     arch/x86/boot/compressed/eboot.[ch]
 F:     arch/*/include/asm/efi.h
@@ -6314,9 +6322,8 @@ F:        Documentation/devicetree/bindings/counter/ftm-quaddec.txt
 F:     drivers/counter/ftm-quaddec.c
 
 FLOPPY DRIVER
-M:     Jiri Kosina <jikos@kernel.org>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/floppy.git
-S:     Odd fixes
+S:     Orphan
+L:     linux-block@vger.kernel.org
 F:     drivers/block/floppy.c
 
 FMC SUBSYSTEM
@@ -6519,6 +6526,7 @@ M:        Li Yang <leoyang.li@nxp.com>
 L:     linuxppc-dev@lists.ozlabs.org
 L:     linux-arm-kernel@lists.infradead.org
 S:     Maintained
+F:     Documentation/devicetree/bindings/misc/fsl,dpaa2-console.txt
 F:     Documentation/devicetree/bindings/soc/fsl/
 F:     drivers/soc/fsl/
 F:     include/linux/fsl/
@@ -6675,7 +6683,7 @@ S:        Maintained
 F:     scripts/gcc-plugins/
 F:     scripts/gcc-plugin.sh
 F:     scripts/Makefile.gcc-plugins
-F:     Documentation/gcc-plugins.txt
+F:     Documentation/core-api/gcc-plugins.rst
 
 GASKET DRIVER FRAMEWORK
 M:     Rob Springer <rspringer@google.com>
@@ -6887,7 +6895,7 @@ T:        git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git
 S:     Maintained
 F:     Documentation/devicetree/bindings/gpio/
 F:     Documentation/driver-api/gpio/
-F:     Documentation/gpio/
+F:     Documentation/admin-guide/gpio/
 F:     Documentation/ABI/testing/gpio-cdev
 F:     Documentation/ABI/obsolete/sysfs-gpio
 F:     drivers/gpio/
@@ -7108,7 +7116,7 @@ M:        Herbert Xu <herbert@gondor.apana.org.au>
 L:     linux-crypto@vger.kernel.org
 S:     Odd fixes
 F:     Documentation/devicetree/bindings/rng/
-F:     Documentation/hw_random.txt
+F:     Documentation/admin-guide/hw_random.rst
 F:     drivers/char/hw_random/
 F:     include/linux/hw_random.h
 
@@ -7282,7 +7290,7 @@ M:        Shaokun Zhang <zhangshaokun@hisilicon.com>
 W:     http://www.hisilicon.com
 S:     Supported
 F:     drivers/perf/hisilicon
-F:     Documentation/perf/hisi-pmu.txt
+F:     Documentation/admin-guide/perf/hisi-pmu.rst
 
 HISILICON ROCE DRIVER
 M:     Lijun Ou <oulijun@huawei.com>
@@ -7955,6 +7963,33 @@ L:       linux-mtd@lists.infradead.org
 S:     Maintained
 F:     drivers/mtd/nand/raw/ingenic/
 
+INGENIC JZ47xx SoCs
+M:     Paul Cercueil <paul@crapouillou.net>
+S:     Maintained
+F:     arch/mips/boot/dts/ingenic/
+F:     arch/mips/include/asm/mach-jz4740/
+F:     arch/mips/jz4740/
+F:     drivers/clk/ingenic/
+F:     drivers/dma/dma-jz4780.c
+F:     drivers/gpu/drm/ingenic/
+F:     drivers/i2c/busses/i2c-jz4780.c
+F:     drivers/iio/adc/ingenic-adc.c
+F:     drivers/irqchip/irq-ingenic.c
+F:     drivers/memory/jz4780-nemc.c
+F:     drivers/mmc/host/jz4740_mmc.c
+F:     drivers/mtd/nand/raw/ingenic/
+F:     drivers/pinctrl/pinctrl-ingenic.c
+F:     drivers/power/supply/ingenic-battery.c
+F:     drivers/pwm/pwm-jz4740.c
+F:     drivers/rtc/rtc-jz4740.c
+F:     drivers/tty/serial/8250/8250_ingenic.c
+F:     drivers/usb/musb/jz4740.c
+F:     drivers/watchdog/jz4740_wdt.c
+F:     include/dt-bindings/iio/adc/ingenic,adc.h
+F:     include/linux/mfd/ingenic-tcu.h
+F:     sound/soc/jz4740/
+F:     sound/soc/codecs/jz47*
+
 INOTIFY
 M:     Jan Kara <jack@suse.cz>
 R:     Amir Goldstein <amir73il@gmail.com>
@@ -8332,7 +8367,7 @@ L:        tboot-devel@lists.sourceforge.net
 W:     http://tboot.sourceforge.net
 T:     hg http://tboot.hg.sourceforge.net:8000/hgroot/tboot/tboot
 S:     Supported
-F:     Documentation/intel_txt.txt
+F:     Documentation/x86/intel_txt.rst
 F:     include/linux/tboot.h
 F:     arch/x86/kernel/tboot.c
 
@@ -8346,7 +8381,7 @@ INTERCONNECT API
 M:     Georgi Djakov <georgi.djakov@linaro.org>
 L:     linux-pm@vger.kernel.org
 S:     Maintained
-F:     Documentation/interconnect/
+F:     Documentation/driver-api/interconnect.rst
 F:     Documentation/devicetree/bindings/interconnect/
 F:     drivers/interconnect/
 F:     include/dt-bindings/interconnect/
@@ -8382,6 +8417,7 @@ L:        linux-fsdevel@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git
 S:     Supported
 F:     fs/iomap.c
+F:     fs/iomap/
 F:     include/linux/iomap.h
 
 IOMMU DRIVERS
@@ -8482,7 +8518,7 @@ F:        drivers/irqchip/
 ISA
 M:     William Breathitt Gray <vilhelm.gray@gmail.com>
 S:     Maintained
-F:     Documentation/isa.txt
+F:     Documentation/driver-api/isa.rst
 F:     drivers/base/isa.c
 F:     include/linux/isa.h
 
@@ -8497,7 +8533,7 @@ F:        drivers/media/radio/radio-isa*
 ISAPNP
 M:     Jaroslav Kysela <perex@perex.cz>
 S:     Maintained
-F:     Documentation/isapnp.txt
+F:     Documentation/driver-api/isapnp.rst
 F:     drivers/pnp/isapnp/
 F:     include/linux/isapnp.h
 
@@ -8695,7 +8731,7 @@ R:        Vivek Goyal <vgoyal@redhat.com>
 L:     kexec@lists.infradead.org
 W:     http://lse.sourceforge.net/kdump/
 S:     Maintained
-F:     Documentation/kdump/
+F:     Documentation/admin-guide/kdump/
 
 KEENE FM RADIO TRANSMITTER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
@@ -8772,7 +8808,7 @@ L:        kvm@vger.kernel.org
 W:     http://www.linux-kvm.org
 T:     git git://git.kernel.org/pub/scm/virt/kvm/kvm.git
 S:     Supported
-F:     Documentation/virtual/kvm/
+F:     Documentation/virt/kvm/
 F:     include/trace/events/kvm.h
 F:     include/uapi/asm-generic/kvm*
 F:     include/uapi/linux/kvm*
@@ -8842,6 +8878,8 @@ F:        arch/s390/include/asm/gmap.h
 F:     arch/s390/include/asm/kvm*
 F:     arch/s390/kvm/
 F:     arch/s390/mm/gmap.c
+F:     tools/testing/selftests/kvm/s390x/
+F:     tools/testing/selftests/kvm/*/s390x/
 
 KERNEL VIRTUAL MACHINE FOR X86 (KVM/x86)
 M:     Paolo Bonzini <pbonzini@redhat.com>
@@ -9049,7 +9087,7 @@ M:        Matan Ziv-Av <matan@svgalib.org>
 L:     platform-driver-x86@vger.kernel.org
 S:     Maintained
 F:     Documentation/ABI/testing/sysfs-platform-lg-laptop
-F:     Documentation/laptops/lg-laptop.rst
+F:     Documentation/admin-guide/laptops/lg-laptop.rst
 F:     drivers/platform/x86/lg-laptop.c
 
 LG2160 MEDIA DRIVER
@@ -9418,7 +9456,7 @@ M:        "Richard Russon (FlatCap)" <ldm@flatcap.org>
 L:     linux-ntfs-dev@lists.sourceforge.net
 W:     http://www.linux-ntfs.org/content/view/19/37/
 S:     Maintained
-F:     Documentation/ldm.txt
+F:     Documentation/admin-guide/ldm.rst
 F:     block/partitions/ldm.*
 
 LSILOGIC MPT FUSION DRIVERS (FC/SAS/SPI)
@@ -10380,7 +10418,7 @@ M:      Johannes Thumshirn <morbidrsa@gmail.com>
 S:     Maintained
 F:     drivers/mcb/
 F:     include/linux/mcb.h
-F:     Documentation/men-chameleon-bus.txt
+F:     Documentation/driver-api/men-chameleon-bus.rst
 
 MEN F21BMC (Board Management Controller)
 M:     Andreas Werner <andreas.werner@men.de>
@@ -10794,7 +10832,7 @@ F:      include/uapi/linux/meye.h
 MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD
 M:     Jiri Slaby <jirislaby@gmail.com>
 S:     Maintained
-F:     Documentation/serial/moxa-smartio.rst
+F:     Documentation/driver-api/serial/moxa-smartio.rst
 F:     drivers/tty/mxser.*
 
 MR800 AVERMEDIA USB FM RADIO DRIVER
@@ -11095,7 +11133,7 @@ M:      Josef Bacik <josef@toxicpanda.com>
 S:     Maintained
 L:     linux-block@vger.kernel.org
 L:     nbd@other.debian.org
-F:     Documentation/blockdev/nbd.txt
+F:     Documentation/admin-guide/blockdev/nbd.rst
 F:     drivers/block/nbd.c
 F:     include/trace/events/nbd.h
 F:     include/uapi/linux/nbd.h
@@ -11554,7 +11592,7 @@ F:      arch/powerpc/include/asm/pnv-ocxl.h
 F:     drivers/misc/ocxl/
 F:     include/misc/ocxl*
 F:     include/uapi/misc/ocxl.h
-F:     Documentation/accelerators/ocxl.rst
+F:     Documentation/userspace-api/accelerators/ocxl.rst
 
 OMAP AUDIO SUPPORT
 M:     Peter Ujfalusi <peter.ujfalusi@ti.com>
@@ -11590,7 +11628,7 @@ L:      linux-omap@vger.kernel.org
 L:     linux-fbdev@vger.kernel.org
 S:     Orphan
 F:     drivers/video/fbdev/omap2/
-F:     Documentation/arm/OMAP/DSS
+F:     Documentation/arm/omap/dss.rst
 
 OMAP FRAMEBUFFER SUPPORT
 L:     linux-fbdev@vger.kernel.org
@@ -11871,11 +11909,13 @@ F:    include/linux/mtd/onenand*.h
 
 OP-TEE DRIVER
 M:     Jens Wiklander <jens.wiklander@linaro.org>
+L:     tee-dev@lists.linaro.org
 S:     Maintained
 F:     drivers/tee/optee/
 
 OP-TEE RANDOM NUMBER GENERATOR (RNG) DRIVER
 M:     Sumit Garg <sumit.garg@linaro.org>
+L:     tee-dev@lists.linaro.org
 S:     Maintained
 F:     drivers/char/hw_random/optee-rng.c
 
@@ -12077,7 +12117,7 @@ PARALLEL LCD/KEYPAD PANEL DRIVER
 M:     Willy Tarreau <willy@haproxy.com>
 M:     Ksenija Stanojevic <ksenija.stanojevic@gmail.com>
 S:     Odd Fixes
-F:     Documentation/auxdisplay/lcd-panel-cgram.txt
+F:     Documentation/admin-guide/lcd-panel-cgram.rst
 F:     drivers/auxdisplay/panel.c
 
 PARALLEL PORT SUBSYSTEM
@@ -12089,14 +12129,15 @@ F:    drivers/parport/
 F:     include/linux/parport*.h
 F:     drivers/char/ppdev.c
 F:     include/uapi/linux/ppdev.h
-F:     Documentation/parport*.txt
+F:     Documentation/driver-api/parport*.rst
 
 PARAVIRT_OPS INTERFACE
 M:     Juergen Gross <jgross@suse.com>
-M:     Alok Kataria <akataria@vmware.com>
+M:     Thomas Hellstrom <thellstrom@vmware.com>
+M:     "VMware, Inc." <pv-drivers@vmware.com>
 L:     virtualization@lists.linux-foundation.org
 S:     Supported
-F:     Documentation/virtual/paravirt_ops.txt
+F:     Documentation/virt/paravirt_ops.txt
 F:     arch/*/kernel/paravirt*
 F:     arch/*/include/asm/paravirt*.h
 F:     include/linux/hypervisor.h
@@ -12105,7 +12146,7 @@ PARIDE DRIVERS FOR PARALLEL PORT IDE DEVICES
 M:     Tim Waugh <tim@cyberelk.net>
 L:     linux-parport@lists.infradead.org (subscribers-only)
 S:     Maintained
-F:     Documentation/blockdev/paride.txt
+F:     Documentation/admin-guide/blockdev/paride.rst
 F:     drivers/block/paride/
 
 PARISC ARCHITECTURE
@@ -12264,7 +12305,7 @@ M:      Kurt Schwemmer <kurt.schwemmer@microsemi.com>
 M:     Logan Gunthorpe <logang@deltatee.com>
 L:     linux-pci@vger.kernel.org
 S:     Maintained
-F:     Documentation/switchtec.txt
+F:     Documentation/driver-api/switchtec.rst
 F:     Documentation/ABI/testing/sysfs-class-switchtec
 F:     drivers/pci/switch/switchtec*
 F:     include/uapi/linux/switchtec_ioctl.h
@@ -12611,6 +12652,17 @@ F:     arch/arm/boot/dts/picoxcell*
 F:     arch/arm/mach-picoxcell/
 F:     drivers/crypto/picoxcell*
 
+PIDFD API
+M:     Christian Brauner <christian@brauner.io>
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux.git
+F:     samples/pidfd/
+F:     tools/testing/selftests/pidfd/
+K:     (?i)pidfd
+K:     (?i)clone3
+K:     \b(clone_args|kernel_clone_args)\b
+
 PIN CONTROL SUBSYSTEM
 M:     Linus Walleij <linus.walleij@linaro.org>
 L:     linux-gpio@vger.kernel.org
@@ -12796,6 +12848,7 @@ F:      drivers/base/power/
 F:     include/linux/pm.h
 F:     include/linux/pm_*
 F:     include/linux/powercap.h
+F:     include/linux/intel_rapl.h
 F:     drivers/powercap/
 F:     kernel/configs/nopm.config
 
@@ -13025,7 +13078,7 @@ M:      Thierry Reding <thierry.reding@gmail.com>
 L:     linux-pwm@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm.git
-F:     Documentation/pwm.txt
+F:     Documentation/driver-api/pwm.rst
 F:     Documentation/devicetree/bindings/pwm/
 F:     include/linux/pwm.h
 F:     drivers/pwm/
@@ -13247,7 +13300,7 @@ M:      Niklas Cassel <niklas.cassel@linaro.org>
 L:     netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
-F:     Documentation/devicetree/bindings/net/qcom,dwmac.txt
+F:     Documentation/devicetree/bindings/net/qcom,ethqos.txt
 
 QUALCOMM GENERIC INTERFACE I2C DRIVER
 M:     Alok Chauhan <alokc@codeaurora.org>
@@ -13386,7 +13439,7 @@ F:      drivers/net/wireless/ralink/rt2x00/
 RAMDISK RAM BLOCK DEVICE DRIVER
 M:     Jens Axboe <axboe@kernel.dk>
 S:     Maintained
-F:     Documentation/blockdev/ramdisk.txt
+F:     Documentation/admin-guide/blockdev/ramdisk.rst
 F:     drivers/block/brd.c
 
 RANCHU VIRTUAL BOARD FOR MIPS
@@ -13495,7 +13548,7 @@ Q:      http://patchwork.ozlabs.org/project/rtc-linux/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git
 S:     Maintained
 F:     Documentation/devicetree/bindings/rtc/
-F:     Documentation/rtc.txt
+F:     Documentation/admin-guide/rtc.rst
 F:     drivers/rtc/
 F:     include/linux/rtc.h
 F:     include/uapi/linux/rtc.h
@@ -13545,9 +13598,11 @@ L:     linux-remoteproc@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ohad/remoteproc.git
 S:     Maintained
 F:     Documentation/devicetree/bindings/remoteproc/
+F:     Documentation/ABI/testing/sysfs-class-remoteproc
 F:     Documentation/remoteproc.txt
 F:     drivers/remoteproc/
 F:     include/linux/remoteproc.h
+F:     include/linux/remoteproc/
 
 REMOTE PROCESSOR MESSAGING (RPMSG) SUBSYSTEM
 M:     Ohad Ben-Cohen <ohad@wizery.com>
@@ -13557,8 +13612,11 @@ T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ohad/rpmsg.git
 S:     Maintained
 F:     drivers/rpmsg/
 F:     Documentation/rpmsg.txt
+F:     Documentation/ABI/testing/sysfs-bus-rpmsg
 F:     include/linux/rpmsg.h
 F:     include/linux/rpmsg/
+F:     include/uapi/linux/rpmsg.h
+F:     samples/rpmsg/
 
 RENESAS CLOCK DRIVERS
 M:     Geert Uytterhoeven <geert+renesas@glider.be>
@@ -13639,7 +13697,7 @@ W:      http://wireless.kernel.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
 S:     Maintained
-F:     Documentation/rfkill.txt
+F:     Documentation/driver-api/rfkill.rst
 F:     Documentation/ABI/stable/sysfs-class-rfkill
 F:     net/rfkill/
 F:     include/linux/rfkill.h
@@ -13667,10 +13725,11 @@ F:    drivers/mtd/nand/raw/r852.c
 F:     drivers/mtd/nand/raw/r852.h
 
 RISC-V ARCHITECTURE
+M:     Paul Walmsley <paul.walmsley@sifive.com>
 M:     Palmer Dabbelt <palmer@sifive.com>
 M:     Albert Ou <aou@eecs.berkeley.edu>
 L:     linux-riscv@lists.infradead.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/palmer/riscv-linux.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git
 S:     Supported
 F:     arch/riscv/
 K:     riscv
@@ -13708,7 +13767,7 @@ ROCKETPORT DRIVER
 P:     Comtrol Corp.
 W:     http://www.comtrol.com
 S:     Maintained
-F:     Documentation/serial/rocket.rst
+F:     Documentation/driver-api/serial/rocket.rst
 F:     drivers/tty/rocket*
 
 ROCKETPORT EXPRESS/INFINITY DRIVER
@@ -14102,7 +14161,7 @@ M:      Sylwester Nawrocki <s.nawrocki@samsung.com>
 L:     linux-kernel@vger.kernel.org
 S:     Supported
 F:     Documentation/devicetree/bindings/phy/samsung-phy.txt
-F:     Documentation/phy/samsung-usb2.txt
+F:     Documentation/driver-api/phy/samsung-usb2.rst
 F:     drivers/phy/samsung/phy-exynos4210-usb2.c
 F:     drivers/phy/samsung/phy-exynos4x12-usb2.c
 F:     drivers/phy/samsung/phy-exynos5250-usb2.c
@@ -14408,7 +14467,7 @@ SGI SN-IA64 (Altix) SERIAL CONSOLE DRIVER
 M:     Pat Gefre <pfg@sgi.com>
 L:     linux-ia64@vger.kernel.org
 S:     Supported
-F:     Documentation/ia64/serial.txt
+F:     Documentation/ia64/serial.rst
 F:     drivers/tty/serial/ioc?_serial.c
 F:     include/linux/ioc?.h
 
@@ -14532,7 +14591,7 @@ M:      Paul Walmsley <paul.walmsley@sifive.com>
 L:     linux-riscv@lists.infradead.org
 T:     git git://github.com/sifive/riscv-linux.git
 S:     Supported
-K:     sifive
+K:     [^@]sifive
 N:     sifive
 
 SIFIVE FU540 SYSTEM-ON-CHIP
@@ -14823,6 +14882,7 @@ F:      Documentation/devicetree/bindings/net/socionext,uniphier-ave4.txt
 
 SOCIONEXT (SNI) NETSEC NETWORK DRIVER
 M:     Jassi Brar <jaswinder.singh@linaro.org>
+M:     Ilias Apalodimas <ilias.apalodimas@linaro.org>
 L:     netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/ethernet/socionext/netsec.c
@@ -14914,7 +14974,7 @@ M:      Mattia Dongili <malattia@linux.it>
 L:     platform-driver-x86@vger.kernel.org
 W:     http://www.linux.it/~malattia/wiki/index.php/Sony_drivers
 S:     Maintained
-F:     Documentation/laptops/sony-laptop.txt
+F:     Documentation/admin-guide/laptops/sony-laptop.rst
 F:     drivers/char/sonypi.c
 F:     drivers/platform/x86/sony-laptop.c
 F:     include/linux/sony-laptop.h
@@ -15332,7 +15392,7 @@ SVGA HANDLING
 M:     Martin Mares <mj@ucw.cz>
 L:     linux-video@atrey.karlin.mff.cuni.cz
 S:     Maintained
-F:     Documentation/svga.txt
+F:     Documentation/admin-guide/svga.rst
 F:     arch/x86/boot/video*
 
 SWIOTLB SUBSYSTEM
@@ -15369,7 +15429,7 @@ F:      drivers/dma-buf/dma-fence*
 F:     drivers/dma-buf/sw_sync.c
 F:     include/linux/sync_file.h
 F:     include/uapi/linux/sync_file.h
-F:     Documentation/sync_file.txt
+F:     Documentation/driver-api/sync_file.rst
 T:     git git://anongit.freedesktop.org/drm/drm-misc
 
 SYNOPSYS ARC ARCHITECTURE
@@ -15691,6 +15751,7 @@ F:      include/media/i2c/tw9910.h
 
 TEE SUBSYSTEM
 M:     Jens Wiklander <jens.wiklander@linaro.org>
+L:     tee-dev@lists.linaro.org
 S:     Maintained
 F:     include/linux/tee_drv.h
 F:     include/uapi/linux/tee.h
@@ -15846,7 +15907,7 @@ M:      Viresh Kumar <viresh.kumar@linaro.org>
 M:     Javi Merino <javi.merino@kernel.org>
 L:     linux-pm@vger.kernel.org
 S:     Supported
-F:     Documentation/thermal/cpu-cooling-api.txt
+F:     Documentation/thermal/cpu-cooling-api.rst
 F:     drivers/thermal/cpu_cooling.c
 F:     include/linux/cpu_cooling.h
 
@@ -15990,7 +16051,7 @@ F:      sound/soc/codecs/isabelle*
 TI LP855x BACKLIGHT DRIVER
 M:     Milo Kim <milo.kim@ti.com>
 S:     Maintained
-F:     Documentation/backlight/lp855x-driver.txt
+F:     Documentation/driver-api/backlight/lp855x-driver.rst
 F:     drivers/video/backlight/lp855x_bl.c
 F:     include/linux/platform_data/lp855x.h
 
@@ -16254,7 +16315,7 @@ M:      Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 M:     Jiri Slaby <jslaby@suse.com>
 S:     Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
-F:     Documentation/serial/
+F:     Documentation/driver-api/serial/
 F:     drivers/tty/
 F:     drivers/tty/serial/serial_core.c
 F:     include/linux/serial_core.h
@@ -16794,7 +16855,7 @@ W:      http://user-mode-linux.sourceforge.net
 Q:     https://patchwork.ozlabs.org/project/linux-um/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml.git
 S:     Maintained
-F:     Documentation/virtual/uml/
+F:     Documentation/virt/uml/
 F:     arch/um/
 F:     arch/x86/um/
 F:     fs/hostfs/
@@ -16865,7 +16926,7 @@ R:      Cornelia Huck <cohuck@redhat.com>
 L:     kvm@vger.kernel.org
 T:     git git://github.com/awilliam/linux-vfio.git
 S:     Maintained
-F:     Documentation/vfio.txt
+F:     Documentation/driver-api/vfio.rst
 F:     drivers/vfio/
 F:     include/linux/vfio.h
 F:     include/uapi/linux/vfio.h
@@ -16874,7 +16935,7 @@ VFIO MEDIATED DEVICE DRIVERS
 M:     Kirti Wankhede <kwankhede@nvidia.com>
 L:     kvm@vger.kernel.org
 S:     Maintained
-F:     Documentation/vfio-mediated-device.txt
+F:     Documentation/driver-api/vfio-mediated-device.rst
 F:     drivers/vfio/mdev/
 F:     include/linux/mdev.h
 F:     samples/vfio-mdev/
@@ -17062,6 +17123,13 @@ S:     Maintained
 F:     drivers/virtio/virtio_input.c
 F:     include/uapi/linux/virtio_input.h
 
+VIRTIO IOMMU DRIVER
+M:     Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
+L:     virtualization@lists.linux-foundation.org
+S:     Maintained
+F:     drivers/iommu/virtio-iommu.c
+F:     include/uapi/linux/virtio_iommu.h
+
 VIRTUAL BOX GUEST DEVICE DRIVER
 M:     Hans de Goede <hdegoede@redhat.com>
 M:     Arnd Bergmann <arnd@arndb.de>
@@ -17113,7 +17181,8 @@ S:      Maintained
 F:     drivers/misc/vmw_balloon.c
 
 VMWARE HYPERVISOR INTERFACE
-M:     Alok Kataria <akataria@vmware.com>
+M:     Thomas Hellstrom <thellstrom@vmware.com>
+M:     "VMware, Inc." <pv-drivers@vmware.com>
 L:     virtualization@lists.linux-foundation.org
 S:     Supported
 F:     arch/x86/kernel/cpu/vmware.c
@@ -17594,9 +17663,8 @@ L:      linux-xfs@vger.kernel.org
 W:     http://xfs.org/
 T:     git git://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git
 S:     Supported
-F:     Documentation/filesystems/xfs.txt
+F:     Documentation/admin-guide/xfs.rst
 F:     Documentation/ABI/testing/sysfs-fs-xfs
-F:     Documentation/filesystems/xfs.txt
 F:     Documentation/filesystems/xfs-delayed-logging-design.txt
 F:     Documentation/filesystems/xfs-self-describing-metadata.txt
 F:     fs/xfs/
@@ -17749,7 +17817,7 @@ R:      Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     drivers/block/zram/
-F:     Documentation/blockdev/zram.txt
+F:     Documentation/admin-guide/blockdev/zram.rst
 
 ZS DECSTATION Z85C30 SERIAL DRIVER
 M:     "Maciej W. Rozycki" <macro@linux-mips.org>
index 2c5d00b..9be5834 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0
 VERSION = 5
-PATCHLEVEL = 2
+PATCHLEVEL = 3
 SUBLEVEL = 0
-EXTRAVERSION =
+EXTRAVERSION = -rc1
 NAME = Bobtail Squid
 
 # *DOCUMENTATION*
@@ -486,11 +486,6 @@ export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE
 export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL
 export KBUILD_ARFLAGS
 
-# When compiling out-of-tree modules, put MODVERDIR in the module
-# tree rather than in the kernel tree. The kernel tree might
-# even be read-only.
-export MODVERDIR := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_versions
-
 # Files to ignore in find ... statements
 
 export RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o    \
@@ -887,6 +882,12 @@ KBUILD_CFLAGS   += $(call cc-option,-Werror=designated-init)
 # change __FILE__ to the relative path from the srctree
 KBUILD_CFLAGS  += $(call cc-option,-fmacro-prefix-map=$(srctree)/=)
 
+# ensure -fcf-protection is disabled when using retpoline as it is
+# incompatible with -mindirect-branch=thunk-extern
+ifdef CONFIG_RETPOLINE
+KBUILD_CFLAGS += $(call cc-option,-fcf-protection=none)
+endif
+
 # use the deterministic mode of AR if available
 KBUILD_ARFLAGS := $(call ar-option,D)
 
@@ -900,10 +901,8 @@ KBUILD_CPPFLAGS += $(ARCH_CPPFLAGS) $(KCPPFLAGS)
 KBUILD_AFLAGS   += $(ARCH_AFLAGS)   $(KAFLAGS)
 KBUILD_CFLAGS   += $(ARCH_CFLAGS)   $(KCFLAGS)
 
-# Use --build-id when available.
-LDFLAGS_BUILD_ID := $(call ld-option, --build-id)
-KBUILD_LDFLAGS_MODULE += $(LDFLAGS_BUILD_ID)
-LDFLAGS_vmlinux += $(LDFLAGS_BUILD_ID)
+KBUILD_LDFLAGS_MODULE += --build-id
+LDFLAGS_vmlinux += --build-id
 
 ifeq ($(CONFIG_STRIP_ASM_SYMS),y)
 LDFLAGS_vmlinux        += $(call ld-option, -X,)
@@ -1031,8 +1030,8 @@ vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_OBJS) $(KBUILD_VMLINUX_LIBS)
 
 # Recurse until adjust_autoksyms.sh is satisfied
 PHONY += autoksyms_recursive
-autoksyms_recursive: $(vmlinux-deps)
 ifdef CONFIG_TRIM_UNUSED_KSYMS
+autoksyms_recursive: $(vmlinux-deps) modules.order
        $(Q)$(CONFIG_SHELL) $(srctree)/scripts/adjust_autoksyms.sh \
          "$(MAKE) -f $(srctree)/Makefile vmlinux"
 endif
@@ -1074,7 +1073,7 @@ $(sort $(vmlinux-deps)): $(vmlinux-dirs) ;
 
 PHONY += $(vmlinux-dirs)
 $(vmlinux-dirs): prepare
-       $(Q)$(MAKE) $(build)=$@ need-builtin=1
+       $(Q)$(MAKE) $(build)=$@ need-builtin=1 need-modorder=1
 
 filechk_kernel.release = \
        echo "$(KERNELVERSION)$$($(CONFIG_SHELL) $(srctree)/scripts/setlocalversion $(srctree))"
@@ -1096,7 +1095,7 @@ scripts: scripts_basic scripts_dtc
 # archprepare is used in arch Makefiles and when processed asm symlink,
 # version.h and scripts_basic is processed / created.
 
-PHONY += prepare archprepare prepare1 prepare3
+PHONY += prepare archprepare prepare3
 
 # prepare3 is used to check if we are building in a separate output directory,
 # and if so do:
@@ -1113,11 +1112,8 @@ ifdef building_out_of_srctree
        fi;
 endif
 
-prepare1: prepare3 outputmakefile asm-generic $(version_h) $(autoksyms_h) \
-                                               include/generated/utsrelease.h
-       $(cmd_crmodverdir)
-
-archprepare: archheaders archscripts prepare1 scripts
+archprepare: archheaders archscripts scripts prepare3 outputmakefile \
+       asm-generic $(version_h) $(autoksyms_h) include/generated/utsrelease.h
 
 prepare0: archprepare
        $(Q)$(MAKE) $(build)=scripts/mod
@@ -1331,8 +1327,8 @@ _modinst_:
                rm -f $(MODLIB)/build ; \
                ln -s $(CURDIR) $(MODLIB)/build ; \
        fi
-       @cp -f $(objtree)/modules.order $(MODLIB)/
-       @cp -f $(objtree)/modules.builtin $(MODLIB)/
+       @sed 's:^:kernel/:' modules.order > $(MODLIB)/modules.order
+       @sed 's:^:kernel/:' modules.builtin > $(MODLIB)/modules.builtin
        @cp -f $(objtree)/modules.builtin.modinfo $(MODLIB)/
        $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modinst
 
@@ -1373,18 +1369,22 @@ endif # CONFIG_MODULES
 # make distclean Remove editor backup files, patch leftover files and the like
 
 # Directories & files removed with 'make clean'
-CLEAN_DIRS  += $(MODVERDIR) include/ksym
+CLEAN_DIRS  += include/ksym
 CLEAN_FILES += modules.builtin.modinfo
 
 # Directories & files removed with 'make mrproper'
 MRPROPER_DIRS  += include/config include/generated          \
                  arch/$(SRCARCH)/include/generated .tmp_objdiff
 MRPROPER_FILES += .config .config.old .version \
-                 Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS \
+                 Module.symvers \
                  signing_key.pem signing_key.priv signing_key.x509     \
                  x509.genkey extra_certificates signing_key.x509.keyid \
                  signing_key.x509.signer vmlinux-gdb.py
 
+# Directories & files removed with 'make distclean'
+DISTCLEAN_DIRS  +=
+DISTCLEAN_FILES += tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS
+
 # clean - Delete most, but leave enough to build external modules
 #
 clean: rm-dirs  := $(CLEAN_DIRS)
@@ -1417,9 +1417,14 @@ mrproper: clean $(mrproper-dirs)
 
 # distclean
 #
+distclean: rm-dirs  := $(wildcard $(DISTCLEAN_DIRS))
+distclean: rm-files := $(wildcard $(DISTCLEAN_FILES))
+
 PHONY += distclean
 
 distclean: mrproper
+       $(call cmd,rmdirs)
+       $(call cmd,rmfiles)
        @find $(srctree) $(RCS_FIND_IGNORE) \
                \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
                -o -name '*.bak' -o -name '#*#' -o -name '*%' \
@@ -1609,7 +1614,7 @@ $(objtree)/Module.symvers:
 module-dirs := $(addprefix _module_,$(KBUILD_EXTMOD))
 PHONY += $(module-dirs) modules
 $(module-dirs): prepare $(objtree)/Module.symvers
-       $(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@)
+       $(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@) need-modorder=1
 
 modules: $(module-dirs)
        @$(kecho) '  Building modules, stage 2.';
@@ -1634,7 +1639,6 @@ PHONY += $(clean-dirs) clean
 $(clean-dirs):
        $(Q)$(MAKE) $(clean)=$(patsubst _clean_%,%,$@)
 
-clean: rm-dirs := $(MODVERDIR)
 clean: rm-files := $(KBUILD_EXTMOD)/Module.symvers
 
 PHONY += help
@@ -1648,8 +1652,6 @@ help:
        @echo  ''
 
 PHONY += prepare
-prepare:
-       $(cmd_crmodverdir)
 endif # KBUILD_EXTMOD
 
 clean: $(clean-dirs)
@@ -1660,7 +1662,7 @@ clean: $(clean-dirs)
                -o -name '*.ko.*' \
                -o -name '*.dtb' -o -name '*.dtb.S' -o -name '*.dt.yaml' \
                -o -name '*.dwo' -o -name '*.lst' \
-               -o -name '*.su'  \
+               -o -name '*.su' -o -name '*.mod' \
                -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
                -o -name '*.lex.c' -o -name '*.tab.[ch]' \
                -o -name '*.asn1.[ch]' \
@@ -1765,8 +1767,6 @@ build-dir = $(patsubst %/,%,$(dir $(build-target)))
        $(Q)$(MAKE) $(build)=$(build-dir) $(build-target)
 %.symtypes: prepare FORCE
        $(Q)$(MAKE) $(build)=$(build-dir) $(build-target)
-%.ko: %.o
-       $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
 
 # Modules
 PHONY += /
@@ -1789,11 +1789,6 @@ quiet_cmd_depmod = DEPMOD  $(KERNELRELEASE)
       cmd_depmod = $(CONFIG_SHELL) $(srctree)/scripts/depmod.sh $(DEPMOD) \
                    $(KERNELRELEASE)
 
-# Create temporary dir for module support files
-# clean it up only when building all modules
-cmd_crmodverdir = $(Q)mkdir -p $(MODVERDIR) \
-                  $(if $(KBUILD_MODULES),; rm -f $(MODVERDIR)/*)
-
 # read saved command lines for existing targets
 existing-targets := $(wildcard $(sort $(targets)))
 
index e8d19c3..a7b57dd 100644 (file)
@@ -128,22 +128,6 @@ config UPROBES
            managed by the kernel and kept transparent to the probed
            application. )
 
-config HAVE_64BIT_ALIGNED_ACCESS
-       def_bool 64BIT && !HAVE_EFFICIENT_UNALIGNED_ACCESS
-       help
-         Some architectures require 64 bit accesses to be 64 bit
-         aligned, which also requires structs containing 64 bit values
-         to be 64 bit aligned too. This includes some 32 bit
-         architectures which can do 64 bit accesses, as well as 64 bit
-         architectures without unaligned access.
-
-         This symbol should be selected by an architecture if 64 bit
-         accesses are required to be 64 bit aligned in this way even
-         though it is not a 64 bit architecture.
-
-         See Documentation/unaligned-memory-access.txt for more
-         information on the topic of unaligned memory accesses.
-
 config HAVE_EFFICIENT_UNALIGNED_ACCESS
        bool
        help
@@ -585,6 +569,9 @@ config HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
 config HAVE_ARCH_HUGE_VMAP
        bool
 
+config ARCH_WANT_HUGE_PMD_SHARE
+       bool
+
 config HAVE_ARCH_SOFT_DIRTY
        bool
 
@@ -809,6 +796,9 @@ config ARCH_NO_COHERENT_DMA_MMAP
 config ARCH_NO_PREEMPT
        bool
 
+config ARCH_SUPPORTS_RT
+       bool
+
 config CPU_NO_EFFICIENT_FFS
        def_bool n
 
index ccf9d65..af2c006 100644 (file)
@@ -93,11 +93,6 @@ static inline void * phys_to_virt(unsigned long address)
 
 #define page_to_phys(page)     page_to_pa(page)
 
-static inline dma_addr_t __deprecated isa_page_to_bus(struct page *page)
-{
-       return page_to_phys(page);
-}
-
 /* Maximum PIO space address supported?  */
 #define IO_SPACE_LIMIT 0xffff
 
index 1db9bbc..728fe02 100644 (file)
 542    common  fsmount                         sys_fsmount
 543    common  fspick                          sys_fspick
 544    common  pidfd_open                      sys_pidfd_open
+# 545 reserved for clone3
index 1ebfa04..44bc522 100644 (file)
                        #interrupt-cells = <1>;
                        interrupts = <20>;
                };
+
+               virtio0: virtio@f0100000 {
+                       compatible = "virtio,mmio";
+                       reg = <0xf0100000 0x2000>;
+                       interrupts = <31>;
+               };
+
+               virtio1: virtio@f0102000 {
+                       compatible = "virtio,mmio";
+                       reg = <0xf0102000 0x2000>;
+                       interrupts = <32>;
+               };
+
+               virtio2: virtio@f0104000 {
+                       compatible = "virtio,mmio";
+                       reg = <0xf0104000 0x2000>;
+                       interrupts = <33>;
+               };
+
+               virtio3: virtio@f0106000 {
+                       compatible = "virtio,mmio";
+                       reg = <0xf0106000 0x2000>;
+                       interrupts = <34>;
+               };
+
+               virtio4: virtio@f0108000 {
+                       compatible = "virtio,mmio";
+                       reg = <0xf0108000 0x2000>;
+                       interrupts = <35>;
+               };
        };
 };
index 9a45cb0..bfc7f5f 100644 (file)
@@ -8,6 +8,7 @@
  */
 /dts-v1/;
 
+#include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/reset/snps,hsdk-reset.h>
 
 / {
                        dma-coherent;
                };
 
+               spi0: spi@20000 {
+                       compatible = "snps,dw-apb-ssi";
+                       reg = <0x20000 0x100>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       interrupts = <16>;
+                       num-cs = <2>;
+                       reg-io-width = <4>;
+                       clocks = <&input_clk>;
+                       cs-gpios = <&creg_gpio 0 GPIO_ACTIVE_LOW>,
+                                  <&creg_gpio 1 GPIO_ACTIVE_LOW>;
+               };
+
                creg_gpio: gpio@14b0 {
                        compatible = "snps,creg-gpio-hsdk";
                        reg = <0x14b0 0x4>;
index b117e6c..436f213 100644 (file)
@@ -35,10 +35,12 @@ CONFIG_INET=y
 # CONFIG_IPV6 is not set
 # CONFIG_WIRELESS is not set
 CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
-# CONFIG_BLK_DEV is not set
+CONFIG_VIRTIO_BLK=y
 CONFIG_NETDEVICES=y
+CONFIG_VIRTIO_NET=y
 # CONFIG_NET_VENDOR_ARC is not set
 # CONFIG_NET_VENDOR_BROADCOM is not set
 # CONFIG_NET_VENDOR_INTEL is not set
@@ -68,6 +70,7 @@ CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
 # CONFIG_HID is not set
 # CONFIG_USB_SUPPORT is not set
+CONFIG_VIRTIO_MMIO=y
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
index c8fb5d6..403125d 100644 (file)
@@ -46,6 +46,9 @@ CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_DW=y
 CONFIG_SERIAL_OF_PLATFORM=y
 # CONFIG_HW_RANDOM is not set
+CONFIG_SPI=y
+CONFIG_SPI_DESIGNWARE=y
+CONFIG_SPI_DW_MMIO=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_DWAPB=y
@@ -66,6 +69,8 @@ CONFIG_MMC=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_DW=y
+CONFIG_DMADEVICES=y
+CONFIG_DW_AXI_DMAC=y
 CONFIG_EXT3_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
index 225e7df..f5ae394 100644 (file)
 #include <asm/irqflags-arcv2.h>
 #include <asm/thread_info.h>   /* For THREAD_SIZE */
 
+/*
+ * Interrupt/Exception stack layout (pt_regs) for ARCv2
+ *   (End of struct aligned to end of page [unless nested])
+ *
+ *  INTERRUPT                          EXCEPTION
+ *
+ *    manual    ---------------------  manual
+ *              |      orig_r0      |
+ *              |      event/ECR    |
+ *              |      bta          |
+ *              |      user_r25     |
+ *              |      gp           |
+ *              |      fp           |
+ *              |      sp           |
+ *              |      r12          |
+ *              |      r30          |
+ *              |      r58          |
+ *              |      r59          |
+ *  hw autosave ---------------------
+ *    optional  |      r0           |
+ *              |      r1           |
+ *              ~                   ~
+ *              |      r9           |
+ *              |      r10          |
+ *              |      r11          |
+ *              |      blink        |
+ *              |      lpe          |
+ *              |      lps          |
+ *              |      lpc          |
+ *              |      ei base      |
+ *              |      ldi base     |
+ *              |      jli base     |
+ *              ---------------------
+ *  hw autosave |       pc / eret   |
+ *   mandatory  | stat32 / erstatus |
+ *              ---------------------
+ */
+
 /*------------------------------------------------------------------------*/
-.macro INTERRUPT_PROLOGUE      called_from
+.macro INTERRUPT_PROLOGUE
 
-       ; Before jumping to Interrupt Vector, hardware micro-ops did following:
+       ; (A) Before jumping to Interrupt Vector, hardware micro-ops did following:
        ;   1. SP auto-switched to kernel mode stack
-       ;   2. STATUS32.Z flag set to U mode at time of interrupt (U:1, K:0)
-       ;   3. Auto saved: r0-r11, blink, LPE,LPS,LPC, JLI,LDI,EI, PC, STAT32
+       ;   2. STATUS32.Z flag set if in U mode at time of interrupt (U:1,K:0)
+       ;   3. Auto save: (mandatory) Push PC and STAT32 on stack
+       ;                 hardware does even if CONFIG_ARC_IRQ_NO_AUTOSAVE
+       ;   4. Auto save: (optional) r0-r11, blink, LPE,LPS,LPC, JLI,LDI,EI
        ;
-       ; Now manually save: r12, sp, fp, gp, r25
+       ; (B) Manually saved some regs: r12,r25,r30, sp,fp,gp, ACCL pair
 
 #ifdef CONFIG_ARC_IRQ_NO_AUTOSAVE
-.ifnc \called_from, exception
-       st.as   r9, [sp, -10]   ; save r9 in it's final stack slot
-       sub     sp, sp, 12      ; skip JLI, LDI, EI
-
-       PUSH    lp_count
-       PUSHAX  lp_start
-       PUSHAX  lp_end
-       PUSH    blink
-
-       PUSH    r11
-       PUSH    r10
-
-       sub     sp, sp, 4       ; skip r9
-
-       PUSH    r8
-       PUSH    r7
-       PUSH    r6
-       PUSH    r5
-       PUSH    r4
-       PUSH    r3
-       PUSH    r2
-       PUSH    r1
-       PUSH    r0
-.endif
-#endif
+       ; carve pt_regs on stack (case #3), PC/STAT32 already on stack
+       sub     sp, sp, SZ_PT_REGS - 8
 
-#ifdef CONFIG_ARC_HAS_ACCL_REGS
-       PUSH    r59
-       PUSH    r58
+       __SAVE_REGFILE_HARD
+#else
+       ; carve pt_regs on stack (case #4), which grew partially already
+       sub     sp, sp, PT_r0
 #endif
 
-       PUSH    r30
-       PUSH    r12
+       __SAVE_REGFILE_SOFT
+.endm
+
+/*------------------------------------------------------------------------*/
+.macro EXCEPTION_PROLOGUE
+
+       ; (A) Before jumping to Exception Vector, hardware micro-ops did following:
+       ;   1. SP auto-switched to kernel mode stack
+       ;   2. STATUS32.Z flag set if in U mode at time of exception (U:1,K:0)
+       ;
+       ; (B) Manually save the complete reg file below
+
+       sub     sp, sp, SZ_PT_REGS      ; carve pt_regs
+
+       ; _HARD saves r10 clobbered by _SOFT as scratch hence comes first
+
+       __SAVE_REGFILE_HARD
+       __SAVE_REGFILE_SOFT
+
+       st      r0, [sp]        ; orig_r0
+
+       lr      r10, [eret]
+       lr      r11, [erstatus]
+       ST2     r10, r11, PT_ret
+
+       lr      r10, [ecr]
+       lr      r11, [erbta]
+       ST2     r10, r11, PT_event
+
+       ; OUTPUT: r10 has ECR expected by EV_Trap
+.endm
+
+/*------------------------------------------------------------------------
+ * This macro saves the registers manually which would normally be autosaved
+ * by hardware on taken interrupts. It is used by
+ *   - exception handlers (which don't have autosave)
+ *   - interrupt autosave disabled due to CONFIG_ARC_IRQ_NO_AUTOSAVE
+ */
+.macro __SAVE_REGFILE_HARD
+
+       ST2     r0,  r1,  PT_r0
+       ST2     r2,  r3,  PT_r2
+       ST2     r4,  r5,  PT_r4
+       ST2     r6,  r7,  PT_r6
+       ST2     r8,  r9,  PT_r8
+       ST2     r10, r11, PT_r10
+
+       st      blink, [sp, PT_blink]
+
+       lr      r10, [lp_end]
+       lr      r11, [lp_start]
+       ST2     r10, r11, PT_lpe
+
+       st      lp_count, [sp, PT_lpc]
+
+       ; skip JLI, LDI, EI for now
+.endm
+
+/*------------------------------------------------------------------------
+ * This macros saves a bunch of other registers which can't be autosaved for
+ * various reasons:
+ *   - r12: the last caller saved scratch reg since hardware saves in pairs so r0-r11
+ *   - r30: free reg, used by gcc as scratch
+ *   - ACCL/ACCH pair when they exist
+ */
+.macro __SAVE_REGFILE_SOFT
+
+       ST2     gp, fp, PT_r26          ; gp (r26), fp (r27)
+
+       st      r12, [sp, PT_sp + 4]
+       st      r30, [sp, PT_sp + 8]
 
        ; Saving pt_regs->sp correctly requires some extra work due to the way
        ; Auto stack switch works
        ;  - U mode: retrieve it from AUX_USER_SP
        ;  - K mode: add the offset from current SP where H/w starts auto push
        ;
-       ; Utilize the fact that Z bit is set if Intr taken in U mode
-       mov.nz  r9, sp
-       add.nz  r9, r9, SZ_PT_REGS - PT_sp - 4
-       bnz     1f
+       ; 1. Utilize the fact that Z bit is set if Intr taken in U mode
+       ; 2. Upon entry SP is always saved (for any inspection, unwinding etc),
+       ;    but on return, restored only if U mode
 
-       lr      r9, [AUX_USER_SP]
-1:
-       PUSH    r9      ; SP
+       lr      r10, [AUX_USER_SP]      ; U mode SP
+
+       ; ISA requires ADD.nz to have same dest and src reg operands
+       mov.nz  r10, sp
+       add.nz  r10, r10, SZ_PT_REGS    ; K mode SP
 
-       PUSH    fp
-       PUSH    gp
+       st      r10, [sp, PT_sp]        ; SP (pt_regs->sp)
 
 #ifdef CONFIG_ARC_CURR_IN_REG
-       PUSH    r25                     ; user_r25
+       st      r25, [sp, PT_user_r25]
        GET_CURR_TASK_ON_CPU    r25
-#else
-       sub     sp, sp, 4
 #endif
 
-.ifnc \called_from, exception
-       sub     sp, sp, 12      ; BTA/ECR/orig_r0 placeholder per pt_regs
-.endif
+#ifdef CONFIG_ARC_HAS_ACCL_REGS
+       ST2     r58, r59, PT_sp + 12
+#endif
 
 .endm
 
 /*------------------------------------------------------------------------*/
-.macro INTERRUPT_EPILOGUE      called_from
+.macro __RESTORE_REGFILE_SOFT
 
-.ifnc \called_from, exception
-       add     sp, sp, 12      ; skip BTA/ECR/orig_r0 placeholderss
-.endif
+       LD2     gp, fp, PT_r26          ; gp (r26), fp (r27)
 
-#ifdef CONFIG_ARC_CURR_IN_REG
-       POP     r25
-#else
-       add     sp, sp, 4
-#endif
+       ld      r12, [sp, PT_sp + 4]
+       ld      r30, [sp, PT_sp + 8]
 
-       POP     gp
-       POP     fp
-
-       ; Don't touch AUX_USER_SP if returning to K mode (Z bit set)
-       ; (Z bit set on K mode is inverse of INTERRUPT_PROLOGUE)
-       add.z   sp, sp, 4
+       ; Restore SP (into AUX_USER_SP) only if returning to U mode
+       ;  - for K mode, it will be implicitly restored as stack is unwound
+       ;  - Z flag set on K is inverse of what hardware does on interrupt entry
+       ;    but that doesn't really matter
        bz      1f
 
-       POPAX   AUX_USER_SP
+       ld      r10, [sp, PT_sp]        ; SP (pt_regs->sp)
+       sr      r10, [AUX_USER_SP]
 1:
-       POP     r12
-       POP     r30
 
-#ifdef CONFIG_ARC_HAS_ACCL_REGS
-       POP     r58
-       POP     r59
+#ifdef CONFIG_ARC_CURR_IN_REG
+       ld      r25, [sp, PT_user_r25]
 #endif
 
-#ifdef CONFIG_ARC_IRQ_NO_AUTOSAVE
-.ifnc \called_from, exception
-       POP     r0
-       POP     r1
-       POP     r2
-       POP     r3
-       POP     r4
-       POP     r5
-       POP     r6
-       POP     r7
-       POP     r8
-       POP     r9
-       POP     r10
-       POP     r11
-
-       POP     blink
-       POPAX   lp_end
-       POPAX   lp_start
-
-       POP     r9
-       mov     lp_count, r9
-
-       add     sp, sp, 12      ; skip JLI, LDI, EI
-       ld.as   r9, [sp, -10]   ; reload r9 which got clobbered
-.endif
+#ifdef CONFIG_ARC_HAS_ACCL_REGS
+       LD2     r58, r59, PT_sp + 12
 #endif
+.endm
 
+/*------------------------------------------------------------------------*/
+.macro __RESTORE_REGFILE_HARD
+
+       ld      blink, [sp, PT_blink]
+
+       LD2     r10, r11, PT_lpe
+       sr      r10, [lp_end]
+       sr      r11, [lp_start]
+
+       ld      r10, [sp, PT_lpc]       ; lp_count can't be target of LD
+       mov     lp_count, r10
+
+       LD2     r0,  r1,  PT_r0
+       LD2     r2,  r3,  PT_r2
+       LD2     r4,  r5,  PT_r4
+       LD2     r6,  r7,  PT_r6
+       LD2     r8,  r9,  PT_r8
+       LD2     r10, r11, PT_r10
 .endm
 
+
 /*------------------------------------------------------------------------*/
-.macro EXCEPTION_PROLOGUE
+.macro INTERRUPT_EPILOGUE
 
-       ; Before jumping to Exception Vector, hardware micro-ops did following:
-       ;   1. SP auto-switched to kernel mode stack
-       ;   2. STATUS32.Z flag set to U mode at time of interrupt (U:1,K:0)
-       ;
-       ; Now manually save the complete reg file
-
-       PUSH    r9              ; freeup a register: slot of erstatus
-
-       PUSHAX  eret
-       sub     sp, sp, 12      ; skip JLI, LDI, EI
-       PUSH    lp_count
-       PUSHAX  lp_start
-       PUSHAX  lp_end
-       PUSH    blink
-
-       PUSH    r11
-       PUSH    r10
-
-       ld.as   r9,  [sp, 10]   ; load stashed r9 (status32 stack slot)
-       lr      r10, [erstatus]
-       st.as   r10, [sp, 10]   ; save status32 at it's right stack slot
-
-       PUSH    r9
-       PUSH    r8
-       PUSH    r7
-       PUSH    r6
-       PUSH    r5
-       PUSH    r4
-       PUSH    r3
-       PUSH    r2
-       PUSH    r1
-       PUSH    r0
-
-       ; -- for interrupts, regs above are auto-saved by h/w in that order --
-       ; Now do what ISR prologue does (manually save r12, sp, fp, gp, r25)
-       ;
-       ; Set Z flag if this was from U mode (expected by INTERRUPT_PROLOGUE)
-       ; Although H/w exception micro-ops do set Z flag for U mode (just like
-       ; for interrupts), it could get clobbered in case we soft land here from
-       ; a TLB Miss exception handler (tlbex.S)
+       ; INPUT: r0 has STAT32 of calling context
+       ; INPUT: Z flag set if returning to K mode
 
-       and     r10, r10, STATUS_U_MASK
-       xor.f   0, r10, STATUS_U_MASK
+       ; _SOFT clobbers r10 restored by _HARD hence the order
 
-       INTERRUPT_PROLOGUE  exception
+       __RESTORE_REGFILE_SOFT
 
-       PUSHAX  erbta
-       PUSHAX  ecr             ; r9 contains ECR, expected by EV_Trap
+#ifdef CONFIG_ARC_IRQ_NO_AUTOSAVE
+       __RESTORE_REGFILE_HARD
+       add     sp, sp, SZ_PT_REGS - 8
+#else
+       add     sp, sp, PT_r0
+#endif
 
-       PUSH    r0              ; orig_r0
 .endm
 
 /*------------------------------------------------------------------------*/
 .macro EXCEPTION_EPILOGUE
 
-       ; Assumes r0 has PT_status32
-       btst   r0, STATUS_U_BIT ; Z flag set if K, used in INTERRUPT_EPILOGUE
-
-       add     sp, sp, 8       ; orig_r0/ECR don't need restoring
-       POPAX   erbta
-
-       INTERRUPT_EPILOGUE  exception
+       ; INPUT: r0 has STAT32 of calling context
 
-       POP     r0
-       POP     r1
-       POP     r2
-       POP     r3
-       POP     r4
-       POP     r5
-       POP     r6
-       POP     r7
-       POP     r8
-       POP     r9
-       POP     r10
-       POP     r11
+       btst    r0, STATUS_U_BIT        ; Z flag set if K, used in restoring SP
 
-       POP     blink
-       POPAX   lp_end
-       POPAX   lp_start
+       ld      r10, [sp, PT_event + 4]
+       sr      r10, [erbta]
 
-       POP     r9
-       mov     lp_count, r9
+       LD2     r10, r11, PT_ret
+       sr      r10, [eret]
+       sr      r11, [erstatus]
 
-       add     sp, sp, 12      ; skip JLI, LDI, EI
-       POPAX   eret
-       POPAX   erstatus
+       __RESTORE_REGFILE_SOFT
+       __RESTORE_REGFILE_HARD
 
-       ld.as   r9, [sp, -12]   ; reload r9 which got clobbered
+       add     sp, sp, SZ_PT_REGS
 .endm
 
 .macro FAKE_RET_FROM_EXCPN
index 66ba1bf..66a2923 100644 (file)
        PUSHAX  CTOP_AUX_EFLAGS
 #endif
 
-       lr      r9, [ecr]
-       st      r9, [sp, PT_event]    /* EV_Trap expects r9 to have ECR */
+       lr      r10, [ecr]
+       st      r10, [sp, PT_event]    /* EV_Trap expects r10 to have ECR */
 .endm
 
 /*--------------------------------------------------------------
index 54f5ec5..a0eeb9f 100644 (file)
 
 #ifdef __ASSEMBLY__
 
+.macro ST2 e, o, off
+#ifdef CONFIG_ARC_HAS_LL64
+       std     \e, [sp, \off]
+#else
+       st      \e, [sp, \off]
+       st      \o, [sp, \off+4]
+#endif
+.endm
+
+.macro LD2 e, o, off
+#ifdef CONFIG_ARC_HAS_LL64
+       ldd     \e, [sp, \off]
+#else
+       ld      \e, [sp, \off]
+       ld      \o, [sp, \off+4]
+#endif
+.endm
+
 #define ASM_NL          `      /* use '`' to mark new line in macro */
 
 /* annotation for data we want in DCCM - if enabled in .config */
index da44618..1d87c18 100644 (file)
@@ -32,7 +32,7 @@
 #ifndef _ASM_ARC_PGTABLE_H
 #define _ASM_ARC_PGTABLE_H
 
-#include <linux/const.h>
+#include <linux/bits.h>
 #define __ARCH_USE_5LEVEL_HACK
 #include <asm-generic/pgtable-nopmd.h>
 #include <asm/page.h>
 #define BITS_FOR_PTE   (PGDIR_SHIFT - PAGE_SHIFT)
 #define BITS_FOR_PGD   (32 - PGDIR_SHIFT)
 
-#define PGDIR_SIZE     _BITUL(PGDIR_SHIFT)     /* vaddr span, not PDG sz */
+#define PGDIR_SIZE     BIT(PGDIR_SHIFT)        /* vaddr span, not PDG sz */
 #define PGDIR_MASK     (~(PGDIR_SIZE-1))
 
-#define        PTRS_PER_PTE    _BITUL(BITS_FOR_PTE)
-#define        PTRS_PER_PGD    _BITUL(BITS_FOR_PGD)
+#define        PTRS_PER_PTE    BIT(BITS_FOR_PTE)
+#define        PTRS_PER_PGD    BIT(BITS_FOR_PGD)
 
 /*
  * Number of entries a user land program use.
index dba1165..1f621e4 100644 (file)
@@ -55,7 +55,14 @@ int main(void)
        DEFINE(PT_r5, offsetof(struct pt_regs, r5));
        DEFINE(PT_r6, offsetof(struct pt_regs, r6));
        DEFINE(PT_r7, offsetof(struct pt_regs, r7));
+       DEFINE(PT_r8, offsetof(struct pt_regs, r8));
+       DEFINE(PT_r10, offsetof(struct pt_regs, r10));
+       DEFINE(PT_r26, offsetof(struct pt_regs, r26));
        DEFINE(PT_ret, offsetof(struct pt_regs, ret));
+       DEFINE(PT_blink, offsetof(struct pt_regs, blink));
+       DEFINE(PT_lpe, offsetof(struct pt_regs, lp_end));
+       DEFINE(PT_lpc, offsetof(struct pt_regs, lp_count));
+       DEFINE(PT_user_r25, offsetof(struct pt_regs, user_r25));
 
        DEFINE(SZ_CALLEE_REGS, sizeof(struct callee_regs));
        DEFINE(SZ_PT_REGS, sizeof(struct pt_regs));
index 14254b8..12d5f12 100644 (file)
@@ -67,7 +67,7 @@ reserved:
 
 ENTRY(handle_interrupt)
 
-       INTERRUPT_PROLOGUE  irq
+       INTERRUPT_PROLOGUE
 
        # irq control APIs local_irq_save/restore/disable/enable fiddle with
        # global interrupt enable bits in STATUS32 (.IE for 1 prio, .E[] for 2 prio)
@@ -79,7 +79,7 @@ ENTRY(handle_interrupt)
        #
        # Note this disable is only for consistent book-keeping as further interrupts
        # will be disabled anyways even w/o this. Hardware tracks active interrupts
-       # seperately in AUX_IRQ_ACTIVE.active and will not take new interrupts
+       # seperately in AUX_IRQ_ACT.active and will not take new interrupts
        # unless this one returns (or higher prio becomes pending in 2-prio scheme)
 
        IRQ_DISABLE
@@ -200,17 +200,18 @@ restore_regs:
        ld      r0, [sp, PT_status32]   ; U/K mode at time of entry
        lr      r10, [AUX_IRQ_ACT]
 
-       bmsk    r11, r10, 15    ; AUX_IRQ_ACT.ACTIVE
+       bmsk    r11, r10, 15            ; extract AUX_IRQ_ACT.active
        breq    r11, 0, .Lexcept_ret    ; No intr active, ret from Exception
 
 ;####### Return from Intr #######
 
+.Lisr_ret:
+
 debug_marker_l1:
        ; bbit1.nt r0, STATUS_DE_BIT, .Lintr_ret_to_delay_slot
        btst    r0, STATUS_DE_BIT               ; Z flag set if bit clear
        bnz     .Lintr_ret_to_delay_slot        ; branch if STATUS_DE_BIT set
 
-.Lisr_ret_fast_path:
        ; Handle special case #1: (Entry via Exception, Return via IRQ)
        ;
        ; Exception in U mode, preempted in kernel, Intr taken (K mode), orig
@@ -223,7 +224,7 @@ debug_marker_l1:
        bset.nz r11, r11, AUX_IRQ_ACT_BIT_U     ; NZ means U
        sr      r11, [AUX_IRQ_ACT]
 
-       INTERRUPT_EPILOGUE  irq
+       INTERRUPT_EPILOGUE
        rtie
 
 ;####### Return from Exception / pure kernel mode #######
@@ -244,8 +245,8 @@ debug_marker_syscall:
 ;
 ; IRQ RTIE won't reliably restore DE bit and/or BTA, needs workaround
 ;
-; Solution is return from Intr w/o any delay slot quirks into a kernel trampoline
-; and from pure kernel mode return to delay slot which handles DS bit/BTA correctly
+; Solution is to drop out of interrupt context into pure kernel mode
+; and return from pure kernel mode which does right things for delay slot
 
 .Lintr_ret_to_delay_slot:
 debug_marker_ds:
@@ -254,48 +255,9 @@ debug_marker_ds:
        add     r2, r2, 1
        st      r2, [@intr_to_DE_cnt]
 
-       ld      r2, [sp, PT_ret]
-       ld      r3, [sp, PT_status32]
-
-       ; STAT32 for Int return created from scratch
-       ; (No delay dlot, disable Further intr in trampoline)
-
-       bic     r0, r3, STATUS_U_MASK|STATUS_DE_MASK|STATUS_IE_MASK|STATUS_L_MASK
-       st      r0, [sp, PT_status32]
-
-       mov     r1, .Lintr_ret_to_delay_slot_2
-       st      r1, [sp, PT_ret]
-
-       ; Orig exception PC/STAT32 safekept @orig_r0 and @event stack slots
-       st      r2, [sp, 0]
-       st      r3, [sp, 4]
-
-       b       .Lisr_ret_fast_path
-
-.Lintr_ret_to_delay_slot_2:
-       ; Trampoline to restore orig exception PC/STAT32/BTA/AUX_USER_SP
-       sub     sp, sp, SZ_PT_REGS
-       st      r9, [sp, -4]
-
-       ld      r9, [sp, 0]
-       sr      r9, [eret]
-
-       ld      r9, [sp, 4]
-       sr      r9, [erstatus]
-
-       ; restore AUX_USER_SP if returning to U mode
-       bbit0   r9, STATUS_U_BIT, 1f
-       ld      r9, [sp, PT_sp]
-       sr      r9, [AUX_USER_SP]
-
-1:
-       ld      r9, [sp, 8]
-       sr      r9, [erbta]
-
-       ld      r9, [sp, -4]
-       add     sp, sp, SZ_PT_REGS
-
-       ; return from pure kernel mode to delay slot
-       rtie
+       ; drop out of interrupt context (clear AUX_IRQ_ACT.active)
+       bmskn   r11, r10, 15
+       sr      r11, [AUX_IRQ_ACT]
+       b       .Lexcept_ret
 
 END(ret_from_exception)
index 7fe5988..5cb0cd7 100644 (file)
@@ -256,7 +256,7 @@ ENTRY(EV_TLBProtV)
 
        EXCEPTION_PROLOGUE
 
-       mov r2, r9      ; ECR set into r9 already
+       mov r2, r10     ; ECR set into r10 already
        lr  r0, [efa]   ; Faulting Data address (not part of pt_regs saved above)
 
        ; Exception auto-disables further Intr/exceptions.
index a2bfacb..72be012 100644 (file)
@@ -232,8 +232,8 @@ ENTRY(EV_Trap)
        EXCEPTION_PROLOGUE
 
        ;============ TRAP 1   :breakpoints
-       ; Check ECR for trap with arg (PROLOGUE ensures r9 has ECR)
-       bmsk.f 0, r9, 7
+       ; Check ECR for trap with arg (PROLOGUE ensures r10 has ECR)
+       bmsk.f 0, r10, 7
        bnz    trap_with_param
 
        ;============ TRAP  (no param): syscall top level
index 182ce67..c2663fc 100644 (file)
@@ -181,11 +181,6 @@ static void *__init unw_hdr_alloc_early(unsigned long sz)
        return memblock_alloc_from(sz, sizeof(unsigned int), MAX_DMA_ADDRESS);
 }
 
-static void *unw_hdr_alloc(unsigned long sz)
-{
-       return kmalloc(sz, GFP_KERNEL);
-}
-
 static void init_unwind_table(struct unwind_table *table, const char *name,
                              const void *core_start, unsigned long core_size,
                              const void *init_start, unsigned long init_size,
@@ -366,6 +361,10 @@ ret_err:
 }
 
 #ifdef CONFIG_MODULES
+static void *unw_hdr_alloc(unsigned long sz)
+{
+       return kmalloc(sz, GFP_KERNEL);
+}
 
 static struct unwind_table *last_table;
 
index 81e8442..3861543 100644 (file)
@@ -63,24 +63,19 @@ void do_page_fault(unsigned long address, struct pt_regs *regs)
        struct vm_area_struct *vma = NULL;
        struct task_struct *tsk = current;
        struct mm_struct *mm = tsk->mm;
-       int si_code = SEGV_MAPERR;
-       int ret;
-       vm_fault_t fault;
-       int write = regs->ecr_cause & ECR_C_PROTV_STORE;  /* ST/EX */
-       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
+       int sig, si_code = SEGV_MAPERR;
+       unsigned int write = 0, exec = 0, mask;
+       vm_fault_t fault = VM_FAULT_SIGSEGV;    /* handle_mm_fault() output */
+       unsigned int flags;                     /* handle_mm_fault() input */
 
        /*
-        * We fault-in kernel-space virtual memory on-demand. The
-        * 'reference' page table is init_mm.pgd.
-        *
         * NOTE! We MUST NOT take any locks for this case. We may
         * be in an interrupt or a critical region, and should
         * only copy the information from the master page table,
         * nothing more.
         */
        if (address >= VMALLOC_START && !user_mode(regs)) {
-               ret = handle_kernel_vaddr_fault(address);
-               if (unlikely(ret))
+               if (unlikely(handle_kernel_vaddr_fault(address)))
                        goto no_context;
                else
                        return;
@@ -93,143 +88,117 @@ void do_page_fault(unsigned long address, struct pt_regs *regs)
        if (faulthandler_disabled() || !mm)
                goto no_context;
 
+       if (regs->ecr_cause & ECR_C_PROTV_STORE)        /* ST/EX */
+               write = 1;
+       else if ((regs->ecr_vec == ECR_V_PROTV) &&
+                (regs->ecr_cause == ECR_C_PROTV_INST_FETCH))
+               exec = 1;
+
+       flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
        if (user_mode(regs))
                flags |= FAULT_FLAG_USER;
+       if (write)
+               flags |= FAULT_FLAG_WRITE;
+
 retry:
        down_read(&mm->mmap_sem);
+
        vma = find_vma(mm, address);
        if (!vma)
                goto bad_area;
-       if (vma->vm_start <= address)
-               goto good_area;
-       if (!(vma->vm_flags & VM_GROWSDOWN))
-               goto bad_area;
-       if (expand_stack(vma, address))
-               goto bad_area;
+       if (unlikely(address < vma->vm_start)) {
+               if (!(vma->vm_flags & VM_GROWSDOWN) || expand_stack(vma, address))
+                       goto bad_area;
+       }
 
        /*
-        * Ok, we have a good vm_area for this memory access, so
-        * we can handle it..
+        * vm_area is good, now check permissions for this memory access
         */
-good_area:
-       si_code = SEGV_ACCERR;
-
-       /* Handle protection violation, execute on heap or stack */
-
-       if ((regs->ecr_vec == ECR_V_PROTV) &&
-           (regs->ecr_cause == ECR_C_PROTV_INST_FETCH))
+       mask = VM_READ;
+       if (write)
+               mask = VM_WRITE;
+       if (exec)
+               mask = VM_EXEC;
+
+       if (!(vma->vm_flags & mask)) {
+               si_code = SEGV_ACCERR;
                goto bad_area;
-
-       if (write) {
-               if (!(vma->vm_flags & VM_WRITE))
-                       goto bad_area;
-               flags |= FAULT_FLAG_WRITE;
-       } else {
-               if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
-                       goto bad_area;
        }
 
-       /*
-        * If for any reason at all we couldn't handle the fault,
-        * make sure we exit gracefully rather than endlessly redo
-        * the fault.
-        */
        fault = handle_mm_fault(vma, address, flags);
 
-       if (fatal_signal_pending(current)) {
+       /*
+        * Fault retry nuances
+        */
+       if (unlikely(fault & VM_FAULT_RETRY)) {
 
                /*
-                * if fault retry, mmap_sem already relinquished by core mm
-                * so OK to return to user mode (with signal handled first)
+                * If fault needs to be retried, handle any pending signals
+                * first (by returning to user mode).
+                * mmap_sem already relinquished by core mm for RETRY case
                 */
-               if (fault & VM_FAULT_RETRY) {
+               if (fatal_signal_pending(current)) {
                        if (!user_mode(regs))
                                goto no_context;
                        return;
                }
-       }
-
-       perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
-
-       if (likely(!(fault & VM_FAULT_ERROR))) {
+               /*
+                * retry state machine
+                */
                if (flags & FAULT_FLAG_ALLOW_RETRY) {
-                       /* To avoid updating stats twice for retry case */
-                       if (fault & VM_FAULT_MAJOR) {
-                               tsk->maj_flt++;
-                               perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
-                                             regs, address);
-                       } else {
-                               tsk->min_flt++;
-                               perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
-                                             regs, address);
-                       }
-
-                       if (fault & VM_FAULT_RETRY) {
-                               flags &= ~FAULT_FLAG_ALLOW_RETRY;
-                               flags |= FAULT_FLAG_TRIED;
-                               goto retry;
-                       }
+                       flags &= ~FAULT_FLAG_ALLOW_RETRY;
+                       flags |= FAULT_FLAG_TRIED;
+                       goto retry;
                }
-
-               /* Fault Handled Gracefully */
-               up_read(&mm->mmap_sem);
-               return;
        }
 
-       if (fault & VM_FAULT_OOM)
-               goto out_of_memory;
-       else if (fault & VM_FAULT_SIGSEGV)
-               goto bad_area;
-       else if (fault & VM_FAULT_SIGBUS)
-               goto do_sigbus;
-
-       /* no man's land */
-       BUG();
+bad_area:
+       up_read(&mm->mmap_sem);
 
        /*
-        * Something tried to access memory that isn't in our memory map..
-        * Fix it, but check if it's kernel or user first..
+        * Major/minor page fault accounting
+        * (in case of retry we only land here once)
         */
-bad_area:
-       up_read(&mm->mmap_sem);
+       perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
 
-       /* User mode accesses just cause a SIGSEGV */
-       if (user_mode(regs)) {
-               tsk->thread.fault_address = address;
-               force_sig_fault(SIGSEGV, si_code, (void __user *)address);
-               return;
-       }
+       if (likely(!(fault & VM_FAULT_ERROR))) {
+               if (fault & VM_FAULT_MAJOR) {
+                       tsk->maj_flt++;
+                       perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
+                                     regs, address);
+               } else {
+                       tsk->min_flt++;
+                       perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
+                                     regs, address);
+               }
 
-no_context:
-       /* Are we prepared to handle this kernel fault?
-        *
-        * (The kernel has valid exception-points in the source
-        *  when it accesses user-memory. When it fails in one
-        *  of those points, we find it in a table and do a jump
-        *  to some fixup code that loads an appropriate error
-        *  code)
-        */
-       if (fixup_exception(regs))
+               /* Normal return path: fault Handled Gracefully */
                return;
+       }
 
-       die("Oops", regs, address);
-
-out_of_memory:
-       up_read(&mm->mmap_sem);
+       if (!user_mode(regs))
+               goto no_context;
 
-       if (user_mode(regs)) {
+       if (fault & VM_FAULT_OOM) {
                pagefault_out_of_memory();
                return;
        }
 
-       goto no_context;
+       if (fault & VM_FAULT_SIGBUS) {
+               sig = SIGBUS;
+               si_code = BUS_ADRERR;
+       }
+       else {
+               sig = SIGSEGV;
+       }
 
-do_sigbus:
-       up_read(&mm->mmap_sem);
+       tsk->thread.fault_address = address;
+       force_sig_fault(sig, si_code, (void __user *)address);
+       return;
 
-       if (!user_mode(regs))
-               goto no_context;
+no_context:
+       if (fixup_exception(regs))
+               return;
 
-       tsk->thread.fault_address = address;
-       force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)address);
+       die("Oops", regs, address);
 }
index 471a97b..c55d95d 100644 (file)
@@ -393,6 +393,17 @@ EV_TLBMissD_fast_ret:      ; additional label for VDK OS-kit instrumentation
 ;-------- Common routine to call Linux Page Fault Handler -----------
 do_slow_path_pf:
 
+#ifdef CONFIG_ISA_ARCV2
+       ; Set Z flag if exception in U mode. Hardware micro-ops do this on any
+       ; taken interrupt/exception, and thus is already the case at the entry
+       ; above, but ensuing code would have already clobbered.
+       ; EXCEPTION_PROLOGUE called in slow path, relies on correct Z flag set
+
+       lr      r2, [erstatus]
+       and     r2, r2, STATUS_U_MASK
+       bxor.f  0, r2, STATUS_U_BIT
+#endif
+
        ; Restore the 4-scratch regs saved by fast path miss handler
        TLBMISS_RESTORE_REGS
 
index 309a994..a4a6153 100644 (file)
@@ -10,6 +10,7 @@
 #error "Incorrect ctop.h include"
 #endif
 
+#include <linux/bits.h>
 #include <linux/types.h>
 #include <soc/nps/common.h>
 
 #define CTOP_INST_AXOR_DI_R2_R2_R3             0x4A664C06
 
 /* Do not use D$ for address in 2G-3G */
-#define HW_COMPLY_KRN_NOT_D_CACHED             _BITUL(28)
+#define HW_COMPLY_KRN_NOT_D_CACHED             BIT(28)
 
 #define NPS_MSU_EN_CFG                         0x80
 #define NPS_CRG_BLKID                          0x480
-#define NPS_CRG_SYNC_BIT                       _BITUL(0)
+#define NPS_CRG_SYNC_BIT                       BIT(0)
 #define NPS_GIM_BLKID                          0x5C0
 
 /* GIM registers and fields*/
-#define NPS_GIM_UART_LINE                      _BITUL(7)
-#define NPS_GIM_DBG_LAN_EAST_TX_DONE_LINE      _BITUL(10)
-#define NPS_GIM_DBG_LAN_EAST_RX_RDY_LINE       _BITUL(11)
-#define NPS_GIM_DBG_LAN_WEST_TX_DONE_LINE      _BITUL(25)
-#define NPS_GIM_DBG_LAN_WEST_RX_RDY_LINE       _BITUL(26)
+#define NPS_GIM_UART_LINE                      BIT(7)
+#define NPS_GIM_DBG_LAN_EAST_TX_DONE_LINE      BIT(10)
+#define NPS_GIM_DBG_LAN_EAST_RX_RDY_LINE       BIT(11)
+#define NPS_GIM_DBG_LAN_WEST_TX_DONE_LINE      BIT(25)
+#define NPS_GIM_DBG_LAN_WEST_RX_RDY_LINE       BIT(26)
 
 #ifndef __ASSEMBLY__
 /* Functional registers definition */
index 2bf1ce3..33b0057 100644 (file)
@@ -377,15 +377,6 @@ config ARCH_FOOTBRIDGE
          Support for systems based on the DC21285 companion chip
          ("FootBridge"), such as the Simtec CATS and the Rebel NetWinder.
 
-config ARCH_NETX
-       bool "Hilscher NetX based"
-       select ARM_VIC
-       select CLKSRC_MMIO
-       select CPU_ARM926T
-       select GENERIC_CLOCKEVENTS
-       help
-         This enables support for systems based on the Hilscher NetX Soc
-
 config ARCH_IOP13XX
        bool "IOP13xx-based"
        depends on MMU
@@ -531,7 +522,7 @@ config ARCH_RPC
        select ARCH_ACORN
        select ARCH_MAY_HAVE_PC_FDC
        select ARCH_SPARSEMEM_ENABLE
-       select ARCH_USES_GETTIMEOFFSET
+       select ARM_HAS_SG_CHAIN
        select CPU_SA110
        select FIQ
        select HAVE_IDE
@@ -552,6 +543,7 @@ config ARCH_SA1100
        select CLKSRC_MMIO
        select CLKSRC_PXA
        select TIMER_OF if OF
+       select COMMON_CLK
        select CPU_FREQ
        select CPU_SA1100
        select GENERIC_CLOCKEVENTS
@@ -770,8 +762,6 @@ source "arch/arm/mach-mvebu/Kconfig"
 
 source "arch/arm/mach-mxs/Kconfig"
 
-source "arch/arm/mach-netx/Kconfig"
-
 source "arch/arm/mach-nomadik/Kconfig"
 
 source "arch/arm/mach-npcm/Kconfig"
@@ -1297,7 +1287,7 @@ config SMP
          will run faster if you say N here.
 
          See also <file:Documentation/x86/i386/IO-APIC.rst>,
-         <file:Documentation/lockup-watchdogs.txt> and the SMP-HOWTO available at
+         <file:Documentation/admin-guide/lockup-watchdogs.rst> and the SMP-HOWTO available at
          <http://tldp.org/HOWTO/SMP-HOWTO.html>.
 
          If you don't know what to do here, say N.
@@ -2036,7 +2026,7 @@ config CRASH_DUMP
          kdump/kexec. The crash dump kernel must be compiled to a
          memory address not used by the main kernel
 
-         For more details see Documentation/kdump/kdump.rst
+         For more details see Documentation/admin-guide/kdump/kdump.rst
 
 config AUTO_ZRELADDR
        bool "Auto calculation of the decompressed kernel image address"
@@ -2142,7 +2132,7 @@ config VFP
          Say Y to include VFP support code in the kernel. This is needed
          if your hardware includes a VFP unit.
 
-         Please see <file:Documentation/arm/VFP/release-notes.txt> for
+         Please see <file:Documentation/arm/vfp/release-notes.rst> for
          release notes and additional status information.
 
          Say N if your target does not have VFP hardware.
index 9a8862f..c929bea 100644 (file)
@@ -638,13 +638,6 @@ choice
                  Say Y here if you want kernel low-level debugging support
                  for Mediatek mt8135 based platforms on UART3.
 
-       config DEBUG_NETX_UART
-               bool "Kernel low-level debugging messages via NetX UART"
-               depends on ARCH_NETX
-               help
-                 Say Y here if you want kernel low-level debugging support
-                 on Hilscher NetX based platforms.
-
        config DEBUG_NOMADIK_UART
                bool "Kernel low-level debugging messages via NOMADIK UART"
                depends on ARCH_NOMADIK
index f863c69..c3624ca 100644 (file)
@@ -191,7 +191,6 @@ machine-$(CONFIG_ARCH_MXC)          += imx
 machine-$(CONFIG_ARCH_MEDIATEK)                += mediatek
 machine-$(CONFIG_ARCH_MILBEAUT)                += milbeaut
 machine-$(CONFIG_ARCH_MXS)             += mxs
-machine-$(CONFIG_ARCH_NETX)            += netx
 machine-$(CONFIG_ARCH_NOMADIK)         += nomadik
 machine-$(CONFIG_ARCH_NPCM)            += npcm
 machine-$(CONFIG_ARCH_NSPIRE)          += nspire
index dab2914..9159fa2 100644 (file)
@@ -586,6 +586,7 @@ dtb-$(CONFIG_SOC_IMX7D) += \
        imx7d-colibri-emmc-eval-v3.dtb \
        imx7d-colibri-eval-v3.dtb \
        imx7d-mba7.dtb \
+       imx7d-meerkat96.dtb \
        imx7d-nitrogen7.dtb \
        imx7d-pico-hobbit.dtb \
        imx7d-pico-pi.dtb \
@@ -602,6 +603,7 @@ dtb-$(CONFIG_SOC_IMX7ULP) += \
 dtb-$(CONFIG_SOC_LS1021A) += \
        ls1021a-moxa-uc-8410a.dtb \
        ls1021a-qds.dtb \
+       ls1021a-tsn.dtb \
        ls1021a-twr.dtb
 dtb-$(CONFIG_SOC_VF610) += \
        vf500-colibri-eval-v3.dtb \
@@ -748,6 +750,7 @@ dtb-$(CONFIG_SOC_AM33XX) += \
        am335x-pepper.dtb \
        am335x-phycore-rdk.dtb \
        am335x-pocketbeagle.dtb \
+       am335x-regor-rdk.dtb \
        am335x-sancloud-bbe.dtb \
        am335x-shc.dtb \
        am335x-sbc-t335.dtb \
@@ -975,6 +978,7 @@ dtb-$(CONFIG_ARCH_STM32) += \
        stm32746g-eval.dtb \
        stm32h743i-eval.dtb \
        stm32h743i-disco.dtb \
+       stm32mp157a-avenger96.dtb \
        stm32mp157a-dk1.dtb \
        stm32mp157c-dk2.dtb \
        stm32mp157c-ed1.dtb \
@@ -1268,10 +1272,16 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
        aspeed-bmc-arm-stardragon4800-rep2.dtb \
        aspeed-bmc-facebook-cmm.dtb \
        aspeed-bmc-facebook-tiogapass.dtb \
+       aspeed-bmc-facebook-yamp.dtb \
        aspeed-bmc-intel-s2600wf.dtb \
+       aspeed-bmc-inspur-fp5280g2.dtb \
+       aspeed-bmc-lenovo-hr630.dtb \
+       aspeed-bmc-microsoft-olympus.dtb \
        aspeed-bmc-opp-lanyang.dtb \
        aspeed-bmc-opp-palmetto.dtb \
        aspeed-bmc-opp-romulus.dtb \
+       aspeed-bmc-opp-swift.dtb \
+       aspeed-bmc-opp-vesnin.dtb \
        aspeed-bmc-opp-witherspoon.dtb \
        aspeed-bmc-opp-zaius.dtb \
        aspeed-bmc-portwell-neptune.dtb \
index 49e46ba..386d5f8 100644 (file)
                        AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* lcd_ac_bias_en.gpio2[25] RI */
                >;
        };
+
+       mmc1_pins: pinmux_mmc1_pins {
+               pinctrl-single,pins = <
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD15, PIN_INPUT, MUX_MODE7)     /* MMC1 CD */
+               >;
+       };
 };
 
 &uart1 {
 };
 
 &cpsw_emac1 {
-       phy-mode = "rgmii-txid";
+       phy-mode = "rgmii-id";
        dual_emac_res_vlan = <2>;
        phy-handle = <&phy1>;
 };
+
+&mmc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&mmc1_pins>;
+       cd-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
+};
index 9e88bc2..b0df725 100644 (file)
                        AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKR, PIN_INPUT_PULLUP, MUX_MODE7)      /* mcasp0_aclkr.gpio3[18], INPUT_PULLDOWN | MODE7 */
                >;
        };
+
+       mmc1_pins: pinmux_mmc1_pins {
+               pinctrl-single,pins = <
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT, MUX_MODE7)     /* MMC1 CD */
+               >;
+       };
 };
 
 &uart1 {
 };
 
 &cpsw_emac1 {
-       phy-mode = "rgmii-txid";
+       phy-mode = "rgmii-id";
        dual_emac_res_vlan = <2>;
        phy-handle = <&phy1>;
 };
+
+&mmc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&mmc1_pins>;
+       cd-gpios = <&gpio2 18 GPIO_ACTIVE_LOW>;
+};
index 28aa004..d6aa46e 100644 (file)
                >;
        };
 
+       mmc1_pins: pinmux_mmc1_pins {
+               pinctrl-single,pins = <
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT, MUX_MODE7)     /* MMC1 CD */
+               >;
+       };
 };
 
 &uart1 {
 };
 
 &cpsw_emac1 {
-       phy-mode = "rgmii-txid";
+       phy-mode = "rgmii-id";
        dual_emac_res_vlan = <2>;
        phy-handle = <&phy1>;
 };
 
        status = "okay";
 };
+
+&mmc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&mmc1_pins>;
+       cd-gpios = <&gpio2 18 GPIO_ACTIVE_LOW>;
+};
index d774bf7..9bfa032 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&user_leds_pins>;
 
-               green {
-                       label = "green:user";
+               user-led0 {
                        gpios = <&gpio1 30 GPIO_ACTIVE_HIGH>;
                        linux,default-trigger = "gpio";
                        default-state = "on";
                };
 
-               yellow {
-                       label = "yellow:user";
+               user-led1 {
                        gpios = <&gpio1 31 GPIO_ACTIVE_LOW>;
                        linux,default-trigger = "gpio";
                        default-state = "on";
 &davinci_mdio {
        phy1: ethernet-phy@2 {
                reg = <2>;
-
-               /* Register 260 (104h) – RGMII Clock and Control Pad Skew */
-               rxc-skew-ps = <1400>;
-               rxdv-skew-ps = <0>;
-               txc-skew-ps = <1400>;
-               txen-skew-ps = <0>;
-               /* Register 261 (105h) – RGMII RX Data Pad Skew */
-               rxd3-skew-ps = <0>;
-               rxd2-skew-ps = <0>;
-               rxd1-skew-ps = <0>;
-               rxd0-skew-ps = <0>;
-               /* Register 262 (106h) – RGMII TX Data Pad Skew */
-               txd3-skew-ps = <0>;
-               txd2-skew-ps = <0>;
-               txd1-skew-ps = <0>;
-               txd0-skew-ps = <0>;
        };
 };
 
index 672daf9..43907d0 100644 (file)
 #include "am335x-pcm-953.dtsi"
 
 /* SoM */
+&gpmc {
+       status = "okay";
+};
+
 &i2c_eeprom {
        status = "okay";
 };
index ee6b1cb..3d0672b 100644 (file)
                reg = <0x80000000 0x10000000>; /* 256 MB */
        };
 
-       regulators {
-               compatible = "simple-bus";
-
-               vcc5v: fixedregulator0 {
-                       compatible = "regulator-fixed";
-                       regulator-name = "vcc5v";
-                       regulator-min-microvolt = <5000000>;
-                       regulator-max-microvolt = <5000000>;
-                       regulator-boot-on;
-                       regulator-always-on;
-               };
+       vcc5v: fixedregulator0 {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc5v";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-boot-on;
+               regulator-always-on;
        };
 };
 
        status = "okay";
 };
 
+/* EMMC */
+&am33xx_pinmux {
+       emmc_pins: pinmux_emmc_pins {
+               pinctrl-single,pins = <
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN1, PIN_INPUT_PULLUP, MUX_MODE2)       /* gpmc_csn1.mmc1_clk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN2, PIN_INPUT_PULLUP, MUX_MODE2)       /* gpmc_csn2.mmc1_cmd */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD0, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad0.mmc1_dat0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD1, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad1.mmc1_dat1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD2, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad2.mmc1_dat2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD3, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad3.mmc1_dat3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD4, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad4.mmc1_dat4 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD5, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad5.mmc1_dat5 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD6, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad6.mmc1_dat6 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD7, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad7.mmc1_dat7 */
+               >;
+       };
+};
+
+&mmc2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&emmc_pins>;
+       vmmc-supply = <&vmmc_reg>;
+       bus-width = <8>;
+       ti,non-removable;
+       status = "disabled";
+};
+
 /* Ethernet */
 &am33xx_pinmux {
        ethernet0_pins: pinmux_ethernet0 {
 };
 
 &gpmc {
-       status = "okay";
+       status = "disabled";
        pinctrl-names = "default";
        pinctrl-0 = <&nandflash_pins>;
        ranges = <0 0 0x08000000 0x1000000>;   /* CS0: NAND */
diff --git a/arch/arm/boot/dts/am335x-regor-rdk.dts b/arch/arm/boot/dts/am335x-regor-rdk.dts
new file mode 100644 (file)
index 0000000..66a1360
--- /dev/null
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Phytec Messtechnik GmbH
+ * Author: Teresa Remmet <t.remmet@phytec.de>
+ *
+ */
+
+/dts-v1/;
+
+#include "am335x-phycore-som.dtsi"
+#include "am335x-regor.dtsi"
+
+/* SoM */
+&gpmc {
+       status = "okay";
+};
+
+&i2c_eeprom {
+       status = "okay";
+};
+
+&serial_flash {
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/am335x-regor.dtsi b/arch/arm/boot/dts/am335x-regor.dtsi
new file mode 100644 (file)
index 0000000..5aff02a
--- /dev/null
@@ -0,0 +1,223 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Phytec Messtechnik GmbH
+ * Author: Teresa Remmet <t.remmet@phytec.de>
+ *
+ */
+
+/ {
+       model = "Phytec AM335x phyBOARD-REGOR";
+       compatible = "phytec,am335x-regor", "phytec,am335x-phycore-som", "ti,am33xx";
+
+       vcc3v3: fixedregulator@1 {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc3v3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-boot-on;
+       };
+
+       /* User IO */
+       user_leds: user_leds {
+               compatible = "gpio-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&user_leds_pins>;
+
+               run_stop-led {
+                       gpios = <&gpio2 22 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "gpio";
+                       default-state = "off";
+               };
+
+               error-led {
+                       gpios = <&gpio3 15 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "gpio";
+                       default-state = "off";
+               };
+       };
+};
+
+/* User Leds */
+&am33xx_pinmux {
+       user_leds_pins: pinmux_user_leds {
+               pinctrl-single,pins = <
+                       AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT_PULLDOWN, MUX_MODE7)    /* lcd_hsync.gpio2_22 */
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_FSX, PIN_OUTPUT_PULLDOWN, MUX_MODE7)   /* mcasp0_fsx.gpio3_15 */
+               >;
+       };
+};
+
+/* CAN Busses */
+&am33xx_pinmux {
+       dcan1_pins: pinmux_dcan1 {
+               pinctrl-single,pins = <
+                       AM33XX_PADCONF(AM335X_PIN_UART0_CTSN, PIN_OUTPUT_PULLUP, MUX_MODE2)     /* uart0_ctsn.d_can1_tx */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RTSN, PIN_INPUT_PULLUP, MUX_MODE2)      /* uart0_rtsn.d_can1_rx */
+               >;
+       };
+};
+
+&dcan1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&dcan1_pins>;
+       status = "okay";
+};
+
+/* Ethernet */
+&am33xx_pinmux {
+       ethernet1_pins: pinmux_ethernet1 {
+               pinctrl-single,pins = <
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A0, PIN_OUTPUT, MUX_MODE1)               /* gpmc_a0.mii2_txen */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A1, PIN_INPUT_PULLDOWN, MUX_MODE1)       /* gpmc_a1.mii2_rxdv */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A2, PIN_OUTPUT, MUX_MODE1)               /* gpmc_a2.mii2_txd3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A3, PIN_OUTPUT, MUX_MODE1)               /* gpmc_a3.mii2_txd2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A4, PIN_OUTPUT, MUX_MODE1)               /* gpmc_a4.mii2_txd1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT, MUX_MODE1)               /* gpmc_a5.mii2_txd0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A6, PIN_INPUT_PULLDOWN, MUX_MODE1)       /* gpmc_a6.mii2_txclk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A7, PIN_INPUT_PULLDOWN, MUX_MODE1)       /* gpmc_a7.mii2_rxclk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A8, PIN_INPUT_PULLDOWN, MUX_MODE1)       /* gpmc_a8.mii2_rxd3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A9, PIN_INPUT_PULLDOWN, MUX_MODE1)        /* gpmc_a9.mii2_rxd2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A10, PIN_INPUT_PULLDOWN, MUX_MODE1)      /* gpmc_a10.mii2_rxd1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A11, PIN_INPUT_PULLDOWN, MUX_MODE1)      /* gpmc_a11.mii2_rxd0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WPN, PIN_INPUT_PULLDOWN, MUX_MODE1)      /* gpmc_wpn.mii2_rxerr */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_BEN1, PIN_INPUT_PULLDOWN, MUX_MODE1)     /* gpmc_ben1.mii2_col */
+               >;
+       };
+};
+
+&cpsw_emac1 {
+       phy-handle = <&phy1>;
+       phy-mode = "mii";
+       dual_emac_res_vlan = <2>;
+};
+
+&davinci_mdio {
+       phy1: ethernet-phy@1 {
+               reg = <1>;
+       };
+};
+
+&mac {
+       slaves = <2>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&ethernet0_pins &ethernet1_pins>;
+       dual_emac = <1>;
+};
+
+/* GPIOs */
+&am33xx_pinmux {
+       pinctrl-names = "default";
+       pinctrl-0 = <&user_gpios_pins>;
+
+       user_gpios_pins: pinmux_user_gpios {
+               pinctrl-single,pins = <
+                       /* DIGIN 1-4 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD11, PIN_INPUT, MUX_MODE7)              /* gpmc_ad11.gpio0_27 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD10, PIN_INPUT, MUX_MODE7)              /* gpmc_ad10.gpio0_26 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD9, PIN_INPUT, MUX_MODE7)               /* gpmc_ad9.gpio0_23 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD8, PIN_INPUT, MUX_MODE7)               /* gpmc_ad8.gpio0_22 */
+                       /* DIGOUT 1-4 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD15, PIN_OUTPUT, MUX_MODE7)             /* gpmc_ad15.gpio1_15 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD14, PIN_OUTPUT, MUX_MODE7)             /* gpmc_ad14.gpio1_14 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD13, PIN_OUTPUT, MUX_MODE7)             /* gpmc_ad13.gpio1_13 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD12, PIN_OUTPUT, MUX_MODE7)             /* gpmc_ad12.gpio1_12 */
+               >;
+       };
+};
+
+/* MMC */
+&am33xx_pinmux {
+       mmc1_pins: pinmux_mmc1 {
+               pinctrl-single,pins = <
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT3, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT2, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CMD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS1, PIN_INPUT_PULLUP, MUX_MODE7)        /* spi0_cs1.mmc0_sdcd */
+               >;
+       };
+};
+
+&mmc1 {
+       vmmc-supply = <&vcc3v3>;
+       bus-width = <4>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&mmc1_pins>;
+       cd-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
+       status = "okay";
+};
+
+/* RTC */
+&i2c_rtc {
+       status = "okay";
+};
+
+/* UARTs */
+&am33xx_pinmux {
+       uart0_pins: pinmux_uart0 {
+               pinctrl-single,pins = <
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+               >;
+       };
+
+       uart2_pins: pinmux_uart2 {
+               pinctrl-single,pins = <
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_INPUT_PULLUP, MUX_MODE1)     /* mii1_tx_clk.uart2_rxd */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_OUTPUT_PULLDOWN, MUX_MODE1)  /* mii1_rx_clk.uart2_txd */
+               >;
+       };
+};
+
+&uart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart0_pins>;
+       status = "okay";
+};
+
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart2_pins>;
+       status = "okay";
+};
+
+/* RS485 - UART1 */
+&am33xx_pinmux {
+       uart1_rs485_pins: pinmux_uart1_rs485_pins {
+               pinctrl-single,pins = <
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RTSN, PIN_OUTPUT_PULLUP, MUX_MODE0)
+               >;
+       };
+};
+
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart1_rs485_pins>;
+       status = "okay";
+       linux,rs485-enabled-at-boot-time;
+};
+
+/* USB */
+&cppi41dma {
+       status = "okay";
+};
+
+&usb_ctrl_mod {
+       status = "okay";
+};
+
+&usb {
+       status = "okay";
+};
+
+&usb0 {
+       status = "okay";
+};
+
+&usb0_phy {
+       status = "okay";
+};
index 2e04f6d..866b5f0 100644 (file)
 #include "am335x-wega.dtsi"
 
 /* SoM */
+&gpmc {
+       status = "okay";
+};
+
 &i2c_eeprom {
        status = "okay";
 };
index 67bde56..61fc4cd 100644 (file)
                compatible = "ti,da830-evm-audio";
        };
 
-       regulators {
-               compatible = "simple-bus";
-
-               vcc3v3: fixedregulator1 {
-                       compatible = "regulator-fixed";
-                       regulator-name = "vcc3v3";
-                       regulator-min-microvolt = <3300000>;
-                       regulator-max-microvolt = <3300000>;
-                       regulator-boot-on;
-               };
+       vcc3v3: fixedregulator1 {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc3v3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-boot-on;
        };
 };
 
index 6105067..fe0207b 100644 (file)
                compatible = "arm,versatile-flash", "cfi-flash";
                reg = <0x40000000 0x04000000>;
                bank-width = <4>;
+               partitions {
+                       compatible = "arm,arm-firmware-suite";
+               };
        };
 
        flash1@44000000 {
                compatible = "arm,versatile-flash", "cfi-flash";
                reg = <0x44000000 0x04000000>;
                bank-width = <4>;
+               partitions {
+                       compatible = "arm,arm-firmware-suite";
+               };
        };
 
        /* SMSC LAN91C111 ethernet with PHY and EEPROM */
index cbbb887..2625ce6 100644 (file)
                compatible = "arm,versatile-flash", "cfi-flash";
                reg = <0x30000000 0x4000000>;
                bank-width = <4>;
+               partitions {
+                       compatible = "arm,arm-firmware-suite";
+               };
        };
 
        fpga_flash@38000000 {
                compatible = "arm,versatile-flash", "cfi-flash";
                reg = <0x38000000 0x800000>;
                bank-width = <4>;
+               partitions {
+                       compatible = "arm,arm-firmware-suite";
+               };
        };
 
        /*
index 2015619..c69cf7d 100644 (file)
                compatible = "arm,versatile-flash", "cfi-flash";
                reg = <0x40000000 0x04000000>;
                bank-width = <4>;
+               partitions {
+                       compatible = "arm,arm-firmware-suite";
+               };
        };
 
        flash1@44000000 {
                compatible = "arm,versatile-flash", "cfi-flash";
                reg = <0x44000000 0x04000000>;
                bank-width = <4>;
+               partitions {
+                       compatible = "arm,arm-firmware-suite";
+               };
        };
 
        bridge {
index a81e9c2..09f3f54 100644 (file)
                compatible = "arm,versatile-flash", "cfi-flash";
                reg = <0x40000000 0x04000000>;
                bank-width = <4>;
+               partitions {
+                       compatible = "arm,arm-firmware-suite";
+               };
        };
 
        flash1@44000000 {
                compatible = "arm,versatile-flash", "cfi-flash";
                reg = <0x44000000 0x04000000>;
                bank-width = <4>;
+               partitions {
+                       compatible = "arm,arm-firmware-suite";
+               };
        };
 
        /* SMSC 9118 ethernet with PHY and EEPROM */
index 9fd1cb9..85e2e9e 100644 (file)
                };
        };
 
+       auxdisplay {
+               compatible = "hit,hd44780";
+               data-gpios = <&gpio1 25 GPIO_ACTIVE_HIGH>,
+                               <&gpio1 26 GPIO_ACTIVE_HIGH>,
+                               <&gpio1 27 GPIO_ACTIVE_HIGH>,
+                               <&gpio1 29 GPIO_ACTIVE_HIGH>;
+               enable-gpios = <&gpio1 24 GPIO_ACTIVE_HIGH>;
+               rs-gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>;
+               rw-gpios = <&gpio1 23 GPIO_ACTIVE_HIGH>;
+               backlight-gpios = <&gpio1 21 GPIO_ACTIVE_LOW>;
+               display-height-chars = <2>;
+               display-width-chars = <16>;
+       };
+
        gpio-keys {
                compatible = "gpio-keys";
                pinctrl-0 = <&backup_button_pin
index 43aba40..d519d30 100644 (file)
 &adc {
        status = "okay";
 };
+
+&ehci0 {
+       status = "okay";
+};
+
+&ehci1 {
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/aspeed-bmc-facebook-yamp.dts b/arch/arm/boot/dts/aspeed-bmc-facebook-yamp.dts
new file mode 100644 (file)
index 0000000..4e09a9c
--- /dev/null
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright (c) 2018 Facebook Inc.
+/dts-v1/;
+
+#include "aspeed-g5.dtsi"
+
+/ {
+       model = "Facebook YAMP 100 BMC";
+       compatible = "facebook,yamp-bmc", "aspeed,ast2500";
+
+       aliases {
+               /*
+                * Override the default uart aliases to avoid breaking
+                * the legacy applications.
+                */
+               serial0 = &uart5;
+               serial1 = &uart1;
+               serial2 = &uart2;
+               serial3 = &uart3;
+       };
+
+       chosen {
+               stdout-path = &uart5;
+               bootargs = "console=ttyS0,9600n8 root=/dev/ram rw";
+       };
+
+       memory@80000000 {
+               reg = <0x80000000 0x20000000>;
+       };
+};
+
+&pinctrl {
+       aspeed,external-nodes = <&gfx &lhc>;
+};
+
+/*
+ * Update reset type to "system" (full chip) to fix warm reboot hang issue
+ * when reset type is set to default ("soc", gated by reset mask registers).
+ */
+&wdt1 {
+       status = "okay";
+       aspeed,reset-type = "system";
+};
+
+/*
+ * wdt2 is not used by Yamp.
+ */
+&wdt2 {
+       status = "disabled";
+};
+
+&fmc {
+       status = "okay";
+       flash@0 {
+               status = "okay";
+               m25p,fast-read;
+               label = "bmc";
+#include "facebook-bmc-flash-layout.dtsi"
+       };
+};
+
+&uart1 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_txd1_default
+                    &pinctrl_rxd1_default>;
+};
+
+&uart2 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_txd2_default
+                    &pinctrl_rxd2_default>;
+};
+
+&uart3 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_txd3_default
+                    &pinctrl_rxd3_default>;
+};
+
+&uart5 {
+       status = "okay";
+};
+
+&mac0 {
+       status = "okay";
+       use-ncsi;
+       no-hw-checksum;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_rmii1_default>;
+};
+
+&i2c0 {
+       status = "okay";
+};
+
+&i2c1 {
+       status = "okay";
+};
+
+&i2c2 {
+       status = "okay";
+
+       i2c-switch@75 {
+               compatible = "nxp,pca9548";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0x75>;
+       };
+};
+
+&i2c3 {
+       status = "okay";
+};
+
+&i2c4 {
+       status = "okay";
+};
+
+&i2c5 {
+       status = "okay";
+};
+
+&i2c6 {
+       status = "okay";
+};
+
+&i2c7 {
+       status = "okay";
+};
+
+&i2c8 {
+       status = "okay";
+};
+
+&i2c9 {
+       status = "okay";
+};
+
+&i2c10 {
+       status = "okay";
+};
+
+&i2c11 {
+       status = "okay";
+};
+
+&i2c12 {
+       status = "okay";
+};
+
+&i2c13 {
+       status = "okay";
+};
+
+&vhub {
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/aspeed-bmc-inspur-fp5280g2.dts b/arch/arm/boot/dts/aspeed-bmc-inspur-fp5280g2.dts
new file mode 100644 (file)
index 0000000..628195b
--- /dev/null
@@ -0,0 +1,846 @@
+// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+#include "aspeed-g5.dtsi"
+#include <dt-bindings/gpio/aspeed-gpio.h>
+#include <dt-bindings/leds/leds-pca955x.h>
+
+/ {
+       model = "FP5280G2 BMC";
+       compatible = "inspur,fp5280g2-bmc", "aspeed,ast2500";
+
+       chosen {
+               stdout-path = &uart5;
+               bootargs = "console=ttyS4,115200 earlyprintk";
+       };
+
+       memory@80000000 {
+               reg = <0x80000000 0x20000000>;
+       };
+
+       reserved-memory {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               vga_memory: framebuffer@9f000000 {
+                       no-map;
+                       reg = <0x9f000000 0x01000000>; /* 16M */
+               };
+
+               flash_memory: region@98000000 {
+                       no-map;
+                       reg = <0x98000000 0x04000000>; /* 64M */
+               };
+
+               coldfire_memory: codefire_memory@9ef00000 {
+                       reg = <0x9ef00000 0x00100000>;
+                       no-map;
+               };
+
+               gfx_memory: framebuffer {
+                       size = <0x01000000>;
+                       alignment = <0x01000000>;
+                       compatible = "shared-dma-pool";
+                       reusable;
+               };
+
+               video_engine_memory: jpegbuffer {
+                       size = <0x02000000>;    /* 32M */
+                       alignment = <0x01000000>;
+                       compatible = "shared-dma-pool";
+                       reusable;
+               };
+       };
+
+       fsi: gpio-fsi {
+               compatible = "aspeed,ast2500-cf-fsi-master", "fsi-master";
+               #address-cells = <2>;
+               #size-cells = <0>;
+               no-gpio-delays;
+
+               memory-region = <&coldfire_memory>;
+               aspeed,sram = <&sram>;
+               aspeed,cvic = <&cvic>;
+
+               clock-gpios = <&gpio ASPEED_GPIO(AA, 0) GPIO_ACTIVE_HIGH>;
+               data-gpios = <&gpio ASPEED_GPIO(AA, 2) GPIO_ACTIVE_HIGH>;
+               mux-gpios = <&gpio ASPEED_GPIO(I, 2) GPIO_ACTIVE_HIGH>;
+               enable-gpios = <&gpio ASPEED_GPIO(I, 3) GPIO_ACTIVE_HIGH>;
+               trans-gpios = <&gpio ASPEED_GPIO(R, 2) GPIO_ACTIVE_HIGH>;
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+
+               checkstop {
+                       label = "checkstop";
+                       gpios = <&gpio ASPEED_GPIO(B, 3) GPIO_ACTIVE_LOW>;
+                       linux,code = <ASPEED_GPIO(B, 3)>;
+               };
+
+               ps0-presence {
+                       label = "ps0-presence";
+                       gpios = <&gpio ASPEED_GPIO(F, 0) GPIO_ACTIVE_LOW>;
+                       linux,code = <ASPEED_GPIO(F, 0)>;
+               };
+
+               ps1-presence {
+                       label = "ps1-presence";
+                       gpios = <&gpio ASPEED_GPIO(F, 1) GPIO_ACTIVE_LOW>;
+                       linux,code = <ASPEED_GPIO(F, 1)>;
+               };
+
+       };
+
+       gpio-keys-polled {
+               compatible = "gpio-keys-polled";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               poll-interval = <1000>;
+
+               fan0-presence {
+                       label = "fan0-presence";
+                       gpios = <&pca1 0 GPIO_ACTIVE_LOW>;
+                       linux,code = <1>;
+               };
+
+               fan1-presence {
+                       label = "fan1-presence";
+                       gpios = <&pca1 1 GPIO_ACTIVE_LOW>;
+                       linux,code = <2>;
+               };
+
+               fan2-presence {
+                       label = "fan2-presence";
+                       gpios = <&pca1 2 GPIO_ACTIVE_LOW>;
+                       linux,code = <3>;
+               };
+
+               fan3-presence {
+                       label = "fan3-presence";
+                       gpios = <&pca1 3 GPIO_ACTIVE_LOW>;
+                       linux,code = <4>;
+               };
+
+               fan4-presence {
+                       label = "fan4-presence";
+                       gpios = <&pca1 4 GPIO_ACTIVE_LOW>;
+                       linux,code = <5>;
+               };
+
+               fan5-presence {
+                       label = "fan5-presence";
+                       gpios = <&pca1 5 GPIO_ACTIVE_LOW>;
+                       linux,code = <6>;
+               };
+
+               fan6-presence {
+                       label = "fan6-presence";
+                       gpios = <&pca1 6 GPIO_ACTIVE_LOW>;
+                       linux,code = <7>;
+               };
+
+               fan7-presence {
+                       label = "fan7-presence";
+                       gpios = <&pca1 7 GPIO_ACTIVE_LOW>;
+                       linux,code = <8>;
+               };
+       };
+
+       leds {
+           compatible = "gpio-leds";
+
+           power {
+                   label = "power";
+                   /* TODO: dummy gpio */
+                   gpios = <&gpio ASPEED_GPIO(R, 1) GPIO_ACTIVE_LOW>;
+           };
+
+       };
+
+       iio-hwmon-battery {
+               compatible = "iio-hwmon";
+               io-channels = <&adc 15>;
+       };
+
+       iio-hwmon {
+               compatible = "iio-hwmon";
+               io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>, <&adc 4>,
+                       <&adc 5>, <&adc 6>, <&adc 7>, <&adc 8>, <&adc 9>,
+                       <&adc 10>, <&adc 11>, <&adc 12>, <&adc 13>, <&adc 14>;
+       };
+
+};
+
+&fmc {
+       status = "okay";
+
+       flash@0 {
+               status = "okay";
+               label = "bmc";
+               m25p,fast-read;
+               spi-max-frequency = <50000000>;
+#include "openbmc-flash-layout.dtsi"
+       };
+};
+
+&spi1 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_spi1_default>;
+
+       flash@0 {
+               status = "okay";
+               label = "pnor";
+               m25p,fast-read;
+               spi-max-frequency = <100000000>;
+       };
+};
+
+&uart1 {
+       /* Rear RS-232 connector */
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_txd1_default
+                       &pinctrl_rxd1_default
+                       &pinctrl_nrts1_default
+                       &pinctrl_ndtr1_default
+                       &pinctrl_ndsr1_default
+                       &pinctrl_ncts1_default
+                       &pinctrl_ndcd1_default
+                       &pinctrl_nri1_default>;
+};
+
+&uart2 {
+       /* Test Point */
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_txd2_default &pinctrl_rxd2_default>;
+};
+
+&uart3 {
+       /* APSS */
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_txd3_default &pinctrl_rxd3_default>;
+};
+
+&uart5 {
+       status = "okay";
+};
+
+&lpc_ctrl {
+       status = "okay";
+       memory-region = <&flash_memory>;
+       flash = <&spi1>;
+};
+
+&mac0 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_rmii1_default>;
+       use-ncsi;
+};
+
+&mac1 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>;
+};
+
+&i2c0 {
+       /* LCD */
+       status = "okay";
+};
+
+&i2c1 {
+       status = "okay";
+
+       eeprom@50 {
+               compatible = "atmel,24c256";
+               reg = <0x50>;
+               label = "fru";
+       };
+
+};
+
+&i2c2 {
+       status = "okay";
+
+       tmp112@48 {
+               compatible = "ti,tmp112";
+               reg = <0x48>;
+               label = "inlet";
+       };
+
+       tmp112@49 {
+               compatible = "ti,tmp112";
+               reg = <0x49>;
+               label = "outlet";
+       };
+
+       i2c-switch@70 {
+               compatible = "nxp,pca9546";
+               reg = <0x70>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               i2c@0 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0>;
+
+                       tmp112@4a {
+                               compatible = "ti,tmp112";
+                               reg = <0x4a>;
+                               label = "psu_inlet";
+                       };
+
+               };
+
+               i2c@1 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <1>;
+
+                       tmp112@4a {
+                               compatible = "ti,tmp112";
+                               reg = <0x4a>;
+                               label = "ocp_zone";
+                       };
+               };
+
+               i2c@2 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <2>;
+
+                       tmp112@4a {
+                               compatible = "ti,tmp112";
+                               reg = <0x4a>;
+                               label = "bmc_zone";
+                       };
+               };
+
+               i2c@3 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <3>;
+
+                       tmp112@7c {
+                               compatible = "microchip,emc1413";
+                               reg = <0x7c>;
+                       };
+               };
+
+       };
+};
+
+&i2c3 {
+       /* Riser Card */
+       status = "okay";
+};
+
+&i2c4 {
+       status = "okay";
+
+       rtc@68 {
+               compatible = "dallas,ds3232";
+               reg = <0x68>;
+       };
+};
+
+&i2c5 {
+       /* vr  */
+       status = "okay";
+};
+
+&i2c6 {
+       /* bp card */
+       status = "okay";
+};
+
+&i2c7 {
+       status = "okay";
+
+       i2c-switch@70 {
+               compatible = "nxp,pca9546";
+               reg = <0x70>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               i2c@0 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0>;
+
+                       adm1278@10 {
+                               compatible = "adi,adm1278";
+                               reg = <0x10>;
+                       };
+
+                       adm1278@13 {
+                               compatible = "adi,adm1278";
+                               reg = <0x13>;
+                       };
+
+                       adm1278@50 {
+                               compatible = "adi,adm1278";
+                               reg = <0x50>;
+                       };
+
+                       adm1278@53 {
+                               compatible = "adi,adm1278";
+                               reg = <0x53>;
+                       };
+
+               };
+
+               /*pcie riser*/
+
+       };
+};
+
+&i2c8 {
+       status = "okay";
+
+       pca0: pca9555@20 {
+               compatible = "nxp,pca9555";
+               reg = <0x20>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               gpio-controller;
+               #gpio-cells = <2>;
+
+               gpio@0 {
+                       reg = <0>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@1 {
+                       reg = <1>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@2 {
+                       reg = <2>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@3 {
+                       reg = <3>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@4 {
+                       reg = <4>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@5 {
+                       reg = <5>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@6 {
+                       reg = <6>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@7 {
+                       reg = <7>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+       };
+
+       pca1: pca9555@21 {
+               compatible = "nxp,pca9555";
+               reg = <0x21>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               gpio-controller;
+               #gpio-cells = <2>;
+
+               gpio@0 {
+                       reg = <0>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@1 {
+                       reg = <1>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@2 {
+                       reg = <2>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@3 {
+                       reg = <3>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@4 {
+                       reg = <4>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@5 {
+                       reg = <5>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@6 {
+                       reg = <6>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@7 {
+                       reg = <7>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+       };
+
+       pca2: pca9555@22 {
+               compatible = "nxp,pca9555";
+               reg = <0x22>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               gpio-controller;
+               #gpio-cells = <2>;
+
+               gpio@0 {
+                       reg = <0>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@1 {
+                       reg = <1>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@2 {
+                       reg = <2>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@3 {
+                       reg = <3>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@4 {
+                       reg = <4>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@5 {
+                       reg = <5>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@6 {
+                       reg = <6>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@7 {
+                       reg = <7>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+       };
+
+       pca3: pca9555@23 {
+               compatible = "nxp,pca9555";
+               reg = <0x23>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               gpio-controller;
+               #gpio-cells = <2>;
+
+               gpio@0 {
+                       reg = <0>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@1 {
+                       reg = <1>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@2 {
+                       reg = <2>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@3 {
+                       reg = <3>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@4 {
+                       reg = <4>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@5 {
+                       reg = <5>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@6 {
+                       reg = <6>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@7 {
+                       reg = <7>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+       };
+
+       pca4: pca9555@24 {
+               compatible = "nxp,pca9555";
+               reg = <0x24>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               gpio-controller;
+               #gpio-cells = <2>;
+
+               gpio@0 {
+                       reg = <0>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@1 {
+                       reg = <1>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@2 {
+                       reg = <2>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@3 {
+                       reg = <3>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@4 {
+                       reg = <4>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@5 {
+                       reg = <5>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@6 {
+                       reg = <6>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@7 {
+                       reg = <7>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+       };
+
+       pca5: pca9555@25 {
+               compatible = "nxp,pca9555";
+               reg = <0x25>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               gpio-controller;
+               #gpio-cells = <2>;
+
+               gpio@0 {
+                       reg = <0>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@1 {
+                       reg = <1>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@2 {
+                       reg = <2>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@3 {
+                       reg = <3>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@4 {
+                       reg = <4>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@5 {
+                       reg = <5>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@6 {
+                       reg = <6>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@7 {
+                       reg = <7>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+       };
+
+};
+
+&i2c9 {
+       /* cpld */
+       status = "okay";
+};
+
+&i2c10 {
+       /* hdd bp */
+       status = "okay";
+};
+
+&i2c11 {
+       status = "okay";
+
+       power-supply@58 {
+               compatible = "pmbus";
+               reg = <0x58>;
+       };
+
+       power-supply@5a {
+               compatible = "pmbus";
+               reg = <0x5a>;
+       };
+};
+
+&i2c12 {
+       /* odcc */
+       status = "okay";
+};
+
+&vuart {
+       status = "okay";
+};
+
+&gfx {
+       status = "okay";
+       memory-region = <&gfx_memory>;
+};
+
+&pinctrl {
+       aspeed,external-nodes = <&gfx &lhc>;
+};
+
+&gpio {
+       pin_gpio_b7 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(B,7) GPIO_ACTIVE_LOW>;
+               output-high;
+               line-name = "BMC_INIT_OK";
+       };
+};
+
+&wdt1 {
+       aspeed,reset-type = "none";
+       aspeed,external-signal;
+       aspeed,ext-push-pull;
+       aspeed,ext-active-high;
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_wdtrst1_default>;
+};
+
+&ibt {
+       status = "okay";
+
+};
+
+&adc {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_adc0_default &pinctrl_adc1_default
+        &pinctrl_adc2_default &pinctrl_adc3_default &pinctrl_adc4_default
+        &pinctrl_adc5_default &pinctrl_adc6_default &pinctrl_adc7_default
+        &pinctrl_adc8_default &pinctrl_adc9_default &pinctrl_adc10_default
+        &pinctrl_adc11_default &pinctrl_adc12_default &pinctrl_adc13_default
+        &pinctrl_adc14_default &pinctrl_adc15_default>;
+};
+
+&vhub {
+       status = "okay";
+};
+
+&video {
+       status = "okay";
+       memory-region = <&video_engine_memory>;
+};
+
+&pwm_tacho {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default
+               &pinctrl_pwm2_default &pinctrl_pwm3_default
+               &pinctrl_pwm4_default &pinctrl_pwm5_default
+               &pinctrl_pwm6_default &pinctrl_pwm7_default>;
+
+       fan@0 {
+               reg = <0x00>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x00 0x01>;
+       };
+
+       fan@1 {
+               reg = <0x01>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x02 0x03>;
+       };
+
+       fan@2 {
+               reg = <0x02>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x04 0x05>;
+       };
+
+       fan@3 {
+               reg = <0x03>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x06 0x07>;
+       };
+
+       fan@4 {
+               reg = <0x04>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x08 0x09>;
+       };
+
+       fan@5 {
+               reg = <0x05>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x0a 0x0b>;
+       };
+
+       fan@6 {
+               reg = <0x06>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x0c 0x0d>;
+       };
+
+       fan@7 {
+               reg = <0x07>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x0e 0x0f>;
+       };
+
+};
+
+#include "ibm-power9-dual.dtsi"
diff --git a/arch/arm/boot/dts/aspeed-bmc-lenovo-hr630.dts b/arch/arm/boot/dts/aspeed-bmc-lenovo-hr630.dts
new file mode 100644 (file)
index 0000000..d3695a3
--- /dev/null
@@ -0,0 +1,566 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Device Tree file for Lenovo Hr630 platform
+ *
+ * Copyright (C) 2019-present Lenovo
+ */
+
+/dts-v1/;
+
+#include "aspeed-g5.dtsi"
+#include <dt-bindings/gpio/aspeed-gpio.h>
+
+/ {
+       model = "HR630 BMC";
+       compatible = "lenovo,hr630-bmc", "aspeed,ast2500";
+
+       aliases {
+               i2c14 = &i2c_rbp;
+               i2c15 = &i2c_fbp1;
+               i2c16 = &i2c_fbp2;
+               i2c17 = &i2c_fbp3;
+               i2c18 = &i2c_riser2;
+               i2c19 = &i2c_pcie4;
+               i2c20 = &i2c_riser1;
+               i2c21 = &i2c_ocp;
+       };
+
+       chosen {
+               stdout-path = &uart5;
+               bootargs = "console=tty0 console=ttyS4,115200 earlyprintk";
+       };
+
+       memory@80000000 {
+               device_type = "memory";
+               reg = <0x80000000 0x20000000>;
+       };
+
+       reserved-memory {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               flash_memory: region@98000000 {
+                       no-map;
+                       reg = <0x98000000 0x00100000>; /* 1M */
+               };
+
+               gfx_memory: framebuffer {
+                       size = <0x01000000>;
+                       alignment = <0x01000000>;
+                       compatible = "shared-dma-pool";
+                       reusable;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               heartbeat {
+                       gpios = <&gpio ASPEED_GPIO(J, 1) GPIO_ACTIVE_LOW>;
+               };
+
+               fault {
+                       gpios = <&gpio ASPEED_GPIO(J, 0) GPIO_ACTIVE_LOW>;
+               };
+       };
+
+       iio-hwmon {
+               compatible = "iio-hwmon";
+               io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>,
+               <&adc 4>, <&adc 5>, <&adc 6>, <&adc 7>,
+               <&adc 8>, <&adc 9>, <&adc 10>,
+               <&adc 12>, <&adc 13>, <&adc 14>;
+       };
+
+};
+
+&fmc {
+       status = "okay";
+       flash@0 {
+               status = "okay";
+               m25p,fast-read;
+               label = "bmc";
+               spi-max-frequency = <50000000>;
+#include "openbmc-flash-layout.dtsi"
+       };
+};
+
+&lpc_ctrl {
+       status = "okay";
+       memory-region = <&flash_memory>;
+       flash = <&spi1>;
+};
+
+&uart1 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_txd1_default
+                       &pinctrl_rxd1_default>;
+};
+
+&uart2 {
+       /* Rear RS-232 connector */
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_txd2_default
+                       &pinctrl_rxd2_default
+                       &pinctrl_nrts2_default
+                       &pinctrl_ndtr2_default
+                       &pinctrl_ndsr2_default
+                       &pinctrl_ncts2_default
+                       &pinctrl_ndcd2_default
+                       &pinctrl_nri2_default>;
+};
+
+&uart3 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_txd3_default
+                       &pinctrl_rxd3_default>;
+};
+
+&uart5 {
+       status = "okay";
+};
+
+&ibt {
+       status = "okay";
+};
+
+&mac0 {
+       status = "okay";
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_rmii1_default>;
+       use-ncsi;
+};
+
+&mac1 {
+       status = "okay";
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>;
+};
+
+&adc {
+       status = "okay";
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_adc0_default
+                       &pinctrl_adc1_default
+                       &pinctrl_adc2_default
+                       &pinctrl_adc3_default
+                       &pinctrl_adc4_default
+                       &pinctrl_adc5_default
+                       &pinctrl_adc6_default
+                       &pinctrl_adc7_default
+                       &pinctrl_adc8_default
+                       &pinctrl_adc9_default
+                       &pinctrl_adc10_default
+                       &pinctrl_adc12_default
+                       &pinctrl_adc13_default
+                       &pinctrl_adc14_default>;
+};
+
+&i2c0 {
+       status = "okay";
+       /* temp1 inlet */
+       tmp75@4e {
+               compatible = "national,lm75";
+               reg = <0x4e>;
+       };
+};
+
+&i2c1 {
+       status = "okay";
+       /* temp2 outlet */
+       tmp75@4d {
+               compatible = "national,lm75";
+               reg = <0x4d>;
+       };
+};
+
+&i2c2 {
+       status = "okay";
+};
+
+&i2c3 {
+       status = "okay";
+};
+
+&i2c4 {
+       status = "okay";
+};
+
+&i2c5 {
+       status = "okay";
+};
+
+&i2c6 {
+       status = "okay";
+       /*      Slot 0,
+        *      Slot 1,
+        *      Slot 2,
+        *      Slot 3
+        */
+
+       i2c-switch@70 {
+               compatible = "nxp,pca9545";
+               reg = <0x70>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               i2c-mux-idle-disconnect;        /* may use mux@70 next. */
+
+               i2c_rbp: i2c@0 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0>;
+               };
+
+               i2c_fbp1: i2c@1 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <1>;
+               };
+
+               i2c_fbp2: i2c@2 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <2>;
+               };
+
+               i2c_fbp3: i2c@3 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <3>;
+               };
+       };
+};
+
+&i2c7 {
+       status = "okay";
+
+       /*      Slot 0,
+        *      Slot 1,
+        *      Slot 2,
+        *      Slot 3
+        */
+       i2c-switch@76 {
+               compatible = "nxp,pca9546";
+               reg = <0x76>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               i2c-mux-idle-disconnect;  /* may use mux@76 next. */
+
+               i2c_riser2: i2c@0 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0>;
+               };
+
+               i2c_pcie4: i2c@1 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <1>;
+               };
+
+               i2c_riser1: i2c@2 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <2>;
+               };
+
+               i2c_ocp: i2c@3 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <3>;
+               };
+       };
+};
+
+&i2c8 {
+       status = "okay";
+
+       eeprom@57 {
+               compatible = "atmel,24c256";
+               reg = <0x57>;
+               pagesize = <16>;
+       };
+};
+
+&i2c9 {
+       status = "okay";
+};
+
+&i2c10 {
+       status = "okay";
+};
+
+&i2c11 {
+       status = "okay";
+};
+
+&i2c12 {
+       status = "okay";
+};
+
+&ehci1 {
+       status = "okay";
+};
+
+&uhci {
+       status = "okay";
+};
+
+&gfx {
+       status = "okay";
+       memory-region = <&gfx_memory>;
+};
+
+&pwm_tacho {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pwm0_default
+       &pinctrl_pwm1_default
+       &pinctrl_pwm2_default
+       &pinctrl_pwm3_default
+       &pinctrl_pwm4_default
+       &pinctrl_pwm5_default
+       &pinctrl_pwm6_default>;
+
+       fan@0 {
+               reg = <0x00>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x00>;
+       };
+
+       fan@1 {
+               reg = <0x00>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x01>;
+       };
+
+       fan@2 {
+               reg = <0x01>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x02>;
+       };
+
+       fan@3 {
+               reg = <0x01>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x03>;
+       };
+
+       fan@4 {
+               reg = <0x02>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x04>;
+       };
+
+       fan@5 {
+               reg = <0x02>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x05>;
+       };
+
+       fan@6 {
+               reg = <0x03>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x06>;
+       };
+
+       fan@7 {
+               reg = <0x03>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x07>;
+       };
+
+       fan@8 {
+               reg = <0x04>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x08>;
+       };
+
+       fan@9 {
+               reg = <0x04>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x09>;
+       };
+
+       fan@10 {
+               reg = <0x05>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x0a>;
+       };
+
+       fan@11 {
+               reg = <0x05>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x0b>;
+       };
+
+       fan@12 {
+               reg = <0x06>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x0c>;
+       };
+
+       fan@13 {
+               reg = <0x06>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x0d>;
+       };
+};
+
+&gpio {
+
+       pin_gpio_b5 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(B, 5) GPIO_ACTIVE_HIGH>;
+               output-high;
+               line-name = "IRQ_BMC_PCH_SMI_LPC_N";
+       };
+
+       pin_gpio_f0 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(F, 0) GPIO_ACTIVE_HIGH>;
+               output-low;
+               line-name = "IRQ_BMC_PCH_NMI_R";
+       };
+
+       pin_gpio_f3 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(F, 3) GPIO_ACTIVE_HIGH>;
+               output-high;
+               line-name = "I2C_BUS0_RST_OUT_N";
+       };
+
+       pin_gpio_f4 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(F, 4) GPIO_ACTIVE_HIGH>;
+               output-low;
+               line-name = "FM_SKT0_FAULT_LED";
+       };
+
+       pin_gpio_f5 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(F, 5) GPIO_ACTIVE_HIGH>;
+               output-low;
+               line-name = "FM_SKT1_FAULT_LED";
+       };
+
+       pin_gpio_g4 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(G, 4) GPIO_ACTIVE_HIGH>;
+               output-high;
+               line-name = "FAN_PWR_CTL_N";
+       };
+
+       pin_gpio_g7 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(G, 7) GPIO_ACTIVE_HIGH>;
+               output-high;
+               line-name = "RST_BMC_PCIE_I2CMUX_N";
+       };
+
+       pin_gpio_h2 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(H, 2) GPIO_ACTIVE_HIGH>;
+               output-high;
+               line-name = "PSU1_FFS_N_R";
+       };
+
+       pin_gpio_h3 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(H, 3) GPIO_ACTIVE_HIGH>;
+               output-high;
+               line-name = "PSU2_FFS_N_R";
+       };
+
+       pin_gpio_i3 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(I, 3) GPIO_ACTIVE_HIGH>;
+               output-high;
+               line-name = "BMC_INTRUDED_COVER";
+       };
+
+       pin_gpio_j2 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(J, 2) GPIO_ACTIVE_HIGH>;
+               output-high;
+               line-name = "BMC_BIOS_UPDATE_N";
+       };
+
+       pin_gpio_j3 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(J, 3) GPIO_ACTIVE_HIGH>;
+               output-high;
+               line-name = "RST_BMC_HDD_I2CMUX_N";
+       };
+
+       pin_gpio_s2 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(S, 2) GPIO_ACTIVE_HIGH>;
+               output-high;
+               line-name = "BMC_VGA_SW";
+       };
+
+       pin_gpio_s4 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(S, 4) GPIO_ACTIVE_HIGH>;
+               output;
+               line-name = "VBAT_EN_N";
+       };
+
+       pin_gpio_s6 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(S, 6) GPIO_ACTIVE_HIGH>;
+               output-high;
+               line-name = "PU_BMC_GPIOS6";
+       };
+
+       pin_gpio_y0 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(Y, 0) GPIO_ACTIVE_HIGH>;
+               output-low;
+               line-name = "BMC_NCSI_MUX_CTL_S0";
+       };
+
+       pin_gpio_y1 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(Y, 1) GPIO_ACTIVE_HIGH>;
+               output-low;
+               line-name = "BMC_NCSI_MUX_CTL_S1";
+       };
+
+       pin_gpio_z0 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(Z, 0) GPIO_ACTIVE_HIGH>;
+               output-high;
+               line-name = "I2C_RISER2_INT_N";
+       };
+
+       pin_gpio_z2 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(Z, 2) GPIO_ACTIVE_HIGH>;
+               output-high;
+               line-name = "I2C_RISER2_RESET_N";
+       };
+
+       pin_gpio_z3 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(Z, 3) GPIO_ACTIVE_HIGH>;
+               output-high;
+               line-name = "FM_BMC_PCH_SCI_LPC_N";
+       };
+
+       pin_gpio_z7 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(Z, 7) GPIO_ACTIVE_HIGH>;
+               output-low;
+               line-name = "BMC_POST_CMPLT_N";
+       };
+
+       pin_gpio_aa0 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(AA, 0) GPIO_ACTIVE_HIGH>;
+               output-low;
+               line-name = "HOST_BMC_USB_SEL";
+       };
+
+       pin_gpio_aa5 {
+               gpio-hog;
+               gpios = <ASPEED_GPIO(AA, 5) GPIO_ACTIVE_HIGH>;
+               output-high;
+               line-name = "I2C_BUS1_RST_OUT_N";
+       };
+
+};
diff --git a/arch/arm/boot/dts/aspeed-bmc-microsoft-olympus.dts b/arch/arm/boot/dts/aspeed-bmc-microsoft-olympus.dts
new file mode 100644 (file)
index 0000000..7331991
--- /dev/null
@@ -0,0 +1,207 @@
+//SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+#include "aspeed-g4.dtsi"
+#include <dt-bindings/gpio/aspeed-gpio.h>
+
+/ {
+       model = "Olympus BMC";
+       compatible = "microsoft,olympus-bmc", "aspeed,ast2400";
+
+       chosen {
+               stdout-path = &uart5;
+               bootargs = "console=ttyS4,115200 earlyprintk";
+       };
+
+       memory@40000000 {
+               reg = <0x40000000 0x20000000>;
+       };
+
+       reserved-memory {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               vga_memory: framebuffer@5f000000 {
+                       no-map;
+                       reg = <0x5f000000 0x01000000>; /* 16M */
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               bmc_heartbeat {
+                       gpios = <&gpio ASPEED_GPIO(B, 0) GPIO_ACTIVE_LOW>;
+               };
+
+               power_green {
+                       gpios = <&gpio ASPEED_GPIO(U, 2) GPIO_ACTIVE_HIGH>;
+               };
+
+               power_amber {
+                       gpios = <&gpio ASPEED_GPIO(U, 3) GPIO_ACTIVE_HIGH>;
+               };
+
+               identify {
+                       gpios = <&gpio ASPEED_GPIO(Q, 5) GPIO_ACTIVE_LOW>;
+               };
+
+               fault {
+                       gpios = <&gpio ASPEED_GPIO(A, 1) GPIO_ACTIVE_LOW>;
+               };
+       };
+
+
+       iio-hwmon {
+               compatible = "iio-hwmon";
+               io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>,
+               <&adc 4>, <&adc 5>, <&adc 6>, <&adc 7>;
+       };
+};
+
+&adc {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 =    <&pinctrl_adc0_default
+                       &pinctrl_adc1_default
+                       &pinctrl_adc2_default
+                       &pinctrl_adc3_default
+                       &pinctrl_adc4_default
+                       &pinctrl_adc5_default
+                       &pinctrl_adc6_default
+                       &pinctrl_adc7_default>;
+};
+
+&fmc {
+       status = "okay";
+
+       flash@0 {
+               status = "okay";
+               m25p,fast-read;
+               label = "bmc";
+#include "openbmc-flash-layout.dtsi"
+       };
+};
+
+&spi {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_spi1_default>;
+
+       flash@0 {
+               status = "okay";
+               m25p,fast-read;
+               label = "pnor";
+       };
+};
+
+&uart5 {
+       status = "okay";
+};
+
+&mac0 {
+       status = "okay";
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_rgmii1_default &pinctrl_mdio1_default>;
+};
+
+&i2c0 {
+       status = "okay";
+};
+
+&i2c1 {
+       status = "okay";
+
+       tmp421@4c {
+               compatible = "ti,tmp421";
+               reg = <0x4c>;
+       };
+};
+
+&i2c2 {
+       status = "okay";
+};
+
+&i2c3 {
+       status = "okay";
+};
+
+&i2c4 {
+       status = "okay";
+       clock-frequency = <100000>;
+};
+
+&i2c5 {
+       status = "okay";
+};
+
+&i2c6 {
+       status = "okay";
+
+       tmp421@4c {
+               compatible = "ti,tmp421";
+               reg = <0x4c>;
+       };
+};
+
+&i2c7 {
+       status = "okay";
+};
+
+&vuart {
+       status = "okay";
+};
+
+&wdt2 {
+       status = "okay";
+};
+
+&lpc_ctrl {
+       status = "okay";
+};
+
+&pwm_tacho {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 =    <&pinctrl_pwm0_default
+                       &pinctrl_pwm1_default
+                       &pinctrl_pwm2_default
+                       &pinctrl_pwm3_default
+                       &pinctrl_pwm4_default
+                       &pinctrl_pwm5_default
+                       &pinctrl_pwm6_default>;
+
+       fan@0 {
+               reg = <0x00>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x00>;
+       };
+
+       fan@1 {
+               reg = <0x01>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x01>;
+       };
+
+       fan@2 {
+               reg = <0x02>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x02>;
+       };
+
+       fan@3 {
+               reg = <0x03>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x03>;
+       };
+
+       fan@4 {
+               reg = <0x04>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x04>;
+       };
+
+       fan@5 {
+               reg = <0x05>;
+               aspeed,fan-tach-ch = /bits/ 8 <0x05>;
+       };
+
+};
index 024e52a..de95112 100644 (file)
 &adc {
        status = "okay";
 };
+
+#include "ibm-power9-dual.dtsi"
index b249da8..b0cb34c 100644 (file)
                line-name = "BMC_TPM_INT_N";
        };
 };
+
+&fsi {
+       cfam@0,0 {
+               reg = <0 0>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               chip-id = <0>;
+
+               scom@1000 {
+                       compatible = "ibm,fsi2pib";
+                       reg = <0x1000 0x400>;
+               };
+
+               fsi_hub0: hub@3400 {
+                       compatible = "ibm,fsi-master-hub";
+                       reg = <0x3400 0x400>;
+                       #address-cells = <2>;
+                       #size-cells = <0>;
+                       no-scan-on-init;
+               };
+       };
+};
index 418a198..9628ecb 100644 (file)
                        compatible = "shared-dma-pool";
                        reusable;
                };
+
+               video_engine_memory: jpegbuffer {
+                       size = <0x02000000>;    /* 32M */
+                       alignment = <0x01000000>;
+                       compatible = "shared-dma-pool";
+                       reusable;
+               };
        };
 
        leds {
 &adc {
        status = "okay";
 };
+
+&video {
+       status = "okay";
+       memory-region = <&video_engine_memory>;
+};
+
+#include "ibm-power9-dual.dtsi"
diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-swift.dts b/arch/arm/boot/dts/aspeed-bmc-opp-swift.dts
new file mode 100644 (file)
index 0000000..caac895
--- /dev/null
@@ -0,0 +1,966 @@
+// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+#include "aspeed-g5.dtsi"
+#include <dt-bindings/gpio/aspeed-gpio.h>
+#include <dt-bindings/leds/leds-pca955x.h>
+
+/ {
+       model = "Swift BMC";
+       compatible = "ibm,swift-bmc", "aspeed,ast2500";
+
+       chosen {
+               stdout-path = &uart5;
+               bootargs = "console=ttyS4,115200 earlyprintk";
+       };
+
+       memory@80000000 {
+               reg = <0x80000000 0x20000000>;
+       };
+
+       reserved-memory {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               flash_memory: region@98000000 {
+                       no-map;
+                       reg = <0x98000000 0x04000000>; /* 64M */
+               };
+
+               gfx_memory: framebuffer {
+                       size = <0x01000000>;
+                       alignment = <0x01000000>;
+                       compatible = "shared-dma-pool";
+                       reusable;
+               };
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+
+               air-water {
+                       label = "air-water";
+                       gpios = <&gpio ASPEED_GPIO(B, 5) GPIO_ACTIVE_LOW>;
+                       linux,code = <ASPEED_GPIO(B, 5)>;
+               };
+
+               checkstop {
+                       label = "checkstop";
+                       gpios = <&gpio ASPEED_GPIO(J, 2) GPIO_ACTIVE_LOW>;
+                       linux,code = <ASPEED_GPIO(J, 2)>;
+               };
+
+               ps0-presence {
+                       label = "ps0-presence";
+                       gpios = <&gpio ASPEED_GPIO(R, 7) GPIO_ACTIVE_LOW>;
+                       linux,code = <ASPEED_GPIO(R, 7)>;
+               };
+
+               ps1-presence {
+                       label = "ps1-presence";
+                       gpios = <&gpio ASPEED_GPIO(N, 0) GPIO_ACTIVE_LOW>;
+                       linux,code = <ASPEED_GPIO(N, 0)>;
+               };
+
+               oppanel-presence {
+                       label = "oppanel-presence";
+                       gpios = <&gpio ASPEED_GPIO(A, 7) GPIO_ACTIVE_LOW>;
+                       linux,code = <ASPEED_GPIO(A, 7)>;
+               };
+
+               opencapi-riser-presence {
+                       label = "opencapi-riser-presence";
+                       gpios = <&gpio ASPEED_GPIO(I, 0) GPIO_ACTIVE_LOW>;
+                       linux,code = <ASPEED_GPIO(I, 0)>;
+               };
+       };
+
+       iio-hwmon-battery {
+               compatible = "iio-hwmon";
+               io-channels = <&adc 12>;
+       };
+
+       gpio-keys-polled {
+               compatible = "gpio-keys-polled";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               poll-interval = <1000>;
+
+               scm0-presence {
+                       label = "scm0-presence";
+                       gpios = <&pca9552 6 GPIO_ACTIVE_LOW>;
+                       linux,code = <6>;
+               };
+
+               scm1-presence {
+                       label = "scm1-presence";
+                       gpios = <&pca9552 7 GPIO_ACTIVE_LOW>;
+                       linux,code = <7>;
+               };
+
+               cpu0vrm-presence {
+                       label = "cpu0vrm-presence";
+                       gpios = <&pca9552 12 GPIO_ACTIVE_LOW>;
+                       linux,code = <12>;
+               };
+
+               cpu1vrm-presence {
+                       label = "cpu1vrm-presence";
+                       gpios = <&pca9552 13 GPIO_ACTIVE_LOW>;
+                       linux,code = <13>;
+               };
+
+               fan0-presence {
+                       label = "fan0-presence";
+                       gpios = <&pca0 5 GPIO_ACTIVE_LOW>;
+                       linux,code = <5>;
+               };
+
+               fan1-presence {
+                       label = "fan1-presence";
+                       gpios = <&pca0 6 GPIO_ACTIVE_LOW>;
+                       linux,code = <6>;
+               };
+
+               fan2-presence {
+                       label = "fan2-presence";
+                       gpios = <&pca0 7 GPIO_ACTIVE_LOW>;
+                       linux,code = <7>;
+               };
+
+               fan3-presence {
+                       label = "fan3-presence";
+                       gpios = <&pca0 8 GPIO_ACTIVE_LOW>;
+                       linux,code = <8>;
+               };
+
+               fanboost-presence {
+                       label = "fanboost-presence";
+                       gpios = <&pca0 9 GPIO_ACTIVE_LOW>;
+                       linux,code = <9>;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               fan0 {
+                       retain-state-shutdown;
+                       default-state = "keep";
+                       gpios = <&pca0 0 GPIO_ACTIVE_LOW>;
+               };
+
+               fan1 {
+                       retain-state-shutdown;
+                       default-state = "keep";
+                       gpios = <&pca0 1 GPIO_ACTIVE_LOW>;
+               };
+
+               fan2 {
+                       retain-state-shutdown;
+                       default-state = "keep";
+                       gpios = <&pca0 2 GPIO_ACTIVE_LOW>;
+               };
+
+               fan3 {
+                       retain-state-shutdown;
+                       default-state = "keep";
+                       gpios = <&pca0 3 GPIO_ACTIVE_LOW>;
+               };
+
+               fanboost {
+                       retain-state-shutdown;
+                       default-state = "keep";
+                       gpios = <&pca0 4 GPIO_ACTIVE_LOW>;
+               };
+
+               front-fault {
+                       retain-state-shutdown;
+                       default-state = "keep";
+                       gpios = <&pca1 2 GPIO_ACTIVE_LOW>;
+               };
+
+               front-power {
+                       retain-state-shutdown;
+                       default-state = "keep";
+                       gpios = <&pca1 3 GPIO_ACTIVE_LOW>;
+               };
+
+               front-id {
+                       retain-state-shutdown;
+                       default-state = "keep";
+                       gpios = <&pca1 0 GPIO_ACTIVE_LOW>;
+               };
+
+               rear-fault {
+                       gpios = <&gpio ASPEED_GPIO(N, 2) GPIO_ACTIVE_LOW>;
+               };
+
+               rear-id {
+                       gpios = <&gpio ASPEED_GPIO(N, 4) GPIO_ACTIVE_LOW>;
+               };
+       };
+
+       fsi: gpio-fsi {
+               compatible = "fsi-master-gpio", "fsi-master";
+               #address-cells = <2>;
+               #size-cells = <0>;
+               no-gpio-delays;
+
+               clock-gpios = <&gpio ASPEED_GPIO(AA, 0) GPIO_ACTIVE_HIGH>;
+               data-gpios = <&gpio ASPEED_GPIO(E, 0) GPIO_ACTIVE_HIGH>;
+               mux-gpios = <&gpio ASPEED_GPIO(P, 4) GPIO_ACTIVE_HIGH>;
+               enable-gpios = <&gpio ASPEED_GPIO(P, 0) GPIO_ACTIVE_HIGH>;
+               trans-gpios = <&gpio ASPEED_GPIO(P, 3) GPIO_ACTIVE_HIGH>;
+       };
+
+       iio-hwmon-dps310 {
+               compatible = "iio-hwmon";
+               io-channels = <&dps 0>;
+       };
+
+};
+
+&fmc {
+       status = "okay";
+
+       flash@0 {
+               status = "okay";
+               label = "bmc";
+               m25p,fast-read;
+               spi-max-frequency = <100000000>;
+               partitions {
+                       #address-cells = < 1 >;
+                       #size-cells = < 1 >;
+                       compatible = "fixed-partitions";
+                       u-boot@0 {
+                               reg = < 0 0x60000 >;
+                               label = "u-boot";
+                       };
+                       u-boot-env@60000 {
+                               reg = < 0x60000 0x20000 >;
+                               label = "u-boot-env";
+                       };
+                       obmc-ubi@80000 {
+                               reg = < 0x80000 0x7F80000>;
+                               label = "obmc-ubi";
+                       };
+               };
+       };
+
+       flash@1 {
+               status = "okay";
+               label = "alt-bmc";
+               m25p,fast-read;
+               spi-max-frequency = <100000000>;
+               partitions {
+                       #address-cells = < 1 >;
+                       #size-cells = < 1 >;
+                       compatible = "fixed-partitions";
+                       u-boot@0 {
+                               reg = < 0 0x60000 >;
+                               label = "alt-u-boot";
+                       };
+                       u-boot-env@60000 {
+                               reg = < 0x60000 0x20000 >;
+                               label = "alt-u-boot-env";
+                       };
+                       obmc-ubi@80000 {
+                               reg = < 0x80000 0x7F80000>;
+                               label = "alt-obmc-ubi";
+                       };
+               };
+       };
+};
+
+&spi1 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_spi1_default>;
+
+       flash@0 {
+               status = "okay";
+               label = "pnor";
+               m25p,fast-read;
+               spi-max-frequency = <100000000>;
+       };
+};
+
+&uart1 {
+       /* Rear RS-232 connector */
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_txd1_default
+                       &pinctrl_rxd1_default
+                       &pinctrl_nrts1_default
+                       &pinctrl_ndtr1_default
+                       &pinctrl_ndsr1_default
+                       &pinctrl_ncts1_default
+                       &pinctrl_ndcd1_default
+                       &pinctrl_nri1_default>;
+};
+
+&uart2 {
+       /* APSS */
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_txd2_default &pinctrl_rxd2_default>;
+};
+
+&uart5 {
+       status = "okay";
+};
+
+&lpc_ctrl {
+       status = "okay";
+       memory-region = <&flash_memory>;
+       flash = <&spi1>;
+};
+
+&mac0 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_rmii1_default>;
+       use-ncsi;
+};
+
+&i2c2 {
+       status = "okay";
+
+       /* MUX ->
+        *    Samtec 1
+        *    Samtec 2
+        */
+};
+
+&i2c3 {
+       status = "okay";
+
+       max31785@52 {
+               compatible = "maxim,max31785a";
+               reg = <0x52>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               fan@0 {
+                       compatible = "pmbus-fan";
+                       reg = <0>;
+                       tach-pulses = <2>;
+                       maxim,fan-rotor-input = "tach";
+                       maxim,fan-pwm-freq = <25000>;
+                       maxim,fan-no-watchdog;
+                       maxim,fan-no-fault-ramp;
+                       maxim,fan-ramp = <2>;
+                       maxim,fan-fault-pin-mon;
+               };
+
+               fan@1 {
+                       compatible = "pmbus-fan";
+                       reg = <1>;
+                       tach-pulses = <2>;
+                       maxim,fan-rotor-input = "tach";
+                       maxim,fan-pwm-freq = <25000>;
+                       maxim,fan-no-watchdog;
+                       maxim,fan-no-fault-ramp;
+                       maxim,fan-ramp = <2>;
+                       maxim,fan-fault-pin-mon;
+               };
+
+               fan@2 {
+                       compatible = "pmbus-fan";
+                       reg = <2>;
+                       tach-pulses = <2>;
+                       maxim,fan-rotor-input = "tach";
+                       maxim,fan-pwm-freq = <25000>;
+                       maxim,fan-no-watchdog;
+                       maxim,fan-no-fault-ramp;
+                       maxim,fan-ramp = <2>;
+                       maxim,fan-fault-pin-mon;
+               };
+
+               fan@3 {
+                       compatible = "pmbus-fan";
+                       reg = <3>;
+                       tach-pulses = <2>;
+                       maxim,fan-rotor-input = "tach";
+                       maxim,fan-pwm-freq = <25000>;
+                       maxim,fan-no-watchdog;
+                       maxim,fan-no-fault-ramp;
+                       maxim,fan-ramp = <2>;
+                       maxim,fan-fault-pin-mon;
+               };
+
+               fan@4 {
+                       compatible = "pmbus-fan";
+                       reg = <4>;
+                       tach-pulses = <2>;
+                       maxim,fan-rotor-input = "tach";
+                       maxim,fan-pwm-freq = <25000>;
+                       maxim,fan-no-watchdog;
+                       maxim,fan-no-fault-ramp;
+                       maxim,fan-ramp = <2>;
+                       maxim,fan-fault-pin-mon;
+               };
+       };
+
+       pca0: pca9552@60 {
+               compatible = "nxp,pca9552";
+               reg = <0x60>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               gpio-controller;
+               #gpio-cells = <2>;
+
+               gpio@0 {
+                       reg = <0>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@1 {
+                       reg = <1>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@2 {
+                       reg = <2>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@3 {
+                       reg = <3>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@4 {
+                       reg = <4>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@5 {
+                       reg = <5>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@6 {
+                       reg = <6>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@7 {
+                       reg = <7>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@8 {
+                       reg = <8>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@9 {
+                       reg = <9>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@10 {
+                       reg = <10>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@11 {
+                       reg = <11>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@12 {
+                       reg = <12>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@13 {
+                       reg = <13>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@14 {
+                       reg = <14>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@15 {
+                       reg = <15>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+       };
+
+       power-supply@68 {
+               compatible = "ibm,cffps1";
+               reg = <0x68>;
+       };
+
+       eeprom@50 {
+               compatible = "atmel,24c64";
+               reg = <0x50>;
+       };
+
+       power-supply@69 {
+               compatible = "ibm,cffps1";
+               reg = <0x69>;
+       };
+
+       eeprom@51 {
+               compatible = "atmel,24c64";
+               reg = <0x51>;
+       };
+};
+
+&i2c7 {
+       status = "okay";
+
+       dps: dps310@76 {
+               compatible = "infineon,dps310";
+               reg = <0x76>;
+               #io-channel-cells = <0>;
+       };
+
+       tmp275@48 {
+               compatible = "ti,tmp275";
+               reg = <0x48>;
+       };
+
+       si7021a20@20 {
+               compatible = "si,si7021a20";
+               reg = <0x20>;
+       };
+
+       eeprom@50 {
+               compatible = "atmel,24c64";
+               reg = <0x50>;
+       };
+
+       pca1: pca9551@60 {
+               compatible = "nxp,pca9551";
+               reg = <0x60>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               gpio-controller;
+               #gpio-cells = <2>;
+
+               gpio@0 {
+                       reg = <0>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@1 {
+                       reg = <1>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@2 {
+                       reg = <2>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@3 {
+                       reg = <3>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@4 {
+                       reg = <4>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@5 {
+                       reg = <5>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@6 {
+                       reg = <6>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@7 {
+                       reg = <7>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+       };
+};
+
+&i2c8 {
+       status = "okay";
+
+       pca9552: pca9552@60 {
+               compatible = "nxp,pca9552";
+               reg = <0x60>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               gpio-controller;
+               #gpio-cells = <2>;
+
+               gpio-line-names = "PS_SMBUS_RESET_N", "APSS_RESET_N",
+                       "GPU0_TH_OVERT_N_BUFF", "GPU1_TH_OVERT_N_BUFF",
+                       "GPU2_TH_OVERT_N_BUFF", "GPU3_TH_OVERT_N_BUFF",
+                       "P9_SCM0_PRES", "P9_SCM1_PRES",
+                       "GPU0_PWR_GOOD_BUFF", "GPU1_PWR_GOOD_BUFF",
+                       "GPU2_PWR_GOOD_BUFF", "GPU3_PWR_GOOD_BUFF",
+                       "PRESENT_VRM_CP0_N", "PRESENT_VRM_CP1_N",
+                       "12V_BREAKER_FLT_N", "THROTTLE_UNLATCHED_N";
+
+               gpio@0 {
+                       reg = <0>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@1 {
+                       reg = <1>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@2 {
+                       reg = <2>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@3 {
+                       reg = <3>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@4 {
+                       reg = <4>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@5 {
+                       reg = <5>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@6 {
+                       reg = <6>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@7 {
+                       reg = <7>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@8 {
+                       reg = <8>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@9 {
+                       reg = <9>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@10 {
+                       reg = <10>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@11 {
+                       reg = <11>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@12 {
+                       reg = <12>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@13 {
+                       reg = <13>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@14 {
+                       reg = <14>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+
+               gpio@15 {
+                       reg = <15>;
+                       type = <PCA955X_TYPE_GPIO>;
+               };
+       };
+
+       rtc@32 {
+               compatible = "epson,rx8900";
+               reg = <0x32>;
+       };
+
+       eeprom@51 {
+               compatible = "atmel,24c64";
+               reg = <0x51>;
+       };
+
+       ucd90160@64 {
+               compatible = "ti,ucd90160";
+               reg = <0x64>;
+       };
+};
+
+&i2c9 {
+       status = "okay";
+
+       eeprom@50 {
+               compatible = "atmel,24c64";
+               reg = <0x50>;
+       };
+
+       tmp423a@4c {
+               compatible = "ti,tmp423";
+               reg = <0x4c>;
+       };
+
+       ir35221@71 {
+               compatible = "infineon,ir35221";
+               reg = <0x71>;
+       };
+
+       ir35221@72 {
+               compatible = "infineon,ir35221";
+               reg = <0x72>;
+       };
+
+       pca2: pca9539@74 {
+               compatible = "nxp,pca9539";
+               reg = <0x74>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               gpio-controller;
+               #gpio-cells = <2>;
+
+               gpio@0 {
+                       reg = <0>;
+               };
+
+               gpio@1 {
+                       reg = <1>;
+               };
+
+               gpio@2 {
+                       reg = <2>;
+               };
+
+               gpio@3 {
+                       reg = <3>;
+               };
+
+               gpio@4 {
+                       reg = <4>;
+               };
+
+               gpio@5 {
+                       reg = <5>;
+               };
+
+               gpio@6 {
+                       reg = <6>;
+               };
+
+               gpio@7 {
+                       reg = <7>;
+               };
+
+               gpio@8 {
+                       reg = <8>;
+               };
+
+               gpio@9 {
+                       reg = <9>;
+               };
+
+               gpio@10 {
+                       reg = <10>;
+               };
+
+               gpio@11 {
+                       reg = <11>;
+               };
+
+               gpio@12 {
+                       reg = <12>;
+               };
+
+               gpio@13 {
+                       reg = <13>;
+               };
+
+               gpio@14 {
+                       reg = <14>;
+               };
+
+               gpio@15 {
+                       reg = <15>;
+               };
+       };
+};
+
+&i2c10 {
+       status = "okay";
+
+       eeprom@50 {
+               compatible = "atmel,24c64";
+               reg = <0x50>;
+       };
+
+       tmp423a@4c {
+               compatible = "ti,tmp423";
+               reg = <0x4c>;
+       };
+
+       ir35221@71 {
+               compatible = "infineon,ir35221";
+               reg = <0x71>;
+       };
+
+       ir35221@72 {
+               compatible = "infineon,ir35221";
+               reg = <0x72>;
+       };
+
+       pca3: pca9539@74 {
+               compatible = "nxp,pca9539";
+               reg = <0x74>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               gpio-controller;
+               #gpio-cells = <2>;
+
+               gpio@0 {
+                       reg = <0>;
+               };
+
+               gpio@1 {
+                       reg = <1>;
+               };
+
+               gpio@2 {
+                       reg = <2>;
+               };
+
+               gpio@3 {
+                       reg = <3>;
+               };
+
+               gpio@4 {
+                       reg = <4>;
+               };
+
+               gpio@5 {
+                       reg = <5>;
+               };
+
+               gpio@6 {
+                       reg = <6>;
+               };
+
+               gpio@7 {
+                       reg = <7>;
+               };
+
+               gpio@8 {
+                       reg = <8>;
+               };
+
+               gpio@9 {
+                       reg = <9>;
+               };
+
+               gpio@10 {
+                       reg = <10>;
+               };
+
+               gpio@11 {
+                       reg = <11>;
+               };
+
+               gpio@12 {
+                       reg = <12>;
+               };
+
+               gpio@13 {
+                       reg = <13>;
+               };
+
+               gpio@14 {
+                       reg = <14>;
+               };
+
+               gpio@15 {
+                       reg = <15>;
+               };
+       };
+};
+
+&i2c11 {
+       /* MUX
+        *   -> PCIe Slot 0
+        *   -> PCIe Slot 1
+        *   -> PCIe Slot 2
+        *   -> PCIe Slot 3
+        */
+       status = "okay";
+};
+
+&i2c12 {
+       status = "okay";
+
+       tmp275@48 {
+               compatible = "ti,tmp275";
+               reg = <0x48>;
+       };
+
+       tmp275@4a {
+               compatible = "ti,tmp275";
+               reg = <0x4a>;
+       };
+};
+
+&i2c13 {
+       status = "okay";
+};
+
+&vuart {
+       status = "okay";
+};
+
+&gfx {
+       status = "okay";
+       memory-region = <&gfx_memory>;
+};
+
+&pinctrl {
+       aspeed,external-nodes = <&gfx &lhc>;
+};
+
+&wdt1 {
+       aspeed,reset-type = "none";
+       aspeed,external-signal;
+       aspeed,ext-push-pull;
+       aspeed,ext-active-high;
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_wdtrst1_default>;
+};
+
+&wdt2 {
+       aspeed,alt-boot;
+};
+
+&ibt {
+       status = "okay";
+};
+
+&adc {
+       status = "okay";
+};
+
+#include "ibm-power9-dual.dtsi"
diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-vesnin.dts b/arch/arm/boot/dts/aspeed-bmc-opp-vesnin.dts
new file mode 100644 (file)
index 0000000..0b9e29c
--- /dev/null
@@ -0,0 +1,224 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright 2019 YADRO
+/dts-v1/;
+
+#include "aspeed-g4.dtsi"
+#include <dt-bindings/gpio/aspeed-gpio.h>
+
+/ {
+       model = "Vesnin BMC";
+       compatible = "yadro,vesnin-bmc", "aspeed,ast2400";
+
+       chosen {
+               stdout-path = &uart5;
+               bootargs = "console=ttyS4,115200 earlyprintk";
+       };
+
+       memory {
+               reg = <0x40000000 0x20000000>;
+       };
+
+       reserved-memory {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               vga_memory: framebuffer@5f000000 {
+                       no-map;
+                       reg = <0x5f000000 0x01000000>; /* 16MB */
+               };
+               flash_memory: region@5c000000 {
+                       no-map;
+                       reg = <0x5c000000 0x02000000>; /* 32M */
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               heartbeat {
+                       gpios = <&gpio ASPEED_GPIO(R, 4) GPIO_ACTIVE_LOW>;
+               };
+               power_red {
+                       gpios = <&gpio ASPEED_GPIO(N, 1) GPIO_ACTIVE_LOW>;
+               };
+
+               id_blue {
+                       gpios = <&gpio ASPEED_GPIO(O, 0) GPIO_ACTIVE_LOW>;
+               };
+
+               alarm_red {
+                       gpios = <&gpio ASPEED_GPIO(N, 6) GPIO_ACTIVE_LOW>;
+               };
+
+               alarm_yel {
+                       gpios = <&gpio ASPEED_GPIO(N, 7) GPIO_ACTIVE_HIGH>;
+               };
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+
+               button_checkstop {
+                       label = "checkstop";
+                       linux,code = <74>;
+                       gpios = <&gpio ASPEED_GPIO(P, 5) GPIO_ACTIVE_LOW>;
+               };
+
+               button_identify {
+                       label = "identify";
+                       linux,code = <152>;
+                       gpios = <&gpio ASPEED_GPIO(O, 7) GPIO_ACTIVE_LOW>;
+               };
+       };
+};
+
+&fmc {
+       status = "okay";
+       flash@0 {
+               status = "okay";
+               m25p,fast-read;
+        label = "bmc";
+#include "openbmc-flash-layout.dtsi"
+       };
+};
+
+&spi {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_spi1debug_default>;
+
+       flash@0 {
+               status = "okay";
+               label = "pnor";
+               m25p,fast-read;
+       };
+};
+
+&mac0 {
+       status = "okay";
+
+       use-ncsi;
+       no-hw-checksum;
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_rmii1_default>;
+};
+
+
+&uart5 {
+       status = "okay";
+};
+
+&lpc_ctrl {
+       status = "okay";
+       memory-region = <&flash_memory>;
+       flash = <&spi>;
+};
+
+&ibt {
+       status = "okay";
+};
+
+&uart3 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_txd2_default &pinctrl_rxd2_default>;
+};
+
+&i2c0 {
+       status = "okay";
+
+       eeprom@50 {
+               compatible = "atmel,24c256";
+               reg = <0x50>;
+               pagesize = <64>;
+       };
+};
+
+&i2c1 {
+       status = "okay";
+
+       tmp75@49 {
+               compatible = "ti,tmp75";
+               reg = <0x49>;
+       };
+};
+
+&i2c2 {
+       status = "okay";
+};
+
+&i2c3 {
+       status = "okay";
+};
+
+&i2c4 {
+       status = "okay";
+
+       occ-hwmon@50 {
+               compatible = "ibm,p8-occ-hwmon";
+               reg = <0x50>;
+       };
+};
+
+&i2c5 {
+       status = "okay";
+
+       occ-hwmon@51 {
+               compatible = "ibm,p8-occ-hwmon";
+               reg = <0x51>;
+       };
+};
+
+&i2c6 {
+       status = "okay";
+
+       w83795g@2f {
+               compatible = "nuvoton,w83795g";
+               reg = <0x2f>;
+       };
+};
+
+&i2c7 {
+       status = "okay";
+
+       occ-hwmon@56 {
+               compatible = "ibm,p8-occ-hwmon";
+               reg = <0x56>;
+       };
+};
+
+&i2c9 {
+       status = "okay";
+};
+
+&i2c10 {
+       status = "okay";
+};
+
+&i2c11 {
+       status = "okay";
+
+       occ-hwmon@57 {
+               compatible = "ibm,p8-occ-hwmon";
+               reg = <0x57>;
+       };
+};
+
+&i2c12 {
+       status = "okay";
+
+       rtc@68 {
+               compatible = "maxim,ds3231";
+               reg = <0x68>;
+       };
+};
+
+&i2c13 {
+       status = "okay";
+};
+
+&vuart {
+       status = "okay";
+};
index f1356ca..31ea34e 100644 (file)
                        compatible = "shared-dma-pool";
                        reusable;
                };
+
+               video_engine_memory: jpegbuffer {
+                       size = <0x02000000>;    /* 32MM */
+                       alignment = <0x01000000>;
+                       compatible = "shared-dma-pool";
+                       reusable;
+               };
        };
 
        gpio-keys {
 &vhub {
        status = "okay";
 };
+
+&video {
+       status = "okay";
+       memory-region = <&video_engine_memory>;
+};
+
+#include "ibm-power9-dual.dtsi"
index 2c5aa90..3062437 100644 (file)
@@ -7,6 +7,14 @@
        model = "Zaius BMC";
        compatible = "ingrasys,zaius-bmc", "aspeed,ast2500";
 
+       aliases {
+               i2c15 = &i2cpcie0;
+               i2c16 = &i2cpcie1;
+               i2c17 = &i2cpcie2;
+               i2c19 = &i2cpcie3;
+               i2c20 = &i2cpcie4;
+       };
+
        chosen {
                stdout-path = &uart5;
                bootargs = "console=ttyS4,115200 earlyprintk";
                reg = <0x71>;
                #address-cells = <1>;
                #size-cells = <0>;
+
+               i2cpcie0: i2c@0 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0>;
+               };
+               i2cpcie1: i2c@1 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <1>;
+               };
+               i2cpcie2: i2c@2 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <2>;
+               };
+               i2ctpm: i2c@3 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <3>;
+               };
        };
 
        /* MUX1 PCA9546A @71h
                reg = <0x71>;
                #address-cells = <1>;
                #size-cells = <0>;
+
+               i2cpcie3: i2c@0 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0>;
+               };
+               i2cpcie4: i2c@1 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <1>;
+               };
        };
 
        /* MUX1 PCA9546A @71h
                                reg = <0x54>;
                        };
                };
+
+       };
+
+       vrm@64 {
+               compatible = "isil,isl68137";
+               reg = <0x64>;
+       };
+
+       vrm@40 {
+               compatible = "isil,isl68137";
+               reg = <0x40>;
+       };
+
+       vrm@60 {
+               compatible = "isil,isl68137";
+               reg = <0x60>;
+       };
+
+       vrm@43 {
+               compatible = "infineon,ir38064";
+               reg = <0x43>;
+       };
+
+       vrm@41 {
+               compatible = "isil,isl68137";
+               reg = <0x41>;
        };
 
        /* Master selector PCA9541A @70h (other master: CPU0)
         *   LM5066I PMBUS @10h
         */
 
-       /* 12V Quarter Brick DC/DC Converter Q54SJ12050 @61h */
-       power-brick@61 {
+       /*
+        * Brick will be one of these types/addresses.  Depending
+        * on the board SKU only one is actually present and will successfully
+        * instantiate while the others will fail the probe operation.
+        * These are the PVT (and presumably beyond) addresses:
+        *    12V Quarter Brick DC/DC Converter Q54SJ12050 @6Ah
+        *    12V Quarter Brick DC/DC Converter Q54SH12050 @30h
+        */
+       power-brick@6a {
+               compatible = "delta,dps800";
+               reg = <0x6a>;
+       };
+       power-brick@30 {
                compatible = "delta,dps800";
-               reg = <0x61>;
+               reg = <0x30>;
        };
 
        /* CPU0 VR ISL68137 0.7V, 0.96V PMBUS @64h */
        /* CPU0 VR ISL68137 1.2V CH03 PMBUS @40h */
        /* CPU0 VR ISL68137 0.8V PMBUS @60h */
-       /* CPU0 VR 1.0V IR38064 I2C @11h, PMBUS @41h */
+       /* CPU0 VR 1.0V IR38064 I2C @11h, PMBUS @43h */
        /* CPU0 VR ISL68137 1.2V CH47 PMBUS @41h */
+       /* Master selector PCA9541A @70h (other master: CPU0)
+        *   LM5066I PMBUS @10h
+        */
 };
 
 &i2c8 {
        status = "okay";
 
-       /* CPU1 VR ISL68137 0.7V, 0.96V PMBUS @65h */
-       /* CPU1 VR ISL68137 1.2V CH03 PMBUS @44h */
-       /* CPU1 VR ISL68137 0.8V PMBUS @61h */
+       vrm@64 {
+               compatible = "isil,isl68137";
+               reg = <0x64>;
+       };
+
+       vrm@40 {
+               compatible = "isil,isl68137";
+               reg = <0x40>;
+       };
+
+       vrm@41 {
+               compatible = "isil,isl68137";
+               reg = <0x41>;
+       };
+
+       vrm@42 {
+               compatible = "infineon,ir38064";
+               reg = <0x42>;
+       };
+
+       vrm@60 {
+               compatible = "isil,isl68137";
+               reg = <0x60>;
+       };
+
+       /* CPU1 VR ISL68137 0.7V, 0.96V PMBUS @64h */
+       /* CPU1 VR ISL68137 1.2V CH03 PMBUS @40h */
+       /* CPU1 VR ISL68137 1.2V CH47 PMBUS @41h */
        /* CPU1 VR 1.0V IR38064 I2C @12h, PMBUS @42h */
-       /* CPU0 VR ISL68137 1.2V CH47 PMBUS @45h */
+       /* CPU1 VR ISL68137 0.8V PMBUS @60h */
 };
 
 
 &ibt {
        status = "okay";
 };
+
+#include "ibm-power9-dual.dtsi"
index 0d7c633..a68ff06 100644 (file)
                        &pinctrl_ddcclk_default &pinctrl_ddcdat_default>;
 };
 
+&p2a {
+       status = "okay";
+       memory-region = <&vga_memory>;
+};
+
 &ibt {
        status = "okay";
 };
index 5d7050d..dd4b0b1 100644 (file)
@@ -53,7 +53,7 @@
                #size-cells = <1>;
                ranges;
 
-               fmc: flash-controller@1e620000 {
+               fmc: spi@1e620000 {
                        reg = < 0x1e620000 0x94
                                0x20000000 0x10000000 >;
                        #address-cells = <1>;
@@ -69,7 +69,7 @@
                        };
                };
 
-               spi: flash-controller@1e630000 {
+               spi: spi@1e630000 {
                        reg = < 0x1e630000 0x18
                                0x30000000 0x10000000 >;
                        #address-cells = <1>;
                                        compatible = "aspeed,g4-pinctrl";
                                };
 
+                               p2a: p2a-control {
+                                       compatible = "aspeed,ast2400-p2a-ctrl";
+                                       status = "disabled";
+                               };
                        };
 
                        rng: hwrng@1e6e2078 {
index 4345c31..5b1ca26 100644 (file)
@@ -60,7 +60,7 @@
                #size-cells = <1>;
                ranges;
 
-               fmc: flash-controller@1e620000 {
+               fmc: spi@1e620000 {
                        reg = < 0x1e620000 0xc4
                                0x20000000 0x10000000 >;
                        #address-cells = <1>;
@@ -86,7 +86,7 @@
                        };
                };
 
-               spi1: flash-controller@1e630000 {
+               spi1: spi@1e630000 {
                        reg = < 0x1e630000 0xc4
                                0x30000000 0x08000000 >;
                        #address-cells = <1>;
                        };
                };
 
-               spi2: flash-controller@1e631000 {
+               spi2: spi@1e631000 {
                        reg = < 0x1e631000 0xc4
                                0x38000000 0x08000000 >;
                        #address-cells = <1>;
                                        aspeed,external-nodes = <&gfx &lhc>;
 
                                };
+
+                               p2a: p2a-control {
+                                       compatible = "aspeed,ast2500-p2a-ctrl";
+                                       status = "disabled";
+                               };
                        };
 
                        rng: hwrng@1e6e2078 {
index 85692c8..4ed8500 100644 (file)
@@ -42,7 +42,7 @@
        clock-frequency = <12000000>;
 };
 
-&slow_osc {
+&clk32k {
        atmel,osc-bypass;
 };
 
index 1fa84d2..7debdea 100644 (file)
        chosen {
                bootargs = "rootfstype=ubifs ubi.mtd=5 root=ubi0:rootfs rw";
                stdout-path = "serial0:115200n8";
-
-               clocksource {
-                       timer = <&timer0>;
-               };
-
-               clockevent {
-                       timer = <&timer1>;
-               };
        };
 
        memory {
index 9483609..691c95e 100644 (file)
                                };
                        };
 
-                       sckc@fffffd50 {
+                       clk32k: sckc@fffffd50 {
                                compatible = "atmel,at91sam9x5-sckc";
                                reg = <0xfffffd50 0x4>;
-
-                               slow_osc: slow_osc {
-                                       compatible = "atmel,at91sam9x5-clk-slow-osc";
-                                       #clock-cells = <0>;
-                                       atmel,startup-time-usec = <1200000>;
-                                       clocks = <&slow_xtal>;
-                               };
-
-                               slow_rc_osc: slow_rc_osc {
-                                       compatible = "atmel,at91sam9x5-clk-slow-rc-osc";
-                                       #clock-cells = <0>;
-                                       atmel,startup-time-usec = <75>;
-                                       clock-frequency = <32768>;
-                                       clock-accuracy = <50000000>;
-                               };
-
-                               clk32k: slck {
-                                       compatible = "atmel,at91sam9x5-clk-slow";
-                                       #clock-cells = <0>;
-                                       clocks = <&slow_rc_osc &slow_osc>;
-                               };
+                               clocks = <&slow_xtal>;
+                               #clock-cells = <0>;
                        };
 
                        rtc@fffffd20 {
index e2d38ce..8643b71 100644 (file)
                                status = "disabled";
                        };
 
-                       sckc@fffffd50 {
+                       clk32k: sckc@fffffd50 {
                                compatible = "atmel,at91sam9x5-sckc";
                                reg = <0xfffffd50 0x4>;
-
-                               slow_osc: slow_osc {
-                                       compatible = "atmel,at91sam9x5-clk-slow-osc";
-                                       #clock-cells = <0>;
-                                       atmel,startup-time-usec = <1200000>;
-                                       clocks = <&slow_xtal>;
-                               };
-
-                               slow_rc_osc: slow_rc_osc {
-                                       compatible = "atmel,at91sam9x5-clk-slow-rc-osc";
-                                       #clock-cells = <0>;
-                                       atmel,startup-time-usec = <75>;
-                                       clock-frequency = <32768>;
-                                       clock-accuracy = <50000000>;
-                               };
-
-                               clk32k: slck {
-                                       compatible = "atmel,at91sam9x5-clk-slow";
-                                       #clock-cells = <0>;
-                                       clocks = <&slow_rc_osc &slow_osc>;
-                               };
+                               clocks = <&slow_xtal>;
+                               #clock-cells = <0>;
                        };
 
                        rtc@fffffd20 {
index 9b7ce6b..ef47c00 100644 (file)
                                clocks = <&pmc PMC_TYPE_CORE PMC_MCK>;
                        };
 
-                       sckc@fffffe50 {
+                       clk32k: sckc@fffffe50 {
                                compatible = "atmel,at91sam9x5-sckc";
                                reg = <0xfffffe50 0x4>;
-
-                               slow_osc: slow_osc {
-                                       compatible = "atmel,at91sam9x5-clk-slow-osc";
-                                       #clock-cells = <0>;
-                                       clocks = <&slow_xtal>;
-                               };
-
-                               slow_rc_osc: slow_rc_osc {
-                                       compatible = "atmel,at91sam9x5-clk-slow-rc-osc";
-                                       #clock-cells = <0>;
-                                       clock-frequency = <32768>;
-                                       clock-accuracy = <50000000>;
-                               };
-
-                               clk32k: slck {
-                                       compatible = "atmel,at91sam9x5-clk-slow";
-                                       #clock-cells = <0>;
-                                       clocks = <&slow_rc_osc>, <&slow_osc>;
-                               };
+                               clocks = <&slow_xtal>;
+                               #clock-cells = <0>;
                        };
 
                        tcb0: timer@f8008000 {
index 80b6ba4..52f91a1 100644 (file)
@@ -42,7 +42,7 @@ clocks {
        };
 
        /* Cygnus ARM PLL */
-       armpll: armpll {
+       armpll: armpll@19000000 {
                #clock-cells = <0>;
                compatible = "brcm,cygnus-armpll";
                clocks = <&osc>;
@@ -67,7 +67,7 @@ clocks {
                clock-mult = <1>;
        };
 
-       genpll: genpll {
+       genpll: genpll@301d000 {
                #clock-cells = <1>;
                compatible = "brcm,cygnus-genpll";
                reg = <0x0301d000 0x2c>, <0x0301c020 0x4>;
@@ -94,7 +94,7 @@ clocks {
                clock-mult = <1>;
        };
 
-       lcpll0: lcpll0 {
+       lcpll0: lcpll0@301d02c {
                #clock-cells = <1>;
                compatible = "brcm,cygnus-lcpll0";
                reg = <0x0301d02c 0x1c>, <0x0301c020 0x4>;
@@ -103,7 +103,7 @@ clocks {
                                     "usb_phy", "smart_card", "ch5";
        };
 
-       mipipll: mipipll {
+       mipipll: mipipll@180a9800 {
                #clock-cells = <1>;
                compatible = "brcm,cygnus-mipipll";
                reg = <0x180a9800 0x2c>, <0x0301c020 0x4>, <0x180aa024 0x4>;
@@ -113,7 +113,7 @@ clocks {
                                     "ch5_unused";
        };
 
-       asiu_clks: asiu_clks {
+       asiu_clks: asiu_clks@301d048 {
                #clock-cells = <1>;
                compatible = "brcm,cygnus-asiu-clk";
                reg = <0x0301d048 0xc>, <0x180aa024 0x4>;
@@ -122,7 +122,7 @@ clocks {
                clock-output-names = "keypad", "adc/touch", "pwm";
        };
 
-       audiopll: audiopll {
+       audiopll: audiopll@180aeb00 {
                #clock-cells = <1>;
                compatible = "brcm,cygnus-audiopll";
                reg = <0x180aeb00 0x68>;
index 5f7b465..2dac3ef 100644 (file)
@@ -45,7 +45,7 @@
                ethernet0 = &eth0;
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0 0>;
        };
@@ -69,7 +69,7 @@
                interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
        };
 
-       core {
+       core@19000000 {
                compatible = "simple-bus";
                ranges = <0x00000000 0x19000000 0x1000000>;
                #address-cells = <1>;
@@ -91,7 +91,7 @@
                              <0x20100 0x100>;
                };
 
-               L2: l2-cache {
+               L2: l2-cache@22000 {
                        compatible = "arm,pl310-cache";
                        reg = <0x22000 0x1000>;
                        cache-unified;
index 6925b30..da6d70f 100644 (file)
@@ -77,7 +77,7 @@
                interrupt-affinity = <&cpu0>, <&cpu1>;
        };
 
-       mpcore {
+       mpcore@19000000 {
                compatible = "simple-bus";
                ranges = <0x00000000 0x19000000 0x00023000>;
                #address-cells = <1>;
                              <0x20100 0x100>;
                };
 
-               L2: l2-cache {
+               L2: l2-cache@22000 {
                        compatible = "arm,pl310-cache";
                        reg = <0x22000 0x1000>;
                        cache-unified;
                };
        };
 
-       axi {
+       axi@18000000 {
                compatible = "simple-bus";
                ranges = <0x00000000 0x18000000 0x0011c40c>;
                #address-cells = <1>;
                                          "imp_sleep_timer_p5",
                                          "imp_sleep_timer_p7",
                                          "imp_sleep_timer_p8";
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-
                        status = "disabled";
 
                        /* ports are defined in board DTS */
index b99c2e5..6197e7d 100644 (file)
                reg-io-width = <4>;
        };
 
-       L2: l2-cache {
+       L2: l2-cache@3ff20000 {
                compatible = "brcm,bcm11351-a2-pl310-cache";
                reg = <0x3ff20000 0x1000>;
                cache-unified;
                #size-cells = <1>;
                ranges;
 
-               root_ccu: root_ccu {
+               root_ccu: root_ccu@35001000 {
                        compatible = "brcm,bcm11351-root-ccu";
                        reg = <0x35001000 0x0f00>;
                        #clock-cells = <1>;
                        clock-output-names = "frac_1m";
                };
 
-               hub_ccu: hub_ccu {
+               hub_ccu: hub_ccu@34000000 {
                        compatible = "brcm,bcm11351-hub-ccu";
                        reg = <0x34000000 0x0f00>;
                        #clock-cells = <1>;
                        clock-output-names = "tmon_1m";
                };
 
-               aon_ccu: aon_ccu {
+               aon_ccu: aon_ccu@35002000 {
                        compatible = "brcm,bcm11351-aon-ccu";
                        reg = <0x35002000 0x0f00>;
                        #clock-cells = <1>;
                                             "pmu_bsc_var";
                };
 
-               master_ccu: master_ccu {
+               master_ccu: master_ccu@3f001000 {
                        compatible = "brcm,bcm11351-master-ccu";
                        reg = <0x3f001000 0x0f00>;
                        #clock-cells = <1>;
                                             "hsic2_12m";
                };
 
-               slave_ccu: slave_ccu {
+               slave_ccu: slave_ccu@3e011000 {
                        compatible = "brcm,bcm11351-slave-ccu";
                        reg = <0x3e011000 0x0f00>;
                        #clock-cells = <1>;
index 8b045cf..be468f4 100644 (file)
@@ -21,7 +21,7 @@
        model = "BCM21664 Garnet board";
        compatible = "brcm,bcm21664-garnet", "brcm,bcm21664";
 
-       memory {
+       memory@80000000 {
                device_type = "memory";
                reg = <0x80000000 0x40000000>; /* 1 GB */
        };
index 758daa3..3cf66fa 100644 (file)
@@ -90,7 +90,7 @@
                reg-io-width = <4>;
        };
 
-       L2: l2-cache {
+       L2: l2-cache@3ff20000 {
                compatible = "arm,pl310-cache";
                reg = <0x3ff20000 0x1000>;
                cache-unified;
                        clock-frequency = <156000000>;
                };
 
-               root_ccu: root_ccu {
+               root_ccu: root_ccu@35001000 {
                        compatible = BCM21664_DT_ROOT_CCU_COMPAT;
                        reg = <0x35001000 0x0f00>;
                        #clock-cells = <1>;
                        clock-output-names = "frac_1m";
                };
 
-               aon_ccu: aon_ccu {
+               aon_ccu: aon_ccu@35002000 {
                        compatible = BCM21664_DT_AON_CCU_COMPAT;
                        reg = <0x35002000 0x0f00>;
                        #clock-cells = <1>;
                        clock-output-names = "hub_timer";
                };
 
-               master_ccu: master_ccu {
+               master_ccu: master_ccu@3f001000 {
                        compatible = BCM21664_DT_MASTER_CCU_COMPAT;
                        reg = <0x3f001000 0x0f00>;
                        #clock-cells = <1>;
                                             "sdio4_sleep";
                };
 
-               slave_ccu: slave_ccu {
+               slave_ccu: slave_ccu@3e011000 {
                        compatible = BCM21664_DT_SLAVE_CCU_COMPAT;
                        reg = <0x3e011000 0x0f00>;
                        #clock-cells = <1>;
index 1c66b15..ace7770 100644 (file)
@@ -45,7 +45,7 @@
                bootargs = "console=ttyS0,115200n8";
        };
 
-       memory {
+       memory@80000000 {
                device_type = "memory";
                reg = <0x80000000 0x20000000>; /* 512 MB */
        };
index 701198f..a36c9b1 100644 (file)
                        clock-frequency = <156000000>;
                };
 
-               root_ccu: root_ccu {
+               root_ccu: root_ccu@35001000 {
                        compatible = BCM21664_DT_ROOT_CCU_COMPAT;
                        reg = <0x35001000 0x0f00>;
                        #clock-cells = <1>;
                        clock-output-names = "frac_1m";
                };
 
-               aon_ccu: aon_ccu {
+               aon_ccu: aon_ccu@35002000 {
                        compatible = BCM21664_DT_AON_CCU_COMPAT;
                        reg = <0x35002000 0x0f00>;
                        #clock-cells = <1>;
                        clock-output-names = "hub_timer";
                };
 
-               slave_ccu: slave_ccu {
+               slave_ccu: slave_ccu@3e011000 {
                        compatible = BCM21664_DT_SLAVE_CCU_COMPAT;
                        reg = <0x3e011000 0x0f00>;
                        #clock-cells = <1>;
                                             "bsc4";
                };
 
-               master_ccu: master_ccu {
+               master_ccu: master_ccu@3f001000 {
                        compatible = BCM21664_DT_MASTER_CCU_COMPAT;
                        reg = <0x3f001000 0x0f00>;
                        #clock-cells = <1>;
index fbfca83..ead6e98 100644 (file)
@@ -21,7 +21,7 @@
        model = "BCM28155 AP board";
        compatible = "brcm,bcm28155-ap", "brcm,bcm11351";
 
-       memory {
+       memory@80000000 {
                device_type = "memory";
                reg = <0x80000000 0x40000000>; /* 1 GB */
        };
index 9777644..4b21ddb 100644 (file)
                        reg = <0x7e204000 0x1000>;
                        interrupts = <2 22>;
                        clocks = <&clocks BCM2835_CLOCK_VPU>;
+                       dmas = <&dma 6>, <&dma 7>;
+                       dma-names = "tx", "rx";
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "disabled";
index 1c6f561..6a96655 100644 (file)
@@ -19,7 +19,7 @@
                bootargs = "console=ttyS0,115200";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000
                       0x88000000 0x08000000>;
@@ -69,8 +69,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                rfkill {
                        label = "WiFi";
index e550799..3b0029e 100644 (file)
@@ -19,7 +19,7 @@
                bootargs = "console=ttyS0,115200";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000
                       0x88000000 0x08000000>;
@@ -53,8 +53,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                brightness {
                        label = "Backlight";
index 7bfa223..90f57ba 100644 (file)
@@ -19,7 +19,7 @@
                bootargs = "console=ttyS0,115200 earlycon";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000
                       0x88000000 0x18000000>;
@@ -99,8 +99,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                restart {
                        label = "Reset";
index fd361c9..41548d6 100644 (file)
                bootargs = "console=ttyS0,115200";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000>;
        };
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                wps {
                        label = "WPS";
index 7c34360..cd797b4 100644 (file)
                bootargs = "console=ttyS0,115200";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000>;
        };
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                wps {
                        label = "WPS";
index 969b8d7..e58c807 100644 (file)
@@ -15,7 +15,7 @@
                bootargs = "console=ttyS0,115200 earlycon";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000>;
        };
@@ -44,8 +44,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                restart {
                        label = "Reset";
index b62854e..766db61 100644 (file)
@@ -19,7 +19,7 @@
                bootargs = "console=ttyS0,115200 earlycon";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000>;
        };
@@ -51,8 +51,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                restart {
                        label = "Reset";
index 75f7b4e..fed75e6 100644 (file)
@@ -62,8 +62,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                wps {
                        label = "WPS";
index 148d16a..79542e1 100644 (file)
@@ -19,7 +19,7 @@
                bootargs = "console=ttyS0,115200";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000
                       0x88000000 0x08000000>;
@@ -58,8 +58,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                wps {
                        label = "WPS";
index eed3aab..abd35a5 100644 (file)
@@ -19,7 +19,7 @@
                bootargs = "console=ttyS0,115200 earlycon";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000
                       0x88000000 0x08000000>;
@@ -93,8 +93,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                rfkill {
                        label = "WiFi";
index fe842f2..c29950b 100644 (file)
@@ -19,7 +19,7 @@
                bootargs = "console=ttyS0,115200";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000
                       0x88000000 0x08000000>;
@@ -59,8 +59,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                restart {
                        label = "Reset";
index 6fcbb05..4dcec68 100644 (file)
@@ -19,7 +19,7 @@
                bootargs = "console=ttyS0,115200 earlycon";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000
                       0x88000000 0x08000000>;
@@ -90,8 +90,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                aoss {
                        label = "AOSS";
index b3e8cc9..0e349e3 100644 (file)
@@ -19,7 +19,7 @@
                bootargs = "console=ttyS0,115200";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000
                       0x88000000 0x08000000>;
@@ -95,8 +95,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                restart {
                        label = "Reset";
index fdeaa89..b9d9501 100644 (file)
@@ -15,7 +15,7 @@
                bootargs = "console=ttyS0,115200";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000>;
        };
@@ -44,8 +44,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                restart {
                        label = "Reset";
index 0d510cb..0052e1b 100644 (file)
@@ -16,7 +16,7 @@
                bootargs = "console=ttyS0,115200";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000>;
        };
@@ -88,8 +88,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                restart {
                        label = "Reset";
index 962e89e..01c390e 100644 (file)
@@ -15,7 +15,7 @@
                bootargs = "earlycon";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000>;
        };
@@ -76,8 +76,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                rfkill {
                        label = "WiFi";
index 658a56f..911c65f 100644 (file)
@@ -19,7 +19,7 @@
                bootargs = "console=ttyS0,115200 earlycon";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000
                       0x88000000 0x08000000>;
@@ -85,8 +85,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                wps {
                        label = "WPS";
index 5fd47ee..18d0ae4 100644 (file)
@@ -16,7 +16,7 @@
                bootargs = "console=ttyS0,115200";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000
                       0x88000000 0x08000000>;
@@ -24,8 +24,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                wps {
                        label = "WPS";
index 6604be6..50f7cd0 100644 (file)
@@ -16,7 +16,7 @@
                bootargs = "earlycon";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000
                       0x88000000 0x18000000>;
@@ -43,8 +43,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                restart {
                        label = "Reset";
index 567ebbd..b47fb07 100644 (file)
@@ -15,7 +15,7 @@
                bootargs = "earlycon";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000>;
        };
@@ -42,8 +42,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                restart {
                        label = "Reset";
index ac2d136..bcc420f 100644 (file)
@@ -16,7 +16,7 @@
                bootargs = "earlycon";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000
                       0x88000000 0x18000000>;
@@ -43,8 +43,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                restart {
                        label = "Reset";
index 74371e8..ac75154 100644 (file)
@@ -16,7 +16,7 @@
                bootargs = "console=ttyS0,115200 earlycon";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000
                       0x88000000 0x08000000>;
@@ -83,8 +83,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                restart {
                        label = "Reset";
index b44af63..6d28b7d 100644 (file)
@@ -16,7 +16,7 @@
                bootargs = "earlycon";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000
                       0x88000000 0x18000000>;
@@ -58,8 +58,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                restart {
                        label = "Reset";
index eebc0d4..f42a170 100644 (file)
@@ -16,7 +16,7 @@
                bootargs = "console=ttyS0,115200";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000
                       0x88000000 0x18000000>;
@@ -64,8 +64,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                brightness {
                        label = "Backlight";
index 456045f..ac3a448 100644 (file)
@@ -13,7 +13,7 @@
        compatible = "phicomm,k3", "brcm,bcm47094", "brcm,bcm4708";
        model = "Phicomm K3";
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000
                       0x88000000 0x18000000>;
@@ -21,8 +21,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                restart {
                        label = "Reset";
index eb59508..57ca1cf 100644 (file)
@@ -15,7 +15,7 @@
                bootargs = "earlycon";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000>;
        };
@@ -38,8 +38,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                restart {
                        label = "Reset";
index 4c71f5e..2e1a7e3 100644 (file)
@@ -15,7 +15,7 @@
                bootargs = "earlycon";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000>;
        };
@@ -48,8 +48,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                restart {
                        label = "Reset";
index 5ad53ea..049cdfd 100644 (file)
@@ -15,7 +15,7 @@
                bootargs = "console=ttyS0,115200 earlycon";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000>;
        };
@@ -58,8 +58,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                rfkill {
                        label = "WiFi";
index ac5266e..372dc1e 100644 (file)
@@ -19,7 +19,7 @@
        #size-cells = <1>;
        interrupt-parent = <&gic>;
 
-       chipcommonA {
+       chipcommonA@18000000 {
                compatible = "simple-bus";
                ranges = <0x00000000 0x18000000 0x00001000>;
                #address-cells = <1>;
@@ -44,7 +44,7 @@
                };
        };
 
-       mpcore {
+       mpcore@19000000 {
                compatible = "simple-bus";
                ranges = <0x00000000 0x19000000 0x00023000>;
                #address-cells = <1>;
                };
        };
 
-       usb2_phy: usb2-phy {
+       usb2_phy: usb2-phy@1800c000 {
                compatible = "brcm,ns-usb2-phy";
                reg = <0x1800c000 0x1000>;
                reg-names = "dmu";
                #address-cells = <0>;
        };
 
-       mdio-bus-mux {
+       mdio-bus-mux@18003000 {
                compatible = "mdio-mux-mmioreg";
                mdio-parent-bus = <&mdio>;
                #address-cells = <1>;
        srab: srab@18007000 {
                compatible = "brcm,bcm5301x-srab";
                reg = <0x18007000 0x1000>;
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                status = "disabled";
 
index b29695b..4af8e32 100644 (file)
@@ -32,7 +32,7 @@
                };
        };
 
-       mpcore {
+       mpcore@18310000 {
                compatible = "simple-bus";
                ranges = <0x00000000 0x18310000 0x00008000>;
                #address-cells = <1>;
index e6a41e1..9c0325c 100644 (file)
@@ -41,9 +41,6 @@
        };
 
        clocks {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
                /* UBUS peripheral clock */
                periph_clk: periph_clk {
                        #clock-cells = <0>;
@@ -94,7 +91,7 @@
                        reg = <0x1e000 0x100>;
                };
 
-               gic: interrupt-controller@1e100 {
+               gic: interrupt-controller@1f000 {
                        compatible = "arm,cortex-a9-gic";
                        reg = <0x1f000 0x1000
                                0x1e100 0x100>;
                                                  IRQ_TYPE_LEVEL_HIGH)>;
                };
 
-               armpll: armpll {
+               armpll: armpll@20000 {
                        #clock-cells = <0>;
                        compatible = "brcm,bcm63138-armpll";
                        clocks = <&periph_clk>;
                        #reset-cells = <2>;
                };
 
-               ahci: sata@8000 {
+               ahci: sata@a000 {
                        compatible = "brcm,bcm63138-ahci", "brcm,sata3-ahci";
                        reg-names = "ahci", "top-ctrl";
                        reg = <0xa000 0x9ac>, <0x8040 0x24>;
index 8006c69..8313b7c 100644 (file)
@@ -6,7 +6,7 @@
        model = "Broadcom STB (bcm7445), SVMB reference board";
        compatible = "brcm,bcm7445", "brcm,brcmstb";
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00 0x00000000 0x00 0x40000000>,
                      <0x00 0x40000000 0x00 0x40000000>,
index 504a632..58f67c9 100644 (file)
@@ -63,7 +63,7 @@
                             <GIC_PPI 10 (GIC_CPU_MASK_RAW(15) | IRQ_TYPE_LEVEL_LOW)>;
        };
 
-       rdb {
+       rdb@f0000000 {
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "simple-bus";
 
        };
 
-       memory_controllers {
+       memory_controllers@f1100000 {
                compatible = "simple-bus";
                ranges = <0x0 0x0 0xf1100000 0x200000>;
                #address-cells = <1>;
                        };
                };
 
-               memc@1 {
+               memc@80000 {
                        compatible = "brcm,brcmstb-memc", "simple-bus";
                        #address-cells = <1>;
                        #size-cells = <1>;
                        };
                };
 
-               memc@2 {
+               memc@100000 {
                        compatible = "brcm,brcmstb-memc", "simple-bus";
                        #address-cells = <1>;
                        #size-cells = <1>;
index 53f990d..b2d323f 100644 (file)
@@ -49,8 +49,6 @@
 
        gpio_keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                hook {
                        label = "HOOK";
index 4991700..b0b8c77 100644 (file)
@@ -17,7 +17,7 @@
                bootargs = "console=ttyS0,115200 earlycon";
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x08000000>;
        };
@@ -43,8 +43,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                restart {
                        label = "Reset";
index 250a1d6..9574682 100644 (file)
        model = "NorthStar Enterprise Router (BCM953012ER)";
        compatible = "brcm,bcm953012er", "brcm,brcm53012", "brcm,bcm4708";
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x00000000 0x8000000>;
        };
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                wps {
                        label = "WPS";
index 52c4c6c..046c59f 100644 (file)
@@ -43,7 +43,7 @@
                serial1 = &uart1;
        };
 
-       memory {
+       memory@80000000 {
                device_type = "memory";
                reg = <0x80000000 0x10000000>;
        };
index 21479b4..8c388eb 100644 (file)
@@ -43,7 +43,7 @@
                stdout-path = "serial0:115200n8";
        };
 
-       memory {
+       memory@60000000 {
                device_type = "memory";
                reg = <0x60000000 0x80000000>;
        };
index cda3d79..c339771 100644 (file)
@@ -43,7 +43,7 @@
                stdout-path = "serial0:115200n8";
        };
 
-       memory {
+       memory@60000000 {
                device_type = "memory";
                reg = <0x60000000 0x80000000>;
        };
index f866498..1c72ec8 100644 (file)
@@ -43,7 +43,7 @@
                stdout-path = "serial0:115200n8";
        };
 
-       memory {
+       memory@60000000 {
                device_type = "memory";
                reg = <0x60000000 0x40000000>;
        };
index df60602..96a021c 100644 (file)
@@ -43,7 +43,7 @@
                stdout-path = "serial0:115200n8";
        };
 
-       memory {
+       memory@60000000 {
                device_type = "memory";
                reg = <0x60000000 0x80000000>;
        };
index 3893e7a..b2c7f21 100644 (file)
@@ -43,7 +43,7 @@
                stdout-path = "serial0:115200n8";
        };
 
-       memory {
+       memory@60000000 {
                device_type = "memory";
                reg = <0x60000000 0x80000000>;
        };
index cf226b0..a2c9de3 100644 (file)
@@ -43,7 +43,7 @@
                stdout-path = "serial0:115200n8";
        };
 
-       memory {
+       memory@60000000 {
                device_type = "memory";
                reg = <0x60000000 0x20000000>;
        };
index 10b3d51..3fcca12 100644 (file)
@@ -42,7 +42,7 @@
                stdout-path = "serial0:115200n8";
        };
 
-       memory {
+       memory@60000000 {
                device_type = "memory";
                reg = <0x60000000 0x80000000>;
        };
index 2952568..5b17727 100644 (file)
@@ -16,7 +16,7 @@
                stdout-path = &serial0;
        };
 
-       memory {
+       memory@0 {
                device_type = "memory";
                reg = <0x0 0x08000000>;
        };
index e39db14..edd0f63 100644 (file)
@@ -43,7 +43,7 @@
                stdout-path = "serial0:115200n8";
        };
 
-       memory {
+       memory@60000000 {
                device_type = "memory";
                reg = <0x60000000 0x80000000>;
        };
index f2d2b87..5b2b1ed 100644 (file)
        };
 };
 
+&cpu {
+       cpu-supply = <&vdcdc3_reg>;
+};
+
+/*
+ * The standard da850-evm kits and SOM's are 375MHz so enable this operating
+ * point by default. Higher frequencies must be enabled for custom boards with
+ * other variants of the SoC.
+ */
+&opp_375 {
+       status = "okay";
+};
+
 &sata {
        status = "okay";
 };
index 2fd2a68..e379d6e 100644 (file)
                        };
                };
        };
+
+       cvdd: regulator0 {
+               compatible = "regulator-fixed";
+               regulator-name = "cvdd";
+               regulator-min-microvolt = <1300000>;
+               regulator-max-microvolt = <1300000>;
+               regulator-always-on;
+               regulator-boot-on;
+       };
 };
 
 &ref_clk {
        clock-frequency = <24000000>;
 };
 
+&cpu {
+       cpu-supply = <&cvdd>;
+};
+
+/*
+ * LCDK has a fixed CVDD of 1.3V, so only operating points >= 300MHz are
+ * valid. Unfortunately due to a problem with the DA8XX OHCI controller, we
+ * can't enable more than one OPP by default, since the controller sometimes
+ * becomes unresponsive after a transition. Fix the frequency at 456 MHz.
+ */
+
+&opp_100 {
+       status = "disabled";
+};
+
+&opp_200 {
+       status = "disabled";
+};
+
+&opp_300 {
+       status = "disabled";
+};
+
+&opp_456 {
+       status = "okay";
+};
+
 &pmx_core {
        status = "okay";
 
index 09c3666..afd04a4 100644 (file)
                amp-supply = <&amp>;
        };
 
+       cvdd: regulator0 {
+               compatible = "regulator-fixed";
+               regulator-name = "cvdd";
+               regulator-min-microvolt = <1200000>;
+               regulator-max-microvolt = <1200000>;
+               regulator-always-on;
+               regulator-boot-on;
+       };
+
        /*
         * This is a 5V current limiting regulator that is shared by USB,
         * the sensor (input) ports, the motor (output) ports and the A/DC.
        clock-frequency = <24000000>;
 };
 
+&cpu {
+       cpu-supply = <&cvdd>;
+};
+
+/* since we have a fixed regulator, we can't run at these points */
+&opp_100 {
+       status = "disabled";
+};
+
+&opp_200 {
+       status = "disabled";
+};
+
+/*
+ * The SoC is actually the 456MHz version, but because of the fixed regulator
+ * This is the fastest we can go.
+ */
+&opp_375 {
+       status = "okay";
+};
+
 &pmx_core {
        status = "okay";
 
index e6e78b8..7cf31b6 100644 (file)
                reg = <0xc0000000 0x0>;
        };
 
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu: cpu@0 {
+                       compatible = "arm,arm926ej-s";
+                       device_type = "cpu";
+                       reg = <0>;
+                       clocks = <&psc0 14>;
+                       operating-points-v2 = <&opp_table>;
+               };
+       };
+
+       opp_table: opp-table {
+               compatible = "operating-points-v2";
+
+               opp_100: opp100-100000000 {
+                       opp-hz = /bits/ 64 <100000000>;
+                       opp-microvolt = <1000000 950000 1050000>;
+               };
+
+               opp_200: opp110-200000000 {
+                       opp-hz = /bits/ 64 <200000000>;
+                       opp-microvolt = <1100000 1050000 1160000>;
+               };
+
+               opp_300: opp120-300000000 {
+                       opp-hz = /bits/ 64 <300000000>;
+                       opp-microvolt = <1200000 1140000 1320000>;
+               };
+
+               /*
+                * Original silicon was 300MHz max, so higher frequencies
+                * need to be enabled on a per-board basis if the chip is
+                * capable.
+                */
+
+               opp_375: opp120-375000000 {
+                       status = "disabled";
+                       opp-hz = /bits/ 64 <375000000>;
+                       opp-microvolt = <1200000 1140000 1320000>;
+               };
+
+               opp_456: opp130-456000000 {
+                       status = "disabled";
+                       opp-hz = /bits/ 64 <456000000>;
+                       opp-microvolt = <1300000 1250000 1350000>;
+               };
+       };
+
        arm {
                #address-cells = <1>;
                #size-cells = <1>;
index abfff54..0a27f03 100644 (file)
@@ -25,7 +25,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial1:115200n8";
        };
 
index ace50e1..dee35e3 100644 (file)
        cpu0-supply = <&buck2_reg>;
 };
 
+&gpu {
+       mali-supply = <&buck3_reg>;
+       status = "okay";
+};
+
 &i2c_0 {
        #address-cells = <1>;
        #size-cells = <0>;
index e257655..248bd37 100644 (file)
        status = "okay";
 };
 
+&gpu {
+       mali-supply = <&buck3_reg>;
+       status = "okay";
+};
+
 &hsotg {
        vusb_d-supply = <&ldo15_reg>;
        vusb_a-supply = <&ldo12_reg>;
index 7479993..86c26a4 100644 (file)
        };
 };
 
+&gpu {
+       mali-supply = <&buck3_reg>;
+       status = "okay";
+};
+
 &i2c_0 {
        #address-cells = <1>;
        #size-cells = <0>;
index 8ce3a77..5659c4a 100644 (file)
                        status = "disabled";
                };
 
+               gpu: gpu@13000000 {
+                       compatible = "samsung,exynos4210-mali", "arm,mali-400";
+                       reg = <0x13000000 0x10000>;
+                       interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 182 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 183 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 179 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 185 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 181 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "gp",
+                                         "gpmmu",
+                                         "pp0",
+                                         "ppmmu0",
+                                         "pp1",
+                                         "ppmmu1",
+                                         "pp2",
+                                         "ppmmu2",
+                                         "pp3",
+                                         "ppmmu3",
+                                         "pmu";
+                       clocks = <&cmu CLK_G3D>,
+                                <&cmu CLK_SCLK_G3D>;
+                       clock-names = "bus", "core";
+                       power-domains = <&pd_g3d>;
+                       status = "disabled";
+                       /* TODO: operating points for DVFS, assigned clock as 134 MHz */
+               };
+
                mfc: codec@13400000 {
                        compatible = "samsung,mfc-v7";
                        reg = <0x13400000 0x10000>;
index 36ccf22..1264cc4 100644 (file)
@@ -54,7 +54,7 @@
        pmu: pmu {
                compatible = "arm,cortex-a9-pmu";
                interrupt-parent = <&combiner>;
-               interrupts = <2 2>, <3 2>;
+               status = "disabled";
        };
 
        soc: soc {
                        };
                };
 
+               gpu: gpu@13000000 {
+                       compatible = "samsung,exynos4210-mali", "arm,mali-400";
+                       reg = <0x13000000 0x10000>;
+                       /*
+                        * CLK_G3D is not actually bus clock but a IP-level clock.
+                        * The bus clock is not described in hardware manual.
+                        */
+                       clocks = <&clock CLK_G3D>,
+                                <&clock CLK_SCLK_G3D>;
+                       clock-names = "bus", "core";
+                       power-domains = <&pd_g3d>;
+                       status = "disabled";
+               };
+
                i2s1: i2s@13960000 {
                        compatible = "samsung,s3c6410-i2s";
                        reg = <0x13960000 0x100>;
index 36b1ede..0d1e1a9 100644 (file)
        status = "okay";
 };
 
+&gpu {
+       mali-supply = <&buck3_reg>;
+       status = "okay";
+};
+
 &hsotg {
        vusb_d-supply = <&ldo3_reg>;
        vusb_a-supply = <&ldo8_reg>;
index 6882480..7c39dd1 100644 (file)
        status = "okay";
 };
 
+&gpu {
+       status = "okay";
+};
+
 &hsotg {
        vusb_d-supply = <&vusb_reg>;
        vusb_a-supply = <&vusbdac_reg>;
index bf092e9..82a8b54 100644 (file)
        };
 };
 
+&gpu {
+       mali-supply = <&buck2_reg>;
+       status = "okay";
+};
+
 &hdmi {
        hpd-gpios = <&gpx3 7 GPIO_ACTIVE_HIGH>;
        pinctrl-names = "default";
index b491c34..f220716 100644 (file)
@@ -8,7 +8,7 @@
  *             www.linaro.org
  *
  * Samsung's Exynos4210 SoC device nodes are listed in this file. Exynos4210
- * based board files can include this file and provide values for board specfic
+ * based board files can include this file and provide values for board specific
  * bindings.
  *
  * Note: This file does not include device nodes for all the controllers in
 
                        trips {
                                cpu_alert0: cpu-alert-0 {
-                               temperature = <85000>; /* millicelsius */
+                                       temperature = <85000>; /* millicelsius */
                                };
                                cpu_alert1: cpu-alert-1 {
-                               temperature = <100000>; /* millicelsius */
+                                       temperature = <100000>; /* millicelsius */
                                };
                                cpu_alert2: cpu-alert-2 {
-                               temperature = <110000>; /* millicelsius */
+                                       temperature = <110000>; /* millicelsius */
                                };
                        };
                };
        samsung,lcd-wb;
 };
 
+&gpu {
+       interrupts = <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+       interrupt-names = "gp",
+                         "gpmmu",
+                         "pp0",
+                         "ppmmu0",
+                         "pp1",
+                         "ppmmu1",
+                         "pp2",
+                         "ppmmu2",
+                         "pp3",
+                         "ppmmu3";
+       operating-points-v2 = <&gpu_opp_table>;
+
+       gpu_opp_table: opp_table {
+               compatible = "operating-points-v2";
+
+               opp-160000000 {
+                       opp-hz = /bits/ 64 <160000000>;
+                       opp-microvolt = <950000>;
+               };
+               opp-267000000 {
+                       opp-hz = /bits/ 64 <267000000>;
+                       opp-microvolt = <1050000>;
+               };
+       };
+};
+
 &mdma1 {
        power-domains = <&pd_lcd0>;
 };
                 <&clock CLK_MOUT_MIXER>, <&clock CLK_SCLK_MIXER>;
 };
 
+&pmu {
+       interrupts = <2 2>, <3 2>;
+       interrupt-affinity = <&cpu0>, <&cpu1>;
+       status = "okay";
+};
+
 &pmu_system_controller {
        clock-names = "clkout0", "clkout1", "clkout2", "clkout3",
                        "clkout4", "clkout8", "clkout9";
index 30eee59..ce87d2f 100644 (file)
                i2c10 = &i2c_cm36651;
        };
 
+       aat1290 {
+               compatible = "skyworks,aat1290";
+               flen-gpios = <&gpj1 1 GPIO_ACTIVE_HIGH>;
+               enset-gpios = <&gpj1 2 GPIO_ACTIVE_HIGH>;
+
+               pinctrl-names = "default", "host", "isp";
+               pinctrl-0 = <&camera_flash_host>;
+               pinctrl-1 = <&camera_flash_host>;
+               pinctrl-2 = <&camera_flash_isp>;
+
+               flash-led {
+                       label = "flash";
+                       led-max-microamp = <520833>;
+                       flash-max-microamp = <1012500>;
+                       flash-max-timeout-us = <1940000>;
+               };
+       };
+
        lcd_vdd3_reg: voltage-regulator-6 {
                compatible = "regulator-fixed";
                regulator-name = "LCD_VDD_2.2V";
        regulator-max-microvolt = <2800000>;
 };
 
+&pinctrl_0 {
+       camera_flash_host: camera-flash-host {
+               samsung,pins = "gpj1-0";
+               samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+               samsung,pin-val = <0>;
+       };
+
+       camera_flash_isp: camera-flash-isp {
+               samsung,pins = "gpj1-0";
+               samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+               samsung,pin-val = <1>;
+       };
+};
+
 &s5c73m3 {
        standby-gpios = <&gpm0 1 GPIO_ACTIVE_LOW>;   /* ISP_STANDBY */
        vdda-supply = <&ldo17_reg>;
index 0038465..462a540 100644 (file)
        cpu0-supply = <&buck2_reg>;
 };
 
+&gpu {
+       mali-supply = <&buck4_reg>;
+       status = "okay";
+};
+
 &hsotg {
        vusb_d-supply = <&ldo15_reg>;
        vusb_a-supply = <&ldo12_reg>;
index 4c15cb6..83be3a7 100644 (file)
        status = "okay";
 };
 
+&gpu {
+       mali-supply = <&buck4_reg>;
+       status = "okay";
+};
+
 &hdmi {
        hpd-gpios = <&gpx3 7 GPIO_ACTIVE_HIGH>;
        pinctrl-names = "default";
index 08d3a0a..ea55f37 100644 (file)
        assigned-clock-rates = <0>, <176000000>;
 };
 
+&gpu {
+       mali-supply = <&buck4_reg>;
+       status = "okay";
+};
+
 &hdmi {
        hpd-gpios = <&gpx3 7 GPIO_ACTIVE_HIGH>;
        pinctrl-names = "default";
index d83fbd4..3731a22 100644 (file)
        cooling-device = <&cpu0 15 15>, <&cpu1 15 15>,
                         <&cpu2 15 15>, <&cpu3 15 15>;
 };
+
+&gpu_opp_table {
+       opp-533000000 {
+               opp-hz = /bits/ 64 <533000000>;
+               opp-microvolt = <1075000>;
+       };
+};
index e5c041e..d20db2d 100644 (file)
        cpu-offset = <0x4000>;
 };
 
+&gpu {
+       interrupts = <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+       interrupt-names = "gp",
+                         "gpmmu",
+                         "pp0",
+                         "ppmmu0",
+                         "pp1",
+                         "ppmmu1",
+                         "pp2",
+                         "ppmmu2",
+                         "pp3",
+                         "ppmmu3",
+                         "pmu";
+       operating-points-v2 = <&gpu_opp_table>;
+
+       gpu_opp_table: opp_table {
+               compatible = "operating-points-v2";
+
+               opp-160000000 {
+                       opp-hz = /bits/ 64 <160000000>;
+                       opp-microvolt = <875000>;
+               };
+               opp-267000000 {
+                       opp-hz = /bits/ 64 <267000000>;
+                       opp-microvolt = <900000>;
+               };
+               opp-350000000 {
+                       opp-hz = /bits/ 64 <350000000>;
+                       opp-microvolt = <950000>;
+               };
+               opp-440000000 {
+                       opp-hz = /bits/ 64 <440000000>;
+                       opp-microvolt = <1025000>;
+               };
+       };
+};
+
 &hdmi {
        compatible = "samsung,exynos4212-hdmi";
 };
 
 &pmu {
        interrupts = <2 2>, <3 2>, <18 2>, <19 2>;
+       interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+       status = "okay";
 };
 
 &pmu_system_controller {
index 8f9e08f..e0db251 100644 (file)
        };
 };
 
+&adc {
+       vdd-supply = <&ldo10_reg>;
+       status = "okay";
+};
+
 &audi2s0 {
        status = "okay";
 };
index 57fc9c9..e6f78b1 100644 (file)
        };
 };
 
+&adc {
+       clocks = <&clock CLK_TSADC>;
+       clock-names = "adc";
+       samsung,syscon-phandle = <&pmu_system_controller>;
+};
+
 &arm_a15_pmu {
        interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
        status = "okay";
index dbf0306..592d7b4 100644 (file)
                                 * (Linaro for Arndale Octa, v2012.07).
                                 */
                                regulator-always-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        ldo4_reg: LDO4 {
                                regulator-name = "PVDD_ANAIP_1V8";
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <1800000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        ldo8_reg: LDO8 {
                                regulator-name = "PVDD_APIO_MMCOFF_2V8";
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <2800000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        ldo14_reg: LDO14 {
                                regulator-name = "PVDD_PERI_2V8";
                                regulator-min-microvolt = <3300000>;
                                regulator-max-microvolt = <3300000>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                               };
                        };
 
                        ldo16_reg: LDO16 {
                                regulator-name = "PVDD_PERI_3V3";
                                regulator-min-microvolt = <2200000>;
                                regulator-max-microvolt = <2200000>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                               };
                        };
 
                        ldo17_reg: LDO17 {
                                regulator-name = "PVDD_EMMC_1V8";
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <1800000>;
+                               /*
+                                * Must stay in "off" mode during shutdown for
+                                * proper eMMC reset.  The "off" mode is in
+                                * fact controlled by LDO18EN.  The eMMC does
+                                * not have reset pin connected so the reset
+                                * will be triggered by falling edge of
+                                * LDO18EN.
+                                */
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        ldo19_reg: LDO19 {
                                regulator-name = "PVDD_TFLASH_2V8";
                                regulator-min-microvolt = <2800000>;
                                regulator-max-microvolt = <2800000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        ldo20_reg: LDO20 {
                                regulator-min-microvolt = <800000>;
                                regulator-max-microvolt = <1100000>;
                                regulator-always-on;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                               };
                        };
 
                        ldo24_reg: LDO24 {
                                regulator-name = "PVDD_CAM1_AVDD_2V8";
                                regulator-min-microvolt = <2800000>;
                                regulator-max-microvolt = <2800000>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                               };
                        };
 
                        ldo25_reg: LDO25 {
                                regulator-name = "PVDD_G3DS_1V0";
                                regulator-min-microvolt = <800000>;
                                regulator-max-microvolt = <1100000>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                               };
                        };
 
                        ldo28_reg: LDO28 {
                        buck1_reg: BUCK1 {
                                regulator-name = "PVDD_MIF_1V1";
                                regulator-min-microvolt = <800000>;
-                               regulator-max-microvolt = <1100000>;
+                               regulator-max-microvolt = <1300000>;
                                regulator-always-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        buck2_reg: BUCK2 {
                                regulator-name = "vdd_arm";
                                regulator-min-microvolt = <800000>;
-                               regulator-max-microvolt = <1000000>;
+                               regulator-max-microvolt = <1500000>;
                                regulator-always-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        buck3_reg: BUCK3 {
                                regulator-name = "PVDD_INT_1V0";
                                regulator-min-microvolt = <800000>;
-                               regulator-max-microvolt = <1000000>;
+                               regulator-max-microvolt = <1400000>;
                                regulator-always-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        buck4_reg: BUCK4 {
                                regulator-name = "PVDD_G3D_1V0";
                                regulator-min-microvolt = <800000>;
-                               regulator-max-microvolt = <1000000>;
+                               regulator-max-microvolt = <1400000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        buck5_reg: BUCK5 {
                                regulator-name = "PVDD_LPDDR3_1V2";
                                regulator-min-microvolt = <800000>;
-                               regulator-max-microvolt = <1200000>;
+                               regulator-max-microvolt = <1400000>;
                                regulator-always-on;
                        };
 
                        buck6_reg: BUCK6 {
                                regulator-name = "PVDD_KFC_1V0";
                                regulator-min-microvolt = <800000>;
-                               regulator-max-microvolt = <1000000>;
+                               regulator-max-microvolt = <1500000>;
                                regulator-always-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        buck7_reg: BUCK7 {
                                regulator-name = "VIN_LLDO_1V4";
-                               regulator-min-microvolt = <800000>;
-                               regulator-max-microvolt = <1400000>;
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1500000>;
                                regulator-always-on;
                        };
 
                        buck8_reg: BUCK8 {
                                regulator-name = "VIN_MLDO_2V0";
-                               regulator-min-microvolt = <800000>;
-                               regulator-max-microvolt = <2000000>;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <2100000>;
                                regulator-always-on;
                        };
 
                                regulator-name = "PVDD_EMMCF_2V8";
                                regulator-min-microvolt = <2800000>;
                                regulator-max-microvolt = <2800000>;
+                               /*
+                                * Must stay in "off" mode during shutdown for
+                                * proper eMMC reset.  The "off" mode is in
+                                * fact controlled by BUCK10EN.  The eMMC does
+                                * not have reset pin connected so the reset
+                                * will be triggered by falling edge of
+                                * BUCK10EN.
+                                */
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
                };
        };
        samsung,dw-mshc-ddr-timing = <0 2>;
        pinctrl-names = "default";
        pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus1 &sd0_bus4 &sd0_bus8>;
-       vmmc-supply = <&ldo10_reg>;
+       vmmc-supply = <&ldo18_reg>;
        vqmmc-supply = <&ldo3_reg>;
        bus-width = <8>;
        cap-mmc-highspeed;
index 5fb2326..55d4dbf 100644 (file)
         * by exynos5420-cpus.dtsi or exynos5422-cpus.dtsi.
         */
 
-       soc: soc {
-               cluster_a15_opp_table: opp_table0 {
-                       compatible = "operating-points-v2";
-                       opp-shared;
-                       opp-1800000000 {
-                               opp-hz = /bits/ 64 <1800000000>;
-                               opp-microvolt = <1250000>;
-                               clock-latency-ns = <140000>;
-                       };
-                       opp-1700000000 {
-                               opp-hz = /bits/ 64 <1700000000>;
-                               opp-microvolt = <1212500>;
-                               clock-latency-ns = <140000>;
-                       };
-                       opp-1600000000 {
-                               opp-hz = /bits/ 64 <1600000000>;
-                               opp-microvolt = <1175000>;
-                               clock-latency-ns = <140000>;
-                       };
-                       opp-1500000000 {
-                               opp-hz = /bits/ 64 <1500000000>;
-                               opp-microvolt = <1137500>;
-                               clock-latency-ns = <140000>;
-                       };
-                       opp-1400000000 {
-                               opp-hz = /bits/ 64 <1400000000>;
-                               opp-microvolt = <1112500>;
-                               clock-latency-ns = <140000>;
-                       };
-                       opp-1300000000 {
-                               opp-hz = /bits/ 64 <1300000000>;
-                               opp-microvolt = <1062500>;
-                               clock-latency-ns = <140000>;
-                       };
-                       opp-1200000000 {
-                               opp-hz = /bits/ 64 <1200000000>;
-                               opp-microvolt = <1037500>;
-                               clock-latency-ns = <140000>;
-                       };
-                       opp-1100000000 {
-                               opp-hz = /bits/ 64 <1100000000>;
-                               opp-microvolt = <1012500>;
-                               clock-latency-ns = <140000>;
-                       };
-                       opp-1000000000 {
-                               opp-hz = /bits/ 64 <1000000000>;
-                               opp-microvolt = < 987500>;
-                               clock-latency-ns = <140000>;
-                       };
-                       opp-900000000 {
-                               opp-hz = /bits/ 64 <900000000>;
-                               opp-microvolt = < 962500>;
-                               clock-latency-ns = <140000>;
-                       };
-                       opp-800000000 {
-                               opp-hz = /bits/ 64 <800000000>;
-                               opp-microvolt = < 937500>;
-                               clock-latency-ns = <140000>;
-                       };
-                       opp-700000000 {
-                               opp-hz = /bits/ 64 <700000000>;
-                               opp-microvolt = < 912500>;
-                               clock-latency-ns = <140000>;
-                       };
+       cluster_a15_opp_table: opp_table0 {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp-1800000000 {
+                       opp-hz = /bits/ 64 <1800000000>;
+                       opp-microvolt = <1250000>;
+                       clock-latency-ns = <140000>;
+               };
+               opp-1700000000 {
+                       opp-hz = /bits/ 64 <1700000000>;
+                       opp-microvolt = <1212500>;
+                       clock-latency-ns = <140000>;
+               };
+               opp-1600000000 {
+                       opp-hz = /bits/ 64 <1600000000>;
+                       opp-microvolt = <1175000>;
+                       clock-latency-ns = <140000>;
+               };
+               opp-1500000000 {
+                       opp-hz = /bits/ 64 <1500000000>;
+                       opp-microvolt = <1137500>;
+                       clock-latency-ns = <140000>;
+               };
+               opp-1400000000 {
+                       opp-hz = /bits/ 64 <1400000000>;
+                       opp-microvolt = <1112500>;
+                       clock-latency-ns = <140000>;
+               };
+               opp-1300000000 {
+                       opp-hz = /bits/ 64 <1300000000>;
+                       opp-microvolt = <1062500>;
+                       clock-latency-ns = <140000>;
+               };
+               opp-1200000000 {
+                       opp-hz = /bits/ 64 <1200000000>;
+                       opp-microvolt = <1037500>;
+                       clock-latency-ns = <140000>;
+               };
+               opp-1100000000 {
+                       opp-hz = /bits/ 64 <1100000000>;
+                       opp-microvolt = <1012500>;
+                       clock-latency-ns = <140000>;
+               };
+               opp-1000000000 {
+                       opp-hz = /bits/ 64 <1000000000>;
+                       opp-microvolt = < 987500>;
+                       clock-latency-ns = <140000>;
+               };
+               opp-900000000 {
+                       opp-hz = /bits/ 64 <900000000>;
+                       opp-microvolt = < 962500>;
+                       clock-latency-ns = <140000>;
+               };
+               opp-800000000 {
+                       opp-hz = /bits/ 64 <800000000>;
+                       opp-microvolt = < 937500>;
+                       clock-latency-ns = <140000>;
+               };
+               opp-700000000 {
+                       opp-hz = /bits/ 64 <700000000>;
+                       opp-microvolt = < 912500>;
+                       clock-latency-ns = <140000>;
                };
+       };
 
-               cluster_a7_opp_table: opp_table1 {
-                       compatible = "operating-points-v2";
-                       opp-shared;
-                       opp-1300000000 {
-                               opp-hz = /bits/ 64 <1300000000>;
-                               opp-microvolt = <1275000>;
-                               clock-latency-ns = <140000>;
-                       };
-                       opp-1200000000 {
-                               opp-hz = /bits/ 64 <1200000000>;
-                               opp-microvolt = <1212500>;
-                               clock-latency-ns = <140000>;
-                       };
-                       opp-1100000000 {
-                               opp-hz = /bits/ 64 <1100000000>;
-                               opp-microvolt = <1162500>;
-                               clock-latency-ns = <140000>;
-                       };
-                       opp-1000000000 {
-                               opp-hz = /bits/ 64 <1000000000>;
-                               opp-microvolt = <1112500>;
-                               clock-latency-ns = <140000>;
-                       };
-                       opp-900000000 {
-                               opp-hz = /bits/ 64 <900000000>;
-                               opp-microvolt = <1062500>;
-                               clock-latency-ns = <140000>;
-                       };
-                       opp-800000000 {
-                               opp-hz = /bits/ 64 <800000000>;
-                               opp-microvolt = <1025000>;
-                               clock-latency-ns = <140000>;
-                       };
-                       opp-700000000 {
-                               opp-hz = /bits/ 64 <700000000>;
-                               opp-microvolt = <975000>;
-                               clock-latency-ns = <140000>;
-                       };
-                       opp-600000000 {
-                               opp-hz = /bits/ 64 <600000000>;
-                               opp-microvolt = <937500>;
-                               clock-latency-ns = <140000>;
-                       };
+       cluster_a7_opp_table: opp_table1 {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp-1300000000 {
+                       opp-hz = /bits/ 64 <1300000000>;
+                       opp-microvolt = <1275000>;
+                       clock-latency-ns = <140000>;
+               };
+               opp-1200000000 {
+                       opp-hz = /bits/ 64 <1200000000>;
+                       opp-microvolt = <1212500>;
+                       clock-latency-ns = <140000>;
+               };
+               opp-1100000000 {
+                       opp-hz = /bits/ 64 <1100000000>;
+                       opp-microvolt = <1162500>;
+                       clock-latency-ns = <140000>;
+               };
+               opp-1000000000 {
+                       opp-hz = /bits/ 64 <1000000000>;
+                       opp-microvolt = <1112500>;
+                       clock-latency-ns = <140000>;
+               };
+               opp-900000000 {
+                       opp-hz = /bits/ 64 <900000000>;
+                       opp-microvolt = <1062500>;
+                       clock-latency-ns = <140000>;
+               };
+               opp-800000000 {
+                       opp-hz = /bits/ 64 <800000000>;
+                       opp-microvolt = <1025000>;
+                       clock-latency-ns = <140000>;
+               };
+               opp-700000000 {
+                       opp-hz = /bits/ 64 <700000000>;
+                       opp-microvolt = <975000>;
+                       clock-latency-ns = <140000>;
+               };
+               opp-600000000 {
+                       opp-hz = /bits/ 64 <600000000>;
+                       opp-microvolt = <937500>;
+                       clock-latency-ns = <140000>;
                };
+       };
 
+       soc: soc {
                cci: cci@10d20000 {
                        compatible = "arm,cci-400";
                        #address-cells = <1>;
                        status = "disabled";
                };
 
-               adc: adc@12d10000 {
-                       compatible = "samsung,exynos-adc-v2";
-                       reg = <0x12D10000 0x100>;
-                       interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&clock CLK_TSADC>;
-                       clock-names = "adc";
-                       #io-channel-cells = <1>;
-                       io-channel-ranges;
-                       samsung,syscon-phandle = <&pmu_system_controller>;
-                       status = "disabled";
-               };
-
                hsi2c_8: i2c@12e00000 {
                        compatible = "samsung,exynos5250-hsi2c";
                        reg = <0x12E00000 0x1000>;
        };
 };
 
+&adc {
+       clocks = <&clock CLK_TSADC>;
+       clock-names = "adc";
+       samsung,syscon-phandle = <&pmu_system_controller>;
+};
+
 &dp {
        clocks = <&clock CLK_DP1>;
        clock-names = "dp";
index 25d95de..829147e 100644 (file)
                                regulator-name = "vdd_adc";
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <1800000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        ldo5_reg: LDO5 {
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <1800000>;
                                regulator-always-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        ldo6_reg: LDO6 {
                                regulator-min-microvolt = <1000000>;
                                regulator-max-microvolt = <1000000>;
                                regulator-always-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        ldo7_reg: LDO7 {
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <1800000>;
                                regulator-always-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        ldo8_reg: LDO8 {
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <1800000>;
                                regulator-always-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        ldo9_reg: LDO9 {
                                regulator-min-microvolt = <3000000>;
                                regulator-max-microvolt = <3000000>;
                                regulator-always-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        ldo10_reg: LDO10 {
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <1800000>;
                                regulator-always-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        ldo11_reg: LDO11 {
                                regulator-min-microvolt = <1000000>;
                                regulator-max-microvolt = <1000000>;
                                regulator-always-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        ldo12_reg: LDO12 {
                                regulator-name = "vddq_mmc2";
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <2800000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        ldo14_reg: LDO14 {
                                regulator-min-microvolt = <3300000>;
                                regulator-max-microvolt = <3300000>;
                                regulator-always-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        ldo16_reg: LDO16 {
                                regulator-min-microvolt = <3300000>;
                                regulator-max-microvolt = <3300000>;
                                regulator-always-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        ldo18_reg: LDO18 {
                                regulator-name = "vdd_emmc_1V8";
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <1800000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        ldo19_reg: LDO19 {
                                regulator-name = "vdd_sd";
                                regulator-min-microvolt = <2800000>;
                                regulator-max-microvolt = <2800000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        ldo20_reg: LDO20 {
                                regulator-min-microvolt = <1100000>;
                                regulator-max-microvolt = <1100000>;
                                regulator-always-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        ldo24_reg: LDO24 {
                                regulator-name = "vdd_ldo26";
                                regulator-min-microvolt = <800000>;
                                regulator-max-microvolt = <3950000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        ldo27_reg: LDO27 {
                                regulator-min-microvolt = <1000000>;
                                regulator-max-microvolt = <1000000>;
                                regulator-always-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        ldo28_reg: LDO28 {
                                regulator-name = "vdd_ldo28";
                                regulator-min-microvolt = <800000>;
                                regulator-max-microvolt = <3950000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        ldo29_reg: LDO29 {
                                regulator-max-microvolt = <1300000>;
                                regulator-always-on;
                                regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        buck2_reg: BUCK2 {
                                regulator-max-microvolt = <1500000>;
                                regulator-always-on;
                                regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        buck3_reg: BUCK3 {
                                regulator-max-microvolt = <1400000>;
                                regulator-always-on;
                                regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        buck4_reg: BUCK4 {
                                regulator-max-microvolt = <1400000>;
                                regulator-always-on;
                                regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        buck5_reg: BUCK5 {
                                regulator-max-microvolt = <1500000>;
                                regulator-always-on;
                                regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        buck7_reg: BUCK7 {
-                               regulator-name = "vdd_1.0v_ldo";
-                               regulator-min-microvolt = <800000>;
+                               regulator-name = "vdd_1.35v_ldo";
+                               regulator-min-microvolt = <1200000>;
                                regulator-max-microvolt = <1500000>;
                                regulator-always-on;
                                regulator-boot-on;
                        };
 
                        buck8_reg: BUCK8 {
-                               regulator-name = "vdd_1.8v_ldo";
-                               regulator-min-microvolt = <800000>;
-                               regulator-max-microvolt = <2000000>;
+                               regulator-name = "vdd_2.0v_ldo";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <2100000>;
                                regulator-always-on;
                                regulator-boot-on;
                        };
                                regulator-max-microvolt = <3750000>;
                                regulator-always-on;
                                regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        buck10_reg: BUCK10 {
                                regulator-name = "vdd_vmem";
                                regulator-min-microvolt = <2850000>;
                                regulator-max-microvolt = <2850000>;
-                               regulator-always-on;
-                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
                };
        };
index 93a48f2..8388720 100644 (file)
        };
 };
 
+&buck10_reg {
+       /* Supplies vmmc-supply of mmc_0 */
+       regulator-always-on;
+       regulator-boot-on;
+};
+
 &hdmi {
        status = "okay";
        ddc = <&i2c_2>;
index ae866bc..0b27beb 100644 (file)
                        interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
                };
 
+               adc: adc@12d10000 {
+                       compatible = "samsung,exynos-adc-v2";
+                       reg = <0x12d10000 0x100>;
+                       interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
+                       #io-channel-cells = <1>;
+                       io-channel-ranges;
+                       status = "disabled";
+               };
+
                /* i2c_0-3 are defined in exynos5.dtsi */
                hsi2c_4: i2c@12ca0000 {
                        compatible = "samsung,exynos5250-hsi2c";
index 3613f05..bfaa2de 100644 (file)
@@ -64,7 +64,7 @@
                gpio-sck = <&gpio1 5 GPIO_ACTIVE_HIGH>;
                gpio-miso = <&gpio1 8 GPIO_ACTIVE_HIGH>;
                gpio-mosi = <&gpio1 7 GPIO_ACTIVE_HIGH>;
-               cs-gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>;
+               cs-gpios = <&gpio0 20 GPIO_ACTIVE_LOW>;
                num-chipselects = <1>;
 
                panel: display@0 {
index bf0cb55..4263a93 100644 (file)
                /* non-configurable replicators don't show up on the
                 * AMBA bus.  As such no need to add "arm,primecell".
                 */
-               compatible = "arm,coresight-replicator";
+               compatible = "arm,coresight-static-replicator";
 
                out-ports {
                        #address-cells = <1>;
                /* non-configurable replicators don't show up on the
                 * AMBA bus.  As such no need to add "arm,primecell".
                 */
-               compatible = "arm,coresight-replicator";
+               compatible = "arm,coresight-static-replicator";
 
                out-ports {
                        #address-cells = <1>;
                /* non-configurable replicators don't show up on the
                 * AMBA bus.  As such no need to add "arm,primecell".
                 */
-               compatible = "arm,coresight-replicator";
+               compatible = "arm,coresight-static-replicator";
 
                out-ports {
                        #address-cells = <1>;
                /* non-configurable replicators don't show up on the
                 * AMBA bus.  As such no need to add "arm,primecell".
                 */
-               compatible = "arm,coresight-replicator";
+               compatible = "arm,coresight-static-replicator";
 
                out-ports {
                        #address-cells = <1>;
        };
 
        funnel@0,e3c41000 {
-               compatible = "arm,coresight-funnel", "arm,primecell";
+               compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                reg = <0 0xe3c41000 0 0x1000>;
 
                clocks = <&clk_375m>;
        };
 
        funnel@0,e3c81000 {
-               compatible = "arm,coresight-funnel", "arm,primecell";
+               compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                reg = <0 0xe3c81000 0 0x1000>;
 
                clocks = <&clk_375m>;
        };
 
        funnel@0,e3cc1000 {
-               compatible = "arm,coresight-funnel", "arm,primecell";
+               compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                reg = <0 0xe3cc1000 0 0x1000>;
 
                clocks = <&clk_375m>;
        };
 
        funnel@0,e3d01000 {
-               compatible = "arm,coresight-funnel", "arm,primecell";
+               compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                reg = <0 0xe3d01000 0 0x1000>;
 
                clocks = <&clk_375m>;
        };
 
        funnel@0,e3c04000 {
-               compatible = "arm,coresight-funnel", "arm,primecell";
+               compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                reg = <0 0xe3c04000 0 0x1000>;
 
                clocks = <&clk_375m>;
diff --git a/arch/arm/boot/dts/ibm-power9-dual.dtsi b/arch/arm/boot/dts/ibm-power9-dual.dtsi
new file mode 100644 (file)
index 0000000..2abc42e
--- /dev/null
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright 2018 IBM Corp
+
+&fsi {
+       cfam@0,0 {
+               reg = <0 0>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               chip-id = <0>;
+
+               scom@1000 {
+                       compatible = "ibm,fsi2pib";
+                       reg = <0x1000 0x400>;
+               };
+
+               i2c@1800 {
+                       compatible = "ibm,fsi-i2c-master";
+                       reg = <0x1800 0x400>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       cfam0_i2c0: i2c-bus@0 {
+                               reg = <0>;
+                       };
+
+                       cfam0_i2c1: i2c-bus@1 {
+                               reg = <1>;
+                       };
+
+                       cfam0_i2c2: i2c-bus@2 {
+                               reg = <2>;
+                       };
+
+                       cfam0_i2c3: i2c-bus@3 {
+                               reg = <3>;
+                       };
+
+                       cfam0_i2c4: i2c-bus@4 {
+                               reg = <4>;
+                       };
+
+                       cfam0_i2c5: i2c-bus@5 {
+                               reg = <5>;
+                       };
+
+                       cfam0_i2c6: i2c-bus@6 {
+                               reg = <6>;
+                       };
+
+                       cfam0_i2c7: i2c-bus@7 {
+                               reg = <7>;
+                       };
+
+                       cfam0_i2c8: i2c-bus@8 {
+                               reg = <8>;
+                       };
+
+                       cfam0_i2c9: i2c-bus@9 {
+                               reg = <9>;
+                       };
+
+                       cfam0_i2c10: i2c-bus@a {
+                               reg = <10>;
+                       };
+
+                       cfam0_i2c11: i2c-bus@b {
+                               reg = <11>;
+                       };
+
+                       cfam0_i2c12: i2c-bus@c {
+                               reg = <12>;
+                       };
+
+                       cfam0_i2c13: i2c-bus@d {
+                               reg = <13>;
+                       };
+
+                       cfam0_i2c14: i2c-bus@e {
+                               reg = <14>;
+                       };
+               };
+
+               sbefifo@2400 {
+                       compatible = "ibm,p9-sbefifo";
+                       reg = <0x2400 0x400>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       fsi_occ0: occ {
+                               compatible = "ibm,p9-occ";
+                       };
+               };
+
+               fsi_hub0: hub@3400 {
+                       compatible = "fsi-master-hub";
+                       reg = <0x3400 0x400>;
+                       #address-cells = <2>;
+                       #size-cells = <0>;
+
+                       no-scan-on-init;
+               };
+       };
+};
+
+&fsi_hub0 {
+       cfam@1,0 {
+               reg = <1 0>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               chip-id = <1>;
+
+               scom@1000 {
+                       compatible = "ibm,fsi2pib";
+                       reg = <0x1000 0x400>;
+               };
+
+               i2c@1800 {
+                       compatible = "ibm,fsi-i2c-master";
+                       reg = <0x1800 0x400>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       cfam1_i2c0: i2c-bus@0 {
+                               reg = <0>;
+                       };
+
+                       cfam1_i2c1: i2c-bus@1 {
+                               reg = <1>;
+                       };
+
+                       cfam1_i2c2: i2c-bus@2 {
+                               reg = <2>;
+                       };
+
+                       cfam1_i2c3: i2c-bus@3 {
+                               reg = <3>;
+                       };
+
+                       cfam1_i2c4: i2c-bus@4 {
+                               reg = <4>;
+                       };
+
+                       cfam1_i2c5: i2c-bus@5 {
+                               reg = <5>;
+                       };
+
+                       cfam1_i2c6: i2c-bus@6 {
+                               reg = <6>;
+                       };
+
+                       cfam1_i2c7: i2c-bus@7 {
+                               reg = <7>;
+                       };
+
+                       cfam1_i2c8: i2c-bus@8 {
+                               reg = <8>;
+                       };
+
+                       cfam1_i2c9: i2c-bus@9 {
+                               reg = <9>;
+                       };
+
+                       cfam1_i2c10: i2c-bus@a {
+                               reg = <10>;
+                       };
+
+                       cfam1_i2c11: i2c-bus@b {
+                               reg = <11>;
+                       };
+
+                       cfam1_i2c12: i2c-bus@c {
+                               reg = <12>;
+                       };
+
+                       cfam1_i2c13: i2c-bus@d {
+                               reg = <13>;
+                       };
+
+                       cfam1_i2c14: i2c-bus@e {
+                               reg = <14>;
+                       };
+               };
+
+               sbefifo@2400 {
+                       compatible = "ibm,p9-sbefifo";
+                       reg = <0x2400 0x400>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       fsi_occ1: occ {
+                               compatible = "ibm,p9-occ";
+                       };
+               };
+
+               fsi_hub1: hub@3400 {
+                       compatible = "fsi-master-hub";
+                       reg = <0x3400 0x400>;
+                       #address-cells = <2>;
+                       #size-cells = <0>;
+
+                       no-scan-on-init;
+               };
+       };
+};
+
+/* Legacy OCC numbering (to get rid of when userspace is fixed) */
+&fsi_occ0 {
+       reg = <1>;
+};
+
+&fsi_occ1 {
+       reg = <2>;
+};
+
+/ {
+       aliases {
+               i2c100 = &cfam0_i2c0;
+               i2c101 = &cfam0_i2c1;
+               i2c102 = &cfam0_i2c2;
+               i2c103 = &cfam0_i2c3;
+               i2c104 = &cfam0_i2c4;
+               i2c105 = &cfam0_i2c5;
+               i2c106 = &cfam0_i2c6;
+               i2c107 = &cfam0_i2c7;
+               i2c108 = &cfam0_i2c8;
+               i2c109 = &cfam0_i2c9;
+               i2c110 = &cfam0_i2c10;
+               i2c111 = &cfam0_i2c11;
+               i2c112 = &cfam0_i2c12;
+               i2c113 = &cfam0_i2c13;
+               i2c114 = &cfam0_i2c14;
+               i2c200 = &cfam1_i2c0;
+               i2c201 = &cfam1_i2c1;
+               i2c202 = &cfam1_i2c2;
+               i2c203 = &cfam1_i2c3;
+               i2c204 = &cfam1_i2c4;
+               i2c205 = &cfam1_i2c5;
+               i2c206 = &cfam1_i2c6;
+               i2c207 = &cfam1_i2c7;
+               i2c208 = &cfam1_i2c8;
+               i2c209 = &cfam1_i2c9;
+               i2c210 = &cfam1_i2c10;
+               i2c211 = &cfam1_i2c11;
+               i2c212 = &cfam1_i2c12;
+               i2c213 = &cfam1_i2c13;
+               i2c214 = &cfam1_i2c14;
+       };
+};
index f0a3fde..10acc53 100644 (file)
        model = "MENLO M53 EMBEDDED DEVICE";
        compatible = "menlo,m53menlo", "fsl,imx53";
 
+       gpio-keys {
+               compatible = "gpio-keys";
+               pinctrl-0 = <&pinctrl_power_button>;
+               pinctrl-names = "default";
+
+               power-button {
+                       label = "Power button";
+                       gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_POWER>;
+               };
+       };
+
+       gpio-poweroff {
+               compatible = "gpio-poweroff";
+               pinctrl-0 = <&pinctrl_power_out>;
+               pinctrl-names = "default";
+               gpios = <&gpio1 13 GPIO_ACTIVE_LOW>;
+       };
+
        leds {
                compatible = "gpio-leds";
                pinctrl-names = "default";
@@ -30,7 +49,7 @@
                eth {
                        label = "EthLedYe";
                        gpios = <&gpio2 11 GPIO_ACTIVE_LOW>;
-                       linux,default-trigger = "none";
+                       linux,default-trigger = "netdev";
                };
        };
 
                };
        };
 
+       beeper {
+               compatible = "gpio-beeper";
+               pinctrl-0 = <&pinctrl_beeper>;
+               gpios = <&gpio6 3 GPIO_ACTIVE_HIGH>;
+       };
+
        reg_usbh1_vbus: regulator-usbh1-vbus {
                compatible = "regulator-fixed";
                regulator-name = "vbus";
                regulator-min-microvolt = <5000000>;
                regulator-max-microvolt = <5000000>;
-               gpio = <&gpio1 2 GPIO_ACTIVE_LOW>;
+               gpio = <&gpio1 2 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
        };
 };
 
        assigned-clock-rates = <133333334>, <33333334>, <33333334>;
 };
 
+&ecspi2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi2>;
+       cs-gpios = <&gpio2 26 GPIO_ACTIVE_HIGH>, <&gpio2 27 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+
+       spidev@0 {
+               compatible = "menlo,m53cpld";
+               spi-max-frequency = <25000000>;
+               reg = <0>;
+       };
+
+       spidev@1 {
+               compatible = "menlo,m53cpld";
+               spi-max-frequency = <25000000>;
+               reg = <1>;
+       };
+};
+
 &esdhc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_esdhc1>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_fec>;
        phy-mode = "rmii";
+       phy-reset-gpios = <&gpio7 7 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
 
+&gpio1 {
+       gpio-line-names =
+               "", "", "", "",
+               "", "", "", "",
+               "", "", "", "",
+               "", "", "", "",
+               "", "", "", "",
+               "", "", "", "",
+               "", "", "", "",
+               "", "", "", "";
+};
+
+&gpio2 {
+       gpio-line-names =
+               "", "", "", "",
+               "", "", "", "",
+               "TestPin_SV2_3", "", "", "",
+               "", "", "", "",
+               "", "", "", "",
+               "", "", "", "",
+               "", "", "", "",
+               "", "", "", "";
+};
+
+&gpio3 {
+       gpio-line-names =
+               "", "", "", "",
+               "", "", "", "",
+               "", "", "", "",
+               "", "", "", "",
+               "", "", "", "",
+               "", "", "", "",
+               "CPLD_JTAG_TDI", "CPLD_JTAG_TMS", "", "",
+               "", "CPLD_JTAG_TDO", "", "";
+};
+
+&gpio5 {
+       gpio-line-names =
+               "", "", "", "",
+               "", "", "", "",
+               "", "", "", "",
+               "", "", "", "",
+               "", "", "CPLD_JTAG_TCK", "KBD_intK",
+               "CPLD_int", "CPLD_JTAG_internal", "CPLD_D[0]", "CPLD_D[1]",
+               "CPLD_D[2]", "CPLD_D[3]", "CPLD_D[4]", "CPLD_D[5]",
+               "CPLD_D[6]", "CPLD_D[7]", "DISP_reset", "KBD_intI";
+};
+
+&gpio6 {
+       gpio-line-names =
+               "", "", "", "",
+               "CPLD_reset", "", "", "",
+               "", "", "", "",
+               "", "", "", "",
+               "", "", "", "",
+               "", "", "", "",
+               "", "", "", "",
+               "", "", "", "";
+};
+
+&gpio7 {
+       gpio-line-names =
+               "", "", "", "",
+               "", "", "", "",
+               "", "", "", "",
+               "", "USB-OTG_OverCurrent", "", "",
+               "", "", "", "",
+               "", "", "", "",
+               "", "", "", "",
+               "", "", "", "";
+};
+
 &i2c1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_i2c1>;
        imx53-m53evk {
                hoggrp {
                        fsl,pins = <
-                               MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK       0x1c4
-                               MX53_PAD_EIM_EB3__GPIO2_31              0x1d5
-                               MX53_PAD_PATA_DA_0__GPIO7_6             0x1d5
-                               MX53_PAD_GPIO_19__CCM_CLKO              0x1d5
-                               MX53_PAD_CSI0_MCLK__CCM_CSI0_MCLK       0x1d5
-                               MX53_PAD_CSI0_DAT4__GPIO5_22            0x1d5
-                               MX53_PAD_CSI0_DAT5__GPIO5_23            0x1d5
-                               MX53_PAD_CSI0_DAT6__GPIO5_24            0x1d5
-                               MX53_PAD_CSI0_DAT7__GPIO5_25            0x1d5
-                               MX53_PAD_CSI0_DAT8__GPIO5_26            0x1d5
-                               MX53_PAD_CSI0_DAT9__GPIO5_27            0x1d5
-                               MX53_PAD_CSI0_DAT10__GPIO5_28           0x1d5
-                               MX53_PAD_CSI0_DAT11__GPIO5_29           0x1d5
-                               MX53_PAD_CSI0_DAT14__GPIO6_0            0x1d5
+                               MX53_PAD_GPIO_19__CCM_CLKO              0x1e4
+                               MX53_PAD_CSI0_DATA_EN__GPIO5_20         0x1e4
+                               MX53_PAD_CSI0_DAT4__GPIO5_22            0x1e4
+                               MX53_PAD_CSI0_DAT5__GPIO5_23            0x1c4
+                               MX53_PAD_CSI0_DAT6__GPIO5_24            0x1e4
+                               MX53_PAD_CSI0_DAT7__GPIO5_25            0x1e4
+                               MX53_PAD_CSI0_DAT8__GPIO5_26            0x1e4
+                               MX53_PAD_CSI0_DAT9__GPIO5_27            0x1c4
+                               MX53_PAD_CSI0_DAT10__GPIO5_28           0x1e4
+                               MX53_PAD_CSI0_DAT11__GPIO5_29           0x1e4
+                               MX53_PAD_PATA_DATA11__GPIO2_11          0x1e4
+                               MX53_PAD_EIM_D24__GPIO3_24              0x1e4
+                               MX53_PAD_EIM_D25__GPIO3_25              0x1e4
+                               MX53_PAD_EIM_D29__GPIO3_29              0x1e4
+                               MX53_PAD_CSI0_PIXCLK__GPIO5_18          0x1e4
+                               MX53_PAD_CSI0_VSYNC__GPIO5_21           0x1e4
+                               MX53_PAD_CSI0_DAT18__GPIO6_4            0x1c4
+                               MX53_PAD_PATA_DATA8__GPIO2_8            0x1e4
                        >;
                };
 
                pinctrl_led: ledgrp {
                        fsl,pins = <
-                               MX53_PAD_CSI0_DAT15__GPIO6_1            0x1d5
-                               MX53_PAD_CSI0_DAT16__GPIO6_2            0x1d5
+                               MX53_PAD_CSI0_DAT15__GPIO6_1            0x1c4
+                               MX53_PAD_CSI0_DAT16__GPIO6_2            0x1c4
+                       >;
+               };
+
+               pinctrl_beeper: beepergrp {
+                       fsl,pins = <
+                               MX53_PAD_CSI0_DAT17__GPIO6_3            0x1c4
                        >;
                };
 
 
                pinctrl_can2: can2grp {
                        fsl,pins = <
-                               MX53_PAD_KEY_COL4__CAN2_TXCAN           0x1c4
+                               MX53_PAD_KEY_COL4__CAN2_TXCAN           0x1e4
                                MX53_PAD_KEY_ROW4__CAN2_RXCAN           0x1c4
                        >;
                };
 
                pinctrl_display_gpio: display-gpiogrp {
                        fsl,pins = <
-                               MX53_PAD_CSI0_DAT12__GPIO5_30           0x1d5 /* Reset */
-                               MX53_PAD_CSI0_DAT13__GPIO5_31           0x1d5 /* Interrupt */
+                               MX53_PAD_CSI0_DAT12__GPIO5_30           0x1c4 /* Reset */
+                               MX53_PAD_CSI0_MCLK__GPIO5_19            0x1e4 /* Int-K */
+                               MX53_PAD_CSI0_DAT13__GPIO5_31           0x1c4 /* Int-I */
+
+                               MX53_PAD_CSI0_DAT14__GPIO6_0            0x1c4 /* Power down */
                        >;
                };
 
                pinctrl_edt_ft5x06: edt-ft5x06grp {
                        fsl,pins = <
-                               MX53_PAD_PATA_DATA9__GPIO2_9            0x1d5 /* Reset */
-                               MX53_PAD_CSI0_DAT19__GPIO6_5            0x1d5 /* Interrupt */
-                               MX53_PAD_PATA_DATA10__GPIO2_10          0x1d5 /* Wake */
+                               MX53_PAD_PATA_DATA9__GPIO2_9            0x1e4 /* Reset */
+                               MX53_PAD_CSI0_DAT19__GPIO6_5            0x1c4 /* Interrupt */
+                               MX53_PAD_PATA_DATA10__GPIO2_10          0x1e4 /* Wake */
+                       >;
+               };
+
+               pinctrl_ecspi2: ecspi2grp {
+                       fsl,pins = <
+                               MX53_PAD_EIM_CS0__ECSPI2_SCLK           0xe4
+                               MX53_PAD_EIM_OE__ECSPI2_MISO            0xe4
+                               MX53_PAD_EIM_CS1__ECSPI2_MOSI           0xe4
+                               MX53_PAD_EIM_RW__GPIO2_26               0xe4
+                               MX53_PAD_EIM_LBA__GPIO2_27              0xe4
                        >;
                };
 
                pinctrl_esdhc1: esdhc1grp {
                        fsl,pins = <
-                               MX53_PAD_SD1_DATA0__ESDHC1_DAT0         0x1d5
-                               MX53_PAD_SD1_DATA1__ESDHC1_DAT1         0x1d5
-                               MX53_PAD_SD1_DATA2__ESDHC1_DAT2         0x1d5
-                               MX53_PAD_SD1_DATA3__ESDHC1_DAT3         0x1d5
-                               MX53_PAD_SD1_CMD__ESDHC1_CMD            0x1d5
-                               MX53_PAD_SD1_CLK__ESDHC1_CLK            0x1d5
+                               MX53_PAD_SD1_DATA0__ESDHC1_DAT0         0x1e4
+                               MX53_PAD_SD1_DATA1__ESDHC1_DAT1         0x1e4
+                               MX53_PAD_SD1_DATA2__ESDHC1_DAT2         0x1e4
+                               MX53_PAD_SD1_DATA3__ESDHC1_DAT3         0x1e4
+                               MX53_PAD_SD1_CMD__ESDHC1_CMD            0x1e4
+                               MX53_PAD_SD1_CLK__ESDHC1_CLK            0x1e4
+                               MX53_PAD_GPIO_1__GPIO1_1                0x1c4
+                               MX53_PAD_GPIO_9__GPIO1_9                0x1e4
                        >;
                };
 
                pinctrl_fec: fecgrp {
                        fsl,pins = <
-                               MX53_PAD_FEC_MDC__FEC_MDC               0x4
-                               MX53_PAD_FEC_MDIO__FEC_MDIO             0x1fc
-                               MX53_PAD_FEC_REF_CLK__FEC_TX_CLK        0x180
-                               MX53_PAD_FEC_RX_ER__FEC_RX_ER           0x180
-                               MX53_PAD_FEC_CRS_DV__FEC_RX_DV          0x180
-                               MX53_PAD_FEC_RXD1__FEC_RDATA_1          0x180
-                               MX53_PAD_FEC_RXD0__FEC_RDATA_0          0x180
-                               MX53_PAD_FEC_TX_EN__FEC_TX_EN           0x4
-                               MX53_PAD_FEC_TXD1__FEC_TDATA_1          0x4
-                               MX53_PAD_FEC_TXD0__FEC_TDATA_0          0x4
+                               MX53_PAD_FEC_MDC__FEC_MDC               0x1e4
+                               MX53_PAD_FEC_MDIO__FEC_MDIO             0x1e4
+                               MX53_PAD_FEC_REF_CLK__FEC_TX_CLK        0x1e4
+                               MX53_PAD_FEC_RX_ER__FEC_RX_ER           0x1e4
+                               MX53_PAD_FEC_CRS_DV__FEC_RX_DV          0x1e4
+                               MX53_PAD_FEC_RXD1__FEC_RDATA_1          0x1e4
+                               MX53_PAD_FEC_RXD0__FEC_RDATA_0          0x1e4
+                               MX53_PAD_FEC_TX_EN__FEC_TX_EN           0x1c4
+                               MX53_PAD_FEC_TXD1__FEC_TDATA_1          0x1e4
+                               MX53_PAD_FEC_TXD0__FEC_TDATA_0          0x1e4
+                               MX53_PAD_PATA_DA_1__GPIO7_7             0x1e4
+                               MX53_PAD_EIM_EB3__GPIO2_31              0x1e4
                        >;
                };
 
                        >;
                };
 
+               pinctrl_power_button: powerbutgrp {
+                       fsl,pins = <
+                               MX53_PAD_SD2_DATA2__GPIO1_13            0x1e4
+                       >;
+               };
+
+               pinctrl_power_out: poweroutgrp {
+                       fsl,pins = <
+                               MX53_PAD_SD2_DATA0__GPIO1_15            0x1e4
+                       >;
+               };
+
                pinctrl_uart1: uart1grp {
                        fsl,pins = <
                                MX53_PAD_PATA_DIOW__UART1_TXD_MUX       0x1e4
                                MX53_PAD_PATA_DMACK__UART1_RXD_MUX      0x1e4
+                               MX53_PAD_PATA_IORDY__UART1_RTS          0x1e4
+                               MX53_PAD_PATA_RESET_B__UART1_CTS        0x1e4
                        >;
                };
 
                        fsl,pins = <
                                MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX  0x1e4
                                MX53_PAD_PATA_DMARQ__UART2_TXD_MUX      0x1e4
+                               MX53_PAD_PATA_DIOR__UART2_RTS           0x1e4
+                               MX53_PAD_PATA_INTRQ__UART2_CTS          0x1e4
+                       >;
+               };
+
+               pinctrl_uart3: uart3grp {
+                       fsl,pins = <
+                               MX53_PAD_PATA_CS_1__UART3_RXD_MUX       0x1e4
+                               MX53_PAD_PATA_CS_0__UART3_TXD_MUX       0x1e4
+                               MX53_PAD_PATA_DA_2__UART3_RTS           0x1e4
                        >;
                };
 
                pinctrl_usb: usbgrp {
                        fsl,pins = <
-                               MX53_PAD_GPIO_2__GPIO1_2                0x1d5
-                               MX53_PAD_GPIO_3__USBOH3_USBH1_OC        0x1d5
+                               MX53_PAD_GPIO_2__GPIO1_2                0x1c4
+                               MX53_PAD_GPIO_3__USBOH3_USBH1_OC        0x1c4
+                               MX53_PAD_GPIO_4__GPIO1_4                0x1c4
+                               MX53_PAD_GPIO_18__GPIO7_13              0x1c4
                        >;
                };
        };
 &uart1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart1>;
+       uart-has-rtscts;
        status = "okay";
 };
 
 &uart2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart2>;
+       uart-has-rtscts;
+       status = "okay";
+};
+
+&uart3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart3>;
+       linux,rs485-enabled-at-boot-time;
        status = "okay";
 };
 
        pinctrl-0 = <&pinctrl_usb>;
        vbus-supply = <&reg_usbh1_vbus>;
        phy_type = "utmi";
-       dr_mode = "peripheral";
+       dr_mode = "host";
        status = "okay";
 };
 
index 09071ca..ec9fb89 100644 (file)
                        >;
                };
 
+               pinctrl_ipu_csi0: ipucsi0grp {
+                       fsl,pins = <
+                               MX53_PAD_CSI0_DAT12__IPU_CSI0_D_12    0x1c4
+                               MX53_PAD_CSI0_DAT13__IPU_CSI0_D_13    0x1c4
+                               MX53_PAD_CSI0_DAT14__IPU_CSI0_D_14    0x1c4
+                               MX53_PAD_CSI0_DAT15__IPU_CSI0_D_15    0x1c4
+                               MX53_PAD_CSI0_DAT16__IPU_CSI0_D_16    0x1c4
+                               MX53_PAD_CSI0_DAT17__IPU_CSI0_D_17    0x1c4
+                               MX53_PAD_CSI0_DAT18__IPU_CSI0_D_18    0x1c4
+                               MX53_PAD_CSI0_DAT19__IPU_CSI0_D_19    0x1c4
+                               MX53_PAD_CSI0_PIXCLK__IPU_CSI0_PIXCLK 0x1e4
+                               MX53_PAD_CSI0_VSYNC__IPU_CSI0_VSYNC   0x1e4
+                               MX53_PAD_CSI0_MCLK__IPU_CSI0_HSYNC    0x1e4
+                               MX53_PAD_CSI0_DATA_EN__IPU_CSI0_DATA_EN 0x1e4
+                       >;
+               };
+
+               pinctrl_ov5642: ov5642grp {
+                       fsl,pins = <
+                               MX53_PAD_NANDF_WP_B__GPIO6_9   0x1e4
+                               MX53_PAD_NANDF_RB0__GPIO6_10   0x1e4
+                               MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK 0x1c4
+                       >;
+               };
+
                pinctrl_uart1: uart1grp {
                        fsl,pins = <
                                MX53_PAD_CSI0_DAT10__UART1_TXD_MUX      0x1e4
        camera: ov5642@3c {
                compatible = "ovti,ov5642";
                reg = <0x3c>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_ov5642>;
+               assigned-clocks = <&clks IMX5_CLK_SSI_EXT1_SEL>,
+                                 <&clks IMX5_CLK_SSI_EXT1_COM_SEL>;
+               assigned-clock-parents = <&clks IMX5_CLK_PLL2_SW>,
+                                        <&clks IMX5_CLK_SSI_EXT1_PODF>;
+               assigned-clock-rates = <0>, <24000000>;
+               clocks = <&clks IMX5_CLK_SSI_EXT1_GATE>;
+               clock-names = "xclk";
+               DVDD-supply = <&ldo9_reg>;
+               AVDD-supply = <&ldo7_reg>;
+               reset-gpios = <&gpio6 9 GPIO_ACTIVE_LOW>;
+               powerdown-gpios = <&gpio6 10 GPIO_ACTIVE_HIGH>;
+
+               port {
+                       ov5642_to_ipu_csi0: endpoint {
+                               remote-endpoint = <&ipu_csi0_from_parallel_sensor>;
+                               bus-width = <8>;
+                               hsync-active = <1>;
+                               vsync-active = <1>;
+                       };
+               };
        };
 
        pmic: dialog@48 {
                compatible = "dlg,da9053", "dlg,da9052";
                reg = <0x48>;
+               interrupt-parent = <&gpio7>;
+               interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+
+               regulators {
+                       ldo7_reg: ldo7 {
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3600000>;
+                       };
+
+                       ldo9_reg: ldo9 {
+                               regulator-min-microvolt = <1250000>;
+                               regulator-max-microvolt = <3650000>;
+                       };
+               };
        };
 };
 
        phy-reset-gpios = <&gpio7 6 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
+
+&ipu_csi0_from_parallel_sensor {
+       remote-endpoint = <&ov5642_to_ipu_csi0>;
+       data-shift = <12>; /* Lines 19:12 used */
+       hsync-active = <1>;
+       vsync-active = <1>;
+};
+
+&ipu_csi0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ipu_csi0>;
+};
index 9b672ed..ed341cf 100644 (file)
@@ -31,6 +31,7 @@
                i2c0 = &i2c1;
                i2c1 = &i2c2;
                i2c2 = &i2c3;
+               ipu0 = &ipu;
                mmc0 = &esdhc1;
                mmc1 = &esdhc2;
                mmc2 = &esdhc3;
                ports = <&ipu_di0>, <&ipu_di1>;
        };
 
+       capture_subsystem {
+               compatible = "fsl,imx-capture-subsystem";
+               ports = <&ipu_csi0>, <&ipu_csi1>;
+       };
+
        tzic: tz-interrupt-controller@fffc000 {
                compatible = "fsl,imx53-tzic", "fsl,tzic";
                interrupt-controller;
 
                        ipu_csi0: port@0 {
                                reg = <0>;
+
+                               ipu_csi0_from_parallel_sensor: endpoint {
+                               };
                        };
 
                        ipu_csi1: port@1 {
                                reg = <1>;
+
+                               ipu_csi1_from_parallel_sensor: endpoint {
+                               };
                        };
 
                        ipu_di0: port@2 {
diff --git a/arch/arm/boot/dts/imx6dl-kontron-samx6i.dtsi b/arch/arm/boot/dts/imx6dl-kontron-samx6i.dtsi
new file mode 100644 (file)
index 0000000..a864fdb
--- /dev/null
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0 OR X11
+/*
+ * Copyright 2019 (C) Pengutronix, Marco Felsch <kernel@pengutronix.de>
+ */
+
+#include "imx6dl.dtsi"
+#include "imx6qdl-kontron-samx6i.dtsi"
+
+/ {
+       model = "Kontron SMARC sAMX6i Dual-Lite/Solo";
+       compatible = "kontron,imx6dl-samx6i", "fsl,imx6dl";
+};
diff --git a/arch/arm/boot/dts/imx6q-kontron-samx6i.dtsi b/arch/arm/boot/dts/imx6q-kontron-samx6i.dtsi
new file mode 100644 (file)
index 0000000..2618ecc
--- /dev/null
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0 OR X11
+/*
+ * Copyright 2019 (C) Pengutronix, Marco Felsch <kernel@pengutronix.de>
+ */
+
+#include "imx6q.dtsi"
+#include "imx6qdl-kontron-samx6i.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+       model = "Kontron SMARC sAMX6i Quad/Dual";
+       compatible = "kontron,imx6q-samx6i", "fsl,imx6q";
+};
+
+/* Quad/Dual SoMs have 3 chip-select signals */
+&ecspi4 {
+       fsl,spi-num-chipselects = <3>;
+       cs-gpios = <&gpio3 24 GPIO_ACTIVE_HIGH>,
+                  <&gpio3 29 GPIO_ACTIVE_HIGH>,
+                  <&gpio3 25 GPIO_ACTIVE_HIGH>;
+};
+
+&pinctrl_ecspi4 {
+       fsl,pins = <
+               MX6QDL_PAD_EIM_D21__ECSPI4_SCLK 0x100b1
+               MX6QDL_PAD_EIM_D28__ECSPI4_MOSI 0x100b1
+               MX6QDL_PAD_EIM_D22__ECSPI4_MISO 0x100b1
+
+               /* SPI4_IMX_CS2# - connected to internal flash */
+               MX6QDL_PAD_EIM_D24__GPIO3_IO24 0x1b0b0
+               /* SPI4_IMX_CS0# - connected to SMARC SPI0_CS0# */
+               MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x1b0b0
+               /* SPI4_CS3# - connected to  SMARC SPI0_CS1# */
+               MX6QDL_PAD_EIM_D25__GPIO3_IO25 0x1b0b0
+       >;
+};
diff --git a/arch/arm/boot/dts/imx6qdl-kontron-samx6i.dtsi b/arch/arm/boot/dts/imx6qdl-kontron-samx6i.dtsi
new file mode 100644 (file)
index 0000000..81c7ebb
--- /dev/null
@@ -0,0 +1,815 @@
+// SPDX-License-Identifier: GPL-2.0 OR X11
+/*
+ * Copyright 2017 (C) Priit Laes <plaes@plaes.org>
+ * Copyright 2018 (C) Pengutronix, Michael Grzeschik <mgr@pengutronix.de>
+ * Copyright 2019 (C) Pengutronix, Marco Felsch <kernel@pengutronix.de>
+ *
+ * Based on initial work by Nikita Yushchenko <nyushchenko at dev.rtsoft.ru>
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/sound/fsl-imx-audmux.h>
+
+/ {
+       reg_1p0v_s0: regulator-1p0v-s0 {
+               compatible = "regulator-fixed";
+               regulator-name = "V_1V0_S0";
+               regulator-min-microvolt = <1000000>;
+               regulator-max-microvolt = <1000000>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&reg_smarc_suppy>;
+       };
+
+       reg_1p35v_vcoredig_s5: regulator-1p35v-vcoredig-s5 {
+               compatible = "regulator-fixed";
+               regulator-name = "V_1V35_VCOREDIG_S5";
+               regulator-min-microvolt = <1350000>;
+               regulator-max-microvolt = <1350000>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&reg_3p3v_s5>;
+       };
+
+       reg_1p8v_s5: regulator-1p8v-s5 {
+               compatible = "regulator-fixed";
+               regulator-name = "V_1V8_S5";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&reg_3p3v_s5>;
+       };
+
+       reg_3p3v_s0: regulator-3p3v-s0 {
+               compatible = "regulator-fixed";
+               regulator-name = "V_3V3_S0";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&reg_3p3v_s5>;
+       };
+
+       reg_3p3v_s0: regulator-3p3v-s0 {
+               compatible = "regulator-fixed";
+               regulator-name = "V_3V3_S0";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&reg_3p3v_s5>;
+       };
+
+       reg_3p3v_s5: regulator-3p3v-s5 {
+               compatible = "regulator-fixed";
+               regulator-name = "V_3V3_S5";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&reg_smarc_suppy>;
+       };
+
+       reg_smarc_lcdbklt: regulator-smarc-lcdbklt {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_lcdbklt_en>;
+               regulator-name = "LCD_BKLT_EN";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               gpio = <&gpio1 16 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       reg_smarc_lcdvdd: regulator-smarc-lcdvdd {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_lcdvdd_en>;
+               regulator-name = "LCD_VDD_EN";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               gpio = <&gpio1 17 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       reg_smarc_rtc: regulator-smarc-rtc {
+               compatible = "regulator-fixed";
+               regulator-name = "V_IN_RTC_BATT";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+               regulator-boot-on;
+       };
+
+       /* Module supply range can be 3.00V ... 5.25V */
+       reg_smarc_suppy: regulator-smarc-supply {
+               compatible = "regulator-fixed";
+               regulator-name = "V_IN_WIDE";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-always-on;
+               regulator-boot-on;
+       };
+
+       lcd: lcd {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "fsl,imx-parallel-display";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_lcd>;
+               status = "disabled";
+
+               port@0 {
+                       reg = <0>;
+
+                       lcd_in: endpoint {
+                       };
+               };
+
+               port@1 {
+                       reg = <1>;
+
+                       lcd_out: endpoint {
+                       };
+               };
+       };
+
+       lcd_backlight: lcd-backlight {
+               compatible = "pwm-backlight";
+               pwms = <&pwm4 0 5000000>;
+               pwm-names = "LCD_BKLT_PWM";
+
+               brightness-levels = <0 10 20 30 40 50 60 70 80 90 100>;
+               default-brightness-level = <4>;
+
+               power-supply = <&reg_smarc_lcdbklt>;
+               status = "disabled";
+       };
+
+       i2c_intern: i2c-gpio-intern {
+               compatible = "i2c-gpio";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_i2c_gpio_intern>;
+               sda-gpios = <&gpio1 28 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+               scl-gpios = <&gpio1 30 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+               i2c-gpio,delay-us = <2>; /* ~100 kHz */
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
+       i2c_lcd: i2c-gpio-lcd {
+               compatible = "i2c-gpio";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_i2c_gpio_lcd>;
+               sda-gpios = <&gpio1 21 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+               scl-gpios = <&gpio1 19 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+               i2c-gpio,delay-us = <2>; /* ~100 kHz */
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "disabld";
+       };
+
+       i2c_cam: i2c-gpio-cam {
+               compatible = "i2c-gpio";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_i2c_gpio_cam>;
+               sda-gpios = <&gpio4 10 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+               scl-gpios = <&gpio1 6 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+               i2c-gpio,delay-us = <2>; /* ~100 kHz */
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "disabld";
+       };
+};
+
+/* I2S0, I2S1 */
+&audmux {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_audmux>;
+
+       audmux_ssi1 {
+               fsl,audmux-port = <MX51_AUDMUX_PORT1_SSI0>;
+               fsl,port-config = <
+                       (IMX_AUDMUX_V2_PTCR_TFSEL(MX51_AUDMUX_PORT3) |
+                        IMX_AUDMUX_V2_PTCR_TCSEL(MX51_AUDMUX_PORT3) |
+                        IMX_AUDMUX_V2_PTCR_SYN    |
+                        IMX_AUDMUX_V2_PTCR_TFSDIR |
+                        IMX_AUDMUX_V2_PTCR_TCLKDIR)
+                       IMX_AUDMUX_V2_PDCR_RXDSEL(MX51_AUDMUX_PORT3)
+               >;
+       };
+
+       audmux_adu3 {
+               fsl,audmux-port = <MX51_AUDMUX_PORT3>;
+               fsl,port-config = <
+                       IMX_AUDMUX_V2_PTCR_SYN
+                       IMX_AUDMUX_V2_PDCR_RXDSEL(MX51_AUDMUX_PORT1_SSI0)
+               >;
+       };
+
+       audmux_ssi2 {
+               fsl,audmux-port = <MX51_AUDMUX_PORT2_SSI1>;
+               fsl,port-config = <
+                       (IMX_AUDMUX_V2_PTCR_TFSEL(MX51_AUDMUX_PORT4) |
+                        IMX_AUDMUX_V2_PTCR_TCSEL(MX51_AUDMUX_PORT4) |
+                        IMX_AUDMUX_V2_PTCR_SYN    |
+                        IMX_AUDMUX_V2_PTCR_TFSDIR |
+                        IMX_AUDMUX_V2_PTCR_TCLKDIR)
+                       IMX_AUDMUX_V2_PDCR_RXDSEL(MX51_AUDMUX_PORT4)
+               >;
+       };
+
+       audmux_adu4 {
+               fsl,audmux-port = <MX51_AUDMUX_PORT4>;
+               fsl,port-config = <
+                       IMX_AUDMUX_V2_PTCR_SYN
+                       IMX_AUDMUX_V2_PDCR_RXDSEL(MX51_AUDMUX_PORT2_SSI1)
+               >;
+       };
+};
+
+/* CAN0 */
+&can1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexcan1>;
+};
+
+/* CAN1 */
+&can2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexcan2>;
+};
+
+/* SPI1 */
+&ecspi2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi2>;
+       cs-gpios = <&gpio2 26 GPIO_ACTIVE_HIGH>,
+                  <&gpio2 27 GPIO_ACTIVE_HIGH>;
+};
+
+/* SPI0 */
+&ecspi4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi4>;
+       cs-gpios = <&gpio3 24 GPIO_ACTIVE_HIGH>,
+                  <&gpio3 29 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+
+       /* default boot source: workaround #1 for errata ERR006282 */
+       smarc_flash: spi-flash@0 {
+               compatible = "winbond,w25q16dw", "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <20000000>;
+       };
+};
+
+/* GBE */
+&fec {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_enet>;
+       phy-mode = "rgmii";
+       phy-reset-gpios = <&gpio1 25 GPIO_ACTIVE_LOW>;
+};
+
+&i2c_intern {
+       pmic@8 {
+               compatible = "fsl,pfuze100";
+               reg = <0x08>;
+
+               regulators {
+                       reg_v_core_s0: sw1ab {
+                               regulator-name = "V_CORE_S0";
+                               regulator-min-microvolt = <300000>;
+                               regulator-max-microvolt = <1875000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       reg_vddsoc_s0: sw1c {
+                               regulator-name = "V_VDDSOC_S0";
+                               regulator-min-microvolt = <300000>;
+                               regulator-max-microvolt = <1875000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       reg_3p15v_s0: sw2 {
+                               regulator-name = "V_3V15_S0";
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       /* sw3a/b is used in dual mode, but driver does not
+                        * support it. Although, there's no need to control
+                        * DDR power - so just leaving dummy entries for sw3a
+                        * and sw3b for now.
+                        */
+                       sw3a {
+                               regulator-min-microvolt = <400000>;
+                               regulator-max-microvolt = <1975000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       sw3b {
+                               regulator-min-microvolt = <400000>;
+                               regulator-max-microvolt = <1975000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       reg_1p8v_s0: sw4 {
+                               regulator-name = "V_1V8_S0";
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       /* Regulator for USB */
+                       reg_5p0v_s0: swbst {
+                               regulator-name = "V_5V0_S0";
+                               regulator-min-microvolt = <5000000>;
+                               regulator-max-microvolt = <5150000>;
+                               regulator-boot-on;
+                       };
+
+                       reg_vsnvs: vsnvs {
+                               regulator-min-microvolt = <1000000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       reg_vrefddr: vrefddr {
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       /*
+                        * Per schematics, of all VGEN's, only VGEN5 has some
+                        * usage ... but even that - over DNI resistor
+                        */
+                       vgen1 {
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <1550000>;
+                       };
+
+                       vgen2 {
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <1550000>;
+                       };
+
+                       vgen3 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       vgen4 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       reg_2p5v_s0: vgen5 {
+                               regulator-name = "V_2V5_S0";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       vgen6 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+               };
+       };
+};
+
+/* I2C_GP */
+&i2c1 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c1>;
+};
+
+/* HDMI_CTRL */
+&i2c2 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c2>;
+};
+
+/* I2C_PM */
+&i2c3 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c3>;
+       status = "okay";
+
+       smarc_eeprom: eeprom@50 {
+               compatible = "atmel,24c32";
+               reg = <0x50>;
+               pagesize = <32>;
+       };
+};
+
+&iomuxc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_mgmt_gpios &pinctrl_gpio>;
+
+       pinctrl_audmux: audmuxgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT4__AUD3_TXC          0x130b0
+                       MX6QDL_PAD_CSI0_DAT5__AUD3_TXD          0x130b0
+                       MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS         0x130b0
+                       MX6QDL_PAD_CSI0_DAT7__AUD3_RXD          0x130b0
+
+                       MX6QDL_PAD_DISP0_DAT20__AUD4_TXC        0x130b0
+                       MX6QDL_PAD_DISP0_DAT21__AUD4_TXD        0x130b0
+                       MX6QDL_PAD_DISP0_DAT22__AUD4_TXFS       0x130b0
+                       MX6QDL_PAD_DISP0_DAT23__AUD4_RXD        0x130b0
+
+                       /* AUDIO MCLK */
+                       MX6QDL_PAD_NANDF_CS2__CCM_CLKO2         0x000b0
+               >;
+       };
+
+       pinctrl_ecspi2: ecspi2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_CS0__ECSPI2_SCLK 0x100b1
+                       MX6QDL_PAD_EIM_CS1__ECSPI2_MOSI 0x100b1
+                       MX6QDL_PAD_EIM_OE__ECSPI2_MISO  0x100b1
+
+                       MX6QDL_PAD_EIM_RW__GPIO2_IO26  0x1b0b0 /* CS0 */
+                       MX6QDL_PAD_EIM_LBA__GPIO2_IO27 0x1b0b0 /* CS1 */
+               >;
+       };
+
+       pinctrl_ecspi4: ecspi4grp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_D21__ECSPI4_SCLK 0x100b1
+                       MX6QDL_PAD_EIM_D28__ECSPI4_MOSI 0x100b1
+                       MX6QDL_PAD_EIM_D22__ECSPI4_MISO 0x100b1
+
+                       /* SPI_IMX_CS2# - connected to internal flash */
+                       MX6QDL_PAD_EIM_D24__GPIO3_IO24 0x1b0b0
+                       /* SPI_IMX_CS0# - connected to SMARC SPI0_CS0# */
+                       MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x1b0b0
+               >;
+       };
+
+       pinctrl_flexcan1: flexcan1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_7__FLEXCAN1_TX 0x1b0b0
+                       MX6QDL_PAD_GPIO_8__FLEXCAN1_RX 0x1b0b0
+               >;
+       };
+
+       pinctrl_flexcan2: flexcan2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_COL4__FLEXCAN2_TX 0x1b0b0
+                       MX6QDL_PAD_KEY_ROW4__FLEXCAN2_RX 0x1b0b0
+               >;
+       };
+
+       pinctrl_gpio: gpiogrp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_DA0__GPIO3_IO00  0x1b0b0 /* GPIO0 / CAM0_PWR# */
+                       MX6QDL_PAD_EIM_DA1__GPIO3_IO01  0x1b0b0 /* GPIO1 / CAM1_PWR# */
+                       MX6QDL_PAD_EIM_DA2__GPIO3_IO02  0x1b0b0 /* GPIO2 / CAM0_RST# */
+                       MX6QDL_PAD_EIM_DA3__GPIO3_IO03  0x1b0b0 /* GPIO3 / CAM1_RST# */
+                       MX6QDL_PAD_EIM_DA4__GPIO3_IO04  0x1b0b0 /* GPIO4 / HDA_RST#  */
+                       MX6QDL_PAD_EIM_DA5__GPIO3_IO05  0x1b0b0 /* GPIO5 / PWM_OUT   */
+                       MX6QDL_PAD_EIM_DA6__GPIO3_IO06  0x1b0b0 /* GPIO6 / TACHIN    */
+                       MX6QDL_PAD_EIM_DA7__GPIO3_IO07  0x1b0b0 /* GPIO7 / PCAM_FLD  */
+                       MX6QDL_PAD_EIM_DA8__GPIO3_IO08  0x1b0b0 /* GPIO8 / CAN0_ERR# */
+                       MX6QDL_PAD_EIM_DA9__GPIO3_IO09  0x1b0b0 /* GPIO9 / CAN1_ERR# */
+                       MX6QDL_PAD_EIM_DA10__GPIO3_IO10 0x1b0b0 /* GPIO10            */
+                       MX6QDL_PAD_EIM_DA11__GPIO3_IO11 0x1b0b0 /* GPIO11            */
+               >;
+       };
+
+       pinctrl_enet: enetgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_RGMII_TXC__RGMII_TXC       0x1b0b0
+                       MX6QDL_PAD_RGMII_TD0__RGMII_TD0       0x1b0b0
+                       MX6QDL_PAD_RGMII_TD1__RGMII_TD1       0x1b0b0
+                       MX6QDL_PAD_RGMII_TD2__RGMII_TD2       0x1b0b0
+                       MX6QDL_PAD_RGMII_TD3__RGMII_TD3       0x1b0b0
+                       MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0
+                       MX6QDL_PAD_RGMII_RXC__RGMII_RXC       0x1b0b0
+                       MX6QDL_PAD_RGMII_RD0__RGMII_RD0       0x1b0b0
+                       MX6QDL_PAD_RGMII_RD1__RGMII_RD1       0x1b0b0
+                       MX6QDL_PAD_RGMII_RD2__RGMII_RD2       0x1b0b0
+                       MX6QDL_PAD_RGMII_RD3__RGMII_RD3       0x1b0b0
+                       MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0
+
+                       MX6QDL_PAD_ENET_MDIO__ENET_MDIO       0x1b0b0
+                       MX6QDL_PAD_ENET_MDC__ENET_MDC         0x1b0b0
+                       MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK  0x1b0b0
+                       MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25    0x1b0b0 /* RST_GBE0_PHY# */
+               >;
+       };
+
+       pinctrl_i2c_gpio_cam: i2c-gpiocamgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_6__GPIO1_IO06   0x1b0b0 /* SCL */
+                       MX6QDL_PAD_KEY_COL2__GPIO4_IO10 0x1b0b0 /* SDA */
+               >;
+       };
+
+       pinctrl_i2c_gpio_intern: i2c-gpiointerngrp {
+               fsl,pins = <
+                       MX6QDL_PAD_ENET_TXD0__GPIO1_IO30  0x1b0b0 /* SCL */
+                       MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x1b0b0 /* SDA */
+               >;
+       };
+
+       pinctrl_i2c_gpio_lcd: i2c-gpiolcdgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD1_DAT2__GPIO1_IO19 0x1b0b0 /* SCL */
+                       MX6QDL_PAD_SD1_DAT3__GPIO1_IO21 0x1b0b0 /* SDA */
+               >;
+       };
+
+       pinctrl_i2c1: i2c1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT9__I2C1_SCL          0x4001b8b1
+                       MX6QDL_PAD_CSI0_DAT8__I2C1_SDA          0x4001b8b1
+               >;
+       };
+
+       pinctrl_i2c2: i2c2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_COL3__I2C2_SCL           0x4001b8b1
+                       MX6QDL_PAD_KEY_ROW3__I2C2_SDA           0x4001b8b1
+               >;
+       };
+
+       pinctrl_i2c3: i2c3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_3__I2C3_SCL             0x4001b8b1
+                       MX6QDL_PAD_GPIO_16__I2C3_SDA            0x4001b8b1
+               >;
+       };
+
+       pinctrl_lcd: lcdgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00  0x100f1
+                       MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01  0x100f1
+                       MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02  0x100f1
+                       MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03  0x100f1
+                       MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04  0x100f1
+                       MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05  0x100f1
+                       MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06  0x100f1
+                       MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07  0x100f1
+                       MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08  0x100f1
+                       MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09  0x100f1
+                       MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x100f1
+                       MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x100f1
+                       MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x100f1
+                       MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x100f1
+                       MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x100f1
+                       MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x100f1
+                       MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x100f1
+                       MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x100f1
+                       MX6QDL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0x100f1
+                       MX6QDL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0x100f1
+                       MX6QDL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0x100f1
+                       MX6QDL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0x100f1
+                       MX6QDL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0x100f1
+                       MX6QDL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0x100f1
+
+                       MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x100f1
+                       MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15       0x100f1 /* DE */
+                       MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02        0x100f1 /* HSYNC */
+                       MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03        0x100f1 /* VSYNC */
+               >;
+       };
+
+       pinctrl_lcdbklt_en: lcdbkltengrp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD1_DAT0__GPIO1_IO16 0x1b0b1
+               >;
+       };
+
+       pinctrl_lcdvdd_en: lcdvddengrp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD1_DAT1__GPIO1_IO17 0x1b0b0
+               >;
+       };
+
+       pinctrl_mipi_csi: mipi-csigrp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_MCLK__CCM_CLKO1 0x000b0 /* CSI0/1 MCLK */
+               >;
+       };
+
+       pinctrl_mgmt_gpios: mgmt-gpiosgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_WAIT__GPIO5_IO00         0x1b0b0 /* LID#           */
+                       MX6QDL_PAD_SD3_DAT7__GPIO6_IO17         0x1b0b0 /* SLEEP#         */
+                       MX6QDL_PAD_GPIO_17__GPIO7_IO12          0x1b0b0 /* CHARGING#      */
+                       MX6QDL_PAD_GPIO_0__GPIO1_IO00           0x1b0b0 /* CHARGER_PRSNT# */
+                       MX6QDL_PAD_SD1_CLK__GPIO1_IO20          0x1b0b0 /* CARRIER_STBY#  */
+                       MX6QDL_PAD_DI0_PIN4__GPIO4_IO20         0x1b0b0 /* BATLOW#        */
+                       MX6QDL_PAD_CSI0_VSYNC__GPIO5_IO21       0x1b0b0 /* TEST#          */
+                       MX6QDL_PAD_GPIO_2__GPIO1_IO02           0x1b0b0 /* VDD_IO_SEL_D#  */
+                       MX6QDL_PAD_NANDF_CS3__GPIO6_IO16        0x1b0b0 /* POWER_BTN#     */
+               >;
+       };
+
+       pinctrl_pcie: pciegrp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_D18__GPIO3_IO18  0x1b0b0 /* PCI_A_PRSNT# */
+                       MX6QDL_PAD_EIM_DA13__GPIO3_IO13 0x1b0b0 /* RST_PCIE_A#  */
+                       MX6QDL_PAD_SD3_DAT6__GPIO6_IO18 0x1b0b0 /* PCIE_WAKE#   */
+               >;
+       };
+
+       pinctrl_pwm4: pwm4grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1
+               >;
+       };
+
+       pinctrl_uart1: uart1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1
+                       MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1
+                       MX6QDL_PAD_EIM_D20__UART1_RTS_B 0x1b0b1
+                       MX6QDL_PAD_EIM_D19__UART1_CTS_B 0x1b0b1
+               >;
+       };
+
+       pinctrl_uart2: uart2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1
+                       MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1
+               >;
+       };
+
+       pinctrl_uart4: uart4grp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b1
+                       MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b1
+                       MX6QDL_PAD_CSI0_DAT16__UART4_RTS_B 0x1b0b1
+                       MX6QDL_PAD_CSI0_DAT17__UART4_CTS_B 0x1b0b1
+               >;
+       };
+
+       pinctrl_uart5: uart5grp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT15__UART5_RX_DATA 0x1b0b1
+                       MX6QDL_PAD_CSI0_DAT14__UART5_TX_DATA 0x1b0b1
+               >;
+       };
+
+       pinctrl_usbotg: usbotggrp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x1f8b0
+                       /* power, oc muxed but not used by the driver */
+                       MX6QDL_PAD_CSI0_PIXCLK__GPIO5_IO18      0x1b0b0 /* USB power */
+                       MX6QDL_PAD_CSI0_DATA_EN__GPIO5_IO20     0x1b0b0 /* USB OC */
+               >;
+       };
+
+       pinctrl_usdhc3: usdhc3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD3_CLK__SD3_CLK 0x17059
+                       MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059
+                       MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059
+                       MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059
+                       MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059
+                       MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059
+
+                       MX6QDL_PAD_NANDF_CS1__GPIO6_IO14 0x1b0b0 /* CD */
+                       MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x1b0b0 /* WP */
+                       MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x1b0b0 /* PWR_EN */
+               >;
+       };
+
+       pinctrl_usdhc4: usdhc4grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD4_CLK__SD4_CLK 0x17059
+                       MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059
+                       MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059
+                       MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059
+                       MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059
+                       MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059
+                       MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059
+                       MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059
+                       MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059
+                       MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059
+               >;
+       };
+
+       pinctrl_wdog1: wdog1rp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_9__WDOG1_B      0x1b0b0
+               >;
+       };
+};
+
+&mipi_csi {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_mipi_csi>;
+};
+
+&pcie {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pcie>;
+       wake-up-gpio = <&gpio6 18 GPIO_ACTIVE_HIGH>;
+       reset-gpio = <&gpio3 13 GPIO_ACTIVE_HIGH>;
+};
+
+/* LCD_BKLT_PWM */
+&pwm4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pwm4>;
+};
+
+&reg_arm {
+       vin-supply = <&reg_v_core_s0>;
+};
+
+&reg_pu {
+       vin-supply = <&reg_vddsoc_s0>;
+};
+
+&reg_soc {
+       vin-supply = <&reg_vddsoc_s0>;
+};
+
+/* SER0 */
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
+       uart-has-rtscts;
+};
+
+/* SER1 */
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2>;
+};
+
+/* SER2 */
+&uart4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart4>;
+       uart-has-rtscts;
+};
+
+/* SER3 */
+&uart5 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart5>;
+};
+
+/* USB0 */
+&usbotg {
+       /*
+        * no 'imx6-usb-charger-detection'
+        * since USB_OTG_CHD_B pin is not wired
+        */
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbotg>;
+};
+
+/* USB1/2 via hub */
+&usbh1 {
+       vbus-supply = <&reg_5p0v_s0>;
+};
+
+/* SDIO */
+&usdhc3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc3>;
+       cd-gpios = <&gpio6 14 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio1 26 GPIO_ACTIVE_HIGH>;
+       no-1-8-v;
+};
+
+/* SDMMC */
+&usdhc4 {
+       /* Internal eMMC, optional on some boards */
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc4>;
+       bus-width = <8>;
+       no-sdio;
+       no-sd;
+       non-removable;
+       vmmc-supply = <&reg_3p3v_s0>;
+       vqmmc-supply = <&reg_1p8v_s0>;
+};
+
+&wdog1 {
+       /* CPLD is feeded by watchdog (hardwired) */
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_wdog1>;
+       status = "okay";
+};
index 185fb17..71ca76a 100644 (file)
        vin-supply = <&sw1c_reg>;
 };
 
+&reg_vdd1p1 {
+       vin-supply = <&vgen5_reg>;
+};
+
+&reg_vdd3p0 {
+       vin-supply = <&sw2_reg>;
+};
+
+&reg_vdd2p5 {
+       vin-supply = <&vgen5_reg>;
+};
+
 &snvs_poweroff {
        status = "okay";
 };
 
+&snvs_pwrkey {
+       status = "okay";
+};
+
 &ssi2 {
        status = "okay";
 };
index b3a77bc..4b80193 100644 (file)
                                compatible = "fsl,imx6q-wdt", "fsl,imx21-wdt";
                                reg = <0x020bc000 0x4000>;
                                interrupts = <0 80 IRQ_TYPE_LEVEL_HIGH>;
-                               clocks = <&clks IMX6QDL_CLK_DUMMY>;
+                               clocks = <&clks IMX6QDL_CLK_IPG>;
                        };
 
                        wdog2: wdog@20c0000 {
                                compatible = "fsl,imx6q-wdt", "fsl,imx21-wdt";
                                reg = <0x020c0000 0x4000>;
                                interrupts = <0 81 IRQ_TYPE_LEVEL_HIGH>;
-                               clocks = <&clks IMX6QDL_CLK_DUMMY>;
+                               clocks = <&clks IMX6QDL_CLK_IPG>;
                                status = "disabled";
                        };
 
                                             <0 54 IRQ_TYPE_LEVEL_HIGH>,
                                             <0 127 IRQ_TYPE_LEVEL_HIGH>;
 
-                               regulator-1p1 {
+                               reg_vdd1p1: regulator-1p1 {
                                        compatible = "fsl,anatop-regulator";
                                        regulator-name = "vdd1p1";
                                        regulator-min-microvolt = <1000000>;
                                        anatop-enable-bit = <0>;
                                };
 
-                               regulator-3p0 {
+                               reg_vdd3p0: regulator-3p0 {
                                        compatible = "fsl,anatop-regulator";
                                        regulator-name = "vdd3p0";
                                        regulator-min-microvolt = <2800000>;
                                        anatop-enable-bit = <0>;
                                };
 
-                               regulator-2p5 {
+                               reg_vdd2p5: regulator-2p5 {
                                        compatible = "fsl,anatop-regulator";
                                        regulator-name = "vdd2p5";
                                        regulator-min-microvolt = <2250000>;
                                        interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
                                        linux,keycode = <KEY_POWER>;
                                        wakeup-source;
+                                       status = "disabled";
                                };
 
                                snvs_lpgpr: snvs-lpgpr {
index f7a48e4..4829aa6 100644 (file)
        status = "okay";
 };
 
+&reg_vdd1p1 {
+       vin-supply = <&sw2_reg>;
+};
+
+&reg_vdd3p0 {
+       vin-supply = <&sw2_reg>;
+};
+
+&reg_vdd2p5 {
+       vin-supply = <&sw2_reg>;
+};
+
 &snvs_poweroff {
        status = "okay";
 };
index 9ddbeea..b36fc01 100644 (file)
                                compatible = "fsl,imx6sl-kpp", "fsl,imx21-kpp";
                                reg = <0x020b8000 0x4000>;
                                interrupts = <0 82 IRQ_TYPE_LEVEL_HIGH>;
-                               clocks = <&clks IMX6SL_CLK_DUMMY>;
+                               clocks = <&clks IMX6SL_CLK_IPG>;
                                status = "disabled";
                        };
 
                                compatible = "fsl,imx6sl-wdt", "fsl,imx21-wdt";
                                reg = <0x020bc000 0x4000>;
                                interrupts = <0 80 IRQ_TYPE_LEVEL_HIGH>;
-                               clocks = <&clks IMX6SL_CLK_DUMMY>;
+                               clocks = <&clks IMX6SL_CLK_IPG>;
                        };
 
                        wdog2: wdog@20c0000 {
                                compatible = "fsl,imx6sl-wdt", "fsl,imx21-wdt";
                                reg = <0x020c0000 0x4000>;
                                interrupts = <0 81 IRQ_TYPE_LEVEL_HIGH>;
-                               clocks = <&clks IMX6SL_CLK_DUMMY>;
+                               clocks = <&clks IMX6SL_CLK_IPG>;
                                status = "disabled";
                        };
 
                                             <0 54 IRQ_TYPE_LEVEL_HIGH>,
                                             <0 127 IRQ_TYPE_LEVEL_HIGH>;
 
-                               regulator-1p1 {
+                               reg_vdd1p1: regulator-1p1 {
                                        compatible = "fsl,anatop-regulator";
                                        regulator-name = "vdd1p1";
                                        regulator-min-microvolt = <1000000>;
                                        anatop-enable-bit = <0>;
                                };
 
-                               regulator-3p0 {
+                               reg_vdd3p0: regulator-3p0 {
                                        compatible = "fsl,anatop-regulator";
                                        regulator-name = "vdd3p0";
                                        regulator-min-microvolt = <2800000>;
                                        anatop-enable-bit = <0>;
                                };
 
-                               regulator-2p5 {
+                               reg_vdd2p5: regulator-2p5 {
                                        compatible = "fsl,anatop-regulator";
                                        regulator-name = "vdd2p5";
                                        regulator-min-microvolt = <2250000>;
index 4a31a41..3e1d32f 100644 (file)
        status = "okay";
 };
 
+&reg_3p0 {
+       vin-supply = <&sw2_reg>;
+};
+
+&snvs_poweroff {
+       status = "okay";
+};
+
+&snvs_pwrkey {
+       status = "okay";
+};
+
 &uart1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart1>;
index 1b4899f..b0a77ff 100644 (file)
                                        regmap = <&snvs>;
                                        offset = <0x38>;
                                        mask = <0x61>;
+                                       status = "disabled";
                                };
 
                                snvs_pwrkey: snvs-powerkey {
                                        interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
                                        linux,keycode = <KEY_POWER>;
                                        wakeup-source;
+                                       status = "disabled";
                                };
                        };
 
index 00c4854..f1830ed 100644 (file)
        enable-active-high;
        vin-supply = <&reg_can_en>;
 };
+
+&reg_vdd1p1 {
+       vin-supply = <&vgen6_reg>;
+};
+
+&reg_vdd3p0 {
+       vin-supply = <&sw2_reg>;
+};
+
+&reg_vdd2p5 {
+       vin-supply = <&vgen6_reg>;
+};
+
+&snvs_pwrkey {
+       status = "okay";
+};
index 998e3e1..a8ee708 100644 (file)
        vin-supply = <&sw1a_reg>;
 };
 
+&reg_vdd1p1 {
+       vin-supply = <&vgen6_reg>;
+};
+
+&reg_vdd3p0 {
+       vin-supply = <&sw2_reg>;
+};
+
+&reg_vdd2p5 {
+       vin-supply = <&vgen6_reg>;
+};
+
 &reg_can_stby {
        /* Transceiver EN/STBY is active low on RevB board */
        gpio = <&gpio4 27 GPIO_ACTIVE_LOW>;
 };
+
+&snvs_pwrkey {
+       status = "okay";
+};
index db0feb9..205ea26 100644 (file)
@@ -1,43 +1,6 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (c) 2016 Andreas Färber
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library 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 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 General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 /dts-v1/;
index 5c7a2bb..5817b49 100644 (file)
@@ -1,43 +1,6 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (c) 2016 Andreas Färber
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library 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 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 General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 /dts-v1/;
                reg = <0x80000000 0x40000000>;
        };
 };
+
+&i2c4 { /* Onboard Motion sensors */
+       status = "okay";
+};
+
+&uart3 { /* Bluetooth */
+       status = "okay";
+};
index 13dfe2a..96f4d89 100644 (file)
@@ -1,43 +1,6 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (c) 2016 Andreas Färber
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library 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 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 General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 /dts-v1/;
                };
        };
 };
+
+&i2c4 { /* Onboard Motion sensors */
+       status = "okay";
+};
+
+&uart3 { /* Bluetooth */
+       status = "okay";
+};
index 53b3eac..25d4aa9 100644 (file)
@@ -1,43 +1,6 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (c) 2016 Andreas Färber
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library 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 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 General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 #include "imx6sx.dtsi"
                startup-delay-us = <70000>;
                enable-active-high;
        };
-
-       reg_bt: regulator-bt {
-               compatible = "regulator-fixed";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_bt_reg>;
-               enable-active-high;
-               gpio = <&gpio2 17 GPIO_ACTIVE_HIGH>;
-               regulator-name = "bt_reg";
-               regulator-min-microvolt = <1800000>;
-               regulator-max-microvolt = <1800000>;
-               regulator-always-on;
-       };
 };
 
 &fec1 {
        };
 };
 
+&i2c2 { /* Brick snap in sensors connector */
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c2>;
+       clock-frequency = <100000>;
+       status = "okay";
+};
+
+&i2c4 { /* Onboard Motion sensors */
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c4>;
+       clock-frequency = <100000>;
+       status = "disabled";
+};
+
 &iomuxc {
        pinctrl_bt_reg: btreggrp {
                fsl,pins =
                        <MX6SX_PAD_GPIO1_IO01__I2C1_SDA         0x4001b8b1>;
        };
 
+       pinctrl_i2c2: i2c2grp {
+               fsl,pins =
+                       <MX6SX_PAD_GPIO1_IO03__I2C2_SDA         0x4001b8b1>,
+                       <MX6SX_PAD_GPIO1_IO02__I2C2_SCL         0x4001b8b1>;
+       };
+
+       pinctrl_i2c4: i2c4grp {
+               fsl,pins =
+                       <MX6SX_PAD_USB_H_DATA__I2C4_SDA         0x4001b8b1>,
+                       <MX6SX_PAD_USB_H_STROBE__I2C4_SCL       0x4001b8b1>;
+       };
+
        pinctrl_uart1: uart1grp {
                fsl,pins =
                        <MX6SX_PAD_GPIO1_IO04__UART1_TX         0x1b0b1>,
        status = "disabled";
 };
 
-&uart3 { /* Bluetooth */
+&uart3 { /* Bluetooth - only on Extended/Full versions */
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart3>;
        uart-has-rtscts;
-       status = "okay";
+       status = "disabled";
+
+       bluetooth {
+               compatible = "ti,wl1831-st";
+               enable-gpios = <&gpio2 17 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_bt_reg>;
+               max-speed = <921600>;
+       };
 };
 
 /* Arduino serial */
index b16a123..bb25add 100644 (file)
                                             <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
 
-                               regulator-1p1 {
+                               reg_vdd1p1: regulator-1p1 {
                                        compatible = "fsl,anatop-regulator";
                                        regulator-name = "vdd1p1";
                                        regulator-min-microvolt = <1000000>;
                                        anatop-enable-bit = <0>;
                                };
 
-                               regulator-3p0 {
+                               reg_vdd3p0: regulator-3p0 {
                                        compatible = "fsl,anatop-regulator";
                                        regulator-name = "vdd3p0";
                                        regulator-min-microvolt = <2800000>;
                                        anatop-enable-bit = <0>;
                                };
 
-                               regulator-2p5 {
+                               reg_vdd2p5: regulator-2p5 {
                                        compatible = "fsl,anatop-regulator";
                                        regulator-name = "vdd2p5";
                                        regulator-min-microvolt = <2250000>;
                                        interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
                                        linux,keycode = <KEY_POWER>;
                                        wakeup-source;
+                                       status = "disabled";
                                };
                        };
 
index 9207d5d..cbe61b6 100644 (file)
        status = "okay";
 };
 
+&snvs_pwrkey {
+       status = "okay";
+};
+
 &tsc {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_tsc>;
index bc77f26..21ddd35 100644 (file)
        display = <&display0>;
        status = "okay";
 
-       display0: display {
+       display0: display0 {
                bits-per-pixel = <16>;
                bus-width = <18>;
 
index 213e802..b26d4f5 100644 (file)
        display = <&display0>;
        status = "okay";
 
-       display0: display {
+       display0: display0 {
                bits-per-pixel = <16>;
                bus-width = <18>;
 
index a7f6d1d..81d4b49 100644 (file)
@@ -59,6 +59,7 @@
                        compatible = "arm,cortex-a7";
                        device_type = "cpu";
                        reg = <0>;
+                       clock-frequency = <696000000>;
                        clock-latency = <61036>; /* two CLK32 periods */
                        #cooling-cells = <2>;
                        operating-points = <
                                        interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
                                        linux,keycode = <KEY_POWER>;
                                        wakeup-source;
+                                       status = "disabled";
                                };
 
                                snvs_lpgpr: snvs-lpgpr {
                                         <&clks IMX6UL_CLK_USDHC1>,
                                         <&clks IMX6UL_CLK_USDHC1>;
                                clock-names = "ipg", "ahb", "per";
+                               fsl,tuning-step= <2>;
+                               fsl,tuning-start-tap = <20>;
                                bus-width = <4>;
                                status = "disabled";
                        };
                                         <&clks IMX6UL_CLK_USDHC2>;
                                clock-names = "ipg", "ahb", "per";
                                bus-width = <4>;
+                               fsl,tuning-step= <2>;
+                               fsl,tuning-start-tap = <20>;
                                status = "disabled";
                        };
 
                                status = "disabled";
                        };
 
+                       pxp: pxp@21cc000 {
+                               compatible = "fsl,imx6ul-pxp";
+                               reg = <0x021cc000 0x4000>;
+                               interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clks IMX6UL_CLK_PXP>;
+                               clock-names = "axi";
+                       };
+
                        qspi: spi@21e0000 {
                                #address-cells = <1>;
                                #size-cells = <0>;
index 006690e..b6147c7 100644 (file)
 };
 
 &usdhc1 {
-       pinctrl-names = "default";
+       pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
        pinctrl-0 = <&pinctrl_usdhc1 &pinctrl_snvs_usdhc1_cd>;
-       no-1-8-v;
+       pinctrl-1 = <&pinctrl_usdhc1_100mhz &pinctrl_snvs_usdhc1_cd>;
+       pinctrl-2 = <&pinctrl_usdhc1_200mhz &pinctrl_snvs_usdhc1_cd>;
+       pinctrl-3 = <&pinctrl_usdhc1 &pinctrl_snvs_usdhc1_sleep_cd>;
        cd-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
        disable-wp;
        wakeup-source;
        keep-power-in-suspend;
        vmmc-supply = <&reg_3v3>;
+       vqmmc-supply = <&reg_sd1_vmmc>;
+       sd-uhs-sdr12;
+       sd-uhs-sdr25;
+       sd-uhs-sdr50;
+       sd-uhs-sdr104;
        status = "okay";
 };
index 9ad1da1..d56728f 100644 (file)
                >;
        };
 
+       pinctrl_snvs_usdhc1_sleep_cd: snvs-usdhc1-cd-grp-slp {
+               fsl,pins = <
+                       MX6ULL_PAD_SNVS_TAMPER0__GPIO5_IO00     0x0
+               >;
+       };
+
        pinctrl_snvs_wifi_pdn: snvs-wifi-pdn-grp {
                fsl,pins = <
                        MX6ULL_PAD_BOOT_MODE1__GPIO5_IO11       0x14
index 22e4a30..b7e67d1 100644 (file)
@@ -12,6 +12,7 @@
 /delete-node/ &crypto;
 
 &cpu0 {
+       clock-frequency = <900000000>;
        operating-points = <
                /* kHz  uV */
                900000  1275000
        compatible = "fsl,imx6ull-ocotp", "syscon";
 };
 
+&pxp {
+       compatible = "fsl,imx6ull-pxp";
+       interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
+};
+
 &usdhc1 {
        compatible = "fsl,imx6ull-usdhc", "fsl,imx6sx-usdhc";
 };
diff --git a/arch/arm/boot/dts/imx7d-meerkat96.dts b/arch/arm/boot/dts/imx7d-meerkat96.dts
new file mode 100644 (file)
index 0000000..5339210
--- /dev/null
@@ -0,0 +1,375 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * Copyright (C) 2019 Linaro Ltd.
+ */
+
+/dts-v1/;
+
+#include "imx7d.dtsi"
+
+/ {
+       model = "96Boards Meerkat96 Board";
+       compatible = "novtech,imx7d-meerkat96", "fsl,imx7d";
+
+       chosen {
+               stdout-path = &uart6;
+       };
+
+       memory@80000000 {
+               device_type = "memory";
+               reg = <0x80000000 0x20000000>; /* 512MB */
+       };
+
+       reg_wlreg_on: regulator-wlreg-on {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_wlreg_on>;
+               regulator-name = "wlreg_on";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               startup-delay-us = <100>;
+               gpio = <&gpio6 15 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               regulator-always-on;
+       };
+
+       reg_3p3v: regulator-3p3v {
+               compatible = "regulator-fixed";
+               regulator-name = "3P3V";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+       };
+
+       reg_usb_otg1_vbus: regulator-usb-otg1-vbus {
+               compatible = "regulator-fixed";
+               regulator-name = "usb_otg1_vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+       };
+
+       reg_usb_otg2_vbus: regulator-usb-otg2-vbus {
+               compatible = "regulator-fixed";
+               regulator-name = "usb_otg2_vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               gpio = <&gpio1 2 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       leds {
+               compatible = "gpio-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_gpio_leds>;
+
+               led1 {
+                       label = "green:user1";
+                       gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
+                       linux,default-trigger = "heartbeat";
+                       default-state = "off";
+               };
+
+               led2 {
+                       label = "green:user2";
+                       gpios = <&gpio1 5 GPIO_ACTIVE_LOW>;
+                       linux,default-trigger = "mmc0";
+                       default-state = "off";
+               };
+
+               led3 {
+                       label = "green:user3";
+                       gpios = <&gpio1 6 GPIO_ACTIVE_LOW>;
+                       linux,default-trigger = "mmc1";
+                       default-state = "off";
+               };
+
+               led4 {
+                       label = "green:user4";
+                       gpios = <&gpio1 7 GPIO_ACTIVE_LOW>;
+                       linux,default-trigger = "none";
+                       default-state = "off";
+                       panic-indicator;
+               };
+
+               led5 {
+                       label = "yellow:wlan";
+                       gpios = <&gpio1 0 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "phy0tx";
+                       default-state = "off";
+               };
+
+               led6 {
+                       label = "blue:bt";
+                       gpios = <&gpio5 2 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "bluetooth-power";
+                       default-state = "off";
+               };
+       };
+};
+
+&i2c1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       status = "okay";
+};
+
+&i2c2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c2>;
+       status = "okay";
+};
+
+&i2c3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c3>;
+       status = "okay";
+};
+
+&i2c4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c4>;
+       status = "okay";
+};
+
+&lcdif {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_lcdif>;
+       status = "okay";
+};
+
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
+       assigned-clocks = <&clks IMX7D_UART1_ROOT_SRC>;
+       assigned-clock-parents = <&clks IMX7D_PLL_SYS_MAIN_240M_CLK>;
+       status = "okay";
+};
+
+&uart3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart3>;
+       assigned-clocks = <&clks IMX7D_UART3_ROOT_SRC>;
+       assigned-clock-parents = <&clks IMX7D_PLL_SYS_MAIN_240M_CLK>;
+       uart-has-rtscts;
+       status = "okay";
+};
+
+&uart6 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart6>;
+       assigned-clocks = <&clks IMX7D_UART6_ROOT_SRC>;
+       assigned-clock-parents = <&clks IMX7D_PLL_SYS_MAIN_240M_CLK>;
+       status = "okay";
+};
+
+&uart7 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart7 &pinctrl_bt_gpios>;
+       assigned-clocks = <&clks IMX7D_UART7_ROOT_SRC>;
+       assigned-clock-parents = <&clks IMX7D_PLL_SYS_MAIN_240M_CLK>;
+       uart-has-rtscts;
+       fsl,dte-mode;
+       status = "okay";
+
+       bluetooth {
+               compatible = "brcm,bcm43438-bt";
+               device-wakeup-gpios = <&gpio6 13 GPIO_ACTIVE_HIGH>;
+               host-wakeup-gpios = <&gpio4 17 GPIO_ACTIVE_HIGH>;
+       };
+};
+
+&usbotg1 {
+       vbus-supply = <&reg_usb_otg1_vbus>;
+       status = "okay";
+};
+
+&usbotg2 {
+       vbus-supply = <&reg_usb_otg2_vbus>;
+       dr_mode = "host";
+       status = "okay";
+};
+
+&usdhc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc1>;
+       keep-power-in-suspend;
+       tuning-step = <2>;
+       vmmc-supply = <&reg_3p3v>;
+       no-1-8-v;
+       broken-cd;
+       status = "okay";
+};
+
+&usdhc3 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc3>;
+       bus-width = <4>;
+       no-1-8-v;
+       no-mmc;
+       non-removable;
+       keep-power-in-suspend;
+       wakeup-source;
+       vmmc-supply = <&reg_wlreg_on>;
+       vqmmc-supply =<&reg_3p3v>;
+       status = "okay";
+
+       brcmf: wifi@1 {
+               reg = <1>;
+               compatible = "brcm,bcm4329-fmac";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_wlan_irq>;
+               interrupt-parent = <&gpio6>;
+               interrupts = <14 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "host-wake";
+       };
+};
+
+&iomuxc {
+       pinctrl_bt_gpios: btgpiosgrp {
+               fsl,pins = <
+                       MX7D_PAD_SAI1_TX_BCLK__GPIO6_IO13       0x59
+                       MX7D_PAD_ECSPI1_MOSI__GPIO4_IO17        0x1f
+               >;
+       };
+
+       pinctrl_gpio_leds: gpioledsgrp {
+               fsl,pins = <
+                       MX7D_PAD_LPSR_GPIO1_IO00__GPIO1_IO0     0x59
+                       MX7D_PAD_LPSR_GPIO1_IO04__GPIO1_IO4     0x59
+                       MX7D_PAD_LPSR_GPIO1_IO05__GPIO1_IO5     0x59
+                       MX7D_PAD_LPSR_GPIO1_IO06__GPIO1_IO6     0x59
+                       MX7D_PAD_LPSR_GPIO1_IO07__GPIO1_IO7     0x59
+                       MX7D_PAD_SD1_RESET_B__GPIO5_IO2         0x59
+               >;
+       };
+
+       pinctrl_i2c1: i2c1grp {
+               fsl,pins = <
+                       MX7D_PAD_I2C1_SDA__I2C1_SDA             0x4000007f
+                       MX7D_PAD_I2C1_SCL__I2C1_SCL             0x4000007f
+               >;
+       };
+
+       pinctrl_i2c2: i2c2grp {
+               fsl,pins = <
+                       MX7D_PAD_I2C2_SDA__I2C2_SDA             0x4000007f
+                       MX7D_PAD_I2C2_SCL__I2C2_SCL             0x4000007f
+               >;
+       };
+
+       pinctrl_i2c3: i2c3grp {
+               fsl,pins = <
+                       MX7D_PAD_ENET1_RGMII_RD1__I2C3_SDA      0x4000007f
+                       MX7D_PAD_ENET1_RGMII_RD0__I2C3_SCL      0x4000007f
+               >;
+       };
+
+       pinctrl_i2c4: i2c4grp {
+               fsl,pins = <
+                       MX7D_PAD_SAI1_RX_BCLK__I2C4_SDA         0x4000007f
+                       MX7D_PAD_SAI1_RX_SYNC__I2C4_SCL         0x4000007f
+               >;
+       };
+
+       pinctrl_lcdif: lcdifgrp {
+               fsl,pins = <
+                       MX7D_PAD_LCD_DATA00__LCD_DATA0          0x79
+                       MX7D_PAD_LCD_DATA01__LCD_DATA1          0x79
+                       MX7D_PAD_LCD_DATA02__LCD_DATA2          0x79
+                       MX7D_PAD_LCD_DATA03__LCD_DATA3          0x79
+                       MX7D_PAD_LCD_DATA04__LCD_DATA4          0x79
+                       MX7D_PAD_LCD_DATA05__LCD_DATA5          0x79
+                       MX7D_PAD_LCD_DATA06__LCD_DATA6          0x79
+                       MX7D_PAD_LCD_DATA07__LCD_DATA7          0x79
+                       MX7D_PAD_LCD_DATA08__LCD_DATA8          0x79
+                       MX7D_PAD_LCD_DATA09__LCD_DATA9          0x79
+                       MX7D_PAD_LCD_DATA10__LCD_DATA10         0x79
+                       MX7D_PAD_LCD_DATA11__LCD_DATA11         0x79
+                       MX7D_PAD_LCD_DATA12__LCD_DATA12         0x79
+                       MX7D_PAD_LCD_DATA13__LCD_DATA13         0x79
+                       MX7D_PAD_LCD_DATA14__LCD_DATA14         0x79
+                       MX7D_PAD_LCD_DATA15__LCD_DATA15         0x79
+                       MX7D_PAD_LCD_DATA16__LCD_DATA16         0x79
+                       MX7D_PAD_LCD_DATA17__LCD_DATA17         0x79
+                       MX7D_PAD_LCD_DATA18__LCD_DATA18         0x79
+                       MX7D_PAD_LCD_DATA19__LCD_DATA19         0x79
+                       MX7D_PAD_LCD_DATA20__LCD_DATA20         0x79
+                       MX7D_PAD_LCD_DATA21__LCD_DATA21         0x79
+                       MX7D_PAD_LCD_DATA22__LCD_DATA22         0x79
+                       MX7D_PAD_LCD_DATA23__LCD_DATA23         0x79
+                       MX7D_PAD_LCD_CLK__LCD_CLK               0x79
+                       MX7D_PAD_LCD_ENABLE__LCD_ENABLE         0x79
+                       MX7D_PAD_LCD_VSYNC__LCD_VSYNC           0x79
+                       MX7D_PAD_LCD_HSYNC__LCD_HSYNC           0x79
+                       MX7D_PAD_LCD_RESET__LCD_RESET           0x79
+               >;
+       };
+
+       pinctrl_uart1: uart1grp {
+               fsl,pins = <
+                       MX7D_PAD_UART1_TX_DATA__UART1_DCE_TX    0x79
+                       MX7D_PAD_UART1_RX_DATA__UART1_DCE_RX    0x79
+               >;
+       };
+
+       pinctrl_uart3: uart3grp {
+               fsl,pins = <
+                       MX7D_PAD_SD3_DATA4__UART3_DCE_RX        0x79
+                       MX7D_PAD_SD3_DATA5__UART3_DCE_TX        0x79
+                       MX7D_PAD_SD3_DATA6__UART3_DCE_RTS       0x79
+                       MX7D_PAD_SD3_DATA7__UART3_DCE_CTS       0x79
+               >;
+       };
+
+       pinctrl_uart6: uart6grp {
+               fsl,pins = <
+                       MX7D_PAD_SD1_CD_B__UART6_DCE_RX         0x79
+                       MX7D_PAD_SD1_WP__UART6_DCE_TX           0x79
+               >;
+       };
+
+       pinctrl_uart7: uart7grp {
+               fsl,pins = <
+                       MX7D_PAD_ECSPI2_SCLK__UART7_DTE_TX      0x79
+                       MX7D_PAD_ECSPI2_MOSI__UART7_DTE_RX      0x79
+                       MX7D_PAD_ECSPI2_MISO__UART7_DTE_CTS     0x79
+                       MX7D_PAD_ECSPI2_SS0__UART7_DTE_RTS      0x79
+               >;
+       };
+
+       pinctrl_usdhc1: usdhc1grp {
+               fsl,pins = <
+                       MX7D_PAD_SD1_CMD__SD1_CMD               0x59
+                       MX7D_PAD_SD1_CLK__SD1_CLK               0x19
+                       MX7D_PAD_SD1_DATA0__SD1_DATA0           0x59
+                       MX7D_PAD_SD1_DATA1__SD1_DATA1           0x59
+                       MX7D_PAD_SD1_DATA2__SD1_DATA2           0x59
+                       MX7D_PAD_SD1_DATA3__SD1_DATA3           0x59
+               >;
+       };
+
+       pinctrl_usdhc3: usdhc3grp {
+               fsl,pins = <
+                       MX7D_PAD_SD3_CMD__SD3_CMD               0x59
+                       MX7D_PAD_SD3_CLK__SD3_CLK               0x0D
+                       MX7D_PAD_SD3_DATA0__SD3_DATA0           0x59
+                       MX7D_PAD_SD3_DATA1__SD3_DATA1           0x59
+                       MX7D_PAD_SD3_DATA2__SD3_DATA2           0x59
+                       MX7D_PAD_SD3_DATA3__SD3_DATA3           0x59
+               >;
+       };
+
+       pinctrl_wlan_irq: wlanirqgrp {
+               fsl,pins = <
+                       MX7D_PAD_SAI1_TX_SYNC__GPIO6_IO14       0x19
+               >;
+       };
+
+       pinctrl_wlreg_on: wlregongrp {
+               fsl,pins = <
+                       MX7D_PAD_SAI1_TX_DATA__GPIO6_IO15       0x19
+               >;
+       };
+};
index 202922e..869efbc 100644 (file)
                        };
 
                        sw2_reg: sw2 {
-                               regulator-min-microvolt = <1500000>;
-                               regulator-max-microvolt = <1850000>;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
                                regulator-boot-on;
                                regulator-always-on;
                        };
        status = "okay";
 };
 
+&reg_1p0d {
+       vin-supply = <&sw2_reg>;
+};
+
+&reg_1p2 {
+       vin-supply = <&sw2_reg>;
+};
+
+&snvs_pwrkey {
+       status = "okay";
+};
+
 &uart1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart1>;
index 3e467a9..4a78ddc 100644 (file)
@@ -16,7 +16,7 @@
        compatible = "zii,imx7d-rpu2", "fsl,imx7d";
 
        chosen {
-               stdout-path = &uart1;
+               stdout-path = &uart2;
        };
 
        cs2000_ref: oscillator {
                >;
        };
 
-       pinctrl_i2c1_gpio: i2c1gpiogrp {
-               fsl,pins = <
-                       MX7D_PAD_I2C1_SDA__GPIO4_IO9            0x4000007f
-                       MX7D_PAD_I2C1_SCL__GPIO4_IO8            0x4000007f
-               >;
-       };
-
        pinctrl_i2c2: i2c2grp {
                fsl,pins = <
                        MX7D_PAD_I2C2_SDA__I2C2_SDA             0x4000007f
                >;
        };
 
-       pinctrl_i2c2_gpio: i2c2gpiogrp {
-               fsl,pins = <
-                       MX7D_PAD_I2C2_SDA__GPIO4_IO11           0x4000007f
-                       MX7D_PAD_I2C2_SCL__GPIO4_IO10           0x4000007f
-               >;
-       };
-
        pinctrl_i2c3: i2c3grp {
                fsl,pins = <
                        MX7D_PAD_I2C3_SDA__I2C3_SDA             0x4000007f
index f33b560..42528d2 100644 (file)
@@ -12,6 +12,8 @@
                        clock-frequency = <996000000>;
                        operating-points-v2 = <&cpu0_opp_table>;
                        #cooling-cells = <2>;
+                       nvmem-cells = <&cpu_speed_grade>;
+                       nvmem-cell-names = "speed_grade";
                };
 
                cpu1: cpu@1 {
 
                opp-792000000 {
                        opp-hz = /bits/ 64 <792000000>;
-                       opp-microvolt = <975000>;
+                       opp-microvolt = <1000000>;
                        clock-latency-ns = <150000>;
+                       opp-supported-hw = <0xf>, <0xf>;
                };
 
                opp-996000000 {
                        opp-hz = /bits/ 64 <996000000>;
-                       opp-microvolt = <1075000>;
+                       opp-microvolt = <1100000>;
                        clock-latency-ns = <150000>;
-                       opp-suspend;
+                       opp-supported-hw = <0xc>, <0xf>;
+               };
+
+               opp-1200000000 {
+                       opp-hz = /bits/ 64 <1200000000>;
+                       opp-microvolt = <1225000>;
+                       clock-latency-ns = <150000>;
+                       opp-supported-hw = <0x8>, <0xf>;
                };
        };
 
index 106711d..c1a4fff 100644 (file)
                 * non-configurable replicators don't show up on the
                 * AMBA bus.  As such no need to add "arm,primecell"
                 */
-               compatible = "arm,coresight-replicator";
+               compatible = "arm,coresight-static-replicator";
 
                out-ports {
                        #address-cells = <1>;
                ranges;
 
                funnel@30041000 {
-                       compatible = "arm,coresight-funnel", "arm,primecell";
+                       compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                        reg = <0x30041000 0x1000>;
                        clocks = <&clks IMX7D_MAIN_AXI_ROOT_CLK>;
                        clock-names = "apb_pclk";
                };
 
                funnel@30083000 {
-                       compatible = "arm,coresight-funnel", "arm,primecell";
+                       compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                        reg = <0x30083000 0x1000>;
                        clocks = <&clks IMX7D_MAIN_AXI_ROOT_CLK>;
                        clock-names = "apb_pclk";
                                tempmon_temp_grade: temp-grade@10 {
                                        reg = <0x10 0x4>;
                                };
+
+                               cpu_speed_grade: speed-grade@10 {
+                                       reg = <0x10 0x4>;
+                               };
                        };
 
                        anatop: anatop@30360000 {
                                        interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
                                        linux,keycode = <KEY_POWER>;
                                        wakeup-source;
+                                       status = "disabled";
                                };
                        };
 
index a09026a..4245b33 100644 (file)
                reg = <0x60000000 0x40000000>;
        };
 
+       backlight {
+               compatible = "pwm-backlight";
+               pwms = <&tpm4 1 50000 0>;
+               brightness-levels = <0 20 25 30 35 40 100>;
+               default-brightness-level = <6>;
+               status = "okay";
+       };
+
+       reg_usb_otg1_vbus: regulator-usb-otg1-vbus {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_usbotg1_vbus>;
+               regulator-name = "usb_otg1_vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               gpio = <&gpio_ptc 0 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
        reg_vsd_3v3: regulator-vsd-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VSD_3V3";
        status = "okay";
 };
 
+&tpm4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pwm0>;
+       status = "okay";
+};
+
+&usbotg1 {
+       vbus-supply = <&reg_usb_otg1_vbus>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbotg1_id>;
+       srp-disable;
+       hnp-disable;
+       adp-disable;
+       over-current-active-low;
+       status = "okay";
+};
+
 &usdhc0 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc0>;
                bias-pull-up;
        };
 
+       pinctrl_pwm0: pwm0grp {
+               fsl,pins = <
+                       IMX7ULP_PAD_PTF2__TPM4_CH1      0x2
+               >;
+       };
+
+       pinctrl_usbotg1_vbus: otg1vbusgrp {
+               fsl,pins = <
+                       IMX7ULP_PAD_PTC0__PTC0          0x20000
+               >;
+       };
+
+       pinctrl_usbotg1_id: otg1idgrp {
+               fsl,pins = <
+                       IMX7ULP_PAD_PTC13__USB0_ID      0x10003
+                       IMX7ULP_PAD_PTC16__USB1_OC2     0x10003
+               >;
+       };
+
        pinctrl_usdhc0: usdhc0grp {
                fsl,pins = <
                        IMX7ULP_PAD_PTD1__SDHC0_CMD     0x43
index e204837..992747a 100644 (file)
@@ -30,6 +30,7 @@
                serial1 = &lpuart5;
                serial2 = &lpuart6;
                serial3 = &lpuart7;
+               usbphy0 = &usbphy1;
        };
 
        cpus {
                        status = "disabled";
                };
 
+               tpm4: pwm@40250000 {
+                       compatible = "fsl,imx7ulp-pwm";
+                       reg = <0x40250000 0x1000>;
+                       assigned-clocks = <&pcc2 IMX7ULP_CLK_LPTPM4>;
+                       assigned-clock-parents = <&scg1 IMX7ULP_CLK_SOSC_BUS_CLK>;
+                       clocks = <&pcc2 IMX7ULP_CLK_LPTPM4>;
+                       #pwm-cells = <3>;
+                       status = "disabled";
+               };
+
                tpm5: tpm@40260000 {
                        compatible = "fsl,imx7ulp-tpm";
                        reg = <0x40260000 0x1000>;
                        clock-names = "ipg", "per";
                };
 
+               usbotg1: usb@40330000 {
+                       compatible = "fsl,imx7ulp-usb", "fsl,imx6ul-usb";
+                       reg = <0x40330000 0x200>;
+                       interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&pcc2 IMX7ULP_CLK_USB0>;
+                       phys = <&usbphy1>;
+                       fsl,usbmisc = <&usbmisc1 0>;
+                       ahb-burst-config = <0x0>;
+                       tx-burst-size-dword = <0x8>;
+                       rx-burst-size-dword = <0x8>;
+                       status = "disabled";
+               };
+
+               usbmisc1: usbmisc@40330200 {
+                       compatible = "fsl,imx7ulp-usbmisc", "fsl,imx7d-usbmisc";
+                       #index-cells = <1>;
+                       reg = <0x40330200 0x200>;
+               };
+
+               usbphy1: usb-phy@0x40350000 {
+                       compatible = "fsl,imx7ulp-usbphy", "fsl,imx6ul-usbphy";
+                       reg = <0x40350000 0x1000>;
+                       interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&pcc2 IMX7ULP_CLK_USB_PHY>;
+                       #phy-cells = <0>;
+               };
+
                usdhc0: mmc@40370000 {
                        compatible = "fsl,imx7ulp-usdhc", "fsl,imx6sx-usdhc";
                        reg = <0x40370000 0x10000>;
index 1612a86..602f74d 100644 (file)
@@ -62,6 +62,9 @@
                compatible = "arm,versatile-flash", "cfi-flash";
                reg = <0x24000000 0x02000000>;
                bank-width = <4>;
+               partitions {
+                       compatible = "arm,arm-firmware-suite";
+               };
        };
 
        fpga {
index e2b1ab9..ae75a1d 100644 (file)
@@ -87,7 +87,7 @@
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <3300000>;
 
-               gpios = <&gpio2 30 GPIO_ACTIVE_LOW>;
+               gpios = <&gpio2 30 GPIO_ACTIVE_HIGH>;
                gpios-states = <1>;
                states = <3300000 1
                          1800000 0>;
diff --git a/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit-28.dts b/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit-28.dts
new file mode 100644 (file)
index 0000000..07ac99b
--- /dev/null
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/dts-v1/;
+
+/*
+ * There are two types of 4.3" LCD, Type 15 and Type 28.
+ * By default, type 15 was used.  This device tree file
+ * uses the timing for the type 28 LCD
+ */
+
+#include "logicpd-torpedo-37xx-devkit.dts"
+
+&lcd0 {
+
+       label = "28";
+
+       panel-timing {
+               clock-frequency = <9000000>;
+               hactive = <480>;
+               vactive = <272>;
+               hfront-porch = <3>;
+               hback-porch = <2>;
+               hsync-len = <42>;
+               vback-porch = <3>;
+               vfront-porch = <2>;
+               vsync-len = <11>;
+               hsync-active = <1>;
+               vsync-active = <1>;
+               de-active = <1>;
+               pixelclk-active = <0>;
+       };
+};
diff --git a/arch/arm/boot/dts/ls1021a-tsn.dts b/arch/arm/boot/dts/ls1021a-tsn.dts
new file mode 100644 (file)
index 0000000..5b76890
--- /dev/null
@@ -0,0 +1,289 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright 2016-2018 NXP Semiconductors
+ * Copyright 2019 Vladimir Oltean <olteanv@gmail.com>
+ */
+
+/dts-v1/;
+#include "ls1021a.dtsi"
+
+/ {
+       model = "NXP LS1021A-TSN Board";
+
+       sys_mclk: clock-mclk {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <24576000>;
+       };
+
+       reg_vdda_codec: regulator-3V3 {
+               compatible = "regulator-fixed";
+               regulator-name = "3P3V";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+       };
+
+       reg_vddio_codec: regulator-2V5 {
+               compatible = "regulator-fixed";
+               regulator-name = "2P5V";
+               regulator-min-microvolt = <2500000>;
+               regulator-max-microvolt = <2500000>;
+               regulator-always-on;
+       };
+};
+
+&dspi0 {
+       bus-num = <0>;
+       status = "okay";
+
+       /* ADG704BRMZ 1:4 SPI mux/demux */
+       sja1105: ethernet-switch@1 {
+               reg = <0x1>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nxp,sja1105t";
+               /* 12 MHz */
+               spi-max-frequency = <12000000>;
+               /* Sample data on trailing clock edge */
+               spi-cpha;
+               /* SPI controller settings for SJA1105 timing requirements */
+               fsl,spi-cs-sck-delay = <1000>;
+               fsl,spi-sck-cs-delay = <1000>;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               /* ETH5 written on chassis */
+                               label = "swp5";
+                               phy-handle = <&rgmii_phy6>;
+                               phy-mode = "rgmii-id";
+                               reg = <0>;
+                       };
+
+                       port@1 {
+                               /* ETH2 written on chassis */
+                               label = "swp2";
+                               phy-handle = <&rgmii_phy3>;
+                               phy-mode = "rgmii-id";
+                               reg = <1>;
+                       };
+
+                       port@2 {
+                               /* ETH3 written on chassis */
+                               label = "swp3";
+                               phy-handle = <&rgmii_phy4>;
+                               phy-mode = "rgmii-id";
+                               reg = <2>;
+                       };
+
+                       port@3 {
+                               /* ETH4 written on chassis */
+                               label = "swp4";
+                               phy-handle = <&rgmii_phy5>;
+                               phy-mode = "rgmii-id";
+                               reg = <3>;
+                       };
+
+                       port@4 {
+                               /* Internal port connected to eth2 */
+                               ethernet = <&enet2>;
+                               phy-mode = "rgmii";
+                               reg = <4>;
+
+                               fixed-link {
+                                       speed = <1000>;
+                                       full-duplex;
+                               };
+                       };
+               };
+       };
+};
+
+&enet0 {
+       tbi-handle = <&tbi0>;
+       phy-handle = <&sgmii_phy2>;
+       phy-mode = "sgmii";
+       status = "okay";
+};
+
+&enet1 {
+       tbi-handle = <&tbi1>;
+       phy-handle = <&sgmii_phy1>;
+       phy-mode = "sgmii";
+       status = "okay";
+};
+
+/* RGMII delays added via PCB traces */
+&enet2 {
+       phy-mode = "rgmii";
+       status = "okay";
+
+       fixed-link {
+               speed = <1000>;
+               full-duplex;
+       };
+};
+
+&esdhc {
+       status = "okay";
+};
+
+&i2c0 {
+       status = "okay";
+
+       /* 3 axis accelerometer */
+       accelerometer@1e {
+               compatible = "fsl,fxls8471";
+               position = <0>;
+               reg = <0x1e>;
+       };
+
+       /* Audio codec (SAI2) */
+       audio-codec@2a {
+               compatible = "fsl,sgtl5000";
+               VDDIO-supply = <&reg_vddio_codec>;
+               VDDA-supply = <&reg_vdda_codec>;
+               #sound-dai-cells = <0>;
+               clocks = <&sys_mclk>;
+               reg = <0x2a>;
+       };
+
+       /* Current sensing circuit for 1V VDDCORE PMIC rail */
+       current-sensor@44 {
+               compatible = "ti,ina220";
+               shunt-resistor = <1000>;
+               reg = <0x44>;
+       };
+
+       /* Current sensing circuit for 12V VCC rail */
+       current-sensor@45 {
+               compatible = "ti,ina220";
+               shunt-resistor = <1000>;
+               reg = <0x45>;
+       };
+
+       /* Thermal monitor - case */
+       temperature-sensor@48 {
+               compatible = "national,lm75";
+               reg = <0x48>;
+       };
+
+       /* Thermal monitor - chip */
+       temperature-sensor@4c {
+               compatible = "ti,tmp451";
+               reg = <0x4c>;
+       };
+
+       eeprom@51 {
+               compatible = "atmel,24c32";
+               reg = <0x51>;
+       };
+
+       /* Unsupported devices:
+        * - FXAS21002C Gyroscope at 0x20
+        * - TI ADS7924 4-channel ADC at 0x49
+        */
+};
+
+&ifc {
+       status = "disabled";
+};
+
+&lpuart0 {
+       status = "okay";
+};
+
+&lpuart3 {
+       status = "okay";
+};
+
+&mdio0 {
+       /* AR8031 */
+       sgmii_phy1: ethernet-phy@1 {
+               reg = <0x1>;
+       };
+
+       /* AR8031 */
+       sgmii_phy2: ethernet-phy@2 {
+               reg = <0x2>;
+       };
+
+       /* BCM5464 quad PHY */
+       rgmii_phy3: ethernet-phy@3 {
+               reg = <0x3>;
+       };
+
+       rgmii_phy4: ethernet-phy@4 {
+               reg = <0x4>;
+       };
+
+       rgmii_phy5: ethernet-phy@5 {
+               reg = <0x5>;
+       };
+
+       rgmii_phy6: ethernet-phy@6 {
+               reg = <0x6>;
+       };
+
+       /* SGMII PCS for enet0 */
+       tbi0: tbi-phy@1f {
+               reg = <0x1f>;
+               device_type = "tbi-phy";
+       };
+};
+
+&mdio1 {
+       /* SGMII PCS for enet1 */
+       tbi1: tbi-phy@1f {
+               reg = <0x1f>;
+               device_type = "tbi-phy";
+       };
+};
+
+&qspi {
+       status = "okay";
+
+       flash@0 {
+               /* Rev. A uses 64MB flash, Rev. B & C use 32MB flash */
+               compatible = "jedec,spi-nor", "s25fl256s1", "s25fl512s";
+               spi-max-frequency = <20000000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               reg = <0>;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition@0 {
+                               label = "RCW";
+                               reg = <0x0 0x40000>;
+                       };
+
+                       partition@40000 {
+                               label = "U-Boot";
+                               reg = <0x40000 0x300000>;
+                       };
+
+                       partition@340000 {
+                               label = "U-Boot Env";
+                               reg = <0x340000 0x100000>;
+                       };
+               };
+       };
+};
+
+&sai2 {
+       status = "okay";
+};
+
+&sata {
+       status = "okay";
+};
+
+&uart0 {
+       status = "okay";
+};
index 8841783..c4447f6 100644 (file)
@@ -1,48 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
 /*
  * Copyright 2014 Carlo Caione <carlo@caione.org>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library 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 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 General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 #include <dt-bindings/interrupt-controller/irq.h>
index 997e69c..98e1c94 100644 (file)
@@ -1,48 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
 /*
  * Copyright 2014 Carlo Caione <carlo@caione.org>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library 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 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 General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 /dts-v1/;
index 6558525..2d31b7c 100644 (file)
@@ -1,48 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
 /*
  * Copyright 2014 Carlo Caione <carlo@caione.org>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library 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 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 General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 #include "meson.dtsi"
index 8686abd..61ec929 100644 (file)
@@ -1,43 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
 /*
  * Copyright 2014 Beniamino Galvani <b.galvani@gmail.com>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library 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 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 General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 /dts-v1/;
index 40c11b6..5a7e3e5 100644 (file)
@@ -1,46 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
 /*
  * Copyright 2014 Carlo Caione <carlo@caione.org>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library 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 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 General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public License
- *     along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 #include <dt-bindings/clock/meson8b-clkc.h>
                };
        };
 
+       mmcbus: bus@c8000000 {
+               compatible = "simple-bus";
+               reg = <0xc8000000 0x8000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0xc8000000 0x8000>;
+
+               dmcbus: bus@6000 {
+                       compatible = "simple-bus";
+                       reg = <0x6000 0x400>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x6000 0x400>;
+
+                       canvas: video-lut@20 {
+                               compatible = "amlogic,meson8-canvas",
+                                            "amlogic,canvas";
+                               reg = <0x20 0x14>;
+                       };
+               };
+       };
+
        apb: bus@d0000000 {
                compatible = "simple-bus";
                reg = <0xd0000000 0x200000>;
index 9bf4249..96d239d 100644 (file)
        phy-handle = <&eth_phy0>;
        phy-mode = "rmii";
 
-       snps,reset-gpio = <&gpio GPIOH_4 0>;
-       snps,reset-delays-us = <0 10000 1000000>;
-       snps,reset-active-low;
-
        mdio {
                compatible = "snps,dwmac-mdio";
                #address-cells = <1>;
                eth_phy0: ethernet-phy@0 {
                        /* IC Plus IP101A/G (0x02430c54) */
                        reg = <0>;
+
+                       reset-assert-us = <10000>;
+                       reset-deassert-us = <10000>;
+                       reset-gpios = <&gpio GPIOH_4 GPIO_ACTIVE_LOW>;
+
                        icplus,select-interrupt;
                        interrupt-parent = <&gpio_intc>;
                        /* GPIOH_3 */
index 08ddd7f..bb27b34 100644 (file)
@@ -1,50 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
 /*
  * Copyright 2015 Endless Mobile, Inc.
  * Author: Carlo Caione <carlo@endlessm.com>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library 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 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 General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public License
- *     along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 /dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+
 #include "meson8b.dtsi"
 
 / {
                device_type = "memory";
                reg = <0x40000000 0x40000000>;
        };
+
+       iio-hwmon {
+               compatible = "iio-hwmon";
+               io-channels = <&saradc 8>;
+       };
+
+       vcck: regulator-vcck {
+               compatible = "pwm-regulator";
+
+               regulator-name = "VCCK";
+               regulator-min-microvolt = <860000>;
+               regulator-max-microvolt = <1140000>;
+
+               pwms = <&pwm_cd 0 1148 0>;
+               pwm-dutycycle-range = <100 0>;
+
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       vcc_1v8: regulator-vcc1v8 {
+               compatible = "regulator-fixed";
+
+               regulator-name = "VCC1V8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+
+               vin-supply = <&vcc_3v3>;
+       };
+
+       vcc_3v3: regulator-vcc3v3 {
+               compatible = "regulator-fixed";
+
+               regulator-name = "VCC3V3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+
+               vin-supply = <&vcc_5v>;
+       };
+
+       vcc_5v: regulator-vcc5v {
+               compatible = "regulator-fixed";
+
+               regulator-name = "VCC5V";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+
+               regulator-boot-on;
+               regulator-always-on;
+       };
+};
+
+&cpu0 {
+       cpu-supply = <&vcck>;
+};
+
+&ethmac {
+       status = "okay";
+
+       pinctrl-0 = <&eth_rmii_pins>;
+       pinctrl-names = "default";
+
+       phy-handle = <&eth_phy0>;
+       phy-mode = "rmii";
+
+       mdio {
+               compatible = "snps,dwmac-mdio";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               eth_phy0: ethernet-phy@0 {
+                       /* IC Plus IP101A/G (0x02430c54) */
+                       reg = <0>;
+
+                       reset-assert-us = <10000>;
+                       reset-deassert-us = <10000>;
+                       reset-gpios = <&gpio GPIOH_4 GPIO_ACTIVE_LOW>;
+
+                       icplus,select-interrupt;
+                       interrupt-parent = <&gpio_intc>;
+                       /* GPIOH_3 */
+                       interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
+               };
+       };
+};
+
+&saradc {
+       status = "okay";
+       vref-supply = <&vcc_1v8>;
+};
+
+&sdio {
+       status = "okay";
+
+       pinctrl-0 = <&sd_b_pins>;
+       pinctrl-names = "default";
+
+       /* SD card */
+       sd_card_slot: slot@1 {
+               compatible = "mmc-slot";
+               reg = <1>;
+               status = "okay";
+
+               bus-width = <4>;
+               no-sdio;
+               cap-mmc-highspeed;
+               cap-sd-highspeed;
+               disable-wp;
+
+               cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_LOW>;
+
+               vmmc-supply = <&vcc_3v3>;
+       };
+};
+
+&pwm_cd {
+       status = "okay";
+       pinctrl-0 = <&pwm_c1_pins>;
+       pinctrl-names = "default";
+       clocks = <&clkc CLKID_XTAL>;
+       clock-names = "clkin0";
 };
 
 &uart_AO {
        pinctrl-0 = <&uart_ao_a_pins>;
        pinctrl-names = "default";
 };
+
+&usb0 {
+       status = "okay";
+};
+
+&usb0_phy {
+       status = "okay";
+};
+
+&usb1 {
+       status = "okay";
+};
+
+&usb1_phy {
+       status = "okay";
+};
index f3ad939..86c4614 100644 (file)
@@ -1,47 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
 /*
  * Copyright 2015 Endless Mobile, Inc.
  * Author: Carlo Caione <carlo@endlessm.com>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library 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 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 General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public License
- *     along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 /dts-v1/;
 &ethmac {
        status = "okay";
 
-       snps,reset-gpio = <&gpio GPIOH_4 GPIO_ACTIVE_HIGH>;
-       snps,reset-active-low;
-       snps,reset-delays-us = <0 10000 30000>;
-
        pinctrl-0 = <&eth_rgmii_pins>;
        pinctrl-names = "default";
 
                /* Realtek RTL8211F (0x001cc916) */
                eth_phy: ethernet-phy@0 {
                        reg = <0>;
+
+                       reset-assert-us = <10000>;
+                       reset-deassert-us = <30000>;
+                       reset-gpios = <&gpio GPIOH_4 GPIO_ACTIVE_LOW>;
+
                        interrupt-parent = <&gpio_intc>;
                        /* GPIOH_3 */
                        interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
index ec67f49..fba2c70 100644 (file)
@@ -1,47 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
 /*
  * Copyright 2015 Endless Mobile, Inc.
  * Author: Carlo Caione <carlo@endlessm.com>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library 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 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 General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public License
- *     along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 #include <dt-bindings/clock/meson8b-clkc.h>
                };
        };
 
+       mmcbus: bus@c8000000 {
+               compatible = "simple-bus";
+               reg = <0xc8000000 0x8000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0xc8000000 0x8000>;
+
+               dmcbus: bus@6000 {
+                       compatible = "simple-bus";
+                       reg = <0x6000 0x400>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x6000 0x400>;
+
+                       canvas: video-lut@48 {
+                               compatible = "amlogic,meson8b-canvas",
+                                            "amlogic,canvas";
+                               reg = <0x48 0x14>;
+                       };
+               };
+       };
+
        apb: bus@d0000000 {
                compatible = "simple-bus";
                reg = <0xd0000000 0x200000>;
index 29d830a..d54477b 100644 (file)
 
        amlogic,tx-delay-ns = <4>;
 
-       snps,reset-gpio = <&gpio GPIOH_4 0>;
-       snps,reset-delays-us = <0 10000 1000000>;
-       snps,reset-active-low;
-
        mdio {
                compatible = "snps,dwmac-mdio";
                #address-cells = <1>;
                eth_phy0: ethernet-phy@0 {
                        /* Realtek RTL8211F (0x001cc916) */
                        reg = <0>;
+
+                       reset-assert-us = <10000>;
+                       reset-deassert-us = <30000>;
+                       reset-gpios = <&gpio GPIOH_4 GPIO_ACTIVE_LOW>;
                };
        };
 };
                                regulator-always-on;
                        };
 
-                       DCDC2 {
-                               regulator-name = "VDDAO";
+                       vddee: DCDC2 {
+                               /* the output is also used as VDDAO */
+                               regulator-name = "VDD_EE";
                                regulator-min-microvolt = <950000>;
                                regulator-max-microvolt = <1150000>;
                                regulator-boot-on;
        };
 };
 
+&mali {
+       mali-supply = <&vddee>;
+};
+
 &saradc {
        status = "okay";
        vref-supply = <&vddio_ao1v8>;
index bb87b25..5bde7f5 100644 (file)
        compatible = "amlogic,meson8m2-clkc", "amlogic,meson8-clkc";
 };
 
+&dmcbus {
+       /* the offset of the canvas registers has changed compared to Meson8 */
+       /delete-node/ video-lut@20;
+
+       canvas: video-lut@48 {
+               compatible = "amlogic,meson8m2-canvas", "amlogic,canvas";
+               reg = <0x48 0x14>;
+       };
+};
+
 &ethmac {
        compatible = "amlogic,meson8m2-dwmac", "snps,dwmac";
        reg = <0xc9410000 0x10000
index 5059eca..bea05dc 100644 (file)
 
                target-module@20000 {                   /* 0x48020000, ap 3 06.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "uart3";
                        reg = <0x20050 0x4>,
                              <0x20054 0x4>,
                              <0x20058 0x4>;
 
                target-module@6a000 {                   /* 0x4806a000, ap 26 18.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "uart1";
                        reg = <0x6a050 0x4>,
                              <0x6a054 0x4>,
                              <0x6a058 0x4>;
 
                target-module@6c000 {                   /* 0x4806c000, ap 28 20.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "uart2";
                        reg = <0x6c050 0x4>,
                              <0x6c054 0x4>,
                              <0x6c058 0x4>;
 
                target-module@6e000 {                   /* 0x4806e000, ap 30 1c.1 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "uart4";
                        reg = <0x6e050 0x4>,
                              <0x6e054 0x4>,
                              <0x6e058 0x4>;
 
                target-module@9c000 {                   /* 0x4809c000, ap 53 36.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mmc1";
                        reg = <0x9c000 0x4>,
                              <0x9c010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@ad000 {                   /* 0x480ad000, ap 63 50.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mmc3";
                        reg = <0xad000 0x4>,
                              <0xad010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@b4000 {                   /* 0x480b4000, ap 67 46.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mmc2";
                        reg = <0xb4000 0x4>,
                              <0xb4010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@d1000 {                   /* 0x480d1000, ap 73 44.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mmc4";
                        reg = <0xd1000 0x4>,
                              <0xd1010 0x4>;
                        reg-names = "rev", "sysc";
 
                target-module@d5000 {                   /* 0x480d5000, ap 75 4e.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "mmc5";
                        reg = <0xd5000 0x4>,
                              <0xd5010 0x4>;
                        reg-names = "rev", "sysc";
index 8ac24e3..8a6721d 100644 (file)
 
        gpio_keys_pins: gpio-keys-pins {
                pinctrl-single,pins = <
-                       MFP_PIN_PXA300(14) MFP_AF0      /* SCK          */
-                       MFP_PIN_PXA300(115) MFP_AF0     /* MOSI         */
-                       MFP_PIN_PXA300(119) MFP_AF0     /* MISO         */
+                       MFP_PIN_PXA300(14) MFP_AF0      /* on-off       */
+                       MFP_PIN_PXA300(115) MFP_AF0     /* rescue boot  */
+                       MFP_PIN_PXA300(119) MFP_AF0     /* setup        */
                >;
                pinctrl-single,low-power-mode = MFP_LPM(MFP_LPM_FLOAT);
        };
index 65d8250..12b1594 100644 (file)
@@ -41,6 +41,8 @@
        };
 
        charger: charger {
+               pinctrl-names = "default";
+               pinctrl-0 = <&charger_pins>;
                compatible = "gpio-charger";
                charger-type = "mains";
                gpios = <&gpio 101 GPIO_ACTIVE_LOW>;
 };
 
 &keys {
+       pinctrl-0 = <&gpio_keys_pins &dock_detect_pins>;
        dock-detect {
                label = "dock detect";
-               gpios = <&gpio 116 GPIO_ACTIVE_HIGH>;
+               gpios = <&gpio 116 GPIO_ACTIVE_LOW>;
                linux,code = <KEY_F5>;
        };
 };
                pinctrl-single,low-power-mode = MFP_LPM(MFP_LPM_FLOAT);
        };
 
+       charger_pins: charger_pins {
+               pinctrl-single,pins = <
+                       MFP_PIN_PXA300(31) MFP_AF0      /* PEN2 */
+               >;
+               pinctrl-single,low-power-mode = MFP_LPM(MFP_LPM_PULL_HIGH);
+               pinctrl-single,bias-pullup = MPF_PULL_UP;
+       };
+
+       dock_detect_pins: dock_detect_pins {
+               pinctrl-single,pins = <
+                       MFP_PIN_PXA300(116) MFP_AF0     /* DOCK_DETECT  */
+               >;
+               pinctrl-single,low-power-mode = MFP_LPM(MFP_LPM_PULL_HIGH);
+               pinctrl-single,bias-pullup = MPF_PULL_UP;
+       };
+
        lcdc_pins: lcdc-pins {
                pinctrl-single,pins = <
                        MFP_PIN_PXA300(54) MFP_AF1      /* LDD_0        */
index 5f9e375..a70560a 100644 (file)
                st,invalid-input-detect-mute;
                /* 2 (half-bridge) and 1 (full-bridge) on-board power */
                st,output-conf = /bits/ 8 <0x1>;
+               st,ch1-output-mapping = /bits/ 8 <0>;
+               st,ch2-output-mapping = /bits/ 8 <1>;
+               st,ch3-output-mapping = /bits/ 8 <2>;
                st,needs_esd_watchdog;
        };
 };
index e1e607f..c237a0e 100644 (file)
 #define MFP_DS13X      < (0x7 << 10) MFP_DSMSK >
 
 /*
+ * MFP bias pull mode for pins.
+ * Example of use: pinctrl-single,bias-pullup = MPF_PULL_UP;
+ */
+#define MPF_PULL_MSK   (0x7 << 13)
+#define MPF_PULL_DOWN  < (0x5 << 13) (0x5 << 13) 0 MPF_PULL_MSK >
+#define MPF_PULL_UP    < (0x6 << 13) (0x6 << 13) 0 MPF_PULL_MSK >
+
+/*
  * MFP low power mode for pins.
  * Example of use:
  *   pinctrl-single,low-power-mode = MFP_LPM(MFP_LPM_PULL_LOW|MFP_LPM_EDGE_FALL);
index 65975df..8b79b41 100644 (file)
                };
 
                replicator {
-                       compatible = "arm,coresight-replicator";
+                       compatible = "arm,coresight-static-replicator";
 
                        clocks = <&rpmcc RPM_QDSS_CLK>;
                        clock-names = "apb_pclk";
                };
 
                funnel@1a04000 {
-                       compatible = "arm,coresight-funnel", "arm,primecell";
+                       compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                        reg = <0x1a04000 0x1000>;
 
                        clocks = <&rpmcc RPM_QDSS_CLK>;
index 643c57f..bf402ae 100644 (file)
                };
        };
 
+       vibrator {
+               compatible = "gpio-vibrator";
+               enable-gpios = <&msmgpio 86 GPIO_ACTIVE_HIGH>;
+               vcc-supply = <&pm8941_l18>;
+       };
+
        smd {
                rpm {
                        rpm_requests {
index b3b0473..3487daf 100644 (file)
                        };
                };
 
+               i2c2_pins: i2c2 {
+                       mux {
+                               pins = "gpio6", "gpio7";
+                               function = "blsp_i2c2";
+
+                               drive-strength = <2>;
+                               bias-disable;
+                       };
+               };
+
                i2c3_pins: i2c3 {
                        mux {
                                pins = "gpio10", "gpio11";
                        };
                };
 
+               i2c11_pins: i2c11 {
+                       mux {
+                               pins = "gpio83", "gpio84";
+                               function = "blsp_i2c11";
+
+                               drive-strength = <2>;
+                               bias-disable;
+                       };
+               };
+
                i2c12_pins: i2c12 {
                        mux {
                                pins = "gpio87", "gpio88";
                                input-enable;
                        };
                };
+
+               touch_pin: touch {
+                       int {
+                               pins = "gpio5";
+                               function = "gpio";
+
+                               drive-strength = <2>;
+                               bias-disable;
+                               input-enable;
+                       };
+
+                       reset {
+                               pins = "gpio8";
+                               function = "gpio";
+
+                               drive-strength = <2>;
+                               bias-pull-up;
+                       };
+               };
+
+               panel_pin: panel {
+                       te {
+                               pins = "gpio12";
+                               function = "mdp_vsync";
+
+                               drive-strength = <2>;
+                               bias-disable;
+                       };
+               };
        };
 
        sdhci@f9824900 {
                };
        };
 
+       i2c@f9967000 {
+               status = "ok";
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2c11_pins>;
+               clock-frequency = <355000>;
+               qcom,src-freq = <50000000>;
+
+               led-controller@38 {
+                       compatible = "ti,lm3630a";
+                       status = "ok";
+                       reg = <0x38>;
+
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       led@0 {
+                               reg = <0>;
+                               led-sources = <0 1>;
+                               label = "lcd-backlight";
+                               default-brightness = <200>;
+                       };
+               };
+       };
+
        i2c@f9968000 {
                status = "ok";
                pinctrl-names = "default";
                };
        };
 
+       i2c@f9924000 {
+               status = "ok";
+
+               clock-frequency = <355000>;
+               qcom,src-freq = <50000000>;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2c2_pins>;
+
+               synaptics@70 {
+                       compatible = "syna,rmi4-i2c";
+                       reg = <0x70>;
+
+                       interrupts-extended = <&msmgpio 5 IRQ_TYPE_EDGE_FALLING>;
+                       vdd-supply = <&pm8941_l22>;
+                       vio-supply = <&pm8941_lvs3>;
+
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&touch_pin>;
+
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       rmi4-f01@1 {
+                               reg = <0x1>;
+                               syna,nosleep-mode = <1>;
+                       };
+
+                       rmi4-f12@12 {
+                               reg = <0x12>;
+                               syna,sensor-type = <1>;
+                       };
+               };
+       };
+
        i2c@f9925000 {
                status = "ok";
                pinctrl-names = "default";
                        };
                };
        };
+
+       mdss@fd900000 {
+               status = "ok";
+
+               mdp@fd900000 {
+                       status = "ok";
+               };
+
+               dsi@fd922800 {
+                       status = "ok";
+
+                       vdda-supply = <&pm8941_l2>;
+                       vdd-supply = <&pm8941_lvs3>;
+                       vddio-supply = <&pm8941_l12>;
+
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       ports {
+                               port@1 {
+                                       endpoint {
+                                               remote-endpoint = <&panel_in>;
+                                               data-lanes = <0 1 2 3>;
+                                       };
+                               };
+                       };
+
+                       panel: panel@0 {
+                               reg = <0>;
+                               compatible = "lg,acx467akm-7";
+
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&panel_pin>;
+
+                               port {
+                                       panel_in: endpoint {
+                                               remote-endpoint = <&dsi0_out>;
+                                       };
+                               };
+                       };
+               };
+
+               dsi-phy@fd922a00 {
+                       status = "ok";
+
+                       vddio-supply = <&pm8941_l12>;
+               };
+       };
 };
 
 &spmi_bus {
index 45b5c8e..369e58f 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/clock/qcom,gcc-msm8974.h>
+#include <dt-bindings/clock/qcom,mmcc-msm8974.h>
 #include <dt-bindings/clock/qcom,rpmcc.h>
 #include <dt-bindings/reset/qcom,gcc-msm8974.h>
 #include <dt-bindings/gpio/gpio.h>
                };
 
                funnel@fc31b000 {
-                       compatible = "arm,coresight-funnel", "arm,primecell";
+                       compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                        reg = <0xfc31b000 0x1000>;
 
                        clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                };
 
                funnel@fc31a000 {
-                       compatible = "arm,coresight-funnel", "arm,primecell";
+                       compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                        reg = <0xfc31a000 0x1000>;
 
                        clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                };
 
                funnel@fc345000 { /* KPSS funnel only 4 inputs are used */
-                       compatible = "arm,coresight-funnel", "arm,primecell";
+                       compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                        reg = <0xfc345000 0x1000>;
 
                        clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                                };
                        };
                };
+
+               mdss: mdss@fd900000 {
+                       status = "disabled";
+
+                       compatible = "qcom,mdss";
+                       reg = <0xfd900000 0x100>,
+                             <0xfd924000 0x1000>;
+                       reg-names = "mdss_phys",
+                                   "vbif_phys";
+
+                       power-domains = <&mmcc MDSS_GDSC>;
+
+                       clocks = <&mmcc MDSS_AHB_CLK>,
+                                <&mmcc MDSS_AXI_CLK>,
+                                <&mmcc MDSS_VSYNC_CLK>;
+                       clock-names = "iface",
+                                     "bus",
+                                     "vsync";
+
+                       interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       mdp: mdp@fd900000 {
+                               status = "disabled";
+
+                               compatible = "qcom,mdp5";
+                               reg = <0xfd900100 0x22000>;
+                               reg-names = "mdp_phys";
+
+                               interrupt-parent = <&mdss>;
+                               interrupts = <0 0>;
+
+                               clocks = <&mmcc MDSS_AHB_CLK>,
+                                        <&mmcc MDSS_AXI_CLK>,
+                                        <&mmcc MDSS_MDP_CLK>,
+                                        <&mmcc MDSS_VSYNC_CLK>;
+                               clock-names = "iface",
+                                             "bus",
+                                             "core",
+                                             "vsync";
+
+                               ports {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       port@0 {
+                                               reg = <0>;
+                                               mdp5_intf1_out: endpoint {
+                                                       remote-endpoint = <&dsi0_in>;
+                                               };
+                                       };
+                               };
+                       };
+
+                       dsi0: dsi@fd922800 {
+                               status = "disabled";
+
+                               compatible = "qcom,mdss-dsi-ctrl";
+                               reg = <0xfd922800 0x1f8>;
+                               reg-names = "dsi_ctrl";
+
+                               interrupt-parent = <&mdss>;
+                               interrupts = <4 IRQ_TYPE_LEVEL_HIGH>;
+
+                               assigned-clocks = <&mmcc BYTE0_CLK_SRC>,
+                                                 <&mmcc PCLK0_CLK_SRC>;
+                               assigned-clock-parents = <&dsi_phy0 0>,
+                                                        <&dsi_phy0 1>;
+
+                               clocks = <&mmcc MDSS_MDP_CLK>,
+                                        <&mmcc MDSS_AHB_CLK>,
+                                        <&mmcc MDSS_AXI_CLK>,
+                                        <&mmcc MDSS_BYTE0_CLK>,
+                                        <&mmcc MDSS_PCLK0_CLK>,
+                                        <&mmcc MDSS_ESC0_CLK>,
+                                        <&mmcc MMSS_MISC_AHB_CLK>;
+                               clock-names = "mdp_core",
+                                             "iface",
+                                             "bus",
+                                             "byte",
+                                             "pixel",
+                                             "core",
+                                             "core_mmss";
+
+                               phys = <&dsi_phy0>;
+                               phy-names = "dsi-phy";
+
+                               ports {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       port@0 {
+                                               reg = <0>;
+                                               dsi0_in: endpoint {
+                                                       remote-endpoint = <&mdp5_intf1_out>;
+                                               };
+                                       };
+
+                                       port@1 {
+                                               reg = <1>;
+                                               dsi0_out: endpoint {
+                                               };
+                                       };
+                               };
+                       };
+
+                       dsi_phy0: dsi-phy@fd922a00 {
+                               status = "disabled";
+
+                               compatible = "qcom,dsi-phy-28nm-hpm";
+                               reg = <0xfd922a00 0xd4>,
+                                     <0xfd922b00 0x280>,
+                                     <0xfd922d80 0x30>;
+                               reg-names = "dsi_pll",
+                                           "dsi_phy",
+                                           "dsi_phy_regulator";
+
+                               #clock-cells = <1>;
+                               #phy-cells = <0>;
+                               qcom,dsi-phy-index = <0>;
+
+                               clocks = <&mmcc MDSS_AHB_CLK>;
+                               clock-names = "iface";
+                       };
+               };
        };
 
        smd {
index 474baa0..07d611d 100644 (file)
@@ -20,7 +20,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial0:115200n8";
        };
 
index ff24301..99acfe4 100644 (file)
@@ -8,6 +8,7 @@
 /dts-v1/;
 #include "r7s72100.dtsi"
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
 #include <dt-bindings/pinctrl/r7s72100-pinctrl.h>
 
 / {
                reg = <0x08000000 0x02000000>;
        };
 
+       keyboard {
+               compatible = "gpio-keys";
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&keyboard_pins>;
+
+               key-1 {
+                       interrupt-parent = <&irqc>;
+                       interrupts = <3 IRQ_TYPE_EDGE_BOTH>;
+                       linux,code = <KEY_1>;
+                       label = "SW1";
+                       wakeup-source;
+               };
+
+               key-2 {
+                       interrupt-parent = <&irqc>;
+                       interrupts = <2 IRQ_TYPE_EDGE_BOTH>;
+                       linux,code = <KEY_2>;
+                       label = "SW2";
+                       wakeup-source;
+               };
+
+               key-3 {
+                       interrupt-parent = <&irqc>;
+                       interrupts = <5 IRQ_TYPE_EDGE_BOTH>;
+                       linux,code = <KEY_3>;
+                       label = "SW3";
+                       wakeup-source;
+               };
+       };
+
        lbsc {
                #address-cells = <1>;
                #size-cells = <1>;
                         <RZA1_PINMUX(1, 7, 1)>;        /* RIIC3SDA */
        };
 
+       keyboard_pins: keyboard {
+               pinmux = <RZA1_PINMUX(1, 9, 3)>,        /* IRQ3 */
+                        <RZA1_PINMUX(1, 8, 3)>,        /* IRQ2 */
+                        <RZA1_PINMUX(1, 11, 3)>;       /* IRQ5 */
+       };
+
        /* Serial Console */
        scif2_pins: serial2 {
                pinmux = <RZA1_PINMUX(3, 0, 6)>,        /* TxD2 */
index 2211f88..d03dcd9 100644 (file)
                        status = "disabled";
                };
 
+               irqc: interrupt-controller@fcfef800 {
+                       compatible = "renesas,r7s72100-irqc",
+                                    "renesas,rza1-irqc";
+                       #interrupt-cells = <2>;
+                       #address-cells = <0>;
+                       interrupt-controller;
+                       reg = <0xfcfef800 0x6>;
+                       interrupt-map =
+                               <0 0 &gic GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+                               <1 0 &gic GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
+                               <2 0 &gic GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+                               <3 0 &gic GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+                               <4 0 &gic GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
+                               <5 0 &gic GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
+                               <6 0 &gic GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
+                               <7 0 &gic GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-map-mask = <7 0>;
+               };
+
                mtu2: timer@fcff0000 {
                        compatible = "renesas,mtu2-r7s72100", "renesas,mtu2";
                        reg = <0xfcff0000 0x400>;
index 991e09d..d062d02 100644 (file)
@@ -9,6 +9,7 @@
 /dts-v1/;
 #include "r7s9210.dtsi"
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
 #include <dt-bindings/pinctrl/r7s9210-pinctrl.h>
 
 / {
@@ -17,6 +18,8 @@
 
        aliases {
                serial0 = &scif4;
+               ethernet0 = &ether0;
+               ethernet1 = &ether1;
        };
 
        chosen {
                stdout-path = "serial0:115200n8";
        };
 
-       memory@40000000 {
-               device_type = "memory";
-               reg = <0x40000000 0x00800000>;   /* HyperRAM */
+       keyboard {
+               compatible = "gpio-keys";
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&keyboard_pins>;
+
+               key-3 {
+                       interrupt-parent = <&irqc>;
+                       interrupts = <0 IRQ_TYPE_EDGE_BOTH>;
+                       linux,code = <KEY_3>;
+                       label = "SW3";
+                       wakeup-source;
+               };
        };
 
        lbsc {
                        gpios = <&pinctrl RZA2_PIN(PORTC, 1) GPIO_ACTIVE_HIGH>;
                };
        };
+
+       memory@40000000 {
+               device_type = "memory";
+               reg = <0x40000000 0x00800000>;   /* HyperRAM */
+       };
+};
+
+&ehci0 {
+       status = "okay";
+};
+
+&ehci1 {
+       status = "okay";
+};
+
+&ether0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&eth0_pins>;
+       status = "okay";
+       renesas,no-ether-link;
+       phy-handle = <&phy0>;
+       phy0: ethernet-phy@0 {
+               reg = <0>;
+       };
+};
+
+&ether1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&eth1_pins>;
+       status = "okay";
+       renesas,no-ether-link;
+       phy-handle = <&phy1>;
+       phy1: ethernet-phy@1 {
+               reg = <0>;
+       };
 };
 
 /* EXTAL */
        clock-frequency = <24000000>;   /* 24MHz */
 };
 
-/* RTC_X1 */
-&rtc_x1_clk {
-       clock-frequency = <32768>;
+/* High resolution System tick timers */
+&ostm0 {
+       status = "okay";
+};
+
+&ostm1 {
+       status = "okay";
 };
 
 &pinctrl {
+       eth0_pins: eth0 {
+               pinmux = <RZA2_PINMUX(PORTE, 0, 7)>, /* REF50CK0 */
+                        <RZA2_PINMUX(PORT6, 1, 7)>, /* RMMI0_TXDEN */
+                        <RZA2_PINMUX(PORT6, 2, 7)>, /* RMII0_TXD0 */
+                        <RZA2_PINMUX(PORT6, 3, 7)>, /* RMII0_TXD1 */
+                        <RZA2_PINMUX(PORTE, 4, 7)>, /* RMII0_CRSDV */
+                        <RZA2_PINMUX(PORTE, 1, 7)>, /* RMII0_RXD0 */
+                        <RZA2_PINMUX(PORTE, 2, 7)>, /* RMII0_RXD1 */
+                        <RZA2_PINMUX(PORTE, 3, 7)>, /* RMII0_RXER */
+                        <RZA2_PINMUX(PORTE, 5, 1)>, /* ET0_MDC */
+                        <RZA2_PINMUX(PORTE, 6, 1)>, /* ET0_MDIO */
+                        <RZA2_PINMUX(PORTL, 0, 5)>; /* IRQ4 */
+       };
+
+       eth1_pins: eth1 {
+               pinmux = <RZA2_PINMUX(PORTK, 3, 7)>, /* REF50CK1 */
+                        <RZA2_PINMUX(PORTK, 0, 7)>, /* RMMI1_TXDEN */
+                        <RZA2_PINMUX(PORTK, 1, 7)>, /* RMII1_TXD0 */
+                        <RZA2_PINMUX(PORTK, 2, 7)>, /* RMII1_TXD1 */
+                        <RZA2_PINMUX(PORT3, 2, 7)>, /* RMII1_CRSDV */
+                        <RZA2_PINMUX(PORTK, 4, 7)>, /* RMII1_RXD0 */
+                        <RZA2_PINMUX(PORT3, 5, 7)>, /* RMII1_RXD1 */
+                        <RZA2_PINMUX(PORT3, 1, 7)>, /* RMII1_RXER */
+                        <RZA2_PINMUX(PORT3, 3, 1)>, /* ET1_MDC */
+                        <RZA2_PINMUX(PORT3, 4, 1)>, /* ET1_MDIO */
+                        <RZA2_PINMUX(PORTL, 1, 5)>; /* IRQ5 */
+       };
+
+       keyboard_pins: keyboard {
+               pinmux = <RZA2_PINMUX(PORTJ, 1, 6)>;    /* IRQ0 */
+       };
+
        /* Serial Console */
        scif4_pins: serial4 {
                pinmux = <RZA2_PINMUX(PORT9, 0, 4)>,    /* TxD4 */
                         <RZA2_PINMUX(PORT9, 1, 4)>;    /* RxD4 */
        };
-};
 
-/* High resolution System tick timers */
-&ostm0 {
-       status = "okay";
+       sdhi0_pins: sdhi0 {
+               pinmux = <RZA2_PINMUX(PORT5, 0, 3)>,    /* SD0_CD */
+                        <RZA2_PINMUX(PORT5, 1, 3)>;    /* SD0_WP */
+       };
+
+       sdhi1_pins: sdhi1 {
+               pinmux = <RZA2_PINMUX(PORT5, 4, 3)>,    /* SD1_CD */
+                        <RZA2_PINMUX(PORT5, 5, 3)>;    /* SD1_WP */
+       };
+
+       usb0_pins: usb0 {
+               pinmux = <RZA2_PINMUX(PORT5, 2, 3)>,    /* VBUSIN0 */
+                        <RZA2_PINMUX(PORTC, 6, 1)>,    /* VBUSEN0 */
+                        <RZA2_PINMUX(PORTC, 7, 1)>;    /* OVRCUR0 */
+       };
+
+       usb1_pins: usb1 {
+               pinmux = <RZA2_PINMUX(PORTC, 0, 1)>,    /* VBUSIN1 */
+                        <RZA2_PINMUX(PORTC, 5, 1)>,    /* VBUSEN1 */
+                        <RZA2_PINMUX(PORT7, 5, 5)>;    /* OVRCUR1 */
+       };
 };
 
-&ostm1 {
-       status = "okay";
+/* RTC_X1 */
+&rtc_x1_clk {
+       clock-frequency = <32768>;
 };
 
 /* Serial Console */
 
        status = "okay";
 };
+
+&sdhi0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&sdhi0_pins>;
+       bus-width = <4>;
+       status = "okay";
+};
+
+&sdhi1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&sdhi1_pins>;
+       bus-width = <4>;
+       status = "okay";
+};
+
+/* USB-0 as Host */
+&usb2_phy0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&usb0_pins>;
+       dr_mode = "host";       /* Requires JP3 to be fitted */
+       status = "okay";
+};
+
+/* USB-1 as Host */
+&usb2_phy1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&usb1_pins>;
+       dr_mode = "host";
+       status = "okay";
+};
+
+/* USB_X1 */
+&usb_x1_clk {
+       clock-frequency = <48000000>;
+};
index 22baa96..72b7977 100644 (file)
                clock-frequency = <0>;
        };
 
+       usb_x1_clk: usb_x1 {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               /* If clk present, value (48000000) must be set by board */
+               clock-frequency = <0>;
+       };
+
        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
                        status = "disabled";
                };
 
+               spi0: spi@e800c800 {
+                       compatible = "renesas,rspi-r7s9210", "renesas,rspi-rz";
+                       reg = <0xe800c800 0x24>;
+                       interrupts = <GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "error", "rx", "tx";
+                       clocks = <&cpg CPG_MOD 97>;
+                       power-domains = <&cpg>;
+                       num-cs = <1>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               spi1: spi@e800d000 {
+                       compatible = "renesas,rspi-r7s9210", "renesas,rspi-rz";
+                       reg = <0xe800d000 0x24>;
+                       interrupts = <GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "error", "rx", "tx";
+                       clocks = <&cpg CPG_MOD 96>;
+                       power-domains = <&cpg>;
+                       num-cs = <1>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               spi2: spi@e800d800 {
+                       compatible = "renesas,rspi-r7s9210", "renesas,rspi-rz";
+                       reg = <0xe800d800 0x24>;
+                       interrupts = <GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 319 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "error", "rx", "tx";
+                       clocks = <&cpg CPG_MOD 95>;
+                       power-domains = <&cpg>;
+                       num-cs = <1>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               ether0: ethernet@e8204000 {
+                       compatible = "renesas,ether-r7s9210";
+                       reg = <0xe8204000 0x200>;
+                       interrupts = <GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 65>;
+                       power-domains = <&cpg>;
+
+                       phy-mode = "rmii";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               ether1: ethernet@e8204200 {
+                       compatible = "renesas,ether-r7s9210";
+                       reg = <0xe8204200 0x200>;
+                       interrupts = <GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 64>;
+                       power-domains = <&cpg>;
+                       phy-mode = "rmii";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               i2c0: i2c@e803a000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "renesas,riic-r7s9210", "renesas,riic-rz";
+                       reg = <0xe803a000 0x44>;
+                       interrupts = <GIC_SPI 232 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 233 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 234 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 235 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 236 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 237 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 238 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 87>;
+                       power-domains = <&cpg>;
+                       clock-frequency = <100000>;
+                       status = "disabled";
+               };
+
+               i2c1: i2c@e803a400 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "renesas,riic-r7s9210", "renesas,riic-rz";
+                       reg = <0xe803a400 0x44>;
+                       interrupts = <GIC_SPI 240 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 241 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 242 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 243 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 244 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 86>;
+                       power-domains = <&cpg>;
+                       clock-frequency = <100000>;
+                       status = "disabled";
+               };
+
+               i2c2: i2c@e803a800 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "renesas,riic-r7s9210", "renesas,riic-rz";
+                       reg = <0xe803a800 0x44>;
+                       interrupts = <GIC_SPI 248 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 249 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 250 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 251 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 252 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 253 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 254 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 255 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 85>;
+                       power-domains = <&cpg>;
+                       clock-frequency = <100000>;
+                       status = "disabled";
+               };
+
+               i2c3: i2c@e803ac00 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "renesas,riic-r7s9210", "renesas,riic-rz";
+                       reg = <0xe803ac00 0x44>;
+                       interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 257 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 258 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 259 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 84>;
+                       power-domains = <&cpg>;
+                       clock-frequency = <100000>;
+                       status = "disabled";
+               };
+
                ostm0: timer@e803b000 {
                        compatible = "renesas,r7s9210-ostm", "renesas,ostm";
                        reg = <0xe803b000 0x30>;
                        status = "disabled";
                };
 
+               ohci0: usb@e8218000 {
+                       compatible = "generic-ohci";
+                       reg = <0xe8218000 0x100>;
+                       interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 61>;
+                       phys = <&usb2_phy0>;
+                       phy-names = "usb";
+                       power-domains = <&cpg>;
+                       status = "disabled";
+               };
+
+               ehci0: usb@e8218100 {
+                       compatible = "generic-ehci";
+                       reg = <0xe8218100 0x100>;
+                       interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 61>;
+                       phys = <&usb2_phy0>;
+                       phy-names = "usb";
+                       power-domains = <&cpg>;
+                       status = "disabled";
+               };
+
+               usb2_phy0: usb-phy@e8218200 {
+                       compatible = "renesas,usb2-phy-r7s9210", "renesas,rcar-gen3-usb2-phy";
+                       reg = <0xe8218200 0x700>;
+                       interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 61>, <&usb_x1_clk>;
+                       clock-names = "fck", "usb_x1";
+                       power-domains = <&cpg>;
+                       #phy-cells = <0>;
+                       status = "disabled";
+               };
+
+               usbhs0: usb@e8219000 {
+                       compatible = "renesas,usbhs-r7s9210", "renesas,rza2-usbhs";
+                       reg = <0xe8219000 0x724>;
+                       interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 61>;
+                       renesas,buswait = <7>;
+                       phys = <&usb2_phy0>;
+                       phy-names = "usb";
+                       power-domains = <&cpg>;
+                       status = "disabled";
+               };
+
+               ohci1: usb@e821a000 {
+                       compatible = "generic-ohci";
+                       reg = <0xe821a000 0x100>;
+                       interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 60>;
+                       phys = <&usb2_phy1>;
+                       phy-names = "usb";
+                       power-domains = <&cpg>;
+                       status = "disabled";
+               };
+
+               ehci1: usb@e821a100 {
+                       compatible = "generic-ehci";
+                       reg = <0xe821a100 0x100>;
+                       interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 60>;
+                       phys = <&usb2_phy1>;
+                       phy-names = "usb";
+                       power-domains = <&cpg>;
+                       status = "disabled";
+               };
+
+               usb2_phy1: usb-phy@e821a200 {
+                       compatible = "renesas,usb2-phy-r7s9210", "renesas,rcar-gen3-usb2-phy";
+                       reg = <0xe821a200 0x700>;
+                       interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 60>, <&usb_x1_clk>;
+                       clock-names = "fck", "usb_x1";
+                       power-domains = <&cpg>;
+                       #phy-cells = <0>;
+                       status = "disabled";
+               };
+
+               usbhs1: usb@e821b000 {
+                       compatible = "renesas,usbhs-r7s9210", "renesas,rza2-usbhs";
+                       reg = <0xe821b000 0x724>;
+                       interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 60>;
+                       renesas,buswait = <7>;
+                       phys = <&usb2_phy1>;
+                       phy-names = "usb";
+                       power-domains = <&cpg>;
+                       status = "disabled";
+               };
+
+               sdhi0: sd@e8228000 {
+                       compatible = "renesas,sdhi-r7s9210";
+                       reg = <0xe8228000 0x8c0>;
+                       interrupts = <GIC_SPI 322 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 103>, <&cpg CPG_MOD 102>;
+                       clock-names = "core", "cd";
+                       power-domains = <&cpg>;
+                       cap-sd-highspeed;
+                       cap-sdio-irq;
+                       status = "disabled";
+               };
+
+               sdhi1: sd@e822a000 {
+                       compatible = "renesas,sdhi-r7s9210";
+                       reg = <0xe822a000 0x8c0>;
+                       interrupts = <GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 101>, <&cpg CPG_MOD 100>;
+                       clock-names = "core", "cd";
+                       power-domains = <&cpg>;
+                       cap-sd-highspeed;
+                       cap-sdio-irq;
+                       status = "disabled";
+               };
+
                gic: interrupt-controller@e8221000 {
                        compatible = "arm,gic-400";
                        #interrupt-cells = <3>;
                        reg = <0xfcfe8004 4>;
                };
 
+               irqc: interrupt-controller@fcfef800 {
+                       compatible = "renesas,r7s9210-irqc",
+                                    "renesas,rza1-irqc";
+                       #interrupt-cells = <2>;
+                       #address-cells = <0>;
+                       interrupt-controller;
+                       reg = <0xfcfef800 0x6>;
+                       interrupt-map =
+                               <0 0 &gic GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
+                               <1 0 &gic GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
+                               <2 0 &gic GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
+                               <3 0 &gic GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+                               <4 0 &gic GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+                               <5 0 &gic GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
+                               <6 0 &gic GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
+                               <7 0 &gic GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-map-mask = <7 0>;
+               };
+
                pinctrl: pin-controller@fcffe000 {
                        compatible = "renesas,r7s9210-pinctrl";
                        reg = <0xfcffe000 0x1000>;
index f70f4a3..a5351dd 100644 (file)
@@ -19,7 +19,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial0:115200n8";
        };
 
index 32757ca..758360a 100644 (file)
@@ -21,7 +21,7 @@
        };
 
        chosen {
-               bootargs = "earlyprintk ignore_loglevel root=/dev/nfs ip=dhcp rw";
+               bootargs = "earlyprintk ignore_loglevel root=/dev/nfs ip=on rw";
                stdout-path = "serial0:115200n8";
        };
 
index ca0e0fc..807e7d0 100644 (file)
@@ -17,7 +17,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial0:115200n8";
        };
 
index 1db220c..ce6603b 100644 (file)
@@ -42,7 +42,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial3:115200n8";
        };
 
index 655b10b..db72a80 100644 (file)
@@ -17,7 +17,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial0:115200n8";
        };
 
index 2840eb0..450efe9 100644 (file)
@@ -18,7 +18,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial1:115200n8";
        };
 
@@ -63,7 +63,7 @@
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <3300000>;
 
-               gpios = <&gpio2 24 GPIO_ACTIVE_LOW>;
+               gpios = <&gpio2 24 GPIO_ACTIVE_HIGH>;
                gpios-states = <1>;
                states = <3300000 1
                          1800000 0>;
index 0b49956..6c7b07c 100644 (file)
@@ -25,7 +25,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial0:115200n8";
        };
 
index d4bee1e..c755f0b 100644 (file)
@@ -21,7 +21,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial0:115200n8";
        };
 
index 7b9508e..83cc619 100644 (file)
@@ -56,7 +56,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial0:115200n8";
        };
 
         */
        i2cpwr: i2c-13 {
                compatible = "i2c-demux-pinctrl";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pmic_irq_pins>;
                i2c-parent = <&iic3>, <&i2c3>;
                i2c-bus-name = "i2c-pwr";
                #address-cells = <1>;
                function = "iic3";
        };
 
+       pmic_irq_pins: pmicirq {
+               groups = "intc_irq2";
+               function = "intc";
+       };
+
        hsusb_pins: hsusb {
                groups = "usb0_ovc_vbus";
                function = "usb0";
index 7a7d3b8..a315ba7 100644 (file)
@@ -19,7 +19,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial0:115200n8";
        };
 
                function = "iic3";
        };
 
+       pmic_irq_pins: pmicirq {
+               groups = "intc_irq2";
+               function = "intc";
+       };
+
        usb0_pins: usb0 {
                groups = "usb0";
                function = "usb0";
 
 &iic3 {
        pinctrl-names = "default";
-       pinctrl-0 = <&iic3_pins>;
+       pinctrl-0 = <&iic3_pins &pmic_irq_pins>;
        status = "okay";
 
        pmic@58 {
index e6580aa..af6bd8f 100644 (file)
@@ -56,7 +56,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial0:115200n8";
        };
 
                function = "intc";
        };
 
+       pmic_irq_pins: pmicirq {
+               groups = "intc_irq2";
+               function = "intc";
+       };
+
        sdhi0_pins: sd0 {
                groups = "sdhi0_data4", "sdhi0_ctrl";
                function = "sdhi0";
 };
 
 &i2c6 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pmic_irq_pins>;
        status = "okay";
        clock-frequency = <100000>;
 
index fefdf82..d6cf16a 100644 (file)
@@ -31,7 +31,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial0:115200n8";
        };
 
                function = "intc";
        };
 
+       pmic_irq_pins: pmicirq {
+               groups = "intc_irq2";
+               function = "intc";
+       };
+
        sdhi0_pins: sd0 {
                groups = "sdhi0_data4", "sdhi0_ctrl";
                function = "sdhi0";
 };
 
 &i2c6 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pmic_irq_pins>;
        status = "okay";
        clock-frequency = <100000>;
 
index b6fa80c..248eb71 100644 (file)
@@ -21,7 +21,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial0:115200n8";
        };
 
                groups = "du1_rgb666", "du1_sync", "du1_disp";
                function = "du1";
        };
+
+       pmic_irq_pins: pmicirq {
+               groups = "intc_irq2";
+               function = "intc";
+       };
 };
 
 &rwdt {
        pmic@58 {
                compatible = "dlg,da9063";
                reg = <0x58>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pmic_irq_pins>;
                interrupt-parent = <&irqc>;
                interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
                interrupt-controller;
index f46f456..bd2a63b 100644 (file)
@@ -20,7 +20,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial0:115200n8";
        };
 
index 38fb43d..c4ea2d6 100644 (file)
                        compatible = "renesas,prr";
                        reg = <0 0xff000044 0 4>;
                };
+
+               cmt0: timer@ffca0000 {
+                       compatible = "renesas,r8a7792-cmt0",
+                                    "renesas,rcar-gen2-cmt0";
+                       reg = <0 0xffca0000 0 0x1004>;
+                       interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 124>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+                       resets = <&cpg 124>;
+
+                       status = "disabled";
+               };
+
+               cmt1: timer@e6130000 {
+                       compatible = "renesas,r8a7792-cmt1",
+                                    "renesas,rcar-gen2-cmt1";
+                       reg = <0 0xe6130000 0 0x1004>;
+                       interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 329>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+                       resets = <&cpg 329>;
+
+                       status = "disabled";
+               };
        };
 
        timer {
index f51601a..42f3313 100644 (file)
@@ -52,7 +52,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial0:115200n8";
        };
 
                function = "intc";
        };
 
+       pmic_irq_pins: pmicirq {
+               groups = "intc_irq2";
+               function = "intc";
+       };
+
        sdhi0_pins: sd0 {
                groups = "sdhi0_data4", "sdhi0_ctrl";
                function = "sdhi0";
 };
 
 &i2c6 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pmic_irq_pins>;
        status = "okay";
        clock-frequency = <100000>;
 
index 0ab3d8d..1d22fcd 100644 (file)
@@ -22,7 +22,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial0:115200n8";
        };
 
index 60e91eb..b3177ae 100644 (file)
@@ -34,7 +34,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial0:115200n8";
        };
 
index da102ff..340ed6c 100644 (file)
                #clock-cells = <0>;
        };
 
+       display_subsystem: display-subsystem {
+               compatible = "rockchip,display-subsystem";
+               ports = <&vop_out>;
+       };
+
        i2s1: i2s1@100b0000 {
                compatible = "rockchip,rk3228-i2s", "rockchip,rk3066-i2s";
                reg = <0x100b0000 0x4000>;
                status = "disabled";
        };
 
+       hdmi_phy: hdmi-phy@12030000 {
+               compatible = "rockchip,rk3228-hdmi-phy";
+               reg = <0x12030000 0x10000>;
+               clocks = <&cru PCLK_HDMI_PHY>, <&xin24m>, <&cru DCLK_HDMI_PHY>;
+               clock-names = "sysclk", "refoclk", "refpclk";
+               #clock-cells = <0>;
+               clock-output-names = "hdmiphy_phy";
+               #phy-cells = <0>;
+               status = "disabled";
+       };
+
        gpu: gpu@20000000 {
                compatible = "rockchip,rk3228-mali", "arm,mali-400";
                reg = <0x20000000 0x10000>;
                status = "disabled";
        };
 
+       vop: vop@20050000 {
+               compatible = "rockchip,rk3228-vop";
+               reg = <0x20050000 0x1ffc>;
+               interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cru ACLK_VOP>, <&cru DCLK_VOP>, <&cru HCLK_VOP>;
+               clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
+               resets = <&cru SRST_VOP_A>, <&cru SRST_VOP_H>, <&cru SRST_VOP_D>;
+               reset-names = "axi", "ahb", "dclk";
+               iommus = <&vop_mmu>;
+               status = "disabled";
+
+               vop_out: port {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       vop_out_hdmi: endpoint@0 {
+                               reg = <0>;
+                               remote-endpoint = <&hdmi_in_vop>;
+                       };
+               };
+       };
+
        vop_mmu: iommu@20053f00 {
                compatible = "rockchip,iommu";
                reg = <0x20053f00 0x100>;
                interrupt-names = "vop_mmu";
                clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>;
                clock-names = "aclk", "iface";
-               iommu-cells = <0>;
+               #iommu-cells = <0>;
                status = "disabled";
        };
 
                status = "disabled";
        };
 
+       hdmi: hdmi@200a0000 {
+               compatible = "rockchip,rk3228-dw-hdmi";
+               reg = <0x200a0000 0x20000>;
+               reg-io-width = <4>;
+               interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+               assigned-clocks = <&cru SCLK_HDMI_PHY>;
+               assigned-clock-parents = <&hdmi_phy>;
+               clocks = <&cru SCLK_HDMI_HDCP>, <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_CEC>;
+               clock-names = "isfr", "iahb", "cec";
+               pinctrl-names = "default";
+               pinctrl-0 = <&hdmii2c_xfer &hdmi_hpd &hdmi_cec>;
+               resets = <&cru SRST_HDMI_P>;
+               reset-names = "hdmi";
+               phys = <&hdmi_phy>;
+               phy-names = "hdmi";
+               rockchip,grf = <&grf>;
+               status = "disabled";
+
+               ports {
+                       hdmi_in: port {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               hdmi_in_vop: endpoint@0 {
+                                       reg = <0>;
+                                       remote-endpoint = <&vop_out_hdmi>;
+                               };
+                       };
+               };
+       };
+
        sdmmc: dwmmc@30000000 {
                compatible = "rockchip,rk3228-dw-mshc", "rockchip,rk3288-dw-mshc";
                reg = <0x30000000 0x4000>;
                        };
                };
 
+               hdmi {
+                       hdmi_hpd: hdmi-hpd {
+                               rockchip,pins = <0 RK_PB7 1 &pcfg_pull_down>;
+                       };
+
+                       hdmii2c_xfer: hdmii2c-xfer {
+                               rockchip,pins = <0 RK_PA6 2 &pcfg_pull_none>,
+                                               <0 RK_PA7 2 &pcfg_pull_none>;
+                       };
+
+                       hdmi_cec: hdmi-cec {
+                               rockchip,pins = <0 RK_PC4 1 &pcfg_pull_none>;
+                       };
+               };
+
                i2c0 {
                        i2c0_xfer: i2c0-xfer {
                                rockchip,pins = <0 RK_PA0 1 &pcfg_pull_none>,
index fbef345..1cadb52 100644 (file)
                pinctrl-0 = <&ac_present_ap>;
        };
 
+       lid_switch: lid-switch {
+               compatible = "gpio-keys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&ap_lid_int_l>;
+
+               lid {
+                       label = "Lid";
+                       gpios = <&gpio0 RK_PA6 GPIO_ACTIVE_LOW>;
+                       wakeup-source;
+                       linux,code = <SW_LID>;
+                       linux,input-type = <EV_SW>;
+                       debounce-interval = <1>;
+               };
+       };
+
        panel: panel {
                compatible ="innolux,n116bge", "simple-panel";
                status = "okay";
        status = "okay";
 };
 
-&gpio_keys {
-       pinctrl-0 = <&pwr_key_l &ap_lid_int_l>;
-       lid {
-               label = "Lid";
-               gpios = <&gpio0 RK_PA6 GPIO_ACTIVE_LOW>;
-               wakeup-source;
-               linux,code = <0>; /* SW_LID */
-               linux,input-type = <5>; /* EV_SW */
-               debounce-interval = <1>;
-       };
-};
-
 &pwm0 {
        status = "okay";
 };
 
                /* Wake only */
                &suspend_l_wake
+               &bt_dev_wake_awake
        >;
        pinctrl-1 = <
                /* Common for sleep and wake, but no owners */
 
                /* Sleep only */
                &suspend_l_sleep
+               &bt_dev_wake_sleep
        >;
 
        backlight {
index e248f55..fcd1191 100644 (file)
        pinctrl-0 = <&vcc50_hdmi_en>;
 };
 
+&gpio0 {
+       gpio-line-names = "PMIC_SLEEP_AP",
+                         "DDRIO_PWROFF",
+                         "DDRIO_RETEN",
+                         "TS3A227E_INT_L",
+                         "PMIC_INT_L",
+                         "PWR_KEY_L",
+                         "AP_LID_INT_L",
+                         "EC_IN_RW",
+
+                         "AC_PRESENT_AP",
+                         /*
+                          * RECOVERY_SW_L is Chrome OS ABI.  Schematics call
+                          * it REC_MODE_L.
+                          */
+                         "RECOVERY_SW_L",
+                         "OTP_OUT",
+                         "HOST1_PWR_EN",
+                         "USBOTG_PWREN_H",
+                         "AP_WARM_RESET_H",
+                         "nFALUT2",
+                         "I2C0_SDA_PMIC",
+
+                         "I2C0_SCL_PMIC",
+                         "SUSPEND_L",
+                         "USB_INT";
+};
+
+&gpio2 {
+       gpio-line-names = "CONFIG0",
+                         "CONFIG1",
+                         "CONFIG2",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "CONFIG3",
+
+                         "",
+                         "EMMC_RST_L",
+                         "",
+                         "",
+                         "BL_PWR_EN",
+                         "AVDD_1V8_DISP_EN";
+};
+
+&gpio3 {
+       gpio-line-names = "FLASH0_D0",
+                         "FLASH0_D1",
+                         "FLASH0_D2",
+                         "FLASH0_D3",
+                         "FLASH0_D4",
+                         "FLASH0_D5",
+                         "FLASH0_D6",
+                         "FLASH0_D7",
+
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+
+                         "FLASH0_CS2/EMMC_CMD",
+                         "",
+                         "FLASH0_DQS/EMMC_CLKO";
+};
+
+&gpio4 {
+       gpio-line-names = "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+
+                         "UART0_RXD",
+                         "UART0_TXD",
+                         "UART0_CTS",
+                         "UART0_RTS",
+                         "SDIO0_D0",
+                         "SDIO0_D1",
+                         "SDIO0_D2",
+                         "SDIO0_D3",
+
+                         "SDIO0_CMD",
+                         "SDIO0_CLK",
+                         "BT_DEV_WAKE",        /* Maybe missing from mighty? */
+                         "",
+                         "WIFI_ENABLE_H",
+                         "BT_ENABLE_L",
+                         "WIFI_HOST_WAKE",
+                         "BT_HOST_WAKE";
+};
+
+&gpio5 {
+       gpio-line-names = "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+
+                         "",
+                         "",
+                         "",
+                         "",
+                         "SPI0_CLK",
+                         "SPI0_CS0",
+                         "SPI0_TXD",
+                         "SPI0_RXD",
+
+                         "",
+                         "",
+                         "",
+                         "VCC50_HDMI_EN";
+};
+
+&gpio6 {
+       gpio-line-names = "I2S0_SCLK",
+                         "I2S0_LRCK_RX",
+                         "I2S0_LRCK_TX",
+                         "I2S0_SDI",
+                         "I2S0_SDO0",
+                         "HP_DET_H",
+                         "ALS_INT",
+                         "INT_CODEC",
+
+                         "I2S0_CLK",
+                         "I2C2_SDA",
+                         "I2C2_SCL",
+                         "MICDET",
+                         "",
+                         "",
+                         "",
+                         "",
+
+                         "SDMMC_D0",
+                         "SDMMC_D1",
+                         "SDMMC_D2",
+                         "SDMMC_D3",
+                         "SDMMC_CLK",
+                         "SDMMC_CMD";
+};
+
+&gpio7 {
+       gpio-line-names = "LCDC_BL",
+                         "PWM_LOG",
+                         "BL_EN",
+                         "TRACKPAD_INT",
+                         "TPM_INT_H",
+                         "SDMMC_DET_L",
+                         /*
+                          * AP_FLASH_WP_L is Chrome OS ABI.  Schematics call
+                          * it FW_WP_AP.
+                          */
+                         "AP_FLASH_WP_L",
+                         "EC_INT",
+
+                         "CPU_NMI",
+                         "DVSOK",
+                         "SDMMC_WP",           /* mighty only */
+                         "EDP_HPD",
+                         "DVS1",
+                         "nFALUT1",            /* nFAULT1 on jaq */
+                         "LCD_EN",
+                         "DVS2",
+
+                         "VCC5V_GOOD_H",
+                         "I2C4_SDA_TP",
+                         "I2C4_SCL_TP",
+                         "I2C5_SDA_HDMI",
+                         "I2C5_SCL_HDMI",
+                         "5V_DRV",
+                         "UART2_RXD",
+                         "UART2_TXD";
+};
+
+&gpio8 {
+       gpio-line-names = "RAM_ID0",
+                         "RAM_ID1",
+                         "RAM_ID2",
+                         "RAM_ID3",
+                         "I2C1_SDA_TPM",
+                         "I2C1_SCL_TPM",
+                         "SPI2_CLK",
+                         "SPI2_CS0",
+
+                         "SPI2_RXD",
+                         "SPI2_TXD";
+};
+
 &pinctrl {
        backlight {
                bl_pwr_en: bl_pwr_en {
index b1613af..164561f 100644 (file)
        pinctrl-0 = <&vcc50_hdmi_en>;
 };
 
+&gpio0 {
+       gpio-line-names = "PMIC_SLEEP_AP",
+                         "DDRIO_PWROFF",
+                         "DDRIO_RETEN",
+                         "TS3A227E_INT_L",
+                         "PMIC_INT_L",
+                         "PWR_KEY_L",
+                         "AP_LID_INT_L",
+                         "EC_IN_RW",
+
+                         "AC_PRESENT_AP",
+                         /*
+                          * RECOVERY_SW_L is Chrome OS ABI.  Schematics call
+                          * it REC_MODE_L.
+                          */
+                         "RECOVERY_SW_L",
+                         "OTP_OUT",
+                         "HOST1_PWR_EN",
+                         "USBOTG_PWREN_H",
+                         "AP_WARM_RESET_H",
+                         "nFAULT2",
+                         "I2C0_SDA_PMIC",
+
+                         "I2C0_SCL_PMIC",
+                         "SUSPEND_L",
+                         "USB_INT";
+};
+
+&gpio2 {
+       gpio-line-names = "CONFIG0",
+                         "CONFIG1",
+                         "CONFIG2",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "CONFIG3",
+
+                         "",
+                         "EMMC_RST_L",
+                         "",
+                         "",
+                         "BL_PWR_EN",
+                         "AVDD_1V8_DISP_EN";
+};
+
+&gpio3 {
+       gpio-line-names = "FLASH0_D0",
+                         "FLASH0_D1",
+                         "FLASH0_D2",
+                         "FLASH0_D3",
+                         "FLASH0_D4",
+                         "FLASH0_D5",
+                         "FLASH0_D6",
+                         "FLASH0_D7",
+
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+
+                         "FLASH0_CS2/EMMC_CMD",
+                         "",
+                         "FLASH0_DQS/EMMC_CLKO";
+};
+
+&gpio4 {
+       gpio-line-names = "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+
+                         "UART0_RXD",
+                         "UART0_TXD",
+                         "UART0_CTS",
+                         "UART0_RTS",
+                         "SDIO0_D0",
+                         "SDIO0_D1",
+                         "SDIO0_D2",
+                         "SDIO0_D3",
+
+                         "SDIO0_CMD",
+                         "SDIO0_CLK",
+                         "BT_DEV_WAKE",
+                         "",
+                         "WIFI_ENABLE_H",
+                         "BT_ENABLE_L",
+                         "WIFI_HOST_WAKE",
+                         "BT_HOST_WAKE";
+};
+
+&gpio5 {
+       gpio-line-names = "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+
+                         "",
+                         "",
+                         "",
+                         "",
+                         "SPI0_CLK",
+                         "SPI0_CS0",
+                         "SPI0_TXD",
+                         "SPI0_RXD",
+
+                         "",
+                         "",
+                         "",
+                         "VCC50_HDMI_EN";
+};
+
+&gpio6 {
+       gpio-line-names = "I2S0_SCLK",
+                         "I2S0_LRCK_RX",
+                         "I2S0_LRCK_TX",
+                         "I2S0_SDI",
+                         "I2S0_SDO0",
+                         "HP_DET_H",
+                         "",
+                         "INT_CODEC",
+
+                         "I2S0_CLK",
+                         "I2C2_SDA",
+                         "I2C2_SCL",
+                         "MICDET",
+                         "",
+                         "",
+                         "",
+                         "",
+
+                         "SDMMC_D0",
+                         "SDMMC_D1",
+                         "SDMMC_D2",
+                         "SDMMC_D3",
+                         "SDMMC_CLK",
+                         "SDMMC_CMD";
+};
+
+&gpio7 {
+       gpio-line-names = "LCDC_BL",
+                         "PWM_LOG",
+                         "BL_EN",
+                         "TRACKPAD_INT",
+                         "TPM_INT_H",
+                         "SDMMC_DET_L",
+                         /*
+                          * AP_FLASH_WP_L is Chrome OS ABI.  Schematics call
+                          * it FW_WP_AP.
+                          */
+                         "AP_FLASH_WP_L",
+                         "EC_INT",
+
+                         "CPU_NMI",
+                         "DVSOK",
+                         "",
+                         "EDP_HPD",
+                         "DVS1",
+                         "nFAULT1",
+                         "LCD_EN",
+                         "DVS2",
+
+                         "VCC5V_GOOD_H",
+                         "I2C4_SDA_TP",
+                         "I2C4_SCL_TP",
+                         "I2C5_SDA_HDMI",
+                         "I2C5_SCL_HDMI",
+                         "5V_DRV",
+                         "UART2_RXD",
+                         "UART2_TXD";
+};
+
+&gpio8 {
+       gpio-line-names = "RAM_ID0",
+                         "RAM_ID1",
+                         "RAM_ID2",
+                         "RAM_ID3",
+                         "I2C1_SDA_TPM",
+                         "I2C1_SCL_TPM",
+                         "SPI2_CLK",
+                         "SPI2_CS0",
+
+                         "SPI2_RXD",
+                         "SPI2_TXD";
+};
+
 &pinctrl {
        backlight {
                bl_pwr_en: bl_pwr_en {
index e852594..aa352d4 100644 (file)
@@ -75,9 +75,7 @@
        cooling-maps {
                /*
                 * After 1st level, throttle the CPU down to as low as 1.4 GHz
-                * and don't let the GPU go faster than 400 MHz.  Note that we
-                * won't throttle the GPU lower than 400 MHz due to CPU
-                * heat--we'll let the GPU do the rest itself.
+                * and don't let the GPU go faster than 400 MHz.
                 */
                cpu_warm_limit_cpu {
                        trip = <&cpu_alert_warm>;
                                         <&cpu2 THERMAL_NO_LIMIT 4>,
                                         <&cpu3 THERMAL_NO_LIMIT 4>;
                };
+               cpu_warm_limit_gpu {
+                       trip = <&cpu_alert_warm>;
+                       cooling-device = <&gpu 1 1>;
+               };
 
                /*
                 * Add some discrete steps to help throttling system deal
                                         <&cpu2 8 THERMAL_NO_LIMIT>,
                                         <&cpu3 8 THERMAL_NO_LIMIT>;
                };
+
+               /* At very hot, don't let GPU go over 300 MHz */
+               cpu_very_hot_limit_gpu {
+                       trip = <&cpu_alert_very_hot>;
+                       cooling-device = <&gpu 2 2>;
+               };
        };
 };
 
-&emmc {
-       /delete-property/mmc-hs200-1_8v;
+&gpu_thermal {
+       /delete-node/ trips;
+       /delete-node/ cooling-maps;
+
+       trips {
+               gpu_alert_warmish: gpu_alert_warmish {
+                       temperature = <60000>; /* millicelsius */
+                       hysteresis = <2000>; /* millicelsius */
+                       type = "passive";
+               };
+               gpu_alert_warm: gpu_alert_warm {
+                       temperature = <65000>; /* millicelsius */
+                       hysteresis = <2000>; /* millicelsius */
+                       type = "passive";
+               };
+               gpu_alert_hotter: gpu_alert_hotter {
+                       temperature = <84000>; /* millicelsius */
+                       hysteresis = <2000>; /* millicelsius */
+                       type = "passive";
+               };
+               gpu_alert_very_very_hot: gpu_alert_very_very_hot {
+                       temperature = <86000>; /* millicelsius */
+                       hysteresis = <2000>; /* millicelsius */
+                       type = "passive";
+               };
+               gpu_crit: gpu_crit {
+                       temperature = <90000>; /* millicelsius */
+                       hysteresis = <2000>; /* millicelsius */
+                       type = "critical";
+               };
+       };
+
+       cooling-maps {
+               /* After 1st level throttle the GPU down to as low as 400 MHz */
+               gpu_warmish_limit_gpu {
+                       trip = <&gpu_alert_warmish>;
+                       cooling-device = <&gpu THERMAL_NO_LIMIT 1>;
+               };
+
+               /*
+                * Slightly after we throttle the GPU, we'll also make sure that
+                * the CPU can't go faster than 1.4 GHz.  Note that we won't
+                * throttle the CPU lower than 1.4 GHz due to GPU heat--we'll
+                * let the CPU do the rest itself.
+                */
+               gpu_warm_limit_cpu {
+                       trip = <&gpu_alert_warm>;
+                       cooling-device = <&cpu0 4 4>,
+                                        <&cpu1 4 4>,
+                                        <&cpu2 4 4>,
+                                        <&cpu3 4 4>;
+               };
+
+               /* When hot, GPU goes down to 300 MHz */
+               gpu_hotter_limit_gpu {
+                       trip = <&gpu_alert_hotter>;
+                       cooling-device = <&gpu 2 2>;
+               };
+
+               /* When really hot, don't let GPU go _above_ 300 MHz */
+               gpu_very_very_hot_limit_gpu {
+                       trip = <&gpu_alert_very_very_hot>;
+                       cooling-device = <&gpu 2 THERMAL_NO_LIMIT>;
+               };
+       };
 };
 
 &i2c2 {
 
 &i2s {
        status = "okay";
-       clock-names = "i2s_hclk", "i2s_clk", "i2s_clk_out";
-       clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>, <&cru SCLK_I2S0_OUT>;
 };
 
 &rk808 {
        };
 };
 
+&gpio0 {
+       gpio-line-names = "PMIC_SLEEP_AP",
+                         "",
+                         "",
+                         "",
+                         "PMIC_INT_L",
+                         "POWER_BUTTON_L",
+                         "",
+                         "",
+
+                         "",
+                         /*
+                          * RECOVERY_SW_L is Chrome OS ABI.  Schematics call
+                          * it REC_MODE_L.
+                          */
+                         "RECOVERY_SW_L",
+                         "OT_RESET",
+                         "",
+                         "",
+                         "AP_WARM_RESET_H",
+                         "",
+                         "I2C0_SDA_PMIC",
+
+                         "I2C0_SCL_PMIC",
+                         "",
+                         "nFALUT";
+};
+
+&gpio2 {
+       gpio-line-names = "CONFIG0",
+                         "CONFIG1",
+                         "CONFIG2",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "CONFIG3",
+
+                         "",
+                         "EMMC_RST_L";
+};
+
+&gpio3 {
+       gpio-line-names = "FLASH0_D0",
+                         "FLASH0_D1",
+                         "FLASH0_D2",
+                         "FLASH0_D3",
+                         "FLASH0_D4",
+                         "FLASH0_D5",
+                         "FLASH0_D6",
+                         "FLASH0_D7",
+
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+
+                         "FLASH0_CS2/EMMC_CMD",
+                         "",
+                         "FLASH0_DQS/EMMC_CLKO";
+};
+
+&gpio4 {
+       gpio-line-names = "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+
+                         "UART0_RXD",
+                         "UART0_TXD",
+                         "UART0_CTS_L",
+                         "UART0_RTS_L",
+                         "SDIO0_D0",
+                         "SDIO0_D1",
+                         "SDIO0_D2",
+                         "SDIO0_D3",
+
+                         "SDIO0_CMD",
+                         "SDIO0_CLK",
+                         "BT_DEV_WAKE",
+                         "",
+                         "WIFI_ENABLE_H",
+                         "BT_ENABLE_L",
+                         "WIFI_HOST_WAKE",
+                         "BT_HOST_WAKE";
+};
+
+&gpio7 {
+       gpio-line-names = "",
+                         "PWM_LOG",
+                         "",
+                         "",
+                         "TPM_INT_H",
+                         "SDMMC_DET_L",
+                         /*
+                          * AP_FLASH_WP_L is Chrome OS ABI.  Schematics call
+                          * it FW_WP_AP.
+                          */
+                         "AP_FLASH_WP_L",
+                         "",
+
+                         "CPU_NMI",
+                         "DVSOK",
+                         "HDMI_WAKE",
+                         "POWER_HDMI_ON",
+                         "DVS1",
+                         "",
+                         "",
+                         "DVS2",
+
+                         "HDMI_CEC",
+                         "",
+                         "",
+                         "I2C5_SDA_HDMI",
+                         "I2C5_SCL_HDMI",
+                         "",
+                         "UART2_RXD",
+                         "UART2_TXD";
+};
+
+&gpio8 {
+       gpio-line-names = "RAM_ID0",
+                         "RAM_ID1",
+                         "RAM_ID2",
+                         "RAM_ID3",
+                         "I2C1_SDA_TPM",
+                         "I2C1_SCL_TPM",
+                         "SPI2_CLK",
+                         "SPI2_CS0",
+
+                         "SPI2_RXD",
+                         "SPI2_TXD";
+};
+
 &pinctrl {
        hdmi {
                power_hdmi_on: power-hdmi-on {
index 468a181..9008e70 100644 (file)
                regulator-boot-on;
                vin-supply = <&vcc18_wl>;
        };
+
+       volume_buttons: volume-buttons {
+               compatible = "gpio-keys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&volum_down_l &volum_up_l>;
+
+               volum_down {
+                       label = "Volum_down";
+                       gpios = <&gpio5 RK_PB3 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_VOLUMEDOWN>;
+                       debounce-interval = <100>;
+               };
+
+               volum_up {
+                       label = "Volum_up";
+                       gpios = <&gpio5 RK_PB2 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_VOLUMEUP>;
+                       debounce-interval = <100>;
+               };
+       };
 };
 
 &backlight {
                        240 241 242 243 244 245 246 247
                        248 249 250 251 252 253 254 255>;
        power-supply = <&backlight_regulator>;
-       post-pwm-on-delay-ms = <200>;
-       pwm-off-delay-ms = <200>;
-};
-
-&emmc {
-       /delete-property/mmc-hs200-1_8v;
-};
-
-&gpio_keys {
-       pinctrl-0 = <&pwr_key_l &ap_lid_int_l &volum_down_l &volum_up_l>;
-
-       volum_down {
-               label = "Volum_down";
-               gpios = <&gpio5 RK_PB3 GPIO_ACTIVE_LOW>;
-               linux,code = <KEY_VOLUMEDOWN>;
-               debounce-interval = <100>;
-       };
-
-       volum_up {
-               label = "Volum_up";
-               gpios = <&gpio5 RK_PB2 GPIO_ACTIVE_LOW>;
-               linux,code = <KEY_VOLUMEUP>;
-               debounce-interval = <100>;
-       };
 };
 
 &i2c_tunnel {
        pinctrl-0 = <&vcc50_hdmi_en>;
 };
 
+&gpio0 {
+       gpio-line-names = "PMIC_SLEEP_AP",
+                         "DDRIO_PWROFF",
+                         "DDRIO_RETEN",
+                         "TS3A227E_INT_L",
+                         "PMIC_INT_L",
+                         "PWR_KEY_L",
+                         "AP_LID_INT_L",
+                         "EC_IN_RW",
+
+                         "AC_PRESENT_AP",
+                         /*
+                          * RECOVERY_SW_L is Chrome OS ABI.  Schematics call
+                          * it REC_MODE_L.
+                          */
+                         "RECOVERY_SW_L",
+                         "OTP_OUT",
+                         "HOST1_PWR_EN",
+                         "USBOTG_PWREN_H",
+                         "AP_WARM_RESET_H",
+                         "nFALUT2",
+                         "I2C0_SDA_PMIC",
+
+                         "I2C0_SCL_PMIC",
+                         "SUSPEND_L",
+                         "USB_INT";
+};
+
+&gpio2 {
+       gpio-line-names = "CONFIG0",
+                         "CONFIG1",
+                         "CONFIG2",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "CONFIG3",
+
+                         "PROCHOT#",
+                         "EMMC_RST_L",
+                         "",
+                         "",
+                         "BL_PWR_EN",
+                         "AVDD_1V8_DISP_EN",
+                         "TOUCH_INT",
+                         "TOUCH_RST",
+
+                         "I2C3_SCL_TP",
+                         "I2C3_SDA_TP";
+};
+
+&gpio3 {
+       gpio-line-names = "FLASH0_D0",
+                         "FLASH0_D1",
+                         "FLASH0_D2",
+                         "FLASH0_D3",
+                         "FLASH0_D4",
+                         "FLASH0_D5",
+                         "FLASH0_D6",
+                         "FLASH0_D7",
+
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+
+                         "FLASH0_CS2/EMMC_CMD",
+                         "",
+                         "FLASH0_DQS/EMMC_CLKO";
+};
+
+&gpio4 {
+       gpio-line-names = "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+
+                         "UART0_RXD",
+                         "UART0_TXD",
+                         "UART0_CTS",
+                         "UART0_RTS",
+                         "SDIO0_D0",
+                         "SDIO0_D1",
+                         "SDIO0_D2",
+                         "SDIO0_D3",
+
+                         "SDIO0_CMD",
+                         "SDIO0_CLK",
+                         "dev_wake",
+                         "",
+                         "WIFI_ENABLE_H",
+                         "BT_ENABLE_L",
+                         "WIFI_HOST_WAKE",
+                         "BT_HOST_WAKE";
+};
+
+&gpio5 {
+       gpio-line-names = "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+
+                         "",
+                         "",
+                         "Volum_Up#",
+                         "Volum_Down#",
+                         "SPI0_CLK",
+                         "SPI0_CS0",
+                         "SPI0_TXD",
+                         "SPI0_RXD",
+
+                         "",
+                         "",
+                         "",
+                         "VCC50_HDMI_EN";
+};
+
+&gpio6 {
+       gpio-line-names = "I2S0_SCLK",
+                         "I2S0_LRCK_RX",
+                         "I2S0_LRCK_TX",
+                         "I2S0_SDI",
+                         "I2S0_SDO0",
+                         "HP_DET_H",
+                         "",
+                         "INT_CODEC",
+
+                         "I2S0_CLK",
+                         "I2C2_SDA",
+                         "I2C2_SCL",
+                         "MICDET",
+                         "",
+                         "",
+                         "",
+                         "",
+
+                         "SDMMC_D0",
+                         "SDMMC_D1",
+                         "SDMMC_D2",
+                         "SDMMC_D3",
+                         "SDMMC_CLK",
+                         "SDMMC_CMD";
+};
+
+&gpio7 {
+       gpio-line-names = "LCDC_BL",
+                         "PWM_LOG",
+                         "BL_EN",
+                         "TRACKPAD_INT",
+                         "TPM_INT_H",
+                         "SDMMC_DET_L",
+                         /*
+                          * AP_FLASH_WP_L is Chrome OS ABI.  Schematics call
+                          * it FW_WP_AP.
+                          */
+                         "AP_FLASH_WP_L",
+                         "EC_INT",
+
+                         "CPU_NMI",
+                         "DVS_OK",
+                         "SDMMC_WP",
+                         "EDP_HPD",
+                         "DVS1",
+                         "nFALUT1",
+                         "LCD_EN",
+                         "DVS2",
+
+                         "VCC5V_GOOD_H",
+                         "I2C4_SDA_TP",
+                         "I2C4_SCL_TP",
+                         "I2C5_SDA_HDMI",
+                         "I2C5_SCL_HDMI",
+                         "5V_DRV",
+                         "UART2_RXD",
+                         "UART2_TXD";
+};
+
+&gpio8 {
+       gpio-line-names = "RAM_ID0",
+                         "RAM_ID1",
+                         "RAM_ID2",
+                         "RAM_ID3",
+                         "I2C1_SDA_TPM",
+                         "I2C1_SCL_TPM",
+                         "SPI2_CLK",
+                         "SPI2_CS0",
+
+                         "SPI2_RXD",
+                         "SPI2_TXD";
+};
+
 &pinctrl {
        backlight {
                bl_pwr_en: bl_pwr_en {
index 9645be7..9b6f4d9 100644 (file)
@@ -35,7 +35,7 @@
        force-hpd;
 };
 
-&gpio_keys {
+&lid_switch {
        pinctrl-0 = <&pwr_key_h &ap_lid_int_l>;
 
        power {
index 2ac8748..9b140db 100644 (file)
        temperature = <70000>;
 };
 
+&cpu_crit {
+       temperature = <90000>;
+};
+
 &edp {
        /delete-property/pinctrl-names;
        /delete-property/pinctrl-0;
        force-hpd;
 };
 
+&gpu_alert0 {
+       temperature = <80000>;
+};
+
+&gpu_crit {
+       temperature = <90000>;
+};
+
 &panel {
        power-supply= <&panel_regulator>;
 };
        pinctrl-0 = <&vcc50_hdmi_en>;
 };
 
+&gpio0 {
+       gpio-line-names = "PMIC_SLEEP_AP",
+                         "DDRIO_PWROFF",
+                         "DDRIO_RETEN",
+                         "TS3A227E_INT_L",
+                         "PMIC_INT_L",
+                         "PWR_KEY_L",
+                         "AP_LID_INT_L",
+                         "EC_IN_RW",
+
+                         "AC_PRESENT_AP",
+                         /*
+                          * RECOVERY_SW_L is Chrome OS ABI.  Schematics call
+                          * it REC_MODE_L.
+                          */
+                         "RECOVERY_SW_L",
+                         "OTP_OUT",
+                         "HOST1_PWR_EN",
+                         "USBOTG_PWREN_H",
+                         "AP_WARM_RESET_H",
+                         "nFALUT2",
+                         "I2C0_SDA_PMIC",
+
+                         "I2C0_SCL_PMIC",
+                         "SUSPEND_L",
+                         "USB_INT";
+};
+
+&gpio2 {
+       gpio-line-names = "CONFIG0",
+                         "CONFIG1",
+                         "CONFIG2",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "CONFIG3",
+
+                         "PWRLIMIT#_CPU",
+                         "EMMC_RST_L",
+                         "",
+                         "",
+                         "BL_PWR_EN",
+                         "AVDD_1V8_DISP_EN";
+};
+
+&gpio3 {
+       gpio-line-names = "FLASH0_D0",
+                         "FLASH0_D1",
+                         "FLASH0_D2",
+                         "FLASH0_D3",
+                         "FLASH0_D4",
+                         "FLASH0_D5",
+                         "FLASH0_D6",
+                         "FLASH0_D7",
+
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+
+                         "FLASH0_CS2/EMMC_CMD",
+                         "",
+                         "FLASH0_DQS/EMMC_CLKO";
+};
+
+&gpio4 {
+       gpio-line-names = "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+
+                         "UART0_RXD",
+                         "UART0_TXD",
+                         "UART0_CTS",
+                         "UART0_RTS",
+                         "SDIO0_D0",
+                         "SDIO0_D1",
+                         "SDIO0_D2",
+                         "SDIO0_D3",
+
+                         "SDIO0_CMD",
+                         "SDIO0_CLK",
+                         "BT_DEV_WAKE",
+                         "",
+                         "WIFI_ENABLE_H",
+                         "BT_ENABLE_L",
+                         "WIFI_HOST_WAKE",
+                         "BT_HOST_WAKE";
+};
+
+&gpio5 {
+       gpio-line-names = "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+
+                         "",
+                         "",
+                         "",
+                         "",
+                         "SPI0_CLK",
+                         "SPI0_CS0",
+                         "SPI0_TXD",
+                         "SPI0_RXD",
+
+                         "",
+                         "",
+                         "",
+                         "VCC50_HDMI_EN";
+};
+
+&gpio6 {
+       gpio-line-names = "I2S0_SCLK",
+                         "I2S0_LRCK_RX",
+                         "I2S0_LRCK_TX",
+                         "I2S0_SDI",
+                         "I2S0_SDO0",
+                         "HP_DET_H",
+                         "ALS_INT",            /* not connected */
+                         "INT_CODEC",
+
+                         "I2S0_CLK",
+                         "I2C2_SDA",
+                         "I2C2_SCL",
+                         "MICDET",
+                         "",
+                         "",
+                         "",
+                         "",
+
+                         "SDMMC_D0",
+                         "SDMMC_D1",
+                         "SDMMC_D2",
+                         "SDMMC_D3",
+                         "SDMMC_CLK",
+                         "SDMMC_CMD";
+};
+
+&gpio7 {
+       gpio-line-names = "LCDC_BL",
+                         "PWM_LOG",
+                         "BL_EN",
+                         "TRACKPAD_INT",
+                         "TPM_INT_H",
+                         "SDMMC_DET_L",
+                         /*
+                          * AP_FLASH_WP_L is Chrome OS ABI.  Schematics call
+                          * it FW_WP_AP.
+                          */
+                         "AP_FLASH_WP_L",
+                         "EC_INT",
+
+                         "CPU_NMI",
+                         "DVS_OK",
+                         "",
+                         "EDP_HOTPLUG",
+                         "DVS1",
+                         "nFALUT1",
+                         "LCD_EN",
+                         "DVS2",
+
+                         "VCC5V_GOOD_H",
+                         "I2C4_SDA_TP",
+                         "I2C4_SCL_TP",
+                         "I2C5_SDA_HDMI",
+                         "I2C5_SCL_HDMI",
+                         "5V_DRV",
+                         "UART2_RXD",
+                         "UART2_TXD";
+};
+
+&gpio8 {
+       gpio-line-names = "RAM_ID0",
+                         "RAM_ID1",
+                         "RAM_ID2",
+                         "RAM_ID3",
+                         "I2C1_SDA_TPM",
+                         "I2C1_SCL_TPM",
+                         "SPI2_CLK",
+                         "SPI2_CS0",
+
+                         "SPI2_RXD",
+                         "SPI2_TXD";
+};
+
 &pinctrl {
        backlight {
                bl_pwr_en: bl_pwr_en {
index 1d8bfed..8fc8eac 100644 (file)
                reg = <0x0 0x0 0x0 0x80000000>;
        };
 
-       gpio_keys: gpio-keys {
+       bt_activity: bt-activity {
                compatible = "gpio-keys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&bt_host_wake>;
+
+               /*
+                * HACK: until we have an LPM driver, we'll use an
+                * ugly GPIO key to allow Bluetooth to wake from S3.
+                * This is expected to only be used by BT modules that
+                * use UART for comms.  For BT modules that talk over
+                * SDIO we should use a wakeup mechanism related to SDIO.
+                *
+                * Use KEY_RESERVED here since that will work as a wakeup but
+                * doesn't get reported to higher levels (so doesn't confuse
+                * Chrome).
+                */
+               bt-wake {
+                       label = "BT Wakeup";
+                       gpios = <&gpio4 RK_PD7 GPIO_ACTIVE_HIGH>;
+                       linux,code = <KEY_RESERVED>;
+                       wakeup-source;
+               };
+
+       };
 
+       power_button: power-button {
+               compatible = "gpio-keys";
                pinctrl-names = "default";
                pinctrl-0 = <&pwr_key_l>;
+
                power {
                        label = "Power";
                        gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
        cpu0-supply = <&vdd_cpu>;
 };
 
+&cpu_crit {
+       temperature = <100000>;
+};
+
 /* rk3288-c used in Veyron Chrome-devices has slightly changed OPPs */
 &cpu_opp_table {
        /delete-node/ opp-312000000;
        status = "okay";
 };
 
+&gpu_alert0 {
+       temperature = <72500>;
+};
+
+&gpu_crit {
+       temperature = <100000>;
+};
+
 &hdmi {
-       ddc-i2c-bus = <&i2c5>;
+       pinctrl-names = "default", "unwedge";
+       pinctrl-0 = <&hdmi_ddc>;
+       pinctrl-1 = <&hdmi_ddc_unwedge>;
        status = "okay";
 };
 
        i2c-scl-rising-time-ns = <300>;         /* 225ns measured */
 };
 
-&i2c5 {
-       status = "okay";
-
-       clock-frequency = <100000>;
-       i2c-scl-falling-time-ns = <300>;
-       i2c-scl-rising-time-ns = <1000>;
-};
-
 &io_domains {
        status = "okay";
 
 
        rockchip,hw-tshut-mode = <1>; /* tshut mode 0:CRU 1:GPIO */
        rockchip,hw-tshut-polarity = <1>; /* tshut polarity 0:LOW 1:HIGH */
+       rockchip,hw-tshut-temp = <125000>;
 };
 
 &uart0 {
                &ddr0_retention
                &ddrio_pwroff
                &global_pwroff
+
+               /* Wake only */
+               &bt_dev_wake_awake
        >;
        pinctrl-1 = <
                /* Common for sleep and wake, but no owners */
                &ddr0_retention
                &ddrio_pwroff
                &global_pwroff
+
+               /* Sleep only */
+               &bt_dev_wake_sleep
        >;
 
        pcfg_pull_none_drv_8ma: pcfg-pull-none-drv-8ma {
                        rockchip,pins = <4 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
+               bt_host_wake: bt-host-wake {
+                       rockchip,pins = <4 RK_PD7 RK_FUNC_GPIO &pcfg_pull_down>;
+               };
+
                /*
                 * We run sdio0 at max speed; bump up drive strength.
                 * We also have external pulls, so disable the internal ones.
                sdio0_clk: sdio0-clk {
                        rockchip,pins = <4 RK_PD1 1 &pcfg_pull_none_drv_8ma>;
                };
+
+               /*
+                * These pins are only present on very new veyron boards; on
+                * older boards bt_dev_wake is simply always high.  Note that
+                * gpio4_D2 is a NC on old veyron boards, so it doesn't hurt
+                * to map this pin everywhere
+                */
+               bt_dev_wake_sleep: bt-dev-wake-sleep {
+                       rockchip,pins = <4 RK_PD2 RK_FUNC_GPIO &pcfg_output_low>;
+               };
+
+               bt_dev_wake_awake: bt-dev-wake-awake {
+                       rockchip,pins = <4 RK_PD2 RK_FUNC_GPIO &pcfg_output_high>;
+               };
        };
 
        tpm {
index aa017ab..cc893e1 100644 (file)
                             <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
                             <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
                clock-frequency = <24000000>;
+               arm,no-tick-in-suspend;
        };
 
        timer: timer@ff810000 {
                                map0 {
                                        trip = <&gpu_alert0>;
                                        cooling-device =
-                                               <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-                                               <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-                                               <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-                                               <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                                               <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
                                };
                        };
                };
                #pwm-cells = <3>;
                pinctrl-names = "default";
                pinctrl-0 = <&pwm0_pin>;
-               clocks = <&cru PCLK_PWM>;
+               clocks = <&cru PCLK_RKPWM>;
                clock-names = "pwm";
                status = "disabled";
        };
                #pwm-cells = <3>;
                pinctrl-names = "default";
                pinctrl-0 = <&pwm1_pin>;
-               clocks = <&cru PCLK_PWM>;
+               clocks = <&cru PCLK_RKPWM>;
                clock-names = "pwm";
                status = "disabled";
        };
                #pwm-cells = <3>;
                pinctrl-names = "default";
                pinctrl-0 = <&pwm2_pin>;
-               clocks = <&cru PCLK_PWM>;
+               clocks = <&cru PCLK_RKPWM>;
                clock-names = "pwm";
                status = "disabled";
        };
        pwm3: pwm@ff680030 {
                compatible = "rockchip,rk3288-pwm";
                reg = <0x0 0xff680030 0x0 0x10>;
-               #pwm-cells = <2>;
+               #pwm-cells = <3>;
                pinctrl-names = "default";
                pinctrl-0 = <&pwm3_pin>;
-               clocks = <&cru PCLK_PWM>;
+               clocks = <&cru PCLK_RKPWM>;
                clock-names = "pwm";
                status = "disabled";
        };
                interrupt-names = "job", "mmu", "gpu";
                clocks = <&cru ACLK_GPU>;
                operating-points-v2 = <&gpu_opp_table>;
+               #cooling-cells = <2>; /* min followed by max */
                power-domains = <&power RK3288_PD_GPU>;
                status = "disabled";
        };
                        opp-hz = /bits/ 64 <400000000>;
                        opp-microvolt = <1100000>;
                };
-               opp-500000000 {
-                       opp-hz = /bits/ 64 <500000000>;
-                       opp-microvolt = <1200000>;
-               };
                opp-600000000 {
                        opp-hz = /bits/ 64 <600000000>;
                        opp-microvolt = <1250000>;
                                rockchip,pins = <7 RK_PC3 2 &pcfg_pull_none>,
                                                <7 RK_PC4 2 &pcfg_pull_none>;
                        };
+
+                       hdmi_ddc_unwedge: hdmi-ddc-unwedge {
+                               rockchip,pins = <7 RK_PC3 RK_FUNC_GPIO &pcfg_output_low>,
+                                               <7 RK_PC4 2 &pcfg_pull_none>;
+                       };
+               };
+
+               pcfg_output_low: pcfg-output-low {
+                       output-low;
                };
 
                pcfg_pull_up: pcfg-pull-up {
index 3bbc84b..f770aac 100644 (file)
                                status = "disabled";
                        };
 
-                       sckc@fffffe50 {
-                               compatible = "atmel,at91sam9x5-sckc";
+                       clk32k: sckc@fffffe50 {
+                               compatible = "atmel,sama5d3-sckc";
                                reg = <0xfffffe50 0x4>;
-
-                               slow_rc_osc: slow_rc_osc {
-                                       compatible = "atmel,at91sam9x5-clk-slow-rc-osc";
-                                       #clock-cells = <0>;
-                                       clock-frequency = <32768>;
-                                       clock-accuracy = <50000000>;
-                                       atmel,startup-time-usec = <75>;
-                               };
-
-                               slow_osc: slow_osc {
-                                       compatible = "atmel,at91sam9x5-clk-slow-osc";
-                                       #clock-cells = <0>;
-                                       clocks = <&slow_xtal>;
-                                       atmel,startup-time-usec = <1200000>;
-                               };
-
-                               clk32k: slowck {
-                                       compatible = "atmel,at91sam9x5-clk-slow";
-                                       #clock-cells = <0>;
-                                       clocks = <&slow_rc_osc &slow_osc>;
-                               };
+                               clocks = <&slow_xtal>;
+                               #clock-cells = <0>;
                        };
 
                        rtc@fffffeb0 {
index daac0c6..1916f31 100644 (file)
@@ -36,7 +36,7 @@
        };
 
        chosen {
-               bootargs = "root=/dev/nfs ip=dhcp ignore_loglevel rw";
+               bootargs = "root=/dev/nfs ip=on ignore_loglevel rw";
                stdout-path = "serial0:115200n8";
        };
 
index ae24599..a0a6d85 100644 (file)
                };
 
                gmac0: ethernet@ff800000 {
-                       compatible = "altr,socfpga-stmmac", "snps,dwmac-3.72a", "snps,dwmac";
+                       compatible = "altr,socfpga-stmmac-a10-s10", "snps,dwmac-3.72a", "snps,dwmac";
                        altr,sysmgr-syscon = <&sysmgr 0x44 0>;
                        reg = <0xff800000 0x2000>;
                        interrupts = <0 92 IRQ_TYPE_LEVEL_HIGH>;
                        rx-fifo-depth = <16384>;
                        clocks = <&l4_mp_clk>;
                        clock-names = "stmmaceth";
-                       resets = <&rst EMAC0_RESET>;
-                       reset-names = "stmmaceth";
+                       resets = <&rst EMAC0_RESET>, <&rst EMAC0_OCP_RESET>;
+                       reset-names = "stmmaceth", "stmmaceth-ocp";
                        snps,axi-config = <&socfpga_axi_setup>;
                        status = "disabled";
                };
 
                gmac1: ethernet@ff802000 {
-                       compatible = "altr,socfpga-stmmac", "snps,dwmac-3.72a", "snps,dwmac";
-                       altr,sysmgr-syscon = <&sysmgr 0x48 0>;
+                       compatible = "altr,socfpga-stmmac-a10-s10", "snps,dwmac-3.72a", "snps,dwmac";
+                       altr,sysmgr-syscon = <&sysmgr 0x48 8>;
                        reg = <0xff802000 0x2000>;
                        interrupts = <0 93 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "macirq";
                        rx-fifo-depth = <16384>;
                        clocks = <&l4_mp_clk>;
                        clock-names = "stmmaceth";
-                       resets = <&rst EMAC1_RESET>;
-                       reset-names = "stmmaceth";
+                       resets = <&rst EMAC1_RESET>, <&rst EMAC1_OCP_RESET>;
+                       reset-names = "stmmaceth", "stmmaceth-ocp";
                        snps,axi-config = <&socfpga_axi_setup>;
                        status = "disabled";
                };
 
                gmac2: ethernet@ff804000 {
-                       compatible = "altr,socfpga-stmmac", "snps,dwmac-3.72a", "snps,dwmac";
-                       altr,sysmgr-syscon = <&sysmgr 0x4C 0>;
+                       compatible = "altr,socfpga-stmmac-a10-s10", "snps,dwmac-3.72a", "snps,dwmac";
+                       altr,sysmgr-syscon = <&sysmgr 0x4C 16>;
                        reg = <0xff804000 0x2000>;
                        interrupts = <0 94 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "macirq";
                        tx-fifo-depth = <4096>;
                        rx-fifo-depth = <16384>;
                        clocks = <&l4_mp_clk>;
-                       resets = <&rst EMAC2_RESET>;
                        clock-names = "stmmaceth";
+                       resets = <&rst EMAC2_RESET>, <&rst EMAC2_OCP_RESET>;
+                       reset-names = "stmmaceth", "stmmaceth-ocp";
                        snps,axi-config = <&socfpga_axi_setup>;
                        status = "disabled";
                };
index 360dae5..0efbecc 100644 (file)
                };
        };
 
+       ref_033v: 033-v-ref {
+               compatible = "regulator-fixed";
+               regulator-name = "0.33V";
+               regulator-min-microvolt = <330000>;
+               regulator-max-microvolt = <330000>;
+       };
+
        soc {
                clkmgr@ffd04000 {
                        clocks {
        i2c-sda-falling-time-ns = <6000>;
        i2c-scl-falling-time-ns = <6000>;
 
+       adc@14 {
+               compatible = "lltc,ltc2497";
+               reg = <0x14>;
+               vref-supply = <&ref_033v>;
+       };
+
+       adc@16 {
+               compatible = "lltc,ltc2497";
+               reg = <0x16>;
+               vref-supply = <&ref_033v>;
+       };
+
        eeprom@51 {
                compatible = "atmel,24c32";
                reg = <0x51>;
index d90b0d1..2b16648 100644 (file)
@@ -44,6 +44,7 @@
 #include "stm32f746.dtsi"
 #include "stm32f746-pinctrl.dtsi"
 #include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
 
 / {
        model = "STMicroelectronics STM32746g-EVAL board";
                        gpios = <&gpiof 10 1>;
                        linux,default-trigger = "heartbeat";
                };
+               orange {
+                       gpios = <&stmfx_pinctrl 17 1>;
+               };
                red {
                        gpios = <&gpiob 7 1>;
                };
+               blue {
+                       gpios = <&stmfx_pinctrl 19 1>;
+               };
        };
 
        gpio_keys {
                };
        };
 
+       joystick {
+               compatible = "gpio-keys";
+               #size-cells = <0>;
+               pinctrl-0 = <&joystick_pins>;
+               pinctrl-names = "default";
+               button-0 {
+                       label = "JoySel";
+                       linux,code = <KEY_ENTER>;
+                       interrupt-parent = <&stmfx_pinctrl>;
+                       interrupts = <0 IRQ_TYPE_EDGE_FALLING>;
+               };
+               button-1 {
+                       label = "JoyDown";
+                       linux,code = <KEY_DOWN>;
+                       interrupt-parent = <&stmfx_pinctrl>;
+                       interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
+               };
+               button-2 {
+                       label = "JoyLeft";
+                       linux,code = <KEY_LEFT>;
+                       interrupt-parent = <&stmfx_pinctrl>;
+                       interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
+               };
+               button-3 {
+                       label = "JoyRight";
+                       linux,code = <KEY_RIGHT>;
+                       interrupt-parent = <&stmfx_pinctrl>;
+                       interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
+               };
+               button-4 {
+                       label = "JoyUp";
+                       linux,code = <KEY_UP>;
+                       interrupt-parent = <&stmfx_pinctrl>;
+                       interrupts = <4 IRQ_TYPE_EDGE_FALLING>;
+               };
+       };
+
        usbotg_hs_phy: usb-phy {
                #phy-cells = <0>;
                compatible = "usb-nop-xceiv";
        i2c-scl-rising-time-ns = <185>;
        i2c-scl-falling-time-ns = <20>;
        status = "okay";
+
+       stmfx: stmfx@42 {
+               compatible = "st,stmfx-0300";
+               reg = <0x42>;
+               interrupts = <8 IRQ_TYPE_EDGE_RISING>;
+               interrupt-parent = <&gpioi>;
+
+               stmfx_pinctrl: stmfx-pin-controller {
+                       compatible = "st,stmfx-0300-pinctrl";
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+                       gpio-ranges = <&stmfx_pinctrl 0 0 24>;
+
+                       joystick_pins: joystick {
+                               pins = "gpio0", "gpio1", "gpio2", "gpio3", "gpio4";
+                               drive-push-pull;
+                               bias-pull-up;
+                       };
+               };
+       };
 };
 
 &rtc {
index 85c417d..df64701 100644 (file)
@@ -26,6 +26,7 @@
                                st,bank-name = "GPIOA";
                                ngpios = <16>;
                                gpio-ranges = <&pinctrl 0 0 16>;
+                               status = "disabled";
                        };
 
                        gpiob: gpio@50003000 {
@@ -38,6 +39,7 @@
                                st,bank-name = "GPIOB";
                                ngpios = <16>;
                                gpio-ranges = <&pinctrl 0 16 16>;
+                               status = "disabled";
                        };
 
                        gpioc: gpio@50004000 {
@@ -50,6 +52,7 @@
                                st,bank-name = "GPIOC";
                                ngpios = <16>;
                                gpio-ranges = <&pinctrl 0 32 16>;
+                               status = "disabled";
                        };
 
                        gpiod: gpio@50005000 {
@@ -62,6 +65,7 @@
                                st,bank-name = "GPIOD";
                                ngpios = <16>;
                                gpio-ranges = <&pinctrl 0 48 16>;
+                               status = "disabled";
                        };
 
                        gpioe: gpio@50006000 {
@@ -74,6 +78,7 @@
                                st,bank-name = "GPIOE";
                                ngpios = <16>;
                                gpio-ranges = <&pinctrl 0 64 16>;
+                               status = "disabled";
                        };
 
                        gpiof: gpio@50007000 {
@@ -86,6 +91,7 @@
                                st,bank-name = "GPIOF";
                                ngpios = <16>;
                                gpio-ranges = <&pinctrl 0 80 16>;
+                               status = "disabled";
                        };
 
                        gpiog: gpio@50008000 {
                                st,bank-name = "GPIOG";
                                ngpios = <16>;
                                gpio-ranges = <&pinctrl 0 96 16>;
+                               status = "disabled";
                        };
 
                        gpioh: gpio@50009000 {
                                st,bank-name = "GPIOH";
                                ngpios = <16>;
                                gpio-ranges = <&pinctrl 0 112 16>;
+                               status = "disabled";
                        };
 
                        gpioi: gpio@5000a000 {
                                st,bank-name = "GPIOI";
                                ngpios = <16>;
                                gpio-ranges = <&pinctrl 0 128 16>;
+                               status = "disabled";
                        };
 
                        gpioj: gpio@5000b000 {
                                st,bank-name = "GPIOJ";
                                ngpios = <16>;
                                gpio-ranges = <&pinctrl 0 144 16>;
+                               status = "disabled";
                        };
 
                        gpiok: gpio@5000c000 {
                                st,bank-name = "GPIOK";
                                ngpios = <8>;
                                gpio-ranges = <&pinctrl 0 160 8>;
+                               status = "disabled";
                        };
 
                        cec_pins_a: cec-0 {
                                };
                        };
 
+                       dcmi_pins_a: dcmi-0 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('H', 8,  AF13)>,/* DCMI_HSYNC */
+                                                <STM32_PINMUX('B', 7,  AF13)>,/* DCMI_VSYNC */
+                                                <STM32_PINMUX('A', 6,  AF13)>,/* DCMI_PIXCLK */
+                                                <STM32_PINMUX('H', 9,  AF13)>,/* DCMI_D0 */
+                                                <STM32_PINMUX('H', 10, AF13)>,/* DCMI_D1 */
+                                                <STM32_PINMUX('H', 11, AF13)>,/* DCMI_D2 */
+                                                <STM32_PINMUX('H', 12, AF13)>,/* DCMI_D3 */
+                                                <STM32_PINMUX('H', 14, AF13)>,/* DCMI_D4 */
+                                                <STM32_PINMUX('I', 4,  AF13)>,/* DCMI_D5 */
+                                                <STM32_PINMUX('B', 8,  AF13)>,/* DCMI_D6 */
+                                                <STM32_PINMUX('E', 6,  AF13)>,/* DCMI_D7 */
+                                                <STM32_PINMUX('I', 1,  AF13)>,/* DCMI_D8 */
+                                                <STM32_PINMUX('H', 7,  AF13)>,/* DCMI_D9 */
+                                                <STM32_PINMUX('I', 3,  AF13)>,/* DCMI_D10 */
+                                                <STM32_PINMUX('H', 15, AF13)>;/* DCMI_D11 */
+                                       bias-disable;
+                               };
+                       };
+
+                       dcmi_sleep_pins_a: dcmi-sleep-0 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('H', 8,  ANALOG)>,/* DCMI_HSYNC */
+                                                <STM32_PINMUX('B', 7,  ANALOG)>,/* DCMI_VSYNC */
+                                                <STM32_PINMUX('A', 6,  ANALOG)>,/* DCMI_PIXCLK */
+                                                <STM32_PINMUX('H', 9,  ANALOG)>,/* DCMI_D0 */
+                                                <STM32_PINMUX('H', 10, ANALOG)>,/* DCMI_D1 */
+                                                <STM32_PINMUX('H', 11, ANALOG)>,/* DCMI_D2 */
+                                                <STM32_PINMUX('H', 12, ANALOG)>,/* DCMI_D3 */
+                                                <STM32_PINMUX('H', 14, ANALOG)>,/* DCMI_D4 */
+                                                <STM32_PINMUX('I', 4,  ANALOG)>,/* DCMI_D5 */
+                                                <STM32_PINMUX('B', 8,  ANALOG)>,/* DCMI_D6 */
+                                                <STM32_PINMUX('E', 6,  ANALOG)>,/* DCMI_D7 */
+                                                <STM32_PINMUX('I', 1,  ANALOG)>,/* DCMI_D8 */
+                                                <STM32_PINMUX('H', 7,  ANALOG)>,/* DCMI_D9 */
+                                                <STM32_PINMUX('I', 3,  ANALOG)>,/* DCMI_D10 */
+                                                <STM32_PINMUX('H', 15, ANALOG)>;/* DCMI_D11 */
+                               };
+                       };
+
                        ethernet0_rgmii_pins_a: rgmii-0 {
                                pins1 {
                                        pinmux = <STM32_PINMUX('G', 5, AF11)>, /* ETH_RGMII_CLK125 */
                                };
                        };
 
+                       i2c1_pins_b: i2c1-2 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('F', 14, AF5)>, /* I2C1_SCL */
+                                                <STM32_PINMUX('F', 15, AF5)>; /* I2C1_SDA */
+                                       bias-disable;
+                                       drive-open-drain;
+                                       slew-rate = <0>;
+                               };
+                       };
+
+                       i2c1_pins_sleep_b: i2c1-3 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('F', 14, ANALOG)>, /* I2C1_SCL */
+                                                <STM32_PINMUX('F', 15, ANALOG)>; /* I2C1_SDA */
+                               };
+                       };
+
                        i2c2_pins_a: i2c2-0 {
                                pins {
                                        pinmux = <STM32_PINMUX('H', 4, AF4)>, /* I2C2_SCL */
                                };
                        };
 
+                       i2c2_pins_b1: i2c2-2 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('H', 5, AF4)>; /* I2C2_SDA */
+                                       bias-disable;
+                                       drive-open-drain;
+                                       slew-rate = <0>;
+                               };
+                       };
+
+                       i2c2_pins_sleep_b1: i2c2-3 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('H', 5, ANALOG)>; /* I2C2_SDA */
+                               };
+                       };
+
                        i2c5_pins_a: i2c5-0 {
                                pins {
                                        pinmux = <STM32_PINMUX('A', 11, AF4)>, /* I2C5_SCL */
                                };
                        };
 
+                       i2s2_pins_a: i2s2-0 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('I', 3, AF5)>, /* I2S2_SDO */
+                                                <STM32_PINMUX('B', 9, AF5)>, /* I2S2_WS */
+                                                <STM32_PINMUX('A', 9, AF5)>; /* I2S2_CK */
+                                       slew-rate = <1>;
+                                       drive-push-pull;
+                                       bias-disable;
+                               };
+                       };
+
+                       i2s2_pins_sleep_a: i2s2-1 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('I', 3, ANALOG)>, /* I2S2_SDO */
+                                                <STM32_PINMUX('B', 9, ANALOG)>, /* I2S2_WS */
+                                                <STM32_PINMUX('A', 9, ANALOG)>; /* I2S2_CK */
+                               };
+                       };
+
                        ltdc_pins_a: ltdc-a-0 {
                                pins {
                                        pinmux = <STM32_PINMUX('G',  7, AF14)>, /* LCD_CLK */
                                };
                        };
 
+                       qspi_clk_sleep_pins_a: qspi-clk-sleep-0 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('F', 10, ANALOG)>; /* QSPI_CLK */
+                               };
+                       };
+
                        qspi_bk1_pins_a: qspi-bk1-0 {
                                pins1 {
                                        pinmux = <STM32_PINMUX('F', 8, AF10)>, /* QSPI_BK1_IO0 */
                                };
                        };
 
+                       qspi_bk1_sleep_pins_a: qspi-bk1-sleep-0 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('F', 8, ANALOG)>, /* QSPI_BK1_IO0 */
+                                                <STM32_PINMUX('F', 9, ANALOG)>, /* QSPI_BK1_IO1 */
+                                                <STM32_PINMUX('F', 7, ANALOG)>, /* QSPI_BK1_IO2 */
+                                                <STM32_PINMUX('F', 6, ANALOG)>, /* QSPI_BK1_IO3 */
+                                                <STM32_PINMUX('B', 6, ANALOG)>; /* QSPI_BK1_NCS */
+                               };
+                       };
+
                        qspi_bk2_pins_a: qspi-bk2-0 {
                                pins1 {
                                        pinmux = <STM32_PINMUX('H', 2, AF9)>, /* QSPI_BK2_IO0 */
                                };
                        };
 
+                       qspi_bk2_sleep_pins_a: qspi-bk2-sleep-0 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('H', 2, ANALOG)>, /* QSPI_BK2_IO0 */
+                                                <STM32_PINMUX('H', 3, ANALOG)>, /* QSPI_BK2_IO1 */
+                                                <STM32_PINMUX('G', 10, ANALOG)>, /* QSPI_BK2_IO2 */
+                                                <STM32_PINMUX('G', 7, ANALOG)>, /* QSPI_BK2_IO3 */
+                                                <STM32_PINMUX('C', 0, ANALOG)>; /* QSPI_BK2_NCS */
+                               };
+                       };
+
+                       sai2a_pins_a: sai2a-0 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('I', 5, AF10)>, /* SAI2_SCK_A */
+                                                <STM32_PINMUX('I', 6, AF10)>, /* SAI2_SD_A */
+                                                <STM32_PINMUX('I', 7, AF10)>, /* SAI2_FS_A */
+                                                <STM32_PINMUX('E', 0, AF10)>; /* SAI2_MCLK_A */
+                                       slew-rate = <0>;
+                                       drive-push-pull;
+                                       bias-disable;
+                               };
+                       };
+
+                       sai2a_sleep_pins_a: sai2a-1 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('I', 5, ANALOG)>, /* SAI2_SCK_A */
+                                                <STM32_PINMUX('I', 6, ANALOG)>, /* SAI2_SD_A */
+                                                <STM32_PINMUX('I', 7, ANALOG)>, /* SAI2_FS_A */
+                                                <STM32_PINMUX('E', 0, ANALOG)>; /* SAI2_MCLK_A */
+                               };
+                       };
+
+                       sai2b_pins_a: sai2b-0 {
+                               pins1 {
+                                       pinmux = <STM32_PINMUX('E', 12, AF10)>, /* SAI2_SCK_B */
+                                                <STM32_PINMUX('E', 13, AF10)>, /* SAI2_FS_B */
+                                                <STM32_PINMUX('E', 14, AF10)>; /* SAI2_MCLK_B */
+                                       slew-rate = <0>;
+                                       drive-push-pull;
+                                       bias-disable;
+                               };
+                               pins2 {
+                                       pinmux = <STM32_PINMUX('F', 11, AF10)>; /* SAI2_SD_B */
+                                       bias-disable;
+                               };
+                       };
+
+                       sai2b_sleep_pins_a: sai2b-1 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('F', 11, ANALOG)>, /* SAI2_SD_B */
+                                                <STM32_PINMUX('E', 12, ANALOG)>, /* SAI2_SCK_B */
+                                                <STM32_PINMUX('E', 13, ANALOG)>, /* SAI2_FS_B */
+                                                <STM32_PINMUX('E', 14, ANALOG)>; /* SAI2_MCLK_B */
+                               };
+                       };
+
+                       sai2b_pins_b: sai2b-2 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('F', 11, AF10)>; /* SAI2_SD_B */
+                                       bias-disable;
+                               };
+                       };
+
+                       sai2b_sleep_pins_b: sai2b-3 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('F', 11, ANALOG)>; /* SAI2_SD_B */
+                               };
+                       };
+
+                       sai4a_pins_a: sai4a-0 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('B', 5, AF10)>; /* SAI4_SD_A */
+                                       slew-rate = <0>;
+                                       drive-push-pull;
+                                       bias-disable;
+                               };
+                       };
+
+                       sai4a_sleep_pins_a: sai4a-1 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('B', 5, ANALOG)>; /* SAI4_SD_A */
+                               };
+                       };
+
                        sdmmc1_b4_pins_a: sdmmc1-b4-0 {
                                pins {
                                        pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
                                        bias-disable;
                                };
                        };
+
+                       uart4_pins_b: uart4-1 {
+                               pins1 {
+                                       pinmux = <STM32_PINMUX('D', 1, AF8)>; /* UART4_TX */
+                                       bias-disable;
+                                       drive-push-pull;
+                                       slew-rate = <0>;
+                               };
+                               pins2 {
+                                       pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+                                       bias-disable;
+                               };
+                       };
+
+                       uart7_pins_a: uart7-0 {
+                               pins1 {
+                                       pinmux = <STM32_PINMUX('E', 8, AF7)>; /* UART4_TX */
+                                       bias-disable;
+                                       drive-push-pull;
+                                       slew-rate = <0>;
+                               };
+                               pins2 {
+                                       pinmux = <STM32_PINMUX('E', 7, AF7)>, /* UART4_RX */
+                                                <STM32_PINMUX('E', 10, AF7)>, /* UART4_CTS */
+                                                <STM32_PINMUX('E', 9, AF7)>; /* UART4_RTS */
+                                       bias-disable;
+                               };
+                       };
                };
 
                pinctrl_z: pin-controller-z@54004000 {
                                st,bank-ioport = <11>;
                                ngpios = <8>;
                                gpio-ranges = <&pinctrl_z 0 400 8>;
+                               status = "disabled";
+                       };
+
+                       i2c2_pins_b2: i2c2-0 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('Z', 0, AF3)>; /* I2C2_SCL */
+                                       bias-disable;
+                                       drive-open-drain;
+                                       slew-rate = <0>;
+                               };
+                       };
+
+                       i2c2_pins_sleep_b2: i2c2-1 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('Z', 0, ANALOG)>; /* I2C2_SCL */
+                               };
                        };
 
                        i2c4_pins_a: i2c4-0 {
diff --git a/arch/arm/boot/dts/stm32mp157a-avenger96.dts b/arch/arm/boot/dts/stm32mp157a-avenger96.dts
new file mode 100644 (file)
index 0000000..2e4742c
--- /dev/null
@@ -0,0 +1,321 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Copyright (C) Linaro Ltd 2019 - All Rights Reserved
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ */
+
+/dts-v1/;
+
+#include "stm32mp157c.dtsi"
+#include "stm32mp157xac-pinctrl.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/mfd/st,stpmic1.h>
+
+/ {
+       model = "Arrow Electronics STM32MP157A Avenger96 board";
+       compatible = "arrow,stm32mp157a-avenger96", "st,stm32mp157";
+
+       aliases {
+               ethernet0 = &ethernet0;
+               mmc0 = &sdmmc1;
+               serial0 = &uart4;
+               serial1 = &uart7;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory@c0000000 {
+               device_type = "memory";
+               reg = <0xc0000000 0x40000000>;
+       };
+
+       led {
+               compatible = "gpio-leds";
+               led1 {
+                       label = "green:user1";
+                       gpios = <&gpioz 7 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "heartbeat";
+                       default-state = "off";
+               };
+
+               led2 {
+                       label = "green:user2";
+                       gpios = <&gpiof 3 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "mmc0";
+                       default-state = "off";
+               };
+
+               led3 {
+                       label = "green:user3";
+                       gpios = <&gpiog 0 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "mmc1";
+                       default-state = "off";
+               };
+
+               led4 {
+                       label = "green:user3";
+                       gpios = <&gpiog 1 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "none";
+                       default-state = "off";
+                       panic-indicator;
+               };
+
+               led5 {
+                       label = "yellow:wifi";
+                       gpios = <&gpioz 3 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "phy0tx";
+                       default-state = "off";
+               };
+
+               led6 {
+                       label = "blue:bt";
+                       gpios = <&gpioz 6 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "bluetooth-power";
+                       default-state = "off";
+               };
+       };
+};
+
+&ethernet0 {
+       status = "okay";
+       pinctrl-0 = <&ethernet0_rgmii_pins_a>;
+       pinctrl-1 = <&ethernet0_rgmii_pins_sleep_a>;
+       pinctrl-names = "default", "sleep";
+       phy-mode = "rgmii";
+       max-speed = <1000>;
+       phy-handle = <&phy0>;
+
+       mdio0 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "snps,dwmac-mdio";
+               phy0: ethernet-phy@7 {
+                       reg = <7>;
+               };
+       };
+};
+
+&i2c1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c1_pins_b>;
+       i2c-scl-rising-time-ns = <185>;
+       i2c-scl-falling-time-ns = <20>;
+       status = "okay";
+       /delete-property/dmas;
+       /delete-property/dma-names;
+};
+
+&i2c2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c2_pins_b1 &i2c2_pins_b2>;
+       i2c-scl-rising-time-ns = <185>;
+       i2c-scl-falling-time-ns = <20>;
+       status = "okay";
+       /delete-property/dmas;
+       /delete-property/dma-names;
+};
+
+&i2c4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c4_pins_a>;
+       i2c-scl-rising-time-ns = <185>;
+       i2c-scl-falling-time-ns = <20>;
+       status = "okay";
+       /delete-property/dmas;
+       /delete-property/dma-names;
+
+       pmic: stpmic@33 {
+               compatible = "st,stpmic1";
+               reg = <0x33>;
+               interrupts-extended = <&exti 55 IRQ_TYPE_EDGE_FALLING>;
+               interrupt-controller;
+               #interrupt-cells = <2>;
+               status = "okay";
+
+               st,main-control-register = <0x04>;
+               st,vin-control-register = <0xc0>;
+               st,usb-control-register = <0x30>;
+
+               regulators {
+                       compatible = "st,stpmic1-regulators";
+
+                       ldo1-supply = <&v3v3>;
+                       ldo2-supply = <&v3v3>;
+                       ldo3-supply = <&vdd_ddr>;
+                       ldo5-supply = <&v3v3>;
+                       ldo6-supply = <&v3v3>;
+                       pwr_sw1-supply = <&bst_out>;
+                       pwr_sw2-supply = <&bst_out>;
+
+                       vddcore: buck1 {
+                               regulator-name = "vddcore";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-always-on;
+                               regulator-initial-mode = <0>;
+                               regulator-over-current-protection;
+                       };
+
+                       vdd_ddr: buck2 {
+                               regulator-name = "vdd_ddr";
+                               regulator-min-microvolt = <1350000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-always-on;
+                               regulator-initial-mode = <0>;
+                               regulator-over-current-protection;
+                       };
+
+                       vdd: buck3 {
+                               regulator-name = "vdd";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                               st,mask_reset;
+                               regulator-initial-mode = <0>;
+                               regulator-over-current-protection;
+                       };
+
+                       v3v3: buck4 {
+                               regulator-name = "v3v3";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                               regulator-over-current-protection;
+                               regulator-initial-mode = <0>;
+                       };
+
+                       vdda: ldo1 {
+                               regulator-name = "vdda";
+                               regulator-min-microvolt = <2900000>;
+                               regulator-max-microvolt = <2900000>;
+                               interrupts = <IT_CURLIM_LDO1 0>;
+                               interrupt-parent = <&pmic>;
+                       };
+
+                       v2v8: ldo2 {
+                               regulator-name = "v2v8";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               interrupts = <IT_CURLIM_LDO2 0>;
+                               interrupt-parent = <&pmic>;
+                       };
+
+                       vtt_ddr: ldo3 {
+                               regulator-name = "vtt_ddr";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <750000>;
+                               regulator-always-on;
+                               regulator-over-current-protection;
+                       };
+
+                       vdd_usb: ldo4 {
+                               regulator-name = "vdd_usb";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               interrupts = <IT_CURLIM_LDO4 0>;
+                               interrupt-parent = <&pmic>;
+                       };
+
+                       vdd_sd: ldo5 {
+                               regulator-name = "vdd_sd";
+                               regulator-min-microvolt = <2900000>;
+                               regulator-max-microvolt = <2900000>;
+                               interrupts = <IT_CURLIM_LDO5 0>;
+                               interrupt-parent = <&pmic>;
+                               regulator-boot-on;
+                       };
+
+                       v1v8: ldo6 {
+                               regulator-name = "v1v8";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               interrupts = <IT_CURLIM_LDO6 0>;
+                               interrupt-parent = <&pmic>;
+                               regulator-enable-ramp-delay = <300000>;
+                       };
+
+                       vref_ddr: vref_ddr {
+                               regulator-name = "vref_ddr";
+                               regulator-always-on;
+                               regulator-over-current-protection;
+                       };
+
+                       bst_out: boost {
+                               regulator-name = "bst_out";
+                               interrupts = <IT_OCP_BOOST 0>;
+                               interrupt-parent = <&pmic>;
+                       };
+
+                       vbus_otg: pwr_sw1 {
+                               regulator-name = "vbus_otg";
+                               interrupts = <IT_OCP_OTG 0>;
+                               interrupt-parent = <&pmic>;
+                               regulator-active-discharge;
+                       };
+
+                       vbus_sw: pwr_sw2 {
+                               regulator-name = "vbus_sw";
+                               interrupts = <IT_OCP_SWOUT 0>;
+                               interrupt-parent = <&pmic>;
+                               regulator-active-discharge;
+                       };
+               };
+
+               onkey {
+                       compatible = "st,stpmic1-onkey";
+                       interrupts = <IT_PONKEY_F 0>, <IT_PONKEY_R 1>;
+                       interrupt-names = "onkey-falling", "onkey-rising";
+                       status = "okay";
+               };
+
+               watchdog {
+                       compatible = "st,stpmic1-wdt";
+                       status = "disabled";
+               };
+       };
+};
+
+&iwdg2 {
+       timeout-sec = <32>;
+       status = "okay";
+};
+
+&rng1 {
+       status = "okay";
+};
+
+&rtc {
+       status = "okay";
+};
+
+&sdmmc1 {
+       pinctrl-names = "default", "opendrain", "sleep";
+       pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>;
+       pinctrl-1 = <&sdmmc1_b4_od_pins_a>;
+       pinctrl-2 = <&sdmmc1_b4_sleep_pins_a>;
+       broken-cd;
+       st,sig-dir;
+       st,neg-edge;
+       st,use-ckin;
+       bus-width = <4>;
+       vmmc-supply = <&vdd_sd>;
+       status = "okay";
+};
+
+&uart4 {
+       /* On Low speed expansion header */
+       label = "LS-UART1";
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart4_pins_b>;
+       status = "okay";
+};
+
+&uart7 {
+       /* On Low speed expansion header */
+       label = "LS-UART0";
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart7_pins_a>;
+       status = "okay";
+};
index 098dbfb..f3f0e37 100644 (file)
@@ -7,7 +7,7 @@
 /dts-v1/;
 
 #include "stm32mp157c.dtsi"
-#include "stm32mp157-pinctrl.dtsi"
+#include "stm32mp157xac-pinctrl.dtsi"
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/mfd/st,stpmic1.h>
 
                reg = <0xc0000000 0x20000000>;
        };
 
+       reserved-memory {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               gpu_reserved: gpu@d4000000 {
+                       reg = <0xd4000000 0x4000000>;
+                       no-map;
+               };
+       };
+
        led {
                compatible = "gpio-leds";
                blue {
@@ -51,7 +62,7 @@
        pinctrl-0 = <&ethernet0_rgmii_pins_a>;
        pinctrl-1 = <&ethernet0_rgmii_pins_sleep_a>;
        pinctrl-names = "default", "sleep";
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
        max-speed = <1000>;
        phy-handle = <&phy0>;
 
        };
 };
 
+&gpu {
+       contiguous-area = <&gpu_reserved>;
+       status = "okay";
+};
+
+&i2c1 {
+       pinctrl-names = "default", "sleep";
+       pinctrl-0 = <&i2c1_pins_a>;
+       pinctrl-1 = <&i2c1_pins_sleep_a>;
+       i2c-scl-rising-time-ns = <100>;
+       i2c-scl-falling-time-ns = <7>;
+       status = "okay";
+       /delete-property/dmas;
+       /delete-property/dma-names;
+
+       hdmi-transmitter@39 {
+               compatible = "sil,sii9022";
+               reg = <0x39>;
+               iovcc-supply = <&v3v3_hdmi>;
+               cvcc12-supply = <&v1v2_hdmi>;
+               reset-gpios = <&gpioa 10 GPIO_ACTIVE_LOW>;
+               interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
+               interrupt-parent = <&gpiog>;
+               pinctrl-names = "default", "sleep";
+               pinctrl-0 = <&ltdc_pins_a>;
+               pinctrl-1 = <&ltdc_pins_sleep_a>;
+               status = "okay";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+                               sii9022_in: endpoint {
+                                       remote-endpoint = <&ltdc_ep0_out>;
+                               };
+                       };
+               };
+       };
+};
 
 &i2c4 {
        pinctrl-names = "default";
        status = "okay";
 };
 
+&ltdc {
+       status = "okay";
+
+       port {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               ltdc_ep0_out: endpoint@0 {
+                       reg = <0>;
+                       remote-endpoint = <&sii9022_in>;
+               };
+       };
+};
+
 &rng1 {
        status = "okay";
 };
index 62a8c78..4fe7f71 100644 (file)
@@ -6,7 +6,7 @@
 /dts-v1/;
 
 #include "stm32mp157c.dtsi"
-#include "stm32mp157-pinctrl.dtsi"
+#include "stm32mp157xaa-pinctrl.dtsi"
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/mfd/st,stpmic1.h>
 
                reg = <0xC0000000 0x40000000>;
        };
 
+       reserved-memory {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               gpu_reserved: gpu@e8000000 {
+                       reg = <0xe8000000 0x8000000>;
+                       no-map;
+               };
+       };
+
        aliases {
                serial0 = &uart4;
        };
        status = "okay";
 };
 
+&gpu {
+       contiguous-area = <&gpu_reserved>;
+       status = "okay";
+};
+
 &i2c4 {
        pinctrl-names = "default";
        pinctrl-0 = <&i2c4_pins_a>;
index b6aca40..feb8f77 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "stm32mp157c-ed1.dts"
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
 
 / {
        model = "STMicroelectronics STM32MP157C eval daughter on eval mother";
                ethernet0 = &ethernet0;
        };
 
+       clocks {
+               clk_ext_camera: clk-ext-camera {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+                       clock-frequency = <24000000>;
+               };
+       };
+
+       joystick {
+               compatible = "gpio-keys";
+               #size-cells = <0>;
+               pinctrl-0 = <&joystick_pins>;
+               pinctrl-names = "default";
+               button-0 {
+                       label = "JoySel";
+                       linux,code = <KEY_ENTER>;
+                       interrupt-parent = <&stmfx_pinctrl>;
+                       interrupts = <0 IRQ_TYPE_EDGE_RISING>;
+               };
+               button-1 {
+                       label = "JoyDown";
+                       linux,code = <KEY_DOWN>;
+                       interrupt-parent = <&stmfx_pinctrl>;
+                       interrupts = <1 IRQ_TYPE_EDGE_RISING>;
+               };
+               button-2 {
+                       label = "JoyLeft";
+                       linux,code = <KEY_LEFT>;
+                       interrupt-parent = <&stmfx_pinctrl>;
+                       interrupts = <2 IRQ_TYPE_EDGE_RISING>;
+               };
+               button-3 {
+                       label = "JoyRight";
+                       linux,code = <KEY_RIGHT>;
+                       interrupt-parent = <&stmfx_pinctrl>;
+                       interrupts = <3 IRQ_TYPE_EDGE_RISING>;
+               };
+               button-4 {
+                       label = "JoyUp";
+                       linux,code = <KEY_UP>;
+                       interrupt-parent = <&stmfx_pinctrl>;
+                       interrupts = <4 IRQ_TYPE_EDGE_RISING>;
+               };
+       };
+
        panel_backlight: panel-backlight {
                compatible = "gpio-backlight";
                gpios = <&gpiod 13 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
 
+&dcmi {
+       status = "okay";
+       pinctrl-names = "default", "sleep";
+       pinctrl-0 = <&dcmi_pins_a>;
+       pinctrl-1 = <&dcmi_sleep_pins_a>;
+
+       port {
+               dcmi_0: endpoint {
+                       remote-endpoint = <&ov5640_0>;
+                       bus-width = <8>;
+                       hsync-active = <0>;
+                       vsync-active = <0>;
+                       pclk-sample = <1>;
+               };
+       };
+};
+
 &dsi {
        #address-cells = <1>;
        #size-cells = <0>;
                reg = <0>;
                reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>;
                backlight = <&panel_backlight>;
+               power-supply = <&v3v3>;
                status = "okay";
 
                port {
        pinctrl-0 = <&ethernet0_rgmii_pins_a>;
        pinctrl-1 = <&ethernet0_rgmii_pins_sleep_a>;
        pinctrl-names = "default", "sleep";
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
        max-speed = <1000>;
        phy-handle = <&phy0>;
 
        i2c-scl-rising-time-ns = <185>;
        i2c-scl-falling-time-ns = <20>;
        status = "okay";
+
+       ov5640: camera@3c {
+               compatible = "ovti,ov5640";
+               pinctrl-names = "default";
+               pinctrl-0 = <&ov5640_pins>;
+               reg = <0x3c>;
+               clocks = <&clk_ext_camera>;
+               clock-names = "xclk";
+               DOVDD-supply = <&v2v8>;
+               powerdown-gpios = <&stmfx_pinctrl 18 GPIO_ACTIVE_HIGH>;
+               reset-gpios = <&stmfx_pinctrl 19 GPIO_ACTIVE_LOW>;
+               rotation = <180>;
+               status = "okay";
+
+               port {
+                       ov5640_0: endpoint {
+                               remote-endpoint = <&dcmi_0>;
+                               bus-width = <8>;
+                               data-shift = <2>; /* lines 9:2 are used */
+                               hsync-active = <0>;
+                               vsync-active = <0>;
+                               pclk-sample = <1>;
+                       };
+               };
+       };
+
+       stmfx: stmfx@42 {
+               compatible = "st,stmfx-0300";
+               reg = <0x42>;
+               interrupts = <8 IRQ_TYPE_EDGE_RISING>;
+               interrupt-parent = <&gpioi>;
+               vdd-supply = <&v3v3>;
+
+               stmfx_pinctrl: stmfx-pin-controller {
+                       compatible = "st,stmfx-0300-pinctrl";
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+                       gpio-ranges = <&stmfx_pinctrl 0 0 24>;
+
+                       joystick_pins: joystick {
+                               pins = "gpio0", "gpio1", "gpio2", "gpio3", "gpio4";
+                               drive-push-pull;
+                               bias-pull-down;
+                       };
+
+                       ov5640_pins: camera {
+                               pins = "agpio2", "agpio3"; /* stmfx pins 18 & 19 */
+                               drive-push-pull;
+                               output-low;
+                       };
+               };
+       };
 };
 
 &i2c5 {
 };
 
 &qspi {
-       pinctrl-names = "default";
+       pinctrl-names = "default", "sleep";
        pinctrl-0 = <&qspi_clk_pins_a &qspi_bk1_pins_a &qspi_bk2_pins_a>;
+       pinctrl-1 = <&qspi_clk_sleep_pins_a &qspi_bk1_sleep_pins_a &qspi_bk2_sleep_pins_a>;
        reg = <0x58003000 0x1000>, <0x70000000 0x4000000>;
        #address-cells = <1>;
        #size-cells = <0>;
        status = "okay";
 
        flash0: mx66l51235l@0 {
+               compatible = "jedec,spi-nor";
                reg = <0>;
                spi-rx-bus-width = <4>;
                spi-max-frequency = <108000000>;
        };
 
        flash1: mx66l51235l@1 {
+               compatible = "jedec,spi-nor";
                reg = <1>;
                spi-rx-bus-width = <4>;
                spi-max-frequency = <108000000>;
index 2afeee6..0c4e6eb 100644 (file)
                        status = "disabled";
                };
 
+               i2s2: audio-controller@4000b000 {
+                       compatible = "st,stm32h7-i2s";
+                       #sound-dai-cells = <0>;
+                       reg = <0x4000b000 0x400>;
+                       interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+                       dmas = <&dmamux1 39 0x400 0x01>,
+                              <&dmamux1 40 0x400 0x01>;
+                       dma-names = "rx", "tx";
+                       status = "disabled";
+               };
+
                spi3: spi@4000c000 {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "disabled";
                };
 
+               i2s3: audio-controller@4000c000 {
+                       compatible = "st,stm32h7-i2s";
+                       #sound-dai-cells = <0>;
+                       reg = <0x4000c000 0x400>;
+                       interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
+                       dmas = <&dmamux1 61 0x400 0x01>,
+                              <&dmamux1 62 0x400 0x01>;
+                       dma-names = "rx", "tx";
+                       status = "disabled";
+               };
+
                spdifrx: audio-controller@4000d000 {
                        compatible = "st,stm32h7-spdifrx";
                        #sound-dai-cells = <0>;
                        status = "disabled";
                };
 
+               i2s1: audio-controller@44004000 {
+                       compatible = "st,stm32h7-i2s";
+                       #sound-dai-cells = <0>;
+                       reg = <0x44004000 0x400>;
+                       interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+                       dmas = <&dmamux1 37 0x400 0x01>,
+                              <&dmamux1 38 0x400 0x01>;
+                       dma-names = "rx", "tx";
+                       status = "disabled";
+               };
+
                spi4: spi@44005000 {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "disabled";
                };
 
+               sai1: sai@4400a000 {
+                       compatible = "st,stm32h7-sai";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0 0x4400a000 0x400>;
+                       reg = <0x4400a000 0x4>, <0x4400a3f0 0x10>;
+                       interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
+                       resets = <&rcc SAI1_R>;
+                       status = "disabled";
+
+                       sai1a: audio-controller@4400a004 {
+                               #sound-dai-cells = <0>;
+
+                               compatible = "st,stm32-sai-sub-a";
+                               reg = <0x4 0x1c>;
+                               clocks = <&rcc SAI1_K>;
+                               clock-names = "sai_ck";
+                               dmas = <&dmamux1 87 0x400 0x01>;
+                               status = "disabled";
+                       };
+
+                       sai1b: audio-controller@4400a024 {
+                               #sound-dai-cells = <0>;
+                               compatible = "st,stm32-sai-sub-b";
+                               reg = <0x24 0x1c>;
+                               clocks = <&rcc SAI1_K>;
+                               clock-names = "sai_ck";
+                               dmas = <&dmamux1 88 0x400 0x01>;
+                               status = "disabled";
+                       };
+               };
+
+               sai2: sai@4400b000 {
+                       compatible = "st,stm32h7-sai";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0 0x4400b000 0x400>;
+                       reg = <0x4400b000 0x4>, <0x4400b3f0 0x10>;
+                       interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
+                       resets = <&rcc SAI2_R>;
+                       status = "disabled";
+
+                       sai2a: audio-controller@4400b004 {
+                               #sound-dai-cells = <0>;
+                               compatible = "st,stm32-sai-sub-a";
+                               reg = <0x4 0x1c>;
+                               clocks = <&rcc SAI2_K>;
+                               clock-names = "sai_ck";
+                               dmas = <&dmamux1 89 0x400 0x01>;
+                               status = "disabled";
+                       };
+
+                       sai2b: audio-controller@4400b024 {
+                               #sound-dai-cells = <0>;
+                               compatible = "st,stm32-sai-sub-b";
+                               reg = <0x24 0x1c>;
+                               clocks = <&rcc SAI2_K>;
+                               clock-names = "sai_ck";
+                               dmas = <&dmamux1 90 0x400 0x01>;
+                               status = "disabled";
+                       };
+               };
+
+               sai3: sai@4400c000 {
+                       compatible = "st,stm32h7-sai";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0 0x4400c000 0x400>;
+                       reg = <0x4400c000 0x4>, <0x4400c3f0 0x10>;
+                       interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
+                       resets = <&rcc SAI3_R>;
+                       status = "disabled";
+
+                       sai3a: audio-controller@4400c004 {
+                               #sound-dai-cells = <0>;
+                               compatible = "st,stm32-sai-sub-a";
+                               reg = <0x04 0x1c>;
+                               clocks = <&rcc SAI3_K>;
+                               clock-names = "sai_ck";
+                               dmas = <&dmamux1 113 0x400 0x01>;
+                               status = "disabled";
+                       };
+
+                       sai3b: audio-controller@4400c024 {
+                               #sound-dai-cells = <0>;
+                               compatible = "st,stm32-sai-sub-b";
+                               reg = <0x24 0x1c>;
+                               clocks = <&rcc SAI3_K>;
+                               clock-names = "sai_ck";
+                               dmas = <&dmamux1 114 0x400 0x01>;
+                               status = "disabled";
+                       };
+               };
+
                dfsdm: dfsdm@4400d000 {
                        compatible = "st,stm32mp1-dfsdm";
                        reg = <0x4400d000 0x800>;
                        status = "disabled";
                };
 
+               dcmi: dcmi@4c006000 {
+                       compatible = "st,stm32-dcmi";
+                       reg = <0x4c006000 0x400>;
+                       interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
+                       resets = <&rcc CAMITF_R>;
+                       clocks = <&rcc DCMI>;
+                       clock-names = "mclk";
+                       dmas = <&dmamux1 75 0x400 0x0d>;
+                       dma-names = "tx";
+                       status = "disabled";
+               };
+
                rcc: rcc@50000000 {
                        compatible = "st,stm32mp1-rcc", "syscon";
                        reg = <0x50000000 0x1000>;
                        status = "disabled";
                };
 
+               sai4: sai@50027000 {
+                       compatible = "st,stm32h7-sai";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0 0x50027000 0x400>;
+                       reg = <0x50027000 0x4>, <0x500273f0 0x10>;
+                       interrupts = <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>;
+                       resets = <&rcc SAI4_R>;
+                       status = "disabled";
+
+                       sai4a: audio-controller@50027004 {
+                               #sound-dai-cells = <0>;
+                               compatible = "st,stm32-sai-sub-a";
+                               reg = <0x04 0x1c>;
+                               clocks = <&rcc SAI4_K>;
+                               clock-names = "sai_ck";
+                               dmas = <&dmamux1 99 0x400 0x01>;
+                               status = "disabled";
+                       };
+
+                       sai4b: audio-controller@50027024 {
+                               #sound-dai-cells = <0>;
+                               compatible = "st,stm32-sai-sub-b";
+                               reg = <0x24 0x1c>;
+                               clocks = <&rcc SAI4_K>;
+                               clock-names = "sai_ck";
+                               dmas = <&dmamux1 100 0x400 0x01>;
+                               status = "disabled";
+                       };
+               };
+
                dts: thermal@50028000 {
                        compatible = "st,stm32-thermal";
                        reg = <0x50028000 0x100>;
                        status = "disabled";
                };
 
+               gpu: gpu@59000000 {
+                       compatible = "vivante,gc";
+                       reg = <0x59000000 0x800>;
+                       interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&rcc GPU>, <&rcc GPU_K>;
+                       clock-names = "bus" ,"core";
+                       resets = <&rcc GPU_R>;
+                       status = "disabled";
+               };
+
                dsi: dsi@5a000000 {
                        compatible = "st,stm32-dsi";
                        reg = <0x5a000000 0x800>;
diff --git a/arch/arm/boot/dts/stm32mp157xaa-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157xaa-pinctrl.dtsi
new file mode 100644 (file)
index 0000000..875adf5
--- /dev/null
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com>
+ */
+
+#include "stm32mp157-pinctrl.dtsi"
+/ {
+       soc {
+               pinctrl: pin-controller@50002000 {
+                       st,package = <STM32MP_PKG_AA>;
+
+                       gpioa: gpio@50002000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 0 16>;
+                       };
+
+                       gpiob: gpio@50003000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 16 16>;
+                       };
+
+                       gpioc: gpio@50004000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 32 16>;
+                       };
+
+                       gpiod: gpio@50005000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 48 16>;
+                       };
+
+                       gpioe: gpio@50006000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 64 16>;
+                       };
+
+                       gpiof: gpio@50007000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 80 16>;
+                       };
+
+                       gpiog: gpio@50008000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 96 16>;
+                       };
+
+                       gpioh: gpio@50009000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 112 16>;
+                       };
+
+                       gpioi: gpio@5000a000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 128 16>;
+                       };
+
+                       gpioj: gpio@5000b000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 144 16>;
+                       };
+
+                       gpiok: gpio@5000c000 {
+                               status = "okay";
+                               ngpios = <8>;
+                               gpio-ranges = <&pinctrl 0 160 8>;
+                       };
+               };
+
+               pinctrl_z: pin-controller-z@54004000 {
+                       st,package = <STM32MP_PKG_AA>;
+
+                       gpioz: gpio@54004000 {
+                               status = "okay";
+                               ngpios = <8>;
+                               gpio-ranges = <&pinctrl_z 0 400 8>;
+                       };
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/stm32mp157xab-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157xab-pinctrl.dtsi
new file mode 100644 (file)
index 0000000..961fa12
--- /dev/null
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com>
+ */
+
+#include "stm32mp157-pinctrl.dtsi"
+/ {
+       soc {
+               pinctrl: pin-controller@50002000 {
+                       st,package = <STM32MP_PKG_AB>;
+
+                       gpioa: gpio@50002000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 0 16>;
+                       };
+
+                       gpiob: gpio@50003000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 16 16>;
+                       };
+
+                       gpioc: gpio@50004000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 32 16>;
+                       };
+
+                       gpiod: gpio@50005000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 48 16>;
+                       };
+
+                       gpioe: gpio@50006000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 64 16>;
+                       };
+
+                       gpiof: gpio@50007000 {
+                               status = "okay";
+                               ngpios = <6>;
+                               gpio-ranges = <&pinctrl 6 86 6>;
+                       };
+
+                       gpiog: gpio@50008000 {
+                               status = "okay";
+                               ngpios = <10>;
+                               gpio-ranges = <&pinctrl 6 102 10>;
+                       };
+
+                       gpioh: gpio@50009000 {
+                               status = "okay";
+                               ngpios = <2>;
+                               gpio-ranges = <&pinctrl 0 112 2>;
+                       };
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/stm32mp157xac-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157xac-pinctrl.dtsi
new file mode 100644 (file)
index 0000000..26600f1
--- /dev/null
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com>
+ */
+
+#include "stm32mp157-pinctrl.dtsi"
+/ {
+       soc {
+               pinctrl: pin-controller@50002000 {
+                       st,package = <STM32MP_PKG_AC>;
+
+                       gpioa: gpio@50002000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 0 16>;
+                       };
+
+                       gpiob: gpio@50003000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 16 16>;
+                       };
+
+                       gpioc: gpio@50004000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 32 16>;
+                       };
+
+                       gpiod: gpio@50005000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 48 16>;
+                       };
+
+                       gpioe: gpio@50006000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 64 16>;
+                       };
+
+                       gpiof: gpio@50007000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 80 16>;
+                       };
+
+                       gpiog: gpio@50008000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 96 16>;
+                       };
+
+                       gpioh: gpio@50009000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 112 16>;
+                       };
+
+                       gpioi: gpio@5000a000 {
+                               status = "okay";
+                               ngpios = <12>;
+                               gpio-ranges = <&pinctrl 0 128 12>;
+                       };
+               };
+
+               pinctrl_z: pin-controller-z@54004000 {
+                       st,package = <STM32MP_PKG_AC>;
+
+                       gpioz: gpio@54004000 {
+                               status = "okay";
+                               ngpios = <8>;
+                               gpio-ranges = <&pinctrl_z 0 400 8>;
+                       };
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/stm32mp157xad-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157xad-pinctrl.dtsi
new file mode 100644 (file)
index 0000000..910113f
--- /dev/null
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com>
+ */
+
+#include "stm32mp157-pinctrl.dtsi"
+/ {
+       soc {
+               pinctrl: pin-controller@50002000 {
+                       st,package = <STM32MP_PKG_AD>;
+
+                       gpioa: gpio@50002000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 0 16>;
+                       };
+
+                       gpiob: gpio@50003000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 16 16>;
+                       };
+
+                       gpioc: gpio@50004000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 32 16>;
+                       };
+
+                       gpiod: gpio@50005000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 48 16>;
+                       };
+
+                       gpioe: gpio@50006000 {
+                               status = "okay";
+                               ngpios = <16>;
+                               gpio-ranges = <&pinctrl 0 64 16>;
+                       };
+
+                       gpiof: gpio@50007000 {
+                               status = "okay";
+                               ngpios = <6>;
+                               gpio-ranges = <&pinctrl 6 86 6>;
+                       };
+
+                       gpiog: gpio@50008000 {
+                               status = "okay";
+                               ngpios = <10>;
+                               gpio-ranges = <&pinctrl 6 102 10>;
+                       };
+
+                       gpioh: gpio@50009000 {
+                               status = "okay";
+                               ngpios = <2>;
+                               gpio-ranges = <&pinctrl 0 112 2>;
+                       };
+               };
+       };
+};
index d003b89..4c20d73 100644 (file)
        };
 
        pcf8563: rtc@51 {
-               compatible = "phg,pcf8563";
+               compatible = "nxp,pcf8563";
                reg = <0x51>;
        };
 };
index c04efad..dcddc33 100644 (file)
                        #clock-cells = <0>;
                        compatible = "fixed-clock";
                        clock-frequency = <24000000>;
+                       clock-accuracy = <50000>;
                        clock-output-names = "osc24M";
                };
 
                        #clock-cells = <0>;
                        compatible = "fixed-clock";
                        clock-frequency = <32768>;
-                       clock-output-names = "osc32k";
+                       clock-accuracy = <50000>;
+                       clock-output-names = "ext_osc32k";
                };
 
                /*
                ccu: clock@1c20000 {
                        compatible = "allwinner,sun6i-a31-ccu";
                        reg = <0x01c20000 0x400>;
-                       clocks = <&osc24M>, <&osc32k>;
+                       clocks = <&osc24M>, <&rtc 0>;
                        clock-names = "hosc", "losc";
                        #clock-cells = <1>;
                        #reset-cells = <1>;
                                     <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&ccu CLK_APB1_PIO>, <&osc24M>, <&osc32k>;
+                       clocks = <&ccu CLK_APB1_PIO>, <&osc24M>, <&rtc 0>;
                        clock-names = "apb", "hosc", "losc";
                        gpio-controller;
                        interrupt-controller;
                        dma-names = "rx", "tx";
                        resets = <&ccu RST_AHB1_SPI0>;
                        status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
                };
 
                spi1: spi@1c69000 {
                        dma-names = "rx", "tx";
                        resets = <&ccu RST_AHB1_SPI1>;
                        status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
                };
 
                spi2: spi@1c6a000 {
                        dma-names = "rx", "tx";
                        resets = <&ccu RST_AHB1_SPI2>;
                        status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
                };
 
                spi3: spi@1c6b000 {
                        dma-names = "rx", "tx";
                        resets = <&ccu RST_AHB1_SPI3>;
                        status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
                };
 
                gic: interrupt-controller@1c81000 {
                };
 
                rtc: rtc@1f00000 {
+                       #clock-cells = <1>;
                        compatible = "allwinner,sun6i-a31-rtc";
                        reg = <0x01f00000 0x54>;
                        interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&osc32k>;
+                       clock-output-names = "osc32k";
                };
 
                nmi_intc: interrupt-controller@1f00c00 {
                        ar100: ar100_clk {
                                compatible = "allwinner,sun6i-a31-ar100-clk";
                                #clock-cells = <0>;
-                               clocks = <&osc32k>, <&osc24M>,
+                               clocks = <&rtc 0>, <&osc24M>,
                                         <&ccu CLK_PLL_PERIPH>,
                                         <&ccu CLK_PLL_PERIPH>;
                                clock-output-names = "ar100";
                        ir_clk: ir_clk {
                                #clock-cells = <0>;
                                compatible = "allwinner,sun4i-a10-mod0-clk";
-                               clocks = <&osc32k>, <&osc24M>;
+                               clocks = <&rtc 0>, <&osc24M>;
                                clock-output-names = "ir";
                        };
 
                        reg = <0x01f02c00 0x400>;
                        interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&apb0_gates 0>, <&osc24M>, <&osc32k>;
+                       clocks = <&apb0_gates 0>, <&osc24M>, <&rtc 0>;
                        clock-names = "apb", "hosc", "losc";
                        resets = <&apb0_rst 0>;
                        gpio-controller;
index 9494947..7449aac 100644 (file)
@@ -49,7 +49,8 @@
 
 / {
        model = "ICnova-A20 SWAC";
-       compatible = "swac,icnova-a20-swac", "incircuit,icnova-a20", "allwinner,sun7i-a20";
+       compatible = "incircuit,icnova-a20-swac", "incircuit,icnova-a20",
+                    "allwinner,sun7i-a20";
 
        aliases {
                serial0 = &uart0;
index 95c6f89..56f451c 100644 (file)
 
 #include "axp209.dtsi"
 
+&ac_power_supply {
+       status = "okay";
+};
+
+&battery_power_supply {
+       status = "okay";
+};
+
 &reg_dcdc2 {
        regulator-always-on;
        regulator-min-microvolt = <1000000>;
index 66d0780..568b90e 100644 (file)
        vref-supply = <&reg_aldo2>;
        status = "okay";
 
-       button@210 {
+       button-210 {
                label = "Volume Up";
                linux,code = <KEY_VOLUMEUP>;
                channel = <0>;
                voltage = <210000>;
        };
 
-       button@410 {
+       button-410 {
                label = "Volume Down";
                linux,code = <KEY_VOLUMEDOWN>;
                channel = <0>;
index 392b0ca..ada6d08 100644 (file)
                        #interrupt-cells = <3>;
                        #gpio-cells = <3>;
 
+                       /omit-if-no-ref/
+                       csi_8bit_parallel_pins: csi-8bit-parallel-pins {
+                               pins = "PE0", "PE2", "PE3", "PE6", "PE7",
+                                      "PE8", "PE9", "PE10", "PE11",
+                                      "PE12", "PE13";
+                               function = "csi";
+                       };
+
+                       /omit-if-no-ref/
+                       csi_mclk_pin: csi-mclk-pin {
+                               pins = "PE1";
+                               function = "csi";
+                       };
+
                        emac_rgmii_pins: emac-rgmii-pins {
                                pins = "PD2", "PD3", "PD4", "PD5", "PD6", "PD7",
                                       "PD11", "PD12", "PD13", "PD14", "PD18",
                        interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_HIGH)>;
                };
 
+               csi: camera@1cb0000 {
+                       compatible = "allwinner,sun8i-a83t-csi";
+                       reg = <0x01cb0000 0x1000>;
+                       interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_BUS_CSI>,
+                                <&ccu CLK_CSI_SCLK>,
+                                <&ccu CLK_DRAM_CSI>;
+                       clock-names = "bus", "mod", "ram";
+                       resets = <&ccu RST_BUS_CSI>;
+                       status = "disabled";
+
+                       csi_in: port {
+                       };
+               };
+
                hdmi: hdmi@1ee0000 {
                        compatible = "allwinner,sun8i-a83t-dw-hdmi";
                        reg = <0x01ee0000 0x10000>;
index 78a37a4..d277d04 100644 (file)
@@ -59,8 +59,7 @@
                gpios = <&r_pio 0 1 GPIO_ACTIVE_HIGH>; /* PL1 */
                enable-active-high;
                gpios-states = <0x1>;
-               states = <1100000 0x0
-                         1300000 0x1>;
+               states = <1100000 0>, <1300000 1>;
        };
 
        wifi_pwrseq: wifi_pwrseq {
index 4970eda..f19ed98 100644 (file)
                gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 */
                enable-active-high;
                gpios-states = <1>;
-               states = <1100000 0
-                         1300000 1>;
+               states = <1100000 0>, <1300000 1>;
        };
 
        wifi_pwrseq: wifi_pwrseq {
index 6277f13..ac9e26b 100644 (file)
@@ -90,6 +90,8 @@
        wifi_pwrseq: wifi_pwrseq {
                compatible = "mmc-pwrseq-simple";
                reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */
+               clocks = <&rtc 1>;
+               clock-names = "ext_clock";
        };
 
        sound_spdif {
 
 &mmc1 {
        vmmc-supply = <&reg_vcc3v3>;
+       vqmmc-supply = <&reg_vcc3v3>;
+       mmc-pwrseq = <&wifi_pwrseq>;
        bus-width = <4>;
        non-removable;
        status = "okay";
index 8408491..4759ba3 100644 (file)
                gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 */
                enable-active-high;
                gpios-states = <0x1>;
-               states = <1100000 0x0
-                         1300000 0x1>;
+               states = <1100000 0>, <1300000 1>;
        };
 };
 
index c488aaa..42d62d1 100644 (file)
 &pio {
        pinctrl-names = "default";
        pinctrl-0 = <&clk_out_a_pin>;
+       vcc-pa-supply = <&reg_aldo2>;
+       vcc-pc-supply = <&reg_dcdc1>;
+       vcc-pd-supply = <&reg_dcdc1>;
+       vcc-pe-supply = <&reg_eldo1>;
+       vcc-pf-supply = <&reg_dcdc1>;
+       vcc-pg-supply = <&reg_dldo1>;
 };
 
 &reg_aldo2 {
-       regulator-always-on;
        regulator-min-microvolt = <2500000>;
        regulator-max-microvolt = <2500000>;
        regulator-name = "vcc-pa";
index bb856e5..6007d0c 100644 (file)
                };
 
                rtc: rtc@1c20400 {
-                       compatible = "allwinner,sun8i-r40-rtc",
-                                    "allwinner,sun8i-h3-rtc";
+                       compatible = "allwinner,sun8i-r40-rtc";
                        reg = <0x01c20400 0x400>;
                        interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
                        clock-output-names = "osc32k", "osc32k-out";
index df72b17..d7aef12 100644 (file)
@@ -84,6 +84,7 @@
                        #clock-cells = <0>;
                        compatible = "fixed-clock";
                        clock-frequency = <24000000>;
+                       clock-accuracy = <50000>;
                        clock-output-names = "osc24M";
                };
 
@@ -91,7 +92,8 @@
                        #clock-cells = <0>;
                        compatible = "fixed-clock";
                        clock-frequency = <32768>;
-                       clock-output-names = "osc32k";
+                       clock-accuracy = <50000>;
+                       clock-output-names = "ext-osc32k";
                };
        };
 
                ccu: clock@1c20000 {
                        compatible = "allwinner,sun8i-v3s-ccu";
                        reg = <0x01c20000 0x400>;
-                       clocks = <&osc24M>, <&osc32k>;
+                       clocks = <&osc24M>, <&rtc 0>;
                        clock-names = "hosc", "losc";
                        #clock-cells = <1>;
                        #reset-cells = <1>;
                };
 
                rtc: rtc@1c20400 {
-                       compatible = "allwinner,sun6i-a31-rtc";
+                       #clock-cells = <1>;
+                       compatible = "allwinner,sun8i-v3-rtc";
                        reg = <0x01c20400 0x54>;
                        interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&osc32k>;
+                       clock-output-names = "osc32k", "osc32k-out";
                };
 
                pio: pinctrl@1c20800 {
                        reg = <0x01c20800 0x400>;
                        interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&osc32k>;
+                       clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&rtc 0>;
                        clock-names = "apb", "hosc", "losc";
                        gpio-controller;
                        #gpio-cells = <3>;
index f05cabd..15c22b0 100644 (file)
@@ -50,6 +50,7 @@
        compatible = "sinovoip,bpi-m2-berry", "allwinner,sun8i-r40";
 
        aliases {
+               ethernet0 = &gmac;
                serial0 = &uart0;
        };
 
                stdout-path = "serial0:115200n8";
        };
 
+       connector {
+               compatible = "hdmi-connector";
+               type = "a";
+
+               port {
+                       hdmi_con_in: endpoint {
+                               remote-endpoint = <&hdmi_out_con>;
+                       };
+               };
+       };
+
        leds {
                compatible = "gpio-leds";
 
        wifi_pwrseq: wifi_pwrseq {
                compatible = "mmc-pwrseq-simple";
                reset-gpios = <&pio 6 10 GPIO_ACTIVE_LOW>; /* PG10 WIFI_EN */
+               clocks = <&ccu CLK_OUTA>;
+               clock-names = "ext_clock";
        };
 };
 
+&ahci {
+       ahci-supply = <&reg_dldo4>;
+       phy-supply = <&reg_eldo3>;
+       status = "okay";
+};
+
+&de {
+       status = "okay";
+};
+
 &ehci1 {
        /* Terminus Tech FE 1.1s 4-port USB 2.0 hub here */
        status = "okay";
 };
 
+&gmac {
+       pinctrl-names = "default";
+       pinctrl-0 = <&gmac_rgmii_pins>;
+       phy-handle = <&phy1>;
+       phy-mode = "rgmii";
+       phy-supply = <&reg_dc1sw>;
+       status = "okay";
+};
+
+&gmac_mdio {
+       phy1: ethernet-phy@1 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <1>;
+       };
+};
+
+&hdmi {
+       status = "okay";
+};
+
+&hdmi_out {
+       hdmi_out_con: endpoint {
+               remote-endpoint = <&hdmi_con_in>;
+       };
+};
+
 &i2c0 {
        status = "okay";
 
        status = "okay";
 };
 
+&pio {
+       pinctrl-names = "default";
+       pinctrl-0 = <&clk_out_a_pin>;
+       vcc-pa-supply = <&reg_aldo2>;
+       vcc-pc-supply = <&reg_dcdc1>;
+       vcc-pd-supply = <&reg_dcdc1>;
+       vcc-pe-supply = <&reg_eldo1>;
+       vcc-pf-supply = <&reg_dcdc1>;
+       vcc-pg-supply = <&reg_dldo1>;
+};
+
+&reg_aldo2 {
+       regulator-min-microvolt = <2500000>;
+       regulator-max-microvolt = <2500000>;
+       regulator-name = "vcc-pa";
+};
+
 &reg_aldo3 {
        regulator-always-on;
        regulator-min-microvolt = <2700000>;
        regulator-name = "avcc";
 };
 
+&reg_dc1sw {
+       regulator-min-microvolt = <3000000>;
+       regulator-max-microvolt = <3000000>;
+       regulator-name = "vcc-gmac-phy";
+};
+
 &reg_dcdc1 {
        regulator-always-on;
        regulator-min-microvolt = <3000000>;
        regulator-name = "vcc-wifi-io";
 };
 
+/*
+ * Our WiFi chip needs both DLDO2 and DLDO3 to be powered at the same
+ * time, with the two being in sync, to be able to meet maximum power
+ * consumption during transmits. Since this is not really supported
+ * right now, just use the two as always on, and we will fix it later.
+ */
+
 &reg_dldo2 {
+       regulator-always-on;
        regulator-min-microvolt = <3300000>;
        regulator-max-microvolt = <3300000>;
        regulator-name = "vcc-wifi";
 };
 
+&reg_dldo3 {
+       regulator-always-on;
+       regulator-min-microvolt = <3300000>;
+       regulator-max-microvolt = <3300000>;
+       regulator-name = "vcc-wifi-2";
+};
+
+&reg_dldo4 {
+       regulator-min-microvolt = <2500000>;
+       regulator-max-microvolt = <2500000>;
+       regulator-name = "vdd2v5-sata";
+};
+
+&reg_eldo3 {
+       regulator-min-microvolt = <1200000>;
+       regulator-max-microvolt = <1200000>;
+       regulator-name = "vdd1v2-sata";
+};
+
+&tcon_tv0 {
+       status = "okay";
+};
+
 &uart0 {
        pinctrl-names = "default";
        pinctrl-0 = <&uart0_pb_pins>;
        status = "okay";
 };
 
+&uart3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart3_pg_pins>, <&uart3_rts_cts_pg_pins>;
+       uart-has-rtscts;
+       status = "okay";
+
+       bluetooth {
+               compatible = "brcm,bcm43438-bt";
+               clocks = <&ccu CLK_OUTA>;
+               clock-names = "lpo";
+               vbat-supply = <&reg_dldo2>;
+               vddio-supply = <&reg_dldo1>;
+               device-wakeup-gpios = <&pio 6 11 GPIO_ACTIVE_HIGH>; /* PG11 */
+               /* TODO host wake line connected to PMIC GPIO pins */
+               shutdown-gpios = <&pio 7 12 GPIO_ACTIVE_HIGH>; /* PH12 */
+               max-speed = <1500000>;
+       };
+};
+
 &usbphy {
        usb1_vbus-supply = <&reg_vcc5v0>;
        status = "okay";
index 53edd1f..22466af 100644 (file)
@@ -21,8 +21,7 @@
                regulator-ramp-delay = <50>; /* 4ms */
                gpios = <&r_pio 0 1 GPIO_ACTIVE_HIGH>; /* PL1 */
                gpios-states = <0x1>;
-               states = <1100000 0x0
-                         1300000 0x1>;
+               states = <1100000 0>, <1300000 1>;
        };
 };
 
index 3aaca10..f2d060f 100644 (file)
@@ -77,4 +77,8 @@
 
 &nand {
        status = "okay";
+
+       nand@0 {
+               reg = <0>;
+       };
 };
index c2706ce..58cd4e8 100644 (file)
                        status = "disabled";
                        reg-names = "nand_data", "denali_reg";
                        reg = <0x68000000 0x20>, <0x68100000 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
                        interrupts = <0 65 4>;
                        pinctrl-names = "default";
-                       pinctrl-0 = <&pinctrl_nand2cs>;
+                       pinctrl-0 = <&pinctrl_nand>;
                        clock-names = "nand", "nand_x", "ecc";
                        clocks = <&sys_clk 2>, <&sys_clk 3>, <&sys_clk 3>;
                        resets = <&sys_rst 2>;
index 3d9080e..60994b6 100644 (file)
@@ -90,4 +90,8 @@
 
 &nand {
        status = "okay";
+
+       nand@0 {
+               reg = <0>;
+       };
 };
index 28038b1..854f2eb 100644 (file)
@@ -98,4 +98,8 @@
 
 &nand {
        status = "okay";
+
+       nand@0 {
+               reg = <0>;
+       };
 };
index 97d051e..7f64e5a 100644 (file)
                        status = "disabled";
                        reg-names = "nand_data", "denali_reg";
                        reg = <0x68000000 0x20>, <0x68100000 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
                        interrupts = <0 65 4>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_nand>;
index 3657387..eff7471 100644 (file)
                        status = "disabled";
                        reg-names = "nand_data", "denali_reg";
                        reg = <0x68000000 0x20>, <0x68100000 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
                        interrupts = <0 65 4>;
                        pinctrl-names = "default";
-                       pinctrl-0 = <&pinctrl_nand2cs>;
+                       pinctrl-0 = <&pinctrl_nand>;
                        clock-names = "nand", "nand_x", "ecc";
                        clocks = <&sys_clk 2>, <&sys_clk 3>, <&sys_clk 3>;
                        resets = <&sys_rst 2>;
index 06a049f..4eddbb8 100644 (file)
                        status = "disabled";
                        reg-names = "nand_data", "denali_reg";
                        reg = <0x68000000 0x20>, <0x68100000 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
                        interrupts = <0 65 4>;
                        pinctrl-names = "default";
-                       pinctrl-0 = <&pinctrl_nand2cs>;
+                       pinctrl-0 = <&pinctrl_nand>;
                        clock-names = "nand", "nand_x", "ecc";
                        clocks = <&sys_clk 2>, <&sys_clk 3>, <&sys_clk 3>;
                        resets = <&sys_rst 2>;
index 01bf94c..cf9ea0b 100644 (file)
@@ -81,4 +81,8 @@
 
 &nand {
        status = "okay";
+
+       nand@0 {
+               reg = <0>;
+       };
 };
index efce027..cbebb6e 100644 (file)
                        status = "disabled";
                        reg-names = "nand_data", "denali_reg";
                        reg = <0x68000000 0x20>, <0x68100000 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
                        interrupts = <0 65 4>;
                        pinctrl-names = "default";
-                       pinctrl-0 = <&pinctrl_nand2cs>;
+                       pinctrl-0 = <&pinctrl_nand>;
                        clock-names = "nand", "nand_x", "ecc";
                        clocks = <&sys_clk 2>, <&sys_clk 3>, <&sys_clk 3>;
                        resets = <&sys_rst 2>;
index 269e6bf..37bd41f 100644 (file)
                compatible = "arm,versatile-flash", "cfi-flash";
                reg = <0x34000000 0x04000000>;
                bank-width = <4>;
+               partitions {
+                       compatible = "arm,arm-firmware-suite";
+               };
        };
 
        i2c0: i2c@10002000 {
index d3963e9..d6a1fc2 100644 (file)
                        #interrupt-cells = <1>;
                        ranges;
 
-                       flash@0,00000000 {
+                       nor_flash: flash@0,00000000 {
                                compatible = "arm,vexpress-flash", "cfi-flash";
                                reg = <0 0x00000000 0x04000000>,
                                      <4 0x00000000 0x04000000>;
                                bank-width = <4>;
+                               partitions {
+                                       compatible = "arm,arm-firmware-suite";
+                               };
                        };
 
                        psram@1,00000000 {
index 798c97a..8e57e15 100644 (file)
@@ -35,6 +35,9 @@
                                reg = <0 0x00000000 0x04000000>,
                                      <1 0x00000000 0x04000000>;
                                bank-width = <4>;
+                               partitions {
+                                       compatible = "arm,arm-firmware-suite";
+                               };
                        };
 
                        psram@2,00000000 {
index 00cd9f5..1de0a65 100644 (file)
                /* non-configurable replicators don't show up on the
                 * AMBA bus.  As such no need to add "arm,primecell".
                 */
-               compatible = "arm,coresight-replicator";
+               compatible = "arm,coresight-static-replicator";
 
                out-ports {
                        #address-cells = <1>;
        };
 
        funnel@20040000 {
-               compatible = "arm,coresight-funnel", "arm,primecell";
+               compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                reg = <0 0x20040000 0 0x1000>;
 
                clocks = <&oscclk6a>;
                                <0 3 &gic 0 39 4>;
        };
 };
+
+&nor_flash {
+       /*
+        * Unfortunately, accessing the flash disturbs the CPU idle states
+        * (suspend) and CPU hotplug of this platform. For this reason, flash
+        * hardware access is disabled by default on this platform alone.
+        */
+       status = "disabled";
+};
index 0507e6d..a1b4cce 100644 (file)
        status = "okay";
 };
 
+&qspi0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_qspi0>;
+       status = "okay";
+
+       /*
+        * Attached MT25QL02 can go up to 90Mhz in DTR and 166 in STR
+        * modes, so, spi-max-frequency is limited to 90MHz
+        */
+       flash@0 {
+               compatible = "jedec,spi-nor";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               spi-max-frequency = <90000000>;
+               spi-rx-bus-width = <4>;
+               reg = <0>;
+               m25p,fast-read;
+       };
+
+       flash@2 {
+               compatible = "jedec,spi-nor";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               spi-max-frequency = <90000000>;
+               spi-rx-bus-width = <4>;
+               reg = <2>;
+               m25p,fast-read;
+       };
+};
+
 &uart0 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart0>;
 
        pinctrl_qspi0: qspi0grp {
                fsl,pins = <
-                       VF610_PAD_PTD7__QSPI0_B_QSCK    0x31c3
-                       VF610_PAD_PTD8__QSPI0_B_CS0     0x31ff
-                       VF610_PAD_PTD9__QSPI0_B_DATA3   0x31c3
-                       VF610_PAD_PTD10__QSPI0_B_DATA2  0x31c3
-                       VF610_PAD_PTD11__QSPI0_B_DATA1  0x31c3
-                       VF610_PAD_PTD12__QSPI0_B_DATA0  0x31c3
+                       VF610_PAD_PTD0__QSPI0_A_QSCK    0x38c2
+                       VF610_PAD_PTD1__QSPI0_A_CS0     0x38c2
+                       VF610_PAD_PTD2__QSPI0_A_DATA3   0x38c3
+                       VF610_PAD_PTD3__QSPI0_A_DATA2   0x38c3
+                       VF610_PAD_PTD4__QSPI0_A_DATA1   0x38c3
+                       VF610_PAD_PTD5__QSPI0_A_DATA0   0x38c3
+                       VF610_PAD_PTD7__QSPI0_B_QSCK    0x38c2
+                       VF610_PAD_PTD8__QSPI0_B_CS0     0x38c2
+                       VF610_PAD_PTD9__QSPI0_B_DATA3   0x38c3
+                       VF610_PAD_PTD10__QSPI0_B_DATA2  0x38c3
+                       VF610_PAD_PTD11__QSPI0_B_DATA1  0x38c3
+                       VF610_PAD_PTD12__QSPI0_B_DATA0  0x38c3
                >;
        };
 
 
        pinctrl_uart2: uart2grp {
                fsl,pins = <
-                       VF610_PAD_PTD0__UART2_TX        0x21a2
-                       VF610_PAD_PTD1__UART2_RX        0x21a1
+                       VF610_PAD_PTD23__UART2_TX       0x21a2
+                       VF610_PAD_PTD22__UART2_RX       0x21a1
                >;
        };
 
index e24ad60..8a9aeeb 100644 (file)
@@ -21,7 +21,7 @@
 /*
  * The public API for this code is documented in arch/arm/include/asm/mcpm.h.
  * For a comprehensive description of the main algorithm used here, please
- * see Documentation/arm/cluster-pm-race-avoidance.txt.
+ * see Documentation/arm/cluster-pm-race-avoidance.rst.
  */
 
 struct sync_struct mcpm_sync;
index d5bd75d..291d969 100644 (file)
@@ -5,7 +5,7 @@
  * Created by:  Nicolas Pitre, March 2012
  * Copyright:   (C) 2012-2013  Linaro Limited
  *
- * Refer to Documentation/arm/cluster-pm-race-avoidance.txt
+ * Refer to Documentation/arm/cluster-pm-race-avoidance.rst
  * for details of the synchronisation algorithms used here.
  */
 
index 9675cc1..f1c7fd4 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright:  (C) 2012-2013  Linaro Limited
  *
  * This algorithm is described in more detail in
- * Documentation/arm/vlocks.txt.
+ * Documentation/arm/vlocks.rst.
  */
 
 #include <linux/linkage.h>
index d04ee19..bcb8bda 100644 (file)
@@ -30,7 +30,6 @@ CONFIG_INET=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
index 25c593d..e802cde 100644 (file)
@@ -25,7 +25,6 @@ CONFIG_INET=y
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
index 8c9b6ea..622436f 100644 (file)
@@ -37,7 +37,6 @@ CONFIG_BT_RFCOMM_TTY=y
 CONFIG_BT_BNEP=m
 CONFIG_BT_HCIUART=m
 CONFIG_BT_HCIUART_H4=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
index 190d6e9..019828d 100644 (file)
@@ -64,7 +64,6 @@ CONFIG_VLAN_8021Q=y
 CONFIG_NET_NCSI=y
 CONFIG_BPF_STREAM_PARSER=y
 # CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
@@ -78,8 +77,6 @@ CONFIG_MTD_UBI=y
 CONFIG_MTD_UBI_FASTMAP=y
 CONFIG_MTD_UBI_BLOCK=y
 CONFIG_BLK_DEV_LOOP=y
-CONFIG_ASPEED_LPC_CTRL=y
-CONFIG_ASPEED_LPC_SNOOP=y
 CONFIG_EEPROM_AT24=y
 CONFIG_NETDEVICES=y
 CONFIG_NETCONSOLE=y
@@ -169,6 +166,10 @@ CONFIG_SENSORS_UCD9200=y
 CONFIG_SENSORS_TMP421=y
 CONFIG_SENSORS_W83773G=y
 CONFIG_WATCHDOG_SYSFS=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_VIDEO_ASPEED=y
 CONFIG_DRM=y
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
@@ -207,8 +208,12 @@ CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_DS1307=y
 CONFIG_RTC_DRV_PCF8523=y
 CONFIG_RTC_DRV_RV8803=y
+CONFIG_RTC_DRV_ASPEED=y
 # CONFIG_VIRTIO_MENU is not set
 # CONFIG_IOMMU_SUPPORT is not set
+CONFIG_ASPEED_LPC_CTRL=y
+CONFIG_ASPEED_LPC_SNOOP=y
+CONFIG_ASPEED_P2A_CTRL=y
 CONFIG_IIO=y
 CONFIG_ASPEED_ADC=y
 CONFIG_MAX1363=y
index 407ffb7..28fe392 100644 (file)
@@ -64,7 +64,6 @@ CONFIG_VLAN_8021Q=y
 CONFIG_NET_NCSI=y
 CONFIG_BPF_STREAM_PARSER=y
 # CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
@@ -78,8 +77,6 @@ CONFIG_MTD_UBI=y
 CONFIG_MTD_UBI_FASTMAP=y
 CONFIG_MTD_UBI_BLOCK=y
 CONFIG_BLK_DEV_LOOP=y
-CONFIG_ASPEED_LPC_CTRL=y
-CONFIG_ASPEED_LPC_SNOOP=y
 CONFIG_EEPROM_AT24=y
 CONFIG_NETDEVICES=y
 CONFIG_NETCONSOLE=y
@@ -169,7 +166,12 @@ CONFIG_SENSORS_UCD9200=y
 CONFIG_SENSORS_TMP421=y
 CONFIG_SENSORS_W83773G=y
 CONFIG_WATCHDOG_SYSFS=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_VIDEO_ASPEED=y
 CONFIG_DRM=y
+CONFIG_DRM_ASPEED_GFX=y
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_DYNAMIC_MINORS=y
@@ -203,16 +205,23 @@ CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_TIMER=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
 CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_EDAC=y
+CONFIG_EDAC_ASPEED=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_DS1307=y
 CONFIG_RTC_DRV_PCF8523=y
 CONFIG_RTC_DRV_RV8803=y
+CONFIG_RTC_DRV_ASPEED=y
 # CONFIG_VIRTIO_MENU is not set
 # CONFIG_IOMMU_SUPPORT is not set
+CONFIG_ASPEED_LPC_CTRL=y
+CONFIG_ASPEED_LPC_SNOOP=y
+CONFIG_ASPEED_P2A_CTRL=y
 CONFIG_IIO=y
 CONFIG_ASPEED_ADC=y
 CONFIG_MAX1363=y
 CONFIG_BMP280=y
+CONFIG_RAS=y
 CONFIG_FSI=y
 CONFIG_FSI_MASTER_GPIO=y
 CONFIG_FSI_MASTER_HUB=y
index a88e314..309c55a 100644 (file)
@@ -46,7 +46,6 @@ CONFIG_IP_PNP_RARP=y
 CONFIG_IPV6_SIT_6RD=y
 CONFIG_CFG80211=y
 CONFIG_MAC80211=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_STANDALONE is not set
index 5386431..31bfe16 100644 (file)
@@ -78,7 +78,6 @@ CONFIG_INET_IPCOMP=y
 CONFIG_NETWORK_PHY_TIMESTAMPING=y
 CONFIG_BRIDGE=y
 # CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_MTD=y
index 5344434..fa997ae 100644 (file)
@@ -45,7 +45,6 @@ CONFIG_BT_RFCOMM=m
 CONFIG_BT_BNEP=m
 CONFIG_BT_HIDP=m
 CONFIG_LIB80211=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_FW_LOADER=m
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
@@ -103,7 +102,6 @@ CONFIG_FB=y
 CONFIG_FB_PXA=y
 CONFIG_FB_PXA_PARAMETERS=y
 CONFIG_FB_MBX=m
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
 # CONFIG_BACKLIGHT_CLASS_DEVICE is not set
 # CONFIG_VGA_CONSOLE is not set
index 3707a01..2f7acde 100644 (file)
@@ -45,7 +45,6 @@ CONFIG_BT_BNEP_PROTO_FILTER=y
 CONFIG_BT_HIDP=m
 CONFIG_BT_HCIBTUSB=m
 CONFIG_LIB80211=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_RAW_NAND=y
@@ -86,7 +85,6 @@ CONFIG_REGULATOR=y
 CONFIG_REGULATOR_DA903X=y
 CONFIG_FB=y
 CONFIG_FB_PXA=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_LCD_TDO24M=y
 # CONFIG_BACKLIGHT_GENERIC is not set
index 419b735..89df0a5 100644 (file)
@@ -27,7 +27,6 @@ CONFIG_AEABI=y
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="console=ttyS0,38400 mem=128M root=/dev/mmcblk0p1 ro rootwait"
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
index 8d484e4..52bad9a 100644 (file)
@@ -49,7 +49,6 @@ CONFIG_BT_BNEP_MC_FILTER=y
 CONFIG_BT_BNEP_PROTO_FILTER=y
 CONFIG_BT_HIDP=m
 CONFIG_CFG80211=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_CONNECTOR=y
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
@@ -102,7 +101,6 @@ CONFIG_WATCHDOG=y
 CONFIG_FB=y
 CONFIG_FIRMWARE_EDID=y
 CONFIG_FB_PXA=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_VGA_CONSOLE is not set
index d282e8b..446134c 100644 (file)
@@ -14,7 +14,6 @@ CONFIG_IP_MULTICAST=y
 CONFIG_IP_PNP=y
 CONFIG_SYN_COOKIES=y
 CONFIG_IPV6=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_SG=y
@@ -33,7 +32,6 @@ CONFIG_DEBUG_GPIO=y
 # CONFIG_HWMON is not set
 CONFIG_FB=y
 CONFIG_FB_PXA=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_BACKLIGHT_GENERIC is not set
index d398ae5..e6df11e 100644 (file)
@@ -63,7 +63,6 @@ CONFIG_MCP_UCB1200_TS=y
 CONFIG_FB=y
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_SA1100=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
index d997259..e4f6442 100644 (file)
@@ -81,7 +81,6 @@ CONFIG_BT_HCIBT3C=m
 CONFIG_BT_HCIBLUECARD=m
 CONFIG_BT_HCIBTUART=m
 CONFIG_BT_HCIVHCI=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
@@ -132,7 +131,6 @@ CONFIG_SPI=y
 CONFIG_SPI_PXA2XX=y
 CONFIG_FB=y
 CONFIG_FB_W100=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_LCD_CORGI=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
index 4a8cad4..9a32a8c 100644 (file)
@@ -45,6 +45,7 @@ CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_PERFORMANCE=m
 CONFIG_CPU_FREQ_GOV_POWERSAVE=m
 CONFIG_CPU_FREQ_GOV_ONDEMAND=m
+CONFIG_CPUFREQ_DT=m
 CONFIG_CPU_IDLE=y
 CONFIG_NET=y
 CONFIG_PACKET=y
index 2f01e84..e70c997 100644 (file)
@@ -31,7 +31,6 @@ CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_MTD=y
index 61228a2..d08f020 100644 (file)
@@ -41,7 +41,6 @@ CONFIG_BT_BNEP=m
 CONFIG_BT_HIDP=m
 CONFIG_BT_HCIBTUSB=m
 CONFIG_LIB80211=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_FW_LOADER=m
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
@@ -101,7 +100,6 @@ CONFIG_FB=y
 CONFIG_FB_PXA=y
 CONFIG_FB_PXA_PARAMETERS=y
 CONFIG_FB_MBX=m
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_LCD_TDO24M=y
 # CONFIG_BACKLIGHT_GENERIC is not set
index 14889a7..ef2d2a8 100644 (file)
@@ -50,7 +50,6 @@ CONFIG_IPV6=y
 # CONFIG_INET6_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET6_XFRM_MODE_BEET is not set
 # CONFIG_IPV6_SIT is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
 CONFIG_MTD_REDBOOT_PARTS=y
index b855758..56452fa 100644 (file)
@@ -40,7 +40,6 @@ CONFIG_CFG80211=m
 CONFIG_MAC80211=m
 CONFIG_MAC80211_RC_PID=y
 # CONFIG_MAC80211_RC_MINSTREL is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_STANDALONE is not set
 CONFIG_MTD=m
 CONFIG_MTD_RAW_NAND=m
@@ -74,7 +73,6 @@ CONFIG_MFD_TC6393XB=y
 CONFIG_FB=y
 CONFIG_FB_PXA=y
 CONFIG_FB_W100=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_VGA_CONSOLE is not set
index 9b959af..2e6a863 100644 (file)
@@ -1,22 +1,16 @@
 CONFIG_SYSVIPC=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
 CONFIG_CGROUPS=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_PERF_EVENTS=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_PARTITION_ADVANCED=y
 CONFIG_ARCH_EXYNOS=y
-CONFIG_ARCH_EXYNOS3=y
 CONFIG_CPU_ICACHE_MISMATCH_WORKAROUND=y
 CONFIG_SMP=y
 CONFIG_BIG_LITTLE=y
 CONFIG_NR_CPUS=8
-CONFIG_PREEMPT=y
-CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
-CONFIG_CMA=y
 CONFIG_SECCOMP=y
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
@@ -38,6 +32,16 @@ CONFIG_NEON=y
 CONFIG_KERNEL_MODE_NEON=y
 CONFIG_PM_DEBUG=y
 CONFIG_PM_ADVANCED_DEBUG=y
+CONFIG_ARM_CRYPTO=y
+CONFIG_CRYPTO_SHA1_ARM_NEON=m
+CONFIG_CRYPTO_SHA256_ARM=m
+CONFIG_CRYPTO_SHA512_ARM=m
+CONFIG_CRYPTO_AES_ARM_BS=m
+CONFIG_CRYPTO_CHACHA20_NEON=m
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_CMA=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -61,10 +65,7 @@ CONFIG_BT_HCIBTSDIO=m
 CONFIG_BT_HCIUART=m
 CONFIG_BT_HCIUART_BCSP=y
 CONFIG_BT_HCIUART_ATH3K=y
-CONFIG_BT_HCIUART_3WIRE=y
 CONFIG_BT_HCIUART_INTEL=y
-CONFIG_BT_HCIUART_BCM=y
-CONFIG_BT_HCIUART_QCA=y
 CONFIG_BT_HCIUART_AG6XX=y
 CONFIG_BT_HCIUART_MRVL=y
 CONFIG_BT_HCIBCM203X=m
@@ -87,8 +88,6 @@ CONFIG_NFC_SHDLC=y
 CONFIG_NFC_S3FWRN5_I2C=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_DMA_CMA=y
-CONFIG_CMA_SIZE_MBYTES=96
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=y
 CONFIG_BLK_DEV_RAM=y
@@ -156,8 +155,6 @@ CONFIG_THERMAL_EMULATION=y
 CONFIG_WATCHDOG=y
 CONFIG_S3C2410_WATCHDOG=y
 CONFIG_MFD_CROS_EC=y
-CONFIG_CROS_EC_I2C=y
-CONFIG_CROS_EC_SPI=y
 CONFIG_MFD_MAX14577=y
 CONFIG_MFD_MAX77686=y
 CONFIG_MFD_MAX77693=y
@@ -216,6 +213,8 @@ CONFIG_DRM_NXP_PTN3460=y
 CONFIG_DRM_PARADE_PS8622=y
 CONFIG_DRM_SII9234=y
 CONFIG_DRM_TOSHIBA_TC358764=y
+CONFIG_DRM_LIMA=y
+CONFIG_DRM_PANFROST=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_LCD_PLATFORM=y
 CONFIG_BACKLIGHT_PWM=y
@@ -283,16 +282,16 @@ CONFIG_RTC_DRV_S5M=y
 CONFIG_RTC_DRV_S3C=y
 CONFIG_DMADEVICES=y
 CONFIG_PL330_DMA=y
-CONFIG_CROS_EC_CHARDEV=y
+CONFIG_CROS_EC_I2C=y
+CONFIG_CROS_EC_SPI=y
 CONFIG_COMMON_CLK_MAX77686=y
 CONFIG_COMMON_CLK_S2MPS11=y
-CONFIG_PM_DEVFREQ=y
+CONFIG_EXYNOS_IOMMU=y
 CONFIG_DEVFREQ_GOV_PERFORMANCE=y
 CONFIG_DEVFREQ_GOV_POWERSAVE=y
 CONFIG_DEVFREQ_GOV_USERSPACE=y
 CONFIG_ARM_EXYNOS_BUS_DEVFREQ=y
 CONFIG_DEVFREQ_EVENT_EXYNOS_NOCP=y
-CONFIG_EXYNOS_IOMMU=y
 CONFIG_EXTCON=y
 CONFIG_EXTCON_MAX14577=y
 CONFIG_EXTCON_MAX77693=y
@@ -320,21 +319,9 @@ CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ASCII=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_NLS_UTF8=y
-CONFIG_PRINTK_TIME=y
-CONFIG_DYNAMIC_DEBUG=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_FS=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_SOFTLOCKUP_DETECTOR=y
-# CONFIG_DETECT_HUNG_TASK is not set
-CONFIG_PROVE_LOCKING=y
-CONFIG_DEBUG_ATOMIC_SLEEP=y
-CONFIG_DEBUG_USER=y
-CONFIG_CRYPTO_RSA=m
-CONFIG_CRYPTO_DH=m
 CONFIG_CRYPTO_USER=m
 CONFIG_CRYPTO_TEST=m
+CONFIG_CRYPTO_DH=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_XTS=m
 CONFIG_CRYPTO_MD5=m
@@ -349,12 +336,18 @@ CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_CRYPTO_USER_API_AEAD=m
 CONFIG_CRYPTO_DEV_EXYNOS_RNG=y
 CONFIG_CRYPTO_DEV_S5P=y
-CONFIG_ARM_CRYPTO=y
-CONFIG_CRYPTO_SHA1_ARM_NEON=m
-CONFIG_CRYPTO_SHA256_ARM=m
-CONFIG_CRYPTO_SHA512_ARM=m
-CONFIG_CRYPTO_AES_ARM_BS=m
-CONFIG_CRYPTO_CHACHA20_NEON=m
 CONFIG_CRC_CCITT=y
+CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=96
 CONFIG_FONTS=y
 CONFIG_FONT_7x14=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_INFO=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_SOFTLOCKUP_DETECTOR=y
+# CONFIG_DETECT_HUNG_TASK is not set
+CONFIG_PROVE_LOCKING=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_USER=y
index e3afca5..4e28771 100644 (file)
@@ -160,7 +160,6 @@ CONFIG_BT_HCIVHCI=m
 CONFIG_BT_MRVL=m
 CONFIG_BT_MRVL_SDIO=m
 # CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_FW_LOADER=m
 CONFIG_CONNECTOR=m
 CONFIG_MTD=y
@@ -247,7 +246,6 @@ CONFIG_FB=y
 CONFIG_FB_PXA=y
 CONFIG_FB_PXA_OVERLAY=y
 CONFIG_FB_PXA_PARAMETERS=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_PWM=y
index ef9aae8..f012e81 100644 (file)
@@ -22,7 +22,6 @@ CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
index 175881b..4d91e41 100644 (file)
@@ -25,7 +25,6 @@ CONFIG_IRLAN=m
 CONFIG_IRNET=m
 CONFIG_IRCOMM=m
 # CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_BLOCK=y
index e90d1df..3946c60 100644 (file)
@@ -32,7 +32,6 @@ CONFIG_IP_PNP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
index 9b779e1..770469f 100644 (file)
@@ -138,7 +138,6 @@ CONFIG_BRIDGE=m
 # CONFIG_BRIDGE_IGMP_SNOOPING is not set
 CONFIG_IEEE802154=y
 # CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_FW_LOADER=m
@@ -228,7 +227,6 @@ CONFIG_FB=y
 CONFIG_FB_PXA=y
 CONFIG_FB_PXA_OVERLAY=y
 CONFIG_FB_PXA_PARAMETERS=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_VGA_CONSOLE is not set
index f2cf072..2b2d617 100644 (file)
@@ -47,7 +47,6 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
 CONFIG_NETFILTER=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_IMX_WEIM=y
index 8116648..a53b292 100644 (file)
@@ -57,6 +57,7 @@ CONFIG_CPU_FREQ_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
 CONFIG_CPUFREQ_DT=y
 CONFIG_ARM_IMX6Q_CPUFREQ=y
+CONFIG_ARM_IMX_CPUFREQ_DT=y
 CONFIG_CPU_IDLE=y
 CONFIG_ARM_CPUIDLE=y
 CONFIG_VFP=y
@@ -211,9 +212,11 @@ CONFIG_SPI_GPIO=y
 CONFIG_SPI_IMX=y
 CONFIG_SPI_FSL_DSPI=y
 CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_SIOX=m
 CONFIG_GPIO_MAX732X=y
 CONFIG_GPIO_MC9S08DZ60=y
 CONFIG_GPIO_PCA953X=y
+CONFIG_GPIO_PCF857X=y
 CONFIG_GPIO_STMPE=y
 CONFIG_GPIO_74X164=y
 CONFIG_POWER_RESET=y
@@ -223,6 +226,7 @@ CONFIG_POWER_SUPPLY=y
 CONFIG_SENSORS_MC13783_ADC=y
 CONFIG_SENSORS_GPIO_FAN=y
 CONFIG_SENSORS_IIO_HWMON=y
+CONFIG_THERMAL_STATISTICS=y
 CONFIG_THERMAL_WRITABLE_TRIPS=y
 CONFIG_CPU_THERMAL=y
 CONFIG_IMX_THERMAL=y
@@ -266,6 +270,7 @@ CONFIG_VIDEO_CODA=m
 CONFIG_VIDEO_IMX_PXP=y
 # CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
 CONFIG_VIDEO_ADV7180=m
+CONFIG_VIDEO_OV2680=m
 CONFIG_VIDEO_OV5640=m
 CONFIG_IMX_IPUV3_CORE=y
 CONFIG_DRM=y
@@ -399,11 +404,15 @@ CONFIG_MPL3115=y
 CONFIG_PWM=y
 CONFIG_PWM_FSL_FTM=y
 CONFIG_PWM_IMX27=y
+CONFIG_PWM_IMX_TPM=y
 CONFIG_NVMEM_IMX_OCOTP=y
 CONFIG_NVMEM_VF610_OCOTP=y
+CONFIG_NVMEM_SNVS_LPGPR=y
 CONFIG_TEE=y
 CONFIG_OPTEE=y
 CONFIG_MUX_MMIO=y
+CONFIG_SIOX=m
+CONFIG_SIOX_BUS_GPIO=m
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_POSIX_ACL=y
index 747550c..2f0a762 100644 (file)
@@ -61,7 +61,6 @@ CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_MATROX=y
 CONFIG_FB_MATROX_MILLENIUM=y
 CONFIG_FB_MATROX_MYSTIQUE=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_LOGO=y
index a73b6a3..30cdb28 100644 (file)
@@ -34,7 +34,6 @@ CONFIG_IPV6=y
 # CONFIG_INET6_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET6_XFRM_MODE_BEET is not set
 # CONFIG_IPV6_SIT is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
index f63362b..18a21fa 100644 (file)
@@ -30,7 +30,6 @@ CONFIG_IPV6=y
 # CONFIG_INET6_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET6_XFRM_MODE_BEET is not set
 # CONFIG_IPV6_SIT is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
index d22f832..089eca4 100644 (file)
@@ -28,7 +28,6 @@ CONFIG_IPV6=y
 # CONFIG_INET6_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET6_XFRM_MODE_BEET is not set
 # CONFIG_IPV6_SIT is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
index 39ebcce..27e7c07 100644 (file)
@@ -104,7 +104,6 @@ CONFIG_NET_CLS_RSVP6=m
 CONFIG_NET_CLS_ACT=y
 CONFIG_NET_ACT_POLICE=y
 CONFIG_NET_PKTGEN=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_BLOCK=y
index 65d37ad..9f079be 100644 (file)
@@ -24,7 +24,6 @@ CONFIG_IRDA=m
 CONFIG_IRLAN=m
 CONFIG_IRCOMM=m
 CONFIG_SA1100_FIR=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_NBD=y
 CONFIG_BLK_DEV_SD=y
@@ -47,7 +46,6 @@ CONFIG_LEGACY_PTY_COUNT=32
 # CONFIG_HWMON is not set
 CONFIG_FB=y
 CONFIG_FB_S1D13XXX=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_BACKLIGHT_GENERIC is not set
index 72fee57..3d5f5b5 100644 (file)
@@ -115,7 +115,6 @@ CONFIG_VLAN_8021Q=y
 CONFIG_CAN=m
 CONFIG_CAN_C_CAN=m
 CONFIG_CAN_C_CAN_PLATFORM=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_DMA_CMA=y
index b8b91d7..df62d4d 100644 (file)
@@ -28,7 +28,6 @@ CONFIG_INET=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_CMDLINE_PARTS=y
index e3d5e15..e518168 100644 (file)
@@ -119,7 +119,6 @@ CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_DRM=y
 CONFIG_DRM_PL111=y
 CONFIG_FB_MODE_HELPERS=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_ROOT_HUB_TT=y
index 4b3b2c6..0cdc6c7 100644 (file)
@@ -40,7 +40,6 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_FW_LOADER is not set
@@ -110,7 +109,6 @@ CONFIG_DRM=y
 CONFIG_DRM_PANEL_SIMPLE=y
 CONFIG_DRM_PL111=y
 CONFIG_FB_MODE_HELPERS=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
index de5be2f..e6486c9 100644 (file)
@@ -53,7 +53,6 @@ CONFIG_BT_BNEP_MC_FILTER=y
 CONFIG_BT_BNEP_PROTO_FILTER=y
 CONFIG_BT_HIDP=m
 CONFIG_BT_HCIBTUSB=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
@@ -96,7 +95,6 @@ CONFIG_FB=y
 CONFIG_FB_PXA=y
 CONFIG_FB_PXA_OVERLAY=y
 CONFIG_FB_W100=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_BACKLIGHT_GENERIC is not set
index 7d26ca0..301f29a 100644 (file)
@@ -4,6 +4,16 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_COMPAT_BRK is not set
+CONFIG_ARCH_S3C24XX=y
+CONFIG_S3C_ADC=y
+CONFIG_S3C24XX_PWM=y
+# CONFIG_CPU_S3C2410 is not set
+CONFIG_CPU_S3C2440=y
+CONFIG_MACH_MINI2440=y
+CONFIG_AEABI=y
+CONFIG_KEXEC=y
+CONFIG_CPU_IDLE=y
+CONFIG_APM_EMULATION=y
 CONFIG_MODULES=y
 CONFIG_MODULE_FORCE_LOAD=y
 CONFIG_MODULE_UNLOAD=y
@@ -16,17 +26,7 @@ CONFIG_MINIX_SUBPARTITION=y
 CONFIG_SOLARIS_X86_PARTITION=y
 CONFIG_UNIXWARE_DISKLABEL=y
 CONFIG_LDM_PARTITION=y
-CONFIG_ARCH_S3C24XX=y
-# CONFIG_CPU_S3C2410 is not set
-CONFIG_CPU_S3C2440=y
-CONFIG_MACH_MINI2440=y
-CONFIG_S3C_ADC=y
-CONFIG_S3C24XX_PWM=y
-CONFIG_AEABI=y
-CONFIG_KEXEC=y
-CONFIG_CPU_IDLE=y
 CONFIG_BINFMT_MISC=m
-CONFIG_APM_EMULATION=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -46,9 +46,6 @@ CONFIG_IP_MROUTE=y
 CONFIG_IP_PIMSM_V1=y
 CONFIG_IP_PIMSM_V2=y
 CONFIG_SYN_COOKIES=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
 CONFIG_INET_DIAG=m
 # CONFIG_IPV6 is not set
 CONFIG_NETFILTER=y
@@ -76,7 +73,6 @@ CONFIG_CFG80211=m
 CONFIG_MAC80211=m
 CONFIG_MAC80211_MESH=y
 CONFIG_MAC80211_LEDS=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_CONNECTOR=m
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
@@ -126,7 +122,6 @@ CONFIG_LIBERTAS=m
 CONFIG_LIBERTAS_SDIO=m
 CONFIG_ZD1211RW=m
 CONFIG_ZD1211RW_DEBUG=y
-CONFIG_INPUT_FF_MEMLESS=y
 CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_EVBUG=m
 # CONFIG_KEYBOARD_ATKBD is not set
@@ -160,7 +155,6 @@ CONFIG_FIRMWARE_EDID=y
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_TILEBLITTING=y
 CONFIG_FB_S3C2410=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_LCD_PLATFORM=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
@@ -174,12 +168,9 @@ CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_VGA16 is not set
 CONFIG_SOUND=y
 CONFIG_SND=y
+CONFIG_SND_DYNAMIC_MINORS=y
 CONFIG_SND_SEQUENCER=m
 CONFIG_SND_SEQ_DUMMY=m
-CONFIG_SND_MIXER_OSS=m
-CONFIG_SND_PCM_OSS=m
-CONFIG_SND_SEQUENCER_OSS=y
-CONFIG_SND_DYNAMIC_MINORS=y
 # CONFIG_SND_DRIVERS is not set
 # CONFIG_SND_ARM is not set
 # CONFIG_SND_SPI is not set
@@ -297,13 +288,6 @@ CONFIG_NLS_ISO8859_15=m
 CONFIG_NLS_KOI8_R=m
 CONFIG_NLS_KOI8_U=m
 CONFIG_NLS_UTF8=m
-CONFIG_DEBUG_INFO=y
-# CONFIG_ENABLE_MUST_CHECK is not set
-CONFIG_STRIP_ASM_SYMS=y
-CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_SCHED_DEBUG is not set
-CONFIG_DEBUG_USER=y
 CONFIG_CRYPTO_CRYPTD=m
 CONFIG_CRYPTO_AUTHENC=m
 CONFIG_CRYPTO_TEST=m
@@ -342,3 +326,10 @@ CONFIG_LIBCRC32C=m
 CONFIG_FONTS=y
 CONFIG_FONT_8x8=y
 CONFIG_FONT_MINI_4x6=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_DEBUG_USER=y
index 94deb0e..a5e8d22 100644 (file)
@@ -50,7 +50,6 @@ CONFIG_MFD_MAX8925=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_MAX8649=y
 CONFIG_REGULATOR_MAX8925=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_MAX8925=y
index 6a11669..9b98761 100644 (file)
@@ -38,7 +38,6 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
 # CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
index 63b5a88..2012370 100644 (file)
@@ -72,7 +72,6 @@ CONFIG_NET_DSA=y
 CONFIG_NET_PKTGEN=m
 CONFIG_CFG80211=y
 CONFIG_MAC80211=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_IMX_WEIM=y
@@ -96,8 +95,6 @@ CONFIG_MTD_UBI=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_ATMEL_TCLIB=y
 CONFIG_ATMEL_SSC=m
-CONFIG_ASPEED_LPC_CTRL=m
-CONFIG_ASPEED_LPC_SNOOP=m
 CONFIG_EEPROM_AT24=y
 # CONFIG_SCSI_PROC_FS is not set
 CONFIG_BLK_DEV_SD=y
@@ -178,10 +175,12 @@ CONFIG_MEDIA_SUPPORT=y
 CONFIG_MEDIA_CAMERA_SUPPORT=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
 CONFIG_SOC_CAMERA=y
+CONFIG_VIDEO_ASPEED=m
 CONFIG_VIDEO_ATMEL_ISI=m
 CONFIG_DRM=y
 CONFIG_DRM_ATMEL_HLCDC=m
 CONFIG_DRM_PANEL_SIMPLE=y
+CONFIG_DRM_ASPEED_GFX=m
 CONFIG_FB_IMX=y
 CONFIG_FB_ATMEL=y
 CONFIG_BACKLIGHT_ATMEL_LCDC=y
@@ -226,6 +225,8 @@ CONFIG_USB_CHIPIDEA_HOST=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_AT91=m
 CONFIG_USB_ATMEL_USBA=m
+CONFIG_USB_ASPEED_VHUB=m
+CONFIG_USB_CONFIGFS=m
 CONFIG_MMC=y
 CONFIG_SDIO_UART=y
 CONFIG_MMC_ATMELMCI=y
@@ -245,11 +246,15 @@ CONFIG_RTC_DRV_RV3029C2=m
 CONFIG_RTC_DRV_AT91RM9200=m
 CONFIG_RTC_DRV_AT91SAM9=m
 CONFIG_RTC_DRV_MV=y
+CONFIG_RTC_DRV_ASPEED=m
 CONFIG_DMADEVICES=y
 CONFIG_AT_HDMAC=y
 CONFIG_MV_XOR=y
 CONFIG_STAGING=y
 CONFIG_FB_XGI=y
+CONFIG_ASPEED_LPC_CTRL=m
+CONFIG_ASPEED_LPC_SNOOP=m
+CONFIG_ASPEED_P2A_CTRL=m
 CONFIG_IIO=m
 CONFIG_ASPEED_ADC=m
 CONFIG_AT91_ADC=m
index 6b748f2..6a40bc2 100644 (file)
@@ -413,6 +413,7 @@ CONFIG_SPI_SPIDEV=y
 CONFIG_SPMI=y
 CONFIG_PINCTRL_AS3722=y
 CONFIG_PINCTRL_RZA2=y
+CONFIG_PINCTRL_STMFX=y
 CONFIG_PINCTRL_PALMAS=y
 CONFIG_PINCTRL_APQ8064=y
 CONFIG_PINCTRL_APQ8084=y
@@ -656,6 +657,8 @@ CONFIG_DRM_VC4=m
 CONFIG_DRM_ETNAVIV=m
 CONFIG_DRM_MXSFB=m
 CONFIG_DRM_PL111=m
+CONFIG_DRM_LIMA=m
+CONFIG_DRM_PANFROST=m
 CONFIG_FB_EFI=y
 CONFIG_FB_WM8505=y
 CONFIG_FB_SH_MOBILE_LCDC=y
@@ -940,7 +943,6 @@ CONFIG_ARCH_TEGRA_2x_SOC=y
 CONFIG_ARCH_TEGRA_3x_SOC=y
 CONFIG_ARCH_TEGRA_114_SOC=y
 CONFIG_ARCH_TEGRA_124_SOC=y
-CONFIG_PM_DEVFREQ=y
 CONFIG_ARM_TEGRA_DEVFREQ=m
 CONFIG_TI_AEMIF=y
 CONFIG_IIO=y
index e956751..b39b130 100644 (file)
@@ -36,7 +36,6 @@ CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 # CONFIG_IPV6 is not set
 CONFIG_NET_PKTGEN=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
index 0e5577a..226f2e9 100644 (file)
@@ -62,7 +62,6 @@ CONFIG_NET_SWITCHDEV=y
 CONFIG_NET_PKTGEN=m
 CONFIG_CFG80211=y
 CONFIG_MAC80211=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_MTD=y
index 3ac2e84..cddce57 100644 (file)
@@ -40,7 +40,6 @@ CONFIG_BT=y
 CONFIG_BT_MRVL=y
 CONFIG_BT_MRVL_SDIO=y
 CONFIG_CFG80211=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_MTD=y
index ed570a0..2773899 100644 (file)
@@ -96,7 +96,6 @@ CONFIG_DRM=y
 CONFIG_DRM_PANEL_SEIKO_43WVF1G=y
 CONFIG_DRM_MXSFB=y
 CONFIG_FB_MODE_HELPERS=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_PWM=y
diff --git a/arch/arm/configs/netx_defconfig b/arch/arm/configs/netx_defconfig
deleted file mode 100644 (file)
index cc5c5f9..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_ARCH_NETX=y
-CONFIG_MACH_NXDKN=y
-CONFIG_MACH_NXDB500=y
-CONFIG_MACH_NXEB500HMI=y
-CONFIG_PREEMPT=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=ttySMX0,115200"
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_XFRM_USER=m
-CONFIG_NET_KEY=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_NET_IPGRE=m
-CONFIG_SYN_COOKIES=y
-CONFIG_INET_AH=y
-CONFIG_INET_ESP=y
-CONFIG_INET_IPCOMP=y
-CONFIG_INET6_AH=m
-CONFIG_INET6_ESP=m
-CONFIG_INET6_IPCOMP=m
-CONFIG_NETFILTER=y
-CONFIG_NET_PKTGEN=m
-CONFIG_MTD=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_PLATRAM=y
-CONFIG_BLK_DEV_LOOP=m
-CONFIG_BLK_DEV_CRYPTOLOOP=m
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_NET_NETX=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_SERIAL_NETX=y
-CONFIG_SERIAL_NETX_CONSOLE=y
-# CONFIG_HWMON is not set
-CONFIG_FB=y
-CONFIG_FB_ARMCLCD=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_LOGO=y
-CONFIG_RTC_CLASS=y
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V4=y
-CONFIG_ROOT_NFS=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_CRYPTO_NULL=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_SHA256=m
-CONFIG_CRYPTO_SHA512=m
-CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_BLOWFISH=m
-CONFIG_CRYPTO_CAST5=m
-CONFIG_CRYPTO_CAST6=m
-CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRC_CCITT=m
-CONFIG_LIBCRC32C=m
index cfc0941..3f35761 100644 (file)
@@ -45,7 +45,6 @@ CONFIG_BT_HCIUART=m
 CONFIG_BT_HCIUART_H4=y
 CONFIG_BT_HCIUART_BCSP=y
 CONFIG_BT_HCIVHCI=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_TESTS=m
 CONFIG_MTD_CMDLINE_PARTS=y
@@ -98,7 +97,6 @@ CONFIG_REGULATOR=y
 CONFIG_DRM=y
 CONFIG_DRM_PANEL_TPO_TPG110=y
 CONFIG_DRM_PL111=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_PWM=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
index c0d152c..63dba62 100644 (file)
@@ -13,7 +13,6 @@ CONFIG_AEABI=y
 CONFIG_CMDLINE="root=/dev/ram0 console=ttyS0,115200n8 rdinit=/sbin/init mem=64M"
 CONFIG_KEXEC=y
 CONFIG_FPE_NWFPE=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
index 8dde118..cb5a878 100644 (file)
@@ -19,7 +19,6 @@ CONFIG_KEXEC=y
 CONFIG_FPE_NWFPE=y
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_MISC=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
index 6bb784f..f7af84e 100644 (file)
@@ -19,7 +19,6 @@ CONFIG_KEXEC=y
 CONFIG_FPE_NWFPE=y
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_MISC=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
index 82af77c..0c43c58 100644 (file)
@@ -79,7 +79,6 @@ CONFIG_BT_RFCOMM=y
 CONFIG_BT_RFCOMM_TTY=y
 CONFIG_BT_BNEP=y
 CONFIG_BT_HIDP=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_CONNECTOR=y
@@ -154,7 +153,6 @@ CONFIG_FB_OMAP_LCDC_EXTERNAL=y
 CONFIG_FB_OMAP_LCDC_HWA742=y
 CONFIG_FB_OMAP_MANUAL_UPDATE=y
 CONFIG_FB_OMAP_LCD_MIPID=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
index 077e0fd..4bdbb03 100644 (file)
@@ -59,7 +59,6 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_IPV6 is not set
 CONFIG_NET_DSA=y
 CONFIG_NET_PKTGEN=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
index e0a6142..4a3fd82 100644 (file)
@@ -30,7 +30,6 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_INPUT_MOUSEDEV_PSAUX is not set
 CONFIG_INPUT_EVDEV=y
@@ -49,7 +48,6 @@ CONFIG_PDA_POWER=y
 # CONFIG_HWMON is not set
 CONFIG_FB=y
 CONFIG_FB_PXA=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_PWM=y
index 9c88a19..a8c5322 100644 (file)
@@ -35,7 +35,6 @@ CONFIG_IP_PNP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
index 7cc8e8e..be19aa1 100644 (file)
@@ -16,7 +16,6 @@ CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 CONFIG_KEXEC=y
 CONFIG_BINFMT_MISC=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
index e7c7b91..0947f02 100644 (file)
@@ -24,7 +24,6 @@ CONFIG_UNIX=y
 CONFIG_INET=y
 CONFIG_IP_PNP=y
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_BLK_DEV is not set
index 7681eea..06bbc7a 100644 (file)
@@ -26,7 +26,6 @@ CONFIG_IP_PNP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_MTD=y
@@ -72,7 +71,6 @@ CONFIG_REGULATOR_DEBUG=y
 CONFIG_REGULATOR_DA903X=y
 CONFIG_FB=y
 CONFIG_FB_PXA=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_LCD_TDO24M=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
index 3aff71e..b211963 100644 (file)
@@ -24,7 +24,6 @@ CONFIG_UNIX=y
 CONFIG_INET=y
 CONFIG_IP_PNP=y
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_BLK_DEV is not set
index 07ebbdc..787c3f9 100644 (file)
@@ -156,7 +156,6 @@ CONFIG_MAC80211=m
 CONFIG_RFKILL=y
 CONFIG_RFKILL_INPUT=y
 CONFIG_RFKILL_GPIO=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_CONNECTOR=y
@@ -462,7 +461,6 @@ CONFIG_PXA3XX_GCU=m
 CONFIG_FB_MBX=m
 CONFIG_FB_VIRTUAL=m
 CONFIG_FB_SIMPLE=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CORGI=m
 CONFIG_LCD_PLATFORM=m
 CONFIG_LCD_TOSA=m
index c185475..34433bf 100644 (file)
@@ -37,6 +37,7 @@ CONFIG_ARM_CPUIDLE=y
 CONFIG_VFP=y
 CONFIG_NEON=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_CMA=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -146,12 +147,13 @@ CONFIG_REGULATOR_QCOM_SMD_RPM=y
 CONFIG_REGULATOR_QCOM_SPMI=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_DRM=y
+CONFIG_DRM_PANEL_SIMPLE=y
 CONFIG_FB=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_BACKLIGHT_LM3630A=y
 CONFIG_BACKLIGHT_LP855X=y
 CONFIG_SOUND=y
 CONFIG_SND=y
@@ -183,6 +185,7 @@ CONFIG_USB_CONFIGFS_NCM=y
 CONFIG_USB_CONFIGFS_ECM=y
 CONFIG_USB_CONFIGFS_F_FS=y
 CONFIG_USB_ULPI_BUS=y
+CONFIG_USB_ETH=m
 CONFIG_MMC=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_ARMMMCI=y
@@ -262,6 +265,8 @@ CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ASCII=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_NLS_UTF8=y
+CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=256
 CONFIG_PRINTK_TIME=y
 CONFIG_DYNAMIC_DEBUG=y
 CONFIG_DEBUG_INFO=y
index cc9fa24..8a056cc 100644 (file)
@@ -34,7 +34,6 @@ CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_AFS_PARTS=y
@@ -65,7 +64,6 @@ CONFIG_DRM=y
 CONFIG_DRM_PANEL_SIMPLE=y
 CONFIG_DRM_PL111=y
 CONFIG_FB_MODE_HELPERS=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
index 39c6485..95b5a4f 100644 (file)
@@ -4,13 +4,8 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_BSD_DISKLABEL=y
-CONFIG_SOLARIS_X86_PARTITION=y
 CONFIG_ARCH_S3C24XX=y
+CONFIG_S3C_ADC=y
 CONFIG_CPU_S3C2412=y
 CONFIG_CPU_S3C2416=y
 CONFIG_CPU_S3C2440=y
@@ -40,13 +35,18 @@ CONFIG_ARCH_S3C2440=y
 CONFIG_MACH_NEO1973_GTA02=y
 CONFIG_MACH_RX1950=y
 CONFIG_MACH_SMDK2443=y
-CONFIG_S3C_ADC=y
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="root=/dev/hda1 ro init=/bin/bash console=ttySAC0"
 CONFIG_FPE_NWFPE=y
 CONFIG_FPE_NWFPE_XP=y
 CONFIG_APM_EMULATION=m
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_SOLARIS_X86_PARTITION=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -74,7 +74,6 @@ CONFIG_INET6_AH=m
 CONFIG_INET6_ESP=m
 CONFIG_INET6_IPCOMP=m
 CONFIG_IPV6_MIP6=m
-CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
 CONFIG_IPV6_TUNNEL=m
 CONFIG_NETFILTER=y
 CONFIG_NF_CONNTRACK=m
@@ -129,7 +128,6 @@ CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 CONFIG_NETFILTER_XT_MATCH_TIME=m
 CONFIG_NETFILTER_XT_MATCH_U32=m
 CONFIG_IP_VS=m
-CONFIG_NF_CONNTRACK_IPV4=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_AH=m
 CONFIG_IP_NF_MATCH_ECN=m
@@ -148,7 +146,6 @@ CONFIG_IP_NF_RAW=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_NF_CONNTRACK_IPV6=m
 CONFIG_IP6_NF_IPTABLES=m
 CONFIG_IP6_NF_MATCH_AH=m
 CONFIG_IP6_NF_MATCH_EUI64=m
@@ -181,11 +178,10 @@ CONFIG_CFG80211=m
 CONFIG_MAC80211=m
 CONFIG_MAC80211_MESH=y
 CONFIG_MAC80211_LEDS=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
-CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_JEDECPROBE=y
@@ -291,11 +287,8 @@ CONFIG_BACKLIGHT_PWM=m
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_SOUND=y
 CONFIG_SND=y
-CONFIG_SND_SEQUENCER=m
-CONFIG_SND_MIXER_OSS=m
-CONFIG_SND_PCM_OSS=m
-CONFIG_SND_SEQUENCER_OSS=y
 CONFIG_SND_VERBOSE_PRINTK=y
+CONFIG_SND_SEQUENCER=m
 # CONFIG_SND_DRIVERS is not set
 # CONFIG_SND_ARM is not set
 # CONFIG_SND_SPI is not set
index 6e26565..59a258d 100644 (file)
@@ -2,9 +2,6 @@ CONFIG_SYSFS_DEPRECATED=y
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_KALLSYMS_ALL=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 CONFIG_ARCH_MULTI_V6=y
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_S3C64XX=y
@@ -18,10 +15,11 @@ CONFIG_MACH_HMT=y
 CONFIG_MACH_SMARTQ5=y
 CONFIG_MACH_SMARTQ7=y
 CONFIG_MACH_WLF_CRAGG_6410=y
-CONFIG_AEABI=y
 CONFIG_CMDLINE="console=ttySAC0,115200 root=/dev/ram init=/linuxrc initrd=0x51000000,6M ramdisk_size=6144"
 CONFIG_VFP=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_MTD=y
 CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_S3C2410=y
@@ -40,15 +38,12 @@ CONFIG_SPI_GPIO=m
 CONFIG_SPI_S3C64XX=m
 CONFIG_FB=y
 CONFIG_FB_S3C=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_LCD_LTV350QV=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_PWM=y
 CONFIG_SOUND=y
 CONFIG_SND=m
-CONFIG_SND_MIXER_OSS=m
-CONFIG_SND_PCM_OSS=m
 CONFIG_SND_SOC=m
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
@@ -61,8 +56,8 @@ CONFIG_USB_SERIAL_EMPEG=m
 CONFIG_USB_SERIAL_FTDI_SIO=m
 CONFIG_USB_SERIAL_PL2303=m
 CONFIG_MMC=y
-CONFIG_MMC_DEBUG=y
 CONFIG_SDIO_UART=y
+CONFIG_MMC_DEBUG=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_S3C=y
 CONFIG_RTC_CLASS=y
index fd4f28a..7091971 100644 (file)
@@ -40,7 +40,6 @@ CONFIG_BT_HCIUART=m
 CONFIG_BT_HCIUART_BCM=y
 CONFIG_CFG80211=m
 CONFIG_MAC80211=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_BLK_DEV_LOOP=y
index d5341b0..ef78534 100644 (file)
@@ -56,7 +56,6 @@ CONFIG_CAN_M_CAN=y
 CONFIG_CFG80211=y
 CONFIG_MAC80211=y
 CONFIG_MAC80211_LEDS=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_STANDALONE is not set
@@ -154,7 +153,6 @@ CONFIG_SOC_CAMERA_OV2640=m
 CONFIG_DRM=y
 CONFIG_DRM_ATMEL_HLCDC=y
 CONFIG_DRM_PANEL_SIMPLE=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_BACKLIGHT_GENERIC is not set
index eb02ba9..c6c7035 100644 (file)
@@ -197,7 +197,6 @@ CONFIG_PWM=y
 CONFIG_PWM_RCAR=y
 CONFIG_PWM_RENESAS_TPU=y
 CONFIG_RESET_CONTROLLER=y
-CONFIG_GENERIC_PHY=y
 CONFIG_PHY_RCAR_GEN2=y
 CONFIG_PHY_RCAR_GEN3_USB2=y
 # CONFIG_DNOTIFY is not set
index 6701a97..fe2e1e8 100644 (file)
@@ -44,7 +44,6 @@ CONFIG_PCI=y
 CONFIG_PCI_MSI=y
 CONFIG_PCIE_ALTERA=y
 CONFIG_PCIE_ALTERA_MSI=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_MTD=y
index 8ee3679..3b206a3 100644 (file)
@@ -28,7 +28,6 @@ CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 CONFIG_NET_IPIP=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_OF_PARTS=y
 CONFIG_MTD_BLOCK=y
index ddd73b2..fc5f71c 100644 (file)
@@ -13,7 +13,6 @@ CONFIG_MACH_SPEAR310=y
 CONFIG_MACH_SPEAR320=y
 CONFIG_BINFMT_MISC=y
 CONFIG_NET=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_OF_PARTS=y
 CONFIG_MTD_BLOCK=y
@@ -54,7 +53,6 @@ CONFIG_WATCHDOG=y
 CONFIG_ARM_SP805_WATCHDOG=y
 CONFIG_DRM=y
 CONFIG_DRM_PL111=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
index 5b410f0..52a56b8 100644 (file)
@@ -10,7 +10,6 @@ CONFIG_PLAT_SPEAR=y
 CONFIG_ARCH_SPEAR6XX=y
 CONFIG_BINFMT_MISC=y
 CONFIG_NET=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_OF_PARTS=y
 CONFIG_MTD_BLOCK=y
index f6d2f67..4fb51d6 100644 (file)
@@ -78,7 +78,6 @@ CONFIG_BT_HCIBT3C=m
 CONFIG_BT_HCIBLUECARD=m
 CONFIG_BT_HCIBTUART=m
 CONFIG_BT_HCIVHCI=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
@@ -126,7 +125,6 @@ CONFIG_SPI=y
 CONFIG_SPI_PXA2XX=y
 CONFIG_FB=y
 CONFIG_FB_PXA=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_LCD_CORGI=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
index 68eb16e..cbc9ade 100644 (file)
@@ -33,7 +33,6 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_MTD=y
index d0a9e5d..3a9503f 100644 (file)
@@ -22,7 +22,6 @@ CONFIG_FPE_NWFPE=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
index ecad225..d66f0c2 100644 (file)
@@ -136,7 +136,6 @@ CONFIG_SA1100_WATCHDOG=y
 CONFIG_FB=y
 CONFIG_FIRMWARE_EDID=y
 CONFIG_FB_PXA=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_VGA_CONSOLE is not set
index bedf397..8223397 100644 (file)
@@ -22,7 +22,6 @@ CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="root=/dev/ram0 rw rootfstype=rootfs console=ttyAMA0,115200n8 lpj=515072"
 CONFIG_CPU_IDLE=y
 # CONFIG_SUSPEND is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
@@ -43,7 +42,6 @@ CONFIG_WATCHDOG=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_FB=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_USB_SUPPORT is not set
index e2151a7..e6b98b6 100644 (file)
@@ -38,7 +38,6 @@ CONFIG_CFG80211_DEBUGFS=y
 CONFIG_MAC80211=y
 CONFIG_MAC80211_LEDS=y
 CONFIG_CAIF=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_BLK_DEV_RAM=y
index 5282324..fe4d4b5 100644 (file)
@@ -62,7 +62,6 @@ CONFIG_DRM_PANEL_SIMPLE=y
 CONFIG_DRM_DUMB_VGA_DAC=y
 CONFIG_DRM_PL111=y
 CONFIG_FB_MODE_HELPERS=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_LOGO=y
 CONFIG_SOUND=y
index 484d77a..2575355 100644 (file)
@@ -45,7 +45,6 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_WIRELESS is not set
 CONFIG_NET_9P=y
 CONFIG_NET_9P_VIRTIO=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DMA_CMA=y
 CONFIG_MTD=y
@@ -86,7 +85,6 @@ CONFIG_DRM_PANEL_SIMPLE=y
 CONFIG_DRM_SII902X=y
 CONFIG_DRM_PL111=y
 CONFIG_FB_MODE_HELPERS=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
index 070e507..2ff1616 100644 (file)
@@ -41,7 +41,6 @@ CONFIG_BT_BNEP=m
 CONFIG_BT_HCIUART=m
 CONFIG_BT_HCIUART_H4=y
 CONFIG_BT_HCIUART_BCSP=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_FW_LOADER=m
 CONFIG_MTD=y
 CONFIG_MTD_REDBOOT_PARTS=y
@@ -110,7 +109,6 @@ CONFIG_WATCHDOG=y
 CONFIG_FB=y
 CONFIG_FB_PXA=m
 CONFIG_FB_PXA_PARAMETERS=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_PWM=m
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
index 2eda246..f1fbdfc 100644 (file)
@@ -43,7 +43,6 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD_COMPLEX_MAPPINGS=y
index 09e7050..aa3023c 100644 (file)
@@ -39,7 +39,6 @@ CONFIG_BT_HCIUART_BCSP=y
 CONFIG_CFG80211=m
 CONFIG_LIB80211=m
 CONFIG_MAC80211=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_REDBOOT_PARTS_READONLY=y
@@ -110,7 +109,6 @@ CONFIG_WATCHDOG=y
 CONFIG_FB=y
 CONFIG_FB_PXA=m
 CONFIG_FB_PXA_PARAMETERS=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
index dfc061d..c4070c1 100644 (file)
@@ -41,7 +41,6 @@ CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="console=ttyAMA0,115200 debug earlyprintk root=/dev/ram rw rootwait"
 #CONFIG_NET is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_DMA_CMA=y
index f11c35c..7a0596f 100644 (file)
@@ -30,7 +30,6 @@
  * ISA I/O bus memory addresses are 1:1 with the physical address.
  */
 #define isa_virt_to_bus virt_to_phys
-#define isa_page_to_bus page_to_phys
 #define isa_bus_to_virt phys_to_virt
 
 /*
index 77e5582..67d2071 100644 (file)
@@ -5,7 +5,7 @@
  *  Copyright (C) 1997-1999 Russell King
  *
  *  Structure passed to kernel to tell it about the
- *  hardware it's running on.  See Documentation/arm/Setup
+ *  hardware it's running on.  See Documentation/arm/setup.rst
  *  for more info.
  */
 #ifndef __ASMARM_SETUP_H
diff --git a/arch/arm/include/debug/netx.S b/arch/arm/include/debug/netx.S
deleted file mode 100644 (file)
index 08afc58..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Debugging macro include header
- *
- *  Copyright (C) 1994-1999 Russell King
- *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
-*/
-
-#define UART_DATA 0
-#define UART_FLAG 0x18
-#define UART_FLAG_BUSY (1 << 3)
-
-               .macro  addruart, rp, rv, tmp
-               ldr     \rp, =CONFIG_DEBUG_UART_PHYS
-               ldr     \rv, =CONFIG_DEBUG_UART_VIRT
-               .endm
-
-               .macro  senduart,rd,rx
-               str     \rd, [\rx, #UART_DATA]
-               .endm
-
-               .macro  busyuart,rd,rx
-1002:          ldr     \rd, [\rx, #UART_FLAG]
-               tst     \rd, #UART_FLAG_BUSY
-               bne     1002b
-               .endm
-
-               .macro  waituart,rd,rx
-1001:          ldr     \rd, [\rx, #UART_FLAG]
-               tst     \rd, #UART_FLAG_BUSY
-               bne     1001b
-               .endm
index 6b335a9..25ceda6 100644 (file)
@@ -9,7 +9,7 @@
  * published by the Free Software Foundation.
  *
  *  Structure passed to kernel to tell it about the
- *  hardware it's running on.  See Documentation/arm/Setup
+ *  hardware it's running on.  See Documentation/arm/setup.rst
  *  for more info.
  */
 #ifndef _UAPI__ASMARM_SETUP_H
index 0b8cfdd..858d4e5 100644 (file)
@@ -826,7 +826,7 @@ ENDPROC(__switch_to)
  * existing ones.  This mechanism should be used only for things that are
  * really small and justified, and not be abused freely.
  *
- * See Documentation/arm/kernel_user_helpers.txt for formal definitions.
+ * See Documentation/arm/kernel_user_helpers.rst for formal definitions.
  */
  THUMB(        .arm    )
 
index b3d439c..deef17f 100644 (file)
@@ -55,6 +55,13 @@ void *module_alloc(unsigned long size)
 }
 #endif
 
+bool module_exit_section(const char *name)
+{
+       return strstarts(name, ".exit") ||
+               strstarts(name, ".ARM.extab.exit") ||
+               strstarts(name, ".ARM.exidx.exit");
+}
+
 int
 apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
               unsigned int relindex, struct module *module)
index 0bff017..b25c545 100644 (file)
@@ -31,7 +31,6 @@ else
 endif
 
 ifeq ($(CONFIG_ARCH_RPC),y)
-  lib-y                                += ecard.o io-acorn.o floppydma.o
   AFLAGS_delay-loop.o          += -march=armv4
 endif
 
index da85e64..d5af6ae 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/suspend.h>
 
 #include <linux/clk/at91_pmc.h>
+#include <linux/platform_data/atmel.h>
 
 #include <asm/cacheflush.h>
 #include <asm/fncpy.h>
index 4ef1e55..5e5f1fa 100644 (file)
@@ -208,6 +208,7 @@ config ARCH_BCM_63XX
 config ARCH_BRCMSTB
        bool "Broadcom BCM7XXX based boards"
        depends on ARCH_MULTI_V7
+       select ARCH_HAS_RESET_CONTROLLER
        select ARM_GIC
        select ARM_ERRATA_798181 if SMP
        select HAVE_ARM_ARCH_TIMER
@@ -217,6 +218,7 @@ config ARCH_BRCMSTB
        select ZONE_DMA if ARM_LPAE
        select SOC_BRCMSTB
        select SOC_BUS
+       select PINCTRL
        help
          Say Y if you intend to run the kernel on a Broadcom ARM-based STB
          chipset.
index 8fd23b2..b59c813 100644 (file)
@@ -40,9 +40,6 @@ obj-$(CONFIG_ARCH_BCM_MOBILE_L2_CACHE) += kona_l2_cache.o
 
 # Support for secure monitor traps
 obj-$(CONFIG_ARCH_BCM_MOBILE_SMC) += bcm_kona_smc.o
-ifeq ($(call as-instr,.arch_extension sec,as_has_sec),as_has_sec)
-CFLAGS_bcm_kona_smc.o          += -Wa,-march=armv7-a+sec -DREQUIRES_SEC
-endif
 
 # BCM2835
 obj-$(CONFIG_ARCH_BCM2835)     += board_bcm2835.o
index 83dd0c1..641e1f8 100644 (file)
@@ -141,6 +141,7 @@ static int bcm63138_smp_boot_secondary(unsigned int cpu,
         * return
         */
        ret = bcm63xx_pmb_power_on_cpu(dn);
+       of_node_put(dn);
        if (ret)
                goto out;
 out:
index a55a7ec..541e850 100644 (file)
@@ -125,9 +125,7 @@ static int bcm_kona_do_smc(u32 service_id, u32 buffer_phys)
                __asmeq("%2", "r4")
                __asmeq("%3", "r5")
                __asmeq("%4", "r6")
-#ifdef REQUIRES_SEC
                ".arch_extension sec\n"
-#endif
                "       smc    #0\n"
                : "=r" (ip), "=r" (r0)
                : "r" (r4), "r" (r5), "r" (r6)
index b81bb38..1238ac8 100644 (file)
@@ -38,6 +38,7 @@ static void bcm281xx_restart(enum reboot_mode mode, const char *cmd)
                return;
        }
        base = of_iomap(np_wdog, 0);
+       of_node_put(np_wdog);
        if (!base) {
                pr_emerg("Couldn't map brcm,kona-wdt\n");
                return;
index 1237996..4555f21 100644 (file)
@@ -334,11 +334,14 @@ static void __init brcmstb_cpu_ctrl_setup(unsigned int max_cpus)
 
        rc = setup_hifcpubiuctrl_regs(np);
        if (rc)
-               return;
+               goto out_put_node;
 
        rc = setup_hifcont_regs(np);
        if (rc)
-               return;
+               goto out_put_node;
+
+out_put_node:
+       of_node_put(np);
 }
 
 static int brcmstb_boot_secondary(unsigned int cpu, struct task_struct *idle)
index 31ae3be..0628e7d 100644 (file)
@@ -631,13 +631,12 @@ static void da850_evm_bb_keys_init(unsigned gpio)
        }
 }
 
-#define DA850_N_BB_USER_LED    2
-
 static struct gpio_led da850_evm_bb_leds[] = {
-       [0 ... DA850_N_BB_USER_LED - 1] = {
-               .active_low = 1,
-               .gpio = -1, /* assigned at runtime */
-               .name = NULL, /* assigned at runtime */
+       {
+               .name = "user_led2",
+       },
+       {
+               .name = "user_led1",
        },
 };
 
@@ -646,6 +645,20 @@ static struct gpio_led_platform_data da850_evm_bb_leds_pdata = {
        .num_leds = ARRAY_SIZE(da850_evm_bb_leds),
 };
 
+static struct gpiod_lookup_table da850_evm_bb_leds_gpio_table = {
+       .dev_id = "leds-gpio",
+       .table = {
+               GPIO_LOOKUP_IDX("i2c-bb-expander",
+                               DA850_EVM_BB_EXP_USER_LED2, NULL,
+                               0, GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP_IDX("i2c-bb-expander",
+                               DA850_EVM_BB_EXP_USER_LED2 + 1, NULL,
+                               1, GPIO_ACTIVE_LOW),
+
+               { },
+       },
+};
+
 static struct platform_device da850_evm_bb_leds_device = {
        .name           = "leds-gpio",
        .id             = -1,
@@ -654,20 +667,6 @@ static struct platform_device da850_evm_bb_leds_device = {
        }
 };
 
-static void da850_evm_bb_leds_init(unsigned gpio)
-{
-       int i;
-       struct gpio_led *led;
-
-       for (i = 0; i < DA850_N_BB_USER_LED; i++) {
-               led = &da850_evm_bb_leds[i];
-
-               led->gpio = gpio + DA850_EVM_BB_EXP_USER_LED2 + i;
-               led->name =
-                       da850_evm_bb_exp[DA850_EVM_BB_EXP_USER_LED2 + i];
-       }
-}
-
 static int da850_evm_bb_expander_setup(struct i2c_client *client,
                                                unsigned gpio, unsigned ngpio,
                                                void *c)
@@ -685,7 +684,7 @@ static int da850_evm_bb_expander_setup(struct i2c_client *client,
                goto io_exp_setup_sw_fail;
        }
 
-       da850_evm_bb_leds_init(gpio);
+       gpiod_add_lookup_table(&da850_evm_bb_leds_gpio_table);
        ret = platform_device_register(&da850_evm_bb_leds_device);
        if (ret) {
                pr_warn("Could not register baseboard GPIO expander LEDs");
@@ -729,10 +728,12 @@ static struct i2c_board_info __initdata da850_evm_i2c_devices[] = {
        },
        {
                I2C_BOARD_INFO("tca6416", 0x20),
+               .dev_name = "ui-expander",
                .platform_data = &da850_evm_ui_expander_info,
        },
        {
                I2C_BOARD_INFO("tca6416", 0x21),
+               .dev_name = "bb-expander",
                .platform_data = &da850_evm_bb_expander_info,
        },
 };
index 1c518b8..d742223 100644 (file)
@@ -49,6 +49,7 @@ config S5P_DEV_MFC
 
 config ARCH_EXYNOS3
        bool "SAMSUNG EXYNOS3"
+       default y
        select ARM_CPU_SUSPEND if PM
        help
          Samsung EXYNOS3 (Cortex-A7) SoC based systems
@@ -106,7 +107,7 @@ config SOC_EXYNOS5420
        bool "SAMSUNG EXYNOS5420"
        default y
        depends on ARCH_EXYNOS5
-       select MCPM if SMP
+       select EXYNOS_MCPM if SMP
        select ARM_CCI400_PORT_CTRL
        select ARM_CPU_SUSPEND
 
@@ -115,6 +116,10 @@ config SOC_EXYNOS5800
        default y
        depends on SOC_EXYNOS5420
 
+config EXYNOS_MCPM
+       bool
+       select MCPM
+
 config EXYNOS_CPU_SUSPEND
        bool
        select ARM_CPU_SUSPEND
index 264dbaa..0fd3fcf 100644 (file)
@@ -14,9 +14,5 @@ obj-$(CONFIG_PM_SLEEP)                += suspend.o
 
 obj-$(CONFIG_SMP)              += platsmp.o headsmp.o
 
-plus_sec := $(call as-instr,.arch_extension sec,+sec)
-AFLAGS_exynos-smc.o            :=-Wa,-march=armv7-a$(plus_sec)
-AFLAGS_sleep.o                 :=-Wa,-march=armv7-a$(plus_sec)
-
-obj-$(CONFIG_MCPM)             += mcpm-exynos.o
+obj-$(CONFIG_EXYNOS_MCPM)      += mcpm-exynos.o
 CFLAGS_mcpm-exynos.o           += -march=armv7-a
index c93356a..56411bb 100644 (file)
@@ -106,7 +106,7 @@ void exynos_firmware_init(void);
 #define C2_STATE       (1 << 3)
 /*
  * Magic values for bootloader indicating chosen low power mode.
- * See also Documentation/arm/Samsung/Bootloader-interface.txt
+ * See also Documentation/arm/samsung/bootloader-interface.rst
  */
 #define EXYNOS_SLEEP_MAGIC     0x00000bad
 #define EXYNOS_AFTR_MAGIC      0xfcba0d10
index d259532..6da31e6 100644 (file)
@@ -10,7 +10,8 @@
 /*
  * Function signature: void exynos_smc(u32 cmd, u32 arg1, u32 arg2, u32 arg3)
  */
-
+       .arch armv7-a
+       .arch_extension sec
 ENTRY(exynos_smc)
        stmfd   sp!, {r4-r11, lr}
        dsb
index 2783c3a..ed93f91 100644 (file)
@@ -44,7 +44,8 @@ ENTRY(exynos_cpu_resume)
 ENDPROC(exynos_cpu_resume)
 
        .align
-
+       .arch armv7-a
+       .arch_extension sec
 ENTRY(exynos_cpu_resume_ns)
        mrc     p15, 0, r0, c0, c0, 0
        ldr     r1, =CPU_MASK
index be122af..6a0d344 100644 (file)
@@ -268,7 +268,7 @@ static int exynos5420_cpu_suspend(unsigned long arg)
        unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
        unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
 
-       if (IS_ENABLED(CONFIG_MCPM)) {
+       if (IS_ENABLED(CONFIG_EXYNOS_MCPM)) {
                mcpm_set_entry_vector(cpu, cluster, exynos_cpu_resume);
                mcpm_cpu_suspend();
        }
@@ -285,7 +285,7 @@ static void exynos_pm_set_wakeup_mask(void)
         * Set wake-up mask registers
         * EXYNOS_EINT_WAKEUP_MASK is set by pinctrl driver in late suspend.
         */
-       pmu_raw_writel(exynos_irqwake_intmask & ~(1 << 31), S5P_WAKEUP_MASK);
+       pmu_raw_writel(exynos_irqwake_intmask & ~BIT(31), S5P_WAKEUP_MASK);
 }
 
 static void exynos_pm_enter_sleep_mode(void)
@@ -351,7 +351,7 @@ static void exynos5420_pm_prepare(void)
        exynos_pm_enter_sleep_mode();
 
        /* ensure at least INFORM0 has the resume address */
-       if (IS_ENABLED(CONFIG_MCPM))
+       if (IS_ENABLED(CONFIG_EXYNOS_MCPM))
                pmu_raw_writel(__pa_symbol(mcpm_entry_point), S5P_INFORM0);
 
        tmp = pmu_raw_readl(EXYNOS_L2_OPTION(0));
@@ -455,7 +455,7 @@ static void exynos5420_prepare_pm_resume(void)
        mpidr = read_cpuid_mpidr();
        cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
 
-       if (IS_ENABLED(CONFIG_MCPM))
+       if (IS_ENABLED(CONFIG_EXYNOS_MCPM))
                WARN_ON(mcpm_cpu_powered_up());
 
        if (IS_ENABLED(CONFIG_HW_PERF_EVENTS) && cluster != 0) {
index 7e6732c..71cc680 100644 (file)
@@ -1,7 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-y                                  := highbank.o system.o smc.o
 
-plus_sec := $(call as-instr,.arch_extension sec,+sec)
-AFLAGS_smc.o                           :=-Wa,-march=armv7-a$(plus_sec)
-
 obj-$(CONFIG_PM_SLEEP)                 += pm.o
index b16c044..78b3f19 100644 (file)
@@ -13,7 +13,8 @@
  * the monitor API number.
  * Function signature : void highbank_smc1(u32 fn, u32 arg)
  */
-
+       .arch armv7-a
+       .arch_extension sec
 ENTRY(highbank_smc1)
        stmfd   sp!, {r4-r11, lr}
        mov     r12, r0
index a2441ed..39a7d93 100644 (file)
 #include "hardware.h"
 
 static int num_idle_cpus = 0;
-static DEFINE_SPINLOCK(cpuidle_lock);
+static DEFINE_RAW_SPINLOCK(cpuidle_lock);
 
 static int imx6q_enter_wait(struct cpuidle_device *dev,
                            struct cpuidle_driver *drv, int index)
 {
-       spin_lock(&cpuidle_lock);
+       raw_spin_lock(&cpuidle_lock);
        if (++num_idle_cpus == num_online_cpus())
                imx6_set_lpm(WAIT_UNCLOCKED);
-       spin_unlock(&cpuidle_lock);
+       raw_spin_unlock(&cpuidle_lock);
 
        cpu_do_idle();
 
-       spin_lock(&cpuidle_lock);
+       raw_spin_lock(&cpuidle_lock);
        if (num_idle_cpus-- == num_online_cpus())
                imx6_set_lpm(WAIT_CLOCKED);
-       spin_unlock(&cpuidle_lock);
+       raw_spin_unlock(&cpuidle_lock);
 
        return index;
 }
index dec5d90..9571345 100644 (file)
@@ -94,6 +94,12 @@ static void __init imx7d_init_machine(void)
        imx7d_enet_init();
 }
 
+static void __init imx7d_init_late(void)
+{
+       if (IS_ENABLED(CONFIG_ARM_IMX_CPUFREQ_DT))
+               platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0);
+}
+
 static void __init imx7d_init_irq(void)
 {
        imx_init_revision_from_anatop();
@@ -110,5 +116,6 @@ static const char *const imx7d_dt_compat[] __initconst = {
 DT_MACHINE_START(IMX7D, "Freescale i.MX7 Dual (Device Tree)")
        .init_irq       = imx7d_init_irq,
        .init_machine   = imx7d_init_machine,
+       .init_late      = imx7d_init_late,
        .dt_compat      = imx7d_dt_compat,
 MACHINE_END
index fc5378b..f7211b5 100644 (file)
@@ -33,7 +33,7 @@ config MACH_AVILA
        help
          Say 'Y' here if you want your kernel to support the Gateworks
          Avila Network Platform. For more information on this platform,
-         see <file:Documentation/arm/IXP4xx>.
+         see <file:Documentation/arm/ixp4xx.rst>.
 
 config MACH_LOFT
     bool "Loft"
@@ -49,7 +49,7 @@ config ARCH_ADI_COYOTE
        help
          Say 'Y' here if you want your kernel to support the ADI 
          Engineering Coyote Gateway Reference Platform. For more
-         information on this platform, see <file:Documentation/arm/IXP4xx>.
+         information on this platform, see <file:Documentation/arm/ixp4xx.rst>.
 
 config MACH_GATEWAY7001
        bool "Gateway 7001"
@@ -72,21 +72,21 @@ config ARCH_IXDP425
        help
          Say 'Y' here if you want your kernel to support Intel's 
          IXDP425 Development Platform (Also known as Richfield).  
-         For more information on this platform, see <file:Documentation/arm/IXP4xx>.
+         For more information on this platform, see <file:Documentation/arm/ixp4xx.rst>.
 
 config MACH_IXDPG425
        bool "IXDPG425"
        help
          Say 'Y' here if you want your kernel to support Intel's
          IXDPG425 Development Platform (Also known as Montajade).
-         For more information on this platform, see <file:Documentation/arm/IXP4xx>.
+         For more information on this platform, see <file:Documentation/arm/ixp4xx.rst>.
 
 config MACH_IXDP465
        bool "IXDP465"
        help
          Say 'Y' here if you want your kernel to support Intel's
          IXDP465 Development Platform (Also known as BMP).
-         For more information on this platform, see <file:Documentation/arm/IXP4xx>.
+         For more information on this platform, see <file:Documentation/arm/ixp4xx.rst>.
 
 config MACH_GORAMO_MLR
        bool "GORAMO Multi Link Router"
@@ -99,7 +99,7 @@ config MACH_KIXRP435
        help
          Say 'Y' here if you want your kernel to support Intel's
          KIXRP435 Reference Platform.
-         For more information on this platform, see <file:Documentation/arm/IXP4xx>.
+         For more information on this platform, see <file:Documentation/arm/ixp4xx.rst>.
 
 #
 # IXCDP1100 is the exact same HW as IXDP425, but with a different machine 
@@ -116,7 +116,7 @@ config ARCH_PRPMC1100
        help
          Say 'Y' here if you want your kernel to support the Motorola
          PrPCM1100 Processor Mezanine Module. For more information on
-         this platform, see <file:Documentation/arm/IXP4xx>.
+         this platform, see <file:Documentation/arm/ixp4xx.rst>.
 
 config MACH_NAS100D
        bool
index f8b0dcc..739b38b 100644 (file)
@@ -1,9 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-y                                  := keystone.o smc.o
 
-plus_sec := $(call as-instr,.arch_extension sec,+sec)
-AFLAGS_smc.o                           :=-Wa,-march=armv7-a$(plus_sec)
-
 obj-$(CONFIG_SMP)                      += platsmp.o
 
 # PM domain driver for Keystone SOCs
index 76d0bf6..21ef75c 100644 (file)
@@ -18,6 +18,7 @@
  *
  * Return: Non zero value on failure
  */
+       .arch_extension sec
 ENTRY(keystone_cpu_smc)
        stmfd   sp!, {r4-r11, lr}
        smc     #0
index 85d1b13..6006505 100644 (file)
@@ -41,18 +41,10 @@ obj-$(CONFIG_SOC_OMAP5)                     += $(omap-4-5-common) $(smp-y) sleep44xx.o
 obj-$(CONFIG_SOC_AM43XX)               += $(omap-4-5-common)
 obj-$(CONFIG_SOC_DRA7XX)               += $(omap-4-5-common) $(smp-y) sleep44xx.o
 
-plus_sec := $(call as-instr,.arch_extension sec,+sec)
-AFLAGS_omap-headsmp.o                  :=-Wa,-march=armv7-a$(plus_sec)
-AFLAGS_omap-smc.o                      :=-Wa,-march=armv7-a$(plus_sec)
-AFLAGS_sleep44xx.o                     :=-Wa,-march=armv7-a$(plus_sec)
-
 # Functions loaded to SRAM
 obj-$(CONFIG_SOC_OMAP2420)             += sram242x.o
 obj-$(CONFIG_SOC_OMAP2430)             += sram243x.o
 
-AFLAGS_sram242x.o                      :=-Wa,-march=armv6
-AFLAGS_sram243x.o                      :=-Wa,-march=armv6
-
 # Restart code (OMAP4/5 currently in omap4-common.c)
 obj-$(CONFIG_SOC_OMAP2420)             += omap2-restart.o
 obj-$(CONFIG_SOC_OMAP2430)             += omap2-restart.o
@@ -94,11 +86,6 @@ obj-$(CONFIG_PM_DEBUG)                       += pm-debug.o
 obj-$(CONFIG_POWER_AVS_OMAP)           += sr_device.o
 obj-$(CONFIG_POWER_AVS_OMAP_CLASS3)    += smartreflex-class3.o
 
-AFLAGS_sleep24xx.o                     :=-Wa,-march=armv6
-AFLAGS_sleep34xx.o                     :=-Wa,-march=armv7-a$(plus_sec)
-AFLAGS_sleep33xx.o                     :=-Wa,-march=armv7-a$(plus_sec)
-AFLAGS_sleep43xx.o                     :=-Wa,-march=armv7-a$(plus_sec)
-
 endif
 
 ifeq ($(CONFIG_CPU_IDLE),y)
index 7d0db77..1762f91 100644 (file)
@@ -55,6 +55,8 @@ ENDPROC(omap5_secondary_startup)
  * omap5_secondary_startup if the primary CPU was put into HYP mode by
  * the boot loader.
  */
+       .arch armv7-a
+       .arch_extension sec
 ENTRY(omap5_secondary_hyp_startup)
 wait_2:        ldr     r2, =AUX_CORE_BOOT0_PA  @ read from AuxCoreBoot0
        ldr     r0, [r2]
index 630b9bd..fd2bcd9 100644 (file)
@@ -20,7 +20,8 @@
  * link register "lr".
  * Function signature : void omap_smc1(u32 fn, u32 arg)
  */
-
+       .arch armv7-a
+       .arch_extension sec
 ENTRY(omap_smc1)
        stmfd   sp!, {r2-r12, lr}
        mov     r12, r0
index e035047..203664c 100644 (file)
@@ -3442,6 +3442,7 @@ static int omap_hwmod_check_module(struct device *dev,
  * @dev: struct device
  * @oh: module
  * @sysc_fields: sysc register bits
+ * @clockdomain: clockdomain
  * @rev_offs: revision register offset
  * @sysc_offs: sysconfig register offset
  * @syss_offs: sysstatus register offset
@@ -3453,6 +3454,7 @@ static int omap_hwmod_check_module(struct device *dev,
 static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
                                      const struct ti_sysc_module_data *data,
                                      struct sysc_regbits *sysc_fields,
+                                     struct clockdomain *clkdm,
                                      s32 rev_offs, s32 sysc_offs,
                                      s32 syss_offs, u32 sysc_flags,
                                      u32 idlemodes)
@@ -3460,8 +3462,6 @@ static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
        struct omap_hwmod_class_sysconfig *sysc;
        struct omap_hwmod_class *class = NULL;
        struct omap_hwmod_ocp_if *oi = NULL;
-       struct clockdomain *clkdm = NULL;
-       struct clk *clk = NULL;
        void __iomem *regs = NULL;
        unsigned long flags;
 
@@ -3508,36 +3508,6 @@ static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
                oi->user = OCP_USER_MPU | OCP_USER_SDMA;
        }
 
-       if (!oh->_clk) {
-               struct clk_hw_omap *hwclk;
-
-               clk = of_clk_get_by_name(dev->of_node, "fck");
-               if (!IS_ERR(clk))
-                       clk_prepare(clk);
-               else
-                       clk = NULL;
-
-               /*
-                * Populate clockdomain based on dts clock. It is needed for
-                * clkdm_deny_idle() and clkdm_allow_idle() until we have have
-                * interconnect driver and reset driver capable of blocking
-                * clockdomain idle during reset, enable and idle.
-                */
-               if (clk) {
-                       hwclk = to_clk_hw_omap(__clk_get_hw(clk));
-                       if (hwclk && hwclk->clkdm_name)
-                               clkdm = clkdm_lookup(hwclk->clkdm_name);
-               }
-
-               /*
-                * Note that we assume interconnect driver manages the clocks
-                * and do not need to populate oh->_clk for dynamically
-                * allocated modules.
-                */
-               clk_unprepare(clk);
-               clk_put(clk);
-       }
-
        spin_lock_irqsave(&oh->_lock, flags);
        if (regs)
                oh->_mpu_rt_va = regs;
@@ -3623,7 +3593,7 @@ int omap_hwmod_init_module(struct device *dev,
        u32 sysc_flags, idlemodes;
        int error;
 
-       if (!dev || !data)
+       if (!dev || !data || !data->name || !cookie)
                return -EINVAL;
 
        oh = _lookup(data->name);
@@ -3694,7 +3664,8 @@ int omap_hwmod_init_module(struct device *dev,
                return error;
 
        return omap_hwmod_allocate_module(dev, oh, data, sysc_fields,
-                                         rev_offs, sysc_offs, syss_offs,
+                                         cookie->clkdm, rev_offs,
+                                         sysc_offs, syss_offs,
                                          sysc_flags, idlemodes);
 }
 
index 4c3543b..adb6271 100644 (file)
@@ -529,7 +529,7 @@ static struct omap_hwmod_class_sysconfig am33xx_gpio_sysc = {
        .sysc_fields    = &omap_hwmod_sysc_type1,
 };
 
-struct omap_hwmod_class am33xx_gpio_hwmod_class = {
+static struct omap_hwmod_class am33xx_gpio_hwmod_class = {
        .name           = "gpio",
        .sysc           = &am33xx_gpio_sysc,
 };
@@ -539,7 +539,7 @@ static struct omap_hwmod_opt_clk gpio1_opt_clks[] = {
        { .role = "dbclk", .clk = "gpio1_dbclk" },
 };
 
-struct omap_hwmod am33xx_gpio1_hwmod = {
+static struct omap_hwmod am33xx_gpio1_hwmod = {
        .name           = "gpio2",
        .class          = &am33xx_gpio_hwmod_class,
        .clkdm_name     = "l4ls_clkdm",
@@ -559,7 +559,7 @@ static struct omap_hwmod_opt_clk gpio2_opt_clks[] = {
        { .role = "dbclk", .clk = "gpio2_dbclk" },
 };
 
-struct omap_hwmod am33xx_gpio2_hwmod = {
+static struct omap_hwmod am33xx_gpio2_hwmod = {
        .name           = "gpio3",
        .class          = &am33xx_gpio_hwmod_class,
        .clkdm_name     = "l4ls_clkdm",
@@ -579,7 +579,7 @@ static struct omap_hwmod_opt_clk gpio3_opt_clks[] = {
        { .role = "dbclk", .clk = "gpio3_dbclk" },
 };
 
-struct omap_hwmod am33xx_gpio3_hwmod = {
+static struct omap_hwmod am33xx_gpio3_hwmod = {
        .name           = "gpio4",
        .class          = &am33xx_gpio_hwmod_class,
        .clkdm_name     = "l4ls_clkdm",
index b0f8c9a..6c6f8fc 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/platform_data/wkup_m3.h>
 #include <linux/platform_data/asoc-ti-mcbsp.h>
 
+#include "clockdomain.h"
 #include "common.h"
 #include "common-board-devices.h"
 #include "control.h"
@@ -460,6 +461,62 @@ static void __init dra7x_evm_mmc_quirk(void)
 }
 #endif
 
+static struct clockdomain *ti_sysc_find_one_clockdomain(struct clk *clk)
+{
+       struct clockdomain *clkdm = NULL;
+       struct clk_hw_omap *hwclk;
+
+       hwclk = to_clk_hw_omap(__clk_get_hw(clk));
+       if (hwclk && hwclk->clkdm_name)
+               clkdm = clkdm_lookup(hwclk->clkdm_name);
+
+       return clkdm;
+}
+
+/**
+ * ti_sysc_clkdm_init - find clockdomain based on clock
+ * @fck: device functional clock
+ * @ick: device interface clock
+ * @dev: struct device
+ *
+ * Populate clockdomain based on clock. It is needed for
+ * clkdm_deny_idle() and clkdm_allow_idle() for blocking clockdomain
+ * clockdomain idle during reset, enable and idle.
+ *
+ * Note that we assume interconnect driver manages the clocks
+ * and do not need to populate oh->_clk for dynamically
+ * allocated modules.
+ */
+static int ti_sysc_clkdm_init(struct device *dev,
+                             struct clk *fck, struct clk *ick,
+                             struct ti_sysc_cookie *cookie)
+{
+       if (fck)
+               cookie->clkdm = ti_sysc_find_one_clockdomain(fck);
+       if (cookie->clkdm)
+               return 0;
+       if (ick)
+               cookie->clkdm = ti_sysc_find_one_clockdomain(ick);
+       if (cookie->clkdm)
+               return 0;
+
+       return -ENODEV;
+}
+
+static void ti_sysc_clkdm_deny_idle(struct device *dev,
+                                   const struct ti_sysc_cookie *cookie)
+{
+       if (cookie->clkdm)
+               clkdm_deny_idle(cookie->clkdm);
+}
+
+static void ti_sysc_clkdm_allow_idle(struct device *dev,
+                                    const struct ti_sysc_cookie *cookie)
+{
+       if (cookie->clkdm)
+               clkdm_allow_idle(cookie->clkdm);
+}
+
 static int ti_sysc_enable_module(struct device *dev,
                                 const struct ti_sysc_cookie *cookie)
 {
@@ -491,6 +548,9 @@ static struct of_dev_auxdata omap_auxdata_lookup[];
 
 static struct ti_sysc_platform_data ti_sysc_pdata = {
        .auxdata = omap_auxdata_lookup,
+       .init_clockdomain = ti_sysc_clkdm_init,
+       .clkdm_deny_idle = ti_sysc_clkdm_deny_idle,
+       .clkdm_allow_idle = ti_sysc_clkdm_allow_idle,
        .init_module = omap_hwmod_init_module,
        .enable_module = ti_sysc_enable_module,
        .idle_module = ti_sysc_idle_module,
index 47a8164..68fee33 100644 (file)
@@ -24,6 +24,7 @@
 #define BIT(nr)                        (1 << (nr))
 
        .arm
+       .arch armv7-a
        .align 3
 
 ENTRY(am33xx_do_wfi)
index 75ea472..ac1324c 100644 (file)
@@ -83,6 +83,8 @@ ENDPROC(enable_omap3630_toggle_l2_on_restore)
  *
  * r0 = physical address of the parameters
  */
+       .arch armv7-a
+       .arch_extension sec
 ENTRY(save_secure_ram_context)
        stmfd   sp!, {r4 - r11, lr}     @ save registers on stack
        mov     r3, r0                  @ physical address of parameters
index 0c10314..c1f4e48 100644 (file)
@@ -56,6 +56,8 @@
 #define RTC_PMIC_EXT_WAKEUP_EN                         BIT(0)
 
        .arm
+       .arch armv7-a
+       .arch_extension sec
        .align 3
 
 ENTRY(am43xx_do_wfi)
index 934033a..f60f6a9 100644 (file)
 #include "omap44xx.h"
 #include "omap4-sar-layout.h"
 
+       .arch armv7-a
+
 #if defined(CONFIG_SMP) && defined(CONFIG_PM)
 
+       .arch_extension sec
 .macro DO_SMC
        dsb
        smc     #0
index 72b5c3d..a3af4a2 100644 (file)
@@ -47,7 +47,3 @@
 #define LUBBOCK_LAST_IRQ       LUBBOCK_IRQ(6)
 
 #define LUBBOCK_SA1111_IRQ_BASE        (LUBBOCK_NR_IRQS + 32)
-
-#ifndef __ASSEMBLY__
-extern void lubbock_set_misc_wr(unsigned int mask, unsigned int set);
-#endif
index a3ecccc..742d18a 100644 (file)
@@ -116,12 +116,11 @@ void lubbock_set_hexled(uint32_t value)
 
 static struct gpio_chip *lubbock_misc_wr_gc;
 
-void lubbock_set_misc_wr(unsigned int mask, unsigned int set)
+static void lubbock_set_misc_wr(unsigned int mask, unsigned int set)
 {
        unsigned long m = mask, v = set;
        lubbock_misc_wr_gc->set_multiple(lubbock_misc_wr_gc, &m, &v);
 }
-EXPORT_SYMBOL(lubbock_set_misc_wr);
 
 static int lubbock_udc_is_connected(void)
 {
index 909fffe..649e0a5 100644 (file)
@@ -269,19 +269,25 @@ static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus)
        sram_base_addr = of_iomap(node, 0);
        if (!sram_base_addr) {
                pr_err("%s: could not map sram registers\n", __func__);
+               of_node_put(node);
                return;
        }
 
-       if (has_pmu && rockchip_smp_prepare_pmu())
+       if (has_pmu && rockchip_smp_prepare_pmu()) {
+               of_node_put(node);
                return;
+       }
 
        if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) {
-               if (rockchip_smp_prepare_sram(node))
+               if (rockchip_smp_prepare_sram(node)) {
+                       of_node_put(node);
                        return;
+               }
 
                /* enable the SCU power domain */
                pmu_set_power_domain(PMU_PWRDN_SCU, true);
 
+               of_node_put(node);
                node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
                if (!node) {
                        pr_err("%s: missing scu\n", __func__);
@@ -291,6 +297,7 @@ static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus)
                scu_base_addr = of_iomap(node, 0);
                if (!scu_base_addr) {
                        pr_err("%s: could not map scu registers\n", __func__);
+                       of_node_put(node);
                        return;
                }
 
@@ -309,6 +316,7 @@ static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus)
                asm ("mrc p15, 1, %0, c9, c0, 2\n" : "=r" (l2ctlr));
                ncores = ((l2ctlr >> 24) & 0x3) + 1;
        }
+       of_node_put(node);
 
        /* Make sure that all cores except the first are really off */
        for (i = 1; i < ncores; i++)
index 744b5b3..87389d9 100644 (file)
@@ -257,12 +257,14 @@ static int __init rk3288_suspend_init(struct device_node *np)
        rk3288_bootram_base = of_iomap(sram_np, 0);
        if (!rk3288_bootram_base) {
                pr_err("%s: could not map bootram base\n", __func__);
+               of_node_put(sram_np);
                return -ENOMEM;
        }
 
        ret = of_address_to_resource(sram_np, 0, &res);
        if (ret) {
                pr_err("%s: could not get bootram phy addr\n", __func__);
+               of_node_put(sram_np);
                return ret;
        }
        rk3288_bootram_phy = res.start;
index 056ef54..90a645a 100644 (file)
@@ -5,4 +5,5 @@
 
 # Object file lists.
 
-obj-y                  := dma.o ecard.o fiq.o irq.o riscpc.o time.o
+obj-y  :=dma.o ecard.o ecard-loader.o fiq.o floppydma.o io-acorn.o irq.o \
+         riscpc.o time.o
index 488d5c3..50e0f97 100644 (file)
 
 struct iomd_dma {
        struct dma_struct       dma;
-       unsigned int            state;
-       unsigned long           base;           /* Controller base address */
+       void __iomem            *base;          /* Controller base address */
        int                     irq;            /* Controller IRQ */
-       struct scatterlist      cur_sg;         /* Current controller buffer */
+       unsigned int            state;
+       dma_addr_t              cur_addr;
+       unsigned int            cur_len;
        dma_addr_t              dma_addr;
        unsigned int            dma_len;
 };
@@ -50,13 +51,13 @@ typedef enum {
 #define CR     (IOMD_IO0CR - IOMD_IO0CURA)
 #define ST     (IOMD_IO0ST - IOMD_IO0CURA)
 
-static void iomd_get_next_sg(struct scatterlist *sg, struct iomd_dma *idma)
+static void iomd_get_next_sg(struct iomd_dma *idma)
 {
        unsigned long end, offset, flags = 0;
 
        if (idma->dma.sg) {
-               sg->dma_address = idma->dma_addr;
-               offset = sg->dma_address & ~PAGE_MASK;
+               idma->cur_addr = idma->dma_addr;
+               offset = idma->cur_addr & ~PAGE_MASK;
 
                end = offset + idma->dma_len;
 
@@ -66,7 +67,7 @@ static void iomd_get_next_sg(struct scatterlist *sg, struct iomd_dma *idma)
                if (offset + TRANSFER_SIZE >= end)
                        flags |= DMA_END_L;
 
-               sg->length = end - TRANSFER_SIZE;
+               idma->cur_len = end - TRANSFER_SIZE;
 
                idma->dma_len -= end - offset;
                idma->dma_addr += end - offset;
@@ -84,52 +85,49 @@ static void iomd_get_next_sg(struct scatterlist *sg, struct iomd_dma *idma)
                }
        } else {
                flags = DMA_END_S | DMA_END_L;
-               sg->dma_address = 0;
-               sg->length = 0;
+               idma->cur_addr = 0;
+               idma->cur_len = 0;
        }
 
-       sg->length |= flags;
+       idma->cur_len |= flags;
 }
 
 static irqreturn_t iomd_dma_handle(int irq, void *dev_id)
 {
        struct iomd_dma *idma = dev_id;
-       unsigned long base = idma->base;
+       void __iomem *base = idma->base;
+       unsigned int state = idma->state;
+       unsigned int status, cur, end;
 
        do {
-               unsigned int status;
-
-               status = iomd_readb(base + ST);
+               status = readb(base + ST);
                if (!(status & DMA_ST_INT))
-                       return IRQ_HANDLED;
-
-               if ((idma->state ^ status) & DMA_ST_AB)
-                       iomd_get_next_sg(&idma->cur_sg, idma);
-
-               switch (status & (DMA_ST_OFL | DMA_ST_AB)) {
-               case DMA_ST_OFL:                        /* OIA */
-               case DMA_ST_AB:                         /* .IB */
-                       iomd_writel(idma->cur_sg.dma_address, base + CURA);
-                       iomd_writel(idma->cur_sg.length, base + ENDA);
-                       idma->state = DMA_ST_AB;
-                       break;
-
-               case DMA_ST_OFL | DMA_ST_AB:            /* OIB */
-               case 0:                                 /* .IA */
-                       iomd_writel(idma->cur_sg.dma_address, base + CURB);
-                       iomd_writel(idma->cur_sg.length, base + ENDB);
-                       idma->state = 0;
-                       break;
+                       goto out;
+
+               if ((state ^ status) & DMA_ST_AB)
+                       iomd_get_next_sg(idma);
+
+               // This efficiently implements state = OFL != AB ? AB : 0
+               state = ((status >> 2) ^ status) & DMA_ST_AB;
+               if (state) {
+                       cur = CURA;
+                       end = ENDA;
+               } else {
+                       cur = CURB;
+                       end = ENDB;
                }
+               writel(idma->cur_addr, base + cur);
+               writel(idma->cur_len, base + end);
 
                if (status & DMA_ST_OFL &&
-                   idma->cur_sg.length == (DMA_END_S|DMA_END_L))
+                   idma->cur_len == (DMA_END_S|DMA_END_L))
                        break;
        } while (1);
 
-       idma->state = ~DMA_ST_AB;
-       disable_irq(irq);
-
+       state = ~DMA_ST_AB;
+       disable_irq_nosync(irq);
+out:
+       idma->state = state;
        return IRQ_HANDLED;
 }
 
@@ -157,7 +155,7 @@ static struct device isa_dma_dev = {
 static void iomd_enable_dma(unsigned int chan, dma_t *dma)
 {
        struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma);
-       unsigned long dma_base = idma->base;
+       void __iomem *base = idma->base;
        unsigned int ctrl = TRANSFER_SIZE | DMA_CR_E;
 
        if (idma->dma.invalid) {
@@ -177,27 +175,30 @@ static void iomd_enable_dma(unsigned int chan, dma_t *dma)
                                DMA_FROM_DEVICE : DMA_TO_DEVICE);
                }
 
-               iomd_writeb(DMA_CR_C, dma_base + CR);
+               idma->dma_addr = idma->dma.sg->dma_address;
+               idma->dma_len = idma->dma.sg->length;
+
+               writeb(DMA_CR_C, base + CR);
                idma->state = DMA_ST_AB;
        }
 
        if (idma->dma.dma_mode == DMA_MODE_READ)
                ctrl |= DMA_CR_D;
 
-       iomd_writeb(ctrl, dma_base + CR);
+       writeb(ctrl, base + CR);
        enable_irq(idma->irq);
 }
 
 static void iomd_disable_dma(unsigned int chan, dma_t *dma)
 {
        struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma);
-       unsigned long dma_base = idma->base;
+       void __iomem *base = idma->base;
        unsigned long flags;
 
        local_irq_save(flags);
        if (idma->state != ~DMA_ST_AB)
                disable_irq(idma->irq);
-       iomd_writeb(0, dma_base + CR);
+       writeb(0, base + CR);
        local_irq_restore(flags);
 }
 
@@ -360,17 +361,17 @@ static int __init rpc_dma_init(void)
         */
        iomd_writeb(DMA_EXT_IO3|DMA_EXT_IO2, IOMD_DMAEXT);
 
-       iomd_dma[DMA_0].base    = IOMD_IO0CURA;
+       iomd_dma[DMA_0].base    = IOMD_BASE + IOMD_IO0CURA;
        iomd_dma[DMA_0].irq     = IRQ_DMA0;
-       iomd_dma[DMA_1].base    = IOMD_IO1CURA;
+       iomd_dma[DMA_1].base    = IOMD_BASE + IOMD_IO1CURA;
        iomd_dma[DMA_1].irq     = IRQ_DMA1;
-       iomd_dma[DMA_2].base    = IOMD_IO2CURA;
+       iomd_dma[DMA_2].base    = IOMD_BASE + IOMD_IO2CURA;
        iomd_dma[DMA_2].irq     = IRQ_DMA2;
-       iomd_dma[DMA_3].base    = IOMD_IO3CURA;
+       iomd_dma[DMA_3].base    = IOMD_BASE + IOMD_IO3CURA;
        iomd_dma[DMA_3].irq     = IRQ_DMA3;
-       iomd_dma[DMA_S0].base   = IOMD_SD0CURA;
+       iomd_dma[DMA_S0].base   = IOMD_BASE + IOMD_SD0CURA;
        iomd_dma[DMA_S0].irq    = IRQ_DMAS0;
-       iomd_dma[DMA_S1].base   = IOMD_SD1CURA;
+       iomd_dma[DMA_S1].base   = IOMD_BASE + IOMD_SD1CURA;
        iomd_dma[DMA_S1].irq    = IRQ_DMAS1;
 
        for (i = DMA_0; i <= DMA_S1; i++) {
index cf0593b..75cfad2 100644 (file)
@@ -67,17 +67,21 @@ struct expcard_blacklist {
        unsigned short   manufacturer;
        unsigned short   product;
        const char      *type;
+       void (*init)(ecard_t *ec);
 };
 
 static ecard_t *cards;
 static ecard_t *slot_to_expcard[MAX_ECARDS];
 static unsigned int ectcr;
 
+static void atomwide_3p_quirk(ecard_t *ec);
+
 /* List of descriptions of cards which don't have an extended
  * identification, or chunk directories containing a description.
  */
 static struct expcard_blacklist __initdata blacklist[] = {
-       { MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1" }
+       { MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1" },
+       { MANU_ATOMWIDE, PROD_ATOMWIDE_3PSERIAL, NULL, atomwide_3p_quirk },
 };
 
 asmlinkage extern int
@@ -493,18 +497,21 @@ static void ecard_dump_irq_state(void)
        printk("Expansion card IRQ state:\n");
 
        for (ec = cards; ec; ec = ec->next) {
+               const char *claimed;
+
                if (ec->slot_no == 8)
                        continue;
 
-               printk("  %d: %sclaimed, ",
-                      ec->slot_no, ec->claimed ? "" : "not ");
+               claimed = ec->claimed ? "" : "not ";
 
                if (ec->ops && ec->ops->irqpending &&
                    ec->ops != &ecard_default_ops)
-                       printk("irq %spending\n",
+                       printk("  %d: %sclaimed irq %spending\n",
+                              ec->slot_no, claimed,
                               ec->ops->irqpending(ec) ? "" : "not ");
                else
-                       printk("irqaddr %p, mask = %02X, status = %02X\n",
+                       printk("  %d: %sclaimed irqaddr %p, mask = %02X, status = %02X\n",
+                              ec->slot_no, claimed,
                               ec->irqaddr, ec->irqmask, readb(ec->irqaddr));
        }
 }
@@ -865,6 +872,16 @@ void __iomem *ecardm_iomap(struct expansion_card *ec, unsigned int res,
 }
 EXPORT_SYMBOL(ecardm_iomap);
 
+static void atomwide_3p_quirk(ecard_t *ec)
+{
+       void __iomem *addr = __ecard_address(ec, ECARD_IOC, ECARD_SYNC);
+       unsigned int i;
+
+       /* Disable interrupts on each port */
+       for (i = 0x2000; i <= 0x2800; i += 0x0400)
+               writeb(0, addr + i + 4);        
+}
+
 /*
  * Probe for an expansion card.
  *
@@ -921,7 +938,10 @@ static int __init ecard_probe(int slot, unsigned irq, card_type_t type)
        for (i = 0; i < ARRAY_SIZE(blacklist); i++)
                if (blacklist[i].manufacturer == ec->cid.manufacturer &&
                    blacklist[i].product == ec->cid.product) {
-                       ec->card_desc = blacklist[i].type;
+                       if (blacklist[i].type)
+                               ec->card_desc = blacklist[i].type;
+                       if (blacklist[i].init)
+                               blacklist[i].init(ec);
                        break;
                }
 
index a023b5f..1fbe7eb 100644 (file)
@@ -115,29 +115,22 @@ static void arch_decomp_setup(void)
        struct tag *t = (struct tag *)params;
        unsigned int nr_pages = 0, page_size = PAGE_SIZE;
 
-       if (t->hdr.tag == ATAG_CORE)
-       {
-               for (; t->hdr.size; t = tag_next(t))
-               {
-                       if (t->hdr.tag == ATAG_VIDEOTEXT)
-                       {
+       if (t->hdr.tag == ATAG_CORE) {
+               for (; t->hdr.size; t = tag_next(t)) {
+                       if (t->hdr.tag == ATAG_VIDEOTEXT) {
                                video_num_rows = t->u.videotext.video_lines;
                                video_num_cols = t->u.videotext.video_cols;
-                               bytes_per_char_h = t->u.videotext.video_points;
-                               bytes_per_char_v = t->u.videotext.video_points;
                                video_x = t->u.videotext.x;
                                video_y = t->u.videotext.y;
-                       }
-
-                       if (t->hdr.tag == ATAG_MEM)
-                       {
+                       } else if (t->hdr.tag == ATAG_VIDEOLFB) {
+                               bytes_per_char_h = t->u.videolfb.lfb_depth;
+                               bytes_per_char_v = 8;
+                       } else if (t->hdr.tag == ATAG_MEM) {
                                page_size = PAGE_SIZE;
                                nr_pages += (t->u.mem.size / PAGE_SIZE);
                        }
                }
-       }
-       else
-       {
+       } else {
                nr_pages = params->nr_pages;
                page_size = params->page_size;
                video_num_rows = params->video_num_rows;
index b8a61cb..803aeb1 100644 (file)
 #include <asm/irq.h>
 #include <asm/fiq.h>
 
-static void iomd_ack_irq_a(struct irq_data *d)
-{
-       unsigned int val, mask;
-
-       mask = 1 << d->irq;
-       val = iomd_readb(IOMD_IRQMASKA);
-       iomd_writeb(val & ~mask, IOMD_IRQMASKA);
-       iomd_writeb(mask, IOMD_IRQCLRA);
-}
-
-static void iomd_mask_irq_a(struct irq_data *d)
-{
-       unsigned int val, mask;
+// These are offsets from the stat register for each IRQ bank
+#define STAT   0x00
+#define REQ    0x04
+#define CLR    0x04
+#define MASK   0x08
 
-       mask = 1 << d->irq;
-       val = iomd_readb(IOMD_IRQMASKA);
-       iomd_writeb(val & ~mask, IOMD_IRQMASKA);
-}
-
-static void iomd_unmask_irq_a(struct irq_data *d)
+static void __iomem *iomd_get_base(struct irq_data *d)
 {
-       unsigned int val, mask;
+       void *cd = irq_data_get_irq_chip_data(d);
 
-       mask = 1 << d->irq;
-       val = iomd_readb(IOMD_IRQMASKA);
-       iomd_writeb(val | mask, IOMD_IRQMASKA);
+       return (void __iomem *)(unsigned long)cd;
 }
 
-static struct irq_chip iomd_a_chip = {
-       .irq_ack        = iomd_ack_irq_a,
-       .irq_mask       = iomd_mask_irq_a,
-       .irq_unmask     = iomd_unmask_irq_a,
-};
-
-static void iomd_mask_irq_b(struct irq_data *d)
+static void iomd_set_base_mask(unsigned int irq, void __iomem *base, u32 mask)
 {
-       unsigned int val, mask;
+       struct irq_data *d = irq_get_irq_data(irq);
 
-       mask = 1 << (d->irq & 7);
-       val = iomd_readb(IOMD_IRQMASKB);
-       iomd_writeb(val & ~mask, IOMD_IRQMASKB);
+       d->mask = mask;
+       irq_set_chip_data(irq, (void *)(unsigned long)base);
 }
 
-static void iomd_unmask_irq_b(struct irq_data *d)
+static void iomd_irq_mask_ack(struct irq_data *d)
 {
-       unsigned int val, mask;
+       void __iomem *base = iomd_get_base(d);
+       unsigned int val, mask = d->mask;
 
-       mask = 1 << (d->irq & 7);
-       val = iomd_readb(IOMD_IRQMASKB);
-       iomd_writeb(val | mask, IOMD_IRQMASKB);
+       val = readb(base + MASK);
+       writeb(val & ~mask, base + MASK);
+       writeb(mask, base + CLR);
 }
 
-static struct irq_chip iomd_b_chip = {
-       .irq_ack        = iomd_mask_irq_b,
-       .irq_mask       = iomd_mask_irq_b,
-       .irq_unmask     = iomd_unmask_irq_b,
-};
-
-static void iomd_mask_irq_dma(struct irq_data *d)
+static void iomd_irq_mask(struct irq_data *d)
 {
-       unsigned int val, mask;
+       void __iomem *base = iomd_get_base(d);
+       unsigned int val, mask = d->mask;
 
-       mask = 1 << (d->irq & 7);
-       val = iomd_readb(IOMD_DMAMASK);
-       iomd_writeb(val & ~mask, IOMD_DMAMASK);
+       val = readb(base + MASK);
+       writeb(val & ~mask, base + MASK);
 }
 
-static void iomd_unmask_irq_dma(struct irq_data *d)
+static void iomd_irq_unmask(struct irq_data *d)
 {
-       unsigned int val, mask;
+       void __iomem *base = iomd_get_base(d);
+       unsigned int val, mask = d->mask;
 
-       mask = 1 << (d->irq & 7);
-       val = iomd_readb(IOMD_DMAMASK);
-       iomd_writeb(val | mask, IOMD_DMAMASK);
+       val = readb(base + MASK);
+       writeb(val | mask, base + MASK);
 }
 
-static struct irq_chip iomd_dma_chip = {
-       .irq_ack        = iomd_mask_irq_dma,
-       .irq_mask       = iomd_mask_irq_dma,
-       .irq_unmask     = iomd_unmask_irq_dma,
+static struct irq_chip iomd_chip_clr = {
+       .irq_mask_ack   = iomd_irq_mask_ack,
+       .irq_mask       = iomd_irq_mask,
+       .irq_unmask     = iomd_irq_unmask,
 };
 
-static void iomd_mask_irq_fiq(struct irq_data *d)
-{
-       unsigned int val, mask;
-
-       mask = 1 << (d->irq & 7);
-       val = iomd_readb(IOMD_FIQMASK);
-       iomd_writeb(val & ~mask, IOMD_FIQMASK);
-}
-
-static void iomd_unmask_irq_fiq(struct irq_data *d)
-{
-       unsigned int val, mask;
-
-       mask = 1 << (d->irq & 7);
-       val = iomd_readb(IOMD_FIQMASK);
-       iomd_writeb(val | mask, IOMD_FIQMASK);
-}
-
-static struct irq_chip iomd_fiq_chip = {
-       .irq_ack        = iomd_mask_irq_fiq,
-       .irq_mask       = iomd_mask_irq_fiq,
-       .irq_unmask     = iomd_unmask_irq_fiq,
+static struct irq_chip iomd_chip_noclr = {
+       .irq_mask       = iomd_irq_mask,
+       .irq_unmask     = iomd_irq_unmask,
 };
 
 extern unsigned char rpc_default_fiq_start, rpc_default_fiq_end;
 
 void __init rpc_init_irq(void)
 {
-       unsigned int irq, clr, set = 0;
+       unsigned int irq, clr, set;
 
        iomd_writeb(0, IOMD_IRQMASKA);
        iomd_writeb(0, IOMD_IRQMASKB);
@@ -130,6 +84,7 @@ void __init rpc_init_irq(void)
 
        for (irq = 0; irq < NR_IRQS; irq++) {
                clr = IRQ_NOREQUEST;
+               set = 0;
 
                if (irq <= 6 || (irq >= 9 && irq <= 15))
                        clr |= IRQ_NOPROBE;
@@ -140,30 +95,37 @@ void __init rpc_init_irq(void)
 
                switch (irq) {
                case 0 ... 7:
-                       irq_set_chip_and_handler(irq, &iomd_a_chip,
+                       irq_set_chip_and_handler(irq, &iomd_chip_clr,
                                                 handle_level_irq);
                        irq_modify_status(irq, clr, set);
+                       iomd_set_base_mask(irq, IOMD_BASE + IOMD_IRQSTATA,
+                                          BIT(irq));
                        break;
 
                case 8 ... 15:
-                       irq_set_chip_and_handler(irq, &iomd_b_chip,
+                       irq_set_chip_and_handler(irq, &iomd_chip_noclr,
                                                 handle_level_irq);
                        irq_modify_status(irq, clr, set);
+                       iomd_set_base_mask(irq, IOMD_BASE + IOMD_IRQSTATB,
+                                          BIT(irq - 8));
                        break;
 
                case 16 ... 21:
-                       irq_set_chip_and_handler(irq, &iomd_dma_chip,
+                       irq_set_chip_and_handler(irq, &iomd_chip_noclr,
                                                 handle_level_irq);
                        irq_modify_status(irq, clr, set);
+                       iomd_set_base_mask(irq, IOMD_BASE + IOMD_DMASTAT,
+                                          BIT(irq - 16));
                        break;
 
                case 64 ... 71:
-                       irq_set_chip(irq, &iomd_fiq_chip);
+                       irq_set_chip(irq, &iomd_chip_noclr);
                        irq_modify_status(irq, clr, set);
+                       iomd_set_base_mask(irq, IOMD_BASE + IOMD_FIQSTAT,
+                                          BIT(irq - 64));
                        break;
                }
        }
 
        init_FIQ(FIQ_START);
 }
-
index e97f93a..1d75015 100644 (file)
@@ -10,7 +10,7 @@
  *   04-Dec-1997       RMK     Updated for new arch/arm/time.c
  *   13=Jun-2004       DS      Moved to arch/arm/common b/c shared w/CLPS7500
  */
-#include <linux/timex.h>
+#include <linux/clocksource.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #define RPC_CLOCK_FREQ 2000000
 #define RPC_LATCH DIV_ROUND_CLOSEST(RPC_CLOCK_FREQ, HZ)
 
-static u32 ioc_timer_gettimeoffset(void)
+static u32 ioc_time;
+
+static u64 ioc_timer_read(struct clocksource *cs)
 {
        unsigned int count1, count2, status;
-       long offset;
+       unsigned long flags;
+       u32 ticks;
 
+       local_irq_save(flags);
        ioc_writeb (0, IOC_T0LATCH);
        barrier ();
        count1 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
@@ -38,27 +42,34 @@ static u32 ioc_timer_gettimeoffset(void)
        ioc_writeb (0, IOC_T0LATCH);
        barrier ();
        count2 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
+       ticks = ioc_time + RPC_LATCH - count2;
+       local_irq_restore(flags);
 
-       offset = count2;
        if (count2 < count1) {
                /*
-                * We have not had an interrupt between reading count1
-                * and count2.
+                * The timer has not reloaded between reading count1 and
+                * count2, check whether an interrupt was actually pending.
                 */
                if (status & (1 << 5))
-                       offset -= RPC_LATCH;
+                       ticks += RPC_LATCH;
        } else if (count2 > count1) {
                /*
-                * We have just had another interrupt between reading
-                * count1 and count2.
+                * The timer has reloaded, so count2 indicates the new
+                * count since the wrap.  The interrupt would not have
+                * been processed, so add the missed ticks.
                 */
-               offset -= RPC_LATCH;
+               ticks += RPC_LATCH;
        }
 
-       offset = (RPC_LATCH - offset) * (tick_nsec / 1000);
-       return DIV_ROUND_CLOSEST(offset, RPC_LATCH) * 1000;
+       return ticks;
 }
 
+static struct clocksource ioctime_clocksource = {
+       .read = ioc_timer_read,
+       .mask = CLOCKSOURCE_MASK(32),
+       .rating = 100,
+};
+
 void __init ioctime_init(void)
 {
        ioc_writeb(RPC_LATCH & 255, IOC_T0LTCHL);
@@ -69,6 +80,7 @@ void __init ioctime_init(void)
 static irqreturn_t
 ioc_timer_interrupt(int irq, void *dev_id)
 {
+       ioc_time += RPC_LATCH;
        timer_tick();
        return IRQ_HANDLED;
 }
@@ -83,7 +95,7 @@ static struct irqaction ioc_timer_irq = {
  */
 void __init ioc_timer_init(void)
 {
-       arch_gettimeoffset = ioc_timer_gettimeoffset;
+       WARN_ON(clocksource_register_hz(&ioctime_clocksource, RPC_CLOCK_FREQ));
        ioctime_init();
        setup_irq(IRQ_TIMER0, &ioc_timer_irq);
 }
index adcb906..c64988c 100644 (file)
@@ -5,7 +5,7 @@
 //
 // S3C24XX Power Manager (Suspend-To-RAM) support
 //
-// See Documentation/arm/Samsung-S3C24XX/Suspend.txt for more information
+// See Documentation/arm/samsung-s3c24xx/suspend.rst for more information
 //
 // Parts based on arch/arm/mach-pxa/pm.c
 //
index dd8d13f..d96a101 100644 (file)
@@ -519,6 +519,29 @@ static const struct gpio_keys_platform_data assabet_keys_pdata = {
        .rep = 0,
 };
 
+static struct gpiod_lookup_table assabet_uart1_gpio_table = {
+       .dev_id = "sa11x0-uart.1",
+       .table = {
+               GPIO_LOOKUP("assabet", 16, "dtr", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("assabet", 17, "rts", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("assabet", 25, "dcd", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("assabet", 26, "cts", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("assabet", 27, "dsr", GPIO_ACTIVE_LOW),
+               { },
+       },
+};
+
+static struct gpiod_lookup_table assabet_uart3_gpio_table = {
+       .dev_id = "sa11x0-uart.3",
+       .table = {
+               GPIO_LOOKUP("assabet", 28, "cts", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("assabet", 29, "dsr", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("assabet", 30, "dcd", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("assabet", 31, "rng", GPIO_ACTIVE_LOW),
+               { },
+       },
+};
+
 static void __init assabet_init(void)
 {
        /*
@@ -565,7 +588,10 @@ static void __init assabet_init(void)
                        neponset_resources, ARRAY_SIZE(neponset_resources));
 #endif
        } else {
+               gpiod_add_lookup_table(&assabet_uart1_gpio_table);
+               gpiod_add_lookup_table(&assabet_uart3_gpio_table);
                gpiod_add_lookup_table(&assabet_cf_vcc_gpio_table);
+
                sa11x0_register_fixed_regulator(0, &assabet_cf_vcc_pdata,
                                        assabet_cf_vcc_consumers,
                                        ARRAY_SIZE(assabet_cf_vcc_consumers),
@@ -655,74 +681,13 @@ static void assabet_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
 {
        if (port->mapbase == _Ser1UTCR0) {
                if (state)
-                       ASSABET_BCR_clear(ASSABET_BCR_RS232EN |
-                                         ASSABET_BCR_COM_RTS |
-                                         ASSABET_BCR_COM_DTR);
-               else
-                       ASSABET_BCR_set(ASSABET_BCR_RS232EN |
-                                       ASSABET_BCR_COM_RTS |
-                                       ASSABET_BCR_COM_DTR);
-       }
-}
-
-/*
- * Assabet uses COM_RTS and COM_DTR for both UART1 (com port)
- * and UART3 (radio module).  We only handle them for UART1 here.
- */
-static void assabet_set_mctrl(struct uart_port *port, u_int mctrl)
-{
-       if (port->mapbase == _Ser1UTCR0) {
-               u_int set = 0, clear = 0;
-
-               if (mctrl & TIOCM_RTS)
-                       clear |= ASSABET_BCR_COM_RTS;
+                       ASSABET_BCR_clear(ASSABET_BCR_RS232EN);
                else
-                       set |= ASSABET_BCR_COM_RTS;
-
-               if (mctrl & TIOCM_DTR)
-                       clear |= ASSABET_BCR_COM_DTR;
-               else
-                       set |= ASSABET_BCR_COM_DTR;
-
-               ASSABET_BCR_clear(clear);
-               ASSABET_BCR_set(set);
-       }
-}
-
-static u_int assabet_get_mctrl(struct uart_port *port)
-{
-       u_int ret = 0;
-       u_int bsr = ASSABET_BSR;
-
-       /* need 2 reads to read current value */
-       bsr = ASSABET_BSR;
-
-       if (port->mapbase == _Ser1UTCR0) {
-               if (bsr & ASSABET_BSR_COM_DCD)
-                       ret |= TIOCM_CD;
-               if (bsr & ASSABET_BSR_COM_CTS)
-                       ret |= TIOCM_CTS;
-               if (bsr & ASSABET_BSR_COM_DSR)
-                       ret |= TIOCM_DSR;
-       } else if (port->mapbase == _Ser3UTCR0) {
-               if (bsr & ASSABET_BSR_RAD_DCD)
-                       ret |= TIOCM_CD;
-               if (bsr & ASSABET_BSR_RAD_CTS)
-                       ret |= TIOCM_CTS;
-               if (bsr & ASSABET_BSR_RAD_DSR)
-                       ret |= TIOCM_DSR;
-               if (bsr & ASSABET_BSR_RAD_RI)
-                       ret |= TIOCM_RI;
-       } else {
-               ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
+                       ASSABET_BCR_set(ASSABET_BCR_RS232EN);
        }
-
-       return ret;
 }
 
 static struct sa1100_port_fns assabet_port_fns __initdata = {
-       .set_mctrl      = assabet_set_mctrl,
-       .get_mctrl      = assabet_get_mctrl,
        .pm             = assabet_uart_pm,
 };
 
index bc0e0e2..de79f35 100644 (file)
@@ -311,8 +311,6 @@ badge4_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
 }
 
 static struct sa1100_port_fns badge4_port_fns __initdata = {
-       //.get_mctrl    = badge4_get_mctrl,
-       //.set_mctrl    = badge4_set_mctrl,
        .pm             = badge4_uart_pm,
 };
 
index 6199e87..e869192 100644 (file)
 /*
  *  linux/arch/arm/mach-sa1100/clock.c
  */
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/list.h>
 #include <linux/errno.h>
 #include <linux/err.h>
-#include <linux/string.h>
 #include <linux/clk.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/io.h>
 #include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
 
 #include <mach/hardware.h>
 #include <mach/generic.h>
 
-struct clkops {
-       void                    (*enable)(struct clk *);
-       void                    (*disable)(struct clk *);
-       unsigned long           (*get_rate)(struct clk *);
+static const char * const clk_tucr_parents[] = {
+       "clk32768", "clk3686400",
 };
 
-struct clk {
-       const struct clkops     *ops;
-       unsigned int            enabled;
-};
-
-#define DEFINE_CLK(_name, _ops)                                \
-struct clk clk_##_name = {                             \
-               .ops    = _ops,                         \
-       }
-
-static DEFINE_SPINLOCK(clocks_lock);
-
-/* Dummy clk routine to build generic kernel parts that may be using them */
-long clk_round_rate(struct clk *clk, unsigned long rate)
-{
-       return clk_get_rate(clk);
-}
-EXPORT_SYMBOL(clk_round_rate);
-
-int clk_set_rate(struct clk *clk, unsigned long rate)
-{
-       return 0;
-}
-EXPORT_SYMBOL(clk_set_rate);
-
-int clk_set_parent(struct clk *clk, struct clk *parent)
-{
-       return 0;
-}
-EXPORT_SYMBOL(clk_set_parent);
+static DEFINE_SPINLOCK(tucr_lock);
 
-struct clk *clk_get_parent(struct clk *clk)
+static int clk_gpio27_enable(struct clk_hw *hw)
 {
-       return NULL;
-}
-EXPORT_SYMBOL(clk_get_parent);
+       unsigned long flags;
 
-static void clk_gpio27_enable(struct clk *clk)
-{
        /*
         * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
         * (SA-1110 Developer's Manual, section 9.1.2.1)
         */
+       local_irq_save(flags);
        GAFR |= GPIO_32_768kHz;
        GPDR |= GPIO_32_768kHz;
-       TUCR = TUCR_3_6864MHz;
+       local_irq_restore(flags);
+
+       return 0;
 }
 
-static void clk_gpio27_disable(struct clk *clk)
+static void clk_gpio27_disable(struct clk_hw *hw)
 {
-       TUCR = 0;
+       unsigned long flags;
+
+       local_irq_save(flags);
        GPDR &= ~GPIO_32_768kHz;
        GAFR &= ~GPIO_32_768kHz;
+       local_irq_restore(flags);
 }
 
-static void clk_cpu_enable(struct clk *clk)
-{
-}
+static const struct clk_ops clk_gpio27_ops = {
+       .enable = clk_gpio27_enable,
+       .disable = clk_gpio27_disable,
+};
 
-static void clk_cpu_disable(struct clk *clk)
-{
-}
+static const char * const clk_gpio27_parents[] = {
+       "tucr-mux",
+};
 
-static unsigned long clk_cpu_get_rate(struct clk *clk)
+static const struct clk_init_data clk_gpio27_init_data __initconst = {
+       .name = "gpio27",
+       .ops = &clk_gpio27_ops,
+       .parent_names = clk_gpio27_parents,
+       .num_parents = ARRAY_SIZE(clk_gpio27_parents),
+};
+
+/*
+ * Derived from the table 8-1 in the SA1110 manual, the MPLL appears to
+ * multiply its input rate by 4 x (4 + PPCR).  This calculation gives
+ * the exact rate.  The figures given in the table are the rates rounded
+ * to 100kHz.  Stick with sa11x0_getspeed() for the time being.
+ */
+static unsigned long clk_mpll_recalc_rate(struct clk_hw *hw,
+       unsigned long prate)
 {
        return sa11x0_getspeed(0) * 1000;
 }
 
-int clk_enable(struct clk *clk)
-{
-       unsigned long flags;
-
-       if (clk) {
-               spin_lock_irqsave(&clocks_lock, flags);
-               if (clk->enabled++ == 0)
-                       clk->ops->enable(clk);
-               spin_unlock_irqrestore(&clocks_lock, flags);
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL(clk_enable);
+static const struct clk_ops clk_mpll_ops = {
+       .recalc_rate = clk_mpll_recalc_rate,
+};
 
-void clk_disable(struct clk *clk)
-{
-       unsigned long flags;
+static const char * const clk_mpll_parents[] = {
+       "clk3686400",
+};
 
-       if (clk) {
-               WARN_ON(clk->enabled == 0);
-               spin_lock_irqsave(&clocks_lock, flags);
-               if (--clk->enabled == 0)
-                       clk->ops->disable(clk);
-               spin_unlock_irqrestore(&clocks_lock, flags);
-       }
-}
-EXPORT_SYMBOL(clk_disable);
+static const struct clk_init_data clk_mpll_init_data __initconst = {
+       .name = "mpll",
+       .ops = &clk_mpll_ops,
+       .parent_names = clk_mpll_parents,
+       .num_parents = ARRAY_SIZE(clk_mpll_parents),
+       .flags = CLK_GET_RATE_NOCACHE | CLK_IS_CRITICAL,
+};
 
-unsigned long clk_get_rate(struct clk *clk)
+int __init sa11xx_clk_init(void)
 {
-       if (clk && clk->ops && clk->ops->get_rate)
-               return clk->ops->get_rate(clk);
-
-       return 0;
-}
-EXPORT_SYMBOL(clk_get_rate);
+       struct clk_hw *hw;
+       int ret;
 
-const struct clkops clk_gpio27_ops = {
-       .enable         = clk_gpio27_enable,
-       .disable        = clk_gpio27_disable,
-};
+       hw = clk_hw_register_fixed_rate(NULL, "clk32768", NULL, 0, 32768);
+       if (IS_ERR(hw))
+               return PTR_ERR(hw);
 
-const struct clkops clk_cpu_ops = {
-       .enable         = clk_cpu_enable,
-       .disable        = clk_cpu_disable,
-       .get_rate       = clk_cpu_get_rate,
-};
+       clk_hw_register_clkdev(hw, NULL, "sa1100-rtc");
 
-static DEFINE_CLK(gpio27, &clk_gpio27_ops);
+       hw = clk_hw_register_fixed_rate(NULL, "clk3686400", NULL, 0, 3686400);
+       if (IS_ERR(hw))
+               return PTR_ERR(hw);
 
-static DEFINE_CLK(cpu, &clk_cpu_ops);
+       clk_hw_register_clkdev(hw, "OSTIMER0", NULL);
 
-static unsigned long clk_36864_get_rate(struct clk *clk)
-{
-       return 3686400;
-}
+       hw = kzalloc(sizeof(*hw), GFP_KERNEL);
+       if (!hw)
+               return -ENOMEM;
+       hw->init = &clk_mpll_init_data;
+       ret = clk_hw_register(NULL, hw);
+       if (ret) {
+               kfree(hw);
+               return ret;
+       }
 
-static struct clkops clk_36864_ops = {
-       .enable         = clk_cpu_enable,
-       .disable        = clk_cpu_disable,
-       .get_rate       = clk_36864_get_rate,
-};
+       clk_hw_register_clkdev(hw, NULL, "sa11x0-fb");
+       clk_hw_register_clkdev(hw, NULL, "sa11x0-pcmcia");
+       clk_hw_register_clkdev(hw, NULL, "sa11x0-pcmcia.0");
+       clk_hw_register_clkdev(hw, NULL, "sa11x0-pcmcia.1");
+       clk_hw_register_clkdev(hw, NULL, "1800");
+
+       hw = clk_hw_register_mux(NULL, "tucr-mux", clk_tucr_parents,
+                                ARRAY_SIZE(clk_tucr_parents), 0,
+                                (void __iomem *)&TUCR, FShft(TUCR_TSEL),
+                                FAlnMsk(TUCR_TSEL), 0, &tucr_lock);
+       clk_set_rate(hw->clk, 3686400);
+
+       hw = kzalloc(sizeof(*hw), GFP_KERNEL);
+       if (!hw)
+               return -ENOMEM;
+       hw->init = &clk_gpio27_init_data;
+       ret = clk_hw_register(NULL, hw);
+       if (ret) {
+               kfree(hw);
+               return ret;
+       }
 
-static DEFINE_CLK(36864, &clk_36864_ops);
-
-static struct clk_lookup sa11xx_clkregs[] = {
-       CLKDEV_INIT("sa1111.0", NULL, &clk_gpio27),
-       CLKDEV_INIT("sa1100-rtc", NULL, NULL),
-       CLKDEV_INIT("sa11x0-fb", NULL, &clk_cpu),
-       CLKDEV_INIT("sa11x0-pcmcia", NULL, &clk_cpu),
-       CLKDEV_INIT("sa11x0-pcmcia.0", NULL, &clk_cpu),
-       CLKDEV_INIT("sa11x0-pcmcia.1", NULL, &clk_cpu),
-       /* sa1111 names devices using internal offsets, PCMCIA is at 0x1800 */
-       CLKDEV_INIT("1800", NULL, &clk_cpu),
-       CLKDEV_INIT(NULL, "OSTIMER0", &clk_36864),
-};
+       clk_hw_register_clkdev(hw, NULL, "sa1111.0");
 
-int __init sa11xx_clk_init(void)
-{
-       clkdev_add_table(sa11xx_clkregs, ARRAY_SIZE(sa11xx_clkregs));
        return 0;
 }
index e93e3a1..d685f03 100644 (file)
@@ -83,57 +83,6 @@ static struct resource h3xxx_flash_resource =
 /*
  * H3xxx uart support
  */
-static struct gpio h3xxx_uart_gpio[] = {
-       { H3XXX_GPIO_COM_DCD,   GPIOF_IN,               "COM DCD" },
-       { H3XXX_GPIO_COM_CTS,   GPIOF_IN,               "COM CTS" },
-       { H3XXX_GPIO_COM_RTS,   GPIOF_OUT_INIT_LOW,     "COM RTS" },
-};
-
-static bool h3xxx_uart_request_gpios(void)
-{
-       static bool h3xxx_uart_gpio_ok;
-       int rc;
-
-       if (h3xxx_uart_gpio_ok)
-               return true;
-
-       rc = gpio_request_array(h3xxx_uart_gpio, ARRAY_SIZE(h3xxx_uart_gpio));
-       if (rc)
-               pr_err("h3xxx_uart_request_gpios: error %d\n", rc);
-       else
-               h3xxx_uart_gpio_ok = true;
-
-       return h3xxx_uart_gpio_ok;
-}
-
-static void h3xxx_uart_set_mctrl(struct uart_port *port, u_int mctrl)
-{
-       if (port->mapbase == _Ser3UTCR0) {
-               if (!h3xxx_uart_request_gpios())
-                       return;
-               gpio_set_value(H3XXX_GPIO_COM_RTS, !(mctrl & TIOCM_RTS));
-       }
-}
-
-static u_int h3xxx_uart_get_mctrl(struct uart_port *port)
-{
-       u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
-
-       if (port->mapbase == _Ser3UTCR0) {
-               if (!h3xxx_uart_request_gpios())
-                       return ret;
-               /*
-                * DCD and CTS bits are inverted in GPLR by RS232 transceiver
-                */
-               if (gpio_get_value(H3XXX_GPIO_COM_DCD))
-                       ret &= ~TIOCM_CD;
-               if (gpio_get_value(H3XXX_GPIO_COM_CTS))
-                       ret &= ~TIOCM_CTS;
-       }
-
-       return ret;
-}
-
 static void h3xxx_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
 {
        if (port->mapbase == _Ser3UTCR0) {
@@ -166,12 +115,20 @@ static int h3xxx_uart_set_wake(struct uart_port *port, u_int enable)
 }
 
 static struct sa1100_port_fns h3xxx_port_fns __initdata = {
-       .set_mctrl      = h3xxx_uart_set_mctrl,
-       .get_mctrl      = h3xxx_uart_get_mctrl,
        .pm             = h3xxx_uart_pm,
        .set_wake       = h3xxx_uart_set_wake,
 };
 
+static struct gpiod_lookup_table h3xxx_uart3_gpio_table = {
+       .dev_id = "sa11x0-uart.3",
+       .table = {
+               GPIO_LOOKUP("gpio", H3XXX_GPIO_COM_DCD, "dcd", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio", H3XXX_GPIO_COM_CTS, "cts", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio", H3XXX_GPIO_COM_RTS, "rts", GPIO_ACTIVE_LOW),
+               { },
+       },
+};
+
 /*
  * EGPIO
  */
@@ -279,6 +236,7 @@ static struct gpiod_lookup_table h3xxx_pcmcia_gpio_table = {
 void __init h3xxx_mach_init(void)
 {
        gpiod_add_lookup_table(&h3xxx_pcmcia_gpio_table);
+       gpiod_add_lookup_table(&h3xxx_uart3_gpio_table);
        sa1100_register_uart_fns(&h3xxx_port_fns);
        sa11x0_register_mtd(&h3xxx_flash_data, &h3xxx_flash_resource, 1);
        platform_add_devices(h3xxx_devices, ARRAY_SIZE(h3xxx_devices));
index 4f4c1bb..6d37d26 100644 (file)
@@ -45,8 +45,6 @@
 /* init funcs */
 static void __init hackkit_map_io(void);
 
-static u_int hackkit_get_mctrl(struct uart_port *port);
-static void hackkit_set_mctrl(struct uart_port *port, u_int mctrl);
 static void hackkit_uart_pm(struct uart_port *port, u_int state, u_int oldstate);
 
 /**********************************************************************
@@ -67,8 +65,6 @@ static struct map_desc hackkit_io_desc[] __initdata = {
 };
 
 static struct sa1100_port_fns hackkit_port_fns __initdata = {
-       .set_mctrl      = hackkit_set_mctrl,
-       .get_mctrl      = hackkit_get_mctrl,
        .pm             = hackkit_uart_pm,
 };
 
@@ -101,50 +97,6 @@ static void hackkit_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
        /* TODO: switch on/off uart in powersave mode */
 }
 
-/*
- * Note! this can be called from IRQ context.
- * FIXME: No modem ctrl lines yet.
- */
-static void hackkit_set_mctrl(struct uart_port *port, u_int mctrl)
-{
-#if 0
-       if (port->mapbase == _Ser1UTCR0) {
-               u_int set = 0, clear = 0;
-
-               if (mctrl & TIOCM_RTS)
-                       set |= PT_CTRL2_RS1_RTS;
-               else
-                       clear |= PT_CTRL2_RS1_RTS;
-
-               if (mctrl & TIOCM_DTR)
-                       set |= PT_CTRL2_RS1_DTR;
-               else
-                       clear |= PT_CTRL2_RS1_DTR;
-
-               PTCTRL2_clear(clear);
-               PTCTRL2_set(set);
-       }
-#endif
-}
-
-static u_int hackkit_get_mctrl(struct uart_port *port)
-{
-       u_int ret = 0;
-#if 0
-       u_int irqsr = PT_IRQSR;
-
-       /* need 2 reads to read current value */
-       irqsr = PT_IRQSR;
-
-       /* TODO: check IRQ source register for modem/com
-        status lines and set them correctly. */
-#endif
-
-       ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
-
-       return ret;
-}
-
 static struct mtd_partition hackkit_partitions[] = {
        {
                .name           = "BLOB",
index a671e4c..6876bc1 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/platform_data/sa11x0-serial.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 #include <linux/serial_core.h>
 #define IRR_SA1111     (1 << 2)
 
 #define NCR_NGPIO      7
-
-#define MDM_CTL0_RTS1  (1 << 0)
-#define MDM_CTL0_DTR1  (1 << 1)
-#define MDM_CTL0_RTS2  (1 << 2)
-#define MDM_CTL0_DTR2  (1 << 3)
 #define MDM_CTL0_NGPIO 4
-
-#define MDM_CTL1_CTS1  (1 << 0)
-#define MDM_CTL1_DSR1  (1 << 1)
-#define MDM_CTL1_DCD1  (1 << 2)
-#define MDM_CTL1_CTS2  (1 << 3)
-#define MDM_CTL1_DSR2  (1 << 4)
-#define MDM_CTL1_DCD2  (1 << 5)
 #define MDM_CTL1_NGPIO 6
-
-#define AUD_SEL_1341   (1 << 0)
-#define AUD_MUTE_1341  (1 << 1)
 #define AUD_NGPIO      2
 
 extern void sa1110_mb_disable(void);
@@ -97,6 +81,30 @@ struct neponset_drvdata {
        struct gpio_chip *gpio[4];
 };
 
+static struct gpiod_lookup_table neponset_uart1_gpio_table = {
+       .dev_id = "sa11x0-uart.1",
+       .table = {
+               GPIO_LOOKUP("neponset-mdm-ctl0", 2, "rts", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("neponset-mdm-ctl0", 3, "dtr", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("neponset-mdm-ctl1", 3, "cts", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("neponset-mdm-ctl1", 4, "dsr", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("neponset-mdm-ctl1", 5, "dcd", GPIO_ACTIVE_LOW),
+               { },
+       },
+};
+
+static struct gpiod_lookup_table neponset_uart3_gpio_table = {
+       .dev_id = "sa11x0-uart.3",
+       .table = {
+               GPIO_LOOKUP("neponset-mdm-ctl0", 0, "rts", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("neponset-mdm-ctl0", 1, "dtr", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("neponset-mdm-ctl1", 0, "cts", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("neponset-mdm-ctl1", 1, "dsr", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("neponset-mdm-ctl1", 2, "dcd", GPIO_ACTIVE_LOW),
+               { },
+       },
+};
+
 static struct gpiod_lookup_table neponset_pcmcia_table = {
        .dev_id = "1800",
        .table = {
@@ -124,69 +132,6 @@ void neponset_ncr_frob(unsigned int mask, unsigned int val)
 }
 EXPORT_SYMBOL(neponset_ncr_frob);
 
-static void neponset_set_mctrl(struct uart_port *port, u_int mctrl)
-{
-       struct neponset_drvdata *n = nep;
-       unsigned long mask, val = 0;
-
-       if (!n)
-               return;
-
-       if (port->mapbase == _Ser1UTCR0) {
-               mask = MDM_CTL0_RTS2 | MDM_CTL0_DTR2;
-
-               if (!(mctrl & TIOCM_RTS))
-                       val |= MDM_CTL0_RTS2;
-
-               if (!(mctrl & TIOCM_DTR))
-                       val |= MDM_CTL0_DTR2;
-       } else if (port->mapbase == _Ser3UTCR0) {
-               mask = MDM_CTL0_RTS1 | MDM_CTL0_DTR1;
-
-               if (!(mctrl & TIOCM_RTS))
-                       val |= MDM_CTL0_RTS1;
-
-               if (!(mctrl & TIOCM_DTR))
-                       val |= MDM_CTL0_DTR1;
-       }
-
-       n->gpio[1]->set_multiple(n->gpio[1], &mask, &val);
-}
-
-static u_int neponset_get_mctrl(struct uart_port *port)
-{
-       void __iomem *base = nep->base;
-       u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
-       u_int mdm_ctl1;
-
-       if (!base)
-               return ret;
-
-       mdm_ctl1 = readb_relaxed(base + MDM_CTL_1);
-       if (port->mapbase == _Ser1UTCR0) {
-               if (mdm_ctl1 & MDM_CTL1_DCD2)
-                       ret &= ~TIOCM_CD;
-               if (mdm_ctl1 & MDM_CTL1_CTS2)
-                       ret &= ~TIOCM_CTS;
-               if (mdm_ctl1 & MDM_CTL1_DSR2)
-                       ret &= ~TIOCM_DSR;
-       } else if (port->mapbase == _Ser3UTCR0) {
-               if (mdm_ctl1 & MDM_CTL1_DCD1)
-                       ret &= ~TIOCM_CD;
-               if (mdm_ctl1 & MDM_CTL1_CTS1)
-                       ret &= ~TIOCM_CTS;
-               if (mdm_ctl1 & MDM_CTL1_DSR1)
-                       ret &= ~TIOCM_DSR;
-       }
-
-       return ret;
-}
-
-static struct sa1100_port_fns neponset_port_fns = {
-       .set_mctrl      = neponset_set_mctrl,
-       .get_mctrl      = neponset_get_mctrl,
-};
-
 /*
  * Install handler for Neponset IRQ.  Note that we have to loop here
  * since the ETHERNET and USAR IRQs are level based, and we need to
@@ -388,6 +333,8 @@ static int neponset_probe(struct platform_device *dev)
                           d->base + AUD_CTL, AUD_NGPIO, false,
                           neponset_aud_names);
 
+       gpiod_add_lookup_table(&neponset_uart1_gpio_table);
+       gpiod_add_lookup_table(&neponset_uart3_gpio_table);
        gpiod_add_lookup_table(&neponset_pcmcia_table);
 
        /*
@@ -402,8 +349,6 @@ static int neponset_probe(struct platform_device *dev)
                 d->irq_base, d->irq_base + NEP_IRQ_NR - 1);
        nep = d;
 
-       sa1100_register_uart_fns(&neponset_port_fns);
-
        /* Ensure that the memory bus request/grant signals are setup */
        sa1110_mb_disable();
 
@@ -442,6 +387,8 @@ static int neponset_remove(struct platform_device *dev)
                platform_device_unregister(d->smc91x);
 
        gpiod_remove_lookup_table(&neponset_pcmcia_table);
+       gpiod_remove_lookup_table(&neponset_uart3_gpio_table);
+       gpiod_remove_lookup_table(&neponset_uart1_gpio_table);
 
        irq_set_chained_handler(irq, NULL);
        irq_free_descs(d->irq_base, NEP_IRQ_NR);
index eea60b2..9e4bc18 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/of.h>
 #include <linux/of_fdt.h>
 #include <linux/of_platform.h>
+#include <linux/psci.h>
 #include <asm/mach/arch.h>
 #include <asm/secure_cntvoff.h>
 #include "common.h"
@@ -60,9 +61,24 @@ static unsigned int __init get_extal_freq(void)
 
 void __init rcar_gen2_timer_init(void)
 {
+       bool need_update = true;
        void __iomem *base;
        u32 freq;
 
+       /*
+        * If PSCI is available then most likely we are running on PSCI-enabled
+        * U-Boot which, we assume, has already taken care of resetting CNTVOFF
+        * and updating counter module before switching to non-secure mode
+        * and we don't need to.
+        */
+#ifdef CONFIG_ARM_PSCI_FW
+       if (psci_ops.cpu_on)
+               need_update = false;
+#endif
+
+       if (need_update == false)
+               goto skip_update;
+
        secure_cntvoff_init();
 
        if (of_machine_is_compatible("renesas,r8a7745") ||
@@ -102,6 +118,7 @@ void __init rcar_gen2_timer_init(void)
 
        iounmap(base);
 
+skip_update:
        of_clk_init(NULL);
        timer_probe();
 }
index 05d6b5a..57699bd 100644 (file)
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 menuconfig ARCH_STM32
-       bool "STMicroelectronics STM32 family" if ARM_SINGLE_ARMV7M || ARCH_MULTI_V7
+       bool "STMicroelectronics STM32 family"
+       depends on ARM_SINGLE_ARMV7M || ARCH_MULTI_V7
        select ARMV7M_SYSTICK if ARM_SINGLE_ARMV7M
        select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7
        select ARM_GIC if ARCH_MULTI_V7
index da6c633..97cd045 100644 (file)
@@ -1,7 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
-plus_sec := $(call as-instr,.arch_extension sec,+sec)
-AFLAGS_smc.o := -Wa,-march=armv7-a$(plus_sec)
-
 obj-y += setup.o smc.o
 obj-$(CONFIG_SMP) += platsmp.o
 obj-$(CONFIG_SUSPEND) += pm.o
index 361a8dc..b1752aa 100644 (file)
@@ -1,6 +1,8 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 #include <linux/linkage.h>
 
+       .arch armv7-a
+       .arch_extension sec
 ENTRY(tango_smc)
        push    {lr}
        mov     ip, r1
index 0b76323..c00ea4f 100644 (file)
@@ -16,8 +16,6 @@
 #include <linux/of_platform.h>
 #include <linux/slab.h>
 #include <linux/amba/bus.h>
-#include <linux/amba/clcd.h>
-#include <linux/platform_data/video-clcd-versatile.h>
 #include <linux/amba/mmci.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
  */
 #define VERSATILE_SYS_PCICTL_OFFSET           0x44
 #define VERSATILE_SYS_MCI_OFFSET              0x48
-#define VERSATILE_SYS_CLCD_OFFSET             0x50
 
 /*
  * VERSATILE peripheral addresses
  */
 #define VERSATILE_MMCI0_BASE           0x10005000      /* MMC interface */
 #define VERSATILE_MMCI1_BASE           0x1000B000      /* MMC Interface */
-#define VERSATILE_CLCD_BASE            0x10120000      /* CLCD */
 #define VERSATILE_SCTL_BASE            0x101E0000      /* System controller */
 #define VERSATILE_IB2_BASE             0x24000000      /* IB2 module */
 #define VERSATILE_IB2_CTL_BASE         (VERSATILE_IB2_BASE + 0x03000000)
@@ -84,158 +80,6 @@ static struct mmci_platform_data mmc1_plat_data = {
 };
 
 /*
- * CLCD support.
- */
-#define SYS_CLCD_MODE_MASK     (3 << 0)
-#define SYS_CLCD_MODE_888      (0 << 0)
-#define SYS_CLCD_MODE_5551     (1 << 0)
-#define SYS_CLCD_MODE_565_RLSB (2 << 0)
-#define SYS_CLCD_MODE_565_BLSB (3 << 0)
-#define SYS_CLCD_NLCDIOON      (1 << 2)
-#define SYS_CLCD_VDDPOSSWITCH  (1 << 3)
-#define SYS_CLCD_PWR3V5SWITCH  (1 << 4)
-#define SYS_CLCD_ID_MASK       (0x1f << 8)
-#define SYS_CLCD_ID_SANYO_3_8  (0x00 << 8)
-#define SYS_CLCD_ID_UNKNOWN_8_4        (0x01 << 8)
-#define SYS_CLCD_ID_EPSON_2_2  (0x02 << 8)
-#define SYS_CLCD_ID_SANYO_2_5  (0x07 << 8)
-#define SYS_CLCD_ID_VGA                (0x1f << 8)
-
-static bool is_sanyo_2_5_lcd;
-
-/*
- * Disable all display connectors on the interface module.
- */
-static void versatile_clcd_disable(struct clcd_fb *fb)
-{
-       void __iomem *sys_clcd = versatile_sys_base + VERSATILE_SYS_CLCD_OFFSET;
-       u32 val;
-
-       val = readl(sys_clcd);
-       val &= ~SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH;
-       writel(val, sys_clcd);
-
-       /*
-        * If the LCD is Sanyo 2x5 in on the IB2 board, turn the back-light off
-        */
-       if (of_machine_is_compatible("arm,versatile-ab") && is_sanyo_2_5_lcd) {
-               unsigned long ctrl;
-
-               ctrl = readl(versatile_ib2_ctrl);
-               ctrl &= ~0x01;
-               writel(ctrl, versatile_ib2_ctrl);
-       }
-}
-
-/*
- * Enable the relevant connector on the interface module.
- */
-static void versatile_clcd_enable(struct clcd_fb *fb)
-{
-       struct fb_var_screeninfo *var = &fb->fb.var;
-       void __iomem *sys_clcd = versatile_sys_base + VERSATILE_SYS_CLCD_OFFSET;
-       u32 val;
-
-       val = readl(sys_clcd);
-       val &= ~SYS_CLCD_MODE_MASK;
-
-       switch (var->green.length) {
-       case 5:
-               val |= SYS_CLCD_MODE_5551;
-               break;
-       case 6:
-               if (var->red.offset == 0)
-                       val |= SYS_CLCD_MODE_565_RLSB;
-               else
-                       val |= SYS_CLCD_MODE_565_BLSB;
-               break;
-       case 8:
-               val |= SYS_CLCD_MODE_888;
-               break;
-       }
-
-       /*
-        * Set the MUX
-        */
-       writel(val, sys_clcd);
-
-       /*
-        * And now enable the PSUs
-        */
-       val |= SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH;
-       writel(val, sys_clcd);
-
-       /*
-        * If the LCD is Sanyo 2x5 in on the IB2 board, turn the back-light on
-        */
-       if (of_machine_is_compatible("arm,versatile-ab") && is_sanyo_2_5_lcd) {
-               unsigned long ctrl;
-
-               ctrl = readl(versatile_ib2_ctrl);
-               ctrl |= 0x01;
-               writel(ctrl, versatile_ib2_ctrl);
-       }
-}
-
-/*
- * Detect which LCD panel is connected, and return the appropriate
- * clcd_panel structure.  Note: we do not have any information on
- * the required timings for the 8.4in panel, so we presently assume
- * VGA timings.
- */
-static int versatile_clcd_setup(struct clcd_fb *fb)
-{
-       void __iomem *sys_clcd = versatile_sys_base + VERSATILE_SYS_CLCD_OFFSET;
-       const char *panel_name;
-       u32 val;
-
-       is_sanyo_2_5_lcd = false;
-
-       val = readl(sys_clcd) & SYS_CLCD_ID_MASK;
-       if (val == SYS_CLCD_ID_SANYO_3_8)
-               panel_name = "Sanyo TM38QV67A02A";
-       else if (val == SYS_CLCD_ID_SANYO_2_5) {
-               panel_name = "Sanyo QVGA Portrait";
-               is_sanyo_2_5_lcd = true;
-       } else if (val == SYS_CLCD_ID_EPSON_2_2)
-               panel_name = "Epson L2F50113T00";
-       else if (val == SYS_CLCD_ID_VGA)
-               panel_name = "VGA";
-       else {
-               printk(KERN_ERR "CLCD: unknown LCD panel ID 0x%08x, using VGA\n",
-                       val);
-               panel_name = "VGA";
-       }
-
-       fb->panel = versatile_clcd_get_panel(panel_name);
-       if (!fb->panel)
-               return -EINVAL;
-
-       return versatile_clcd_setup_dma(fb, SZ_1M);
-}
-
-static void versatile_clcd_decode(struct clcd_fb *fb, struct clcd_regs *regs)
-{
-       clcdfb_decode(fb, regs);
-
-       /* Always clear BGR for RGB565: we do the routing externally */
-       if (fb->fb.var.green.length == 6)
-               regs->cntl &= ~CNTL_BGR;
-}
-
-static struct clcd_board clcd_plat_data = {
-       .name           = "Versatile",
-       .caps           = CLCD_CAP_5551 | CLCD_CAP_565 | CLCD_CAP_888,
-       .check          = clcdfb_check,
-       .decode         = versatile_clcd_decode,
-       .disable        = versatile_clcd_disable,
-       .enable         = versatile_clcd_enable,
-       .setup          = versatile_clcd_setup,
-       .mmap           = versatile_clcd_mmap_dma,
-       .remove         = versatile_clcd_remove_dma,
-};
-
-/*
  * Lookup table for attaching a specific name and platform_data pointer to
  * devices as they get created by of_platform_populate().  Ideally this table
  * would not exist, but the current clock implementation depends on some devices
@@ -244,7 +88,6 @@ static struct clcd_board clcd_plat_data = {
 struct of_dev_auxdata versatile_auxdata_lookup[] __initdata = {
        OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI0_BASE, "fpga:05", &mmc0_plat_data),
        OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI1_BASE, "fpga:0b", &mmc1_plat_data),
-       OF_DEV_AUXDATA("arm,primecell", VERSATILE_CLCD_BASE, "dev:20", &clcd_plat_data),
        {}
 };
 
@@ -299,12 +142,12 @@ static void __init versatile_dt_pci_init(void)
                 * driver had it so we will keep it.
                 */
                writel(1, versatile_sys_base + VERSATILE_SYS_PCICTL_OFFSET);
-               return;
+               goto out_put_node;
        }
 
        newprop = kzalloc(sizeof(*newprop), GFP_KERNEL);
        if (!newprop)
-               return;
+               goto out_put_node;
 
        newprop->name = kstrdup("status", GFP_KERNEL);
        newprop->value = kstrdup("disabled", GFP_KERNEL);
@@ -312,6 +155,9 @@ static void __init versatile_dt_pci_init(void)
        of_update_property(np, newprop);
 
        pr_info("Not plugged into PCI backplane!\n");
+
+out_put_node:
+       of_node_put(np);
 }
 
 static void __init versatile_dt_init(void)
index cc79811..820b60a 100644 (file)
@@ -709,7 +709,7 @@ config ARM_VIRT_EXT
          assistance.
 
          A compliant bootloader is required in order to make maximum
-         use of this feature.  Refer to Documentation/arm/Booting for
+         use of this feature.  Refer to Documentation/arm/booting.rst for
          details.
 
 config SWP_EMULATE
@@ -875,7 +875,7 @@ config KUSER_HELPERS
          the CPU type fitted to the system.  This permits binaries to be
          run on ARMv4 through to ARMv7 without modification.
 
-         See Documentation/arm/kernel_user_helpers.txt for details.
+         See Documentation/arm/kernel_user_helpers.rst for details.
 
          However, the fixed address nature of these helpers can be used
          by ROP (return orientated programming) authors when creating
index 0e41723..890eeaa 100644 (file)
 
 #ifdef CONFIG_MMU
 
-#ifdef CONFIG_KPROBES
-static inline int notify_page_fault(struct pt_regs *regs, unsigned int fsr)
-{
-       int ret = 0;
-
-       if (!user_mode(regs)) {
-               /* kprobe_running() needs smp_processor_id() */
-               preempt_disable();
-               if (kprobe_running() && kprobe_fault_handler(regs, fsr))
-                       ret = 1;
-               preempt_enable();
-       }
-
-       return ret;
-}
-#else
-static inline int notify_page_fault(struct pt_regs *regs, unsigned int fsr)
-{
-       return 0;
-}
-#endif
-
 /*
  * This is useful to dump out the page tables associated with
  * 'addr' in mm 'mm'.
@@ -265,7 +243,7 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
        vm_fault_t fault;
        unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
-       if (notify_page_fault(regs, fsr))
+       if (kprobe_page_fault(regs, fsr))
                return 0;
 
        tsk = current;
index 53da57f..301e572 100644 (file)
@@ -243,7 +243,7 @@ config SAMSUNG_PM_DEBUG
        depends on DEBUG_EXYNOS_UART || DEBUG_S3C24XX_UART || DEBUG_S3C2410_UART
        help
          Say Y here if you want verbose debugging from the PM Suspend and
-         Resume code. See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
+         Resume code. See <file:Documentation/arm/samsung-s3c24xx/suspend.rst>
          for more information.
 
 config S3C_PM_DEBUG_LED_SMDK
@@ -268,7 +268,7 @@ config SAMSUNG_PM_CHECK
          Note, this can take several seconds depending on memory size
          and CPU speed.
 
-         See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
+         See <file:Documentation/arm/samsung-s3c24xx/suspend.rst>
 
 config SAMSUNG_PM_CHECK_CHUNKSIZE
        int "S3C2410 PM Suspend CRC Chunksize (KiB)"
@@ -280,7 +280,7 @@ config SAMSUNG_PM_CHECK_CHUNKSIZE
          the CRC data block will take more memory, but will identify any
          faults with better precision.
 
-         See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
+         See <file:Documentation/arm/samsung-s3c24xx/suspend.rst>
 
 config SAMSUNG_WAKEMASK
        bool
index 4eac94c..9e74c7f 100644 (file)
@@ -7,7 +7,7 @@
 #   http://www.arm.linux.org.uk/developer/machines/download.php
 #
 # Please do not send patches to this file; it is automatically generated!
-# To add an entry into this database, please see Documentation/arm/README,
+# To add an entry into this database, please see Documentation/arm/arm.rst,
 # or visit:
 #
 #   http://www.arm.linux.org.uk/developer/machines/?action=new
index ca85df2..87b7769 100644 (file)
@@ -13,8 +13,7 @@ ccflags-y += -DDISABLE_BRANCH_PROFILING
 ldflags-$(CONFIG_CPU_ENDIAN_BE8) := --be8
 ldflags-y := -Bsymbolic --no-undefined -soname=linux-vdso.so.1 \
            -z max-page-size=4096 -nostdlib -shared $(ldflags-y) \
-           $(call ld-option, --hash-style=sysv) \
-           $(call ld-option, --build-id) \
+           --hash-style=sysv --build-id \
            -T
 
 obj-$(CONFIG_VDSO) += vdso.o
index a36ff61..3adcec0 100644 (file)
@@ -24,6 +24,7 @@ config ARM64
        select ARCH_HAS_KCOV
        select ARCH_HAS_KEEPINITRD
        select ARCH_HAS_MEMBARRIER_SYNC_CORE
+       select ARCH_HAS_PTE_DEVMAP
        select ARCH_HAS_PTE_SPECIAL
        select ARCH_HAS_SETUP_DMA_OPS
        select ARCH_HAS_SET_DIRECT_MAP
@@ -72,6 +73,7 @@ config ARM64
        select ARCH_SUPPORTS_NUMA_BALANCING
        select ARCH_WANT_COMPAT_IPC_PARSE_VERSION if COMPAT
        select ARCH_WANT_FRAME_POINTERS
+       select ARCH_WANT_HUGE_PMD_SHARE if ARM64_4K_PAGES || (ARM64_16K_PAGES && !ARM64_VA_BITS_36)
        select ARCH_HAS_UBSAN_SANITIZE_ALL
        select ARM_AMBA
        select ARM_ARCH_TIMER
@@ -905,7 +907,6 @@ config SYS_SUPPORTS_HUGETLBFS
        def_bool y
 
 config ARCH_WANT_HUGE_PMD_SHARE
-       def_bool y if ARM64_4K_PAGES || (ARM64_16K_PAGES && !ARM64_VA_BITS_36)
 
 config ARCH_HAS_CACHE_LINE_SIZE
        def_bool y
@@ -996,7 +997,7 @@ config CRASH_DUMP
          reserved region and then later executed after a crash by
          kdump/kexec.
 
-         For more details see Documentation/kdump/kdump.rst
+         For more details see Documentation/admin-guide/kdump/kdump.rst
 
 config XEN_DOM0
        def_bool y
@@ -1142,7 +1143,7 @@ config KUSER_HELPERS
          the system. This permits binaries to be run on ARMv4 through
          to ARMv8 without modification.
 
-         See Documentation/arm/kernel_user_helpers.txt for details.
+         See Documentation/arm/kernel_user_helpers.rst for details.
 
          However, the fixed address nature of these helpers can be used
          by ROP (return orientated programming) authors when creating
index d07fc06..4778c77 100644 (file)
@@ -66,8 +66,11 @@ config ARCH_BITMAIN
 
 config ARCH_BRCMSTB
        bool "Broadcom Set-Top-Box SoCs"
+       select ARCH_HAS_RESET_CONTROLLER
+       select BCM7038_L1_IRQ
        select BRCMSTB_L2_IRQ
        select GENERIC_IRQ_CHIP
+       select PINCTRL
        help
          This enables support for Broadcom's ARMv8 Set Top Box SoCs
 
index c3a618e..f0349ef 100644 (file)
                        status = "disabled";
                };
        };
+
+       usb_power_supply: usb-power-supply {
+               compatible = "x-powers,axp803-usb-power-supply",
+                            "x-powers,axp813-usb-power-supply";
+               status = "disabled";
+       };
 };
index 019ae09..5634245 100644 (file)
@@ -85,8 +85,6 @@
 };
 
 &i2c0 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&i2c0_pins>;
        status = "okay";
 
        sensor@48 {
        bias-pull-up;
 };
 
+&i2c1 {
+       status = "okay";
+
+       touchscreen@5d {
+               compatible = "goodix,gt5663";
+               reg = <0x5d>;
+               AVDD28-supply = <&reg_ldo_io0>;                 /* VCC-CTP: GPIO0-LDO */
+               interrupt-parent = <&pio>;
+               interrupts = <7 4 IRQ_TYPE_EDGE_FALLING>;
+               irq-gpios = <&pio 7 4 GPIO_ACTIVE_HIGH>;        /* CTP-INT: PH4 */
+               reset-gpios = <&pio 7 8 GPIO_ACTIVE_HIGH>;      /* CTP-RST: PH8 */
+               touchscreen-inverted-x;
+               touchscreen-inverted-y;
+       };
+};
+
 &mmc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&mmc1_pins>;
        regulator-name = "vdd-cpus";
 };
 
+&reg_ldo_io0 {
+       regulator-min-microvolt = <2800000>;
+       regulator-max-microvolt = <2800000>;
+       regulator-name = "vcc-ctp";
+       status = "okay";
+};
+
 &reg_rtc_ldo {
        regulator-name = "vcc-rtc";
 };
index 0a56c0c..208373e 100644 (file)
 };
 
 &i2c1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&i2c1_pins>;
        status = "okay";
 };
 
        status = "okay";
 };
 
+&usb_power_supply {
+       status = "okay";
+};
+
 &usbphy {
        usb0_id_det-gpios = <&pio 7 9 GPIO_ACTIVE_HIGH>; /* PH9 */
+       usb0_vbus_power-supply = <&usb_power_supply>;
        usb0_vbus-supply = <&reg_drivevbus>;
        status = "okay";
 };
index f4e7853..9b9d915 100644 (file)
 };
 
 /* i2c1 connected with gpio headers like pine64, bananapi */
-&i2c1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&i2c1_pins>;
-       status = "disabled";
-};
-
 &i2c1_pins {
        bias-pull-up;
 };
index 6a21545..787ebd8 100644 (file)
        status = "okay";
 };
 
+&i2c0 {
+       status = "okay";
+
+       touchscreen@5d {
+               compatible = "goodix,gt911";
+               reg = <0x5d>;
+               AVDD28-supply = <&reg_ldo_io0>;                 /* VDD_CTP: GPIO0-LDO */
+               interrupt-parent = <&pio>;
+               interrupts = <7 4 IRQ_TYPE_EDGE_FALLING>;
+               irq-gpios = <&pio 7 4 GPIO_ACTIVE_HIGH>;        /* CTP-INT: PH4 */
+               reset-gpios = <&pio 7 11 GPIO_ACTIVE_HIGH>;     /* CTP-RST: PH11 */
+               touchscreen-inverted-x;
+               touchscreen-inverted-y;
+       };
+};
+
 &mdio {
        ext_rgmii_phy: ethernet-phy@1 {
                compatible = "ethernet-phy-ieee802.3-c22";
        regulator-name = "vcc-phy";
 };
 
+&reg_ldo_io0 {
+       regulator-min-microvolt = <2800000>;
+       regulator-max-microvolt = <2800000>;
+       regulator-name = "vdd-ctp";
+       status = "okay";
+};
+
 &uart0 {
        pinctrl-names = "default";
        pinctrl-0 = <&uart0_pb_pins>;
index 510f661..5ef3c62 100644 (file)
        wifi_pwrseq: wifi_pwrseq {
                compatible = "mmc-pwrseq-simple";
                reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>; /* PL8 */
+               clocks = <&rtc 1>;
+               clock-names = "ext_clock";
        };
 };
 
        bus-width = <4>;
        non-removable;
        status = "okay";
+
+       brcmf: wifi@1 {
+               reg = <1>;
+               compatible = "brcm,bcm4329-fmac";
+               interrupt-parent = <&r_pio>;
+               interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+               interrupt-names = "host-wake";
+       };
 };
 
 &ohci0 {
 &uart1 {
        pinctrl-names = "default";
        pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+       uart-has-rtscts;
        status = "okay";
+
+       bluetooth {
+               compatible = "brcm,bcm43438-bt";
+               max-speed = <1500000>;
+               clocks = <&rtc 1>;
+               clock-names = "lpo";
+               vbat-supply = <&reg_dldo2>;
+               vddio-supply = <&reg_dldo4>;
+               device-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 */
+               host-wakeup-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 */
+               shutdown-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 */
+       };
 };
 
 /* On Pi-2 connector, RTS/CTS optional */
index b7ac637..409523c 100644 (file)
 };
 
 &i2c1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&i2c1_pins>;
        status = "okay";
 };
 
index 0ec46b9..1069e70 100644 (file)
                compatible = "mmc-pwrseq-simple";
                reset-gpios = <&r_pio 0 2 GPIO_ACTIVE_LOW>; /* PL2 */
        };
+
+       speaker_amp: audio-amplifier {
+               compatible = "simple-audio-amplifier";
+               enable-gpios = <&r_pio 0 12 GPIO_ACTIVE_HIGH>; /* PL12 */
+               sound-name-prefix = "Speaker Amp";
+       };
+};
+
+&codec {
+       status = "okay";
+};
+
+&codec_analog {
+       cpvdd-supply = <&reg_eldo1>;
+       status = "okay";
+};
+
+&dai {
+       status = "okay";
 };
 
 &ehci1 {
  */
 &i2c0 {
        clock-frequency = <100000>;
-       pinctrl-names = "default";
-       pinctrl-0 = <&i2c0_pins>;
        status = "okay";
 };
 
        vcc-hdmi-supply = <&reg_dldo1>;
 };
 
+&sound {
+       simple-audio-card,aux-devs = <&codec_analog>, <&speaker_amp>;
+       simple-audio-card,widgets = "Headphone", "Headphone Jack",
+                                   "Microphone", "Headset Microphone",
+                                   "Microphone", "Internal Microphone",
+                                   "Speaker", "Internal Speaker";
+       simple-audio-card,routing =
+                       "Left DAC", "AIF1 Slot 0 Left",
+                       "Right DAC", "AIF1 Slot 0 Right",
+                       "AIF1 Slot 0 Left ADC", "Left ADC",
+                       "AIF1 Slot 0 Right ADC", "Right ADC",
+                       "Headphone Jack", "HP",
+                       "Speaker Amp INL", "LINEOUT",
+                       "Speaker Amp INR", "LINEOUT",
+                       "Internal Speaker", "Speaker Amp OUTL",
+                       "Internal Speaker", "Speaker Amp OUTR",
+                       "Internal Microphone", "MBIAS",
+                       "MIC1", "Internal Microphone",
+                       "Headset Microphone", "HBIAS",
+                       "MIC2", "Headset Microphone";
+       status = "okay";
+};
+
 &uart0 {
        pinctrl-names = "default";
        pinctrl-0 = <&uart0_pb_pins>;
index 8c5b521..9cc9bdd 100644 (file)
                                function = "i2c1";
                        };
 
+                       /omit-if-no-ref/
+                       lcd_rgb666_pins: lcd-rgb666-pins {
+                               pins = "PD0", "PD1", "PD2", "PD3", "PD4",
+                                      "PD5", "PD6", "PD7", "PD8", "PD9",
+                                      "PD10", "PD11", "PD12", "PD13",
+                                      "PD14", "PD15", "PD16", "PD17",
+                                      "PD18", "PD19", "PD20", "PD21";
+                               function = "lcd0";
+                       };
+
                        mmc0_pins: mmc0-pins {
                                pins = "PF0", "PF1", "PF2", "PF3",
                                       "PF4", "PF5";
                        status = "disabled";
                };
 
+               lradc: lradc@1c21800 {
+                       compatible = "allwinner,sun50i-a64-lradc",
+                                    "allwinner,sun8i-a83t-r-lradc";
+                       reg = <0x01c21800 0x400>;
+                       interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+                       status = "disabled";
+               };
+
                i2s0: i2s@1c22000 {
                        #sound-dai-cells = <0>;
                        compatible = "allwinner,sun50i-a64-i2s",
                        interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&ccu CLK_BUS_I2C0>;
                        resets = <&ccu RST_BUS_I2C0>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&i2c0_pins>;
                        status = "disabled";
                        #address-cells = <1>;
                        #size-cells = <0>;
                        interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&ccu CLK_BUS_I2C1>;
                        resets = <&ccu RST_BUS_I2C1>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&i2c1_pins>;
                        status = "disabled";
                        #address-cells = <1>;
                        #size-cells = <0>;
index 62409af..c924090 100644 (file)
@@ -55,8 +55,7 @@
                regulator-ramp-delay = <50>; /* 4ms */
                gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 */
                gpios-states = <0x1>;
-               states = <1100000 0x0
-                         1300000 0x1>;
+               states = <1100000 0>, <1300000 1>;
        };
 };
 
index 9887948..1c7dde8 100644 (file)
                regulator-ramp-delay = <50>; /* 4ms */
                gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>;
                gpios-states = <0x1>;
-               states = <1100000 0x0
-                         1300000 0x1>;
+               states = <1100000 0>, <1300000 1>;
        };
 
        wifi_pwrseq: wifi_pwrseq {
index 4802902..1898345 100644 (file)
        status = "okay";
 };
 
+&pio {
+       vcc-pc-supply = <&reg_bldo2>;
+       vcc-pd-supply = <&reg_cldo1>;
+       vcc-pg-supply = <&reg_aldo1>;
+};
+
 &r_i2c {
        status = "okay";
 
        pcf8563: rtc@51 {
                compatible = "nxp,pcf8563";
                reg = <0x51>;
+               interrupt-parent = <&r_intc>;
+               interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
                #clock-cells = <0>;
        };
 };
 
+&r_pio {
+       vcc-pm-supply = <&reg_aldo1>;
+};
+
 &uart0 {
        pinctrl-names = "default";
        pinctrl-0 = <&uart0_ph_pins>;
index 16c5c3d..7628a7c 100644 (file)
                        #reset-cells = <1>;
                };
 
+               dma: dma-controller@3002000 {
+                       compatible = "allwinner,sun50i-h6-dma";
+                       reg = <0x03002000 0x1000>;
+                       interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_BUS_DMA>, <&ccu CLK_MBUS_DMA>;
+                       clock-names = "bus", "mbus";
+                       dma-channels = <16>;
+                       dma-requests = <46>;
+                       resets = <&ccu RST_BUS_DMA>;
+                       #dma-cells = <1>;
+               };
+
                sid: sid@3006000 {
                        compatible = "allwinner,sun50i-h6-sid";
                        reg = <0x03006000 0x400>;
                };
 
+               watchdog: watchdog@30090a0 {
+                       compatible = "allwinner,sun50i-h6-wdt",
+                                    "allwinner,sun6i-a31-wdt";
+                       reg = <0x030090a0 0x20>;
+                       interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+                       /* Broken on some H6 boards */
+                       status = "disabled";
+               };
+
                pio: pinctrl@300b000 {
                        compatible = "allwinner,sun50i-h6-pinctrl";
                        reg = <0x0300b000 0x400>;
                        #reset-cells = <1>;
                };
 
+               r_watchdog: watchdog@7020400 {
+                       compatible = "allwinner,sun50i-h6-wdt",
+                                    "allwinner,sun6i-a31-wdt";
+                       reg = <0x07020400 0x20>;
+                       interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
                r_intc: interrupt-controller@7021000 {
                        compatible = "allwinner,sun50i-h6-r-intc",
                                     "allwinner,sun6i-a31-r-intc";
index 4b0f674..b05d781 100644 (file)
                };
 
                gmac0: ethernet@ff800000 {
-                       compatible = "altr,socfpga-stmmac", "snps,dwmac-3.74a", "snps,dwmac";
+                       compatible = "altr,socfpga-stmmac-a10-s10", "snps,dwmac-3.74a", "snps,dwmac";
                        reg = <0xff800000 0x2000>;
                        interrupts = <0 90 4>;
                        interrupt-names = "macirq";
                };
 
                gmac1: ethernet@ff802000 {
-                       compatible = "altr,socfpga-stmmac", "snps,dwmac-3.74a", "snps,dwmac";
+                       compatible = "altr,socfpga-stmmac-a10-s10", "snps,dwmac-3.74a", "snps,dwmac";
                        reg = <0xff802000 0x2000>;
                        interrupts = <0 91 4>;
                        interrupt-names = "macirq";
                        rx-fifo-depth = <16384>;
                        snps,multicast-filter-bins = <256>;
                        iommus = <&smmu 2>;
-                       altr,sysmgr-syscon = <&sysmgr 0x48 0>;
+                       altr,sysmgr-syscon = <&sysmgr 0x48 8>;
                        status = "disabled";
                };
 
                gmac2: ethernet@ff804000 {
-                       compatible = "altr,socfpga-stmmac", "snps,dwmac-3.74a", "snps,dwmac";
+                       compatible = "altr,socfpga-stmmac-a10-s10", "snps,dwmac-3.74a", "snps,dwmac";
                        reg = <0xff804000 0x2000>;
                        interrupts = <0 92 4>;
                        interrupt-names = "macirq";
                        rx-fifo-depth = <16384>;
                        snps,multicast-filter-bins = <256>;
                        iommus = <&smmu 3>;
-                       altr,sysmgr-syscon = <&sysmgr 0x4c 0>;
+                       altr,sysmgr-syscon = <&sysmgr 0x4c 16>;
                        status = "disabled";
                };
 
index e129c03..07b861f 100644 (file)
@@ -3,6 +3,7 @@ dtb-$(CONFIG_ARCH_MESON) += meson-axg-s400.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-g12a-sei510.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-g12a-u200.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-g12a-x96-max.dtb
+dtb-$(CONFIG_ARCH_MESON) += meson-g12b-odroid-n2.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-nanopi-k2.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-nexbox-a95x.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-odroidc2.dtb
index 75fe1a2..4cd2d59 100644 (file)
 
 /* emmc storage */
 &sd_emmc_c {
-       status = "disabled";
-       pinctrl-0 = <&emmc_pins>;
+       status = "okay";
+       pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>;
        pinctrl-1 = <&emmc_clk_gate_pins>;
        pinctrl-names = "default", "clk-gate";
 
index 34704fe..6219337 100644 (file)
                ranges;
 
                ethmac: ethernet@ff3f0000 {
-                       compatible = "amlogic,meson-axg-dwmac", "snps,dwmac";
+                       compatible = "amlogic,meson-axg-dwmac",
+                                    "snps,dwmac-3.70a",
+                                    "snps,dwmac";
                        reg = <0x0 0xff3f0000 0x0 0x10000
                               0x0 0xff634540 0x0 0x8>;
                        interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
                                };
 
                                emmc_pins: emmc {
-                                       mux {
+                                       mux-0 {
                                                groups = "emmc_nand_d0",
                                                         "emmc_nand_d1",
                                                         "emmc_nand_d2",
                                                         "emmc_nand_d5",
                                                         "emmc_nand_d6",
                                                         "emmc_nand_d7",
-                                                        "emmc_clk",
-                                                        "emmc_cmd",
-                                                        "emmc_ds";
+                                                        "emmc_cmd";
+                                               function = "emmc";
+                                               bias-pull-up;
+                                       };
+
+                                       mux-1 {
+                                               groups = "emmc_clk";
                                                function = "emmc";
                                                bias-disable;
                                        };
                                };
 
+                               emmc_ds_pins: emmc_ds {
+                                       mux {
+                                               groups = "emmc_ds";
+                                               function = "emmc";
+                                               bias-pull-down;
+                                       };
+                               };
+
                                emmc_clk_gate_pins: emmc_clk_gate {
                                        mux {
                                                groups = "BOOT_8";
                                };
 
                                sdio_pins: sdio {
-                                       mux {
+                                       mux-0 {
                                                groups = "sdio_d0",
                                                         "sdio_d1",
                                                         "sdio_d2",
                                                         "sdio_d3",
-                                                        "sdio_cmd",
-                                                        "sdio_clk";
+                                                        "sdio_cmd";
+                                               function = "sdio";
+                                               bias-pull-up;
+                                       };
+
+                                       mux-1 {
+                                               groups = "sdio_clk";
                                                function = "sdio";
                                                bias-disable;
                                        };
index 34b4058..c7a8736 100644 (file)
@@ -9,15 +9,12 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/gpio/meson-g12a-gpio.h>
+#include <dt-bindings/sound/meson-g12a-tohdmitx.h>
 
 / {
        compatible = "seirobotics,sei510", "amlogic,g12a";
        model = "SEI Robotics SEI510";
 
-       aliases {
-               serial0 = &uart_AO;
-       };
-
        adc_keys {
                compatible = "adc-keys";
                io-channels = <&saradc 0>;
                };
        };
 
-       ao_5v: regulator-ao_5v {
-               compatible = "regulator-fixed";
-               regulator-name = "AO_5V";
-               regulator-min-microvolt = <5000000>;
-               regulator-max-microvolt = <5000000>;
-               vin-supply = <&dc_in>;
-               regulator-always-on;
+       aliases {
+               serial0 = &uart_AO;
+               ethernet0 = &ethmac;
+       };
+
+       mono_dac: audio-codec-0 {
+               compatible = "maxim,max98357a";
+               #sound-dai-cells = <0>;
+               sound-name-prefix = "U16";
+               sdmode-gpios = <&gpio GPIOX_8 GPIO_ACTIVE_HIGH>;
+       };
+
+       dmics: audio-codec-1 {
+               #sound-dai-cells = <0>;
+               compatible = "dmic-codec";
+               num-channels = <2>;
+               wakeup-delay-ms = <50>;
+               status = "okay";
+               sound-name-prefix = "MIC";
        };
 
        chosen {
                };
        };
 
-       dc_in: regulator-dc_in {
-               compatible = "regulator-fixed";
-               regulator-name = "DC_IN";
-               regulator-min-microvolt = <5000000>;
-               regulator-max-microvolt = <5000000>;
-               regulator-always-on;
-       };
-
-       emmc_1v8: regulator-emmc_1v8 {
-               compatible = "regulator-fixed";
-               regulator-name = "EMMC_1V8";
-               regulator-min-microvolt = <1800000>;
-               regulator-max-microvolt = <1800000>;
-               vin-supply = <&vddao_3v3>;
-               regulator-always-on;
+       emmc_pwrseq: emmc-pwrseq {
+               compatible = "mmc-pwrseq-emmc";
+               reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>;
        };
 
        hdmi-connector {
                reg = <0x0 0x0 0x0 0x40000000>;
        };
 
-       reserved-memory {
-               /* TEE Reserved Memory */
-               bl32_reserved: bl32@5000000 {
-                       reg = <0x0 0x05300000 0x0 0x2000000>;
-                       no-map;
-               };
+       ao_5v: regulator-ao_5v {
+               compatible = "regulator-fixed";
+               regulator-name = "AO_5V";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&dc_in>;
+               regulator-always-on;
+       };
+
+       dc_in: regulator-dc_in {
+               compatible = "regulator-fixed";
+               regulator-name = "DC_IN";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-always-on;
+       };
+
+       emmc_1v8: regulator-emmc_1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "EMMC_1V8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               vin-supply = <&vddao_3v3>;
+               regulator-always-on;
        };
 
        vddao_3v3: regulator-vddao_3v3 {
                vin-supply = <&vddao_3v3>;
                regulator-always-on;
        };
+
+       reserved-memory {
+               /* TEE Reserved Memory */
+               bl32_reserved: bl32@5000000 {
+                       reg = <0x0 0x05300000 0x0 0x2000000>;
+                       no-map;
+               };
+       };
+
+       sdio_pwrseq: sdio-pwrseq {
+               compatible = "mmc-pwrseq-simple";
+               reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>;
+               clocks = <&wifi32k>;
+               clock-names = "ext_clock";
+       };
+
+       wifi32k: wifi32k {
+               compatible = "pwm-clock";
+               #clock-cells = <0>;
+               clock-frequency = <32768>;
+               pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */
+       };
+
+       sound {
+               compatible = "amlogic,axg-sound-card";
+               model = "G12A-SEI510";
+               audio-aux-devs = <&tdmout_a>, <&tdmout_b>,
+                                <&tdmin_a>, <&tdmin_b>;
+               audio-routing = "TDMOUT_A IN 0", "FRDDR_A OUT 0",
+                               "TDMOUT_A IN 1", "FRDDR_B OUT 0",
+                               "TDMOUT_A IN 2", "FRDDR_C OUT 0",
+                               "TDM_A Playback", "TDMOUT_A OUT",
+                               "TDMOUT_B IN 0", "FRDDR_A OUT 1",
+                               "TDMOUT_B IN 1", "FRDDR_B OUT 1",
+                               "TDMOUT_B IN 2", "FRDDR_C OUT 1",
+                               "TDM_B Playback", "TDMOUT_B OUT",
+                               "TODDR_A IN 4", "PDM Capture",
+                               "TODDR_B IN 4", "PDM Capture",
+                               "TODDR_C IN 4", "PDM Capture",
+                               "TDMIN_A IN 0", "TDM_A Capture",
+                               "TDMIN_A IN 3", "TDM_A Loopback",
+                               "TDMIN_B IN 0", "TDM_A Capture",
+                               "TDMIN_B IN 3", "TDM_A Loopback",
+                               "TDMIN_A IN 1", "TDM_B Capture",
+                               "TDMIN_A IN 4", "TDM_B Loopback",
+                               "TDMIN_B IN 1", "TDM_B Capture",
+                               "TDMIN_B IN 4", "TDM_B Loopback",
+                               "TODDR_A IN 0", "TDMIN_A OUT",
+                               "TODDR_B IN 0", "TDMIN_A OUT",
+                               "TODDR_C IN 0", "TDMIN_A OUT",
+                               "TODDR_A IN 1", "TDMIN_B OUT",
+                               "TODDR_B IN 1", "TDMIN_B OUT",
+                               "TODDR_C IN 1", "TDMIN_B OUT";
+
+               assigned-clocks = <&clkc CLKID_MPLL2>,
+                                 <&clkc CLKID_MPLL0>,
+                                 <&clkc CLKID_MPLL1>;
+               assigned-clock-parents = <0>, <0>, <0>;
+               assigned-clock-rates = <294912000>,
+                                      <270950400>,
+                                      <393216000>;
+               status = "okay";
+
+               dai-link-0 {
+                       sound-dai = <&frddr_a>;
+               };
+
+               dai-link-1 {
+                       sound-dai = <&frddr_b>;
+               };
+
+               dai-link-2 {
+                       sound-dai = <&frddr_c>;
+               };
+
+               dai-link-3 {
+                       sound-dai = <&toddr_a>;
+               };
+
+               dai-link-4 {
+                       sound-dai = <&toddr_b>;
+               };
+
+               dai-link-5 {
+                       sound-dai = <&toddr_c>;
+               };
+
+               /* internal speaker interface */
+               dai-link-6 {
+                       sound-dai = <&tdmif_a>;
+                       dai-format = "i2s";
+                       dai-tdm-slot-tx-mask-0 = <1 1>;
+                       mclk-fs = <256>;
+
+                       codec-0 {
+                               sound-dai = <&mono_dac>;
+                       };
+
+                       codec-1 {
+                               sound-dai = <&tohdmitx TOHDMITX_I2S_IN_A>;
+                       };
+               };
+
+               /* 8ch hdmi interface */
+               dai-link-7 {
+                       sound-dai = <&tdmif_b>;
+                       dai-format = "i2s";
+                       dai-tdm-slot-tx-mask-0 = <1 1>;
+                       dai-tdm-slot-tx-mask-1 = <1 1>;
+                       dai-tdm-slot-tx-mask-2 = <1 1>;
+                       dai-tdm-slot-tx-mask-3 = <1 1>;
+                       mclk-fs = <256>;
+
+                       codec@0 {
+                               sound-dai = <&tohdmitx TOHDMITX_I2S_IN_B>;
+                       };
+               };
+
+               /* internal digital mics */
+               dai-link-8 {
+                       sound-dai = <&pdm>;
+
+                       codec {
+                               sound-dai = <&dmics>;
+                       };
+               };
+
+               /* hdmi glue */
+               dai-link-9 {
+                       sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>;
+
+                       codec {
+                               sound-dai = <&hdmi_tx>;
+                       };
+               };
+       };
+};
+
+&arb {
+       status = "okay";
 };
 
 &cec_AO {
        hdmi-phandle = <&hdmi_tx>;
 };
 
+&clkc_audio {
+       status = "okay";
+};
+
 &cvbs_vdac_port {
        cvbs_vdac_out: endpoint {
                remote-endpoint = <&cvbs_connector_in>;
        };
 };
 
-&saradc {
+&ethmac {
        status = "okay";
-       vref-supply = <&vddio_ao1v8>;
+       phy-handle = <&internal_ephy>;
+       phy-mode = "rmii";
 };
 
-&uart_A {
+&frddr_a {
        status = "okay";
-       pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>;
-       pinctrl-names = "default";
-       uart-has-rtscts;
+};
 
-       bluetooth {
-               compatible = "brcm,bcm43438-bt";
-               shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>;
-       };
+&frddr_b {
+       status = "okay";
+};
+
+&frddr_c {
+       status = "okay";
 };
 
 &hdmi_tx {
        };
 };
 
+&i2c3 {
+       status = "okay";
+       pinctrl-0 = <&i2c3_sda_a_pins>, <&i2c3_sck_a_pins>;
+       pinctrl-names = "default";
+};
+
+&pwm_ef {
+       status = "okay";
+       pinctrl-0 = <&pwm_e_pins>;
+       pinctrl-names = "default";
+       clocks = <&xtal>;
+       clock-names = "clkin0";
+};
+
+&pdm {
+       pinctrl-0 = <&pdm_din0_z_pins>, <&pdm_din1_z_pins>,
+                   <&pdm_din2_z_pins>, <&pdm_din3_z_pins>,
+                   <&pdm_dclk_z_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+};
+
+&saradc {
+       status = "okay";
+       vref-supply = <&vddio_ao1v8>;
+};
+
+/* SDIO */
+&sd_emmc_a {
+       status = "okay";
+       pinctrl-0 = <&sdio_pins>;
+       pinctrl-1 = <&sdio_clk_gate_pins>;
+       pinctrl-names = "default", "clk-gate";
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       bus-width = <4>;
+       cap-sd-highspeed;
+       sd-uhs-sdr50;
+       max-frequency = <100000000>;
+
+       non-removable;
+       disable-wp;
+
+       mmc-pwrseq = <&sdio_pwrseq>;
+
+       vmmc-supply = <&vddao_3v3>;
+       vqmmc-supply = <&vddio_ao1v8>;
+
+       brcmf: wifi@1 {
+               reg = <1>;
+               compatible = "brcm,bcm4329-fmac";
+       };
+};
+
+/* SD card */
+&sd_emmc_b {
+       status = "okay";
+       pinctrl-0 = <&sdcard_c_pins>;
+       pinctrl-1 = <&sdcard_clk_gate_c_pins>;
+       pinctrl-names = "default", "clk-gate";
+
+       bus-width = <4>;
+       cap-sd-highspeed;
+       max-frequency = <50000000>;
+       disable-wp;
+
+       cd-gpios = <&gpio GPIOC_6 GPIO_ACTIVE_LOW>;
+       vmmc-supply = <&vddao_3v3>;
+       vqmmc-supply = <&vddao_3v3>;
+};
+
+/* eMMC */
+&sd_emmc_c {
+       status = "okay";
+       pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>;
+       pinctrl-1 = <&emmc_clk_gate_pins>;
+       pinctrl-names = "default", "clk-gate";
+
+       bus-width = <8>;
+       cap-mmc-highspeed;
+       mmc-ddr-1_8v;
+       mmc-hs200-1_8v;
+       max-frequency = <200000000>;
+       non-removable;
+       disable-wp;
+
+       mmc-pwrseq = <&emmc_pwrseq>;
+       vmmc-supply = <&vddao_3v3>;
+       vqmmc-supply = <&emmc_1v8>;
+};
+
+&tdmif_a {
+       pinctrl-0 = <&tdm_a_dout0_pins>, <&tdm_a_fs_pins>, <&tdm_a_sclk_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+
+       assigned-clocks = <&clkc_audio AUD_CLKID_TDM_SCLK_PAD0>,
+                         <&clkc_audio AUD_CLKID_TDM_LRCLK_PAD0>;
+       assigned-clock-parents = <&clkc_audio AUD_CLKID_MST_A_SCLK>,
+                                <&clkc_audio AUD_CLKID_MST_A_LRCLK>;
+       assigned-clock-rates = <0>, <0>;
+};
+
+&tdmif_b {
+       status = "okay";
+};
+
+&tdmin_a {
+       status = "okay";
+};
+
+&tdmin_b {
+       status = "okay";
+};
+
+&tdmout_a {
+       status = "okay";
+};
+
+&tdmout_b {
+       status = "okay";
+};
+
+&toddr_a {
+       status = "okay";
+};
+
+&toddr_b {
+       status = "okay";
+};
+
+&toddr_c {
+       status = "okay";
+};
+
+&tohdmitx {
+       status = "okay";
+};
+
+&uart_A {
+       status = "okay";
+       pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>;
+       pinctrl-names = "default";
+       uart-has-rtscts;
+
+       bluetooth {
+               compatible = "brcm,bcm43438-bt";
+               shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>;
+               max-speed = <2000000>;
+               clocks = <&wifi32k>;
+               clock-names = "lpo";
+               vbat-supply = <&vddao_3v3>;
+               vddio-supply = <&vddio_ao1v8>;
+       };
+};
+
 &uart_AO {
        status = "okay";
        pinctrl-0 = <&uart_ao_a_pins>;
index 0e8045b..8551fbd 100644 (file)
 
        aliases {
                serial0 = &uart_AO;
+               ethernet0 = &ethmac;
        };
+
        chosen {
                stdout-path = "serial0:115200n8";
        };
-       memory@0 {
-               device_type = "memory";
-               reg = <0x0 0x0 0x0 0x40000000>;
-       };
 
        cvbs-connector {
                compatible = "composite-video-connector";
                };
        };
 
-       flash_1v8: regulator-flash_1v8 {
-               compatible = "regulator-fixed";
-               regulator-name = "FLASH_1V8";
-               regulator-min-microvolt = <1800000>;
-               regulator-max-microvolt = <1800000>;
-               vin-supply = <&vcc_3v3>;
-               regulator-always-on;
+       emmc_pwrseq: emmc-pwrseq {
+               compatible = "mmc-pwrseq-emmc";
+               reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>;
        };
 
        hdmi-connector {
                };
        };
 
+       memory@0 {
+               device_type = "memory";
+               reg = <0x0 0x0 0x0 0x40000000>;
+       };
+
+       flash_1v8: regulator-flash_1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "FLASH_1V8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               vin-supply = <&vcc_3v3>;
+               regulator-always-on;
+       };
+
        main_12v: regulator-main_12v {
                compatible = "regulator-fixed";
                regulator-name = "12V";
                regulator-always-on;
        };
 
+       usb_pwr_en: regulator-usb_pwr_en {
+               compatible = "regulator-fixed";
+               regulator-name = "USB_PWR_EN";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&vcc_5v>;
+
+               gpio = <&gpio GPIOH_6 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
        vcc_1v8: regulator-vcc_1v8 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_1V8";
                enable-active-high;
        };
 
-       usb_pwr_en: regulator-usb_pwr_en {
-               compatible = "regulator-fixed";
-               regulator-name = "USB_PWR_EN";
-               regulator-min-microvolt = <5000000>;
-               regulator-max-microvolt = <5000000>;
-               vin-supply = <&vcc_5v>;
-
-               gpio = <&gpio GPIOH_6 GPIO_ACTIVE_HIGH>;
-               enable-active-high;
-       };
-
        vddao_1v8: regulator-vddao_1v8 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_1V8";
        };
 };
 
+&ethmac {
+       status = "okay";
+       phy-handle = <&internal_ephy>;
+       phy-mode = "rmii";
+};
+
 &hdmi_tx {
        status = "okay";
        pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>;
        };
 };
 
+&ir {
+       status = "okay";
+       pinctrl-0 = <&remote_input_ao_pins>;
+       pinctrl-names = "default";
+};
+
+/* i2c Touch */
+&i2c0 {
+       status = "okay";
+       pinctrl-0 = <&i2c0_sda_z0_pins>, <&i2c0_sck_z1_pins>;
+       pinctrl-names = "default";
+};
+
+/* i2c CM */
+&i2c2 {
+       status = "okay";
+       pinctrl-0 = <&i2c2_sda_z_pins>, <&i2c2_sck_z_pins>;
+       pinctrl-names = "default";
+};
+
+/* i2c Audio */
+&i2c3 {
+       status = "okay";
+       pinctrl-0 = <&i2c3_sda_a_pins>, <&i2c3_sck_a_pins>;
+       pinctrl-names = "default";
+};
+
+/* SD card */
+&sd_emmc_b {
+       status = "okay";
+       pinctrl-0 = <&sdcard_c_pins>;
+       pinctrl-1 = <&sdcard_clk_gate_c_pins>;
+       pinctrl-names = "default", "clk-gate";
+
+       bus-width = <4>;
+       cap-sd-highspeed;
+       max-frequency = <50000000>;
+       disable-wp;
+
+       cd-gpios = <&gpio GPIOC_6 GPIO_ACTIVE_LOW>;
+       vmmc-supply = <&vddao_3v3>;
+       vqmmc-supply = <&vddao_3v3>;
+};
+
+/* eMMC */
+&sd_emmc_c {
+       status = "okay";
+       pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>;
+       pinctrl-1 = <&emmc_clk_gate_pins>;
+       pinctrl-names = "default", "clk-gate";
+
+       bus-width = <8>;
+       cap-mmc-highspeed;
+       mmc-ddr-1_8v;
+       mmc-hs200-1_8v;
+       max-frequency = <200000000>;
+       non-removable;
+       disable-wp;
+
+       mmc-pwrseq = <&emmc_pwrseq>;
+       vmmc-supply = <&vcc_3v3>;
+       vqmmc-supply = <&flash_1v8>;
+};
+
 &uart_AO {
        status = "okay";
        pinctrl-0 = <&uart_ao_a_pins>;
index b3d913f..fe4013c 100644 (file)
@@ -8,6 +8,7 @@
 #include "meson-g12a.dtsi"
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/gpio/meson-g12a-gpio.h>
+#include <dt-bindings/sound/meson-g12a-tohdmitx.h>
 
 / {
        compatible = "amediatech,x96-max", "amlogic,u200", "amlogic,g12a";
 
        aliases {
                serial0 = &uart_AO;
+               ethernet0 = &ethmac;
        };
+
+       spdif_dit: audio-codec-1 {
+               #sound-dai-cells = <0>;
+               compatible = "linux,spdif-dit";
+               status = "okay";
+               sound-name-prefix = "DIT";
+       };
+
        chosen {
                stdout-path = "serial0:115200n8";
        };
                };
        };
 
+       emmc_pwrseq: emmc-pwrseq {
+               compatible = "mmc-pwrseq-emmc";
+               reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>;
+       };
+
+       sdio_pwrseq: sdio-pwrseq {
+               compatible = "mmc-pwrseq-simple";
+               reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>;
+               clocks = <&wifi32k>;
+               clock-names = "ext_clock";
+       };
+
        flash_1v8: regulator-flash_1v8 {
                compatible = "regulator-fixed";
                regulator-name = "FLASH_1V8";
                vin-supply = <&dc_in>;
                regulator-always-on;
        };
+
+       sound {
+               compatible = "amlogic,axg-sound-card";
+               model = "G12A-X96-MAX";
+               audio-aux-devs = <&tdmout_b>;
+               audio-routing = "TDMOUT_B IN 0", "FRDDR_A OUT 1",
+                               "TDMOUT_B IN 1", "FRDDR_B OUT 1",
+                               "TDMOUT_B IN 2", "FRDDR_C OUT 1",
+                               "TDM_B Playback", "TDMOUT_B OUT",
+                               "SPDIFOUT IN 0", "FRDDR_A OUT 3",
+                               "SPDIFOUT IN 1", "FRDDR_B OUT 3",
+                               "SPDIFOUT IN 2", "FRDDR_C OUT 3";
+
+               assigned-clocks = <&clkc CLKID_MPLL2>,
+                                 <&clkc CLKID_MPLL0>,
+                                 <&clkc CLKID_MPLL1>;
+               assigned-clock-parents = <0>, <0>, <0>;
+               assigned-clock-rates = <294912000>,
+                                      <270950400>,
+                                      <393216000>;
+               status = "okay";
+
+               dai-link-0 {
+                       sound-dai = <&frddr_a>;
+               };
+
+               dai-link-1 {
+                       sound-dai = <&frddr_b>;
+               };
+
+               dai-link-2 {
+                       sound-dai = <&frddr_c>;
+               };
+
+               /* 8ch hdmi interface */
+               dai-link-3 {
+                       sound-dai = <&tdmif_b>;
+                       dai-format = "i2s";
+                       dai-tdm-slot-tx-mask-0 = <1 1>;
+                       dai-tdm-slot-tx-mask-1 = <1 1>;
+                       dai-tdm-slot-tx-mask-2 = <1 1>;
+                       dai-tdm-slot-tx-mask-3 = <1 1>;
+                       mclk-fs = <256>;
+
+                       codec {
+                               sound-dai = <&tohdmitx TOHDMITX_I2S_IN_B>;
+                       };
+               };
+
+               /* spdif hdmi or toslink interface */
+               dai-link-4 {
+                       sound-dai = <&spdifout>;
+
+                       codec-0 {
+                               sound-dai = <&spdif_dit>;
+                       };
+
+                       codec-1 {
+                               sound-dai = <&tohdmitx TOHDMITX_SPDIF_IN_A>;
+                       };
+               };
+
+               /* spdif hdmi interface */
+               dai-link-5 {
+                       sound-dai = <&spdifout_b>;
+
+                       codec {
+                               sound-dai = <&tohdmitx TOHDMITX_SPDIF_IN_B>;
+                       };
+               };
+
+               /* hdmi glue */
+               dai-link-6 {
+                       sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>;
+
+                       codec {
+                               sound-dai = <&hdmi_tx>;
+                       };
+               };
+       };
+
+       wifi32k: wifi32k {
+               compatible = "pwm-clock";
+               #clock-cells = <0>;
+               clock-frequency = <32768>;
+               pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */
+       };
+};
+
+&arb {
+       status = "okay";
 };
 
 &cec_AO {
        hdmi-phandle = <&hdmi_tx>;
 };
 
+&clkc_audio {
+       status = "okay";
+};
+
 &cvbs_vdac_port {
        cvbs_vdac_out: endpoint {
                remote-endpoint = <&cvbs_connector_in>;
        };
 };
 
+&frddr_a {
+       status = "okay";
+};
+
+&frddr_b {
+       status = "okay";
+};
+
+&frddr_c {
+       status = "okay";
+};
+
 &hdmi_tx {
        status = "okay";
        pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>;
        };
 };
 
+&ir {
+       status = "okay";
+       pinctrl-0 = <&remote_input_ao_pins>;
+       pinctrl-names = "default";
+};
+
+&ext_mdio {
+       external_phy: ethernet-phy@0 {
+               /* Realtek RTL8211F (0x001cc916) */
+               reg = <0>;
+               max-speed = <1000>;
+               eee-broken-1000t;
+
+               reset-assert-us = <10000>;
+               reset-deassert-us = <30000>;
+               reset-gpios = <&gpio GPIOZ_15 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>;
+
+               interrupt-parent = <&gpio_intc>;
+               /* MAC_INTR on GPIOZ_14 */
+               interrupts = <26 IRQ_TYPE_LEVEL_LOW>;
+       };
+};
+
+&ethmac {
+       pinctrl-0 = <&eth_pins>, <&eth_rgmii_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+       phy-mode = "rgmii";
+       phy-handle = <&external_phy>;
+       amlogic,tx-delay-ns = <2>;
+};
+
+&pwm_ef {
+       status = "okay";
+       pinctrl-0 = <&pwm_e_pins>;
+       pinctrl-names = "default";
+       clocks = <&xtal>;
+       clock-names = "clkin0";
+};
+
 &uart_A {
        status = "okay";
        pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>;
        bluetooth {
                compatible = "brcm,bcm43438-bt";
                shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>;
+               max-speed = <2000000>;
+               clocks = <&wifi32k>;
+               clock-names = "lpo";
        };
 };
 
        status = "okay";
        dr_mode = "host";
 };
+
+/* SDIO */
+&sd_emmc_a {
+       status = "okay";
+       pinctrl-0 = <&sdio_pins>;
+       pinctrl-1 = <&sdio_clk_gate_pins>;
+       pinctrl-names = "default", "clk-gate";
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       bus-width = <4>;
+       cap-sd-highspeed;
+       sd-uhs-sdr50;
+       max-frequency = <100000000>;
+
+       non-removable;
+       disable-wp;
+
+       mmc-pwrseq = <&sdio_pwrseq>;
+
+       vmmc-supply = <&vddao_3v3>;
+       vqmmc-supply = <&vddao_1v8>;
+
+       brcmf: wifi@1 {
+               reg = <1>;
+               compatible = "brcm,bcm4329-fmac";
+       };
+};
+
+/* SD card */
+&sd_emmc_b {
+       status = "okay";
+       pinctrl-0 = <&sdcard_c_pins>;
+       pinctrl-1 = <&sdcard_clk_gate_c_pins>;
+       pinctrl-names = "default", "clk-gate";
+
+       bus-width = <4>;
+       cap-sd-highspeed;
+       max-frequency = <100000000>;
+       disable-wp;
+
+       cd-gpios = <&gpio GPIOC_6 GPIO_ACTIVE_LOW>;
+       vmmc-supply = <&vddao_3v3>;
+       vqmmc-supply = <&vddao_3v3>;
+};
+
+/* eMMC */
+&sd_emmc_c {
+       status = "okay";
+       pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>;
+       pinctrl-1 = <&emmc_clk_gate_pins>;
+       pinctrl-names = "default", "clk-gate";
+
+       bus-width = <8>;
+       cap-mmc-highspeed;
+       max-frequency = <100000000>;
+       non-removable;
+       disable-wp;
+
+       mmc-pwrseq = <&emmc_pwrseq>;
+       vmmc-supply = <&vcc_3v3>;
+       vqmmc-supply = <&flash_1v8>;
+};
+
+&spdifout {
+       pinctrl-0 = <&spdif_out_h_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+};
+
+&spdifout_b {
+       status = "okay";
+};
+
+&tdmif_b {
+       status = "okay";
+};
+
+&tdmout_b {
+       status = "okay";
+};
+
+&tohdmitx {
+       status = "okay";
+};
index 9f72396..f8d43e3 100644 (file)
@@ -5,10 +5,12 @@
 
 #include <dt-bindings/phy/phy.h>
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/clock/axg-audio-clkc.h>
 #include <dt-bindings/clock/g12a-clkc.h>
 #include <dt-bindings/clock/g12a-aoclkc.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/reset/amlogic,meson-axg-audio-arb.h>
 #include <dt-bindings/reset/amlogic,meson-g12a-reset.h>
 
 / {
        #address-cells = <2>;
        #size-cells = <2>;
 
+       tdmif_a: audio-controller-0 {
+               compatible = "amlogic,axg-tdm-iface";
+               #sound-dai-cells = <0>;
+               sound-name-prefix = "TDM_A";
+               clocks = <&clkc_audio AUD_CLKID_MST_A_MCLK>,
+                        <&clkc_audio AUD_CLKID_MST_A_SCLK>,
+                        <&clkc_audio AUD_CLKID_MST_A_LRCLK>;
+               clock-names = "mclk", "sclk", "lrclk";
+               status = "disabled";
+       };
+
+       tdmif_b: audio-controller-1 {
+               compatible = "amlogic,axg-tdm-iface";
+               #sound-dai-cells = <0>;
+               sound-name-prefix = "TDM_B";
+               clocks = <&clkc_audio AUD_CLKID_MST_B_MCLK>,
+                        <&clkc_audio AUD_CLKID_MST_B_SCLK>,
+                        <&clkc_audio AUD_CLKID_MST_B_LRCLK>;
+               clock-names = "mclk", "sclk", "lrclk";
+               status = "disabled";
+       };
+
+       tdmif_c: audio-controller-2 {
+               compatible = "amlogic,axg-tdm-iface";
+               #sound-dai-cells = <0>;
+               sound-name-prefix = "TDM_C";
+               clocks = <&clkc_audio AUD_CLKID_MST_C_MCLK>,
+                        <&clkc_audio AUD_CLKID_MST_C_SCLK>,
+                        <&clkc_audio AUD_CLKID_MST_C_LRCLK>;
+               clock-names = "mclk", "sclk", "lrclk";
+               status = "disabled";
+       };
+
        cpus {
                #address-cells = <0x2>;
                #size-cells = <0x0>;
                #size-cells = <2>;
                ranges;
 
+               ethmac: ethernet@ff3f0000 {
+                       compatible = "amlogic,meson-axg-dwmac",
+                                    "snps,dwmac-3.70a",
+                                    "snps,dwmac";
+                       reg = <0x0 0xff3f0000 0x0 0x10000
+                              0x0 0xff634540 0x0 0x8>;
+                       interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "macirq";
+                       clocks = <&clkc CLKID_ETH>,
+                                <&clkc CLKID_FCLK_DIV2>,
+                                <&clkc CLKID_MPLL2>;
+                       clock-names = "stmmaceth", "clkin0", "clkin1";
+                       status = "disabled";
+
+                       mdio0: mdio {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "snps,dwmac-mdio";
+                       };
+               };
+
                apb: bus@ff600000 {
                        compatible = "simple-bus";
                        reg = <0x0 0xff600000 0x0 0x200000>;
                                clock-names = "isfr", "iahb", "venci";
                                #address-cells = <1>;
                                #size-cells = <0>;
+                               #sound-dai-cells = <0>;
                                status = "disabled";
 
                                /* VPU VENC Input */
                                };
                        };
 
+                       apb_efuse: bus@30000 {
+                               compatible = "simple-bus";
+                               reg = <0x0 0x30000 0x0 0x2000>;
+                               #address-cells = <2>;
+                               #size-cells = <2>;
+                               ranges = <0x0 0x0 0x0 0x30000 0x0 0x2000>;
+
+                               hwrng: rng@218 {
+                                       compatible = "amlogic,meson-rng";
+                                       reg = <0x0 0x218 0x0 0x4>;
+                               };
+                       };
+
                        periphs: bus@34400 {
                                compatible = "simple-bus";
                                reg = <0x0 0x34400 0x0 0x400>;
                                                gpio-ranges = <&periphs_pinctrl 0 0 86>;
                                        };
 
-                                       cec_ao_a_h_pins: cec_ao_a_h {
+                                       cec_ao_a_h_pins: cec_ao_a_h {
+                                               mux {
+                                                       groups = "cec_ao_a_h";
+                                                       function = "cec_ao_a_h";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       cec_ao_b_h_pins: cec_ao_b_h {
+                                               mux {
+                                                       groups = "cec_ao_b_h";
+                                                       function = "cec_ao_b_h";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       emmc_pins: emmc {
+                                               mux-0 {
+                                                       groups = "emmc_nand_d0",
+                                                                "emmc_nand_d1",
+                                                                "emmc_nand_d2",
+                                                                "emmc_nand_d3",
+                                                                "emmc_nand_d4",
+                                                                "emmc_nand_d5",
+                                                                "emmc_nand_d6",
+                                                                "emmc_nand_d7",
+                                                                "emmc_cmd";
+                                                       function = "emmc";
+                                                       bias-pull-up;
+                                                       drive-strength-microamp = <4000>;
+                                               };
+
+                                               mux-1 {
+                                                       groups = "emmc_clk";
+                                                       function = "emmc";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <4000>;
+                                               };
+                                       };
+
+                                       emmc_ds_pins: emmc-ds {
+                                               mux {
+                                                       groups = "emmc_nand_ds";
+                                                       function = "emmc";
+                                                       bias-pull-down;
+                                                       drive-strength-microamp = <4000>;
+                                               };
+                                       };
+
+                                       emmc_clk_gate_pins: emmc_clk_gate {
+                                               mux {
+                                                       groups = "BOOT_8";
+                                                       function = "gpio_periphs";
+                                                       bias-pull-down;
+                                                       drive-strength-microamp = <4000>;
+                                               };
+                                       };
+
+                                       hdmitx_ddc_pins: hdmitx_ddc {
+                                               mux {
+                                                       groups = "hdmitx_sda",
+                                                                "hdmitx_sck";
+                                                       function = "hdmitx";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <4000>;
+                                               };
+                                       };
+
+                                       hdmitx_hpd_pins: hdmitx_hpd {
+                                               mux {
+                                                       groups = "hdmitx_hpd_in";
+                                                       function = "hdmitx";
+                                                       bias-disable;
+                                               };
+                                       };
+
+
+                                       i2c0_sda_c_pins: i2c0-sda-c {
+                                               mux {
+                                                       groups = "i2c0_sda_c";
+                                                       function = "i2c0";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+
+                                               };
+                                       };
+
+                                       i2c0_sck_c_pins: i2c0-sck-c {
+                                               mux {
+                                                       groups = "i2c0_sck_c";
+                                                       function = "i2c0";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       i2c0_sda_z0_pins: i2c0-sda-z0 {
+                                               mux {
+                                                       groups = "i2c0_sda_z0";
+                                                       function = "i2c0";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       i2c0_sck_z1_pins: i2c0-sck-z1 {
+                                               mux {
+                                                       groups = "i2c0_sck_z1";
+                                                       function = "i2c0";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       i2c0_sda_z7_pins: i2c0-sda-z7 {
+                                               mux {
+                                                       groups = "i2c0_sda_z7";
+                                                       function = "i2c0";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       i2c0_sda_z8_pins: i2c0-sda-z8 {
+                                               mux {
+                                                       groups = "i2c0_sda_z8";
+                                                       function = "i2c0";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       i2c1_sda_x_pins: i2c1-sda-x {
+                                               mux {
+                                                       groups = "i2c1_sda_x";
+                                                       function = "i2c1";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       i2c1_sck_x_pins: i2c1-sck-x {
+                                               mux {
+                                                       groups = "i2c1_sck_x";
+                                                       function = "i2c1";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       i2c1_sda_h2_pins: i2c1-sda-h2 {
+                                               mux {
+                                                       groups = "i2c1_sda_h2";
+                                                       function = "i2c1";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       i2c1_sck_h3_pins: i2c1-sck-h3 {
+                                               mux {
+                                                       groups = "i2c1_sck_h3";
+                                                       function = "i2c1";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       i2c1_sda_h6_pins: i2c1-sda-h6 {
+                                               mux {
+                                                       groups = "i2c1_sda_h6";
+                                                       function = "i2c1";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       i2c1_sck_h7_pins: i2c1-sck-h7 {
+                                               mux {
+                                                       groups = "i2c1_sck_h7";
+                                                       function = "i2c1";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       i2c2_sda_x_pins: i2c2-sda-x {
+                                               mux {
+                                                       groups = "i2c2_sda_x";
+                                                       function = "i2c2";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       i2c2_sck_x_pins: i2c2-sck-x {
+                                               mux {
+                                                       groups = "i2c2_sck_x";
+                                                       function = "i2c2";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       i2c2_sda_z_pins: i2c2-sda-z {
+                                               mux {
+                                                       groups = "i2c2_sda_z";
+                                                       function = "i2c2";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       i2c2_sck_z_pins: i2c2-sck-z {
+                                               mux {
+                                                       groups = "i2c2_sck_z";
+                                                       function = "i2c2";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       i2c3_sda_h_pins: i2c3-sda-h {
+                                               mux {
+                                                       groups = "i2c3_sda_h";
+                                                       function = "i2c3";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       i2c3_sck_h_pins: i2c3-sck-h {
+                                               mux {
+                                                       groups = "i2c3_sck_h";
+                                                       function = "i2c3";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       i2c3_sda_a_pins: i2c3-sda-a {
+                                               mux {
+                                                       groups = "i2c3_sda_a";
+                                                       function = "i2c3";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       i2c3_sck_a_pins: i2c3-sck-a {
+                                               mux {
+                                                       groups = "i2c3_sck_a";
+                                                       function = "i2c3";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       mclk0_a_pins: mclk0-a {
+                                               mux {
+                                                       groups = "mclk0_a";
+                                                       function = "mclk0";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       mclk1_a_pins: mclk1-a {
+                                               mux {
+                                                       groups = "mclk1_a";
+                                                       function = "mclk1";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       mclk1_x_pins: mclk1-x {
+                                               mux {
+                                                       groups = "mclk1_x";
+                                                       function = "mclk1";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       mclk1_z_pins: mclk1-z {
+                                               mux {
+                                                       groups = "mclk1_z";
+                                                       function = "mclk1";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       pdm_din0_a_pins: pdm-din0-a {
+                                               mux {
+                                                       groups = "pdm_din0_a";
+                                                       function = "pdm";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pdm_din0_c_pins: pdm-din0-c {
+                                               mux {
+                                                       groups = "pdm_din0_c";
+                                                       function = "pdm";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pdm_din0_x_pins: pdm-din0-x {
+                                               mux {
+                                                       groups = "pdm_din0_x";
+                                                       function = "pdm";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pdm_din0_z_pins: pdm-din0-z {
+                                               mux {
+                                                       groups = "pdm_din0_z";
+                                                       function = "pdm";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pdm_din1_a_pins: pdm-din1-a {
+                                               mux {
+                                                       groups = "pdm_din1_a";
+                                                       function = "pdm";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pdm_din1_c_pins: pdm-din1-c {
+                                               mux {
+                                                       groups = "pdm_din1_c";
+                                                       function = "pdm";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pdm_din1_x_pins: pdm-din1-x {
+                                               mux {
+                                                       groups = "pdm_din1_x";
+                                                       function = "pdm";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pdm_din1_z_pins: pdm-din1-z {
+                                               mux {
+                                                       groups = "pdm_din1_z";
+                                                       function = "pdm";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pdm_din2_a_pins: pdm-din2-a {
+                                               mux {
+                                                       groups = "pdm_din2_a";
+                                                       function = "pdm";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pdm_din2_c_pins: pdm-din2-c {
+                                               mux {
+                                                       groups = "pdm_din2_c";
+                                                       function = "pdm";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pdm_din2_x_pins: pdm-din2-x {
+                                               mux {
+                                                       groups = "pdm_din2_x";
+                                                       function = "pdm";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pdm_din2_z_pins: pdm-din2-z {
+                                               mux {
+                                                       groups = "pdm_din2_z";
+                                                       function = "pdm";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pdm_din3_a_pins: pdm-din3-a {
+                                               mux {
+                                                       groups = "pdm_din3_a";
+                                                       function = "pdm";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pdm_din3_c_pins: pdm-din3-c {
+                                               mux {
+                                                       groups = "pdm_din3_c";
+                                                       function = "pdm";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pdm_din3_x_pins: pdm-din3-x {
+                                               mux {
+                                                       groups = "pdm_din3_x";
+                                                       function = "pdm";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pdm_din3_z_pins: pdm-din3-z {
+                                               mux {
+                                                       groups = "pdm_din3_z";
+                                                       function = "pdm";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pdm_dclk_a_pins: pdm-dclk-a {
+                                               mux {
+                                                       groups = "pdm_dclk_a";
+                                                       function = "pdm";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <500>;
+                                               };
+                                       };
+
+                                       pdm_dclk_c_pins: pdm-dclk-c {
+                                               mux {
+                                                       groups = "pdm_dclk_c";
+                                                       function = "pdm";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <500>;
+                                               };
+                                       };
+
+                                       pdm_dclk_x_pins: pdm-dclk-x {
+                                               mux {
+                                                       groups = "pdm_dclk_x";
+                                                       function = "pdm";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <500>;
+                                               };
+                                       };
+
+                                       pdm_dclk_z_pins: pdm-dclk-z {
+                                               mux {
+                                                       groups = "pdm_dclk_z";
+                                                       function = "pdm";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <500>;
+                                               };
+                                       };
+
+                                       pwm_a_pins: pwm-a {
+                                               mux {
+                                                       groups = "pwm_a";
+                                                       function = "pwm_a";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pwm_b_x7_pins: pwm-b-x7 {
+                                               mux {
+                                                       groups = "pwm_b_x7";
+                                                       function = "pwm_b";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pwm_b_x19_pins: pwm-b-x19 {
+                                               mux {
+                                                       groups = "pwm_b_x19";
+                                                       function = "pwm_b";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pwm_c_c_pins: pwm-c-c {
+                                               mux {
+                                                       groups = "pwm_c_c";
+                                                       function = "pwm_c";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pwm_c_x5_pins: pwm-c-x5 {
+                                               mux {
+                                                       groups = "pwm_c_x5";
+                                                       function = "pwm_c";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pwm_c_x8_pins: pwm-c-x8 {
+                                               mux {
+                                                       groups = "pwm_c_x8";
+                                                       function = "pwm_c";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pwm_d_x3_pins: pwm-d-x3 {
+                                               mux {
+                                                       groups = "pwm_d_x3";
+                                                       function = "pwm_d";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pwm_d_x6_pins: pwm-d-x6 {
+                                               mux {
+                                                       groups = "pwm_d_x6";
+                                                       function = "pwm_d";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pwm_e_pins: pwm-e {
+                                               mux {
+                                                       groups = "pwm_e";
+                                                       function = "pwm_e";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pwm_f_x_pins: pwm-f-x {
+                                               mux {
+                                                       groups = "pwm_f_x";
+                                                       function = "pwm_f";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pwm_f_h_pins: pwm-f-h {
+                                               mux {
+                                                       groups = "pwm_f_h";
+                                                       function = "pwm_f";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       sdcard_c_pins: sdcard_c {
+                                               mux-0 {
+                                                       groups = "sdcard_d0_c",
+                                                                "sdcard_d1_c",
+                                                                "sdcard_d2_c",
+                                                                "sdcard_d3_c",
+                                                                "sdcard_cmd_c";
+                                                       function = "sdcard";
+                                                       bias-pull-up;
+                                                       drive-strength-microamp = <4000>;
+                                               };
+
+                                               mux-1 {
+                                                       groups = "sdcard_clk_c";
+                                                       function = "sdcard";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <4000>;
+                                               };
+                                       };
+
+                                       sdcard_clk_gate_c_pins: sdcard_clk_gate_c {
+                                               mux {
+                                                       groups = "GPIOC_4";
+                                                       function = "gpio_periphs";
+                                                       bias-pull-down;
+                                                       drive-strength-microamp = <4000>;
+                                               };
+                                       };
+
+                                       sdcard_z_pins: sdcard_z {
+                                               mux-0 {
+                                                       groups = "sdcard_d0_z",
+                                                                "sdcard_d1_z",
+                                                                "sdcard_d2_z",
+                                                                "sdcard_d3_z",
+                                                                "sdcard_cmd_z";
+                                                       function = "sdcard";
+                                                       bias-pull-up;
+                                                       drive-strength-microamp = <4000>;
+                                               };
+
+                                               mux-1 {
+                                                       groups = "sdcard_clk_z";
+                                                       function = "sdcard";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <4000>;
+                                               };
+                                       };
+
+                                       sdcard_clk_gate_z_pins: sdcard_clk_gate_z {
+                                               mux {
+                                                       groups = "GPIOZ_6";
+                                                       function = "gpio_periphs";
+                                                       bias-pull-down;
+                                                       drive-strength-microamp = <4000>;
+                                               };
+                                       };
+
+                                       sdio_pins: sdio {
+                                               mux {
+                                                       groups = "sdio_d0",
+                                                                "sdio_d1",
+                                                                "sdio_d2",
+                                                                "sdio_d3",
+                                                                "sdio_clk",
+                                                                "sdio_cmd";
+                                                       function = "sdio";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <4000>;
+                                               };
+                                       };
+
+                                       sdio_clk_gate_pins: sdio_clk_gate {
+                                               mux {
+                                                       groups = "GPIOX_4";
+                                                       function = "gpio_periphs";
+                                                       bias-pull-down;
+                                                       drive-strength-microamp = <4000>;
+                                               };
+                                       };
+
+                                       spdif_in_a10_pins: spdif-in-a10 {
+                                               mux {
+                                                       groups = "spdif_in_a10";
+                                                       function = "spdif_in";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       spdif_in_a12_pins: spdif-in-a12 {
+                                               mux {
+                                                       groups = "spdif_in_a12";
+                                                       function = "spdif_in";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       spdif_in_h_pins: spdif-in-h {
+                                               mux {
+                                                       groups = "spdif_in_h";
+                                                       function = "spdif_in";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       spdif_out_h_pins: spdif-out-h {
+                                               mux {
+                                                       groups = "spdif_out_h";
+                                                       function = "spdif_out";
+                                                       drive-strength-microamp = <500>;
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       spdif_out_a11_pins: spdif-out-a11 {
+                                               mux {
+                                                       groups = "spdif_out_a11";
+                                                       function = "spdif_out";
+                                                       drive-strength-microamp = <500>;
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       spdif_out_a13_pins: spdif-out-a13 {
+                                               mux {
+                                                       groups = "spdif_out_a13";
+                                                       function = "spdif_out";
+                                                       drive-strength-microamp = <500>;
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_a_din0_pins: tdm-a-din0 {
+                                               mux {
+                                                       groups = "tdm_a_din0";
+                                                       function = "tdm_a";
+                                                       bias-disable;
+                                               };
+                                       };
+
+
+                                       tdm_a_din1_pins: tdm-a-din1 {
+                                               mux {
+                                                       groups = "tdm_a_din1";
+                                                       function = "tdm_a";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_a_dout0_pins: tdm-a-dout0 {
+                                               mux {
+                                                       groups = "tdm_a_dout0";
+                                                       function = "tdm_a";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_a_dout1_pins: tdm-a-dout1 {
+                                               mux {
+                                                       groups = "tdm_a_dout1";
+                                                       function = "tdm_a";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_a_fs_pins: tdm-a-fs {
+                                               mux {
+                                                       groups = "tdm_a_fs";
+                                                       function = "tdm_a";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_a_sclk_pins: tdm-a-sclk {
+                                               mux {
+                                                       groups = "tdm_a_sclk";
+                                                       function = "tdm_a";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_a_slv_fs_pins: tdm-a-slv-fs {
+                                               mux {
+                                                       groups = "tdm_a_slv_fs";
+                                                       function = "tdm_a";
+                                                       bias-disable;
+                                               };
+                                       };
+
+
+                                       tdm_a_slv_sclk_pins: tdm-a-slv-sclk {
+                                               mux {
+                                                       groups = "tdm_a_slv_sclk";
+                                                       function = "tdm_a";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_b_din0_pins: tdm-b-din0 {
+                                               mux {
+                                                       groups = "tdm_b_din0";
+                                                       function = "tdm_b";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_b_din1_pins: tdm-b-din1 {
+                                               mux {
+                                                       groups = "tdm_b_din1";
+                                                       function = "tdm_b";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_b_din2_pins: tdm-b-din2 {
+                                               mux {
+                                                       groups = "tdm_b_din2";
+                                                       function = "tdm_b";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_b_din3_a_pins: tdm-b-din3-a {
+                                               mux {
+                                                       groups = "tdm_b_din3_a";
+                                                       function = "tdm_b";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_b_din3_h_pins: tdm-b-din3-h {
+                                               mux {
+                                                       groups = "tdm_b_din3_h";
+                                                       function = "tdm_b";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_b_dout0_pins: tdm-b-dout0 {
+                                               mux {
+                                                       groups = "tdm_b_dout0";
+                                                       function = "tdm_b";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_b_dout1_pins: tdm-b-dout1 {
+                                               mux {
+                                                       groups = "tdm_b_dout1";
+                                                       function = "tdm_b";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_b_dout2_pins: tdm-b-dout2 {
+                                               mux {
+                                                       groups = "tdm_b_dout2";
+                                                       function = "tdm_b";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_b_dout3_a_pins: tdm-b-dout3-a {
+                                               mux {
+                                                       groups = "tdm_b_dout3_a";
+                                                       function = "tdm_b";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_b_dout3_h_pins: tdm-b-dout3-h {
+                                               mux {
+                                                       groups = "tdm_b_dout3_h";
+                                                       function = "tdm_b";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_b_fs_pins: tdm-b-fs {
+                                               mux {
+                                                       groups = "tdm_b_fs";
+                                                       function = "tdm_b";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_b_sclk_pins: tdm-b-sclk {
+                                               mux {
+                                                       groups = "tdm_b_sclk";
+                                                       function = "tdm_b";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_b_slv_fs_pins: tdm-b-slv-fs {
+                                               mux {
+                                                       groups = "tdm_b_slv_fs";
+                                                       function = "tdm_b";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_b_slv_sclk_pins: tdm-b-slv-sclk {
+                                               mux {
+                                                       groups = "tdm_b_slv_sclk";
+                                                       function = "tdm_b";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_c_din0_a_pins: tdm-c-din0-a {
+                                               mux {
+                                                       groups = "tdm_c_din0_a";
+                                                       function = "tdm_c";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_c_din0_z_pins: tdm-c-din0-z {
+                                               mux {
+                                                       groups = "tdm_c_din0_z";
+                                                       function = "tdm_c";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_c_din1_a_pins: tdm-c-din1-a {
+                                               mux {
+                                                       groups = "tdm_c_din1_a";
+                                                       function = "tdm_c";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_c_din1_z_pins: tdm-c-din1-z {
+                                               mux {
+                                                       groups = "tdm_c_din1_z";
+                                                       function = "tdm_c";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_c_din2_a_pins: tdm-c-din2-a {
+                                               mux {
+                                                       groups = "tdm_c_din2_a";
+                                                       function = "tdm_c";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       eth_leds_pins: eth-leds {
+                                               mux {
+                                                       groups = "eth_link_led",
+                                                                "eth_act_led";
+                                                       function = "eth";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       eth_pins: eth {
+                                               mux {
+                                                       groups = "eth_mdio",
+                                                                "eth_mdc",
+                                                                "eth_rgmii_rx_clk",
+                                                                "eth_rx_dv",
+                                                                "eth_rxd0",
+                                                                "eth_rxd1",
+                                                                "eth_txen",
+                                                                "eth_txd0",
+                                                                "eth_txd1";
+                                                       function = "eth";
+                                                       drive-strength-microamp = <4000>;
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       eth_rgmii_pins: eth-rgmii {
+                                               mux {
+                                                       groups = "eth_rxd2_rgmii",
+                                                                "eth_rxd3_rgmii",
+                                                                "eth_rgmii_tx_clk",
+                                                                "eth_txd2_rgmii",
+                                                                "eth_txd3_rgmii";
+                                                       function = "eth";
+                                                       drive-strength-microamp = <4000>;
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_c_din2_z_pins: tdm-c-din2-z {
+                                               mux {
+                                                       groups = "tdm_c_din2_z";
+                                                       function = "tdm_c";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_c_din3_a_pins: tdm-c-din3-a {
+                                               mux {
+                                                       groups = "tdm_c_din3_a";
+                                                       function = "tdm_c";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_c_din3_z_pins: tdm-c-din3-z {
+                                               mux {
+                                                       groups = "tdm_c_din3_z";
+                                                       function = "tdm_c";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_c_dout0_a_pins: tdm-c-dout0-a {
+                                               mux {
+                                                       groups = "tdm_c_dout0_a";
+                                                       function = "tdm_c";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_c_dout0_z_pins: tdm-c-dout0-z {
+                                               mux {
+                                                       groups = "tdm_c_dout0_z";
+                                                       function = "tdm_c";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_c_dout1_a_pins: tdm-c-dout1-a {
+                                               mux {
+                                                       groups = "tdm_c_dout1_a";
+                                                       function = "tdm_c";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_c_dout1_z_pins: tdm-c-dout1-z {
+                                               mux {
+                                                       groups = "tdm_c_dout1_z";
+                                                       function = "tdm_c";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_c_dout2_a_pins: tdm-c-dout2-a {
+                                               mux {
+                                                       groups = "tdm_c_dout2_a";
+                                                       function = "tdm_c";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_c_dout2_z_pins: tdm-c-dout2-z {
+                                               mux {
+                                                       groups = "tdm_c_dout2_z";
+                                                       function = "tdm_c";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_c_dout3_a_pins: tdm-c-dout3-a {
+                                               mux {
+                                                       groups = "tdm_c_dout3_a";
+                                                       function = "tdm_c";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_c_dout3_z_pins: tdm-c-dout3-z {
+                                               mux {
+                                                       groups = "tdm_c_dout3_z";
+                                                       function = "tdm_c";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_c_fs_a_pins: tdm-c-fs-a {
+                                               mux {
+                                                       groups = "tdm_c_fs_a";
+                                                       function = "tdm_c";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_c_fs_z_pins: tdm-c-fs-z {
+                                               mux {
+                                                       groups = "tdm_c_fs_z";
+                                                       function = "tdm_c";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_c_sclk_a_pins: tdm-c-sclk-a {
                                                mux {
-                                                       groups = "cec_ao_a_h";
-                                                       function = "cec_ao_a_h";
+                                                       groups = "tdm_c_sclk_a";
+                                                       function = "tdm_c";
                                                        bias-disable;
+                                                       drive-strength-microamp = <3000>;
                                                };
                                        };
 
-                                       cec_ao_b_h_pins: cec_ao_b_h {
+                                       tdm_c_sclk_z_pins: tdm-c-sclk-z {
                                                mux {
-                                                       groups = "cec_ao_b_h";
-                                                       function = "cec_ao_b_h";
+                                                       groups = "tdm_c_sclk_z";
+                                                       function = "tdm_c";
                                                        bias-disable;
+                                                       drive-strength-microamp = <3000>;
                                                };
                                        };
 
-                                       hdmitx_ddc_pins: hdmitx_ddc {
+                                       tdm_c_slv_fs_a_pins: tdm-c-slv-fs-a {
                                                mux {
-                                                       groups = "hdmitx_sda",
-                                                                "hdmitx_sck";
-                                                       function = "hdmitx";
+                                                       groups = "tdm_c_slv_fs_a";
+                                                       function = "tdm_c";
                                                        bias-disable;
                                                };
                                        };
 
-                                       hdmitx_hpd_pins: hdmitx_hpd {
+                                       tdm_c_slv_fs_z_pins: tdm-c-slv-fs-z {
                                                mux {
-                                                       groups = "hdmitx_hpd_in";
-                                                       function = "hdmitx";
+                                                       groups = "tdm_c_slv_fs_z";
+                                                       function = "tdm_c";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_c_slv_sclk_a_pins: tdm-c-slv-sclk-a {
+                                               mux {
+                                                       groups = "tdm_c_slv_sclk_a";
+                                                       function = "tdm_c";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_c_slv_sclk_z_pins: tdm-c-slv-sclk-z {
+                                               mux {
+                                                       groups = "tdm_c_slv_sclk_z";
+                                                       function = "tdm_c";
                                                        bias-disable;
                                                };
                                        };
                                };
                        };
 
+                       pdm: audio-controller@40000 {
+                               compatible = "amlogic,g12a-pdm",
+                                            "amlogic,axg-pdm";
+                               reg = <0x0 0x40000 0x0 0x34>;
+                               #sound-dai-cells = <0>;
+                               sound-name-prefix = "PDM";
+                               clocks = <&clkc_audio AUD_CLKID_PDM>,
+                                        <&clkc_audio AUD_CLKID_PDM_DCLK>,
+                                        <&clkc_audio AUD_CLKID_PDM_SYSCLK>;
+                               clock-names = "pclk", "dclk", "sysclk";
+                               status = "disabled";
+                       };
+
+                       audio: bus@42000 {
+                               compatible = "simple-bus";
+                               reg = <0x0 0x42000 0x0 0x2000>;
+                               #address-cells = <2>;
+                               #size-cells = <2>;
+                               ranges = <0x0 0x0 0x0 0x42000 0x0 0x2000>;
+
+                               clkc_audio: clock-controller@0 {
+                                       status = "disabled";
+                                       compatible = "amlogic,g12a-audio-clkc";
+                                       reg = <0x0 0x0 0x0 0xb4>;
+                                       #clock-cells = <1>;
+
+                                       clocks = <&clkc CLKID_AUDIO>,
+                                                <&clkc CLKID_MPLL0>,
+                                                <&clkc CLKID_MPLL1>,
+                                                <&clkc CLKID_MPLL2>,
+                                                <&clkc CLKID_MPLL3>,
+                                                <&clkc CLKID_HIFI_PLL>,
+                                                <&clkc CLKID_FCLK_DIV3>,
+                                                <&clkc CLKID_FCLK_DIV4>,
+                                                <&clkc CLKID_GP0_PLL>;
+                                       clock-names = "pclk",
+                                                     "mst_in0",
+                                                     "mst_in1",
+                                                     "mst_in2",
+                                                     "mst_in3",
+                                                     "mst_in4",
+                                                     "mst_in5",
+                                                     "mst_in6",
+                                                     "mst_in7";
+
+                                       resets = <&reset RESET_AUDIO>;
+                               };
+
+                               toddr_a: audio-controller@100 {
+                                       compatible = "amlogic,g12a-toddr",
+                                                    "amlogic,axg-toddr";
+                                       reg = <0x0 0x100 0x0 0x1c>;
+                                       #sound-dai-cells = <0>;
+                                       sound-name-prefix = "TODDR_A";
+                                       interrupts = <GIC_SPI 148 IRQ_TYPE_EDGE_RISING>;
+                                       clocks = <&clkc_audio AUD_CLKID_TODDR_A>;
+                                       resets = <&arb AXG_ARB_TODDR_A>;
+                                       status = "disabled";
+                               };
+
+                               toddr_b: audio-controller@140 {
+                                       compatible = "amlogic,g12a-toddr",
+                                                    "amlogic,axg-toddr";
+                                       reg = <0x0 0x140 0x0 0x1c>;
+                                       #sound-dai-cells = <0>;
+                                       sound-name-prefix = "TODDR_B";
+                                       interrupts = <GIC_SPI 149 IRQ_TYPE_EDGE_RISING>;
+                                       clocks = <&clkc_audio AUD_CLKID_TODDR_B>;
+                                       resets = <&arb AXG_ARB_TODDR_B>;
+                                       status = "disabled";
+                               };
+
+                               toddr_c: audio-controller@180 {
+                                       compatible = "amlogic,g12a-toddr",
+                                                    "amlogic,axg-toddr";
+                                       reg = <0x0 0x180 0x0 0x1c>;
+                                       #sound-dai-cells = <0>;
+                                       sound-name-prefix = "TODDR_C";
+                                       interrupts = <GIC_SPI 150 IRQ_TYPE_EDGE_RISING>;
+                                       clocks = <&clkc_audio AUD_CLKID_TODDR_C>;
+                                       resets = <&arb AXG_ARB_TODDR_C>;
+                                       status = "disabled";
+                               };
+
+                               frddr_a: audio-controller@1c0 {
+                                       compatible = "amlogic,g12a-frddr",
+                                                    "amlogic,axg-frddr";
+                                       reg = <0x0 0x1c0 0x0 0x1c>;
+                                       #sound-dai-cells = <0>;
+                                       sound-name-prefix = "FRDDR_A";
+                                       interrupts = <GIC_SPI 152 IRQ_TYPE_EDGE_RISING>;
+                                       clocks = <&clkc_audio AUD_CLKID_FRDDR_A>;
+                                       resets = <&arb AXG_ARB_FRDDR_A>;
+                                       status = "disabled";
+                               };
+
+                               frddr_b: audio-controller@200 {
+                                       compatible = "amlogic,g12a-frddr",
+                                                    "amlogic,axg-frddr";
+                                       reg = <0x0 0x200 0x0 0x1c>;
+                                       #sound-dai-cells = <0>;
+                                       sound-name-prefix = "FRDDR_B";
+                                       interrupts = <GIC_SPI 153 IRQ_TYPE_EDGE_RISING>;
+                                       clocks = <&clkc_audio AUD_CLKID_FRDDR_B>;
+                                       resets = <&arb AXG_ARB_FRDDR_B>;
+                                       status = "disabled";
+                               };
+
+                               frddr_c: audio-controller@240 {
+                                       compatible = "amlogic,g12a-frddr",
+                                                    "amlogic,axg-frddr";
+                                       reg = <0x0 0x240 0x0 0x1c>;
+                                       #sound-dai-cells = <0>;
+                                       sound-name-prefix = "FRDDR_C";
+                                       interrupts = <GIC_SPI 154 IRQ_TYPE_EDGE_RISING>;
+                                       clocks = <&clkc_audio AUD_CLKID_FRDDR_C>;
+                                       resets = <&arb AXG_ARB_FRDDR_C>;
+                                       status = "disabled";
+                               };
+
+                               arb: reset-controller@280 {
+                                       status = "disabled";
+                                       compatible = "amlogic,meson-axg-audio-arb";
+                                       reg = <0x0 0x280 0x0 0x4>;
+                                       #reset-cells = <1>;
+                                       clocks = <&clkc_audio AUD_CLKID_DDR_ARB>;
+                               };
+
+                               tdmin_a: audio-controller@300 {
+                                       compatible = "amlogic,g12a-tdmin",
+                                                    "amlogic,axg-tdmin";
+                                       reg = <0x0 0x300 0x0 0x40>;
+                                       sound-name-prefix = "TDMIN_A";
+                                       clocks = <&clkc_audio AUD_CLKID_TDMIN_A>,
+                                                <&clkc_audio AUD_CLKID_TDMIN_A_SCLK>,
+                                                <&clkc_audio AUD_CLKID_TDMIN_A_SCLK_SEL>,
+                                                <&clkc_audio AUD_CLKID_TDMIN_A_LRCLK>,
+                                                <&clkc_audio AUD_CLKID_TDMIN_A_LRCLK>;
+                                       clock-names = "pclk", "sclk", "sclk_sel",
+                                                     "lrclk", "lrclk_sel";
+                                       status = "disabled";
+                               };
+
+                               tdmin_b: audio-controller@340 {
+                                       compatible = "amlogic,g12a-tdmin",
+                                                    "amlogic,axg-tdmin";
+                                       reg = <0x0 0x340 0x0 0x40>;
+                                       sound-name-prefix = "TDMIN_B";
+                                       clocks = <&clkc_audio AUD_CLKID_TDMIN_B>,
+                                                <&clkc_audio AUD_CLKID_TDMIN_B_SCLK>,
+                                                <&clkc_audio AUD_CLKID_TDMIN_B_SCLK_SEL>,
+                                                <&clkc_audio AUD_CLKID_TDMIN_B_LRCLK>,
+                                                <&clkc_audio AUD_CLKID_TDMIN_B_LRCLK>;
+                                       clock-names = "pclk", "sclk", "sclk_sel",
+                                                     "lrclk", "lrclk_sel";
+                                       status = "disabled";
+                               };
+
+                               tdmin_c: audio-controller@380 {
+                                       compatible = "amlogic,g12a-tdmin",
+                                                    "amlogic,axg-tdmin";
+                                       reg = <0x0 0x380 0x0 0x40>;
+                                       sound-name-prefix = "TDMIN_C";
+                                       clocks = <&clkc_audio AUD_CLKID_TDMIN_C>,
+                                                <&clkc_audio AUD_CLKID_TDMIN_C_SCLK>,
+                                                <&clkc_audio AUD_CLKID_TDMIN_C_SCLK_SEL>,
+                                                <&clkc_audio AUD_CLKID_TDMIN_C_LRCLK>,
+                                                <&clkc_audio AUD_CLKID_TDMIN_C_LRCLK>;
+                                       clock-names = "pclk", "sclk", "sclk_sel",
+                                                     "lrclk", "lrclk_sel";
+                                       status = "disabled";
+                               };
+
+                               tdmin_lb: audio-controller@3c0 {
+                                       compatible = "amlogic,g12a-tdmin",
+                                                    "amlogic,axg-tdmin";
+                                       reg = <0x0 0x3c0 0x0 0x40>;
+                                       sound-name-prefix = "TDMIN_LB";
+                                       clocks = <&clkc_audio AUD_CLKID_TDMIN_LB>,
+                                                <&clkc_audio AUD_CLKID_TDMIN_LB_SCLK>,
+                                                <&clkc_audio AUD_CLKID_TDMIN_LB_SCLK_SEL>,
+                                                <&clkc_audio AUD_CLKID_TDMIN_LB_LRCLK>,
+                                                <&clkc_audio AUD_CLKID_TDMIN_LB_LRCLK>;
+                                       clock-names = "pclk", "sclk", "sclk_sel",
+                                                     "lrclk", "lrclk_sel";
+                                       status = "disabled";
+                               };
+
+                               spdifin: audio-controller@400 {
+                                       compatible = "amlogic,g12a-spdifin",
+                                                    "amlogic,axg-spdifin";
+                                       reg = <0x0 0x400 0x0 0x30>;
+                                       #sound-dai-cells = <0>;
+                                       sound-name-prefix = "SPDIFIN";
+                                       interrupts = <GIC_SPI 151 IRQ_TYPE_EDGE_RISING>;
+                                       clocks = <&clkc_audio AUD_CLKID_SPDIFIN>,
+                                                <&clkc_audio AUD_CLKID_SPDIFIN_CLK>;
+                                       clock-names = "pclk", "refclk";
+                                       status = "disabled";
+                               };
+
+                               spdifout: audio-controller@480 {
+                                       compatible = "amlogic,g12a-spdifout",
+                                                    "amlogic,axg-spdifout";
+                                       reg = <0x0 0x480 0x0 0x50>;
+                                       #sound-dai-cells = <0>;
+                                       sound-name-prefix = "SPDIFOUT";
+                                       clocks = <&clkc_audio AUD_CLKID_SPDIFOUT>,
+                                                <&clkc_audio AUD_CLKID_SPDIFOUT_CLK>;
+                                       clock-names = "pclk", "mclk";
+                                       status = "disabled";
+                               };
+
+                               tdmout_a: audio-controller@500 {
+                                       compatible = "amlogic,g12a-tdmout";
+                                       reg = <0x0 0x500 0x0 0x40>;
+                                       sound-name-prefix = "TDMOUT_A";
+                                       clocks = <&clkc_audio AUD_CLKID_TDMOUT_A>,
+                                                <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK>,
+                                                <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK_SEL>,
+                                                <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>,
+                                                <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>;
+                                       clock-names = "pclk", "sclk", "sclk_sel",
+                                                     "lrclk", "lrclk_sel";
+                                       status = "disabled";
+                               };
+
+                               tdmout_b: audio-controller@540 {
+                                       compatible = "amlogic,g12a-tdmout";
+                                       reg = <0x0 0x540 0x0 0x40>;
+                                       sound-name-prefix = "TDMOUT_B";
+                                       clocks = <&clkc_audio AUD_CLKID_TDMOUT_B>,
+                                                <&clkc_audio AUD_CLKID_TDMOUT_B_SCLK>,
+                                                <&clkc_audio AUD_CLKID_TDMOUT_B_SCLK_SEL>,
+                                                <&clkc_audio AUD_CLKID_TDMOUT_B_LRCLK>,
+                                                <&clkc_audio AUD_CLKID_TDMOUT_B_LRCLK>;
+                                       clock-names = "pclk", "sclk", "sclk_sel",
+                                                     "lrclk", "lrclk_sel";
+                                       status = "disabled";
+                               };
+
+                               tdmout_c: audio-controller@580 {
+                                       compatible = "amlogic,g12a-tdmout";
+                                       reg = <0x0 0x580 0x0 0x40>;
+                                       sound-name-prefix = "TDMOUT_C";
+                                       clocks = <&clkc_audio AUD_CLKID_TDMOUT_C>,
+                                                <&clkc_audio AUD_CLKID_TDMOUT_C_SCLK>,
+                                                <&clkc_audio AUD_CLKID_TDMOUT_C_SCLK_SEL>,
+                                                <&clkc_audio AUD_CLKID_TDMOUT_C_LRCLK>,
+                                                <&clkc_audio AUD_CLKID_TDMOUT_C_LRCLK>;
+                                       clock-names = "pclk", "sclk", "sclk_sel",
+                                                     "lrclk", "lrclk_sel";
+                                       status = "disabled";
+                               };
+
+                               spdifout_b: audio-controller@680 {
+                                       compatible = "amlogic,g12a-spdifout",
+                                                    "amlogic,axg-spdifout";
+                                       reg = <0x0 0x680 0x0 0x50>;
+                                       #sound-dai-cells = <0>;
+                                       sound-name-prefix = "SPDIFOUT_B";
+                                       clocks = <&clkc_audio AUD_CLKID_SPDIFOUT_B>,
+                                                <&clkc_audio AUD_CLKID_SPDIFOUT_B_CLK>;
+                                       clock-names = "pclk", "mclk";
+                                       status = "disabled";
+                               };
+
+                               tohdmitx: audio-controller@744 {
+                                       compatible = "amlogic,g12a-tohdmitx";
+                                       reg = <0x0 0x744 0x0 0x4>;
+                                       #sound-dai-cells = <1>;
+                                       sound-name-prefix = "TOHDMITX";
+                                       status = "disabled";
+                               };
+                       };
+
                        usb3_pcie_phy: phy@46000 {
                                compatible = "amlogic,g12a-usb3-pcie-phy";
                                reg = <0x0 0x46000 0x0 0x2000>;
                                assigned-clock-rates = <100000000>;
                                #phy-cells = <1>;
                        };
+
+                       eth_phy: mdio-multiplexer@4c000 {
+                               compatible = "amlogic,g12a-mdio-mux";
+                               reg = <0x0 0x4c000 0x0 0xa4>;
+                               clocks = <&clkc CLKID_ETH_PHY>,
+                                        <&xtal>,
+                                        <&clkc CLKID_MPLL_50M>;
+                               clock-names = "pclk", "clkin0", "clkin1";
+                               mdio-parent-bus = <&mdio0>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               ext_mdio: mdio@0 {
+                                       reg = <0>;
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+                               };
+
+                               int_mdio: mdio@1 {
+                                       reg = <1>;
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       internal_ephy: ethernet_phy@8 {
+                                               compatible = "ethernet-phy-id0180.3301",
+                                                            "ethernet-phy-ieee802.3-c22";
+                                               interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+                                               reg = <8>;
+                                               max-speed = <100>;
+                                       };
+                               };
+                       };
                };
 
                aobus: bus@ff800000 {
                                                gpio-ranges = <&ao_pinctrl 0 0 15>;
                                        };
 
+                                       i2c_ao_sck_pins: i2c_ao_sck_pins {
+                                               mux {
+                                                       groups = "i2c_ao_sck";
+                                                       function = "i2c_ao";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       i2c_ao_sda_pins: i2c_ao_sda {
+                                               mux {
+                                                       groups = "i2c_ao_sda";
+                                                       function = "i2c_ao";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       i2c_ao_sck_e_pins: i2c_ao_sck_e {
+                                               mux {
+                                                       groups = "i2c_ao_sck_e";
+                                                       function = "i2c_ao";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       i2c_ao_sda_e_pins: i2c_ao_sda_e {
+                                               mux {
+                                                       groups = "i2c_ao_sda_e";
+                                                       function = "i2c_ao";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       mclk0_ao_pins: mclk0-ao {
+                                               mux {
+                                                       groups = "mclk0_ao";
+                                                       function = "mclk0_ao";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_ao_b_din0_pins: tdm-ao-b-din0 {
+                                               mux {
+                                                       groups = "tdm_ao_b_din0";
+                                                       function = "tdm_ao_b";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       spdif_ao_out_pins: spdif-ao-out {
+                                               mux {
+                                                       groups = "spdif_ao_out";
+                                                       function = "spdif_ao_out";
+                                                       drive-strength-microamp = <500>;
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_ao_b_din1_pins: tdm-ao-b-din1 {
+                                               mux {
+                                                       groups = "tdm_ao_b_din1";
+                                                       function = "tdm_ao_b";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_ao_b_din2_pins: tdm-ao-b-din2 {
+                                               mux {
+                                                       groups = "tdm_ao_b_din2";
+                                                       function = "tdm_ao_b";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_ao_b_dout0_pins: tdm-ao-b-dout0 {
+                                               mux {
+                                                       groups = "tdm_ao_b_dout0";
+                                                       function = "tdm_ao_b";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_ao_b_dout1_pins: tdm-ao-b-dout1 {
+                                               mux {
+                                                       groups = "tdm_ao_b_dout1";
+                                                       function = "tdm_ao_b";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_ao_b_dout2_pins: tdm-ao-b-dout2 {
+                                               mux {
+                                                       groups = "tdm_ao_b_dout2";
+                                                       function = "tdm_ao_b";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_ao_b_fs_pins: tdm-ao-b-fs {
+                                               mux {
+                                                       groups = "tdm_ao_b_fs";
+                                                       function = "tdm_ao_b";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_ao_b_sclk_pins: tdm-ao-b-sclk {
+                                               mux {
+                                                       groups = "tdm_ao_b_sclk";
+                                                       function = "tdm_ao_b";
+                                                       bias-disable;
+                                                       drive-strength-microamp = <3000>;
+                                               };
+                                       };
+
+                                       tdm_ao_b_slv_fs_pins: tdm-ao-b-slv-fs {
+                                               mux {
+                                                       groups = "tdm_ao_b_slv_fs";
+                                                       function = "tdm_ao_b";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       tdm_ao_b_slv_sclk_pins: tdm-ao-b-slv-sclk {
+                                               mux {
+                                                       groups = "tdm_ao_b_slv_sclk";
+                                                       function = "tdm_ao_b";
+                                                       bias-disable;
+                                               };
+                                       };
+
                                        uart_ao_a_pins: uart-a-ao {
                                                mux {
                                                        groups = "uart_ao_a_tx",
                                                        bias-disable;
                                                };
                                        };
+
+                                       pwm_ao_a_pins: pwm-ao-a {
+                                               mux {
+                                                       groups = "pwm_ao_a";
+                                                       function = "pwm_ao_a";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pwm_ao_b_pins: pwm-ao-b {
+                                               mux {
+                                                       groups = "pwm_ao_b";
+                                                       function = "pwm_ao_b";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pwm_ao_c_4_pins: pwm-ao-c-4 {
+                                               mux {
+                                                       groups = "pwm_ao_c_4";
+                                                       function = "pwm_ao_c";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pwm_ao_c_6_pins: pwm-ao-c-6 {
+                                               mux {
+                                                       groups = "pwm_ao_c_6";
+                                                       function = "pwm_ao_c";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pwm_ao_d_5_pins: pwm-ao-d-5 {
+                                               mux {
+                                                       groups = "pwm_ao_d_5";
+                                                       function = "pwm_ao_d";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pwm_ao_d_10_pins: pwm-ao-d-10 {
+                                               mux {
+                                                       groups = "pwm_ao_d_10";
+                                                       function = "pwm_ao_d";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       pwm_ao_d_e_pins: pwm-ao-d-e {
+                                               mux {
+                                                       groups = "pwm_ao_d_e";
+                                                       function = "pwm_ao_d";
+                                               };
+                                       };
+
+                                       remote_input_ao_pins: remote-input-ao {
+                                               mux {
+                                                       groups = "remote_ao_input";
+                                                       function = "remote_ao_input";
+                                                       bias-disable;
+                                               };
+                                       };
                                };
                        };
 
                                status = "disabled";
                        };
 
+                       pwm_AO_cd: pwm@2000 {
+                               compatible = "amlogic,meson-g12a-ao-pwm-cd";
+                               reg = <0x0 0x2000 0x0 0x20>;
+                               #pwm-cells = <3>;
+                               status = "disabled";
+                       };
+
                        uart_AO: serial@3000 {
                                compatible = "amlogic,meson-gx-uart",
                                             "amlogic,meson-ao-uart";
                                reg = <0x0 0x3000 0x0 0x18>;
                                interrupts = <GIC_SPI 193 IRQ_TYPE_EDGE_RISING>;
-                               clocks = <&xtal>, <&xtal>, <&xtal>;
+                               clocks = <&xtal>, <&clkc_AO CLKID_AO_UART>, <&xtal>;
                                clock-names = "xtal", "pclk", "baud";
                                status = "disabled";
                        };
                                             "amlogic,meson-ao-uart";
                                reg = <0x0 0x4000 0x0 0x18>;
                                interrupts = <GIC_SPI 197 IRQ_TYPE_EDGE_RISING>;
-                               clocks = <&xtal>, <&xtal>, <&xtal>;
+                               clocks = <&xtal>, <&clkc_AO CLKID_AO_UART2>, <&xtal>;
                                clock-names = "xtal", "pclk", "baud";
                                status = "disabled";
                        };
 
+                       i2c_AO: i2c@5000 {
+                               compatible = "amlogic,meson-axg-i2c";
+                               status = "disabled";
+                               reg = <0x0 0x05000 0x0 0x20>;
+                               interrupts = <GIC_SPI 195 IRQ_TYPE_EDGE_RISING>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               clocks = <&clkc CLKID_I2C>;
+                       };
+
+                       pwm_AO_ab: pwm@7000 {
+                               compatible = "amlogic,meson-g12a-ao-pwm-ab";
+                               reg = <0x0 0x7000 0x0 0x20>;
+                               #pwm-cells = <3>;
+                               status = "disabled";
+                       };
+
+                       ir: ir@8000 {
+                               compatible = "amlogic,meson-gxbb-ir";
+                               reg = <0x0 0x8000 0x0 0x20>;
+                               interrupts = <GIC_SPI 196 IRQ_TYPE_EDGE_RISING>;
+                               status = "disabled";
+                       };
+
                        saradc: adc@9000 {
                                compatible = "amlogic,meson-g12a-saradc",
                                             "amlogic,meson-saradc";
                                #reset-cells = <1>;
                        };
 
+                       gpio_intc: interrupt-controller@f080 {
+                               compatible = "amlogic,meson-g12a-gpio-intc",
+                                            "amlogic,meson-gpio-intc";
+                               reg = <0x0 0xf080 0x0 0x10>;
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                               amlogic,channel-interrupts = <64 65 66 67 68 69 70 71>;
+                       };
+
+                       pwm_ef: pwm@19000 {
+                               compatible = "amlogic,meson-g12a-ee-pwm";
+                               reg = <0x0 0x19000 0x0 0x20>;
+                               #pwm-cells = <3>;
+                               status = "disabled";
+                       };
+
+                       pwm_cd: pwm@1a000 {
+                               compatible = "amlogic,meson-g12a-ee-pwm";
+                               reg = <0x0 0x1a000 0x0 0x20>;
+                               #pwm-cells = <3>;
+                               status = "disabled";
+                       };
+
+                       pwm_ab: pwm@1b000 {
+                               compatible = "amlogic,meson-g12a-ee-pwm";
+                               reg = <0x0 0x1b000 0x0 0x20>;
+                               #pwm-cells = <3>;
+                               status = "disabled";
+                       };
+
+                       i2c3: i2c@1c000 {
+                               compatible = "amlogic,meson-axg-i2c";
+                               status = "disabled";
+                               reg = <0x0 0x1c000 0x0 0x20>;
+                               interrupts = <GIC_SPI 39 IRQ_TYPE_EDGE_RISING>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               clocks = <&clkc CLKID_I2C>;
+                       };
+
+                       i2c2: i2c@1d000 {
+                               compatible = "amlogic,meson-axg-i2c";
+                               status = "disabled";
+                               reg = <0x0 0x1d000 0x0 0x20>;
+                               interrupts = <GIC_SPI 215 IRQ_TYPE_EDGE_RISING>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               clocks = <&clkc CLKID_I2C>;
+                       };
+
+                       i2c1: i2c@1e000 {
+                               compatible = "amlogic,meson-axg-i2c";
+                               status = "disabled";
+                               reg = <0x0 0x1e000 0x0 0x20>;
+                               interrupts = <GIC_SPI 214 IRQ_TYPE_EDGE_RISING>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               clocks = <&clkc CLKID_I2C>;
+                       };
+
+                       i2c0: i2c@1f000 {
+                               compatible = "amlogic,meson-axg-i2c";
+                               status = "disabled";
+                               reg = <0x0 0x1f000 0x0 0x20>;
+                               interrupts = <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               clocks = <&clkc CLKID_I2C>;
+                       };
+
                        clk_msr: clock-measure@18000 {
                                compatible = "amlogic,meson-g12a-clk-measure";
                                reg = <0x0 0x18000 0x0 0x10>;
                        };
                };
 
+               sd_emmc_a: sd@ffe03000 {
+                       compatible = "amlogic,meson-axg-mmc";
+                       reg = <0x0 0xffe03000 0x0 0x800>;
+                       interrupts = <GIC_SPI 189 IRQ_TYPE_EDGE_RISING>;
+                       status = "disabled";
+                       clocks = <&clkc CLKID_SD_EMMC_A>,
+                                <&clkc CLKID_SD_EMMC_A_CLK0>,
+                                <&clkc CLKID_FCLK_DIV2>;
+                       clock-names = "core", "clkin0", "clkin1";
+                       resets = <&reset RESET_SD_EMMC_A>;
+                       amlogic,dram-access-quirk;
+               };
+
+               sd_emmc_b: sd@ffe05000 {
+                       compatible = "amlogic,meson-axg-mmc";
+                       reg = <0x0 0xffe05000 0x0 0x800>;
+                       interrupts = <GIC_SPI 190 IRQ_TYPE_EDGE_RISING>;
+                       status = "disabled";
+                       clocks = <&clkc CLKID_SD_EMMC_B>,
+                                <&clkc CLKID_SD_EMMC_B_CLK0>,
+                                <&clkc CLKID_FCLK_DIV2>;
+                       clock-names = "core", "clkin0", "clkin1";
+                       resets = <&reset RESET_SD_EMMC_B>;
+               };
+
+               sd_emmc_c: mmc@ffe07000 {
+                       compatible = "amlogic,meson-axg-mmc";
+                       reg = <0x0 0xffe07000 0x0 0x800>;
+                       interrupts = <GIC_SPI 191 IRQ_TYPE_EDGE_RISING>;
+                       status = "disabled";
+                       clocks = <&clkc CLKID_SD_EMMC_C>,
+                                <&clkc CLKID_SD_EMMC_C_CLK0>,
+                                <&clkc CLKID_FCLK_DIV2>;
+                       clock-names = "core", "clkin0", "clkin1";
+                       resets = <&reset RESET_SD_EMMC_C>;
+               };
+
                usb: usb@ffe09000 {
                        status = "disabled";
                        compatible = "amlogic,meson-g12a-usb-ctrl";
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts
new file mode 100644 (file)
index 0000000..81780ff
--- /dev/null
@@ -0,0 +1,386 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+/dts-v1/;
+
+#include "meson-g12b.dtsi"
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/meson-g12a-gpio.h>
+#include <dt-bindings/sound/meson-g12a-tohdmitx.h>
+
+/ {
+       compatible = "hardkernel,odroid-n2", "amlogic,g12b";
+       model = "Hardkernel ODROID-N2";
+
+       aliases {
+               serial0 = &uart_AO;
+               ethernet0 = &ethmac;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x0 0x0 0x0 0x40000000>;
+       };
+
+       emmc_pwrseq: emmc-pwrseq {
+               compatible = "mmc-pwrseq-emmc";
+               reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>;
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               blue {
+                       label = "n2:blue";
+                       gpios = <&gpio_ao GPIOAO_11 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "heartbeat";
+               };
+       };
+
+       tflash_vdd: regulator-tflash_vdd {
+               compatible = "regulator-fixed";
+
+               regulator-name = "TFLASH_VDD";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+
+               gpio = <&gpio_ao GPIOAO_8 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       tf_io: gpio-regulator-tf_io {
+               compatible = "regulator-gpio";
+
+               regulator-name = "TF_IO";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <3300000>;
+
+               gpios = <&gpio_ao GPIOAO_9 GPIO_ACTIVE_HIGH>;
+               gpios-states = <0>;
+
+               states = <3300000 0
+                         1800000 1>;
+       };
+
+       flash_1v8: regulator-flash_1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "FLASH_1V8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               vin-supply = <&vcc_3v3>;
+               regulator-always-on;
+       };
+
+       main_12v: regulator-main_12v {
+               compatible = "regulator-fixed";
+               regulator-name = "12V";
+               regulator-min-microvolt = <12000000>;
+               regulator-max-microvolt = <12000000>;
+               regulator-always-on;
+       };
+
+       vcc_5v: regulator-vcc_5v {
+               compatible = "regulator-fixed";
+               regulator-name = "5V";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-always-on;
+               vin-supply = <&main_12v>;
+       };
+
+       vcc_1v8: regulator-vcc_1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "VCC_1V8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               vin-supply = <&vcc_3v3>;
+               regulator-always-on;
+       };
+
+       vcc_3v3: regulator-vcc_3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "VCC_3V3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&vddao_3v3>;
+               regulator-always-on;
+               /* FIXME: actually controlled by VDDCPU_B_EN */
+       };
+
+       hub_5v: regulator-hub_5v {
+               compatible = "regulator-fixed";
+               regulator-name = "HUB_5V";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&vcc_5v>;
+
+               /* Connected to the Hub CHIPENABLE, LOW sets low power state */
+               gpio = <&gpio GPIOH_5 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       usb_pwr_en: regulator-usb_pwr_en {
+               compatible = "regulator-fixed";
+               regulator-name = "USB_PWR_EN";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&vcc_5v>;
+
+               /* Connected to the microUSB port power enable */
+               gpio = <&gpio GPIOH_6 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       vddao_1v8: regulator-vddao_1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "VDDAO_1V8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               vin-supply = <&vddao_3v3>;
+               regulator-always-on;
+       };
+
+       vddao_3v3: regulator-vddao_3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "VDDAO_3V3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&main_12v>;
+               regulator-always-on;
+       };
+
+       hdmi-connector {
+               compatible = "hdmi-connector";
+               type = "a";
+
+               port {
+                       hdmi_connector_in: endpoint {
+                               remote-endpoint = <&hdmi_tx_tmds_out>;
+                       };
+               };
+       };
+
+       sound {
+               compatible = "amlogic,axg-sound-card";
+               model = "G12A-ODROIDN2";
+               audio-aux-devs = <&tdmout_b>;
+               audio-routing = "TDMOUT_B IN 0", "FRDDR_A OUT 1",
+                               "TDMOUT_B IN 1", "FRDDR_B OUT 1",
+                               "TDMOUT_B IN 2", "FRDDR_C OUT 1",
+                               "TDM_B Playback", "TDMOUT_B OUT";
+
+               assigned-clocks = <&clkc CLKID_MPLL2>,
+                                 <&clkc CLKID_MPLL0>,
+                                 <&clkc CLKID_MPLL1>;
+               assigned-clock-parents = <0>, <0>, <0>;
+               assigned-clock-rates = <294912000>,
+                                      <270950400>,
+                                      <393216000>;
+               status = "okay";
+
+               dai-link-0 {
+                       sound-dai = <&frddr_a>;
+               };
+
+               dai-link-1 {
+                       sound-dai = <&frddr_b>;
+               };
+
+               dai-link-2 {
+                       sound-dai = <&frddr_c>;
+               };
+
+               /* 8ch hdmi interface */
+               dai-link-3 {
+                       sound-dai = <&tdmif_b>;
+                       dai-format = "i2s";
+                       dai-tdm-slot-tx-mask-0 = <1 1>;
+                       dai-tdm-slot-tx-mask-1 = <1 1>;
+                       dai-tdm-slot-tx-mask-2 = <1 1>;
+                       dai-tdm-slot-tx-mask-3 = <1 1>;
+                       mclk-fs = <256>;
+
+                       codec {
+                               sound-dai = <&tohdmitx TOHDMITX_I2S_IN_B>;
+                       };
+               };
+
+               /* hdmi glue */
+               dai-link-4 {
+                       sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>;
+
+                       codec {
+                               sound-dai = <&hdmi_tx>;
+                       };
+               };
+       };
+};
+
+&arb {
+       status = "okay";
+};
+
+&cec_AO {
+       pinctrl-0 = <&cec_ao_a_h_pins>;
+       pinctrl-names = "default";
+       status = "disabled";
+       hdmi-phandle = <&hdmi_tx>;
+};
+
+&cecb_AO {
+       pinctrl-0 = <&cec_ao_b_h_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+       hdmi-phandle = <&hdmi_tx>;
+};
+
+&clkc_audio {
+       status = "okay";
+};
+
+&ext_mdio {
+       external_phy: ethernet-phy@0 {
+               /* Realtek RTL8211F (0x001cc916) */     
+               reg = <0>;
+               max-speed = <1000>;
+
+               reset-assert-us = <10000>;
+               reset-deassert-us = <30000>;
+               reset-gpios = <&gpio GPIOZ_15 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>;
+
+               interrupt-parent = <&gpio_intc>;
+               /* MAC_INTR on GPIOZ_14 */
+               interrupts = <26 IRQ_TYPE_LEVEL_LOW>;
+       };
+};
+
+&ethmac {
+       pinctrl-0 = <&eth_pins>, <&eth_rgmii_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+       phy-mode = "rgmii";
+       phy-handle = <&external_phy>;
+       amlogic,tx-delay-ns = <2>;
+};
+
+&frddr_a {
+       status = "okay";
+};
+
+&frddr_b {
+       status = "okay";
+};
+
+&frddr_c {
+       status = "okay";
+};
+
+&gpio {
+       /*
+        * WARNING: The USB Hub on the Odroid-N2 needs a reset signal
+        * to be turned high in order to be detected by the USB Controller
+        * This signal should be handled by a USB specific power sequence
+        * in order to reset the Hub when USB bus is powered down.
+        */
+       usb-hub {
+               gpio-hog;
+               gpios = <GPIOH_4 GPIO_ACTIVE_HIGH>;
+               output-high;
+               line-name = "usb-hub-reset";
+       };
+};
+
+&hdmi_tx {
+       status = "okay";
+       pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>;
+       pinctrl-names = "default";
+       hdmi-supply = <&vcc_5v>;
+};
+
+&hdmi_tx_tmds_port {
+       hdmi_tx_tmds_out: endpoint {
+               remote-endpoint = <&hdmi_connector_in>;
+       };
+};
+
+&ir {
+       status = "okay";
+       pinctrl-0 = <&remote_input_ao_pins>;
+       pinctrl-names = "default";
+};
+
+/* SD card */
+&sd_emmc_b {
+       status = "okay";
+       pinctrl-0 = <&sdcard_c_pins>;
+       pinctrl-1 = <&sdcard_clk_gate_c_pins>;
+       pinctrl-names = "default", "clk-gate";
+
+       bus-width = <4>;
+       cap-sd-highspeed;
+       max-frequency = <50000000>;
+       disable-wp;
+
+       cd-gpios = <&gpio GPIOC_6 GPIO_ACTIVE_LOW>;
+       vmmc-supply = <&tflash_vdd>;
+       vqmmc-supply = <&tf_io>;
+
+};
+
+/* eMMC */
+&sd_emmc_c {
+       status = "okay";
+       pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>;
+       pinctrl-1 = <&emmc_clk_gate_pins>;
+       pinctrl-names = "default", "clk-gate";
+
+       bus-width = <8>;
+       cap-mmc-highspeed;
+       mmc-ddr-1_8v;
+       mmc-hs200-1_8v;
+       max-frequency = <200000000>;
+       disable-wp;
+
+       mmc-pwrseq = <&emmc_pwrseq>;
+       vmmc-supply = <&vcc_3v3>;
+       vqmmc-supply = <&flash_1v8>;
+};
+
+&tdmif_b {
+       status = "okay";
+};
+
+&tdmout_b {
+       status = "okay";
+};
+
+&tohdmitx {
+       status = "okay";
+};
+
+&uart_AO {
+       status = "okay";
+       pinctrl-0 = <&uart_ao_a_pins>;
+       pinctrl-names = "default";
+};
+
+&usb {
+       status = "okay";
+       vbus-supply = <&usb_pwr_en>;
+};
+
+&usb2_phy0 {
+       phy-supply = <&vcc_5v>;
+};
+
+&usb2_phy1 {
+       /* Enable the hub which is connected to this port */
+       phy-supply = <&hub_5v>;
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi
new file mode 100644 (file)
index 0000000..9e88e51
--- /dev/null
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#include "meson-g12a.dtsi"
+
+/ {
+       compatible = "amlogic,g12b";
+
+       cpus {
+               cpu-map {
+                       cluster0 {
+                               core0 {
+                                       cpu = <&cpu0>;
+                               };
+
+                               core1 {
+                                       cpu = <&cpu1>;
+                               };
+                       };
+
+                       cluster1 {
+                               core0 {
+                                       cpu = <&cpu100>;
+                               };
+
+                               core1 {
+                                       cpu = <&cpu101>;
+                               };
+
+                               core2 {
+                                       cpu = <&cpu102>;
+                               };
+
+                               core3 {
+                                       cpu = <&cpu103>;
+                               };
+                       };
+               };
+
+               /delete-node/ cpu@2;
+               /delete-node/ cpu@3;
+
+               cpu100: cpu@100 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a73";
+                       reg = <0x0 0x100>;
+                       enable-method = "psci";
+                       next-level-cache = <&l2>;
+               };
+
+               cpu101: cpu@101 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a73";
+                       reg = <0x0 0x101>;
+                       enable-method = "psci";
+                       next-level-cache = <&l2>;
+               };
+
+               cpu102: cpu@102 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a73";
+                       reg = <0x0 0x102>;
+                       enable-method = "psci";
+                       next-level-cache = <&l2>;
+               };
+
+               cpu103: cpu@103 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a73";
+                       reg = <0x0 0x103>;
+                       enable-method = "psci";
+                       next-level-cache = <&l2>;
+               };
+       };
+};
+
+&clkc {
+       compatible = "amlogic,g12b-clkc";
+};
index 016641a..a9b7785 100644 (file)
 
        bus-width = <4>;
        cap-sd-highspeed;
-       max-frequency = <100000000>;
+       max-frequency = <50000000>;
 
        non-removable;
        disable-wp;
 
        bus-width = <4>;
        cap-sd-highspeed;
-       max-frequency = <100000000>;
+       max-frequency = <50000000>;
        disable-wp;
 
        cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_LOW>;
index 6772709..74d03fc 100644 (file)
                };
 
                ethmac: ethernet@c9410000 {
-                       compatible = "amlogic,meson-gx-dwmac", "amlogic,meson-gxbb-dwmac", "snps,dwmac";
+                       compatible = "amlogic,meson-gxbb-dwmac",
+                                    "snps,dwmac-3.70a",
+                                    "snps,dwmac";
                        reg = <0x0 0xc9410000 0x0 0x10000
                               0x0 0xc8834540 0x0 0x4>;
                        interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
index ade2ee0..c34c1c9 100644 (file)
 
        amlogic,tx-delay-ns = <2>;
 
-       snps,reset-gpio = <&gpio GPIOZ_14 0>;
-       snps,reset-delays-us = <0 10000 1000000>;
-       snps,reset-active-low;
-
        mdio {
                compatible = "snps,dwmac-mdio";
                #address-cells = <1>;
                eth_phy0: ethernet-phy@0 {
                        /* Realtek RTL8211F (0x001cc916) */
                        reg = <0>;
+
+                       reset-assert-us = <10000>;
+                       reset-deassert-us = <30000>;
+                       reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>;
+
                        interrupt-parent = <&gpio_intc>;
                        /* MAC_INTR on GPIOZ_15 */
                        interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
 
        bus-width = <4>;
        cap-sd-highspeed;
-       max-frequency = <200000000>;
+       max-frequency = <50000000>;
 
        non-removable;
        disable-wp;
        sd-uhs-sdr12;
        sd-uhs-sdr25;
        sd-uhs-sdr50;
-       sd-uhs-sdr104;
-       max-frequency = <200000000>;
+       sd-uhs-ddr50;
+       max-frequency = <100000000>;
        disable-wp;
 
        cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_LOW>;
index 25105ac..b636912 100644 (file)
        phy-handle = <&eth_phy0>;
        phy-mode = "rmii";
 
-       snps,reset-gpio = <&gpio GPIOZ_14 0>;
-       snps,reset-delays-us = <0 10000 1000000>;
-       snps,reset-active-low;
-
        mdio {
                compatible = "snps,dwmac-mdio";
                #address-cells = <1>;
                eth_phy0: ethernet-phy@0 {
                        /* IC Plus IP101GR (0x02430c54) */
                        reg = <0>;
+
+                       reset-assert-us = <10000>;
+                       reset-deassert-us = <10000>;
+                       reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>;
                };
        };
 };
 
        bus-width = <4>;
        cap-sd-highspeed;
-       max-frequency = <100000000>;
+       max-frequency = <50000000>;
        disable-wp;
 
        cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_LOW>;
index 1cc9dc6..9972b15 100644 (file)
        phy-handle = <&eth_phy0>;
        phy-mode = "rgmii";
 
-       snps,reset-gpio = <&gpio GPIOZ_14 0>;
-       snps,reset-delays-us = <0 10000 1000000>;
-       snps,reset-active-low;
-
        amlogic,tx-delay-ns = <2>;
 
        mdio {
                eth_phy0: ethernet-phy@0 {
                        /* Realtek RTL8211F (0x001cc916) */
                        reg = <0>;
+
+                       reset-assert-us = <10000>;
+                       reset-deassert-us = <30000>;
+                       reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>;
+
                        interrupt-parent = <&gpio_intc>;
                        /* MAC_INTR on GPIOZ_15 */
                        interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
 
        bus-width = <4>;
        cap-sd-highspeed;
+       sd-uhs-sdr12;
+       sd-uhs-sdr25;
+       sd-uhs-sdr50;
+       sd-uhs-ddr50;
        max-frequency = <100000000>;
        disable-wp;
 
        pinctrl-names = "default", "clk-gate";
 
        bus-width = <8>;
-       max-frequency = <100000000>;
+       max-frequency = <200000000>;
        non-removable;
        disable-wp;
        cap-mmc-highspeed;
index 9d2406a..3c93d18 100644 (file)
 
        amlogic,tx-delay-ns = <2>;
 
-       snps,reset-gpio = <&gpio GPIOZ_14 0>;
-       snps,reset-delays-us = <0 10000 1000000>;
-       snps,reset-active-low;
-
        mdio {
                compatible = "snps,dwmac-mdio";
                #address-cells = <1>;
                eth_phy0: ethernet-phy@3 {
                        /* Micrel KSZ9031 (0x00221620) */
                        reg = <3>;
+
+                       reset-assert-us = <10000>;
+                       reset-deassert-us = <30000>;
+                       reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>;
+
                        interrupt-parent = <&gpio_intc>;
                        /* MAC_INTR on GPIOZ_15 */
                        interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
index 0be0f2a..e8f9258 100644 (file)
 
        bus-width = <4>;
        cap-sd-highspeed;
-       max-frequency = <100000000>;
+       max-frequency = <50000000>;
 
        non-removable;
        disable-wp;
index ad4d50b..43b11e3 100644 (file)
                };
        };
 
-       usb_vbus: regulator-usb0-vbus {
+       usb_pwr: regulator-usb-pwrs {
                compatible = "regulator-fixed";
 
-               regulator-name = "USB0_VBUS";
+               regulator-name = "USB_PWR";
 
                regulator-min-microvolt = <5000000>;
                regulator-max-microvolt = <5000000>;
                enable-active-high;
        };
 
-       vcc_3v3: regulator-vcc_3v3 {
+       vddio_boot: regulator-vddio_boot {
                compatible = "regulator-fixed";
-               regulator-name = "VCC_3V3";
+               regulator-name = "VDDIO_BOOT";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+       };
+
+       vddao_3v3: regulator-vddao_3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
        };
 
-       vcc_1v8: regulator-vcc_1v8 {
+       vddio_ao18: regulator-vddio_ao18 {
                compatible = "regulator-fixed";
-               regulator-name = "VCC_1V8";
+               regulator-name = "VDDIO_AO18";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
        };
 
+       vcc_3v3: regulator-vcc_3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "VCC_3V3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+       };
+
        emmc_pwrseq: emmc-pwrseq {
                compatible = "mmc-pwrseq-emmc";
                reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>;
                pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */
        };
 
+       hdmi-connector {
+               compatible = "hdmi-connector";
+               type = "a";
+
+               port {
+                       hdmi_connector_in: endpoint {
+                               remote-endpoint = <&hdmi_tx_tmds_out>;
+                       };
+               };
+       };
+
        sdio_pwrseq: sdio-pwrseq {
                compatible = "mmc-pwrseq-simple";
-               reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>,
-                               <&gpio GPIOX_20 GPIO_ACTIVE_LOW>;
+               reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>;
                clocks = <&wifi32k>;
                clock-names = "ext_clock";
        };
 };
 
+&cec_AO {
+       status = "okay";
+       pinctrl-0 = <&ao_cec_pins>;
+       pinctrl-names = "default";
+       hdmi-phandle = <&hdmi_tx>;
+};
+
 &ethmac {
        status = "okay";
        pinctrl-0 = <&eth_rgmii_pins>;
 
        amlogic,tx-delay-ns = <2>;
 
-       snps,reset-gpio = <&gpio GPIOZ_14 0>;
-       snps,reset-delays-us = <0 10000 1000000>;
-       snps,reset-active-low;
-
        mdio {
                compatible = "snps,dwmac-mdio";
                #address-cells = <1>;
                eth_phy0: ethernet-phy@0 {
                        /* Realtek RTL8211F (0x001cc916) */
                        reg = <0>;
+
+                       reset-assert-us = <10000>;
+                       reset-deassert-us = <30000>;
+                       reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>;
+
+                       interrupt-parent = <&gpio_intc>;
+                       /* MAC_INTR on GPIOZ_15 */
+                       interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
                };
        };
 };
 
+&hdmi_tx {
+       status = "okay";
+       pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
+       pinctrl-names = "default";
+};
+
+&hdmi_tx_tmds_port {
+       hdmi_tx_tmds_out: endpoint {
+               remote-endpoint = <&hdmi_connector_in>;
+       };
+};
+
 &ir {
        status = "okay";
        pinctrl-0 = <&remote_input_ao_pins>;
        clock-names = "clkin0";
 };
 
+&saradc {
+       status = "okay";
+       vref-supply = <&vddio_ao18>;
+};
+
 /* Wireless SDIO Module */
 &sd_emmc_a {
        status = "okay";
-       pinctrl-0 = <&sdio_pins &sdio_irq_pins>;
+       pinctrl-0 = <&sdio_pins>;
        pinctrl-1 = <&sdio_clk_gate_pins>;
        pinctrl-names = "default", "clk-gate";
        #address-cells = <1>;
 
        bus-width = <4>;
        cap-sd-highspeed;
-       max-frequency = <100000000>;
+       max-frequency = <50000000>;
 
        non-removable;
        disable-wp;
 
        mmc-pwrseq = <&sdio_pwrseq>;
 
-       vmmc-supply = <&vcc_3v3>;
-       vqmmc-supply = <&vcc_1v8>;
+       vmmc-supply = <&vddao_3v3>;
+       vqmmc-supply = <&vddio_boot>;
 
        brcmf: wifi@1 {
                reg = <1>;
 
        bus-width = <4>;
        cap-sd-highspeed;
-       max-frequency = <100000000>;
+       max-frequency = <50000000>;
        disable-wp;
 
        cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_LOW>;
 
-       vmmc-supply = <&vcc_3v3>;
+       vmmc-supply = <&vddao_3v3>;
+       vqmmc-supply = <&vcc_3v3>;
 };
 
 /* eMMC */
 
        mmc-pwrseq = <&emmc_pwrseq>;
        vmmc-supply = <&vcc_3v3>;
-       vmmcq-sumpply = <&vcc_1v8>;
+       vqmmc-supply = <&vddio_boot>;
+};
+
+/* This is connected to the Bluetooth module: */
+&uart_A {
+       status = "okay";
+       pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>;
+       pinctrl-names = "default";
+
+       bluetooth {
+               compatible = "brcm,bcm43438-bt";
+               shutdown-gpios = <&gpio GPIOX_20 GPIO_ACTIVE_HIGH>;
+       };
 };
 
+/* This UART is brought out to the DB9 connector */
 &uart_AO {
        status = "okay";
        pinctrl-0 = <&uart_ao_a_pins>;
 
 &usb0_phy {
        status = "okay";
-       phy-supply = <&usb_vbus>;
+       phy-supply = <&usb_pwr>;
 };
 
 &usb1_phy {
index 2d2db78..4c53988 100644 (file)
                regulator-max-microvolt = <3300000>;
        };
 
+       vddio_ao18: regulator-vddio_ao18 {
+               compatible = "regulator-fixed";
+               regulator-name = "VDDIO_AO18";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+       };
+
        vcc_3v3: regulator-vcc_3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
 
        amlogic,tx-delay-ns = <2>;
 
-       snps,reset-gpio = <&gpio GPIOZ_14 0>;
-       snps,reset-delays-us = <0 10000 1000000>;
-       snps,reset-active-low;
-
        mdio {
                compatible = "snps,dwmac-mdio";
                #address-cells = <1>;
                eth_phy0: ethernet-phy@0 {
                        /* Realtek RTL8211F (0x001cc916) */
                        reg = <0>;
+
+                       reset-assert-us = <10000>;
+                       reset-deassert-us = <30000>;
+                       reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>;
                };
        };
 };
        clock-names = "clkin0";
 };
 
+&saradc {
+       status = "okay";
+       vref-supply = <&vddio_ao18>;
+};
+
 /* Wireless SDIO Module */
 &sd_emmc_a {
        status = "okay";
 
        bus-width = <4>;
        cap-sd-highspeed;
-       max-frequency = <100000000>;
+       max-frequency = <50000000>;
 
        non-removable;
        disable-wp;
 
        bus-width = <4>;
        cap-sd-highspeed;
-       max-frequency = <100000000>;
+       max-frequency = <50000000>;
        disable-wp;
 
        cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_LOW>;
        vqmmc-supply = <&vddio_boot>;
 };
 
+/* This is connected to the Bluetooth module: */
+&uart_A {
+       status = "okay";
+       pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>;
+       pinctrl-names = "default";
+       uart-has-rtscts;
+
+       bluetooth {
+               compatible = "brcm,bcm43438-bt";
+               shutdown-gpios = <&gpio GPIOX_20 GPIO_ACTIVE_HIGH>;
+       };
+};
+
 /* This UART is brought out to the DB9 connector */
 &uart_AO {
        status = "okay";
index a60d365..f734faa 100644 (file)
                };
 
                emmc_pins: emmc {
-                       mux {
+                       mux-0 {
                                groups = "emmc_nand_d07",
-                                      "emmc_cmd",
-                                      "emmc_clk";
+                                      "emmc_cmd";
+                               function = "emmc";
+                               bias-pull-up;
+                       };
+
+                       mux-1 {
+                               groups = "emmc_clk";
                                function = "emmc";
                                bias-disable;
                        };
                        mux {
                                groups = "emmc_ds";
                                function = "emmc";
-                               bias-disable;
+                               bias-pull-down;
                        };
                };
 
                };
 
                sdcard_pins: sdcard {
-                       mux {
+                       mux-0 {
                                groups = "sdcard_d0",
                                       "sdcard_d1",
                                       "sdcard_d2",
                                       "sdcard_d3",
-                                      "sdcard_cmd",
-                                      "sdcard_clk";
+                                      "sdcard_cmd";
+                               function = "sdcard";
+                               bias-pull-up;
+                       };
+
+                       mux-1 {
+                               groups = "sdcard_clk";
                                function = "sdcard";
                                bias-disable;
                        };
                };
 
                sdio_pins: sdio {
-                       mux {
+                       mux-0 {
                                groups = "sdio_d0",
                                       "sdio_d1",
                                       "sdio_d2",
                                       "sdio_d3",
-                                      "sdio_cmd",
-                                      "sdio_clk";
+                                      "sdio_cmd";
+                               function = "sdio";
+                               bias-pull-up;
+                       };
+
+                       mux-1 {
+                               groups = "sdio_clk";
                                function = "sdio";
                                bias-disable;
                        };
index 70433e0..3a1484e 100644 (file)
 
        bus-width = <4>;
        cap-sd-highspeed;
-       max-frequency = <100000000>;
+       max-frequency = <50000000>;
 
        non-removable;
        disable-wp;
index 0c8e830..b08c453 100644 (file)
 
        amlogic,tx-delay-ns = <2>;
 
-       /* External PHY reset is shared with internal PHY Led signals */
-       snps,reset-gpio = <&gpio GPIOZ_14 0>;
-       snps,reset-delays-us = <0 10000 1000000>;
-       snps,reset-active-low;
-
        /* External PHY is in RGMII */
        phy-mode = "rgmii";
 };
 
 &external_mdio {
        external_phy: ethernet-phy@0 {
-               compatible = "ethernet-phy-id001c.c916", "ethernet-phy-ieee802.3-c22";
+               /* Realtek RTL8211F (0x001cc916) */
                reg = <0>;
                max-speed = <1000>;
+
+               /* External PHY reset is shared with internal PHY Led signal */
+               reset-assert-us = <10000>;
+               reset-deassert-us = <30000>;
+               reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>;
+
                interrupt-parent = <&gpio_intc>;
                interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
                eee-broken-1000t;
index 255cede..4b8ce73 100644 (file)
                regulator-max-microvolt = <1800000>;
        };
 
+       /* This is provided by LDOs on the eMMC daugther card */
        vddio_boot: regulator-vddio_boot {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_BOOT";
-               regulator-min-microvolt = <3300000>;
-               regulator-max-microvolt = <3300000>;
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               vin-supply = <&vcc_3v3>;
        };
 };
 
 
        bus-width = <4>;
        cap-sd-highspeed;
-       max-frequency = <100000000>;
+       max-frequency = <50000000>;
        disable-wp;
 
        cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_LOW>;
 
        bus-width = <8>;
        cap-mmc-highspeed;
-       mmc-ddr-3_3v;
-       max-frequency = <50000000>;
-       non-removable;
+       mmc-ddr-1_8v;
+       mmc-hs200-1_8v;
+       max-frequency = <200000000>;
        disable-wp;
 
        mmc-pwrseq = <&emmc_pwrseq>;
index 9cbdb85..26907ac 100644 (file)
 
        bus-width = <4>;
        cap-sd-highspeed;
-       max-frequency = <100000000>;
+       max-frequency = <50000000>;
        disable-wp;
 
        cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_LOW>;
index bc811a2..e3c16f5 100644 (file)
 
        bus-width = <4>;
        cap-sd-highspeed;
-       max-frequency = <100000000>;
+       max-frequency = <50000000>;
 
        non-removable;
        disable-wp;
 
        bus-width = <4>;
        cap-sd-highspeed;
-       max-frequency = <100000000>;
+       max-frequency = <50000000>;
        disable-wp;
 
        cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_LOW>;
index 3093ae4..c959456 100644 (file)
                };
 
                emmc_pins: emmc {
-                       mux {
+                       mux-0 {
                                groups = "emmc_nand_d07",
-                                      "emmc_cmd",
-                                      "emmc_clk";
+                                      "emmc_cmd";
+                               function = "emmc";
+                               bias-pull-up;
+                       };
+
+                       mux-1 {
+                               groups = "emmc_clk";
                                function = "emmc";
                                bias-disable;
                        };
                        mux {
                                groups = "emmc_ds";
                                function = "emmc";
-                               bias-disable;
+                               bias-pull-down;
                        };
                };
 
                };
 
                sdcard_pins: sdcard {
-                       mux {
+                       mux-0 {
                                groups = "sdcard_d0",
                                       "sdcard_d1",
                                       "sdcard_d2",
                                       "sdcard_d3",
-                                      "sdcard_cmd",
-                                      "sdcard_clk";
+                                      "sdcard_cmd";
+                               function = "sdcard";
+                               bias-pull-up;
+                       };
+
+                       mux-1 {
+                               groups = "sdcard_clk";
                                function = "sdcard";
                                bias-disable;
                        };
                };
 
                sdio_pins: sdio {
-                       mux {
+                       mux-0 {
                                groups = "sdio_d0",
                                       "sdio_d1",
                                       "sdio_d2",
                                       "sdio_d3",
-                                      "sdio_cmd",
-                                      "sdio_clk";
+                                      "sdio_cmd";
+                               function = "sdio";
+                               bias-pull-up;
+                       };
+
+                       mux-1 {
+                               groups = "sdio_clk";
                                function = "sdio";
                                bias-disable;
                        };
index 3f086ed..989d33a 100644 (file)
@@ -18,7 +18,6 @@
 
        aliases {
                serial0 = &uart_AO;
-               serial1 = &uart_A;
                serial2 = &uart_AO_B;
        };
 
 
        gpio-keys-polled {
                compatible = "gpio-keys-polled";
-               #address-cells = <1>;
-               #size-cells = <0>;
                poll-interval = <100>;
 
-               button@0 {
+               power-button {
                        label = "power";
                        linux,code = <KEY_POWER>;
                        gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_LOW>;
 
        amlogic,tx-delay-ns = <2>;
 
-       /* External PHY reset is shared with internal PHY Led signals */
-       snps,reset-gpio = <&gpio GPIOZ_14 0>;
-       snps,reset-delays-us = <0 10000 1000000>;
-       snps,reset-active-low;
-
        /* External PHY is in RGMII */
        phy-mode = "rgmii";
 
        external_phy: ethernet-phy@0 {
                /* Realtek RTL8211F (0x001cc916) */
                reg = <0>;
+
+               reset-assert-us = <10000>;
+               reset-deassert-us = <30000>;
+               reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>;
+
                interrupt-parent = <&gpio_intc>;
                /* MAC_INTR on GPIOZ_15 */
                interrupts = <25 IRQ_TYPE_LEVEL_LOW>;
 &sd_emmc_a {
        status = "okay";
        pinctrl-0 = <&sdio_pins>;
-       pinctrl-names = "default";
+       pinctrl-1 = <&sdio_clk_gate_pins>;
+       pinctrl-names = "default", "clk-gate";
        #address-cells = <1>;
        #size-cells = <0>;
 
        bus-width = <4>;
-       max-frequency = <100000000>;
+       max-frequency = <50000000>;
 
        non-removable;
        disable-wp;
 &sd_emmc_b {
        status = "okay";
        pinctrl-0 = <&sdcard_pins>;
-       pinctrl-names = "default";
+       pinctrl-1 = <&sdcard_clk_gate_pins>;
+       pinctrl-names = "default", "clk-gate";
 
        bus-width = <4>;
        cap-sd-highspeed;
-       max-frequency = <100000000>;
+       max-frequency = <50000000>;
        disable-wp;
 
        cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_LOW>;
 &sd_emmc_c {
        status = "okay";
        pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>;
-       pinctrl-names = "default";
+       pinctrl-1 = <&emmc_clk_gate_pins>;
+       pinctrl-names = "default", "clk-gate";
 
        bus-width = <8>;
-       cap-sd-highspeed;
        cap-mmc-highspeed;
        max-frequency = <200000000>;
        non-removable;
        disable-wp;
        mmc-ddr-1_8v;
        mmc-hs200-1_8v;
-       mmc-hs400-1_8v;
 
        mmc-pwrseq = <&emmc_pwrseq>;
        vmmc-supply = <&vcc_3v3>;
 /* This one is connected to the Bluetooth module */
 &uart_A {
        status = "okay";
-       pinctrl-0 = <&uart_a_pins>;
+       pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>;
        pinctrl-names = "default";
+       uart-has-rtscts;
+
+       bluetooth {
+               compatible = "brcm,bcm43438-bt";
+               shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>;
+       };
 };
 
 /* This is brought out on the Linux_RX (18) and Linux_TX (19) pins: */
index 25f3b6b..c2bd4db 100644 (file)
 
        amlogic,tx-delay-ns = <2>;
 
-       snps,reset-gpio = <&gpio GPIOZ_14 0>;
-       snps,reset-delays-us = <0 10000 1000000>;
-       snps,reset-active-low;
-
        /* External PHY is in RGMII */
        phy-mode = "rgmii";
 };
 
 &external_mdio {
        external_phy: ethernet-phy@0 {
-               compatible = "ethernet-phy-id001c.c916", "ethernet-phy-ieee802.3-c22";
+               /* Realtek RTL8211F (0x001cc916) */
                reg = <0>;
                max-speed = <1000>;
+
+               reset-assert-us = <10000>;
+               reset-deassert-us = <30000>;
+               reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>;
        };
 };
 
 
        bus-width = <4>;
        cap-sd-highspeed;
-       max-frequency = <100000000>;
+       max-frequency = <50000000>;
        disable-wp;
 
        cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_LOW>;
index 73d656e..ea45ae0 100644 (file)
 
        amlogic,tx-delay-ns = <2>;
 
-       /* External PHY reset is shared with internal PHY Led signals */
-       snps,reset-gpio = <&gpio GPIOZ_14 0>;
-       snps,reset-delays-us = <0 10000 1000000>;
-       snps,reset-active-low;
-
        /* External PHY is in RGMII */
        phy-mode = "rgmii";
 };
 
 &external_mdio {
        external_phy: ethernet-phy@0 {
-               compatible = "ethernet-phy-id001c.c916", "ethernet-phy-ieee802.3-c22";
+               /* Realtek RTL8211F (0x001cc916) */
                reg = <0>;
                max-speed = <1000>;
+
+               /* External PHY reset is shared with internal PHY Led signal */
+               reset-assert-us = <10000>;
+               reset-deassert-us = <30000>;
+               reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>;
+
                interrupt-parent = <&gpio_intc>;
                /* MAC_INTR on GPIOZ_15 */
                interrupts = <25 IRQ_TYPE_LEVEL_LOW>;
index 7fa20a8..5cd4d35 100644 (file)
        /* Select external PHY by default */
        phy-handle = <&external_phy>;
 
-       snps,reset-gpio = <&gpio GPIOZ_14 0>;
-       snps,reset-delays-us = <0 10000 1000000>;
-       snps,reset-active-low;
-
        amlogic,tx-delay-ns = <2>;
 
        /* External PHY is in RGMII */
 
 &external_mdio {
        external_phy: ethernet-phy@0 {
-               compatible = "ethernet-phy-id001c.c916", "ethernet-phy-ieee802.3-c22";
+               /* Realtek RTL8211F (0x001cc916) */
                reg = <0>;
                max-speed = <1000>;
+
+               reset-assert-us = <10000>;
+               reset-deassert-us = <30000>;
+               reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>;
        };
 };
 
 
        bus-width = <4>;
        cap-sd-highspeed;
-       max-frequency = <100000000>;
+       max-frequency = <50000000>;
 
        non-removable;
        disable-wp;
 
        bus-width = <4>;
        cap-sd-highspeed;
-       max-frequency = <100000000>;
+       max-frequency = <50000000>;
        disable-wp;
 
        cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_LOW>;
index 7446e0d..26a039a 100644 (file)
 
        /* main funnel on Juno r0, cssys0 funnel on Juno r1/r2 as per TRM*/
        main_funnel: funnel@20040000 {
-               compatible = "arm,coresight-funnel", "arm,primecell";
+               compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                reg = <0 0x20040000 0 0x1000>;
 
                clocks = <&soc_smc50mhz>;
        };
 
        funnel@220c0000 { /* cluster0 funnel */
-               compatible = "arm,coresight-funnel", "arm,primecell";
+               compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                reg = <0 0x220c0000 0 0x1000>;
 
                clocks = <&soc_smc50mhz>;
        };
 
        funnel@230c0000 { /* cluster1 funnel */
-               compatible = "arm,coresight-funnel", "arm,primecell";
+               compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                reg = <0 0x230c0000 0 0x1000>;
 
                clocks = <&soc_smc50mhz>;
index cf28515..eda3d9e 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 / {
        funnel@20130000 { /* cssys1 */
-               compatible = "arm,coresight-funnel", "arm,primecell";
+               compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                reg = <0 0x20130000 0 0x1000>;
 
                clocks = <&soc_smc50mhz>;
@@ -47,7 +47,7 @@
        };
 
        funnel@20150000 { /* cssys2 */
-               compatible = "arm,coresight-funnel", "arm,primecell";
+               compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                reg = <0 0x20150000 0 0x1000>;
 
                clocks = <&soc_smc50mhz>;
index 1792b07..9f60dac 100644 (file)
                        flash@0,00000000 {
                                /* 2 * 32MiB NOR Flash memory mounted on CS0 */
                                compatible = "arm,vexpress-flash", "cfi-flash";
-                               linux,part-probe = "afs";
                                reg = <0 0x00000000 0x04000000>;
                                bank-width = <4>;
                                /*
                                 * flash hardware access is disabled by default.
                                 */
                                status = "disabled";
+                               partitions {
+                                       compatible = "arm,arm-firmware-suite";
+                               };
                        };
 
                        ethernet@2,00000000 {
diff --git a/arch/arm64/boot/dts/broadcom/stingray/stingray-usb.dtsi b/arch/arm64/boot/dts/broadcom/stingray/stingray-usb.dtsi
new file mode 100644 (file)
index 0000000..55259f9
--- /dev/null
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: (GPL-2.0 or BSD-3-Clause)
+/*
+ *Copyright(c) 2018 Broadcom
+ */
+       usb {
+               compatible = "simple-bus";
+               dma-ranges;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0x0 0x68500000 0x00400000>;
+
+               usbphy0: usb-phy@0 {
+                       compatible = "brcm,sr-usb-combo-phy";
+                       reg = <0x00000000 0x100>;
+                       #phy-cells = <1>;
+                       status = "disabled";
+               };
+
+               xhci0: usb@1000 {
+                       compatible = "generic-xhci";
+                       reg = <0x00001000 0x1000>;
+                       interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>;
+                       phys = <&usbphy0 1>, <&usbphy0 0>;
+                       phy-names = "phy0", "phy1";
+                       dma-coherent;
+                       status = "disabled";
+               };
+
+               bdc0: usb@2000 {
+                       compatible = "brcm,bdc-v0.16";
+                       reg = <0x00002000 0x1000>;
+                       interrupts = <GIC_SPI 259 IRQ_TYPE_LEVEL_HIGH>;
+                       phys = <&usbphy0 0>, <&usbphy0 1>;
+                       phy-names = "phy0", "phy1";
+                       dma-coherent;
+                       status = "disabled";
+               };
+
+               usbphy1: usb-phy@10000 {
+                       compatible = "brcm,sr-usb-combo-phy";
+                       reg = <0x00010000 0x100>;
+                       #phy-cells = <1>;
+                       status = "disabled";
+               };
+
+               usbphy2: usb-phy@20000 {
+                       compatible = "brcm,sr-usb-hs-phy";
+                       reg = <0x00020000 0x100>;
+                       #phy-cells = <0>;
+                       status = "disabled";
+               };
+
+               xhci1: usb@11000 {
+                       compatible = "generic-xhci";
+                       reg = <0x00011000 0x1000>;
+                       interrupts = <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>;
+                       phys = <&usbphy1 1>, <&usbphy2>, <&usbphy1 0>;
+                       phy-names = "phy0", "phy1", "phy2";
+                       dma-coherent;
+                       status = "disabled";
+               };
+
+               bdc1: usb@21000 {
+                       compatible = "brcm,bdc-v0.16";
+                       reg = <0x00021000 0x1000>;
+                       interrupts = <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>;
+                       phys = <&usbphy2>;
+                       phy-names = "phy0";
+                       dma-coherent;
+                       status = "disabled";
+               };
+       };
index 35c4670..71e2e34 100644 (file)
        #include "stingray-fs4.dtsi"
        #include "stingray-sata.dtsi"
        #include "stingray-pcie.dtsi"
+       #include "stingray-usb.dtsi"
 
        hsls {
                compatible = "simple-bus";
                        status = "disabled";
                };
        };
+
+       tmons {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0x0 0x8f100000 0x100>;
+
+               tmon: tmon@0 {
+                       compatible = "brcm,sr-thermal";
+                       reg = <0x0 0x40>;
+                       brcm,tmon-mask = <0x3f>;
+                       #thermal-sensor-cells = <1>;
+               };
+       };
+
+       thermal-zones {
+               ihost0_thermal: ihost0-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tmon 0>;
+                       trips {
+                               cpu-crit {
+                                       temperature = <105000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+               };
+               ihost1_thermal: ihost1-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tmon 1>;
+                       trips {
+                               cpu-crit {
+                                       temperature = <105000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+               };
+               ihost2_thermal: ihost2-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tmon 2>;
+                       trips {
+                               cpu-crit {
+                                       temperature = <105000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+               };
+               ihost3_thermal: ihost3-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tmon 3>;
+                       trips {
+                               cpu-crit {
+                                       temperature = <105000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+               };
+               crmu_thermal: crmu-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tmon 4>;
+                       trips {
+                               cpu-crit {
+                                       temperature = <105000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+               };
+               nitro_thermal: nitro-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tmon 5>;
+                       trips {
+                               cpu-crit {
+                                       temperature = <105000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+               };
+       };
+
+       nic-hsls {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0x0  0x0 0x7fffffff>;
+
+               nic_i2c0: i2c@60826100 {
+                       compatible = "brcm,iproc-nic-i2c";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x60826100 0x100>,
+                             <0x60e00408 0x1000>;
+                       brcm,ape-hsls-addr-mask = <0x03400000>;
+                       clock-frequency = <100000>;
+                       status = "disabled";
+               };
+       };
 };
index d2de166..6f90b0e 100644 (file)
        pinctrl-0 = <&te_irq>;
 };
 
+&gpu {
+       mali-supply = <&buck6_reg>;
+       status = "okay";
+};
+
 &hdmi {
        hpd-gpios = <&gpa3 0 GPIO_ACTIVE_HIGH>;
        status = "okay";
index d29d13f..a76f620 100644 (file)
                };
        };
 
+       gpu: gpu@14ac0000 {
+               compatible = "samsung,exynos5433-mali", "arm,mali-t760";
+               reg = <0x14ac0000 0x5000>;
+               interrupts = <GIC_SPI 282 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 283 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 281 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "job", "mmu", "gpu";
+               clocks = <&cmu_g3d CLK_ACLK_G3D>;
+               clock-names = "core";
+               power-domains = <&pd_g3d>;
+               operating-points-v2 = <&gpu_opp_table>;
+               status = "disabled";
+
+               gpu_opp_table: opp_table {
+                       compatible = "operating-points-v2";
+
+                       opp-160000000 {
+                               opp-hz = /bits/ 64 <160000000>;
+                               opp-microvolt = <1000000>;
+                       };
+                       opp-267000000 {
+                               opp-hz = /bits/ 64 <267000000>;
+                               opp-microvolt = <1000000>;
+                       };
+                       opp-350000000 {
+                               opp-hz = /bits/ 64 <350000000>;
+                               opp-microvolt = <1025000>;
+                       };
+                       opp-420000000 {
+                               opp-hz = /bits/ 64 <420000000>;
+                               opp-microvolt = <1025000>;
+                       };
+                       opp-500000000 {
+                               opp-hz = /bits/ 64 <500000000>;
+                               opp-microvolt = <1075000>;
+                       };
+                       opp-550000000 {
+                               opp-hz = /bits/ 64 <550000000>;
+                               opp-microvolt = <1125000>;
+                       };
+                       opp-600000000 {
+                               opp-hz = /bits/ 64 <600000000>;
+                               opp-microvolt = <1150000>;
+                       };
+                       opp-700000000 {
+                               opp-hz = /bits/ 64 <700000000>;
+                               opp-microvolt = <1150000>;
+                       };
+               };
+       };
+
        psci {
                compatible = "arm,psci";
                method = "smc";
index 00dd89b..080e0f5 100644 (file)
        clock-frequency = <24000000>;
 };
 
+&gpu {
+       mali-supply = <&buck6_reg>;
+       status = "okay";
+};
+
 &serial_2 {
        status = "okay";
 };
index 077d234..bcb9d8c 100644 (file)
                };
        };
 
+       gpu: gpu@14ac0000 {
+               compatible = "samsung,exynos5433-mali", "arm,mali-t760";
+               reg = <0x14ac0000 0x5000>;
+               interrupts = <GIC_SPI 241 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 242 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 240 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "job", "mmu", "gpu";
+               status = "disabled";
+               /* TODO: operating points for DVFS, cooling device */
+       };
+
        psci {
                compatible = "arm,psci-0.2";
                method = "smc";
index 0bd122f..c043aca 100644 (file)
@@ -22,6 +22,7 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-rdb.dtb
 
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mq-evk.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mq-librem5-devkit.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mq-zii-ultra-rmb3.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mq-zii-ultra-zest.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8qxp-mek.dtb
index b359068..de6ef39 100644 (file)
@@ -17,6 +17,7 @@
        compatible = "fsl,ls1028a-qds", "fsl,ls1028a";
 
        aliases {
+               crypto = &crypto;
                gpio0 = &gpio1;
                gpio1 = &gpio2;
                gpio2 = &gpio3;
                regulator-always-on;
        };
 
+       sb_3v3: regulator-sb3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "3v3_vbus";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
        sound {
                compatible = "simple-audio-card";
                simple-audio-card,format = "i2s";
                        #size-cells = <0>;
                        reg = <0x3>;
 
+                       temperature-sensor@4c {
+                               compatible = "nxp,sa56004";
+                               reg = <0x4c>;
+                               vcc-supply = <&sb_3v3>;
+                       };
+
                        rtc@51 {
                                compatible = "nxp,pcf2129";
                                reg = <0x51>;
 &sai1 {
        status = "okay";
 };
+
+&sata {
+       status = "okay";
+};
index f9c272f..9fb9113 100644 (file)
@@ -16,6 +16,7 @@
        compatible = "fsl,ls1028a-rdb", "fsl,ls1028a";
 
        aliases {
+               crypto = &crypto;
                serial0 = &duart0;
                serial1 = &duart1;
        };
                regulator-always-on;
        };
 
+       sb_3v3: regulator-sb3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "3v3_vbus";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
        sound {
                compatible = "simple-audio-card";
                simple-audio-card,format = "i2s";
                        #size-cells = <0>;
                        reg = <0x3>;
 
+                       temperature-sensor@4c {
+                               compatible = "nxp,sa56004";
+                               reg = <0x4c>;
+                               vcc-supply = <&sb_3v3>;
+                       };
+
                        rtc@51 {
                                compatible = "nxp,pcf2129";
                                reg = <0x51>;
 &sai4 {
        status = "okay";
 };
+
+&sata {
+       status = "okay";
+};
index 22a1c74..7975519 100644 (file)
                clock-output-names = "sysclk";
        };
 
+       dpclk: clock-dp {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <27000000>;
+               clock-output-names= "dpclk";
+       };
+
+       aclk: clock-axi {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <650000000>;
+               clock-output-names= "aclk";
+       };
+
+       pclk: clock-apb {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <650000000>;
+               clock-output-names= "pclk";
+       };
+
        reboot {
                compatible ="syscon-reboot";
                regmap = <&dcfg>;
                        #interrupt-cells = <2>;
                };
 
-               wdog0: watchdog@23c0000 {
-                       compatible = "fsl,ls1028a-wdt", "fsl,imx21-wdt";
-                       reg = <0x0 0x23c0000 0x0 0x10000>;
-                       interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&clockgen 4 1>;
-                       big-endian;
-                       status = "disabled";
+               usb0: usb@3100000 {
+                       compatible = "fsl,ls1028a-dwc3", "snps,dwc3";
+                       reg = <0x0 0x3100000 0x0 0x10000>;
+                       interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+                       dr_mode = "host";
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,quirk-frame-length-adjustment = <0x20>;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+               };
+
+               usb1: usb@3110000 {
+                       compatible = "fsl,ls1028a-dwc3", "snps,dwc3";
+                       reg = <0x0 0x3110000 0x0 0x10000>;
+                       interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
+                       dr_mode = "host";
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,quirk-frame-length-adjustment = <0x20>;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
                };
 
                sata: sata@3200000 {
                                     <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH>;
                };
 
+               crypto: crypto@8000000 {
+                       compatible = "fsl,sec-v5.0", "fsl,sec-v4.0";
+                       fsl,sec-era = <10>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x00 0x8000000 0x100000>;
+                       reg = <0x00 0x8000000 0x0 0x100000>;
+                       interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>;
+                       dma-coherent;
+
+                       sec_jr0: jr@10000 {
+                               compatible = "fsl,sec-v5.0-job-ring",
+                                            "fsl,sec-v4.0-job-ring";
+                               reg     = <0x10000 0x10000>;
+                               interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+                       };
+
+                       sec_jr1: jr@20000 {
+                               compatible = "fsl,sec-v5.0-job-ring",
+                                            "fsl,sec-v4.0-job-ring";
+                               reg     = <0x20000 0x10000>;
+                               interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
+                       };
+
+                       sec_jr2: jr@30000 {
+                               compatible = "fsl,sec-v5.0-job-ring",
+                                            "fsl,sec-v4.0-job-ring";
+                               reg     = <0x30000 0x10000>;
+                               interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>;
+                       };
+
+                       sec_jr3: jr@40000 {
+                               compatible = "fsl,sec-v5.0-job-ring",
+                                            "fsl,sec-v4.0-job-ring";
+                               reg     = <0x40000 0x10000>;
+                               interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+                       };
+               };
+
+               qdma: dma-controller@8380000 {
+                       compatible = "fsl,ls1028a-qdma", "fsl,ls1021a-qdma";
+                       reg = <0x0 0x8380000 0x0 0x1000>, /* Controller regs */
+                             <0x0 0x8390000 0x0 0x10000>, /* Status regs */
+                             <0x0 0x83a0000 0x0 0x40000>; /* Block regs */
+                       interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 251 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 252 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 253 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 254 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "qdma-error", "qdma-queue0",
+                               "qdma-queue1", "qdma-queue2", "qdma-queue3";
+                       dma-channels = <8>;
+                       block-number = <1>;
+                       block-offset = <0x10000>;
+                       fsl,dma-queues = <2>;
+                       status-sizes = <64>;
+                       queue-sizes = <64 64>;
+               };
+
+               cluster1_core0_watchdog: watchdog@c000000 {
+                       compatible = "arm,sp805", "arm,primecell";
+                       reg = <0x0 0xc000000 0x0 0x1000>;
+                       clocks = <&clockgen 4 15>, <&clockgen 4 15>;
+                       clock-names = "apb_pclk", "wdog_clk";
+               };
+
+               cluster1_core1_watchdog: watchdog@c010000 {
+                       compatible = "arm,sp805", "arm,primecell";
+                       reg = <0x0 0xc010000 0x0 0x1000>;
+                       clocks = <&clockgen 4 15>, <&clockgen 4 15>;
+                       clock-names = "apb_pclk", "wdog_clk";
+               };
+
                sai1: audio-controller@f100000 {
                        #sound-dai-cells = <0>;
                        compatible = "fsl,vf610-sai";
                        };
                };
        };
+
+       malidp0: display@f080000 {
+               compatible = "arm,mali-dp500";
+               reg = <0x0 0xf080000 0x0 0x10000>;
+               interrupts = <0 222 IRQ_TYPE_LEVEL_HIGH>,
+                            <0 223 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "DE", "SE";
+               clocks = <&dpclk>, <&aclk>, <&aclk>, <&pclk>;
+               clock-names = "pxlclk", "mclk", "aclk", "pclk";
+               arm,malidp-output-port-lines = /bits/ 8 <8 8 8>;
+
+               port {
+                       dp0_out: endpoint {
+
+                       };
+               };
+       };
 };
index 2d5d894..ee7f2b2 100644 (file)
                gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
                enable-active-high;
        };
+
+       wm8524: audio-codec {
+               #sound-dai-cells = <0>;
+               compatible = "wlf,wm8524";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_gpio_wlf>;
+               wlf,mute-gpios = <&gpio5 21 GPIO_ACTIVE_LOW>;
+       };
+
+       sound-wm8524 {
+               compatible = "simple-audio-card";
+               simple-audio-card,name = "wm8524-audio";
+               simple-audio-card,format = "i2s";
+               simple-audio-card,frame-master = <&cpudai>;
+               simple-audio-card,bitclock-master = <&cpudai>;
+               simple-audio-card,widgets =
+                       "Line", "Left Line Out Jack",
+                       "Line", "Right Line Out Jack";
+               simple-audio-card,routing =
+                       "Left Line Out Jack", "LINEVOUTL",
+                       "Right Line Out Jack", "LINEVOUTR";
+
+               cpudai: simple-audio-card,cpu {
+                       sound-dai = <&sai3>;
+               };
+
+               simple-audio-card,codec {
+                       sound-dai = <&wm8524>;
+                       clocks = <&clk IMX8MM_CLK_SAI3_ROOT>;
+               };
+       };
+};
+
+&A53_0 {
+       cpu-supply = <&buck2_reg>;
 };
 
 &fec1 {
        };
 };
 
+&sai3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_sai3>;
+       assigned-clocks = <&clk IMX8MM_CLK_SAI3>;
+       assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>;
+       assigned-clock-rates = <24576000>;
+       status = "okay";
+};
+
+&snvs_pwrkey {
+       status = "okay";
+};
+
 &uart2 { /* console */
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart2>;
        status = "okay";
 };
 
+&i2c1 {
+       clock-frequency = <400000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       status = "okay";
+
+       pmic@4b {
+               compatible = "rohm,bd71847";
+               reg = <0x4b>;
+               pinctrl-0 = <&pinctrl_pmic>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <3 GPIO_ACTIVE_LOW>;
+               rohm,reset-snvs-powered;
+
+               regulators {
+                       buck1_reg: BUCK1 {
+                               regulator-name = "BUCK1";
+                               regulator-min-microvolt = <700000>;
+                               regulator-max-microvolt = <1300000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                               regulator-ramp-delay = <1250>;
+                       };
+
+                       buck2_reg: BUCK2 {
+                               regulator-name = "BUCK2";
+                               regulator-min-microvolt = <700000>;
+                               regulator-max-microvolt = <1300000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                               regulator-ramp-delay = <1250>;
+                               rohm,dvs-run-voltage = <1000000>;
+                               rohm,dvs-idle-voltage = <900000>;
+                       };
+
+                       buck3_reg: BUCK3 {
+                               // BUCK5 in datasheet
+                               regulator-name = "BUCK3";
+                               regulator-min-microvolt = <700000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       buck4_reg: BUCK4 {
+                               // BUCK6 in datasheet
+                               regulator-name = "BUCK4";
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       buck5_reg: BUCK5 {
+                               // BUCK7 in datasheet
+                               regulator-name = "BUCK5";
+                               regulator-min-microvolt = <1605000>;
+                               regulator-max-microvolt = <1995000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       buck6_reg: BUCK6 {
+                               // BUCK8 in datasheet
+                               regulator-name = "BUCK6";
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <1400000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       ldo1_reg: LDO1 {
+                               regulator-name = "LDO1";
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       ldo2_reg: LDO2 {
+                               regulator-name = "LDO2";
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <900000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       ldo3_reg: LDO3 {
+                               regulator-name = "LDO3";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       ldo4_reg: LDO4 {
+                               regulator-name = "LDO4";
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       ldo6_reg: LDO6 {
+                               regulator-name = "LDO6";
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+               };
+       };
+};
+
 &iomuxc {
        pinctrl-names = "default";
 
                >;
        };
 
+       pinctrl_gpio_wlf: gpiowlfgrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_I2C4_SDA_GPIO5_IO21        0xd6
+               >;
+       };
+
+       pinctrl_i2c1: i2c1grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL                  0x400001c3
+                       MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA                  0x400001c3
+               >;
+       };
+
+       pinctrl_pmic: pmicirq {
+               fsl,pins = <
+                       MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3               0x41
+               >;
+       };
+
        pinctrl_reg_usdhc2_vmmc: regusdhc2vmmc {
                fsl,pins = <
                        MX8MM_IOMUXC_SD2_RESET_B_GPIO2_IO19     0x41
                >;
        };
 
+       pinctrl_sai3: sai3grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SAI3_TXFS_SAI3_TX_SYNC     0xd6
+                       MX8MM_IOMUXC_SAI3_TXC_SAI3_TX_BCLK      0xd6
+                       MX8MM_IOMUXC_SAI3_MCLK_SAI3_MCLK        0xd6
+                       MX8MM_IOMUXC_SAI3_TXD_SAI3_TX_DATA0     0xd6
+               >;
+       };
+
        pinctrl_uart2: uart2grp {
                fsl,pins = <
                        MX8MM_IOMUXC_UART2_RXD_UART2_DCE_RX     0x140
index 6b407a9..232a741 100644 (file)
@@ -53,6 +53,8 @@
                        enable-method = "psci";
                        next-level-cache = <&A53_L2>;
                        operating-points-v2 = <&a53_opp_table>;
+                       nvmem-cells = <&cpu_speed_grade>;
+                       nvmem-cell-names = "speed_grade";
                };
 
                A53_1: cpu@1 {
                opp-1200000000 {
                        opp-hz = /bits/ 64 <1200000000>;
                        opp-microvolt = <850000>;
+                       opp-supported-hw = <0xe>, <0x7>;
                        clock-latency-ns = <150000>;
                };
 
                opp-1600000000 {
                        opp-hz = /bits/ 64 <1600000000>;
                        opp-microvolt = <900000>;
+                       opp-supported-hw = <0xc>, <0x7>;
+                       clock-latency-ns = <150000>;
+               };
+
+               opp-1800000000 {
+                       opp-hz = /bits/ 64 <1800000000>;
+                       opp-microvolt = <1000000>;
+                       /* Consumer only but rely on speed grading */
+                       opp-supported-hw = <0x8>, <0x7>;
                        clock-latency-ns = <150000>;
-                       opp-suspend;
                };
        };
 
                clock-output-names = "clk_ext4";
        };
 
-       gic: interrupt-controller@38800000 {
-               compatible = "arm,gic-v3";
-               reg = <0x0 0x38800000 0 0x10000>, /* GIC Dist */
-                     <0x0 0x38880000 0 0xC0000>; /* GICR (RD_base + SGI_base) */
-               #interrupt-cells = <3>;
-               interrupt-controller;
-               interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
-       };
-
        psci {
                compatible = "arm,psci-1.0";
                method = "smc";
                arm,no-tick-in-suspend;
        };
 
-       soc {
+       usbphynop1: usbphynop1 {
+               compatible = "usb-nop-xceiv";
+               clocks = <&clk IMX8MM_CLK_USB_PHY_REF>;
+               assigned-clocks = <&clk IMX8MM_CLK_USB_PHY_REF>;
+               assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_100M>;
+               clock-names = "main_clk";
+       };
+
+       usbphynop2: usbphynop2 {
+               compatible = "usb-nop-xceiv";
+               clocks = <&clk IMX8MM_CLK_USB_PHY_REF>;
+               assigned-clocks = <&clk IMX8MM_CLK_USB_PHY_REF>;
+               assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_100M>;
+               clock-names = "main_clk";
+       };
+
+       soc@0 {
                compatible = "simple-bus";
                #address-cells = <1>;
                #size-cells = <1>;
                        compatible = "fsl,aips-bus", "simple-bus";
                        #address-cells = <1>;
                        #size-cells = <1>;
-                       ranges;
+                       ranges = <0x30000000 0x30000000 0x400000>;
+
+                       sai1: sai@30010000 {
+                               compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai";
+                               reg = <0x30010000 0x10000>;
+                               interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_SAI1_IPG>,
+                                        <&clk IMX8MM_CLK_SAI1_ROOT>,
+                                        <&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>;
+                               clock-names = "bus", "mclk1", "mclk2", "mclk3";
+                               dmas = <&sdma2 0 2 0>, <&sdma2 1 2 0>;
+                               dma-names = "rx", "tx";
+                               status = "disabled";
+                       };
+
+                       sai2: sai@30020000 {
+                               compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai";
+                               reg = <0x30020000 0x10000>;
+                               interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_SAI2_IPG>,
+                                       <&clk IMX8MM_CLK_SAI2_ROOT>,
+                                       <&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>;
+                               clock-names = "bus", "mclk1", "mclk2", "mclk3";
+                               dmas = <&sdma2 2 2 0>, <&sdma2 3 2 0>;
+                               dma-names = "rx", "tx";
+                               status = "disabled";
+                       };
+
+                       sai3: sai@30030000 {
+                               #sound-dai-cells = <0>;
+                               compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai";
+                               reg = <0x30030000 0x10000>;
+                               interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_SAI3_IPG>,
+                                        <&clk IMX8MM_CLK_SAI3_ROOT>,
+                                        <&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>;
+                               clock-names = "bus", "mclk1", "mclk2", "mclk3";
+                               dmas = <&sdma2 4 2 0>, <&sdma2 5 2 0>;
+                               dma-names = "rx", "tx";
+                               status = "disabled";
+                       };
+
+                       sai5: sai@30050000 {
+                               compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai";
+                               reg = <0x30050000 0x10000>;
+                               interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_SAI5_IPG>,
+                                        <&clk IMX8MM_CLK_SAI5_ROOT>,
+                                        <&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>;
+                               clock-names = "bus", "mclk1", "mclk2", "mclk3";
+                               dmas = <&sdma2 8 2 0>, <&sdma2 9 2 0>;
+                               dma-names = "rx", "tx";
+                               status = "disabled";
+                       };
+
+                       sai6: sai@30060000 {
+                               compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai";
+                               reg = <0x30060000 0x10000>;
+                               interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_SAI6_IPG>,
+                                        <&clk IMX8MM_CLK_SAI6_ROOT>,
+                                        <&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>;
+                               clock-names = "bus", "mclk1", "mclk2", "mclk3";
+                               dmas = <&sdma2 10 2 0>, <&sdma2 11 2 0>;
+                               dma-names = "rx", "tx";
+                               status = "disabled";
+                       };
 
                        gpio1: gpio@30200000 {
                                compatible = "fsl,imx8mm-gpio", "fsl,imx35-gpio";
                                reg = <0x30200000 0x10000>;
                                interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_GPIO1_ROOT>;
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
                                reg = <0x30210000 0x10000>;
                                interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_GPIO2_ROOT>;
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
                                reg = <0x30220000 0x10000>;
                                interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_GPIO3_ROOT>;
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
                                reg = <0x30230000 0x10000>;
                                interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_GPIO4_ROOT>;
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
                                reg = <0x30240000 0x10000>;
                                interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_GPIO5_ROOT>;
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
                                /* For nvmem subnodes */
                                #address-cells = <1>;
                                #size-cells = <1>;
+
+                               cpu_speed_grade: speed-grade@10 {
+                                       reg = <0x10 4>;
+                               };
                        };
 
                        anatop: anatop@30360000 {
                                        offset = <0x34>;
                                        interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,
                                                     <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+                                       clocks = <&clk IMX8MM_CLK_SNVS_ROOT>;
+                                       clock-names = "snvs-rtc";
                                };
 
                                snvs_pwrkey: snvs-powerkey {
                                        interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
                                        linux,keycode = <KEY_POWER>;
                                        wakeup-source;
+                                       status = "disabled";
                                };
                        };
 
                        compatible = "fsl,aips-bus", "simple-bus";
                        #address-cells = <1>;
                        #size-cells = <1>;
-                       ranges;
+                       ranges = <0x30400000 0x30400000 0x400000>;
 
                        pwm1: pwm@30660000 {
                                compatible = "fsl,imx8mm-pwm", "fsl,imx27-pwm";
                        compatible = "fsl,aips-bus", "simple-bus";
                        #address-cells = <1>;
                        #size-cells = <1>;
-                       ranges;
+                       ranges = <0x30800000 0x30800000 0x400000>;
 
                        ecspi1: spi@30820000 {
                                compatible = "fsl,imx8mm-ecspi", "fsl,imx51-ecspi";
                        compatible = "fsl,aips-bus", "simple-bus";
                        #address-cells = <1>;
                        #size-cells = <1>;
-                       ranges;
+                       ranges = <0x32c00000 0x32c00000 0x400000>;
 
                        usbotg1: usb@32e40000 {
                                compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb";
                                status = "disabled";
                        };
 
-                       usbphynop1: usbphynop1 {
-                               compatible = "usb-nop-xceiv";
-                               clocks = <&clk IMX8MM_CLK_USB_PHY_REF>;
-                               assigned-clocks = <&clk IMX8MM_CLK_USB_PHY_REF>;
-                               assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_100M>;
-                               clock-names = "main_clk";
-                       };
-
                        usbmisc1: usbmisc@32e40200 {
                                compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc";
                                #index-cells = <1>;
                                status = "disabled";
                        };
 
-                       usbphynop2: usbphynop2 {
-                               compatible = "usb-nop-xceiv";
-                               clocks = <&clk IMX8MM_CLK_USB_PHY_REF>;
-                               assigned-clocks = <&clk IMX8MM_CLK_USB_PHY_REF>;
-                               assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_100M>;
-                               clock-names = "main_clk";
-                       };
-
                        usbmisc2: usbmisc@32e50200 {
                                compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc";
                                #index-cells = <1>;
                        dma-names = "rx-tx";
                        status = "disabled";
                };
+
+               gic: interrupt-controller@38800000 {
+                       compatible = "arm,gic-v3";
+                       reg = <0x38800000 0x10000>, /* GIC Dist */
+                             <0x38880000 0xc0000>; /* GICR (RD_base + SGI_base) */
+                       #interrupt-cells = <3>;
+                       interrupt-controller;
+                       interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+               };
        };
 };
index b2038be..e3df9b8 100644 (file)
        power-supply = <&sw1a_reg>;
 };
 
+&snvs_pwrkey {
+       status = "okay";
+};
+
 &uart1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart1>;
diff --git a/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts b/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts
new file mode 100644 (file)
index 0000000..5179e22
--- /dev/null
@@ -0,0 +1,809 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018-2019 Purism SPC
+ */
+
+/dts-v1/;
+
+#include "dt-bindings/input/input.h"
+#include "dt-bindings/pwm/pwm.h"
+#include "dt-bindings/usb/pd.h"
+#include "imx8mq.dtsi"
+
+/ {
+       model = "Purism Librem 5 devkit";
+       compatible = "purism,librem5-devkit", "fsl,imx8mq";
+
+       backlight_dsi: backlight-dsi {
+               compatible = "pwm-backlight";
+               /* 200 Hz for the PAM2841 */
+               pwms = <&pwm1 0 5000000>;
+               brightness-levels = <0 100>;
+               num-interpolated-steps = <100>;
+               /* Default brightness level (index into the array defined by */
+               /* the "brightness-levels" property) */
+               default-brightness-level = <0>;
+               power-supply = <&reg_22v4_p>;
+       };
+
+       chosen {
+               stdout-path = &uart1;
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_gpio_keys>;
+
+               btn1 {
+                       label = "VOL_UP";
+                       gpios = <&gpio4 21 GPIO_ACTIVE_LOW>;
+                       wakeup-source;
+                       linux,code = <KEY_VOLUMEUP>;
+               };
+
+               btn2 {
+                       label = "VOL_DOWN";
+                       gpios = <&gpio4 22 GPIO_ACTIVE_LOW>;
+                       wakeup-source;
+                       linux,code = <KEY_VOLUMEDOWN>;
+               };
+
+               hp-det {
+                       label = "HP_DET";
+                       gpios = <&gpio3 20 GPIO_ACTIVE_LOW>;
+                       wakeup-source;
+                       linux,code = <KEY_HP>;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_gpio_leds>;
+
+               led1 {
+                       label = "LED 1";
+                       gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>;
+                       default-state = "off";
+               };
+       };
+
+       pmic_osc: clock-pmic {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <32768>;
+               clock-output-names = "pmic_osc";
+       };
+
+       reg_1v8_p: regulator-1v8-p {
+               compatible = "regulator-fixed";
+               regulator-name = "1v8_p";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               vin-supply = <&reg_pwr_en>;
+       };
+
+       reg_2v8_p: regulator-2v8-p {
+               compatible = "regulator-fixed";
+               regulator-name = "2v8_p";
+               regulator-min-microvolt = <2800000>;
+               regulator-max-microvolt = <2800000>;
+               vin-supply = <&reg_pwr_en>;
+       };
+
+       reg_3v3_p: regulator-3v3-p {
+               compatible = "regulator-fixed";
+               regulator-name = "3v3_p";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&reg_pwr_en>;
+
+               regulator-state-mem {
+                       regulator-on-in-suspend;
+               };
+       };
+
+       reg_5v_p: regulator-5v-p {
+               compatible = "regulator-fixed";
+               regulator-name = "5v_p";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&reg_pwr_en>;
+
+               regulator-state-mem {
+                       regulator-on-in-suspend;
+               };
+       };
+
+       reg_22v4_p: regulator-22v4-p  {
+               compatible = "regulator-fixed";
+               regulator-name = "22v4_P";
+               regulator-min-microvolt = <22400000>;
+               regulator-max-microvolt = <22400000>;
+               vin-supply = <&reg_pwr_en>;
+       };
+
+       reg_pwr_en: regulator-pwr-en {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_pwr_en>;
+               regulator-name = "PWR_EN";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               gpio = <&gpio1 8 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               regulator-always-on;
+       };
+
+       reg_usdhc2_vmmc: regulator-usdhc2-vmmc {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_usdhc2_pwr>;
+               regulator-name = "VSD_3V3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               regulator-always-on;
+       };
+
+       vibrator {
+               compatible = "gpio-vibrator";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_haptic>;
+               enable-gpios = <&gpio5 4 GPIO_ACTIVE_LOW>;
+               vcc-supply = <&reg_3v3_p>;
+       };
+
+       wifi_pwr_en: regulator-wifi-en {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_wifi_pwr_en>;
+               regulator-name = "WIFI_EN";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               gpio = <&gpio3 5 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               regulator-always-on;
+       };
+};
+
+&clk {
+       assigned-clocks = <&clk IMX8MQ_AUDIO_PLL1>, <&clk IMX8MQ_AUDIO_PLL2>;
+       assigned-clock-rates = <786432000>, <722534400>;
+};
+
+&fec1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_fec1>;
+       phy-mode = "rgmii-id";
+       phy-handle = <&ethphy0>;
+       fsl,magic-packet;
+       phy-supply = <&reg_3v3_p>;
+       status = "okay";
+
+       mdio {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               ethphy0: ethernet-phy@1 {
+                       compatible = "ethernet-phy-ieee802.3-c22";
+                       reg = <1>;
+               };
+       };
+};
+
+&i2c1 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       status = "okay";
+
+       pmic: pmic@4b {
+               compatible = "rohm,bd71837";
+               reg = <0x4b>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_pmic>;
+               clocks = <&pmic_osc>;
+               clock-names = "osc";
+               clock-output-names = "pmic_clk";
+               interrupt-parent = <&gpio1>;
+               interrupts = <3 GPIO_ACTIVE_LOW>;
+               interrupt-names = "irq";
+               rohm,reset-snvs-powered;
+
+               regulators {
+                       buck1_reg: BUCK1 {
+                               regulator-name = "buck1";
+                               regulator-min-microvolt = <700000>;
+                               regulator-max-microvolt = <1300000>;
+                               regulator-boot-on;
+                               regulator-ramp-delay = <1250>;
+                               rohm,dvs-run-voltage = <900000>;
+                               rohm,dvs-idle-voltage = <850000>;
+                               rohm,dvs-suspend-voltage = <800000>;
+                       };
+
+                       buck2_reg: BUCK2 {
+                               regulator-name = "buck2";
+                               regulator-min-microvolt = <700000>;
+                               regulator-max-microvolt = <1300000>;
+                               regulator-boot-on;
+                               regulator-ramp-delay = <1250>;
+                               rohm,dvs-run-voltage = <1000000>;
+                               rohm,dvs-idle-voltage = <900000>;
+                       };
+
+                       buck3_reg: BUCK3 {
+                               regulator-name = "buck3";
+                               regulator-min-microvolt = <700000>;
+                               regulator-max-microvolt = <1300000>;
+                               regulator-boot-on;
+                               rohm,dvs-run-voltage = <1000000>;
+                       };
+
+                       buck4_reg: BUCK4 {
+                               regulator-name = "buck4";
+                               regulator-min-microvolt = <700000>;
+                               regulator-max-microvolt = <1300000>;
+                               rohm,dvs-run-voltage = <1000000>;
+                       };
+
+                       buck5_reg: BUCK5 {
+                               regulator-name = "buck5";
+                               regulator-min-microvolt = <700000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-boot-on;
+                       };
+
+                       buck6_reg: BUCK6 {
+                               regulator-name = "buck6";
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                       };
+
+                       buck7_reg: BUCK7 {
+                               regulator-name = "buck7";
+                               regulator-min-microvolt = <1605000>;
+                               regulator-max-microvolt = <1995000>;
+                               regulator-boot-on;
+                       };
+
+                       buck8_reg: BUCK8 {
+                               regulator-name = "buck8";
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <1400000>;
+                               regulator-boot-on;
+                       };
+
+                       ldo1_reg: LDO1 {
+                               regulator-name = "ldo1";
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                               /* leave on for snvs power button */
+                               regulator-always-on;
+                       };
+
+                       ldo2_reg: LDO2 {
+                               regulator-name = "ldo2";
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <900000>;
+                               regulator-boot-on;
+                               /* leave on for snvs power button */
+                               regulator-always-on;
+                       };
+
+                       ldo3_reg: LDO3 {
+                               regulator-name = "ldo3";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                       };
+
+                       ldo4_reg: LDO4 {
+                               regulator-name = "ldo4";
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-boot-on;
+                       };
+
+                       ldo5_reg: LDO5 {
+                               regulator-name = "ldo5";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       ldo6_reg: LDO6 {
+                               regulator-name = "ldo6";
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-boot-on;
+                       };
+
+                       ldo7_reg: LDO7 {
+                               regulator-name = "ldo7";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                       };
+               };
+       };
+
+       typec_ptn5100: usb_typec@52 {
+               compatible = "nxp,ptn5110";
+               reg = <0x52>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_typec>;
+               interrupt-parent = <&gpio3>;
+               interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
+
+               connector {
+                       compatible = "usb-c-connector";
+                       label = "USB-C";
+                       data-role = "dual";
+                       power-role = "dual";
+                       try-power-role = "sink";
+                       source-pdos = <PDO_FIXED(5000, 2000,
+                               PDO_FIXED_USB_COMM |
+                               PDO_FIXED_DUAL_ROLE |
+                               PDO_FIXED_DATA_SWAP )>;
+                       sink-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_USB_COMM |
+                               PDO_FIXED_DUAL_ROLE |
+                               PDO_FIXED_DATA_SWAP )
+                            PDO_VAR(5000, 3000, 3000)>;
+                       op-sink-microwatt = <10000000>;
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+
+                                       usb_con_hs: endpoint {
+                                               remote-endpoint = <&typec_hs>;
+                                       };
+                               };
+
+                               port@1 {
+                                       reg = <1>;
+
+                                       usb_con_ss: endpoint {
+                                               remote-endpoint = <&typec_ss>;
+                                       };
+                               };
+                       };
+               };
+       };
+
+       rtc@68 {
+               compatible = "microcrystal,rv4162";
+               reg = <0x68>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_rtc>;
+               interrupt-parent = <&gpio4>;
+               interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
+       };
+
+       charger@6b { /* bq25896 */
+               compatible = "ti,bq25890";
+               reg = <0x6b>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_charger>;
+               interrupt-parent = <&gpio3>;
+               interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
+               ti,battery-regulation-voltage = <4192000>; /* 4.192V */
+               ti,charge-current = <1600000>; /* 1.6A */
+               ti,termination-current = <66000>;  /* 66mA */
+               ti,precharge-current = <130000>; /* 130mA */
+               ti,minimum-sys-voltage = <3000000>; /* 3V */
+               ti,boost-voltage = <5000000>; /* 5V */
+               ti,boost-max-current = <50000>; /* 50mA */
+       };
+};
+
+&i2c3 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c3>;
+       status = "okay";
+
+       magnetometer@1e {
+               compatible = "st,lsm9ds1-magn";
+               reg = <0x1e>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_imu>;
+               interrupt-parent = <&gpio3>;
+               interrupts = <19 IRQ_TYPE_LEVEL_LOW>;
+               vdd-supply = <&reg_3v3_p>;
+               vddio-supply = <&reg_3v3_p>;
+       };
+
+       touchscreen@5d {
+               compatible = "goodix,gt5688";
+               reg = <0x5d>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_ts>;
+               interrupt-parent = <&gpio3>;
+               interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+               reset-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
+               irq-gpios = <&gpio3 0 GPIO_ACTIVE_HIGH>;
+               touchscreen-size-x = <720>;
+               touchscreen-size-y = <1440>;
+               AVDD28-supply = <&reg_2v8_p>;
+               VDDIO-supply = <&reg_1v8_p>;
+       };
+};
+
+&iomuxc {
+       pinctrl_bl: blgrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_GPIO1_IO01_PWM1_OUT        0x6 /* DSI_BL_PWM */
+               >;
+       };
+
+       pinctrl_bt: btgrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_NAND_DATA05_GPIO3_IO11     0x16 /* nBT_DISABLE */
+                       MX8MQ_IOMUXC_NAND_DATA01_GPIO3_IO7      0x10 /* BT_HOST_WAKE */
+               >;
+       };
+
+       pinctrl_charger: chargergrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SAI5_MCLK_GPIO3_IO25       0x80 /* CHRG_nINT */
+               >;
+       };
+
+       pinctrl_fec1: fec1grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_ENET_MDC_ENET1_MDC                 0x3
+                       MX8MQ_IOMUXC_ENET_MDIO_ENET1_MDIO               0x3
+                       MX8MQ_IOMUXC_ENET_TD3_ENET1_RGMII_TD3           0x1f
+                       MX8MQ_IOMUXC_ENET_TD2_ENET1_RGMII_TD2           0x1f
+                       MX8MQ_IOMUXC_ENET_TD1_ENET1_RGMII_TD1           0x1f
+                       MX8MQ_IOMUXC_ENET_TD0_ENET1_RGMII_TD0           0x1f
+                       MX8MQ_IOMUXC_ENET_RD3_ENET1_RGMII_RD3           0x91
+                       MX8MQ_IOMUXC_ENET_RD2_ENET1_RGMII_RD2           0x91
+                       MX8MQ_IOMUXC_ENET_RD1_ENET1_RGMII_RD1           0x91
+                       MX8MQ_IOMUXC_ENET_RD0_ENET1_RGMII_RD0           0x91
+                       MX8MQ_IOMUXC_ENET_TXC_ENET1_RGMII_TXC           0x1f
+                       MX8MQ_IOMUXC_ENET_RXC_ENET1_RGMII_RXC           0x91
+                       MX8MQ_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL     0x91
+                       MX8MQ_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL     0x1f
+                       MX8MQ_IOMUXC_GPIO1_IO09_GPIO1_IO9               0x19
+                       MX8MQ_IOMUXC_GPIO1_IO15_CCMSRCGPCMIX_CLKO2      0x1f
+               >;
+       };
+
+       pinctrl_ts: tsgrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_NAND_ALE_GPIO3_IO0         0x16  /* TOUCH INT */
+                       MX8MQ_IOMUXC_GPIO1_IO05_GPIO1_IO5       0x19  /* TOUCH RST */
+               >;
+       };
+
+       pinctrl_gpio_leds: gpioledgrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_GPIO1_IO13_GPIO1_IO13      0x16
+               >;
+       };
+
+       pinctrl_gpio_keys: gpiokeygrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SAI2_RXFS_GPIO4_IO21       0x16
+                       MX8MQ_IOMUXC_SAI2_RXC_GPIO4_IO22        0x16
+                       MX8MQ_IOMUXC_SAI5_RXC_GPIO3_IO20        0x180  /* HP_DET */
+               >;
+       };
+
+       pinctrl_haptic: hapticgrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SPDIF_RX_GPIO5_IO4         0xc6   /* nHAPTIC */
+               >;
+       };
+
+       pinctrl_i2c1: i2c1grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_I2C1_SCL_I2C1_SCL          0x4000001f
+                       MX8MQ_IOMUXC_I2C1_SDA_I2C1_SDA          0x4000001f
+               >;
+       };
+
+       pinctrl_i2c3: i2c3grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_I2C3_SCL_I2C3_SCL          0x4000001f
+                       MX8MQ_IOMUXC_I2C3_SDA_I2C3_SDA          0x4000001f
+               >;
+       };
+
+       pinctrl_imu: imugrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SAI5_RXFS_GPIO3_IO19       0x8  /* IMU_INT */
+               >;
+       };
+
+       pinctrl_pmic: pmicgrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_GPIO1_IO03_GPIO1_IO3       0x80  /* PMIC intr */
+               >;
+       };
+
+       pinctrl_pwr_en: pwrengrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_GPIO1_IO08_GPIO1_IO8       0x06
+               >;
+       };
+
+       pinctrl_rtc: rtcgrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SAI3_RXC_GPIO4_IO29        0x80  /* RTC intr */
+               >;
+       };
+
+       pinctrl_typec: typecgrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_NAND_DATA06_GPIO3_IO12             0x16
+                       MX8MQ_IOMUXC_NAND_CE0_B_GPIO3_IO1               0x80
+               >;
+       };
+
+       pinctrl_uart1: uart1grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_UART1_RXD_UART1_DCE_RX             0x49
+                       MX8MQ_IOMUXC_UART1_TXD_UART1_DCE_TX             0x49
+               >;
+       };
+
+       pinctrl_uart2: uart2grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_UART2_TXD_UART2_DCE_TX             0x49
+                       MX8MQ_IOMUXC_UART2_RXD_UART2_DCE_RX             0x49
+                       MX8MQ_IOMUXC_UART4_RXD_UART2_DCE_CTS_B          0x49
+                       MX8MQ_IOMUXC_UART4_TXD_UART2_DCE_RTS_B          0x49
+               >;
+       };
+
+       pinctrl_uart3: uart3grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_UART3_RXD_UART3_DCE_RX             0x49
+                       MX8MQ_IOMUXC_UART3_TXD_UART3_DCE_TX             0x49
+               >;
+       };
+
+       pinctrl_uart4: uart4grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_ECSPI2_SCLK_UART4_DCE_RX           0x49
+                       MX8MQ_IOMUXC_ECSPI2_MOSI_UART4_DCE_TX           0x49
+                       MX8MQ_IOMUXC_ECSPI2_MISO_UART4_DCE_CTS_B        0x49
+                       MX8MQ_IOMUXC_ECSPI2_SS0_UART4_DCE_RTS_B         0x49
+                       MX8MQ_IOMUXC_GPIO1_IO00_ANAMIX_REF_CLK_32K      0x49
+               >;
+       };
+
+       pinctrl_usdhc1: usdhc1grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK                 0x83
+                       MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD                 0xc3
+                       MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0             0xc3
+                       MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1             0xc3
+                       MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2             0xc3
+                       MX8MQ_IOMUXC_SD1_DATA3_USDHC1_DATA3             0xc3
+                       MX8MQ_IOMUXC_SD1_DATA4_USDHC1_DATA4             0xc3
+                       MX8MQ_IOMUXC_SD1_DATA5_USDHC1_DATA5             0xc3
+                       MX8MQ_IOMUXC_SD1_DATA6_USDHC1_DATA6             0xc3
+                       MX8MQ_IOMUXC_SD1_DATA7_USDHC1_DATA7             0xc3
+                       MX8MQ_IOMUXC_SD1_STROBE_USDHC1_STROBE           0x83
+                       MX8MQ_IOMUXC_SD1_RESET_B_USDHC1_RESET_B         0xc1
+               >;
+       };
+
+       pinctrl_usdhc1_100mhz: usdhc1grp100mhz {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK                 0x8d
+                       MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD                 0xcd
+                       MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0             0xcd
+                       MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1             0xcd
+                       MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2             0xcd
+                       MX8MQ_IOMUXC_SD1_DATA3_USDHC1_DATA3             0xcd
+                       MX8MQ_IOMUXC_SD1_DATA4_USDHC1_DATA4             0xcd
+                       MX8MQ_IOMUXC_SD1_DATA5_USDHC1_DATA5             0xcd
+                       MX8MQ_IOMUXC_SD1_DATA6_USDHC1_DATA6             0xcd
+                       MX8MQ_IOMUXC_SD1_DATA7_USDHC1_DATA7             0xcd
+                       MX8MQ_IOMUXC_SD1_STROBE_USDHC1_STROBE           0x8d
+                       MX8MQ_IOMUXC_SD1_RESET_B_USDHC1_RESET_B         0xc1
+               >;
+       };
+
+       pinctrl_usdhc1_200mhz: usdhc1grp200mhz {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK                 0x9f
+                       MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD                 0xdf
+                       MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0             0xdf
+                       MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1             0xdf
+                       MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2             0xdf
+                       MX8MQ_IOMUXC_SD1_DATA3_USDHC1_DATA3             0xdf
+                       MX8MQ_IOMUXC_SD1_DATA4_USDHC1_DATA4             0xdf
+                       MX8MQ_IOMUXC_SD1_DATA5_USDHC1_DATA5             0xdf
+                       MX8MQ_IOMUXC_SD1_DATA6_USDHC1_DATA6             0xdf
+                       MX8MQ_IOMUXC_SD1_DATA7_USDHC1_DATA7             0xdf
+                       MX8MQ_IOMUXC_SD1_STROBE_USDHC1_STROBE           0x9f
+                       MX8MQ_IOMUXC_SD1_RESET_B_USDHC1_RESET_B         0xc1
+               >;
+       };
+
+       pinctrl_usdhc2_pwr: usdhc2grppwr {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SD2_RESET_B_GPIO2_IO19     0x41
+               >;
+       };
+
+       pinctrl_usdhc2_gpio: usdhc2grpgpio {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SD2_WP_GPIO2_IO20          0x80 /* WIFI_WAKE */
+               >;
+       };
+
+       pinctrl_usdhc2: usdhc2grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SD2_CLK_USDHC2_CLK         0x83
+                       MX8MQ_IOMUXC_SD2_CMD_USDHC2_CMD         0xc3
+                       MX8MQ_IOMUXC_SD2_DATA0_USDHC2_DATA0     0xc3
+                       MX8MQ_IOMUXC_SD2_DATA1_USDHC2_DATA1     0xc3
+                       MX8MQ_IOMUXC_SD2_DATA2_USDHC2_DATA2     0xc3
+                       MX8MQ_IOMUXC_SD2_DATA3_USDHC2_DATA3     0xc3
+               >;
+       };
+
+       pinctrl_usdhc2_100mhz: usdhc2grp100mhz {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SD2_CLK_USDHC2_CLK         0x8d
+                       MX8MQ_IOMUXC_SD2_CMD_USDHC2_CMD         0xcd
+                       MX8MQ_IOMUXC_SD2_DATA0_USDHC2_DATA0     0xcd
+                       MX8MQ_IOMUXC_SD2_DATA1_USDHC2_DATA1     0xcd
+                       MX8MQ_IOMUXC_SD2_DATA2_USDHC2_DATA2     0xcd
+                       MX8MQ_IOMUXC_SD2_DATA3_USDHC2_DATA3     0xcd
+               >;
+       };
+
+       pinctrl_usdhc2_200mhz: usdhc2grp200mhz {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SD2_CLK_USDHC2_CLK         0x9f
+                       MX8MQ_IOMUXC_SD2_CMD_USDHC2_CMD         0xcf
+                       MX8MQ_IOMUXC_SD2_DATA0_USDHC2_DATA0     0xcf
+                       MX8MQ_IOMUXC_SD2_DATA1_USDHC2_DATA1     0xcf
+                       MX8MQ_IOMUXC_SD2_DATA2_USDHC2_DATA2     0xcf
+                       MX8MQ_IOMUXC_SD2_DATA3_USDHC2_DATA3     0xcf
+               >;
+       };
+
+       pinctrl_wdog: wdoggrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B    0xc6
+               >;
+       };
+
+       pinctrl_wifi_pwr_en: wifipwrengrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_NAND_CLE_GPIO3_IO5         0x06
+               >;
+       };
+
+       pinctrl_wwan: wwangrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_NAND_CE3_B_GPIO3_IO4       0x09 /* nWWAN_DISABLE */
+                       MX8MQ_IOMUXC_NAND_DATA02_GPIO3_IO8      0x80 /* nWoWWAN */
+                       MX8MQ_IOMUXC_NAND_DATA03_GPIO3_IO9      0x19 /* WWAN_RESET */
+               >;
+       };
+};
+
+&pgc_gpu {
+       power-supply = <&buck3_reg>;
+};
+
+&pgc_vpu {
+       power-supply = <&buck4_reg>;
+};
+
+&pwm1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_bl>;
+       status = "okay";
+};
+
+&snvs_pwrkey {
+       status = "okay";
+};
+
+&uart1 { /* console */
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
+       status = "okay";
+};
+
+&uart3 { /* GNSS */
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart3>;
+       status = "okay";
+};
+
+&uart4 { /* BT */
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart4>, <&pinctrl_bt>;
+       uart-has-rtscts;
+       status = "okay";
+};
+
+&usb3_phy0 {
+       status = "okay";
+};
+
+&usb3_phy1 {
+       vbus-supply = <&reg_5v_p>;
+       status = "okay";
+};
+
+&usb_dwc3_0 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       dr_mode = "otg";
+       status = "okay";
+
+       port@0 {
+               reg = <0>;
+
+               typec_hs: endpoint {
+                       remote-endpoint = <&usb_con_hs>;
+               };
+       };
+
+       port@1 {
+               reg = <1>;
+
+               typec_ss: endpoint {
+                       remote-endpoint = <&usb_con_ss>;
+               };
+       };
+};
+
+&usb_dwc3_1 {
+       dr_mode = "host";
+       status = "okay";
+};
+
+&usdhc1 {
+       pinctrl-names = "default", "state_100mhz", "state_200mhz";
+       pinctrl-0 = <&pinctrl_usdhc1>;
+       pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+       pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+       bus-width = <8>;
+       non-removable;
+       status = "okay";
+};
+
+&usdhc2 {
+       pinctrl-names = "default", "state_100mhz", "state_200mhz";
+       pinctrl-0 = <&pinctrl_usdhc2>;
+       pinctrl-1 = <&pinctrl_usdhc2_100mhz>;
+       pinctrl-2 = <&pinctrl_usdhc2_200mhz>;
+       bus-width = <4>;
+       vmmc-supply = <&reg_usdhc2_vmmc>;
+       power-supply = <&wifi_pwr_en>;
+       non-removable;
+       disable-wp;
+       cap-sdio-irq;
+       keep-power-in-suspend;
+       wakeup-source;
+       status = "okay";
+};
+
+&wdog1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_wdog>;
+       fsl,ext-reset-output;
+       status = "okay";
+};
index 6d635ba..d09b808 100644 (file)
@@ -8,6 +8,7 @@
 #include <dt-bindings/power/imx8mq-power.h>
 #include <dt-bindings/reset/imx8mq-reset.h>
 #include <dt-bindings/gpio/gpio.h>
+#include "dt-bindings/input/input.h"
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/thermal/thermal.h>
 #include "imx8mq-pinfunc.h"
        #size-cells = <2>;
 
        aliases {
+               gpio0 = &gpio1;
+               gpio1 = &gpio2;
+               gpio2 = &gpio3;
+               gpio3 = &gpio4;
+               gpio4 = &gpio5;
                i2c0 = &i2c1;
                i2c1 = &i2c2;
                i2c2 = &i2c3;
                        next-level-cache = <&A53_L2>;
                        operating-points-v2 = <&a53_opp_table>;
                        #cooling-cells = <2>;
+                       nvmem-cells = <&cpu_speed_grade>;
+                       nvmem-cell-names = "speed_grade";
                };
 
                A53_1: cpu@1 {
                opp-800000000 {
                        opp-hz = /bits/ 64 <800000000>;
                        opp-microvolt = <900000>;
+                       /* Industrial only */
+                       opp-supported-hw = <0xf>, <0x4>;
+                       clock-latency-ns = <150000>;
+               };
+
+               opp-1000000000 {
+                       opp-hz = /bits/ 64 <1000000000>;
+                       opp-microvolt = <900000>;
+                       /* Consumer only */
+                       opp-supported-hw = <0xe>, <0x3>;
                        clock-latency-ns = <150000>;
                };
 
                opp-1300000000 {
                        opp-hz = /bits/ 64 <1300000000>;
                        opp-microvolt = <1000000>;
+                       opp-supported-hw = <0xc>, <0x7>;
+                       clock-latency-ns = <150000>;
+               };
+
+               opp-1500000000 {
+                       opp-hz = /bits/ 64 <1500000000>;
+                       opp-microvolt = <1000000>;
+                       /* Consumer only but rely on speed grading */
+                       opp-supported-hw = <0x8>, <0x7>;
                        clock-latency-ns = <150000>;
-                       opp-suspend;
                };
        };
 
                                clocks = <&clk IMX8MQ_CLK_OCOTP_ROOT>;
                                #address-cells = <1>;
                                #size-cells = <1>;
+
+                               cpu_speed_grade: speed-grade@10 {
+                                       reg = <0x10 4>;
+                               };
                        };
 
                        anatop: syscon@30360000 {
                                        offset = <0x34>;
                                        interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,
                                                <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+                                       clocks = <&clk IMX8MQ_CLK_SNVS_ROOT>;
+                                       clock-names = "snvs-rtc";
                                };
 
+                               snvs_pwrkey: snvs-powerkey {
+                                       compatible = "fsl,sec-v4.0-pwrkey";
+                                       regmap = <&snvs>;
+                                       interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+                                       linux,keycode = <KEY_POWER>;
+                                       wakeup-source;
+                                       status = "disabled";
+                               };
                        };
 
                        clk: clock-controller@30380000 {
                        };
                };
 
+               bus@32c00000 { /* AIPS4 */
+                       compatible = "fsl,imx8mq-aips-bus", "simple-bus";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x32c00000 0x32c00000 0x400000>;
+
+                       irqsteer: interrupt-controller@32e2d000 {
+                               compatible = "fsl,imx8m-irqsteer", "fsl,imx-irqsteer";
+                               reg = <0x32e2d000 0x1000>;
+                               interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MQ_CLK_DISP_APB_ROOT>;
+                               clock-names = "ipg";
+                               fsl,channel = <0>;
+                               fsl,num-irqs = <64>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                       };
+               };
+
                gpu: gpu@38000000 {
                        compatible = "vivante,gc";
                        reg = <0x38000000 0x40000>;
                        status = "disabled";
                };
 
-
                pcie0: pcie@33800000 {
                        compatible = "fsl,imx8mq-pcie";
                        reg = <0x33800000 0x400000>,
index 0683ee2..05fa0b7 100644 (file)
        #size-cells = <2>;
 
        aliases {
+               gpio0 = &lsio_gpio0;
+               gpio1 = &lsio_gpio1;
+               gpio2 = &lsio_gpio2;
+               gpio3 = &lsio_gpio3;
+               gpio4 = &lsio_gpio4;
+               gpio5 = &lsio_gpio5;
+               gpio6 = &lsio_gpio6;
+               gpio7 = &lsio_gpio7;
                mmc0 = &usdhc1;
                mmc1 = &usdhc2;
                mmc2 = &usdhc3;
-               serial0 = &adma_lpuart0;
                mu1 = &lsio_mu1;
+               serial0 = &adma_lpuart0;
        };
 
        cpus {
                        compatible = "fsl,imx8qxp-iomuxc";
                };
 
+               ocotp: imx8qx-ocotp {
+                       compatible = "fsl,imx8qxp-scu-ocotp";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+               };
+
                pd: imx8qx-pd {
                        compatible = "fsl,imx8qxp-scu-pd";
                        #power-domain-cells = <1>;
                rtc: rtc {
                        compatible = "fsl,imx8qxp-sc-rtc";
                };
+
+               watchdog {
+                       compatible = "fsl,imx8qxp-sc-wdt", "fsl,imx-sc-wdt";
+                       timeout-sec = <60>;
+               };
        };
 
        timer {
                };
        };
 
-       lsio_subsys: bus@5d000000 {
+       ddr_subsyss: bus@5c000000 {
                compatible = "simple-bus";
                #address-cells = <1>;
                #size-cells = <1>;
-               ranges = <0x5d000000 0x0 0x5d000000 0x1000000>;
-
-               lsio_lpcg: clock-controller@5d400000 {
-                       compatible = "fsl,imx8qxp-lpcg-lsio";
-                       reg = <0x5d400000 0x400000>;
-                       #clock-cells = <1>;
-               };
+               ranges = <0x5c000000 0x0 0x5c000000 0x1000000>;
 
-               lsio_mu0: mailbox@5d1b0000 {
-                       compatible = "fsl,imx8qxp-mu", "fsl,imx6sx-mu";
-                       reg = <0x5d1b0000 0x10000>;
-                       interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
-                       #mbox-cells = <2>;
-                       status = "disabled";
-               };
-
-               lsio_mu1: mailbox@5d1c0000 {
-                       compatible = "fsl,imx8qxp-mu", "fsl,imx6sx-mu";
-                       reg = <0x5d1c0000 0x10000>;
-                       interrupts = <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH>;
-                       #mbox-cells = <2>;
-               };
-
-               lsio_mu2: mailbox@5d1d0000 {
-                       compatible = "fsl,imx8qxp-mu", "fsl,imx6sx-mu";
-                       reg = <0x5d1d0000 0x10000>;
-                       interrupts = <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>;
-                       #mbox-cells = <2>;
-                       status = "disabled";
-               };
-
-               lsio_mu3: mailbox@5d1e0000 {
-                       compatible = "fsl,imx8qxp-mu", "fsl,imx6sx-mu";
-                       reg = <0x5d1e0000 0x10000>;
-                       interrupts = <GIC_SPI 179 IRQ_TYPE_LEVEL_HIGH>;
-                       #mbox-cells = <2>;
-                       status = "disabled";
+               ddr-pmu@5c020000 {
+                       compatible = "fsl,imx8-ddr-pmu";
+                       reg = <0x5c020000 0x10000>;
+                       interrupt-parent = <&gic>;
+                       interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
                };
+       };
 
-               lsio_mu4: mailbox@5d1f0000 {
-                       compatible = "fsl,imx8qxp-mu", "fsl,imx6sx-mu";
-                       reg = <0x5d1f0000 0x10000>;
-                       interrupts = <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>;
-                       #mbox-cells = <2>;
-                       status = "disabled";
-               };
+       lsio_subsys: bus@5d000000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x5d000000 0x0 0x5d000000 0x1000000>;
 
                lsio_gpio0: gpio@5d080000 {
                        compatible = "fsl,imx8qxp-gpio", "fsl,imx35-gpio";
                        #interrupt-cells = <2>;
                        power-domains = <&pd IMX_SC_R_GPIO_7>;
                };
-       };
 
-       watchdog {
-               compatible = "fsl,imx8qxp-sc-wdt", "fsl,imx-sc-wdt";
-               timeout-sec = <60>;
+               lsio_mu0: mailbox@5d1b0000 {
+                       compatible = "fsl,imx8qxp-mu", "fsl,imx6sx-mu";
+                       reg = <0x5d1b0000 0x10000>;
+                       interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
+                       #mbox-cells = <2>;
+                       status = "disabled";
+               };
+
+               lsio_mu1: mailbox@5d1c0000 {
+                       compatible = "fsl,imx8qxp-mu", "fsl,imx6sx-mu";
+                       reg = <0x5d1c0000 0x10000>;
+                       interrupts = <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH>;
+                       #mbox-cells = <2>;
+               };
+
+               lsio_mu2: mailbox@5d1d0000 {
+                       compatible = "fsl,imx8qxp-mu", "fsl,imx6sx-mu";
+                       reg = <0x5d1d0000 0x10000>;
+                       interrupts = <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>;
+                       #mbox-cells = <2>;
+                       status = "disabled";
+               };
+
+               lsio_mu3: mailbox@5d1e0000 {
+                       compatible = "fsl,imx8qxp-mu", "fsl,imx6sx-mu";
+                       reg = <0x5d1e0000 0x10000>;
+                       interrupts = <GIC_SPI 179 IRQ_TYPE_LEVEL_HIGH>;
+                       #mbox-cells = <2>;
+                       status = "disabled";
+               };
+
+               lsio_mu4: mailbox@5d1f0000 {
+                       compatible = "fsl,imx8qxp-mu", "fsl,imx6sx-mu";
+                       reg = <0x5d1f0000 0x10000>;
+                       interrupts = <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>;
+                       #mbox-cells = <2>;
+                       status = "disabled";
+               };
+
+               lsio_mu13: mailbox@5d280000 {
+                       compatible = "fsl,imx8qxp-mu", "fsl,imx6sx-mu";
+                       reg = <0x5d280000 0x10000>;
+                       interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>;
+                       #mbox-cells = <2>;
+                       power-domains = <&pd IMX_SC_R_MU_13A>;
+               };
+
+               lsio_lpcg: clock-controller@5d400000 {
+                       compatible = "fsl,imx8qxp-lpcg-lsio";
+                       reg = <0x5d400000 0x400000>;
+                       #clock-cells = <1>;
+               };
        };
 };
diff --git a/arch/arm64/boot/dts/hisilicon/hi3660-coresight.dtsi b/arch/arm64/boot/dts/hisilicon/hi3660-coresight.dtsi
new file mode 100644 (file)
index 0000000..d607f2f
--- /dev/null
@@ -0,0 +1,456 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * dtsi for Hisilicon Hi3660 Coresight
+ *
+ * Copyright (C) 2016-2018 Hisilicon Ltd.
+ *
+ * Author: Wanglai Shi <shiwanglai@hisilicon.com>
+ *
+ */
+/ {
+       soc {
+               /* A53 cluster internals */
+               etm@ecc40000 {
+                       compatible = "arm,coresight-etm4x", "arm,primecell";
+                       reg = <0 0xecc40000 0 0x1000>;
+                       clocks = <&crg_ctrl HI3660_PCLK>;
+                       clock-names = "apb_pclk";
+                       cpu = <&cpu0>;
+
+                       out-ports {
+                               port {
+                                       etm0_out: endpoint {
+                                               remote-endpoint =
+                                                       <&cluster0_funnel_in0>;
+                                       };
+                               };
+                       };
+               };
+
+               etm@ecd40000 {
+                       compatible = "arm,coresight-etm4x", "arm,primecell";
+                       reg = <0 0xecd40000 0 0x1000>;
+                       clocks = <&crg_ctrl HI3660_PCLK>;
+                       clock-names = "apb_pclk";
+                       cpu = <&cpu1>;
+
+                       out-ports {
+                               port {
+                                       etm1_out: endpoint {
+                                               remote-endpoint =
+                                                       <&cluster0_funnel_in1>;
+                                       };
+                               };
+                       };
+               };
+
+               etm@ece40000 {
+                       compatible = "arm,coresight-etm4x", "arm,primecell";
+                       reg = <0 0xece40000 0 0x1000>;
+                       clocks = <&crg_ctrl HI3660_PCLK>;
+                       clock-names = "apb_pclk";
+                       cpu = <&cpu2>;
+
+                       out-ports {
+                               port {
+                                       etm2_out: endpoint {
+                                               remote-endpoint =
+                                                       <&cluster0_funnel_in2>;
+                                       };
+                               };
+                       };
+               };
+
+               etm@ecf40000 {
+                       compatible = "arm,coresight-etm4x", "arm,primecell";
+                       reg = <0 0xecf40000 0 0x1000>;
+                       clocks = <&crg_ctrl HI3660_PCLK>;
+                       clock-names = "apb_pclk";
+                       cpu = <&cpu3>;
+
+                       out-ports {
+                               port {
+                                       etm3_out: endpoint {
+                                               remote-endpoint =
+                                                       <&cluster0_funnel_in3>;
+                                       };
+                               };
+                       };
+               };
+
+               funnel@ec801000 {
+                       compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
+                       reg = <0 0xec801000 0 0x1000>;
+                       clocks = <&crg_ctrl HI3660_PCLK>;
+                       clock-names = "apb_pclk";
+
+                       out-ports {
+                               port {
+                                       cluster0_funnel_out: endpoint {
+                                               remote-endpoint =
+                                                       <&cluster0_etf_in>;
+                                       };
+                               };
+                       };
+
+                       in-ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+                                       cluster0_funnel_in0: endpoint {
+                                               remote-endpoint = <&etm0_out>;
+                                       };
+                               };
+
+                               port@1 {
+                                       reg = <1>;
+                                       cluster0_funnel_in1: endpoint {
+                                               remote-endpoint = <&etm1_out>;
+                                       };
+                               };
+
+                               port@2 {
+                                       reg = <2>;
+                                       cluster0_funnel_in2: endpoint {
+                                               remote-endpoint = <&etm2_out>;
+                                       };
+                               };
+
+                               port@3 {
+                                       reg = <3>;
+                                       cluster0_funnel_in3: endpoint {
+                                               remote-endpoint = <&etm3_out>;
+                                       };
+                               };
+                       };
+               };
+
+               etf@ec802000 {
+                       compatible = "arm,coresight-tmc", "arm,primecell";
+                       reg = <0 0xec802000 0 0x1000>;
+                       clocks = <&crg_ctrl HI3660_PCLK>;
+                       clock-names = "apb_pclk";
+
+                       in-ports {
+                               port {
+                                       cluster0_etf_in: endpoint {
+                                               remote-endpoint =
+                                                       <&cluster0_funnel_out>;
+                                       };
+                               };
+                       };
+
+                       out-ports {
+                               port {
+                                       cluster0_etf_out: endpoint {
+                                               remote-endpoint =
+                                                       <&combo_funnel_in0>;
+                                       };
+                               };
+                       };
+               };
+
+               /* A73 cluster internals */
+               etm@ed440000 {
+                       compatible = "arm,coresight-etm4x", "arm,primecell";
+                       reg = <0 0xed440000 0 0x1000>;
+                       clocks = <&crg_ctrl HI3660_PCLK>;
+                       clock-names = "apb_pclk";
+                       cpu = <&cpu4>;
+
+                       out-ports {
+                               port {
+                                       etm4_out: endpoint {
+                                               remote-endpoint =
+                                                       <&cluster1_funnel_in0>;
+                                       };
+                               };
+                       };
+               };
+
+               etm@ed540000 {
+                       compatible = "arm,coresight-etm4x", "arm,primecell";
+                       reg = <0 0xed540000 0 0x1000>;
+                       clocks = <&crg_ctrl HI3660_PCLK>;
+                       clock-names = "apb_pclk";
+                       cpu = <&cpu5>;
+
+                       out-ports {
+                               port {
+                                       etm5_out: endpoint {
+                                               remote-endpoint =
+                                                       <&cluster1_funnel_in1>;
+                                       };
+                               };
+                       };
+               };
+
+               etm@ed640000 {
+                       compatible = "arm,coresight-etm4x", "arm,primecell";
+                       reg = <0 0xed640000 0 0x1000>;
+                       clocks = <&crg_ctrl HI3660_PCLK>;
+                       clock-names = "apb_pclk";
+                       cpu = <&cpu6>;
+
+                       out-ports {
+                               port {
+                                       etm6_out: endpoint {
+                                               remote-endpoint =
+                                                       <&cluster1_funnel_in2>;
+                                       };
+                               };
+                       };
+               };
+
+               etm@ed740000 {
+                       compatible = "arm,coresight-etm4x", "arm,primecell";
+                       reg = <0 0xed740000 0 0x1000>;
+                       clocks = <&crg_ctrl HI3660_PCLK>;
+                       clock-names = "apb_pclk";
+                       cpu = <&cpu7>;
+
+                       out-ports {
+                               port {
+                                       etm7_out: endpoint {
+                                               remote-endpoint =
+                                                       <&cluster1_funnel_in3>;
+                                       };
+                               };
+                       };
+               };
+
+               funnel@ed001000 {
+                       compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
+                       reg = <0 0xed001000 0 0x1000>;
+                       clocks = <&crg_ctrl HI3660_PCLK>;
+                       clock-names = "apb_pclk";
+                       out-ports {
+                               port {
+                                       cluster1_funnel_out: endpoint {
+                                               remote-endpoint =
+                                                       <&cluster1_etf_in>;
+                                       };
+                               };
+                       };
+
+                       in-ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+                                       cluster1_funnel_in0: endpoint {
+                                               remote-endpoint = <&etm4_out>;
+                                       };
+                               };
+
+                               port@1 {
+                                       reg = <1>;
+                                       cluster1_funnel_in1: endpoint {
+                                               remote-endpoint = <&etm5_out>;
+                                       };
+                               };
+
+                               port@2 {
+                                       reg = <2>;
+                                       cluster1_funnel_in2: endpoint {
+                                               remote-endpoint = <&etm6_out>;
+                                       };
+                               };
+
+                               port@3 {
+                                       reg = <3>;
+                                       cluster1_funnel_in3: endpoint {
+                                               remote-endpoint = <&etm7_out>;
+                                       };
+                               };
+                       };
+               };
+
+               etf@ed002000 {
+                       compatible = "arm,coresight-tmc", "arm,primecell";
+                       reg = <0 0xed002000 0 0x1000>;
+                       clocks = <&crg_ctrl HI3660_PCLK>;
+                       clock-names = "apb_pclk";
+
+                       in-ports {
+                               port {
+                                       cluster1_etf_in: endpoint {
+                                               remote-endpoint =
+                                                       <&cluster1_funnel_out>;
+                                       };
+                               };
+                       };
+
+                       out-ports {
+                               port {
+                                       cluster1_etf_out: endpoint {
+                                               remote-endpoint =
+                                                       <&combo_funnel_in1>;
+                                       };
+                               };
+                       };
+               };
+
+               /* An invisible combo funnel between clusters and top funnel */
+               funnel {
+                       compatible = "arm,coresight-static-funnel";
+                       clocks = <&crg_ctrl HI3660_PCLK>;
+                       clock-names = "apb_pclk";
+
+                       out-ports {
+                               port {
+                                       combo_funnel_out: endpoint {
+                                               remote-endpoint =
+                                                       <&top_funnel_in>;
+                                       };
+                               };
+                       };
+
+                       in-ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+                                       combo_funnel_in0: endpoint {
+                                               remote-endpoint =
+                                                       <&cluster0_etf_out>;
+                                       };
+                               };
+
+                               port@1 {
+                                       reg = <1>;
+                                       combo_funnel_in1: endpoint {
+                                               remote-endpoint =
+                                                       <&cluster1_etf_out>;
+                                       };
+                               };
+                       };
+               };
+
+               /* Top internals */
+               funnel@ec031000 {
+                       compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
+                       reg = <0 0xec031000 0 0x1000>;
+                       clocks = <&crg_ctrl HI3660_PCLK>;
+                       clock-names = "apb_pclk";
+
+                       out-ports {
+                               port {
+                                       top_funnel_out: endpoint {
+                                               remote-endpoint =
+                                                       <&top_etf_in>;
+                                       };
+                               };
+                       };
+
+                       in-ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+                                       top_funnel_in: endpoint {
+                                               remote-endpoint =
+                                                       <&combo_funnel_out>;
+                                       };
+                               };
+                       };
+               };
+
+               etf@ec036000 {
+                       compatible = "arm,coresight-tmc", "arm,primecell";
+                       reg = <0 0xec036000 0 0x1000>;
+                       clocks = <&crg_ctrl HI3660_PCLK>;
+                       clock-names = "apb_pclk";
+
+                       in-ports {
+                               port {
+                                       top_etf_in: endpoint {
+                                               remote-endpoint =
+                                                       <&top_funnel_out>;
+                                       };
+                               };
+                       };
+
+                       out-ports {
+                               port {
+                                       top_etf_out: endpoint {
+                                               remote-endpoint =
+                                                       <&replicator_in>;
+                                       };
+                               };
+                       };
+               };
+
+               replicator {
+                       compatible = "arm,coresight-static-replicator";
+                       clocks = <&crg_ctrl HI3660_PCLK>;
+                       clock-names = "apb_pclk";
+
+                       in-ports {
+                               port {
+                                       replicator_in: endpoint {
+                                               remote-endpoint =
+                                                       <&top_etf_out>;
+                                       };
+                               };
+                       };
+
+                       out-ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+                                       replicator0_out0: endpoint {
+                                               remote-endpoint = <&etr_in>;
+                                       };
+                               };
+
+                               port@1 {
+                                       reg = <1>;
+                                       replicator0_out1: endpoint {
+                                               remote-endpoint = <&tpiu_in>;
+                                       };
+                               };
+                       };
+               };
+
+               etr@ec033000 {
+                       compatible = "arm,coresight-tmc", "arm,primecell";
+                       reg = <0 0xec033000 0 0x1000>;
+                       clocks = <&crg_ctrl HI3660_PCLK>;
+                       clock-names = "apb_pclk";
+
+                       in-ports {
+                               port {
+                                       etr_in: endpoint {
+                                               remote-endpoint =
+                                                       <&replicator0_out0>;
+                                       };
+                               };
+                       };
+               };
+
+               tpiu@ec032000 {
+                       compatible = "arm,coresight-tpiu", "arm,primecell";
+                       reg = <0 0xec032000 0 0x1000>;
+                       clocks = <&crg_ctrl HI3660_PCLK>;
+                       clock-names = "apb_pclk";
+
+                       in-ports {
+                               port {
+                                       tpiu_in: endpoint {
+                                               remote-endpoint =
+                                                       <&replicator0_out1>;
+                                       };
+                               };
+                       };
+               };
+       };
+};
index aa6a8ad..253cc34 100644 (file)
                };
        };
 };
+
+#include "hi3660-coresight.dtsi"
index 30f54b7..651771a 100644 (file)
@@ -11,7 +11,7 @@
 / {
        soc {
                funnel@f6401000 {
-                       compatible = "arm,coresight-funnel", "arm,primecell";
+                       compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                        reg = <0 0xf6401000 0 0x1000>;
                        clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>;
                        clock-names = "apb_pclk";
@@ -61,7 +61,7 @@
                };
 
                replicator {
-                       compatible = "arm,coresight-replicator";
+                       compatible = "arm,coresight-static-replicator";
                        clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>;
                        clock-names = "apb_pclk";
 
                };
 
                funnel@f6501000 {
-                       compatible = "arm,coresight-funnel", "arm,primecell";
+                       compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                        reg = <0 0xf6501000 0 0x1000>;
                        clocks = <&acpu_sctrl HI6220_ACPU_SFT_AT_S>;
                        clock-names = "apb_pclk";
index 6be019e..fbcf03f 100644 (file)
 
        flash@0 {
                reg = <0>;
-               compatible = "winbond,w25q32dw", "jedec,spi-flash";
+               compatible = "jedec,spi-nor";
                spi-max-frequency = <104000000>;
                m25p,fast-read;
-
-               partitions {
-                       compatible = "fixed-partitions";
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-
-                       partition@0 {
-                               label = "uboot";
-                               reg = <0 0x180000>;
-                       };
-
-                       partition@180000 {
-                               label = "ubootenv";
-                               reg = <0x180000 0x10000>;
-                       };
-               };
        };
 };
 
index d20d84c..f34ee87 100644 (file)
                ethernet2 = &cp0_eth2;
        };
 
+       cp0_exp_usb3_0_current_regulator: gpio-regulator {
+               compatible = "regulator-gpio";
+               regulator-name = "cp0-usb3-0-current-regulator";
+               regulator-type = "current";
+               regulator-min-microamp = <500000>;
+               regulator-max-microamp = <900000>;
+               gpios = <&expander0 4 GPIO_ACTIVE_HIGH>;
+               states = <500000 0x0
+                         900000 0x1>;
+               enable-active-high;
+               gpios-states = <0>;
+       };
+
+       cp0_exp_usb3_1_current_regulator: gpio-regulator {
+               compatible = "regulator-gpio";
+               regulator-name = "cp0-usb3-1-current-regulator";
+               regulator-type = "current";
+               regulator-min-microamp = <500000>;
+               regulator-max-microamp = <900000>;
+               gpios = <&expander0 5 GPIO_ACTIVE_HIGH>;
+               states = <500000 0x0
+                         900000 0x1>;
+               enable-active-high;
+               gpios-states = <0>;
+       };
+
        cp0_reg_usb3_0_vbus: cp0-usb3-0-vbus {
                compatible = "regulator-fixed";
                regulator-name = "usb3h0-vbus";
@@ -35,6 +61,7 @@
                regulator-max-microvolt = <5000000>;
                enable-active-high;
                gpio = <&expander0 0 GPIO_ACTIVE_HIGH>;
+               vin-supply = <&cp0_exp_usb3_0_current_regulator>;
        };
 
        cp0_reg_usb3_1_vbus: cp0-usb3-1-vbus {
@@ -44,6 +71,7 @@
                regulator-max-microvolt = <5000000>;
                enable-active-high;
                gpio = <&expander0 1 GPIO_ACTIVE_HIGH>;
+               vin-supply = <&cp0_exp_usb3_1_current_regulator>;
        };
 
        cp0_usb3_0_phy: cp0-usb3-0-phy {
index 9143aa1..f275d94 100644 (file)
@@ -63,6 +63,7 @@
                tx-disable-gpio = <&cp1_gpio1 29 GPIO_ACTIVE_HIGH>;
                pinctrl-names = "default";
                pinctrl-0 = <&cp0_sfp_present_pins &cp1_sfp_tx_disable_pins>;
+               maximum-power-milliwatt = <2000>;
        };
 
        leds {
index 9f4f939..d6e9c01 100644 (file)
@@ -27,6 +27,8 @@
                ethernet1 = &cp0_eth2;
                ethernet2 = &cp1_eth0;
                ethernet3 = &cp1_eth1;
+               i2c1 = &cp0_i2c0;
+               i2c2 = &cp1_i2c0;
        };
 
        cp0_reg_usb3_0_vbus: cp0-usb3-0-vbus {
        };
 };
 
-&i2c0 {
-       status = "okay";
-       clock-frequency = <100000>;
-};
-
 &spi0 {
        status = "okay";
 
index 329f8ce..205071b 100644 (file)
        num-lanes = <4>;
        num-viewport = <8>;
        reset-gpios = <&cp0_gpio2 20 GPIO_ACTIVE_LOW>;
+       ranges = <0x81000000 0x0 0xf9010000 0x0 0xf9010000 0x0 0x10000
+                 0x82000000 0x0 0xc0000000 0x0 0xc0000000 0x0 0x20000000>;
        status = "okay";
 };
 
index 861fd21..9024a2d 100644 (file)
                        compatible = "arm,cortex-a72";
                        reg = <0x000>;
                        enable-method = "psci";
+                       #cooling-cells = <2>;
                };
                cpu1: cpu@1 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a72";
                        reg = <0x001>;
                        enable-method = "psci";
+                       #cooling-cells = <2>;
                };
        };
 };
index 2baafe1..ea13ae7 100644 (file)
                        compatible = "arm,cortex-a72";
                        reg = <0x000>;
                        enable-method = "psci";
+                       #cooling-cells = <2>;
                };
                cpu1: cpu@1 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a72";
                        reg = <0x001>;
                        enable-method = "psci";
+                       #cooling-cells = <2>;
                };
                cpu2: cpu@100 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a72";
                        reg = <0x100>;
                        enable-method = "psci";
+                       #cooling-cells = <2>;
                };
                cpu3: cpu@101 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a72";
                        reg = <0x101>;
                        enable-method = "psci";
+                       #cooling-cells = <2>;
                };
        };
+
 };
index 91dad7e..96228f9 100644 (file)
         *
         * Only one thermal zone per AP/CP may trigger interrupts at a time, the
         * first one that will have a critical trip point will be chosen.
-        *
-        * The cooling maps are always empty as there are no cooling devices.
         */
        thermal-zones {
                ap_thermal_ic: ap-thermal-ic {
                        cooling-maps { };
                };
 
-               ap_thermal_cpu1: ap-thermal-cpu1 {
+               ap_thermal_cpu0: ap-thermal-cpu0 {
                        polling-delay-passive = <1000>;
                        polling-delay = <1000>;
 
                        thermal-sensors = <&ap_thermal 1>;
 
-                       trips { };
-                       cooling-maps { };
+                       trips {
+                               cpu0_hot: cpu0-hot {
+                                       temperature = <85000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                               cpu0_emerg: cpu0-emerg {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                       };
+
+                       cooling-maps {
+                               map0_hot: map0-hot {
+                                       trip = <&cpu0_hot>;
+                                       cooling-device = <&cpu0 1 2>,
+                                               <&cpu1 1 2>;
+                               };
+                               map0_emerg: map0-ermerg {
+                                       trip = <&cpu0_emerg>;
+                                       cooling-device = <&cpu0 3 3>,
+                                               <&cpu1 3 3>;
+                               };
+                       };
                };
 
-               ap_thermal_cpu2: ap-thermal-cpu2 {
+               ap_thermal_cpu1: ap-thermal-cpu1 {
                        polling-delay-passive = <1000>;
                        polling-delay = <1000>;
 
                        thermal-sensors = <&ap_thermal 2>;
 
-                       trips { };
-                       cooling-maps { };
+                       trips {
+                               cpu1_hot: cpu1-hot {
+                                       temperature = <85000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                               cpu1_emerg: cpu1-emerg {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                       };
+
+                       cooling-maps {
+                               map1_hot: map1-hot {
+                                       trip = <&cpu1_hot>;
+                                       cooling-device = <&cpu0 1 2>,
+                                               <&cpu1 1 2>;
+                               };
+                               map1_emerg: map1-emerg {
+                                       trip = <&cpu1_emerg>;
+                                       cooling-device = <&cpu0 3 3>,
+                                               <&cpu1 3 3>;
+                               };
+                       };
                };
 
-               ap_thermal_cpu3: ap-thermal-cpu3 {
+               ap_thermal_cpu2: ap-thermal-cpu2 {
                        polling-delay-passive = <1000>;
                        polling-delay = <1000>;
 
                        thermal-sensors = <&ap_thermal 3>;
 
-                       trips { };
-                       cooling-maps { };
+                       trips {
+                               cpu2_hot: cpu2-hot {
+                                       temperature = <85000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                               cpu2_emerg: cpu2-emerg {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                       };
+
+                       cooling-maps {
+                               map2_hot: map2-hot {
+                                       trip = <&cpu2_hot>;
+                                       cooling-device = <&cpu2 1 2>,
+                                               <&cpu3 1 2>;
+                               };
+                               map2_emerg: map2-emerg {
+                                       trip = <&cpu2_emerg>;
+                                       cooling-device = <&cpu2 3 3>,
+                                               <&cpu3 3 3>;
+                               };
+                       };
                };
 
-               ap_thermal_cpu4: ap-thermal-cpu4 {
+               ap_thermal_cpu3: ap-thermal-cpu3 {
                        polling-delay-passive = <1000>;
                        polling-delay = <1000>;
 
                        thermal-sensors = <&ap_thermal 4>;
 
-                       trips { };
-                       cooling-maps { };
+                       trips {
+                               cpu3_hot: cpu3-hot {
+                                       temperature = <85000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                               cpu3_emerg: cpu3-emerg {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                       };
+
+                       cooling-maps {
+                               map3_hot: map3-bhot {
+                                       trip = <&cpu3_hot>;
+                                       cooling-device = <&cpu2 1 2>,
+                                               <&cpu3 1 2>;
+                               };
+                               map3_emerg: map3-emerg {
+                                       trip = <&cpu3_emerg>;
+                                       cooling-device = <&cpu2 3 3>,
+                                               <&cpu3 3 3>;
+                               };
+                       };
                };
        };
 };
index 4d6e4a0..f71afb1 100644 (file)
                                        <85 IRQ_TYPE_LEVEL_HIGH>,
                                        <84 IRQ_TYPE_LEVEL_HIGH>,
                                        <83 IRQ_TYPE_LEVEL_HIGH>;
+                               #interrupt-cells = <2>;
                                status = "disabled";
                        };
 
                                        <81 IRQ_TYPE_LEVEL_HIGH>,
                                        <80 IRQ_TYPE_LEVEL_HIGH>,
                                        <79 IRQ_TYPE_LEVEL_HIGH>;
+                               #interrupt-cells = <2>;
                                status = "disabled";
                        };
                };
index e8f952f..458bbc4 100644 (file)
@@ -7,3 +7,4 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt6797-x20-dev.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt7622-rfb1.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt7622-bananapi-bpi-r64.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8173-evb.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-evb.dtb
diff --git a/arch/arm64/boot/dts/mediatek/mt8183-evb.dts b/arch/arm64/boot/dts/mediatek/mt8183-evb.dts
new file mode 100644 (file)
index 0000000..d8e555c
--- /dev/null
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ben Ho <ben.ho@mediatek.com>
+ *        Erin Lo <erin.lo@mediatek.com>
+ */
+
+/dts-v1/;
+#include "mt8183.dtsi"
+
+/ {
+       model = "MediaTek MT8183 evaluation board";
+       compatible = "mediatek,mt8183-evb", "mediatek,mt8183";
+
+       aliases {
+               serial0 = &uart0;
+       };
+
+       memory@40000000 {
+               device_type = "memory";
+               reg = <0 0x40000000 0 0x80000000>;
+       };
+
+       chosen {
+               stdout-path = "serial0:921600n8";
+       };
+};
+
+&auxadc {
+       status = "okay";
+};
+
+&pio {
+       spi_pins_0: spi0{
+               pins_spi{
+                       pinmux = <PINMUX_GPIO85__FUNC_SPI0_MI>,
+                                <PINMUX_GPIO86__FUNC_SPI0_CSB>,
+                                <PINMUX_GPIO87__FUNC_SPI0_MO>,
+                                <PINMUX_GPIO88__FUNC_SPI0_CLK>;
+                       bias-disable;
+               };
+       };
+
+       spi_pins_1: spi1{
+               pins_spi{
+                       pinmux = <PINMUX_GPIO161__FUNC_SPI1_A_MI>,
+                                <PINMUX_GPIO162__FUNC_SPI1_A_CSB>,
+                                <PINMUX_GPIO163__FUNC_SPI1_A_MO>,
+                                <PINMUX_GPIO164__FUNC_SPI1_A_CLK>;
+                       bias-disable;
+               };
+       };
+
+       spi_pins_2: spi2{
+               pins_spi{
+                       pinmux = <PINMUX_GPIO0__FUNC_SPI2_CSB>,
+                                <PINMUX_GPIO1__FUNC_SPI2_MO>,
+                                <PINMUX_GPIO2__FUNC_SPI2_CLK>,
+                                <PINMUX_GPIO94__FUNC_SPI2_MI>;
+                       bias-disable;
+               };
+       };
+
+       spi_pins_3: spi3{
+               pins_spi{
+                       pinmux = <PINMUX_GPIO21__FUNC_SPI3_MI>,
+                                <PINMUX_GPIO22__FUNC_SPI3_CSB>,
+                                <PINMUX_GPIO23__FUNC_SPI3_MO>,
+                                <PINMUX_GPIO24__FUNC_SPI3_CLK>;
+                       bias-disable;
+               };
+       };
+
+       spi_pins_4: spi4{
+               pins_spi{
+                       pinmux = <PINMUX_GPIO17__FUNC_SPI4_MI>,
+                                <PINMUX_GPIO18__FUNC_SPI4_CSB>,
+                                <PINMUX_GPIO19__FUNC_SPI4_MO>,
+                                <PINMUX_GPIO20__FUNC_SPI4_CLK>;
+                       bias-disable;
+               };
+       };
+
+       spi_pins_5: spi5{
+               pins_spi{
+                       pinmux = <PINMUX_GPIO13__FUNC_SPI5_MI>,
+                                <PINMUX_GPIO14__FUNC_SPI5_CSB>,
+                                <PINMUX_GPIO15__FUNC_SPI5_MO>,
+                                <PINMUX_GPIO16__FUNC_SPI5_CLK>;
+                       bias-disable;
+               };
+       };
+};
+
+&spi0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&spi_pins_0>;
+       mediatek,pad-select = <0>;
+       status = "okay";
+};
+
+&spi1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&spi_pins_1>;
+       mediatek,pad-select = <0>;
+       status = "okay";
+};
+
+&spi2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&spi_pins_2>;
+       mediatek,pad-select = <0>;
+       status = "okay";
+};
+
+&spi3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&spi_pins_3>;
+       mediatek,pad-select = <0>;
+       status = "okay";
+};
+
+&spi4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&spi_pins_4>;
+       mediatek,pad-select = <0>;
+       status = "okay";
+};
+
+&spi5 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&spi_pins_5>;
+       mediatek,pad-select = <0>;
+       status = "okay";
+
+};
+
+&uart0 {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8183.dtsi b/arch/arm64/boot/dts/mediatek/mt8183.dtsi
new file mode 100644 (file)
index 0000000..c2749c4
--- /dev/null
@@ -0,0 +1,447 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ben Ho <ben.ho@mediatek.com>
+ *        Erin Lo <erin.lo@mediatek.com>
+ */
+
+#include <dt-bindings/clock/mt8183-clk.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include "mt8183-pinfunc.h"
+
+/ {
+       compatible = "mediatek,mt8183";
+       interrupt-parent = <&sysirq>;
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu-map {
+                       cluster0 {
+                               core0 {
+                                       cpu = <&cpu0>;
+                               };
+                               core1 {
+                                       cpu = <&cpu1>;
+                               };
+                               core2 {
+                                       cpu = <&cpu2>;
+                               };
+                               core3 {
+                                       cpu = <&cpu3>;
+                               };
+                       };
+
+                       cluster1 {
+                               core0 {
+                                       cpu = <&cpu4>;
+                               };
+                               core1 {
+                                       cpu = <&cpu5>;
+                               };
+                               core2 {
+                                       cpu = <&cpu6>;
+                               };
+                               core3 {
+                                       cpu = <&cpu7>;
+                               };
+                       };
+               };
+
+               cpu0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53";
+                       reg = <0x000>;
+                       enable-method = "psci";
+                       capacity-dmips-mhz = <741>;
+               };
+
+               cpu1: cpu@1 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53";
+                       reg = <0x001>;
+                       enable-method = "psci";
+                       capacity-dmips-mhz = <741>;
+               };
+
+               cpu2: cpu@2 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53";
+                       reg = <0x002>;
+                       enable-method = "psci";
+                       capacity-dmips-mhz = <741>;
+               };
+
+               cpu3: cpu@3 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53";
+                       reg = <0x003>;
+                       enable-method = "psci";
+                       capacity-dmips-mhz = <741>;
+               };
+
+               cpu4: cpu@100 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a73";
+                       reg = <0x100>;
+                       enable-method = "psci";
+                       capacity-dmips-mhz = <1024>;
+               };
+
+               cpu5: cpu@101 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a73";
+                       reg = <0x101>;
+                       enable-method = "psci";
+                       capacity-dmips-mhz = <1024>;
+               };
+
+               cpu6: cpu@102 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a73";
+                       reg = <0x102>;
+                       enable-method = "psci";
+                       capacity-dmips-mhz = <1024>;
+               };
+
+               cpu7: cpu@103 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a73";
+                       reg = <0x103>;
+                       enable-method = "psci";
+                       capacity-dmips-mhz = <1024>;
+               };
+       };
+
+       pmu-a53 {
+               compatible = "arm,cortex-a53-pmu";
+               interrupt-parent = <&gic>;
+               interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_LOW &ppi_cluster0>;
+       };
+
+       pmu-a73 {
+               compatible = "arm,cortex-a73-pmu";
+               interrupt-parent = <&gic>;
+               interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_LOW &ppi_cluster1>;
+       };
+
+       psci {
+               compatible      = "arm,psci-1.0";
+               method          = "smc";
+       };
+
+       clk26m: oscillator {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <26000000>;
+               clock-output-names = "clk26m";
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupt-parent = <&gic>;
+               interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW 0>,
+                            <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW 0>,
+                            <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW 0>,
+                            <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW 0>;
+       };
+
+       soc {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               compatible = "simple-bus";
+               ranges;
+
+               soc_data: soc_data@8000000 {
+                       compatible = "mediatek,mt8183-efuse",
+                                    "mediatek,efuse";
+                       reg = <0 0x08000000 0 0x0010>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       status = "disabled";
+               };
+
+               gic: interrupt-controller@c000000 {
+                       compatible = "arm,gic-v3";
+                       #interrupt-cells = <4>;
+                       interrupt-parent = <&gic>;
+                       interrupt-controller;
+                       reg = <0 0x0c000000 0 0x40000>,  /* GICD */
+                             <0 0x0c100000 0 0x200000>, /* GICR */
+                             <0 0x0c400000 0 0x2000>,   /* GICC */
+                             <0 0x0c410000 0 0x1000>,   /* GICH */
+                             <0 0x0c420000 0 0x2000>;   /* GICV */
+
+                       interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH 0>;
+                       ppi-partitions {
+                               ppi_cluster0: interrupt-partition-0 {
+                                       affinity = <&cpu0 &cpu1 &cpu2 &cpu3>;
+                               };
+                               ppi_cluster1: interrupt-partition-1 {
+                                       affinity = <&cpu4 &cpu5 &cpu6 &cpu7>;
+                               };
+                       };
+               };
+
+               mcucfg: syscon@c530000 {
+                       compatible = "mediatek,mt8183-mcucfg", "syscon";
+                       reg = <0 0x0c530000 0 0x1000>;
+                       #clock-cells = <1>;
+               };
+
+               sysirq: interrupt-controller@c530a80 {
+                       compatible = "mediatek,mt8183-sysirq",
+                                    "mediatek,mt6577-sysirq";
+                       interrupt-controller;
+                       #interrupt-cells = <3>;
+                       interrupt-parent = <&gic>;
+                       reg = <0 0x0c530a80 0 0x50>;
+               };
+
+               topckgen: syscon@10000000 {
+                       compatible = "mediatek,mt8183-topckgen", "syscon";
+                       reg = <0 0x10000000 0 0x1000>;
+                       #clock-cells = <1>;
+               };
+
+               infracfg: syscon@10001000 {
+                       compatible = "mediatek,mt8183-infracfg", "syscon";
+                       reg = <0 0x10001000 0 0x1000>;
+                       #clock-cells = <1>;
+               };
+
+               pio: pinctrl@10005000 {
+                       compatible = "mediatek,mt8183-pinctrl";
+                       reg = <0 0x10005000 0 0x1000>,
+                             <0 0x11f20000 0 0x1000>,
+                             <0 0x11e80000 0 0x1000>,
+                             <0 0x11e70000 0 0x1000>,
+                             <0 0x11e90000 0 0x1000>,
+                             <0 0x11d30000 0 0x1000>,
+                             <0 0x11d20000 0 0x1000>,
+                             <0 0x11c50000 0 0x1000>,
+                             <0 0x11f30000 0 0x1000>,
+                             <0 0x1000b000 0 0x1000>;
+                       reg-names = "iocfg0", "iocfg1", "iocfg2",
+                                   "iocfg3", "iocfg4", "iocfg5",
+                                   "iocfg6", "iocfg7", "iocfg8",
+                                   "eint";
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       gpio-ranges = <&pio 0 0 192>;
+                       interrupt-controller;
+                       interrupts = <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH>;
+                       #interrupt-cells = <2>;
+               };
+
+               apmixedsys: syscon@1000c000 {
+                       compatible = "mediatek,mt8183-apmixedsys", "syscon";
+                       reg = <0 0x1000c000 0 0x1000>;
+                       #clock-cells = <1>;
+               };
+
+               pwrap: pwrap@1000d000 {
+                       compatible = "mediatek,mt8183-pwrap";
+                       reg = <0 0x1000d000 0 0x1000>;
+                       reg-names = "pwrap";
+                       interrupts = <GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&topckgen CLK_TOP_MUX_PMICSPI>,
+                                <&infracfg CLK_INFRA_PMIC_AP>;
+                       clock-names = "spi", "wrap";
+               };
+
+               auxadc: auxadc@11001000 {
+                       compatible = "mediatek,mt8183-auxadc",
+                                    "mediatek,mt8173-auxadc";
+                       reg = <0 0x11001000 0 0x1000>;
+                       clocks = <&infracfg CLK_INFRA_AUXADC>;
+                       clock-names = "main";
+                       #io-channel-cells = <1>;
+                       status = "disabled";
+               };
+
+               uart0: serial@11002000 {
+                       compatible = "mediatek,mt8183-uart",
+                                    "mediatek,mt6577-uart";
+                       reg = <0 0x11002000 0 0x1000>;
+                       interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_LOW>;
+                       clocks = <&clk26m>, <&infracfg CLK_INFRA_UART0>;
+                       clock-names = "baud", "bus";
+                       status = "disabled";
+               };
+
+               uart1: serial@11003000 {
+                       compatible = "mediatek,mt8183-uart",
+                                    "mediatek,mt6577-uart";
+                       reg = <0 0x11003000 0 0x1000>;
+                       interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_LOW>;
+                       clocks = <&clk26m>, <&infracfg CLK_INFRA_UART1>;
+                       clock-names = "baud", "bus";
+                       status = "disabled";
+               };
+
+               uart2: serial@11004000 {
+                       compatible = "mediatek,mt8183-uart",
+                                    "mediatek,mt6577-uart";
+                       reg = <0 0x11004000 0 0x1000>;
+                       interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_LOW>;
+                       clocks = <&clk26m>, <&infracfg CLK_INFRA_UART2>;
+                       clock-names = "baud", "bus";
+                       status = "disabled";
+               };
+
+               spi0: spi@1100a000 {
+                       compatible = "mediatek,mt8183-spi";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0 0x1100a000 0 0x1000>;
+                       interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_LOW>;
+                       clocks = <&topckgen CLK_TOP_SYSPLL_D5_D2>,
+                                <&topckgen CLK_TOP_MUX_SPI>,
+                                <&infracfg CLK_INFRA_SPI0>;
+                       clock-names = "parent-clk", "sel-clk", "spi-clk";
+                       status = "disabled";
+               };
+
+               spi1: spi@11010000 {
+                       compatible = "mediatek,mt8183-spi";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0 0x11010000 0 0x1000>;
+                       interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_LOW>;
+                       clocks = <&topckgen CLK_TOP_SYSPLL_D5_D2>,
+                                <&topckgen CLK_TOP_MUX_SPI>,
+                                <&infracfg CLK_INFRA_SPI1>;
+                       clock-names = "parent-clk", "sel-clk", "spi-clk";
+                       status = "disabled";
+               };
+
+               spi2: spi@11012000 {
+                       compatible = "mediatek,mt8183-spi";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0 0x11012000 0 0x1000>;
+                       interrupts = <GIC_SPI 129 IRQ_TYPE_LEVEL_LOW>;
+                       clocks = <&topckgen CLK_TOP_SYSPLL_D5_D2>,
+                                <&topckgen CLK_TOP_MUX_SPI>,
+                                <&infracfg CLK_INFRA_SPI2>;
+                       clock-names = "parent-clk", "sel-clk", "spi-clk";
+                       status = "disabled";
+               };
+
+               spi3: spi@11013000 {
+                       compatible = "mediatek,mt8183-spi";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0 0x11013000 0 0x1000>;
+                       interrupts = <GIC_SPI 130 IRQ_TYPE_LEVEL_LOW>;
+                       clocks = <&topckgen CLK_TOP_SYSPLL_D5_D2>,
+                                <&topckgen CLK_TOP_MUX_SPI>,
+                                <&infracfg CLK_INFRA_SPI3>;
+                       clock-names = "parent-clk", "sel-clk", "spi-clk";
+                       status = "disabled";
+               };
+
+               spi4: spi@11018000 {
+                       compatible = "mediatek,mt8183-spi";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0 0x11018000 0 0x1000>;
+                       interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_LOW>;
+                       clocks = <&topckgen CLK_TOP_SYSPLL_D5_D2>,
+                                <&topckgen CLK_TOP_MUX_SPI>,
+                                <&infracfg CLK_INFRA_SPI4>;
+                       clock-names = "parent-clk", "sel-clk", "spi-clk";
+                       status = "disabled";
+               };
+
+               spi5: spi@11019000 {
+                       compatible = "mediatek,mt8183-spi";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0 0x11019000 0 0x1000>;
+                       interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_LOW>;
+                       clocks = <&topckgen CLK_TOP_SYSPLL_D5_D2>,
+                                <&topckgen CLK_TOP_MUX_SPI>,
+                                <&infracfg CLK_INFRA_SPI5>;
+                       clock-names = "parent-clk", "sel-clk", "spi-clk";
+                       status = "disabled";
+               };
+
+               audiosys: syscon@11220000 {
+                       compatible = "mediatek,mt8183-audiosys", "syscon";
+                       reg = <0 0x11220000 0 0x1000>;
+                       #clock-cells = <1>;
+               };
+
+               efuse: efuse@11f10000 {
+                       compatible = "mediatek,mt8183-efuse",
+                                    "mediatek,efuse";
+                       reg = <0 0x11f10000 0 0x1000>;
+               };
+
+               mfgcfg: syscon@13000000 {
+                       compatible = "mediatek,mt8183-mfgcfg", "syscon";
+                       reg = <0 0x13000000 0 0x1000>;
+                       #clock-cells = <1>;
+               };
+
+               mmsys: syscon@14000000 {
+                       compatible = "mediatek,mt8183-mmsys", "syscon";
+                       reg = <0 0x14000000 0 0x1000>;
+                       #clock-cells = <1>;
+               };
+
+               imgsys: syscon@15020000 {
+                       compatible = "mediatek,mt8183-imgsys", "syscon";
+                       reg = <0 0x15020000 0 0x1000>;
+                       #clock-cells = <1>;
+               };
+
+               vdecsys: syscon@16000000 {
+                       compatible = "mediatek,mt8183-vdecsys", "syscon";
+                       reg = <0 0x16000000 0 0x1000>;
+                       #clock-cells = <1>;
+               };
+
+               vencsys: syscon@17000000 {
+                       compatible = "mediatek,mt8183-vencsys", "syscon";
+                       reg = <0 0x17000000 0 0x1000>;
+                       #clock-cells = <1>;
+               };
+
+               ipu_conn: syscon@19000000 {
+                       compatible = "mediatek,mt8183-ipu_conn", "syscon";
+                       reg = <0 0x19000000 0 0x1000>;
+                       #clock-cells = <1>;
+               };
+
+               ipu_adl: syscon@19010000 {
+                       compatible = "mediatek,mt8183-ipu_adl", "syscon";
+                       reg = <0 0x19010000 0 0x1000>;
+                       #clock-cells = <1>;
+               };
+
+               ipu_core0: syscon@19180000 {
+                       compatible = "mediatek,mt8183-ipu_core0", "syscon";
+                       reg = <0 0x19180000 0 0x1000>;
+                       #clock-cells = <1>;
+               };
+
+               ipu_core1: syscon@19280000 {
+                       compatible = "mediatek,mt8183-ipu_core1", "syscon";
+                       reg = <0 0x19280000 0 0x1000>;
+                       #clock-cells = <1>;
+               };
+
+               camsys: syscon@1a000000 {
+                       compatible = "mediatek,mt8183-camsys", "syscon";
+                       reg = <0 0x1a000000 0 0x1000>;
+                       #clock-cells = <1>;
+               };
+       };
+};
index 14d7fea..bdace01 100644 (file)
@@ -7,18 +7,70 @@
 #include "tegra186-p3310.dtsi"
 
 / {
-       model = "NVIDIA Tegra186 P2771-0000 Development Board";
+       model = "NVIDIA Jetson TX2 Developer Kit";
        compatible = "nvidia,p2771-0000", "nvidia,tegra186";
 
+       aconnect {
+               status = "okay";
+
+               dma-controller@2930000 {
+                       status = "okay";
+               };
+
+               interrupt-controller@2a40000 {
+                       status = "okay";
+               };
+       };
+
        i2c@3160000 {
                power-monitor@42 {
                        compatible = "ti,ina3221";
                        reg = <0x42>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       channel@0 {
+                               reg = <0x0>;
+                               label = "VDD_MUX";
+                               shunt-resistor-micro-ohms = <20000>;
+                       };
+
+                       channel@1 {
+                               reg = <0x1>;
+                               label = "VDD_5V0_IO_SYS";
+                               shunt-resistor-micro-ohms = <5000>;
+                       };
+
+                       channel@2 {
+                               reg = <0x2>;
+                               label = "VDD_3V3_SYS";
+                               shunt-resistor-micro-ohms = <10000>;
+                       };
                };
 
                power-monitor@43 {
                        compatible = "ti,ina3221";
                        reg = <0x43>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       channel@0 {
+                               reg = <0x0>;
+                               label = "VDD_3V3_IO_SLP";
+                               shunt-resistor-micro-ohms = <10000>;
+                       };
+
+                       channel@1 {
+                               reg = <0x1>;
+                               label = "VDD_1V8_IO";
+                               shunt-resistor-micro-ohms = <10000>;
+                       };
+
+                       channel@2 {
+                               reg = <0x2>;
+                               label = "VDD_M2_IN";
+                               shunt-resistor-micro-ohms = <10000>;
+                       };
                };
 
                exp1: gpio@74 {
@@ -31,6 +83,8 @@
 
                        #gpio-cells = <2>;
                        gpio-controller;
+
+                       vcc-supply = <&vdd_3v3_sys>;
                };
 
                exp2: gpio@77 {
@@ -43,6 +97,8 @@
 
                        #gpio-cells = <2>;
                        gpio-controller;
+
+                       vcc-supply = <&vdd_1v8>;
                };
        };
 
                phy-names = "usb2-0", "usb2-1", "usb3-0";
        };
 
+       i2c@c250000 {
+               /* carrier board ID EEPROM */
+               eeprom@57 {
+                       compatible = "atmel,24c02";
+                       reg = <0x57>;
+
+                       address-bits = <8>;
+                       page-size = <8>;
+                       size = <256>;
+                       read-only;
+               };
+       };
+
        pcie@10003000 {
                status = "okay";
 
                        regulator-min-microvolt = <5000000>;
                        regulator-max-microvolt = <5000000>;
 
-                       gpio = <&gpio TEGRA_MAIN_GPIO(L, 4) GPIO_ACTIVE_HIGH>;
+                       gpio = <&gpio TEGRA186_MAIN_GPIO(L, 4) GPIO_ACTIVE_HIGH>;
                        enable-active-high;
 
                        vin-supply = <&vdd_5v0_sys>;
                        regulator-min-microvolt = <5000000>;
                        regulator-max-microvolt = <5000000>;
 
-                       gpio = <&gpio TEGRA_MAIN_GPIO(L, 5) GPIO_ACTIVE_HIGH>;
+                       gpio = <&gpio TEGRA186_MAIN_GPIO(L, 5) GPIO_ACTIVE_HIGH>;
                        enable-active-high;
 
                        vin-supply = <&vdd_5v0_sys>;
index 64686b0..5e18acf 100644 (file)
@@ -4,7 +4,7 @@
 #include <dt-bindings/mfd/max77620.h>
 
 / {
-       model = "NVIDIA Tegra186 P3310 Processor Module";
+       model = "NVIDIA Jetson TX2";
        compatible = "nvidia,p3310", "nvidia,tegra186";
 
        aliases {
                power-monitor@40 {
                        compatible = "ti,ina3221";
                        reg = <0x40>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       channel@0 {
+                               reg = <0x0>;
+                               label = "VDD_SYS_GPU";
+                               shunt-resistor-micro-ohms = <10000>;
+                       };
+
+                       channel@1 {
+                               reg = <0x1>;
+                               label = "VDD_SYS_SOC";
+                               shunt-resistor-micro-ohms = <10000>;
+                       };
+
+                       channel@2 {
+                               reg = <0x2>;
+                               label = "VDD_3V8_WIFI";
+                               shunt-resistor-micro-ohms = <10000>;
+                       };
                };
 
                power-monitor@41 {
                        compatible = "ti,ina3221";
                        reg = <0x41>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       channel@0 {
+                               reg = <0x0>;
+                               label = "VDD_IN";
+                               shunt-resistor-micro-ohms = <5000>;
+                       };
+
+                       channel@1 {
+                               reg = <0x1>;
+                               label = "VDD_SYS_CPU";
+                               shunt-resistor-micro-ohms = <10000>;
+                       };
+
+                       channel@2 {
+                               reg = <0x2>;
+                               label = "VDD_5V0_DDR";
+                               shunt-resistor-micro-ohms = <10000>;
+                       };
                };
        };
 
 
        i2c@c250000 {
                status = "okay";
+
+               /* module ID EEPROM */
+               eeprom@50 {
+                       compatible = "atmel,24c02";
+                       reg = <0x50>;
+
+                       address-bits = <8>;
+                       page-size = <8>;
+                       size = <256>;
+                       read-only;
+               };
        };
 
        rtc@c2a0000 {
index 426ac0b..47cd831 100644 (file)
                snps,rxpbl = <8>;
        };
 
+       aconnect {
+               compatible = "nvidia,tegra186-aconnect",
+                            "nvidia,tegra210-aconnect";
+               clocks = <&bpmp TEGRA186_CLK_APE>,
+                        <&bpmp TEGRA186_CLK_APB2APE>;
+               clock-names = "ape", "apb2ape";
+               power-domains = <&bpmp TEGRA186_POWER_DOMAIN_AUD>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x02900000 0x0 0x02900000 0x200000>;
+               status = "disabled";
+
+               dma-controller@2930000 {
+                       compatible = "nvidia,tegra186-adma";
+                       reg = <0x02930000 0x20000>;
+                       interrupt-parent = <&agic>;
+                       interrupts =  <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>,
+                                     <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+                       #dma-cells = <1>;
+                       clocks = <&bpmp TEGRA186_CLK_AHUB>;
+                       clock-names = "d_audio";
+                       status = "disabled";
+               };
+
+               agic: interrupt-controller@2a40000 {
+                       compatible = "nvidia,tegra186-agic",
+                                    "nvidia,tegra210-agic";
+                       #interrupt-cells = <3>;
+                       interrupt-controller;
+                       reg = <0x02a41000 0x1000>,
+                             <0x02a42000 0x2000>;
+                       interrupts = <GIC_SPI 145
+                               (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+                       clocks = <&bpmp TEGRA186_CLK_APE>;
+                       clock-names = "clk";
+                       status = "disabled";
+               };
+       };
+
        memory-controller@2c00000 {
                compatible = "nvidia,tegra186-mc";
                reg = <0x0 0x02c00000 0x0 0xb0000>;
                clock-names = "div-clk";
                resets = <&bpmp TEGRA186_RESET_I2C4>;
                reset-names = "i2c";
+               pinctrl-names = "default", "idle";
+               pinctrl-0 = <&state_dpaux1_i2c>;
+               pinctrl-1 = <&state_dpaux1_off>;
                status = "disabled";
        };
 
                clock-names = "div-clk";
                resets = <&bpmp TEGRA186_RESET_I2C6>;
                reset-names = "i2c";
+               pinctrl-names = "default", "idle";
+               pinctrl-0 = <&state_dpaux_i2c>;
+               pinctrl-1 = <&state_dpaux_off>;
                status = "disabled";
        };
 
                };
        };
 
+       bpmp: bpmp {
+               compatible = "nvidia,tegra186-bpmp";
+               iommus = <&smmu TEGRA186_SID_BPMP>;
+               mboxes = <&hsp_top0 TEGRA_HSP_MBOX_TYPE_DB
+                                   TEGRA_HSP_DB_MASTER_BPMP>;
+               shmem = <&cpu_bpmp_tx &cpu_bpmp_rx>;
+               #clock-cells = <1>;
+               #reset-cells = <1>;
+               #power-domain-cells = <1>;
+
+               bpmp_i2c: i2c {
+                       compatible = "nvidia,tegra186-bpmp-i2c";
+                       nvidia,bpmp-bus-id = <5>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               bpmp_thermal: thermal {
+                       compatible = "nvidia,tegra186-bpmp-thermal";
+                       #thermal-sensor-cells = <1>;
+               };
+       };
+
        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
                cpu@0 {
                        compatible = "nvidia,tegra186-denver";
                        device_type = "cpu";
+                       i-cache-size = <0x20000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <512>;
+                       d-cache-size = <0x10000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&L2_DENVER>;
                        reg = <0x000>;
                };
 
                cpu@1 {
                        compatible = "nvidia,tegra186-denver";
                        device_type = "cpu";
+                       i-cache-size = <0x20000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <512>;
+                       d-cache-size = <0x10000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&L2_DENVER>;
                        reg = <0x001>;
                };
 
                cpu@2 {
                        compatible = "arm,cortex-a57";
                        device_type = "cpu";
+                       i-cache-size = <0xC000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <256>;
+                       d-cache-size = <0x8000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&L2_A57>;
                        reg = <0x100>;
                };
 
                cpu@3 {
                        compatible = "arm,cortex-a57";
                        device_type = "cpu";
+                       i-cache-size = <0xC000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <256>;
+                       d-cache-size = <0x8000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&L2_A57>;
                        reg = <0x101>;
                };
 
                cpu@4 {
                        compatible = "arm,cortex-a57";
                        device_type = "cpu";
+                       i-cache-size = <0xC000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <256>;
+                       d-cache-size = <0x8000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&L2_A57>;
                        reg = <0x102>;
                };
 
                cpu@5 {
                        compatible = "arm,cortex-a57";
                        device_type = "cpu";
+                       i-cache-size = <0xC000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <256>;
+                       d-cache-size = <0x8000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&L2_A57>;
                        reg = <0x103>;
                };
-       };
 
-       bpmp: bpmp {
-               compatible = "nvidia,tegra186-bpmp";
-               iommus = <&smmu TEGRA186_SID_BPMP>;
-               mboxes = <&hsp_top0 TEGRA_HSP_MBOX_TYPE_DB
-                                   TEGRA_HSP_DB_MASTER_BPMP>;
-               shmem = <&cpu_bpmp_tx &cpu_bpmp_rx>;
-               #clock-cells = <1>;
-               #reset-cells = <1>;
-               #power-domain-cells = <1>;
-
-               bpmp_i2c: i2c {
-                       compatible = "nvidia,tegra186-bpmp-i2c";
-                       nvidia,bpmp-bus-id = <5>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       status = "disabled";
+               L2_DENVER: l2-cache0 {
+                       compatible = "cache";
+                       cache-unified;
+                       cache-level = <2>;
+                       cache-size = <0x200000>;
+                       cache-line-size = <64>;
+                       cache-sets = <2048>;
                };
 
-               bpmp_thermal: thermal {
-                       compatible = "nvidia,tegra186-bpmp-thermal";
-                       #thermal-sensor-cells = <1>;
+               L2_A57: l2-cache1 {
+                       compatible = "cache";
+                       cache-unified;
+                       cache-level = <2>;
+                       cache-size = <0x200000>;
+                       cache-line-size = <64>;
+                       cache-sets = <2048>;
                };
        };
 
                             <GIC_PPI 10
                                (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
                interrupt-parent = <&gic>;
+               always-on;
        };
 };
index 0fd5bd2..62e07e1 100644 (file)
@@ -4,7 +4,7 @@
 #include <dt-bindings/mfd/max77620.h>
 
 / {
-       model = "NVIDIA Tegra194 P2888 Processor Module";
+       model = "NVIDIA Jetson AGX Xavier";
        compatible = "nvidia,p2888", "nvidia,tegra194";
 
        aliases {
                                                regulator-boot-on;
                                        };
 
-                                       sd3 {
+                                       vdd_1v8ao: sd3 {
                                                regulator-name = "VDD_1V8AO";
                                                regulator-min-microvolt = <1800000>;
                                                regulator-max-microvolt = <1800000>;
index 73801b4..23597d5 100644 (file)
@@ -7,10 +7,22 @@
 #include "tegra194-p2888.dtsi"
 
 / {
-       model = "NVIDIA Jetson AGX Xavier Development Kit";
+       model = "NVIDIA Jetson AGX Xavier Developer Kit";
        compatible = "nvidia,p2972-0000", "nvidia,tegra194";
 
        cbb {
+               aconnect {
+                       status = "okay";
+
+                       dma-controller@2930000 {
+                               status = "okay";
+                       };
+
+                       interrupt-controller@2a40000 {
+                               status = "okay";
+                       };
+               };
+
                ddc: i2c@31c0000 {
                        status = "okay";
                };
                };
        };
 
+       pcie@14100000 {
+               status = "okay";
+
+               vddio-pex-ctl-supply = <&vdd_1v8ao>;
+
+               phys = <&p2u_hsio_0>;
+               phy-names = "p2u-0";
+       };
+
+       pcie@14140000 {
+               status = "okay";
+
+               vddio-pex-ctl-supply = <&vdd_1v8ao>;
+
+               phys = <&p2u_hsio_7>;
+               phy-names = "p2u-0";
+       };
+
+       pcie@14180000 {
+               status = "okay";
+
+               vddio-pex-ctl-supply = <&vdd_1v8ao>;
+
+               phys = <&p2u_hsio_2>, <&p2u_hsio_3>, <&p2u_hsio_4>,
+                      <&p2u_hsio_5>;
+               phy-names = "p2u-0", "p2u-1", "p2u-2", "p2u-3";
+       };
+
+       pcie@141a0000 {
+               status = "disabled";
+
+               vddio-pex-ctl-supply = <&vdd_1v8ao>;
+
+               phys = <&p2u_nvhs_0>, <&p2u_nvhs_1>, <&p2u_nvhs_2>,
+                      <&p2u_nvhs_3>, <&p2u_nvhs_4>, <&p2u_nvhs_5>,
+                      <&p2u_nvhs_6>, <&p2u_nvhs_7>;
+
+               phy-names = "p2u-0", "p2u-1", "p2u-2", "p2u-3", "p2u-4",
+                           "p2u-5", "p2u-6", "p2u-7";
+       };
+
        fan: fan {
                compatible = "pwm-fan";
                pwms = <&pwm4 0 45334>;
index c77ca21..adebbbf 100644 (file)
                        snps,rxpbl = <8>;
                };
 
+               aconnect {
+                       compatible = "nvidia,tegra194-aconnect",
+                                    "nvidia,tegra210-aconnect";
+                       clocks = <&bpmp TEGRA194_CLK_APE>,
+                                <&bpmp TEGRA194_CLK_APB2APE>;
+                       clock-names = "ape", "apb2ape";
+                       power-domains = <&bpmp TEGRA194_POWER_DOMAIN_AUD>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x02900000 0x02900000 0x200000>;
+                       status = "disabled";
+
+                       dma-controller@2930000 {
+                               compatible = "nvidia,tegra194-adma",
+                                            "nvidia,tegra186-adma";
+                               reg = <0x02930000 0x20000>;
+                               interrupt-parent = <&agic>;
+                               interrupts =  <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>,
+                                             <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+                               #dma-cells = <1>;
+                               clocks = <&bpmp TEGRA194_CLK_AHUB>;
+                               clock-names = "d_audio";
+                               status = "disabled";
+                       };
+
+                       agic: interrupt-controller@2a40000 {
+                               compatible = "nvidia,tegra194-agic",
+                                            "nvidia,tegra210-agic";
+                               #interrupt-cells = <3>;
+                               interrupt-controller;
+                               reg = <0x02a41000 0x1000>,
+                                     <0x02a42000 0x2000>;
+                               interrupts = <GIC_SPI 145
+                                             (GIC_CPU_MASK_SIMPLE(4) |
+                                              IRQ_TYPE_LEVEL_HIGH)>;
+                               clocks = <&bpmp TEGRA194_CLK_APE>;
+                               clock-names = "clk";
+                               status = "disabled";
+                       };
+               };
+
                uarta: serial@3100000 {
                        compatible = "nvidia,tegra194-uart", "nvidia,tegra20-uart";
                        reg = <0x03100000 0x40>;
                        #mbox-cells = <2>;
                };
 
+               p2u_hsio_0: phy@3e10000 {
+                       compatible = "nvidia,tegra194-p2u";
+                       reg = <0x03e10000 0x10000>;
+                       reg-names = "ctl";
+
+                       #phy-cells = <0>;
+               };
+
+               p2u_hsio_1: phy@3e20000 {
+                       compatible = "nvidia,tegra194-p2u";
+                       reg = <0x03e20000 0x10000>;
+                       reg-names = "ctl";
+
+                       #phy-cells = <0>;
+               };
+
+               p2u_hsio_2: phy@3e30000 {
+                       compatible = "nvidia,tegra194-p2u";
+                       reg = <0x03e30000 0x10000>;
+                       reg-names = "ctl";
+
+                       #phy-cells = <0>;
+               };
+
+               p2u_hsio_3: phy@3e40000 {
+                       compatible = "nvidia,tegra194-p2u";
+                       reg = <0x03e40000 0x10000>;
+                       reg-names = "ctl";
+
+                       #phy-cells = <0>;
+               };
+
+               p2u_hsio_4: phy@3e50000 {
+                       compatible = "nvidia,tegra194-p2u";
+                       reg = <0x03e50000 0x10000>;
+                       reg-names = "ctl";
+
+                       #phy-cells = <0>;
+               };
+
+               p2u_hsio_5: phy@3e60000 {
+                       compatible = "nvidia,tegra194-p2u";
+                       reg = <0x03e60000 0x10000>;
+                       reg-names = "ctl";
+
+                       #phy-cells = <0>;
+               };
+
+               p2u_hsio_6: phy@3e70000 {
+                       compatible = "nvidia,tegra194-p2u";
+                       reg = <0x03e70000 0x10000>;
+                       reg-names = "ctl";
+
+                       #phy-cells = <0>;
+               };
+
+               p2u_hsio_7: phy@3e80000 {
+                       compatible = "nvidia,tegra194-p2u";
+                       reg = <0x03e80000 0x10000>;
+                       reg-names = "ctl";
+
+                       #phy-cells = <0>;
+               };
+
+               p2u_hsio_8: phy@3e90000 {
+                       compatible = "nvidia,tegra194-p2u";
+                       reg = <0x03e90000 0x10000>;
+                       reg-names = "ctl";
+
+                       #phy-cells = <0>;
+               };
+
+               p2u_hsio_9: phy@3ea0000 {
+                       compatible = "nvidia,tegra194-p2u";
+                       reg = <0x03ea0000 0x10000>;
+                       reg-names = "ctl";
+
+                       #phy-cells = <0>;
+               };
+
+               p2u_nvhs_0: phy@3eb0000 {
+                       compatible = "nvidia,tegra194-p2u";
+                       reg = <0x03eb0000 0x10000>;
+                       reg-names = "ctl";
+
+                       #phy-cells = <0>;
+               };
+
+               p2u_nvhs_1: phy@3ec0000 {
+                       compatible = "nvidia,tegra194-p2u";
+                       reg = <0x03ec0000 0x10000>;
+                       reg-names = "ctl";
+
+                       #phy-cells = <0>;
+               };
+
+               p2u_nvhs_2: phy@3ed0000 {
+                       compatible = "nvidia,tegra194-p2u";
+                       reg = <0x03ed0000 0x10000>;
+                       reg-names = "ctl";
+
+                       #phy-cells = <0>;
+               };
+
+               p2u_nvhs_3: phy@3ee0000 {
+                       compatible = "nvidia,tegra194-p2u";
+                       reg = <0x03ee0000 0x10000>;
+                       reg-names = "ctl";
+
+                       #phy-cells = <0>;
+               };
+
+               p2u_nvhs_4: phy@3ef0000 {
+                       compatible = "nvidia,tegra194-p2u";
+                       reg = <0x03ef0000 0x10000>;
+                       reg-names = "ctl";
+
+                       #phy-cells = <0>;
+               };
+
+               p2u_nvhs_5: phy@3f00000 {
+                       compatible = "nvidia,tegra194-p2u";
+                       reg = <0x03f00000 0x10000>;
+                       reg-names = "ctl";
+
+                       #phy-cells = <0>;
+               };
+
+               p2u_nvhs_6: phy@3f10000 {
+                       compatible = "nvidia,tegra194-p2u";
+                       reg = <0x03f10000 0x10000>;
+                       reg-names = "ctl";
+
+                       #phy-cells = <0>;
+               };
+
+               p2u_nvhs_7: phy@3f20000 {
+                       compatible = "nvidia,tegra194-p2u";
+                       reg = <0x03f20000 0x10000>;
+                       reg-names = "ctl";
+
+                       #phy-cells = <0>;
+               };
+
+               p2u_hsio_10: phy@3f30000 {
+                       compatible = "nvidia,tegra194-p2u";
+                       reg = <0x03f30000 0x10000>;
+                       reg-names = "ctl";
+
+                       #phy-cells = <0>;
+               };
+
+               p2u_hsio_11: phy@3f40000 {
+                       compatible = "nvidia,tegra194-p2u";
+                       reg = <0x03f40000 0x10000>;
+                       reg-names = "ctl";
+
+                       #phy-cells = <0>;
+               };
+
                hsp_aon: hsp@c150000 {
                        compatible = "nvidia,tegra194-hsp", "nvidia,tegra186-hsp";
                        reg = <0x0c150000 0xa0000>;
                };
        };
 
+       pcie@14100000 {
+               compatible = "nvidia,tegra194-pcie", "snps,dw-pcie";
+               power-domains = <&bpmp TEGRA194_POWER_DOMAIN_PCIEX1A>;
+               reg = <0x00 0x14100000 0x0 0x00020000   /* appl registers (128K)      */
+                      0x00 0x30000000 0x0 0x00040000   /* configuration space (256K) */
+                      0x00 0x30040000 0x0 0x00040000   /* iATU_DMA reg space (256K)  */
+                      0x00 0x30080000 0x0 0x00040000>; /* DBI reg space (256K)       */
+               reg-names = "appl", "config", "atu_dma", "dbi";
+
+               status = "disabled";
+
+               #address-cells = <3>;
+               #size-cells = <2>;
+               device_type = "pci";
+               num-lanes = <1>;
+               num-viewport = <8>;
+               linux,pci-domain = <1>;
+
+               clocks = <&bpmp TEGRA194_CLK_PEX0_CORE_1>;
+               clock-names = "core";
+
+               resets = <&bpmp TEGRA194_RESET_PEX0_CORE_1_APB>,
+                        <&bpmp TEGRA194_RESET_PEX0_CORE_1>;
+               reset-names = "apb", "core";
+
+               interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>,  /* controller interrupt */
+                            <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;  /* MSI interrupt */
+               interrupt-names = "intr", "msi";
+
+               #interrupt-cells = <1>;
+               interrupt-map-mask = <0 0 0 0>;
+               interrupt-map = <0 0 0 0 &gic GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+
+               nvidia,bpmp = <&bpmp 1>;
+
+               supports-clkreq;
+               nvidia,aspm-cmrt-us = <60>;
+               nvidia,aspm-pwr-on-t-us = <20>;
+               nvidia,aspm-l0s-entrance-latency-us = <3>;
+
+               bus-range = <0x0 0xff>;
+               ranges = <0x81000000 0x0  0x30100000 0x0  0x30100000 0x0 0x00100000   /* downstream I/O (1MB) */
+                         0xc2000000 0x12 0x00000000 0x12 0x00000000 0x0 0x30000000   /* prefetchable memory (768MB) */
+                         0x82000000 0x0  0x40000000 0x12 0x30000000 0x0 0x10000000>; /* non-prefetchable memory (256MB) */
+       };
+
+       pcie@14120000 {
+               compatible = "nvidia,tegra194-pcie", "snps,dw-pcie";
+               power-domains = <&bpmp TEGRA194_POWER_DOMAIN_PCIEX1A>;
+               reg = <0x00 0x14120000 0x0 0x00020000   /* appl registers (128K)      */
+                      0x00 0x32000000 0x0 0x00040000   /* configuration space (256K) */
+                      0x00 0x32040000 0x0 0x00040000   /* iATU_DMA reg space (256K)  */
+                      0x00 0x32080000 0x0 0x00040000>; /* DBI reg space (256K)       */
+               reg-names = "appl", "config", "atu_dma", "dbi";
+
+               status = "disabled";
+
+               #address-cells = <3>;
+               #size-cells = <2>;
+               device_type = "pci";
+               num-lanes = <1>;
+               num-viewport = <8>;
+               linux,pci-domain = <2>;
+
+               clocks = <&bpmp TEGRA194_CLK_PEX0_CORE_2>;
+               clock-names = "core";
+
+               resets = <&bpmp TEGRA194_RESET_PEX0_CORE_2_APB>,
+                        <&bpmp TEGRA194_RESET_PEX0_CORE_2>;
+               reset-names = "apb", "core";
+
+               interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>,  /* controller interrupt */
+                            <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;  /* MSI interrupt */
+               interrupt-names = "intr", "msi";
+
+               #interrupt-cells = <1>;
+               interrupt-map-mask = <0 0 0 0>;
+               interrupt-map = <0 0 0 0 &gic GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
+
+               nvidia,bpmp = <&bpmp 2>;
+
+               supports-clkreq;
+               nvidia,aspm-cmrt-us = <60>;
+               nvidia,aspm-pwr-on-t-us = <20>;
+               nvidia,aspm-l0s-entrance-latency-us = <3>;
+
+               bus-range = <0x0 0xff>;
+               ranges = <0x81000000 0x0  0x32100000 0x0  0x32100000 0x0 0x00100000   /* downstream I/O (1MB) */
+                         0xc2000000 0x12 0x40000000 0x12 0x40000000 0x0 0x30000000   /* prefetchable memory (768MB) */
+                         0x82000000 0x0  0x40000000 0x12 0x70000000 0x0 0x10000000>; /* non-prefetchable memory (256MB) */
+       };
+
+       pcie@14140000 {
+               compatible = "nvidia,tegra194-pcie", "snps,dw-pcie";
+               power-domains = <&bpmp TEGRA194_POWER_DOMAIN_PCIEX1A>;
+               reg = <0x00 0x14140000 0x0 0x00020000   /* appl registers (128K)      */
+                      0x00 0x34000000 0x0 0x00040000   /* configuration space (256K) */
+                      0x00 0x34040000 0x0 0x00040000   /* iATU_DMA reg space (256K)  */
+                      0x00 0x34080000 0x0 0x00040000>; /* DBI reg space (256K)       */
+               reg-names = "appl", "config", "atu_dma", "dbi";
+
+               status = "disabled";
+
+               #address-cells = <3>;
+               #size-cells = <2>;
+               device_type = "pci";
+               num-lanes = <1>;
+               num-viewport = <8>;
+               linux,pci-domain = <3>;
+
+               clocks = <&bpmp TEGRA194_CLK_PEX0_CORE_3>;
+               clock-names = "core";
+
+               resets = <&bpmp TEGRA194_RESET_PEX0_CORE_3_APB>,
+                        <&bpmp TEGRA194_RESET_PEX0_CORE_3>;
+               reset-names = "apb", "core";
+
+               interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>,  /* controller interrupt */
+                            <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;  /* MSI interrupt */
+               interrupt-names = "intr", "msi";
+
+               #interrupt-cells = <1>;
+               interrupt-map-mask = <0 0 0 0>;
+               interrupt-map = <0 0 0 0 &gic GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+
+               nvidia,bpmp = <&bpmp 3>;
+
+               supports-clkreq;
+               nvidia,aspm-cmrt-us = <60>;
+               nvidia,aspm-pwr-on-t-us = <20>;
+               nvidia,aspm-l0s-entrance-latency-us = <3>;
+
+               bus-range = <0x0 0xff>;
+               ranges = <0x81000000 0x0  0x34100000 0x0  0x34100000 0x0 0x00100000   /* downstream I/O (1MB) */
+                         0xc2000000 0x12 0x80000000 0x12 0x80000000 0x0 0x30000000   /* prefetchable memory (768MB) */
+                         0x82000000 0x0  0x40000000 0x12 0xb0000000 0x0 0x10000000>; /* non-prefetchable memory (256MB) */
+       };
+
+       pcie@14160000 {
+               compatible = "nvidia,tegra194-pcie", "snps,dw-pcie";
+               power-domains = <&bpmp TEGRA194_POWER_DOMAIN_PCIEX4A>;
+               reg = <0x00 0x14160000 0x0 0x00020000   /* appl registers (128K)      */
+                      0x00 0x36000000 0x0 0x00040000   /* configuration space (256K) */
+                      0x00 0x36040000 0x0 0x00040000   /* iATU_DMA reg space (256K)  */
+                      0x00 0x36080000 0x0 0x00040000>; /* DBI reg space (256K)       */
+               reg-names = "appl", "config", "atu_dma", "dbi";
+
+               status = "disabled";
+
+               #address-cells = <3>;
+               #size-cells = <2>;
+               device_type = "pci";
+               num-lanes = <4>;
+               num-viewport = <8>;
+               linux,pci-domain = <4>;
+
+               clocks = <&bpmp TEGRA194_CLK_PEX0_CORE_4>;
+               clock-names = "core";
+
+               resets = <&bpmp TEGRA194_RESET_PEX0_CORE_4_APB>,
+                        <&bpmp TEGRA194_RESET_PEX0_CORE_4>;
+               reset-names = "apb", "core";
+
+               interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>,  /* controller interrupt */
+                            <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;  /* MSI interrupt */
+               interrupt-names = "intr", "msi";
+
+               #interrupt-cells = <1>;
+               interrupt-map-mask = <0 0 0 0>;
+               interrupt-map = <0 0 0 0 &gic GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
+
+               nvidia,bpmp = <&bpmp 4>;
+
+               supports-clkreq;
+               nvidia,aspm-cmrt-us = <60>;
+               nvidia,aspm-pwr-on-t-us = <20>;
+               nvidia,aspm-l0s-entrance-latency-us = <3>;
+
+               bus-range = <0x0 0xff>;
+               ranges = <0x81000000 0x0  0x36100000 0x0  0x36100000 0x0 0x00100000   /* downstream I/O (1MB) */
+                         0xc2000000 0x14 0x00000000 0x14 0x00000000 0x3 0x40000000   /* prefetchable memory (13GB) */
+                         0x82000000 0x0  0x40000000 0x17 0x40000000 0x0 0xc0000000>; /* non-prefetchable memory (3GB) */
+       };
+
+       pcie@14180000 {
+               compatible = "nvidia,tegra194-pcie", "snps,dw-pcie";
+               power-domains = <&bpmp TEGRA194_POWER_DOMAIN_PCIEX8B>;
+               reg = <0x00 0x14180000 0x0 0x00020000   /* appl registers (128K)      */
+                      0x00 0x38000000 0x0 0x00040000   /* configuration space (256K) */
+                      0x00 0x38040000 0x0 0x00040000   /* iATU_DMA reg space (256K)  */
+                      0x00 0x38080000 0x0 0x00040000>; /* DBI reg space (256K)       */
+               reg-names = "appl", "config", "atu_dma", "dbi";
+
+               status = "disabled";
+
+               #address-cells = <3>;
+               #size-cells = <2>;
+               device_type = "pci";
+               num-lanes = <8>;
+               num-viewport = <8>;
+               linux,pci-domain = <0>;
+
+               clocks = <&bpmp TEGRA194_CLK_PEX0_CORE_0>;
+               clock-names = "core";
+
+               resets = <&bpmp TEGRA194_RESET_PEX0_CORE_0_APB>,
+                        <&bpmp TEGRA194_RESET_PEX0_CORE_0>;
+               reset-names = "apb", "core";
+
+               interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>,  /* controller interrupt */
+                            <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;  /* MSI interrupt */
+               interrupt-names = "intr", "msi";
+
+               #interrupt-cells = <1>;
+               interrupt-map-mask = <0 0 0 0>;
+               interrupt-map = <0 0 0 0 &gic GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+
+               nvidia,bpmp = <&bpmp 0>;
+
+               supports-clkreq;
+               nvidia,aspm-cmrt-us = <60>;
+               nvidia,aspm-pwr-on-t-us = <20>;
+               nvidia,aspm-l0s-entrance-latency-us = <3>;
+
+               bus-range = <0x0 0xff>;
+               ranges = <0x81000000 0x0  0x38100000 0x0  0x38100000 0x0 0x00100000   /* downstream I/O (1MB) */
+                         0xc2000000 0x18 0x00000000 0x18 0x00000000 0x3 0x40000000   /* prefetchable memory (13GB) */
+                         0x82000000 0x0  0x40000000 0x1b 0x40000000 0x0 0xc0000000>; /* non-prefetchable memory (3GB) */
+       };
+
+       pcie@141a0000 {
+               compatible = "nvidia,tegra194-pcie", "snps,dw-pcie";
+               power-domains = <&bpmp TEGRA194_POWER_DOMAIN_PCIEX8A>;
+               reg = <0x00 0x141a0000 0x0 0x00020000   /* appl registers (128K)      */
+                      0x00 0x3a000000 0x0 0x00040000   /* configuration space (256K) */
+                      0x00 0x3a040000 0x0 0x00040000   /* iATU_DMA reg space (256K)  */
+                      0x00 0x3a080000 0x0 0x00040000>; /* DBI reg space (256K)       */
+               reg-names = "appl", "config", "atu_dma", "dbi";
+
+               status = "disabled";
+
+               #address-cells = <3>;
+               #size-cells = <2>;
+               device_type = "pci";
+               num-lanes = <8>;
+               num-viewport = <8>;
+               linux,pci-domain = <5>;
+
+               clocks = <&bpmp TEGRA194_CLK_PEX1_CORE_5>,
+                       <&bpmp TEGRA194_CLK_PEX1_CORE_5M>;
+               clock-names = "core", "core_m";
+
+               resets = <&bpmp TEGRA194_RESET_PEX1_CORE_5_APB>,
+                        <&bpmp TEGRA194_RESET_PEX1_CORE_5>;
+               reset-names = "apb", "core";
+
+               interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,  /* controller interrupt */
+                            <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;  /* MSI interrupt */
+               interrupt-names = "intr", "msi";
+
+               nvidia,bpmp = <&bpmp 5>;
+
+               #interrupt-cells = <1>;
+               interrupt-map-mask = <0 0 0 0>;
+               interrupt-map = <0 0 0 0 &gic GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
+
+               supports-clkreq;
+               nvidia,aspm-cmrt-us = <60>;
+               nvidia,aspm-pwr-on-t-us = <20>;
+               nvidia,aspm-l0s-entrance-latency-us = <3>;
+
+               bus-range = <0x0 0xff>;
+               ranges = <0x81000000 0x0  0x3a100000 0x0  0x3a100000 0x0 0x00100000   /* downstream I/O (1MB) */
+                         0xc2000000 0x1c 0x00000000 0x1c 0x00000000 0x3 0x40000000   /* prefetchable memory (13GB) */
+                         0x82000000 0x0  0x40000000 0x1f 0x40000000 0x0 0xc0000000>; /* non-prefetchable memory (3GB) */
+       };
+
        sysram@40000000 {
                compatible = "nvidia,tegra194-sysram", "mmio-sram";
                reg = <0x0 0x40000000 0x0 0x50000>;
                             <GIC_PPI 10
                                (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
                interrupt-parent = <&gic>;
+               always-on;
        };
 };
index 4dcd0d3..2772382 100644 (file)
                };
        };
 
+       i2c@7000c500 {
+               /* module ID EEPROM */
+               eeprom@50 {
+                       compatible = "atmel,24c02";
+                       reg = <0x50>;
+
+                       address-bits = <8>;
+                       page-size = <8>;
+                       size = <256>;
+                       read-only;
+               };
+       };
+
        pmc@7000e400 {
                nvidia,invert-interrupt;
        };
                        regulator-max-microvolt = <1320000>;
                        enable-gpios = <&pmic 6 GPIO_ACTIVE_HIGH>;
                        regulator-ramp-delay = <80>;
-                       regulator-enable-ramp-delay = <1000>;
+                       regulator-enable-ramp-delay = <2000>;
+                       regulator-settling-time-us = <160>;
                };
        };
 };
index 5a57396..a3cafe3 100644 (file)
                };
        };
 
+       i2c@7000c500 {
+               /* carrier board ID EEPROM */
+               eeprom@57 {
+                       compatible = "atmel,24c02";
+                       reg = <0x57>;
+
+                       address-bits = <8>;
+                       page-size = <8>;
+                       size = <256>;
+                       read-only;
+               };
+       };
+
        clock@70110000 {
                status = "okay";
 
index 5d01819..9d17ec7 100644 (file)
                status = "okay";
        };
 
+       pwm@7000a000 {
+               status = "okay";
+       };
+
+       i2c@7000c500 {
+               status = "okay";
+               clock-frequency = <100000>;
+
+               eeprom@50 {
+                       compatible = "atmel,24c02";
+                       reg = <0x50>;
+
+                       address-bits = <8>;
+                       page-size = <8>;
+                       size = <256>;
+                       read-only;
+               };
+
+               eeprom@57 {
+                       compatible = "atmel,24c02";
+                       reg = <0x57>;
+
+                       address-bits = <8>;
+                       page-size = <8>;
+                       size = <256>;
+                       read-only;
+               };
+       };
+
        hdmi_ddc: i2c@7000c700 {
                status = "okay";
                clock-frequency = <100000>;
                cpu@3 {
                        enable-method = "psci";
                };
+
+               idle-states {
+                       cpu-sleep {
+                               status = "okay";
+                       };
+               };
        };
 
        gpio-keys {
                };
 
                vdd_gpu: regulator@6 {
-                       compatible = "regulator-fixed";
+                       compatible = "pwm-regulator";
                        reg = <6>;
-
+                       pwms = <&pwm 1 4880>;
                        regulator-name = "VDD_GPU";
-                       regulator-min-microvolt = <5000000>;
-                       regulator-max-microvolt = <5000000>;
-                       regulator-enable-ramp-delay = <250>;
-
-                       gpio = <&pmic 6 GPIO_ACTIVE_HIGH>;
-                       enable-active-high;
-
+                       regulator-min-microvolt = <710000>;
+                       regulator-max-microvolt = <1320000>;
+                       regulator-ramp-delay = <80>;
+                       regulator-enable-ramp-delay = <2000>;
+                       regulator-settling-time-us = <160>;
+                       enable-gpios = <&pmic 6 GPIO_ACTIVE_HIGH>;
                        vin-supply = <&vdd_5v0_sys>;
                };
        };
index a550c0a..6597531 100644 (file)
                         <&tegra_car 72>,
                         <&tegra_car 74>;
                reset-names = "pex", "afi", "pcie_x";
+
+               pinctrl-names = "default", "idle";
+               pinctrl-0 = <&pex_dpd_disable>;
+               pinctrl-1 = <&pex_dpd_enable>;
+
                status = "disabled";
 
                pci@1,0 {
                        pins = "sdmmc3";
                        power-source = <TEGRA_IO_PAD_VOLTAGE_1V8>;
                };
+
+               pex_dpd_disable: pex_en {
+                       pex-dpd-disable {
+                               pins = "pex-bias", "pex-clk1", "pex-clk2";
+                               low-power-disable;
+                       };
+               };
+
+               pex_dpd_enable: pex_dis {
+                       pex-dpd-enable {
+                               pins = "pex-bias", "pex-clk1", "pex-clk2";
+                               low-power-enable;
+                       };
+               };
        };
 
        fuse@7000f800 {
                        compatible = "nvidia,tegra210-agic";
                        #interrupt-cells = <3>;
                        interrupt-controller;
-                       reg = <0x702f9000 0x2000>,
+                       reg = <0x702f9000 0x1000>,
                              <0x702fa000 0x2000>;
                        interrupts = <GIC_SPI 102 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
                        clocks = <&tegra_car TEGRA210_CLK_APE>;
                             <GIC_PPI 10
                                (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
                interrupt-parent = <&gic>;
+               arm,no-tick-in-suspend;
        };
 
        soctherm: thermal-sensor@700e2000 {
index 21d548f..0a7e5df 100644 (file)
@@ -7,6 +7,10 @@ dtb-$(CONFIG_ARCH_QCOM)        += msm8992-bullhead-rev-101.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8994-angler-rev-101.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8996-mtp.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8998-mtp.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sdm845-cheza-r1.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sdm845-cheza-r2.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sdm845-cheza-r3.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sdm845-db845c.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sdm845-mtp.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += qcs404-evb-1000.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += qcs404-evb-4000.dtb
index dacd465..5ea9fb8 100644 (file)
                        reg = <0x0>;
                        next-level-cache = <&L2_0>;
                        enable-method = "psci";
-                       cpu-idle-states = <&CPU_SPC>;
+                       cpu-idle-states = <&CPU_SLEEP_0>;
                        clocks = <&apcs>;
                        operating-points-v2 = <&cpu_opp_table>;
                        #cooling-cells = <2>;
                        reg = <0x1>;
                        next-level-cache = <&L2_0>;
                        enable-method = "psci";
-                       cpu-idle-states = <&CPU_SPC>;
+                       cpu-idle-states = <&CPU_SLEEP_0>;
                        clocks = <&apcs>;
                        operating-points-v2 = <&cpu_opp_table>;
                        #cooling-cells = <2>;
                        reg = <0x2>;
                        next-level-cache = <&L2_0>;
                        enable-method = "psci";
-                       cpu-idle-states = <&CPU_SPC>;
+                       cpu-idle-states = <&CPU_SLEEP_0>;
                        clocks = <&apcs>;
                        operating-points-v2 = <&cpu_opp_table>;
                        #cooling-cells = <2>;
                        reg = <0x3>;
                        next-level-cache = <&L2_0>;
                        enable-method = "psci";
-                       cpu-idle-states = <&CPU_SPC>;
+                       cpu-idle-states = <&CPU_SLEEP_0>;
                        clocks = <&apcs>;
                        operating-points-v2 = <&cpu_opp_table>;
                        #cooling-cells = <2>;
                };
 
                idle-states {
-                       CPU_SPC: spc {
+                       entry-method = "psci";
+
+                       CPU_SLEEP_0: cpu-sleep-0 {
                                compatible = "arm,idle-state";
+                               idle-state-name = "standalone-power-collapse";
                                arm,psci-suspend-param = <0x40000002>;
                                entry-latency-us = <130>;
                                exit-latency-us = <150>;
                };
 
                funnel@821000 {
-                       compatible = "arm,coresight-funnel", "arm,primecell";
+                       compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                        reg = <0x821000 0x1000>;
 
                        clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
                };
 
                funnel@841000 { /* APSS funnel only 4 inputs are used */
-                       compatible = "arm,coresight-funnel", "arm,primecell";
+                       compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                        reg = <0x841000 0x1000>;
 
                        clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
index 942465d..96c0a48 100644 (file)
@@ -94,6 +94,8 @@
                        compatible = "qcom,kryo";
                        reg = <0x0 0x0>;
                        enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
+                       capacity-dmips-mhz = <1024>;
                        next-level-cache = <&L2_0>;
                        L2_0: l2-cache {
                              compatible = "cache";
                        compatible = "qcom,kryo";
                        reg = <0x0 0x1>;
                        enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
+                       capacity-dmips-mhz = <1024>;
                        next-level-cache = <&L2_0>;
                };
 
                        compatible = "qcom,kryo";
                        reg = <0x0 0x100>;
                        enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
+                       capacity-dmips-mhz = <1024>;
                        next-level-cache = <&L2_1>;
                        L2_1: l2-cache {
                              compatible = "cache";
                        compatible = "qcom,kryo";
                        reg = <0x0 0x101>;
                        enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
+                       capacity-dmips-mhz = <1024>;
                        next-level-cache = <&L2_1>;
                };
 
                                };
                        };
                };
+
+               idle-states {
+                       entry-method = "psci";
+
+                       CPU_SLEEP_0: cpu-sleep-0 {
+                               compatible = "arm,idle-state";
+                               idle-state-name = "standalone-power-collapse";
+                               arm,psci-suspend-param = <0x00000004>;
+                               entry-latency-us = <130>;
+                               exit-latency-us = <80>;
+                               min-residency-us = <300>;
+                       };
+               };
        };
 
        thermal-zones {
                        clock-names = "ref_clk_src", "ref_clk";
                        clocks = <&rpmcc RPM_SMD_LN_BB_CLK>,
                                 <&gcc GCC_UFS_CLKREF_CLK>;
+                       resets = <&ufshc 0>;
                        status = "disabled";
                };
 
-               ufshc@624000 {
+               ufshc: ufshc@624000 {
                        compatible = "qcom,ufshc";
                        reg = <0x624000 0x2500>;
                        interrupts = <GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>;
                                <0 0>;
 
                        lanes-per-direction = <1>;
+                       #reset-cells = <1>;
                        status = "disabled";
 
                        ufs_variant {
                        clock-names = "iface",
                                      "bus";
                        #iommu-cells = <1>;
-                       status = "disabled";
                };
 
                camss: camss@a00000 {
                        clock-names = "iface", "bus";
 
                        power-domains = <&mmcc GPU_GDSC>;
-
-                       status = "disabled";
                };
 
                mdp_smmu: arm,smmu@d00000 {
                        clock-names = "iface", "bus";
 
                        power-domains = <&mmcc MDSS_GDSC>;
-
-                       status = "disabled";
                };
 
                lpass_q6_smmu: arm,smmu-lpass_q6@1600000 {
                        clocks = <&gcc GCC_HLOS1_VOTE_LPASS_CORE_SMMU_CLK>,
                                 <&gcc GCC_HLOS1_VOTE_LPASS_ADSP_SMMU_CLK>;
                        clock-names = "iface", "bus";
-                       status = "disabled";
                };
 
                agnoc@0 {
                        #interrupt-cells = <1>;
 
                        clocks = <&mmcc MDSS_AHB_CLK>;
-                       clock-names = "iface_clk";
+                       clock-names = "iface";
 
                        #address-cells = <1>;
                        #size-cells = <1>;
                                         <&mmcc MDSS_MDP_CLK>,
                                         <&mmcc SMMU_MDP_AXI_CLK>,
                                         <&mmcc MDSS_VSYNC_CLK>;
-                               clock-names = "iface_clk",
-                                             "bus_clk",
-                                             "core_clk",
-                                             "iommu_clk",
-                                             "vsync_clk";
+                               clock-names = "iface",
+                                             "bus",
+                                             "core",
+                                             "iommu",
+                                             "vsync";
 
                                iommus = <&mdp_smmu 0>;
 
                                         <&mmcc MDSS_HDMI_AHB_CLK>,
                                         <&mmcc MDSS_EXTPCLK_CLK>;
                                clock-names =
-                                       "mdp_core_clk",
-                                       "iface_clk",
-                                       "core_clk",
-                                       "alt_iface_clk",
-                                       "extp_clk";
+                                       "mdp_core",
+                                       "iface",
+                                       "core",
+                                       "alt_iface",
+                                       "extp";
 
                                phys = <&hdmi_phy>;
                                phy-names = "hdmi_phy";
 
                                clocks = <&mmcc MDSS_AHB_CLK>,
                                         <&gcc GCC_HDMI_CLKREF_CLK>;
-                               clock-names = "iface_clk",
-                                             "ref_clk";
+                               clock-names = "iface",
+                                             "ref";
                        };
                };
        };
                                power-domains = <&gcc HLOS1_VOTE_LPASS_ADSP_GDSC>;
                                compatible = "qcom,apr-v2";
                                qcom,smd-channels = "apr_audio_svc";
-                               reg = <APR_DOMAIN_ADSP>;
+                               qcom,apr-domain = <APR_DOMAIN_ADSP>;
                                #address-cells = <1>;
                                #size-cells = <0>;
 
index 574be78..c13ed7a 100644 (file)
@@ -4,6 +4,7 @@
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/clock/qcom,gcc-msm8998.h>
 #include <dt-bindings/clock/qcom,rpmcc.h>
+#include <dt-bindings/power/qcom-rpmpd.h>
 #include <dt-bindings/gpio/gpio.h>
 
 / {
@@ -78,6 +79,7 @@
                        compatible = "arm,armv8";
                        reg = <0x0 0x0>;
                        enable-method = "psci";
+                       cpu-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>;
                        next-level-cache = <&L2_0>;
                        L2_0: l2-cache {
                                compatible = "arm,arch-cache";
@@ -96,6 +98,7 @@
                        compatible = "arm,armv8";
                        reg = <0x0 0x1>;
                        enable-method = "psci";
+                       cpu-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>;
                        next-level-cache = <&L2_0>;
                        L1_I_1: l1-icache {
                                compatible = "arm,arch-cache";
                        compatible = "arm,armv8";
                        reg = <0x0 0x2>;
                        enable-method = "psci";
+                       cpu-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>;
                        next-level-cache = <&L2_0>;
                        L1_I_2: l1-icache {
                                compatible = "arm,arch-cache";
                        compatible = "arm,armv8";
                        reg = <0x0 0x3>;
                        enable-method = "psci";
+                       cpu-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>;
                        next-level-cache = <&L2_0>;
                        L1_I_3: l1-icache {
                                compatible = "arm,arch-cache";
                        compatible = "arm,armv8";
                        reg = <0x0 0x100>;
                        enable-method = "psci";
+                       cpu-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>;
                        next-level-cache = <&L2_1>;
                        L2_1: l2-cache {
                                compatible = "arm,arch-cache";
                        compatible = "arm,armv8";
                        reg = <0x0 0x101>;
                        enable-method = "psci";
+                       cpu-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>;
                        next-level-cache = <&L2_1>;
                        L1_I_101: l1-icache {
                                compatible = "arm,arch-cache";
                        compatible = "arm,armv8";
                        reg = <0x0 0x102>;
                        enable-method = "psci";
+                       cpu-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>;
                        next-level-cache = <&L2_1>;
                        L1_I_102: l1-icache {
                                compatible = "arm,arch-cache";
                        compatible = "arm,armv8";
                        reg = <0x0 0x103>;
                        enable-method = "psci";
+                       cpu-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>;
                        next-level-cache = <&L2_1>;
                        L1_I_103: l1-icache {
                                compatible = "arm,arch-cache";
                                };
                        };
                };
+
+               idle-states {
+                       entry-method = "psci";
+
+                       LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 {
+                               compatible = "arm,idle-state";
+                               idle-state-name = "little-retention";
+                               arm,psci-suspend-param = <0x00000002>;
+                               entry-latency-us = <81>;
+                               exit-latency-us = <86>;
+                               min-residency-us = <200>;
+                       };
+
+                       LITTLE_CPU_SLEEP_1: cpu-sleep-0-1 {
+                               compatible = "arm,idle-state";
+                               idle-state-name = "little-power-collapse";
+                               arm,psci-suspend-param = <0x40000003>;
+                               entry-latency-us = <273>;
+                               exit-latency-us = <612>;
+                               min-residency-us = <1000>;
+                               local-timer-stop;
+                       };
+
+                       BIG_CPU_SLEEP_0: cpu-sleep-1-0 {
+                               compatible = "arm,idle-state";
+                               idle-state-name = "big-retention";
+                               arm,psci-suspend-param = <0x00000002>;
+                               entry-latency-us = <79>;
+                               exit-latency-us = <82>;
+                               min-residency-us = <200>;
+                       };
+
+                       BIG_CPU_SLEEP_1: cpu-sleep-1-1 {
+                               compatible = "arm,idle-state";
+                               idle-state-name = "big-power-collapse";
+                               arm,psci-suspend-param = <0x40000003>;
+                               entry-latency-us = <336>;
+                               exit-latency-us = <525>;
+                               min-residency-us = <1000>;
+                               local-timer-stop;
+                       };
+               };
        };
 
        firmware {
                                compatible = "qcom,rpmcc-msm8998", "qcom,rpmcc";
                                #clock-cells = <1>;
                        };
+
+                       rpmpd: power-controller {
+                               compatible = "qcom,msm8998-rpmpd";
+                               #power-domain-cells = <1>;
+                               operating-points-v2 = <&rpmpd_opp_table>;
+
+                               rpmpd_opp_table: opp-table {
+                                       compatible = "operating-points-v2";
+
+                                       rpmpd_opp_ret: opp1 {
+                                               opp-level = <16>;
+                                       };
+
+                                       rpmpd_opp_ret_plus: opp2 {
+                                               opp-level = <32>;
+                                       };
+
+                                       rpmpd_opp_min_svs: opp3 {
+                                               opp-level = <48>;
+                                       };
+
+                                       rpmpd_opp_low_svs: opp4 {
+                                               opp-level = <64>;
+                                       };
+
+                                       rpmpd_opp_svs: opp5 {
+                                               opp-level = <128>;
+                                       };
+
+                                       rpmpd_opp_svs_plus: opp6 {
+                                               opp-level = <192>;
+                                       };
+
+                                       rpmpd_opp_nom: opp7 {
+                                               opp-level = <256>;
+                                       };
+
+                                       rpmpd_opp_nom_plus: opp8 {
+                                               opp-level = <320>;
+                                       };
+
+                                       rpmpd_opp_turbo: opp9 {
+                                               opp-level = <384>;
+                                       };
+
+                                       rpmpd_opp_turbo_plus: opp10 {
+                                               opp-level = <512>;
+                                       };
+                               };
+                       };
                };
        };
 
                        #thermal-sensor-cells = <1>;
                };
 
+               anoc1_smmu: iommu@1680000 {
+                       compatible = "qcom,msm8998-smmu-v2", "qcom,smmu-v2";
+                       reg = <0x01680000 0x10000>;
+                       #iommu-cells = <1>;
+
+                       #global-interrupts = <0>;
+                       interrupts =
+                               <GIC_SPI 364 IRQ_TYPE_EDGE_RISING>,
+                               <GIC_SPI 365 IRQ_TYPE_EDGE_RISING>,
+                               <GIC_SPI 366 IRQ_TYPE_EDGE_RISING>,
+                               <GIC_SPI 367 IRQ_TYPE_EDGE_RISING>,
+                               <GIC_SPI 368 IRQ_TYPE_EDGE_RISING>,
+                               <GIC_SPI 369 IRQ_TYPE_EDGE_RISING>;
+               };
+
+               pcie0: pci@1c00000 {
+                       compatible = "qcom,pcie-msm8996";
+                       reg =   <0x01c00000 0x2000>,
+                               <0x1b000000 0xf1d>,
+                               <0x1b000f20 0xa8>,
+                               <0x1b100000 0x100000>;
+                       reg-names = "parf", "dbi", "elbi", "config";
+                       device_type = "pci";
+                       linux,pci-domain = <0>;
+                       bus-range = <0x00 0xff>;
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       num-lanes = <1>;
+                       phys = <&pciephy>;
+                       phy-names = "pciephy";
+
+                       ranges = <0x01000000 0x0 0x1b200000 0x1b200000 0x0 0x100000>,
+                                <0x02000000 0x0 0x1b300000 0x1b300000 0x0 0xd00000>;
+
+                       #interrupt-cells = <1>;
+                       interrupts = <GIC_SPI 405 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi";
+                       interrupt-map-mask = <0 0 0 0x7>;
+                       interrupt-map = <0 0 0 1 &intc 0 135 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0 0 0 2 &intc 0 136 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0 0 0 3 &intc 0 138 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0 0 0 4 &intc 0 139 IRQ_TYPE_LEVEL_HIGH>;
+
+                       clocks = <&gcc GCC_PCIE_0_PIPE_CLK>,
+                                <&gcc GCC_PCIE_0_MSTR_AXI_CLK>,
+                                <&gcc GCC_PCIE_0_SLV_AXI_CLK>,
+                                <&gcc GCC_PCIE_0_CFG_AHB_CLK>,
+                                <&gcc GCC_PCIE_0_AUX_CLK>;
+                       clock-names = "pipe", "bus_master", "bus_slave", "cfg", "aux";
+
+                       power-domains = <&gcc PCIE_0_GDSC>;
+                       iommu-map = <0x100 &anoc1_smmu 0x1480 1>;
+                       perst-gpios = <&tlmm 35 GPIO_ACTIVE_LOW>;
+               };
+
+               phy@1c06000 {
+                       compatible = "qcom,msm8998-qmp-pcie-phy";
+                       reg = <0x01c06000 0x18c>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       clocks = <&gcc GCC_PCIE_PHY_AUX_CLK>,
+                                <&gcc GCC_PCIE_0_CFG_AHB_CLK>,
+                                <&gcc GCC_PCIE_CLKREF_CLK>;
+                       clock-names = "aux", "cfg_ahb", "ref";
+
+                       resets = <&gcc GCC_PCIE_0_PHY_BCR>, <&gcc GCC_PCIE_PHY_BCR>;
+                       reset-names = "phy", "common";
+
+                       vdda-phy-supply = <&vreg_l1a_0p875>;
+                       vdda-pll-supply = <&vreg_l2a_1p2>;
+
+                       pciephy: lane@1c06800 {
+                               reg = <0x01c06200 0x128>, <0x01c06400 0x1fc>, <0x01c06800 0x20c>;
+                               #phy-cells = <0>;
+
+                               clocks = <&gcc GCC_PCIE_0_PIPE_CLK>;
+                               clock-names = "pipe0";
+                               clock-output-names = "pcie_0_pipe_clk_src";
+                               #clock-cells = <0>;
+                       };
+               };
+
                tcsr_mutex_regs: syscon@1f40000 {
                        compatible = "syscon";
                        reg = <0x1f40000 0x20000>;
index d3ca35a..051a52d 100644 (file)
@@ -39,7 +39,7 @@
                #size-cells = <0>;
 
                pm8998_pon: pon@800 {
-                       compatible = "qcom,pm8916-pon";
+                       compatible = "qcom,pm8998-pon";
 
                        reg = <0x800>;
                        mode-bootloader = <0x2>;
index e8e186b..14240fe 100644 (file)
@@ -98,7 +98,7 @@
                                qcom,pre-scaling = <1 1>;
                        };
 
-                       vph_pwr {
+                       pon_1: vph_pwr {
                                reg = <ADC5_VPH_PWR>;
                                qcom,pre-scaling = <1 3>;
                        };
                                qcom,pre-scaling = <1 1>;
                        };
 
-                       xo_therm_100k_pu {
-                               reg = <ADC5_XO_THERM_100K_PU>;
+                       pa_therm1: thermistor1 {
+                               reg = <ADC5_AMUX_THM1_100K_PU>;
+                               qcom,ratiometric;
+                               qcom,hw-settle-time = <200>;
                                qcom,pre-scaling = <1 1>;
                        };
 
-                       amux_thm1_100k_pu {
-                               reg = <ADC5_AMUX_THM1_100K_PU>;
+                       pa_therm3: thermistor3 {
+                               reg = <ADC5_AMUX_THM3_100K_PU>;
+                               qcom,ratiometric;
+                               qcom,hw-settle-time = <200>;
                                qcom,pre-scaling = <1 1>;
                        };
 
-                       amux_thm3_100k_pu {
-                               reg = <ADC5_AMUX_THM3_100K_PU>;
+                       xo_therm: xo_temp {
+                               reg = <ADC5_XO_THERM_100K_PU>;
+                               qcom,ratiometric;
+                               qcom,hw-settle-time = <200>;
                                qcom,pre-scaling = <1 1>;
                        };
                };
index 2c31271..11c0a71 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 // Copyright (c) 2018, Linaro Limited
 
+#include <dt-bindings/gpio/gpio.h>
 #include "qcs404.dtsi"
 #include "pms405.dtsi"
 
        qcom,controlled-remotely;
 };
 
+&gcc {
+       protected-clocks = <GCC_BIMC_CDSP_CLK>,
+                          <GCC_CDSP_CFG_AHB_CLK>,
+                          <GCC_CDSP_BIMC_CLK_SRC>,
+                          <GCC_CDSP_TBU_CLK>;
+};
+
 &pms405_spmi_regulators {
-       vdd_s3-supply = <&pms405_s3>;
+       vdd_s3-supply = <&vph_pwr>;
 
        pms405_s3: s3 {
                regulator-always-on;
                regulator-boot-on;
                regulator-name = "vdd_apc";
                regulator-min-microvolt = <1048000>;
-               regulator-max-microvolt = <1352000>;
+               regulator-max-microvolt = <1384000>;
        };
 };
 
+&pcie {
+       status = "ok";
+
+       perst-gpio = <&tlmm 43 GPIO_ACTIVE_LOW>;
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&perst_state>;
+};
+
+&pcie_phy {
+       status = "ok";
+
+       vdda-vp-supply = <&vreg_l3_1p05>;
+       vdda-vph-supply = <&vreg_l5_1p8>;
+};
+
 &remoteproc_adsp {
        status = "ok";
 };
                };
 
                vreg_l3_1p05: l3 {
-                       regulator-min-microvolt = <1050000>;
+                       regulator-min-microvolt = <1048000>;
                        regulator-max-microvolt = <1160000>;
                };
 
 };
 
 &tlmm {
+       perst_state: perst {
+               pins = "gpio43";
+               function = "gpio";
+
+               drive-strength = <2>;
+               bias-disable;
+               output-low;
+       };
+
        sdc1_on: sdc1-on {
                clk {
                        pins = "sdc1_clk";
                data {
                        pins = "sdc1_data";
                        bias-pull-up;
-                       dreive-strength = <10>;
+                       drive-strength = <10>;
                };
 
                rclk {
                data {
                        pins = "sdc1_data";
                        bias-pull-up;
-                       dreive-strength = <2>;
+                       drive-strength = <2>;
                };
 
                rclk {
index ffedf96..3d07897 100644 (file)
@@ -3,7 +3,10 @@
 
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/clock/qcom,gcc-qcs404.h>
+#include <dt-bindings/clock/qcom,turingcc-qcs404.h>
 #include <dt-bindings/clock/qcom,rpmcc.h>
+#include <dt-bindings/power/qcom-rpmpd.h>
+#include <dt-bindings/thermal/thermal.h>
 
 / {
        interrupt-parent = <&intc>;
@@ -30,7 +33,9 @@
                        compatible = "arm,cortex-a53";
                        reg = <0x100>;
                        enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
                        next-level-cache = <&L2_0>;
+                       #cooling-cells = <2>;
                };
 
                CPU1: cpu@101 {
@@ -38,7 +43,9 @@
                        compatible = "arm,cortex-a53";
                        reg = <0x101>;
                        enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
                        next-level-cache = <&L2_0>;
+                       #cooling-cells = <2>;
                };
 
                CPU2: cpu@102 {
@@ -46,7 +53,9 @@
                        compatible = "arm,cortex-a53";
                        reg = <0x102>;
                        enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
                        next-level-cache = <&L2_0>;
+                       #cooling-cells = <2>;
                };
 
                CPU3: cpu@103 {
                        compatible = "arm,cortex-a53";
                        reg = <0x103>;
                        enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
                        next-level-cache = <&L2_0>;
+                       #cooling-cells = <2>;
                };
 
                L2_0: l2-cache {
                        compatible = "cache";
                        cache-level = <2>;
                };
+
+               idle-states {
+                       entry-method = "psci";
+
+                       CPU_SLEEP_0: cpu-sleep-0 {
+                               compatible = "arm,idle-state";
+                               idle-state-name = "standalone-power-collapse";
+                               arm,psci-suspend-param = <0x40000003>;
+                               entry-latency-us = <125>;
+                               exit-latency-us = <180>;
+                               min-residency-us = <595>;
+                               local-timer-stop;
+                       };
+               };
        };
 
        firmware {
                method = "smc";
        };
 
-       remoteproc_adsp: remoteproc-adsp {
-               compatible = "qcom,qcs404-adsp-pas";
-
-               interrupts-extended = <&intc GIC_SPI 293 IRQ_TYPE_EDGE_RISING>,
-                                     <&adsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
-                                     <&adsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
-                                     <&adsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
-                                     <&adsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>;
-               interrupt-names = "wdog", "fatal", "ready",
-                                 "handover", "stop-ack";
-
-               clocks = <&xo_board>;
-               clock-names = "xo";
-
-               memory-region = <&adsp_fw_mem>;
-
-               qcom,smem-states = <&adsp_smp2p_out 0>;
-               qcom,smem-state-names = "stop";
-
-               status = "disabled";
-
-               glink-edge {
-                       interrupts = <GIC_SPI 289 IRQ_TYPE_EDGE_RISING>;
-
-                       qcom,remote-pid = <2>;
-                       mboxes = <&apcs_glb 8>;
-
-                       label = "adsp";
-               };
-       };
-
-       remoteproc_cdsp: remoteproc-cdsp {
-               compatible = "qcom,qcs404-cdsp-pas";
-
-               interrupts-extended = <&intc GIC_SPI 229 IRQ_TYPE_EDGE_RISING>,
-                                     <&cdsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
-                                     <&cdsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
-                                     <&cdsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
-                                     <&cdsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>;
-               interrupt-names = "wdog", "fatal", "ready",
-                                 "handover", "stop-ack";
-
-               clocks = <&xo_board>;
-               clock-names = "xo";
-
-               memory-region = <&cdsp_fw_mem>;
-
-               qcom,smem-states = <&cdsp_smp2p_out 0>;
-               qcom,smem-state-names = "stop";
-
-               status = "disabled";
-
-               glink-edge {
-                       interrupts = <GIC_SPI 141 IRQ_TYPE_EDGE_RISING>;
-
-                       qcom,remote-pid = <5>;
-                       mboxes = <&apcs_glb 12>;
-
-                       label = "cdsp";
-               };
-       };
-
-       remoteproc_wcss: remoteproc-wcss {
-               compatible = "qcom,qcs404-wcss-pas";
-
-               interrupts-extended = <&intc GIC_SPI 153 IRQ_TYPE_EDGE_RISING>,
-                                     <&wcss_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
-                                     <&wcss_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
-                                     <&wcss_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
-                                     <&wcss_smp2p_in 3 IRQ_TYPE_EDGE_RISING>;
-               interrupt-names = "wdog", "fatal", "ready",
-                                 "handover", "stop-ack";
-
-               clocks = <&xo_board>;
-               clock-names = "xo";
-
-               memory-region = <&wlan_fw_mem>;
-
-               qcom,smem-states = <&wcss_smp2p_out 0>;
-               qcom,smem-state-names = "stop";
-
-               status = "disabled";
-
-               glink-edge {
-                       interrupts = <GIC_SPI 156 IRQ_TYPE_EDGE_RISING>;
-
-                       qcom,remote-pid = <1>;
-                       mboxes = <&apcs_glb 16>;
-
-                       label = "wcss";
-               };
-       };
-
        reserved-memory {
                #address-cells = <2>;
                #size-cells = <2>;
                                compatible = "qcom,rpmcc-qcs404";
                                #clock-cells = <1>;
                        };
+
+                       rpmpd: power-controller {
+                               compatible = "qcom,qcs404-rpmpd";
+                               #power-domain-cells = <1>;
+                               operating-points-v2 = <&rpmpd_opp_table>;
+
+                               rpmpd_opp_table: opp-table {
+                                       compatible = "operating-points-v2";
+
+                                       rpmpd_opp_ret: opp1 {
+                                               opp-level = <16>;
+                                       };
+
+                                       rpmpd_opp_ret_plus: opp2 {
+                                               opp-level = <32>;
+                                       };
+
+                                       rpmpd_opp_min_svs: opp3 {
+                                               opp-level = <48>;
+                                       };
+
+                                       rpmpd_opp_low_svs: opp4 {
+                                               opp-level = <64>;
+                                       };
+
+                                       rpmpd_opp_svs: opp5 {
+                                               opp-level = <128>;
+                                       };
+
+                                       rpmpd_opp_svs_plus: opp6 {
+                                               opp-level = <192>;
+                                       };
+
+                                       rpmpd_opp_nom: opp7 {
+                                               opp-level = <256>;
+                                       };
+
+                                       rpmpd_opp_nom_plus: opp8 {
+                                               opp-level = <320>;
+                                       };
+
+                                       rpmpd_opp_turbo: opp9 {
+                                               opp-level = <384>;
+                                       };
+
+                                       rpmpd_opp_turbo_no_cpr: opp10 {
+                                               opp-level = <416>;
+                                       };
+
+                                       rpmpd_opp_turbo_plus: opp11 {
+                                               opp-level = <512>;
+                                       };
+                               };
+                       };
                };
        };
 
                ranges = <0 0 0 0xffffffff>;
                compatible = "simple-bus";
 
+               turingcc: clock-controller@800000 {
+                       compatible = "qcom,qcs404-turingcc";
+                       reg = <0x00800000 0x30000>;
+                       clocks = <&gcc GCC_CDSP_CFG_AHB_CLK>;
+
+                       #clock-cells = <1>;
+                       #reset-cells = <1>;
+
+                       status = "disabled";
+               };
+
                rpm_msg_ram: memory@60000 {
                        compatible = "qcom,rpm-msg-ram";
                        reg = <0x00060000 0x6000>;
                };
 
+               qfprom: qfprom@a4000 {
+                       compatible = "qcom,qfprom";
+                       reg = <0x000a4000 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       tsens_caldata: caldata@d0 {
+                               reg = <0x1f8 0x14>;
+                       };
+               };
+
                rng: rng@e3000 {
                        compatible = "qcom,prng-ee";
                        reg = <0x000e3000 0x1000>;
                        clock-names = "core";
                };
 
+               tsens: thermal-sensor@4a9000 {
+                       compatible = "qcom,qcs404-tsens", "qcom,tsens-v1";
+                       reg = <0x004a9000 0x1000>, /* TM */
+                             <0x004a8000 0x1000>; /* SROT */
+                       nvmem-cells = <&tsens_caldata>;
+                       nvmem-cell-names = "calib";
+                       #qcom,sensors = <10>;
+                       #thermal-sensor-cells = <1>;
+               };
+
+               remoteproc_cdsp: remoteproc@b00000 {
+                       compatible = "qcom,qcs404-cdsp-pas";
+                       reg = <0x00b00000 0x4040>;
+
+                       interrupts-extended = <&intc GIC_SPI 229 IRQ_TYPE_EDGE_RISING>,
+                                             <&cdsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
+                                             <&cdsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
+                                             <&cdsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
+                                             <&cdsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>;
+                       interrupt-names = "wdog", "fatal", "ready",
+                                         "handover", "stop-ack";
+
+                       clocks = <&xo_board>,
+                                <&gcc GCC_CDSP_CFG_AHB_CLK>,
+                                <&gcc GCC_CDSP_TBU_CLK>,
+                                <&gcc GCC_BIMC_CDSP_CLK>,
+                                <&turingcc TURING_WRAPPER_AON_CLK>,
+                                <&turingcc TURING_Q6SS_AHBS_AON_CLK>,
+                                <&turingcc TURING_Q6SS_AHBM_AON_CLK>,
+                                <&turingcc TURING_Q6SS_Q6_AXIM_CLK>;
+                       clock-names = "xo",
+                                     "sway",
+                                     "tbu",
+                                     "bimc",
+                                     "ahb_aon",
+                                     "q6ss_slave",
+                                     "q6ss_master",
+                                     "q6_axim";
+
+                       resets = <&gcc GCC_CDSP_RESTART>;
+                       reset-names = "restart";
+
+                       qcom,halt-regs = <&tcsr 0x19004>;
+
+                       memory-region = <&cdsp_fw_mem>;
+
+                       qcom,smem-states = <&cdsp_smp2p_out 0>;
+                       qcom,smem-state-names = "stop";
+
+                       status = "disabled";
+
+                       glink-edge {
+                               interrupts = <GIC_SPI 141 IRQ_TYPE_EDGE_RISING>;
+
+                               qcom,remote-pid = <5>;
+                               mboxes = <&apcs_glb 12>;
+
+                               label = "cdsp";
+                       };
+               };
+
                tlmm: pinctrl@1000000 {
                        compatible = "qcom,qcs404-pinctrl";
                        reg = <0x01000000 0x200000>,
                        compatible = "qcom,gcc-qcs404";
                        reg = <0x01800000 0x80000>;
                        #clock-cells = <1>;
+                       #reset-cells = <1>;
 
                        assigned-clocks = <&gcc GCC_APSS_AHB_CLK_SRC>;
                        assigned-clock-rates = <19200000>;
                        reg = <0x01905000 0x20000>;
                };
 
+               tcsr: syscon@1937000 {
+                       compatible = "syscon";
+                       reg = <0x01937000 0x25000>;
+               };
+
                spmi_bus: spmi@200f000 {
                        compatible = "qcom,spmi-pmic-arb";
                        reg = <0x0200f000 0x001000>,
                        #interrupt-cells = <4>;
                };
 
+               remoteproc_wcss: remoteproc@7400000 {
+                       compatible = "qcom,qcs404-wcss-pas";
+                       reg = <0x07400000 0x4040>;
+
+                       interrupts-extended = <&intc GIC_SPI 153 IRQ_TYPE_EDGE_RISING>,
+                                             <&wcss_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
+                                             <&wcss_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
+                                             <&wcss_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
+                                             <&wcss_smp2p_in 3 IRQ_TYPE_EDGE_RISING>;
+                       interrupt-names = "wdog", "fatal", "ready",
+                                         "handover", "stop-ack";
+
+                       clocks = <&xo_board>;
+                       clock-names = "xo";
+
+                       memory-region = <&wlan_fw_mem>;
+
+                       qcom,smem-states = <&wcss_smp2p_out 0>;
+                       qcom,smem-state-names = "stop";
+
+                       status = "disabled";
+
+                       glink-edge {
+                               interrupts = <GIC_SPI 156 IRQ_TYPE_EDGE_RISING>;
+
+                               qcom,remote-pid = <1>;
+                               mboxes = <&apcs_glb 16>;
+
+                               label = "wcss";
+                       };
+               };
+
+               pcie_phy: phy@7786000 {
+                       compatible = "qcom,qcs404-pcie2-phy", "qcom,pcie2-phy";
+                       reg = <0x07786000 0xb8>;
+
+                       clocks = <&gcc GCC_PCIE_0_PIPE_CLK>;
+                       resets = <&gcc GCC_PCIEPHY_0_PHY_BCR>,
+                                <&gcc 21>;
+                       reset-names = "phy", "pipe";
+
+                       clock-output-names = "pcie_0_pipe_clk";
+                       #phy-cells = <0>;
+
+                       status = "disabled";
+               };
+
                sdcc1: sdcc@7804000 {
                        compatible = "qcom,sdhci-msm-v5";
                        reg = <0x07804000 0x1000>, <0x7805000 0x1000>;
                                status = "disabled";
                        };
                };
+
+               remoteproc_adsp: remoteproc@c700000 {
+                       compatible = "qcom,qcs404-adsp-pas";
+                       reg = <0x0c700000 0x4040>;
+
+                       interrupts-extended = <&intc GIC_SPI 293 IRQ_TYPE_EDGE_RISING>,
+                                             <&adsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
+                                             <&adsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
+                                             <&adsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
+                                             <&adsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>;
+                       interrupt-names = "wdog", "fatal", "ready",
+                                         "handover", "stop-ack";
+
+                       clocks = <&xo_board>;
+                       clock-names = "xo";
+
+                       memory-region = <&adsp_fw_mem>;
+
+                       qcom,smem-states = <&adsp_smp2p_out 0>;
+                       qcom,smem-state-names = "stop";
+
+                       status = "disabled";
+
+                       glink-edge {
+                               interrupts = <GIC_SPI 289 IRQ_TYPE_EDGE_RISING>;
+
+                               qcom,remote-pid = <2>;
+                               mboxes = <&apcs_glb 8>;
+
+                               label = "adsp";
+                       };
+               };
+
+               pcie: pci@10000000 {
+                       compatible = "qcom,pcie-qcs404", "snps,dw-pcie";
+                       reg =  <0x10000000 0xf1d>,
+                              <0x10000f20 0xa8>,
+                              <0x07780000 0x2000>,
+                              <0x10001000 0x2000>;
+                       reg-names = "dbi", "elbi", "parf", "config";
+                       device_type = "pci";
+                       linux,pci-domain = <0>;
+                       bus-range = <0x00 0xff>;
+                       num-lanes = <1>;
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+
+                       ranges = <0x81000000 0 0          0x10003000 0 0x00010000>, /* I/O */
+                                <0x82000000 0 0x10013000 0x10013000 0 0x007ed000>; /* memory */
+
+                       interrupts = <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi";
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 0x7>;
+                       interrupt-map = <0 0 0 1 &intc GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
+                                       <0 0 0 2 &intc GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>, /* int_b */
+                                       <0 0 0 3 &intc GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
+                                       <0 0 0 4 &intc GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
+                       clocks = <&gcc GCC_PCIE_0_CFG_AHB_CLK>,
+                                <&gcc GCC_PCIE_0_AUX_CLK>,
+                                <&gcc GCC_PCIE_0_MSTR_AXI_CLK>,
+                                <&gcc GCC_PCIE_0_SLV_AXI_CLK>;
+                       clock-names = "iface", "aux", "master_bus", "slave_bus";
+
+                       resets = <&gcc 18>,
+                                <&gcc 17>,
+                                <&gcc 15>,
+                                <&gcc 19>,
+                                <&gcc GCC_PCIE_0_BCR>,
+                                <&gcc 16>;
+                       reset-names = "axi_m",
+                                     "axi_s",
+                                     "axi_m_sticky",
+                                     "pipe_sticky",
+                                     "pwr",
+                                     "ahb";
+
+                       phys = <&pcie_phy>;
+                       phy-names = "pciephy";
+
+                       status = "disabled";
+               };
        };
 
        timer {
                        #interrupt-cells = <2>;
                };
        };
+
+       thermal-zones {
+               aoss-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens 0>;
+
+                       trips {
+                               aoss_alert0: trip-point@0 {
+                                       temperature = <105000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               q6-hvx-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens 1>;
+
+                       trips {
+                               q6_hvx_alert0: trip-point@0 {
+                                       temperature = <105000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               lpass-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens 2>;
+
+                       trips {
+                               lpass_alert0: trip-point@0 {
+                                       temperature = <105000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               wlan-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens 3>;
+
+                       trips {
+                               wlan_alert0: trip-point@0 {
+                                       temperature = <105000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               cluster-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens 4>;
+
+                       trips {
+                               cluster_alert0: trip-point@0 {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                               cluster_alert1: trip-point@1 {
+                                       temperature = <105000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                               cluster_crit: cluster_crit {
+                                       temperature = <120000>;
+                                       hysteresis = <2000>;
+                                       type = "critical";
+                               };
+                       };
+                       cooling-maps {
+                               map0 {
+                                       trip = <&cluster_alert1>;
+                                       cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                      <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                      <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                      <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+
+               cpu0-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens 5>;
+
+                       trips {
+                               cpu0_alert0: trip-point@0 {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                               cpu0_alert1: trip-point@1 {
+                                       temperature = <105000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                               cpu0_crit: cpu_crit {
+                                       temperature = <120000>;
+                                       hysteresis = <2000>;
+                                       type = "critical";
+                               };
+                       };
+                       cooling-maps {
+                               map0 {
+                                       trip = <&cpu0_alert1>;
+                                       cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                      <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                      <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                      <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+
+               cpu1-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens 6>;
+
+                       trips {
+                               cpu1_alert0: trip-point@0 {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                               cpu1_alert1: trip-point@1 {
+                                       temperature = <105000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                               cpu1_crit: cpu_crit {
+                                       temperature = <120000>;
+                                       hysteresis = <2000>;
+                                       type = "critical";
+                               };
+                       };
+                       cooling-maps {
+                               map0 {
+                                       trip = <&cpu1_alert1>;
+                                       cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                      <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                      <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                      <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+
+               cpu2-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens 7>;
+
+                       trips {
+                               cpu2_alert0: trip-point@0 {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                               cpu2_alert1: trip-point@1 {
+                                       temperature = <105000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                               cpu2_crit: cpu_crit {
+                                       temperature = <120000>;
+                                       hysteresis = <2000>;
+                                       type = "critical";
+                               };
+                       };
+                       cooling-maps {
+                               map0 {
+                                       trip = <&cpu2_alert1>;
+                                       cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                      <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                      <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                      <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+
+               cpu3-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens 8>;
+
+                       trips {
+                               cpu3_alert0: trip-point@0 {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                               cpu3_alert1: trip-point@1 {
+                                       temperature = <105000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                               cpu3_crit: cpu_crit {
+                                       temperature = <120000>;
+                                       hysteresis = <2000>;
+                                       type = "critical";
+                               };
+                       };
+                       cooling-maps {
+                               map0 {
+                                       trip = <&cpu3_alert1>;
+                                       cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                      <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                      <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                      <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+
+               gpu-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens 9>;
+
+                       trips {
+                               gpu_alert0: trip-point@0 {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+       };
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cheza-r1.dts b/arch/arm64/boot/dts/qcom/sdm845-cheza-r1.dts
new file mode 100644 (file)
index 0000000..bd7c25b
--- /dev/null
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Cheza board device tree source
+ *
+ * Copyright 2018 Google LLC.
+ */
+
+/dts-v1/;
+
+#include "sdm845-cheza.dtsi"
+
+/ {
+       model = "Google Cheza (rev1)";
+       compatible = "google,cheza-rev1", "qcom,sdm845";
+
+       /*
+        * FIXED REGULATORS (not in sdm845-cheza.dtsi) - parents above children
+        */
+
+       /*
+        * NOTE: Technically pp3500_a is not the exact same signal as
+        * pp3500_a_vbob (there's a load switch between them and the EC can
+        * control pp3500_a via "en_pp3300_a"), but from the AP's point of
+        * view they are the same.
+        */
+       pp3500_a:
+       pp3500_a_vbob: pp3500-a-vbob-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vreg_bob";
+
+               /*
+                * Comes on automatically when pp5000_ldo comes on, which
+                * comes on automatically when ppvar_sys comes on
+                */
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <3500000>;
+               regulator-max-microvolt = <3500000>;
+
+               vin-supply = <&ppvar_sys>;
+       };
+
+       pp3300_dx_edp: pp3300-dx-edp-regulator {
+               /* Yes, it's really 3.5 despite the name of the signal */
+               regulator-min-microvolt = <3500000>;
+               regulator-max-microvolt = <3500000>;
+
+               vin-supply = <&pp3500_a>;
+       };
+};
+
+/* FIXED REGULATOR OVERRIDES (modifications to sdm845-cheza.dtsi) */
+
+/*
+ * L19 and L28 technically go to 3.3V, but most boards have old AOP firmware
+ * that limits them to 3.0, and trying to run at 3.3V with that old firmware
+ * prevents the system from booting.
+ */
+&src_pp3000_l19a {
+       regulator-min-microvolt = <3008000>;
+       regulator-max-microvolt = <3008000>;
+};
+
+&src_pp3300_l22a {
+       /delete-property/regulator-boot-on;
+       /delete-property/regulator-always-on;
+};
+
+&src_pp3300_l28a {
+       regulator-min-microvolt = <3008000>;
+       regulator-max-microvolt = <3008000>;
+};
+
+&src_vreg_bob {
+       regulator-min-microvolt = <3500000>;
+       regulator-max-microvolt = <3500000>;
+       vin-supply = <&pp3500_a_vbob>;
+};
+
+/*
+ * NON-REGULATOR OVERRIDES
+ * (modifications to sdm845-cheza.dtsi) - alphabetized by dtsi label
+ */
+
+/* PINCTRL - board-specific pinctrl */
+
+&tlmm {
+       gpio-line-names = "AP_SPI_FP_MISO",
+                         "AP_SPI_FP_MOSI",
+                         "AP_SPI_FP_CLK",
+                         "AP_SPI_FP_CS_L",
+                         "UART_AP_TX_DBG_RX",
+                         "UART_DBG_TX_AP_RX",
+                         "",
+                         "FP_RST_L",
+                         "FCAM_EN",
+                         "",
+                         "EDP_BRIJ_IRQ",
+                         "EC_IN_RW_ODL",
+                         "",
+                         "RCAM_MCLK",
+                         "FCAM_MCLK",
+                         "",
+                         "RCAM_EN",
+                         "CCI0_SDA",
+                         "CCI0_SCL",
+                         "CCI1_SDA",
+                         "CCI1_SCL",
+                         "FCAM_RST_L",
+                         "",
+                         "PEN_RST_L",
+                         "PEN_IRQ_L",
+                         "",
+                         "RCAM_VSYNC",
+                         "ESIM_MISO",
+                         "ESIM_MOSI",
+                         "ESIM_CLK",
+                         "ESIM_CS_L",
+                         "AP_PEN_1V8_SDA",
+                         "AP_PEN_1V8_SCL",
+                         "AP_TS_I2C_SDA",
+                         "AP_TS_I2C_SCL",
+                         "RCAM_RST_L",
+                         "",
+                         "AP_EDP_BKLTEN",
+                         "AP_BRD_ID1",
+                         "BOOT_CONFIG_4",
+                         "AMP_IRQ_L",
+                         "EDP_BRIJ_I2C_SDA",
+                         "EDP_BRIJ_I2C_SCL",
+                         "EN_PP3300_DX_EDP",
+                         "SD_CD_ODL",
+                         "BT_UART_RTS",
+                         "BT_UART_CTS",
+                         "BT_UART_RXD",
+                         "BT_UART_TXD",
+                         "AMP_I2C_SDA",
+                         "AMP_I2C_SCL",
+                         "AP_BRD_ID3",
+                         "",
+                         "AP_EC_SPI_CLK",
+                         "AP_EC_SPI_CS_L",
+                         "AP_EC_SPI_MISO",
+                         "AP_EC_SPI_MOSI",
+                         "FORCED_USB_BOOT",
+                         "AMP_BCLK",
+                         "AMP_LRCLK",
+                         "AMP_DOUT",
+                         "AMP_DIN",
+                         "AP_BRD_ID2",
+                         "PEN_PDCT_L",
+                         "HP_MCLK",
+                         "HP_BCLK",
+                         "HP_LRCLK",
+                         "HP_DOUT",
+                         "HP_DIN",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "BT_SLIMBUS_DATA",
+                         "BT_SLIMBUS_CLK",
+                         "AMP_RESET_L",
+                         "",
+                         "FCAM_VSYNC",
+                         "",
+                         "AP_SKU_ID1",
+                         "EC_WOV_BCLK",
+                         "EC_WOV_LRCLK",
+                         "EC_WOV_DOUT",
+                         "",
+                         "",
+                         "AP_H1_SPI_MISO",
+                         "AP_H1_SPI_MOSI",
+                         "AP_H1_SPI_CLK",
+                         "AP_H1_SPI_CS_L",
+                         "",
+                         "AP_SPI_CS0_L",
+                         "AP_SPI_MOSI",
+                         "AP_SPI_MISO",
+                         "",
+                         "",
+                         "AP_SPI_CLK",
+                         "",
+                         "RFFE6_CLK",
+                         "RFFE6_DATA",
+                         "BOOT_CONFIG_1",
+                         "BOOT_CONFIG_2",
+                         "BOOT_CONFIG_0",
+                         "EDP_BRIJ_EN",
+                         "",
+                         "USB_HS_TX_EN",
+                         "UIM2_DATA",
+                         "UIM2_CLK",
+                         "UIM2_RST",
+                         "UIM2_PRESENT",
+                         "UIM1_DATA",
+                         "UIM1_CLK",
+                         "UIM1_RST",
+                         "",
+                         "AP_SKU_ID2",
+                         "SDM_GRFC_8",
+                         "SDM_GRFC_9",
+                         "AP_RST_REQ",
+                         "HP_IRQ",
+                         "TS_RESET_L",
+                         "PEN_EJECT_ODL",
+                         "HUB_RST_L",
+                         "FP_TO_AP_IRQ",
+                         "AP_EC_INT_L",
+                         "",
+                         "",
+                         "TS_INT_L",
+                         "AP_SUSPEND_L",
+                         "SDM_GRFC_3",
+                         "",
+                         "H1_AP_INT_ODL",
+                         "QLINK_REQ",
+                         "QLINK_EN",
+                         "SDM_GRFC_2",
+                         "BOOT_CONFIG_3",
+                         "WMSS_RESET_L",
+                         "SDM_GRFC_0",
+                         "SDM_GRFC_1",
+                         "RFFE3_DATA",
+                         "RFFE3_CLK",
+                         "RFFE4_DATA",
+                         "RFFE4_CLK",
+                         "RFFE5_DATA",
+                         "RFFE5_CLK",
+                         "GNSS_EN",
+                         "WCI2_LTE_COEX_RXD",
+                         "WCI2_LTE_COEX_TXD",
+                         "AP_RAM_ID1",
+                         "AP_RAM_ID2",
+                         "RFFE1_DATA",
+                         "RFFE1_CLK";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cheza-r2.dts b/arch/arm64/boot/dts/qcom/sdm845-cheza-r2.dts
new file mode 100644 (file)
index 0000000..2b72305
--- /dev/null
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Cheza board device tree source
+ *
+ * Copyright 2018 Google LLC.
+ */
+
+/dts-v1/;
+
+#include "sdm845-cheza.dtsi"
+
+/ {
+       model = "Google Cheza (rev2)";
+       compatible = "google,cheza-rev2", "qcom,sdm845";
+
+       /*
+        * FIXED REGULATORS (not in sdm845-cheza.dtsi) - parents above children
+        */
+
+       /*
+        * NOTE: Technically pp3500_a is not the exact same signal as
+        * pp3500_a_vbob (there's a load switch between them and the EC can
+        * control pp3500_a via "en_pp3300_a"), but from the AP's point of
+        * view they are the same.
+        */
+       pp3500_a:
+       pp3500_a_vbob: pp3500-a-vbob-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vreg_bob";
+
+               /*
+                * Comes on automatically when pp5000_ldo comes on, which
+                * comes on automatically when ppvar_sys comes on
+                */
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <3500000>;
+               regulator-max-microvolt = <3500000>;
+
+               vin-supply = <&ppvar_sys>;
+       };
+
+       pp3300_dx_edp: pp3300-dx-edp-regulator {
+               /* Yes, it's really 3.5 despite the name of the signal */
+               regulator-min-microvolt = <3500000>;
+               regulator-max-microvolt = <3500000>;
+
+               vin-supply = <&pp3500_a>;
+       };
+};
+
+/* FIXED REGULATOR OVERRIDES (modifications to sdm845-cheza.dtsi) */
+
+/*
+ * L19 and L28 technically go to 3.3V, but most boards have old AOP firmware
+ * that limits them to 3.0, and trying to run at 3.3V with that old firmware
+ * prevents the system from booting.
+ */
+&src_pp3000_l19a {
+       regulator-min-microvolt = <3008000>;
+       regulator-max-microvolt = <3008000>;
+};
+
+&src_pp3300_l22a {
+       /delete-property/regulator-boot-on;
+       /delete-property/regulator-always-on;
+};
+
+&src_pp3300_l28a {
+       regulator-min-microvolt = <3008000>;
+       regulator-max-microvolt = <3008000>;
+};
+
+&src_vreg_bob {
+       regulator-min-microvolt = <3500000>;
+       regulator-max-microvolt = <3500000>;
+       vin-supply = <&pp3500_a_vbob>;
+};
+
+/*
+ * NON-REGULATOR OVERRIDES
+ * (modifications to sdm845-cheza.dtsi) - alphabetized by dtsi label
+ */
+
+/* PINCTRL - board-specific pinctrl */
+
+&tlmm {
+       gpio-line-names = "AP_SPI_FP_MISO",
+                         "AP_SPI_FP_MOSI",
+                         "AP_SPI_FP_CLK",
+                         "AP_SPI_FP_CS_L",
+                         "UART_AP_TX_DBG_RX",
+                         "UART_DBG_TX_AP_RX",
+                         "BRIJ_SUSPEND",
+                         "FP_RST_L",
+                         "FCAM_EN",
+                         "",
+                         "EDP_BRIJ_IRQ",
+                         "EC_IN_RW_ODL",
+                         "",
+                         "RCAM_MCLK",
+                         "FCAM_MCLK",
+                         "",
+                         "RCAM_EN",
+                         "CCI0_SDA",
+                         "CCI0_SCL",
+                         "CCI1_SDA",
+                         "CCI1_SCL",
+                         "FCAM_RST_L",
+                         "FPMCU_BOOT0",
+                         "PEN_RST_L",
+                         "PEN_IRQ_L",
+                         "FPMCU_SEL_OD",
+                         "RCAM_VSYNC",
+                         "ESIM_MISO",
+                         "ESIM_MOSI",
+                         "ESIM_CLK",
+                         "ESIM_CS_L",
+                         "AP_PEN_1V8_SDA",
+                         "AP_PEN_1V8_SCL",
+                         "AP_TS_I2C_SDA",
+                         "AP_TS_I2C_SCL",
+                         "RCAM_RST_L",
+                         "",
+                         "AP_EDP_BKLTEN",
+                         "AP_BRD_ID1",
+                         "BOOT_CONFIG_4",
+                         "AMP_IRQ_L",
+                         "EDP_BRIJ_I2C_SDA",
+                         "EDP_BRIJ_I2C_SCL",
+                         "EN_PP3300_DX_EDP",
+                         "SD_CD_ODL",
+                         "BT_UART_RTS",
+                         "BT_UART_CTS",
+                         "BT_UART_RXD",
+                         "BT_UART_TXD",
+                         "AMP_I2C_SDA",
+                         "AMP_I2C_SCL",
+                         "AP_BRD_ID3",
+                         "",
+                         "AP_EC_SPI_CLK",
+                         "AP_EC_SPI_CS_L",
+                         "AP_EC_SPI_MISO",
+                         "AP_EC_SPI_MOSI",
+                         "FORCED_USB_BOOT",
+                         "AMP_BCLK",
+                         "AMP_LRCLK",
+                         "AMP_DOUT",
+                         "AMP_DIN",
+                         "AP_BRD_ID2",
+                         "PEN_PDCT_L",
+                         "HP_MCLK",
+                         "HP_BCLK",
+                         "HP_LRCLK",
+                         "HP_DOUT",
+                         "HP_DIN",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "BT_SLIMBUS_DATA",
+                         "BT_SLIMBUS_CLK",
+                         "AMP_RESET_L",
+                         "",
+                         "FCAM_VSYNC",
+                         "",
+                         "AP_SKU_ID1",
+                         "EC_WOV_BCLK",
+                         "EC_WOV_LRCLK",
+                         "EC_WOV_DOUT",
+                         "",
+                         "",
+                         "AP_H1_SPI_MISO",
+                         "AP_H1_SPI_MOSI",
+                         "AP_H1_SPI_CLK",
+                         "AP_H1_SPI_CS_L",
+                         "",
+                         "AP_SPI_CS0_L",
+                         "AP_SPI_MOSI",
+                         "AP_SPI_MISO",
+                         "",
+                         "",
+                         "AP_SPI_CLK",
+                         "",
+                         "RFFE6_CLK",
+                         "RFFE6_DATA",
+                         "BOOT_CONFIG_1",
+                         "BOOT_CONFIG_2",
+                         "BOOT_CONFIG_0",
+                         "EDP_BRIJ_EN",
+                         "",
+                         "USB_HS_TX_EN",
+                         "UIM2_DATA",
+                         "UIM2_CLK",
+                         "UIM2_RST",
+                         "UIM2_PRESENT",
+                         "UIM1_DATA",
+                         "UIM1_CLK",
+                         "UIM1_RST",
+                         "",
+                         "AP_SKU_ID2",
+                         "SDM_GRFC_8",
+                         "SDM_GRFC_9",
+                         "AP_RST_REQ",
+                         "HP_IRQ",
+                         "TS_RESET_L",
+                         "PEN_EJECT_ODL",
+                         "HUB_RST_L",
+                         "FP_TO_AP_IRQ",
+                         "AP_EC_INT_L",
+                         "",
+                         "",
+                         "TS_INT_L",
+                         "AP_SUSPEND_L",
+                         "SDM_GRFC_3",
+                         "",
+                         "H1_AP_INT_ODL",
+                         "QLINK_REQ",
+                         "QLINK_EN",
+                         "SDM_GRFC_2",
+                         "BOOT_CONFIG_3",
+                         "WMSS_RESET_L",
+                         "SDM_GRFC_0",
+                         "SDM_GRFC_1",
+                         "RFFE3_DATA",
+                         "RFFE3_CLK",
+                         "RFFE4_DATA",
+                         "RFFE4_CLK",
+                         "RFFE5_DATA",
+                         "RFFE5_CLK",
+                         "GNSS_EN",
+                         "WCI2_LTE_COEX_RXD",
+                         "WCI2_LTE_COEX_TXD",
+                         "AP_RAM_ID1",
+                         "AP_RAM_ID2",
+                         "RFFE1_DATA",
+                         "RFFE1_CLK";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cheza-r3.dts b/arch/arm64/boot/dts/qcom/sdm845-cheza-r3.dts
new file mode 100644 (file)
index 0000000..1ba67be
--- /dev/null
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Cheza board device tree source
+ *
+ * Copyright 2018 Google LLC.
+ */
+
+/dts-v1/;
+
+#include "sdm845-cheza.dtsi"
+
+/ {
+       model = "Google Cheza (rev3+)";
+       compatible = "google,cheza", "qcom,sdm845";
+};
+
+/* PINCTRL - board-specific pinctrl */
+
+&tlmm {
+       gpio-line-names = "AP_SPI_FP_MISO",
+                         "AP_SPI_FP_MOSI",
+                         "AP_SPI_FP_CLK",
+                         "AP_SPI_FP_CS_L",
+                         "UART_AP_TX_DBG_RX",
+                         "UART_DBG_TX_AP_RX",
+                         "BRIJ_SUSPEND",
+                         "FP_RST_L",
+                         "FCAM_EN",
+                         "",
+                         "EDP_BRIJ_IRQ",
+                         "EC_IN_RW_ODL",
+                         "",
+                         "RCAM_MCLK",
+                         "FCAM_MCLK",
+                         "",
+                         "RCAM_EN",
+                         "CCI0_SDA",
+                         "CCI0_SCL",
+                         "CCI1_SDA",
+                         "CCI1_SCL",
+                         "FCAM_RST_L",
+                         "FPMCU_BOOT0",
+                         "PEN_RST_L",
+                         "PEN_IRQ_L",
+                         "FPMCU_SEL_OD",
+                         "RCAM_VSYNC",
+                         "ESIM_MISO",
+                         "ESIM_MOSI",
+                         "ESIM_CLK",
+                         "ESIM_CS_L",
+                         "AP_PEN_1V8_SDA",
+                         "AP_PEN_1V8_SCL",
+                         "AP_TS_I2C_SDA",
+                         "AP_TS_I2C_SCL",
+                         "RCAM_RST_L",
+                         "",
+                         "AP_EDP_BKLTEN",
+                         "AP_BRD_ID0",
+                         "BOOT_CONFIG_4",
+                         "AMP_IRQ_L",
+                         "EDP_BRIJ_I2C_SDA",
+                         "EDP_BRIJ_I2C_SCL",
+                         "EN_PP3300_DX_EDP",
+                         "SD_CD_ODL",
+                         "BT_UART_RTS",
+                         "BT_UART_CTS",
+                         "BT_UART_RXD",
+                         "BT_UART_TXD",
+                         "AMP_I2C_SDA",
+                         "AMP_I2C_SCL",
+                         "AP_BRD_ID2",
+                         "",
+                         "AP_EC_SPI_CLK",
+                         "AP_EC_SPI_CS_L",
+                         "AP_EC_SPI_MISO",
+                         "AP_EC_SPI_MOSI",
+                         "FORCED_USB_BOOT",
+                         "AMP_BCLK",
+                         "AMP_LRCLK",
+                         "AMP_DOUT",
+                         "AMP_DIN",
+                         "AP_BRD_ID1",
+                         "PEN_PDCT_L",
+                         "HP_MCLK",
+                         "HP_BCLK",
+                         "HP_LRCLK",
+                         "HP_DOUT",
+                         "HP_DIN",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "BT_SLIMBUS_DATA",
+                         "BT_SLIMBUS_CLK",
+                         "AMP_RESET_L",
+                         "",
+                         "FCAM_VSYNC",
+                         "",
+                         "AP_SKU_ID0",
+                         "EC_WOV_BCLK",
+                         "EC_WOV_LRCLK",
+                         "EC_WOV_DOUT",
+                         "",
+                         "",
+                         "AP_H1_SPI_MISO",
+                         "AP_H1_SPI_MOSI",
+                         "AP_H1_SPI_CLK",
+                         "AP_H1_SPI_CS_L",
+                         "",
+                         "AP_SPI_CS0_L",
+                         "AP_SPI_MOSI",
+                         "AP_SPI_MISO",
+                         "",
+                         "",
+                         "AP_SPI_CLK",
+                         "",
+                         "RFFE6_CLK",
+                         "RFFE6_DATA",
+                         "BOOT_CONFIG_1",
+                         "BOOT_CONFIG_2",
+                         "BOOT_CONFIG_0",
+                         "EDP_BRIJ_EN",
+                         "",
+                         "USB_HS_TX_EN",
+                         "UIM2_DATA",
+                         "UIM2_CLK",
+                         "UIM2_RST",
+                         "UIM2_PRESENT",
+                         "UIM1_DATA",
+                         "UIM1_CLK",
+                         "UIM1_RST",
+                         "",
+                         "AP_SKU_ID1",
+                         "SDM_GRFC_8",
+                         "SDM_GRFC_9",
+                         "AP_RST_REQ",
+                         "HP_IRQ",
+                         "TS_RESET_L",
+                         "PEN_EJECT_ODL",
+                         "HUB_RST_L",
+                         "FP_TO_AP_IRQ",
+                         "AP_EC_INT_L",
+                         "",
+                         "",
+                         "TS_INT_L",
+                         "AP_SUSPEND_L",
+                         "SDM_GRFC_3",
+                         /*
+                          * AP_FLASH_WP_L is crossystem ABI. Rev3 schematics
+                          * call it BIOS_FLASH_WP_R_L.
+                          */
+                         "AP_FLASH_WP_L",
+                         "H1_AP_INT_ODL",
+                         "QLINK_REQ",
+                         "QLINK_EN",
+                         "SDM_GRFC_2",
+                         "BOOT_CONFIG_3",
+                         "WMSS_RESET_L",
+                         "SDM_GRFC_0",
+                         "SDM_GRFC_1",
+                         "RFFE3_DATA",
+                         "RFFE3_CLK",
+                         "RFFE4_DATA",
+                         "RFFE4_CLK",
+                         "RFFE5_DATA",
+                         "RFFE5_CLK",
+                         "GNSS_EN",
+                         "WCI2_LTE_COEX_RXD",
+                         "WCI2_LTE_COEX_TXD",
+                         "AP_RAM_ID0",
+                         "AP_RAM_ID1",
+                         "RFFE1_DATA",
+                         "RFFE1_CLK";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi
new file mode 100644 (file)
index 0000000..1ebbd56
--- /dev/null
@@ -0,0 +1,1326 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Cheza device tree source (common between revisions)
+ *
+ * Copyright 2018 Google LLC.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+#include "sdm845.dtsi"
+
+/* PMICs depend on spmi_bus label and so must come after SoC */
+#include "pm8005.dtsi"
+#include "pm8998.dtsi"
+
+/ {
+       aliases {
+               bluetooth0 = &bluetooth;
+               hsuart0 = &uart6;
+               serial0 = &uart9;
+               wifi0 = &wifi;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       backlight: backlight {
+               compatible = "pwm-backlight";
+               pwms = <&cros_ec_pwm 0>;
+               enable-gpios = <&tlmm 37 GPIO_ACTIVE_HIGH>;
+               power-supply = <&ppvar_sys>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&ap_edp_bklten>;
+       };
+
+       /* FIXED REGULATORS - parents above children */
+
+       /* This is the top level supply and variable voltage */
+       ppvar_sys: ppvar-sys-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "ppvar_sys";
+               regulator-always-on;
+               regulator-boot-on;
+       };
+
+       /* This divides ppvar_sys by 2, so voltage is variable */
+       src_vph_pwr: src-vph-pwr-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "src_vph_pwr";
+
+               /* EC turns on with switchcap_on_l; always on for AP */
+               regulator-always-on;
+               regulator-boot-on;
+
+               vin-supply = <&ppvar_sys>;
+       };
+
+       pp5000_a: pp5000-a-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "pp5000_a";
+
+               /* EC turns on with en_pp5000_a; always on for AP */
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+
+               vin-supply = <&ppvar_sys>;
+       };
+
+       src_vreg_bob: src-vreg-bob-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "src_vreg_bob";
+
+               /* EC turns on with vbob_en; always on for AP */
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <3600000>;
+               regulator-max-microvolt = <3600000>;
+
+               vin-supply = <&ppvar_sys>;
+       };
+
+       pp3300_dx_edp: pp3300-dx-edp-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "pp3300_dx_edp";
+
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+
+               gpio = <&tlmm 43 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               pinctrl-names = "default";
+               pinctrl-0 = <&en_pp3300_dx_edp>;
+       };
+
+       /*
+        * Apparently RPMh does not provide support for PM8998 S4 because it
+        * is always-on; model it as a fixed regulator.
+        */
+       src_pp1800_s4a: pm8998-smps4 {
+               compatible = "regulator-fixed";
+               regulator-name = "src_pp1800_s4a";
+
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+
+               regulator-always-on;
+               regulator-boot-on;
+
+               vin-supply = <&src_vph_pwr>;
+       };
+
+       /* BOARD-SPECIFIC TOP LEVEL NODES */
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pen_eject_odl>;
+
+               pen-insert {
+                       label = "Pen Insert";
+                       /* Insert = low, eject = high */
+                       gpios = <&tlmm 119 GPIO_ACTIVE_LOW>;
+                       linux,code = <SW_PEN_INSERTED>;
+                       linux,input-type = <EV_SW>;
+                       wakeup-source;
+               };
+       };
+
+       panel: panel {
+               compatible ="innolux,p120zdg-bf1";
+               power-supply = <&pp3300_dx_edp>;
+               backlight = <&backlight>;
+               no-hpd;
+
+               ports {
+                       panel_in: port {
+                               panel_in_edp: endpoint {
+                                       remote-endpoint = <&sn65dsi86_out>;
+                               };
+                       };
+               };
+       };
+};
+
+/*
+ * Reserved memory changes
+ *
+ * Putting this all together (out of order with the rest of the file) to keep
+ * all modifications to the memory map (from sdm845.dtsi) in one place.
+ */
+
+/*
+ * Our mpss_region is 8MB bigger than the default one and that conflicts
+ * with venus_mem and cdsp_mem.
+ *
+ * For venus_mem we'll delete and re-create at a different address.
+ *
+ * cdsp_mem isn't used on cheza right now so we won't bother re-creating it; but
+ * that also means we need to delete cdsp_pas.
+ */
+/delete-node/ &venus_mem;
+/delete-node/ &cdsp_mem;
+/delete-node/ &cdsp_pas;
+
+/* Increase the size from 120 MB to 128 MB */
+&mpss_region {
+       reg = <0 0x8e000000 0 0x8000000>;
+};
+
+/* Increase the size from 2MB to 8MB */
+&rmtfs_mem {
+       reg = <0 0x88f00000 0 0x800000>;
+};
+
+/ {
+       reserved-memory {
+               venus_mem: memory@96000000 {
+                       reg = <0 0x96000000 0 0x500000>;
+                       no-map;
+               };
+       };
+};
+
+&qspi {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&qspi_clk &qspi_cs0 &qspi_data01>;
+
+       flash@0 {
+               compatible = "jedec,spi-nor";
+               reg = <0>;
+
+               /*
+                * In theory chip supports up to 104 MHz and controller up
+                * to 80 MHz, but above 25 MHz wasn't reliable so we'll use
+                * that for now.  b:117440651
+                */
+               spi-max-frequency = <25000000>;
+               spi-tx-bus-width = <2>;
+               spi-rx-bus-width = <2>;
+       };
+};
+
+
+&apps_rsc {
+       pm8998-rpmh-regulators {
+               compatible = "qcom,pm8998-rpmh-regulators";
+               qcom,pmic-id = "a";
+
+               vdd-s1-supply = <&src_vph_pwr>;
+               vdd-s2-supply = <&src_vph_pwr>;
+               vdd-s3-supply = <&src_vph_pwr>;
+               vdd-s4-supply = <&src_vph_pwr>;
+               vdd-s5-supply = <&src_vph_pwr>;
+               vdd-s6-supply = <&src_vph_pwr>;
+               vdd-s7-supply = <&src_vph_pwr>;
+               vdd-s8-supply = <&src_vph_pwr>;
+               vdd-s9-supply = <&src_vph_pwr>;
+               vdd-s10-supply = <&src_vph_pwr>;
+               vdd-s11-supply = <&src_vph_pwr>;
+               vdd-s12-supply = <&src_vph_pwr>;
+               vdd-s13-supply = <&src_vph_pwr>;
+               vdd-l1-l27-supply = <&src_pp1025_s7a>;
+               vdd-l2-l8-l17-supply = <&src_pp1350_s3a>;
+               vdd-l3-l11-supply = <&src_pp1025_s7a>;
+               vdd-l4-l5-supply = <&src_pp1025_s7a>;
+               vdd-l6-supply = <&src_vph_pwr>;
+               vdd-l7-l12-l14-l15-supply = <&src_pp2040_s5a>;
+               vdd-l9-supply = <&src_pp2040_s5a>;
+               vdd-l10-l23-l25-supply = <&src_vreg_bob>;
+               vdd-l13-l19-l21-supply = <&src_vreg_bob>;
+               vdd-l16-l28-supply = <&src_vreg_bob>;
+               vdd-l18-l22-supply = <&src_vreg_bob>;
+               vdd-l20-l24-supply = <&src_vreg_bob>;
+               vdd-l26-supply = <&src_pp1350_s3a>;
+               vin-lvs-1-2-supply = <&src_pp1800_s4a>;
+
+               src_pp1125_s2a: smps2 {
+                       regulator-min-microvolt = <1100000>;
+                       regulator-max-microvolt = <1100000>;
+               };
+
+               src_pp1350_s3a: smps3 {
+                       regulator-min-microvolt = <1352000>;
+                       regulator-max-microvolt = <1352000>;
+               };
+
+               src_pp2040_s5a: smps5 {
+                       regulator-min-microvolt = <1904000>;
+                       regulator-max-microvolt = <2040000>;
+               };
+
+               src_pp1025_s7a: smps7 {
+                       regulator-min-microvolt = <900000>;
+                       regulator-max-microvolt = <1028000>;
+               };
+
+               vdd_qusb_hs0:
+               vdda_hp_pcie_core:
+               vdda_mipi_csi0_0p9:
+               vdda_mipi_csi1_0p9:
+               vdda_mipi_csi2_0p9:
+               vdda_mipi_dsi0_pll:
+               vdda_mipi_dsi1_pll:
+               vdda_qlink_lv:
+               vdda_qlink_lv_ck:
+               vdda_qrefs_0p875:
+               vdda_pcie_core:
+               vdda_pll_cc_ebi01:
+               vdda_pll_cc_ebi23:
+               vdda_sp_sensor:
+               vdda_ufs1_core:
+               vdda_ufs2_core:
+               vdda_usb1_ss_core:
+               vdda_usb2_ss_core:
+               src_pp875_l1a: ldo1 {
+                       regulator-min-microvolt = <880000>;
+                       regulator-max-microvolt = <880000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vddpx_10:
+               src_pp1200_l2a: ldo2 {
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1200000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+
+                       /* TODO: why??? */
+                       regulator-always-on;
+               };
+
+               pp1000_l3a_sdr845: ldo3 {
+                       regulator-min-microvolt = <1000000>;
+                       regulator-max-microvolt = <1000000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vdd_wcss_cx:
+               vdd_wcss_mx:
+               vdda_wcss_pll:
+               src_pp800_l5a: ldo5 {
+                       regulator-min-microvolt = <800000>;
+                       regulator-max-microvolt = <800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vddpx_13:
+               src_pp1800_l6a: ldo6 {
+                       regulator-min-microvolt = <1856000>;
+                       regulator-max-microvolt = <1856000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               pp1800_l7a_wcn3990: ldo7 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               src_pp1200_l8a: ldo8 {
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1248000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               pp1800_dx_pen:
+               src_pp1800_l9a: ldo9 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               src_pp1800_l10a: ldo10 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               pp1000_l11a_sdr845: ldo11 {
+                       regulator-min-microvolt = <1000000>;
+                       regulator-max-microvolt = <1048000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vdd_qfprom:
+               vdd_qfprom_sp:
+               vdda_apc1_cs_1p8:
+               vdda_gfx_cs_1p8:
+               vdda_qrefs_1p8:
+               vdda_qusb_hs0_1p8:
+               vddpx_11:
+               src_pp1800_l12a: ldo12 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vddpx_2:
+               src_pp2950_l13a: ldo13 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <2960000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               src_pp1800_l14a: ldo14 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               src_pp1800_l15a: ldo15 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               pp2700_l16a: ldo16 {
+                       regulator-min-microvolt = <2704000>;
+                       regulator-max-microvolt = <2704000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               src_pp1300_l17a: ldo17 {
+                       regulator-min-microvolt = <1304000>;
+                       regulator-max-microvolt = <1304000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               pp2700_l18a: ldo18 {
+                       regulator-min-microvolt = <2704000>;
+                       regulator-max-microvolt = <2960000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               /*
+                * NOTE: this rail should have been called
+                * src_pp3300_l19a in the schematic
+                */
+               src_pp3000_l19a: ldo19 {
+                       regulator-min-microvolt = <3304000>;
+                       regulator-max-microvolt = <3304000>;
+
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               src_pp2950_l20a: ldo20 {
+                       regulator-min-microvolt = <2704000>;
+                       regulator-max-microvolt = <2960000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               src_pp2950_l21a: ldo21 {
+                       regulator-min-microvolt = <2704000>;
+                       regulator-max-microvolt = <2960000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               pp3300_hub:
+               src_pp3300_l22a: ldo22 {
+                       regulator-min-microvolt = <3304000>;
+                       regulator-max-microvolt = <3304000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       /*
+                        * HACK: Should add a usb hub node and driver
+                        * to turn this on and off at suspend/resume time
+                        */
+                       regulator-boot-on;
+                       regulator-always-on;
+               };
+
+               pp3300_l23a_ch1_wcn3990: ldo23 {
+                       regulator-min-microvolt = <3000000>;
+                       regulator-max-microvolt = <3312000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vdda_qusb_hs0_3p1:
+               src_pp3075_l24a: ldo24 {
+                       regulator-min-microvolt = <3088000>;
+                       regulator-max-microvolt = <3088000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               pp3300_l25a_ch0_wcn3990: ldo25 {
+                       regulator-min-microvolt = <3304000>;
+                       regulator-max-microvolt = <3304000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               pp1200_hub:
+               vdda_hp_pcie_1p2:
+               vdda_hv_ebi0:
+               vdda_hv_ebi1:
+               vdda_hv_ebi2:
+               vdda_hv_ebi3:
+               vdda_mipi_csi_1p25:
+               vdda_mipi_dsi0_1p2:
+               vdda_mipi_dsi1_1p2:
+               vdda_pcie_1p2:
+               vdda_ufs1_1p2:
+               vdda_ufs2_1p2:
+               vdda_usb1_ss_1p2:
+               vdda_usb2_ss_1p2:
+               src_pp1200_l26a: ldo26 {
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1200000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               pp3300_dx_pen:
+               src_pp3300_l28a: ldo28 {
+                       regulator-min-microvolt = <3304000>;
+                       regulator-max-microvolt = <3304000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               src_pp1800_lvs1: lvs1 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+               };
+
+               src_pp1800_lvs2: lvs2 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+               };
+       };
+
+       pm8005-rpmh-regulators {
+               compatible = "qcom,pm8005-rpmh-regulators";
+               qcom,pmic-id = "c";
+
+               vdd-s1-supply = <&src_vph_pwr>;
+               vdd-s2-supply = <&src_vph_pwr>;
+               vdd-s3-supply = <&src_vph_pwr>;
+               vdd-s4-supply = <&src_vph_pwr>;
+
+               src_pp600_s3c: smps3 {
+                       regulator-min-microvolt = <600000>;
+                       regulator-max-microvolt = <600000>;
+               };
+       };
+};
+
+&dsi0 {
+       status = "okay";
+       vdda-supply = <&vdda_mipi_dsi0_1p2>;
+
+       ports {
+               port@1 {
+                       endpoint {
+                               remote-endpoint = <&sn65dsi86_in>;
+                               data-lanes = <0 1 2 3>;
+                       };
+               };
+       };
+};
+
+&dsi0_phy {
+       status = "okay";
+       vdds-supply = <&vdda_mipi_dsi0_pll>;
+};
+
+edp_brij_i2c: &i2c3 {
+       status = "okay";
+       clock-frequency = <400000>;
+
+       sn65dsi86_bridge: bridge@2d {
+               compatible = "ti,sn65dsi86";
+               reg = <0x2d>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&edp_brij_en &edp_brij_irq>;
+
+               interrupt-parent = <&tlmm>;
+               interrupts = <10 IRQ_TYPE_LEVEL_HIGH>;
+
+               enable-gpios = <&tlmm 102 GPIO_ACTIVE_HIGH>;
+
+               vpll-supply = <&src_pp1800_s4a>;
+               vccio-supply = <&src_pp1800_s4a>;
+               vcca-supply = <&src_pp1200_l2a>;
+               vcc-supply = <&src_pp1200_l2a>;
+
+               clocks = <&rpmhcc RPMH_LN_BB_CLK2>;
+               clock-names = "refclk";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+                               sn65dsi86_in: endpoint {
+                                       remote-endpoint = <&dsi0_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+                               sn65dsi86_out: endpoint {
+                                       remote-endpoint = <&panel_in_edp>;
+                               };
+                       };
+               };
+       };
+};
+
+ap_pen_1v8: &i2c11 {
+       status = "okay";
+       clock-frequency = <400000>;
+
+       digitizer@9 {
+               compatible = "wacom,w9013", "hid-over-i2c";
+               reg = <0x9>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pen_irq_l>, <&pen_pdct_l>, <&pen_rst_l>;
+
+               vdd-supply = <&pp3300_dx_pen>;
+               vddl-supply = <&pp1800_dx_pen>;
+               post-power-on-delay-ms = <100>;
+
+               interrupt-parent = <&tlmm>;
+               interrupts = <24 IRQ_TYPE_LEVEL_LOW>;
+
+               hid-descr-addr = <0x1>;
+       };
+};
+
+amp_i2c: &i2c12 {
+       status = "okay";
+       clock-frequency = <400000>;
+};
+
+ap_ts_i2c: &i2c14 {
+       status = "okay";
+       clock-frequency = <400000>;
+
+       touchscreen@10 {
+               compatible = "elan,ekth3500";
+               reg = <0x10>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&ts_int_l &ts_reset_l>;
+
+               interrupt-parent = <&tlmm>;
+               interrupts = <125 IRQ_TYPE_LEVEL_LOW>;
+
+               vcc33-supply = <&src_pp3300_l28a>;
+
+               reset-gpios = <&tlmm 118 GPIO_ACTIVE_LOW>;
+       };
+};
+
+&lpasscc {
+       status = "okay";
+};
+
+&mdss {
+       status = "okay";
+};
+
+&mdss_mdp {
+       status = "okay";
+};
+
+&qupv3_id_0 {
+       status = "okay";
+};
+
+&qupv3_id_1 {
+       status = "okay";
+};
+
+&sdhc_2 {
+       status = "okay";
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&sdc2_clk &sdc2_cmd &sdc2_data &sd_cd_odl>;
+
+       vmmc-supply = <&src_pp2950_l21a>;
+       vqmmc-supply = <&vddpx_2>;
+
+       cd-gpios = <&tlmm 44 GPIO_ACTIVE_LOW>;
+};
+
+&spi0 {
+       status = "okay";
+};
+
+&spi10 {
+       status = "okay";
+
+       cros_ec: ec@0 {
+               compatible = "google,cros-ec-spi";
+               reg = <0>;
+               interrupt-parent = <&tlmm>;
+               interrupts = <122 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&ec_ap_int_l>;
+               spi-max-frequency = <3000000>;
+
+               cros_ec_pwm: ec-pwm {
+                       compatible = "google,cros-ec-pwm";
+                       #pwm-cells = <1>;
+               };
+
+               i2c_tunnel: i2c-tunnel {
+                       compatible = "google,cros-ec-i2c-tunnel";
+                       google,remote-bus = <0>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               pdupdate {
+                       compatible = "google,cros-ec-pd-update";
+               };
+       };
+};
+
+#include <arm/cros-ec-keyboard.dtsi>
+#include <arm/cros-ec-sbs.dtsi>
+
+&uart6 {
+       status = "okay";
+
+       bluetooth: wcn3990-bt {
+               compatible = "qcom,wcn3990-bt";
+               vddio-supply = <&src_pp1800_s4a>;
+               vddxo-supply = <&pp1800_l7a_wcn3990>;
+               vddrf-supply = <&src_pp1300_l17a>;
+               vddch0-supply = <&pp3300_l25a_ch0_wcn3990>;
+               max-speed = <3200000>;
+       };
+};
+
+&uart9 {
+       status = "okay";
+};
+
+&ufs_mem_hc {
+       status = "okay";
+       pinctrl-names = "init", "default";
+       pinctrl-0 = <&ufs_dev_reset_assert>;
+       pinctrl-1 = <&ufs_dev_reset_deassert>;
+
+       vcc-supply = <&src_pp2950_l20a>;
+       vcc-max-microamp = <600000>;
+};
+
+&ufs_mem_phy {
+       status = "okay";
+
+       vdda-phy-supply = <&vdda_ufs1_core>;
+       vdda-pll-supply = <&vdda_ufs1_1p2>;
+};
+
+&usb_1 {
+       status = "okay";
+
+       /* We'll use this as USB 2.0 only */
+       qcom,select-utmi-as-pipe-clk;
+};
+
+&usb_1_dwc3 {
+       /*
+        * The hardware design intends this port to be hooked up in peripheral
+        * mode, so we'll hardcode it here.  Some details:
+        * - SDM845 expects only a single Type C connector so it has only one
+        *   native Type C port but cheza has two Type C connectors.
+        * - The only source of DP is the single native Type C port.
+        * - On cheza we want to be able to hook DP up to _either_ of the
+        *   two Type C connectors and want to be able to achieve 4 lanes of DP.
+        * - When you configure a Type C port for 4 lanes of DP you lose USB3.
+        * - In order to make everything work, the native Type C port is always
+        *   configured as 4-lanes DP so it's always available.
+        * - The extra USB3 port on SDM845 goes to a USB 3 hub which is then
+        *   sent to the two Type C connectors.
+        * - The extra USB2 lines from the native Type C port are always
+        *   setup as "peripheral" so that we can mux them over to one connector
+        *   or the other if someone needs the connector configured as a gadget
+        *   (but they only get USB2 speeds).
+        *
+        * All the hardware muxes would allow us to hook things up in different
+        * ways to some potential benefit for static configurations (you could
+        * achieve extra USB2 bandwidth by using two different ports for the
+        * two conenctors or possibly even get USB3 peripheral mode), but in
+        * each case you end up forcing to disconnect/reconnect an in-use
+        * USB session in some cases depending on what you hotplug into the
+        * other connector.  Thus hardcoding this as peripheral makes sense.
+        */
+       dr_mode = "peripheral";
+
+       /*
+        * We always need the high speed pins as 4-lanes DP in case someone
+        * hotplugs a DP peripheral.  Thus limit this port to a max of high
+        * speed.
+        */
+       maximum-speed = "high-speed";
+
+       /*
+        * We don't need the usb3-phy since we run in highspeed mode always, so
+        * re-define these properties removing the superspeed USB PHY reference.
+        */
+       phys = <&usb_1_hsphy>;
+       phy-names = "usb2-phy";
+};
+
+&usb_1_hsphy {
+       status = "okay";
+
+       vdd-supply = <&vdda_usb1_ss_core>;
+       vdda-pll-supply = <&vdda_qusb_hs0_1p8>;
+       vdda-phy-dpdm-supply = <&vdda_qusb_hs0_3p1>;
+
+       qcom,imp-res-offset-value = <8>;
+       qcom,hstx-trim-value = <QUSB2_V2_HSTX_TRIM_21_6_MA>;
+       qcom,preemphasis-level = <QUSB2_V2_PREEMPHASIS_5_PERCENT>;
+       qcom,preemphasis-width = <QUSB2_V2_PREEMPHASIS_WIDTH_HALF_BIT>;
+};
+
+&usb_2 {
+       status = "okay";
+};
+
+&usb_2_dwc3 {
+       /* We have this hooked up to a hub and we always use in host mode */
+       dr_mode = "host";
+};
+
+&usb_2_hsphy {
+       status = "okay";
+
+       vdd-supply = <&vdda_usb2_ss_core>;
+       vdda-pll-supply = <&vdda_qusb_hs0_1p8>;
+       vdda-phy-dpdm-supply = <&vdda_qusb_hs0_3p1>;
+
+       qcom,imp-res-offset-value = <8>;
+       qcom,hstx-trim-value = <QUSB2_V2_HSTX_TRIM_22_8_MA>;
+};
+
+&usb_2_qmpphy {
+       status = "okay";
+
+       vdda-phy-supply = <&vdda_usb2_ss_1p2>;
+       vdda-pll-supply = <&vdda_usb2_ss_core>;
+};
+
+&wifi {
+       status = "okay";
+
+       vdd-0.8-cx-mx-supply = <&src_pp800_l5a >;
+       vdd-1.8-xo-supply = <&pp1800_l7a_wcn3990>;
+       vdd-1.3-rfa-supply = <&src_pp1300_l17a>;
+       vdd-3.3-ch0-supply = <&pp3300_l25a_ch0_wcn3990>;
+};
+
+/* PINCTRL - additions to nodes defined in sdm845.dtsi */
+
+&qspi_cs0 {
+       pinconf {
+               pins = "gpio90";
+               bias-disable;
+       };
+};
+
+&qspi_clk {
+       pinconf {
+               pins = "gpio95";
+               bias-disable;
+       };
+};
+
+&qspi_data01 {
+       pinconf {
+               pins = "gpio91", "gpio92";
+
+               /* High-Z when no transfers; nice to park the lines */
+               bias-pull-up;
+       };
+};
+
+&qup_i2c3_default {
+       pinconf {
+               pins = "gpio41", "gpio42";
+               drive-strength = <2>;
+
+               /* Has external pullup */
+               bias-disable;
+       };
+};
+
+&qup_i2c11_default {
+       pinconf {
+               pins = "gpio31", "gpio32";
+               drive-strength = <2>;
+
+               /* Has external pullup */
+               bias-disable;
+       };
+};
+
+&qup_i2c12_default {
+       pinconf {
+               pins = "gpio49", "gpio50";
+               drive-strength = <2>;
+
+               /* Has external pullup */
+               bias-disable;
+       };
+};
+
+&qup_i2c14_default {
+       pinconf {
+               pins = "gpio33", "gpio34";
+               drive-strength = <2>;
+
+               /* Has external pullup */
+               bias-disable;
+       };
+};
+
+&qup_spi0_default {
+       pinconf {
+               pins = "gpio0", "gpio1", "gpio2", "gpio3";
+               drive-strength = <2>;
+               bias-disable;
+       };
+};
+
+&qup_spi5_default {
+       pinconf {
+               pins = "gpio85", "gpio86", "gpio87", "gpio88";
+               drive-strength = <2>;
+               bias-disable;
+       };
+};
+
+&qup_spi10_default {
+       pinconf {
+               pins = "gpio53", "gpio54", "gpio55", "gpio56";
+               drive-strength = <2>;
+               bias-disable;
+       };
+};
+
+&qup_uart6_default {
+       /* Change pinmux to all 4 pins since CTS and RTS are connected */
+       pinmux {
+               pins = "gpio45", "gpio46",
+                      "gpio47", "gpio48";
+       };
+
+       pinconf-cts {
+               /*
+                * Configure a pull-down on 45 (CTS) to match the pull of
+                * the Bluetooth module.
+                */
+               pins = "gpio45";
+               bias-pull-down;
+       };
+
+       pinconf-rts-tx {
+               /* We'll drive 46 (RTS) and 47 (TX), so no pull */
+               pins = "gpio46", "gpio47";
+               drive-strength = <2>;
+               bias-disable;
+       };
+
+       pinconf-rx {
+               /*
+                * Configure a pull-up on 48 (RX). This is needed to avoid
+                * garbage data when the TX pin of the Bluetooth module is
+                * in tri-state (module powered off or not driving the
+                * signal yet).
+                */
+               pins = "gpio48";
+               bias-pull-up;
+       };
+};
+
+&qup_uart9_default {
+       pinconf-tx {
+               pins = "gpio4";
+               drive-strength = <2>;
+               bias-disable;
+       };
+
+       pinconf-rx {
+               pins = "gpio5";
+               drive-strength = <2>;
+               bias-pull-up;
+       };
+};
+
+/* PINCTRL - board-specific pinctrl */
+&pm8005_gpio {
+       gpio-line-names = "",
+                         "",
+                         "SLB",
+                         "";
+};
+
+&pm8998_adc {
+       adc-chan@ADC5_AMUX_THM1_100K_PU {
+               reg = <ADC5_AMUX_THM1_100K_PU>;
+               label = "sdm_temp";
+       };
+
+       adc-chan@ADC5_AMUX_THM2_100K_PU {
+               reg = <ADC5_AMUX_THM2_100K_PU>;
+               label = "quiet_temp";
+       };
+
+       adc-chan@ADC5_AMUX_THM3_100K_PU {
+               reg = <ADC5_AMUX_THM3_100K_PU>;
+               label = "lte_temp_1";
+       };
+
+       adc-chan@ADC5_AMUX_THM4_100K_PU {
+               reg = <ADC5_AMUX_THM4_100K_PU>;
+               label = "lte_temp_2";
+       };
+
+       adc-chan@ADC5_AMUX_THM5_100K_PU {
+               reg = <ADC5_AMUX_THM5_100K_PU>;
+               label = "charger_temp";
+       };
+};
+
+&pm8998_gpio {
+       gpio-line-names = "",
+                         "",
+                         "SW_CTRL",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "CFG_OPT1",
+                         "WCSS_PWR_REQ",
+                         "",
+                         "CFG_OPT2",
+                         "SLB";
+};
+
+&tlmm {
+       /*
+        * pinctrl settings for pins that have no real owners.
+        */
+       pinctrl-names = "default", "sleep";
+       pinctrl-0 = <&bios_flash_wp_r_l>,
+                   <&ap_suspend_l_deassert>;
+
+       pinctrl-1 = <&bios_flash_wp_r_l>,
+                   <&ap_suspend_l_assert>;
+
+       /*
+        * Hogs prevent usermode from changing the value. A GPIO can be both
+        * here and in the pinctrl section.
+        */
+       ap-suspend-l-hog {
+               gpio-hog;
+               gpios = <126 GPIO_ACTIVE_LOW>;
+               output-low;
+       };
+
+       ap_edp_bklten: ap-edp-bklten {
+               pinmux {
+                       pins = "gpio37";
+                       function = "gpio";
+               };
+
+               pinconf {
+                       pins = "gpio37";
+                       drive-strength = <2>;
+                       bias-disable;
+               };
+       };
+
+       bios_flash_wp_r_l: bios-flash-wp-r-l {
+               pinmux {
+                       pins = "gpio128";
+                       function = "gpio";
+                       input-enable;
+               };
+
+               pinconf {
+                       pins = "gpio128";
+                       bias-disable;
+               };
+       };
+
+       ec_ap_int_l: ec-ap-int-l {
+               pinmux {
+                      pins = "gpio122";
+                      function = "gpio";
+                      input-enable;
+               };
+
+               pinconf {
+                      pins = "gpio122";
+                      bias-pull-up;
+               };
+       };
+
+       edp_brij_en: edp-brij-en {
+               pinmux {
+                       pins = "gpio102";
+                       function = "gpio";
+               };
+
+               pinconf {
+                       pins = "gpio102";
+                       drive-strength = <2>;
+                       bias-disable;
+               };
+       };
+
+       edp_brij_irq: edp-brij-irq {
+               pinmux {
+                       pins = "gpio10";
+                       function = "gpio";
+               };
+
+               pinconf {
+                       pins = "gpio10";
+                       drive-strength = <2>;
+                       bias-pull-down;
+               };
+       };
+
+       en_pp3300_dx_edp: en-pp3300-dx-edp {
+               pinmux {
+                       pins = "gpio43";
+                       function = "gpio";
+               };
+
+               pinconf {
+                       pins = "gpio43";
+                       drive-strength = <2>;
+                       bias-disable;
+               };
+       };
+
+       h1_ap_int_odl: h1-ap-int-odl {
+               pinmux {
+                       pins = "gpio129";
+                       function = "gpio";
+                       input-enable;
+               };
+
+               pinconf {
+                       pins = "gpio129";
+                       bias-pull-up;
+               };
+       };
+
+       pen_eject_odl: pen-eject-odl {
+               pinmux {
+                       pins = "gpio119";
+                       function = "gpio";
+                       bias-pull-up;
+               };
+       };
+
+       pen_irq_l: pen-irq-l {
+               pinmux {
+                       pins = "gpio24";
+                       function = "gpio";
+               };
+
+               pinconf {
+                       pins = "gpio24";
+
+                       /* Has external pullup */
+                       bias-disable;
+               };
+       };
+
+       pen_pdct_l: pen-pdct-l {
+               pinmux {
+                       pins = "gpio63";
+                       function = "gpio";
+               };
+
+               pinconf {
+                       pins = "gpio63";
+
+                       /* Has external pullup */
+                       bias-disable;
+               };
+       };
+
+       pen_rst_l: pen-rst-l {
+               pinmux  {
+                       pins = "gpio23";
+                       function = "gpio";
+               };
+
+               pinconf {
+                       pins = "gpio23";
+                       bias-disable;
+                       drive-strength = <2>;
+
+                       /*
+                        * The pen driver doesn't currently support
+                        * driving this reset line.  By specifying
+                        * output-high here we're relying on the fact
+                        * that this pin has a default pulldown at boot
+                        * (which makes sure the pen was in reset if it
+                        * was powered) and then we set it high here to
+                        * take it out of reset.  Better would be if the
+                        * pen driver could control this and we could
+                        * remove "output-high" here.
+                        */
+                       output-high;
+               };
+       };
+
+       sdc2_clk: sdc2-clk {
+               pinconf {
+                       pins = "sdc2_clk";
+                       bias-disable;
+
+                       /*
+                        * It seems that mmc_test reports errors if drive
+                        * strength is not 16.
+                        */
+                       drive-strength = <16>;
+               };
+       };
+
+       sdc2_cmd: sdc2-cmd {
+               pinconf {
+                       pins = "sdc2_cmd";
+                       bias-pull-up;
+                       drive-strength = <16>;
+               };
+       };
+
+       sdc2_data: sdc2-data {
+               pinconf {
+                       pins = "sdc2_data";
+                       bias-pull-up;
+                       drive-strength = <16>;
+               };
+       };
+
+       sd_cd_odl: sd-cd-odl {
+               pinmux {
+                       pins = "gpio44";
+                       function = "gpio";
+               };
+
+               pinconf {
+                       pins = "gpio44";
+                       bias-pull-up;
+               };
+       };
+
+       ts_int_l: ts-int-l {
+               pinmux  {
+                       pins = "gpio125";
+                       function = "gpio";
+               };
+
+               pinconf {
+                       pins = "gpio125";
+                       bias-pull-up;
+               };
+       };
+
+       ts_reset_l: ts-reset-l {
+               pinmux  {
+                       pins = "gpio118";
+                       function = "gpio";
+               };
+
+               pinconf {
+                       pins = "gpio118";
+                       bias-disable;
+                       drive-strength = <2>;
+               };
+       };
+
+       ufs_dev_reset_assert: ufs_dev_reset_assert {
+               config {
+                       pins = "ufs_reset";
+                       bias-pull-down;         /* default: pull down */
+                       /*
+                        * UFS_RESET driver strengths are having
+                        * different values/steps compared to typical
+                        * GPIO drive strengths.
+                        *
+                        * Following table clarifies:
+                        *
+                        * HDRV value | UFS_RESET | Typical GPIO
+                        *   (dec)    |   (mA)    |    (mA)
+                        *     0      |   0.8     |    2
+                        *     1      |   1.55    |    4
+                        *     2      |   2.35    |    6
+                        *     3      |   3.1     |    8
+                        *     4      |   3.9     |    10
+                        *     5      |   4.65    |    12
+                        *     6      |   5.4     |    14
+                        *     7      |   6.15    |    16
+                        *
+                        * POR value for UFS_RESET HDRV is 3 which means
+                        * 3.1mA and we want to use that. Hence just
+                        * specify 8mA to "drive-strength" binding and
+                        * that should result into writing 3 to HDRV
+                        * field.
+                        */
+                       drive-strength = <8>;   /* default: 3.1 mA */
+                       output-low; /* active low reset */
+               };
+       };
+
+       ufs_dev_reset_deassert: ufs_dev_reset_deassert {
+               config {
+                       pins = "ufs_reset";
+                       bias-pull-down;         /* default: pull down */
+                       /*
+                        * default: 3.1 mA
+                        * check comments under ufs_dev_reset_assert
+                        */
+                       drive-strength = <8>;
+                       output-high; /* active low reset */
+               };
+       };
+
+       ap_suspend_l_assert: ap_suspend_l_assert {
+               config {
+                       pins = "gpio126";
+                       function = "gpio";
+                       bias-no-pull;
+                       drive-strength = <2>;
+                       output-low;
+               };
+       };
+
+       ap_suspend_l_deassert: ap_suspend_l_deassert {
+               config {
+                       pins = "gpio126";
+                       function = "gpio";
+                       bias-no-pull;
+                       drive-strength = <2>;
+                       output-high;
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
new file mode 100644 (file)
index 0000000..71bd717
--- /dev/null
@@ -0,0 +1,557 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019, Linaro Ltd.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+#include "sdm845.dtsi"
+#include "pm8998.dtsi"
+#include "pmi8998.dtsi"
+
+/ {
+       model = "Thundercomm Dragonboard 845c";
+       compatible = "thundercomm,db845c", "qcom,sdm845";
+
+       aliases {
+               serial0 = &uart9;
+               hsuart0 = &uart6;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       dc12v: dc12v-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "DC12V";
+               regulator-min-microvolt = <12000000>;
+               regulator-max-microvolt = <12000000>;
+               regulator-always-on;
+       };
+
+       gpio_keys {
+               compatible = "gpio-keys";
+               autorepeat;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&vol_up_pin_a>;
+
+               vol-up {
+                       label = "Volume Up";
+                       linux,code = <KEY_VOLUMEUP>;
+                       gpios = <&pm8998_gpio 6 GPIO_ACTIVE_LOW>;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               user4 {
+                       label = "green:user4";
+                       gpios = <&pm8998_gpio 13 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "panic-indicator";
+                       default-state = "off";
+               };
+
+               wlan {
+                       label = "yellow:wlan";
+                       gpios = <&pm8998_gpio 9 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "phy0tx";
+                       default-state = "off";
+               };
+
+               bt {
+                       label = "blue:bt";
+                       gpios = <&pm8998_gpio 5 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "bluetooth-power";
+                       default-state = "off";
+               };
+       };
+
+       lt9611_1v8: lt9611-vdd18-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "LT9611_1V8";
+
+               vin-supply = <&vdc_5v>;
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+
+               gpio = <&tlmm 89 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       lt9611_3v3: lt9611-3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "LT9611_3V3";
+
+               vin-supply = <&vdc_3v3>;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+
+               // TODO: make it possible to drive same GPIO from two clients
+               // gpio = <&tlmm 89 GPIO_ACTIVE_HIGH>;
+               // enable-active-high;
+       };
+
+       pcie0_1p05v: pcie-0-1p05v-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "PCIE0_1.05V";
+
+               vin-supply = <&vbat>;
+               regulator-min-microvolt = <1050000>;
+               regulator-max-microvolt = <1050000>;
+
+               // TODO: make it possible to drive same GPIO from two clients
+               // gpio = <&tlmm 90 GPIO_ACTIVE_HIGH>;
+               // enable-active-high;
+       };
+
+       pcie0_3p3v_dual: vldo-3v3-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "VLDO_3V3";
+
+               vin-supply = <&vbat>;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+
+               gpio = <&tlmm 90 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&pcie0_pwren_state>;
+       };
+
+       v5p0_hdmiout: v5p0-hdmiout-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "V5P0_HDMIOUT";
+
+               vin-supply = <&vdc_5v>;
+               regulator-min-microvolt = <500000>;
+               regulator-max-microvolt = <500000>;
+
+               // TODO: make it possible to drive same GPIO from two clients
+               // gpio = <&tlmm 89 GPIO_ACTIVE_HIGH>;
+               // enable-active-high;
+       };
+
+       vbat: vbat-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "VBAT";
+
+               vin-supply = <&dc12v>;
+               regulator-min-microvolt = <4200000>;
+               regulator-max-microvolt = <4200000>;
+               regulator-always-on;
+       };
+
+       vbat_som: vbat-som-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "VBAT_SOM";
+
+               vin-supply = <&dc12v>;
+               regulator-min-microvolt = <4200000>;
+               regulator-max-microvolt = <4200000>;
+               regulator-always-on;
+       };
+
+       vdc_3v3: vdc-3v3-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "VDC_3V3";
+               vin-supply = <&dc12v>;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+       };
+
+       vdc_5v: vdc-5v-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "VDC_5V";
+
+               vin-supply = <&dc12v>;
+               regulator-min-microvolt = <500000>;
+               regulator-max-microvolt = <500000>;
+               regulator-always-on;
+       };
+
+       vreg_s4a_1p8: vreg-s4a-1p8 {
+               compatible = "regulator-fixed";
+               regulator-name = "vreg_s4a_1p8";
+
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-always-on;
+       };
+
+       vph_pwr: vph-pwr-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vph_pwr";
+
+               vin-supply = <&vbat_som>;
+       };
+};
+
+&adsp_pas {
+       status = "okay";
+
+       firmware-name = "qcom/db845c/adsp.mdt";
+};
+
+&apps_rsc {
+       pm8998-rpmh-regulators {
+               compatible = "qcom,pm8998-rpmh-regulators";
+               qcom,pmic-id = "a";
+               vdd-s1-supply = <&vph_pwr>;
+               vdd-s2-supply = <&vph_pwr>;
+               vdd-s3-supply = <&vph_pwr>;
+               vdd-s4-supply = <&vph_pwr>;
+               vdd-s5-supply = <&vph_pwr>;
+               vdd-s6-supply = <&vph_pwr>;
+               vdd-s7-supply = <&vph_pwr>;
+               vdd-s8-supply = <&vph_pwr>;
+               vdd-s9-supply = <&vph_pwr>;
+               vdd-s10-supply = <&vph_pwr>;
+               vdd-s11-supply = <&vph_pwr>;
+               vdd-s12-supply = <&vph_pwr>;
+               vdd-s13-supply = <&vph_pwr>;
+               vdd-l1-l27-supply = <&vreg_s7a_1p025>;
+               vdd-l2-l8-l17-supply = <&vreg_s3a_1p35>;
+               vdd-l3-l11-supply = <&vreg_s7a_1p025>;
+               vdd-l4-l5-supply = <&vreg_s7a_1p025>;
+               vdd-l6-supply = <&vph_pwr>;
+               vdd-l7-l12-l14-l15-supply = <&vreg_s5a_2p04>;
+               vdd-l9-supply = <&vreg_bob>;
+               vdd-l10-l23-l25-supply = <&vreg_bob>;
+               vdd-l13-l19-l21-supply = <&vreg_bob>;
+               vdd-l16-l28-supply = <&vreg_bob>;
+               vdd-l18-l22-supply = <&vreg_bob>;
+               vdd-l20-l24-supply = <&vreg_bob>;
+               vdd-l26-supply = <&vreg_s3a_1p35>;
+               vin-lvs-1-2-supply = <&vreg_s4a_1p8>;
+
+               vreg_s3a_1p35: smps3 {
+                       regulator-min-microvolt = <1352000>;
+                       regulator-max-microvolt = <1352000>;
+               };
+
+               vreg_s5a_2p04: smps5 {
+                       regulator-min-microvolt = <1904000>;
+                       regulator-max-microvolt = <2040000>;
+               };
+
+               vreg_s7a_1p025: smps7 {
+                       regulator-min-microvolt = <900000>;
+                       regulator-max-microvolt = <1028000>;
+               };
+
+               vreg_l1a_0p875: ldo1 {
+                       regulator-min-microvolt = <880000>;
+                       regulator-max-microvolt = <880000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l5a_0p8: ldo5 {
+                       regulator-min-microvolt = <800000>;
+                       regulator-max-microvolt = <800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l12a_1p8: ldo12 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l7a_1p8: ldo7 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l13a_2p95: ldo13 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <2960000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l17a_1p3: ldo17 {
+                       regulator-min-microvolt = <1304000>;
+                       regulator-max-microvolt = <1304000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l20a_2p95: ldo20 {
+                       regulator-min-microvolt = <2960000>;
+                       regulator-max-microvolt = <2968000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l21a_2p95: ldo21 {
+                       regulator-min-microvolt = <2960000>;
+                       regulator-max-microvolt = <2968000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l24a_3p075: ldo24 {
+                       regulator-min-microvolt = <3088000>;
+                       regulator-max-microvolt = <3088000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l25a_3p3: ldo25 {
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3312000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l26a_1p2: ldo26 {
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1200000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+       };
+
+       pmi8998-rpmh-regulators {
+               compatible = "qcom,pmi8998-rpmh-regulators";
+               qcom,pmic-id = "b";
+
+               vdd-bob-supply = <&vph_pwr>;
+
+               vreg_bob: bob {
+                       regulator-min-microvolt = <3312000>;
+                       regulator-max-microvolt = <3600000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_AUTO>;
+                       regulator-allow-bypass;
+               };
+       };
+};
+
+&cdsp_pas {
+       status = "okay";
+       firmware-name = "qcom/db845c/cdsp.mdt";
+};
+
+&gcc {
+       protected-clocks = <GCC_QSPI_CORE_CLK>,
+                          <GCC_QSPI_CORE_CLK_SRC>,
+                          <GCC_QSPI_CNOC_PERIPH_AHB_CLK>;
+};
+
+&pm8998_gpio {
+       vol_up_pin_a: vol-up-active {
+               pins = "gpio6";
+               function = "normal";
+               input-enable;
+               bias-pull-up;
+               qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>;
+       };
+};
+
+&pm8998_pon {
+       resin {
+               compatible = "qcom,pm8941-resin";
+               interrupts = <0x0 0x8 1 IRQ_TYPE_EDGE_BOTH>;
+               debounce = <15625>;
+               bias-pull-up;
+               linux,code = <KEY_VOLUMEDOWN>;
+       };
+};
+
+&qupv3_id_0 {
+       status = "okay";
+};
+
+&qupv3_id_1 {
+       status = "okay";
+};
+
+&sdhc_2 {
+       status = "okay";
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&sdc2_default_state &sdc2_card_det_n>;
+
+       vmmc-supply = <&vreg_l21a_2p95>;
+       vqmmc-supply = <&vreg_l13a_2p95>;
+
+       bus-width = <4>;
+       cd-gpios = <&tlmm 126 GPIO_ACTIVE_LOW>;
+};
+
+&tlmm {
+       pcie0_pwren_state: pcie0-pwren {
+               pins = "gpio90";
+               function = "gpio";
+
+               drive-strength = <2>;
+               bias-disable;
+       };
+
+       sdc2_default_state: sdc2-default {
+               clk {
+                       pins = "sdc2_clk";
+                       bias-disable;
+
+                       /*
+                        * It seems that mmc_test reports errors if drive
+                        * strength is not 16 on clk, cmd, and data pins.
+                        */
+                       drive-strength = <16>;
+               };
+
+               cmd {
+                       pins = "sdc2_cmd";
+                       bias-pull-up;
+                       drive-strength = <10>;
+               };
+
+               data {
+                       pins = "sdc2_data";
+                       bias-pull-up;
+                       drive-strength = <10>;
+               };
+       };
+
+       sdc2_card_det_n: sd-card-det-n {
+               pins = "gpio126";
+               function = "gpio";
+               bias-pull-up;
+       };
+};
+
+&uart6 {
+       status = "okay";
+
+       bluetooth {
+               compatible = "qcom,wcn3990-bt";
+
+               vddio-supply = <&vreg_s4a_1p8>;
+               vddxo-supply = <&vreg_l7a_1p8>;
+               vddrf-supply = <&vreg_l17a_1p3>;
+               vddch0-supply = <&vreg_l25a_3p3>;
+               max-speed = <3200000>;
+       };
+};
+
+&uart9 {
+       status = "okay";
+};
+
+&usb_1 {
+       status = "okay";
+};
+
+&usb_1_dwc3 {
+       dr_mode = "peripheral";
+};
+
+&usb_1_hsphy {
+       status = "okay";
+
+       vdd-supply = <&vreg_l1a_0p875>;
+       vdda-pll-supply = <&vreg_l12a_1p8>;
+       vdda-phy-dpdm-supply = <&vreg_l24a_3p075>;
+
+       qcom,imp-res-offset-value = <8>;
+       qcom,hstx-trim-value = <QUSB2_V2_HSTX_TRIM_21_6_MA>;
+       qcom,preemphasis-level = <QUSB2_V2_PREEMPHASIS_5_PERCENT>;
+       qcom,preemphasis-width = <QUSB2_V2_PREEMPHASIS_WIDTH_HALF_BIT>;
+};
+
+&usb_1_qmpphy {
+       status = "okay";
+
+       vdda-phy-supply = <&vreg_l26a_1p2>;
+       vdda-pll-supply = <&vreg_l1a_0p875>;
+};
+
+&usb_2 {
+       status = "okay";
+};
+
+&usb_2_dwc3 {
+       dr_mode = "host";
+};
+
+&usb_2_hsphy {
+       status = "okay";
+
+       vdd-supply = <&vreg_l1a_0p875>;
+       vdda-pll-supply = <&vreg_l12a_1p8>;
+       vdda-phy-dpdm-supply = <&vreg_l24a_3p075>;
+
+       qcom,imp-res-offset-value = <8>;
+       qcom,hstx-trim-value = <QUSB2_V2_HSTX_TRIM_22_8_MA>;
+};
+
+&usb_2_qmpphy {
+       status = "okay";
+
+       vdda-phy-supply = <&vreg_l26a_1p2>;
+       vdda-pll-supply = <&vreg_l1a_0p875>;
+};
+
+&ufs_mem_hc {
+       status = "okay";
+
+       vcc-supply = <&vreg_l20a_2p95>;
+       vcc-max-microamp = <800000>;
+};
+
+&ufs_mem_phy {
+       status = "okay";
+
+       vdda-phy-supply = <&vreg_l1a_0p875>;
+       vdda-pll-supply = <&vreg_l26a_1p2>;
+};
+
+&wifi {
+       status = "okay";
+
+       vdd-0.8-cx-mx-supply = <&vreg_l5a_0p8>;
+       vdd-1.8-xo-supply = <&vreg_l7a_1p8>;
+       vdd-1.3-rfa-supply = <&vreg_l17a_1p3>;
+       vdd-3.3-ch0-supply = <&vreg_l25a_3p3>;
+};
+
+/* PINCTRL - additions to nodes defined in sdm845.dtsi */
+
+&qup_uart6_default {
+       pinmux {
+               pins = "gpio45", "gpio46", "gpio47", "gpio48";
+               function = "qup6";
+       };
+
+       cts {
+               pins = "gpio45";
+               bias-disable;
+       };
+
+       rts-tx {
+               pins = "gpio46", "gpio47";
+               drive-strength = <2>;
+               bias-disable;
+       };
+
+       rx {
+               pins = "gpio48";
+               bias-pull-up;
+       };
+};
+
+&qup_uart9_default {
+       pinconf-tx {
+               pins = "gpio4";
+               drive-strength = <2>;
+               bias-disable;
+       };
+
+       pinconf-rx {
+               pins = "gpio5";
+               drive-strength = <2>;
+               bias-pull-up;
+       };
+};
index 02b8357..2e78638 100644 (file)
 };
 
 &usb_1_dwc3 {
-       /* Until we have Type C hooked up we'll force this as host. */
-       dr_mode = "host";
+       /* Until we have Type C hooked up we'll force this as peripheral. */
+       dr_mode = "peripheral";
 };
 
 &usb_1_hsphy {
index fcb9330..4babff5 100644 (file)
                        compatible = "qcom,kryo385";
                        reg = <0x0 0x0>;
                        enable-method = "psci";
+                       cpu-idle-states = <&LITTLE_CPU_SLEEP_0
+                                          &LITTLE_CPU_SLEEP_1
+                                          &CLUSTER_SLEEP_0>;
                        capacity-dmips-mhz = <607>;
                        qcom,freq-domain = <&cpufreq_hw 0>;
                        #cooling-cells = <2>;
                        compatible = "qcom,kryo385";
                        reg = <0x0 0x100>;
                        enable-method = "psci";
+                       cpu-idle-states = <&LITTLE_CPU_SLEEP_0
+                                          &LITTLE_CPU_SLEEP_1
+                                          &CLUSTER_SLEEP_0>;
                        capacity-dmips-mhz = <607>;
                        qcom,freq-domain = <&cpufreq_hw 0>;
                        #cooling-cells = <2>;
                        compatible = "qcom,kryo385";
                        reg = <0x0 0x200>;
                        enable-method = "psci";
+                       cpu-idle-states = <&LITTLE_CPU_SLEEP_0
+                                          &LITTLE_CPU_SLEEP_1
+                                          &CLUSTER_SLEEP_0>;
                        capacity-dmips-mhz = <607>;
                        qcom,freq-domain = <&cpufreq_hw 0>;
                        #cooling-cells = <2>;
                        compatible = "qcom,kryo385";
                        reg = <0x0 0x300>;
                        enable-method = "psci";
+                       cpu-idle-states = <&LITTLE_CPU_SLEEP_0
+                                          &LITTLE_CPU_SLEEP_1
+                                          &CLUSTER_SLEEP_0>;
                        capacity-dmips-mhz = <607>;
                        qcom,freq-domain = <&cpufreq_hw 0>;
                        #cooling-cells = <2>;
                        reg = <0x0 0x400>;
                        enable-method = "psci";
                        capacity-dmips-mhz = <1024>;
+                       cpu-idle-states = <&BIG_CPU_SLEEP_0
+                                          &BIG_CPU_SLEEP_1
+                                          &CLUSTER_SLEEP_0>;
                        qcom,freq-domain = <&cpufreq_hw 1>;
                        #cooling-cells = <2>;
                        next-level-cache = <&L2_400>;
                        reg = <0x0 0x500>;
                        enable-method = "psci";
                        capacity-dmips-mhz = <1024>;
+                       cpu-idle-states = <&BIG_CPU_SLEEP_0
+                                          &BIG_CPU_SLEEP_1
+                                          &CLUSTER_SLEEP_0>;
                        qcom,freq-domain = <&cpufreq_hw 1>;
                        #cooling-cells = <2>;
                        next-level-cache = <&L2_500>;
                        reg = <0x0 0x600>;
                        enable-method = "psci";
                        capacity-dmips-mhz = <1024>;
+                       cpu-idle-states = <&BIG_CPU_SLEEP_0
+                                          &BIG_CPU_SLEEP_1
+                                          &CLUSTER_SLEEP_0>;
                        qcom,freq-domain = <&cpufreq_hw 1>;
                        #cooling-cells = <2>;
                        next-level-cache = <&L2_600>;
                        reg = <0x0 0x700>;
                        enable-method = "psci";
                        capacity-dmips-mhz = <1024>;
+                       cpu-idle-states = <&BIG_CPU_SLEEP_0
+                                          &BIG_CPU_SLEEP_1
+                                          &CLUSTER_SLEEP_0>;
                        qcom,freq-domain = <&cpufreq_hw 1>;
                        #cooling-cells = <2>;
                        next-level-cache = <&L2_700>;
                                core3 {
                                        cpu = <&CPU3>;
                                };
-                       };
 
-                       cluster1 {
-                               core0 {
+                               core4 {
                                        cpu = <&CPU4>;
                                };
 
-                               core1 {
+                               core5 {
                                        cpu = <&CPU5>;
                                };
 
-                               core2 {
+                               core6 {
                                        cpu = <&CPU6>;
                                };
 
-                               core3 {
+                               core7 {
                                        cpu = <&CPU7>;
                                };
                        };
                };
+
+               idle-states {
+                       entry-method = "psci";
+
+                       LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 {
+                               compatible = "arm,idle-state";
+                               idle-state-name = "little-power-down";
+                               arm,psci-suspend-param = <0x40000003>;
+                               entry-latency-us = <350>;
+                               exit-latency-us = <461>;
+                               min-residency-us = <1890>;
+                               local-timer-stop;
+                       };
+
+                       LITTLE_CPU_SLEEP_1: cpu-sleep-0-1 {
+                               compatible = "arm,idle-state";
+                               idle-state-name = "little-rail-power-down";
+                               arm,psci-suspend-param = <0x40000004>;
+                               entry-latency-us = <360>;
+                               exit-latency-us = <531>;
+                               min-residency-us = <3934>;
+                               local-timer-stop;
+                       };
+
+                       BIG_CPU_SLEEP_0: cpu-sleep-1-0 {
+                               compatible = "arm,idle-state";
+                               idle-state-name = "big-power-down";
+                               arm,psci-suspend-param = <0x40000003>;
+                               entry-latency-us = <264>;
+                               exit-latency-us = <621>;
+                               min-residency-us = <952>;
+                               local-timer-stop;
+                       };
+
+                       BIG_CPU_SLEEP_1: cpu-sleep-1-1 {
+                               compatible = "arm,idle-state";
+                               idle-state-name = "big-rail-power-down";
+                               arm,psci-suspend-param = <0x40000004>;
+                               entry-latency-us = <702>;
+                               exit-latency-us = <1061>;
+                               min-residency-us = <4488>;
+                               local-timer-stop;
+                       };
+
+                       CLUSTER_SLEEP_0: cluster-sleep-0 {
+                               compatible = "arm,idle-state";
+                               idle-state-name = "cluster-power-down";
+                               arm,psci-suspend-param = <0x400000F4>;
+                               entry-latency-us = <3263>;
+                               exit-latency-us = <6562>;
+                               min-residency-us = <9987>;
+                               local-timer-stop;
+                       };
+               };
        };
 
        pmu {
                        };
                };
 
+               mss_pil: remoteproc@4080000 {
+                       compatible = "qcom,sdm845-mss-pil";
+                       reg = <0 0x04080000 0 0x408>, <0 0x04180000 0 0x48>;
+                       reg-names = "qdsp6", "rmb";
+
+                       interrupts-extended =
+                               <&intc GIC_SPI 266 IRQ_TYPE_EDGE_RISING>,
+                               <&modem_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
+                               <&modem_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
+                               <&modem_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
+                               <&modem_smp2p_in 3 IRQ_TYPE_EDGE_RISING>,
+                               <&modem_smp2p_in 7 IRQ_TYPE_EDGE_RISING>;
+                       interrupt-names = "wdog", "fatal", "ready",
+                                         "handover", "stop-ack",
+                                         "shutdown-ack";
+
+                       clocks = <&gcc GCC_MSS_CFG_AHB_CLK>,
+                                <&gcc GCC_MSS_Q6_MEMNOC_AXI_CLK>,
+                                <&gcc GCC_BOOT_ROM_AHB_CLK>,
+                                <&gcc GCC_MSS_GPLL0_DIV_CLK_SRC>,
+                                <&gcc GCC_MSS_SNOC_AXI_CLK>,
+                                <&gcc GCC_MSS_MFAB_AXIS_CLK>,
+                                <&gcc GCC_PRNG_AHB_CLK>,
+                                <&rpmhcc RPMH_CXO_CLK>;
+                       clock-names = "iface", "bus", "mem", "gpll0_mss",
+                                     "snoc_axi", "mnoc_axi", "prng", "xo";
+
+                       qcom,smem-states = <&modem_smp2p_out 0>;
+                       qcom,smem-state-names = "stop";
+
+                       resets = <&aoss_reset AOSS_CC_MSS_RESTART>,
+                                <&pdc_reset PDC_MODEM_SYNC_RESET>;
+                       reset-names = "mss_restart", "pdc_reset";
+
+                       qcom,halt-regs = <&tcsr_mutex_regs 0x23000 0x25000 0x24000>;
+
+                       power-domains = <&aoss_qmp 2>,
+                                       <&rpmhpd SDM845_CX>,
+                                       <&rpmhpd SDM845_MX>,
+                                       <&rpmhpd SDM845_MSS>;
+                       power-domain-names = "load_state", "cx", "mx", "mss";
+
+                       mba {
+                               memory-region = <&mba_region>;
+                       };
+
+                       mpss {
+                               memory-region = <&mpss_region>;
+                       };
+
+                       glink-edge {
+                               interrupts = <GIC_SPI 449 IRQ_TYPE_EDGE_RISING>;
+                               label = "modem";
+                               qcom,remote-pid = <1>;
+                               mboxes = <&apss_shared 12>;
+                       };
+               };
+
                gpucc: clock-controller@5090000 {
                        compatible = "qcom,sdm845-gpucc";
                        reg = <0 0x05090000 0 0x9000>;
                        };
                };
 
+               gpu@5000000 {
+                       compatible = "qcom,adreno-630.2", "qcom,adreno";
+                       #stream-id-cells = <16>;
+
+                       reg = <0 0x5000000 0 0x40000>, <0 0x509e000 0 0x10>;
+                       reg-names = "kgsl_3d0_reg_memory", "cx_mem";
+
+                       /*
+                        * Look ma, no clocks! The GPU clocks and power are
+                        * controlled entirely by the GMU
+                        */
+
+                       interrupts = <GIC_SPI 300 IRQ_TYPE_LEVEL_HIGH>;
+
+                       iommus = <&adreno_smmu 0>;
+
+                       operating-points-v2 = <&gpu_opp_table>;
+
+                       qcom,gmu = <&gmu>;
+
+                       zap-shader {
+                               memory-region = <&gpu_mem>;
+                       };
+
+                       gpu_opp_table: opp-table {
+                               compatible = "operating-points-v2";
+
+                               opp-710000000 {
+                                       opp-hz = /bits/ 64 <710000000>;
+                                       opp-level = <RPMH_REGULATOR_LEVEL_TURBO_L1>;
+                               };
+
+                               opp-675000000 {
+                                       opp-hz = /bits/ 64 <675000000>;
+                                       opp-level = <RPMH_REGULATOR_LEVEL_TURBO>;
+                               };
+
+                               opp-596000000 {
+                                       opp-hz = /bits/ 64 <596000000>;
+                                       opp-level = <RPMH_REGULATOR_LEVEL_NOM_L1>;
+                               };
+
+                               opp-520000000 {
+                                       opp-hz = /bits/ 64 <520000000>;
+                                       opp-level = <RPMH_REGULATOR_LEVEL_NOM>;
+                               };
+
+                               opp-414000000 {
+                                       opp-hz = /bits/ 64 <414000000>;
+                                       opp-level = <RPMH_REGULATOR_LEVEL_SVS_L1>;
+                               };
+
+                               opp-342000000 {
+                                       opp-hz = /bits/ 64 <342000000>;
+                                       opp-level = <RPMH_REGULATOR_LEVEL_SVS>;
+                               };
+
+                               opp-257000000 {
+                                       opp-hz = /bits/ 64 <257000000>;
+                                       opp-level = <RPMH_REGULATOR_LEVEL_LOW_SVS>;
+                               };
+                       };
+               };
+
+               adreno_smmu: iommu@5040000 {
+                       compatible = "qcom,sdm845-smmu-v2", "qcom,smmu-v2";
+                       reg = <0 0x5040000 0 0x10000>;
+                       #iommu-cells = <1>;
+                       #global-interrupts = <2>;
+                       interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 231 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 364 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 365 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 366 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 367 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 368 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 369 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 370 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 371 IRQ_TYPE_EDGE_RISING>;
+                       clocks = <&gcc GCC_GPU_MEMNOC_GFX_CLK>,
+                                <&gcc GCC_GPU_CFG_AHB_CLK>;
+                       clock-names = "bus", "iface";
+
+                       power-domains = <&gpucc GPU_CX_GDSC>;
+               };
+
+               gmu: gmu@506a000 {
+                       compatible="qcom,adreno-gmu-630.2", "qcom,adreno-gmu";
+
+                       reg = <0 0x506a000 0 0x30000>,
+                             <0 0xb280000 0 0x10000>,
+                             <0 0xb480000 0 0x10000>;
+                       reg-names = "gmu", "gmu_pdc", "gmu_pdc_seq";
+
+                       interrupts = <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "hfi", "gmu";
+
+                       clocks = <&gpucc GPU_CC_CX_GMU_CLK>,
+                                <&gpucc GPU_CC_CXO_CLK>,
+                                <&gcc GCC_DDRSS_GPU_AXI_CLK>,
+                                <&gcc GCC_GPU_MEMNOC_GFX_CLK>;
+                       clock-names = "gmu", "cxo", "axi", "memnoc";
+
+                       power-domains = <&gpucc GPU_CX_GDSC>,
+                                       <&gpucc GPU_GX_GDSC>;
+                       power-domain-names = "cx", "gx";
+
+                       iommus = <&adreno_smmu 5>;
+
+                       operating-points-v2 = <&gmu_opp_table>;
+
+                       gmu_opp_table: opp-table {
+                               compatible = "operating-points-v2";
+
+                               opp-400000000 {
+                                       opp-hz = /bits/ 64 <400000000>;
+                                       opp-level = <RPMH_REGULATOR_LEVEL_SVS>;
+                               };
+
+                               opp-200000000 {
+                                       opp-hz = /bits/ 64 <200000000>;
+                                       opp-level = <RPMH_REGULATOR_LEVEL_MIN_SVS>;
+                               };
+                       };
+               };
+
                dispcc: clock-controller@af00000 {
                        compatible = "qcom,sdm845-dispcc";
                        reg = <0 0x0af00000 0 0x10000>;
                        #reset-cells = <1>;
                };
 
+               aoss_qmp: qmp@c300000 {
+                       compatible = "qcom,sdm845-aoss-qmp";
+                       reg = <0 0x0c300000 0 0x100000>;
+                       interrupts = <GIC_SPI 389 IRQ_TYPE_EDGE_RISING>;
+                       mboxes = <&apss_shared 0>;
+
+                       #clock-cells = <0>;
+                       #power-domain-cells = <1>;
+               };
+
                spmi_bus: spmi@c440000 {
                        compatible = "qcom,spmi-pmic-arb";
                        reg = <0 0x0c440000 0 0x1100>,
index 6cde526..42b74c2 100644 (file)
@@ -1,4 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
+dtb-$(CONFIG_ARCH_R8A774A1) += r8a774a1-hihope-rzg2m.dtb
+dtb-$(CONFIG_ARCH_R8A774A1) += r8a774a1-hihope-rzg2m-ex.dtb
 dtb-$(CONFIG_ARCH_R8A774C0) += r8a774c0-cat874.dtb r8a774c0-ek874.dtb
 dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-salvator-x.dtb r8a7795-h3ulcb.dtb
 dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-h3ulcb-kf.dtb
diff --git a/arch/arm64/boot/dts/renesas/hihope-common.dtsi b/arch/arm64/boot/dts/renesas/hihope-common.dtsi
new file mode 100644 (file)
index 0000000..3311a98
--- /dev/null
@@ -0,0 +1,325 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for the HiHope RZ/G2[MN] main board common parts
+ *
+ * Copyright (C) 2019 Renesas Electronics Corp.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+       aliases {
+               serial0 = &scif2;
+       };
+
+       chosen {
+               bootargs = "ignore_loglevel";
+               stdout-path = "serial0:115200n8";
+       };
+
+       hdmi0-out {
+               compatible = "hdmi-connector";
+               type = "a";
+
+               port {
+                       hdmi0_con: endpoint {
+                               remote-endpoint = <&rcar_dw_hdmi0_out>;
+                       };
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               led0 {
+                       gpios = <&gpio6 11 GPIO_ACTIVE_HIGH>;
+               };
+
+               led1 {
+                       gpios = <&gpio6 12 GPIO_ACTIVE_HIGH>;
+               };
+
+               led2 {
+                       gpios = <&gpio6 13 GPIO_ACTIVE_HIGH>;
+               };
+
+               led3 {
+                       gpios = <&gpio0  0 GPIO_ACTIVE_HIGH>;
+               };
+       };
+
+       reg_1p8v: regulator0 {
+               compatible = "regulator-fixed";
+               regulator-name = "fixed-1.8V";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       reg_3p3v: regulator1 {
+               compatible = "regulator-fixed";
+               regulator-name = "fixed-3.3V";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       vbus0_usb2: regulator-vbus0-usb2 {
+               compatible = "regulator-fixed";
+
+               regulator-name = "USB20_VBUS0";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+
+               gpio = <&gpio6 16 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       vccq_sdhi0: regulator-vccq-sdhi0 {
+               compatible = "regulator-gpio";
+
+               regulator-name = "SDHI0 VccQ";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <3300000>;
+
+               gpios = <&gpio6 30 GPIO_ACTIVE_HIGH>;
+               gpios-states = <1>;
+               states = <3300000 1
+                         1800000 0>;
+       };
+
+       x302_clk: x302-clock {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <33000000>;
+       };
+
+       x304_clk: x304-clock {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <25000000>;
+       };
+};
+
+&du {
+       clocks = <&cpg CPG_MOD 724>,
+                <&cpg CPG_MOD 723>,
+                <&cpg CPG_MOD 722>,
+                <&versaclock5 1>,
+                <&x302_clk>,
+                <&versaclock5 2>;
+       clock-names = "du.0", "du.1", "du.2",
+                     "dclkin.0", "dclkin.1", "dclkin.2";
+       status = "okay";
+};
+
+&ehci0 {
+       status = "okay";
+};
+
+&ehci1 {
+       status = "okay";
+};
+
+&extal_clk {
+       clock-frequency = <16666666>;
+};
+
+&extalr_clk {
+       clock-frequency = <32768>;
+};
+
+&gpio6 {
+       usb1-reset {
+               gpio-hog;
+               gpios = <10 GPIO_ACTIVE_LOW>;
+               output-low;
+               line-name = "usb1-reset";
+       };
+};
+
+&hdmi0 {
+       status = "okay";
+
+       ports {
+               port@1 {
+                       reg = <1>;
+                       rcar_dw_hdmi0_out: endpoint {
+                               remote-endpoint = <&hdmi0_con>;
+                       };
+               };
+       };
+};
+
+&hsusb {
+       dr_mode = "otg";
+       status = "okay";
+};
+
+&i2c4 {
+       clock-frequency = <400000>;
+       status = "okay";
+
+       versaclock5: clock-generator@6a {
+               compatible = "idt,5p49v5923";
+               reg = <0x6a>;
+               #clock-cells = <1>;
+               clocks = <&x304_clk>;
+               clock-names = "xin";
+       };
+};
+
+&ohci0 {
+       status = "okay";
+};
+
+&ohci1 {
+       status = "okay";
+};
+
+&pcie_bus_clk {
+       clock-frequency = <100000000>;
+};
+
+&pfc {
+       pinctrl-0 = <&scif_clk_pins>;
+       pinctrl-names = "default";
+
+       scif2_pins: scif2 {
+               groups = "scif2_data_a";
+               function = "scif2";
+       };
+
+       scif_clk_pins: scif_clk {
+               groups = "scif_clk_a";
+               function = "scif_clk";
+       };
+
+       sdhi0_pins: sd0 {
+               groups = "sdhi0_data4", "sdhi0_ctrl";
+               function = "sdhi0";
+               power-source = <3300>;
+       };
+
+       sdhi0_pins_uhs: sd0_uhs {
+               groups = "sdhi0_data4", "sdhi0_ctrl";
+               function = "sdhi0";
+               power-source = <1800>;
+       };
+
+       sdhi3_pins: sd3 {
+               groups = "sdhi3_data8", "sdhi3_ctrl", "sdhi3_ds";
+               function = "sdhi3";
+               power-source = <1800>;
+       };
+
+       usb0_pins: usb0 {
+               groups = "usb0";
+               function = "usb0";
+       };
+
+       usb1_pins: usb1 {
+               mux {
+                       groups = "usb1";
+                       function = "usb1";
+               };
+
+               ovc {
+                       pins = "GP_6_27";
+                       bias-pull-up;
+               };
+       };
+
+       usb30_pins: usb30 {
+               groups = "usb30";
+               function = "usb30";
+       };
+};
+
+&rwdt {
+       timeout-sec = <60>;
+       status = "okay";
+};
+
+&scif2 {
+       pinctrl-0 = <&scif2_pins>;
+       pinctrl-names = "default";
+
+       status = "okay";
+};
+
+&scif_clk {
+       clock-frequency = <14745600>;
+};
+
+&sdhi0 {
+       pinctrl-0 = <&sdhi0_pins>;
+       pinctrl-1 = <&sdhi0_pins_uhs>;
+       pinctrl-names = "default", "state_uhs";
+
+       vmmc-supply = <&reg_3p3v>;
+       vqmmc-supply = <&vccq_sdhi0>;
+       cd-gpios = <&gpio3 12 GPIO_ACTIVE_LOW>;
+       bus-width = <4>;
+       sd-uhs-sdr50;
+       sd-uhs-sdr104;
+       status = "okay";
+};
+
+&sdhi3 {
+       pinctrl-0 = <&sdhi3_pins>;
+       pinctrl-1 = <&sdhi3_pins>;
+       pinctrl-names = "default", "state_uhs";
+
+       vmmc-supply = <&reg_3p3v>;
+       vqmmc-supply = <&reg_1p8v>;
+       bus-width = <8>;
+       mmc-hs200-1_8v;
+       non-removable;
+       fixed-emmc-driver-type = <1>;
+};
+
+&usb_extal_clk {
+       clock-frequency = <50000000>;
+};
+
+&usb2_phy0 {
+       pinctrl-0 = <&usb0_pins>;
+       pinctrl-names = "default";
+
+       vbus-supply = <&vbus0_usb2>;
+       status = "okay";
+};
+
+&usb2_phy1 {
+       pinctrl-0 = <&usb1_pins>;
+       pinctrl-names = "default";
+
+       status = "okay";
+};
+
+&usb3_peri0 {
+       phys = <&usb3_phy0>;
+       phy-names = "usb";
+
+       companion = <&xhci0>;
+
+       status = "okay";
+};
+
+&usb3_phy0 {
+       status = "okay";
+};
+
+&usb3s0_clk {
+       clock-frequency = <100000000>;
+};
+
+&xhci0 {
+       pinctrl-0 = <&usb30_pins>;
+       pinctrl-names = "default";
+
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/renesas/hihope-rzg2-ex.dtsi b/arch/arm64/boot/dts/renesas/hihope-rzg2-ex.dtsi
new file mode 100644 (file)
index 0000000..07a6eea
--- /dev/null
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for the RZ/G2[MN] HiHope sub board common parts
+ *
+ * Copyright (C) 2019 Renesas Electronics Corp.
+ */
+
+/ {
+       aliases {
+               ethernet0 = &avb;
+       };
+
+       chosen {
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
+       };
+};
+
+&avb {
+       pinctrl-0 = <&avb_pins>;
+       pinctrl-names = "default";
+       phy-handle = <&phy0>;
+       phy-mode = "rgmii-txid";
+       status = "okay";
+
+       phy0: ethernet-phy@0 {
+               rxc-skew-ps = <1500>;
+               reg = <0>;
+               interrupt-parent = <&gpio2>;
+               interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+               reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
+       };
+};
+
+&pciec0 {
+       status = "okay";
+};
+
+&pciec1 {
+       status = "okay";
+};
+
+&pfc {
+       pinctrl-0 = <&scif_clk_pins>;
+       pinctrl-names = "default";
+
+       avb_pins: avb {
+               mux {
+                       groups = "avb_link", "avb_mdio", "avb_mii";
+                       function = "avb";
+               };
+
+               pins_mdio {
+                       groups = "avb_mdio";
+                       drive-strength = <24>;
+               };
+
+               pins_mii_tx {
+                       pins = "PIN_AVB_TX_CTL", "PIN_AVB_TXC", "PIN_AVB_TD0",
+                              "PIN_AVB_TD1", "PIN_AVB_TD2", "PIN_AVB_TD3";
+                       drive-strength = <12>;
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/renesas/r8a774a1-hihope-rzg2m-ex.dts b/arch/arm64/boot/dts/renesas/r8a774a1-hihope-rzg2m-ex.dts
new file mode 100644 (file)
index 0000000..6e33a3b
--- /dev/null
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for the HiHope RZ/G2M sub board
+ *
+ * Copyright (C) 2019 Renesas Electronics Corp.
+ */
+
+#include "r8a774a1-hihope-rzg2m.dts"
+#include "hihope-rzg2-ex.dtsi"
+
+/ {
+       model = "HopeRun HiHope RZ/G2M with sub board";
+       compatible = "hoperun,hihope-rzg2-ex", "hoperun,hihope-rzg2m",
+                    "renesas,r8a774a1";
+};
diff --git a/arch/arm64/boot/dts/renesas/r8a774a1-hihope-rzg2m.dts b/arch/arm64/boot/dts/renesas/r8a774a1-hihope-rzg2m.dts
new file mode 100644 (file)
index 0000000..93ca973
--- /dev/null
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for the HiHope RZ/G2M main board
+ *
+ * Copyright (C) 2019 Renesas Electronics Corp.
+ */
+
+/dts-v1/;
+#include "r8a774a1.dtsi"
+#include "hihope-common.dtsi"
+
+/ {
+       model = "HopeRun HiHope RZ/G2M main board based on r8a774a1";
+       compatible = "hoperun,hihope-rzg2m", "renesas,r8a774a1";
+
+       memory@48000000 {
+               device_type = "memory";
+               /* first 128MB is reserved for secure area. */
+               reg = <0x0 0x48000000 0x0 0x78000000>;
+       };
+
+       memory@600000000 {
+               device_type = "memory";
+               reg = <0x6 0x00000000 0x0 0x80000000>;
+       };
+};
index de282c4..f209457 100644 (file)
                clock-frequency = <0>;
        };
 
+       cluster0_opp: opp_table0 {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp-500000000 {
+                       opp-hz = /bits/ 64 <500000000>;
+                       opp-microvolt = <820000>;
+                       clock-latency-ns = <300000>;
+               };
+               opp-1000000000 {
+                       opp-hz = /bits/ 64 <1000000000>;
+                       opp-microvolt = <820000>;
+                       clock-latency-ns = <300000>;
+               };
+               opp-1500000000 {
+                       opp-hz = /bits/ 64 <1500000000>;
+                       opp-microvolt = <820000>;
+                       clock-latency-ns = <300000>;
+               };
+       };
+
+       cluster1_opp: opp_table1 {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp-800000000 {
+                       opp-hz = /bits/ 64 <800000000>;
+                       opp-microvolt = <820000>;
+                       clock-latency-ns = <300000>;
+               };
+               opp-1000000000 {
+                       opp-hz = /bits/ 64 <1000000000>;
+                       opp-microvolt = <820000>;
+                       clock-latency-ns = <300000>;
+               };
+               opp-1200000000 {
+                       opp-hz = /bits/ 64 <1200000000>;
+                       opp-microvolt = <820000>;
+                       clock-latency-ns = <300000>;
+               };
+       };
+
        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
 
+               cpu-map {
+                       cluster0 {
+                               core0 {
+                                       cpu = <&a57_0>;
+                               };
+                               core1 {
+                                       cpu = <&a57_1>;
+                               };
+                       };
+
+                       cluster1 {
+                               core0 {
+                                       cpu = <&a53_0>;
+                               };
+                               core1 {
+                                       cpu = <&a53_1>;
+                               };
+                               core2 {
+                                       cpu = <&a53_2>;
+                               };
+                               core3 {
+                                       cpu = <&a53_3>;
+                               };
+                       };
+               };
+
                a57_0: cpu@0 {
                        compatible = "arm,cortex-a57";
                        reg = <0x0>;
                        power-domains = <&sysc R8A774A1_PD_CA57_CPU0>;
                        next-level-cache = <&L2_CA57>;
                        enable-method = "psci";
+                       dynamic-power-coefficient = <854>;
                        clocks = <&cpg CPG_CORE R8A774A1_CLK_Z>;
+                       operating-points-v2 = <&cluster0_opp>;
+                       capacity-dmips-mhz = <1024>;
+                       #cooling-cells = <2>;
                };
 
                a57_1: cpu@1 {
                        next-level-cache = <&L2_CA57>;
                        enable-method = "psci";
                        clocks = <&cpg CPG_CORE R8A774A1_CLK_Z>;
+                       operating-points-v2 = <&cluster0_opp>;
+                       capacity-dmips-mhz = <1024>;
+                       #cooling-cells = <2>;
                };
 
                a53_0: cpu@100 {
                        power-domains = <&sysc R8A774A1_PD_CA53_CPU0>;
                        next-level-cache = <&L2_CA53>;
                        enable-method = "psci";
+                       #cooling-cells = <2>;
+                       dynamic-power-coefficient = <277>;
                        clocks = <&cpg CPG_CORE R8A774A1_CLK_Z2>;
+                       operating-points-v2 = <&cluster1_opp>;
+                       capacity-dmips-mhz = <560>;
                };
 
                a53_1: cpu@101 {
                        next-level-cache = <&L2_CA53>;
                        enable-method = "psci";
                        clocks = <&cpg CPG_CORE R8A774A1_CLK_Z2>;
+                       operating-points-v2 = <&cluster1_opp>;
+                       capacity-dmips-mhz = <560>;
                };
 
                a53_2: cpu@102 {
                        next-level-cache = <&L2_CA53>;
                        enable-method = "psci";
                        clocks = <&cpg CPG_CORE R8A774A1_CLK_Z2>;
+                       operating-points-v2 = <&cluster1_opp>;
+                       capacity-dmips-mhz = <560>;
                };
 
                a53_3: cpu@103 {
                        next-level-cache = <&L2_CA53>;
                        enable-method = "psci";
                        clocks = <&cpg CPG_CORE R8A774A1_CLK_Z2>;
+                       operating-points-v2 = <&cluster1_opp>;
+                       capacity-dmips-mhz = <560>;
                };
 
                L2_CA57: cache-controller-0 {
                        reg = <0 0xe6060000 0 0x50c>;
                };
 
+               cmt0: timer@e60f0000 {
+                       compatible = "renesas,r8a774a1-cmt0",
+                                    "renesas,rcar-gen3-cmt0";
+                       reg = <0 0xe60f0000 0 0x1004>;
+                       interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 303>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
+                       resets = <&cpg 303>;
+                       status = "disabled";
+               };
+
+               cmt1: timer@e6130000 {
+                       compatible = "renesas,r8a774a1-cmt1",
+                                    "renesas,rcar-gen3-cmt1";
+                       reg = <0 0xe6130000 0 0x1004>;
+                       interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 302>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
+                       resets = <&cpg 302>;
+                       status = "disabled";
+               };
+
+               cmt2: timer@e6140000 {
+                       compatible = "renesas,r8a774a1-cmt1",
+                                    "renesas,rcar-gen3-cmt1";
+                       reg = <0 0xe6140000 0 0x1004>;
+                       interrupts = <GIC_SPI 398 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 399 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 400 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 401 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 402 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 403 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 404 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 405 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 301>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
+                       resets = <&cpg 301>;
+                       status = "disabled";
+               };
+
+               cmt3: timer@e6148000 {
+                       compatible = "renesas,r8a774a1-cmt1",
+                                    "renesas,rcar-gen3-cmt1";
+                       reg = <0 0xe6148000 0 0x1004>;
+                       interrupts = <GIC_SPI 470 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 471 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 472 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 473 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 474 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 475 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 476 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 477 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 300>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
+                       resets = <&cpg 300>;
+                       status = "disabled";
+               };
+
                cpg: clock-controller@e6150000 {
                        compatible = "renesas,r8a774a1-cpg-mssr";
                        reg = <0 0xe6150000 0 0x0bb0>;
                        resets = <&cpg 407>;
                };
 
+               tmu0: timer@e61e0000 {
+                       compatible = "renesas,tmu-r8a774a1", "renesas,tmu";
+                       reg = <0 0xe61e0000 0 0x30>;
+                       interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 125>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
+                       resets = <&cpg 125>;
+                       status = "disabled";
+               };
+
+               tmu1: timer@e6fc0000 {
+                       compatible = "renesas,tmu-r8a774a1", "renesas,tmu";
+                       reg = <0 0xe6fc0000 0 0x30>;
+                       interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 124>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
+                       resets = <&cpg 124>;
+                       status = "disabled";
+               };
+
+               tmu2: timer@e6fd0000 {
+                       compatible = "renesas,tmu-r8a774a1", "renesas,tmu";
+                       reg = <0 0xe6fd0000 0 0x30>;
+                       interrupts = <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 123>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
+                       resets = <&cpg 123>;
+                       status = "disabled";
+               };
+
+               tmu3: timer@e6fe0000 {
+                       compatible = "renesas,tmu-r8a774a1", "renesas,tmu";
+                       reg = <0 0xe6fe0000 0 0x30>;
+                       interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 122>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
+                       resets = <&cpg 122>;
+                       status = "disabled";
+               };
+
+               tmu4: timer@ffc00000 {
+                       compatible = "renesas,tmu-r8a774a1", "renesas,tmu";
+                       reg = <0 0xffc00000 0 0x30>;
+                       interrupts = <GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 121>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
+                       resets = <&cpg 121>;
+                       status = "disabled";
+               };
+
                i2c0: i2c@e6500000 {
                        #address-cells = <1>;
                        #size-cells = <0>;
                                     "renesas,rcar-gen3-usbhs";
                        reg = <0 0xe6590000 0 0x200>;
                        interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&cpg CPG_MOD 704>;
+                       clocks = <&cpg CPG_MOD 704>, <&cpg CPG_MOD 703>;
                        dmas = <&usb_dmac0 0>, <&usb_dmac0 1>,
                               <&usb_dmac1 0>, <&usb_dmac1 1>;
                        dma-names = "ch0", "ch1", "ch2", "ch3";
                        renesas,buswait = <11>;
-                       phys = <&usb2_phy0>;
+                       phys = <&usb2_phy0 3>;
                        phy-names = "usb";
                        power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
-                       resets = <&cpg 704>;
+                       resets = <&cpg 704>, <&cpg 703>;
                        status = "disabled";
                };
 
                        resets = <&cpg 219>;
                        #dma-cells = <1>;
                        dma-channels = <16>;
+                       iommus = <&ipmmu_ds0 0>, <&ipmmu_ds0 1>,
+                              <&ipmmu_ds0 2>, <&ipmmu_ds0 3>,
+                              <&ipmmu_ds0 4>, <&ipmmu_ds0 5>,
+                              <&ipmmu_ds0 6>, <&ipmmu_ds0 7>,
+                              <&ipmmu_ds0 8>, <&ipmmu_ds0 9>,
+                              <&ipmmu_ds0 10>, <&ipmmu_ds0 11>,
+                              <&ipmmu_ds0 12>, <&ipmmu_ds0 13>,
+                              <&ipmmu_ds0 14>, <&ipmmu_ds0 15>;
                };
 
                dmac1: dma-controller@e7300000 {
                        resets = <&cpg 218>;
                        #dma-cells = <1>;
                        dma-channels = <16>;
+                       iommus = <&ipmmu_ds1 0>, <&ipmmu_ds1 1>,
+                              <&ipmmu_ds1 2>, <&ipmmu_ds1 3>,
+                              <&ipmmu_ds1 4>, <&ipmmu_ds1 5>,
+                              <&ipmmu_ds1 6>, <&ipmmu_ds1 7>,
+                              <&ipmmu_ds1 8>, <&ipmmu_ds1 9>,
+                              <&ipmmu_ds1 10>, <&ipmmu_ds1 11>,
+                              <&ipmmu_ds1 12>, <&ipmmu_ds1 13>,
+                              <&ipmmu_ds1 14>, <&ipmmu_ds1 15>;
                };
 
                dmac2: dma-controller@e7310000 {
                        resets = <&cpg 217>;
                        #dma-cells = <1>;
                        dma-channels = <16>;
+                       iommus = <&ipmmu_ds1 16>, <&ipmmu_ds1 17>,
+                              <&ipmmu_ds1 18>, <&ipmmu_ds1 19>,
+                              <&ipmmu_ds1 20>, <&ipmmu_ds1 21>,
+                              <&ipmmu_ds1 22>, <&ipmmu_ds1 23>,
+                              <&ipmmu_ds1 24>, <&ipmmu_ds1 25>,
+                              <&ipmmu_ds1 26>, <&ipmmu_ds1 27>,
+                              <&ipmmu_ds1 28>, <&ipmmu_ds1 29>,
+                              <&ipmmu_ds1 30>, <&ipmmu_ds1 31>;
                };
 
                ipmmu_ds0: mmu@e6740000 {
                        power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
                        resets = <&cpg 812>;
                        phy-mode = "rgmii";
+                       iommus = <&ipmmu_ds0 16>;
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "disabled";
                        resets = <&cpg 502>;
                        #dma-cells = <1>;
                        dma-channels = <16>;
+                       iommus = <&ipmmu_mp 0>, <&ipmmu_mp 1>,
+                              <&ipmmu_mp 2>, <&ipmmu_mp 3>,
+                              <&ipmmu_mp 4>, <&ipmmu_mp 5>,
+                              <&ipmmu_mp 6>, <&ipmmu_mp 7>,
+                              <&ipmmu_mp 8>, <&ipmmu_mp 9>,
+                              <&ipmmu_mp 10>, <&ipmmu_mp 11>,
+                              <&ipmmu_mp 12>, <&ipmmu_mp 13>,
+                              <&ipmmu_mp 14>, <&ipmmu_mp 15>;
                };
 
                audma1: dma-controller@ec720000 {
                        resets = <&cpg 501>;
                        #dma-cells = <1>;
                        dma-channels = <16>;
+                       iommus = <&ipmmu_mp 16>, <&ipmmu_mp 17>,
+                              <&ipmmu_mp 18>, <&ipmmu_mp 19>,
+                              <&ipmmu_mp 20>, <&ipmmu_mp 21>,
+                              <&ipmmu_mp 22>, <&ipmmu_mp 23>,
+                              <&ipmmu_mp 24>, <&ipmmu_mp 25>,
+                              <&ipmmu_mp 26>, <&ipmmu_mp 27>,
+                              <&ipmmu_mp 28>, <&ipmmu_mp 29>,
+                              <&ipmmu_mp 30>, <&ipmmu_mp 31>;
                };
 
                xhci0: usb@ee000000 {
                        compatible = "generic-ohci";
                        reg = <0 0xee080000 0 0x100>;
                        interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&cpg CPG_MOD 703>;
-                       phys = <&usb2_phy0>;
+                       clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
+                       phys = <&usb2_phy0 1>;
                        phy-names = "usb";
                        power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
-                       resets = <&cpg 703>;
+                       resets = <&cpg 703>, <&cpg 704>;
                        status = "disabled";
                };
 
                        reg = <0 0xee0a0000 0 0x100>;
                        interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 702>;
-                       phys = <&usb2_phy1>;
+                       phys = <&usb2_phy1 1>;
                        phy-names = "usb";
                        power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
                        resets = <&cpg 702>;
                        compatible = "generic-ehci";
                        reg = <0 0xee080100 0 0x100>;
                        interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&cpg CPG_MOD 703>;
-                       phys = <&usb2_phy0>;
+                       clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
+                       phys = <&usb2_phy0 2>;
                        phy-names = "usb";
                        companion = <&ohci0>;
                        power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
-                       resets = <&cpg 703>;
+                       resets = <&cpg 703>, <&cpg 704>;
                        status = "disabled";
                };
 
                        reg = <0 0xee0a0100 0 0x100>;
                        interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 702>;
-                       phys = <&usb2_phy1>;
+                       phys = <&usb2_phy1 2>;
                        phy-names = "usb";
                        companion = <&ohci1>;
                        power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
                                     "renesas,rcar-gen3-usb2-phy";
                        reg = <0 0xee080200 0 0x700>;
                        interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&cpg CPG_MOD 703>;
+                       clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
                        power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
-                       resets = <&cpg 703>;
-                       #phy-cells = <0>;
+                       resets = <&cpg 703>, <&cpg 704>;
+                       #phy-cells = <1>;
                        status = "disabled";
                };
 
                        clocks = <&cpg CPG_MOD 702>;
                        power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
                        resets = <&cpg 702>;
-                       #phy-cells = <0>;
+                       #phy-cells = <1>;
                        status = "disabled";
                };
 
                        resets = <&cpg 408>;
                };
 
+               pciec0: pcie@fe000000 {
+                       compatible = "renesas,pcie-r8a774a1",
+                                    "renesas,pcie-rcar-gen3";
+                       reg = <0 0xfe000000 0 0x80000>;
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       bus-range = <0x00 0xff>;
+                       device_type = "pci";
+                       ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000
+                               0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000
+                               0x02000000 0 0x30000000 0 0x30000000 0 0x08000000
+                               0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>;
+                       /* Map all possible DDR as inbound ranges */
+                       dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x80000000>;
+                       interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+                               <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+                               <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 0>;
+                       interrupt-map = <0 0 0 0 &gic GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 319>, <&pcie_bus_clk>;
+                       clock-names = "pcie", "pcie_bus";
+                       power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
+                       resets = <&cpg 319>;
+                       status = "disabled";
+               };
+
+               pciec1: pcie@ee800000 {
+                       compatible = "renesas,pcie-r8a774a1",
+                                    "renesas,pcie-rcar-gen3";
+                       reg = <0 0xee800000 0 0x80000>;
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       bus-range = <0x00 0xff>;
+                       device_type = "pci";
+                       ranges = <0x01000000 0 0x00000000 0 0xee900000 0 0x00100000
+                               0x02000000 0 0xeea00000 0 0xeea00000 0 0x00200000
+                               0x02000000 0 0xc0000000 0 0xc0000000 0 0x08000000
+                               0x42000000 0 0xc8000000 0 0xc8000000 0 0x08000000>;
+                       /* Map all possible DDR as inbound ranges */
+                       dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x80000000>;
+                       interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>,
+                               <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>,
+                               <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 0>;
+                       interrupt-map = <0 0 0 0 &gic GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 318>, <&pcie_bus_clk>;
+                       clock-names = "pcie", "pcie_bus";
+                       power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
+                       resets = <&cpg 318>;
+                       status = "disabled";
+               };
+
+               fdp1@fe940000 {
+                       compatible = "renesas,fdp1";
+                       reg = <0 0xfe940000 0 0x2400>;
+                       interrupts = <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 119>;
+                       power-domains = <&sysc R8A774A1_PD_A3VC>;
+                       resets = <&cpg 119>;
+                       renesas,fcp = <&fcpf0>;
+               };
+
                fcpf0: fcp@fe950000 {
                        compatible = "renesas,fcpf";
                        reg = <0 0xfe950000 0 0x200>;
                        iommus = <&ipmmu_vc0 19>;
                };
 
+               vspb: vsp@fe960000 {
+                       compatible = "renesas,vsp2";
+                       reg = <0 0xfe960000 0 0x8000>;
+                       interrupts = <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 626>;
+                       power-domains = <&sysc R8A774A1_PD_A3VC>;
+                       resets = <&cpg 626>;
+
+                       renesas,fcp = <&fcpvb0>;
+               };
+
+               vspd0: vsp@fea20000 {
+                       compatible = "renesas,vsp2";
+                       reg = <0 0xfea20000 0 0x5000>;
+                       interrupts = <GIC_SPI 466 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 623>;
+                       power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
+                       resets = <&cpg 623>;
+
+                       renesas,fcp = <&fcpvd0>;
+               };
+
+               vspd1: vsp@fea28000 {
+                       compatible = "renesas,vsp2";
+                       reg = <0 0xfea28000 0 0x5000>;
+                       interrupts = <GIC_SPI 467 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 622>;
+                       power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
+                       resets = <&cpg 622>;
+
+                       renesas,fcp = <&fcpvd1>;
+               };
+
+               vspd2: vsp@fea30000 {
+                       compatible = "renesas,vsp2";
+                       reg = <0 0xfea30000 0 0x5000>;
+                       interrupts = <GIC_SPI 468 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 621>;
+                       power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
+                       resets = <&cpg 621>;
+
+                       renesas,fcp = <&fcpvd2>;
+               };
+
+               vspi0: vsp@fe9a0000 {
+                       compatible = "renesas,vsp2";
+                       reg = <0 0xfe9a0000 0 0x8000>;
+                       interrupts = <GIC_SPI 444 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 631>;
+                       power-domains = <&sysc R8A774A1_PD_A3VC>;
+                       resets = <&cpg 631>;
+
+                       renesas,fcp = <&fcpvi0>;
+               };
+
                csi20: csi2@fea80000 {
                        compatible = "renesas,r8a774a1-csi2";
                        reg = <0 0xfea80000 0 0x10000>;
                        };
                };
 
+               hdmi0: hdmi@fead0000 {
+                       compatible = "renesas,r8a774a1-hdmi",
+                                    "renesas,rcar-gen3-hdmi";
+                       reg = <0 0xfead0000 0 0x10000>;
+                       interrupts = <GIC_SPI 389 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 729>,
+                                <&cpg CPG_CORE R8A774A1_CLK_HDMI>;
+                       clock-names = "iahb", "isfr";
+                       power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
+                       resets = <&cpg 729>;
+                       status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               port@0 {
+                                       reg = <0>;
+                                       dw_hdmi0_in: endpoint {
+                                               remote-endpoint = <&du_out_hdmi0>;
+                                       };
+                               };
+                               port@1 {
+                                       reg = <1>;
+                               };
+                               port@2 {
+                                       /* HDMI sound */
+                                       reg = <2>;
+                               };
+                       };
+               };
+
+               du: display@feb00000 {
+                       compatible = "renesas,du-r8a774a1";
+                       reg = <0 0xfeb00000 0 0x70000>;
+                       interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 724>,
+                                <&cpg CPG_MOD 723>,
+                                <&cpg CPG_MOD 722>;
+                       clock-names = "du.0", "du.1", "du.2";
+                       status = "disabled";
+
+                       vsps = <&vspd0 &vspd1 &vspd2>;
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+                                       du_out_rgb: endpoint {
+                                       };
+                               };
+                               port@1 {
+                                       reg = <1>;
+                                       du_out_hdmi0: endpoint {
+                                               remote-endpoint = <&dw_hdmi0_in>;
+                                       };
+                               };
+                               port@2 {
+                                       reg = <2>;
+                                       du_out_lvds0: endpoint {
+                                               remote-endpoint = <&lvds0_in>;
+                                       };
+                               };
+                       };
+               };
+
+               lvds0: lvds@feb90000 {
+                       compatible = "renesas,r8a774a1-lvds";
+                       reg = <0 0xfeb90000 0 0x14>;
+                       clocks = <&cpg CPG_MOD 727>;
+                       power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
+                       resets = <&cpg 727>;
+                       status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+                                       lvds0_in: endpoint {
+                                               remote-endpoint = <&du_out_lvds0>;
+                                       };
+                               };
+                               port@1 {
+                                       reg = <1>;
+                                       lvds0_out: endpoint {
+                                       };
+                               };
+                       };
+               };
+
                prr: chipid@fff00044 {
                        compatible = "renesas,prr";
                        reg = <0 0xfff00044 0 4>;
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
                        thermal-sensors = <&tsc 0>;
+                       sustainable-power = <3874>;
 
                        trips {
                                sensor1_crit: sensor1-crit {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
                        thermal-sensors = <&tsc 1>;
+                       sustainable-power = <3874>;
 
                        trips {
                                sensor2_crit: sensor2-crit {
                                        type = "critical";
                                };
                        };
-
                };
 
                sensor_thermal3: sensor-thermal3 {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
                        thermal-sensors = <&tsc 2>;
+                       sustainable-power = <3874>;
 
                        trips {
+                               target: trip-point1 {
+                                       temperature = <100000>;
+                                       hysteresis = <1000>;
+                                       type = "passive";
+                               };
+
                                sensor3_crit: sensor3-crit {
                                        temperature = <120000>;
                                        hysteresis = <1000>;
                                        type = "critical";
                                };
                        };
+                       cooling-maps {
+                               map0 {
+                                       trip = <&target>;
+                                       cooling-device = <&a57_0 0 2>;
+                                       contribution = <1024>;
+                               };
+                               map1 {
+                                       trip = <&target>;
+                                       cooling-device = <&a53_0 0 2>;
+                                       contribution = <1024>;
+                               };
+                       };
                };
        };
 
index 013a48c..46a77ee 100644 (file)
@@ -8,6 +8,7 @@
 /dts-v1/;
 #include "r8a774c0.dtsi"
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/display/tda998x.h>
 
 / {
        model = "Silicon Linux RZ/G2E 96board platform (CAT874)";
 
        aliases {
                serial0 = &scif2;
+               serial1 = &hscif2;
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial0:115200n8";
        };
 
+       hdmi-out {
+               compatible = "hdmi-connector";
+               type = "a";
+
+               port {
+                       hdmi_con_out: endpoint {
+                               remote-endpoint = <&tda19988_out>;
+                       };
+               };
+       };
+
        leds {
                compatible = "gpio-leds";
 
                reg = <0x0 0x48000000 0x0 0x78000000>;
        };
 
+       sound: sound {
+               compatible = "simple-audio-card";
+
+               simple-audio-card,name = "CAT874 HDMI sound";
+               simple-audio-card,format = "i2s";
+               simple-audio-card,bitclock-master = <&sndcpu>;
+               simple-audio-card,frame-master = <&sndcpu>;
+
+               sndcpu: simple-audio-card,cpu {
+                       sound-dai = <&rcar_sound>;
+               };
+
+               sndcodec: simple-audio-card,codec {
+                       sound-dai = <&tda19988>;
+               };
+       };
+
        vcc_sdhi0: regulator-vcc-sdhi0 {
                compatible = "regulator-fixed";
 
                states = <3300000 1
                          1800000 0>;
        };
+
+       wlan_en_reg: fixedregulator {
+               compatible = "regulator-fixed";
+               regulator-name = "wlan-en-regulator";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               startup-delay-us = <70000>;
+
+               gpio = <&gpio2 25 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       x13_clk: x13 {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <74250000>;
+       };
+};
+
+&audio_clk_a {
+       clock-frequency = <22579200>;
+};
+
+&du {
+       pinctrl-0 = <&du_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+
+       clocks = <&cpg CPG_MOD 724>,
+                <&cpg CPG_MOD 723>,
+                <&x13_clk>;
+       clock-names = "du.0", "du.1", "dclkin.0";
+
+       ports {
+               port@0 {
+                       endpoint {
+                               remote-endpoint = <&tda19988_in>;
+                       };
+               };
+       };
 };
 
 &ehci0 {
        clock-frequency = <48000000>;
 };
 
+&hscif2 {
+       pinctrl-0 = <&hscif2_pins>;
+       pinctrl-names = "default";
+
+       uart-has-rtscts;
+       status = "okay";
+
+       bluetooth {
+               compatible = "ti,wl1837-st";
+               enable-gpios = <&gpio4 6 GPIO_ACTIVE_HIGH>;
+       };
+};
+
+&i2c0 {
+       status = "okay";
+       clock-frequency = <100000>;
+
+       hd3ss3220@47 {
+               compatible = "ti,hd3ss3220";
+               reg = <0x47>;
+               interrupt-parent = <&gpio6>;
+               interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+
+               connector {
+                       compatible = "usb-c-connector";
+                       label = "USB-C";
+                       data-role = "dual";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@1 {
+                                       reg = <1>;
+                                       hd3ss3220_ep: endpoint {
+                                               remote-endpoint = <&usb3_role_switch>;
+                                       };
+                               };
+                       };
+               };
+       };
+
+       tda19988: tda19988@70 {
+               compatible = "nxp,tda998x";
+               reg = <0x70>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
+
+               video-ports = <0x234501>;
+
+               #sound-dai-cells = <0>;
+               audio-ports = <TDA998x_I2S 0x03>;
+               clocks = <&rcar_sound 1>;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+                               tda19988_in: endpoint {
+                                       remote-endpoint = <&du_out_rgb>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+                               tda19988_out: endpoint {
+                                       remote-endpoint = <&hdmi_con_out>;
+                               };
+                       };
+               };
+       };
+};
+
 &i2c1 {
        pinctrl-0 = <&i2c1_pins>;
        pinctrl-names = "default";
        };
 };
 
+&lvds0 {
+       status = "okay";
+
+       clocks = <&cpg CPG_MOD 727>, <&x13_clk>, <&extal_clk>;
+       clock-names = "fck", "dclkin.0", "extal";
+};
+
 &ohci0 {
        dr_mode = "host";
        status = "okay";
 };
 
 &pfc {
+       du_pins: du {
+               groups = "du_rgb888", "du_clk_out_0", "du_sync", "du_disp",
+                        "du_clk_in_0";
+               function = "du";
+       };
+
        i2c1_pins: i2c1 {
                groups = "i2c1_b";
                function = "i2c1";
        };
 
+       hscif2_pins: hscif2 {
+               groups = "hscif2_data_a", "hscif2_ctrl_a";
+               function = "hscif2";
+       };
+
        scif2_pins: scif2 {
                groups = "scif2_data_a";
                function = "scif2";
                function = "sdhi0";
                power-source = <1800>;
        };
+
+       sdhi3_pins: sd3 {
+               groups = "sdhi3_data4", "sdhi3_ctrl";
+               function = "sdhi3";
+               power-source = <1800>;
+       };
+
+       sound_pins: sound {
+               groups = "ssi01239_ctrl", "ssi0_data";
+               function = "ssi";
+       };
+
+       sound_clk_pins: sound_clk {
+               groups = "audio_clkout1_a";
+               function = "audio_clk";
+       };
+
+       usb30_pins: usb30 {
+               groups = "usb30", "usb30_id";
+               function = "usb30";
+       };
+};
+
+&rcar_sound {
+       pinctrl-0 = <&sound_pins &sound_clk_pins>;
+       pinctrl-names = "default";
+
+       /* Single DAI */
+       #sound-dai-cells = <0>;
+
+       /* audio_clkout0/1/2/3 */
+       #clock-cells = <1>;
+       clock-frequency = <11289600>;
+
+       status = "okay";
+
+       rcar_sound,dai {
+               dai0 {
+                       playback = <&ssi0 &src0 &dvc0>;
+               };
+       };
 };
 
 &rwdt {
        status = "okay";
 };
 
+&sdhi3 {
+       status = "okay";
+       pinctrl-0 = <&sdhi3_pins>;
+       pinctrl-names = "default";
+
+       vmmc-supply = <&wlan_en_reg>;
+       bus-width = <4>;
+       non-removable;
+       cap-power-off-card;
+       keep-power-in-suspend;
+
+       #address-cells = <1>;
+       #size-cells = <0>;
+       wlcore: wlcore@2 {
+               compatible = "ti,wl1837";
+               reg = <2>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
+       };
+};
+
 &usb2_phy0 {
        renesas,no-otg-pins;
        status = "okay";
 };
+
+&usb3_peri0 {
+       companion = <&xhci0>;
+       status = "okay";
+       usb-role-switch;
+
+       port {
+               usb3_role_switch: endpoint {
+                       remote-endpoint = <&hd3ss3220_ep>;
+               };
+       };
+};
+
+&xhci0 {
+       pinctrl-0 = <&usb30_pins>;
+       pinctrl-names = "default";
+
+       status = "okay";
+};
index 3f86db1..e7b5bf2 100644 (file)
@@ -70,7 +70,7 @@
                #size-cells = <0>;
 
                a53_0: cpu@0 {
-                       compatible = "arm,cortex-a53", "arm,armv8";
+                       compatible = "arm,cortex-a53";
                        reg = <0>;
                        device_type = "cpu";
                        power-domains = <&sysc R8A774C0_PD_CA53_CPU0>;
@@ -81,7 +81,7 @@
                };
 
                a53_1: cpu@1 {
-                       compatible = "arm,cortex-a53", "arm,armv8";
+                       compatible = "arm,cortex-a53";
                        reg = <1>;
                        device_type = "cpu";
                        power-domains = <&sysc R8A774C0_PD_CA53_CPU1>;
                               <&usb_dmac1 0>, <&usb_dmac1 1>;
                        dma-names = "ch0", "ch1", "ch2", "ch3";
                        renesas,buswait = <11>;
-                       phys = <&usb2_phy0>;
+                       phys = <&usb2_phy0 3>;
                        phy-names = "usb";
                        power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
                        resets = <&cpg 704>, <&cpg 703>;
                        reg = <0 0xee080000 0 0x100>;
                        interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
-                       phys = <&usb2_phy0>;
+                       phys = <&usb2_phy0 1>;
                        phy-names = "usb";
                        power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
                        resets = <&cpg 703>, <&cpg 704>;
                        reg = <0 0xee080100 0 0x100>;
                        interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
-                       phys = <&usb2_phy0>;
+                       phys = <&usb2_phy0 2>;
                        phy-names = "usb";
                        companion = <&ohci0>;
                        power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
                        clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
                        power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
                        resets = <&cpg 703>, <&cpg 704>;
-                       #phy-cells = <0>;
+                       #phy-cells = <1>;
                        status = "disabled";
                };
 
index 097538c..1745ac4 100644 (file)
                        power-domains = <&sysc R8A7795_PD_CA57_CPU0>;
                        next-level-cache = <&L2_CA57>;
                        enable-method = "psci";
+                       dynamic-power-coefficient = <854>;
                        clocks = <&cpg CPG_CORE R8A7795_CLK_Z>;
                        operating-points-v2 = <&cluster0_opp>;
                        capacity-dmips-mhz = <1024>;
                        power-domains = <&sysc R8A7795_PD_CA53_CPU0>;
                        next-level-cache = <&L2_CA53>;
                        enable-method = "psci";
+                       #cooling-cells = <2>;
+                       dynamic-power-coefficient = <277>;
                        clocks = <&cpg CPG_CORE R8A7795_CLK_Z2>;
                        operating-points-v2 = <&cluster1_opp>;
                        capacity-dmips-mhz = <535>;
                               <&usb_dmac1 0>, <&usb_dmac1 1>;
                        dma-names = "ch0", "ch1", "ch2", "ch3";
                        renesas,buswait = <11>;
-                       phys = <&usb2_phy0>;
+                       phys = <&usb2_phy0 3>;
                        phy-names = "usb";
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
                        resets = <&cpg 704>, <&cpg 703>;
                               <&usb_dmac3 0>, <&usb_dmac3 1>;
                        dma-names = "ch0", "ch1", "ch2", "ch3";
                        renesas,buswait = <11>;
-                       phys = <&usb2_phy3>;
+                       phys = <&usb2_phy3 3>;
                        phy-names = "usb";
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
                        resets = <&cpg 705>, <&cpg 700>;
                        status = "disabled";
                };
 
+               tpu: pwm@e6e80000 {
+                       compatible = "renesas,tpu-r8a7795", "renesas,tpu";
+                       reg = <0 0xe6e80000 0 0x148>;
+                       interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 304>;
+                       power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
+                       resets = <&cpg 304>;
+                       #pwm-cells = <3>;
+                       status = "disabled";
+               };
+
                msiof0: spi@e6e90000 {
                        compatible = "renesas,msiof-r8a7795",
                                     "renesas,rcar-gen3-msiof";
                        reg = <0 0xee080000 0 0x100>;
                        interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
-                       phys = <&usb2_phy0>;
+                       phys = <&usb2_phy0 1>;
                        phy-names = "usb";
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
                        resets = <&cpg 703>, <&cpg 704>;
                        reg = <0 0xee0a0000 0 0x100>;
                        interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 702>;
-                       phys = <&usb2_phy1>;
+                       phys = <&usb2_phy1 1>;
                        phy-names = "usb";
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
                        resets = <&cpg 702>;
                        reg = <0 0xee0c0000 0 0x100>;
                        interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 701>;
-                       phys = <&usb2_phy2>;
+                       phys = <&usb2_phy2 1>;
                        phy-names = "usb";
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
                        resets = <&cpg 701>;
                        reg = <0 0xee0e0000 0 0x100>;
                        interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 700>, <&cpg CPG_MOD 705>;
-                       phys = <&usb2_phy3>;
+                       phys = <&usb2_phy3 1>;
                        phy-names = "usb";
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
                        resets = <&cpg 700>, <&cpg 705>;
                        reg = <0 0xee080100 0 0x100>;
                        interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
-                       phys = <&usb2_phy0>;
+                       phys = <&usb2_phy0 2>;
                        phy-names = "usb";
                        companion = <&ohci0>;
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
                        reg = <0 0xee0a0100 0 0x100>;
                        interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 702>;
-                       phys = <&usb2_phy1>;
+                       phys = <&usb2_phy1 2>;
                        phy-names = "usb";
                        companion = <&ohci1>;
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
                        reg = <0 0xee0c0100 0 0x100>;
                        interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 701>;
-                       phys = <&usb2_phy2>;
+                       phys = <&usb2_phy2 2>;
                        phy-names = "usb";
                        companion = <&ohci2>;
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
                        reg = <0 0xee0e0100 0 0x100>;
                        interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 700>, <&cpg CPG_MOD 705>;
-                       phys = <&usb2_phy3>;
+                       phys = <&usb2_phy3 2>;
                        phy-names = "usb";
                        companion = <&ohci3>;
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
                        clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
                        resets = <&cpg 703>, <&cpg 704>;
-                       #phy-cells = <0>;
+                       #phy-cells = <1>;
                        status = "disabled";
                };
 
                        clocks = <&cpg CPG_MOD 702>;
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
                        resets = <&cpg 702>;
-                       #phy-cells = <0>;
+                       #phy-cells = <1>;
                        status = "disabled";
                };
 
                        clocks = <&cpg CPG_MOD 701>;
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
                        resets = <&cpg 701>;
-                       #phy-cells = <0>;
+                       #phy-cells = <1>;
                        status = "disabled";
                };
 
                        clocks = <&cpg CPG_MOD 700>, <&cpg CPG_MOD 705>;
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
                        resets = <&cpg 700>, <&cpg 705>;
-                       #phy-cells = <0>;
+                       #phy-cells = <1>;
                        status = "disabled";
                };
 
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
                        thermal-sensors = <&tsc 0>;
+                       sustainable-power = <6313>;
 
                        trips {
-                               sensor1_passive: sensor1-passive {
-                                       temperature = <95000>;
-                                       hysteresis = <1000>;
-                                       type = "passive";
-                               };
                                sensor1_crit: sensor1-crit {
                                        temperature = <120000>;
                                        hysteresis = <1000>;
                                        type = "critical";
                                };
                        };
-
-                       cooling-maps {
-                               map0 {
-                                       trip = <&sensor1_passive>;
-                                       cooling-device = <&a57_0 4 4>,
-                                                        <&a57_1 4 4>,
-                                                        <&a57_2 4 4>,
-                                                        <&a57_3 4 4>;
-                               };
-                       };
                };
 
                sensor_thermal2: sensor-thermal2 {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
                        thermal-sensors = <&tsc 1>;
+                       sustainable-power = <6313>;
 
                        trips {
-                               sensor2_passive: sensor2-passive {
-                                       temperature = <95000>;
-                                       hysteresis = <1000>;
-                                       type = "passive";
-                               };
                                sensor2_crit: sensor2-crit {
                                        temperature = <120000>;
                                        hysteresis = <1000>;
                                        type = "critical";
                                };
                        };
-
-                       cooling-maps {
-                               map0 {
-                                       trip = <&sensor2_passive>;
-                                       cooling-device = <&a57_0 4 4>,
-                                                        <&a57_1 4 4>,
-                                                        <&a57_2 4 4>,
-                                                        <&a57_3 4 4>;
-                               };
-                       };
                };
 
                sensor_thermal3: sensor-thermal3 {
                        thermal-sensors = <&tsc 2>;
 
                        trips {
-                               sensor3_passive: sensor3-passive {
-                                       temperature = <95000>;
+                               target: trip-point1 {
+                                       temperature = <100000>;
                                        hysteresis = <1000>;
                                        type = "passive";
                                };
+
                                sensor3_crit: sensor3-crit {
                                        temperature = <120000>;
                                        hysteresis = <1000>;
 
                        cooling-maps {
                                map0 {
-                                       trip = <&sensor3_passive>;
-                                       cooling-device = <&a57_0 4 4>,
-                                                        <&a57_1 4 4>,
-                                                        <&a57_2 4 4>,
-                                                        <&a57_3 4 4>;
+                                       trip = <&target>;
+                                       cooling-device = <&a57_0 2 4>;
+                                       contribution = <1024>;
+                               };
+
+                               map1 {
+                                       trip = <&target>;
+                                       cooling-device = <&a53_0 0 2>;
+                                       contribution = <1024>;
                                };
                        };
                };
index d5e2f4a..26df5b8 100644 (file)
                        power-domains = <&sysc R8A7796_PD_CA57_CPU0>;
                        next-level-cache = <&L2_CA57>;
                        enable-method = "psci";
+                       dynamic-power-coefficient = <854>;
                        clocks = <&cpg CPG_CORE R8A7796_CLK_Z>;
                        operating-points-v2 = <&cluster0_opp>;
                        capacity-dmips-mhz = <1024>;
                        power-domains = <&sysc R8A7796_PD_CA53_CPU0>;
                        next-level-cache = <&L2_CA53>;
                        enable-method = "psci";
+                       #cooling-cells = <2>;
+                       dynamic-power-coefficient = <277>;
                        clocks = <&cpg CPG_CORE R8A7796_CLK_Z2>;
                        operating-points-v2 = <&cluster1_opp>;
                        capacity-dmips-mhz = <535>;
                               <&usb_dmac1 0>, <&usb_dmac1 1>;
                        dma-names = "ch0", "ch1", "ch2", "ch3";
                        renesas,buswait = <11>;
-                       phys = <&usb2_phy0>;
+                       phys = <&usb2_phy0 3>;
                        phy-names = "usb";
                        power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
                        resets = <&cpg 704>, <&cpg 703>;
                        status = "disabled";
                };
 
+               tpu: pwm@e6e80000 {
+                       compatible = "renesas,tpu-r8a7796", "renesas,tpu";
+                       reg = <0 0xe6e80000 0 0x148>;
+                       interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 304>;
+                       power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
+                       resets = <&cpg 304>;
+                       #pwm-cells = <3>;
+                       status = "disabled";
+               };
+
                msiof0: spi@e6e90000 {
                        compatible = "renesas,msiof-r8a7796",
                                     "renesas,rcar-gen3-msiof";
                        reg = <0 0xee080000 0 0x100>;
                        interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
-                       phys = <&usb2_phy0>;
+                       phys = <&usb2_phy0 1>;
                        phy-names = "usb";
                        power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
                        resets = <&cpg 703>, <&cpg 704>;
                        reg = <0 0xee0a0000 0 0x100>;
                        interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 702>;
-                       phys = <&usb2_phy1>;
+                       phys = <&usb2_phy1 1>;
                        phy-names = "usb";
                        power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
                        resets = <&cpg 702>;
                        reg = <0 0xee080100 0 0x100>;
                        interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
-                       phys = <&usb2_phy0>;
+                       phys = <&usb2_phy0 2>;
                        phy-names = "usb";
                        companion = <&ohci0>;
                        power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
                        reg = <0 0xee0a0100 0 0x100>;
                        interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 702>;
-                       phys = <&usb2_phy1>;
+                       phys = <&usb2_phy1 2>;
                        phy-names = "usb";
                        companion = <&ohci1>;
                        power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
                        clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
                        power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
                        resets = <&cpg 703>, <&cpg 704>;
-                       #phy-cells = <0>;
+                       #phy-cells = <1>;
                        status = "disabled";
                };
 
                        clocks = <&cpg CPG_MOD 702>;
                        power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
                        resets = <&cpg 702>;
-                       #phy-cells = <0>;
+                       #phy-cells = <1>;
                        status = "disabled";
                };
 
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
                        thermal-sensors = <&tsc 0>;
+                       sustainable-power = <3874>;
 
                        trips {
-                               sensor1_passive: sensor1-passive {
-                                       temperature = <95000>;
-                                       hysteresis = <1000>;
-                                       type = "passive";
-                               };
                                sensor1_crit: sensor1-crit {
                                        temperature = <120000>;
                                        hysteresis = <1000>;
                                        type = "critical";
                                };
                        };
-
-                       cooling-maps {
-                               map0 {
-                                       trip = <&sensor1_passive>;
-                                       cooling-device = <&a57_0 5 5>, <&a57_1 5 5>;
-                               };
-                       };
                };
 
                sensor_thermal2: sensor-thermal2 {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
                        thermal-sensors = <&tsc 1>;
+                       sustainable-power = <3874>;
 
                        trips {
-                               sensor2_passive: sensor2-passive {
-                                       temperature = <95000>;
-                                       hysteresis = <1000>;
-                                       type = "passive";
-                               };
                                sensor2_crit: sensor2-crit {
                                        temperature = <120000>;
                                        hysteresis = <1000>;
                                        type = "critical";
                                };
                        };
-
-                       cooling-maps {
-                               map0 {
-                                       trip = <&sensor2_passive>;
-                                       cooling-device = <&a57_0 5 5>, <&a57_1 5 5>;
-                               };
-                       };
                };
 
                sensor_thermal3: sensor-thermal3 {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
                        thermal-sensors = <&tsc 2>;
+                       sustainable-power = <3874>;
 
                        trips {
-                               sensor3_passive: sensor3-passive {
-                                       temperature = <95000>;
+                               target: trip-point1 {
+                                       temperature = <100000>;
                                        hysteresis = <1000>;
                                        type = "passive";
                                };
+
                                sensor3_crit: sensor3-crit {
                                        temperature = <120000>;
                                        hysteresis = <1000>;
                                        type = "critical";
                                };
                        };
-
                        cooling-maps {
                                map0 {
-                                       trip = <&sensor3_passive>;
-                                       cooling-device = <&a57_0 5 5>, <&a57_1 5 5>;
+                                       trip = <&target>;
+                                       cooling-device = <&a57_0 2 4>;
+                                       contribution = <1024>;
+                               };
+                               map1 {
+                                       trip = <&target>;
+                                       cooling-device = <&a53_0 0 2>;
+                                       contribution = <1024>;
                                };
                        };
                };
index 2554b17..131f895 100644 (file)
                        power-domains = <&sysc R8A77965_PD_CA57_CPU0>;
                        next-level-cache = <&L2_CA57>;
                        enable-method = "psci";
+                       #cooling-cells = <2>;
+                       dynamic-power-coefficient = <854>;
                        clocks = <&cpg CPG_CORE R8A77965_CLK_Z>;
                        operating-points-v2 = <&cluster0_opp>;
                };
                               <&usb_dmac1 0>, <&usb_dmac1 1>;
                        dma-names = "ch0", "ch1", "ch2", "ch3";
                        renesas,buswait = <11>;
-                       phys = <&usb2_phy0>;
+                       phys = <&usb2_phy0 3>;
                        phy-names = "usb";
                        power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
                        resets = <&cpg 704>, <&cpg 703>;
                        status = "disabled";
                };
 
+               tpu: pwm@e6e80000 {
+                       compatible = "renesas,tpu-r8a77965", "renesas,tpu";
+                       reg = <0 0xe6e80000 0 0x148>;
+                       interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 304>;
+                       power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
+                       resets = <&cpg 304>;
+                       #pwm-cells = <3>;
+                       status = "disabled";
+               };
+
                msiof0: spi@e6e90000 {
                        compatible = "renesas,msiof-r8a77965",
                                     "renesas,rcar-gen3-msiof";
                        reg = <0 0xee080000 0 0x100>;
                        interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
-                       phys = <&usb2_phy0>;
+                       phys = <&usb2_phy0 1>;
                        phy-names = "usb";
                        power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
                        resets = <&cpg 703>, <&cpg 704>;
                        reg = <0 0xee0a0000 0 0x100>;
                        interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 702>;
-                       phys = <&usb2_phy1>;
+                       phys = <&usb2_phy1 1>;
                        phy-names = "usb";
                        power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
                        resets = <&cpg 702>;
                        reg = <0 0xee080100 0 0x100>;
                        interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
-                       phys = <&usb2_phy0>;
+                       phys = <&usb2_phy0 2>;
                        phy-names = "usb";
                        companion = <&ohci0>;
                        power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
                        reg = <0 0xee0a0100 0 0x100>;
                        interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 702>;
-                       phys = <&usb2_phy1>;
+                       phys = <&usb2_phy1 2>;
                        phy-names = "usb";
                        companion = <&ohci1>;
                        power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
                        clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
                        power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
                        resets = <&cpg 703>, <&cpg 704>;
-                       #phy-cells = <0>;
+                       #phy-cells = <1>;
                        status = "disabled";
                };
 
                        clocks = <&cpg CPG_MOD 702>;
                        power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
                        resets = <&cpg 702>;
-                       #phy-cells = <0>;
+                       #phy-cells = <1>;
                        status = "disabled";
                };
 
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
                        thermal-sensors = <&tsc 0>;
+                       sustainable-power = <2439>;
 
                        trips {
                                sensor1_crit: sensor1-crit {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
                        thermal-sensors = <&tsc 1>;
+                       sustainable-power = <2439>;
 
                        trips {
                                sensor2_crit: sensor2-crit {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
                        thermal-sensors = <&tsc 2>;
+                       sustainable-power = <2439>;
 
                        trips {
+                               target: trip-point1 {
+                                       /* miliCelsius  */
+                                       temperature = <100000>;
+                                       hysteresis = <1000>;
+                                       type = "passive";
+                               };
+
                                sensor3_crit: sensor3-crit {
                                        temperature = <120000>;
                                        hysteresis = <1000>;
                                        type = "critical";
                                };
                        };
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&target>;
+                                       cooling-device = <&a57_0 2 4>;
+                                       contribution = <1024>;
+                               };
+                       };
                };
        };
 
index b6d5332..233f26f 100644 (file)
@@ -19,7 +19,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial0:115200n8";
        };
 
index c727725..83fc13a 100644 (file)
@@ -19,7 +19,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial0:115200n8";
        };
 
 &avb {
        pinctrl-0 = <&avb_pins>;
        pinctrl-names = "default";
-       renesas,no-ether-link;
        phy-handle = <&phy0>;
        status = "okay";
 
index 56cb566..b431866 100644 (file)
                        compatible = "arm,cortex-a53";
                        reg = <0>;
                        device_type = "cpu";
+                       #cooling-cells = <2>;
                        power-domains = <&sysc R8A77990_PD_CA53_CPU0>;
                        next-level-cache = <&L2_CA53>;
                        enable-method = "psci";
+                       dynamic-power-coefficient = <277>;
                        clocks =<&cpg CPG_CORE R8A77990_CLK_Z2>;
                        operating-points-v2 = <&cluster1_opp>;
                };
                               <&usb_dmac1 0>, <&usb_dmac1 1>;
                        dma-names = "ch0", "ch1", "ch2", "ch3";
                        renesas,buswait = <11>;
-                       phys = <&usb2_phy0>;
+                       phys = <&usb2_phy0 3>;
                        phy-names = "usb";
                        power-domains = <&sysc R8A77990_PD_ALWAYS_ON>;
                        resets = <&cpg 704>, <&cpg 703>;
                        reg = <0 0xee080000 0 0x100>;
                        interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
-                       phys = <&usb2_phy0>;
+                       phys = <&usb2_phy0 1>;
                        phy-names = "usb";
                        power-domains = <&sysc R8A77990_PD_ALWAYS_ON>;
                        resets = <&cpg 703>, <&cpg 704>;
                        reg = <0 0xee080100 0 0x100>;
                        interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
-                       phys = <&usb2_phy0>;
+                       phys = <&usb2_phy0 2>;
                        phy-names = "usb";
                        companion = <&ohci0>;
                        power-domains = <&sysc R8A77990_PD_ALWAYS_ON>;
                        clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
                        power-domains = <&sysc R8A77990_PD_ALWAYS_ON>;
                        resets = <&cpg 703>, <&cpg 704>;
-                       #phy-cells = <0>;
+                       #phy-cells = <1>;
                        status = "disabled";
                };
 
 
                du: display@feb00000 {
                        compatible = "renesas,du-r8a77990";
-                       reg = <0 0xfeb00000 0 0x80000>;
+                       reg = <0 0xfeb00000 0 0x40000>;
                        interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 724>,
                        resets = <&cpg 727>;
                        status = "disabled";
 
+                       renesas,companion = <&lvds1>;
+
                        ports {
                                #address-cells = <1>;
                                #size-cells = <0>;
        thermal-zones {
                cpu-thermal {
                        polling-delay-passive = <250>;
-                       polling-delay = <1000>;
-                       thermal-sensors = <&thermal>;
+                       polling-delay = <0>;
+                       thermal-sensors = <&thermal 0>;
+                       sustainable-power = <717>;
 
                        trips {
-                               cpu-crit {
+                               target: trip-point1 {
+                                       temperature = <100000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+
+                               sensor1_crit: sensor1-crit {
                                        temperature = <120000>;
                                        hysteresis = <2000>;
                                        type = "critical";
                        };
 
                        cooling-maps {
+                               map0 {
+                                       trip = <&target>;
+                                       cooling-device = <&a53_0 0 2>;
+                                       contribution = <1024>;
+                               };
                        };
                };
        };
index a7dc11e..0711170 100644 (file)
@@ -20,7 +20,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial0:115200n8";
        };
 
        status = "okay";
 
        ports {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               port@0 {
-                       reg = <0>;
-
+               port {
                        vin4_in: endpoint {
                                remote-endpoint = <&adv7180_out>;
                        };
index 5bf3af2..0a344eb 100644 (file)
                               <&usb_dmac1 0>, <&usb_dmac1 1>;
                        dma-names = "ch0", "ch1", "ch2", "ch3";
                        renesas,buswait = <11>;
-                       phys = <&usb2_phy0>;
+                       phys = <&usb2_phy0 3>;
                        phy-names = "usb";
                        power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
                        resets = <&cpg 704>, <&cpg 703>;
                        reg = <0 0xee080000 0 0x100>;
                        interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
-                       phys = <&usb2_phy0>;
+                       phys = <&usb2_phy0 1>;
                        phy-names = "usb";
                        power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
                        resets = <&cpg 703>, <&cpg 704>;
                        reg = <0 0xee080100 0 0x100>;
                        interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
-                       phys = <&usb2_phy0>;
+                       phys = <&usb2_phy0 2>;
                        phy-names = "usb";
                        companion = <&ohci0>;
                        power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
                        clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>;
                        power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
                        resets = <&cpg 703>, <&cpg 704>;
-                       #phy-cells = <0>;
+                       #phy-cells = <1>;
                        status = "disabled";
                };
 
                        resets = <&cpg 727>;
                        status = "disabled";
 
+                       renesas,companion = <&lvds1>;
+
                        ports {
                                #address-cells = <1>;
                                #size-cells = <0>;
index 2dba132..5c2c847 100644 (file)
@@ -39,7 +39,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial0:115200n8";
        };
 
index 7a09576..27851a7 100644 (file)
                regulator-min-microvolt = <5000000>;
                regulator-max-microvolt = <5000000>;
        };
+
+       wlan_en: regulator-wlan_en {
+               compatible = "regulator-fixed";
+               regulator-name = "wlan-en-regulator";
+
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+
+               gpio = <&gpio_exp_74 4 GPIO_ACTIVE_HIGH>;
+               startup-delay-us = <70000>;
+               enable-active-high;
+       };
 };
 
 &can0 {
                        line-name = "Audio_Out_OFF";
                };
 
+               sd-wifi-mux {
+                       gpio-hog;
+                       gpios = <5 GPIO_ACTIVE_HIGH>;
+                       output-low;     /* Connect WL1837 */
+                       line-name = "SD WiFi mux";
+               };
+
                hub_pwen {
                        gpio-hog;
                        gpios = <6 GPIO_ACTIVE_HIGH>;
                function = "scif1";
        };
 
+       sdhi3_pins: sdhi3 {
+               groups = "sdhi3_data4", "sdhi3_ctrl";
+               function = "sdhi3";
+               power-source = <3300>;
+       };
+
        usb0_pins: usb0 {
                groups = "usb0";
                function = "usb0";
        status = "okay";
 };
 
+&sdhi3 {
+       pinctrl-0 = <&sdhi3_pins>;
+       pinctrl-names = "default";
+
+       vmmc-supply = <&wlan_en>;
+       vqmmc-supply = <&wlan_en>;
+       bus-width = <4>;
+       no-1-8-v;
+       non-removable;
+       cap-power-off-card;
+       keep-power-in-suspend;
+       max-frequency = <26000000>;
+       status = "okay";
+
+       #address-cells = <1>;
+       #size-cells = <0>;
+       wlcore: wlcore@2 {
+               compatible = "ti,wl1837";
+               reg = <2>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
+       };
+};
+
 &usb2_phy0 {
        pinctrl-0 = <&usb0_pins>;
        pinctrl-names = "default";
index e70e1ba..7e498b4 100644 (file)
@@ -26,7 +26,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
                stdout-path = "serial0:115200n8";
        };
 
index 5f2687a..daa2c78 100644 (file)
@@ -16,6 +16,10 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-gru-bob.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-gru-kevin.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-gru-scarlet-inx.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-gru-scarlet-kd.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-hugsun-x99.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-khadas-edge.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-khadas-edge-captain.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-khadas-edge-v.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopc-t4.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopi-m4.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopi-neo4.dtb
index 5d499c9..bb40c16 100644 (file)
        phy-mode = "rgmii";
        pinctrl-names = "default";
        pinctrl-0 = <&rgmiim1_pins>;
-       snps,force_thresh_dma_mode;
+       snps,aal;
        snps,reset-gpio = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>;
        snps,reset-active-low;
        snps,reset-delays-us = <0 10000 50000>;
+       snps,rxpbl = <0x4>;
+       snps,txpbl = <0x4>;
        tx_delay = <0x24>;
        rx_delay = <0x18>;
        status = "okay";
index 9944686..e9fefd8 100644 (file)
                compatible = "snps,dw-wdt";
                reg = <0x0 0xff1a0000 0x0 0x100>;
                interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cru PCLK_WDT>;
        };
 
        pwm0: pwm@ff1b0000 {
index 6b059bd..ebe2ee7 100644 (file)
        };
 };
 
+&spi1 {
+       /* On both Low speed and High speed expansion */
+       cs-gpios = <0>, <&gpio4 RK_PA6 0>, <&gpio4 RK_PA7 0>;
+       status = "okay";
+};
+
 &usbdrd_dwc3_0 {
        dr_mode = "host";
 };
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-hugsun-x99.dts b/arch/arm64/boot/dts/rockchip/rk3399-hugsun-x99.dts
new file mode 100644 (file)
index 0000000..0d1f5f9
--- /dev/null
@@ -0,0 +1,733 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/dts-v1/;
+#include <dt-bindings/pwm/pwm.h>
+#include <dt-bindings/input/input.h>
+#include "rk3399.dtsi"
+#include "rk3399-opp.dtsi"
+
+/ {
+       model = "Hugsun X99 TV BOX";
+       compatible = "hugsun,x99", "rockchip,rk3399";
+
+       chosen {
+               stdout-path = "serial2:1500000n8";
+       };
+
+       clkin_gmac: external-gmac-clock {
+               compatible = "fixed-clock";
+               clock-frequency = <125000000>;
+               clock-output-names = "clkin_gmac";
+               #clock-cells = <0>;
+       };
+
+       dc_5v: dc-5v {
+               compatible = "regulator-fixed";
+               regulator-name = "dc_5v";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+       };
+
+       vcc_sys: vcc-sys {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_sys";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-always-on;
+               vin-supply = <&dc_5v>;
+       };
+
+       vcc_phy: vcc-phy-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_phy";
+               regulator-always-on;
+               regulator-boot-on;
+       };
+
+       vcc1v8_s0: vcc1v8-s0 {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc1v8_s0";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-always-on;
+       };
+
+       vcc3v3_sys: vcc3v3-sys {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc3v3_sys";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+               vin-supply = <&vcc_sys>;
+       };
+
+       vcc5v0_host: vcc5v0-host-regulator {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio4 RK_PD2 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&host_vbus_drv>;
+               regulator-name = "vcc5v0_host";
+               regulator-always-on;
+       };
+
+       vcc5v0_typec: vcc5v0-typec-regulator {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&vcc5v0_typec_en>;
+               regulator-name = "vcc5v0_typec";
+               regulator-always-on;
+               vin-supply = <&vcc5v0_usb>;
+       };
+
+       vcc5v0_usb: vcc5v0-usb {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc5v0_usb";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&dc_5v>;
+       };
+
+       vdd_log: vdd-log {
+               compatible = "pwm-regulator";
+               pwms = <&pwm2 0 25000 1>;
+               pwm-supply = <&vcc_sys>;
+               regulator-name = "vdd_log";
+               regulator-min-microvolt = <800000>;
+               regulator-max-microvolt = <1400000>;
+               regulator-always-on;
+               regulator-boot-on;
+       };
+
+       sdio_pwrseq: sdio-pwrseq {
+               compatible = "mmc-pwrseq-simple";
+               clocks = <&rk808 1>;
+               clock-names = "ext_clock";
+               pinctrl-names = "default";
+               pinctrl-0 = <&wifi_reg_on_h>;
+               reset-gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>;
+       };
+
+};
+
+&cpu_l0 {
+       cpu-supply = <&vdd_cpu_l>;
+};
+
+&cpu_l1 {
+       cpu-supply = <&vdd_cpu_l>;
+};
+
+&cpu_l2 {
+       cpu-supply = <&vdd_cpu_l>;
+};
+
+&cpu_l3 {
+       cpu-supply = <&vdd_cpu_l>;
+};
+
+&cpu_b0 {
+       cpu-supply = <&vdd_cpu_b>;
+};
+
+&cpu_b1 {
+       cpu-supply = <&vdd_cpu_b>;
+};
+
+&emmc_phy {
+       status = "okay";
+};
+
+&gmac {
+       assigned-clocks = <&cru SCLK_RMII_SRC>;
+       assigned-clock-parents = <&clkin_gmac>;
+       clock_in_out = "input";
+       phy-supply = <&vcc_phy>;
+       phy-mode = "rgmii";
+       pinctrl-names = "default";
+       pinctrl-0 = <&rgmii_pins>;
+       snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
+       snps,reset-active-low;
+       snps,reset-delays-us = <0 10000 50000>;
+       tx_delay = <0x28>;
+       rx_delay = <0x11>;
+       status = "okay";
+};
+
+&gpu {
+       status = "okay";
+       mali-supply = <&vdd_gpu>;
+};
+
+&hdmi {
+       ddc-i2c-bus = <&i2c3>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&hdmi_cec>;
+       status = "okay";
+};
+
+&hdmi_sound {
+       status = "okay";
+};
+
+&i2c0 {
+       status = "okay";
+       i2c-scl-rising-time-ns = <180>;
+       i2c-scl-falling-time-ns = <30>;
+       clock-frequency = <400000>;
+
+       vdd_cpu_b: syr827@40 {
+               compatible = "silergy,syr827";
+               reg = <0x40>;
+               regulator-compatible = "fan53555-reg";
+               pinctrl-0 = <&vsel1_gpio>;
+               regulator-name = "vdd_cpu_b";
+               regulator-min-microvolt = <712500>;
+               regulator-max-microvolt = <1500000>;
+               regulator-ramp-delay = <1000>;
+               fcs,suspend-voltage-selector = <1>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&vcc_sys>;
+               regulator-state-mem {
+                       regulator-off-in-suspend;
+               };
+       };
+
+       vdd_gpu: syr828@41 {
+               compatible = "silergy,syr828";
+               reg = <0x41>;
+               regulator-compatible = "fan53555-reg";
+               pinctrl-0 = <&vsel2_gpio>;
+               regulator-name = "vdd_gpu";
+               regulator-min-microvolt = <712500>;
+               regulator-max-microvolt = <1500000>;
+               regulator-ramp-delay = <1000>;
+               fcs,suspend-voltage-selector = <1>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&vcc_sys>;
+               regulator-initial-mode = <1>;
+               regulator-state-mem {
+                       regulator-off-in-suspend;
+               };
+       };
+
+       rk808: pmic@1b {
+               compatible = "rockchip,rk808";
+               reg = <0x1b>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <21 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pmic_int_l>;
+               rockchip,system-power-controller;
+               wakeup-source;
+               #clock-cells = <1>;
+               clock-output-names = "xin32k", "rtc_clko_wifi";
+
+               vcc1-supply = <&vcc_sys>;
+               vcc2-supply = <&vcc_sys>;
+               vcc3-supply = <&vcc_sys>;
+               vcc4-supply = <&vcc_sys>;
+               vcc6-supply = <&vcc_sys>;
+               vcc7-supply = <&vcc_sys>;
+               vcc8-supply = <&vcc3v3_sys>;
+               vcc9-supply = <&vcc_sys>;
+               vcc10-supply = <&vcc_sys>;
+               vcc11-supply = <&vcc_sys>;
+               vcc12-supply = <&vcc3v3_sys>;
+               vddio-supply = <&vcc_1v8>;
+
+               regulators {
+                       vdd_center: DCDC_REG1 {
+                               regulator-name = "vdd_center";
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <900000>;
+                               regulator-ramp-delay = <6001>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdd_cpu_l: DCDC_REG2 {
+                               regulator-name = "vdd_cpu_l";
+                               regulator-min-microvolt = <750000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-ramp-delay = <6001>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc_ddr: DCDC_REG3 {
+                               regulator-name = "vcc_ddr";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                               };
+                       };
+
+                       vcc_1v8: DCDC_REG4 {
+                               regulator-name = "vcc_1v8";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       vcc1v8_dvp: LDO_REG1 {
+                               regulator-name = "vcc1v8_dvp";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       vcca1v8_hdmi: LDO_REG2 {
+                               regulator-name = "vcca1v8_hdmi";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       vcca_1v8: LDO_REG3 {
+                               regulator-name = "vcca_1v8";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       vcc_sd: LDO_REG4 {
+                               regulator-name = "vcc_sd";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <3300000>;
+                               };
+                       };
+
+                       vcc3v0_sd: LDO_REG5 {
+                               regulator-name = "vcc3v0_sd";
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <3000000>;
+                               };
+                       };
+
+                       vcc_1v5: LDO_REG6 {
+                               regulator-name = "vcc_1v5";
+                               regulator-min-microvolt = <1500000>;
+                               regulator-max-microvolt = <1500000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1500000>;
+                               };
+                       };
+
+                       vcca0v9_hdmi: LDO_REG7 {
+                               regulator-name = "vcca0v9_hdmi";
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <900000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <900000>;
+                               };
+                       };
+
+                       vcc_3v0: LDO_REG8 {
+                               regulator-name = "vcc_3v0";
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <3000000>;
+                               };
+                       };
+
+                       vcc3v3_s3: SWITCH_REG1 {
+                               regulator-name = "vcc3v3_s3";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                               };
+                       };
+
+                       vcc3v3_s0: SWITCH_REG2 {
+                               regulator-name = "vcc3v3_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                               };
+                       };
+               };
+       };
+};
+
+&i2c1 {
+       i2c-scl-rising-time-ns = <300>;
+       i2c-scl-falling-time-ns = <15>;
+       status = "okay";
+};
+
+&i2c3 {
+       i2c-scl-rising-time-ns = <450>;
+       i2c-scl-falling-time-ns = <15>;
+       status = "okay";
+};
+
+&i2c4 {
+       i2c-scl-rising-time-ns = <600>;
+       i2c-scl-falling-time-ns = <40>;
+       status = "okay";
+
+       fusb0: typec-portc@22 {
+               compatible = "fcs,fusb302";
+               reg = <0x22>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <RK_PA2 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&fusb0_int>;
+               vbus-supply = <&vcc5v0_typec>;
+               status = "okay";
+       };
+};
+
+&i2c7 {
+       status = "okay";
+};
+
+&i2s0 {
+       rockchip,playback-channels = <8>;
+       rockchip,capture-channels = <8>;
+       status = "okay";
+};
+
+&i2s1 {
+       rockchip,playback-channels = <2>;
+       rockchip,capture-channels = <2>;
+       status = "okay";
+};
+
+&i2s2 {
+       status = "okay";
+};
+
+&io_domains {
+       status = "okay";
+       audio-supply = <&vcc1v8_s0>;
+       bt656-supply = <&vcc1v8_s0>;
+       gpio1830-supply = <&vcc_3v0>;
+       sdmmc-supply = <&vcc_sd>;
+};
+
+&pmu_io_domains {
+       status = "okay";
+       pmu1830-supply = <&vcc_1v8>;
+};
+
+&pinctrl {
+       fusb30x {
+               fusb0_int: fusb0-int {
+                       rockchip,pins =
+                               <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+       };
+
+       gmac {
+               rgmii_sleep_pins: rgmii-sleep-pins {
+                       rockchip,pins =
+                               <3 RK_PB7 RK_FUNC_GPIO &pcfg_output_low>;
+               };
+       };
+
+       pmic {
+               pmic_int_l: pmic-int-l {
+                       rockchip,pins =
+                               <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+
+               vsel1_gpio: vsel1-gpio {
+                       rockchip,pins =
+                               <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>;
+               };
+
+               vsel2_gpio: vsel2-gpio {
+                       rockchip,pins =
+                               <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>;
+               };
+       };
+
+       sdio {
+               bt_host_wake_l: bt-host-wake-l {
+                       rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               bt_reg_on_h: bt-reg-on-h {
+                       /* external pullup to VCC1V8_PMUPLL */
+                       rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               bt_wake_l: bt-wake-l {
+                       rockchip,pins = <2 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               wifi_reg_on_h: wifi-reg_on-h {
+                       rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       wifi {
+               wifi_host_wake_l: wifi-host-wake-l {
+                       rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       usb-typec {
+               vcc5v0_typec_en: vcc5v0_typec_en {
+                       rockchip,pins = <1 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+       };
+
+       usb2 {
+               host_vbus_drv: host-vbus-drv {
+                       rockchip,pins =
+                               <4 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+};
+
+&pwm0 {
+       status = "okay";
+};
+
+&pwm2 {
+       status = "okay";
+       pinctrl-0 = <&pwm2_pin_pull_down>;
+};
+
+&saradc {
+       vref-supply = <&vcc1v8_s0>;
+       status = "okay";
+};
+
+&sdmmc {
+       clock-frequency = <150000000>;
+       clock-freq-min-max = <200000 150000000>;
+       supports-sd;
+       bus-width = <4>;
+       cap-mmc-highspeed;
+       cap-sd-highspeed;
+       disable-wp;
+       vqmmc-supply = <&vcc_sd>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>;
+       card-detect-delay = <800>;
+       status = "okay";
+};
+
+&sdhci {
+       bus-width = <8>;
+       mmc-hs400-1_8v;
+       mmc-hs400-enhanced-strobe;
+       supports-emmc;
+       non-removable;
+       keep-power-in-suspend;
+       status = "okay";
+};
+
+&sdio0 {
+       bus-width = <4>;
+       clock-frequency = <50000000>;
+       cap-sdio-irq;
+       cap-sd-highspeed;
+       keep-power-in-suspend;
+       mmc-pwrseq = <&sdio_pwrseq>;
+       non-removable;
+       pinctrl-names = "default";
+       pinctrl-0 = <&sdio0_bus4 &sdio0_cmd &sdio0_clk>;
+       sd-uhs-sdr104;
+       #address-cells = <1>;
+       #size-cells = <0>;
+       status = "okay";
+
+       brcmf: wifi@1 {
+               compatible = "brcm,bcm4329-fmac";
+               reg = <1>;
+               interrupt-parent = <&gpio0>;
+               interrupts = <RK_PA3 GPIO_ACTIVE_HIGH>;
+               interrupt-names = "host-wake";
+               pinctrl-names = "default";
+               pinctrl-0 = <&wifi_host_wake_l>;
+       };
+};
+
+&spdif {
+       status = "okay";
+       pinctrl-0 = <&spdif_bus_1>;
+       #sound-dai-cells = <0>;
+};
+
+&spi1 {
+       status = "okay";
+       max-freq = <10000000>;
+
+       flash@0 {
+               compatible = "jedec,spi-nor";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               reg = <0>;
+               spi-max-frequency = <10000000>;
+       };
+};
+
+&tcphy0 {
+       status = "okay";
+};
+
+&tcphy1 {
+       status = "okay";
+};
+
+&tsadc {
+       /* tshut mode 0:CRU 1:GPIO */
+       rockchip,hw-tshut-mode = <1>;
+       /* tshut polarity 0:LOW 1:HIGH */
+       rockchip,hw-tshut-polarity = <1>;
+       rockchip,hw-tshut-temp = <110000>;
+       status = "okay";
+};
+
+&u2phy0 {
+       status = "okay";
+
+       u2phy0_host: host-port {
+               phy-supply = <&vcc5v0_host>;
+               status = "okay";
+       };
+
+       u2phy0_otg: otg-port {
+               status = "okay";
+       };
+};
+
+&u2phy1 {
+       status = "okay";
+
+       u2phy1_host: host-port {
+               phy-supply = <&vcc5v0_host>;
+               status = "okay";
+       };
+
+       u2phy1_otg: otg-port {
+               status = "okay";
+       };
+};
+
+&uart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart0_xfer &uart0_rts &uart0_cts>;
+       status = "okay";
+
+       bluetooth {
+               compatible = "brcm,bcm43438-bt";
+               clocks = <&rk808 1>;
+               clock-names = "ext_clock";
+               device-wakeup-gpios = <&gpio2 RK_PD2 GPIO_ACTIVE_HIGH>;
+               host-wakeup-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_HIGH>;
+               shutdown-gpios = <&gpio0 RK_PB1 GPIO_ACTIVE_HIGH>;
+               max-speed = <4000000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&bt_reg_on_h &bt_host_wake_l &bt_wake_l>;
+               vbat-supply = <&vcc3v3_sys>;
+               vddio-supply = <&vcc_1v8>;
+       };
+};
+
+&uart2 {
+       status = "okay";
+};
+
+&usb_host0_ehci {
+       status = "okay";
+};
+
+&usb_host0_ohci {
+       status = "okay";
+};
+
+&usb_host1_ehci {
+       status = "okay";
+};
+
+&usb_host1_ohci {
+       status = "okay";
+};
+
+&usbdrd3_0 {
+       status = "okay";
+};
+
+&usbdrd_dwc3_0 {
+       status = "okay";
+       dr_mode = "otg";
+};
+
+&usbdrd3_1 {
+       status = "okay";
+};
+
+&usbdrd_dwc3_1 {
+       status = "okay";
+       dr_mode = "host";
+};
+
+&vopb {
+       status = "okay";
+};
+
+&vopb_mmu {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge-captain.dts b/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge-captain.dts
new file mode 100644 (file)
index 0000000..8302e51
--- /dev/null
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Shenzhen Wesion Technology Co., Ltd.
+ * (https://www.khadas.com)
+ */
+
+/dts-v1/;
+#include "rk3399-khadas-edge.dtsi"
+
+/ {
+       model = "Khadas Edge-Captain";
+       compatible = "khadas,edge-captain", "rockchip,rk3399";
+};
+
+&gmac {
+       status = "okay";
+};
+
+&pcie_phy {
+       status = "okay";
+};
+
+&pcie0 {
+       ep-gpios = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>;
+       num-lanes = <4>;
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge-v.dts b/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge-v.dts
new file mode 100644 (file)
index 0000000..f5dcb99
--- /dev/null
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Shenzhen Wesion Technology Co., Ltd.
+ * (https://www.khadas.com)
+ */
+
+/dts-v1/;
+#include "rk3399-khadas-edge.dtsi"
+
+/ {
+       model = "Khadas Edge-V";
+       compatible = "khadas,edge-v", "rockchip,rk3399";
+};
+
+&gmac {
+       status = "okay";
+};
+
+&pcie_phy {
+       status = "okay";
+};
+
+&pcie0 {
+       ep-gpios = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>;
+       num-lanes = <4>;
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dts b/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dts
new file mode 100644 (file)
index 0000000..31616e7
--- /dev/null
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Shenzhen Wesion Technology Co., Ltd.
+ * (https://www.khadas.com)
+ */
+
+/dts-v1/;
+#include "rk3399-khadas-edge.dtsi"
+
+/ {
+       model = "Khadas Edge";
+       compatible = "khadas,edge", "rockchip,rk3399";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi
new file mode 100644 (file)
index 0000000..4944d78
--- /dev/null
@@ -0,0 +1,804 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Shenzhen Wesion Technology Co., Ltd.
+ * (https://www.khadas.com)
+ */
+
+/dts-v1/;
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/pwm/pwm.h>
+#include "rk3399.dtsi"
+#include "rk3399-opp.dtsi"
+
+/ {
+       chosen {
+               stdout-path = "serial2:1500000n8";
+       };
+
+       clkin_gmac: external-gmac-clock {
+               compatible = "fixed-clock";
+               clock-frequency = <125000000>;
+               clock-output-names = "clkin_gmac";
+               #clock-cells = <0>;
+       };
+
+       sdio_pwrseq: sdio-pwrseq {
+               compatible = "mmc-pwrseq-simple";
+               clocks = <&rk808 1>;
+               clock-names = "ext_clock";
+               pinctrl-names = "default";
+               pinctrl-0 = <&wifi_enable_h>;
+
+               /*
+                * On the module itself this is one of these (depending
+                * on the actual card populated):
+                * - SDIO_RESET_L_WL_REG_ON
+                * - PDN (power down when low)
+                */
+               reset-gpios = <&gpio2 RK_PD4 GPIO_ACTIVE_LOW>;
+       };
+
+       /* switched by pmic_sleep */
+       vcc1v8_s3: vcca1v8_s3: vcc1v8-s3 {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc1v8_s3";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               vin-supply = <&vcc_1v8>;
+       };
+
+       vcc3v3_pcie: vcc3v3-pcie-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc3v3_pcie";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&vsys_3v3>;
+       };
+
+       /* Actually 3 regulators (host0, 1, 2) controlled by the same gpio */
+       vcc5v0_host: vcc5v0-host-regulator {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio4 RK_PD1 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&vcc5v0_host_en>;
+               regulator-name = "vcc5v0_host";
+               regulator-always-on;
+               vin-supply = <&vsys_5v0>;
+       };
+
+       vdd_log: vdd-log {
+               compatible = "pwm-regulator";
+               pwms = <&pwm2 0 25000 1>;
+               regulator-name = "vdd_log";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <800000>;
+               regulator-max-microvolt = <1400000>;
+               vin-supply = <&vsys_3v3>;
+       };
+
+       vsys: vsys {
+               compatible = "regulator-fixed";
+               regulator-name = "vsys";
+               regulator-always-on;
+               regulator-boot-on;
+       };
+
+       vsys_3v3: vsys-3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "vsys_3v3";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&vsys>;
+       };
+
+       vsys_5v0: vsys-5v0 {
+               compatible = "regulator-fixed";
+               regulator-name = "vsys_5v0";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&vsys>;
+       };
+
+       adc-keys {
+               compatible = "adc-keys";
+               io-channels = <&saradc 1>;
+               io-channel-names = "buttons";
+               keyup-threshold-microvolt = <1800000>;
+               poll-interval = <100>;
+
+               recovery {
+                       label = "Recovery";
+                       linux,code = <KEY_VENDOR>;
+                       press-threshold-microvolt = <18000>;
+               };
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               autorepeat;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pwrbtn>;
+
+               power {
+                       debounce-interval = <100>;
+                       gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
+                       label = "GPIO Key Power";
+                       linux,code = <KEY_POWER>;
+                       wakeup-source;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&sys_led_gpio>, <&user_led_gpio>;
+
+               sys-led {
+                       label = "sys_led";
+                       linux,default-trigger = "heartbeat";
+                       gpios = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>;
+               };
+
+               user-led {
+                       label = "user_led";
+                       default-state = "off";
+                       gpios = <&gpio4 RK_PD0 GPIO_ACTIVE_HIGH>;
+               };
+       };
+
+       fan: pwm-fan {
+               compatible = "pwm-fan";
+               cooling-levels = <0 150 200 255>;
+               #cooling-cells = <2>;
+               fan-supply = <&vsys_5v0>;
+               pwms = <&pwm0 0 40000 0>;
+       };
+};
+
+&cpu_l0 {
+       cpu-supply = <&vdd_cpu_l>;
+};
+
+&cpu_l1 {
+       cpu-supply = <&vdd_cpu_l>;
+};
+
+&cpu_l2 {
+       cpu-supply = <&vdd_cpu_l>;
+};
+
+&cpu_l3 {
+       cpu-supply = <&vdd_cpu_l>;
+};
+
+&cpu_b0 {
+       cpu-supply = <&vdd_cpu_b>;
+};
+
+&cpu_b1 {
+       cpu-supply = <&vdd_cpu_b>;
+};
+
+&cpu_thermal {
+       trips {
+               cpu_warm: cpu_warm {
+                       temperature = <55000>;
+                       hysteresis = <2000>;
+                       type = "active";
+               };
+
+               cpu_hot: cpu_hot {
+                       temperature = <65000>;
+                       hysteresis = <2000>;
+                       type = "active";
+               };
+       };
+
+       cooling-maps {
+               map2 {
+                       trip = <&cpu_warm>;
+                       cooling-device = <&fan THERMAL_NO_LIMIT 1>;
+               };
+
+               map3 {
+                       trip = <&cpu_hot>;
+                       cooling-device = <&fan 2 THERMAL_NO_LIMIT>;
+               };
+       };
+};
+
+&emmc_phy {
+       status = "okay";
+};
+
+&gmac {
+       assigned-clocks = <&cru SCLK_RMII_SRC>;
+       assigned-clock-parents = <&clkin_gmac>;
+       clock_in_out = "input";
+       phy-supply = <&vcc_lan>;
+       phy-mode = "rgmii";
+       pinctrl-names = "default";
+       pinctrl-0 = <&rgmii_pins>;
+       snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
+       snps,reset-active-low;
+       snps,reset-delays-us = <0 10000 50000>;
+       tx_delay = <0x28>;
+       rx_delay = <0x11>;
+};
+
+&gpu {
+       mali-supply = <&vdd_gpu>;
+       status = "okay";
+};
+
+&gpu_thermal {
+       trips {
+               gpu_warm: gpu_warm {
+                       temperature = <55000>;
+                       hysteresis = <2000>;
+                       type = "active";
+               };
+
+               gpu_hot: gpu_hot {
+                       temperature = <65000>;
+                       hysteresis = <2000>;
+                       type = "active";
+               };
+       };
+
+       cooling-maps {
+               map1 {
+                       trip = <&gpu_warm>;
+                       cooling-device = <&fan THERMAL_NO_LIMIT 1>;
+               };
+
+               map2 {
+                       trip = <&gpu_hot>;
+                       cooling-device = <&fan 2 THERMAL_NO_LIMIT>;
+               };
+       };
+};
+
+&hdmi {
+       ddc-i2c-bus = <&i2c3>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&hdmi_cec>;
+       status = "okay";
+};
+
+&hdmi_sound {
+       status = "okay";
+};
+
+&i2c3 {
+       i2c-scl-rising-time-ns = <450>;
+       i2c-scl-falling-time-ns = <15>;
+       status = "okay";
+};
+
+&i2c4 {
+       clock-frequency = <400000>;
+       i2c-scl-rising-time-ns = <168>;
+       i2c-scl-falling-time-ns = <4>;
+       status = "okay";
+
+       rk808: pmic@1b {
+               compatible = "rockchip,rk808";
+               reg = <0x1b>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <RK_PC6 IRQ_TYPE_LEVEL_LOW>;
+               #clock-cells = <1>;
+               clock-output-names = "xin32k", "rk808-clkout2";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pmic_int_l>;
+               rockchip,system-power-controller;
+               wakeup-source;
+
+               vcc1-supply = <&vsys_3v3>;
+               vcc2-supply = <&vsys_3v3>;
+               vcc3-supply = <&vsys_3v3>;
+               vcc4-supply = <&vsys_3v3>;
+               vcc6-supply = <&vsys_3v3>;
+               vcc7-supply = <&vsys_3v3>;
+               vcc8-supply = <&vsys_3v3>;
+               vcc9-supply = <&vsys_3v3>;
+               vcc10-supply = <&vsys_3v3>;
+               vcc11-supply = <&vsys_3v3>;
+               vcc12-supply = <&vsys_3v3>;
+               vddio-supply = <&vcc_1v8>;
+
+               regulators {
+                       vdd_center: DCDC_REG1 {
+                               regulator-name = "vdd_center";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <750000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-ramp-delay = <6001>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdd_cpu_l: DCDC_REG2 {
+                               regulator-name = "vdd_cpu_l";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <750000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-ramp-delay = <6001>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc_ddr: DCDC_REG3 {
+                               regulator-name = "vcc_ddr";
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                               };
+                       };
+
+                       vcc_1v8: DCDC_REG4 {
+                               regulator-name = "vcc_1v8";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       vcc1v8_apio2: LDO_REG1 {
+                               regulator-name = "vcc1v8_apio2";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc_vldo2: LDO_REG2 {
+                               regulator-name = "vcc_vldo2";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3000000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc1v8_pmupll: LDO_REG3 {
+                               regulator-name = "vcc1v8_pmupll";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       vccio_sd: LDO_REG4 {
+                               regulator-name = "vccio_sd";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3000000>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <3000000>;
+                               };
+                       };
+
+                       vcc_vldo5: LDO_REG5 {
+                               regulator-name = "vcc_vldo5";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3000000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc_1v5: LDO_REG6 {
+                               regulator-name = "vcc_1v5";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1500000>;
+                               regulator-max-microvolt = <1500000>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1500000>;
+                               };
+                       };
+
+                       vcc1v8_codec: LDO_REG7 {
+                               regulator-name = "vcc1v8_codec";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc_3v0: LDO_REG8 {
+                               regulator-name = "vcc_3v0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3000000>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <3000000>;
+                               };
+                       };
+
+                       vcc3v3_s3: vcc_lan: SWITCH_REG1 {
+                               regulator-name = "vcc3v3_s3";
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc3v3_s0: SWITCH_REG2 {
+                               regulator-name = "vcc3v3_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+               };
+       };
+
+       vdd_cpu_b: regulator@40 {
+               compatible = "silergy,syr827";
+               reg = <0x40>;
+               fcs,suspend-voltage-selector = <1>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&cpu_b_sleep>;
+               regulator-name = "vdd_cpu_b";
+               regulator-min-microvolt = <712500>;
+               regulator-max-microvolt = <1500000>;
+               regulator-ramp-delay = <1000>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&vsys_3v3>;
+
+               regulator-state-mem {
+                       regulator-off-in-suspend;
+               };
+       };
+
+       vdd_gpu: regulator@41 {
+               compatible = "silergy,syr828";
+               reg = <0x41>;
+               fcs,suspend-voltage-selector = <1>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&gpu_sleep>;
+               regulator-name = "vdd_gpu";
+               regulator-min-microvolt = <712500>;
+               regulator-max-microvolt = <1500000>;
+               regulator-ramp-delay = <1000>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&vsys_3v3>;
+
+               regulator-state-mem {
+                       regulator-off-in-suspend;
+               };
+       };
+};
+
+&i2c8 {
+       clock-frequency = <400000>;
+       i2c-scl-rising-time-ns = <160>;
+       i2c-scl-falling-time-ns = <30>;
+       status = "okay";
+};
+
+&i2s0 {
+       rockchip,playback-channels = <8>;
+       rockchip,capture-channels = <8>;
+       status = "okay";
+};
+
+&i2s1 {
+       rockchip,playback-channels = <2>;
+       rockchip,capture-channels = <2>;
+       status = "okay";
+};
+
+&i2s2 {
+       status = "okay";
+};
+
+&io_domains {
+       bt656-supply = <&vcc1v8_apio2>;
+       audio-supply = <&vcc1v8_codec>;
+       sdmmc-supply = <&vccio_sd>;
+       gpio1830-supply = <&vcc_3v0>;
+       status = "okay";
+};
+
+&pmu_io_domains {
+       pmu1830-supply = <&vcc_1v8>;
+       status = "okay";
+};
+
+&pinctrl {
+       bt {
+               bt_host_wake_l: bt-host-wake-l {
+                       rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               bt_reg_on_h: bt-reg-on-h {
+                       rockchip,pins = <2 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               bt_wake_l: bt-wake-l {
+                       rockchip,pins = <2 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       buttons {
+               pwrbtn: pwrbtn {
+                       rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+       };
+
+       leds {
+               sys_led_gpio: sys_led-gpio {
+                       rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               user_led_gpio: user_led-gpio {
+                       rockchip,pins = <4 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       pmic {
+               pmic_int_l: pmic-int-l {
+                       rockchip,pins = <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+
+               cpu_b_sleep: cpu-b-sleep {
+                       rockchip,pins = <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_down>;
+               };
+
+               gpu_sleep: gpu-sleep {
+                       rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_down>;
+               };
+       };
+
+       sdio-pwrseq {
+               wifi_enable_h: wifi-enable-h {
+                       rockchip,pins = <2 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       usb2 {
+               vcc5v0_host_en: vcc5v0-host-en {
+                       rockchip,pins = <4 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       wifi {
+               wifi_host_wake_l: wifi-host-wake-l {
+                       rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+};
+
+&pwm0 {
+       status = "okay";
+};
+
+&pwm2 {
+       status = "okay";
+};
+
+&saradc {
+       vref-supply = <&vcca1v8_s3>;
+       status = "okay";
+};
+
+&sdio0 {
+       /* WiFi & BT combo module Ampak AP6356S */
+       bus-width = <4>;
+       cap-sdio-irq;
+       cap-sd-highspeed;
+       keep-power-in-suspend;
+       mmc-pwrseq = <&sdio_pwrseq>;
+       non-removable;
+       pinctrl-names = "default";
+       pinctrl-0 = <&sdio0_bus4 &sdio0_cmd &sdio0_clk>;
+       sd-uhs-sdr104;
+       vqmmc-supply = <&vcc1v8_s3>;
+       vmmc-supply = <&vccio_sd>;
+       status = "okay";
+
+       brcmf: wifi@1 {
+               compatible = "brcm,bcm4329-fmac";
+               interrupt-parent = <&gpio0>;
+               interrupts = <RK_PA3 GPIO_ACTIVE_HIGH>;
+               interrupt-names = "host-wake";
+               brcm,drive-strength = <5>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&wifi_host_wake_l>;
+       };
+};
+
+&sdmmc {
+       bus-width = <4>;
+       cap-mmc-highspeed;
+       cap-sd-highspeed;
+       cd-gpios = <&gpio0 RK_PA7 GPIO_ACTIVE_LOW>;
+       disable-wp;
+       max-frequency = <150000000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_bus4>;
+       status = "okay";
+};
+
+&sdhci {
+       bus-width = <8>;
+       mmc-hs400-1_8v;
+       mmc-hs400-enhanced-strobe;
+       non-removable;
+       status = "okay";
+};
+
+&tcphy0 {
+       status = "okay";
+};
+
+&tcphy1 {
+       status = "okay";
+};
+
+&tsadc {
+       /* tshut mode 0:CRU 1:GPIO */
+       rockchip,hw-tshut-mode = <1>;
+       /* tshut polarity 0:LOW 1:HIGH */
+       rockchip,hw-tshut-polarity = <1>;
+       status = "okay";
+};
+
+&u2phy0 {
+       status = "okay";
+
+       u2phy0_otg: otg-port {
+               status = "okay";
+       };
+
+       u2phy0_host: host-port {
+               phy-supply = <&vcc5v0_host>;
+               status = "okay";
+       };
+};
+
+&u2phy1 {
+       status = "okay";
+
+       u2phy1_otg: otg-port {
+               status = "okay";
+       };
+
+       u2phy1_host: host-port {
+               phy-supply = <&vcc5v0_host>;
+               status = "okay";
+       };
+};
+
+&uart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart0_xfer &uart0_rts &uart0_cts>;
+       status = "okay";
+
+       bluetooth {
+               compatible = "brcm,bcm43438-bt";
+               clocks = <&rk808 1>;
+               clock-names = "lpo";
+               device-wakeup-gpios = <&gpio2 RK_PD2 GPIO_ACTIVE_HIGH>;
+               host-wakeup-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_HIGH>;
+               shutdown-gpios = <&gpio2 RK_PD3 GPIO_ACTIVE_HIGH>;
+               max-speed = <4000000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&bt_reg_on_h &bt_host_wake_l &bt_wake_l>;
+               vbat-supply = <&vsys_3v3>;
+               vddio-supply = <&vcc_1v8>;
+       };
+};
+
+&uart2 {
+       status = "okay";
+};
+
+&usb_host0_ehci {
+       status = "okay";
+};
+
+&usb_host0_ohci {
+       status = "okay";
+};
+
+&usb_host1_ehci {
+       status = "okay";
+};
+
+&usb_host1_ohci {
+       status = "okay";
+};
+
+&usbdrd3_0 {
+       status = "okay";
+};
+
+&usbdrd_dwc3_0 {
+       status = "okay";
+       dr_mode = "otg";
+};
+
+&usbdrd3_1 {
+       status = "okay";
+};
+
+&usbdrd_dwc3_1 {
+       status = "okay";
+       dr_mode = "host";
+};
+
+&vopb {
+       status = "okay";
+};
+
+&vopb_mmu {
+       status = "okay";
+};
+
+&vopl {
+       status = "okay";
+};
+
+&vopl_mmu {
+       status = "okay";
+};
index e030627..1ae1ebd 100644 (file)
                #clock-cells = <0>;
        };
 
+       sdio_pwrseq: sdio-pwrseq {
+               compatible = "mmc-pwrseq-simple";
+               clocks = <&rk808 1>;
+               clock-names = "ext_clock";
+               pinctrl-names = "default";
+               pinctrl-0 = <&wifi_enable_h>;
+               reset-gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>;
+       };
+
        vcc12v_dcin: dc-12v {
                compatible = "regulator-fixed";
                regulator-name = "vcc12v_dcin";
        status = "okay";
 };
 
+&hdmi_sound {
+       status = "okay";
+};
+
 &i2c0 {
        clock-frequency = <400000>;
        i2c-scl-rising-time-ns = <168>;
 };
 
 &pinctrl {
+       bt {
+               bt_enable_h: bt-enable-h {
+                       rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               bt_host_wake_l: bt-host-wake-l {
+                       rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               bt_wake_l: bt-wake-l {
+                       rockchip,pins = <2 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
        pcie {
                pcie_pwr_en: pcie-pwr-en {
                        rockchip,pins = <2 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
+       sdio0 {
+               sdio0_bus4: sdio0-bus4 {
+                       rockchip,pins =
+                               <2 20 RK_FUNC_1 &pcfg_pull_up_20ma>,
+                               <2 21 RK_FUNC_1 &pcfg_pull_up_20ma>,
+                               <2 22 RK_FUNC_1 &pcfg_pull_up_20ma>,
+                               <2 23 RK_FUNC_1 &pcfg_pull_up_20ma>;
+               };
+
+               sdio0_cmd: sdio0-cmd {
+                       rockchip,pins =
+                               <2 24 RK_FUNC_1 &pcfg_pull_up_20ma>;
+               };
+
+               sdio0_clk: sdio0-clk {
+                       rockchip,pins =
+                               <2 25 RK_FUNC_1 &pcfg_pull_none_20ma>;
+               };
+       };
+
        pmic {
                pmic_int_l: pmic-int-l {
                        rockchip,pins = <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>;
                        rockchip,pins = <4 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
+
+       wifi {
+               wifi_enable_h: wifi-enable-h {
+                       rockchip,pins =
+                               <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               wifi_host_wake_l: wifi-host-wake-l {
+                       rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
 };
 
 &pwm2 {
        vref-supply = <&vcc_1v8>;
 };
 
+&sdio0 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       bus-width = <4>;
+       clock-frequency = <50000000>;
+       cap-sdio-irq;
+       cap-sd-highspeed;
+       keep-power-in-suspend;
+       mmc-pwrseq = <&sdio_pwrseq>;
+       non-removable;
+       pinctrl-names = "default";
+       pinctrl-0 = <&sdio0_bus4 &sdio0_cmd &sdio0_clk>;
+       sd-uhs-sdr104;
+       status = "okay";
+
+       brcmf: wifi@1 {
+               compatible = "brcm,bcm4329-fmac";
+               reg = <1>;
+               interrupt-parent = <&gpio0>;
+               interrupts = <RK_PA3 GPIO_ACTIVE_HIGH>;
+               interrupt-names = "host-wake";
+               pinctrl-names = "default";
+               pinctrl-0 = <&wifi_host_wake_l>;
+       };
+};
+
 &sdmmc {
        bus-width = <4>;
        cap-mmc-highspeed;
        };
 };
 
+&uart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>;
+       status = "okay";
+
+       bluetooth {
+               compatible = "brcm,bcm43438-bt";
+               clocks = <&rk808 1>;
+               clock-names = "ext_clock";
+               device-wakeup-gpios = <&gpio2 RK_PD3 GPIO_ACTIVE_HIGH>;
+               host-wakeup-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_HIGH>;
+               shutdown-gpios = <&gpio0 RK_PB1 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&bt_host_wake_l &bt_wake_l &bt_enable_h>;
+       };
+};
+
 &uart2 {
        status = "okay";
 };
index 12285c5..437a75f 100644 (file)
        };
 };
 
+&spi0 {
+       /* On Low speed expansion (LS-SPI0) */
+       status = "okay";
+};
+
+&spi4 {
+       /* On High speed expansion (HS-SPI1) */
+       status = "okay";
+};
+
+&thermal_zones {
+       cpu_thermal: cpu {
+               polling-delay-passive = <100>;
+               polling-delay = <1000>;
+               thermal-sensors = <&tsadc 0>;
+               sustainable-power = <1550>;
+
+               trips {
+                       cpu_alert0: cpu_alert0 {
+                                   temperature = <65000>;
+                                   hysteresis = <2000>;
+                                   type = "passive";
+                       };
+
+                       cpu_alert1: cpu_alert1 {
+                                   temperature = <75000>;
+                                   hysteresis = <2000>;
+                                   type = "passive";
+                       };
+
+                       cpu_crit: cpu_crit {
+                                 temperature = <95000>;
+                                 hysteresis = <2000>;
+                                 type = "critical";
+                       };
+               };
+
+               cooling-maps {
+                            map0 {
+
+                            trip = <&cpu_alert1>;
+                            cooling-device =
+                                       <&cpu_b0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                       <&cpu_b1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                       };
+               };
+       };
+};
+
 &usbdrd_dwc3_0 {
        dr_mode = "otg";
 };
index 20ec7d1..eb55940 100644 (file)
        gpio1830-supply = <&vcc_3v0>;
 };
 
+&pcie0 {
+       ep-gpios = <&gpio2 RK_PD4 GPIO_ACTIVE_HIGH>;
+       num-lanes = <4>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pcie_perst>;
+       vpcie12v-supply = <&vcc12v_dcin>;
+       vpcie3v3-supply = <&vcc3v3_pcie>;
+       status = "okay";
+};
+
+&pcie_phy {
+       status = "okay";
+};
+
 &pmu_io_domains {
        pmu1830-supply = <&vcc_3v0>;
        status = "okay";
        };
 
        pcie {
+               pcie_perst: pcie-perst {
+                       rockchip,pins = <2 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
                pcie_pwr_en: pcie-pwr-en {
                        rockchip,pins = <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>;
                };
index 04623e5..1bc1579 100644 (file)
        status = "okay";
 
        u2phy0_otg: otg-port {
-               phy-supply = <&vcc5v0_typec0>;
                status = "okay";
        };
 
        u2phy0_host: host-port {
-               phy-supply = <&vcc5v0_host>;
+               phy-supply = <&vcc5v0_typec0>;
                status = "okay";
        };
 };
 
 &usbdrd_dwc3_0 {
        status = "okay";
-       dr_mode = "otg";
+       dr_mode = "host";
 };
 
 &usbdrd3_1 {
index 196ac9b..cede1ad 100644 (file)
                        compatible = "snps,dwc3";
                        reg = <0x0 0xfe800000 0x0 0x100000>;
                        interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH 0>;
+                       clocks = <&cru SCLK_USB3OTG0_REF>, <&cru ACLK_USB3OTG0>,
+                                <&cru SCLK_USB3OTG0_SUSPEND>;
+                       clock-names = "ref", "bus_early", "suspend";
                        dr_mode = "otg";
                        phys = <&u2phy0_otg>, <&tcphy0_usb3>;
                        phy-names = "usb2-phy", "usb3-phy";
                        compatible = "snps,dwc3";
                        reg = <0x0 0xfe900000 0x0 0x100000>;
                        interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH 0>;
+                       clocks = <&cru SCLK_USB3OTG1_REF>, <&cru ACLK_USB3OTG1>,
+                                <&cru SCLK_USB3OTG1_SUSPEND>;
+                       clock-names = "ref", "bus_early", "suspend";
                        dr_mode = "otg";
                        phys = <&u2phy1_otg>, <&tcphy1_usb3>;
                        phy-names = "usb2-phy", "usb3-phy";
                                        type = "critical";
                                };
                        };
-
-                       cooling-maps {
-                               map0 {
-                                       trip = <&gpu_alert0>;
-                                       cooling-device =
-                                               <&cpu_b0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-                                               <&cpu_b1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
-                               };
-                       };
                };
        };
 
                reg = <0x0 0xff914000 0x0 0x100>, <0x0 0xff915000 0x0 0x100>;
                interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH 0>;
                interrupt-names = "isp0_mmu";
-               clocks = <&cru ACLK_ISP0_NOC>, <&cru HCLK_ISP0_NOC>;
+               clocks = <&cru ACLK_ISP0_WRAPPER>, <&cru HCLK_ISP0_WRAPPER>;
                clock-names = "aclk", "iface";
                #iommu-cells = <0>;
+               power-domains = <&power RK3399_PD_ISP0>;
                rockchip,disable-mmu-reset;
-               status = "disabled";
        };
 
        isp1_mmu: iommu@ff924000 {
                reg = <0x0 0xff924000 0x0 0x100>, <0x0 0xff925000 0x0 0x100>;
                interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH 0>;
                interrupt-names = "isp1_mmu";
-               clocks = <&cru ACLK_ISP1_NOC>, <&cru HCLK_ISP1_NOC>;
+               clocks = <&cru ACLK_ISP1_WRAPPER>, <&cru HCLK_ISP1_WRAPPER>;
                clock-names = "aclk", "iface";
                #iommu-cells = <0>;
+               power-domains = <&power RK3399_PD_ISP1>;
                rockchip,disable-mmu-reset;
-               status = "disabled";
        };
 
        hdmi_sound: hdmi-sound {
diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro.dtsi b/arch/arm64/boot/dts/rockchip/rk3399pro.dtsi
new file mode 100644 (file)
index 0000000..bb5ebf6
--- /dev/null
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd.
+
+#include "rk3399.dtsi"
+
+/ {
+       compatible = "rockchip,rk3399pro";
+};
+
+/* Default to enabled since AP talk to NPU part over pcie */
+&pcie_phy {
+       status = "okay";
+};
+
+/* Default to enabled since AP talk to NPU part over pcie */
+&pcie0 {
+       ep-gpios = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>;
+       num-lanes = <4>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pcie_clkreqn_cpm>;
+       status = "okay";
+};
index 7968d52..f72f048 100644 (file)
 
 &nand {
        status = "okay";
+
+       nand@0 {
+               reg = <0>;
+       };
 };
index a3cd475..8ec40a0 100644 (file)
@@ -8,8 +8,6 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/gpio/uniphier-gpio.h>
 
-/memreserve/ 0x80000000 0x02000000;
-
 / {
        compatible = "socionext,uniphier-ld11";
        #address-cells = <2>;
                             <1 10 4>;
        };
 
+       reserved-memory {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               secure-memory@81000000 {
+                       reg = <0x0 0x81000000 0x0 0x01000000>;
+                       no-map;
+               };
+       };
+
        soc@0 {
                compatible = "simple-bus";
                #address-cells = <1>;
                        status = "disabled";
                        reg-names = "nand_data", "denali_reg";
                        reg = <0x68000000 0x20>, <0x68100000 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
                        interrupts = <0 65 4>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_nand>;
index 017f632..b658f2b 100644 (file)
@@ -9,8 +9,6 @@
 #include <dt-bindings/gpio/uniphier-gpio.h>
 #include <dt-bindings/thermal/thermal.h>
 
-/memreserve/ 0x80000000 0x02000000;
-
 / {
        compatible = "socionext,uniphier-ld20";
        #address-cells = <2>;
                };
        };
 
+       reserved-memory {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               secure-memory@81000000 {
+                       reg = <0x0 0x81000000 0x0 0x01000000>;
+                       no-map;
+               };
+       };
+
        soc@0 {
                compatible = "simple-bus";
                #address-cells = <1>;
                        status = "disabled";
                        reg-names = "nand_data", "denali_reg";
                        reg = <0x68000000 0x20>, <0x68100000 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
                        interrupts = <0 65 4>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_nand>;
index 1965e4d..754315b 100644 (file)
 
 &nand {
        status = "okay";
+
+       nand@0 {
+               reg = <0>;
+       };
 };
index bb97abe..d6f6cee 100644 (file)
@@ -8,8 +8,6 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/gpio/uniphier-gpio.h>
 
-/memreserve/ 0x80000000 0x02000000;
-
 / {
        compatible = "socionext,uniphier-pxs3";
        #address-cells = <2>;
                             <1 10 4>;
        };
 
+       reserved-memory {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               secure-memory@81000000 {
+                       reg = <0x0 0x81000000 0x0 0x01000000>;
+                       no-map;
+               };
+       };
+
        soc@0 {
                compatible = "simple-bus";
                #address-cells = <1>;
                        status = "disabled";
                        reg-names = "nand_data", "denali_reg";
                        reg = <0x68000000 0x20>, <0x68100000 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
                        interrupts = <0 65 4>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_nand>;
index 286d717..231436b 100644 (file)
@@ -60,7 +60,7 @@
        };
 
        funnel@10001000 {
-               compatible = "arm,coresight-funnel", "arm,primecell";
+               compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                reg = <0 0x10001000 0 0x1000>;
                clocks = <&clk26mhz>;
                clock-names = "apb_pclk";
index b25d199..e27eb3e 100644 (file)
                };
 
                funnel@10001000 { /* SoC Funnel */
-                       compatible = "arm,coresight-funnel", "arm,primecell";
+                       compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                        reg = <0 0x10001000 0 0x1000>;
                        clocks = <&ext_26m>;
                        clock-names = "apb_pclk";
                };
 
                funnel@11001000 { /* Cluster0 Funnel */
-                       compatible = "arm,coresight-funnel", "arm,primecell";
+                       compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                        reg = <0 0x11001000 0 0x1000>;
                        clocks = <&ext_26m>;
                        clock-names = "apb_pclk";
                };
 
                funnel@11002000 { /* Cluster1 Funnel */
-                       compatible = "arm,coresight-funnel", "arm,primecell";
+                       compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                        reg = <0 0x11002000 0 0x1000>;
                        clocks = <&ext_26m>;
                        clock-names = "apb_pclk";
                };
 
                funnel@11005000 { /* Main Funnel */
-                       compatible = "arm,coresight-funnel", "arm,primecell";
+                       compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
                        reg = <0 0x11005000 0 0x1000>;
                        clocks = <&ext_26m>;
                        clock-names = "apb_pclk";
index 4bb862c..79b9591 100644 (file)
                                clock-names = "enable";
                                clocks = <&apahb_gate CLK_DMA_EB>;
                        };
+
+                       sdio3: sdio@50430000 {
+                               compatible  = "sprd,sdhci-r11";
+                               reg = <0 0x50430000 0 0x1000>;
+                               interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+
+                               clock-names = "sdio", "enable", "2x_enable";
+                               clocks = <&aon_prediv CLK_EMMC_2X>,
+                                      <&apahb_gate CLK_EMMC_EB>,
+                                      <&aon_gate CLK_EMMC_2X_EN>;
+                               assigned-clocks = <&aon_prediv CLK_EMMC_2X>;
+                               assigned-clock-parents = <&clk_l0_409m6>;
+
+                               sprd,phy-delay-mmc-hs400 = <0x44 0x7f 0x2e 0x2e>;
+                               sprd,phy-delay-mmc-hs200 = <0x0 0x8c 0x8c 0x8c>;
+                               sprd,phy-delay-mmc-ddr52 = <0x3f 0x75 0x14 0x14>;
+                               sprd,phy-delay-mmc-hs400es = <0x3f 0x3f 0x2e 0x2e>;
+                               vmmc-supply = <&vddemmccore>;
+                               bus-width = <8>;
+                               non-removable;
+                               no-sdio;
+                               no-sd;
+                               cap-mmc-hw-reset;
+                               mmc-hs400-enhanced-strobe;
+                               mmc-hs400-1_8v;
+                               mmc-hs200-1_8v;
+                               mmc-ddr-1_8v;
+                       };
                };
 
                aon {
                clock-frequency = <100000000>;
                clock-output-names = "ext-rco-100m";
        };
+
+       clk_l0_409m6: clk_l0_409m6 {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <409600000>;
+               clock-output-names = "ext-409m6";
+       };
 };
index 63e619d..b397945 100644 (file)
@@ -7,3 +7,5 @@
 #
 
 dtb-$(CONFIG_ARCH_K3_AM6_SOC) += k3-am654-base-board.dtb
+
+dtb-$(CONFIG_ARCH_K3_J721E_SOC) += k3-j721e-common-proc-board.dtb
index 7524552..ca70ff7 100644 (file)
@@ -4,6 +4,7 @@
  *
  * Copyright (C) 2016-2018 Texas Instruments Incorporated - http://www.ti.com/
  */
+#include <dt-bindings/phy/phy-am654-serdes.h>
 
 &cbass_main {
        msmc_ram: sram@70000000 {
@@ -44,6 +45,7 @@
                gic_its: gic-its@18200000 {
                        compatible = "arm,gic-v3-its";
                        reg = <0x00 0x01820000 0x00 0x10000>;
+                       socionext,synquacer-pre-its = <0x1000000 0x400000>;
                        msi-controller;
                        #msi-cells = <1>;
                };
                interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
        };
 
+       serdes0: serdes@900000 {
+               compatible = "ti,phy-am654-serdes";
+               reg = <0x0 0x900000 0x0 0x2000>;
+               reg-names = "serdes";
+               #phy-cells = <2>;
+               power-domains = <&k3_pds 153>;
+               clocks = <&k3_clks 153 4>, <&k3_clks 153 1>, <&serdes1 AM654_SERDES_LO_REFCLK>;
+               clock-output-names = "serdes0_cmu_refclk", "serdes0_lo_refclk", "serdes0_ro_refclk";
+               assigned-clocks = <&k3_clks 153 4>, <&serdes0 AM654_SERDES_CMU_REFCLK>;
+               assigned-clock-parents = <&k3_clks 153 8>, <&k3_clks 153 4>;
+               ti,serdes-clk = <&serdes0_clk>;
+               #clock-cells = <1>;
+               mux-controls = <&serdes_mux 0>;
+       };
+
+       serdes1: serdes@910000 {
+               compatible = "ti,phy-am654-serdes";
+               reg = <0x0 0x910000 0x0 0x2000>;
+               reg-names = "serdes";
+               #phy-cells = <2>;
+               power-domains = <&k3_pds 154>;
+               clocks = <&serdes0 AM654_SERDES_RO_REFCLK>, <&k3_clks 154 1>, <&k3_clks 154 5>;
+               clock-output-names = "serdes1_cmu_refclk", "serdes1_lo_refclk", "serdes1_ro_refclk";
+               assigned-clocks = <&k3_clks 154 5>, <&serdes1 AM654_SERDES_CMU_REFCLK>;
+               assigned-clock-parents = <&k3_clks 154 9>, <&k3_clks 154 5>;
+               ti,serdes-clk = <&serdes1_clk>;
+               #clock-cells = <1>;
+               mux-controls = <&serdes_mux 1>;
+       };
+
        main_uart0: serial@2800000 {
                compatible = "ti,am654-uart";
                reg = <0x00 0x02800000 0x00 0x100>;
                #address-cells = <1>;
                #size-cells = <1>;
                ranges = <0x0 0x0 0x00100000 0x1c000>;
+
+               pcie0_mode: pcie-mode@4060 {
+                       compatible = "syscon";
+                       reg = <0x00004060 0x4>;
+               };
+
+               pcie1_mode: pcie-mode@4070 {
+                       compatible = "syscon";
+                       reg = <0x00004070 0x4>;
+               };
+
+               pcie_devid: pcie-devid@210 {
+                       compatible = "syscon";
+                       reg = <0x00000210 0x4>;
+               };
+
+               serdes0_clk: serdes_clk@4080 {
+                       compatible = "syscon";
+                       reg = <0x00004080 0x4>;
+               };
+
+               serdes1_clk: serdes_clk@4090 {
+                       compatible = "syscon";
+                       reg = <0x00004090 0x4>;
+               };
+
+               serdes_mux: mux-controller {
+                       compatible = "mmio-mux";
+                       #mux-control-cells = <1>;
+                       mux-reg-masks = <0x4080 0x3>, /* SERDES0 lane select */
+                                       <0x4090 0x3>; /* SERDES1 lane select */
+               };
        };
 
        dwc3_0: dwc3@4000000 {
                clock-names = "wkupclk", "refclk";
                #phy-cells = <0>;
        };
+
+       intr_main_gpio: interrupt-controller0 {
+               compatible = "ti,sci-intr";
+               ti,intr-trigger-type = <1>;
+               interrupt-controller;
+               interrupt-parent = <&gic500>;
+               #interrupt-cells = <2>;
+               ti,sci = <&dmsc>;
+               ti,sci-dst-id = <56>;
+               ti,sci-rm-range-girq = <0x1>;
+       };
+
+       cbass_main_navss: interconnect0 {
+               compatible = "simple-bus";
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               intr_main_navss: interrupt-controller1 {
+                       compatible = "ti,sci-intr";
+                       ti,intr-trigger-type = <4>;
+                       interrupt-controller;
+                       interrupt-parent = <&gic500>;
+                       #interrupt-cells = <2>;
+                       ti,sci = <&dmsc>;
+                       ti,sci-dst-id = <56>;
+                       ti,sci-rm-range-girq = <0x0>, <0x2>;
+               };
+
+               inta_main_udmass: interrupt-controller@33d00000 {
+                       compatible = "ti,sci-inta";
+                       reg = <0x0 0x33d00000 0x0 0x100000>;
+                       interrupt-controller;
+                       interrupt-parent = <&intr_main_navss>;
+                       msi-controller;
+                       ti,sci = <&dmsc>;
+                       ti,sci-dev-id = <179>;
+                       ti,sci-rm-range-vint = <0x0>;
+                       ti,sci-rm-range-global-event = <0x1>;
+               };
+       };
+
+       main_gpio0:  main_gpio0@600000 {
+               compatible = "ti,am654-gpio", "ti,keystone-gpio";
+               reg = <0x0 0x600000 0x0 0x100>;
+               gpio-controller;
+               #gpio-cells = <2>;
+               interrupt-parent = <&intr_main_gpio>;
+               interrupts = <57 256>, <57 257>, <57 258>, <57 259>, <57 260>,
+                               <57 261>;
+               interrupt-controller;
+               #interrupt-cells = <2>;
+               ti,ngpio = <96>;
+               ti,davinci-gpio-unbanked = <0>;
+               clocks = <&k3_clks 57 0>;
+               clock-names = "gpio";
+       };
+
+       main_gpio1:  main_gpio1@601000 {
+               compatible = "ti,am654-gpio", "ti,keystone-gpio";
+               reg = <0x0 0x601000 0x0 0x100>;
+               gpio-controller;
+               #gpio-cells = <2>;
+               interrupt-parent = <&intr_main_gpio>;
+               interrupts = <58 256>, <58 257>, <58 258>, <58 259>, <58 260>,
+                               <58 261>;
+               interrupt-controller;
+               #interrupt-cells = <2>;
+               ti,ngpio = <90>;
+               ti,davinci-gpio-unbanked = <0>;
+               clocks = <&k3_clks 58 0>;
+               clock-names = "gpio";
+       };
+
+       pcie0_rc: pcie@5500000 {
+               compatible = "ti,am654-pcie-rc";
+               reg =  <0x0 0x5500000 0x0 0x1000>, <0x0 0x5501000 0x0 0x1000>, <0x0 0x10000000 0x0 0x2000>, <0x0 0x5506000 0x0 0x1000>;
+               reg-names = "app", "dbics", "config", "atu";
+               power-domains = <&k3_pds 120>;
+               #address-cells = <3>;
+               #size-cells = <2>;
+               ranges = <0x81000000 0 0          0x0 0x10020000 0 0x00010000
+                         0x82000000 0 0x10030000 0x0 0x10030000 0 0x07FD0000>;
+               ti,syscon-pcie-id = <&pcie_devid>;
+               ti,syscon-pcie-mode = <&pcie0_mode>;
+               bus-range = <0x0 0xff>;
+               num-viewport = <16>;
+               max-link-speed = <3>;
+               dma-coherent;
+               interrupts = <GIC_SPI 340 IRQ_TYPE_EDGE_RISING>;
+               msi-map = <0x0 &gic_its 0x0 0x10000>;
+       };
+
+       pcie0_ep: pcie-ep@5500000 {
+               compatible = "ti,am654-pcie-ep";
+               reg =  <0x0 0x5500000 0x0 0x1000>, <0x0 0x5501000 0x0 0x1000>, <0x0 0x10000000 0x0 0x8000000>, <0x0 0x5506000 0x0 0x1000>;
+               reg-names = "app", "dbics", "addr_space", "atu";
+               power-domains = <&k3_pds 120>;
+               ti,syscon-pcie-mode = <&pcie0_mode>;
+               num-ib-windows = <16>;
+               num-ob-windows = <16>;
+               max-link-speed = <3>;
+               dma-coherent;
+               interrupts = <GIC_SPI 340 IRQ_TYPE_EDGE_RISING>;
+       };
+
+       pcie1_rc: pcie@5600000 {
+               compatible = "ti,am654-pcie-rc";
+               reg =  <0x0 0x5600000 0x0 0x1000>, <0x0 0x5601000 0x0 0x1000>, <0x0 0x18000000 0x0 0x2000>, <0x0 0x5606000 0x0 0x1000>;
+               reg-names = "app", "dbics", "config", "atu";
+               power-domains = <&k3_pds 121>;
+               #address-cells = <3>;
+               #size-cells = <2>;
+               ranges = <0x81000000 0 0          0x0   0x18020000 0 0x00010000
+                         0x82000000 0 0x18030000 0x0   0x18030000 0 0x07FD0000>;
+               ti,syscon-pcie-id = <&pcie_devid>;
+               ti,syscon-pcie-mode = <&pcie1_mode>;
+               bus-range = <0x0 0xff>;
+               num-viewport = <16>;
+               max-link-speed = <3>;
+               dma-coherent;
+               interrupts = <GIC_SPI 355 IRQ_TYPE_EDGE_RISING>;
+               msi-map = <0x0 &gic_its 0x10000 0x10000>;
+       };
+
+       pcie1_ep: pcie-ep@5600000 {
+               compatible = "ti,am654-pcie-ep";
+               reg =  <0x0 0x5600000 0x0 0x1000>, <0x0 0x5601000 0x0 0x1000>, <0x0 0x18000000 0x0 0x4000000>, <0x0 0x5606000 0x0 0x1000>;
+               reg-names = "app", "dbics", "addr_space", "atu";
+               power-domains = <&k3_pds 121>;
+               ti,syscon-pcie-mode = <&pcie1_mode>;
+               num-ib-windows = <16>;
+               num-ob-windows = <16>;
+               max-link-speed = <3>;
+               dma-coherent;
+               interrupts = <GIC_SPI 355 IRQ_TYPE_EDGE_RISING>;
+       };
 };
index 6f7d2b3..afc29ea 100644 (file)
                        power-domains = <&k3_pds 149>;
        };
 
+       mcu_ram: sram@41c00000 {
+               compatible = "mmio-sram";
+               reg = <0x00 0x41c00000 0x00 0x80000>;
+               ranges = <0x0 0x00 0x41c00000 0x80000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+       };
+
        mcu_i2c0: i2c@40b00000 {
                compatible = "ti,am654-i2c", "ti,omap4-i2c";
                reg = <0x0 0x40b00000 0x0 0x100>;
index 7cbdc09..9cf2c08 100644 (file)
@@ -7,7 +7,7 @@
 
 &cbass_wakeup {
        dmsc: dmsc {
-               compatible = "ti,k2g-sci";
+               compatible = "ti,am654-sci";
                ti,host-id = <12>;
                #address-cells = <1>;
                #size-cells = <1>;
                clocks = <&k3_clks 115 1>;
                power-domains = <&k3_pds 115>;
        };
+
+       intr_wkup_gpio: interrupt-controller2 {
+               compatible = "ti,sci-intr";
+               ti,intr-trigger-type = <1>;
+               interrupt-controller;
+               interrupt-parent = <&gic500>;
+               #interrupt-cells = <2>;
+               ti,sci = <&dmsc>;
+               ti,sci-dst-id = <56>;
+               ti,sci-rm-range-girq = <0x4>;
+       };
+
+       wkup_gpio0: wkup_gpio0@42110000 {
+               compatible = "ti,am654-gpio", "ti,keystone-gpio";
+               reg = <0x42110000 0x100>;
+               gpio-controller;
+               #gpio-cells = <2>;
+               interrupt-parent = <&intr_wkup_gpio>;
+               interrupts = <59 128>, <59 129>, <59 130>, <59 131>;
+               interrupt-controller;
+               #interrupt-cells = <2>;
+               ti,ngpio = <56>;
+               ti,davinci-gpio-unbanked = <0>;
+               clocks = <&k3_clks 59 0>;
+               clock-names = "gpio";
+       };
 };
index 50f4be2..82edf10 100644 (file)
                         <0x00 0x00900000 0x00 0x00900000 0x00 0x00012000>, /* serdes */
                         <0x00 0x01000000 0x00 0x01000000 0x00 0x0af02400>, /* Most peripherals */
                         <0x00 0x30800000 0x00 0x30800000 0x00 0x0bc00000>, /* MAIN NAVSS */
+                        <0x00 0x70000000 0x00 0x70000000 0x00 0x00200000>, /* MSMC SRAM */
+                        <0x00 0x10000000 0x00 0x10000000 0x00 0x10000000>, /* PCIe DAT */
                         /* MCUSS Range */
                         <0x00 0x28380000 0x00 0x28380000 0x00 0x03880000>,
                         <0x00 0x40200000 0x00 0x40200000 0x00 0x00900100>,
+                        <0x00 0x41000000 0x00 0x41000000 0x00 0x00020000>,
+                        <0x00 0x41400000 0x00 0x41400000 0x00 0x00020000>,
+                        <0x00 0x41c00000 0x00 0x41c00000 0x00 0x00080000>,
                         <0x00 0x42040000 0x00 0x42040000 0x00 0x03ac2400>,
                         <0x00 0x45100000 0x00 0x45100000 0x00 0x00c24000>,
                         <0x00 0x46000000 0x00 0x46000000 0x00 0x00200000>,
@@ -82,6 +87,9 @@
                        #size-cells = <2>;
                        ranges = <0x00 0x28380000 0x00 0x28380000 0x00 0x03880000>, /* MCU NAVSS*/
                                 <0x00 0x40200000 0x00 0x40200000 0x00 0x00900100>, /* First peripheral window */
+                                <0x00 0x41000000 0x00 0x41000000 0x00 0x00020000>, /* MCU R5F Core0 */
+                                <0x00 0x41400000 0x00 0x41400000 0x00 0x00020000>, /* MCU R5F Core1 */
+                                <0x00 0x41c00000 0x00 0x41c00000 0x00 0x00080000>, /* MCU SRAM */
                                 <0x00 0x42040000 0x00 0x42040000 0x00 0x03ac2400>, /* WKUP */
                                 <0x00 0x45100000 0x00 0x45100000 0x00 0x00c24000>, /* MMRs, remaining NAVSS */
                                 <0x00 0x46000000 0x00 0x46000000 0x00 0x00200000>, /* CPSW */
index cf1aa27..52c245d 100644 (file)
@@ -6,6 +6,7 @@
 /dts-v1/;
 
 #include "k3-am654.dtsi"
+#include <dt-bindings/input/input.h>
 
 / {
        compatible =  "ti,am654-evm", "ti,am654";
                        no-map;
                };
        };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               autorepeat;
+               pinctrl-names = "default";
+               pinctrl-0 = <&push_button_pins_default>;
+
+               sw5 {
+                       label = "GPIO Key USER1";
+                       linux,code = <BTN_0>;
+                       gpios = <&wkup_gpio0 24 GPIO_ACTIVE_LOW>;
+               };
+
+               sw6 {
+                       label = "GPIO Key USER2";
+                       linux,code = <BTN_1>;
+                       gpios = <&wkup_gpio0 27 GPIO_ACTIVE_LOW>;
+               };
+       };
 };
 
 &wkup_pmx0 {
                        AM65X_WKUP_IOPAD(0x00e4, PIN_INPUT, 0) /* (AD6) WKUP_I2C0_SDA */
                >;
        };
+
+       push_button_pins_default: push_button__pins_default {
+               pinctrl-single,pins = <
+                       AM65X_WKUP_IOPAD(0x0030, PIN_INPUT, 7) /* (R5) WKUP_GPIO0_24 */
+                       AM65X_WKUP_IOPAD(0x003c, PIN_INPUT, 7) /* (P2) WKUP_GPIO0_27 */
+               >;
+       };
 };
 
 &main_pmx0 {
                ti,adc-channels = <0 1 2 3 4 5 6 7>;
        };
 };
+
+&serdes0 {
+       status = "disabled";
+};
+
+&serdes1 {
+       status = "disabled";
+};
+
+&pcie0_rc {
+       status = "disabled";
+};
+
+&pcie0_ep {
+       status = "disabled";
+};
+
+&pcie1_rc {
+       status = "disabled";
+};
+
+&pcie1_ep {
+       status = "disabled";
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts b/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts
new file mode 100644 (file)
index 0000000..c680123
--- /dev/null
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+/dts-v1/;
+
+#include "k3-j721e-som-p0.dtsi"
+
+/ {
+       chosen {
+               stdout-path = "serial2:115200n8";
+               bootargs = "console=ttyS2,115200n8 earlycon=ns16550a,mmio32,0x02800000";
+       };
+};
+
+&wkup_uart0 {
+       /* Wakeup UART is used by System firmware */
+       status = "disabled";
+};
+
+&main_uart3 {
+       /* UART not brought out */
+       status = "disabled";
+};
+
+&main_uart5 {
+       /* UART not brought out */
+       status = "disabled";
+};
+
+&main_uart6 {
+       /* UART not brought out */
+       status = "disabled";
+};
+
+&main_uart7 {
+       /* UART not brought out */
+       status = "disabled";
+};
+
+&main_uart8 {
+       /* UART not brought out */
+       status = "disabled";
+};
+
+&main_uart9 {
+       /* UART not brought out */
+       status = "disabled";
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi
new file mode 100644 (file)
index 0000000..a013081
--- /dev/null
@@ -0,0 +1,243 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for J721E SoC Family Main Domain peripherals
+ *
+ * Copyright (C) 2016-2019 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+&cbass_main {
+       msmc_ram: sram@70000000 {
+               compatible = "mmio-sram";
+               reg = <0x0 0x70000000 0x0 0x800000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0x0 0x70000000 0x800000>;
+
+               atf-sram@0 {
+                       reg = <0x0 0x20000>;
+               };
+       };
+
+       gic500: interrupt-controller@1800000 {
+               compatible = "arm,gic-v3";
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+               #interrupt-cells = <3>;
+               interrupt-controller;
+               reg = <0x00 0x01800000 0x00 0x10000>,   /* GICD */
+                     <0x00 0x01900000 0x00 0x100000>;  /* GICR */
+
+               /* vcpumntirq: virtual CPU interface maintenance interrupt */
+               interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+
+               gic_its: gic-its@18200000 {
+                       compatible = "arm,gic-v3-its";
+                       reg = <0x00 0x01820000 0x00 0x10000>;
+                       socionext,synquacer-pre-its = <0x1000000 0x400000>;
+                       msi-controller;
+                       #msi-cells = <1>;
+               };
+       };
+
+       smmu0: smmu@36600000 {
+               compatible = "arm,smmu-v3";
+               reg = <0x0 0x36600000 0x0 0x100000>;
+               interrupt-parent = <&gic500>;
+               interrupts = <GIC_SPI 772 IRQ_TYPE_EDGE_RISING>,
+                            <GIC_SPI 768 IRQ_TYPE_EDGE_RISING>;
+               interrupt-names = "eventq", "gerror";
+               #iommu-cells = <1>;
+       };
+
+       main_gpio_intr: interrupt-controller0 {
+               compatible = "ti,sci-intr";
+               ti,intr-trigger-type = <1>;
+               interrupt-controller;
+               interrupt-parent = <&gic500>;
+               #interrupt-cells = <2>;
+               ti,sci = <&dmsc>;
+               ti,sci-dst-id = <14>;
+               ti,sci-rm-range-girq = <0x1>;
+       };
+
+       cbass_main_navss: interconnect0 {
+               compatible = "simple-bus";
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               main_navss_intr: interrupt-controller1 {
+                       compatible = "ti,sci-intr";
+                       ti,intr-trigger-type = <4>;
+                       interrupt-controller;
+                       interrupt-parent = <&gic500>;
+                       #interrupt-cells = <2>;
+                       ti,sci = <&dmsc>;
+                       ti,sci-dst-id = <14>;
+                       ti,sci-rm-range-girq = <0>, <2>;
+               };
+
+               main_udmass_inta: interrupt-controller@33d00000 {
+                       compatible = "ti,sci-inta";
+                       reg = <0x0 0x33d00000 0x0 0x100000>;
+                       interrupt-controller;
+                       interrupt-parent = <&main_navss_intr>;
+                       msi-controller;
+                       ti,sci = <&dmsc>;
+                       ti,sci-dev-id = <209>;
+                       ti,sci-rm-range-vint = <0xa>;
+                       ti,sci-rm-range-global-event = <0xd>;
+               };
+       };
+
+       secure_proxy_main: mailbox@32c00000 {
+               compatible = "ti,am654-secure-proxy";
+               #mbox-cells = <1>;
+               reg-names = "target_data", "rt", "scfg";
+               reg = <0x00 0x32c00000 0x00 0x100000>,
+                     <0x00 0x32400000 0x00 0x100000>,
+                     <0x00 0x32800000 0x00 0x100000>;
+               interrupt-names = "rx_011";
+               interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+       };
+
+       main_pmx0: pinmux@11c000 {
+               compatible = "pinctrl-single";
+               /* Proxy 0 addressing */
+               reg = <0x0 0x11c000 0x0 0x2b4>;
+               #pinctrl-cells = <1>;
+               pinctrl-single,register-width = <32>;
+               pinctrl-single,function-mask = <0xffffffff>;
+       };
+
+       main_uart0: serial@2800000 {
+               compatible = "ti,j721e-uart", "ti,am654-uart";
+               reg = <0x00 0x02800000 0x00 0x100>;
+               reg-shift = <2>;
+               reg-io-width = <4>;
+               interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>;
+               clock-frequency = <48000000>;
+               current-speed = <115200>;
+               power-domains = <&k3_pds 146>;
+               clocks = <&k3_clks 146 0>;
+               clock-names = "fclk";
+       };
+
+       main_uart1: serial@2810000 {
+               compatible = "ti,j721e-uart", "ti,am654-uart";
+               reg = <0x00 0x02810000 0x00 0x100>;
+               reg-shift = <2>;
+               reg-io-width = <4>;
+               interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
+               clock-frequency = <48000000>;
+               current-speed = <115200>;
+               power-domains = <&k3_pds 278>;
+               clocks = <&k3_clks 278 0>;
+               clock-names = "fclk";
+       };
+
+       main_uart2: serial@2820000 {
+               compatible = "ti,j721e-uart", "ti,am654-uart";
+               reg = <0x00 0x02820000 0x00 0x100>;
+               reg-shift = <2>;
+               reg-io-width = <4>;
+               interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>;
+               clock-frequency = <48000000>;
+               current-speed = <115200>;
+               power-domains = <&k3_pds 279>;
+               clocks = <&k3_clks 279 0>;
+               clock-names = "fclk";
+       };
+
+       main_uart3: serial@2830000 {
+               compatible = "ti,j721e-uart", "ti,am654-uart";
+               reg = <0x00 0x02830000 0x00 0x100>;
+               reg-shift = <2>;
+               reg-io-width = <4>;
+               interrupts = <GIC_SPI 195 IRQ_TYPE_LEVEL_HIGH>;
+               clock-frequency = <48000000>;
+               current-speed = <115200>;
+               power-domains = <&k3_pds 280>;
+               clocks = <&k3_clks 280 0>;
+               clock-names = "fclk";
+       };
+
+       main_uart4: serial@2840000 {
+               compatible = "ti,j721e-uart", "ti,am654-uart";
+               reg = <0x00 0x02840000 0x00 0x100>;
+               reg-shift = <2>;
+               reg-io-width = <4>;
+               interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>;
+               clock-frequency = <48000000>;
+               current-speed = <115200>;
+               power-domains = <&k3_pds 281>;
+               clocks = <&k3_clks 281 0>;
+               clock-names = "fclk";
+       };
+
+       main_uart5: serial@2850000 {
+               compatible = "ti,j721e-uart", "ti,am654-uart";
+               reg = <0x00 0x02850000 0x00 0x100>;
+               reg-shift = <2>;
+               reg-io-width = <4>;
+               interrupts = <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>;
+               clock-frequency = <48000000>;
+               current-speed = <115200>;
+               power-domains = <&k3_pds 282>;
+               clocks = <&k3_clks 282 0>;
+               clock-names = "fclk";
+       };
+
+       main_uart6: serial@2860000 {
+               compatible = "ti,j721e-uart", "ti,am654-uart";
+               reg = <0x00 0x02860000 0x00 0x100>;
+               reg-shift = <2>;
+               reg-io-width = <4>;
+               interrupts = <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>;
+               clock-frequency = <48000000>;
+               current-speed = <115200>;
+               power-domains = <&k3_pds 283>;
+               clocks = <&k3_clks 283 0>;
+               clock-names = "fclk";
+       };
+
+       main_uart7: serial@2870000 {
+               compatible = "ti,j721e-uart", "ti,am654-uart";
+               reg = <0x00 0x02870000 0x00 0x100>;
+               reg-shift = <2>;
+               reg-io-width = <4>;
+               interrupts = <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
+               clock-frequency = <48000000>;
+               current-speed = <115200>;
+               power-domains = <&k3_pds 284>;
+               clocks = <&k3_clks 284 0>;
+               clock-names = "fclk";
+       };
+
+       main_uart8: serial@2880000 {
+               compatible = "ti,j721e-uart", "ti,am654-uart";
+               reg = <0x00 0x02880000 0x00 0x100>;
+               reg-shift = <2>;
+               reg-io-width = <4>;
+               interrupts = <GIC_SPI 248 IRQ_TYPE_LEVEL_HIGH>;
+               clock-frequency = <48000000>;
+               current-speed = <115200>;
+               power-domains = <&k3_pds 285>;
+               clocks = <&k3_clks 285 0>;
+               clock-names = "fclk";
+       };
+
+       main_uart9: serial@2890000 {
+               compatible = "ti,j721e-uart", "ti,am654-uart";
+               reg = <0x00 0x02890000 0x00 0x100>;
+               reg-shift = <2>;
+               reg-io-width = <4>;
+               interrupts = <GIC_SPI 249 IRQ_TYPE_LEVEL_HIGH>;
+               clock-frequency = <48000000>;
+               current-speed = <115200>;
+               power-domains = <&k3_pds 286>;
+               clocks = <&k3_clks 286 0>;
+               clock-names = "fclk";
+       };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi
new file mode 100644 (file)
index 0000000..07b58ee
--- /dev/null
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for J721E SoC Family MCU/WAKEUP Domain peripherals
+ *
+ * Copyright (C) 2016-2019 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+&cbass_mcu_wakeup {
+       dmsc: dmsc@44083000 {
+               compatible = "ti,k2g-sci";
+               ti,host-id = <12>;
+
+               mbox-names = "rx", "tx";
+
+               mboxes= <&secure_proxy_main 11>,
+                       <&secure_proxy_main 13>;
+
+               reg-names = "debug_messages";
+               reg = <0x00 0x44083000 0x0 0x1000>;
+
+               k3_pds: power-controller {
+                       compatible = "ti,sci-pm-domain";
+                       #power-domain-cells = <1>;
+               };
+
+               k3_clks: clocks {
+                       compatible = "ti,k2g-sci-clk";
+                       #clock-cells = <2>;
+               };
+
+               k3_reset: reset-controller {
+                       compatible = "ti,sci-reset";
+                       #reset-cells = <2>;
+               };
+       };
+
+       wkup_pmx0: pinmux@4301c000 {
+               compatible = "pinctrl-single";
+               /* Proxy 0 addressing */
+               reg = <0x00 0x4301c000 0x00 0x178>;
+               #pinctrl-cells = <1>;
+               pinctrl-single,register-width = <32>;
+               pinctrl-single,function-mask = <0xffffffff>;
+       };
+
+       mcu_ram: sram@41c00000 {
+               compatible = "mmio-sram";
+               reg = <0x00 0x41c00000 0x00 0x100000>;
+               ranges = <0x0 0x00 0x41c00000 0x100000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+       };
+
+       wkup_uart0: serial@42300000 {
+               compatible = "ti,j721e-uart", "ti,am654-uart";
+               reg = <0x00 0x42300000 0x00 0x100>;
+               reg-shift = <2>;
+               reg-io-width = <4>;
+               interrupts = <GIC_SPI 897 IRQ_TYPE_LEVEL_HIGH>;
+               clock-frequency = <48000000>;
+               current-speed = <115200>;
+               power-domains = <&k3_pds 287>;
+               clocks = <&k3_clks 287 0>;
+               clock-names = "fclk";
+       };
+
+       mcu_uart0: serial@40a00000 {
+               compatible = "ti,j721e-uart", "ti,am654-uart";
+               reg = <0x00 0x40a00000 0x00 0x100>;
+               reg-shift = <2>;
+               reg-io-width = <4>;
+               interrupts = <GIC_SPI 846 IRQ_TYPE_LEVEL_HIGH>;
+               clock-frequency = <96000000>;
+               current-speed = <115200>;
+               power-domains = <&k3_pds 149>;
+               clocks = <&k3_clks 149 0>;
+               clock-names = "fclk";
+       };
+
+       wkup_gpio_intr: interrupt-controller2 {
+               compatible = "ti,sci-intr";
+               ti,intr-trigger-type = <1>;
+               interrupt-controller;
+               interrupt-parent = <&gic500>;
+               #interrupt-cells = <2>;
+               ti,sci = <&dmsc>;
+               ti,sci-dst-id = <14>;
+               ti,sci-rm-range-girq = <0x5>;
+       };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi
new file mode 100644 (file)
index 0000000..1884fc7
--- /dev/null
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+/dts-v1/;
+
+#include "k3-j721e.dtsi"
+
+/ {
+       memory@80000000 {
+               device_type = "memory";
+               /* 4G RAM */
+               reg = <0x00000000 0x80000000 0x00000000 0x80000000>,
+                     <0x00000008 0x80000000 0x00000000 0x80000000>;
+       };
+
+       reserved_memory: reserved-memory {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               secure_ddr: optee@9e800000 {
+                       reg = <0x00 0x9e800000 0x00 0x01800000>;
+                       alignment = <0x1000>;
+                       no-map;
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e.dtsi b/arch/arm64/boot/dts/ti/k3-j721e.dtsi
new file mode 100644 (file)
index 0000000..f8dd74b
--- /dev/null
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for J721E SoC Family
+ *
+ * Copyright (C) 2016-2019 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/pinctrl/k3.h>
+
+/ {
+       model = "Texas Instruments K3 J721E SoC";
+       compatible = "ti,j721e";
+       interrupt-parent = <&gic500>;
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       aliases {
+               serial0 = &wkup_uart0;
+               serial1 = &mcu_uart0;
+               serial2 = &main_uart0;
+               serial3 = &main_uart1;
+               serial4 = &main_uart2;
+               serial5 = &main_uart3;
+               serial6 = &main_uart4;
+               serial7 = &main_uart5;
+               serial8 = &main_uart6;
+               serial9 = &main_uart7;
+               serial10 = &main_uart8;
+               serial11 = &main_uart9;
+       };
+
+       chosen { };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               cpu-map {
+                       cluster0: cluster0 {
+                               core0 {
+                                       cpu = <&cpu0>;
+                               };
+
+                               core1 {
+                                       cpu = <&cpu1>;
+                               };
+                       };
+
+               };
+
+               cpu0: cpu@0 {
+                       compatible = "arm,cortex-a72";
+                       reg = <0x000>;
+                       device_type = "cpu";
+                       enable-method = "psci";
+                       i-cache-size = <0xC000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <256>;
+                       d-cache-size = <0x8000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <128>;
+                       next-level-cache = <&L2_0>;
+               };
+
+               cpu1: cpu@1 {
+                       compatible = "arm,cortex-a72";
+                       reg = <0x001>;
+                       device_type = "cpu";
+                       enable-method = "psci";
+                       i-cache-size = <0xC000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <256>;
+                       d-cache-size = <0x8000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <128>;
+                       next-level-cache = <&L2_0>;
+               };
+       };
+
+       L2_0: l2-cache0 {
+               compatible = "cache";
+               cache-level = <2>;
+               cache-size = <0x100000>;
+               cache-line-size = <64>;
+               cache-sets = <2048>;
+               next-level-cache = <&msmc_l3>;
+       };
+
+       msmc_l3: l3-cache0 {
+               compatible = "cache";
+               cache-level = <3>;
+       };
+
+       firmware {
+               optee {
+                       compatible = "linaro,optee-tz";
+                       method = "smc";
+               };
+
+               psci: psci {
+                       compatible = "arm,psci-1.0";
+                       method = "smc";
+               };
+       };
+
+       a72_timer0: timer-cl0-cpu0 {
+               compatible = "arm,armv8-timer";
+               interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>, /* cntpsirq */
+                            <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>, /* cntpnsirq */
+                            <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>, /* cntvirq */
+                            <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>; /* cnthpirq */
+       };
+
+       pmu: pmu {
+               compatible = "arm,armv8-pmuv3";
+               /* Recommendation from GIC500 TRM Table A.3 */
+               interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH>;
+       };
+
+       cbass_main: interconnect@100000 {
+               compatible = "simple-bus";
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges = <0x00 0x00100000 0x00 0x00100000 0x00 0x00020000>, /* ctrl mmr */
+                        <0x00 0x00600000 0x00 0x00600000 0x00 0x00031100>, /* GPIO */
+                        <0x00 0x00900000 0x00 0x00900000 0x00 0x00012000>, /* serdes */
+                        <0x00 0x00A40000 0x00 0x00A40000 0x00 0x00000800>, /* timesync router */
+                        <0x00 0x01000000 0x00 0x01000000 0x00 0x0af02400>, /* Most peripherals */
+                        <0x00 0x30800000 0x00 0x30800000 0x00 0x0bc00000>, /* MAIN NAVSS */
+                        <0x00 0x0d000000 0x00 0x0d000000 0x00 0x01000000>, /* PCIe Core*/
+                        <0x00 0x10000000 0x00 0x10000000 0x00 0x10000000>, /* PCIe DAT */
+                        <0x00 0x64800000 0x00 0x64800000 0x00 0x00800000>, /* C71 */
+                        <0x4d 0x80800000 0x4d 0x80800000 0x00 0x00800000>, /* C66_0 */
+                        <0x4d 0x81800000 0x4d 0x81800000 0x00 0x00800000>, /* C66_1 */
+                        <0x4e 0x20000000 0x4e 0x20000000 0x00 0x00080000>, /* GPU */
+                        <0x00 0x70000000 0x00 0x70000000 0x00 0x00800000>, /* MSMC RAM */
+
+                        /* MCUSS_WKUP Range */
+                        <0x00 0x28380000 0x00 0x28380000 0x00 0x03880000>,
+                        <0x00 0x40200000 0x00 0x40200000 0x00 0x00998400>,
+                        <0x00 0x40f00000 0x00 0x40f00000 0x00 0x00020000>,
+                        <0x00 0x41000000 0x00 0x41000000 0x00 0x00020000>,
+                        <0x00 0x41400000 0x00 0x41400000 0x00 0x00020000>,
+                        <0x00 0x41c00000 0x00 0x41c00000 0x00 0x00100000>,
+                        <0x00 0x42040000 0x00 0x42040000 0x00 0x03ac2400>,
+                        <0x00 0x45100000 0x00 0x45100000 0x00 0x00c24000>,
+                        <0x00 0x46000000 0x00 0x46000000 0x00 0x00200000>,
+                        <0x00 0x47000000 0x00 0x47000000 0x00 0x00068400>,
+                        <0x00 0x50000000 0x00 0x50000000 0x00 0x10000000>,
+                        <0x05 0x00000000 0x05 0x00000000 0x01 0x00000000>,
+                        <0x07 0x00000000 0x07 0x00000000 0x01 0x00000000>;
+
+               cbass_mcu_wakeup: interconnect@28380000 {
+                       compatible = "simple-bus";
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges = <0x00 0x28380000 0x00 0x28380000 0x00 0x03880000>, /* MCU NAVSS*/
+                                <0x00 0x40200000 0x00 0x40200000 0x00 0x00998400>, /* First peripheral window */
+                                <0x00 0x40f00000 0x00 0x40f00000 0x00 0x00020000>, /* CTRL_MMR0 */
+                                <0x00 0x41000000 0x00 0x41000000 0x00 0x00020000>, /* MCU R5F Core0 */
+                                <0x00 0x41400000 0x00 0x41400000 0x00 0x00020000>, /* MCU R5F Core1 */
+                                <0x00 0x41c00000 0x00 0x41c00000 0x00 0x00100000>, /* MCU SRAM */
+                                <0x00 0x42040000 0x00 0x42040000 0x00 0x03ac2400>, /* WKUP peripheral window */
+                                <0x00 0x45100000 0x00 0x45100000 0x00 0x00c24000>, /* MMRs, remaining NAVSS */
+                                <0x00 0x46000000 0x00 0x46000000 0x00 0x00200000>, /* CPSW */
+                                <0x00 0x47000000 0x00 0x47000000 0x00 0x00068400>, /* OSPI register space */
+                                <0x00 0x50000000 0x00 0x50000000 0x00 0x10000000>, /* FSS OSPI0/1 data region 0 */
+                                <0x05 0x00000000 0x05 0x00000000 0x01 0x00000000>, /* FSS OSPI0 data region 3 */
+                                <0x07 0x00000000 0x07 0x00000000 0x01 0x00000000>; /* FSS OSPI1 data region 3*/
+               };
+       };
+};
+
+/* Now include the peripherals for each bus segments */
+#include "k3-j721e-main.dtsi"
+#include "k3-j721e-mcu-wakeup.dtsi"
index dd827e6..0e58ef0 100644 (file)
@@ -83,6 +83,7 @@ CONFIG_CPUFREQ_DT=y
 CONFIG_ACPI_CPPC_CPUFREQ=m
 CONFIG_ARM_ARMADA_37XX_CPUFREQ=y
 CONFIG_ARM_SCPI_CPUFREQ=y
+CONFIG_ARM_IMX_CPUFREQ_DT=m
 CONFIG_ARM_TEGRA186_CPUFREQ=y
 CONFIG_ARM_SCPI_PROTOCOL=y
 CONFIG_RASPBERRYPI_FIRMWARE=y
@@ -192,7 +193,7 @@ CONFIG_PCIE_QCOM=y
 CONFIG_PCIE_ARMADA_8K=y
 CONFIG_PCIE_KIRIN=y
 CONFIG_PCIE_HISI_STB=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_PCIE_TEGRA194=m
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_HISILICON_LPC=y
@@ -216,6 +217,7 @@ CONFIG_BLK_DEV_SD=y
 CONFIG_SCSI_SAS_ATA=y
 CONFIG_SCSI_HISI_SAS=y
 CONFIG_SCSI_HISI_SAS_PCI=y
+CONFIG_SCSI_MPT3SAS=m
 CONFIG_SCSI_UFSHCD=y
 CONFIG_SCSI_UFSHCD_PLATFORM=y
 CONFIG_SCSI_UFS_QCOM=m
@@ -231,6 +233,11 @@ CONFIG_SATA_SIL24=y
 CONFIG_SATA_RCAR=y
 CONFIG_PATA_PLATFORM=y
 CONFIG_PATA_OF_PLATFORM=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
 CONFIG_NETDEVICES=y
 CONFIG_MACVLAN=m
 CONFIG_MACVTAP=m
@@ -240,6 +247,7 @@ CONFIG_VIRTIO_NET=y
 CONFIG_AMD_XGBE=y
 CONFIG_NET_XGENE=y
 CONFIG_ATL1C=m
+CONFIG_BNX2X=m
 CONFIG_MACB=y
 CONFIG_THUNDER_NIC_PF=y
 CONFIG_FEC=y
@@ -252,6 +260,15 @@ CONFIG_HNS3_ENET=y
 CONFIG_E1000E=y
 CONFIG_IGB=y
 CONFIG_IGBVF=y
+CONFIG_MLX4_EN=m
+CONFIG_MLX4_CORE=m
+CONFIG_MLX4_DEBUG=y
+CONFIG_MLX4_CORE_GEN2=y
+CONFIG_MLX5_CORE=m
+CONFIG_MLX5_CORE_EN=y
+CONFIG_MLX5_EN_ARFS=y
+CONFIG_MLX5_EN_RXNFC=y
+CONFIG_MLX5_MPFS=y
 CONFIG_MVNETA=y
 CONFIG_MVPP2=y
 CONFIG_SKY2=y
@@ -291,6 +308,7 @@ CONFIG_WLCORE_SDIO=m
 CONFIG_INPUT_EVDEV=y
 CONFIG_KEYBOARD_ADC=m
 CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_SNVS_PWRKEY=m
 CONFIG_KEYBOARD_CROS_EC=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ATMEL_MXT=m
@@ -344,6 +362,7 @@ CONFIG_I2C_BCM2835=m
 CONFIG_I2C_DESIGNWARE_PLATFORM=y
 CONFIG_I2C_GPIO=m
 CONFIG_I2C_IMX=y
+CONFIG_I2C_IMX_LPI2C=y
 CONFIG_I2C_MESON=y
 CONFIG_I2C_MV64XXX=y
 CONFIG_I2C_PXA=y
@@ -359,6 +378,7 @@ CONFIG_SPI_ARMADA_3700=y
 CONFIG_SPI_BCM2835=m
 CONFIG_SPI_BCM2835AUX=m
 CONFIG_SPI_NXP_FLEXSPI=y
+CONFIG_SPI_IMX=m
 CONFIG_SPI_MESON_SPICC=m
 CONFIG_SPI_MESON_SPIFC=m
 CONFIG_SPI_ORION=y
@@ -371,6 +391,7 @@ CONFIG_SPI_SUN6I=y
 CONFIG_SPMI=y
 CONFIG_PINCTRL_SINGLE=y
 CONFIG_PINCTRL_MAX77620=y
+CONFIG_PINCTRL_IMX8MM=y
 CONFIG_PINCTRL_IMX8MQ=y
 CONFIG_PINCTRL_IMX8QXP=y
 CONFIG_PINCTRL_IPQ8074=y
@@ -389,6 +410,7 @@ CONFIG_GPIO_RCAR=y
 CONFIG_GPIO_UNIPHIER=y
 CONFIG_GPIO_XGENE=y
 CONFIG_GPIO_XGENE_SB=y
+CONFIG_GPIO_MAX732X=y
 CONFIG_GPIO_PCA953X=y
 CONFIG_GPIO_PCA953X_IRQ=y
 CONFIG_GPIO_MAX77620=y
@@ -405,9 +427,11 @@ CONFIG_SENSORS_LM90=m
 CONFIG_SENSORS_PWM_FAN=m
 CONFIG_SENSORS_RASPBERRYPI_HWMON=m
 CONFIG_SENSORS_INA2XX=m
+CONFIG_SENSORS_INA3221=m
 CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y
 CONFIG_CPU_THERMAL=y
 CONFIG_THERMAL_EMULATION=y
+CONFIG_QORIQ_THERMAL=m
 CONFIG_ROCKCHIP_THERMAL=m
 CONFIG_RCAR_THERMAL=y
 CONFIG_RCAR_GEN3_THERMAL=y
@@ -421,7 +445,9 @@ CONFIG_UNIPHIER_THERMAL=y
 CONFIG_WATCHDOG=y
 CONFIG_ARM_SP805_WATCHDOG=y
 CONFIG_S3C2410_WATCHDOG=y
+CONFIG_SUNXI_WATCHDOG=m
 CONFIG_IMX2_WDT=y
+CONFIG_IMX_SC_WDT=m
 CONFIG_MESON_GXBB_WATCHDOG=m
 CONFIG_MESON_WATCHDOG=m
 CONFIG_RENESAS_WDT=y
@@ -440,8 +466,10 @@ CONFIG_MFD_MAX77620=y
 CONFIG_MFD_SPMI_PMIC=y
 CONFIG_MFD_RK808=y
 CONFIG_MFD_SEC_CORE=y
+CONFIG_MFD_ROHM_BD718XX=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_AXP20X=y
+CONFIG_REGULATOR_BD718XX=y
 CONFIG_REGULATOR_BD9571MWV=y
 CONFIG_REGULATOR_FAN53555=y
 CONFIG_REGULATOR_GPIO=y
@@ -479,6 +507,7 @@ CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m
 CONFIG_VIDEO_RENESAS_FCP=m
 CONFIG_VIDEO_RENESAS_VSP1=m
 CONFIG_DRM=m
+CONFIG_DRM_I2C_NXP_TDA998X=m
 CONFIG_DRM_NOUVEAU=m
 CONFIG_DRM_EXYNOS=m
 CONFIG_DRM_EXYNOS5433_DECON=y
@@ -506,6 +535,8 @@ CONFIG_DRM_HISI_HIBMC=m
 CONFIG_DRM_HISI_KIRIN=m
 CONFIG_DRM_MESON=m
 CONFIG_DRM_PL111=m
+CONFIG_DRM_LIMA=m
+CONFIG_DRM_PANFROST=m
 CONFIG_FB=y
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_BACKLIGHT_GENERIC=m
@@ -561,6 +592,8 @@ CONFIG_USB_ULPI=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_RENESAS_USBHS_UDC=m
 CONFIG_USB_RENESAS_USB3=m
+CONFIG_TYPEC=m
+CONFIG_TYPEC_HD3SS3220=m
 CONFIG_MMC=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_ARMMMCI=y
@@ -611,11 +644,13 @@ CONFIG_RTC_DRV_PL031=y
 CONFIG_RTC_DRV_SUN6I=y
 CONFIG_RTC_DRV_ARMADA38X=y
 CONFIG_RTC_DRV_TEGRA=y
+CONFIG_RTC_DRV_SNVS=m
 CONFIG_RTC_DRV_IMX_SC=m
 CONFIG_RTC_DRV_XGENE=y
 CONFIG_DMADEVICES=y
 CONFIG_FSL_EDMA=y
 CONFIG_DMA_BCM2835=m
+CONFIG_DMA_SUN6I=m
 CONFIG_K3_DMA=y
 CONFIG_MV_XOR=y
 CONFIG_MV_XOR_V2=y
@@ -641,6 +676,7 @@ CONFIG_COMMON_CLK_CS2000_CP=y
 CONFIG_COMMON_CLK_S2MPS11=y
 CONFIG_CLK_QORIQ=y
 CONFIG_COMMON_CLK_PWM=y
+CONFIG_CLK_IMX8MM=y
 CONFIG_CLK_IMX8MQ=y
 CONFIG_CLK_IMX8QXP=y
 CONFIG_TI_SCI_CLK=y
@@ -675,6 +711,7 @@ CONFIG_RPMSG_QCOM_GLINK_RPM=y
 CONFIG_RPMSG_QCOM_GLINK_SMEM=m
 CONFIG_RPMSG_QCOM_SMD=y
 CONFIG_RASPBERRYPI_POWER=y
+CONFIG_IMX_SCU_SOC=y
 CONFIG_QCOM_COMMAND_DB=y
 CONFIG_QCOM_GENI_SE=y
 CONFIG_QCOM_GLINK_SSR=m
@@ -698,6 +735,7 @@ CONFIG_ARCH_TEGRA_210_SOC=y
 CONFIG_ARCH_TEGRA_186_SOC=y
 CONFIG_ARCH_TEGRA_194_SOC=y
 CONFIG_ARCH_K3_AM6_SOC=y
+CONFIG_ARCH_K3_J721E_SOC=y
 CONFIG_SOC_TI=y
 CONFIG_TI_SCI_PM_DOMAINS=y
 CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y
@@ -710,7 +748,9 @@ CONFIG_ROCKCHIP_SARADC=m
 CONFIG_IIO_CROS_EC_SENSORS_CORE=m
 CONFIG_IIO_CROS_EC_SENSORS=m
 CONFIG_IIO_CROS_EC_LIGHT_PROX=m
+CONFIG_SENSORS_ISL29018=m
 CONFIG_IIO_CROS_EC_BARO=m
+CONFIG_MPL3115=m
 CONFIG_PWM=y
 CONFIG_PWM_BCM2835=m
 CONFIG_PWM_CROS_EC=m
@@ -743,6 +783,9 @@ CONFIG_PHY_TEGRA_XUSB=y
 CONFIG_HISI_PMU=y
 CONFIG_QCOM_L2_PMU=y
 CONFIG_QCOM_L3_PMU=y
+CONFIG_NVMEM_SUNXI_SID=y
+CONFIG_NVMEM_IMX_OCOTP=y
+CONFIG_NVMEM_IMX_OCOTP_SCU=y
 CONFIG_QCOM_QFPROM=y
 CONFIG_ROCKCHIP_EFUSE=y
 CONFIG_UNIPHIER_EFUSE=y
index f318258..92d2e9f 100644 (file)
@@ -16,6 +16,7 @@
 #define PTE_WRITE              (PTE_DBM)                /* same as DBM (51) */
 #define PTE_DIRTY              (_AT(pteval_t, 1) << 55)
 #define PTE_SPECIAL            (_AT(pteval_t, 1) << 56)
+#define PTE_DEVMAP             (_AT(pteval_t, 1) << 57)
 #define PTE_PROT_NONE          (_AT(pteval_t, 1) << 58) /* only when !PTE_VALID */
 
 #ifndef __ASSEMBLY__
index 3052381..87a4b2d 100644 (file)
@@ -79,6 +79,7 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
 #define pte_write(pte)         (!!(pte_val(pte) & PTE_WRITE))
 #define pte_user_exec(pte)     (!(pte_val(pte) & PTE_UXN))
 #define pte_cont(pte)          (!!(pte_val(pte) & PTE_CONT))
+#define pte_devmap(pte)                (!!(pte_val(pte) & PTE_DEVMAP))
 
 #define pte_cont_addr_end(addr, end)                                           \
 ({     unsigned long __boundary = ((addr) + CONT_PTE_SIZE) & CONT_PTE_MASK;    \
@@ -206,6 +207,11 @@ static inline pmd_t pmd_mkcont(pmd_t pmd)
        return __pmd(pmd_val(pmd) | PMD_SECT_CONT);
 }
 
+static inline pte_t pte_mkdevmap(pte_t pte)
+{
+       return set_pte_bit(pte, __pgprot(PTE_DEVMAP));
+}
+
 static inline void set_pte(pte_t *ptep, pte_t pte)
 {
        WRITE_ONCE(*ptep, pte);
@@ -388,6 +394,11 @@ static inline int pmd_protnone(pmd_t pmd)
 
 #define pmd_mkhuge(pmd)                (__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT))
 
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+#define pmd_devmap(pmd)                pte_devmap(pmd_pte(pmd))
+#endif
+#define pmd_mkdevmap(pmd)      pte_pmd(pte_mkdevmap(pmd_pte(pmd)))
+
 #define __pmd_to_phys(pmd)     __pte_to_phys(pmd_pte(pmd))
 #define __phys_to_pmd_val(phys)        __phys_to_pte_val(phys)
 #define pmd_pfn(pmd)           ((__pmd_to_phys(pmd) & PMD_MASK) >> PAGE_SHIFT)
@@ -673,6 +684,16 @@ static inline int pmdp_set_access_flags(struct vm_area_struct *vma,
 {
        return ptep_set_access_flags(vma, address, (pte_t *)pmdp, pmd_pte(entry), dirty);
 }
+
+static inline int pud_devmap(pud_t pud)
+{
+       return 0;
+}
+
+static inline int pgd_devmap(pgd_t pgd)
+{
+       return 0;
+}
 #endif
 
 /*
index a7522fc..06ebcfe 100644 (file)
@@ -9,7 +9,7 @@
 #ifndef __ASM_SYSREG_H
 #define __ASM_SYSREG_H
 
-#include <linux/const.h>
+#include <linux/bits.h>
 #include <linux/stringify.h>
 
 /*
 #define SYS_CNTV_CVAL_EL02             sys_reg(3, 5, 14, 3, 2)
 
 /* Common SCTLR_ELx flags. */
-#define SCTLR_ELx_DSSBS        (_BITUL(44))
-#define SCTLR_ELx_ENIA (_BITUL(31))
-#define SCTLR_ELx_ENIB (_BITUL(30))
-#define SCTLR_ELx_ENDA (_BITUL(27))
-#define SCTLR_ELx_EE    (_BITUL(25))
-#define SCTLR_ELx_IESB (_BITUL(21))
-#define SCTLR_ELx_WXN  (_BITUL(19))
-#define SCTLR_ELx_ENDB (_BITUL(13))
-#define SCTLR_ELx_I    (_BITUL(12))
-#define SCTLR_ELx_SA   (_BITUL(3))
-#define SCTLR_ELx_C    (_BITUL(2))
-#define SCTLR_ELx_A    (_BITUL(1))
-#define SCTLR_ELx_M    (_BITUL(0))
+#define SCTLR_ELx_DSSBS        (BIT(44))
+#define SCTLR_ELx_ENIA (BIT(31))
+#define SCTLR_ELx_ENIB (BIT(30))
+#define SCTLR_ELx_ENDA (BIT(27))
+#define SCTLR_ELx_EE    (BIT(25))
+#define SCTLR_ELx_IESB (BIT(21))
+#define SCTLR_ELx_WXN  (BIT(19))
+#define SCTLR_ELx_ENDB (BIT(13))
+#define SCTLR_ELx_I    (BIT(12))
+#define SCTLR_ELx_SA   (BIT(3))
+#define SCTLR_ELx_C    (BIT(2))
+#define SCTLR_ELx_A    (BIT(1))
+#define SCTLR_ELx_M    (BIT(0))
 
 #define SCTLR_ELx_FLAGS        (SCTLR_ELx_M  | SCTLR_ELx_A | SCTLR_ELx_C | \
                         SCTLR_ELx_SA | SCTLR_ELx_I | SCTLR_ELx_IESB)
 
 /* SCTLR_EL2 specific flags. */
-#define SCTLR_EL2_RES1 ((_BITUL(4))  | (_BITUL(5))  | (_BITUL(11)) | (_BITUL(16)) | \
-                        (_BITUL(18)) | (_BITUL(22)) | (_BITUL(23)) | (_BITUL(28)) | \
-                        (_BITUL(29)))
-#define SCTLR_EL2_RES0 ((_BITUL(6))  | (_BITUL(7))  | (_BITUL(8))  | (_BITUL(9))  | \
-                        (_BITUL(10)) | (_BITUL(13)) | (_BITUL(14)) | (_BITUL(15)) | \
-                        (_BITUL(17)) | (_BITUL(20)) | (_BITUL(24)) | (_BITUL(26)) | \
-                        (_BITUL(27)) | (_BITUL(30)) | (_BITUL(31)) | \
+#define SCTLR_EL2_RES1 ((BIT(4))  | (BIT(5))  | (BIT(11)) | (BIT(16)) | \
+                        (BIT(18)) | (BIT(22)) | (BIT(23)) | (BIT(28)) | \
+                        (BIT(29)))
+#define SCTLR_EL2_RES0 ((BIT(6))  | (BIT(7))  | (BIT(8))  | (BIT(9))  | \
+                        (BIT(10)) | (BIT(13)) | (BIT(14)) | (BIT(15)) | \
+                        (BIT(17)) | (BIT(20)) | (BIT(24)) | (BIT(26)) | \
+                        (BIT(27)) | (BIT(30)) | (BIT(31)) | \
                         (0xffffefffUL << 32))
 
 #ifdef CONFIG_CPU_BIG_ENDIAN
 #endif
 
 /* SCTLR_EL1 specific flags. */
-#define SCTLR_EL1_UCI          (_BITUL(26))
-#define SCTLR_EL1_E0E          (_BITUL(24))
-#define SCTLR_EL1_SPAN         (_BITUL(23))
-#define SCTLR_EL1_NTWE         (_BITUL(18))
-#define SCTLR_EL1_NTWI         (_BITUL(16))
-#define SCTLR_EL1_UCT          (_BITUL(15))
-#define SCTLR_EL1_DZE          (_BITUL(14))
-#define SCTLR_EL1_UMA          (_BITUL(9))
-#define SCTLR_EL1_SED          (_BITUL(8))
-#define SCTLR_EL1_ITD          (_BITUL(7))
-#define SCTLR_EL1_CP15BEN      (_BITUL(5))
-#define SCTLR_EL1_SA0          (_BITUL(4))
-
-#define SCTLR_EL1_RES1 ((_BITUL(11)) | (_BITUL(20)) | (_BITUL(22)) | (_BITUL(28)) | \
-                        (_BITUL(29)))
-#define SCTLR_EL1_RES0  ((_BITUL(6))  | (_BITUL(10)) | (_BITUL(13)) | (_BITUL(17)) | \
-                        (_BITUL(27)) | (_BITUL(30)) | (_BITUL(31)) | \
+#define SCTLR_EL1_UCI          (BIT(26))
+#define SCTLR_EL1_E0E          (BIT(24))
+#define SCTLR_EL1_SPAN         (BIT(23))
+#define SCTLR_EL1_NTWE         (BIT(18))
+#define SCTLR_EL1_NTWI         (BIT(16))
+#define SCTLR_EL1_UCT          (BIT(15))
+#define SCTLR_EL1_DZE          (BIT(14))
+#define SCTLR_EL1_UMA          (BIT(9))
+#define SCTLR_EL1_SED          (BIT(8))
+#define SCTLR_EL1_ITD          (BIT(7))
+#define SCTLR_EL1_CP15BEN      (BIT(5))
+#define SCTLR_EL1_SA0          (BIT(4))
+
+#define SCTLR_EL1_RES1 ((BIT(11)) | (BIT(20)) | (BIT(22)) | (BIT(28)) | \
+                        (BIT(29)))
+#define SCTLR_EL1_RES0  ((BIT(6))  | (BIT(10)) | (BIT(13)) | (BIT(17)) | \
+                        (BIT(27)) | (BIT(30)) | (BIT(31)) | \
                         (0xffffefffUL << 32))
 
 #ifdef CONFIG_CPU_BIG_ENDIAN
 #define ZCR_ELx_LEN_SIZE       9
 #define ZCR_ELx_LEN_MASK       0x1ff
 
-#define CPACR_EL1_ZEN_EL1EN    (_BITUL(16)) /* enable EL1 access */
-#define CPACR_EL1_ZEN_EL0EN    (_BITUL(17)) /* enable EL0 access, if EL1EN set */
+#define CPACR_EL1_ZEN_EL1EN    (BIT(16)) /* enable EL1 access */
+#define CPACR_EL1_ZEN_EL0EN    (BIT(17)) /* enable EL0 access, if EL1EN set */
 #define CPACR_EL1_ZEN          (CPACR_EL1_ZEN_EL1EN | CPACR_EL1_ZEN_EL0EN)
 
 
 /* Safe value for MPIDR_EL1: Bit31:RES1, Bit30:U:0, Bit24:MT:0 */
-#define SYS_MPIDR_SAFE_VAL     (_BITUL(31))
+#define SYS_MPIDR_SAFE_VAL     (BIT(31))
 
 #ifdef __ASSEMBLY__
 
index 49825e9..42bd8c0 100644 (file)
@@ -10,7 +10,7 @@
  * aarch32_setup_additional_pages() and are provided for compatibility
  * reasons with 32 bit (aarch32) applications that need them.
  *
- * See Documentation/arm/kernel_user_helpers.txt for formal definitions.
+ * See Documentation/arm/kernel_user_helpers.rst for formal definitions.
  */
 
 #include <asm/unistd.h>
index 288c14d..60a4c62 100644 (file)
@@ -96,8 +96,8 @@ VDSO_LDFLAGS := $(VDSO_CPPFLAGS)
 VDSO_LDFLAGS += -Wl,-Bsymbolic -Wl,--no-undefined -Wl,-soname=linux-vdso.so.1
 VDSO_LDFLAGS += -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096
 VDSO_LDFLAGS += -nostdlib -shared -mfloat-abi=soft
-VDSO_LDFLAGS += $(call cc32-ldoption,-Wl$(comma)--hash-style=sysv)
-VDSO_LDFLAGS += $(call cc32-ldoption,-Wl$(comma)--build-id)
+VDSO_LDFLAGS += -Wl,--hash-style=sysv
+VDSO_LDFLAGS += -Wl,--build-id
 VDSO_LDFLAGS += $(call cc32-ldoption,-fuse-ld=bfd)
 
 
index c8c61b1..9568c11 100644 (file)
@@ -59,28 +59,6 @@ static inline const struct fault_info *esr_to_debug_fault_info(unsigned int esr)
        return debug_fault_info + DBG_ESR_EVT(esr);
 }
 
-#ifdef CONFIG_KPROBES
-static inline int notify_page_fault(struct pt_regs *regs, unsigned int esr)
-{
-       int ret = 0;
-
-       /* kprobe_running() needs smp_processor_id() */
-       if (!user_mode(regs)) {
-               preempt_disable();
-               if (kprobe_running() && kprobe_fault_handler(regs, esr))
-                       ret = 1;
-               preempt_enable();
-       }
-
-       return ret;
-}
-#else
-static inline int notify_page_fault(struct pt_regs *regs, unsigned int esr)
-{
-       return 0;
-}
-#endif
-
 static void data_abort_decode(unsigned int esr)
 {
        pr_alert("Data abort info:\n");
@@ -434,7 +412,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
        unsigned long vm_flags = VM_READ | VM_WRITE;
        unsigned int mm_flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
-       if (notify_page_fault(regs, esr))
+       if (kprobe_page_fault(regs, esr))
                return 0;
 
        /*
index 1b49c08..750a69d 100644 (file)
@@ -942,6 +942,11 @@ void *__init fixmap_remap_fdt(phys_addr_t dt_phys)
        return dt_virt;
 }
 
+int __init arch_ioremap_p4d_supported(void)
+{
+       return 0;
+}
+
 int __init arch_ioremap_pud_supported(void)
 {
        /*
@@ -1069,4 +1074,21 @@ int arch_add_memory(int nid, u64 start, u64 size,
        return __add_pages(nid, start >> PAGE_SHIFT, size >> PAGE_SHIFT,
                           restrictions);
 }
+void arch_remove_memory(int nid, u64 start, u64 size,
+                       struct vmem_altmap *altmap)
+{
+       unsigned long start_pfn = start >> PAGE_SHIFT;
+       unsigned long nr_pages = size >> PAGE_SHIFT;
+       struct zone *zone;
+
+       /*
+        * FIXME: Cleanup page tables (also in arch_add_memory() in case
+        * adding fails). Until then, this function should only be used
+        * during memory hotplug (adding memory), not for memory
+        * unplug. ARCH_ENABLE_MEMORY_HOTREMOVE must not be
+        * unlocked yet.
+        */
+       zone = page_zone(pfn_to_page(start_pfn));
+       __remove_pages(zone, start_pfn, nr_pages, altmap);
+}
 #endif
index cf798a1..3973847 100644 (file)
@@ -10,6 +10,9 @@ config CSKY
        select COMMON_CLK
        select CLKSRC_MMIO
        select CLKSRC_OF
+       select CSKY_MPINTC if CPU_CK860
+       select CSKY_MP_TIMER if CPU_CK860
+       select CSKY_APB_INTC
        select DMA_DIRECT_REMAP
        select IRQ_DOMAIN
        select HANDLE_DOMAIN_IRQ
@@ -30,6 +33,7 @@ config CSKY
        select GENERIC_IRQ_MULTI_HANDLER
        select GENERIC_SCHED_CLOCK
        select GENERIC_SMP_IDLE_THREAD
+       select GX6605S_TIMER if CPU_CK610
        select HAVE_ARCH_TRACEHOOK
        select HAVE_ARCH_AUDITSYSCALL
        select HAVE_DYNAMIC_FTRACE
index e52b42b..601ce3b 100644 (file)
@@ -5,5 +5,4 @@ obj-y                                   += bswapsi.o
 obj-y                                  += cacheflush.o
 obj-y                                  += mmap.o
 obj-y                                  += memcpy.o
-obj-y                                  += memset.o
 obj-y                                  += strksyms.o
index 81f3771..ba8eb58 100644 (file)
@@ -78,6 +78,12 @@ static inline void tlb_invalid_all(void)
        cpwcr("cpcr8", 0x04000000);
 }
 
+
+static inline void local_tlb_invalid_all(void)
+{
+       tlb_invalid_all();
+}
+
 static inline void tlb_invalid_indexed(void)
 {
        cpwcr("cpcr8", 0x02000000);
index 5abe80b..0cd4338 100644 (file)
@@ -7,7 +7,4 @@
 #define __HAVE_ARCH_MEMCPY
 extern void *memcpy(void *, const void *, __kernel_size_t);
 
-#define __HAVE_ARCH_MEMSET
-extern void *memset(void *, int, __kernel_size_t);
-
 #endif /* __ABI_CSKY_STRING_H */
diff --git a/arch/csky/abiv1/memset.c b/arch/csky/abiv1/memset.c
deleted file mode 100644 (file)
index b4aa75b..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
-
-#include <linux/types.h>
-
-void *memset(void *dest, int c, size_t l)
-{
-       char *d = dest;
-       int ch = c & 0xff;
-       int tmp = (ch | ch << 8 | ch << 16 | ch << 24);
-
-       while (((uintptr_t)d & 0x3) && l--)
-               *d++ = ch;
-
-       while (l >= 16) {
-               *(((u32 *)d))   = tmp;
-               *(((u32 *)d)+1) = tmp;
-               *(((u32 *)d)+2) = tmp;
-               *(((u32 *)d)+3) = tmp;
-               l -= 16;
-               d += 16;
-       }
-
-       while (l > 3) {
-               *(((u32 *)d)) = tmp;
-               l -= 4;
-               d += 4;
-       }
-
-       while (l) {
-               *d = ch;
-               l--;
-               d++;
-       }
-
-       return dest;
-}
index 436995c..c7ccbb2 100644 (file)
@@ -4,4 +4,3 @@
 #include <linux/module.h>
 
 EXPORT_SYMBOL(memcpy);
-EXPORT_SYMBOL(memset);
index e4480e6..73ded7c 100644 (file)
@@ -85,6 +85,16 @@ static inline void tlb_invalid_all(void)
 #endif
 }
 
+static inline void local_tlb_invalid_all(void)
+{
+#ifdef CONFIG_CPU_HAS_TLBI
+       asm volatile("tlbi.all\n":::"memory");
+       sync_is();
+#else
+       tlb_invalid_all();
+#endif
+}
+
 static inline void tlb_invalid_indexed(void)
 {
        mtcr("cr<8, 15>", 0x02000000);
diff --git a/arch/csky/include/asm/asid.h b/arch/csky/include/asm/asid.h
new file mode 100644 (file)
index 0000000..ac08b0f
--- /dev/null
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_ASM_ASID_H
+#define __ASM_ASM_ASID_H
+
+#include <linux/atomic.h>
+#include <linux/compiler.h>
+#include <linux/cpumask.h>
+#include <linux/percpu.h>
+#include <linux/spinlock.h>
+
+struct asid_info
+{
+       atomic64_t      generation;
+       unsigned long   *map;
+       atomic64_t __percpu     *active;
+       u64 __percpu            *reserved;
+       u32                     bits;
+       /* Lock protecting the structure */
+       raw_spinlock_t          lock;
+       /* Which CPU requires context flush on next call */
+       cpumask_t               flush_pending;
+       /* Number of ASID allocated by context (shift value) */
+       unsigned int            ctxt_shift;
+       /* Callback to locally flush the context. */
+       void                    (*flush_cpu_ctxt_cb)(void);
+};
+
+#define NUM_ASIDS(info)                        (1UL << ((info)->bits))
+#define NUM_CTXT_ASIDS(info)           (NUM_ASIDS(info) >> (info)->ctxt_shift)
+
+#define active_asid(info, cpu) *per_cpu_ptr((info)->active, cpu)
+
+void asid_new_context(struct asid_info *info, atomic64_t *pasid,
+                     unsigned int cpu, struct mm_struct *mm);
+
+/*
+ * Check the ASID is still valid for the context. If not generate a new ASID.
+ *
+ * @pasid: Pointer to the current ASID batch
+ * @cpu: current CPU ID. Must have been acquired throught get_cpu()
+ */
+static inline void asid_check_context(struct asid_info *info,
+                                     atomic64_t *pasid, unsigned int cpu,
+                                     struct mm_struct *mm)
+{
+       u64 asid, old_active_asid;
+
+       asid = atomic64_read(pasid);
+
+       /*
+        * The memory ordering here is subtle.
+        * If our active_asid is non-zero and the ASID matches the current
+        * generation, then we update the active_asid entry with a relaxed
+        * cmpxchg. Racing with a concurrent rollover means that either:
+        *
+        * - We get a zero back from the cmpxchg and end up waiting on the
+        *   lock. Taking the lock synchronises with the rollover and so
+        *   we are forced to see the updated generation.
+        *
+        * - We get a valid ASID back from the cmpxchg, which means the
+        *   relaxed xchg in flush_context will treat us as reserved
+        *   because atomic RmWs are totally ordered for a given location.
+        */
+       old_active_asid = atomic64_read(&active_asid(info, cpu));
+       if (old_active_asid &&
+           !((asid ^ atomic64_read(&info->generation)) >> info->bits) &&
+           atomic64_cmpxchg_relaxed(&active_asid(info, cpu),
+                                    old_active_asid, asid))
+               return;
+
+       asid_new_context(info, pasid, cpu, mm);
+}
+
+int asid_allocator_init(struct asid_info *info,
+                       u32 bits, unsigned int asid_per_ctxt,
+                       void (*flush_cpu_ctxt_cb)(void));
+
+#endif
index cb34467..b382a14 100644 (file)
@@ -5,7 +5,7 @@
 #define __ASM_CSKY_MMU_H
 
 typedef struct {
-       unsigned long asid[NR_CPUS];
+       atomic64_t      asid;
        void *vdso;
 } mm_context_t;
 
index 734db3a..0285b0a 100644 (file)
 
 #define TLBMISS_HANDLER_SETUP_PGD(pgd) \
        setup_pgd(__pa(pgd), false)
+
 #define TLBMISS_HANDLER_SETUP_PGD_KERNEL(pgd) \
        setup_pgd(__pa(pgd), true)
 
-#define cpu_context(cpu, mm)   ((mm)->context.asid[cpu])
-#define cpu_asid(cpu, mm)      (cpu_context((cpu), (mm)) & ASID_MASK)
-#define asid_cache(cpu)                (cpu_data[cpu].asid_cache)
+#define ASID_MASK              ((1 << CONFIG_CPU_ASID_BITS) - 1)
+#define cpu_asid(mm)           (atomic64_read(&mm->context.asid) & ASID_MASK)
 
-#define ASID_FIRST_VERSION     (1 << CONFIG_CPU_ASID_BITS)
-#define ASID_INC               0x1
-#define ASID_MASK              (ASID_FIRST_VERSION - 1)
-#define ASID_VERSION_MASK      ~ASID_MASK
+#define init_new_context(tsk,mm)       ({ atomic64_set(&(mm)->context.asid, 0); 0; })
+#define activate_mm(prev,next)         switch_mm(prev, next, current)
 
 #define destroy_context(mm)            do {} while (0)
 #define enter_lazy_tlb(mm, tsk)                do {} while (0)
 #define deactivate_mm(tsk, mm)         do {} while (0)
 
-/*
- *  All unused by hardware upper bits will be considered
- *  as a software asid extension.
- */
-static inline void
-get_new_mmu_context(struct mm_struct *mm, unsigned long cpu)
-{
-       unsigned long asid = asid_cache(cpu);
-
-       asid += ASID_INC;
-       if (!(asid & ASID_MASK)) {
-               flush_tlb_all();        /* start new asid cycle */
-               if (!asid)              /* fix version if needed */
-                       asid = ASID_FIRST_VERSION;
-       }
-       cpu_context(cpu, mm) = asid_cache(cpu) = asid;
-}
-
-/*
- * Initialize the context related info for a new mm_struct
- * instance.
- */
-static inline int
-init_new_context(struct task_struct *tsk, struct mm_struct *mm)
-{
-       int i;
-
-       for_each_online_cpu(i)
-               cpu_context(i, mm) = 0;
-       return 0;
-}
-
-static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
-                       struct task_struct *tsk)
-{
-       unsigned int cpu = smp_processor_id();
-       unsigned long flags;
-
-       local_irq_save(flags);
-       /* Check if our ASID is of an older version and thus invalid */
-       if ((cpu_context(cpu, next) ^ asid_cache(cpu)) & ASID_VERSION_MASK)
-               get_new_mmu_context(next, cpu);
-       write_mmu_entryhi(cpu_asid(cpu, next));
-       TLBMISS_HANDLER_SETUP_PGD(next->pgd);
-
-       /*
-        * Mark current->active_mm as not "active" anymore.
-        * We don't want to mislead possible IPI tlb flush routines.
-        */
-       cpumask_clear_cpu(cpu, mm_cpumask(prev));
-       cpumask_set_cpu(cpu, mm_cpumask(next));
+void check_and_switch_context(struct mm_struct *mm, unsigned int cpu);
 
-       local_irq_restore(flags);
-}
-
-/*
- * After we have set current->mm to a new value, this activates
- * the context for the new mm so we see the new mappings.
- */
 static inline void
-activate_mm(struct mm_struct *prev, struct mm_struct *next)
+switch_mm(struct mm_struct *prev, struct mm_struct *next,
+         struct task_struct *tsk)
 {
-       unsigned long flags;
-       int cpu = smp_processor_id();
-
-       local_irq_save(flags);
+       unsigned int cpu = smp_processor_id();
 
-       /* Unconditionally get a new ASID.  */
-       get_new_mmu_context(next, cpu);
+       if (prev != next)
+               check_and_switch_context(next, cpu);
 
-       write_mmu_entryhi(cpu_asid(cpu, next));
        TLBMISS_HANDLER_SETUP_PGD(next->pgd);
-
-       /* mark mmu ownership change */
-       cpumask_clear_cpu(cpu, mm_cpumask(prev));
-       cpumask_set_cpu(cpu, mm_cpumask(next));
-
-       local_irq_restore(flags);
-}
-
-/*
- * If mm is currently active_mm, we can't really drop it. Instead,
- * we will get a new one for it.
- */
-static inline void
-drop_mmu_context(struct mm_struct *mm, unsigned int cpu)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       if (cpumask_test_cpu(cpu, mm_cpumask(mm)))  {
-               get_new_mmu_context(mm, cpu);
-               write_mmu_entryhi(cpu_asid(cpu, mm));
-       } else {
-               /* will get a new context next time */
-               cpu_context(cpu, mm) = 0;
-       }
-
-       local_irq_restore(flags);
+       write_mmu_entryhi(next->context.asid.counter);
 }
-
 #endif /* __ASM_CSKY_MMU_CONTEXT_H */
index dcea277..c429a6f 100644 (file)
@@ -290,8 +290,6 @@ static inline pte_t *pte_offset(pmd_t *dir, unsigned long address)
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 extern void paging_init(void);
 
-extern void show_jtlb_table(void);
-
 void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
                      pte_t *pte);
 
index 376c972..4c1a193 100644 (file)
@@ -9,17 +9,44 @@
 #include <linux/platform_device.h>
 
 #define CSKY_PMU_MAX_EVENTS 32
+#define DEFAULT_COUNT_WIDTH 48
+
+#define HPCR           "<0, 0x0>"      /* PMU Control reg */
+#define HPSPR          "<0, 0x1>"      /* Start PC reg */
+#define HPEPR          "<0, 0x2>"      /* End PC reg */
+#define HPSIR          "<0, 0x3>"      /* Soft Counter reg */
+#define HPCNTENR       "<0, 0x4>"      /* Count Enable reg */
+#define HPINTENR       "<0, 0x5>"      /* Interrupt Enable reg */
+#define HPOFSR         "<0, 0x6>"      /* Interrupt Status reg */
+
+/* The events for a given PMU register set. */
+struct pmu_hw_events {
+       /*
+        * The events that are active on the PMU for the given index.
+        */
+       struct perf_event *events[CSKY_PMU_MAX_EVENTS];
 
-#define HPCR           "<0, 0x0>"      /* PMU Control reg */
-#define HPCNTENR       "<0, 0x4>"      /* Count Enable reg */
+       /*
+        * A 1 bit for an index indicates that the counter is being used for
+        * an event. A 0 means that the counter can be used.
+        */
+       unsigned long used_mask[BITS_TO_LONGS(CSKY_PMU_MAX_EVENTS)];
+};
 
 static uint64_t (*hw_raw_read_mapping[CSKY_PMU_MAX_EVENTS])(void);
 static void (*hw_raw_write_mapping[CSKY_PMU_MAX_EVENTS])(uint64_t val);
 
-struct csky_pmu_t {
-       struct pmu      pmu;
-       uint32_t        hpcr;
+static struct csky_pmu_t {
+       struct pmu                      pmu;
+       struct pmu_hw_events __percpu   *hw_events;
+       struct platform_device          *plat_device;
+       uint32_t                        count_width;
+       uint32_t                        hpcr;
+       u64                             max_period;
 } csky_pmu;
+static int csky_pmu_irq;
+
+#define to_csky_pmu(p)  (container_of(p, struct csky_pmu, pmu))
 
 #define cprgr(reg)                             \
 ({                                             \
@@ -701,6 +728,20 @@ static const int csky_pmu_hw_map[PERF_COUNT_HW_MAX] = {
 #define CACHE_OP_UNSUPPORTED   0xffff
 static const int csky_pmu_cache_map[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
        [C(L1D)] = {
+#ifdef CONFIG_CPU_CK810
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = 0x5,
+                       [C(RESULT_MISS)]        = 0x6,
+               },
+#else
                [C(OP_READ)] = {
                        [C(RESULT_ACCESS)]      = 0x14,
                        [C(RESULT_MISS)]        = 0x15,
@@ -710,9 +751,10 @@ static const int csky_pmu_cache_map[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
                        [C(RESULT_MISS)]        = 0x17,
                },
                [C(OP_PREFETCH)] = {
-                       [C(RESULT_ACCESS)]      = 0x5,
-                       [C(RESULT_MISS)]        = 0x6,
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
                },
+#endif
        },
        [C(L1I)] = {
                [C(OP_READ)] = {
@@ -729,6 +771,20 @@ static const int csky_pmu_cache_map[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
                },
        },
        [C(LL)] = {
+#ifdef CONFIG_CPU_CK810
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)]      = 0x7,
+                       [C(RESULT_MISS)]        = 0x8,
+               },
+#else
                [C(OP_READ)] = {
                        [C(RESULT_ACCESS)]      = 0x18,
                        [C(RESULT_MISS)]        = 0x19,
@@ -738,29 +794,48 @@ static const int csky_pmu_cache_map[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
                        [C(RESULT_MISS)]        = 0x1b,
                },
                [C(OP_PREFETCH)] = {
-                       [C(RESULT_ACCESS)]      = 0x7,
-                       [C(RESULT_MISS)]        = 0x8,
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
                },
+#endif
        },
        [C(DTLB)] = {
+#ifdef CONFIG_CPU_CK810
                [C(OP_READ)] = {
-                       [C(RESULT_ACCESS)]      = 0x5,
-                       [C(RESULT_MISS)]        = 0xb,
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
                },
                [C(OP_WRITE)] = {
                        [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
                        [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
                },
+#else
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = 0x14,
+                       [C(RESULT_MISS)]        = 0xb,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)]      = 0x16,
+                       [C(RESULT_MISS)]        = 0xb,
+               },
+#endif
                [C(OP_PREFETCH)] = {
                        [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
                        [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
                },
        },
        [C(ITLB)] = {
+#ifdef CONFIG_CPU_CK810
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
+                       [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
+               },
+#else
                [C(OP_READ)] = {
                        [C(RESULT_ACCESS)]      = 0x3,
                        [C(RESULT_MISS)]        = 0xa,
                },
+#endif
                [C(OP_WRITE)] = {
                        [C(RESULT_ACCESS)]      = CACHE_OP_UNSUPPORTED,
                        [C(RESULT_MISS)]        = CACHE_OP_UNSUPPORTED,
@@ -800,11 +875,57 @@ static const int csky_pmu_cache_map[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
        },
 };
 
+int  csky_pmu_event_set_period(struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       s64 left = local64_read(&hwc->period_left);
+       s64 period = hwc->sample_period;
+       int ret = 0;
+
+       if (unlikely(left <= -period)) {
+               left = period;
+               local64_set(&hwc->period_left, left);
+               hwc->last_period = period;
+               ret = 1;
+       }
+
+       if (unlikely(left <= 0)) {
+               left += period;
+               local64_set(&hwc->period_left, left);
+               hwc->last_period = period;
+               ret = 1;
+       }
+
+       if (left > (s64)csky_pmu.max_period)
+               left = csky_pmu.max_period;
+
+       /*
+        * The hw event starts counting from this event offset,
+        * mark it to be able to extract future "deltas":
+        */
+       local64_set(&hwc->prev_count, (u64)(-left));
+
+       if (hw_raw_write_mapping[hwc->idx] != NULL)
+               hw_raw_write_mapping[hwc->idx]((u64)(-left) &
+                                               csky_pmu.max_period);
+
+       cpwcr(HPOFSR, ~BIT(hwc->idx) & cprcr(HPOFSR));
+
+       perf_event_update_userpage(event);
+
+       return ret;
+}
+
 static void csky_perf_event_update(struct perf_event *event,
                                   struct hw_perf_event *hwc)
 {
        uint64_t prev_raw_count = local64_read(&hwc->prev_count);
-       uint64_t new_raw_count = hw_raw_read_mapping[hwc->idx]();
+       /*
+        * Sign extend count value to 64bit, otherwise delta calculation
+        * would be incorrect when overflow occurs.
+        */
+       uint64_t new_raw_count = sign_extend64(
+               hw_raw_read_mapping[hwc->idx](), csky_pmu.count_width - 1);
        int64_t delta = new_raw_count - prev_raw_count;
 
        /*
@@ -816,6 +937,11 @@ static void csky_perf_event_update(struct perf_event *event,
        local64_sub(delta, &hwc->period_left);
 }
 
+static void csky_pmu_reset(void *info)
+{
+       cpwcr(HPCR, BIT(31) | BIT(30) | BIT(1));
+}
+
 static void csky_pmu_read(struct perf_event *event)
 {
        csky_perf_event_update(event, &event->hw);
@@ -844,15 +970,6 @@ static int csky_pmu_event_init(struct perf_event *event)
        struct hw_perf_event *hwc = &event->hw;
        int ret;
 
-       if (event->attr.exclude_user)
-               csky_pmu.hpcr = BIT(2);
-       else if (event->attr.exclude_kernel)
-               csky_pmu.hpcr = BIT(3);
-       else
-               csky_pmu.hpcr = BIT(2) | BIT(3);
-
-       csky_pmu.hpcr |= BIT(1) | BIT(0);
-
        switch (event->attr.type) {
        case PERF_TYPE_HARDWARE:
                if (event->attr.config >= PERF_COUNT_HW_MAX)
@@ -861,21 +978,32 @@ static int csky_pmu_event_init(struct perf_event *event)
                if (ret == HW_OP_UNSUPPORTED)
                        return -ENOENT;
                hwc->idx = ret;
-               return 0;
+               break;
        case PERF_TYPE_HW_CACHE:
                ret = csky_pmu_cache_event(event->attr.config);
                if (ret == CACHE_OP_UNSUPPORTED)
                        return -ENOENT;
                hwc->idx = ret;
-               return 0;
+               break;
        case PERF_TYPE_RAW:
                if (hw_raw_read_mapping[event->attr.config] == NULL)
                        return -ENOENT;
                hwc->idx = event->attr.config;
-               return 0;
+               break;
        default:
                return -ENOENT;
        }
+
+       if (event->attr.exclude_user)
+               csky_pmu.hpcr = BIT(2);
+       else if (event->attr.exclude_kernel)
+               csky_pmu.hpcr = BIT(3);
+       else
+               csky_pmu.hpcr = BIT(2) | BIT(3);
+
+       csky_pmu.hpcr |= BIT(1) | BIT(0);
+
+       return 0;
 }
 
 /* starts all counters */
@@ -892,6 +1020,7 @@ static void csky_pmu_disable(struct pmu *pmu)
 
 static void csky_pmu_start(struct perf_event *event, int flags)
 {
+       unsigned long flg;
        struct hw_perf_event *hwc = &event->hw;
        int idx = hwc->idx;
 
@@ -903,16 +1032,34 @@ static void csky_pmu_start(struct perf_event *event, int flags)
 
        hwc->state = 0;
 
+       csky_pmu_event_set_period(event);
+
+       local_irq_save(flg);
+
+       cpwcr(HPINTENR, BIT(idx) | cprcr(HPINTENR));
        cpwcr(HPCNTENR, BIT(idx) | cprcr(HPCNTENR));
+
+       local_irq_restore(flg);
 }
 
-static void csky_pmu_stop(struct perf_event *event, int flags)
+static void csky_pmu_stop_event(struct perf_event *event)
 {
+       unsigned long flg;
        struct hw_perf_event *hwc = &event->hw;
        int idx = hwc->idx;
 
+       local_irq_save(flg);
+
+       cpwcr(HPINTENR, ~BIT(idx) & cprcr(HPINTENR));
+       cpwcr(HPCNTENR, ~BIT(idx) & cprcr(HPCNTENR));
+
+       local_irq_restore(flg);
+}
+
+static void csky_pmu_stop(struct perf_event *event, int flags)
+{
        if (!(event->hw.state & PERF_HES_STOPPED)) {
-               cpwcr(HPCNTENR, ~BIT(idx) & cprcr(HPCNTENR));
+               csky_pmu_stop_event(event);
                event->hw.state |= PERF_HES_STOPPED;
        }
 
@@ -925,22 +1072,26 @@ static void csky_pmu_stop(struct perf_event *event, int flags)
 
 static void csky_pmu_del(struct perf_event *event, int flags)
 {
+       struct pmu_hw_events *hw_events = this_cpu_ptr(csky_pmu.hw_events);
+       struct hw_perf_event *hwc = &event->hw;
+
        csky_pmu_stop(event, PERF_EF_UPDATE);
 
+       hw_events->events[hwc->idx] = NULL;
+
        perf_event_update_userpage(event);
 }
 
 /* allocate hardware counter and optionally start counting */
 static int csky_pmu_add(struct perf_event *event, int flags)
 {
+       struct pmu_hw_events *hw_events = this_cpu_ptr(csky_pmu.hw_events);
        struct hw_perf_event *hwc = &event->hw;
 
-       local64_set(&hwc->prev_count, 0);
-
-       if (hw_raw_write_mapping[hwc->idx] != NULL)
-               hw_raw_write_mapping[hwc->idx](0);
+       hw_events->events[hwc->idx] = event;
 
        hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+
        if (flags & PERF_EF_START)
                csky_pmu_start(event, PERF_EF_RELOAD);
 
@@ -949,8 +1100,110 @@ static int csky_pmu_add(struct perf_event *event, int flags)
        return 0;
 }
 
-int __init init_hw_perf_events(void)
+static irqreturn_t csky_pmu_handle_irq(int irq_num, void *dev)
+{
+       struct perf_sample_data data;
+       struct pmu_hw_events *cpuc = this_cpu_ptr(csky_pmu.hw_events);
+       struct pt_regs *regs;
+       int idx;
+
+       /*
+        * Did an overflow occur?
+        */
+       if (!cprcr(HPOFSR))
+               return IRQ_NONE;
+
+       /*
+        * Handle the counter(s) overflow(s)
+        */
+       regs = get_irq_regs();
+
+       csky_pmu_disable(&csky_pmu.pmu);
+
+       for (idx = 0; idx < CSKY_PMU_MAX_EVENTS; ++idx) {
+               struct perf_event *event = cpuc->events[idx];
+               struct hw_perf_event *hwc;
+
+               /* Ignore if we don't have an event. */
+               if (!event)
+                       continue;
+               /*
+                * We have a single interrupt for all counters. Check that
+                * each counter has overflowed before we process it.
+                */
+               if (!(cprcr(HPOFSR) & BIT(idx)))
+                       continue;
+
+               hwc = &event->hw;
+               csky_perf_event_update(event, &event->hw);
+               perf_sample_data_init(&data, 0, hwc->last_period);
+               csky_pmu_event_set_period(event);
+
+               if (perf_event_overflow(event, &data, regs))
+                       csky_pmu_stop_event(event);
+       }
+
+       csky_pmu_enable(&csky_pmu.pmu);
+
+       /*
+        * Handle the pending perf events.
+        *
+        * Note: this call *must* be run with interrupts disabled. For
+        * platforms that can have the PMU interrupts raised as an NMI, this
+        * will not work.
+        */
+       irq_work_run();
+
+       return IRQ_HANDLED;
+}
+
+static int csky_pmu_request_irq(irq_handler_t handler)
 {
+       int err, irqs;
+       struct platform_device *pmu_device = csky_pmu.plat_device;
+
+       if (!pmu_device)
+               return -ENODEV;
+
+       irqs = min(pmu_device->num_resources, num_possible_cpus());
+       if (irqs < 1) {
+               pr_err("no irqs for PMUs defined\n");
+               return -ENODEV;
+       }
+
+       csky_pmu_irq = platform_get_irq(pmu_device, 0);
+       if (csky_pmu_irq < 0)
+               return -ENODEV;
+       err = request_percpu_irq(csky_pmu_irq, handler, "csky-pmu",
+                                this_cpu_ptr(csky_pmu.hw_events));
+       if (err) {
+               pr_err("unable to request IRQ%d for CSKY PMU counters\n",
+                      csky_pmu_irq);
+               return err;
+       }
+
+       return 0;
+}
+
+static void csky_pmu_free_irq(void)
+{
+       int irq;
+       struct platform_device *pmu_device = csky_pmu.plat_device;
+
+       irq = platform_get_irq(pmu_device, 0);
+       if (irq >= 0)
+               free_percpu_irq(irq, this_cpu_ptr(csky_pmu.hw_events));
+}
+
+int init_hw_perf_events(void)
+{
+       csky_pmu.hw_events = alloc_percpu_gfp(struct pmu_hw_events,
+                                             GFP_KERNEL);
+       if (!csky_pmu.hw_events) {
+               pr_info("failed to allocate per-cpu PMU data.\n");
+               return -ENOMEM;
+       }
+
        csky_pmu.pmu = (struct pmu) {
                .pmu_enable     = csky_pmu_enable,
                .pmu_disable    = csky_pmu_disable,
@@ -1022,10 +1275,97 @@ int __init init_hw_perf_events(void)
        hw_raw_write_mapping[0x1a] = csky_pmu_write_l2wac;
        hw_raw_write_mapping[0x1b] = csky_pmu_write_l2wmc;
 
-       csky_pmu.pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
+       return 0;
+}
 
-       cpwcr(HPCR, BIT(31) | BIT(30) | BIT(1));
+static int csky_pmu_starting_cpu(unsigned int cpu)
+{
+       enable_percpu_irq(csky_pmu_irq, 0);
+       return 0;
+}
 
-       return perf_pmu_register(&csky_pmu.pmu, "cpu", PERF_TYPE_RAW);
+static int csky_pmu_dying_cpu(unsigned int cpu)
+{
+       disable_percpu_irq(csky_pmu_irq);
+       return 0;
 }
-arch_initcall(init_hw_perf_events);
+
+int csky_pmu_device_probe(struct platform_device *pdev,
+                         const struct of_device_id *of_table)
+{
+       struct device_node *node = pdev->dev.of_node;
+       int ret;
+
+       ret = init_hw_perf_events();
+       if (ret) {
+               pr_notice("[perf] failed to probe PMU!\n");
+               return ret;
+       }
+
+       if (of_property_read_u32(node, "count-width",
+                                &csky_pmu.count_width)) {
+               csky_pmu.count_width = DEFAULT_COUNT_WIDTH;
+       }
+       csky_pmu.max_period = BIT(csky_pmu.count_width) - 1;
+
+       csky_pmu.plat_device = pdev;
+
+       /* Ensure the PMU has sane values out of reset. */
+       on_each_cpu(csky_pmu_reset, &csky_pmu, 1);
+
+       ret = csky_pmu_request_irq(csky_pmu_handle_irq);
+       if (ret) {
+               csky_pmu.pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
+               pr_notice("[perf] PMU request irq fail!\n");
+       }
+
+       ret = cpuhp_setup_state(CPUHP_AP_PERF_ONLINE, "AP_PERF_ONLINE",
+                               csky_pmu_starting_cpu,
+                               csky_pmu_dying_cpu);
+       if (ret) {
+               csky_pmu_free_irq();
+               free_percpu(csky_pmu.hw_events);
+               return ret;
+       }
+
+       ret = perf_pmu_register(&csky_pmu.pmu, "cpu", PERF_TYPE_RAW);
+       if (ret) {
+               csky_pmu_free_irq();
+               free_percpu(csky_pmu.hw_events);
+       }
+
+       return ret;
+}
+
+const static struct of_device_id csky_pmu_of_device_ids[] = {
+       {.compatible = "csky,csky-pmu"},
+       {},
+};
+
+static int csky_pmu_dev_probe(struct platform_device *pdev)
+{
+       return csky_pmu_device_probe(pdev, csky_pmu_of_device_ids);
+}
+
+static struct platform_driver csky_pmu_driver = {
+       .driver = {
+                  .name = "csky-pmu",
+                  .of_match_table = csky_pmu_of_device_ids,
+                  },
+       .probe = csky_pmu_dev_probe,
+};
+
+static int __init csky_pmu_probe(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&csky_pmu_driver);
+       if (ret)
+               pr_notice("[perf] PMU initialization failed\n");
+       else
+               pr_notice("[perf] PMU initialization done\n");
+
+       return ret;
+}
+
+device_initcall(csky_pmu_probe);
index b07a534..b753d38 100644 (file)
@@ -212,8 +212,6 @@ void csky_start_secondary(void)
        TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir);
        TLBMISS_HANDLER_SETUP_PGD_KERNEL(swapper_pg_dir);
 
-       asid_cache(smp_processor_id()) = ASID_FIRST_VERSION;
-
 #ifdef CONFIG_CPU_HAS_FPU
        init_fpu();
 #endif
index 2792e96..b057480 100644 (file)
@@ -120,6 +120,7 @@ asmlinkage void trap_c(struct pt_regs *regs)
 
        switch (vector) {
        case VEC_ZERODIV:
+               die_if_kernel("Kernel mode ZERO DIV", regs, vector);
                sig = SIGFPE;
                break;
        /* ptrace */
@@ -128,6 +129,7 @@ asmlinkage void trap_c(struct pt_regs *regs)
                sig = SIGTRAP;
                break;
        case VEC_ILLEGAL:
+               die_if_kernel("Kernel mode ILLEGAL", regs, vector);
 #ifndef CONFIG_CPU_NO_USER_BKPT
                if (*(uint16_t *)instruction_pointer(regs) != USR_BKPT)
 #endif
@@ -139,6 +141,7 @@ asmlinkage void trap_c(struct pt_regs *regs)
        case VEC_TRAP1:
        /* jtagserver breakpoint */
        case VEC_BREAKPOINT:
+               die_if_kernel("Kernel mode BKPT", regs, vector);
                info.si_code = TRAP_BRKPT;
                sig = SIGTRAP;
                break;
@@ -150,8 +153,10 @@ asmlinkage void trap_c(struct pt_regs *regs)
 #endif
 #ifdef CONFIG_CPU_HAS_FPU
        case VEC_FPE:
+               die_if_kernel("Kernel mode FPE", regs, vector);
                return fpu_fpe(regs);
        case VEC_PRIV:
+               die_if_kernel("Kernel mode PRIV", regs, vector);
                if (fpu_libc_helper(regs))
                        return;
 #endif
index 4eebebd..c94ef64 100644 (file)
@@ -12,3 +12,5 @@ obj-y +=                      init.o
 obj-y +=                       ioremap.o
 obj-y +=                       syscache.o
 obj-y +=                       tlb.o
+obj-y +=                       asid.o
+obj-y +=                       context.o
diff --git a/arch/csky/mm/asid.c b/arch/csky/mm/asid.c
new file mode 100644 (file)
index 0000000..b2e9147
--- /dev/null
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Generic ASID allocator.
+ *
+ * Based on arch/arm/mm/context.c
+ *
+ * Copyright (C) 2002-2003 Deep Blue Solutions Ltd, all rights reserved.
+ * Copyright (C) 2012 ARM Ltd.
+ */
+
+#include <linux/slab.h>
+#include <linux/mm_types.h>
+
+#include <asm/asid.h>
+
+#define reserved_asid(info, cpu) *per_cpu_ptr((info)->reserved, cpu)
+
+#define ASID_MASK(info)                        (~GENMASK((info)->bits - 1, 0))
+#define ASID_FIRST_VERSION(info)       (1UL << ((info)->bits))
+
+#define asid2idx(info, asid)           (((asid) & ~ASID_MASK(info)) >> (info)->ctxt_shift)
+#define idx2asid(info, idx)            (((idx) << (info)->ctxt_shift) & ~ASID_MASK(info))
+
+static void flush_context(struct asid_info *info)
+{
+       int i;
+       u64 asid;
+
+       /* Update the list of reserved ASIDs and the ASID bitmap. */
+       bitmap_clear(info->map, 0, NUM_CTXT_ASIDS(info));
+
+       for_each_possible_cpu(i) {
+               asid = atomic64_xchg_relaxed(&active_asid(info, i), 0);
+               /*
+                * If this CPU has already been through a
+                * rollover, but hasn't run another task in
+                * the meantime, we must preserve its reserved
+                * ASID, as this is the only trace we have of
+                * the process it is still running.
+                */
+               if (asid == 0)
+                       asid = reserved_asid(info, i);
+               __set_bit(asid2idx(info, asid), info->map);
+               reserved_asid(info, i) = asid;
+       }
+
+       /*
+        * Queue a TLB invalidation for each CPU to perform on next
+        * context-switch
+        */
+       cpumask_setall(&info->flush_pending);
+}
+
+static bool check_update_reserved_asid(struct asid_info *info, u64 asid,
+                                      u64 newasid)
+{
+       int cpu;
+       bool hit = false;
+
+       /*
+        * Iterate over the set of reserved ASIDs looking for a match.
+        * If we find one, then we can update our mm to use newasid
+        * (i.e. the same ASID in the current generation) but we can't
+        * exit the loop early, since we need to ensure that all copies
+        * of the old ASID are updated to reflect the mm. Failure to do
+        * so could result in us missing the reserved ASID in a future
+        * generation.
+        */
+       for_each_possible_cpu(cpu) {
+               if (reserved_asid(info, cpu) == asid) {
+                       hit = true;
+                       reserved_asid(info, cpu) = newasid;
+               }
+       }
+
+       return hit;
+}
+
+static u64 new_context(struct asid_info *info, atomic64_t *pasid,
+                      struct mm_struct *mm)
+{
+       static u32 cur_idx = 1;
+       u64 asid = atomic64_read(pasid);
+       u64 generation = atomic64_read(&info->generation);
+
+       if (asid != 0) {
+               u64 newasid = generation | (asid & ~ASID_MASK(info));
+
+               /*
+                * If our current ASID was active during a rollover, we
+                * can continue to use it and this was just a false alarm.
+                */
+               if (check_update_reserved_asid(info, asid, newasid))
+                       return newasid;
+
+               /*
+                * We had a valid ASID in a previous life, so try to re-use
+                * it if possible.
+                */
+               if (!__test_and_set_bit(asid2idx(info, asid), info->map))
+                       return newasid;
+       }
+
+       /*
+        * Allocate a free ASID. If we can't find one, take a note of the
+        * currently active ASIDs and mark the TLBs as requiring flushes.  We
+        * always count from ASID #2 (index 1), as we use ASID #0 when setting
+        * a reserved TTBR0 for the init_mm and we allocate ASIDs in even/odd
+        * pairs.
+        */
+       asid = find_next_zero_bit(info->map, NUM_CTXT_ASIDS(info), cur_idx);
+       if (asid != NUM_CTXT_ASIDS(info))
+               goto set_asid;
+
+       /* We're out of ASIDs, so increment the global generation count */
+       generation = atomic64_add_return_relaxed(ASID_FIRST_VERSION(info),
+                                                &info->generation);
+       flush_context(info);
+
+       /* We have more ASIDs than CPUs, so this will always succeed */
+       asid = find_next_zero_bit(info->map, NUM_CTXT_ASIDS(info), 1);
+
+set_asid:
+       __set_bit(asid, info->map);
+       cur_idx = asid;
+       cpumask_clear(mm_cpumask(mm));
+       return idx2asid(info, asid) | generation;
+}
+
+/*
+ * Generate a new ASID for the context.
+ *
+ * @pasid: Pointer to the current ASID batch allocated. It will be updated
+ * with the new ASID batch.
+ * @cpu: current CPU ID. Must have been acquired through get_cpu()
+ */
+void asid_new_context(struct asid_info *info, atomic64_t *pasid,
+                     unsigned int cpu, struct mm_struct *mm)
+{
+       unsigned long flags;
+       u64 asid;
+
+       raw_spin_lock_irqsave(&info->lock, flags);
+       /* Check that our ASID belongs to the current generation. */
+       asid = atomic64_read(pasid);
+       if ((asid ^ atomic64_read(&info->generation)) >> info->bits) {
+               asid = new_context(info, pasid, mm);
+               atomic64_set(pasid, asid);
+       }
+
+       if (cpumask_test_and_clear_cpu(cpu, &info->flush_pending))
+               info->flush_cpu_ctxt_cb();
+
+       atomic64_set(&active_asid(info, cpu), asid);
+       cpumask_set_cpu(cpu, mm_cpumask(mm));
+       raw_spin_unlock_irqrestore(&info->lock, flags);
+}
+
+/*
+ * Initialize the ASID allocator
+ *
+ * @info: Pointer to the asid allocator structure
+ * @bits: Number of ASIDs available
+ * @asid_per_ctxt: Number of ASIDs to allocate per-context. ASIDs are
+ * allocated contiguously for a given context. This value should be a power of
+ * 2.
+ */
+int asid_allocator_init(struct asid_info *info,
+                       u32 bits, unsigned int asid_per_ctxt,
+                       void (*flush_cpu_ctxt_cb)(void))
+{
+       info->bits = bits;
+       info->ctxt_shift = ilog2(asid_per_ctxt);
+       info->flush_cpu_ctxt_cb = flush_cpu_ctxt_cb;
+       /*
+        * Expect allocation after rollover to fail if we don't have at least
+        * one more ASID than CPUs. ASID #0 is always reserved.
+        */
+       WARN_ON(NUM_CTXT_ASIDS(info) - 1 <= num_possible_cpus());
+       atomic64_set(&info->generation, ASID_FIRST_VERSION(info));
+       info->map = kcalloc(BITS_TO_LONGS(NUM_CTXT_ASIDS(info)),
+                           sizeof(*info->map), GFP_KERNEL);
+       if (!info->map)
+               return -ENOMEM;
+
+       raw_spin_lock_init(&info->lock);
+
+       return 0;
+}
diff --git a/arch/csky/mm/context.c b/arch/csky/mm/context.c
new file mode 100644 (file)
index 0000000..0d95bdd
--- /dev/null
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#include <linux/bitops.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+
+#include <asm/asid.h>
+#include <asm/mmu_context.h>
+#include <asm/smp.h>
+#include <asm/tlbflush.h>
+
+static DEFINE_PER_CPU(atomic64_t, active_asids);
+static DEFINE_PER_CPU(u64, reserved_asids);
+
+struct asid_info asid_info;
+
+void check_and_switch_context(struct mm_struct *mm, unsigned int cpu)
+{
+       asid_check_context(&asid_info, &mm->context.asid, cpu, mm);
+}
+
+static void asid_flush_cpu_ctxt(void)
+{
+       local_tlb_invalid_all();
+}
+
+static int asids_init(void)
+{
+       BUG_ON(((1 << CONFIG_CPU_ASID_BITS) - 1) <= num_possible_cpus());
+
+       if (asid_allocator_init(&asid_info, CONFIG_CPU_ASID_BITS, 1,
+                               asid_flush_cpu_ctxt))
+               panic("Unable to initialize ASID allocator for %lu ASIDs\n",
+                     NUM_ASIDS(&asid_info));
+
+       asid_info.active = &active_asids;
+       asid_info.reserved = &reserved_asids;
+
+       pr_info("ASID allocator initialised with %lu entries\n",
+               NUM_CTXT_ASIDS(&asid_info));
+
+       return 0;
+}
+early_initcall(asids_init);
index 66e5970..eb0dc9e 100644 (file)
@@ -114,8 +114,6 @@ void __init pre_mmu_init(void)
        TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir);
        TLBMISS_HANDLER_SETUP_PGD_KERNEL(swapper_pg_dir);
 
-       asid_cache(smp_processor_id()) = ASID_FIRST_VERSION;
-
        /* Setup page mask to 4k */
        write_mmu_pagemask(0);
 }
index 08b8394..eb3ba6c 100644 (file)
 #include <asm/pgtable.h>
 #include <asm/setup.h>
 
-#define CSKY_TLB_SIZE CONFIG_CPU_TLB_SIZE
+/*
+ * One C-SKY MMU TLB entry contain two PFN/page entry, ie:
+ * 1VPN -> 2PFN
+ */
+#define TLB_ENTRY_SIZE         (PAGE_SIZE * 2)
+#define TLB_ENTRY_SIZE_MASK    (PAGE_MASK << 1)
 
 void flush_tlb_all(void)
 {
@@ -19,201 +24,148 @@ void flush_tlb_all(void)
 
 void flush_tlb_mm(struct mm_struct *mm)
 {
-       int cpu = smp_processor_id();
-
-       if (cpu_context(cpu, mm) != 0)
-               drop_mmu_context(mm, cpu);
-
+#ifdef CONFIG_CPU_HAS_TLBI
+       asm volatile("tlbi.asids %0"::"r"(cpu_asid(mm)));
+#else
        tlb_invalid_all();
+#endif
 }
 
+/*
+ * MMU operation regs only could invalid tlb entry in jtlb and we
+ * need change asid field to invalid I-utlb & D-utlb.
+ */
+#ifndef CONFIG_CPU_HAS_TLBI
 #define restore_asid_inv_utlb(oldpid, newpid) \
 do { \
-       if ((oldpid & ASID_MASK) == newpid) \
+       if (oldpid == newpid) \
                write_mmu_entryhi(oldpid + 1); \
        write_mmu_entryhi(oldpid); \
 } while (0)
+#endif
 
 void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
-                          unsigned long end)
+                       unsigned long end)
 {
-       struct mm_struct *mm = vma->vm_mm;
-       int cpu = smp_processor_id();
-
-       if (cpu_context(cpu, mm) != 0) {
-               unsigned long size, flags;
-               int newpid = cpu_asid(cpu, mm);
-
-               local_irq_save(flags);
-               size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
-               size = (size + 1) >> 1;
-               if (size <= CSKY_TLB_SIZE/2) {
-                       start &= (PAGE_MASK << 1);
-                       end += ((PAGE_SIZE << 1) - 1);
-                       end &= (PAGE_MASK << 1);
-#ifdef CONFIG_CPU_HAS_TLBI
-                       while (start < end) {
-                               asm volatile("tlbi.vaas %0"
-                                            ::"r"(start | newpid));
-                               start += (PAGE_SIZE << 1);
-                       }
-                       sync_is();
-#else
-                       {
-                       int oldpid = read_mmu_entryhi();
-
-                       while (start < end) {
-                               int idx;
-
-                               write_mmu_entryhi(start | newpid);
-                               start += (PAGE_SIZE << 1);
-                               tlb_probe();
-                               idx = read_mmu_index();
-                               if (idx >= 0)
-                                       tlb_invalid_indexed();
-                       }
-                       restore_asid_inv_utlb(oldpid, newpid);
-                       }
-#endif
-               } else {
-                       drop_mmu_context(mm, cpu);
-               }
-               local_irq_restore(flags);
-       }
-}
+       unsigned long newpid = cpu_asid(vma->vm_mm);
 
-void flush_tlb_kernel_range(unsigned long start, unsigned long end)
-{
-       unsigned long size, flags;
+       start &= TLB_ENTRY_SIZE_MASK;
+       end   += TLB_ENTRY_SIZE - 1;
+       end   &= TLB_ENTRY_SIZE_MASK;
 
-       local_irq_save(flags);
-       size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
-       if (size <= CSKY_TLB_SIZE) {
-               start &= (PAGE_MASK << 1);
-               end += ((PAGE_SIZE << 1) - 1);
-               end &= (PAGE_MASK << 1);
 #ifdef CONFIG_CPU_HAS_TLBI
-               while (start < end) {
-                       asm volatile("tlbi.vaas %0"::"r"(start));
-                       start += (PAGE_SIZE << 1);
-               }
-               sync_is();
-#else
-               {
-               int oldpid = read_mmu_entryhi();
-
-               while (start < end) {
-                       int idx;
-
-                       write_mmu_entryhi(start);
-                       start += (PAGE_SIZE << 1);
-                       tlb_probe();
-                       idx = read_mmu_index();
-                       if (idx >= 0)
-                               tlb_invalid_indexed();
-               }
-               restore_asid_inv_utlb(oldpid, 0);
-               }
-#endif
-       } else {
-               flush_tlb_all();
+       while (start < end) {
+               asm volatile("tlbi.vas %0"::"r"(start | newpid));
+               start += 2*PAGE_SIZE;
        }
+       sync_is();
+#else
+       {
+       unsigned long flags, oldpid;
+
+       local_irq_save(flags);
+       oldpid = read_mmu_entryhi() & ASID_MASK;
+       while (start < end) {
+               int idx;
 
+               write_mmu_entryhi(start | newpid);
+               start += 2*PAGE_SIZE;
+               tlb_probe();
+               idx = read_mmu_index();
+               if (idx >= 0)
+                       tlb_invalid_indexed();
+       }
+       restore_asid_inv_utlb(oldpid, newpid);
        local_irq_restore(flags);
+       }
+#endif
 }
 
-void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
 {
-       int cpu = smp_processor_id();
-       int newpid = cpu_asid(cpu, vma->vm_mm);
-
-       if (!vma || cpu_context(cpu, vma->vm_mm) != 0) {
-               page &= (PAGE_MASK << 1);
+       start &= TLB_ENTRY_SIZE_MASK;
+       end   += TLB_ENTRY_SIZE - 1;
+       end   &= TLB_ENTRY_SIZE_MASK;
 
 #ifdef CONFIG_CPU_HAS_TLBI
-               asm volatile("tlbi.vaas %0"::"r"(page | newpid));
-               sync_is();
+       while (start < end) {
+               asm volatile("tlbi.vaas %0"::"r"(start));
+               start += 2*PAGE_SIZE;
+       }
+       sync_is();
 #else
-               {
-               int oldpid, idx;
-               unsigned long flags;
+       {
+       unsigned long flags, oldpid;
 
-               local_irq_save(flags);
-               oldpid = read_mmu_entryhi();
-               write_mmu_entryhi(page | newpid);
+       local_irq_save(flags);
+       oldpid = read_mmu_entryhi() & ASID_MASK;
+       while (start < end) {
+               int idx;
+
+               write_mmu_entryhi(start | oldpid);
+               start += 2*PAGE_SIZE;
                tlb_probe();
                idx = read_mmu_index();
                if (idx >= 0)
                        tlb_invalid_indexed();
-
-               restore_asid_inv_utlb(oldpid, newpid);
-               local_irq_restore(flags);
-               }
-#endif
        }
+       restore_asid_inv_utlb(oldpid, oldpid);
+       local_irq_restore(flags);
+       }
+#endif
 }
 
-/*
- * Remove one kernel space TLB entry.  This entry is assumed to be marked
- * global so we don't do the ASID thing.
- */
-void flush_tlb_one(unsigned long page)
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
 {
-       int oldpid;
+       int newpid = cpu_asid(vma->vm_mm);
 
-       oldpid = read_mmu_entryhi();
-       page &= (PAGE_MASK << 1);
+       addr &= TLB_ENTRY_SIZE_MASK;
 
 #ifdef CONFIG_CPU_HAS_TLBI
-       page = page | (oldpid & 0xfff);
-       asm volatile("tlbi.vaas %0"::"r"(page));
+       asm volatile("tlbi.vas %0"::"r"(addr | newpid));
        sync_is();
 #else
        {
-       int idx;
+       int oldpid, idx;
        unsigned long flags;
 
-       page = page | (oldpid & 0xff);
-
        local_irq_save(flags);
-       write_mmu_entryhi(page);
+       oldpid = read_mmu_entryhi() & ASID_MASK;
+       write_mmu_entryhi(addr | newpid);
        tlb_probe();
        idx = read_mmu_index();
        if (idx >= 0)
                tlb_invalid_indexed();
-       restore_asid_inv_utlb(oldpid, oldpid);
+
+       restore_asid_inv_utlb(oldpid, newpid);
        local_irq_restore(flags);
        }
 #endif
 }
-EXPORT_SYMBOL(flush_tlb_one);
 
-/* show current 32 jtlbs */
-void show_jtlb_table(void)
+void flush_tlb_one(unsigned long addr)
 {
+       addr &= TLB_ENTRY_SIZE_MASK;
+
+#ifdef CONFIG_CPU_HAS_TLBI
+       asm volatile("tlbi.vaas %0"::"r"(addr));
+       sync_is();
+#else
+       {
+       int oldpid, idx;
        unsigned long flags;
-       int entryhi, entrylo0, entrylo1;
-       int entry;
-       int oldpid;
 
        local_irq_save(flags);
-       entry = 0;
-       pr_info("\n\n\n");
-
-       oldpid = read_mmu_entryhi();
-       while (entry < CSKY_TLB_SIZE) {
-               write_mmu_index(entry);
-               tlb_read();
-               entryhi = read_mmu_entryhi();
-               entrylo0 = read_mmu_entrylo0();
-               entrylo0 = entrylo0;
-               entrylo1 = read_mmu_entrylo1();
-               entrylo1 = entrylo1;
-               pr_info("jtlb[%d]:      entryhi - 0x%x; entrylo0 - 0x%x;"
-                       "       entrylo1 - 0x%x\n",
-                       entry, entryhi, entrylo0, entrylo1);
-               entry++;
-       }
-       write_mmu_entryhi(oldpid);
+       oldpid = read_mmu_entryhi() & ASID_MASK;
+       write_mmu_entryhi(addr | oldpid);
+       tlb_probe();
+       idx = read_mmu_index();
+       if (idx >= 0)
+               tlb_invalid_indexed();
+
+       restore_asid_inv_utlb(oldpid, oldpid);
        local_irq_restore(flags);
+       }
+#endif
 }
+EXPORT_SYMBOL(flush_tlb_one);
index 647a83b..7aa16c7 100644 (file)
@@ -51,12 +51,6 @@ static inline void FNAME(int nr, volatile unsigned long *addr)       \
        }                                                       \
 }
 
-/*
- * clear_bit() doesn't provide any barrier for the compiler.
- */
-#define smp_mb__before_clear_bit()     barrier()
-#define smp_mb__after_clear_bit()      barrier()
-
 H8300_GEN_BITOP(set_bit,    "bset")
 H8300_GEN_BITOP(clear_bit,  "bclr")
 H8300_GEN_BITOP(change_bit, "bnot")
index 3c9e1bd..d6544dc 100644 (file)
@@ -11,6 +11,8 @@
 #include <asm/mem-layout.h>
 #include <asm/atomic.h>
 
+#include <asm-generic/pgalloc.h>       /* for pte_{alloc,free}_one */
+
 #define check_pgt_cache() do {} while (0)
 
 extern unsigned long long kmap_generation;
@@ -46,38 +48,6 @@ static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
        free_page((unsigned long) pgd);
 }
 
-static inline struct page *pte_alloc_one(struct mm_struct *mm)
-{
-       struct page *pte;
-
-       pte = alloc_page(GFP_KERNEL | __GFP_ZERO);
-       if (!pte)
-               return NULL;
-       if (!pgtable_page_ctor(pte)) {
-               __free_page(pte);
-               return NULL;
-       }
-       return pte;
-}
-
-/* _kernel variant gets to use a different allocator */
-static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm)
-{
-       gfp_t flags =  GFP_KERNEL | __GFP_ZERO;
-       return (pte_t *) __get_free_page(flags);
-}
-
-static inline void pte_free(struct mm_struct *mm, struct page *pte)
-{
-       pgtable_page_dtor(pte);
-       __free_page(pte);
-}
-
-static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
-{
-       free_page((unsigned long)pte);
-}
-
 static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
                                pgtable_t pte)
 {
index 4f054b1..f6e454f 100644 (file)
@@ -9,6 +9,8 @@
 #define _ASM_HEXAGON_SYSCALL_H
 
 #include <uapi/linux/audit.h>
+#include <linux/err.h>
+#include <asm/ptrace.h>
 
 typedef long (*syscall_fn)(unsigned long, unsigned long,
        unsigned long, unsigned long,
@@ -31,6 +33,18 @@ static inline void syscall_get_arguments(struct task_struct *task,
        memcpy(args, &(&regs->r00)[0], 6 * sizeof(args[0]));
 }
 
+static inline long syscall_get_error(struct task_struct *task,
+                                    struct pt_regs *regs)
+{
+       return IS_ERR_VALUE(regs->r00) ? regs->r00 : 0;
+}
+
+static inline long syscall_get_return_value(struct task_struct *task,
+                                           struct pt_regs *regs)
+{
+       return regs->r00;
+}
+
 static inline int syscall_get_arch(struct task_struct *task)
 {
        return AUDIT_ARCH_HEXAGON;
index 8f10663..3795d18 100644 (file)
@@ -852,7 +852,7 @@ valid_phys_addr_range (phys_addr_t phys_addr, unsigned long size)
         * /dev/mem reads and writes use copy_to_user(), which implicitly
         * uses a granule-sized kernel identity mapping.  It's really
         * only safe to do this for regions in kern_memmap.  For more
-        * details, see Documentation/ia64/aliasing.txt.
+        * details, see Documentation/ia64/aliasing.rst.
         */
        attr = kern_mem_attribute(phys_addr, size);
        if (attr & EFI_MEMORY_WB || attr & EFI_MEMORY_UC)
index d80c99a..0750a71 100644 (file)
@@ -28,7 +28,7 @@
 #include <asm/native/inst.h>
 
 /*
- * See Documentation/ia64/fsys.txt for details on fsyscalls.
+ * See Documentation/ia64/fsys.rst for details on fsyscalls.
  *
  * On entry to an fsyscall handler:
  *   r10       = 0 (i.e., defaults to "successful syscall return")
index 7c52bd2..a23c393 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/smp.h>
 #include <linux/pagemap.h>
 #include <linux/mount.h>
+#include <linux/pseudo_fs.h>
 #include <linux/bitops.h>
 #include <linux/capability.h>
 #include <linux/rcupdate.h>
@@ -600,17 +601,19 @@ pfm_unprotect_ctx_ctxsw(pfm_context_t *x, unsigned long f)
 /* forward declaration */
 static const struct dentry_operations pfmfs_dentry_operations;
 
-static struct dentry *
-pfmfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data)
+static int pfmfs_init_fs_context(struct fs_context *fc)
 {
-       return mount_pseudo(fs_type, "pfm:", NULL, &pfmfs_dentry_operations,
-                       PFMFS_MAGIC);
+       struct pseudo_fs_context *ctx = init_pseudo(fc, PFMFS_MAGIC);
+       if (!ctx)
+               return -ENOMEM;
+       ctx->dops = &pfmfs_dentry_operations;
+       return 0;
 }
 
 static struct file_system_type pfm_fs_type = {
-       .name     = "pfmfs",
-       .mount    = pfmfs_mount,
-       .kill_sb  = kill_anon_super,
+       .name                   = "pfmfs",
+       .init_fs_context        = pfmfs_init_fs_context,
+       .kill_sb                = kill_anon_super,
 };
 MODULE_ALIAS_FS("pfmfs");
 
index ecc4492..36d5faf 100644 (file)
 432    common  fsmount                         sys_fsmount
 433    common  fspick                          sys_fspick
 434    common  pidfd_open                      sys_pidfd_open
+# 435 reserved for clone3
index 3c3a283..c2f299f 100644 (file)
 
 extern int die(char *, struct pt_regs *, long);
 
-#ifdef CONFIG_KPROBES
-static inline int notify_page_fault(struct pt_regs *regs, int trap)
-{
-       int ret = 0;
-
-       if (!user_mode(regs)) {
-               /* kprobe_running() needs smp_processor_id() */
-               preempt_disable();
-               if (kprobe_running() && kprobe_fault_handler(regs, trap))
-                       ret = 1;
-               preempt_enable();
-       }
-
-       return ret;
-}
-#else
-static inline int notify_page_fault(struct pt_regs *regs, int trap)
-{
-       return 0;
-}
-#endif
-
 /*
  * Return TRUE if ADDRESS points at a page in the kernel's mapped segment
  * (inside region 5, on ia64) and that page is present.
@@ -116,7 +94,7 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
        /*
         * This is to handle the kprobes on user space access instructions
         */
-       if (notify_page_fault(regs, TRAP_BRKPT))
+       if (kprobe_page_fault(regs, TRAP_BRKPT))
                return;
 
        if (user_mode(regs))
index d28e291..aae75fd 100644 (file)
@@ -681,7 +681,6 @@ int arch_add_memory(int nid, u64 start, u64 size,
        return ret;
 }
 
-#ifdef CONFIG_MEMORY_HOTREMOVE
 void arch_remove_memory(int nid, u64 start, u64 size,
                        struct vmem_altmap *altmap)
 {
@@ -693,4 +692,3 @@ void arch_remove_memory(int nid, u64 start, u64 size,
        __remove_pages(zone, start_pfn, nr_pages, altmap);
 }
 #endif
-#endif
index 5e3e7b1..0c0de2c 100644 (file)
@@ -42,7 +42,7 @@ ioremap (unsigned long phys_addr, unsigned long size)
        /*
         * For things in kern_memmap, we must use the same attribute
         * as the rest of the kernel.  For more details, see
-        * Documentation/ia64/aliasing.txt.
+        * Documentation/ia64/aliasing.rst.
         */
        attr = kern_mem_attribute(phys_addr, size);
        if (attr & EFI_MEMORY_WB)
index e308196..165e561 100644 (file)
@@ -450,7 +450,7 @@ pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma,
                return -ENOSYS;
 
        /*
-        * Avoid attribute aliasing.  See Documentation/ia64/aliasing.txt
+        * Avoid attribute aliasing.  See Documentation/ia64/aliasing.rst
         * for more details.
         */
        if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))
index 9a3eb25..a88a285 100644 (file)
 432    common  fsmount                         sys_fsmount
 433    common  fspick                          sys_fspick
 434    common  pidfd_open                      sys_pidfd_open
+# 435 reserved for clone3
index ba32825..b3ffe7c 100644 (file)
@@ -57,6 +57,7 @@ const char *get_system_type(void)
                case TITAN_CHIP_1060:
                        return "TI AR7 (TNETV1060)";
                }
+               /* fall through */
        default:
                return "TI AR7 (unknown)";
        }
index f22538c..ea385a8 100644 (file)
@@ -153,7 +153,7 @@ static void __init ath79_detect_sys_type(void)
        case REV_ID_MAJOR_QCA9533_V2:
                ver = 2;
                ath79_soc_rev = 2;
-               /* drop through */
+               /* fall through */
 
        case REV_ID_MAJOR_QCA9533:
                ath79_soc = ATH79_SOC_QCA9533;
index 172dd83..a109393 100644 (file)
@@ -94,6 +94,7 @@ static int __init bcm63xx_detect_flash_type(void)
                case STRAPBUS_6368_BOOT_SEL_PARALLEL:
                        return BCM63XX_FLASH_TYPE_PARALLEL;
                }
+               /* fall through */
        default:
                return -EINVAL;
        }
index 1738a06..2f81a94 100644 (file)
@@ -162,7 +162,7 @@ void __init plat_mem_setup(void)
        ioport_resource.start = 0;
        ioport_resource.end = ~0;
 
-       /* intended to somewhat resemble ARM; see Documentation/arm/Booting */
+       /* intended to somewhat resemble ARM; see Documentation/arm/booting.rst */
        if (fw_arg0 == 0 && fw_arg1 == 0xffffffff)
                dtb = phys_to_virt(fw_arg2);
        else if (fw_passed_dtb) /* UHI interface or appended dtb */
index 9ff7e8f..61f8621 100644 (file)
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
+
 / {
        #address-cells = <1>;
        #size-cells = <1>;
 
                sysc: system-controller@0 {
                        compatible = "ralink,mt7620a-sysc", "syscon";
-                       reg = <0x0 0x100>;
+                       reg = <0x0 0x60>;
+               };
+
+               pinmux: pinmux@60 {
+                       compatible = "pinctrl-single";
+                       reg = <0x60 0x8>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       #pinctrl-cells = <2>;
+                       pinctrl-single,bit-per-mux;
+                       pinctrl-single,register-width = <32>;
+                       pinctrl-single,function-mask = <0x1>;
+
+                       pinmux_gpio_gpio: pinmux_gpio_gpio {
+                               pinctrl-single,bits = <0x0 0x0 0x3>;
+                       };
+
+                       pinmux_spi_cs1_cs: pinmux_spi_cs1_cs {
+                               pinctrl-single,bits = <0x0 0x0 0x30>;
+                       };
+
+                       pinmux_i2s_gpio: pinmux_i2s_gpio {
+                               pinctrl-single,bits = <0x0 0x40 0xc0>;
+                       };
+
+                       pinmux_uart0_uart: pinmux_uart0_uart0 {
+                               pinctrl-single,bits = <0x0 0x0 0x300>;
+                       };
+
+                       pinmux_sdmode_sdxc: pinmux_sdmode_sdxc {
+                               pinctrl-single,bits = <0x0 0x0 0xc00>;
+                       };
+
+                       pinmux_sdmode_gpio: pinmux_sdmode_gpio {
+                               pinctrl-single,bits = <0x0 0x400 0xc00>;
+                       };
+
+                       pinmux_spi_spi: pinmux_spi_spi {
+                               pinctrl-single,bits = <0x0 0x0 0x1000>;
+                       };
+
+                       pinmux_refclk_gpio: pinmux_refclk_gpio {
+                               pinctrl-single,bits = <0x0 0x40000 0x40000>;
+                       };
+
+                       pinmux_i2c_i2c: pinmux_i2c_i2c {
+                               pinctrl-single,bits = <0x0 0x0 0x300000>;
+                       };
+
+                       pinmux_uart1_uart: pinmux_uart1_uart1 {
+                               pinctrl-single,bits = <0x0 0x0 0x3000000>;
+                       };
+
+                       pinmux_uart2_uart: pinmux_uart2_uart {
+                               pinctrl-single,bits = <0x0 0x0 0xc000000>;
+                       };
+
+                       pinmux_pwm0_pwm: pinmux_pwm0_pwm {
+                               pinctrl-single,bits = <0x0 0x0 0x30000000>;
+                       };
+
+                       pinmux_pwm0_gpio: pinmux_pwm0_gpio {
+                               pinctrl-single,bits = <0x0 0x10000000
+                                                      0x30000000>;
+                       };
+
+                       pinmux_pwm1_pwm: pinmux_pwm1_pwm {
+                               pinctrl-single,bits = <0x0 0x0 0xc0000000>;
+                       };
+
+                       pinmux_pwm1_gpio: pinmux_pwm1_gpio {
+                               pinctrl-single,bits = <0x0 0x40000000
+                                                      0xc0000000>;
+                       };
+
+                       pinmux_p0led_an_gpio: pinmux_p0led_an_gpio {
+                               pinctrl-single,bits = <0x4 0x4 0xc>;
+                       };
+
+                       pinmux_p1led_an_gpio: pinmux_p1led_an_gpio {
+                               pinctrl-single,bits = <0x4 0x10 0x30>;
+                       };
+
+                       pinmux_p2led_an_gpio: pinmux_p2led_an_gpio {
+                               pinctrl-single,bits = <0x4 0x40 0xc0>;
+                       };
+
+                       pinmux_p3led_an_gpio: pinmux_p3led_an_gpio {
+                               pinctrl-single,bits = <0x4 0x100 0x300>;
+                       };
+
+                       pinmux_p4led_an_gpio: pinmux_p4led_an_gpio {
+                               pinctrl-single,bits = <0x4 0x400 0xc00>;
+                       };
+               };
+
+               watchdog: watchdog@100 {
+                       compatible = "mediatek,mt7621-wdt";
+                       reg = <0x100 0x30>;
+
+                       resets = <&resetc 8>;
+                       reset-names = "wdt";
+
+                       interrupt-parent = <&intc>;
+                       interrupts = <24>;
+
+                       status = "disabled";
                };
 
                intc: interrupt-controller@200 {
                        reg = <0x300 0x100>;
                };
 
+               gpio: gpio@600 {
+                       compatible = "mediatek,mt7621-gpio";
+                       reg = <0x600 0x100>;
+
+                       gpio-controller;
+                       interrupt-controller;
+                       #gpio-cells = <2>;
+                       #interrupt-cells = <2>;
+
+                       interrupt-parent = <&intc>;
+                       interrupts = <6>;
+               };
+
+               spi: spi@b00 {
+                       compatible = "ralink,mt7621-spi";
+                       reg = <0xb00 0x100>;
+
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinmux_spi_spi>;
+
+                       resets = <&resetc 18>;
+                       reset-names = "spi";
+
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       status = "disabled";
+               };
+
                uart0: uartlite@c00 {
                        compatible = "ns16550a";
                        reg = <0xc00 0x100>;
 
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinmux_uart0_uart>;
+
                        resets = <&resetc 12>;
                        reset-names = "uart0";
 
                        compatible = "ns16550a";
                        reg = <0xd00 0x100>;
 
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinmux_uart1_uart>;
+
                        resets = <&resetc 19>;
                        reset-names = "uart1";
 
                        compatible = "ns16550a";
                        reg = <0xe00 0x100>;
 
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinmux_uart2_uart>;
+
                        resets = <&resetc 20>;
                        reset-names = "uart2";
 
index 676fab5..b077597 100644 (file)
@@ -485,11 +485,11 @@ cvmx_pko_status_t cvmx_pko_config_port(uint64_t port, uint64_t base_queue,
                        config.s.qos_mask = 0xff;
                        break;
                case CVMX_PKO_QUEUE_STATIC_PRIORITY:
-                       /* Pass 1 will fall through to the error case */
                        if (!cvmx_octeon_is_pass1()) {
                                config.s.qos_mask = 0xff;
                                break;
                        }
+                       /* fall through - to the error case, when Pass 1 */
                default:
                        cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid "
                                     "priority %llu\n",
index c83fdf6..cef2754 100644 (file)
@@ -71,7 +71,6 @@ CONFIG_NET_ACT_POLICE=y
 CONFIG_HAMRADIO=y
 CONFIG_CFG80211=m
 CONFIG_MAC80211=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
index 5dd6b19..c35add2 100644 (file)
@@ -37,7 +37,6 @@ CONFIG_IP_ADVANCED_ROUTER=y
 CONFIG_CFG80211=m
 CONFIG_MAC80211=m
 CONFIG_MAC80211_DEBUGFS=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-2
index 6f981af..4ffc59c 100644 (file)
@@ -37,7 +37,6 @@ CONFIG_IP_ADVANCED_ROUTER=y
 CONFIG_CFG80211=m
 CONFIG_MAC80211=m
 CONFIG_MAC80211_DEBUGFS=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-2
index d22fe62..54e2f9a 100644 (file)
@@ -34,7 +34,6 @@ CONFIG_INET=y
 CONFIG_CFG80211=y
 CONFIG_NL80211_TESTMODE=y
 CONFIG_MAC80211=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_MTD=y
index 597bc0a..6656602 100644 (file)
@@ -99,7 +99,6 @@ CONFIG_BPQETHER=m
 CONFIG_BAYCOM_SER_FDX=m
 CONFIG_BAYCOM_SER_HDX=m
 CONFIG_YAM=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_FW_LOADER=m
 CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_CRYPTOLOOP=m
index 8a91f01..f669a40 100644 (file)
@@ -26,7 +26,6 @@ CONFIG_INET=y
 CONFIG_CFG80211=y
 CONFIG_NL80211_TESTMODE=y
 CONFIG_MAC80211=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_STANDALONE is not set
index 39adcca..a0b7758 100644 (file)
@@ -35,7 +35,6 @@ CONFIG_INET=y
 CONFIG_CFG80211=y
 CONFIG_NL80211_TESTMODE=y
 CONFIG_MAC80211=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_STANDALONE is not set
index d7abb64..b669536 100644 (file)
@@ -42,7 +42,6 @@ CONFIG_IP_MROUTE=y
 CONFIG_IP_PIMSM_V1=y
 CONFIG_IP_PIMSM_V2=y
 CONFIG_SYN_COOKIES=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
index 50bebce..cb4aa23 100644 (file)
@@ -44,7 +44,6 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
 # CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 # CONFIG_FW_LOADER is not set
 # CONFIG_ALLOW_DEV_COREDUMP is not set
index 20c6284..c6a652a 100644 (file)
@@ -14,7 +14,6 @@ CONFIG_NET_KEY=y
 CONFIG_NET_KEY_MIGRATE=y
 CONFIG_INET=y
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_JEDECPROBE=y
 CONFIG_MTD_CFI_AMDSTD=y
index 8bcb61a..7a7af70 100644 (file)
@@ -83,7 +83,6 @@ CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
 CONFIG_PHONET=m
 CONFIG_NET_9P=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_FW_LOADER=m
 CONFIG_MTD=m
 CONFIG_MTD_BLOCK=m
index 9d9af5f..9085f4d 100644 (file)
@@ -249,7 +249,6 @@ CONFIG_WATCHDOG_NOWAYOUT=y
 CONFIG_SSB=m
 CONFIG_SSB_DRIVER_PCICORE=y
 # CONFIG_VGA_ARB is not set
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_BACKLIGHT_GENERIC is not set
index 54db5de..82d942a 100644 (file)
@@ -91,7 +91,6 @@ CONFIG_NET_ACT_SKBEDIT=m
 CONFIG_CFG80211=m
 CONFIG_MAC80211=m
 CONFIG_RFKILL=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_CDROM_PKTCDVD=m
index 8f6d8af..572cab9 100644 (file)
@@ -42,7 +42,6 @@ CONFIG_INET6_ESP=m
 CONFIG_INET6_IPCOMP=m
 CONFIG_IPV6_TUNNEL=m
 CONFIG_NETWORK_SECMARK=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_CONNECTOR=y
 CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_CRYPTOLOOP=m
index 300127b..d44f146 100644 (file)
@@ -77,7 +77,6 @@ CONFIG_MAC80211=m
 CONFIG_MAC80211_LEDS=y
 CONFIG_RFKILL=m
 CONFIG_RFKILL_INPUT=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_RAM=y
@@ -144,7 +143,6 @@ CONFIG_FB_TILEBLITTING=y
 CONFIG_FB_SIS=y
 CONFIG_FB_SIS_300=y
 CONFIG_FB_SIS_315=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_GENERIC=m
index 3d390a7..25e7042 100644 (file)
@@ -34,7 +34,6 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
 # CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_STANDALONE is not set
index 247d56e..3a158d4 100644 (file)
@@ -35,7 +35,6 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
 # CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_STANDALONE is not set
index 1322adb..90ee008 100644 (file)
@@ -97,7 +97,6 @@ CONFIG_CFG80211_WEXT=y
 CONFIG_MAC80211=m
 CONFIG_RFKILL=m
 CONFIG_RFKILL_INPUT=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_MTD=m
index 0de92ac..59eedf5 100644 (file)
@@ -214,7 +214,6 @@ CONFIG_CFG80211=m
 CONFIG_MAC80211=m
 CONFIG_MAC80211_MESH=y
 CONFIG_RFKILL=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_CONNECTOR=m
 CONFIG_MTD=y
index efc3aba..8ef6125 100644 (file)
@@ -219,7 +219,6 @@ CONFIG_CFG80211=m
 CONFIG_MAC80211=m
 CONFIG_MAC80211_MESH=y
 CONFIG_RFKILL=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_CONNECTOR=m
 CONFIG_MTD=y
index c6ceeca..d2a008c 100644 (file)
@@ -216,7 +216,6 @@ CONFIG_CFG80211=m
 CONFIG_MAC80211=m
 CONFIG_MAC80211_MESH=y
 CONFIG_RFKILL=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_CONNECTOR=m
 CONFIG_MTD=y
index 56861ae..970df6d 100644 (file)
@@ -216,7 +216,6 @@ CONFIG_CFG80211=m
 CONFIG_MAC80211=m
 CONFIG_MAC80211_MESH=y
 CONFIG_RFKILL=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_CONNECTOR=m
index 8dc5d96..5599cde 100644 (file)
@@ -39,7 +39,6 @@ CONFIG_IP_PIMSM_V1=y
 CONFIG_IP_PIMSM_V2=y
 CONFIG_SYN_COOKIES=y
 # CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_VIRTIO_BLK=y
index 0649b8f..a39426e 100644 (file)
@@ -42,7 +42,6 @@ CONFIG_INET=y
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
 # CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 # CONFIG_FW_LOADER is not set
 # CONFIG_ALLOW_DEV_COREDUMP is not set
index 2f08d07..24e0718 100644 (file)
@@ -214,7 +214,6 @@ CONFIG_IR_IMG_RC6=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_FB=y
 CONFIG_FB_MODE_HELPERS=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_SOUND=y
index aa0b169..738ba3b 100644 (file)
@@ -25,7 +25,6 @@ CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_INET_AH=y
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
index 1a0677d..208da8a 100644 (file)
@@ -41,7 +41,6 @@ CONFIG_TCP_CONG_ADVANCED=y
 CONFIG_TCP_CONG_WESTWOOD=y
 # CONFIG_TCP_CONG_HTCP is not set
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_RAW_NAND=y
@@ -77,7 +76,6 @@ CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_FB=y
 CONFIG_FB_JZ4740=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 # CONFIG_BACKLIGHT_CLASS_DEVICE is not set
 # CONFIG_VGA_CONSOLE is not set
index 864c70f..5b94718 100644 (file)
@@ -104,7 +104,6 @@ CONFIG_NET_ACT_MIRRED=m
 CONFIG_NET_ACT_IPT=m
 CONFIG_NET_ACT_PEDIT=m
 CONFIG_HAMRADIO=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_BLOCK2MTD=y
index 0392e38..110948b 100644 (file)
@@ -69,7 +69,6 @@ CONFIG_BRIDGE=y
 CONFIG_VLAN_8021Q=y
 CONFIG_NET_SCHED=y
 CONFIG_HAMRADIO=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
index ad89816..6883ea4 100644 (file)
@@ -43,7 +43,6 @@ CONFIG_NETWORK_SECMARK=y
 CONFIG_CFG80211=m
 CONFIG_MAC80211=m
 CONFIG_RFKILL=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_FW_LOADER=m
 CONFIG_CONNECTOR=m
 CONFIG_BLK_DEV_RAM=y
index f0a11a7..6547f84 100644 (file)
@@ -28,7 +28,6 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_IPV6 is not set
 CONFIG_NETWORK_SECMARK=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_RAM=y
index 025e456..7e099f7 100644 (file)
@@ -26,7 +26,6 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_IPV6 is not set
 CONFIG_NETWORK_SECMARK=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_RAM=y
index 6849024..0d881dd 100644 (file)
@@ -30,7 +30,6 @@ CONFIG_TCP_CONG_BIC=y
 CONFIG_TCP_CONG_CUBIC=m
 # CONFIG_IPV6 is not set
 CONFIG_NETWORK_SECMARK=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_RAM=y
index ded3dce..523b944 100644 (file)
@@ -42,7 +42,6 @@ CONFIG_INET=y
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
 # CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 # CONFIG_FW_LOADER is not set
 # CONFIG_ALLOW_DEV_COREDUMP is not set
index 203db83..49b5ea6 100644 (file)
@@ -71,7 +71,6 @@ CONFIG_BRIDGE=y
 CONFIG_VLAN_8021Q=y
 CONFIG_NET_SCHED=y
 CONFIG_HAMRADIO=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
index 6ad7d3c..290369f 100644 (file)
@@ -9,6 +9,8 @@
 #ifndef _ASM_CPU_H
 #define _ASM_CPU_H
 
+#include <linux/bits.h>
+
 /*
    As of the MIPS32 and MIPS64 specs from MTI, the PRId register (CP0
    register 15, select 0) is defined in this (backwards compatible) way:
@@ -353,76 +355,69 @@ enum cpu_type_enum {
        MIPS_CPU_ISA_M64R6)
 
 /*
- * Private version of BIT_ULL() to escape include file recursion hell.
- * We soon will have to switch to another mechanism that will work with
- * more than 64 bits anyway.
- */
-#define MBIT_ULL(bit)          (1ULL << (bit))
-
-/*
  * CPU Option encodings
  */
-#define MIPS_CPU_TLB           MBIT_ULL( 0)    /* CPU has TLB */
-#define MIPS_CPU_4KEX          MBIT_ULL( 1)    /* "R4K" exception model */
-#define MIPS_CPU_3K_CACHE      MBIT_ULL( 2)    /* R3000-style caches */
-#define MIPS_CPU_4K_CACHE      MBIT_ULL( 3)    /* R4000-style caches */
-#define MIPS_CPU_TX39_CACHE    MBIT_ULL( 4)    /* TX3900-style caches */
-#define MIPS_CPU_FPU           MBIT_ULL( 5)    /* CPU has FPU */
-#define MIPS_CPU_32FPR         MBIT_ULL( 6)    /* 32 dbl. prec. FP registers */
-#define MIPS_CPU_COUNTER       MBIT_ULL( 7)    /* Cycle count/compare */
-#define MIPS_CPU_WATCH         MBIT_ULL( 8)    /* watchpoint registers */
-#define MIPS_CPU_DIVEC         MBIT_ULL( 9)    /* dedicated interrupt vector */
-#define MIPS_CPU_VCE           MBIT_ULL(10)    /* virt. coherence conflict possible */
-#define MIPS_CPU_CACHE_CDEX_P  MBIT_ULL(11)    /* Create_Dirty_Exclusive CACHE op */
-#define MIPS_CPU_CACHE_CDEX_S  MBIT_ULL(12)    /* ... same for seconary cache ... */
-#define MIPS_CPU_MCHECK                MBIT_ULL(13)    /* Machine check exception */
-#define MIPS_CPU_EJTAG         MBIT_ULL(14)    /* EJTAG exception */
-#define MIPS_CPU_NOFPUEX       MBIT_ULL(15)    /* no FPU exception */
-#define MIPS_CPU_LLSC          MBIT_ULL(16)    /* CPU has ll/sc instructions */
-#define MIPS_CPU_INCLUSIVE_CACHES      MBIT_ULL(17)    /* P-cache subset enforced */
-#define MIPS_CPU_PREFETCH      MBIT_ULL(18)    /* CPU has usable prefetch */
-#define MIPS_CPU_VINT          MBIT_ULL(19)    /* CPU supports MIPSR2 vectored interrupts */
-#define MIPS_CPU_VEIC          MBIT_ULL(20)    /* CPU supports MIPSR2 external interrupt controller mode */
-#define MIPS_CPU_ULRI          MBIT_ULL(21)    /* CPU has ULRI feature */
-#define MIPS_CPU_PCI           MBIT_ULL(22)    /* CPU has Perf Ctr Int indicator */
-#define MIPS_CPU_RIXI          MBIT_ULL(23)    /* CPU has TLB Read/eXec Inhibit */
-#define MIPS_CPU_MICROMIPS     MBIT_ULL(24)    /* CPU has microMIPS capability */
-#define MIPS_CPU_TLBINV                MBIT_ULL(25)    /* CPU supports TLBINV/F */
-#define MIPS_CPU_SEGMENTS      MBIT_ULL(26)    /* CPU supports Segmentation Control registers */
-#define MIPS_CPU_EVA           MBIT_ULL(27)    /* CPU supports Enhanced Virtual Addressing */
-#define MIPS_CPU_HTW           MBIT_ULL(28)    /* CPU support Hardware Page Table Walker */
-#define MIPS_CPU_RIXIEX                MBIT_ULL(29)    /* CPU has unique exception codes for {Read, Execute}-Inhibit exceptions */
-#define MIPS_CPU_MAAR          MBIT_ULL(30)    /* MAAR(I) registers are present */
-#define MIPS_CPU_FRE           MBIT_ULL(31)    /* FRE & UFE bits implemented */
-#define MIPS_CPU_RW_LLB                MBIT_ULL(32)    /* LLADDR/LLB writes are allowed */
-#define MIPS_CPU_LPA           MBIT_ULL(33)    /* CPU supports Large Physical Addressing */
-#define MIPS_CPU_CDMM          MBIT_ULL(34)    /* CPU has Common Device Memory Map */
-#define MIPS_CPU_BP_GHIST      MBIT_ULL(35)    /* R12K+ Branch Prediction Global History */
-#define MIPS_CPU_SP            MBIT_ULL(36)    /* Small (1KB) page support */
-#define MIPS_CPU_FTLB          MBIT_ULL(37)    /* CPU has Fixed-page-size TLB */
-#define MIPS_CPU_NAN_LEGACY    MBIT_ULL(38)    /* Legacy NaN implemented */
-#define MIPS_CPU_NAN_2008      MBIT_ULL(39)    /* 2008 NaN implemented */
-#define MIPS_CPU_VP            MBIT_ULL(40)    /* MIPSr6 Virtual Processors (multi-threading) */
-#define MIPS_CPU_LDPTE         MBIT_ULL(41)    /* CPU has ldpte/lddir instructions */
-#define MIPS_CPU_MVH           MBIT_ULL(42)    /* CPU supports MFHC0/MTHC0 */
-#define MIPS_CPU_EBASE_WG      MBIT_ULL(43)    /* CPU has EBase.WG */
-#define MIPS_CPU_BADINSTR      MBIT_ULL(44)    /* CPU has BadInstr register */
-#define MIPS_CPU_BADINSTRP     MBIT_ULL(45)    /* CPU has BadInstrP register */
-#define MIPS_CPU_CTXTC         MBIT_ULL(46)    /* CPU has [X]ConfigContext registers */
-#define MIPS_CPU_PERF          MBIT_ULL(47)    /* CPU has MIPS performance counters */
-#define MIPS_CPU_GUESTCTL0EXT  MBIT_ULL(48)    /* CPU has VZ GuestCtl0Ext register */
-#define MIPS_CPU_GUESTCTL1     MBIT_ULL(49)    /* CPU has VZ GuestCtl1 register */
-#define MIPS_CPU_GUESTCTL2     MBIT_ULL(50)    /* CPU has VZ GuestCtl2 register */
-#define MIPS_CPU_GUESTID       MBIT_ULL(51)    /* CPU uses VZ ASE GuestID feature */
-#define MIPS_CPU_DRG           MBIT_ULL(52)    /* CPU has VZ Direct Root to Guest (DRG) */
-#define MIPS_CPU_UFR           MBIT_ULL(53)    /* CPU supports User mode FR switching */
+#define MIPS_CPU_TLB           BIT_ULL( 0)     /* CPU has TLB */
+#define MIPS_CPU_4KEX          BIT_ULL( 1)     /* "R4K" exception model */
+#define MIPS_CPU_3K_CACHE      BIT_ULL( 2)     /* R3000-style caches */
+#define MIPS_CPU_4K_CACHE      BIT_ULL( 3)     /* R4000-style caches */
+#define MIPS_CPU_TX39_CACHE    BIT_ULL( 4)     /* TX3900-style caches */
+#define MIPS_CPU_FPU           BIT_ULL( 5)     /* CPU has FPU */
+#define MIPS_CPU_32FPR         BIT_ULL( 6)     /* 32 dbl. prec. FP registers */
+#define MIPS_CPU_COUNTER       BIT_ULL( 7)     /* Cycle count/compare */
+#define MIPS_CPU_WATCH         BIT_ULL( 8)     /* watchpoint registers */
+#define MIPS_CPU_DIVEC         BIT_ULL( 9)     /* dedicated interrupt vector */
+#define MIPS_CPU_VCE           BIT_ULL(10)     /* virt. coherence conflict possible */
+#define MIPS_CPU_CACHE_CDEX_P  BIT_ULL(11)     /* Create_Dirty_Exclusive CACHE op */
+#define MIPS_CPU_CACHE_CDEX_S  BIT_ULL(12)     /* ... same for seconary cache ... */
+#define MIPS_CPU_MCHECK                BIT_ULL(13)     /* Machine check exception */
+#define MIPS_CPU_EJTAG         BIT_ULL(14)     /* EJTAG exception */
+#define MIPS_CPU_NOFPUEX       BIT_ULL(15)     /* no FPU exception */
+#define MIPS_CPU_LLSC          BIT_ULL(16)     /* CPU has ll/sc instructions */
+#define MIPS_CPU_INCLUSIVE_CACHES BIT_ULL(17)  /* P-cache subset enforced */
+#define MIPS_CPU_PREFETCH      BIT_ULL(18)     /* CPU has usable prefetch */
+#define MIPS_CPU_VINT          BIT_ULL(19)     /* CPU supports MIPSR2 vectored interrupts */
+#define MIPS_CPU_VEIC          BIT_ULL(20)     /* CPU supports MIPSR2 external interrupt controller mode */
+#define MIPS_CPU_ULRI          BIT_ULL(21)     /* CPU has ULRI feature */
+#define MIPS_CPU_PCI           BIT_ULL(22)     /* CPU has Perf Ctr Int indicator */
+#define MIPS_CPU_RIXI          BIT_ULL(23)     /* CPU has TLB Read/eXec Inhibit */
+#define MIPS_CPU_MICROMIPS     BIT_ULL(24)     /* CPU has microMIPS capability */
+#define MIPS_CPU_TLBINV                BIT_ULL(25)     /* CPU supports TLBINV/F */
+#define MIPS_CPU_SEGMENTS      BIT_ULL(26)     /* CPU supports Segmentation Control registers */
+#define MIPS_CPU_EVA           BIT_ULL(27)     /* CPU supports Enhanced Virtual Addressing */
+#define MIPS_CPU_HTW           BIT_ULL(28)     /* CPU support Hardware Page Table Walker */
+#define MIPS_CPU_RIXIEX                BIT_ULL(29)     /* CPU has unique exception codes for {Read, Execute}-Inhibit exceptions */
+#define MIPS_CPU_MAAR          BIT_ULL(30)     /* MAAR(I) registers are present */
+#define MIPS_CPU_FRE           BIT_ULL(31)     /* FRE & UFE bits implemented */
+#define MIPS_CPU_RW_LLB                BIT_ULL(32)     /* LLADDR/LLB writes are allowed */
+#define MIPS_CPU_LPA           BIT_ULL(33)     /* CPU supports Large Physical Addressing */
+#define MIPS_CPU_CDMM          BIT_ULL(34)     /* CPU has Common Device Memory Map */
+#define MIPS_CPU_BP_GHIST      BIT_ULL(35)     /* R12K+ Branch Prediction Global History */
+#define MIPS_CPU_SP            BIT_ULL(36)     /* Small (1KB) page support */
+#define MIPS_CPU_FTLB          BIT_ULL(37)     /* CPU has Fixed-page-size TLB */
+#define MIPS_CPU_NAN_LEGACY    BIT_ULL(38)     /* Legacy NaN implemented */
+#define MIPS_CPU_NAN_2008      BIT_ULL(39)     /* 2008 NaN implemented */
+#define MIPS_CPU_VP            BIT_ULL(40)     /* MIPSr6 Virtual Processors (multi-threading) */
+#define MIPS_CPU_LDPTE         BIT_ULL(41)     /* CPU has ldpte/lddir instructions */
+#define MIPS_CPU_MVH           BIT_ULL(42)     /* CPU supports MFHC0/MTHC0 */
+#define MIPS_CPU_EBASE_WG      BIT_ULL(43)     /* CPU has EBase.WG */
+#define MIPS_CPU_BADINSTR      BIT_ULL(44)     /* CPU has BadInstr register */
+#define MIPS_CPU_BADINSTRP     BIT_ULL(45)     /* CPU has BadInstrP register */
+#define MIPS_CPU_CTXTC         BIT_ULL(46)     /* CPU has [X]ConfigContext registers */
+#define MIPS_CPU_PERF          BIT_ULL(47)     /* CPU has MIPS performance counters */
+#define MIPS_CPU_GUESTCTL0EXT  BIT_ULL(48)     /* CPU has VZ GuestCtl0Ext register */
+#define MIPS_CPU_GUESTCTL1     BIT_ULL(49)     /* CPU has VZ GuestCtl1 register */
+#define MIPS_CPU_GUESTCTL2     BIT_ULL(50)     /* CPU has VZ GuestCtl2 register */
+#define MIPS_CPU_GUESTID       BIT_ULL(51)     /* CPU uses VZ ASE GuestID feature */
+#define MIPS_CPU_DRG           BIT_ULL(52)     /* CPU has VZ Direct Root to Guest (DRG) */
+#define MIPS_CPU_UFR           BIT_ULL(53)     /* CPU supports User mode FR switching */
 #define MIPS_CPU_SHARED_FTLB_RAM \
-                               MBIT_ULL(54)    /* CPU shares FTLB RAM with another */
+                               BIT_ULL(54)     /* CPU shares FTLB RAM with another */
 #define MIPS_CPU_SHARED_FTLB_ENTRIES \
-                               MBIT_ULL(55)    /* CPU shares FTLB entries with another */
+                               BIT_ULL(55)     /* CPU shares FTLB entries with another */
 #define MIPS_CPU_MT_PER_TC_PERF_COUNTERS \
-                               MBIT_ULL(56)    /* CPU has perf counters implemented per TC (MIPSMT ASE) */
-#define MIPS_CPU_MMID          MBIT_ULL(57)    /* CPU supports MemoryMapIDs */
+                               BIT_ULL(56)     /* CPU has perf counters implemented per TC (MIPSMT ASE) */
+#define MIPS_CPU_MMID          BIT_ULL(57)     /* CPU supports MemoryMapIDs */
 
 /*
  * CPU ASE encodings
index 29997e4..97a2806 100644 (file)
@@ -149,8 +149,6 @@ static inline void *isa_bus_to_virt(unsigned long address)
        return phys_to_virt(address);
 }
 
-#define isa_page_to_bus page_to_phys
-
 /*
  * However PCI ones are not necessarily 1:1 and therefore these interfaces
  * are forbidden in portable PCI drivers.
@@ -462,7 +460,12 @@ __BUILD_MEMORY_PFX(, bwlq, type, 0)
 BUILDIO_MEM(b, u8)
 BUILDIO_MEM(w, u16)
 BUILDIO_MEM(l, u32)
+#ifdef CONFIG_64BIT
 BUILDIO_MEM(q, u64)
+#else
+__BUILD_MEMORY_PFX(__raw_, q, u64, 0)
+__BUILD_MEMORY_PFX(__mem_, q, u64, 0)
+#endif
 
 #define __BUILD_IOPORT_PFX(bus, bwlq, type)                            \
        __BUILD_IOPORT_SINGLE(bus, bwlq, type, 1, 0,)                   \
@@ -488,12 +491,16 @@ __BUILDIO(q, u64)
 #define readb_relaxed                  __relaxed_readb
 #define readw_relaxed                  __relaxed_readw
 #define readl_relaxed                  __relaxed_readl
+#ifdef CONFIG_64BIT
 #define readq_relaxed                  __relaxed_readq
+#endif
 
 #define writeb_relaxed                 __relaxed_writeb
 #define writew_relaxed                 __relaxed_writew
 #define writel_relaxed                 __relaxed_writel
+#ifdef CONFIG_64BIT
 #define writeq_relaxed                 __relaxed_writeq
+#endif
 
 #define readb_be(addr)                                                 \
        __raw_readb((__force unsigned *)(addr))
@@ -516,8 +523,10 @@ __BUILDIO(q, u64)
 /*
  * Some code tests for these symbols
  */
+#ifdef CONFIG_64BIT
 #define readq                          readq
 #define writeq                         writeq
+#endif
 
 #define __BUILD_MEMORY_STRING(bwlq, type)                              \
                                                                        \
index 3cf8e4d..68b1e5d 100644 (file)
@@ -41,6 +41,7 @@ do {                                                                  \
 #define kretprobe_blacklist_size 0
 
 void arch_remove_kprobe(struct kprobe *p);
+int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
 
 /* Architecture specific copy of original instruction*/
 struct arch_specific_insn {
diff --git a/arch/mips/include/asm/mach-jz4740/clock.h b/arch/mips/include/asm/mach-jz4740/clock.h
deleted file mode 100644 (file)
index 600d505..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
- */
-
-#ifndef __ASM_JZ4740_CLOCK_H__
-#define __ASM_JZ4740_CLOCK_H__
-
-enum jz4740_wait_mode {
-       JZ4740_WAIT_MODE_IDLE,
-       JZ4740_WAIT_MODE_SLEEP,
-};
-
-void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode);
-
-void jz4740_clock_suspend(void);
-void jz4740_clock_resume(void);
-
-void jz4740_clock_udc_enable_auto_suspend(void);
-void jz4740_clock_udc_disable_auto_suspend(void);
-
-#endif
index e54d4e1..0483093 100644 (file)
@@ -1,6 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- *
  *  Copyright (C) 2012 John Crispin <john@phrozen.org>
  */
 
index acf80ae..83bb439 100644 (file)
@@ -89,6 +89,12 @@ static inline unsigned long mips_get_syscall_arg(unsigned long *arg,
        unreachable();
 }
 
+static inline long syscall_get_error(struct task_struct *task,
+                                    struct pt_regs *regs)
+{
+       return regs->regs[7] ? -regs->regs[2] : 0;
+}
+
 static inline long syscall_get_return_value(struct task_struct *task,
                                            struct pt_regs *regs)
 {
index 071e9d9..4a7a80c 100644 (file)
@@ -37,8 +37,6 @@
 
 #include <asm/mach-jz4740/platform.h>
 
-#include "clock.h"
-
 /* GPIOs */
 #define QI_LB60_GPIO_KEYOUT(x)         (JZ_GPIO_PORTC(10) + (x))
 #define QI_LB60_GPIO_KEYIN(x)          (JZ_GPIO_PORTD(18) + (x))
@@ -466,27 +464,27 @@ static unsigned long pin_cfg_bias_disable[] = {
 static struct pinctrl_map pin_map[] __initdata = {
        /* NAND pin configuration */
        PIN_MAP_MUX_GROUP_DEFAULT("jz4740-nand",
-                       "10010000.jz4740-pinctrl", "nand", "nand-cs1"),
+                       "10010000.pin-controller", "nand-cs1", "nand"),
 
        /* fbdev pin configuration */
        PIN_MAP_MUX_GROUP("jz4740-fb", PINCTRL_STATE_DEFAULT,
-                       "10010000.jz4740-pinctrl", "lcd", "lcd-8bit"),
+                       "10010000.pin-controller", "lcd-8bit", "lcd"),
        PIN_MAP_MUX_GROUP("jz4740-fb", PINCTRL_STATE_SLEEP,
-                       "10010000.jz4740-pinctrl", "lcd", "lcd-no-pins"),
+                       "10010000.pin-controller", "lcd-no-pins", "lcd"),
 
        /* MMC pin configuration */
        PIN_MAP_MUX_GROUP_DEFAULT("jz4740-mmc.0",
-                       "10010000.jz4740-pinctrl", "mmc", "mmc-1bit"),
+                       "10010000.pin-controller", "mmc-1bit", "mmc"),
        PIN_MAP_MUX_GROUP_DEFAULT("jz4740-mmc.0",
-                       "10010000.jz4740-pinctrl", "mmc", "mmc-4bit"),
+                       "10010000.pin-controller", "mmc-4bit", "mmc"),
        PIN_MAP_CONFIGS_PIN_DEFAULT("jz4740-mmc.0",
-                       "10010000.jz4740-pinctrl", "PD0", pin_cfg_bias_disable),
+                       "10010000.pin-controller", "PD0", pin_cfg_bias_disable),
        PIN_MAP_CONFIGS_PIN_DEFAULT("jz4740-mmc.0",
-                       "10010000.jz4740-pinctrl", "PD2", pin_cfg_bias_disable),
+                       "10010000.pin-controller", "PD2", pin_cfg_bias_disable),
 
        /* PWM pin configuration */
        PIN_MAP_MUX_GROUP_DEFAULT("jz4740-pwm",
-                       "10010000.jz4740-pinctrl", "pwm4", "pwm4"),
+                       "10010000.pin-controller", "pwm4", "pwm4"),
 };
 
 
index 4b89abb..c74c99f 100644 (file)
@@ -21,8 +21,6 @@
 #include <linux/serial_core.h>
 #include <linux/serial_8250.h>
 
-#include "clock.h"
-
 /* USB Device Controller */
 struct platform_device jz4740_udc_xceiv_device = {
        .name = "usb_phy_generic",
index bbdd2b8..f9b551f 100644 (file)
@@ -9,21 +9,13 @@
 #include <linux/delay.h>
 #include <linux/suspend.h>
 
-#include <asm/mach-jz4740/clock.h>
-
 static int jz4740_pm_enter(suspend_state_t state)
 {
-       jz4740_clock_suspend();
-
-       jz4740_clock_set_wait_mode(JZ4740_WAIT_MODE_SLEEP);
-
        __asm__(".set\tmips3\n\t"
                "wait\n\t"
                ".set\tmips0");
 
-       jz4740_clock_set_wait_mode(JZ4740_WAIT_MODE_IDLE);
 
-       jz4740_clock_resume();
 
        return 0;
 }
index a3260c7..cb768e5 100644 (file)
 #include <linux/clockchips.h>
 #include <linux/sched_clock.h>
 
-#include <asm/mach-jz4740/clock.h>
 #include <asm/mach-jz4740/irq.h>
 #include <asm/mach-jz4740/timer.h>
 #include <asm/time.h>
 
-#include "clock.h"
-
 #define TIMER_CLOCKEVENT 0
 #define TIMER_CLOCKSOURCE 1
 
index 4b5e1f2..2625232 100644 (file)
@@ -333,20 +333,21 @@ void prepare_ftrace_return(unsigned long *parent_ra_addr, unsigned long self_ra,
                return;
 
        /*
-        * "parent_ra_addr" is the stack address saved the return address of
-        * the caller of _mcount.
+        * "parent_ra_addr" is the stack address where the return address of
+        * the caller of _mcount is saved.
         *
-        * if the gcc < 4.5, a leaf function does not save the return address
-        * in the stack address, so, we "emulate" one in _mcount's stack space,
-        * and hijack it directly, but for a non-leaf function, it save the
-        * return address to the its own stack space, we can not hijack it
-        * directly, but need to find the real stack address,
-        * ftrace_get_parent_addr() does it!
+        * If gcc < 4.5, a leaf function does not save the return address
+        * in the stack address, so we "emulate" one in _mcount's stack space,
+        * and hijack it directly.
+        * For a non-leaf function, it does save the return address to its own
+        * stack space, so we can not hijack it directly, but need to find the
+        * real stack address, which is done by ftrace_get_parent_addr().
         *
-        * if gcc>= 4.5, with the new -mmcount-ra-address option, for a
+        * If gcc >= 4.5, with the new -mmcount-ra-address option, for a
         * non-leaf function, the location of the return address will be saved
-        * to $12 for us, and for a leaf function, only put a zero into $12. we
-        * do it in ftrace_graph_caller of mcount.S.
+        * to $12 for us.
+        * For a leaf function, it just puts a zero into $12, so we handle
+        * it in ftrace_graph_caller() of mcount.S.
         */
 
        /* old_parent_ra = *parent_ra_addr; */
index 81ba1d3..6cfae24 100644 (file)
@@ -398,7 +398,7 @@ out:
        return 1;
 }
 
-static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
 {
        struct kprobe *cur = kprobe_running();
        struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
index e0ebaa0..a3e2da8 100644 (file)
@@ -790,15 +790,19 @@ static void reset_counters(void *arg)
        case 4:
                mipsxx_pmu_write_control(3, 0);
                mipspmu.write_counter(3, 0);
+               /* fall through */
        case 3:
                mipsxx_pmu_write_control(2, 0);
                mipspmu.write_counter(2, 0);
+               /* fall through */
        case 2:
                mipsxx_pmu_write_control(1, 0);
                mipspmu.write_counter(1, 0);
+               /* fall through */
        case 1:
                mipsxx_pmu_write_control(0, 0);
                mipspmu.write_counter(0, 0);
+               /* fall through */
        }
 }
 
@@ -1380,7 +1384,7 @@ static int mipsxx_pmu_handle_shared_irq(void)
        struct perf_sample_data data;
        unsigned int counters = mipspmu.num_counters;
        u64 counter;
-       int handled = IRQ_NONE;
+       int n, handled = IRQ_NONE;
        struct pt_regs *regs;
 
        if (cpu_has_perf_cntr_intr_bit && !(read_c0_cause() & CAUSEF_PCI))
@@ -1401,20 +1405,16 @@ static int mipsxx_pmu_handle_shared_irq(void)
 
        perf_sample_data_init(&data, 0, 0);
 
-       switch (counters) {
-#define HANDLE_COUNTER(n)                                              \
-       case n + 1:                                                     \
-               if (test_bit(n, cpuc->used_mask)) {                     \
-                       counter = mipspmu.read_counter(n);              \
-                       if (counter & mipspmu.overflow) {               \
-                               handle_associated_event(cpuc, n, &data, regs); \
-                               handled = IRQ_HANDLED;                  \
-                       }                                               \
-               }
-       HANDLE_COUNTER(3)
-       HANDLE_COUNTER(2)
-       HANDLE_COUNTER(1)
-       HANDLE_COUNTER(0)
+       for (n = counters - 1; n >= 0; n--) {
+               if (!test_bit(n, cpuc->used_mask))
+                       continue;
+
+               counter = mipspmu.read_counter(n);
+               if (!(counter & mipspmu.overflow))
+                       continue;
+
+               handle_associated_event(cpuc, n, &data, regs);
+               handled = IRQ_HANDLED;
        }
 
 #ifdef CONFIG_MIPS_PERF_SHARED_TC_COUNTERS
index 97035e1..c9c879e 100644 (file)
 432    n32     fsmount                         sys_fsmount
 433    n32     fspick                          sys_fspick
 434    n32     pidfd_open                      sys_pidfd_open
+# 435 reserved for clone3
index d729272..bbce915 100644 (file)
 432    n64     fsmount                         sys_fsmount
 433    n64     fspick                          sys_fspick
 434    n64     pidfd_open                      sys_pidfd_open
+# 435 reserved for clone3
index dba084c..9653591 100644 (file)
 432    o32     fsmount                         sys_fsmount
 433    o32     fspick                          sys_fspick
 434    o32     pidfd_open                      sys_pidfd_open
+# 435 reserved for clone3
index cfd87e6..115b417 100644 (file)
 #include <irq.h>
 
 /* register definitions - internal irqs */
-#define LTQ_ICU_IM0_ISR                0x0000
-#define LTQ_ICU_IM0_IER                0x0008
-#define LTQ_ICU_IM0_IOSR       0x0010
-#define LTQ_ICU_IM0_IRSR       0x0018
-#define LTQ_ICU_IM0_IMR                0x0020
-#define LTQ_ICU_IM1_ISR                0x0028
-#define LTQ_ICU_OFFSET         (LTQ_ICU_IM1_ISR - LTQ_ICU_IM0_ISR)
+#define LTQ_ICU_ISR            0x0000
+#define LTQ_ICU_IER            0x0008
+#define LTQ_ICU_IOSR           0x0010
+#define LTQ_ICU_IRSR           0x0018
+#define LTQ_ICU_IMR            0x0020
+
+#define LTQ_ICU_IM_SIZE                0x28
 
 /* register definitions - external irqs */
 #define LTQ_EIU_EXIN_C         0x0000
  */
 #define LTQ_ICU_EBU_IRQ                22
 
-#define ltq_icu_w32(m, x, y)   ltq_w32((x), ltq_icu_membase[m] + (y))
-#define ltq_icu_r32(m, x)      ltq_r32(ltq_icu_membase[m] + (x))
+#define ltq_icu_w32(vpe, m, x, y)      \
+       ltq_w32((x), ltq_icu_membase[vpe] + m*LTQ_ICU_IM_SIZE + (y))
+
+#define ltq_icu_r32(vpe, m, x)         \
+       ltq_r32(ltq_icu_membase[vpe] + m*LTQ_ICU_IM_SIZE + (x))
 
 #define ltq_eiu_w32(x, y)      ltq_w32((x), ltq_eiu_membase + (y))
 #define ltq_eiu_r32(x)         ltq_r32(ltq_eiu_membase + (x))
 
-/* our 2 ipi interrupts for VSMP */
-#define MIPS_CPU_IPI_RESCHED_IRQ       0
-#define MIPS_CPU_IPI_CALL_IRQ          1
-
 /* we have a cascade of 8 irqs */
 #define MIPS_CPU_IRQ_CASCADE           8
 
 static int exin_avail;
 static u32 ltq_eiu_irq[MAX_EIU];
-static void __iomem *ltq_icu_membase[MAX_IM];
+static void __iomem *ltq_icu_membase[NR_CPUS];
 static void __iomem *ltq_eiu_membase;
 static struct irq_domain *ltq_domain;
+static DEFINE_SPINLOCK(ltq_eiu_lock);
+static DEFINE_RAW_SPINLOCK(ltq_icu_lock);
 static int ltq_perfcount_irq;
 
 int ltq_eiu_get_irq(int exin)
@@ -75,49 +76,84 @@ int ltq_eiu_get_irq(int exin)
 
 void ltq_disable_irq(struct irq_data *d)
 {
-       u32 ier = LTQ_ICU_IM0_IER;
-       int offset = d->hwirq - MIPS_CPU_IRQ_CASCADE;
-       int im = offset / INT_NUM_IM_OFFSET;
+       unsigned long offset = d->hwirq - MIPS_CPU_IRQ_CASCADE;
+       unsigned long im = offset / INT_NUM_IM_OFFSET;
+       unsigned long flags;
+       int vpe;
 
        offset %= INT_NUM_IM_OFFSET;
-       ltq_icu_w32(im, ltq_icu_r32(im, ier) & ~BIT(offset), ier);
+
+       raw_spin_lock_irqsave(&ltq_icu_lock, flags);
+       for_each_present_cpu(vpe) {
+               ltq_icu_w32(vpe, im,
+                           ltq_icu_r32(vpe, im, LTQ_ICU_IER) & ~BIT(offset),
+                           LTQ_ICU_IER);
+       }
+       raw_spin_unlock_irqrestore(&ltq_icu_lock, flags);
 }
 
 void ltq_mask_and_ack_irq(struct irq_data *d)
 {
-       u32 ier = LTQ_ICU_IM0_IER;
-       u32 isr = LTQ_ICU_IM0_ISR;
-       int offset = d->hwirq - MIPS_CPU_IRQ_CASCADE;
-       int im = offset / INT_NUM_IM_OFFSET;
+       unsigned long offset = d->hwirq - MIPS_CPU_IRQ_CASCADE;
+       unsigned long im = offset / INT_NUM_IM_OFFSET;
+       unsigned long flags;
+       int vpe;
 
        offset %= INT_NUM_IM_OFFSET;
-       ltq_icu_w32(im, ltq_icu_r32(im, ier) & ~BIT(offset), ier);
-       ltq_icu_w32(im, BIT(offset), isr);
+
+       raw_spin_lock_irqsave(&ltq_icu_lock, flags);
+       for_each_present_cpu(vpe) {
+               ltq_icu_w32(vpe, im,
+                           ltq_icu_r32(vpe, im, LTQ_ICU_IER) & ~BIT(offset),
+                           LTQ_ICU_IER);
+               ltq_icu_w32(vpe, im, BIT(offset), LTQ_ICU_ISR);
+       }
+       raw_spin_unlock_irqrestore(&ltq_icu_lock, flags);
 }
 
 static void ltq_ack_irq(struct irq_data *d)
 {
-       u32 isr = LTQ_ICU_IM0_ISR;
-       int offset = d->hwirq - MIPS_CPU_IRQ_CASCADE;
-       int im = offset / INT_NUM_IM_OFFSET;
+       unsigned long offset = d->hwirq - MIPS_CPU_IRQ_CASCADE;
+       unsigned long im = offset / INT_NUM_IM_OFFSET;
+       unsigned long flags;
+       int vpe;
 
        offset %= INT_NUM_IM_OFFSET;
-       ltq_icu_w32(im, BIT(offset), isr);
+
+       raw_spin_lock_irqsave(&ltq_icu_lock, flags);
+       for_each_present_cpu(vpe) {
+               ltq_icu_w32(vpe, im, BIT(offset), LTQ_ICU_ISR);
+       }
+       raw_spin_unlock_irqrestore(&ltq_icu_lock, flags);
 }
 
 void ltq_enable_irq(struct irq_data *d)
 {
-       u32 ier = LTQ_ICU_IM0_IER;
-       int offset = d->hwirq - MIPS_CPU_IRQ_CASCADE;
-       int im = offset / INT_NUM_IM_OFFSET;
+       unsigned long offset = d->hwirq - MIPS_CPU_IRQ_CASCADE;
+       unsigned long im = offset / INT_NUM_IM_OFFSET;
+       unsigned long flags;
+       int vpe;
 
        offset %= INT_NUM_IM_OFFSET;
-       ltq_icu_w32(im, ltq_icu_r32(im, ier) | BIT(offset), ier);
+
+       vpe = cpumask_first(irq_data_get_effective_affinity_mask(d));
+
+       /* This shouldn't be even possible, maybe during CPU hotplug spam */
+       if (unlikely(vpe >= nr_cpu_ids))
+               vpe = smp_processor_id();
+
+       raw_spin_lock_irqsave(&ltq_icu_lock, flags);
+
+       ltq_icu_w32(vpe, im, ltq_icu_r32(vpe, im, LTQ_ICU_IER) | BIT(offset),
+                   LTQ_ICU_IER);
+
+       raw_spin_unlock_irqrestore(&ltq_icu_lock, flags);
 }
 
 static int ltq_eiu_settype(struct irq_data *d, unsigned int type)
 {
        int i;
+       unsigned long flags;
 
        for (i = 0; i < exin_avail; i++) {
                if (d->hwirq == ltq_eiu_irq[i]) {
@@ -154,8 +190,11 @@ static int ltq_eiu_settype(struct irq_data *d, unsigned int type)
                        if (edge)
                                irq_set_handler(d->hwirq, handle_edge_irq);
 
-                       ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) |
-                               (val << (i * 4)), LTQ_EIU_EXIN_C);
+                       spin_lock_irqsave(&ltq_eiu_lock, flags);
+                       ltq_eiu_w32((ltq_eiu_r32(LTQ_EIU_EXIN_C) &
+                                   (~(7 << (i * 4)))) | (val << (i * 4)),
+                                   LTQ_EIU_EXIN_C);
+                       spin_unlock_irqrestore(&ltq_eiu_lock, flags);
                }
        }
 
@@ -199,6 +238,21 @@ static void ltq_shutdown_eiu_irq(struct irq_data *d)
        }
 }
 
+#if defined(CONFIG_SMP)
+static int ltq_icu_irq_set_affinity(struct irq_data *d,
+                                   const struct cpumask *cpumask, bool force)
+{
+       struct cpumask tmask;
+
+       if (!cpumask_and(&tmask, cpumask, cpu_online_mask))
+               return -EINVAL;
+
+       irq_data_update_effective_affinity(d, &tmask);
+
+       return IRQ_SET_MASK_OK;
+}
+#endif
+
 static struct irq_chip ltq_irq_type = {
        .name = "icu",
        .irq_enable = ltq_enable_irq,
@@ -207,6 +261,9 @@ static struct irq_chip ltq_irq_type = {
        .irq_ack = ltq_ack_irq,
        .irq_mask = ltq_disable_irq,
        .irq_mask_ack = ltq_mask_and_ack_irq,
+#if defined(CONFIG_SMP)
+       .irq_set_affinity = ltq_icu_irq_set_affinity,
+#endif
 };
 
 static struct irq_chip ltq_eiu_type = {
@@ -220,15 +277,19 @@ static struct irq_chip ltq_eiu_type = {
        .irq_mask = ltq_disable_irq,
        .irq_mask_ack = ltq_mask_and_ack_irq,
        .irq_set_type = ltq_eiu_settype,
+#if defined(CONFIG_SMP)
+       .irq_set_affinity = ltq_icu_irq_set_affinity,
+#endif
 };
 
 static void ltq_hw_irq_handler(struct irq_desc *desc)
 {
-       int module = irq_desc_get_irq(desc) - 2;
+       unsigned int module = irq_desc_get_irq(desc) - 2;
        u32 irq;
-       int hwirq;
+       irq_hw_number_t hwirq;
+       int vpe = smp_processor_id();
 
-       irq = ltq_icu_r32(module, LTQ_ICU_IM0_IOSR);
+       irq = ltq_icu_r32(vpe, module, LTQ_ICU_IOSR);
        if (irq == 0)
                return;
 
@@ -249,6 +310,7 @@ static void ltq_hw_irq_handler(struct irq_desc *desc)
 static int icu_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
 {
        struct irq_chip *chip = &ltq_irq_type;
+       struct irq_data *data;
        int i;
 
        if (hw < MIPS_CPU_IRQ_CASCADE)
@@ -258,6 +320,10 @@ static int icu_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
                if (hw == ltq_eiu_irq[i])
                        chip = &ltq_eiu_type;
 
+       data = irq_get_irq_data(irq);
+
+       irq_data_update_effective_affinity(data, cpumask_of(0));
+
        irq_set_chip_and_handler(irq, chip, handle_level_irq);
 
        return 0;
@@ -272,28 +338,37 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
 {
        struct device_node *eiu_node;
        struct resource res;
-       int i, ret;
+       int i, ret, vpe;
 
-       for (i = 0; i < MAX_IM; i++) {
-               if (of_address_to_resource(node, i, &res))
-                       panic("Failed to get icu memory range");
+       /* load register regions of available ICUs */
+       for_each_possible_cpu(vpe) {
+               if (of_address_to_resource(node, vpe, &res))
+                       panic("Failed to get icu%i memory range", vpe);
 
                if (!request_mem_region(res.start, resource_size(&res),
                                        res.name))
-                       pr_err("Failed to request icu memory");
+                       pr_err("Failed to request icu%i memory\n", vpe);
 
-               ltq_icu_membase[i] = ioremap_nocache(res.start,
+               ltq_icu_membase[vpe] = ioremap_nocache(res.start,
                                        resource_size(&res));
-               if (!ltq_icu_membase[i])
-                       panic("Failed to remap icu memory");
+
+               if (!ltq_icu_membase[vpe])
+                       panic("Failed to remap icu%i memory", vpe);
        }
 
        /* turn off all irqs by default */
-       for (i = 0; i < MAX_IM; i++) {
-               /* make sure all irqs are turned off by default */
-               ltq_icu_w32(i, 0, LTQ_ICU_IM0_IER);
-               /* clear all possibly pending interrupts */
-               ltq_icu_w32(i, ~0, LTQ_ICU_IM0_ISR);
+       for_each_possible_cpu(vpe) {
+               for (i = 0; i < MAX_IM; i++) {
+                       /* make sure all irqs are turned off by default */
+                       ltq_icu_w32(vpe, i, 0, LTQ_ICU_IER);
+
+                       /* clear all possibly pending interrupts */
+                       ltq_icu_w32(vpe, i, ~0, LTQ_ICU_ISR);
+                       ltq_icu_w32(vpe, i, ~0, LTQ_ICU_IMR);
+
+                       /* clear resend */
+                       ltq_icu_w32(vpe, i, 0, LTQ_ICU_IRSR);
+               }
        }
 
        mips_cpu_irq_init();
@@ -347,7 +422,7 @@ unsigned int get_c0_compare_int(void)
        return CP0_LEGACY_COMPARE_IRQ;
 }
 
-static struct of_device_id __initdata of_irq_ids[] = {
+static const struct of_device_id of_irq_ids[] __initconst = {
        { .compatible = "lantiq,icu", .data = icu_of_init },
        {},
 };
index 899b2fb..7b5180d 100644 (file)
@@ -26,7 +26,8 @@ struct pt_regs;
  *
  * It's only valid to call this when @task is known to be blocked.
  */
-int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
+static inline int
+syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
 {
        return regs->syscallno;
 }
@@ -47,7 +48,8 @@ int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
  * system call instruction.  This may not be the same as what the
  * register state looked like at system call entry tracing.
  */
-void syscall_rollback(struct task_struct *task, struct pt_regs *regs)
+static inline void
+syscall_rollback(struct task_struct *task, struct pt_regs *regs)
 {
        regs->uregs[0] = regs->orig_r0;
 }
@@ -62,7 +64,8 @@ void syscall_rollback(struct task_struct *task, struct pt_regs *regs)
  * It's only valid to call this when @task is stopped for tracing on exit
  * from a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT.
  */
-long syscall_get_error(struct task_struct *task, struct pt_regs *regs)
+static inline long
+syscall_get_error(struct task_struct *task, struct pt_regs *regs)
 {
        unsigned long error = regs->uregs[0];
        return IS_ERR_VALUE(error) ? error : 0;
@@ -79,7 +82,8 @@ long syscall_get_error(struct task_struct *task, struct pt_regs *regs)
  * It's only valid to call this when @task is stopped for tracing on exit
  * from a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT.
  */
-long syscall_get_return_value(struct task_struct *task, struct pt_regs *regs)
+static inline long
+syscall_get_return_value(struct task_struct *task, struct pt_regs *regs)
 {
        return regs->uregs[0];
 }
@@ -99,8 +103,9 @@ long syscall_get_return_value(struct task_struct *task, struct pt_regs *regs)
  * It's only valid to call this when @task is stopped for tracing on exit
  * from a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT.
  */
-void syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
-                             int error, long val)
+static inline void
+syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
+                        int error, long val)
 {
        regs->uregs[0] = (long)error ? error : val;
 }
@@ -118,8 +123,9 @@ void syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
  * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT.
  */
 #define SYSCALL_MAX_ARGS 6
-void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
-                          unsigned long *args)
+static inline void
+syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
+                     unsigned long *args)
 {
        args[0] = regs->orig_r0;
        args++;
@@ -138,8 +144,9 @@ void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
  * It's only valid to call this when @task is stopped for tracing on
  * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT.
  */
-void syscall_set_arguments(struct task_struct *task, struct pt_regs *regs,
-                          const unsigned long *args)
+static inline void
+syscall_set_arguments(struct task_struct *task, struct pt_regs *regs,
+                     const unsigned long *args)
 {
        regs->orig_r0 = args[0];
        args++;
index 42875ff..6d732e4 100644 (file)
@@ -277,7 +277,7 @@ config SMP
          machines, but will use only one CPU of a multiprocessor machine.
          On a uniprocessor machine, the kernel will run faster if you say N.
 
-         See also <file:Documentation/lockup-watchdogs.txt> and the SMP-HOWTO
+         See also <file:Documentation/admin-guide/lockup-watchdogs.rst> and the SMP-HOWTO
          available at <http://www.tldp.org/docs.html#howto>.
 
          If you don't know what to do here, say N.
index e09cf2d..904034d 100644 (file)
@@ -50,6 +50,10 @@ struct kprobe_ctlblk {
 
 int __kprobes parisc_kprobe_break_handler(struct pt_regs *regs);
 int __kprobes parisc_kprobe_ss_handler(struct pt_regs *regs);
+static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+{
+       return 0;
+}
 
 #endif /* CONFIG_KPROBES */
 #endif /* _PARISC_KPROBES_H */
index 80757e4..00b127a 100644 (file)
@@ -29,6 +29,13 @@ static inline void syscall_get_arguments(struct task_struct *tsk,
        args[0] = regs->gr[26];
 }
 
+static inline long syscall_get_error(struct task_struct *task,
+                                    struct pt_regs *regs)
+{
+       unsigned long error = regs->gr[28];
+       return IS_ERR_VALUE(error) ? error : 0;
+}
+
 static inline long syscall_get_return_value(struct task_struct *task,
                                                struct pt_regs *regs)
 {
index b0838dc..cd438e4 100644 (file)
@@ -166,6 +166,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5)       \
 #define __ARCH_WANT_SYS_FORK
 #define __ARCH_WANT_SYS_VFORK
 #define __ARCH_WANT_SYS_CLONE
+#define __ARCH_WANT_SYS_CLONE3
 #define __ARCH_WANT_COMPAT_SYS_SENDFILE
 
 #ifdef CONFIG_64BIT
index 3e43059..d9d3387 100644 (file)
@@ -1732,6 +1732,7 @@ ENDPROC_CFI(sys_\name\()_wrapper)
        .endm
 
 fork_like clone
+fork_like clone3
 fork_like fork
 fork_like vfork
 
index d58960b..5d7f269 100644 (file)
@@ -133,6 +133,9 @@ int __kprobes parisc_kprobe_ss_handler(struct pt_regs *regs)
        struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
        struct kprobe *p = kprobe_running();
 
+       if (!p)
+               return 0;
+
        if (regs->iaoq[0] != (unsigned long)p->ainsn.insn+4)
                return 0;
 
index ba67893..df46b0e 100644 (file)
@@ -63,7 +63,7 @@ ENTRY_CFI(flush_tlb_all_local)
 
        /* Flush Instruction Tlb */
 
-       LDREG           ITLB_SID_BASE(%r1), %r20
+88:    LDREG           ITLB_SID_BASE(%r1), %r20
        LDREG           ITLB_SID_STRIDE(%r1), %r21
        LDREG           ITLB_SID_COUNT(%r1), %r22
        LDREG           ITLB_OFF_BASE(%r1), %arg0
@@ -103,6 +103,7 @@ fitonemiddle:                                       /* Loop if LOOP = 1 */
        add             %r21, %r20, %r20                /* increment space */
 
 fitdone:
+       ALTERNATIVE(88b, fitdone, ALT_COND_NO_SPLIT_TLB, INSN_NOP)
 
        /* Flush Data Tlb */
 
index f642ba3..9f6ff7b 100644 (file)
@@ -167,6 +167,9 @@ long arch_ptrace(struct task_struct *child, long request,
                if ((addr & (sizeof(unsigned long)-1)) ||
                     addr >= sizeof(struct pt_regs))
                        break;
+               if (addr == PT_IAOQ0 || addr == PT_IAOQ1) {
+                       data |= 3; /* ensure userspace privilege */
+               }
                if ((addr >= PT_GR1 && addr <= PT_GR31) ||
                                addr == PT_IAOQ0 || addr == PT_IAOQ1 ||
                                (addr >= PT_FR0 && addr <= PT_FR31 + 4) ||
@@ -228,16 +231,18 @@ long arch_ptrace(struct task_struct *child, long request,
 
 static compat_ulong_t translate_usr_offset(compat_ulong_t offset)
 {
-       if (offset < 0)
-               return sizeof(struct pt_regs);
-       else if (offset <= 32*4)        /* gr[0..31] */
-               return offset * 2 + 4;
-       else if (offset <= 32*4+32*8)   /* gr[0..31] + fr[0..31] */
-               return offset + 32*4;
-       else if (offset < sizeof(struct pt_regs)/2 + 32*4)
-               return offset * 2 + 4 - 32*8;
+       compat_ulong_t pos;
+
+       if (offset < 32*4)      /* gr[0..31] */
+               pos = offset * 2 + 4;
+       else if (offset < 32*4+32*8)    /* fr[0] ... fr[31] */
+               pos = (offset - 32*4) + PT_FR0;
+       else if (offset < sizeof(struct pt_regs)/2 + 32*4) /* sr[0] ... ipsw */
+               pos = (offset - 32*4 - 32*8) * 2 + PT_SR0 + 4;
        else
-               return sizeof(struct pt_regs);
+               pos = sizeof(struct pt_regs);
+
+       return pos;
 }
 
 long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
@@ -281,9 +286,12 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
                        addr = translate_usr_offset(addr);
                        if (addr >= sizeof(struct pt_regs))
                                break;
+                       if (addr == PT_IAOQ0+4 || addr == PT_IAOQ1+4) {
+                               data |= 3; /* ensure userspace privilege */
+                       }
                        if (addr >= PT_FR0 && addr <= PT_FR31 + 4) {
                                /* Special case, fp regs are 64 bits anyway */
-                               *(__u64 *) ((char *) task_regs(child) + addr) = data;
+                               *(__u32 *) ((char *) task_regs(child) + addr) = data;
                                ret = 0;
                        }
                        else if ((addr >= PT_GR1+4 && addr <= PT_GR31+4) ||
@@ -496,7 +504,8 @@ static void set_reg(struct pt_regs *regs, int num, unsigned long val)
                        return;
        case RI(iaoq[0]):
        case RI(iaoq[1]):
-                       regs->iaoq[num - RI(iaoq[0])] = val;
+                       /* set 2 lowest bits to ensure userspace privilege: */
+                       regs->iaoq[num - RI(iaoq[0])] = val | 3;
                        return;
        case RI(sar):   regs->sar = val;
                        return;
index 5022b9e..670d137 100644 (file)
 432    common  fsmount                         sys_fsmount
 433    common  fspick                          sys_fspick
 434    common  pidfd_open                      sys_pidfd_open
+435    common  clone3                          sys_clone3_wrapper
index f516796..77f6ebf 100644 (file)
@@ -121,6 +121,7 @@ config PPC
        select ARCH_32BIT_OFF_T if PPC32
        select ARCH_HAS_DEBUG_VIRTUAL
        select ARCH_HAS_DEVMEM_IS_ALLOWED
+       select ARCH_HAS_DMA_MMAP_PGPROT
        select ARCH_HAS_ELF_RANDOMIZE
        select ARCH_HAS_FORTIFY_SOURCE
        select ARCH_HAS_GCOV_PROFILE_ALL
@@ -129,6 +130,7 @@ config PPC
        select ARCH_HAS_MMIOWB                  if PPC64
        select ARCH_HAS_PHYS_TO_DMA
        select ARCH_HAS_PMEM_API                if PPC64
+       select ARCH_HAS_PTE_DEVMAP              if PPC_BOOK3S_64
        select ARCH_HAS_PTE_SPECIAL
        select ARCH_HAS_MEMBARRIER_CALLBACKS
        select ARCH_HAS_SCALED_CPUTIME          if VIRT_CPU_ACCOUNTING_NATIVE && PPC64
@@ -136,7 +138,6 @@ config PPC
        select ARCH_HAS_TICK_BROADCAST          if GENERIC_CLOCKEVENTS_BROADCAST
        select ARCH_HAS_UACCESS_FLUSHCACHE      if PPC64
        select ARCH_HAS_UBSAN_SANITIZE_ALL
-       select ARCH_HAS_ZONE_DEVICE             if PPC_BOOK3S_64
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select ARCH_KEEP_MEMBLOCK
        select ARCH_MIGHT_HAVE_PC_PARPORT
index 62e6ea0..8308f32 100644 (file)
@@ -90,7 +90,6 @@
 #define _PAGE_SOFT_DIRTY       _RPAGE_SW3 /* software: software dirty tracking */
 #define _PAGE_SPECIAL          _RPAGE_SW2 /* software: special page */
 #define _PAGE_DEVMAP           _RPAGE_SW1 /* software: ZONE_DEVICE page */
-#define __HAVE_ARCH_PTE_DEVMAP
 
 /*
  * Drivers request for cache inhibited pte mapping using _PAGE_NO_CACHE
index 463c63a..1111202 100644 (file)
 #define H_SCM_UNBIND_MEM        0x3F0
 #define H_SCM_QUERY_BLOCK_MEM_BINDING 0x3F4
 #define H_SCM_QUERY_LOGICAL_MEM_BINDING 0x3F8
-#define H_SCM_MEM_QUERY                0x3FC
-#define H_SCM_BLOCK_CLEAR       0x400
-#define MAX_HCALL_OPCODE       H_SCM_BLOCK_CLEAR
+#define H_SCM_UNBIND_ALL        0x3FC
+#define H_SCM_HEALTH            0x400
+#define H_SCM_PERFORMANCE_STATS 0x418
+#define MAX_HCALL_OPCODE       H_SCM_PERFORMANCE_STATS
+
+/* Scope args for H_SCM_UNBIND_ALL */
+#define H_UNBIND_SCOPE_ALL (0x1)
+#define H_UNBIND_SCOPE_DRC (0x2)
 
 /* H_VIOCTL functions */
 #define H_GET_VIOA_DUMP_SIZE   0x01
index dc9a1ca..c6bbe97 100644 (file)
@@ -27,11 +27,10 @@ static inline void ppc_set_pmu_inuse(int inuse)
 #ifdef CONFIG_PPC_PSERIES
                get_lppaca()->pmcregs_in_use = inuse;
 #endif
-       } else {
+       }
 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
-               get_paca()->pmcregs_in_use = inuse;
+       get_paca()->pmcregs_in_use = inuse;
 #endif
-       }
 #endif
 }
 
index 81abcf6..38d62ac 100644 (file)
@@ -35,6 +35,16 @@ static inline void syscall_rollback(struct task_struct *task,
        regs->gpr[3] = regs->orig_gpr3;
 }
 
+static inline long syscall_get_error(struct task_struct *task,
+                                    struct pt_regs *regs)
+{
+       /*
+        * If the system call failed,
+        * regs->gpr[3] contains a positive ERRORCODE.
+        */
+       return (regs->ccr & 0x10000000UL) ? -regs->gpr[3] : 0;
+}
+
 static inline long syscall_get_return_value(struct task_struct *task,
                                            struct pt_regs *regs)
 {
index 01555c6..be48c22 100644 (file)
@@ -31,7 +31,7 @@
  * Struct fields are always 32 or 64 bit aligned, depending on them being 32
  * or 64 bit wide respectively.
  *
- * See Documentation/virtual/kvm/ppc-pv.txt
+ * See Documentation/virt/kvm/ppc-pv.txt
  */
 struct kvm_vcpu_arch_shared {
        __u64 scratch1;
index 65065ce..c0c7372 100644 (file)
 #define MAP_DENYWRITE  0x0800          /* ETXTBSY */
 #define MAP_EXECUTABLE 0x1000          /* mark it as an executable */
 
+
 #define MCL_CURRENT     0x2000          /* lock all currently mapped pages */
 #define MCL_FUTURE      0x4000          /* lock all additions to address space */
 #define MCL_ONFAULT    0x8000          /* lock all pages that are faulted in */
 
-#define MAP_POPULATE   0x8000          /* populate (prefault) pagetables */
-#define MAP_NONBLOCK   0x10000         /* do not block on IO */
-#define MAP_STACK      0x20000         /* give out an address that is best suited for process/thread stacks */
-#define MAP_HUGETLB    0x40000         /* create a huge page mapping */
-
 /* Override any generic PKEY permission defines */
 #define PKEY_DISABLE_EXECUTE   0x4
 #undef PKEY_ACCESS_MASK
index 56dfa7a..ea0c692 100644 (file)
@@ -49,7 +49,8 @@ obj-y                         := cputable.o ptrace.o syscalls.o \
                                   signal.o sysfs.o cacheinfo.o time.o \
                                   prom.o traps.o setup-common.o \
                                   udbg.o misc.o io.o misc_$(BITS).o \
-                                  of_platform.o prom_parse.o
+                                  of_platform.o prom_parse.o \
+                                  dma-common.o
 obj-$(CONFIG_PPC64)            += setup_64.o sys_ppc32.o \
                                   signal_64.o ptrace32.o \
                                   paca.o nvram_64.o firmware.o
diff --git a/arch/powerpc/kernel/dma-common.c b/arch/powerpc/kernel/dma-common.c
new file mode 100644 (file)
index 0000000..dc7ef6b
--- /dev/null
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Contains common dma routines for all powerpc platforms.
+ *
+ * Copyright (C) 2019 Shawn Anastasio.
+ */
+
+#include <linux/mm.h>
+#include <linux/dma-noncoherent.h>
+
+pgprot_t arch_dma_mmap_pgprot(struct device *dev, pgprot_t prot,
+               unsigned long attrs)
+{
+       if (!dev_is_dma_coherent(dev))
+               return pgprot_noncached(prot);
+       return prot;
+}
index f50b708..98600b2 100644 (file)
@@ -1198,6 +1198,9 @@ SYSCALL_DEFINE0(rt_sigreturn)
                        goto bad;
 
                if (MSR_TM_ACTIVE(msr_hi<<32)) {
+                       /* Trying to start TM on non TM system */
+                       if (!cpu_has_feature(CPU_FTR_TM))
+                               goto bad;
                        /* We only recheckpoint on return if we're
                         * transaction.
                         */
index 2f80e27..1175155 100644 (file)
@@ -771,6 +771,11 @@ SYSCALL_DEFINE0(rt_sigreturn)
        if (MSR_TM_ACTIVE(msr)) {
                /* We recheckpoint on return. */
                struct ucontext __user *uc_transact;
+
+               /* Trying to start TM on non TM system */
+               if (!cpu_has_feature(CPU_FTR_TM))
+                       goto badframe;
+
                if (__get_user(uc_transact, &uc->uc_link))
                        goto badframe;
                if (restore_tm_sigcontexts(current, &uc->uc_mcontext,
index f2c3bda..3331749 100644 (file)
 432    common  fsmount                         sys_fsmount
 433    common  fspick                          sys_fspick
 434    common  pidfd_open                      sys_pidfd_open
+# 435 reserved for clone3
index 5bf05cc..e99a147 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/anon_inodes.h>
 #include <linux/iommu.h>
 #include <linux/file.h>
+#include <linux/mm.h>
 
 #include <asm/kvm_ppc.h>
 #include <asm/kvm_book3s.h>
@@ -45,43 +46,6 @@ static unsigned long kvmppc_stt_pages(unsigned long tce_pages)
        return tce_pages + ALIGN(stt_bytes, PAGE_SIZE) / PAGE_SIZE;
 }
 
-static long kvmppc_account_memlimit(unsigned long stt_pages, bool inc)
-{
-       long ret = 0;
-
-       if (!current || !current->mm)
-               return ret; /* process exited */
-
-       down_write(&current->mm->mmap_sem);
-
-       if (inc) {
-               unsigned long locked, lock_limit;
-
-               locked = current->mm->locked_vm + stt_pages;
-               lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
-               if (locked > lock_limit && !capable(CAP_IPC_LOCK))
-                       ret = -ENOMEM;
-               else
-                       current->mm->locked_vm += stt_pages;
-       } else {
-               if (WARN_ON_ONCE(stt_pages > current->mm->locked_vm))
-                       stt_pages = current->mm->locked_vm;
-
-               current->mm->locked_vm -= stt_pages;
-       }
-
-       pr_debug("[%d] RLIMIT_MEMLOCK KVM %c%ld %ld/%ld%s\n", current->pid,
-                       inc ? '+' : '-',
-                       stt_pages << PAGE_SHIFT,
-                       current->mm->locked_vm << PAGE_SHIFT,
-                       rlimit(RLIMIT_MEMLOCK),
-                       ret ? " - exceeded" : "");
-
-       up_write(&current->mm->mmap_sem);
-
-       return ret;
-}
-
 static void kvm_spapr_tce_iommu_table_free(struct rcu_head *head)
 {
        struct kvmppc_spapr_tce_iommu_table *stit = container_of(head,
@@ -291,7 +255,7 @@ static int kvm_spapr_tce_release(struct inode *inode, struct file *filp)
 
        kvm_put_kvm(stt->kvm);
 
-       kvmppc_account_memlimit(
+       account_locked_vm(current->mm,
                kvmppc_stt_pages(kvmppc_tce_pages(stt->size)), false);
        call_rcu(&stt->rcu, release_spapr_tce_table);
 
@@ -316,7 +280,7 @@ long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
                return -EINVAL;
 
        npages = kvmppc_tce_pages(size);
-       ret = kvmppc_account_memlimit(kvmppc_stt_pages(npages), true);
+       ret = account_locked_vm(current->mm, kvmppc_stt_pages(npages), true);
        if (ret)
                return ret;
 
@@ -362,7 +326,7 @@ long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
 
        kfree(stt);
  fail_acct:
-       kvmppc_account_memlimit(kvmppc_stt_pages(npages), false);
+       account_locked_vm(current->mm, kvmppc_stt_pages(npages), false);
        return ret;
 }
 
index ec1804f..cde3f5a 100644 (file)
@@ -3569,9 +3569,18 @@ int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,
        mtspr(SPRN_DEC, vcpu->arch.dec_expires - mftb());
 
        if (kvmhv_on_pseries()) {
+               /*
+                * 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.
+                */
+               unsigned long host_psscr;
                /* call our hypervisor to load up HV regs and go */
                struct hv_guest_state hvregs;
 
+               host_psscr = mfspr(SPRN_PSSCR_PR);
+               mtspr(SPRN_PSSCR_PR, vcpu->arch.psscr);
                kvmhv_save_hv_regs(vcpu, &hvregs);
                hvregs.lpcr = lpcr;
                vcpu->arch.regs.msr = vcpu->arch.shregs.msr;
@@ -3590,6 +3599,8 @@ int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,
                vcpu->arch.shregs.msr = vcpu->arch.regs.msr;
                vcpu->arch.shregs.dar = mfspr(SPRN_DAR);
                vcpu->arch.shregs.dsisr = mfspr(SPRN_DSISR);
+               vcpu->arch.psscr = mfspr(SPRN_PSSCR_PR);
+               mtspr(SPRN_PSSCR_PR, host_psscr);
 
                /* H_CEDE has to be handled now, not later */
                if (trap == BOOK3S_INTERRUPT_SYSCALL && !vcpu->arch.nested &&
@@ -3654,6 +3665,8 @@ int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,
                vcpu->arch.vpa.dirty = 1;
                save_pmu = lp->pmcregs_in_use;
        }
+       /* Must save pmu if this guest is capable of running nested guests */
+       save_pmu |= nesting_enabled(vcpu->kvm);
 
        kvmhv_save_guest_pmu(vcpu, save_pmu);
 
index 6ca0d73..e3ba670 100644 (file)
@@ -1986,10 +1986,8 @@ static int kvmppc_xive_create(struct kvm_device *dev, u32 type)
 
        xive->single_escalation = xive_native_has_single_escalation();
 
-       if (ret) {
-               kfree(xive);
+       if (ret)
                return ret;
-       }
 
        return 0;
 }
index 5596c8e..a998823 100644 (file)
@@ -1090,9 +1090,9 @@ static int kvmppc_xive_native_create(struct kvm_device *dev, u32 type)
        xive->ops = &kvmppc_xive_native_ops;
 
        if (ret)
-               kfree(xive);
+               return ret;
 
-       return ret;
+       return 0;
 }
 
 /*
index 9a5963e..b8ad14b 100644 (file)
@@ -1899,11 +1899,20 @@ void hash__setup_initial_memory_limit(phys_addr_t first_memblock_base,
         *
         * For guests on platforms before POWER9, we clamp the it limit to 1G
         * to avoid some funky things such as RTAS bugs etc...
+        *
+        * On POWER9 we limit to 1TB in case the host erroneously told us that
+        * the RMA was >1TB. Effective address bits 0:23 are treated as zero
+        * (meaning the access is aliased to zero i.e. addr = addr % 1TB)
+        * for virtual real mode addressing and so it doesn't make sense to
+        * have an area larger than 1TB as it can't be addressed.
         */
        if (!early_cpu_has_feature(CPU_FTR_HVMODE)) {
                ppc64_rma_size = first_memblock_size;
                if (!early_cpu_has_feature(CPU_FTR_ARCH_300))
                        ppc64_rma_size = min_t(u64, ppc64_rma_size, 0x40000000);
+               else
+                       ppc64_rma_size = min_t(u64, ppc64_rma_size,
+                                              1UL << SID_SHIFT_1T);
 
                /* Finally limit subsequent allocations */
                memblock_set_current_limit(ppc64_rma_size);
index 90ee3a8..b056cae 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/hugetlb.h>
 #include <linux/swap.h>
 #include <linux/sizes.h>
+#include <linux/mm.h>
 #include <asm/mmu_context.h>
 #include <asm/pte-walk.h>
 #include <linux/mm_inline.h>
@@ -46,40 +47,6 @@ struct mm_iommu_table_group_mem_t {
        u64 dev_hpa;            /* Device memory base address */
 };
 
-static long mm_iommu_adjust_locked_vm(struct mm_struct *mm,
-               unsigned long npages, bool incr)
-{
-       long ret = 0, locked, lock_limit;
-
-       if (!npages)
-               return 0;
-
-       down_write(&mm->mmap_sem);
-
-       if (incr) {
-               locked = mm->locked_vm + npages;
-               lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
-               if (locked > lock_limit && !capable(CAP_IPC_LOCK))
-                       ret = -ENOMEM;
-               else
-                       mm->locked_vm += npages;
-       } else {
-               if (WARN_ON_ONCE(npages > mm->locked_vm))
-                       npages = mm->locked_vm;
-               mm->locked_vm -= npages;
-       }
-
-       pr_debug("[%d] RLIMIT_MEMLOCK HASH64 %c%ld %ld/%ld\n",
-                       current ? current->pid : 0,
-                       incr ? '+' : '-',
-                       npages << PAGE_SHIFT,
-                       mm->locked_vm << PAGE_SHIFT,
-                       rlimit(RLIMIT_MEMLOCK));
-       up_write(&mm->mmap_sem);
-
-       return ret;
-}
-
 bool mm_iommu_preregistered(struct mm_struct *mm)
 {
        return !list_empty(&mm->context.iommu_group_mem_list);
@@ -96,7 +63,7 @@ static long mm_iommu_do_alloc(struct mm_struct *mm, unsigned long ua,
        unsigned long entry, chunk;
 
        if (dev_hpa == MM_IOMMU_TABLE_INVALID_HPA) {
-               ret = mm_iommu_adjust_locked_vm(mm, entries, true);
+               ret = account_locked_vm(mm, entries, true);
                if (ret)
                        return ret;
 
@@ -211,7 +178,7 @@ free_exit:
        kfree(mem);
 
 unlock_exit:
-       mm_iommu_adjust_locked_vm(mm, locked_entries, false);
+       account_locked_vm(mm, locked_entries, false);
 
        return ret;
 }
@@ -311,7 +278,7 @@ long mm_iommu_put(struct mm_struct *mm, struct mm_iommu_table_group_mem_t *mem)
 unlock_exit:
        mutex_unlock(&mem_list_mutex);
 
-       mm_iommu_adjust_locked_vm(mm, unlock_entries, false);
+       account_locked_vm(mm, unlock_entries, false);
 
        return ret;
 }
index 65c2ba1..b4ca9e9 100644 (file)
@@ -1237,3 +1237,8 @@ int radix__ioremap_range(unsigned long ea, phys_addr_t pa, unsigned long size,
                return 0;
        }
 }
+
+int __init arch_ioremap_p4d_supported(void)
+{
+       return 0;
+}
index d989592..8432c28 100644 (file)
 #include <asm/debug.h>
 #include <asm/kup.h>
 
-static inline bool notify_page_fault(struct pt_regs *regs)
-{
-       bool ret = false;
-
-#ifdef CONFIG_KPROBES
-       /* kprobe_running() needs smp_processor_id() */
-       if (!user_mode(regs)) {
-               preempt_disable();
-               if (kprobe_running() && kprobe_fault_handler(regs, 11))
-                       ret = true;
-               preempt_enable();
-       }
-#endif /* CONFIG_KPROBES */
-
-       if (unlikely(debugger_fault_handler(regs)))
-               ret = true;
-
-       return ret;
-}
-
 /*
  * Check whether the instruction inst is a store using
  * an update addressing form which will update r1.
@@ -461,8 +441,9 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
        int is_write = page_fault_is_write(error_code);
        vm_fault_t fault, major = 0;
        bool must_retry = false;
+       bool kprobe_fault = kprobe_page_fault(regs, 11);
 
-       if (notify_page_fault(regs))
+       if (unlikely(debugger_fault_handler(regs) || kprobe_fault))
                return 0;
 
        if (unlikely(page_fault_is_bad(error_code))) {
index 26a8da3..9191a66 100644 (file)
@@ -125,7 +125,6 @@ int __ref arch_add_memory(int nid, u64 start, u64 size,
        return __add_pages(nid, start_pfn, nr_pages, restrictions);
 }
 
-#ifdef CONFIG_MEMORY_HOTREMOVE
 void __ref arch_remove_memory(int nid, u64 start, u64 size,
                             struct vmem_altmap *altmap)
 {
@@ -151,7 +150,6 @@ void __ref arch_remove_memory(int nid, u64 start, u64 size,
                pr_warn("Hash collision while resizing HPT\n");
 }
 #endif
-#endif /* CONFIG_MEMORY_HOTPLUG */
 
 #ifndef CONFIG_NEED_MULTIPLE_NODES
 void __init mem_topology_setup(void)
@@ -241,7 +239,7 @@ void __init paging_init(void)
 
 #ifdef CONFIG_ZONE_DMA
        max_zone_pfns[ZONE_DMA] = min(max_low_pfn,
-                       ((1UL << ARCH_ZONE_DMA_BITS) - 1) >> PAGE_SHIFT);
+                                     1UL << (ARCH_ZONE_DMA_BITS - PAGE_SHIFT));
 #endif
        max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
 #ifdef CONFIG_HIGHMEM
index 5e53c13..eb2e75d 100644 (file)
@@ -70,23 +70,23 @@ static int change_memblock_state(struct memory_block *mem, void *arg)
 /* called with device_hotplug_lock held */
 static bool memtrace_offline_pages(u32 nid, u64 start_pfn, u64 nr_pages)
 {
-       u64 end_pfn = start_pfn + nr_pages - 1;
+       const unsigned long start = PFN_PHYS(start_pfn);
+       const unsigned long size = PFN_PHYS(nr_pages);
 
-       if (walk_memory_range(start_pfn, end_pfn, NULL,
-           check_memblock_online))
+       if (walk_memory_blocks(start, size, NULL, check_memblock_online))
                return false;
 
-       walk_memory_range(start_pfn, end_pfn, (void *)MEM_GOING_OFFLINE,
-                         change_memblock_state);
+       walk_memory_blocks(start, size, (void *)MEM_GOING_OFFLINE,
+                          change_memblock_state);
 
        if (offline_pages(start_pfn, nr_pages)) {
-               walk_memory_range(start_pfn, end_pfn, (void *)MEM_ONLINE,
-                                 change_memblock_state);
+               walk_memory_blocks(start, size, (void *)MEM_ONLINE,
+                                  change_memblock_state);
                return false;
        }
 
-       walk_memory_range(start_pfn, end_pfn, (void *)MEM_OFFLINE,
-                         change_memblock_state);
+       walk_memory_blocks(start, size, (void *)MEM_OFFLINE,
+                          change_memblock_state);
 
 
        return true;
@@ -242,9 +242,8 @@ static int memtrace_online(void)
                 */
                if (!memhp_auto_online) {
                        lock_device_hotplug();
-                       walk_memory_range(PFN_DOWN(ent->start),
-                                         PFN_UP(ent->start + ent->size - 1),
-                                         NULL, online_mem_block);
+                       walk_memory_blocks(ent->start, ent->size, NULL,
+                                          online_mem_block);
                        unlock_device_hotplug();
                }
 
index c8ec670..2c07908 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/sched.h>
 #include <linux/libnvdimm.h>
 #include <linux/platform_device.h>
+#include <linux/delay.h>
 
 #include <asm/plpar_wrappers.h>
 
@@ -43,8 +44,9 @@ struct papr_scm_priv {
 static int drc_pmem_bind(struct papr_scm_priv *p)
 {
        unsigned long ret[PLPAR_HCALL_BUFSIZE];
-       uint64_t rc, token;
        uint64_t saved = 0;
+       uint64_t token;
+       int64_t rc;
 
        /*
         * When the hypervisor cannot map all the requested memory in a single
@@ -64,6 +66,10 @@ static int drc_pmem_bind(struct papr_scm_priv *p)
        } while (rc == H_BUSY);
 
        if (rc) {
+               /* H_OVERLAP needs a separate error path */
+               if (rc == H_OVERLAP)
+                       return -EBUSY;
+
                dev_err(&p->pdev->dev, "bind err: %lld\n", rc);
                return -ENXIO;
        }
@@ -78,22 +84,36 @@ static int drc_pmem_bind(struct papr_scm_priv *p)
 static int drc_pmem_unbind(struct papr_scm_priv *p)
 {
        unsigned long ret[PLPAR_HCALL_BUFSIZE];
-       uint64_t rc, token;
+       uint64_t token = 0;
+       int64_t rc;
 
-       token = 0;
+       dev_dbg(&p->pdev->dev, "unbind drc %x\n", p->drc_index);
 
-       /* NB: unbind has the same retry requirements mentioned above */
+       /* NB: unbind has the same retry requirements as drc_pmem_bind() */
        do {
-               rc = plpar_hcall(H_SCM_UNBIND_MEM, ret, p->drc_index,
-                               p->bound_addr, p->blocks, token);
+
+               /* Unbind of all SCM resources associated with drcIndex */
+               rc = plpar_hcall(H_SCM_UNBIND_ALL, ret, H_UNBIND_SCOPE_DRC,
+                                p->drc_index, token);
                token = ret[0];
-               cond_resched();
+
+               /* Check if we are stalled for some time */
+               if (H_IS_LONG_BUSY(rc)) {
+                       msleep(get_longbusy_msecs(rc));
+                       rc = H_BUSY;
+               } else if (rc == H_BUSY) {
+                       cond_resched();
+               }
+
        } while (rc == H_BUSY);
 
        if (rc)
                dev_err(&p->pdev->dev, "unbind error: %lld\n", rc);
+       else
+               dev_dbg(&p->pdev->dev, "unbind drc %x complete\n",
+                       p->drc_index);
 
-       return !!rc;
+       return rc == H_SUCCESS ? 0 : -ENXIO;
 }
 
 static int papr_scm_meta_get(struct papr_scm_priv *p,
@@ -389,6 +409,14 @@ static int papr_scm_probe(struct platform_device *pdev)
 
        /* request the hypervisor to bind this region to somewhere in memory */
        rc = drc_pmem_bind(p);
+
+       /* If phyp says drc memory still bound then force unbound and retry */
+       if (rc == -EBUSY) {
+               dev_warn(&pdev->dev, "Retrying bind after unbinding\n");
+               drc_pmem_unbind(p);
+               rc = drc_pmem_bind(p);
+       }
+
        if (rc)
                goto err;
 
index 082c7e1..1cdb395 100644 (file)
@@ -479,7 +479,7 @@ static int xive_find_target_in_mask(const struct cpumask *mask,
         * Now go through the entire mask until we find a valid
         * target.
         */
-       for (;;) {
+       do {
                /*
                 * We re-check online as the fallback case passes us
                 * an untested affinity mask
@@ -487,12 +487,11 @@ static int xive_find_target_in_mask(const struct cpumask *mask,
                if (cpu_online(cpu) && xive_try_pick_target(cpu))
                        return cpu;
                cpu = cpumask_next(cpu, mask);
-               if (cpu == first)
-                       break;
                /* Wrap around */
                if (cpu >= nr_cpu_ids)
                        cpu = cpumask_first(mask);
-       }
+       } while (cpu != first);
+
        return -1;
 }
 
index 13a1c0d..59a4727 100644 (file)
@@ -52,6 +52,8 @@ config RISCV
        select ARCH_HAS_MMIOWB
        select HAVE_EBPF_JIT if 64BIT
        select EDAC_SUPPORT
+       select ARCH_HAS_GIGANTIC_PAGE
+       select ARCH_WANT_HUGE_PMD_SHARE if 64BIT
 
 config MMU
        def_bool y
@@ -66,6 +68,12 @@ config PAGE_OFFSET
        default 0xffffffff80000000 if 64BIT && MAXPHYSMEM_2GB
        default 0xffffffe000000000 if 64BIT && MAXPHYSMEM_128GB
 
+config ARCH_WANT_GENERAL_HUGETLB
+       def_bool y
+
+config SYS_SUPPORTS_HUGETLBFS
+       def_bool y
+
 config STACKTRACE_SUPPORT
        def_bool y
 
@@ -97,6 +105,8 @@ config PGTABLE_LEVELS
        default 3 if 64BIT
        default 2
 
+source "arch/riscv/Kconfig.socs"
+
 menu "Platform type"
 
 choice
diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
new file mode 100644 (file)
index 0000000..536c0ef
--- /dev/null
@@ -0,0 +1,13 @@
+menu "SoC selection"
+
+config SOC_SIFIVE
+       bool "SiFive SoCs"
+       select SERIAL_SIFIVE
+       select SERIAL_SIFIVE_CONSOLE
+       select CLK_SIFIVE
+       select CLK_SIFIVE_FU540_PRCI
+       select SIFIVE_PLIC
+       help
+         This enables support for SiFive SoC platform hardware.
+
+endmenu
index f8b3b07..7a117be 100644 (file)
@@ -34,8 +34,6 @@ else
        KBUILD_LDFLAGS += -melf32lriscv
 endif
 
-KBUILD_CFLAGS += -Wall
-
 # ISA string setting
 riscv-march-$(CONFIG_ARCH_RV32I)       := rv32ima
 riscv-march-$(CONFIG_ARCH_RV64I)       := rv64ima
index baaeef9..6d6189e 100644 (file)
@@ -1,2 +1,2 @@
 # SPDX-License-Identifier: GPL-2.0
-dtb-y += hifive-unleashed-a00.dtb
+dtb-$(CONFIG_SOC_SIFIVE) += hifive-unleashed-a00.dtb
index 4098349..9bf63f0 100644 (file)
                        #size-cells = <0>;
                        status = "disabled";
                };
+               eth0: ethernet@10090000 {
+                       compatible = "sifive,fu540-c000-gem";
+                       interrupt-parent = <&plic0>;
+                       interrupts = <53>;
+                       reg = <0x0 0x10090000 0x0 0x2000
+                              0x0 0x100a0000 0x0 0x1000>;
+                       local-mac-address = [00 00 00 00 00 00];
+                       clock-names = "pclk", "hclk";
+                       clocks = <&prci PRCI_CLK_GEMGXLPLL>,
+                                <&prci PRCI_CLK_GEMGXLPLL>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
        };
 };
index 0b55c53..93d68cb 100644 (file)
                disable-wp;
        };
 };
+
+&eth0 {
+       status = "okay";
+       phy-mode = "gmii";
+       phy-handle = <&phy0>;
+       phy0: ethernet-phy@0 {
+               reg = <0>;
+       };
+};
index 04944fb..b7b749b 100644 (file)
@@ -1,5 +1,7 @@
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_HIGH_RES_TIMERS=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_CGROUPS=y
@@ -12,6 +14,7 @@ CONFIG_CHECKPOINT_RESTORE=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
 CONFIG_BPF_SYSCALL=y
+CONFIG_SOC_SIFIVE=y
 CONFIG_SMP=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
@@ -49,8 +52,6 @@ CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_OF_PLATFORM=y
 CONFIG_SERIAL_EARLYCON_RISCV_SBI=y
-CONFIG_SERIAL_SIFIVE=y
-CONFIG_SERIAL_SIFIVE_CONSOLE=y
 CONFIG_HVC_RISCV_SBI=y
 # CONFIG_PTP_1588_CLOCK is not set
 CONFIG_DRM=y
@@ -66,9 +67,6 @@ CONFIG_USB_OHCI_HCD_PLATFORM=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_UAS=y
 CONFIG_VIRTIO_MMIO=y
-CONFIG_CLK_SIFIVE=y
-CONFIG_CLK_SIFIVE_FU540_PRCI=y
-CONFIG_SIFIVE_PLIC=y
 CONFIG_SPI_SIFIVE=y
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
index 1a911ed..d5449ef 100644 (file)
@@ -1,5 +1,7 @@
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_HIGH_RES_TIMERS=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_CGROUPS=y
index 1efaedd..16970f2 100644 (file)
@@ -22,6 +22,7 @@ generic-y += kvm_para.h
 generic-y += local.h
 generic-y += local64.h
 generic-y += mm-arch-hooks.h
+generic-y += msi.h
 generic-y += percpu.h
 generic-y += preempt.h
 generic-y += sections.h
index ad8678f..555b20b 100644 (file)
@@ -6,11 +6,66 @@
 #ifndef _ASM_RISCV_CACHEFLUSH_H
 #define _ASM_RISCV_CACHEFLUSH_H
 
-#include <asm-generic/cacheflush.h>
+#include <linux/mm.h>
 
-#undef flush_icache_range
-#undef flush_icache_user_range
-#undef flush_dcache_page
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
+
+/*
+ * The cache doesn't need to be flushed when TLB entries change when
+ * the cache is mapped to physical memory, not virtual memory
+ */
+static inline void flush_cache_all(void)
+{
+}
+
+static inline void flush_cache_mm(struct mm_struct *mm)
+{
+}
+
+static inline void flush_cache_dup_mm(struct mm_struct *mm)
+{
+}
+
+static inline void flush_cache_range(struct vm_area_struct *vma,
+                                    unsigned long start,
+                                    unsigned long end)
+{
+}
+
+static inline void flush_cache_page(struct vm_area_struct *vma,
+                                   unsigned long vmaddr,
+                                   unsigned long pfn)
+{
+}
+
+static inline void flush_dcache_mmap_lock(struct address_space *mapping)
+{
+}
+
+static inline void flush_dcache_mmap_unlock(struct address_space *mapping)
+{
+}
+
+static inline void flush_icache_page(struct vm_area_struct *vma,
+                                    struct page *page)
+{
+}
+
+static inline void flush_cache_vmap(unsigned long start, unsigned long end)
+{
+}
+
+static inline void flush_cache_vunmap(unsigned long start, unsigned long end)
+{
+}
+
+#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
+       do { \
+               memcpy(dst, src, len); \
+               flush_icache_user_range(vma, page, vaddr, len); \
+       } while (0)
+#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
+       memcpy(dst, src, len)
 
 static inline void local_flush_icache_all(void)
 {
index c207f66..9c66033 100644 (file)
  */
 enum fixed_addresses {
        FIX_HOLE,
+#define FIX_FDT_SIZE   SZ_1M
+       FIX_FDT_END,
+       FIX_FDT = FIX_FDT_END + FIX_FDT_SIZE / PAGE_SIZE - 1,
+       FIX_PTE,
+       FIX_PMD,
        FIX_EARLYCON_MEM_BASE,
        __end_of_fixed_addresses
 };
diff --git a/arch/riscv/include/asm/hugetlb.h b/arch/riscv/include/asm/hugetlb.h
new file mode 100644 (file)
index 0000000..728a5db
--- /dev/null
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_RISCV_HUGETLB_H
+#define _ASM_RISCV_HUGETLB_H
+
+#include <asm-generic/hugetlb.h>
+#include <asm/page.h>
+
+static inline int is_hugepage_only_range(struct mm_struct *mm,
+                                        unsigned long addr,
+                                        unsigned long len) {
+       return 0;
+}
+
+static inline void arch_clear_hugepage_flags(struct page *page)
+{
+}
+
+#endif /* _ASM_RISCV_HUGETLB_H */
diff --git a/arch/riscv/include/asm/image.h b/arch/riscv/include/asm/image.h
new file mode 100644 (file)
index 0000000..ef28e10
--- /dev/null
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ASM_IMAGE_H
+#define __ASM_IMAGE_H
+
+#define RISCV_IMAGE_MAGIC      "RISCV"
+
+#define RISCV_IMAGE_FLAG_BE_SHIFT      0
+#define RISCV_IMAGE_FLAG_BE_MASK       0x1
+
+#define RISCV_IMAGE_FLAG_LE            0
+#define RISCV_IMAGE_FLAG_BE            1
+
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#error conversion of header fields to LE not yet implemented
+#else
+#define __HEAD_FLAG_BE         RISCV_IMAGE_FLAG_LE
+#endif
+
+#define __HEAD_FLAG(field)     (__HEAD_FLAG_##field << \
+                               RISCV_IMAGE_FLAG_##field##_SHIFT)
+
+#define __HEAD_FLAGS           (__HEAD_FLAG(BE))
+
+#define RISCV_HEADER_VERSION_MAJOR 0
+#define RISCV_HEADER_VERSION_MINOR 1
+
+#define RISCV_HEADER_VERSION (RISCV_HEADER_VERSION_MAJOR << 16 | \
+                             RISCV_HEADER_VERSION_MINOR)
+
+#ifndef __ASSEMBLY__
+/**
+ * struct riscv_image_header - riscv kernel image header
+ * @code0:             Executable code
+ * @code1:             Executable code
+ * @text_offset:       Image load offset (little endian)
+ * @image_size:                Effective Image size (little endian)
+ * @flags:             kernel flags (little endian)
+ * @version:           version
+ * @res1:              reserved
+ * @res2:              reserved
+ * @magic:             Magic number
+ * @res3:              reserved (will be used for additional RISC-V specific
+ *                     header)
+ * @res4:              reserved (will be used for PE COFF offset)
+ *
+ * The intention is for this header format to be shared between multiple
+ * architectures to avoid a proliferation of image header formats.
+ */
+
+struct riscv_image_header {
+       u32 code0;
+       u32 code1;
+       u64 text_offset;
+       u64 image_size;
+       u64 flags;
+       u32 version;
+       u32 res1;
+       u64 res2;
+       u64 magic;
+       u32 res3;
+       u32 res4;
+};
+#endif /* __ASSEMBLY__ */
+#endif /* __ASM_IMAGE_H */
index 8ddb6c7..707e00a 100644 (file)
 #define PAGE_SIZE      (_AC(1, UL) << PAGE_SHIFT)
 #define PAGE_MASK      (~(PAGE_SIZE - 1))
 
+#ifdef CONFIG_64BIT
+#define HUGE_MAX_HSTATE                2
+#else
+#define HUGE_MAX_HSTATE                1
+#endif
+#define HPAGE_SHIFT            PMD_SHIFT
+#define HPAGE_SIZE             (_AC(1, UL) << HPAGE_SHIFT)
+#define HPAGE_MASK              (~(HPAGE_SIZE - 1))
+#define HUGETLB_PAGE_ORDER      (HPAGE_SHIFT - PAGE_SHIFT)
+
 /*
  * PAGE_OFFSET -- the first address of the first page of memory.
  * When not using MMU this corresponds to the first free page in
@@ -115,8 +125,4 @@ extern unsigned long min_low_pfn;
 #include <asm-generic/memory_model.h>
 #include <asm-generic/getorder.h>
 
-/* vDSO support */
-/* We do define AT_SYSINFO_EHDR but don't use the gate mechanism */
-#define __HAVE_ARCH_GATE_AREA
-
 #endif /* _ASM_RISCV_PAGE_H */
index 45dfac2..7463098 100644 (file)
@@ -70,6 +70,11 @@ static inline pmd_t pfn_pmd(unsigned long pfn, pgprot_t prot)
        return __pmd((pfn << _PAGE_PFN_SHIFT) | pgprot_val(prot));
 }
 
+static inline unsigned long _pmd_pfn(pmd_t pmd)
+{
+       return pmd_val(pmd) >> _PAGE_PFN_SHIFT;
+}
+
 #define pmd_ERROR(e) \
        pr_err("%s:%d: bad pmd %016lx.\n", __FILE__, __LINE__, pmd_val(e))
 
index f7c3f7d..a364aba 100644 (file)
@@ -59,6 +59,8 @@
 #define PAGE_KERNEL            __pgprot(_PAGE_KERNEL)
 #define PAGE_KERNEL_EXEC       __pgprot(_PAGE_KERNEL | _PAGE_EXEC)
 
+#define PAGE_TABLE             __pgprot(_PAGE_TABLE)
+
 extern pgd_t swapper_pg_dir[];
 
 /* MAP_PRIVATE permissions: xwr (copy-on-write) */
@@ -113,12 +115,16 @@ static inline void pmd_clear(pmd_t *pmdp)
        set_pmd(pmdp, __pmd(0));
 }
 
-
 static inline pgd_t pfn_pgd(unsigned long pfn, pgprot_t prot)
 {
        return __pgd((pfn << _PAGE_PFN_SHIFT) | pgprot_val(prot));
 }
 
+static inline unsigned long _pgd_pfn(pgd_t pgd)
+{
+       return pgd_val(pgd) >> _PAGE_PFN_SHIFT;
+}
+
 #define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
 
 /* Locate an entry in the page global directory */
@@ -250,6 +256,11 @@ static inline pte_t pte_mkspecial(pte_t pte)
        return __pte(pte_val(pte) | _PAGE_SPECIAL);
 }
 
+static inline pte_t pte_mkhuge(pte_t pte)
+{
+       return pte;
+}
+
 /* Modify page protection bits */
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
@@ -396,6 +407,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
 #define kern_addr_valid(addr)   (1) /* FIXME */
 #endif
 
+extern void *dtb_early_va;
 extern void setup_bootmem(void);
 extern void paging_init(void);
 
@@ -409,7 +421,7 @@ static inline void pgtable_cache_init(void)
 #define VMALLOC_START    (PAGE_OFFSET - VMALLOC_SIZE)
 
 /*
- * Task size is 0x40000000000 for RV64 or 0xb800000 for RV32.
+ * Task size is 0x4000000000 for RV64 or 0xb800000 for RV32.
  * Note that PGDIR_SIZE must evenly divide TASK_SIZE.
  */
 #ifdef CONFIG_64BIT
index 0e2eeeb..13ce76c 100644 (file)
@@ -18,6 +18,7 @@
 #ifdef __LP64__
 #define __ARCH_WANT_NEW_STAT
 #define __ARCH_WANT_SET_GET_RLIMIT
+#define __ARCH_WANT_SYS_CLONE3
 #endif /* __LP64__ */
 
 #include <asm-generic/unistd.h>
index 4e46f31..0f1ba17 100644 (file)
 #include <asm/thread_info.h>
 #include <asm/page.h>
 #include <asm/csr.h>
+#include <asm/image.h>
 
 __INIT
 ENTRY(_start)
+       /*
+        * Image header expected by Linux boot-loaders. The image header data
+        * structure is described in asm/image.h.
+        * Do not modify it without modifying the structure and all bootloaders
+        * that expects this header format!!
+        */
+       /* jump to start kernel */
+       j _start_kernel
+       /* reserved */
+       .word 0
+       .balign 8
+#if __riscv_xlen == 64
+       /* Image load offset(2MB) from start of RAM */
+       .dword 0x200000
+#else
+       /* Image load offset(4MB) from start of RAM */
+       .dword 0x400000
+#endif
+       /* Effective size of kernel image */
+       .dword _end - _start
+       .dword __HEAD_FLAGS
+       .word RISCV_HEADER_VERSION
+       .word 0
+       .dword 0
+       .asciz RISCV_IMAGE_MAGIC
+       .word 0
+       .balign 4
+       .word 0
+
+.global _start_kernel
+_start_kernel:
        /* Mask all interrupts */
        csrw CSR_SIE, zero
        csrw CSR_SIP, zero
@@ -55,7 +87,9 @@ clear_bss_done:
 
        /* Initialize page tables and relocate to virtual addresses */
        la sp, init_thread_union + THREAD_SIZE
+       mv a0, s1
        call setup_vm
+       la a0, early_pg_dir
        call relocate
 
        /* Restore C environment */
@@ -64,25 +98,23 @@ clear_bss_done:
        la sp, init_thread_union + THREAD_SIZE
 
        /* Start the kernel */
-       mv a0, s1
        call parse_dtb
        tail start_kernel
 
 relocate:
        /* Relocate return address */
        li a1, PAGE_OFFSET
-       la a0, _start
-       sub a1, a1, a0
+       la a2, _start
+       sub a1, a1, a2
        add ra, ra, a1
 
        /* Point stvec to virtual address of intruction after satp write */
-       la a0, 1f
-       add a0, a0, a1
-       csrw CSR_STVEC, a0
+       la a2, 1f
+       add a2, a2, a1
+       csrw CSR_STVEC, a2
 
        /* Compute satp for kernel page tables, but don't load it yet */
-       la a2, swapper_pg_dir
-       srl a2, a2, PAGE_SHIFT
+       srl a2, a0, PAGE_SHIFT
        li a1, SATP_MODE
        or a2, a2, a1
 
@@ -148,6 +180,7 @@ relocate:
        fence
 
        /* Enable virtual memory and relocate to virtual address */
+       la a0, swapper_pg_dir
        call relocate
 
        tail smp_callin
index b92e683..a990a6c 100644 (file)
@@ -39,11 +39,9 @@ struct screen_info screen_info = {
 atomic_t hart_lottery;
 unsigned long boot_cpu_hartid;
 
-void __init parse_dtb(phys_addr_t dtb_phys)
+void __init parse_dtb(void)
 {
-       void *dtb = __va(dtb_phys);
-
-       if (early_init_dt_scan(dtb))
+       if (early_init_dt_scan(dtb_early_va))
                return;
 
        pr_err("No DTB passed to the kernel\n");
index a0084c3..c9c21e0 100644 (file)
@@ -92,22 +92,3 @@ const char *arch_vma_name(struct vm_area_struct *vma)
                return "[vdso]";
        return NULL;
 }
-
-/*
- * Function stubs to prevent linker errors when AT_SYSINFO_EHDR is defined
- */
-
-int in_gate_area_no_mm(unsigned long addr)
-{
-       return 0;
-}
-
-int in_gate_area(struct mm_struct *mm, unsigned long addr)
-{
-       return 0;
-}
-
-struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
-{
-       return NULL;
-}
index fc51d3b..74055e1 100644 (file)
@@ -12,3 +12,5 @@ obj-y += ioremap.o
 obj-y += cacheflush.o
 obj-y += context.o
 obj-y += sifive_l2_cache.o
+
+obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
diff --git a/arch/riscv/mm/hugetlbpage.c b/arch/riscv/mm/hugetlbpage.c
new file mode 100644 (file)
index 0000000..0d4747e
--- /dev/null
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/hugetlb.h>
+#include <linux/err.h>
+
+int pud_huge(pud_t pud)
+{
+       return pud_present(pud) &&
+               (pud_val(pud) & (_PAGE_READ | _PAGE_WRITE | _PAGE_EXEC));
+}
+
+int pmd_huge(pmd_t pmd)
+{
+       return pmd_present(pmd) &&
+               (pmd_val(pmd) & (_PAGE_READ | _PAGE_WRITE | _PAGE_EXEC));
+}
+
+static __init int setup_hugepagesz(char *opt)
+{
+       unsigned long ps = memparse(opt, &opt);
+
+       if (ps == HPAGE_SIZE) {
+               hugetlb_add_hstate(HPAGE_SHIFT - PAGE_SHIFT);
+       } else if (IS_ENABLED(CONFIG_64BIT) && ps == PUD_SIZE) {
+               hugetlb_add_hstate(PUD_SHIFT - PAGE_SHIFT);
+       } else {
+               hugetlb_bad_size();
+               pr_err("hugepagesz: Unsupported page size %lu M\n", ps >> 20);
+               return 0;
+       }
+
+       return 1;
+}
+__setup("hugepagesz=", setup_hugepagesz);
+
+#ifdef CONFIG_CONTIG_ALLOC
+static __init int gigantic_pages_init(void)
+{
+       /* With CONTIG_ALLOC, we can allocate gigantic pages at runtime */
+       if (IS_ENABLED(CONFIG_64BIT) && !size_to_hstate(1UL << PUD_SHIFT))
+               hugetlb_add_hstate(PUD_SHIFT - PAGE_SHIFT);
+       return 0;
+}
+arch_initcall(gigantic_pages_init);
+#endif
index 84747d7..42bf939 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (C) 2012 Regents of the University of California
+ * Copyright (C) 2019 Western Digital Corporation or its affiliates.
  */
 
 #include <linux/init.h>
@@ -21,6 +22,8 @@ unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]
                                                        __page_aligned_bss;
 EXPORT_SYMBOL(empty_zero_page);
 
+extern char _start[];
+
 static void __init zone_sizes_init(void)
 {
        unsigned long max_zone_pfns[MAX_NR_ZONES] = { 0, };
@@ -39,13 +42,6 @@ void setup_zero_page(void)
        memset((void *)empty_zero_page, 0, PAGE_SIZE);
 }
 
-void __init paging_init(void)
-{
-       setup_zero_page();
-       local_flush_tlb_all();
-       zone_sizes_init();
-}
-
 void __init mem_init(void)
 {
 #ifdef CONFIG_FLATMEM
@@ -84,29 +80,20 @@ disable:
        initrd_start = 0;
        initrd_end = 0;
 }
-
-void __init free_initrd_mem(unsigned long start, unsigned long end)
-{
-       free_reserved_area((void *)start, (void *)end, -1, "initrd");
-}
 #endif /* CONFIG_BLK_DEV_INITRD */
 
 void __init setup_bootmem(void)
 {
        struct memblock_region *reg;
        phys_addr_t mem_size = 0;
+       phys_addr_t vmlinux_end = __pa(&_end);
+       phys_addr_t vmlinux_start = __pa(&_start);
 
        /* Find the memory region containing the kernel */
        for_each_memblock(memory, reg) {
-               phys_addr_t vmlinux_end = __pa(_end);
                phys_addr_t end = reg->base + reg->size;
 
                if (reg->base <= vmlinux_end && vmlinux_end <= end) {
-                       /*
-                        * Reserve from the start of the region to the end of
-                        * the kernel
-                        */
-                       memblock_reserve(reg->base, vmlinux_end - reg->base);
                        mem_size = min(reg->size, (phys_addr_t)-PAGE_OFFSET);
 
                        /*
@@ -120,6 +107,9 @@ void __init setup_bootmem(void)
        }
        BUG_ON(mem_size == 0);
 
+       /* Reserve from the start of the kernel to the end of the kernel */
+       memblock_reserve(vmlinux_start, vmlinux_end - vmlinux_start);
+
        set_max_mapnr(PFN_DOWN(mem_size));
        max_low_pfn = PFN_DOWN(memblock_end_of_DRAM());
 
@@ -147,17 +137,15 @@ EXPORT_SYMBOL(va_pa_offset);
 unsigned long pfn_base;
 EXPORT_SYMBOL(pfn_base);
 
+void *dtb_early_va;
 pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned_bss;
-pgd_t trampoline_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE);
+pgd_t trampoline_pg_dir[PTRS_PER_PGD] __page_aligned_bss;
+pte_t fixmap_pte[PTRS_PER_PTE] __page_aligned_bss;
+static bool mmu_enabled;
 
-#ifndef __PAGETABLE_PMD_FOLDED
-#define NUM_SWAPPER_PMDS ((uintptr_t)-PAGE_OFFSET >> PGDIR_SHIFT)
-pmd_t swapper_pmd[PTRS_PER_PMD*((-PAGE_OFFSET)/PGDIR_SIZE)] __page_aligned_bss;
-pmd_t trampoline_pmd[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE);
-pmd_t fixmap_pmd[PTRS_PER_PMD] __page_aligned_bss;
-#endif
+#define MAX_EARLY_MAPPING_SIZE SZ_128M
 
-pte_t fixmap_pte[PTRS_PER_PTE] __page_aligned_bss;
+pgd_t early_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE);
 
 void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot)
 {
@@ -176,6 +164,156 @@ void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot)
        }
 }
 
+static pte_t *__init get_pte_virt(phys_addr_t pa)
+{
+       if (mmu_enabled) {
+               clear_fixmap(FIX_PTE);
+               return (pte_t *)set_fixmap_offset(FIX_PTE, pa);
+       } else {
+               return (pte_t *)((uintptr_t)pa);
+       }
+}
+
+static phys_addr_t __init alloc_pte(uintptr_t va)
+{
+       /*
+        * We only create PMD or PGD early mappings so we
+        * should never reach here with MMU disabled.
+        */
+       BUG_ON(!mmu_enabled);
+
+       return memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE);
+}
+
+static void __init create_pte_mapping(pte_t *ptep,
+                                     uintptr_t va, phys_addr_t pa,
+                                     phys_addr_t sz, pgprot_t prot)
+{
+       uintptr_t pte_index = pte_index(va);
+
+       BUG_ON(sz != PAGE_SIZE);
+
+       if (pte_none(ptep[pte_index]))
+               ptep[pte_index] = pfn_pte(PFN_DOWN(pa), prot);
+}
+
+#ifndef __PAGETABLE_PMD_FOLDED
+
+pmd_t trampoline_pmd[PTRS_PER_PMD] __page_aligned_bss;
+pmd_t fixmap_pmd[PTRS_PER_PMD] __page_aligned_bss;
+
+#if MAX_EARLY_MAPPING_SIZE < PGDIR_SIZE
+#define NUM_EARLY_PMDS         1UL
+#else
+#define NUM_EARLY_PMDS         (1UL + MAX_EARLY_MAPPING_SIZE / PGDIR_SIZE)
+#endif
+pmd_t early_pmd[PTRS_PER_PMD * NUM_EARLY_PMDS] __initdata __aligned(PAGE_SIZE);
+
+static pmd_t *__init get_pmd_virt(phys_addr_t pa)
+{
+       if (mmu_enabled) {
+               clear_fixmap(FIX_PMD);
+               return (pmd_t *)set_fixmap_offset(FIX_PMD, pa);
+       } else {
+               return (pmd_t *)((uintptr_t)pa);
+       }
+}
+
+static phys_addr_t __init alloc_pmd(uintptr_t va)
+{
+       uintptr_t pmd_num;
+
+       if (mmu_enabled)
+               return memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE);
+
+       pmd_num = (va - PAGE_OFFSET) >> PGDIR_SHIFT;
+       BUG_ON(pmd_num >= NUM_EARLY_PMDS);
+       return (uintptr_t)&early_pmd[pmd_num * PTRS_PER_PMD];
+}
+
+static void __init create_pmd_mapping(pmd_t *pmdp,
+                                     uintptr_t va, phys_addr_t pa,
+                                     phys_addr_t sz, pgprot_t prot)
+{
+       pte_t *ptep;
+       phys_addr_t pte_phys;
+       uintptr_t pmd_index = pmd_index(va);
+
+       if (sz == PMD_SIZE) {
+               if (pmd_none(pmdp[pmd_index]))
+                       pmdp[pmd_index] = pfn_pmd(PFN_DOWN(pa), prot);
+               return;
+       }
+
+       if (pmd_none(pmdp[pmd_index])) {
+               pte_phys = alloc_pte(va);
+               pmdp[pmd_index] = pfn_pmd(PFN_DOWN(pte_phys), PAGE_TABLE);
+               ptep = get_pte_virt(pte_phys);
+               memset(ptep, 0, PAGE_SIZE);
+       } else {
+               pte_phys = PFN_PHYS(_pmd_pfn(pmdp[pmd_index]));
+               ptep = get_pte_virt(pte_phys);
+       }
+
+       create_pte_mapping(ptep, va, pa, sz, prot);
+}
+
+#define pgd_next_t             pmd_t
+#define alloc_pgd_next(__va)   alloc_pmd(__va)
+#define get_pgd_next_virt(__pa)        get_pmd_virt(__pa)
+#define create_pgd_next_mapping(__nextp, __va, __pa, __sz, __prot)     \
+       create_pmd_mapping(__nextp, __va, __pa, __sz, __prot)
+#define PTE_PARENT_SIZE                PMD_SIZE
+#define fixmap_pgd_next                fixmap_pmd
+#else
+#define pgd_next_t             pte_t
+#define alloc_pgd_next(__va)   alloc_pte(__va)
+#define get_pgd_next_virt(__pa)        get_pte_virt(__pa)
+#define create_pgd_next_mapping(__nextp, __va, __pa, __sz, __prot)     \
+       create_pte_mapping(__nextp, __va, __pa, __sz, __prot)
+#define PTE_PARENT_SIZE                PGDIR_SIZE
+#define fixmap_pgd_next                fixmap_pte
+#endif
+
+static void __init create_pgd_mapping(pgd_t *pgdp,
+                                     uintptr_t va, phys_addr_t pa,
+                                     phys_addr_t sz, pgprot_t prot)
+{
+       pgd_next_t *nextp;
+       phys_addr_t next_phys;
+       uintptr_t pgd_index = pgd_index(va);
+
+       if (sz == PGDIR_SIZE) {
+               if (pgd_val(pgdp[pgd_index]) == 0)
+                       pgdp[pgd_index] = pfn_pgd(PFN_DOWN(pa), prot);
+               return;
+       }
+
+       if (pgd_val(pgdp[pgd_index]) == 0) {
+               next_phys = alloc_pgd_next(va);
+               pgdp[pgd_index] = pfn_pgd(PFN_DOWN(next_phys), PAGE_TABLE);
+               nextp = get_pgd_next_virt(next_phys);
+               memset(nextp, 0, PAGE_SIZE);
+       } else {
+               next_phys = PFN_PHYS(_pgd_pfn(pgdp[pgd_index]));
+               nextp = get_pgd_next_virt(next_phys);
+       }
+
+       create_pgd_next_mapping(nextp, va, pa, sz, prot);
+}
+
+static uintptr_t __init best_map_size(phys_addr_t base, phys_addr_t size)
+{
+       uintptr_t map_size = PAGE_SIZE;
+
+       /* Upgrade to PMD/PGDIR mappings whenever possible */
+       if (!(base & (PTE_PARENT_SIZE - 1)) &&
+           !(size & (PTE_PARENT_SIZE - 1)))
+               map_size = PTE_PARENT_SIZE;
+
+       return map_size;
+}
+
 /*
  * setup_vm() is called from head.S with MMU-off.
  *
@@ -195,55 +333,115 @@ void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot)
        "not use absolute addressing."
 #endif
 
-asmlinkage void __init setup_vm(void)
+asmlinkage void __init setup_vm(uintptr_t dtb_pa)
 {
-       extern char _start;
-       uintptr_t i;
-       uintptr_t pa = (uintptr_t) &_start;
-       pgprot_t prot = __pgprot(pgprot_val(PAGE_KERNEL) | _PAGE_EXEC);
+       uintptr_t va, end_va;
+       uintptr_t load_pa = (uintptr_t)(&_start);
+       uintptr_t load_sz = (uintptr_t)(&_end) - load_pa;
+       uintptr_t map_size = best_map_size(load_pa, MAX_EARLY_MAPPING_SIZE);
 
-       va_pa_offset = PAGE_OFFSET - pa;
-       pfn_base = PFN_DOWN(pa);
+       va_pa_offset = PAGE_OFFSET - load_pa;
+       pfn_base = PFN_DOWN(load_pa);
+
+       /*
+        * Enforce boot alignment requirements of RV32 and
+        * RV64 by only allowing PMD or PGD mappings.
+        */
+       BUG_ON(map_size == PAGE_SIZE);
 
        /* Sanity check alignment and size */
        BUG_ON((PAGE_OFFSET % PGDIR_SIZE) != 0);
-       BUG_ON((pa % (PAGE_SIZE * PTRS_PER_PTE)) != 0);
+       BUG_ON((load_pa % map_size) != 0);
+       BUG_ON(load_sz > MAX_EARLY_MAPPING_SIZE);
+
+       /* Setup early PGD for fixmap */
+       create_pgd_mapping(early_pg_dir, FIXADDR_START,
+                          (uintptr_t)fixmap_pgd_next, PGDIR_SIZE, PAGE_TABLE);
 
 #ifndef __PAGETABLE_PMD_FOLDED
-       trampoline_pg_dir[(PAGE_OFFSET >> PGDIR_SHIFT) % PTRS_PER_PGD] =
-               pfn_pgd(PFN_DOWN((uintptr_t)trampoline_pmd),
-                       __pgprot(_PAGE_TABLE));
-       trampoline_pmd[0] = pfn_pmd(PFN_DOWN(pa), prot);
+       /* Setup fixmap PMD */
+       create_pmd_mapping(fixmap_pmd, FIXADDR_START,
+                          (uintptr_t)fixmap_pte, PMD_SIZE, PAGE_TABLE);
+       /* Setup trampoline PGD and PMD */
+       create_pgd_mapping(trampoline_pg_dir, PAGE_OFFSET,
+                          (uintptr_t)trampoline_pmd, PGDIR_SIZE, PAGE_TABLE);
+       create_pmd_mapping(trampoline_pmd, PAGE_OFFSET,
+                          load_pa, PMD_SIZE, PAGE_KERNEL_EXEC);
+#else
+       /* Setup trampoline PGD */
+       create_pgd_mapping(trampoline_pg_dir, PAGE_OFFSET,
+                          load_pa, PGDIR_SIZE, PAGE_KERNEL_EXEC);
+#endif
 
-       for (i = 0; i < (-PAGE_OFFSET)/PGDIR_SIZE; ++i) {
-               size_t o = (PAGE_OFFSET >> PGDIR_SHIFT) % PTRS_PER_PGD + i;
+       /*
+        * Setup early PGD covering entire kernel which will allows
+        * us to reach paging_init(). We map all memory banks later
+        * in setup_vm_final() below.
+        */
+       end_va = PAGE_OFFSET + load_sz;
+       for (va = PAGE_OFFSET; va < end_va; va += map_size)
+               create_pgd_mapping(early_pg_dir, va,
+                                  load_pa + (va - PAGE_OFFSET),
+                                  map_size, PAGE_KERNEL_EXEC);
+
+       /* Create fixed mapping for early FDT parsing */
+       end_va = __fix_to_virt(FIX_FDT) + FIX_FDT_SIZE;
+       for (va = __fix_to_virt(FIX_FDT); va < end_va; va += PAGE_SIZE)
+               create_pte_mapping(fixmap_pte, va,
+                                  dtb_pa + (va - __fix_to_virt(FIX_FDT)),
+                                  PAGE_SIZE, PAGE_KERNEL);
+
+       /* Save pointer to DTB for early FDT parsing */
+       dtb_early_va = (void *)fix_to_virt(FIX_FDT) + (dtb_pa & ~PAGE_MASK);
+}
 
-               swapper_pg_dir[o] =
-                       pfn_pgd(PFN_DOWN((uintptr_t)swapper_pmd) + i,
-                               __pgprot(_PAGE_TABLE));
-       }
-       for (i = 0; i < ARRAY_SIZE(swapper_pmd); i++)
-               swapper_pmd[i] = pfn_pmd(PFN_DOWN(pa + i * PMD_SIZE), prot);
-
-       swapper_pg_dir[(FIXADDR_START >> PGDIR_SHIFT) % PTRS_PER_PGD] =
-               pfn_pgd(PFN_DOWN((uintptr_t)fixmap_pmd),
-                               __pgprot(_PAGE_TABLE));
-       fixmap_pmd[(FIXADDR_START >> PMD_SHIFT) % PTRS_PER_PMD] =
-               pfn_pmd(PFN_DOWN((uintptr_t)fixmap_pte),
-                               __pgprot(_PAGE_TABLE));
-#else
-       trampoline_pg_dir[(PAGE_OFFSET >> PGDIR_SHIFT) % PTRS_PER_PGD] =
-               pfn_pgd(PFN_DOWN(pa), prot);
+static void __init setup_vm_final(void)
+{
+       uintptr_t va, map_size;
+       phys_addr_t pa, start, end;
+       struct memblock_region *reg;
 
-       for (i = 0; i < (-PAGE_OFFSET)/PGDIR_SIZE; ++i) {
-               size_t o = (PAGE_OFFSET >> PGDIR_SHIFT) % PTRS_PER_PGD + i;
+       /* Set mmu_enabled flag */
+       mmu_enabled = true;
 
-               swapper_pg_dir[o] =
-                       pfn_pgd(PFN_DOWN(pa + i * PGDIR_SIZE), prot);
+       /* Setup swapper PGD for fixmap */
+       create_pgd_mapping(swapper_pg_dir, FIXADDR_START,
+                          __pa(fixmap_pgd_next),
+                          PGDIR_SIZE, PAGE_TABLE);
+
+       /* Map all memory banks */
+       for_each_memblock(memory, reg) {
+               start = reg->base;
+               end = start + reg->size;
+
+               if (start >= end)
+                       break;
+               if (memblock_is_nomap(reg))
+                       continue;
+               if (start <= __pa(PAGE_OFFSET) &&
+                   __pa(PAGE_OFFSET) < end)
+                       start = __pa(PAGE_OFFSET);
+
+               map_size = best_map_size(start, end - start);
+               for (pa = start; pa < end; pa += map_size) {
+                       va = (uintptr_t)__va(pa);
+                       create_pgd_mapping(swapper_pg_dir, va, pa,
+                                          map_size, PAGE_KERNEL_EXEC);
+               }
        }
 
-       swapper_pg_dir[(FIXADDR_START >> PGDIR_SHIFT) % PTRS_PER_PGD] =
-               pfn_pgd(PFN_DOWN((uintptr_t)fixmap_pte),
-                               __pgprot(_PAGE_TABLE));
-#endif
+       /* Clear fixmap PTE and PMD mappings */
+       clear_fixmap(FIX_PTE);
+       clear_fixmap(FIX_PMD);
+
+       /* Move to swapper page table */
+       csr_write(sptbr, PFN_DOWN(__pa(swapper_pg_dir)) | SATP_MODE);
+       local_flush_tlb_all();
+}
+
+void __init paging_init(void)
+{
+       setup_vm_final();
+       setup_zero_page();
+       zone_sizes_init();
 }
index 4eb6461..2e637ad 100644 (file)
@@ -109,13 +109,14 @@ EXPORT_SYMBOL_GPL(unregister_sifive_l2_error_notifier);
 
 static irqreturn_t l2_int_handler(int irq, void *device)
 {
-       unsigned int regval, add_h, add_l;
+       unsigned int add_h, add_l;
 
        if (irq == g_irq[DIR_CORR]) {
                add_h = readl(l2_base + SIFIVE_L2_DIRECCFIX_HIGH);
                add_l = readl(l2_base + SIFIVE_L2_DIRECCFIX_LOW);
                pr_err("L2CACHE: DirError @ 0x%08X.%08X\n", add_h, add_l);
-               regval = readl(l2_base + SIFIVE_L2_DIRECCFIX_COUNT);
+               /* Reading this register clears the DirError interrupt sig */
+               readl(l2_base + SIFIVE_L2_DIRECCFIX_COUNT);
                atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_CE,
                                           "DirECCFix");
        }
@@ -123,7 +124,8 @@ static irqreturn_t l2_int_handler(int irq, void *device)
                add_h = readl(l2_base + SIFIVE_L2_DATECCFIX_HIGH);
                add_l = readl(l2_base + SIFIVE_L2_DATECCFIX_LOW);
                pr_err("L2CACHE: DataError @ 0x%08X.%08X\n", add_h, add_l);
-               regval = readl(l2_base + SIFIVE_L2_DATECCFIX_COUNT);
+               /* Reading this register clears the DataError interrupt sig */
+               readl(l2_base + SIFIVE_L2_DATECCFIX_COUNT);
                atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_CE,
                                           "DatECCFix");
        }
@@ -131,7 +133,8 @@ static irqreturn_t l2_int_handler(int irq, void *device)
                add_h = readl(l2_base + SIFIVE_L2_DATECCFAIL_HIGH);
                add_l = readl(l2_base + SIFIVE_L2_DATECCFAIL_LOW);
                pr_err("L2CACHE: DataFail @ 0x%08X.%08X\n", add_h, add_l);
-               regval = readl(l2_base + SIFIVE_L2_DATECCFAIL_COUNT);
+               /* Reading this register clears the DataFail interrupt sig */
+               readl(l2_base + SIFIVE_L2_DATECCFAIL_COUNT);
                atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_UE,
                                           "DatECCFail");
        }
index 5d8570e..a4ad273 100644 (file)
@@ -189,6 +189,7 @@ config S390
        select VIRT_CPU_ACCOUNTING
        select ARCH_HAS_SCALED_CPUTIME
        select HAVE_NMI
+       select ARCH_HAS_FORCE_DMA_UNENCRYPTED
        select SWIOTLB
        select GENERIC_ALLOCATOR
 
index e4b5824..aa738ca 100644 (file)
@@ -220,15 +220,13 @@ appldata_timer_handler(struct ctl_table *ctl, int write,
                           void __user *buffer, size_t *lenp, loff_t *ppos)
 {
        int timer_active = appldata_timer_active;
-       int zero = 0;
-       int one = 1;
        int rc;
        struct ctl_table ctl_entry = {
                .procname       = ctl->procname,
                .data           = &timer_active,
                .maxlen         = sizeof(int),
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        };
 
        rc = proc_douintvec_minmax(&ctl_entry, write, buffer, lenp, ppos);
@@ -255,13 +253,12 @@ appldata_interval_handler(struct ctl_table *ctl, int write,
                           void __user *buffer, size_t *lenp, loff_t *ppos)
 {
        int interval = appldata_interval;
-       int one = 1;
        int rc;
        struct ctl_table ctl_entry = {
                .procname       = ctl->procname,
                .data           = &interval,
                .maxlen         = sizeof(int),
-               .extra1         = &one,
+               .extra1         = SYSCTL_ONE,
        };
 
        rc = proc_dointvec_minmax(&ctl_entry, write, buffer, lenp, ppos);
@@ -289,13 +286,11 @@ appldata_generic_handler(struct ctl_table *ctl, int write,
        struct list_head *lh;
        int rc, found;
        int active;
-       int zero = 0;
-       int one = 1;
        struct ctl_table ctl_entry = {
                .data           = &active,
                .maxlen         = sizeof(int),
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        };
 
        found = 0;
index 0cf6b53..60f9075 100644 (file)
@@ -8,27 +8,27 @@
 #ifndef __ASM_CTL_REG_H
 #define __ASM_CTL_REG_H
 
-#include <linux/const.h>
-
-#define CR0_CLOCK_COMPARATOR_SIGN      _BITUL(63 - 10)
-#define CR0_EMERGENCY_SIGNAL_SUBMASK   _BITUL(63 - 49)
-#define CR0_EXTERNAL_CALL_SUBMASK      _BITUL(63 - 50)
-#define CR0_CLOCK_COMPARATOR_SUBMASK   _BITUL(63 - 52)
-#define CR0_CPU_TIMER_SUBMASK          _BITUL(63 - 53)
-#define CR0_SERVICE_SIGNAL_SUBMASK     _BITUL(63 - 54)
-#define CR0_UNUSED_56                  _BITUL(63 - 56)
-#define CR0_INTERRUPT_KEY_SUBMASK      _BITUL(63 - 57)
-#define CR0_MEASUREMENT_ALERT_SUBMASK  _BITUL(63 - 58)
-
-#define CR2_GUARDED_STORAGE            _BITUL(63 - 59)
-
-#define CR14_UNUSED_32                 _BITUL(63 - 32)
-#define CR14_UNUSED_33                 _BITUL(63 - 33)
-#define CR14_CHANNEL_REPORT_SUBMASK    _BITUL(63 - 35)
-#define CR14_RECOVERY_SUBMASK          _BITUL(63 - 36)
-#define CR14_DEGRADATION_SUBMASK       _BITUL(63 - 37)
-#define CR14_EXTERNAL_DAMAGE_SUBMASK   _BITUL(63 - 38)
-#define CR14_WARNING_SUBMASK           _BITUL(63 - 39)
+#include <linux/bits.h>
+
+#define CR0_CLOCK_COMPARATOR_SIGN      BIT(63 - 10)
+#define CR0_EMERGENCY_SIGNAL_SUBMASK   BIT(63 - 49)
+#define CR0_EXTERNAL_CALL_SUBMASK      BIT(63 - 50)
+#define CR0_CLOCK_COMPARATOR_SUBMASK   BIT(63 - 52)
+#define CR0_CPU_TIMER_SUBMASK          BIT(63 - 53)
+#define CR0_SERVICE_SIGNAL_SUBMASK     BIT(63 - 54)
+#define CR0_UNUSED_56                  BIT(63 - 56)
+#define CR0_INTERRUPT_KEY_SUBMASK      BIT(63 - 57)
+#define CR0_MEASUREMENT_ALERT_SUBMASK  BIT(63 - 58)
+
+#define CR2_GUARDED_STORAGE            BIT(63 - 59)
+
+#define CR14_UNUSED_32                 BIT(63 - 32)
+#define CR14_UNUSED_33                 BIT(63 - 33)
+#define CR14_CHANNEL_REPORT_SUBMASK    BIT(63 - 35)
+#define CR14_RECOVERY_SUBMASK          BIT(63 - 36)
+#define CR14_DEGRADATION_SUBMASK       BIT(63 - 37)
+#define CR14_EXTERNAL_DAMAGE_SUBMASK   BIT(63 - 38)
+#define CR14_WARNING_SUBMASK           BIT(63 - 39)
 
 #ifndef __ASSEMBLY__
 
index 1e5dc45..b160da8 100644 (file)
@@ -12,7 +12,7 @@
 #ifndef _ASM_S390_NMI_H
 #define _ASM_S390_NMI_H
 
-#include <linux/const.h>
+#include <linux/bits.h>
 #include <linux/types.h>
 
 #define MCIC_SUBCLASS_MASK     (1ULL<<63 | 1ULL<<62 | 1ULL<<61 | \
                                1ULL<<55 | 1ULL<<54 | 1ULL<<53 | \
                                1ULL<<52 | 1ULL<<47 | 1ULL<<46 | \
                                1ULL<<45 | 1ULL<<44)
-#define MCCK_CODE_SYSTEM_DAMAGE                _BITUL(63)
-#define MCCK_CODE_EXT_DAMAGE           _BITUL(63 - 5)
-#define MCCK_CODE_CP                   _BITUL(63 - 9)
-#define MCCK_CODE_CPU_TIMER_VALID      _BITUL(63 - 46)
-#define MCCK_CODE_PSW_MWP_VALID                _BITUL(63 - 20)
-#define MCCK_CODE_PSW_IA_VALID         _BITUL(63 - 23)
-#define MCCK_CODE_CR_VALID             _BITUL(63 - 29)
-#define MCCK_CODE_GS_VALID             _BITUL(63 - 36)
-#define MCCK_CODE_FC_VALID             _BITUL(63 - 43)
+#define MCCK_CODE_SYSTEM_DAMAGE                BIT(63)
+#define MCCK_CODE_EXT_DAMAGE           BIT(63 - 5)
+#define MCCK_CODE_CP                   BIT(63 - 9)
+#define MCCK_CODE_CPU_TIMER_VALID      BIT(63 - 46)
+#define MCCK_CODE_PSW_MWP_VALID                BIT(63 - 20)
+#define MCCK_CODE_PSW_IA_VALID         BIT(63 - 23)
+#define MCCK_CODE_CR_VALID             BIT(63 - 29)
+#define MCCK_CODE_GS_VALID             BIT(63 - 36)
+#define MCCK_CODE_FC_VALID             BIT(63 - 43)
 
 #ifndef __ASSEMBLY__
 
index 14883b1..d56c519 100644 (file)
@@ -12,7 +12,7 @@
 #ifndef __ASM_S390_PROCESSOR_H
 #define __ASM_S390_PROCESSOR_H
 
-#include <linux/const.h>
+#include <linux/bits.h>
 
 #define CIF_MCCK_PENDING       0       /* machine check handling is pending */
 #define CIF_ASCE_PRIMARY       1       /* primary asce needs fixup / uaccess */
 #define CIF_MCCK_GUEST         7       /* machine check happening in guest */
 #define CIF_DEDICATED_CPU      8       /* this CPU is dedicated */
 
-#define _CIF_MCCK_PENDING      _BITUL(CIF_MCCK_PENDING)
-#define _CIF_ASCE_PRIMARY      _BITUL(CIF_ASCE_PRIMARY)
-#define _CIF_ASCE_SECONDARY    _BITUL(CIF_ASCE_SECONDARY)
-#define _CIF_NOHZ_DELAY                _BITUL(CIF_NOHZ_DELAY)
-#define _CIF_FPU               _BITUL(CIF_FPU)
-#define _CIF_IGNORE_IRQ                _BITUL(CIF_IGNORE_IRQ)
-#define _CIF_ENABLED_WAIT      _BITUL(CIF_ENABLED_WAIT)
-#define _CIF_MCCK_GUEST                _BITUL(CIF_MCCK_GUEST)
-#define _CIF_DEDICATED_CPU     _BITUL(CIF_DEDICATED_CPU)
+#define _CIF_MCCK_PENDING      BIT(CIF_MCCK_PENDING)
+#define _CIF_ASCE_PRIMARY      BIT(CIF_ASCE_PRIMARY)
+#define _CIF_ASCE_SECONDARY    BIT(CIF_ASCE_SECONDARY)
+#define _CIF_NOHZ_DELAY                BIT(CIF_NOHZ_DELAY)
+#define _CIF_FPU               BIT(CIF_FPU)
+#define _CIF_IGNORE_IRQ                BIT(CIF_IGNORE_IRQ)
+#define _CIF_ENABLED_WAIT      BIT(CIF_ENABLED_WAIT)
+#define _CIF_MCCK_GUEST                BIT(CIF_MCCK_GUEST)
+#define _CIF_DEDICATED_CPU     BIT(CIF_DEDICATED_CPU)
 
 #ifndef __ASSEMBLY__
 
index 6f70d81..f009a13 100644 (file)
@@ -7,7 +7,7 @@
 #ifndef _S390_PTRACE_H
 #define _S390_PTRACE_H
 
-#include <linux/const.h>
+#include <linux/bits.h>
 #include <uapi/asm/ptrace.h>
 
 #define PIF_SYSCALL            0       /* inside a system call */
 #define PIF_SYSCALL_RESTART    2       /* restart the current system call */
 #define PIF_GUEST_FAULT                3       /* indicates program check in sie64a */
 
-#define _PIF_SYSCALL           _BITUL(PIF_SYSCALL)
-#define _PIF_PER_TRAP          _BITUL(PIF_PER_TRAP)
-#define _PIF_SYSCALL_RESTART   _BITUL(PIF_SYSCALL_RESTART)
-#define _PIF_GUEST_FAULT       _BITUL(PIF_GUEST_FAULT)
+#define _PIF_SYSCALL           BIT(PIF_SYSCALL)
+#define _PIF_PER_TRAP          BIT(PIF_PER_TRAP)
+#define _PIF_SYSCALL_RESTART   BIT(PIF_SYSCALL_RESTART)
+#define _PIF_GUEST_FAULT       BIT(PIF_GUEST_FAULT)
 
 #ifndef __ASSEMBLY__
 
index 925889d..82deb8f 100644 (file)
@@ -6,7 +6,7 @@
 #ifndef _ASM_S390_SETUP_H
 #define _ASM_S390_SETUP_H
 
-#include <linux/const.h>
+#include <linux/bits.h>
 #include <uapi/asm/setup.h>
 
 #define EP_OFFSET              0x10008
  * Machine features detected in early.c
  */
 
-#define MACHINE_FLAG_VM                _BITUL(0)
-#define MACHINE_FLAG_KVM       _BITUL(1)
-#define MACHINE_FLAG_LPAR      _BITUL(2)
-#define MACHINE_FLAG_DIAG9C    _BITUL(3)
-#define MACHINE_FLAG_ESOP      _BITUL(4)
-#define MACHINE_FLAG_IDTE      _BITUL(5)
-#define MACHINE_FLAG_DIAG44    _BITUL(6)
-#define MACHINE_FLAG_EDAT1     _BITUL(7)
-#define MACHINE_FLAG_EDAT2     _BITUL(8)
-#define MACHINE_FLAG_TOPOLOGY  _BITUL(10)
-#define MACHINE_FLAG_TE                _BITUL(11)
-#define MACHINE_FLAG_TLB_LC    _BITUL(12)
-#define MACHINE_FLAG_VX                _BITUL(13)
-#define MACHINE_FLAG_TLB_GUEST _BITUL(14)
-#define MACHINE_FLAG_NX                _BITUL(15)
-#define MACHINE_FLAG_GS                _BITUL(16)
-#define MACHINE_FLAG_SCC       _BITUL(17)
-
-#define LPP_MAGIC              _BITUL(31)
+#define MACHINE_FLAG_VM                BIT(0)
+#define MACHINE_FLAG_KVM       BIT(1)
+#define MACHINE_FLAG_LPAR      BIT(2)
+#define MACHINE_FLAG_DIAG9C    BIT(3)
+#define MACHINE_FLAG_ESOP      BIT(4)
+#define MACHINE_FLAG_IDTE      BIT(5)
+#define MACHINE_FLAG_DIAG44    BIT(6)
+#define MACHINE_FLAG_EDAT1     BIT(7)
+#define MACHINE_FLAG_EDAT2     BIT(8)
+#define MACHINE_FLAG_TOPOLOGY  BIT(10)
+#define MACHINE_FLAG_TE                BIT(11)
+#define MACHINE_FLAG_TLB_LC    BIT(12)
+#define MACHINE_FLAG_VX                BIT(13)
+#define MACHINE_FLAG_TLB_GUEST BIT(14)
+#define MACHINE_FLAG_NX                BIT(15)
+#define MACHINE_FLAG_GS                BIT(16)
+#define MACHINE_FLAG_SCC       BIT(17)
+
+#define LPP_MAGIC              BIT(31)
 #define LPP_PID_MASK           _AC(0xffffffff, UL)
 
 /* Offsets to entry points in kernel/head.S  */
index ce4e17c..e582fbe 100644 (file)
@@ -8,7 +8,7 @@
 #ifndef _ASM_THREAD_INFO_H
 #define _ASM_THREAD_INFO_H
 
-#include <linux/const.h>
+#include <linux/bits.h>
 
 /*
  * General size of kernel stacks
@@ -82,21 +82,21 @@ void arch_setup_new_exec(void);
 #define TIF_SECCOMP            26      /* secure computing */
 #define TIF_SYSCALL_TRACEPOINT 27      /* syscall tracepoint instrumentation */
 
-#define _TIF_NOTIFY_RESUME     _BITUL(TIF_NOTIFY_RESUME)
-#define _TIF_SIGPENDING                _BITUL(TIF_SIGPENDING)
-#define _TIF_NEED_RESCHED      _BITUL(TIF_NEED_RESCHED)
-#define _TIF_UPROBE            _BITUL(TIF_UPROBE)
-#define _TIF_GUARDED_STORAGE   _BITUL(TIF_GUARDED_STORAGE)
-#define _TIF_PATCH_PENDING     _BITUL(TIF_PATCH_PENDING)
-#define _TIF_ISOLATE_BP                _BITUL(TIF_ISOLATE_BP)
-#define _TIF_ISOLATE_BP_GUEST  _BITUL(TIF_ISOLATE_BP_GUEST)
-
-#define _TIF_31BIT             _BITUL(TIF_31BIT)
-#define _TIF_SINGLE_STEP       _BITUL(TIF_SINGLE_STEP)
-
-#define _TIF_SYSCALL_TRACE     _BITUL(TIF_SYSCALL_TRACE)
-#define _TIF_SYSCALL_AUDIT     _BITUL(TIF_SYSCALL_AUDIT)
-#define _TIF_SECCOMP           _BITUL(TIF_SECCOMP)
-#define _TIF_SYSCALL_TRACEPOINT        _BITUL(TIF_SYSCALL_TRACEPOINT)
+#define _TIF_NOTIFY_RESUME     BIT(TIF_NOTIFY_RESUME)
+#define _TIF_SIGPENDING                BIT(TIF_SIGPENDING)
+#define _TIF_NEED_RESCHED      BIT(TIF_NEED_RESCHED)
+#define _TIF_UPROBE            BIT(TIF_UPROBE)
+#define _TIF_GUARDED_STORAGE   BIT(TIF_GUARDED_STORAGE)
+#define _TIF_PATCH_PENDING     BIT(TIF_PATCH_PENDING)
+#define _TIF_ISOLATE_BP                BIT(TIF_ISOLATE_BP)
+#define _TIF_ISOLATE_BP_GUEST  BIT(TIF_ISOLATE_BP_GUEST)
+
+#define _TIF_31BIT             BIT(TIF_31BIT)
+#define _TIF_SINGLE_STEP       BIT(TIF_SINGLE_STEP)
+
+#define _TIF_SYSCALL_TRACE     BIT(TIF_SYSCALL_TRACE)
+#define _TIF_SYSCALL_AUDIT     BIT(TIF_SYSCALL_AUDIT)
+#define _TIF_SECCOMP           BIT(TIF_SECCOMP)
+#define _TIF_SYSCALL_TRACEPOINT        BIT(TIF_SYSCALL_TRACEPOINT)
 
 #endif /* _ASM_THREAD_INFO_H */
index 6ebacfe..a90d3e9 100644 (file)
 432  common    fsmount                 sys_fsmount                     sys_fsmount
 433  common    fspick                  sys_fspick                      sys_fspick
 434  common    pidfd_open              sys_pidfd_open                  sys_pidfd_open
+# 435 reserved for clone3
index 8964a3f..2db6fb4 100644 (file)
@@ -587,15 +587,13 @@ static int topology_ctl_handler(struct ctl_table *ctl, int write,
 {
        int enabled = topology_is_enabled();
        int new_mode;
-       int zero = 0;
-       int one = 1;
        int rc;
        struct ctl_table ctl_entry = {
                .procname       = ctl->procname,
                .data           = &enabled,
                .maxlen         = sizeof(int),
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        };
 
        rc = proc_douintvec_minmax(&ctl_entry, write, buffer, lenp, ppos);
index 9dde4d7..b5fd6e8 100644 (file)
@@ -1224,28 +1224,11 @@ no_timer:
 
 void kvm_s390_vcpu_wakeup(struct kvm_vcpu *vcpu)
 {
-       /*
-        * We cannot move this into the if, as the CPU might be already
-        * in kvm_vcpu_block without having the waitqueue set (polling)
-        */
        vcpu->valid_wakeup = true;
+       kvm_vcpu_wake_up(vcpu);
+
        /*
-        * This is mostly to document, that the read in swait_active could
-        * be moved before other stores, leading to subtle races.
-        * All current users do not store or use an atomic like update
-        */
-       smp_mb__after_atomic();
-       if (swait_active(&vcpu->wq)) {
-               /*
-                * The vcpu gave up the cpu voluntarily, mark it as a good
-                * yield-candidate.
-                */
-               vcpu->preempted = true;
-               swake_up_one(&vcpu->wq);
-               vcpu->stat.halt_wakeup++;
-       }
-       /*
-        * The VCPU might not be sleeping but is executing the VSIE. Let's
+        * The VCPU might not be sleeping but rather executing VSIE. Let's
         * kick it, so it leaves the SIE to process the request.
         */
        kvm_s390_vsie_kick(vcpu);
index 0ba174f..6350766 100644 (file)
@@ -67,20 +67,6 @@ static int __init fault_init(void)
 }
 early_initcall(fault_init);
 
-static inline int notify_page_fault(struct pt_regs *regs)
-{
-       int ret = 0;
-
-       /* kprobe_running() needs smp_processor_id() */
-       if (kprobes_built_in() && !user_mode(regs)) {
-               preempt_disable();
-               if (kprobe_running() && kprobe_fault_handler(regs, 14))
-                       ret = 1;
-               preempt_enable();
-       }
-       return ret;
-}
-
 /*
  * Find out which address space caused the exception.
  */
@@ -412,7 +398,7 @@ static inline vm_fault_t do_exception(struct pt_regs *regs, int access)
         */
        clear_pt_regs_flag(regs, PIF_PER_TRAP);
 
-       if (notify_page_fault(regs))
+       if (kprobe_page_fault(regs, 14))
                return 0;
 
        mm = tsk->mm;
index f0bee6a..20340a0 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/export.h>
 #include <linux/cma.h>
 #include <linux/gfp.h>
-#include <linux/dma-mapping.h>
+#include <linux/dma-direct.h>
 #include <asm/processor.h>
 #include <linux/uaccess.h>
 #include <asm/pgtable.h>
@@ -161,6 +161,11 @@ bool sev_active(void)
        return is_prot_virt_guest();
 }
 
+bool force_dma_unencrypted(struct device *dev)
+{
+       return sev_active();
+}
+
 /* protected virtualization */
 static void pv_init(void)
 {
@@ -273,6 +278,9 @@ int arch_add_memory(int nid, u64 start, u64 size,
        unsigned long size_pages = PFN_DOWN(size);
        int rc;
 
+       if (WARN_ON_ONCE(restrictions->altmap))
+               return -EINVAL;
+
        rc = vmem_add_mapping(start, size);
        if (rc)
                return rc;
@@ -283,16 +291,15 @@ int arch_add_memory(int nid, u64 start, u64 size,
        return rc;
 }
 
-#ifdef CONFIG_MEMORY_HOTREMOVE
 void arch_remove_memory(int nid, u64 start, u64 size,
                        struct vmem_altmap *altmap)
 {
-       /*
-        * There is no hardware or firmware interface which could trigger a
-        * hot memory remove on s390. So there is nothing that needs to be
-        * implemented.
-        */
-       BUG();
+       unsigned long start_pfn = start >> PAGE_SHIFT;
+       unsigned long nr_pages = size >> PAGE_SHIFT;
+       struct zone *zone;
+
+       zone = page_zone(pfn_to_page(start_pfn));
+       __remove_pages(zone, start_pfn, nr_pages, altmap);
+       vmem_remove_mapping(start, size);
 }
-#endif
 #endif /* CONFIG_MEMORY_HOTPLUG */
index 31a7d12..6b1b594 100644 (file)
@@ -626,7 +626,7 @@ config CRASH_DUMP
          to a memory address not used by the main kernel using
          PHYSICAL_START.
 
-         For more details see Documentation/kdump/kdump.rst
+         For more details see Documentation/admin-guide/kdump/kdump.rst
 
 config KEXEC_JUMP
        bool "kexec jump (EXPERIMENTAL)"
@@ -679,7 +679,7 @@ config SMP
          People using multiprocessor machines who say Y here should also say
          Y to "Enhanced Real Time Clock Support", below.
 
-         See also <file:Documentation/lockup-watchdogs.txt> and the SMP-HOWTO
+         See also <file:Documentation/admin-guide/lockup-watchdogs.rst> and the SMP-HOWTO
          available at <http://www.tldp.org/docs.html#howto>.
 
          If you don't know what to do here, say N.
index b9a3705..cee24c3 100644 (file)
@@ -8,27 +8,19 @@ config SH_ALPHA_BOARD
        bool
 
 config SH_DEVICE_TREE
-       bool "Board Described by Device Tree"
+       bool
        select OF
        select OF_EARLY_FLATTREE
        select TIMER_OF
        select COMMON_CLK
        select GENERIC_CALIBRATE_DELAY
-       help
-         Select Board Described by Device Tree to build a kernel that
-         does not hard-code any board-specific knowledge but instead uses
-         a device tree blob provided by the boot-loader. You must enable
-         drivers for any hardware you want to use separately. At this
-         time, only boards based on the open-hardware J-Core processors
-         have sufficient driver coverage to use this option; do not
-         select it if you are using original SuperH hardware.
 
 config SH_JCORE_SOC
        bool "J-Core SoC"
-       depends on SH_DEVICE_TREE && (CPU_SH2 || CPU_J2)
+       select SH_DEVICE_TREE
        select CLKSRC_JCORE_PIT
        select JCORE_AIC
-       default y if CPU_J2
+       depends on CPU_J2
        help
          Select this option to include drivers core components of the
          J-Core SoC, including interrupt controllers and timers.
index 0ef3f1f..cc6e4ce 100644 (file)
@@ -28,7 +28,6 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
index 6c7cdc3..530498f 100644 (file)
@@ -29,7 +29,6 @@ CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 # CONFIG_IPV6 is not set
 # CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
index d0d9ebc..6dd0da7 100644 (file)
@@ -53,7 +53,6 @@ CONFIG_NET_KEY=y
 CONFIG_INET=y
 # CONFIG_IPV6 is not set
 # CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
 CONFIG_MTD_CFI=y
index 5a90e24..911437c 100644 (file)
@@ -19,7 +19,6 @@ CONFIG_UNIX=y
 CONFIG_INET=y
 CONFIG_IP_PNP=y
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
index 1d27666..ae067e0 100644 (file)
@@ -32,7 +32,6 @@ CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_STANDALONE is not set
 # CONFIG_FW_LOADER is not set
 CONFIG_GDROM=y
index bdb61d1..5c60e71 100644 (file)
@@ -26,7 +26,6 @@ CONFIG_INET=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 # CONFIG_SCSI_LOWLEVEL is not set
index ba67e37..2fb7db4 100644 (file)
@@ -31,7 +31,6 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_IPV6 is not set
 CONFIG_IRDA=y
 CONFIG_SH_SIR=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
index aab4ff1..02ba622 100644 (file)
@@ -31,7 +31,6 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_DEBUG_DRIVER=y
 CONFIG_DEBUG_DEVRES=y
index 444d759..a5b865a 100644 (file)
@@ -26,7 +26,6 @@ CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
index 91d43e2..a92db66 100644 (file)
@@ -18,7 +18,6 @@ CONFIG_HD64461_ENABLER=y
 CONFIG_PCCARD=y
 CONFIG_PM=y
 CONFIG_APM_EMULATION=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_STANDALONE is not set
 CONFIG_BLK_DEV_SD=y
 CONFIG_ATA=y
index 9cc37f2..04436b4 100644 (file)
@@ -28,7 +28,6 @@ CONFIG_INET=y
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
 # CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_INPUT_MOUSEDEV is not set
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
index 46693d0..1dc3f67 100644 (file)
@@ -35,7 +35,6 @@ CONFIG_INET=y
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
 # CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
index 467f4d2..567af75 100644 (file)
@@ -26,7 +26,6 @@ CONFIG_IP_PNP=y
 # CONFIG_IPV6 is not set
 CONFIG_NETFILTER=y
 CONFIG_ATALK=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_IDE=y
index 9e3edfd..10f6d37 100644 (file)
@@ -29,7 +29,6 @@ CONFIG_IP_ADVANCED_ROUTER=y
 CONFIG_IP_PNP=y
 # CONFIG_IPV6 is not set
 CONFIG_NETFILTER=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_SD=y
index fb7415d..664c4de 100644 (file)
@@ -35,7 +35,6 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_MTD=y
index c3f7d58..ed84d13 100644 (file)
@@ -19,7 +19,6 @@ CONFIG_NET=y
 CONFIG_INET=y
 CONFIG_IP_PNP=y
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_IDE=y
index 121a75d..494a167 100644 (file)
@@ -26,7 +26,6 @@ CONFIG_INET=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_FW_LOADER=m
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
index 87641b7..e3a1d3d 100644 (file)
@@ -37,7 +37,6 @@ CONFIG_IP_MULTICAST=y
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
index 435bcd6..0a18f80 100644 (file)
@@ -36,7 +36,6 @@ CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 # CONFIG_IPV6 is not set
 CONFIG_BRIDGE=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_FW_LOADER=m
 CONFIG_MTD=y
 CONFIG_MTD_CFI=y
index 5877e6d..7226ac5 100644 (file)
@@ -43,7 +43,6 @@ CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 # CONFIG_IPV6 is not set
 CONFIG_BRIDGE=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_FW_LOADER=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_SD=y
index b195bc0..9f4f474 100644 (file)
@@ -31,7 +31,6 @@ CONFIG_BINFMT_ZFLAT=y
 CONFIG_BINFMT_SHARED_FLAT=y
 CONFIG_PM=y
 CONFIG_CPU_IDLE=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_FW_LOADER is not set
index 8c47195..10a32bd 100644 (file)
@@ -45,7 +45,6 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_FW_LOADER is not set
index ad003ee..2b0572b 100644 (file)
@@ -36,7 +36,6 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_FW_LOADER is not set
 CONFIG_BLK_DEV_LOOP=y
index 27fc01d..fb9fa7f 100644 (file)
@@ -25,7 +25,6 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
index 379d673..6a3cfe0 100644 (file)
@@ -22,7 +22,6 @@ CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_FW_LOADER=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_SD=y
index 11177bc..2b3d7d2 100644 (file)
@@ -22,7 +22,6 @@ CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_FW_LOADER=m
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
index 95e5208..d10a041 100644 (file)
@@ -41,7 +41,6 @@ CONFIG_IP_PNP_BOOTP=y
 CONFIG_IPV6=y
 # CONFIG_INET6_XFRM_MODE_BEET is not set
 CONFIG_NET_SCHED=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_PARPORT=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
index 49a2933..7fa116b 100644 (file)
@@ -91,7 +91,6 @@ CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 # CONFIG_IPV6 is not set
 # CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
index 3553acd..a93402b 100644 (file)
@@ -58,7 +58,6 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_FW_LOADER is not set
index fc77a67..06d067c 100644 (file)
@@ -28,7 +28,6 @@ CONFIG_INET=y
 CONFIG_SYN_COOKIES=y
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
index 1e11652..9a527f9 100644 (file)
@@ -63,7 +63,6 @@ CONFIG_NET_SCH_NETEM=y
 CONFIG_NET_CLS_TCINDEX=y
 CONFIG_NET_CLS_ROUTE4=y
 CONFIG_NET_CLS_FW=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
index c66e512..3b0e1eb 100644 (file)
@@ -62,7 +62,6 @@ CONFIG_NET_SCH_NETEM=y
 CONFIG_NET_CLS_TCINDEX=y
 CONFIG_NET_CLS_ROUTE4=y
 CONFIG_NET_CLS_FW=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
index ccc7fc4..88bf9e8 100644 (file)
@@ -26,7 +26,6 @@ CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_SD=y
index 9f6d46d..0e8d5cc 100644 (file)
@@ -30,7 +30,6 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
index 489ffdf..e5beb62 100644 (file)
@@ -34,7 +34,6 @@ CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 CONFIG_IP_PNP_RARP=y
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_FW_LOADER is not set
index cbd6742..99975db 100644 (file)
@@ -44,7 +44,6 @@ CONFIG_NET_IPIP=y
 # CONFIG_IPV6 is not set
 CONFIG_NETWORK_SECMARK=y
 CONFIG_NET_PKTGEN=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_CDROM_PKTCDVD=y
index 65a1aad..c86f284 100644 (file)
@@ -32,7 +32,6 @@ CONFIG_NET_CLS_BASIC=y
 CONFIG_NET_CLS_TCINDEX=y
 CONFIG_NET_CLS_ROUTE4=y
 CONFIG_NET_CLS_U32=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
index d04bc27..9adee90 100644 (file)
@@ -15,7 +15,6 @@ CONFIG_KEXEC=y
 CONFIG_KEXEC_JUMP=y
 CONFIG_HIBERNATION=y
 CONFIG_CPU_IDLE=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
index b0c4bc8..9f2aed0 100644 (file)
@@ -33,7 +33,6 @@ CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_IPV6=y
 # CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
index 405bf62..d0a0aa7 100644 (file)
@@ -26,7 +26,6 @@ CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLKDEVS=y
index e5b733c..c17590f 100644 (file)
@@ -17,7 +17,6 @@ CONFIG_KEXEC_JUMP=y
 CONFIG_PM=y
 CONFIG_HIBERNATION=y
 CONFIG_CPU_IDLE=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
index a89ccc1..9b885c1 100644 (file)
@@ -43,7 +43,6 @@ CONFIG_IP_ADVANCED_ROUTER=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
index 5201bb7..1b88929 100644 (file)
@@ -26,7 +26,6 @@ CONFIG_IP_ADVANCED_ROUTER=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
index 755c4f7..dc2be25 100644 (file)
@@ -59,7 +59,6 @@ CONFIG_CAN=m
 CONFIG_CAN_RAW=m
 CONFIG_CAN_BCM=m
 CONFIG_CAN_VCAN=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_SD=y
index 171ab05..4ec961a 100644 (file)
@@ -142,7 +142,6 @@ CONFIG_GACT_PROB=y
 CONFIG_NET_ACT_MIRRED=m
 CONFIG_NET_ACT_IPT=m
 CONFIG_NET_ACT_PEDIT=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_FW_LOADER=m
 CONFIG_CONNECTOR=m
 CONFIG_MTD=m
index 1b7412d..dc2e306 100644 (file)
@@ -33,7 +33,6 @@ CONFIG_CFG80211=y
 CONFIG_MAC80211=y
 CONFIG_MAC80211_RC_PID=y
 # CONFIG_MAC80211_RC_MINSTREL is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
index f891045..cb2f564 100644 (file)
@@ -46,7 +46,6 @@ CONFIG_IP_ADVANCED_ROUTER=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 # CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
index 1f8c0d3..318296f 100644 (file)
@@ -485,7 +485,8 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
        struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
 
        addr = (kprobe_opcode_t *) (args->regs->pc);
-       if (val == DIE_TRAP) {
+       if (val == DIE_TRAP &&
+           args->trapnr == (BREAKPOINT_INSTRUCTION & 0xff)) {
                if (!kprobe_running()) {
                        if (kprobe_handler(args->regs)) {
                                ret = NOTIFY_STOP;
index 834c9c7..b5ed26c 100644 (file)
 432    common  fsmount                         sys_fsmount
 433    common  fspick                          sys_fspick
 434    common  pidfd_open                      sys_pidfd_open
+# 435 reserved for clone3
index 3093bc3..5f51456 100644 (file)
 #include <asm/tlbflush.h>
 #include <asm/traps.h>
 
-static inline int notify_page_fault(struct pt_regs *regs, int trap)
-{
-       int ret = 0;
-
-       if (kprobes_built_in() && !user_mode(regs)) {
-               preempt_disable();
-               if (kprobe_running() && kprobe_fault_handler(regs, trap))
-                       ret = 1;
-               preempt_enable();
-       }
-
-       return ret;
-}
-
 static void
 force_sig_info_fault(int si_signo, int si_code, unsigned long address)
 {
@@ -412,14 +398,14 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
        if (unlikely(fault_in_kernel_space(address))) {
                if (vmalloc_fault(address) >= 0)
                        return;
-               if (notify_page_fault(regs, vec))
+               if (kprobe_page_fault(regs, vec))
                        return;
 
                bad_area_nosemaphore(regs, error_code, address);
                return;
        }
 
-       if (unlikely(notify_page_fault(regs, vec)))
+       if (unlikely(kprobe_page_fault(regs, vec)))
                return;
 
        /* Only enable interrupts if they were on before the fault */
index 13c6a6b..dfdbaa5 100644 (file)
@@ -429,7 +429,6 @@ int memory_add_physaddr_to_nid(u64 addr)
 EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
 #endif
 
-#ifdef CONFIG_MEMORY_HOTREMOVE
 void arch_remove_memory(int nid, u64 start, u64 size,
                        struct vmem_altmap *altmap)
 {
@@ -440,5 +439,4 @@ void arch_remove_memory(int nid, u64 start, u64 size,
        zone = page_zone(pfn_to_page(start_pfn));
        __remove_pages(zone, start_pfn, nr_pages, altmap);
 }
-#endif
 #endif /* CONFIG_MEMORY_HOTPLUG */
index e9f5d62..7926a2e 100644 (file)
@@ -180,7 +180,7 @@ config SMP
          Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
          Management" code will be disabled if you say Y here.
 
-         See also <file:Documentation/lockup-watchdogs.txt> and the SMP-HOWTO
+         See also <file:Documentation/admin-guide/lockup-watchdogs.rst> and the SMP-HOWTO
          available at <http://www.tldp.org/docs.html#howto>.
 
          If you don't know what to do here, say N.
index f6f99ec..cec9f41 100644 (file)
 #define MCL_FUTURE      0x4000          /* lock all additions to address space */
 #define MCL_ONFAULT    0x8000          /* lock all pages that are faulted in */
 
-#define MAP_POPULATE   0x8000          /* populate (prefault) pagetables */
-#define MAP_NONBLOCK   0x10000         /* do not block on IO */
-#define MAP_STACK      0x20000         /* give out an address that is best suited for process/thread stacks */
-#define MAP_HUGETLB    0x40000         /* create a huge page mapping */
-
-
 #endif /* _UAPI__SPARC_MMAN_H__ */
index c58e71f..8c8cc75 100644 (file)
 432    common  fsmount                         sys_fsmount
 433    common  fspick                          sys_fspick
 434    common  pidfd_open                      sys_pidfd_open
+# 435 reserved for clone3
index 83fda4d..2371fb6 100644 (file)
 
 int show_unhandled_signals = 1;
 
-static inline __kprobes int notify_page_fault(struct pt_regs *regs)
-{
-       int ret = 0;
-
-       /* kprobe_running() needs smp_processor_id() */
-       if (kprobes_built_in() && !user_mode(regs)) {
-               preempt_disable();
-               if (kprobe_running() && kprobe_fault_handler(regs, 0))
-                       ret = 1;
-               preempt_enable();
-       }
-       return ret;
-}
-
 static void __kprobes unhandled_fault(unsigned long address,
                                      struct task_struct *tsk,
                                      struct pt_regs *regs)
@@ -285,7 +271,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
 
        fault_code = get_thread_fault_code();
 
-       if (notify_page_fault(regs))
+       if (kprobe_page_fault(regs, 0))
                goto exit_exception;
 
        si_code = SEGV_MAPERR;
index 5a9e4e1..324a239 100644 (file)
@@ -115,8 +115,7 @@ quiet_cmd_vdso = VDSO    $@
                       -T $(filter %.lds,$^) $(filter %.o,$^) && \
                sh $(srctree)/$(src)/checkundef.sh '$(OBJDUMP)' '$@'
 
-VDSO_LDFLAGS = -shared $(call ld-option, --hash-style=both) \
-       $(call ld-option, --build-id) -Bsymbolic
+VDSO_LDFLAGS = -shared --hash-style=both --build-id -Bsymbolic
 GCOV_PROFILE := n
 
 #
index 8797413..222855c 100644 (file)
@@ -70,6 +70,7 @@ config X86
        select ARCH_HAS_KCOV                    if X86_64
        select ARCH_HAS_MEMBARRIER_SYNC_CORE
        select ARCH_HAS_PMEM_API                if X86_64
+       select ARCH_HAS_PTE_DEVMAP              if X86_64
        select ARCH_HAS_PTE_SPECIAL
        select ARCH_HAS_REFCOUNT
        select ARCH_HAS_UACCESS_FLUSHCACHE      if X86_64
@@ -80,7 +81,6 @@ config X86
        select ARCH_HAS_STRICT_MODULE_RWX
        select ARCH_HAS_SYNC_CORE_BEFORE_USERMODE
        select ARCH_HAS_UBSAN_SANITIZE_ALL
-       select ARCH_HAS_ZONE_DEVICE             if X86_64
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select ARCH_MIGHT_HAVE_ACPI_PDC         if ACPI
        select ARCH_MIGHT_HAVE_PC_PARPORT
@@ -94,6 +94,7 @@ config X86
        select ARCH_USE_QUEUED_SPINLOCKS
        select ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
        select ARCH_WANTS_DYNAMIC_TASK_STRUCT
+       select ARCH_WANT_HUGE_PMD_SHARE
        select ARCH_WANTS_THP_SWAP              if X86_64
        select BUILDTIME_EXTABLE_SORT
        select CLKEVT_I8253
@@ -307,9 +308,6 @@ config ARCH_HIBERNATION_POSSIBLE
 config ARCH_SUSPEND_POSSIBLE
        def_bool y
 
-config ARCH_WANT_HUGE_PMD_SHARE
-       def_bool y
-
 config ARCH_WANT_GENERAL_HUGETLB
        def_bool y
 
@@ -402,7 +400,7 @@ config SMP
          Management" code will be disabled if you say Y here.
 
          See also <file:Documentation/x86/i386/IO-APIC.rst>,
-         <file:Documentation/lockup-watchdogs.txt> and the SMP-HOWTO available at
+         <file:Documentation/admin-guide/lockup-watchdogs.rst> and the SMP-HOWTO available at
          <http://www.tldp.org/docs.html#howto>.
 
          If you don't know what to do here, say N.
@@ -1528,6 +1526,7 @@ config AMD_MEM_ENCRYPT
        depends on X86_64 && CPU_SUP_AMD
        select DYNAMIC_PHYSICAL_MASK
        select ARCH_USE_MEMREMAP_PROT
+       select ARCH_HAS_FORCE_DMA_UNENCRYPTED
        ---help---
          Say yes to enable support for the encryption of system memory.
          This requires an AMD processor that supports Secure Memory
@@ -1959,7 +1958,7 @@ config EFI_STUB
           This kernel feature allows a bzImage to be loaded directly
          by EFI firmware without the use of a bootloader.
 
-         See Documentation/efi-stub.txt for more information.
+         See Documentation/admin-guide/efi-stub.rst for more information.
 
 config EFI_MIXED
        bool "EFI mixed-mode support"
@@ -2057,7 +2056,7 @@ config CRASH_DUMP
          to a memory address not used by the main kernel or BIOS using
          PHYSICAL_START, or it must be built as a relocatable image
          (CONFIG_RELOCATABLE=y).
-         For more details see Documentation/kdump/kdump.rst
+         For more details see Documentation/admin-guide/kdump/kdump.rst
 
 config KEXEC_JUMP
        bool "kexec jump"
@@ -2094,7 +2093,7 @@ config PHYSICAL_START
          the reserved region.  In other words, it can be set based on
          the "X" value as specified in the "crashkernel=YM@XM"
          command line boot parameter passed to the panic-ed
-         kernel. Please take a look at Documentation/kdump/kdump.rst
+         kernel. Please take a look at Documentation/admin-guide/kdump/kdump.rst
          for more details about crash dumps.
 
          Usage of bzImage for capturing the crash dump is recommended as
index 220d127..d6662fd 100644 (file)
@@ -384,14 +384,11 @@ struct boot_params *make_boot_params(struct efi_config *c)
        struct apm_bios_info *bi;
        struct setup_header *hdr;
        efi_loaded_image_t *image;
-       void *options, *handle;
+       void *handle;
        efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
        int options_size = 0;
        efi_status_t status;
        char *cmdline_ptr;
-       u16 *s2;
-       u8 *s1;
-       int i;
        unsigned long ramdisk_addr;
        unsigned long ramdisk_size;
 
@@ -494,8 +491,6 @@ static void add_e820ext(struct boot_params *params,
                        struct setup_data *e820ext, u32 nr_entries)
 {
        struct setup_data *data;
-       efi_status_t status;
-       unsigned long size;
 
        e820ext->type = SETUP_E820_EXT;
        e820ext->len  = nr_entries * sizeof(struct boot_e820_entry);
@@ -677,8 +672,6 @@ static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg,
                                   void *priv)
 {
        const char *signature;
-       __u32 nr_desc;
-       efi_status_t status;
        struct exit_boot_struct *p = priv;
 
        signature = efi_is_64bit() ? EFI64_LOADER_SIGNATURE
@@ -747,7 +740,6 @@ struct boot_params *
 efi_main(struct efi_config *c, struct boot_params *boot_params)
 {
        struct desc_ptr *gdt = NULL;
-       efi_loaded_image_t *image;
        struct setup_header *hdr = &boot_params->hdr;
        efi_status_t status;
        struct desc_struct *desc;
index 24e65a0..53ac0cb 100644 (file)
@@ -17,6 +17,7 @@
 #include "pgtable.h"
 #include "../string.h"
 #include "../voffset.h"
+#include <asm/bootparam_utils.h>
 
 /*
  * WARNING!!
index d2f1841..c818139 100644 (file)
@@ -23,7 +23,6 @@
 #include <asm/page.h>
 #include <asm/boot.h>
 #include <asm/bootparam.h>
-#include <asm/bootparam_utils.h>
 
 #define BOOT_CTYPE_H
 #include <linux/acpi.h>
index f8debf7..5f2d030 100644 (file)
@@ -40,7 +40,6 @@ int cmdline_find_option_bool(const char *option);
 static unsigned long find_trampoline_placement(void)
 {
        unsigned long bios_start = 0, ebda_start = 0;
-       unsigned long trampoline_start;
        struct boot_e820_entry *entry;
        char *signature;
        int i;
index 9f1f9e3..830bd98 100644 (file)
@@ -343,3 +343,9 @@ For 32-bit we have the following conventions - kernel is built with
 .Lafter_call_\@:
 #endif
 .endm
+
+#ifdef CONFIG_PARAVIRT_XXL
+#define GET_CR2_INTO(reg) GET_CR2_INTO_AX ; _ASM_MOV %_ASM_AX, reg
+#else
+#define GET_CR2_INTO(reg) _ASM_MOV %cr2, reg
+#endif
index 90b4732..2bb986f 100644 (file)
 .Lfinished_frame_\@:
 .endm
 
-.macro SAVE_ALL pt_regs_ax=%eax switch_stacks=0
+.macro SAVE_ALL pt_regs_ax=%eax switch_stacks=0 skip_gs=0
        cld
+.if \skip_gs == 0
        PUSH_GS
+.endif
        FIXUP_FRAME
        pushl   %fs
        pushl   %es
        movl    %edx, %es
        movl    $(__KERNEL_PERCPU), %edx
        movl    %edx, %fs
+.if \skip_gs == 0
        SET_KERNEL_GS %edx
-
+.endif
        /* Switch to kernel stack if necessary */
 .if \switch_stacks > 0
        SWITCH_TO_KERNEL_STACK
 .endif
-
 .endm
 
 .macro SAVE_ALL_NMI cr3_reg:req
@@ -1441,39 +1443,46 @@ BUILD_INTERRUPT3(hv_stimer0_callback_vector, HYPERV_STIMER0_VECTOR,
 
 ENTRY(page_fault)
        ASM_CLAC
-       pushl   $do_page_fault
-       ALIGN
-       jmp common_exception
+       pushl   $0; /* %gs's slot on the stack */
+
+       SAVE_ALL switch_stacks=1 skip_gs=1
+
+       ENCODE_FRAME_POINTER
+       UNWIND_ESPFIX_STACK
+
+       /* fixup %gs */
+       GS_TO_REG %ecx
+       REG_TO_PTGS %ecx
+       SET_KERNEL_GS %ecx
+
+       GET_CR2_INTO(%ecx)                      # might clobber %eax
+
+       /* fixup orig %eax */
+       movl    PT_ORIG_EAX(%esp), %edx         # get the error code
+       movl    $-1, PT_ORIG_EAX(%esp)          # no syscall to restart
+
+       TRACE_IRQS_OFF
+       movl    %esp, %eax                      # pt_regs pointer
+       call    do_page_fault
+       jmp     ret_from_exception
 END(page_fault)
 
 common_exception:
        /* the function address is in %gs's slot on the stack */
-       FIXUP_FRAME
-       pushl   %fs
-       pushl   %es
-       pushl   %ds
-       pushl   %eax
-       movl    $(__USER_DS), %eax
-       movl    %eax, %ds
-       movl    %eax, %es
-       movl    $(__KERNEL_PERCPU), %eax
-       movl    %eax, %fs
-       pushl   %ebp
-       pushl   %edi
-       pushl   %esi
-       pushl   %edx
-       pushl   %ecx
-       pushl   %ebx
-       SWITCH_TO_KERNEL_STACK
+       SAVE_ALL switch_stacks=1 skip_gs=1
        ENCODE_FRAME_POINTER
-       cld
        UNWIND_ESPFIX_STACK
+
+       /* fixup %gs */
        GS_TO_REG %ecx
        movl    PT_GS(%esp), %edi               # get the function address
-       movl    PT_ORIG_EAX(%esp), %edx         # get the error code
-       movl    $-1, PT_ORIG_EAX(%esp)          # no syscall to restart
        REG_TO_PTGS %ecx
        SET_KERNEL_GS %ecx
+
+       /* fixup orig %eax */
+       movl    PT_ORIG_EAX(%esp), %edx         # get the error code
+       movl    $-1, PT_ORIG_EAX(%esp)          # no syscall to restart
+
        TRACE_IRQS_OFF
        movl    %esp, %eax                      # pt_regs pointer
        CALL_NOSPEC %edi
index 0ea4831..3f5a978 100644 (file)
@@ -864,18 +864,84 @@ apicinterrupt IRQ_WORK_VECTOR                     irq_work_interrupt              smp_irq_work_interrupt
  */
 #define CPU_TSS_IST(x) PER_CPU_VAR(cpu_tss_rw) + (TSS_ist + (x) * 8)
 
+.macro idtentry_part do_sym, has_error_code:req, read_cr2:req, paranoid:req, shift_ist=-1, ist_offset=0
+
+       .if \paranoid
+       call    paranoid_entry
+       /* returned flag: ebx=0: need swapgs on exit, ebx=1: don't need it */
+       .else
+       call    error_entry
+       .endif
+       UNWIND_HINT_REGS
+
+       .if \read_cr2
+       /*
+        * Store CR2 early so subsequent faults cannot clobber it. Use R12 as
+        * intermediate storage as RDX can be clobbered in enter_from_user_mode().
+        * GET_CR2_INTO can clobber RAX.
+        */
+       GET_CR2_INTO(%r12);
+       .endif
+
+       .if \shift_ist != -1
+       TRACE_IRQS_OFF_DEBUG                    /* reload IDT in case of recursion */
+       .else
+       TRACE_IRQS_OFF
+       .endif
+
+       .if \paranoid == 0
+       testb   $3, CS(%rsp)
+       jz      .Lfrom_kernel_no_context_tracking_\@
+       CALL_enter_from_user_mode
+.Lfrom_kernel_no_context_tracking_\@:
+       .endif
+
+       movq    %rsp, %rdi                      /* pt_regs pointer */
+
+       .if \has_error_code
+       movq    ORIG_RAX(%rsp), %rsi            /* get error code */
+       movq    $-1, ORIG_RAX(%rsp)             /* no syscall to restart */
+       .else
+       xorl    %esi, %esi                      /* no error code */
+       .endif
+
+       .if \shift_ist != -1
+       subq    $\ist_offset, CPU_TSS_IST(\shift_ist)
+       .endif
+
+       .if \read_cr2
+       movq    %r12, %rdx                      /* Move CR2 into 3rd argument */
+       .endif
+
+       call    \do_sym
+
+       .if \shift_ist != -1
+       addq    $\ist_offset, CPU_TSS_IST(\shift_ist)
+       .endif
+
+       .if \paranoid
+       /* this procedure expect "no swapgs" flag in ebx */
+       jmp     paranoid_exit
+       .else
+       jmp     error_exit
+       .endif
+
+.endm
+
 /**
  * idtentry - Generate an IDT entry stub
  * @sym:               Name of the generated entry point
- * @do_sym:            C function to be called
- * @has_error_code:    True if this IDT vector has an error code on the stack
- * @paranoid:          non-zero means that this vector may be invoked from
+ * @do_sym:            C function to be called
+ * @has_error_code:    True if this IDT vector has an error code on the stack
+ * @paranoid:          non-zero means that this vector may be invoked from
  *                     kernel mode with user GSBASE and/or user CR3.
  *                     2 is special -- see below.
  * @shift_ist:         Set to an IST index if entries from kernel mode should
- *                             decrement the IST stack so that nested entries get a
+ *                     decrement the IST stack so that nested entries get a
  *                     fresh stack.  (This is for #DB, which has a nasty habit
- *                             of recursing.)
+ *                     of recursing.)
+ * @create_gap:                create a 6-word stack gap when coming from kernel mode.
+ * @read_cr2:          load CR2 into the 3rd argument; done before calling any C code
  *
  * idtentry generates an IDT stub that sets up a usable kernel context,
  * creates struct pt_regs, and calls @do_sym.  The stub has the following
@@ -900,15 +966,19 @@ apicinterrupt IRQ_WORK_VECTOR                     irq_work_interrupt              smp_irq_work_interrupt
  * @paranoid == 2 is special: the stub will never switch stacks.  This is for
  * #DF: if the thread stack is somehow unusable, we'll still get a useful OOPS.
  */
-.macro idtentry sym do_sym has_error_code:req paranoid=0 shift_ist=-1 ist_offset=0 create_gap=0
+.macro idtentry sym do_sym has_error_code:req paranoid=0 shift_ist=-1 ist_offset=0 create_gap=0 read_cr2=0
 ENTRY(\sym)
        UNWIND_HINT_IRET_REGS offset=\has_error_code*8
 
        /* Sanity check */
-       .if \shift_ist != -1 && \paranoid == 0
+       .if \shift_ist != -1 && \paranoid != 1
        .error "using shift_ist requires paranoid=1"
        .endif
 
+       .if \create_gap && \paranoid
+       .error "using create_gap requires paranoid=0"
+       .endif
+
        ASM_CLAC
 
        .if \has_error_code == 0
@@ -934,47 +1004,7 @@ ENTRY(\sym)
 .Lfrom_usermode_no_gap_\@:
        .endif
 
-       .if \paranoid
-       call    paranoid_entry
-       .else
-       call    error_entry
-       .endif
-       UNWIND_HINT_REGS
-       /* returned flag: ebx=0: need swapgs on exit, ebx=1: don't need it */
-
-       .if \paranoid
-       .if \shift_ist != -1
-       TRACE_IRQS_OFF_DEBUG                    /* reload IDT in case of recursion */
-       .else
-       TRACE_IRQS_OFF
-       .endif
-       .endif
-
-       movq    %rsp, %rdi                      /* pt_regs pointer */
-
-       .if \has_error_code
-       movq    ORIG_RAX(%rsp), %rsi            /* get error code */
-       movq    $-1, ORIG_RAX(%rsp)             /* no syscall to restart */
-       .else
-       xorl    %esi, %esi                      /* no error code */
-       .endif
-
-       .if \shift_ist != -1
-       subq    $\ist_offset, CPU_TSS_IST(\shift_ist)
-       .endif
-
-       call    \do_sym
-
-       .if \shift_ist != -1
-       addq    $\ist_offset, CPU_TSS_IST(\shift_ist)
-       .endif
-
-       /* these procedures expect "no swapgs" flag in ebx */
-       .if \paranoid
-       jmp     paranoid_exit
-       .else
-       jmp     error_exit
-       .endif
+       idtentry_part \do_sym, \has_error_code, \read_cr2, \paranoid, \shift_ist, \ist_offset
 
        .if \paranoid == 1
        /*
@@ -983,21 +1013,9 @@ ENTRY(\sym)
         * run in real process context if user_mode(regs).
         */
 .Lfrom_usermode_switch_stack_\@:
-       call    error_entry
-
-       movq    %rsp, %rdi                      /* pt_regs pointer */
-
-       .if \has_error_code
-       movq    ORIG_RAX(%rsp), %rsi            /* get error code */
-       movq    $-1, ORIG_RAX(%rsp)             /* no syscall to restart */
-       .else
-       xorl    %esi, %esi                      /* no error code */
+       idtentry_part \do_sym, \has_error_code, \read_cr2, paranoid=0
        .endif
 
-       call    \do_sym
-
-       jmp     error_exit
-       .endif
 _ASM_NOKPROBE(\sym)
 END(\sym)
 .endm
@@ -1007,7 +1025,7 @@ idtentry overflow                 do_overflow                     has_error_code=0
 idtentry bounds                                do_bounds                       has_error_code=0
 idtentry invalid_op                    do_invalid_op                   has_error_code=0
 idtentry device_not_available          do_device_not_available         has_error_code=0
-idtentry double_fault                  do_double_fault                 has_error_code=1 paranoid=2
+idtentry double_fault                  do_double_fault                 has_error_code=1 paranoid=2 read_cr2=1
 idtentry coprocessor_segment_overrun   do_coprocessor_segment_overrun  has_error_code=0
 idtentry invalid_TSS                   do_invalid_TSS                  has_error_code=1
 idtentry segment_not_present           do_segment_not_present          has_error_code=1
@@ -1176,14 +1194,13 @@ idtentry stack_segment          do_stack_segment        has_error_code=1
 #ifdef CONFIG_XEN_PV
 idtentry xennmi                        do_nmi                  has_error_code=0
 idtentry xendebug              do_debug                has_error_code=0
-idtentry xenint3               do_int3                 has_error_code=0
 #endif
 
 idtentry general_protection    do_general_protection   has_error_code=1
-idtentry page_fault            do_page_fault           has_error_code=1
+idtentry page_fault            do_page_fault           has_error_code=1        read_cr2=1
 
 #ifdef CONFIG_KVM_GUEST
-idtentry async_page_fault      do_async_page_fault     has_error_code=1
+idtentry async_page_fault      do_async_page_fault     has_error_code=1        read_cr2=1
 #endif
 
 #ifdef CONFIG_X86_MCE
@@ -1282,18 +1299,9 @@ ENTRY(error_entry)
        movq    %rax, %rsp                      /* switch stack */
        ENCODE_FRAME_POINTER
        pushq   %r12
-
-       /*
-        * We need to tell lockdep that IRQs are off.  We can't do this until
-        * we fix gsbase, and we should do it before enter_from_user_mode
-        * (which can take locks).
-        */
-       TRACE_IRQS_OFF
-       CALL_enter_from_user_mode
        ret
 
 .Lerror_entry_done:
-       TRACE_IRQS_OFF
        ret
 
        /*
index cfdca8b..cc20465 100644 (file)
@@ -12,9 +12,7 @@
 
        /* rdi: arg1 ... normal C conventions. rax is saved/restored. */
        .macro THUNK name, func, put_ret_addr_in_rdi=0
-       .globl \name
-       .type \name, @function
-\name:
+       ENTRY(\name)
        pushq %rbp
        movq %rsp, %rbp
 
@@ -35,6 +33,7 @@
 
        call \func
        jmp  .L_restore
+       ENDPROC(\name)
        _ASM_NOKPROBE(\name)
        .endm
 
index 3477339..8df5491 100644 (file)
@@ -176,9 +176,8 @@ quiet_cmd_vdso = VDSO    $@
                       -T $(filter %.lds,$^) $(filter %.o,$^) && \
                 sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@'
 
-VDSO_LDFLAGS = -shared $(call ld-option, --hash-style=both) \
-       $(call ld-option, --build-id) $(call ld-option, --eh-frame-hdr) \
-       -Bsymbolic
+VDSO_LDFLAGS = -shared --hash-style=both --build-id \
+       $(call ld-option, --eh-frame-hdr) -Bsymbolic
 GCOV_PROFILE := n
 
 quiet_cmd_vdso_and_check = VDSO    $@
index 42d4c89..240626e 100644 (file)
@@ -65,9 +65,6 @@ subsys_initcall(sysenter_setup);
 /* Register vsyscall32 into the ABI table */
 #include <linux/sysctl.h>
 
-static const int zero;
-static const int one = 1;
-
 static struct ctl_table abi_table2[] = {
        {
                .procname       = "vsyscall32",
@@ -75,8 +72,8 @@ static struct ctl_table abi_table2[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = (int *)&zero,
-               .extra2         = (int *)&one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        {}
 };
index 0e033ef..0d25868 100644 (file)
@@ -60,8 +60,17 @@ static int hv_cpu_init(unsigned int cpu)
        if (!hv_vp_assist_page)
                return 0;
 
-       if (!*hvp)
-               *hvp = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL);
+       /*
+        * The VP ASSIST PAGE is an "overlay" page (see Hyper-V TLFS's Section
+        * 5.2.1 "GPA Overlay Pages"). Here it must be zeroed out to make sure
+        * we always write the EOI MSR in hv_apic_eoi_write() *after* the
+        * EOI optimization is disabled in hv_cpu_die(), otherwise a CPU may
+        * not be stopped in the case of CPU offlining and the VM will hang.
+        */
+       if (!*hvp) {
+               *hvp = __vmalloc(PAGE_SIZE, GFP_KERNEL | __GFP_ZERO,
+                                PAGE_KERNEL);
+       }
 
        if (*hvp) {
                u64 val;
index 64a6c95..2179030 100644 (file)
@@ -239,6 +239,7 @@ COMPAT_SYSCALL_DEFINE5(x86_clone, unsigned long, clone_flags,
 {
        struct kernel_clone_args args = {
                .flags          = (clone_flags & ~CSIGNAL),
+               .pidfd          = parent_tidptr,
                .child_tid      = child_tidptr,
                .parent_tid     = parent_tidptr,
                .exit_signal    = (clone_flags & CSIGNAL),
@@ -246,5 +247,8 @@ COMPAT_SYSCALL_DEFINE5(x86_clone, unsigned long, clone_flags,
                .tls            = tls_val,
        };
 
+       if (!legacy_clone_args_valid(&args))
+               return -EINVAL;
+
        return _do_fork(&args);
 }
index 050e5f9..e647aa0 100644 (file)
@@ -49,7 +49,7 @@ static inline void generic_apic_probe(void)
 
 #ifdef CONFIG_X86_LOCAL_APIC
 
-extern unsigned int apic_verbosity;
+extern int apic_verbosity;
 extern int local_apic_timer_c2_ok;
 
 extern int disable_apic;
index 50a30f6..e41cbf2 100644 (file)
@@ -53,8 +53,20 @@ struct hypervisor_x86 {
 
        /* runtime callbacks */
        struct x86_hyper_runtime runtime;
+
+       /* ignore nopv parameter */
+       bool ignore_nopv;
 };
 
+extern const struct hypervisor_x86 x86_hyper_vmware;
+extern const struct hypervisor_x86 x86_hyper_ms_hyperv;
+extern const struct hypervisor_x86 x86_hyper_xen_pv;
+extern const struct hypervisor_x86 x86_hyper_kvm;
+extern const struct hypervisor_x86 x86_hyper_jailhouse;
+extern const struct hypervisor_x86 x86_hyper_acrn;
+extern struct hypervisor_x86 x86_hyper_xen_hvm;
+
+extern bool nopv;
 extern enum x86_hypervisor_type x86_hyper_type;
 extern void init_hypervisor_platform(void);
 static inline bool hypervisor_is_type(enum x86_hypervisor_type type)
index a06a9f8..6bed97f 100644 (file)
@@ -165,7 +165,6 @@ static inline unsigned int isa_virt_to_bus(volatile void *address)
 {
        return (unsigned int)virt_to_phys(address);
 }
-#define isa_page_to_bus(page)  ((unsigned int)page_to_phys(page))
 #define isa_bus_to_virt                phys_to_virt
 
 /*
index 0cc5b61..7b0a4ee 100644 (file)
@@ -607,15 +607,16 @@ struct kvm_vcpu_arch {
 
        /*
         * QEMU userspace and the guest each have their own FPU state.
-        * In vcpu_run, we switch between the user, maintained in the
-        * task_struct struct, and guest FPU contexts. While running a VCPU,
-        * the VCPU thread will have the guest FPU context.
+        * In vcpu_run, we switch between the user and guest FPU contexts.
+        * While running a VCPU, the VCPU thread will have the guest FPU
+        * context.
         *
         * Note that while the PKRU state lives inside the fpu registers,
         * it is switched out separately at VMENTER and VMEXIT time. The
         * "guest_fpu" state here contains the guest FPU context, with the
         * host PRKU bits.
         */
+       struct fpu *user_fpu;
        struct fpu *guest_fpu;
 
        u64 xcr0;
@@ -1496,25 +1497,29 @@ enum {
 #define kvm_arch_vcpu_memslots_id(vcpu) ((vcpu)->arch.hflags & HF_SMM_MASK ? 1 : 0)
 #define kvm_memslots_for_spte_role(kvm, role) __kvm_memslots(kvm, (role).smm)
 
+asmlinkage void __noreturn kvm_spurious_fault(void);
+
 /*
  * Hardware virtualization extension instructions may fault if a
  * reboot turns off virtualization while processes are running.
- * Trap the fault and ignore the instruction if that happens.
+ * Usually after catching the fault we just panic; during reboot
+ * instead the instruction is ignored.
  */
-asmlinkage void kvm_spurious_fault(void);
-
-#define ____kvm_handle_fault_on_reboot(insn, cleanup_insn)     \
-       "666: " insn "\n\t" \
-       "668: \n\t"                           \
-       ".pushsection .fixup, \"ax\" \n" \
-       "667: \n\t" \
-       cleanup_insn "\n\t"                   \
-       "cmpb $0, kvm_rebooting \n\t"         \
-       "jne 668b \n\t"                       \
-       __ASM_SIZE(push) " $666b \n\t"        \
-       "jmp kvm_spurious_fault \n\t"         \
-       ".popsection \n\t" \
-       _ASM_EXTABLE(666b, 667b)
+#define ____kvm_handle_fault_on_reboot(insn, cleanup_insn)             \
+       "666: \n\t"                                                     \
+       insn "\n\t"                                                     \
+       "jmp    668f \n\t"                                              \
+       "667: \n\t"                                                     \
+       "call   kvm_spurious_fault \n\t"                                \
+       "668: \n\t"                                                     \
+       ".pushsection .fixup, \"ax\" \n\t"                              \
+       "700: \n\t"                                                     \
+       cleanup_insn "\n\t"                                             \
+       "cmpb   $0, kvm_rebooting\n\t"                                  \
+       "je     667b \n\t"                                              \
+       "jmp    668b \n\t"                                              \
+       ".popsection \n\t"                                              \
+       _ASM_EXTABLE(666b, 700b)
 
 #define __kvm_handle_fault_on_reboot(insn)             \
        ____kvm_handle_fault_on_reboot(insn, "")
index 5ed3cf1..9b4df6e 100644 (file)
@@ -92,7 +92,7 @@ void kvm_async_pf_task_wait(u32 token, int interrupt_kernel);
 void kvm_async_pf_task_wake(u32 token);
 u32 kvm_read_and_reset_pf_reason(void);
 extern void kvm_disable_steal_time(void);
-void do_async_page_fault(struct pt_regs *regs, unsigned long error_code);
+void do_async_page_fault(struct pt_regs *regs, unsigned long error_code, unsigned long address);
 
 #ifdef CONFIG_PARAVIRT_SPINLOCKS
 void __init kvm_spinlock_init(void);
index c25c38a..dce26f1 100644 (file)
@@ -116,7 +116,7 @@ static inline void write_cr0(unsigned long x)
 
 static inline unsigned long read_cr2(void)
 {
-       return PVOP_CALL0(unsigned long, mmu.read_cr2);
+       return PVOP_CALLEE0(unsigned long, mmu.read_cr2);
 }
 
 static inline void write_cr2(unsigned long x)
@@ -746,6 +746,7 @@ bool __raw_callee_save___native_vcpu_is_preempted(long cpu);
            PV_RESTORE_ALL_CALLER_REGS                                  \
            FRAME_END                                                   \
            "ret;"                                                      \
+           ".size " PV_THUNK_NAME(func) ", .-" PV_THUNK_NAME(func) ";" \
            ".popsection")
 
 /* Get a reference to a callee-save function */
@@ -909,13 +910,7 @@ extern void default_banner(void);
                  ANNOTATE_RETPOLINE_SAFE;                              \
                  call PARA_INDIRECT(pv_ops+PV_CPU_swapgs);             \
                 )
-#endif
-
-#define GET_CR2_INTO_RAX                               \
-       ANNOTATE_RETPOLINE_SAFE;                                \
-       call PARA_INDIRECT(pv_ops+PV_MMU_read_cr2);
 
-#ifdef CONFIG_PARAVIRT_XXL
 #define USERGS_SYSRET64                                                        \
        PARA_SITE(PARA_PATCH(PV_CPU_usergs_sysret64),                   \
                  ANNOTATE_RETPOLINE_SAFE;                              \
@@ -929,9 +924,19 @@ extern void default_banner(void);
                  call PARA_INDIRECT(pv_ops+PV_IRQ_save_fl);        \
                  PV_RESTORE_REGS(clobbers | CLBR_CALLEE_SAVE);)
 #endif
-#endif
+#endif /* CONFIG_PARAVIRT_XXL */
+#endif /* CONFIG_X86_64 */
+
+#ifdef CONFIG_PARAVIRT_XXL
+
+#define GET_CR2_INTO_AX                                                        \
+       PARA_SITE(PARA_PATCH(PV_MMU_read_cr2),                          \
+                 ANNOTATE_RETPOLINE_SAFE;                              \
+                 call PARA_INDIRECT(pv_ops+PV_MMU_read_cr2);           \
+                )
+
+#endif /* CONFIG_PARAVIRT_XXL */
 
-#endif /* CONFIG_X86_32 */
 
 #endif /* __ASSEMBLY__ */
 #else  /* CONFIG_PARAVIRT */
index 946f8f1..639b2df 100644 (file)
@@ -220,7 +220,7 @@ struct pv_mmu_ops {
        void (*exit_mmap)(struct mm_struct *mm);
 
 #ifdef CONFIG_PARAVIRT_XXL
-       unsigned long (*read_cr2)(void);
+       struct paravirt_callee_save read_cr2;
        void (*write_cr2)(unsigned long);
 
        unsigned long (*read_cr3)(void);
index 5e0509b..0bc530c 100644 (file)
@@ -271,7 +271,7 @@ static inline int has_transparent_hugepage(void)
        return boot_cpu_has(X86_FEATURE_PSE);
 }
 
-#ifdef __HAVE_ARCH_PTE_DEVMAP
+#ifdef CONFIG_ARCH_HAS_PTE_DEVMAP
 static inline int pmd_devmap(pmd_t pmd)
 {
        return !!(pmd_val(pmd) & _PAGE_DEVMAP);
@@ -732,7 +732,7 @@ static inline int pte_present(pte_t a)
        return pte_flags(a) & (_PAGE_PRESENT | _PAGE_PROTNONE);
 }
 
-#ifdef __HAVE_ARCH_PTE_DEVMAP
+#ifdef CONFIG_ARCH_HAS_PTE_DEVMAP
 static inline int pte_devmap(pte_t a)
 {
        return (pte_flags(a) & _PAGE_DEVMAP) == _PAGE_DEVMAP;
index d6ff0bb..b5e49e6 100644 (file)
 #if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
 #define _PAGE_NX       (_AT(pteval_t, 1) << _PAGE_BIT_NX)
 #define _PAGE_DEVMAP   (_AT(u64, 1) << _PAGE_BIT_DEVMAP)
-#define __HAVE_ARCH_PTE_DEVMAP
 #else
 #define _PAGE_NX       (_AT(pteval_t, 0))
 #define _PAGE_DEVMAP   (_AT(pteval_t, 0))
index 7d6f3f3..b25e633 100644 (file)
@@ -40,7 +40,7 @@ asmlinkage void simd_coprocessor_error(void);
 asmlinkage void xen_divide_error(void);
 asmlinkage void xen_xennmi(void);
 asmlinkage void xen_xendebug(void);
-asmlinkage void xen_xenint3(void);
+asmlinkage void xen_int3(void);
 asmlinkage void xen_overflow(void);
 asmlinkage void xen_bounds(void);
 asmlinkage void xen_invalid_op(void);
@@ -74,14 +74,14 @@ dotraplinkage void do_invalid_TSS(struct pt_regs *regs, long error_code);
 dotraplinkage void do_segment_not_present(struct pt_regs *regs, long error_code);
 dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code);
 #ifdef CONFIG_X86_64
-dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code);
+dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code, unsigned long address);
 asmlinkage __visible notrace struct pt_regs *sync_regs(struct pt_regs *eregs);
 asmlinkage __visible notrace
 struct bad_iret_stack *fixup_bad_iret(struct bad_iret_stack *s);
 void __init trap_init(void);
 #endif
 dotraplinkage void do_general_protection(struct pt_regs *regs, long error_code);
-dotraplinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code);
+dotraplinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code, unsigned long address);
 dotraplinkage void do_spurious_interrupt_bug(struct pt_regs *regs, long error_code);
 dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code);
 dotraplinkage void do_alignment_check(struct pt_regs *regs, long error_code);
index c82abd6..9c44353 100644 (file)
@@ -66,7 +66,9 @@ static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, un
 })
 
 #ifdef CONFIG_DEBUG_ATOMIC_SLEEP
-# define WARN_ON_IN_IRQ()      WARN_ON_ONCE(!in_task())
+static inline bool pagefault_disabled(void);
+# define WARN_ON_IN_IRQ()      \
+       WARN_ON_ONCE(!in_task() && !pagefault_disabled())
 #else
 # define WARN_ON_IN_IRQ()
 #endif
index b85a7c5..ac09341 100644 (file)
@@ -301,6 +301,8 @@ extern struct x86_apic_ops x86_apic_ops;
 extern void x86_early_init_platform_quirks(void);
 extern void x86_init_noop(void);
 extern void x86_init_uint_noop(unsigned int unused);
+extern bool bool_x86_init_noop(void);
+extern void x86_op_int_noop(int cpu);
 extern bool x86_pnpbios_disabled(void);
 
 #endif
index 39171b3..42e1245 100644 (file)
@@ -44,14 +44,14 @@ static inline uint32_t xen_cpuid_base(void)
 }
 
 #ifdef CONFIG_XEN
-extern bool xen_hvm_need_lapic(void);
+extern bool __init xen_hvm_need_lapic(void);
 
-static inline bool xen_x2apic_para_available(void)
+static inline bool __init xen_x2apic_para_available(void)
 {
        return xen_hvm_need_lapic();
 }
 #else
-static inline bool xen_x2apic_para_available(void)
+static inline bool __init xen_x2apic_para_available(void)
 {
        return (xen_cpuid_base() != 0);
 }
index e901b0a..503d3f4 100644 (file)
@@ -435,9 +435,12 @@ struct kvm_nested_state {
 
 /* for KVM_CAP_PMU_EVENT_FILTER */
 struct kvm_pmu_event_filter {
-       __u32 action;
-       __u32 nevents;
-       __u64 events[0];
+       __u32 action;
+       __u32 nevents;
+       __u32 fixed_counter_bitmap;
+       __u32 flags;
+       __u32 pad[4];
+       __u64 events[0];
 };
 
 #define KVM_PMU_EVENT_ALLOW 0
index 1bd91cb..f529136 100644 (file)
@@ -183,7 +183,7 @@ EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok);
 /*
  * Debug level, exported for io_apic.c
  */
-unsigned int apic_verbosity;
+int apic_verbosity;
 
 int pic_mode;
 
index da64452..5c7ee3d 100644 (file)
@@ -76,6 +76,7 @@ static void __used common(void)
        BLANK();
        OFFSET(XEN_vcpu_info_mask, vcpu_info, evtchn_upcall_mask);
        OFFSET(XEN_vcpu_info_pending, vcpu_info, evtchn_upcall_pending);
+       OFFSET(XEN_vcpu_info_arch_cr2, vcpu_info, arch.cr2);
 #endif
 
        BLANK();
index 87e39ad..553bfbf 100644 (file)
 #include <asm/processor.h>
 #include <asm/hypervisor.h>
 
-extern const struct hypervisor_x86 x86_hyper_vmware;
-extern const struct hypervisor_x86 x86_hyper_ms_hyperv;
-extern const struct hypervisor_x86 x86_hyper_xen_pv;
-extern const struct hypervisor_x86 x86_hyper_xen_hvm;
-extern const struct hypervisor_x86 x86_hyper_kvm;
-extern const struct hypervisor_x86 x86_hyper_jailhouse;
-extern const struct hypervisor_x86 x86_hyper_acrn;
-
 static const __initconst struct hypervisor_x86 * const hypervisors[] =
 {
 #ifdef CONFIG_XEN_PV
@@ -58,6 +50,14 @@ static const __initconst struct hypervisor_x86 * const hypervisors[] =
 enum x86_hypervisor_type x86_hyper_type;
 EXPORT_SYMBOL(x86_hyper_type);
 
+bool __initdata nopv;
+static __init int parse_nopv(char *arg)
+{
+       nopv = true;
+       return 0;
+}
+early_param("nopv", parse_nopv);
+
 static inline const struct hypervisor_x86 * __init
 detect_hypervisor_vendor(void)
 {
@@ -65,6 +65,9 @@ detect_hypervisor_vendor(void)
        uint32_t pri, max_pri = 0;
 
        for (p = hypervisors; p < hypervisors + ARRAY_SIZE(hypervisors); p++) {
+               if (unlikely(nopv) && !(*p)->ignore_nopv)
+                       continue;
+
                pri = (*p)->detect();
                if (pri > max_pri) {
                        max_pri = pri;
index bf30349..a46dee8 100644 (file)
@@ -2104,8 +2104,7 @@ static int rdt_init_fs_context(struct fs_context *fc)
        ctx->kfc.magic = RDTGROUP_SUPER_MAGIC;
        fc->fs_private = &ctx->kfc;
        fc->ops = &rdt_fs_context_ops;
-       if (fc->user_ns)
-               put_user_ns(fc->user_ns);
+       put_user_ns(fc->user_ns);
        fc->user_ns = get_user_ns(&init_user_ns);
        fc->global = true;
        return 0;
index e69408b..7da2bcd 100644 (file)
@@ -86,9 +86,9 @@ static bool _e820__mapped_any(struct e820_table *table,
                        continue;
                if (entry->addr >= end || entry->addr + entry->size <= start)
                        continue;
-               return 1;
+               return true;
        }
-       return 0;
+       return false;
 }
 
 bool e820__mapped_raw_any(u64 start, u64 end, enum e820_type type)
index 4b73f59..024c305 100644 (file)
@@ -373,7 +373,7 @@ static int add_brk_on_nop(struct dyn_ftrace *rec)
        return add_break(rec->ip, old);
 }
 
-static int add_breakpoints(struct dyn_ftrace *rec, int enable)
+static int add_breakpoints(struct dyn_ftrace *rec, bool enable)
 {
        unsigned long ftrace_addr;
        int ret;
@@ -481,7 +481,7 @@ static int add_update_nop(struct dyn_ftrace *rec)
        return add_update_code(ip, new);
 }
 
-static int add_update(struct dyn_ftrace *rec, int enable)
+static int add_update(struct dyn_ftrace *rec, bool enable)
 {
        unsigned long ftrace_addr;
        int ret;
@@ -527,7 +527,7 @@ static int finish_update_nop(struct dyn_ftrace *rec)
        return ftrace_write(ip, new, 1);
 }
 
-static int finish_update(struct dyn_ftrace *rec, int enable)
+static int finish_update(struct dyn_ftrace *rec, bool enable)
 {
        unsigned long ftrace_addr;
        int ret;
index bcd206c..a6342c8 100644 (file)
@@ -29,9 +29,7 @@
 #ifdef CONFIG_PARAVIRT_XXL
 #include <asm/asm-offsets.h>
 #include <asm/paravirt.h>
-#define GET_CR2_INTO(reg) GET_CR2_INTO_RAX ; movq %rax, reg
 #else
-#define GET_CR2_INTO(reg) movq %cr2, reg
 #define INTERRUPT_RETURN iretq
 #endif
 
@@ -253,10 +251,10 @@ END(secondary_startup_64)
  * start_secondary() via .Ljump_to_C_code.
  */
 ENTRY(start_cpu0)
-       movq    initial_stack(%rip), %rsp
        UNWIND_HINT_EMPTY
+       movq    initial_stack(%rip), %rsp
        jmp     .Ljump_to_C_code
-ENDPROC(start_cpu0)
+END(start_cpu0)
 #endif
 
        /* Both SMP bootup and ACPI suspend change these variables */
@@ -323,7 +321,7 @@ early_idt_handler_common:
 
        cmpq $14,%rsi           /* Page fault? */
        jnz 10f
-       GET_CR2_INTO(%rdi)      /* Can clobber any volatile register if pv */
+       GET_CR2_INTO(%rdi)      /* can clobber %rax if pv */
        call early_make_pgtable
        andl %eax,%eax
        jz 20f                  /* All good */
index 838cf8a..1cb3ca9 100644 (file)
@@ -65,8 +65,6 @@ static int sched_itmt_update_handler(struct ctl_table *table, int write,
        return ret;
 }
 
-static unsigned int zero;
-static unsigned int one = 1;
 static struct ctl_table itmt_kern_table[] = {
        {
                .procname       = "sched_itmt_enabled",
@@ -74,8 +72,8 @@ static struct ctl_table itmt_kern_table[] = {
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = sched_itmt_update_handler,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        {}
 };
index 6857b45..3ad34f0 100644 (file)
@@ -217,4 +217,5 @@ const struct hypervisor_x86 x86_hyper_jailhouse __refconst = {
        .detect                 = jailhouse_detect,
        .init.init_platform     = jailhouse_init_platform,
        .init.x2apic_available  = jailhouse_x2apic_available,
+       .ignore_nopv            = true,
 };
index 82caf01..b7f34fe 100644 (file)
@@ -242,23 +242,23 @@ EXPORT_SYMBOL_GPL(kvm_read_and_reset_pf_reason);
 NOKPROBE_SYMBOL(kvm_read_and_reset_pf_reason);
 
 dotraplinkage void
-do_async_page_fault(struct pt_regs *regs, unsigned long error_code)
+do_async_page_fault(struct pt_regs *regs, unsigned long error_code, unsigned long address)
 {
        enum ctx_state prev_state;
 
        switch (kvm_read_and_reset_pf_reason()) {
        default:
-               do_page_fault(regs, error_code);
+               do_page_fault(regs, error_code, address);
                break;
        case KVM_PV_REASON_PAGE_NOT_PRESENT:
                /* page is swapped out by the host. */
                prev_state = exception_enter();
-               kvm_async_pf_task_wait((u32)read_cr2(), !user_mode(regs));
+               kvm_async_pf_task_wait((u32)address, !user_mode(regs));
                exception_exit(prev_state);
                break;
        case KVM_PV_REASON_PAGE_READY:
                rcu_irq_enter();
-               kvm_async_pf_task_wake((u32)read_cr2());
+               kvm_async_pf_task_wake((u32)address);
                rcu_irq_exit();
                break;
        }
@@ -838,6 +838,7 @@ asm(
 "cmpb  $0, " __stringify(KVM_STEAL_TIME_preempted) "+steal_time(%rax);"
 "setne %al;"
 "ret;"
+".size __raw_callee_save___kvm_vcpu_is_preempted, .-__raw_callee_save___kvm_vcpu_is_preempted;"
 ".popsection");
 
 #endif
index 1bfe5c6..afac7cc 100644 (file)
@@ -546,17 +546,15 @@ void __init default_get_smp_config(unsigned int early)
                         * local APIC has default address
                         */
                        mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
-                       return;
+                       goto out;
                }
 
                pr_info("Default MP configuration #%d\n", mpf->feature1);
                construct_default_ISA_mptable(mpf->feature1);
 
        } else if (mpf->physptr) {
-               if (check_physptr(mpf, early)) {
-                       early_memunmap(mpf, sizeof(*mpf));
-                       return;
-               }
+               if (check_physptr(mpf, early))
+                       goto out;
        } else
                BUG();
 
@@ -565,7 +563,7 @@ void __init default_get_smp_config(unsigned int early)
        /*
         * Only use the first configuration found.
         */
-
+out:
        early_memunmap(mpf, sizeof(*mpf));
 }
 
index 98039d7..0aa6256 100644 (file)
@@ -370,7 +370,7 @@ struct paravirt_patch_template pv_ops = {
        .mmu.exit_mmap          = paravirt_nop,
 
 #ifdef CONFIG_PARAVIRT_XXL
-       .mmu.read_cr2           = native_read_cr2,
+       .mmu.read_cr2           = __PV_IS_CALLEE_SAVE(native_read_cr2),
        .mmu.write_cr2          = native_write_cr2,
        .mmu.read_cr3           = __native_read_cr3,
        .mmu.write_cr3          = native_write_cr3,
index 250e4c4..af64519 100644 (file)
@@ -143,17 +143,7 @@ void __show_regs(struct pt_regs *regs, enum show_regs_mode mode)
 
 void release_thread(struct task_struct *dead_task)
 {
-       if (dead_task->mm) {
-#ifdef CONFIG_MODIFY_LDT_SYSCALL
-               if (dead_task->mm->context.ldt) {
-                       pr_warn("WARNING: dead process %s still has LDT? <%p/%d>\n",
-                               dead_task->comm,
-                               dead_task->mm->context.ldt->entries,
-                               dead_task->mm->context.ldt->nr_entries);
-                       BUG();
-               }
-#endif
-       }
+       WARN_ON(dead_task->mm);
 }
 
 enum which_selector {
index 71691a8..0fdbe89 100644 (file)
@@ -369,12 +369,22 @@ static int putreg(struct task_struct *child,
        case offsetof(struct user_regs_struct,fs_base):
                if (value >= TASK_SIZE_MAX)
                        return -EIO;
-               x86_fsbase_write_task(child, value);
+               /*
+                * When changing the FS base, use do_arch_prctl_64()
+                * to set the index to zero and to set the base
+                * as requested.
+                */
+               if (child->thread.fsbase != value)
+                       return do_arch_prctl_64(child, ARCH_SET_FS, value);
                return 0;
        case offsetof(struct user_regs_struct,gs_base):
+               /*
+                * Exactly the same here as the %fs handling above.
+                */
                if (value >= TASK_SIZE_MAX)
                        return -EIO;
-               x86_gsbase_write_task(child, value);
+               if (child->thread.gsbase != value)
+                       return do_arch_prctl_64(child, ARCH_SET_GS, value);
                return 0;
 #endif
        }
index 259d1d2..fdbd47c 100644 (file)
@@ -1368,8 +1368,6 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
        pr_info("CPU0: ");
        print_cpu_info(&cpu_data(0));
 
-       native_pv_lock_init();
-
        uv_system_init();
 
        set_mtrr_aps_delayed_init();
@@ -1399,6 +1397,7 @@ void __init native_smp_prepare_boot_cpu(void)
        /* already set me in cpu_online_mask in boot_cpu_init() */
        cpumask_set_cpu(me, cpu_callout_mask);
        cpu_set_state_online(me);
+       native_pv_lock_init();
 }
 
 void __init calculate_max_logical_packages(void)
index 87095a4..4bb0f84 100644 (file)
@@ -313,13 +313,10 @@ __visible void __noreturn handle_stack_overflow(const char *message,
 
 #ifdef CONFIG_X86_64
 /* Runs on IST stack */
-dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
+dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code, unsigned long cr2)
 {
        static const char str[] = "double fault";
        struct task_struct *tsk = current;
-#ifdef CONFIG_VMAP_STACK
-       unsigned long cr2;
-#endif
 
 #ifdef CONFIG_X86_ESPFIX64
        extern unsigned char native_irq_return_iret[];
@@ -415,7 +412,6 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
         * stack even if the actual trigger for the double fault was
         * something else.
         */
-       cr2 = read_cr2();
        if ((unsigned long)task_stack_page(tsk) - 1 - cr2 < PAGE_SIZE)
                handle_stack_overflow("kernel stack overflow (double-fault)", regs, cr2);
 #endif
index 50a2b49..1bef687 100644 (file)
@@ -29,8 +29,8 @@ void x86_init_noop(void) { }
 void __init x86_init_uint_noop(unsigned int unused) { }
 static int __init iommu_init_noop(void) { return 0; }
 static void iommu_shutdown_noop(void) { }
-static bool __init bool_x86_init_noop(void) { return false; }
-static void x86_op_int_noop(int cpu) { }
+bool __init bool_x86_init_noop(void) { return false; }
+void x86_op_int_noop(int cpu) { }
 
 /*
  * The platform setup functions are preset with the default functions
index ead6812..22c2720 100644 (file)
@@ -368,9 +368,13 @@ static inline void do_cpuid_7_mask(struct kvm_cpuid_entry2 *entry, int index)
                F(SPEC_CTRL_SSBD) | F(ARCH_CAPABILITIES) | F(INTEL_STIBP) |
                F(MD_CLEAR);
 
+       /* cpuid 7.1.eax */
+       const u32 kvm_cpuid_7_1_eax_x86_features =
+               F(AVX512_BF16);
+
        switch (index) {
        case 0:
-               entry->eax = 0;
+               entry->eax = min(entry->eax, 1u);
                entry->ebx &= kvm_cpuid_7_0_ebx_x86_features;
                cpuid_mask(&entry->ebx, CPUID_7_0_EBX);
                /* TSC_ADJUST is emulated */
@@ -394,6 +398,12 @@ static inline void do_cpuid_7_mask(struct kvm_cpuid_entry2 *entry, int index)
                 */
                entry->edx |= F(ARCH_CAPABILITIES);
                break;
+       case 1:
+               entry->eax &= kvm_cpuid_7_1_eax_x86_features;
+               entry->ebx = 0;
+               entry->ecx = 0;
+               entry->edx = 0;
+               break;
        default:
                WARN_ON_ONCE(1);
                entry->eax = 0;
index 8e409ad..718f7d9 100644 (file)
@@ -312,29 +312,42 @@ static void invalidate_registers(struct x86_emulate_ctxt *ctxt)
 
 static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *));
 
-#define FOP_FUNC(name) \
+#define __FOP_FUNC(name) \
        ".align " __stringify(FASTOP_SIZE) " \n\t" \
        ".type " name ", @function \n\t" \
        name ":\n\t"
 
-#define FOP_RET   "ret \n\t"
+#define FOP_FUNC(name) \
+       __FOP_FUNC(#name)
+
+#define __FOP_RET(name) \
+       "ret \n\t" \
+       ".size " name ", .-" name "\n\t"
+
+#define FOP_RET(name) \
+       __FOP_RET(#name)
 
 #define FOP_START(op) \
        extern void em_##op(struct fastop *fake); \
        asm(".pushsection .text, \"ax\" \n\t" \
            ".global em_" #op " \n\t" \
-           FOP_FUNC("em_" #op)
+           ".align " __stringify(FASTOP_SIZE) " \n\t" \
+           "em_" #op ":\n\t"
 
 #define FOP_END \
            ".popsection")
 
+#define __FOPNOP(name) \
+       __FOP_FUNC(name) \
+       __FOP_RET(name)
+
 #define FOPNOP() \
-       FOP_FUNC(__stringify(__UNIQUE_ID(nop))) \
-       FOP_RET
+       __FOPNOP(__stringify(__UNIQUE_ID(nop)))
 
 #define FOP1E(op,  dst) \
-       FOP_FUNC(#op "_" #dst) \
-       "10: " #op " %" #dst " \n\t" FOP_RET
+       __FOP_FUNC(#op "_" #dst) \
+       "10: " #op " %" #dst " \n\t" \
+       __FOP_RET(#op "_" #dst)
 
 #define FOP1EEX(op,  dst) \
        FOP1E(op, dst) _ASM_EXTABLE(10b, kvm_fastop_exception)
@@ -366,8 +379,9 @@ static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *));
        FOP_END
 
 #define FOP2E(op,  dst, src)      \
-       FOP_FUNC(#op "_" #dst "_" #src) \
-       #op " %" #src ", %" #dst " \n\t" FOP_RET
+       __FOP_FUNC(#op "_" #dst "_" #src) \
+       #op " %" #src ", %" #dst " \n\t" \
+       __FOP_RET(#op "_" #dst "_" #src)
 
 #define FASTOP2(op) \
        FOP_START(op) \
@@ -405,8 +419,9 @@ static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *));
        FOP_END
 
 #define FOP3E(op,  dst, src, src2) \
-       FOP_FUNC(#op "_" #dst "_" #src "_" #src2) \
-       #op " %" #src2 ", %" #src ", %" #dst " \n\t" FOP_RET
+       __FOP_FUNC(#op "_" #dst "_" #src "_" #src2) \
+       #op " %" #src2 ", %" #src ", %" #dst " \n\t"\
+       __FOP_RET(#op "_" #dst "_" #src "_" #src2)
 
 /* 3-operand, word-only, src2=cl */
 #define FASTOP3WCL(op) \
@@ -423,7 +438,7 @@ static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *));
        ".type " #op ", @function \n\t" \
        #op ": \n\t" \
        #op " %al \n\t" \
-       FOP_RET
+       __FOP_RET(#op)
 
 asm(".pushsection .fixup, \"ax\"\n"
     ".global kvm_fastop_exception \n"
@@ -449,7 +464,10 @@ FOP_SETCC(setle)
 FOP_SETCC(setnle)
 FOP_END;
 
-FOP_START(salc) "pushf; sbb %al, %al; popf \n\t" FOP_RET
+FOP_START(salc)
+FOP_FUNC(salc)
+"pushf; sbb %al, %al; popf \n\t"
+FOP_RET(salc)
 FOP_END;
 
 /*
index a39e38f..c10a8b1 100644 (file)
@@ -1594,7 +1594,7 @@ 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, longmode, rep;
+       bool fast, rep;
 
        /*
         * hypercall generates UD from non zero cpl and real mode
@@ -1605,9 +1605,14 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
                return 1;
        }
 
-       longmode = is_64_bit_mode(vcpu);
-
-       if (!longmode) {
+#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);
+       } else
+#endif
+       {
                param = ((u64)kvm_rdx_read(vcpu) << 32) |
                        (kvm_rax_read(vcpu) & 0xffffffff);
                ingpa = ((u64)kvm_rbx_read(vcpu) << 32) |
@@ -1615,13 +1620,6 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
                outgpa = ((u64)kvm_rdi_read(vcpu) << 32) |
                        (kvm_rsi_read(vcpu) & 0xffffffff);
        }
-#ifdef CONFIG_X86_64
-       else {
-               param = kvm_rcx_read(vcpu);
-               ingpa = kvm_rdx_read(vcpu);
-               outgpa = kvm_r8_read(vcpu);
-       }
-#endif
 
        code = param & 0xffff;
        fast = !!(param & HV_HYPERCALL_FAST_BIT);
index 1add1bc..d859ae8 100644 (file)
 #include "lapic.h"
 #include "irq.h"
 
-#if 0
-#define ioapic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg)
-#else
-#define ioapic_debug(fmt, arg...)
-#endif
 static int ioapic_service(struct kvm_ioapic *vioapic, int irq,
                bool line_status);
 
@@ -294,7 +289,6 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
        default:
                index = (ioapic->ioregsel - 0x10) >> 1;
 
-               ioapic_debug("change redir index %x val %x\n", index, val);
                if (index >= IOAPIC_NUM_PINS)
                        return;
                e = &ioapic->redirtbl[index];
@@ -343,12 +337,6 @@ static int ioapic_service(struct kvm_ioapic *ioapic, int irq, bool line_status)
            entry->fields.remote_irr))
                return -1;
 
-       ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x "
-                    "vector=%x trig_mode=%x\n",
-                    entry->fields.dest_id, entry->fields.dest_mode,
-                    entry->fields.delivery_mode, entry->fields.vector,
-                    entry->fields.trig_mode);
-
        irqe.dest_id = entry->fields.dest_id;
        irqe.vector = entry->fields.vector;
        irqe.dest_mode = entry->fields.dest_mode;
@@ -515,7 +503,6 @@ static int ioapic_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
        if (!ioapic_in_range(ioapic, addr))
                return -EOPNOTSUPP;
 
-       ioapic_debug("addr %lx\n", (unsigned long)addr);
        ASSERT(!(addr & 0xf));  /* check alignment */
 
        addr &= 0xff;
@@ -558,8 +545,6 @@ static int ioapic_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
        if (!ioapic_in_range(ioapic, addr))
                return -EOPNOTSUPP;
 
-       ioapic_debug("ioapic_mmio_write addr=%p len=%d val=%p\n",
-                    (void*)addr, len, val);
        ASSERT(!(addr & 0xf));  /* check alignment */
 
        switch (len) {
index a232e76..0aa1586 100644 (file)
@@ -52,9 +52,6 @@
 #define PRIu64 "u"
 #define PRIo64 "o"
 
-/* #define apic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) */
-#define apic_debug(fmt, arg...) do {} while (0)
-
 /* 14 is the version for Xeon and Pentium 8.4.8*/
 #define APIC_VERSION                   (0x14UL | ((KVM_APIC_LVT_NUM - 1) << 16))
 #define LAPIC_MMIO_LENGTH              (1 << 12)
@@ -121,6 +118,17 @@ static inline u32 kvm_x2apic_id(struct kvm_lapic *apic)
        return apic->vcpu->vcpu_id;
 }
 
+bool kvm_can_post_timer_interrupt(struct kvm_vcpu *vcpu)
+{
+       return pi_inject_timer && kvm_vcpu_apicv_active(vcpu);
+}
+EXPORT_SYMBOL_GPL(kvm_can_post_timer_interrupt);
+
+static bool kvm_use_posted_timer_interrupt(struct kvm_vcpu *vcpu)
+{
+       return kvm_can_post_timer_interrupt(vcpu) && vcpu->mode == IN_GUEST_MODE;
+}
+
 static inline bool kvm_apic_map_get_logical_dest(struct kvm_apic_map *map,
                u32 dest_id, struct kvm_lapic ***cluster, u16 *mask) {
        switch (map->mode) {
@@ -627,7 +635,7 @@ static bool pv_eoi_get_pending(struct kvm_vcpu *vcpu)
 {
        u8 val;
        if (pv_eoi_get_user(vcpu, &val) < 0)
-               apic_debug("Can't read EOI MSR value: 0x%llx\n",
+               printk(KERN_WARNING "Can't read EOI MSR value: 0x%llx\n",
                           (unsigned long long)vcpu->arch.pv_eoi.msr_val);
        return val & 0x1;
 }
@@ -635,7 +643,7 @@ static bool pv_eoi_get_pending(struct kvm_vcpu *vcpu)
 static void pv_eoi_set_pending(struct kvm_vcpu *vcpu)
 {
        if (pv_eoi_put_user(vcpu, KVM_PV_EOI_ENABLED) < 0) {
-               apic_debug("Can't set EOI MSR value: 0x%llx\n",
+               printk(KERN_WARNING "Can't set EOI MSR value: 0x%llx\n",
                           (unsigned long long)vcpu->arch.pv_eoi.msr_val);
                return;
        }
@@ -645,7 +653,7 @@ static void pv_eoi_set_pending(struct kvm_vcpu *vcpu)
 static void pv_eoi_clr_pending(struct kvm_vcpu *vcpu)
 {
        if (pv_eoi_put_user(vcpu, KVM_PV_EOI_DISABLED) < 0) {
-               apic_debug("Can't clear EOI MSR value: 0x%llx\n",
+               printk(KERN_WARNING "Can't clear EOI MSR value: 0x%llx\n",
                           (unsigned long long)vcpu->arch.pv_eoi.msr_val);
                return;
        }
@@ -679,9 +687,6 @@ static bool __apic_update_ppr(struct kvm_lapic *apic, u32 *new_ppr)
        else
                ppr = isrv & 0xf0;
 
-       apic_debug("vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x",
-                  apic, ppr, isr, isrv);
-
        *new_ppr = ppr;
        if (old_ppr != ppr)
                kvm_lapic_set_reg(apic, APIC_PROCPRI, ppr);
@@ -758,8 +763,6 @@ static bool kvm_apic_match_logical_addr(struct kvm_lapic *apic, u32 mda)
                return ((logical_id >> 4) == (mda >> 4))
                       && (logical_id & mda & 0xf) != 0;
        default:
-               apic_debug("Bad DFR vcpu %d: %08x\n",
-                          apic->vcpu->vcpu_id, kvm_lapic_get_reg(apic, APIC_DFR));
                return false;
        }
 }
@@ -798,10 +801,6 @@ bool kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
        struct kvm_lapic *target = vcpu->arch.apic;
        u32 mda = kvm_apic_mda(vcpu, dest, source, target);
 
-       apic_debug("target %p, source %p, dest 0x%x, "
-                  "dest_mode 0x%x, short_hand 0x%x\n",
-                  target, source, dest, dest_mode, short_hand);
-
        ASSERT(target);
        switch (short_hand) {
        case APIC_DEST_NOSHORT:
@@ -816,8 +815,6 @@ bool kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
        case APIC_DEST_ALLBUT:
                return target != source;
        default:
-               apic_debug("kvm: apic: Bad dest shorthand value %x\n",
-                          short_hand);
                return false;
        }
 }
@@ -1095,15 +1092,10 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
                        smp_wmb();
                        kvm_make_request(KVM_REQ_EVENT, vcpu);
                        kvm_vcpu_kick(vcpu);
-               } else {
-                       apic_debug("Ignoring de-assert INIT to vcpu %d\n",
-                                  vcpu->vcpu_id);
                }
                break;
 
        case APIC_DM_STARTUP:
-               apic_debug("SIPI to vcpu %d vector 0x%02x\n",
-                          vcpu->vcpu_id, vector);
                result = 1;
                apic->sipi_vector = vector;
                /* make sure sipi_vector is visible for the receiver */
@@ -1221,14 +1213,6 @@ static void apic_send_ipi(struct kvm_lapic *apic)
 
        trace_kvm_apic_ipi(icr_low, irq.dest_id);
 
-       apic_debug("icr_high 0x%x, icr_low 0x%x, "
-                  "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
-                  "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x, "
-                  "msi_redir_hint 0x%x\n",
-                  icr_high, icr_low, irq.shorthand, irq.dest_id,
-                  irq.trig_mode, irq.level, irq.dest_mode, irq.delivery_mode,
-                  irq.vector, irq.msi_redir_hint);
-
        kvm_irq_delivery_to_apic(apic->vcpu->kvm, apic, &irq, NULL);
 }
 
@@ -1282,7 +1266,6 @@ static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset)
 
        switch (offset) {
        case APIC_ARBPRI:
-               apic_debug("Access APIC ARBPRI register which is for P6\n");
                break;
 
        case APIC_TMCCT:        /* Timer CCR */
@@ -1349,11 +1332,8 @@ 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 (offset > 0x3f0 || !(valid_reg_mask & APIC_REG_MASK(offset))) {
-               apic_debug("KVM_APIC_READ: read reserved register %x\n",
-                          offset);
+       if (offset > 0x3f0 || !(valid_reg_mask & APIC_REG_MASK(offset)))
                return 1;
-       }
 
        result = __apic_read(apic, offset & ~0xf);
 
@@ -1411,9 +1391,6 @@ static void update_divide_count(struct kvm_lapic *apic)
        tmp1 = tdcr & 0xf;
        tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1;
        apic->divide_count = 0x1 << (tmp2 & 0x7);
-
-       apic_debug("timer divide count is 0x%x\n",
-                                  apic->divide_count);
 }
 
 static void limit_periodic_timer_frequency(struct kvm_lapic *apic)
@@ -1455,29 +1432,6 @@ static void apic_update_lvtt(struct kvm_lapic *apic)
        }
 }
 
-static void apic_timer_expired(struct kvm_lapic *apic)
-{
-       struct kvm_vcpu *vcpu = apic->vcpu;
-       struct swait_queue_head *q = &vcpu->wq;
-       struct kvm_timer *ktimer = &apic->lapic_timer;
-
-       if (atomic_read(&apic->lapic_timer.pending))
-               return;
-
-       atomic_inc(&apic->lapic_timer.pending);
-       kvm_set_pending_timer(vcpu);
-
-       /*
-        * For x86, the atomic_inc() is serialized, thus
-        * using swait_active() is safe.
-        */
-       if (swait_active(q))
-               swake_up_one(q);
-
-       if (apic_lvtt_tscdeadline(apic) || ktimer->hv_timer_in_use)
-               ktimer->expired_tscdeadline = ktimer->tscdeadline;
-}
-
 /*
  * On APICv, this test will cause a busy wait
  * during a higher-priority task.
@@ -1551,7 +1505,7 @@ static inline void adjust_lapic_timer_advance(struct kvm_vcpu *vcpu,
        apic->lapic_timer.timer_advance_ns = timer_advance_ns;
 }
 
-void kvm_wait_lapic_expire(struct kvm_vcpu *vcpu)
+static void __kvm_wait_lapic_expire(struct kvm_vcpu *vcpu)
 {
        struct kvm_lapic *apic = vcpu->arch.apic;
        u64 guest_tsc, tsc_deadline;
@@ -1559,9 +1513,6 @@ void kvm_wait_lapic_expire(struct kvm_vcpu *vcpu)
        if (apic->lapic_timer.expired_tscdeadline == 0)
                return;
 
-       if (!lapic_timer_int_injected(vcpu))
-               return;
-
        tsc_deadline = apic->lapic_timer.expired_tscdeadline;
        apic->lapic_timer.expired_tscdeadline = 0;
        guest_tsc = kvm_read_l1_tsc(vcpu, rdtsc());
@@ -1573,8 +1524,57 @@ void kvm_wait_lapic_expire(struct kvm_vcpu *vcpu)
        if (unlikely(!apic->lapic_timer.timer_advance_adjust_done))
                adjust_lapic_timer_advance(vcpu, apic->lapic_timer.advance_expire_delta);
 }
+
+void kvm_wait_lapic_expire(struct kvm_vcpu *vcpu)
+{
+       if (lapic_timer_int_injected(vcpu))
+               __kvm_wait_lapic_expire(vcpu);
+}
 EXPORT_SYMBOL_GPL(kvm_wait_lapic_expire);
 
+static void kvm_apic_inject_pending_timer_irqs(struct kvm_lapic *apic)
+{
+       struct kvm_timer *ktimer = &apic->lapic_timer;
+
+       kvm_apic_local_deliver(apic, APIC_LVTT);
+       if (apic_lvtt_tscdeadline(apic))
+               ktimer->tscdeadline = 0;
+       if (apic_lvtt_oneshot(apic)) {
+               ktimer->tscdeadline = 0;
+               ktimer->target_expiration = 0;
+       }
+}
+
+static void apic_timer_expired(struct kvm_lapic *apic)
+{
+       struct kvm_vcpu *vcpu = apic->vcpu;
+       struct swait_queue_head *q = &vcpu->wq;
+       struct kvm_timer *ktimer = &apic->lapic_timer;
+
+       if (atomic_read(&apic->lapic_timer.pending))
+               return;
+
+       if (apic_lvtt_tscdeadline(apic) || ktimer->hv_timer_in_use)
+               ktimer->expired_tscdeadline = ktimer->tscdeadline;
+
+       if (kvm_use_posted_timer_interrupt(apic->vcpu)) {
+               if (apic->lapic_timer.timer_advance_ns)
+                       __kvm_wait_lapic_expire(vcpu);
+               kvm_apic_inject_pending_timer_irqs(apic);
+               return;
+       }
+
+       atomic_inc(&apic->lapic_timer.pending);
+       kvm_set_pending_timer(vcpu);
+
+       /*
+        * For x86, the atomic_inc() is serialized, thus
+        * using swait_active() is safe.
+        */
+       if (swait_active(q))
+               swake_up_one(q);
+}
+
 static void start_sw_tscdeadline(struct kvm_lapic *apic)
 {
        struct kvm_timer *ktimer = &apic->lapic_timer;
@@ -1601,7 +1601,7 @@ static void start_sw_tscdeadline(struct kvm_lapic *apic)
            likely(ns > apic->lapic_timer.timer_advance_ns)) {
                expire = ktime_add_ns(now, ns);
                expire = ktime_sub_ns(expire, ktimer->timer_advance_ns);
-               hrtimer_start(&ktimer->timer, expire, HRTIMER_MODE_ABS_PINNED);
+               hrtimer_start(&ktimer->timer, expire, HRTIMER_MODE_ABS);
        } else
                apic_timer_expired(apic);
 
@@ -1648,16 +1648,6 @@ static bool set_target_expiration(struct kvm_lapic *apic)
 
        limit_periodic_timer_frequency(apic);
 
-       apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016"
-                  PRIx64 ", "
-                  "timer initial count 0x%x, period %lldns, "
-                  "expire @ 0x%016" PRIx64 ".\n", __func__,
-                  APIC_BUS_CYCLE_NS, ktime_to_ns(now),
-                  kvm_lapic_get_reg(apic, APIC_TMICT),
-                  apic->lapic_timer.period,
-                  ktime_to_ns(ktime_add_ns(now,
-                               apic->lapic_timer.period)));
-
        apic->lapic_timer.tscdeadline = kvm_read_l1_tsc(apic->vcpu, tscl) +
                nsec_to_cycles(apic->vcpu, apic->lapic_timer.period);
        apic->lapic_timer.target_expiration = ktime_add_ns(now, apic->lapic_timer.period);
@@ -1703,7 +1693,7 @@ static void start_sw_period(struct kvm_lapic *apic)
 
        hrtimer_start(&apic->lapic_timer.timer,
                apic->lapic_timer.target_expiration,
-               HRTIMER_MODE_ABS_PINNED);
+               HRTIMER_MODE_ABS);
 }
 
 bool kvm_lapic_hv_timer_in_use(struct kvm_vcpu *vcpu)
@@ -1860,8 +1850,6 @@ static void apic_manage_nmi_watchdog(struct kvm_lapic *apic, u32 lvt0_val)
        if (apic->lvt0_in_nmi_mode != lvt0_in_nmi_mode) {
                apic->lvt0_in_nmi_mode = lvt0_in_nmi_mode;
                if (lvt0_in_nmi_mode) {
-                       apic_debug("Receive NMI setting on APIC_LVT0 "
-                                  "for cpu %d\n", apic->vcpu->vcpu_id);
                        atomic_inc(&apic->vcpu->kvm->arch.vapics_in_nmi_mode);
                } else
                        atomic_dec(&apic->vcpu->kvm->arch.vapics_in_nmi_mode);
@@ -1975,8 +1963,6 @@ int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
        case APIC_TDCR: {
                uint32_t old_divisor = apic->divide_count;
 
-               if (val & 4)
-                       apic_debug("KVM_WRITE:TDCR %x\n", val);
                kvm_lapic_set_reg(apic, APIC_TDCR, val);
                update_divide_count(apic);
                if (apic->divide_count != old_divisor &&
@@ -1988,10 +1974,8 @@ int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
                break;
        }
        case APIC_ESR:
-               if (apic_x2apic_mode(apic) && val != 0) {
-                       apic_debug("KVM_WRITE:ESR not zero %x\n", val);
+               if (apic_x2apic_mode(apic) && val != 0)
                        ret = 1;
-               }
                break;
 
        case APIC_SELF_IPI:
@@ -2004,8 +1988,7 @@ int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
                ret = 1;
                break;
        }
-       if (ret)
-               apic_debug("Local APIC Write to read-only register %x\n", reg);
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(kvm_lapic_reg_write);
@@ -2033,20 +2016,12 @@ static int apic_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
         * 32/64/128 bits registers must be accessed thru 32 bits.
         * Refer SDM 8.4.1
         */
-       if (len != 4 || (offset & 0xf)) {
-               /* Don't shout loud, $infamous_os would cause only noise. */
-               apic_debug("apic write: bad size=%d %lx\n", len, (long)address);
+       if (len != 4 || (offset & 0xf))
                return 0;
-       }
 
        val = *(u32*)data;
 
-       /* too common printing */
-       if (offset != APIC_EOI)
-               apic_debug("%s: offset 0x%x with length 0x%x, and value is "
-                          "0x%x\n", __func__, offset, len, val);
-
-       kvm_lapic_reg_write(apic, offset, val);
+       kvm_lapic_reg_write(apic, offset & 0xff0, val);
 
        return 0;
 }
@@ -2178,11 +2153,6 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
        if ((value & MSR_IA32_APICBASE_ENABLE) &&
             apic->base_address != APIC_DEFAULT_PHYS_BASE)
                pr_warn_once("APIC base relocation is unsupported by KVM");
-
-       /* with FSB delivery interrupt, we can restart APIC functionality */
-       apic_debug("apic base msr is 0x%016" PRIx64 ", and base address is "
-                  "0x%lx.\n", apic->vcpu->arch.apic_base, apic->base_address);
-
 }
 
 void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
@@ -2193,8 +2163,6 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
        if (!apic)
                return;
 
-       apic_debug("%s\n", __func__);
-
        /* Stop the timer in case it's a reset to an active apic */
        hrtimer_cancel(&apic->lapic_timer.timer);
 
@@ -2247,11 +2215,6 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
 
        vcpu->arch.apic_arb_prio = 0;
        vcpu->arch.apic_attention = 0;
-
-       apic_debug("%s: vcpu=%p, id=0x%x, base_msr="
-                  "0x%016" PRIx64 ", base_address=0x%0lx.\n", __func__,
-                  vcpu, kvm_lapic_get_reg(apic, APIC_ID),
-                  vcpu->arch.apic_base, apic->base_address);
 }
 
 /*
@@ -2323,7 +2286,6 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu, int timer_advance_ns)
        struct kvm_lapic *apic;
 
        ASSERT(vcpu != NULL);
-       apic_debug("apic_init %d\n", vcpu->vcpu_id);
 
        apic = kzalloc(sizeof(*apic), GFP_KERNEL_ACCOUNT);
        if (!apic)
@@ -2340,7 +2302,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu, int timer_advance_ns)
        apic->vcpu = vcpu;
 
        hrtimer_init(&apic->lapic_timer.timer, CLOCK_MONOTONIC,
-                    HRTIMER_MODE_ABS_PINNED);
+                    HRTIMER_MODE_ABS);
        apic->lapic_timer.timer.function = apic_timer_fn;
        if (timer_advance_ns == -1) {
                apic->lapic_timer.timer_advance_ns = LAPIC_TIMER_ADVANCE_ADJUST_INIT;
@@ -2397,13 +2359,7 @@ void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu)
        struct kvm_lapic *apic = vcpu->arch.apic;
 
        if (atomic_read(&apic->lapic_timer.pending) > 0) {
-               kvm_apic_local_deliver(apic, APIC_LVTT);
-               if (apic_lvtt_tscdeadline(apic))
-                       apic->lapic_timer.tscdeadline = 0;
-               if (apic_lvtt_oneshot(apic)) {
-                       apic->lapic_timer.tscdeadline = 0;
-                       apic->lapic_timer.target_expiration = 0;
-               }
+               kvm_apic_inject_pending_timer_irqs(apic);
                atomic_set(&apic->lapic_timer.pending, 0);
        }
 }
@@ -2525,12 +2481,13 @@ void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
 {
        struct hrtimer *timer;
 
-       if (!lapic_in_kernel(vcpu))
+       if (!lapic_in_kernel(vcpu) ||
+               kvm_can_post_timer_interrupt(vcpu))
                return;
 
        timer = &vcpu->arch.apic->lapic_timer.timer;
        if (hrtimer_cancel(timer))
-               hrtimer_start_expires(timer, HRTIMER_MODE_ABS_PINNED);
+               hrtimer_start_expires(timer, HRTIMER_MODE_ABS);
 }
 
 /*
@@ -2678,11 +2635,8 @@ int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data)
        if (!lapic_in_kernel(vcpu) || !apic_x2apic_mode(apic))
                return 1;
 
-       if (reg == APIC_DFR || reg == APIC_ICR2) {
-               apic_debug("KVM_APIC_READ: read x2apic reserved register %x\n",
-                          reg);
+       if (reg == APIC_DFR || reg == APIC_ICR2)
                return 1;
-       }
 
        if (kvm_lapic_reg_read(apic, reg, 4, &low))
                return 1;
@@ -2780,8 +2734,6 @@ void kvm_apic_accept_events(struct kvm_vcpu *vcpu)
                /* evaluate pending_events before reading the vector */
                smp_rmb();
                sipi_vector = apic->sipi_vector;
-               apic_debug("vcpu %d received sipi with vector # %x\n",
-                        vcpu->vcpu_id, sipi_vector);
                kvm_vcpu_deliver_sipi_vector(vcpu, sipi_vector);
                vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
        }
index 3674717..50053d2 100644 (file)
@@ -236,6 +236,7 @@ void kvm_lapic_switch_to_hv_timer(struct kvm_vcpu *vcpu);
 void kvm_lapic_expired_hv_timer(struct kvm_vcpu *vcpu);
 bool kvm_lapic_hv_timer_in_use(struct kvm_vcpu *vcpu);
 void kvm_lapic_restart_hv_timer(struct kvm_vcpu *vcpu);
+bool kvm_can_post_timer_interrupt(struct kvm_vcpu *vcpu);
 
 static inline enum lapic_mode kvm_apic_mode(u64 apic_base)
 {
index 9a5814d..24843cf 100644 (file)
@@ -3466,7 +3466,7 @@ static bool fast_page_fault(struct kvm_vcpu *vcpu, gva_t gva, int level,
                /*
                 * Currently, fast page fault only works for direct mapping
                 * since the gfn is not stable for indirect shadow page. See
-                * Documentation/virtual/kvm/locking.txt to get more detail.
+                * Documentation/virt/kvm/locking.txt to get more detail.
                 */
                fault_handled = fast_pf_fix_direct_spte(vcpu, sp,
                                                        iterator.sptep, spte,
@@ -4597,11 +4597,11 @@ static void update_permission_bitmask(struct kvm_vcpu *vcpu,
                 */
 
                /* Faults from writes to non-writable pages */
-               u8 wf = (pfec & PFERR_WRITE_MASK) ? ~w : 0;
+               u8 wf = (pfec & PFERR_WRITE_MASK) ? (u8)~w : 0;
                /* Faults from user mode accesses to supervisor pages */
-               u8 uf = (pfec & PFERR_USER_MASK) ? ~u : 0;
+               u8 uf = (pfec & PFERR_USER_MASK) ? (u8)~u : 0;
                /* Faults from fetches of non-executable pages*/
-               u8 ff = (pfec & PFERR_FETCH_MASK) ? ~x : 0;
+               u8 ff = (pfec & PFERR_FETCH_MASK) ? (u8)~x : 0;
                /* Faults from kernel mode fetches of user pages */
                u8 smepf = 0;
                /* Faults from kernel mode accesses of user pages */
index aa5a259..46875bb 100644 (file)
@@ -19,8 +19,8 @@
 #include "lapic.h"
 #include "pmu.h"
 
-/* This keeps the total size of the filter under 4k. */
-#define KVM_PMU_EVENT_FILTER_MAX_EVENTS 63
+/* This is enough to filter the vast majority of currently defined events. */
+#define KVM_PMU_EVENT_FILTER_MAX_EVENTS 300
 
 /* NOTE:
  * - Each perf counter is defined as "struct kvm_pmc";
@@ -131,8 +131,8 @@ static void pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type,
                                                 intr ? kvm_perf_overflow_intr :
                                                 kvm_perf_overflow, pmc);
        if (IS_ERR(event)) {
-               printk_once("kvm_pmu: event creation failed %ld\n",
-                           PTR_ERR(event));
+               pr_debug_ratelimited("kvm_pmu: event creation failed %ld for pmc->idx = %d\n",
+                           PTR_ERR(event), pmc->idx);
                return;
        }
 
@@ -206,12 +206,24 @@ void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 ctrl, int idx)
 {
        unsigned en_field = ctrl & 0x3;
        bool pmi = ctrl & 0x8;
+       struct kvm_pmu_event_filter *filter;
+       struct kvm *kvm = pmc->vcpu->kvm;
 
        pmc_stop_counter(pmc);
 
        if (!en_field || !pmc_is_enabled(pmc))
                return;
 
+       filter = srcu_dereference(kvm->arch.pmu_event_filter, &kvm->srcu);
+       if (filter) {
+               if (filter->action == KVM_PMU_EVENT_DENY &&
+                   test_bit(idx, (ulong *)&filter->fixed_counter_bitmap))
+                       return;
+               if (filter->action == KVM_PMU_EVENT_ALLOW &&
+                   !test_bit(idx, (ulong *)&filter->fixed_counter_bitmap))
+                       return;
+       }
+
        pmc_reprogram_counter(pmc, PERF_TYPE_HARDWARE,
                              kvm_x86_ops->pmu_ops->find_fixed_event(idx),
                              !(en_field & 0x2), /* exclude user */
@@ -385,6 +397,9 @@ int kvm_vm_ioctl_set_pmu_event_filter(struct kvm *kvm, void __user *argp)
            tmp.action != KVM_PMU_EVENT_DENY)
                return -EINVAL;
 
+       if (tmp.flags != 0)
+               return -EINVAL;
+
        if (tmp.nevents > KVM_PMU_EVENT_FILTER_MAX_EVENTS)
                return -E2BIG;
 
@@ -406,8 +421,8 @@ int kvm_vm_ioctl_set_pmu_event_filter(struct kvm *kvm, void __user *argp)
        mutex_unlock(&kvm->lock);
 
        synchronize_srcu_expedited(&kvm->srcu);
-       r = 0;
+       r = 0;
 cleanup:
        kfree(filter);
-       return r;
+       return r;
 }
index 583b9fa..7eafc69 100644 (file)
@@ -2143,12 +2143,20 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
                goto out;
        }
 
+       svm->vcpu.arch.user_fpu = kmem_cache_zalloc(x86_fpu_cache,
+                                                    GFP_KERNEL_ACCOUNT);
+       if (!svm->vcpu.arch.user_fpu) {
+               printk(KERN_ERR "kvm: failed to allocate kvm userspace's fpu\n");
+               err = -ENOMEM;
+               goto free_partial_svm;
+       }
+
        svm->vcpu.arch.guest_fpu = kmem_cache_zalloc(x86_fpu_cache,
                                                     GFP_KERNEL_ACCOUNT);
        if (!svm->vcpu.arch.guest_fpu) {
                printk(KERN_ERR "kvm: failed to allocate vcpu's fpu\n");
                err = -ENOMEM;
-               goto free_partial_svm;
+               goto free_user_fpu;
        }
 
        err = kvm_vcpu_init(&svm->vcpu, kvm, id);
@@ -2211,6 +2219,8 @@ uninit:
        kvm_vcpu_uninit(&svm->vcpu);
 free_svm:
        kmem_cache_free(x86_fpu_cache, svm->vcpu.arch.guest_fpu);
+free_user_fpu:
+       kmem_cache_free(x86_fpu_cache, svm->vcpu.arch.user_fpu);
 free_partial_svm:
        kmem_cache_free(kvm_vcpu_cache, svm);
 out:
@@ -2241,6 +2251,7 @@ static void svm_free_vcpu(struct kvm_vcpu *vcpu)
        __free_page(virt_to_page(svm->nested.hsave));
        __free_pages(virt_to_page(svm->nested.msrpm), MSRPM_ALLOC_ORDER);
        kvm_vcpu_uninit(vcpu);
+       kmem_cache_free(x86_fpu_cache, svm->vcpu.arch.user_fpu);
        kmem_cache_free(x86_fpu_cache, svm->vcpu.arch.guest_fpu);
        kmem_cache_free(kvm_vcpu_cache, svm);
 }
@@ -7128,13 +7139,41 @@ static int nested_enable_evmcs(struct kvm_vcpu *vcpu,
 
 static bool svm_need_emulation_on_page_fault(struct kvm_vcpu *vcpu)
 {
-       bool is_user, smap;
-
-       is_user = svm_get_cpl(vcpu) == 3;
-       smap = !kvm_read_cr4_bits(vcpu, X86_CR4_SMAP);
+       unsigned long cr4 = kvm_read_cr4(vcpu);
+       bool smep = cr4 & X86_CR4_SMEP;
+       bool smap = cr4 & X86_CR4_SMAP;
+       bool is_user = svm_get_cpl(vcpu) == 3;
 
        /*
-        * Detect and workaround Errata 1096 Fam_17h_00_0Fh
+        * Detect and workaround Errata 1096 Fam_17h_00_0Fh.
+        *
+        * Errata:
+        * When CPU raise #NPF on guest data access and vCPU CR4.SMAP=1, it is
+        * possible that CPU microcode implementing DecodeAssist will fail
+        * to read bytes of instruction which caused #NPF. In this case,
+        * GuestIntrBytes field of the VMCB on a VMEXIT will incorrectly
+        * return 0 instead of the correct guest instruction bytes.
+        *
+        * This happens because CPU microcode reading instruction bytes
+        * uses a special opcode which attempts to read data using CPL=0
+        * priviledges. The microcode reads CS:RIP and if it hits a SMAP
+        * fault, it gives up and returns no instruction bytes.
+        *
+        * Detection:
+        * We reach here in case CPU supports DecodeAssist, raised #NPF and
+        * returned 0 in GuestIntrBytes field of the VMCB.
+        * First, errata can only be triggered in case vCPU CR4.SMAP=1.
+        * Second, if vCPU CR4.SMEP=1, errata could only be triggered
+        * in case vCPU CPL==3 (Because otherwise guest would have triggered
+        * a SMEP fault instead of #NPF).
+        * Otherwise, vCPU CR4.SMEP=0, errata could be triggered by any vCPU CPL.
+        * As most guests enable SMAP if they have also enabled SMEP, use above
+        * logic in order to attempt minimize false-positive of detecting errata
+        * while still preserving all cases semantic correctness.
+        *
+        * Workaround:
+        * To determine what instruction the guest was executing, the hypervisor
+        * will have to decode the instruction at the instruction pointer.
         *
         * In non SEV guest, hypervisor will be able to read the guest
         * memory to decode the instruction pointer when insn_len is zero
@@ -7145,11 +7184,11 @@ static bool svm_need_emulation_on_page_fault(struct kvm_vcpu *vcpu)
         * instruction pointer so we will not able to workaround it. Lets
         * print the error and request to kill the guest.
         */
-       if (is_user && smap) {
+       if (smap && (!smep || is_user)) {
                if (!sev_guest(vcpu->kvm))
                        return true;
 
-               pr_err_ratelimited("KVM: Guest triggered AMD Erratum 1096\n");
+               pr_err_ratelimited("KVM: SEV Guest triggered AMD Erratum 1096\n");
                kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
        }
 
index bb509c2..ced9fba 100644 (file)
@@ -194,6 +194,7 @@ static void vmx_disable_shadow_vmcs(struct vcpu_vmx *vmx)
 {
        secondary_exec_controls_clearbit(vmx, SECONDARY_EXEC_SHADOW_VMCS);
        vmcs_write64(VMCS_LINK_POINTER, -1ull);
+       vmx->nested.need_vmcs12_to_shadow_sync = false;
 }
 
 static inline void nested_release_evmcs(struct kvm_vcpu *vcpu)
@@ -219,6 +220,8 @@ static void free_nested(struct kvm_vcpu *vcpu)
        if (!vmx->nested.vmxon && !vmx->nested.smm.vmxon)
                return;
 
+       kvm_clear_request(KVM_REQ_GET_VMCS12_PAGES, vcpu);
+
        vmx->nested.vmxon = false;
        vmx->nested.smm.vmxon = false;
        free_vpid(vmx->nested.vpid02);
@@ -231,7 +234,9 @@ static void free_nested(struct kvm_vcpu *vcpu)
                vmx->vmcs01.shadow_vmcs = NULL;
        }
        kfree(vmx->nested.cached_vmcs12);
+       vmx->nested.cached_vmcs12 = NULL;
        kfree(vmx->nested.cached_shadow_vmcs12);
+       vmx->nested.cached_shadow_vmcs12 = NULL;
        /* Unpin physical memory we referred to in the vmcs02 */
        if (vmx->nested.apic_access_page) {
                kvm_release_page_dirty(vmx->nested.apic_access_page);
@@ -1341,6 +1346,9 @@ static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx)
        unsigned long val;
        int i;
 
+       if (WARN_ON(!shadow_vmcs))
+               return;
+
        preempt_disable();
 
        vmcs_load(shadow_vmcs);
@@ -1373,6 +1381,9 @@ static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
        unsigned long val;
        int i, q;
 
+       if (WARN_ON(!shadow_vmcs))
+               return;
+
        vmcs_load(shadow_vmcs);
 
        for (q = 0; q < ARRAY_SIZE(fields); q++) {
@@ -4194,7 +4205,10 @@ int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification,
                 * mode, e.g. a 32-bit address size can yield a 64-bit virtual
                 * address when using FS/GS with a non-zero base.
                 */
-               *ret = s.base + off;
+               if (seg_reg == VCPU_SREG_FS || seg_reg == VCPU_SREG_GS)
+                       *ret = s.base + off;
+               else
+                       *ret = off;
 
                /* Long mode: #GP(0)/#SS(0) if the memory address is in a
                 * non-canonical form. This is the only check on the memory
@@ -4433,7 +4447,6 @@ static inline void nested_release_vmcs12(struct kvm_vcpu *vcpu)
                /* copy to memory all shadowed fields in case
                   they were modified */
                copy_shadow_to_vmcs12(vmx);
-               vmx->nested.need_vmcs12_to_shadow_sync = false;
                vmx_disable_shadow_vmcs(vmx);
        }
        vmx->nested.posted_intr_nv = -1;
index 68d231d..4dea0e0 100644 (file)
@@ -337,17 +337,22 @@ static void intel_pmu_init(struct kvm_vcpu *vcpu)
 static void intel_pmu_reset(struct kvm_vcpu *vcpu)
 {
        struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+       struct kvm_pmc *pmc = NULL;
        int i;
 
        for (i = 0; i < INTEL_PMC_MAX_GENERIC; i++) {
-               struct kvm_pmc *pmc = &pmu->gp_counters[i];
+               pmc = &pmu->gp_counters[i];
 
                pmc_stop_counter(pmc);
                pmc->counter = pmc->eventsel = 0;
        }
 
-       for (i = 0; i < INTEL_PMC_MAX_FIXED; i++)
-               pmc_stop_counter(&pmu->fixed_counters[i]);
+       for (i = 0; i < INTEL_PMC_MAX_FIXED; i++) {
+               pmc = &pmu->fixed_counters[i];
+
+               pmc_stop_counter(pmc);
+               pmc->counter = 0;
+       }
 
        pmu->fixed_ctr_ctrl = pmu->global_ctrl = pmu->global_status =
                pmu->global_ovf_ctrl = 0;
index d4cb194..4010d51 100644 (file)
@@ -54,9 +54,9 @@ ENTRY(vmx_vmenter)
        ret
 
 3:     cmpb $0, kvm_rebooting
-       jne 4f
-       call kvm_spurious_fault
-4:     ret
+       je 4f
+       ret
+4:     ud2
 
        .pushsection .fixup, "ax"
 5:     jmp 3b
index 6953655..074385c 100644 (file)
@@ -5829,6 +5829,7 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu)
        }
 
        if (unlikely(vmx->fail)) {
+               dump_vmcs();
                vcpu->run->exit_reason = KVM_EXIT_FAIL_ENTRY;
                vcpu->run->fail_entry.hardware_entry_failure_reason
                        = vmcs_read32(VM_INSTRUCTION_ERROR);
@@ -6597,6 +6598,7 @@ static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
        free_loaded_vmcs(vmx->loaded_vmcs);
        kfree(vmx->guest_msrs);
        kvm_vcpu_uninit(vcpu);
+       kmem_cache_free(x86_fpu_cache, vmx->vcpu.arch.user_fpu);
        kmem_cache_free(x86_fpu_cache, vmx->vcpu.arch.guest_fpu);
        kmem_cache_free(kvm_vcpu_cache, vmx);
 }
@@ -6612,12 +6614,20 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
        if (!vmx)
                return ERR_PTR(-ENOMEM);
 
+       vmx->vcpu.arch.user_fpu = kmem_cache_zalloc(x86_fpu_cache,
+                       GFP_KERNEL_ACCOUNT);
+       if (!vmx->vcpu.arch.user_fpu) {
+               printk(KERN_ERR "kvm: failed to allocate kvm userspace's fpu\n");
+               err = -ENOMEM;
+               goto free_partial_vcpu;
+       }
+
        vmx->vcpu.arch.guest_fpu = kmem_cache_zalloc(x86_fpu_cache,
                        GFP_KERNEL_ACCOUNT);
        if (!vmx->vcpu.arch.guest_fpu) {
                printk(KERN_ERR "kvm: failed to allocate vcpu's fpu\n");
                err = -ENOMEM;
-               goto free_partial_vcpu;
+               goto free_user_fpu;
        }
 
        vmx->vpid = allocate_vpid();
@@ -6720,6 +6730,8 @@ uninit_vcpu:
 free_vcpu:
        free_vpid(vmx->vpid);
        kmem_cache_free(x86_fpu_cache, vmx->vcpu.arch.guest_fpu);
+free_user_fpu:
+       kmem_cache_free(x86_fpu_cache, vmx->vcpu.arch.user_fpu);
 free_partial_vcpu:
        kmem_cache_free(kvm_vcpu_cache, vmx);
        return ERR_PTR(err);
@@ -7064,7 +7076,8 @@ static int vmx_set_hv_timer(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc,
        u64 tscl, guest_tscl, delta_tsc, lapic_timer_advance_cycles;
        struct kvm_timer *ktimer = &vcpu->arch.apic->lapic_timer;
 
-       if (kvm_mwait_in_guest(vcpu->kvm))
+       if (kvm_mwait_in_guest(vcpu->kvm) ||
+               kvm_can_post_timer_interrupt(vcpu))
                return -EOPNOTSUPP;
 
        vmx = to_vmx(vcpu);
@@ -7453,7 +7466,7 @@ static int enable_smi_window(struct kvm_vcpu *vcpu)
 
 static bool vmx_need_emulation_on_page_fault(struct kvm_vcpu *vcpu)
 {
-       return 0;
+       return false;
 }
 
 static __init int hardware_setup(void)
index 4a0b74e..c6d951c 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/kvm_irqfd.h>
 #include <linux/irqbypass.h>
 #include <linux/sched/stat.h>
+#include <linux/sched/isolation.h>
 #include <linux/mem_encrypt.h>
 
 #include <trace/events/kvm.h>
@@ -153,6 +154,9 @@ EXPORT_SYMBOL_GPL(enable_vmware_backdoor);
 static bool __read_mostly force_emulation_prefix = false;
 module_param(force_emulation_prefix, bool, S_IRUGO);
 
+int __read_mostly pi_inject_timer = -1;
+module_param(pi_inject_timer, bint, S_IRUGO | S_IWUSR);
+
 #define KVM_NR_SHARED_MSRS 16
 
 struct kvm_shared_msrs_global {
@@ -1456,12 +1460,8 @@ static void update_pvclock_gtod(struct timekeeper *tk)
 
 void kvm_set_pending_timer(struct kvm_vcpu *vcpu)
 {
-       /*
-        * Note: KVM_REQ_PENDING_TIMER is implicitly checked in
-        * vcpu_enter_guest.  This function is only called from
-        * the physical CPU that is running vcpu.
-        */
        kvm_make_request(KVM_REQ_PENDING_TIMER, vcpu);
+       kvm_vcpu_kick(vcpu);
 }
 
 static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)
@@ -1540,9 +1540,6 @@ static void kvm_get_time_scale(uint64_t scaled_hz, uint64_t base_hz,
 
        *pshift = shift;
        *pmultiplier = div_frac(scaled64, tps32);
-
-       pr_debug("%s: base_hz %llu => %llu, shift %d, mul %u\n",
-                __func__, base_hz, scaled_hz, shift, *pmultiplier);
 }
 
 #ifdef CONFIG_X86_64
@@ -1785,12 +1782,10 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr)
            vcpu->arch.virtual_tsc_khz == kvm->arch.last_tsc_khz) {
                if (!kvm_check_tsc_unstable()) {
                        offset = kvm->arch.cur_tsc_offset;
-                       pr_debug("kvm: matched tsc offset for %llu\n", data);
                } else {
                        u64 delta = nsec_to_cycles(vcpu, elapsed);
                        data += delta;
                        offset = kvm_compute_tsc_offset(vcpu, data);
-                       pr_debug("kvm: adjusted tsc offset by %llu\n", delta);
                }
                matched = true;
                already_matched = (vcpu->arch.this_tsc_generation == kvm->arch.cur_tsc_generation);
@@ -1809,8 +1804,6 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr)
                kvm->arch.cur_tsc_write = data;
                kvm->arch.cur_tsc_offset = offset;
                matched = false;
-               pr_debug("kvm: new tsc generation %llu, clock %llu\n",
-                        kvm->arch.cur_tsc_generation, data);
        }
 
        /*
@@ -3313,6 +3306,10 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 
        kvm_x86_ops->vcpu_load(vcpu, cpu);
 
+       fpregs_assert_state_consistent();
+       if (test_thread_flag(TIF_NEED_FPU_LOAD))
+               switch_fpu_return();
+
        /* Apply any externally detected TSC adjustments (due to suspend) */
        if (unlikely(vcpu->arch.tsc_offset_adjustment)) {
                adjust_tsc_offset_host(vcpu, vcpu->arch.tsc_offset_adjustment);
@@ -6911,7 +6908,6 @@ static void kvm_timer_init(void)
                cpufreq_register_notifier(&kvmclock_cpufreq_notifier_block,
                                          CPUFREQ_TRANSITION_NOTIFIER);
        }
-       pr_debug("kvm: max_tsc_khz = %ld\n", max_tsc_khz);
 
        cpuhp_setup_state(CPUHP_AP_X86_KVM_CLK_ONLINE, "x86/kvm/clk:online",
                          kvmclock_cpu_online, kvmclock_cpu_down_prep);
@@ -7070,6 +7066,8 @@ int kvm_arch_init(void *opaque)
                host_xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
 
        kvm_lapic_init();
+       if (pi_inject_timer == -1)
+               pi_inject_timer = housekeeping_enabled(HK_FLAG_TIMER);
 #ifdef CONFIG_X86_64
        pvclock_gtod_register_notifier(&pvclock_gtod_notifier);
 
@@ -7208,7 +7206,7 @@ static void kvm_sched_yield(struct kvm *kvm, unsigned long dest_id)
 
        rcu_read_unlock();
 
-       if (target)
+       if (target && READ_ONCE(target->ready))
                kvm_vcpu_yield_to(target);
 }
 
@@ -7248,6 +7246,7 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
                break;
        case KVM_HC_KICK_CPU:
                kvm_pv_kick_cpu_op(vcpu->kvm, a0, a1);
+               kvm_sched_yield(vcpu->kvm, a1);
                ret = 0;
                break;
 #ifdef CONFIG_X86_64
@@ -7996,9 +7995,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
        trace_kvm_entry(vcpu->vcpu_id);
        guest_enter_irqoff();
 
-       fpregs_assert_state_consistent();
-       if (test_thread_flag(TIF_NEED_FPU_LOAD))
-               switch_fpu_return();
+       /* The preempt notifier should have taken care of the FPU already.  */
+       WARN_ON_ONCE(test_thread_flag(TIF_NEED_FPU_LOAD));
 
        if (unlikely(vcpu->arch.switch_db_regs)) {
                set_debugreg(0, 7);
@@ -8276,7 +8274,7 @@ static void kvm_load_guest_fpu(struct kvm_vcpu *vcpu)
 {
        fpregs_lock();
 
-       copy_fpregs_to_fpstate(&current->thread.fpu);
+       copy_fpregs_to_fpstate(vcpu->arch.user_fpu);
        /* PKRU is separately restored in kvm_x86_ops->run.  */
        __copy_kernel_to_fpregs(&vcpu->arch.guest_fpu->state,
                                ~XFEATURE_MASK_PKRU);
@@ -8293,7 +8291,7 @@ static void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
        fpregs_lock();
 
        copy_fpregs_to_fpstate(vcpu->arch.guest_fpu);
-       copy_kernel_to_fpregs(&current->thread.fpu.state);
+       copy_kernel_to_fpregs(&vcpu->arch.user_fpu->state);
 
        fpregs_mark_activate();
        fpregs_unlock();
index e08a128..6594020 100644 (file)
@@ -301,6 +301,8 @@ extern unsigned int min_timer_period_us;
 
 extern bool enable_vmware_backdoor;
 
+extern int pi_inject_timer;
+
 extern struct static_key kvm_no_apic_vcpu;
 
 static inline u64 nsec_to_cycles(struct kvm_vcpu *vcpu, u64 nsec)
index 378a1f7..4fe1601 100644 (file)
@@ -239,7 +239,7 @@ copy_user_handle_tail:
        ret
 
        _ASM_EXTABLE_UA(1b, 2b)
-ENDPROC(copy_user_handle_tail)
+END(copy_user_handle_tail)
 
 /*
  * copy_user_nocache - Uncached memory copy with exception handling
index 74fdff9..304f958 100644 (file)
@@ -115,29 +115,29 @@ ENDPROC(__get_user_8)
 EXPORT_SYMBOL(__get_user_8)
 
 
+bad_get_user_clac:
+       ASM_CLAC
 bad_get_user:
        xor %edx,%edx
        mov $(-EFAULT),%_ASM_AX
-       ASM_CLAC
        ret
-END(bad_get_user)
 
 #ifdef CONFIG_X86_32
+bad_get_user_8_clac:
+       ASM_CLAC
 bad_get_user_8:
        xor %edx,%edx
        xor %ecx,%ecx
        mov $(-EFAULT),%_ASM_AX
-       ASM_CLAC
        ret
-END(bad_get_user_8)
 #endif
 
-       _ASM_EXTABLE_UA(1b, bad_get_user)
-       _ASM_EXTABLE_UA(2b, bad_get_user)
-       _ASM_EXTABLE_UA(3b, bad_get_user)
+       _ASM_EXTABLE_UA(1b, bad_get_user_clac)
+       _ASM_EXTABLE_UA(2b, bad_get_user_clac)
+       _ASM_EXTABLE_UA(3b, bad_get_user_clac)
 #ifdef CONFIG_X86_64
-       _ASM_EXTABLE_UA(4b, bad_get_user)
+       _ASM_EXTABLE_UA(4b, bad_get_user_clac)
 #else
-       _ASM_EXTABLE_UA(4b, bad_get_user_8)
-       _ASM_EXTABLE_UA(5b, bad_get_user_8)
+       _ASM_EXTABLE_UA(4b, bad_get_user_8_clac)
+       _ASM_EXTABLE_UA(5b, bad_get_user_8_clac)
 #endif
index d2e5c9c..14bf783 100644 (file)
@@ -32,8 +32,6 @@
  */
 
 #define ENTER  mov PER_CPU_VAR(current_task), %_ASM_BX
-#define EXIT   ASM_CLAC ;      \
-               ret
 
 .text
 ENTRY(__put_user_1)
@@ -43,7 +41,8 @@ ENTRY(__put_user_1)
        ASM_STAC
 1:     movb %al,(%_ASM_CX)
        xor %eax,%eax
-       EXIT
+       ASM_CLAC
+       ret
 ENDPROC(__put_user_1)
 EXPORT_SYMBOL(__put_user_1)
 
@@ -56,7 +55,8 @@ ENTRY(__put_user_2)
        ASM_STAC
 2:     movw %ax,(%_ASM_CX)
        xor %eax,%eax
-       EXIT
+       ASM_CLAC
+       ret
 ENDPROC(__put_user_2)
 EXPORT_SYMBOL(__put_user_2)
 
@@ -69,7 +69,8 @@ ENTRY(__put_user_4)
        ASM_STAC
 3:     movl %eax,(%_ASM_CX)
        xor %eax,%eax
-       EXIT
+       ASM_CLAC
+       ret
 ENDPROC(__put_user_4)
 EXPORT_SYMBOL(__put_user_4)
 
@@ -85,19 +86,21 @@ ENTRY(__put_user_8)
 5:     movl %edx,4(%_ASM_CX)
 #endif
        xor %eax,%eax
-       EXIT
+       ASM_CLAC
+       RET
 ENDPROC(__put_user_8)
 EXPORT_SYMBOL(__put_user_8)
 
+bad_put_user_clac:
+       ASM_CLAC
 bad_put_user:
        movl $-EFAULT,%eax
-       EXIT
-END(bad_put_user)
+       RET
 
-       _ASM_EXTABLE_UA(1b, bad_put_user)
-       _ASM_EXTABLE_UA(2b, bad_put_user)
-       _ASM_EXTABLE_UA(3b, bad_put_user)
-       _ASM_EXTABLE_UA(4b, bad_put_user)
+       _ASM_EXTABLE_UA(1b, bad_put_user_clac)
+       _ASM_EXTABLE_UA(2b, bad_put_user_clac)
+       _ASM_EXTABLE_UA(3b, bad_put_user_clac)
+       _ASM_EXTABLE_UA(4b, bad_put_user_clac)
 #ifdef CONFIG_X86_32
-       _ASM_EXTABLE_UA(5b, bad_put_user)
+       _ASM_EXTABLE_UA(5b, bad_put_user_clac)
 #endif
index e0e006f..fff28c6 100644 (file)
@@ -60,7 +60,7 @@ EXPORT_SYMBOL(clear_user);
  * but reuse __memcpy_mcsafe in case a new read error is encountered.
  * clac() is handled in _copy_to_iter_mcsafe().
  */
-__visible unsigned long
+__visible notrace unsigned long
 mcsafe_handle_tail(char *to, char *from, unsigned len)
 {
        for (; len; --len, to++, from++) {
index a5a41ec..0c12222 100644 (file)
@@ -177,7 +177,7 @@ static inline void reg_copy(FPU_REG const *x, FPU_REG *y)
 #define setexponentpos(x,y) { (*(short *)&((x)->exp)) = \
   ((y) + EXTENDED_Ebias) & 0x7fff; }
 #define exponent16(x)         (*(short *)&((x)->exp))
-#define setexponent16(x,y)  { (*(short *)&((x)->exp)) = (y); }
+#define setexponent16(x,y)  { (*(short *)&((x)->exp)) = (u16)(y); }
 #define addexponent(x,y)    { (*(short *)&((x)->exp)) += (y); }
 #define stdexp(x)           { (*(short *)&((x)->exp)) += EXTENDED_Ebias; }
 
index 8dc9095..742619e 100644 (file)
@@ -18,7 +18,7 @@
 #include "control_w.h"
 
 #define MAKE_REG(s, e, l, h) { l, h, \
-               ((EXTENDED_Ebias+(e)) | ((SIGN_##s != 0)*0x8000)) }
+               (u16)((EXTENDED_Ebias+(e)) | ((SIGN_##s != 0)*0x8000)) }
 
 FPU_REG const CONST_1 = MAKE_REG(POS, 0, 0x00000000, 0x80000000);
 #if 0
index 794f364..6c46095 100644 (file)
@@ -46,23 +46,6 @@ kmmio_fault(struct pt_regs *regs, unsigned long addr)
        return 0;
 }
 
-static nokprobe_inline int kprobes_fault(struct pt_regs *regs)
-{
-       if (!kprobes_built_in())
-               return 0;
-       if (user_mode(regs))
-               return 0;
-       /*
-        * To be potentially processing a kprobe fault and to be allowed to call
-        * kprobe_running(), we have to be non-preemptible.
-        */
-       if (preemptible())
-               return 0;
-       if (!kprobe_running())
-               return 0;
-       return kprobe_fault_handler(regs, X86_TRAP_PF);
-}
-
 /*
  * Prefetch quirks:
  *
@@ -1282,7 +1265,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 (kprobes_fault(regs))
+       if (kprobe_page_fault(regs, X86_TRAP_PF))
                return;
 
        /*
@@ -1313,7 +1296,7 @@ void do_user_addr_fault(struct pt_regs *regs,
        mm = tsk->mm;
 
        /* kprobes don't want to hook the spurious faults: */
-       if (unlikely(kprobes_fault(regs)))
+       if (unlikely(kprobe_page_fault(regs, X86_TRAP_PF)))
                return;
 
        /*
@@ -1507,9 +1490,8 @@ good_area:
 NOKPROBE_SYMBOL(do_user_addr_fault);
 
 /*
- * This routine handles page faults.  It determines the address,
- * and the problem, and then passes it off to one of the appropriate
- * routines.
+ * Explicitly marked noinline such that the function tracer sees this as the
+ * page_fault entry point.
  */
 static noinline void
 __do_page_fault(struct pt_regs *regs, unsigned long hw_error_code,
@@ -1528,33 +1510,26 @@ __do_page_fault(struct pt_regs *regs, unsigned long hw_error_code,
 }
 NOKPROBE_SYMBOL(__do_page_fault);
 
-static nokprobe_inline void
-trace_page_fault_entries(unsigned long address, struct pt_regs *regs,
-                        unsigned long error_code)
+static __always_inline void
+trace_page_fault_entries(struct pt_regs *regs, unsigned long error_code,
+                        unsigned long address)
 {
+       if (!trace_pagefault_enabled())
+               return;
+
        if (user_mode(regs))
                trace_page_fault_user(address, regs, error_code);
        else
                trace_page_fault_kernel(address, regs, error_code);
 }
 
-/*
- * We must have this function blacklisted from kprobes, tagged with notrace
- * and call read_cr2() before calling anything else. To avoid calling any
- * kind of tracing machinery before we've observed the CR2 value.
- *
- * exception_{enter,exit}() contains all sorts of tracepoints.
- */
-dotraplinkage void notrace
-do_page_fault(struct pt_regs *regs, unsigned long error_code)
+dotraplinkage void
+do_page_fault(struct pt_regs *regs, unsigned long error_code, unsigned long address)
 {
-       unsigned long address = read_cr2(); /* Get the faulting address */
        enum ctx_state prev_state;
 
        prev_state = exception_enter();
-       if (trace_pagefault_enabled())
-               trace_page_fault_entries(address, regs, error_code);
-
+       trace_page_fault_entries(regs, error_code, address);
        __do_page_fault(regs, error_code, address);
        exception_exit(prev_state);
 }
index f265a43..4068abb 100644 (file)
@@ -860,7 +860,6 @@ int arch_add_memory(int nid, u64 start, u64 size,
        return __add_pages(nid, start_pfn, nr_pages, restrictions);
 }
 
-#ifdef CONFIG_MEMORY_HOTREMOVE
 void arch_remove_memory(int nid, u64 start, u64 size,
                        struct vmem_altmap *altmap)
 {
@@ -872,7 +871,6 @@ void arch_remove_memory(int nid, u64 start, u64 size,
        __remove_pages(zone, start_pfn, nr_pages, altmap);
 }
 #endif
-#endif
 
 int kernel_set_to_readonly __read_mostly;
 
index 08bbf64..a6b5c65 100644 (file)
@@ -1198,7 +1198,6 @@ void __ref vmemmap_free(unsigned long start, unsigned long end,
        remove_pagetable(start, end, false, altmap);
 }
 
-#ifdef CONFIG_MEMORY_HOTREMOVE
 static void __meminit
 kernel_physical_mapping_remove(unsigned long start, unsigned long end)
 {
@@ -1219,7 +1218,6 @@ void __ref arch_remove_memory(int nid, u64 start, u64 size,
        __remove_pages(zone, start_pfn, nr_pages, altmap);
        kernel_physical_mapping_remove(start, start + size);
 }
-#endif
 #endif /* CONFIG_MEMORY_HOTPLUG */
 
 static struct kcore_list kcore_vsyscall;
@@ -1520,7 +1518,9 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
 {
        int err;
 
-       if (boot_cpu_has(X86_FEATURE_PSE))
+       if (end - start < PAGES_PER_SECTION * sizeof(struct page))
+               err = vmemmap_populate_basepages(start, end, node);
+       else if (boot_cpu_has(X86_FEATURE_PSE))
                err = vmemmap_populate_hugepages(start, end, node, altmap);
        else if (altmap) {
                pr_err_once("%s: no cpu support for altmap allocations\n",
index e500f1d..63e99f1 100644 (file)
@@ -459,6 +459,11 @@ void iounmap(volatile void __iomem *addr)
 }
 EXPORT_SYMBOL(iounmap);
 
+int __init arch_ioremap_p4d_supported(void)
+{
+       return 0;
+}
+
 int __init arch_ioremap_pud_supported(void)
 {
 #ifdef CONFIG_X86_64
index e0df96f..fece30c 100644 (file)
 #include <linux/dma-direct.h>
 #include <linux/swiotlb.h>
 #include <linux/mem_encrypt.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/tlbflush.h>
 #include <asm/fixmap.h>
@@ -41,7 +45,7 @@ EXPORT_SYMBOL_GPL(sev_enable_key);
 bool sev_enabled __section(.data);
 
 /* Buffer used for early in-place encryption by BSP, no locking needed */
-static char sme_early_buffer[PAGE_SIZE] __aligned(PAGE_SIZE);
+static char sme_early_buffer[PAGE_SIZE] __initdata __aligned(PAGE_SIZE);
 
 /*
  * This routine does not change the underlying encryption setting of the
@@ -348,6 +352,32 @@ bool sev_active(void)
 }
 EXPORT_SYMBOL(sev_active);
 
+/* Override for DMA direct allocation check - ARCH_HAS_FORCE_DMA_UNENCRYPTED */
+bool force_dma_unencrypted(struct device *dev)
+{
+       /*
+        * For SEV, all DMA must be to unencrypted addresses.
+        */
+       if (sev_active())
+               return true;
+
+       /*
+        * For SME, all DMA must be to unencrypted addresses if the
+        * device does not support DMA to addresses that include the
+        * encryption mask.
+        */
+       if (sme_active()) {
+               u64 dma_enc_mask = DMA_BIT_MASK(__ffs64(sme_me_mask));
+               u64 dma_dev_mask = min_not_zero(dev->coherent_dma_mask,
+                                               dev->bus_dma_mask);
+
+               if (dma_dev_mask <= dma_enc_mask)
+                       return true;
+       }
+
+       return false;
+}
+
 /* Architecture __weak replacement functions */
 void __init mem_encrypt_free_decrypted_mem(void)
 {
index 0e75642..e138f7d 100644 (file)
@@ -210,18 +210,18 @@ static void __init xen_hvm_guest_init(void)
 #endif
 }
 
-static bool xen_nopv;
 static __init int xen_parse_nopv(char *arg)
 {
-       xen_nopv = true;
-       return 0;
+       pr_notice("\"xen_nopv\" is deprecated, please use \"nopv\" instead\n");
+
+       if (xen_cpuid_base())
+               nopv = true;
+       return 0;
 }
 early_param("xen_nopv", xen_parse_nopv);
 
-bool xen_hvm_need_lapic(void)
+bool __init xen_hvm_need_lapic(void)
 {
-       if (xen_nopv)
-               return false;
        if (xen_pv_domain())
                return false;
        if (!xen_hvm_domain())
@@ -230,15 +230,6 @@ bool xen_hvm_need_lapic(void)
                return false;
        return true;
 }
-EXPORT_SYMBOL_GPL(xen_hvm_need_lapic);
-
-static uint32_t __init xen_platform_hvm(void)
-{
-       if (xen_pv_domain() || xen_nopv)
-               return 0;
-
-       return xen_cpuid_base();
-}
 
 static __init void xen_hvm_guest_late_init(void)
 {
@@ -251,6 +242,9 @@ static __init void xen_hvm_guest_late_init(void)
        /* PVH detected. */
        xen_pvh = true;
 
+       if (nopv)
+               panic("\"nopv\" and \"xen_nopv\" parameters are unsupported in PVH guest.");
+
        /* Make sure we don't fall back to (default) ACPI_IRQ_MODEL_PIC. */
        if (!nr_ioapics && acpi_irq_model == ACPI_IRQ_MODEL_PIC)
                acpi_irq_model = ACPI_IRQ_MODEL_PLATFORM;
@@ -260,7 +254,38 @@ static __init void xen_hvm_guest_late_init(void)
 #endif
 }
 
-const __initconst struct hypervisor_x86 x86_hyper_xen_hvm = {
+static uint32_t __init xen_platform_hvm(void)
+{
+       uint32_t xen_domain = xen_cpuid_base();
+       struct x86_hyper_init *h = &x86_hyper_xen_hvm.init;
+
+       if (xen_pv_domain())
+               return 0;
+
+       if (xen_pvh_domain() && nopv) {
+               /* Guest booting via the Xen-PVH boot entry goes here */
+               pr_info("\"nopv\" parameter is ignored in PVH guest\n");
+               nopv = false;
+       } else if (nopv && xen_domain) {
+               /*
+                * Guest booting via normal boot entry (like via grub2) goes
+                * here.
+                *
+                * Use interface functions for bare hardware if nopv,
+                * xen_hvm_guest_late_init is an exception as we need to
+                * detect PVH and panic there.
+                */
+               h->init_platform = x86_init_noop;
+               h->x2apic_available = bool_x86_init_noop;
+               h->init_mem_mapping = x86_init_noop;
+               h->init_after_bootmem = x86_init_noop;
+               h->guest_late_init = xen_hvm_guest_late_init;
+               x86_hyper_xen_hvm.runtime.pin_vcpu = x86_op_int_noop;
+       }
+       return xen_domain;
+}
+
+struct hypervisor_x86 x86_hyper_xen_hvm __initdata = {
        .name                   = "Xen HVM",
        .detect                 = xen_platform_hvm,
        .type                   = X86_HYPER_XEN_HVM,
@@ -269,4 +294,5 @@ const __initconst struct hypervisor_x86 x86_hyper_xen_hvm = {
        .init.init_mem_mapping  = xen_hvm_init_mem_mapping,
        .init.guest_late_init   = xen_hvm_guest_late_init,
        .runtime.pin_vcpu       = xen_pin_vcpu,
+       .ignore_nopv            = true,
 };
index 4722ba2..7ceb328 100644 (file)
@@ -596,12 +596,12 @@ struct trap_array_entry {
 
 static struct trap_array_entry trap_array[] = {
        { debug,                       xen_xendebug,                    true },
-       { int3,                        xen_xenint3,                     true },
        { double_fault,                xen_double_fault,                true },
 #ifdef CONFIG_X86_MCE
        { machine_check,               xen_machine_check,               true },
 #endif
        { nmi,                         xen_xennmi,                      true },
+       { int3,                        xen_int3,                        false },
        { overflow,                    xen_overflow,                    false },
 #ifdef CONFIG_IA32_EMULATION
        { entry_INT80_compat,          xen_entry_INT80_compat,          false },
@@ -998,7 +998,8 @@ void __init xen_setup_vcpu_info_placement(void)
                        __PV_IS_CALLEE_SAVE(xen_irq_disable_direct);
                pv_ops.irq.irq_enable =
                        __PV_IS_CALLEE_SAVE(xen_irq_enable_direct);
-               pv_ops.mmu.read_cr2 = xen_read_cr2_direct;
+               pv_ops.mmu.read_cr2 =
+                       __PV_IS_CALLEE_SAVE(xen_read_cr2_direct);
        }
 }
 
@@ -1463,4 +1464,5 @@ const __initconst struct hypervisor_x86 x86_hyper_xen_pv = {
        .detect                 = xen_platform_pv,
        .type                   = X86_HYPER_XEN_PV,
        .runtime.pin_vcpu       = xen_pin_vcpu,
+       .ignore_nopv            = true,
 };
index f6e5eee..26e8b32 100644 (file)
@@ -1307,16 +1307,6 @@ static void xen_write_cr2(unsigned long cr2)
        this_cpu_read(xen_vcpu)->arch.cr2 = cr2;
 }
 
-static unsigned long xen_read_cr2(void)
-{
-       return this_cpu_read(xen_vcpu)->arch.cr2;
-}
-
-unsigned long xen_read_cr2_direct(void)
-{
-       return this_cpu_read(xen_vcpu_info.arch.cr2);
-}
-
 static noinline void xen_flush_tlb(void)
 {
        struct mmuext_op *op;
@@ -2397,7 +2387,7 @@ static void xen_leave_lazy_mmu(void)
 }
 
 static const struct pv_mmu_ops xen_mmu_ops __initconst = {
-       .read_cr2 = xen_read_cr2,
+       .read_cr2 = __PV_IS_CALLEE_SAVE(xen_read_cr2),
        .write_cr2 = xen_write_cr2,
 
        .read_cr3 = xen_read_cr3,
index 3776122..6deb490 100644 (file)
@@ -68,11 +68,8 @@ void xen_init_lock_cpu(int cpu)
        int irq;
        char *name;
 
-       if (!xen_pvspin) {
-               if (cpu == 0)
-                       static_branch_disable(&virt_spin_lock_key);
+       if (!xen_pvspin)
                return;
-       }
 
        WARN(per_cpu(lock_kicker_irq, cpu) >= 0, "spinlock on CPU%d exists on IRQ%d!\n",
             cpu, per_cpu(lock_kicker_irq, cpu));
@@ -124,6 +121,7 @@ void __init xen_init_spinlocks(void)
 
        if (!xen_pvspin) {
                printk(KERN_DEBUG "xen: PV spinlocks disabled\n");
+               static_branch_disable(&virt_spin_lock_key);
                return;
        }
        printk(KERN_DEBUG "xen: PV spinlocks enabled\n");
index 8019edd..be104ee 100644 (file)
@@ -10,6 +10,7 @@
 #include <asm/percpu.h>
 #include <asm/processor-flags.h>
 #include <asm/frame.h>
+#include <asm/asm.h>
 
 #include <linux/linkage.h>
 
@@ -135,3 +136,18 @@ ENTRY(check_events)
        FRAME_END
        ret
 ENDPROC(check_events)
+
+ENTRY(xen_read_cr2)
+       FRAME_BEGIN
+       _ASM_MOV PER_CPU_VAR(xen_vcpu), %_ASM_AX
+       _ASM_MOV XEN_vcpu_info_arch_cr2(%_ASM_AX), %_ASM_AX
+       FRAME_END
+       ret
+       ENDPROC(xen_read_cr2);
+
+ENTRY(xen_read_cr2_direct)
+       FRAME_BEGIN
+       _ASM_MOV PER_CPU_VAR(xen_vcpu_info) + XEN_vcpu_info_arch_cr2, %_ASM_AX
+       FRAME_END
+       ret
+       ENDPROC(xen_read_cr2_direct);
index 1e9ef0b..ebf610b 100644 (file)
@@ -32,7 +32,6 @@ xen_pv_trap divide_error
 xen_pv_trap debug
 xen_pv_trap xendebug
 xen_pv_trap int3
-xen_pv_trap xenint3
 xen_pv_trap xennmi
 xen_pv_trap overflow
 xen_pv_trap bounds
index 2f111f4..45a441c 100644 (file)
@@ -134,6 +134,9 @@ __visible void xen_irq_disable_direct(void);
 __visible unsigned long xen_save_fl_direct(void);
 __visible void xen_restore_fl_direct(unsigned long);
 
+__visible unsigned long xen_read_cr2(void);
+__visible unsigned long xen_read_cr2_direct(void);
+
 /* These are not functions, and cannot be called normally */
 __visible void xen_iret(void);
 __visible void xen_sysret32(void);
diff --git a/arch/xtensa/boot/dts/virt.dts b/arch/xtensa/boot/dts/virt.dts
new file mode 100644 (file)
index 0000000..6aecbc0
--- /dev/null
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+
+/ {
+       compatible = "cdns,xtensa-iss";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       interrupt-parent = <&pic>;
+
+       chosen {
+               bootargs = "console=ttyS0,115200n8 debug";
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x00000000 0x80000000>;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               cpu@0 {
+                       compatible = "cdns,xtensa-cpu";
+                       reg = <0>;
+                       clocks = <&osc>;
+               };
+       };
+
+       clocks {
+               osc: osc {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+                       clock-frequency = <40000000>;
+               };
+       };
+
+       pic: pic {
+               compatible = "cdns,xtensa-pic";
+               /* one cell: internal irq number,
+                * two cells: second cell == 0: internal irq number
+                *            second cell == 1: external irq number
+                */
+               #address-cells = <0>;
+               #interrupt-cells = <2>;
+               interrupt-controller;
+       };
+
+       pci {
+               compatible = "pci-host-ecam-generic";
+               device_type = "pci";
+               #address-cells = <3>;
+               #size-cells = <2>;
+               #interrupt-cells = <0x1>;
+
+               bus-range = <0x0 0x3f>;
+               reg = <0xc0000000 0x04000000>;
+
+                    // BUS_ADDRESS(3)  CPU_PHYSICAL(1)  SIZE(2)
+               ranges = <0x01000000 0x0 0xc4000000  0xc4000000  0x0 0x04000000>,
+                        <0x02000000 0x0 0xc8000000  0xc8000000  0x0 0x18000000>;
+
+                    // PCI_DEVICE(3)  INT#(1)  CONTROLLER(PHANDLE)  CONTROLLER_DATA(2)
+               interrupt-map = <
+                       0x0000 0x0 0x0  0x1  &pic  0x0 0x1
+                       0x0800 0x0 0x0  0x1  &pic  0x1 0x1
+                       0x1000 0x0 0x0  0x1  &pic  0x2 0x1
+                       0x1800 0x0 0x0  0x1  &pic  0x3 0x1
+                       >;
+
+               interrupt-map-mask = <0x1800 0x0 0x0  0x7>;
+       };
+};
diff --git a/arch/xtensa/configs/virt_defconfig b/arch/xtensa/configs/virt_defconfig
new file mode 100644 (file)
index 0000000..bfc45a1
--- /dev/null
@@ -0,0 +1,113 @@
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_MEMCG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_NAMESPACES=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_EXPERT=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_PERF_EVENTS=y
+CONFIG_XTENSA_VARIANT_DC233C=y
+CONFIG_XTENSA_UNALIGNED_USER=y
+CONFIG_VECTORS_OFFSET=0x00002000
+CONFIG_XTENSA_KSEG_512M=y
+CONFIG_HIGHMEM=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,115200n8 ip=dhcp root=/dev/nfs rw debug memmap=0x80000000@0"
+CONFIG_USE_OF=y
+CONFIG_BUILTIN_DTB_SOURCE="virt"
+# CONFIG_PARSE_BOOTPARAM is not set
+CONFIG_JUMP_LABEL=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_COMPACTION is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+# CONFIG_WIRELESS is not set
+CONFIG_PCI=y
+CONFIG_PCI_HOST_GENERIC=y
+CONFIG_UEVENT_HELPER=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_STANDALONE is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_VIRTIO_BLK=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_NETDEVICES=y
+CONFIG_VIRTIO_NET=y
+# CONFIG_ETHERNET is not set
+# CONFIG_WLAN is not set
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_VIRTIO=y
+# CONFIG_HWMON is not set
+CONFIG_DRM=y
+CONFIG_DRM_VGEM=y
+CONFIG_DRM_VIRTIO_GPU=y
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_LOGO=y
+# CONFIG_USB_SUPPORT is not set
+CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO_INPUT=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_EXT3_FS=y
+CONFIG_FANOTIFY=y
+CONFIG_VFAT_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_SWAP=y
+CONFIG_ROOT_NFS=y
+CONFIG_SUNRPC_DEBUG=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_CRYPTO_ECHAINIV=y
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_LZO=y
+CONFIG_CRYPTO_ANSI_CPRNG=y
+CONFIG_CRYPTO_DEV_VIRTIO=y
+CONFIG_FONTS=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_INFO=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_STACKTRACE=y
+CONFIG_RCU_TRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_S32C1I_SELFTEST is not set
index 8308a9c..71a7e84 100644 (file)
 #endif
        .endm
 
+#define XTENSA_STACK_ALIGNMENT         16
+
+#if defined(__XTENSA_WINDOWED_ABI__)
+#define XTENSA_FRAME_SIZE_RESERVE      16
+#define XTENSA_SPILL_STACK_RESERVE     32
+
+#define abi_entry(frame_size) \
+       entry sp, (XTENSA_FRAME_SIZE_RESERVE + \
+                  (((frame_size) + XTENSA_STACK_ALIGNMENT - 1) & \
+                   -XTENSA_STACK_ALIGNMENT))
+#define abi_entry_default abi_entry(0)
+
+#define abi_ret(frame_size) retw
+#define abi_ret_default retw
+
+#elif defined(__XTENSA_CALL0_ABI__)
+
+#define XTENSA_SPILL_STACK_RESERVE     0
+
+#define abi_entry(frame_size) __abi_entry (frame_size)
+
+       .macro  __abi_entry frame_size
+       .ifgt \frame_size
+       addi sp, sp, -(((\frame_size) + XTENSA_STACK_ALIGNMENT - 1) & \
+                      -XTENSA_STACK_ALIGNMENT)
+       .endif
+       .endm
+
+#define abi_entry_default
+
+#define abi_ret(frame_size) __abi_ret (frame_size)
+
+       .macro  __abi_ret frame_size
+       .ifgt \frame_size
+       addi sp, sp, (((\frame_size) + XTENSA_STACK_ALIGNMENT - 1) & \
+                     -XTENSA_STACK_ALIGNMENT)
+       .endif
+       ret
+       .endm
+
+#define abi_ret_default ret
+
+#else
+#error Unsupported Xtensa ABI
+#endif
+
 #endif /* _XTENSA_ASMMACRO_H */
index 323d057..3b054d2 100644 (file)
@@ -42,7 +42,7 @@
 #if XCHAL_HAVE_S32C1I && (XCHAL_HW_MIN_VERSION >= XTENSA_HWVERSION_RC_2009_0)
 /*
  * We Have Atomic Operation Control (ATOMCTL) Register; Initialize it.
- * For details see Documentation/xtensa/atomctl.txt
+ * For details see Documentation/xtensa/atomctl.rst
  */
 #if XCHAL_DCACHE_IS_COHERENT
        movi    a3, 0x25        /* For SMP/MX -- internal for writeback,
index 5604833..913826d 100644 (file)
@@ -55,16 +55,6 @@ extern void platform_idle (void);
 extern void platform_heartbeat (void);
 
 /*
- * platform_pcibios_init is called to allow the platform to setup the pci bus.
- */
-extern void platform_pcibios_init (void);
-
-/*
- * platform_pcibios_fixup allows to modify the PCI configuration.
- */
-extern int platform_pcibios_fixup (void);
-
-/*
  * platform_calibrate_ccount calibrates cpu clock freq (CONFIG_XTENSA_CALIBRATE)
  */
 extern void platform_calibrate_ccount (void);
diff --git a/arch/xtensa/include/asm/types.h b/arch/xtensa/include/asm/types.h
deleted file mode 100644 (file)
index 2b410b8..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * include/asm-xtensa/types.h
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- */
-#ifndef _XTENSA_TYPES_H
-#define _XTENSA_TYPES_H
-
-#include <uapi/asm/types.h>
-
-#ifndef __ASSEMBLY__
-/*
- * These aren't exported outside the kernel to avoid name space clashes
- */
-
-#define BITS_PER_LONG 32
-
-#endif
-#endif /* _XTENSA_TYPES_H */
index be72606..ebbb488 100644 (file)
 #define MAP_STACK      0x40000         /* give out an address that is best suited for process/thread stacks */
 #define MAP_HUGETLB    0x80000         /* create a huge page mapping */
 #define MAP_FIXED_NOREPLACE 0x100000   /* MAP_FIXED which doesn't unmap underlying mapping */
-#ifdef CONFIG_MMAP_ALLOW_UNINITIALIZED
-# define MAP_UNINITIALIZED 0x4000000   /* For anonymous mmap, memory could be
+#define MAP_UNINITIALIZED 0x4000000    /* For anonymous mmap, memory could be
                                         * uninitialized */
-#else
-# define MAP_UNINITIALIZED 0x0         /* Don't support this flag */
-#endif
 
 /*
  * Flags for msync
index 92bf24a..60c2200 100644 (file)
 
 ENTRY(coprocessor_flush)
 
-       entry   a1, 32
+       /* reserve 4 bytes on stack to save a0 */
+       abi_entry(4)
+
        s32i    a0, a1, 0
        movi    a0, .Lsave_cp_regs_jump_table
        addx8   a3, a3, a0
@@ -131,7 +133,8 @@ ENTRY(coprocessor_flush)
        beqz    a3, 1f
        callx0  a3
 1:     l32i    a0, a1, 0
-       retw
+
+       abi_ret(4)
 
 ENDPROC(coprocessor_flush)
 
index e54af8b..183fa8e 100644 (file)
@@ -1842,7 +1842,8 @@ ENDPROC(fast_store_prohibited)
 
 ENTRY(system_call)
 
-       entry   a1, 32
+       /* reserve 4 bytes on stack for function parameter */
+       abi_entry(4)
 
        /* regs->syscall = regs->areg[2] */
 
@@ -1892,7 +1893,7 @@ ENTRY(system_call)
 
        s32i    a6, a2, PT_AREG2
        bnez    a3, 1f
-       retw
+       abi_ret(4)
 
 1:
        l32i    a4, a1, 4
@@ -1901,7 +1902,7 @@ ENTRY(system_call)
        mov     a6, a2
        call4   do_syscall_trace_leave
        s32i    a3, a2, PT_SYSCALL
-       retw
+       abi_ret(4)
 
 ENDPROC(system_call)
 
@@ -1952,7 +1953,7 @@ ENDPROC(system_call)
 
 ENTRY(_switch_to)
 
-       entry   a1, 48
+       abi_entry(XTENSA_SPILL_STACK_RESERVE)
 
        mov     a11, a3                 # and 'next' (a3)
 
@@ -2013,7 +2014,7 @@ ENTRY(_switch_to)
        wsr     a14, ps
        rsync
 
-       retw
+       abi_ret(XTENSA_SPILL_STACK_RESERVE)
 
 ENDPROC(_switch_to)
 
index 0eeda2e..5e4619f 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <linux/linkage.h>
+#include <asm/asmmacro.h>
 #include <asm/ftrace.h>
 
 /*
 
 ENTRY(_mcount)
 
-       entry   a1, 16
+       abi_entry_default
 
        movi    a4, ftrace_trace_function
        l32i    a4, a4, 0
        movi    a3, ftrace_stub
        bne     a3, a4, 1f
-       retw
+       abi_ret_default
 
 1:     xor     a7, a2, a1
        movi    a3, 0x3fffffff
@@ -40,11 +41,11 @@ ENTRY(_mcount)
        addi    a6, a6, -MCOUNT_INSN_SIZE
        callx4  a4
 
-       retw
+       abi_ret_default
 
 ENDPROC(_mcount)
 
 ENTRY(ftrace_stub)
-       entry   a1, 16
-       retw
+       abi_entry_default
+       abi_ret_default
 ENDPROC(ftrace_stub)
index 8b823f9..3f32e27 100644 (file)
 #include <asm/pci-bridge.h>
 #include <asm/platform.h>
 
-/* PCI Controller */
-
-
-/*
- * pcibios_alloc_controller
- * pcibios_enable_device
- * pcibios_fixups
- * pcibios_align_resource
- * pcibios_fixup_bus
- * pci_bus_add_device
- */
-
-static struct pci_controller *pci_ctrl_head;
-static struct pci_controller **pci_ctrl_tail = &pci_ctrl_head;
-
-static int pci_bus_count;
-
 /*
  * We need to avoid collisions with `mirrored' VGA ports
  * and other strange ISA hardware, so we always want the
@@ -75,81 +58,6 @@ pcibios_align_resource(void *data, const struct resource *res,
        return start;
 }
 
-static void __init pci_controller_apertures(struct pci_controller *pci_ctrl,
-                                           struct list_head *resources)
-{
-       struct resource *res;
-       unsigned long io_offset;
-       int i;
-
-       io_offset = (unsigned long)pci_ctrl->io_space.base;
-       res = &pci_ctrl->io_resource;
-       if (!res->flags) {
-               if (io_offset)
-                       pr_err("I/O resource not set for host bridge %d\n",
-                              pci_ctrl->index);
-               res->start = 0;
-               res->end = IO_SPACE_LIMIT;
-               res->flags = IORESOURCE_IO;
-       }
-       res->start += io_offset;
-       res->end += io_offset;
-       pci_add_resource_offset(resources, res, io_offset);
-
-       for (i = 0; i < 3; i++) {
-               res = &pci_ctrl->mem_resources[i];
-               if (!res->flags) {
-                       if (i > 0)
-                               continue;
-                       pr_err("Memory resource not set for host bridge %d\n",
-                              pci_ctrl->index);
-                       res->start = 0;
-                       res->end = ~0U;
-                       res->flags = IORESOURCE_MEM;
-               }
-               pci_add_resource(resources, res);
-       }
-}
-
-static int __init pcibios_init(void)
-{
-       struct pci_controller *pci_ctrl;
-       struct list_head resources;
-       struct pci_bus *bus;
-       int next_busno = 0, ret;
-
-       pr_info("PCI: Probing PCI hardware\n");
-
-       /* Scan all of the recorded PCI controllers.  */
-       for (pci_ctrl = pci_ctrl_head; pci_ctrl; pci_ctrl = pci_ctrl->next) {
-               pci_ctrl->last_busno = 0xff;
-               INIT_LIST_HEAD(&resources);
-               pci_controller_apertures(pci_ctrl, &resources);
-               bus = pci_scan_root_bus(NULL, pci_ctrl->first_busno,
-                                       pci_ctrl->ops, pci_ctrl, &resources);
-               if (!bus)
-                       continue;
-
-               pci_ctrl->bus = bus;
-               pci_ctrl->last_busno = bus->busn_res.end;
-               if (next_busno <= pci_ctrl->last_busno)
-                       next_busno = pci_ctrl->last_busno+1;
-       }
-       pci_bus_count = next_busno;
-       ret = platform_pcibios_fixup();
-       if (ret)
-               return ret;
-
-       for (pci_ctrl = pci_ctrl_head; pci_ctrl; pci_ctrl = pci_ctrl->next) {
-               if (pci_ctrl->bus)
-                       pci_bus_add_devices(pci_ctrl->bus);
-       }
-
-       return 0;
-}
-
-subsys_initcall(pcibios_init);
-
 void pcibios_fixup_bus(struct pci_bus *bus)
 {
        if (bus->parent) {
@@ -158,38 +66,6 @@ void pcibios_fixup_bus(struct pci_bus *bus)
        }
 }
 
-void pcibios_set_master(struct pci_dev *dev)
-{
-       /* No special bus mastering setup handling */
-}
-
-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
-       u16 cmd, old_cmd;
-       int idx;
-       struct resource *r;
-
-       pci_read_config_word(dev, PCI_COMMAND, &cmd);
-       old_cmd = cmd;
-       for (idx=0; idx<6; idx++) {
-               r = &dev->resource[idx];
-               if (!r->start && r->end) {
-                       pci_err(dev, "can't enable device: resource collisions\n");
-                       return -EINVAL;
-               }
-               if (r->flags & IORESOURCE_IO)
-                       cmd |= PCI_COMMAND_IO;
-               if (r->flags & IORESOURCE_MEM)
-                       cmd |= PCI_COMMAND_MEMORY;
-       }
-       if (cmd != old_cmd) {
-               pci_info(dev, "enabling device (%04x -> %04x)\n", old_cmd, cmd);
-               pci_write_config_word(dev, PCI_COMMAND, cmd);
-       }
-
-       return 0;
-}
-
 /*
  * Platform support for /proc/bus/pci/X/Y mmap()s.
  *  -- paulus.
index 1cf0082..a95ba05 100644 (file)
@@ -34,8 +34,6 @@ _F(void, halt, (void), { while(1); });
 _F(void, power_off, (void), { while(1); });
 _F(void, idle, (void), { __asm__ __volatile__ ("waiti 0" ::: "memory"); });
 _F(void, heartbeat, (void), { });
-_F(int,  pcibios_fixup, (void), { return 0; });
-_F(void, pcibios_init, (void), { });
 
 #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
 _F(void, calibrate_ccount, (void),
index 176cb46..5cb8a62 100644 (file)
@@ -405,10 +405,6 @@ void __init setup_arch(char **cmdline_p)
        conswitchp = &dummy_con;
 # endif
 #endif
-
-#ifdef CONFIG_PCI
-       platform_pcibios_init();
-#endif
 }
 
 static DEFINE_PER_CPU(struct cpu, cpu_data);
index c6e73b1..4cb9ca5 100644 (file)
@@ -43,7 +43,7 @@ ENTRY(csum_partial)
         * Experiments with Ethernet and SLIP connections show that buf
         * is aligned on either a 2-byte or 4-byte boundary.
         */
-       entry   sp, 32
+       abi_entry_default
        extui   a5, a2, 0, 2
        bnez    a5, 8f          /* branch if 2-byte aligned */
        /* Fall-through on common case, 4-byte alignment */
@@ -107,7 +107,7 @@ ENTRY(csum_partial)
        ONES_ADD(a4, a6)
 7:
        mov     a2, a4
-       retw
+       abi_ret_default
 
        /* uncommon case, buf is 2-byte aligned */
 8:
@@ -195,7 +195,7 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst, int len,
 
 ENTRY(csum_partial_copy_generic)
 
-       entry   sp, 32
+       abi_entry_default
        mov     a12, a3
        mov     a11, a4
        or      a10, a2, a3
@@ -316,7 +316,7 @@ EX(11f)     s8i     a9, a3, 0
        ONES_ADD(a5, a9)
 8:
        mov     a2, a5
-       retw
+       abi_ret_default
 
 5:
        /* Control branch to here when either src or dst is odd.  We
@@ -383,12 +383,12 @@ ENDPROC(csum_partial_copy_generic)
        blt     a12, a11, .Leloop
 #endif
 2:
-       retw
+       abi_ret_default
 
 11:
        movi    a2, -EFAULT
        s32i    a2, a7, 0       /* dst_err_ptr */
        movi    a2, 0
-       retw
+       abi_ret_default
 
 .previous
index efecfd7..582d817 100644 (file)
@@ -79,7 +79,7 @@
        bne     a3, a7, .Lnextbyte # continue loop if $a3:src != $a7:src_end
 #endif /* !XCHAL_HAVE_LOOPS */
 .Lbytecopydone:
-       retw
+       abi_ret_default
 
 /*
  * Destination is unaligned
 ENTRY(__memcpy)
 WEAK(memcpy)
 
-       entry   sp, 16          # minimal stack frame
+       abi_entry_default
        # a2/ dst, a3/ src, a4/ len
        mov     a5, a2          # copy dst so that a2 is return value
 .Lcommon:
@@ -161,7 +161,7 @@ WEAK(memcpy)
        bbsi.l  a4, 2, .L3
        bbsi.l  a4, 1, .L4
        bbsi.l  a4, 0, .L5
-       retw
+       abi_ret_default
 .L3:
        # copy 4 bytes
        l32i    a6, a3,  0
@@ -170,7 +170,7 @@ WEAK(memcpy)
        addi    a5, a5,  4
        bbsi.l  a4, 1, .L4
        bbsi.l  a4, 0, .L5
-       retw
+       abi_ret_default
 .L4:
        # copy 2 bytes
        l16ui   a6, a3,  0
@@ -178,12 +178,12 @@ WEAK(memcpy)
        s16i    a6, a5,  0
        addi    a5, a5,  2
        bbsi.l  a4, 0, .L5
-       retw
+       abi_ret_default
 .L5:
        # copy 1 byte
        l8ui    a6, a3,  0
        s8i     a6, a5,  0
-       retw
+       abi_ret_default
 
 /*
  * Destination is aligned, Source is unaligned
@@ -255,7 +255,7 @@ WEAK(memcpy)
 #endif
        bbsi.l  a4, 1, .L14
        bbsi.l  a4, 0, .L15
-.Ldone:        retw
+.Ldone:        abi_ret_default
 .L14:
        # copy 2 bytes
        l8ui    a6, a3,  0
@@ -265,12 +265,12 @@ WEAK(memcpy)
        s8i     a7, a5,  1
        addi    a5, a5,  2
        bbsi.l  a4, 0, .L15
-       retw
+       abi_ret_default
 .L15:
        # copy 1 byte
        l8ui    a6, a3,  0
        s8i     a6, a5,  0
-       retw
+       abi_ret_default
 
 ENDPROC(__memcpy)
 
@@ -280,7 +280,7 @@ ENDPROC(__memcpy)
 
 ENTRY(bcopy)
 
-       entry   sp, 16          # minimal stack frame
+       abi_entry_default
        # a2=src, a3=dst, a4=len
        mov     a5, a3
        mov     a3, a2
@@ -346,7 +346,7 @@ ENDPROC(bcopy)
                                       # $a3:src != $a7:src_start
 #endif /* !XCHAL_HAVE_LOOPS */
 .Lbackbytecopydone:
-       retw
+       abi_ret_default
 
 /*
  * Destination is unaligned
@@ -380,7 +380,7 @@ ENDPROC(bcopy)
 ENTRY(__memmove)
 WEAK(memmove)
 
-       entry   sp, 16          # minimal stack frame
+       abi_entry_default
        # a2/ dst, a3/ src, a4/ len
        mov     a5, a2          # copy dst so that a2 is return value
 .Lmovecommon:
@@ -435,7 +435,7 @@ WEAK(memmove)
        bbsi.l  a4, 2, .Lback3
        bbsi.l  a4, 1, .Lback4
        bbsi.l  a4, 0, .Lback5
-       retw
+       abi_ret_default
 .Lback3:
        # copy 4 bytes
        addi    a3, a3, -4
@@ -444,7 +444,7 @@ WEAK(memmove)
        s32i    a6, a5,  0
        bbsi.l  a4, 1, .Lback4
        bbsi.l  a4, 0, .Lback5
-       retw
+       abi_ret_default
 .Lback4:
        # copy 2 bytes
        addi    a3, a3, -2
@@ -452,14 +452,14 @@ WEAK(memmove)
        addi    a5, a5, -2
        s16i    a6, a5,  0
        bbsi.l  a4, 0, .Lback5
-       retw
+       abi_ret_default
 .Lback5:
        # copy 1 byte
        addi    a3, a3, -1
        l8ui    a6, a3,  0
        addi    a5, a5, -1
        s8i     a6, a5,  0
-       retw
+       abi_ret_default
 
 /*
  * Destination is aligned, Source is unaligned
@@ -531,7 +531,7 @@ WEAK(memmove)
        bbsi.l  a4, 1, .Lback14
        bbsi.l  a4, 0, .Lback15
 .Lbackdone:
-       retw
+       abi_ret_default
 .Lback14:
        # copy 2 bytes
        addi    a3, a3, -2
@@ -541,13 +541,13 @@ WEAK(memmove)
        s8i     a6, a5,  0
        s8i     a7, a5,  1
        bbsi.l  a4, 0, .Lback15
-       retw
+       abi_ret_default
 .Lback15:
        # copy 1 byte
        addi    a3, a3, -1
        addi    a5, a5, -1
        l8ui    a6, a3,  0
        s8i     a6, a5,  0
-       retw
+       abi_ret_default
 
 ENDPROC(__memmove)
index 8632eac..59b1524 100644 (file)
@@ -34,7 +34,7 @@
 ENTRY(__memset)
 WEAK(memset)
 
-       entry   sp, 16          # minimal stack frame
+       abi_entry_default
        # a2/ dst, a3/ c, a4/ length
        extui   a3, a3, 0, 8    # mask to just 8 bits
        slli    a7, a3, 8       # duplicate character in all bytes of word
@@ -48,7 +48,7 @@ WEAK(memset)
        srli    a7, a4, 4       # number of loop iterations with 16B
                                # per iteration
        bnez    a4, .Laligned
-       retw
+       abi_ret_default
 
 /*
  * Destination is word-aligned.
@@ -95,7 +95,7 @@ EX(10f) s16i  a3, a5,  0
 EX(10f) s8i    a3, a5,  0
 .L5:
 .Lret1:
-       retw
+       abi_ret_default
 
 /*
  * Destination is unaligned
@@ -139,7 +139,7 @@ EX(10f) s8i a3, a5, 0
        blt     a5, a6, .Lbyteloop
 #endif /* !XCHAL_HAVE_LOOPS */
 .Lbytesetdone:
-       retw
+       abi_ret_default
 
 ENDPROC(__memset)
 
@@ -150,4 +150,4 @@ ENDPROC(__memset)
 
 10:
        movi    a2, 0
-       retw
+       abi_ret_default
index c4c6c85..4faf46f 100644 (file)
@@ -50,7 +50,7 @@
 .text
 ENTRY(__strncpy_user)
 
-       entry   sp, 16          # minimal stack frame
+       abi_entry_default
        # a2/ dst, a3/ src, a4/ len
        mov     a11, a2         # leave dst in return value register
        beqz    a4, .Lret       # if len is zero
@@ -93,7 +93,7 @@ EX(10f)       s8i     a9, a11, 0              # store byte 0
        bnez    a4, .Lsrcaligned        # if len is nonzero
 .Lret:
        sub     a2, a11, a2             # compute strlen
-       retw
+       abi_ret_default
 
 /*
  * dst is word-aligned, src is word-aligned
@@ -148,14 +148,14 @@ EX(10f)   s8i     a9, a11, 0
 .Lz3:  # byte 3 is zero
        addi    a11, a11, 3             # advance dst pointer
        sub     a2, a11, a2             # compute strlen
-       retw
+       abi_ret_default
 .Lz0:  # byte 0 is zero
 #ifdef __XTENSA_EB__
        movi    a9, 0
 #endif /* __XTENSA_EB__ */
 EX(10f)        s8i     a9, a11, 0
        sub     a2, a11, a2             # compute strlen
-       retw
+       abi_ret_default
 .Lz1:  # byte 1 is zero
 #ifdef __XTENSA_EB__
        extui   a9, a9, 16, 16
@@ -163,7 +163,7 @@ EX(10f)     s8i     a9, a11, 0
 EX(10f)        s16i    a9, a11, 0
        addi    a11, a11, 1             # advance dst pointer
        sub     a2, a11, a2             # compute strlen
-       retw
+       abi_ret_default
 .Lz2:  # byte 2 is zero
 #ifdef __XTENSA_EB__
        extui   a9, a9, 16, 16
@@ -173,7 +173,7 @@ EX(10f)     s16i    a9, a11, 0
 EX(10f)        s8i     a9, a11, 2
        addi    a11, a11, 2             # advance dst pointer
        sub     a2, a11, a2             # compute strlen
-       retw
+       abi_ret_default
 
        .align  4               # 1 mod 4 alignment for LOOPNEZ
        .byte   0               # (0 mod 4 alignment for LBEG)
@@ -199,7 +199,7 @@ EX(10f)     s8i     a9, a11, 0
 
 .Lunalignedend:
        sub     a2, a11, a2             # compute strlen
-       retw
+       abi_ret_default
 
 ENDPROC(__strncpy_user)
 
@@ -214,4 +214,4 @@ ENDPROC(__strncpy_user)
 10:
 11:
        movi    a2, -EFAULT
-       retw
+       abi_ret_default
index 1f2ca2b..3d391dc 100644 (file)
@@ -45,7 +45,7 @@
 .text
 ENTRY(__strnlen_user)
 
-       entry   sp, 16          # minimal stack frame
+       abi_entry_default
        # a2/ s, a3/ len
        addi    a4, a2, -4      # because we overincrement at the end;
                                # we compensate with load offsets of 4
@@ -96,7 +96,7 @@ EX(10f)       l32i    a9, a4, 4       # load 4 bytes for remaining checks
        addi    a4, a4, 1       # advance string pointer
 .L101:
        sub     a2, a4, a2      # compute length
-       retw
+       abi_ret_default
 
 # NOTE that in several places below, we point to the byte just after
 # the zero byte in order to include the NULL terminator in the count.
@@ -106,15 +106,15 @@ EX(10f)   l32i    a9, a4, 4       # load 4 bytes for remaining checks
 .Lz0:  # byte 0 is zero
        addi    a4, a4, 1       # point just beyond zero byte
        sub     a2, a4, a2      # subtract to get length
-       retw
+       abi_ret_default
 .Lz1:  # byte 1 is zero
        addi    a4, a4, 1+1     # point just beyond zero byte
        sub     a2, a4, a2      # subtract to get length
-       retw
+       abi_ret_default
 .Lz2:  # byte 2 is zero
        addi    a4, a4, 2+1     # point just beyond zero byte
        sub     a2, a4, a2      # subtract to get length
-       retw
+       abi_ret_default
 
 .L1mod2:       # address is odd
 EX(10f)        l8ui    a9, a4, 4               # get byte 0
@@ -130,7 +130,7 @@ EX(10f)     l32i    a9, a4, 0       # get word with first two bytes of string
        # byte 3 is zero
        addi    a4, a4, 3+1     # point just beyond zero byte
        sub     a2, a4, a2      # subtract to get length
-       retw
+       abi_ret_default
 
 ENDPROC(__strnlen_user)
 
@@ -138,4 +138,4 @@ ENDPROC(__strnlen_user)
        .align  4
 10:
        movi    a2, 0
-       retw
+       abi_ret_default
index 228607e..a0aa404 100644 (file)
@@ -60,7 +60,7 @@
        .text
 ENTRY(__xtensa_copy_user)
 
-       entry   sp, 16          # minimal stack frame
+       abi_entry_default
        # a2/ dst, a3/ src, a4/ len
        mov     a5, a2          # copy dst so that a2 is return value
        mov     a11, a4         # preserve original len for error case
@@ -75,7 +75,7 @@ ENTRY(__xtensa_copy_user)
        __ssa8  a3              # set shift amount from byte offset
        bnez    a4, .Lsrcunaligned
        movi    a2, 0           # return success for len==0
-       retw
+       abi_ret_default
 
 /*
  * Destination is unaligned
@@ -127,7 +127,7 @@ EX(10f)     s8i     a6, a5, 0
 #endif /* !XCHAL_HAVE_LOOPS */
 .Lbytecopydone:
        movi    a2, 0           # return success for len bytes copied
-       retw
+       abi_ret_default
 
 /*
  * Destination and source are word-aligned.
@@ -187,7 +187,7 @@ EX(10f)     l8ui    a6, a3,  0
 EX(10f)        s8i     a6, a5,  0
 .L5:
        movi    a2, 0           # return success for len bytes copied
-       retw
+       abi_ret_default
 
 /*
  * Destination is aligned, Source is unaligned
@@ -264,7 +264,7 @@ EX(10f)     l8ui    a6, a3,  0
 EX(10f)        s8i     a6, a5,  0
 .L15:
        movi    a2, 0           # return success for len bytes copied
-       retw
+       abi_ret_default
 
 ENDPROC(__xtensa_copy_user)
 
@@ -281,4 +281,4 @@ ENDPROC(__xtensa_copy_user)
 10:
        sub     a2, a5, a2      /* a2 <-- bytes copied */
        sub     a2, a11, a2     /* a2 <-- bytes not copied */
-       retw
+       abi_ret_default
index b51746f..79467c7 100644 (file)
@@ -45,10 +45,7 @@ void __init bootmem_init(void)
         * If PHYS_OFFSET is zero reserve page at address 0:
         * successfull allocations should never return NULL.
         */
-       if (PHYS_OFFSET)
-               memblock_reserve(0, PHYS_OFFSET);
-       else
-               memblock_reserve(0, 1);
+       memblock_reserve(0, PHYS_OFFSET ? PHYS_OFFSET : 1);
 
        early_init_fdt_scan_reserved_mem();
 
index 11a01c3..6aa036c 100644 (file)
@@ -30,7 +30,7 @@
 
 ENTRY(clear_page)
 
-       entry   a1, 16
+       abi_entry_default
 
        movi    a3, 0
        __loopi a2, a7, PAGE_SIZE, 32
@@ -44,7 +44,7 @@ ENTRY(clear_page)
        s32i    a3, a2, 28
        __endla a2, a7, 32
 
-       retw
+       abi_ret_default
 
 ENDPROC(clear_page)
 
@@ -57,7 +57,7 @@ ENDPROC(clear_page)
 
 ENTRY(copy_page)
 
-       entry   a1, 16
+       abi_entry_default
 
        __loopi a2, a4, PAGE_SIZE, 32
 
@@ -86,7 +86,7 @@ ENTRY(copy_page)
 
        __endl  a2, a4
 
-       retw
+       abi_ret_default
 
 ENDPROC(copy_page)
 
@@ -116,7 +116,7 @@ ENTRY(__tlbtemp_mapping_start)
 
 ENTRY(clear_page_alias)
 
-       entry   a1, 32
+       abi_entry_default
 
        /* Skip setting up a temporary DTLB if not aliased low page. */
 
@@ -144,14 +144,14 @@ ENTRY(clear_page_alias)
        __endla a2, a7, 32
 
        bnez    a6, 1f
-       retw
+       abi_ret_default
 
        /* We need to invalidate the temporary idtlb entry, if any. */
 
 1:     idtlb   a4
        dsync
 
-       retw
+       abi_ret_default
 
 ENDPROC(clear_page_alias)
 
@@ -164,7 +164,7 @@ ENDPROC(clear_page_alias)
 
 ENTRY(copy_page_alias)
 
-       entry   a1, 32
+       abi_entry_default
 
        /* Skip setting up a temporary DTLB for destination if not aliased. */
 
@@ -221,19 +221,19 @@ ENTRY(copy_page_alias)
 
        bnez    a6, 1f
        bnez    a7, 2f
-       retw
+       abi_ret_default
 
 1:     addi    a2, a2, -PAGE_SIZE
        idtlb   a2
        dsync
        bnez    a7, 2f
-       retw
+       abi_ret_default
 
 2:     addi    a3, a3, -PAGE_SIZE+1
        idtlb   a3
        dsync
 
-       retw
+       abi_ret_default
 
 ENDPROC(copy_page_alias)
 
@@ -248,7 +248,7 @@ ENDPROC(copy_page_alias)
 
 ENTRY(__flush_invalidate_dcache_page_alias)
 
-       entry   sp, 16
+       abi_entry_default
 
        movi    a7, 0                   # required for exception handler
        addi    a6, a3, (PAGE_KERNEL | _PAGE_HW_WRITE)
@@ -261,7 +261,7 @@ ENTRY(__flush_invalidate_dcache_page_alias)
        idtlb   a4
        dsync
 
-       retw
+       abi_ret_default
 
 ENDPROC(__flush_invalidate_dcache_page_alias)
 
@@ -272,7 +272,7 @@ ENDPROC(__flush_invalidate_dcache_page_alias)
 
 ENTRY(__invalidate_dcache_page_alias)
 
-       entry   sp, 16
+       abi_entry_default
 
        movi    a7, 0                   # required for exception handler
        addi    a6, a3, (PAGE_KERNEL | _PAGE_HW_WRITE)
@@ -285,7 +285,7 @@ ENTRY(__invalidate_dcache_page_alias)
        idtlb   a4
        dsync
 
-       retw
+       abi_ret_default
 
 ENDPROC(__invalidate_dcache_page_alias)
 #endif
@@ -296,7 +296,7 @@ ENTRY(__tlbtemp_mapping_itlb)
        
 ENTRY(__invalidate_icache_page_alias)
 
-       entry   sp, 16
+       abi_entry_default
 
        addi    a6, a3, (PAGE_KERNEL_EXEC | _PAGE_HW_WRITE)
        mov     a4, a2
@@ -307,7 +307,7 @@ ENTRY(__invalidate_icache_page_alias)
 
        iitlb   a4
        isync
-       retw
+       abi_ret_default
 
 ENDPROC(__invalidate_icache_page_alias)
 
@@ -325,12 +325,12 @@ ENTRY(__tlbtemp_mapping_end)
 
 ENTRY(__invalidate_icache_page)
 
-       entry   sp, 16
+       abi_entry_default
 
        ___invalidate_icache_page a2 a3
        isync
 
-       retw
+       abi_ret_default
 
 ENDPROC(__invalidate_icache_page)
 
@@ -340,12 +340,12 @@ ENDPROC(__invalidate_icache_page)
 
 ENTRY(__invalidate_dcache_page)
 
-       entry   sp, 16
+       abi_entry_default
 
        ___invalidate_dcache_page a2 a3
        dsync
 
-       retw
+       abi_ret_default
 
 ENDPROC(__invalidate_dcache_page)
 
@@ -355,12 +355,12 @@ ENDPROC(__invalidate_dcache_page)
 
 ENTRY(__flush_invalidate_dcache_page)
 
-       entry   sp, 16
+       abi_entry_default
 
        ___flush_invalidate_dcache_page a2 a3
 
        dsync
-       retw
+       abi_ret_default
 
 ENDPROC(__flush_invalidate_dcache_page)
 
@@ -370,12 +370,12 @@ ENDPROC(__flush_invalidate_dcache_page)
 
 ENTRY(__flush_dcache_page)
 
-       entry   sp, 16
+       abi_entry_default
 
        ___flush_dcache_page a2 a3
 
        dsync
-       retw
+       abi_ret_default
 
 ENDPROC(__flush_dcache_page)
 
@@ -385,12 +385,12 @@ ENDPROC(__flush_dcache_page)
 
 ENTRY(__invalidate_icache_range)
 
-       entry   sp, 16
+       abi_entry_default
 
        ___invalidate_icache_range a2 a3 a4
        isync
 
-       retw
+       abi_ret_default
 
 ENDPROC(__invalidate_icache_range)
 
@@ -400,12 +400,12 @@ ENDPROC(__invalidate_icache_range)
 
 ENTRY(__flush_invalidate_dcache_range)
 
-       entry   sp, 16
+       abi_entry_default
 
        ___flush_invalidate_dcache_range a2 a3 a4
        dsync
 
-       retw
+       abi_ret_default
 
 ENDPROC(__flush_invalidate_dcache_range)
 
@@ -415,12 +415,12 @@ ENDPROC(__flush_invalidate_dcache_range)
 
 ENTRY(__flush_dcache_range)
 
-       entry   sp, 16
+       abi_entry_default
 
        ___flush_dcache_range a2 a3 a4
        dsync
 
-       retw
+       abi_ret_default
 
 ENDPROC(__flush_dcache_range)
 
@@ -430,11 +430,11 @@ ENDPROC(__flush_dcache_range)
 
 ENTRY(__invalidate_dcache_range)
 
-       entry   sp, 16
+       abi_entry_default
 
        ___invalidate_dcache_range a2 a3 a4
 
-       retw
+       abi_ret_default
 
 ENDPROC(__invalidate_dcache_range)
 
@@ -444,12 +444,12 @@ ENDPROC(__invalidate_dcache_range)
 
 ENTRY(__invalidate_icache_all)
 
-       entry   sp, 16
+       abi_entry_default
 
        ___invalidate_icache_all a2 a3
        isync
 
-       retw
+       abi_ret_default
 
 ENDPROC(__invalidate_icache_all)
 
@@ -459,12 +459,12 @@ ENDPROC(__invalidate_icache_all)
 
 ENTRY(__flush_invalidate_dcache_all)
 
-       entry   sp, 16
+       abi_entry_default
 
        ___flush_invalidate_dcache_all a2 a3
        dsync
 
-       retw
+       abi_ret_default
 
 ENDPROC(__flush_invalidate_dcache_all)
 
@@ -474,11 +474,11 @@ ENDPROC(__flush_invalidate_dcache_all)
 
 ENTRY(__invalidate_dcache_all)
 
-       entry   sp, 16
+       abi_entry_default
 
        ___invalidate_dcache_all a2 a3
        dsync
 
-       retw
+       abi_ret_default
 
 ENDPROC(__invalidate_dcache_all)
index 56cb169..8b5f8e5 100644 (file)
@@ -89,7 +89,7 @@ config BLK_DEV_THROTTLING
        one needs to mount and use blkio cgroup controller for creating
        cgroups and specifying per device IO rate policies.
 
-       See Documentation/cgroup-v1/blkio-controller.rst for more information.
+       See Documentation/admin-guide/cgroup-v1/blkio-controller.rst for more information.
 
 config BLK_DEV_THROTTLING_LOW
        bool "Block throttling .low limit interface support (EXPERIMENTAL)"
@@ -110,7 +110,7 @@ config BLK_CMDLINE_PARSER
        which don't otherwise have any standardized method for listing the
        partitions on a block device.
 
-       See Documentation/block/cmdline-partition.txt for more information.
+       See Documentation/block/cmdline-partition.rst for more information.
 
 config BLK_WBT
        bool "Enable support for block device writeback throttling"
index 7a6b2f2..b89310a 100644 (file)
@@ -26,7 +26,7 @@ config IOSCHED_BFQ
        regardless of the device parameters and with any workload. It
        also guarantees a low latency to interactive and soft
        real-time applications.  Details in
-       Documentation/block/bfq-iosched.txt
+       Documentation/block/bfq-iosched.rst
 
 config BFQ_GROUP_IOSCHED
        bool "BFQ hierarchical scheduling support"
index b627e3f..586fcfe 100644 (file)
@@ -17,7 +17,7 @@
  * low-latency capabilities. BFQ also supports full hierarchical
  * scheduling through cgroups. Next paragraphs provide an introduction
  * on BFQ inner workings. Details on BFQ benefits, usage and
- * limitations can be found in Documentation/block/bfq-iosched.txt.
+ * limitations can be found in Documentation/block/bfq-iosched.rst.
  *
  * BFQ is a proportional-share storage-I/O scheduling algorithm based
  * on the slice-by-slice service scheme of CFQ. But BFQ assigns
index 825c9c0..ca39b46 100644 (file)
@@ -383,7 +383,7 @@ static const struct blk_integrity_profile nop_profile = {
  * send/receive integrity metadata it must use this function to register
  * the capability with the block layer. The template is a blk_integrity
  * struct with values appropriate for the underlying hardware. See
- * Documentation/block/data-integrity.txt.
+ * Documentation/block/data-integrity.rst.
  */
 void blk_integrity_register(struct gendisk *disk, struct blk_integrity *template)
 {
index 2e0559f..77bcab1 100644 (file)
@@ -17,7 +17,7 @@
  *
  * ioprio_set(PRIO_PROCESS, pid, prio);
  *
- * See also Documentation/block/ioprio.txt
+ * See also Documentation/block/ioprio.rst
  *
  */
 #include <linux/gfp.h>
index b8a682b..2a2a2e8 100644 (file)
@@ -25,7 +25,7 @@
 #include "blk-mq-sched.h"
 
 /*
- * See Documentation/block/deadline-iosched.txt
+ * See Documentation/block/deadline-iosched.rst
  */
 static const int read_expire = HZ / 2;  /* max time before a read is submitted. */
 static const int write_expire = 5 * HZ; /* ditto for writes, these limits are SOFT! */
index 37b9710..702689a 100644 (file)
@@ -194,7 +194,7 @@ config LDM_PARTITION
          Normal partitions are now called Basic Disks under Windows 2000, XP,
          and Vista.
 
-         For a fuller description read <file:Documentation/ldm.txt>.
+         For a fuller description read <file:Documentation/admin-guide/ldm.rst>.
 
          If unsure, say N.
 
index 60fb3df..f1edd54 100644 (file)
@@ -11,7 +11,7 @@
  *
  * The format for the command line is just like mtdparts.
  *
- * For further information, see "Documentation/block/cmdline-partition.txt"
+ * For further information, see "Documentation/block/cmdline-partition.rst"
  *
  */
 
index db013dc..e294f44 100644 (file)
@@ -155,16 +155,6 @@ static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
        return 0;
 }
 
-static unsigned long acpi_meminfo_start_pfn(struct acpi_memory_info *info)
-{
-       return PFN_DOWN(info->start_addr);
-}
-
-static unsigned long acpi_meminfo_end_pfn(struct acpi_memory_info *info)
-{
-       return PFN_UP(info->start_addr + info->length-1);
-}
-
 static int acpi_bind_memblk(struct memory_block *mem, void *arg)
 {
        return acpi_bind_one(&mem->dev, arg);
@@ -173,9 +163,8 @@ static int acpi_bind_memblk(struct memory_block *mem, void *arg)
 static int acpi_bind_memory_blocks(struct acpi_memory_info *info,
                                   struct acpi_device *adev)
 {
-       return walk_memory_range(acpi_meminfo_start_pfn(info),
-                                acpi_meminfo_end_pfn(info), adev,
-                                acpi_bind_memblk);
+       return walk_memory_blocks(info->start_addr, info->length, adev,
+                                 acpi_bind_memblk);
 }
 
 static int acpi_unbind_memblk(struct memory_block *mem, void *arg)
@@ -186,8 +175,8 @@ static int acpi_unbind_memblk(struct memory_block *mem, void *arg)
 
 static void acpi_unbind_memory_blocks(struct acpi_memory_info *info)
 {
-       walk_memory_range(acpi_meminfo_start_pfn(info),
-                         acpi_meminfo_end_pfn(info), NULL, acpi_unbind_memblk);
+       walk_memory_blocks(info->start_addr, info->length, NULL,
+                          acpi_unbind_memblk);
 }
 
 static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
index 9489ffc..4f325e4 100644 (file)
@@ -60,6 +60,12 @@ module_param(report_key_events, int, 0644);
 MODULE_PARM_DESC(report_key_events,
        "0: none, 1: output changes, 2: brightness changes, 3: all");
 
+static int hw_changes_brightness = -1;
+module_param(hw_changes_brightness, int, 0644);
+MODULE_PARM_DESC(hw_changes_brightness,
+       "Set this to 1 on buggy hw which changes the brightness itself when "
+       "a hotkey is pressed: -1: auto, 0: normal 1: hw-changes-brightness");
+
 /*
  * Whether the struct acpi_video_device_attrib::device_id_scheme bit should be
  * assumed even if not actually set.
@@ -405,6 +411,14 @@ static int video_set_report_key_events(const struct dmi_system_id *id)
        return 0;
 }
 
+static int video_hw_changes_brightness(
+       const struct dmi_system_id *d)
+{
+       if (hw_changes_brightness == -1)
+               hw_changes_brightness = 1;
+       return 0;
+}
+
 static const struct dmi_system_id video_dmi_table[] = {
        /*
         * Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121
@@ -529,6 +543,21 @@ static const struct dmi_system_id video_dmi_table[] = {
                DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"),
                },
        },
+       /*
+        * Some machines change the brightness themselves when a brightness
+        * hotkey gets pressed, despite us telling them not to. In this case
+        * acpi_video_device_notify() should only call backlight_force_update(
+        * BACKLIGHT_UPDATE_HOTKEY) and not do anything else.
+        */
+       {
+        /* https://bugzilla.kernel.org/show_bug.cgi?id=204077 */
+        .callback = video_hw_changes_brightness,
+        .ident = "Packard Bell EasyNote MZ35",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Packard Bell"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "EasyNote MZ35"),
+               },
+       },
        {}
 };
 
@@ -1612,6 +1641,14 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
        bus = video_device->video;
        input = bus->input;
 
+       if (hw_changes_brightness > 0) {
+               if (video_device->backlight)
+                       backlight_force_update(video_device->backlight,
+                                              BACKLIGHT_UPDATE_HOTKEY);
+               acpi_notifier_call_chain(device, event, 0);
+               return;
+       }
+
        switch (event) {
        case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS:        /* Cycle brightness */
                brightness_switch_event(video_device, event);
index 587aeee..46a8baf 100644 (file)
@@ -174,12 +174,11 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
                return_ACPI_STATUS(status);
        }
 
-       /* Complete the initialization/resolution of package objects */
+       /* Complete the initialization/resolution of new objects */
 
-       status = acpi_ns_walk_namespace(ACPI_TYPE_PACKAGE, ACPI_ROOT_OBJECT,
-                                       ACPI_UINT32_MAX, 0,
-                                       acpi_ns_init_one_package, NULL, NULL,
-                                       NULL);
+       acpi_ex_exit_interpreter();
+       acpi_ns_initialize_objects();
+       acpi_ex_enter_interpreter();
 
        /* Parameter Data (optional) */
 
@@ -437,12 +436,11 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
                return_ACPI_STATUS(status);
        }
 
-       /* Complete the initialization/resolution of package objects */
+       /* Complete the initialization/resolution of new objects */
 
-       status = acpi_ns_walk_namespace(ACPI_TYPE_PACKAGE, ACPI_ROOT_OBJECT,
-                                       ACPI_UINT32_MAX, 0,
-                                       acpi_ns_init_one_package, NULL, NULL,
-                                       NULL);
+       acpi_ex_exit_interpreter();
+       acpi_ns_initialize_objects();
+       acpi_ex_enter_interpreter();
 
        /* Store the ddb_handle into the Target operand */
 
index ef8f8a9..86f1693 100644 (file)
@@ -297,15 +297,11 @@ acpi_status acpi_load_table(struct acpi_table_header *table)
        status = acpi_tb_install_and_load_table(ACPI_PTR_TO_PHYSADDR(table),
                                                ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL,
                                                FALSE, &table_index);
-
        if (ACPI_SUCCESS(status)) {
-               /* Complete the initialization/resolution of package objects */
 
-               status = acpi_ns_walk_namespace(ACPI_TYPE_PACKAGE,
-                                               ACPI_ROOT_OBJECT,
-                                               ACPI_UINT32_MAX, 0,
-                                               acpi_ns_init_one_package,
-                                               NULL, NULL, NULL);
+               /* Complete the initialization/resolution of new objects */
+
+               acpi_ns_initialize_objects();
        }
 
        return_ACPI_STATUS(status);
index ad2c565..a86a770 100644 (file)
@@ -17,7 +17,9 @@
 
 #include "internal.h"
 
+#ifdef CONFIG_DMI
 static const struct dmi_system_id acpi_rev_dmi_table[] __initconst;
+#endif
 
 /*
  * POLICY: If *anything* doesn't work, put it on the blacklist.
@@ -61,7 +63,9 @@ int __init acpi_blacklisted(void)
        }
 
        (void)early_acpi_osi_init();
+#ifdef CONFIG_DMI
        dmi_check_system(acpi_rev_dmi_table);
+#endif
 
        return blacklisted;
 }
index 23022cf..c02fa27 100644 (file)
@@ -2426,7 +2426,7 @@ static void write_blk_ctl(struct nfit_blk *nfit_blk, unsigned int bw,
                offset = to_interleave_offset(offset, mmio);
 
        writeq(cmd, mmio->addr.base + offset);
-       nvdimm_flush(nfit_blk->nd_region);
+       nvdimm_flush(nfit_blk->nd_region, NULL);
 
        if (nfit_blk->dimm_flags & NFIT_BLK_DCR_LATCH)
                readq(mmio->addr.base + offset);
@@ -2475,7 +2475,7 @@ static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk,
        }
 
        if (rw)
-               nvdimm_flush(nfit_blk->nd_region);
+               nvdimm_flush(nfit_blk->nd_region, NULL);
 
        rc = read_blk_stat(nfit_blk, lane) ? -EIO : 0;
        return rc;
index 43a1457..df51680 100644 (file)
@@ -1379,7 +1379,6 @@ init_tsq(struct idt77252_dev *card)
                printk("%s: can't allocate TSQ.\n", card->name);
                return -1;
        }
-       memset(card->tsq.base, 0, TSQSIZE);
 
        card->tsq.last = card->tsq.base + TSQ_NUM_ENTRIES - 1;
        card->tsq.next = card->tsq.last;
index 0dbc430..ba5c809 100644 (file)
@@ -357,8 +357,7 @@ int devtmpfs_mount(const char *mntdir)
        if (!thread)
                return 0;
 
-       err = ksys_mount("devtmpfs", (char *)mntdir, "devtmpfs", MS_SILENT,
-                        NULL);
+       err = ksys_mount("devtmpfs", mntdir, "devtmpfs", MS_SILENT, NULL);
        if (err)
                printk(KERN_INFO "devtmpfs: error mounting %i\n", err);
        else
index 776dd69..ba9d30b 100644 (file)
@@ -16,9 +16,6 @@
  * firmware fallback configuration table
  */
 
-static unsigned int zero;
-static unsigned int one = 1;
-
 struct firmware_fallback_config fw_fallback_config = {
        .force_sysfs_fallback = IS_ENABLED(CONFIG_FW_LOADER_USER_HELPER_FALLBACK),
        .loading_timeout = 60,
@@ -26,6 +23,7 @@ struct firmware_fallback_config fw_fallback_config = {
 };
 EXPORT_SYMBOL_GPL(fw_fallback_config);
 
+#ifdef CONFIG_SYSCTL
 struct ctl_table firmware_config_table[] = {
        {
                .procname       = "force_sysfs_fallback",
@@ -33,8 +31,8 @@ struct ctl_table firmware_config_table[] = {
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_douintvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        {
                .procname       = "ignore_sysfs_fallback",
@@ -42,9 +40,10 @@ struct ctl_table firmware_config_table[] = {
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_douintvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        { }
 };
 EXPORT_SYMBOL_GPL(firmware_config_table);
+#endif
index f180427..20c39d1 100644 (file)
@@ -34,11 +34,21 @@ static DEFINE_MUTEX(mem_sysfs_mutex);
 
 static int sections_per_block;
 
-static inline int base_memory_block_id(int section_nr)
+static inline unsigned long base_memory_block_id(unsigned long section_nr)
 {
        return section_nr / sections_per_block;
 }
 
+static inline unsigned long pfn_to_block_id(unsigned long pfn)
+{
+       return base_memory_block_id(pfn_to_section_nr(pfn));
+}
+
+static inline unsigned long phys_to_block_id(unsigned long phys)
+{
+       return pfn_to_block_id(PFN_DOWN(phys));
+}
+
 static int memory_subsys_online(struct device *dev);
 static int memory_subsys_offline(struct device *dev);
 
@@ -126,9 +136,9 @@ static ssize_t phys_index_show(struct device *dev,
 static ssize_t removable_show(struct device *dev, struct device_attribute *attr,
                              char *buf)
 {
-       unsigned long i, pfn;
-       int ret = 1;
        struct memory_block *mem = to_memory_block(dev);
+       unsigned long pfn;
+       int ret = 1, i;
 
        if (mem->state != MEM_ONLINE)
                goto out;
@@ -578,23 +588,13 @@ int __weak arch_get_memory_phys_device(unsigned long start_pfn)
        return 0;
 }
 
-/*
- * A reference for the returned object is held and the reference for the
- * hinted object is released.
- */
-struct memory_block *find_memory_block_hinted(struct mem_section *section,
-                                             struct memory_block *hint)
+/* A reference for the returned memory block device is acquired. */
+static struct memory_block *find_memory_block_by_id(unsigned long block_id)
 {
-       int block_id = base_memory_block_id(__section_nr(section));
-       struct device *hintdev = hint ? &hint->dev : NULL;
        struct device *dev;
 
-       dev = subsys_find_device_by_id(&memory_subsys, block_id, hintdev);
-       if (hint)
-               put_device(&hint->dev);
-       if (!dev)
-               return NULL;
-       return to_memory_block(dev);
+       dev = subsys_find_device_by_id(&memory_subsys, block_id, NULL);
+       return dev ? to_memory_block(dev) : NULL;
 }
 
 /*
@@ -607,7 +607,9 @@ struct memory_block *find_memory_block_hinted(struct mem_section *section,
  */
 struct memory_block *find_memory_block(struct mem_section *section)
 {
-       return find_memory_block_hinted(section, NULL);
+       unsigned long block_id = base_memory_block_id(__section_nr(section));
+
+       return find_memory_block_by_id(block_id);
 }
 
 static struct attribute *memory_memblk_attrs[] = {
@@ -652,20 +654,22 @@ int register_memory(struct memory_block *memory)
 }
 
 static int init_memory_block(struct memory_block **memory,
-                            struct mem_section *section, unsigned long state)
+                            unsigned long block_id, unsigned long state)
 {
        struct memory_block *mem;
        unsigned long start_pfn;
-       int scn_nr;
        int ret = 0;
 
+       mem = find_memory_block_by_id(block_id);
+       if (mem) {
+               put_device(&mem->dev);
+               return -EEXIST;
+       }
        mem = kzalloc(sizeof(*mem), GFP_KERNEL);
        if (!mem)
                return -ENOMEM;
 
-       scn_nr = __section_nr(section);
-       mem->start_section_nr =
-                       base_memory_block_id(scn_nr) * sections_per_block;
+       mem->start_section_nr = block_id * sections_per_block;
        mem->end_section_nr = mem->start_section_nr + sections_per_block - 1;
        mem->state = state;
        start_pfn = section_nr_to_pfn(mem->start_section_nr);
@@ -677,97 +681,101 @@ static int init_memory_block(struct memory_block **memory,
        return ret;
 }
 
-static int add_memory_block(int base_section_nr)
+static int add_memory_block(unsigned long base_section_nr)
 {
+       int ret, section_count = 0;
        struct memory_block *mem;
-       int i, ret, section_count = 0, section_nr;
+       unsigned long nr;
 
-       for (i = base_section_nr;
-            i < base_section_nr + sections_per_block;
-            i++) {
-               if (!present_section_nr(i))
-                       continue;
-               if (section_count == 0)
-                       section_nr = i;
-               section_count++;
-       }
+       for (nr = base_section_nr; nr < base_section_nr + sections_per_block;
+            nr++)
+               if (present_section_nr(nr))
+                       section_count++;
 
        if (section_count == 0)
                return 0;
-       ret = init_memory_block(&mem, __nr_to_section(section_nr), MEM_ONLINE);
+       ret = init_memory_block(&mem, base_memory_block_id(base_section_nr),
+                               MEM_ONLINE);
        if (ret)
                return ret;
        mem->section_count = section_count;
        return 0;
 }
 
+static void unregister_memory(struct memory_block *memory)
+{
+       if (WARN_ON_ONCE(memory->dev.bus != &memory_subsys))
+               return;
+
+       /* drop the ref. we got via find_memory_block() */
+       put_device(&memory->dev);
+       device_unregister(&memory->dev);
+}
+
 /*
- * need an interface for the VM to add new memory regions,
- * but without onlining it.
+ * Create memory block devices for the given memory area. Start and size
+ * have to be aligned to memory block granularity. Memory block devices
+ * will be initialized as offline.
  */
-int hotplug_memory_register(int nid, struct mem_section *section)
+int create_memory_block_devices(unsigned long start, unsigned long size)
 {
-       int ret = 0;
+       const unsigned long start_block_id = pfn_to_block_id(PFN_DOWN(start));
+       unsigned long end_block_id = pfn_to_block_id(PFN_DOWN(start + size));
        struct memory_block *mem;
+       unsigned long block_id;
+       int ret = 0;
 
-       mutex_lock(&mem_sysfs_mutex);
+       if (WARN_ON_ONCE(!IS_ALIGNED(start, memory_block_size_bytes()) ||
+                        !IS_ALIGNED(size, memory_block_size_bytes())))
+               return -EINVAL;
 
-       mem = find_memory_block(section);
-       if (mem) {
-               mem->section_count++;
-               put_device(&mem->dev);
-       } else {
-               ret = init_memory_block(&mem, section, MEM_OFFLINE);
+       mutex_lock(&mem_sysfs_mutex);
+       for (block_id = start_block_id; block_id != end_block_id; block_id++) {
+               ret = init_memory_block(&mem, block_id, MEM_OFFLINE);
                if (ret)
-                       goto out;
-               mem->section_count++;
+                       break;
+               mem->section_count = sections_per_block;
+       }
+       if (ret) {
+               end_block_id = block_id;
+               for (block_id = start_block_id; block_id != end_block_id;
+                    block_id++) {
+                       mem = find_memory_block_by_id(block_id);
+                       mem->section_count = 0;
+                       unregister_memory(mem);
+               }
        }
-
-out:
        mutex_unlock(&mem_sysfs_mutex);
        return ret;
 }
 
-#ifdef CONFIG_MEMORY_HOTREMOVE
-static void
-unregister_memory(struct memory_block *memory)
-{
-       BUG_ON(memory->dev.bus != &memory_subsys);
-
-       /* drop the ref. we got via find_memory_block() */
-       put_device(&memory->dev);
-       device_unregister(&memory->dev);
-}
-
-void unregister_memory_section(struct mem_section *section)
+/*
+ * Remove memory block devices for the given memory area. Start and size
+ * have to be aligned to memory block granularity. Memory block devices
+ * have to be offline.
+ */
+void remove_memory_block_devices(unsigned long start, unsigned long size)
 {
+       const unsigned long start_block_id = pfn_to_block_id(PFN_DOWN(start));
+       const unsigned long end_block_id = pfn_to_block_id(PFN_DOWN(start + size));
        struct memory_block *mem;
+       unsigned long block_id;
 
-       if (WARN_ON_ONCE(!present_section(section)))
+       if (WARN_ON_ONCE(!IS_ALIGNED(start, memory_block_size_bytes()) ||
+                        !IS_ALIGNED(size, memory_block_size_bytes())))
                return;
 
        mutex_lock(&mem_sysfs_mutex);
-
-       /*
-        * Some users of the memory hotplug do not want/need memblock to
-        * track all sections. Skip over those.
-        */
-       mem = find_memory_block(section);
-       if (!mem)
-               goto out_unlock;
-
-       unregister_mem_sect_under_nodes(mem, __section_nr(section));
-
-       mem->section_count--;
-       if (mem->section_count == 0)
+       for (block_id = start_block_id; block_id != end_block_id; block_id++) {
+               mem = find_memory_block_by_id(block_id);
+               if (WARN_ON_ONCE(!mem))
+                       continue;
+               mem->section_count = 0;
+               unregister_memory_block_under_nodes(mem);
                unregister_memory(mem);
-       else
-               put_device(&mem->dev);
-
-out_unlock:
+       }
        mutex_unlock(&mem_sysfs_mutex);
 }
-#endif /* CONFIG_MEMORY_HOTREMOVE */
 
 /* return true if the memory block is offlined, otherwise, return false */
 bool is_memblock_offlined(struct memory_block *mem)
@@ -804,10 +812,9 @@ static const struct attribute_group *memory_root_attr_groups[] = {
  */
 int __init memory_dev_init(void)
 {
-       unsigned int i;
        int ret;
        int err;
-       unsigned long block_sz;
+       unsigned long block_sz, nr;
 
        ret = subsys_system_register(&memory_subsys, memory_root_attr_groups);
        if (ret)
@@ -821,9 +828,9 @@ int __init memory_dev_init(void)
         * during boot and have been initialized
         */
        mutex_lock(&mem_sysfs_mutex);
-       for (i = 0; i <= __highest_present_section_nr;
-               i += sections_per_block) {
-               err = add_memory_block(i);
+       for (nr = 0; nr <= __highest_present_section_nr;
+            nr += sections_per_block) {
+               err = add_memory_block(nr);
                if (!ret)
                        ret = err;
        }
@@ -834,3 +841,43 @@ out:
                printk(KERN_ERR "%s() failed: %d\n", __func__, ret);
        return ret;
 }
+
+/**
+ * walk_memory_blocks - walk through all present memory blocks overlapped
+ *                     by the range [start, start + size)
+ *
+ * @start: start address of the memory range
+ * @size: size of the memory range
+ * @arg: argument passed to func
+ * @func: callback for each memory section walked
+ *
+ * This function walks through all present memory blocks overlapped by the
+ * range [start, start + size), calling func on each memory block.
+ *
+ * In case func() returns an error, walking is aborted and the error is
+ * returned.
+ */
+int walk_memory_blocks(unsigned long start, unsigned long size,
+                      void *arg, walk_memory_blocks_func_t func)
+{
+       const unsigned long start_block_id = phys_to_block_id(start);
+       const unsigned long end_block_id = phys_to_block_id(start + size - 1);
+       struct memory_block *mem;
+       unsigned long block_id;
+       int ret = 0;
+
+       if (!size)
+               return 0;
+
+       for (block_id = start_block_id; block_id <= end_block_id; block_id++) {
+               mem = find_memory_block_by_id(block_id);
+               if (!mem)
+                       continue;
+
+               ret = func(mem, arg);
+               put_device(&mem->dev);
+               if (ret)
+                       break;
+       }
+       return ret;
+}
index aa878fb..75b7e6f 100644 (file)
@@ -753,7 +753,8 @@ static int __ref get_nid_for_pfn(unsigned long pfn)
 }
 
 /* register memory section under specified node if it spans that node */
-int register_mem_sect_under_node(struct memory_block *mem_blk, void *arg)
+static int register_mem_sect_under_node(struct memory_block *mem_blk,
+                                        void *arg)
 {
        int ret, nid = *(int *)arg;
        unsigned long pfn, sect_start_pfn, sect_end_pfn;
@@ -802,23 +803,18 @@ int register_mem_sect_under_node(struct memory_block *mem_blk, void *arg)
        return 0;
 }
 
-/* unregister memory section under all nodes that it spans */
-int unregister_mem_sect_under_nodes(struct memory_block *mem_blk,
-                                   unsigned long phys_index)
+/*
+ * Unregister memory block device under all nodes that it spans.
+ * Has to be called with mem_sysfs_mutex held (due to unlinked_nodes).
+ */
+void unregister_memory_block_under_nodes(struct memory_block *mem_blk)
 {
-       NODEMASK_ALLOC(nodemask_t, unlinked_nodes, GFP_KERNEL);
        unsigned long pfn, sect_start_pfn, sect_end_pfn;
+       static nodemask_t unlinked_nodes;
 
-       if (!mem_blk) {
-               NODEMASK_FREE(unlinked_nodes);
-               return -EFAULT;
-       }
-       if (!unlinked_nodes)
-               return -ENOMEM;
-       nodes_clear(*unlinked_nodes);
-
-       sect_start_pfn = section_nr_to_pfn(phys_index);
-       sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1;
+       nodes_clear(unlinked_nodes);
+       sect_start_pfn = section_nr_to_pfn(mem_blk->start_section_nr);
+       sect_end_pfn = section_nr_to_pfn(mem_blk->end_section_nr);
        for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) {
                int nid;
 
@@ -827,21 +823,20 @@ int unregister_mem_sect_under_nodes(struct memory_block *mem_blk,
                        continue;
                if (!node_online(nid))
                        continue;
-               if (node_test_and_set(nid, *unlinked_nodes))
+               if (node_test_and_set(nid, unlinked_nodes))
                        continue;
                sysfs_remove_link(&node_devices[nid]->dev.kobj,
                         kobject_name(&mem_blk->dev.kobj));
                sysfs_remove_link(&mem_blk->dev.kobj,
                         kobject_name(&node_devices[nid]->dev.kobj));
        }
-       NODEMASK_FREE(unlinked_nodes);
-       return 0;
 }
 
 int link_mem_sections(int nid, unsigned long start_pfn, unsigned long end_pfn)
 {
-       return walk_memory_range(start_pfn, end_pfn, (void *)&nid,
-                                       register_mem_sect_under_node);
+       return walk_memory_blocks(PFN_PHYS(start_pfn),
+                                 PFN_PHYS(end_pfn - start_pfn), (void *)&nid,
+                                 register_mem_sect_under_node);
 }
 
 #ifdef CONFIG_HUGETLBFS
index 7139032..506a017 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (c) 2002-3 Patrick Mochel
  * Copyright (c) 2002-3 Open Source Development Labs
  *
- * Please see Documentation/driver-model/platform.rst for more
+ * Please see Documentation/driver-api/driver-model/platform.rst for more
  * information.
  */
 
index 33c30c1..b063bc4 100644 (file)
@@ -1536,7 +1536,8 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
        if (ret)
                genpd_free_dev_data(dev, gpd_data);
        else
-               dev_pm_qos_add_notifier(dev, &gpd_data->nb);
+               dev_pm_qos_add_notifier(dev, &gpd_data->nb,
+                                       DEV_PM_QOS_RESUME_LATENCY);
 
        return ret;
 }
@@ -1569,7 +1570,8 @@ static int genpd_remove_device(struct generic_pm_domain *genpd,
 
        pdd = dev->power.subsys_data->domain_data;
        gpd_data = to_gpd_data(pdd);
-       dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
+       dev_pm_qos_remove_notifier(dev, &gpd_data->nb,
+                                  DEV_PM_QOS_RESUME_LATENCY);
 
        genpd_lock(genpd);
 
@@ -1597,7 +1599,7 @@ static int genpd_remove_device(struct generic_pm_domain *genpd,
 
  out:
        genpd_unlock(genpd);
-       dev_pm_qos_add_notifier(dev, &gpd_data->nb);
+       dev_pm_qos_add_notifier(dev, &gpd_data->nb, DEV_PM_QOS_RESUME_LATENCY);
 
        return ret;
 }
index 3838045..daa8c76 100644 (file)
@@ -33,7 +33,7 @@ static int dev_update_qos_constraint(struct device *dev, void *data)
                 * take its current PM QoS constraint (that's the only thing
                 * known at this point anyway).
                 */
-               constraint_ns = dev_pm_qos_read_value(dev);
+               constraint_ns = dev_pm_qos_read_value(dev, DEV_PM_QOS_RESUME_LATENCY);
                constraint_ns *= NSEC_PER_USEC;
        }
 
@@ -66,7 +66,7 @@ static bool default_suspend_ok(struct device *dev)
        td->constraint_changed = false;
        td->cached_suspend_ok = false;
        td->effective_constraint_ns = 0;
-       constraint_ns = __dev_pm_qos_read_value(dev);
+       constraint_ns = __dev_pm_qos_resume_latency(dev);
 
        spin_unlock_irqrestore(&dev->power.lock, flags);
 
index 6c91f8d..6c90fd7 100644 (file)
@@ -90,29 +90,49 @@ enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask)
 EXPORT_SYMBOL_GPL(dev_pm_qos_flags);
 
 /**
- * __dev_pm_qos_read_value - Get PM QoS constraint for a given device.
+ * __dev_pm_qos_resume_latency - Get resume latency constraint for a given device.
  * @dev: Device to get the PM QoS constraint value for.
  *
  * This routine must be called with dev->power.lock held.
  */
-s32 __dev_pm_qos_read_value(struct device *dev)
+s32 __dev_pm_qos_resume_latency(struct device *dev)
 {
        lockdep_assert_held(&dev->power.lock);
 
-       return dev_pm_qos_raw_read_value(dev);
+       return dev_pm_qos_raw_resume_latency(dev);
 }
 
 /**
  * dev_pm_qos_read_value - Get PM QoS constraint for a given device (locked).
  * @dev: Device to get the PM QoS constraint value for.
+ * @type: QoS request type.
  */
-s32 dev_pm_qos_read_value(struct device *dev)
+s32 dev_pm_qos_read_value(struct device *dev, enum dev_pm_qos_req_type type)
 {
+       struct dev_pm_qos *qos = dev->power.qos;
        unsigned long flags;
        s32 ret;
 
        spin_lock_irqsave(&dev->power.lock, flags);
-       ret = __dev_pm_qos_read_value(dev);
+
+       switch (type) {
+       case DEV_PM_QOS_RESUME_LATENCY:
+               ret = IS_ERR_OR_NULL(qos) ? PM_QOS_RESUME_LATENCY_NO_CONSTRAINT
+                       : pm_qos_read_value(&qos->resume_latency);
+               break;
+       case DEV_PM_QOS_MIN_FREQUENCY:
+               ret = IS_ERR_OR_NULL(qos) ? PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE
+                       : pm_qos_read_value(&qos->min_frequency);
+               break;
+       case DEV_PM_QOS_MAX_FREQUENCY:
+               ret = IS_ERR_OR_NULL(qos) ? PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE
+                       : pm_qos_read_value(&qos->max_frequency);
+               break;
+       default:
+               WARN_ON(1);
+               ret = 0;
+       }
+
        spin_unlock_irqrestore(&dev->power.lock, flags);
 
        return ret;
@@ -149,6 +169,14 @@ static int apply_constraint(struct dev_pm_qos_request *req,
                        req->dev->power.set_latency_tolerance(req->dev, value);
                }
                break;
+       case DEV_PM_QOS_MIN_FREQUENCY:
+               ret = pm_qos_update_target(&qos->min_frequency,
+                                          &req->data.pnode, action, value);
+               break;
+       case DEV_PM_QOS_MAX_FREQUENCY:
+               ret = pm_qos_update_target(&qos->max_frequency,
+                                          &req->data.pnode, action, value);
+               break;
        case DEV_PM_QOS_FLAGS:
                ret = pm_qos_update_flags(&qos->flags, &req->data.flr,
                                          action, value);
@@ -177,12 +205,11 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
        if (!qos)
                return -ENOMEM;
 
-       n = kzalloc(sizeof(*n), GFP_KERNEL);
+       n = kzalloc(3 * sizeof(*n), GFP_KERNEL);
        if (!n) {
                kfree(qos);
                return -ENOMEM;
        }
-       BLOCKING_INIT_NOTIFIER_HEAD(n);
 
        c = &qos->resume_latency;
        plist_head_init(&c->list);
@@ -191,6 +218,7 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
        c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
        c->type = PM_QOS_MIN;
        c->notifiers = n;
+       BLOCKING_INIT_NOTIFIER_HEAD(n);
 
        c = &qos->latency_tolerance;
        plist_head_init(&c->list);
@@ -199,6 +227,24 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
        c->no_constraint_value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT;
        c->type = PM_QOS_MIN;
 
+       c = &qos->min_frequency;
+       plist_head_init(&c->list);
+       c->target_value = PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE;
+       c->default_value = PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE;
+       c->no_constraint_value = PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE;
+       c->type = PM_QOS_MAX;
+       c->notifiers = ++n;
+       BLOCKING_INIT_NOTIFIER_HEAD(n);
+
+       c = &qos->max_frequency;
+       plist_head_init(&c->list);
+       c->target_value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
+       c->default_value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
+       c->no_constraint_value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
+       c->type = PM_QOS_MIN;
+       c->notifiers = ++n;
+       BLOCKING_INIT_NOTIFIER_HEAD(n);
+
        INIT_LIST_HEAD(&qos->flags.list);
 
        spin_lock_irq(&dev->power.lock);
@@ -252,11 +298,25 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
                apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
                memset(req, 0, sizeof(*req));
        }
+
        c = &qos->latency_tolerance;
        plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
                apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
                memset(req, 0, sizeof(*req));
        }
+
+       c = &qos->min_frequency;
+       plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
+               apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE);
+               memset(req, 0, sizeof(*req));
+       }
+
+       c = &qos->max_frequency;
+       plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
+               apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
+               memset(req, 0, sizeof(*req));
+       }
+
        f = &qos->flags;
        list_for_each_entry_safe(req, tmp, &f->list, data.flr.node) {
                apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
@@ -368,6 +428,8 @@ static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req,
        switch(req->type) {
        case DEV_PM_QOS_RESUME_LATENCY:
        case DEV_PM_QOS_LATENCY_TOLERANCE:
+       case DEV_PM_QOS_MIN_FREQUENCY:
+       case DEV_PM_QOS_MAX_FREQUENCY:
                curr_value = req->data.pnode.prio;
                break;
        case DEV_PM_QOS_FLAGS:
@@ -467,6 +529,7 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
  *
  * @dev: target device for the constraint
  * @notifier: notifier block managed by caller.
+ * @type: request type.
  *
  * Will register the notifier into a notification chain that gets called
  * upon changes to the target value for the device.
@@ -474,7 +537,8 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
  * If the device's constraints object doesn't exist when this routine is called,
  * it will be created (or error code will be returned if that fails).
  */
-int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
+int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier,
+                           enum dev_pm_qos_req_type type)
 {
        int ret = 0;
 
@@ -485,10 +549,28 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
        else if (!dev->power.qos)
                ret = dev_pm_qos_constraints_allocate(dev);
 
-       if (!ret)
+       if (ret)
+               goto unlock;
+
+       switch (type) {
+       case DEV_PM_QOS_RESUME_LATENCY:
                ret = blocking_notifier_chain_register(dev->power.qos->resume_latency.notifiers,
                                                       notifier);
+               break;
+       case DEV_PM_QOS_MIN_FREQUENCY:
+               ret = blocking_notifier_chain_register(dev->power.qos->min_frequency.notifiers,
+                                                      notifier);
+               break;
+       case DEV_PM_QOS_MAX_FREQUENCY:
+               ret = blocking_notifier_chain_register(dev->power.qos->max_frequency.notifiers,
+                                                      notifier);
+               break;
+       default:
+               WARN_ON(1);
+               ret = -EINVAL;
+       }
 
+unlock:
        mutex_unlock(&dev_pm_qos_mtx);
        return ret;
 }
@@ -500,24 +582,44 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_add_notifier);
  *
  * @dev: target device for the constraint
  * @notifier: notifier block to be removed.
+ * @type: request type.
  *
  * Will remove the notifier from the notification chain that gets called
  * upon changes to the target value.
  */
 int dev_pm_qos_remove_notifier(struct device *dev,
-                              struct notifier_block *notifier)
+                              struct notifier_block *notifier,
+                              enum dev_pm_qos_req_type type)
 {
-       int retval = 0;
+       int ret = 0;
 
        mutex_lock(&dev_pm_qos_mtx);
 
        /* Silently return if the constraints object is not present. */
-       if (!IS_ERR_OR_NULL(dev->power.qos))
-               retval = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers,
-                                                           notifier);
+       if (IS_ERR_OR_NULL(dev->power.qos))
+               goto unlock;
+
+       switch (type) {
+       case DEV_PM_QOS_RESUME_LATENCY:
+               ret = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers,
+                                                        notifier);
+               break;
+       case DEV_PM_QOS_MIN_FREQUENCY:
+               ret = blocking_notifier_chain_unregister(dev->power.qos->min_frequency.notifiers,
+                                                        notifier);
+               break;
+       case DEV_PM_QOS_MAX_FREQUENCY:
+               ret = blocking_notifier_chain_unregister(dev->power.qos->max_frequency.notifiers,
+                                                        notifier);
+               break;
+       default:
+               WARN_ON(1);
+               ret = -EINVAL;
+       }
 
+unlock:
        mutex_unlock(&dev_pm_qos_mtx);
-       return retval;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(dev_pm_qos_remove_notifier);
 
@@ -577,6 +679,9 @@ static void __dev_pm_qos_drop_user_request(struct device *dev,
                req = dev->power.qos->flags_req;
                dev->power.qos->flags_req = NULL;
                break;
+       default:
+               WARN_ON(1);
+               return;
        }
        __dev_pm_qos_remove_request(req);
        kfree(req);
index 952a1e7..b753355 100644 (file)
@@ -275,7 +275,7 @@ static int rpm_check_suspend_allowed(struct device *dev)
            || (dev->power.request_pending
                        && dev->power.request == RPM_REQ_RESUME))
                retval = -EAGAIN;
-       else if (__dev_pm_qos_read_value(dev) == 0)
+       else if (__dev_pm_qos_resume_latency(dev) == 0)
                retval = -EPERM;
        else if (dev->power.runtime_status == RPM_SUSPENDED)
                retval = 1;
index 96ec7e0..1bb8ec5 100644 (file)
@@ -31,7 +31,7 @@ config BLK_DEV_FD
          If you want to use the floppy disk drive(s) of your PC under Linux,
          say Y. Information about this driver, especially important for IBM
          Thinkpad users, is contained in
-         <file:Documentation/blockdev/floppy.txt>.
+         <file:Documentation/admin-guide/blockdev/floppy.rst>.
          That file also contains the location of the Floppy driver FAQ as
          well as location of the fdutils package used to configure additional
          parameters of the driver at run time.
@@ -96,7 +96,7 @@ config PARIDE
          your computer's parallel port. Most of them are actually IDE devices
          using a parallel port IDE adapter. This option enables the PARIDE
          subsystem which contains drivers for many of these external drives.
-         Read <file:Documentation/blockdev/paride.txt> for more information.
+         Read <file:Documentation/admin-guide/blockdev/paride.rst> for more information.
 
          If you have said Y to the "Parallel-port support" configuration
          option, you may share a single port between your printer and other
@@ -261,7 +261,7 @@ config BLK_DEV_NBD
          userland (making server and client physically the same computer,
          communicating using the loopback network device).
 
-         Read <file:Documentation/blockdev/nbd.txt> for more information,
+         Read <file:Documentation/admin-guide/blockdev/nbd.rst> for more information,
          especially about where to find the server code, which runs in user
          space and does not need special kernel support.
 
@@ -303,7 +303,7 @@ config BLK_DEV_RAM
          during the initial install of Linux.
 
          Note that the kernel command line option "ramdisk=XX" is now obsolete.
-         For details, read <file:Documentation/blockdev/ramdisk.txt>.
+         For details, read <file:Documentation/admin-guide/blockdev/ramdisk.rst>.
 
          To compile this driver as a module, choose M here: the
          module will be called brd. An alias "rd" has been defined
index b933a7e..0469ace 100644 (file)
@@ -2120,6 +2120,9 @@ static void setup_format_params(int track)
        raw_cmd->kernel_data = floppy_track_buffer;
        raw_cmd->length = 4 * F_SECT_PER_TRACK;
 
+       if (!F_SECT_PER_TRACK)
+               return;
+
        /* allow for about 30ms for data transport per track */
        head_shift = (F_SECT_PER_TRACK + 5) / 6;
 
@@ -3230,8 +3233,12 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g,
        int cnt;
 
        /* sanity checking for parameters. */
-       if (g->sect <= 0 ||
-           g->head <= 0 ||
+       if ((int)g->sect <= 0 ||
+           (int)g->head <= 0 ||
+           /* check for overflow in max_sector */
+           (int)(g->sect * g->head) <= 0 ||
+           /* check for zero in F_SECT_PER_TRACK */
+           (unsigned char)((g->sect << 2) >> FD_SIZECODE(g)) == 0 ||
            g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
            /* check if reserved bits are set */
            (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
@@ -3375,6 +3382,24 @@ static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
        return 0;
 }
 
+static bool valid_floppy_drive_params(const short autodetect[8],
+               int native_format)
+{
+       size_t floppy_type_size = ARRAY_SIZE(floppy_type);
+       size_t i = 0;
+
+       for (i = 0; i < 8; ++i) {
+               if (autodetect[i] < 0 ||
+                   autodetect[i] >= floppy_type_size)
+                       return false;
+       }
+
+       if (native_format < 0 || native_format >= floppy_type_size)
+               return false;
+
+       return true;
+}
+
 static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
                    unsigned long param)
 {
@@ -3501,6 +3526,9 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
                SUPBOUND(size, strlen((const char *)outparam) + 1);
                break;
        case FDSETDRVPRM:
+               if (!valid_floppy_drive_params(inparam.dp.autodetect,
+                               inparam.dp.native_format))
+                       return -EINVAL;
                *UDP = inparam.dp;
                break;
        case FDGETDRVPRM:
@@ -3698,6 +3726,8 @@ static int compat_setdrvprm(int drive,
                return -EPERM;
        if (copy_from_user(&v, arg, sizeof(struct compat_floppy_drive_params)))
                return -EFAULT;
+       if (!valid_floppy_drive_params(v.autodetect, v.native_format))
+               return -EINVAL;
        mutex_lock(&floppy_mutex);
        UDP->cmos = v.cmos;
        UDP->max_dtr = v.max_dtr;
@@ -4424,7 +4454,7 @@ static int __init floppy_setup(char *str)
                pr_cont("\n");
        } else
                DPRINT("botched floppy option\n");
-       DPRINT("Read Documentation/blockdev/floppy.txt\n");
+       DPRINT("Read Documentation/admin-guide/blockdev/floppy.rst\n");
        return 0;
 }
 
index e5009a3..3327192 100644 (file)
@@ -115,6 +115,8 @@ static int atomic_dec_return_safe(atomic_t *v)
 #define RBD_FEATURE_LAYERING           (1ULL<<0)
 #define RBD_FEATURE_STRIPINGV2         (1ULL<<1)
 #define RBD_FEATURE_EXCLUSIVE_LOCK     (1ULL<<2)
+#define RBD_FEATURE_OBJECT_MAP         (1ULL<<3)
+#define RBD_FEATURE_FAST_DIFF          (1ULL<<4)
 #define RBD_FEATURE_DEEP_FLATTEN       (1ULL<<5)
 #define RBD_FEATURE_DATA_POOL          (1ULL<<7)
 #define RBD_FEATURE_OPERATIONS         (1ULL<<8)
@@ -122,6 +124,8 @@ static int atomic_dec_return_safe(atomic_t *v)
 #define RBD_FEATURES_ALL       (RBD_FEATURE_LAYERING |         \
                                 RBD_FEATURE_STRIPINGV2 |       \
                                 RBD_FEATURE_EXCLUSIVE_LOCK |   \
+                                RBD_FEATURE_OBJECT_MAP |       \
+                                RBD_FEATURE_FAST_DIFF |        \
                                 RBD_FEATURE_DEEP_FLATTEN |     \
                                 RBD_FEATURE_DATA_POOL |        \
                                 RBD_FEATURE_OPERATIONS)
@@ -203,6 +207,11 @@ struct rbd_client {
        struct list_head        node;
 };
 
+struct pending_result {
+       int                     result;         /* first nonzero result */
+       int                     num_pending;
+};
+
 struct rbd_img_request;
 
 enum obj_request_type {
@@ -219,6 +228,18 @@ enum obj_operation_type {
        OBJ_OP_ZEROOUT,
 };
 
+#define RBD_OBJ_FLAG_DELETION                  (1U << 0)
+#define RBD_OBJ_FLAG_COPYUP_ENABLED            (1U << 1)
+#define RBD_OBJ_FLAG_COPYUP_ZEROS              (1U << 2)
+#define RBD_OBJ_FLAG_MAY_EXIST                 (1U << 3)
+#define RBD_OBJ_FLAG_NOOP_FOR_NONEXISTENT      (1U << 4)
+
+enum rbd_obj_read_state {
+       RBD_OBJ_READ_START = 1,
+       RBD_OBJ_READ_OBJECT,
+       RBD_OBJ_READ_PARENT,
+};
+
 /*
  * Writes go through the following state machine to deal with
  * layering:
@@ -245,17 +266,28 @@ enum obj_operation_type {
  * even if there is a parent).
  */
 enum rbd_obj_write_state {
-       RBD_OBJ_WRITE_FLAT = 1,
-       RBD_OBJ_WRITE_GUARD,
-       RBD_OBJ_WRITE_READ_FROM_PARENT,
-       RBD_OBJ_WRITE_COPYUP_EMPTY_SNAPC,
-       RBD_OBJ_WRITE_COPYUP_OPS,
+       RBD_OBJ_WRITE_START = 1,
+       RBD_OBJ_WRITE_PRE_OBJECT_MAP,
+       RBD_OBJ_WRITE_OBJECT,
+       __RBD_OBJ_WRITE_COPYUP,
+       RBD_OBJ_WRITE_COPYUP,
+       RBD_OBJ_WRITE_POST_OBJECT_MAP,
+};
+
+enum rbd_obj_copyup_state {
+       RBD_OBJ_COPYUP_START = 1,
+       RBD_OBJ_COPYUP_READ_PARENT,
+       __RBD_OBJ_COPYUP_OBJECT_MAPS,
+       RBD_OBJ_COPYUP_OBJECT_MAPS,
+       __RBD_OBJ_COPYUP_WRITE_OBJECT,
+       RBD_OBJ_COPYUP_WRITE_OBJECT,
 };
 
 struct rbd_obj_request {
        struct ceph_object_extent ex;
+       unsigned int            flags;  /* RBD_OBJ_FLAG_* */
        union {
-               bool                    tried_parent;   /* for reads */
+               enum rbd_obj_read_state  read_state;    /* for reads */
                enum rbd_obj_write_state write_state;   /* for writes */
        };
 
@@ -271,14 +303,15 @@ struct rbd_obj_request {
                        u32                     bvec_idx;
                };
        };
+
+       enum rbd_obj_copyup_state copyup_state;
        struct bio_vec          *copyup_bvecs;
        u32                     copyup_bvec_count;
 
-       struct ceph_osd_request *osd_req;
-
-       u64                     xferred;        /* bytes transferred */
-       int                     result;
+       struct list_head        osd_reqs;       /* w/ r_private_item */
 
+       struct mutex            state_mutex;
+       struct pending_result   pending;
        struct kref             kref;
 };
 
@@ -287,11 +320,19 @@ enum img_req_flags {
        IMG_REQ_LAYERED,        /* ENOENT handling: normal = 0, layered = 1 */
 };
 
+enum rbd_img_state {
+       RBD_IMG_START = 1,
+       RBD_IMG_EXCLUSIVE_LOCK,
+       __RBD_IMG_OBJECT_REQUESTS,
+       RBD_IMG_OBJECT_REQUESTS,
+};
+
 struct rbd_img_request {
        struct rbd_device       *rbd_dev;
        enum obj_operation_type op_type;
        enum obj_request_type   data_type;
        unsigned long           flags;
+       enum rbd_img_state      state;
        union {
                u64                     snap_id;        /* for reads */
                struct ceph_snap_context *snapc;        /* for writes */
@@ -300,13 +341,14 @@ struct rbd_img_request {
                struct request          *rq;            /* block request */
                struct rbd_obj_request  *obj_request;   /* obj req initiator */
        };
-       spinlock_t              completion_lock;
-       u64                     xferred;/* aggregate bytes transferred */
-       int                     result; /* first nonzero obj_request result */
 
+       struct list_head        lock_item;
        struct list_head        object_extents; /* obj_req.ex structs */
-       u32                     pending_count;
 
+       struct mutex            state_mutex;
+       struct pending_result   pending;
+       struct work_struct      work;
+       int                     work_result;
        struct kref             kref;
 };
 
@@ -380,7 +422,17 @@ struct rbd_device {
        struct work_struct      released_lock_work;
        struct delayed_work     lock_dwork;
        struct work_struct      unlock_work;
-       wait_queue_head_t       lock_waitq;
+       spinlock_t              lock_lists_lock;
+       struct list_head        acquiring_list;
+       struct list_head        running_list;
+       struct completion       acquire_wait;
+       int                     acquire_err;
+       struct completion       releasing_wait;
+
+       spinlock_t              object_map_lock;
+       u8                      *object_map;
+       u64                     object_map_size;        /* in objects */
+       u64                     object_map_flags;
 
        struct workqueue_struct *task_wq;
 
@@ -408,12 +460,10 @@ struct rbd_device {
  * Flag bits for rbd_dev->flags:
  * - REMOVING (which is coupled with rbd_dev->open_count) is protected
  *   by rbd_dev->lock
- * - BLACKLISTED is protected by rbd_dev->lock_rwsem
  */
 enum rbd_dev_flags {
        RBD_DEV_FLAG_EXISTS,    /* mapped snapshot has not been deleted */
        RBD_DEV_FLAG_REMOVING,  /* this mapping is being removed */
-       RBD_DEV_FLAG_BLACKLISTED, /* our ceph_client is blacklisted */
 };
 
 static DEFINE_MUTEX(client_mutex);     /* Serialize client creation */
@@ -466,6 +516,8 @@ static int minor_to_rbd_dev_id(int minor)
 
 static bool __rbd_is_lock_owner(struct rbd_device *rbd_dev)
 {
+       lockdep_assert_held(&rbd_dev->lock_rwsem);
+
        return rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED ||
               rbd_dev->lock_state == RBD_LOCK_STATE_RELEASING;
 }
@@ -583,6 +635,26 @@ static int _rbd_dev_v2_snap_size(struct rbd_device *rbd_dev, u64 snap_id,
                                u8 *order, u64 *snap_size);
 static int _rbd_dev_v2_snap_features(struct rbd_device *rbd_dev, u64 snap_id,
                u64 *snap_features);
+static int rbd_dev_v2_get_flags(struct rbd_device *rbd_dev);
+
+static void rbd_obj_handle_request(struct rbd_obj_request *obj_req, int result);
+static void rbd_img_handle_request(struct rbd_img_request *img_req, int result);
+
+/*
+ * Return true if nothing else is pending.
+ */
+static bool pending_result_dec(struct pending_result *pending, int *result)
+{
+       rbd_assert(pending->num_pending > 0);
+
+       if (*result && !pending->result)
+               pending->result = *result;
+       if (--pending->num_pending)
+               return false;
+
+       *result = pending->result;
+       return true;
+}
 
 static int rbd_open(struct block_device *bdev, fmode_t mode)
 {
@@ -1317,6 +1389,8 @@ static void zero_bvecs(struct ceph_bvec_iter *bvec_pos, u32 off, u32 bytes)
 static void rbd_obj_zero_range(struct rbd_obj_request *obj_req, u32 off,
                               u32 bytes)
 {
+       dout("%s %p data buf %u~%u\n", __func__, obj_req, off, bytes);
+
        switch (obj_req->img_request->data_type) {
        case OBJ_REQUEST_BIO:
                zero_bios(&obj_req->bio_pos, off, bytes);
@@ -1339,13 +1413,6 @@ static void rbd_obj_request_put(struct rbd_obj_request *obj_request)
        kref_put(&obj_request->kref, rbd_obj_request_destroy);
 }
 
-static void rbd_img_request_get(struct rbd_img_request *img_request)
-{
-       dout("%s: img %p (was %d)\n", __func__, img_request,
-            kref_read(&img_request->kref));
-       kref_get(&img_request->kref);
-}
-
 static void rbd_img_request_destroy(struct kref *kref);
 static void rbd_img_request_put(struct rbd_img_request *img_request)
 {
@@ -1362,7 +1429,6 @@ static inline void rbd_img_obj_request_add(struct rbd_img_request *img_request,
 
        /* Image request now owns object's original reference */
        obj_request->img_request = img_request;
-       img_request->pending_count++;
        dout("%s: img %p obj %p\n", __func__, img_request, obj_request);
 }
 
@@ -1375,13 +1441,13 @@ static inline void rbd_img_obj_request_del(struct rbd_img_request *img_request,
        rbd_obj_request_put(obj_request);
 }
 
-static void rbd_obj_request_submit(struct rbd_obj_request *obj_request)
+static void rbd_osd_submit(struct ceph_osd_request *osd_req)
 {
-       struct ceph_osd_request *osd_req = obj_request->osd_req;
+       struct rbd_obj_request *obj_req = osd_req->r_priv;
 
-       dout("%s %p object_no %016llx %llu~%llu osd_req %p\n", __func__,
-            obj_request, obj_request->ex.oe_objno, obj_request->ex.oe_off,
-            obj_request->ex.oe_len, osd_req);
+       dout("%s osd_req %p for obj_req %p objno %llu %llu~%llu\n",
+            __func__, osd_req, obj_req, obj_req->ex.oe_objno,
+            obj_req->ex.oe_off, obj_req->ex.oe_len);
        ceph_osdc_start_request(osd_req->r_osdc, osd_req, false);
 }
 
@@ -1457,41 +1523,38 @@ static bool rbd_img_is_write(struct rbd_img_request *img_req)
        }
 }
 
-static void rbd_obj_handle_request(struct rbd_obj_request *obj_req);
-
 static void rbd_osd_req_callback(struct ceph_osd_request *osd_req)
 {
        struct rbd_obj_request *obj_req = osd_req->r_priv;
+       int result;
 
        dout("%s osd_req %p result %d for obj_req %p\n", __func__, osd_req,
             osd_req->r_result, obj_req);
-       rbd_assert(osd_req == obj_req->osd_req);
 
-       obj_req->result = osd_req->r_result < 0 ? osd_req->r_result : 0;
-       if (!obj_req->result && !rbd_img_is_write(obj_req->img_request))
-               obj_req->xferred = osd_req->r_result;
+       /*
+        * Writes aren't allowed to return a data payload.  In some
+        * guarded write cases (e.g. stat + zero on an empty object)
+        * a stat response makes it through, but we don't care.
+        */
+       if (osd_req->r_result > 0 && rbd_img_is_write(obj_req->img_request))
+               result = 0;
        else
-               /*
-                * Writes aren't allowed to return a data payload.  In some
-                * guarded write cases (e.g. stat + zero on an empty object)
-                * a stat response makes it through, but we don't care.
-                */
-               obj_req->xferred = 0;
+               result = osd_req->r_result;
 
-       rbd_obj_handle_request(obj_req);
+       rbd_obj_handle_request(obj_req, result);
 }
 
-static void rbd_osd_req_format_read(struct rbd_obj_request *obj_request)
+static void rbd_osd_format_read(struct ceph_osd_request *osd_req)
 {
-       struct ceph_osd_request *osd_req = obj_request->osd_req;
+       struct rbd_obj_request *obj_request = osd_req->r_priv;
 
        osd_req->r_flags = CEPH_OSD_FLAG_READ;
        osd_req->r_snapid = obj_request->img_request->snap_id;
 }
 
-static void rbd_osd_req_format_write(struct rbd_obj_request *obj_request)
+static void rbd_osd_format_write(struct ceph_osd_request *osd_req)
 {
-       struct ceph_osd_request *osd_req = obj_request->osd_req;
+       struct rbd_obj_request *obj_request = osd_req->r_priv;
 
        osd_req->r_flags = CEPH_OSD_FLAG_WRITE;
        ktime_get_real_ts64(&osd_req->r_mtime);
@@ -1499,19 +1562,21 @@ static void rbd_osd_req_format_write(struct rbd_obj_request *obj_request)
 }
 
 static struct ceph_osd_request *
-__rbd_osd_req_create(struct rbd_obj_request *obj_req,
-                    struct ceph_snap_context *snapc, unsigned int num_ops)
+__rbd_obj_add_osd_request(struct rbd_obj_request *obj_req,
+                         struct ceph_snap_context *snapc, int num_ops)
 {
        struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
        struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
        struct ceph_osd_request *req;
        const char *name_format = rbd_dev->image_format == 1 ?
                                      RBD_V1_DATA_FORMAT : RBD_V2_DATA_FORMAT;
+       int ret;
 
        req = ceph_osdc_alloc_request(osdc, snapc, num_ops, false, GFP_NOIO);
        if (!req)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
+       list_add_tail(&req->r_private_item, &obj_req->osd_reqs);
        req->r_callback = rbd_osd_req_callback;
        req->r_priv = obj_req;
 
@@ -1522,27 +1587,20 @@ __rbd_osd_req_create(struct rbd_obj_request *obj_req,
        ceph_oloc_copy(&req->r_base_oloc, &rbd_dev->header_oloc);
        req->r_base_oloc.pool = rbd_dev->layout.pool_id;
 
-       if (ceph_oid_aprintf(&req->r_base_oid, GFP_NOIO, name_format,
-                       rbd_dev->header.object_prefix, obj_req->ex.oe_objno))
-               goto err_req;
+       ret = ceph_oid_aprintf(&req->r_base_oid, GFP_NOIO, name_format,
+                              rbd_dev->header.object_prefix,
+                              obj_req->ex.oe_objno);
+       if (ret)
+               return ERR_PTR(ret);
 
        return req;
-
-err_req:
-       ceph_osdc_put_request(req);
-       return NULL;
 }
 
 static struct ceph_osd_request *
-rbd_osd_req_create(struct rbd_obj_request *obj_req, unsigned int num_ops)
-{
-       return __rbd_osd_req_create(obj_req, obj_req->img_request->snapc,
-                                   num_ops);
-}
-
-static void rbd_osd_req_destroy(struct ceph_osd_request *osd_req)
+rbd_obj_add_osd_request(struct rbd_obj_request *obj_req, int num_ops)
 {
-       ceph_osdc_put_request(osd_req);
+       return __rbd_obj_add_osd_request(obj_req, obj_req->img_request->snapc,
+                                        num_ops);
 }
 
 static struct rbd_obj_request *rbd_obj_request_create(void)
@@ -1554,6 +1612,8 @@ static struct rbd_obj_request *rbd_obj_request_create(void)
                return NULL;
 
        ceph_object_extent_init(&obj_request->ex);
+       INIT_LIST_HEAD(&obj_request->osd_reqs);
+       mutex_init(&obj_request->state_mutex);
        kref_init(&obj_request->kref);
 
        dout("%s %p\n", __func__, obj_request);
@@ -1563,14 +1623,19 @@ static struct rbd_obj_request *rbd_obj_request_create(void)
 static void rbd_obj_request_destroy(struct kref *kref)
 {
        struct rbd_obj_request *obj_request;
+       struct ceph_osd_request *osd_req;
        u32 i;
 
        obj_request = container_of(kref, struct rbd_obj_request, kref);
 
        dout("%s: obj %p\n", __func__, obj_request);
 
-       if (obj_request->osd_req)
-               rbd_osd_req_destroy(obj_request->osd_req);
+       while (!list_empty(&obj_request->osd_reqs)) {
+               osd_req = list_first_entry(&obj_request->osd_reqs,
+                                   struct ceph_osd_request, r_private_item);
+               list_del_init(&osd_req->r_private_item);
+               ceph_osdc_put_request(osd_req);
+       }
 
        switch (obj_request->img_request->data_type) {
        case OBJ_REQUEST_NODATA:
@@ -1684,8 +1749,9 @@ static struct rbd_img_request *rbd_img_request_create(
        if (rbd_dev_parent_get(rbd_dev))
                img_request_layered_set(img_request);
 
-       spin_lock_init(&img_request->completion_lock);
+       INIT_LIST_HEAD(&img_request->lock_item);
        INIT_LIST_HEAD(&img_request->object_extents);
+       mutex_init(&img_request->state_mutex);
        kref_init(&img_request->kref);
 
        dout("%s: rbd_dev %p %s -> img %p\n", __func__, rbd_dev,
@@ -1703,6 +1769,7 @@ static void rbd_img_request_destroy(struct kref *kref)
 
        dout("%s: img %p\n", __func__, img_request);
 
+       WARN_ON(!list_empty(&img_request->lock_item));
        for_each_obj_request_safe(img_request, obj_request, next_obj_request)
                rbd_img_obj_request_del(img_request, obj_request);
 
@@ -1717,304 +1784,781 @@ static void rbd_img_request_destroy(struct kref *kref)
        kmem_cache_free(rbd_img_request_cache, img_request);
 }
 
-static void prune_extents(struct ceph_file_extent *img_extents,
-                         u32 *num_img_extents, u64 overlap)
-{
-       u32 cnt = *num_img_extents;
+#define BITS_PER_OBJ   2
+#define OBJS_PER_BYTE  (BITS_PER_BYTE / BITS_PER_OBJ)
+#define OBJ_MASK       ((1 << BITS_PER_OBJ) - 1)
 
-       /* drop extents completely beyond the overlap */
-       while (cnt && img_extents[cnt - 1].fe_off >= overlap)
-               cnt--;
+static void __rbd_object_map_index(struct rbd_device *rbd_dev, u64 objno,
+                                  u64 *index, u8 *shift)
+{
+       u32 off;
 
-       if (cnt) {
-               struct ceph_file_extent *ex = &img_extents[cnt - 1];
+       rbd_assert(objno < rbd_dev->object_map_size);
+       *index = div_u64_rem(objno, OBJS_PER_BYTE, &off);
+       *shift = (OBJS_PER_BYTE - off - 1) * BITS_PER_OBJ;
+}
 
-               /* trim final overlapping extent */
-               if (ex->fe_off + ex->fe_len > overlap)
-                       ex->fe_len = overlap - ex->fe_off;
-       }
+static u8 __rbd_object_map_get(struct rbd_device *rbd_dev, u64 objno)
+{
+       u64 index;
+       u8 shift;
 
-       *num_img_extents = cnt;
+       lockdep_assert_held(&rbd_dev->object_map_lock);
+       __rbd_object_map_index(rbd_dev, objno, &index, &shift);
+       return (rbd_dev->object_map[index] >> shift) & OBJ_MASK;
 }
 
-/*
- * Determine the byte range(s) covered by either just the object extent
- * or the entire object in the parent image.
- */
-static int rbd_obj_calc_img_extents(struct rbd_obj_request *obj_req,
-                                   bool entire)
+static void __rbd_object_map_set(struct rbd_device *rbd_dev, u64 objno, u8 val)
 {
-       struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
-       int ret;
-
-       if (!rbd_dev->parent_overlap)
-               return 0;
+       u64 index;
+       u8 shift;
+       u8 *p;
 
-       ret = ceph_extent_to_file(&rbd_dev->layout, obj_req->ex.oe_objno,
-                                 entire ? 0 : obj_req->ex.oe_off,
-                                 entire ? rbd_dev->layout.object_size :
-                                                       obj_req->ex.oe_len,
-                                 &obj_req->img_extents,
-                                 &obj_req->num_img_extents);
-       if (ret)
-               return ret;
+       lockdep_assert_held(&rbd_dev->object_map_lock);
+       rbd_assert(!(val & ~OBJ_MASK));
 
-       prune_extents(obj_req->img_extents, &obj_req->num_img_extents,
-                     rbd_dev->parent_overlap);
-       return 0;
+       __rbd_object_map_index(rbd_dev, objno, &index, &shift);
+       p = &rbd_dev->object_map[index];
+       *p = (*p & ~(OBJ_MASK << shift)) | (val << shift);
 }
 
-static void rbd_osd_req_setup_data(struct rbd_obj_request *obj_req, u32 which)
+static u8 rbd_object_map_get(struct rbd_device *rbd_dev, u64 objno)
 {
-       switch (obj_req->img_request->data_type) {
-       case OBJ_REQUEST_BIO:
-               osd_req_op_extent_osd_data_bio(obj_req->osd_req, which,
-                                              &obj_req->bio_pos,
-                                              obj_req->ex.oe_len);
-               break;
-       case OBJ_REQUEST_BVECS:
-       case OBJ_REQUEST_OWN_BVECS:
-               rbd_assert(obj_req->bvec_pos.iter.bi_size ==
-                                                       obj_req->ex.oe_len);
-               rbd_assert(obj_req->bvec_idx == obj_req->bvec_count);
-               osd_req_op_extent_osd_data_bvec_pos(obj_req->osd_req, which,
-                                                   &obj_req->bvec_pos);
-               break;
-       default:
-               BUG();
-       }
+       u8 state;
+
+       spin_lock(&rbd_dev->object_map_lock);
+       state = __rbd_object_map_get(rbd_dev, objno);
+       spin_unlock(&rbd_dev->object_map_lock);
+       return state;
 }
 
-static int rbd_obj_setup_read(struct rbd_obj_request *obj_req)
+static bool use_object_map(struct rbd_device *rbd_dev)
 {
-       obj_req->osd_req = __rbd_osd_req_create(obj_req, NULL, 1);
-       if (!obj_req->osd_req)
-               return -ENOMEM;
-
-       osd_req_op_extent_init(obj_req->osd_req, 0, CEPH_OSD_OP_READ,
-                              obj_req->ex.oe_off, obj_req->ex.oe_len, 0, 0);
-       rbd_osd_req_setup_data(obj_req, 0);
-
-       rbd_osd_req_format_read(obj_req);
-       return 0;
+       return ((rbd_dev->header.features & RBD_FEATURE_OBJECT_MAP) &&
+               !(rbd_dev->object_map_flags & RBD_FLAG_OBJECT_MAP_INVALID));
 }
 
-static int __rbd_obj_setup_stat(struct rbd_obj_request *obj_req,
-                               unsigned int which)
+static bool rbd_object_map_may_exist(struct rbd_device *rbd_dev, u64 objno)
 {
-       struct page **pages;
+       u8 state;
 
-       /*
-        * The response data for a STAT call consists of:
-        *     le64 length;
-        *     struct {
-        *         le32 tv_sec;
-        *         le32 tv_nsec;
-        *     } mtime;
-        */
-       pages = ceph_alloc_page_vector(1, GFP_NOIO);
-       if (IS_ERR(pages))
-               return PTR_ERR(pages);
+       /* fall back to default logic if object map is disabled or invalid */
+       if (!use_object_map(rbd_dev))
+               return true;
 
-       osd_req_op_init(obj_req->osd_req, which, CEPH_OSD_OP_STAT, 0);
-       osd_req_op_raw_data_in_pages(obj_req->osd_req, which, pages,
-                                    8 + sizeof(struct ceph_timespec),
-                                    0, false, true);
-       return 0;
+       state = rbd_object_map_get(rbd_dev, objno);
+       return state != OBJECT_NONEXISTENT;
 }
 
-static int count_write_ops(struct rbd_obj_request *obj_req)
+static void rbd_object_map_name(struct rbd_device *rbd_dev, u64 snap_id,
+                               struct ceph_object_id *oid)
 {
-       return 2; /* setallochint + write/writefull */
+       if (snap_id == CEPH_NOSNAP)
+               ceph_oid_printf(oid, "%s%s", RBD_OBJECT_MAP_PREFIX,
+                               rbd_dev->spec->image_id);
+       else
+               ceph_oid_printf(oid, "%s%s.%016llx", RBD_OBJECT_MAP_PREFIX,
+                               rbd_dev->spec->image_id, snap_id);
 }
 
-static void __rbd_obj_setup_write(struct rbd_obj_request *obj_req,
-                                 unsigned int which)
+static int rbd_object_map_lock(struct rbd_device *rbd_dev)
 {
-       struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
-       u16 opcode;
-
-       osd_req_op_alloc_hint_init(obj_req->osd_req, which++,
-                                  rbd_dev->layout.object_size,
-                                  rbd_dev->layout.object_size);
-
-       if (rbd_obj_is_entire(obj_req))
-               opcode = CEPH_OSD_OP_WRITEFULL;
-       else
-               opcode = CEPH_OSD_OP_WRITE;
+       struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
+       CEPH_DEFINE_OID_ONSTACK(oid);
+       u8 lock_type;
+       char *lock_tag;
+       struct ceph_locker *lockers;
+       u32 num_lockers;
+       bool broke_lock = false;
+       int ret;
 
-       osd_req_op_extent_init(obj_req->osd_req, which, opcode,
-                              obj_req->ex.oe_off, obj_req->ex.oe_len, 0, 0);
-       rbd_osd_req_setup_data(obj_req, which++);
+       rbd_object_map_name(rbd_dev, CEPH_NOSNAP, &oid);
 
-       rbd_assert(which == obj_req->osd_req->r_num_ops);
-       rbd_osd_req_format_write(obj_req);
-}
+again:
+       ret = ceph_cls_lock(osdc, &oid, &rbd_dev->header_oloc, RBD_LOCK_NAME,
+                           CEPH_CLS_LOCK_EXCLUSIVE, "", "", "", 0);
+       if (ret != -EBUSY || broke_lock) {
+               if (ret == -EEXIST)
+                       ret = 0; /* already locked by myself */
+               if (ret)
+                       rbd_warn(rbd_dev, "failed to lock object map: %d", ret);
+               return ret;
+       }
 
-static int rbd_obj_setup_write(struct rbd_obj_request *obj_req)
-{
-       unsigned int num_osd_ops, which = 0;
-       bool need_guard;
-       int ret;
+       ret = ceph_cls_lock_info(osdc, &oid, &rbd_dev->header_oloc,
+                                RBD_LOCK_NAME, &lock_type, &lock_tag,
+                                &lockers, &num_lockers);
+       if (ret) {
+               if (ret == -ENOENT)
+                       goto again;
 
-       /* reverse map the entire object onto the parent */
-       ret = rbd_obj_calc_img_extents(obj_req, true);
-       if (ret)
+               rbd_warn(rbd_dev, "failed to get object map lockers: %d", ret);
                return ret;
+       }
 
-       need_guard = rbd_obj_copyup_enabled(obj_req);
-       num_osd_ops = need_guard + count_write_ops(obj_req);
+       kfree(lock_tag);
+       if (num_lockers == 0)
+               goto again;
 
-       obj_req->osd_req = rbd_osd_req_create(obj_req, num_osd_ops);
-       if (!obj_req->osd_req)
-               return -ENOMEM;
+       rbd_warn(rbd_dev, "breaking object map lock owned by %s%llu",
+                ENTITY_NAME(lockers[0].id.name));
 
-       if (need_guard) {
-               ret = __rbd_obj_setup_stat(obj_req, which++);
-               if (ret)
-                       return ret;
+       ret = ceph_cls_break_lock(osdc, &oid, &rbd_dev->header_oloc,
+                                 RBD_LOCK_NAME, lockers[0].id.cookie,
+                                 &lockers[0].id.name);
+       ceph_free_lockers(lockers, num_lockers);
+       if (ret) {
+               if (ret == -ENOENT)
+                       goto again;
 
-               obj_req->write_state = RBD_OBJ_WRITE_GUARD;
-       } else {
-               obj_req->write_state = RBD_OBJ_WRITE_FLAT;
+               rbd_warn(rbd_dev, "failed to break object map lock: %d", ret);
+               return ret;
        }
 
-       __rbd_obj_setup_write(obj_req, which);
-       return 0;
+       broke_lock = true;
+       goto again;
 }
 
-static u16 truncate_or_zero_opcode(struct rbd_obj_request *obj_req)
+static void rbd_object_map_unlock(struct rbd_device *rbd_dev)
 {
-       return rbd_obj_is_tail(obj_req) ? CEPH_OSD_OP_TRUNCATE :
-                                         CEPH_OSD_OP_ZERO;
+       struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
+       CEPH_DEFINE_OID_ONSTACK(oid);
+       int ret;
+
+       rbd_object_map_name(rbd_dev, CEPH_NOSNAP, &oid);
+
+       ret = ceph_cls_unlock(osdc, &oid, &rbd_dev->header_oloc, RBD_LOCK_NAME,
+                             "");
+       if (ret && ret != -ENOENT)
+               rbd_warn(rbd_dev, "failed to unlock object map: %d", ret);
 }
 
-static int rbd_obj_setup_discard(struct rbd_obj_request *obj_req)
+static int decode_object_map_header(void **p, void *end, u64 *object_map_size)
 {
-       struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
-       u64 off = obj_req->ex.oe_off;
-       u64 next_off = obj_req->ex.oe_off + obj_req->ex.oe_len;
+       u8 struct_v;
+       u32 struct_len;
+       u32 header_len;
+       void *header_end;
        int ret;
 
-       /*
-        * Align the range to alloc_size boundary and punt on discards
-        * that are too small to free up any space.
-        *
-        * alloc_size == object_size && is_tail() is a special case for
-        * filestore with filestore_punch_hole = false, needed to allow
-        * truncate (in addition to delete).
-        */
-       if (rbd_dev->opts->alloc_size != rbd_dev->layout.object_size ||
-           !rbd_obj_is_tail(obj_req)) {
-               off = round_up(off, rbd_dev->opts->alloc_size);
-               next_off = round_down(next_off, rbd_dev->opts->alloc_size);
-               if (off >= next_off)
-                       return 1;
-       }
+       ceph_decode_32_safe(p, end, header_len, e_inval);
+       header_end = *p + header_len;
 
-       /* reverse map the entire object onto the parent */
-       ret = rbd_obj_calc_img_extents(obj_req, true);
+       ret = ceph_start_decoding(p, end, 1, "BitVector header", &struct_v,
+                                 &struct_len);
        if (ret)
                return ret;
 
-       obj_req->osd_req = rbd_osd_req_create(obj_req, 1);
-       if (!obj_req->osd_req)
-               return -ENOMEM;
-
-       if (rbd_obj_is_entire(obj_req) && !obj_req->num_img_extents) {
-               osd_req_op_init(obj_req->osd_req, 0, CEPH_OSD_OP_DELETE, 0);
-       } else {
-               dout("%s %p %llu~%llu -> %llu~%llu\n", __func__,
-                    obj_req, obj_req->ex.oe_off, obj_req->ex.oe_len,
-                    off, next_off - off);
-               osd_req_op_extent_init(obj_req->osd_req, 0,
-                                      truncate_or_zero_opcode(obj_req),
-                                      off, next_off - off, 0, 0);
-       }
+       ceph_decode_64_safe(p, end, *object_map_size, e_inval);
 
-       obj_req->write_state = RBD_OBJ_WRITE_FLAT;
-       rbd_osd_req_format_write(obj_req);
+       *p = header_end;
        return 0;
+
+e_inval:
+       return -EINVAL;
 }
 
-static int count_zeroout_ops(struct rbd_obj_request *obj_req)
+static int __rbd_object_map_load(struct rbd_device *rbd_dev)
 {
-       int num_osd_ops;
+       struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
+       CEPH_DEFINE_OID_ONSTACK(oid);
+       struct page **pages;
+       void *p, *end;
+       size_t reply_len;
+       u64 num_objects;
+       u64 object_map_bytes;
+       u64 object_map_size;
+       int num_pages;
+       int ret;
 
-       if (rbd_obj_is_entire(obj_req) && obj_req->num_img_extents &&
-           !rbd_obj_copyup_enabled(obj_req))
-               num_osd_ops = 2; /* create + truncate */
-       else
-               num_osd_ops = 1; /* delete/truncate/zero */
+       rbd_assert(!rbd_dev->object_map && !rbd_dev->object_map_size);
 
-       return num_osd_ops;
-}
+       num_objects = ceph_get_num_objects(&rbd_dev->layout,
+                                          rbd_dev->mapping.size);
+       object_map_bytes = DIV_ROUND_UP_ULL(num_objects * BITS_PER_OBJ,
+                                           BITS_PER_BYTE);
+       num_pages = calc_pages_for(0, object_map_bytes) + 1;
+       pages = ceph_alloc_page_vector(num_pages, GFP_KERNEL);
+       if (IS_ERR(pages))
+               return PTR_ERR(pages);
 
-static void __rbd_obj_setup_zeroout(struct rbd_obj_request *obj_req,
-                                   unsigned int which)
-{
-       u16 opcode;
+       reply_len = num_pages * PAGE_SIZE;
+       rbd_object_map_name(rbd_dev, rbd_dev->spec->snap_id, &oid);
+       ret = ceph_osdc_call(osdc, &oid, &rbd_dev->header_oloc,
+                            "rbd", "object_map_load", CEPH_OSD_FLAG_READ,
+                            NULL, 0, pages, &reply_len);
+       if (ret)
+               goto out;
 
-       if (rbd_obj_is_entire(obj_req)) {
-               if (obj_req->num_img_extents) {
-                       if (!rbd_obj_copyup_enabled(obj_req))
-                               osd_req_op_init(obj_req->osd_req, which++,
-                                               CEPH_OSD_OP_CREATE, 0);
-                       opcode = CEPH_OSD_OP_TRUNCATE;
-               } else {
-                       osd_req_op_init(obj_req->osd_req, which++,
-                                       CEPH_OSD_OP_DELETE, 0);
-                       opcode = 0;
-               }
-       } else {
-               opcode = truncate_or_zero_opcode(obj_req);
+       p = page_address(pages[0]);
+       end = p + min(reply_len, (size_t)PAGE_SIZE);
+       ret = decode_object_map_header(&p, end, &object_map_size);
+       if (ret)
+               goto out;
+
+       if (object_map_size != num_objects) {
+               rbd_warn(rbd_dev, "object map size mismatch: %llu vs %llu",
+                        object_map_size, num_objects);
+               ret = -EINVAL;
+               goto out;
        }
 
-       if (opcode)
-               osd_req_op_extent_init(obj_req->osd_req, which++, opcode,
-                                      obj_req->ex.oe_off, obj_req->ex.oe_len,
-                                      0, 0);
+       if (offset_in_page(p) + object_map_bytes > reply_len) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       rbd_dev->object_map = kvmalloc(object_map_bytes, GFP_KERNEL);
+       if (!rbd_dev->object_map) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       rbd_dev->object_map_size = object_map_size;
+       ceph_copy_from_page_vector(pages, rbd_dev->object_map,
+                                  offset_in_page(p), object_map_bytes);
+
+out:
+       ceph_release_page_vector(pages, num_pages);
+       return ret;
+}
 
-       rbd_assert(which == obj_req->osd_req->r_num_ops);
-       rbd_osd_req_format_write(obj_req);
+static void rbd_object_map_free(struct rbd_device *rbd_dev)
+{
+       kvfree(rbd_dev->object_map);
+       rbd_dev->object_map = NULL;
+       rbd_dev->object_map_size = 0;
 }
 
-static int rbd_obj_setup_zeroout(struct rbd_obj_request *obj_req)
+static int rbd_object_map_load(struct rbd_device *rbd_dev)
 {
-       unsigned int num_osd_ops, which = 0;
-       bool need_guard;
        int ret;
 
-       /* reverse map the entire object onto the parent */
-       ret = rbd_obj_calc_img_extents(obj_req, true);
+       ret = __rbd_object_map_load(rbd_dev);
        if (ret)
                return ret;
 
-       need_guard = rbd_obj_copyup_enabled(obj_req);
-       num_osd_ops = need_guard + count_zeroout_ops(obj_req);
-
-       obj_req->osd_req = rbd_osd_req_create(obj_req, num_osd_ops);
-       if (!obj_req->osd_req)
-               return -ENOMEM;
+       ret = rbd_dev_v2_get_flags(rbd_dev);
+       if (ret) {
+               rbd_object_map_free(rbd_dev);
+               return ret;
+       }
+
+       if (rbd_dev->object_map_flags & RBD_FLAG_OBJECT_MAP_INVALID)
+               rbd_warn(rbd_dev, "object map is invalid");
+
+       return 0;
+}
+
+static int rbd_object_map_open(struct rbd_device *rbd_dev)
+{
+       int ret;
+
+       ret = rbd_object_map_lock(rbd_dev);
+       if (ret)
+               return ret;
+
+       ret = rbd_object_map_load(rbd_dev);
+       if (ret) {
+               rbd_object_map_unlock(rbd_dev);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void rbd_object_map_close(struct rbd_device *rbd_dev)
+{
+       rbd_object_map_free(rbd_dev);
+       rbd_object_map_unlock(rbd_dev);
+}
+
+/*
+ * This function needs snap_id (or more precisely just something to
+ * distinguish between HEAD and snapshot object maps), new_state and
+ * current_state that were passed to rbd_object_map_update().
+ *
+ * To avoid allocating and stashing a context we piggyback on the OSD
+ * request.  A HEAD update has two ops (assert_locked).  For new_state
+ * and current_state we decode our own object_map_update op, encoded in
+ * rbd_cls_object_map_update().
+ */
+static int rbd_object_map_update_finish(struct rbd_obj_request *obj_req,
+                                       struct ceph_osd_request *osd_req)
+{
+       struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
+       struct ceph_osd_data *osd_data;
+       u64 objno;
+       u8 state, new_state, current_state;
+       bool has_current_state;
+       void *p;
+
+       if (osd_req->r_result)
+               return osd_req->r_result;
+
+       /*
+        * Nothing to do for a snapshot object map.
+        */
+       if (osd_req->r_num_ops == 1)
+               return 0;
+
+       /*
+        * Update in-memory HEAD object map.
+        */
+       rbd_assert(osd_req->r_num_ops == 2);
+       osd_data = osd_req_op_data(osd_req, 1, cls, request_data);
+       rbd_assert(osd_data->type == CEPH_OSD_DATA_TYPE_PAGES);
+
+       p = page_address(osd_data->pages[0]);
+       objno = ceph_decode_64(&p);
+       rbd_assert(objno == obj_req->ex.oe_objno);
+       rbd_assert(ceph_decode_64(&p) == objno + 1);
+       new_state = ceph_decode_8(&p);
+       has_current_state = ceph_decode_8(&p);
+       if (has_current_state)
+               current_state = ceph_decode_8(&p);
+
+       spin_lock(&rbd_dev->object_map_lock);
+       state = __rbd_object_map_get(rbd_dev, objno);
+       if (!has_current_state || current_state == state ||
+           (current_state == OBJECT_EXISTS && state == OBJECT_EXISTS_CLEAN))
+               __rbd_object_map_set(rbd_dev, objno, new_state);
+       spin_unlock(&rbd_dev->object_map_lock);
+
+       return 0;
+}
+
+static void rbd_object_map_callback(struct ceph_osd_request *osd_req)
+{
+       struct rbd_obj_request *obj_req = osd_req->r_priv;
+       int result;
+
+       dout("%s osd_req %p result %d for obj_req %p\n", __func__, osd_req,
+            osd_req->r_result, obj_req);
+
+       result = rbd_object_map_update_finish(obj_req, osd_req);
+       rbd_obj_handle_request(obj_req, result);
+}
+
+static bool update_needed(struct rbd_device *rbd_dev, u64 objno, u8 new_state)
+{
+       u8 state = rbd_object_map_get(rbd_dev, objno);
 
-       if (need_guard) {
-               ret = __rbd_obj_setup_stat(obj_req, which++);
+       if (state == new_state ||
+           (new_state == OBJECT_PENDING && state == OBJECT_NONEXISTENT) ||
+           (new_state == OBJECT_NONEXISTENT && state != OBJECT_PENDING))
+               return false;
+
+       return true;
+}
+
+static int rbd_cls_object_map_update(struct ceph_osd_request *req,
+                                    int which, u64 objno, u8 new_state,
+                                    const u8 *current_state)
+{
+       struct page **pages;
+       void *p, *start;
+       int ret;
+
+       ret = osd_req_op_cls_init(req, which, "rbd", "object_map_update");
+       if (ret)
+               return ret;
+
+       pages = ceph_alloc_page_vector(1, GFP_NOIO);
+       if (IS_ERR(pages))
+               return PTR_ERR(pages);
+
+       p = start = page_address(pages[0]);
+       ceph_encode_64(&p, objno);
+       ceph_encode_64(&p, objno + 1);
+       ceph_encode_8(&p, new_state);
+       if (current_state) {
+               ceph_encode_8(&p, 1);
+               ceph_encode_8(&p, *current_state);
+       } else {
+               ceph_encode_8(&p, 0);
+       }
+
+       osd_req_op_cls_request_data_pages(req, which, pages, p - start, 0,
+                                         false, true);
+       return 0;
+}
+
+/*
+ * Return:
+ *   0 - object map update sent
+ *   1 - object map update isn't needed
+ *  <0 - error
+ */
+static int rbd_object_map_update(struct rbd_obj_request *obj_req, u64 snap_id,
+                                u8 new_state, const u8 *current_state)
+{
+       struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
+       struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
+       struct ceph_osd_request *req;
+       int num_ops = 1;
+       int which = 0;
+       int ret;
+
+       if (snap_id == CEPH_NOSNAP) {
+               if (!update_needed(rbd_dev, obj_req->ex.oe_objno, new_state))
+                       return 1;
+
+               num_ops++; /* assert_locked */
+       }
+
+       req = ceph_osdc_alloc_request(osdc, NULL, num_ops, false, GFP_NOIO);
+       if (!req)
+               return -ENOMEM;
+
+       list_add_tail(&req->r_private_item, &obj_req->osd_reqs);
+       req->r_callback = rbd_object_map_callback;
+       req->r_priv = obj_req;
+
+       rbd_object_map_name(rbd_dev, snap_id, &req->r_base_oid);
+       ceph_oloc_copy(&req->r_base_oloc, &rbd_dev->header_oloc);
+       req->r_flags = CEPH_OSD_FLAG_WRITE;
+       ktime_get_real_ts64(&req->r_mtime);
+
+       if (snap_id == CEPH_NOSNAP) {
+               /*
+                * Protect against possible race conditions during lock
+                * ownership transitions.
+                */
+               ret = ceph_cls_assert_locked(req, which++, RBD_LOCK_NAME,
+                                            CEPH_CLS_LOCK_EXCLUSIVE, "", "");
                if (ret)
                        return ret;
+       }
+
+       ret = rbd_cls_object_map_update(req, which, obj_req->ex.oe_objno,
+                                       new_state, current_state);
+       if (ret)
+               return ret;
+
+       ret = ceph_osdc_alloc_messages(req, GFP_NOIO);
+       if (ret)
+               return ret;
 
-               obj_req->write_state = RBD_OBJ_WRITE_GUARD;
+       ceph_osdc_start_request(osdc, req, false);
+       return 0;
+}
+
+static void prune_extents(struct ceph_file_extent *img_extents,
+                         u32 *num_img_extents, u64 overlap)
+{
+       u32 cnt = *num_img_extents;
+
+       /* drop extents completely beyond the overlap */
+       while (cnt && img_extents[cnt - 1].fe_off >= overlap)
+               cnt--;
+
+       if (cnt) {
+               struct ceph_file_extent *ex = &img_extents[cnt - 1];
+
+               /* trim final overlapping extent */
+               if (ex->fe_off + ex->fe_len > overlap)
+                       ex->fe_len = overlap - ex->fe_off;
+       }
+
+       *num_img_extents = cnt;
+}
+
+/*
+ * Determine the byte range(s) covered by either just the object extent
+ * or the entire object in the parent image.
+ */
+static int rbd_obj_calc_img_extents(struct rbd_obj_request *obj_req,
+                                   bool entire)
+{
+       struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
+       int ret;
+
+       if (!rbd_dev->parent_overlap)
+               return 0;
+
+       ret = ceph_extent_to_file(&rbd_dev->layout, obj_req->ex.oe_objno,
+                                 entire ? 0 : obj_req->ex.oe_off,
+                                 entire ? rbd_dev->layout.object_size :
+                                                       obj_req->ex.oe_len,
+                                 &obj_req->img_extents,
+                                 &obj_req->num_img_extents);
+       if (ret)
+               return ret;
+
+       prune_extents(obj_req->img_extents, &obj_req->num_img_extents,
+                     rbd_dev->parent_overlap);
+       return 0;
+}
+
+static void rbd_osd_setup_data(struct ceph_osd_request *osd_req, int which)
+{
+       struct rbd_obj_request *obj_req = osd_req->r_priv;
+
+       switch (obj_req->img_request->data_type) {
+       case OBJ_REQUEST_BIO:
+               osd_req_op_extent_osd_data_bio(osd_req, which,
+                                              &obj_req->bio_pos,
+                                              obj_req->ex.oe_len);
+               break;
+       case OBJ_REQUEST_BVECS:
+       case OBJ_REQUEST_OWN_BVECS:
+               rbd_assert(obj_req->bvec_pos.iter.bi_size ==
+                                                       obj_req->ex.oe_len);
+               rbd_assert(obj_req->bvec_idx == obj_req->bvec_count);
+               osd_req_op_extent_osd_data_bvec_pos(osd_req, which,
+                                                   &obj_req->bvec_pos);
+               break;
+       default:
+               BUG();
+       }
+}
+
+static int rbd_osd_setup_stat(struct ceph_osd_request *osd_req, int which)
+{
+       struct page **pages;
+
+       /*
+        * The response data for a STAT call consists of:
+        *     le64 length;
+        *     struct {
+        *         le32 tv_sec;
+        *         le32 tv_nsec;
+        *     } mtime;
+        */
+       pages = ceph_alloc_page_vector(1, GFP_NOIO);
+       if (IS_ERR(pages))
+               return PTR_ERR(pages);
+
+       osd_req_op_init(osd_req, which, CEPH_OSD_OP_STAT, 0);
+       osd_req_op_raw_data_in_pages(osd_req, which, pages,
+                                    8 + sizeof(struct ceph_timespec),
+                                    0, false, true);
+       return 0;
+}
+
+static int rbd_osd_setup_copyup(struct ceph_osd_request *osd_req, int which,
+                               u32 bytes)
+{
+       struct rbd_obj_request *obj_req = osd_req->r_priv;
+       int ret;
+
+       ret = osd_req_op_cls_init(osd_req, which, "rbd", "copyup");
+       if (ret)
+               return ret;
+
+       osd_req_op_cls_request_data_bvecs(osd_req, which, obj_req->copyup_bvecs,
+                                         obj_req->copyup_bvec_count, bytes);
+       return 0;
+}
+
+static int rbd_obj_init_read(struct rbd_obj_request *obj_req)
+{
+       obj_req->read_state = RBD_OBJ_READ_START;
+       return 0;
+}
+
+static void __rbd_osd_setup_write_ops(struct ceph_osd_request *osd_req,
+                                     int which)
+{
+       struct rbd_obj_request *obj_req = osd_req->r_priv;
+       struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
+       u16 opcode;
+
+       if (!use_object_map(rbd_dev) ||
+           !(obj_req->flags & RBD_OBJ_FLAG_MAY_EXIST)) {
+               osd_req_op_alloc_hint_init(osd_req, which++,
+                                          rbd_dev->layout.object_size,
+                                          rbd_dev->layout.object_size);
+       }
+
+       if (rbd_obj_is_entire(obj_req))
+               opcode = CEPH_OSD_OP_WRITEFULL;
+       else
+               opcode = CEPH_OSD_OP_WRITE;
+
+       osd_req_op_extent_init(osd_req, which, opcode,
+                              obj_req->ex.oe_off, obj_req->ex.oe_len, 0, 0);
+       rbd_osd_setup_data(osd_req, which);
+}
+
+static int rbd_obj_init_write(struct rbd_obj_request *obj_req)
+{
+       int ret;
+
+       /* reverse map the entire object onto the parent */
+       ret = rbd_obj_calc_img_extents(obj_req, true);
+       if (ret)
+               return ret;
+
+       if (rbd_obj_copyup_enabled(obj_req))
+               obj_req->flags |= RBD_OBJ_FLAG_COPYUP_ENABLED;
+
+       obj_req->write_state = RBD_OBJ_WRITE_START;
+       return 0;
+}
+
+static u16 truncate_or_zero_opcode(struct rbd_obj_request *obj_req)
+{
+       return rbd_obj_is_tail(obj_req) ? CEPH_OSD_OP_TRUNCATE :
+                                         CEPH_OSD_OP_ZERO;
+}
+
+static void __rbd_osd_setup_discard_ops(struct ceph_osd_request *osd_req,
+                                       int which)
+{
+       struct rbd_obj_request *obj_req = osd_req->r_priv;
+
+       if (rbd_obj_is_entire(obj_req) && !obj_req->num_img_extents) {
+               rbd_assert(obj_req->flags & RBD_OBJ_FLAG_DELETION);
+               osd_req_op_init(osd_req, which, CEPH_OSD_OP_DELETE, 0);
        } else {
-               obj_req->write_state = RBD_OBJ_WRITE_FLAT;
+               osd_req_op_extent_init(osd_req, which,
+                                      truncate_or_zero_opcode(obj_req),
+                                      obj_req->ex.oe_off, obj_req->ex.oe_len,
+                                      0, 0);
+       }
+}
+
+static int rbd_obj_init_discard(struct rbd_obj_request *obj_req)
+{
+       struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
+       u64 off, next_off;
+       int ret;
+
+       /*
+        * Align the range to alloc_size boundary and punt on discards
+        * that are too small to free up any space.
+        *
+        * alloc_size == object_size && is_tail() is a special case for
+        * filestore with filestore_punch_hole = false, needed to allow
+        * truncate (in addition to delete).
+        */
+       if (rbd_dev->opts->alloc_size != rbd_dev->layout.object_size ||
+           !rbd_obj_is_tail(obj_req)) {
+               off = round_up(obj_req->ex.oe_off, rbd_dev->opts->alloc_size);
+               next_off = round_down(obj_req->ex.oe_off + obj_req->ex.oe_len,
+                                     rbd_dev->opts->alloc_size);
+               if (off >= next_off)
+                       return 1;
+
+               dout("%s %p %llu~%llu -> %llu~%llu\n", __func__,
+                    obj_req, obj_req->ex.oe_off, obj_req->ex.oe_len,
+                    off, next_off - off);
+               obj_req->ex.oe_off = off;
+               obj_req->ex.oe_len = next_off - off;
+       }
+
+       /* reverse map the entire object onto the parent */
+       ret = rbd_obj_calc_img_extents(obj_req, true);
+       if (ret)
+               return ret;
+
+       obj_req->flags |= RBD_OBJ_FLAG_NOOP_FOR_NONEXISTENT;
+       if (rbd_obj_is_entire(obj_req) && !obj_req->num_img_extents)
+               obj_req->flags |= RBD_OBJ_FLAG_DELETION;
+
+       obj_req->write_state = RBD_OBJ_WRITE_START;
+       return 0;
+}
+
+static void __rbd_osd_setup_zeroout_ops(struct ceph_osd_request *osd_req,
+                                       int which)
+{
+       struct rbd_obj_request *obj_req = osd_req->r_priv;
+       u16 opcode;
+
+       if (rbd_obj_is_entire(obj_req)) {
+               if (obj_req->num_img_extents) {
+                       if (!(obj_req->flags & RBD_OBJ_FLAG_COPYUP_ENABLED))
+                               osd_req_op_init(osd_req, which++,
+                                               CEPH_OSD_OP_CREATE, 0);
+                       opcode = CEPH_OSD_OP_TRUNCATE;
+               } else {
+                       rbd_assert(obj_req->flags & RBD_OBJ_FLAG_DELETION);
+                       osd_req_op_init(osd_req, which++,
+                                       CEPH_OSD_OP_DELETE, 0);
+                       opcode = 0;
+               }
+       } else {
+               opcode = truncate_or_zero_opcode(obj_req);
+       }
+
+       if (opcode)
+               osd_req_op_extent_init(osd_req, which, opcode,
+                                      obj_req->ex.oe_off, obj_req->ex.oe_len,
+                                      0, 0);
+}
+
+static int rbd_obj_init_zeroout(struct rbd_obj_request *obj_req)
+{
+       int ret;
+
+       /* reverse map the entire object onto the parent */
+       ret = rbd_obj_calc_img_extents(obj_req, true);
+       if (ret)
+               return ret;
+
+       if (rbd_obj_copyup_enabled(obj_req))
+               obj_req->flags |= RBD_OBJ_FLAG_COPYUP_ENABLED;
+       if (!obj_req->num_img_extents) {
+               obj_req->flags |= RBD_OBJ_FLAG_NOOP_FOR_NONEXISTENT;
+               if (rbd_obj_is_entire(obj_req))
+                       obj_req->flags |= RBD_OBJ_FLAG_DELETION;
        }
 
-       __rbd_obj_setup_zeroout(obj_req, which);
+       obj_req->write_state = RBD_OBJ_WRITE_START;
        return 0;
 }
 
+static int count_write_ops(struct rbd_obj_request *obj_req)
+{
+       struct rbd_img_request *img_req = obj_req->img_request;
+
+       switch (img_req->op_type) {
+       case OBJ_OP_WRITE:
+               if (!use_object_map(img_req->rbd_dev) ||
+                   !(obj_req->flags & RBD_OBJ_FLAG_MAY_EXIST))
+                       return 2; /* setallochint + write/writefull */
+
+               return 1; /* write/writefull */
+       case OBJ_OP_DISCARD:
+               return 1; /* delete/truncate/zero */
+       case OBJ_OP_ZEROOUT:
+               if (rbd_obj_is_entire(obj_req) && obj_req->num_img_extents &&
+                   !(obj_req->flags & RBD_OBJ_FLAG_COPYUP_ENABLED))
+                       return 2; /* create + truncate */
+
+               return 1; /* delete/truncate/zero */
+       default:
+               BUG();
+       }
+}
+
+static void rbd_osd_setup_write_ops(struct ceph_osd_request *osd_req,
+                                   int which)
+{
+       struct rbd_obj_request *obj_req = osd_req->r_priv;
+
+       switch (obj_req->img_request->op_type) {
+       case OBJ_OP_WRITE:
+               __rbd_osd_setup_write_ops(osd_req, which);
+               break;
+       case OBJ_OP_DISCARD:
+               __rbd_osd_setup_discard_ops(osd_req, which);
+               break;
+       case OBJ_OP_ZEROOUT:
+               __rbd_osd_setup_zeroout_ops(osd_req, which);
+               break;
+       default:
+               BUG();
+       }
+}
+
 /*
- * For each object request in @img_req, allocate an OSD request, add
- * individual OSD ops and prepare them for submission.  The number of
- * OSD ops depends on op_type and the overlap point (if any).
+ * Prune the list of object requests (adjust offset and/or length, drop
+ * redundant requests).  Prepare object request state machines and image
+ * request state machine for execution.
  */
 static int __rbd_img_fill_request(struct rbd_img_request *img_req)
 {
@@ -2024,16 +2568,16 @@ static int __rbd_img_fill_request(struct rbd_img_request *img_req)
        for_each_obj_request_safe(img_req, obj_req, next_obj_req) {
                switch (img_req->op_type) {
                case OBJ_OP_READ:
-                       ret = rbd_obj_setup_read(obj_req);
+                       ret = rbd_obj_init_read(obj_req);
                        break;
                case OBJ_OP_WRITE:
-                       ret = rbd_obj_setup_write(obj_req);
+                       ret = rbd_obj_init_write(obj_req);
                        break;
                case OBJ_OP_DISCARD:
-                       ret = rbd_obj_setup_discard(obj_req);
+                       ret = rbd_obj_init_discard(obj_req);
                        break;
                case OBJ_OP_ZEROOUT:
-                       ret = rbd_obj_setup_zeroout(obj_req);
+                       ret = rbd_obj_init_zeroout(obj_req);
                        break;
                default:
                        BUG();
@@ -2041,17 +2585,12 @@ static int __rbd_img_fill_request(struct rbd_img_request *img_req)
                if (ret < 0)
                        return ret;
                if (ret > 0) {
-                       img_req->xferred += obj_req->ex.oe_len;
-                       img_req->pending_count--;
                        rbd_img_obj_request_del(img_req, obj_req);
                        continue;
                }
-
-               ret = ceph_osdc_alloc_messages(obj_req->osd_req, GFP_NOIO);
-               if (ret)
-                       return ret;
        }
 
+       img_req->state = RBD_IMG_START;
        return 0;
 }
 
@@ -2340,17 +2879,55 @@ static int rbd_img_fill_from_bvecs(struct rbd_img_request *img_req,
                                         &it);
 }
 
-static void rbd_img_request_submit(struct rbd_img_request *img_request)
+static void rbd_img_handle_request_work(struct work_struct *work)
 {
-       struct rbd_obj_request *obj_request;
+       struct rbd_img_request *img_req =
+           container_of(work, struct rbd_img_request, work);
 
-       dout("%s: img %p\n", __func__, img_request);
+       rbd_img_handle_request(img_req, img_req->work_result);
+}
 
-       rbd_img_request_get(img_request);
-       for_each_obj_request(img_request, obj_request)
-               rbd_obj_request_submit(obj_request);
+static void rbd_img_schedule(struct rbd_img_request *img_req, int result)
+{
+       INIT_WORK(&img_req->work, rbd_img_handle_request_work);
+       img_req->work_result = result;
+       queue_work(rbd_wq, &img_req->work);
+}
 
-       rbd_img_request_put(img_request);
+static bool rbd_obj_may_exist(struct rbd_obj_request *obj_req)
+{
+       struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
+
+       if (rbd_object_map_may_exist(rbd_dev, obj_req->ex.oe_objno)) {
+               obj_req->flags |= RBD_OBJ_FLAG_MAY_EXIST;
+               return true;
+       }
+
+       dout("%s %p objno %llu assuming dne\n", __func__, obj_req,
+            obj_req->ex.oe_objno);
+       return false;
+}
+
+static int rbd_obj_read_object(struct rbd_obj_request *obj_req)
+{
+       struct ceph_osd_request *osd_req;
+       int ret;
+
+       osd_req = __rbd_obj_add_osd_request(obj_req, NULL, 1);
+       if (IS_ERR(osd_req))
+               return PTR_ERR(osd_req);
+
+       osd_req_op_extent_init(osd_req, 0, CEPH_OSD_OP_READ,
+                              obj_req->ex.oe_off, obj_req->ex.oe_len, 0, 0);
+       rbd_osd_setup_data(osd_req, 0);
+       rbd_osd_format_read(osd_req);
+
+       ret = ceph_osdc_alloc_messages(osd_req, GFP_NOIO);
+       if (ret)
+               return ret;
+
+       rbd_osd_submit(osd_req);
+       return 0;
 }
 
 static int rbd_obj_read_from_parent(struct rbd_obj_request *obj_req)
@@ -2396,51 +2973,144 @@ static int rbd_obj_read_from_parent(struct rbd_obj_request *obj_req)
                return ret;
        }
 
-       rbd_img_request_submit(child_img_req);
+       /* avoid parent chain recursion */
+       rbd_img_schedule(child_img_req, 0);
        return 0;
 }
 
-static bool rbd_obj_handle_read(struct rbd_obj_request *obj_req)
+static bool rbd_obj_advance_read(struct rbd_obj_request *obj_req, int *result)
 {
        struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
        int ret;
 
-       if (obj_req->result == -ENOENT &&
-           rbd_dev->parent_overlap && !obj_req->tried_parent) {
-               /* reverse map this object extent onto the parent */
-               ret = rbd_obj_calc_img_extents(obj_req, false);
+again:
+       switch (obj_req->read_state) {
+       case RBD_OBJ_READ_START:
+               rbd_assert(!*result);
+
+               if (!rbd_obj_may_exist(obj_req)) {
+                       *result = -ENOENT;
+                       obj_req->read_state = RBD_OBJ_READ_OBJECT;
+                       goto again;
+               }
+
+               ret = rbd_obj_read_object(obj_req);
                if (ret) {
-                       obj_req->result = ret;
+                       *result = ret;
                        return true;
                }
-
-               if (obj_req->num_img_extents) {
-                       obj_req->tried_parent = true;
-                       ret = rbd_obj_read_from_parent(obj_req);
+               obj_req->read_state = RBD_OBJ_READ_OBJECT;
+               return false;
+       case RBD_OBJ_READ_OBJECT:
+               if (*result == -ENOENT && rbd_dev->parent_overlap) {
+                       /* reverse map this object extent onto the parent */
+                       ret = rbd_obj_calc_img_extents(obj_req, false);
                        if (ret) {
-                               obj_req->result = ret;
+                               *result = ret;
                                return true;
                        }
-                       return false;
+                       if (obj_req->num_img_extents) {
+                               ret = rbd_obj_read_from_parent(obj_req);
+                               if (ret) {
+                                       *result = ret;
+                                       return true;
+                               }
+                               obj_req->read_state = RBD_OBJ_READ_PARENT;
+                               return false;
+                       }
                }
+
+               /*
+                * -ENOENT means a hole in the image -- zero-fill the entire
+                * length of the request.  A short read also implies zero-fill
+                * to the end of the request.
+                */
+               if (*result == -ENOENT) {
+                       rbd_obj_zero_range(obj_req, 0, obj_req->ex.oe_len);
+                       *result = 0;
+               } else if (*result >= 0) {
+                       if (*result < obj_req->ex.oe_len)
+                               rbd_obj_zero_range(obj_req, *result,
+                                               obj_req->ex.oe_len - *result);
+                       else
+                               rbd_assert(*result == obj_req->ex.oe_len);
+                       *result = 0;
+               }
+               return true;
+       case RBD_OBJ_READ_PARENT:
+               return true;
+       default:
+               BUG();
        }
+}
+
+static bool rbd_obj_write_is_noop(struct rbd_obj_request *obj_req)
+{
+       struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
+
+       if (rbd_object_map_may_exist(rbd_dev, obj_req->ex.oe_objno))
+               obj_req->flags |= RBD_OBJ_FLAG_MAY_EXIST;
+
+       if (!(obj_req->flags & RBD_OBJ_FLAG_MAY_EXIST) &&
+           (obj_req->flags & RBD_OBJ_FLAG_NOOP_FOR_NONEXISTENT)) {
+               dout("%s %p noop for nonexistent\n", __func__, obj_req);
+               return true;
+       }
+
+       return false;
+}
+
+/*
+ * Return:
+ *   0 - object map update sent
+ *   1 - object map update isn't needed
+ *  <0 - error
+ */
+static int rbd_obj_write_pre_object_map(struct rbd_obj_request *obj_req)
+{
+       struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
+       u8 new_state;
+
+       if (!(rbd_dev->header.features & RBD_FEATURE_OBJECT_MAP))
+               return 1;
+
+       if (obj_req->flags & RBD_OBJ_FLAG_DELETION)
+               new_state = OBJECT_PENDING;
+       else
+               new_state = OBJECT_EXISTS;
+
+       return rbd_object_map_update(obj_req, CEPH_NOSNAP, new_state, NULL);
+}
+
+static int rbd_obj_write_object(struct rbd_obj_request *obj_req)
+{
+       struct ceph_osd_request *osd_req;
+       int num_ops = count_write_ops(obj_req);
+       int which = 0;
+       int ret;
 
-       /*
-        * -ENOENT means a hole in the image -- zero-fill the entire
-        * length of the request.  A short read also implies zero-fill
-        * to the end of the request.  In both cases we update xferred
-        * count to indicate the whole request was satisfied.
-        */
-       if (obj_req->result == -ENOENT ||
-           (!obj_req->result && obj_req->xferred < obj_req->ex.oe_len)) {
-               rbd_assert(!obj_req->xferred || !obj_req->result);
-               rbd_obj_zero_range(obj_req, obj_req->xferred,
-                                  obj_req->ex.oe_len - obj_req->xferred);
-               obj_req->result = 0;
-               obj_req->xferred = obj_req->ex.oe_len;
+       if (obj_req->flags & RBD_OBJ_FLAG_COPYUP_ENABLED)
+               num_ops++; /* stat */
+
+       osd_req = rbd_obj_add_osd_request(obj_req, num_ops);
+       if (IS_ERR(osd_req))
+               return PTR_ERR(osd_req);
+
+       if (obj_req->flags & RBD_OBJ_FLAG_COPYUP_ENABLED) {
+               ret = rbd_osd_setup_stat(osd_req, which++);
+               if (ret)
+                       return ret;
        }
 
-       return true;
+       rbd_osd_setup_write_ops(osd_req, which);
+       rbd_osd_format_write(osd_req);
+
+       ret = ceph_osdc_alloc_messages(osd_req, GFP_NOIO);
+       if (ret)
+               return ret;
+
+       rbd_osd_submit(osd_req);
+       return 0;
 }
 
 /*
@@ -2463,123 +3133,67 @@ static bool is_zero_bvecs(struct bio_vec *bvecs, u32 bytes)
 
 #define MODS_ONLY      U32_MAX
 
-static int rbd_obj_issue_copyup_empty_snapc(struct rbd_obj_request *obj_req,
-                                           u32 bytes)
+static int rbd_obj_copyup_empty_snapc(struct rbd_obj_request *obj_req,
+                                     u32 bytes)
 {
+       struct ceph_osd_request *osd_req;
        int ret;
 
        dout("%s obj_req %p bytes %u\n", __func__, obj_req, bytes);
-       rbd_assert(obj_req->osd_req->r_ops[0].op == CEPH_OSD_OP_STAT);
        rbd_assert(bytes > 0 && bytes != MODS_ONLY);
-       rbd_osd_req_destroy(obj_req->osd_req);
 
-       obj_req->osd_req = __rbd_osd_req_create(obj_req, &rbd_empty_snapc, 1);
-       if (!obj_req->osd_req)
-               return -ENOMEM;
+       osd_req = __rbd_obj_add_osd_request(obj_req, &rbd_empty_snapc, 1);
+       if (IS_ERR(osd_req))
+               return PTR_ERR(osd_req);
 
-       ret = osd_req_op_cls_init(obj_req->osd_req, 0, "rbd", "copyup");
+       ret = rbd_osd_setup_copyup(osd_req, 0, bytes);
        if (ret)
                return ret;
 
-       osd_req_op_cls_request_data_bvecs(obj_req->osd_req, 0,
-                                         obj_req->copyup_bvecs,
-                                         obj_req->copyup_bvec_count,
-                                         bytes);
-       rbd_osd_req_format_write(obj_req);
+       rbd_osd_format_write(osd_req);
 
-       ret = ceph_osdc_alloc_messages(obj_req->osd_req, GFP_NOIO);
+       ret = ceph_osdc_alloc_messages(osd_req, GFP_NOIO);
        if (ret)
                return ret;
 
-       rbd_obj_request_submit(obj_req);
+       rbd_osd_submit(osd_req);
        return 0;
 }
 
-static int rbd_obj_issue_copyup_ops(struct rbd_obj_request *obj_req, u32 bytes)
+static int rbd_obj_copyup_current_snapc(struct rbd_obj_request *obj_req,
+                                       u32 bytes)
 {
-       struct rbd_img_request *img_req = obj_req->img_request;
-       unsigned int num_osd_ops = (bytes != MODS_ONLY);
-       unsigned int which = 0;
+       struct ceph_osd_request *osd_req;
+       int num_ops = count_write_ops(obj_req);
+       int which = 0;
        int ret;
 
        dout("%s obj_req %p bytes %u\n", __func__, obj_req, bytes);
-       rbd_assert(obj_req->osd_req->r_ops[0].op == CEPH_OSD_OP_STAT ||
-                  obj_req->osd_req->r_ops[0].op == CEPH_OSD_OP_CALL);
-       rbd_osd_req_destroy(obj_req->osd_req);
 
-       switch (img_req->op_type) {
-       case OBJ_OP_WRITE:
-               num_osd_ops += count_write_ops(obj_req);
-               break;
-       case OBJ_OP_ZEROOUT:
-               num_osd_ops += count_zeroout_ops(obj_req);
-               break;
-       default:
-               BUG();
-       }
+       if (bytes != MODS_ONLY)
+               num_ops++; /* copyup */
 
-       obj_req->osd_req = rbd_osd_req_create(obj_req, num_osd_ops);
-       if (!obj_req->osd_req)
-               return -ENOMEM;
+       osd_req = rbd_obj_add_osd_request(obj_req, num_ops);
+       if (IS_ERR(osd_req))
+               return PTR_ERR(osd_req);
 
        if (bytes != MODS_ONLY) {
-               ret = osd_req_op_cls_init(obj_req->osd_req, which, "rbd",
-                                         "copyup");
+               ret = rbd_osd_setup_copyup(osd_req, which++, bytes);
                if (ret)
                        return ret;
-
-               osd_req_op_cls_request_data_bvecs(obj_req->osd_req, which++,
-                                                 obj_req->copyup_bvecs,
-                                                 obj_req->copyup_bvec_count,
-                                                 bytes);
        }
 
-       switch (img_req->op_type) {
-       case OBJ_OP_WRITE:
-               __rbd_obj_setup_write(obj_req, which);
-               break;
-       case OBJ_OP_ZEROOUT:
-               __rbd_obj_setup_zeroout(obj_req, which);
-               break;
-       default:
-               BUG();
-       }
+       rbd_osd_setup_write_ops(osd_req, which);
+       rbd_osd_format_write(osd_req);
 
-       ret = ceph_osdc_alloc_messages(obj_req->osd_req, GFP_NOIO);
+       ret = ceph_osdc_alloc_messages(osd_req, GFP_NOIO);
        if (ret)
                return ret;
 
-       rbd_obj_request_submit(obj_req);
+       rbd_osd_submit(osd_req);
        return 0;
 }
 
-static int rbd_obj_issue_copyup(struct rbd_obj_request *obj_req, u32 bytes)
-{
-       /*
-        * Only send non-zero copyup data to save some I/O and network
-        * bandwidth -- zero copyup data is equivalent to the object not
-        * existing.
-        */
-       if (is_zero_bvecs(obj_req->copyup_bvecs, bytes)) {
-               dout("%s obj_req %p detected zeroes\n", __func__, obj_req);
-               bytes = 0;
-       }
-
-       if (obj_req->img_request->snapc->num_snaps && bytes > 0) {
-               /*
-                * Send a copyup request with an empty snapshot context to
-                * deep-copyup the object through all existing snapshots.
-                * A second request with the current snapshot context will be
-                * sent for the actual modification.
-                */
-               obj_req->write_state = RBD_OBJ_WRITE_COPYUP_EMPTY_SNAPC;
-               return rbd_obj_issue_copyup_empty_snapc(obj_req, bytes);
-       }
-
-       obj_req->write_state = RBD_OBJ_WRITE_COPYUP_OPS;
-       return rbd_obj_issue_copyup_ops(obj_req, bytes);
-}
-
 static int setup_copyup_bvecs(struct rbd_obj_request *obj_req, u64 obj_overlap)
 {
        u32 i;
@@ -2608,7 +3222,12 @@ static int setup_copyup_bvecs(struct rbd_obj_request *obj_req, u64 obj_overlap)
        return 0;
 }
 
-static int rbd_obj_handle_write_guard(struct rbd_obj_request *obj_req)
+/*
+ * The target object doesn't exist.  Read the data for the entire
+ * target object up to the overlap point (if any) from the parent,
+ * so we can use it for a copyup.
+ */
+static int rbd_obj_copyup_read_parent(struct rbd_obj_request *obj_req)
 {
        struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
        int ret;
@@ -2623,178 +3242,492 @@ static int rbd_obj_handle_write_guard(struct rbd_obj_request *obj_req)
                 * request -- pass MODS_ONLY since the copyup isn't needed
                 * anymore.
                 */
-               obj_req->write_state = RBD_OBJ_WRITE_COPYUP_OPS;
-               return rbd_obj_issue_copyup_ops(obj_req, MODS_ONLY);
+               return rbd_obj_copyup_current_snapc(obj_req, MODS_ONLY);
        }
 
        ret = setup_copyup_bvecs(obj_req, rbd_obj_img_extents_bytes(obj_req));
        if (ret)
                return ret;
 
-       obj_req->write_state = RBD_OBJ_WRITE_READ_FROM_PARENT;
        return rbd_obj_read_from_parent(obj_req);
 }
 
-static bool rbd_obj_handle_write(struct rbd_obj_request *obj_req)
+static void rbd_obj_copyup_object_maps(struct rbd_obj_request *obj_req)
+{
+       struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
+       struct ceph_snap_context *snapc = obj_req->img_request->snapc;
+       u8 new_state;
+       u32 i;
+       int ret;
+
+       rbd_assert(!obj_req->pending.result && !obj_req->pending.num_pending);
+
+       if (!(rbd_dev->header.features & RBD_FEATURE_OBJECT_MAP))
+               return;
+
+       if (obj_req->flags & RBD_OBJ_FLAG_COPYUP_ZEROS)
+               return;
+
+       for (i = 0; i < snapc->num_snaps; i++) {
+               if ((rbd_dev->header.features & RBD_FEATURE_FAST_DIFF) &&
+                   i + 1 < snapc->num_snaps)
+                       new_state = OBJECT_EXISTS_CLEAN;
+               else
+                       new_state = OBJECT_EXISTS;
+
+               ret = rbd_object_map_update(obj_req, snapc->snaps[i],
+                                           new_state, NULL);
+               if (ret < 0) {
+                       obj_req->pending.result = ret;
+                       return;
+               }
+
+               rbd_assert(!ret);
+               obj_req->pending.num_pending++;
+       }
+}
+
+static void rbd_obj_copyup_write_object(struct rbd_obj_request *obj_req)
+{
+       u32 bytes = rbd_obj_img_extents_bytes(obj_req);
+       int ret;
+
+       rbd_assert(!obj_req->pending.result && !obj_req->pending.num_pending);
+
+       /*
+        * Only send non-zero copyup data to save some I/O and network
+        * bandwidth -- zero copyup data is equivalent to the object not
+        * existing.
+        */
+       if (obj_req->flags & RBD_OBJ_FLAG_COPYUP_ZEROS)
+               bytes = 0;
+
+       if (obj_req->img_request->snapc->num_snaps && bytes > 0) {
+               /*
+                * Send a copyup request with an empty snapshot context to
+                * deep-copyup the object through all existing snapshots.
+                * A second request with the current snapshot context will be
+                * sent for the actual modification.
+                */
+               ret = rbd_obj_copyup_empty_snapc(obj_req, bytes);
+               if (ret) {
+                       obj_req->pending.result = ret;
+                       return;
+               }
+
+               obj_req->pending.num_pending++;
+               bytes = MODS_ONLY;
+       }
+
+       ret = rbd_obj_copyup_current_snapc(obj_req, bytes);
+       if (ret) {
+               obj_req->pending.result = ret;
+               return;
+       }
+
+       obj_req->pending.num_pending++;
+}
+
+static bool rbd_obj_advance_copyup(struct rbd_obj_request *obj_req, int *result)
+{
+       struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
+       int ret;
+
+again:
+       switch (obj_req->copyup_state) {
+       case RBD_OBJ_COPYUP_START:
+               rbd_assert(!*result);
+
+               ret = rbd_obj_copyup_read_parent(obj_req);
+               if (ret) {
+                       *result = ret;
+                       return true;
+               }
+               if (obj_req->num_img_extents)
+                       obj_req->copyup_state = RBD_OBJ_COPYUP_READ_PARENT;
+               else
+                       obj_req->copyup_state = RBD_OBJ_COPYUP_WRITE_OBJECT;
+               return false;
+       case RBD_OBJ_COPYUP_READ_PARENT:
+               if (*result)
+                       return true;
+
+               if (is_zero_bvecs(obj_req->copyup_bvecs,
+                                 rbd_obj_img_extents_bytes(obj_req))) {
+                       dout("%s %p detected zeros\n", __func__, obj_req);
+                       obj_req->flags |= RBD_OBJ_FLAG_COPYUP_ZEROS;
+               }
+
+               rbd_obj_copyup_object_maps(obj_req);
+               if (!obj_req->pending.num_pending) {
+                       *result = obj_req->pending.result;
+                       obj_req->copyup_state = RBD_OBJ_COPYUP_OBJECT_MAPS;
+                       goto again;
+               }
+               obj_req->copyup_state = __RBD_OBJ_COPYUP_OBJECT_MAPS;
+               return false;
+       case __RBD_OBJ_COPYUP_OBJECT_MAPS:
+               if (!pending_result_dec(&obj_req->pending, result))
+                       return false;
+               /* fall through */
+       case RBD_OBJ_COPYUP_OBJECT_MAPS:
+               if (*result) {
+                       rbd_warn(rbd_dev, "snap object map update failed: %d",
+                                *result);
+                       return true;
+               }
+
+               rbd_obj_copyup_write_object(obj_req);
+               if (!obj_req->pending.num_pending) {
+                       *result = obj_req->pending.result;
+                       obj_req->copyup_state = RBD_OBJ_COPYUP_WRITE_OBJECT;
+                       goto again;
+               }
+               obj_req->copyup_state = __RBD_OBJ_COPYUP_WRITE_OBJECT;
+               return false;
+       case __RBD_OBJ_COPYUP_WRITE_OBJECT:
+               if (!pending_result_dec(&obj_req->pending, result))
+                       return false;
+               /* fall through */
+       case RBD_OBJ_COPYUP_WRITE_OBJECT:
+               return true;
+       default:
+               BUG();
+       }
+}
+
+/*
+ * Return:
+ *   0 - object map update sent
+ *   1 - object map update isn't needed
+ *  <0 - error
+ */
+static int rbd_obj_write_post_object_map(struct rbd_obj_request *obj_req)
+{
+       struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
+       u8 current_state = OBJECT_PENDING;
+
+       if (!(rbd_dev->header.features & RBD_FEATURE_OBJECT_MAP))
+               return 1;
+
+       if (!(obj_req->flags & RBD_OBJ_FLAG_DELETION))
+               return 1;
+
+       return rbd_object_map_update(obj_req, CEPH_NOSNAP, OBJECT_NONEXISTENT,
+                                    &current_state);
+}
+
+static bool rbd_obj_advance_write(struct rbd_obj_request *obj_req, int *result)
+{
+       struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
+       int ret;
+
+again:
+       switch (obj_req->write_state) {
+       case RBD_OBJ_WRITE_START:
+               rbd_assert(!*result);
+
+               if (rbd_obj_write_is_noop(obj_req))
+                       return true;
+
+               ret = rbd_obj_write_pre_object_map(obj_req);
+               if (ret < 0) {
+                       *result = ret;
+                       return true;
+               }
+               obj_req->write_state = RBD_OBJ_WRITE_PRE_OBJECT_MAP;
+               if (ret > 0)
+                       goto again;
+               return false;
+       case RBD_OBJ_WRITE_PRE_OBJECT_MAP:
+               if (*result) {
+                       rbd_warn(rbd_dev, "pre object map update failed: %d",
+                                *result);
+                       return true;
+               }
+               ret = rbd_obj_write_object(obj_req);
+               if (ret) {
+                       *result = ret;
+                       return true;
+               }
+               obj_req->write_state = RBD_OBJ_WRITE_OBJECT;
+               return false;
+       case RBD_OBJ_WRITE_OBJECT:
+               if (*result == -ENOENT) {
+                       if (obj_req->flags & RBD_OBJ_FLAG_COPYUP_ENABLED) {
+                               *result = 0;
+                               obj_req->copyup_state = RBD_OBJ_COPYUP_START;
+                               obj_req->write_state = __RBD_OBJ_WRITE_COPYUP;
+                               goto again;
+                       }
+                       /*
+                        * On a non-existent object:
+                        *   delete - -ENOENT, truncate/zero - 0
+                        */
+                       if (obj_req->flags & RBD_OBJ_FLAG_DELETION)
+                               *result = 0;
+               }
+               if (*result)
+                       return true;
+
+               obj_req->write_state = RBD_OBJ_WRITE_COPYUP;
+               goto again;
+       case __RBD_OBJ_WRITE_COPYUP:
+               if (!rbd_obj_advance_copyup(obj_req, result))
+                       return false;
+               /* fall through */
+       case RBD_OBJ_WRITE_COPYUP:
+               if (*result) {
+                       rbd_warn(rbd_dev, "copyup failed: %d", *result);
+                       return true;
+               }
+               ret = rbd_obj_write_post_object_map(obj_req);
+               if (ret < 0) {
+                       *result = ret;
+                       return true;
+               }
+               obj_req->write_state = RBD_OBJ_WRITE_POST_OBJECT_MAP;
+               if (ret > 0)
+                       goto again;
+               return false;
+       case RBD_OBJ_WRITE_POST_OBJECT_MAP:
+               if (*result)
+                       rbd_warn(rbd_dev, "post object map update failed: %d",
+                                *result);
+               return true;
+       default:
+               BUG();
+       }
+}
+
+/*
+ * Return true if @obj_req is completed.
+ */
+static bool __rbd_obj_handle_request(struct rbd_obj_request *obj_req,
+                                    int *result)
+{
+       struct rbd_img_request *img_req = obj_req->img_request;
+       struct rbd_device *rbd_dev = img_req->rbd_dev;
+       bool done;
+
+       mutex_lock(&obj_req->state_mutex);
+       if (!rbd_img_is_write(img_req))
+               done = rbd_obj_advance_read(obj_req, result);
+       else
+               done = rbd_obj_advance_write(obj_req, result);
+       mutex_unlock(&obj_req->state_mutex);
+
+       if (done && *result) {
+               rbd_assert(*result < 0);
+               rbd_warn(rbd_dev, "%s at objno %llu %llu~%llu result %d",
+                        obj_op_name(img_req->op_type), obj_req->ex.oe_objno,
+                        obj_req->ex.oe_off, obj_req->ex.oe_len, *result);
+       }
+       return done;
+}
+
+/*
+ * This is open-coded in rbd_img_handle_request() to avoid parent chain
+ * recursion.
+ */
+static void rbd_obj_handle_request(struct rbd_obj_request *obj_req, int result)
+{
+       if (__rbd_obj_handle_request(obj_req, &result))
+               rbd_img_handle_request(obj_req->img_request, result);
+}
+
+static bool need_exclusive_lock(struct rbd_img_request *img_req)
+{
+       struct rbd_device *rbd_dev = img_req->rbd_dev;
+
+       if (!(rbd_dev->header.features & RBD_FEATURE_EXCLUSIVE_LOCK))
+               return false;
+
+       if (rbd_dev->spec->snap_id != CEPH_NOSNAP)
+               return false;
+
+       rbd_assert(!test_bit(IMG_REQ_CHILD, &img_req->flags));
+       if (rbd_dev->opts->lock_on_read ||
+           (rbd_dev->header.features & RBD_FEATURE_OBJECT_MAP))
+               return true;
+
+       return rbd_img_is_write(img_req);
+}
+
+static bool rbd_lock_add_request(struct rbd_img_request *img_req)
+{
+       struct rbd_device *rbd_dev = img_req->rbd_dev;
+       bool locked;
+
+       lockdep_assert_held(&rbd_dev->lock_rwsem);
+       locked = rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED;
+       spin_lock(&rbd_dev->lock_lists_lock);
+       rbd_assert(list_empty(&img_req->lock_item));
+       if (!locked)
+               list_add_tail(&img_req->lock_item, &rbd_dev->acquiring_list);
+       else
+               list_add_tail(&img_req->lock_item, &rbd_dev->running_list);
+       spin_unlock(&rbd_dev->lock_lists_lock);
+       return locked;
+}
+
+static void rbd_lock_del_request(struct rbd_img_request *img_req)
+{
+       struct rbd_device *rbd_dev = img_req->rbd_dev;
+       bool need_wakeup;
+
+       lockdep_assert_held(&rbd_dev->lock_rwsem);
+       spin_lock(&rbd_dev->lock_lists_lock);
+       rbd_assert(!list_empty(&img_req->lock_item));
+       list_del_init(&img_req->lock_item);
+       need_wakeup = (rbd_dev->lock_state == RBD_LOCK_STATE_RELEASING &&
+                      list_empty(&rbd_dev->running_list));
+       spin_unlock(&rbd_dev->lock_lists_lock);
+       if (need_wakeup)
+               complete(&rbd_dev->releasing_wait);
+}
+
+static int rbd_img_exclusive_lock(struct rbd_img_request *img_req)
+{
+       struct rbd_device *rbd_dev = img_req->rbd_dev;
+
+       if (!need_exclusive_lock(img_req))
+               return 1;
+
+       if (rbd_lock_add_request(img_req))
+               return 1;
+
+       if (rbd_dev->opts->exclusive) {
+               WARN_ON(1); /* lock got released? */
+               return -EROFS;
+       }
+
+       /*
+        * Note the use of mod_delayed_work() in rbd_acquire_lock()
+        * and cancel_delayed_work() in wake_lock_waiters().
+        */
+       dout("%s rbd_dev %p queueing lock_dwork\n", __func__, rbd_dev);
+       queue_delayed_work(rbd_dev->task_wq, &rbd_dev->lock_dwork, 0);
+       return 0;
+}
+
+static void rbd_img_object_requests(struct rbd_img_request *img_req)
+{
+       struct rbd_obj_request *obj_req;
+
+       rbd_assert(!img_req->pending.result && !img_req->pending.num_pending);
+
+       for_each_obj_request(img_req, obj_req) {
+               int result = 0;
+
+               if (__rbd_obj_handle_request(obj_req, &result)) {
+                       if (result) {
+                               img_req->pending.result = result;
+                               return;
+                       }
+               } else {
+                       img_req->pending.num_pending++;
+               }
+       }
+}
+
+static bool rbd_img_advance(struct rbd_img_request *img_req, int *result)
 {
+       struct rbd_device *rbd_dev = img_req->rbd_dev;
        int ret;
 
-       switch (obj_req->write_state) {
-       case RBD_OBJ_WRITE_GUARD:
-               rbd_assert(!obj_req->xferred);
-               if (obj_req->result == -ENOENT) {
-                       /*
-                        * The target object doesn't exist.  Read the data for
-                        * the entire target object up to the overlap point (if
-                        * any) from the parent, so we can use it for a copyup.
-                        */
-                       ret = rbd_obj_handle_write_guard(obj_req);
-                       if (ret) {
-                               obj_req->result = ret;
-                               return true;
-                       }
-                       return false;
-               }
-               /* fall through */
-       case RBD_OBJ_WRITE_FLAT:
-       case RBD_OBJ_WRITE_COPYUP_OPS:
-               if (!obj_req->result)
-                       /*
-                        * There is no such thing as a successful short
-                        * write -- indicate the whole request was satisfied.
-                        */
-                       obj_req->xferred = obj_req->ex.oe_len;
-               return true;
-       case RBD_OBJ_WRITE_READ_FROM_PARENT:
-               if (obj_req->result)
-                       return true;
+again:
+       switch (img_req->state) {
+       case RBD_IMG_START:
+               rbd_assert(!*result);
 
-               rbd_assert(obj_req->xferred);
-               ret = rbd_obj_issue_copyup(obj_req, obj_req->xferred);
-               if (ret) {
-                       obj_req->result = ret;
-                       obj_req->xferred = 0;
+               ret = rbd_img_exclusive_lock(img_req);
+               if (ret < 0) {
+                       *result = ret;
                        return true;
                }
+               img_req->state = RBD_IMG_EXCLUSIVE_LOCK;
+               if (ret > 0)
+                       goto again;
                return false;
-       case RBD_OBJ_WRITE_COPYUP_EMPTY_SNAPC:
-               if (obj_req->result)
+       case RBD_IMG_EXCLUSIVE_LOCK:
+               if (*result)
                        return true;
 
-               obj_req->write_state = RBD_OBJ_WRITE_COPYUP_OPS;
-               ret = rbd_obj_issue_copyup_ops(obj_req, MODS_ONLY);
-               if (ret) {
-                       obj_req->result = ret;
-                       return true;
+               rbd_assert(!need_exclusive_lock(img_req) ||
+                          __rbd_is_lock_owner(rbd_dev));
+
+               rbd_img_object_requests(img_req);
+               if (!img_req->pending.num_pending) {
+                       *result = img_req->pending.result;
+                       img_req->state = RBD_IMG_OBJECT_REQUESTS;
+                       goto again;
                }
+               img_req->state = __RBD_IMG_OBJECT_REQUESTS;
                return false;
+       case __RBD_IMG_OBJECT_REQUESTS:
+               if (!pending_result_dec(&img_req->pending, result))
+                       return false;
+               /* fall through */
+       case RBD_IMG_OBJECT_REQUESTS:
+               return true;
        default:
                BUG();
        }
 }
 
 /*
- * Returns true if @obj_req is completed, or false otherwise.
+ * Return true if @img_req is completed.
  */
-static bool __rbd_obj_handle_request(struct rbd_obj_request *obj_req)
-{
-       switch (obj_req->img_request->op_type) {
-       case OBJ_OP_READ:
-               return rbd_obj_handle_read(obj_req);
-       case OBJ_OP_WRITE:
-               return rbd_obj_handle_write(obj_req);
-       case OBJ_OP_DISCARD:
-       case OBJ_OP_ZEROOUT:
-               if (rbd_obj_handle_write(obj_req)) {
-                       /*
-                        * Hide -ENOENT from delete/truncate/zero -- discarding
-                        * a non-existent object is not a problem.
-                        */
-                       if (obj_req->result == -ENOENT) {
-                               obj_req->result = 0;
-                               obj_req->xferred = obj_req->ex.oe_len;
-                       }
-                       return true;
-               }
-               return false;
-       default:
-               BUG();
-       }
-}
-
-static void rbd_obj_end_request(struct rbd_obj_request *obj_req)
+static bool __rbd_img_handle_request(struct rbd_img_request *img_req,
+                                    int *result)
 {
-       struct rbd_img_request *img_req = obj_req->img_request;
+       struct rbd_device *rbd_dev = img_req->rbd_dev;
+       bool done;
 
-       rbd_assert((!obj_req->result &&
-                   obj_req->xferred == obj_req->ex.oe_len) ||
-                  (obj_req->result < 0 && !obj_req->xferred));
-       if (!obj_req->result) {
-               img_req->xferred += obj_req->xferred;
-               return;
+       if (need_exclusive_lock(img_req)) {
+               down_read(&rbd_dev->lock_rwsem);
+               mutex_lock(&img_req->state_mutex);
+               done = rbd_img_advance(img_req, result);
+               if (done)
+                       rbd_lock_del_request(img_req);
+               mutex_unlock(&img_req->state_mutex);
+               up_read(&rbd_dev->lock_rwsem);
+       } else {
+               mutex_lock(&img_req->state_mutex);
+               done = rbd_img_advance(img_req, result);
+               mutex_unlock(&img_req->state_mutex);
        }
 
-       rbd_warn(img_req->rbd_dev,
-                "%s at objno %llu %llu~%llu result %d xferred %llu",
-                obj_op_name(img_req->op_type), obj_req->ex.oe_objno,
-                obj_req->ex.oe_off, obj_req->ex.oe_len, obj_req->result,
-                obj_req->xferred);
-       if (!img_req->result) {
-               img_req->result = obj_req->result;
-               img_req->xferred = 0;
+       if (done && *result) {
+               rbd_assert(*result < 0);
+               rbd_warn(rbd_dev, "%s%s result %d",
+                     test_bit(IMG_REQ_CHILD, &img_req->flags) ? "child " : "",
+                     obj_op_name(img_req->op_type), *result);
        }
+       return done;
 }
 
-static void rbd_img_end_child_request(struct rbd_img_request *img_req)
-{
-       struct rbd_obj_request *obj_req = img_req->obj_request;
-
-       rbd_assert(test_bit(IMG_REQ_CHILD, &img_req->flags));
-       rbd_assert((!img_req->result &&
-                   img_req->xferred == rbd_obj_img_extents_bytes(obj_req)) ||
-                  (img_req->result < 0 && !img_req->xferred));
-
-       obj_req->result = img_req->result;
-       obj_req->xferred = img_req->xferred;
-       rbd_img_request_put(img_req);
-}
-
-static void rbd_img_end_request(struct rbd_img_request *img_req)
-{
-       rbd_assert(!test_bit(IMG_REQ_CHILD, &img_req->flags));
-       rbd_assert((!img_req->result &&
-                   img_req->xferred == blk_rq_bytes(img_req->rq)) ||
-                  (img_req->result < 0 && !img_req->xferred));
-
-       blk_mq_end_request(img_req->rq,
-                          errno_to_blk_status(img_req->result));
-       rbd_img_request_put(img_req);
-}
-
-static void rbd_obj_handle_request(struct rbd_obj_request *obj_req)
+static void rbd_img_handle_request(struct rbd_img_request *img_req, int result)
 {
-       struct rbd_img_request *img_req;
-
 again:
-       if (!__rbd_obj_handle_request(obj_req))
-               return;
-
-       img_req = obj_req->img_request;
-       spin_lock(&img_req->completion_lock);
-       rbd_obj_end_request(obj_req);
-       rbd_assert(img_req->pending_count);
-       if (--img_req->pending_count) {
-               spin_unlock(&img_req->completion_lock);
+       if (!__rbd_img_handle_request(img_req, &result))
                return;
-       }
 
-       spin_unlock(&img_req->completion_lock);
        if (test_bit(IMG_REQ_CHILD, &img_req->flags)) {
-               obj_req = img_req->obj_request;
-               rbd_img_end_child_request(img_req);
-               goto again;
+               struct rbd_obj_request *obj_req = img_req->obj_request;
+
+               rbd_img_request_put(img_req);
+               if (__rbd_obj_handle_request(obj_req, &result)) {
+                       img_req = obj_req->img_request;
+                       goto again;
+               }
+       } else {
+               struct request *rq = img_req->rq;
+
+               rbd_img_request_put(img_req);
+               blk_mq_end_request(rq, errno_to_blk_status(result));
        }
-       rbd_img_end_request(img_req);
 }
 
 static const struct rbd_client_id rbd_empty_cid;
@@ -2839,6 +3772,7 @@ static void __rbd_lock(struct rbd_device *rbd_dev, const char *cookie)
 {
        struct rbd_client_id cid = rbd_get_cid(rbd_dev);
 
+       rbd_dev->lock_state = RBD_LOCK_STATE_LOCKED;
        strcpy(rbd_dev->lock_cookie, cookie);
        rbd_set_owner_cid(rbd_dev, &cid);
        queue_work(rbd_dev->task_wq, &rbd_dev->acquired_lock_work);
@@ -2863,7 +3797,6 @@ static int rbd_lock(struct rbd_device *rbd_dev)
        if (ret)
                return ret;
 
-       rbd_dev->lock_state = RBD_LOCK_STATE_LOCKED;
        __rbd_lock(rbd_dev, cookie);
        return 0;
 }
@@ -2882,7 +3815,7 @@ static void rbd_unlock(struct rbd_device *rbd_dev)
        ret = ceph_cls_unlock(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc,
                              RBD_LOCK_NAME, rbd_dev->lock_cookie);
        if (ret && ret != -ENOENT)
-               rbd_warn(rbd_dev, "failed to unlock: %d", ret);
+               rbd_warn(rbd_dev, "failed to unlock header: %d", ret);
 
        /* treat errors as the image is unlocked */
        rbd_dev->lock_state = RBD_LOCK_STATE_UNLOCKED;
@@ -3009,15 +3942,34 @@ e_inval:
        goto out;
 }
 
-static void wake_requests(struct rbd_device *rbd_dev, bool wake_all)
+/*
+ * Either image request state machine(s) or rbd_add_acquire_lock()
+ * (i.e. "rbd map").
+ */
+static void wake_lock_waiters(struct rbd_device *rbd_dev, int result)
 {
-       dout("%s rbd_dev %p wake_all %d\n", __func__, rbd_dev, wake_all);
+       struct rbd_img_request *img_req;
+
+       dout("%s rbd_dev %p result %d\n", __func__, rbd_dev, result);
+       lockdep_assert_held_write(&rbd_dev->lock_rwsem);
 
        cancel_delayed_work(&rbd_dev->lock_dwork);
-       if (wake_all)
-               wake_up_all(&rbd_dev->lock_waitq);
-       else
-               wake_up(&rbd_dev->lock_waitq);
+       if (!completion_done(&rbd_dev->acquire_wait)) {
+               rbd_assert(list_empty(&rbd_dev->acquiring_list) &&
+                          list_empty(&rbd_dev->running_list));
+               rbd_dev->acquire_err = result;
+               complete_all(&rbd_dev->acquire_wait);
+               return;
+       }
+
+       list_for_each_entry(img_req, &rbd_dev->acquiring_list, lock_item) {
+               mutex_lock(&img_req->state_mutex);
+               rbd_assert(img_req->state == RBD_IMG_EXCLUSIVE_LOCK);
+               rbd_img_schedule(img_req, result);
+               mutex_unlock(&img_req->state_mutex);
+       }
+
+       list_splice_tail_init(&rbd_dev->acquiring_list, &rbd_dev->running_list);
 }
 
 static int get_lock_owner_info(struct rbd_device *rbd_dev,
@@ -3132,13 +4084,10 @@ static int rbd_try_lock(struct rbd_device *rbd_dev)
                        goto again;
 
                ret = find_watcher(rbd_dev, lockers);
-               if (ret) {
-                       if (ret > 0)
-                               ret = 0; /* have to request lock */
-                       goto out;
-               }
+               if (ret)
+                       goto out; /* request lock or error */
 
-               rbd_warn(rbd_dev, "%s%llu seems dead, breaking lock",
+               rbd_warn(rbd_dev, "breaking header lock owned by %s%llu",
                         ENTITY_NAME(lockers[0].id.name));
 
                ret = ceph_monc_blacklist_add(&client->monc,
@@ -3165,53 +4114,90 @@ out:
        return ret;
 }
 
+static int rbd_post_acquire_action(struct rbd_device *rbd_dev)
+{
+       int ret;
+
+       if (rbd_dev->header.features & RBD_FEATURE_OBJECT_MAP) {
+               ret = rbd_object_map_open(rbd_dev);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 /*
- * ret is set only if lock_state is RBD_LOCK_STATE_UNLOCKED
+ * Return:
+ *   0 - lock acquired
+ *   1 - caller should call rbd_request_lock()
+ *  <0 - error
  */
-static enum rbd_lock_state rbd_try_acquire_lock(struct rbd_device *rbd_dev,
-                                               int *pret)
+static int rbd_try_acquire_lock(struct rbd_device *rbd_dev)
 {
-       enum rbd_lock_state lock_state;
+       int ret;
 
        down_read(&rbd_dev->lock_rwsem);
        dout("%s rbd_dev %p read lock_state %d\n", __func__, rbd_dev,
             rbd_dev->lock_state);
        if (__rbd_is_lock_owner(rbd_dev)) {
-               lock_state = rbd_dev->lock_state;
                up_read(&rbd_dev->lock_rwsem);
-               return lock_state;
+               return 0;
        }
 
        up_read(&rbd_dev->lock_rwsem);
        down_write(&rbd_dev->lock_rwsem);
        dout("%s rbd_dev %p write lock_state %d\n", __func__, rbd_dev,
             rbd_dev->lock_state);
-       if (!__rbd_is_lock_owner(rbd_dev)) {
-               *pret = rbd_try_lock(rbd_dev);
-               if (*pret)
-                       rbd_warn(rbd_dev, "failed to acquire lock: %d", *pret);
+       if (__rbd_is_lock_owner(rbd_dev)) {
+               up_write(&rbd_dev->lock_rwsem);
+               return 0;
+       }
+
+       ret = rbd_try_lock(rbd_dev);
+       if (ret < 0) {
+               rbd_warn(rbd_dev, "failed to lock header: %d", ret);
+               if (ret == -EBLACKLISTED)
+                       goto out;
+
+               ret = 1; /* request lock anyway */
+       }
+       if (ret > 0) {
+               up_write(&rbd_dev->lock_rwsem);
+               return ret;
+       }
+
+       rbd_assert(rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED);
+       rbd_assert(list_empty(&rbd_dev->running_list));
+
+       ret = rbd_post_acquire_action(rbd_dev);
+       if (ret) {
+               rbd_warn(rbd_dev, "post-acquire action failed: %d", ret);
+               /*
+                * Can't stay in RBD_LOCK_STATE_LOCKED because
+                * rbd_lock_add_request() would let the request through,
+                * assuming that e.g. object map is locked and loaded.
+                */
+               rbd_unlock(rbd_dev);
        }
 
-       lock_state = rbd_dev->lock_state;
+out:
+       wake_lock_waiters(rbd_dev, ret);
        up_write(&rbd_dev->lock_rwsem);
-       return lock_state;
+       return ret;
 }
 
 static void rbd_acquire_lock(struct work_struct *work)
 {
        struct rbd_device *rbd_dev = container_of(to_delayed_work(work),
                                            struct rbd_device, lock_dwork);
-       enum rbd_lock_state lock_state;
-       int ret = 0;
+       int ret;
 
        dout("%s rbd_dev %p\n", __func__, rbd_dev);
 again:
-       lock_state = rbd_try_acquire_lock(rbd_dev, &ret);
-       if (lock_state != RBD_LOCK_STATE_UNLOCKED || ret == -EBLACKLISTED) {
-               if (lock_state == RBD_LOCK_STATE_LOCKED)
-                       wake_requests(rbd_dev, true);
-               dout("%s rbd_dev %p lock_state %d ret %d - done\n", __func__,
-                    rbd_dev, lock_state, ret);
+       ret = rbd_try_acquire_lock(rbd_dev);
+       if (ret <= 0) {
+               dout("%s rbd_dev %p ret %d - done\n", __func__, rbd_dev, ret);
                return;
        }
 
@@ -3220,16 +4206,9 @@ again:
                goto again; /* treat this as a dead client */
        } else if (ret == -EROFS) {
                rbd_warn(rbd_dev, "peer will not release lock");
-               /*
-                * If this is rbd_add_acquire_lock(), we want to fail
-                * immediately -- reuse BLACKLISTED flag.  Otherwise we
-                * want to block.
-                */
-               if (!(rbd_dev->disk->flags & GENHD_FL_UP)) {
-                       set_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags);
-                       /* wake "rbd map --exclusive" process */
-                       wake_requests(rbd_dev, false);
-               }
+               down_write(&rbd_dev->lock_rwsem);
+               wake_lock_waiters(rbd_dev, ret);
+               up_write(&rbd_dev->lock_rwsem);
        } else if (ret < 0) {
                rbd_warn(rbd_dev, "error requesting lock: %d", ret);
                mod_delayed_work(rbd_dev->task_wq, &rbd_dev->lock_dwork,
@@ -3246,43 +4225,67 @@ again:
        }
 }
 
-/*
- * lock_rwsem must be held for write
- */
-static bool rbd_release_lock(struct rbd_device *rbd_dev)
+static bool rbd_quiesce_lock(struct rbd_device *rbd_dev)
 {
-       dout("%s rbd_dev %p read lock_state %d\n", __func__, rbd_dev,
-            rbd_dev->lock_state);
+       bool need_wait;
+
+       dout("%s rbd_dev %p\n", __func__, rbd_dev);
+       lockdep_assert_held_write(&rbd_dev->lock_rwsem);
+
        if (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED)
                return false;
 
-       rbd_dev->lock_state = RBD_LOCK_STATE_RELEASING;
-       downgrade_write(&rbd_dev->lock_rwsem);
        /*
         * Ensure that all in-flight IO is flushed.
-        *
-        * FIXME: ceph_osdc_sync() flushes the entire OSD client, which
-        * may be shared with other devices.
         */
-       ceph_osdc_sync(&rbd_dev->rbd_client->client->osdc);
+       rbd_dev->lock_state = RBD_LOCK_STATE_RELEASING;
+       rbd_assert(!completion_done(&rbd_dev->releasing_wait));
+       need_wait = !list_empty(&rbd_dev->running_list);
+       downgrade_write(&rbd_dev->lock_rwsem);
+       if (need_wait)
+               wait_for_completion(&rbd_dev->releasing_wait);
        up_read(&rbd_dev->lock_rwsem);
 
        down_write(&rbd_dev->lock_rwsem);
-       dout("%s rbd_dev %p write lock_state %d\n", __func__, rbd_dev,
-            rbd_dev->lock_state);
        if (rbd_dev->lock_state != RBD_LOCK_STATE_RELEASING)
                return false;
 
+       rbd_assert(list_empty(&rbd_dev->running_list));
+       return true;
+}
+
+static void rbd_pre_release_action(struct rbd_device *rbd_dev)
+{
+       if (rbd_dev->header.features & RBD_FEATURE_OBJECT_MAP)
+               rbd_object_map_close(rbd_dev);
+}
+
+static void __rbd_release_lock(struct rbd_device *rbd_dev)
+{
+       rbd_assert(list_empty(&rbd_dev->running_list));
+
+       rbd_pre_release_action(rbd_dev);
        rbd_unlock(rbd_dev);
+}
+
+/*
+ * lock_rwsem must be held for write
+ */
+static void rbd_release_lock(struct rbd_device *rbd_dev)
+{
+       if (!rbd_quiesce_lock(rbd_dev))
+               return;
+
+       __rbd_release_lock(rbd_dev);
+
        /*
         * Give others a chance to grab the lock - we would re-acquire
-        * almost immediately if we got new IO during ceph_osdc_sync()
-        * otherwise.  We need to ack our own notifications, so this
-        * lock_dwork will be requeued from rbd_wait_state_locked()
-        * after wake_requests() in rbd_handle_released_lock().
+        * almost immediately if we got new IO while draining the running
+        * list otherwise.  We need to ack our own notifications, so this
+        * lock_dwork will be requeued from rbd_handle_released_lock() by
+        * way of maybe_kick_acquire().
         */
        cancel_delayed_work(&rbd_dev->lock_dwork);
-       return true;
 }
 
 static void rbd_release_lock_work(struct work_struct *work)
@@ -3295,6 +4298,23 @@ static void rbd_release_lock_work(struct work_struct *work)
        up_write(&rbd_dev->lock_rwsem);
 }
 
+static void maybe_kick_acquire(struct rbd_device *rbd_dev)
+{
+       bool have_requests;
+
+       dout("%s rbd_dev %p\n", __func__, rbd_dev);
+       if (__rbd_is_lock_owner(rbd_dev))
+               return;
+
+       spin_lock(&rbd_dev->lock_lists_lock);
+       have_requests = !list_empty(&rbd_dev->acquiring_list);
+       spin_unlock(&rbd_dev->lock_lists_lock);
+       if (have_requests || delayed_work_pending(&rbd_dev->lock_dwork)) {
+               dout("%s rbd_dev %p kicking lock_dwork\n", __func__, rbd_dev);
+               mod_delayed_work(rbd_dev->task_wq, &rbd_dev->lock_dwork, 0);
+       }
+}
+
 static void rbd_handle_acquired_lock(struct rbd_device *rbd_dev, u8 struct_v,
                                     void **p)
 {
@@ -3324,8 +4344,7 @@ static void rbd_handle_acquired_lock(struct rbd_device *rbd_dev, u8 struct_v,
                down_read(&rbd_dev->lock_rwsem);
        }
 
-       if (!__rbd_is_lock_owner(rbd_dev))
-               wake_requests(rbd_dev, false);
+       maybe_kick_acquire(rbd_dev);
        up_read(&rbd_dev->lock_rwsem);
 }
 
@@ -3357,8 +4376,7 @@ static void rbd_handle_released_lock(struct rbd_device *rbd_dev, u8 struct_v,
                down_read(&rbd_dev->lock_rwsem);
        }
 
-       if (!__rbd_is_lock_owner(rbd_dev))
-               wake_requests(rbd_dev, false);
+       maybe_kick_acquire(rbd_dev);
        up_read(&rbd_dev->lock_rwsem);
 }
 
@@ -3608,7 +4626,6 @@ static void cancel_tasks_sync(struct rbd_device *rbd_dev)
 
 static void rbd_unregister_watch(struct rbd_device *rbd_dev)
 {
-       WARN_ON(waitqueue_active(&rbd_dev->lock_waitq));
        cancel_tasks_sync(rbd_dev);
 
        mutex_lock(&rbd_dev->watch_mutex);
@@ -3630,7 +4647,8 @@ static void rbd_reacquire_lock(struct rbd_device *rbd_dev)
        char cookie[32];
        int ret;
 
-       WARN_ON(rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED);
+       if (!rbd_quiesce_lock(rbd_dev))
+               return;
 
        format_lock_cookie(rbd_dev, cookie);
        ret = ceph_cls_set_cookie(osdc, &rbd_dev->header_oid,
@@ -3646,11 +4664,11 @@ static void rbd_reacquire_lock(struct rbd_device *rbd_dev)
                 * Lock cookie cannot be updated on older OSDs, so do
                 * a manual release and queue an acquire.
                 */
-               if (rbd_release_lock(rbd_dev))
-                       queue_delayed_work(rbd_dev->task_wq,
-                                          &rbd_dev->lock_dwork, 0);
+               __rbd_release_lock(rbd_dev);
+               queue_delayed_work(rbd_dev->task_wq, &rbd_dev->lock_dwork, 0);
        } else {
                __rbd_lock(rbd_dev, cookie);
+               wake_lock_waiters(rbd_dev, 0);
        }
 }
 
@@ -3671,15 +4689,18 @@ static void rbd_reregister_watch(struct work_struct *work)
        ret = __rbd_register_watch(rbd_dev);
        if (ret) {
                rbd_warn(rbd_dev, "failed to reregister watch: %d", ret);
-               if (ret == -EBLACKLISTED || ret == -ENOENT) {
-                       set_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags);
-                       wake_requests(rbd_dev, true);
-               } else {
+               if (ret != -EBLACKLISTED && ret != -ENOENT) {
                        queue_delayed_work(rbd_dev->task_wq,
                                           &rbd_dev->watch_dwork,
                                           RBD_RETRY_DELAY);
+                       mutex_unlock(&rbd_dev->watch_mutex);
+                       return;
                }
+
                mutex_unlock(&rbd_dev->watch_mutex);
+               down_write(&rbd_dev->lock_rwsem);
+               wake_lock_waiters(rbd_dev, ret);
+               up_write(&rbd_dev->lock_rwsem);
                return;
        }
 
@@ -3742,7 +4763,7 @@ static int rbd_obj_method_sync(struct rbd_device *rbd_dev,
 
        ret = ceph_osdc_call(osdc, oid, oloc, RBD_DRV_NAME, method_name,
                             CEPH_OSD_FLAG_READ, req_page, outbound_size,
-                            reply_page, &inbound_size);
+                            &reply_page, &inbound_size);
        if (!ret) {
                memcpy(inbound, page_address(reply_page), inbound_size);
                ret = inbound_size;
@@ -3754,54 +4775,6 @@ static int rbd_obj_method_sync(struct rbd_device *rbd_dev,
        return ret;
 }
 
-/*
- * lock_rwsem must be held for read
- */
-static int rbd_wait_state_locked(struct rbd_device *rbd_dev, bool may_acquire)
-{
-       DEFINE_WAIT(wait);
-       unsigned long timeout;
-       int ret = 0;
-
-       if (test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags))
-               return -EBLACKLISTED;
-
-       if (rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED)
-               return 0;
-
-       if (!may_acquire) {
-               rbd_warn(rbd_dev, "exclusive lock required");
-               return -EROFS;
-       }
-
-       do {
-               /*
-                * Note the use of mod_delayed_work() in rbd_acquire_lock()
-                * and cancel_delayed_work() in wake_requests().
-                */
-               dout("%s rbd_dev %p queueing lock_dwork\n", __func__, rbd_dev);
-               queue_delayed_work(rbd_dev->task_wq, &rbd_dev->lock_dwork, 0);
-               prepare_to_wait_exclusive(&rbd_dev->lock_waitq, &wait,
-                                         TASK_UNINTERRUPTIBLE);
-               up_read(&rbd_dev->lock_rwsem);
-               timeout = schedule_timeout(ceph_timeout_jiffies(
-                                               rbd_dev->opts->lock_timeout));
-               down_read(&rbd_dev->lock_rwsem);
-               if (test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags)) {
-                       ret = -EBLACKLISTED;
-                       break;
-               }
-               if (!timeout) {
-                       rbd_warn(rbd_dev, "timed out waiting for lock");
-                       ret = -ETIMEDOUT;
-                       break;
-               }
-       } while (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED);
-
-       finish_wait(&rbd_dev->lock_waitq, &wait);
-       return ret;
-}
-
 static void rbd_queue_workfn(struct work_struct *work)
 {
        struct request *rq = blk_mq_rq_from_pdu(work);
@@ -3812,7 +4785,6 @@ static void rbd_queue_workfn(struct work_struct *work)
        u64 length = blk_rq_bytes(rq);
        enum obj_operation_type op_type;
        u64 mapping_size;
-       bool must_be_locked;
        int result;
 
        switch (req_op(rq)) {
@@ -3886,21 +4858,10 @@ static void rbd_queue_workfn(struct work_struct *work)
                goto err_rq;
        }
 
-       must_be_locked =
-           (rbd_dev->header.features & RBD_FEATURE_EXCLUSIVE_LOCK) &&
-           (op_type != OBJ_OP_READ || rbd_dev->opts->lock_on_read);
-       if (must_be_locked) {
-               down_read(&rbd_dev->lock_rwsem);
-               result = rbd_wait_state_locked(rbd_dev,
-                                              !rbd_dev->opts->exclusive);
-               if (result)
-                       goto err_unlock;
-       }
-
        img_request = rbd_img_request_create(rbd_dev, op_type, snapc);
        if (!img_request) {
                result = -ENOMEM;
-               goto err_unlock;
+               goto err_rq;
        }
        img_request->rq = rq;
        snapc = NULL; /* img_request consumes a ref */
@@ -3910,19 +4871,14 @@ static void rbd_queue_workfn(struct work_struct *work)
        else
                result = rbd_img_fill_from_bio(img_request, offset, length,
                                               rq->bio);
-       if (result || !img_request->pending_count)
+       if (result)
                goto err_img_request;
 
-       rbd_img_request_submit(img_request);
-       if (must_be_locked)
-               up_read(&rbd_dev->lock_rwsem);
+       rbd_img_handle_request(img_request, 0);
        return;
 
 err_img_request:
        rbd_img_request_put(img_request);
-err_unlock:
-       if (must_be_locked)
-               up_read(&rbd_dev->lock_rwsem);
 err_rq:
        if (result)
                rbd_warn(rbd_dev, "%s %llx at %llx result %d",
@@ -4589,7 +5545,13 @@ static struct rbd_device *__rbd_dev_create(struct rbd_client *rbdc,
        INIT_WORK(&rbd_dev->released_lock_work, rbd_notify_released_lock);
        INIT_DELAYED_WORK(&rbd_dev->lock_dwork, rbd_acquire_lock);
        INIT_WORK(&rbd_dev->unlock_work, rbd_release_lock_work);
-       init_waitqueue_head(&rbd_dev->lock_waitq);
+       spin_lock_init(&rbd_dev->lock_lists_lock);
+       INIT_LIST_HEAD(&rbd_dev->acquiring_list);
+       INIT_LIST_HEAD(&rbd_dev->running_list);
+       init_completion(&rbd_dev->acquire_wait);
+       init_completion(&rbd_dev->releasing_wait);
+
+       spin_lock_init(&rbd_dev->object_map_lock);
 
        rbd_dev->dev.bus = &rbd_bus_type;
        rbd_dev->dev.type = &rbd_device_type;
@@ -4772,6 +5734,32 @@ static int rbd_dev_v2_features(struct rbd_device *rbd_dev)
                                                &rbd_dev->header.features);
 }
 
+/*
+ * These are generic image flags, but since they are used only for
+ * object map, store them in rbd_dev->object_map_flags.
+ *
+ * For the same reason, this function is called only on object map
+ * (re)load and not on header refresh.
+ */
+static int rbd_dev_v2_get_flags(struct rbd_device *rbd_dev)
+{
+       __le64 snapid = cpu_to_le64(rbd_dev->spec->snap_id);
+       __le64 flags;
+       int ret;
+
+       ret = rbd_obj_method_sync(rbd_dev, &rbd_dev->header_oid,
+                                 &rbd_dev->header_oloc, "get_flags",
+                                 &snapid, sizeof(snapid),
+                                 &flags, sizeof(flags));
+       if (ret < 0)
+               return ret;
+       if (ret < sizeof(flags))
+               return -EBADMSG;
+
+       rbd_dev->object_map_flags = le64_to_cpu(flags);
+       return 0;
+}
+
 struct parent_image_info {
        u64             pool_id;
        const char      *pool_ns;
@@ -4829,7 +5817,7 @@ static int __get_parent_info(struct rbd_device *rbd_dev,
 
        ret = ceph_osdc_call(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc,
                             "rbd", "parent_get", CEPH_OSD_FLAG_READ,
-                            req_page, sizeof(u64), reply_page, &reply_len);
+                            req_page, sizeof(u64), &reply_page, &reply_len);
        if (ret)
                return ret == -EOPNOTSUPP ? 1 : ret;
 
@@ -4841,7 +5829,7 @@ static int __get_parent_info(struct rbd_device *rbd_dev,
 
        ret = ceph_osdc_call(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc,
                             "rbd", "parent_overlap_get", CEPH_OSD_FLAG_READ,
-                            req_page, sizeof(u64), reply_page, &reply_len);
+                            req_page, sizeof(u64), &reply_page, &reply_len);
        if (ret)
                return ret;
 
@@ -4872,7 +5860,7 @@ static int __get_parent_info_legacy(struct rbd_device *rbd_dev,
 
        ret = ceph_osdc_call(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc,
                             "rbd", "get_parent", CEPH_OSD_FLAG_READ,
-                            req_page, sizeof(u64), reply_page, &reply_len);
+                            req_page, sizeof(u64), &reply_page, &reply_len);
        if (ret)
                return ret;
 
@@ -5605,28 +6593,49 @@ static void rbd_dev_image_unlock(struct rbd_device *rbd_dev)
 {
        down_write(&rbd_dev->lock_rwsem);
        if (__rbd_is_lock_owner(rbd_dev))
-               rbd_unlock(rbd_dev);
+               __rbd_release_lock(rbd_dev);
        up_write(&rbd_dev->lock_rwsem);
 }
 
+/*
+ * If the wait is interrupted, an error is returned even if the lock
+ * was successfully acquired.  rbd_dev_image_unlock() will release it
+ * if needed.
+ */
 static int rbd_add_acquire_lock(struct rbd_device *rbd_dev)
 {
-       int ret;
+       long ret;
 
        if (!(rbd_dev->header.features & RBD_FEATURE_EXCLUSIVE_LOCK)) {
+               if (!rbd_dev->opts->exclusive && !rbd_dev->opts->lock_on_read)
+                       return 0;
+
                rbd_warn(rbd_dev, "exclusive-lock feature is not enabled");
                return -EINVAL;
        }
 
-       /* FIXME: "rbd map --exclusive" should be in interruptible */
-       down_read(&rbd_dev->lock_rwsem);
-       ret = rbd_wait_state_locked(rbd_dev, true);
-       up_read(&rbd_dev->lock_rwsem);
+       if (rbd_dev->spec->snap_id != CEPH_NOSNAP)
+               return 0;
+
+       rbd_assert(!rbd_is_lock_owner(rbd_dev));
+       queue_delayed_work(rbd_dev->task_wq, &rbd_dev->lock_dwork, 0);
+       ret = wait_for_completion_killable_timeout(&rbd_dev->acquire_wait,
+                           ceph_timeout_jiffies(rbd_dev->opts->lock_timeout));
+       if (ret > 0)
+               ret = rbd_dev->acquire_err;
+       else if (!ret)
+               ret = -ETIMEDOUT;
+
        if (ret) {
-               rbd_warn(rbd_dev, "failed to acquire exclusive lock");
-               return -EROFS;
+               rbd_warn(rbd_dev, "failed to acquire exclusive lock: %ld", ret);
+               return ret;
        }
 
+       /*
+        * The lock may have been released by now, unless automatic lock
+        * transitions are disabled.
+        */
+       rbd_assert(!rbd_dev->opts->exclusive || rbd_is_lock_owner(rbd_dev));
        return 0;
 }
 
@@ -5724,6 +6733,8 @@ static void rbd_dev_unprobe(struct rbd_device *rbd_dev)
        struct rbd_image_header *header;
 
        rbd_dev_parent_put(rbd_dev);
+       rbd_object_map_free(rbd_dev);
+       rbd_dev_mapping_clear(rbd_dev);
 
        /* Free dynamic fields from the header, then zero it out */
 
@@ -5824,7 +6835,6 @@ out_err:
 static void rbd_dev_device_release(struct rbd_device *rbd_dev)
 {
        clear_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags);
-       rbd_dev_mapping_clear(rbd_dev);
        rbd_free_disk(rbd_dev);
        if (!single_major)
                unregister_blkdev(rbd_dev->major, rbd_dev->name);
@@ -5858,23 +6868,17 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev)
        if (ret)
                goto err_out_blkdev;
 
-       ret = rbd_dev_mapping_set(rbd_dev);
-       if (ret)
-               goto err_out_disk;
-
        set_capacity(rbd_dev->disk, rbd_dev->mapping.size / SECTOR_SIZE);
        set_disk_ro(rbd_dev->disk, rbd_dev->opts->read_only);
 
        ret = dev_set_name(&rbd_dev->dev, "%d", rbd_dev->dev_id);
        if (ret)
-               goto err_out_mapping;
+               goto err_out_disk;
 
        set_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags);
        up_write(&rbd_dev->header_rwsem);
        return 0;
 
-err_out_mapping:
-       rbd_dev_mapping_clear(rbd_dev);
 err_out_disk:
        rbd_free_disk(rbd_dev);
 err_out_blkdev:
@@ -5975,6 +6979,17 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
                goto err_out_probe;
        }
 
+       ret = rbd_dev_mapping_set(rbd_dev);
+       if (ret)
+               goto err_out_probe;
+
+       if (rbd_dev->spec->snap_id != CEPH_NOSNAP &&
+           (rbd_dev->header.features & RBD_FEATURE_OBJECT_MAP)) {
+               ret = rbd_object_map_load(rbd_dev);
+               if (ret)
+                       goto err_out_probe;
+       }
+
        if (rbd_dev->header.features & RBD_FEATURE_LAYERING) {
                ret = rbd_dev_v2_parent_info(rbd_dev);
                if (ret)
@@ -6071,11 +7086,9 @@ static ssize_t do_rbd_add(struct bus_type *bus,
        if (rc)
                goto err_out_image_probe;
 
-       if (rbd_dev->opts->exclusive) {
-               rc = rbd_add_acquire_lock(rbd_dev);
-               if (rc)
-                       goto err_out_device_setup;
-       }
+       rc = rbd_add_acquire_lock(rbd_dev);
+       if (rc)
+               goto err_out_image_lock;
 
        /* Everything's ready.  Announce the disk to the world. */
 
@@ -6101,7 +7114,6 @@ out:
 
 err_out_image_lock:
        rbd_dev_image_unlock(rbd_dev);
-err_out_device_setup:
        rbd_dev_device_release(rbd_dev);
 err_out_image_probe:
        rbd_dev_image_release(rbd_dev);
index 62ff50d..ac98ab6 100644 (file)
@@ -18,6 +18,7 @@
 /* For format version 2, rbd image 'foo' consists of objects
  *   rbd_id.foo                - id of image
  *   rbd_header.<id>   - image metadata
+ *   rbd_object_map.<id> - optional image object map
  *   rbd_data.<id>.0000000000000000
  *   rbd_data.<id>.0000000000000001
  *   ...               - data
@@ -25,6 +26,7 @@
  */
 
 #define RBD_HEADER_PREFIX      "rbd_header."
+#define RBD_OBJECT_MAP_PREFIX  "rbd_object_map."
 #define RBD_ID_PREFIX          "rbd_id."
 #define RBD_V2_DATA_FORMAT     "%s.%016llx"
 
@@ -39,6 +41,14 @@ enum rbd_notify_op {
        RBD_NOTIFY_OP_HEADER_UPDATE      = 3,
 };
 
+#define OBJECT_NONEXISTENT     0
+#define OBJECT_EXISTS          1
+#define OBJECT_PENDING         2
+#define OBJECT_EXISTS_CLEAN    3
+
+#define RBD_FLAG_OBJECT_MAP_INVALID    (1ULL << 0)
+#define RBD_FLAG_FAST_DIFF_INVALID     (1ULL << 1)
+
 /*
  * For format version 1, rbd image 'foo' consists of objects
  *   foo.rbd           - image metadata
index 1ffc647..fe7a4b7 100644 (file)
@@ -12,7 +12,7 @@ config ZRAM
          It has several use cases, for example: /tmp storage, use as swap
          disks and maybe many more.
 
-         See Documentation/blockdev/zram.txt for more information.
+         See Documentation/admin-guide/blockdev/zram.rst for more information.
 
 config ZRAM_WRITEBACK
        bool "Write back incompressible or idle page to backing device"
@@ -26,7 +26,7 @@ config ZRAM_WRITEBACK
         With /sys/block/zramX/{idle,writeback}, application could ask
         idle page's writeback to the backing device to save in memory.
 
-        See Documentation/blockdev/zram.txt for more information.
+        See Documentation/admin-guide/blockdev/zram.rst for more information.
 
 config ZRAM_MEMORY_TRACKING
        bool "Track zRam block status"
@@ -36,4 +36,4 @@ config ZRAM_MEMORY_TRACKING
          of zRAM. Admin could see the information via
          /sys/kernel/debug/zram/zramX/block_state.
 
-         See Documentation/blockdev/zram.txt for more information.
+         See Documentation/admin-guide/blockdev/zram.rst for more information.
index 972854c..ec1004c 100644 (file)
@@ -399,8 +399,8 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
                                               &gisb_panic_notifier);
        }
 
-       dev_info(&pdev->dev, "registered mem: %p, irqs: %d, %d\n",
-                       gdev->base, timeout_irq, tea_irq);
+       dev_info(&pdev->dev, "registered irqs: %d, %d\n",
+                timeout_irq, tea_irq);
 
        return 0;
 }
index 1c3f621..0fe3f52 100644 (file)
@@ -443,11 +443,31 @@ int dprc_get_obj_region(struct fsl_mc_io *mc_io,
        struct fsl_mc_command cmd = { 0 };
        struct dprc_cmd_get_obj_region *cmd_params;
        struct dprc_rsp_get_obj_region *rsp_params;
+       u16 major_ver, minor_ver;
        int err;
 
        /* prepare command */
-       cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG,
-                                         cmd_flags, token);
+       err = dprc_get_api_version(mc_io, 0,
+                                    &major_ver,
+                                    &minor_ver);
+       if (err)
+               return err;
+
+       /**
+        * MC API version 6.3 introduced a new field to the region
+        * descriptor: base_address. If the older API is in use then the base
+        * address is set to zero to indicate it needs to be obtained elsewhere
+        * (typically the device tree).
+        */
+       if (major_ver > 6 || (major_ver == 6 && minor_ver >= 3))
+               cmd.header =
+                       mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG_V2,
+                                            cmd_flags, token);
+       else
+               cmd.header =
+                       mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG,
+                                            cmd_flags, token);
+
        cmd_params = (struct dprc_cmd_get_obj_region *)cmd.params;
        cmd_params->obj_id = cpu_to_le32(obj_id);
        cmd_params->region_index = region_index;
@@ -461,8 +481,12 @@ int dprc_get_obj_region(struct fsl_mc_io *mc_io,
 
        /* retrieve response parameters */
        rsp_params = (struct dprc_rsp_get_obj_region *)cmd.params;
-       region_desc->base_offset = le64_to_cpu(rsp_params->base_addr);
+       region_desc->base_offset = le64_to_cpu(rsp_params->base_offset);
        region_desc->size = le32_to_cpu(rsp_params->size);
+       if (major_ver > 6 || (major_ver == 6 && minor_ver >= 3))
+               region_desc->base_address = le64_to_cpu(rsp_params->base_addr);
+       else
+               region_desc->base_address = 0;
 
        return 0;
 }
index f0404c6..5c9bf2e 100644 (file)
@@ -487,10 +487,19 @@ static int fsl_mc_device_get_mmio_regions(struct fsl_mc_device *mc_dev,
                                "dprc_get_obj_region() failed: %d\n", error);
                        goto error_cleanup_regions;
                }
-
-               error = translate_mc_addr(mc_dev, mc_region_type,
+               /*
+                * Older MC only returned region offset and no base address
+                * If base address is in the region_desc use it otherwise
+                * revert to old mechanism
+                */
+               if (region_desc.base_address)
+                       regions[i].start = region_desc.base_address +
+                                               region_desc.base_offset;
+               else
+                       error = translate_mc_addr(mc_dev, mc_region_type,
                                          region_desc.base_offset,
                                          &regions[i].start);
+
                if (error < 0) {
                        dev_err(parent_dev,
                                "Invalid MC offset: %#x (for %s.%d\'s region %d)\n",
@@ -504,6 +513,8 @@ static int fsl_mc_device_get_mmio_regions(struct fsl_mc_device *mc_dev,
                regions[i].flags = IORESOURCE_IO;
                if (region_desc.flags & DPRC_REGION_CACHEABLE)
                        regions[i].flags |= IORESOURCE_CACHEABLE;
+               if (region_desc.flags & DPRC_REGION_SHAREABLE)
+                       regions[i].flags |= IORESOURCE_MEM;
        }
 
        mc_dev->regions = regions;
index ea11b4f..020fcc0 100644 (file)
@@ -79,9 +79,11 @@ int dpmcp_reset(struct fsl_mc_io *mc_io,
 
 /* DPRC command versioning */
 #define DPRC_CMD_BASE_VERSION                  1
+#define DPRC_CMD_2ND_VERSION                   2
 #define DPRC_CMD_ID_OFFSET                     4
 
 #define DPRC_CMD(id)   (((id) << DPRC_CMD_ID_OFFSET) | DPRC_CMD_BASE_VERSION)
+#define DPRC_CMD_V2(id)        (((id) << DPRC_CMD_ID_OFFSET) | DPRC_CMD_2ND_VERSION)
 
 /* DPRC command IDs */
 #define DPRC_CMDID_CLOSE                        DPRC_CMD(0x800)
@@ -100,6 +102,7 @@ int dpmcp_reset(struct fsl_mc_io *mc_io,
 #define DPRC_CMDID_GET_OBJ_COUNT                DPRC_CMD(0x159)
 #define DPRC_CMDID_GET_OBJ                      DPRC_CMD(0x15A)
 #define DPRC_CMDID_GET_OBJ_REG                  DPRC_CMD(0x15E)
+#define DPRC_CMDID_GET_OBJ_REG_V2               DPRC_CMD_V2(0x15E)
 #define DPRC_CMDID_SET_OBJ_IRQ                  DPRC_CMD(0x15F)
 
 struct dprc_cmd_open {
@@ -199,9 +202,16 @@ struct dprc_rsp_get_obj_region {
        /* response word 0 */
        __le64 pad;
        /* response word 1 */
-       __le64 base_addr;
+       __le64 base_offset;
        /* response word 2 */
        __le32 size;
+       __le32 pad2;
+       /* response word 3 */
+       __le32 flags;
+       __le32 pad3;
+       /* response word 4 */
+       /* base_addr may be zero if older MC firmware is used */
+       __le64 base_addr;
 };
 
 struct dprc_cmd_set_obj_irq {
@@ -334,6 +344,7 @@ int dprc_set_obj_irq(struct fsl_mc_io *mc_io,
 /* Region flags */
 /* Cacheable - Indicates that region should be mapped as cacheable */
 #define DPRC_REGION_CACHEABLE  0x00000001
+#define DPRC_REGION_SHAREABLE  0x00000002
 
 /**
  * enum dprc_region_type - Region type
@@ -342,7 +353,8 @@ int dprc_set_obj_irq(struct fsl_mc_io *mc_io,
  */
 enum dprc_region_type {
        DPRC_REGION_TYPE_MC_PORTAL,
-       DPRC_REGION_TYPE_QBMAN_PORTAL
+       DPRC_REGION_TYPE_QBMAN_PORTAL,
+       DPRC_REGION_TYPE_QBMAN_MEM_BACKED_PORTAL
 };
 
 /**
@@ -360,6 +372,7 @@ struct dprc_region_desc {
        u32 size;
        u32 flags;
        enum dprc_region_type type;
+       u64 base_address;
 };
 
 int dprc_get_obj_region(struct fsl_mc_io *mc_io,
index b727416..e6deabd 100644 (file)
@@ -71,6 +71,9 @@ static const char * const clock_names[SYSC_MAX_CLOCKS] = {
  * @name: name if available
  * @revision: interconnect target module revision
  * @needs_resume: runtime resume needed on resume from suspend
+ * @clk_enable_quirk: module specific clock enable quirk
+ * @clk_disable_quirk: module specific clock disable quirk
+ * @reset_done_quirk: module specific reset done quirk
  */
 struct sysc {
        struct device *dev;
@@ -89,10 +92,14 @@ struct sysc {
        struct ti_sysc_cookie cookie;
        const char *name;
        u32 revision;
-       bool enabled;
-       bool needs_resume;
-       bool child_needs_resume;
+       unsigned int enabled:1;
+       unsigned int needs_resume:1;
+       unsigned int child_needs_resume:1;
+       unsigned int disable_on_idle:1;
        struct delayed_work idle_work;
+       void (*clk_enable_quirk)(struct sysc *sysc);
+       void (*clk_disable_quirk)(struct sysc *sysc);
+       void (*reset_done_quirk)(struct sysc *sysc);
 };
 
 static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np,
@@ -100,6 +107,20 @@ static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np,
 
 static void sysc_write(struct sysc *ddata, int offset, u32 value)
 {
+       if (ddata->cfg.quirks & SYSC_QUIRK_16BIT) {
+               writew_relaxed(value & 0xffff, ddata->module_va + offset);
+
+               /* Only i2c revision has LO and HI register with stride of 4 */
+               if (ddata->offsets[SYSC_REVISION] >= 0 &&
+                   offset == ddata->offsets[SYSC_REVISION]) {
+                       u16 hi = value >> 16;
+
+                       writew_relaxed(hi, ddata->module_va + offset + 4);
+               }
+
+               return;
+       }
+
        writel_relaxed(value, ddata->module_va + offset);
 }
 
@@ -109,7 +130,14 @@ static u32 sysc_read(struct sysc *ddata, int offset)
                u32 val;
 
                val = readw_relaxed(ddata->module_va + offset);
-               val |= (readw_relaxed(ddata->module_va + offset + 4) << 16);
+
+               /* Only i2c revision has LO and HI register with stride of 4 */
+               if (ddata->offsets[SYSC_REVISION] >= 0 &&
+                   offset == ddata->offsets[SYSC_REVISION]) {
+                       u16 tmp = readw_relaxed(ddata->module_va + offset + 4);
+
+                       val |= tmp << 16;
+               }
 
                return val;
        }
@@ -132,6 +160,26 @@ static u32 sysc_read_revision(struct sysc *ddata)
        return sysc_read(ddata, offset);
 }
 
+static u32 sysc_read_sysconfig(struct sysc *ddata)
+{
+       int offset = ddata->offsets[SYSC_SYSCONFIG];
+
+       if (offset < 0)
+               return 0;
+
+       return sysc_read(ddata, offset);
+}
+
+static u32 sysc_read_sysstatus(struct sysc *ddata)
+{
+       int offset = ddata->offsets[SYSC_SYSSTATUS];
+
+       if (offset < 0)
+               return 0;
+
+       return sysc_read(ddata, offset);
+}
+
 static int sysc_add_named_clock_from_child(struct sysc *ddata,
                                           const char *name,
                                           const char *optfck_name)
@@ -422,6 +470,30 @@ static void sysc_disable_opt_clocks(struct sysc *ddata)
        }
 }
 
+static void sysc_clkdm_deny_idle(struct sysc *ddata)
+{
+       struct ti_sysc_platform_data *pdata;
+
+       if (ddata->legacy_mode)
+               return;
+
+       pdata = dev_get_platdata(ddata->dev);
+       if (pdata && pdata->clkdm_deny_idle)
+               pdata->clkdm_deny_idle(ddata->dev, &ddata->cookie);
+}
+
+static void sysc_clkdm_allow_idle(struct sysc *ddata)
+{
+       struct ti_sysc_platform_data *pdata;
+
+       if (ddata->legacy_mode)
+               return;
+
+       pdata = dev_get_platdata(ddata->dev);
+       if (pdata && pdata->clkdm_allow_idle)
+               pdata->clkdm_allow_idle(ddata->dev, &ddata->cookie);
+}
+
 /**
  * sysc_init_resets - init rstctrl reset line if configured
  * @ddata: device driver data
@@ -431,7 +503,7 @@ static void sysc_disable_opt_clocks(struct sysc *ddata)
 static int sysc_init_resets(struct sysc *ddata)
 {
        ddata->rsts =
-               devm_reset_control_array_get_optional_exclusive(ddata->dev);
+               devm_reset_control_get_optional(ddata->dev, "rstctrl");
        if (IS_ERR(ddata->rsts))
                return PTR_ERR(ddata->rsts);
 
@@ -694,8 +766,11 @@ static int sysc_ioremap(struct sysc *ddata)
                            ddata->offsets[SYSC_SYSCONFIG],
                            ddata->offsets[SYSC_SYSSTATUS]);
 
+               if (size < SZ_1K)
+                       size = SZ_1K;
+
                if ((size + sizeof(u32)) > ddata->module_size)
-                       return -EINVAL;
+                       size = ddata->module_size;
        }
 
        ddata->module_va = devm_ioremap(ddata->dev,
@@ -794,7 +869,9 @@ static void sysc_show_registers(struct sysc *ddata)
 }
 
 #define SYSC_IDLE_MASK (SYSC_NR_IDLEMODES - 1)
+#define SYSC_CLOCACT_ICK       2
 
+/* Caller needs to manage sysc_clkdm_deny_idle() and sysc_clkdm_allow_idle() */
 static int sysc_enable_module(struct device *dev)
 {
        struct sysc *ddata;
@@ -805,23 +882,34 @@ static int sysc_enable_module(struct device *dev)
        if (ddata->offsets[SYSC_SYSCONFIG] == -ENODEV)
                return 0;
 
-       /*
-        * TODO: Need to prevent clockdomain autoidle?
-        * See clkdm_deny_idle() in arch/mach-omap2/omap_hwmod.c
-        */
-
        regbits = ddata->cap->regbits;
        reg = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);
 
+       /* Set CLOCKACTIVITY, we only use it for ick */
+       if (regbits->clkact_shift >= 0 &&
+           (ddata->cfg.quirks & SYSC_QUIRK_USE_CLOCKACT ||
+            ddata->cfg.sysc_val & BIT(regbits->clkact_shift)))
+               reg |= SYSC_CLOCACT_ICK << regbits->clkact_shift;
+
        /* Set SIDLE mode */
        idlemodes = ddata->cfg.sidlemodes;
        if (!idlemodes || regbits->sidle_shift < 0)
                goto set_midle;
 
-       best_mode = fls(ddata->cfg.sidlemodes) - 1;
-       if (best_mode > SYSC_IDLE_MASK) {
-               dev_err(dev, "%s: invalid sidlemode\n", __func__);
-               return -EINVAL;
+       if (ddata->cfg.quirks & (SYSC_QUIRK_SWSUP_SIDLE |
+                                SYSC_QUIRK_SWSUP_SIDLE_ACT)) {
+               best_mode = SYSC_IDLE_NO;
+       } else {
+               best_mode = fls(ddata->cfg.sidlemodes) - 1;
+               if (best_mode > SYSC_IDLE_MASK) {
+                       dev_err(dev, "%s: invalid sidlemode\n", __func__);
+                       return -EINVAL;
+               }
+
+               /* Set WAKEUP */
+               if (regbits->enwkup_shift >= 0 &&
+                   ddata->cfg.sysc_val & BIT(regbits->enwkup_shift))
+                       reg |= BIT(regbits->enwkup_shift);
        }
 
        reg &= ~(SYSC_IDLE_MASK << regbits->sidle_shift);
@@ -832,7 +920,7 @@ set_midle:
        /* Set MIDLE mode */
        idlemodes = ddata->cfg.midlemodes;
        if (!idlemodes || regbits->midle_shift < 0)
-               return 0;
+               goto set_autoidle;
 
        best_mode = fls(ddata->cfg.midlemodes) - 1;
        if (best_mode > SYSC_IDLE_MASK) {
@@ -844,6 +932,14 @@ set_midle:
        reg |= best_mode << regbits->midle_shift;
        sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
 
+set_autoidle:
+       /* Autoidle bit must enabled separately if available */
+       if (regbits->autoidle_shift >= 0 &&
+           ddata->cfg.sysc_val & BIT(regbits->autoidle_shift)) {
+               reg |= 1 << regbits->autoidle_shift;
+               sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
+       }
+
        return 0;
 }
 
@@ -861,6 +957,7 @@ static int sysc_best_idle_mode(u32 idlemodes, u32 *best_mode)
        return 0;
 }
 
+/* Caller needs to manage sysc_clkdm_deny_idle() and sysc_clkdm_allow_idle() */
 static int sysc_disable_module(struct device *dev)
 {
        struct sysc *ddata;
@@ -872,11 +969,6 @@ static int sysc_disable_module(struct device *dev)
        if (ddata->offsets[SYSC_SYSCONFIG] == -ENODEV)
                return 0;
 
-       /*
-        * TODO: Need to prevent clockdomain autoidle?
-        * See clkdm_deny_idle() in arch/mach-omap2/omap_hwmod.c
-        */
-
        regbits = ddata->cap->regbits;
        reg = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);
 
@@ -901,14 +993,21 @@ set_sidle:
        if (!idlemodes || regbits->sidle_shift < 0)
                return 0;
 
-       ret = sysc_best_idle_mode(idlemodes, &best_mode);
-       if (ret) {
-               dev_err(dev, "%s: invalid sidlemode\n", __func__);
-               return ret;
+       if (ddata->cfg.quirks & SYSC_QUIRK_SWSUP_SIDLE) {
+               best_mode = SYSC_IDLE_FORCE;
+       } else {
+               ret = sysc_best_idle_mode(idlemodes, &best_mode);
+               if (ret) {
+                       dev_err(dev, "%s: invalid sidlemode\n", __func__);
+                       return ret;
+               }
        }
 
        reg &= ~(SYSC_IDLE_MASK << regbits->sidle_shift);
        reg |= best_mode << regbits->sidle_shift;
+       if (regbits->autoidle_shift >= 0 &&
+           ddata->cfg.sysc_val & BIT(regbits->autoidle_shift))
+               reg |= 1 << regbits->autoidle_shift;
        sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
 
        return 0;
@@ -932,6 +1031,9 @@ static int __maybe_unused sysc_runtime_suspend_legacy(struct device *dev,
                dev_err(dev, "%s: could not idle: %i\n",
                        __func__, error);
 
+       if (ddata->disable_on_idle)
+               reset_control_assert(ddata->rsts);
+
        return 0;
 }
 
@@ -941,6 +1043,9 @@ static int __maybe_unused sysc_runtime_resume_legacy(struct device *dev,
        struct ti_sysc_platform_data *pdata;
        int error;
 
+       if (ddata->disable_on_idle)
+               reset_control_deassert(ddata->rsts);
+
        pdata = dev_get_platdata(ddata->dev);
        if (!pdata)
                return 0;
@@ -966,14 +1071,16 @@ static int __maybe_unused sysc_runtime_suspend(struct device *dev)
        if (!ddata->enabled)
                return 0;
 
+       sysc_clkdm_deny_idle(ddata);
+
        if (ddata->legacy_mode) {
                error = sysc_runtime_suspend_legacy(dev, ddata);
                if (error)
-                       return error;
+                       goto err_allow_idle;
        } else {
                error = sysc_disable_module(dev);
                if (error)
-                       return error;
+                       goto err_allow_idle;
        }
 
        sysc_disable_main_clocks(ddata);
@@ -983,6 +1090,12 @@ static int __maybe_unused sysc_runtime_suspend(struct device *dev)
 
        ddata->enabled = false;
 
+err_allow_idle:
+       sysc_clkdm_allow_idle(ddata);
+
+       if (ddata->disable_on_idle)
+               reset_control_assert(ddata->rsts);
+
        return error;
 }
 
@@ -996,10 +1109,15 @@ static int __maybe_unused sysc_runtime_resume(struct device *dev)
        if (ddata->enabled)
                return 0;
 
+       if (ddata->disable_on_idle)
+               reset_control_deassert(ddata->rsts);
+
+       sysc_clkdm_deny_idle(ddata);
+
        if (sysc_opt_clks_needed(ddata)) {
                error = sysc_enable_opt_clocks(ddata);
                if (error)
-                       return error;
+                       goto err_allow_idle;
        }
 
        error = sysc_enable_main_clocks(ddata);
@@ -1018,6 +1136,8 @@ static int __maybe_unused sysc_runtime_resume(struct device *dev)
 
        ddata->enabled = true;
 
+       sysc_clkdm_allow_idle(ddata);
+
        return 0;
 
 err_main_clocks:
@@ -1025,6 +1145,8 @@ err_main_clocks:
 err_opt_clocks:
        if (sysc_opt_clks_needed(ddata))
                sysc_disable_opt_clocks(ddata);
+err_allow_idle:
+       sysc_clkdm_allow_idle(ddata);
 
        return error;
 }
@@ -1106,8 +1228,10 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
                   0),
        SYSC_QUIRK("timer", 0, 0, 0x10, -1, 0x4fff1301, 0xffff00ff,
                   0),
+       SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000046, 0xffffffff,
+                  SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE),
        SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000052, 0xffffffff,
-                  SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
+                  SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE),
        /* Uarts on omap4 and later */
        SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x50411e03, 0xffff00ff,
                   SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
@@ -1119,6 +1243,22 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
                   SYSC_QUIRK_EXT_OPT_CLOCK | SYSC_QUIRK_NO_RESET_ON_INIT |
                   SYSC_QUIRK_SWSUP_SIDLE),
 
+       /* Quirks that need to be set based on detected module */
+       SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x00000006, 0xffffffff,
+                  SYSC_MODULE_QUIRK_HDQ1W),
+       SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x0000000a, 0xffffffff,
+                  SYSC_MODULE_QUIRK_HDQ1W),
+       SYSC_QUIRK("i2c", 0, 0, 0x20, 0x10, 0x00000036, 0x000000ff,
+                  SYSC_MODULE_QUIRK_I2C),
+       SYSC_QUIRK("i2c", 0, 0, 0x20, 0x10, 0x0000003c, 0x000000ff,
+                  SYSC_MODULE_QUIRK_I2C),
+       SYSC_QUIRK("i2c", 0, 0, 0x20, 0x10, 0x00000040, 0x000000ff,
+                  SYSC_MODULE_QUIRK_I2C),
+       SYSC_QUIRK("i2c", 0, 0, 0x10, 0x90, 0x5040000a, 0xfffff0f0,
+                  SYSC_MODULE_QUIRK_I2C),
+       SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0,
+                  SYSC_MODULE_QUIRK_WDT),
+
 #ifdef DEBUG
        SYSC_QUIRK("adc", 0, 0, 0x10, -1, 0x47300001, 0xffffffff, 0),
        SYSC_QUIRK("atl", 0, 0, -1, -1, 0x0a070100, 0xffffffff, 0),
@@ -1132,11 +1272,8 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
        SYSC_QUIRK("dwc3", 0, 0, 0x10, -1, 0x500a0200, 0xffffffff, 0),
        SYSC_QUIRK("epwmss", 0, 0, 0x4, -1, 0x47400001, 0xffffffff, 0),
        SYSC_QUIRK("gpu", 0, 0x1fc00, 0x1fc10, -1, 0, 0, 0),
-       SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x00000006, 0xffffffff, 0),
-       SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x0000000a, 0xffffffff, 0),
        SYSC_QUIRK("hsi", 0, 0, 0x10, 0x14, 0x50043101, 0xffffffff, 0),
        SYSC_QUIRK("iss", 0, 0, 0x10, -1, 0x40000101, 0xffffffff, 0),
-       SYSC_QUIRK("i2c", 0, 0, 0x10, 0x90, 0x5040000a, 0xfffff0f0, 0),
        SYSC_QUIRK("lcdc", 0, 0, 0x54, -1, 0x4f201000, 0xffffffff, 0),
        SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44306302, 0xffffffff, 0),
        SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44307b02, 0xffffffff, 0),
@@ -1172,7 +1309,6 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
        SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, -1, 0x50700101, 0xffffffff, 0),
        SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050,
                   0xffffffff, 0),
-       SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0, 0),
        SYSC_QUIRK("vfpe", 0, 0, 0x104, -1, 0x4d001200, 0xffffffff, 0),
 #endif
 };
@@ -1245,6 +1381,121 @@ static void sysc_init_revision_quirks(struct sysc *ddata)
        }
 }
 
+/* 1-wire needs module's internal clocks enabled for reset */
+static void sysc_clk_enable_quirk_hdq1w(struct sysc *ddata)
+{
+       int offset = 0x0c;      /* HDQ_CTRL_STATUS */
+       u16 val;
+
+       val = sysc_read(ddata, offset);
+       val |= BIT(5);
+       sysc_write(ddata, offset, val);
+}
+
+/* I2C needs extra enable bit toggling for reset */
+static void sysc_clk_quirk_i2c(struct sysc *ddata, bool enable)
+{
+       int offset;
+       u16 val;
+
+       /* I2C_CON, omap2/3 is different from omap4 and later */
+       if ((ddata->revision & 0xffffff00) == 0x001f0000)
+               offset = 0x24;
+       else
+               offset = 0xa4;
+
+       /* I2C_EN */
+       val = sysc_read(ddata, offset);
+       if (enable)
+               val |= BIT(15);
+       else
+               val &= ~BIT(15);
+       sysc_write(ddata, offset, val);
+}
+
+static void sysc_clk_enable_quirk_i2c(struct sysc *ddata)
+{
+       sysc_clk_quirk_i2c(ddata, true);
+}
+
+static void sysc_clk_disable_quirk_i2c(struct sysc *ddata)
+{
+       sysc_clk_quirk_i2c(ddata, false);
+}
+
+/* Watchdog timer needs a disable sequence after reset */
+static void sysc_reset_done_quirk_wdt(struct sysc *ddata)
+{
+       int wps, spr, error;
+       u32 val;
+
+       wps = 0x34;
+       spr = 0x48;
+
+       sysc_write(ddata, spr, 0xaaaa);
+       error = readl_poll_timeout(ddata->module_va + wps, val,
+                                  !(val & 0x10), 100,
+                                  MAX_MODULE_SOFTRESET_WAIT);
+       if (error)
+               dev_warn(ddata->dev, "wdt disable spr failed\n");
+
+       sysc_write(ddata, wps, 0x5555);
+       error = readl_poll_timeout(ddata->module_va + wps, val,
+                                  !(val & 0x10), 100,
+                                  MAX_MODULE_SOFTRESET_WAIT);
+       if (error)
+               dev_warn(ddata->dev, "wdt disable wps failed\n");
+}
+
+static void sysc_init_module_quirks(struct sysc *ddata)
+{
+       if (ddata->legacy_mode || !ddata->name)
+               return;
+
+       if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_HDQ1W) {
+               ddata->clk_enable_quirk = sysc_clk_enable_quirk_hdq1w;
+
+               return;
+       }
+
+       if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_I2C) {
+               ddata->clk_enable_quirk = sysc_clk_enable_quirk_i2c;
+               ddata->clk_disable_quirk = sysc_clk_disable_quirk_i2c;
+
+               return;
+       }
+
+       if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_WDT)
+               ddata->reset_done_quirk = sysc_reset_done_quirk_wdt;
+}
+
+static int sysc_clockdomain_init(struct sysc *ddata)
+{
+       struct ti_sysc_platform_data *pdata = dev_get_platdata(ddata->dev);
+       struct clk *fck = NULL, *ick = NULL;
+       int error;
+
+       if (!pdata || !pdata->init_clockdomain)
+               return 0;
+
+       switch (ddata->nr_clocks) {
+       case 2:
+               ick = ddata->clocks[SYSC_ICK];
+               /* fallthrough */
+       case 1:
+               fck = ddata->clocks[SYSC_FCK];
+               break;
+       case 0:
+               return 0;
+       }
+
+       error = pdata->init_clockdomain(ddata->dev, fck, ick, &ddata->cookie);
+       if (!error || error == -ENODEV)
+               return 0;
+
+       return error;
+}
+
 /*
  * Note that pdata->init_module() typically does a reset first. After
  * pdata->init_module() is done, PM runtime can be used for the interconnect
@@ -1255,7 +1506,7 @@ static int sysc_legacy_init(struct sysc *ddata)
        struct ti_sysc_platform_data *pdata = dev_get_platdata(ddata->dev);
        int error;
 
-       if (!ddata->legacy_mode || !pdata || !pdata->init_module)
+       if (!pdata || !pdata->init_module)
                return 0;
 
        error = pdata->init_module(ddata->dev, ddata->mdata, &ddata->cookie);
@@ -1280,7 +1531,7 @@ static int sysc_legacy_init(struct sysc *ddata)
  */
 static int sysc_rstctrl_reset_deassert(struct sysc *ddata, bool reset)
 {
-       int error;
+       int error, val;
 
        if (!ddata->rsts)
                return 0;
@@ -1291,37 +1542,68 @@ static int sysc_rstctrl_reset_deassert(struct sysc *ddata, bool reset)
                        return error;
        }
 
-       return reset_control_deassert(ddata->rsts);
+       error = reset_control_deassert(ddata->rsts);
+       if (error == -EEXIST)
+               return 0;
+
+       error = readx_poll_timeout(reset_control_status, ddata->rsts, val,
+                                  val == 0, 100, MAX_MODULE_SOFTRESET_WAIT);
+
+       return error;
 }
 
+/*
+ * Note that the caller must ensure the interconnect target module is enabled
+ * before calling reset. Otherwise reset will not complete.
+ */
 static int sysc_reset(struct sysc *ddata)
 {
-       int offset = ddata->offsets[SYSC_SYSCONFIG];
-       int val;
+       int sysc_offset, syss_offset, sysc_val, rstval, quirks, error = 0;
+       u32 sysc_mask, syss_done;
+
+       sysc_offset = ddata->offsets[SYSC_SYSCONFIG];
+       syss_offset = ddata->offsets[SYSC_SYSSTATUS];
+       quirks = ddata->cfg.quirks;
 
-       if (ddata->legacy_mode || offset < 0 ||
+       if (ddata->legacy_mode || sysc_offset < 0 ||
+           ddata->cap->regbits->srst_shift < 0 ||
            ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)
                return 0;
 
-       /*
-        * Currently only support reset status in sysstatus.
-        * Warn and return error in all other cases
-        */
-       if (!ddata->cfg.syss_mask) {
-               dev_err(ddata->dev, "No ti,syss-mask. Reset failed\n");
-               return -EINVAL;
-       }
+       sysc_mask = BIT(ddata->cap->regbits->srst_shift);
 
-       val = sysc_read(ddata, offset);
-       val |= (0x1 << ddata->cap->regbits->srst_shift);
-       sysc_write(ddata, offset, val);
+       if (ddata->cfg.quirks & SYSS_QUIRK_RESETDONE_INVERTED)
+               syss_done = 0;
+       else
+               syss_done = ddata->cfg.syss_mask;
+
+       if (ddata->clk_disable_quirk)
+               ddata->clk_disable_quirk(ddata);
+
+       sysc_val = sysc_read_sysconfig(ddata);
+       sysc_val |= sysc_mask;
+       sysc_write(ddata, sysc_offset, sysc_val);
+
+       if (ddata->clk_enable_quirk)
+               ddata->clk_enable_quirk(ddata);
 
        /* Poll on reset status */
-       offset = ddata->offsets[SYSC_SYSSTATUS];
+       if (syss_offset >= 0) {
+               error = readx_poll_timeout(sysc_read_sysstatus, ddata, rstval,
+                                          (rstval & ddata->cfg.syss_mask) ==
+                                          syss_done,
+                                          100, MAX_MODULE_SOFTRESET_WAIT);
+
+       } else if (ddata->cfg.quirks & SYSC_QUIRK_RESET_STATUS) {
+               error = readx_poll_timeout(sysc_read_sysconfig, ddata, rstval,
+                                          !(rstval & sysc_mask),
+                                          100, MAX_MODULE_SOFTRESET_WAIT);
+       }
+
+       if (ddata->reset_done_quirk)
+               ddata->reset_done_quirk(ddata);
 
-       return readl_poll_timeout(ddata->module_va + offset, val,
-                                 (val & ddata->cfg.syss_mask) == 0x0,
-                                 100, MAX_MODULE_SOFTRESET_WAIT);
+       return error;
 }
 
 /*
@@ -1334,12 +1616,8 @@ static int sysc_init_module(struct sysc *ddata)
 {
        int error = 0;
        bool manage_clocks = true;
-       bool reset = true;
-
-       if (ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)
-               reset = false;
 
-       error = sysc_rstctrl_reset_deassert(ddata, reset);
+       error = sysc_rstctrl_reset_deassert(ddata, false);
        if (error)
                return error;
 
@@ -1347,7 +1625,13 @@ static int sysc_init_module(struct sysc *ddata)
            (SYSC_QUIRK_NO_IDLE | SYSC_QUIRK_NO_IDLE_ON_INIT))
                manage_clocks = false;
 
+       error = sysc_clockdomain_init(ddata);
+       if (error)
+               return error;
+
        if (manage_clocks) {
+               sysc_clkdm_deny_idle(ddata);
+
                error = sysc_enable_opt_clocks(ddata);
                if (error)
                        return error;
@@ -1357,23 +1641,43 @@ static int sysc_init_module(struct sysc *ddata)
                        goto err_opt_clocks;
        }
 
+       if (!(ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)) {
+               error = sysc_rstctrl_reset_deassert(ddata, true);
+               if (error)
+                       goto err_main_clocks;
+       }
+
        ddata->revision = sysc_read_revision(ddata);
        sysc_init_revision_quirks(ddata);
+       sysc_init_module_quirks(ddata);
 
-       error = sysc_legacy_init(ddata);
-       if (error)
-               goto err_main_clocks;
+       if (ddata->legacy_mode) {
+               error = sysc_legacy_init(ddata);
+               if (error)
+                       goto err_main_clocks;
+       }
+
+       if (!ddata->legacy_mode && manage_clocks) {
+               error = sysc_enable_module(ddata->dev);
+               if (error)
+                       goto err_main_clocks;
+       }
 
        error = sysc_reset(ddata);
        if (error)
                dev_err(ddata->dev, "Reset failed with %d\n", error);
 
+       if (!ddata->legacy_mode && manage_clocks)
+               sysc_disable_module(ddata->dev);
+
 err_main_clocks:
        if (manage_clocks)
                sysc_disable_main_clocks(ddata);
 err_opt_clocks:
-       if (manage_clocks)
+       if (manage_clocks) {
                sysc_disable_opt_clocks(ddata);
+               sysc_clkdm_allow_idle(ddata);
+       }
 
        return error;
 }
@@ -1663,9 +1967,6 @@ static struct dev_pm_domain sysc_child_pm_domain = {
  */
 static void sysc_legacy_idle_quirk(struct sysc *ddata, struct device *child)
 {
-       if (!ddata->legacy_mode)
-               return;
-
        if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE)
                dev_pm_domain_set(child, &sysc_child_pm_domain);
 }
@@ -2005,6 +2306,7 @@ static const struct sysc_capabilities sysc_dra7_mcan = {
        .type = TI_SYSC_DRA7_MCAN,
        .sysc_mask = SYSC_DRA7_MCAN_ENAWAKEUP | SYSC_OMAP4_SOFTRESET,
        .regbits = &sysc_regbits_dra7_mcan,
+       .mod_quirks = SYSS_QUIRK_RESETDONE_INVERTED,
 };
 
 static int sysc_init_pdata(struct sysc *ddata)
@@ -2012,20 +2314,22 @@ static int sysc_init_pdata(struct sysc *ddata)
        struct ti_sysc_platform_data *pdata = dev_get_platdata(ddata->dev);
        struct ti_sysc_module_data *mdata;
 
-       if (!pdata || !ddata->legacy_mode)
+       if (!pdata)
                return 0;
 
        mdata = devm_kzalloc(ddata->dev, sizeof(*mdata), GFP_KERNEL);
        if (!mdata)
                return -ENOMEM;
 
-       mdata->name = ddata->legacy_mode;
-       mdata->module_pa = ddata->module_pa;
-       mdata->module_size = ddata->module_size;
-       mdata->offsets = ddata->offsets;
-       mdata->nr_offsets = SYSC_MAX_REGS;
-       mdata->cap = ddata->cap;
-       mdata->cfg = &ddata->cfg;
+       if (ddata->legacy_mode) {
+               mdata->name = ddata->legacy_mode;
+               mdata->module_pa = ddata->module_pa;
+               mdata->module_size = ddata->module_size;
+               mdata->offsets = ddata->offsets;
+               mdata->nr_offsets = SYSC_MAX_REGS;
+               mdata->cap = ddata->cap;
+               mdata->cfg = &ddata->cfg;
+       }
 
        ddata->mdata = mdata;
 
@@ -2145,7 +2449,7 @@ static int sysc_probe(struct platform_device *pdev)
        }
 
        if (!of_get_available_child_count(ddata->dev->of_node))
-               reset_control_assert(ddata->rsts);
+               ddata->disable_on_idle = true;
 
        return 0;
 
index 466ebd8..3e86688 100644 (file)
@@ -291,7 +291,7 @@ config RTC
          and set the RTC in an SMP compatible fashion.
 
          If you think you have a use for such a device (such as periodic data
-         sampling), then say Y here, and read <file:Documentation/rtc.txt>
+         sampling), then say Y here, and read <file:Documentation/admin-guide/rtc.rst>
          for details.
 
          To compile this driver as a module, choose M here: the
@@ -313,7 +313,7 @@ config JS_RTC
          /dev/rtc.
 
          If you think you have a use for such a device (such as periodic data
-         sampling), then say Y here, and read <file:Documentation/rtc.txt>
+         sampling), then say Y here, and read <file:Documentation/admin-guide/rtc.rst>
          for details.
 
          To compile this driver as a module, choose M here: the
@@ -382,7 +382,7 @@ config SONYPI
          Device which can be found in many (all ?) Sony Vaio laptops.
 
          If you have one of those laptops, read
-         <file:Documentation/laptops/sonypi.txt>, and say Y or M here.
+         <file:Documentation/admin-guide/laptops/sonypi.rst>, and say Y or M here.
 
          To compile this driver as a module, choose M here: the
          module will be called sonypi.
index 95be722..9044d31 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright 2006 Michael Buesch <m@bues.ch>
  * Copyright 2005 (c) MontaVista Software, Inc.
  *
- * Please read Documentation/hw_random.txt for details on use.
+ * Please read Documentation/admin-guide/hw_random.rst for details on use.
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
index 7376af2..801fa1c 100644 (file)
@@ -90,6 +90,17 @@ config COMMON_CLK_SCPI
          This driver uses SCPI Message Protocol to interact with the
          firmware providing all the clock controls.
 
+config COMMON_CLK_SI5341
+       tristate "Clock driver for SiLabs 5341 and 5340 A/B/C/D devices"
+       depends on I2C
+       select REGMAP_I2C
+       help
+         This driver supports Silicon Labs Si5341 and Si5340 programmable clock
+         generators. Not all features of these chips are currently supported
+         by the driver, in particular it only supports XTAL input. The chip can
+         be pre-programmed to support other configurations and features not yet
+         implemented in the driver.
+
 config COMMON_CLK_SI5351
        tristate "Clock driver for SiLabs 5351A/B/C"
        depends on I2C
@@ -214,7 +225,7 @@ config CLK_QORIQ
 
 config COMMON_CLK_XGENE
        bool "Clock driver for APM XGene SoC"
-       default y
+       default ARCH_XGENE
        depends on ARM64 || COMPILE_TEST
        ---help---
          Sypport for the APM X-Gene SoC reference, PLL, and device clocks.
index 9ef4305..0cad760 100644 (file)
@@ -49,6 +49,7 @@ obj-$(CONFIG_COMMON_CLK_HI655X)               += clk-hi655x.o
 obj-$(CONFIG_COMMON_CLK_S2MPS11)       += clk-s2mps11.o
 obj-$(CONFIG_COMMON_CLK_SCMI)           += clk-scmi.o
 obj-$(CONFIG_COMMON_CLK_SCPI)           += clk-scpi.o
+obj-$(CONFIG_COMMON_CLK_SI5341)                += clk-si5341.o
 obj-$(CONFIG_COMMON_CLK_SI5351)                += clk-si5351.o
 obj-$(CONFIG_COMMON_CLK_SI514)         += clk-si514.o
 obj-$(CONFIG_COMMON_CLK_SI544)         += clk-si544.o
index 45526f5..9bfe9a2 100644 (file)
                                 SLOW_CLOCK_FREQ)
 
 #define        AT91_SCKC_CR                    0x00
-#define                AT91_SCKC_RCEN          (1 << 0)
-#define                AT91_SCKC_OSC32EN       (1 << 1)
-#define                AT91_SCKC_OSC32BYP      (1 << 2)
-#define                AT91_SCKC_OSCSEL        (1 << 3)
+
+struct clk_slow_bits {
+       u32 cr_rcen;
+       u32 cr_osc32en;
+       u32 cr_osc32byp;
+       u32 cr_oscsel;
+};
 
 struct clk_slow_osc {
        struct clk_hw hw;
        void __iomem *sckcr;
+       const struct clk_slow_bits *bits;
        unsigned long startup_usec;
 };
 
@@ -34,6 +38,7 @@ struct clk_slow_osc {
 struct clk_sama5d4_slow_osc {
        struct clk_hw hw;
        void __iomem *sckcr;
+       const struct clk_slow_bits *bits;
        unsigned long startup_usec;
        bool prepared;
 };
@@ -43,6 +48,7 @@ struct clk_sama5d4_slow_osc {
 struct clk_slow_rc_osc {
        struct clk_hw hw;
        void __iomem *sckcr;
+       const struct clk_slow_bits *bits;
        unsigned long frequency;
        unsigned long accuracy;
        unsigned long startup_usec;
@@ -53,6 +59,7 @@ struct clk_slow_rc_osc {
 struct clk_sam9x5_slow {
        struct clk_hw hw;
        void __iomem *sckcr;
+       const struct clk_slow_bits *bits;
        u8 parent;
 };
 
@@ -64,10 +71,10 @@ static int clk_slow_osc_prepare(struct clk_hw *hw)
        void __iomem *sckcr = osc->sckcr;
        u32 tmp = readl(sckcr);
 
-       if (tmp & (AT91_SCKC_OSC32BYP | AT91_SCKC_OSC32EN))
+       if (tmp & (osc->bits->cr_osc32byp | osc->bits->cr_osc32en))
                return 0;
 
-       writel(tmp | AT91_SCKC_OSC32EN, sckcr);
+       writel(tmp | osc->bits->cr_osc32en, sckcr);
 
        usleep_range(osc->startup_usec, osc->startup_usec + 1);
 
@@ -80,10 +87,10 @@ static void clk_slow_osc_unprepare(struct clk_hw *hw)
        void __iomem *sckcr = osc->sckcr;
        u32 tmp = readl(sckcr);
 
-       if (tmp & AT91_SCKC_OSC32BYP)
+       if (tmp & osc->bits->cr_osc32byp)
                return;
 
-       writel(tmp & ~AT91_SCKC_OSC32EN, sckcr);
+       writel(tmp & ~osc->bits->cr_osc32en, sckcr);
 }
 
 static int clk_slow_osc_is_prepared(struct clk_hw *hw)
@@ -92,10 +99,10 @@ static int clk_slow_osc_is_prepared(struct clk_hw *hw)
        void __iomem *sckcr = osc->sckcr;
        u32 tmp = readl(sckcr);
 
-       if (tmp & AT91_SCKC_OSC32BYP)
+       if (tmp & osc->bits->cr_osc32byp)
                return 1;
 
-       return !!(tmp & AT91_SCKC_OSC32EN);
+       return !!(tmp & osc->bits->cr_osc32en);
 }
 
 static const struct clk_ops slow_osc_ops = {
@@ -109,7 +116,8 @@ at91_clk_register_slow_osc(void __iomem *sckcr,
                           const char *name,
                           const char *parent_name,
                           unsigned long startup,
-                          bool bypass)
+                          bool bypass,
+                          const struct clk_slow_bits *bits)
 {
        struct clk_slow_osc *osc;
        struct clk_hw *hw;
@@ -132,10 +140,11 @@ at91_clk_register_slow_osc(void __iomem *sckcr,
        osc->hw.init = &init;
        osc->sckcr = sckcr;
        osc->startup_usec = startup;
+       osc->bits = bits;
 
        if (bypass)
-               writel((readl(sckcr) & ~AT91_SCKC_OSC32EN) | AT91_SCKC_OSC32BYP,
-                      sckcr);
+               writel((readl(sckcr) & ~osc->bits->cr_osc32en) |
+                                       osc->bits->cr_osc32byp, sckcr);
 
        hw = &osc->hw;
        ret = clk_hw_register(NULL, &osc->hw);
@@ -147,6 +156,14 @@ at91_clk_register_slow_osc(void __iomem *sckcr,
        return hw;
 }
 
+static void at91_clk_unregister_slow_osc(struct clk_hw *hw)
+{
+       struct clk_slow_osc *osc = to_clk_slow_osc(hw);
+
+       clk_hw_unregister(hw);
+       kfree(osc);
+}
+
 static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw,
                                                 unsigned long parent_rate)
 {
@@ -168,7 +185,7 @@ static int clk_slow_rc_osc_prepare(struct clk_hw *hw)
        struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
        void __iomem *sckcr = osc->sckcr;
 
-       writel(readl(sckcr) | AT91_SCKC_RCEN, sckcr);
+       writel(readl(sckcr) | osc->bits->cr_rcen, sckcr);
 
        usleep_range(osc->startup_usec, osc->startup_usec + 1);
 
@@ -180,14 +197,14 @@ static void clk_slow_rc_osc_unprepare(struct clk_hw *hw)
        struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
        void __iomem *sckcr = osc->sckcr;
 
-       writel(readl(sckcr) & ~AT91_SCKC_RCEN, sckcr);
+       writel(readl(sckcr) & ~osc->bits->cr_rcen, sckcr);
 }
 
 static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw)
 {
        struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
 
-       return !!(readl(osc->sckcr) & AT91_SCKC_RCEN);
+       return !!(readl(osc->sckcr) & osc->bits->cr_rcen);
 }
 
 static const struct clk_ops slow_rc_osc_ops = {
@@ -203,7 +220,8 @@ at91_clk_register_slow_rc_osc(void __iomem *sckcr,
                              const char *name,
                              unsigned long frequency,
                              unsigned long accuracy,
-                             unsigned long startup)
+                             unsigned long startup,
+                             const struct clk_slow_bits *bits)
 {
        struct clk_slow_rc_osc *osc;
        struct clk_hw *hw;
@@ -225,6 +243,7 @@ at91_clk_register_slow_rc_osc(void __iomem *sckcr,
 
        osc->hw.init = &init;
        osc->sckcr = sckcr;
+       osc->bits = bits;
        osc->frequency = frequency;
        osc->accuracy = accuracy;
        osc->startup_usec = startup;
@@ -239,6 +258,14 @@ at91_clk_register_slow_rc_osc(void __iomem *sckcr,
        return hw;
 }
 
+static void at91_clk_unregister_slow_rc_osc(struct clk_hw *hw)
+{
+       struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
+
+       clk_hw_unregister(hw);
+       kfree(osc);
+}
+
 static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
 {
        struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
@@ -250,14 +277,14 @@ static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
 
        tmp = readl(sckcr);
 
-       if ((!index && !(tmp & AT91_SCKC_OSCSEL)) ||
-           (index && (tmp & AT91_SCKC_OSCSEL)))
+       if ((!index && !(tmp & slowck->bits->cr_oscsel)) ||
+           (index && (tmp & slowck->bits->cr_oscsel)))
                return 0;
 
        if (index)
-               tmp |= AT91_SCKC_OSCSEL;
+               tmp |= slowck->bits->cr_oscsel;
        else
-               tmp &= ~AT91_SCKC_OSCSEL;
+               tmp &= ~slowck->bits->cr_oscsel;
 
        writel(tmp, sckcr);
 
@@ -270,7 +297,7 @@ static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw)
 {
        struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
 
-       return !!(readl(slowck->sckcr) & AT91_SCKC_OSCSEL);
+       return !!(readl(slowck->sckcr) & slowck->bits->cr_oscsel);
 }
 
 static const struct clk_ops sam9x5_slow_ops = {
@@ -282,7 +309,8 @@ static struct clk_hw * __init
 at91_clk_register_sam9x5_slow(void __iomem *sckcr,
                              const char *name,
                              const char **parent_names,
-                             int num_parents)
+                             int num_parents,
+                             const struct clk_slow_bits *bits)
 {
        struct clk_sam9x5_slow *slowck;
        struct clk_hw *hw;
@@ -304,7 +332,8 @@ at91_clk_register_sam9x5_slow(void __iomem *sckcr,
 
        slowck->hw.init = &init;
        slowck->sckcr = sckcr;
-       slowck->parent = !!(readl(sckcr) & AT91_SCKC_OSCSEL);
+       slowck->bits = bits;
+       slowck->parent = !!(readl(sckcr) & slowck->bits->cr_oscsel);
 
        hw = &slowck->hw;
        ret = clk_hw_register(NULL, &slowck->hw);
@@ -316,22 +345,33 @@ at91_clk_register_sam9x5_slow(void __iomem *sckcr,
        return hw;
 }
 
+static void at91_clk_unregister_sam9x5_slow(struct clk_hw *hw)
+{
+       struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
+
+       clk_hw_unregister(hw);
+       kfree(slowck);
+}
+
 static void __init at91sam9x5_sckc_register(struct device_node *np,
-                                           unsigned int rc_osc_startup_us)
+                                           unsigned int rc_osc_startup_us,
+                                           const struct clk_slow_bits *bits)
 {
        const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
        void __iomem *regbase = of_iomap(np, 0);
        struct device_node *child = NULL;
        const char *xtal_name;
-       struct clk_hw *hw;
+       struct clk_hw *slow_rc, *slow_osc, *slowck;
        bool bypass;
+       int ret;
 
        if (!regbase)
                return;
 
-       hw = at91_clk_register_slow_rc_osc(regbase, parent_names[0], 32768,
-                                          50000000, rc_osc_startup_us);
-       if (IS_ERR(hw))
+       slow_rc = at91_clk_register_slow_rc_osc(regbase, parent_names[0],
+                                               32768, 50000000,
+                                               rc_osc_startup_us, bits);
+       if (IS_ERR(slow_rc))
                return;
 
        xtal_name = of_clk_get_parent_name(np, 0);
@@ -339,7 +379,7 @@ static void __init at91sam9x5_sckc_register(struct device_node *np,
                /* DT backward compatibility */
                child = of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow-osc");
                if (!child)
-                       return;
+                       goto unregister_slow_rc;
 
                xtal_name = of_clk_get_parent_name(child, 0);
                bypass = of_property_read_bool(child, "atmel,osc-bypass");
@@ -350,38 +390,133 @@ static void __init at91sam9x5_sckc_register(struct device_node *np,
        }
 
        if (!xtal_name)
-               return;
-
-       hw = at91_clk_register_slow_osc(regbase, parent_names[1], xtal_name,
-                                       1200000, bypass);
-       if (IS_ERR(hw))
-               return;
+               goto unregister_slow_rc;
 
-       hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2);
-       if (IS_ERR(hw))
-               return;
+       slow_osc = at91_clk_register_slow_osc(regbase, parent_names[1],
+                                             xtal_name, 1200000, bypass, bits);
+       if (IS_ERR(slow_osc))
+               goto unregister_slow_rc;
 
-       of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+       slowck = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names,
+                                              2, bits);
+       if (IS_ERR(slowck))
+               goto unregister_slow_osc;
 
        /* DT backward compatibility */
        if (child)
-               of_clk_add_hw_provider(child, of_clk_hw_simple_get, hw);
+               ret = of_clk_add_hw_provider(child, of_clk_hw_simple_get,
+                                            slowck);
+       else
+               ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, slowck);
+
+       if (WARN_ON(ret))
+               goto unregister_slowck;
+
+       return;
+
+unregister_slowck:
+       at91_clk_unregister_sam9x5_slow(slowck);
+unregister_slow_osc:
+       at91_clk_unregister_slow_osc(slow_osc);
+unregister_slow_rc:
+       at91_clk_unregister_slow_rc_osc(slow_rc);
 }
 
+static const struct clk_slow_bits at91sam9x5_bits = {
+       .cr_rcen = BIT(0),
+       .cr_osc32en = BIT(1),
+       .cr_osc32byp = BIT(2),
+       .cr_oscsel = BIT(3),
+};
+
 static void __init of_at91sam9x5_sckc_setup(struct device_node *np)
 {
-       at91sam9x5_sckc_register(np, 75);
+       at91sam9x5_sckc_register(np, 75, &at91sam9x5_bits);
 }
 CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc",
               of_at91sam9x5_sckc_setup);
 
 static void __init of_sama5d3_sckc_setup(struct device_node *np)
 {
-       at91sam9x5_sckc_register(np, 500);
+       at91sam9x5_sckc_register(np, 500, &at91sam9x5_bits);
 }
 CLK_OF_DECLARE(sama5d3_clk_sckc, "atmel,sama5d3-sckc",
               of_sama5d3_sckc_setup);
 
+static const struct clk_slow_bits at91sam9x60_bits = {
+       .cr_osc32en = BIT(1),
+       .cr_osc32byp = BIT(2),
+       .cr_oscsel = BIT(24),
+};
+
+static void __init of_sam9x60_sckc_setup(struct device_node *np)
+{
+       void __iomem *regbase = of_iomap(np, 0);
+       struct clk_hw_onecell_data *clk_data;
+       struct clk_hw *slow_rc, *slow_osc;
+       const char *xtal_name;
+       const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
+       bool bypass;
+       int ret;
+
+       if (!regbase)
+               return;
+
+       slow_rc = clk_hw_register_fixed_rate(NULL, parent_names[0], NULL, 0,
+                                            32768);
+       if (IS_ERR(slow_rc))
+               return;
+
+       xtal_name = of_clk_get_parent_name(np, 0);
+       if (!xtal_name)
+               goto unregister_slow_rc;
+
+       bypass = of_property_read_bool(np, "atmel,osc-bypass");
+       slow_osc = at91_clk_register_slow_osc(regbase, parent_names[1],
+                                             xtal_name, 5000000, bypass,
+                                             &at91sam9x60_bits);
+       if (IS_ERR(slow_osc))
+               goto unregister_slow_rc;
+
+       clk_data = kzalloc(sizeof(*clk_data) + (2 * sizeof(struct clk_hw *)),
+                          GFP_KERNEL);
+       if (!clk_data)
+               goto unregister_slow_osc;
+
+       /* MD_SLCK and TD_SLCK. */
+       clk_data->num = 2;
+       clk_data->hws[0] = clk_hw_register_fixed_rate(NULL, "md_slck",
+                                                     parent_names[0],
+                                                     0, 32768);
+       if (IS_ERR(clk_data->hws[0]))
+               goto clk_data_free;
+
+       clk_data->hws[1] = at91_clk_register_sam9x5_slow(regbase, "td_slck",
+                                                        parent_names, 2,
+                                                        &at91sam9x60_bits);
+       if (IS_ERR(clk_data->hws[1]))
+               goto unregister_md_slck;
+
+       ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
+       if (WARN_ON(ret))
+               goto unregister_td_slck;
+
+       return;
+
+unregister_td_slck:
+       at91_clk_unregister_sam9x5_slow(clk_data->hws[1]);
+unregister_md_slck:
+       clk_hw_unregister(clk_data->hws[0]);
+clk_data_free:
+       kfree(clk_data);
+unregister_slow_osc:
+       at91_clk_unregister_slow_osc(slow_osc);
+unregister_slow_rc:
+       clk_hw_unregister(slow_rc);
+}
+CLK_OF_DECLARE(sam9x60_clk_sckc, "microchip,sam9x60-sckc",
+              of_sam9x60_sckc_setup);
+
 static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw)
 {
        struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
@@ -393,7 +528,7 @@ static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw)
         * Assume that if it has already been selected (for example by the
         * bootloader), enough time has aready passed.
         */
-       if ((readl(osc->sckcr) & AT91_SCKC_OSCSEL)) {
+       if ((readl(osc->sckcr) & osc->bits->cr_oscsel)) {
                osc->prepared = true;
                return 0;
        }
@@ -416,33 +551,35 @@ static const struct clk_ops sama5d4_slow_osc_ops = {
        .is_prepared = clk_sama5d4_slow_osc_is_prepared,
 };
 
+static const struct clk_slow_bits at91sama5d4_bits = {
+       .cr_oscsel = BIT(3),
+};
+
 static void __init of_sama5d4_sckc_setup(struct device_node *np)
 {
        void __iomem *regbase = of_iomap(np, 0);
-       struct clk_hw *hw;
+       struct clk_hw *slow_rc, *slowck;
        struct clk_sama5d4_slow_osc *osc;
        struct clk_init_data init;
        const char *xtal_name;
        const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
-       bool bypass;
        int ret;
 
        if (!regbase)
                return;
 
-       hw = clk_hw_register_fixed_rate_with_accuracy(NULL, parent_names[0],
-                                                     NULL, 0, 32768,
-                                                     250000000);
-       if (IS_ERR(hw))
+       slow_rc = clk_hw_register_fixed_rate_with_accuracy(NULL,
+                                                          parent_names[0],
+                                                          NULL, 0, 32768,
+                                                          250000000);
+       if (IS_ERR(slow_rc))
                return;
 
        xtal_name = of_clk_get_parent_name(np, 0);
 
-       bypass = of_property_read_bool(np, "atmel,osc-bypass");
-
        osc = kzalloc(sizeof(*osc), GFP_KERNEL);
        if (!osc)
-               return;
+               goto unregister_slow_rc;
 
        init.name = parent_names[1];
        init.ops = &sama5d4_slow_osc_ops;
@@ -453,22 +590,32 @@ static void __init of_sama5d4_sckc_setup(struct device_node *np)
        osc->hw.init = &init;
        osc->sckcr = regbase;
        osc->startup_usec = 1200000;
+       osc->bits = &at91sama5d4_bits;
 
-       if (bypass)
-               writel((readl(regbase) | AT91_SCKC_OSC32BYP), regbase);
-
-       hw = &osc->hw;
        ret = clk_hw_register(NULL, &osc->hw);
-       if (ret) {
-               kfree(osc);
-               return;
-       }
-
-       hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2);
-       if (IS_ERR(hw))
-               return;
-
-       of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+       if (ret)
+               goto free_slow_osc_data;
+
+       slowck = at91_clk_register_sam9x5_slow(regbase, "slowck",
+                                              parent_names, 2,
+                                              &at91sama5d4_bits);
+       if (IS_ERR(slowck))
+               goto unregister_slow_osc;
+
+       ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, slowck);
+       if (WARN_ON(ret))
+               goto unregister_slowck;
+
+       return;
+
+unregister_slowck:
+       at91_clk_unregister_sam9x5_slow(slowck);
+unregister_slow_osc:
+       clk_hw_unregister(&osc->hw);
+free_slow_osc_data:
+       kfree(osc);
+unregister_slow_rc:
+       clk_hw_unregister(slow_rc);
 }
 CLK_OF_DECLARE(sama5d4_clk_sckc, "atmel,sama5d4-sckc",
               of_sama5d4_sckc_setup);
index 29ee7b7..8c83977 100644 (file)
@@ -1,4 +1,13 @@
 # SPDX-License-Identifier: GPL-2.0-only
+config CLK_BCM2835
+       bool "Broadcom BCM2835 clock support"
+       depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST
+       depends on COMMON_CLK
+       default ARCH_BCM2835 || ARCH_BRCMSTB
+       help
+         Enable common clock framework support for Broadcom BCM2835
+         SoCs.
+
 config CLK_BCM_63XX
        bool "Broadcom BCM63xx clock support"
        depends on ARCH_BCM_63XX || COMPILE_TEST
@@ -8,6 +17,14 @@ config CLK_BCM_63XX
          Enable common clock framework support for Broadcom BCM63xx DSL SoCs
          based on the ARM architecture
 
+config CLK_BCM_63XX_GATE
+       bool "Broadcom BCM63xx gated clock support"
+       depends on BMIPS_GENERIC || COMPILE_TEST
+       default BMIPS_GENERIC
+       help
+         Enable common clock framework support for Broadcom BCM63xx DSL SoCs
+         based on the MIPS architecture
+
 config CLK_BCM_KONA
        bool "Broadcom Kona CCU clock support"
        depends on ARCH_BCM_MOBILE || COMPILE_TEST
@@ -64,3 +81,10 @@ config CLK_BCM_SR
        default ARCH_BCM_IPROC
        help
          Enable common clock framework support for the Broadcom Stingray SoC
+
+config CLK_RASPBERRYPI
+       tristate "Raspberry Pi firmware based clock support"
+       depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE)
+       help
+         Enable common clock framework support for Raspberry Pi's firmware
+         dependent clocks
index 002661d..0070ddf 100644 (file)
@@ -1,12 +1,14 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_CLK_BCM_63XX)     += clk-bcm63xx.o
+obj-$(CONFIG_CLK_BCM_63XX_GATE)        += clk-bcm63xx-gate.o
 obj-$(CONFIG_CLK_BCM_KONA)     += clk-kona.o
 obj-$(CONFIG_CLK_BCM_KONA)     += clk-kona-setup.o
 obj-$(CONFIG_CLK_BCM_KONA)     += clk-bcm281xx.o
 obj-$(CONFIG_CLK_BCM_KONA)     += clk-bcm21664.o
 obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o
-obj-$(CONFIG_ARCH_BCM2835)     += clk-bcm2835.o
-obj-$(CONFIG_ARCH_BCM2835)     += clk-bcm2835-aux.o
+obj-$(CONFIG_CLK_BCM2835)      += clk-bcm2835.o
+obj-$(CONFIG_CLK_BCM2835)      += clk-bcm2835-aux.o
+obj-$(CONFIG_CLK_RASPBERRYPI)  += clk-raspberrypi.o
 obj-$(CONFIG_ARCH_BCM_53573)   += clk-bcm53573-ilp.o
 obj-$(CONFIG_CLK_BCM_CYGNUS)   += clk-cygnus.o
 obj-$(CONFIG_CLK_BCM_HR2)      += clk-hr2.o
index 770bb01..867ae3c 100644 (file)
@@ -1651,30 +1651,10 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .fixed_divider = 1,
                .flags = CLK_SET_RATE_PARENT),
 
-       /* PLLB is used for the ARM's clock. */
-       [BCM2835_PLLB]          = REGISTER_PLL(
-               .name = "pllb",
-               .cm_ctrl_reg = CM_PLLB,
-               .a2w_ctrl_reg = A2W_PLLB_CTRL,
-               .frac_reg = A2W_PLLB_FRAC,
-               .ana_reg_base = A2W_PLLB_ANA0,
-               .reference_enable_mask = A2W_XOSC_CTRL_PLLB_ENABLE,
-               .lock_mask = CM_LOCK_FLOCKB,
-
-               .ana = &bcm2835_ana_default,
-
-               .min_rate = 600000000u,
-               .max_rate = 3000000000u,
-               .max_fb_rate = BCM2835_MAX_FB_RATE),
-       [BCM2835_PLLB_ARM]      = REGISTER_PLL_DIV(
-               .name = "pllb_arm",
-               .source_pll = "pllb",
-               .cm_reg = CM_PLLB,
-               .a2w_reg = A2W_PLLB_ARM,
-               .load_mask = CM_PLLB_LOADARM,
-               .hold_mask = CM_PLLB_HOLDARM,
-               .fixed_divider = 1,
-               .flags = CLK_SET_RATE_PARENT),
+       /*
+        * PLLB is used for the ARM's clock. Controlled by firmware, see
+        * clk-raspberrypi.c.
+        */
 
        /*
         * PLLC is the core PLL, used to drive the core VPU clock.
diff --git a/drivers/clk/bcm/clk-bcm63xx-gate.c b/drivers/clk/bcm/clk-bcm63xx-gate.c
new file mode 100644 (file)
index 0000000..9e1dcd4
--- /dev/null
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/clk-provider.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+struct clk_bcm63xx_table_entry {
+       const char * const name;
+       u8 bit;
+       unsigned long flags;
+};
+
+struct clk_bcm63xx_hw {
+       void __iomem *regs;
+       spinlock_t lock;
+
+       struct clk_hw_onecell_data data;
+};
+
+static const struct clk_bcm63xx_table_entry bcm3368_clocks[] = {
+       { .name = "mac", .bit = 3, },
+       { .name = "tc", .bit = 5, },
+       { .name = "us_top", .bit = 6, },
+       { .name = "ds_top", .bit = 7, },
+       { .name = "acm", .bit = 8, },
+       { .name = "spi", .bit = 9, },
+       { .name = "usbs", .bit = 10, },
+       { .name = "bmu", .bit = 11, },
+       { .name = "pcm", .bit = 12, },
+       { .name = "ntp", .bit = 13, },
+       { .name = "acp_b", .bit = 14, },
+       { .name = "acp_a", .bit = 15, },
+       { .name = "emusb", .bit = 17, },
+       { .name = "enet0", .bit = 18, },
+       { .name = "enet1", .bit = 19, },
+       { .name = "usbsu", .bit = 20, },
+       { .name = "ephy", .bit = 21, },
+       { },
+};
+
+static const struct clk_bcm63xx_table_entry bcm6328_clocks[] = {
+       { .name = "phy_mips", .bit = 0, },
+       { .name = "adsl_qproc", .bit = 1, },
+       { .name = "adsl_afe", .bit = 2, },
+       { .name = "adsl", .bit = 3, },
+       { .name = "mips", .bit = 4, .flags = CLK_IS_CRITICAL, },
+       { .name = "sar", .bit = 5, },
+       { .name = "pcm", .bit = 6, },
+       { .name = "usbd", .bit = 7, },
+       { .name = "usbh", .bit = 8, },
+       { .name = "hsspi", .bit = 9, },
+       { .name = "pcie", .bit = 10, },
+       { .name = "robosw", .bit = 11, },
+       { },
+};
+
+static const struct clk_bcm63xx_table_entry bcm6358_clocks[] = {
+       { .name = "enet", .bit = 4, },
+       { .name = "adslphy", .bit = 5, },
+       { .name = "pcm", .bit = 8, },
+       { .name = "spi", .bit = 9, },
+       { .name = "usbs", .bit = 10, },
+       { .name = "sar", .bit = 11, },
+       { .name = "emusb", .bit = 17, },
+       { .name = "enet0", .bit = 18, },
+       { .name = "enet1", .bit = 19, },
+       { .name = "usbsu", .bit = 20, },
+       { .name = "ephy", .bit = 21, },
+       { },
+};
+
+static const struct clk_bcm63xx_table_entry bcm6362_clocks[] = {
+       { .name = "adsl_qproc", .bit = 1, },
+       { .name = "adsl_afe", .bit = 2, },
+       { .name = "adsl", .bit = 3, },
+       { .name = "mips", .bit = 4, .flags = CLK_IS_CRITICAL, },
+       { .name = "wlan_ocp", .bit = 5, },
+       { .name = "swpkt_usb", .bit = 7, },
+       { .name = "swpkt_sar", .bit = 8, },
+       { .name = "sar", .bit = 9, },
+       { .name = "robosw", .bit = 10, },
+       { .name = "pcm", .bit = 11, },
+       { .name = "usbd", .bit = 12, },
+       { .name = "usbh", .bit = 13, },
+       { .name = "ipsec", .bit = 14, },
+       { .name = "spi", .bit = 15, },
+       { .name = "hsspi", .bit = 16, },
+       { .name = "pcie", .bit = 17, },
+       { .name = "fap", .bit = 18, },
+       { .name = "phymips", .bit = 19, },
+       { .name = "nand", .bit = 20, },
+       { },
+};
+
+static const struct clk_bcm63xx_table_entry bcm6368_clocks[] = {
+       { .name = "vdsl_qproc", .bit = 2, },
+       { .name = "vdsl_afe", .bit = 3, },
+       { .name = "vdsl_bonding", .bit = 4, },
+       { .name = "vdsl", .bit = 5, },
+       { .name = "phymips", .bit = 6, },
+       { .name = "swpkt_usb", .bit = 7, },
+       { .name = "swpkt_sar", .bit = 8, },
+       { .name = "spi", .bit = 9, },
+       { .name = "usbd", .bit = 10, },
+       { .name = "sar", .bit = 11, },
+       { .name = "robosw", .bit = 12, },
+       { .name = "utopia", .bit = 13, },
+       { .name = "pcm", .bit = 14, },
+       { .name = "usbh", .bit = 15, },
+       { .name = "disable_gless", .bit = 16, },
+       { .name = "nand", .bit = 17, },
+       { .name = "ipsec", .bit = 18, },
+       { },
+};
+
+static const struct clk_bcm63xx_table_entry bcm63268_clocks[] = {
+       { .name = "disable_gless", .bit = 0, },
+       { .name = "vdsl_qproc", .bit = 1, },
+       { .name = "vdsl_afe", .bit = 2, },
+       { .name = "vdsl", .bit = 3, },
+       { .name = "mips", .bit = 4, .flags = CLK_IS_CRITICAL, },
+       { .name = "wlan_ocp", .bit = 5, },
+       { .name = "dect", .bit = 6, },
+       { .name = "fap0", .bit = 7, },
+       { .name = "fap1", .bit = 8, },
+       { .name = "sar", .bit = 9, },
+       { .name = "robosw", .bit = 10, },
+       { .name = "pcm", .bit = 11, },
+       { .name = "usbd", .bit = 12, },
+       { .name = "usbh", .bit = 13, },
+       { .name = "ipsec", .bit = 14, },
+       { .name = "spi", .bit = 15, },
+       { .name = "hsspi", .bit = 16, },
+       { .name = "pcie", .bit = 17, },
+       { .name = "phymips", .bit = 18, },
+       { .name = "gmac", .bit = 19, },
+       { .name = "nand", .bit = 20, },
+       { .name = "tbus", .bit = 27, },
+       { .name = "robosw250", .bit = 31, },
+       { },
+};
+
+static int clk_bcm63xx_probe(struct platform_device *pdev)
+{
+       const struct clk_bcm63xx_table_entry *entry, *table;
+       struct clk_bcm63xx_hw *hw;
+       struct resource *r;
+       u8 maxbit = 0;
+       int i, ret;
+
+       table = of_device_get_match_data(&pdev->dev);
+       if (!table)
+               return -EINVAL;
+
+       for (entry = table; entry->name; entry++)
+               maxbit = max_t(u8, maxbit, entry->bit);
+
+       hw = devm_kzalloc(&pdev->dev, struct_size(hw, data.hws, maxbit),
+                         GFP_KERNEL);
+       if (!hw)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, hw);
+
+       spin_lock_init(&hw->lock);
+
+       hw->data.num = maxbit;
+       for (i = 0; i < maxbit; i++)
+               hw->data.hws[i] = ERR_PTR(-ENODEV);
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       hw->regs = devm_ioremap_resource(&pdev->dev, r);
+       if (IS_ERR(hw->regs))
+               return PTR_ERR(hw->regs);
+
+       for (entry = table; entry->name; entry++) {
+               struct clk_hw *clk;
+
+               clk = clk_hw_register_gate(&pdev->dev, entry->name, NULL,
+                                          entry->flags, hw->regs, entry->bit,
+                                          CLK_GATE_BIG_ENDIAN, &hw->lock);
+               if (IS_ERR(clk)) {
+                       ret = PTR_ERR(clk);
+                       goto out_err;
+               }
+
+               hw->data.hws[entry->bit] = clk;
+       }
+
+       ret = of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get,
+                                    &hw->data);
+       if (!ret)
+               return 0;
+out_err:
+       for (i = 0; i < hw->data.num; i++) {
+               if (!IS_ERR(hw->data.hws[i]))
+                       clk_hw_unregister_gate(hw->data.hws[i]);
+       }
+
+       return ret;
+}
+
+static int clk_bcm63xx_remove(struct platform_device *pdev)
+{
+       struct clk_bcm63xx_hw *hw = platform_get_drvdata(pdev);
+       int i;
+
+       of_clk_del_provider(pdev->dev.of_node);
+
+       for (i = 0; i < hw->data.num; i++) {
+               if (!IS_ERR(hw->data.hws[i]))
+                       clk_hw_unregister_gate(hw->data.hws[i]);
+       }
+
+       return 0;
+}
+
+static const struct of_device_id clk_bcm63xx_dt_ids[] = {
+       { .compatible = "brcm,bcm3368-clocks", .data = &bcm3368_clocks, },
+       { .compatible = "brcm,bcm6328-clocks", .data = &bcm6328_clocks, },
+       { .compatible = "brcm,bcm6358-clocks", .data = &bcm6358_clocks, },
+       { .compatible = "brcm,bcm6362-clocks", .data = &bcm6362_clocks, },
+       { .compatible = "brcm,bcm6368-clocks", .data = &bcm6368_clocks, },
+       { .compatible = "brcm,bcm63268-clocks", .data = &bcm63268_clocks, },
+       { }
+};
+
+static struct platform_driver clk_bcm63xx = {
+       .probe = clk_bcm63xx_probe,
+       .remove = clk_bcm63xx_remove,
+       .driver = {
+               .name = "bcm63xx-clock",
+               .of_match_table = clk_bcm63xx_dt_ids,
+       },
+};
+builtin_platform_driver(clk_bcm63xx);
diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c
new file mode 100644 (file)
index 0000000..1654fd0
--- /dev/null
@@ -0,0 +1,315 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Raspberry Pi driver for firmware controlled clocks
+ *
+ * Even though clk-bcm2835 provides an interface to the hardware registers for
+ * the system clocks we've had to factor out 'pllb' as the firmware 'owns' it.
+ * We're not allowed to change it directly as we might race with the
+ * over-temperature and under-voltage protections provided by the firmware.
+ *
+ * Copyright (C) 2019 Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+ */
+
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+#define RPI_FIRMWARE_ARM_CLK_ID                0x00000003
+
+#define RPI_FIRMWARE_STATE_ENABLE_BIT  BIT(0)
+#define RPI_FIRMWARE_STATE_WAIT_BIT    BIT(1)
+
+/*
+ * Even though the firmware interface alters 'pllb' the frequencies are
+ * provided as per 'pllb_arm'. We need to scale before passing them trough.
+ */
+#define RPI_FIRMWARE_PLLB_ARM_DIV_RATE 2
+
+#define A2W_PLL_FRAC_BITS              20
+
+struct raspberrypi_clk {
+       struct device *dev;
+       struct rpi_firmware *firmware;
+       struct platform_device *cpufreq;
+
+       unsigned long min_rate;
+       unsigned long max_rate;
+
+       struct clk_hw pllb;
+       struct clk_hw *pllb_arm;
+       struct clk_lookup *pllb_arm_lookup;
+};
+
+/*
+ * Structure of the message passed to Raspberry Pi's firmware in order to
+ * change clock rates. The 'disable_turbo' option is only available to the ARM
+ * clock (pllb) which we enable by default as turbo mode will alter multiple
+ * clocks at once.
+ *
+ * Even though we're able to access the clock registers directly we're bound to
+ * use the firmware interface as the firmware ultimately takes care of
+ * mitigating overheating/undervoltage situations and we would be changing
+ * frequencies behind his back.
+ *
+ * For more information on the firmware interface check:
+ * https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface
+ */
+struct raspberrypi_firmware_prop {
+       __le32 id;
+       __le32 val;
+       __le32 disable_turbo;
+} __packed;
+
+static int raspberrypi_clock_property(struct rpi_firmware *firmware, u32 tag,
+                                     u32 clk, u32 *val)
+{
+       struct raspberrypi_firmware_prop msg = {
+               .id = cpu_to_le32(clk),
+               .val = cpu_to_le32(*val),
+               .disable_turbo = cpu_to_le32(1),
+       };
+       int ret;
+
+       ret = rpi_firmware_property(firmware, tag, &msg, sizeof(msg));
+       if (ret)
+               return ret;
+
+       *val = le32_to_cpu(msg.val);
+
+       return 0;
+}
+
+static int raspberrypi_fw_pll_is_on(struct clk_hw *hw)
+{
+       struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
+                                                  pllb);
+       u32 val = 0;
+       int ret;
+
+       ret = raspberrypi_clock_property(rpi->firmware,
+                                        RPI_FIRMWARE_GET_CLOCK_STATE,
+                                        RPI_FIRMWARE_ARM_CLK_ID, &val);
+       if (ret)
+               return 0;
+
+       return !!(val & RPI_FIRMWARE_STATE_ENABLE_BIT);
+}
+
+
+static unsigned long raspberrypi_fw_pll_get_rate(struct clk_hw *hw,
+                                                unsigned long parent_rate)
+{
+       struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
+                                                  pllb);
+       u32 val = 0;
+       int ret;
+
+       ret = raspberrypi_clock_property(rpi->firmware,
+                                        RPI_FIRMWARE_GET_CLOCK_RATE,
+                                        RPI_FIRMWARE_ARM_CLK_ID,
+                                        &val);
+       if (ret)
+               return ret;
+
+       return val * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
+}
+
+static int raspberrypi_fw_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+                                      unsigned long parent_rate)
+{
+       struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
+                                                  pllb);
+       u32 new_rate = rate / RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
+       int ret;
+
+       ret = raspberrypi_clock_property(rpi->firmware,
+                                        RPI_FIRMWARE_SET_CLOCK_RATE,
+                                        RPI_FIRMWARE_ARM_CLK_ID,
+                                        &new_rate);
+       if (ret)
+               dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d",
+                                   clk_hw_get_name(hw), ret);
+
+       return ret;
+}
+
+/*
+ * Sadly there is no firmware rate rounding interface. We borrowed it from
+ * clk-bcm2835.
+ */
+static int raspberrypi_pll_determine_rate(struct clk_hw *hw,
+                                         struct clk_rate_request *req)
+{
+       struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
+                                                  pllb);
+       u64 div, final_rate;
+       u32 ndiv, fdiv;
+
+       /* We can't use req->rate directly as it would overflow */
+       final_rate = clamp(req->rate, rpi->min_rate, rpi->max_rate);
+
+       div = (u64)final_rate << A2W_PLL_FRAC_BITS;
+       do_div(div, req->best_parent_rate);
+
+       ndiv = div >> A2W_PLL_FRAC_BITS;
+       fdiv = div & ((1 << A2W_PLL_FRAC_BITS) - 1);
+
+       final_rate = ((u64)req->best_parent_rate *
+                                       ((ndiv << A2W_PLL_FRAC_BITS) + fdiv));
+
+       req->rate = final_rate >> A2W_PLL_FRAC_BITS;
+
+       return 0;
+}
+
+static const struct clk_ops raspberrypi_firmware_pll_clk_ops = {
+       .is_prepared = raspberrypi_fw_pll_is_on,
+       .recalc_rate = raspberrypi_fw_pll_get_rate,
+       .set_rate = raspberrypi_fw_pll_set_rate,
+       .determine_rate = raspberrypi_pll_determine_rate,
+};
+
+static int raspberrypi_register_pllb(struct raspberrypi_clk *rpi)
+{
+       u32 min_rate = 0, max_rate = 0;
+       struct clk_init_data init;
+       int ret;
+
+       memset(&init, 0, sizeof(init));
+
+       /* All of the PLLs derive from the external oscillator. */
+       init.parent_names = (const char *[]){ "osc" };
+       init.num_parents = 1;
+       init.name = "pllb";
+       init.ops = &raspberrypi_firmware_pll_clk_ops;
+       init.flags = CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED;
+
+       /* Get min & max rates set by the firmware */
+       ret = raspberrypi_clock_property(rpi->firmware,
+                                        RPI_FIRMWARE_GET_MIN_CLOCK_RATE,
+                                        RPI_FIRMWARE_ARM_CLK_ID,
+                                        &min_rate);
+       if (ret) {
+               dev_err(rpi->dev, "Failed to get %s min freq: %d\n",
+                       init.name, ret);
+               return ret;
+       }
+
+       ret = raspberrypi_clock_property(rpi->firmware,
+                                        RPI_FIRMWARE_GET_MAX_CLOCK_RATE,
+                                        RPI_FIRMWARE_ARM_CLK_ID,
+                                        &max_rate);
+       if (ret) {
+               dev_err(rpi->dev, "Failed to get %s max freq: %d\n",
+                       init.name, ret);
+               return ret;
+       }
+
+       if (!min_rate || !max_rate) {
+               dev_err(rpi->dev, "Unexpected frequency range: min %u, max %u\n",
+                       min_rate, max_rate);
+               return -EINVAL;
+       }
+
+       dev_info(rpi->dev, "CPU frequency range: min %u, max %u\n",
+                min_rate, max_rate);
+
+       rpi->min_rate = min_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
+       rpi->max_rate = max_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
+
+       rpi->pllb.init = &init;
+
+       return devm_clk_hw_register(rpi->dev, &rpi->pllb);
+}
+
+static int raspberrypi_register_pllb_arm(struct raspberrypi_clk *rpi)
+{
+       rpi->pllb_arm = clk_hw_register_fixed_factor(rpi->dev,
+                               "pllb_arm", "pllb",
+                               CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+                               1, 2);
+       if (IS_ERR(rpi->pllb_arm)) {
+               dev_err(rpi->dev, "Failed to initialize pllb_arm\n");
+               return PTR_ERR(rpi->pllb_arm);
+       }
+
+       rpi->pllb_arm_lookup = clkdev_hw_create(rpi->pllb_arm, NULL, "cpu0");
+       if (!rpi->pllb_arm_lookup) {
+               dev_err(rpi->dev, "Failed to initialize pllb_arm_lookup\n");
+               clk_hw_unregister_fixed_factor(rpi->pllb_arm);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static int raspberrypi_clk_probe(struct platform_device *pdev)
+{
+       struct device_node *firmware_node;
+       struct device *dev = &pdev->dev;
+       struct rpi_firmware *firmware;
+       struct raspberrypi_clk *rpi;
+       int ret;
+
+       firmware_node = of_find_compatible_node(NULL, NULL,
+                                       "raspberrypi,bcm2835-firmware");
+       if (!firmware_node) {
+               dev_err(dev, "Missing firmware node\n");
+               return -ENOENT;
+       }
+
+       firmware = rpi_firmware_get(firmware_node);
+       of_node_put(firmware_node);
+       if (!firmware)
+               return -EPROBE_DEFER;
+
+       rpi = devm_kzalloc(dev, sizeof(*rpi), GFP_KERNEL);
+       if (!rpi)
+               return -ENOMEM;
+
+       rpi->dev = dev;
+       rpi->firmware = firmware;
+       platform_set_drvdata(pdev, rpi);
+
+       ret = raspberrypi_register_pllb(rpi);
+       if (ret) {
+               dev_err(dev, "Failed to initialize pllb, %d\n", ret);
+               return ret;
+       }
+
+       ret = raspberrypi_register_pllb_arm(rpi);
+       if (ret)
+               return ret;
+
+       rpi->cpufreq = platform_device_register_data(dev, "raspberrypi-cpufreq",
+                                                    -1, NULL, 0);
+
+       return 0;
+}
+
+static int raspberrypi_clk_remove(struct platform_device *pdev)
+{
+       struct raspberrypi_clk *rpi = platform_get_drvdata(pdev);
+
+       platform_device_unregister(rpi->cpufreq);
+
+       return 0;
+}
+
+static struct platform_driver raspberrypi_clk_driver = {
+       .driver = {
+               .name = "raspberrypi-clk",
+       },
+       .probe          = raspberrypi_clk_probe,
+       .remove         = raspberrypi_clk_remove,
+};
+module_platform_driver(raspberrypi_clk_driver);
+
+MODULE_AUTHOR("Nicolas Saenz Julienne <nsaenzjulienne@suse.de>");
+MODULE_DESCRIPTION("Raspberry Pi firmware clock driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:raspberrypi-clk");
index 0649956..524bf9a 100644 (file)
@@ -75,8 +75,8 @@ void clk_bulk_put(int num_clks, struct clk_bulk_data *clks)
 }
 EXPORT_SYMBOL_GPL(clk_bulk_put);
 
-int __must_check clk_bulk_get(struct device *dev, int num_clks,
-                             struct clk_bulk_data *clks)
+static int __clk_bulk_get(struct device *dev, int num_clks,
+                         struct clk_bulk_data *clks, bool optional)
 {
        int ret;
        int i;
@@ -88,10 +88,14 @@ int __must_check clk_bulk_get(struct device *dev, int num_clks,
                clks[i].clk = clk_get(dev, clks[i].id);
                if (IS_ERR(clks[i].clk)) {
                        ret = PTR_ERR(clks[i].clk);
+                       clks[i].clk = NULL;
+
+                       if (ret == -ENOENT && optional)
+                               continue;
+
                        if (ret != -EPROBE_DEFER)
                                dev_err(dev, "Failed to get clk '%s': %d\n",
                                        clks[i].id, ret);
-                       clks[i].clk = NULL;
                        goto err;
                }
        }
@@ -103,8 +107,21 @@ err:
 
        return ret;
 }
+
+int __must_check clk_bulk_get(struct device *dev, int num_clks,
+                             struct clk_bulk_data *clks)
+{
+       return __clk_bulk_get(dev, num_clks, clks, false);
+}
 EXPORT_SYMBOL(clk_bulk_get);
 
+int __must_check clk_bulk_get_optional(struct device *dev, int num_clks,
+                                      struct clk_bulk_data *clks)
+{
+       return __clk_bulk_get(dev, num_clks, clks, true);
+}
+EXPORT_SYMBOL_GPL(clk_bulk_get_optional);
+
 void clk_bulk_put_all(int num_clks, struct clk_bulk_data *clks)
 {
        if (IS_ERR_OR_NULL(clks))
index 0443dfc..239102e 100644 (file)
@@ -630,7 +630,7 @@ of_clk_cdce_get(struct of_phandle_args *clkspec, void *data)
 static int cdce706_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
-       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+       struct i2c_adapter *adapter = client->adapter;
        struct cdce706_dev_data *cdce;
        int ret;
 
index daa1fc8..be16076 100644 (file)
@@ -52,8 +52,8 @@ static void devm_clk_bulk_release(struct device *dev, void *res)
        clk_bulk_put(devres->num_clks, devres->clks);
 }
 
-int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
-                     struct clk_bulk_data *clks)
+static int __devm_clk_bulk_get(struct device *dev, int num_clks,
+                              struct clk_bulk_data *clks, bool optional)
 {
        struct clk_bulk_devres *devres;
        int ret;
@@ -63,7 +63,10 @@ int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
        if (!devres)
                return -ENOMEM;
 
-       ret = clk_bulk_get(dev, num_clks, clks);
+       if (optional)
+               ret = clk_bulk_get_optional(dev, num_clks, clks);
+       else
+               ret = clk_bulk_get(dev, num_clks, clks);
        if (!ret) {
                devres->clks = clks;
                devres->num_clks = num_clks;
@@ -74,8 +77,21 @@ int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
 
        return ret;
 }
+
+int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
+                     struct clk_bulk_data *clks)
+{
+       return __devm_clk_bulk_get(dev, num_clks, clks, false);
+}
 EXPORT_SYMBOL_GPL(devm_clk_bulk_get);
 
+int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks,
+                     struct clk_bulk_data *clks)
+{
+       return __devm_clk_bulk_get(dev, num_clks, clks, true);
+}
+EXPORT_SYMBOL_GPL(devm_clk_bulk_get_optional);
+
 int __must_check devm_clk_bulk_get_all(struct device *dev,
                                       struct clk_bulk_data **clks)
 {
index a2f31e5..fa8c917 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 
-#include <linux/mfd/lochnagar.h>
 #include <linux/mfd/lochnagar1_regs.h>
 #include <linux/mfd/lochnagar2_regs.h>
 
@@ -40,48 +39,46 @@ struct lochnagar_clk {
 struct lochnagar_clk_priv {
        struct device *dev;
        struct regmap *regmap;
-       enum lochnagar_type type;
-
-       const char **parents;
-       unsigned int nparents;
 
        struct lochnagar_clk lclks[LOCHNAGAR_NUM_CLOCKS];
 };
 
-static const char * const lochnagar1_clk_parents[] = {
-       "ln-none",
-       "ln-spdif-mclk",
-       "ln-psia1-mclk",
-       "ln-psia2-mclk",
-       "ln-cdc-clkout",
-       "ln-dsp-clkout",
-       "ln-pmic-32k",
-       "ln-gf-mclk1",
-       "ln-gf-mclk3",
-       "ln-gf-mclk2",
-       "ln-gf-mclk4",
+#define LN_PARENT(NAME) { .name = NAME, .fw_name = NAME }
+
+static const struct clk_parent_data lochnagar1_clk_parents[] = {
+       LN_PARENT("ln-none"),
+       LN_PARENT("ln-spdif-mclk"),
+       LN_PARENT("ln-psia1-mclk"),
+       LN_PARENT("ln-psia2-mclk"),
+       LN_PARENT("ln-cdc-clkout"),
+       LN_PARENT("ln-dsp-clkout"),
+       LN_PARENT("ln-pmic-32k"),
+       LN_PARENT("ln-gf-mclk1"),
+       LN_PARENT("ln-gf-mclk3"),
+       LN_PARENT("ln-gf-mclk2"),
+       LN_PARENT("ln-gf-mclk4"),
 };
 
-static const char * const lochnagar2_clk_parents[] = {
-       "ln-none",
-       "ln-cdc-clkout",
-       "ln-dsp-clkout",
-       "ln-pmic-32k",
-       "ln-spdif-mclk",
-       "ln-clk-12m",
-       "ln-clk-11m",
-       "ln-clk-24m",
-       "ln-clk-22m",
-       "ln-clk-8m",
-       "ln-usb-clk-24m",
-       "ln-gf-mclk1",
-       "ln-gf-mclk3",
-       "ln-gf-mclk2",
-       "ln-psia1-mclk",
-       "ln-psia2-mclk",
-       "ln-spdif-clkout",
-       "ln-adat-mclk",
-       "ln-usb-clk-12m",
+static const struct clk_parent_data lochnagar2_clk_parents[] = {
+       LN_PARENT("ln-none"),
+       LN_PARENT("ln-cdc-clkout"),
+       LN_PARENT("ln-dsp-clkout"),
+       LN_PARENT("ln-pmic-32k"),
+       LN_PARENT("ln-spdif-mclk"),
+       LN_PARENT("ln-clk-12m"),
+       LN_PARENT("ln-clk-11m"),
+       LN_PARENT("ln-clk-24m"),
+       LN_PARENT("ln-clk-22m"),
+       LN_PARENT("ln-clk-8m"),
+       LN_PARENT("ln-usb-clk-24m"),
+       LN_PARENT("ln-gf-mclk1"),
+       LN_PARENT("ln-gf-mclk3"),
+       LN_PARENT("ln-gf-mclk2"),
+       LN_PARENT("ln-psia1-mclk"),
+       LN_PARENT("ln-psia2-mclk"),
+       LN_PARENT("ln-spdif-clkout"),
+       LN_PARENT("ln-adat-mclk"),
+       LN_PARENT("ln-usb-clk-12m"),
 };
 
 #define LN1_CLK(ID, NAME, REG) \
@@ -122,6 +119,24 @@ static const struct lochnagar_clk lochnagar2_clks[LOCHNAGAR_NUM_CLOCKS] = {
        LN2_CLK(SOUNDCARD_MCLK, "ln-soundcard-mclk"),
 };
 
+struct lochnagar_config {
+       const struct clk_parent_data *parents;
+       int nparents;
+       const struct lochnagar_clk *clks;
+};
+
+static const struct lochnagar_config lochnagar1_conf = {
+       .parents = lochnagar1_clk_parents,
+       .nparents = ARRAY_SIZE(lochnagar1_clk_parents),
+       .clks = lochnagar1_clks,
+};
+
+static const struct lochnagar_config lochnagar2_conf = {
+       .parents = lochnagar2_clk_parents,
+       .nparents = ARRAY_SIZE(lochnagar2_clk_parents),
+       .clks = lochnagar2_clks,
+};
+
 static inline struct lochnagar_clk *lochnagar_hw_to_lclk(struct clk_hw *hw)
 {
        return container_of(hw, struct lochnagar_clk, hw);
@@ -183,7 +198,7 @@ static u8 lochnagar_clk_get_parent(struct clk_hw *hw)
        if (ret < 0) {
                dev_dbg(priv->dev, "Failed to read parent of %s: %d\n",
                        lclk->name, ret);
-               return priv->nparents;
+               return hw->init->num_parents;
        }
 
        val &= lclk->src_mask;
@@ -198,46 +213,6 @@ static const struct clk_ops lochnagar_clk_ops = {
        .get_parent = lochnagar_clk_get_parent,
 };
 
-static int lochnagar_init_parents(struct lochnagar_clk_priv *priv)
-{
-       struct device_node *np = priv->dev->of_node;
-       int i, j;
-
-       switch (priv->type) {
-       case LOCHNAGAR1:
-               memcpy(priv->lclks, lochnagar1_clks, sizeof(lochnagar1_clks));
-
-               priv->nparents = ARRAY_SIZE(lochnagar1_clk_parents);
-               priv->parents = devm_kmemdup(priv->dev, lochnagar1_clk_parents,
-                                            sizeof(lochnagar1_clk_parents),
-                                            GFP_KERNEL);
-               break;
-       case LOCHNAGAR2:
-               memcpy(priv->lclks, lochnagar2_clks, sizeof(lochnagar2_clks));
-
-               priv->nparents = ARRAY_SIZE(lochnagar2_clk_parents);
-               priv->parents = devm_kmemdup(priv->dev, lochnagar2_clk_parents,
-                                            sizeof(lochnagar2_clk_parents),
-                                            GFP_KERNEL);
-               break;
-       default:
-               dev_err(priv->dev, "Unknown Lochnagar type: %d\n", priv->type);
-               return -EINVAL;
-       }
-
-       if (!priv->parents)
-               return -ENOMEM;
-
-       for (i = 0; i < priv->nparents; i++) {
-               j = of_property_match_string(np, "clock-names",
-                                            priv->parents[i]);
-               if (j >= 0)
-                       priv->parents[i] = of_clk_get_parent_name(np, j);
-       }
-
-       return 0;
-}
-
 static struct clk_hw *
 lochnagar_of_clk_hw_get(struct of_phandle_args *clkspec, void *data)
 {
@@ -252,16 +227,42 @@ lochnagar_of_clk_hw_get(struct of_phandle_args *clkspec, void *data)
        return &priv->lclks[idx].hw;
 }
 
-static int lochnagar_init_clks(struct lochnagar_clk_priv *priv)
+static const struct of_device_id lochnagar_of_match[] = {
+       { .compatible = "cirrus,lochnagar1-clk", .data = &lochnagar1_conf },
+       { .compatible = "cirrus,lochnagar2-clk", .data = &lochnagar2_conf },
+       {}
+};
+MODULE_DEVICE_TABLE(of, lochnagar_of_match);
+
+static int lochnagar_clk_probe(struct platform_device *pdev)
 {
        struct clk_init_data clk_init = {
                .ops = &lochnagar_clk_ops,
-               .parent_names = priv->parents,
-               .num_parents = priv->nparents,
        };
+       struct device *dev = &pdev->dev;
+       struct lochnagar_clk_priv *priv;
+       const struct of_device_id *of_id;
        struct lochnagar_clk *lclk;
+       struct lochnagar_config *conf;
        int ret, i;
 
+       of_id = of_match_device(lochnagar_of_match, dev);
+       if (!of_id)
+               return -EINVAL;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->dev = dev;
+       priv->regmap = dev_get_regmap(dev->parent, NULL);
+       conf = (struct lochnagar_config *)of_id->data;
+
+       memcpy(priv->lclks, conf->clks, sizeof(priv->lclks));
+
+       clk_init.parent_data = conf->parents;
+       clk_init.num_parents = conf->nparents;
+
        for (i = 0; i < ARRAY_SIZE(priv->lclks); i++) {
                lclk = &priv->lclks[i];
 
@@ -273,55 +274,21 @@ static int lochnagar_init_clks(struct lochnagar_clk_priv *priv)
                lclk->priv = priv;
                lclk->hw.init = &clk_init;
 
-               ret = devm_clk_hw_register(priv->dev, &lclk->hw);
+               ret = devm_clk_hw_register(dev, &lclk->hw);
                if (ret) {
-                       dev_err(priv->dev, "Failed to register %s: %d\n",
+                       dev_err(dev, "Failed to register %s: %d\n",
                                lclk->name, ret);
                        return ret;
                }
        }
 
-       ret = devm_of_clk_add_hw_provider(priv->dev, lochnagar_of_clk_hw_get,
-                                         priv);
+       ret = devm_of_clk_add_hw_provider(dev, lochnagar_of_clk_hw_get, priv);
        if (ret < 0)
-               dev_err(priv->dev, "Failed to register provider: %d\n", ret);
+               dev_err(dev, "Failed to register provider: %d\n", ret);
 
        return ret;
 }
 
-static const struct of_device_id lochnagar_of_match[] = {
-       { .compatible = "cirrus,lochnagar1-clk", .data = (void *)LOCHNAGAR1 },
-       { .compatible = "cirrus,lochnagar2-clk", .data = (void *)LOCHNAGAR2 },
-       {}
-};
-MODULE_DEVICE_TABLE(of, lochnagar_of_match);
-
-static int lochnagar_clk_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct lochnagar_clk_priv *priv;
-       const struct of_device_id *of_id;
-       int ret;
-
-       of_id = of_match_device(lochnagar_of_match, dev);
-       if (!of_id)
-               return -EINVAL;
-
-       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       priv->dev = dev;
-       priv->regmap = dev_get_regmap(dev->parent, NULL);
-       priv->type = (enum lochnagar_type)of_id->data;
-
-       ret = lochnagar_init_parents(priv);
-       if (ret)
-               return ret;
-
-       return lochnagar_init_clks(priv);
-}
-
 static struct platform_driver lochnagar_clk_driver = {
        .driver = {
                .name = "lochnagar-clk",
index 5f0490b..87fe0b0 100644 (file)
@@ -44,10 +44,24 @@ static unsigned long clk_pwm_recalc_rate(struct clk_hw *hw,
        return clk_pwm->fixed_rate;
 }
 
+static int clk_pwm_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty)
+{
+       struct clk_pwm *clk_pwm = to_clk_pwm(hw);
+       struct pwm_state state;
+
+       pwm_get_state(clk_pwm->pwm, &state);
+
+       duty->num = state.duty_cycle;
+       duty->den = state.period;
+
+       return 0;
+}
+
 static const struct clk_ops clk_pwm_ops = {
        .prepare = clk_pwm_prepare,
        .unprepare = clk_pwm_unprepare,
        .recalc_rate = clk_pwm_recalc_rate,
+       .get_duty_cycle = clk_pwm_get_duty_cycle,
 };
 
 static int clk_pwm_probe(struct platform_device *pdev)
index dd93d3a..07f3b25 100644 (file)
@@ -635,6 +635,17 @@ static const struct clockgen_chipinfo chipinfo[] = {
                .flags = CG_VER3 | CG_LITTLE_ENDIAN,
        },
        {
+               .compat = "fsl,lx2160a-clockgen",
+               .cmux_groups = {
+                       &clockgen2_cmux_cga12, &clockgen2_cmux_cgb
+               },
+               .cmux_to_group = {
+                       0, 0, 0, 0, 1, 1, 1, 1, -1
+               },
+               .pll_mask = 0x37,
+               .flags = CG_VER3 | CG_LITTLE_ENDIAN,
+       },
+       {
                .compat = "fsl,p2041-clockgen",
                .guts_compat = "fsl,qoriq-device-config-1.0",
                .init_periph = p2041_init_periph,
@@ -1493,6 +1504,7 @@ CLK_OF_DECLARE(qoriq_clockgen_ls1043a, "fsl,ls1043a-clockgen", clockgen_init);
 CLK_OF_DECLARE(qoriq_clockgen_ls1046a, "fsl,ls1046a-clockgen", clockgen_init);
 CLK_OF_DECLARE(qoriq_clockgen_ls1088a, "fsl,ls1088a-clockgen", clockgen_init);
 CLK_OF_DECLARE(qoriq_clockgen_ls2080a, "fsl,ls2080a-clockgen", clockgen_init);
+CLK_OF_DECLARE(qoriq_clockgen_lx2160a, "fsl,lx2160a-clockgen", clockgen_init);
 CLK_OF_DECLARE(qoriq_clockgen_p2041, "fsl,p2041-clockgen", clockgen_init);
 CLK_OF_DECLARE(qoriq_clockgen_p3041, "fsl,p3041-clockgen", clockgen_init);
 CLK_OF_DECLARE(qoriq_clockgen_p4080, "fsl,p4080-clockgen", clockgen_init);
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
new file mode 100644 (file)
index 0000000..72424eb
--- /dev/null
@@ -0,0 +1,1346 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Silicon Labs Si5341/Si5340 Clock generator
+ * Copyright (C) 2019 Topic Embedded Products
+ * Author: Mike Looijmans <mike.looijmans@topic.nl>
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/gcd.h>
+#include <linux/math64.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+
+#define SI5341_MAX_NUM_OUTPUTS 10
+#define SI5340_MAX_NUM_OUTPUTS 4
+
+#define SI5341_NUM_SYNTH 5
+#define SI5340_NUM_SYNTH 4
+
+/* Range of the synthesizer fractional divider */
+#define SI5341_SYNTH_N_MIN     10
+#define SI5341_SYNTH_N_MAX     4095
+
+/* The chip can get its input clock from 3 input pins or an XTAL */
+
+/* There is one PLL running at 13500–14256 MHz */
+#define SI5341_PLL_VCO_MIN 13500000000ull
+#define SI5341_PLL_VCO_MAX 14256000000ull
+
+/* The 5 frequency synthesizers obtain their input from the PLL */
+struct clk_si5341_synth {
+       struct clk_hw hw;
+       struct clk_si5341 *data;
+       u8 index;
+};
+#define to_clk_si5341_synth(_hw) \
+       container_of(_hw, struct clk_si5341_synth, hw)
+
+/* The output stages can be connected to any synth (full mux) */
+struct clk_si5341_output {
+       struct clk_hw hw;
+       struct clk_si5341 *data;
+       u8 index;
+};
+#define to_clk_si5341_output(_hw) \
+       container_of(_hw, struct clk_si5341_output, hw)
+
+struct clk_si5341 {
+       struct clk_hw hw;
+       struct regmap *regmap;
+       struct i2c_client *i2c_client;
+       struct clk_si5341_synth synth[SI5341_NUM_SYNTH];
+       struct clk_si5341_output clk[SI5341_MAX_NUM_OUTPUTS];
+       struct clk *pxtal;
+       const char *pxtal_name;
+       const u16 *reg_output_offset;
+       const u16 *reg_rdiv_offset;
+       u64 freq_vco; /* 13500–14256 MHz */
+       u8 num_outputs;
+       u8 num_synth;
+};
+#define to_clk_si5341(_hw)     container_of(_hw, struct clk_si5341, hw)
+
+struct clk_si5341_output_config {
+       u8 out_format_drv_bits;
+       u8 out_cm_ampl_bits;
+       bool synth_master;
+       bool always_on;
+};
+
+#define SI5341_PAGE            0x0001
+#define SI5341_PN_BASE         0x0002
+#define SI5341_DEVICE_REV      0x0005
+#define SI5341_STATUS          0x000C
+#define SI5341_SOFT_RST                0x001C
+
+/* Input dividers (48-bit) */
+#define SI5341_IN_PDIV(x)      (0x0208 + ((x) * 10))
+#define SI5341_IN_PSET(x)      (0x020E + ((x) * 10))
+
+/* PLL configuration */
+#define SI5341_PLL_M_NUM       0x0235
+#define SI5341_PLL_M_DEN       0x023B
+
+/* Output configuration */
+#define SI5341_OUT_CONFIG(output)      \
+                       ((output)->data->reg_output_offset[(output)->index])
+#define SI5341_OUT_FORMAT(output)      (SI5341_OUT_CONFIG(output) + 1)
+#define SI5341_OUT_CM(output)          (SI5341_OUT_CONFIG(output) + 2)
+#define SI5341_OUT_MUX_SEL(output)     (SI5341_OUT_CONFIG(output) + 3)
+#define SI5341_OUT_R_REG(output)       \
+                       ((output)->data->reg_rdiv_offset[(output)->index])
+
+/* Synthesize N divider */
+#define SI5341_SYNTH_N_NUM(x)  (0x0302 + ((x) * 11))
+#define SI5341_SYNTH_N_DEN(x)  (0x0308 + ((x) * 11))
+#define SI5341_SYNTH_N_UPD(x)  (0x030C + ((x) * 11))
+
+/* Synthesizer output enable, phase bypass, power mode */
+#define SI5341_SYNTH_N_CLK_TO_OUTX_EN  0x0A03
+#define SI5341_SYNTH_N_PIBYP           0x0A04
+#define SI5341_SYNTH_N_PDNB            0x0A05
+#define SI5341_SYNTH_N_CLK_DIS         0x0B4A
+
+#define SI5341_REGISTER_MAX    0xBFF
+
+/* SI5341_OUT_CONFIG bits */
+#define SI5341_OUT_CFG_PDN             BIT(0)
+#define SI5341_OUT_CFG_OE              BIT(1)
+#define SI5341_OUT_CFG_RDIV_FORCE2     BIT(2)
+
+/* Static configuration (to be moved to firmware) */
+struct si5341_reg_default {
+       u16 address;
+       u8 value;
+};
+
+/* Output configuration registers 0..9 are not quite logically organized */
+static const u16 si5341_reg_output_offset[] = {
+       0x0108,
+       0x010D,
+       0x0112,
+       0x0117,
+       0x011C,
+       0x0121,
+       0x0126,
+       0x012B,
+       0x0130,
+       0x013A,
+};
+
+static const u16 si5340_reg_output_offset[] = {
+       0x0112,
+       0x0117,
+       0x0126,
+       0x012B,
+};
+
+/* The location of the R divider registers */
+static const u16 si5341_reg_rdiv_offset[] = {
+       0x024A,
+       0x024D,
+       0x0250,
+       0x0253,
+       0x0256,
+       0x0259,
+       0x025C,
+       0x025F,
+       0x0262,
+       0x0268,
+};
+static const u16 si5340_reg_rdiv_offset[] = {
+       0x0250,
+       0x0253,
+       0x025C,
+       0x025F,
+};
+
+/*
+ * Programming sequence from ClockBuilder, settings to initialize the system
+ * using only the XTAL input, without pre-divider.
+ * This also contains settings that aren't mentioned anywhere in the datasheet.
+ * The "known" settings like synth and output configuration are done later.
+ */
+static const struct si5341_reg_default si5341_reg_defaults[] = {
+       { 0x0017, 0x3A }, /* INT mask (disable interrupts) */
+       { 0x0018, 0xFF }, /* INT mask */
+       { 0x0021, 0x0F }, /* Select XTAL as input */
+       { 0x0022, 0x00 }, /* Not in datasheet */
+       { 0x002B, 0x02 }, /* SPI config */
+       { 0x002C, 0x20 }, /* LOS enable for XTAL */
+       { 0x002D, 0x00 }, /* LOS timing */
+       { 0x002E, 0x00 },
+       { 0x002F, 0x00 },
+       { 0x0030, 0x00 },
+       { 0x0031, 0x00 },
+       { 0x0032, 0x00 },
+       { 0x0033, 0x00 },
+       { 0x0034, 0x00 },
+       { 0x0035, 0x00 },
+       { 0x0036, 0x00 },
+       { 0x0037, 0x00 },
+       { 0x0038, 0x00 }, /* LOS setting (thresholds) */
+       { 0x0039, 0x00 },
+       { 0x003A, 0x00 },
+       { 0x003B, 0x00 },
+       { 0x003C, 0x00 },
+       { 0x003D, 0x00 }, /* LOS setting (thresholds) end */
+       { 0x0041, 0x00 }, /* LOS0_DIV_SEL */
+       { 0x0042, 0x00 }, /* LOS1_DIV_SEL */
+       { 0x0043, 0x00 }, /* LOS2_DIV_SEL */
+       { 0x0044, 0x00 }, /* LOS3_DIV_SEL */
+       { 0x009E, 0x00 }, /* Not in datasheet */
+       { 0x0102, 0x01 }, /* Enable outputs */
+       { 0x013F, 0x00 }, /* Not in datasheet */
+       { 0x0140, 0x00 }, /* Not in datasheet */
+       { 0x0141, 0x40 }, /* OUT LOS */
+       { 0x0202, 0x00 }, /* XAXB_FREQ_OFFSET (=0)*/
+       { 0x0203, 0x00 },
+       { 0x0204, 0x00 },
+       { 0x0205, 0x00 },
+       { 0x0206, 0x00 }, /* PXAXB (2^x) */
+       { 0x0208, 0x00 }, /* Px divider setting (usually 0) */
+       { 0x0209, 0x00 },
+       { 0x020A, 0x00 },
+       { 0x020B, 0x00 },
+       { 0x020C, 0x00 },
+       { 0x020D, 0x00 },
+       { 0x020E, 0x00 },
+       { 0x020F, 0x00 },
+       { 0x0210, 0x00 },
+       { 0x0211, 0x00 },
+       { 0x0212, 0x00 },
+       { 0x0213, 0x00 },
+       { 0x0214, 0x00 },
+       { 0x0215, 0x00 },
+       { 0x0216, 0x00 },
+       { 0x0217, 0x00 },
+       { 0x0218, 0x00 },
+       { 0x0219, 0x00 },
+       { 0x021A, 0x00 },
+       { 0x021B, 0x00 },
+       { 0x021C, 0x00 },
+       { 0x021D, 0x00 },
+       { 0x021E, 0x00 },
+       { 0x021F, 0x00 },
+       { 0x0220, 0x00 },
+       { 0x0221, 0x00 },
+       { 0x0222, 0x00 },
+       { 0x0223, 0x00 },
+       { 0x0224, 0x00 },
+       { 0x0225, 0x00 },
+       { 0x0226, 0x00 },
+       { 0x0227, 0x00 },
+       { 0x0228, 0x00 },
+       { 0x0229, 0x00 },
+       { 0x022A, 0x00 },
+       { 0x022B, 0x00 },
+       { 0x022C, 0x00 },
+       { 0x022D, 0x00 },
+       { 0x022E, 0x00 },
+       { 0x022F, 0x00 }, /* Px divider setting (usually 0) end */
+       { 0x026B, 0x00 }, /* DESIGN_ID (ASCII string) */
+       { 0x026C, 0x00 },
+       { 0x026D, 0x00 },
+       { 0x026E, 0x00 },
+       { 0x026F, 0x00 },
+       { 0x0270, 0x00 },
+       { 0x0271, 0x00 },
+       { 0x0272, 0x00 }, /* DESIGN_ID (ASCII string) end */
+       { 0x0339, 0x1F }, /* N_FSTEP_MSK */
+       { 0x033B, 0x00 }, /* Nx_FSTEPW (Frequency step) */
+       { 0x033C, 0x00 },
+       { 0x033D, 0x00 },
+       { 0x033E, 0x00 },
+       { 0x033F, 0x00 },
+       { 0x0340, 0x00 },
+       { 0x0341, 0x00 },
+       { 0x0342, 0x00 },
+       { 0x0343, 0x00 },
+       { 0x0344, 0x00 },
+       { 0x0345, 0x00 },
+       { 0x0346, 0x00 },
+       { 0x0347, 0x00 },
+       { 0x0348, 0x00 },
+       { 0x0349, 0x00 },
+       { 0x034A, 0x00 },
+       { 0x034B, 0x00 },
+       { 0x034C, 0x00 },
+       { 0x034D, 0x00 },
+       { 0x034E, 0x00 },
+       { 0x034F, 0x00 },
+       { 0x0350, 0x00 },
+       { 0x0351, 0x00 },
+       { 0x0352, 0x00 },
+       { 0x0353, 0x00 },
+       { 0x0354, 0x00 },
+       { 0x0355, 0x00 },
+       { 0x0356, 0x00 },
+       { 0x0357, 0x00 },
+       { 0x0358, 0x00 }, /* Nx_FSTEPW (Frequency step) end */
+       { 0x0359, 0x00 }, /* Nx_DELAY */
+       { 0x035A, 0x00 },
+       { 0x035B, 0x00 },
+       { 0x035C, 0x00 },
+       { 0x035D, 0x00 },
+       { 0x035E, 0x00 },
+       { 0x035F, 0x00 },
+       { 0x0360, 0x00 },
+       { 0x0361, 0x00 },
+       { 0x0362, 0x00 }, /* Nx_DELAY end */
+       { 0x0802, 0x00 }, /* Not in datasheet */
+       { 0x0803, 0x00 }, /* Not in datasheet */
+       { 0x0804, 0x00 }, /* Not in datasheet */
+       { 0x090E, 0x02 }, /* XAXB_EXTCLK_EN=0 XAXB_PDNB=1 (use XTAL) */
+       { 0x091C, 0x04 }, /* ZDM_EN=4 (Normal mode) */
+       { 0x0943, 0x00 }, /* IO_VDD_SEL=0 (0=1v8, use 1=3v3) */
+       { 0x0949, 0x00 }, /* IN_EN (disable input clocks) */
+       { 0x094A, 0x00 }, /* INx_TO_PFD_EN (disabled) */
+       { 0x0A02, 0x00 }, /* Not in datasheet */
+       { 0x0B44, 0x0F }, /* PDIV_ENB (datasheet does not mention what it is) */
+};
+
+/* Read and interpret a 44-bit followed by a 32-bit value in the regmap */
+static int si5341_decode_44_32(struct regmap *regmap, unsigned int reg,
+       u64 *val1, u32 *val2)
+{
+       int err;
+       u8 r[10];
+
+       err = regmap_bulk_read(regmap, reg, r, 10);
+       if (err < 0)
+               return err;
+
+       *val1 = ((u64)((r[5] & 0x0f) << 8 | r[4]) << 32) |
+                (get_unaligned_le32(r));
+       *val2 = get_unaligned_le32(&r[6]);
+
+       return 0;
+}
+
+static int si5341_encode_44_32(struct regmap *regmap, unsigned int reg,
+       u64 n_num, u32 n_den)
+{
+       u8 r[10];
+
+       /* Shift left as far as possible without overflowing */
+       while (!(n_num & BIT_ULL(43)) && !(n_den & BIT(31))) {
+               n_num <<= 1;
+               n_den <<= 1;
+       }
+
+       /* 44 bits (6 bytes) numerator */
+       put_unaligned_le32(n_num, r);
+       r[4] = (n_num >> 32) & 0xff;
+       r[5] = (n_num >> 40) & 0x0f;
+       /* 32 bits denominator */
+       put_unaligned_le32(n_den, &r[6]);
+
+       /* Program the fraction */
+       return regmap_bulk_write(regmap, reg, r, sizeof(r));
+}
+
+/* VCO, we assume it runs at a constant frequency */
+static unsigned long si5341_clk_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       struct clk_si5341 *data = to_clk_si5341(hw);
+       int err;
+       u64 res;
+       u64 m_num;
+       u32 m_den;
+       unsigned int shift;
+
+       /* Assume that PDIV is not being used, just read the PLL setting */
+       err = si5341_decode_44_32(data->regmap, SI5341_PLL_M_NUM,
+                               &m_num, &m_den);
+       if (err < 0)
+               return 0;
+
+       if (!m_num || !m_den)
+               return 0;
+
+       /*
+        * Though m_num is 64-bit, only the upper bits are actually used. While
+        * calculating m_num and m_den, they are shifted as far as possible to
+        * the left. To avoid 96-bit division here, we just shift them back so
+        * we can do with just 64 bits.
+        */
+       shift = 0;
+       res = m_num;
+       while (res & 0xffff00000000ULL) {
+               ++shift;
+               res >>= 1;
+       }
+       res *= parent_rate;
+       do_div(res, (m_den >> shift));
+
+       /* We cannot return the actual frequency in 32 bit, store it locally */
+       data->freq_vco = res;
+
+       /* Report kHz since the value is out of range */
+       do_div(res, 1000);
+
+       return (unsigned long)res;
+}
+
+static const struct clk_ops si5341_clk_ops = {
+       .recalc_rate = si5341_clk_recalc_rate,
+};
+
+/* Synthesizers, there are 5 synthesizers that connect to any of the outputs */
+
+/* The synthesizer is on if all power and enable bits are set */
+static int si5341_synth_clk_is_on(struct clk_hw *hw)
+{
+       struct clk_si5341_synth *synth = to_clk_si5341_synth(hw);
+       int err;
+       u32 val;
+       u8 index = synth->index;
+
+       err = regmap_read(synth->data->regmap,
+                       SI5341_SYNTH_N_CLK_TO_OUTX_EN, &val);
+       if (err < 0)
+               return 0;
+
+       if (!(val & BIT(index)))
+               return 0;
+
+       err = regmap_read(synth->data->regmap, SI5341_SYNTH_N_PDNB, &val);
+       if (err < 0)
+               return 0;
+
+       if (!(val & BIT(index)))
+               return 0;
+
+       /* This bit must be 0 for the synthesizer to receive clock input */
+       err = regmap_read(synth->data->regmap, SI5341_SYNTH_N_CLK_DIS, &val);
+       if (err < 0)
+               return 0;
+
+       return !(val & BIT(index));
+}
+
+static void si5341_synth_clk_unprepare(struct clk_hw *hw)
+{
+       struct clk_si5341_synth *synth = to_clk_si5341_synth(hw);
+       u8 index = synth->index; /* In range 0..5 */
+       u8 mask = BIT(index);
+
+       /* Disable output */
+       regmap_update_bits(synth->data->regmap,
+               SI5341_SYNTH_N_CLK_TO_OUTX_EN, mask, 0);
+       /* Power down */
+       regmap_update_bits(synth->data->regmap,
+               SI5341_SYNTH_N_PDNB, mask, 0);
+       /* Disable clock input to synth (set to 1 to disable) */
+       regmap_update_bits(synth->data->regmap,
+               SI5341_SYNTH_N_CLK_DIS, mask, mask);
+}
+
+static int si5341_synth_clk_prepare(struct clk_hw *hw)
+{
+       struct clk_si5341_synth *synth = to_clk_si5341_synth(hw);
+       int err;
+       u8 index = synth->index;
+       u8 mask = BIT(index);
+
+       /* Power up */
+       err = regmap_update_bits(synth->data->regmap,
+               SI5341_SYNTH_N_PDNB, mask, mask);
+       if (err < 0)
+               return err;
+
+       /* Enable clock input to synth (set bit to 0 to enable) */
+       err = regmap_update_bits(synth->data->regmap,
+               SI5341_SYNTH_N_CLK_DIS, mask, 0);
+       if (err < 0)
+               return err;
+
+       /* Enable output */
+       return regmap_update_bits(synth->data->regmap,
+               SI5341_SYNTH_N_CLK_TO_OUTX_EN, mask, mask);
+}
+
+/* Synth clock frequency: Fvco * n_den / n_den, with Fvco in 13500-14256 MHz */
+static unsigned long si5341_synth_clk_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       struct clk_si5341_synth *synth = to_clk_si5341_synth(hw);
+       u64 f;
+       u64 n_num;
+       u32 n_den;
+       int err;
+
+       err = si5341_decode_44_32(synth->data->regmap,
+                       SI5341_SYNTH_N_NUM(synth->index), &n_num, &n_den);
+       if (err < 0)
+               return err;
+
+       /*
+        * n_num and n_den are shifted left as much as possible, so to prevent
+        * overflow in 64-bit math, we shift n_den 4 bits to the right
+        */
+       f = synth->data->freq_vco;
+       f *= n_den >> 4;
+
+       /* Now we need to to 64-bit division: f/n_num */
+       /* And compensate for the 4 bits we dropped */
+       f = div64_u64(f, (n_num >> 4));
+
+       return f;
+}
+
+static long si5341_synth_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *parent_rate)
+{
+       struct clk_si5341_synth *synth = to_clk_si5341_synth(hw);
+       u64 f;
+
+       /* The synthesizer accuracy is such that anything in range will work */
+       f = synth->data->freq_vco;
+       do_div(f, SI5341_SYNTH_N_MAX);
+       if (rate < f)
+               return f;
+
+       f = synth->data->freq_vco;
+       do_div(f, SI5341_SYNTH_N_MIN);
+       if (rate > f)
+               return f;
+
+       return rate;
+}
+
+static int si5341_synth_program(struct clk_si5341_synth *synth,
+       u64 n_num, u32 n_den, bool is_integer)
+{
+       int err;
+       u8 index = synth->index;
+
+       err = si5341_encode_44_32(synth->data->regmap,
+                       SI5341_SYNTH_N_NUM(index), n_num, n_den);
+
+       err = regmap_update_bits(synth->data->regmap,
+               SI5341_SYNTH_N_PIBYP, BIT(index), is_integer ? BIT(index) : 0);
+       if (err < 0)
+               return err;
+
+       return regmap_write(synth->data->regmap,
+               SI5341_SYNTH_N_UPD(index), 0x01);
+}
+
+
+static int si5341_synth_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long parent_rate)
+{
+       struct clk_si5341_synth *synth = to_clk_si5341_synth(hw);
+       u64 n_num;
+       u32 n_den;
+       u32 r;
+       u32 g;
+       bool is_integer;
+
+       n_num = synth->data->freq_vco;
+       n_den = rate;
+
+       /* see if there's an integer solution */
+       r = do_div(n_num, rate);
+       is_integer = (r == 0);
+       if (is_integer) {
+               /* Integer divider equal to n_num */
+               n_den = 1;
+       } else {
+               /* Calculate a fractional solution */
+               g = gcd(r, rate);
+               n_den = rate / g;
+               n_num *= n_den;
+               n_num += r / g;
+       }
+
+       dev_dbg(&synth->data->i2c_client->dev,
+                       "%s(%u): n=0x%llx d=0x%x %s\n", __func__,
+                               synth->index, n_num, n_den,
+                               is_integer ? "int" : "frac");
+
+       return si5341_synth_program(synth, n_num, n_den, is_integer);
+}
+
+static const struct clk_ops si5341_synth_clk_ops = {
+       .is_prepared = si5341_synth_clk_is_on,
+       .prepare = si5341_synth_clk_prepare,
+       .unprepare = si5341_synth_clk_unprepare,
+       .recalc_rate = si5341_synth_clk_recalc_rate,
+       .round_rate = si5341_synth_clk_round_rate,
+       .set_rate = si5341_synth_clk_set_rate,
+};
+
+static int si5341_output_clk_is_on(struct clk_hw *hw)
+{
+       struct clk_si5341_output *output = to_clk_si5341_output(hw);
+       int err;
+       u32 val;
+
+       err = regmap_read(output->data->regmap,
+                       SI5341_OUT_CONFIG(output), &val);
+       if (err < 0)
+               return err;
+
+       /* Bit 0=PDN, 1=OE so only a value of 0x2 enables the output */
+       return (val & 0x03) == SI5341_OUT_CFG_OE;
+}
+
+/* Disables and then powers down the output */
+static void si5341_output_clk_unprepare(struct clk_hw *hw)
+{
+       struct clk_si5341_output *output = to_clk_si5341_output(hw);
+
+       regmap_update_bits(output->data->regmap,
+                       SI5341_OUT_CONFIG(output),
+                       SI5341_OUT_CFG_OE, 0);
+       regmap_update_bits(output->data->regmap,
+                       SI5341_OUT_CONFIG(output),
+                       SI5341_OUT_CFG_PDN, SI5341_OUT_CFG_PDN);
+}
+
+/* Powers up and then enables the output */
+static int si5341_output_clk_prepare(struct clk_hw *hw)
+{
+       struct clk_si5341_output *output = to_clk_si5341_output(hw);
+       int err;
+
+       err = regmap_update_bits(output->data->regmap,
+                       SI5341_OUT_CONFIG(output),
+                       SI5341_OUT_CFG_PDN, 0);
+       if (err < 0)
+               return err;
+
+       return regmap_update_bits(output->data->regmap,
+                       SI5341_OUT_CONFIG(output),
+                       SI5341_OUT_CFG_OE, SI5341_OUT_CFG_OE);
+}
+
+static unsigned long si5341_output_clk_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       struct clk_si5341_output *output = to_clk_si5341_output(hw);
+       int err;
+       u32 val;
+       u32 r_divider;
+       u8 r[3];
+
+       err = regmap_bulk_read(output->data->regmap,
+                       SI5341_OUT_R_REG(output), r, 3);
+       if (err < 0)
+               return err;
+
+       /* Calculate value as 24-bit integer*/
+       r_divider = r[2] << 16 | r[1] << 8 | r[0];
+
+       /* If Rx_REG is zero, the divider is disabled, so return a "0" rate */
+       if (!r_divider)
+               return 0;
+
+       /* Divider is 2*(Rx_REG+1) */
+       r_divider += 1;
+       r_divider <<= 1;
+
+       err = regmap_read(output->data->regmap,
+                       SI5341_OUT_CONFIG(output), &val);
+       if (err < 0)
+               return err;
+
+       if (val & SI5341_OUT_CFG_RDIV_FORCE2)
+               r_divider = 2;
+
+       return parent_rate / r_divider;
+}
+
+static long si5341_output_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *parent_rate)
+{
+       unsigned long r;
+
+       r = *parent_rate >> 1;
+
+       /* If rate is an even divisor, no changes to parent required */
+       if (r && !(r % rate))
+               return (long)rate;
+
+       if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
+               if (rate > 200000000) {
+                       /* minimum r-divider is 2 */
+                       r = 2;
+               } else {
+                       /* Take a parent frequency near 400 MHz */
+                       r = (400000000u / rate) & ~1;
+               }
+               *parent_rate = r * rate;
+       } else {
+               /* We cannot change our parent's rate, report what we can do */
+               r /= rate;
+               rate = *parent_rate / (r << 1);
+       }
+
+       return rate;
+}
+
+static int si5341_output_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long parent_rate)
+{
+       struct clk_si5341_output *output = to_clk_si5341_output(hw);
+       /* Frequency divider is (r_div + 1) * 2 */
+       u32 r_div = (parent_rate / rate) >> 1;
+       int err;
+       u8 r[3];
+
+       if (r_div <= 1)
+               r_div = 0;
+       else if (r_div >= BIT(24))
+               r_div = BIT(24) - 1;
+       else
+               --r_div;
+
+       /* For a value of "2", we set the "OUT0_RDIV_FORCE2" bit */
+       err = regmap_update_bits(output->data->regmap,
+                       SI5341_OUT_CONFIG(output),
+                       SI5341_OUT_CFG_RDIV_FORCE2,
+                       (r_div == 0) ? SI5341_OUT_CFG_RDIV_FORCE2 : 0);
+       if (err < 0)
+               return err;
+
+       /* Always write Rx_REG, because a zero value disables the divider */
+       r[0] = r_div ? (r_div & 0xff) : 1;
+       r[1] = (r_div >> 8) & 0xff;
+       r[2] = (r_div >> 16) & 0xff;
+       err = regmap_bulk_write(output->data->regmap,
+                       SI5341_OUT_R_REG(output), r, 3);
+
+       return 0;
+}
+
+static int si5341_output_reparent(struct clk_si5341_output *output, u8 index)
+{
+       return regmap_update_bits(output->data->regmap,
+               SI5341_OUT_MUX_SEL(output), 0x07, index);
+}
+
+static int si5341_output_set_parent(struct clk_hw *hw, u8 index)
+{
+       struct clk_si5341_output *output = to_clk_si5341_output(hw);
+
+       if (index >= output->data->num_synth)
+               return -EINVAL;
+
+       return si5341_output_reparent(output, index);
+}
+
+static u8 si5341_output_get_parent(struct clk_hw *hw)
+{
+       struct clk_si5341_output *output = to_clk_si5341_output(hw);
+       int err;
+       u32 val;
+
+       err = regmap_read(output->data->regmap,
+                       SI5341_OUT_MUX_SEL(output), &val);
+
+       return val & 0x7;
+}
+
+static const struct clk_ops si5341_output_clk_ops = {
+       .is_prepared = si5341_output_clk_is_on,
+       .prepare = si5341_output_clk_prepare,
+       .unprepare = si5341_output_clk_unprepare,
+       .recalc_rate = si5341_output_clk_recalc_rate,
+       .round_rate = si5341_output_clk_round_rate,
+       .set_rate = si5341_output_clk_set_rate,
+       .set_parent = si5341_output_set_parent,
+       .get_parent = si5341_output_get_parent,
+};
+
+/*
+ * The chip can be bought in a pre-programmed version, or one can program the
+ * NVM in the chip to boot up in a preset mode. This routine tries to determine
+ * if that's the case, or if we need to reset and program everything from
+ * scratch. Returns negative error, or true/false.
+ */
+static int si5341_is_programmed_already(struct clk_si5341 *data)
+{
+       int err;
+       u8 r[4];
+
+       /* Read the PLL divider value, it must have a non-zero value */
+       err = regmap_bulk_read(data->regmap, SI5341_PLL_M_DEN,
+                       r, ARRAY_SIZE(r));
+       if (err < 0)
+               return err;
+
+       return !!get_unaligned_le32(r);
+}
+
+static struct clk_hw *
+of_clk_si5341_get(struct of_phandle_args *clkspec, void *_data)
+{
+       struct clk_si5341 *data = _data;
+       unsigned int idx = clkspec->args[1];
+       unsigned int group = clkspec->args[0];
+
+       switch (group) {
+       case 0:
+               if (idx >= data->num_outputs) {
+                       dev_err(&data->i2c_client->dev,
+                               "invalid output index %u\n", idx);
+                       return ERR_PTR(-EINVAL);
+               }
+               return &data->clk[idx].hw;
+       case 1:
+               if (idx >= data->num_synth) {
+                       dev_err(&data->i2c_client->dev,
+                               "invalid synthesizer index %u\n", idx);
+                       return ERR_PTR(-EINVAL);
+               }
+               return &data->synth[idx].hw;
+       case 2:
+               if (idx > 0) {
+                       dev_err(&data->i2c_client->dev,
+                               "invalid PLL index %u\n", idx);
+                       return ERR_PTR(-EINVAL);
+               }
+               return &data->hw;
+       default:
+               dev_err(&data->i2c_client->dev, "invalid group %u\n", group);
+               return ERR_PTR(-EINVAL);
+       }
+}
+
+static int si5341_probe_chip_id(struct clk_si5341 *data)
+{
+       int err;
+       u8 reg[4];
+       u16 model;
+
+       err = regmap_bulk_read(data->regmap, SI5341_PN_BASE, reg,
+                               ARRAY_SIZE(reg));
+       if (err < 0) {
+               dev_err(&data->i2c_client->dev, "Failed to read chip ID\n");
+               return err;
+       }
+
+       model = get_unaligned_le16(reg);
+
+       dev_info(&data->i2c_client->dev, "Chip: %x Grade: %u Rev: %u\n",
+                model, reg[2], reg[3]);
+
+       switch (model) {
+       case 0x5340:
+               data->num_outputs = SI5340_MAX_NUM_OUTPUTS;
+               data->num_synth = SI5340_NUM_SYNTH;
+               data->reg_output_offset = si5340_reg_output_offset;
+               data->reg_rdiv_offset = si5340_reg_rdiv_offset;
+               break;
+       case 0x5341:
+               data->num_outputs = SI5341_MAX_NUM_OUTPUTS;
+               data->num_synth = SI5341_NUM_SYNTH;
+               data->reg_output_offset = si5341_reg_output_offset;
+               data->reg_rdiv_offset = si5341_reg_rdiv_offset;
+               break;
+       default:
+               dev_err(&data->i2c_client->dev, "Model '%x' not supported\n",
+                       model);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* Read active settings into the regmap cache for later reference */
+static int si5341_read_settings(struct clk_si5341 *data)
+{
+       int err;
+       u8 i;
+       u8 r[10];
+
+       err = regmap_bulk_read(data->regmap, SI5341_PLL_M_NUM, r, 10);
+       if (err < 0)
+               return err;
+
+       err = regmap_bulk_read(data->regmap,
+                               SI5341_SYNTH_N_CLK_TO_OUTX_EN, r, 3);
+       if (err < 0)
+               return err;
+
+       err = regmap_bulk_read(data->regmap,
+                               SI5341_SYNTH_N_CLK_DIS, r, 1);
+       if (err < 0)
+               return err;
+
+       for (i = 0; i < data->num_synth; ++i) {
+               err = regmap_bulk_read(data->regmap,
+                                       SI5341_SYNTH_N_NUM(i), r, 10);
+               if (err < 0)
+                       return err;
+       }
+
+       for (i = 0; i < data->num_outputs; ++i) {
+               err = regmap_bulk_read(data->regmap,
+                                       data->reg_output_offset[i], r, 4);
+               if (err < 0)
+                       return err;
+
+               err = regmap_bulk_read(data->regmap,
+                                       data->reg_rdiv_offset[i], r, 3);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int si5341_write_multiple(struct clk_si5341 *data,
+       const struct si5341_reg_default *values, unsigned int num_values)
+{
+       unsigned int i;
+       int res;
+
+       for (i = 0; i < num_values; ++i) {
+               res = regmap_write(data->regmap,
+                       values[i].address, values[i].value);
+               if (res < 0) {
+                       dev_err(&data->i2c_client->dev,
+                               "Failed to write %#x:%#x\n",
+                               values[i].address, values[i].value);
+                       return res;
+               }
+       }
+
+       return 0;
+}
+
+static const struct si5341_reg_default si5341_preamble[] = {
+       { 0x0B25, 0x00 },
+       { 0x0502, 0x01 },
+       { 0x0505, 0x03 },
+       { 0x0957, 0x1F },
+       { 0x0B4E, 0x1A },
+};
+
+static int si5341_send_preamble(struct clk_si5341 *data)
+{
+       int res;
+       u32 revision;
+
+       /* For revision 2 and up, the values are slightly different */
+       res = regmap_read(data->regmap, SI5341_DEVICE_REV, &revision);
+       if (res < 0)
+               return res;
+
+       /* Write "preamble" as specified by datasheet */
+       res = regmap_write(data->regmap, 0xB24, revision < 2 ? 0xD8 : 0xC0);
+       if (res < 0)
+               return res;
+       res = si5341_write_multiple(data,
+               si5341_preamble, ARRAY_SIZE(si5341_preamble));
+       if (res < 0)
+               return res;
+
+       /* Datasheet specifies a 300ms wait after sending the preamble */
+       msleep(300);
+
+       return 0;
+}
+
+/* Perform a soft reset and write post-amble */
+static int si5341_finalize_defaults(struct clk_si5341 *data)
+{
+       int res;
+       u32 revision;
+
+       res = regmap_read(data->regmap, SI5341_DEVICE_REV, &revision);
+       if (res < 0)
+               return res;
+
+       dev_dbg(&data->i2c_client->dev, "%s rev=%u\n", __func__, revision);
+
+       res = regmap_write(data->regmap, SI5341_SOFT_RST, 0x01);
+       if (res < 0)
+               return res;
+
+       /* Datasheet does not explain these nameless registers */
+       res = regmap_write(data->regmap, 0xB24, revision < 2 ? 0xDB : 0xC3);
+       if (res < 0)
+               return res;
+       res = regmap_write(data->regmap, 0x0B25, 0x02);
+       if (res < 0)
+               return res;
+
+       return 0;
+}
+
+
+static const struct regmap_range si5341_regmap_volatile_range[] = {
+       regmap_reg_range(0x000C, 0x0012), /* Status */
+       regmap_reg_range(0x001C, 0x001E), /* reset, finc/fdec */
+       regmap_reg_range(0x00E2, 0x00FE), /* NVM, interrupts, device ready */
+       /* Update bits for synth config */
+       regmap_reg_range(SI5341_SYNTH_N_UPD(0), SI5341_SYNTH_N_UPD(0)),
+       regmap_reg_range(SI5341_SYNTH_N_UPD(1), SI5341_SYNTH_N_UPD(1)),
+       regmap_reg_range(SI5341_SYNTH_N_UPD(2), SI5341_SYNTH_N_UPD(2)),
+       regmap_reg_range(SI5341_SYNTH_N_UPD(3), SI5341_SYNTH_N_UPD(3)),
+       regmap_reg_range(SI5341_SYNTH_N_UPD(4), SI5341_SYNTH_N_UPD(4)),
+};
+
+static const struct regmap_access_table si5341_regmap_volatile = {
+       .yes_ranges = si5341_regmap_volatile_range,
+       .n_yes_ranges = ARRAY_SIZE(si5341_regmap_volatile_range),
+};
+
+/* Pages 0, 1, 2, 3, 9, A, B are valid, so there are 12 pages */
+static const struct regmap_range_cfg si5341_regmap_ranges[] = {
+       {
+               .range_min = 0,
+               .range_max = SI5341_REGISTER_MAX,
+               .selector_reg = SI5341_PAGE,
+               .selector_mask = 0xff,
+               .selector_shift = 0,
+               .window_start = 0,
+               .window_len = 256,
+       },
+};
+
+static const struct regmap_config si5341_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .cache_type = REGCACHE_RBTREE,
+       .ranges = si5341_regmap_ranges,
+       .num_ranges = ARRAY_SIZE(si5341_regmap_ranges),
+       .max_register = SI5341_REGISTER_MAX,
+       .volatile_table = &si5341_regmap_volatile,
+};
+
+static int si5341_dt_parse_dt(struct i2c_client *client,
+       struct clk_si5341_output_config *config)
+{
+       struct device_node *child;
+       struct device_node *np = client->dev.of_node;
+       u32 num;
+       u32 val;
+
+       memset(config, 0, sizeof(struct clk_si5341_output_config) *
+                               SI5341_MAX_NUM_OUTPUTS);
+
+       for_each_child_of_node(np, child) {
+               if (of_property_read_u32(child, "reg", &num)) {
+                       dev_err(&client->dev, "missing reg property of %s\n",
+                               child->name);
+                       goto put_child;
+               }
+
+               if (num >= SI5341_MAX_NUM_OUTPUTS) {
+                       dev_err(&client->dev, "invalid clkout %d\n", num);
+                       goto put_child;
+               }
+
+               if (!of_property_read_u32(child, "silabs,format", &val)) {
+                       /* Set cm and ampl conservatively to 3v3 settings */
+                       switch (val) {
+                       case 1: /* normal differential */
+                               config[num].out_cm_ampl_bits = 0x33;
+                               break;
+                       case 2: /* low-power differential */
+                               config[num].out_cm_ampl_bits = 0x13;
+                               break;
+                       case 4: /* LVCMOS */
+                               config[num].out_cm_ampl_bits = 0x33;
+                               /* Set SI recommended impedance for LVCMOS */
+                               config[num].out_format_drv_bits |= 0xc0;
+                               break;
+                       default:
+                               dev_err(&client->dev,
+                                       "invalid silabs,format %u for %u\n",
+                                       val, num);
+                               goto put_child;
+                       }
+                       config[num].out_format_drv_bits &= ~0x07;
+                       config[num].out_format_drv_bits |= val & 0x07;
+                       /* Always enable the SYNC feature */
+                       config[num].out_format_drv_bits |= 0x08;
+               }
+
+               if (!of_property_read_u32(child, "silabs,common-mode", &val)) {
+                       if (val > 0xf) {
+                               dev_err(&client->dev,
+                                       "invalid silabs,common-mode %u\n",
+                                       val);
+                               goto put_child;
+                       }
+                       config[num].out_cm_ampl_bits &= 0xf0;
+                       config[num].out_cm_ampl_bits |= val & 0x0f;
+               }
+
+               if (!of_property_read_u32(child, "silabs,amplitude", &val)) {
+                       if (val > 0xf) {
+                               dev_err(&client->dev,
+                                       "invalid silabs,amplitude %u\n",
+                                       val);
+                               goto put_child;
+                       }
+                       config[num].out_cm_ampl_bits &= 0x0f;
+                       config[num].out_cm_ampl_bits |= (val << 4) & 0xf0;
+               }
+
+               if (of_property_read_bool(child, "silabs,disable-high"))
+                       config[num].out_format_drv_bits |= 0x10;
+
+               config[num].synth_master =
+                       of_property_read_bool(child, "silabs,synth-master");
+
+               config[num].always_on =
+                       of_property_read_bool(child, "always-on");
+       }
+
+       return 0;
+
+put_child:
+       of_node_put(child);
+       return -EINVAL;
+}
+
+/*
+ * If not pre-configured, calculate and set the PLL configuration manually.
+ * For low-jitter performance, the PLL should be set such that the synthesizers
+ * only need integer division.
+ * Without any user guidance, we'll set the PLL to 14GHz, which still allows
+ * the chip to generate any frequency on its outputs, but jitter performance
+ * may be sub-optimal.
+ */
+static int si5341_initialize_pll(struct clk_si5341 *data)
+{
+       struct device_node *np = data->i2c_client->dev.of_node;
+       u32 m_num = 0;
+       u32 m_den = 0;
+
+       if (of_property_read_u32(np, "silabs,pll-m-num", &m_num)) {
+               dev_err(&data->i2c_client->dev,
+                       "PLL configuration requires silabs,pll-m-num\n");
+       }
+       if (of_property_read_u32(np, "silabs,pll-m-den", &m_den)) {
+               dev_err(&data->i2c_client->dev,
+                       "PLL configuration requires silabs,pll-m-den\n");
+       }
+
+       if (!m_num || !m_den) {
+               dev_err(&data->i2c_client->dev,
+                       "PLL configuration invalid, assume 14GHz\n");
+               m_den = clk_get_rate(data->pxtal) / 10;
+               m_num = 1400000000;
+       }
+
+       return si5341_encode_44_32(data->regmap,
+                       SI5341_PLL_M_NUM, m_num, m_den);
+}
+
+static int si5341_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       struct clk_si5341 *data;
+       struct clk_init_data init;
+       const char *root_clock_name;
+       const char *synth_clock_names[SI5341_NUM_SYNTH];
+       int err;
+       unsigned int i;
+       struct clk_si5341_output_config config[SI5341_MAX_NUM_OUTPUTS];
+       bool initialization_required;
+
+       data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->i2c_client = client;
+
+       data->pxtal = devm_clk_get(&client->dev, "xtal");
+       if (IS_ERR(data->pxtal)) {
+               if (PTR_ERR(data->pxtal) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+
+               dev_err(&client->dev, "Missing xtal clock input\n");
+       }
+
+       err = si5341_dt_parse_dt(client, config);
+       if (err)
+               return err;
+
+       if (of_property_read_string(client->dev.of_node, "clock-output-names",
+                       &init.name))
+               init.name = client->dev.of_node->name;
+       root_clock_name = init.name;
+
+       data->regmap = devm_regmap_init_i2c(client, &si5341_regmap_config);
+       if (IS_ERR(data->regmap))
+               return PTR_ERR(data->regmap);
+
+       i2c_set_clientdata(client, data);
+
+       err = si5341_probe_chip_id(data);
+       if (err < 0)
+               return err;
+
+       /* "Activate" the xtal (usually a fixed clock) */
+       clk_prepare_enable(data->pxtal);
+
+       if (of_property_read_bool(client->dev.of_node, "silabs,reprogram")) {
+               initialization_required = true;
+       } else {
+               err = si5341_is_programmed_already(data);
+               if (err < 0)
+                       return err;
+
+               initialization_required = !err;
+       }
+
+       if (initialization_required) {
+               /* Populate the regmap cache in preparation for "cache only" */
+               err = si5341_read_settings(data);
+               if (err < 0)
+                       return err;
+
+               err = si5341_send_preamble(data);
+               if (err < 0)
+                       return err;
+
+               /*
+                * We intend to send all 'final' register values in a single
+                * transaction. So cache all register writes until we're done
+                * configuring.
+                */
+               regcache_cache_only(data->regmap, true);
+
+               /* Write the configuration pairs from the firmware blob */
+               err = si5341_write_multiple(data, si5341_reg_defaults,
+                                       ARRAY_SIZE(si5341_reg_defaults));
+               if (err < 0)
+                       return err;
+
+               /* PLL configuration is required */
+               err = si5341_initialize_pll(data);
+               if (err < 0)
+                       return err;
+       }
+
+       /* Register the PLL */
+       data->pxtal_name = __clk_get_name(data->pxtal);
+       init.parent_names = &data->pxtal_name;
+       init.num_parents = 1; /* For now, only XTAL input supported */
+       init.ops = &si5341_clk_ops;
+       init.flags = 0;
+       data->hw.init = &init;
+
+       err = devm_clk_hw_register(&client->dev, &data->hw);
+       if (err) {
+               dev_err(&client->dev, "clock registration failed\n");
+               return err;
+       }
+
+       init.num_parents = 1;
+       init.parent_names = &root_clock_name;
+       init.ops = &si5341_synth_clk_ops;
+       for (i = 0; i < data->num_synth; ++i) {
+               synth_clock_names[i] = devm_kasprintf(&client->dev, GFP_KERNEL,
+                               "%s.N%u", client->dev.of_node->name, i);
+               init.name = synth_clock_names[i];
+               data->synth[i].index = i;
+               data->synth[i].data = data;
+               data->synth[i].hw.init = &init;
+               err = devm_clk_hw_register(&client->dev, &data->synth[i].hw);
+               if (err) {
+                       dev_err(&client->dev,
+                               "synth N%u registration failed\n", i);
+               }
+       }
+
+       init.num_parents = data->num_synth;
+       init.parent_names = synth_clock_names;
+       init.ops = &si5341_output_clk_ops;
+       for (i = 0; i < data->num_outputs; ++i) {
+               init.name = kasprintf(GFP_KERNEL, "%s.%d",
+                       client->dev.of_node->name, i);
+               init.flags = config[i].synth_master ? CLK_SET_RATE_PARENT : 0;
+               data->clk[i].index = i;
+               data->clk[i].data = data;
+               data->clk[i].hw.init = &init;
+               if (config[i].out_format_drv_bits & 0x07) {
+                       regmap_write(data->regmap,
+                               SI5341_OUT_FORMAT(&data->clk[i]),
+                               config[i].out_format_drv_bits);
+                       regmap_write(data->regmap,
+                               SI5341_OUT_CM(&data->clk[i]),
+                               config[i].out_cm_ampl_bits);
+               }
+               err = devm_clk_hw_register(&client->dev, &data->clk[i].hw);
+               kfree(init.name); /* clock framework made a copy of the name */
+               if (err) {
+                       dev_err(&client->dev,
+                               "output %u registration failed\n", i);
+                       return err;
+               }
+               if (config[i].always_on)
+                       clk_prepare(data->clk[i].hw.clk);
+       }
+
+       err = of_clk_add_hw_provider(client->dev.of_node, of_clk_si5341_get,
+                       data);
+       if (err) {
+               dev_err(&client->dev, "unable to add clk provider\n");
+               return err;
+       }
+
+       if (initialization_required) {
+               /* Synchronize */
+               regcache_cache_only(data->regmap, false);
+               err = regcache_sync(data->regmap);
+               if (err < 0)
+                       return err;
+
+               err = si5341_finalize_defaults(data);
+               if (err < 0)
+                       return err;
+       }
+
+       /* Free the names, clk framework makes copies */
+       for (i = 0; i < data->num_synth; ++i)
+                devm_kfree(&client->dev, (void *)synth_clock_names[i]);
+
+       return 0;
+}
+
+static const struct i2c_device_id si5341_id[] = {
+       { "si5340", 0 },
+       { "si5341", 1 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, si5341_id);
+
+static const struct of_device_id clk_si5341_of_match[] = {
+       { .compatible = "silabs,si5340" },
+       { .compatible = "silabs,si5341" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, clk_si5341_of_match);
+
+static struct i2c_driver si5341_driver = {
+       .driver = {
+               .name = "si5341",
+               .of_match_table = clk_si5341_of_match,
+       },
+       .probe          = si5341_probe,
+       .id_table       = si5341_id,
+};
+module_i2c_driver(si5341_driver);
+
+MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>");
+MODULE_DESCRIPTION("Si5341 driver");
+MODULE_LICENSE("GPL");
index 64e607f..d9ec908 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
+#include <linux/math64.h>
 #include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/regmap.h>
 /* Lowest frequency synthesizeable using only the HS divider */
 #define MIN_HSDIV_FREQ (FVCO_MIN / HS_DIV_MAX)
 
+/* Range and interpretation of the adjustment value */
+#define DELTA_M_MAX    8161512
+#define DELTA_M_FRAC_NUM       19
+#define DELTA_M_FRAC_DEN       20000
+
 enum si544_speed_grade {
        si544a,
        si544b,
@@ -71,12 +77,14 @@ struct clk_si544 {
  * @hs_div:            1st divider, 5..2046, must be even when >33
  * @ls_div_bits:       2nd divider, as 2^x, range 0..5
  *                      If ls_div_bits is non-zero, hs_div must be even
+ * @delta_m:           Frequency shift for small -950..+950 ppm changes, 24 bit
  */
 struct clk_si544_muldiv {
        u32 fb_div_frac;
        u16 fb_div_int;
        u16 hs_div;
        u8 ls_div_bits;
+       s32 delta_m;
 };
 
 /* Enables or disables the output driver */
@@ -134,9 +142,30 @@ static int si544_get_muldiv(struct clk_si544 *data,
        settings->fb_div_int = reg[4] | (reg[5] & 0x07) << 8;
        settings->fb_div_frac = reg[0] | reg[1] << 8 | reg[2] << 16 |
                                reg[3] << 24;
+
+       err = regmap_bulk_read(data->regmap, SI544_REG_ADPLL_DELTA_M0, reg, 3);
+       if (err)
+               return err;
+
+       /* Interpret as 24-bit signed number */
+       settings->delta_m = reg[0] << 8 | reg[1] << 16 | reg[2] << 24;
+       settings->delta_m >>= 8;
+
        return 0;
 }
 
+static int si544_set_delta_m(struct clk_si544 *data, s32 delta_m)
+{
+       u8 reg[3];
+
+       reg[0] = delta_m;
+       reg[1] = delta_m >> 8;
+       reg[2] = delta_m >> 16;
+
+       return regmap_bulk_write(data->regmap, SI544_REG_ADPLL_DELTA_M0,
+                                reg, 3);
+}
+
 static int si544_set_muldiv(struct clk_si544 *data,
        struct clk_si544_muldiv *settings)
 {
@@ -238,11 +267,15 @@ static int si544_calc_muldiv(struct clk_si544_muldiv *settings,
        do_div(vco, FXO);
        settings->fb_div_frac = vco;
 
+       /* Reset the frequency adjustment */
+       settings->delta_m = 0;
+
        return 0;
 }
 
 /* Calculate resulting frequency given the register settings */
-static unsigned long si544_calc_rate(struct clk_si544_muldiv *settings)
+static unsigned long si544_calc_center_rate(
+               const struct clk_si544_muldiv *settings)
 {
        u32 d = settings->hs_div * BIT(settings->ls_div_bits);
        u64 vco;
@@ -261,6 +294,25 @@ static unsigned long si544_calc_rate(struct clk_si544_muldiv *settings)
        return vco;
 }
 
+static unsigned long si544_calc_rate(const struct clk_si544_muldiv *settings)
+{
+       unsigned long rate = si544_calc_center_rate(settings);
+       s64 delta = (s64)rate * (DELTA_M_FRAC_NUM * settings->delta_m);
+
+       /*
+        * The clock adjustment is much smaller than 1 Hz, round to the
+        * nearest multiple. Apparently div64_s64 rounds towards zero, hence
+        * check the sign and adjust into the proper direction.
+        */
+       if (settings->delta_m < 0)
+               delta -= ((s64)DELTA_M_MAX * DELTA_M_FRAC_DEN) / 2;
+       else
+               delta += ((s64)DELTA_M_MAX * DELTA_M_FRAC_DEN) / 2;
+       delta = div64_s64(delta, ((s64)DELTA_M_MAX * DELTA_M_FRAC_DEN));
+
+       return rate + delta;
+}
+
 static unsigned long si544_recalc_rate(struct clk_hw *hw,
                unsigned long parent_rate)
 {
@@ -279,33 +331,60 @@ static long si544_round_rate(struct clk_hw *hw, unsigned long rate,
                unsigned long *parent_rate)
 {
        struct clk_si544 *data = to_clk_si544(hw);
-       struct clk_si544_muldiv settings;
-       int err;
 
        if (!is_valid_frequency(data, rate))
                return -EINVAL;
 
-       err = si544_calc_muldiv(&settings, rate);
-       if (err)
-               return err;
+       /* The accuracy is less than 1 Hz, so any rate is possible */
+       return rate;
+}
 
-       return si544_calc_rate(&settings);
+/* Calculates the maximum "small" change, 950 * rate / 1000000 */
+static unsigned long si544_max_delta(unsigned long rate)
+{
+       u64 num = rate;
+
+       num *= DELTA_M_FRAC_NUM;
+       do_div(num, DELTA_M_FRAC_DEN);
+
+       return num;
+}
+
+static s32 si544_calc_delta(s32 delta, s32 max_delta)
+{
+       s64 n = (s64)delta * DELTA_M_MAX;
+
+       return div_s64(n, max_delta);
 }
 
-/*
- * Update output frequency for "big" frequency changes
- */
 static int si544_set_rate(struct clk_hw *hw, unsigned long rate,
                unsigned long parent_rate)
 {
        struct clk_si544 *data = to_clk_si544(hw);
        struct clk_si544_muldiv settings;
+       unsigned long center;
+       long max_delta;
+       long delta;
        unsigned int old_oe_state;
        int err;
 
        if (!is_valid_frequency(data, rate))
                return -EINVAL;
 
+       /* Try using the frequency adjustment feature for a <= 950ppm change */
+       err = si544_get_muldiv(data, &settings);
+       if (err)
+               return err;
+
+       center = si544_calc_center_rate(&settings);
+       max_delta = si544_max_delta(center);
+       delta = rate - center;
+
+       if (abs(delta) <= max_delta)
+               return si544_set_delta_m(data,
+                                        si544_calc_delta(delta, max_delta));
+
+       /* Too big for the delta adjustment, need to reprogram */
        err = si544_calc_muldiv(&settings, rate);
        if (err)
                return err;
@@ -321,6 +400,9 @@ static int si544_set_rate(struct clk_hw *hw, unsigned long rate,
        if (err < 0)
                return err;
 
+       err = si544_set_delta_m(data, settings.delta_m);
+       if (err < 0)
+               return err;
 
        err = si544_set_muldiv(data, &settings);
        if (err < 0)
index 87b410d..c099070 100644 (file)
@@ -1324,10 +1324,7 @@ static void clk_core_init_rate_req(struct clk_core * const core,
 
 static bool clk_core_can_round(struct clk_core * const core)
 {
-       if (core->ops->determine_rate || core->ops->round_rate)
-               return true;
-
-       return false;
+       return core->ops->determine_rate || core->ops->round_rate;
 }
 
 static int clk_core_round_rate_nolock(struct clk_core *core,
@@ -2194,7 +2191,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
 EXPORT_SYMBOL_GPL(clk_set_rate);
 
 /**
- * clk_set_rate_exclusive - specify a new rate get exclusive control
+ * clk_set_rate_exclusive - specify a new rate and get exclusive control
  * @clk: the clk whose rate is being changed
  * @rate: the new rate for clk
  *
@@ -2202,7 +2199,7 @@ EXPORT_SYMBOL_GPL(clk_set_rate);
  * within a critical section
  *
  * This can be used initially to ensure that at least 1 consumer is
- * statisfied when several consumers are competing for exclusivity over the
+ * satisfied when several consumers are competing for exclusivity over the
  * same clock provider.
  *
  * The exclusivity is not applied if setting the rate failed.
@@ -2997,20 +2994,65 @@ static int clk_flags_show(struct seq_file *s, void *data)
 }
 DEFINE_SHOW_ATTRIBUTE(clk_flags);
 
+static void possible_parent_show(struct seq_file *s, struct clk_core *core,
+                                unsigned int i, char terminator)
+{
+       struct clk_core *parent;
+
+       /*
+        * Go through the following options to fetch a parent's name.
+        *
+        * 1. Fetch the registered parent clock and use its name
+        * 2. Use the global (fallback) name if specified
+        * 3. Use the local fw_name if provided
+        * 4. Fetch parent clock's clock-output-name if DT index was set
+        *
+        * This may still fail in some cases, such as when the parent is
+        * specified directly via a struct clk_hw pointer, but it isn't
+        * registered (yet).
+        */
+       parent = clk_core_get_parent_by_index(core, i);
+       if (parent)
+               seq_printf(s, "%s", parent->name);
+       else if (core->parents[i].name)
+               seq_printf(s, "%s", core->parents[i].name);
+       else if (core->parents[i].fw_name)
+               seq_printf(s, "<%s>(fw)", core->parents[i].fw_name);
+       else if (core->parents[i].index >= 0)
+               seq_printf(s, "%s",
+                          of_clk_get_parent_name(core->of_node,
+                                                 core->parents[i].index));
+       else
+               seq_puts(s, "(missing)");
+
+       seq_putc(s, terminator);
+}
+
 static int possible_parents_show(struct seq_file *s, void *data)
 {
        struct clk_core *core = s->private;
        int i;
 
        for (i = 0; i < core->num_parents - 1; i++)
-               seq_printf(s, "%s ", core->parents[i].name);
+               possible_parent_show(s, core, i, ' ');
 
-       seq_printf(s, "%s\n", core->parents[i].name);
+       possible_parent_show(s, core, i, '\n');
 
        return 0;
 }
 DEFINE_SHOW_ATTRIBUTE(possible_parents);
 
+static int current_parent_show(struct seq_file *s, void *data)
+{
+       struct clk_core *core = s->private;
+
+       if (core->parent)
+               seq_printf(s, "%s\n", core->parent->name);
+
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(current_parent);
+
 static int clk_duty_cycle_show(struct seq_file *s, void *data)
 {
        struct clk_core *core = s->private;
@@ -3043,6 +3085,10 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
        debugfs_create_file("clk_duty_cycle", 0444, root, core,
                            &clk_duty_cycle_fops);
 
+       if (core->num_parents > 0)
+               debugfs_create_file("clk_parent", 0444, root, core,
+                                   &current_parent_fops);
+
        if (core->num_parents > 1)
                debugfs_create_file("clk_possible_parents", 0444, root, core,
                                    &possible_parents_fops);
@@ -4038,6 +4084,7 @@ struct of_clk_provider {
        void *data;
 };
 
+extern struct of_device_id __clk_of_table;
 static const struct of_device_id __clk_of_table_sentinel
        __used __section(__clk_of_table_end);
 
index d8400d6..2d80190 100644 (file)
@@ -33,10 +33,6 @@ clk_hw_create_clk(struct device *dev, struct clk_hw *hw, const char *dev_id,
 {
        return (struct clk *)hw;
 }
-static struct clk_hw *__clk_get_hw(struct clk *clk)
-{
-       return (struct clk_hw *)clk;
-}
 static inline void __clk_put(struct clk *clk) { }
 
 #endif
index 7b35a11..25c863d 100644 (file)
@@ -72,13 +72,14 @@ static const struct clk_ops clk_busy_divider_ops = {
        .set_rate = clk_busy_divider_set_rate,
 };
 
-struct clk *imx_clk_busy_divider(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_busy_divider(const char *name, const char *parent_name,
                                 void __iomem *reg, u8 shift, u8 width,
                                 void __iomem *busy_reg, u8 busy_shift)
 {
        struct clk_busy_divider *busy;
-       struct clk *clk;
+       struct clk_hw *hw;
        struct clk_init_data init;
+       int ret;
 
        busy = kzalloc(sizeof(*busy), GFP_KERNEL);
        if (!busy)
@@ -101,11 +102,15 @@ struct clk *imx_clk_busy_divider(const char *name, const char *parent_name,
 
        busy->div.hw.init = &init;
 
-       clk = clk_register(NULL, &busy->div.hw);
-       if (IS_ERR(clk))
+       hw = &busy->div.hw;
+
+       ret = clk_hw_register(NULL, hw);
+       if (ret) {
                kfree(busy);
+               return ERR_PTR(ret);
+       }
 
-       return clk;
+       return hw;
 }
 
 struct clk_busy_mux {
@@ -146,13 +151,14 @@ static const struct clk_ops clk_busy_mux_ops = {
        .set_parent = clk_busy_mux_set_parent,
 };
 
-struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift,
+struct clk_hw *imx_clk_hw_busy_mux(const char *name, void __iomem *reg, u8 shift,
                             u8 width, void __iomem *busy_reg, u8 busy_shift,
                             const char * const *parent_names, int num_parents)
 {
        struct clk_busy_mux *busy;
-       struct clk *clk;
+       struct clk_hw *hw;
        struct clk_init_data init;
+       int ret;
 
        busy = kzalloc(sizeof(*busy), GFP_KERNEL);
        if (!busy)
@@ -175,9 +181,13 @@ struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift,
 
        busy->mux.hw.init = &init;
 
-       clk = clk_register(NULL, &busy->mux.hw);
-       if (IS_ERR(clk))
+       hw = &busy->mux.hw;
+
+       ret = clk_hw_register(NULL, hw);
+       if (ret) {
                kfree(busy);
+               return ERR_PTR(ret);
+       }
 
-       return clk;
+       return hw;
 }
index 00d026e..cb182be 100644 (file)
@@ -69,13 +69,14 @@ static const struct clk_ops clk_cpu_ops = {
        .set_rate       = clk_cpu_set_rate,
 };
 
-struct clk *imx_clk_cpu(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_cpu(const char *name, const char *parent_name,
                struct clk *div, struct clk *mux, struct clk *pll,
                struct clk *step)
 {
        struct clk_cpu *cpu;
-       struct clk *clk;
+       struct clk_hw *hw;
        struct clk_init_data init;
+       int ret;
 
        cpu = kzalloc(sizeof(*cpu), GFP_KERNEL);
        if (!cpu)
@@ -93,10 +94,13 @@ struct clk *imx_clk_cpu(const char *name, const char *parent_name,
        init.num_parents = 1;
 
        cpu->hw.init = &init;
+       hw = &cpu->hw;
 
-       clk = clk_register(NULL, &cpu->hw);
-       if (IS_ERR(clk))
+       ret = clk_hw_register(NULL, hw);
+       if (ret) {
                kfree(cpu);
+               return ERR_PTR(ret);
+       }
 
-       return clk;
+       return hw;
 }
index bab46c6..4b17b91 100644 (file)
@@ -85,13 +85,14 @@ static const struct clk_ops clk_fixup_div_ops = {
        .set_rate = clk_fixup_div_set_rate,
 };
 
-struct clk *imx_clk_fixup_divider(const char *name, const char *parent,
+struct clk_hw *imx_clk_hw_fixup_divider(const char *name, const char *parent,
                                  void __iomem *reg, u8 shift, u8 width,
                                  void (*fixup)(u32 *val))
 {
        struct clk_fixup_div *fixup_div;
-       struct clk *clk;
+       struct clk_hw *hw;
        struct clk_init_data init;
+       int ret;
 
        if (!fixup)
                return ERR_PTR(-EINVAL);
@@ -114,9 +115,13 @@ struct clk *imx_clk_fixup_divider(const char *name, const char *parent,
        fixup_div->ops = &clk_divider_ops;
        fixup_div->fixup = fixup;
 
-       clk = clk_register(NULL, &fixup_div->divider.hw);
-       if (IS_ERR(clk))
+       hw = &fixup_div->divider.hw;
+
+       ret = clk_hw_register(NULL, hw);
+       if (ret) {
                kfree(fixup_div);
+               return ERR_PTR(ret);
+       }
 
-       return clk;
+       return hw;
 }
index 1aa3e8d..b569d91 100644 (file)
@@ -63,13 +63,14 @@ static const struct clk_ops clk_fixup_mux_ops = {
        .set_parent = clk_fixup_mux_set_parent,
 };
 
-struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg,
+struct clk_hw *imx_clk_hw_fixup_mux(const char *name, void __iomem *reg,
                              u8 shift, u8 width, const char * const *parents,
                              int num_parents, void (*fixup)(u32 *val))
 {
        struct clk_fixup_mux *fixup_mux;
-       struct clk *clk;
+       struct clk_hw *hw;
        struct clk_init_data init;
+       int ret;
 
        if (!fixup)
                return ERR_PTR(-EINVAL);
@@ -92,9 +93,13 @@ struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg,
        fixup_mux->ops = &clk_mux_ops;
        fixup_mux->fixup = fixup;
 
-       clk = clk_register(NULL, &fixup_mux->mux.hw);
-       if (IS_ERR(clk))
+       hw = &fixup_mux->mux.hw;
+
+       ret = clk_hw_register(NULL, hw);
+       if (ret) {
                kfree(fixup_mux);
+               return ERR_PTR(ret);
+       }
 
-       return clk;
+       return hw;
 }
index cffa496..7734289 100644 (file)
@@ -55,13 +55,14 @@ static const struct clk_ops clk_gate_exclusive_ops = {
        .is_enabled = clk_gate_exclusive_is_enabled,
 };
 
-struct clk *imx_clk_gate_exclusive(const char *name, const char *parent,
+struct clk_hw *imx_clk_hw_gate_exclusive(const char *name, const char *parent,
         void __iomem *reg, u8 shift, u32 exclusive_mask)
 {
        struct clk_gate_exclusive *exgate;
        struct clk_gate *gate;
-       struct clk *clk;
+       struct clk_hw *hw;
        struct clk_init_data init;
+       int ret;
 
        if (exclusive_mask == 0)
                return ERR_PTR(-EINVAL);
@@ -83,9 +84,13 @@ struct clk *imx_clk_gate_exclusive(const char *name, const char *parent,
        gate->hw.init = &init;
        exgate->exclusive_mask = exclusive_mask;
 
-       clk = clk_register(NULL, &gate->hw);
-       if (IS_ERR(clk))
-               kfree(exgate);
+       hw = &gate->hw;
 
-       return clk;
+       ret = clk_hw_register(NULL, hw);
+       if (ret) {
+               kfree(gate);
+               return ERR_PTR(ret);
+       }
+
+       return hw;
 }
index ec08fda..7d44ce8 100644 (file)
@@ -122,15 +122,16 @@ static const struct clk_ops clk_gate2_ops = {
        .is_enabled = clk_gate2_is_enabled,
 };
 
-struct clk *clk_register_gate2(struct device *dev, const char *name,
+struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 bit_idx, u8 cgr_val,
                u8 clk_gate2_flags, spinlock_t *lock,
                unsigned int *share_count)
 {
        struct clk_gate2 *gate;
-       struct clk *clk;
+       struct clk_hw *hw;
        struct clk_init_data init;
+       int ret;
 
        gate = kzalloc(sizeof(struct clk_gate2), GFP_KERNEL);
        if (!gate)
@@ -151,10 +152,13 @@ struct clk *clk_register_gate2(struct device *dev, const char *name,
        init.num_parents = parent_name ? 1 : 0;
 
        gate->hw.init = &init;
+       hw = &gate->hw;
 
-       clk = clk_register(dev, &gate->hw);
-       if (IS_ERR(clk))
+       ret = clk_hw_register(NULL, hw);
+       if (ret) {
                kfree(gate);
+               return ERR_PTR(ret);
+       }
 
-       return clk;
+       return hw;
 }
index d5de733..60f2de8 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/types.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
+#include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/of.h>
@@ -87,8 +88,8 @@ static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", };
 static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", };
 static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
 
-static struct clk *clk[IMX6QDL_CLK_END];
-static struct clk_onecell_data clk_data;
+static struct clk_hw **hws;
+static struct clk_hw_onecell_data *clk_hw_data;
 
 static struct clk_div_table clk_enet_ref_table[] = {
        { .val = 0, .div = 20, },
@@ -138,12 +139,13 @@ static inline int clk_on_imx6dl(void)
        return of_machine_is_compatible("fsl,imx6dl");
 }
 
-static struct clk ** const uart_clks[] __initconst = {
-       &clk[IMX6QDL_CLK_UART_IPG],
-       &clk[IMX6QDL_CLK_UART_SERIAL],
-       NULL
+static const int uart_clk_ids[] __initconst = {
+       IMX6QDL_CLK_UART_IPG,
+       IMX6QDL_CLK_UART_SERIAL,
 };
 
+static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata;
+
 static int ldb_di_sel_by_clock_id(int clock_id)
 {
        switch (clock_id) {
@@ -254,25 +256,14 @@ static bool pll6_bypassed(struct device_node *node)
        return false;
 }
 
-#define CCM_CCDR               0x04
 #define CCM_CCSR               0x0c
 #define CCM_CS2CDR             0x2c
 
-#define CCDR_MMDC_CH1_MASK             BIT(16)
 #define CCSR_PLL3_SW_CLK_SEL           BIT(0)
 
 #define CS2CDR_LDB_DI0_CLK_SEL_SHIFT   9
 #define CS2CDR_LDB_DI1_CLK_SEL_SHIFT   12
 
-static void __init imx6q_mmdc_ch1_mask_handshake(void __iomem *ccm_base)
-{
-       unsigned int reg;
-
-       reg = readl_relaxed(ccm_base + CCM_CCDR);
-       reg |= CCDR_MMDC_CH1_MASK;
-       writel_relaxed(reg, ccm_base + CCM_CCDR);
-}
-
 /*
  * The only way to disable the MMDC_CH1 clock is to move it to pll3_sw_clk
  * via periph2_clk2_sel and then to disable pll3_sw_clk by selecting the
@@ -282,14 +273,8 @@ static void mmdc_ch1_disable(void __iomem *ccm_base)
 {
        unsigned int reg;
 
-       clk_set_parent(clk[IMX6QDL_CLK_PERIPH2_CLK2_SEL],
-                      clk[IMX6QDL_CLK_PLL3_USB_OTG]);
-
-       /*
-        * Handshake with mmdc_ch1 module must be masked when changing
-        * periph2_clk_sel.
-        */
-       clk_set_parent(clk[IMX6QDL_CLK_PERIPH2], clk[IMX6QDL_CLK_PERIPH2_CLK2]);
+       clk_set_parent(hws[IMX6QDL_CLK_PERIPH2_CLK2_SEL]->clk,
+                      hws[IMX6QDL_CLK_PLL3_USB_OTG]->clk);
 
        /* Disable pll3_sw_clk by selecting the bypass clock source */
        reg = readl_relaxed(ccm_base + CCM_CCSR);
@@ -305,8 +290,6 @@ static void mmdc_ch1_reenable(void __iomem *ccm_base)
        reg = readl_relaxed(ccm_base + CCM_CCSR);
        reg &= ~CCSR_PLL3_SW_CLK_SEL;
        writel_relaxed(reg, ccm_base + CCM_CCSR);
-
-       clk_set_parent(clk[IMX6QDL_CLK_PERIPH2], clk[IMX6QDL_CLK_PERIPH2_PRE]);
 }
 
 /*
@@ -365,8 +348,8 @@ static void init_ldb_clks(struct device_node *np, void __iomem *ccm_base)
 
                /* Only switch to or from pll2_pfd2_396m if it is disabled */
                if ((sel[i][0] == 2 || sel[i][3] == 2) &&
-                   (clk_get_parent(clk[IMX6QDL_CLK_PERIPH_PRE]) ==
-                    clk[IMX6QDL_CLK_PLL2_PFD2_396M])) {
+                   (clk_get_parent(hws[IMX6QDL_CLK_PERIPH_PRE]->clk) ==
+                    hws[IMX6QDL_CLK_PLL2_PFD2_396M]->clk)) {
                        pr_err("ccm: ldb_di%d_sel: couldn't disable pll2_pfd2_396m\n",
                               i);
                        sel[i][3] = sel[i][2] = sel[i][1] = sel[i][0];
@@ -418,8 +401,8 @@ static void disable_anatop_clocks(void __iomem *anatop_base)
        /* Make sure PLL2 PFDs 0-2 are gated */
        reg = readl_relaxed(anatop_base + CCM_ANALOG_PFD_528);
        /* Cannot gate PFD2 if pll2_pfd2_396m is the parent of MMDC clock */
-       if (clk_get_parent(clk[IMX6QDL_CLK_PERIPH_PRE]) ==
-           clk[IMX6QDL_CLK_PLL2_PFD2_396M])
+       if (clk_get_parent(hws[IMX6QDL_CLK_PERIPH_PRE]->clk) ==
+           hws[IMX6QDL_CLK_PLL2_PFD2_396M]->clk)
                reg |= PFD0_CLKGATE | PFD1_CLKGATE;
        else
                reg |= PFD0_CLKGATE | PFD1_CLKGATE | PFD2_CLKGATE;
@@ -436,31 +419,45 @@ static void disable_anatop_clocks(void __iomem *anatop_base)
        writel_relaxed(reg, anatop_base + CCM_ANALOG_PLL_VIDEO);
 }
 
+static struct clk_hw * __init imx6q_obtain_fixed_clk_hw(struct device_node *np,
+                                                       const char *name,
+                                                       unsigned long rate)
+{
+       struct clk *clk = of_clk_get_by_name(np, name);
+       struct clk_hw *hw;
+
+       if (IS_ERR(clk))
+               hw = imx_obtain_fixed_clock_hw(name, rate);
+       else
+               hw = __clk_get_hw(clk);
+
+       return hw;
+}
+
 static void __init imx6q_clocks_init(struct device_node *ccm_node)
 {
        struct device_node *np;
        void __iomem *anatop_base, *base;
        int ret;
+       int i;
+
+       clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
+                                         IMX6QDL_CLK_END), GFP_KERNEL);
+       if (WARN_ON(!clk_hw_data))
+               return;
 
-       clk[IMX6QDL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
-       clk[IMX6QDL_CLK_CKIL] = of_clk_get_by_name(ccm_node, "ckil");
-       if (IS_ERR(clk[IMX6QDL_CLK_CKIL]))
-               clk[IMX6QDL_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0);
-       clk[IMX6QDL_CLK_CKIH] = of_clk_get_by_name(ccm_node, "ckih1");
-       if (IS_ERR(clk[IMX6QDL_CLK_CKIH]))
-               clk[IMX6QDL_CLK_CKIH] = imx_obtain_fixed_clock("ckih1", 0);
-       clk[IMX6QDL_CLK_OSC] = of_clk_get_by_name(ccm_node, "osc");
-       if (IS_ERR(clk[IMX6QDL_CLK_OSC]))
-               clk[IMX6QDL_CLK_OSC] = imx_obtain_fixed_clock("osc", 0);
+       clk_hw_data->num = IMX6QDL_CLK_END;
+       hws = clk_hw_data->hws;
 
-       /* Clock source from external clock via CLK1/2 PADs */
-       clk[IMX6QDL_CLK_ANACLK1] = of_clk_get_by_name(ccm_node, "anaclk1");
-       if (IS_ERR(clk[IMX6QDL_CLK_ANACLK1]))
-               clk[IMX6QDL_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0);
+       hws[IMX6QDL_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
 
-       clk[IMX6QDL_CLK_ANACLK2] = of_clk_get_by_name(ccm_node, "anaclk2");
-       if (IS_ERR(clk[IMX6QDL_CLK_ANACLK2]))
-               clk[IMX6QDL_CLK_ANACLK2] = imx_obtain_fixed_clock("anaclk2", 0);
+       hws[IMX6QDL_CLK_CKIL] = imx6q_obtain_fixed_clk_hw(ccm_node, "ckil", 0);
+       hws[IMX6QDL_CLK_CKIH] = imx6q_obtain_fixed_clk_hw(ccm_node, "ckih1", 0);
+       hws[IMX6QDL_CLK_OSC] = imx6q_obtain_fixed_clk_hw(ccm_node, "osc", 0);
+
+       /* Clock source from external clock via CLK1/2 PADs */
+       hws[IMX6QDL_CLK_ANACLK1] = imx6q_obtain_fixed_clk_hw(ccm_node, "anaclk1", 0);
+       hws[IMX6QDL_CLK_ANACLK2] = imx6q_obtain_fixed_clk_hw(ccm_node, "anaclk2", 0);
 
        np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
        anatop_base = base = of_iomap(np, 0);
@@ -475,47 +472,47 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
                video_div_table[3].div = 1;
        }
 
-       clk[IMX6QDL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clk[IMX6QDL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clk[IMX6QDL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clk[IMX6QDL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clk[IMX6QDL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clk[IMX6QDL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clk[IMX6QDL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6QDL_PLL1_BYPASS_SRC] = imx_clk_hw_mux("pll1_bypass_src", base + 0x00, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6QDL_PLL2_BYPASS_SRC] = imx_clk_hw_mux("pll2_bypass_src", base + 0x30, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6QDL_PLL3_BYPASS_SRC] = imx_clk_hw_mux("pll3_bypass_src", base + 0x10, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6QDL_PLL4_BYPASS_SRC] = imx_clk_hw_mux("pll4_bypass_src", base + 0x70, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6QDL_PLL5_BYPASS_SRC] = imx_clk_hw_mux("pll5_bypass_src", base + 0xa0, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6QDL_PLL6_BYPASS_SRC] = imx_clk_hw_mux("pll6_bypass_src", base + 0xe0, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6QDL_PLL7_BYPASS_SRC] = imx_clk_hw_mux("pll7_bypass_src", base + 0x20, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
 
        /*                                    type               name    parent_name        base         div_mask */
-       clk[IMX6QDL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS,     "pll1", "osc", base + 0x00, 0x7f);
-       clk[IMX6QDL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
-       clk[IMX6QDL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB,     "pll3", "osc", base + 0x10, 0x3);
-       clk[IMX6QDL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV,      "pll4", "osc", base + 0x70, 0x7f);
-       clk[IMX6QDL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV,      "pll5", "osc", base + 0xa0, 0x7f);
-       clk[IMX6QDL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET,    "pll6", "osc", base + 0xe0, 0x3);
-       clk[IMX6QDL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB,     "pll7", "osc", base + 0x20, 0x3);
-
-       clk[IMX6QDL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
-       clk[IMX6QDL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
-       clk[IMX6QDL_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
-       clk[IMX6QDL_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
-       clk[IMX6QDL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
-       clk[IMX6QDL_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
-       clk[IMX6QDL_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6QDL_CLK_PLL1] = imx_clk_hw_pllv3(IMX_PLLV3_SYS,     "pll1", "osc", base + 0x00, 0x7f);
+       hws[IMX6QDL_CLK_PLL2] = imx_clk_hw_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
+       hws[IMX6QDL_CLK_PLL3] = imx_clk_hw_pllv3(IMX_PLLV3_USB,     "pll3", "osc", base + 0x10, 0x3);
+       hws[IMX6QDL_CLK_PLL4] = imx_clk_hw_pllv3(IMX_PLLV3_AV,      "pll4", "osc", base + 0x70, 0x7f);
+       hws[IMX6QDL_CLK_PLL5] = imx_clk_hw_pllv3(IMX_PLLV3_AV,      "pll5", "osc", base + 0xa0, 0x7f);
+       hws[IMX6QDL_CLK_PLL6] = imx_clk_hw_pllv3(IMX_PLLV3_ENET,    "pll6", "osc", base + 0xe0, 0x3);
+       hws[IMX6QDL_CLK_PLL7] = imx_clk_hw_pllv3(IMX_PLLV3_USB,     "pll7", "osc", base + 0x20, 0x3);
+
+       hws[IMX6QDL_PLL1_BYPASS] = imx_clk_hw_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6QDL_PLL2_BYPASS] = imx_clk_hw_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6QDL_PLL3_BYPASS] = imx_clk_hw_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6QDL_PLL4_BYPASS] = imx_clk_hw_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6QDL_PLL5_BYPASS] = imx_clk_hw_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6QDL_PLL6_BYPASS] = imx_clk_hw_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6QDL_PLL7_BYPASS] = imx_clk_hw_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
 
        /* Do not bypass PLLs initially */
-       clk_set_parent(clk[IMX6QDL_PLL1_BYPASS], clk[IMX6QDL_CLK_PLL1]);
-       clk_set_parent(clk[IMX6QDL_PLL2_BYPASS], clk[IMX6QDL_CLK_PLL2]);
-       clk_set_parent(clk[IMX6QDL_PLL3_BYPASS], clk[IMX6QDL_CLK_PLL3]);
-       clk_set_parent(clk[IMX6QDL_PLL4_BYPASS], clk[IMX6QDL_CLK_PLL4]);
-       clk_set_parent(clk[IMX6QDL_PLL5_BYPASS], clk[IMX6QDL_CLK_PLL5]);
-       clk_set_parent(clk[IMX6QDL_PLL6_BYPASS], clk[IMX6QDL_CLK_PLL6]);
-       clk_set_parent(clk[IMX6QDL_PLL7_BYPASS], clk[IMX6QDL_CLK_PLL7]);
-
-       clk[IMX6QDL_CLK_PLL1_SYS]      = imx_clk_gate("pll1_sys",      "pll1_bypass", base + 0x00, 13);
-       clk[IMX6QDL_CLK_PLL2_BUS]      = imx_clk_gate("pll2_bus",      "pll2_bypass", base + 0x30, 13);
-       clk[IMX6QDL_CLK_PLL3_USB_OTG]  = imx_clk_gate("pll3_usb_otg",  "pll3_bypass", base + 0x10, 13);
-       clk[IMX6QDL_CLK_PLL4_AUDIO]    = imx_clk_gate("pll4_audio",    "pll4_bypass", base + 0x70, 13);
-       clk[IMX6QDL_CLK_PLL5_VIDEO]    = imx_clk_gate("pll5_video",    "pll5_bypass", base + 0xa0, 13);
-       clk[IMX6QDL_CLK_PLL6_ENET]     = imx_clk_gate("pll6_enet",     "pll6_bypass", base + 0xe0, 13);
-       clk[IMX6QDL_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
+       clk_set_parent(hws[IMX6QDL_PLL1_BYPASS]->clk, hws[IMX6QDL_CLK_PLL1]->clk);
+       clk_set_parent(hws[IMX6QDL_PLL2_BYPASS]->clk, hws[IMX6QDL_CLK_PLL2]->clk);
+       clk_set_parent(hws[IMX6QDL_PLL3_BYPASS]->clk, hws[IMX6QDL_CLK_PLL3]->clk);
+       clk_set_parent(hws[IMX6QDL_PLL4_BYPASS]->clk, hws[IMX6QDL_CLK_PLL4]->clk);
+       clk_set_parent(hws[IMX6QDL_PLL5_BYPASS]->clk, hws[IMX6QDL_CLK_PLL5]->clk);
+       clk_set_parent(hws[IMX6QDL_PLL6_BYPASS]->clk, hws[IMX6QDL_CLK_PLL6]->clk);
+       clk_set_parent(hws[IMX6QDL_PLL7_BYPASS]->clk, hws[IMX6QDL_CLK_PLL7]->clk);
+
+       hws[IMX6QDL_CLK_PLL1_SYS]      = imx_clk_hw_gate("pll1_sys",      "pll1_bypass", base + 0x00, 13);
+       hws[IMX6QDL_CLK_PLL2_BUS]      = imx_clk_hw_gate("pll2_bus",      "pll2_bypass", base + 0x30, 13);
+       hws[IMX6QDL_CLK_PLL3_USB_OTG]  = imx_clk_hw_gate("pll3_usb_otg",  "pll3_bypass", base + 0x10, 13);
+       hws[IMX6QDL_CLK_PLL4_AUDIO]    = imx_clk_hw_gate("pll4_audio",    "pll4_bypass", base + 0x70, 13);
+       hws[IMX6QDL_CLK_PLL5_VIDEO]    = imx_clk_hw_gate("pll5_video",    "pll5_bypass", base + 0xa0, 13);
+       hws[IMX6QDL_CLK_PLL6_ENET]     = imx_clk_hw_gate("pll6_enet",     "pll6_bypass", base + 0xe0, 13);
+       hws[IMX6QDL_CLK_PLL7_USB_HOST] = imx_clk_hw_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
 
        /*
         * Bit 20 is the reserved and read-only bit, we do this only for:
@@ -523,15 +520,15 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
         * - Keep refcount when do usbphy clk_enable/disable, in that case,
         * the clk framework may need to enable/disable usbphy's parent
         */
-       clk[IMX6QDL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20);
-       clk[IMX6QDL_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
+       hws[IMX6QDL_CLK_USBPHY1] = imx_clk_hw_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20);
+       hws[IMX6QDL_CLK_USBPHY2] = imx_clk_hw_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
 
        /*
         * usbphy*_gate needs to be on after system boots up, and software
         * never needs to control it anymore.
         */
-       clk[IMX6QDL_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6);
-       clk[IMX6QDL_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6);
+       hws[IMX6QDL_CLK_USBPHY1_GATE] = imx_clk_hw_gate("usbphy1_gate", "dummy", base + 0x10, 6);
+       hws[IMX6QDL_CLK_USBPHY2_GATE] = imx_clk_hw_gate("usbphy2_gate", "dummy", base + 0x20, 6);
 
        /*
         * The ENET PLL is special in that is has multiple outputs with
@@ -545,22 +542,22 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
         *
         */
        if (!pll6_bypassed(ccm_node)) {
-               clk[IMX6QDL_CLK_SATA_REF] = imx_clk_fixed_factor("sata_ref", "pll6_enet", 1, 5);
-               clk[IMX6QDL_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 4);
-               clk[IMX6QDL_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
+               hws[IMX6QDL_CLK_SATA_REF] = imx_clk_hw_fixed_factor("sata_ref", "pll6_enet", 1, 5);
+               hws[IMX6QDL_CLK_PCIE_REF] = imx_clk_hw_fixed_factor("pcie_ref", "pll6_enet", 1, 4);
+               hws[IMX6QDL_CLK_ENET_REF] = clk_hw_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
                                                base + 0xe0, 0, 2, 0, clk_enet_ref_table,
                                                &imx_ccm_lock);
        } else {
-               clk[IMX6QDL_CLK_SATA_REF] = imx_clk_fixed_factor("sata_ref", "pll6_enet", 1, 1);
-               clk[IMX6QDL_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 1);
-               clk[IMX6QDL_CLK_ENET_REF] = imx_clk_fixed_factor("enet_ref", "pll6_enet", 1, 1);
+               hws[IMX6QDL_CLK_SATA_REF] = imx_clk_hw_fixed_factor("sata_ref", "pll6_enet", 1, 1);
+               hws[IMX6QDL_CLK_PCIE_REF] = imx_clk_hw_fixed_factor("pcie_ref", "pll6_enet", 1, 1);
+               hws[IMX6QDL_CLK_ENET_REF] = imx_clk_hw_fixed_factor("enet_ref", "pll6_enet", 1, 1);
        }
 
-       clk[IMX6QDL_CLK_SATA_REF_100M] = imx_clk_gate("sata_ref_100m", "sata_ref", base + 0xe0, 20);
-       clk[IMX6QDL_CLK_PCIE_REF_125M] = imx_clk_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19);
+       hws[IMX6QDL_CLK_SATA_REF_100M] = imx_clk_hw_gate("sata_ref_100m", "sata_ref", base + 0xe0, 20);
+       hws[IMX6QDL_CLK_PCIE_REF_125M] = imx_clk_hw_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19);
 
-       clk[IMX6QDL_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
-       clk[IMX6QDL_CLK_LVDS2_SEL] = imx_clk_mux("lvds2_sel", base + 0x160, 5, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
+       hws[IMX6QDL_CLK_LVDS1_SEL] = imx_clk_hw_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
+       hws[IMX6QDL_CLK_LVDS2_SEL] = imx_clk_hw_mux("lvds2_sel", base + 0x160, 5, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
 
        /*
         * lvds1_gate and lvds2_gate are pseudo-gates.  Both can be
@@ -572,84 +569,84 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
         * it.
         */
        writel(readl(base + 0x160) & ~0x3c00, base + 0x160);
-       clk[IMX6QDL_CLK_LVDS1_GATE] = imx_clk_gate_exclusive("lvds1_gate", "lvds1_sel", base + 0x160, 10, BIT(12));
-       clk[IMX6QDL_CLK_LVDS2_GATE] = imx_clk_gate_exclusive("lvds2_gate", "lvds2_sel", base + 0x160, 11, BIT(13));
+       hws[IMX6QDL_CLK_LVDS1_GATE] = imx_clk_hw_gate_exclusive("lvds1_gate", "lvds1_sel", base + 0x160, 10, BIT(12));
+       hws[IMX6QDL_CLK_LVDS2_GATE] = imx_clk_hw_gate_exclusive("lvds2_gate", "lvds2_sel", base + 0x160, 11, BIT(13));
 
-       clk[IMX6QDL_CLK_LVDS1_IN] = imx_clk_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10));
-       clk[IMX6QDL_CLK_LVDS2_IN] = imx_clk_gate_exclusive("lvds2_in", "anaclk2", base + 0x160, 13, BIT(11));
+       hws[IMX6QDL_CLK_LVDS1_IN] = imx_clk_hw_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10));
+       hws[IMX6QDL_CLK_LVDS2_IN] = imx_clk_hw_gate_exclusive("lvds2_in", "anaclk2", base + 0x160, 13, BIT(11));
 
        /*                                            name              parent_name        reg       idx */
-       clk[IMX6QDL_CLK_PLL2_PFD0_352M] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus",     base + 0x100, 0);
-       clk[IMX6QDL_CLK_PLL2_PFD1_594M] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus",     base + 0x100, 1);
-       clk[IMX6QDL_CLK_PLL2_PFD2_396M] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus",     base + 0x100, 2);
-       clk[IMX6QDL_CLK_PLL3_PFD0_720M] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0,  0);
-       clk[IMX6QDL_CLK_PLL3_PFD1_540M] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0,  1);
-       clk[IMX6QDL_CLK_PLL3_PFD2_508M] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0,  2);
-       clk[IMX6QDL_CLK_PLL3_PFD3_454M] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0,  3);
+       hws[IMX6QDL_CLK_PLL2_PFD0_352M] = imx_clk_hw_pfd("pll2_pfd0_352m", "pll2_bus",     base + 0x100, 0);
+       hws[IMX6QDL_CLK_PLL2_PFD1_594M] = imx_clk_hw_pfd("pll2_pfd1_594m", "pll2_bus",     base + 0x100, 1);
+       hws[IMX6QDL_CLK_PLL2_PFD2_396M] = imx_clk_hw_pfd("pll2_pfd2_396m", "pll2_bus",     base + 0x100, 2);
+       hws[IMX6QDL_CLK_PLL3_PFD0_720M] = imx_clk_hw_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0,  0);
+       hws[IMX6QDL_CLK_PLL3_PFD1_540M] = imx_clk_hw_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0,  1);
+       hws[IMX6QDL_CLK_PLL3_PFD2_508M] = imx_clk_hw_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0,  2);
+       hws[IMX6QDL_CLK_PLL3_PFD3_454M] = imx_clk_hw_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0,  3);
 
        /*                                                name         parent_name     mult div */
-       clk[IMX6QDL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2);
-       clk[IMX6QDL_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg",   1, 4);
-       clk[IMX6QDL_CLK_PLL3_80M]  = imx_clk_fixed_factor("pll3_80m",  "pll3_usb_otg",   1, 6);
-       clk[IMX6QDL_CLK_PLL3_60M]  = imx_clk_fixed_factor("pll3_60m",  "pll3_usb_otg",   1, 8);
-       clk[IMX6QDL_CLK_TWD]       = imx_clk_fixed_factor("twd",       "arm",            1, 2);
-       clk[IMX6QDL_CLK_GPT_3M]    = imx_clk_fixed_factor("gpt_3m",    "osc",            1, 8);
-       clk[IMX6QDL_CLK_VIDEO_27M] = imx_clk_fixed_factor("video_27m", "pll3_pfd1_540m", 1, 20);
+       hws[IMX6QDL_CLK_PLL2_198M] = imx_clk_hw_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2);
+       hws[IMX6QDL_CLK_PLL3_120M] = imx_clk_hw_fixed_factor("pll3_120m", "pll3_usb_otg",   1, 4);
+       hws[IMX6QDL_CLK_PLL3_80M]  = imx_clk_hw_fixed_factor("pll3_80m",  "pll3_usb_otg",   1, 6);
+       hws[IMX6QDL_CLK_PLL3_60M]  = imx_clk_hw_fixed_factor("pll3_60m",  "pll3_usb_otg",   1, 8);
+       hws[IMX6QDL_CLK_TWD]       = imx_clk_hw_fixed_factor("twd",       "arm",            1, 2);
+       hws[IMX6QDL_CLK_GPT_3M]    = imx_clk_hw_fixed_factor("gpt_3m",    "osc",            1, 8);
+       hws[IMX6QDL_CLK_VIDEO_27M] = imx_clk_hw_fixed_factor("video_27m", "pll3_pfd1_540m", 1, 20);
        if (clk_on_imx6dl() || clk_on_imx6qp()) {
-               clk[IMX6QDL_CLK_GPU2D_AXI] = imx_clk_fixed_factor("gpu2d_axi", "mmdc_ch0_axi_podf", 1, 1);
-               clk[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_fixed_factor("gpu3d_axi", "mmdc_ch0_axi_podf", 1, 1);
+               hws[IMX6QDL_CLK_GPU2D_AXI] = imx_clk_hw_fixed_factor("gpu2d_axi", "mmdc_ch0_axi_podf", 1, 1);
+               hws[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_hw_fixed_factor("gpu3d_axi", "mmdc_ch0_axi_podf", 1, 1);
        }
 
-       clk[IMX6QDL_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
-       clk[IMX6QDL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock);
-       clk[IMX6QDL_CLK_PLL5_POST_DIV] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
-       clk[IMX6QDL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
+       hws[IMX6QDL_CLK_PLL4_POST_DIV] = clk_hw_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
+       hws[IMX6QDL_CLK_PLL4_AUDIO_DIV] = clk_hw_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock);
+       hws[IMX6QDL_CLK_PLL5_POST_DIV] = clk_hw_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
+       hws[IMX6QDL_CLK_PLL5_VIDEO_DIV] = clk_hw_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
 
        np = ccm_node;
        base = of_iomap(np, 0);
        WARN_ON(!base);
 
        /*                                              name                reg       shift width parent_names     num_parents */
-       clk[IMX6QDL_CLK_STEP]             = imx_clk_mux("step",             base + 0xc,  8,  1, step_sels,         ARRAY_SIZE(step_sels));
-       clk[IMX6QDL_CLK_PLL1_SW]          = imx_clk_mux("pll1_sw",          base + 0xc,  2,  1, pll1_sw_sels,      ARRAY_SIZE(pll1_sw_sels));
-       clk[IMX6QDL_CLK_PERIPH_PRE]       = imx_clk_mux("periph_pre",       base + 0x18, 18, 2, periph_pre_sels,   ARRAY_SIZE(periph_pre_sels));
-       clk[IMX6QDL_CLK_PERIPH2_PRE]      = imx_clk_mux("periph2_pre",      base + 0x18, 21, 2, periph_pre_sels,   ARRAY_SIZE(periph_pre_sels));
-       clk[IMX6QDL_CLK_PERIPH_CLK2_SEL]  = imx_clk_mux("periph_clk2_sel",  base + 0x18, 12, 2, periph_clk2_sels,  ARRAY_SIZE(periph_clk2_sels));
-       clk[IMX6QDL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
-       clk[IMX6QDL_CLK_AXI_SEL]          = imx_clk_mux("axi_sel",          base + 0x14, 6,  2, axi_sels,          ARRAY_SIZE(axi_sels));
-       clk[IMX6QDL_CLK_ESAI_SEL]         = imx_clk_mux("esai_sel",         base + 0x20, 19, 2, audio_sels,        ARRAY_SIZE(audio_sels));
-       clk[IMX6QDL_CLK_ASRC_SEL]         = imx_clk_mux("asrc_sel",         base + 0x30, 7,  2, audio_sels,        ARRAY_SIZE(audio_sels));
-       clk[IMX6QDL_CLK_SPDIF_SEL]        = imx_clk_mux("spdif_sel",        base + 0x30, 20, 2, audio_sels,        ARRAY_SIZE(audio_sels));
+       hws[IMX6QDL_CLK_STEP]             = imx_clk_hw_mux("step",                  base + 0xc,  8,  1, step_sels,         ARRAY_SIZE(step_sels));
+       hws[IMX6QDL_CLK_PLL1_SW]          = imx_clk_hw_mux("pll1_sw",       base + 0xc,  2,  1, pll1_sw_sels,      ARRAY_SIZE(pll1_sw_sels));
+       hws[IMX6QDL_CLK_PERIPH_PRE]       = imx_clk_hw_mux("periph_pre",       base + 0x18, 18, 2, periph_pre_sels,   ARRAY_SIZE(periph_pre_sels));
+       hws[IMX6QDL_CLK_PERIPH2_PRE]      = imx_clk_hw_mux("periph2_pre",      base + 0x18, 21, 2, periph_pre_sels,   ARRAY_SIZE(periph_pre_sels));
+       hws[IMX6QDL_CLK_PERIPH_CLK2_SEL]  = imx_clk_hw_mux("periph_clk2_sel",  base + 0x18, 12, 2, periph_clk2_sels,  ARRAY_SIZE(periph_clk2_sels));
+       hws[IMX6QDL_CLK_PERIPH2_CLK2_SEL] = imx_clk_hw_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
+       hws[IMX6QDL_CLK_AXI_SEL]          = imx_clk_hw_mux("axi_sel",          base + 0x14, 6,  2, axi_sels,          ARRAY_SIZE(axi_sels));
+       hws[IMX6QDL_CLK_ESAI_SEL]         = imx_clk_hw_mux("esai_sel",         base + 0x20, 19, 2, audio_sels,        ARRAY_SIZE(audio_sels));
+       hws[IMX6QDL_CLK_ASRC_SEL]         = imx_clk_hw_mux("asrc_sel",         base + 0x30, 7,  2, audio_sels,        ARRAY_SIZE(audio_sels));
+       hws[IMX6QDL_CLK_SPDIF_SEL]        = imx_clk_hw_mux("spdif_sel",        base + 0x30, 20, 2, audio_sels,        ARRAY_SIZE(audio_sels));
        if (clk_on_imx6q()) {
-               clk[IMX6QDL_CLK_GPU2D_AXI]        = imx_clk_mux("gpu2d_axi",        base + 0x18, 0,  1, gpu_axi_sels,      ARRAY_SIZE(gpu_axi_sels));
-               clk[IMX6QDL_CLK_GPU3D_AXI]        = imx_clk_mux("gpu3d_axi",        base + 0x18, 1,  1, gpu_axi_sels,      ARRAY_SIZE(gpu_axi_sels));
+               hws[IMX6QDL_CLK_GPU2D_AXI]        = imx_clk_hw_mux("gpu2d_axi",        base + 0x18, 0,  1, gpu_axi_sels,      ARRAY_SIZE(gpu_axi_sels));
+               hws[IMX6QDL_CLK_GPU3D_AXI]        = imx_clk_hw_mux("gpu3d_axi",        base + 0x18, 1,  1, gpu_axi_sels,      ARRAY_SIZE(gpu_axi_sels));
        }
        if (clk_on_imx6qp()) {
-               clk[IMX6QDL_CLK_CAN_SEL]   = imx_clk_mux("can_sel",     base + 0x20, 8,  2, can_sels, ARRAY_SIZE(can_sels));
-               clk[IMX6QDL_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel",   base + 0x38, 18, 1, ecspi_sels,  ARRAY_SIZE(ecspi_sels));
-               clk[IMX6QDL_CLK_IPG_PER_SEL] = imx_clk_mux("ipg_per_sel", base + 0x1c, 6, 1, ipg_per_sels, ARRAY_SIZE(ipg_per_sels));
-               clk[IMX6QDL_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
-               clk[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_mux("gpu2d_core_sel", base + 0x18, 16, 2, gpu2d_core_sels_2, ARRAY_SIZE(gpu2d_core_sels_2));
+               hws[IMX6QDL_CLK_CAN_SEL]   = imx_clk_hw_mux("can_sel",  base + 0x20, 8,  2, can_sels, ARRAY_SIZE(can_sels));
+               hws[IMX6QDL_CLK_ECSPI_SEL] = imx_clk_hw_mux("ecspi_sel",        base + 0x38, 18, 1, ecspi_sels,  ARRAY_SIZE(ecspi_sels));
+               hws[IMX6QDL_CLK_IPG_PER_SEL] = imx_clk_hw_mux("ipg_per_sel", base + 0x1c, 6, 1, ipg_per_sels, ARRAY_SIZE(ipg_per_sels));
+               hws[IMX6QDL_CLK_UART_SEL] = imx_clk_hw_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
+               hws[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_hw_mux("gpu2d_core_sel", base + 0x18, 16, 2, gpu2d_core_sels_2, ARRAY_SIZE(gpu2d_core_sels_2));
        } else if (clk_on_imx6dl()) {
-               clk[IMX6QDL_CLK_MLB_SEL] = imx_clk_mux("mlb_sel",   base + 0x18, 16, 2, gpu2d_core_sels,   ARRAY_SIZE(gpu2d_core_sels));
+               hws[IMX6QDL_CLK_MLB_SEL] = imx_clk_hw_mux("mlb_sel",   base + 0x18, 16, 2, gpu2d_core_sels,   ARRAY_SIZE(gpu2d_core_sels));
        } else {
-               clk[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_mux("gpu2d_core_sel",   base + 0x18, 16, 2, gpu2d_core_sels,   ARRAY_SIZE(gpu2d_core_sels));
+               hws[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_hw_mux("gpu2d_core_sel",   base + 0x18, 16, 2, gpu2d_core_sels,   ARRAY_SIZE(gpu2d_core_sels));
        }
-       clk[IMX6QDL_CLK_GPU3D_CORE_SEL]   = imx_clk_mux("gpu3d_core_sel",   base + 0x18, 4,  2, gpu3d_core_sels,   ARRAY_SIZE(gpu3d_core_sels));
+       hws[IMX6QDL_CLK_GPU3D_CORE_SEL]   = imx_clk_hw_mux("gpu3d_core_sel",   base + 0x18, 4,  2, gpu3d_core_sels,   ARRAY_SIZE(gpu3d_core_sels));
        if (clk_on_imx6dl())
-               clk[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_mux("gpu2d_core_sel", base + 0x18, 8,  2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels));
+               hws[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_hw_mux("gpu2d_core_sel", base + 0x18, 8,  2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels));
        else
-               clk[IMX6QDL_CLK_GPU3D_SHADER_SEL] = imx_clk_mux("gpu3d_shader_sel", base + 0x18, 8,  2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels));
-       clk[IMX6QDL_CLK_IPU1_SEL]         = imx_clk_mux("ipu1_sel",         base + 0x3c, 9,  2, ipu_sels,          ARRAY_SIZE(ipu_sels));
-       clk[IMX6QDL_CLK_IPU2_SEL]         = imx_clk_mux("ipu2_sel",         base + 0x3c, 14, 2, ipu_sels,          ARRAY_SIZE(ipu_sels));
+               hws[IMX6QDL_CLK_GPU3D_SHADER_SEL] = imx_clk_hw_mux("gpu3d_shader_sel", base + 0x18, 8,  2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels));
+       hws[IMX6QDL_CLK_IPU1_SEL]         = imx_clk_hw_mux("ipu1_sel",         base + 0x3c, 9,  2, ipu_sels,          ARRAY_SIZE(ipu_sels));
+       hws[IMX6QDL_CLK_IPU2_SEL]         = imx_clk_hw_mux("ipu2_sel",         base + 0x3c, 14, 2, ipu_sels,          ARRAY_SIZE(ipu_sels));
 
        disable_anatop_clocks(anatop_base);
 
-       imx6q_mmdc_ch1_mask_handshake(base);
+       imx_mmdc_mask_handshake(base, 1);
 
        if (clk_on_imx6qp()) {
-               clk[IMX6QDL_CLK_LDB_DI0_SEL]      = imx_clk_mux_flags("ldb_di0_sel", base + 0x2c, 9,  3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);
-               clk[IMX6QDL_CLK_LDB_DI1_SEL]      = imx_clk_mux_flags("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);
+               hws[IMX6QDL_CLK_LDB_DI0_SEL]      = imx_clk_hw_mux_flags("ldb_di0_sel", base + 0x2c, 9,  3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);
+               hws[IMX6QDL_CLK_LDB_DI1_SEL]      = imx_clk_hw_mux_flags("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);
        } else {
                /*
                 * The LDB_DI0/1_SEL muxes are registered read-only due to a hardware
@@ -658,322 +655,333 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
                 */
                init_ldb_clks(np, base);
 
-               clk[IMX6QDL_CLK_LDB_DI0_SEL]      = imx_clk_mux_ldb("ldb_di0_sel", base + 0x2c, 9,  3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels));
-               clk[IMX6QDL_CLK_LDB_DI1_SEL]      = imx_clk_mux_ldb("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels));
+               hws[IMX6QDL_CLK_LDB_DI0_SEL]      = imx_clk_hw_mux_ldb("ldb_di0_sel", base + 0x2c, 9,  3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels));
+               hws[IMX6QDL_CLK_LDB_DI1_SEL]      = imx_clk_hw_mux_ldb("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels));
        }
-       clk[IMX6QDL_CLK_IPU1_DI0_PRE_SEL] = imx_clk_mux_flags("ipu1_di0_pre_sel", base + 0x34, 6,  3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
-       clk[IMX6QDL_CLK_IPU1_DI1_PRE_SEL] = imx_clk_mux_flags("ipu1_di1_pre_sel", base + 0x34, 15, 3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
-       clk[IMX6QDL_CLK_IPU2_DI0_PRE_SEL] = imx_clk_mux_flags("ipu2_di0_pre_sel", base + 0x38, 6,  3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
-       clk[IMX6QDL_CLK_IPU2_DI1_PRE_SEL] = imx_clk_mux_flags("ipu2_di1_pre_sel", base + 0x38, 15, 3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
-       clk[IMX6QDL_CLK_HSI_TX_SEL]       = imx_clk_mux("hsi_tx_sel",       base + 0x30, 28, 1, hsi_tx_sels,       ARRAY_SIZE(hsi_tx_sels));
-       clk[IMX6QDL_CLK_PCIE_AXI_SEL]     = imx_clk_mux("pcie_axi_sel",     base + 0x18, 10, 1, pcie_axi_sels,     ARRAY_SIZE(pcie_axi_sels));
+
+       hws[IMX6QDL_CLK_IPU1_DI0_PRE_SEL] = imx_clk_hw_mux_flags("ipu1_di0_pre_sel", base + 0x34, 6,  3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6QDL_CLK_IPU1_DI1_PRE_SEL] = imx_clk_hw_mux_flags("ipu1_di1_pre_sel", base + 0x34, 15, 3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6QDL_CLK_IPU2_DI0_PRE_SEL] = imx_clk_hw_mux_flags("ipu2_di0_pre_sel", base + 0x38, 6,  3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6QDL_CLK_IPU2_DI1_PRE_SEL] = imx_clk_hw_mux_flags("ipu2_di1_pre_sel", base + 0x38, 15, 3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6QDL_CLK_HSI_TX_SEL]       = imx_clk_hw_mux("hsi_tx_sel",       base + 0x30, 28, 1, hsi_tx_sels,       ARRAY_SIZE(hsi_tx_sels));
+       hws[IMX6QDL_CLK_PCIE_AXI_SEL]     = imx_clk_hw_mux("pcie_axi_sel",     base + 0x18, 10, 1, pcie_axi_sels,     ARRAY_SIZE(pcie_axi_sels));
+
        if (clk_on_imx6qp()) {
-               clk[IMX6QDL_CLK_IPU1_DI0_SEL]     = imx_clk_mux_flags("ipu1_di0_sel",     base + 0x34, 0,  3, ipu1_di0_sels_2,     ARRAY_SIZE(ipu1_di0_sels_2), CLK_SET_RATE_PARENT);
-               clk[IMX6QDL_CLK_IPU1_DI1_SEL]     = imx_clk_mux_flags("ipu1_di1_sel",     base + 0x34, 9,  3, ipu1_di1_sels_2,     ARRAY_SIZE(ipu1_di1_sels_2), CLK_SET_RATE_PARENT);
-               clk[IMX6QDL_CLK_IPU2_DI0_SEL]     = imx_clk_mux_flags("ipu2_di0_sel",     base + 0x38, 0,  3, ipu2_di0_sels_2,     ARRAY_SIZE(ipu2_di0_sels_2), CLK_SET_RATE_PARENT);
-               clk[IMX6QDL_CLK_IPU2_DI1_SEL]     = imx_clk_mux_flags("ipu2_di1_sel",     base + 0x38, 9,  3, ipu2_di1_sels_2,     ARRAY_SIZE(ipu2_di1_sels_2), CLK_SET_RATE_PARENT);
-               clk[IMX6QDL_CLK_SSI1_SEL]         = imx_clk_mux("ssi1_sel",   base + 0x1c, 10, 2, ssi_sels,          ARRAY_SIZE(ssi_sels));
-               clk[IMX6QDL_CLK_SSI2_SEL]         = imx_clk_mux("ssi2_sel",   base + 0x1c, 12, 2, ssi_sels,          ARRAY_SIZE(ssi_sels));
-               clk[IMX6QDL_CLK_SSI3_SEL]         = imx_clk_mux("ssi3_sel",   base + 0x1c, 14, 2, ssi_sels,          ARRAY_SIZE(ssi_sels));
-               clk[IMX6QDL_CLK_USDHC1_SEL]       = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels));
-               clk[IMX6QDL_CLK_USDHC2_SEL]       = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels));
-               clk[IMX6QDL_CLK_USDHC3_SEL]       = imx_clk_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels));
-               clk[IMX6QDL_CLK_USDHC4_SEL]       = imx_clk_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels));
-               clk[IMX6QDL_CLK_ENFC_SEL]         = imx_clk_mux("enfc_sel",         base + 0x2c, 15, 3, enfc_sels_2,         ARRAY_SIZE(enfc_sels_2));
-               clk[IMX6QDL_CLK_EIM_SEL]          = imx_clk_mux("eim_sel",      base + 0x1c, 27, 2, eim_sels,        ARRAY_SIZE(eim_sels));
-               clk[IMX6QDL_CLK_EIM_SLOW_SEL]     = imx_clk_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels,   ARRAY_SIZE(eim_slow_sels));
-               clk[IMX6QDL_CLK_PRE_AXI]          = imx_clk_mux("pre_axi",      base + 0x18, 1,  1, pre_axi_sels,    ARRAY_SIZE(pre_axi_sels));
+               hws[IMX6QDL_CLK_IPU1_DI0_SEL]     = imx_clk_hw_mux_flags("ipu1_di0_sel",     base + 0x34, 0,  3, ipu1_di0_sels_2,     ARRAY_SIZE(ipu1_di0_sels_2), CLK_SET_RATE_PARENT);
+               hws[IMX6QDL_CLK_IPU1_DI1_SEL]     = imx_clk_hw_mux_flags("ipu1_di1_sel",     base + 0x34, 9,  3, ipu1_di1_sels_2,     ARRAY_SIZE(ipu1_di1_sels_2), CLK_SET_RATE_PARENT);
+               hws[IMX6QDL_CLK_IPU2_DI0_SEL]     = imx_clk_hw_mux_flags("ipu2_di0_sel",     base + 0x38, 0,  3, ipu2_di0_sels_2,     ARRAY_SIZE(ipu2_di0_sels_2), CLK_SET_RATE_PARENT);
+               hws[IMX6QDL_CLK_IPU2_DI1_SEL]     = imx_clk_hw_mux_flags("ipu2_di1_sel",     base + 0x38, 9,  3, ipu2_di1_sels_2,     ARRAY_SIZE(ipu2_di1_sels_2), CLK_SET_RATE_PARENT);
+               hws[IMX6QDL_CLK_SSI1_SEL]         = imx_clk_hw_mux("ssi1_sel",   base + 0x1c, 10, 2, ssi_sels,          ARRAY_SIZE(ssi_sels));
+               hws[IMX6QDL_CLK_SSI2_SEL]         = imx_clk_hw_mux("ssi2_sel",   base + 0x1c, 12, 2, ssi_sels,          ARRAY_SIZE(ssi_sels));
+               hws[IMX6QDL_CLK_SSI3_SEL]         = imx_clk_hw_mux("ssi3_sel",   base + 0x1c, 14, 2, ssi_sels,          ARRAY_SIZE(ssi_sels));
+               hws[IMX6QDL_CLK_USDHC1_SEL]       = imx_clk_hw_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels));
+               hws[IMX6QDL_CLK_USDHC2_SEL]       = imx_clk_hw_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels));
+               hws[IMX6QDL_CLK_USDHC3_SEL]       = imx_clk_hw_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels));
+               hws[IMX6QDL_CLK_USDHC4_SEL]       = imx_clk_hw_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels));
+               hws[IMX6QDL_CLK_ENFC_SEL]         = imx_clk_hw_mux("enfc_sel",         base + 0x2c, 15, 3, enfc_sels_2,         ARRAY_SIZE(enfc_sels_2));
+               hws[IMX6QDL_CLK_EIM_SEL]          = imx_clk_hw_mux("eim_sel",      base + 0x1c, 27, 2, eim_sels,        ARRAY_SIZE(eim_sels));
+               hws[IMX6QDL_CLK_EIM_SLOW_SEL]     = imx_clk_hw_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels,   ARRAY_SIZE(eim_slow_sels));
+               hws[IMX6QDL_CLK_PRE_AXI]          = imx_clk_hw_mux("pre_axi",   base + 0x18, 1,  1, pre_axi_sels,    ARRAY_SIZE(pre_axi_sels));
        } else {
-               clk[IMX6QDL_CLK_IPU1_DI0_SEL]     = imx_clk_mux_flags("ipu1_di0_sel",     base + 0x34, 0,  3, ipu1_di0_sels,     ARRAY_SIZE(ipu1_di0_sels), CLK_SET_RATE_PARENT);
-               clk[IMX6QDL_CLK_IPU1_DI1_SEL]     = imx_clk_mux_flags("ipu1_di1_sel",     base + 0x34, 9,  3, ipu1_di1_sels,     ARRAY_SIZE(ipu1_di1_sels), CLK_SET_RATE_PARENT);
-               clk[IMX6QDL_CLK_IPU2_DI0_SEL]     = imx_clk_mux_flags("ipu2_di0_sel",     base + 0x38, 0,  3, ipu2_di0_sels,     ARRAY_SIZE(ipu2_di0_sels), CLK_SET_RATE_PARENT);
-               clk[IMX6QDL_CLK_IPU2_DI1_SEL]     = imx_clk_mux_flags("ipu2_di1_sel",     base + 0x38, 9,  3, ipu2_di1_sels,     ARRAY_SIZE(ipu2_di1_sels), CLK_SET_RATE_PARENT);
-               clk[IMX6QDL_CLK_SSI1_SEL]         = imx_clk_fixup_mux("ssi1_sel",   base + 0x1c, 10, 2, ssi_sels,          ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
-               clk[IMX6QDL_CLK_SSI2_SEL]         = imx_clk_fixup_mux("ssi2_sel",   base + 0x1c, 12, 2, ssi_sels,          ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
-               clk[IMX6QDL_CLK_SSI3_SEL]         = imx_clk_fixup_mux("ssi3_sel",   base + 0x1c, 14, 2, ssi_sels,          ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
-               clk[IMX6QDL_CLK_USDHC1_SEL]       = imx_clk_fixup_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
-               clk[IMX6QDL_CLK_USDHC2_SEL]       = imx_clk_fixup_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
-               clk[IMX6QDL_CLK_USDHC3_SEL]       = imx_clk_fixup_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
-               clk[IMX6QDL_CLK_USDHC4_SEL]       = imx_clk_fixup_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
-               clk[IMX6QDL_CLK_ENFC_SEL]         = imx_clk_mux("enfc_sel",         base + 0x2c, 16, 2, enfc_sels,         ARRAY_SIZE(enfc_sels));
-               clk[IMX6QDL_CLK_EIM_SEL]          = imx_clk_fixup_mux("eim_sel",      base + 0x1c, 27, 2, eim_sels,        ARRAY_SIZE(eim_sels), imx_cscmr1_fixup);
-               clk[IMX6QDL_CLK_EIM_SLOW_SEL]     = imx_clk_fixup_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels,   ARRAY_SIZE(eim_slow_sels), imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_IPU1_DI0_SEL]     = imx_clk_hw_mux_flags("ipu1_di0_sel",     base + 0x34, 0,  3, ipu1_di0_sels,     ARRAY_SIZE(ipu1_di0_sels), CLK_SET_RATE_PARENT);
+               hws[IMX6QDL_CLK_IPU1_DI1_SEL]     = imx_clk_hw_mux_flags("ipu1_di1_sel",     base + 0x34, 9,  3, ipu1_di1_sels,     ARRAY_SIZE(ipu1_di1_sels), CLK_SET_RATE_PARENT);
+               hws[IMX6QDL_CLK_IPU2_DI0_SEL]     = imx_clk_hw_mux_flags("ipu2_di0_sel",     base + 0x38, 0,  3, ipu2_di0_sels,     ARRAY_SIZE(ipu2_di0_sels), CLK_SET_RATE_PARENT);
+               hws[IMX6QDL_CLK_IPU2_DI1_SEL]     = imx_clk_hw_mux_flags("ipu2_di1_sel",     base + 0x38, 9,  3, ipu2_di1_sels,     ARRAY_SIZE(ipu2_di1_sels), CLK_SET_RATE_PARENT);
+               hws[IMX6QDL_CLK_SSI1_SEL]         = imx_clk_hw_fixup_mux("ssi1_sel",   base + 0x1c, 10, 2, ssi_sels,          ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_SSI2_SEL]         = imx_clk_hw_fixup_mux("ssi2_sel",   base + 0x1c, 12, 2, ssi_sels,          ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_SSI3_SEL]         = imx_clk_hw_fixup_mux("ssi3_sel",   base + 0x1c, 14, 2, ssi_sels,          ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_USDHC1_SEL]       = imx_clk_hw_fixup_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_USDHC2_SEL]       = imx_clk_hw_fixup_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_USDHC3_SEL]       = imx_clk_hw_fixup_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_USDHC4_SEL]       = imx_clk_hw_fixup_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_ENFC_SEL]         = imx_clk_hw_mux("enfc_sel",         base + 0x2c, 16, 2, enfc_sels,         ARRAY_SIZE(enfc_sels));
+               hws[IMX6QDL_CLK_EIM_SEL]          = imx_clk_hw_fixup_mux("eim_sel",      base + 0x1c, 27, 2, eim_sels,        ARRAY_SIZE(eim_sels), imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_EIM_SLOW_SEL]     = imx_clk_hw_fixup_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels,   ARRAY_SIZE(eim_slow_sels), imx_cscmr1_fixup);
        }
-       clk[IMX6QDL_CLK_VDO_AXI_SEL]      = imx_clk_mux("vdo_axi_sel",      base + 0x18, 11, 1, vdo_axi_sels,      ARRAY_SIZE(vdo_axi_sels));
-       clk[IMX6QDL_CLK_VPU_AXI_SEL]      = imx_clk_mux("vpu_axi_sel",      base + 0x18, 14, 2, vpu_axi_sels,      ARRAY_SIZE(vpu_axi_sels));
-       clk[IMX6QDL_CLK_CKO1_SEL]         = imx_clk_mux("cko1_sel",         base + 0x60, 0,  4, cko1_sels,         ARRAY_SIZE(cko1_sels));
-       clk[IMX6QDL_CLK_CKO2_SEL]         = imx_clk_mux("cko2_sel",         base + 0x60, 16, 5, cko2_sels,         ARRAY_SIZE(cko2_sels));
-       clk[IMX6QDL_CLK_CKO]              = imx_clk_mux("cko",              base + 0x60, 8, 1,  cko_sels,          ARRAY_SIZE(cko_sels));
+
+       hws[IMX6QDL_CLK_VDO_AXI_SEL]      = imx_clk_hw_mux("vdo_axi_sel",      base + 0x18, 11, 1, vdo_axi_sels,      ARRAY_SIZE(vdo_axi_sels));
+       hws[IMX6QDL_CLK_VPU_AXI_SEL]      = imx_clk_hw_mux("vpu_axi_sel",      base + 0x18, 14, 2, vpu_axi_sels,      ARRAY_SIZE(vpu_axi_sels));
+       hws[IMX6QDL_CLK_CKO1_SEL]         = imx_clk_hw_mux("cko1_sel",         base + 0x60, 0,  4, cko1_sels,         ARRAY_SIZE(cko1_sels));
+       hws[IMX6QDL_CLK_CKO2_SEL]         = imx_clk_hw_mux("cko2_sel",         base + 0x60, 16, 5, cko2_sels,         ARRAY_SIZE(cko2_sels));
+       hws[IMX6QDL_CLK_CKO]              = imx_clk_hw_mux("cko",              base + 0x60, 8, 1,  cko_sels,          ARRAY_SIZE(cko_sels));
 
        /*                                          name         reg      shift width busy: reg, shift parent_names  num_parents */
-       clk[IMX6QDL_CLK_PERIPH]  = imx_clk_busy_mux("periph",  base + 0x14, 25,  1,   base + 0x48, 5,  periph_sels,  ARRAY_SIZE(periph_sels));
-       clk[IMX6QDL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26,  1,   base + 0x48, 3,  periph2_sels, ARRAY_SIZE(periph2_sels));
+       hws[IMX6QDL_CLK_PERIPH]  = imx_clk_hw_busy_mux("periph",  base + 0x14, 25,  1,   base + 0x48, 5,  periph_sels,  ARRAY_SIZE(periph_sels));
+       hws[IMX6QDL_CLK_PERIPH2] = imx_clk_hw_busy_mux("periph2", base + 0x14, 26,  1,   base + 0x48, 3,  periph2_sels, ARRAY_SIZE(periph2_sels));
 
        /*                                                  name                parent_name          reg       shift width */
-       clk[IMX6QDL_CLK_PERIPH_CLK2]      = imx_clk_divider("periph_clk2",      "periph_clk2_sel",   base + 0x14, 27, 3);
-       clk[IMX6QDL_CLK_PERIPH2_CLK2]     = imx_clk_divider("periph2_clk2",     "periph2_clk2_sel",  base + 0x14, 0,  3);
-       clk[IMX6QDL_CLK_IPG]              = imx_clk_divider("ipg",              "ahb",               base + 0x14, 8,  2);
-       clk[IMX6QDL_CLK_ESAI_PRED]        = imx_clk_divider("esai_pred",        "esai_sel",          base + 0x28, 9,  3);
-       clk[IMX6QDL_CLK_ESAI_PODF]        = imx_clk_divider("esai_podf",        "esai_pred",         base + 0x28, 25, 3);
-       clk[IMX6QDL_CLK_ASRC_PRED]        = imx_clk_divider("asrc_pred",        "asrc_sel",          base + 0x30, 12, 3);
-       clk[IMX6QDL_CLK_ASRC_PODF]        = imx_clk_divider("asrc_podf",        "asrc_pred",         base + 0x30, 9,  3);
-       clk[IMX6QDL_CLK_SPDIF_PRED]       = imx_clk_divider("spdif_pred",       "spdif_sel",         base + 0x30, 25, 3);
-       clk[IMX6QDL_CLK_SPDIF_PODF]       = imx_clk_divider("spdif_podf",       "spdif_pred",        base + 0x30, 22, 3);
+       hws[IMX6QDL_CLK_PERIPH_CLK2]      = imx_clk_hw_divider("periph_clk2",      "periph_clk2_sel",   base + 0x14, 27, 3);
+       hws[IMX6QDL_CLK_PERIPH2_CLK2]     = imx_clk_hw_divider("periph2_clk2",     "periph2_clk2_sel",  base + 0x14, 0,  3);
+       hws[IMX6QDL_CLK_IPG]              = imx_clk_hw_divider("ipg",              "ahb",               base + 0x14, 8,  2);
+       hws[IMX6QDL_CLK_ESAI_PRED]        = imx_clk_hw_divider("esai_pred",        "esai_sel",          base + 0x28, 9,  3);
+       hws[IMX6QDL_CLK_ESAI_PODF]        = imx_clk_hw_divider("esai_podf",        "esai_pred",         base + 0x28, 25, 3);
+       hws[IMX6QDL_CLK_ASRC_PRED]        = imx_clk_hw_divider("asrc_pred",        "asrc_sel",          base + 0x30, 12, 3);
+       hws[IMX6QDL_CLK_ASRC_PODF]        = imx_clk_hw_divider("asrc_podf",        "asrc_pred",         base + 0x30, 9,  3);
+       hws[IMX6QDL_CLK_SPDIF_PRED]       = imx_clk_hw_divider("spdif_pred",       "spdif_sel",         base + 0x30, 25, 3);
+       hws[IMX6QDL_CLK_SPDIF_PODF]       = imx_clk_hw_divider("spdif_podf",       "spdif_pred",        base + 0x30, 22, 3);
+
        if (clk_on_imx6qp()) {
-               clk[IMX6QDL_CLK_IPG_PER] = imx_clk_divider("ipg_per", "ipg_per_sel", base + 0x1c, 0, 6);
-               clk[IMX6QDL_CLK_ECSPI_ROOT] = imx_clk_divider("ecspi_root", "ecspi_sel", base + 0x38, 19, 6);
-               clk[IMX6QDL_CLK_CAN_ROOT] = imx_clk_divider("can_root", "can_sel", base + 0x20, 2, 6);
-               clk[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_divider("uart_serial_podf", "uart_sel", base + 0x24, 0, 6);
-               clk[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0", 2, 7);
-               clk[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1", 2, 7);
+               hws[IMX6QDL_CLK_IPG_PER] = imx_clk_hw_divider("ipg_per", "ipg_per_sel", base + 0x1c, 0, 6);
+               hws[IMX6QDL_CLK_ECSPI_ROOT] = imx_clk_hw_divider("ecspi_root", "ecspi_sel", base + 0x38, 19, 6);
+               hws[IMX6QDL_CLK_CAN_ROOT] = imx_clk_hw_divider("can_root", "can_sel", base + 0x20, 2, 6);
+               hws[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_hw_divider("uart_serial_podf", "uart_sel", base + 0x24, 0, 6);
+               hws[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di0_div_3_5", "ldb_di0", 2, 7);
+               hws[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di1_div_3_5", "ldb_di1", 2, 7);
        } else {
-               clk[IMX6QDL_CLK_ECSPI_ROOT] = imx_clk_divider("ecspi_root", "pll3_60m", base + 0x38, 19, 6);
-               clk[IMX6QDL_CLK_CAN_ROOT] = imx_clk_divider("can_root", "pll3_60m", base + 0x20, 2, 6);
-               clk[IMX6QDL_CLK_IPG_PER] = imx_clk_fixup_divider("ipg_per", "ipg", base + 0x1c, 0, 6, imx_cscmr1_fixup);
-               clk[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_divider("uart_serial_podf", "pll3_80m",          base + 0x24, 0,  6);
-               clk[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
-               clk[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
+               hws[IMX6QDL_CLK_ECSPI_ROOT] = imx_clk_hw_divider("ecspi_root", "pll3_60m", base + 0x38, 19, 6);
+               hws[IMX6QDL_CLK_CAN_ROOT] = imx_clk_hw_divider("can_root", "pll3_60m", base + 0x20, 2, 6);
+               hws[IMX6QDL_CLK_IPG_PER] = imx_clk_hw_fixup_divider("ipg_per", "ipg", base + 0x1c, 0, 6, imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_hw_divider("uart_serial_podf", "pll3_80m",          base + 0x24, 0,  6);
+               hws[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
+               hws[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
        }
+
        if (clk_on_imx6dl())
-               clk[IMX6QDL_CLK_MLB_PODF]  = imx_clk_divider("mlb_podf",  "mlb_sel",    base + 0x18, 23, 3);
+               hws[IMX6QDL_CLK_MLB_PODF]  = imx_clk_hw_divider("mlb_podf",  "mlb_sel",    base + 0x18, 23, 3);
        else
-               clk[IMX6QDL_CLK_GPU2D_CORE_PODF]  = imx_clk_divider("gpu2d_core_podf",  "gpu2d_core_sel",    base + 0x18, 23, 3);
-       clk[IMX6QDL_CLK_GPU3D_CORE_PODF]  = imx_clk_divider("gpu3d_core_podf",  "gpu3d_core_sel",    base + 0x18, 26, 3);
+               hws[IMX6QDL_CLK_GPU2D_CORE_PODF]  = imx_clk_hw_divider("gpu2d_core_podf",  "gpu2d_core_sel",    base + 0x18, 23, 3);
+       hws[IMX6QDL_CLK_GPU3D_CORE_PODF]  = imx_clk_hw_divider("gpu3d_core_podf",  "gpu3d_core_sel",    base + 0x18, 26, 3);
        if (clk_on_imx6dl())
-               clk[IMX6QDL_CLK_GPU2D_CORE_PODF]  = imx_clk_divider("gpu2d_core_podf",     "gpu2d_core_sel",  base + 0x18, 29, 3);
+               hws[IMX6QDL_CLK_GPU2D_CORE_PODF]  = imx_clk_hw_divider("gpu2d_core_podf",     "gpu2d_core_sel",  base + 0x18, 29, 3);
        else
-               clk[IMX6QDL_CLK_GPU3D_SHADER]     = imx_clk_divider("gpu3d_shader",     "gpu3d_shader_sel",  base + 0x18, 29, 3);
-       clk[IMX6QDL_CLK_IPU1_PODF]        = imx_clk_divider("ipu1_podf",        "ipu1_sel",          base + 0x3c, 11, 3);
-       clk[IMX6QDL_CLK_IPU2_PODF]        = imx_clk_divider("ipu2_podf",        "ipu2_sel",          base + 0x3c, 16, 3);
-       clk[IMX6QDL_CLK_LDB_DI0_PODF]     = imx_clk_divider_flags("ldb_di0_podf", "ldb_di0_div_3_5", base + 0x20, 10, 1, 0);
-       clk[IMX6QDL_CLK_LDB_DI1_PODF]     = imx_clk_divider_flags("ldb_di1_podf", "ldb_di1_div_3_5", base + 0x20, 11, 1, 0);
-       clk[IMX6QDL_CLK_IPU1_DI0_PRE]     = imx_clk_divider("ipu1_di0_pre",     "ipu1_di0_pre_sel",  base + 0x34, 3,  3);
-       clk[IMX6QDL_CLK_IPU1_DI1_PRE]     = imx_clk_divider("ipu1_di1_pre",     "ipu1_di1_pre_sel",  base + 0x34, 12, 3);
-       clk[IMX6QDL_CLK_IPU2_DI0_PRE]     = imx_clk_divider("ipu2_di0_pre",     "ipu2_di0_pre_sel",  base + 0x38, 3,  3);
-       clk[IMX6QDL_CLK_IPU2_DI1_PRE]     = imx_clk_divider("ipu2_di1_pre",     "ipu2_di1_pre_sel",  base + 0x38, 12, 3);
-       clk[IMX6QDL_CLK_HSI_TX_PODF]      = imx_clk_divider("hsi_tx_podf",      "hsi_tx_sel",        base + 0x30, 29, 3);
-       clk[IMX6QDL_CLK_SSI1_PRED]        = imx_clk_divider("ssi1_pred",        "ssi1_sel",          base + 0x28, 6,  3);
-       clk[IMX6QDL_CLK_SSI1_PODF]        = imx_clk_divider("ssi1_podf",        "ssi1_pred",         base + 0x28, 0,  6);
-       clk[IMX6QDL_CLK_SSI2_PRED]        = imx_clk_divider("ssi2_pred",        "ssi2_sel",          base + 0x2c, 6,  3);
-       clk[IMX6QDL_CLK_SSI2_PODF]        = imx_clk_divider("ssi2_podf",        "ssi2_pred",         base + 0x2c, 0,  6);
-       clk[IMX6QDL_CLK_SSI3_PRED]        = imx_clk_divider("ssi3_pred",        "ssi3_sel",          base + 0x28, 22, 3);
-       clk[IMX6QDL_CLK_SSI3_PODF]        = imx_clk_divider("ssi3_podf",        "ssi3_pred",         base + 0x28, 16, 6);
-       clk[IMX6QDL_CLK_USDHC1_PODF]      = imx_clk_divider("usdhc1_podf",      "usdhc1_sel",        base + 0x24, 11, 3);
-       clk[IMX6QDL_CLK_USDHC2_PODF]      = imx_clk_divider("usdhc2_podf",      "usdhc2_sel",        base + 0x24, 16, 3);
-       clk[IMX6QDL_CLK_USDHC3_PODF]      = imx_clk_divider("usdhc3_podf",      "usdhc3_sel",        base + 0x24, 19, 3);
-       clk[IMX6QDL_CLK_USDHC4_PODF]      = imx_clk_divider("usdhc4_podf",      "usdhc4_sel",        base + 0x24, 22, 3);
-       clk[IMX6QDL_CLK_ENFC_PRED]        = imx_clk_divider("enfc_pred",        "enfc_sel",          base + 0x2c, 18, 3);
-       clk[IMX6QDL_CLK_ENFC_PODF]        = imx_clk_divider("enfc_podf",        "enfc_pred",         base + 0x2c, 21, 6);
+               hws[IMX6QDL_CLK_GPU3D_SHADER]     = imx_clk_hw_divider("gpu3d_shader",     "gpu3d_shader_sel",  base + 0x18, 29, 3);
+       hws[IMX6QDL_CLK_IPU1_PODF]        = imx_clk_hw_divider("ipu1_podf",        "ipu1_sel",          base + 0x3c, 11, 3);
+       hws[IMX6QDL_CLK_IPU2_PODF]        = imx_clk_hw_divider("ipu2_podf",        "ipu2_sel",          base + 0x3c, 16, 3);
+       hws[IMX6QDL_CLK_LDB_DI0_PODF]     = imx_clk_hw_divider_flags("ldb_di0_podf", "ldb_di0_div_3_5", base + 0x20, 10, 1, 0);
+       hws[IMX6QDL_CLK_LDB_DI1_PODF]     = imx_clk_hw_divider_flags("ldb_di1_podf", "ldb_di1_div_3_5", base + 0x20, 11, 1, 0);
+       hws[IMX6QDL_CLK_IPU1_DI0_PRE]     = imx_clk_hw_divider("ipu1_di0_pre",     "ipu1_di0_pre_sel",  base + 0x34, 3,  3);
+       hws[IMX6QDL_CLK_IPU1_DI1_PRE]     = imx_clk_hw_divider("ipu1_di1_pre",     "ipu1_di1_pre_sel",  base + 0x34, 12, 3);
+       hws[IMX6QDL_CLK_IPU2_DI0_PRE]     = imx_clk_hw_divider("ipu2_di0_pre",     "ipu2_di0_pre_sel",  base + 0x38, 3,  3);
+       hws[IMX6QDL_CLK_IPU2_DI1_PRE]     = imx_clk_hw_divider("ipu2_di1_pre",     "ipu2_di1_pre_sel",  base + 0x38, 12, 3);
+       hws[IMX6QDL_CLK_HSI_TX_PODF]      = imx_clk_hw_divider("hsi_tx_podf",      "hsi_tx_sel",        base + 0x30, 29, 3);
+       hws[IMX6QDL_CLK_SSI1_PRED]        = imx_clk_hw_divider("ssi1_pred",        "ssi1_sel",          base + 0x28, 6,  3);
+       hws[IMX6QDL_CLK_SSI1_PODF]        = imx_clk_hw_divider("ssi1_podf",        "ssi1_pred",         base + 0x28, 0,  6);
+       hws[IMX6QDL_CLK_SSI2_PRED]        = imx_clk_hw_divider("ssi2_pred",        "ssi2_sel",          base + 0x2c, 6,  3);
+       hws[IMX6QDL_CLK_SSI2_PODF]        = imx_clk_hw_divider("ssi2_podf",        "ssi2_pred",         base + 0x2c, 0,  6);
+       hws[IMX6QDL_CLK_SSI3_PRED]        = imx_clk_hw_divider("ssi3_pred",        "ssi3_sel",          base + 0x28, 22, 3);
+       hws[IMX6QDL_CLK_SSI3_PODF]        = imx_clk_hw_divider("ssi3_podf",        "ssi3_pred",         base + 0x28, 16, 6);
+       hws[IMX6QDL_CLK_USDHC1_PODF]      = imx_clk_hw_divider("usdhc1_podf",      "usdhc1_sel",        base + 0x24, 11, 3);
+       hws[IMX6QDL_CLK_USDHC2_PODF]      = imx_clk_hw_divider("usdhc2_podf",      "usdhc2_sel",        base + 0x24, 16, 3);
+       hws[IMX6QDL_CLK_USDHC3_PODF]      = imx_clk_hw_divider("usdhc3_podf",      "usdhc3_sel",        base + 0x24, 19, 3);
+       hws[IMX6QDL_CLK_USDHC4_PODF]      = imx_clk_hw_divider("usdhc4_podf",      "usdhc4_sel",        base + 0x24, 22, 3);
+       hws[IMX6QDL_CLK_ENFC_PRED]        = imx_clk_hw_divider("enfc_pred",        "enfc_sel",          base + 0x2c, 18, 3);
+       hws[IMX6QDL_CLK_ENFC_PODF]        = imx_clk_hw_divider("enfc_podf",        "enfc_pred",         base + 0x2c, 21, 6);
        if (clk_on_imx6qp()) {
-               clk[IMX6QDL_CLK_EIM_PODF]         = imx_clk_divider("eim_podf",   "eim_sel",           base + 0x1c, 20, 3);
-               clk[IMX6QDL_CLK_EIM_SLOW_PODF]    = imx_clk_divider("eim_slow_podf", "eim_slow_sel",   base + 0x1c, 23, 3);
+               hws[IMX6QDL_CLK_EIM_PODF]         = imx_clk_hw_divider("eim_podf",   "eim_sel",           base + 0x1c, 20, 3);
+               hws[IMX6QDL_CLK_EIM_SLOW_PODF]    = imx_clk_hw_divider("eim_slow_podf", "eim_slow_sel",   base + 0x1c, 23, 3);
        } else {
-               clk[IMX6QDL_CLK_EIM_PODF]         = imx_clk_fixup_divider("eim_podf",   "eim_sel",           base + 0x1c, 20, 3, imx_cscmr1_fixup);
-               clk[IMX6QDL_CLK_EIM_SLOW_PODF]    = imx_clk_fixup_divider("eim_slow_podf", "eim_slow_sel",   base + 0x1c, 23, 3, imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_EIM_PODF]         = imx_clk_hw_fixup_divider("eim_podf",   "eim_sel",           base + 0x1c, 20, 3, imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_EIM_SLOW_PODF]    = imx_clk_hw_fixup_divider("eim_slow_podf", "eim_slow_sel",   base + 0x1c, 23, 3, imx_cscmr1_fixup);
        }
-       clk[IMX6QDL_CLK_VPU_AXI_PODF]     = imx_clk_divider("vpu_axi_podf",     "vpu_axi_sel",       base + 0x24, 25, 3);
-       clk[IMX6QDL_CLK_CKO1_PODF]        = imx_clk_divider("cko1_podf",        "cko1_sel",          base + 0x60, 4,  3);
-       clk[IMX6QDL_CLK_CKO2_PODF]        = imx_clk_divider("cko2_podf",        "cko2_sel",          base + 0x60, 21, 3);
+
+       hws[IMX6QDL_CLK_VPU_AXI_PODF]     = imx_clk_hw_divider("vpu_axi_podf",     "vpu_axi_sel",       base + 0x24, 25, 3);
+       hws[IMX6QDL_CLK_CKO1_PODF]        = imx_clk_hw_divider("cko1_podf",        "cko1_sel",          base + 0x60, 4,  3);
+       hws[IMX6QDL_CLK_CKO2_PODF]        = imx_clk_hw_divider("cko2_podf",        "cko2_sel",          base + 0x60, 21, 3);
 
        /*                                                        name                 parent_name    reg        shift width busy: reg, shift */
-       clk[IMX6QDL_CLK_AXI]               = imx_clk_busy_divider("axi",               "axi_sel",     base + 0x14, 16,  3,   base + 0x48, 0);
-       clk[IMX6QDL_CLK_MMDC_CH0_AXI_PODF] = imx_clk_busy_divider("mmdc_ch0_axi_podf", "periph",      base + 0x14, 19,  3,   base + 0x48, 4);
+       hws[IMX6QDL_CLK_AXI]               = imx_clk_hw_busy_divider("axi",               "axi_sel",     base + 0x14, 16,  3,   base + 0x48, 0);
+       hws[IMX6QDL_CLK_MMDC_CH0_AXI_PODF] = imx_clk_hw_busy_divider("mmdc_ch0_axi_podf", "periph",      base + 0x14, 19,  3,   base + 0x48, 4);
        if (clk_on_imx6qp()) {
-               clk[IMX6QDL_CLK_MMDC_CH1_AXI_CG] = imx_clk_gate("mmdc_ch1_axi_cg", "periph2", base + 0x4, 18);
-               clk[IMX6QDL_CLK_MMDC_CH1_AXI_PODF] = imx_clk_busy_divider("mmdc_ch1_axi_podf", "mmdc_ch1_axi_cg", base + 0x14, 3, 3, base + 0x48, 2);
+               hws[IMX6QDL_CLK_MMDC_CH1_AXI_CG] = imx_clk_hw_gate("mmdc_ch1_axi_cg", "periph2", base + 0x4, 18);
+               hws[IMX6QDL_CLK_MMDC_CH1_AXI_PODF] = imx_clk_hw_busy_divider("mmdc_ch1_axi_podf", "mmdc_ch1_axi_cg", base + 0x14, 3, 3, base + 0x48, 2);
        } else {
-               clk[IMX6QDL_CLK_MMDC_CH1_AXI_PODF] = imx_clk_busy_divider("mmdc_ch1_axi_podf", "periph2",     base + 0x14, 3,   3,   base + 0x48, 2);
+               hws[IMX6QDL_CLK_MMDC_CH1_AXI_PODF] = imx_clk_hw_busy_divider("mmdc_ch1_axi_podf", "periph2",     base + 0x14, 3,   3,   base + 0x48, 2);
        }
-       clk[IMX6QDL_CLK_ARM]               = imx_clk_busy_divider("arm",               "pll1_sw",     base + 0x10, 0,   3,   base + 0x48, 16);
-       clk[IMX6QDL_CLK_AHB]               = imx_clk_busy_divider("ahb",               "periph",      base + 0x14, 10,  3,   base + 0x48, 1);
+       hws[IMX6QDL_CLK_ARM]               = imx_clk_hw_busy_divider("arm",               "pll1_sw",     base + 0x10, 0,   3,   base + 0x48, 16);
+       hws[IMX6QDL_CLK_AHB]               = imx_clk_hw_busy_divider("ahb",               "periph",      base + 0x14, 10,  3,   base + 0x48, 1);
 
        /*                                            name             parent_name          reg         shift */
-       clk[IMX6QDL_CLK_APBH_DMA]     = imx_clk_gate2("apbh_dma",      "usdhc3",            base + 0x68, 4);
-       clk[IMX6QDL_CLK_ASRC]         = imx_clk_gate2_shared("asrc",         "asrc_podf",   base + 0x68, 6, &share_count_asrc);
-       clk[IMX6QDL_CLK_ASRC_IPG]     = imx_clk_gate2_shared("asrc_ipg",     "ahb",         base + 0x68, 6, &share_count_asrc);
-       clk[IMX6QDL_CLK_ASRC_MEM]     = imx_clk_gate2_shared("asrc_mem",     "ahb",         base + 0x68, 6, &share_count_asrc);
-       clk[IMX6QDL_CLK_CAAM_MEM]     = imx_clk_gate2("caam_mem",      "ahb",               base + 0x68, 8);
-       clk[IMX6QDL_CLK_CAAM_ACLK]    = imx_clk_gate2("caam_aclk",     "ahb",               base + 0x68, 10);
-       clk[IMX6QDL_CLK_CAAM_IPG]     = imx_clk_gate2("caam_ipg",      "ipg",               base + 0x68, 12);
-       clk[IMX6QDL_CLK_CAN1_IPG]     = imx_clk_gate2("can1_ipg",      "ipg",               base + 0x68, 14);
-       clk[IMX6QDL_CLK_CAN1_SERIAL]  = imx_clk_gate2("can1_serial",   "can_root",          base + 0x68, 16);
-       clk[IMX6QDL_CLK_CAN2_IPG]     = imx_clk_gate2("can2_ipg",      "ipg",               base + 0x68, 18);
-       clk[IMX6QDL_CLK_CAN2_SERIAL]  = imx_clk_gate2("can2_serial",   "can_root",          base + 0x68, 20);
-       clk[IMX6QDL_CLK_DCIC1]        = imx_clk_gate2("dcic1",         "ipu1_podf",         base + 0x68, 24);
-       clk[IMX6QDL_CLK_DCIC2]        = imx_clk_gate2("dcic2",         "ipu2_podf",         base + 0x68, 26);
-       clk[IMX6QDL_CLK_ECSPI1]       = imx_clk_gate2("ecspi1",        "ecspi_root",        base + 0x6c, 0);
-       clk[IMX6QDL_CLK_ECSPI2]       = imx_clk_gate2("ecspi2",        "ecspi_root",        base + 0x6c, 2);
-       clk[IMX6QDL_CLK_ECSPI3]       = imx_clk_gate2("ecspi3",        "ecspi_root",        base + 0x6c, 4);
-       clk[IMX6QDL_CLK_ECSPI4]       = imx_clk_gate2("ecspi4",        "ecspi_root",        base + 0x6c, 6);
+       hws[IMX6QDL_CLK_APBH_DMA]     = imx_clk_hw_gate2("apbh_dma",      "usdhc3",            base + 0x68, 4);
+       hws[IMX6QDL_CLK_ASRC]         = imx_clk_hw_gate2_shared("asrc",         "asrc_podf",   base + 0x68, 6, &share_count_asrc);
+       hws[IMX6QDL_CLK_ASRC_IPG]     = imx_clk_hw_gate2_shared("asrc_ipg",     "ahb",         base + 0x68, 6, &share_count_asrc);
+       hws[IMX6QDL_CLK_ASRC_MEM]     = imx_clk_hw_gate2_shared("asrc_mem",     "ahb",         base + 0x68, 6, &share_count_asrc);
+       hws[IMX6QDL_CLK_CAAM_MEM]     = imx_clk_hw_gate2("caam_mem",      "ahb",               base + 0x68, 8);
+       hws[IMX6QDL_CLK_CAAM_ACLK]    = imx_clk_hw_gate2("caam_aclk",     "ahb",               base + 0x68, 10);
+       hws[IMX6QDL_CLK_CAAM_IPG]     = imx_clk_hw_gate2("caam_ipg",      "ipg",               base + 0x68, 12);
+       hws[IMX6QDL_CLK_CAN1_IPG]     = imx_clk_hw_gate2("can1_ipg",      "ipg",               base + 0x68, 14);
+       hws[IMX6QDL_CLK_CAN1_SERIAL]  = imx_clk_hw_gate2("can1_serial",   "can_root",          base + 0x68, 16);
+       hws[IMX6QDL_CLK_CAN2_IPG]     = imx_clk_hw_gate2("can2_ipg",      "ipg",               base + 0x68, 18);
+       hws[IMX6QDL_CLK_CAN2_SERIAL]  = imx_clk_hw_gate2("can2_serial",   "can_root",          base + 0x68, 20);
+       hws[IMX6QDL_CLK_DCIC1]        = imx_clk_hw_gate2("dcic1",         "ipu1_podf",         base + 0x68, 24);
+       hws[IMX6QDL_CLK_DCIC2]        = imx_clk_hw_gate2("dcic2",         "ipu2_podf",         base + 0x68, 26);
+       hws[IMX6QDL_CLK_ECSPI1]       = imx_clk_hw_gate2("ecspi1",        "ecspi_root",        base + 0x6c, 0);
+       hws[IMX6QDL_CLK_ECSPI2]       = imx_clk_hw_gate2("ecspi2",        "ecspi_root",        base + 0x6c, 2);
+       hws[IMX6QDL_CLK_ECSPI3]       = imx_clk_hw_gate2("ecspi3",        "ecspi_root",        base + 0x6c, 4);
+       hws[IMX6QDL_CLK_ECSPI4]       = imx_clk_hw_gate2("ecspi4",        "ecspi_root",        base + 0x6c, 6);
        if (clk_on_imx6dl())
-               clk[IMX6DL_CLK_I2C4]  = imx_clk_gate2("i2c4",          "ipg_per",           base + 0x6c, 8);
+               hws[IMX6DL_CLK_I2C4]  = imx_clk_hw_gate2("i2c4",          "ipg_per",           base + 0x6c, 8);
        else
-               clk[IMX6Q_CLK_ECSPI5] = imx_clk_gate2("ecspi5",        "ecspi_root",        base + 0x6c, 8);
-       clk[IMX6QDL_CLK_ENET]         = imx_clk_gate2("enet",          "ipg",               base + 0x6c, 10);
-       clk[IMX6QDL_CLK_EPIT1]        = imx_clk_gate2("epit1",         "ipg",               base + 0x6c, 12);
-       clk[IMX6QDL_CLK_EPIT2]        = imx_clk_gate2("epit2",         "ipg",               base + 0x6c, 14);
-       clk[IMX6QDL_CLK_ESAI_EXTAL]   = imx_clk_gate2_shared("esai_extal",   "esai_podf",   base + 0x6c, 16, &share_count_esai);
-       clk[IMX6QDL_CLK_ESAI_IPG]     = imx_clk_gate2_shared("esai_ipg",   "ahb",           base + 0x6c, 16, &share_count_esai);
-       clk[IMX6QDL_CLK_ESAI_MEM]     = imx_clk_gate2_shared("esai_mem", "ahb",             base + 0x6c, 16, &share_count_esai);
-       clk[IMX6QDL_CLK_GPT_IPG]      = imx_clk_gate2("gpt_ipg",       "ipg",               base + 0x6c, 20);
-       clk[IMX6QDL_CLK_GPT_IPG_PER]  = imx_clk_gate2("gpt_ipg_per",   "ipg_per",           base + 0x6c, 22);
-       clk[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24);
-       clk[IMX6QDL_CLK_GPU3D_CORE]   = imx_clk_gate2("gpu3d_core",    "gpu3d_core_podf",   base + 0x6c, 26);
-       clk[IMX6QDL_CLK_HDMI_IAHB]    = imx_clk_gate2("hdmi_iahb",     "ahb",               base + 0x70, 0);
-       clk[IMX6QDL_CLK_HDMI_ISFR]    = imx_clk_gate2("hdmi_isfr",     "mipi_core_cfg",     base + 0x70, 4);
-       clk[IMX6QDL_CLK_I2C1]         = imx_clk_gate2("i2c1",          "ipg_per",           base + 0x70, 6);
-       clk[IMX6QDL_CLK_I2C2]         = imx_clk_gate2("i2c2",          "ipg_per",           base + 0x70, 8);
-       clk[IMX6QDL_CLK_I2C3]         = imx_clk_gate2("i2c3",          "ipg_per",           base + 0x70, 10);
-       clk[IMX6QDL_CLK_IIM]          = imx_clk_gate2("iim",           "ipg",               base + 0x70, 12);
-       clk[IMX6QDL_CLK_ENFC]         = imx_clk_gate2("enfc",          "enfc_podf",         base + 0x70, 14);
-       clk[IMX6QDL_CLK_VDOA]         = imx_clk_gate2("vdoa",          "vdo_axi",           base + 0x70, 26);
-       clk[IMX6QDL_CLK_IPU1]         = imx_clk_gate2("ipu1",          "ipu1_podf",         base + 0x74, 0);
-       clk[IMX6QDL_CLK_IPU1_DI0]     = imx_clk_gate2("ipu1_di0",      "ipu1_di0_sel",      base + 0x74, 2);
-       clk[IMX6QDL_CLK_IPU1_DI1]     = imx_clk_gate2("ipu1_di1",      "ipu1_di1_sel",      base + 0x74, 4);
-       clk[IMX6QDL_CLK_IPU2]         = imx_clk_gate2("ipu2",          "ipu2_podf",         base + 0x74, 6);
-       clk[IMX6QDL_CLK_IPU2_DI0]     = imx_clk_gate2("ipu2_di0",      "ipu2_di0_sel",      base + 0x74, 8);
+               hws[IMX6Q_CLK_ECSPI5] = imx_clk_hw_gate2("ecspi5",        "ecspi_root",        base + 0x6c, 8);
+       hws[IMX6QDL_CLK_ENET]         = imx_clk_hw_gate2("enet",          "ipg",               base + 0x6c, 10);
+       hws[IMX6QDL_CLK_EPIT1]        = imx_clk_hw_gate2("epit1",         "ipg",               base + 0x6c, 12);
+       hws[IMX6QDL_CLK_EPIT2]        = imx_clk_hw_gate2("epit2",         "ipg",               base + 0x6c, 14);
+       hws[IMX6QDL_CLK_ESAI_EXTAL]   = imx_clk_hw_gate2_shared("esai_extal",   "esai_podf",   base + 0x6c, 16, &share_count_esai);
+       hws[IMX6QDL_CLK_ESAI_IPG]     = imx_clk_hw_gate2_shared("esai_ipg",   "ahb",           base + 0x6c, 16, &share_count_esai);
+       hws[IMX6QDL_CLK_ESAI_MEM]     = imx_clk_hw_gate2_shared("esai_mem", "ahb",             base + 0x6c, 16, &share_count_esai);
+       hws[IMX6QDL_CLK_GPT_IPG]      = imx_clk_hw_gate2("gpt_ipg",       "ipg",               base + 0x6c, 20);
+       hws[IMX6QDL_CLK_GPT_IPG_PER]  = imx_clk_hw_gate2("gpt_ipg_per",   "ipg_per",           base + 0x6c, 22);
+       hws[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_hw_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24);
+       hws[IMX6QDL_CLK_GPU3D_CORE]   = imx_clk_hw_gate2("gpu3d_core",    "gpu3d_core_podf",   base + 0x6c, 26);
+       hws[IMX6QDL_CLK_HDMI_IAHB]    = imx_clk_hw_gate2("hdmi_iahb",     "ahb",               base + 0x70, 0);
+       hws[IMX6QDL_CLK_HDMI_ISFR]    = imx_clk_hw_gate2("hdmi_isfr",     "mipi_core_cfg",     base + 0x70, 4);
+       hws[IMX6QDL_CLK_I2C1]         = imx_clk_hw_gate2("i2c1",          "ipg_per",           base + 0x70, 6);
+       hws[IMX6QDL_CLK_I2C2]         = imx_clk_hw_gate2("i2c2",          "ipg_per",           base + 0x70, 8);
+       hws[IMX6QDL_CLK_I2C3]         = imx_clk_hw_gate2("i2c3",          "ipg_per",           base + 0x70, 10);
+       hws[IMX6QDL_CLK_IIM]          = imx_clk_hw_gate2("iim",           "ipg",               base + 0x70, 12);
+       hws[IMX6QDL_CLK_ENFC]         = imx_clk_hw_gate2("enfc",          "enfc_podf",         base + 0x70, 14);
+       hws[IMX6QDL_CLK_VDOA]         = imx_clk_hw_gate2("vdoa",          "vdo_axi",           base + 0x70, 26);
+       hws[IMX6QDL_CLK_IPU1]         = imx_clk_hw_gate2("ipu1",          "ipu1_podf",         base + 0x74, 0);
+       hws[IMX6QDL_CLK_IPU1_DI0]     = imx_clk_hw_gate2("ipu1_di0",      "ipu1_di0_sel",      base + 0x74, 2);
+       hws[IMX6QDL_CLK_IPU1_DI1]     = imx_clk_hw_gate2("ipu1_di1",      "ipu1_di1_sel",      base + 0x74, 4);
+       hws[IMX6QDL_CLK_IPU2]         = imx_clk_hw_gate2("ipu2",          "ipu2_podf",         base + 0x74, 6);
+       hws[IMX6QDL_CLK_IPU2_DI0]     = imx_clk_hw_gate2("ipu2_di0",      "ipu2_di0_sel",      base + 0x74, 8);
        if (clk_on_imx6qp()) {
-               clk[IMX6QDL_CLK_LDB_DI0]      = imx_clk_gate2("ldb_di0",       "ldb_di0_sel",      base + 0x74, 12);
-               clk[IMX6QDL_CLK_LDB_DI1]      = imx_clk_gate2("ldb_di1",       "ldb_di1_sel",      base + 0x74, 14);
+               hws[IMX6QDL_CLK_LDB_DI0]      = imx_clk_hw_gate2("ldb_di0",       "ldb_di0_sel",      base + 0x74, 12);
+               hws[IMX6QDL_CLK_LDB_DI1]      = imx_clk_hw_gate2("ldb_di1",       "ldb_di1_sel",      base + 0x74, 14);
        } else {
-               clk[IMX6QDL_CLK_LDB_DI0]      = imx_clk_gate2("ldb_di0",       "ldb_di0_podf",      base + 0x74, 12);
-               clk[IMX6QDL_CLK_LDB_DI1]      = imx_clk_gate2("ldb_di1",       "ldb_di1_podf",      base + 0x74, 14);
+               hws[IMX6QDL_CLK_LDB_DI0]      = imx_clk_hw_gate2("ldb_di0",       "ldb_di0_podf",      base + 0x74, 12);
+               hws[IMX6QDL_CLK_LDB_DI1]      = imx_clk_hw_gate2("ldb_di1",       "ldb_di1_podf",      base + 0x74, 14);
        }
-       clk[IMX6QDL_CLK_IPU2_DI1]     = imx_clk_gate2("ipu2_di1",      "ipu2_di1_sel",      base + 0x74, 10);
-       clk[IMX6QDL_CLK_HSI_TX]       = imx_clk_gate2_shared("hsi_tx", "hsi_tx_podf",       base + 0x74, 16, &share_count_mipi_core_cfg);
-       clk[IMX6QDL_CLK_MIPI_CORE_CFG] = imx_clk_gate2_shared("mipi_core_cfg", "video_27m", base + 0x74, 16, &share_count_mipi_core_cfg);
-       clk[IMX6QDL_CLK_MIPI_IPG]     = imx_clk_gate2_shared("mipi_ipg", "ipg",             base + 0x74, 16, &share_count_mipi_core_cfg);
+       hws[IMX6QDL_CLK_IPU2_DI1]     = imx_clk_hw_gate2("ipu2_di1",      "ipu2_di1_sel",      base + 0x74, 10);
+       hws[IMX6QDL_CLK_HSI_TX]       = imx_clk_hw_gate2_shared("hsi_tx", "hsi_tx_podf",       base + 0x74, 16, &share_count_mipi_core_cfg);
+       hws[IMX6QDL_CLK_MIPI_CORE_CFG] = imx_clk_hw_gate2_shared("mipi_core_cfg", "video_27m", base + 0x74, 16, &share_count_mipi_core_cfg);
+       hws[IMX6QDL_CLK_MIPI_IPG]     = imx_clk_hw_gate2_shared("mipi_ipg", "ipg",             base + 0x74, 16, &share_count_mipi_core_cfg);
+
        if (clk_on_imx6dl())
                /*
                 * The multiplexer and divider of the imx6q clock gpu2d get
                 * redefined/reused as mlb_sys_sel and mlb_sys_clk_podf on imx6dl.
                 */
-               clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb",            "mlb_podf",   base + 0x74, 18);
+               hws[IMX6QDL_CLK_MLB] = imx_clk_hw_gate2("mlb",            "mlb_podf",   base + 0x74, 18);
        else
-               clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb",            "axi",               base + 0x74, 18);
-       clk[IMX6QDL_CLK_MMDC_CH0_AXI] = imx_clk_gate2_flags("mmdc_ch0_axi",  "mmdc_ch0_axi_podf", base + 0x74, 20, CLK_IS_CRITICAL);
-       clk[IMX6QDL_CLK_MMDC_CH1_AXI] = imx_clk_gate2("mmdc_ch1_axi",  "mmdc_ch1_axi_podf", base + 0x74, 22);
-       clk[IMX6QDL_CLK_MMDC_P0_IPG]  = imx_clk_gate2_flags("mmdc_p0_ipg",   "ipg",         base + 0x74, 24, CLK_IS_CRITICAL);
-       clk[IMX6QDL_CLK_OCRAM]        = imx_clk_gate2("ocram",         "ahb",               base + 0x74, 28);
-       clk[IMX6QDL_CLK_OPENVG_AXI]   = imx_clk_gate2("openvg_axi",    "axi",               base + 0x74, 30);
-       clk[IMX6QDL_CLK_PCIE_AXI]     = imx_clk_gate2("pcie_axi",      "pcie_axi_sel",      base + 0x78, 0);
-       clk[IMX6QDL_CLK_PER1_BCH]     = imx_clk_gate2("per1_bch",      "usdhc3",            base + 0x78, 12);
-       clk[IMX6QDL_CLK_PWM1]         = imx_clk_gate2("pwm1",          "ipg_per",           base + 0x78, 16);
-       clk[IMX6QDL_CLK_PWM2]         = imx_clk_gate2("pwm2",          "ipg_per",           base + 0x78, 18);
-       clk[IMX6QDL_CLK_PWM3]         = imx_clk_gate2("pwm3",          "ipg_per",           base + 0x78, 20);
-       clk[IMX6QDL_CLK_PWM4]         = imx_clk_gate2("pwm4",          "ipg_per",           base + 0x78, 22);
-       clk[IMX6QDL_CLK_GPMI_BCH_APB] = imx_clk_gate2("gpmi_bch_apb",  "usdhc3",            base + 0x78, 24);
-       clk[IMX6QDL_CLK_GPMI_BCH]     = imx_clk_gate2("gpmi_bch",      "usdhc4",            base + 0x78, 26);
-       clk[IMX6QDL_CLK_GPMI_IO]      = imx_clk_gate2("gpmi_io",       "enfc",              base + 0x78, 28);
-       clk[IMX6QDL_CLK_GPMI_APB]     = imx_clk_gate2("gpmi_apb",      "usdhc3",            base + 0x78, 30);
-       clk[IMX6QDL_CLK_ROM]          = imx_clk_gate2_flags("rom",     "ahb",               base + 0x7c, 0, CLK_IS_CRITICAL);
-       clk[IMX6QDL_CLK_SATA]         = imx_clk_gate2("sata",          "ahb",               base + 0x7c, 4);
-       clk[IMX6QDL_CLK_SDMA]         = imx_clk_gate2("sdma",          "ahb",               base + 0x7c, 6);
-       clk[IMX6QDL_CLK_SPBA]         = imx_clk_gate2("spba",          "ipg",               base + 0x7c, 12);
-       clk[IMX6QDL_CLK_SPDIF]        = imx_clk_gate2_shared("spdif",     "spdif_podf",     base + 0x7c, 14, &share_count_spdif);
-       clk[IMX6QDL_CLK_SPDIF_GCLK]   = imx_clk_gate2_shared("spdif_gclk", "ipg",           base + 0x7c, 14, &share_count_spdif);
-       clk[IMX6QDL_CLK_SSI1_IPG]     = imx_clk_gate2_shared("ssi1_ipg",      "ipg",        base + 0x7c, 18, &share_count_ssi1);
-       clk[IMX6QDL_CLK_SSI2_IPG]     = imx_clk_gate2_shared("ssi2_ipg",      "ipg",        base + 0x7c, 20, &share_count_ssi2);
-       clk[IMX6QDL_CLK_SSI3_IPG]     = imx_clk_gate2_shared("ssi3_ipg",      "ipg",        base + 0x7c, 22, &share_count_ssi3);
-       clk[IMX6QDL_CLK_SSI1]         = imx_clk_gate2_shared("ssi1",          "ssi1_podf",  base + 0x7c, 18, &share_count_ssi1);
-       clk[IMX6QDL_CLK_SSI2]         = imx_clk_gate2_shared("ssi2",          "ssi2_podf",  base + 0x7c, 20, &share_count_ssi2);
-       clk[IMX6QDL_CLK_SSI3]         = imx_clk_gate2_shared("ssi3",          "ssi3_podf",  base + 0x7c, 22, &share_count_ssi3);
-       clk[IMX6QDL_CLK_UART_IPG]     = imx_clk_gate2("uart_ipg",      "ipg",               base + 0x7c, 24);
-       clk[IMX6QDL_CLK_UART_SERIAL]  = imx_clk_gate2("uart_serial",   "uart_serial_podf",  base + 0x7c, 26);
-       clk[IMX6QDL_CLK_USBOH3]       = imx_clk_gate2("usboh3",        "ipg",               base + 0x80, 0);
-       clk[IMX6QDL_CLK_USDHC1]       = imx_clk_gate2("usdhc1",        "usdhc1_podf",       base + 0x80, 2);
-       clk[IMX6QDL_CLK_USDHC2]       = imx_clk_gate2("usdhc2",        "usdhc2_podf",       base + 0x80, 4);
-       clk[IMX6QDL_CLK_USDHC3]       = imx_clk_gate2("usdhc3",        "usdhc3_podf",       base + 0x80, 6);
-       clk[IMX6QDL_CLK_USDHC4]       = imx_clk_gate2("usdhc4",        "usdhc4_podf",       base + 0x80, 8);
-       clk[IMX6QDL_CLK_EIM_SLOW]     = imx_clk_gate2("eim_slow",      "eim_slow_podf",     base + 0x80, 10);
-       clk[IMX6QDL_CLK_VDO_AXI]      = imx_clk_gate2("vdo_axi",       "vdo_axi_sel",       base + 0x80, 12);
-       clk[IMX6QDL_CLK_VPU_AXI]      = imx_clk_gate2("vpu_axi",       "vpu_axi_podf",      base + 0x80, 14);
+               hws[IMX6QDL_CLK_MLB] = imx_clk_hw_gate2("mlb",            "axi",               base + 0x74, 18);
+       hws[IMX6QDL_CLK_MMDC_CH0_AXI] = imx_clk_hw_gate2_flags("mmdc_ch0_axi",  "mmdc_ch0_axi_podf", base + 0x74, 20, CLK_IS_CRITICAL);
+       hws[IMX6QDL_CLK_MMDC_CH1_AXI] = imx_clk_hw_gate2("mmdc_ch1_axi",  "mmdc_ch1_axi_podf", base + 0x74, 22);
+       hws[IMX6QDL_CLK_MMDC_P0_IPG]  = imx_clk_hw_gate2_flags("mmdc_p0_ipg",   "ipg",         base + 0x74, 24, CLK_IS_CRITICAL);
+       hws[IMX6QDL_CLK_OCRAM]        = imx_clk_hw_gate2("ocram",         "ahb",               base + 0x74, 28);
+       hws[IMX6QDL_CLK_OPENVG_AXI]   = imx_clk_hw_gate2("openvg_axi",    "axi",               base + 0x74, 30);
+       hws[IMX6QDL_CLK_PCIE_AXI]     = imx_clk_hw_gate2("pcie_axi",      "pcie_axi_sel",      base + 0x78, 0);
+       hws[IMX6QDL_CLK_PER1_BCH]     = imx_clk_hw_gate2("per1_bch",      "usdhc3",            base + 0x78, 12);
+       hws[IMX6QDL_CLK_PWM1]         = imx_clk_hw_gate2("pwm1",          "ipg_per",           base + 0x78, 16);
+       hws[IMX6QDL_CLK_PWM2]         = imx_clk_hw_gate2("pwm2",          "ipg_per",           base + 0x78, 18);
+       hws[IMX6QDL_CLK_PWM3]         = imx_clk_hw_gate2("pwm3",          "ipg_per",           base + 0x78, 20);
+       hws[IMX6QDL_CLK_PWM4]         = imx_clk_hw_gate2("pwm4",          "ipg_per",           base + 0x78, 22);
+       hws[IMX6QDL_CLK_GPMI_BCH_APB] = imx_clk_hw_gate2("gpmi_bch_apb",  "usdhc3",            base + 0x78, 24);
+       hws[IMX6QDL_CLK_GPMI_BCH]     = imx_clk_hw_gate2("gpmi_bch",      "usdhc4",            base + 0x78, 26);
+       hws[IMX6QDL_CLK_GPMI_IO]      = imx_clk_hw_gate2("gpmi_io",       "enfc",              base + 0x78, 28);
+       hws[IMX6QDL_CLK_GPMI_APB]     = imx_clk_hw_gate2("gpmi_apb",      "usdhc3",            base + 0x78, 30);
+       hws[IMX6QDL_CLK_ROM]          = imx_clk_hw_gate2_flags("rom",     "ahb",               base + 0x7c, 0, CLK_IS_CRITICAL);
+       hws[IMX6QDL_CLK_SATA]         = imx_clk_hw_gate2("sata",          "ahb",               base + 0x7c, 4);
+       hws[IMX6QDL_CLK_SDMA]         = imx_clk_hw_gate2("sdma",          "ahb",               base + 0x7c, 6);
+       hws[IMX6QDL_CLK_SPBA]         = imx_clk_hw_gate2("spba",          "ipg",               base + 0x7c, 12);
+       hws[IMX6QDL_CLK_SPDIF]        = imx_clk_hw_gate2_shared("spdif",     "spdif_podf",     base + 0x7c, 14, &share_count_spdif);
+       hws[IMX6QDL_CLK_SPDIF_GCLK]   = imx_clk_hw_gate2_shared("spdif_gclk", "ipg",           base + 0x7c, 14, &share_count_spdif);
+       hws[IMX6QDL_CLK_SSI1_IPG]     = imx_clk_hw_gate2_shared("ssi1_ipg",      "ipg",        base + 0x7c, 18, &share_count_ssi1);
+       hws[IMX6QDL_CLK_SSI2_IPG]     = imx_clk_hw_gate2_shared("ssi2_ipg",      "ipg",        base + 0x7c, 20, &share_count_ssi2);
+       hws[IMX6QDL_CLK_SSI3_IPG]     = imx_clk_hw_gate2_shared("ssi3_ipg",      "ipg",        base + 0x7c, 22, &share_count_ssi3);
+       hws[IMX6QDL_CLK_SSI1]         = imx_clk_hw_gate2_shared("ssi1",          "ssi1_podf",  base + 0x7c, 18, &share_count_ssi1);
+       hws[IMX6QDL_CLK_SSI2]         = imx_clk_hw_gate2_shared("ssi2",          "ssi2_podf",  base + 0x7c, 20, &share_count_ssi2);
+       hws[IMX6QDL_CLK_SSI3]         = imx_clk_hw_gate2_shared("ssi3",          "ssi3_podf",  base + 0x7c, 22, &share_count_ssi3);
+       hws[IMX6QDL_CLK_UART_IPG]     = imx_clk_hw_gate2("uart_ipg",      "ipg",               base + 0x7c, 24);
+       hws[IMX6QDL_CLK_UART_SERIAL]  = imx_clk_hw_gate2("uart_serial",   "uart_serial_podf",  base + 0x7c, 26);
+       hws[IMX6QDL_CLK_USBOH3]       = imx_clk_hw_gate2("usboh3",        "ipg",               base + 0x80, 0);
+       hws[IMX6QDL_CLK_USDHC1]       = imx_clk_hw_gate2("usdhc1",        "usdhc1_podf",       base + 0x80, 2);
+       hws[IMX6QDL_CLK_USDHC2]       = imx_clk_hw_gate2("usdhc2",        "usdhc2_podf",       base + 0x80, 4);
+       hws[IMX6QDL_CLK_USDHC3]       = imx_clk_hw_gate2("usdhc3",        "usdhc3_podf",       base + 0x80, 6);
+       hws[IMX6QDL_CLK_USDHC4]       = imx_clk_hw_gate2("usdhc4",        "usdhc4_podf",       base + 0x80, 8);
+       hws[IMX6QDL_CLK_EIM_SLOW]     = imx_clk_hw_gate2("eim_slow",      "eim_slow_podf",     base + 0x80, 10);
+       hws[IMX6QDL_CLK_VDO_AXI]      = imx_clk_hw_gate2("vdo_axi",       "vdo_axi_sel",       base + 0x80, 12);
+       hws[IMX6QDL_CLK_VPU_AXI]      = imx_clk_hw_gate2("vpu_axi",       "vpu_axi_podf",      base + 0x80, 14);
        if (clk_on_imx6qp()) {
-               clk[IMX6QDL_CLK_PRE0] = imx_clk_gate2("pre0",          "pre_axi",           base + 0x80, 16);
-               clk[IMX6QDL_CLK_PRE1] = imx_clk_gate2("pre1",          "pre_axi",           base + 0x80, 18);
-               clk[IMX6QDL_CLK_PRE2] = imx_clk_gate2("pre2",          "pre_axi",         base + 0x80, 20);
-               clk[IMX6QDL_CLK_PRE3] = imx_clk_gate2("pre3",          "pre_axi",           base + 0x80, 22);
-               clk[IMX6QDL_CLK_PRG0_AXI] = imx_clk_gate2_shared("prg0_axi",  "ipu1_podf",  base + 0x80, 24, &share_count_prg0);
-               clk[IMX6QDL_CLK_PRG1_AXI] = imx_clk_gate2_shared("prg1_axi",  "ipu2_podf",  base + 0x80, 26, &share_count_prg1);
-               clk[IMX6QDL_CLK_PRG0_APB] = imx_clk_gate2_shared("prg0_apb",  "ipg",        base + 0x80, 24, &share_count_prg0);
-               clk[IMX6QDL_CLK_PRG1_APB] = imx_clk_gate2_shared("prg1_apb",  "ipg",        base + 0x80, 26, &share_count_prg1);
+               hws[IMX6QDL_CLK_PRE0] = imx_clk_hw_gate2("pre0",               "pre_axi",           base + 0x80, 16);
+               hws[IMX6QDL_CLK_PRE1] = imx_clk_hw_gate2("pre1",               "pre_axi",           base + 0x80, 18);
+               hws[IMX6QDL_CLK_PRE2] = imx_clk_hw_gate2("pre2",               "pre_axi",         base + 0x80, 20);
+               hws[IMX6QDL_CLK_PRE3] = imx_clk_hw_gate2("pre3",               "pre_axi",           base + 0x80, 22);
+               hws[IMX6QDL_CLK_PRG0_AXI] = imx_clk_hw_gate2_shared("prg0_axi",  "ipu1_podf",  base + 0x80, 24, &share_count_prg0);
+               hws[IMX6QDL_CLK_PRG1_AXI] = imx_clk_hw_gate2_shared("prg1_axi",  "ipu2_podf",  base + 0x80, 26, &share_count_prg1);
+               hws[IMX6QDL_CLK_PRG0_APB] = imx_clk_hw_gate2_shared("prg0_apb",  "ipg",     base + 0x80, 24, &share_count_prg0);
+               hws[IMX6QDL_CLK_PRG1_APB] = imx_clk_hw_gate2_shared("prg1_apb",  "ipg",     base + 0x80, 26, &share_count_prg1);
        }
-       clk[IMX6QDL_CLK_CKO1]         = imx_clk_gate("cko1",           "cko1_podf",         base + 0x60, 7);
-       clk[IMX6QDL_CLK_CKO2]         = imx_clk_gate("cko2",           "cko2_podf",         base + 0x60, 24);
+       hws[IMX6QDL_CLK_CKO1]         = imx_clk_hw_gate("cko1",           "cko1_podf",         base + 0x60, 7);
+       hws[IMX6QDL_CLK_CKO2]         = imx_clk_hw_gate("cko2",           "cko2_podf",         base + 0x60, 24);
 
        /*
         * The gpt_3m clock is not available on i.MX6Q TO1.0.  Let's point it
         * to clock gpt_ipg_per to ease the gpt driver code.
         */
        if (clk_on_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0)
-               clk[IMX6QDL_CLK_GPT_3M] = clk[IMX6QDL_CLK_GPT_IPG_PER];
+               hws[IMX6QDL_CLK_GPT_3M] = hws[IMX6QDL_CLK_GPT_IPG_PER];
 
-       imx_check_clocks(clk, ARRAY_SIZE(clk));
+       imx_check_clk_hws(hws, IMX6QDL_CLK_END);
 
-       clk_data.clks = clk;
-       clk_data.clk_num = ARRAY_SIZE(clk);
-       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+       of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
 
-       clk_register_clkdev(clk[IMX6QDL_CLK_ENET_REF], "enet_ref", NULL);
+       clk_hw_register_clkdev(hws[IMX6QDL_CLK_ENET_REF], "enet_ref", NULL);
 
-       clk_set_rate(clk[IMX6QDL_CLK_PLL3_PFD1_540M], 540000000);
+       clk_set_rate(hws[IMX6QDL_CLK_PLL3_PFD1_540M]->clk, 540000000);
        if (clk_on_imx6dl())
-               clk_set_parent(clk[IMX6QDL_CLK_IPU1_SEL], clk[IMX6QDL_CLK_PLL3_PFD1_540M]);
+               clk_set_parent(hws[IMX6QDL_CLK_IPU1_SEL]->clk, hws[IMX6QDL_CLK_PLL3_PFD1_540M]->clk);
 
-       clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI0_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
-       clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI1_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
-       clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI0_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
-       clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI1_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
-       clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI0_SEL], clk[IMX6QDL_CLK_IPU1_DI0_PRE]);
-       clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI1_SEL], clk[IMX6QDL_CLK_IPU1_DI1_PRE]);
-       clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI0_SEL], clk[IMX6QDL_CLK_IPU2_DI0_PRE]);
-       clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI1_SEL], clk[IMX6QDL_CLK_IPU2_DI1_PRE]);
+       clk_set_parent(hws[IMX6QDL_CLK_IPU1_DI0_PRE_SEL]->clk, hws[IMX6QDL_CLK_PLL5_VIDEO_DIV]->clk);
+       clk_set_parent(hws[IMX6QDL_CLK_IPU1_DI1_PRE_SEL]->clk, hws[IMX6QDL_CLK_PLL5_VIDEO_DIV]->clk);
+       clk_set_parent(hws[IMX6QDL_CLK_IPU2_DI0_PRE_SEL]->clk, hws[IMX6QDL_CLK_PLL5_VIDEO_DIV]->clk);
+       clk_set_parent(hws[IMX6QDL_CLK_IPU2_DI1_PRE_SEL]->clk, hws[IMX6QDL_CLK_PLL5_VIDEO_DIV]->clk);
+       clk_set_parent(hws[IMX6QDL_CLK_IPU1_DI0_SEL]->clk, hws[IMX6QDL_CLK_IPU1_DI0_PRE]->clk);
+       clk_set_parent(hws[IMX6QDL_CLK_IPU1_DI1_SEL]->clk, hws[IMX6QDL_CLK_IPU1_DI1_PRE]->clk);
+       clk_set_parent(hws[IMX6QDL_CLK_IPU2_DI0_SEL]->clk, hws[IMX6QDL_CLK_IPU2_DI0_PRE]->clk);
+       clk_set_parent(hws[IMX6QDL_CLK_IPU2_DI1_SEL]->clk, hws[IMX6QDL_CLK_IPU2_DI1_PRE]->clk);
 
        /*
         * The gpmi needs 100MHz frequency in the EDO/Sync mode,
         * We can not get the 100MHz from the pll2_pfd0_352m.
         * So choose pll2_pfd2_396m as enfc_sel's parent.
         */
-       clk_set_parent(clk[IMX6QDL_CLK_ENFC_SEL], clk[IMX6QDL_CLK_PLL2_PFD2_396M]);
+       clk_set_parent(hws[IMX6QDL_CLK_ENFC_SEL]->clk, hws[IMX6QDL_CLK_PLL2_PFD2_396M]->clk);
 
        if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
-               clk_prepare_enable(clk[IMX6QDL_CLK_USBPHY1_GATE]);
-               clk_prepare_enable(clk[IMX6QDL_CLK_USBPHY2_GATE]);
+               clk_prepare_enable(hws[IMX6QDL_CLK_USBPHY1_GATE]->clk);
+               clk_prepare_enable(hws[IMX6QDL_CLK_USBPHY2_GATE]->clk);
        }
 
        /*
         * Let's initially set up CLKO with OSC24M, since this configuration
         * is widely used by imx6q board designs to clock audio codec.
         */
-       ret = clk_set_parent(clk[IMX6QDL_CLK_CKO2_SEL], clk[IMX6QDL_CLK_OSC]);
+       ret = clk_set_parent(hws[IMX6QDL_CLK_CKO2_SEL]->clk, hws[IMX6QDL_CLK_OSC]->clk);
        if (!ret)
-               ret = clk_set_parent(clk[IMX6QDL_CLK_CKO], clk[IMX6QDL_CLK_CKO2]);
+               ret = clk_set_parent(hws[IMX6QDL_CLK_CKO]->clk, hws[IMX6QDL_CLK_CKO2]->clk);
        if (ret)
                pr_warn("failed to set up CLKO: %d\n", ret);
 
        /* Audio-related clocks configuration */
-       clk_set_parent(clk[IMX6QDL_CLK_SPDIF_SEL], clk[IMX6QDL_CLK_PLL3_PFD3_454M]);
+       clk_set_parent(hws[IMX6QDL_CLK_SPDIF_SEL]->clk, hws[IMX6QDL_CLK_PLL3_PFD3_454M]->clk);
 
        /* All existing boards with PCIe use LVDS1 */
        if (IS_ENABLED(CONFIG_PCI_IMX6))
-               clk_set_parent(clk[IMX6QDL_CLK_LVDS1_SEL], clk[IMX6QDL_CLK_SATA_REF_100M]);
+               clk_set_parent(hws[IMX6QDL_CLK_LVDS1_SEL]->clk, hws[IMX6QDL_CLK_SATA_REF_100M]->clk);
 
        /*
         * Initialize the GPU clock muxes, so that the maximum specified clock
         * rates for the respective SoC are not exceeded.
         */
        if (clk_on_imx6dl()) {
-               clk_set_parent(clk[IMX6QDL_CLK_GPU3D_CORE_SEL],
-                              clk[IMX6QDL_CLK_PLL2_PFD1_594M]);
-               clk_set_parent(clk[IMX6QDL_CLK_GPU2D_CORE_SEL],
-                              clk[IMX6QDL_CLK_PLL2_PFD1_594M]);
+               clk_set_parent(hws[IMX6QDL_CLK_GPU3D_CORE_SEL]->clk,
+                              hws[IMX6QDL_CLK_PLL2_PFD1_594M]->clk);
+               clk_set_parent(hws[IMX6QDL_CLK_GPU2D_CORE_SEL]->clk,
+                              hws[IMX6QDL_CLK_PLL2_PFD1_594M]->clk);
        } else if (clk_on_imx6q()) {
-               clk_set_parent(clk[IMX6QDL_CLK_GPU3D_CORE_SEL],
-                              clk[IMX6QDL_CLK_MMDC_CH0_AXI]);
-               clk_set_parent(clk[IMX6QDL_CLK_GPU3D_SHADER_SEL],
-                              clk[IMX6QDL_CLK_PLL2_PFD1_594M]);
-               clk_set_parent(clk[IMX6QDL_CLK_GPU2D_CORE_SEL],
-                              clk[IMX6QDL_CLK_PLL3_USB_OTG]);
+               clk_set_parent(hws[IMX6QDL_CLK_GPU3D_CORE_SEL]->clk,
+                              hws[IMX6QDL_CLK_MMDC_CH0_AXI]->clk);
+               clk_set_parent(hws[IMX6QDL_CLK_GPU3D_SHADER_SEL]->clk,
+                              hws[IMX6QDL_CLK_PLL2_PFD1_594M]->clk);
+               clk_set_parent(hws[IMX6QDL_CLK_GPU2D_CORE_SEL]->clk,
+                              hws[IMX6QDL_CLK_PLL3_USB_OTG]->clk);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
+               int index = uart_clk_ids[i];
+
+               uart_clks[i] = &hws[index]->clk;
        }
 
        imx_register_uart_clocks(uart_clks);
index f9f1f8a..4bd44d8 100644 (file)
@@ -13,8 +13,6 @@
 
 #include "clk.h"
 
-#define CCDR                           0x4
-#define BM_CCM_CCDR_MMDC_CH0_MASK      (1 << 17)
 #define CCSR                   0xc
 #define BM_CCSR_PLL1_SW_CLK_SEL        (1 << 2)
 #define CACRR                  0x10
@@ -97,8 +95,8 @@ static unsigned int share_count_ssi2;
 static unsigned int share_count_ssi3;
 static unsigned int share_count_spdif;
 
-static struct clk *clks[IMX6SL_CLK_END];
-static struct clk_onecell_data clk_data;
+static struct clk_hw **hws;
+static struct clk_hw_onecell_data *clk_hw_data;
 static void __iomem *ccm_base;
 static void __iomem *anatop_base;
 
@@ -179,74 +177,84 @@ void imx6sl_set_wait_clk(bool enter)
                imx6sl_enable_pll_arm(false);
 }
 
-static struct clk ** const uart_clks[] __initconst = {
-       &clks[IMX6SL_CLK_UART],
-       &clks[IMX6SL_CLK_UART_SERIAL],
-       NULL
+static const int uart_clk_ids[] __initconst = {
+       IMX6SL_CLK_UART,
+       IMX6SL_CLK_UART_SERIAL,
 };
 
+static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata;
+
 static void __init imx6sl_clocks_init(struct device_node *ccm_node)
 {
        struct device_node *np;
        void __iomem *base;
        int ret;
+       int i;
+
+       clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
+                                         IMX6SL_CLK_END), GFP_KERNEL);
+       if (WARN_ON(!clk_hw_data))
+               return;
+
+       clk_hw_data->num = IMX6SL_CLK_END;
+       hws = clk_hw_data->hws;
 
-       clks[IMX6SL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
-       clks[IMX6SL_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0);
-       clks[IMX6SL_CLK_OSC] = imx_obtain_fixed_clock("osc", 0);
+       hws[IMX6SL_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
+       hws[IMX6SL_CLK_CKIL] = imx_obtain_fixed_clock_hw("ckil", 0);
+       hws[IMX6SL_CLK_OSC] = imx_obtain_fixed_clock_hw("osc", 0);
        /* Clock source from external clock via CLK1 PAD */
-       clks[IMX6SL_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0);
+       hws[IMX6SL_CLK_ANACLK1] = imx_obtain_fixed_clock_hw("anaclk1", 0);
 
        np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-anatop");
        base = of_iomap(np, 0);
        WARN_ON(!base);
        anatop_base = base;
 
-       clks[IMX6SL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SL_PLL1_BYPASS_SRC] = imx_clk_hw_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SL_PLL2_BYPASS_SRC] = imx_clk_hw_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SL_PLL3_BYPASS_SRC] = imx_clk_hw_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SL_PLL4_BYPASS_SRC] = imx_clk_hw_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SL_PLL5_BYPASS_SRC] = imx_clk_hw_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SL_PLL6_BYPASS_SRC] = imx_clk_hw_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SL_PLL7_BYPASS_SRC] = imx_clk_hw_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
 
        /*                                    type               name    parent_name        base         div_mask */
-       clks[IMX6SL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS,     "pll1", "osc", base + 0x00, 0x7f);
-       clks[IMX6SL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
-       clks[IMX6SL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB,     "pll3", "osc", base + 0x10, 0x3);
-       clks[IMX6SL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV,      "pll4", "osc", base + 0x70, 0x7f);
-       clks[IMX6SL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV,      "pll5", "osc", base + 0xa0, 0x7f);
-       clks[IMX6SL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET,    "pll6", "osc", base + 0xe0, 0x3);
-       clks[IMX6SL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB,     "pll7", "osc", base + 0x20, 0x3);
-
-       clks[IMX6SL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SL_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SL_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SL_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SL_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SL_CLK_PLL1] = imx_clk_hw_pllv3(IMX_PLLV3_SYS,     "pll1", "osc", base + 0x00, 0x7f);
+       hws[IMX6SL_CLK_PLL2] = imx_clk_hw_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
+       hws[IMX6SL_CLK_PLL3] = imx_clk_hw_pllv3(IMX_PLLV3_USB,     "pll3", "osc", base + 0x10, 0x3);
+       hws[IMX6SL_CLK_PLL4] = imx_clk_hw_pllv3(IMX_PLLV3_AV,      "pll4", "osc", base + 0x70, 0x7f);
+       hws[IMX6SL_CLK_PLL5] = imx_clk_hw_pllv3(IMX_PLLV3_AV,      "pll5", "osc", base + 0xa0, 0x7f);
+       hws[IMX6SL_CLK_PLL6] = imx_clk_hw_pllv3(IMX_PLLV3_ENET,    "pll6", "osc", base + 0xe0, 0x3);
+       hws[IMX6SL_CLK_PLL7] = imx_clk_hw_pllv3(IMX_PLLV3_USB,     "pll7", "osc", base + 0x20, 0x3);
+
+       hws[IMX6SL_PLL1_BYPASS] = imx_clk_hw_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SL_PLL2_BYPASS] = imx_clk_hw_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SL_PLL3_BYPASS] = imx_clk_hw_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SL_PLL4_BYPASS] = imx_clk_hw_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SL_PLL5_BYPASS] = imx_clk_hw_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SL_PLL6_BYPASS] = imx_clk_hw_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SL_PLL7_BYPASS] = imx_clk_hw_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
 
        /* Do not bypass PLLs initially */
-       clk_set_parent(clks[IMX6SL_PLL1_BYPASS], clks[IMX6SL_CLK_PLL1]);
-       clk_set_parent(clks[IMX6SL_PLL2_BYPASS], clks[IMX6SL_CLK_PLL2]);
-       clk_set_parent(clks[IMX6SL_PLL3_BYPASS], clks[IMX6SL_CLK_PLL3]);
-       clk_set_parent(clks[IMX6SL_PLL4_BYPASS], clks[IMX6SL_CLK_PLL4]);
-       clk_set_parent(clks[IMX6SL_PLL5_BYPASS], clks[IMX6SL_CLK_PLL5]);
-       clk_set_parent(clks[IMX6SL_PLL6_BYPASS], clks[IMX6SL_CLK_PLL6]);
-       clk_set_parent(clks[IMX6SL_PLL7_BYPASS], clks[IMX6SL_CLK_PLL7]);
-
-       clks[IMX6SL_CLK_PLL1_SYS]      = imx_clk_gate("pll1_sys",      "pll1_bypass", base + 0x00, 13);
-       clks[IMX6SL_CLK_PLL2_BUS]      = imx_clk_gate("pll2_bus",      "pll2_bypass", base + 0x30, 13);
-       clks[IMX6SL_CLK_PLL3_USB_OTG]  = imx_clk_gate("pll3_usb_otg",  "pll3_bypass", base + 0x10, 13);
-       clks[IMX6SL_CLK_PLL4_AUDIO]    = imx_clk_gate("pll4_audio",    "pll4_bypass", base + 0x70, 13);
-       clks[IMX6SL_CLK_PLL5_VIDEO]    = imx_clk_gate("pll5_video",    "pll5_bypass", base + 0xa0, 13);
-       clks[IMX6SL_CLK_PLL6_ENET]     = imx_clk_gate("pll6_enet",     "pll6_bypass", base + 0xe0, 13);
-       clks[IMX6SL_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
-
-       clks[IMX6SL_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
-       clks[IMX6SL_CLK_LVDS1_OUT] = imx_clk_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x160, 10, BIT(12));
-       clks[IMX6SL_CLK_LVDS1_IN] = imx_clk_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10));
+       clk_set_parent(hws[IMX6SL_PLL1_BYPASS]->clk, hws[IMX6SL_CLK_PLL1]->clk);
+       clk_set_parent(hws[IMX6SL_PLL2_BYPASS]->clk, hws[IMX6SL_CLK_PLL2]->clk);
+       clk_set_parent(hws[IMX6SL_PLL3_BYPASS]->clk, hws[IMX6SL_CLK_PLL3]->clk);
+       clk_set_parent(hws[IMX6SL_PLL4_BYPASS]->clk, hws[IMX6SL_CLK_PLL4]->clk);
+       clk_set_parent(hws[IMX6SL_PLL5_BYPASS]->clk, hws[IMX6SL_CLK_PLL5]->clk);
+       clk_set_parent(hws[IMX6SL_PLL6_BYPASS]->clk, hws[IMX6SL_CLK_PLL6]->clk);
+       clk_set_parent(hws[IMX6SL_PLL7_BYPASS]->clk, hws[IMX6SL_CLK_PLL7]->clk);
+
+       hws[IMX6SL_CLK_PLL1_SYS]      = imx_clk_hw_gate("pll1_sys",      "pll1_bypass", base + 0x00, 13);
+       hws[IMX6SL_CLK_PLL2_BUS]      = imx_clk_hw_gate("pll2_bus",      "pll2_bypass", base + 0x30, 13);
+       hws[IMX6SL_CLK_PLL3_USB_OTG]  = imx_clk_hw_gate("pll3_usb_otg",  "pll3_bypass", base + 0x10, 13);
+       hws[IMX6SL_CLK_PLL4_AUDIO]    = imx_clk_hw_gate("pll4_audio",    "pll4_bypass", base + 0x70, 13);
+       hws[IMX6SL_CLK_PLL5_VIDEO]    = imx_clk_hw_gate("pll5_video",    "pll5_bypass", base + 0xa0, 13);
+       hws[IMX6SL_CLK_PLL6_ENET]     = imx_clk_hw_gate("pll6_enet",     "pll6_bypass", base + 0xe0, 13);
+       hws[IMX6SL_CLK_PLL7_USB_HOST] = imx_clk_hw_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
+
+       hws[IMX6SL_CLK_LVDS1_SEL] = imx_clk_hw_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
+       hws[IMX6SL_CLK_LVDS1_OUT] = imx_clk_hw_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x160, 10, BIT(12));
+       hws[IMX6SL_CLK_LVDS1_IN] = imx_clk_hw_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10));
 
        /*
         * usbphy1 and usbphy2 are implemented as dummy gates using reserve
@@ -255,32 +263,32 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
         * turned on during boot, and software will not need to control it
         * anymore after that.
         */
-       clks[IMX6SL_CLK_USBPHY1]      = imx_clk_gate("usbphy1",      "pll3_usb_otg",  base + 0x10, 20);
-       clks[IMX6SL_CLK_USBPHY2]      = imx_clk_gate("usbphy2",      "pll7_usb_host", base + 0x20, 20);
-       clks[IMX6SL_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy",         base + 0x10, 6);
-       clks[IMX6SL_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy",         base + 0x20, 6);
+       hws[IMX6SL_CLK_USBPHY1]      = imx_clk_hw_gate("usbphy1",      "pll3_usb_otg",  base + 0x10, 20);
+       hws[IMX6SL_CLK_USBPHY2]      = imx_clk_hw_gate("usbphy2",      "pll7_usb_host", base + 0x20, 20);
+       hws[IMX6SL_CLK_USBPHY1_GATE] = imx_clk_hw_gate("usbphy1_gate", "dummy",         base + 0x10, 6);
+       hws[IMX6SL_CLK_USBPHY2_GATE] = imx_clk_hw_gate("usbphy2_gate", "dummy",         base + 0x20, 6);
 
        /*                                                           dev   name              parent_name      flags                reg        shift width div: flags, div_table lock */
-       clks[IMX6SL_CLK_PLL4_POST_DIV]  = clk_register_divider_table(NULL, "pll4_post_div",  "pll4_audio",    CLK_SET_RATE_PARENT, base + 0x70,  19, 2,   0, post_div_table, &imx_ccm_lock);
-       clks[IMX6SL_CLK_PLL4_AUDIO_DIV] =       clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1,   0, &imx_ccm_lock);
-       clks[IMX6SL_CLK_PLL5_POST_DIV]  = clk_register_divider_table(NULL, "pll5_post_div",  "pll5_video",    CLK_SET_RATE_PARENT, base + 0xa0,  19, 2,   0, post_div_table, &imx_ccm_lock);
-       clks[IMX6SL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2,   0, video_div_table, &imx_ccm_lock);
-       clks[IMX6SL_CLK_ENET_REF]       = clk_register_divider_table(NULL, "enet_ref",       "pll6_enet",     0,                   base + 0xe0,  0,  2,   0, clk_enet_ref_table, &imx_ccm_lock);
+       hws[IMX6SL_CLK_PLL4_POST_DIV]  = clk_hw_register_divider_table(NULL, "pll4_post_div",  "pll4_audio",    CLK_SET_RATE_PARENT, base + 0x70,  19, 2,   0, post_div_table, &imx_ccm_lock);
+       hws[IMX6SL_CLK_PLL4_AUDIO_DIV] =       clk_hw_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1,   0, &imx_ccm_lock);
+       hws[IMX6SL_CLK_PLL5_POST_DIV]  = clk_hw_register_divider_table(NULL, "pll5_post_div",  "pll5_video",    CLK_SET_RATE_PARENT, base + 0xa0,  19, 2,   0, post_div_table, &imx_ccm_lock);
+       hws[IMX6SL_CLK_PLL5_VIDEO_DIV] = clk_hw_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2,   0, video_div_table, &imx_ccm_lock);
+       hws[IMX6SL_CLK_ENET_REF]       = clk_hw_register_divider_table(NULL, "enet_ref",       "pll6_enet",     0,                   base + 0xe0,  0,  2,   0, clk_enet_ref_table, &imx_ccm_lock);
 
        /*                                       name         parent_name     reg           idx */
-       clks[IMX6SL_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0", "pll2_bus",     base + 0x100, 0);
-       clks[IMX6SL_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1", "pll2_bus",     base + 0x100, 1);
-       clks[IMX6SL_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2", "pll2_bus",     base + 0x100, 2);
-       clks[IMX6SL_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0", "pll3_usb_otg", base + 0xf0,  0);
-       clks[IMX6SL_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1", "pll3_usb_otg", base + 0xf0,  1);
-       clks[IMX6SL_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2", "pll3_usb_otg", base + 0xf0,  2);
-       clks[IMX6SL_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3", "pll3_usb_otg", base + 0xf0,  3);
+       hws[IMX6SL_CLK_PLL2_PFD0] = imx_clk_hw_pfd("pll2_pfd0", "pll2_bus",     base + 0x100, 0);
+       hws[IMX6SL_CLK_PLL2_PFD1] = imx_clk_hw_pfd("pll2_pfd1", "pll2_bus",     base + 0x100, 1);
+       hws[IMX6SL_CLK_PLL2_PFD2] = imx_clk_hw_pfd("pll2_pfd2", "pll2_bus",     base + 0x100, 2);
+       hws[IMX6SL_CLK_PLL3_PFD0] = imx_clk_hw_pfd("pll3_pfd0", "pll3_usb_otg", base + 0xf0,  0);
+       hws[IMX6SL_CLK_PLL3_PFD1] = imx_clk_hw_pfd("pll3_pfd1", "pll3_usb_otg", base + 0xf0,  1);
+       hws[IMX6SL_CLK_PLL3_PFD2] = imx_clk_hw_pfd("pll3_pfd2", "pll3_usb_otg", base + 0xf0,  2);
+       hws[IMX6SL_CLK_PLL3_PFD3] = imx_clk_hw_pfd("pll3_pfd3", "pll3_usb_otg", base + 0xf0,  3);
 
        /*                                                name         parent_name     mult div */
-       clks[IMX6SL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2",      1, 2);
-       clks[IMX6SL_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg",   1, 4);
-       clks[IMX6SL_CLK_PLL3_80M]  = imx_clk_fixed_factor("pll3_80m",  "pll3_usb_otg",   1, 6);
-       clks[IMX6SL_CLK_PLL3_60M]  = imx_clk_fixed_factor("pll3_60m",  "pll3_usb_otg",   1, 8);
+       hws[IMX6SL_CLK_PLL2_198M] = imx_clk_hw_fixed_factor("pll2_198m", "pll2_pfd2",      1, 2);
+       hws[IMX6SL_CLK_PLL3_120M] = imx_clk_hw_fixed_factor("pll3_120m", "pll3_usb_otg",   1, 4);
+       hws[IMX6SL_CLK_PLL3_80M]  = imx_clk_hw_fixed_factor("pll3_80m",  "pll3_usb_otg",   1, 6);
+       hws[IMX6SL_CLK_PLL3_60M]  = imx_clk_hw_fixed_factor("pll3_60m",  "pll3_usb_otg",   1, 8);
 
        np = ccm_node;
        base = of_iomap(np, 0);
@@ -288,157 +296,160 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
        ccm_base = base;
 
        /*                                              name                reg       shift width parent_names     num_parents */
-       clks[IMX6SL_CLK_STEP]             = imx_clk_mux("step",             base + 0xc,  8,  1, step_sels,         ARRAY_SIZE(step_sels));
-       clks[IMX6SL_CLK_PLL1_SW]          = imx_clk_mux("pll1_sw",          base + 0xc,  2,  1, pll1_sw_sels,      ARRAY_SIZE(pll1_sw_sels));
-       clks[IMX6SL_CLK_OCRAM_ALT_SEL]    = imx_clk_mux("ocram_alt_sel",    base + 0x14, 7,  1, ocram_alt_sels,    ARRAY_SIZE(ocram_alt_sels));
-       clks[IMX6SL_CLK_OCRAM_SEL]        = imx_clk_mux("ocram_sel",        base + 0x14, 6,  1, ocram_sels,        ARRAY_SIZE(ocram_sels));
-       clks[IMX6SL_CLK_PRE_PERIPH2_SEL]  = imx_clk_mux("pre_periph2_sel",  base + 0x18, 21, 2, pre_periph_sels,   ARRAY_SIZE(pre_periph_sels));
-       clks[IMX6SL_CLK_PRE_PERIPH_SEL]   = imx_clk_mux("pre_periph_sel",   base + 0x18, 18, 2, pre_periph_sels,   ARRAY_SIZE(pre_periph_sels));
-       clks[IMX6SL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
-       clks[IMX6SL_CLK_PERIPH_CLK2_SEL]  = imx_clk_mux("periph_clk2_sel",  base + 0x18, 12, 2, periph_clk2_sels,  ARRAY_SIZE(periph_clk2_sels));
-       clks[IMX6SL_CLK_CSI_SEL]          = imx_clk_mux("csi_sel",          base + 0x3c, 9,  2, csi_sels,          ARRAY_SIZE(csi_sels));
-       clks[IMX6SL_CLK_LCDIF_AXI_SEL]    = imx_clk_mux("lcdif_axi_sel",    base + 0x3c, 14, 2, lcdif_axi_sels,    ARRAY_SIZE(lcdif_axi_sels));
-       clks[IMX6SL_CLK_USDHC1_SEL]       = imx_clk_fixup_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels),  imx_cscmr1_fixup);
-       clks[IMX6SL_CLK_USDHC2_SEL]       = imx_clk_fixup_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels),  imx_cscmr1_fixup);
-       clks[IMX6SL_CLK_USDHC3_SEL]       = imx_clk_fixup_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels),  imx_cscmr1_fixup);
-       clks[IMX6SL_CLK_USDHC4_SEL]       = imx_clk_fixup_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels),  imx_cscmr1_fixup);
-       clks[IMX6SL_CLK_SSI1_SEL]         = imx_clk_fixup_mux("ssi1_sel",   base + 0x1c, 10, 2, ssi_sels,          ARRAY_SIZE(ssi_sels),    imx_cscmr1_fixup);
-       clks[IMX6SL_CLK_SSI2_SEL]         = imx_clk_fixup_mux("ssi2_sel",   base + 0x1c, 12, 2, ssi_sels,          ARRAY_SIZE(ssi_sels),    imx_cscmr1_fixup);
-       clks[IMX6SL_CLK_SSI3_SEL]         = imx_clk_fixup_mux("ssi3_sel",   base + 0x1c, 14, 2, ssi_sels,          ARRAY_SIZE(ssi_sels),    imx_cscmr1_fixup);
-       clks[IMX6SL_CLK_PERCLK_SEL]       = imx_clk_fixup_mux("perclk_sel", base + 0x1c, 6,  1, perclk_sels,       ARRAY_SIZE(perclk_sels), imx_cscmr1_fixup);
-       clks[IMX6SL_CLK_PXP_AXI_SEL]      = imx_clk_mux("pxp_axi_sel",      base + 0x34, 6,  3, pxp_axi_sels,      ARRAY_SIZE(pxp_axi_sels));
-       clks[IMX6SL_CLK_EPDC_AXI_SEL]     = imx_clk_mux("epdc_axi_sel",     base + 0x34, 15, 3, epdc_axi_sels,     ARRAY_SIZE(epdc_axi_sels));
-       clks[IMX6SL_CLK_GPU2D_OVG_SEL]    = imx_clk_mux("gpu2d_ovg_sel",    base + 0x18, 4,  2, gpu2d_ovg_sels,    ARRAY_SIZE(gpu2d_ovg_sels));
-       clks[IMX6SL_CLK_GPU2D_SEL]        = imx_clk_mux("gpu2d_sel",        base + 0x18, 8,  2, gpu2d_sels,        ARRAY_SIZE(gpu2d_sels));
-       clks[IMX6SL_CLK_LCDIF_PIX_SEL]    = imx_clk_mux("lcdif_pix_sel",    base + 0x38, 6,  3, lcdif_pix_sels,    ARRAY_SIZE(lcdif_pix_sels));
-       clks[IMX6SL_CLK_EPDC_PIX_SEL]     = imx_clk_mux("epdc_pix_sel",     base + 0x38, 15, 3, epdc_pix_sels,     ARRAY_SIZE(epdc_pix_sels));
-       clks[IMX6SL_CLK_SPDIF0_SEL]       = imx_clk_mux("spdif0_sel",       base + 0x30, 20, 2, audio_sels,        ARRAY_SIZE(audio_sels));
-       clks[IMX6SL_CLK_SPDIF1_SEL]       = imx_clk_mux("spdif1_sel",       base + 0x30, 7,  2, audio_sels,        ARRAY_SIZE(audio_sels));
-       clks[IMX6SL_CLK_EXTERN_AUDIO_SEL] = imx_clk_mux("extern_audio_sel", base + 0x20, 19, 2, audio_sels,        ARRAY_SIZE(audio_sels));
-       clks[IMX6SL_CLK_ECSPI_SEL]        = imx_clk_mux("ecspi_sel",        base + 0x38, 18, 1, ecspi_sels,        ARRAY_SIZE(ecspi_sels));
-       clks[IMX6SL_CLK_UART_SEL]         = imx_clk_mux("uart_sel",         base + 0x24, 6,  1, uart_sels,         ARRAY_SIZE(uart_sels));
+       hws[IMX6SL_CLK_STEP]             = imx_clk_hw_mux("step",             base + 0xc,  8,  1, step_sels,         ARRAY_SIZE(step_sels));
+       hws[IMX6SL_CLK_PLL1_SW]          = imx_clk_hw_mux("pll1_sw",          base + 0xc,  2,  1, pll1_sw_sels,      ARRAY_SIZE(pll1_sw_sels));
+       hws[IMX6SL_CLK_OCRAM_ALT_SEL]    = imx_clk_hw_mux("ocram_alt_sel",    base + 0x14, 7,  1, ocram_alt_sels,    ARRAY_SIZE(ocram_alt_sels));
+       hws[IMX6SL_CLK_OCRAM_SEL]        = imx_clk_hw_mux("ocram_sel",        base + 0x14, 6,  1, ocram_sels,        ARRAY_SIZE(ocram_sels));
+       hws[IMX6SL_CLK_PRE_PERIPH2_SEL]  = imx_clk_hw_mux("pre_periph2_sel",  base + 0x18, 21, 2, pre_periph_sels,   ARRAY_SIZE(pre_periph_sels));
+       hws[IMX6SL_CLK_PRE_PERIPH_SEL]   = imx_clk_hw_mux("pre_periph_sel",   base + 0x18, 18, 2, pre_periph_sels,   ARRAY_SIZE(pre_periph_sels));
+       hws[IMX6SL_CLK_PERIPH2_CLK2_SEL] = imx_clk_hw_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
+       hws[IMX6SL_CLK_PERIPH_CLK2_SEL]  = imx_clk_hw_mux("periph_clk2_sel",  base + 0x18, 12, 2, periph_clk2_sels,  ARRAY_SIZE(periph_clk2_sels));
+       hws[IMX6SL_CLK_CSI_SEL]          = imx_clk_hw_mux("csi_sel",          base + 0x3c, 9,  2, csi_sels,          ARRAY_SIZE(csi_sels));
+       hws[IMX6SL_CLK_LCDIF_AXI_SEL]    = imx_clk_hw_mux("lcdif_axi_sel",    base + 0x3c, 14, 2, lcdif_axi_sels,    ARRAY_SIZE(lcdif_axi_sels));
+       hws[IMX6SL_CLK_USDHC1_SEL]       = imx_clk_hw_fixup_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels),  imx_cscmr1_fixup);
+       hws[IMX6SL_CLK_USDHC2_SEL]       = imx_clk_hw_fixup_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels),  imx_cscmr1_fixup);
+       hws[IMX6SL_CLK_USDHC3_SEL]       = imx_clk_hw_fixup_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels),  imx_cscmr1_fixup);
+       hws[IMX6SL_CLK_USDHC4_SEL]       = imx_clk_hw_fixup_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels),  imx_cscmr1_fixup);
+       hws[IMX6SL_CLK_SSI1_SEL]         = imx_clk_hw_fixup_mux("ssi1_sel",   base + 0x1c, 10, 2, ssi_sels,          ARRAY_SIZE(ssi_sels),    imx_cscmr1_fixup);
+       hws[IMX6SL_CLK_SSI2_SEL]         = imx_clk_hw_fixup_mux("ssi2_sel",   base + 0x1c, 12, 2, ssi_sels,          ARRAY_SIZE(ssi_sels),    imx_cscmr1_fixup);
+       hws[IMX6SL_CLK_SSI3_SEL]         = imx_clk_hw_fixup_mux("ssi3_sel",   base + 0x1c, 14, 2, ssi_sels,          ARRAY_SIZE(ssi_sels),    imx_cscmr1_fixup);
+       hws[IMX6SL_CLK_PERCLK_SEL]       = imx_clk_hw_fixup_mux("perclk_sel", base + 0x1c, 6,  1, perclk_sels,       ARRAY_SIZE(perclk_sels), imx_cscmr1_fixup);
+       hws[IMX6SL_CLK_PXP_AXI_SEL]      = imx_clk_hw_mux("pxp_axi_sel",      base + 0x34, 6,  3, pxp_axi_sels,      ARRAY_SIZE(pxp_axi_sels));
+       hws[IMX6SL_CLK_EPDC_AXI_SEL]     = imx_clk_hw_mux("epdc_axi_sel",     base + 0x34, 15, 3, epdc_axi_sels,     ARRAY_SIZE(epdc_axi_sels));
+       hws[IMX6SL_CLK_GPU2D_OVG_SEL]    = imx_clk_hw_mux("gpu2d_ovg_sel",    base + 0x18, 4,  2, gpu2d_ovg_sels,    ARRAY_SIZE(gpu2d_ovg_sels));
+       hws[IMX6SL_CLK_GPU2D_SEL]        = imx_clk_hw_mux("gpu2d_sel",        base + 0x18, 8,  2, gpu2d_sels,        ARRAY_SIZE(gpu2d_sels));
+       hws[IMX6SL_CLK_LCDIF_PIX_SEL]    = imx_clk_hw_mux("lcdif_pix_sel",    base + 0x38, 6,  3, lcdif_pix_sels,    ARRAY_SIZE(lcdif_pix_sels));
+       hws[IMX6SL_CLK_EPDC_PIX_SEL]     = imx_clk_hw_mux("epdc_pix_sel",     base + 0x38, 15, 3, epdc_pix_sels,     ARRAY_SIZE(epdc_pix_sels));
+       hws[IMX6SL_CLK_SPDIF0_SEL]       = imx_clk_hw_mux("spdif0_sel",       base + 0x30, 20, 2, audio_sels,        ARRAY_SIZE(audio_sels));
+       hws[IMX6SL_CLK_SPDIF1_SEL]       = imx_clk_hw_mux("spdif1_sel",       base + 0x30, 7,  2, audio_sels,        ARRAY_SIZE(audio_sels));
+       hws[IMX6SL_CLK_EXTERN_AUDIO_SEL] = imx_clk_hw_mux("extern_audio_sel", base + 0x20, 19, 2, audio_sels,        ARRAY_SIZE(audio_sels));
+       hws[IMX6SL_CLK_ECSPI_SEL]        = imx_clk_hw_mux("ecspi_sel",        base + 0x38, 18, 1, ecspi_sels,        ARRAY_SIZE(ecspi_sels));
+       hws[IMX6SL_CLK_UART_SEL]         = imx_clk_hw_mux("uart_sel",         base + 0x24, 6,  1, uart_sels,         ARRAY_SIZE(uart_sels));
 
        /*                                          name       reg        shift width busy: reg, shift parent_names  num_parents */
-       clks[IMX6SL_CLK_PERIPH]  = imx_clk_busy_mux("periph",  base + 0x14, 25,  1,   base + 0x48, 5,  periph_sels,  ARRAY_SIZE(periph_sels));
-       clks[IMX6SL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26,  1,   base + 0x48, 3,  periph2_sels, ARRAY_SIZE(periph2_sels));
+       hws[IMX6SL_CLK_PERIPH]  = imx_clk_hw_busy_mux("periph",  base + 0x14, 25,  1,   base + 0x48, 5,  periph_sels,  ARRAY_SIZE(periph_sels));
+       hws[IMX6SL_CLK_PERIPH2] = imx_clk_hw_busy_mux("periph2", base + 0x14, 26,  1,   base + 0x48, 3,  periph2_sels, ARRAY_SIZE(periph2_sels));
 
        /*                                                   name                 parent_name          reg       shift width */
-       clks[IMX6SL_CLK_OCRAM_PODF]        = imx_clk_busy_divider("ocram_podf",   "ocram_sel",         base + 0x14, 16, 3, base + 0x48, 0);
-       clks[IMX6SL_CLK_PERIPH_CLK2_PODF]  = imx_clk_divider("periph_clk2_podf",  "periph_clk2_sel",   base + 0x14, 27, 3);
-       clks[IMX6SL_CLK_PERIPH2_CLK2_PODF] = imx_clk_divider("periph2_clk2_podf", "periph2_clk2_sel",  base + 0x14, 0,  3);
-       clks[IMX6SL_CLK_IPG]               = imx_clk_divider("ipg",               "ahb",               base + 0x14, 8,  2);
-       clks[IMX6SL_CLK_CSI_PODF]          = imx_clk_divider("csi_podf",          "csi_sel",           base + 0x3c, 11, 3);
-       clks[IMX6SL_CLK_LCDIF_AXI_PODF]    = imx_clk_divider("lcdif_axi_podf",    "lcdif_axi_sel",     base + 0x3c, 16, 3);
-       clks[IMX6SL_CLK_USDHC1_PODF]       = imx_clk_divider("usdhc1_podf",       "usdhc1_sel",        base + 0x24, 11, 3);
-       clks[IMX6SL_CLK_USDHC2_PODF]       = imx_clk_divider("usdhc2_podf",       "usdhc2_sel",        base + 0x24, 16, 3);
-       clks[IMX6SL_CLK_USDHC3_PODF]       = imx_clk_divider("usdhc3_podf",       "usdhc3_sel",        base + 0x24, 19, 3);
-       clks[IMX6SL_CLK_USDHC4_PODF]       = imx_clk_divider("usdhc4_podf",       "usdhc4_sel",        base + 0x24, 22, 3);
-       clks[IMX6SL_CLK_SSI1_PRED]         = imx_clk_divider("ssi1_pred",         "ssi1_sel",          base + 0x28, 6,  3);
-       clks[IMX6SL_CLK_SSI1_PODF]         = imx_clk_divider("ssi1_podf",         "ssi1_pred",         base + 0x28, 0,  6);
-       clks[IMX6SL_CLK_SSI2_PRED]         = imx_clk_divider("ssi2_pred",         "ssi2_sel",          base + 0x2c, 6,  3);
-       clks[IMX6SL_CLK_SSI2_PODF]         = imx_clk_divider("ssi2_podf",         "ssi2_pred",         base + 0x2c, 0,  6);
-       clks[IMX6SL_CLK_SSI3_PRED]         = imx_clk_divider("ssi3_pred",         "ssi3_sel",          base + 0x28, 22, 3);
-       clks[IMX6SL_CLK_SSI3_PODF]         = imx_clk_divider("ssi3_podf",         "ssi3_pred",         base + 0x28, 16, 6);
-       clks[IMX6SL_CLK_PERCLK]            = imx_clk_fixup_divider("perclk",      "perclk_sel",        base + 0x1c, 0,  6, imx_cscmr1_fixup);
-       clks[IMX6SL_CLK_PXP_AXI_PODF]      = imx_clk_divider("pxp_axi_podf",      "pxp_axi_sel",       base + 0x34, 3,  3);
-       clks[IMX6SL_CLK_EPDC_AXI_PODF]     = imx_clk_divider("epdc_axi_podf",     "epdc_axi_sel",      base + 0x34, 12, 3);
-       clks[IMX6SL_CLK_GPU2D_OVG_PODF]    = imx_clk_divider("gpu2d_ovg_podf",    "gpu2d_ovg_sel",     base + 0x18, 26, 3);
-       clks[IMX6SL_CLK_GPU2D_PODF]        = imx_clk_divider("gpu2d_podf",        "gpu2d_sel",         base + 0x18, 29, 3);
-       clks[IMX6SL_CLK_LCDIF_PIX_PRED]    = imx_clk_divider("lcdif_pix_pred",    "lcdif_pix_sel",     base + 0x38, 3,  3);
-       clks[IMX6SL_CLK_EPDC_PIX_PRED]     = imx_clk_divider("epdc_pix_pred",     "epdc_pix_sel",      base + 0x38, 12, 3);
-       clks[IMX6SL_CLK_LCDIF_PIX_PODF]    = imx_clk_fixup_divider("lcdif_pix_podf", "lcdif_pix_pred", base + 0x1c, 20, 3, imx_cscmr1_fixup);
-       clks[IMX6SL_CLK_EPDC_PIX_PODF]     = imx_clk_divider("epdc_pix_podf",     "epdc_pix_pred",     base + 0x18, 23, 3);
-       clks[IMX6SL_CLK_SPDIF0_PRED]       = imx_clk_divider("spdif0_pred",       "spdif0_sel",        base + 0x30, 25, 3);
-       clks[IMX6SL_CLK_SPDIF0_PODF]       = imx_clk_divider("spdif0_podf",       "spdif0_pred",       base + 0x30, 22, 3);
-       clks[IMX6SL_CLK_SPDIF1_PRED]       = imx_clk_divider("spdif1_pred",       "spdif1_sel",        base + 0x30, 12, 3);
-       clks[IMX6SL_CLK_SPDIF1_PODF]       = imx_clk_divider("spdif1_podf",       "spdif1_pred",       base + 0x30, 9,  3);
-       clks[IMX6SL_CLK_EXTERN_AUDIO_PRED] = imx_clk_divider("extern_audio_pred", "extern_audio_sel",  base + 0x28, 9,  3);
-       clks[IMX6SL_CLK_EXTERN_AUDIO_PODF] = imx_clk_divider("extern_audio_podf", "extern_audio_pred", base + 0x28, 25, 3);
-       clks[IMX6SL_CLK_ECSPI_ROOT]        = imx_clk_divider("ecspi_root",        "ecspi_sel",         base + 0x38, 19, 6);
-       clks[IMX6SL_CLK_UART_ROOT]         = imx_clk_divider("uart_root",         "uart_sel",          base + 0x24, 0,  6);
+       hws[IMX6SL_CLK_OCRAM_PODF]        = imx_clk_hw_busy_divider("ocram_podf",   "ocram_sel",         base + 0x14, 16, 3, base + 0x48, 0);
+       hws[IMX6SL_CLK_PERIPH_CLK2_PODF]  = imx_clk_hw_divider("periph_clk2_podf",  "periph_clk2_sel",   base + 0x14, 27, 3);
+       hws[IMX6SL_CLK_PERIPH2_CLK2_PODF] = imx_clk_hw_divider("periph2_clk2_podf", "periph2_clk2_sel",  base + 0x14, 0,  3);
+       hws[IMX6SL_CLK_IPG]               = imx_clk_hw_divider("ipg",               "ahb",               base + 0x14, 8,  2);
+       hws[IMX6SL_CLK_CSI_PODF]          = imx_clk_hw_divider("csi_podf",          "csi_sel",           base + 0x3c, 11, 3);
+       hws[IMX6SL_CLK_LCDIF_AXI_PODF]    = imx_clk_hw_divider("lcdif_axi_podf",    "lcdif_axi_sel",     base + 0x3c, 16, 3);
+       hws[IMX6SL_CLK_USDHC1_PODF]       = imx_clk_hw_divider("usdhc1_podf",       "usdhc1_sel",        base + 0x24, 11, 3);
+       hws[IMX6SL_CLK_USDHC2_PODF]       = imx_clk_hw_divider("usdhc2_podf",       "usdhc2_sel",        base + 0x24, 16, 3);
+       hws[IMX6SL_CLK_USDHC3_PODF]       = imx_clk_hw_divider("usdhc3_podf",       "usdhc3_sel",        base + 0x24, 19, 3);
+       hws[IMX6SL_CLK_USDHC4_PODF]       = imx_clk_hw_divider("usdhc4_podf",       "usdhc4_sel",        base + 0x24, 22, 3);
+       hws[IMX6SL_CLK_SSI1_PRED]         = imx_clk_hw_divider("ssi1_pred",         "ssi1_sel",          base + 0x28, 6,  3);
+       hws[IMX6SL_CLK_SSI1_PODF]         = imx_clk_hw_divider("ssi1_podf",         "ssi1_pred",         base + 0x28, 0,  6);
+       hws[IMX6SL_CLK_SSI2_PRED]         = imx_clk_hw_divider("ssi2_pred",         "ssi2_sel",          base + 0x2c, 6,  3);
+       hws[IMX6SL_CLK_SSI2_PODF]         = imx_clk_hw_divider("ssi2_podf",         "ssi2_pred",         base + 0x2c, 0,  6);
+       hws[IMX6SL_CLK_SSI3_PRED]         = imx_clk_hw_divider("ssi3_pred",         "ssi3_sel",          base + 0x28, 22, 3);
+       hws[IMX6SL_CLK_SSI3_PODF]         = imx_clk_hw_divider("ssi3_podf",         "ssi3_pred",         base + 0x28, 16, 6);
+       hws[IMX6SL_CLK_PERCLK]            = imx_clk_hw_fixup_divider("perclk",      "perclk_sel",        base + 0x1c, 0,  6, imx_cscmr1_fixup);
+       hws[IMX6SL_CLK_PXP_AXI_PODF]      = imx_clk_hw_divider("pxp_axi_podf",      "pxp_axi_sel",       base + 0x34, 3,  3);
+       hws[IMX6SL_CLK_EPDC_AXI_PODF]     = imx_clk_hw_divider("epdc_axi_podf",     "epdc_axi_sel",      base + 0x34, 12, 3);
+       hws[IMX6SL_CLK_GPU2D_OVG_PODF]    = imx_clk_hw_divider("gpu2d_ovg_podf",    "gpu2d_ovg_sel",     base + 0x18, 26, 3);
+       hws[IMX6SL_CLK_GPU2D_PODF]        = imx_clk_hw_divider("gpu2d_podf",        "gpu2d_sel",         base + 0x18, 29, 3);
+       hws[IMX6SL_CLK_LCDIF_PIX_PRED]    = imx_clk_hw_divider("lcdif_pix_pred",    "lcdif_pix_sel",     base + 0x38, 3,  3);
+       hws[IMX6SL_CLK_EPDC_PIX_PRED]     = imx_clk_hw_divider("epdc_pix_pred",     "epdc_pix_sel",      base + 0x38, 12, 3);
+       hws[IMX6SL_CLK_LCDIF_PIX_PODF]    = imx_clk_hw_fixup_divider("lcdif_pix_podf", "lcdif_pix_pred", base + 0x1c, 20, 3, imx_cscmr1_fixup);
+       hws[IMX6SL_CLK_EPDC_PIX_PODF]     = imx_clk_hw_divider("epdc_pix_podf",     "epdc_pix_pred",     base + 0x18, 23, 3);
+       hws[IMX6SL_CLK_SPDIF0_PRED]       = imx_clk_hw_divider("spdif0_pred",       "spdif0_sel",        base + 0x30, 25, 3);
+       hws[IMX6SL_CLK_SPDIF0_PODF]       = imx_clk_hw_divider("spdif0_podf",       "spdif0_pred",       base + 0x30, 22, 3);
+       hws[IMX6SL_CLK_SPDIF1_PRED]       = imx_clk_hw_divider("spdif1_pred",       "spdif1_sel",        base + 0x30, 12, 3);
+       hws[IMX6SL_CLK_SPDIF1_PODF]       = imx_clk_hw_divider("spdif1_podf",       "spdif1_pred",       base + 0x30, 9,  3);
+       hws[IMX6SL_CLK_EXTERN_AUDIO_PRED] = imx_clk_hw_divider("extern_audio_pred", "extern_audio_sel",  base + 0x28, 9,  3);
+       hws[IMX6SL_CLK_EXTERN_AUDIO_PODF] = imx_clk_hw_divider("extern_audio_podf", "extern_audio_pred", base + 0x28, 25, 3);
+       hws[IMX6SL_CLK_ECSPI_ROOT]        = imx_clk_hw_divider("ecspi_root",        "ecspi_sel",         base + 0x38, 19, 6);
+       hws[IMX6SL_CLK_UART_ROOT]         = imx_clk_hw_divider("uart_root",         "uart_sel",          base + 0x24, 0,  6);
 
        /*                                                name         parent_name reg       shift width busy: reg, shift */
-       clks[IMX6SL_CLK_AHB]       = imx_clk_busy_divider("ahb",       "periph",  base + 0x14, 10, 3,    base + 0x48, 1);
-       clks[IMX6SL_CLK_MMDC_ROOT] = imx_clk_busy_divider("mmdc",      "periph2", base + 0x14, 3,  3,    base + 0x48, 2);
-       clks[IMX6SL_CLK_ARM]       = imx_clk_busy_divider("arm",       "pll1_sw", base + 0x10, 0,  3,    base + 0x48, 16);
+       hws[IMX6SL_CLK_AHB]       = imx_clk_hw_busy_divider("ahb",       "periph",  base + 0x14, 10, 3,    base + 0x48, 1);
+       hws[IMX6SL_CLK_MMDC_ROOT] = imx_clk_hw_busy_divider("mmdc",      "periph2", base + 0x14, 3,  3,    base + 0x48, 2);
+       hws[IMX6SL_CLK_ARM]       = imx_clk_hw_busy_divider("arm",       "pll1_sw", base + 0x10, 0,  3,    base + 0x48, 16);
 
        /*                                            name            parent_name          reg         shift */
-       clks[IMX6SL_CLK_ECSPI1]       = imx_clk_gate2("ecspi1",       "ecspi_root",        base + 0x6c, 0);
-       clks[IMX6SL_CLK_ECSPI2]       = imx_clk_gate2("ecspi2",       "ecspi_root",        base + 0x6c, 2);
-       clks[IMX6SL_CLK_ECSPI3]       = imx_clk_gate2("ecspi3",       "ecspi_root",        base + 0x6c, 4);
-       clks[IMX6SL_CLK_ECSPI4]       = imx_clk_gate2("ecspi4",       "ecspi_root",        base + 0x6c, 6);
-       clks[IMX6SL_CLK_ENET]         = imx_clk_gate2("enet",         "ipg",               base + 0x6c, 10);
-       clks[IMX6SL_CLK_EPIT1]        = imx_clk_gate2("epit1",        "perclk",            base + 0x6c, 12);
-       clks[IMX6SL_CLK_EPIT2]        = imx_clk_gate2("epit2",        "perclk",            base + 0x6c, 14);
-       clks[IMX6SL_CLK_EXTERN_AUDIO] = imx_clk_gate2("extern_audio", "extern_audio_podf", base + 0x6c, 16);
-       clks[IMX6SL_CLK_GPT]          = imx_clk_gate2("gpt",          "perclk",            base + 0x6c, 20);
-       clks[IMX6SL_CLK_GPT_SERIAL]   = imx_clk_gate2("gpt_serial",   "perclk",            base + 0x6c, 22);
-       clks[IMX6SL_CLK_GPU2D_OVG]    = imx_clk_gate2("gpu2d_ovg",    "gpu2d_ovg_podf",    base + 0x6c, 26);
-       clks[IMX6SL_CLK_I2C1]         = imx_clk_gate2("i2c1",         "perclk",            base + 0x70, 6);
-       clks[IMX6SL_CLK_I2C2]         = imx_clk_gate2("i2c2",         "perclk",            base + 0x70, 8);
-       clks[IMX6SL_CLK_I2C3]         = imx_clk_gate2("i2c3",         "perclk",            base + 0x70, 10);
-       clks[IMX6SL_CLK_OCOTP]        = imx_clk_gate2("ocotp",        "ipg",               base + 0x70, 12);
-       clks[IMX6SL_CLK_CSI]          = imx_clk_gate2("csi",          "csi_podf",          base + 0x74, 0);
-       clks[IMX6SL_CLK_PXP_AXI]      = imx_clk_gate2("pxp_axi",      "pxp_axi_podf",      base + 0x74, 2);
-       clks[IMX6SL_CLK_EPDC_AXI]     = imx_clk_gate2("epdc_axi",     "epdc_axi_podf",     base + 0x74, 4);
-       clks[IMX6SL_CLK_LCDIF_AXI]    = imx_clk_gate2("lcdif_axi",    "lcdif_axi_podf",    base + 0x74, 6);
-       clks[IMX6SL_CLK_LCDIF_PIX]    = imx_clk_gate2("lcdif_pix",    "lcdif_pix_podf",    base + 0x74, 8);
-       clks[IMX6SL_CLK_EPDC_PIX]     = imx_clk_gate2("epdc_pix",     "epdc_pix_podf",     base + 0x74, 10);
-       clks[IMX6SL_CLK_MMDC_P0_IPG]  = imx_clk_gate2_flags("mmdc_p0_ipg",  "ipg",         base + 0x74, 24, CLK_IS_CRITICAL);
-       clks[IMX6SL_CLK_MMDC_P1_IPG]  = imx_clk_gate2("mmdc_p1_ipg",  "ipg",               base + 0x74, 26);
-       clks[IMX6SL_CLK_OCRAM]        = imx_clk_gate2("ocram",        "ocram_podf",        base + 0x74, 28);
-       clks[IMX6SL_CLK_PWM1]         = imx_clk_gate2("pwm1",         "perclk",            base + 0x78, 16);
-       clks[IMX6SL_CLK_PWM2]         = imx_clk_gate2("pwm2",         "perclk",            base + 0x78, 18);
-       clks[IMX6SL_CLK_PWM3]         = imx_clk_gate2("pwm3",         "perclk",            base + 0x78, 20);
-       clks[IMX6SL_CLK_PWM4]         = imx_clk_gate2("pwm4",         "perclk",            base + 0x78, 22);
-       clks[IMX6SL_CLK_SDMA]         = imx_clk_gate2("sdma",         "ipg",               base + 0x7c, 6);
-       clks[IMX6SL_CLK_SPBA]         = imx_clk_gate2("spba",         "ipg",               base + 0x7c, 12);
-       clks[IMX6SL_CLK_SPDIF]        = imx_clk_gate2_shared("spdif",     "spdif0_podf",   base + 0x7c, 14, &share_count_spdif);
-       clks[IMX6SL_CLK_SPDIF_GCLK]   = imx_clk_gate2_shared("spdif_gclk",  "ipg",         base + 0x7c, 14, &share_count_spdif);
-       clks[IMX6SL_CLK_SSI1_IPG]     = imx_clk_gate2_shared("ssi1_ipg",     "ipg",        base + 0x7c, 18, &share_count_ssi1);
-       clks[IMX6SL_CLK_SSI2_IPG]     = imx_clk_gate2_shared("ssi2_ipg",     "ipg",        base + 0x7c, 20, &share_count_ssi2);
-       clks[IMX6SL_CLK_SSI3_IPG]     = imx_clk_gate2_shared("ssi3_ipg",     "ipg",        base + 0x7c, 22, &share_count_ssi3);
-       clks[IMX6SL_CLK_SSI1]         = imx_clk_gate2_shared("ssi1",         "ssi1_podf",  base + 0x7c, 18, &share_count_ssi1);
-       clks[IMX6SL_CLK_SSI2]         = imx_clk_gate2_shared("ssi2",         "ssi2_podf",  base + 0x7c, 20, &share_count_ssi2);
-       clks[IMX6SL_CLK_SSI3]         = imx_clk_gate2_shared("ssi3",         "ssi3_podf",  base + 0x7c, 22, &share_count_ssi3);
-       clks[IMX6SL_CLK_UART]         = imx_clk_gate2("uart",         "ipg",               base + 0x7c, 24);
-       clks[IMX6SL_CLK_UART_SERIAL]  = imx_clk_gate2("uart_serial",  "uart_root",         base + 0x7c, 26);
-       clks[IMX6SL_CLK_USBOH3]       = imx_clk_gate2("usboh3",       "ipg",               base + 0x80, 0);
-       clks[IMX6SL_CLK_USDHC1]       = imx_clk_gate2("usdhc1",       "usdhc1_podf",       base + 0x80, 2);
-       clks[IMX6SL_CLK_USDHC2]       = imx_clk_gate2("usdhc2",       "usdhc2_podf",       base + 0x80, 4);
-       clks[IMX6SL_CLK_USDHC3]       = imx_clk_gate2("usdhc3",       "usdhc3_podf",       base + 0x80, 6);
-       clks[IMX6SL_CLK_USDHC4]       = imx_clk_gate2("usdhc4",       "usdhc4_podf",       base + 0x80, 8);
+       hws[IMX6SL_CLK_ECSPI1]       = imx_clk_hw_gate2("ecspi1",       "ecspi_root",        base + 0x6c, 0);
+       hws[IMX6SL_CLK_ECSPI2]       = imx_clk_hw_gate2("ecspi2",       "ecspi_root",        base + 0x6c, 2);
+       hws[IMX6SL_CLK_ECSPI3]       = imx_clk_hw_gate2("ecspi3",       "ecspi_root",        base + 0x6c, 4);
+       hws[IMX6SL_CLK_ECSPI4]       = imx_clk_hw_gate2("ecspi4",       "ecspi_root",        base + 0x6c, 6);
+       hws[IMX6SL_CLK_ENET]         = imx_clk_hw_gate2("enet",         "ipg",               base + 0x6c, 10);
+       hws[IMX6SL_CLK_EPIT1]        = imx_clk_hw_gate2("epit1",        "perclk",            base + 0x6c, 12);
+       hws[IMX6SL_CLK_EPIT2]        = imx_clk_hw_gate2("epit2",        "perclk",            base + 0x6c, 14);
+       hws[IMX6SL_CLK_EXTERN_AUDIO] = imx_clk_hw_gate2("extern_audio", "extern_audio_podf", base + 0x6c, 16);
+       hws[IMX6SL_CLK_GPT]          = imx_clk_hw_gate2("gpt",          "perclk",            base + 0x6c, 20);
+       hws[IMX6SL_CLK_GPT_SERIAL]   = imx_clk_hw_gate2("gpt_serial",   "perclk",            base + 0x6c, 22);
+       hws[IMX6SL_CLK_GPU2D_OVG]    = imx_clk_hw_gate2("gpu2d_ovg",    "gpu2d_ovg_podf",    base + 0x6c, 26);
+       hws[IMX6SL_CLK_I2C1]         = imx_clk_hw_gate2("i2c1",         "perclk",            base + 0x70, 6);
+       hws[IMX6SL_CLK_I2C2]         = imx_clk_hw_gate2("i2c2",         "perclk",            base + 0x70, 8);
+       hws[IMX6SL_CLK_I2C3]         = imx_clk_hw_gate2("i2c3",         "perclk",            base + 0x70, 10);
+       hws[IMX6SL_CLK_OCOTP]        = imx_clk_hw_gate2("ocotp",        "ipg",               base + 0x70, 12);
+       hws[IMX6SL_CLK_CSI]          = imx_clk_hw_gate2("csi",          "csi_podf",          base + 0x74, 0);
+       hws[IMX6SL_CLK_PXP_AXI]      = imx_clk_hw_gate2("pxp_axi",      "pxp_axi_podf",      base + 0x74, 2);
+       hws[IMX6SL_CLK_EPDC_AXI]     = imx_clk_hw_gate2("epdc_axi",     "epdc_axi_podf",     base + 0x74, 4);
+       hws[IMX6SL_CLK_LCDIF_AXI]    = imx_clk_hw_gate2("lcdif_axi",    "lcdif_axi_podf",    base + 0x74, 6);
+       hws[IMX6SL_CLK_LCDIF_PIX]    = imx_clk_hw_gate2("lcdif_pix",    "lcdif_pix_podf",    base + 0x74, 8);
+       hws[IMX6SL_CLK_EPDC_PIX]     = imx_clk_hw_gate2("epdc_pix",     "epdc_pix_podf",     base + 0x74, 10);
+       hws[IMX6SL_CLK_MMDC_P0_IPG]  = imx_clk_hw_gate2_flags("mmdc_p0_ipg",  "ipg",         base + 0x74, 24, CLK_IS_CRITICAL);
+       hws[IMX6SL_CLK_MMDC_P1_IPG]  = imx_clk_hw_gate2("mmdc_p1_ipg",  "ipg",               base + 0x74, 26);
+       hws[IMX6SL_CLK_OCRAM]        = imx_clk_hw_gate2("ocram",        "ocram_podf",        base + 0x74, 28);
+       hws[IMX6SL_CLK_PWM1]         = imx_clk_hw_gate2("pwm1",         "perclk",            base + 0x78, 16);
+       hws[IMX6SL_CLK_PWM2]         = imx_clk_hw_gate2("pwm2",         "perclk",            base + 0x78, 18);
+       hws[IMX6SL_CLK_PWM3]         = imx_clk_hw_gate2("pwm3",         "perclk",            base + 0x78, 20);
+       hws[IMX6SL_CLK_PWM4]         = imx_clk_hw_gate2("pwm4",         "perclk",            base + 0x78, 22);
+       hws[IMX6SL_CLK_SDMA]         = imx_clk_hw_gate2("sdma",         "ipg",               base + 0x7c, 6);
+       hws[IMX6SL_CLK_SPBA]         = imx_clk_hw_gate2("spba",         "ipg",               base + 0x7c, 12);
+       hws[IMX6SL_CLK_SPDIF]        = imx_clk_hw_gate2_shared("spdif",     "spdif0_podf",   base + 0x7c, 14, &share_count_spdif);
+       hws[IMX6SL_CLK_SPDIF_GCLK]   = imx_clk_hw_gate2_shared("spdif_gclk",  "ipg",         base + 0x7c, 14, &share_count_spdif);
+       hws[IMX6SL_CLK_SSI1_IPG]     = imx_clk_hw_gate2_shared("ssi1_ipg",     "ipg",        base + 0x7c, 18, &share_count_ssi1);
+       hws[IMX6SL_CLK_SSI2_IPG]     = imx_clk_hw_gate2_shared("ssi2_ipg",     "ipg",        base + 0x7c, 20, &share_count_ssi2);
+       hws[IMX6SL_CLK_SSI3_IPG]     = imx_clk_hw_gate2_shared("ssi3_ipg",     "ipg",        base + 0x7c, 22, &share_count_ssi3);
+       hws[IMX6SL_CLK_SSI1]         = imx_clk_hw_gate2_shared("ssi1",         "ssi1_podf",  base + 0x7c, 18, &share_count_ssi1);
+       hws[IMX6SL_CLK_SSI2]         = imx_clk_hw_gate2_shared("ssi2",         "ssi2_podf",  base + 0x7c, 20, &share_count_ssi2);
+       hws[IMX6SL_CLK_SSI3]         = imx_clk_hw_gate2_shared("ssi3",         "ssi3_podf",  base + 0x7c, 22, &share_count_ssi3);
+       hws[IMX6SL_CLK_UART]         = imx_clk_hw_gate2("uart",         "ipg",               base + 0x7c, 24);
+       hws[IMX6SL_CLK_UART_SERIAL]  = imx_clk_hw_gate2("uart_serial",  "uart_root",         base + 0x7c, 26);
+       hws[IMX6SL_CLK_USBOH3]       = imx_clk_hw_gate2("usboh3",       "ipg",               base + 0x80, 0);
+       hws[IMX6SL_CLK_USDHC1]       = imx_clk_hw_gate2("usdhc1",       "usdhc1_podf",       base + 0x80, 2);
+       hws[IMX6SL_CLK_USDHC2]       = imx_clk_hw_gate2("usdhc2",       "usdhc2_podf",       base + 0x80, 4);
+       hws[IMX6SL_CLK_USDHC3]       = imx_clk_hw_gate2("usdhc3",       "usdhc3_podf",       base + 0x80, 6);
+       hws[IMX6SL_CLK_USDHC4]       = imx_clk_hw_gate2("usdhc4",       "usdhc4_podf",       base + 0x80, 8);
 
        /* Ensure the MMDC CH0 handshake is bypassed */
-       writel_relaxed(readl_relaxed(base + CCDR) |
-               BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR);
+       imx_mmdc_mask_handshake(base, 0);
 
-       imx_check_clocks(clks, ARRAY_SIZE(clks));
+       imx_check_clk_hws(hws, IMX6SL_CLK_END);
 
-       clk_data.clks = clks;
-       clk_data.clk_num = ARRAY_SIZE(clks);
-       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+       of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
 
        /* Ensure the AHB clk is at 132MHz. */
-       ret = clk_set_rate(clks[IMX6SL_CLK_AHB], 132000000);
+       ret = clk_set_rate(hws[IMX6SL_CLK_AHB]->clk, 132000000);
        if (ret)
                pr_warn("%s: failed to set AHB clock rate %d!\n",
                        __func__, ret);
 
        if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
-               clk_prepare_enable(clks[IMX6SL_CLK_USBPHY1_GATE]);
-               clk_prepare_enable(clks[IMX6SL_CLK_USBPHY2_GATE]);
+               clk_prepare_enable(hws[IMX6SL_CLK_USBPHY1_GATE]->clk);
+               clk_prepare_enable(hws[IMX6SL_CLK_USBPHY2_GATE]->clk);
        }
 
        /* Audio-related clocks configuration */
-       clk_set_parent(clks[IMX6SL_CLK_SPDIF0_SEL], clks[IMX6SL_CLK_PLL3_PFD3]);
+       clk_set_parent(hws[IMX6SL_CLK_SPDIF0_SEL]->clk, hws[IMX6SL_CLK_PLL3_PFD3]->clk);
 
        /* set PLL5 video as lcdif pix parent clock */
-       clk_set_parent(clks[IMX6SL_CLK_LCDIF_PIX_SEL],
-                       clks[IMX6SL_CLK_PLL5_VIDEO_DIV]);
+       clk_set_parent(hws[IMX6SL_CLK_LCDIF_PIX_SEL]->clk,
+                       hws[IMX6SL_CLK_PLL5_VIDEO_DIV]->clk);
 
-       clk_set_parent(clks[IMX6SL_CLK_LCDIF_AXI_SEL],
-                      clks[IMX6SL_CLK_PLL2_PFD2]);
+       clk_set_parent(hws[IMX6SL_CLK_LCDIF_AXI_SEL]->clk,
+                      hws[IMX6SL_CLK_PLL2_PFD2]->clk);
+
+       for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
+               int index = uart_clk_ids[i];
+
+               uart_clks[i] = &hws[index]->clk;
+       }
 
        imx_register_uart_clocks(uart_clks);
 }
index 7eea448..5f3e92c 100644 (file)
@@ -7,6 +7,7 @@
 #include <dt-bindings/clock/imx6sll-clock.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
+#include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
@@ -16,7 +17,6 @@
 #include "clk.h"
 
 #define CCM_ANALOG_PLL_BYPASS          (0x1 << 16)
-#define BM_CCM_CCDR_MMDC_CH0_MASK      (0x2 << 16)
 #define xPLL_CLR(offset)               (offset + 0x8)
 
 static const char *pll_bypass_src_sels[] = { "osc", "dummy", };
@@ -53,8 +53,8 @@ static const char *lcdif_sels[] = { "lcdif_podf", "ipp_di0", "ipp_di1", "ldb_di0
 static const char *epdc_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd2_508m", };
 static const char *epdc_sels[] = { "epdc_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", };
 
-static struct clk *clks[IMX6SLL_CLK_END];
-static struct clk_onecell_data clk_data;
+static struct clk_hw **hws;
+static struct clk_hw_onecell_data *clk_hw_data;
 
 static const struct clk_div_table post_div_table[] = {
        { .val = 2, .div = 1, },
@@ -76,33 +76,43 @@ static u32 share_count_ssi1;
 static u32 share_count_ssi2;
 static u32 share_count_ssi3;
 
-static struct clk ** const uart_clks[] __initconst = {
-       &clks[IMX6SLL_CLK_UART1_IPG],
-       &clks[IMX6SLL_CLK_UART1_SERIAL],
-       &clks[IMX6SLL_CLK_UART2_IPG],
-       &clks[IMX6SLL_CLK_UART2_SERIAL],
-       &clks[IMX6SLL_CLK_UART3_IPG],
-       &clks[IMX6SLL_CLK_UART3_SERIAL],
-       &clks[IMX6SLL_CLK_UART4_IPG],
-       &clks[IMX6SLL_CLK_UART4_SERIAL],
-       &clks[IMX6SLL_CLK_UART5_IPG],
-       &clks[IMX6SLL_CLK_UART5_SERIAL],
-       NULL
+static const int uart_clk_ids[] __initconst = {
+       IMX6SLL_CLK_UART1_IPG,
+       IMX6SLL_CLK_UART1_SERIAL,
+       IMX6SLL_CLK_UART2_IPG,
+       IMX6SLL_CLK_UART2_SERIAL,
+       IMX6SLL_CLK_UART3_IPG,
+       IMX6SLL_CLK_UART3_SERIAL,
+       IMX6SLL_CLK_UART4_IPG,
+       IMX6SLL_CLK_UART4_SERIAL,
+       IMX6SLL_CLK_UART5_IPG,
+       IMX6SLL_CLK_UART5_SERIAL,
 };
 
+static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata;
+
 static void __init imx6sll_clocks_init(struct device_node *ccm_node)
 {
        struct device_node *np;
        void __iomem *base;
+       int i;
+
+       clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
+                                         IMX6SLL_CLK_END), GFP_KERNEL);
+       if (WARN_ON(!clk_hw_data))
+               return;
+
+       clk_hw_data->num = IMX6SLL_CLK_END;
+       hws = clk_hw_data->hws;
 
-       clks[IMX6SLL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
+       hws[IMX6SLL_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
 
-       clks[IMX6SLL_CLK_CKIL] = of_clk_get_by_name(ccm_node, "ckil");
-       clks[IMX6SLL_CLK_OSC] = of_clk_get_by_name(ccm_node, "osc");
+       hws[IMX6SLL_CLK_CKIL] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ckil"));
+       hws[IMX6SLL_CLK_OSC] = __clk_get_hw(of_clk_get_by_name(ccm_node, "osc"));
 
        /* ipp_di clock is external input */
-       clks[IMX6SLL_CLK_IPP_DI0] = of_clk_get_by_name(ccm_node, "ipp_di0");
-       clks[IMX6SLL_CLK_IPP_DI1] = of_clk_get_by_name(ccm_node, "ipp_di1");
+       hws[IMX6SLL_CLK_IPP_DI0] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di0"));
+       hws[IMX6SLL_CLK_IPP_DI1] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di1"));
 
        np = of_find_compatible_node(NULL, NULL, "fsl,imx6sll-anatop");
        base = of_iomap(np, 0);
@@ -118,37 +128,37 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node)
        writel_relaxed(CCM_ANALOG_PLL_BYPASS, base + xPLL_CLR(0xa0));
        writel_relaxed(CCM_ANALOG_PLL_BYPASS, base + xPLL_CLR(0xe0));
 
-       clks[IMX6SLL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SLL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SLL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SLL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SLL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SLL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SLL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-
-       clks[IMX6SLL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS,    "pll1", "pll1_bypass_src", base + 0x00, 0x7f);
-       clks[IMX6SLL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1);
-       clks[IMX6SLL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB,    "pll3", "pll3_bypass_src", base + 0x10, 0x3);
-       clks[IMX6SLL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV,     "pll4", "pll4_bypass_src", base + 0x70, 0x7f);
-       clks[IMX6SLL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV,     "pll5", "pll5_bypass_src", base + 0xa0, 0x7f);
-       clks[IMX6SLL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET,   "pll6", "pll6_bypass_src", base + 0xe0, 0x3);
-       clks[IMX6SLL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB,    "pll7", "pll7_bypass_src", base + 0x20, 0x3);
-
-       clks[IMX6SLL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SLL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SLL_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SLL_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SLL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SLL_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SLL_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
-
-       clks[IMX6SLL_CLK_PLL1_SYS]      = imx_clk_fixed_factor("pll1_sys", "pll1_bypass", 1, 1);
-       clks[IMX6SLL_CLK_PLL2_BUS]      = imx_clk_gate("pll2_bus",         "pll2_bypass", base + 0x30, 13);
-       clks[IMX6SLL_CLK_PLL3_USB_OTG]  = imx_clk_gate("pll3_usb_otg",     "pll3_bypass", base + 0x10, 13);
-       clks[IMX6SLL_CLK_PLL4_AUDIO]    = imx_clk_gate("pll4_audio",       "pll4_bypass", base + 0x70, 13);
-       clks[IMX6SLL_CLK_PLL5_VIDEO]    = imx_clk_gate("pll5_video",       "pll5_bypass", base + 0xa0, 13);
-       clks[IMX6SLL_CLK_PLL6_ENET]     = imx_clk_gate("pll6_enet",        "pll6_bypass", base + 0xe0, 13);
-       clks[IMX6SLL_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host",    "pll7_bypass", base + 0x20, 13);
+       hws[IMX6SLL_PLL1_BYPASS_SRC] = imx_clk_hw_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SLL_PLL2_BYPASS_SRC] = imx_clk_hw_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SLL_PLL3_BYPASS_SRC] = imx_clk_hw_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SLL_PLL4_BYPASS_SRC] = imx_clk_hw_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SLL_PLL5_BYPASS_SRC] = imx_clk_hw_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SLL_PLL6_BYPASS_SRC] = imx_clk_hw_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SLL_PLL7_BYPASS_SRC] = imx_clk_hw_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+
+       hws[IMX6SLL_CLK_PLL1] = imx_clk_hw_pllv3(IMX_PLLV3_SYS,  "pll1", "pll1_bypass_src", base + 0x00, 0x7f);
+       hws[IMX6SLL_CLK_PLL2] = imx_clk_hw_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1);
+       hws[IMX6SLL_CLK_PLL3] = imx_clk_hw_pllv3(IMX_PLLV3_USB,  "pll3", "pll3_bypass_src", base + 0x10, 0x3);
+       hws[IMX6SLL_CLK_PLL4] = imx_clk_hw_pllv3(IMX_PLLV3_AV,   "pll4", "pll4_bypass_src", base + 0x70, 0x7f);
+       hws[IMX6SLL_CLK_PLL5] = imx_clk_hw_pllv3(IMX_PLLV3_AV,   "pll5", "pll5_bypass_src", base + 0xa0, 0x7f);
+       hws[IMX6SLL_CLK_PLL6] = imx_clk_hw_pllv3(IMX_PLLV3_ENET,         "pll6", "pll6_bypass_src", base + 0xe0, 0x3);
+       hws[IMX6SLL_CLK_PLL7] = imx_clk_hw_pllv3(IMX_PLLV3_USB,  "pll7", "pll7_bypass_src", base + 0x20, 0x3);
+
+       hws[IMX6SLL_PLL1_BYPASS] = imx_clk_hw_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SLL_PLL2_BYPASS] = imx_clk_hw_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SLL_PLL3_BYPASS] = imx_clk_hw_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SLL_PLL4_BYPASS] = imx_clk_hw_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SLL_PLL5_BYPASS] = imx_clk_hw_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SLL_PLL6_BYPASS] = imx_clk_hw_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SLL_PLL7_BYPASS] = imx_clk_hw_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
+
+       hws[IMX6SLL_CLK_PLL1_SYS]       = imx_clk_hw_fixed_factor("pll1_sys", "pll1_bypass", 1, 1);
+       hws[IMX6SLL_CLK_PLL2_BUS]       = imx_clk_hw_gate("pll2_bus",      "pll2_bypass", base + 0x30, 13);
+       hws[IMX6SLL_CLK_PLL3_USB_OTG]   = imx_clk_hw_gate("pll3_usb_otg",          "pll3_bypass", base + 0x10, 13);
+       hws[IMX6SLL_CLK_PLL4_AUDIO]     = imx_clk_hw_gate("pll4_audio",    "pll4_bypass", base + 0x70, 13);
+       hws[IMX6SLL_CLK_PLL5_VIDEO]     = imx_clk_hw_gate("pll5_video",    "pll5_bypass", base + 0xa0, 13);
+       hws[IMX6SLL_CLK_PLL6_ENET]      = imx_clk_hw_gate("pll6_enet",     "pll6_bypass", base + 0xe0, 13);
+       hws[IMX6SLL_CLK_PLL7_USB_HOST]  = imx_clk_hw_gate("pll7_usb_host",         "pll7_bypass", base + 0x20, 13);
 
        /*
         * Bit 20 is the reserved and read-only bit, we do this only for:
@@ -156,209 +166,213 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node)
         * - Keep refcount when do usbphy clk_enable/disable, in that case,
         * the clk framework many need to enable/disable usbphy's parent
         */
-       clks[IMX6SLL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg",  base + 0x10, 20);
-       clks[IMX6SLL_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
+       hws[IMX6SLL_CLK_USBPHY1] = imx_clk_hw_gate("usbphy1", "pll3_usb_otg",  base + 0x10, 20);
+       hws[IMX6SLL_CLK_USBPHY2] = imx_clk_hw_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
 
        /*
         * usbphy*_gate needs to be on after system boots up, and software
         * never needs to control it anymore.
         */
        if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
-               clks[IMX6SLL_CLK_USBPHY1_GATE] = imx_clk_gate_flags("usbphy1_gate", "dummy", base + 0x10, 6, CLK_IS_CRITICAL);
-               clks[IMX6SLL_CLK_USBPHY2_GATE] = imx_clk_gate_flags("usbphy2_gate", "dummy", base + 0x20, 6, CLK_IS_CRITICAL);
+               hws[IMX6SLL_CLK_USBPHY1_GATE] = imx_clk_hw_gate_flags("usbphy1_gate", "dummy", base + 0x10, 6, CLK_IS_CRITICAL);
+               hws[IMX6SLL_CLK_USBPHY2_GATE] = imx_clk_hw_gate_flags("usbphy2_gate", "dummy", base + 0x20, 6, CLK_IS_CRITICAL);
        }
 
        /*                                      name               parent_name     reg          idx */
-       clks[IMX6SLL_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0);
-       clks[IMX6SLL_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1);
-       clks[IMX6SLL_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2);
-       clks[IMX6SLL_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3_594m", "pll2_bus", base + 0x100, 3);
-       clks[IMX6SLL_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0);
-       clks[IMX6SLL_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1);
-       clks[IMX6SLL_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2);
-       clks[IMX6SLL_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3);
-
-       clks[IMX6SLL_CLK_PLL4_POST_DIV]  = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio",
+       hws[IMX6SLL_CLK_PLL2_PFD0] = imx_clk_hw_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0);
+       hws[IMX6SLL_CLK_PLL2_PFD1] = imx_clk_hw_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1);
+       hws[IMX6SLL_CLK_PLL2_PFD2] = imx_clk_hw_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2);
+       hws[IMX6SLL_CLK_PLL2_PFD3] = imx_clk_hw_pfd("pll2_pfd3_594m", "pll2_bus",       base + 0x100, 3);
+       hws[IMX6SLL_CLK_PLL3_PFD0] = imx_clk_hw_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0);
+       hws[IMX6SLL_CLK_PLL3_PFD1] = imx_clk_hw_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1);
+       hws[IMX6SLL_CLK_PLL3_PFD2] = imx_clk_hw_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2);
+       hws[IMX6SLL_CLK_PLL3_PFD3] = imx_clk_hw_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3);
+
+       hws[IMX6SLL_CLK_PLL4_POST_DIV]  = clk_hw_register_divider_table(NULL, "pll4_post_div", "pll4_audio",
                 CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
-       clks[IMX6SLL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div",
+       hws[IMX6SLL_CLK_PLL4_AUDIO_DIV] = clk_hw_register_divider(NULL, "pll4_audio_div", "pll4_post_div",
                 CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 15, 1, 0, &imx_ccm_lock);
-       clks[IMX6SLL_CLK_PLL5_POST_DIV]  = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video",
+       hws[IMX6SLL_CLK_PLL5_POST_DIV]  = clk_hw_register_divider_table(NULL, "pll5_post_div", "pll5_video",
                 CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
-       clks[IMX6SLL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div",
+       hws[IMX6SLL_CLK_PLL5_VIDEO_DIV] = clk_hw_register_divider_table(NULL, "pll5_video_div", "pll5_post_div",
                 CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
 
        /*                                                 name         parent_name      mult  div */
-       clks[IMX6SLL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2);
-       clks[IMX6SLL_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg",   1, 4);
-       clks[IMX6SLL_CLK_PLL3_80M]  = imx_clk_fixed_factor("pll3_80m",  "pll3_usb_otg",   1, 6);
-       clks[IMX6SLL_CLK_PLL3_60M]  = imx_clk_fixed_factor("pll3_60m",  "pll3_usb_otg",   1, 8);
+       hws[IMX6SLL_CLK_PLL2_198M] = imx_clk_hw_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2);
+       hws[IMX6SLL_CLK_PLL3_120M] = imx_clk_hw_fixed_factor("pll3_120m", "pll3_usb_otg",   1, 4);
+       hws[IMX6SLL_CLK_PLL3_80M]  = imx_clk_hw_fixed_factor("pll3_80m",  "pll3_usb_otg",   1, 6);
+       hws[IMX6SLL_CLK_PLL3_60M]  = imx_clk_hw_fixed_factor("pll3_60m",  "pll3_usb_otg",   1, 8);
 
        np = ccm_node;
        base = of_iomap(np, 0);
        WARN_ON(!base);
 
-       clks[IMX6SLL_CLK_STEP]            = imx_clk_mux("step", base + 0x0c, 8, 1, step_sels, ARRAY_SIZE(step_sels));
-       clks[IMX6SLL_CLK_PLL1_SW]         = imx_clk_mux_flags("pll1_sw",   base + 0x0c, 2,  1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels), 0);
-       clks[IMX6SLL_CLK_AXI_ALT_SEL]     = imx_clk_mux("axi_alt_sel",     base + 0x14, 7,  1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels));
-       clks[IMX6SLL_CLK_AXI_SEL]         = imx_clk_mux_flags("axi_sel",   base + 0x14, 6,  1, axi_sels, ARRAY_SIZE(axi_sels), 0);
-       clks[IMX6SLL_CLK_PERIPH_PRE]      = imx_clk_mux("periph_pre",      base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
-       clks[IMX6SLL_CLK_PERIPH2_PRE]     = imx_clk_mux("periph2_pre",     base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels));
-       clks[IMX6SLL_CLK_PERIPH_CLK2_SEL]  = imx_clk_mux("periph_clk2_sel",  base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
-       clks[IMX6SLL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
-       clks[IMX6SLL_CLK_USDHC1_SEL]      = imx_clk_mux("usdhc1_sel",   base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
-       clks[IMX6SLL_CLK_USDHC2_SEL]      = imx_clk_mux("usdhc2_sel",   base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
-       clks[IMX6SLL_CLK_USDHC3_SEL]      = imx_clk_mux("usdhc3_sel",   base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
-       clks[IMX6SLL_CLK_SSI1_SEL]        = imx_clk_mux("ssi1_sel",     base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
-       clks[IMX6SLL_CLK_SSI2_SEL]        = imx_clk_mux("ssi2_sel",     base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
-       clks[IMX6SLL_CLK_SSI3_SEL]        = imx_clk_mux("ssi3_sel",     base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
-       clks[IMX6SLL_CLK_PERCLK_SEL]      = imx_clk_mux("perclk_sel",   base + 0x1c, 6,  1, perclk_sels, ARRAY_SIZE(perclk_sels));
-       clks[IMX6SLL_CLK_UART_SEL]        = imx_clk_mux("uart_sel",     base + 0x24, 6,  1, uart_sels, ARRAY_SIZE(uart_sels));
-       clks[IMX6SLL_CLK_SPDIF_SEL]       = imx_clk_mux("spdif_sel",    base + 0x30, 20, 2, spdif_sels, ARRAY_SIZE(spdif_sels));
-       clks[IMX6SLL_CLK_EXTERN_AUDIO_SEL] = imx_clk_mux("extern_audio_sel", base + 0x30, 7,  2, spdif_sels, ARRAY_SIZE(spdif_sels));
-       clks[IMX6SLL_CLK_EPDC_PRE_SEL]    = imx_clk_mux("epdc_pre_sel", base + 0x34, 15, 3, epdc_pre_sels, ARRAY_SIZE(epdc_pre_sels));
-       clks[IMX6SLL_CLK_EPDC_SEL]        = imx_clk_mux("epdc_sel",     base + 0x34, 9, 3, epdc_sels, ARRAY_SIZE(epdc_sels));
-       clks[IMX6SLL_CLK_ECSPI_SEL]       = imx_clk_mux("ecspi_sel",    base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
-       clks[IMX6SLL_CLK_LCDIF_PRE_SEL]   = imx_clk_mux("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels));
-       clks[IMX6SLL_CLK_LCDIF_SEL]       = imx_clk_mux("lcdif_sel",     base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels));
-
-       clks[IMX6SLL_CLK_PERIPH]  = imx_clk_busy_mux("periph",  base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
-       clks[IMX6SLL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
-
-       clks[IMX6SLL_CLK_PERIPH_CLK2]   = imx_clk_divider("periph_clk2",   "periph_clk2_sel",   base + 0x14, 27, 3);
-       clks[IMX6SLL_CLK_PERIPH2_CLK2]  = imx_clk_divider("periph2_clk2",  "periph2_clk2_sel",  base + 0x14, 0,  3);
-       clks[IMX6SLL_CLK_IPG]           = imx_clk_divider("ipg",           "ahb",               base + 0x14, 8,  2);
-       clks[IMX6SLL_CLK_LCDIF_PODF]    = imx_clk_divider("lcdif_podf",    "lcdif_pred",        base + 0x18, 23, 3);
-       clks[IMX6SLL_CLK_PERCLK]        = imx_clk_divider("perclk",        "perclk_sel",        base + 0x1c, 0,  6);
-       clks[IMX6SLL_CLK_USDHC3_PODF]   = imx_clk_divider("usdhc3_podf",   "usdhc3_sel",        base + 0x24, 19, 3);
-       clks[IMX6SLL_CLK_USDHC2_PODF]   = imx_clk_divider("usdhc2_podf",   "usdhc2_sel",        base + 0x24, 16, 3);
-       clks[IMX6SLL_CLK_USDHC1_PODF]   = imx_clk_divider("usdhc1_podf",   "usdhc1_sel",        base + 0x24, 11, 3);
-       clks[IMX6SLL_CLK_UART_PODF]     = imx_clk_divider("uart_podf",     "uart_sel",          base + 0x24, 0,  6);
-       clks[IMX6SLL_CLK_SSI3_PRED]     = imx_clk_divider("ssi3_pred",     "ssi3_sel",          base + 0x28, 22, 3);
-       clks[IMX6SLL_CLK_SSI3_PODF]     = imx_clk_divider("ssi3_podf",     "ssi3_pred",         base + 0x28, 16, 6);
-       clks[IMX6SLL_CLK_SSI1_PRED]     = imx_clk_divider("ssi1_pred",     "ssi1_sel",          base + 0x28, 6,  3);
-       clks[IMX6SLL_CLK_SSI1_PODF]     = imx_clk_divider("ssi1_podf",     "ssi1_pred",         base + 0x28, 0,  6);
-       clks[IMX6SLL_CLK_SSI2_PRED]     = imx_clk_divider("ssi2_pred",     "ssi2_sel",          base + 0x2c, 6,  3);
-       clks[IMX6SLL_CLK_SSI2_PODF]     = imx_clk_divider("ssi2_podf",     "ssi2_pred",         base + 0x2c, 0,  6);
-       clks[IMX6SLL_CLK_SPDIF_PRED]    = imx_clk_divider("spdif_pred",    "spdif_sel",         base + 0x30, 25, 3);
-       clks[IMX6SLL_CLK_SPDIF_PODF]    = imx_clk_divider("spdif_podf",    "spdif_pred",        base + 0x30, 22, 3);
-       clks[IMX6SLL_CLK_EXTERN_AUDIO_PRED] = imx_clk_divider("extern_audio_pred", "extern_audio_sel",  base + 0x30, 12, 3);
-       clks[IMX6SLL_CLK_EXTERN_AUDIO_PODF] = imx_clk_divider("extern_audio_podf", "extern_audio_pred", base + 0x30, 9,  3);
-       clks[IMX6SLL_CLK_EPDC_PODF]  = imx_clk_divider("epdc_podf",  "epdc_pre_sel",  base + 0x34, 12, 3);
-       clks[IMX6SLL_CLK_ECSPI_PODF] = imx_clk_divider("ecspi_podf", "ecspi_sel",     base + 0x38, 19, 6);
-       clks[IMX6SLL_CLK_LCDIF_PRED] = imx_clk_divider("lcdif_pred", "lcdif_pre_sel", base + 0x38, 12, 3);
-
-       clks[IMX6SLL_CLK_ARM]           = imx_clk_busy_divider("arm",       "pll1_sw",  base +  0x10, 0,  3,  base + 0x48, 16);
-       clks[IMX6SLL_CLK_MMDC_PODF]     = imx_clk_busy_divider("mmdc_podf", "periph2",  base +  0x14, 3,  3,  base + 0x48, 2);
-       clks[IMX6SLL_CLK_AXI_PODF]      = imx_clk_busy_divider("axi",       "axi_sel",  base +  0x14, 16, 3,  base + 0x48, 0);
-       clks[IMX6SLL_CLK_AHB]           = imx_clk_busy_divider("ahb",       "periph",   base +  0x14, 10, 3,  base + 0x48, 1);
-
-       clks[IMX6SLL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
-       clks[IMX6SLL_CLK_LDB_DI0_DIV_7]   = imx_clk_fixed_factor("ldb_di0_div_7",   "ldb_di0_sel", 1, 7);
-       clks[IMX6SLL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
-       clks[IMX6SLL_CLK_LDB_DI1_DIV_7]   = imx_clk_fixed_factor("ldb_di1_div_7",   "ldb_di1_sel", 1, 7);
-
-       clks[IMX6SLL_CLK_LDB_DI0_SEL]   = imx_clk_mux("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels));
-       clks[IMX6SLL_CLK_LDB_DI1_SEL]   = imx_clk_mux("ldb_di1_sel", base + 0x1c, 7, 3, ldb_di1_sels, ARRAY_SIZE(ldb_di1_sels));
-       clks[IMX6SLL_CLK_LDB_DI0_DIV_SEL] = imx_clk_mux("ldb_di0_div_sel", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels));
-       clks[IMX6SLL_CLK_LDB_DI1_DIV_SEL] = imx_clk_mux("ldb_di1_div_sel", base + 0x20, 10, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels));
+       hws[IMX6SLL_CLK_STEP]             = imx_clk_hw_mux("step", base + 0x0c, 8, 1, step_sels, ARRAY_SIZE(step_sels));
+       hws[IMX6SLL_CLK_PLL1_SW]          = imx_clk_hw_mux_flags("pll1_sw",   base + 0x0c, 2,  1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels), 0);
+       hws[IMX6SLL_CLK_AXI_ALT_SEL]      = imx_clk_hw_mux("axi_alt_sel",          base + 0x14, 7,  1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels));
+       hws[IMX6SLL_CLK_AXI_SEL]          = imx_clk_hw_mux_flags("axi_sel",   base + 0x14, 6,  1, axi_sels, ARRAY_SIZE(axi_sels), 0);
+       hws[IMX6SLL_CLK_PERIPH_PRE]       = imx_clk_hw_mux("periph_pre",      base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
+       hws[IMX6SLL_CLK_PERIPH2_PRE]      = imx_clk_hw_mux("periph2_pre",     base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels));
+       hws[IMX6SLL_CLK_PERIPH_CLK2_SEL]  = imx_clk_hw_mux("periph_clk2_sel",  base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
+       hws[IMX6SLL_CLK_PERIPH2_CLK2_SEL] = imx_clk_hw_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
+       hws[IMX6SLL_CLK_USDHC1_SEL]       = imx_clk_hw_mux("usdhc1_sel",   base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+       hws[IMX6SLL_CLK_USDHC2_SEL]       = imx_clk_hw_mux("usdhc2_sel",   base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+       hws[IMX6SLL_CLK_USDHC3_SEL]       = imx_clk_hw_mux("usdhc3_sel",   base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+       hws[IMX6SLL_CLK_SSI1_SEL]         = imx_clk_hw_mux("ssi1_sel",     base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
+       hws[IMX6SLL_CLK_SSI2_SEL]         = imx_clk_hw_mux("ssi2_sel",     base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
+       hws[IMX6SLL_CLK_SSI3_SEL]         = imx_clk_hw_mux("ssi3_sel",     base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
+       hws[IMX6SLL_CLK_PERCLK_SEL]       = imx_clk_hw_mux("perclk_sel",   base + 0x1c, 6,  1, perclk_sels, ARRAY_SIZE(perclk_sels));
+       hws[IMX6SLL_CLK_UART_SEL]         = imx_clk_hw_mux("uart_sel",  base + 0x24, 6,  1, uart_sels, ARRAY_SIZE(uart_sels));
+       hws[IMX6SLL_CLK_SPDIF_SEL]        = imx_clk_hw_mux("spdif_sel", base + 0x30, 20, 2, spdif_sels, ARRAY_SIZE(spdif_sels));
+       hws[IMX6SLL_CLK_EXTERN_AUDIO_SEL] = imx_clk_hw_mux("extern_audio_sel", base + 0x30, 7,  2, spdif_sels, ARRAY_SIZE(spdif_sels));
+       hws[IMX6SLL_CLK_EPDC_PRE_SEL]     = imx_clk_hw_mux("epdc_pre_sel",      base + 0x34, 15, 3, epdc_pre_sels, ARRAY_SIZE(epdc_pre_sels));
+       hws[IMX6SLL_CLK_EPDC_SEL]         = imx_clk_hw_mux("epdc_sel",  base + 0x34, 9, 3, epdc_sels, ARRAY_SIZE(epdc_sels));
+       hws[IMX6SLL_CLK_ECSPI_SEL]        = imx_clk_hw_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
+       hws[IMX6SLL_CLK_LCDIF_PRE_SEL]    = imx_clk_hw_mux("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels));
+       hws[IMX6SLL_CLK_LCDIF_SEL]        = imx_clk_hw_mux("lcdif_sel",     base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels));
+
+       hws[IMX6SLL_CLK_PERIPH]  = imx_clk_hw_busy_mux("periph",  base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
+       hws[IMX6SLL_CLK_PERIPH2] = imx_clk_hw_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
+
+       hws[IMX6SLL_CLK_PERIPH_CLK2]    = imx_clk_hw_divider("periph_clk2",   "periph_clk2_sel",        base + 0x14, 27, 3);
+       hws[IMX6SLL_CLK_PERIPH2_CLK2]   = imx_clk_hw_divider("periph2_clk2",  "periph2_clk2_sel",       base + 0x14, 0,  3);
+       hws[IMX6SLL_CLK_IPG]            = imx_clk_hw_divider("ipg",        "ahb",       base + 0x14, 8, 2);
+       hws[IMX6SLL_CLK_LCDIF_PODF]     = imx_clk_hw_divider("lcdif_podf",         "lcdif_pred",        base + 0x18, 23, 3);
+       hws[IMX6SLL_CLK_PERCLK] = imx_clk_hw_divider("perclk",     "perclk_sel",        base + 0x1c, 0,  6);
+       hws[IMX6SLL_CLK_USDHC3_PODF]   = imx_clk_hw_divider("usdhc3_podf",   "usdhc3_sel",      base + 0x24, 19, 3);
+       hws[IMX6SLL_CLK_USDHC2_PODF]    = imx_clk_hw_divider("usdhc2_podf",   "usdhc2_sel",     base + 0x24, 16, 3);
+       hws[IMX6SLL_CLK_USDHC1_PODF]    = imx_clk_hw_divider("usdhc1_podf",   "usdhc1_sel",     base + 0x24, 11, 3);
+       hws[IMX6SLL_CLK_UART_PODF]      = imx_clk_hw_divider("uart_podf",          "uart_sel",          base + 0x24, 0,  6);
+       hws[IMX6SLL_CLK_SSI3_PRED]      = imx_clk_hw_divider("ssi3_pred",          "ssi3_sel",          base + 0x28, 22, 3);
+       hws[IMX6SLL_CLK_SSI3_PODF]      = imx_clk_hw_divider("ssi3_podf",          "ssi3_pred",         base + 0x28, 16, 6);
+       hws[IMX6SLL_CLK_SSI1_PRED]      = imx_clk_hw_divider("ssi1_pred",          "ssi1_sel",          base + 0x28, 6,  3);
+       hws[IMX6SLL_CLK_SSI1_PODF]      = imx_clk_hw_divider("ssi1_podf",          "ssi1_pred",         base + 0x28, 0,  6);
+       hws[IMX6SLL_CLK_SSI2_PRED]      = imx_clk_hw_divider("ssi2_pred",          "ssi2_sel",          base + 0x2c, 6,  3);
+       hws[IMX6SLL_CLK_SSI2_PODF]      = imx_clk_hw_divider("ssi2_podf",          "ssi2_pred",         base + 0x2c, 0,  6);
+       hws[IMX6SLL_CLK_SPDIF_PRED]     = imx_clk_hw_divider("spdif_pred",         "spdif_sel",         base + 0x30, 25, 3);
+       hws[IMX6SLL_CLK_SPDIF_PODF]     = imx_clk_hw_divider("spdif_podf",         "spdif_pred",        base + 0x30, 22, 3);
+       hws[IMX6SLL_CLK_EXTERN_AUDIO_PRED] = imx_clk_hw_divider("extern_audio_pred", "extern_audio_sel",  base + 0x30, 12, 3);
+       hws[IMX6SLL_CLK_EXTERN_AUDIO_PODF] = imx_clk_hw_divider("extern_audio_podf", "extern_audio_pred", base + 0x30, 9,  3);
+       hws[IMX6SLL_CLK_EPDC_PODF]  = imx_clk_hw_divider("epdc_podf",  "epdc_pre_sel",  base + 0x34, 12, 3);
+       hws[IMX6SLL_CLK_ECSPI_PODF] = imx_clk_hw_divider("ecspi_podf", "ecspi_sel",     base + 0x38, 19, 6);
+       hws[IMX6SLL_CLK_LCDIF_PRED] = imx_clk_hw_divider("lcdif_pred", "lcdif_pre_sel", base + 0x38, 12, 3);
+
+       hws[IMX6SLL_CLK_ARM]            = imx_clk_hw_busy_divider("arm",        "pll1_sw",      base +  0x10, 0,  3,  base + 0x48, 16);
+       hws[IMX6SLL_CLK_MMDC_PODF]      = imx_clk_hw_busy_divider("mmdc_podf",  "periph2",      base +  0x14, 3,  3,  base + 0x48, 2);
+       hws[IMX6SLL_CLK_AXI_PODF]       = imx_clk_hw_busy_divider("axi",        "axi_sel",      base +  0x14, 16, 3,  base + 0x48, 0);
+       hws[IMX6SLL_CLK_AHB]            = imx_clk_hw_busy_divider("ahb",        "periph",       base +  0x14, 10, 3,  base + 0x48, 1);
+
+       hws[IMX6SLL_CLK_LDB_DI0_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
+       hws[IMX6SLL_CLK_LDB_DI0_DIV_7]    = imx_clk_hw_fixed_factor("ldb_di0_div_7",   "ldb_di0_sel", 1, 7);
+       hws[IMX6SLL_CLK_LDB_DI1_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
+       hws[IMX6SLL_CLK_LDB_DI1_DIV_7]    = imx_clk_hw_fixed_factor("ldb_di1_div_7",   "ldb_di1_sel", 1, 7);
+
+       hws[IMX6SLL_CLK_LDB_DI0_SEL]    = imx_clk_hw_mux("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels));
+       hws[IMX6SLL_CLK_LDB_DI1_SEL]   = imx_clk_hw_mux("ldb_di1_sel", base + 0x1c, 7, 3, ldb_di1_sels, ARRAY_SIZE(ldb_di1_sels));
+       hws[IMX6SLL_CLK_LDB_DI0_DIV_SEL] = imx_clk_hw_mux("ldb_di0_div_sel", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels));
+       hws[IMX6SLL_CLK_LDB_DI1_DIV_SEL] = imx_clk_hw_mux("ldb_di1_div_sel", base + 0x20, 10, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels));
 
        /* CCGR0 */
-       clks[IMX6SLL_CLK_AIPSTZ1]       = imx_clk_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL);
-       clks[IMX6SLL_CLK_AIPSTZ2]       = imx_clk_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL);
-       clks[IMX6SLL_CLK_DCP]           = imx_clk_gate2("dcp", "ahb", base + 0x68, 10);
-       clks[IMX6SLL_CLK_UART2_IPG]     = imx_clk_gate2("uart2_ipg", "ipg", base + 0x68, 28);
-       clks[IMX6SLL_CLK_UART2_SERIAL]  = imx_clk_gate2("uart2_serial", "uart_podf", base + 0x68, 28);
-       clks[IMX6SLL_CLK_GPIO2]         = imx_clk_gate2("gpio2", "ipg", base + 0x68, 30);
+       hws[IMX6SLL_CLK_AIPSTZ1]        = imx_clk_hw_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL);
+       hws[IMX6SLL_CLK_AIPSTZ2]        = imx_clk_hw_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL);
+       hws[IMX6SLL_CLK_DCP]            = imx_clk_hw_gate2("dcp", "ahb", base + 0x68, 10);
+       hws[IMX6SLL_CLK_UART2_IPG]      = imx_clk_hw_gate2("uart2_ipg", "ipg", base + 0x68, 28);
+       hws[IMX6SLL_CLK_UART2_SERIAL]   = imx_clk_hw_gate2("uart2_serial",      "uart_podf", base + 0x68, 28);
+       hws[IMX6SLL_CLK_GPIO2]          = imx_clk_hw_gate2("gpio2", "ipg", base + 0x68, 30);
 
        /* CCGR1 */
-       clks[IMX6SLL_CLK_ECSPI1]        = imx_clk_gate2("ecspi1",       "ecspi_podf", base + 0x6c, 0);
-       clks[IMX6SLL_CLK_ECSPI2]        = imx_clk_gate2("ecspi2",       "ecspi_podf", base + 0x6c, 2);
-       clks[IMX6SLL_CLK_ECSPI3]        = imx_clk_gate2("ecspi3",       "ecspi_podf", base + 0x6c, 4);
-       clks[IMX6SLL_CLK_ECSPI4]        = imx_clk_gate2("ecspi4",       "ecspi_podf", base + 0x6c, 6);
-       clks[IMX6SLL_CLK_UART3_IPG]     = imx_clk_gate2("uart3_ipg",    "ipg", base + 0x6c, 10);
-       clks[IMX6SLL_CLK_UART3_SERIAL]  = imx_clk_gate2("uart3_serial", "uart_podf", base + 0x6c, 10);
-       clks[IMX6SLL_CLK_EPIT1]         = imx_clk_gate2("epit1",        "perclk", base + 0x6c, 12);
-       clks[IMX6SLL_CLK_EPIT2]         = imx_clk_gate2("epit2",        "perclk", base + 0x6c, 14);
-       clks[IMX6SLL_CLK_GPT_BUS]       = imx_clk_gate2("gpt1_bus",     "perclk", base + 0x6c, 20);
-       clks[IMX6SLL_CLK_GPT_SERIAL]    = imx_clk_gate2("gpt1_serial",  "perclk", base + 0x6c, 22);
-       clks[IMX6SLL_CLK_UART4_IPG]     = imx_clk_gate2("uart4_ipg",    "ipg", base + 0x6c, 24);
-       clks[IMX6SLL_CLK_UART4_SERIAL]  = imx_clk_gate2("uart4_serial", "uart_podf", base + 0x6c, 24);
-       clks[IMX6SLL_CLK_GPIO1]         = imx_clk_gate2("gpio1",        "ipg", base + 0x6c, 26);
-       clks[IMX6SLL_CLK_GPIO5]         = imx_clk_gate2("gpio5",        "ipg", base + 0x6c, 30);
+       hws[IMX6SLL_CLK_ECSPI1] = imx_clk_hw_gate2("ecspi1",    "ecspi_podf", base + 0x6c, 0);
+       hws[IMX6SLL_CLK_ECSPI2] = imx_clk_hw_gate2("ecspi2",    "ecspi_podf", base + 0x6c, 2);
+       hws[IMX6SLL_CLK_ECSPI3] = imx_clk_hw_gate2("ecspi3",    "ecspi_podf", base + 0x6c, 4);
+       hws[IMX6SLL_CLK_ECSPI4] = imx_clk_hw_gate2("ecspi4",    "ecspi_podf", base + 0x6c, 6);
+       hws[IMX6SLL_CLK_UART3_IPG]      = imx_clk_hw_gate2("uart3_ipg", "ipg", base + 0x6c, 10);
+       hws[IMX6SLL_CLK_UART3_SERIAL]   = imx_clk_hw_gate2("uart3_serial",      "uart_podf", base + 0x6c, 10);
+       hws[IMX6SLL_CLK_EPIT1]          = imx_clk_hw_gate2("epit1",     "perclk", base + 0x6c, 12);
+       hws[IMX6SLL_CLK_EPIT2]          = imx_clk_hw_gate2("epit2",     "perclk", base + 0x6c, 14);
+       hws[IMX6SLL_CLK_GPT_BUS]        = imx_clk_hw_gate2("gpt1_bus",  "perclk", base + 0x6c, 20);
+       hws[IMX6SLL_CLK_GPT_SERIAL]     = imx_clk_hw_gate2("gpt1_serial",       "perclk", base + 0x6c, 22);
+       hws[IMX6SLL_CLK_UART4_IPG]      = imx_clk_hw_gate2("uart4_ipg", "ipg", base + 0x6c, 24);
+       hws[IMX6SLL_CLK_UART4_SERIAL]   = imx_clk_hw_gate2("uart4_serial",      "uart_podf", base + 0x6c, 24);
+       hws[IMX6SLL_CLK_GPIO1]          = imx_clk_hw_gate2("gpio1",     "ipg", base + 0x6c, 26);
+       hws[IMX6SLL_CLK_GPIO5]          = imx_clk_hw_gate2("gpio5",     "ipg", base + 0x6c, 30);
 
        /* CCGR2 */
-       clks[IMX6SLL_CLK_GPIO6]         = imx_clk_gate2("gpio6",        "ipg",    base + 0x70, 0);
-       clks[IMX6SLL_CLK_CSI]           = imx_clk_gate2("csi",          "axi",    base + 0x70,  2);
-       clks[IMX6SLL_CLK_I2C1]          = imx_clk_gate2("i2c1",         "perclk", base + 0x70,  6);
-       clks[IMX6SLL_CLK_I2C2]          = imx_clk_gate2("i2c2",         "perclk", base + 0x70,  8);
-       clks[IMX6SLL_CLK_I2C3]          = imx_clk_gate2("i2c3",         "perclk", base + 0x70,  10);
-       clks[IMX6SLL_CLK_OCOTP]         = imx_clk_gate2("ocotp",        "ipg",    base + 0x70,  12);
-       clks[IMX6SLL_CLK_GPIO3]         = imx_clk_gate2("gpio3",        "ipg",    base + 0x70,  26);
-       clks[IMX6SLL_CLK_LCDIF_APB]     = imx_clk_gate2("lcdif_apb",    "axi",    base + 0x70,  28);
-       clks[IMX6SLL_CLK_PXP]           = imx_clk_gate2("pxp",          "axi",    base + 0x70,  30);
+       hws[IMX6SLL_CLK_GPIO6]          = imx_clk_hw_gate2("gpio6",     "ipg",    base + 0x70, 0);
+       hws[IMX6SLL_CLK_CSI]            = imx_clk_hw_gate2("csi",               "axi",    base + 0x70,  2);
+       hws[IMX6SLL_CLK_I2C1]           = imx_clk_hw_gate2("i2c1",              "perclk", base + 0x70,  6);
+       hws[IMX6SLL_CLK_I2C2]           = imx_clk_hw_gate2("i2c2",              "perclk", base + 0x70,  8);
+       hws[IMX6SLL_CLK_I2C3]           = imx_clk_hw_gate2("i2c3",              "perclk", base + 0x70,  10);
+       hws[IMX6SLL_CLK_OCOTP]          = imx_clk_hw_gate2("ocotp",     "ipg",    base + 0x70,  12);
+       hws[IMX6SLL_CLK_GPIO3]          = imx_clk_hw_gate2("gpio3",     "ipg",    base + 0x70,  26);
+       hws[IMX6SLL_CLK_LCDIF_APB]      = imx_clk_hw_gate2("lcdif_apb", "axi",    base + 0x70,  28);
+       hws[IMX6SLL_CLK_PXP]            = imx_clk_hw_gate2("pxp",               "axi",    base + 0x70,  30);
 
        /* CCGR3 */
-       clks[IMX6SLL_CLK_UART5_IPG]     = imx_clk_gate2("uart5_ipg",    "ipg",          base + 0x74, 2);
-       clks[IMX6SLL_CLK_UART5_SERIAL]  = imx_clk_gate2("uart5_serial", "uart_podf",    base + 0x74, 2);
-       clks[IMX6SLL_CLK_EPDC_AXI]      = imx_clk_gate2("epdc_aclk",    "axi",          base + 0x74, 4);
-       clks[IMX6SLL_CLK_EPDC_PIX]      = imx_clk_gate2("epdc_pix",     "epdc_podf",    base + 0x74, 4);
-       clks[IMX6SLL_CLK_LCDIF_PIX]     = imx_clk_gate2("lcdif_pix",    "lcdif_podf",   base + 0x74, 10);
-       clks[IMX6SLL_CLK_GPIO4]         = imx_clk_gate2("gpio4",        "ipg",          base + 0x74, 12);
-       clks[IMX6SLL_CLK_WDOG1]         = imx_clk_gate2("wdog1",        "ipg",          base + 0x74, 16);
-       clks[IMX6SLL_CLK_MMDC_P0_FAST]  = imx_clk_gate_flags("mmdc_p0_fast", "mmdc_podf",  base + 0x74, 20, CLK_IS_CRITICAL);
-       clks[IMX6SLL_CLK_MMDC_P0_IPG]   = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg",        base + 0x74, 24, CLK_IS_CRITICAL);
-       clks[IMX6SLL_CLK_MMDC_P1_IPG]   = imx_clk_gate2("mmdc_p1_ipg", "ipg",      base + 0x74, 26);
-       clks[IMX6SLL_CLK_OCRAM]         = imx_clk_gate_flags("ocram","ahb",                base + 0x74, 28, CLK_IS_CRITICAL);
+       hws[IMX6SLL_CLK_UART5_IPG]      = imx_clk_hw_gate2("uart5_ipg", "ipg",          base + 0x74, 2);
+       hws[IMX6SLL_CLK_UART5_SERIAL]   = imx_clk_hw_gate2("uart5_serial",      "uart_podf",    base + 0x74, 2);
+       hws[IMX6SLL_CLK_EPDC_AXI]       = imx_clk_hw_gate2("epdc_aclk", "axi",          base + 0x74, 4);
+       hws[IMX6SLL_CLK_EPDC_PIX]       = imx_clk_hw_gate2("epdc_pix",  "epdc_podf",    base + 0x74, 4);
+       hws[IMX6SLL_CLK_LCDIF_PIX]      = imx_clk_hw_gate2("lcdif_pix", "lcdif_podf",   base + 0x74, 10);
+       hws[IMX6SLL_CLK_GPIO4]          = imx_clk_hw_gate2("gpio4",     "ipg",          base + 0x74, 12);
+       hws[IMX6SLL_CLK_WDOG1]          = imx_clk_hw_gate2("wdog1",     "ipg",          base + 0x74, 16);
+       hws[IMX6SLL_CLK_MMDC_P0_FAST]   = imx_clk_hw_gate_flags("mmdc_p0_fast", "mmdc_podf",  base + 0x74,      20, CLK_IS_CRITICAL);
+       hws[IMX6SLL_CLK_MMDC_P0_IPG]    = imx_clk_hw_gate2_flags("mmdc_p0_ipg", "ipg",     base + 0x74, 24, CLK_IS_CRITICAL);
+       hws[IMX6SLL_CLK_MMDC_P1_IPG]    = imx_clk_hw_gate2_flags("mmdc_p1_ipg", "ipg",     base + 0x74, 26, CLK_IS_CRITICAL);
+       hws[IMX6SLL_CLK_OCRAM]          = imx_clk_hw_gate_flags("ocram", "ahb",            base + 0x74, 28, CLK_IS_CRITICAL);
 
        /* CCGR4 */
-       clks[IMX6SLL_CLK_PWM1]          = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16);
-       clks[IMX6SLL_CLK_PWM2]          = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18);
-       clks[IMX6SLL_CLK_PWM3]          = imx_clk_gate2("pwm3", "perclk", base + 0x78, 20);
-       clks[IMX6SLL_CLK_PWM4]          = imx_clk_gate2("pwm4", "perclk", base + 0x78, 22);
+       hws[IMX6SLL_CLK_PWM1]           = imx_clk_hw_gate2("pwm1", "perclk", base + 0x78, 16);
+       hws[IMX6SLL_CLK_PWM2]           = imx_clk_hw_gate2("pwm2", "perclk", base + 0x78, 18);
+       hws[IMX6SLL_CLK_PWM3]           = imx_clk_hw_gate2("pwm3", "perclk", base + 0x78, 20);
+       hws[IMX6SLL_CLK_PWM4]           = imx_clk_hw_gate2("pwm4", "perclk", base + 0x78, 22);
 
        /* CCGR5 */
-       clks[IMX6SLL_CLK_ROM]           = imx_clk_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL);
-       clks[IMX6SLL_CLK_SDMA]          = imx_clk_gate2("sdma",  "ahb", base + 0x7c, 6);
-       clks[IMX6SLL_CLK_WDOG2]         = imx_clk_gate2("wdog2", "ipg", base + 0x7c, 10);
-       clks[IMX6SLL_CLK_SPBA]          = imx_clk_gate2("spba",  "ipg", base + 0x7c, 12);
-       clks[IMX6SLL_CLK_EXTERN_AUDIO]  = imx_clk_gate2_shared("extern_audio",  "extern_audio_podf", base + 0x7c, 14, &share_count_audio);
-       clks[IMX6SLL_CLK_SPDIF]         = imx_clk_gate2_shared("spdif",         "spdif_podf",   base + 0x7c, 14, &share_count_audio);
-       clks[IMX6SLL_CLK_SPDIF_GCLK]    = imx_clk_gate2_shared("spdif_gclk",    "ipg",          base + 0x7c, 14, &share_count_audio);
-       clks[IMX6SLL_CLK_SSI1]          = imx_clk_gate2_shared("ssi1",          "ssi1_podf",    base + 0x7c, 18, &share_count_ssi1);
-       clks[IMX6SLL_CLK_SSI1_IPG]      = imx_clk_gate2_shared("ssi1_ipg",      "ipg",          base + 0x7c, 18, &share_count_ssi1);
-       clks[IMX6SLL_CLK_SSI2]          = imx_clk_gate2_shared("ssi2",          "ssi2_podf",    base + 0x7c, 20, &share_count_ssi2);
-       clks[IMX6SLL_CLK_SSI2_IPG]      = imx_clk_gate2_shared("ssi2_ipg",      "ipg",          base + 0x7c, 20, &share_count_ssi2);
-       clks[IMX6SLL_CLK_SSI3]          = imx_clk_gate2_shared("ssi3",          "ssi3_podf",    base + 0x7c, 22, &share_count_ssi3);
-       clks[IMX6SLL_CLK_SSI3_IPG]      = imx_clk_gate2_shared("ssi3_ipg",      "ipg",          base + 0x7c, 22, &share_count_ssi3);
-       clks[IMX6SLL_CLK_UART1_IPG]     = imx_clk_gate2("uart1_ipg",    "ipg",          base + 0x7c, 24);
-       clks[IMX6SLL_CLK_UART1_SERIAL]  = imx_clk_gate2("uart1_serial", "uart_podf",    base + 0x7c, 24);
+       hws[IMX6SLL_CLK_ROM]            = imx_clk_hw_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL);
+       hws[IMX6SLL_CLK_SDMA]           = imx_clk_hw_gate2("sdma",       "ahb", base + 0x7c, 6);
+       hws[IMX6SLL_CLK_WDOG2]          = imx_clk_hw_gate2("wdog2", "ipg",      base + 0x7c, 10);
+       hws[IMX6SLL_CLK_SPBA]           = imx_clk_hw_gate2("spba",       "ipg", base + 0x7c, 12);
+       hws[IMX6SLL_CLK_EXTERN_AUDIO]   = imx_clk_hw_gate2_shared("extern_audio",  "extern_audio_podf", base + 0x7c, 14, &share_count_audio);
+       hws[IMX6SLL_CLK_SPDIF]          = imx_clk_hw_gate2_shared("spdif",              "spdif_podf",   base + 0x7c, 14, &share_count_audio);
+       hws[IMX6SLL_CLK_SPDIF_GCLK]     = imx_clk_hw_gate2_shared("spdif_gclk", "ipg",          base + 0x7c, 14, &share_count_audio);
+       hws[IMX6SLL_CLK_SSI1]           = imx_clk_hw_gate2_shared("ssi1",               "ssi1_podf",    base + 0x7c, 18, &share_count_ssi1);
+       hws[IMX6SLL_CLK_SSI1_IPG]       = imx_clk_hw_gate2_shared("ssi1_ipg",   "ipg",          base + 0x7c, 18, &share_count_ssi1);
+       hws[IMX6SLL_CLK_SSI2]           = imx_clk_hw_gate2_shared("ssi2",               "ssi2_podf",    base + 0x7c, 20, &share_count_ssi2);
+       hws[IMX6SLL_CLK_SSI2_IPG]       = imx_clk_hw_gate2_shared("ssi2_ipg",   "ipg",          base + 0x7c, 20, &share_count_ssi2);
+       hws[IMX6SLL_CLK_SSI3]           = imx_clk_hw_gate2_shared("ssi3",               "ssi3_podf",    base + 0x7c, 22, &share_count_ssi3);
+       hws[IMX6SLL_CLK_SSI3_IPG]       = imx_clk_hw_gate2_shared("ssi3_ipg",   "ipg",          base + 0x7c, 22, &share_count_ssi3);
+       hws[IMX6SLL_CLK_UART1_IPG]      = imx_clk_hw_gate2("uart1_ipg", "ipg",          base + 0x7c, 24);
+       hws[IMX6SLL_CLK_UART1_SERIAL]   = imx_clk_hw_gate2("uart1_serial",      "uart_podf",    base + 0x7c, 24);
 
        /* CCGR6 */
-       clks[IMX6SLL_CLK_USBOH3]        = imx_clk_gate2("usboh3", "ipg",          base + 0x80,  0);
-       clks[IMX6SLL_CLK_USDHC1]        = imx_clk_gate2("usdhc1", "usdhc1_podf",  base + 0x80,  2);
-       clks[IMX6SLL_CLK_USDHC2]        = imx_clk_gate2("usdhc2", "usdhc2_podf",  base + 0x80,  4);
-       clks[IMX6SLL_CLK_USDHC3]        = imx_clk_gate2("usdhc3", "usdhc3_podf",  base + 0x80,  6);
+       hws[IMX6SLL_CLK_USBOH3] = imx_clk_hw_gate2("usboh3", "ipg",       base + 0x80,  0);
+       hws[IMX6SLL_CLK_USDHC1] = imx_clk_hw_gate2("usdhc1", "usdhc1_podf",  base + 0x80,       2);
+       hws[IMX6SLL_CLK_USDHC2] = imx_clk_hw_gate2("usdhc2", "usdhc2_podf",  base + 0x80,       4);
+       hws[IMX6SLL_CLK_USDHC3] = imx_clk_hw_gate2("usdhc3", "usdhc3_podf",  base + 0x80,       6);
 
        /* mask handshake of mmdc */
-       writel_relaxed(BM_CCM_CCDR_MMDC_CH0_MASK, base + 0x4);
+       imx_mmdc_mask_handshake(base, 0);
 
-       imx_check_clocks(clks, ARRAY_SIZE(clks));
+       imx_check_clk_hws(hws, IMX6SLL_CLK_END);
 
-       clk_data.clks = clks;
-       clk_data.clk_num = ARRAY_SIZE(clks);
-       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+       of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
+
+       for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
+               int index = uart_clk_ids[i];
+
+               uart_clks[i] = &hws[index]->clk;
+       }
 
        imx_register_uart_clocks(uart_clks);
 
        /* Lower the AHB clock rate before changing the clock source. */
-       clk_set_rate(clks[IMX6SLL_CLK_AHB], 99000000);
+       clk_set_rate(hws[IMX6SLL_CLK_AHB]->clk, 99000000);
 
        /* Change periph_pre clock to pll2_bus to adjust AXI rate to 264MHz */
-       clk_set_parent(clks[IMX6SLL_CLK_PERIPH_CLK2_SEL], clks[IMX6SLL_CLK_PLL3_USB_OTG]);
-       clk_set_parent(clks[IMX6SLL_CLK_PERIPH], clks[IMX6SLL_CLK_PERIPH_CLK2]);
-       clk_set_parent(clks[IMX6SLL_CLK_PERIPH_PRE], clks[IMX6SLL_CLK_PLL2_BUS]);
-       clk_set_parent(clks[IMX6SLL_CLK_PERIPH], clks[IMX6SLL_CLK_PERIPH_PRE]);
+       clk_set_parent(hws[IMX6SLL_CLK_PERIPH_CLK2_SEL]->clk, hws[IMX6SLL_CLK_PLL3_USB_OTG]->clk);
+       clk_set_parent(hws[IMX6SLL_CLK_PERIPH]->clk, hws[IMX6SLL_CLK_PERIPH_CLK2]->clk);
+       clk_set_parent(hws[IMX6SLL_CLK_PERIPH_PRE]->clk, hws[IMX6SLL_CLK_PLL2_BUS]->clk);
+       clk_set_parent(hws[IMX6SLL_CLK_PERIPH]->clk, hws[IMX6SLL_CLK_PERIPH_PRE]->clk);
 
-       clk_set_rate(clks[IMX6SLL_CLK_AHB], 132000000);
+       clk_set_rate(hws[IMX6SLL_CLK_AHB]->clk, 132000000);
 }
 CLK_OF_DECLARE_DRIVER(imx6sll, "fsl,imx6sll-ccm", imx6sll_clocks_init);
index d243e34..c4685c0 100644 (file)
@@ -6,6 +6,7 @@
 #include <dt-bindings/clock/imx6sx-clock.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
+#include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
@@ -16,9 +17,6 @@
 
 #include "clk.h"
 
-#define CCDR    0x4
-#define BM_CCM_CCDR_MMDC_CH0_MASK       (0x2 << 16)
-
 static const char *step_sels[]         = { "osc", "pll2_pfd2_396m", };
 static const char *pll1_sw_sels[]      = { "pll1_sys", "step", };
 static const char *periph_pre_sels[]   = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll2_198m", };
@@ -83,8 +81,8 @@ static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", };
 static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", };
 static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
 
-static struct clk *clks[IMX6SX_CLK_CLK_END];
-static struct clk_onecell_data clk_data;
+static struct clk_hw **hws;
+static struct clk_hw_onecell_data *clk_hw_data;
 
 static const struct clk_div_table clk_enet_ref_table[] = {
        { .val = 0, .div = 20, },
@@ -118,76 +116,86 @@ static u32 share_count_ssi3;
 static u32 share_count_sai1;
 static u32 share_count_sai2;
 
-static struct clk ** const uart_clks[] __initconst = {
-       &clks[IMX6SX_CLK_UART_IPG],
-       &clks[IMX6SX_CLK_UART_SERIAL],
-       NULL
+static const int uart_clk_ids[] __initconst = {
+       IMX6SX_CLK_UART_IPG,
+       IMX6SX_CLK_UART_SERIAL,
 };
 
+static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata;
+
 static void __init imx6sx_clocks_init(struct device_node *ccm_node)
 {
        struct device_node *np;
        void __iomem *base;
+       int i;
+
+       clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
+                                         IMX6SX_CLK_CLK_END), GFP_KERNEL);
+       if (WARN_ON(!clk_hw_data))
+               return;
+
+       clk_hw_data->num = IMX6SX_CLK_CLK_END;
+       hws = clk_hw_data->hws;
 
-       clks[IMX6SX_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
+       hws[IMX6SX_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
 
-       clks[IMX6SX_CLK_CKIL] = of_clk_get_by_name(ccm_node, "ckil");
-       clks[IMX6SX_CLK_OSC] = of_clk_get_by_name(ccm_node, "osc");
+       hws[IMX6SX_CLK_CKIL] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ckil"));
+       hws[IMX6SX_CLK_OSC] = __clk_get_hw(of_clk_get_by_name(ccm_node, "osc"));
 
        /* ipp_di clock is external input */
-       clks[IMX6SX_CLK_IPP_DI0] = of_clk_get_by_name(ccm_node, "ipp_di0");
-       clks[IMX6SX_CLK_IPP_DI1] = of_clk_get_by_name(ccm_node, "ipp_di1");
+       hws[IMX6SX_CLK_IPP_DI0] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di0"));
+       hws[IMX6SX_CLK_IPP_DI1] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di1"));
 
        /* Clock source from external clock via CLK1/2 PAD */
-       clks[IMX6SX_CLK_ANACLK1] = of_clk_get_by_name(ccm_node, "anaclk1");
-       clks[IMX6SX_CLK_ANACLK2] = of_clk_get_by_name(ccm_node, "anaclk2");
+       hws[IMX6SX_CLK_ANACLK1] = __clk_get_hw(of_clk_get_by_name(ccm_node, "anaclk1"));
+       hws[IMX6SX_CLK_ANACLK2] = __clk_get_hw(of_clk_get_by_name(ccm_node, "anaclk2"));
 
        np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-anatop");
        base = of_iomap(np, 0);
        WARN_ON(!base);
        of_node_put(np);
 
-       clks[IMX6SX_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SX_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SX_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SX_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SX_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SX_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SX_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SX_PLL1_BYPASS_SRC] = imx_clk_hw_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SX_PLL2_BYPASS_SRC] = imx_clk_hw_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SX_PLL3_BYPASS_SRC] = imx_clk_hw_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SX_PLL4_BYPASS_SRC] = imx_clk_hw_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SX_PLL5_BYPASS_SRC] = imx_clk_hw_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SX_PLL6_BYPASS_SRC] = imx_clk_hw_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SX_PLL7_BYPASS_SRC] = imx_clk_hw_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
 
        /*                                    type               name    parent_name        base         div_mask */
-       clks[IMX6SX_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS,     "pll1", "osc", base + 0x00, 0x7f);
-       clks[IMX6SX_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
-       clks[IMX6SX_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB,     "pll3", "osc", base + 0x10, 0x3);
-       clks[IMX6SX_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV,      "pll4", "osc", base + 0x70, 0x7f);
-       clks[IMX6SX_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV,      "pll5", "osc", base + 0xa0, 0x7f);
-       clks[IMX6SX_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET,    "pll6", "osc", base + 0xe0, 0x3);
-       clks[IMX6SX_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB,     "pll7", "osc", base + 0x20, 0x3);
-
-       clks[IMX6SX_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SX_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SX_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SX_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SX_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SX_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SX_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_CLK_PLL1] = imx_clk_hw_pllv3(IMX_PLLV3_SYS,     "pll1", "osc", base + 0x00, 0x7f);
+       hws[IMX6SX_CLK_PLL2] = imx_clk_hw_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
+       hws[IMX6SX_CLK_PLL3] = imx_clk_hw_pllv3(IMX_PLLV3_USB,     "pll3", "osc", base + 0x10, 0x3);
+       hws[IMX6SX_CLK_PLL4] = imx_clk_hw_pllv3(IMX_PLLV3_AV,      "pll4", "osc", base + 0x70, 0x7f);
+       hws[IMX6SX_CLK_PLL5] = imx_clk_hw_pllv3(IMX_PLLV3_AV,      "pll5", "osc", base + 0xa0, 0x7f);
+       hws[IMX6SX_CLK_PLL6] = imx_clk_hw_pllv3(IMX_PLLV3_ENET,    "pll6", "osc", base + 0xe0, 0x3);
+       hws[IMX6SX_CLK_PLL7] = imx_clk_hw_pllv3(IMX_PLLV3_USB,     "pll7", "osc", base + 0x20, 0x3);
+
+       hws[IMX6SX_PLL1_BYPASS] = imx_clk_hw_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_PLL2_BYPASS] = imx_clk_hw_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_PLL3_BYPASS] = imx_clk_hw_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_PLL4_BYPASS] = imx_clk_hw_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_PLL5_BYPASS] = imx_clk_hw_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_PLL6_BYPASS] = imx_clk_hw_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_PLL7_BYPASS] = imx_clk_hw_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
 
        /* Do not bypass PLLs initially */
-       clk_set_parent(clks[IMX6SX_PLL1_BYPASS], clks[IMX6SX_CLK_PLL1]);
-       clk_set_parent(clks[IMX6SX_PLL2_BYPASS], clks[IMX6SX_CLK_PLL2]);
-       clk_set_parent(clks[IMX6SX_PLL3_BYPASS], clks[IMX6SX_CLK_PLL3]);
-       clk_set_parent(clks[IMX6SX_PLL4_BYPASS], clks[IMX6SX_CLK_PLL4]);
-       clk_set_parent(clks[IMX6SX_PLL5_BYPASS], clks[IMX6SX_CLK_PLL5]);
-       clk_set_parent(clks[IMX6SX_PLL6_BYPASS], clks[IMX6SX_CLK_PLL6]);
-       clk_set_parent(clks[IMX6SX_PLL7_BYPASS], clks[IMX6SX_CLK_PLL7]);
-
-       clks[IMX6SX_CLK_PLL1_SYS]      = imx_clk_gate("pll1_sys",      "pll1_bypass", base + 0x00, 13);
-       clks[IMX6SX_CLK_PLL2_BUS]      = imx_clk_gate("pll2_bus",      "pll2_bypass", base + 0x30, 13);
-       clks[IMX6SX_CLK_PLL3_USB_OTG]  = imx_clk_gate("pll3_usb_otg",  "pll3_bypass", base + 0x10, 13);
-       clks[IMX6SX_CLK_PLL4_AUDIO]    = imx_clk_gate("pll4_audio",    "pll4_bypass", base + 0x70, 13);
-       clks[IMX6SX_CLK_PLL5_VIDEO]    = imx_clk_gate("pll5_video",    "pll5_bypass", base + 0xa0, 13);
-       clks[IMX6SX_CLK_PLL6_ENET]     = imx_clk_gate("pll6_enet",     "pll6_bypass", base + 0xe0, 13);
-       clks[IMX6SX_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
+       clk_set_parent(hws[IMX6SX_PLL1_BYPASS]->clk, hws[IMX6SX_CLK_PLL1]->clk);
+       clk_set_parent(hws[IMX6SX_PLL2_BYPASS]->clk, hws[IMX6SX_CLK_PLL2]->clk);
+       clk_set_parent(hws[IMX6SX_PLL3_BYPASS]->clk, hws[IMX6SX_CLK_PLL3]->clk);
+       clk_set_parent(hws[IMX6SX_PLL4_BYPASS]->clk, hws[IMX6SX_CLK_PLL4]->clk);
+       clk_set_parent(hws[IMX6SX_PLL5_BYPASS]->clk, hws[IMX6SX_CLK_PLL5]->clk);
+       clk_set_parent(hws[IMX6SX_PLL6_BYPASS]->clk, hws[IMX6SX_CLK_PLL6]->clk);
+       clk_set_parent(hws[IMX6SX_PLL7_BYPASS]->clk, hws[IMX6SX_CLK_PLL7]->clk);
+
+       hws[IMX6SX_CLK_PLL1_SYS]      = imx_clk_hw_gate("pll1_sys",      "pll1_bypass", base + 0x00, 13);
+       hws[IMX6SX_CLK_PLL2_BUS]      = imx_clk_hw_gate("pll2_bus",      "pll2_bypass", base + 0x30, 13);
+       hws[IMX6SX_CLK_PLL3_USB_OTG]  = imx_clk_hw_gate("pll3_usb_otg",  "pll3_bypass", base + 0x10, 13);
+       hws[IMX6SX_CLK_PLL4_AUDIO]    = imx_clk_hw_gate("pll4_audio",    "pll4_bypass", base + 0x70, 13);
+       hws[IMX6SX_CLK_PLL5_VIDEO]    = imx_clk_hw_gate("pll5_video",    "pll5_bypass", base + 0xa0, 13);
+       hws[IMX6SX_CLK_PLL6_ENET]     = imx_clk_hw_gate("pll6_enet",     "pll6_bypass", base + 0xe0, 13);
+       hws[IMX6SX_CLK_PLL7_USB_HOST] = imx_clk_hw_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
 
        /*
         * Bit 20 is the reserved and read-only bit, we do this only for:
@@ -195,361 +203,363 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
         * - Keep refcount when do usbphy clk_enable/disable, in that case,
         * the clk framework may need to enable/disable usbphy's parent
         */
-       clks[IMX6SX_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg",  base + 0x10, 20);
-       clks[IMX6SX_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
+       hws[IMX6SX_CLK_USBPHY1] = imx_clk_hw_gate("usbphy1", "pll3_usb_otg",  base + 0x10, 20);
+       hws[IMX6SX_CLK_USBPHY2] = imx_clk_hw_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
 
        /*
         * usbphy*_gate needs to be on after system boots up, and software
         * never needs to control it anymore.
         */
-       clks[IMX6SX_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6);
-       clks[IMX6SX_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6);
+       hws[IMX6SX_CLK_USBPHY1_GATE] = imx_clk_hw_gate("usbphy1_gate", "dummy", base + 0x10, 6);
+       hws[IMX6SX_CLK_USBPHY2_GATE] = imx_clk_hw_gate("usbphy2_gate", "dummy", base + 0x20, 6);
 
        /* FIXME 100MHz is used for pcie ref for all imx6 pcie, excepted imx6q */
-       clks[IMX6SX_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 5);
-       clks[IMX6SX_CLK_PCIE_REF_125M] = imx_clk_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19);
+       hws[IMX6SX_CLK_PCIE_REF] = imx_clk_hw_fixed_factor("pcie_ref", "pll6_enet", 1, 5);
+       hws[IMX6SX_CLK_PCIE_REF_125M] = imx_clk_hw_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19);
 
-       clks[IMX6SX_CLK_LVDS1_OUT] = imx_clk_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x160, 10, BIT(12));
-       clks[IMX6SX_CLK_LVDS2_OUT] = imx_clk_gate_exclusive("lvds2_out", "lvds2_sel", base + 0x160, 11, BIT(13));
-       clks[IMX6SX_CLK_LVDS1_IN]  = imx_clk_gate_exclusive("lvds1_in",  "anaclk1",   base + 0x160, 12, BIT(10));
-       clks[IMX6SX_CLK_LVDS2_IN]  = imx_clk_gate_exclusive("lvds2_in",  "anaclk2",   base + 0x160, 13, BIT(11));
+       hws[IMX6SX_CLK_LVDS1_OUT] = imx_clk_hw_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x160, 10, BIT(12));
+       hws[IMX6SX_CLK_LVDS2_OUT] = imx_clk_hw_gate_exclusive("lvds2_out", "lvds2_sel", base + 0x160, 11, BIT(13));
+       hws[IMX6SX_CLK_LVDS1_IN]  = imx_clk_hw_gate_exclusive("lvds1_in",  "anaclk1",   base + 0x160, 12, BIT(10));
+       hws[IMX6SX_CLK_LVDS2_IN]  = imx_clk_hw_gate_exclusive("lvds2_in",  "anaclk2",   base + 0x160, 13, BIT(11));
 
-       clks[IMX6SX_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
+       hws[IMX6SX_CLK_ENET_REF] = clk_hw_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
                        base + 0xe0, 0, 2, 0, clk_enet_ref_table,
                        &imx_ccm_lock);
-       clks[IMX6SX_CLK_ENET2_REF] = clk_register_divider_table(NULL, "enet2_ref", "pll6_enet", 0,
+       hws[IMX6SX_CLK_ENET2_REF] = clk_hw_register_divider_table(NULL, "enet2_ref", "pll6_enet", 0,
                        base + 0xe0, 2, 2, 0, clk_enet_ref_table,
                        &imx_ccm_lock);
-       clks[IMX6SX_CLK_ENET2_REF_125M] = imx_clk_gate("enet2_ref_125m", "enet2_ref", base + 0xe0, 20);
+       hws[IMX6SX_CLK_ENET2_REF_125M] = imx_clk_hw_gate("enet2_ref_125m", "enet2_ref", base + 0xe0, 20);
 
-       clks[IMX6SX_CLK_ENET_PTP_REF] = imx_clk_fixed_factor("enet_ptp_ref", "pll6_enet", 1, 20);
-       clks[IMX6SX_CLK_ENET_PTP] = imx_clk_gate("enet_ptp_25m", "enet_ptp_ref", base + 0xe0, 21);
+       hws[IMX6SX_CLK_ENET_PTP_REF] = imx_clk_hw_fixed_factor("enet_ptp_ref", "pll6_enet", 1, 20);
+       hws[IMX6SX_CLK_ENET_PTP] = imx_clk_hw_gate("enet_ptp_25m", "enet_ptp_ref", base + 0xe0, 21);
 
        /*                                       name              parent_name     reg           idx */
-       clks[IMX6SX_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus",     base + 0x100, 0);
-       clks[IMX6SX_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus",     base + 0x100, 1);
-       clks[IMX6SX_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus",     base + 0x100, 2);
-       clks[IMX6SX_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3_594m", "pll2_bus",     base + 0x100, 3);
-       clks[IMX6SX_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0,  0);
-       clks[IMX6SX_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0,  1);
-       clks[IMX6SX_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0,  2);
-       clks[IMX6SX_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0,  3);
+       hws[IMX6SX_CLK_PLL2_PFD0] = imx_clk_hw_pfd("pll2_pfd0_352m", "pll2_bus",     base + 0x100, 0);
+       hws[IMX6SX_CLK_PLL2_PFD1] = imx_clk_hw_pfd("pll2_pfd1_594m", "pll2_bus",     base + 0x100, 1);
+       hws[IMX6SX_CLK_PLL2_PFD2] = imx_clk_hw_pfd("pll2_pfd2_396m", "pll2_bus",     base + 0x100, 2);
+       hws[IMX6SX_CLK_PLL2_PFD3] = imx_clk_hw_pfd("pll2_pfd3_594m", "pll2_bus",     base + 0x100, 3);
+       hws[IMX6SX_CLK_PLL3_PFD0] = imx_clk_hw_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0,  0);
+       hws[IMX6SX_CLK_PLL3_PFD1] = imx_clk_hw_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0,  1);
+       hws[IMX6SX_CLK_PLL3_PFD2] = imx_clk_hw_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0,  2);
+       hws[IMX6SX_CLK_PLL3_PFD3] = imx_clk_hw_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0,  3);
 
        /*                                                name         parent_name       mult div */
-       clks[IMX6SX_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1,   2);
-       clks[IMX6SX_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg",   1,   4);
-       clks[IMX6SX_CLK_PLL3_80M]  = imx_clk_fixed_factor("pll3_80m",  "pll3_usb_otg",   1,   6);
-       clks[IMX6SX_CLK_PLL3_60M]  = imx_clk_fixed_factor("pll3_60m",  "pll3_usb_otg",   1,   8);
-       clks[IMX6SX_CLK_TWD]       = imx_clk_fixed_factor("twd",       "arm",            1,   2);
-       clks[IMX6SX_CLK_GPT_3M]    = imx_clk_fixed_factor("gpt_3m",    "osc",            1,   8);
-
-       clks[IMX6SX_CLK_PLL4_POST_DIV]  = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio",
+       hws[IMX6SX_CLK_PLL2_198M] = imx_clk_hw_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1,   2);
+       hws[IMX6SX_CLK_PLL3_120M] = imx_clk_hw_fixed_factor("pll3_120m", "pll3_usb_otg",   1,   4);
+       hws[IMX6SX_CLK_PLL3_80M]  = imx_clk_hw_fixed_factor("pll3_80m",  "pll3_usb_otg",   1,   6);
+       hws[IMX6SX_CLK_PLL3_60M]  = imx_clk_hw_fixed_factor("pll3_60m",  "pll3_usb_otg",   1,   8);
+       hws[IMX6SX_CLK_TWD]       = imx_clk_hw_fixed_factor("twd",       "arm",            1,   2);
+       hws[IMX6SX_CLK_GPT_3M]    = imx_clk_hw_fixed_factor("gpt_3m",    "osc",            1,   8);
+
+       hws[IMX6SX_CLK_PLL4_POST_DIV]  = clk_hw_register_divider_table(NULL, "pll4_post_div", "pll4_audio",
                                CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
-       clks[IMX6SX_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div",
+       hws[IMX6SX_CLK_PLL4_AUDIO_DIV] = clk_hw_register_divider(NULL, "pll4_audio_div", "pll4_post_div",
                                CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock);
-       clks[IMX6SX_CLK_PLL5_POST_DIV]  = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video",
+       hws[IMX6SX_CLK_PLL5_POST_DIV]  = clk_hw_register_divider_table(NULL, "pll5_post_div", "pll5_video",
                                CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
-       clks[IMX6SX_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div",
+       hws[IMX6SX_CLK_PLL5_VIDEO_DIV] = clk_hw_register_divider_table(NULL, "pll5_video_div", "pll5_post_div",
                                CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
 
        /*                                                name                reg           shift   width   parent_names       num_parents */
-       clks[IMX6SX_CLK_LVDS1_SEL]          = imx_clk_mux("lvds1_sel",        base + 0x160, 0,      5,      lvds_sels,         ARRAY_SIZE(lvds_sels));
-       clks[IMX6SX_CLK_LVDS2_SEL]          = imx_clk_mux("lvds2_sel",        base + 0x160, 5,      5,      lvds_sels,         ARRAY_SIZE(lvds_sels));
+       hws[IMX6SX_CLK_LVDS1_SEL]          = imx_clk_hw_mux("lvds1_sel",        base + 0x160, 0,      5,      lvds_sels,         ARRAY_SIZE(lvds_sels));
+       hws[IMX6SX_CLK_LVDS2_SEL]          = imx_clk_hw_mux("lvds2_sel",        base + 0x160, 5,      5,      lvds_sels,         ARRAY_SIZE(lvds_sels));
 
        np = ccm_node;
        base = of_iomap(np, 0);
        WARN_ON(!base);
 
        /*                                                name                reg           shift   width   parent_names       num_parents */
-       clks[IMX6SX_CLK_STEP]               = imx_clk_mux("step",             base + 0xc,   8,      1,      step_sels,         ARRAY_SIZE(step_sels));
-       clks[IMX6SX_CLK_PLL1_SW]            = imx_clk_mux("pll1_sw",          base + 0xc,   2,      1,      pll1_sw_sels,      ARRAY_SIZE(pll1_sw_sels));
-       clks[IMX6SX_CLK_OCRAM_SEL]          = imx_clk_mux("ocram_sel",        base + 0x14,  6,      2,      ocram_sels,        ARRAY_SIZE(ocram_sels));
-       clks[IMX6SX_CLK_PERIPH_PRE]         = imx_clk_mux("periph_pre",       base + 0x18,  18,     2,      periph_pre_sels,   ARRAY_SIZE(periph_pre_sels));
-       clks[IMX6SX_CLK_PERIPH2_PRE]        = imx_clk_mux("periph2_pre",      base + 0x18,  21,     2,      periph2_pre_sels,   ARRAY_SIZE(periph2_pre_sels));
-       clks[IMX6SX_CLK_PERIPH_CLK2_SEL]    = imx_clk_mux("periph_clk2_sel",  base + 0x18,  12,     2,      periph_clk2_sels,  ARRAY_SIZE(periph_clk2_sels));
-       clks[IMX6SX_CLK_PERIPH2_CLK2_SEL]   = imx_clk_mux("periph2_clk2_sel", base + 0x18,  20,     1,      periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
-       clks[IMX6SX_CLK_PCIE_AXI_SEL]       = imx_clk_mux("pcie_axi_sel",     base + 0x18,  10,     1,      pcie_axi_sels,     ARRAY_SIZE(pcie_axi_sels));
-       clks[IMX6SX_CLK_GPU_AXI_SEL]        = imx_clk_mux("gpu_axi_sel",      base + 0x18,  8,      2,      gpu_axi_sels,      ARRAY_SIZE(gpu_axi_sels));
-       clks[IMX6SX_CLK_GPU_CORE_SEL]       = imx_clk_mux("gpu_core_sel",     base + 0x18,  4,      2,      gpu_core_sels,     ARRAY_SIZE(gpu_core_sels));
-       clks[IMX6SX_CLK_EIM_SLOW_SEL]       = imx_clk_mux("eim_slow_sel",     base + 0x1c,  29,     2,      eim_slow_sels,     ARRAY_SIZE(eim_slow_sels));
-       clks[IMX6SX_CLK_USDHC1_SEL]         = imx_clk_mux("usdhc1_sel",       base + 0x1c,  16,     1,      usdhc_sels,        ARRAY_SIZE(usdhc_sels));
-       clks[IMX6SX_CLK_USDHC2_SEL]         = imx_clk_mux("usdhc2_sel",       base + 0x1c,  17,     1,      usdhc_sels,        ARRAY_SIZE(usdhc_sels));
-       clks[IMX6SX_CLK_USDHC3_SEL]         = imx_clk_mux("usdhc3_sel",       base + 0x1c,  18,     1,      usdhc_sels,        ARRAY_SIZE(usdhc_sels));
-       clks[IMX6SX_CLK_USDHC4_SEL]         = imx_clk_mux("usdhc4_sel",       base + 0x1c,  19,     1,      usdhc_sels,        ARRAY_SIZE(usdhc_sels));
-       clks[IMX6SX_CLK_SSI3_SEL]           = imx_clk_mux("ssi3_sel",         base + 0x1c,  14,     2,      ssi_sels,          ARRAY_SIZE(ssi_sels));
-       clks[IMX6SX_CLK_SSI2_SEL]           = imx_clk_mux("ssi2_sel",         base + 0x1c,  12,     2,      ssi_sels,          ARRAY_SIZE(ssi_sels));
-       clks[IMX6SX_CLK_SSI1_SEL]           = imx_clk_mux("ssi1_sel",         base + 0x1c,  10,     2,      ssi_sels,          ARRAY_SIZE(ssi_sels));
-       clks[IMX6SX_CLK_QSPI1_SEL]          = imx_clk_mux_flags("qspi1_sel", base + 0x1c,  7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SX_CLK_PERCLK_SEL]         = imx_clk_mux("perclk_sel",       base + 0x1c,  6,      1,      perclk_sels,       ARRAY_SIZE(perclk_sels));
-       clks[IMX6SX_CLK_VID_SEL]            = imx_clk_mux("vid_sel",          base + 0x20,  21,     3,      vid_sels,          ARRAY_SIZE(vid_sels));
-       clks[IMX6SX_CLK_ESAI_SEL]           = imx_clk_mux("esai_sel",         base + 0x20,  19,     2,      audio_sels,        ARRAY_SIZE(audio_sels));
-       clks[IMX6SX_CLK_CAN_SEL]            = imx_clk_mux("can_sel",          base + 0x20,  8,      2,      can_sels,          ARRAY_SIZE(can_sels));
-       clks[IMX6SX_CLK_UART_SEL]           = imx_clk_mux("uart_sel",         base + 0x24,  6,      1,      uart_sels,         ARRAY_SIZE(uart_sels));
-       clks[IMX6SX_CLK_QSPI2_SEL]          = imx_clk_mux_flags("qspi2_sel", base + 0x2c, 15, 3, qspi2_sels, ARRAY_SIZE(qspi2_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SX_CLK_SPDIF_SEL]          = imx_clk_mux("spdif_sel",        base + 0x30,  20,     2,      audio_sels,        ARRAY_SIZE(audio_sels));
-       clks[IMX6SX_CLK_AUDIO_SEL]          = imx_clk_mux("audio_sel",        base + 0x30,  7,      2,      audio_sels,        ARRAY_SIZE(audio_sels));
-       clks[IMX6SX_CLK_ENET_PRE_SEL]       = imx_clk_mux("enet_pre_sel",     base + 0x34,  15,     3,      enet_pre_sels,     ARRAY_SIZE(enet_pre_sels));
-       clks[IMX6SX_CLK_ENET_SEL]           = imx_clk_mux("enet_sel",         base + 0x34,  9,      3,      enet_sels,         ARRAY_SIZE(enet_sels));
-       clks[IMX6SX_CLK_M4_PRE_SEL]         = imx_clk_mux("m4_pre_sel",       base + 0x34,  6,      3,      m4_pre_sels,       ARRAY_SIZE(m4_pre_sels));
-       clks[IMX6SX_CLK_M4_SEL]             = imx_clk_mux("m4_sel",           base + 0x34,  0,      3,      m4_sels,           ARRAY_SIZE(m4_sels));
-       clks[IMX6SX_CLK_ECSPI_SEL]          = imx_clk_mux("ecspi_sel",        base + 0x38,  18,     1,      ecspi_sels,        ARRAY_SIZE(ecspi_sels));
-       clks[IMX6SX_CLK_LCDIF2_PRE_SEL]     = imx_clk_mux("lcdif2_pre_sel",   base + 0x38,  6,      3,      lcdif2_pre_sels,   ARRAY_SIZE(lcdif2_pre_sels));
-       clks[IMX6SX_CLK_LCDIF2_SEL]         = imx_clk_mux("lcdif2_sel",       base + 0x38,  0,      3,      lcdif2_sels,       ARRAY_SIZE(lcdif2_sels));
-       clks[IMX6SX_CLK_DISPLAY_SEL]        = imx_clk_mux("display_sel",      base + 0x3c,  14,     2,      display_sels,      ARRAY_SIZE(display_sels));
-       clks[IMX6SX_CLK_CSI_SEL]            = imx_clk_mux("csi_sel",          base + 0x3c,  9,      2,      csi_sels,          ARRAY_SIZE(csi_sels));
-       clks[IMX6SX_CLK_CKO1_SEL]           = imx_clk_mux("cko1_sel",         base + 0x60,  0,      4,      cko1_sels,         ARRAY_SIZE(cko1_sels));
-       clks[IMX6SX_CLK_CKO2_SEL]           = imx_clk_mux("cko2_sel",         base + 0x60,  16,     5,      cko2_sels,         ARRAY_SIZE(cko2_sels));
-       clks[IMX6SX_CLK_CKO]                = imx_clk_mux("cko",              base + 0x60,  8,      1,      cko_sels,          ARRAY_SIZE(cko_sels));
-
-       clks[IMX6SX_CLK_LDB_DI1_DIV_SEL]    = imx_clk_mux_flags("ldb_di1_div_sel", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SX_CLK_LDB_DI0_DIV_SEL]    = imx_clk_mux_flags("ldb_di0_div_sel", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SX_CLK_LDB_DI1_SEL]        = imx_clk_mux_flags("ldb_di1_sel",     base + 0x2c, 12, 3, ldb_di1_sels,      ARRAY_SIZE(ldb_di1_sels),    CLK_SET_RATE_PARENT);
-       clks[IMX6SX_CLK_LDB_DI0_SEL]        = imx_clk_mux_flags("ldb_di0_sel",     base + 0x2c, 9,  3, ldb_di0_sels,      ARRAY_SIZE(ldb_di0_sels),    CLK_SET_RATE_PARENT);
-       clks[IMX6SX_CLK_LCDIF1_PRE_SEL]     = imx_clk_mux_flags("lcdif1_pre_sel",  base + 0x38, 15, 3, lcdif1_pre_sels,   ARRAY_SIZE(lcdif1_pre_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SX_CLK_LCDIF1_SEL]         = imx_clk_mux_flags("lcdif1_sel",      base + 0x38, 9,  3, lcdif1_sels,       ARRAY_SIZE(lcdif1_sels),     CLK_SET_RATE_PARENT);
+       hws[IMX6SX_CLK_STEP]               = imx_clk_hw_mux("step",             base + 0xc,   8,      1,      step_sels,         ARRAY_SIZE(step_sels));
+       hws[IMX6SX_CLK_PLL1_SW]            = imx_clk_hw_mux("pll1_sw",          base + 0xc,   2,      1,      pll1_sw_sels,      ARRAY_SIZE(pll1_sw_sels));
+       hws[IMX6SX_CLK_OCRAM_SEL]          = imx_clk_hw_mux("ocram_sel",        base + 0x14,  6,      2,      ocram_sels,        ARRAY_SIZE(ocram_sels));
+       hws[IMX6SX_CLK_PERIPH_PRE]         = imx_clk_hw_mux("periph_pre",       base + 0x18,  18,     2,      periph_pre_sels,   ARRAY_SIZE(periph_pre_sels));
+       hws[IMX6SX_CLK_PERIPH2_PRE]        = imx_clk_hw_mux("periph2_pre",      base + 0x18,  21,     2,      periph2_pre_sels,   ARRAY_SIZE(periph2_pre_sels));
+       hws[IMX6SX_CLK_PERIPH_CLK2_SEL]    = imx_clk_hw_mux("periph_clk2_sel",  base + 0x18,  12,     2,      periph_clk2_sels,  ARRAY_SIZE(periph_clk2_sels));
+       hws[IMX6SX_CLK_PERIPH2_CLK2_SEL]   = imx_clk_hw_mux("periph2_clk2_sel", base + 0x18,  20,     1,      periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
+       hws[IMX6SX_CLK_PCIE_AXI_SEL]       = imx_clk_hw_mux("pcie_axi_sel",     base + 0x18,  10,     1,      pcie_axi_sels,     ARRAY_SIZE(pcie_axi_sels));
+       hws[IMX6SX_CLK_GPU_AXI_SEL]        = imx_clk_hw_mux("gpu_axi_sel",      base + 0x18,  8,      2,      gpu_axi_sels,      ARRAY_SIZE(gpu_axi_sels));
+       hws[IMX6SX_CLK_GPU_CORE_SEL]       = imx_clk_hw_mux("gpu_core_sel",     base + 0x18,  4,      2,      gpu_core_sels,     ARRAY_SIZE(gpu_core_sels));
+       hws[IMX6SX_CLK_EIM_SLOW_SEL]       = imx_clk_hw_mux("eim_slow_sel",     base + 0x1c,  29,     2,      eim_slow_sels,     ARRAY_SIZE(eim_slow_sels));
+       hws[IMX6SX_CLK_USDHC1_SEL]         = imx_clk_hw_mux("usdhc1_sel",       base + 0x1c,  16,     1,      usdhc_sels,        ARRAY_SIZE(usdhc_sels));
+       hws[IMX6SX_CLK_USDHC2_SEL]         = imx_clk_hw_mux("usdhc2_sel",       base + 0x1c,  17,     1,      usdhc_sels,        ARRAY_SIZE(usdhc_sels));
+       hws[IMX6SX_CLK_USDHC3_SEL]         = imx_clk_hw_mux("usdhc3_sel",       base + 0x1c,  18,     1,      usdhc_sels,        ARRAY_SIZE(usdhc_sels));
+       hws[IMX6SX_CLK_USDHC4_SEL]         = imx_clk_hw_mux("usdhc4_sel",       base + 0x1c,  19,     1,      usdhc_sels,        ARRAY_SIZE(usdhc_sels));
+       hws[IMX6SX_CLK_SSI3_SEL]           = imx_clk_hw_mux("ssi3_sel",         base + 0x1c,  14,     2,      ssi_sels,          ARRAY_SIZE(ssi_sels));
+       hws[IMX6SX_CLK_SSI2_SEL]           = imx_clk_hw_mux("ssi2_sel",         base + 0x1c,  12,     2,      ssi_sels,          ARRAY_SIZE(ssi_sels));
+       hws[IMX6SX_CLK_SSI1_SEL]           = imx_clk_hw_mux("ssi1_sel",         base + 0x1c,  10,     2,      ssi_sels,          ARRAY_SIZE(ssi_sels));
+       hws[IMX6SX_CLK_QSPI1_SEL]          = imx_clk_hw_mux_flags("qspi1_sel", base + 0x1c,  7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_CLK_PERCLK_SEL]         = imx_clk_hw_mux("perclk_sel",       base + 0x1c,  6,      1,      perclk_sels,       ARRAY_SIZE(perclk_sels));
+       hws[IMX6SX_CLK_VID_SEL]            = imx_clk_hw_mux("vid_sel",          base + 0x20,  21,     3,      vid_sels,          ARRAY_SIZE(vid_sels));
+       hws[IMX6SX_CLK_ESAI_SEL]           = imx_clk_hw_mux("esai_sel",         base + 0x20,  19,     2,      audio_sels,        ARRAY_SIZE(audio_sels));
+       hws[IMX6SX_CLK_CAN_SEL]            = imx_clk_hw_mux("can_sel",          base + 0x20,  8,      2,      can_sels,          ARRAY_SIZE(can_sels));
+       hws[IMX6SX_CLK_UART_SEL]           = imx_clk_hw_mux("uart_sel",         base + 0x24,  6,      1,      uart_sels,         ARRAY_SIZE(uart_sels));
+       hws[IMX6SX_CLK_QSPI2_SEL]          = imx_clk_hw_mux_flags("qspi2_sel", base + 0x2c, 15, 3, qspi2_sels, ARRAY_SIZE(qspi2_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_CLK_SPDIF_SEL]          = imx_clk_hw_mux("spdif_sel",        base + 0x30,  20,     2,      audio_sels,        ARRAY_SIZE(audio_sels));
+       hws[IMX6SX_CLK_AUDIO_SEL]          = imx_clk_hw_mux("audio_sel",        base + 0x30,  7,      2,      audio_sels,        ARRAY_SIZE(audio_sels));
+       hws[IMX6SX_CLK_ENET_PRE_SEL]       = imx_clk_hw_mux("enet_pre_sel",     base + 0x34,  15,     3,      enet_pre_sels,     ARRAY_SIZE(enet_pre_sels));
+       hws[IMX6SX_CLK_ENET_SEL]           = imx_clk_hw_mux("enet_sel",         base + 0x34,  9,      3,      enet_sels,         ARRAY_SIZE(enet_sels));
+       hws[IMX6SX_CLK_M4_PRE_SEL]         = imx_clk_hw_mux("m4_pre_sel",       base + 0x34,  6,      3,      m4_pre_sels,       ARRAY_SIZE(m4_pre_sels));
+       hws[IMX6SX_CLK_M4_SEL]             = imx_clk_hw_mux("m4_sel",           base + 0x34,  0,      3,      m4_sels,           ARRAY_SIZE(m4_sels));
+       hws[IMX6SX_CLK_ECSPI_SEL]          = imx_clk_hw_mux("ecspi_sel",        base + 0x38,  18,     1,      ecspi_sels,        ARRAY_SIZE(ecspi_sels));
+       hws[IMX6SX_CLK_LCDIF2_PRE_SEL]     = imx_clk_hw_mux("lcdif2_pre_sel",   base + 0x38,  6,      3,      lcdif2_pre_sels,   ARRAY_SIZE(lcdif2_pre_sels));
+       hws[IMX6SX_CLK_LCDIF2_SEL]         = imx_clk_hw_mux("lcdif2_sel",       base + 0x38,  0,      3,      lcdif2_sels,       ARRAY_SIZE(lcdif2_sels));
+       hws[IMX6SX_CLK_DISPLAY_SEL]        = imx_clk_hw_mux("display_sel",      base + 0x3c,  14,     2,      display_sels,      ARRAY_SIZE(display_sels));
+       hws[IMX6SX_CLK_CSI_SEL]            = imx_clk_hw_mux("csi_sel",          base + 0x3c,  9,      2,      csi_sels,          ARRAY_SIZE(csi_sels));
+       hws[IMX6SX_CLK_CKO1_SEL]           = imx_clk_hw_mux("cko1_sel",         base + 0x60,  0,      4,      cko1_sels,         ARRAY_SIZE(cko1_sels));
+       hws[IMX6SX_CLK_CKO2_SEL]           = imx_clk_hw_mux("cko2_sel",         base + 0x60,  16,     5,      cko2_sels,         ARRAY_SIZE(cko2_sels));
+       hws[IMX6SX_CLK_CKO]                = imx_clk_hw_mux("cko",              base + 0x60,  8,      1,      cko_sels,          ARRAY_SIZE(cko_sels));
+
+       hws[IMX6SX_CLK_LDB_DI1_DIV_SEL]    = imx_clk_hw_mux_flags("ldb_di1_div_sel", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_CLK_LDB_DI0_DIV_SEL]    = imx_clk_hw_mux_flags("ldb_di0_div_sel", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_CLK_LDB_DI1_SEL]        = imx_clk_hw_mux_flags("ldb_di1_sel",     base + 0x2c, 12, 3, ldb_di1_sels,      ARRAY_SIZE(ldb_di1_sels),    CLK_SET_RATE_PARENT);
+       hws[IMX6SX_CLK_LDB_DI0_SEL]        = imx_clk_hw_mux_flags("ldb_di0_sel",     base + 0x2c, 9,  3, ldb_di0_sels,      ARRAY_SIZE(ldb_di0_sels),    CLK_SET_RATE_PARENT);
+       hws[IMX6SX_CLK_LCDIF1_PRE_SEL]     = imx_clk_hw_mux_flags("lcdif1_pre_sel",  base + 0x38, 15, 3, lcdif1_pre_sels,   ARRAY_SIZE(lcdif1_pre_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_CLK_LCDIF1_SEL]         = imx_clk_hw_mux_flags("lcdif1_sel",      base + 0x38, 9,  3, lcdif1_sels,       ARRAY_SIZE(lcdif1_sels),     CLK_SET_RATE_PARENT);
 
        /*                                                    name              parent_name          reg          shift width */
-       clks[IMX6SX_CLK_PERIPH_CLK2]        = imx_clk_divider("periph_clk2",    "periph_clk2_sel",   base + 0x14, 27,   3);
-       clks[IMX6SX_CLK_PERIPH2_CLK2]       = imx_clk_divider("periph2_clk2",   "periph2_clk2_sel",  base + 0x14, 0,    3);
-       clks[IMX6SX_CLK_IPG]                = imx_clk_divider("ipg",            "ahb",               base + 0x14, 8,    2);
-       clks[IMX6SX_CLK_GPU_CORE_PODF]      = imx_clk_divider("gpu_core_podf",  "gpu_core_sel",      base + 0x18, 29,   3);
-       clks[IMX6SX_CLK_GPU_AXI_PODF]       = imx_clk_divider("gpu_axi_podf",   "gpu_axi_sel",       base + 0x18, 26,   3);
-       clks[IMX6SX_CLK_LCDIF1_PODF]        = imx_clk_divider("lcdif1_podf",    "lcdif1_pred",       base + 0x18, 23,   3);
-       clks[IMX6SX_CLK_QSPI1_PODF]         = imx_clk_divider("qspi1_podf",     "qspi1_sel",         base + 0x1c, 26,   3);
-       clks[IMX6SX_CLK_EIM_SLOW_PODF]      = imx_clk_divider("eim_slow_podf",  "eim_slow_sel",      base + 0x1c, 23,   3);
-       clks[IMX6SX_CLK_LCDIF2_PODF]        = imx_clk_divider("lcdif2_podf",    "lcdif2_pred",       base + 0x1c, 20,   3);
-       clks[IMX6SX_CLK_PERCLK]             = imx_clk_divider_flags("perclk", "perclk_sel", base + 0x1c, 0, 6, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_VID_PODF]           = imx_clk_divider("vid_podf",       "vid_sel",           base + 0x20, 24,   2);
-       clks[IMX6SX_CLK_CAN_PODF]           = imx_clk_divider("can_podf",       "can_sel",           base + 0x20, 2,    6);
-       clks[IMX6SX_CLK_USDHC4_PODF]        = imx_clk_divider("usdhc4_podf",    "usdhc4_sel",        base + 0x24, 22,   3);
-       clks[IMX6SX_CLK_USDHC3_PODF]        = imx_clk_divider("usdhc3_podf",    "usdhc3_sel",        base + 0x24, 19,   3);
-       clks[IMX6SX_CLK_USDHC2_PODF]        = imx_clk_divider("usdhc2_podf",    "usdhc2_sel",        base + 0x24, 16,   3);
-       clks[IMX6SX_CLK_USDHC1_PODF]        = imx_clk_divider("usdhc1_podf",    "usdhc1_sel",        base + 0x24, 11,   3);
-       clks[IMX6SX_CLK_UART_PODF]          = imx_clk_divider("uart_podf",      "uart_sel",          base + 0x24, 0,    6);
-       clks[IMX6SX_CLK_ESAI_PRED]          = imx_clk_divider("esai_pred",      "esai_sel",          base + 0x28, 9,    3);
-       clks[IMX6SX_CLK_ESAI_PODF]          = imx_clk_divider("esai_podf",      "esai_pred",         base + 0x28, 25,   3);
-       clks[IMX6SX_CLK_SSI3_PRED]          = imx_clk_divider("ssi3_pred",      "ssi3_sel",          base + 0x28, 22,   3);
-       clks[IMX6SX_CLK_SSI3_PODF]          = imx_clk_divider("ssi3_podf",      "ssi3_pred",         base + 0x28, 16,   6);
-       clks[IMX6SX_CLK_SSI1_PRED]          = imx_clk_divider("ssi1_pred",      "ssi1_sel",          base + 0x28, 6,    3);
-       clks[IMX6SX_CLK_SSI1_PODF]          = imx_clk_divider("ssi1_podf",      "ssi1_pred",         base + 0x28, 0,    6);
-       clks[IMX6SX_CLK_QSPI2_PRED]         = imx_clk_divider("qspi2_pred",     "qspi2_sel",         base + 0x2c, 18,   3);
-       clks[IMX6SX_CLK_QSPI2_PODF]         = imx_clk_divider("qspi2_podf",     "qspi2_pred",        base + 0x2c, 21,   6);
-       clks[IMX6SX_CLK_SSI2_PRED]          = imx_clk_divider("ssi2_pred",      "ssi2_sel",          base + 0x2c, 6,    3);
-       clks[IMX6SX_CLK_SSI2_PODF]          = imx_clk_divider("ssi2_podf",      "ssi2_pred",         base + 0x2c, 0,    6);
-       clks[IMX6SX_CLK_SPDIF_PRED]         = imx_clk_divider("spdif_pred",     "spdif_sel",         base + 0x30, 25,   3);
-       clks[IMX6SX_CLK_SPDIF_PODF]         = imx_clk_divider("spdif_podf",     "spdif_pred",        base + 0x30, 22,   3);
-       clks[IMX6SX_CLK_AUDIO_PRED]         = imx_clk_divider("audio_pred",     "audio_sel",         base + 0x30, 12,   3);
-       clks[IMX6SX_CLK_AUDIO_PODF]         = imx_clk_divider("audio_podf",     "audio_pred",        base + 0x30, 9,    3);
-       clks[IMX6SX_CLK_ENET_PODF]          = imx_clk_divider("enet_podf",      "enet_pre_sel",      base + 0x34, 12,   3);
-       clks[IMX6SX_CLK_M4_PODF]            = imx_clk_divider("m4_podf",        "m4_sel",            base + 0x34, 3,    3);
-       clks[IMX6SX_CLK_ECSPI_PODF]         = imx_clk_divider("ecspi_podf",     "ecspi_sel",         base + 0x38, 19,   6);
-       clks[IMX6SX_CLK_LCDIF1_PRED]        = imx_clk_divider("lcdif1_pred",    "lcdif1_pre_sel",    base + 0x38, 12,   3);
-       clks[IMX6SX_CLK_LCDIF2_PRED]        = imx_clk_divider("lcdif2_pred",    "lcdif2_pre_sel",    base + 0x38, 3,    3);
-       clks[IMX6SX_CLK_DISPLAY_PODF]       = imx_clk_divider("display_podf",   "display_sel",       base + 0x3c, 16,   3);
-       clks[IMX6SX_CLK_CSI_PODF]           = imx_clk_divider("csi_podf",       "csi_sel",           base + 0x3c, 11,   3);
-       clks[IMX6SX_CLK_CKO1_PODF]          = imx_clk_divider("cko1_podf",      "cko1_sel",          base + 0x60, 4,    3);
-       clks[IMX6SX_CLK_CKO2_PODF]          = imx_clk_divider("cko2_podf",      "cko2_sel",          base + 0x60, 21,   3);
-
-       clks[IMX6SX_CLK_LDB_DI0_DIV_3_5]    = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
-       clks[IMX6SX_CLK_LDB_DI0_DIV_7]      = imx_clk_fixed_factor("ldb_di0_div_7",   "ldb_di0_sel", 1, 7);
-       clks[IMX6SX_CLK_LDB_DI1_DIV_3_5]    = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
-       clks[IMX6SX_CLK_LDB_DI1_DIV_7]      = imx_clk_fixed_factor("ldb_di1_div_7",   "ldb_di1_sel", 1, 7);
+       hws[IMX6SX_CLK_PERIPH_CLK2]        = imx_clk_hw_divider("periph_clk2",    "periph_clk2_sel",   base + 0x14, 27,   3);
+       hws[IMX6SX_CLK_PERIPH2_CLK2]       = imx_clk_hw_divider("periph2_clk2",   "periph2_clk2_sel",  base + 0x14, 0,    3);
+       hws[IMX6SX_CLK_IPG]                = imx_clk_hw_divider("ipg",            "ahb",               base + 0x14, 8,    2);
+       hws[IMX6SX_CLK_GPU_CORE_PODF]      = imx_clk_hw_divider("gpu_core_podf",  "gpu_core_sel",      base + 0x18, 29,   3);
+       hws[IMX6SX_CLK_GPU_AXI_PODF]       = imx_clk_hw_divider("gpu_axi_podf",   "gpu_axi_sel",       base + 0x18, 26,   3);
+       hws[IMX6SX_CLK_LCDIF1_PODF]        = imx_clk_hw_divider("lcdif1_podf",    "lcdif1_pred",       base + 0x18, 23,   3);
+       hws[IMX6SX_CLK_QSPI1_PODF]         = imx_clk_hw_divider("qspi1_podf",     "qspi1_sel",         base + 0x1c, 26,   3);
+       hws[IMX6SX_CLK_EIM_SLOW_PODF]      = imx_clk_hw_divider("eim_slow_podf",  "eim_slow_sel",      base + 0x1c, 23,   3);
+       hws[IMX6SX_CLK_LCDIF2_PODF]        = imx_clk_hw_divider("lcdif2_podf",    "lcdif2_pred",       base + 0x1c, 20,   3);
+       hws[IMX6SX_CLK_PERCLK]             = imx_clk_hw_divider_flags("perclk", "perclk_sel", base + 0x1c, 0, 6, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_VID_PODF]           = imx_clk_hw_divider("vid_podf",       "vid_sel",           base + 0x20, 24,   2);
+       hws[IMX6SX_CLK_CAN_PODF]           = imx_clk_hw_divider("can_podf",       "can_sel",           base + 0x20, 2,    6);
+       hws[IMX6SX_CLK_USDHC4_PODF]        = imx_clk_hw_divider("usdhc4_podf",    "usdhc4_sel",        base + 0x24, 22,   3);
+       hws[IMX6SX_CLK_USDHC3_PODF]        = imx_clk_hw_divider("usdhc3_podf",    "usdhc3_sel",        base + 0x24, 19,   3);
+       hws[IMX6SX_CLK_USDHC2_PODF]        = imx_clk_hw_divider("usdhc2_podf",    "usdhc2_sel",        base + 0x24, 16,   3);
+       hws[IMX6SX_CLK_USDHC1_PODF]        = imx_clk_hw_divider("usdhc1_podf",    "usdhc1_sel",        base + 0x24, 11,   3);
+       hws[IMX6SX_CLK_UART_PODF]          = imx_clk_hw_divider("uart_podf",      "uart_sel",          base + 0x24, 0,    6);
+       hws[IMX6SX_CLK_ESAI_PRED]          = imx_clk_hw_divider("esai_pred",      "esai_sel",          base + 0x28, 9,    3);
+       hws[IMX6SX_CLK_ESAI_PODF]          = imx_clk_hw_divider("esai_podf",      "esai_pred",         base + 0x28, 25,   3);
+       hws[IMX6SX_CLK_SSI3_PRED]          = imx_clk_hw_divider("ssi3_pred",      "ssi3_sel",          base + 0x28, 22,   3);
+       hws[IMX6SX_CLK_SSI3_PODF]          = imx_clk_hw_divider("ssi3_podf",      "ssi3_pred",         base + 0x28, 16,   6);
+       hws[IMX6SX_CLK_SSI1_PRED]          = imx_clk_hw_divider("ssi1_pred",      "ssi1_sel",          base + 0x28, 6,    3);
+       hws[IMX6SX_CLK_SSI1_PODF]          = imx_clk_hw_divider("ssi1_podf",      "ssi1_pred",         base + 0x28, 0,    6);
+       hws[IMX6SX_CLK_QSPI2_PRED]         = imx_clk_hw_divider("qspi2_pred",     "qspi2_sel",         base + 0x2c, 18,   3);
+       hws[IMX6SX_CLK_QSPI2_PODF]         = imx_clk_hw_divider("qspi2_podf",     "qspi2_pred",        base + 0x2c, 21,   6);
+       hws[IMX6SX_CLK_SSI2_PRED]          = imx_clk_hw_divider("ssi2_pred",      "ssi2_sel",          base + 0x2c, 6,    3);
+       hws[IMX6SX_CLK_SSI2_PODF]          = imx_clk_hw_divider("ssi2_podf",      "ssi2_pred",         base + 0x2c, 0,    6);
+       hws[IMX6SX_CLK_SPDIF_PRED]         = imx_clk_hw_divider("spdif_pred",     "spdif_sel",         base + 0x30, 25,   3);
+       hws[IMX6SX_CLK_SPDIF_PODF]         = imx_clk_hw_divider("spdif_podf",     "spdif_pred",        base + 0x30, 22,   3);
+       hws[IMX6SX_CLK_AUDIO_PRED]         = imx_clk_hw_divider("audio_pred",     "audio_sel",         base + 0x30, 12,   3);
+       hws[IMX6SX_CLK_AUDIO_PODF]         = imx_clk_hw_divider("audio_podf",     "audio_pred",        base + 0x30, 9,    3);
+       hws[IMX6SX_CLK_ENET_PODF]          = imx_clk_hw_divider("enet_podf",      "enet_pre_sel",      base + 0x34, 12,   3);
+       hws[IMX6SX_CLK_M4_PODF]            = imx_clk_hw_divider("m4_podf",        "m4_sel",            base + 0x34, 3,    3);
+       hws[IMX6SX_CLK_ECSPI_PODF]         = imx_clk_hw_divider("ecspi_podf",     "ecspi_sel",         base + 0x38, 19,   6);
+       hws[IMX6SX_CLK_LCDIF1_PRED]        = imx_clk_hw_divider("lcdif1_pred",    "lcdif1_pre_sel",    base + 0x38, 12,   3);
+       hws[IMX6SX_CLK_LCDIF2_PRED]        = imx_clk_hw_divider("lcdif2_pred",    "lcdif2_pre_sel",    base + 0x38, 3,    3);
+       hws[IMX6SX_CLK_DISPLAY_PODF]       = imx_clk_hw_divider("display_podf",   "display_sel",       base + 0x3c, 16,   3);
+       hws[IMX6SX_CLK_CSI_PODF]           = imx_clk_hw_divider("csi_podf",       "csi_sel",           base + 0x3c, 11,   3);
+       hws[IMX6SX_CLK_CKO1_PODF]          = imx_clk_hw_divider("cko1_podf",      "cko1_sel",          base + 0x60, 4,    3);
+       hws[IMX6SX_CLK_CKO2_PODF]          = imx_clk_hw_divider("cko2_podf",      "cko2_sel",          base + 0x60, 21,   3);
+
+       hws[IMX6SX_CLK_LDB_DI0_DIV_3_5]    = imx_clk_hw_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
+       hws[IMX6SX_CLK_LDB_DI0_DIV_7]      = imx_clk_hw_fixed_factor("ldb_di0_div_7",   "ldb_di0_sel", 1, 7);
+       hws[IMX6SX_CLK_LDB_DI1_DIV_3_5]    = imx_clk_hw_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
+       hws[IMX6SX_CLK_LDB_DI1_DIV_7]      = imx_clk_hw_fixed_factor("ldb_di1_div_7",   "ldb_di1_sel", 1, 7);
 
        /*                                               name        reg          shift width busy: reg,   shift parent_names       num_parents */
-       clks[IMX6SX_CLK_PERIPH]       = imx_clk_busy_mux("periph",   base + 0x14, 25,   1,    base + 0x48, 5,    periph_sels,       ARRAY_SIZE(periph_sels));
-       clks[IMX6SX_CLK_PERIPH2]      = imx_clk_busy_mux("periph2",  base + 0x14, 26,   1,    base + 0x48, 3,    periph2_sels,      ARRAY_SIZE(periph2_sels));
+       hws[IMX6SX_CLK_PERIPH]       = imx_clk_hw_busy_mux("periph",   base + 0x14, 25,   1,    base + 0x48, 5,    periph_sels,       ARRAY_SIZE(periph_sels));
+       hws[IMX6SX_CLK_PERIPH2]      = imx_clk_hw_busy_mux("periph2",  base + 0x14, 26,   1,    base + 0x48, 3,    periph2_sels,      ARRAY_SIZE(periph2_sels));
        /*                                                   name             parent_name    reg          shift width busy: reg,   shift */
-       clks[IMX6SX_CLK_OCRAM_PODF]   = imx_clk_busy_divider("ocram_podf",    "ocram_sel",   base + 0x14, 16,   3,    base + 0x48, 0);
-       clks[IMX6SX_CLK_AHB]          = imx_clk_busy_divider("ahb",           "periph",      base + 0x14, 10,   3,    base + 0x48, 1);
-       clks[IMX6SX_CLK_MMDC_PODF]    = imx_clk_busy_divider("mmdc_podf",     "periph2",     base + 0x14, 3,    3,    base + 0x48, 2);
-       clks[IMX6SX_CLK_ARM]          = imx_clk_busy_divider("arm",           "pll1_sw",     base + 0x10, 0,    3,    base + 0x48, 16);
+       hws[IMX6SX_CLK_OCRAM_PODF]   = imx_clk_hw_busy_divider("ocram_podf",    "ocram_sel",   base + 0x14, 16,   3,    base + 0x48, 0);
+       hws[IMX6SX_CLK_AHB]          = imx_clk_hw_busy_divider("ahb",           "periph",      base + 0x14, 10,   3,    base + 0x48, 1);
+       hws[IMX6SX_CLK_MMDC_PODF]    = imx_clk_hw_busy_divider("mmdc_podf",     "periph2",     base + 0x14, 3,    3,    base + 0x48, 2);
+       hws[IMX6SX_CLK_ARM]          = imx_clk_hw_busy_divider("arm",           "pll1_sw",     base + 0x10, 0,    3,    base + 0x48, 16);
 
        /*                                            name             parent_name          reg         shift */
        /* CCGR0 */
-       clks[IMX6SX_CLK_AIPS_TZ1]     = imx_clk_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_AIPS_TZ2]     = imx_clk_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_APBH_DMA]     = imx_clk_gate2("apbh_dma",      "usdhc3",            base + 0x68, 4);
-       clks[IMX6SX_CLK_ASRC_MEM]     = imx_clk_gate2_shared("asrc_mem", "ahb",             base + 0x68, 6, &share_count_asrc);
-       clks[IMX6SX_CLK_ASRC_IPG]     = imx_clk_gate2_shared("asrc_ipg", "ahb",             base + 0x68, 6, &share_count_asrc);
-       clks[IMX6SX_CLK_CAAM_MEM]     = imx_clk_gate2("caam_mem",      "ahb",               base + 0x68, 8);
-       clks[IMX6SX_CLK_CAAM_ACLK]    = imx_clk_gate2("caam_aclk",     "ahb",               base + 0x68, 10);
-       clks[IMX6SX_CLK_CAAM_IPG]     = imx_clk_gate2("caam_ipg",      "ipg",               base + 0x68, 12);
-       clks[IMX6SX_CLK_CAN1_IPG]     = imx_clk_gate2("can1_ipg",      "ipg",               base + 0x68, 14);
-       clks[IMX6SX_CLK_CAN1_SERIAL]  = imx_clk_gate2("can1_serial",   "can_podf",          base + 0x68, 16);
-       clks[IMX6SX_CLK_CAN2_IPG]     = imx_clk_gate2("can2_ipg",      "ipg",               base + 0x68, 18);
-       clks[IMX6SX_CLK_CAN2_SERIAL]  = imx_clk_gate2("can2_serial",   "can_podf",          base + 0x68, 20);
-       clks[IMX6SX_CLK_DCIC1]        = imx_clk_gate2("dcic1",         "display_podf",      base + 0x68, 24);
-       clks[IMX6SX_CLK_DCIC2]        = imx_clk_gate2("dcic2",         "display_podf",      base + 0x68, 26);
-       clks[IMX6SX_CLK_AIPS_TZ3]     = imx_clk_gate2_flags("aips_tz3", "ahb", base + 0x68, 30, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_AIPS_TZ1]     = imx_clk_hw_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_AIPS_TZ2]     = imx_clk_hw_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_APBH_DMA]     = imx_clk_hw_gate2("apbh_dma",      "usdhc3",            base + 0x68, 4);
+       hws[IMX6SX_CLK_ASRC_MEM]     = imx_clk_hw_gate2_shared("asrc_mem", "ahb",             base + 0x68, 6, &share_count_asrc);
+       hws[IMX6SX_CLK_ASRC_IPG]     = imx_clk_hw_gate2_shared("asrc_ipg", "ahb",             base + 0x68, 6, &share_count_asrc);
+       hws[IMX6SX_CLK_CAAM_MEM]     = imx_clk_hw_gate2("caam_mem",      "ahb",               base + 0x68, 8);
+       hws[IMX6SX_CLK_CAAM_ACLK]    = imx_clk_hw_gate2("caam_aclk",     "ahb",               base + 0x68, 10);
+       hws[IMX6SX_CLK_CAAM_IPG]     = imx_clk_hw_gate2("caam_ipg",      "ipg",               base + 0x68, 12);
+       hws[IMX6SX_CLK_CAN1_IPG]     = imx_clk_hw_gate2("can1_ipg",      "ipg",               base + 0x68, 14);
+       hws[IMX6SX_CLK_CAN1_SERIAL]  = imx_clk_hw_gate2("can1_serial",   "can_podf",          base + 0x68, 16);
+       hws[IMX6SX_CLK_CAN2_IPG]     = imx_clk_hw_gate2("can2_ipg",      "ipg",               base + 0x68, 18);
+       hws[IMX6SX_CLK_CAN2_SERIAL]  = imx_clk_hw_gate2("can2_serial",   "can_podf",          base + 0x68, 20);
+       hws[IMX6SX_CLK_DCIC1]        = imx_clk_hw_gate2("dcic1",         "display_podf",      base + 0x68, 24);
+       hws[IMX6SX_CLK_DCIC2]        = imx_clk_hw_gate2("dcic2",         "display_podf",      base + 0x68, 26);
+       hws[IMX6SX_CLK_AIPS_TZ3]     = imx_clk_hw_gate2_flags("aips_tz3", "ahb", base + 0x68, 30, CLK_IS_CRITICAL);
 
        /* CCGR1 */
-       clks[IMX6SX_CLK_ECSPI1]       = imx_clk_gate2("ecspi1",        "ecspi_podf",        base + 0x6c, 0);
-       clks[IMX6SX_CLK_ECSPI2]       = imx_clk_gate2("ecspi2",        "ecspi_podf",        base + 0x6c, 2);
-       clks[IMX6SX_CLK_ECSPI3]       = imx_clk_gate2("ecspi3",        "ecspi_podf",        base + 0x6c, 4);
-       clks[IMX6SX_CLK_ECSPI4]       = imx_clk_gate2("ecspi4",        "ecspi_podf",        base + 0x6c, 6);
-       clks[IMX6SX_CLK_ECSPI5]       = imx_clk_gate2("ecspi5",        "ecspi_podf",        base + 0x6c, 8);
-       clks[IMX6SX_CLK_EPIT1]        = imx_clk_gate2("epit1",         "perclk",            base + 0x6c, 12);
-       clks[IMX6SX_CLK_EPIT2]        = imx_clk_gate2("epit2",         "perclk",            base + 0x6c, 14);
-       clks[IMX6SX_CLK_ESAI_EXTAL]   = imx_clk_gate2_shared("esai_extal", "esai_podf",     base + 0x6c, 16, &share_count_esai);
-       clks[IMX6SX_CLK_ESAI_IPG]     = imx_clk_gate2_shared("esai_ipg",   "ahb",           base + 0x6c, 16, &share_count_esai);
-       clks[IMX6SX_CLK_ESAI_MEM]     = imx_clk_gate2_shared("esai_mem",   "ahb",           base + 0x6c, 16, &share_count_esai);
-       clks[IMX6SX_CLK_WAKEUP]       = imx_clk_gate2_flags("wakeup", "ipg", base + 0x6c, 18, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_GPT_BUS]      = imx_clk_gate2("gpt_bus",       "perclk",            base + 0x6c, 20);
-       clks[IMX6SX_CLK_GPT_SERIAL]   = imx_clk_gate2("gpt_serial",    "perclk",            base + 0x6c, 22);
-       clks[IMX6SX_CLK_GPU]          = imx_clk_gate2("gpu",           "gpu_core_podf",     base + 0x6c, 26);
-       clks[IMX6SX_CLK_OCRAM_S]      = imx_clk_gate2("ocram_s",       "ahb",               base + 0x6c, 28);
-       clks[IMX6SX_CLK_CANFD]        = imx_clk_gate2("canfd",         "can_podf",          base + 0x6c, 30);
+       hws[IMX6SX_CLK_ECSPI1]       = imx_clk_hw_gate2("ecspi1",        "ecspi_podf",        base + 0x6c, 0);
+       hws[IMX6SX_CLK_ECSPI2]       = imx_clk_hw_gate2("ecspi2",        "ecspi_podf",        base + 0x6c, 2);
+       hws[IMX6SX_CLK_ECSPI3]       = imx_clk_hw_gate2("ecspi3",        "ecspi_podf",        base + 0x6c, 4);
+       hws[IMX6SX_CLK_ECSPI4]       = imx_clk_hw_gate2("ecspi4",        "ecspi_podf",        base + 0x6c, 6);
+       hws[IMX6SX_CLK_ECSPI5]       = imx_clk_hw_gate2("ecspi5",        "ecspi_podf",        base + 0x6c, 8);
+       hws[IMX6SX_CLK_EPIT1]        = imx_clk_hw_gate2("epit1",         "perclk",            base + 0x6c, 12);
+       hws[IMX6SX_CLK_EPIT2]        = imx_clk_hw_gate2("epit2",         "perclk",            base + 0x6c, 14);
+       hws[IMX6SX_CLK_ESAI_EXTAL]   = imx_clk_hw_gate2_shared("esai_extal", "esai_podf",     base + 0x6c, 16, &share_count_esai);
+       hws[IMX6SX_CLK_ESAI_IPG]     = imx_clk_hw_gate2_shared("esai_ipg",   "ahb",           base + 0x6c, 16, &share_count_esai);
+       hws[IMX6SX_CLK_ESAI_MEM]     = imx_clk_hw_gate2_shared("esai_mem",   "ahb",           base + 0x6c, 16, &share_count_esai);
+       hws[IMX6SX_CLK_WAKEUP]       = imx_clk_hw_gate2_flags("wakeup", "ipg", base + 0x6c, 18, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_GPT_BUS]      = imx_clk_hw_gate2("gpt_bus",       "perclk",            base + 0x6c, 20);
+       hws[IMX6SX_CLK_GPT_SERIAL]   = imx_clk_hw_gate2("gpt_serial",    "perclk",            base + 0x6c, 22);
+       hws[IMX6SX_CLK_GPU]          = imx_clk_hw_gate2("gpu",           "gpu_core_podf",     base + 0x6c, 26);
+       hws[IMX6SX_CLK_OCRAM_S]      = imx_clk_hw_gate2("ocram_s",       "ahb",               base + 0x6c, 28);
+       hws[IMX6SX_CLK_CANFD]        = imx_clk_hw_gate2("canfd",         "can_podf",          base + 0x6c, 30);
 
        /* CCGR2 */
-       clks[IMX6SX_CLK_CSI]          = imx_clk_gate2("csi",           "csi_podf",          base + 0x70, 2);
-       clks[IMX6SX_CLK_I2C1]         = imx_clk_gate2("i2c1",          "perclk",            base + 0x70, 6);
-       clks[IMX6SX_CLK_I2C2]         = imx_clk_gate2("i2c2",          "perclk",            base + 0x70, 8);
-       clks[IMX6SX_CLK_I2C3]         = imx_clk_gate2("i2c3",          "perclk",            base + 0x70, 10);
-       clks[IMX6SX_CLK_OCOTP]        = imx_clk_gate2("ocotp",         "ipg",               base + 0x70, 12);
-       clks[IMX6SX_CLK_IOMUXC]       = imx_clk_gate2("iomuxc",        "lcdif1_podf",       base + 0x70, 14);
-       clks[IMX6SX_CLK_IPMUX1]       = imx_clk_gate2_flags("ipmux1", "ahb", base + 0x70, 16, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_IPMUX2]       = imx_clk_gate2_flags("ipmux2", "ahb", base + 0x70, 18, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_IPMUX3]       = imx_clk_gate2_flags("ipmux3", "ahb", base + 0x70, 20, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_TZASC1]       = imx_clk_gate2_flags("tzasc1", "mmdc_podf", base + 0x70, 22, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_LCDIF_APB]    = imx_clk_gate2("lcdif_apb",     "display_podf",      base + 0x70, 28);
-       clks[IMX6SX_CLK_PXP_AXI]      = imx_clk_gate2("pxp_axi",       "display_podf",      base + 0x70, 30);
+       hws[IMX6SX_CLK_CSI]          = imx_clk_hw_gate2("csi",           "csi_podf",          base + 0x70, 2);
+       hws[IMX6SX_CLK_I2C1]         = imx_clk_hw_gate2("i2c1",          "perclk",            base + 0x70, 6);
+       hws[IMX6SX_CLK_I2C2]         = imx_clk_hw_gate2("i2c2",          "perclk",            base + 0x70, 8);
+       hws[IMX6SX_CLK_I2C3]         = imx_clk_hw_gate2("i2c3",          "perclk",            base + 0x70, 10);
+       hws[IMX6SX_CLK_OCOTP]        = imx_clk_hw_gate2("ocotp",         "ipg",               base + 0x70, 12);
+       hws[IMX6SX_CLK_IOMUXC]       = imx_clk_hw_gate2("iomuxc",        "lcdif1_podf",       base + 0x70, 14);
+       hws[IMX6SX_CLK_IPMUX1]       = imx_clk_hw_gate2_flags("ipmux1", "ahb", base + 0x70, 16, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_IPMUX2]       = imx_clk_hw_gate2_flags("ipmux2", "ahb", base + 0x70, 18, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_IPMUX3]       = imx_clk_hw_gate2_flags("ipmux3", "ahb", base + 0x70, 20, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_TZASC1]       = imx_clk_hw_gate2_flags("tzasc1", "mmdc_podf", base + 0x70, 22, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_LCDIF_APB]    = imx_clk_hw_gate2("lcdif_apb",     "display_podf",      base + 0x70, 28);
+       hws[IMX6SX_CLK_PXP_AXI]      = imx_clk_hw_gate2("pxp_axi",       "display_podf",      base + 0x70, 30);
 
        /* CCGR3 */
-       clks[IMX6SX_CLK_M4]           = imx_clk_gate2("m4",            "m4_podf",           base + 0x74, 2);
-       clks[IMX6SX_CLK_ENET]         = imx_clk_gate2("enet",          "ipg",               base + 0x74, 4);
-       clks[IMX6SX_CLK_ENET_AHB]     = imx_clk_gate2("enet_ahb",      "enet_sel",          base + 0x74, 4);
-       clks[IMX6SX_CLK_DISPLAY_AXI]  = imx_clk_gate2("display_axi",   "display_podf",      base + 0x74, 6);
-       clks[IMX6SX_CLK_LCDIF2_PIX]   = imx_clk_gate2("lcdif2_pix",    "lcdif2_sel",        base + 0x74, 8);
-       clks[IMX6SX_CLK_LCDIF1_PIX]   = imx_clk_gate2("lcdif1_pix",    "lcdif1_sel",        base + 0x74, 10);
-       clks[IMX6SX_CLK_LDB_DI0]      = imx_clk_gate2("ldb_di0",       "ldb_di0_div_sel",   base + 0x74, 12);
-       clks[IMX6SX_CLK_QSPI1]        = imx_clk_gate2("qspi1",         "qspi1_podf",        base + 0x74, 14);
-       clks[IMX6SX_CLK_MLB]          = imx_clk_gate2("mlb",           "ahb",               base + 0x74, 18);
-       clks[IMX6SX_CLK_MMDC_P0_FAST] = imx_clk_gate2_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_MMDC_P0_IPG]  = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_MMDC_P1_IPG]  = imx_clk_gate2("mmdc_p1_ipg", "ipg", base + 0x74, 26);
-       clks[IMX6SX_CLK_OCRAM]        = imx_clk_gate2_flags("ocram", "ocram_podf", base + 0x74, 28, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_M4]           = imx_clk_hw_gate2("m4",            "m4_podf",           base + 0x74, 2);
+       hws[IMX6SX_CLK_ENET]         = imx_clk_hw_gate2("enet",          "ipg",               base + 0x74, 4);
+       hws[IMX6SX_CLK_ENET_AHB]     = imx_clk_hw_gate2("enet_ahb",      "enet_sel",          base + 0x74, 4);
+       hws[IMX6SX_CLK_DISPLAY_AXI]  = imx_clk_hw_gate2("display_axi",   "display_podf",      base + 0x74, 6);
+       hws[IMX6SX_CLK_LCDIF2_PIX]   = imx_clk_hw_gate2("lcdif2_pix",    "lcdif2_sel",        base + 0x74, 8);
+       hws[IMX6SX_CLK_LCDIF1_PIX]   = imx_clk_hw_gate2("lcdif1_pix",    "lcdif1_sel",        base + 0x74, 10);
+       hws[IMX6SX_CLK_LDB_DI0]      = imx_clk_hw_gate2("ldb_di0",       "ldb_di0_div_sel",   base + 0x74, 12);
+       hws[IMX6SX_CLK_QSPI1]        = imx_clk_hw_gate2("qspi1",         "qspi1_podf",        base + 0x74, 14);
+       hws[IMX6SX_CLK_MLB]          = imx_clk_hw_gate2("mlb",           "ahb",               base + 0x74, 18);
+       hws[IMX6SX_CLK_MMDC_P0_FAST] = imx_clk_hw_gate2_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_MMDC_P0_IPG]  = imx_clk_hw_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_MMDC_P1_IPG]  = imx_clk_hw_gate2_flags("mmdc_p1_ipg", "ipg", base + 0x74, 26, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_OCRAM]        = imx_clk_hw_gate2_flags("ocram", "ocram_podf", base + 0x74, 28, CLK_IS_CRITICAL);
 
        /* CCGR4 */
-       clks[IMX6SX_CLK_PCIE_AXI]     = imx_clk_gate2("pcie_axi",      "display_podf",      base + 0x78, 0);
-       clks[IMX6SX_CLK_QSPI2]        = imx_clk_gate2("qspi2",         "qspi2_podf",        base + 0x78, 10);
-       clks[IMX6SX_CLK_PER1_BCH]     = imx_clk_gate2("per1_bch",      "usdhc3",            base + 0x78, 12);
-       clks[IMX6SX_CLK_PER2_MAIN]    = imx_clk_gate2_flags("per2_main", "ahb", base + 0x78, 14, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_PWM1]         = imx_clk_gate2("pwm1",          "perclk",            base + 0x78, 16);
-       clks[IMX6SX_CLK_PWM2]         = imx_clk_gate2("pwm2",          "perclk",            base + 0x78, 18);
-       clks[IMX6SX_CLK_PWM3]         = imx_clk_gate2("pwm3",          "perclk",            base + 0x78, 20);
-       clks[IMX6SX_CLK_PWM4]         = imx_clk_gate2("pwm4",          "perclk",            base + 0x78, 22);
-       clks[IMX6SX_CLK_GPMI_BCH_APB] = imx_clk_gate2("gpmi_bch_apb",  "usdhc3",            base + 0x78, 24);
-       clks[IMX6SX_CLK_GPMI_BCH]     = imx_clk_gate2("gpmi_bch",      "usdhc4",            base + 0x78, 26);
-       clks[IMX6SX_CLK_GPMI_IO]      = imx_clk_gate2("gpmi_io",       "qspi2_podf",        base + 0x78, 28);
-       clks[IMX6SX_CLK_GPMI_APB]     = imx_clk_gate2("gpmi_apb",      "usdhc3",            base + 0x78, 30);
+       hws[IMX6SX_CLK_PCIE_AXI]     = imx_clk_hw_gate2("pcie_axi",      "display_podf",      base + 0x78, 0);
+       hws[IMX6SX_CLK_QSPI2]        = imx_clk_hw_gate2("qspi2",         "qspi2_podf",        base + 0x78, 10);
+       hws[IMX6SX_CLK_PER1_BCH]     = imx_clk_hw_gate2("per1_bch",      "usdhc3",            base + 0x78, 12);
+       hws[IMX6SX_CLK_PER2_MAIN]    = imx_clk_hw_gate2_flags("per2_main", "ahb", base + 0x78, 14, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_PWM1]         = imx_clk_hw_gate2("pwm1",          "perclk",            base + 0x78, 16);
+       hws[IMX6SX_CLK_PWM2]         = imx_clk_hw_gate2("pwm2",          "perclk",            base + 0x78, 18);
+       hws[IMX6SX_CLK_PWM3]         = imx_clk_hw_gate2("pwm3",          "perclk",            base + 0x78, 20);
+       hws[IMX6SX_CLK_PWM4]         = imx_clk_hw_gate2("pwm4",          "perclk",            base + 0x78, 22);
+       hws[IMX6SX_CLK_GPMI_BCH_APB] = imx_clk_hw_gate2("gpmi_bch_apb",  "usdhc3",            base + 0x78, 24);
+       hws[IMX6SX_CLK_GPMI_BCH]     = imx_clk_hw_gate2("gpmi_bch",      "usdhc4",            base + 0x78, 26);
+       hws[IMX6SX_CLK_GPMI_IO]      = imx_clk_hw_gate2("gpmi_io",       "qspi2_podf",        base + 0x78, 28);
+       hws[IMX6SX_CLK_GPMI_APB]     = imx_clk_hw_gate2("gpmi_apb",      "usdhc3",            base + 0x78, 30);
 
        /* CCGR5 */
-       clks[IMX6SX_CLK_ROM]          = imx_clk_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_SDMA]         = imx_clk_gate2("sdma",          "ahb",               base + 0x7c, 6);
-       clks[IMX6SX_CLK_SPBA]         = imx_clk_gate2("spba",          "ipg",               base + 0x7c, 12);
-       clks[IMX6SX_CLK_AUDIO]        = imx_clk_gate2_shared("audio",  "audio_podf",        base + 0x7c, 14, &share_count_audio);
-       clks[IMX6SX_CLK_SPDIF]        = imx_clk_gate2_shared("spdif",  "spdif_podf",        base + 0x7c, 14, &share_count_audio);
-       clks[IMX6SX_CLK_SPDIF_GCLK]   = imx_clk_gate2_shared("spdif_gclk",    "ipg",        base + 0x7c, 14, &share_count_audio);
-       clks[IMX6SX_CLK_SSI1_IPG]     = imx_clk_gate2_shared("ssi1_ipg",      "ipg",        base + 0x7c, 18, &share_count_ssi1);
-       clks[IMX6SX_CLK_SSI2_IPG]     = imx_clk_gate2_shared("ssi2_ipg",      "ipg",        base + 0x7c, 20, &share_count_ssi2);
-       clks[IMX6SX_CLK_SSI3_IPG]     = imx_clk_gate2_shared("ssi3_ipg",      "ipg",        base + 0x7c, 22, &share_count_ssi3);
-       clks[IMX6SX_CLK_SSI1]         = imx_clk_gate2_shared("ssi1",          "ssi1_podf",  base + 0x7c, 18, &share_count_ssi1);
-       clks[IMX6SX_CLK_SSI2]         = imx_clk_gate2_shared("ssi2",          "ssi2_podf",  base + 0x7c, 20, &share_count_ssi2);
-       clks[IMX6SX_CLK_SSI3]         = imx_clk_gate2_shared("ssi3",          "ssi3_podf",  base + 0x7c, 22, &share_count_ssi3);
-       clks[IMX6SX_CLK_UART_IPG]     = imx_clk_gate2("uart_ipg",      "ipg",               base + 0x7c, 24);
-       clks[IMX6SX_CLK_UART_SERIAL]  = imx_clk_gate2("uart_serial",   "uart_podf",         base + 0x7c, 26);
-       clks[IMX6SX_CLK_SAI1_IPG]     = imx_clk_gate2_shared("sai1_ipg", "ipg",             base + 0x7c, 28, &share_count_sai1);
-       clks[IMX6SX_CLK_SAI2_IPG]     = imx_clk_gate2_shared("sai2_ipg", "ipg",             base + 0x7c, 30, &share_count_sai2);
-       clks[IMX6SX_CLK_SAI1]         = imx_clk_gate2_shared("sai1",    "ssi1_podf",        base + 0x7c, 28, &share_count_sai1);
-       clks[IMX6SX_CLK_SAI2]         = imx_clk_gate2_shared("sai2",    "ssi2_podf",        base + 0x7c, 30, &share_count_sai2);
+       hws[IMX6SX_CLK_ROM]          = imx_clk_hw_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_SDMA]         = imx_clk_hw_gate2("sdma",          "ahb",               base + 0x7c, 6);
+       hws[IMX6SX_CLK_SPBA]         = imx_clk_hw_gate2("spba",          "ipg",               base + 0x7c, 12);
+       hws[IMX6SX_CLK_AUDIO]        = imx_clk_hw_gate2_shared("audio",  "audio_podf",        base + 0x7c, 14, &share_count_audio);
+       hws[IMX6SX_CLK_SPDIF]        = imx_clk_hw_gate2_shared("spdif",  "spdif_podf",        base + 0x7c, 14, &share_count_audio);
+       hws[IMX6SX_CLK_SPDIF_GCLK]   = imx_clk_hw_gate2_shared("spdif_gclk",    "ipg",        base + 0x7c, 14, &share_count_audio);
+       hws[IMX6SX_CLK_SSI1_IPG]     = imx_clk_hw_gate2_shared("ssi1_ipg",      "ipg",        base + 0x7c, 18, &share_count_ssi1);
+       hws[IMX6SX_CLK_SSI2_IPG]     = imx_clk_hw_gate2_shared("ssi2_ipg",      "ipg",        base + 0x7c, 20, &share_count_ssi2);
+       hws[IMX6SX_CLK_SSI3_IPG]     = imx_clk_hw_gate2_shared("ssi3_ipg",      "ipg",        base + 0x7c, 22, &share_count_ssi3);
+       hws[IMX6SX_CLK_SSI1]         = imx_clk_hw_gate2_shared("ssi1",          "ssi1_podf",  base + 0x7c, 18, &share_count_ssi1);
+       hws[IMX6SX_CLK_SSI2]         = imx_clk_hw_gate2_shared("ssi2",          "ssi2_podf",  base + 0x7c, 20, &share_count_ssi2);
+       hws[IMX6SX_CLK_SSI3]         = imx_clk_hw_gate2_shared("ssi3",          "ssi3_podf",  base + 0x7c, 22, &share_count_ssi3);
+       hws[IMX6SX_CLK_UART_IPG]     = imx_clk_hw_gate2("uart_ipg",      "ipg",               base + 0x7c, 24);
+       hws[IMX6SX_CLK_UART_SERIAL]  = imx_clk_hw_gate2("uart_serial",   "uart_podf",         base + 0x7c, 26);
+       hws[IMX6SX_CLK_SAI1_IPG]     = imx_clk_hw_gate2_shared("sai1_ipg", "ipg",             base + 0x7c, 28, &share_count_sai1);
+       hws[IMX6SX_CLK_SAI2_IPG]     = imx_clk_hw_gate2_shared("sai2_ipg", "ipg",             base + 0x7c, 30, &share_count_sai2);
+       hws[IMX6SX_CLK_SAI1]         = imx_clk_hw_gate2_shared("sai1",  "ssi1_podf",        base + 0x7c, 28, &share_count_sai1);
+       hws[IMX6SX_CLK_SAI2]         = imx_clk_hw_gate2_shared("sai2",  "ssi2_podf",        base + 0x7c, 30, &share_count_sai2);
 
        /* CCGR6 */
-       clks[IMX6SX_CLK_USBOH3]       = imx_clk_gate2("usboh3",        "ipg",               base + 0x80, 0);
-       clks[IMX6SX_CLK_USDHC1]       = imx_clk_gate2("usdhc1",        "usdhc1_podf",       base + 0x80, 2);
-       clks[IMX6SX_CLK_USDHC2]       = imx_clk_gate2("usdhc2",        "usdhc2_podf",       base + 0x80, 4);
-       clks[IMX6SX_CLK_USDHC3]       = imx_clk_gate2("usdhc3",        "usdhc3_podf",       base + 0x80, 6);
-       clks[IMX6SX_CLK_USDHC4]       = imx_clk_gate2("usdhc4",        "usdhc4_podf",       base + 0x80, 8);
-       clks[IMX6SX_CLK_EIM_SLOW]     = imx_clk_gate2("eim_slow",      "eim_slow_podf",     base + 0x80, 10);
-       clks[IMX6SX_CLK_PWM8]         = imx_clk_gate2("pwm8",          "perclk",            base + 0x80, 16);
-       clks[IMX6SX_CLK_VADC]         = imx_clk_gate2("vadc",          "vid_podf",          base + 0x80, 20);
-       clks[IMX6SX_CLK_GIS]          = imx_clk_gate2("gis",           "display_podf",      base + 0x80, 22);
-       clks[IMX6SX_CLK_I2C4]         = imx_clk_gate2("i2c4",          "perclk",            base + 0x80, 24);
-       clks[IMX6SX_CLK_PWM5]         = imx_clk_gate2("pwm5",          "perclk",            base + 0x80, 26);
-       clks[IMX6SX_CLK_PWM6]         = imx_clk_gate2("pwm6",          "perclk",            base + 0x80, 28);
-       clks[IMX6SX_CLK_PWM7]         = imx_clk_gate2("pwm7",          "perclk",            base + 0x80, 30);
-
-       clks[IMX6SX_CLK_CKO1]         = imx_clk_gate("cko1",           "cko1_podf",         base + 0x60, 7);
-       clks[IMX6SX_CLK_CKO2]         = imx_clk_gate("cko2",           "cko2_podf",         base + 0x60, 24);
+       hws[IMX6SX_CLK_USBOH3]       = imx_clk_hw_gate2("usboh3",        "ipg",               base + 0x80, 0);
+       hws[IMX6SX_CLK_USDHC1]       = imx_clk_hw_gate2("usdhc1",        "usdhc1_podf",       base + 0x80, 2);
+       hws[IMX6SX_CLK_USDHC2]       = imx_clk_hw_gate2("usdhc2",        "usdhc2_podf",       base + 0x80, 4);
+       hws[IMX6SX_CLK_USDHC3]       = imx_clk_hw_gate2("usdhc3",        "usdhc3_podf",       base + 0x80, 6);
+       hws[IMX6SX_CLK_USDHC4]       = imx_clk_hw_gate2("usdhc4",        "usdhc4_podf",       base + 0x80, 8);
+       hws[IMX6SX_CLK_EIM_SLOW]     = imx_clk_hw_gate2("eim_slow",      "eim_slow_podf",     base + 0x80, 10);
+       hws[IMX6SX_CLK_PWM8]         = imx_clk_hw_gate2("pwm8",          "perclk",            base + 0x80, 16);
+       hws[IMX6SX_CLK_VADC]         = imx_clk_hw_gate2("vadc",          "vid_podf",          base + 0x80, 20);
+       hws[IMX6SX_CLK_GIS]          = imx_clk_hw_gate2("gis",           "display_podf",      base + 0x80, 22);
+       hws[IMX6SX_CLK_I2C4]         = imx_clk_hw_gate2("i2c4",          "perclk",            base + 0x80, 24);
+       hws[IMX6SX_CLK_PWM5]         = imx_clk_hw_gate2("pwm5",          "perclk",            base + 0x80, 26);
+       hws[IMX6SX_CLK_PWM6]         = imx_clk_hw_gate2("pwm6",          "perclk",            base + 0x80, 28);
+       hws[IMX6SX_CLK_PWM7]         = imx_clk_hw_gate2("pwm7",          "perclk",            base + 0x80, 30);
+
+       hws[IMX6SX_CLK_CKO1]         = imx_clk_hw_gate("cko1",           "cko1_podf",         base + 0x60, 7);
+       hws[IMX6SX_CLK_CKO2]         = imx_clk_hw_gate("cko2",           "cko2_podf",         base + 0x60, 24);
 
        /* mask handshake of mmdc */
-       writel_relaxed(BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR);
+       imx_mmdc_mask_handshake(base, 0);
 
-       imx_check_clocks(clks, ARRAY_SIZE(clks));
+       imx_check_clk_hws(hws, IMX6SX_CLK_CLK_END);
 
-       clk_data.clks = clks;
-       clk_data.clk_num = ARRAY_SIZE(clks);
-       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+       of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
 
        if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
-               clk_prepare_enable(clks[IMX6SX_CLK_USBPHY1_GATE]);
-               clk_prepare_enable(clks[IMX6SX_CLK_USBPHY2_GATE]);
+               clk_prepare_enable(hws[IMX6SX_CLK_USBPHY1_GATE]->clk);
+               clk_prepare_enable(hws[IMX6SX_CLK_USBPHY2_GATE]->clk);
        }
 
        /* Set the default 132MHz for EIM module */
-       clk_set_parent(clks[IMX6SX_CLK_EIM_SLOW_SEL], clks[IMX6SX_CLK_PLL2_PFD2]);
-       clk_set_rate(clks[IMX6SX_CLK_EIM_SLOW], 132000000);
+       clk_set_parent(hws[IMX6SX_CLK_EIM_SLOW_SEL]->clk, hws[IMX6SX_CLK_PLL2_PFD2]->clk);
+       clk_set_rate(hws[IMX6SX_CLK_EIM_SLOW]->clk, 132000000);
 
        /* set parent clock for LCDIF1 pixel clock */
-       clk_set_parent(clks[IMX6SX_CLK_LCDIF1_PRE_SEL], clks[IMX6SX_CLK_PLL5_VIDEO_DIV]);
-       clk_set_parent(clks[IMX6SX_CLK_LCDIF1_SEL], clks[IMX6SX_CLK_LCDIF1_PODF]);
+       clk_set_parent(hws[IMX6SX_CLK_LCDIF1_PRE_SEL]->clk, hws[IMX6SX_CLK_PLL5_VIDEO_DIV]->clk);
+       clk_set_parent(hws[IMX6SX_CLK_LCDIF1_SEL]->clk, hws[IMX6SX_CLK_LCDIF1_PODF]->clk);
 
        /* Set the parent clks of PCIe lvds1 and pcie_axi to be pcie ref, axi */
-       if (clk_set_parent(clks[IMX6SX_CLK_LVDS1_SEL], clks[IMX6SX_CLK_PCIE_REF_125M]))
+       if (clk_set_parent(hws[IMX6SX_CLK_LVDS1_SEL]->clk, hws[IMX6SX_CLK_PCIE_REF_125M]->clk))
                pr_err("Failed to set pcie bus parent clk.\n");
-       if (clk_set_parent(clks[IMX6SX_CLK_PCIE_AXI_SEL], clks[IMX6SX_CLK_AXI]))
-               pr_err("Failed to set pcie parent clk.\n");
 
        /*
         * Init enet system AHB clock, set to 200MHz
         * pll2_pfd2_396m-> ENET_PODF-> ENET_AHB
         */
-       clk_set_parent(clks[IMX6SX_CLK_ENET_PRE_SEL], clks[IMX6SX_CLK_PLL2_PFD2]);
-       clk_set_parent(clks[IMX6SX_CLK_ENET_SEL], clks[IMX6SX_CLK_ENET_PODF]);
-       clk_set_rate(clks[IMX6SX_CLK_ENET_PODF], 200000000);
-       clk_set_rate(clks[IMX6SX_CLK_ENET_REF], 125000000);
-       clk_set_rate(clks[IMX6SX_CLK_ENET2_REF], 125000000);
+       clk_set_parent(hws[IMX6SX_CLK_ENET_PRE_SEL]->clk, hws[IMX6SX_CLK_PLL2_PFD2]->clk);
+       clk_set_parent(hws[IMX6SX_CLK_ENET_SEL]->clk, hws[IMX6SX_CLK_ENET_PODF]->clk);
+       clk_set_rate(hws[IMX6SX_CLK_ENET_PODF]->clk, 200000000);
+       clk_set_rate(hws[IMX6SX_CLK_ENET_REF]->clk, 125000000);
+       clk_set_rate(hws[IMX6SX_CLK_ENET2_REF]->clk, 125000000);
 
        /* Audio clocks */
-       clk_set_rate(clks[IMX6SX_CLK_PLL4_AUDIO_DIV], 393216000);
+       clk_set_rate(hws[IMX6SX_CLK_PLL4_AUDIO_DIV]->clk, 393216000);
 
-       clk_set_parent(clks[IMX6SX_CLK_SPDIF_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
-       clk_set_rate(clks[IMX6SX_CLK_SPDIF_PODF], 98304000);
+       clk_set_parent(hws[IMX6SX_CLK_SPDIF_SEL]->clk, hws[IMX6SX_CLK_PLL4_AUDIO_DIV]->clk);
+       clk_set_rate(hws[IMX6SX_CLK_SPDIF_PODF]->clk, 98304000);
 
-       clk_set_parent(clks[IMX6SX_CLK_AUDIO_SEL], clks[IMX6SX_CLK_PLL3_USB_OTG]);
-       clk_set_rate(clks[IMX6SX_CLK_AUDIO_PODF], 24000000);
+       clk_set_parent(hws[IMX6SX_CLK_AUDIO_SEL]->clk, hws[IMX6SX_CLK_PLL3_USB_OTG]->clk);
+       clk_set_rate(hws[IMX6SX_CLK_AUDIO_PODF]->clk, 24000000);
 
-       clk_set_parent(clks[IMX6SX_CLK_SSI1_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
-       clk_set_parent(clks[IMX6SX_CLK_SSI2_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
-       clk_set_parent(clks[IMX6SX_CLK_SSI3_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
-       clk_set_rate(clks[IMX6SX_CLK_SSI1_PODF], 24576000);
-       clk_set_rate(clks[IMX6SX_CLK_SSI2_PODF], 24576000);
-       clk_set_rate(clks[IMX6SX_CLK_SSI3_PODF], 24576000);
+       clk_set_parent(hws[IMX6SX_CLK_SSI1_SEL]->clk, hws[IMX6SX_CLK_PLL4_AUDIO_DIV]->clk);
+       clk_set_parent(hws[IMX6SX_CLK_SSI2_SEL]->clk, hws[IMX6SX_CLK_PLL4_AUDIO_DIV]->clk);
+       clk_set_parent(hws[IMX6SX_CLK_SSI3_SEL]->clk, hws[IMX6SX_CLK_PLL4_AUDIO_DIV]->clk);
+       clk_set_rate(hws[IMX6SX_CLK_SSI1_PODF]->clk, 24576000);
+       clk_set_rate(hws[IMX6SX_CLK_SSI2_PODF]->clk, 24576000);
+       clk_set_rate(hws[IMX6SX_CLK_SSI3_PODF]->clk, 24576000);
 
-       clk_set_parent(clks[IMX6SX_CLK_ESAI_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
-       clk_set_rate(clks[IMX6SX_CLK_ESAI_PODF], 24576000);
+       clk_set_parent(hws[IMX6SX_CLK_ESAI_SEL]->clk, hws[IMX6SX_CLK_PLL4_AUDIO_DIV]->clk);
+       clk_set_rate(hws[IMX6SX_CLK_ESAI_PODF]->clk, 24576000);
 
        /* Set parent clock for vadc */
-       clk_set_parent(clks[IMX6SX_CLK_VID_SEL], clks[IMX6SX_CLK_PLL3_USB_OTG]);
+       clk_set_parent(hws[IMX6SX_CLK_VID_SEL]->clk, hws[IMX6SX_CLK_PLL3_USB_OTG]->clk);
 
        /* default parent of can_sel clock is invalid, manually set it here */
-       clk_set_parent(clks[IMX6SX_CLK_CAN_SEL], clks[IMX6SX_CLK_PLL3_60M]);
+       clk_set_parent(hws[IMX6SX_CLK_CAN_SEL]->clk, hws[IMX6SX_CLK_PLL3_60M]->clk);
 
        /* Update gpu clock from default 528M to 720M */
-       clk_set_parent(clks[IMX6SX_CLK_GPU_CORE_SEL], clks[IMX6SX_CLK_PLL3_PFD0]);
-       clk_set_parent(clks[IMX6SX_CLK_GPU_AXI_SEL], clks[IMX6SX_CLK_PLL3_PFD0]);
+       clk_set_parent(hws[IMX6SX_CLK_GPU_CORE_SEL]->clk, hws[IMX6SX_CLK_PLL3_PFD0]->clk);
+       clk_set_parent(hws[IMX6SX_CLK_GPU_AXI_SEL]->clk, hws[IMX6SX_CLK_PLL3_PFD0]->clk);
 
-       clk_set_parent(clks[IMX6SX_CLK_QSPI1_SEL], clks[IMX6SX_CLK_PLL2_BUS]);
-       clk_set_parent(clks[IMX6SX_CLK_QSPI2_SEL], clks[IMX6SX_CLK_PLL2_BUS]);
+       clk_set_parent(hws[IMX6SX_CLK_QSPI1_SEL]->clk, hws[IMX6SX_CLK_PLL2_BUS]->clk);
+       clk_set_parent(hws[IMX6SX_CLK_QSPI2_SEL]->clk, hws[IMX6SX_CLK_PLL2_BUS]->clk);
+
+       for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
+               int index = uart_clk_ids[i];
+
+               uart_clks[i] = &hws[index]->clk;
+       }
 
        imx_register_uart_clocks(uart_clks);
 }
index 8fd52e1..bc93198 100644 (file)
@@ -6,6 +6,7 @@
 #include <dt-bindings/clock/imx6ul-clock.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
+#include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
@@ -16,9 +17,6 @@
 
 #include "clk.h"
 
-#define BM_CCM_CCDR_MMDC_CH0_MASK      (0x2 << 16)
-#define CCDR   0x4
-
 static const char *pll_bypass_src_sels[] = { "osc", "dummy", };
 static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", };
 static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", };
@@ -70,8 +68,8 @@ static const char *cko2_sels[] = { "dummy", "dummy", "dummy", "usdhc1", "dummy",
                                   "dummy", "dummy", "dummy", "dummy", "uart_serial", "spdif", "dummy", "dummy", };
 static const char *cko_sels[] = { "cko1", "cko2", };
 
-static struct clk *clks[IMX6UL_CLK_END];
-static struct clk_onecell_data clk_data;
+static struct clk_hw **hws;
+static struct clk_hw_onecell_data *clk_hw_data;
 
 static const struct clk_div_table clk_enet_ref_table[] = {
        { .val = 0, .div = 20, },
@@ -118,61 +116,69 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
        struct device_node *np;
        void __iomem *base;
 
-       clks[IMX6UL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
+       clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
+                                         IMX6UL_CLK_END), GFP_KERNEL);
+       if (WARN_ON(!clk_hw_data))
+               return;
+
+       clk_hw_data->num = IMX6UL_CLK_END;
+       hws = clk_hw_data->hws;
+
+       hws[IMX6UL_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
 
-       clks[IMX6UL_CLK_CKIL] = of_clk_get_by_name(ccm_node, "ckil");
-       clks[IMX6UL_CLK_OSC] = of_clk_get_by_name(ccm_node, "osc");
+       hws[IMX6UL_CLK_CKIL] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ckil"));
+       hws[IMX6UL_CLK_OSC] = __clk_get_hw(of_clk_get_by_name(ccm_node, "osc"));
 
        /* ipp_di clock is external input */
-       clks[IMX6UL_CLK_IPP_DI0] = of_clk_get_by_name(ccm_node, "ipp_di0");
-       clks[IMX6UL_CLK_IPP_DI1] = of_clk_get_by_name(ccm_node, "ipp_di1");
+       hws[IMX6UL_CLK_IPP_DI0] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di0"));
+       hws[IMX6UL_CLK_IPP_DI1] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di1"));
 
        np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-anatop");
        base = of_iomap(np, 0);
        of_node_put(np);
        WARN_ON(!base);
 
-       clks[IMX6UL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6UL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6UL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6UL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6UL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6UL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6UL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-
-       clks[IMX6UL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS,     "pll1", "osc", base + 0x00, 0x7f);
-       clks[IMX6UL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
-       clks[IMX6UL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB,     "pll3", "osc", base + 0x10, 0x3);
-       clks[IMX6UL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV,      "pll4", "osc", base + 0x70, 0x7f);
-       clks[IMX6UL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV,      "pll5", "osc", base + 0xa0, 0x7f);
-       clks[IMX6UL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET,    "pll6", "osc", base + 0xe0, 0x3);
-       clks[IMX6UL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB,     "pll7", "osc", base + 0x20, 0x3);
-
-       clks[IMX6UL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6UL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6UL_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6UL_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6UL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6UL_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6UL_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6UL_CLK_CSI_SEL] = imx_clk_mux_flags("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6UL_PLL1_BYPASS_SRC] = imx_clk_hw_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6UL_PLL2_BYPASS_SRC] = imx_clk_hw_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6UL_PLL3_BYPASS_SRC] = imx_clk_hw_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6UL_PLL4_BYPASS_SRC] = imx_clk_hw_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6UL_PLL5_BYPASS_SRC] = imx_clk_hw_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6UL_PLL6_BYPASS_SRC] = imx_clk_hw_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6UL_PLL7_BYPASS_SRC] = imx_clk_hw_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+
+       hws[IMX6UL_CLK_PLL1] = imx_clk_hw_pllv3(IMX_PLLV3_SYS,   "pll1", "osc", base + 0x00, 0x7f);
+       hws[IMX6UL_CLK_PLL2] = imx_clk_hw_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
+       hws[IMX6UL_CLK_PLL3] = imx_clk_hw_pllv3(IMX_PLLV3_USB,   "pll3", "osc", base + 0x10, 0x3);
+       hws[IMX6UL_CLK_PLL4] = imx_clk_hw_pllv3(IMX_PLLV3_AV,    "pll4", "osc", base + 0x70, 0x7f);
+       hws[IMX6UL_CLK_PLL5] = imx_clk_hw_pllv3(IMX_PLLV3_AV,    "pll5", "osc", base + 0xa0, 0x7f);
+       hws[IMX6UL_CLK_PLL6] = imx_clk_hw_pllv3(IMX_PLLV3_ENET,  "pll6", "osc", base + 0xe0, 0x3);
+       hws[IMX6UL_CLK_PLL7] = imx_clk_hw_pllv3(IMX_PLLV3_USB,   "pll7", "osc", base + 0x20, 0x3);
+
+       hws[IMX6UL_PLL1_BYPASS] = imx_clk_hw_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6UL_PLL2_BYPASS] = imx_clk_hw_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6UL_PLL3_BYPASS] = imx_clk_hw_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6UL_PLL4_BYPASS] = imx_clk_hw_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6UL_PLL5_BYPASS] = imx_clk_hw_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6UL_PLL6_BYPASS] = imx_clk_hw_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6UL_PLL7_BYPASS] = imx_clk_hw_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6UL_CLK_CSI_SEL] = imx_clk_hw_mux_flags("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels), CLK_SET_RATE_PARENT);
 
        /* Do not bypass PLLs initially */
-       clk_set_parent(clks[IMX6UL_PLL1_BYPASS], clks[IMX6UL_CLK_PLL1]);
-       clk_set_parent(clks[IMX6UL_PLL2_BYPASS], clks[IMX6UL_CLK_PLL2]);
-       clk_set_parent(clks[IMX6UL_PLL3_BYPASS], clks[IMX6UL_CLK_PLL3]);
-       clk_set_parent(clks[IMX6UL_PLL4_BYPASS], clks[IMX6UL_CLK_PLL4]);
-       clk_set_parent(clks[IMX6UL_PLL5_BYPASS], clks[IMX6UL_CLK_PLL5]);
-       clk_set_parent(clks[IMX6UL_PLL6_BYPASS], clks[IMX6UL_CLK_PLL6]);
-       clk_set_parent(clks[IMX6UL_PLL7_BYPASS], clks[IMX6UL_CLK_PLL7]);
-
-       clks[IMX6UL_CLK_PLL1_SYS]       = imx_clk_fixed_factor("pll1_sys",      "pll1_bypass", 1, 1);
-       clks[IMX6UL_CLK_PLL2_BUS]       = imx_clk_gate("pll2_bus",      "pll2_bypass", base + 0x30, 13);
-       clks[IMX6UL_CLK_PLL3_USB_OTG]   = imx_clk_gate("pll3_usb_otg",  "pll3_bypass", base + 0x10, 13);
-       clks[IMX6UL_CLK_PLL4_AUDIO]     = imx_clk_gate("pll4_audio",    "pll4_bypass", base + 0x70, 13);
-       clks[IMX6UL_CLK_PLL5_VIDEO]     = imx_clk_gate("pll5_video",    "pll5_bypass", base + 0xa0, 13);
-       clks[IMX6UL_CLK_PLL6_ENET]      = imx_clk_gate("pll6_enet",     "pll6_bypass", base + 0xe0, 13);
-       clks[IMX6UL_CLK_PLL7_USB_HOST]  = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
+       clk_set_parent(hws[IMX6UL_PLL1_BYPASS]->clk, hws[IMX6UL_CLK_PLL1]->clk);
+       clk_set_parent(hws[IMX6UL_PLL2_BYPASS]->clk, hws[IMX6UL_CLK_PLL2]->clk);
+       clk_set_parent(hws[IMX6UL_PLL3_BYPASS]->clk, hws[IMX6UL_CLK_PLL3]->clk);
+       clk_set_parent(hws[IMX6UL_PLL4_BYPASS]->clk, hws[IMX6UL_CLK_PLL4]->clk);
+       clk_set_parent(hws[IMX6UL_PLL5_BYPASS]->clk, hws[IMX6UL_CLK_PLL5]->clk);
+       clk_set_parent(hws[IMX6UL_PLL6_BYPASS]->clk, hws[IMX6UL_CLK_PLL6]->clk);
+       clk_set_parent(hws[IMX6UL_PLL7_BYPASS]->clk, hws[IMX6UL_CLK_PLL7]->clk);
+
+       hws[IMX6UL_CLK_PLL1_SYS]        = imx_clk_hw_fixed_factor("pll1_sys",   "pll1_bypass", 1, 1);
+       hws[IMX6UL_CLK_PLL2_BUS]        = imx_clk_hw_gate("pll2_bus",   "pll2_bypass", base + 0x30, 13);
+       hws[IMX6UL_CLK_PLL3_USB_OTG]    = imx_clk_hw_gate("pll3_usb_otg",       "pll3_bypass", base + 0x10, 13);
+       hws[IMX6UL_CLK_PLL4_AUDIO]      = imx_clk_hw_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
+       hws[IMX6UL_CLK_PLL5_VIDEO]      = imx_clk_hw_gate("pll5_video", "pll5_bypass", base + 0xa0, 13);
+       hws[IMX6UL_CLK_PLL6_ENET]       = imx_clk_hw_gate("pll6_enet",  "pll6_bypass", base + 0xe0, 13);
+       hws[IMX6UL_CLK_PLL7_USB_HOST]   = imx_clk_hw_gate("pll7_usb_host",      "pll7_bypass", base + 0x20, 13);
 
        /*
         * Bit 20 is the reserved and read-only bit, we do this only for:
@@ -180,291 +186,289 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
         * - Keep refcount when do usbphy clk_enable/disable, in that case,
         * the clk framework many need to enable/disable usbphy's parent
         */
-       clks[IMX6UL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg",  base + 0x10, 20);
-       clks[IMX6UL_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
+       hws[IMX6UL_CLK_USBPHY1] = imx_clk_hw_gate("usbphy1", "pll3_usb_otg",  base + 0x10, 20);
+       hws[IMX6UL_CLK_USBPHY2] = imx_clk_hw_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
 
        /*
         * usbphy*_gate needs to be on after system boots up, and software
         * never needs to control it anymore.
         */
-       clks[IMX6UL_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6);
-       clks[IMX6UL_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6);
+       hws[IMX6UL_CLK_USBPHY1_GATE] = imx_clk_hw_gate("usbphy1_gate", "dummy", base + 0x10, 6);
+       hws[IMX6UL_CLK_USBPHY2_GATE] = imx_clk_hw_gate("usbphy2_gate", "dummy", base + 0x20, 6);
 
        /*                                      name               parent_name     reg          idx */
-       clks[IMX6UL_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus",     base + 0x100, 0);
-       clks[IMX6UL_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus",     base + 0x100, 1);
-       clks[IMX6UL_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus",     base + 0x100, 2);
-       clks[IMX6UL_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3_594m", "pll2_bus",     base + 0x100, 3);
-       clks[IMX6UL_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0,  0);
-       clks[IMX6UL_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0,  1);
-       clks[IMX6UL_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0,  2);
-       clks[IMX6UL_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0,  3);
-
-       clks[IMX6UL_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
+       hws[IMX6UL_CLK_PLL2_PFD0] = imx_clk_hw_pfd("pll2_pfd0_352m", "pll2_bus",           base + 0x100, 0);
+       hws[IMX6UL_CLK_PLL2_PFD1] = imx_clk_hw_pfd("pll2_pfd1_594m", "pll2_bus",           base + 0x100, 1);
+       hws[IMX6UL_CLK_PLL2_PFD2] = imx_clk_hw_pfd("pll2_pfd2_396m", "pll2_bus",           base + 0x100, 2);
+       hws[IMX6UL_CLK_PLL2_PFD3] = imx_clk_hw_pfd("pll2_pfd3_594m", "pll2_bus",           base + 0x100, 3);
+       hws[IMX6UL_CLK_PLL3_PFD0] = imx_clk_hw_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0,  0);
+       hws[IMX6UL_CLK_PLL3_PFD1] = imx_clk_hw_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0,  1);
+       hws[IMX6UL_CLK_PLL3_PFD2] = imx_clk_hw_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0,        2);
+       hws[IMX6UL_CLK_PLL3_PFD3] = imx_clk_hw_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0,        3);
+
+       hws[IMX6UL_CLK_ENET_REF] = clk_hw_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
                        base + 0xe0, 0, 2, 0, clk_enet_ref_table, &imx_ccm_lock);
-       clks[IMX6UL_CLK_ENET2_REF] = clk_register_divider_table(NULL, "enet2_ref", "pll6_enet", 0,
+       hws[IMX6UL_CLK_ENET2_REF] = clk_hw_register_divider_table(NULL, "enet2_ref", "pll6_enet", 0,
                        base + 0xe0, 2, 2, 0, clk_enet_ref_table, &imx_ccm_lock);
 
-       clks[IMX6UL_CLK_ENET2_REF_125M] = imx_clk_gate("enet_ref_125m", "enet2_ref", base + 0xe0, 20);
-       clks[IMX6UL_CLK_ENET_PTP_REF]   = imx_clk_fixed_factor("enet_ptp_ref", "pll6_enet", 1, 20);
-       clks[IMX6UL_CLK_ENET_PTP]       = imx_clk_gate("enet_ptp", "enet_ptp_ref", base + 0xe0, 21);
+       hws[IMX6UL_CLK_ENET2_REF_125M] = imx_clk_hw_gate("enet_ref_125m", "enet2_ref", base + 0xe0, 20);
+       hws[IMX6UL_CLK_ENET_PTP_REF]    = imx_clk_hw_fixed_factor("enet_ptp_ref", "pll6_enet", 1, 20);
+       hws[IMX6UL_CLK_ENET_PTP]        = imx_clk_hw_gate("enet_ptp", "enet_ptp_ref", base + 0xe0, 21);
 
-       clks[IMX6UL_CLK_PLL4_POST_DIV]  = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio",
+       hws[IMX6UL_CLK_PLL4_POST_DIV]  = clk_hw_register_divider_table(NULL, "pll4_post_div", "pll4_audio",
                 CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
-       clks[IMX6UL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div",
+       hws[IMX6UL_CLK_PLL4_AUDIO_DIV] = clk_hw_register_divider(NULL, "pll4_audio_div", "pll4_post_div",
                 CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 15, 1, 0, &imx_ccm_lock);
-       clks[IMX6UL_CLK_PLL5_POST_DIV]  = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video",
+       hws[IMX6UL_CLK_PLL5_POST_DIV]  = clk_hw_register_divider_table(NULL, "pll5_post_div", "pll5_video",
                 CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
-       clks[IMX6UL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div",
+       hws[IMX6UL_CLK_PLL5_VIDEO_DIV] = clk_hw_register_divider_table(NULL, "pll5_video_div", "pll5_post_div",
                 CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
 
        /*                                                 name         parent_name      mult  div */
-       clks[IMX6UL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1,     2);
-       clks[IMX6UL_CLK_PLL3_80M]  = imx_clk_fixed_factor("pll3_80m",  "pll3_usb_otg",   1,     6);
-       clks[IMX6UL_CLK_PLL3_60M]  = imx_clk_fixed_factor("pll3_60m",  "pll3_usb_otg",   1,     8);
-       clks[IMX6UL_CLK_GPT_3M]    = imx_clk_fixed_factor("gpt_3m",     "osc",           1,     8);
+       hws[IMX6UL_CLK_PLL2_198M] = imx_clk_hw_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1,   2);
+       hws[IMX6UL_CLK_PLL3_80M]  = imx_clk_hw_fixed_factor("pll3_80m",  "pll3_usb_otg",   1,   6);
+       hws[IMX6UL_CLK_PLL3_60M]  = imx_clk_hw_fixed_factor("pll3_60m",  "pll3_usb_otg",   1,   8);
+       hws[IMX6UL_CLK_GPT_3M]     = imx_clk_hw_fixed_factor("gpt_3m",  "osc",           1,     8);
 
        np = ccm_node;
        base = of_iomap(np, 0);
        WARN_ON(!base);
 
-       clks[IMX6UL_CA7_SECONDARY_SEL]    = imx_clk_mux("ca7_secondary_sel", base + 0xc, 3, 1, ca7_secondary_sels, ARRAY_SIZE(ca7_secondary_sels));
-       clks[IMX6UL_CLK_STEP]             = imx_clk_mux("step", base + 0x0c, 8, 1, step_sels, ARRAY_SIZE(step_sels));
-       clks[IMX6UL_CLK_PLL1_SW]          = imx_clk_mux_flags("pll1_sw",   base + 0x0c, 2,  1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels), 0);
-       clks[IMX6UL_CLK_AXI_ALT_SEL]      = imx_clk_mux("axi_alt_sel",          base + 0x14, 7,  1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels));
-       clks[IMX6UL_CLK_AXI_SEL]          = imx_clk_mux_flags("axi_sel",        base + 0x14, 6,  1, axi_sels, ARRAY_SIZE(axi_sels), 0);
-       clks[IMX6UL_CLK_PERIPH_PRE]       = imx_clk_mux("periph_pre",       base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
-       clks[IMX6UL_CLK_PERIPH2_PRE]      = imx_clk_mux("periph2_pre",      base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels));
-       clks[IMX6UL_CLK_PERIPH_CLK2_SEL]  = imx_clk_mux("periph_clk2_sel",  base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
-       clks[IMX6UL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
-       clks[IMX6UL_CLK_EIM_SLOW_SEL]     = imx_clk_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels));
-       clks[IMX6UL_CLK_GPMI_SEL]         = imx_clk_mux("gpmi_sel",     base + 0x1c, 19, 1, gpmi_sels, ARRAY_SIZE(gpmi_sels));
-       clks[IMX6UL_CLK_BCH_SEL]          = imx_clk_mux("bch_sel",      base + 0x1c, 18, 1, bch_sels, ARRAY_SIZE(bch_sels));
-       clks[IMX6UL_CLK_USDHC2_SEL]       = imx_clk_mux("usdhc2_sel",   base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
-       clks[IMX6UL_CLK_USDHC1_SEL]       = imx_clk_mux("usdhc1_sel",   base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
-       clks[IMX6UL_CLK_SAI3_SEL]         = imx_clk_mux("sai3_sel",     base + 0x1c, 14, 2, sai_sels, ARRAY_SIZE(sai_sels));
-       clks[IMX6UL_CLK_SAI2_SEL]         = imx_clk_mux("sai2_sel",     base + 0x1c, 12, 2, sai_sels, ARRAY_SIZE(sai_sels));
-       clks[IMX6UL_CLK_SAI1_SEL]         = imx_clk_mux("sai1_sel",     base + 0x1c, 10, 2, sai_sels, ARRAY_SIZE(sai_sels));
-       clks[IMX6UL_CLK_QSPI1_SEL]        = imx_clk_mux("qspi1_sel",    base + 0x1c, 7,  3, qspi1_sels, ARRAY_SIZE(qspi1_sels));
-       clks[IMX6UL_CLK_PERCLK_SEL]       = imx_clk_mux("perclk_sel",   base + 0x1c, 6,  1, perclk_sels, ARRAY_SIZE(perclk_sels));
-       clks[IMX6UL_CLK_CAN_SEL]          = imx_clk_mux("can_sel",      base + 0x20, 8,  2, can_sels, ARRAY_SIZE(can_sels));
+       hws[IMX6UL_CA7_SECONDARY_SEL]     = imx_clk_hw_mux("ca7_secondary_sel", base + 0xc, 3, 1, ca7_secondary_sels, ARRAY_SIZE(ca7_secondary_sels));
+       hws[IMX6UL_CLK_STEP]              = imx_clk_hw_mux("step", base + 0x0c, 8, 1, step_sels, ARRAY_SIZE(step_sels));
+       hws[IMX6UL_CLK_PLL1_SW]   = imx_clk_hw_mux_flags("pll1_sw",   base + 0x0c, 2,  1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels), 0);
+       hws[IMX6UL_CLK_AXI_ALT_SEL]       = imx_clk_hw_mux("axi_alt_sel",               base + 0x14, 7,  1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels));
+       hws[IMX6UL_CLK_AXI_SEL]   = imx_clk_hw_mux_flags("axi_sel",     base + 0x14, 6,  1, axi_sels, ARRAY_SIZE(axi_sels), 0);
+       hws[IMX6UL_CLK_PERIPH_PRE]        = imx_clk_hw_mux("periph_pre",       base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
+       hws[IMX6UL_CLK_PERIPH2_PRE]       = imx_clk_hw_mux("periph2_pre",      base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels));
+       hws[IMX6UL_CLK_PERIPH_CLK2_SEL]  = imx_clk_hw_mux("periph_clk2_sel",  base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
+       hws[IMX6UL_CLK_PERIPH2_CLK2_SEL] = imx_clk_hw_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
+       hws[IMX6UL_CLK_EIM_SLOW_SEL]      = imx_clk_hw_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels));
+       hws[IMX6UL_CLK_GPMI_SEL]          = imx_clk_hw_mux("gpmi_sel",     base + 0x1c, 19, 1, gpmi_sels, ARRAY_SIZE(gpmi_sels));
+       hws[IMX6UL_CLK_BCH_SEL]   = imx_clk_hw_mux("bch_sel",   base + 0x1c, 18, 1, bch_sels, ARRAY_SIZE(bch_sels));
+       hws[IMX6UL_CLK_USDHC2_SEL]        = imx_clk_hw_mux("usdhc2_sel",   base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+       hws[IMX6UL_CLK_USDHC1_SEL]        = imx_clk_hw_mux("usdhc1_sel",   base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+       hws[IMX6UL_CLK_SAI3_SEL]          = imx_clk_hw_mux("sai3_sel",     base + 0x1c, 14, 2, sai_sels, ARRAY_SIZE(sai_sels));
+       hws[IMX6UL_CLK_SAI2_SEL]         = imx_clk_hw_mux("sai2_sel",     base + 0x1c, 12, 2, sai_sels, ARRAY_SIZE(sai_sels));
+       hws[IMX6UL_CLK_SAI1_SEL]          = imx_clk_hw_mux("sai1_sel",     base + 0x1c, 10, 2, sai_sels, ARRAY_SIZE(sai_sels));
+       hws[IMX6UL_CLK_QSPI1_SEL]         = imx_clk_hw_mux("qspi1_sel",    base + 0x1c, 7,  3, qspi1_sels, ARRAY_SIZE(qspi1_sels));
+       hws[IMX6UL_CLK_PERCLK_SEL]        = imx_clk_hw_mux("perclk_sel",        base + 0x1c, 6,  1, perclk_sels, ARRAY_SIZE(perclk_sels));
+       hws[IMX6UL_CLK_CAN_SEL]   = imx_clk_hw_mux("can_sel",   base + 0x20, 8,  2, can_sels, ARRAY_SIZE(can_sels));
        if (clk_on_imx6ull())
-               clks[IMX6ULL_CLK_ESAI_SEL]        = imx_clk_mux("esai_sel",     base + 0x20, 19, 2, esai_sels, ARRAY_SIZE(esai_sels));
-       clks[IMX6UL_CLK_UART_SEL]         = imx_clk_mux("uart_sel",     base + 0x24, 6,  1, uart_sels, ARRAY_SIZE(uart_sels));
-       clks[IMX6UL_CLK_ENFC_SEL]         = imx_clk_mux("enfc_sel",     base + 0x2c, 15, 3, enfc_sels, ARRAY_SIZE(enfc_sels));
-       clks[IMX6UL_CLK_LDB_DI0_SEL]      = imx_clk_mux("ldb_di0_sel",  base + 0x2c, 9,  3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels));
-       clks[IMX6UL_CLK_SPDIF_SEL]        = imx_clk_mux("spdif_sel",    base + 0x30, 20, 2, spdif_sels, ARRAY_SIZE(spdif_sels));
+               hws[IMX6ULL_CLK_ESAI_SEL]         = imx_clk_hw_mux("esai_sel",  base + 0x20, 19, 2, esai_sels, ARRAY_SIZE(esai_sels));
+       hws[IMX6UL_CLK_UART_SEL]          = imx_clk_hw_mux("uart_sel",  base + 0x24, 6,  1, uart_sels, ARRAY_SIZE(uart_sels));
+       hws[IMX6UL_CLK_ENFC_SEL]          = imx_clk_hw_mux("enfc_sel",  base + 0x2c, 15, 3, enfc_sels, ARRAY_SIZE(enfc_sels));
+       hws[IMX6UL_CLK_LDB_DI0_SEL]       = imx_clk_hw_mux("ldb_di0_sel",       base + 0x2c, 9,  3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels));
+       hws[IMX6UL_CLK_SPDIF_SEL]         = imx_clk_hw_mux("spdif_sel", base + 0x30, 20, 2, spdif_sels, ARRAY_SIZE(spdif_sels));
        if (clk_on_imx6ul()) {
-               clks[IMX6UL_CLK_SIM_PRE_SEL]      = imx_clk_mux("sim_pre_sel",  base + 0x34, 15, 3, sim_pre_sels, ARRAY_SIZE(sim_pre_sels));
-               clks[IMX6UL_CLK_SIM_SEL]          = imx_clk_mux("sim_sel",      base + 0x34, 9, 3, sim_sels, ARRAY_SIZE(sim_sels));
+               hws[IMX6UL_CLK_SIM_PRE_SEL]     = imx_clk_hw_mux("sim_pre_sel", base + 0x34, 15, 3, sim_pre_sels, ARRAY_SIZE(sim_pre_sels));
+               hws[IMX6UL_CLK_SIM_SEL]         = imx_clk_hw_mux("sim_sel",     base + 0x34, 9, 3, sim_sels, ARRAY_SIZE(sim_sels));
        } else if (clk_on_imx6ull()) {
-               clks[IMX6ULL_CLK_EPDC_PRE_SEL]    = imx_clk_mux("epdc_pre_sel", base + 0x34, 15, 3, epdc_pre_sels, ARRAY_SIZE(epdc_pre_sels));
-               clks[IMX6ULL_CLK_EPDC_SEL]        = imx_clk_mux("epdc_sel",     base + 0x34, 9, 3, epdc_sels, ARRAY_SIZE(epdc_sels));
+               hws[IMX6ULL_CLK_EPDC_PRE_SEL]   = imx_clk_hw_mux("epdc_pre_sel",        base + 0x34, 15, 3, epdc_pre_sels, ARRAY_SIZE(epdc_pre_sels));
+               hws[IMX6ULL_CLK_EPDC_SEL]       = imx_clk_hw_mux("epdc_sel",    base + 0x34, 9, 3, epdc_sels, ARRAY_SIZE(epdc_sels));
        }
-       clks[IMX6UL_CLK_ECSPI_SEL]        = imx_clk_mux("ecspi_sel",    base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
-       clks[IMX6UL_CLK_LCDIF_PRE_SEL]    = imx_clk_mux_flags("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6UL_CLK_LCDIF_SEL]        = imx_clk_mux("lcdif_sel",    base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels));
-
-       clks[IMX6UL_CLK_LDB_DI0_DIV_SEL]  = imx_clk_mux("ldb_di0", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels));
-       clks[IMX6UL_CLK_LDB_DI1_DIV_SEL]  = imx_clk_mux("ldb_di1", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels));
-
-       clks[IMX6UL_CLK_CKO1_SEL]         = imx_clk_mux("cko1_sel", base + 0x60, 0,  4, cko1_sels, ARRAY_SIZE(cko1_sels));
-       clks[IMX6UL_CLK_CKO2_SEL]         = imx_clk_mux("cko2_sel", base + 0x60, 16, 5, cko2_sels, ARRAY_SIZE(cko2_sels));
-       clks[IMX6UL_CLK_CKO]              = imx_clk_mux("cko", base + 0x60, 8, 1, cko_sels, ARRAY_SIZE(cko_sels));
-
-       clks[IMX6UL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
-       clks[IMX6UL_CLK_LDB_DI0_DIV_7]   = imx_clk_fixed_factor("ldb_di0_div_7",   "ldb_di0_sel", 1, 7);
-       clks[IMX6UL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "qspi1_sel", 2, 7);
-       clks[IMX6UL_CLK_LDB_DI1_DIV_7]   = imx_clk_fixed_factor("ldb_di1_div_7",   "qspi1_sel", 1, 7);
-
-       clks[IMX6UL_CLK_PERIPH]  = imx_clk_busy_mux("periph",  base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
-       clks[IMX6UL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
-
-       clks[IMX6UL_CLK_PERIPH_CLK2]    = imx_clk_divider("periph_clk2",   "periph_clk2_sel",   base + 0x14, 27, 3);
-       clks[IMX6UL_CLK_PERIPH2_CLK2]   = imx_clk_divider("periph2_clk2",  "periph2_clk2_sel",  base + 0x14, 0,  3);
-       clks[IMX6UL_CLK_IPG]            = imx_clk_divider("ipg",           "ahb",               base + 0x14, 8,  2);
-       clks[IMX6UL_CLK_LCDIF_PODF]     = imx_clk_divider("lcdif_podf",    "lcdif_pred",        base + 0x18, 23, 3);
-       clks[IMX6UL_CLK_QSPI1_PDOF]     = imx_clk_divider("qspi1_podf",    "qspi1_sel",         base + 0x1c, 26, 3);
-       clks[IMX6UL_CLK_EIM_SLOW_PODF]  = imx_clk_divider("eim_slow_podf", "eim_slow_sel",      base + 0x1c, 23, 3);
-       clks[IMX6UL_CLK_PERCLK]         = imx_clk_divider("perclk",        "perclk_sel",        base + 0x1c, 0,  6);
-       clks[IMX6UL_CLK_CAN_PODF]       = imx_clk_divider("can_podf",      "can_sel",           base + 0x20, 2,  6);
-       clks[IMX6UL_CLK_GPMI_PODF]      = imx_clk_divider("gpmi_podf",     "gpmi_sel",          base + 0x24, 22, 3);
-       clks[IMX6UL_CLK_BCH_PODF]       = imx_clk_divider("bch_podf",      "bch_sel",           base + 0x24, 19, 3);
-       clks[IMX6UL_CLK_USDHC2_PODF]    = imx_clk_divider("usdhc2_podf",   "usdhc2_sel",        base + 0x24, 16, 3);
-       clks[IMX6UL_CLK_USDHC1_PODF]    = imx_clk_divider("usdhc1_podf",   "usdhc1_sel",        base + 0x24, 11, 3);
-       clks[IMX6UL_CLK_UART_PODF]      = imx_clk_divider("uart_podf",     "uart_sel",          base + 0x24, 0,  6);
-       clks[IMX6UL_CLK_SAI3_PRED]      = imx_clk_divider("sai3_pred",     "sai3_sel",          base + 0x28, 22, 3);
-       clks[IMX6UL_CLK_SAI3_PODF]      = imx_clk_divider("sai3_podf",     "sai3_pred",         base + 0x28, 16, 6);
-       clks[IMX6UL_CLK_SAI1_PRED]      = imx_clk_divider("sai1_pred",     "sai1_sel",          base + 0x28, 6,  3);
-       clks[IMX6UL_CLK_SAI1_PODF]      = imx_clk_divider("sai1_podf",     "sai1_pred",         base + 0x28, 0,  6);
+       hws[IMX6UL_CLK_ECSPI_SEL]         = imx_clk_hw_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
+       hws[IMX6UL_CLK_LCDIF_PRE_SEL]     = imx_clk_hw_mux_flags("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6UL_CLK_LCDIF_SEL]         = imx_clk_hw_mux("lcdif_sel", base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels));
+
+       hws[IMX6UL_CLK_LDB_DI0_DIV_SEL]  = imx_clk_hw_mux("ldb_di0", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels));
+       hws[IMX6UL_CLK_LDB_DI1_DIV_SEL]  = imx_clk_hw_mux("ldb_di1", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels));
+
+       hws[IMX6UL_CLK_CKO1_SEL]          = imx_clk_hw_mux("cko1_sel", base + 0x60, 0,  4, cko1_sels, ARRAY_SIZE(cko1_sels));
+       hws[IMX6UL_CLK_CKO2_SEL]          = imx_clk_hw_mux("cko2_sel", base + 0x60, 16, 5, cko2_sels, ARRAY_SIZE(cko2_sels));
+       hws[IMX6UL_CLK_CKO]               = imx_clk_hw_mux("cko", base + 0x60, 8, 1, cko_sels, ARRAY_SIZE(cko_sels));
+
+       hws[IMX6UL_CLK_LDB_DI0_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
+       hws[IMX6UL_CLK_LDB_DI0_DIV_7]    = imx_clk_hw_fixed_factor("ldb_di0_div_7",   "ldb_di0_sel", 1, 7);
+       hws[IMX6UL_CLK_LDB_DI1_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di1_div_3_5", "qspi1_sel", 2, 7);
+       hws[IMX6UL_CLK_LDB_DI1_DIV_7]    = imx_clk_hw_fixed_factor("ldb_di1_div_7",   "qspi1_sel", 1, 7);
+
+       hws[IMX6UL_CLK_PERIPH]  = imx_clk_hw_busy_mux("periph",  base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
+       hws[IMX6UL_CLK_PERIPH2] = imx_clk_hw_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
+
+       hws[IMX6UL_CLK_PERIPH_CLK2]     = imx_clk_hw_divider("periph_clk2",   "periph_clk2_sel",        base + 0x14, 27, 3);
+       hws[IMX6UL_CLK_PERIPH2_CLK2]    = imx_clk_hw_divider("periph2_clk2",  "periph2_clk2_sel",       base + 0x14, 0,  3);
+       hws[IMX6UL_CLK_IPG]             = imx_clk_hw_divider("ipg",        "ahb",               base + 0x14, 8,  2);
+       hws[IMX6UL_CLK_LCDIF_PODF]      = imx_clk_hw_divider("lcdif_podf",         "lcdif_pred",        base + 0x18, 23, 3);
+       hws[IMX6UL_CLK_QSPI1_PDOF]      = imx_clk_hw_divider("qspi1_podf",         "qspi1_sel",         base + 0x1c, 26, 3);
+       hws[IMX6UL_CLK_EIM_SLOW_PODF]   = imx_clk_hw_divider("eim_slow_podf", "eim_slow_sel",   base + 0x1c, 23, 3);
+       hws[IMX6UL_CLK_PERCLK]          = imx_clk_hw_divider("perclk",     "perclk_sel",        base + 0x1c, 0,  6);
+       hws[IMX6UL_CLK_CAN_PODF]        = imx_clk_hw_divider("can_podf",           "can_sel",           base + 0x20, 2,  6);
+       hws[IMX6UL_CLK_GPMI_PODF]       = imx_clk_hw_divider("gpmi_podf",          "gpmi_sel",          base + 0x24, 22, 3);
+       hws[IMX6UL_CLK_BCH_PODF]        = imx_clk_hw_divider("bch_podf",           "bch_sel",           base + 0x24, 19, 3);
+       hws[IMX6UL_CLK_USDHC2_PODF]     = imx_clk_hw_divider("usdhc2_podf",   "usdhc2_sel",     base + 0x24, 16, 3);
+       hws[IMX6UL_CLK_USDHC1_PODF]     = imx_clk_hw_divider("usdhc1_podf",   "usdhc1_sel",     base + 0x24, 11, 3);
+       hws[IMX6UL_CLK_UART_PODF]       = imx_clk_hw_divider("uart_podf",          "uart_sel",          base + 0x24, 0,  6);
+       hws[IMX6UL_CLK_SAI3_PRED]       = imx_clk_hw_divider("sai3_pred",          "sai3_sel",          base + 0x28, 22, 3);
+       hws[IMX6UL_CLK_SAI3_PODF]       = imx_clk_hw_divider("sai3_podf",          "sai3_pred",         base + 0x28, 16, 6);
+       hws[IMX6UL_CLK_SAI1_PRED]       = imx_clk_hw_divider("sai1_pred",          "sai1_sel",          base + 0x28, 6,  3);
+       hws[IMX6UL_CLK_SAI1_PODF]       = imx_clk_hw_divider("sai1_podf",          "sai1_pred",         base + 0x28, 0,  6);
        if (clk_on_imx6ull()) {
-               clks[IMX6ULL_CLK_ESAI_PRED]     = imx_clk_divider("esai_pred",     "esai_sel",          base + 0x28, 9,  3);
-               clks[IMX6ULL_CLK_ESAI_PODF]     = imx_clk_divider("esai_podf",     "esai_pred",         base + 0x28, 25, 3);
+               hws[IMX6ULL_CLK_ESAI_PRED]      = imx_clk_hw_divider("esai_pred",     "esai_sel",               base + 0x28, 9,  3);
+               hws[IMX6ULL_CLK_ESAI_PODF]      = imx_clk_hw_divider("esai_podf",     "esai_pred",              base + 0x28, 25, 3);
        }
-       clks[IMX6UL_CLK_ENFC_PRED]      = imx_clk_divider("enfc_pred",     "enfc_sel",          base + 0x2c, 18, 3);
-       clks[IMX6UL_CLK_ENFC_PODF]      = imx_clk_divider("enfc_podf",     "enfc_pred",         base + 0x2c, 21, 6);
-       clks[IMX6UL_CLK_SAI2_PRED]      = imx_clk_divider("sai2_pred",     "sai2_sel",          base + 0x2c, 6,  3);
-       clks[IMX6UL_CLK_SAI2_PODF]      = imx_clk_divider("sai2_podf",     "sai2_pred",         base + 0x2c, 0,  6);
-       clks[IMX6UL_CLK_SPDIF_PRED]     = imx_clk_divider("spdif_pred",    "spdif_sel",         base + 0x30, 25, 3);
-       clks[IMX6UL_CLK_SPDIF_PODF]     = imx_clk_divider("spdif_podf",    "spdif_pred",        base + 0x30, 22, 3);
+       hws[IMX6UL_CLK_ENFC_PRED]       = imx_clk_hw_divider("enfc_pred",          "enfc_sel",          base + 0x2c, 18, 3);
+       hws[IMX6UL_CLK_ENFC_PODF]       = imx_clk_hw_divider("enfc_podf",          "enfc_pred",         base + 0x2c, 21, 6);
+       hws[IMX6UL_CLK_SAI2_PRED]       = imx_clk_hw_divider("sai2_pred",          "sai2_sel",          base + 0x2c, 6,  3);
+       hws[IMX6UL_CLK_SAI2_PODF]       = imx_clk_hw_divider("sai2_podf",          "sai2_pred",         base + 0x2c, 0,  6);
+       hws[IMX6UL_CLK_SPDIF_PRED]      = imx_clk_hw_divider("spdif_pred",         "spdif_sel",         base + 0x30, 25, 3);
+       hws[IMX6UL_CLK_SPDIF_PODF]      = imx_clk_hw_divider("spdif_podf",         "spdif_pred",        base + 0x30, 22, 3);
        if (clk_on_imx6ul())
-               clks[IMX6UL_CLK_SIM_PODF]       = imx_clk_divider("sim_podf",      "sim_pre_sel",       base + 0x34, 12, 3);
+               hws[IMX6UL_CLK_SIM_PODF]        = imx_clk_hw_divider("sim_podf",           "sim_pre_sel",       base + 0x34, 12, 3);
        else if (clk_on_imx6ull())
-               clks[IMX6ULL_CLK_EPDC_PODF]     = imx_clk_divider("epdc_podf",     "epdc_pre_sel",      base + 0x34, 12, 3);
-       clks[IMX6UL_CLK_ECSPI_PODF]     = imx_clk_divider("ecspi_podf",    "ecspi_sel",         base + 0x38, 19, 6);
-       clks[IMX6UL_CLK_LCDIF_PRED]     = imx_clk_divider("lcdif_pred",    "lcdif_pre_sel",     base + 0x38, 12, 3);
-       clks[IMX6UL_CLK_CSI_PODF]       = imx_clk_divider("csi_podf",      "csi_sel",           base + 0x3c, 11, 3);
+               hws[IMX6ULL_CLK_EPDC_PODF]      = imx_clk_hw_divider("epdc_podf",          "epdc_pre_sel",      base + 0x34, 12, 3);
+       hws[IMX6UL_CLK_ECSPI_PODF]      = imx_clk_hw_divider("ecspi_podf",         "ecspi_sel",         base + 0x38, 19, 6);
+       hws[IMX6UL_CLK_LCDIF_PRED]      = imx_clk_hw_divider("lcdif_pred",         "lcdif_pre_sel",     base + 0x38, 12, 3);
+       hws[IMX6UL_CLK_CSI_PODF]       = imx_clk_hw_divider("csi_podf",      "csi_sel",           base + 0x3c, 11, 3);
 
-       clks[IMX6UL_CLK_CKO1_PODF]      = imx_clk_divider("cko1_podf",     "cko1_sel",          base + 0x60, 4,  3);
-       clks[IMX6UL_CLK_CKO2_PODF]      = imx_clk_divider("cko2_podf",     "cko2_sel",          base + 0x60, 21, 3);
+       hws[IMX6UL_CLK_CKO1_PODF]       = imx_clk_hw_divider("cko1_podf",     "cko1_sel",          base + 0x60, 4,  3);
+       hws[IMX6UL_CLK_CKO2_PODF]       = imx_clk_hw_divider("cko2_podf",     "cko2_sel",          base + 0x60, 21, 3);
 
-       clks[IMX6UL_CLK_ARM]            = imx_clk_busy_divider("arm",       "pll1_sw",  base +  0x10, 0,  3,  base + 0x48, 16);
-       clks[IMX6UL_CLK_MMDC_PODF]      = imx_clk_busy_divider("mmdc_podf", "periph2",  base +  0x14, 3,  3,  base + 0x48, 2);
-       clks[IMX6UL_CLK_AXI_PODF]       = imx_clk_busy_divider("axi_podf",  "axi_sel",  base +  0x14, 16, 3,  base + 0x48, 0);
-       clks[IMX6UL_CLK_AHB]            = imx_clk_busy_divider("ahb",       "periph",   base +  0x14, 10, 3,  base + 0x48, 1);
+       hws[IMX6UL_CLK_ARM]             = imx_clk_hw_busy_divider("arm",            "pll1_sw",  base +  0x10, 0,  3,  base + 0x48, 16);
+       hws[IMX6UL_CLK_MMDC_PODF]       = imx_clk_hw_busy_divider("mmdc_podf", "periph2",       base +  0x14, 3,  3,  base + 0x48, 2);
+       hws[IMX6UL_CLK_AXI_PODF]        = imx_clk_hw_busy_divider("axi_podf",  "axi_sel",       base +  0x14, 16, 3,  base + 0x48, 0);
+       hws[IMX6UL_CLK_AHB]             = imx_clk_hw_busy_divider("ahb",            "periph",   base +  0x14, 10, 3,  base + 0x48, 1);
 
        /* CCGR0 */
-       clks[IMX6UL_CLK_AIPSTZ1]        = imx_clk_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL);
-       clks[IMX6UL_CLK_AIPSTZ2]        = imx_clk_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL);
-       clks[IMX6UL_CLK_APBHDMA]        = imx_clk_gate2("apbh_dma",     "bch_podf",     base + 0x68,    4);
-       clks[IMX6UL_CLK_ASRC_IPG]       = imx_clk_gate2_shared("asrc_ipg",      "ahb",  base + 0x68,    6, &share_count_asrc);
-       clks[IMX6UL_CLK_ASRC_MEM]       = imx_clk_gate2_shared("asrc_mem",      "ahb",  base + 0x68,    6, &share_count_asrc);
+       hws[IMX6UL_CLK_AIPSTZ1] = imx_clk_hw_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL);
+       hws[IMX6UL_CLK_AIPSTZ2] = imx_clk_hw_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL);
+       hws[IMX6UL_CLK_APBHDMA] = imx_clk_hw_gate2("apbh_dma",  "bch_podf",     base + 0x68,    4);
+       hws[IMX6UL_CLK_ASRC_IPG]        = imx_clk_hw_gate2_shared("asrc_ipg",   "ahb",  base + 0x68,    6, &share_count_asrc);
+       hws[IMX6UL_CLK_ASRC_MEM]        = imx_clk_hw_gate2_shared("asrc_mem",   "ahb",  base + 0x68,    6, &share_count_asrc);
        if (clk_on_imx6ul()) {
-               clks[IMX6UL_CLK_CAAM_MEM]       = imx_clk_gate2("caam_mem",     "ahb",          base + 0x68,    8);
-               clks[IMX6UL_CLK_CAAM_ACLK]      = imx_clk_gate2("caam_aclk",    "ahb",          base + 0x68,    10);
-               clks[IMX6UL_CLK_CAAM_IPG]       = imx_clk_gate2("caam_ipg",     "ipg",          base + 0x68,    12);
+               hws[IMX6UL_CLK_CAAM_MEM]        = imx_clk_hw_gate2("caam_mem",  "ahb",          base + 0x68,    8);
+               hws[IMX6UL_CLK_CAAM_ACLK]       = imx_clk_hw_gate2("caam_aclk", "ahb",          base + 0x68,    10);
+               hws[IMX6UL_CLK_CAAM_IPG]        = imx_clk_hw_gate2("caam_ipg",  "ipg",          base + 0x68,    12);
        } else if (clk_on_imx6ull()) {
-               clks[IMX6ULL_CLK_DCP_CLK]       = imx_clk_gate2("dcp",          "ahb",          base + 0x68,    10);
-               clks[IMX6UL_CLK_ENET]           = imx_clk_gate2("enet",         "ipg",          base + 0x68,    12);
-               clks[IMX6UL_CLK_ENET_AHB]       = imx_clk_gate2("enet_ahb",     "ahb",          base + 0x68,    12);
+               hws[IMX6ULL_CLK_DCP_CLK]        = imx_clk_hw_gate2("dcp",               "ahb",          base + 0x68,    10);
+               hws[IMX6UL_CLK_ENET]            = imx_clk_hw_gate2("enet",              "ipg",          base + 0x68,    12);
+               hws[IMX6UL_CLK_ENET_AHB]        = imx_clk_hw_gate2("enet_ahb",  "ahb",          base + 0x68,    12);
        }
-       clks[IMX6UL_CLK_CAN1_IPG]       = imx_clk_gate2("can1_ipg",     "ipg",          base + 0x68,    14);
-       clks[IMX6UL_CLK_CAN1_SERIAL]    = imx_clk_gate2("can1_serial",  "can_podf",     base + 0x68,    16);
-       clks[IMX6UL_CLK_CAN2_IPG]       = imx_clk_gate2("can2_ipg",     "ipg",          base + 0x68,    18);
-       clks[IMX6UL_CLK_CAN2_SERIAL]    = imx_clk_gate2("can2_serial",  "can_podf",     base + 0x68,    20);
-       clks[IMX6UL_CLK_GPT2_BUS]       = imx_clk_gate2("gpt2_bus",     "perclk",       base + 0x68,    24);
-       clks[IMX6UL_CLK_GPT2_SERIAL]    = imx_clk_gate2("gpt2_serial",  "perclk",       base + 0x68,    26);
-       clks[IMX6UL_CLK_UART2_IPG]      = imx_clk_gate2("uart2_ipg",    "ipg",          base + 0x68,    28);
-       clks[IMX6UL_CLK_UART2_SERIAL]   = imx_clk_gate2("uart2_serial", "uart_podf",    base + 0x68,    28);
+       hws[IMX6UL_CLK_CAN1_IPG]        = imx_clk_hw_gate2("can1_ipg",  "ipg",          base + 0x68,    14);
+       hws[IMX6UL_CLK_CAN1_SERIAL]     = imx_clk_hw_gate2("can1_serial",       "can_podf",     base + 0x68,    16);
+       hws[IMX6UL_CLK_CAN2_IPG]        = imx_clk_hw_gate2("can2_ipg",  "ipg",          base + 0x68,    18);
+       hws[IMX6UL_CLK_CAN2_SERIAL]     = imx_clk_hw_gate2("can2_serial",       "can_podf",     base + 0x68,    20);
+       hws[IMX6UL_CLK_GPT2_BUS]        = imx_clk_hw_gate2("gpt2_bus",  "perclk",       base + 0x68,    24);
+       hws[IMX6UL_CLK_GPT2_SERIAL]     = imx_clk_hw_gate2("gpt2_serial",       "perclk",       base + 0x68,    26);
+       hws[IMX6UL_CLK_UART2_IPG]       = imx_clk_hw_gate2("uart2_ipg", "ipg",          base + 0x68,    28);
+       hws[IMX6UL_CLK_UART2_SERIAL]    = imx_clk_hw_gate2("uart2_serial",      "uart_podf",    base + 0x68,    28);
        if (clk_on_imx6ull())
-               clks[IMX6UL_CLK_AIPSTZ3]        = imx_clk_gate2("aips_tz3",     "ahb",           base + 0x80,   18);
-       clks[IMX6UL_CLK_GPIO2]          = imx_clk_gate2("gpio2",        "ipg",          base + 0x68,    30);
+               hws[IMX6UL_CLK_AIPSTZ3] = imx_clk_hw_gate2("aips_tz3",  "ahb",           base + 0x80,   18);
+       hws[IMX6UL_CLK_GPIO2]           = imx_clk_hw_gate2("gpio2",     "ipg",          base + 0x68,    30);
 
        /* CCGR1 */
-       clks[IMX6UL_CLK_ECSPI1]         = imx_clk_gate2("ecspi1",       "ecspi_podf",   base + 0x6c,    0);
-       clks[IMX6UL_CLK_ECSPI2]         = imx_clk_gate2("ecspi2",       "ecspi_podf",   base + 0x6c,    2);
-       clks[IMX6UL_CLK_ECSPI3]         = imx_clk_gate2("ecspi3",       "ecspi_podf",   base + 0x6c,    4);
-       clks[IMX6UL_CLK_ECSPI4]         = imx_clk_gate2("ecspi4",       "ecspi_podf",   base + 0x6c,    6);
-       clks[IMX6UL_CLK_ADC2]           = imx_clk_gate2("adc2",         "ipg",          base + 0x6c,    8);
-       clks[IMX6UL_CLK_UART3_IPG]      = imx_clk_gate2("uart3_ipg",    "ipg",          base + 0x6c,    10);
-       clks[IMX6UL_CLK_UART3_SERIAL]   = imx_clk_gate2("uart3_serial", "uart_podf",    base + 0x6c,    10);
-       clks[IMX6UL_CLK_EPIT1]          = imx_clk_gate2("epit1",        "perclk",       base + 0x6c,    12);
-       clks[IMX6UL_CLK_EPIT2]          = imx_clk_gate2("epit2",        "perclk",       base + 0x6c,    14);
-       clks[IMX6UL_CLK_ADC1]           = imx_clk_gate2("adc1",         "ipg",          base + 0x6c,    16);
-       clks[IMX6UL_CLK_GPT1_BUS]       = imx_clk_gate2("gpt1_bus",     "perclk",       base + 0x6c,    20);
-       clks[IMX6UL_CLK_GPT1_SERIAL]    = imx_clk_gate2("gpt1_serial",  "perclk",       base + 0x6c,    22);
-       clks[IMX6UL_CLK_UART4_IPG]      = imx_clk_gate2("uart4_ipg",    "ipg",          base + 0x6c,    24);
-       clks[IMX6UL_CLK_UART4_SERIAL]   = imx_clk_gate2("uart4_serial", "uart_podf",    base + 0x6c,    24);
-       clks[IMX6UL_CLK_GPIO1]          = imx_clk_gate2("gpio1",        "ipg",          base + 0x6c,    26);
-       clks[IMX6UL_CLK_GPIO5]          = imx_clk_gate2("gpio5",        "ipg",          base + 0x6c,    30);
+       hws[IMX6UL_CLK_ECSPI1]          = imx_clk_hw_gate2("ecspi1",    "ecspi_podf",   base + 0x6c,    0);
+       hws[IMX6UL_CLK_ECSPI2]          = imx_clk_hw_gate2("ecspi2",    "ecspi_podf",   base + 0x6c,    2);
+       hws[IMX6UL_CLK_ECSPI3]          = imx_clk_hw_gate2("ecspi3",    "ecspi_podf",   base + 0x6c,    4);
+       hws[IMX6UL_CLK_ECSPI4]          = imx_clk_hw_gate2("ecspi4",    "ecspi_podf",   base + 0x6c,    6);
+       hws[IMX6UL_CLK_ADC2]            = imx_clk_hw_gate2("adc2",              "ipg",          base + 0x6c,    8);
+       hws[IMX6UL_CLK_UART3_IPG]       = imx_clk_hw_gate2("uart3_ipg", "ipg",          base + 0x6c,    10);
+       hws[IMX6UL_CLK_UART3_SERIAL]    = imx_clk_hw_gate2("uart3_serial",      "uart_podf",    base + 0x6c,    10);
+       hws[IMX6UL_CLK_EPIT1]           = imx_clk_hw_gate2("epit1",     "perclk",       base + 0x6c,    12);
+       hws[IMX6UL_CLK_EPIT2]           = imx_clk_hw_gate2("epit2",     "perclk",       base + 0x6c,    14);
+       hws[IMX6UL_CLK_ADC1]            = imx_clk_hw_gate2("adc1",              "ipg",          base + 0x6c,    16);
+       hws[IMX6UL_CLK_GPT1_BUS]        = imx_clk_hw_gate2("gpt1_bus",  "perclk",       base + 0x6c,    20);
+       hws[IMX6UL_CLK_GPT1_SERIAL]     = imx_clk_hw_gate2("gpt1_serial",       "perclk",       base + 0x6c,    22);
+       hws[IMX6UL_CLK_UART4_IPG]       = imx_clk_hw_gate2("uart4_ipg", "ipg",          base + 0x6c,    24);
+       hws[IMX6UL_CLK_UART4_SERIAL]    = imx_clk_hw_gate2("uart4_serial",      "uart_podf",    base + 0x6c,    24);
+       hws[IMX6UL_CLK_GPIO1]           = imx_clk_hw_gate2("gpio1",     "ipg",          base + 0x6c,    26);
+       hws[IMX6UL_CLK_GPIO5]           = imx_clk_hw_gate2("gpio5",     "ipg",          base + 0x6c,    30);
 
        /* CCGR2 */
        if (clk_on_imx6ull()) {
-               clks[IMX6ULL_CLK_ESAI_EXTAL]    = imx_clk_gate2_shared("esai_extal",    "esai_podf",    base + 0x70,    0, &share_count_esai);
-               clks[IMX6ULL_CLK_ESAI_IPG]      = imx_clk_gate2_shared("esai_ipg",      "ahb",          base + 0x70,    0, &share_count_esai);
-               clks[IMX6ULL_CLK_ESAI_MEM]      = imx_clk_gate2_shared("esai_mem",      "ahb",          base + 0x70,    0, &share_count_esai);
+               hws[IMX6ULL_CLK_ESAI_EXTAL]     = imx_clk_hw_gate2_shared("esai_extal", "esai_podf",    base + 0x70,    0, &share_count_esai);
+               hws[IMX6ULL_CLK_ESAI_IPG]       = imx_clk_hw_gate2_shared("esai_ipg",   "ahb",          base + 0x70,    0, &share_count_esai);
+               hws[IMX6ULL_CLK_ESAI_MEM]       = imx_clk_hw_gate2_shared("esai_mem",   "ahb",          base + 0x70,    0, &share_count_esai);
        }
-       clks[IMX6UL_CLK_CSI]            = imx_clk_gate2("csi",          "csi_podf",             base + 0x70,    2);
-       clks[IMX6UL_CLK_I2C1]           = imx_clk_gate2("i2c1",         "perclk",       base + 0x70,    6);
-       clks[IMX6UL_CLK_I2C2]           = imx_clk_gate2("i2c2",         "perclk",       base + 0x70,    8);
-       clks[IMX6UL_CLK_I2C3]           = imx_clk_gate2("i2c3",         "perclk",       base + 0x70,    10);
-       clks[IMX6UL_CLK_OCOTP]          = imx_clk_gate2("ocotp",        "ipg",          base + 0x70,    12);
-       clks[IMX6UL_CLK_IOMUXC]         = imx_clk_gate2("iomuxc",       "lcdif_podf",   base + 0x70,    14);
-       clks[IMX6UL_CLK_GPIO3]          = imx_clk_gate2("gpio3",        "ipg",          base + 0x70,    26);
-       clks[IMX6UL_CLK_LCDIF_APB]      = imx_clk_gate2("lcdif_apb",    "axi",          base + 0x70,    28);
-       clks[IMX6UL_CLK_PXP]            = imx_clk_gate2("pxp",          "axi",          base + 0x70,    30);
+       hws[IMX6UL_CLK_CSI]             = imx_clk_hw_gate2("csi",               "csi_podf",             base + 0x70,    2);
+       hws[IMX6UL_CLK_I2C1]            = imx_clk_hw_gate2("i2c1",              "perclk",       base + 0x70,    6);
+       hws[IMX6UL_CLK_I2C2]            = imx_clk_hw_gate2("i2c2",              "perclk",       base + 0x70,    8);
+       hws[IMX6UL_CLK_I2C3]            = imx_clk_hw_gate2("i2c3",              "perclk",       base + 0x70,    10);
+       hws[IMX6UL_CLK_OCOTP]           = imx_clk_hw_gate2("ocotp",     "ipg",          base + 0x70,    12);
+       hws[IMX6UL_CLK_IOMUXC]          = imx_clk_hw_gate2("iomuxc",    "lcdif_podf",   base + 0x70,    14);
+       hws[IMX6UL_CLK_GPIO3]           = imx_clk_hw_gate2("gpio3",     "ipg",          base + 0x70,    26);
+       hws[IMX6UL_CLK_LCDIF_APB]       = imx_clk_hw_gate2("lcdif_apb", "axi",          base + 0x70,    28);
+       hws[IMX6UL_CLK_PXP]             = imx_clk_hw_gate2("pxp",               "axi",          base + 0x70,    30);
 
        /* CCGR3 */
-       clks[IMX6UL_CLK_UART5_IPG]      = imx_clk_gate2("uart5_ipg",    "ipg",          base + 0x74,    2);
-       clks[IMX6UL_CLK_UART5_SERIAL]   = imx_clk_gate2("uart5_serial", "uart_podf",    base + 0x74,    2);
+       hws[IMX6UL_CLK_UART5_IPG]       = imx_clk_hw_gate2("uart5_ipg", "ipg",          base + 0x74,    2);
+       hws[IMX6UL_CLK_UART5_SERIAL]    = imx_clk_hw_gate2("uart5_serial",      "uart_podf",    base + 0x74,    2);
        if (clk_on_imx6ul()) {
-               clks[IMX6UL_CLK_ENET]           = imx_clk_gate2("enet",         "ipg",          base + 0x74,    4);
-               clks[IMX6UL_CLK_ENET_AHB]       = imx_clk_gate2("enet_ahb",     "ahb",          base + 0x74,    4);
+               hws[IMX6UL_CLK_ENET]            = imx_clk_hw_gate2("enet",              "ipg",          base + 0x74,    4);
+               hws[IMX6UL_CLK_ENET_AHB]        = imx_clk_hw_gate2("enet_ahb",  "ahb",          base + 0x74,    4);
        } else if (clk_on_imx6ull()) {
-               clks[IMX6ULL_CLK_EPDC_ACLK]     = imx_clk_gate2("epdc_aclk",    "axi",          base + 0x74,    4);
-               clks[IMX6ULL_CLK_EPDC_PIX]      = imx_clk_gate2("epdc_pix",     "epdc_podf",    base + 0x74,    4);
+               hws[IMX6ULL_CLK_EPDC_ACLK]      = imx_clk_hw_gate2("epdc_aclk", "axi",          base + 0x74,    4);
+               hws[IMX6ULL_CLK_EPDC_PIX]       = imx_clk_hw_gate2("epdc_pix",  "epdc_podf",    base + 0x74,    4);
        }
-       clks[IMX6UL_CLK_UART6_IPG]      = imx_clk_gate2("uart6_ipg",    "ipg",          base + 0x74,    6);
-       clks[IMX6UL_CLK_UART6_SERIAL]   = imx_clk_gate2("uart6_serial", "uart_podf",    base + 0x74,    6);
-       clks[IMX6UL_CLK_LCDIF_PIX]      = imx_clk_gate2("lcdif_pix",    "lcdif_podf",   base + 0x74,    10);
-       clks[IMX6UL_CLK_GPIO4]          = imx_clk_gate2("gpio4",        "ipg",          base + 0x74,    12);
-       clks[IMX6UL_CLK_QSPI]           = imx_clk_gate2("qspi1",        "qspi1_podf",   base + 0x74,    14);
-       clks[IMX6UL_CLK_WDOG1]          = imx_clk_gate2("wdog1",        "ipg",          base + 0x74,    16);
-       clks[IMX6UL_CLK_MMDC_P0_FAST]   = imx_clk_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74,  20, CLK_IS_CRITICAL);
-       clks[IMX6UL_CLK_MMDC_P0_IPG]    = imx_clk_gate2_flags("mmdc_p0_ipg",    "ipg",          base + 0x74,    24, CLK_IS_CRITICAL);
-       clks[IMX6UL_CLK_MMDC_P1_IPG]    = imx_clk_gate2("mmdc_p1_ipg",  "ipg",          base + 0x74,    26);
-       clks[IMX6UL_CLK_AXI]            = imx_clk_gate_flags("axi",     "axi_podf",     base + 0x74,    28, CLK_IS_CRITICAL);
+       hws[IMX6UL_CLK_UART6_IPG]       = imx_clk_hw_gate2("uart6_ipg", "ipg",          base + 0x74,    6);
+       hws[IMX6UL_CLK_UART6_SERIAL]    = imx_clk_hw_gate2("uart6_serial",      "uart_podf",    base + 0x74,    6);
+       hws[IMX6UL_CLK_LCDIF_PIX]       = imx_clk_hw_gate2("lcdif_pix", "lcdif_podf",   base + 0x74,    10);
+       hws[IMX6UL_CLK_GPIO4]           = imx_clk_hw_gate2("gpio4",     "ipg",          base + 0x74,    12);
+       hws[IMX6UL_CLK_QSPI]            = imx_clk_hw_gate2("qspi1",     "qspi1_podf",   base + 0x74,    14);
+       hws[IMX6UL_CLK_WDOG1]           = imx_clk_hw_gate2("wdog1",     "ipg",          base + 0x74,    16);
+       hws[IMX6UL_CLK_MMDC_P0_FAST]    = imx_clk_hw_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74,       20, CLK_IS_CRITICAL);
+       hws[IMX6UL_CLK_MMDC_P0_IPG]     = imx_clk_hw_gate2_flags("mmdc_p0_ipg", "ipg",          base + 0x74,    24, CLK_IS_CRITICAL);
+       hws[IMX6UL_CLK_MMDC_P1_IPG]     = imx_clk_hw_gate2_flags("mmdc_p1_ipg", "ipg",          base + 0x74,    26, CLK_IS_CRITICAL);
+       hws[IMX6UL_CLK_AXI]             = imx_clk_hw_gate_flags("axi",  "axi_podf",     base + 0x74,    28, CLK_IS_CRITICAL);
 
        /* CCGR4 */
-       clks[IMX6UL_CLK_PER_BCH]        = imx_clk_gate2("per_bch",      "bch_podf",     base + 0x78,    12);
-       clks[IMX6UL_CLK_PWM1]           = imx_clk_gate2("pwm1",         "perclk",       base + 0x78,    16);
-       clks[IMX6UL_CLK_PWM2]           = imx_clk_gate2("pwm2",         "perclk",       base + 0x78,    18);
-       clks[IMX6UL_CLK_PWM3]           = imx_clk_gate2("pwm3",         "perclk",       base + 0x78,    20);
-       clks[IMX6UL_CLK_PWM4]           = imx_clk_gate2("pwm4",         "perclk",       base + 0x78,    22);
-       clks[IMX6UL_CLK_GPMI_BCH_APB]   = imx_clk_gate2("gpmi_bch_apb", "bch_podf",     base + 0x78,    24);
-       clks[IMX6UL_CLK_GPMI_BCH]       = imx_clk_gate2("gpmi_bch",     "gpmi_podf",    base + 0x78,    26);
-       clks[IMX6UL_CLK_GPMI_IO]        = imx_clk_gate2("gpmi_io",      "enfc_podf",    base + 0x78,    28);
-       clks[IMX6UL_CLK_GPMI_APB]       = imx_clk_gate2("gpmi_apb",     "bch_podf",     base + 0x78,    30);
+       hws[IMX6UL_CLK_PER_BCH] = imx_clk_hw_gate2("per_bch",   "bch_podf",     base + 0x78,    12);
+       hws[IMX6UL_CLK_PWM1]            = imx_clk_hw_gate2("pwm1",              "perclk",       base + 0x78,    16);
+       hws[IMX6UL_CLK_PWM2]            = imx_clk_hw_gate2("pwm2",              "perclk",       base + 0x78,    18);
+       hws[IMX6UL_CLK_PWM3]            = imx_clk_hw_gate2("pwm3",              "perclk",       base + 0x78,    20);
+       hws[IMX6UL_CLK_PWM4]            = imx_clk_hw_gate2("pwm4",              "perclk",       base + 0x78,    22);
+       hws[IMX6UL_CLK_GPMI_BCH_APB]    = imx_clk_hw_gate2("gpmi_bch_apb",      "bch_podf",     base + 0x78,    24);
+       hws[IMX6UL_CLK_GPMI_BCH]        = imx_clk_hw_gate2("gpmi_bch",  "gpmi_podf",    base + 0x78,    26);
+       hws[IMX6UL_CLK_GPMI_IO] = imx_clk_hw_gate2("gpmi_io",   "enfc_podf",    base + 0x78,    28);
+       hws[IMX6UL_CLK_GPMI_APB]        = imx_clk_hw_gate2("gpmi_apb",  "bch_podf",     base + 0x78,    30);
 
        /* CCGR5 */
-       clks[IMX6UL_CLK_ROM]            = imx_clk_gate2_flags("rom",    "ahb",          base + 0x7c,    0,      CLK_IS_CRITICAL);
-       clks[IMX6UL_CLK_SDMA]           = imx_clk_gate2("sdma",         "ahb",          base + 0x7c,    6);
-       clks[IMX6UL_CLK_KPP]            = imx_clk_gate2("kpp",          "ipg",          base + 0x7c,    8);
-       clks[IMX6UL_CLK_WDOG2]          = imx_clk_gate2("wdog2",        "ipg",          base + 0x7c,    10);
-       clks[IMX6UL_CLK_SPBA]           = imx_clk_gate2("spba",         "ipg",          base + 0x7c,    12);
-       clks[IMX6UL_CLK_SPDIF]          = imx_clk_gate2_shared("spdif",         "spdif_podf",   base + 0x7c,    14, &share_count_audio);
-       clks[IMX6UL_CLK_SPDIF_GCLK]     = imx_clk_gate2_shared("spdif_gclk",    "ipg",          base + 0x7c,    14, &share_count_audio);
-       clks[IMX6UL_CLK_SAI3]           = imx_clk_gate2_shared("sai3",          "sai3_podf",    base + 0x7c,    22, &share_count_sai3);
-       clks[IMX6UL_CLK_SAI3_IPG]       = imx_clk_gate2_shared("sai3_ipg",      "ipg",          base + 0x7c,    22, &share_count_sai3);
-       clks[IMX6UL_CLK_UART1_IPG]      = imx_clk_gate2("uart1_ipg",    "ipg",          base + 0x7c,    24);
-       clks[IMX6UL_CLK_UART1_SERIAL]   = imx_clk_gate2("uart1_serial", "uart_podf",    base + 0x7c,    24);
-       clks[IMX6UL_CLK_UART7_IPG]      = imx_clk_gate2("uart7_ipg",    "ipg",          base + 0x7c,    26);
-       clks[IMX6UL_CLK_UART7_SERIAL]   = imx_clk_gate2("uart7_serial", "uart_podf",    base + 0x7c,    26);
-       clks[IMX6UL_CLK_SAI1]           = imx_clk_gate2_shared("sai1",          "sai1_podf",    base + 0x7c,    28, &share_count_sai1);
-       clks[IMX6UL_CLK_SAI1_IPG]       = imx_clk_gate2_shared("sai1_ipg",      "ipg",          base + 0x7c,    28, &share_count_sai1);
-       clks[IMX6UL_CLK_SAI2]           = imx_clk_gate2_shared("sai2",          "sai2_podf",    base + 0x7c,    30, &share_count_sai2);
-       clks[IMX6UL_CLK_SAI2_IPG]       = imx_clk_gate2_shared("sai2_ipg",      "ipg",          base + 0x7c,    30, &share_count_sai2);
+       hws[IMX6UL_CLK_ROM]             = imx_clk_hw_gate2_flags("rom", "ahb",          base + 0x7c,    0,      CLK_IS_CRITICAL);
+       hws[IMX6UL_CLK_SDMA]            = imx_clk_hw_gate2("sdma",              "ahb",          base + 0x7c,    6);
+       hws[IMX6UL_CLK_KPP]             = imx_clk_hw_gate2("kpp",               "ipg",          base + 0x7c,    8);
+       hws[IMX6UL_CLK_WDOG2]           = imx_clk_hw_gate2("wdog2",     "ipg",          base + 0x7c,    10);
+       hws[IMX6UL_CLK_SPBA]            = imx_clk_hw_gate2("spba",              "ipg",          base + 0x7c,    12);
+       hws[IMX6UL_CLK_SPDIF]           = imx_clk_hw_gate2_shared("spdif",              "spdif_podf",   base + 0x7c,    14, &share_count_audio);
+       hws[IMX6UL_CLK_SPDIF_GCLK]      = imx_clk_hw_gate2_shared("spdif_gclk", "ipg",          base + 0x7c,    14, &share_count_audio);
+       hws[IMX6UL_CLK_SAI3]            = imx_clk_hw_gate2_shared("sai3",               "sai3_podf",    base + 0x7c,    22, &share_count_sai3);
+       hws[IMX6UL_CLK_SAI3_IPG]        = imx_clk_hw_gate2_shared("sai3_ipg",   "ipg",          base + 0x7c,    22, &share_count_sai3);
+       hws[IMX6UL_CLK_UART1_IPG]       = imx_clk_hw_gate2("uart1_ipg", "ipg",          base + 0x7c,    24);
+       hws[IMX6UL_CLK_UART1_SERIAL]    = imx_clk_hw_gate2("uart1_serial",      "uart_podf",    base + 0x7c,    24);
+       hws[IMX6UL_CLK_UART7_IPG]       = imx_clk_hw_gate2("uart7_ipg", "ipg",          base + 0x7c,    26);
+       hws[IMX6UL_CLK_UART7_SERIAL]    = imx_clk_hw_gate2("uart7_serial",      "uart_podf",    base + 0x7c,    26);
+       hws[IMX6UL_CLK_SAI1]            = imx_clk_hw_gate2_shared("sai1",               "sai1_podf",    base + 0x7c,    28, &share_count_sai1);
+       hws[IMX6UL_CLK_SAI1_IPG]        = imx_clk_hw_gate2_shared("sai1_ipg",   "ipg",          base + 0x7c,    28, &share_count_sai1);
+       hws[IMX6UL_CLK_SAI2]            = imx_clk_hw_gate2_shared("sai2",               "sai2_podf",    base + 0x7c,    30, &share_count_sai2);
+       hws[IMX6UL_CLK_SAI2_IPG]        = imx_clk_hw_gate2_shared("sai2_ipg",   "ipg",          base + 0x7c,    30, &share_count_sai2);
 
        /* CCGR6 */
-       clks[IMX6UL_CLK_USBOH3]         = imx_clk_gate2("usboh3",       "ipg",           base + 0x80,   0);
-       clks[IMX6UL_CLK_USDHC1]         = imx_clk_gate2("usdhc1",       "usdhc1_podf",   base + 0x80,   2);
-       clks[IMX6UL_CLK_USDHC2]         = imx_clk_gate2("usdhc2",       "usdhc2_podf",   base + 0x80,   4);
+       hws[IMX6UL_CLK_USBOH3]          = imx_clk_hw_gate2("usboh3",    "ipg",           base + 0x80,   0);
+       hws[IMX6UL_CLK_USDHC1]          = imx_clk_hw_gate2("usdhc1",    "usdhc1_podf",   base + 0x80,   2);
+       hws[IMX6UL_CLK_USDHC2]          = imx_clk_hw_gate2("usdhc2",    "usdhc2_podf",   base + 0x80,   4);
        if (clk_on_imx6ul()) {
-               clks[IMX6UL_CLK_SIM1]           = imx_clk_gate2("sim1",         "sim_sel",       base + 0x80,   6);
-               clks[IMX6UL_CLK_SIM2]           = imx_clk_gate2("sim2",         "sim_sel",       base + 0x80,   8);
+               hws[IMX6UL_CLK_SIM1]            = imx_clk_hw_gate2("sim1",              "sim_sel",       base + 0x80,   6);
+               hws[IMX6UL_CLK_SIM2]            = imx_clk_hw_gate2("sim2",              "sim_sel",       base + 0x80,   8);
        }
-       clks[IMX6UL_CLK_EIM]            = imx_clk_gate2("eim",          "eim_slow_podf", base + 0x80,   10);
-       clks[IMX6UL_CLK_PWM8]           = imx_clk_gate2("pwm8",         "perclk",        base + 0x80,   16);
-       clks[IMX6UL_CLK_UART8_IPG]      = imx_clk_gate2("uart8_ipg",    "ipg",           base + 0x80,   14);
-       clks[IMX6UL_CLK_UART8_SERIAL]   = imx_clk_gate2("uart8_serial", "uart_podf",     base + 0x80,   14);
-       clks[IMX6UL_CLK_WDOG3]          = imx_clk_gate2("wdog3",        "ipg",           base + 0x80,   20);
-       clks[IMX6UL_CLK_I2C4]           = imx_clk_gate2("i2c4",         "perclk",        base + 0x80,   24);
-       clks[IMX6UL_CLK_PWM5]           = imx_clk_gate2("pwm5",         "perclk",        base + 0x80,   26);
-       clks[IMX6UL_CLK_PWM6]           = imx_clk_gate2("pwm6",         "perclk",        base + 0x80,   28);
-       clks[IMX6UL_CLK_PWM7]           = imx_clk_gate2("pwm7",         "perclk",        base + 0x80,   30);
+       hws[IMX6UL_CLK_EIM]             = imx_clk_hw_gate2("eim",               "eim_slow_podf", base + 0x80,   10);
+       hws[IMX6UL_CLK_PWM8]            = imx_clk_hw_gate2("pwm8",              "perclk",        base + 0x80,   16);
+       hws[IMX6UL_CLK_UART8_IPG]       = imx_clk_hw_gate2("uart8_ipg", "ipg",           base + 0x80,   14);
+       hws[IMX6UL_CLK_UART8_SERIAL]    = imx_clk_hw_gate2("uart8_serial", "uart_podf",  base + 0x80,   14);
+       hws[IMX6UL_CLK_WDOG3]           = imx_clk_hw_gate2("wdog3",     "ipg",           base + 0x80,   20);
+       hws[IMX6UL_CLK_I2C4]            = imx_clk_hw_gate2("i2c4",              "perclk",        base + 0x80,   24);
+       hws[IMX6UL_CLK_PWM5]            = imx_clk_hw_gate2("pwm5",              "perclk",        base + 0x80,   26);
+       hws[IMX6UL_CLK_PWM6]            = imx_clk_hw_gate2("pwm6",              "perclk",        base + 0x80,   28);
+       hws[IMX6UL_CLK_PWM7]            = imx_clk_hw_gate2("pwm7",              "perclk",        base + 0x80,   30);
 
        /* CCOSR */
-       clks[IMX6UL_CLK_CKO1]           = imx_clk_gate("cko1",          "cko1_podf",     base + 0x60,   7);
-       clks[IMX6UL_CLK_CKO2]           = imx_clk_gate("cko2",          "cko2_podf",     base + 0x60,   24);
+       hws[IMX6UL_CLK_CKO1]            = imx_clk_hw_gate("cko1",               "cko1_podf",     base + 0x60,   7);
+       hws[IMX6UL_CLK_CKO2]            = imx_clk_hw_gate("cko2",               "cko2_podf",     base + 0x60,   24);
 
        /* mask handshake of mmdc */
-       writel_relaxed(BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR);
+       imx_mmdc_mask_handshake(base, 0);
 
-       imx_check_clocks(clks, ARRAY_SIZE(clks));
+       imx_check_clk_hws(hws, IMX6UL_CLK_END);
 
-       clk_data.clks = clks;
-       clk_data.clk_num = ARRAY_SIZE(clks);
-       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+       of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
 
        /*
         * Lower the AHB clock rate before changing the parent clock source,
@@ -473,39 +477,39 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
         * AXI clock rate, so we need to lower AHB rate first to make sure at
         * any time, AHB rate is <= 133MHz.
         */
-       clk_set_rate(clks[IMX6UL_CLK_AHB], 99000000);
+       clk_set_rate(hws[IMX6UL_CLK_AHB]->clk, 99000000);
 
        /* Change periph_pre clock to pll2_bus to adjust AXI rate to 264MHz */
-       clk_set_parent(clks[IMX6UL_CLK_PERIPH_CLK2_SEL], clks[IMX6UL_CLK_OSC]);
-       clk_set_parent(clks[IMX6UL_CLK_PERIPH], clks[IMX6UL_CLK_PERIPH_CLK2]);
-       clk_set_parent(clks[IMX6UL_CLK_PERIPH_PRE], clks[IMX6UL_CLK_PLL2_BUS]);
-       clk_set_parent(clks[IMX6UL_CLK_PERIPH], clks[IMX6UL_CLK_PERIPH_PRE]);
+       clk_set_parent(hws[IMX6UL_CLK_PERIPH_CLK2_SEL]->clk, hws[IMX6UL_CLK_OSC]->clk);
+       clk_set_parent(hws[IMX6UL_CLK_PERIPH]->clk, hws[IMX6UL_CLK_PERIPH_CLK2]->clk);
+       clk_set_parent(hws[IMX6UL_CLK_PERIPH_PRE]->clk, hws[IMX6UL_CLK_PLL2_BUS]->clk);
+       clk_set_parent(hws[IMX6UL_CLK_PERIPH]->clk, hws[IMX6UL_CLK_PERIPH_PRE]->clk);
 
        /* Make sure AHB rate is 132MHz  */
-       clk_set_rate(clks[IMX6UL_CLK_AHB], 132000000);
+       clk_set_rate(hws[IMX6UL_CLK_AHB]->clk, 132000000);
 
        /* set perclk to from OSC */
-       clk_set_parent(clks[IMX6UL_CLK_PERCLK_SEL], clks[IMX6UL_CLK_OSC]);
+       clk_set_parent(hws[IMX6UL_CLK_PERCLK_SEL]->clk, hws[IMX6UL_CLK_OSC]->clk);
 
-       clk_set_rate(clks[IMX6UL_CLK_ENET_REF], 50000000);
-       clk_set_rate(clks[IMX6UL_CLK_ENET2_REF], 50000000);
-       clk_set_rate(clks[IMX6UL_CLK_CSI], 24000000);
+       clk_set_rate(hws[IMX6UL_CLK_ENET_REF]->clk, 50000000);
+       clk_set_rate(hws[IMX6UL_CLK_ENET2_REF]->clk, 50000000);
+       clk_set_rate(hws[IMX6UL_CLK_CSI]->clk, 24000000);
 
        if (clk_on_imx6ull())
-               clk_prepare_enable(clks[IMX6UL_CLK_AIPSTZ3]);
+               clk_prepare_enable(hws[IMX6UL_CLK_AIPSTZ3]->clk);
 
        if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
-               clk_prepare_enable(clks[IMX6UL_CLK_USBPHY1_GATE]);
-               clk_prepare_enable(clks[IMX6UL_CLK_USBPHY2_GATE]);
+               clk_prepare_enable(hws[IMX6UL_CLK_USBPHY1_GATE]->clk);
+               clk_prepare_enable(hws[IMX6UL_CLK_USBPHY2_GATE]->clk);
        }
 
-       clk_set_parent(clks[IMX6UL_CLK_CAN_SEL], clks[IMX6UL_CLK_PLL3_60M]);
+       clk_set_parent(hws[IMX6UL_CLK_CAN_SEL]->clk, hws[IMX6UL_CLK_PLL3_60M]->clk);
        if (clk_on_imx6ul())
-               clk_set_parent(clks[IMX6UL_CLK_SIM_PRE_SEL], clks[IMX6UL_CLK_PLL3_USB_OTG]);
+               clk_set_parent(hws[IMX6UL_CLK_SIM_PRE_SEL]->clk, hws[IMX6UL_CLK_PLL3_USB_OTG]->clk);
        else if (clk_on_imx6ull())
-               clk_set_parent(clks[IMX6ULL_CLK_EPDC_PRE_SEL], clks[IMX6UL_CLK_PLL3_PFD2]);
+               clk_set_parent(hws[IMX6ULL_CLK_EPDC_PRE_SEL]->clk, hws[IMX6UL_CLK_PLL3_PFD2]->clk);
 
-       clk_set_parent(clks[IMX6UL_CLK_ENFC_SEL], clks[IMX6UL_CLK_PLL2_PFD2]);
+       clk_set_parent(hws[IMX6UL_CLK_ENFC_SEL]->clk, hws[IMX6UL_CLK_PLL2_PFD2]->clk);
 }
 
 CLK_OF_DECLARE(imx6ul, "fsl,imx6ul-ccm", imx6ul_clocks_init);
index 8f3aa99..fbea774 100644 (file)
@@ -6,6 +6,7 @@
 #include <dt-bindings/clock/imx7d-clock.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
+#include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
@@ -39,7 +40,6 @@ static const struct clk_div_table post_div_table[] = {
        { }
 };
 
-static struct clk *clks[IMX7D_CLK_END];
 static const char *arm_a7_sel[] = { "osc", "pll_arm_main_clk",
        "pll_enet_500m_clk", "pll_dram_main_clk",
        "pll_sys_main_clk", "pll_sys_pfd0_392m_clk", "pll_audio_post_div",
@@ -373,517 +373,533 @@ static const char *pll_enet_bypass_sel[] = { "pll_enet_main", "pll_enet_main_src
 static const char *pll_audio_bypass_sel[] = { "pll_audio_main", "pll_audio_main_src", };
 static const char *pll_video_bypass_sel[] = { "pll_video_main", "pll_video_main_src", };
 
-static struct clk_onecell_data clk_data;
-
-static struct clk ** const uart_clks[] __initconst = {
-       &clks[IMX7D_UART1_ROOT_CLK],
-       &clks[IMX7D_UART2_ROOT_CLK],
-       &clks[IMX7D_UART3_ROOT_CLK],
-       &clks[IMX7D_UART4_ROOT_CLK],
-       &clks[IMX7D_UART5_ROOT_CLK],
-       &clks[IMX7D_UART6_ROOT_CLK],
-       &clks[IMX7D_UART7_ROOT_CLK],
-       NULL
+static struct clk_hw **hws;
+static struct clk_hw_onecell_data *clk_hw_data;
+
+static const int uart_clk_ids[] __initconst = {
+       IMX7D_UART1_ROOT_CLK,
+       IMX7D_UART2_ROOT_CLK,
+       IMX7D_UART3_ROOT_CLK,
+       IMX7D_UART4_ROOT_CLK,
+       IMX7D_UART5_ROOT_CLK,
+       IMX7D_UART6_ROOT_CLK,
+       IMX7D_UART7_ROOT_CLK,
 };
 
+static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata;
+
 static void __init imx7d_clocks_init(struct device_node *ccm_node)
 {
        struct device_node *np;
        void __iomem *base;
+       int i;
+
+       clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
+                                         IMX7D_CLK_END), GFP_KERNEL);
+       if (WARN_ON(!clk_hw_data))
+               return;
+
+       clk_hw_data->num = IMX7D_CLK_END;
+       hws = clk_hw_data->hws;
 
-       clks[IMX7D_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
-       clks[IMX7D_OSC_24M_CLK] = of_clk_get_by_name(ccm_node, "osc");
-       clks[IMX7D_CKIL] = of_clk_get_by_name(ccm_node, "ckil");
+       hws[IMX7D_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
+       hws[IMX7D_OSC_24M_CLK] = __clk_get_hw(of_clk_get_by_name(ccm_node, "osc"));
+       hws[IMX7D_CKIL] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ckil"));
 
        np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-anatop");
        base = of_iomap(np, 0);
        WARN_ON(!base);
        of_node_put(np);
 
-       clks[IMX7D_PLL_ARM_MAIN_SRC]  = imx_clk_mux("pll_arm_main_src", base + 0x60, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
-       clks[IMX7D_PLL_DRAM_MAIN_SRC] = imx_clk_mux("pll_dram_main_src", base + 0x70, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
-       clks[IMX7D_PLL_SYS_MAIN_SRC]  = imx_clk_mux("pll_sys_main_src", base + 0xb0, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
-       clks[IMX7D_PLL_ENET_MAIN_SRC] = imx_clk_mux("pll_enet_main_src", base + 0xe0, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
-       clks[IMX7D_PLL_AUDIO_MAIN_SRC] = imx_clk_mux("pll_audio_main_src", base + 0xf0, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
-       clks[IMX7D_PLL_VIDEO_MAIN_SRC] = imx_clk_mux("pll_video_main_src", base + 0x130, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
-
-       clks[IMX7D_PLL_ARM_MAIN]  = imx_clk_pllv3(IMX_PLLV3_SYS, "pll_arm_main", "osc", base + 0x60, 0x7f);
-       clks[IMX7D_PLL_DRAM_MAIN] = imx_clk_pllv3(IMX_PLLV3_DDR_IMX7, "pll_dram_main", "osc", base + 0x70, 0x7f);
-       clks[IMX7D_PLL_SYS_MAIN]  = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll_sys_main", "osc", base + 0xb0, 0x1);
-       clks[IMX7D_PLL_ENET_MAIN] = imx_clk_pllv3(IMX_PLLV3_ENET_IMX7, "pll_enet_main", "osc", base + 0xe0, 0x0);
-       clks[IMX7D_PLL_AUDIO_MAIN] = imx_clk_pllv3(IMX_PLLV3_AV_IMX7, "pll_audio_main", "osc", base + 0xf0, 0x7f);
-       clks[IMX7D_PLL_VIDEO_MAIN] = imx_clk_pllv3(IMX_PLLV3_AV_IMX7, "pll_video_main", "osc", base + 0x130, 0x7f);
-
-       clks[IMX7D_PLL_ARM_MAIN_BYPASS]  = imx_clk_mux_flags("pll_arm_main_bypass", base + 0x60, 16, 1, pll_arm_bypass_sel, ARRAY_SIZE(pll_arm_bypass_sel), CLK_SET_RATE_PARENT);
-       clks[IMX7D_PLL_DRAM_MAIN_BYPASS] = imx_clk_mux_flags("pll_dram_main_bypass", base + 0x70, 16, 1, pll_dram_bypass_sel, ARRAY_SIZE(pll_dram_bypass_sel), CLK_SET_RATE_PARENT);
-       clks[IMX7D_PLL_SYS_MAIN_BYPASS]  = imx_clk_mux_flags("pll_sys_main_bypass", base + 0xb0, 16, 1, pll_sys_bypass_sel, ARRAY_SIZE(pll_sys_bypass_sel), CLK_SET_RATE_PARENT);
-       clks[IMX7D_PLL_ENET_MAIN_BYPASS] = imx_clk_mux_flags("pll_enet_main_bypass", base + 0xe0, 16, 1, pll_enet_bypass_sel, ARRAY_SIZE(pll_enet_bypass_sel), CLK_SET_RATE_PARENT);
-       clks[IMX7D_PLL_AUDIO_MAIN_BYPASS] = imx_clk_mux_flags("pll_audio_main_bypass", base + 0xf0, 16, 1, pll_audio_bypass_sel, ARRAY_SIZE(pll_audio_bypass_sel), CLK_SET_RATE_PARENT);
-       clks[IMX7D_PLL_VIDEO_MAIN_BYPASS] = imx_clk_mux_flags("pll_video_main_bypass", base + 0x130, 16, 1, pll_video_bypass_sel, ARRAY_SIZE(pll_video_bypass_sel), CLK_SET_RATE_PARENT);
-
-       clks[IMX7D_PLL_ARM_MAIN_CLK] = imx_clk_gate("pll_arm_main_clk", "pll_arm_main_bypass", base + 0x60, 13);
-       clks[IMX7D_PLL_DRAM_MAIN_CLK] = imx_clk_gate("pll_dram_main_clk", "pll_dram_test_div", base + 0x70, 13);
-       clks[IMX7D_PLL_SYS_MAIN_CLK] = imx_clk_gate("pll_sys_main_clk", "pll_sys_main_bypass", base + 0xb0, 13);
-       clks[IMX7D_PLL_AUDIO_MAIN_CLK] = imx_clk_gate("pll_audio_main_clk", "pll_audio_main_bypass", base + 0xf0, 13);
-       clks[IMX7D_PLL_VIDEO_MAIN_CLK] = imx_clk_gate("pll_video_main_clk", "pll_video_main_bypass", base + 0x130, 13);
-
-       clks[IMX7D_PLL_DRAM_TEST_DIV]  = clk_register_divider_table(NULL, "pll_dram_test_div", "pll_dram_main_bypass",
+       hws[IMX7D_PLL_ARM_MAIN_SRC]  = imx_clk_hw_mux("pll_arm_main_src", base + 0x60, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+       hws[IMX7D_PLL_DRAM_MAIN_SRC] = imx_clk_hw_mux("pll_dram_main_src", base + 0x70, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+       hws[IMX7D_PLL_SYS_MAIN_SRC]  = imx_clk_hw_mux("pll_sys_main_src", base + 0xb0, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+       hws[IMX7D_PLL_ENET_MAIN_SRC] = imx_clk_hw_mux("pll_enet_main_src", base + 0xe0, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+       hws[IMX7D_PLL_AUDIO_MAIN_SRC] = imx_clk_hw_mux("pll_audio_main_src", base + 0xf0, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+       hws[IMX7D_PLL_VIDEO_MAIN_SRC] = imx_clk_hw_mux("pll_video_main_src", base + 0x130, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+
+       hws[IMX7D_PLL_ARM_MAIN]  = imx_clk_hw_pllv3(IMX_PLLV3_SYS, "pll_arm_main", "osc", base + 0x60, 0x7f);
+       hws[IMX7D_PLL_DRAM_MAIN] = imx_clk_hw_pllv3(IMX_PLLV3_DDR_IMX7, "pll_dram_main", "osc", base + 0x70, 0x7f);
+       hws[IMX7D_PLL_SYS_MAIN]  = imx_clk_hw_pllv3(IMX_PLLV3_GENERIC, "pll_sys_main", "osc", base + 0xb0, 0x1);
+       hws[IMX7D_PLL_ENET_MAIN] = imx_clk_hw_pllv3(IMX_PLLV3_ENET_IMX7, "pll_enet_main", "osc", base + 0xe0, 0x0);
+       hws[IMX7D_PLL_AUDIO_MAIN] = imx_clk_hw_pllv3(IMX_PLLV3_AV_IMX7, "pll_audio_main", "osc", base + 0xf0, 0x7f);
+       hws[IMX7D_PLL_VIDEO_MAIN] = imx_clk_hw_pllv3(IMX_PLLV3_AV_IMX7, "pll_video_main", "osc", base + 0x130, 0x7f);
+
+       hws[IMX7D_PLL_ARM_MAIN_BYPASS]  = imx_clk_hw_mux_flags("pll_arm_main_bypass", base + 0x60, 16, 1, pll_arm_bypass_sel, ARRAY_SIZE(pll_arm_bypass_sel), CLK_SET_RATE_PARENT);
+       hws[IMX7D_PLL_DRAM_MAIN_BYPASS] = imx_clk_hw_mux_flags("pll_dram_main_bypass", base + 0x70, 16, 1, pll_dram_bypass_sel, ARRAY_SIZE(pll_dram_bypass_sel), CLK_SET_RATE_PARENT);
+       hws[IMX7D_PLL_SYS_MAIN_BYPASS]  = imx_clk_hw_mux_flags("pll_sys_main_bypass", base + 0xb0, 16, 1, pll_sys_bypass_sel, ARRAY_SIZE(pll_sys_bypass_sel), CLK_SET_RATE_PARENT);
+       hws[IMX7D_PLL_ENET_MAIN_BYPASS] = imx_clk_hw_mux_flags("pll_enet_main_bypass", base + 0xe0, 16, 1, pll_enet_bypass_sel, ARRAY_SIZE(pll_enet_bypass_sel), CLK_SET_RATE_PARENT);
+       hws[IMX7D_PLL_AUDIO_MAIN_BYPASS] = imx_clk_hw_mux_flags("pll_audio_main_bypass", base + 0xf0, 16, 1, pll_audio_bypass_sel, ARRAY_SIZE(pll_audio_bypass_sel), CLK_SET_RATE_PARENT);
+       hws[IMX7D_PLL_VIDEO_MAIN_BYPASS] = imx_clk_hw_mux_flags("pll_video_main_bypass", base + 0x130, 16, 1, pll_video_bypass_sel, ARRAY_SIZE(pll_video_bypass_sel), CLK_SET_RATE_PARENT);
+
+       hws[IMX7D_PLL_ARM_MAIN_CLK] = imx_clk_hw_gate("pll_arm_main_clk", "pll_arm_main_bypass", base + 0x60, 13);
+       hws[IMX7D_PLL_DRAM_MAIN_CLK] = imx_clk_hw_gate("pll_dram_main_clk", "pll_dram_test_div", base + 0x70, 13);
+       hws[IMX7D_PLL_SYS_MAIN_CLK] = imx_clk_hw_gate("pll_sys_main_clk", "pll_sys_main_bypass", base + 0xb0, 13);
+       hws[IMX7D_PLL_AUDIO_MAIN_CLK] = imx_clk_hw_gate("pll_audio_main_clk", "pll_audio_main_bypass", base + 0xf0, 13);
+       hws[IMX7D_PLL_VIDEO_MAIN_CLK] = imx_clk_hw_gate("pll_video_main_clk", "pll_video_main_bypass", base + 0x130, 13);
+
+       hws[IMX7D_PLL_DRAM_TEST_DIV]  = clk_hw_register_divider_table(NULL, "pll_dram_test_div", "pll_dram_main_bypass",
                                CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x70, 21, 2, 0, test_div_table, &imx_ccm_lock);
-       clks[IMX7D_PLL_AUDIO_TEST_DIV]  = clk_register_divider_table(NULL, "pll_audio_test_div", "pll_audio_main_clk",
+       hws[IMX7D_PLL_AUDIO_TEST_DIV]  = clk_hw_register_divider_table(NULL, "pll_audio_test_div", "pll_audio_main_clk",
                                CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xf0, 19, 2, 0, test_div_table, &imx_ccm_lock);
-       clks[IMX7D_PLL_AUDIO_POST_DIV] = clk_register_divider_table(NULL, "pll_audio_post_div", "pll_audio_test_div",
+       hws[IMX7D_PLL_AUDIO_POST_DIV] = clk_hw_register_divider_table(NULL, "pll_audio_post_div", "pll_audio_test_div",
                                CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xf0, 22, 2, 0, post_div_table, &imx_ccm_lock);
-       clks[IMX7D_PLL_VIDEO_TEST_DIV]  = clk_register_divider_table(NULL, "pll_video_test_div", "pll_video_main_clk",
+       hws[IMX7D_PLL_VIDEO_TEST_DIV]  = clk_hw_register_divider_table(NULL, "pll_video_test_div", "pll_video_main_clk",
                                CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x130, 19, 2, 0, test_div_table, &imx_ccm_lock);
-       clks[IMX7D_PLL_VIDEO_POST_DIV] = clk_register_divider_table(NULL, "pll_video_post_div", "pll_video_test_div",
+       hws[IMX7D_PLL_VIDEO_POST_DIV] = clk_hw_register_divider_table(NULL, "pll_video_post_div", "pll_video_test_div",
                                CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x130, 22, 2, 0, post_div_table, &imx_ccm_lock);
 
-       clks[IMX7D_PLL_SYS_PFD0_392M_CLK] = imx_clk_pfd("pll_sys_pfd0_392m_clk", "pll_sys_main_clk", base + 0xc0, 0);
-       clks[IMX7D_PLL_SYS_PFD1_332M_CLK] = imx_clk_pfd("pll_sys_pfd1_332m_clk", "pll_sys_main_clk", base + 0xc0, 1);
-       clks[IMX7D_PLL_SYS_PFD2_270M_CLK] = imx_clk_pfd("pll_sys_pfd2_270m_clk", "pll_sys_main_clk", base + 0xc0, 2);
-
-       clks[IMX7D_PLL_SYS_PFD3_CLK] = imx_clk_pfd("pll_sys_pfd3_clk", "pll_sys_main_clk", base + 0xc0, 3);
-       clks[IMX7D_PLL_SYS_PFD4_CLK] = imx_clk_pfd("pll_sys_pfd4_clk", "pll_sys_main_clk", base + 0xd0, 0);
-       clks[IMX7D_PLL_SYS_PFD5_CLK] = imx_clk_pfd("pll_sys_pfd5_clk", "pll_sys_main_clk", base + 0xd0, 1);
-       clks[IMX7D_PLL_SYS_PFD6_CLK] = imx_clk_pfd("pll_sys_pfd6_clk", "pll_sys_main_clk", base + 0xd0, 2);
-       clks[IMX7D_PLL_SYS_PFD7_CLK] = imx_clk_pfd("pll_sys_pfd7_clk", "pll_sys_main_clk", base + 0xd0, 3);
-
-       clks[IMX7D_PLL_SYS_MAIN_480M] = imx_clk_fixed_factor("pll_sys_main_480m", "pll_sys_main_clk", 1, 1);
-       clks[IMX7D_PLL_SYS_MAIN_240M] = imx_clk_fixed_factor("pll_sys_main_240m", "pll_sys_main_clk", 1, 2);
-       clks[IMX7D_PLL_SYS_MAIN_120M] = imx_clk_fixed_factor("pll_sys_main_120m", "pll_sys_main_clk", 1, 4);
-       clks[IMX7D_PLL_DRAM_MAIN_533M] = imx_clk_fixed_factor("pll_dram_533m", "pll_dram_main_clk", 1, 2);
-
-       clks[IMX7D_PLL_SYS_MAIN_480M_CLK] = imx_clk_gate_dis_flags("pll_sys_main_480m_clk", "pll_sys_main_480m", base + 0xb0, 4, CLK_IS_CRITICAL);
-       clks[IMX7D_PLL_SYS_MAIN_240M_CLK] = imx_clk_gate_dis("pll_sys_main_240m_clk", "pll_sys_main_240m", base + 0xb0, 5);
-       clks[IMX7D_PLL_SYS_MAIN_120M_CLK] = imx_clk_gate_dis("pll_sys_main_120m_clk", "pll_sys_main_120m", base + 0xb0, 6);
-       clks[IMX7D_PLL_DRAM_MAIN_533M_CLK] = imx_clk_gate("pll_dram_533m_clk", "pll_dram_533m", base + 0x70, 12);
-
-       clks[IMX7D_PLL_SYS_PFD0_196M] = imx_clk_fixed_factor("pll_sys_pfd0_196m", "pll_sys_pfd0_392m_clk", 1, 2);
-       clks[IMX7D_PLL_SYS_PFD1_166M] = imx_clk_fixed_factor("pll_sys_pfd1_166m", "pll_sys_pfd1_332m_clk", 1, 2);
-       clks[IMX7D_PLL_SYS_PFD2_135M] = imx_clk_fixed_factor("pll_sys_pfd2_135m", "pll_sys_pfd2_270m_clk", 1, 2);
-
-       clks[IMX7D_PLL_SYS_PFD0_196M_CLK] = imx_clk_gate_dis("pll_sys_pfd0_196m_clk", "pll_sys_pfd0_196m", base + 0xb0, 26);
-       clks[IMX7D_PLL_SYS_PFD1_166M_CLK] = imx_clk_gate_dis("pll_sys_pfd1_166m_clk", "pll_sys_pfd1_166m", base + 0xb0, 27);
-       clks[IMX7D_PLL_SYS_PFD2_135M_CLK] = imx_clk_gate_dis("pll_sys_pfd2_135m_clk", "pll_sys_pfd2_135m", base + 0xb0, 28);
-
-       clks[IMX7D_PLL_ENET_MAIN_CLK] = imx_clk_fixed_factor("pll_enet_main_clk", "pll_enet_main_bypass", 1, 1);
-       clks[IMX7D_PLL_ENET_MAIN_500M] = imx_clk_fixed_factor("pll_enet_500m", "pll_enet_main_clk", 1, 2);
-       clks[IMX7D_PLL_ENET_MAIN_250M] = imx_clk_fixed_factor("pll_enet_250m", "pll_enet_main_clk", 1, 4);
-       clks[IMX7D_PLL_ENET_MAIN_125M] = imx_clk_fixed_factor("pll_enet_125m", "pll_enet_main_clk", 1, 8);
-       clks[IMX7D_PLL_ENET_MAIN_100M] = imx_clk_fixed_factor("pll_enet_100m", "pll_enet_main_clk", 1, 10);
-       clks[IMX7D_PLL_ENET_MAIN_50M] = imx_clk_fixed_factor("pll_enet_50m", "pll_enet_main_clk", 1, 20);
-       clks[IMX7D_PLL_ENET_MAIN_40M] = imx_clk_fixed_factor("pll_enet_40m", "pll_enet_main_clk", 1, 25);
-       clks[IMX7D_PLL_ENET_MAIN_25M] = imx_clk_fixed_factor("pll_enet_25m", "pll_enet_main_clk", 1, 40);
-
-       clks[IMX7D_PLL_ENET_MAIN_500M_CLK] = imx_clk_gate("pll_enet_500m_clk", "pll_enet_500m", base + 0xe0, 12);
-       clks[IMX7D_PLL_ENET_MAIN_250M_CLK] = imx_clk_gate("pll_enet_250m_clk", "pll_enet_250m", base + 0xe0, 11);
-       clks[IMX7D_PLL_ENET_MAIN_125M_CLK] = imx_clk_gate("pll_enet_125m_clk", "pll_enet_125m", base + 0xe0, 10);
-       clks[IMX7D_PLL_ENET_MAIN_100M_CLK] = imx_clk_gate("pll_enet_100m_clk", "pll_enet_100m", base + 0xe0, 9);
-       clks[IMX7D_PLL_ENET_MAIN_50M_CLK]  = imx_clk_gate("pll_enet_50m_clk", "pll_enet_50m", base + 0xe0, 8);
-       clks[IMX7D_PLL_ENET_MAIN_40M_CLK]  = imx_clk_gate("pll_enet_40m_clk", "pll_enet_40m", base + 0xe0, 7);
-       clks[IMX7D_PLL_ENET_MAIN_25M_CLK]  = imx_clk_gate("pll_enet_25m_clk", "pll_enet_25m", base + 0xe0, 6);
-
-       clks[IMX7D_LVDS1_OUT_SEL] = imx_clk_mux("lvds1_sel", base + 0x170, 0, 5, lvds1_sel, ARRAY_SIZE(lvds1_sel));
-       clks[IMX7D_LVDS1_OUT_CLK] = imx_clk_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x170, 5, BIT(6));
+       hws[IMX7D_PLL_SYS_PFD0_392M_CLK] = imx_clk_hw_pfd("pll_sys_pfd0_392m_clk", "pll_sys_main_clk", base + 0xc0, 0);
+       hws[IMX7D_PLL_SYS_PFD1_332M_CLK] = imx_clk_hw_pfd("pll_sys_pfd1_332m_clk", "pll_sys_main_clk", base + 0xc0, 1);
+       hws[IMX7D_PLL_SYS_PFD2_270M_CLK] = imx_clk_hw_pfd("pll_sys_pfd2_270m_clk", "pll_sys_main_clk", base + 0xc0, 2);
+
+       hws[IMX7D_PLL_SYS_PFD3_CLK] = imx_clk_hw_pfd("pll_sys_pfd3_clk", "pll_sys_main_clk", base + 0xc0, 3);
+       hws[IMX7D_PLL_SYS_PFD4_CLK] = imx_clk_hw_pfd("pll_sys_pfd4_clk", "pll_sys_main_clk", base + 0xd0, 0);
+       hws[IMX7D_PLL_SYS_PFD5_CLK] = imx_clk_hw_pfd("pll_sys_pfd5_clk", "pll_sys_main_clk", base + 0xd0, 1);
+       hws[IMX7D_PLL_SYS_PFD6_CLK] = imx_clk_hw_pfd("pll_sys_pfd6_clk", "pll_sys_main_clk", base + 0xd0, 2);
+       hws[IMX7D_PLL_SYS_PFD7_CLK] = imx_clk_hw_pfd("pll_sys_pfd7_clk", "pll_sys_main_clk", base + 0xd0, 3);
+
+       hws[IMX7D_PLL_SYS_MAIN_480M] = imx_clk_hw_fixed_factor("pll_sys_main_480m", "pll_sys_main_clk", 1, 1);
+       hws[IMX7D_PLL_SYS_MAIN_240M] = imx_clk_hw_fixed_factor("pll_sys_main_240m", "pll_sys_main_clk", 1, 2);
+       hws[IMX7D_PLL_SYS_MAIN_120M] = imx_clk_hw_fixed_factor("pll_sys_main_120m", "pll_sys_main_clk", 1, 4);
+       hws[IMX7D_PLL_DRAM_MAIN_533M] = imx_clk_hw_fixed_factor("pll_dram_533m", "pll_dram_main_clk", 1, 2);
+
+       hws[IMX7D_PLL_SYS_MAIN_480M_CLK] = imx_clk_hw_gate_dis_flags("pll_sys_main_480m_clk", "pll_sys_main_480m", base + 0xb0, 4, CLK_IS_CRITICAL);
+       hws[IMX7D_PLL_SYS_MAIN_240M_CLK] = imx_clk_hw_gate_dis("pll_sys_main_240m_clk", "pll_sys_main_240m", base + 0xb0, 5);
+       hws[IMX7D_PLL_SYS_MAIN_120M_CLK] = imx_clk_hw_gate_dis("pll_sys_main_120m_clk", "pll_sys_main_120m", base + 0xb0, 6);
+       hws[IMX7D_PLL_DRAM_MAIN_533M_CLK] = imx_clk_hw_gate("pll_dram_533m_clk", "pll_dram_533m", base + 0x70, 12);
+
+       hws[IMX7D_PLL_SYS_PFD0_196M] = imx_clk_hw_fixed_factor("pll_sys_pfd0_196m", "pll_sys_pfd0_392m_clk", 1, 2);
+       hws[IMX7D_PLL_SYS_PFD1_166M] = imx_clk_hw_fixed_factor("pll_sys_pfd1_166m", "pll_sys_pfd1_332m_clk", 1, 2);
+       hws[IMX7D_PLL_SYS_PFD2_135M] = imx_clk_hw_fixed_factor("pll_sys_pfd2_135m", "pll_sys_pfd2_270m_clk", 1, 2);
+
+       hws[IMX7D_PLL_SYS_PFD0_196M_CLK] = imx_clk_hw_gate_dis("pll_sys_pfd0_196m_clk", "pll_sys_pfd0_196m", base + 0xb0, 26);
+       hws[IMX7D_PLL_SYS_PFD1_166M_CLK] = imx_clk_hw_gate_dis("pll_sys_pfd1_166m_clk", "pll_sys_pfd1_166m", base + 0xb0, 27);
+       hws[IMX7D_PLL_SYS_PFD2_135M_CLK] = imx_clk_hw_gate_dis("pll_sys_pfd2_135m_clk", "pll_sys_pfd2_135m", base + 0xb0, 28);
+
+       hws[IMX7D_PLL_ENET_MAIN_CLK] = imx_clk_hw_fixed_factor("pll_enet_main_clk", "pll_enet_main_bypass", 1, 1);
+       hws[IMX7D_PLL_ENET_MAIN_500M] = imx_clk_hw_fixed_factor("pll_enet_500m", "pll_enet_main_clk", 1, 2);
+       hws[IMX7D_PLL_ENET_MAIN_250M] = imx_clk_hw_fixed_factor("pll_enet_250m", "pll_enet_main_clk", 1, 4);
+       hws[IMX7D_PLL_ENET_MAIN_125M] = imx_clk_hw_fixed_factor("pll_enet_125m", "pll_enet_main_clk", 1, 8);
+       hws[IMX7D_PLL_ENET_MAIN_100M] = imx_clk_hw_fixed_factor("pll_enet_100m", "pll_enet_main_clk", 1, 10);
+       hws[IMX7D_PLL_ENET_MAIN_50M] = imx_clk_hw_fixed_factor("pll_enet_50m", "pll_enet_main_clk", 1, 20);
+       hws[IMX7D_PLL_ENET_MAIN_40M] = imx_clk_hw_fixed_factor("pll_enet_40m", "pll_enet_main_clk", 1, 25);
+       hws[IMX7D_PLL_ENET_MAIN_25M] = imx_clk_hw_fixed_factor("pll_enet_25m", "pll_enet_main_clk", 1, 40);
+
+       hws[IMX7D_PLL_ENET_MAIN_500M_CLK] = imx_clk_hw_gate("pll_enet_500m_clk", "pll_enet_500m", base + 0xe0, 12);
+       hws[IMX7D_PLL_ENET_MAIN_250M_CLK] = imx_clk_hw_gate("pll_enet_250m_clk", "pll_enet_250m", base + 0xe0, 11);
+       hws[IMX7D_PLL_ENET_MAIN_125M_CLK] = imx_clk_hw_gate("pll_enet_125m_clk", "pll_enet_125m", base + 0xe0, 10);
+       hws[IMX7D_PLL_ENET_MAIN_100M_CLK] = imx_clk_hw_gate("pll_enet_100m_clk", "pll_enet_100m", base + 0xe0, 9);
+       hws[IMX7D_PLL_ENET_MAIN_50M_CLK]  = imx_clk_hw_gate("pll_enet_50m_clk", "pll_enet_50m", base + 0xe0, 8);
+       hws[IMX7D_PLL_ENET_MAIN_40M_CLK]  = imx_clk_hw_gate("pll_enet_40m_clk", "pll_enet_40m", base + 0xe0, 7);
+       hws[IMX7D_PLL_ENET_MAIN_25M_CLK]  = imx_clk_hw_gate("pll_enet_25m_clk", "pll_enet_25m", base + 0xe0, 6);
+
+       hws[IMX7D_LVDS1_OUT_SEL] = imx_clk_hw_mux("lvds1_sel", base + 0x170, 0, 5, lvds1_sel, ARRAY_SIZE(lvds1_sel));
+       hws[IMX7D_LVDS1_OUT_CLK] = imx_clk_hw_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x170, 5, BIT(6));
 
        np = ccm_node;
        base = of_iomap(np, 0);
        WARN_ON(!base);
 
-       clks[IMX7D_ARM_A7_ROOT_SRC] = imx_clk_mux2("arm_a7_src", base + 0x8000, 24, 3, arm_a7_sel, ARRAY_SIZE(arm_a7_sel));
-       clks[IMX7D_ARM_M4_ROOT_SRC] = imx_clk_mux2("arm_m4_src", base + 0x8080, 24, 3, arm_m4_sel, ARRAY_SIZE(arm_m4_sel));
-       clks[IMX7D_MAIN_AXI_ROOT_SRC] = imx_clk_mux2("axi_src", base + 0x8800, 24, 3, axi_sel, ARRAY_SIZE(axi_sel));
-       clks[IMX7D_DISP_AXI_ROOT_SRC] = imx_clk_mux2("disp_axi_src", base + 0x8880, 24, 3, disp_axi_sel, ARRAY_SIZE(disp_axi_sel));
-       clks[IMX7D_ENET_AXI_ROOT_SRC] = imx_clk_mux2("enet_axi_src", base + 0x8900, 24, 3, enet_axi_sel, ARRAY_SIZE(enet_axi_sel));
-       clks[IMX7D_NAND_USDHC_BUS_ROOT_SRC] = imx_clk_mux2("nand_usdhc_src", base + 0x8980, 24, 3, nand_usdhc_bus_sel, ARRAY_SIZE(nand_usdhc_bus_sel));
-       clks[IMX7D_AHB_CHANNEL_ROOT_SRC] = imx_clk_mux2("ahb_src", base + 0x9000, 24, 3, ahb_channel_sel, ARRAY_SIZE(ahb_channel_sel));
-       clks[IMX7D_DRAM_PHYM_ROOT_SRC] = imx_clk_mux2("dram_phym_src", base + 0x9800, 24, 1, dram_phym_sel, ARRAY_SIZE(dram_phym_sel));
-       clks[IMX7D_DRAM_ROOT_SRC] = imx_clk_mux2("dram_src", base + 0x9880, 24, 1, dram_sel, ARRAY_SIZE(dram_sel));
-       clks[IMX7D_DRAM_PHYM_ALT_ROOT_SRC] = imx_clk_mux2("dram_phym_alt_src", base + 0xa000, 24, 3, dram_phym_alt_sel, ARRAY_SIZE(dram_phym_alt_sel));
-       clks[IMX7D_DRAM_ALT_ROOT_SRC]  = imx_clk_mux2("dram_alt_src", base + 0xa080, 24, 3, dram_alt_sel, ARRAY_SIZE(dram_alt_sel));
-       clks[IMX7D_USB_HSIC_ROOT_SRC] = imx_clk_mux2("usb_hsic_src", base + 0xa100, 24, 3, usb_hsic_sel, ARRAY_SIZE(usb_hsic_sel));
-       clks[IMX7D_PCIE_CTRL_ROOT_SRC] = imx_clk_mux2("pcie_ctrl_src", base + 0xa180, 24, 3, pcie_ctrl_sel, ARRAY_SIZE(pcie_ctrl_sel));
-       clks[IMX7D_PCIE_PHY_ROOT_SRC] = imx_clk_mux2("pcie_phy_src", base + 0xa200, 24, 3, pcie_phy_sel, ARRAY_SIZE(pcie_phy_sel));
-       clks[IMX7D_EPDC_PIXEL_ROOT_SRC] = imx_clk_mux2("epdc_pixel_src", base + 0xa280, 24, 3, epdc_pixel_sel, ARRAY_SIZE(epdc_pixel_sel));
-       clks[IMX7D_LCDIF_PIXEL_ROOT_SRC] = imx_clk_mux2("lcdif_pixel_src", base + 0xa300, 24, 3, lcdif_pixel_sel, ARRAY_SIZE(lcdif_pixel_sel));
-       clks[IMX7D_MIPI_DSI_ROOT_SRC] = imx_clk_mux2("mipi_dsi_src", base + 0xa380, 24, 3,  mipi_dsi_sel, ARRAY_SIZE(mipi_dsi_sel));
-       clks[IMX7D_MIPI_CSI_ROOT_SRC] = imx_clk_mux2("mipi_csi_src", base + 0xa400, 24, 3, mipi_csi_sel, ARRAY_SIZE(mipi_csi_sel));
-       clks[IMX7D_MIPI_DPHY_ROOT_SRC] = imx_clk_mux2("mipi_dphy_src", base + 0xa480, 24, 3, mipi_dphy_sel, ARRAY_SIZE(mipi_dphy_sel));
-       clks[IMX7D_SAI1_ROOT_SRC] = imx_clk_mux2("sai1_src", base + 0xa500, 24, 3, sai1_sel, ARRAY_SIZE(sai1_sel));
-       clks[IMX7D_SAI2_ROOT_SRC] = imx_clk_mux2("sai2_src", base + 0xa580, 24, 3, sai2_sel, ARRAY_SIZE(sai2_sel));
-       clks[IMX7D_SAI3_ROOT_SRC] = imx_clk_mux2("sai3_src", base + 0xa600, 24, 3, sai3_sel, ARRAY_SIZE(sai3_sel));
-       clks[IMX7D_SPDIF_ROOT_SRC] = imx_clk_mux2("spdif_src", base + 0xa680, 24, 3, spdif_sel, ARRAY_SIZE(spdif_sel));
-       clks[IMX7D_ENET1_REF_ROOT_SRC] = imx_clk_mux2("enet1_ref_src", base + 0xa700, 24, 3, enet1_ref_sel, ARRAY_SIZE(enet1_ref_sel));
-       clks[IMX7D_ENET1_TIME_ROOT_SRC] = imx_clk_mux2("enet1_time_src", base + 0xa780, 24, 3, enet1_time_sel, ARRAY_SIZE(enet1_time_sel));
-       clks[IMX7D_ENET2_REF_ROOT_SRC] = imx_clk_mux2("enet2_ref_src", base + 0xa800, 24, 3, enet2_ref_sel, ARRAY_SIZE(enet2_ref_sel));
-       clks[IMX7D_ENET2_TIME_ROOT_SRC] = imx_clk_mux2("enet2_time_src", base + 0xa880, 24, 3, enet2_time_sel, ARRAY_SIZE(enet2_time_sel));
-       clks[IMX7D_ENET_PHY_REF_ROOT_SRC] = imx_clk_mux2("enet_phy_ref_src", base + 0xa900, 24, 3, enet_phy_ref_sel, ARRAY_SIZE(enet_phy_ref_sel));
-       clks[IMX7D_EIM_ROOT_SRC] = imx_clk_mux2("eim_src", base + 0xa980, 24, 3, eim_sel, ARRAY_SIZE(eim_sel));
-       clks[IMX7D_NAND_ROOT_SRC] = imx_clk_mux2("nand_src", base + 0xaa00, 24, 3, nand_sel, ARRAY_SIZE(nand_sel));
-       clks[IMX7D_QSPI_ROOT_SRC] = imx_clk_mux2("qspi_src", base + 0xaa80, 24, 3, qspi_sel, ARRAY_SIZE(qspi_sel));
-       clks[IMX7D_USDHC1_ROOT_SRC] = imx_clk_mux2("usdhc1_src", base + 0xab00, 24, 3, usdhc1_sel, ARRAY_SIZE(usdhc1_sel));
-       clks[IMX7D_USDHC2_ROOT_SRC] = imx_clk_mux2("usdhc2_src", base + 0xab80, 24, 3, usdhc2_sel, ARRAY_SIZE(usdhc2_sel));
-       clks[IMX7D_USDHC3_ROOT_SRC] = imx_clk_mux2("usdhc3_src", base + 0xac00, 24, 3, usdhc3_sel, ARRAY_SIZE(usdhc3_sel));
-       clks[IMX7D_CAN1_ROOT_SRC] = imx_clk_mux2("can1_src", base + 0xac80, 24, 3, can1_sel, ARRAY_SIZE(can1_sel));
-       clks[IMX7D_CAN2_ROOT_SRC] = imx_clk_mux2("can2_src", base + 0xad00, 24, 3, can2_sel, ARRAY_SIZE(can2_sel));
-       clks[IMX7D_I2C1_ROOT_SRC] = imx_clk_mux2("i2c1_src", base + 0xad80, 24, 3, i2c1_sel, ARRAY_SIZE(i2c1_sel));
-       clks[IMX7D_I2C2_ROOT_SRC] = imx_clk_mux2("i2c2_src", base + 0xae00, 24, 3, i2c2_sel, ARRAY_SIZE(i2c2_sel));
-       clks[IMX7D_I2C3_ROOT_SRC] = imx_clk_mux2("i2c3_src", base + 0xae80, 24, 3, i2c3_sel, ARRAY_SIZE(i2c3_sel));
-       clks[IMX7D_I2C4_ROOT_SRC] = imx_clk_mux2("i2c4_src", base + 0xaf00, 24, 3, i2c4_sel, ARRAY_SIZE(i2c4_sel));
-       clks[IMX7D_UART1_ROOT_SRC] = imx_clk_mux2("uart1_src", base + 0xaf80, 24, 3, uart1_sel, ARRAY_SIZE(uart1_sel));
-       clks[IMX7D_UART2_ROOT_SRC] = imx_clk_mux2("uart2_src", base + 0xb000, 24, 3, uart2_sel, ARRAY_SIZE(uart2_sel));
-       clks[IMX7D_UART3_ROOT_SRC] = imx_clk_mux2("uart3_src", base + 0xb080, 24, 3, uart3_sel, ARRAY_SIZE(uart3_sel));
-       clks[IMX7D_UART4_ROOT_SRC] = imx_clk_mux2("uart4_src", base + 0xb100, 24, 3, uart4_sel, ARRAY_SIZE(uart4_sel));
-       clks[IMX7D_UART5_ROOT_SRC] = imx_clk_mux2("uart5_src", base + 0xb180, 24, 3, uart5_sel, ARRAY_SIZE(uart5_sel));
-       clks[IMX7D_UART6_ROOT_SRC] = imx_clk_mux2("uart6_src", base + 0xb200, 24, 3, uart6_sel, ARRAY_SIZE(uart6_sel));
-       clks[IMX7D_UART7_ROOT_SRC] = imx_clk_mux2("uart7_src", base + 0xb280, 24, 3, uart7_sel, ARRAY_SIZE(uart7_sel));
-       clks[IMX7D_ECSPI1_ROOT_SRC] = imx_clk_mux2("ecspi1_src", base + 0xb300, 24, 3, ecspi1_sel, ARRAY_SIZE(ecspi1_sel));
-       clks[IMX7D_ECSPI2_ROOT_SRC] = imx_clk_mux2("ecspi2_src", base + 0xb380, 24, 3, ecspi2_sel, ARRAY_SIZE(ecspi2_sel));
-       clks[IMX7D_ECSPI3_ROOT_SRC] = imx_clk_mux2("ecspi3_src", base + 0xb400, 24, 3, ecspi3_sel, ARRAY_SIZE(ecspi3_sel));
-       clks[IMX7D_ECSPI4_ROOT_SRC] = imx_clk_mux2("ecspi4_src", base + 0xb480, 24, 3, ecspi4_sel, ARRAY_SIZE(ecspi4_sel));
-       clks[IMX7D_PWM1_ROOT_SRC] = imx_clk_mux2("pwm1_src", base + 0xb500, 24, 3, pwm1_sel, ARRAY_SIZE(pwm1_sel));
-       clks[IMX7D_PWM2_ROOT_SRC] = imx_clk_mux2("pwm2_src", base + 0xb580, 24, 3, pwm2_sel, ARRAY_SIZE(pwm2_sel));
-       clks[IMX7D_PWM3_ROOT_SRC] = imx_clk_mux2("pwm3_src", base + 0xb600, 24, 3, pwm3_sel, ARRAY_SIZE(pwm3_sel));
-       clks[IMX7D_PWM4_ROOT_SRC] = imx_clk_mux2("pwm4_src", base + 0xb680, 24, 3, pwm4_sel, ARRAY_SIZE(pwm4_sel));
-       clks[IMX7D_FLEXTIMER1_ROOT_SRC] = imx_clk_mux2("flextimer1_src", base + 0xb700, 24, 3, flextimer1_sel, ARRAY_SIZE(flextimer1_sel));
-       clks[IMX7D_FLEXTIMER2_ROOT_SRC] = imx_clk_mux2("flextimer2_src", base + 0xb780, 24, 3, flextimer2_sel, ARRAY_SIZE(flextimer2_sel));
-       clks[IMX7D_SIM1_ROOT_SRC] = imx_clk_mux2("sim1_src", base + 0xb800, 24, 3, sim1_sel, ARRAY_SIZE(sim1_sel));
-       clks[IMX7D_SIM2_ROOT_SRC] = imx_clk_mux2("sim2_src", base + 0xb880, 24, 3, sim2_sel, ARRAY_SIZE(sim2_sel));
-       clks[IMX7D_GPT1_ROOT_SRC] = imx_clk_mux2("gpt1_src", base + 0xb900, 24, 3, gpt1_sel, ARRAY_SIZE(gpt1_sel));
-       clks[IMX7D_GPT2_ROOT_SRC] = imx_clk_mux2("gpt2_src", base + 0xb980, 24, 3, gpt2_sel, ARRAY_SIZE(gpt2_sel));
-       clks[IMX7D_GPT3_ROOT_SRC] = imx_clk_mux2("gpt3_src", base + 0xba00, 24, 3, gpt3_sel, ARRAY_SIZE(gpt3_sel));
-       clks[IMX7D_GPT4_ROOT_SRC] = imx_clk_mux2("gpt4_src", base + 0xba80, 24, 3, gpt4_sel, ARRAY_SIZE(gpt4_sel));
-       clks[IMX7D_TRACE_ROOT_SRC] = imx_clk_mux2("trace_src", base + 0xbb00, 24, 3, trace_sel, ARRAY_SIZE(trace_sel));
-       clks[IMX7D_WDOG_ROOT_SRC] = imx_clk_mux2("wdog_src", base + 0xbb80, 24, 3, wdog_sel, ARRAY_SIZE(wdog_sel));
-       clks[IMX7D_CSI_MCLK_ROOT_SRC] = imx_clk_mux2("csi_mclk_src", base + 0xbc00, 24, 3, csi_mclk_sel, ARRAY_SIZE(csi_mclk_sel));
-       clks[IMX7D_AUDIO_MCLK_ROOT_SRC] = imx_clk_mux2("audio_mclk_src", base + 0xbc80, 24, 3, audio_mclk_sel, ARRAY_SIZE(audio_mclk_sel));
-       clks[IMX7D_WRCLK_ROOT_SRC] = imx_clk_mux2("wrclk_src", base + 0xbd00, 24, 3, wrclk_sel, ARRAY_SIZE(wrclk_sel));
-       clks[IMX7D_CLKO1_ROOT_SRC] = imx_clk_mux2("clko1_src", base + 0xbd80, 24, 3, clko1_sel, ARRAY_SIZE(clko1_sel));
-       clks[IMX7D_CLKO2_ROOT_SRC] = imx_clk_mux2("clko2_src", base + 0xbe00, 24, 3, clko2_sel, ARRAY_SIZE(clko2_sel));
-
-       clks[IMX7D_ARM_A7_ROOT_CG] = imx_clk_gate3("arm_a7_cg", "arm_a7_src", base + 0x8000, 28);
-       clks[IMX7D_ARM_M4_ROOT_CG] = imx_clk_gate3("arm_m4_cg", "arm_m4_src", base + 0x8080, 28);
-       clks[IMX7D_MAIN_AXI_ROOT_CG] = imx_clk_gate3("axi_cg", "axi_src", base + 0x8800, 28);
-       clks[IMX7D_DISP_AXI_ROOT_CG] = imx_clk_gate3("disp_axi_cg", "disp_axi_src", base + 0x8880, 28);
-       clks[IMX7D_ENET_AXI_ROOT_CG] = imx_clk_gate3("enet_axi_cg", "enet_axi_src", base + 0x8900, 28);
-       clks[IMX7D_NAND_USDHC_BUS_ROOT_CG] = imx_clk_gate3("nand_usdhc_cg", "nand_usdhc_src", base + 0x8980, 28);
-       clks[IMX7D_AHB_CHANNEL_ROOT_CG] = imx_clk_gate3("ahb_cg", "ahb_src", base + 0x9000, 28);
-       clks[IMX7D_DRAM_PHYM_ROOT_CG] = imx_clk_gate3("dram_phym_cg", "dram_phym_src", base + 0x9800, 28);
-       clks[IMX7D_DRAM_ROOT_CG] = imx_clk_gate3("dram_cg", "dram_src", base + 0x9880, 28);
-       clks[IMX7D_DRAM_PHYM_ALT_ROOT_CG] = imx_clk_gate3("dram_phym_alt_cg", "dram_phym_alt_src", base + 0xa000, 28);
-       clks[IMX7D_DRAM_ALT_ROOT_CG] = imx_clk_gate3("dram_alt_cg", "dram_alt_src", base + 0xa080, 28);
-       clks[IMX7D_USB_HSIC_ROOT_CG] = imx_clk_gate3("usb_hsic_cg", "usb_hsic_src", base + 0xa100, 28);
-       clks[IMX7D_PCIE_CTRL_ROOT_CG] = imx_clk_gate3("pcie_ctrl_cg", "pcie_ctrl_src", base + 0xa180, 28);
-       clks[IMX7D_PCIE_PHY_ROOT_CG] = imx_clk_gate3("pcie_phy_cg", "pcie_phy_src", base + 0xa200, 28);
-       clks[IMX7D_EPDC_PIXEL_ROOT_CG] = imx_clk_gate3("epdc_pixel_cg", "epdc_pixel_src", base + 0xa280, 28);
-       clks[IMX7D_LCDIF_PIXEL_ROOT_CG] = imx_clk_gate3("lcdif_pixel_cg", "lcdif_pixel_src", base + 0xa300, 28);
-       clks[IMX7D_MIPI_DSI_ROOT_CG] = imx_clk_gate3("mipi_dsi_cg", "mipi_dsi_src", base + 0xa380, 28);
-       clks[IMX7D_MIPI_CSI_ROOT_CG] = imx_clk_gate3("mipi_csi_cg", "mipi_csi_src", base + 0xa400, 28);
-       clks[IMX7D_MIPI_DPHY_ROOT_CG] = imx_clk_gate3("mipi_dphy_cg", "mipi_dphy_src", base + 0xa480, 28);
-       clks[IMX7D_SAI1_ROOT_CG] = imx_clk_gate3("sai1_cg", "sai1_src", base + 0xa500, 28);
-       clks[IMX7D_SAI2_ROOT_CG] = imx_clk_gate3("sai2_cg", "sai2_src", base + 0xa580, 28);
-       clks[IMX7D_SAI3_ROOT_CG] = imx_clk_gate3("sai3_cg", "sai3_src", base + 0xa600, 28);
-       clks[IMX7D_SPDIF_ROOT_CG] = imx_clk_gate3("spdif_cg", "spdif_src", base + 0xa680, 28);
-       clks[IMX7D_ENET1_REF_ROOT_CG] = imx_clk_gate3("enet1_ref_cg", "enet1_ref_src", base + 0xa700, 28);
-       clks[IMX7D_ENET1_TIME_ROOT_CG] = imx_clk_gate3("enet1_time_cg", "enet1_time_src", base + 0xa780, 28);
-       clks[IMX7D_ENET2_REF_ROOT_CG] = imx_clk_gate3("enet2_ref_cg", "enet2_ref_src", base + 0xa800, 28);
-       clks[IMX7D_ENET2_TIME_ROOT_CG] = imx_clk_gate3("enet2_time_cg", "enet2_time_src", base + 0xa880, 28);
-       clks[IMX7D_ENET_PHY_REF_ROOT_CG] = imx_clk_gate3("enet_phy_ref_cg", "enet_phy_ref_src", base + 0xa900, 28);
-       clks[IMX7D_EIM_ROOT_CG] = imx_clk_gate3("eim_cg", "eim_src", base + 0xa980, 28);
-       clks[IMX7D_NAND_ROOT_CG] = imx_clk_gate3("nand_cg", "nand_src", base + 0xaa00, 28);
-       clks[IMX7D_QSPI_ROOT_CG] = imx_clk_gate3("qspi_cg", "qspi_src", base + 0xaa80, 28);
-       clks[IMX7D_USDHC1_ROOT_CG] = imx_clk_gate3("usdhc1_cg", "usdhc1_src", base + 0xab00, 28);
-       clks[IMX7D_USDHC2_ROOT_CG] = imx_clk_gate3("usdhc2_cg", "usdhc2_src", base + 0xab80, 28);
-       clks[IMX7D_USDHC3_ROOT_CG] = imx_clk_gate3("usdhc3_cg", "usdhc3_src", base + 0xac00, 28);
-       clks[IMX7D_CAN1_ROOT_CG] = imx_clk_gate3("can1_cg", "can1_src", base + 0xac80, 28);
-       clks[IMX7D_CAN2_ROOT_CG] = imx_clk_gate3("can2_cg", "can2_src", base + 0xad00, 28);
-       clks[IMX7D_I2C1_ROOT_CG] = imx_clk_gate3("i2c1_cg", "i2c1_src", base + 0xad80, 28);
-       clks[IMX7D_I2C2_ROOT_CG] = imx_clk_gate3("i2c2_cg", "i2c2_src", base + 0xae00, 28);
-       clks[IMX7D_I2C3_ROOT_CG] = imx_clk_gate3("i2c3_cg", "i2c3_src", base + 0xae80, 28);
-       clks[IMX7D_I2C4_ROOT_CG] = imx_clk_gate3("i2c4_cg", "i2c4_src", base + 0xaf00, 28);
-       clks[IMX7D_UART1_ROOT_CG] = imx_clk_gate3("uart1_cg", "uart1_src", base + 0xaf80, 28);
-       clks[IMX7D_UART2_ROOT_CG] = imx_clk_gate3("uart2_cg", "uart2_src", base + 0xb000, 28);
-       clks[IMX7D_UART3_ROOT_CG] = imx_clk_gate3("uart3_cg", "uart3_src", base + 0xb080, 28);
-       clks[IMX7D_UART4_ROOT_CG] = imx_clk_gate3("uart4_cg", "uart4_src", base + 0xb100, 28);
-       clks[IMX7D_UART5_ROOT_CG] = imx_clk_gate3("uart5_cg", "uart5_src", base + 0xb180, 28);
-       clks[IMX7D_UART6_ROOT_CG] = imx_clk_gate3("uart6_cg", "uart6_src", base + 0xb200, 28);
-       clks[IMX7D_UART7_ROOT_CG] = imx_clk_gate3("uart7_cg", "uart7_src", base + 0xb280, 28);
-       clks[IMX7D_ECSPI1_ROOT_CG] = imx_clk_gate3("ecspi1_cg", "ecspi1_src", base + 0xb300, 28);
-       clks[IMX7D_ECSPI2_ROOT_CG] = imx_clk_gate3("ecspi2_cg", "ecspi2_src", base + 0xb380, 28);
-       clks[IMX7D_ECSPI3_ROOT_CG] = imx_clk_gate3("ecspi3_cg", "ecspi3_src", base + 0xb400, 28);
-       clks[IMX7D_ECSPI4_ROOT_CG] = imx_clk_gate3("ecspi4_cg", "ecspi4_src", base + 0xb480, 28);
-       clks[IMX7D_PWM1_ROOT_CG] = imx_clk_gate3("pwm1_cg", "pwm1_src", base + 0xb500, 28);
-       clks[IMX7D_PWM2_ROOT_CG] = imx_clk_gate3("pwm2_cg", "pwm2_src", base + 0xb580, 28);
-       clks[IMX7D_PWM3_ROOT_CG] = imx_clk_gate3("pwm3_cg", "pwm3_src", base + 0xb600, 28);
-       clks[IMX7D_PWM4_ROOT_CG] = imx_clk_gate3("pwm4_cg", "pwm4_src", base + 0xb680, 28);
-       clks[IMX7D_FLEXTIMER1_ROOT_CG] = imx_clk_gate3("flextimer1_cg", "flextimer1_src", base + 0xb700, 28);
-       clks[IMX7D_FLEXTIMER2_ROOT_CG] = imx_clk_gate3("flextimer2_cg", "flextimer2_src", base + 0xb780, 28);
-       clks[IMX7D_SIM1_ROOT_CG] = imx_clk_gate3("sim1_cg", "sim1_src", base + 0xb800, 28);
-       clks[IMX7D_SIM2_ROOT_CG] = imx_clk_gate3("sim2_cg", "sim2_src", base + 0xb880, 28);
-       clks[IMX7D_GPT1_ROOT_CG] = imx_clk_gate3("gpt1_cg", "gpt1_src", base + 0xb900, 28);
-       clks[IMX7D_GPT2_ROOT_CG] = imx_clk_gate3("gpt2_cg", "gpt2_src", base + 0xb980, 28);
-       clks[IMX7D_GPT3_ROOT_CG] = imx_clk_gate3("gpt3_cg", "gpt3_src", base + 0xbA00, 28);
-       clks[IMX7D_GPT4_ROOT_CG] = imx_clk_gate3("gpt4_cg", "gpt4_src", base + 0xbA80, 28);
-       clks[IMX7D_TRACE_ROOT_CG] = imx_clk_gate3("trace_cg", "trace_src", base + 0xbb00, 28);
-       clks[IMX7D_WDOG_ROOT_CG] = imx_clk_gate3("wdog_cg", "wdog_src", base + 0xbb80, 28);
-       clks[IMX7D_CSI_MCLK_ROOT_CG] = imx_clk_gate3("csi_mclk_cg", "csi_mclk_src", base + 0xbc00, 28);
-       clks[IMX7D_AUDIO_MCLK_ROOT_CG] = imx_clk_gate3("audio_mclk_cg", "audio_mclk_src", base + 0xbc80, 28);
-       clks[IMX7D_WRCLK_ROOT_CG] = imx_clk_gate3("wrclk_cg", "wrclk_src", base + 0xbd00, 28);
-       clks[IMX7D_CLKO1_ROOT_CG] = imx_clk_gate3("clko1_cg", "clko1_src", base + 0xbd80, 28);
-       clks[IMX7D_CLKO2_ROOT_CG] = imx_clk_gate3("clko2_cg", "clko2_src", base + 0xbe00, 28);
-
-       clks[IMX7D_MAIN_AXI_ROOT_PRE_DIV] = imx_clk_divider2("axi_pre_div", "axi_cg", base + 0x8800, 16, 3);
-       clks[IMX7D_DISP_AXI_ROOT_PRE_DIV] = imx_clk_divider2("disp_axi_pre_div", "disp_axi_cg", base + 0x8880, 16, 3);
-       clks[IMX7D_ENET_AXI_ROOT_PRE_DIV] = imx_clk_divider2("enet_axi_pre_div", "enet_axi_cg", base + 0x8900, 16, 3);
-       clks[IMX7D_NAND_USDHC_BUS_ROOT_PRE_DIV] = imx_clk_divider2("nand_usdhc_pre_div", "nand_usdhc_cg", base + 0x8980, 16, 3);
-       clks[IMX7D_AHB_CHANNEL_ROOT_PRE_DIV] = imx_clk_divider2("ahb_pre_div", "ahb_cg", base + 0x9000, 16, 3);
-       clks[IMX7D_DRAM_PHYM_ALT_ROOT_PRE_DIV] = imx_clk_divider2("dram_phym_alt_pre_div", "dram_phym_alt_cg", base + 0xa000, 16, 3);
-       clks[IMX7D_DRAM_ALT_ROOT_PRE_DIV] = imx_clk_divider2("dram_alt_pre_div", "dram_alt_cg", base + 0xa080, 16, 3);
-       clks[IMX7D_USB_HSIC_ROOT_PRE_DIV] = imx_clk_divider2("usb_hsic_pre_div", "usb_hsic_cg", base + 0xa100, 16, 3);
-       clks[IMX7D_PCIE_CTRL_ROOT_PRE_DIV] = imx_clk_divider2("pcie_ctrl_pre_div", "pcie_ctrl_cg", base + 0xa180, 16, 3);
-       clks[IMX7D_PCIE_PHY_ROOT_PRE_DIV] = imx_clk_divider2("pcie_phy_pre_div", "pcie_phy_cg", base + 0xa200, 16, 3);
-       clks[IMX7D_EPDC_PIXEL_ROOT_PRE_DIV] = imx_clk_divider2("epdc_pixel_pre_div", "epdc_pixel_cg", base + 0xa280, 16, 3);
-       clks[IMX7D_LCDIF_PIXEL_ROOT_PRE_DIV] = imx_clk_divider2("lcdif_pixel_pre_div", "lcdif_pixel_cg", base + 0xa300, 16, 3);
-       clks[IMX7D_MIPI_DSI_ROOT_PRE_DIV] = imx_clk_divider2("mipi_dsi_pre_div", "mipi_dsi_cg", base + 0xa380, 16, 3);
-       clks[IMX7D_MIPI_CSI_ROOT_PRE_DIV] = imx_clk_divider2("mipi_csi_pre_div", "mipi_csi_cg", base + 0xa400, 16, 3);
-       clks[IMX7D_MIPI_DPHY_ROOT_PRE_DIV] = imx_clk_divider2("mipi_dphy_pre_div", "mipi_dphy_cg", base + 0xa480, 16, 3);
-       clks[IMX7D_SAI1_ROOT_PRE_DIV] = imx_clk_divider2("sai1_pre_div", "sai1_cg", base + 0xa500, 16, 3);
-       clks[IMX7D_SAI2_ROOT_PRE_DIV] = imx_clk_divider2("sai2_pre_div", "sai2_cg", base + 0xa580, 16, 3);
-       clks[IMX7D_SAI3_ROOT_PRE_DIV] = imx_clk_divider2("sai3_pre_div", "sai3_cg", base + 0xa600, 16, 3);
-       clks[IMX7D_SPDIF_ROOT_PRE_DIV] = imx_clk_divider2("spdif_pre_div", "spdif_cg", base + 0xa680, 16, 3);
-       clks[IMX7D_ENET1_REF_ROOT_PRE_DIV] = imx_clk_divider2("enet1_ref_pre_div", "enet1_ref_cg", base + 0xa700, 16, 3);
-       clks[IMX7D_ENET1_TIME_ROOT_PRE_DIV] = imx_clk_divider2("enet1_time_pre_div", "enet1_time_cg", base + 0xa780, 16, 3);
-       clks[IMX7D_ENET2_REF_ROOT_PRE_DIV] = imx_clk_divider2("enet2_ref_pre_div", "enet2_ref_cg", base + 0xa800, 16, 3);
-       clks[IMX7D_ENET2_TIME_ROOT_PRE_DIV] = imx_clk_divider2("enet2_time_pre_div", "enet2_time_cg", base + 0xa880, 16, 3);
-       clks[IMX7D_ENET_PHY_REF_ROOT_PRE_DIV] = imx_clk_divider2("enet_phy_ref_pre_div", "enet_phy_ref_cg", base + 0xa900, 16, 3);
-       clks[IMX7D_EIM_ROOT_PRE_DIV] = imx_clk_divider2("eim_pre_div", "eim_cg", base + 0xa980, 16, 3);
-       clks[IMX7D_NAND_ROOT_PRE_DIV] = imx_clk_divider2("nand_pre_div", "nand_cg", base + 0xaa00, 16, 3);
-       clks[IMX7D_QSPI_ROOT_PRE_DIV] = imx_clk_divider2("qspi_pre_div", "qspi_cg", base + 0xaa80, 16, 3);
-       clks[IMX7D_USDHC1_ROOT_PRE_DIV] = imx_clk_divider2("usdhc1_pre_div", "usdhc1_cg", base + 0xab00, 16, 3);
-       clks[IMX7D_USDHC2_ROOT_PRE_DIV] = imx_clk_divider2("usdhc2_pre_div", "usdhc2_cg", base + 0xab80, 16, 3);
-       clks[IMX7D_USDHC3_ROOT_PRE_DIV] = imx_clk_divider2("usdhc3_pre_div", "usdhc3_cg", base + 0xac00, 16, 3);
-       clks[IMX7D_CAN1_ROOT_PRE_DIV] = imx_clk_divider2("can1_pre_div", "can1_cg", base + 0xac80, 16, 3);
-       clks[IMX7D_CAN2_ROOT_PRE_DIV] = imx_clk_divider2("can2_pre_div", "can2_cg", base + 0xad00, 16, 3);
-       clks[IMX7D_I2C1_ROOT_PRE_DIV] = imx_clk_divider2("i2c1_pre_div", "i2c1_cg", base + 0xad80, 16, 3);
-       clks[IMX7D_I2C2_ROOT_PRE_DIV] = imx_clk_divider2("i2c2_pre_div", "i2c2_cg", base + 0xae00, 16, 3);
-       clks[IMX7D_I2C3_ROOT_PRE_DIV] = imx_clk_divider2("i2c3_pre_div", "i2c3_cg", base + 0xae80, 16, 3);
-       clks[IMX7D_I2C4_ROOT_PRE_DIV] = imx_clk_divider2("i2c4_pre_div", "i2c4_cg", base + 0xaf00, 16, 3);
-       clks[IMX7D_UART1_ROOT_PRE_DIV] = imx_clk_divider2("uart1_pre_div", "uart1_cg", base + 0xaf80, 16, 3);
-       clks[IMX7D_UART2_ROOT_PRE_DIV] = imx_clk_divider2("uart2_pre_div", "uart2_cg", base + 0xb000, 16, 3);
-       clks[IMX7D_UART3_ROOT_PRE_DIV] = imx_clk_divider2("uart3_pre_div", "uart3_cg", base + 0xb080, 16, 3);
-       clks[IMX7D_UART4_ROOT_PRE_DIV] = imx_clk_divider2("uart4_pre_div", "uart4_cg", base + 0xb100, 16, 3);
-       clks[IMX7D_UART5_ROOT_PRE_DIV] = imx_clk_divider2("uart5_pre_div", "uart5_cg", base + 0xb180, 16, 3);
-       clks[IMX7D_UART6_ROOT_PRE_DIV] = imx_clk_divider2("uart6_pre_div", "uart6_cg", base + 0xb200, 16, 3);
-       clks[IMX7D_UART7_ROOT_PRE_DIV] = imx_clk_divider2("uart7_pre_div", "uart7_cg", base + 0xb280, 16, 3);
-       clks[IMX7D_ECSPI1_ROOT_PRE_DIV] = imx_clk_divider2("ecspi1_pre_div", "ecspi1_cg", base + 0xb300, 16, 3);
-       clks[IMX7D_ECSPI2_ROOT_PRE_DIV] = imx_clk_divider2("ecspi2_pre_div", "ecspi2_cg", base + 0xb380, 16, 3);
-       clks[IMX7D_ECSPI3_ROOT_PRE_DIV] = imx_clk_divider2("ecspi3_pre_div", "ecspi3_cg", base + 0xb400, 16, 3);
-       clks[IMX7D_ECSPI4_ROOT_PRE_DIV] = imx_clk_divider2("ecspi4_pre_div", "ecspi4_cg", base + 0xb480, 16, 3);
-       clks[IMX7D_PWM1_ROOT_PRE_DIV] = imx_clk_divider2("pwm1_pre_div", "pwm1_cg", base + 0xb500, 16, 3);
-       clks[IMX7D_PWM2_ROOT_PRE_DIV] = imx_clk_divider2("pwm2_pre_div", "pwm2_cg", base + 0xb580, 16, 3);
-       clks[IMX7D_PWM3_ROOT_PRE_DIV] = imx_clk_divider2("pwm3_pre_div", "pwm3_cg", base + 0xb600, 16, 3);
-       clks[IMX7D_PWM4_ROOT_PRE_DIV] = imx_clk_divider2("pwm4_pre_div", "pwm4_cg", base + 0xb680, 16, 3);
-       clks[IMX7D_FLEXTIMER1_ROOT_PRE_DIV] = imx_clk_divider2("flextimer1_pre_div", "flextimer1_cg", base + 0xb700, 16, 3);
-       clks[IMX7D_FLEXTIMER2_ROOT_PRE_DIV] = imx_clk_divider2("flextimer2_pre_div", "flextimer2_cg", base + 0xb780, 16, 3);
-       clks[IMX7D_SIM1_ROOT_PRE_DIV] = imx_clk_divider2("sim1_pre_div", "sim1_cg", base + 0xb800, 16, 3);
-       clks[IMX7D_SIM2_ROOT_PRE_DIV] = imx_clk_divider2("sim2_pre_div", "sim2_cg", base + 0xb880, 16, 3);
-       clks[IMX7D_GPT1_ROOT_PRE_DIV] = imx_clk_divider2("gpt1_pre_div", "gpt1_cg", base + 0xb900, 16, 3);
-       clks[IMX7D_GPT2_ROOT_PRE_DIV] = imx_clk_divider2("gpt2_pre_div", "gpt2_cg", base + 0xb980, 16, 3);
-       clks[IMX7D_GPT3_ROOT_PRE_DIV] = imx_clk_divider2("gpt3_pre_div", "gpt3_cg", base + 0xba00, 16, 3);
-       clks[IMX7D_GPT4_ROOT_PRE_DIV] = imx_clk_divider2("gpt4_pre_div", "gpt4_cg", base + 0xba80, 16, 3);
-       clks[IMX7D_TRACE_ROOT_PRE_DIV] = imx_clk_divider2("trace_pre_div", "trace_cg", base + 0xbb00, 16, 3);
-       clks[IMX7D_WDOG_ROOT_PRE_DIV] = imx_clk_divider2("wdog_pre_div", "wdog_cg", base + 0xbb80, 16, 3);
-       clks[IMX7D_CSI_MCLK_ROOT_PRE_DIV] = imx_clk_divider2("csi_mclk_pre_div", "csi_mclk_cg", base + 0xbc00, 16, 3);
-       clks[IMX7D_AUDIO_MCLK_ROOT_PRE_DIV] = imx_clk_divider2("audio_mclk_pre_div", "audio_mclk_cg", base + 0xbc80, 16, 3);
-       clks[IMX7D_WRCLK_ROOT_PRE_DIV] = imx_clk_divider2("wrclk_pre_div", "wrclk_cg", base + 0xbd00, 16, 3);
-       clks[IMX7D_CLKO1_ROOT_PRE_DIV] = imx_clk_divider2("clko1_pre_div", "clko1_cg", base + 0xbd80, 16, 3);
-       clks[IMX7D_CLKO2_ROOT_PRE_DIV] = imx_clk_divider2("clko2_pre_div", "clko2_cg", base + 0xbe00, 16, 3);
-
-       clks[IMX7D_ARM_A7_ROOT_DIV] = imx_clk_divider2("arm_a7_div", "arm_a7_cg", base + 0x8000, 0, 3);
-       clks[IMX7D_ARM_M4_ROOT_DIV] = imx_clk_divider2("arm_m4_div", "arm_m4_cg", base + 0x8080, 0, 3);
-       clks[IMX7D_MAIN_AXI_ROOT_DIV] = imx_clk_divider2("axi_post_div", "axi_pre_div", base + 0x8800, 0, 6);
-       clks[IMX7D_DISP_AXI_ROOT_DIV] = imx_clk_divider2("disp_axi_post_div", "disp_axi_pre_div", base + 0x8880, 0, 6);
-       clks[IMX7D_ENET_AXI_ROOT_DIV] = imx_clk_divider2("enet_axi_post_div", "enet_axi_pre_div", base + 0x8900, 0, 6);
-       clks[IMX7D_NAND_USDHC_BUS_ROOT_CLK] = imx_clk_divider2("nand_usdhc_root_clk", "nand_usdhc_pre_div", base + 0x8980, 0, 6);
-       clks[IMX7D_AHB_CHANNEL_ROOT_DIV] = imx_clk_divider2("ahb_root_clk", "ahb_pre_div", base + 0x9000, 0, 6);
-       clks[IMX7D_IPG_ROOT_CLK] = imx_clk_divider_flags("ipg_root_clk", "ahb_root_clk", base + 0x9080, 0, 2, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE | CLK_SET_RATE_PARENT);
-       clks[IMX7D_DRAM_ROOT_DIV] = imx_clk_divider2("dram_post_div", "dram_cg", base + 0x9880, 0, 3);
-       clks[IMX7D_DRAM_PHYM_ALT_ROOT_DIV] = imx_clk_divider2("dram_phym_alt_post_div", "dram_phym_alt_pre_div", base + 0xa000, 0, 3);
-       clks[IMX7D_DRAM_ALT_ROOT_DIV] = imx_clk_divider2("dram_alt_post_div", "dram_alt_pre_div", base + 0xa080, 0, 3);
-       clks[IMX7D_USB_HSIC_ROOT_DIV] = imx_clk_divider2("usb_hsic_post_div", "usb_hsic_pre_div", base + 0xa100, 0, 6);
-       clks[IMX7D_PCIE_CTRL_ROOT_DIV] = imx_clk_divider2("pcie_ctrl_post_div", "pcie_ctrl_pre_div", base + 0xa180, 0, 6);
-       clks[IMX7D_PCIE_PHY_ROOT_DIV] = imx_clk_divider2("pcie_phy_post_div", "pcie_phy_pre_div", base + 0xa200, 0, 6);
-       clks[IMX7D_EPDC_PIXEL_ROOT_DIV] = imx_clk_divider2("epdc_pixel_post_div", "epdc_pixel_pre_div", base + 0xa280, 0, 6);
-       clks[IMX7D_LCDIF_PIXEL_ROOT_DIV] = imx_clk_divider2("lcdif_pixel_post_div", "lcdif_pixel_pre_div", base + 0xa300, 0, 6);
-       clks[IMX7D_MIPI_DSI_ROOT_DIV] = imx_clk_divider2("mipi_dsi_post_div", "mipi_dsi_pre_div", base + 0xa380, 0, 6);
-       clks[IMX7D_MIPI_CSI_ROOT_DIV] = imx_clk_divider2("mipi_csi_post_div", "mipi_csi_pre_div", base + 0xa400, 0, 6);
-       clks[IMX7D_MIPI_DPHY_ROOT_DIV] = imx_clk_divider2("mipi_dphy_post_div", "mipi_dphy_pre_div", base + 0xa480, 0, 6);
-       clks[IMX7D_SAI1_ROOT_DIV] = imx_clk_divider2("sai1_post_div", "sai1_pre_div", base + 0xa500, 0, 6);
-       clks[IMX7D_SAI2_ROOT_DIV] = imx_clk_divider2("sai2_post_div", "sai2_pre_div", base + 0xa580, 0, 6);
-       clks[IMX7D_SAI3_ROOT_DIV] = imx_clk_divider2("sai3_post_div", "sai3_pre_div", base + 0xa600, 0, 6);
-       clks[IMX7D_SPDIF_ROOT_DIV] = imx_clk_divider2("spdif_post_div", "spdif_pre_div", base + 0xa680, 0, 6);
-       clks[IMX7D_ENET1_REF_ROOT_DIV] = imx_clk_divider2("enet1_ref_post_div", "enet1_ref_pre_div", base + 0xa700, 0, 6);
-       clks[IMX7D_ENET1_TIME_ROOT_DIV] = imx_clk_divider2("enet1_time_post_div", "enet1_time_pre_div", base + 0xa780, 0, 6);
-       clks[IMX7D_ENET2_REF_ROOT_DIV] = imx_clk_divider2("enet2_ref_post_div", "enet2_ref_pre_div", base + 0xa800, 0, 6);
-       clks[IMX7D_ENET2_TIME_ROOT_DIV] = imx_clk_divider2("enet2_time_post_div", "enet2_time_pre_div", base + 0xa880, 0, 6);
-       clks[IMX7D_ENET_PHY_REF_ROOT_CLK] = imx_clk_divider2("enet_phy_ref_root_clk", "enet_phy_ref_pre_div", base + 0xa900, 0, 6);
-       clks[IMX7D_EIM_ROOT_DIV] = imx_clk_divider2("eim_post_div", "eim_pre_div", base + 0xa980, 0, 6);
-       clks[IMX7D_NAND_ROOT_CLK] = imx_clk_divider2("nand_root_clk", "nand_pre_div", base + 0xaa00, 0, 6);
-       clks[IMX7D_QSPI_ROOT_DIV] = imx_clk_divider2("qspi_post_div", "qspi_pre_div", base + 0xaa80, 0, 6);
-       clks[IMX7D_USDHC1_ROOT_DIV] = imx_clk_divider2("usdhc1_post_div", "usdhc1_pre_div", base + 0xab00, 0, 6);
-       clks[IMX7D_USDHC2_ROOT_DIV] = imx_clk_divider2("usdhc2_post_div", "usdhc2_pre_div", base + 0xab80, 0, 6);
-       clks[IMX7D_USDHC3_ROOT_DIV] = imx_clk_divider2("usdhc3_post_div", "usdhc3_pre_div", base + 0xac00, 0, 6);
-       clks[IMX7D_CAN1_ROOT_DIV] = imx_clk_divider2("can1_post_div", "can1_pre_div", base + 0xac80, 0, 6);
-       clks[IMX7D_CAN2_ROOT_DIV] = imx_clk_divider2("can2_post_div", "can2_pre_div", base + 0xad00, 0, 6);
-       clks[IMX7D_I2C1_ROOT_DIV] = imx_clk_divider2("i2c1_post_div", "i2c1_pre_div", base + 0xad80, 0, 6);
-       clks[IMX7D_I2C2_ROOT_DIV] = imx_clk_divider2("i2c2_post_div", "i2c2_pre_div", base + 0xae00, 0, 6);
-       clks[IMX7D_I2C3_ROOT_DIV] = imx_clk_divider2("i2c3_post_div", "i2c3_pre_div", base + 0xae80, 0, 6);
-       clks[IMX7D_I2C4_ROOT_DIV] = imx_clk_divider2("i2c4_post_div", "i2c4_pre_div", base + 0xaf00, 0, 6);
-       clks[IMX7D_UART1_ROOT_DIV] = imx_clk_divider2("uart1_post_div", "uart1_pre_div", base + 0xaf80, 0, 6);
-       clks[IMX7D_UART2_ROOT_DIV] = imx_clk_divider2("uart2_post_div", "uart2_pre_div", base + 0xb000, 0, 6);
-       clks[IMX7D_UART3_ROOT_DIV] = imx_clk_divider2("uart3_post_div", "uart3_pre_div", base + 0xb080, 0, 6);
-       clks[IMX7D_UART4_ROOT_DIV] = imx_clk_divider2("uart4_post_div", "uart4_pre_div", base + 0xb100, 0, 6);
-       clks[IMX7D_UART5_ROOT_DIV] = imx_clk_divider2("uart5_post_div", "uart5_pre_div", base + 0xb180, 0, 6);
-       clks[IMX7D_UART6_ROOT_DIV] = imx_clk_divider2("uart6_post_div", "uart6_pre_div", base + 0xb200, 0, 6);
-       clks[IMX7D_UART7_ROOT_DIV] = imx_clk_divider2("uart7_post_div", "uart7_pre_div", base + 0xb280, 0, 6);
-       clks[IMX7D_ECSPI1_ROOT_DIV] = imx_clk_divider2("ecspi1_post_div", "ecspi1_pre_div", base + 0xb300, 0, 6);
-       clks[IMX7D_ECSPI2_ROOT_DIV] = imx_clk_divider2("ecspi2_post_div", "ecspi2_pre_div", base + 0xb380, 0, 6);
-       clks[IMX7D_ECSPI3_ROOT_DIV] = imx_clk_divider2("ecspi3_post_div", "ecspi3_pre_div", base + 0xb400, 0, 6);
-       clks[IMX7D_ECSPI4_ROOT_DIV] = imx_clk_divider2("ecspi4_post_div", "ecspi4_pre_div", base + 0xb480, 0, 6);
-       clks[IMX7D_PWM1_ROOT_DIV] = imx_clk_divider2("pwm1_post_div", "pwm1_pre_div", base + 0xb500, 0, 6);
-       clks[IMX7D_PWM2_ROOT_DIV] = imx_clk_divider2("pwm2_post_div", "pwm2_pre_div", base + 0xb580, 0, 6);
-       clks[IMX7D_PWM3_ROOT_DIV] = imx_clk_divider2("pwm3_post_div", "pwm3_pre_div", base + 0xb600, 0, 6);
-       clks[IMX7D_PWM4_ROOT_DIV] = imx_clk_divider2("pwm4_post_div", "pwm4_pre_div", base + 0xb680, 0, 6);
-       clks[IMX7D_FLEXTIMER1_ROOT_DIV] = imx_clk_divider2("flextimer1_post_div", "flextimer1_pre_div", base + 0xb700, 0, 6);
-       clks[IMX7D_FLEXTIMER2_ROOT_DIV] = imx_clk_divider2("flextimer2_post_div", "flextimer2_pre_div", base + 0xb780, 0, 6);
-       clks[IMX7D_SIM1_ROOT_DIV] = imx_clk_divider2("sim1_post_div", "sim1_pre_div", base + 0xb800, 0, 6);
-       clks[IMX7D_SIM2_ROOT_DIV] = imx_clk_divider2("sim2_post_div", "sim2_pre_div", base + 0xb880, 0, 6);
-       clks[IMX7D_GPT1_ROOT_DIV] = imx_clk_divider2("gpt1_post_div", "gpt1_pre_div", base + 0xb900, 0, 6);
-       clks[IMX7D_GPT2_ROOT_DIV] = imx_clk_divider2("gpt2_post_div", "gpt2_pre_div", base + 0xb980, 0, 6);
-       clks[IMX7D_GPT3_ROOT_DIV] = imx_clk_divider2("gpt3_post_div", "gpt3_pre_div", base + 0xba00, 0, 6);
-       clks[IMX7D_GPT4_ROOT_DIV] = imx_clk_divider2("gpt4_post_div", "gpt4_pre_div", base + 0xba80, 0, 6);
-       clks[IMX7D_TRACE_ROOT_DIV] = imx_clk_divider2("trace_post_div", "trace_pre_div", base + 0xbb00, 0, 6);
-       clks[IMX7D_WDOG_ROOT_DIV] = imx_clk_divider2("wdog_post_div", "wdog_pre_div", base + 0xbb80, 0, 6);
-       clks[IMX7D_CSI_MCLK_ROOT_DIV] = imx_clk_divider2("csi_mclk_post_div", "csi_mclk_pre_div", base + 0xbc00, 0, 6);
-       clks[IMX7D_AUDIO_MCLK_ROOT_DIV] = imx_clk_divider2("audio_mclk_post_div", "audio_mclk_pre_div", base + 0xbc80, 0, 6);
-       clks[IMX7D_WRCLK_ROOT_DIV] = imx_clk_divider2("wrclk_post_div", "wrclk_pre_div", base + 0xbd00, 0, 6);
-       clks[IMX7D_CLKO1_ROOT_DIV] = imx_clk_divider2("clko1_post_div", "clko1_pre_div", base + 0xbd80, 0, 6);
-       clks[IMX7D_CLKO2_ROOT_DIV] = imx_clk_divider2("clko2_post_div", "clko2_pre_div", base + 0xbe00, 0, 6);
-
-       clks[IMX7D_ARM_A7_ROOT_CLK] = imx_clk_gate2_flags("arm_a7_root_clk", "arm_a7_div", base + 0x4000, 0, CLK_OPS_PARENT_ENABLE);
-       clks[IMX7D_ARM_M4_ROOT_CLK] = imx_clk_gate4("arm_m4_root_clk", "arm_m4_div", base + 0x4010, 0);
-       clks[IMX7D_MAIN_AXI_ROOT_CLK] = imx_clk_gate2_flags("main_axi_root_clk", "axi_post_div", base + 0x4040, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
-       clks[IMX7D_DISP_AXI_ROOT_CLK] = imx_clk_gate4("disp_axi_root_clk", "disp_axi_post_div", base + 0x4050, 0);
-       clks[IMX7D_ENET_AXI_ROOT_CLK] = imx_clk_gate4("enet_axi_root_clk", "enet_axi_post_div", base + 0x4060, 0);
-       clks[IMX7D_OCRAM_CLK] = imx_clk_gate4("ocram_clk", "main_axi_root_clk", base + 0x4110, 0);
-       clks[IMX7D_OCRAM_S_CLK] = imx_clk_gate4("ocram_s_clk", "ahb_root_clk", base + 0x4120, 0);
-       clks[IMX7D_DRAM_ROOT_CLK] = imx_clk_gate2_flags("dram_root_clk", "dram_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
-       clks[IMX7D_DRAM_PHYM_ROOT_CLK] = imx_clk_gate2_flags("dram_phym_root_clk", "dram_phym_cg", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
-       clks[IMX7D_DRAM_PHYM_ALT_ROOT_CLK] = imx_clk_gate2_flags("dram_phym_alt_root_clk", "dram_phym_alt_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
-       clks[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_gate2_flags("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
-       clks[IMX7D_OCOTP_CLK] = imx_clk_gate4("ocotp_clk", "ipg_root_clk", base + 0x4230, 0);
-       clks[IMX7D_SNVS_CLK] = imx_clk_gate4("snvs_clk", "ipg_root_clk", base + 0x4250, 0);
-       clks[IMX7D_MU_ROOT_CLK] = imx_clk_gate4("mu_root_clk", "ipg_root_clk", base + 0x4270, 0);
-       clks[IMX7D_CAAM_CLK] = imx_clk_gate4("caam_clk", "ipg_root_clk", base + 0x4240, 0);
-       clks[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4690, 0);
-       clks[IMX7D_SDMA_CORE_CLK] = imx_clk_gate4("sdma_root_clk", "ahb_root_clk", base + 0x4480, 0);
-       clks[IMX7D_PCIE_CTRL_ROOT_CLK] = imx_clk_gate4("pcie_ctrl_root_clk", "pcie_ctrl_post_div", base + 0x4600, 0);
-       clks[IMX7D_PCIE_PHY_ROOT_CLK] = imx_clk_gate4("pcie_phy_root_clk", "pcie_phy_post_div", base + 0x4600, 0);
-       clks[IMX7D_EPDC_PIXEL_ROOT_CLK] = imx_clk_gate4("epdc_pixel_root_clk", "epdc_pixel_post_div", base + 0x44a0, 0);
-       clks[IMX7D_LCDIF_PIXEL_ROOT_CLK] = imx_clk_gate4("lcdif_pixel_root_clk", "lcdif_pixel_post_div", base + 0x44b0, 0);
-       clks[IMX7D_MIPI_DSI_ROOT_CLK] = imx_clk_gate4("mipi_dsi_root_clk", "mipi_dsi_post_div", base + 0x4650, 0);
-       clks[IMX7D_MIPI_CSI_ROOT_CLK] = imx_clk_gate4("mipi_csi_root_clk", "mipi_csi_post_div", base + 0x4640, 0);
-       clks[IMX7D_MIPI_DPHY_ROOT_CLK] = imx_clk_gate4("mipi_dphy_root_clk", "mipi_dphy_post_div", base + 0x4660, 0);
-       clks[IMX7D_ENET1_IPG_ROOT_CLK] = imx_clk_gate2_shared2("enet1_ipg_root_clk", "enet_axi_post_div", base + 0x4700, 0, &share_count_enet1);
-       clks[IMX7D_ENET1_TIME_ROOT_CLK] = imx_clk_gate2_shared2("enet1_time_root_clk", "enet1_time_post_div", base + 0x4700, 0, &share_count_enet1);
-       clks[IMX7D_ENET2_IPG_ROOT_CLK] = imx_clk_gate2_shared2("enet2_ipg_root_clk", "enet_axi_post_div", base + 0x4710, 0, &share_count_enet2);
-       clks[IMX7D_ENET2_TIME_ROOT_CLK] = imx_clk_gate2_shared2("enet2_time_root_clk", "enet2_time_post_div", base + 0x4710, 0, &share_count_enet2);
-       clks[IMX7D_SAI1_ROOT_CLK] = imx_clk_gate2_shared2("sai1_root_clk", "sai1_post_div", base + 0x48c0, 0, &share_count_sai1);
-       clks[IMX7D_SAI1_IPG_CLK]  = imx_clk_gate2_shared2("sai1_ipg_clk",  "ipg_root_clk",  base + 0x48c0, 0, &share_count_sai1);
-       clks[IMX7D_SAI2_ROOT_CLK] = imx_clk_gate2_shared2("sai2_root_clk", "sai2_post_div", base + 0x48d0, 0, &share_count_sai2);
-       clks[IMX7D_SAI2_IPG_CLK]  = imx_clk_gate2_shared2("sai2_ipg_clk",  "ipg_root_clk",  base + 0x48d0, 0, &share_count_sai2);
-       clks[IMX7D_SAI3_ROOT_CLK] = imx_clk_gate2_shared2("sai3_root_clk", "sai3_post_div", base + 0x48e0, 0, &share_count_sai3);
-       clks[IMX7D_SAI3_IPG_CLK]  = imx_clk_gate2_shared2("sai3_ipg_clk",  "ipg_root_clk",  base + 0x48e0, 0, &share_count_sai3);
-       clks[IMX7D_SPDIF_ROOT_CLK] = imx_clk_gate4("spdif_root_clk", "spdif_post_div", base + 0x44d0, 0);
-       clks[IMX7D_EIM_ROOT_CLK] = imx_clk_gate4("eim_root_clk", "eim_post_div", base + 0x4160, 0);
-       clks[IMX7D_NAND_RAWNAND_CLK] = imx_clk_gate2_shared2("nand_rawnand_clk", "nand_root_clk", base + 0x4140, 0, &share_count_nand);
-       clks[IMX7D_NAND_USDHC_BUS_RAWNAND_CLK] = imx_clk_gate2_shared2("nand_usdhc_rawnand_clk", "nand_usdhc_root_clk", base + 0x4140, 0, &share_count_nand);
-       clks[IMX7D_QSPI_ROOT_CLK] = imx_clk_gate4("qspi_root_clk", "qspi_post_div", base + 0x4150, 0);
-       clks[IMX7D_USDHC1_ROOT_CLK] = imx_clk_gate4("usdhc1_root_clk", "usdhc1_post_div", base + 0x46c0, 0);
-       clks[IMX7D_USDHC2_ROOT_CLK] = imx_clk_gate4("usdhc2_root_clk", "usdhc2_post_div", base + 0x46d0, 0);
-       clks[IMX7D_USDHC3_ROOT_CLK] = imx_clk_gate4("usdhc3_root_clk", "usdhc3_post_div", base + 0x46e0, 0);
-       clks[IMX7D_CAN1_ROOT_CLK] = imx_clk_gate4("can1_root_clk", "can1_post_div", base + 0x4740, 0);
-       clks[IMX7D_CAN2_ROOT_CLK] = imx_clk_gate4("can2_root_clk", "can2_post_div", base + 0x4750, 0);
-       clks[IMX7D_I2C1_ROOT_CLK] = imx_clk_gate4("i2c1_root_clk", "i2c1_post_div", base + 0x4880, 0);
-       clks[IMX7D_I2C2_ROOT_CLK] = imx_clk_gate4("i2c2_root_clk", "i2c2_post_div", base + 0x4890, 0);
-       clks[IMX7D_I2C3_ROOT_CLK] = imx_clk_gate4("i2c3_root_clk", "i2c3_post_div", base + 0x48a0, 0);
-       clks[IMX7D_I2C4_ROOT_CLK] = imx_clk_gate4("i2c4_root_clk", "i2c4_post_div", base + 0x48b0, 0);
-       clks[IMX7D_UART1_ROOT_CLK] = imx_clk_gate4("uart1_root_clk", "uart1_post_div", base + 0x4940, 0);
-       clks[IMX7D_UART2_ROOT_CLK] = imx_clk_gate4("uart2_root_clk", "uart2_post_div", base + 0x4950, 0);
-       clks[IMX7D_UART3_ROOT_CLK] = imx_clk_gate4("uart3_root_clk", "uart3_post_div", base + 0x4960, 0);
-       clks[IMX7D_UART4_ROOT_CLK] = imx_clk_gate4("uart4_root_clk", "uart4_post_div", base + 0x4970, 0);
-       clks[IMX7D_UART5_ROOT_CLK] = imx_clk_gate4("uart5_root_clk", "uart5_post_div", base + 0x4980, 0);
-       clks[IMX7D_UART6_ROOT_CLK] = imx_clk_gate4("uart6_root_clk", "uart6_post_div", base + 0x4990, 0);
-       clks[IMX7D_UART7_ROOT_CLK] = imx_clk_gate4("uart7_root_clk", "uart7_post_div", base + 0x49a0, 0);
-       clks[IMX7D_ECSPI1_ROOT_CLK] = imx_clk_gate4("ecspi1_root_clk", "ecspi1_post_div", base + 0x4780, 0);
-       clks[IMX7D_ECSPI2_ROOT_CLK] = imx_clk_gate4("ecspi2_root_clk", "ecspi2_post_div", base + 0x4790, 0);
-       clks[IMX7D_ECSPI3_ROOT_CLK] = imx_clk_gate4("ecspi3_root_clk", "ecspi3_post_div", base + 0x47a0, 0);
-       clks[IMX7D_ECSPI4_ROOT_CLK] = imx_clk_gate4("ecspi4_root_clk", "ecspi4_post_div", base + 0x47b0, 0);
-       clks[IMX7D_PWM1_ROOT_CLK] = imx_clk_gate4("pwm1_root_clk", "pwm1_post_div", base + 0x4840, 0);
-       clks[IMX7D_PWM2_ROOT_CLK] = imx_clk_gate4("pwm2_root_clk", "pwm2_post_div", base + 0x4850, 0);
-       clks[IMX7D_PWM3_ROOT_CLK] = imx_clk_gate4("pwm3_root_clk", "pwm3_post_div", base + 0x4860, 0);
-       clks[IMX7D_PWM4_ROOT_CLK] = imx_clk_gate4("pwm4_root_clk", "pwm4_post_div", base + 0x4870, 0);
-       clks[IMX7D_FLEXTIMER1_ROOT_CLK] = imx_clk_gate4("flextimer1_root_clk", "flextimer1_post_div", base + 0x4800, 0);
-       clks[IMX7D_FLEXTIMER2_ROOT_CLK] = imx_clk_gate4("flextimer2_root_clk", "flextimer2_post_div", base + 0x4810, 0);
-       clks[IMX7D_SIM1_ROOT_CLK] = imx_clk_gate4("sim1_root_clk", "sim1_post_div", base + 0x4900, 0);
-       clks[IMX7D_SIM2_ROOT_CLK] = imx_clk_gate4("sim2_root_clk", "sim2_post_div", base + 0x4910, 0);
-       clks[IMX7D_GPT1_ROOT_CLK] = imx_clk_gate4("gpt1_root_clk", "gpt1_post_div", base + 0x47c0, 0);
-       clks[IMX7D_GPT2_ROOT_CLK] = imx_clk_gate4("gpt2_root_clk", "gpt2_post_div", base + 0x47d0, 0);
-       clks[IMX7D_GPT3_ROOT_CLK] = imx_clk_gate4("gpt3_root_clk", "gpt3_post_div", base + 0x47e0, 0);
-       clks[IMX7D_GPT4_ROOT_CLK] = imx_clk_gate4("gpt4_root_clk", "gpt4_post_div", base + 0x47f0, 0);
-       clks[IMX7D_TRACE_ROOT_CLK] = imx_clk_gate4("trace_root_clk", "trace_post_div", base + 0x4300, 0);
-       clks[IMX7D_WDOG1_ROOT_CLK] = imx_clk_gate4("wdog1_root_clk", "wdog_post_div", base + 0x49c0, 0);
-       clks[IMX7D_WDOG2_ROOT_CLK] = imx_clk_gate4("wdog2_root_clk", "wdog_post_div", base + 0x49d0, 0);
-       clks[IMX7D_WDOG3_ROOT_CLK] = imx_clk_gate4("wdog3_root_clk", "wdog_post_div", base + 0x49e0, 0);
-       clks[IMX7D_WDOG4_ROOT_CLK] = imx_clk_gate4("wdog4_root_clk", "wdog_post_div", base + 0x49f0, 0);
-       clks[IMX7D_KPP_ROOT_CLK] = imx_clk_gate4("kpp_root_clk", "ipg_root_clk", base + 0x4aa0, 0);
-       clks[IMX7D_CSI_MCLK_ROOT_CLK] = imx_clk_gate4("csi_mclk_root_clk", "csi_mclk_post_div", base + 0x4490, 0);
-       clks[IMX7D_AUDIO_MCLK_ROOT_CLK] = imx_clk_gate4("audio_mclk_root_clk", "audio_mclk_post_div", base + 0x4790, 0);
-       clks[IMX7D_WRCLK_ROOT_CLK] = imx_clk_gate4("wrclk_root_clk", "wrclk_post_div", base + 0x47a0, 0);
-       clks[IMX7D_USB_CTRL_CLK] = imx_clk_gate4("usb_ctrl_clk", "ahb_root_clk", base + 0x4680, 0);
-       clks[IMX7D_USB_PHY1_CLK] = imx_clk_gate4("usb_phy1_clk", "pll_usb1_main_clk", base + 0x46a0, 0);
-       clks[IMX7D_USB_PHY2_CLK] = imx_clk_gate4("usb_phy2_clk", "pll_usb_main_clk", base + 0x46b0, 0);
-       clks[IMX7D_ADC_ROOT_CLK] = imx_clk_gate4("adc_root_clk", "ipg_root_clk", base + 0x4200, 0);
-
-       clks[IMX7D_GPT_3M_CLK] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8);
-
-       clks[IMX7D_CLK_ARM] = imx_clk_cpu("arm", "arm_a7_root_clk",
-                                        clks[IMX7D_ARM_A7_ROOT_CLK],
-                                        clks[IMX7D_ARM_A7_ROOT_SRC],
-                                        clks[IMX7D_PLL_ARM_MAIN_CLK],
-                                        clks[IMX7D_PLL_SYS_MAIN_CLK]);
-
-       imx_check_clocks(clks, ARRAY_SIZE(clks));
-
-       clk_data.clks = clks;
-       clk_data.clk_num = ARRAY_SIZE(clks);
-       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
-
-       clk_set_parent(clks[IMX7D_PLL_ARM_MAIN_BYPASS], clks[IMX7D_PLL_ARM_MAIN]);
-       clk_set_parent(clks[IMX7D_PLL_DRAM_MAIN_BYPASS], clks[IMX7D_PLL_DRAM_MAIN]);
-       clk_set_parent(clks[IMX7D_PLL_SYS_MAIN_BYPASS], clks[IMX7D_PLL_SYS_MAIN]);
-       clk_set_parent(clks[IMX7D_PLL_ENET_MAIN_BYPASS], clks[IMX7D_PLL_ENET_MAIN]);
-       clk_set_parent(clks[IMX7D_PLL_AUDIO_MAIN_BYPASS], clks[IMX7D_PLL_AUDIO_MAIN]);
-       clk_set_parent(clks[IMX7D_PLL_VIDEO_MAIN_BYPASS], clks[IMX7D_PLL_VIDEO_MAIN]);
-
-       clk_set_parent(clks[IMX7D_MIPI_CSI_ROOT_SRC], clks[IMX7D_PLL_SYS_PFD3_CLK]);
+       hws[IMX7D_ARM_A7_ROOT_SRC] = imx_clk_hw_mux2("arm_a7_src", base + 0x8000, 24, 3, arm_a7_sel, ARRAY_SIZE(arm_a7_sel));
+       hws[IMX7D_ARM_M4_ROOT_SRC] = imx_clk_hw_mux2("arm_m4_src", base + 0x8080, 24, 3, arm_m4_sel, ARRAY_SIZE(arm_m4_sel));
+       hws[IMX7D_MAIN_AXI_ROOT_SRC] = imx_clk_hw_mux2("axi_src", base + 0x8800, 24, 3, axi_sel, ARRAY_SIZE(axi_sel));
+       hws[IMX7D_DISP_AXI_ROOT_SRC] = imx_clk_hw_mux2("disp_axi_src", base + 0x8880, 24, 3, disp_axi_sel, ARRAY_SIZE(disp_axi_sel));
+       hws[IMX7D_ENET_AXI_ROOT_SRC] = imx_clk_hw_mux2("enet_axi_src", base + 0x8900, 24, 3, enet_axi_sel, ARRAY_SIZE(enet_axi_sel));
+       hws[IMX7D_NAND_USDHC_BUS_ROOT_SRC] = imx_clk_hw_mux2("nand_usdhc_src", base + 0x8980, 24, 3, nand_usdhc_bus_sel, ARRAY_SIZE(nand_usdhc_bus_sel));
+       hws[IMX7D_AHB_CHANNEL_ROOT_SRC] = imx_clk_hw_mux2("ahb_src", base + 0x9000, 24, 3, ahb_channel_sel, ARRAY_SIZE(ahb_channel_sel));
+       hws[IMX7D_DRAM_PHYM_ROOT_SRC] = imx_clk_hw_mux2("dram_phym_src", base + 0x9800, 24, 1, dram_phym_sel, ARRAY_SIZE(dram_phym_sel));
+       hws[IMX7D_DRAM_ROOT_SRC] = imx_clk_hw_mux2("dram_src", base + 0x9880, 24, 1, dram_sel, ARRAY_SIZE(dram_sel));
+       hws[IMX7D_DRAM_PHYM_ALT_ROOT_SRC] = imx_clk_hw_mux2("dram_phym_alt_src", base + 0xa000, 24, 3, dram_phym_alt_sel, ARRAY_SIZE(dram_phym_alt_sel));
+       hws[IMX7D_DRAM_ALT_ROOT_SRC]  = imx_clk_hw_mux2("dram_alt_src", base + 0xa080, 24, 3, dram_alt_sel, ARRAY_SIZE(dram_alt_sel));
+       hws[IMX7D_USB_HSIC_ROOT_SRC] = imx_clk_hw_mux2("usb_hsic_src", base + 0xa100, 24, 3, usb_hsic_sel, ARRAY_SIZE(usb_hsic_sel));
+       hws[IMX7D_PCIE_CTRL_ROOT_SRC] = imx_clk_hw_mux2("pcie_ctrl_src", base + 0xa180, 24, 3, pcie_ctrl_sel, ARRAY_SIZE(pcie_ctrl_sel));
+       hws[IMX7D_PCIE_PHY_ROOT_SRC] = imx_clk_hw_mux2("pcie_phy_src", base + 0xa200, 24, 3, pcie_phy_sel, ARRAY_SIZE(pcie_phy_sel));
+       hws[IMX7D_EPDC_PIXEL_ROOT_SRC] = imx_clk_hw_mux2("epdc_pixel_src", base + 0xa280, 24, 3, epdc_pixel_sel, ARRAY_SIZE(epdc_pixel_sel));
+       hws[IMX7D_LCDIF_PIXEL_ROOT_SRC] = imx_clk_hw_mux2("lcdif_pixel_src", base + 0xa300, 24, 3, lcdif_pixel_sel, ARRAY_SIZE(lcdif_pixel_sel));
+       hws[IMX7D_MIPI_DSI_ROOT_SRC] = imx_clk_hw_mux2("mipi_dsi_src", base + 0xa380, 24, 3,  mipi_dsi_sel, ARRAY_SIZE(mipi_dsi_sel));
+       hws[IMX7D_MIPI_CSI_ROOT_SRC] = imx_clk_hw_mux2("mipi_csi_src", base + 0xa400, 24, 3, mipi_csi_sel, ARRAY_SIZE(mipi_csi_sel));
+       hws[IMX7D_MIPI_DPHY_ROOT_SRC] = imx_clk_hw_mux2("mipi_dphy_src", base + 0xa480, 24, 3, mipi_dphy_sel, ARRAY_SIZE(mipi_dphy_sel));
+       hws[IMX7D_SAI1_ROOT_SRC] = imx_clk_hw_mux2("sai1_src", base + 0xa500, 24, 3, sai1_sel, ARRAY_SIZE(sai1_sel));
+       hws[IMX7D_SAI2_ROOT_SRC] = imx_clk_hw_mux2("sai2_src", base + 0xa580, 24, 3, sai2_sel, ARRAY_SIZE(sai2_sel));
+       hws[IMX7D_SAI3_ROOT_SRC] = imx_clk_hw_mux2("sai3_src", base + 0xa600, 24, 3, sai3_sel, ARRAY_SIZE(sai3_sel));
+       hws[IMX7D_SPDIF_ROOT_SRC] = imx_clk_hw_mux2("spdif_src", base + 0xa680, 24, 3, spdif_sel, ARRAY_SIZE(spdif_sel));
+       hws[IMX7D_ENET1_REF_ROOT_SRC] = imx_clk_hw_mux2("enet1_ref_src", base + 0xa700, 24, 3, enet1_ref_sel, ARRAY_SIZE(enet1_ref_sel));
+       hws[IMX7D_ENET1_TIME_ROOT_SRC] = imx_clk_hw_mux2("enet1_time_src", base + 0xa780, 24, 3, enet1_time_sel, ARRAY_SIZE(enet1_time_sel));
+       hws[IMX7D_ENET2_REF_ROOT_SRC] = imx_clk_hw_mux2("enet2_ref_src", base + 0xa800, 24, 3, enet2_ref_sel, ARRAY_SIZE(enet2_ref_sel));
+       hws[IMX7D_ENET2_TIME_ROOT_SRC] = imx_clk_hw_mux2("enet2_time_src", base + 0xa880, 24, 3, enet2_time_sel, ARRAY_SIZE(enet2_time_sel));
+       hws[IMX7D_ENET_PHY_REF_ROOT_SRC] = imx_clk_hw_mux2("enet_phy_ref_src", base + 0xa900, 24, 3, enet_phy_ref_sel, ARRAY_SIZE(enet_phy_ref_sel));
+       hws[IMX7D_EIM_ROOT_SRC] = imx_clk_hw_mux2("eim_src", base + 0xa980, 24, 3, eim_sel, ARRAY_SIZE(eim_sel));
+       hws[IMX7D_NAND_ROOT_SRC] = imx_clk_hw_mux2("nand_src", base + 0xaa00, 24, 3, nand_sel, ARRAY_SIZE(nand_sel));
+       hws[IMX7D_QSPI_ROOT_SRC] = imx_clk_hw_mux2("qspi_src", base + 0xaa80, 24, 3, qspi_sel, ARRAY_SIZE(qspi_sel));
+       hws[IMX7D_USDHC1_ROOT_SRC] = imx_clk_hw_mux2("usdhc1_src", base + 0xab00, 24, 3, usdhc1_sel, ARRAY_SIZE(usdhc1_sel));
+       hws[IMX7D_USDHC2_ROOT_SRC] = imx_clk_hw_mux2("usdhc2_src", base + 0xab80, 24, 3, usdhc2_sel, ARRAY_SIZE(usdhc2_sel));
+       hws[IMX7D_USDHC3_ROOT_SRC] = imx_clk_hw_mux2("usdhc3_src", base + 0xac00, 24, 3, usdhc3_sel, ARRAY_SIZE(usdhc3_sel));
+       hws[IMX7D_CAN1_ROOT_SRC] = imx_clk_hw_mux2("can1_src", base + 0xac80, 24, 3, can1_sel, ARRAY_SIZE(can1_sel));
+       hws[IMX7D_CAN2_ROOT_SRC] = imx_clk_hw_mux2("can2_src", base + 0xad00, 24, 3, can2_sel, ARRAY_SIZE(can2_sel));
+       hws[IMX7D_I2C1_ROOT_SRC] = imx_clk_hw_mux2("i2c1_src", base + 0xad80, 24, 3, i2c1_sel, ARRAY_SIZE(i2c1_sel));
+       hws[IMX7D_I2C2_ROOT_SRC] = imx_clk_hw_mux2("i2c2_src", base + 0xae00, 24, 3, i2c2_sel, ARRAY_SIZE(i2c2_sel));
+       hws[IMX7D_I2C3_ROOT_SRC] = imx_clk_hw_mux2("i2c3_src", base + 0xae80, 24, 3, i2c3_sel, ARRAY_SIZE(i2c3_sel));
+       hws[IMX7D_I2C4_ROOT_SRC] = imx_clk_hw_mux2("i2c4_src", base + 0xaf00, 24, 3, i2c4_sel, ARRAY_SIZE(i2c4_sel));
+       hws[IMX7D_UART1_ROOT_SRC] = imx_clk_hw_mux2("uart1_src", base + 0xaf80, 24, 3, uart1_sel, ARRAY_SIZE(uart1_sel));
+       hws[IMX7D_UART2_ROOT_SRC] = imx_clk_hw_mux2("uart2_src", base + 0xb000, 24, 3, uart2_sel, ARRAY_SIZE(uart2_sel));
+       hws[IMX7D_UART3_ROOT_SRC] = imx_clk_hw_mux2("uart3_src", base + 0xb080, 24, 3, uart3_sel, ARRAY_SIZE(uart3_sel));
+       hws[IMX7D_UART4_ROOT_SRC] = imx_clk_hw_mux2("uart4_src", base + 0xb100, 24, 3, uart4_sel, ARRAY_SIZE(uart4_sel));
+       hws[IMX7D_UART5_ROOT_SRC] = imx_clk_hw_mux2("uart5_src", base + 0xb180, 24, 3, uart5_sel, ARRAY_SIZE(uart5_sel));
+       hws[IMX7D_UART6_ROOT_SRC] = imx_clk_hw_mux2("uart6_src", base + 0xb200, 24, 3, uart6_sel, ARRAY_SIZE(uart6_sel));
+       hws[IMX7D_UART7_ROOT_SRC] = imx_clk_hw_mux2("uart7_src", base + 0xb280, 24, 3, uart7_sel, ARRAY_SIZE(uart7_sel));
+       hws[IMX7D_ECSPI1_ROOT_SRC] = imx_clk_hw_mux2("ecspi1_src", base + 0xb300, 24, 3, ecspi1_sel, ARRAY_SIZE(ecspi1_sel));
+       hws[IMX7D_ECSPI2_ROOT_SRC] = imx_clk_hw_mux2("ecspi2_src", base + 0xb380, 24, 3, ecspi2_sel, ARRAY_SIZE(ecspi2_sel));
+       hws[IMX7D_ECSPI3_ROOT_SRC] = imx_clk_hw_mux2("ecspi3_src", base + 0xb400, 24, 3, ecspi3_sel, ARRAY_SIZE(ecspi3_sel));
+       hws[IMX7D_ECSPI4_ROOT_SRC] = imx_clk_hw_mux2("ecspi4_src", base + 0xb480, 24, 3, ecspi4_sel, ARRAY_SIZE(ecspi4_sel));
+       hws[IMX7D_PWM1_ROOT_SRC] = imx_clk_hw_mux2("pwm1_src", base + 0xb500, 24, 3, pwm1_sel, ARRAY_SIZE(pwm1_sel));
+       hws[IMX7D_PWM2_ROOT_SRC] = imx_clk_hw_mux2("pwm2_src", base + 0xb580, 24, 3, pwm2_sel, ARRAY_SIZE(pwm2_sel));
+       hws[IMX7D_PWM3_ROOT_SRC] = imx_clk_hw_mux2("pwm3_src", base + 0xb600, 24, 3, pwm3_sel, ARRAY_SIZE(pwm3_sel));
+       hws[IMX7D_PWM4_ROOT_SRC] = imx_clk_hw_mux2("pwm4_src", base + 0xb680, 24, 3, pwm4_sel, ARRAY_SIZE(pwm4_sel));
+       hws[IMX7D_FLEXTIMER1_ROOT_SRC] = imx_clk_hw_mux2("flextimer1_src", base + 0xb700, 24, 3, flextimer1_sel, ARRAY_SIZE(flextimer1_sel));
+       hws[IMX7D_FLEXTIMER2_ROOT_SRC] = imx_clk_hw_mux2("flextimer2_src", base + 0xb780, 24, 3, flextimer2_sel, ARRAY_SIZE(flextimer2_sel));
+       hws[IMX7D_SIM1_ROOT_SRC] = imx_clk_hw_mux2("sim1_src", base + 0xb800, 24, 3, sim1_sel, ARRAY_SIZE(sim1_sel));
+       hws[IMX7D_SIM2_ROOT_SRC] = imx_clk_hw_mux2("sim2_src", base + 0xb880, 24, 3, sim2_sel, ARRAY_SIZE(sim2_sel));
+       hws[IMX7D_GPT1_ROOT_SRC] = imx_clk_hw_mux2("gpt1_src", base + 0xb900, 24, 3, gpt1_sel, ARRAY_SIZE(gpt1_sel));
+       hws[IMX7D_GPT2_ROOT_SRC] = imx_clk_hw_mux2("gpt2_src", base + 0xb980, 24, 3, gpt2_sel, ARRAY_SIZE(gpt2_sel));
+       hws[IMX7D_GPT3_ROOT_SRC] = imx_clk_hw_mux2("gpt3_src", base + 0xba00, 24, 3, gpt3_sel, ARRAY_SIZE(gpt3_sel));
+       hws[IMX7D_GPT4_ROOT_SRC] = imx_clk_hw_mux2("gpt4_src", base + 0xba80, 24, 3, gpt4_sel, ARRAY_SIZE(gpt4_sel));
+       hws[IMX7D_TRACE_ROOT_SRC] = imx_clk_hw_mux2("trace_src", base + 0xbb00, 24, 3, trace_sel, ARRAY_SIZE(trace_sel));
+       hws[IMX7D_WDOG_ROOT_SRC] = imx_clk_hw_mux2("wdog_src", base + 0xbb80, 24, 3, wdog_sel, ARRAY_SIZE(wdog_sel));
+       hws[IMX7D_CSI_MCLK_ROOT_SRC] = imx_clk_hw_mux2("csi_mclk_src", base + 0xbc00, 24, 3, csi_mclk_sel, ARRAY_SIZE(csi_mclk_sel));
+       hws[IMX7D_AUDIO_MCLK_ROOT_SRC] = imx_clk_hw_mux2("audio_mclk_src", base + 0xbc80, 24, 3, audio_mclk_sel, ARRAY_SIZE(audio_mclk_sel));
+       hws[IMX7D_WRCLK_ROOT_SRC] = imx_clk_hw_mux2("wrclk_src", base + 0xbd00, 24, 3, wrclk_sel, ARRAY_SIZE(wrclk_sel));
+       hws[IMX7D_CLKO1_ROOT_SRC] = imx_clk_hw_mux2("clko1_src", base + 0xbd80, 24, 3, clko1_sel, ARRAY_SIZE(clko1_sel));
+       hws[IMX7D_CLKO2_ROOT_SRC] = imx_clk_hw_mux2("clko2_src", base + 0xbe00, 24, 3, clko2_sel, ARRAY_SIZE(clko2_sel));
+
+       hws[IMX7D_ARM_A7_ROOT_CG] = imx_clk_hw_gate3("arm_a7_cg", "arm_a7_src", base + 0x8000, 28);
+       hws[IMX7D_ARM_M4_ROOT_CG] = imx_clk_hw_gate3("arm_m4_cg", "arm_m4_src", base + 0x8080, 28);
+       hws[IMX7D_MAIN_AXI_ROOT_CG] = imx_clk_hw_gate3("axi_cg", "axi_src", base + 0x8800, 28);
+       hws[IMX7D_DISP_AXI_ROOT_CG] = imx_clk_hw_gate3("disp_axi_cg", "disp_axi_src", base + 0x8880, 28);
+       hws[IMX7D_ENET_AXI_ROOT_CG] = imx_clk_hw_gate3("enet_axi_cg", "enet_axi_src", base + 0x8900, 28);
+       hws[IMX7D_NAND_USDHC_BUS_ROOT_CG] = imx_clk_hw_gate3("nand_usdhc_cg", "nand_usdhc_src", base + 0x8980, 28);
+       hws[IMX7D_AHB_CHANNEL_ROOT_CG] = imx_clk_hw_gate3("ahb_cg", "ahb_src", base + 0x9000, 28);
+       hws[IMX7D_DRAM_PHYM_ROOT_CG] = imx_clk_hw_gate3("dram_phym_cg", "dram_phym_src", base + 0x9800, 28);
+       hws[IMX7D_DRAM_ROOT_CG] = imx_clk_hw_gate3("dram_cg", "dram_src", base + 0x9880, 28);
+       hws[IMX7D_DRAM_PHYM_ALT_ROOT_CG] = imx_clk_hw_gate3("dram_phym_alt_cg", "dram_phym_alt_src", base + 0xa000, 28);
+       hws[IMX7D_DRAM_ALT_ROOT_CG] = imx_clk_hw_gate3("dram_alt_cg", "dram_alt_src", base + 0xa080, 28);
+       hws[IMX7D_USB_HSIC_ROOT_CG] = imx_clk_hw_gate3("usb_hsic_cg", "usb_hsic_src", base + 0xa100, 28);
+       hws[IMX7D_PCIE_CTRL_ROOT_CG] = imx_clk_hw_gate3("pcie_ctrl_cg", "pcie_ctrl_src", base + 0xa180, 28);
+       hws[IMX7D_PCIE_PHY_ROOT_CG] = imx_clk_hw_gate3("pcie_phy_cg", "pcie_phy_src", base + 0xa200, 28);
+       hws[IMX7D_EPDC_PIXEL_ROOT_CG] = imx_clk_hw_gate3("epdc_pixel_cg", "epdc_pixel_src", base + 0xa280, 28);
+       hws[IMX7D_LCDIF_PIXEL_ROOT_CG] = imx_clk_hw_gate3("lcdif_pixel_cg", "lcdif_pixel_src", base + 0xa300, 28);
+       hws[IMX7D_MIPI_DSI_ROOT_CG] = imx_clk_hw_gate3("mipi_dsi_cg", "mipi_dsi_src", base + 0xa380, 28);
+       hws[IMX7D_MIPI_CSI_ROOT_CG] = imx_clk_hw_gate3("mipi_csi_cg", "mipi_csi_src", base + 0xa400, 28);
+       hws[IMX7D_MIPI_DPHY_ROOT_CG] = imx_clk_hw_gate3("mipi_dphy_cg", "mipi_dphy_src", base + 0xa480, 28);
+       hws[IMX7D_SAI1_ROOT_CG] = imx_clk_hw_gate3("sai1_cg", "sai1_src", base + 0xa500, 28);
+       hws[IMX7D_SAI2_ROOT_CG] = imx_clk_hw_gate3("sai2_cg", "sai2_src", base + 0xa580, 28);
+       hws[IMX7D_SAI3_ROOT_CG] = imx_clk_hw_gate3("sai3_cg", "sai3_src", base + 0xa600, 28);
+       hws[IMX7D_SPDIF_ROOT_CG] = imx_clk_hw_gate3("spdif_cg", "spdif_src", base + 0xa680, 28);
+       hws[IMX7D_ENET1_REF_ROOT_CG] = imx_clk_hw_gate3("enet1_ref_cg", "enet1_ref_src", base + 0xa700, 28);
+       hws[IMX7D_ENET1_TIME_ROOT_CG] = imx_clk_hw_gate3("enet1_time_cg", "enet1_time_src", base + 0xa780, 28);
+       hws[IMX7D_ENET2_REF_ROOT_CG] = imx_clk_hw_gate3("enet2_ref_cg", "enet2_ref_src", base + 0xa800, 28);
+       hws[IMX7D_ENET2_TIME_ROOT_CG] = imx_clk_hw_gate3("enet2_time_cg", "enet2_time_src", base + 0xa880, 28);
+       hws[IMX7D_ENET_PHY_REF_ROOT_CG] = imx_clk_hw_gate3("enet_phy_ref_cg", "enet_phy_ref_src", base + 0xa900, 28);
+       hws[IMX7D_EIM_ROOT_CG] = imx_clk_hw_gate3("eim_cg", "eim_src", base + 0xa980, 28);
+       hws[IMX7D_NAND_ROOT_CG] = imx_clk_hw_gate3("nand_cg", "nand_src", base + 0xaa00, 28);
+       hws[IMX7D_QSPI_ROOT_CG] = imx_clk_hw_gate3("qspi_cg", "qspi_src", base + 0xaa80, 28);
+       hws[IMX7D_USDHC1_ROOT_CG] = imx_clk_hw_gate3("usdhc1_cg", "usdhc1_src", base + 0xab00, 28);
+       hws[IMX7D_USDHC2_ROOT_CG] = imx_clk_hw_gate3("usdhc2_cg", "usdhc2_src", base + 0xab80, 28);
+       hws[IMX7D_USDHC3_ROOT_CG] = imx_clk_hw_gate3("usdhc3_cg", "usdhc3_src", base + 0xac00, 28);
+       hws[IMX7D_CAN1_ROOT_CG] = imx_clk_hw_gate3("can1_cg", "can1_src", base + 0xac80, 28);
+       hws[IMX7D_CAN2_ROOT_CG] = imx_clk_hw_gate3("can2_cg", "can2_src", base + 0xad00, 28);
+       hws[IMX7D_I2C1_ROOT_CG] = imx_clk_hw_gate3("i2c1_cg", "i2c1_src", base + 0xad80, 28);
+       hws[IMX7D_I2C2_ROOT_CG] = imx_clk_hw_gate3("i2c2_cg", "i2c2_src", base + 0xae00, 28);
+       hws[IMX7D_I2C3_ROOT_CG] = imx_clk_hw_gate3("i2c3_cg", "i2c3_src", base + 0xae80, 28);
+       hws[IMX7D_I2C4_ROOT_CG] = imx_clk_hw_gate3("i2c4_cg", "i2c4_src", base + 0xaf00, 28);
+       hws[IMX7D_UART1_ROOT_CG] = imx_clk_hw_gate3("uart1_cg", "uart1_src", base + 0xaf80, 28);
+       hws[IMX7D_UART2_ROOT_CG] = imx_clk_hw_gate3("uart2_cg", "uart2_src", base + 0xb000, 28);
+       hws[IMX7D_UART3_ROOT_CG] = imx_clk_hw_gate3("uart3_cg", "uart3_src", base + 0xb080, 28);
+       hws[IMX7D_UART4_ROOT_CG] = imx_clk_hw_gate3("uart4_cg", "uart4_src", base + 0xb100, 28);
+       hws[IMX7D_UART5_ROOT_CG] = imx_clk_hw_gate3("uart5_cg", "uart5_src", base + 0xb180, 28);
+       hws[IMX7D_UART6_ROOT_CG] = imx_clk_hw_gate3("uart6_cg", "uart6_src", base + 0xb200, 28);
+       hws[IMX7D_UART7_ROOT_CG] = imx_clk_hw_gate3("uart7_cg", "uart7_src", base + 0xb280, 28);
+       hws[IMX7D_ECSPI1_ROOT_CG] = imx_clk_hw_gate3("ecspi1_cg", "ecspi1_src", base + 0xb300, 28);
+       hws[IMX7D_ECSPI2_ROOT_CG] = imx_clk_hw_gate3("ecspi2_cg", "ecspi2_src", base + 0xb380, 28);
+       hws[IMX7D_ECSPI3_ROOT_CG] = imx_clk_hw_gate3("ecspi3_cg", "ecspi3_src", base + 0xb400, 28);
+       hws[IMX7D_ECSPI4_ROOT_CG] = imx_clk_hw_gate3("ecspi4_cg", "ecspi4_src", base + 0xb480, 28);
+       hws[IMX7D_PWM1_ROOT_CG] = imx_clk_hw_gate3("pwm1_cg", "pwm1_src", base + 0xb500, 28);
+       hws[IMX7D_PWM2_ROOT_CG] = imx_clk_hw_gate3("pwm2_cg", "pwm2_src", base + 0xb580, 28);
+       hws[IMX7D_PWM3_ROOT_CG] = imx_clk_hw_gate3("pwm3_cg", "pwm3_src", base + 0xb600, 28);
+       hws[IMX7D_PWM4_ROOT_CG] = imx_clk_hw_gate3("pwm4_cg", "pwm4_src", base + 0xb680, 28);
+       hws[IMX7D_FLEXTIMER1_ROOT_CG] = imx_clk_hw_gate3("flextimer1_cg", "flextimer1_src", base + 0xb700, 28);
+       hws[IMX7D_FLEXTIMER2_ROOT_CG] = imx_clk_hw_gate3("flextimer2_cg", "flextimer2_src", base + 0xb780, 28);
+       hws[IMX7D_SIM1_ROOT_CG] = imx_clk_hw_gate3("sim1_cg", "sim1_src", base + 0xb800, 28);
+       hws[IMX7D_SIM2_ROOT_CG] = imx_clk_hw_gate3("sim2_cg", "sim2_src", base + 0xb880, 28);
+       hws[IMX7D_GPT1_ROOT_CG] = imx_clk_hw_gate3("gpt1_cg", "gpt1_src", base + 0xb900, 28);
+       hws[IMX7D_GPT2_ROOT_CG] = imx_clk_hw_gate3("gpt2_cg", "gpt2_src", base + 0xb980, 28);
+       hws[IMX7D_GPT3_ROOT_CG] = imx_clk_hw_gate3("gpt3_cg", "gpt3_src", base + 0xbA00, 28);
+       hws[IMX7D_GPT4_ROOT_CG] = imx_clk_hw_gate3("gpt4_cg", "gpt4_src", base + 0xbA80, 28);
+       hws[IMX7D_TRACE_ROOT_CG] = imx_clk_hw_gate3("trace_cg", "trace_src", base + 0xbb00, 28);
+       hws[IMX7D_WDOG_ROOT_CG] = imx_clk_hw_gate3("wdog_cg", "wdog_src", base + 0xbb80, 28);
+       hws[IMX7D_CSI_MCLK_ROOT_CG] = imx_clk_hw_gate3("csi_mclk_cg", "csi_mclk_src", base + 0xbc00, 28);
+       hws[IMX7D_AUDIO_MCLK_ROOT_CG] = imx_clk_hw_gate3("audio_mclk_cg", "audio_mclk_src", base + 0xbc80, 28);
+       hws[IMX7D_WRCLK_ROOT_CG] = imx_clk_hw_gate3("wrclk_cg", "wrclk_src", base + 0xbd00, 28);
+       hws[IMX7D_CLKO1_ROOT_CG] = imx_clk_hw_gate3("clko1_cg", "clko1_src", base + 0xbd80, 28);
+       hws[IMX7D_CLKO2_ROOT_CG] = imx_clk_hw_gate3("clko2_cg", "clko2_src", base + 0xbe00, 28);
+
+       hws[IMX7D_MAIN_AXI_ROOT_PRE_DIV] = imx_clk_hw_divider2("axi_pre_div", "axi_cg", base + 0x8800, 16, 3);
+       hws[IMX7D_DISP_AXI_ROOT_PRE_DIV] = imx_clk_hw_divider2("disp_axi_pre_div", "disp_axi_cg", base + 0x8880, 16, 3);
+       hws[IMX7D_ENET_AXI_ROOT_PRE_DIV] = imx_clk_hw_divider2("enet_axi_pre_div", "enet_axi_cg", base + 0x8900, 16, 3);
+       hws[IMX7D_NAND_USDHC_BUS_ROOT_PRE_DIV] = imx_clk_hw_divider2("nand_usdhc_pre_div", "nand_usdhc_cg", base + 0x8980, 16, 3);
+       hws[IMX7D_AHB_CHANNEL_ROOT_PRE_DIV] = imx_clk_hw_divider2("ahb_pre_div", "ahb_cg", base + 0x9000, 16, 3);
+       hws[IMX7D_DRAM_PHYM_ALT_ROOT_PRE_DIV] = imx_clk_hw_divider2("dram_phym_alt_pre_div", "dram_phym_alt_cg", base + 0xa000, 16, 3);
+       hws[IMX7D_DRAM_ALT_ROOT_PRE_DIV] = imx_clk_hw_divider2("dram_alt_pre_div", "dram_alt_cg", base + 0xa080, 16, 3);
+       hws[IMX7D_USB_HSIC_ROOT_PRE_DIV] = imx_clk_hw_divider2("usb_hsic_pre_div", "usb_hsic_cg", base + 0xa100, 16, 3);
+       hws[IMX7D_PCIE_CTRL_ROOT_PRE_DIV] = imx_clk_hw_divider2("pcie_ctrl_pre_div", "pcie_ctrl_cg", base + 0xa180, 16, 3);
+       hws[IMX7D_PCIE_PHY_ROOT_PRE_DIV] = imx_clk_hw_divider2("pcie_phy_pre_div", "pcie_phy_cg", base + 0xa200, 16, 3);
+       hws[IMX7D_EPDC_PIXEL_ROOT_PRE_DIV] = imx_clk_hw_divider2("epdc_pixel_pre_div", "epdc_pixel_cg", base + 0xa280, 16, 3);
+       hws[IMX7D_LCDIF_PIXEL_ROOT_PRE_DIV] = imx_clk_hw_divider2("lcdif_pixel_pre_div", "lcdif_pixel_cg", base + 0xa300, 16, 3);
+       hws[IMX7D_MIPI_DSI_ROOT_PRE_DIV] = imx_clk_hw_divider2("mipi_dsi_pre_div", "mipi_dsi_cg", base + 0xa380, 16, 3);
+       hws[IMX7D_MIPI_CSI_ROOT_PRE_DIV] = imx_clk_hw_divider2("mipi_csi_pre_div", "mipi_csi_cg", base + 0xa400, 16, 3);
+       hws[IMX7D_MIPI_DPHY_ROOT_PRE_DIV] = imx_clk_hw_divider2("mipi_dphy_pre_div", "mipi_dphy_cg", base + 0xa480, 16, 3);
+       hws[IMX7D_SAI1_ROOT_PRE_DIV] = imx_clk_hw_divider2("sai1_pre_div", "sai1_cg", base + 0xa500, 16, 3);
+       hws[IMX7D_SAI2_ROOT_PRE_DIV] = imx_clk_hw_divider2("sai2_pre_div", "sai2_cg", base + 0xa580, 16, 3);
+       hws[IMX7D_SAI3_ROOT_PRE_DIV] = imx_clk_hw_divider2("sai3_pre_div", "sai3_cg", base + 0xa600, 16, 3);
+       hws[IMX7D_SPDIF_ROOT_PRE_DIV] = imx_clk_hw_divider2("spdif_pre_div", "spdif_cg", base + 0xa680, 16, 3);
+       hws[IMX7D_ENET1_REF_ROOT_PRE_DIV] = imx_clk_hw_divider2("enet1_ref_pre_div", "enet1_ref_cg", base + 0xa700, 16, 3);
+       hws[IMX7D_ENET1_TIME_ROOT_PRE_DIV] = imx_clk_hw_divider2("enet1_time_pre_div", "enet1_time_cg", base + 0xa780, 16, 3);
+       hws[IMX7D_ENET2_REF_ROOT_PRE_DIV] = imx_clk_hw_divider2("enet2_ref_pre_div", "enet2_ref_cg", base + 0xa800, 16, 3);
+       hws[IMX7D_ENET2_TIME_ROOT_PRE_DIV] = imx_clk_hw_divider2("enet2_time_pre_div", "enet2_time_cg", base + 0xa880, 16, 3);
+       hws[IMX7D_ENET_PHY_REF_ROOT_PRE_DIV] = imx_clk_hw_divider2("enet_phy_ref_pre_div", "enet_phy_ref_cg", base + 0xa900, 16, 3);
+       hws[IMX7D_EIM_ROOT_PRE_DIV] = imx_clk_hw_divider2("eim_pre_div", "eim_cg", base + 0xa980, 16, 3);
+       hws[IMX7D_NAND_ROOT_PRE_DIV] = imx_clk_hw_divider2("nand_pre_div", "nand_cg", base + 0xaa00, 16, 3);
+       hws[IMX7D_QSPI_ROOT_PRE_DIV] = imx_clk_hw_divider2("qspi_pre_div", "qspi_cg", base + 0xaa80, 16, 3);
+       hws[IMX7D_USDHC1_ROOT_PRE_DIV] = imx_clk_hw_divider2("usdhc1_pre_div", "usdhc1_cg", base + 0xab00, 16, 3);
+       hws[IMX7D_USDHC2_ROOT_PRE_DIV] = imx_clk_hw_divider2("usdhc2_pre_div", "usdhc2_cg", base + 0xab80, 16, 3);
+       hws[IMX7D_USDHC3_ROOT_PRE_DIV] = imx_clk_hw_divider2("usdhc3_pre_div", "usdhc3_cg", base + 0xac00, 16, 3);
+       hws[IMX7D_CAN1_ROOT_PRE_DIV] = imx_clk_hw_divider2("can1_pre_div", "can1_cg", base + 0xac80, 16, 3);
+       hws[IMX7D_CAN2_ROOT_PRE_DIV] = imx_clk_hw_divider2("can2_pre_div", "can2_cg", base + 0xad00, 16, 3);
+       hws[IMX7D_I2C1_ROOT_PRE_DIV] = imx_clk_hw_divider2("i2c1_pre_div", "i2c1_cg", base + 0xad80, 16, 3);
+       hws[IMX7D_I2C2_ROOT_PRE_DIV] = imx_clk_hw_divider2("i2c2_pre_div", "i2c2_cg", base + 0xae00, 16, 3);
+       hws[IMX7D_I2C3_ROOT_PRE_DIV] = imx_clk_hw_divider2("i2c3_pre_div", "i2c3_cg", base + 0xae80, 16, 3);
+       hws[IMX7D_I2C4_ROOT_PRE_DIV] = imx_clk_hw_divider2("i2c4_pre_div", "i2c4_cg", base + 0xaf00, 16, 3);
+       hws[IMX7D_UART1_ROOT_PRE_DIV] = imx_clk_hw_divider2("uart1_pre_div", "uart1_cg", base + 0xaf80, 16, 3);
+       hws[IMX7D_UART2_ROOT_PRE_DIV] = imx_clk_hw_divider2("uart2_pre_div", "uart2_cg", base + 0xb000, 16, 3);
+       hws[IMX7D_UART3_ROOT_PRE_DIV] = imx_clk_hw_divider2("uart3_pre_div", "uart3_cg", base + 0xb080, 16, 3);
+       hws[IMX7D_UART4_ROOT_PRE_DIV] = imx_clk_hw_divider2("uart4_pre_div", "uart4_cg", base + 0xb100, 16, 3);
+       hws[IMX7D_UART5_ROOT_PRE_DIV] = imx_clk_hw_divider2("uart5_pre_div", "uart5_cg", base + 0xb180, 16, 3);
+       hws[IMX7D_UART6_ROOT_PRE_DIV] = imx_clk_hw_divider2("uart6_pre_div", "uart6_cg", base + 0xb200, 16, 3);
+       hws[IMX7D_UART7_ROOT_PRE_DIV] = imx_clk_hw_divider2("uart7_pre_div", "uart7_cg", base + 0xb280, 16, 3);
+       hws[IMX7D_ECSPI1_ROOT_PRE_DIV] = imx_clk_hw_divider2("ecspi1_pre_div", "ecspi1_cg", base + 0xb300, 16, 3);
+       hws[IMX7D_ECSPI2_ROOT_PRE_DIV] = imx_clk_hw_divider2("ecspi2_pre_div", "ecspi2_cg", base + 0xb380, 16, 3);
+       hws[IMX7D_ECSPI3_ROOT_PRE_DIV] = imx_clk_hw_divider2("ecspi3_pre_div", "ecspi3_cg", base + 0xb400, 16, 3);
+       hws[IMX7D_ECSPI4_ROOT_PRE_DIV] = imx_clk_hw_divider2("ecspi4_pre_div", "ecspi4_cg", base + 0xb480, 16, 3);
+       hws[IMX7D_PWM1_ROOT_PRE_DIV] = imx_clk_hw_divider2("pwm1_pre_div", "pwm1_cg", base + 0xb500, 16, 3);
+       hws[IMX7D_PWM2_ROOT_PRE_DIV] = imx_clk_hw_divider2("pwm2_pre_div", "pwm2_cg", base + 0xb580, 16, 3);
+       hws[IMX7D_PWM3_ROOT_PRE_DIV] = imx_clk_hw_divider2("pwm3_pre_div", "pwm3_cg", base + 0xb600, 16, 3);
+       hws[IMX7D_PWM4_ROOT_PRE_DIV] = imx_clk_hw_divider2("pwm4_pre_div", "pwm4_cg", base + 0xb680, 16, 3);
+       hws[IMX7D_FLEXTIMER1_ROOT_PRE_DIV] = imx_clk_hw_divider2("flextimer1_pre_div", "flextimer1_cg", base + 0xb700, 16, 3);
+       hws[IMX7D_FLEXTIMER2_ROOT_PRE_DIV] = imx_clk_hw_divider2("flextimer2_pre_div", "flextimer2_cg", base + 0xb780, 16, 3);
+       hws[IMX7D_SIM1_ROOT_PRE_DIV] = imx_clk_hw_divider2("sim1_pre_div", "sim1_cg", base + 0xb800, 16, 3);
+       hws[IMX7D_SIM2_ROOT_PRE_DIV] = imx_clk_hw_divider2("sim2_pre_div", "sim2_cg", base + 0xb880, 16, 3);
+       hws[IMX7D_GPT1_ROOT_PRE_DIV] = imx_clk_hw_divider2("gpt1_pre_div", "gpt1_cg", base + 0xb900, 16, 3);
+       hws[IMX7D_GPT2_ROOT_PRE_DIV] = imx_clk_hw_divider2("gpt2_pre_div", "gpt2_cg", base + 0xb980, 16, 3);
+       hws[IMX7D_GPT3_ROOT_PRE_DIV] = imx_clk_hw_divider2("gpt3_pre_div", "gpt3_cg", base + 0xba00, 16, 3);
+       hws[IMX7D_GPT4_ROOT_PRE_DIV] = imx_clk_hw_divider2("gpt4_pre_div", "gpt4_cg", base + 0xba80, 16, 3);
+       hws[IMX7D_TRACE_ROOT_PRE_DIV] = imx_clk_hw_divider2("trace_pre_div", "trace_cg", base + 0xbb00, 16, 3);
+       hws[IMX7D_WDOG_ROOT_PRE_DIV] = imx_clk_hw_divider2("wdog_pre_div", "wdog_cg", base + 0xbb80, 16, 3);
+       hws[IMX7D_CSI_MCLK_ROOT_PRE_DIV] = imx_clk_hw_divider2("csi_mclk_pre_div", "csi_mclk_cg", base + 0xbc00, 16, 3);
+       hws[IMX7D_AUDIO_MCLK_ROOT_PRE_DIV] = imx_clk_hw_divider2("audio_mclk_pre_div", "audio_mclk_cg", base + 0xbc80, 16, 3);
+       hws[IMX7D_WRCLK_ROOT_PRE_DIV] = imx_clk_hw_divider2("wrclk_pre_div", "wrclk_cg", base + 0xbd00, 16, 3);
+       hws[IMX7D_CLKO1_ROOT_PRE_DIV] = imx_clk_hw_divider2("clko1_pre_div", "clko1_cg", base + 0xbd80, 16, 3);
+       hws[IMX7D_CLKO2_ROOT_PRE_DIV] = imx_clk_hw_divider2("clko2_pre_div", "clko2_cg", base + 0xbe00, 16, 3);
+
+       hws[IMX7D_ARM_A7_ROOT_DIV] = imx_clk_hw_divider2("arm_a7_div", "arm_a7_cg", base + 0x8000, 0, 3);
+       hws[IMX7D_ARM_M4_ROOT_DIV] = imx_clk_hw_divider2("arm_m4_div", "arm_m4_cg", base + 0x8080, 0, 3);
+       hws[IMX7D_MAIN_AXI_ROOT_DIV] = imx_clk_hw_divider2("axi_post_div", "axi_pre_div", base + 0x8800, 0, 6);
+       hws[IMX7D_DISP_AXI_ROOT_DIV] = imx_clk_hw_divider2("disp_axi_post_div", "disp_axi_pre_div", base + 0x8880, 0, 6);
+       hws[IMX7D_ENET_AXI_ROOT_DIV] = imx_clk_hw_divider2("enet_axi_post_div", "enet_axi_pre_div", base + 0x8900, 0, 6);
+       hws[IMX7D_NAND_USDHC_BUS_ROOT_CLK] = imx_clk_hw_divider2("nand_usdhc_root_clk", "nand_usdhc_pre_div", base + 0x8980, 0, 6);
+       hws[IMX7D_AHB_CHANNEL_ROOT_DIV] = imx_clk_hw_divider2("ahb_root_clk", "ahb_pre_div", base + 0x9000, 0, 6);
+       hws[IMX7D_IPG_ROOT_CLK] = imx_clk_hw_divider_flags("ipg_root_clk", "ahb_root_clk", base + 0x9080, 0, 2, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE | CLK_SET_RATE_PARENT);
+       hws[IMX7D_DRAM_ROOT_DIV] = imx_clk_hw_divider2("dram_post_div", "dram_cg", base + 0x9880, 0, 3);
+       hws[IMX7D_DRAM_PHYM_ALT_ROOT_DIV] = imx_clk_hw_divider2("dram_phym_alt_post_div", "dram_phym_alt_pre_div", base + 0xa000, 0, 3);
+       hws[IMX7D_DRAM_ALT_ROOT_DIV] = imx_clk_hw_divider2("dram_alt_post_div", "dram_alt_pre_div", base + 0xa080, 0, 3);
+       hws[IMX7D_USB_HSIC_ROOT_DIV] = imx_clk_hw_divider2("usb_hsic_post_div", "usb_hsic_pre_div", base + 0xa100, 0, 6);
+       hws[IMX7D_PCIE_CTRL_ROOT_DIV] = imx_clk_hw_divider2("pcie_ctrl_post_div", "pcie_ctrl_pre_div", base + 0xa180, 0, 6);
+       hws[IMX7D_PCIE_PHY_ROOT_DIV] = imx_clk_hw_divider2("pcie_phy_post_div", "pcie_phy_pre_div", base + 0xa200, 0, 6);
+       hws[IMX7D_EPDC_PIXEL_ROOT_DIV] = imx_clk_hw_divider2("epdc_pixel_post_div", "epdc_pixel_pre_div", base + 0xa280, 0, 6);
+       hws[IMX7D_LCDIF_PIXEL_ROOT_DIV] = imx_clk_hw_divider2("lcdif_pixel_post_div", "lcdif_pixel_pre_div", base + 0xa300, 0, 6);
+       hws[IMX7D_MIPI_DSI_ROOT_DIV] = imx_clk_hw_divider2("mipi_dsi_post_div", "mipi_dsi_pre_div", base + 0xa380, 0, 6);
+       hws[IMX7D_MIPI_CSI_ROOT_DIV] = imx_clk_hw_divider2("mipi_csi_post_div", "mipi_csi_pre_div", base + 0xa400, 0, 6);
+       hws[IMX7D_MIPI_DPHY_ROOT_DIV] = imx_clk_hw_divider2("mipi_dphy_post_div", "mipi_dphy_pre_div", base + 0xa480, 0, 6);
+       hws[IMX7D_SAI1_ROOT_DIV] = imx_clk_hw_divider2("sai1_post_div", "sai1_pre_div", base + 0xa500, 0, 6);
+       hws[IMX7D_SAI2_ROOT_DIV] = imx_clk_hw_divider2("sai2_post_div", "sai2_pre_div", base + 0xa580, 0, 6);
+       hws[IMX7D_SAI3_ROOT_DIV] = imx_clk_hw_divider2("sai3_post_div", "sai3_pre_div", base + 0xa600, 0, 6);
+       hws[IMX7D_SPDIF_ROOT_DIV] = imx_clk_hw_divider2("spdif_post_div", "spdif_pre_div", base + 0xa680, 0, 6);
+       hws[IMX7D_ENET1_REF_ROOT_DIV] = imx_clk_hw_divider2("enet1_ref_post_div", "enet1_ref_pre_div", base + 0xa700, 0, 6);
+       hws[IMX7D_ENET1_TIME_ROOT_DIV] = imx_clk_hw_divider2("enet1_time_post_div", "enet1_time_pre_div", base + 0xa780, 0, 6);
+       hws[IMX7D_ENET2_REF_ROOT_DIV] = imx_clk_hw_divider2("enet2_ref_post_div", "enet2_ref_pre_div", base + 0xa800, 0, 6);
+       hws[IMX7D_ENET2_TIME_ROOT_DIV] = imx_clk_hw_divider2("enet2_time_post_div", "enet2_time_pre_div", base + 0xa880, 0, 6);
+       hws[IMX7D_ENET_PHY_REF_ROOT_CLK] = imx_clk_hw_divider2("enet_phy_ref_root_clk", "enet_phy_ref_pre_div", base + 0xa900, 0, 6);
+       hws[IMX7D_EIM_ROOT_DIV] = imx_clk_hw_divider2("eim_post_div", "eim_pre_div", base + 0xa980, 0, 6);
+       hws[IMX7D_NAND_ROOT_CLK] = imx_clk_hw_divider2("nand_root_clk", "nand_pre_div", base + 0xaa00, 0, 6);
+       hws[IMX7D_QSPI_ROOT_DIV] = imx_clk_hw_divider2("qspi_post_div", "qspi_pre_div", base + 0xaa80, 0, 6);
+       hws[IMX7D_USDHC1_ROOT_DIV] = imx_clk_hw_divider2("usdhc1_post_div", "usdhc1_pre_div", base + 0xab00, 0, 6);
+       hws[IMX7D_USDHC2_ROOT_DIV] = imx_clk_hw_divider2("usdhc2_post_div", "usdhc2_pre_div", base + 0xab80, 0, 6);
+       hws[IMX7D_USDHC3_ROOT_DIV] = imx_clk_hw_divider2("usdhc3_post_div", "usdhc3_pre_div", base + 0xac00, 0, 6);
+       hws[IMX7D_CAN1_ROOT_DIV] = imx_clk_hw_divider2("can1_post_div", "can1_pre_div", base + 0xac80, 0, 6);
+       hws[IMX7D_CAN2_ROOT_DIV] = imx_clk_hw_divider2("can2_post_div", "can2_pre_div", base + 0xad00, 0, 6);
+       hws[IMX7D_I2C1_ROOT_DIV] = imx_clk_hw_divider2("i2c1_post_div", "i2c1_pre_div", base + 0xad80, 0, 6);
+       hws[IMX7D_I2C2_ROOT_DIV] = imx_clk_hw_divider2("i2c2_post_div", "i2c2_pre_div", base + 0xae00, 0, 6);
+       hws[IMX7D_I2C3_ROOT_DIV] = imx_clk_hw_divider2("i2c3_post_div", "i2c3_pre_div", base + 0xae80, 0, 6);
+       hws[IMX7D_I2C4_ROOT_DIV] = imx_clk_hw_divider2("i2c4_post_div", "i2c4_pre_div", base + 0xaf00, 0, 6);
+       hws[IMX7D_UART1_ROOT_DIV] = imx_clk_hw_divider2("uart1_post_div", "uart1_pre_div", base + 0xaf80, 0, 6);
+       hws[IMX7D_UART2_ROOT_DIV] = imx_clk_hw_divider2("uart2_post_div", "uart2_pre_div", base + 0xb000, 0, 6);
+       hws[IMX7D_UART3_ROOT_DIV] = imx_clk_hw_divider2("uart3_post_div", "uart3_pre_div", base + 0xb080, 0, 6);
+       hws[IMX7D_UART4_ROOT_DIV] = imx_clk_hw_divider2("uart4_post_div", "uart4_pre_div", base + 0xb100, 0, 6);
+       hws[IMX7D_UART5_ROOT_DIV] = imx_clk_hw_divider2("uart5_post_div", "uart5_pre_div", base + 0xb180, 0, 6);
+       hws[IMX7D_UART6_ROOT_DIV] = imx_clk_hw_divider2("uart6_post_div", "uart6_pre_div", base + 0xb200, 0, 6);
+       hws[IMX7D_UART7_ROOT_DIV] = imx_clk_hw_divider2("uart7_post_div", "uart7_pre_div", base + 0xb280, 0, 6);
+       hws[IMX7D_ECSPI1_ROOT_DIV] = imx_clk_hw_divider2("ecspi1_post_div", "ecspi1_pre_div", base + 0xb300, 0, 6);
+       hws[IMX7D_ECSPI2_ROOT_DIV] = imx_clk_hw_divider2("ecspi2_post_div", "ecspi2_pre_div", base + 0xb380, 0, 6);
+       hws[IMX7D_ECSPI3_ROOT_DIV] = imx_clk_hw_divider2("ecspi3_post_div", "ecspi3_pre_div", base + 0xb400, 0, 6);
+       hws[IMX7D_ECSPI4_ROOT_DIV] = imx_clk_hw_divider2("ecspi4_post_div", "ecspi4_pre_div", base + 0xb480, 0, 6);
+       hws[IMX7D_PWM1_ROOT_DIV] = imx_clk_hw_divider2("pwm1_post_div", "pwm1_pre_div", base + 0xb500, 0, 6);
+       hws[IMX7D_PWM2_ROOT_DIV] = imx_clk_hw_divider2("pwm2_post_div", "pwm2_pre_div", base + 0xb580, 0, 6);
+       hws[IMX7D_PWM3_ROOT_DIV] = imx_clk_hw_divider2("pwm3_post_div", "pwm3_pre_div", base + 0xb600, 0, 6);
+       hws[IMX7D_PWM4_ROOT_DIV] = imx_clk_hw_divider2("pwm4_post_div", "pwm4_pre_div", base + 0xb680, 0, 6);
+       hws[IMX7D_FLEXTIMER1_ROOT_DIV] = imx_clk_hw_divider2("flextimer1_post_div", "flextimer1_pre_div", base + 0xb700, 0, 6);
+       hws[IMX7D_FLEXTIMER2_ROOT_DIV] = imx_clk_hw_divider2("flextimer2_post_div", "flextimer2_pre_div", base + 0xb780, 0, 6);
+       hws[IMX7D_SIM1_ROOT_DIV] = imx_clk_hw_divider2("sim1_post_div", "sim1_pre_div", base + 0xb800, 0, 6);
+       hws[IMX7D_SIM2_ROOT_DIV] = imx_clk_hw_divider2("sim2_post_div", "sim2_pre_div", base + 0xb880, 0, 6);
+       hws[IMX7D_GPT1_ROOT_DIV] = imx_clk_hw_divider2("gpt1_post_div", "gpt1_pre_div", base + 0xb900, 0, 6);
+       hws[IMX7D_GPT2_ROOT_DIV] = imx_clk_hw_divider2("gpt2_post_div", "gpt2_pre_div", base + 0xb980, 0, 6);
+       hws[IMX7D_GPT3_ROOT_DIV] = imx_clk_hw_divider2("gpt3_post_div", "gpt3_pre_div", base + 0xba00, 0, 6);
+       hws[IMX7D_GPT4_ROOT_DIV] = imx_clk_hw_divider2("gpt4_post_div", "gpt4_pre_div", base + 0xba80, 0, 6);
+       hws[IMX7D_TRACE_ROOT_DIV] = imx_clk_hw_divider2("trace_post_div", "trace_pre_div", base + 0xbb00, 0, 6);
+       hws[IMX7D_WDOG_ROOT_DIV] = imx_clk_hw_divider2("wdog_post_div", "wdog_pre_div", base + 0xbb80, 0, 6);
+       hws[IMX7D_CSI_MCLK_ROOT_DIV] = imx_clk_hw_divider2("csi_mclk_post_div", "csi_mclk_pre_div", base + 0xbc00, 0, 6);
+       hws[IMX7D_AUDIO_MCLK_ROOT_DIV] = imx_clk_hw_divider2("audio_mclk_post_div", "audio_mclk_pre_div", base + 0xbc80, 0, 6);
+       hws[IMX7D_WRCLK_ROOT_DIV] = imx_clk_hw_divider2("wrclk_post_div", "wrclk_pre_div", base + 0xbd00, 0, 6);
+       hws[IMX7D_CLKO1_ROOT_DIV] = imx_clk_hw_divider2("clko1_post_div", "clko1_pre_div", base + 0xbd80, 0, 6);
+       hws[IMX7D_CLKO2_ROOT_DIV] = imx_clk_hw_divider2("clko2_post_div", "clko2_pre_div", base + 0xbe00, 0, 6);
+
+       hws[IMX7D_ARM_A7_ROOT_CLK] = imx_clk_hw_gate2_flags("arm_a7_root_clk", "arm_a7_div", base + 0x4000, 0, CLK_OPS_PARENT_ENABLE);
+       hws[IMX7D_ARM_M4_ROOT_CLK] = imx_clk_hw_gate4("arm_m4_root_clk", "arm_m4_div", base + 0x4010, 0);
+       hws[IMX7D_MAIN_AXI_ROOT_CLK] = imx_clk_hw_gate2_flags("main_axi_root_clk", "axi_post_div", base + 0x4040, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
+       hws[IMX7D_DISP_AXI_ROOT_CLK] = imx_clk_hw_gate4("disp_axi_root_clk", "disp_axi_post_div", base + 0x4050, 0);
+       hws[IMX7D_ENET_AXI_ROOT_CLK] = imx_clk_hw_gate4("enet_axi_root_clk", "enet_axi_post_div", base + 0x4060, 0);
+       hws[IMX7D_OCRAM_CLK] = imx_clk_hw_gate4("ocram_clk", "main_axi_root_clk", base + 0x4110, 0);
+       hws[IMX7D_OCRAM_S_CLK] = imx_clk_hw_gate4("ocram_s_clk", "ahb_root_clk", base + 0x4120, 0);
+       hws[IMX7D_DRAM_ROOT_CLK] = imx_clk_hw_gate2_flags("dram_root_clk", "dram_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
+       hws[IMX7D_DRAM_PHYM_ROOT_CLK] = imx_clk_hw_gate2_flags("dram_phym_root_clk", "dram_phym_cg", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
+       hws[IMX7D_DRAM_PHYM_ALT_ROOT_CLK] = imx_clk_hw_gate2_flags("dram_phym_alt_root_clk", "dram_phym_alt_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
+       hws[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_hw_gate2_flags("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
+       hws[IMX7D_OCOTP_CLK] = imx_clk_hw_gate4("ocotp_clk", "ipg_root_clk", base + 0x4230, 0);
+       hws[IMX7D_SNVS_CLK] = imx_clk_hw_gate4("snvs_clk", "ipg_root_clk", base + 0x4250, 0);
+       hws[IMX7D_MU_ROOT_CLK] = imx_clk_hw_gate4("mu_root_clk", "ipg_root_clk", base + 0x4270, 0);
+       hws[IMX7D_CAAM_CLK] = imx_clk_hw_gate4("caam_clk", "ipg_root_clk", base + 0x4240, 0);
+       hws[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_hw_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4690, 0);
+       hws[IMX7D_SDMA_CORE_CLK] = imx_clk_hw_gate4("sdma_root_clk", "ahb_root_clk", base + 0x4480, 0);
+       hws[IMX7D_PCIE_CTRL_ROOT_CLK] = imx_clk_hw_gate4("pcie_ctrl_root_clk", "pcie_ctrl_post_div", base + 0x4600, 0);
+       hws[IMX7D_PCIE_PHY_ROOT_CLK] = imx_clk_hw_gate4("pcie_phy_root_clk", "pcie_phy_post_div", base + 0x4600, 0);
+       hws[IMX7D_EPDC_PIXEL_ROOT_CLK] = imx_clk_hw_gate4("epdc_pixel_root_clk", "epdc_pixel_post_div", base + 0x44a0, 0);
+       hws[IMX7D_LCDIF_PIXEL_ROOT_CLK] = imx_clk_hw_gate4("lcdif_pixel_root_clk", "lcdif_pixel_post_div", base + 0x44b0, 0);
+       hws[IMX7D_MIPI_DSI_ROOT_CLK] = imx_clk_hw_gate4("mipi_dsi_root_clk", "mipi_dsi_post_div", base + 0x4650, 0);
+       hws[IMX7D_MIPI_CSI_ROOT_CLK] = imx_clk_hw_gate4("mipi_csi_root_clk", "mipi_csi_post_div", base + 0x4640, 0);
+       hws[IMX7D_MIPI_DPHY_ROOT_CLK] = imx_clk_hw_gate4("mipi_dphy_root_clk", "mipi_dphy_post_div", base + 0x4660, 0);
+       hws[IMX7D_ENET1_IPG_ROOT_CLK] = imx_clk_hw_gate2_shared2("enet1_ipg_root_clk", "enet_axi_post_div", base + 0x4700, 0, &share_count_enet1);
+       hws[IMX7D_ENET1_TIME_ROOT_CLK] = imx_clk_hw_gate2_shared2("enet1_time_root_clk", "enet1_time_post_div", base + 0x4700, 0, &share_count_enet1);
+       hws[IMX7D_ENET2_IPG_ROOT_CLK] = imx_clk_hw_gate2_shared2("enet2_ipg_root_clk", "enet_axi_post_div", base + 0x4710, 0, &share_count_enet2);
+       hws[IMX7D_ENET2_TIME_ROOT_CLK] = imx_clk_hw_gate2_shared2("enet2_time_root_clk", "enet2_time_post_div", base + 0x4710, 0, &share_count_enet2);
+       hws[IMX7D_SAI1_ROOT_CLK] = imx_clk_hw_gate2_shared2("sai1_root_clk", "sai1_post_div", base + 0x48c0, 0, &share_count_sai1);
+       hws[IMX7D_SAI1_IPG_CLK]  = imx_clk_hw_gate2_shared2("sai1_ipg_clk",  "ipg_root_clk",  base + 0x48c0, 0, &share_count_sai1);
+       hws[IMX7D_SAI2_ROOT_CLK] = imx_clk_hw_gate2_shared2("sai2_root_clk", "sai2_post_div", base + 0x48d0, 0, &share_count_sai2);
+       hws[IMX7D_SAI2_IPG_CLK]  = imx_clk_hw_gate2_shared2("sai2_ipg_clk",  "ipg_root_clk",  base + 0x48d0, 0, &share_count_sai2);
+       hws[IMX7D_SAI3_ROOT_CLK] = imx_clk_hw_gate2_shared2("sai3_root_clk", "sai3_post_div", base + 0x48e0, 0, &share_count_sai3);
+       hws[IMX7D_SAI3_IPG_CLK]  = imx_clk_hw_gate2_shared2("sai3_ipg_clk",  "ipg_root_clk",  base + 0x48e0, 0, &share_count_sai3);
+       hws[IMX7D_SPDIF_ROOT_CLK] = imx_clk_hw_gate4("spdif_root_clk", "spdif_post_div", base + 0x44d0, 0);
+       hws[IMX7D_EIM_ROOT_CLK] = imx_clk_hw_gate4("eim_root_clk", "eim_post_div", base + 0x4160, 0);
+       hws[IMX7D_NAND_RAWNAND_CLK] = imx_clk_hw_gate2_shared2("nand_rawnand_clk", "nand_root_clk", base + 0x4140, 0, &share_count_nand);
+       hws[IMX7D_NAND_USDHC_BUS_RAWNAND_CLK] = imx_clk_hw_gate2_shared2("nand_usdhc_rawnand_clk", "nand_usdhc_root_clk", base + 0x4140, 0, &share_count_nand);
+       hws[IMX7D_QSPI_ROOT_CLK] = imx_clk_hw_gate4("qspi_root_clk", "qspi_post_div", base + 0x4150, 0);
+       hws[IMX7D_USDHC1_ROOT_CLK] = imx_clk_hw_gate4("usdhc1_root_clk", "usdhc1_post_div", base + 0x46c0, 0);
+       hws[IMX7D_USDHC2_ROOT_CLK] = imx_clk_hw_gate4("usdhc2_root_clk", "usdhc2_post_div", base + 0x46d0, 0);
+       hws[IMX7D_USDHC3_ROOT_CLK] = imx_clk_hw_gate4("usdhc3_root_clk", "usdhc3_post_div", base + 0x46e0, 0);
+       hws[IMX7D_CAN1_ROOT_CLK] = imx_clk_hw_gate4("can1_root_clk", "can1_post_div", base + 0x4740, 0);
+       hws[IMX7D_CAN2_ROOT_CLK] = imx_clk_hw_gate4("can2_root_clk", "can2_post_div", base + 0x4750, 0);
+       hws[IMX7D_I2C1_ROOT_CLK] = imx_clk_hw_gate4("i2c1_root_clk", "i2c1_post_div", base + 0x4880, 0);
+       hws[IMX7D_I2C2_ROOT_CLK] = imx_clk_hw_gate4("i2c2_root_clk", "i2c2_post_div", base + 0x4890, 0);
+       hws[IMX7D_I2C3_ROOT_CLK] = imx_clk_hw_gate4("i2c3_root_clk", "i2c3_post_div", base + 0x48a0, 0);
+       hws[IMX7D_I2C4_ROOT_CLK] = imx_clk_hw_gate4("i2c4_root_clk", "i2c4_post_div", base + 0x48b0, 0);
+       hws[IMX7D_UART1_ROOT_CLK] = imx_clk_hw_gate4("uart1_root_clk", "uart1_post_div", base + 0x4940, 0);
+       hws[IMX7D_UART2_ROOT_CLK] = imx_clk_hw_gate4("uart2_root_clk", "uart2_post_div", base + 0x4950, 0);
+       hws[IMX7D_UART3_ROOT_CLK] = imx_clk_hw_gate4("uart3_root_clk", "uart3_post_div", base + 0x4960, 0);
+       hws[IMX7D_UART4_ROOT_CLK] = imx_clk_hw_gate4("uart4_root_clk", "uart4_post_div", base + 0x4970, 0);
+       hws[IMX7D_UART5_ROOT_CLK] = imx_clk_hw_gate4("uart5_root_clk", "uart5_post_div", base + 0x4980, 0);
+       hws[IMX7D_UART6_ROOT_CLK] = imx_clk_hw_gate4("uart6_root_clk", "uart6_post_div", base + 0x4990, 0);
+       hws[IMX7D_UART7_ROOT_CLK] = imx_clk_hw_gate4("uart7_root_clk", "uart7_post_div", base + 0x49a0, 0);
+       hws[IMX7D_ECSPI1_ROOT_CLK] = imx_clk_hw_gate4("ecspi1_root_clk", "ecspi1_post_div", base + 0x4780, 0);
+       hws[IMX7D_ECSPI2_ROOT_CLK] = imx_clk_hw_gate4("ecspi2_root_clk", "ecspi2_post_div", base + 0x4790, 0);
+       hws[IMX7D_ECSPI3_ROOT_CLK] = imx_clk_hw_gate4("ecspi3_root_clk", "ecspi3_post_div", base + 0x47a0, 0);
+       hws[IMX7D_ECSPI4_ROOT_CLK] = imx_clk_hw_gate4("ecspi4_root_clk", "ecspi4_post_div", base + 0x47b0, 0);
+       hws[IMX7D_PWM1_ROOT_CLK] = imx_clk_hw_gate4("pwm1_root_clk", "pwm1_post_div", base + 0x4840, 0);
+       hws[IMX7D_PWM2_ROOT_CLK] = imx_clk_hw_gate4("pwm2_root_clk", "pwm2_post_div", base + 0x4850, 0);
+       hws[IMX7D_PWM3_ROOT_CLK] = imx_clk_hw_gate4("pwm3_root_clk", "pwm3_post_div", base + 0x4860, 0);
+       hws[IMX7D_PWM4_ROOT_CLK] = imx_clk_hw_gate4("pwm4_root_clk", "pwm4_post_div", base + 0x4870, 0);
+       hws[IMX7D_FLEXTIMER1_ROOT_CLK] = imx_clk_hw_gate4("flextimer1_root_clk", "flextimer1_post_div", base + 0x4800, 0);
+       hws[IMX7D_FLEXTIMER2_ROOT_CLK] = imx_clk_hw_gate4("flextimer2_root_clk", "flextimer2_post_div", base + 0x4810, 0);
+       hws[IMX7D_SIM1_ROOT_CLK] = imx_clk_hw_gate4("sim1_root_clk", "sim1_post_div", base + 0x4900, 0);
+       hws[IMX7D_SIM2_ROOT_CLK] = imx_clk_hw_gate4("sim2_root_clk", "sim2_post_div", base + 0x4910, 0);
+       hws[IMX7D_GPT1_ROOT_CLK] = imx_clk_hw_gate4("gpt1_root_clk", "gpt1_post_div", base + 0x47c0, 0);
+       hws[IMX7D_GPT2_ROOT_CLK] = imx_clk_hw_gate4("gpt2_root_clk", "gpt2_post_div", base + 0x47d0, 0);
+       hws[IMX7D_GPT3_ROOT_CLK] = imx_clk_hw_gate4("gpt3_root_clk", "gpt3_post_div", base + 0x47e0, 0);
+       hws[IMX7D_GPT4_ROOT_CLK] = imx_clk_hw_gate4("gpt4_root_clk", "gpt4_post_div", base + 0x47f0, 0);
+       hws[IMX7D_TRACE_ROOT_CLK] = imx_clk_hw_gate4("trace_root_clk", "trace_post_div", base + 0x4300, 0);
+       hws[IMX7D_WDOG1_ROOT_CLK] = imx_clk_hw_gate4("wdog1_root_clk", "wdog_post_div", base + 0x49c0, 0);
+       hws[IMX7D_WDOG2_ROOT_CLK] = imx_clk_hw_gate4("wdog2_root_clk", "wdog_post_div", base + 0x49d0, 0);
+       hws[IMX7D_WDOG3_ROOT_CLK] = imx_clk_hw_gate4("wdog3_root_clk", "wdog_post_div", base + 0x49e0, 0);
+       hws[IMX7D_WDOG4_ROOT_CLK] = imx_clk_hw_gate4("wdog4_root_clk", "wdog_post_div", base + 0x49f0, 0);
+       hws[IMX7D_KPP_ROOT_CLK] = imx_clk_hw_gate4("kpp_root_clk", "ipg_root_clk", base + 0x4aa0, 0);
+       hws[IMX7D_CSI_MCLK_ROOT_CLK] = imx_clk_hw_gate4("csi_mclk_root_clk", "csi_mclk_post_div", base + 0x4490, 0);
+       hws[IMX7D_AUDIO_MCLK_ROOT_CLK] = imx_clk_hw_gate4("audio_mclk_root_clk", "audio_mclk_post_div", base + 0x4790, 0);
+       hws[IMX7D_WRCLK_ROOT_CLK] = imx_clk_hw_gate4("wrclk_root_clk", "wrclk_post_div", base + 0x47a0, 0);
+       hws[IMX7D_USB_CTRL_CLK] = imx_clk_hw_gate4("usb_ctrl_clk", "ahb_root_clk", base + 0x4680, 0);
+       hws[IMX7D_USB_PHY1_CLK] = imx_clk_hw_gate4("usb_phy1_clk", "pll_usb1_main_clk", base + 0x46a0, 0);
+       hws[IMX7D_USB_PHY2_CLK] = imx_clk_hw_gate4("usb_phy2_clk", "pll_usb_main_clk", base + 0x46b0, 0);
+       hws[IMX7D_ADC_ROOT_CLK] = imx_clk_hw_gate4("adc_root_clk", "ipg_root_clk", base + 0x4200, 0);
+
+       hws[IMX7D_GPT_3M_CLK] = imx_clk_hw_fixed_factor("gpt_3m", "osc", 1, 8);
+
+       hws[IMX7D_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a7_root_clk",
+                                        hws[IMX7D_ARM_A7_ROOT_CLK]->clk,
+                                        hws[IMX7D_ARM_A7_ROOT_SRC]->clk,
+                                        hws[IMX7D_PLL_ARM_MAIN_CLK]->clk,
+                                        hws[IMX7D_PLL_SYS_MAIN_CLK]->clk);
+
+       imx_check_clk_hws(hws, IMX7D_CLK_END);
+
+       of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
+
+       clk_set_parent(hws[IMX7D_PLL_ARM_MAIN_BYPASS]->clk, hws[IMX7D_PLL_ARM_MAIN]->clk);
+       clk_set_parent(hws[IMX7D_PLL_DRAM_MAIN_BYPASS]->clk, hws[IMX7D_PLL_DRAM_MAIN]->clk);
+       clk_set_parent(hws[IMX7D_PLL_SYS_MAIN_BYPASS]->clk, hws[IMX7D_PLL_SYS_MAIN]->clk);
+       clk_set_parent(hws[IMX7D_PLL_ENET_MAIN_BYPASS]->clk, hws[IMX7D_PLL_ENET_MAIN]->clk);
+       clk_set_parent(hws[IMX7D_PLL_AUDIO_MAIN_BYPASS]->clk, hws[IMX7D_PLL_AUDIO_MAIN]->clk);
+       clk_set_parent(hws[IMX7D_PLL_VIDEO_MAIN_BYPASS]->clk, hws[IMX7D_PLL_VIDEO_MAIN]->clk);
+
+       clk_set_parent(hws[IMX7D_MIPI_CSI_ROOT_SRC]->clk, hws[IMX7D_PLL_SYS_PFD3_CLK]->clk);
 
        /* use old gpt clk setting, gpt1 root clk must be twice as gpt counter freq */
-       clk_set_parent(clks[IMX7D_GPT1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]);
+       clk_set_parent(hws[IMX7D_GPT1_ROOT_SRC]->clk, hws[IMX7D_OSC_24M_CLK]->clk);
 
        /* Set clock rate for USBPHY, the USB_PLL at CCM is from USBOTG2 */
-       clks[IMX7D_USB1_MAIN_480M_CLK] = imx_clk_fixed_factor("pll_usb1_main_clk", "osc", 20, 1);
-       clks[IMX7D_USB_MAIN_480M_CLK] = imx_clk_fixed_factor("pll_usb_main_clk", "osc", 20, 1);
+       hws[IMX7D_USB1_MAIN_480M_CLK] = imx_clk_hw_fixed_factor("pll_usb1_main_clk", "osc", 20, 1);
+       hws[IMX7D_USB_MAIN_480M_CLK] = imx_clk_hw_fixed_factor("pll_usb_main_clk", "osc", 20, 1);
+
+       for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
+               int index = uart_clk_ids[i];
+
+               uart_clks[i] = &hws[index]->clk;
+       }
+
 
        imx_register_uart_clocks(uart_clks);
 
index 6668210..42e4667 100644 (file)
@@ -115,7 +115,7 @@ static void __init imx7ulp_clk_scg1_init(struct device_node *np)
 
        clks[IMX7ULP_CLK_NIC0_DIV]      = imx_clk_hw_divider_flags("nic0_clk",          "nic_sel",  base + 0x40, 24, 4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
        clks[IMX7ULP_CLK_NIC1_DIV]      = imx_clk_hw_divider_flags("nic1_clk",          "nic0_clk", base + 0x40, 16, 4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
-       clks[IMX7ULP_CLK_NIC1_BUS_DIV]  = imx_clk_hw_divider_flags("nic1_bus_clk",      "nic1_clk", base + 0x40, 4,  4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
+       clks[IMX7ULP_CLK_NIC1_BUS_DIV]  = imx_clk_hw_divider_flags("nic1_bus_clk",      "nic0_clk", base + 0x40, 4,  4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
 
        clks[IMX7ULP_CLK_GPU_DIV]       = imx_clk_hw_divider("gpu_clk", "nic0_clk", base + 0x40, 20, 4);
 
index 122a81a..6b8e75d 100644 (file)
@@ -288,6 +288,9 @@ static const char *imx8mm_usb_core_sels[] = {"osc_24m", "sys_pll1_100m", "sys_pl
 static const char *imx8mm_usb_phy_sels[] = {"osc_24m", "sys_pll1_100m", "sys_pll1_40m", "sys_pll2_100m",
                                             "sys_pll2_200m", "clk_ext2", "clk_ext3", "audio_pll2_out", };
 
+static const char *imx8mm_gic_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m", "sys_pll2_100m",
+                                       "sys_pll1_800m", "clk_ext2", "clk_ext4", "audio_pll2_out" };
+
 static const char *imx8mm_ecspi1_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m", "sys_pll1_160m",
                                           "sys_pll1_800m", "sys_pll3_out", "sys_pll2_250m", "audio_pll2_out", };
 
@@ -325,7 +328,7 @@ static const char *imx8mm_dsi_dbi_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll
                                            "sys_pll2_1000m", "sys_pll3_out", "audio_pll2_out", "video_pll1_out", };
 
 static const char *imx8mm_usdhc3_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m",
-                                          "sys_pll3_out", "sys_pll1_266m", "audio_pll2_clk", "sys_pll1_100m", };
+                                          "sys_pll3_out", "sys_pll1_266m", "audio_pll2_out", "sys_pll1_100m", };
 
 static const char *imx8mm_csi1_core_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll2_250m", "sys_pll1_800m",
                                              "sys_pll2_1000m", "sys_pll3_out", "audio_pll2_out", "video_pll1_out", };
@@ -361,11 +364,11 @@ static const char *imx8mm_pdm_sels[] = {"osc_24m", "sys_pll2_100m", "audio_pll1_
                                        "sys_pll2_1000m", "sys_pll3_out", "clk_ext3", "audio_pll2_out", };
 
 static const char *imx8mm_vpu_h1_sels[] = {"osc_24m", "vpu_pll_out", "sys_pll1_800m", "sys_pll2_1000m",
-                                          "audio_pll2_clk", "sys_pll2_125m", "sys_pll3_clk", "audio_pll1_out", };
+                                          "audio_pll2_out", "sys_pll2_125m", "sys_pll3_clk", "audio_pll1_out", };
 
 static const char *imx8mm_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", };
 
-static const char *imx8mm_clko1_sels[] = {"osc_24m", "sys_pll1_800m", "osc_27m", "sys_pll1_200m", "audio_pll2_clk",
+static const char *imx8mm_clko1_sels[] = {"osc_24m", "sys_pll1_800m", "osc_27m", "sys_pll1_200m", "audio_pll2_out",
                                         "vpu_pll", "sys_pll1_80m", };
 
 static struct clk *clks[IMX8MM_CLK_END];
@@ -523,7 +526,7 @@ static int __init imx8mm_clocks_init(struct device_node *ccm_node)
 
        /* IP */
        clks[IMX8MM_CLK_DRAM_ALT] = imx8m_clk_composite("dram_alt", imx8mm_dram_alt_sels, base + 0xa000);
-       clks[IMX8MM_CLK_DRAM_APB] = imx8m_clk_composite("dram_apb", imx8mm_dram_apb_sels, base + 0xa080);
+       clks[IMX8MM_CLK_DRAM_APB] = imx8m_clk_composite_critical("dram_apb", imx8mm_dram_apb_sels, base + 0xa080);
        clks[IMX8MM_CLK_VPU_G1] = imx8m_clk_composite("vpu_g1", imx8mm_vpu_g1_sels, base + 0xa100);
        clks[IMX8MM_CLK_VPU_G2] = imx8m_clk_composite("vpu_g2", imx8mm_vpu_g2_sels, base + 0xa180);
        clks[IMX8MM_CLK_DISP_DTRC] = imx8m_clk_composite("disp_dtrc", imx8mm_disp_dtrc_sels, base + 0xa200);
@@ -558,6 +561,7 @@ static int __init imx8mm_clocks_init(struct device_node *ccm_node)
        clks[IMX8MM_CLK_UART4] = imx8m_clk_composite("uart4", imx8mm_uart4_sels, base + 0xb080);
        clks[IMX8MM_CLK_USB_CORE_REF] = imx8m_clk_composite("usb_core_ref", imx8mm_usb_core_sels, base + 0xb100);
        clks[IMX8MM_CLK_USB_PHY_REF] = imx8m_clk_composite("usb_phy_ref", imx8mm_usb_phy_sels, base + 0xb180);
+       clks[IMX8MM_CLK_GIC] = imx8m_clk_composite_critical("gic", imx8mm_gic_sels, base + 0xb200);
        clks[IMX8MM_CLK_ECSPI1] = imx8m_clk_composite("ecspi1", imx8mm_ecspi1_sels, base + 0xb280);
        clks[IMX8MM_CLK_ECSPI2] = imx8m_clk_composite("ecspi2", imx8mm_ecspi2_sels, base + 0xb300);
        clks[IMX8MM_CLK_PWM1] = imx8m_clk_composite("pwm1", imx8mm_pwm1_sels, base + 0xb380);
@@ -590,6 +594,11 @@ static int __init imx8mm_clocks_init(struct device_node *ccm_node)
        clks[IMX8MM_CLK_ECSPI2_ROOT] = imx_clk_gate4("ecspi2_root_clk", "ecspi2", base + 0x4080, 0);
        clks[IMX8MM_CLK_ECSPI3_ROOT] = imx_clk_gate4("ecspi3_root_clk", "ecspi3", base + 0x4090, 0);
        clks[IMX8MM_CLK_ENET1_ROOT] = imx_clk_gate4("enet1_root_clk", "enet_axi", base + 0x40a0, 0);
+       clks[IMX8MM_CLK_GPIO1_ROOT] = imx_clk_gate4("gpio1_root_clk", "ipg_root", base + 0x40b0, 0);
+       clks[IMX8MM_CLK_GPIO2_ROOT] = imx_clk_gate4("gpio2_root_clk", "ipg_root", base + 0x40c0, 0);
+       clks[IMX8MM_CLK_GPIO3_ROOT] = imx_clk_gate4("gpio3_root_clk", "ipg_root", base + 0x40d0, 0);
+       clks[IMX8MM_CLK_GPIO4_ROOT] = imx_clk_gate4("gpio4_root_clk", "ipg_root", base + 0x40e0, 0);
+       clks[IMX8MM_CLK_GPIO5_ROOT] = imx_clk_gate4("gpio5_root_clk", "ipg_root", base + 0x40f0, 0);
        clks[IMX8MM_CLK_GPT1_ROOT] = imx_clk_gate4("gpt1_root_clk", "gpt1", base + 0x4100, 0);
        clks[IMX8MM_CLK_I2C1_ROOT] = imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0);
        clks[IMX8MM_CLK_I2C2_ROOT] = imx_clk_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0);
@@ -617,6 +626,7 @@ static int __init imx8mm_clocks_init(struct device_node *ccm_node)
        clks[IMX8MM_CLK_SAI5_IPG] = imx_clk_gate2_shared2("sai5_ipg_clk", "ipg_audio_root", base + 0x4370, 0, &share_count_sai5);
        clks[IMX8MM_CLK_SAI6_ROOT] = imx_clk_gate2_shared2("sai6_root_clk", "sai6", base + 0x4380, 0, &share_count_sai6);
        clks[IMX8MM_CLK_SAI6_IPG] = imx_clk_gate2_shared2("sai6_ipg_clk", "ipg_audio_root", base + 0x4380, 0, &share_count_sai6);
+       clks[IMX8MM_CLK_SNVS_ROOT] = imx_clk_gate4("snvs_root_clk", "ipg_root", base + 0x4470, 0);
        clks[IMX8MM_CLK_UART1_ROOT] = imx_clk_gate4("uart1_root_clk", "uart1", base + 0x4490, 0);
        clks[IMX8MM_CLK_UART2_ROOT] = imx_clk_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0);
        clks[IMX8MM_CLK_UART3_ROOT] = imx_clk_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0);
index daf1841..d407a07 100644 (file)
@@ -192,6 +192,9 @@ static const char * const imx8mq_usb_core_sels[] = {"osc_25m", "sys1_pll_100m",
 static const char * const imx8mq_usb_phy_sels[] = {"osc_25m", "sys1_pll_100m", "sys1_pll_40m", "sys2_pll_100m",
                                             "sys2_pll_200m", "clk_ext2", "clk_ext3", "audio_pll2_out", };
 
+static const char * const imx8mq_gic_sels[] = {"osc_25m", "sys2_pll_200m", "sys1_pll_40m", "sys2_pll_100m",
+                                              "sys2_pll_200m", "clk_ext2", "clk_ext3", "audio_pll2_out" };
+
 static const char * const imx8mq_ecspi1_sels[] = {"osc_25m", "sys2_pll_200m", "sys1_pll_40m", "sys1_pll_160m",
                                           "sys1_pll_800m", "sys3_pll2_out", "sys2_pll_250m", "audio_pll2_out", };
 
@@ -269,13 +272,20 @@ static const char * const imx8mq_clko2_sels[] = {"osc_25m", "sys2_pll_200m", "sy
 
 static struct clk_onecell_data clk_data;
 
+static struct clk ** const uart_clks[] = {
+       &clks[IMX8MQ_CLK_UART1_ROOT],
+       &clks[IMX8MQ_CLK_UART2_ROOT],
+       &clks[IMX8MQ_CLK_UART3_ROOT],
+       &clks[IMX8MQ_CLK_UART4_ROOT],
+       NULL
+};
+
 static int imx8mq_clocks_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
        void __iomem *base;
        int err;
-       int i;
 
        clks[IMX8MQ_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
        clks[IMX8MQ_CLK_32K] = of_clk_get_by_name(np, "ckil");
@@ -358,9 +368,9 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
        clks[IMX8MQ_SYS2_PLL_1000M] = imx_clk_fixed_factor("sys2_pll_1000m", "sys2_pll_out", 1, 1);
 
        np = dev->of_node;
-       base = of_iomap(np, 0);
-       if (WARN_ON(!base))
-               return -ENOMEM;
+       base = devm_platform_ioremap_resource(pdev, 0);
+       if (WARN_ON(IS_ERR(base)))
+               return PTR_ERR(base);
 
        /* CORE */
        clks[IMX8MQ_CLK_A53_SRC] = imx_clk_mux2("arm_a53_src", base + 0x8000, 24, 3, imx8mq_a53_sels, ARRAY_SIZE(imx8mq_a53_sels));
@@ -442,6 +452,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
        clks[IMX8MQ_CLK_UART4] = imx8m_clk_composite("uart4", imx8mq_uart4_sels, base + 0xb080);
        clks[IMX8MQ_CLK_USB_CORE_REF] = imx8m_clk_composite("usb_core_ref", imx8mq_usb_core_sels, base + 0xb100);
        clks[IMX8MQ_CLK_USB_PHY_REF] = imx8m_clk_composite("usb_phy_ref", imx8mq_usb_phy_sels, base + 0xb180);
+       clks[IMX8MQ_CLK_GIC] = imx8m_clk_composite_critical("gic", imx8mq_gic_sels, base + 0xb200);
        clks[IMX8MQ_CLK_ECSPI1] = imx8m_clk_composite("ecspi1", imx8mq_ecspi1_sels, base + 0xb280);
        clks[IMX8MQ_CLK_ECSPI2] = imx8m_clk_composite("ecspi2", imx8mq_ecspi2_sels, base + 0xb300);
        clks[IMX8MQ_CLK_PWM1] = imx8m_clk_composite("pwm1", imx8mq_pwm1_sels, base + 0xb380);
@@ -507,6 +518,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
        clks[IMX8MQ_CLK_SAI5_IPG] = imx_clk_gate2_shared2("sai5_ipg_clk", "ipg_audio_root", base + 0x4370, 0, &share_count_sai5);
        clks[IMX8MQ_CLK_SAI6_ROOT] = imx_clk_gate2_shared2("sai6_root_clk", "sai6", base + 0x4380, 0, &share_count_sai6);
        clks[IMX8MQ_CLK_SAI6_IPG] = imx_clk_gate2_shared2("sai6_ipg_clk", "ipg_audio_root", base + 0x4380, 0, &share_count_sai6);
+       clks[IMX8MQ_CLK_SNVS_ROOT] = imx_clk_gate4("snvs_root_clk", "ipg_root", base + 0x4470, 0);
        clks[IMX8MQ_CLK_UART1_ROOT] = imx_clk_gate4("uart1_root_clk", "uart1", base + 0x4490, 0);
        clks[IMX8MQ_CLK_UART2_ROOT] = imx_clk_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0);
        clks[IMX8MQ_CLK_UART3_ROOT] = imx_clk_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0);
@@ -543,10 +555,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
                                           clks[IMX8MQ_ARM_PLL_OUT],
                                           clks[IMX8MQ_SYS1_PLL_800M]);
 
-       for (i = 0; i < IMX8MQ_CLK_END; i++)
-               if (IS_ERR(clks[i]))
-                       pr_err("i.MX8mq clk %u register failed with %ld\n",
-                              i, PTR_ERR(clks[i]));
+       imx_check_clocks(clks, ARRAY_SIZE(clks));
 
        clk_data.clks = clks;
        clk_data.clk_num = ARRAY_SIZE(clks);
@@ -554,6 +563,8 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
        err = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
        WARN_ON(err);
 
+       imx_register_uart_clocks(uart_clks);
+
        return err;
 }
 
index fa82dde..50b7c30 100644 (file)
@@ -121,12 +121,13 @@ static const struct clk_ops clk_pfd_ops = {
        .is_enabled     = clk_pfd_is_enabled,
 };
 
-struct clk *imx_clk_pfd(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_pfd(const char *name, const char *parent_name,
                        void __iomem *reg, u8 idx)
 {
        struct clk_pfd *pfd;
-       struct clk *clk;
+       struct clk_hw *hw;
        struct clk_init_data init;
+       int ret;
 
        pfd = kzalloc(sizeof(*pfd), GFP_KERNEL);
        if (!pfd)
@@ -142,10 +143,13 @@ struct clk *imx_clk_pfd(const char *name, const char *parent_name,
        init.num_parents = 1;
 
        pfd->hw.init = &init;
+       hw = &pfd->hw;
 
-       clk = clk_register(NULL, &pfd->hw);
-       if (IS_ERR(clk))
+       ret = clk_hw_register(NULL, hw);
+       if (ret) {
                kfree(pfd);
+               return ERR_PTR(ret);
+       }
 
-       return clk;
+       return hw;
 }
index 93b0596..df91a82 100644 (file)
@@ -410,14 +410,15 @@ static const struct clk_ops clk_pllv3_enet_ops = {
        .recalc_rate    = clk_pllv3_enet_recalc_rate,
 };
 
-struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
+struct clk_hw *imx_clk_hw_pllv3(enum imx_pllv3_type type, const char *name,
                          const char *parent_name, void __iomem *base,
                          u32 div_mask)
 {
        struct clk_pllv3 *pll;
        const struct clk_ops *ops;
-       struct clk *clk;
+       struct clk_hw *hw;
        struct clk_init_data init;
+       int ret;
 
        pll = kzalloc(sizeof(*pll), GFP_KERNEL);
        if (!pll)
@@ -478,10 +479,13 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
        init.num_parents = 1;
 
        pll->hw.init = &init;
+       hw = &pll->hw;
 
-       clk = clk_register(NULL, &pll->hw);
-       if (IS_ERR(clk))
+       ret = clk_hw_register(NULL, hw);
+       if (ret) {
                kfree(pll);
+               return ERR_PTR(ret);
+       }
 
-       return clk;
+       return hw;
 }
index 1efed86..f628071 100644 (file)
@@ -1,14 +1,30 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/err.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include "clk.h"
 
+#define CCM_CCDR                       0x4
+#define CCDR_MMDC_CH0_MASK             BIT(17)
+#define CCDR_MMDC_CH1_MASK             BIT(16)
+
 DEFINE_SPINLOCK(imx_ccm_lock);
 
-void __init imx_check_clocks(struct clk *clks[], unsigned int count)
+void __init imx_mmdc_mask_handshake(void __iomem *ccm_base,
+                                   unsigned int chn)
+{
+       unsigned int reg;
+
+       reg = readl_relaxed(ccm_base + CCM_CCDR);
+       reg |= chn == 0 ? CCDR_MMDC_CH0_MASK : CCDR_MMDC_CH1_MASK;
+       writel_relaxed(reg, ccm_base + CCM_CCDR);
+}
+
+void imx_check_clocks(struct clk *clks[], unsigned int count)
 {
        unsigned i;
 
@@ -59,6 +75,17 @@ struct clk * __init imx_obtain_fixed_clock(
        return clk;
 }
 
+struct clk_hw * __init imx_obtain_fixed_clock_hw(
+                       const char *name, unsigned long rate)
+{
+       struct clk *clk;
+
+       clk = imx_obtain_fixed_clock_from_dt(name);
+       if (IS_ERR(clk))
+               clk = imx_clk_fixed(name, rate);
+       return __clk_get_hw(clk);
+}
+
 struct clk_hw * __init imx_obtain_fixed_clk_hw(struct device_node *np,
                                               const char *name)
 {
@@ -97,8 +124,8 @@ void imx_cscmr1_fixup(u32 *val)
        return;
 }
 
-static int imx_keep_uart_clocks __initdata;
-static struct clk ** const *imx_uart_clocks __initdata;
+static int imx_keep_uart_clocks;
+static struct clk ** const *imx_uart_clocks;
 
 static int __init imx_keep_uart_clocks_param(char *str)
 {
@@ -111,7 +138,7 @@ __setup_param("earlycon", imx_keep_uart_earlycon,
 __setup_param("earlyprintk", imx_keep_uart_earlyprintk,
              imx_keep_uart_clocks_param, 0);
 
-void __init imx_register_uart_clocks(struct clk ** const clks[])
+void imx_register_uart_clocks(struct clk ** const clks[])
 {
        if (imx_keep_uart_clocks) {
                int i;
index 8639a8f..d94d9cb 100644 (file)
@@ -10,6 +10,8 @@ extern spinlock_t imx_ccm_lock;
 void imx_check_clocks(struct clk *clks[], unsigned int count);
 void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count);
 void imx_register_uart_clocks(struct clk ** const clks[]);
+void imx_register_uart_clocks_hws(struct clk_hw ** const hws[]);
+void imx_mmdc_mask_handshake(void __iomem *ccm_base, unsigned int chn);
 
 extern void imx_cscmr1_fixup(u32 *val);
 
@@ -48,6 +50,74 @@ struct imx_pll14xx_clk {
        int flags;
 };
 
+#define imx_clk_busy_divider(name, parent_name, reg, shift, width, busy_reg, busy_shift) \
+       imx_clk_hw_busy_divider(name, parent_name, reg, shift, width, busy_reg, busy_shift)->clk
+
+#define imx_clk_busy_mux(name, reg, shift, width, busy_reg, busy_shift, parent_names, num_parents) \
+       imx_clk_hw_busy_mux(name, reg, shift, width, busy_reg, busy_shift, parent_names, num_parents)->clk
+
+#define imx_clk_cpu(name, parent_name, div, mux, pll, step) \
+       imx_clk_hw_cpu(name, parent_name, div, mux, pll, step)->clk
+
+#define clk_register_gate2(dev, name, parent_name, flags, reg, bit_idx, \
+                               cgr_val, clk_gate_flags, lock, share_count) \
+       clk_hw_register_gate2(dev, name, parent_name, flags, reg, bit_idx, \
+                               cgr_val, clk_gate_flags, lock, share_count)->clk
+
+#define imx_clk_pllv3(type, name, parent_name, base, div_mask) \
+       imx_clk_hw_pllv3(type, name, parent_name, base, div_mask)->clk
+
+#define imx_clk_pfd(name, parent_name, reg, idx) \
+       imx_clk_hw_pfd(name, parent_name, reg, idx)->clk
+
+#define imx_clk_gate_exclusive(name, parent, reg, shift, exclusive_mask) \
+       imx_clk_hw_gate_exclusive(name, parent, reg, shift, exclusive_mask)->clk
+
+#define imx_clk_fixup_divider(name, parent, reg, shift, width, fixup) \
+       imx_clk_hw_fixup_divider(name, parent, reg, shift, width, fixup)->clk
+
+#define imx_clk_fixup_mux(name, reg, shift, width, parents, num_parents, fixup) \
+       imx_clk_hw_fixup_mux(name, reg, shift, width, parents, num_parents, fixup)->clk
+
+#define imx_clk_mux_ldb(name, reg, shift, width, parents, num_parents) \
+       imx_clk_hw_mux_ldb(name, reg, shift, width, parents, num_parents)->clk
+
+#define imx_clk_fixed_factor(name, parent, mult, div) \
+       imx_clk_hw_fixed_factor(name, parent, mult, div)->clk
+
+#define imx_clk_divider2(name, parent, reg, shift, width) \
+       imx_clk_hw_divider2(name, parent, reg, shift, width)->clk
+
+#define imx_clk_gate_dis(name, parent, reg, shift) \
+       imx_clk_hw_gate_dis(name, parent, reg, shift)->clk
+
+#define imx_clk_gate_dis_flags(name, parent, reg, shift, flags) \
+       imx_clk_hw_gate_dis_flags(name, parent, reg, shift, flags)->clk
+
+#define imx_clk_gate_flags(name, parent, reg, shift, flags) \
+       imx_clk_hw_gate_flags(name, parent, reg, shift, flags)->clk
+
+#define imx_clk_gate2(name, parent, reg, shift) \
+       imx_clk_hw_gate2(name, parent, reg, shift)->clk
+
+#define imx_clk_gate2_flags(name, parent, reg, shift, flags) \
+       imx_clk_hw_gate2_flags(name, parent, reg, shift, flags)->clk
+
+#define imx_clk_gate2_shared(name, parent, reg, shift, share_count) \
+       imx_clk_hw_gate2_shared(name, parent, reg, shift, share_count)->clk
+
+#define imx_clk_gate2_shared2(name, parent, reg, shift, share_count) \
+       imx_clk_hw_gate2_shared2(name, parent, reg, shift, share_count)->clk
+
+#define imx_clk_gate3(name, parent, reg, shift) \
+       imx_clk_hw_gate3(name, parent, reg, shift)->clk
+
+#define imx_clk_gate4(name, parent, reg, shift) \
+       imx_clk_hw_gate4(name, parent, reg, shift)->clk
+
+#define imx_clk_mux(name, reg, shift, width, parents, num_parents) \
+       imx_clk_hw_mux(name, reg, shift, width, parents, num_parents)->clk
+
 struct clk *imx_clk_pll14xx(const char *name, const char *parent_name,
                 void __iomem *base, const struct imx_pll14xx_clk *pll_clk);
 
@@ -80,13 +150,13 @@ enum imx_pllv3_type {
        IMX_PLLV3_AV_IMX7,
 };
 
-struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
+struct clk_hw *imx_clk_hw_pllv3(enum imx_pllv3_type type, const char *name,
                const char *parent_name, void __iomem *base, u32 div_mask);
 
 struct clk_hw *imx_clk_pllv4(const char *name, const char *parent_name,
                             void __iomem *base);
 
-struct clk *clk_register_gate2(struct device *dev, const char *name,
+struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 bit_idx, u8 cgr_val,
                u8 clk_gate_flags, spinlock_t *lock,
@@ -95,23 +165,26 @@ struct clk *clk_register_gate2(struct device *dev, const char *name,
 struct clk * imx_obtain_fixed_clock(
                        const char *name, unsigned long rate);
 
+struct clk_hw *imx_obtain_fixed_clock_hw(
+                       const char *name, unsigned long rate);
+
 struct clk_hw *imx_obtain_fixed_clk_hw(struct device_node *np,
                                       const char *name);
 
-struct clk *imx_clk_gate_exclusive(const char *name, const char *parent,
+struct clk_hw *imx_clk_hw_gate_exclusive(const char *name, const char *parent,
         void __iomem *reg, u8 shift, u32 exclusive_mask);
 
-struct clk *imx_clk_pfd(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_pfd(const char *name, const char *parent_name,
                void __iomem *reg, u8 idx);
 
 struct clk_hw *imx_clk_pfdv2(const char *name, const char *parent_name,
                             void __iomem *reg, u8 idx);
 
-struct clk *imx_clk_busy_divider(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_busy_divider(const char *name, const char *parent_name,
                                 void __iomem *reg, u8 shift, u8 width,
                                 void __iomem *busy_reg, u8 busy_shift);
 
-struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift,
+struct clk_hw *imx_clk_hw_busy_mux(const char *name, void __iomem *reg, u8 shift,
                             u8 width, void __iomem *busy_reg, u8 busy_shift,
                             const char * const *parent_names, int num_parents);
 
@@ -121,11 +194,11 @@ struct clk_hw *imx7ulp_clk_composite(const char *name,
                                     bool rate_present, bool gate_present,
                                     void __iomem *reg);
 
-struct clk *imx_clk_fixup_divider(const char *name, const char *parent,
+struct clk_hw *imx_clk_hw_fixup_divider(const char *name, const char *parent,
                                  void __iomem *reg, u8 shift, u8 width,
                                  void (*fixup)(u32 *val));
 
-struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg,
+struct clk_hw *imx_clk_hw_fixup_mux(const char *name, void __iomem *reg,
                              u8 shift, u8 width, const char * const *parents,
                              int num_parents, void (*fixup)(u32 *val));
 
@@ -139,19 +212,19 @@ static inline struct clk_hw *imx_clk_hw_fixed(const char *name, int rate)
        return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate);
 }
 
-static inline struct clk *imx_clk_mux_ldb(const char *name, void __iomem *reg,
+static inline struct clk_hw *imx_clk_hw_mux_ldb(const char *name, void __iomem *reg,
                        u8 shift, u8 width, const char * const *parents,
                        int num_parents)
 {
-       return clk_register_mux(NULL, name, parents, num_parents,
+       return clk_hw_register_mux(NULL, name, parents, num_parents,
                        CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, reg,
                        shift, width, CLK_MUX_READ_ONLY, &imx_ccm_lock);
 }
 
-static inline struct clk *imx_clk_fixed_factor(const char *name,
+static inline struct clk_hw *imx_clk_hw_fixed_factor(const char *name,
                const char *parent, unsigned int mult, unsigned int div)
 {
-       return clk_register_fixed_factor(NULL, name, parent,
+       return clk_hw_register_fixed_factor(NULL, name, parent,
                        CLK_SET_RATE_PARENT, mult, div);
 }
 
@@ -188,10 +261,10 @@ static inline struct clk_hw *imx_clk_hw_divider_flags(const char *name,
                                       reg, shift, width, 0, &imx_ccm_lock);
 }
 
-static inline struct clk *imx_clk_divider2(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_divider2(const char *name, const char *parent,
                void __iomem *reg, u8 shift, u8 width)
 {
-       return clk_register_divider(NULL, name, parent,
+       return clk_hw_register_divider(NULL, name, parent,
                        CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
                        reg, shift, width, 0, &imx_ccm_lock);
 }
@@ -212,10 +285,10 @@ static inline struct clk *imx_clk_gate(const char *name, const char *parent,
                        shift, 0, &imx_ccm_lock);
 }
 
-static inline struct clk *imx_clk_gate_flags(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_gate_flags(const char *name, const char *parent,
                void __iomem *reg, u8 shift, unsigned long flags)
 {
-       return clk_register_gate(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
+       return clk_hw_register_gate(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
                        shift, 0, &imx_ccm_lock);
 }
 
@@ -226,47 +299,47 @@ static inline struct clk_hw *imx_clk_hw_gate(const char *name, const char *paren
                                    shift, 0, &imx_ccm_lock);
 }
 
-static inline struct clk *imx_clk_gate_dis(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_gate_dis(const char *name, const char *parent,
                void __iomem *reg, u8 shift)
 {
-       return clk_register_gate(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+       return clk_hw_register_gate(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
                        shift, CLK_GATE_SET_TO_DISABLE, &imx_ccm_lock);
 }
 
-static inline struct clk *imx_clk_gate_dis_flags(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_gate_dis_flags(const char *name, const char *parent,
                void __iomem *reg, u8 shift, unsigned long flags)
 {
-       return clk_register_gate(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
+       return clk_hw_register_gate(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
                        shift, CLK_GATE_SET_TO_DISABLE, &imx_ccm_lock);
 }
 
-static inline struct clk *imx_clk_gate2(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_gate2(const char *name, const char *parent,
                void __iomem *reg, u8 shift)
 {
-       return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+       return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
                        shift, 0x3, 0, &imx_ccm_lock, NULL);
 }
 
-static inline struct clk *imx_clk_gate2_flags(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_gate2_flags(const char *name, const char *parent,
                void __iomem *reg, u8 shift, unsigned long flags)
 {
-       return clk_register_gate2(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
+       return clk_hw_register_gate2(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
                        shift, 0x3, 0, &imx_ccm_lock, NULL);
 }
 
-static inline struct clk *imx_clk_gate2_shared(const char *name,
+static inline struct clk_hw *imx_clk_hw_gate2_shared(const char *name,
                const char *parent, void __iomem *reg, u8 shift,
                unsigned int *share_count)
 {
-       return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+       return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
                        shift, 0x3, 0, &imx_ccm_lock, share_count);
 }
 
-static inline struct clk *imx_clk_gate2_shared2(const char *name,
+static inline struct clk_hw *imx_clk_hw_gate2_shared2(const char *name,
                const char *parent, void __iomem *reg, u8 shift,
                unsigned int *share_count)
 {
-       return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT |
+       return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT |
                                  CLK_OPS_PARENT_ENABLE, reg, shift, 0x3, 0,
                                  &imx_ccm_lock, share_count);
 }
@@ -278,10 +351,10 @@ static inline struct clk *imx_clk_gate2_cgr(const char *name,
                        shift, cgr_val, 0, &imx_ccm_lock, NULL);
 }
 
-static inline struct clk *imx_clk_gate3(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_gate3(const char *name, const char *parent,
                void __iomem *reg, u8 shift)
 {
-       return clk_register_gate(NULL, name, parent,
+       return clk_hw_register_gate(NULL, name, parent,
                        CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
                        reg, shift, 0, &imx_ccm_lock);
 }
@@ -295,10 +368,10 @@ static inline struct clk *imx_clk_gate3_flags(const char *name,
                        reg, shift, 0, &imx_ccm_lock);
 }
 
-static inline struct clk *imx_clk_gate4(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_gate4(const char *name, const char *parent,
                void __iomem *reg, u8 shift)
 {
-       return clk_register_gate2(NULL, name, parent,
+       return clk_hw_register_gate2(NULL, name, parent,
                        CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
                        reg, shift, 0x3, 0, &imx_ccm_lock, NULL);
 }
@@ -312,11 +385,11 @@ static inline struct clk *imx_clk_gate4_flags(const char *name,
                        reg, shift, 0x3, 0, &imx_ccm_lock, NULL);
 }
 
-static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,
+static inline struct clk_hw *imx_clk_hw_mux(const char *name, void __iomem *reg,
                        u8 shift, u8 width, const char * const *parents,
                        int num_parents)
 {
-       return clk_register_mux(NULL, name, parents, num_parents,
+       return clk_hw_register_mux(NULL, name, parents, num_parents,
                        CLK_SET_RATE_NO_REPARENT, reg, shift,
                        width, 0, &imx_ccm_lock);
 }
@@ -373,7 +446,7 @@ static inline struct clk_hw *imx_clk_hw_mux_flags(const char *name,
                                   reg, shift, width, 0, &imx_ccm_lock);
 }
 
-struct clk *imx_clk_cpu(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_cpu(const char *name, const char *parent_name,
                struct clk *div, struct clk *mux, struct clk *pll,
                struct clk *step);
 
index ab58a6a..250570a 100644 (file)
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_INGENIC_CGU_COMMON)       += cgu.o
+obj-$(CONFIG_INGENIC_CGU_COMMON)       += cgu.o pm.o
 obj-$(CONFIG_INGENIC_CGU_JZ4740)       += jz4740-cgu.o
 obj-$(CONFIG_INGENIC_CGU_JZ4725B)      += jz4725b-cgu.o
 obj-$(CONFIG_INGENIC_CGU_JZ4770)       += jz4770-cgu.o
index 92c3314..6e96303 100644 (file)
@@ -375,8 +375,11 @@ ingenic_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
                div_reg = readl(cgu->base + clk_info->div.reg);
                div = (div_reg >> clk_info->div.shift) &
                      GENMASK(clk_info->div.bits - 1, 0);
-               div += 1;
-               div *= clk_info->div.div;
+
+               if (clk_info->div.div_table)
+                       div = clk_info->div.div_table[div];
+               else
+                       div = (div + 1) * clk_info->div.div;
 
                rate /= div;
        } else if (clk_info->type & CGU_CLK_FIXDIV) {
@@ -386,16 +389,37 @@ ingenic_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
        return rate;
 }
 
+static unsigned int
+ingenic_clk_calc_hw_div(const struct ingenic_cgu_clk_info *clk_info,
+                       unsigned int div)
+{
+       unsigned int i;
+
+       for (i = 0; i < (1 << clk_info->div.bits)
+                               && clk_info->div.div_table[i]; i++) {
+               if (clk_info->div.div_table[i] >= div)
+                       return i;
+       }
+
+       return i - 1;
+}
+
 static unsigned
 ingenic_clk_calc_div(const struct ingenic_cgu_clk_info *clk_info,
                     unsigned long parent_rate, unsigned long req_rate)
 {
-       unsigned div;
+       unsigned int div, hw_div;
 
        /* calculate the divide */
        div = DIV_ROUND_UP(parent_rate, req_rate);
 
-       /* and impose hardware constraints */
+       if (clk_info->div.div_table) {
+               hw_div = ingenic_clk_calc_hw_div(clk_info, div);
+
+               return clk_info->div.div_table[hw_div];
+       }
+
+       /* Impose hardware constraints */
        div = min_t(unsigned, div, 1 << clk_info->div.bits);
        div = max_t(unsigned, div, 1);
 
@@ -438,7 +462,7 @@ ingenic_clk_set_rate(struct clk_hw *hw, unsigned long req_rate,
        const struct ingenic_cgu_clk_info *clk_info;
        const unsigned timeout = 100;
        unsigned long rate, flags;
-       unsigned div, i;
+       unsigned int hw_div, div, i;
        u32 reg, mask;
        int ret = 0;
 
@@ -451,13 +475,18 @@ ingenic_clk_set_rate(struct clk_hw *hw, unsigned long req_rate,
                if (rate != req_rate)
                        return -EINVAL;
 
+               if (clk_info->div.div_table)
+                       hw_div = ingenic_clk_calc_hw_div(clk_info, div);
+               else
+                       hw_div = ((div / clk_info->div.div) - 1);
+
                spin_lock_irqsave(&cgu->lock, flags);
                reg = readl(cgu->base + clk_info->div.reg);
 
                /* update the divide */
                mask = GENMASK(clk_info->div.bits - 1, 0);
                reg &= ~(mask << clk_info->div.shift);
-               reg |= ((div / clk_info->div.div) - 1) << clk_info->div.shift;
+               reg |= hw_div << clk_info->div.shift;
 
                /* clear the stop bit */
                if (clk_info->div.stop_bit != -1)
index bfbcf6d..0dc8004 100644 (file)
@@ -10,6 +10,7 @@
 #define __DRIVERS_CLK_INGENIC_CGU_H__
 
 #include <linux/bitops.h>
+#include <linux/clk-provider.h>
 #include <linux/of.h>
 #include <linux/spinlock.h>
 
@@ -79,6 +80,8 @@ struct ingenic_cgu_mux_info {
  *          isn't one
  * @busy_bit: the index of the busy bit within reg, or -1 if there isn't one
  * @stop_bit: the index of the stop bit within reg, or -1 if there isn't one
+ * @div_table: optional table to map the value read from the register to the
+ *             actual divider value
  */
 struct ingenic_cgu_div_info {
        unsigned reg;
@@ -88,6 +91,7 @@ struct ingenic_cgu_div_info {
        s8 ce_bit;
        s8 busy_bit;
        s8 stop_bit;
+       const u8 *div_table;
 };
 
 /**
index 8901ea0..2642d36 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/of.h>
 #include <dt-bindings/clock/jz4725b-cgu.h>
 #include "cgu.h"
+#include "pm.h"
 
 /* CGU register offsets */
 #define CGU_REG_CPCCR          0x00
@@ -33,6 +34,14 @@ static const s8 pll_od_encoding[4] = {
        0x0, 0x1, -1, 0x3,
 };
 
+static const u8 jz4725b_cgu_cpccr_div_table[] = {
+       1, 2, 3, 4, 6, 8,
+};
+
+static const u8 jz4725b_cgu_pll_half_div_table[] = {
+       2, 1,
+};
+
 static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
 
        /* External clocks */
@@ -66,37 +75,55 @@ static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
        [JZ4725B_CLK_PLL_HALF] = {
                "pll half", CGU_CLK_DIV,
                .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
-               .div = { CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1,
+                       jz4725b_cgu_pll_half_div_table,
+               },
        },
 
        [JZ4725B_CLK_CCLK] = {
                "cclk", CGU_CLK_DIV,
                .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
-               .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1,
+                       jz4725b_cgu_cpccr_div_table,
+               },
        },
 
        [JZ4725B_CLK_HCLK] = {
                "hclk", CGU_CLK_DIV,
                .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
-               .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1,
+                       jz4725b_cgu_cpccr_div_table,
+               },
        },
 
        [JZ4725B_CLK_PCLK] = {
                "pclk", CGU_CLK_DIV,
                .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
-               .div = { CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1,
+                       jz4725b_cgu_cpccr_div_table,
+               },
        },
 
        [JZ4725B_CLK_MCLK] = {
                "mclk", CGU_CLK_DIV,
                .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
-               .div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1,
+                       jz4725b_cgu_cpccr_div_table,
+               },
        },
 
        [JZ4725B_CLK_IPU] = {
                "ipu", CGU_CLK_DIV | CGU_CLK_GATE,
                .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
-               .div = { CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1,
+                       jz4725b_cgu_cpccr_div_table,
+               },
                .gate = { CGU_REG_CLKGR, 13 },
        },
 
@@ -227,5 +254,7 @@ static void __init jz4725b_cgu_init(struct device_node *np)
        retval = ingenic_cgu_register_clocks(cgu);
        if (retval)
                pr_err("%s: failed to register CGU Clocks\n", __func__);
+
+       ingenic_cgu_register_syscore_ops(cgu);
 }
 CLK_OF_DECLARE(jz4725b_cgu, "ingenic,jz4725b-cgu", jz4725b_cgu_init);
index c77f4e1..4c0a209 100644 (file)
@@ -11,8 +11,8 @@
 #include <linux/io.h>
 #include <linux/of.h>
 #include <dt-bindings/clock/jz4740-cgu.h>
-#include <asm/mach-jz4740/clock.h>
 #include "cgu.h"
+#include "pm.h"
 
 /* CGU register offsets */
 #define CGU_REG_CPCCR          0x00
@@ -49,6 +49,10 @@ static const s8 pll_od_encoding[4] = {
        0x0, 0x1, -1, 0x3,
 };
 
+static const u8 jz4740_cgu_cpccr_div_table[] = {
+       1, 2, 3, 4, 6, 8, 12, 16, 24, 32,
+};
+
 static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
 
        /* External clocks */
@@ -88,31 +92,46 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
        [JZ4740_CLK_CCLK] = {
                "cclk", CGU_CLK_DIV,
                .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
-               .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1,
+                       jz4740_cgu_cpccr_div_table,
+               },
        },
 
        [JZ4740_CLK_HCLK] = {
                "hclk", CGU_CLK_DIV,
                .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
-               .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1,
+                       jz4740_cgu_cpccr_div_table,
+               },
        },
 
        [JZ4740_CLK_PCLK] = {
                "pclk", CGU_CLK_DIV,
                .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
-               .div = { CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1,
+                       jz4740_cgu_cpccr_div_table,
+               },
        },
 
        [JZ4740_CLK_MCLK] = {
                "mclk", CGU_CLK_DIV,
                .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
-               .div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1,
+                       jz4740_cgu_cpccr_div_table,
+               },
        },
 
        [JZ4740_CLK_LCD] = {
                "lcd", CGU_CLK_DIV | CGU_CLK_GATE,
                .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
-               .div = { CGU_REG_CPCCR, 16, 1, 5, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 16, 1, 5, 22, -1, -1,
+                       jz4740_cgu_cpccr_div_table,
+               },
                .gate = { CGU_REG_CLKGR, 10 },
        },
 
@@ -219,77 +238,7 @@ static void __init jz4740_cgu_init(struct device_node *np)
        retval = ingenic_cgu_register_clocks(cgu);
        if (retval)
                pr_err("%s: failed to register CGU Clocks\n", __func__);
-}
-CLK_OF_DECLARE(jz4740_cgu, "ingenic,jz4740-cgu", jz4740_cgu_init);
-
-void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode)
-{
-       uint32_t lcr = readl(cgu->base + CGU_REG_LCR);
-
-       switch (mode) {
-       case JZ4740_WAIT_MODE_IDLE:
-               lcr &= ~LCR_SLEEP;
-               break;
-
-       case JZ4740_WAIT_MODE_SLEEP:
-               lcr |= LCR_SLEEP;
-               break;
-       }
-
-       writel(lcr, cgu->base + CGU_REG_LCR);
-}
 
-void jz4740_clock_udc_disable_auto_suspend(void)
-{
-       uint32_t clkgr = readl(cgu->base + CGU_REG_CLKGR);
-
-       clkgr &= ~CLKGR_UDC;
-       writel(clkgr, cgu->base + CGU_REG_CLKGR);
-}
-EXPORT_SYMBOL_GPL(jz4740_clock_udc_disable_auto_suspend);
-
-void jz4740_clock_udc_enable_auto_suspend(void)
-{
-       uint32_t clkgr = readl(cgu->base + CGU_REG_CLKGR);
-
-       clkgr |= CLKGR_UDC;
-       writel(clkgr, cgu->base + CGU_REG_CLKGR);
-}
-EXPORT_SYMBOL_GPL(jz4740_clock_udc_enable_auto_suspend);
-
-#define JZ_CLOCK_GATE_UART0    BIT(0)
-#define JZ_CLOCK_GATE_TCU      BIT(1)
-#define JZ_CLOCK_GATE_DMAC     BIT(12)
-
-void jz4740_clock_suspend(void)
-{
-       uint32_t clkgr, cppcr;
-
-       clkgr = readl(cgu->base + CGU_REG_CLKGR);
-       clkgr |= JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0;
-       writel(clkgr, cgu->base + CGU_REG_CLKGR);
-
-       cppcr = readl(cgu->base + CGU_REG_CPPCR);
-       cppcr &= ~BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.enable_bit);
-       writel(cppcr, cgu->base + CGU_REG_CPPCR);
-}
-
-void jz4740_clock_resume(void)
-{
-       uint32_t clkgr, cppcr, stable;
-
-       cppcr = readl(cgu->base + CGU_REG_CPPCR);
-       cppcr |= BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.enable_bit);
-       writel(cppcr, cgu->base + CGU_REG_CPPCR);
-
-       stable = BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.stable_bit);
-       do {
-               cppcr = readl(cgu->base + CGU_REG_CPPCR);
-       } while (!(cppcr & stable));
-
-       clkgr = readl(cgu->base + CGU_REG_CLKGR);
-       clkgr &= ~JZ_CLOCK_GATE_TCU;
-       clkgr &= ~JZ_CLOCK_GATE_DMAC;
-       clkgr &= ~JZ_CLOCK_GATE_UART0;
-       writel(clkgr, cgu->base + CGU_REG_CLKGR);
+       ingenic_cgu_register_syscore_ops(cgu);
 }
+CLK_OF_DECLARE(jz4740_cgu, "ingenic,jz4740-cgu", jz4740_cgu_init);
index dfce740..eebc1be 100644 (file)
@@ -9,9 +9,9 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/of.h>
-#include <linux/syscore_ops.h>
 #include <dt-bindings/clock/jz4770-cgu.h>
 #include "cgu.h"
+#include "pm.h"
 
 /*
  * CPM registers offset address definition
@@ -38,9 +38,6 @@
 #define CGU_REG_MSC2CDR                0xA8
 #define CGU_REG_BCHCDR         0xAC
 
-/* bits within the LCR register */
-#define LCR_LPM                        BIT(0)          /* Low Power Mode */
-
 /* bits within the OPCR register */
 #define OPCR_SPENDH            BIT(5)          /* UHC PHY suspend */
 
@@ -87,6 +84,10 @@ static const s8 pll_od_encoding[8] = {
        0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
 };
 
+static const u8 jz4770_cgu_cpccr_div_table[] = {
+       1, 2, 3, 4, 6, 8, 12,
+};
+
 static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
 
        /* External clocks */
@@ -144,34 +145,52 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
        [JZ4770_CLK_CCLK] = {
                "cclk", CGU_CLK_DIV,
                .parents = { JZ4770_CLK_PLL0, },
-               .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1,
+                       jz4770_cgu_cpccr_div_table,
+               },
        },
        [JZ4770_CLK_H0CLK] = {
                "h0clk", CGU_CLK_DIV,
                .parents = { JZ4770_CLK_PLL0, },
-               .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1,
+                       jz4770_cgu_cpccr_div_table,
+               },
        },
        [JZ4770_CLK_H1CLK] = {
                "h1clk", CGU_CLK_DIV | CGU_CLK_GATE,
                .parents = { JZ4770_CLK_PLL0, },
-               .div = { CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1,
+                       jz4770_cgu_cpccr_div_table,
+               },
                .gate = { CGU_REG_CLKGR1, 7 },
        },
        [JZ4770_CLK_H2CLK] = {
                "h2clk", CGU_CLK_DIV,
                .parents = { JZ4770_CLK_PLL0, },
-               .div = { CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1,
+                       jz4770_cgu_cpccr_div_table,
+               },
        },
        [JZ4770_CLK_C1CLK] = {
                "c1clk", CGU_CLK_DIV | CGU_CLK_GATE,
                .parents = { JZ4770_CLK_PLL0, },
-               .div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1,
+                       jz4770_cgu_cpccr_div_table,
+               },
                .gate = { CGU_REG_OPCR, 31, true }, // disable CCLK stop on idle
        },
        [JZ4770_CLK_PCLK] = {
                "pclk", CGU_CLK_DIV,
                .parents = { JZ4770_CLK_PLL0, },
-               .div = { CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1,
+                       jz4770_cgu_cpccr_div_table,
+               },
        },
 
        /* Those divided clocks can connect to PLL0 or PLL1 */
@@ -407,30 +426,6 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
        },
 };
 
-#if IS_ENABLED(CONFIG_PM_SLEEP)
-static int jz4770_cgu_pm_suspend(void)
-{
-       u32 val;
-
-       val = readl(cgu->base + CGU_REG_LCR);
-       writel(val | LCR_LPM, cgu->base + CGU_REG_LCR);
-       return 0;
-}
-
-static void jz4770_cgu_pm_resume(void)
-{
-       u32 val;
-
-       val = readl(cgu->base + CGU_REG_LCR);
-       writel(val & ~LCR_LPM, cgu->base + CGU_REG_LCR);
-}
-
-static struct syscore_ops jz4770_cgu_pm_ops = {
-       .suspend = jz4770_cgu_pm_suspend,
-       .resume = jz4770_cgu_pm_resume,
-};
-#endif /* CONFIG_PM_SLEEP */
-
 static void __init jz4770_cgu_init(struct device_node *np)
 {
        int retval;
@@ -444,9 +439,7 @@ static void __init jz4770_cgu_init(struct device_node *np)
        if (retval)
                pr_err("%s: failed to register CGU Clocks\n", __func__);
 
-#if IS_ENABLED(CONFIG_PM_SLEEP)
-       register_syscore_ops(&jz4770_cgu_pm_ops);
-#endif
+       ingenic_cgu_register_syscore_ops(cgu);
 }
 
 /* We only probe via devicetree, no need for a platform driver */
index 2464fc4..8c67f89 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/of.h>
 #include <dt-bindings/clock/jz4780-cgu.h>
 #include "cgu.h"
+#include "pm.h"
 
 /* CGU register offsets */
 #define CGU_REG_CLOCKCONTROL   0x00
@@ -721,5 +722,7 @@ static void __init jz4780_cgu_init(struct device_node *np)
                pr_err("%s: failed to register CGU Clocks\n", __func__);
                return;
        }
+
+       ingenic_cgu_register_syscore_ops(cgu);
 }
 CLK_OF_DECLARE(jz4780_cgu, "ingenic,jz4780-cgu", jz4780_cgu_init);
diff --git a/drivers/clk/ingenic/pm.c b/drivers/clk/ingenic/pm.c
new file mode 100644 (file)
index 0000000..341752b
--- /dev/null
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Paul Cercueil <paul@crapouillou.net>
+ */
+
+#include "cgu.h"
+#include "pm.h"
+
+#include <linux/io.h>
+#include <linux/syscore_ops.h>
+
+#define CGU_REG_LCR            0x04
+
+#define LCR_LOW_POWER_MODE     BIT(0)
+
+static void __iomem * __maybe_unused ingenic_cgu_base;
+
+static int __maybe_unused ingenic_cgu_pm_suspend(void)
+{
+       u32 val = readl(ingenic_cgu_base + CGU_REG_LCR);
+
+       writel(val | LCR_LOW_POWER_MODE, ingenic_cgu_base + CGU_REG_LCR);
+
+       return 0;
+}
+
+static void __maybe_unused ingenic_cgu_pm_resume(void)
+{
+       u32 val = readl(ingenic_cgu_base + CGU_REG_LCR);
+
+       writel(val & ~LCR_LOW_POWER_MODE, ingenic_cgu_base + CGU_REG_LCR);
+}
+
+static struct syscore_ops __maybe_unused ingenic_cgu_pm_ops = {
+       .suspend = ingenic_cgu_pm_suspend,
+       .resume = ingenic_cgu_pm_resume,
+};
+
+void ingenic_cgu_register_syscore_ops(struct ingenic_cgu *cgu)
+{
+       if (IS_ENABLED(CONFIG_PM_SLEEP)) {
+               ingenic_cgu_base = cgu->base;
+               register_syscore_ops(&ingenic_cgu_pm_ops);
+       }
+}
diff --git a/drivers/clk/ingenic/pm.h b/drivers/clk/ingenic/pm.h
new file mode 100644 (file)
index 0000000..fa75404
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 Paul Cercueil <paul@crapouillou.net>
+ */
+#ifndef DRIVERS_CLK_INGENIC_PM_H
+#define DRIVERS_CLK_INGENIC_PM_H
+
+struct ingenic_cgu;
+
+void ingenic_cgu_register_syscore_ops(struct ingenic_cgu *cgu);
+
+#endif /* DRIVERS_CLK_INGENIC_PM_H */
index 0ca6301..38aeefb 100644 (file)
@@ -15,3 +15,14 @@ config TI_SCI_CLK
          This adds the clock driver support over TI System Control Interface.
          If you wish to use clock resources from the PMMC firmware, say Y.
          Otherwise, say N.
+
+config TI_SCI_CLK_PROBE_FROM_FW
+       bool "Probe available clocks from firmware"
+       depends on TI_SCI_CLK
+       default n
+       help
+         Forces the TI SCI clock driver to probe available clocks from the
+         firmware. By default, only the used clocks are probed from DT.
+         This is mostly only useful for debugging purposes, and will
+         increase the boot time of the device. If you want the clocks probed
+         from firmware, say Y. Otherwise, say N.
index 4cb70be..7edf8c8 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/slab.h>
 #include <linux/soc/ti/ti_sci_protocol.h>
 #include <linux/bsearch.h>
+#include <linux/list_sort.h>
 
 #define SCI_CLK_SSC_ENABLE             BIT(0)
 #define SCI_CLK_ALLOW_FREQ_CHANGE      BIT(1)
@@ -52,14 +53,16 @@ struct sci_clk_provider {
  * @num_parents: Number of parents for this clock
  * @provider:   Master clock provider
  * @flags:      Flags for the clock
+ * @node:       Link for handling clocks probed via DT
  */
 struct sci_clk {
        struct clk_hw hw;
        u16 dev_id;
-       u8 clk_id;
-       u8 num_parents;
+       u32 clk_id;
+       u32 num_parents;
        struct sci_clk_provider *provider;
        u8 flags;
+       struct list_head node;
 };
 
 #define to_sci_clk(_hw) container_of(_hw, struct sci_clk, hw)
@@ -218,11 +221,11 @@ static int sci_clk_set_rate(struct clk_hw *hw, unsigned long rate,
 static u8 sci_clk_get_parent(struct clk_hw *hw)
 {
        struct sci_clk *clk = to_sci_clk(hw);
-       u8 parent_id;
+       u32 parent_id = 0;
        int ret;
 
        ret = clk->provider->ops->get_parent(clk->provider->sci, clk->dev_id,
-                                            clk->clk_id, &parent_id);
+                                            clk->clk_id, (void *)&parent_id);
        if (ret) {
                dev_err(clk->provider->dev,
                        "get-parent failed for dev=%d, clk=%d, ret=%d\n",
@@ -230,7 +233,9 @@ static u8 sci_clk_get_parent(struct clk_hw *hw)
                return 0;
        }
 
-       return parent_id - clk->clk_id - 1;
+       parent_id = parent_id - clk->clk_id - 1;
+
+       return (u8)parent_id;
 }
 
 /**
@@ -280,8 +285,8 @@ static int _sci_clk_build(struct sci_clk_provider *provider,
        int i;
        int ret = 0;
 
-       name = kasprintf(GFP_KERNEL, "%s:%d:%d", dev_name(provider->dev),
-                        sci_clk->dev_id, sci_clk->clk_id);
+       name = kasprintf(GFP_KERNEL, "clk:%d:%d", sci_clk->dev_id,
+                        sci_clk->clk_id);
 
        init.name = name;
 
@@ -306,8 +311,7 @@ static int _sci_clk_build(struct sci_clk_provider *provider,
                for (i = 0; i < sci_clk->num_parents; i++) {
                        char *parent_name;
 
-                       parent_name = kasprintf(GFP_KERNEL, "%s:%d:%d",
-                                               dev_name(provider->dev),
+                       parent_name = kasprintf(GFP_KERNEL, "clk:%d:%d",
                                                sci_clk->dev_id,
                                                sci_clk->clk_id + 1 + i);
                        if (!parent_name) {
@@ -404,22 +408,9 @@ static const struct of_device_id ti_sci_clk_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, ti_sci_clk_of_match);
 
-/**
- * ti_sci_clk_probe - Probe function for the TI SCI clock driver
- * @pdev: platform device pointer to be probed
- *
- * Probes the TI SCI clock device. Allocates a new clock provider
- * and registers this to the common clock framework. Also applies
- * any required flags to the identified clocks via clock lists
- * supplied from DT. Returns 0 for success, negative error value
- * for failure.
- */
-static int ti_sci_clk_probe(struct platform_device *pdev)
+#ifdef CONFIG_TI_SCI_CLK_PROBE_FROM_FW
+static int ti_sci_scan_clocks_from_fw(struct sci_clk_provider *provider)
 {
-       struct device *dev = &pdev->dev;
-       struct device_node *np = dev->of_node;
-       struct sci_clk_provider *provider;
-       const struct ti_sci_handle *handle;
        int ret;
        int num_clks = 0;
        struct sci_clk **clks = NULL;
@@ -428,24 +419,14 @@ static int ti_sci_clk_probe(struct platform_device *pdev)
        int max_clks = 0;
        int clk_id = 0;
        int dev_id = 0;
-       u8 num_parents;
+       u32 num_parents = 0;
        int gap_size = 0;
-
-       handle = devm_ti_sci_get_handle(dev);
-       if (IS_ERR(handle))
-               return PTR_ERR(handle);
-
-       provider = devm_kzalloc(dev, sizeof(*provider), GFP_KERNEL);
-       if (!provider)
-               return -ENOMEM;
-
-       provider->sci = handle;
-       provider->ops = &handle->ops.clk_ops;
-       provider->dev = dev;
+       struct device *dev = provider->dev;
 
        while (1) {
                ret = provider->ops->get_num_parents(provider->sci, dev_id,
-                                                    clk_id, &num_parents);
+                                                    clk_id,
+                                                    (void *)&num_parents);
                if (ret) {
                        gap_size++;
                        if (!clk_id) {
@@ -502,6 +483,188 @@ static int ti_sci_clk_probe(struct platform_device *pdev)
 
        devm_kfree(dev, clks);
 
+       return 0;
+}
+
+#else
+
+static int _cmp_sci_clk_list(void *priv, struct list_head *a,
+                            struct list_head *b)
+{
+       struct sci_clk *ca = container_of(a, struct sci_clk, node);
+       struct sci_clk *cb = container_of(b, struct sci_clk, node);
+
+       return _cmp_sci_clk(ca, &cb);
+}
+
+static int ti_sci_scan_clocks_from_dt(struct sci_clk_provider *provider)
+{
+       struct device *dev = provider->dev;
+       struct device_node *np = NULL;
+       int ret;
+       int index;
+       struct of_phandle_args args;
+       struct list_head clks;
+       struct sci_clk *sci_clk, *prev;
+       int num_clks = 0;
+       int num_parents;
+       int clk_id;
+       const char * const clk_names[] = {
+               "clocks", "assigned-clocks", "assigned-clock-parents", NULL
+       };
+       const char * const *clk_name;
+
+       INIT_LIST_HEAD(&clks);
+
+       clk_name = clk_names;
+
+       while (*clk_name) {
+               np = of_find_node_with_property(np, *clk_name);
+               if (!np) {
+                       clk_name++;
+                       break;
+               }
+
+               if (!of_device_is_available(np))
+                       continue;
+
+               index = 0;
+
+               do {
+                       ret = of_parse_phandle_with_args(np, *clk_name,
+                                                        "#clock-cells", index,
+                                                        &args);
+                       if (ret)
+                               break;
+
+                       if (args.args_count == 2 && args.np == dev->of_node) {
+                               sci_clk = devm_kzalloc(dev, sizeof(*sci_clk),
+                                                      GFP_KERNEL);
+                               if (!sci_clk)
+                                       return -ENOMEM;
+
+                               sci_clk->dev_id = args.args[0];
+                               sci_clk->clk_id = args.args[1];
+                               sci_clk->provider = provider;
+                               provider->ops->get_num_parents(provider->sci,
+                                                              sci_clk->dev_id,
+                                                              sci_clk->clk_id,
+                                                              (void *)&sci_clk->num_parents);
+                               list_add_tail(&sci_clk->node, &clks);
+
+                               num_clks++;
+
+                               num_parents = sci_clk->num_parents;
+                               if (num_parents == 1)
+                                       num_parents = 0;
+
+                               /*
+                                * Linux kernel has inherent limitation
+                                * of 255 clock parents at the moment.
+                                * Right now, it is not expected that
+                                * any mux clock from sci-clk driver
+                                * would exceed that limit either, but
+                                * the ABI basically provides that
+                                * possibility. Print out a warning if
+                                * this happens for any clock.
+                                */
+                               if (num_parents >= 255) {
+                                       dev_warn(dev, "too many parents for dev=%d, clk=%d (%d), cropping to 255.\n",
+                                                sci_clk->dev_id,
+                                                sci_clk->clk_id, num_parents);
+                                       num_parents = 255;
+                               }
+
+                               clk_id = args.args[1] + 1;
+
+                               while (num_parents--) {
+                                       sci_clk = devm_kzalloc(dev,
+                                                              sizeof(*sci_clk),
+                                                              GFP_KERNEL);
+                                       if (!sci_clk)
+                                               return -ENOMEM;
+                                       sci_clk->dev_id = args.args[0];
+                                       sci_clk->clk_id = clk_id++;
+                                       sci_clk->provider = provider;
+                                       list_add_tail(&sci_clk->node, &clks);
+
+                                       num_clks++;
+                               }
+                       }
+
+                       index++;
+               } while (args.np);
+       }
+
+       list_sort(NULL, &clks, _cmp_sci_clk_list);
+
+       provider->clocks = devm_kmalloc_array(dev, num_clks, sizeof(sci_clk),
+                                             GFP_KERNEL);
+       if (!provider->clocks)
+               return -ENOMEM;
+
+       num_clks = 0;
+       prev = NULL;
+
+       list_for_each_entry(sci_clk, &clks, node) {
+               if (prev && prev->dev_id == sci_clk->dev_id &&
+                   prev->clk_id == sci_clk->clk_id)
+                       continue;
+
+               provider->clocks[num_clks++] = sci_clk;
+               prev = sci_clk;
+       }
+
+       provider->num_clocks = num_clks;
+
+       return 0;
+}
+#endif
+
+/**
+ * ti_sci_clk_probe - Probe function for the TI SCI clock driver
+ * @pdev: platform device pointer to be probed
+ *
+ * Probes the TI SCI clock device. Allocates a new clock provider
+ * and registers this to the common clock framework. Also applies
+ * any required flags to the identified clocks via clock lists
+ * supplied from DT. Returns 0 for success, negative error value
+ * for failure.
+ */
+static int ti_sci_clk_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct sci_clk_provider *provider;
+       const struct ti_sci_handle *handle;
+       int ret;
+
+       handle = devm_ti_sci_get_handle(dev);
+       if (IS_ERR(handle))
+               return PTR_ERR(handle);
+
+       provider = devm_kzalloc(dev, sizeof(*provider), GFP_KERNEL);
+       if (!provider)
+               return -ENOMEM;
+
+       provider->sci = handle;
+       provider->ops = &handle->ops.clk_ops;
+       provider->dev = dev;
+
+#ifdef CONFIG_TI_SCI_CLK_PROBE_FROM_FW
+       ret = ti_sci_scan_clocks_from_fw(provider);
+       if (ret) {
+               dev_err(dev, "scan clocks from FW failed: %d\n", ret);
+               return ret;
+       }
+#else
+       ret = ti_sci_scan_clocks_from_dt(provider);
+       if (ret) {
+               dev_err(dev, "scan clocks from DT failed: %d\n", ret);
+               return ret;
+       }
+#endif
+
        ret = ti_sci_init_clocks(provider);
        if (ret) {
                pr_err("ti-sci-init-clocks failed.\n");
index f797f09..ce3d9b3 100644 (file)
@@ -300,4 +300,10 @@ config COMMON_CLK_MT8516
        help
          This driver supports MediaTek MT8516 clocks.
 
+config COMMON_CLK_MT8516_AUDSYS
+       bool "Clock driver for MediaTek MT8516 audsys"
+       depends on COMMON_CLK_MT8516
+       help
+         This driver supports MediaTek MT8516 audsys clocks.
+
 endmenu
index f74937b..672de00 100644 (file)
@@ -45,3 +45,4 @@ obj-$(CONFIG_COMMON_CLK_MT8183_MMSYS) += clk-mt8183-mm.o
 obj-$(CONFIG_COMMON_CLK_MT8183_VDECSYS) += clk-mt8183-vdec.o
 obj-$(CONFIG_COMMON_CLK_MT8183_VENCSYS) += clk-mt8183-venc.o
 obj-$(CONFIG_COMMON_CLK_MT8516) += clk-mt8516.o
+obj-$(CONFIG_COMMON_CLK_MT8516_AUDSYS) += clk-mt8516-aud.o
index 9d86510..1aa5f40 100644 (file)
@@ -395,14 +395,6 @@ static const char * const atb_parents[] = {
        "syspll_d5"
 };
 
-static const char * const sspm_parents[] = {
-       "clk26m",
-       "univpll_d2_d4",
-       "syspll_d2_d2",
-       "univpll_d2_d2",
-       "syspll_d3"
-};
-
 static const char * const dpi0_parents[] = {
        "clk26m",
        "tvdpll_d2",
@@ -606,9 +598,6 @@ static const struct mtk_mux top_muxes[] = {
        MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_ATB, "atb_sel",
                atb_parents, 0xa0,
                0xa4, 0xa8, 0, 2, 7, 0x004, 24),
-       MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_SSPM, "sspm_sel",
-               sspm_parents, 0xa0,
-               0xa4, 0xa8, 8, 3, 15, 0x004, 25),
        MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_DPI0, "dpi0_sel",
                dpi0_parents, 0xa0,
                0xa4, 0xa8, 16, 4, 23, 0x004, 26),
@@ -947,12 +936,8 @@ static const struct mtk_gate infra_clks[] = {
                "fufs_sel", 13),
        GATE_INFRA2(CLK_INFRA_MD32_BCLK, "infra_md32_bclk",
                "axi_sel", 14),
-       GATE_INFRA2(CLK_INFRA_SSPM, "infra_sspm",
-               "sspm_sel", 15),
        GATE_INFRA2(CLK_INFRA_UNIPRO_MBIST, "infra_unipro_mbist",
                "axi_sel", 16),
-       GATE_INFRA2(CLK_INFRA_SSPM_BUS_HCLK, "infra_sspm_bus_hclk",
-               "axi_sel", 17),
        GATE_INFRA2(CLK_INFRA_I2C5, "infra_i2c5",
                "i2c_sel", 18),
        GATE_INFRA2(CLK_INFRA_I2C5_ARBITER, "infra_i2c5_arbiter",
@@ -986,10 +971,6 @@ static const struct mtk_gate infra_clks[] = {
                "msdc50_0_sel", 1),
        GATE_INFRA3(CLK_INFRA_MSDC2_SELF, "infra_msdc2_self",
                "msdc50_0_sel", 2),
-       GATE_INFRA3(CLK_INFRA_SSPM_26M_SELF, "infra_sspm_26m_self",
-               "f_f26m_ck", 3),
-       GATE_INFRA3(CLK_INFRA_SSPM_32K_SELF, "infra_sspm_32k_self",
-               "f_f26m_ck", 4),
        GATE_INFRA3(CLK_INFRA_UFS_AXI, "infra_ufs_axi",
                "axi_sel", 5),
        GATE_INFRA3(CLK_INFRA_I2C6, "infra_i2c6",
diff --git a/drivers/clk/mediatek/clk-mt8516-aud.c b/drivers/clk/mediatek/clk-mt8516-aud.c
new file mode 100644 (file)
index 0000000..6ab3a06
--- /dev/null
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ * Author: James Liao <jamesjj.liao@mediatek.com>
+ *         Fabien Parent <fparent@baylibre.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include "clk-mtk.h"
+#include "clk-gate.h"
+
+#include <dt-bindings/clock/mt8516-clk.h>
+
+static const struct mtk_gate_regs aud_cg_regs = {
+       .set_ofs = 0x0,
+       .clr_ofs = 0x0,
+       .sta_ofs = 0x0,
+};
+
+#define GATE_AUD(_id, _name, _parent, _shift) {        \
+               .id = _id,                      \
+               .name = _name,                  \
+               .parent_name = _parent,         \
+               .regs = &aud_cg_regs,           \
+               .shift = _shift,                \
+               .ops = &mtk_clk_gate_ops_no_setclr,             \
+       }
+
+static const struct mtk_gate aud_clks[] __initconst = {
+       GATE_AUD(CLK_AUD_AFE, "aud_afe", "clk26m_ck", 2),
+       GATE_AUD(CLK_AUD_I2S, "aud_i2s", "i2s_infra_bck", 6),
+       GATE_AUD(CLK_AUD_22M, "aud_22m", "rg_aud_engen1", 8),
+       GATE_AUD(CLK_AUD_24M, "aud_24m", "rg_aud_engen2", 9),
+       GATE_AUD(CLK_AUD_INTDIR, "aud_intdir", "rg_aud_spdif_in", 15),
+       GATE_AUD(CLK_AUD_APLL2_TUNER, "aud_apll2_tuner", "rg_aud_engen2", 18),
+       GATE_AUD(CLK_AUD_APLL_TUNER, "aud_apll_tuner", "rg_aud_engen1", 19),
+       GATE_AUD(CLK_AUD_HDMI, "aud_hdmi", "apll12_div4", 20),
+       GATE_AUD(CLK_AUD_SPDF, "aud_spdf", "apll12_div6", 21),
+       GATE_AUD(CLK_AUD_ADC, "aud_adc", "aud_afe", 24),
+       GATE_AUD(CLK_AUD_DAC, "aud_dac", "aud_afe", 25),
+       GATE_AUD(CLK_AUD_DAC_PREDIS, "aud_dac_predis", "aud_afe", 26),
+       GATE_AUD(CLK_AUD_TML, "aud_tml", "aud_afe", 27),
+};
+
+static void __init mtk_audsys_init(struct device_node *node)
+{
+       struct clk_onecell_data *clk_data;
+       int r;
+
+       clk_data = mtk_alloc_clk_data(CLK_AUD_NR_CLK);
+
+       mtk_clk_register_gates(node, aud_clks, ARRAY_SIZE(aud_clks), clk_data);
+
+       r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+       if (r)
+               pr_err("%s(): could not register clock provider: %d\n",
+                       __func__, r);
+
+}
+CLK_OF_DECLARE(mtk_audsys, "mediatek,mt8516-audsys", mtk_audsys_init);
index 26fe43c..9d4261e 100644 (file)
@@ -231,11 +231,6 @@ static const char * const nfi1x_pad_parents[] __initconst = {
        "nfi1x_ck"
 };
 
-static const char * const ddrphycfg_parents[] __initconst = {
-       "clk26m_ck",
-       "mainpll_d16"
-};
-
 static const char * const usb_78m_parents[] __initconst = {
        "clk_null",
        "clk26m_ck",
index 7a8ef80..3ddd0ef 100644 (file)
@@ -469,11 +469,6 @@ static struct clk_regmap axg_mpll0_div = {
                        .shift   = 16,
                        .width   = 9,
                },
-               .ssen = {
-                       .reg_off = HHI_MPLL_CNTL,
-                       .shift   = 25,
-                       .width   = 1,
-               },
                .misc = {
                        .reg_off = HHI_PLL_TOP_MISC,
                        .shift   = 0,
@@ -568,6 +563,11 @@ static struct clk_regmap axg_mpll2_div = {
                        .shift   = 16,
                        .width   = 9,
                },
+               .ssen = {
+                       .reg_off = HHI_MPLL_CNTL,
+                       .shift   = 25,
+                       .width   = 1,
+               },
                .misc = {
                        .reg_off = HHI_PLL_TOP_MISC,
                        .shift   = 2,
index f76850d..2d39a8b 100644 (file)
@@ -115,21 +115,12 @@ static int mpll_set_rate(struct clk_hw *hw,
        else
                __acquire(mpll->lock);
 
-       /* Enable and set the fractional part */
+       /* Set the fractional part */
        meson_parm_write(clk->map, &mpll->sdm, sdm);
-       meson_parm_write(clk->map, &mpll->sdm_en, 1);
-
-       /* Set additional fractional part enable if required */
-       if (MESON_PARM_APPLICABLE(&mpll->ssen))
-               meson_parm_write(clk->map, &mpll->ssen, 1);
 
        /* Set the integer divider part */
        meson_parm_write(clk->map, &mpll->n2, n2);
 
-       /* Set the magic misc bit if required */
-       if (MESON_PARM_APPLICABLE(&mpll->misc))
-               meson_parm_write(clk->map, &mpll->misc, 1);
-
        if (mpll->lock)
                spin_unlock_irqrestore(mpll->lock, flags);
        else
@@ -138,6 +129,30 @@ static int mpll_set_rate(struct clk_hw *hw,
        return 0;
 }
 
+static void mpll_init(struct clk_hw *hw)
+{
+       struct clk_regmap *clk = to_clk_regmap(hw);
+       struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk);
+
+       if (mpll->init_count)
+               regmap_multi_reg_write(clk->map, mpll->init_regs,
+                                      mpll->init_count);
+
+       /* Enable the fractional part */
+       meson_parm_write(clk->map, &mpll->sdm_en, 1);
+
+       /* Set spread spectrum if possible */
+       if (MESON_PARM_APPLICABLE(&mpll->ssen)) {
+               unsigned int ss =
+                       mpll->flags & CLK_MESON_MPLL_SPREAD_SPECTRUM ? 1 : 0;
+               meson_parm_write(clk->map, &mpll->ssen, ss);
+       }
+
+       /* Set the magic misc bit if required */
+       if (MESON_PARM_APPLICABLE(&mpll->misc))
+               meson_parm_write(clk->map, &mpll->misc, 1);
+}
+
 const struct clk_ops meson_clk_mpll_ro_ops = {
        .recalc_rate    = mpll_recalc_rate,
        .round_rate     = mpll_round_rate,
@@ -148,6 +163,7 @@ const struct clk_ops meson_clk_mpll_ops = {
        .recalc_rate    = mpll_recalc_rate,
        .round_rate     = mpll_round_rate,
        .set_rate       = mpll_set_rate,
+       .init           = mpll_init,
 };
 EXPORT_SYMBOL_GPL(meson_clk_mpll_ops);
 
index cf79340..a991d56 100644 (file)
@@ -18,11 +18,14 @@ struct meson_clk_mpll_data {
        struct parm n2;
        struct parm ssen;
        struct parm misc;
+       const struct reg_sequence *init_regs;
+       unsigned int init_count;
        spinlock_t *lock;
        u8 flags;
 };
 
 #define CLK_MESON_MPLL_ROUND_CLOSEST   BIT(0)
+#define CLK_MESON_MPLL_SPREAD_SPECTRUM BIT(1)
 
 extern const struct clk_ops meson_clk_mpll_ro_ops;
 extern const struct clk_ops meson_clk_mpll_ops;
index 206fafd..db1c4ed 100644 (file)
@@ -150,6 +150,57 @@ static struct clk_regmap g12a_sys_pll = {
        },
 };
 
+static struct clk_regmap g12b_sys1_pll_dco = {
+       .data = &(struct meson_clk_pll_data){
+               .en = {
+                       .reg_off = HHI_SYS1_PLL_CNTL0,
+                       .shift   = 28,
+                       .width   = 1,
+               },
+               .m = {
+                       .reg_off = HHI_SYS1_PLL_CNTL0,
+                       .shift   = 0,
+                       .width   = 8,
+               },
+               .n = {
+                       .reg_off = HHI_SYS1_PLL_CNTL0,
+                       .shift   = 10,
+                       .width   = 5,
+               },
+               .l = {
+                       .reg_off = HHI_SYS1_PLL_CNTL0,
+                       .shift   = 31,
+                       .width   = 1,
+               },
+               .rst = {
+                       .reg_off = HHI_SYS1_PLL_CNTL0,
+                       .shift   = 29,
+                       .width   = 1,
+               },
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "sys1_pll_dco",
+               .ops = &meson_clk_pll_ro_ops,
+               .parent_names = (const char *[]){ IN_PREFIX "xtal" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12b_sys1_pll = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_SYS1_PLL_CNTL0,
+               .shift = 16,
+               .width = 3,
+               .flags = CLK_DIVIDER_POWER_OF_TWO,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "sys1_pll",
+               .ops = &clk_regmap_divider_ro_ops,
+               .parent_names = (const char *[]){ "sys1_pll_dco" },
+               .num_parents = 1,
+       },
+};
+
 static struct clk_regmap g12a_sys_pll_div16_en = {
        .data = &(struct clk_regmap_gate_data){
                .offset = HHI_SYS_CPU_CLK_CNTL1,
@@ -167,6 +218,23 @@ static struct clk_regmap g12a_sys_pll_div16_en = {
        },
 };
 
+static struct clk_regmap g12b_sys1_pll_div16_en = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL1,
+               .bit_idx = 24,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "sys1_pll_div16_en",
+               .ops = &clk_regmap_gate_ro_ops,
+               .parent_names = (const char *[]){ "sys1_pll" },
+               .num_parents = 1,
+               /*
+                * This clock is used to debug the sys_pll range
+                * Linux should not change it at runtime
+                */
+       },
+};
+
 static struct clk_fixed_factor g12a_sys_pll_div16 = {
        .mult = 1,
        .div = 16,
@@ -178,6 +246,17 @@ static struct clk_fixed_factor g12a_sys_pll_div16 = {
        },
 };
 
+static struct clk_fixed_factor g12b_sys1_pll_div16 = {
+       .mult = 1,
+       .div = 16,
+       .hw.init = &(struct clk_init_data){
+               .name = "sys1_pll_div16",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "sys1_pll_div16_en" },
+               .num_parents = 1,
+       },
+};
+
 /* Datasheet names this field as "premux0" */
 static struct clk_regmap g12a_cpu_clk_premux0 = {
        .data = &(struct clk_regmap_mux_data){
@@ -306,6 +385,150 @@ static struct clk_regmap g12a_cpu_clk = {
        },
 };
 
+/* Datasheet names this field as "Final_mux_sel" */
+static struct clk_regmap g12b_cpu_clk = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SYS_CPU_CLK_CNTL0,
+               .mask = 0x1,
+               .shift = 11,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpu_clk",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ "cpu_clk_dyn",
+                                                 "sys1_pll" },
+               .num_parents = 2,
+       },
+};
+
+/* Datasheet names this field as "premux0" */
+static struct clk_regmap g12b_cpub_clk_premux0 = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL,
+               .mask = 0x3,
+               .shift = 0,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_dyn0_sel",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ IN_PREFIX "xtal",
+                                                 "fclk_div2",
+                                                 "fclk_div3" },
+               .num_parents = 3,
+       },
+};
+
+/* Datasheet names this field as "mux0_divn_tcnt" */
+static struct clk_regmap g12b_cpub_clk_mux0_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL,
+               .shift = 4,
+               .width = 6,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_dyn0_div",
+               .ops = &clk_regmap_divider_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_dyn0_sel" },
+               .num_parents = 1,
+       },
+};
+
+/* Datasheet names this field as "postmux0" */
+static struct clk_regmap g12b_cpub_clk_postmux0 = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL,
+               .mask = 0x1,
+               .shift = 2,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_dyn0",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_dyn0_sel",
+                                                 "cpub_clk_dyn0_div" },
+               .num_parents = 2,
+       },
+};
+
+/* Datasheet names this field as "premux1" */
+static struct clk_regmap g12b_cpub_clk_premux1 = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL,
+               .mask = 0x3,
+               .shift = 16,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_dyn1_sel",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ IN_PREFIX "xtal",
+                                                 "fclk_div2",
+                                                 "fclk_div3" },
+               .num_parents = 3,
+       },
+};
+
+/* Datasheet names this field as "Mux1_divn_tcnt" */
+static struct clk_regmap g12b_cpub_clk_mux1_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL,
+               .shift = 20,
+               .width = 6,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_dyn1_div",
+               .ops = &clk_regmap_divider_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_dyn1_sel" },
+               .num_parents = 1,
+       },
+};
+
+/* Datasheet names this field as "postmux1" */
+static struct clk_regmap g12b_cpub_clk_postmux1 = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL,
+               .mask = 0x1,
+               .shift = 18,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_dyn1",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_dyn1_sel",
+                                                 "cpub_clk_dyn1_div" },
+               .num_parents = 2,
+       },
+};
+
+/* Datasheet names this field as "Final_dyn_mux_sel" */
+static struct clk_regmap g12b_cpub_clk_dyn = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL,
+               .mask = 0x1,
+               .shift = 10,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_dyn",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_dyn0",
+                                                 "cpub_clk_dyn1" },
+               .num_parents = 2,
+       },
+};
+
+/* Datasheet names this field as "Final_mux_sel" */
+static struct clk_regmap g12b_cpub_clk = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL,
+               .mask = 0x1,
+               .shift = 11,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_dyn",
+                                                 "sys_pll" },
+               .num_parents = 2,
+       },
+};
+
 static struct clk_regmap g12a_cpu_clk_div16_en = {
        .data = &(struct clk_regmap_gate_data){
                .offset = HHI_SYS_CPU_CLK_CNTL1,
@@ -323,6 +546,23 @@ static struct clk_regmap g12a_cpu_clk_div16_en = {
        },
 };
 
+static struct clk_regmap g12b_cpub_clk_div16_en = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL1,
+               .bit_idx = 1,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "cpub_clk_div16_en",
+               .ops = &clk_regmap_gate_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk" },
+               .num_parents = 1,
+               /*
+                * This clock is used to debug the cpu_clk range
+                * Linux should not change it at runtime
+                */
+       },
+};
+
 static struct clk_fixed_factor g12a_cpu_clk_div16 = {
        .mult = 1,
        .div = 16,
@@ -334,6 +574,17 @@ static struct clk_fixed_factor g12a_cpu_clk_div16 = {
        },
 };
 
+static struct clk_fixed_factor g12b_cpub_clk_div16 = {
+       .mult = 1,
+       .div = 16,
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_div16",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "cpub_clk_div16_en" },
+               .num_parents = 1,
+       },
+};
+
 static struct clk_regmap g12a_cpu_clk_apb_div = {
        .data = &(struct clk_regmap_div_data){
                .offset = HHI_SYS_CPU_CLK_CNTL1,
@@ -445,15 +696,249 @@ static struct clk_regmap g12a_cpu_clk_trace_div = {
        },
 };
 
-static struct clk_regmap g12a_cpu_clk_trace = {
+static struct clk_regmap g12a_cpu_clk_trace = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_SYS_CPU_CLK_CNTL1,
+               .bit_idx = 23,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "cpu_clk_trace",
+               .ops = &clk_regmap_gate_ro_ops,
+               .parent_names = (const char *[]){ "cpu_clk_trace_div" },
+               .num_parents = 1,
+               /*
+                * This clock is set by the ROM monitor code,
+                * Linux should not change it at runtime
+                */
+       },
+};
+
+static struct clk_fixed_factor g12b_cpub_clk_div2 = {
+       .mult = 1,
+       .div = 2,
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_div2",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "cpub_clk" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12b_cpub_clk_div3 = {
+       .mult = 1,
+       .div = 3,
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_div3",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "cpub_clk" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12b_cpub_clk_div4 = {
+       .mult = 1,
+       .div = 4,
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_div4",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "cpub_clk" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12b_cpub_clk_div5 = {
+       .mult = 1,
+       .div = 5,
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_div5",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "cpub_clk" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12b_cpub_clk_div6 = {
+       .mult = 1,
+       .div = 6,
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_div6",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "cpub_clk" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12b_cpub_clk_div7 = {
+       .mult = 1,
+       .div = 7,
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_div7",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "cpub_clk" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12b_cpub_clk_div8 = {
+       .mult = 1,
+       .div = 8,
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_div8",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "cpub_clk" },
+               .num_parents = 1,
+       },
+};
+
+static u32 mux_table_cpub[] = { 1, 2, 3, 4, 5, 6, 7 };
+static struct clk_regmap g12b_cpub_clk_apb_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL1,
+               .mask = 7,
+               .shift = 3,
+               .table = mux_table_cpub,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_apb_sel",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_div2",
+                                                 "cpub_clk_div3",
+                                                 "cpub_clk_div4",
+                                                 "cpub_clk_div5",
+                                                 "cpub_clk_div6",
+                                                 "cpub_clk_div7",
+                                                 "cpub_clk_div8" },
+               .num_parents = 7,
+       },
+};
+
+static struct clk_regmap g12b_cpub_clk_apb = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL1,
+               .bit_idx = 16,
+               .flags = CLK_GATE_SET_TO_DISABLE,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "cpub_clk_apb",
+               .ops = &clk_regmap_gate_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_apb_sel" },
+               .num_parents = 1,
+               /*
+                * This clock is set by the ROM monitor code,
+                * Linux should not change it at runtime
+                */
+       },
+};
+
+static struct clk_regmap g12b_cpub_clk_atb_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL1,
+               .mask = 7,
+               .shift = 6,
+               .table = mux_table_cpub,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_atb_sel",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_div2",
+                                                 "cpub_clk_div3",
+                                                 "cpub_clk_div4",
+                                                 "cpub_clk_div5",
+                                                 "cpub_clk_div6",
+                                                 "cpub_clk_div7",
+                                                 "cpub_clk_div8" },
+               .num_parents = 7,
+       },
+};
+
+static struct clk_regmap g12b_cpub_clk_atb = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL1,
+               .bit_idx = 17,
+               .flags = CLK_GATE_SET_TO_DISABLE,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "cpub_clk_atb",
+               .ops = &clk_regmap_gate_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_atb_sel" },
+               .num_parents = 1,
+               /*
+                * This clock is set by the ROM monitor code,
+                * Linux should not change it at runtime
+                */
+       },
+};
+
+static struct clk_regmap g12b_cpub_clk_axi_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL1,
+               .mask = 7,
+               .shift = 9,
+               .table = mux_table_cpub,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_axi_sel",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_div2",
+                                                 "cpub_clk_div3",
+                                                 "cpub_clk_div4",
+                                                 "cpub_clk_div5",
+                                                 "cpub_clk_div6",
+                                                 "cpub_clk_div7",
+                                                 "cpub_clk_div8" },
+               .num_parents = 7,
+       },
+};
+
+static struct clk_regmap g12b_cpub_clk_axi = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL1,
+               .bit_idx = 18,
+               .flags = CLK_GATE_SET_TO_DISABLE,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "cpub_clk_axi",
+               .ops = &clk_regmap_gate_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_axi_sel" },
+               .num_parents = 1,
+               /*
+                * This clock is set by the ROM monitor code,
+                * Linux should not change it at runtime
+                */
+       },
+};
+
+static struct clk_regmap g12b_cpub_clk_trace_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL1,
+               .mask = 7,
+               .shift = 20,
+               .table = mux_table_cpub,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_trace_sel",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_div2",
+                                                 "cpub_clk_div3",
+                                                 "cpub_clk_div4",
+                                                 "cpub_clk_div5",
+                                                 "cpub_clk_div6",
+                                                 "cpub_clk_div7",
+                                                 "cpub_clk_div8" },
+               .num_parents = 7,
+       },
+};
+
+static struct clk_regmap g12b_cpub_clk_trace = {
        .data = &(struct clk_regmap_gate_data){
-               .offset = HHI_SYS_CPU_CLK_CNTL1,
+               .offset = HHI_SYS_CPUB_CLK_CNTL1,
                .bit_idx = 23,
+               .flags = CLK_GATE_SET_TO_DISABLE,
        },
        .hw.init = &(struct clk_init_data) {
-               .name = "cpu_clk_trace",
+               .name = "cpub_clk_trace",
                .ops = &clk_regmap_gate_ro_ops,
-               .parent_names = (const char *[]){ "cpu_clk_trace_div" },
+               .parent_names = (const char *[]){ "cpub_clk_trace_sel" },
                .num_parents = 1,
                /*
                 * This clock is set by the ROM monitor code,
@@ -865,6 +1350,16 @@ static struct clk_regmap g12a_fclk_div3 = {
                .ops = &clk_regmap_gate_ops,
                .parent_names = (const char *[]){ "fclk_div3_div" },
                .num_parents = 1,
+               /*
+                * This clock is used by the resident firmware and is required
+                * by the platform to operate correctly.
+                * Until the following condition are met, we need this clock to
+                * be marked as critical:
+                * a) Mark the clock used by a firmware resource, if possible
+                * b) CCF has a clock hand-off mechanism to make the sure the
+                *    clock stays on until the proper driver comes along
+                */
+               .flags = CLK_IS_CRITICAL,
        },
 };
 
@@ -1001,6 +1496,10 @@ static struct clk_fixed_factor g12a_mpll_prediv = {
        },
 };
 
+static const struct reg_sequence g12a_mpll0_init_regs[] = {
+       { .reg = HHI_MPLL_CNTL2,        .def = 0x40000033 },
+};
+
 static struct clk_regmap g12a_mpll0_div = {
        .data = &(struct meson_clk_mpll_data){
                .sdm = {
@@ -1024,6 +1523,8 @@ static struct clk_regmap g12a_mpll0_div = {
                        .width   = 1,
                },
                .lock = &meson_clk_lock,
+               .init_regs = g12a_mpll0_init_regs,
+               .init_count = ARRAY_SIZE(g12a_mpll0_init_regs),
        },
        .hw.init = &(struct clk_init_data){
                .name = "mpll0_div",
@@ -1047,6 +1548,10 @@ static struct clk_regmap g12a_mpll0 = {
        },
 };
 
+static const struct reg_sequence g12a_mpll1_init_regs[] = {
+       { .reg = HHI_MPLL_CNTL4,        .def = 0x40000033 },
+};
+
 static struct clk_regmap g12a_mpll1_div = {
        .data = &(struct meson_clk_mpll_data){
                .sdm = {
@@ -1070,6 +1575,8 @@ static struct clk_regmap g12a_mpll1_div = {
                        .width   = 1,
                },
                .lock = &meson_clk_lock,
+               .init_regs = g12a_mpll1_init_regs,
+               .init_count = ARRAY_SIZE(g12a_mpll1_init_regs),
        },
        .hw.init = &(struct clk_init_data){
                .name = "mpll1_div",
@@ -1093,6 +1600,10 @@ static struct clk_regmap g12a_mpll1 = {
        },
 };
 
+static const struct reg_sequence g12a_mpll2_init_regs[] = {
+       { .reg = HHI_MPLL_CNTL6,        .def = 0x40000033 },
+};
+
 static struct clk_regmap g12a_mpll2_div = {
        .data = &(struct meson_clk_mpll_data){
                .sdm = {
@@ -1116,6 +1627,8 @@ static struct clk_regmap g12a_mpll2_div = {
                        .width   = 1,
                },
                .lock = &meson_clk_lock,
+               .init_regs = g12a_mpll2_init_regs,
+               .init_count = ARRAY_SIZE(g12a_mpll2_init_regs),
        },
        .hw.init = &(struct clk_init_data){
                .name = "mpll2_div",
@@ -1139,6 +1652,10 @@ static struct clk_regmap g12a_mpll2 = {
        },
 };
 
+static const struct reg_sequence g12a_mpll3_init_regs[] = {
+       { .reg = HHI_MPLL_CNTL8,        .def = 0x40000033 },
+};
+
 static struct clk_regmap g12a_mpll3_div = {
        .data = &(struct meson_clk_mpll_data){
                .sdm = {
@@ -1162,6 +1679,8 @@ static struct clk_regmap g12a_mpll3_div = {
                        .width   = 1,
                },
                .lock = &meson_clk_lock,
+               .init_regs = g12a_mpll3_init_regs,
+               .init_count = ARRAY_SIZE(g12a_mpll3_init_regs),
        },
        .hw.init = &(struct clk_init_data){
                .name = "mpll3_div",
@@ -2480,6 +2999,33 @@ static struct clk_regmap g12a_mali = {
        },
 };
 
+static struct clk_regmap g12a_ts_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_TS_CLK_CNTL,
+               .shift = 0,
+               .width = 8,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "ts_div",
+               .ops = &clk_regmap_divider_ro_ops,
+               .parent_names = (const char *[]){ "xtal" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12a_ts = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_TS_CLK_CNTL,
+               .bit_idx = 8,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "ts",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "ts_div" },
+               .num_parents = 1,
+       },
+};
+
 /* Everything Else (EE) domain gates */
 static MESON_GATE(g12a_ddr,                    HHI_GCLK_MPEG0, 0);
 static MESON_GATE(g12a_dos,                    HHI_GCLK_MPEG0, 1);
@@ -2769,6 +3315,257 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = {
                [CLKID_VDEC_HEVCF_SEL]          = &g12a_vdec_hevcf_sel.hw,
                [CLKID_VDEC_HEVCF_DIV]          = &g12a_vdec_hevcf_div.hw,
                [CLKID_VDEC_HEVCF]              = &g12a_vdec_hevcf.hw,
+               [CLKID_TS_DIV]                  = &g12a_ts_div.hw,
+               [CLKID_TS]                      = &g12a_ts.hw,
+               [NR_CLKS]                       = NULL,
+       },
+       .num = NR_CLKS,
+};
+
+static struct clk_hw_onecell_data g12b_hw_onecell_data = {
+       .hws = {
+               [CLKID_SYS_PLL]                 = &g12a_sys_pll.hw,
+               [CLKID_FIXED_PLL]               = &g12a_fixed_pll.hw,
+               [CLKID_FCLK_DIV2]               = &g12a_fclk_div2.hw,
+               [CLKID_FCLK_DIV3]               = &g12a_fclk_div3.hw,
+               [CLKID_FCLK_DIV4]               = &g12a_fclk_div4.hw,
+               [CLKID_FCLK_DIV5]               = &g12a_fclk_div5.hw,
+               [CLKID_FCLK_DIV7]               = &g12a_fclk_div7.hw,
+               [CLKID_FCLK_DIV2P5]             = &g12a_fclk_div2p5.hw,
+               [CLKID_GP0_PLL]                 = &g12a_gp0_pll.hw,
+               [CLKID_MPEG_SEL]                = &g12a_mpeg_clk_sel.hw,
+               [CLKID_MPEG_DIV]                = &g12a_mpeg_clk_div.hw,
+               [CLKID_CLK81]                   = &g12a_clk81.hw,
+               [CLKID_MPLL0]                   = &g12a_mpll0.hw,
+               [CLKID_MPLL1]                   = &g12a_mpll1.hw,
+               [CLKID_MPLL2]                   = &g12a_mpll2.hw,
+               [CLKID_MPLL3]                   = &g12a_mpll3.hw,
+               [CLKID_DDR]                     = &g12a_ddr.hw,
+               [CLKID_DOS]                     = &g12a_dos.hw,
+               [CLKID_AUDIO_LOCKER]            = &g12a_audio_locker.hw,
+               [CLKID_MIPI_DSI_HOST]           = &g12a_mipi_dsi_host.hw,
+               [CLKID_ETH_PHY]                 = &g12a_eth_phy.hw,
+               [CLKID_ISA]                     = &g12a_isa.hw,
+               [CLKID_PL301]                   = &g12a_pl301.hw,
+               [CLKID_PERIPHS]                 = &g12a_periphs.hw,
+               [CLKID_SPICC0]                  = &g12a_spicc_0.hw,
+               [CLKID_I2C]                     = &g12a_i2c.hw,
+               [CLKID_SANA]                    = &g12a_sana.hw,
+               [CLKID_SD]                      = &g12a_sd.hw,
+               [CLKID_RNG0]                    = &g12a_rng0.hw,
+               [CLKID_UART0]                   = &g12a_uart0.hw,
+               [CLKID_SPICC1]                  = &g12a_spicc_1.hw,
+               [CLKID_HIU_IFACE]               = &g12a_hiu_reg.hw,
+               [CLKID_MIPI_DSI_PHY]            = &g12a_mipi_dsi_phy.hw,
+               [CLKID_ASSIST_MISC]             = &g12a_assist_misc.hw,
+               [CLKID_SD_EMMC_A]               = &g12a_emmc_a.hw,
+               [CLKID_SD_EMMC_B]               = &g12a_emmc_b.hw,
+               [CLKID_SD_EMMC_C]               = &g12a_emmc_c.hw,
+               [CLKID_AUDIO_CODEC]             = &g12a_audio_codec.hw,
+               [CLKID_AUDIO]                   = &g12a_audio.hw,
+               [CLKID_ETH]                     = &g12a_eth_core.hw,
+               [CLKID_DEMUX]                   = &g12a_demux.hw,
+               [CLKID_AUDIO_IFIFO]             = &g12a_audio_ififo.hw,
+               [CLKID_ADC]                     = &g12a_adc.hw,
+               [CLKID_UART1]                   = &g12a_uart1.hw,
+               [CLKID_G2D]                     = &g12a_g2d.hw,
+               [CLKID_RESET]                   = &g12a_reset.hw,
+               [CLKID_PCIE_COMB]               = &g12a_pcie_comb.hw,
+               [CLKID_PARSER]                  = &g12a_parser.hw,
+               [CLKID_USB]                     = &g12a_usb_general.hw,
+               [CLKID_PCIE_PHY]                = &g12a_pcie_phy.hw,
+               [CLKID_AHB_ARB0]                = &g12a_ahb_arb0.hw,
+               [CLKID_AHB_DATA_BUS]            = &g12a_ahb_data_bus.hw,
+               [CLKID_AHB_CTRL_BUS]            = &g12a_ahb_ctrl_bus.hw,
+               [CLKID_HTX_HDCP22]              = &g12a_htx_hdcp22.hw,
+               [CLKID_HTX_PCLK]                = &g12a_htx_pclk.hw,
+               [CLKID_BT656]                   = &g12a_bt656.hw,
+               [CLKID_USB1_DDR_BRIDGE]         = &g12a_usb1_to_ddr.hw,
+               [CLKID_MMC_PCLK]                = &g12a_mmc_pclk.hw,
+               [CLKID_UART2]                   = &g12a_uart2.hw,
+               [CLKID_VPU_INTR]                = &g12a_vpu_intr.hw,
+               [CLKID_GIC]                     = &g12a_gic.hw,
+               [CLKID_SD_EMMC_A_CLK0_SEL]      = &g12a_sd_emmc_a_clk0_sel.hw,
+               [CLKID_SD_EMMC_A_CLK0_DIV]      = &g12a_sd_emmc_a_clk0_div.hw,
+               [CLKID_SD_EMMC_A_CLK0]          = &g12a_sd_emmc_a_clk0.hw,
+               [CLKID_SD_EMMC_B_CLK0_SEL]      = &g12a_sd_emmc_b_clk0_sel.hw,
+               [CLKID_SD_EMMC_B_CLK0_DIV]      = &g12a_sd_emmc_b_clk0_div.hw,
+               [CLKID_SD_EMMC_B_CLK0]          = &g12a_sd_emmc_b_clk0.hw,
+               [CLKID_SD_EMMC_C_CLK0_SEL]      = &g12a_sd_emmc_c_clk0_sel.hw,
+               [CLKID_SD_EMMC_C_CLK0_DIV]      = &g12a_sd_emmc_c_clk0_div.hw,
+               [CLKID_SD_EMMC_C_CLK0]          = &g12a_sd_emmc_c_clk0.hw,
+               [CLKID_MPLL0_DIV]               = &g12a_mpll0_div.hw,
+               [CLKID_MPLL1_DIV]               = &g12a_mpll1_div.hw,
+               [CLKID_MPLL2_DIV]               = &g12a_mpll2_div.hw,
+               [CLKID_MPLL3_DIV]               = &g12a_mpll3_div.hw,
+               [CLKID_FCLK_DIV2_DIV]           = &g12a_fclk_div2_div.hw,
+               [CLKID_FCLK_DIV3_DIV]           = &g12a_fclk_div3_div.hw,
+               [CLKID_FCLK_DIV4_DIV]           = &g12a_fclk_div4_div.hw,
+               [CLKID_FCLK_DIV5_DIV]           = &g12a_fclk_div5_div.hw,
+               [CLKID_FCLK_DIV7_DIV]           = &g12a_fclk_div7_div.hw,
+               [CLKID_FCLK_DIV2P5_DIV]         = &g12a_fclk_div2p5_div.hw,
+               [CLKID_HIFI_PLL]                = &g12a_hifi_pll.hw,
+               [CLKID_VCLK2_VENCI0]            = &g12a_vclk2_venci0.hw,
+               [CLKID_VCLK2_VENCI1]            = &g12a_vclk2_venci1.hw,
+               [CLKID_VCLK2_VENCP0]            = &g12a_vclk2_vencp0.hw,
+               [CLKID_VCLK2_VENCP1]            = &g12a_vclk2_vencp1.hw,
+               [CLKID_VCLK2_VENCT0]            = &g12a_vclk2_venct0.hw,
+               [CLKID_VCLK2_VENCT1]            = &g12a_vclk2_venct1.hw,
+               [CLKID_VCLK2_OTHER]             = &g12a_vclk2_other.hw,
+               [CLKID_VCLK2_ENCI]              = &g12a_vclk2_enci.hw,
+               [CLKID_VCLK2_ENCP]              = &g12a_vclk2_encp.hw,
+               [CLKID_DAC_CLK]                 = &g12a_dac_clk.hw,
+               [CLKID_AOCLK]                   = &g12a_aoclk_gate.hw,
+               [CLKID_IEC958]                  = &g12a_iec958_gate.hw,
+               [CLKID_ENC480P]                 = &g12a_enc480p.hw,
+               [CLKID_RNG1]                    = &g12a_rng1.hw,
+               [CLKID_VCLK2_ENCT]              = &g12a_vclk2_enct.hw,
+               [CLKID_VCLK2_ENCL]              = &g12a_vclk2_encl.hw,
+               [CLKID_VCLK2_VENCLMMC]          = &g12a_vclk2_venclmmc.hw,
+               [CLKID_VCLK2_VENCL]             = &g12a_vclk2_vencl.hw,
+               [CLKID_VCLK2_OTHER1]            = &g12a_vclk2_other1.hw,
+               [CLKID_FIXED_PLL_DCO]           = &g12a_fixed_pll_dco.hw,
+               [CLKID_SYS_PLL_DCO]             = &g12a_sys_pll_dco.hw,
+               [CLKID_GP0_PLL_DCO]             = &g12a_gp0_pll_dco.hw,
+               [CLKID_HIFI_PLL_DCO]            = &g12a_hifi_pll_dco.hw,
+               [CLKID_DMA]                     = &g12a_dma.hw,
+               [CLKID_EFUSE]                   = &g12a_efuse.hw,
+               [CLKID_ROM_BOOT]                = &g12a_rom_boot.hw,
+               [CLKID_RESET_SEC]               = &g12a_reset_sec.hw,
+               [CLKID_SEC_AHB_APB3]            = &g12a_sec_ahb_apb3.hw,
+               [CLKID_MPLL_PREDIV]             = &g12a_mpll_prediv.hw,
+               [CLKID_VPU_0_SEL]               = &g12a_vpu_0_sel.hw,
+               [CLKID_VPU_0_DIV]               = &g12a_vpu_0_div.hw,
+               [CLKID_VPU_0]                   = &g12a_vpu_0.hw,
+               [CLKID_VPU_1_SEL]               = &g12a_vpu_1_sel.hw,
+               [CLKID_VPU_1_DIV]               = &g12a_vpu_1_div.hw,
+               [CLKID_VPU_1]                   = &g12a_vpu_1.hw,
+               [CLKID_VPU]                     = &g12a_vpu.hw,
+               [CLKID_VAPB_0_SEL]              = &g12a_vapb_0_sel.hw,
+               [CLKID_VAPB_0_DIV]              = &g12a_vapb_0_div.hw,
+               [CLKID_VAPB_0]                  = &g12a_vapb_0.hw,
+               [CLKID_VAPB_1_SEL]              = &g12a_vapb_1_sel.hw,
+               [CLKID_VAPB_1_DIV]              = &g12a_vapb_1_div.hw,
+               [CLKID_VAPB_1]                  = &g12a_vapb_1.hw,
+               [CLKID_VAPB_SEL]                = &g12a_vapb_sel.hw,
+               [CLKID_VAPB]                    = &g12a_vapb.hw,
+               [CLKID_HDMI_PLL_DCO]            = &g12a_hdmi_pll_dco.hw,
+               [CLKID_HDMI_PLL_OD]             = &g12a_hdmi_pll_od.hw,
+               [CLKID_HDMI_PLL_OD2]            = &g12a_hdmi_pll_od2.hw,
+               [CLKID_HDMI_PLL]                = &g12a_hdmi_pll.hw,
+               [CLKID_VID_PLL]                 = &g12a_vid_pll_div.hw,
+               [CLKID_VID_PLL_SEL]             = &g12a_vid_pll_sel.hw,
+               [CLKID_VID_PLL_DIV]             = &g12a_vid_pll.hw,
+               [CLKID_VCLK_SEL]                = &g12a_vclk_sel.hw,
+               [CLKID_VCLK2_SEL]               = &g12a_vclk2_sel.hw,
+               [CLKID_VCLK_INPUT]              = &g12a_vclk_input.hw,
+               [CLKID_VCLK2_INPUT]             = &g12a_vclk2_input.hw,
+               [CLKID_VCLK_DIV]                = &g12a_vclk_div.hw,
+               [CLKID_VCLK2_DIV]               = &g12a_vclk2_div.hw,
+               [CLKID_VCLK]                    = &g12a_vclk.hw,
+               [CLKID_VCLK2]                   = &g12a_vclk2.hw,
+               [CLKID_VCLK_DIV1]               = &g12a_vclk_div1.hw,
+               [CLKID_VCLK_DIV2_EN]            = &g12a_vclk_div2_en.hw,
+               [CLKID_VCLK_DIV4_EN]            = &g12a_vclk_div4_en.hw,
+               [CLKID_VCLK_DIV6_EN]            = &g12a_vclk_div6_en.hw,
+               [CLKID_VCLK_DIV12_EN]           = &g12a_vclk_div12_en.hw,
+               [CLKID_VCLK2_DIV1]              = &g12a_vclk2_div1.hw,
+               [CLKID_VCLK2_DIV2_EN]           = &g12a_vclk2_div2_en.hw,
+               [CLKID_VCLK2_DIV4_EN]           = &g12a_vclk2_div4_en.hw,
+               [CLKID_VCLK2_DIV6_EN]           = &g12a_vclk2_div6_en.hw,
+               [CLKID_VCLK2_DIV12_EN]          = &g12a_vclk2_div12_en.hw,
+               [CLKID_VCLK_DIV2]               = &g12a_vclk_div2.hw,
+               [CLKID_VCLK_DIV4]               = &g12a_vclk_div4.hw,
+               [CLKID_VCLK_DIV6]               = &g12a_vclk_div6.hw,
+               [CLKID_VCLK_DIV12]              = &g12a_vclk_div12.hw,
+               [CLKID_VCLK2_DIV2]              = &g12a_vclk2_div2.hw,
+               [CLKID_VCLK2_DIV4]              = &g12a_vclk2_div4.hw,
+               [CLKID_VCLK2_DIV6]              = &g12a_vclk2_div6.hw,
+               [CLKID_VCLK2_DIV12]             = &g12a_vclk2_div12.hw,
+               [CLKID_CTS_ENCI_SEL]            = &g12a_cts_enci_sel.hw,
+               [CLKID_CTS_ENCP_SEL]            = &g12a_cts_encp_sel.hw,
+               [CLKID_CTS_VDAC_SEL]            = &g12a_cts_vdac_sel.hw,
+               [CLKID_HDMI_TX_SEL]             = &g12a_hdmi_tx_sel.hw,
+               [CLKID_CTS_ENCI]                = &g12a_cts_enci.hw,
+               [CLKID_CTS_ENCP]                = &g12a_cts_encp.hw,
+               [CLKID_CTS_VDAC]                = &g12a_cts_vdac.hw,
+               [CLKID_HDMI_TX]                 = &g12a_hdmi_tx.hw,
+               [CLKID_HDMI_SEL]                = &g12a_hdmi_sel.hw,
+               [CLKID_HDMI_DIV]                = &g12a_hdmi_div.hw,
+               [CLKID_HDMI]                    = &g12a_hdmi.hw,
+               [CLKID_MALI_0_SEL]              = &g12a_mali_0_sel.hw,
+               [CLKID_MALI_0_DIV]              = &g12a_mali_0_div.hw,
+               [CLKID_MALI_0]                  = &g12a_mali_0.hw,
+               [CLKID_MALI_1_SEL]              = &g12a_mali_1_sel.hw,
+               [CLKID_MALI_1_DIV]              = &g12a_mali_1_div.hw,
+               [CLKID_MALI_1]                  = &g12a_mali_1.hw,
+               [CLKID_MALI]                    = &g12a_mali.hw,
+               [CLKID_MPLL_50M_DIV]            = &g12a_mpll_50m_div.hw,
+               [CLKID_MPLL_50M]                = &g12a_mpll_50m.hw,
+               [CLKID_SYS_PLL_DIV16_EN]        = &g12a_sys_pll_div16_en.hw,
+               [CLKID_SYS_PLL_DIV16]           = &g12a_sys_pll_div16.hw,
+               [CLKID_CPU_CLK_DYN0_SEL]        = &g12a_cpu_clk_premux0.hw,
+               [CLKID_CPU_CLK_DYN0_DIV]        = &g12a_cpu_clk_mux0_div.hw,
+               [CLKID_CPU_CLK_DYN0]            = &g12a_cpu_clk_postmux0.hw,
+               [CLKID_CPU_CLK_DYN1_SEL]        = &g12a_cpu_clk_premux1.hw,
+               [CLKID_CPU_CLK_DYN1_DIV]        = &g12a_cpu_clk_mux1_div.hw,
+               [CLKID_CPU_CLK_DYN1]            = &g12a_cpu_clk_postmux1.hw,
+               [CLKID_CPU_CLK_DYN]             = &g12a_cpu_clk_dyn.hw,
+               [CLKID_CPU_CLK]                 = &g12b_cpu_clk.hw,
+               [CLKID_CPU_CLK_DIV16_EN]        = &g12a_cpu_clk_div16_en.hw,
+               [CLKID_CPU_CLK_DIV16]           = &g12a_cpu_clk_div16.hw,
+               [CLKID_CPU_CLK_APB_DIV]         = &g12a_cpu_clk_apb_div.hw,
+               [CLKID_CPU_CLK_APB]             = &g12a_cpu_clk_apb.hw,
+               [CLKID_CPU_CLK_ATB_DIV]         = &g12a_cpu_clk_atb_div.hw,
+               [CLKID_CPU_CLK_ATB]             = &g12a_cpu_clk_atb.hw,
+               [CLKID_CPU_CLK_AXI_DIV]         = &g12a_cpu_clk_axi_div.hw,
+               [CLKID_CPU_CLK_AXI]             = &g12a_cpu_clk_axi.hw,
+               [CLKID_CPU_CLK_TRACE_DIV]       = &g12a_cpu_clk_trace_div.hw,
+               [CLKID_CPU_CLK_TRACE]           = &g12a_cpu_clk_trace.hw,
+               [CLKID_PCIE_PLL_DCO]            = &g12a_pcie_pll_dco.hw,
+               [CLKID_PCIE_PLL_DCO_DIV2]       = &g12a_pcie_pll_dco_div2.hw,
+               [CLKID_PCIE_PLL_OD]             = &g12a_pcie_pll_od.hw,
+               [CLKID_PCIE_PLL]                = &g12a_pcie_pll.hw,
+               [CLKID_VDEC_1_SEL]              = &g12a_vdec_1_sel.hw,
+               [CLKID_VDEC_1_DIV]              = &g12a_vdec_1_div.hw,
+               [CLKID_VDEC_1]                  = &g12a_vdec_1.hw,
+               [CLKID_VDEC_HEVC_SEL]           = &g12a_vdec_hevc_sel.hw,
+               [CLKID_VDEC_HEVC_DIV]           = &g12a_vdec_hevc_div.hw,
+               [CLKID_VDEC_HEVC]               = &g12a_vdec_hevc.hw,
+               [CLKID_VDEC_HEVCF_SEL]          = &g12a_vdec_hevcf_sel.hw,
+               [CLKID_VDEC_HEVCF_DIV]          = &g12a_vdec_hevcf_div.hw,
+               [CLKID_VDEC_HEVCF]              = &g12a_vdec_hevcf.hw,
+               [CLKID_TS_DIV]                  = &g12a_ts_div.hw,
+               [CLKID_TS]                      = &g12a_ts.hw,
+               [CLKID_SYS1_PLL_DCO]            = &g12b_sys1_pll_dco.hw,
+               [CLKID_SYS1_PLL]                = &g12b_sys1_pll.hw,
+               [CLKID_SYS1_PLL_DIV16_EN]       = &g12b_sys1_pll_div16_en.hw,
+               [CLKID_SYS1_PLL_DIV16]          = &g12b_sys1_pll_div16.hw,
+               [CLKID_CPUB_CLK_DYN0_SEL]       = &g12b_cpub_clk_premux0.hw,
+               [CLKID_CPUB_CLK_DYN0_DIV]       = &g12b_cpub_clk_mux0_div.hw,
+               [CLKID_CPUB_CLK_DYN0]           = &g12b_cpub_clk_postmux0.hw,
+               [CLKID_CPUB_CLK_DYN1_SEL]       = &g12b_cpub_clk_premux1.hw,
+               [CLKID_CPUB_CLK_DYN1_DIV]       = &g12b_cpub_clk_mux1_div.hw,
+               [CLKID_CPUB_CLK_DYN1]           = &g12b_cpub_clk_postmux1.hw,
+               [CLKID_CPUB_CLK_DYN]            = &g12b_cpub_clk_dyn.hw,
+               [CLKID_CPUB_CLK]                = &g12b_cpub_clk.hw,
+               [CLKID_CPUB_CLK_DIV16_EN]       = &g12b_cpub_clk_div16_en.hw,
+               [CLKID_CPUB_CLK_DIV16]          = &g12b_cpub_clk_div16.hw,
+               [CLKID_CPUB_CLK_DIV2]           = &g12b_cpub_clk_div2.hw,
+               [CLKID_CPUB_CLK_DIV3]           = &g12b_cpub_clk_div3.hw,
+               [CLKID_CPUB_CLK_DIV4]           = &g12b_cpub_clk_div4.hw,
+               [CLKID_CPUB_CLK_DIV5]           = &g12b_cpub_clk_div5.hw,
+               [CLKID_CPUB_CLK_DIV6]           = &g12b_cpub_clk_div6.hw,
+               [CLKID_CPUB_CLK_DIV7]           = &g12b_cpub_clk_div7.hw,
+               [CLKID_CPUB_CLK_DIV8]           = &g12b_cpub_clk_div8.hw,
+               [CLKID_CPUB_CLK_APB_SEL]        = &g12b_cpub_clk_apb_sel.hw,
+               [CLKID_CPUB_CLK_APB]            = &g12b_cpub_clk_apb.hw,
+               [CLKID_CPUB_CLK_ATB_SEL]        = &g12b_cpub_clk_atb_sel.hw,
+               [CLKID_CPUB_CLK_ATB]            = &g12b_cpub_clk_atb.hw,
+               [CLKID_CPUB_CLK_AXI_SEL]        = &g12b_cpub_clk_axi_sel.hw,
+               [CLKID_CPUB_CLK_AXI]            = &g12b_cpub_clk_axi.hw,
+               [CLKID_CPUB_CLK_TRACE_SEL]      = &g12b_cpub_clk_trace_sel.hw,
+               [CLKID_CPUB_CLK_TRACE]          = &g12b_cpub_clk_trace.hw,
                [NR_CLKS]                       = NULL,
        },
        .num = NR_CLKS,
@@ -2966,16 +3763,52 @@ static struct clk_regmap *const g12a_clk_regmaps[] = {
        &g12a_vdec_hevcf_sel,
        &g12a_vdec_hevcf_div,
        &g12a_vdec_hevcf,
+       &g12a_ts_div,
+       &g12a_ts,
+       &g12b_cpu_clk,
+       &g12b_sys1_pll_dco,
+       &g12b_sys1_pll,
+       &g12b_sys1_pll_div16_en,
+       &g12b_cpub_clk_premux0,
+       &g12b_cpub_clk_mux0_div,
+       &g12b_cpub_clk_postmux0,
+       &g12b_cpub_clk_premux1,
+       &g12b_cpub_clk_mux1_div,
+       &g12b_cpub_clk_postmux1,
+       &g12b_cpub_clk_dyn,
+       &g12b_cpub_clk,
+       &g12b_cpub_clk_div16_en,
+       &g12b_cpub_clk_apb_sel,
+       &g12b_cpub_clk_apb,
+       &g12b_cpub_clk_atb_sel,
+       &g12b_cpub_clk_atb,
+       &g12b_cpub_clk_axi_sel,
+       &g12b_cpub_clk_axi,
+       &g12b_cpub_clk_trace_sel,
+       &g12b_cpub_clk_trace,
+};
+
+static const struct reg_sequence g12a_init_regs[] = {
+       { .reg = HHI_MPLL_CNTL0,        .def = 0x00000543 },
 };
 
 static const struct meson_eeclkc_data g12a_clkc_data = {
        .regmap_clks = g12a_clk_regmaps,
        .regmap_clk_num = ARRAY_SIZE(g12a_clk_regmaps),
-       .hw_onecell_data = &g12a_hw_onecell_data
+       .hw_onecell_data = &g12a_hw_onecell_data,
+       .init_regs = g12a_init_regs,
+       .init_count = ARRAY_SIZE(g12a_init_regs),
+};
+
+static const struct meson_eeclkc_data g12b_clkc_data = {
+       .regmap_clks = g12a_clk_regmaps,
+       .regmap_clk_num = ARRAY_SIZE(g12a_clk_regmaps),
+       .hw_onecell_data = &g12b_hw_onecell_data
 };
 
 static const struct of_device_id clkc_match_table[] = {
        { .compatible = "amlogic,g12a-clkc", .data = &g12a_clkc_data },
+       { .compatible = "amlogic,g12b-clkc", .data = &g12b_clkc_data },
        {}
 };
 
index bcc05cd..c8aed31 100644 (file)
@@ -69,6 +69,8 @@
 #define HHI_VDEC4_CLK_CNTL             0x1EC
 #define HHI_HDCP22_CLK_CNTL            0x1F0
 #define HHI_VAPBCLK_CNTL               0x1F4
+#define HHI_SYS_CPUB_CLK_CNTL1         0x200
+#define HHI_SYS_CPUB_CLK_CNTL          0x208
 #define HHI_VPU_CLKB_CNTL              0x20C
 #define HHI_GEN_CLK_CNTL               0x228
 #define HHI_VDIN_MEAS_CLK_CNTL         0x250
 #define HHI_HDMI_PLL_CNTL5             0x334
 #define HHI_HDMI_PLL_CNTL6             0x338
 #define HHI_SPICC_CLK_CNTL             0x3dc
+#define HHI_SYS1_PLL_CNTL0             0x380
+#define HHI_SYS1_PLL_CNTL1             0x384
+#define HHI_SYS1_PLL_CNTL2             0x388
+#define HHI_SYS1_PLL_CNTL3             0x38c
+#define HHI_SYS1_PLL_CNTL4             0x390
+#define HHI_SYS1_PLL_CNTL5             0x394
+#define HHI_SYS1_PLL_CNTL6             0x398
 
 /*
  * CLKID index values
 #define CLKID_VDEC_HEVC_DIV                    206
 #define CLKID_VDEC_HEVCF_SEL                   208
 #define CLKID_VDEC_HEVCF_DIV                   209
+#define CLKID_TS_DIV                           211
+#define CLKID_SYS1_PLL_DCO                     213
+#define CLKID_SYS1_PLL                         214
+#define CLKID_SYS1_PLL_DIV16_EN                        215
+#define CLKID_SYS1_PLL_DIV16                   216
+#define CLKID_CPUB_CLK_DYN0_SEL                        217
+#define CLKID_CPUB_CLK_DYN0_DIV                        218
+#define CLKID_CPUB_CLK_DYN0                    219
+#define CLKID_CPUB_CLK_DYN1_SEL                        220
+#define CLKID_CPUB_CLK_DYN1_DIV                        221
+#define CLKID_CPUB_CLK_DYN1                    222
+#define CLKID_CPUB_CLK_DYN                     223
+#define CLKID_CPUB_CLK                         224
+#define CLKID_CPUB_CLK_DIV16_EN                        225
+#define CLKID_CPUB_CLK_DIV16                   226
+#define CLKID_CPUB_CLK_DIV2                    227
+#define CLKID_CPUB_CLK_DIV3                    228
+#define CLKID_CPUB_CLK_DIV4                    229
+#define CLKID_CPUB_CLK_DIV5                    230
+#define CLKID_CPUB_CLK_DIV6                    231
+#define CLKID_CPUB_CLK_DIV7                    232
+#define CLKID_CPUB_CLK_DIV8                    233
+#define CLKID_CPUB_CLK_APB_SEL                 234
+#define CLKID_CPUB_CLK_APB                     235
+#define CLKID_CPUB_CLK_ATB_SEL                 236
+#define CLKID_CPUB_CLK_ATB                     237
+#define CLKID_CPUB_CLK_AXI_SEL                 238
+#define CLKID_CPUB_CLK_AXI                     239
+#define CLKID_CPUB_CLK_TRACE_SEL               240
+#define CLKID_CPUB_CLK_TRACE                   241
 
-#define NR_CLKS                                        211
+#define NR_CLKS                                        242
 
 /* include the CLKIDs that have been made part of the DT binding */
 #include <dt-bindings/clock/g12a-clkc.h>
index 29ffb4f..dab16d9 100644 (file)
@@ -679,11 +679,6 @@ static struct clk_regmap gxbb_mpll0_div = {
                        .shift   = 16,
                        .width   = 9,
                },
-               .ssen = {
-                       .reg_off = HHI_MPLL_CNTL,
-                       .shift   = 25,
-                       .width   = 1,
-               },
                .lock = &meson_clk_lock,
        },
        .hw.init = &(struct clk_init_data){
index 37a34c9..6ba2094 100644 (file)
@@ -34,6 +34,9 @@ int meson_eeclkc_probe(struct platform_device *pdev)
                return PTR_ERR(map);
        }
 
+       if (data->init_count)
+               regmap_multi_reg_write(map, data->init_regs, data->init_count);
+
        input = meson_clk_hw_register_input(dev, "xtal", IN_PREFIX "xtal", 0);
        if (IS_ERR(input)) {
                ret = PTR_ERR(input);
index 1b809b1..9ab5d6f 100644 (file)
@@ -17,6 +17,8 @@ struct platform_device;
 struct meson_eeclkc_data {
        struct clk_regmap *const        *regmap_clks;
        unsigned int                    regmap_clk_num;
+       const struct reg_sequence       *init_regs;
+       unsigned int                    init_count;
        struct clk_hw_onecell_data      *hw_onecell_data;
 };
 
index 62cd3a7..537219f 100644 (file)
@@ -2153,6 +2153,132 @@ static struct clk_regmap meson8b_vdec_hevc = {
        },
 };
 
+/* TODO: the clock at index 0 is "DDR_PLL" which we don't support yet */
+static const char * const meson8b_cts_amclk_parent_names[] = {
+       "mpll0", "mpll1", "mpll2"
+};
+
+static u32 meson8b_cts_amclk_mux_table[] = { 1, 2, 3 };
+
+static struct clk_regmap meson8b_cts_amclk_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_AUD_CLK_CNTL,
+               .mask = 0x3,
+               .shift = 9,
+               .table = meson8b_cts_amclk_mux_table,
+               .flags = CLK_MUX_ROUND_CLOSEST,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cts_amclk_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = meson8b_cts_amclk_parent_names,
+               .num_parents = ARRAY_SIZE(meson8b_cts_amclk_parent_names),
+       },
+};
+
+static struct clk_regmap meson8b_cts_amclk_div = {
+       .data = &(struct clk_regmap_div_data) {
+               .offset = HHI_AUD_CLK_CNTL,
+               .shift = 0,
+               .width = 8,
+               .flags = CLK_DIVIDER_ROUND_CLOSEST,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cts_amclk_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_names = (const char *[]){ "cts_amclk_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap meson8b_cts_amclk = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_AUD_CLK_CNTL,
+               .bit_idx = 8,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cts_amclk",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "cts_amclk_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+/* TODO: the clock at index 0 is "DDR_PLL" which we don't support yet */
+static const char * const meson8b_cts_mclk_i958_parent_names[] = {
+       "mpll0", "mpll1", "mpll2"
+};
+
+static u32 meson8b_cts_mclk_i958_mux_table[] = { 1, 2, 3 };
+
+static struct clk_regmap meson8b_cts_mclk_i958_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_AUD_CLK_CNTL2,
+               .mask = 0x3,
+               .shift = 25,
+               .table = meson8b_cts_mclk_i958_mux_table,
+               .flags = CLK_MUX_ROUND_CLOSEST,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "cts_mclk_i958_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = meson8b_cts_mclk_i958_parent_names,
+               .num_parents = ARRAY_SIZE(meson8b_cts_mclk_i958_parent_names),
+       },
+};
+
+static struct clk_regmap meson8b_cts_mclk_i958_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_AUD_CLK_CNTL2,
+               .shift = 16,
+               .width = 8,
+               .flags = CLK_DIVIDER_ROUND_CLOSEST,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "cts_mclk_i958_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_names = (const char *[]){ "cts_mclk_i958_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap meson8b_cts_mclk_i958 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_AUD_CLK_CNTL2,
+               .bit_idx = 24,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cts_mclk_i958",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "cts_mclk_i958_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap meson8b_cts_i958 = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_AUD_CLK_CNTL2,
+               .mask = 0x1,
+               .shift = 27,
+               },
+       .hw.init = &(struct clk_init_data){
+               .name = "cts_i958",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = (const char *[]){ "cts_amclk",
+                                                 "cts_mclk_i958" },
+               .num_parents = 2,
+               /*
+                * The parent is specific to origin of the audio data. Let the
+                * consumer choose the appropriate parent.
+                */
+               .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+       },
+};
+
 /* Everything Else (EE) domain gates */
 
 static MESON_GATE(meson8b_ddr, HHI_GCLK_MPEG0, 0);
@@ -2432,6 +2558,13 @@ static struct clk_hw_onecell_data meson8_hw_onecell_data = {
                [CLKID_VDEC_HEVC_DIV]       = &meson8b_vdec_hevc_div.hw,
                [CLKID_VDEC_HEVC_EN]        = &meson8b_vdec_hevc_en.hw,
                [CLKID_VDEC_HEVC]           = &meson8b_vdec_hevc.hw,
+               [CLKID_CTS_AMCLK_SEL]       = &meson8b_cts_amclk_sel.hw,
+               [CLKID_CTS_AMCLK_DIV]       = &meson8b_cts_amclk_div.hw,
+               [CLKID_CTS_AMCLK]           = &meson8b_cts_amclk.hw,
+               [CLKID_CTS_MCLK_I958_SEL]   = &meson8b_cts_mclk_i958_sel.hw,
+               [CLKID_CTS_MCLK_I958_DIV]   = &meson8b_cts_mclk_i958_div.hw,
+               [CLKID_CTS_MCLK_I958]       = &meson8b_cts_mclk_i958.hw,
+               [CLKID_CTS_I958]            = &meson8b_cts_i958.hw,
                [CLK_NR_CLKS]               = NULL,
        },
        .num = CLK_NR_CLKS,
@@ -2641,6 +2774,13 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = {
                [CLKID_VDEC_HEVC_DIV]       = &meson8b_vdec_hevc_div.hw,
                [CLKID_VDEC_HEVC_EN]        = &meson8b_vdec_hevc_en.hw,
                [CLKID_VDEC_HEVC]           = &meson8b_vdec_hevc.hw,
+               [CLKID_CTS_AMCLK_SEL]       = &meson8b_cts_amclk_sel.hw,
+               [CLKID_CTS_AMCLK_DIV]       = &meson8b_cts_amclk_div.hw,
+               [CLKID_CTS_AMCLK]           = &meson8b_cts_amclk.hw,
+               [CLKID_CTS_MCLK_I958_SEL]   = &meson8b_cts_mclk_i958_sel.hw,
+               [CLKID_CTS_MCLK_I958_DIV]   = &meson8b_cts_mclk_i958_div.hw,
+               [CLKID_CTS_MCLK_I958]       = &meson8b_cts_mclk_i958.hw,
+               [CLKID_CTS_I958]            = &meson8b_cts_i958.hw,
                [CLK_NR_CLKS]               = NULL,
        },
        .num = CLK_NR_CLKS,
@@ -2852,6 +2992,13 @@ static struct clk_hw_onecell_data meson8m2_hw_onecell_data = {
                [CLKID_VDEC_HEVC_DIV]       = &meson8b_vdec_hevc_div.hw,
                [CLKID_VDEC_HEVC_EN]        = &meson8b_vdec_hevc_en.hw,
                [CLKID_VDEC_HEVC]           = &meson8b_vdec_hevc.hw,
+               [CLKID_CTS_AMCLK_SEL]       = &meson8b_cts_amclk_sel.hw,
+               [CLKID_CTS_AMCLK_DIV]       = &meson8b_cts_amclk_div.hw,
+               [CLKID_CTS_AMCLK]           = &meson8b_cts_amclk.hw,
+               [CLKID_CTS_MCLK_I958_SEL]   = &meson8b_cts_mclk_i958_sel.hw,
+               [CLKID_CTS_MCLK_I958_DIV]   = &meson8b_cts_mclk_i958_div.hw,
+               [CLKID_CTS_MCLK_I958]       = &meson8b_cts_mclk_i958.hw,
+               [CLKID_CTS_I958]            = &meson8b_cts_i958.hw,
                [CLK_NR_CLKS]               = NULL,
        },
        .num = CLK_NR_CLKS,
@@ -3041,6 +3188,13 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = {
        &meson8b_vdec_hevc_div,
        &meson8b_vdec_hevc_en,
        &meson8b_vdec_hevc,
+       &meson8b_cts_amclk,
+       &meson8b_cts_amclk_sel,
+       &meson8b_cts_amclk_div,
+       &meson8b_cts_mclk_i958_sel,
+       &meson8b_cts_mclk_i958_div,
+       &meson8b_cts_mclk_i958,
+       &meson8b_cts_i958,
 };
 
 static const struct meson8b_clk_reset_line {
index ed37196..c889fbe 100644 (file)
@@ -30,7 +30,9 @@
 #define HHI_SYS_CPU_CLK_CNTL1          0x15c /* 0x57 offset in data sheet */
 #define HHI_VID_CLK_DIV                        0x164 /* 0x59 offset in data sheet */
 #define HHI_MPEG_CLK_CNTL              0x174 /* 0x5d offset in data sheet */
+#define HHI_AUD_CLK_CNTL               0x178 /* 0x5e offset in data sheet */
 #define HHI_VID_CLK_CNTL               0x17c /* 0x5f offset in data sheet */
+#define HHI_AUD_CLK_CNTL2              0x190 /* 0x64 offset in data sheet */
 #define HHI_VID_CLK_CNTL2              0x194 /* 0x65 offset in data sheet */
 #define HHI_VID_DIVIDER_CNTL           0x198 /* 0x66 offset in data sheet */
 #define HHI_SYS_CPU_CLK_CNTL0          0x19c /* 0x67 offset in data sheet */
 #define CLKID_VDEC_HEVC_SEL    203
 #define CLKID_VDEC_HEVC_DIV    204
 #define CLKID_VDEC_HEVC_EN     205
+#define CLKID_CTS_AMCLK_SEL    207
+#define CLKID_CTS_AMCLK_DIV    208
+#define CLKID_CTS_MCLK_I958_SEL        210
+#define CLKID_CTS_MCLK_I958_DIV        211
 
-#define CLK_NR_CLKS            207
+#define CLK_NR_CLKS            214
 
 /*
  * include the CLKID and RESETID that have
index cb43d54..90bf181 100644 (file)
@@ -78,11 +78,10 @@ static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate,
        struct mmp_clk_factor_masks *masks = factor->masks;
        int i;
        unsigned long val;
-       unsigned long prev_rate, rate = 0;
+       unsigned long rate = 0;
        unsigned long flags = 0;
 
        for (i = 0; i < factor->ftbl_cnt; i++) {
-               prev_rate = rate;
                rate = (((prate / 10000) * factor->ftbl[i].den) /
                        (factor->ftbl[i].num * factor->masks->factor)) * 10000;
                if (rate > drate)
index 35af3aa..4768023 100644 (file)
@@ -185,6 +185,11 @@ static void __init mv88f6180_get_clk_ratio(
        }
 }
 
+static u32 __init mv98dx1135_get_tclk_freq(void __iomem *sar)
+{
+       return 166666667;
+}
+
 static const struct coreclk_soc_desc kirkwood_coreclks = {
        .get_tclk_freq = kirkwood_get_tclk_freq,
        .get_cpu_freq = kirkwood_get_cpu_freq,
@@ -201,6 +206,14 @@ static const struct coreclk_soc_desc mv88f6180_coreclks = {
        .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
 };
 
+static const struct coreclk_soc_desc mv98dx1135_coreclks = {
+       .get_tclk_freq = mv98dx1135_get_tclk_freq,
+       .get_cpu_freq = kirkwood_get_cpu_freq,
+       .get_clk_ratio = kirkwood_get_clk_ratio,
+       .ratios = kirkwood_coreclk_ratios,
+       .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
+};
+
 /*
  * Clock Gating Control
  */
@@ -325,6 +338,8 @@ static void __init kirkwood_clk_init(struct device_node *np)
 
        if (of_device_is_compatible(np, "marvell,mv88f6180-core-clock"))
                mvebu_coreclk_setup(np, &mv88f6180_coreclks);
+       else if (of_device_is_compatible(np, "marvell,mv98dx1135-core-clock"))
+               mvebu_coreclk_setup(np, &mv98dx1135_coreclks);
        else
                mvebu_coreclk_setup(np, &kirkwood_coreclks);
 
@@ -339,3 +354,5 @@ CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock",
               kirkwood_clk_init);
 CLK_OF_DECLARE(mv88f6180_clk, "marvell,mv88f6180-core-clock",
               kirkwood_clk_init);
+CLK_OF_DECLARE(98dx1135_clk, "marvell,mv98dx1135-core-clock",
+              kirkwood_clk_init);
index d2f39a9..d004cda 100644 (file)
@@ -130,22 +130,6 @@ static const char * const gcc_xo_gpll0_gpll4_gpll0_early_div[] = {
        "gpll0_early_div"
 };
 
-static const struct parent_map gcc_xo_gpll0_gpll2_gpll3_gpll0_early_div_map[] = {
-       { P_XO, 0 },
-       { P_GPLL0, 1 },
-       { P_GPLL2, 2 },
-       { P_GPLL3, 3 },
-       { P_GPLL0_EARLY_DIV, 6 }
-};
-
-static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll0_early_div[] = {
-       "xo",
-       "gpll0",
-       "gpll2",
-       "gpll3",
-       "gpll0_early_div"
-};
-
 static const struct parent_map gcc_xo_gpll0_gpll1_early_div_gpll1_gpll4_gpll0_early_div_map[] = {
        { P_XO, 0 },
        { P_GPLL0, 1 },
@@ -184,26 +168,6 @@ static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll2_early_gpll0_early
        "gpll0_early_div"
 };
 
-static const struct parent_map gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll4_gpll0_early_div_map[] = {
-       { P_XO, 0 },
-       { P_GPLL0, 1 },
-       { P_GPLL2, 2 },
-       { P_GPLL3, 3 },
-       { P_GPLL1, 4 },
-       { P_GPLL4, 5 },
-       { P_GPLL0_EARLY_DIV, 6 }
-};
-
-static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll4_gpll0_early_div[] = {
-       "xo",
-       "gpll0",
-       "gpll2",
-       "gpll3",
-       "gpll1",
-       "gpll4",
-       "gpll0_early_div"
-};
-
 static struct clk_fixed_factor xo = {
        .mult = 1,
        .div = 1,
index a54807e..29cf464 100644 (file)
@@ -2766,6 +2766,13 @@ static const struct qcom_reset_map gcc_qcs404_resets[] = {
        [GCC_PCIE_0_PHY_BCR] = { 0x3e004 },
        [GCC_PCIE_0_LINK_DOWN_BCR] = { 0x3e038 },
        [GCC_PCIEPHY_0_PHY_BCR] = { 0x3e03c },
+       [GCC_PCIE_0_AXI_MASTER_STICKY_ARES] = { 0x3e040, 6},
+       [GCC_PCIE_0_AHB_ARES] = { 0x3e040, 5 },
+       [GCC_PCIE_0_AXI_SLAVE_ARES] = { 0x3e040, 4 },
+       [GCC_PCIE_0_AXI_MASTER_ARES] = { 0x3e040, 3 },
+       [GCC_PCIE_0_CORE_STICKY_ARES] = { 0x3e040, 2 },
+       [GCC_PCIE_0_SLEEP_ARES] = { 0x3e040, 1 },
+       [GCC_PCIE_0_PIPE_ARES] = { 0x3e040, 0 },
        [GCC_EMAC_BCR] = { 0x4e000 },
 };
 
index 679bc7d..a250f59 100644 (file)
@@ -141,7 +141,9 @@ static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status)
                udelay(1);
        }
 
-       return gdsc_poll_status(sc, status);
+       ret = gdsc_poll_status(sc, status);
+       WARN(ret, "%s status stuck at 'o%s'", sc->pd.name, status ? "ff" : "n");
+       return ret;
 }
 
 static inline int gdsc_deassert_reset(struct gdsc *sc)
index e98a9f5..5ca183e 100644 (file)
@@ -30,8 +30,8 @@
  * @div: divisor value (1-64)
  * @src_shift: Shift to access the register bits to select the parent clock
  * @src_width: Number of register bits to select the parent clock (may be 0)
- * @parents: Array to map from valid parent clocks indices to hardware indices
  * @nb: Notifier block to save/restore clock state for system resume
+ * @parents: Array to map from valid parent clocks indices to hardware indices
  */
 struct div6_clock {
        struct clk_hw hw;
@@ -39,8 +39,8 @@ struct div6_clock {
        unsigned int div;
        u32 src_shift;
        u32 src_width;
-       u8 *parents;
        struct notifier_block nb;
+       u8 parents[];
 };
 
 #define to_div6_clock(_hw) container_of(_hw, struct div6_clock, hw)
@@ -221,17 +221,10 @@ struct clk * __init cpg_div6_register(const char *name,
        struct clk *clk;
        unsigned int i;
 
-       clock = kzalloc(sizeof(*clock), GFP_KERNEL);
+       clock = kzalloc(struct_size(clock, parents, num_parents), GFP_KERNEL);
        if (!clock)
                return ERR_PTR(-ENOMEM);
 
-       clock->parents = kmalloc_array(num_parents, sizeof(*clock->parents),
-                                      GFP_KERNEL);
-       if (!clock->parents) {
-               clk = ERR_PTR(-ENOMEM);
-               goto free_clock;
-       }
-
        clock->reg = reg;
 
        /*
@@ -259,7 +252,7 @@ struct clk * __init cpg_div6_register(const char *name,
                pr_err("%s: invalid number of parents for DIV6 clock %s\n",
                       __func__, name);
                clk = ERR_PTR(-EINVAL);
-               goto free_parents;
+               goto free_clock;
        }
 
        /* Filter out invalid parents */
@@ -282,7 +275,7 @@ struct clk * __init cpg_div6_register(const char *name,
 
        clk = clk_register(NULL, &clock->hw);
        if (IS_ERR(clk))
-               goto free_parents;
+               goto free_clock;
 
        if (notifiers) {
                clock->nb.notifier_call = cpg_div6_clock_notifier_call;
@@ -291,8 +284,6 @@ struct clk * __init cpg_div6_register(const char *name,
 
        return clk;
 
-free_parents:
-       kfree(clock->parents);
 free_clock:
        kfree(clock);
        return clk;
index 92ece22..2db9093 100644 (file)
 /**
  * struct mstp_clock_group - MSTP gating clocks group
  *
- * @data: clocks in this group
+ * @data: clock specifier translation for clocks in this group
  * @smstpcr: module stop control register
  * @mstpsr: module stop status register (optional)
  * @lock: protects writes to SMSTPCR
  * @width_8bit: registers are 8-bit, not 32-bit
+ * @clks: clocks in this group
  */
 struct mstp_clock_group {
        struct clk_onecell_data data;
@@ -42,6 +43,7 @@ struct mstp_clock_group {
        void __iomem *mstpsr;
        spinlock_t lock;
        bool width_8bit;
+       struct clk *clks[];
 };
 
 /**
@@ -186,14 +188,13 @@ static void __init cpg_mstp_clocks_init(struct device_node *np)
        struct clk **clks;
        unsigned int i;
 
-       group = kzalloc(sizeof(*group), GFP_KERNEL);
-       clks = kmalloc_array(MSTP_MAX_CLOCKS, sizeof(*clks), GFP_KERNEL);
-       if (group == NULL || clks == NULL) {
+       group = kzalloc(struct_size(group, clks, MSTP_MAX_CLOCKS), GFP_KERNEL);
+       if (group == NULL) {
                kfree(group);
-               kfree(clks);
                return;
        }
 
+       clks = group->clks;
        spin_lock_init(&group->lock);
        group->data.clks = clks;
 
@@ -203,7 +204,6 @@ static void __init cpg_mstp_clocks_init(struct device_node *np)
        if (group->smstpcr == NULL) {
                pr_err("%s: failed to remap SMSTPCR\n", __func__);
                kfree(group);
-               kfree(clks);
                return;
        }
 
@@ -297,16 +297,12 @@ found:
                return PTR_ERR(clk);
 
        error = pm_clk_create(dev);
-       if (error) {
-               dev_err(dev, "pm_clk_create failed %d\n", error);
+       if (error)
                goto fail_put;
-       }
 
        error = pm_clk_add_clk(dev, clk);
-       if (error) {
-               dev_err(dev, "pm_clk_add_clk %pC failed %d\n", clk, error);
+       if (error)
                goto fail_destroy;
-       }
 
        return 0;
 
index 76ed7d1..e05bfa2 100644 (file)
@@ -113,6 +113,11 @@ static const struct cpg_core_clk r8a774a1_core_clks[] __initconst = {
 };
 
 static const struct mssr_mod_clk r8a774a1_mod_clks[] __initconst = {
+       DEF_MOD("tmu4",                  121,   R8A774A1_CLK_S0D6),
+       DEF_MOD("tmu3",                  122,   R8A774A1_CLK_S3D2),
+       DEF_MOD("tmu2",                  123,   R8A774A1_CLK_S3D2),
+       DEF_MOD("tmu1",                  124,   R8A774A1_CLK_S3D2),
+       DEF_MOD("tmu0",                  125,   R8A774A1_CLK_CP),
        DEF_MOD("fdp1-0",                119,   R8A774A1_CLK_S0D1),
        DEF_MOD("scif5",                 202,   R8A774A1_CLK_S3D4),
        DEF_MOD("scif4",                 203,   R8A774A1_CLK_S3D4),
index 9e9a6f2..fbc8c75 100644 (file)
@@ -138,6 +138,7 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = {
        DEF_MOD("cmt2",                  301,   R8A7795_CLK_R),
        DEF_MOD("cmt1",                  302,   R8A7795_CLK_R),
        DEF_MOD("cmt0",                  303,   R8A7795_CLK_R),
+       DEF_MOD("tpu0",                  304,   R8A7795_CLK_S3D4),
        DEF_MOD("scif2",                 310,   R8A7795_CLK_S3D4),
        DEF_MOD("sdif3",                 311,   R8A7795_CLK_SD3),
        DEF_MOD("sdif2",                 312,   R8A7795_CLK_SD2),
@@ -201,6 +202,10 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = {
        DEF_MOD("ehci0",                 703,   R8A7795_CLK_S3D2),
        DEF_MOD("hsusb",                 704,   R8A7795_CLK_S3D2),
        DEF_MOD("hsusb3",                705,   R8A7795_CLK_S3D2),
+       DEF_MOD("cmm3",                  708,   R8A7795_CLK_S2D1),
+       DEF_MOD("cmm2",                  709,   R8A7795_CLK_S2D1),
+       DEF_MOD("cmm1",                  710,   R8A7795_CLK_S2D1),
+       DEF_MOD("cmm0",                  711,   R8A7795_CLK_S2D1),
        DEF_MOD("csi21",                 713,   R8A7795_CLK_CSI0), /* ES1.x */
        DEF_MOD("csi20",                 714,   R8A7795_CLK_CSI0),
        DEF_MOD("csi41",                 715,   R8A7795_CLK_CSI0),
index d8e9af5..90cc6a1 100644 (file)
@@ -134,6 +134,7 @@ static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = {
        DEF_MOD("cmt2",                  301,   R8A7796_CLK_R),
        DEF_MOD("cmt1",                  302,   R8A7796_CLK_R),
        DEF_MOD("cmt0",                  303,   R8A7796_CLK_R),
+       DEF_MOD("tpu0",                  304,   R8A7796_CLK_S3D4),
        DEF_MOD("scif2",                 310,   R8A7796_CLK_S3D4),
        DEF_MOD("sdif3",                 311,   R8A7796_CLK_SD3),
        DEF_MOD("sdif2",                 312,   R8A7796_CLK_SD2),
@@ -180,6 +181,9 @@ static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = {
        DEF_MOD("ehci1",                 702,   R8A7796_CLK_S3D2),
        DEF_MOD("ehci0",                 703,   R8A7796_CLK_S3D2),
        DEF_MOD("hsusb",                 704,   R8A7796_CLK_S3D2),
+       DEF_MOD("cmm2",                  709,   R8A7796_CLK_S2D1),
+       DEF_MOD("cmm1",                  710,   R8A7796_CLK_S2D1),
+       DEF_MOD("cmm0",                  711,   R8A7796_CLK_S2D1),
        DEF_MOD("csi20",                 714,   R8A7796_CLK_CSI0),
        DEF_MOD("csi40",                 716,   R8A7796_CLK_CSI0),
        DEF_MOD("du2",                   722,   R8A7796_CLK_S2D1),
index 8f87e31..b4e8c5b 100644 (file)
@@ -132,6 +132,7 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = {
        DEF_MOD("cmt2",                 301,    R8A77965_CLK_R),
        DEF_MOD("cmt1",                 302,    R8A77965_CLK_R),
        DEF_MOD("cmt0",                 303,    R8A77965_CLK_R),
+       DEF_MOD("tpu0",                 304,    R8A77965_CLK_S3D4),
        DEF_MOD("scif2",                310,    R8A77965_CLK_S3D4),
        DEF_MOD("sdif3",                311,    R8A77965_CLK_SD3),
        DEF_MOD("sdif2",                312,    R8A77965_CLK_SD2),
@@ -179,6 +180,9 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = {
        DEF_MOD("ehci1",                702,    R8A77965_CLK_S3D2),
        DEF_MOD("ehci0",                703,    R8A77965_CLK_S3D2),
        DEF_MOD("hsusb",                704,    R8A77965_CLK_S3D2),
+       DEF_MOD("cmm3",                 708,    R8A77965_CLK_S2D1),
+       DEF_MOD("cmm1",                 710,    R8A77965_CLK_S2D1),
+       DEF_MOD("cmm0",                 711,    R8A77965_CLK_S2D1),
        DEF_MOD("csi20",                714,    R8A77965_CLK_CSI0),
        DEF_MOD("csi40",                716,    R8A77965_CLK_CSI0),
        DEF_MOD("du3",                  721,    R8A77965_CLK_S2D1),
index 9570404..ceabf55 100644 (file)
@@ -183,6 +183,8 @@ static const struct mssr_mod_clk r8a77990_mod_clks[] __initconst = {
 
        DEF_MOD("ehci0",                 703,   R8A77990_CLK_S3D2),
        DEF_MOD("hsusb",                 704,   R8A77990_CLK_S3D2),
+       DEF_MOD("cmm1",                  710,   R8A77990_CLK_S1D1),
+       DEF_MOD("cmm0",                  711,   R8A77990_CLK_S1D1),
        DEF_MOD("csi40",                 716,   R8A77990_CLK_CSI0),
        DEF_MOD("du1",                   723,   R8A77990_CLK_S1D1),
        DEF_MOD("du0",                   724,   R8A77990_CLK_S1D1),
index 6870727..962bb33 100644 (file)
@@ -146,6 +146,8 @@ static const struct mssr_mod_clk r8a77995_mod_clks[] __initconst = {
        DEF_MOD("vspbs",                 627,   R8A77995_CLK_S0D1),
        DEF_MOD("ehci0",                 703,   R8A77995_CLK_S3D2),
        DEF_MOD("hsusb",                 704,   R8A77995_CLK_S3D2),
+       DEF_MOD("cmm1",                  710,   R8A77995_CLK_S1D1),
+       DEF_MOD("cmm0",                  711,   R8A77995_CLK_S1D1),
        DEF_MOD("du1",                   723,   R8A77995_CLK_S1D1),
        DEF_MOD("du0",                   724,   R8A77995_CLK_S1D1),
        DEF_MOD("lvds",                  727,   R8A77995_CLK_S2D1),
index 7d04218..b33e138 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
+#include <linux/pm_clock.h>
+#include <linux/pm_domain.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <dt-bindings/clock/r9a06g032-sysctrl.h>
@@ -29,6 +31,7 @@ struct r9a06g032_gate {
 /* This is used to describe a clock for instantiation */
 struct r9a06g032_clkdesc {
        const char *name;
+       uint32_t managed: 1;
        uint32_t type: 3;
        uint32_t index: 8;
        uint32_t source : 8; /* source index + 1 (0 == none) */
@@ -61,7 +64,11 @@ struct r9a06g032_clkdesc {
 #define D_GATE(_idx, _n, _src, ...) \
        { .type = K_GATE, .index = R9A06G032_##_idx, \
                .source = 1 + R9A06G032_##_src, .name = _n, \
-               .gate = I_GATE(__VA_ARGS__), }
+               .gate = I_GATE(__VA_ARGS__) }
+#define D_MODULE(_idx, _n, _src, ...) \
+       { .type = K_GATE, .index = R9A06G032_##_idx, \
+               .source = 1 + R9A06G032_##_src, .name = _n, \
+               .managed = 1, .gate = I_GATE(__VA_ARGS__) }
 #define D_ROOT(_idx, _n, _mul, _div) \
        { .type = K_FFC, .index = R9A06G032_##_idx, .name = _n, \
                .div = _div, .mul = _mul }
@@ -122,7 +129,7 @@ enum { K_GATE = 0, K_FFC, K_DIV, K_BITSEL, K_DUALGATE };
 
 #define R9A06G032_CLOCK_COUNT          (R9A06G032_UART_GROUP_34567 + 1)
 
-static const struct r9a06g032_clkdesc r9a06g032_clocks[] __initconst = {
+static const struct r9a06g032_clkdesc r9a06g032_clocks[] = {
        D_ROOT(CLKOUT, "clkout", 25, 1),
        D_ROOT(CLK_PLL_USB, "clk_pll_usb", 12, 10),
        D_FFC(CLKOUT_D10, "clkout_d10", CLKOUT, 10),
@@ -171,7 +178,7 @@ static const struct r9a06g032_clkdesc r9a06g032_clocks[] __initconst = {
        D_GATE(CLK_P6_PG2, "clk_p6_pg2", DIV_P6_PG, 0x8a3, 0x8a4, 0x8a5, 0, 0xb61, 0, 0),
        D_GATE(CLK_P6_PG3, "clk_p6_pg3", DIV_P6_PG, 0x8a6, 0x8a7, 0x8a8, 0, 0xb62, 0, 0),
        D_GATE(CLK_P6_PG4, "clk_p6_pg4", DIV_P6_PG, 0x8a9, 0x8aa, 0x8ab, 0, 0xb63, 0, 0),
-       D_GATE(CLK_PCI_USB, "clk_pci_usb", CLKOUT_D40, 0xe6, 0, 0, 0, 0, 0, 0),
+       D_MODULE(CLK_PCI_USB, "clk_pci_usb", CLKOUT_D40, 0xe6, 0, 0, 0, 0, 0, 0),
        D_GATE(CLK_QSPI0, "clk_qspi0", DIV_QSPI0, 0x2a4, 0x2a5, 0, 0, 0, 0, 0),
        D_GATE(CLK_QSPI1, "clk_qspi1", DIV_QSPI1, 0x484, 0x485, 0, 0, 0, 0, 0),
        D_GATE(CLK_RGMII_REF, "clk_rgmii_ref", CLKOUT_D8, 0x340, 0, 0, 0, 0, 0, 0),
@@ -188,17 +195,17 @@ static const struct r9a06g032_clkdesc r9a06g032_clocks[] __initconst = {
        D_GATE(CLK_SPI5, "clk_spi5", DIV_P4_PG, 0x822, 0x823, 0, 0, 0, 0, 0),
        D_GATE(CLK_SWITCH, "clk_switch", DIV_SWITCH, 0x982, 0x983, 0, 0, 0, 0, 0),
        D_DIV(DIV_MOTOR, "div_motor", CLKOUT_D5, 84, 2, 8),
-       D_GATE(HCLK_ECAT125, "hclk_ecat125", CLKOUT_D8, 0x400, 0x401, 0, 0x402, 0, 0x440, 0x441),
-       D_GATE(HCLK_PINCONFIG, "hclk_pinconfig", CLKOUT_D40, 0x740, 0x741, 0x742, 0, 0xae0, 0, 0),
-       D_GATE(HCLK_SERCOS, "hclk_sercos", CLKOUT_D10, 0x420, 0x422, 0, 0x421, 0, 0x460, 0x461),
-       D_GATE(HCLK_SGPIO2, "hclk_sgpio2", DIV_P5_PG, 0x8c3, 0x8c4, 0x8c5, 0, 0xb41, 0, 0),
-       D_GATE(HCLK_SGPIO3, "hclk_sgpio3", DIV_P5_PG, 0x8c6, 0x8c7, 0x8c8, 0, 0xb42, 0, 0),
-       D_GATE(HCLK_SGPIO4, "hclk_sgpio4", DIV_P5_PG, 0x8c9, 0x8ca, 0x8cb, 0, 0xb43, 0, 0),
-       D_GATE(HCLK_TIMER0, "hclk_timer0", CLKOUT_D40, 0x743, 0x744, 0x745, 0, 0xae1, 0, 0),
-       D_GATE(HCLK_TIMER1, "hclk_timer1", CLKOUT_D40, 0x746, 0x747, 0x748, 0, 0xae2, 0, 0),
-       D_GATE(HCLK_USBF, "hclk_usbf", CLKOUT_D8, 0xe3, 0, 0, 0xe4, 0, 0x102, 0x103),
-       D_GATE(HCLK_USBH, "hclk_usbh", CLKOUT_D8, 0xe0, 0xe1, 0, 0xe2, 0, 0x100, 0x101),
-       D_GATE(HCLK_USBPM, "hclk_usbpm", CLKOUT_D8, 0xe5, 0, 0, 0, 0, 0, 0),
+       D_MODULE(HCLK_ECAT125, "hclk_ecat125", CLKOUT_D8, 0x400, 0x401, 0, 0x402, 0, 0x440, 0x441),
+       D_MODULE(HCLK_PINCONFIG, "hclk_pinconfig", CLKOUT_D40, 0x740, 0x741, 0x742, 0, 0xae0, 0, 0),
+       D_MODULE(HCLK_SERCOS, "hclk_sercos", CLKOUT_D10, 0x420, 0x422, 0, 0x421, 0, 0x460, 0x461),
+       D_MODULE(HCLK_SGPIO2, "hclk_sgpio2", DIV_P5_PG, 0x8c3, 0x8c4, 0x8c5, 0, 0xb41, 0, 0),
+       D_MODULE(HCLK_SGPIO3, "hclk_sgpio3", DIV_P5_PG, 0x8c6, 0x8c7, 0x8c8, 0, 0xb42, 0, 0),
+       D_MODULE(HCLK_SGPIO4, "hclk_sgpio4", DIV_P5_PG, 0x8c9, 0x8ca, 0x8cb, 0, 0xb43, 0, 0),
+       D_MODULE(HCLK_TIMER0, "hclk_timer0", CLKOUT_D40, 0x743, 0x744, 0x745, 0, 0xae1, 0, 0),
+       D_MODULE(HCLK_TIMER1, "hclk_timer1", CLKOUT_D40, 0x746, 0x747, 0x748, 0, 0xae2, 0, 0),
+       D_MODULE(HCLK_USBF, "hclk_usbf", CLKOUT_D8, 0xe3, 0, 0, 0xe4, 0, 0x102, 0x103),
+       D_MODULE(HCLK_USBH, "hclk_usbh", CLKOUT_D8, 0xe0, 0xe1, 0, 0xe2, 0, 0x100, 0x101),
+       D_MODULE(HCLK_USBPM, "hclk_usbpm", CLKOUT_D8, 0xe5, 0, 0, 0, 0, 0, 0),
        D_GATE(CLK_48_PG_F, "clk_48_pg_f", CLK_48, 0x78c, 0x78d, 0, 0x78e, 0, 0xb04, 0xb05),
        D_GATE(CLK_48_PG4, "clk_48_pg4", CLK_48, 0x789, 0x78a, 0x78b, 0, 0xb03, 0, 0),
        D_FFC(CLK_DDRPHY_PLLCLK_D4, "clk_ddrphy_pllclk_d4", CLK_DDRPHY_PLLCLK, 4),
@@ -208,13 +215,13 @@ static const struct r9a06g032_clkdesc r9a06g032_clocks[] __initconst = {
        D_FFC(CLK_REF_SYNC_D8, "clk_ref_sync_d8", CLK_REF_SYNC, 8),
        D_FFC(CLK_SERCOS100_D2, "clk_sercos100_d2", CLK_SERCOS100, 2),
        D_DIV(DIV_CA7, "div_ca7", CLK_REF_SYNC, 57, 1, 4, 1, 2, 4),
-       D_GATE(HCLK_CAN0, "hclk_can0", CLK_48, 0x783, 0x784, 0x785, 0, 0xb01, 0, 0),
-       D_GATE(HCLK_CAN1, "hclk_can1", CLK_48, 0x786, 0x787, 0x788, 0, 0xb02, 0, 0),
-       D_GATE(HCLK_DELTASIGMA, "hclk_deltasigma", DIV_MOTOR, 0x1ef, 0x1f0, 0x1f1, 0, 0, 0, 0),
-       D_GATE(HCLK_PWMPTO, "hclk_pwmpto", DIV_MOTOR, 0x1ec, 0x1ed, 0x1ee, 0, 0, 0, 0),
-       D_GATE(HCLK_RSV, "hclk_rsv", CLK_48, 0x780, 0x781, 0x782, 0, 0xb00, 0, 0),
-       D_GATE(HCLK_SGPIO0, "hclk_sgpio0", DIV_MOTOR, 0x1e0, 0x1e1, 0x1e2, 0, 0, 0, 0),
-       D_GATE(HCLK_SGPIO1, "hclk_sgpio1", DIV_MOTOR, 0x1e3, 0x1e4, 0x1e5, 0, 0, 0, 0),
+       D_MODULE(HCLK_CAN0, "hclk_can0", CLK_48, 0x783, 0x784, 0x785, 0, 0xb01, 0, 0),
+       D_MODULE(HCLK_CAN1, "hclk_can1", CLK_48, 0x786, 0x787, 0x788, 0, 0xb02, 0, 0),
+       D_MODULE(HCLK_DELTASIGMA, "hclk_deltasigma", DIV_MOTOR, 0x1ef, 0x1f0, 0x1f1, 0, 0, 0, 0),
+       D_MODULE(HCLK_PWMPTO, "hclk_pwmpto", DIV_MOTOR, 0x1ec, 0x1ed, 0x1ee, 0, 0, 0, 0),
+       D_MODULE(HCLK_RSV, "hclk_rsv", CLK_48, 0x780, 0x781, 0x782, 0, 0xb00, 0, 0),
+       D_MODULE(HCLK_SGPIO0, "hclk_sgpio0", DIV_MOTOR, 0x1e0, 0x1e1, 0x1e2, 0, 0, 0, 0),
+       D_MODULE(HCLK_SGPIO1, "hclk_sgpio1", DIV_MOTOR, 0x1e3, 0x1e4, 0x1e5, 0, 0, 0, 0),
        D_DIV(RTOS_MDC, "rtos_mdc", CLK_REF_SYNC, 100, 80, 640, 80, 160, 320, 640),
        D_GATE(CLK_CM3, "clk_cm3", CLK_REF_SYNC_D4, 0xba0, 0xba1, 0, 0xba2, 0, 0xbc0, 0xbc1),
        D_GATE(CLK_DDRC, "clk_ddrc", CLK_DDRPHY_PLLCLK_D4, 0x323, 0x324, 0, 0, 0, 0, 0),
@@ -222,53 +229,53 @@ static const struct r9a06g032_clkdesc r9a06g032_clocks[] __initconst = {
        D_GATE(CLK_HSR50, "clk_hsr50", CLK_HSR100_D2, 0x484, 0x485, 0, 0, 0, 0, 0),
        D_GATE(CLK_HW_RTOS, "clk_hw_rtos", CLK_REF_SYNC_D4, 0xc60, 0xc61, 0, 0, 0, 0, 0),
        D_GATE(CLK_SERCOS50, "clk_sercos50", CLK_SERCOS100_D2, 0x424, 0x423, 0, 0, 0, 0, 0),
-       D_GATE(HCLK_ADC, "hclk_adc", CLK_REF_SYNC_D8, 0x1af, 0x1b0, 0x1b1, 0, 0, 0, 0),
-       D_GATE(HCLK_CM3, "hclk_cm3", CLK_REF_SYNC_D4, 0xc20, 0xc21, 0xc22, 0, 0, 0, 0),
-       D_GATE(HCLK_CRYPTO_EIP150, "hclk_crypto_eip150", CLK_REF_SYNC_D4, 0x123, 0x124, 0x125, 0, 0x142, 0, 0),
-       D_GATE(HCLK_CRYPTO_EIP93, "hclk_crypto_eip93", CLK_REF_SYNC_D4, 0x120, 0x121, 0, 0x122, 0, 0x140, 0x141),
-       D_GATE(HCLK_DDRC, "hclk_ddrc", CLK_REF_SYNC_D4, 0x320, 0x322, 0, 0x321, 0, 0x3a0, 0x3a1),
-       D_GATE(HCLK_DMA0, "hclk_dma0", CLK_REF_SYNC_D4, 0x260, 0x261, 0x262, 0x263, 0x2c0, 0x2c1, 0x2c2),
-       D_GATE(HCLK_DMA1, "hclk_dma1", CLK_REF_SYNC_D4, 0x264, 0x265, 0x266, 0x267, 0x2c3, 0x2c4, 0x2c5),
-       D_GATE(HCLK_GMAC0, "hclk_gmac0", CLK_REF_SYNC_D4, 0x360, 0x361, 0x362, 0x363, 0x3c0, 0x3c1, 0x3c2),
-       D_GATE(HCLK_GMAC1, "hclk_gmac1", CLK_REF_SYNC_D4, 0x380, 0x381, 0x382, 0x383, 0x3e0, 0x3e1, 0x3e2),
-       D_GATE(HCLK_GPIO0, "hclk_gpio0", CLK_REF_SYNC_D4, 0x212, 0x213, 0x214, 0, 0, 0, 0),
-       D_GATE(HCLK_GPIO1, "hclk_gpio1", CLK_REF_SYNC_D4, 0x215, 0x216, 0x217, 0, 0, 0, 0),
-       D_GATE(HCLK_GPIO2, "hclk_gpio2", CLK_REF_SYNC_D4, 0x229, 0x22a, 0x22b, 0, 0, 0, 0),
-       D_GATE(HCLK_HSR, "hclk_hsr", CLK_HSR100_D2, 0x480, 0x482, 0, 0x481, 0, 0x4c0, 0x4c1),
-       D_GATE(HCLK_I2C0, "hclk_i2c0", CLK_REF_SYNC_D8, 0x1a9, 0x1aa, 0x1ab, 0, 0, 0, 0),
-       D_GATE(HCLK_I2C1, "hclk_i2c1", CLK_REF_SYNC_D8, 0x1ac, 0x1ad, 0x1ae, 0, 0, 0, 0),
-       D_GATE(HCLK_LCD, "hclk_lcd", CLK_REF_SYNC_D4, 0x7a0, 0x7a1, 0x7a2, 0, 0xb20, 0, 0),
-       D_GATE(HCLK_MSEBI_M, "hclk_msebi_m", CLK_REF_SYNC_D4, 0x164, 0x165, 0x166, 0, 0x183, 0, 0),
-       D_GATE(HCLK_MSEBI_S, "hclk_msebi_s", CLK_REF_SYNC_D4, 0x160, 0x161, 0x162, 0x163, 0x180, 0x181, 0x182),
-       D_GATE(HCLK_NAND, "hclk_nand", CLK_REF_SYNC_D4, 0x280, 0x281, 0x282, 0x283, 0x2e0, 0x2e1, 0x2e2),
-       D_GATE(HCLK_PG_I, "hclk_pg_i", CLK_REF_SYNC_D4, 0x7ac, 0x7ad, 0, 0x7ae, 0, 0xb24, 0xb25),
-       D_GATE(HCLK_PG19, "hclk_pg19", CLK_REF_SYNC_D4, 0x22c, 0x22d, 0x22e, 0, 0, 0, 0),
-       D_GATE(HCLK_PG20, "hclk_pg20", CLK_REF_SYNC_D4, 0x22f, 0x230, 0x231, 0, 0, 0, 0),
-       D_GATE(HCLK_PG3, "hclk_pg3", CLK_REF_SYNC_D4, 0x7a6, 0x7a7, 0x7a8, 0, 0xb22, 0, 0),
-       D_GATE(HCLK_PG4, "hclk_pg4", CLK_REF_SYNC_D4, 0x7a9, 0x7aa, 0x7ab, 0, 0xb23, 0, 0),
-       D_GATE(HCLK_QSPI0, "hclk_qspi0", CLK_REF_SYNC_D4, 0x2a0, 0x2a1, 0x2a2, 0x2a3, 0x300, 0x301, 0x302),
-       D_GATE(HCLK_QSPI1, "hclk_qspi1", CLK_REF_SYNC_D4, 0x480, 0x481, 0x482, 0x483, 0x4c0, 0x4c1, 0x4c2),
-       D_GATE(HCLK_ROM, "hclk_rom", CLK_REF_SYNC_D4, 0xaa0, 0xaa1, 0xaa2, 0, 0xb80, 0, 0),
-       D_GATE(HCLK_RTC, "hclk_rtc", CLK_REF_SYNC_D8, 0xa00, 0, 0, 0, 0, 0, 0),
-       D_GATE(HCLK_SDIO0, "hclk_sdio0", CLK_REF_SYNC_D4, 0x60, 0x61, 0x62, 0x63, 0x80, 0x81, 0x82),
-       D_GATE(HCLK_SDIO1, "hclk_sdio1", CLK_REF_SYNC_D4, 0x640, 0x641, 0x642, 0x643, 0x660, 0x661, 0x662),
-       D_GATE(HCLK_SEMAP, "hclk_semap", CLK_REF_SYNC_D4, 0x7a3, 0x7a4, 0x7a5, 0, 0xb21, 0, 0),
-       D_GATE(HCLK_SPI0, "hclk_spi0", CLK_REF_SYNC_D4, 0x200, 0x201, 0x202, 0, 0, 0, 0),
-       D_GATE(HCLK_SPI1, "hclk_spi1", CLK_REF_SYNC_D4, 0x203, 0x204, 0x205, 0, 0, 0, 0),
-       D_GATE(HCLK_SPI2, "hclk_spi2", CLK_REF_SYNC_D4, 0x206, 0x207, 0x208, 0, 0, 0, 0),
-       D_GATE(HCLK_SPI3, "hclk_spi3", CLK_REF_SYNC_D4, 0x209, 0x20a, 0x20b, 0, 0, 0, 0),
-       D_GATE(HCLK_SPI4, "hclk_spi4", CLK_REF_SYNC_D4, 0x20c, 0x20d, 0x20e, 0, 0, 0, 0),
-       D_GATE(HCLK_SPI5, "hclk_spi5", CLK_REF_SYNC_D4, 0x20f, 0x210, 0x211, 0, 0, 0, 0),
-       D_GATE(HCLK_SWITCH, "hclk_switch", CLK_REF_SYNC_D4, 0x980, 0, 0x981, 0, 0, 0, 0),
-       D_GATE(HCLK_SWITCH_RG, "hclk_switch_rg", CLK_REF_SYNC_D4, 0xc40, 0xc41, 0xc42, 0, 0, 0, 0),
-       D_GATE(HCLK_UART0, "hclk_uart0", CLK_REF_SYNC_D8, 0x1a0, 0x1a1, 0x1a2, 0, 0, 0, 0),
-       D_GATE(HCLK_UART1, "hclk_uart1", CLK_REF_SYNC_D8, 0x1a3, 0x1a4, 0x1a5, 0, 0, 0, 0),
-       D_GATE(HCLK_UART2, "hclk_uart2", CLK_REF_SYNC_D8, 0x1a6, 0x1a7, 0x1a8, 0, 0, 0, 0),
-       D_GATE(HCLK_UART3, "hclk_uart3", CLK_REF_SYNC_D4, 0x218, 0x219, 0x21a, 0, 0, 0, 0),
-       D_GATE(HCLK_UART4, "hclk_uart4", CLK_REF_SYNC_D4, 0x21b, 0x21c, 0x21d, 0, 0, 0, 0),
-       D_GATE(HCLK_UART5, "hclk_uart5", CLK_REF_SYNC_D4, 0x220, 0x221, 0x222, 0, 0, 0, 0),
-       D_GATE(HCLK_UART6, "hclk_uart6", CLK_REF_SYNC_D4, 0x223, 0x224, 0x225, 0, 0, 0, 0),
-       D_GATE(HCLK_UART7, "hclk_uart7", CLK_REF_SYNC_D4, 0x226, 0x227, 0x228, 0, 0, 0, 0),
+       D_MODULE(HCLK_ADC, "hclk_adc", CLK_REF_SYNC_D8, 0x1af, 0x1b0, 0x1b1, 0, 0, 0, 0),
+       D_MODULE(HCLK_CM3, "hclk_cm3", CLK_REF_SYNC_D4, 0xc20, 0xc21, 0xc22, 0, 0, 0, 0),
+       D_MODULE(HCLK_CRYPTO_EIP150, "hclk_crypto_eip150", CLK_REF_SYNC_D4, 0x123, 0x124, 0x125, 0, 0x142, 0, 0),
+       D_MODULE(HCLK_CRYPTO_EIP93, "hclk_crypto_eip93", CLK_REF_SYNC_D4, 0x120, 0x121, 0, 0x122, 0, 0x140, 0x141),
+       D_MODULE(HCLK_DDRC, "hclk_ddrc", CLK_REF_SYNC_D4, 0x320, 0x322, 0, 0x321, 0, 0x3a0, 0x3a1),
+       D_MODULE(HCLK_DMA0, "hclk_dma0", CLK_REF_SYNC_D4, 0x260, 0x261, 0x262, 0x263, 0x2c0, 0x2c1, 0x2c2),
+       D_MODULE(HCLK_DMA1, "hclk_dma1", CLK_REF_SYNC_D4, 0x264, 0x265, 0x266, 0x267, 0x2c3, 0x2c4, 0x2c5),
+       D_MODULE(HCLK_GMAC0, "hclk_gmac0", CLK_REF_SYNC_D4, 0x360, 0x361, 0x362, 0x363, 0x3c0, 0x3c1, 0x3c2),
+       D_MODULE(HCLK_GMAC1, "hclk_gmac1", CLK_REF_SYNC_D4, 0x380, 0x381, 0x382, 0x383, 0x3e0, 0x3e1, 0x3e2),
+       D_MODULE(HCLK_GPIO0, "hclk_gpio0", CLK_REF_SYNC_D4, 0x212, 0x213, 0x214, 0, 0, 0, 0),
+       D_MODULE(HCLK_GPIO1, "hclk_gpio1", CLK_REF_SYNC_D4, 0x215, 0x216, 0x217, 0, 0, 0, 0),
+       D_MODULE(HCLK_GPIO2, "hclk_gpio2", CLK_REF_SYNC_D4, 0x229, 0x22a, 0x22b, 0, 0, 0, 0),
+       D_MODULE(HCLK_HSR, "hclk_hsr", CLK_HSR100_D2, 0x480, 0x482, 0, 0x481, 0, 0x4c0, 0x4c1),
+       D_MODULE(HCLK_I2C0, "hclk_i2c0", CLK_REF_SYNC_D8, 0x1a9, 0x1aa, 0x1ab, 0, 0, 0, 0),
+       D_MODULE(HCLK_I2C1, "hclk_i2c1", CLK_REF_SYNC_D8, 0x1ac, 0x1ad, 0x1ae, 0, 0, 0, 0),
+       D_MODULE(HCLK_LCD, "hclk_lcd", CLK_REF_SYNC_D4, 0x7a0, 0x7a1, 0x7a2, 0, 0xb20, 0, 0),
+       D_MODULE(HCLK_MSEBI_M, "hclk_msebi_m", CLK_REF_SYNC_D4, 0x164, 0x165, 0x166, 0, 0x183, 0, 0),
+       D_MODULE(HCLK_MSEBI_S, "hclk_msebi_s", CLK_REF_SYNC_D4, 0x160, 0x161, 0x162, 0x163, 0x180, 0x181, 0x182),
+       D_MODULE(HCLK_NAND, "hclk_nand", CLK_REF_SYNC_D4, 0x280, 0x281, 0x282, 0x283, 0x2e0, 0x2e1, 0x2e2),
+       D_MODULE(HCLK_PG_I, "hclk_pg_i", CLK_REF_SYNC_D4, 0x7ac, 0x7ad, 0, 0x7ae, 0, 0xb24, 0xb25),
+       D_MODULE(HCLK_PG19, "hclk_pg19", CLK_REF_SYNC_D4, 0x22c, 0x22d, 0x22e, 0, 0, 0, 0),
+       D_MODULE(HCLK_PG20, "hclk_pg20", CLK_REF_SYNC_D4, 0x22f, 0x230, 0x231, 0, 0, 0, 0),
+       D_MODULE(HCLK_PG3, "hclk_pg3", CLK_REF_SYNC_D4, 0x7a6, 0x7a7, 0x7a8, 0, 0xb22, 0, 0),
+       D_MODULE(HCLK_PG4, "hclk_pg4", CLK_REF_SYNC_D4, 0x7a9, 0x7aa, 0x7ab, 0, 0xb23, 0, 0),
+       D_MODULE(HCLK_QSPI0, "hclk_qspi0", CLK_REF_SYNC_D4, 0x2a0, 0x2a1, 0x2a2, 0x2a3, 0x300, 0x301, 0x302),
+       D_MODULE(HCLK_QSPI1, "hclk_qspi1", CLK_REF_SYNC_D4, 0x480, 0x481, 0x482, 0x483, 0x4c0, 0x4c1, 0x4c2),
+       D_MODULE(HCLK_ROM, "hclk_rom", CLK_REF_SYNC_D4, 0xaa0, 0xaa1, 0xaa2, 0, 0xb80, 0, 0),
+       D_MODULE(HCLK_RTC, "hclk_rtc", CLK_REF_SYNC_D8, 0xa00, 0, 0, 0, 0, 0, 0),
+       D_MODULE(HCLK_SDIO0, "hclk_sdio0", CLK_REF_SYNC_D4, 0x60, 0x61, 0x62, 0x63, 0x80, 0x81, 0x82),
+       D_MODULE(HCLK_SDIO1, "hclk_sdio1", CLK_REF_SYNC_D4, 0x640, 0x641, 0x642, 0x643, 0x660, 0x661, 0x662),
+       D_MODULE(HCLK_SEMAP, "hclk_semap", CLK_REF_SYNC_D4, 0x7a3, 0x7a4, 0x7a5, 0, 0xb21, 0, 0),
+       D_MODULE(HCLK_SPI0, "hclk_spi0", CLK_REF_SYNC_D4, 0x200, 0x201, 0x202, 0, 0, 0, 0),
+       D_MODULE(HCLK_SPI1, "hclk_spi1", CLK_REF_SYNC_D4, 0x203, 0x204, 0x205, 0, 0, 0, 0),
+       D_MODULE(HCLK_SPI2, "hclk_spi2", CLK_REF_SYNC_D4, 0x206, 0x207, 0x208, 0, 0, 0, 0),
+       D_MODULE(HCLK_SPI3, "hclk_spi3", CLK_REF_SYNC_D4, 0x209, 0x20a, 0x20b, 0, 0, 0, 0),
+       D_MODULE(HCLK_SPI4, "hclk_spi4", CLK_REF_SYNC_D4, 0x20c, 0x20d, 0x20e, 0, 0, 0, 0),
+       D_MODULE(HCLK_SPI5, "hclk_spi5", CLK_REF_SYNC_D4, 0x20f, 0x210, 0x211, 0, 0, 0, 0),
+       D_MODULE(HCLK_SWITCH, "hclk_switch", CLK_REF_SYNC_D4, 0x980, 0, 0x981, 0, 0, 0, 0),
+       D_MODULE(HCLK_SWITCH_RG, "hclk_switch_rg", CLK_REF_SYNC_D4, 0xc40, 0xc41, 0xc42, 0, 0, 0, 0),
+       D_MODULE(HCLK_UART0, "hclk_uart0", CLK_REF_SYNC_D8, 0x1a0, 0x1a1, 0x1a2, 0, 0, 0, 0),
+       D_MODULE(HCLK_UART1, "hclk_uart1", CLK_REF_SYNC_D8, 0x1a3, 0x1a4, 0x1a5, 0, 0, 0, 0),
+       D_MODULE(HCLK_UART2, "hclk_uart2", CLK_REF_SYNC_D8, 0x1a6, 0x1a7, 0x1a8, 0, 0, 0, 0),
+       D_MODULE(HCLK_UART3, "hclk_uart3", CLK_REF_SYNC_D4, 0x218, 0x219, 0x21a, 0, 0, 0, 0),
+       D_MODULE(HCLK_UART4, "hclk_uart4", CLK_REF_SYNC_D4, 0x21b, 0x21c, 0x21d, 0, 0, 0, 0),
+       D_MODULE(HCLK_UART5, "hclk_uart5", CLK_REF_SYNC_D4, 0x220, 0x221, 0x222, 0, 0, 0, 0),
+       D_MODULE(HCLK_UART6, "hclk_uart6", CLK_REF_SYNC_D4, 0x223, 0x224, 0x225, 0, 0, 0, 0),
+       D_MODULE(HCLK_UART7, "hclk_uart7", CLK_REF_SYNC_D4, 0x226, 0x227, 0x228, 0, 0, 0, 0),
        /*
         * These are not hardware clocks, but are needed to handle the special
         * case where we have a 'selector bit' that doesn't just change the
@@ -345,6 +352,84 @@ struct r9a06g032_clk_gate {
 
 #define to_r9a06g032_gate(_hw) container_of(_hw, struct r9a06g032_clk_gate, hw)
 
+static int create_add_module_clock(struct of_phandle_args *clkspec,
+                                  struct device *dev)
+{
+       struct clk *clk;
+       int error;
+
+       clk = of_clk_get_from_provider(clkspec);
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       error = pm_clk_create(dev);
+       if (error) {
+               clk_put(clk);
+               return error;
+       }
+
+       error = pm_clk_add_clk(dev, clk);
+       if (error) {
+               pm_clk_destroy(dev);
+               clk_put(clk);
+       }
+
+       return error;
+}
+
+static int r9a06g032_attach_dev(struct generic_pm_domain *pd,
+                               struct device *dev)
+{
+       struct device_node *np = dev->of_node;
+       struct of_phandle_args clkspec;
+       int i = 0;
+       int error;
+       int index;
+
+       while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i,
+                                          &clkspec)) {
+               if (clkspec.np != pd->dev.of_node)
+                       continue;
+
+               index = clkspec.args[0];
+               if (index < R9A06G032_CLOCK_COUNT &&
+                   r9a06g032_clocks[index].managed) {
+                       error = create_add_module_clock(&clkspec, dev);
+                       of_node_put(clkspec.np);
+                       if (error)
+                               return error;
+               }
+               i++;
+       }
+
+       return 0;
+}
+
+static void r9a06g032_detach_dev(struct generic_pm_domain *unused, struct device *dev)
+{
+       if (!pm_clk_no_clocks(dev))
+               pm_clk_destroy(dev);
+}
+
+static int r9a06g032_add_clk_domain(struct device *dev)
+{
+       struct device_node *np = dev->of_node;
+       struct generic_pm_domain *pd;
+
+       pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+       if (!pd)
+               return -ENOMEM;
+
+       pd->name = np->name;
+       pd->flags = GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP;
+       pd->attach_dev = r9a06g032_attach_dev;
+       pd->detach_dev = r9a06g032_detach_dev;
+       pm_genpd_init(pd, &pm_domain_always_on_gov, false);
+
+       of_genpd_add_provider_simple(np, pd);
+       return 0;
+}
+
 static void
 r9a06g032_clk_gate_set(struct r9a06g032_priv *clocks,
                       struct r9a06g032_gate *g, int on)
@@ -871,8 +956,12 @@ static int __init r9a06g032_clocks_probe(struct platform_device *pdev)
        if (error)
                return error;
 
-       return devm_add_action_or_reset(dev,
+       error = devm_add_action_or_reset(dev,
                                        r9a06g032_clocks_del_clk_provider, np);
+       if (error)
+               return error;
+
+       return r9a06g032_add_clk_domain(dev);
 }
 
 static const struct of_device_id r9a06g032_match[] = {
index 0201809..52bbb9c 100644 (file)
@@ -112,14 +112,15 @@ static const u16 srcr[] = {
  * @dev: CPG/MSSR device
  * @base: CPG/MSSR register block base address
  * @rmw_lock: protects RMW register accesses
- * @clks: Array containing all Core and Module Clocks
+ * @np: Device node in DT for this CPG/MSSR module
  * @num_core_clks: Number of Core Clocks in clks[]
  * @num_mod_clks: Number of Module Clocks in clks[]
  * @last_dt_core_clk: ID of the last Core Clock exported to DT
+ * @stbyctrl: This device has Standby Control Registers
  * @notifiers: Notifier chain to save/restore clock state for system resume
  * @smstpcr_saved[].mask: Mask of SMSTPCR[] bits under our control
  * @smstpcr_saved[].val: Saved values of SMSTPCR[]
- * @stbyctrl: This device has Standby Control Registers
+ * @clks: Array containing all Core and Module Clocks
  */
 struct cpg_mssr_priv {
 #ifdef CONFIG_RESET_CONTROLLER
@@ -130,7 +131,6 @@ struct cpg_mssr_priv {
        spinlock_t rmw_lock;
        struct device_node *np;
 
-       struct clk **clks;
        unsigned int num_core_clks;
        unsigned int num_mod_clks;
        unsigned int last_dt_core_clk;
@@ -141,6 +141,8 @@ struct cpg_mssr_priv {
                u32 mask;
                u32 val;
        } smstpcr_saved[ARRAY_SIZE(smstpcr)];
+
+       struct clk *clks[];
 };
 
 static struct cpg_mssr_priv *cpg_mssr_priv;
@@ -447,9 +449,8 @@ fail:
 
 struct cpg_mssr_clk_domain {
        struct generic_pm_domain genpd;
-       struct device_node *np;
        unsigned int num_core_pm_clks;
-       unsigned int core_pm_clks[0];
+       unsigned int core_pm_clks[];
 };
 
 static struct cpg_mssr_clk_domain *cpg_mssr_clk_domain;
@@ -459,7 +460,7 @@ static bool cpg_mssr_is_pm_clk(const struct of_phandle_args *clkspec,
 {
        unsigned int i;
 
-       if (clkspec->np != pd->np || clkspec->args_count != 2)
+       if (clkspec->np != pd->genpd.dev.of_node || clkspec->args_count != 2)
                return false;
 
        switch (clkspec->args[0]) {
@@ -510,16 +511,12 @@ found:
                return PTR_ERR(clk);
 
        error = pm_clk_create(dev);
-       if (error) {
-               dev_err(dev, "pm_clk_create failed %d\n", error);
+       if (error)
                goto fail_put;
-       }
 
        error = pm_clk_add_clk(dev, clk);
-       if (error) {
-               dev_err(dev, "pm_clk_add_clk %pC failed %d\n", clk, error);
+       if (error)
                goto fail_destroy;
-       }
 
        return 0;
 
@@ -549,7 +546,6 @@ static int __init cpg_mssr_add_clk_domain(struct device *dev,
        if (!pd)
                return -ENOMEM;
 
-       pd->np = np;
        pd->num_core_pm_clks = num_core_pm_clks;
        memcpy(pd->core_pm_clks, core_pm_clks, pm_size);
 
@@ -896,7 +892,6 @@ static int __init cpg_mssr_common_init(struct device *dev,
                                       const struct cpg_mssr_info *info)
 {
        struct cpg_mssr_priv *priv;
-       struct clk **clks = NULL;
        unsigned int nclks, i;
        int error;
 
@@ -906,7 +901,8 @@ static int __init cpg_mssr_common_init(struct device *dev,
                        return error;
        }
 
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       nclks = info->num_total_core_clks + info->num_hw_mod_clks;
+       priv = kzalloc(struct_size(priv, clks, nclks), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
@@ -920,15 +916,7 @@ static int __init cpg_mssr_common_init(struct device *dev,
                goto out_err;
        }
 
-       nclks = info->num_total_core_clks + info->num_hw_mod_clks;
-       clks = kmalloc_array(nclks, sizeof(*clks), GFP_KERNEL);
-       if (!clks) {
-               error = -ENOMEM;
-               goto out_err;
-       }
-
        cpg_mssr_priv = priv;
-       priv->clks = clks;
        priv->num_core_clks = info->num_total_core_clks;
        priv->num_mod_clks = info->num_hw_mod_clks;
        priv->last_dt_core_clk = info->last_dt_core_clk;
@@ -936,7 +924,7 @@ static int __init cpg_mssr_common_init(struct device *dev,
        priv->stbyctrl = info->stbyctrl;
 
        for (i = 0; i < nclks; i++)
-               clks[i] = ERR_PTR(-ENOENT);
+               priv->clks[i] = ERR_PTR(-ENOENT);
 
        error = of_clk_add_provider(np, cpg_mssr_clk_src_twocell_get, priv);
        if (error)
@@ -945,7 +933,6 @@ static int __init cpg_mssr_common_init(struct device *dev,
        return 0;
 
 out_err:
-       kfree(clks);
        if (priv->base)
                iounmap(priv->base);
        kfree(priv);
index c61f4d3..4abe7ff 100644 (file)
@@ -46,29 +46,27 @@ static unsigned long rockchip_mmc_recalc(struct clk_hw *hw,
 static int rockchip_mmc_get_phase(struct clk_hw *hw)
 {
        struct rockchip_mmc_clock *mmc_clock = to_mmc_clock(hw);
-       unsigned long rate = clk_get_rate(hw->clk);
+       unsigned long rate = clk_hw_get_rate(hw);
        u32 raw_value;
        u16 degrees;
        u32 delay_num = 0;
 
        /* See the comment for rockchip_mmc_set_phase below */
-       if (!rate) {
-               pr_err("%s: invalid clk rate\n", __func__);
+       if (!rate)
                return -EINVAL;
-       }
 
        raw_value = readl(mmc_clock->reg) >> (mmc_clock->shift);
 
        degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90;
 
        if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
-               /* degrees/delaynum * 10000 */
+               /* degrees/delaynum * 1000000 */
                unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
-                                       36 * (rate / 1000000);
+                                       36 * (rate / 10000);
 
                delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
                delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
-               degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
+               degrees += DIV_ROUND_CLOSEST(delay_num * factor, 1000000);
        }
 
        return degrees % 360;
@@ -77,7 +75,7 @@ static int rockchip_mmc_get_phase(struct clk_hw *hw)
 static int rockchip_mmc_set_phase(struct clk_hw *hw, int degrees)
 {
        struct rockchip_mmc_clock *mmc_clock = to_mmc_clock(hw);
-       unsigned long rate = clk_get_rate(hw->clk);
+       unsigned long rate = clk_hw_get_rate(hw);
        u8 nineties, remainder;
        u8 delay_num;
        u32 raw_value;
index bb39a79..3a50189 100644 (file)
@@ -794,6 +794,9 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
        GATE(ACLK_GIC, "aclk_gic", "aclk_bus_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(13), 12, GFLAGS),
        GATE(ACLK_DCF, "aclk_dcf", "aclk_bus_pre", 0, PX30_CLKGATE_CON(13), 15, GFLAGS),
 
+       /* aclk_dmac is controlled by sgrf_soc_con1[11]. */
+       SGRF_GATE(ACLK_DMAC, "aclk_dmac", "aclk_bus_pre"),
+
        GATE(0, "hclk_bus_niu", "hclk_bus_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(13), 9, GFLAGS),
        GATE(0, "hclk_rom", "hclk_bus_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(13), 14, GFLAGS),
        GATE(HCLK_PDM, "hclk_pdm", "hclk_bus_pre", 0, PX30_CLKGATE_CON(14), 1, GFLAGS),
@@ -957,7 +960,6 @@ static void __init px30_clk_init(struct device_node *np)
 {
        struct rockchip_clk_provider *ctx;
        void __iomem *reg_base;
-       struct clk *clk;
 
        reg_base = of_iomap(np, 0);
        if (!reg_base) {
@@ -972,14 +974,6 @@ static void __init px30_clk_init(struct device_node *np)
                return;
        }
 
-       /* aclk_dmac is controlled by sgrf_soc_con1[11]. */
-       clk = clk_register_fixed_factor(NULL, "aclk_dmac", "aclk_bus_pre", 0, 1, 1);
-       if (IS_ERR(clk))
-               pr_warn("%s: could not register clock aclk_dmac: %ld\n",
-                       __func__, PTR_ERR(clk));
-       else
-               rockchip_clk_add_lookup(ctx, clk, ACLK_DMAC);
-
        rockchip_clk_register_plls(ctx, px30_pll_clks,
                                   ARRAY_SIZE(px30_pll_clks),
                                   PX30_GRF_SOC_STATUS0);
index bdb1263..d17cfb7 100644 (file)
@@ -101,6 +101,7 @@ static struct rockchip_cpuclk_rate_table rk3228_cpuclk_rates[] __initdata = {
        RK3228_CPUCLK_RATE(1608000000, 1, 7),
        RK3228_CPUCLK_RATE(1512000000, 1, 7),
        RK3228_CPUCLK_RATE(1488000000, 1, 5),
+       RK3228_CPUCLK_RATE(1464000000, 1, 5),
        RK3228_CPUCLK_RATE(1416000000, 1, 5),
        RK3228_CPUCLK_RATE(1392000000, 1, 5),
        RK3228_CPUCLK_RATE(1296000000, 1, 5),
@@ -246,7 +247,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = {
                        RK2928_CLKGATE_CON(4), 0, GFLAGS),
 
        /* PD_MISC */
-       MUX(0, "hdmiphy", mux_hdmiphy_p, CLK_SET_RATE_PARENT,
+       MUX(SCLK_HDMI_PHY, "hdmiphy", mux_hdmiphy_p, CLK_SET_RATE_PARENT,
                        RK2928_MISC_CON, 13, 1, MFLAGS),
        MUX(0, "usb480m_phy", mux_usb480m_phy_p, CLK_SET_RATE_PARENT,
                        RK2928_MISC_CON, 14, 1, MFLAGS),
index 0576296..cc2a177 100644 (file)
@@ -113,7 +113,6 @@ static struct rockchip_pll_rate_table rk3288_pll_rates[] = {
        RK3066_PLL_RATE( 160000000, 1, 80, 12),
        RK3066_PLL_RATE( 157500000, 1, 105, 16),
        RK3066_PLL_RATE( 126000000, 1, 84, 16),
-       RK3066_PLL_RATE(  48000000, 1, 64, 32),
        { /* sentinel */ },
 };
 
@@ -767,6 +766,9 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
        GATE(PCLK_GRF, "pclk_grf", "pclk_pd_alive", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(14), 11, GFLAGS),
        GATE(0, "pclk_alive_niu", "pclk_pd_alive", 0, RK3288_CLKGATE_CON(14), 12, GFLAGS),
 
+       /* Watchdog pclk is controlled by RK3288_SGRF_SOC_CON0[1]. */
+       SGRF_GATE(PCLK_WDT, "pclk_wdt", "pclk_pd_alive"),
+
        /* pclk_pd_pmu gates */
        GATE(PCLK_PMU, "pclk_pmu", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(17), 0, GFLAGS),
        GATE(0, "pclk_intmem1", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(17), 1, GFLAGS),
@@ -915,7 +917,6 @@ static struct syscore_ops rk3288_clk_syscore_ops = {
 static void __init rk3288_clk_init(struct device_node *np)
 {
        struct rockchip_clk_provider *ctx;
-       struct clk *clk;
 
        rk3288_cru_base = of_iomap(np, 0);
        if (!rk3288_cru_base) {
@@ -930,14 +931,6 @@ static void __init rk3288_clk_init(struct device_node *np)
                return;
        }
 
-       /* Watchdog pclk is controlled by RK3288_SGRF_SOC_CON0[1]. */
-       clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_pd_alive", 0, 1, 1);
-       if (IS_ERR(clk))
-               pr_warn("%s: could not register clock pclk_wdt: %ld\n",
-                       __func__, PTR_ERR(clk));
-       else
-               rockchip_clk_add_lookup(ctx, clk, PCLK_WDT);
-
        rockchip_clk_register_plls(ctx, rk3288_pll_clks,
                                   ARRAY_SIZE(rk3288_pll_clks),
                                   RK3288_GRF_SOC_STATUS1);
index 076b977..c186a19 100644 (file)
@@ -791,6 +791,9 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
        GATE(PCLK_SARADC, "pclk_saradc", "pclk_bus", 0, RK3328_CLKGATE_CON(17), 15, GFLAGS),
        GATE(0, "pclk_pmu", "pclk_bus", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(28), 3, GFLAGS),
 
+       /* Watchdog pclk is controlled from the secure GRF */
+       SGRF_GATE(PCLK_WDT, "pclk_wdt", "pclk_bus"),
+
        GATE(PCLK_USB3PHY_OTG, "pclk_usb3phy_otg", "pclk_phy_pre", 0, RK3328_CLKGATE_CON(28), 1, GFLAGS),
        GATE(PCLK_USB3PHY_PIPE, "pclk_usb3phy_pipe", "pclk_phy_pre", 0, RK3328_CLKGATE_CON(28), 2, GFLAGS),
        GATE(PCLK_USB3_GRF, "pclk_usb3_grf", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(17), 2, GFLAGS),
index 43b022d..5544334 100644 (file)
@@ -811,6 +811,9 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
        GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(22), 2, GFLAGS),
        GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(22), 1, GFLAGS),
 
+       /* Watchdog pclk is controlled by sgrf_soc_con3[7]. */
+       SGRF_GATE(PCLK_WDT, "pclk_wdt", "pclk_pd_alive"),
+
        /*
         * pclk_vio gates
         * pclk_vio comes from the exactly same source as hclk_vio
@@ -862,7 +865,6 @@ static void __init rk3368_clk_init(struct device_node *np)
 {
        struct rockchip_clk_provider *ctx;
        void __iomem *reg_base;
-       struct clk *clk;
 
        reg_base = of_iomap(np, 0);
        if (!reg_base) {
@@ -877,14 +879,6 @@ static void __init rk3368_clk_init(struct device_node *np)
                return;
        }
 
-       /* Watchdog pclk is controlled by sgrf_soc_con3[7]. */
-       clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_pd_alive", 0, 1, 1);
-       if (IS_ERR(clk))
-               pr_warn("%s: could not register clock pclk_wdt: %ld\n",
-                       __func__, PTR_ERR(clk));
-       else
-               rockchip_clk_add_lookup(ctx, clk, PCLK_WDT);
-
        rockchip_clk_register_plls(ctx, rk3368_pll_clks,
                                   ARRAY_SIZE(rk3368_pll_clks),
                                   RK3368_GRF_SOC_STATUS0);
index a7ff713..ce1d244 100644 (file)
@@ -1295,6 +1295,9 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
        GATE(PCLK_PMU_INTR_ARB, "pclk_pmu_intr_arb", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 9, GFLAGS),
        GATE(PCLK_SGRF, "pclk_sgrf", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 10, GFLAGS),
 
+       /* Watchdog pclk is controlled by RK3399 SECURE_GRF_SOC_CON3[8]. */
+       SGRF_GATE(PCLK_WDT, "pclk_wdt", "pclk_alive"),
+
        GATE(SCLK_MIPIDPHY_REF, "clk_mipidphy_ref", "xin24m", 0, RK3399_CLKGATE_CON(11), 14, GFLAGS),
        GATE(SCLK_DPHY_PLL, "clk_dphy_pll", "clk_mipidphy_ref", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 0, GFLAGS),
 
@@ -1522,7 +1525,6 @@ static void __init rk3399_clk_init(struct device_node *np)
 {
        struct rockchip_clk_provider *ctx;
        void __iomem *reg_base;
-       struct clk *clk;
 
        reg_base = of_iomap(np, 0);
        if (!reg_base) {
@@ -1537,14 +1539,6 @@ static void __init rk3399_clk_init(struct device_node *np)
                return;
        }
 
-       /* Watchdog pclk is controlled by RK3399 SECURE_GRF_SOC_CON3[8]. */
-       clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_alive", 0, 1, 1);
-       if (IS_ERR(clk))
-               pr_warn("%s: could not register clock pclk_wdt: %ld\n",
-                       __func__, PTR_ERR(clk));
-       else
-               rockchip_clk_add_lookup(ctx, clk, PCLK_WDT);
-
        rockchip_clk_register_plls(ctx, rk3399_pll_clks,
                                   ARRAY_SIZE(rk3399_pll_clks), -1);
 
index adb66cc..b811597 100644 (file)
@@ -811,6 +811,10 @@ struct rockchip_clk_branch {
                .gate_offset    = -1,                           \
        }
 
+/* SGRF clocks are only accessible from secure mode, so not controllable */
+#define SGRF_GATE(_id, cname, pname)                           \
+               FACTOR(_id, cname, pname, 0, 1, 1)
+
 struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np,
                        void __iomem *base, unsigned long nr_clks);
 void rockchip_clk_of_add_provider(struct device_node *np,
index 982eb02..51564fc 100644 (file)
@@ -958,6 +958,7 @@ static const struct samsung_gate_clock exynos4210_gate_clks[] __initconst = {
 
 /* list of gate clocks supported in exynos4x12 soc */
 static const struct samsung_gate_clock exynos4x12_gate_clks[] __initconst = {
+       GATE(CLK_ASYNC_G3D, "async_g3d", "aclk200", GATE_IP_LEFTBUS, 6, 0, 0),
        GATE(CLK_AUDSS, "audss", "sclk_epll", E4X12_GATE_IP_MAUDIO, 0, 0, 0),
        GATE(CLK_MDNIE0, "mdnie0", "aclk160", GATE_IP_LCD0, 2, 0, 0),
        GATE(CLK_ROTATOR, "rotator", "aclk200", E4X12_GATE_IP_IMAGE, 1, 0, 0),
index 12d800f..01bca5a 100644 (file)
 #define SRC_CDREX              0x20200
 #define DIV_CDREX0             0x20500
 #define DIV_CDREX1             0x20504
+#define GATE_BUS_CDREX0                0x20700
+#define GATE_BUS_CDREX1                0x20704
 #define KPLL_LOCK              0x28000
 #define KPLL_CON0              0x28100
 #define SRC_KFC                        0x28200
@@ -245,6 +247,8 @@ static const unsigned long exynos5x_clk_regs[] __initconst = {
        DIV_CDREX1,
        SRC_KFC,
        DIV_KFC0,
+       GATE_BUS_CDREX0,
+       GATE_BUS_CDREX1,
 };
 
 static const unsigned long exynos5800_clk_regs[] __initconst = {
@@ -422,6 +426,9 @@ PNAME(mout_group13_5800_p)  = { "dout_osc_div", "mout_sw_aclkfl1_550_cam" };
 PNAME(mout_group14_5800_p)     = { "dout_aclk550_cam", "dout_sclk_sw" };
 PNAME(mout_group15_5800_p)     = { "dout_osc_div", "mout_sw_aclk550_cam" };
 PNAME(mout_group16_5800_p)     = { "dout_osc_div", "mout_mau_epll_clk" };
+PNAME(mout_mx_mspll_ccore_phy_p) = { "sclk_bpll", "mout_sclk_dpll",
+                                       "mout_sclk_mpll", "ff_dout_spll2",
+                                       "mout_sclk_spll", "mout_sclk_epll"};
 
 /* fixed rate clocks generated outside the soc */
 static struct samsung_fixed_rate_clock
@@ -447,7 +454,7 @@ static const struct samsung_fixed_factor_clock
 static const struct samsung_fixed_factor_clock
                exynos5800_fixed_factor_clks[] __initconst = {
        FFACTOR(0, "ff_dout_epll2", "mout_sclk_epll", 1, 2, 0),
-       FFACTOR(0, "ff_dout_spll2", "mout_sclk_spll", 1, 2, 0),
+       FFACTOR(CLK_FF_DOUT_SPLL2, "ff_dout_spll2", "mout_sclk_spll", 1, 2, 0),
 };
 
 static const struct samsung_mux_clock exynos5800_mux_clks[] __initconst = {
@@ -469,11 +476,14 @@ static const struct samsung_mux_clock exynos5800_mux_clks[] __initconst = {
        MUX(0, "mout_aclk300_disp1", mout_group5_5800_p, SRC_TOP2, 24, 2),
        MUX(0, "mout_aclk300_gscl", mout_group5_5800_p, SRC_TOP2, 28, 2),
 
+       MUX(CLK_MOUT_MX_MSPLL_CCORE_PHY, "mout_mx_mspll_ccore_phy",
+               mout_mx_mspll_ccore_phy_p, SRC_TOP7, 0, 3),
+
        MUX(CLK_MOUT_MX_MSPLL_CCORE, "mout_mx_mspll_ccore",
-                       mout_mx_mspll_ccore_p, SRC_TOP7, 16, 2),
+                       mout_mx_mspll_ccore_p, SRC_TOP7, 16, 3),
        MUX_F(CLK_MOUT_MAU_EPLL, "mout_mau_epll_clk", mout_mau_epll_clk_5800_p,
                        SRC_TOP7, 20, 2, CLK_SET_RATE_PARENT, 0),
-       MUX(0, "sclk_bpll", mout_bpll_p, SRC_TOP7, 24, 1),
+       MUX(CLK_SCLK_BPLL, "sclk_bpll", mout_bpll_p, SRC_TOP7, 24, 1),
        MUX(0, "mout_epll2", mout_epll2_5800_p, SRC_TOP7, 28, 1),
 
        MUX(0, "mout_aclk550_cam", mout_group3_5800_p, SRC_TOP8, 16, 3),
@@ -645,7 +655,7 @@ static const struct samsung_mux_clock exynos5x_mux_clks[] __initconst = {
 
        MUX(0, "mout_sclk_mpll", mout_mpll_p, SRC_TOP6, 0, 1),
        MUX(CLK_MOUT_VPLL, "mout_sclk_vpll", mout_vpll_p, SRC_TOP6, 4, 1),
-       MUX(0, "mout_sclk_spll", mout_spll_p, SRC_TOP6, 8, 1),
+       MUX(CLK_MOUT_SCLK_SPLL, "mout_sclk_spll", mout_spll_p, SRC_TOP6, 8, 1),
        MUX(0, "mout_sclk_ipll", mout_ipll_p, SRC_TOP6, 12, 1),
        MUX(0, "mout_sclk_rpll", mout_rpll_p, SRC_TOP6, 16, 1),
        MUX_F(CLK_MOUT_EPLL, "mout_sclk_epll", mout_epll_p, SRC_TOP6, 20, 1,
@@ -803,8 +813,21 @@ static const struct samsung_div_clock exynos5x_div_clks[] __initconst = {
                        "mout_aclk400_disp1", DIV_TOP2, 4, 3),
 
        /* CDREX Block */
-       DIV(CLK_DOUT_PCLK_CDREX, "dout_pclk_cdrex", "dout_aclk_cdrex1",
-                       DIV_CDREX0, 28, 3),
+       /*
+        * The three clocks below are controlled using the same register and
+        * bits. They are put into one because there is a need of
+        * synchronization between the BUS and DREXs (two external memory
+        * interfaces).
+        * They are put here to show this HW assumption and for clock
+        * information summary completeness.
+        */
+       DIV_F(CLK_DOUT_PCLK_CDREX, "dout_pclk_cdrex", "dout_aclk_cdrex1",
+                       DIV_CDREX0, 28, 3, CLK_GET_RATE_NOCACHE, 0),
+       DIV_F(CLK_DOUT_PCLK_DREX0, "dout_pclk_drex0", "dout_cclk_drex0",
+                       DIV_CDREX0, 28, 3, CLK_GET_RATE_NOCACHE, 0),
+       DIV_F(CLK_DOUT_PCLK_DREX1, "dout_pclk_drex1", "dout_cclk_drex0",
+                       DIV_CDREX0, 28, 3, CLK_GET_RATE_NOCACHE, 0),
+
        DIV_F(CLK_DOUT_SCLK_CDREX, "dout_sclk_cdrex", "mout_mclk_cdrex",
                        DIV_CDREX0, 24, 3, CLK_SET_RATE_PARENT, 0),
        DIV(CLK_DOUT_ACLK_CDREX1, "dout_aclk_cdrex1", "dout_clk2x_phy0",
@@ -1167,6 +1190,32 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = {
                        GATE_TOP_SCLK_ISP, 12, CLK_SET_RATE_PARENT, 0),
 
        GATE(CLK_G3D, "g3d", "mout_user_aclk_g3d", GATE_IP_G3D, 9, 0, 0),
+
+       /* CDREX */
+       GATE(CLK_CLKM_PHY0, "clkm_phy0", "dout_sclk_cdrex",
+                       GATE_BUS_CDREX0, 0, 0, 0),
+       GATE(CLK_CLKM_PHY1, "clkm_phy1", "dout_sclk_cdrex",
+                       GATE_BUS_CDREX0, 1, 0, 0),
+       GATE(0, "mx_mspll_ccore_phy", "mout_mx_mspll_ccore_phy",
+                       SRC_MASK_TOP7, 0, CLK_IGNORE_UNUSED, 0),
+
+       GATE(CLK_ACLK_PPMU_DREX1_1, "aclk_ppmu_drex1_1", "dout_aclk_cdrex1",
+                       GATE_BUS_CDREX1, 12, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_ACLK_PPMU_DREX1_0, "aclk_ppmu_drex1_0", "dout_aclk_cdrex1",
+                       GATE_BUS_CDREX1, 13, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_ACLK_PPMU_DREX0_1, "aclk_ppmu_drex0_1", "dout_aclk_cdrex1",
+                       GATE_BUS_CDREX1, 14, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_ACLK_PPMU_DREX0_0, "aclk_ppmu_drex0_0", "dout_aclk_cdrex1",
+                       GATE_BUS_CDREX1, 15, CLK_IGNORE_UNUSED, 0),
+
+       GATE(CLK_PCLK_PPMU_DREX1_1, "pclk_ppmu_drex1_1", "dout_pclk_cdrex",
+                       GATE_BUS_CDREX1, 26, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_PCLK_PPMU_DREX1_0, "pclk_ppmu_drex1_0", "dout_pclk_cdrex",
+                       GATE_BUS_CDREX1, 27, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_PCLK_PPMU_DREX0_1, "pclk_ppmu_drex0_1", "dout_pclk_cdrex",
+                       GATE_BUS_CDREX1, 28, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_PCLK_PPMU_DREX0_0, "pclk_ppmu_drex0_0", "dout_pclk_cdrex",
+                       GATE_BUS_CDREX1, 29, CLK_IGNORE_UNUSED, 0),
 };
 
 static const struct samsung_div_clock exynos5x_disp_div_clks[] __initconst = {
@@ -1282,6 +1331,17 @@ static const struct samsung_pll_rate_table exynos5420_pll2550x_24mhz_tbl[] __ini
        PLL_35XX_RATE(24 * MHZ, 200000000,  200, 3, 3),
 };
 
+static const struct samsung_pll_rate_table exynos5422_bpll_rate_table[] = {
+       PLL_35XX_RATE(24 * MHZ, 825000000, 275, 4, 1),
+       PLL_35XX_RATE(24 * MHZ, 728000000, 182, 3, 1),
+       PLL_35XX_RATE(24 * MHZ, 633000000, 211, 4, 1),
+       PLL_35XX_RATE(24 * MHZ, 543000000, 181, 2, 2),
+       PLL_35XX_RATE(24 * MHZ, 413000000, 413, 6, 2),
+       PLL_35XX_RATE(24 * MHZ, 275000000, 275, 3, 3),
+       PLL_35XX_RATE(24 * MHZ, 206000000, 206, 3, 3),
+       PLL_35XX_RATE(24 * MHZ, 165000000, 110, 2, 3),
+};
+
 static const struct samsung_pll_rate_table exynos5420_epll_24mhz_tbl[] = {
        PLL_36XX_RATE(24 * MHZ, 600000000U, 100, 2, 1, 0),
        PLL_36XX_RATE(24 * MHZ, 400000000U, 200, 3, 2, 0),
@@ -1424,9 +1484,13 @@ static void __init exynos5x_clk_init(struct device_node *np,
                exynos5x_plls[apll].rate_table = exynos5420_pll2550x_24mhz_tbl;
                exynos5x_plls[epll].rate_table = exynos5420_epll_24mhz_tbl;
                exynos5x_plls[kpll].rate_table = exynos5420_pll2550x_24mhz_tbl;
-               exynos5x_plls[bpll].rate_table = exynos5420_pll2550x_24mhz_tbl;
        }
 
+       if (soc == EXYNOS5420)
+               exynos5x_plls[bpll].rate_table = exynos5420_pll2550x_24mhz_tbl;
+       else
+               exynos5x_plls[bpll].rate_table = exynos5422_bpll_rate_table;
+
        samsung_clk_register_pll(ctx, exynos5x_plls, ARRAY_SIZE(exynos5x_plls),
                                        reg_base);
        samsung_clk_register_fixed_rate(ctx, exynos5x_fixed_rate_clks,
index 945d5f2..7824c2b 100644 (file)
@@ -5587,8 +5587,8 @@ static int __init exynos5433_cmu_probe(struct platform_device *pdev)
        data->nr_clk_save = info->nr_clk_regs;
        data->clk_suspend = info->suspend_regs;
        data->nr_clk_suspend = info->nr_suspend_regs;
-       data->nr_pclks = of_count_phandle_with_args(dev->of_node, "clocks",
-                                                   "#clock-cells");
+       data->nr_pclks = of_clk_get_parent_count(dev->of_node);
+
        if (data->nr_pclks > 0) {
                data->pclks = devm_kcalloc(dev, sizeof(struct clk *),
                                           data->nr_pclks, GFP_KERNEL);
index 5bed36e..993f3a7 100644 (file)
@@ -161,8 +161,12 @@ static const struct stratix10_gate_clock s10_gate_clks[] = {
          8, 0, 0, 0, 0, 0, 0},
        { STRATIX10_SPI_M_CLK, "spi_m_clk", "l4_mp_clk", NULL, 1, 0, 0xA4,
          9, 0, 0, 0, 0, 0, 0},
-       { STRATIX10_NAND_CLK, "nand_clk", "l4_main_clk", NULL, 1, 0, 0xA4,
+       { STRATIX10_NAND_X_CLK, "nand_x_clk", "l4_mp_clk", NULL, 1, 0, 0xA4,
          10, 0, 0, 0, 0, 0, 0},
+       { STRATIX10_NAND_CLK, "nand_clk", "nand_x_clk", NULL, 1, 0, 0xA4,
+         10, 0, 0, 0, 0, 0, 4},
+       { STRATIX10_NAND_ECC_CLK, "nand_ecc_clk", "nand_x_clk", NULL, 1, 0, 0xA4,
+         10, 0, 0, 0, 0, 0, 4},
 };
 
 static int s10_clk_register_c_perip(const struct stratix10_perip_c_clock *clks,
index e038b04..a5bdca1 100644 (file)
@@ -42,6 +42,7 @@ int sprd_clk_regmap_init(struct platform_device *pdev,
        void __iomem *base;
        struct device_node *node = pdev->dev.of_node;
        struct regmap *regmap;
+       struct resource *res;
 
        if (of_find_property(node, "sprd,syscon", NULL)) {
                regmap = syscon_regmap_lookup_by_phandle(node, "sprd,syscon");
@@ -50,10 +51,14 @@ int sprd_clk_regmap_init(struct platform_device *pdev,
                        return PTR_ERR(regmap);
                }
        } else {
-               base = of_iomap(node, 0);
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+               base = devm_ioremap_resource(&pdev->dev, res);
+               if (IS_ERR(base))
+                       return PTR_ERR(base);
+
                regmap = devm_regmap_init_mmio(&pdev->dev, base,
                                               &sprdclk_regmap_config);
-               if (IS_ERR_OR_NULL(regmap)) {
+               if (IS_ERR(regmap)) {
                        pr_err("failed to init regmap\n");
                        return PTR_ERR(regmap);
                }
index 9980ab5..f76305b 100644 (file)
@@ -2023,6 +2023,7 @@ static int sc9860_clk_probe(struct platform_device *pdev)
 {
        const struct of_device_id *match;
        const struct sprd_clk_desc *desc;
+       int ret;
 
        match = of_match_node(sprd_sc9860_clk_ids, pdev->dev.of_node);
        if (!match) {
@@ -2031,7 +2032,9 @@ static int sc9860_clk_probe(struct platform_device *pdev)
        }
 
        desc = match->data;
-       sprd_clk_regmap_init(pdev, desc);
+       ret = sprd_clk_regmap_init(pdev, desc);
+       if (ret)
+               return ret;
 
        return sprd_clk_probe(&pdev->dev, desc->hw_clks);
 }
index df43952..f32366d 100644 (file)
@@ -160,8 +160,9 @@ static struct ccu_nk pll_periph_base_clk = {
        },
 };
 
-static CLK_FIXED_FACTOR(pll_periph_clk, "pll-periph", "pll-periph-base",
-                       2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph_clk, "pll-periph",
+                          &pll_periph_base_clk.common.hw,
+                          2, 1, CLK_SET_RATE_PARENT);
 
 /* Not documented on A10 */
 static struct ccu_div pll_periph_sata_clk = {
@@ -1028,19 +1029,29 @@ static struct ccu_common *sun4i_sun7i_ccu_clks[] = {
        &out_b_clk.common
 };
 
+static const struct clk_hw *clk_parent_pll_audio[] = {
+       &pll_audio_base_clk.common.hw
+};
+
 /* Post-divider for pll-audio is hardcoded to 1 */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
-                       "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
-                       "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_video0_2x_clk, "pll-video0-2x",
-                       "pll-video0", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_video1_2x_clk, "pll-video1-2x",
-                       "pll-video1", 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+                           clk_parent_pll_audio,
+                           2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+                           clk_parent_pll_audio,
+                           1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_video0_2x_clk, "pll-video0-2x",
+                          &pll_video0_clk.common.hw,
+                          1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_video1_2x_clk, "pll-video1-2x",
+                          &pll_video1_clk.common.hw,
+                          1, 2, CLK_SET_RATE_PARENT);
 
 
 static struct clk_hw_onecell_data sun4i_a10_hw_clks = {
index 1786ee8..49bd7a4 100644 (file)
@@ -597,23 +597,34 @@ static SUNXI_CCU_M_WITH_GATE(gpu_clk, "gpu", "pll-gpu",
                             0x1a0, 0, 3, BIT(31), CLK_SET_RATE_PARENT);
 
 /* Fixed Factor clocks */
-static CLK_FIXED_FACTOR(osc12M_clk, "osc12M", "osc24M", 2, 1, 0);
+static CLK_FIXED_FACTOR_FW_NAME(osc12M_clk, "osc12M", "hosc", 2, 1, 0);
+
+static const struct clk_hw *clk_parent_pll_audio[] = {
+       &pll_audio_base_clk.common.hw
+};
 
 /* We hardcode the divider to 1 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
-                       "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
-                       "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x",
-                       "pll-periph0", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_periph1_2x_clk, "pll-periph1-2x",
-                       "pll-periph1", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_video0_2x_clk, "pll-video0-2x",
-                       "pll-video0", 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+                           clk_parent_pll_audio,
+                           2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+                           clk_parent_pll_audio,
+                           1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph0_2x_clk, "pll-periph0-2x",
+                          &pll_periph0_clk.common.hw,
+                          1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_periph1_2x_clk, "pll-periph1-2x",
+                          &pll_periph1_clk.common.hw,
+                          1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_video0_2x_clk, "pll-video0-2x",
+                          &pll_video0_clk.common.hw,
+                          1, 2, CLK_SET_RATE_PARENT);
 
 static struct ccu_common *sun50i_a64_ccu_clks[] = {
        &pll_cpux_clk.common,
index 27554ea..45a1ed3 100644 (file)
@@ -49,7 +49,7 @@ static struct ccu_div ar100_clk = {
        },
 };
 
-static CLK_FIXED_FACTOR(r_ahb_clk, "r-ahb", "ar100", 1, 1, 0);
+static CLK_FIXED_FACTOR_HW(r_ahb_clk, "r-ahb", &ar100_clk.common.hw, 1, 1, 0);
 
 static struct ccu_div r_apb1_clk = {
        .div            = _SUNXI_CCU_DIV(0, 2),
@@ -104,7 +104,7 @@ static SUNXI_CCU_GATE(r_apb2_i2c_clk,       "r-apb2-i2c",   "r-apb2",
 static SUNXI_CCU_GATE(r_apb1_ir_clk,   "r-apb1-ir",    "r-apb1",
                      0x1cc, BIT(0), 0);
 static SUNXI_CCU_GATE(r_apb1_w1_clk,   "r-apb1-w1",    "r-apb1",
-                     0x1cc, BIT(0), 0);
+                     0x1ec, BIT(0), 0);
 
 /* Information of IR(RX) mod clock is gathered from BSP source code */
 static const char * const r_mod0_default_parents[] = { "osc32k", "osc24M" };
index 9d3f989..aebef4a 100644 (file)
@@ -622,8 +622,9 @@ static SUNXI_CCU_GATE(bus_xhci_clk, "bus-xhci", "ahb3", 0xa8c, BIT(5), 0);
 static SUNXI_CCU_GATE(bus_ehci3_clk, "bus-ehci3", "ahb3", 0xa8c, BIT(7), 0);
 static SUNXI_CCU_GATE(bus_otg_clk, "bus-otg", "ahb3", 0xa8c, BIT(8), 0);
 
-static CLK_FIXED_FACTOR(pcie_ref_100m_clk, "pcie-ref-100M",
-                       "pll-periph0-4x", 24, 1, 0);
+static struct clk_fixed_factor pll_periph0_4x_clk;
+static CLK_FIXED_FACTOR_HW(pcie_ref_100m_clk, "pcie-ref-100M",
+                          &pll_periph0_4x_clk.hw, 24, 1, 0);
 static SUNXI_CCU_GATE(pcie_ref_clk, "pcie-ref", "pcie-ref-100M",
                      0xab0, BIT(31), 0);
 static SUNXI_CCU_GATE(pcie_ref_out_clk, "pcie-ref-out", "pcie-ref",
@@ -745,34 +746,52 @@ static SUNXI_CCU_M_WITH_MUX_GATE(hdcp_clk, "hdcp", hdcp_parents, 0xc40,
 static SUNXI_CCU_GATE(bus_hdcp_clk, "bus-hdcp", "ahb3", 0xc4c, BIT(0), 0);
 
 /* Fixed factor clocks */
-static CLK_FIXED_FACTOR(osc12M_clk, "osc12M", "osc24M", 2, 1, 0);
+static CLK_FIXED_FACTOR_FW_NAME(osc12M_clk, "osc12M", "hosc", 2, 1, 0);
+
+static const struct clk_hw *clk_parent_pll_audio[] = {
+       &pll_audio_base_clk.common.hw
+};
 
 /*
  * The divider of pll-audio is fixed to 8 now, as pll-audio-4x has a
  * fixed post-divider 2.
  */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
-                       "pll-audio-base", 8, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
-                       "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
-                       "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-
-static CLK_FIXED_FACTOR(pll_periph0_4x_clk, "pll-periph0-4x",
-                       "pll-periph0", 1, 4, 0);
-static CLK_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x",
-                       "pll-periph0", 1, 2, 0);
-
-static CLK_FIXED_FACTOR(pll_periph1_4x_clk, "pll-periph1-4x",
-                       "pll-periph1", 1, 4, 0);
-static CLK_FIXED_FACTOR(pll_periph1_2x_clk, "pll-periph1-2x",
-                       "pll-periph1", 1, 2, 0);
-
-static CLK_FIXED_FACTOR(pll_video0_4x_clk, "pll-video0-4x",
-                       "pll-video0", 1, 4, CLK_SET_RATE_PARENT);
-
-static CLK_FIXED_FACTOR(pll_video1_4x_clk, "pll-video1-4x",
-                       "pll-video1", 1, 4, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+                           clk_parent_pll_audio,
+                           8, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+                           clk_parent_pll_audio,
+                           4, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+                           clk_parent_pll_audio,
+                           2, 1, CLK_SET_RATE_PARENT);
+
+static const struct clk_hw *pll_periph0_parents[] = {
+       &pll_periph0_clk.common.hw
+};
+static CLK_FIXED_FACTOR_HWS(pll_periph0_4x_clk, "pll-periph0-4x",
+                           pll_periph0_parents,
+                           1, 4, 0);
+static CLK_FIXED_FACTOR_HWS(pll_periph0_2x_clk, "pll-periph0-2x",
+                           pll_periph0_parents,
+                           1, 2, 0);
+
+static const struct clk_hw *pll_periph1_parents[] = {
+       &pll_periph1_clk.common.hw
+};
+static CLK_FIXED_FACTOR_HWS(pll_periph1_4x_clk, "pll-periph1-4x",
+                           pll_periph1_parents,
+                           1, 4, 0);
+static CLK_FIXED_FACTOR_HWS(pll_periph1_2x_clk, "pll-periph1-2x",
+                           pll_periph1_parents,
+                           1, 2, 0);
+
+static CLK_FIXED_FACTOR_HW(pll_video0_4x_clk, "pll-video0-4x",
+                          &pll_video0_clk.common.hw,
+                          1, 4, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_video1_4x_clk, "pll-video1-4x",
+                          &pll_video1_clk.common.hw,
+                          1, 4, CLK_SET_RATE_PARENT);
 
 static struct ccu_common *sun50i_h6_ccu_clks[] = {
        &pll_cpux_clk.common,
index b71ed0f..b78e9b5 100644 (file)
@@ -603,19 +603,29 @@ static struct ccu_common *sun5i_a10s_ccu_clks[] = {
        &iep_clk.common,
 };
 
+static const struct clk_hw *clk_parent_pll_audio[] = {
+       &pll_audio_base_clk.common.hw
+};
+
 /* We hardcode the divider to 1 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
-                       "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
-                       "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_video0_2x_clk, "pll-video0-2x",
-                       "pll-video0", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_video1_2x_clk, "pll-video1-2x",
-                       "pll-video1", 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+                           clk_parent_pll_audio,
+                           2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+                           clk_parent_pll_audio,
+                           1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_video0_2x_clk, "pll-video0-2x",
+                          &pll_video0_clk.common.hw,
+                          1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_video1_2x_clk, "pll-video1-2x",
+                          &pll_video1_clk.common.hw,
+                          1, 2, CLK_SET_RATE_PARENT);
 
 static struct clk_hw_onecell_data sun5i_a10s_hw_clks = {
        .hws    = {
index 2ff7b08..9b40d53 100644 (file)
@@ -955,21 +955,32 @@ static struct ccu_common *sun6i_a31_ccu_clks[] = {
        &out_c_clk.common,
 };
 
+static const struct clk_hw *clk_parent_pll_audio[] = {
+       &pll_audio_base_clk.common.hw
+};
+
 /* We hardcode the divider to 1 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
-                       "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
-                       "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_periph_2x_clk, "pll-periph-2x",
-                       "pll-periph", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_video0_2x_clk, "pll-video0-2x",
-                       "pll-video0", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_video1_2x_clk, "pll-video1-2x",
-                       "pll-video1", 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+                           clk_parent_pll_audio,
+                           2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+                           clk_parent_pll_audio,
+                           1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph_2x_clk, "pll-periph-2x",
+                          &pll_periph_clk.common.hw,
+                          1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_video0_2x_clk, "pll-video0-2x",
+                          &pll_video0_clk.common.hw,
+                          1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_video1_2x_clk, "pll-video1-2x",
+                          &pll_video1_clk.common.hw,
+                          1, 2, CLK_SET_RATE_PARENT);
 
 static struct clk_hw_onecell_data sun6i_a31_hw_clks = {
        .hws    = {
index 14ced50..103aa50 100644 (file)
@@ -543,19 +543,29 @@ static struct ccu_common *sun8i_a23_ccu_clks[] = {
        &ats_clk.common,
 };
 
+static const struct clk_hw *clk_parent_pll_audio[] = {
+       &pll_audio_base_clk.common.hw
+};
+
 /* We hardcode the divider to 1 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
-                       "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
-                       "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_periph_2x_clk, "pll-periph-2x",
-                       "pll-periph", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_video_2x_clk, "pll-video-2x",
-                       "pll-video", 1, 2, 0);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+                           clk_parent_pll_audio,
+                           2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+                           clk_parent_pll_audio,
+                           1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph_2x_clk, "pll-periph-2x",
+                          &pll_periph_clk.common.hw,
+                          1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_video_2x_clk, "pll-video-2x",
+                          &pll_video_clk.common.hw,
+                          1, 2, 0);
 
 static struct clk_hw_onecell_data sun8i_a23_hw_clks = {
        .hws    = {
index 61fb41f..91838cd 100644 (file)
@@ -580,19 +580,29 @@ static struct ccu_common *sun8i_a33_ccu_clks[] = {
        &ats_clk.common,
 };
 
+static const struct clk_hw *clk_parent_pll_audio[] = {
+       &pll_audio_base_clk.common.hw
+};
+
 /* We hardcode the divider to 1 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
-                       "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
-                       "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_periph_2x_clk, "pll-periph-2x",
-                       "pll-periph", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_video_2x_clk, "pll-video-2x",
-                       "pll-video", 1, 2, 0);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+                           clk_parent_pll_audio,
+                           2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+                           clk_parent_pll_audio,
+                           1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph_2x_clk, "pll-periph-2x",
+                          &pll_periph_clk.common.hw,
+                          1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_video_2x_clk, "pll-video-2x",
+                          &pll_video_clk.common.hw,
+                          1, 2, 0);
 
 static struct clk_hw_onecell_data sun8i_a33_hw_clks = {
        .hws    = {
index 9601504..6b63636 100644 (file)
@@ -717,17 +717,26 @@ static struct ccu_common *sun50i_h5_ccu_clks[] = {
        &gpu_clk.common,
 };
 
+static const struct clk_hw *clk_parent_pll_audio[] = {
+       &pll_audio_base_clk.common.hw
+};
+
 /* We hardcode the divider to 1 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
-                       "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
-                       "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x",
-                       "pll-periph0", 1, 2, 0);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+                           clk_parent_pll_audio,
+                           2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+                           clk_parent_pll_audio,
+                           1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph0_2x_clk, "pll-periph0-2x",
+                          &pll_periph0_clk.common.hw,
+                          1, 2, 0);
 
 static struct clk_hw_onecell_data sun8i_h3_hw_clks = {
        .hws    = {
index b5be11e..4646fdc 100644 (file)
 
 #include "ccu-sun8i-r.h"
 
-static const char * const ar100_parents[] = { "osc32k", "osc24M",
-                                            "pll-periph0", "iosc" };
-static const char * const a83t_ar100_parents[] = { "osc16M-d512", "osc24M",
-                                                  "pll-periph0", "iosc" };
+static const struct clk_parent_data ar100_parents[] = {
+       { .fw_name = "losc" },
+       { .fw_name = "hosc" },
+       { .fw_name = "pll-periph" },
+       { .fw_name = "iosc" },
+};
+
 static const struct ccu_mux_var_prediv ar100_predivs[] = {
        { .index = 2, .shift = 8, .width = 5 },
 };
@@ -39,64 +42,49 @@ static struct ccu_div ar100_clk = {
        .common         = {
                .reg            = 0x00,
                .features       = CCU_FEATURE_VARIABLE_PREDIV,
-               .hw.init        = CLK_HW_INIT_PARENTS("ar100",
-                                                     ar100_parents,
-                                                     &ccu_div_ops,
-                                                     0),
-       },
-};
-
-static struct ccu_div a83t_ar100_clk = {
-       .div            = _SUNXI_CCU_DIV_FLAGS(4, 2, CLK_DIVIDER_POWER_OF_TWO),
-
-       .mux            = {
-               .shift  = 16,
-               .width  = 2,
-
-               .var_predivs    = ar100_predivs,
-               .n_var_predivs  = ARRAY_SIZE(ar100_predivs),
-       },
-
-       .common         = {
-               .reg            = 0x00,
-               .features       = CCU_FEATURE_VARIABLE_PREDIV,
-               .hw.init        = CLK_HW_INIT_PARENTS("ar100",
-                                                     a83t_ar100_parents,
-                                                     &ccu_div_ops,
-                                                     0),
+               .hw.init        = CLK_HW_INIT_PARENTS_DATA("ar100",
+                                                          ar100_parents,
+                                                          &ccu_div_ops,
+                                                          0),
        },
 };
 
-static CLK_FIXED_FACTOR(ahb0_clk, "ahb0", "ar100", 1, 1, 0);
+static CLK_FIXED_FACTOR_HW(ahb0_clk, "ahb0", &ar100_clk.common.hw, 1, 1, 0);
 
 static struct ccu_div apb0_clk = {
        .div            = _SUNXI_CCU_DIV_FLAGS(0, 2, CLK_DIVIDER_POWER_OF_TWO),
 
        .common         = {
                .reg            = 0x0c,
-               .hw.init        = CLK_HW_INIT("apb0",
-                                             "ahb0",
-                                             &ccu_div_ops,
-                                             0),
+               .hw.init        = CLK_HW_INIT_HW("apb0",
+                                                &ahb0_clk.hw,
+                                                &ccu_div_ops,
+                                                0),
        },
 };
 
 static SUNXI_CCU_M(a83t_apb0_clk, "apb0", "ahb0", 0x0c, 0, 2, 0);
 
-static SUNXI_CCU_GATE(apb0_pio_clk,    "apb0-pio",     "apb0",
-                     0x28, BIT(0), 0);
-static SUNXI_CCU_GATE(apb0_ir_clk,     "apb0-ir",      "apb0",
-                     0x28, BIT(1), 0);
-static SUNXI_CCU_GATE(apb0_timer_clk,  "apb0-timer",   "apb0",
-                     0x28, BIT(2), 0);
-static SUNXI_CCU_GATE(apb0_rsb_clk,    "apb0-rsb",     "apb0",
-                     0x28, BIT(3), 0);
-static SUNXI_CCU_GATE(apb0_uart_clk,   "apb0-uart",    "apb0",
-                     0x28, BIT(4), 0);
-static SUNXI_CCU_GATE(apb0_i2c_clk,    "apb0-i2c",     "apb0",
-                     0x28, BIT(6), 0);
-static SUNXI_CCU_GATE(apb0_twd_clk,    "apb0-twd",     "apb0",
-                     0x28, BIT(7), 0);
+/*
+ * Define the parent as an array that can be reused to save space
+ * instead of having compound literals for each gate. Also have it
+ * non-const so we can change it on the A83T.
+ */
+static const struct clk_hw *apb0_gate_parent[] = { &apb0_clk.common.hw };
+static SUNXI_CCU_GATE_HWS(apb0_pio_clk,                "apb0-pio",
+                         apb0_gate_parent, 0x28, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(apb0_ir_clk,         "apb0-ir",
+                         apb0_gate_parent, 0x28, BIT(1), 0);
+static SUNXI_CCU_GATE_HWS(apb0_timer_clk,      "apb0-timer",
+                         apb0_gate_parent, 0x28, BIT(2), 0);
+static SUNXI_CCU_GATE_HWS(apb0_rsb_clk,                "apb0-rsb",
+                         apb0_gate_parent, 0x28, BIT(3), 0);
+static SUNXI_CCU_GATE_HWS(apb0_uart_clk,       "apb0-uart",
+                         apb0_gate_parent, 0x28, BIT(4), 0);
+static SUNXI_CCU_GATE_HWS(apb0_i2c_clk,                "apb0-i2c",
+                         apb0_gate_parent, 0x28, BIT(6), 0);
+static SUNXI_CCU_GATE_HWS(apb0_twd_clk,                "apb0-twd",
+                         apb0_gate_parent, 0x28, BIT(7), 0);
 
 static const char * const r_mod0_default_parents[] = { "osc32k", "osc24M" };
 static SUNXI_CCU_MP_WITH_MUX_GATE(ir_clk, "ir",
@@ -107,7 +95,10 @@ static SUNXI_CCU_MP_WITH_MUX_GATE(ir_clk, "ir",
                                  BIT(31),      /* gate */
                                  0);
 
-static const char *const a83t_r_mod0_parents[] = { "osc16M", "osc24M" };
+static const struct clk_parent_data a83t_r_mod0_parents[] = {
+       { .fw_name = "iosc" },
+       { .fw_name = "hosc" },
+};
 static const struct ccu_mux_fixed_prediv a83t_ir_predivs[] = {
        { .index = 0, .div = 16 },
 };
@@ -127,15 +118,15 @@ static struct ccu_mp a83t_ir_clk = {
        .common         = {
                .reg            = 0x54,
                .features       = CCU_FEATURE_VARIABLE_PREDIV,
-               .hw.init        = CLK_HW_INIT_PARENTS("ir",
-                                                     a83t_r_mod0_parents,
-                                                     &ccu_mp_ops,
-                                                     0),
+               .hw.init        = CLK_HW_INIT_PARENTS_DATA("ir",
+                                                          a83t_r_mod0_parents,
+                                                          &ccu_mp_ops,
+                                                          0),
        },
 };
 
 static struct ccu_common *sun8i_a83t_r_ccu_clks[] = {
-       &a83t_ar100_clk.common,
+       &ar100_clk.common,
        &a83t_apb0_clk.common,
        &apb0_pio_clk.common,
        &apb0_ir_clk.common,
@@ -174,7 +165,7 @@ static struct ccu_common *sun50i_a64_r_ccu_clks[] = {
 
 static struct clk_hw_onecell_data sun8i_a83t_r_hw_clks = {
        .hws    = {
-               [CLK_AR100]             = &a83t_ar100_clk.common.hw,
+               [CLK_AR100]             = &ar100_clk.common.hw,
                [CLK_AHB0]              = &ahb0_clk.hw,
                [CLK_APB0]              = &a83t_apb0_clk.common.hw,
                [CLK_APB0_PIO]          = &apb0_pio_clk.common.hw,
@@ -291,6 +282,9 @@ static void __init sunxi_r_ccu_init(struct device_node *node,
 
 static void __init sun8i_a83t_r_ccu_setup(struct device_node *node)
 {
+       /* Fix apb0 bus gate parents here */
+       apb0_gate_parent[0] = &a83t_apb0_clk.common.hw;
+
        sunxi_r_ccu_init(node, &sun8i_a83t_r_ccu_desc);
 }
 CLK_OF_DECLARE(sun8i_a83t_r_ccu, "allwinner,sun8i-a83t-r-ccu",
index 540f5f7..8974908 100644 (file)
@@ -944,25 +944,37 @@ static struct ccu_common *sun8i_r40_ccu_clks[] = {
 };
 
 /* Fixed Factor clocks */
-static CLK_FIXED_FACTOR(osc12M_clk, "osc12M", "osc24M", 2, 1, 0);
+static CLK_FIXED_FACTOR_FW_NAME(osc12M_clk, "osc12M", "hosc", 2, 1, 0);
+
+static const struct clk_hw *clk_parent_pll_audio[] = {
+       &pll_audio_base_clk.common.hw
+};
 
 /* We hardcode the divider to 4 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
-                       "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
-                       "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
-                       "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x",
-                       "pll-periph0", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_periph1_2x_clk, "pll-periph1-2x",
-                       "pll-periph1", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_video0_2x_clk, "pll-video0-2x",
-                       "pll-video0", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_video1_2x_clk, "pll-video1-2x",
-                       "pll-video1", 1, 2, 0);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+                           clk_parent_pll_audio,
+                           4, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+                           clk_parent_pll_audio,
+                           2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+                           clk_parent_pll_audio,
+                           1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph0_2x_clk, "pll-periph0-2x",
+                          &pll_periph0_clk.common.hw,
+                          1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_periph1_2x_clk, "pll-periph1-2x",
+                          &pll_periph1_clk.common.hw,
+                          1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_video0_2x_clk, "pll-video0-2x",
+                          &pll_video0_clk.common.hw,
+                          1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_video1_2x_clk, "pll-video1-2x",
+                          &pll_video1_clk.common.hw,
+                          1, 2, 0);
 
 static struct clk_hw_onecell_data sun8i_r40_hw_clks = {
        .hws    = {
index cbbf06d..9b3939f 100644 (file)
@@ -429,17 +429,26 @@ static struct ccu_common *sun8i_v3s_ccu_clks[] = {
        &mipi_csi_clk.common,
 };
 
+static const struct clk_hw *clk_parent_pll_audio[] = {
+       &pll_audio_base_clk.common.hw
+};
+
 /* We hardcode the divider to 4 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
-                       "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
-                       "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
-                       "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x",
-                       "pll-periph0", 1, 2, 0);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+                           clk_parent_pll_audio,
+                           4, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+                           clk_parent_pll_audio,
+                           2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+                           clk_parent_pll_audio,
+                           1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph0_2x_clk, "pll-periph0-2x",
+                          &pll_periph0_clk.common.hw,
+                          1, 2, 0);
 
 static struct clk_hw_onecell_data sun8i_v3s_hw_clks = {
        .hws    = {
index 2f82cd8..4b4a507 100644 (file)
 
 #include "ccu-sun9i-a80-usb.h"
 
-static SUNXI_CCU_GATE(bus_hci0_clk, "bus-hci0", "bus-usb", 0x0, BIT(1), 0);
-static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc24M", 0x0, BIT(2), 0);
-static SUNXI_CCU_GATE(bus_hci1_clk, "bus-hci1", "bus-usb", 0x0, BIT(3), 0);
-static SUNXI_CCU_GATE(bus_hci2_clk, "bus-hci2", "bus-usb", 0x0, BIT(5), 0);
-static SUNXI_CCU_GATE(usb_ohci2_clk, "usb-ohci2", "osc24M", 0x0, BIT(6), 0);
-
-static SUNXI_CCU_GATE(usb0_phy_clk, "usb0-phy", "osc24M", 0x4, BIT(1), 0);
-static SUNXI_CCU_GATE(usb1_hsic_clk, "usb1-hsic", "osc24M", 0x4, BIT(2), 0);
-static SUNXI_CCU_GATE(usb1_phy_clk, "usb1-phy", "osc24M", 0x4, BIT(3), 0);
-static SUNXI_CCU_GATE(usb2_hsic_clk, "usb2-hsic", "osc24M", 0x4, BIT(4), 0);
-static SUNXI_CCU_GATE(usb2_phy_clk, "usb2-phy", "osc24M", 0x4, BIT(5), 0);
-static SUNXI_CCU_GATE(usb_hsic_clk, "usb-hsic", "osc24M", 0x4, BIT(10), 0);
+static const struct clk_parent_data clk_parent_hosc[] = {
+       { .fw_name = "hosc" },
+};
+
+static const struct clk_parent_data clk_parent_bus[] = {
+       { .fw_name = "bus" },
+};
+
+static SUNXI_CCU_GATE_DATA(bus_hci0_clk, "bus-hci0", clk_parent_bus, 0x0, BIT(1), 0);
+static SUNXI_CCU_GATE_DATA(usb_ohci0_clk, "usb-ohci0", clk_parent_hosc, 0x0, BIT(2), 0);
+static SUNXI_CCU_GATE_DATA(bus_hci1_clk, "bus-hci1", clk_parent_bus, 0x0, BIT(3), 0);
+static SUNXI_CCU_GATE_DATA(bus_hci2_clk, "bus-hci2", clk_parent_bus, 0x0, BIT(5), 0);
+static SUNXI_CCU_GATE_DATA(usb_ohci2_clk, "usb-ohci2", clk_parent_hosc, 0x0, BIT(6), 0);
+
+static SUNXI_CCU_GATE_DATA(usb0_phy_clk, "usb0-phy", clk_parent_hosc, 0x4, BIT(1), 0);
+static SUNXI_CCU_GATE_DATA(usb1_hsic_clk, "usb1-hsic", clk_parent_hosc, 0x4, BIT(2), 0);
+static SUNXI_CCU_GATE_DATA(usb1_phy_clk, "usb1-phy", clk_parent_hosc, 0x4, BIT(3), 0);
+static SUNXI_CCU_GATE_DATA(usb2_hsic_clk, "usb2-hsic", clk_parent_hosc, 0x4, BIT(4), 0);
+static SUNXI_CCU_GATE_DATA(usb2_phy_clk, "usb2-phy", clk_parent_hosc, 0x4, BIT(5), 0);
+static SUNXI_CCU_GATE_DATA(usb_hsic_clk, "usb-hsic", clk_parent_hosc, 0x4, BIT(10), 0);
 
 static struct ccu_common *sun9i_a80_usb_clks[] = {
        &bus_hci0_clk.common,
index e748b8a..7ecc3a5 100644 (file)
@@ -374,16 +374,25 @@ static struct ccu_common *suniv_ccu_clks[] = {
        &avs_clk.common,
 };
 
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
-                       "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
-                       "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
-                       "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_video_2x_clk, "pll-video-2x",
-                       "pll-video", 1, 2, 0);
+static const struct clk_hw *clk_parent_pll_audio[] = {
+       &pll_audio_base_clk.common.hw
+};
+
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+                           clk_parent_pll_audio,
+                           4, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+                           clk_parent_pll_audio,
+                           2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+                           clk_parent_pll_audio,
+                           1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_video_2x_clk, "pll-video-2x",
+                           &pll_video_clk.common.hw,
+                           1, 2, 0);
 
 static struct clk_hw_onecell_data suniv_hw_clks = {
        .hws    = {
index c173778..7fe3ac9 100644 (file)
@@ -101,7 +101,7 @@ int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
                if (!hw)
                        continue;
 
-               ret = clk_hw_register(NULL, hw);
+               ret = of_clk_hw_register(node, hw);
                if (ret) {
                        pr_err("Couldn't register clock %d - %s\n",
                               i, clk_hw_get_name(hw));
index da8100e..c386689 100644 (file)
@@ -28,6 +28,59 @@ struct ccu_gate {
                }                                                       \
        }
 
+#define SUNXI_CCU_GATE_HW(_struct, _name, _parent, _reg, _gate, _flags)        \
+       struct ccu_gate _struct = {                                     \
+               .enable = _gate,                                        \
+               .common = {                                             \
+                       .reg            = _reg,                         \
+                       .hw.init        = CLK_HW_INIT_HW(_name,         \
+                                                        _parent,       \
+                                                        &ccu_gate_ops, \
+                                                        _flags),       \
+               }                                                       \
+       }
+
+#define SUNXI_CCU_GATE_FW(_struct, _name, _parent, _reg, _gate, _flags)        \
+       struct ccu_gate _struct = {                                     \
+               .enable = _gate,                                        \
+               .common = {                                             \
+                       .reg            = _reg,                         \
+                       .hw.init        = CLK_HW_INIT_FW_NAME(_name,    \
+                                                             _parent,  \
+                                                             &ccu_gate_ops, \
+                                                             _flags),  \
+               }                                                       \
+       }
+
+/*
+ * The following two macros allow the re-use of the data structure
+ * holding the parent info.
+ */
+#define SUNXI_CCU_GATE_HWS(_struct, _name, _parent, _reg, _gate, _flags) \
+       struct ccu_gate _struct = {                                     \
+               .enable = _gate,                                        \
+               .common = {                                             \
+                       .reg            = _reg,                         \
+                       .hw.init        = CLK_HW_INIT_HWS(_name,        \
+                                                         _parent,      \
+                                                         &ccu_gate_ops, \
+                                                         _flags),      \
+               }                                                       \
+       }
+
+#define SUNXI_CCU_GATE_DATA(_struct, _name, _data, _reg, _gate, _flags)        \
+       struct ccu_gate _struct = {                                     \
+               .enable = _gate,                                        \
+               .common = {                                             \
+                       .reg            = _reg,                         \
+                       .hw.init        =                               \
+                               CLK_HW_INIT_PARENTS_DATA(_name,         \
+                                                        _data,         \
+                                                        &ccu_gate_ops, \
+                                                        _flags),       \
+               }                                                       \
+       }
+
 static inline struct ccu_gate *hw_to_ccu_gate(struct clk_hw *hw)
 {
        struct ccu_common *common = hw_to_ccu_common(hw);
index 623fda5..d3a4338 100644 (file)
@@ -980,6 +980,8 @@ static struct clk ** __init sunxi_divs_clk_setup(struct device_node *node,
                if (endp) {
                        derived_name = kstrndup(clk_name, endp - clk_name,
                                                GFP_KERNEL);
+                       if (!derived_name)
+                               return NULL;
                        factors.name = derived_name;
                } else {
                        factors.name = clk_name;
index ac1d27a..df172d5 100644 (file)
@@ -984,8 +984,6 @@ static void tegra210_pllre_set_defaults(struct tegra_clk_pll *pllre)
        pllre->params->defaults_set = true;
 
        if (val & PLL_ENABLE) {
-               pr_warn("PLL_RE already enabled. Postponing set full defaults\n");
-
                /*
                 * PLL is ON: check if defaults already set, then set those
                 * that can be updated in flight.
@@ -1005,13 +1003,20 @@ static void tegra210_pllre_set_defaults(struct tegra_clk_pll *pllre)
                _pll_misc_chk_default(clk_base, pllre->params, 0, val,
                                ~mask & PLLRE_MISC0_WRITE_MASK);
 
-               /* Enable lock detect */
+               /* The PLL doesn't work if it's in IDDQ. */
                val = readl_relaxed(clk_base + pllre->params->ext_misc_reg[0]);
+               if (val & PLLRE_MISC0_IDDQ)
+                       pr_warn("unexpected IDDQ bit set for enabled clock\n");
+
+               /* Enable lock detect */
                val &= ~mask;
                val |= PLLRE_MISC0_DEFAULT_VALUE & mask;
                writel_relaxed(val, clk_base + pllre->params->ext_misc_reg[0]);
                udelay(1);
 
+               if (!pllre->params->defaults_set)
+                       pr_warn("PLL_RE already enabled. Postponing set full defaults\n");
+
                return;
        }
 
@@ -2204,9 +2209,9 @@ static struct div_nmp pllu_nmp = {
 };
 
 static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
-       { 12000000, 480000000, 40, 1, 0, 0 },
-       { 13000000, 480000000, 36, 1, 0, 0 }, /* actual: 468.0 MHz */
-       { 38400000, 480000000, 25, 2, 0, 0 },
+       { 12000000, 480000000, 40, 1, 1, 0 },
+       { 13000000, 480000000, 36, 1, 1, 0 }, /* actual: 468.0 MHz */
+       { 38400000, 480000000, 25, 2, 1, 0 },
        {        0,         0,  0, 0, 0, 0 },
 };
 
@@ -3332,7 +3337,7 @@ static struct tegra_clk_init_table init_table[] __initdata = {
        { TEGRA210_CLK_DFLL_SOC, TEGRA210_CLK_PLL_P, 51000000, 1 },
        { TEGRA210_CLK_DFLL_REF, TEGRA210_CLK_PLL_P, 51000000, 1 },
        { TEGRA210_CLK_SBC4, TEGRA210_CLK_PLL_P, 12000000, 1 },
-       { TEGRA210_CLK_PLL_RE_VCO, TEGRA210_CLK_CLK_MAX, 672000000, 1 },
+       { TEGRA210_CLK_PLL_U_OUT1, TEGRA210_CLK_CLK_MAX, 48000000, 1 },
        { TEGRA210_CLK_XUSB_GATE, TEGRA210_CLK_CLK_MAX, 0, 1 },
        { TEGRA210_CLK_XUSB_SS_SRC, TEGRA210_CLK_PLL_U_480M, 120000000, 0 },
        { TEGRA210_CLK_XUSB_FS_SRC, TEGRA210_CLK_PLL_U_48M, 48000000, 0 },
@@ -3357,7 +3362,6 @@ static struct tegra_clk_init_table init_table[] __initdata = {
        { TEGRA210_CLK_PLL_DP, TEGRA210_CLK_CLK_MAX, 270000000, 0 },
        { TEGRA210_CLK_SOC_THERM, TEGRA210_CLK_PLL_P, 51000000, 0 },
        { TEGRA210_CLK_CCLK_G, TEGRA210_CLK_CLK_MAX, 0, 1 },
-       { TEGRA210_CLK_PLL_U_OUT1, TEGRA210_CLK_CLK_MAX, 48000000, 1 },
        { TEGRA210_CLK_PLL_U_OUT2, TEGRA210_CLK_CLK_MAX, 60000000, 1 },
        { TEGRA210_CLK_SPDIF_IN_SYNC, TEGRA210_CLK_CLK_MAX, 24576000, 0 },
        { TEGRA210_CLK_I2S0_SYNC, TEGRA210_CLK_CLK_MAX, 24576000, 0 },
index 4786e0e..6cb863c 100644 (file)
@@ -425,91 +425,6 @@ int ti_clk_parse_divider_data(int *div_table, int num_dividers, int max_div,
        return 0;
 }
 
-static const struct clk_div_table *
-_get_div_table_from_setup(struct ti_clk_divider *setup, u8 *width)
-{
-       const struct clk_div_table *table = NULL;
-
-       ti_clk_parse_divider_data(setup->dividers, setup->num_dividers,
-                                 setup->max_div, setup->flags, width,
-                                 &table);
-
-       return table;
-}
-
-struct clk_hw *ti_clk_build_component_div(struct ti_clk_divider *setup)
-{
-       struct clk_omap_divider *div;
-       struct clk_omap_reg *reg;
-       int ret;
-
-       if (!setup)
-               return NULL;
-
-       div = kzalloc(sizeof(*div), GFP_KERNEL);
-       if (!div)
-               return ERR_PTR(-ENOMEM);
-
-       reg = (struct clk_omap_reg *)&div->reg;
-       reg->index = setup->module;
-       reg->offset = setup->reg;
-
-       if (setup->flags & CLKF_INDEX_STARTS_AT_ONE)
-               div->flags |= CLK_DIVIDER_ONE_BASED;
-
-       if (setup->flags & CLKF_INDEX_POWER_OF_TWO)
-               div->flags |= CLK_DIVIDER_POWER_OF_TWO;
-
-       div->table = _get_div_table_from_setup(setup, &div->width);
-       if (IS_ERR(div->table)) {
-               ret = PTR_ERR(div->table);
-               kfree(div);
-               return ERR_PTR(ret);
-       }
-
-
-       div->shift = setup->bit_shift;
-       div->latch = -EINVAL;
-
-       return &div->hw;
-}
-
-struct clk *ti_clk_register_divider(struct ti_clk *setup)
-{
-       struct ti_clk_divider *div = setup->data;
-       struct clk_omap_reg reg = {
-               .index = div->module,
-               .offset = div->reg,
-       };
-       u8 width;
-       u32 flags = 0;
-       u8 div_flags = 0;
-       const struct clk_div_table *table;
-       struct clk *clk;
-
-       if (div->flags & CLKF_INDEX_STARTS_AT_ONE)
-               div_flags |= CLK_DIVIDER_ONE_BASED;
-
-       if (div->flags & CLKF_INDEX_POWER_OF_TWO)
-               div_flags |= CLK_DIVIDER_POWER_OF_TWO;
-
-       if (div->flags & CLKF_SET_RATE_PARENT)
-               flags |= CLK_SET_RATE_PARENT;
-
-       table = _get_div_table_from_setup(div, &width);
-       if (IS_ERR(table))
-               return (struct clk *)table;
-
-       clk = _register_divider(NULL, setup->name, div->parent,
-                               flags, &reg, div->bit_shift,
-                               width, -EINVAL, div_flags, table);
-
-       if (IS_ERR(clk))
-               kfree(table);
-
-       return clk;
-}
-
 static struct clk_div_table *
 __init ti_clk_get_div_table(struct device_node *node)
 {
index 504c0e9..4238955 100644 (file)
@@ -131,36 +131,6 @@ static struct clk *_register_gate(struct device *dev, const char *name,
        return clk;
 }
 
-struct clk_hw *ti_clk_build_component_gate(struct ti_clk_gate *setup)
-{
-       struct clk_hw_omap *gate;
-       struct clk_omap_reg *reg;
-       const struct clk_hw_omap_ops *ops = &clkhwops_wait;
-
-       if (!setup)
-               return NULL;
-
-       gate = kzalloc(sizeof(*gate), GFP_KERNEL);
-       if (!gate)
-               return ERR_PTR(-ENOMEM);
-
-       reg = (struct clk_omap_reg *)&gate->enable_reg;
-       reg->index = setup->module;
-       reg->offset = setup->reg;
-
-       gate->enable_bit = setup->bit_shift;
-
-       if (setup->flags & CLKF_NO_WAIT)
-               ops = NULL;
-
-       if (setup->flags & CLKF_INTERFACE)
-               ops = &clkhwops_iclk_wait;
-
-       gate->ops = ops;
-
-       return &gate->hw;
-}
-
 static void __init _of_ti_gate_clk_setup(struct device_node *node,
                                         const struct clk_ops *ops,
                                         const struct clk_hw_omap_ops *hw_ops)
index b7f9a4f..0069e7c 100644 (file)
@@ -164,37 +164,6 @@ static struct clk *_register_mux(struct device *dev, const char *name,
        return clk;
 }
 
-struct clk *ti_clk_register_mux(struct ti_clk *setup)
-{
-       struct ti_clk_mux *mux;
-       u32 flags;
-       u8 mux_flags = 0;
-       struct clk_omap_reg reg;
-       u32 mask;
-
-       mux = setup->data;
-       flags = CLK_SET_RATE_NO_REPARENT;
-
-       mask = mux->num_parents;
-       if (!(mux->flags & CLKF_INDEX_STARTS_AT_ONE))
-               mask--;
-
-       mask = (1 << fls(mask)) - 1;
-       reg.index = mux->module;
-       reg.offset = mux->reg;
-       reg.ptr = NULL;
-
-       if (mux->flags & CLKF_INDEX_STARTS_AT_ONE)
-               mux_flags |= CLK_MUX_INDEX_ONE;
-
-       if (mux->flags & CLKF_SET_RATE_PARENT)
-               flags |= CLK_SET_RATE_PARENT;
-
-       return _register_mux(NULL, setup->name, mux->parents, mux->num_parents,
-                            flags, &reg, mux->bit_shift, mask, -EINVAL,
-                            mux_flags, NULL);
-}
-
 /**
  * of_mux_clk_setup - Setup function for simple mux rate clock
  * @node: DT node for the clock
index 23553ed..2d22d6b 100644 (file)
@@ -248,16 +248,12 @@ static int __maybe_unused cn_proc_show(struct seq_file *m, void *v)
        return 0;
 }
 
-static struct cn_dev cdev = {
-       .input   = cn_rx_skb,
-};
-
 static int cn_init(void)
 {
        struct cn_dev *dev = &cdev;
        struct netlink_kernel_cfg cfg = {
                .groups = CN_NETLINK_USERS + 0xf,
-               .input  = dev->input,
+               .input  = cn_rx_skb,
        };
 
        dev->nls = netlink_kernel_create(&init_net, NETLINK_CONNECTOR, &cfg);
index 56a4ebb..f7c23fa 100644 (file)
@@ -131,23 +131,18 @@ static int bmips_cpufreq_exit(struct cpufreq_policy *policy)
 static int bmips_cpufreq_init(struct cpufreq_policy *policy)
 {
        struct cpufreq_frequency_table *freq_table;
-       int ret;
 
        freq_table = bmips_cpufreq_get_freq_table(policy);
        if (IS_ERR(freq_table)) {
-               ret = PTR_ERR(freq_table);
-               pr_err("%s: couldn't determine frequency table (%d).\n",
-                       BMIPS_CPUFREQ_NAME, ret);
-               return ret;
+               pr_err("%s: couldn't determine frequency table (%ld).\n",
+                       BMIPS_CPUFREQ_NAME, PTR_ERR(freq_table));
+               return PTR_ERR(freq_table);
        }
 
-       ret = cpufreq_generic_init(policy, freq_table, TRANSITION_LATENCY);
-       if (ret)
-               bmips_cpufreq_exit(policy);
-       else
-               pr_info("%s: registered\n", BMIPS_CPUFREQ_NAME);
+       cpufreq_generic_init(policy, freq_table, TRANSITION_LATENCY);
+       pr_info("%s: registered\n", BMIPS_CPUFREQ_NAME);
 
-       return ret;
+       return 0;
 }
 
 static struct cpufreq_driver bmips_cpufreq_driver = {
index 0a9f675..8dda623 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/pm_qos.h>
 #include <linux/slab.h>
 #include <linux/suspend.h>
 #include <linux/syscore_ops.h>
@@ -158,7 +159,7 @@ EXPORT_SYMBOL_GPL(arch_set_freq_scale);
  * - set policies transition latency
  * - policy->cpus with all possible CPUs
  */
-int cpufreq_generic_init(struct cpufreq_policy *policy,
+void cpufreq_generic_init(struct cpufreq_policy *policy,
                struct cpufreq_frequency_table *table,
                unsigned int transition_latency)
 {
@@ -170,8 +171,6 @@ int cpufreq_generic_init(struct cpufreq_policy *policy,
         * share the clock and voltage and clock.
         */
        cpumask_setall(policy->cpus);
-
-       return 0;
 }
 EXPORT_SYMBOL_GPL(cpufreq_generic_init);
 
@@ -714,23 +713,15 @@ static ssize_t show_scaling_cur_freq(struct cpufreq_policy *policy, char *buf)
 static ssize_t store_##file_name                                       \
 (struct cpufreq_policy *policy, const char *buf, size_t count)         \
 {                                                                      \
-       int ret, temp;                                                  \
-       struct cpufreq_policy new_policy;                               \
+       unsigned long val;                                              \
+       int ret;                                                        \
                                                                        \
-       memcpy(&new_policy, policy, sizeof(*policy));                   \
-       new_policy.min = policy->user_policy.min;                       \
-       new_policy.max = policy->user_policy.max;                       \
-                                                                       \
-       ret = sscanf(buf, "%u", &new_policy.object);                    \
+       ret = sscanf(buf, "%lu", &val);                                 \
        if (ret != 1)                                                   \
                return -EINVAL;                                         \
                                                                        \
-       temp = new_policy.object;                                       \
-       ret = cpufreq_set_policy(policy, &new_policy);          \
-       if (!ret)                                                       \
-               policy->user_policy.object = temp;                      \
-                                                                       \
-       return ret ? ret : count;                                       \
+       ret = dev_pm_qos_update_request(policy->object##_freq_req, val);\
+       return ret >= 0 ? count : ret;                                  \
 }
 
 store_one(scaling_min_freq, min);
@@ -996,7 +987,7 @@ static void add_cpu_dev_symlink(struct cpufreq_policy *policy, unsigned int cpu)
 {
        struct device *dev = get_cpu_device(cpu);
 
-       if (!dev)
+       if (unlikely(!dev))
                return;
 
        if (cpumask_test_and_set_cpu(cpu, policy->real_cpus))
@@ -1112,17 +1103,18 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, unsigned int cp
        return ret;
 }
 
-static void refresh_frequency_limits(struct cpufreq_policy *policy)
+void refresh_frequency_limits(struct cpufreq_policy *policy)
 {
-       struct cpufreq_policy new_policy = *policy;
-
-       pr_debug("updating policy for CPU %u\n", policy->cpu);
+       struct cpufreq_policy new_policy;
 
-       new_policy.min = policy->user_policy.min;
-       new_policy.max = policy->user_policy.max;
+       if (!policy_is_inactive(policy)) {
+               new_policy = *policy;
+               pr_debug("updating policy for CPU %u\n", policy->cpu);
 
-       cpufreq_set_policy(policy, &new_policy);
+               cpufreq_set_policy(policy, &new_policy);
+       }
 }
+EXPORT_SYMBOL(refresh_frequency_limits);
 
 static void handle_update(struct work_struct *work)
 {
@@ -1130,14 +1122,60 @@ static void handle_update(struct work_struct *work)
                container_of(work, struct cpufreq_policy, update);
 
        pr_debug("handle_update for cpu %u called\n", policy->cpu);
+       down_write(&policy->rwsem);
        refresh_frequency_limits(policy);
+       up_write(&policy->rwsem);
+}
+
+static int cpufreq_notifier_min(struct notifier_block *nb, unsigned long freq,
+                               void *data)
+{
+       struct cpufreq_policy *policy = container_of(nb, struct cpufreq_policy, nb_min);
+
+       schedule_work(&policy->update);
+       return 0;
+}
+
+static int cpufreq_notifier_max(struct notifier_block *nb, unsigned long freq,
+                               void *data)
+{
+       struct cpufreq_policy *policy = container_of(nb, struct cpufreq_policy, nb_max);
+
+       schedule_work(&policy->update);
+       return 0;
+}
+
+static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy)
+{
+       struct kobject *kobj;
+       struct completion *cmp;
+
+       down_write(&policy->rwsem);
+       cpufreq_stats_free_table(policy);
+       kobj = &policy->kobj;
+       cmp = &policy->kobj_unregister;
+       up_write(&policy->rwsem);
+       kobject_put(kobj);
+
+       /*
+        * We need to make sure that the underlying kobj is
+        * actually not referenced anymore by anybody before we
+        * proceed with unloading.
+        */
+       pr_debug("waiting for dropping of refcount\n");
+       wait_for_completion(cmp);
+       pr_debug("wait complete\n");
 }
 
 static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
 {
        struct cpufreq_policy *policy;
+       struct device *dev = get_cpu_device(cpu);
        int ret;
 
+       if (!dev)
+               return NULL;
+
        policy = kzalloc(sizeof(*policy), GFP_KERNEL);
        if (!policy)
                return NULL;
@@ -1154,7 +1192,7 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
        ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
                                   cpufreq_global_kobject, "policy%u", cpu);
        if (ret) {
-               pr_err("%s: failed to init policy->kobj: %d\n", __func__, ret);
+               dev_err(dev, "%s: failed to init policy->kobj: %d\n", __func__, ret);
                /*
                 * The entire policy object will be freed below, but the extra
                 * memory allocated for the kobject name needs to be freed by
@@ -1164,6 +1202,25 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
                goto err_free_real_cpus;
        }
 
+       policy->nb_min.notifier_call = cpufreq_notifier_min;
+       policy->nb_max.notifier_call = cpufreq_notifier_max;
+
+       ret = dev_pm_qos_add_notifier(dev, &policy->nb_min,
+                                     DEV_PM_QOS_MIN_FREQUENCY);
+       if (ret) {
+               dev_err(dev, "Failed to register MIN QoS notifier: %d (%*pbl)\n",
+                       ret, cpumask_pr_args(policy->cpus));
+               goto err_kobj_remove;
+       }
+
+       ret = dev_pm_qos_add_notifier(dev, &policy->nb_max,
+                                     DEV_PM_QOS_MAX_FREQUENCY);
+       if (ret) {
+               dev_err(dev, "Failed to register MAX QoS notifier: %d (%*pbl)\n",
+                       ret, cpumask_pr_args(policy->cpus));
+               goto err_min_qos_notifier;
+       }
+
        INIT_LIST_HEAD(&policy->policy_list);
        init_rwsem(&policy->rwsem);
        spin_lock_init(&policy->transition_lock);
@@ -1174,6 +1231,11 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
        policy->cpu = cpu;
        return policy;
 
+err_min_qos_notifier:
+       dev_pm_qos_remove_notifier(dev, &policy->nb_min,
+                                  DEV_PM_QOS_MIN_FREQUENCY);
+err_kobj_remove:
+       cpufreq_policy_put_kobj(policy);
 err_free_real_cpus:
        free_cpumask_var(policy->real_cpus);
 err_free_rcpumask:
@@ -1186,30 +1248,9 @@ err_free_policy:
        return NULL;
 }
 
-static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy)
-{
-       struct kobject *kobj;
-       struct completion *cmp;
-
-       down_write(&policy->rwsem);
-       cpufreq_stats_free_table(policy);
-       kobj = &policy->kobj;
-       cmp = &policy->kobj_unregister;
-       up_write(&policy->rwsem);
-       kobject_put(kobj);
-
-       /*
-        * We need to make sure that the underlying kobj is
-        * actually not referenced anymore by anybody before we
-        * proceed with unloading.
-        */
-       pr_debug("waiting for dropping of refcount\n");
-       wait_for_completion(cmp);
-       pr_debug("wait complete\n");
-}
-
 static void cpufreq_policy_free(struct cpufreq_policy *policy)
 {
+       struct device *dev = get_cpu_device(policy->cpu);
        unsigned long flags;
        int cpu;
 
@@ -1221,6 +1262,14 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
                per_cpu(cpufreq_cpu_data, cpu) = NULL;
        write_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
+       dev_pm_qos_remove_notifier(dev, &policy->nb_max,
+                                  DEV_PM_QOS_MAX_FREQUENCY);
+       dev_pm_qos_remove_notifier(dev, &policy->nb_min,
+                                  DEV_PM_QOS_MIN_FREQUENCY);
+       dev_pm_qos_remove_request(policy->max_freq_req);
+       dev_pm_qos_remove_request(policy->min_freq_req);
+       kfree(policy->min_freq_req);
+
        cpufreq_policy_put_kobj(policy);
        free_cpumask_var(policy->real_cpus);
        free_cpumask_var(policy->related_cpus);
@@ -1298,16 +1347,50 @@ static int cpufreq_online(unsigned int cpu)
        cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
 
        if (new_policy) {
-               policy->user_policy.min = policy->min;
-               policy->user_policy.max = policy->max;
+               struct device *dev = get_cpu_device(cpu);
 
                for_each_cpu(j, policy->related_cpus) {
                        per_cpu(cpufreq_cpu_data, j) = policy;
                        add_cpu_dev_symlink(policy, j);
                }
-       } else {
-               policy->min = policy->user_policy.min;
-               policy->max = policy->user_policy.max;
+
+               policy->min_freq_req = kzalloc(2 * sizeof(*policy->min_freq_req),
+                                              GFP_KERNEL);
+               if (!policy->min_freq_req)
+                       goto out_destroy_policy;
+
+               ret = dev_pm_qos_add_request(dev, policy->min_freq_req,
+                                            DEV_PM_QOS_MIN_FREQUENCY,
+                                            policy->min);
+               if (ret < 0) {
+                       /*
+                        * So we don't call dev_pm_qos_remove_request() for an
+                        * uninitialized request.
+                        */
+                       kfree(policy->min_freq_req);
+                       policy->min_freq_req = NULL;
+
+                       dev_err(dev, "Failed to add min-freq constraint (%d)\n",
+                               ret);
+                       goto out_destroy_policy;
+               }
+
+               /*
+                * This must be initialized right here to avoid calling
+                * dev_pm_qos_remove_request() on uninitialized request in case
+                * of errors.
+                */
+               policy->max_freq_req = policy->min_freq_req + 1;
+
+               ret = dev_pm_qos_add_request(dev, policy->max_freq_req,
+                                            DEV_PM_QOS_MAX_FREQUENCY,
+                                            policy->max);
+               if (ret < 0) {
+                       policy->max_freq_req = NULL;
+                       dev_err(dev, "Failed to add max-freq constraint (%d)\n",
+                               ret);
+                       goto out_destroy_policy;
+               }
        }
 
        if (cpufreq_driver->get && has_target()) {
@@ -2280,6 +2363,7 @@ int cpufreq_set_policy(struct cpufreq_policy *policy,
                       struct cpufreq_policy *new_policy)
 {
        struct cpufreq_governor *old_gov;
+       struct device *cpu_dev = get_cpu_device(policy->cpu);
        int ret;
 
        pr_debug("setting new policy for CPU %u: %u - %u kHz\n",
@@ -2288,17 +2372,21 @@ int cpufreq_set_policy(struct cpufreq_policy *policy,
        memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo));
 
        /*
-       * This check works well when we store new min/max freq attributes,
-       * because new_policy is a copy of policy with one field updated.
-       */
-       if (new_policy->min > new_policy->max)
-               return -EINVAL;
+        * PM QoS framework collects all the requests from users and provide us
+        * the final aggregated value here.
+        */
+       new_policy->min = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MIN_FREQUENCY);
+       new_policy->max = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MAX_FREQUENCY);
 
        /* verify the cpu speed can be set within this limit */
        ret = cpufreq_driver->verify(new_policy);
        if (ret)
                return ret;
 
+       /*
+        * The notifier-chain shall be removed once all the users of
+        * CPUFREQ_ADJUST are moved to use the QoS framework.
+        */
        /* adjust if necessary - all reasons */
        blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
                        CPUFREQ_ADJUST, new_policy);
@@ -2377,10 +2465,9 @@ int cpufreq_set_policy(struct cpufreq_policy *policy,
  * @cpu: CPU to re-evaluate the policy for.
  *
  * Update the current frequency for the cpufreq policy of @cpu and use
- * cpufreq_set_policy() to re-apply the min and max limits saved in the
- * user_policy sub-structure of that policy, which triggers the evaluation
- * of policy notifiers and the cpufreq driver's ->verify() callback for the
- * policy in question, among other things.
+ * cpufreq_set_policy() to re-apply the min and max limits, which triggers the
+ * evaluation of policy notifiers and the cpufreq driver's ->verify() callback
+ * for the policy in question, among other things.
  */
 void cpufreq_update_policy(unsigned int cpu)
 {
@@ -2440,10 +2527,9 @@ static int cpufreq_boost_set_sw(int state)
                        break;
                }
 
-               down_write(&policy->rwsem);
-               policy->user_policy.max = policy->max;
-               cpufreq_governor_limits(policy);
-               up_write(&policy->rwsem);
+               ret = dev_pm_qos_update_request(policy->max_freq_req, policy->max);
+               if (ret)
+                       break;
        }
 
        return ret;
index 3de48ae..297d23c 100644 (file)
@@ -90,7 +90,8 @@ static int davinci_cpu_init(struct cpufreq_policy *policy)
         * Setting the latency to 2000 us to accommodate addition of drivers
         * to pre/post change notification list.
         */
-       return cpufreq_generic_init(policy, freq_table, 2000 * 1000);
+       cpufreq_generic_init(policy, freq_table, 2000 * 1000);
+       return 0;
 }
 
 static struct cpufreq_driver davinci_driver = {
index b54fd26..4f85f31 100644 (file)
@@ -44,10 +44,11 @@ static int imx_cpufreq_dt_probe(struct platform_device *pdev)
         * According to datasheet minimum speed grading is not supported for
         * consumer parts so clamp to 1 to avoid warning for "no OPPs"
         *
-        * Applies to 8mq and 8mm.
+        * Applies to i.MX8M series SoCs.
         */
        if (mkt_segment == 0 && speed_grade == 0 && (
                        of_machine_is_compatible("fsl,imx8mm") ||
+                       of_machine_is_compatible("fsl,imx8mn") ||
                        of_machine_is_compatible("fsl,imx8mq")))
                speed_grade = 1;
 
index 47ccfa6..648a09a 100644 (file)
@@ -190,14 +190,12 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
 
 static int imx6q_cpufreq_init(struct cpufreq_policy *policy)
 {
-       int ret;
-
        policy->clk = clks[ARM].clk;
-       ret = cpufreq_generic_init(policy, freq_table, transition_latency);
+       cpufreq_generic_init(policy, freq_table, transition_latency);
        policy->suspend_freq = max_freq;
        dev_pm_opp_of_register_em(policy->cpus);
 
-       return ret;
+       return 0;
 }
 
 static struct cpufreq_driver imx6q_cpufreq_driver = {
index f2ff5de..cc27d4c 100644 (file)
@@ -898,7 +898,6 @@ static void intel_pstate_update_policies(void)
 static void intel_pstate_update_max_freq(unsigned int cpu)
 {
        struct cpufreq_policy *policy = cpufreq_cpu_acquire(cpu);
-       struct cpufreq_policy new_policy;
        struct cpudata *cpudata;
 
        if (!policy)
@@ -908,11 +907,7 @@ static void intel_pstate_update_max_freq(unsigned int cpu)
        policy->cpuinfo.max_freq = global.turbo_disabled_mf ?
                        cpudata->pstate.max_freq : cpudata->pstate.turbo_freq;
 
-       memcpy(&new_policy, policy, sizeof(*policy));
-       new_policy.max = min(policy->user_policy.max, policy->cpuinfo.max_freq);
-       new_policy.min = min(policy->user_policy.min, new_policy.max);
-
-       cpufreq_set_policy(policy, &new_policy);
+       refresh_frequency_limits(policy);
 
        cpufreq_cpu_release(policy);
 }
index 7ab564c..cb74bdc 100644 (file)
@@ -85,7 +85,8 @@ static int kirkwood_cpufreq_target(struct cpufreq_policy *policy,
 /* Module init and exit code */
 static int kirkwood_cpufreq_cpu_init(struct cpufreq_policy *policy)
 {
-       return cpufreq_generic_init(policy, kirkwood_freq_table, 5000);
+       cpufreq_generic_init(policy, kirkwood_freq_table, 5000);
+       return 0;
 }
 
 static struct cpufreq_driver kirkwood_cpufreq_driver = {
index 21c9ce8..0ea8877 100644 (file)
@@ -81,7 +81,7 @@ static int ls1x_cpufreq_init(struct cpufreq_policy *policy)
        struct device *cpu_dev = get_cpu_device(policy->cpu);
        struct cpufreq_frequency_table *freq_tbl;
        unsigned int pll_freq, freq;
-       int steps, i, ret;
+       int steps, i;
 
        pll_freq = clk_get_rate(cpufreq->pll_clk) / 1000;
 
@@ -103,11 +103,9 @@ static int ls1x_cpufreq_init(struct cpufreq_policy *policy)
        freq_tbl[i].frequency = CPUFREQ_TABLE_END;
 
        policy->clk = cpufreq->clk;
-       ret = cpufreq_generic_init(policy, freq_tbl, 0);
-       if (ret)
-               kfree(freq_tbl);
+       cpufreq_generic_init(policy, freq_tbl, 0);
 
-       return ret;
+       return 0;
 }
 
 static int ls1x_cpufreq_exit(struct cpufreq_policy *policy)
index da34469..890813e 100644 (file)
@@ -95,7 +95,8 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)
        }
 
        policy->clk = cpuclk;
-       return cpufreq_generic_init(policy, &loongson2_clockmod_table[0], 0);
+       cpufreq_generic_init(policy, &loongson2_clockmod_table[0], 0);
+       return 0;
 }
 
 static int loongson2_cpufreq_exit(struct cpufreq_policy *policy)
index f5220b3..28d3460 100644 (file)
@@ -140,7 +140,8 @@ static unsigned int maple_cpufreq_get_speed(unsigned int cpu)
 
 static int maple_cpufreq_cpu_init(struct cpufreq_policy *policy)
 {
-       return cpufreq_generic_init(policy, maple_cpu_freqs, 12000);
+       cpufreq_generic_init(policy, maple_cpu_freqs, 12000);
+       return 0;
 }
 
 static struct cpufreq_driver maple_cpufreq_driver = {
index 29643f0..8d14b42 100644 (file)
@@ -122,23 +122,18 @@ static int omap_cpu_init(struct cpufreq_policy *policy)
                        dev_err(mpu_dev,
                                "%s: cpu%d: failed creating freq table[%d]\n",
                                __func__, policy->cpu, result);
-                       goto fail;
+                       clk_put(policy->clk);
+                       return result;
                }
        }
 
        atomic_inc_return(&freq_table_users);
 
        /* FIXME: what's the actual transition time? */
-       result = cpufreq_generic_init(policy, freq_table, 300 * 1000);
-       if (!result) {
-               dev_pm_opp_of_register_em(policy->cpus);
-               return 0;
-       }
+       cpufreq_generic_init(policy, freq_table, 300 * 1000);
+       dev_pm_opp_of_register_em(policy->cpus);
 
-       freq_table_free();
-fail:
-       clk_put(policy->clk);
-       return result;
+       return 0;
 }
 
 static int omap_cpu_exit(struct cpufreq_policy *policy)
index 6b1e4ab..c66f566 100644 (file)
@@ -131,10 +131,18 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
        int err = -ENODEV;
 
        cpu = of_get_cpu_node(policy->cpu, NULL);
+       if (!cpu)
+               goto out;
 
+       max_freqp = of_get_property(cpu, "clock-frequency", NULL);
        of_node_put(cpu);
-       if (!cpu)
+       if (!max_freqp) {
+               err = -EINVAL;
                goto out;
+       }
+
+       /* we need the freq in kHz */
+       max_freq = *max_freqp / 1000;
 
        dn = of_find_compatible_node(NULL, NULL, "1682m-sdc");
        if (!dn)
@@ -171,16 +179,6 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
        }
 
        pr_debug("init cpufreq on CPU %d\n", policy->cpu);
-
-       max_freqp = of_get_property(cpu, "clock-frequency", NULL);
-       if (!max_freqp) {
-               err = -EINVAL;
-               goto out_unmap_sdcpwr;
-       }
-
-       /* we need the freq in kHz */
-       max_freq = *max_freqp / 1000;
-
        pr_debug("max clock-frequency is at %u kHz\n", max_freq);
        pr_debug("initializing frequency table\n");
 
@@ -196,10 +194,8 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
        policy->cur = pas_freqs[cur_astate].frequency;
        ppc_proc_freq = policy->cur * 1000ul;
 
-       return cpufreq_generic_init(policy, pas_freqs, get_gizmo_latency());
-
-out_unmap_sdcpwr:
-       iounmap(sdcpwr_mapbase);
+       cpufreq_generic_init(policy, pas_freqs, get_gizmo_latency());
+       return 0;
 
 out_unmap_sdcasr:
        iounmap(sdcasr_mapbase);
index 650104d..73621bc 100644 (file)
@@ -372,7 +372,8 @@ static int pmac_cpufreq_target(     struct cpufreq_policy *policy,
 
 static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
 {
-       return cpufreq_generic_init(policy, pmac_cpu_freqs, transition_latency);
+       cpufreq_generic_init(policy, pmac_cpu_freqs, transition_latency);
+       return 0;
 }
 
 static u32 read_gpio(struct device_node *np)
index 1af3492..d7542a1 100644 (file)
@@ -321,7 +321,8 @@ static unsigned int g5_cpufreq_get_speed(unsigned int cpu)
 
 static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy)
 {
-       return cpufreq_generic_init(policy, g5_cpu_freqs, transition_latency);
+       cpufreq_generic_init(policy, g5_cpu_freqs, transition_latency);
+       return 0;
 }
 
 static struct cpufreq_driver g5_cpufreq_driver = {
index f7ff1ed..1069103 100644 (file)
@@ -447,21 +447,16 @@ static int s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
        /* Datasheet says PLL stabalisation time must be at least 300us,
         * so but add some fudge. (reference in LOCKCON0 register description)
         */
-       ret = cpufreq_generic_init(policy, s3c_freq->freq_table,
+       cpufreq_generic_init(policy, s3c_freq->freq_table,
                        (500 * 1000) + s3c_freq->regulator_latency);
-       if (ret)
-               goto err_freq_table;
-
        register_reboot_notifier(&s3c2416_cpufreq_reboot_notifier);
 
        return 0;
 
-err_freq_table:
 #ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
-       regulator_put(s3c_freq->vddarm);
 err_vddarm:
-#endif
        clk_put(s3c_freq->armclk);
+#endif
 err_armclk:
        clk_put(s3c_freq->hclk);
 err_hclk:
index 37df2d8..af0c00d 100644 (file)
@@ -144,7 +144,6 @@ out:
 
 static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
 {
-       int ret;
        struct cpufreq_frequency_table *freq;
 
        if (policy->cpu != 0)
@@ -165,8 +164,7 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
 #ifdef CONFIG_REGULATOR
        vddarm = regulator_get(NULL, "vddarm");
        if (IS_ERR(vddarm)) {
-               ret = PTR_ERR(vddarm);
-               pr_err("Failed to obtain VDDARM: %d\n", ret);
+               pr_err("Failed to obtain VDDARM: %ld\n", PTR_ERR(vddarm));
                pr_err("Only frequency scaling available\n");
                vddarm = NULL;
        } else {
@@ -196,16 +194,9 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
         * the PLLs, which we don't currently) is ~300us worst case,
         * but add some fudge.
         */
-       ret = cpufreq_generic_init(policy, s3c64xx_freq_table,
+       cpufreq_generic_init(policy, s3c64xx_freq_table,
                        (500 * 1000) + regulator_latency);
-       if (ret != 0) {
-               pr_err("Failed to configure frequency table: %d\n",
-                      ret);
-               regulator_put(vddarm);
-               clk_put(policy->clk);
-       }
-
-       return ret;
+       return 0;
 }
 
 static struct cpufreq_driver s3c64xx_cpufreq_driver = {
index e5cb17d..5d10030 100644 (file)
@@ -541,7 +541,8 @@ static int s5pv210_cpu_init(struct cpufreq_policy *policy)
        s5pv210_dram_conf[1].freq = clk_get_rate(dmc1_clk);
 
        policy->suspend_freq = SLEEP_FREQ;
-       return cpufreq_generic_init(policy, s5pv210_freq_table, 40000);
+       cpufreq_generic_init(policy, s5pv210_freq_table, 40000);
+       return 0;
 
 out_dmc1:
        clk_put(dmc0_clk);
index ab5cab9..5c075ef 100644 (file)
@@ -181,7 +181,8 @@ static int sa1100_target(struct cpufreq_policy *policy, unsigned int ppcr)
 
 static int __init sa1100_cpu_init(struct cpufreq_policy *policy)
 {
-       return cpufreq_generic_init(policy, sa11x0_freq_table, 0);
+       cpufreq_generic_init(policy, sa11x0_freq_table, 0);
+       return 0;
 }
 
 static struct cpufreq_driver sa1100_driver __refdata = {
index dab54e0..d9d04d9 100644 (file)
@@ -303,7 +303,8 @@ static int sa1110_target(struct cpufreq_policy *policy, unsigned int ppcr)
 
 static int __init sa1110_cpu_init(struct cpufreq_policy *policy)
 {
-       return cpufreq_generic_init(policy, sa11x0_freq_table, 0);
+       cpufreq_generic_init(policy, sa11x0_freq_table, 0);
+       return 0;
 }
 
 /* sa1110_driver needs __refdata because it must remain after init registers
index 4074e26..73bd8dc 100644 (file)
@@ -153,8 +153,9 @@ static int spear_cpufreq_target(struct cpufreq_policy *policy,
 static int spear_cpufreq_init(struct cpufreq_policy *policy)
 {
        policy->clk = spear_cpufreq.clk;
-       return cpufreq_generic_init(policy, spear_cpufreq.freq_tbl,
+       cpufreq_generic_init(policy, spear_cpufreq.freq_tbl,
                        spear_cpufreq.transition_latency);
+       return 0;
 }
 
 static struct cpufreq_driver spear_cpufreq_driver = {
index 3c32cc7..f84ecd2 100644 (file)
@@ -118,17 +118,11 @@ static int tegra_target(struct cpufreq_policy *policy, unsigned int index)
 static int tegra_cpu_init(struct cpufreq_policy *policy)
 {
        struct tegra20_cpufreq *cpufreq = cpufreq_get_driver_data();
-       int ret;
 
        clk_prepare_enable(cpufreq->cpu_clk);
 
        /* FIXME: what's the actual transition time? */
-       ret = cpufreq_generic_init(policy, freq_table, 300 * 1000);
-       if (ret) {
-               clk_disable_unprepare(cpufreq->cpu_clk);
-               return ret;
-       }
-
+       cpufreq_generic_init(policy, freq_table, 300 * 1000);
        policy->clk = cpufreq->cpu_clk;
        policy->suspend_freq = freq_table[0].frequency;
        return 0;
index 9fddf82..2e3e141 100644 (file)
@@ -110,7 +110,7 @@ int cpuidle_governor_latency_req(unsigned int cpu)
 {
        int global_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
        struct device *device = get_cpu_device(cpu);
-       int device_req = dev_pm_qos_raw_read_value(device);
+       int device_req = dev_pm_qos_raw_resume_latency(device);
 
        return device_req < global_req ? device_req : global_req;
 }
index 02a6bed..f10a87e 100644 (file)
@@ -108,7 +108,6 @@ void ppc4xx_trng_probe(struct crypto4xx_core_device *core_dev)
        return;
 
 err_out:
-       of_node_put(trng);
        iounmap(dev->trng_base);
        kfree(rng);
        dev->trng_base = NULL;
index 866b2e0..c69ed4b 100644 (file)
@@ -622,6 +622,7 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
 
        unsigned long long *final;
        unsigned int dm_offset;
+       unsigned int jobid;
        unsigned int ilen;
        bool in_place = true; /* Default value */
        int ret;
@@ -660,9 +661,11 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
                p_tag = scatterwalk_ffwd(sg_tag, p_inp, ilen);
        }
 
+       jobid = CCP_NEW_JOBID(cmd_q->ccp);
+
        memset(&op, 0, sizeof(op));
        op.cmd_q = cmd_q;
-       op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
+       op.jobid = jobid;
        op.sb_key = cmd_q->sb_key; /* Pre-allocated */
        op.sb_ctx = cmd_q->sb_ctx; /* Pre-allocated */
        op.init = 1;
@@ -813,6 +816,13 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
        final[0] = cpu_to_be64(aes->aad_len * 8);
        final[1] = cpu_to_be64(ilen * 8);
 
+       memset(&op, 0, sizeof(op));
+       op.cmd_q = cmd_q;
+       op.jobid = jobid;
+       op.sb_key = cmd_q->sb_key; /* Pre-allocated */
+       op.sb_ctx = cmd_q->sb_ctx; /* Pre-allocated */
+       op.init = 1;
+       op.u.aes.type = aes->type;
        op.u.aes.mode = CCP_AES_MODE_GHASH;
        op.u.aes.action = CCP_AES_GHASHFINAL;
        op.src.type = CCP_MEMTYPE_SYSTEM;
@@ -840,7 +850,8 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
                if (ret)
                        goto e_tag;
 
-               ret = memcmp(tag.address, final_wa.address, AES_BLOCK_SIZE);
+               ret = crypto_memneq(tag.address, final_wa.address,
+                                   AES_BLOCK_SIZE) ? -EBADMSG : 0;
                ccp_dm_free(&tag);
        }
 
index de5a8ca..6b17d17 100644 (file)
 #include "sp-dev.h"
 #include "psp-dev.h"
 
-#define SEV_VERSION_GREATER_OR_EQUAL(_maj, _min)       \
-               ((psp_master->api_major) >= _maj &&     \
-                (psp_master->api_minor) >= _min)
-
 #define DEVICE_NAME            "sev"
 #define SEV_FW_FILE            "amd/sev.fw"
 #define SEV_FW_NAME_SIZE       64
@@ -47,6 +43,15 @@ MODULE_PARM_DESC(psp_probe_timeout, " default timeout value, in seconds, during
 static bool psp_dead;
 static int psp_timeout;
 
+static inline bool sev_version_greater_or_equal(u8 maj, u8 min)
+{
+       if (psp_master->api_major > maj)
+               return true;
+       if (psp_master->api_major == maj && psp_master->api_minor >= min)
+               return true;
+       return false;
+}
+
 static struct psp_device *psp_alloc_struct(struct sp_device *sp)
 {
        struct device *dev = sp->dev;
@@ -588,7 +593,7 @@ static int sev_ioctl_do_get_id2(struct sev_issue_cmd *argp)
        int ret;
 
        /* SEV GET_ID is available from SEV API v0.16 and up */
-       if (!SEV_VERSION_GREATER_OR_EQUAL(0, 16))
+       if (!sev_version_greater_or_equal(0, 16))
                return -ENOTSUPP;
 
        if (copy_from_user(&input, (void __user *)argp->data, sizeof(input)))
@@ -651,7 +656,7 @@ static int sev_ioctl_do_get_id(struct sev_issue_cmd *argp)
        int ret;
 
        /* SEV GET_ID available from SEV API v0.16 and up */
-       if (!SEV_VERSION_GREATER_OR_EQUAL(0, 16))
+       if (!sev_version_greater_or_equal(0, 16))
                return -ENOTSUPP;
 
        /* SEV FW expects the buffer it fills with the ID to be
@@ -1053,7 +1058,7 @@ void psp_pci_init(void)
                psp_master->sev_state = SEV_STATE_UNINIT;
        }
 
-       if (SEV_VERSION_GREATER_OR_EQUAL(0, 15) &&
+       if (sev_version_greater_or_equal(0, 15) &&
            sev_update_firmware(psp_master->dev) == 0)
                sev_get_api_version();
 
index 23061f2..2b70d87 100644 (file)
@@ -338,7 +338,7 @@ static int stm32_hash_xmit_cpu(struct stm32_hash_dev *hdev,
 
        len32 = DIV_ROUND_UP(length, sizeof(u32));
 
-       dev_dbg(hdev->dev, "%s: length: %d, final: %x len32 %i\n",
+       dev_dbg(hdev->dev, "%s: length: %zd, final: %x len32 %i\n",
                __func__, length, final, len32);
 
        hdev->flags |= HASH_FLAGS_CPU;
index 4ab14d5..6f7cbf6 100644 (file)
@@ -8,7 +8,7 @@
  * keysize in CBC and ECB mode.
  * Add support also for DES and 3DES in CBC and ECB mode.
  *
- * You could find the datasheet in Documentation/arm/sunxi/README
+ * You could find the datasheet in Documentation/arm/sunxi.rst
  */
 #include "sun4i-ss.h"
 
index cdcda7f..2e87042 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Core file which registers crypto algorithms supported by the SS.
  *
- * You could find a link for the datasheet in Documentation/arm/sunxi/README
+ * You could find a link for the datasheet in Documentation/arm/sunxi.rst
  */
 #include <linux/clk.h>
 #include <linux/crypto.h>
index d2b6d89..fcffba5 100644 (file)
@@ -6,7 +6,7 @@
  *
  * This file add support for MD5 and SHA1.
  *
- * You could find the datasheet in Documentation/arm/sunxi/README
+ * You could find the datasheet in Documentation/arm/sunxi.rst
  */
 #include "sun4i-ss.h"
 #include <linux/scatterlist.h>
index 68b82d1..8654d48 100644 (file)
@@ -8,7 +8,7 @@
  * Support MD5 and SHA1 hash algorithms.
  * Support DES and 3DES
  *
- * You could find the datasheet in Documentation/arm/sunxi/README
+ * You could find the datasheet in Documentation/arm/sunxi.rst
  */
 
 #include <linux/clk.h>
index 2109cfe..8fafbea 100644 (file)
@@ -295,6 +295,22 @@ static ssize_t target_node_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(target_node);
 
+static unsigned long long dev_dax_resource(struct dev_dax *dev_dax)
+{
+       struct dax_region *dax_region = dev_dax->region;
+
+       return dax_region->res.start;
+}
+
+static ssize_t resource_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct dev_dax *dev_dax = to_dev_dax(dev);
+
+       return sprintf(buf, "%#llx\n", dev_dax_resource(dev_dax));
+}
+static DEVICE_ATTR_RO(resource);
+
 static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
                char *buf)
 {
@@ -313,6 +329,8 @@ static umode_t dev_dax_visible(struct kobject *kobj, struct attribute *a, int n)
 
        if (a == &dev_attr_target_node.attr && dev_dax_target_node(dev_dax) < 0)
                return 0;
+       if (a == &dev_attr_resource.attr)
+               return 0400;
        return a->mode;
 }
 
@@ -320,6 +338,7 @@ static struct attribute *dev_dax_attributes[] = {
        &dev_attr_modalias.attr,
        &dev_attr_size.attr,
        &dev_attr_target_node.attr,
+       &dev_attr_resource.attr,
        NULL,
 };
 
@@ -388,7 +407,7 @@ struct dev_dax *__devm_create_dev_dax(struct dax_region *dax_region, int id,
         * No 'host' or dax_operations since there is no access to this
         * device outside of mmap of the resulting character device.
         */
-       dax_dev = alloc_dax(dev_dax, NULL, NULL);
+       dax_dev = alloc_dax(dev_dax, NULL, NULL, DAXDEV_F_SYNC);
        if (!dax_dev)
                goto err;
 
index c915889..6ccca3b 100644 (file)
@@ -43,6 +43,7 @@ struct dax_region {
  * @target_node: effective numa node if dev_dax memory range is onlined
  * @dev - device core
  * @pgmap - pgmap for memmap setup / lifetime (driver owned)
+ * @dax_mem_res: physical address range of hotadded DAX memory
  */
 struct dev_dax {
        struct dax_region *region;
@@ -50,6 +51,7 @@ struct dev_dax {
        int target_node;
        struct device dev;
        struct dev_pagemap pgmap;
+       struct resource *dax_kmem_res;
 };
 
 static inline struct dev_dax *to_dev_dax(struct device *dev)
index a02318c..3d0a7e7 100644 (file)
@@ -66,23 +66,59 @@ int dev_dax_kmem_probe(struct device *dev)
        new_res->name = dev_name(dev);
 
        rc = add_memory(numa_node, new_res->start, resource_size(new_res));
-       if (rc)
+       if (rc) {
+               release_resource(new_res);
+               kfree(new_res);
                return rc;
+       }
+       dev_dax->dax_kmem_res = new_res;
 
        return 0;
 }
 
+#ifdef CONFIG_MEMORY_HOTREMOVE
+static int dev_dax_kmem_remove(struct device *dev)
+{
+       struct dev_dax *dev_dax = to_dev_dax(dev);
+       struct resource *res = dev_dax->dax_kmem_res;
+       resource_size_t kmem_start = res->start;
+       resource_size_t kmem_size = resource_size(res);
+       int rc;
+
+       /*
+        * We have one shot for removing memory, if some memory blocks were not
+        * offline prior to calling this function remove_memory() will fail, and
+        * there is no way to hotremove this memory until reboot because device
+        * unbind will succeed even if we return failure.
+        */
+       rc = remove_memory(dev_dax->target_node, kmem_start, kmem_size);
+       if (rc) {
+               dev_err(dev,
+                       "DAX region %pR cannot be hotremoved until the next reboot\n",
+                       res);
+               return rc;
+       }
+
+       /* Release and free dax resources */
+       release_resource(res);
+       kfree(res);
+       dev_dax->dax_kmem_res = NULL;
+
+       return 0;
+}
+#else
 static int dev_dax_kmem_remove(struct device *dev)
 {
        /*
-        * Purposely leak the request_mem_region() for the device-dax
-        * range and return '0' to ->remove() attempts. The removal of
-        * the device from the driver always succeeds, but the region
-        * is permanently pinned as reserved by the unreleased
+        * Without hotremove purposely leak the request_mem_region() for the
+        * device-dax range and return '0' to ->remove() attempts. The removal
+        * of the device from the driver always succeeds, but the region is
+        * permanently pinned as reserved by the unreleased
         * request_mem_region().
         */
        return 0;
 }
+#endif /* CONFIG_MEMORY_HOTREMOVE */
 
 static struct dax_device_driver device_dax_kmem_driver = {
        .drv = {
index 4e5ae7e..26a654d 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/pagemap.h>
 #include <linux/module.h>
 #include <linux/mount.h>
+#include <linux/pseudo_fs.h>
 #include <linux/magic.h>
 #include <linux/genhd.h>
 #include <linux/pfn_t.h>
@@ -195,6 +196,8 @@ enum dax_device_flags {
        DAXDEV_ALIVE,
        /* gate whether dax_flush() calls the low level flush routine */
        DAXDEV_WRITE_CACHE,
+       /* flag to check if device supports synchronous flush */
+       DAXDEV_SYNC,
 };
 
 /**
@@ -372,6 +375,18 @@ bool dax_write_cache_enabled(struct dax_device *dax_dev)
 }
 EXPORT_SYMBOL_GPL(dax_write_cache_enabled);
 
+bool __dax_synchronous(struct dax_device *dax_dev)
+{
+       return test_bit(DAXDEV_SYNC, &dax_dev->flags);
+}
+EXPORT_SYMBOL_GPL(__dax_synchronous);
+
+void __set_dax_synchronous(struct dax_device *dax_dev)
+{
+       set_bit(DAXDEV_SYNC, &dax_dev->flags);
+}
+EXPORT_SYMBOL_GPL(__set_dax_synchronous);
+
 bool dax_alive(struct dax_device *dax_dev)
 {
        lockdep_assert_held(&dax_srcu);
@@ -455,16 +470,19 @@ static const struct super_operations dax_sops = {
        .drop_inode = generic_delete_inode,
 };
 
-static struct dentry *dax_mount(struct file_system_type *fs_type,
-               int flags, const char *dev_name, void *data)
+static int dax_init_fs_context(struct fs_context *fc)
 {
-       return mount_pseudo(fs_type, "dax:", &dax_sops, NULL, DAXFS_MAGIC);
+       struct pseudo_fs_context *ctx = init_pseudo(fc, DAXFS_MAGIC);
+       if (!ctx)
+               return -ENOMEM;
+       ctx->ops = &dax_sops;
+       return 0;
 }
 
 static struct file_system_type dax_fs_type = {
-       .name = "dax",
-       .mount = dax_mount,
-       .kill_sb = kill_anon_super,
+       .name           = "dax",
+       .init_fs_context = dax_init_fs_context,
+       .kill_sb        = kill_anon_super,
 };
 
 static int dax_test(struct inode *inode, void *data)
@@ -526,7 +544,7 @@ static void dax_add_host(struct dax_device *dax_dev, const char *host)
 }
 
 struct dax_device *alloc_dax(void *private, const char *__host,
-               const struct dax_operations *ops)
+               const struct dax_operations *ops, unsigned long flags)
 {
        struct dax_device *dax_dev;
        const char *host;
@@ -549,6 +567,9 @@ struct dax_device *alloc_dax(void *private, const char *__host,
        dax_add_host(dax_dev, host);
        dax_dev->ops = ops;
        dax_dev->private = private;
+       if (flags & DAXDEV_F_SYNC)
+               set_dax_synchronous(dax_dev);
+
        return dax_dev;
 
  err_dev:
@@ -648,10 +669,6 @@ static int dax_fs_init(void)
        if (!dax_cache)
                return -ENOMEM;
 
-       rc = register_filesystem(&dax_fs_type);
-       if (rc)
-               goto err_register_fs;
-
        dax_mnt = kern_mount(&dax_fs_type);
        if (IS_ERR(dax_mnt)) {
                rc = PTR_ERR(dax_mnt);
@@ -662,8 +679,6 @@ static int dax_fs_init(void)
        return 0;
 
  err_mount:
-       unregister_filesystem(&dax_fs_type);
- err_register_fs:
        kmem_cache_destroy(dax_cache);
 
        return rc;
@@ -672,7 +687,6 @@ static int dax_fs_init(void)
 static void dax_fs_exit(void)
 {
        kern_unmount(dax_mnt);
-       unregister_filesystem(&dax_fs_type);
        kmem_cache_destroy(dax_cache);
 }
 
index d5f9158..b6a9c2f 100644 (file)
@@ -15,7 +15,7 @@ config SYNC_FILE
          associated with a buffer. When a job is submitted to the GPU a fence
          is attached to the buffer and is transferred via userspace, using Sync
          Files fds, to the DRM driver for example. More details at
-         Documentation/sync_file.txt.
+         Documentation/driver-api/sync_file.rst.
 
 config SW_SYNC
        bool "Sync File Validation Framework"
index dc4b2c5..f45bfb2 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/reservation.h>
 #include <linux/mm.h>
 #include <linux/mount.h>
+#include <linux/pseudo_fs.h>
 
 #include <uapi/linux/dma-buf.h>
 #include <uapi/linux/magic.h>
@@ -59,16 +60,20 @@ static const struct dentry_operations dma_buf_dentry_ops = {
 
 static struct vfsmount *dma_buf_mnt;
 
-static struct dentry *dma_buf_fs_mount(struct file_system_type *fs_type,
-               int flags, const char *name, void *data)
+static int dma_buf_fs_init_context(struct fs_context *fc)
 {
-       return mount_pseudo(fs_type, "dmabuf:", NULL, &dma_buf_dentry_ops,
-                       DMA_BUF_MAGIC);
+       struct pseudo_fs_context *ctx;
+
+       ctx = init_pseudo(fc, DMA_BUF_MAGIC);
+       if (!ctx)
+               return -ENOMEM;
+       ctx->dops = &dma_buf_dentry_ops;
+       return 0;
 }
 
 static struct file_system_type dma_buf_fs_type = {
        .name = "dmabuf",
-       .mount = dma_buf_fs_mount,
+       .init_fs_context = dma_buf_fs_init_context,
        .kill_sb = kill_anon_super,
 };
 
index 703275c..03fa0c5 100644 (file)
@@ -103,6 +103,7 @@ config AXI_DMAC
        depends on MICROBLAZE || NIOS2 || ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_SOCFPGA || COMPILE_TEST
        select DMA_ENGINE
        select DMA_VIRTUAL_CHANNELS
+       select REGMAP_MMIO
        help
          Enable support for the Analog Devices AXI-DMAC peripheral. This DMA
          controller is often used in Analog Device's reference designs for FPGA
@@ -584,7 +585,7 @@ config TEGRA20_APB_DMA
 
 config TEGRA210_ADMA
        tristate "NVIDIA Tegra210 ADMA support"
-       depends on (ARCH_TEGRA_210_SOC || COMPILE_TEST) && PM_CLK
+       depends on (ARCH_TEGRA_210_SOC || COMPILE_TEST)
        select DMA_ENGINE
        select DMA_VIRTUAL_CHANNELS
        help
@@ -666,6 +667,8 @@ source "drivers/dma/qcom/Kconfig"
 
 source "drivers/dma/dw/Kconfig"
 
+source "drivers/dma/dw-edma/Kconfig"
+
 source "drivers/dma/hsu/Kconfig"
 
 source "drivers/dma/sh/Kconfig"
index 6126e1c..5bddf6f 100644 (file)
@@ -29,6 +29,7 @@ obj-$(CONFIG_DMA_SUN4I) += sun4i-dma.o
 obj-$(CONFIG_DMA_SUN6I) += sun6i-dma.o
 obj-$(CONFIG_DW_AXI_DMAC) += dw-axi-dmac/
 obj-$(CONFIG_DW_DMAC_CORE) += dw/
+obj-$(CONFIG_DW_EDMA) += dw-edma/
 obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
 obj-$(CONFIG_FSL_DMA) += fsldma.o
 obj-$(CONFIG_FSL_EDMA) += fsl-edma.o fsl-edma-common.o
index 464725d..9adc7a2 100644 (file)
@@ -2508,9 +2508,8 @@ DEFINE_SHOW_ATTRIBUTE(pl08x_debugfs);
 static void init_pl08x_debugfs(struct pl08x_driver_data *pl08x)
 {
        /* Expose a simple debugfs interface to view all clocks */
-       (void) debugfs_create_file(dev_name(&pl08x->adev->dev),
-                       S_IFREG | S_IRUGO, NULL, pl08x,
-                       &pl08x_debugfs_fops);
+       debugfs_create_file(dev_name(&pl08x->adev->dev), S_IFREG | S_IRUGO,
+                           NULL, pl08x, &pl08x_debugfs_fops);
 }
 
 #else
index 627ef3e..b58ac72 100644 (file)
@@ -1568,11 +1568,14 @@ static void at_xdmac_handle_cyclic(struct at_xdmac_chan *atchan)
        struct at_xdmac_desc            *desc;
        struct dma_async_tx_descriptor  *txd;
 
-       desc = list_first_entry(&atchan->xfers_list, struct at_xdmac_desc, xfer_node);
-       txd = &desc->tx_dma_desc;
+       if (!list_empty(&atchan->xfers_list)) {
+               desc = list_first_entry(&atchan->xfers_list,
+                                       struct at_xdmac_desc, xfer_node);
+               txd = &desc->tx_dma_desc;
 
-       if (txd->flags & DMA_PREP_INTERRUPT)
-               dmaengine_desc_get_callback_invoke(txd, NULL);
+               if (txd->flags & DMA_PREP_INTERRUPT)
+                       dmaengine_desc_get_callback_invoke(txd, NULL);
+       }
 }
 
 static void at_xdmac_handle_error(struct at_xdmac_chan *atchan)
index fa81d01..275e90f 100644 (file)
@@ -164,7 +164,6 @@ struct sba_device {
        struct list_head reqs_free_list;
        /* DebugFS directory entries */
        struct dentry *root;
-       struct dentry *stats;
 };
 
 /* ====== Command helper routines ===== */
@@ -1716,17 +1715,11 @@ static int sba_probe(struct platform_device *pdev)
 
        /* Create debugfs root entry */
        sba->root = debugfs_create_dir(dev_name(sba->dev), NULL);
-       if (IS_ERR_OR_NULL(sba->root)) {
-               dev_err(sba->dev, "failed to create debugfs root entry\n");
-               sba->root = NULL;
-               goto skip_debugfs;
-       }
 
        /* Create debugfs stats entry */
-       sba->stats = debugfs_create_devm_seqfile(sba->dev, "stats", sba->root,
-                                                sba_debugfs_stats_show);
-       if (IS_ERR_OR_NULL(sba->stats))
-               dev_err(sba->dev, "failed to create debugfs stats file\n");
+       debugfs_create_devm_seqfile(sba->dev, "stats", sba->root,
+                                   sba_debugfs_stats_show);
+
 skip_debugfs:
 
        /* Register DMA device with Linux async framework */
index 547786a..e51d836 100644 (file)
@@ -1378,10 +1378,8 @@ static int __init init_coh901318_debugfs(void)
 
        dma_dentry = debugfs_create_dir("dma", NULL);
 
-       (void) debugfs_create_file("status",
-                                  S_IFREG | S_IRUGO,
-                                  dma_dentry, NULL,
-                                  &coh901318_debugfs_status_operations);
+       debugfs_create_file("status", S_IFREG | S_IRUGO, dma_dentry, NULL,
+                           &coh901318_debugfs_status_operations);
        return 0;
 }
 
index 8a3f104..a0ee404 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Driver for the Analog Devices AXI-DMAC core
  *
- * Copyright 2013-2015 Analog Devices Inc.
+ * Copyright 2013-2019 Analog Devices Inc.
  *  Author: Lars-Peter Clausen <lars@metafoo.de>
  */
 
@@ -18,7 +18,9 @@
 #include <linux/of.h>
 #include <linux/of_dma.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
+#include <linux/fpga/adi-axi-common.h>
 
 #include <dt-bindings/dma/axi-dmac.h>
 
@@ -62,6 +64,8 @@
 #define AXI_DMAC_REG_STATUS            0x430
 #define AXI_DMAC_REG_CURRENT_SRC_ADDR  0x434
 #define AXI_DMAC_REG_CURRENT_DEST_ADDR 0x438
+#define AXI_DMAC_REG_PARTIAL_XFER_LEN  0x44c
+#define AXI_DMAC_REG_PARTIAL_XFER_ID   0x450
 
 #define AXI_DMAC_CTRL_ENABLE           BIT(0)
 #define AXI_DMAC_CTRL_PAUSE            BIT(1)
 #define AXI_DMAC_IRQ_EOT               BIT(1)
 
 #define AXI_DMAC_FLAG_CYCLIC           BIT(0)
+#define AXI_DMAC_FLAG_LAST             BIT(1)
+#define AXI_DMAC_FLAG_PARTIAL_REPORT   BIT(2)
+
+#define AXI_DMAC_FLAG_PARTIAL_XFER_DONE BIT(31)
 
 /* The maximum ID allocated by the hardware is 31 */
 #define AXI_DMAC_SG_UNUSED 32U
@@ -82,12 +90,14 @@ struct axi_dmac_sg {
        unsigned int dest_stride;
        unsigned int src_stride;
        unsigned int id;
+       unsigned int partial_len;
        bool schedule_when_free;
 };
 
 struct axi_dmac_desc {
        struct virt_dma_desc vdesc;
        bool cyclic;
+       bool have_partial_xfer;
 
        unsigned int num_submitted;
        unsigned int num_completed;
@@ -108,8 +118,10 @@ struct axi_dmac_chan {
        unsigned int dest_type;
 
        unsigned int max_length;
-       unsigned int align_mask;
+       unsigned int address_align_mask;
+       unsigned int length_align_mask;
 
+       bool hw_partial_xfer;
        bool hw_cyclic;
        bool hw_2d;
 };
@@ -167,14 +179,14 @@ static bool axi_dmac_check_len(struct axi_dmac_chan *chan, unsigned int len)
 {
        if (len == 0)
                return false;
-       if ((len & chan->align_mask) != 0) /* Not aligned */
+       if ((len & chan->length_align_mask) != 0) /* Not aligned */
                return false;
        return true;
 }
 
 static bool axi_dmac_check_addr(struct axi_dmac_chan *chan, dma_addr_t addr)
 {
-       if ((addr & chan->align_mask) != 0) /* Not aligned */
+       if ((addr & chan->address_align_mask) != 0) /* Not aligned */
                return false;
        return true;
 }
@@ -210,11 +222,13 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan)
        }
 
        desc->num_submitted++;
-       if (desc->num_submitted == desc->num_sgs) {
+       if (desc->num_submitted == desc->num_sgs ||
+           desc->have_partial_xfer) {
                if (desc->cyclic)
                        desc->num_submitted = 0; /* Start again */
                else
                        chan->next_desc = NULL;
+               flags |= AXI_DMAC_FLAG_LAST;
        } else {
                chan->next_desc = desc;
        }
@@ -240,6 +254,9 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan)
                desc->num_sgs == 1)
                flags |= AXI_DMAC_FLAG_CYCLIC;
 
+       if (chan->hw_partial_xfer)
+               flags |= AXI_DMAC_FLAG_PARTIAL_REPORT;
+
        axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, sg->x_len - 1);
        axi_dmac_write(dmac, AXI_DMAC_REG_Y_LENGTH, sg->y_len - 1);
        axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, flags);
@@ -252,6 +269,83 @@ static struct axi_dmac_desc *axi_dmac_active_desc(struct axi_dmac_chan *chan)
                struct axi_dmac_desc, vdesc.node);
 }
 
+static inline unsigned int axi_dmac_total_sg_bytes(struct axi_dmac_chan *chan,
+       struct axi_dmac_sg *sg)
+{
+       if (chan->hw_2d)
+               return sg->x_len * sg->y_len;
+       else
+               return sg->x_len;
+}
+
+static void axi_dmac_dequeue_partial_xfers(struct axi_dmac_chan *chan)
+{
+       struct axi_dmac *dmac = chan_to_axi_dmac(chan);
+       struct axi_dmac_desc *desc;
+       struct axi_dmac_sg *sg;
+       u32 xfer_done, len, id, i;
+       bool found_sg;
+
+       do {
+               len = axi_dmac_read(dmac, AXI_DMAC_REG_PARTIAL_XFER_LEN);
+               id  = axi_dmac_read(dmac, AXI_DMAC_REG_PARTIAL_XFER_ID);
+
+               found_sg = false;
+               list_for_each_entry(desc, &chan->active_descs, vdesc.node) {
+                       for (i = 0; i < desc->num_sgs; i++) {
+                               sg = &desc->sg[i];
+                               if (sg->id == AXI_DMAC_SG_UNUSED)
+                                       continue;
+                               if (sg->id == id) {
+                                       desc->have_partial_xfer = true;
+                                       sg->partial_len = len;
+                                       found_sg = true;
+                                       break;
+                               }
+                       }
+                       if (found_sg)
+                               break;
+               }
+
+               if (found_sg) {
+                       dev_dbg(dmac->dma_dev.dev,
+                               "Found partial segment id=%u, len=%u\n",
+                               id, len);
+               } else {
+                       dev_warn(dmac->dma_dev.dev,
+                                "Not found partial segment id=%u, len=%u\n",
+                                id, len);
+               }
+
+               /* Check if we have any more partial transfers */
+               xfer_done = axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_DONE);
+               xfer_done = !(xfer_done & AXI_DMAC_FLAG_PARTIAL_XFER_DONE);
+
+       } while (!xfer_done);
+}
+
+static void axi_dmac_compute_residue(struct axi_dmac_chan *chan,
+       struct axi_dmac_desc *active)
+{
+       struct dmaengine_result *rslt = &active->vdesc.tx_result;
+       unsigned int start = active->num_completed - 1;
+       struct axi_dmac_sg *sg;
+       unsigned int i, total;
+
+       rslt->result = DMA_TRANS_NOERROR;
+       rslt->residue = 0;
+
+       /*
+        * We get here if the last completed segment is partial, which
+        * means we can compute the residue from that segment onwards
+        */
+       for (i = start; i < active->num_sgs; i++) {
+               sg = &active->sg[i];
+               total = axi_dmac_total_sg_bytes(chan, sg);
+               rslt->residue += (total - sg->partial_len);
+       }
+}
+
 static bool axi_dmac_transfer_done(struct axi_dmac_chan *chan,
        unsigned int completed_transfers)
 {
@@ -263,6 +357,10 @@ static bool axi_dmac_transfer_done(struct axi_dmac_chan *chan,
        if (!active)
                return false;
 
+       if (chan->hw_partial_xfer &&
+           (completed_transfers & AXI_DMAC_FLAG_PARTIAL_XFER_DONE))
+               axi_dmac_dequeue_partial_xfers(chan);
+
        do {
                sg = &active->sg[active->num_completed];
                if (sg->id == AXI_DMAC_SG_UNUSED) /* Not yet submitted */
@@ -276,10 +374,14 @@ static bool axi_dmac_transfer_done(struct axi_dmac_chan *chan,
                        start_next = true;
                }
 
+               if (sg->partial_len)
+                       axi_dmac_compute_residue(chan, active);
+
                if (active->cyclic)
                        vchan_cyclic_callback(&active->vdesc);
 
-               if (active->num_completed == active->num_sgs) {
+               if (active->num_completed == active->num_sgs ||
+                   sg->partial_len) {
                        if (active->cyclic) {
                                active->num_completed = 0; /* wrap around */
                        } else {
@@ -391,7 +493,7 @@ static struct axi_dmac_sg *axi_dmac_fill_linear_sg(struct axi_dmac_chan *chan,
        num_segments = DIV_ROUND_UP(period_len, chan->max_length);
        segment_size = DIV_ROUND_UP(period_len, num_segments);
        /* Take care of alignment */
-       segment_size = ((segment_size - 1) | chan->align_mask) + 1;
+       segment_size = ((segment_size - 1) | chan->length_align_mask) + 1;
 
        for (i = 0; i < num_periods; i++) {
                len = period_len;
@@ -561,6 +663,9 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_interleaved(
                desc->sg[0].y_len = 1;
        }
 
+       if (flags & DMA_CYCLIC)
+               desc->cyclic = true;
+
        return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
 }
 
@@ -574,6 +679,44 @@ static void axi_dmac_desc_free(struct virt_dma_desc *vdesc)
        kfree(container_of(vdesc, struct axi_dmac_desc, vdesc));
 }
 
+static bool axi_dmac_regmap_rdwr(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case AXI_DMAC_REG_IRQ_MASK:
+       case AXI_DMAC_REG_IRQ_SOURCE:
+       case AXI_DMAC_REG_IRQ_PENDING:
+       case AXI_DMAC_REG_CTRL:
+       case AXI_DMAC_REG_TRANSFER_ID:
+       case AXI_DMAC_REG_START_TRANSFER:
+       case AXI_DMAC_REG_FLAGS:
+       case AXI_DMAC_REG_DEST_ADDRESS:
+       case AXI_DMAC_REG_SRC_ADDRESS:
+       case AXI_DMAC_REG_X_LENGTH:
+       case AXI_DMAC_REG_Y_LENGTH:
+       case AXI_DMAC_REG_DEST_STRIDE:
+       case AXI_DMAC_REG_SRC_STRIDE:
+       case AXI_DMAC_REG_TRANSFER_DONE:
+       case AXI_DMAC_REG_ACTIVE_TRANSFER_ID:
+       case AXI_DMAC_REG_STATUS:
+       case AXI_DMAC_REG_CURRENT_SRC_ADDR:
+       case AXI_DMAC_REG_CURRENT_DEST_ADDR:
+       case AXI_DMAC_REG_PARTIAL_XFER_LEN:
+       case AXI_DMAC_REG_PARTIAL_XFER_ID:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const struct regmap_config axi_dmac_regmap_config = {
+       .reg_bits = 32,
+       .val_bits = 32,
+       .reg_stride = 4,
+       .max_register = AXI_DMAC_REG_PARTIAL_XFER_ID,
+       .readable_reg = axi_dmac_regmap_rdwr,
+       .writeable_reg = axi_dmac_regmap_rdwr,
+};
+
 /*
  * The configuration stored in the devicetree matches the configuration
  * parameters of the peripheral instance and allows the driver to know which
@@ -617,7 +760,7 @@ static int axi_dmac_parse_chan_dt(struct device_node *of_chan,
                return ret;
        chan->dest_width = val / 8;
 
-       chan->align_mask = max(chan->dest_width, chan->src_width) - 1;
+       chan->address_align_mask = max(chan->dest_width, chan->src_width) - 1;
 
        if (axi_dmac_dest_is_mem(chan) && axi_dmac_src_is_mem(chan))
                chan->direction = DMA_MEM_TO_MEM;
@@ -631,9 +774,12 @@ static int axi_dmac_parse_chan_dt(struct device_node *of_chan,
        return 0;
 }
 
-static void axi_dmac_detect_caps(struct axi_dmac *dmac)
+static int axi_dmac_detect_caps(struct axi_dmac *dmac)
 {
        struct axi_dmac_chan *chan = &dmac->chan;
+       unsigned int version;
+
+       version = axi_dmac_read(dmac, ADI_AXI_REG_VERSION);
 
        axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, AXI_DMAC_FLAG_CYCLIC);
        if (axi_dmac_read(dmac, AXI_DMAC_REG_FLAGS) == AXI_DMAC_FLAG_CYCLIC)
@@ -647,6 +793,35 @@ static void axi_dmac_detect_caps(struct axi_dmac *dmac)
        chan->max_length = axi_dmac_read(dmac, AXI_DMAC_REG_X_LENGTH);
        if (chan->max_length != UINT_MAX)
                chan->max_length++;
+
+       axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS, 0xffffffff);
+       if (axi_dmac_read(dmac, AXI_DMAC_REG_DEST_ADDRESS) == 0 &&
+           chan->dest_type == AXI_DMAC_BUS_TYPE_AXI_MM) {
+               dev_err(dmac->dma_dev.dev,
+                       "Destination memory-mapped interface not supported.");
+               return -ENODEV;
+       }
+
+       axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS, 0xffffffff);
+       if (axi_dmac_read(dmac, AXI_DMAC_REG_SRC_ADDRESS) == 0 &&
+           chan->src_type == AXI_DMAC_BUS_TYPE_AXI_MM) {
+               dev_err(dmac->dma_dev.dev,
+                       "Source memory-mapped interface not supported.");
+               return -ENODEV;
+       }
+
+       if (version >= ADI_AXI_PCORE_VER(4, 2, 'a'))
+               chan->hw_partial_xfer = true;
+
+       if (version >= ADI_AXI_PCORE_VER(4, 1, 'a')) {
+               axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, 0x00);
+               chan->length_align_mask =
+                       axi_dmac_read(dmac, AXI_DMAC_REG_X_LENGTH);
+       } else {
+               chan->length_align_mask = chan->address_align_mask;
+       }
+
+       return 0;
 }
 
 static int axi_dmac_probe(struct platform_device *pdev)
@@ -722,7 +897,11 @@ static int axi_dmac_probe(struct platform_device *pdev)
        if (ret < 0)
                return ret;
 
-       axi_dmac_detect_caps(dmac);
+       ret = axi_dmac_detect_caps(dmac);
+       if (ret)
+               goto err_clk_disable;
+
+       dma_dev->copy_align = (dmac->chan.address_align_mask + 1);
 
        axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_MASK, 0x00);
 
@@ -742,6 +921,8 @@ static int axi_dmac_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, dmac);
 
+       devm_regmap_init_mmio(&pdev->dev, dmac->base, &axi_dmac_regmap_config);
+
        return 0;
 
 err_unregister_of:
index 6b8c4c4..7fe9309 100644 (file)
@@ -156,7 +156,6 @@ struct jz4780_dma_dev {
 };
 
 struct jz4780_dma_filter_data {
-       struct device_node *of_node;
        uint32_t transfer_type;
        int channel;
 };
@@ -772,8 +771,6 @@ static bool jz4780_dma_filter_fn(struct dma_chan *chan, void *param)
        struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan);
        struct jz4780_dma_filter_data *data = param;
 
-       if (jzdma->dma_device.dev->of_node != data->of_node)
-               return false;
 
        if (data->channel > -1) {
                if (data->channel != jzchan->id)
@@ -797,7 +794,6 @@ static struct dma_chan *jz4780_of_dma_xlate(struct of_phandle_args *dma_spec,
        if (dma_spec->args_count != 2)
                return NULL;
 
-       data.of_node = ofdma->of_node;
        data.transfer_type = dma_spec->args[0];
        data.channel = dma_spec->args[1];
 
@@ -822,7 +818,8 @@ static struct dma_chan *jz4780_of_dma_xlate(struct of_phandle_args *dma_spec,
                return dma_get_slave_channel(
                        &jzdma->chan[data.channel].vchan.chan);
        } else {
-               return dma_request_channel(mask, jz4780_dma_filter_fn, &data);
+               return __dma_request_channel(&mask, jz4780_dma_filter_fn, &data,
+                                            ofdma->of_node);
        }
 }
 
index 58cbf9f..03ac4b9 100644 (file)
@@ -61,7 +61,7 @@ static long dmaengine_ref_count;
 /* --- sysfs implementation --- */
 
 /**
- * dev_to_dma_chan - convert a device pointer to the its sysfs container object
+ * dev_to_dma_chan - convert a device pointer to its sysfs container object
  * @dev - device node
  *
  * Must be called under dma_list_mutex
@@ -629,11 +629,13 @@ EXPORT_SYMBOL_GPL(dma_get_any_slave_channel);
  * @mask: capabilities that the channel must satisfy
  * @fn: optional callback to disposition available channels
  * @fn_param: opaque parameter to pass to dma_filter_fn
+ * @np: device node to look for DMA channels
  *
  * Returns pointer to appropriate DMA channel on success or NULL.
  */
 struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
-                                      dma_filter_fn fn, void *fn_param)
+                                      dma_filter_fn fn, void *fn_param,
+                                      struct device_node *np)
 {
        struct dma_device *device, *_d;
        struct dma_chan *chan = NULL;
@@ -641,6 +643,10 @@ struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
        /* Find a channel */
        mutex_lock(&dma_list_mutex);
        list_for_each_entry_safe(device, _d, &dma_device_list, global_node) {
+               /* Finds a DMA controller with matching device node */
+               if (np && device->dev->of_node && np != device->dev->of_node)
+                       continue;
+
                chan = find_candidate(device, mask, fn, fn_param);
                if (!IS_ERR(chan))
                        break;
@@ -699,7 +705,7 @@ struct dma_chan *dma_request_chan(struct device *dev, const char *name)
                chan = acpi_dma_request_slave_chan_by_name(dev, name);
 
        if (chan) {
-               /* Valid channel found or requester need to be deferred */
+               /* Valid channel found or requester needs to be deferred */
                if (!IS_ERR(chan) || PTR_ERR(chan) == -EPROBE_DEFER)
                        return chan;
        }
@@ -757,7 +763,7 @@ struct dma_chan *dma_request_chan_by_mask(const dma_cap_mask_t *mask)
        if (!mask)
                return ERR_PTR(-ENODEV);
 
-       chan = __dma_request_channel(mask, NULL, NULL);
+       chan = __dma_request_channel(mask, NULL, NULL, NULL);
        if (!chan) {
                mutex_lock(&dma_list_mutex);
                if (list_empty(&dma_device_list))
index d0ad46e..3d22ae8 100644 (file)
@@ -62,7 +62,7 @@ MODULE_PARM_DESC(pq_sources,
 static int timeout = 3000;
 module_param(timeout, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), "
-                "Pass -1 for infinite timeout");
+                "Pass 0xFFFFFFFF (4294967295) for maximum timeout");
 
 static bool noverify;
 module_param(noverify, bool, S_IRUGO | S_IWUSR);
@@ -94,7 +94,7 @@ MODULE_PARM_DESC(transfer_size, "Optional custom transfer size in bytes (default
  * @iterations:                iterations before stopping test
  * @xor_sources:       number of xor source buffers
  * @pq_sources:                number of p+q source buffers
- * @timeout:           transfer timeout in msec, -1 for infinite timeout
+ * @timeout:           transfer timeout in msec, 0 - 0xFFFFFFFF (4294967295)
  */
 struct dmatest_params {
        unsigned int    buf_size;
@@ -105,7 +105,7 @@ struct dmatest_params {
        unsigned int    iterations;
        unsigned int    xor_sources;
        unsigned int    pq_sources;
-       int             timeout;
+       unsigned int    timeout;
        bool            noverify;
        bool            norandom;
        int             alignment;
diff --git a/drivers/dma/dw-edma/Kconfig b/drivers/dma/dw-edma/Kconfig
new file mode 100644 (file)
index 0000000..7ff17b2
--- /dev/null
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config DW_EDMA
+       tristate "Synopsys DesignWare eDMA controller driver"
+       depends on PCI && PCI_MSI
+       select DMA_ENGINE
+       select DMA_VIRTUAL_CHANNELS
+       help
+         Support the Synopsys DesignWare eDMA controller, normally
+         implemented on endpoints SoCs.
+
+config DW_EDMA_PCIE
+       tristate "Synopsys DesignWare eDMA PCIe driver"
+       depends on PCI && PCI_MSI
+       select DW_EDMA
+       help
+         Provides a glue-logic between the Synopsys DesignWare
+         eDMA controller and an endpoint PCIe device. This also serves
+         as a reference design to whom desires to use this IP.
diff --git a/drivers/dma/dw-edma/Makefile b/drivers/dma/dw-edma/Makefile
new file mode 100644 (file)
index 0000000..8d45c0d
--- /dev/null
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_DW_EDMA)          += dw-edma.o
+dw-edma-$(CONFIG_DEBUG_FS)     := dw-edma-v0-debugfs.o
+dw-edma-objs                   := dw-edma-core.o \
+                                       dw-edma-v0-core.o $(dw-edma-y)
+obj-$(CONFIG_DW_EDMA_PCIE)     += dw-edma-pcie.o
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
new file mode 100644 (file)
index 0000000..ff392c0
--- /dev/null
@@ -0,0 +1,937 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
+ * Synopsys DesignWare eDMA core driver
+ *
+ * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/pm_runtime.h>
+#include <linux/dmaengine.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/dma/edma.h>
+#include <linux/pci.h>
+
+#include "dw-edma-core.h"
+#include "dw-edma-v0-core.h"
+#include "../dmaengine.h"
+#include "../virt-dma.h"
+
+static inline
+struct device *dchan2dev(struct dma_chan *dchan)
+{
+       return &dchan->dev->device;
+}
+
+static inline
+struct device *chan2dev(struct dw_edma_chan *chan)
+{
+       return &chan->vc.chan.dev->device;
+}
+
+static inline
+struct dw_edma_desc *vd2dw_edma_desc(struct virt_dma_desc *vd)
+{
+       return container_of(vd, struct dw_edma_desc, vd);
+}
+
+static struct dw_edma_burst *dw_edma_alloc_burst(struct dw_edma_chunk *chunk)
+{
+       struct dw_edma_burst *burst;
+
+       burst = kzalloc(sizeof(*burst), GFP_NOWAIT);
+       if (unlikely(!burst))
+               return NULL;
+
+       INIT_LIST_HEAD(&burst->list);
+       if (chunk->burst) {
+               /* Create and add new element into the linked list */
+               chunk->bursts_alloc++;
+               list_add_tail(&burst->list, &chunk->burst->list);
+       } else {
+               /* List head */
+               chunk->bursts_alloc = 0;
+               chunk->burst = burst;
+       }
+
+       return burst;
+}
+
+static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc)
+{
+       struct dw_edma_chan *chan = desc->chan;
+       struct dw_edma *dw = chan->chip->dw;
+       struct dw_edma_chunk *chunk;
+
+       chunk = kzalloc(sizeof(*chunk), GFP_NOWAIT);
+       if (unlikely(!chunk))
+               return NULL;
+
+       INIT_LIST_HEAD(&chunk->list);
+       chunk->chan = chan;
+       /* Toggling change bit (CB) in each chunk, this is a mechanism to
+        * inform the eDMA HW block that this is a new linked list ready
+        * to be consumed.
+        *  - Odd chunks originate CB equal to 0
+        *  - Even chunks originate CB equal to 1
+        */
+       chunk->cb = !(desc->chunks_alloc % 2);
+       chunk->ll_region.paddr = dw->ll_region.paddr + chan->ll_off;
+       chunk->ll_region.vaddr = dw->ll_region.vaddr + chan->ll_off;
+
+       if (desc->chunk) {
+               /* Create and add new element into the linked list */
+               desc->chunks_alloc++;
+               list_add_tail(&chunk->list, &desc->chunk->list);
+               if (!dw_edma_alloc_burst(chunk)) {
+                       kfree(chunk);
+                       return NULL;
+               }
+       } else {
+               /* List head */
+               chunk->burst = NULL;
+               desc->chunks_alloc = 0;
+               desc->chunk = chunk;
+       }
+
+       return chunk;
+}
+
+static struct dw_edma_desc *dw_edma_alloc_desc(struct dw_edma_chan *chan)
+{
+       struct dw_edma_desc *desc;
+
+       desc = kzalloc(sizeof(*desc), GFP_NOWAIT);
+       if (unlikely(!desc))
+               return NULL;
+
+       desc->chan = chan;
+       if (!dw_edma_alloc_chunk(desc)) {
+               kfree(desc);
+               return NULL;
+       }
+
+       return desc;
+}
+
+static void dw_edma_free_burst(struct dw_edma_chunk *chunk)
+{
+       struct dw_edma_burst *child, *_next;
+
+       /* Remove all the list elements */
+       list_for_each_entry_safe(child, _next, &chunk->burst->list, list) {
+               list_del(&child->list);
+               kfree(child);
+               chunk->bursts_alloc--;
+       }
+
+       /* Remove the list head */
+       kfree(child);
+       chunk->burst = NULL;
+}
+
+static void dw_edma_free_chunk(struct dw_edma_desc *desc)
+{
+       struct dw_edma_chunk *child, *_next;
+
+       if (!desc->chunk)
+               return;
+
+       /* Remove all the list elements */
+       list_for_each_entry_safe(child, _next, &desc->chunk->list, list) {
+               dw_edma_free_burst(child);
+               list_del(&child->list);
+               kfree(child);
+               desc->chunks_alloc--;
+       }
+
+       /* Remove the list head */
+       kfree(child);
+       desc->chunk = NULL;
+}
+
+static void dw_edma_free_desc(struct dw_edma_desc *desc)
+{
+       dw_edma_free_chunk(desc);
+       kfree(desc);
+}
+
+static void vchan_free_desc(struct virt_dma_desc *vdesc)
+{
+       dw_edma_free_desc(vd2dw_edma_desc(vdesc));
+}
+
+static void dw_edma_start_transfer(struct dw_edma_chan *chan)
+{
+       struct dw_edma_chunk *child;
+       struct dw_edma_desc *desc;
+       struct virt_dma_desc *vd;
+
+       vd = vchan_next_desc(&chan->vc);
+       if (!vd)
+               return;
+
+       desc = vd2dw_edma_desc(vd);
+       if (!desc)
+               return;
+
+       child = list_first_entry_or_null(&desc->chunk->list,
+                                        struct dw_edma_chunk, list);
+       if (!child)
+               return;
+
+       dw_edma_v0_core_start(child, !desc->xfer_sz);
+       desc->xfer_sz += child->ll_region.sz;
+       dw_edma_free_burst(child);
+       list_del(&child->list);
+       kfree(child);
+       desc->chunks_alloc--;
+}
+
+static int dw_edma_device_config(struct dma_chan *dchan,
+                                struct dma_slave_config *config)
+{
+       struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+
+       memcpy(&chan->config, config, sizeof(*config));
+       chan->configured = true;
+
+       return 0;
+}
+
+static int dw_edma_device_pause(struct dma_chan *dchan)
+{
+       struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+       int err = 0;
+
+       if (!chan->configured)
+               err = -EPERM;
+       else if (chan->status != EDMA_ST_BUSY)
+               err = -EPERM;
+       else if (chan->request != EDMA_REQ_NONE)
+               err = -EPERM;
+       else
+               chan->request = EDMA_REQ_PAUSE;
+
+       return err;
+}
+
+static int dw_edma_device_resume(struct dma_chan *dchan)
+{
+       struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+       int err = 0;
+
+       if (!chan->configured) {
+               err = -EPERM;
+       } else if (chan->status != EDMA_ST_PAUSE) {
+               err = -EPERM;
+       } else if (chan->request != EDMA_REQ_NONE) {
+               err = -EPERM;
+       } else {
+               chan->status = EDMA_ST_BUSY;
+               dw_edma_start_transfer(chan);
+       }
+
+       return err;
+}
+
+static int dw_edma_device_terminate_all(struct dma_chan *dchan)
+{
+       struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+       int err = 0;
+       LIST_HEAD(head);
+
+       if (!chan->configured) {
+               /* Do nothing */
+       } else if (chan->status == EDMA_ST_PAUSE) {
+               chan->status = EDMA_ST_IDLE;
+               chan->configured = false;
+       } else if (chan->status == EDMA_ST_IDLE) {
+               chan->configured = false;
+       } else if (dw_edma_v0_core_ch_status(chan) == DMA_COMPLETE) {
+               /*
+                * The channel is in a false BUSY state, probably didn't
+                * receive or lost an interrupt
+                */
+               chan->status = EDMA_ST_IDLE;
+               chan->configured = false;
+       } else if (chan->request > EDMA_REQ_PAUSE) {
+               err = -EPERM;
+       } else {
+               chan->request = EDMA_REQ_STOP;
+       }
+
+       return err;
+}
+
+static void dw_edma_device_issue_pending(struct dma_chan *dchan)
+{
+       struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+       unsigned long flags;
+
+       spin_lock_irqsave(&chan->vc.lock, flags);
+       if (chan->configured && chan->request == EDMA_REQ_NONE &&
+           chan->status == EDMA_ST_IDLE && vchan_issue_pending(&chan->vc)) {
+               chan->status = EDMA_ST_BUSY;
+               dw_edma_start_transfer(chan);
+       }
+       spin_unlock_irqrestore(&chan->vc.lock, flags);
+}
+
+static enum dma_status
+dw_edma_device_tx_status(struct dma_chan *dchan, dma_cookie_t cookie,
+                        struct dma_tx_state *txstate)
+{
+       struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+       struct dw_edma_desc *desc;
+       struct virt_dma_desc *vd;
+       unsigned long flags;
+       enum dma_status ret;
+       u32 residue = 0;
+
+       ret = dma_cookie_status(dchan, cookie, txstate);
+       if (ret == DMA_COMPLETE)
+               return ret;
+
+       if (ret == DMA_IN_PROGRESS && chan->status == EDMA_ST_PAUSE)
+               ret = DMA_PAUSED;
+
+       if (!txstate)
+               goto ret_residue;
+
+       spin_lock_irqsave(&chan->vc.lock, flags);
+       vd = vchan_find_desc(&chan->vc, cookie);
+       if (vd) {
+               desc = vd2dw_edma_desc(vd);
+               if (desc)
+                       residue = desc->alloc_sz - desc->xfer_sz;
+       }
+       spin_unlock_irqrestore(&chan->vc.lock, flags);
+
+ret_residue:
+       dma_set_residue(txstate, residue);
+
+       return ret;
+}
+
+static struct dma_async_tx_descriptor *
+dw_edma_device_transfer(struct dw_edma_transfer *xfer)
+{
+       struct dw_edma_chan *chan = dchan2dw_edma_chan(xfer->dchan);
+       enum dma_transfer_direction direction = xfer->direction;
+       phys_addr_t src_addr, dst_addr;
+       struct scatterlist *sg = NULL;
+       struct dw_edma_chunk *chunk;
+       struct dw_edma_burst *burst;
+       struct dw_edma_desc *desc;
+       u32 cnt;
+       int i;
+
+       if ((direction == DMA_MEM_TO_DEV && chan->dir == EDMA_DIR_WRITE) ||
+           (direction == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ))
+               return NULL;
+
+       if (xfer->cyclic) {
+               if (!xfer->xfer.cyclic.len || !xfer->xfer.cyclic.cnt)
+                       return NULL;
+       } else {
+               if (xfer->xfer.sg.len < 1)
+                       return NULL;
+       }
+
+       if (!chan->configured)
+               return NULL;
+
+       desc = dw_edma_alloc_desc(chan);
+       if (unlikely(!desc))
+               goto err_alloc;
+
+       chunk = dw_edma_alloc_chunk(desc);
+       if (unlikely(!chunk))
+               goto err_alloc;
+
+       src_addr = chan->config.src_addr;
+       dst_addr = chan->config.dst_addr;
+
+       if (xfer->cyclic) {
+               cnt = xfer->xfer.cyclic.cnt;
+       } else {
+               cnt = xfer->xfer.sg.len;
+               sg = xfer->xfer.sg.sgl;
+       }
+
+       for (i = 0; i < cnt; i++) {
+               if (!xfer->cyclic && !sg)
+                       break;
+
+               if (chunk->bursts_alloc == chan->ll_max) {
+                       chunk = dw_edma_alloc_chunk(desc);
+                       if (unlikely(!chunk))
+                               goto err_alloc;
+               }
+
+               burst = dw_edma_alloc_burst(chunk);
+               if (unlikely(!burst))
+                       goto err_alloc;
+
+               if (xfer->cyclic)
+                       burst->sz = xfer->xfer.cyclic.len;
+               else
+                       burst->sz = sg_dma_len(sg);
+
+               chunk->ll_region.sz += burst->sz;
+               desc->alloc_sz += burst->sz;
+
+               if (direction == DMA_DEV_TO_MEM) {
+                       burst->sar = src_addr;
+                       if (xfer->cyclic) {
+                               burst->dar = xfer->xfer.cyclic.paddr;
+                       } else {
+                               burst->dar = sg_dma_address(sg);
+                               /* Unlike the typical assumption by other
+                                * drivers/IPs the peripheral memory isn't
+                                * a FIFO memory, in this case, it's a
+                                * linear memory and that why the source
+                                * and destination addresses are increased
+                                * by the same portion (data length)
+                                */
+                               src_addr += sg_dma_len(sg);
+                       }
+               } else {
+                       burst->dar = dst_addr;
+                       if (xfer->cyclic) {
+                               burst->sar = xfer->xfer.cyclic.paddr;
+                       } else {
+                               burst->sar = sg_dma_address(sg);
+                               /* Unlike the typical assumption by other
+                                * drivers/IPs the peripheral memory isn't
+                                * a FIFO memory, in this case, it's a
+                                * linear memory and that why the source
+                                * and destination addresses are increased
+                                * by the same portion (data length)
+                                */
+                               dst_addr += sg_dma_len(sg);
+                       }
+               }
+
+               if (!xfer->cyclic)
+                       sg = sg_next(sg);
+       }
+
+       return vchan_tx_prep(&chan->vc, &desc->vd, xfer->flags);
+
+err_alloc:
+       if (desc)
+               dw_edma_free_desc(desc);
+
+       return NULL;
+}
+
+static struct dma_async_tx_descriptor *
+dw_edma_device_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
+                            unsigned int len,
+                            enum dma_transfer_direction direction,
+                            unsigned long flags, void *context)
+{
+       struct dw_edma_transfer xfer;
+
+       xfer.dchan = dchan;
+       xfer.direction = direction;
+       xfer.xfer.sg.sgl = sgl;
+       xfer.xfer.sg.len = len;
+       xfer.flags = flags;
+       xfer.cyclic = false;
+
+       return dw_edma_device_transfer(&xfer);
+}
+
+static struct dma_async_tx_descriptor *
+dw_edma_device_prep_dma_cyclic(struct dma_chan *dchan, dma_addr_t paddr,
+                              size_t len, size_t count,
+                              enum dma_transfer_direction direction,
+                              unsigned long flags)
+{
+       struct dw_edma_transfer xfer;
+
+       xfer.dchan = dchan;
+       xfer.direction = direction;
+       xfer.xfer.cyclic.paddr = paddr;
+       xfer.xfer.cyclic.len = len;
+       xfer.xfer.cyclic.cnt = count;
+       xfer.flags = flags;
+       xfer.cyclic = true;
+
+       return dw_edma_device_transfer(&xfer);
+}
+
+static void dw_edma_done_interrupt(struct dw_edma_chan *chan)
+{
+       struct dw_edma_desc *desc;
+       struct virt_dma_desc *vd;
+       unsigned long flags;
+
+       dw_edma_v0_core_clear_done_int(chan);
+
+       spin_lock_irqsave(&chan->vc.lock, flags);
+       vd = vchan_next_desc(&chan->vc);
+       if (vd) {
+               switch (chan->request) {
+               case EDMA_REQ_NONE:
+                       desc = vd2dw_edma_desc(vd);
+                       if (desc->chunks_alloc) {
+                               chan->status = EDMA_ST_BUSY;
+                               dw_edma_start_transfer(chan);
+                       } else {
+                               list_del(&vd->node);
+                               vchan_cookie_complete(vd);
+                               chan->status = EDMA_ST_IDLE;
+                       }
+                       break;
+
+               case EDMA_REQ_STOP:
+                       list_del(&vd->node);
+                       vchan_cookie_complete(vd);
+                       chan->request = EDMA_REQ_NONE;
+                       chan->status = EDMA_ST_IDLE;
+                       break;
+
+               case EDMA_REQ_PAUSE:
+                       chan->request = EDMA_REQ_NONE;
+                       chan->status = EDMA_ST_PAUSE;
+                       break;
+
+               default:
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&chan->vc.lock, flags);
+}
+
+static void dw_edma_abort_interrupt(struct dw_edma_chan *chan)
+{
+       struct virt_dma_desc *vd;
+       unsigned long flags;
+
+       dw_edma_v0_core_clear_abort_int(chan);
+
+       spin_lock_irqsave(&chan->vc.lock, flags);
+       vd = vchan_next_desc(&chan->vc);
+       if (vd) {
+               list_del(&vd->node);
+               vchan_cookie_complete(vd);
+       }
+       spin_unlock_irqrestore(&chan->vc.lock, flags);
+       chan->request = EDMA_REQ_NONE;
+       chan->status = EDMA_ST_IDLE;
+}
+
+static irqreturn_t dw_edma_interrupt(int irq, void *data, bool write)
+{
+       struct dw_edma_irq *dw_irq = data;
+       struct dw_edma *dw = dw_irq->dw;
+       unsigned long total, pos, val;
+       unsigned long off;
+       u32 mask;
+
+       if (write) {
+               total = dw->wr_ch_cnt;
+               off = 0;
+               mask = dw_irq->wr_mask;
+       } else {
+               total = dw->rd_ch_cnt;
+               off = dw->wr_ch_cnt;
+               mask = dw_irq->rd_mask;
+       }
+
+       val = dw_edma_v0_core_status_done_int(dw, write ?
+                                                         EDMA_DIR_WRITE :
+                                                         EDMA_DIR_READ);
+       val &= mask;
+       for_each_set_bit(pos, &val, total) {
+               struct dw_edma_chan *chan = &dw->chan[pos + off];
+
+               dw_edma_done_interrupt(chan);
+       }
+
+       val = dw_edma_v0_core_status_abort_int(dw, write ?
+                                                          EDMA_DIR_WRITE :
+                                                          EDMA_DIR_READ);
+       val &= mask;
+       for_each_set_bit(pos, &val, total) {
+               struct dw_edma_chan *chan = &dw->chan[pos + off];
+
+               dw_edma_abort_interrupt(chan);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static inline irqreturn_t dw_edma_interrupt_write(int irq, void *data)
+{
+       return dw_edma_interrupt(irq, data, true);
+}
+
+static inline irqreturn_t dw_edma_interrupt_read(int irq, void *data)
+{
+       return dw_edma_interrupt(irq, data, false);
+}
+
+static irqreturn_t dw_edma_interrupt_common(int irq, void *data)
+{
+       dw_edma_interrupt(irq, data, true);
+       dw_edma_interrupt(irq, data, false);
+
+       return IRQ_HANDLED;
+}
+
+static int dw_edma_alloc_chan_resources(struct dma_chan *dchan)
+{
+       struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+
+       if (chan->status != EDMA_ST_IDLE)
+               return -EBUSY;
+
+       pm_runtime_get(chan->chip->dev);
+
+       return 0;
+}
+
+static void dw_edma_free_chan_resources(struct dma_chan *dchan)
+{
+       unsigned long timeout = jiffies + msecs_to_jiffies(5000);
+       struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+       int ret;
+
+       while (time_before(jiffies, timeout)) {
+               ret = dw_edma_device_terminate_all(dchan);
+               if (!ret)
+                       break;
+
+               if (time_after_eq(jiffies, timeout))
+                       return;
+
+               cpu_relax();
+       }
+
+       pm_runtime_put(chan->chip->dev);
+}
+
+static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
+                                u32 wr_alloc, u32 rd_alloc)
+{
+       struct dw_edma_region *dt_region;
+       struct device *dev = chip->dev;
+       struct dw_edma *dw = chip->dw;
+       struct dw_edma_chan *chan;
+       size_t ll_chunk, dt_chunk;
+       struct dw_edma_irq *irq;
+       struct dma_device *dma;
+       u32 i, j, cnt, ch_cnt;
+       u32 alloc, off_alloc;
+       int err = 0;
+       u32 pos;
+
+       ch_cnt = dw->wr_ch_cnt + dw->rd_ch_cnt;
+       ll_chunk = dw->ll_region.sz;
+       dt_chunk = dw->dt_region.sz;
+
+       /* Calculate linked list chunk for each channel */
+       ll_chunk /= roundup_pow_of_two(ch_cnt);
+
+       /* Calculate linked list chunk for each channel */
+       dt_chunk /= roundup_pow_of_two(ch_cnt);
+
+       if (write) {
+               i = 0;
+               cnt = dw->wr_ch_cnt;
+               dma = &dw->wr_edma;
+               alloc = wr_alloc;
+               off_alloc = 0;
+       } else {
+               i = dw->wr_ch_cnt;
+               cnt = dw->rd_ch_cnt;
+               dma = &dw->rd_edma;
+               alloc = rd_alloc;
+               off_alloc = wr_alloc;
+       }
+
+       INIT_LIST_HEAD(&dma->channels);
+       for (j = 0; (alloc || dw->nr_irqs == 1) && j < cnt; j++, i++) {
+               chan = &dw->chan[i];
+
+               dt_region = devm_kzalloc(dev, sizeof(*dt_region), GFP_KERNEL);
+               if (!dt_region)
+                       return -ENOMEM;
+
+               chan->vc.chan.private = dt_region;
+
+               chan->chip = chip;
+               chan->id = j;
+               chan->dir = write ? EDMA_DIR_WRITE : EDMA_DIR_READ;
+               chan->configured = false;
+               chan->request = EDMA_REQ_NONE;
+               chan->status = EDMA_ST_IDLE;
+
+               chan->ll_off = (ll_chunk * i);
+               chan->ll_max = (ll_chunk / EDMA_LL_SZ) - 1;
+
+               chan->dt_off = (dt_chunk * i);
+
+               dev_vdbg(dev, "L. List:\tChannel %s[%u] off=0x%.8lx, max_cnt=%u\n",
+                        write ? "write" : "read", j,
+                        chan->ll_off, chan->ll_max);
+
+               if (dw->nr_irqs == 1)
+                       pos = 0;
+               else
+                       pos = off_alloc + (j % alloc);
+
+               irq = &dw->irq[pos];
+
+               if (write)
+                       irq->wr_mask |= BIT(j);
+               else
+                       irq->rd_mask |= BIT(j);
+
+               irq->dw = dw;
+               memcpy(&chan->msi, &irq->msi, sizeof(chan->msi));
+
+               dev_vdbg(dev, "MSI:\t\tChannel %s[%u] addr=0x%.8x%.8x, data=0x%.8x\n",
+                        write ? "write" : "read", j,
+                        chan->msi.address_hi, chan->msi.address_lo,
+                        chan->msi.data);
+
+               chan->vc.desc_free = vchan_free_desc;
+               vchan_init(&chan->vc, dma);
+
+               dt_region->paddr = dw->dt_region.paddr + chan->dt_off;
+               dt_region->vaddr = dw->dt_region.vaddr + chan->dt_off;
+               dt_region->sz = dt_chunk;
+
+               dev_vdbg(dev, "Data:\tChannel %s[%u] off=0x%.8lx\n",
+                        write ? "write" : "read", j, chan->dt_off);
+
+               dw_edma_v0_core_device_config(chan);
+       }
+
+       /* Set DMA channel capabilities */
+       dma_cap_zero(dma->cap_mask);
+       dma_cap_set(DMA_SLAVE, dma->cap_mask);
+       dma_cap_set(DMA_CYCLIC, dma->cap_mask);
+       dma_cap_set(DMA_PRIVATE, dma->cap_mask);
+       dma->directions = BIT(write ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV);
+       dma->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+       dma->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+       dma->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
+       dma->chancnt = cnt;
+
+       /* Set DMA channel callbacks */
+       dma->dev = chip->dev;
+       dma->device_alloc_chan_resources = dw_edma_alloc_chan_resources;
+       dma->device_free_chan_resources = dw_edma_free_chan_resources;
+       dma->device_config = dw_edma_device_config;
+       dma->device_pause = dw_edma_device_pause;
+       dma->device_resume = dw_edma_device_resume;
+       dma->device_terminate_all = dw_edma_device_terminate_all;
+       dma->device_issue_pending = dw_edma_device_issue_pending;
+       dma->device_tx_status = dw_edma_device_tx_status;
+       dma->device_prep_slave_sg = dw_edma_device_prep_slave_sg;
+       dma->device_prep_dma_cyclic = dw_edma_device_prep_dma_cyclic;
+
+       dma_set_max_seg_size(dma->dev, U32_MAX);
+
+       /* Register DMA device */
+       err = dma_async_device_register(dma);
+
+       return err;
+}
+
+static inline void dw_edma_dec_irq_alloc(int *nr_irqs, u32 *alloc, u16 cnt)
+{
+       if (*nr_irqs && *alloc < cnt) {
+               (*alloc)++;
+               (*nr_irqs)--;
+       }
+}
+
+static inline void dw_edma_add_irq_mask(u32 *mask, u32 alloc, u16 cnt)
+{
+       while (*mask * alloc < cnt)
+               (*mask)++;
+}
+
+static int dw_edma_irq_request(struct dw_edma_chip *chip,
+                              u32 *wr_alloc, u32 *rd_alloc)
+{
+       struct device *dev = chip->dev;
+       struct dw_edma *dw = chip->dw;
+       u32 wr_mask = 1;
+       u32 rd_mask = 1;
+       int i, err = 0;
+       u32 ch_cnt;
+
+       ch_cnt = dw->wr_ch_cnt + dw->rd_ch_cnt;
+
+       if (dw->nr_irqs < 1)
+               return -EINVAL;
+
+       if (dw->nr_irqs == 1) {
+               /* Common IRQ shared among all channels */
+               err = request_irq(pci_irq_vector(to_pci_dev(dev), 0),
+                                 dw_edma_interrupt_common,
+                                 IRQF_SHARED, dw->name, &dw->irq[0]);
+               if (err) {
+                       dw->nr_irqs = 0;
+                       return err;
+               }
+
+               get_cached_msi_msg(pci_irq_vector(to_pci_dev(dev), 0),
+                                  &dw->irq[0].msi);
+       } else {
+               /* Distribute IRQs equally among all channels */
+               int tmp = dw->nr_irqs;
+
+               while (tmp && (*wr_alloc + *rd_alloc) < ch_cnt) {
+                       dw_edma_dec_irq_alloc(&tmp, wr_alloc, dw->wr_ch_cnt);
+                       dw_edma_dec_irq_alloc(&tmp, rd_alloc, dw->rd_ch_cnt);
+               }
+
+               dw_edma_add_irq_mask(&wr_mask, *wr_alloc, dw->wr_ch_cnt);
+               dw_edma_add_irq_mask(&rd_mask, *rd_alloc, dw->rd_ch_cnt);
+
+               for (i = 0; i < (*wr_alloc + *rd_alloc); i++) {
+                       err = request_irq(pci_irq_vector(to_pci_dev(dev), i),
+                                         i < *wr_alloc ?
+                                               dw_edma_interrupt_write :
+                                               dw_edma_interrupt_read,
+                                         IRQF_SHARED, dw->name,
+                                         &dw->irq[i]);
+                       if (err) {
+                               dw->nr_irqs = i;
+                               return err;
+                       }
+
+                       get_cached_msi_msg(pci_irq_vector(to_pci_dev(dev), i),
+                                          &dw->irq[i].msi);
+               }
+
+               dw->nr_irqs = i;
+       }
+
+       return err;
+}
+
+int dw_edma_probe(struct dw_edma_chip *chip)
+{
+       struct device *dev = chip->dev;
+       struct dw_edma *dw = chip->dw;
+       u32 wr_alloc = 0;
+       u32 rd_alloc = 0;
+       int i, err;
+
+       raw_spin_lock_init(&dw->lock);
+
+       /* Find out how many write channels are supported by hardware */
+       dw->wr_ch_cnt = dw_edma_v0_core_ch_count(dw, EDMA_DIR_WRITE);
+       if (!dw->wr_ch_cnt)
+               return -EINVAL;
+
+       /* Find out how many read channels are supported by hardware */
+       dw->rd_ch_cnt = dw_edma_v0_core_ch_count(dw, EDMA_DIR_READ);
+       if (!dw->rd_ch_cnt)
+               return -EINVAL;
+
+       dev_vdbg(dev, "Channels:\twrite=%d, read=%d\n",
+                dw->wr_ch_cnt, dw->rd_ch_cnt);
+
+       /* Allocate channels */
+       dw->chan = devm_kcalloc(dev, dw->wr_ch_cnt + dw->rd_ch_cnt,
+                               sizeof(*dw->chan), GFP_KERNEL);
+       if (!dw->chan)
+               return -ENOMEM;
+
+       snprintf(dw->name, sizeof(dw->name), "dw-edma-core:%d", chip->id);
+
+       /* Disable eDMA, only to establish the ideal initial conditions */
+       dw_edma_v0_core_off(dw);
+
+       /* Request IRQs */
+       err = dw_edma_irq_request(chip, &wr_alloc, &rd_alloc);
+       if (err)
+               return err;
+
+       /* Setup write channels */
+       err = dw_edma_channel_setup(chip, true, wr_alloc, rd_alloc);
+       if (err)
+               goto err_irq_free;
+
+       /* Setup read channels */
+       err = dw_edma_channel_setup(chip, false, wr_alloc, rd_alloc);
+       if (err)
+               goto err_irq_free;
+
+       /* Power management */
+       pm_runtime_enable(dev);
+
+       /* Turn debugfs on */
+       dw_edma_v0_core_debugfs_on(chip);
+
+       return 0;
+
+err_irq_free:
+       for (i = (dw->nr_irqs - 1); i >= 0; i--)
+               free_irq(pci_irq_vector(to_pci_dev(dev), i), &dw->irq[i]);
+
+       dw->nr_irqs = 0;
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(dw_edma_probe);
+
+int dw_edma_remove(struct dw_edma_chip *chip)
+{
+       struct dw_edma_chan *chan, *_chan;
+       struct device *dev = chip->dev;
+       struct dw_edma *dw = chip->dw;
+       int i;
+
+       /* Disable eDMA */
+       dw_edma_v0_core_off(dw);
+
+       /* Free irqs */
+       for (i = (dw->nr_irqs - 1); i >= 0; i--)
+               free_irq(pci_irq_vector(to_pci_dev(dev), i), &dw->irq[i]);
+
+       /* Power management */
+       pm_runtime_disable(dev);
+
+       list_for_each_entry_safe(chan, _chan, &dw->wr_edma.channels,
+                                vc.chan.device_node) {
+               list_del(&chan->vc.chan.device_node);
+               tasklet_kill(&chan->vc.task);
+       }
+
+       list_for_each_entry_safe(chan, _chan, &dw->rd_edma.channels,
+                                vc.chan.device_node) {
+               list_del(&chan->vc.chan.device_node);
+               tasklet_kill(&chan->vc.task);
+       }
+
+       /* Deregister eDMA device */
+       dma_async_device_unregister(&dw->wr_edma);
+       dma_async_device_unregister(&dw->rd_edma);
+
+       /* Turn debugfs off */
+       dw_edma_v0_core_debugfs_off();
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dw_edma_remove);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Synopsys DesignWare eDMA controller core driver");
+MODULE_AUTHOR("Gustavo Pimentel <gustavo.pimentel@synopsys.com>");
diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
new file mode 100644 (file)
index 0000000..b6cc90c
--- /dev/null
@@ -0,0 +1,165 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
+ * Synopsys DesignWare eDMA core driver
+ *
+ * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+ */
+
+#ifndef _DW_EDMA_CORE_H
+#define _DW_EDMA_CORE_H
+
+#include <linux/msi.h>
+#include <linux/dma/edma.h>
+
+#include "../virt-dma.h"
+
+#define EDMA_LL_SZ                                     24
+
+enum dw_edma_dir {
+       EDMA_DIR_WRITE = 0,
+       EDMA_DIR_READ
+};
+
+enum dw_edma_mode {
+       EDMA_MODE_LEGACY = 0,
+       EDMA_MODE_UNROLL
+};
+
+enum dw_edma_request {
+       EDMA_REQ_NONE = 0,
+       EDMA_REQ_STOP,
+       EDMA_REQ_PAUSE
+};
+
+enum dw_edma_status {
+       EDMA_ST_IDLE = 0,
+       EDMA_ST_PAUSE,
+       EDMA_ST_BUSY
+};
+
+struct dw_edma_chan;
+struct dw_edma_chunk;
+
+struct dw_edma_burst {
+       struct list_head                list;
+       u64                             sar;
+       u64                             dar;
+       u32                             sz;
+};
+
+struct dw_edma_region {
+       phys_addr_t                     paddr;
+       dma_addr_t                      vaddr;
+       size_t                          sz;
+};
+
+struct dw_edma_chunk {
+       struct list_head                list;
+       struct dw_edma_chan             *chan;
+       struct dw_edma_burst            *burst;
+
+       u32                             bursts_alloc;
+
+       u8                              cb;
+       struct dw_edma_region           ll_region;      /* Linked list */
+};
+
+struct dw_edma_desc {
+       struct virt_dma_desc            vd;
+       struct dw_edma_chan             *chan;
+       struct dw_edma_chunk            *chunk;
+
+       u32                             chunks_alloc;
+
+       u32                             alloc_sz;
+       u32                             xfer_sz;
+};
+
+struct dw_edma_chan {
+       struct virt_dma_chan            vc;
+       struct dw_edma_chip             *chip;
+       int                             id;
+       enum dw_edma_dir                dir;
+
+       off_t                           ll_off;
+       u32                             ll_max;
+
+       off_t                           dt_off;
+
+       struct msi_msg                  msi;
+
+       enum dw_edma_request            request;
+       enum dw_edma_status             status;
+       u8                              configured;
+
+       struct dma_slave_config         config;
+};
+
+struct dw_edma_irq {
+       struct msi_msg                  msi;
+       u32                             wr_mask;
+       u32                             rd_mask;
+       struct dw_edma                  *dw;
+};
+
+struct dw_edma {
+       char                            name[20];
+
+       struct dma_device               wr_edma;
+       u16                             wr_ch_cnt;
+
+       struct dma_device               rd_edma;
+       u16                             rd_ch_cnt;
+
+       struct dw_edma_region           rg_region;      /* Registers */
+       struct dw_edma_region           ll_region;      /* Linked list */
+       struct dw_edma_region           dt_region;      /* Data */
+
+       struct dw_edma_irq              *irq;
+       int                             nr_irqs;
+
+       u32                             version;
+       enum dw_edma_mode               mode;
+
+       struct dw_edma_chan             *chan;
+       const struct dw_edma_core_ops   *ops;
+
+       raw_spinlock_t                  lock;           /* Only for legacy */
+};
+
+struct dw_edma_sg {
+       struct scatterlist              *sgl;
+       unsigned int                    len;
+};
+
+struct dw_edma_cyclic {
+       dma_addr_t                      paddr;
+       size_t                          len;
+       size_t                          cnt;
+};
+
+struct dw_edma_transfer {
+       struct dma_chan                 *dchan;
+       union dw_edma_xfer {
+               struct dw_edma_sg       sg;
+               struct dw_edma_cyclic   cyclic;
+       } xfer;
+       enum dma_transfer_direction     direction;
+       unsigned long                   flags;
+       bool                            cyclic;
+};
+
+static inline
+struct dw_edma_chan *vc2dw_edma_chan(struct virt_dma_chan *vc)
+{
+       return container_of(vc, struct dw_edma_chan, vc);
+}
+
+static inline
+struct dw_edma_chan *dchan2dw_edma_chan(struct dma_chan *dchan)
+{
+       return vc2dw_edma_chan(to_virt_chan(dchan));
+}
+
+#endif /* _DW_EDMA_CORE_H */
diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
new file mode 100644 (file)
index 0000000..4c96e1c
--- /dev/null
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
+ * Synopsys DesignWare eDMA PCIe driver
+ *
+ * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+#include <linux/dma/edma.h>
+#include <linux/pci-epf.h>
+#include <linux/msi.h>
+
+#include "dw-edma-core.h"
+
+struct dw_edma_pcie_data {
+       /* eDMA registers location */
+       enum pci_barno                  rg_bar;
+       off_t                           rg_off;
+       size_t                          rg_sz;
+       /* eDMA memory linked list location */
+       enum pci_barno                  ll_bar;
+       off_t                           ll_off;
+       size_t                          ll_sz;
+       /* eDMA memory data location */
+       enum pci_barno                  dt_bar;
+       off_t                           dt_off;
+       size_t                          dt_sz;
+       /* Other */
+       u32                             version;
+       enum dw_edma_mode               mode;
+       u8                              irqs;
+};
+
+static const struct dw_edma_pcie_data snps_edda_data = {
+       /* eDMA registers location */
+       .rg_bar                         = BAR_0,
+       .rg_off                         = 0x00001000,   /*  4 Kbytes */
+       .rg_sz                          = 0x00002000,   /*  8 Kbytes */
+       /* eDMA memory linked list location */
+       .ll_bar                         = BAR_2,
+       .ll_off                         = 0x00000000,   /*  0 Kbytes */
+       .ll_sz                          = 0x00800000,   /*  8 Mbytes */
+       /* eDMA memory data location */
+       .dt_bar                         = BAR_2,
+       .dt_off                         = 0x00800000,   /*  8 Mbytes */
+       .dt_sz                          = 0x03800000,   /* 56 Mbytes */
+       /* Other */
+       .version                        = 0,
+       .mode                           = EDMA_MODE_UNROLL,
+       .irqs                           = 1,
+};
+
+static int dw_edma_pcie_probe(struct pci_dev *pdev,
+                             const struct pci_device_id *pid)
+{
+       const struct dw_edma_pcie_data *pdata = (void *)pid->driver_data;
+       struct device *dev = &pdev->dev;
+       struct dw_edma_chip *chip;
+       int err, nr_irqs;
+       struct dw_edma *dw;
+
+       /* Enable PCI device */
+       err = pcim_enable_device(pdev);
+       if (err) {
+               pci_err(pdev, "enabling device failed\n");
+               return err;
+       }
+
+       /* Mapping PCI BAR regions */
+       err = pcim_iomap_regions(pdev, BIT(pdata->rg_bar) |
+                                      BIT(pdata->ll_bar) |
+                                      BIT(pdata->dt_bar),
+                                pci_name(pdev));
+       if (err) {
+               pci_err(pdev, "eDMA BAR I/O remapping failed\n");
+               return err;
+       }
+
+       pci_set_master(pdev);
+
+       /* DMA configuration */
+       err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+       if (!err) {
+               err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+               if (err) {
+                       pci_err(pdev, "consistent DMA mask 64 set failed\n");
+                       return err;
+               }
+       } else {
+               pci_err(pdev, "DMA mask 64 set failed\n");
+
+               err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+               if (err) {
+                       pci_err(pdev, "DMA mask 32 set failed\n");
+                       return err;
+               }
+
+               err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+               if (err) {
+                       pci_err(pdev, "consistent DMA mask 32 set failed\n");
+                       return err;
+               }
+       }
+
+       /* Data structure allocation */
+       chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL);
+       if (!dw)
+               return -ENOMEM;
+
+       /* IRQs allocation */
+       nr_irqs = pci_alloc_irq_vectors(pdev, 1, pdata->irqs,
+                                       PCI_IRQ_MSI | PCI_IRQ_MSIX);
+       if (nr_irqs < 1) {
+               pci_err(pdev, "fail to alloc IRQ vector (number of IRQs=%u)\n",
+                       nr_irqs);
+               return -EPERM;
+       }
+
+       /* Data structure initialization */
+       chip->dw = dw;
+       chip->dev = dev;
+       chip->id = pdev->devfn;
+       chip->irq = pdev->irq;
+
+       dw->rg_region.vaddr = (dma_addr_t)pcim_iomap_table(pdev)[pdata->rg_bar];
+       dw->rg_region.vaddr += pdata->rg_off;
+       dw->rg_region.paddr = pdev->resource[pdata->rg_bar].start;
+       dw->rg_region.paddr += pdata->rg_off;
+       dw->rg_region.sz = pdata->rg_sz;
+
+       dw->ll_region.vaddr = (dma_addr_t)pcim_iomap_table(pdev)[pdata->ll_bar];
+       dw->ll_region.vaddr += pdata->ll_off;
+       dw->ll_region.paddr = pdev->resource[pdata->ll_bar].start;
+       dw->ll_region.paddr += pdata->ll_off;
+       dw->ll_region.sz = pdata->ll_sz;
+
+       dw->dt_region.vaddr = (dma_addr_t)pcim_iomap_table(pdev)[pdata->dt_bar];
+       dw->dt_region.vaddr += pdata->dt_off;
+       dw->dt_region.paddr = pdev->resource[pdata->dt_bar].start;
+       dw->dt_region.paddr += pdata->dt_off;
+       dw->dt_region.sz = pdata->dt_sz;
+
+       dw->version = pdata->version;
+       dw->mode = pdata->mode;
+       dw->nr_irqs = nr_irqs;
+
+       /* Debug info */
+       pci_dbg(pdev, "Version:\t%u\n", dw->version);
+
+       pci_dbg(pdev, "Mode:\t%s\n",
+               dw->mode == EDMA_MODE_LEGACY ? "Legacy" : "Unroll");
+
+       pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%pa, p=%pa)\n",
+               pdata->rg_bar, pdata->rg_off, pdata->rg_sz,
+               &dw->rg_region.vaddr, &dw->rg_region.paddr);
+
+       pci_dbg(pdev, "L. List:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%pa, p=%pa)\n",
+               pdata->ll_bar, pdata->ll_off, pdata->ll_sz,
+               &dw->ll_region.vaddr, &dw->ll_region.paddr);
+
+       pci_dbg(pdev, "Data:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%pa, p=%pa)\n",
+               pdata->dt_bar, pdata->dt_off, pdata->dt_sz,
+               &dw->dt_region.vaddr, &dw->dt_region.paddr);
+
+       pci_dbg(pdev, "Nr. IRQs:\t%u\n", dw->nr_irqs);
+
+       /* Validating if PCI interrupts were enabled */
+       if (!pci_dev_msi_enabled(pdev)) {
+               pci_err(pdev, "enable interrupt failed\n");
+               return -EPERM;
+       }
+
+       dw->irq = devm_kcalloc(dev, nr_irqs, sizeof(*dw->irq), GFP_KERNEL);
+       if (!dw->irq)
+               return -ENOMEM;
+
+       /* Starting eDMA driver */
+       err = dw_edma_probe(chip);
+       if (err) {
+               pci_err(pdev, "eDMA probe failed\n");
+               return err;
+       }
+
+       /* Saving data structure reference */
+       pci_set_drvdata(pdev, chip);
+
+       return 0;
+}
+
+static void dw_edma_pcie_remove(struct pci_dev *pdev)
+{
+       struct dw_edma_chip *chip = pci_get_drvdata(pdev);
+       int err;
+
+       /* Stopping eDMA driver */
+       err = dw_edma_remove(chip);
+       if (err)
+               pci_warn(pdev, "can't remove device properly: %d\n", err);
+
+       /* Freeing IRQs */
+       pci_free_irq_vectors(pdev);
+}
+
+static const struct pci_device_id dw_edma_pcie_id_table[] = {
+       { PCI_DEVICE_DATA(SYNOPSYS, EDDA, &snps_edda_data) },
+       { }
+};
+MODULE_DEVICE_TABLE(pci, dw_edma_pcie_id_table);
+
+static struct pci_driver dw_edma_pcie_driver = {
+       .name           = "dw-edma-pcie",
+       .id_table       = dw_edma_pcie_id_table,
+       .probe          = dw_edma_pcie_probe,
+       .remove         = dw_edma_pcie_remove,
+};
+
+module_pci_driver(dw_edma_pcie_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Synopsys DesignWare eDMA PCIe driver");
+MODULE_AUTHOR("Gustavo Pimentel <gustavo.pimentel@synopsys.com>");
diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
new file mode 100644 (file)
index 0000000..8a3180e
--- /dev/null
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
+ * Synopsys DesignWare eDMA v0 core
+ *
+ * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+ */
+
+#include <linux/bitfield.h>
+
+#include "dw-edma-core.h"
+#include "dw-edma-v0-core.h"
+#include "dw-edma-v0-regs.h"
+#include "dw-edma-v0-debugfs.h"
+
+enum dw_edma_control {
+       DW_EDMA_V0_CB                                   = BIT(0),
+       DW_EDMA_V0_TCB                                  = BIT(1),
+       DW_EDMA_V0_LLP                                  = BIT(2),
+       DW_EDMA_V0_LIE                                  = BIT(3),
+       DW_EDMA_V0_RIE                                  = BIT(4),
+       DW_EDMA_V0_CCS                                  = BIT(8),
+       DW_EDMA_V0_LLE                                  = BIT(9),
+};
+
+static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
+{
+       return (struct dw_edma_v0_regs __iomem *)dw->rg_region.vaddr;
+}
+
+#define SET(dw, name, value)                           \
+       writel(value, &(__dw_regs(dw)->name))
+
+#define GET(dw, name)                                  \
+       readl(&(__dw_regs(dw)->name))
+
+#define SET_RW(dw, dir, name, value)                   \
+       do {                                            \
+               if ((dir) == EDMA_DIR_WRITE)            \
+                       SET(dw, wr_##name, value);      \
+               else                                    \
+                       SET(dw, rd_##name, value);      \
+       } while (0)
+
+#define GET_RW(dw, dir, name)                          \
+       ((dir) == EDMA_DIR_WRITE                        \
+         ? GET(dw, wr_##name)                          \
+         : GET(dw, rd_##name))
+
+#define SET_BOTH(dw, name, value)                      \
+       do {                                            \
+               SET(dw, wr_##name, value);              \
+               SET(dw, rd_##name, value);              \
+       } while (0)
+
+static inline struct dw_edma_v0_ch_regs __iomem *
+__dw_ch_regs(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch)
+{
+       if (dw->mode == EDMA_MODE_LEGACY)
+               return &(__dw_regs(dw)->type.legacy.ch);
+
+       if (dir == EDMA_DIR_WRITE)
+               return &__dw_regs(dw)->type.unroll.ch[ch].wr;
+
+       return &__dw_regs(dw)->type.unroll.ch[ch].rd;
+}
+
+static inline void writel_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
+                            u32 value, void __iomem *addr)
+{
+       if (dw->mode == EDMA_MODE_LEGACY) {
+               u32 viewport_sel;
+               unsigned long flags;
+
+               raw_spin_lock_irqsave(&dw->lock, flags);
+
+               viewport_sel = FIELD_PREP(EDMA_V0_VIEWPORT_MASK, ch);
+               if (dir == EDMA_DIR_READ)
+                       viewport_sel |= BIT(31);
+
+               writel(viewport_sel,
+                      &(__dw_regs(dw)->type.legacy.viewport_sel));
+               writel(value, addr);
+
+               raw_spin_unlock_irqrestore(&dw->lock, flags);
+       } else {
+               writel(value, addr);
+       }
+}
+
+static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
+                          const void __iomem *addr)
+{
+       u32 value;
+
+       if (dw->mode == EDMA_MODE_LEGACY) {
+               u32 viewport_sel;
+               unsigned long flags;
+
+               raw_spin_lock_irqsave(&dw->lock, flags);
+
+               viewport_sel = FIELD_PREP(EDMA_V0_VIEWPORT_MASK, ch);
+               if (dir == EDMA_DIR_READ)
+                       viewport_sel |= BIT(31);
+
+               writel(viewport_sel,
+                      &(__dw_regs(dw)->type.legacy.viewport_sel));
+               value = readl(addr);
+
+               raw_spin_unlock_irqrestore(&dw->lock, flags);
+       } else {
+               value = readl(addr);
+       }
+
+       return value;
+}
+
+#define SET_CH(dw, dir, ch, name, value) \
+       writel_ch(dw, dir, ch, value, &(__dw_ch_regs(dw, dir, ch)->name))
+
+#define GET_CH(dw, dir, ch, name) \
+       readl_ch(dw, dir, ch, &(__dw_ch_regs(dw, dir, ch)->name))
+
+#define SET_LL(ll, value) \
+       writel(value, ll)
+
+/* eDMA management callbacks */
+void dw_edma_v0_core_off(struct dw_edma *dw)
+{
+       SET_BOTH(dw, int_mask, EDMA_V0_DONE_INT_MASK | EDMA_V0_ABORT_INT_MASK);
+       SET_BOTH(dw, int_clear, EDMA_V0_DONE_INT_MASK | EDMA_V0_ABORT_INT_MASK);
+       SET_BOTH(dw, engine_en, 0);
+}
+
+u16 dw_edma_v0_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir)
+{
+       u32 num_ch;
+
+       if (dir == EDMA_DIR_WRITE)
+               num_ch = FIELD_GET(EDMA_V0_WRITE_CH_COUNT_MASK, GET(dw, ctrl));
+       else
+               num_ch = FIELD_GET(EDMA_V0_READ_CH_COUNT_MASK, GET(dw, ctrl));
+
+       if (num_ch > EDMA_V0_MAX_NR_CH)
+               num_ch = EDMA_V0_MAX_NR_CH;
+
+       return (u16)num_ch;
+}
+
+enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan)
+{
+       struct dw_edma *dw = chan->chip->dw;
+       u32 tmp;
+
+       tmp = FIELD_GET(EDMA_V0_CH_STATUS_MASK,
+                       GET_CH(dw, chan->dir, chan->id, ch_control1));
+
+       if (tmp == 1)
+               return DMA_IN_PROGRESS;
+       else if (tmp == 3)
+               return DMA_COMPLETE;
+       else
+               return DMA_ERROR;
+}
+
+void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan)
+{
+       struct dw_edma *dw = chan->chip->dw;
+
+       SET_RW(dw, chan->dir, int_clear,
+              FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id)));
+}
+
+void dw_edma_v0_core_clear_abort_int(struct dw_edma_chan *chan)
+{
+       struct dw_edma *dw = chan->chip->dw;
+
+       SET_RW(dw, chan->dir, int_clear,
+              FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id)));
+}
+
+u32 dw_edma_v0_core_status_done_int(struct dw_edma *dw, enum dw_edma_dir dir)
+{
+       return FIELD_GET(EDMA_V0_DONE_INT_MASK, GET_RW(dw, dir, int_status));
+}
+
+u32 dw_edma_v0_core_status_abort_int(struct dw_edma *dw, enum dw_edma_dir dir)
+{
+       return FIELD_GET(EDMA_V0_ABORT_INT_MASK, GET_RW(dw, dir, int_status));
+}
+
+static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
+{
+       struct dw_edma_burst *child;
+       struct dw_edma_v0_lli *lli;
+       struct dw_edma_v0_llp *llp;
+       u32 control = 0, i = 0;
+       u64 sar, dar, addr;
+       int j;
+
+       lli = (struct dw_edma_v0_lli *)chunk->ll_region.vaddr;
+
+       if (chunk->cb)
+               control = DW_EDMA_V0_CB;
+
+       j = chunk->bursts_alloc;
+       list_for_each_entry(child, &chunk->burst->list, list) {
+               j--;
+               if (!j)
+                       control |= (DW_EDMA_V0_LIE | DW_EDMA_V0_RIE);
+
+               /* Channel control */
+               SET_LL(&lli[i].control, control);
+               /* Transfer size */
+               SET_LL(&lli[i].transfer_size, child->sz);
+               /* SAR - low, high */
+               sar = cpu_to_le64(child->sar);
+               SET_LL(&lli[i].sar_low, lower_32_bits(sar));
+               SET_LL(&lli[i].sar_high, upper_32_bits(sar));
+               /* DAR - low, high */
+               dar = cpu_to_le64(child->dar);
+               SET_LL(&lli[i].dar_low, lower_32_bits(dar));
+               SET_LL(&lli[i].dar_high, upper_32_bits(dar));
+               i++;
+       }
+
+       llp = (struct dw_edma_v0_llp *)&lli[i];
+       control = DW_EDMA_V0_LLP | DW_EDMA_V0_TCB;
+       if (!chunk->cb)
+               control |= DW_EDMA_V0_CB;
+
+       /* Channel control */
+       SET_LL(&llp->control, control);
+       /* Linked list  - low, high */
+       addr = cpu_to_le64(chunk->ll_region.paddr);
+       SET_LL(&llp->llp_low, lower_32_bits(addr));
+       SET_LL(&llp->llp_high, upper_32_bits(addr));
+}
+
+void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
+{
+       struct dw_edma_chan *chan = chunk->chan;
+       struct dw_edma *dw = chan->chip->dw;
+       u32 tmp;
+       u64 llp;
+
+       dw_edma_v0_core_write_chunk(chunk);
+
+       if (first) {
+               /* Enable engine */
+               SET_RW(dw, chan->dir, engine_en, BIT(0));
+               /* Interrupt unmask - done, abort */
+               tmp = GET_RW(dw, chan->dir, int_mask);
+               tmp &= ~FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id));
+               tmp &= ~FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id));
+               SET_RW(dw, chan->dir, int_mask, tmp);
+               /* Linked list error */
+               tmp = GET_RW(dw, chan->dir, linked_list_err_en);
+               tmp |= FIELD_PREP(EDMA_V0_LINKED_LIST_ERR_MASK, BIT(chan->id));
+               SET_RW(dw, chan->dir, linked_list_err_en, tmp);
+               /* Channel control */
+               SET_CH(dw, chan->dir, chan->id, ch_control1,
+                      (DW_EDMA_V0_CCS | DW_EDMA_V0_LLE));
+               /* Linked list - low, high */
+               llp = cpu_to_le64(chunk->ll_region.paddr);
+               SET_CH(dw, chan->dir, chan->id, llp_low, lower_32_bits(llp));
+               SET_CH(dw, chan->dir, chan->id, llp_high, upper_32_bits(llp));
+       }
+       /* Doorbell */
+       SET_RW(dw, chan->dir, doorbell,
+              FIELD_PREP(EDMA_V0_DOORBELL_CH_MASK, chan->id));
+}
+
+int dw_edma_v0_core_device_config(struct dw_edma_chan *chan)
+{
+       struct dw_edma *dw = chan->chip->dw;
+       u32 tmp = 0;
+
+       /* MSI done addr - low, high */
+       SET_RW(dw, chan->dir, done_imwr_low, chan->msi.address_lo);
+       SET_RW(dw, chan->dir, done_imwr_high, chan->msi.address_hi);
+       /* MSI abort addr - low, high */
+       SET_RW(dw, chan->dir, abort_imwr_low, chan->msi.address_lo);
+       SET_RW(dw, chan->dir, abort_imwr_high, chan->msi.address_hi);
+       /* MSI data - low, high */
+       switch (chan->id) {
+       case 0:
+       case 1:
+               tmp = GET_RW(dw, chan->dir, ch01_imwr_data);
+               break;
+
+       case 2:
+       case 3:
+               tmp = GET_RW(dw, chan->dir, ch23_imwr_data);
+               break;
+
+       case 4:
+       case 5:
+               tmp = GET_RW(dw, chan->dir, ch45_imwr_data);
+               break;
+
+       case 6:
+       case 7:
+               tmp = GET_RW(dw, chan->dir, ch67_imwr_data);
+               break;
+       }
+
+       if (chan->id & BIT(0)) {
+               /* Channel odd {1, 3, 5, 7} */
+               tmp &= EDMA_V0_CH_EVEN_MSI_DATA_MASK;
+               tmp |= FIELD_PREP(EDMA_V0_CH_ODD_MSI_DATA_MASK,
+                                 chan->msi.data);
+       } else {
+               /* Channel even {0, 2, 4, 6} */
+               tmp &= EDMA_V0_CH_ODD_MSI_DATA_MASK;
+               tmp |= FIELD_PREP(EDMA_V0_CH_EVEN_MSI_DATA_MASK,
+                                 chan->msi.data);
+       }
+
+       switch (chan->id) {
+       case 0:
+       case 1:
+               SET_RW(dw, chan->dir, ch01_imwr_data, tmp);
+               break;
+
+       case 2:
+       case 3:
+               SET_RW(dw, chan->dir, ch23_imwr_data, tmp);
+               break;
+
+       case 4:
+       case 5:
+               SET_RW(dw, chan->dir, ch45_imwr_data, tmp);
+               break;
+
+       case 6:
+       case 7:
+               SET_RW(dw, chan->dir, ch67_imwr_data, tmp);
+               break;
+       }
+
+       return 0;
+}
+
+/* eDMA debugfs callbacks */
+void dw_edma_v0_core_debugfs_on(struct dw_edma_chip *chip)
+{
+       dw_edma_v0_debugfs_on(chip);
+}
+
+void dw_edma_v0_core_debugfs_off(void)
+{
+       dw_edma_v0_debugfs_off();
+}
diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.h b/drivers/dma/dw-edma/dw-edma-v0-core.h
new file mode 100644 (file)
index 0000000..abae152
--- /dev/null
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
+ * Synopsys DesignWare eDMA v0 core
+ *
+ * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+ */
+
+#ifndef _DW_EDMA_V0_CORE_H
+#define _DW_EDMA_V0_CORE_H
+
+#include <linux/dma/edma.h>
+
+/* eDMA management callbacks */
+void dw_edma_v0_core_off(struct dw_edma *chan);
+u16 dw_edma_v0_core_ch_count(struct dw_edma *chan, enum dw_edma_dir dir);
+enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan);
+void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan);
+void dw_edma_v0_core_clear_abort_int(struct dw_edma_chan *chan);
+u32 dw_edma_v0_core_status_done_int(struct dw_edma *chan, enum dw_edma_dir dir);
+u32 dw_edma_v0_core_status_abort_int(struct dw_edma *chan, enum dw_edma_dir dir);
+void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first);
+int dw_edma_v0_core_device_config(struct dw_edma_chan *chan);
+/* eDMA debug fs callbacks */
+void dw_edma_v0_core_debugfs_on(struct dw_edma_chip *chip);
+void dw_edma_v0_core_debugfs_off(void);
+
+#endif /* _DW_EDMA_V0_CORE_H */
diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
new file mode 100644 (file)
index 0000000..3226f52
--- /dev/null
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
+ * Synopsys DesignWare eDMA v0 core
+ *
+ * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+ */
+
+#include <linux/debugfs.h>
+#include <linux/bitfield.h>
+
+#include "dw-edma-v0-debugfs.h"
+#include "dw-edma-v0-regs.h"
+#include "dw-edma-core.h"
+
+#define REGS_ADDR(name) \
+       ((dma_addr_t *)&regs->name)
+#define REGISTER(name) \
+       { #name, REGS_ADDR(name) }
+
+#define WR_REGISTER(name) \
+       { #name, REGS_ADDR(wr_##name) }
+#define RD_REGISTER(name) \
+       { #name, REGS_ADDR(rd_##name) }
+
+#define WR_REGISTER_LEGACY(name) \
+       { #name, REGS_ADDR(type.legacy.wr_##name) }
+#define RD_REGISTER_LEGACY(name) \
+       { #name, REGS_ADDR(type.legacy.rd_##name) }
+
+#define WR_REGISTER_UNROLL(name) \
+       { #name, REGS_ADDR(type.unroll.wr_##name) }
+#define RD_REGISTER_UNROLL(name) \
+       { #name, REGS_ADDR(type.unroll.rd_##name) }
+
+#define WRITE_STR                              "write"
+#define READ_STR                               "read"
+#define CHANNEL_STR                            "channel"
+#define REGISTERS_STR                          "registers"
+
+static struct dentry                           *base_dir;
+static struct dw_edma                          *dw;
+static struct dw_edma_v0_regs                  *regs;
+
+static struct {
+       void                                    *start;
+       void                                    *end;
+} lim[2][EDMA_V0_MAX_NR_CH];
+
+struct debugfs_entries {
+       char                                    name[24];
+       dma_addr_t                              *reg;
+};
+
+static int dw_edma_debugfs_u32_get(void *data, u64 *val)
+{
+       if (dw->mode == EDMA_MODE_LEGACY &&
+           data >= (void *)&regs->type.legacy.ch) {
+               void *ptr = (void *)&regs->type.legacy.ch;
+               u32 viewport_sel = 0;
+               unsigned long flags;
+               u16 ch;
+
+               for (ch = 0; ch < dw->wr_ch_cnt; ch++)
+                       if (lim[0][ch].start >= data && data < lim[0][ch].end) {
+                               ptr += (data - lim[0][ch].start);
+                               goto legacy_sel_wr;
+                       }
+
+               for (ch = 0; ch < dw->rd_ch_cnt; ch++)
+                       if (lim[1][ch].start >= data && data < lim[1][ch].end) {
+                               ptr += (data - lim[1][ch].start);
+                               goto legacy_sel_rd;
+                       }
+
+               return 0;
+legacy_sel_rd:
+               viewport_sel = BIT(31);
+legacy_sel_wr:
+               viewport_sel |= FIELD_PREP(EDMA_V0_VIEWPORT_MASK, ch);
+
+               raw_spin_lock_irqsave(&dw->lock, flags);
+
+               writel(viewport_sel, &regs->type.legacy.viewport_sel);
+               *val = readl(ptr);
+
+               raw_spin_unlock_irqrestore(&dw->lock, flags);
+       } else {
+               *val = readl(data);
+       }
+
+       return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_edma_debugfs_u32_get, NULL, "0x%08llx\n");
+
+static void dw_edma_debugfs_create_x32(const struct debugfs_entries entries[],
+                                      int nr_entries, struct dentry *dir)
+{
+       int i;
+
+       for (i = 0; i < nr_entries; i++) {
+               if (!debugfs_create_file_unsafe(entries[i].name, 0444, dir,
+                                               entries[i].reg, &fops_x32))
+                       break;
+       }
+}
+
+static void dw_edma_debugfs_regs_ch(struct dw_edma_v0_ch_regs *regs,
+                                   struct dentry *dir)
+{
+       int nr_entries;
+       const struct debugfs_entries debugfs_regs[] = {
+               REGISTER(ch_control1),
+               REGISTER(ch_control2),
+               REGISTER(transfer_size),
+               REGISTER(sar_low),
+               REGISTER(sar_high),
+               REGISTER(dar_low),
+               REGISTER(dar_high),
+               REGISTER(llp_low),
+               REGISTER(llp_high),
+       };
+
+       nr_entries = ARRAY_SIZE(debugfs_regs);
+       dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, dir);
+}
+
+static void dw_edma_debugfs_regs_wr(struct dentry *dir)
+{
+       const struct debugfs_entries debugfs_regs[] = {
+               /* eDMA global registers */
+               WR_REGISTER(engine_en),
+               WR_REGISTER(doorbell),
+               WR_REGISTER(ch_arb_weight_low),
+               WR_REGISTER(ch_arb_weight_high),
+               /* eDMA interrupts registers */
+               WR_REGISTER(int_status),
+               WR_REGISTER(int_mask),
+               WR_REGISTER(int_clear),
+               WR_REGISTER(err_status),
+               WR_REGISTER(done_imwr_low),
+               WR_REGISTER(done_imwr_high),
+               WR_REGISTER(abort_imwr_low),
+               WR_REGISTER(abort_imwr_high),
+               WR_REGISTER(ch01_imwr_data),
+               WR_REGISTER(ch23_imwr_data),
+               WR_REGISTER(ch45_imwr_data),
+               WR_REGISTER(ch67_imwr_data),
+               WR_REGISTER(linked_list_err_en),
+       };
+       const struct debugfs_entries debugfs_unroll_regs[] = {
+               /* eDMA channel context grouping */
+               WR_REGISTER_UNROLL(engine_chgroup),
+               WR_REGISTER_UNROLL(engine_hshake_cnt_low),
+               WR_REGISTER_UNROLL(engine_hshake_cnt_high),
+               WR_REGISTER_UNROLL(ch0_pwr_en),
+               WR_REGISTER_UNROLL(ch1_pwr_en),
+               WR_REGISTER_UNROLL(ch2_pwr_en),
+               WR_REGISTER_UNROLL(ch3_pwr_en),
+               WR_REGISTER_UNROLL(ch4_pwr_en),
+               WR_REGISTER_UNROLL(ch5_pwr_en),
+               WR_REGISTER_UNROLL(ch6_pwr_en),
+               WR_REGISTER_UNROLL(ch7_pwr_en),
+       };
+       struct dentry *regs_dir, *ch_dir;
+       int nr_entries, i;
+       char name[16];
+
+       regs_dir = debugfs_create_dir(WRITE_STR, dir);
+       if (!regs_dir)
+               return;
+
+       nr_entries = ARRAY_SIZE(debugfs_regs);
+       dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
+
+       if (dw->mode == EDMA_MODE_UNROLL) {
+               nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
+               dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
+                                          regs_dir);
+       }
+
+       for (i = 0; i < dw->wr_ch_cnt; i++) {
+               snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i);
+
+               ch_dir = debugfs_create_dir(name, regs_dir);
+               if (!ch_dir)
+                       return;
+
+               dw_edma_debugfs_regs_ch(&regs->type.unroll.ch[i].wr, ch_dir);
+
+               lim[0][i].start = &regs->type.unroll.ch[i].wr;
+               lim[0][i].end = &regs->type.unroll.ch[i].padding_1[0];
+       }
+}
+
+static void dw_edma_debugfs_regs_rd(struct dentry *dir)
+{
+       const struct debugfs_entries debugfs_regs[] = {
+               /* eDMA global registers */
+               RD_REGISTER(engine_en),
+               RD_REGISTER(doorbell),
+               RD_REGISTER(ch_arb_weight_low),
+               RD_REGISTER(ch_arb_weight_high),
+               /* eDMA interrupts registers */
+               RD_REGISTER(int_status),
+               RD_REGISTER(int_mask),
+               RD_REGISTER(int_clear),
+               RD_REGISTER(err_status_low),
+               RD_REGISTER(err_status_high),
+               RD_REGISTER(linked_list_err_en),
+               RD_REGISTER(done_imwr_low),
+               RD_REGISTER(done_imwr_high),
+               RD_REGISTER(abort_imwr_low),
+               RD_REGISTER(abort_imwr_high),
+               RD_REGISTER(ch01_imwr_data),
+               RD_REGISTER(ch23_imwr_data),
+               RD_REGISTER(ch45_imwr_data),
+               RD_REGISTER(ch67_imwr_data),
+       };
+       const struct debugfs_entries debugfs_unroll_regs[] = {
+               /* eDMA channel context grouping */
+               RD_REGISTER_UNROLL(engine_chgroup),
+               RD_REGISTER_UNROLL(engine_hshake_cnt_low),
+               RD_REGISTER_UNROLL(engine_hshake_cnt_high),
+               RD_REGISTER_UNROLL(ch0_pwr_en),
+               RD_REGISTER_UNROLL(ch1_pwr_en),
+               RD_REGISTER_UNROLL(ch2_pwr_en),
+               RD_REGISTER_UNROLL(ch3_pwr_en),
+               RD_REGISTER_UNROLL(ch4_pwr_en),
+               RD_REGISTER_UNROLL(ch5_pwr_en),
+               RD_REGISTER_UNROLL(ch6_pwr_en),
+               RD_REGISTER_UNROLL(ch7_pwr_en),
+       };
+       struct dentry *regs_dir, *ch_dir;
+       int nr_entries, i;
+       char name[16];
+
+       regs_dir = debugfs_create_dir(READ_STR, dir);
+       if (!regs_dir)
+               return;
+
+       nr_entries = ARRAY_SIZE(debugfs_regs);
+       dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
+
+       if (dw->mode == EDMA_MODE_UNROLL) {
+               nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
+               dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
+                                          regs_dir);
+       }
+
+       for (i = 0; i < dw->rd_ch_cnt; i++) {
+               snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i);
+
+               ch_dir = debugfs_create_dir(name, regs_dir);
+               if (!ch_dir)
+                       return;
+
+               dw_edma_debugfs_regs_ch(&regs->type.unroll.ch[i].rd, ch_dir);
+
+               lim[1][i].start = &regs->type.unroll.ch[i].rd;
+               lim[1][i].end = &regs->type.unroll.ch[i].padding_2[0];
+       }
+}
+
+static void dw_edma_debugfs_regs(void)
+{
+       const struct debugfs_entries debugfs_regs[] = {
+               REGISTER(ctrl_data_arb_prior),
+               REGISTER(ctrl),
+       };
+       struct dentry *regs_dir;
+       int nr_entries;
+
+       regs_dir = debugfs_create_dir(REGISTERS_STR, base_dir);
+       if (!regs_dir)
+               return;
+
+       nr_entries = ARRAY_SIZE(debugfs_regs);
+       dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
+
+       dw_edma_debugfs_regs_wr(regs_dir);
+       dw_edma_debugfs_regs_rd(regs_dir);
+}
+
+void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
+{
+       dw = chip->dw;
+       if (!dw)
+               return;
+
+       regs = (struct dw_edma_v0_regs *)dw->rg_region.vaddr;
+       if (!regs)
+               return;
+
+       base_dir = debugfs_create_dir(dw->name, 0);
+       if (!base_dir)
+               return;
+
+       debugfs_create_u32("version", 0444, base_dir, &dw->version);
+       debugfs_create_u32("mode", 0444, base_dir, &dw->mode);
+       debugfs_create_u16("wr_ch_cnt", 0444, base_dir, &dw->wr_ch_cnt);
+       debugfs_create_u16("rd_ch_cnt", 0444, base_dir, &dw->rd_ch_cnt);
+
+       dw_edma_debugfs_regs();
+}
+
+void dw_edma_v0_debugfs_off(void)
+{
+       debugfs_remove_recursive(base_dir);
+}
diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.h b/drivers/dma/dw-edma/dw-edma-v0-debugfs.h
new file mode 100644 (file)
index 0000000..5450a0a
--- /dev/null
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
+ * Synopsys DesignWare eDMA v0 core
+ *
+ * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+ */
+
+#ifndef _DW_EDMA_V0_DEBUG_FS_H
+#define _DW_EDMA_V0_DEBUG_FS_H
+
+#include <linux/dma/edma.h>
+
+#ifdef CONFIG_DEBUG_FS
+void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip);
+void dw_edma_v0_debugfs_off(void);
+#else
+static inline void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
+{
+}
+
+static inline void dw_edma_v0_debugfs_off(void)
+{
+}
+#endif /* CONFIG_DEBUG_FS */
+
+#endif /* _DW_EDMA_V0_DEBUG_FS_H */
diff --git a/drivers/dma/dw-edma/dw-edma-v0-regs.h b/drivers/dma/dw-edma/dw-edma-v0-regs.h
new file mode 100644 (file)
index 0000000..cd64768
--- /dev/null
@@ -0,0 +1,158 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
+ * Synopsys DesignWare eDMA v0 core
+ *
+ * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+ */
+
+#ifndef _DW_EDMA_V0_REGS_H
+#define _DW_EDMA_V0_REGS_H
+
+#include <linux/dmaengine.h>
+
+#define EDMA_V0_MAX_NR_CH                              8
+#define EDMA_V0_VIEWPORT_MASK                          GENMASK(2, 0)
+#define EDMA_V0_DONE_INT_MASK                          GENMASK(7, 0)
+#define EDMA_V0_ABORT_INT_MASK                         GENMASK(23, 16)
+#define EDMA_V0_WRITE_CH_COUNT_MASK                    GENMASK(3, 0)
+#define EDMA_V0_READ_CH_COUNT_MASK                     GENMASK(19, 16)
+#define EDMA_V0_CH_STATUS_MASK                         GENMASK(6, 5)
+#define EDMA_V0_DOORBELL_CH_MASK                       GENMASK(2, 0)
+#define EDMA_V0_LINKED_LIST_ERR_MASK                   GENMASK(7, 0)
+
+#define EDMA_V0_CH_ODD_MSI_DATA_MASK                   GENMASK(31, 16)
+#define EDMA_V0_CH_EVEN_MSI_DATA_MASK                  GENMASK(15, 0)
+
+struct dw_edma_v0_ch_regs {
+       u32 ch_control1;                                /* 0x000 */
+       u32 ch_control2;                                /* 0x004 */
+       u32 transfer_size;                              /* 0x008 */
+       u32 sar_low;                                    /* 0x00c */
+       u32 sar_high;                                   /* 0x010 */
+       u32 dar_low;                                    /* 0x014 */
+       u32 dar_high;                                   /* 0x018 */
+       u32 llp_low;                                    /* 0x01c */
+       u32 llp_high;                                   /* 0x020 */
+};
+
+struct dw_edma_v0_ch {
+       struct dw_edma_v0_ch_regs wr;                   /* 0x200 */
+       u32 padding_1[55];                              /* [0x224..0x2fc] */
+       struct dw_edma_v0_ch_regs rd;                   /* 0x300 */
+       u32 padding_2[55];                              /* [0x224..0x2fc] */
+};
+
+struct dw_edma_v0_unroll {
+       u32 padding_1;                                  /* 0x0f8 */
+       u32 wr_engine_chgroup;                          /* 0x100 */
+       u32 rd_engine_chgroup;                          /* 0x104 */
+       u32 wr_engine_hshake_cnt_low;                   /* 0x108 */
+       u32 wr_engine_hshake_cnt_high;                  /* 0x10c */
+       u32 padding_2[2];                               /* [0x110..0x114] */
+       u32 rd_engine_hshake_cnt_low;                   /* 0x118 */
+       u32 rd_engine_hshake_cnt_high;                  /* 0x11c */
+       u32 padding_3[2];                               /* [0x120..0x124] */
+       u32 wr_ch0_pwr_en;                              /* 0x128 */
+       u32 wr_ch1_pwr_en;                              /* 0x12c */
+       u32 wr_ch2_pwr_en;                              /* 0x130 */
+       u32 wr_ch3_pwr_en;                              /* 0x134 */
+       u32 wr_ch4_pwr_en;                              /* 0x138 */
+       u32 wr_ch5_pwr_en;                              /* 0x13c */
+       u32 wr_ch6_pwr_en;                              /* 0x140 */
+       u32 wr_ch7_pwr_en;                              /* 0x144 */
+       u32 padding_4[8];                               /* [0x148..0x164] */
+       u32 rd_ch0_pwr_en;                              /* 0x168 */
+       u32 rd_ch1_pwr_en;                              /* 0x16c */
+       u32 rd_ch2_pwr_en;                              /* 0x170 */
+       u32 rd_ch3_pwr_en;                              /* 0x174 */
+       u32 rd_ch4_pwr_en;                              /* 0x178 */
+       u32 rd_ch5_pwr_en;                              /* 0x18c */
+       u32 rd_ch6_pwr_en;                              /* 0x180 */
+       u32 rd_ch7_pwr_en;                              /* 0x184 */
+       u32 padding_5[30];                              /* [0x188..0x1fc] */
+       struct dw_edma_v0_ch ch[EDMA_V0_MAX_NR_CH];     /* [0x200..0x1120] */
+};
+
+struct dw_edma_v0_legacy {
+       u32 viewport_sel;                               /* 0x0f8 */
+       struct dw_edma_v0_ch_regs ch;                   /* [0x100..0x120] */
+};
+
+struct dw_edma_v0_regs {
+       /* eDMA global registers */
+       u32 ctrl_data_arb_prior;                        /* 0x000 */
+       u32 padding_1;                                  /* 0x004 */
+       u32 ctrl;                                       /* 0x008 */
+       u32 wr_engine_en;                               /* 0x00c */
+       u32 wr_doorbell;                                /* 0x010 */
+       u32 padding_2;                                  /* 0x014 */
+       u32 wr_ch_arb_weight_low;                       /* 0x018 */
+       u32 wr_ch_arb_weight_high;                      /* 0x01c */
+       u32 padding_3[3];                               /* [0x020..0x028] */
+       u32 rd_engine_en;                               /* 0x02c */
+       u32 rd_doorbell;                                /* 0x030 */
+       u32 padding_4;                                  /* 0x034 */
+       u32 rd_ch_arb_weight_low;                       /* 0x038 */
+       u32 rd_ch_arb_weight_high;                      /* 0x03c */
+       u32 padding_5[3];                               /* [0x040..0x048] */
+       /* eDMA interrupts registers */
+       u32 wr_int_status;                              /* 0x04c */
+       u32 padding_6;                                  /* 0x050 */
+       u32 wr_int_mask;                                /* 0x054 */
+       u32 wr_int_clear;                               /* 0x058 */
+       u32 wr_err_status;                              /* 0x05c */
+       u32 wr_done_imwr_low;                           /* 0x060 */
+       u32 wr_done_imwr_high;                          /* 0x064 */
+       u32 wr_abort_imwr_low;                          /* 0x068 */
+       u32 wr_abort_imwr_high;                         /* 0x06c */
+       u32 wr_ch01_imwr_data;                          /* 0x070 */
+       u32 wr_ch23_imwr_data;                          /* 0x074 */
+       u32 wr_ch45_imwr_data;                          /* 0x078 */
+       u32 wr_ch67_imwr_data;                          /* 0x07c */
+       u32 padding_7[4];                               /* [0x080..0x08c] */
+       u32 wr_linked_list_err_en;                      /* 0x090 */
+       u32 padding_8[3];                               /* [0x094..0x09c] */
+       u32 rd_int_status;                              /* 0x0a0 */
+       u32 padding_9;                                  /* 0x0a4 */
+       u32 rd_int_mask;                                /* 0x0a8 */
+       u32 rd_int_clear;                               /* 0x0ac */
+       u32 padding_10;                                 /* 0x0b0 */
+       u32 rd_err_status_low;                          /* 0x0b4 */
+       u32 rd_err_status_high;                         /* 0x0b8 */
+       u32 padding_11[2];                              /* [0x0bc..0x0c0] */
+       u32 rd_linked_list_err_en;                      /* 0x0c4 */
+       u32 padding_12;                                 /* 0x0c8 */
+       u32 rd_done_imwr_low;                           /* 0x0cc */
+       u32 rd_done_imwr_high;                          /* 0x0d0 */
+       u32 rd_abort_imwr_low;                          /* 0x0d4 */
+       u32 rd_abort_imwr_high;                         /* 0x0d8 */
+       u32 rd_ch01_imwr_data;                          /* 0x0dc */
+       u32 rd_ch23_imwr_data;                          /* 0x0e0 */
+       u32 rd_ch45_imwr_data;                          /* 0x0e4 */
+       u32 rd_ch67_imwr_data;                          /* 0x0e8 */
+       u32 padding_13[4];                              /* [0x0ec..0x0f8] */
+       /* eDMA channel context grouping */
+       union dw_edma_v0_type {
+               struct dw_edma_v0_legacy legacy;        /* [0x0f8..0x120] */
+               struct dw_edma_v0_unroll unroll;        /* [0x0f8..0x1120] */
+       } type;
+};
+
+struct dw_edma_v0_lli {
+       u32 control;
+       u32 transfer_size;
+       u32 sar_low;
+       u32 sar_high;
+       u32 dar_low;
+       u32 dar_high;
+};
+
+struct dw_edma_v0_llp {
+       u32 control;
+       u32 reserved;
+       u32 llp_low;
+       u32 llp_high;
+};
+
+#endif /* _DW_EDMA_V0_REGS_H */
index e79a75d..8de87b1 100644 (file)
 struct dw_dma_pci_data {
        const struct dw_dma_platform_data *pdata;
        int (*probe)(struct dw_dma_chip *chip);
+       int (*remove)(struct dw_dma_chip *chip);
+       struct dw_dma_chip *chip;
 };
 
 static const struct dw_dma_pci_data dw_pci_data = {
        .probe = dw_dma_probe,
+       .remove = dw_dma_remove,
 };
 
 static const struct dw_dma_platform_data idma32_pdata = {
@@ -34,11 +37,13 @@ static const struct dw_dma_platform_data idma32_pdata = {
 static const struct dw_dma_pci_data idma32_pci_data = {
        .pdata = &idma32_pdata,
        .probe = idma32_dma_probe,
+       .remove = idma32_dma_remove,
 };
 
 static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
 {
-       const struct dw_dma_pci_data *data = (void *)pid->driver_data;
+       const struct dw_dma_pci_data *drv_data = (void *)pid->driver_data;
+       struct dw_dma_pci_data *data;
        struct dw_dma_chip *chip;
        int ret;
 
@@ -63,6 +68,10 @@ static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
        if (ret)
                return ret;
 
+       data = devm_kmemdup(&pdev->dev, drv_data, sizeof(*drv_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
        chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
                return -ENOMEM;
@@ -73,21 +82,24 @@ static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
        chip->irq = pdev->irq;
        chip->pdata = data->pdata;
 
+       data->chip = chip;
+
        ret = data->probe(chip);
        if (ret)
                return ret;
 
-       pci_set_drvdata(pdev, chip);
+       pci_set_drvdata(pdev, data);
 
        return 0;
 }
 
 static void dw_pci_remove(struct pci_dev *pdev)
 {
-       struct dw_dma_chip *chip = pci_get_drvdata(pdev);
+       struct dw_dma_pci_data *data = pci_get_drvdata(pdev);
+       struct dw_dma_chip *chip = data->chip;
        int ret;
 
-       ret = dw_dma_remove(chip);
+       ret = data->remove(chip);
        if (ret)
                dev_warn(&pdev->dev, "can't remove device properly: %d\n", ret);
 }
@@ -96,16 +108,16 @@ static void dw_pci_remove(struct pci_dev *pdev)
 
 static int dw_pci_suspend_late(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
-       struct dw_dma_chip *chip = pci_get_drvdata(pci);
+       struct dw_dma_pci_data *data = dev_get_drvdata(dev);
+       struct dw_dma_chip *chip = data->chip;
 
        return do_dw_dma_disable(chip);
 };
 
 static int dw_pci_resume_early(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
-       struct dw_dma_chip *chip = pci_get_drvdata(pci);
+       struct dw_dma_pci_data *data = dev_get_drvdata(dev);
+       struct dw_dma_chip *chip = data->chip;
 
        return do_dw_dma_enable(chip);
 };
@@ -131,6 +143,11 @@ static const struct pci_device_id dw_pci_id_table[] = {
        { PCI_VDEVICE(INTEL, 0x2286), (kernel_ulong_t)&dw_pci_data },
        { PCI_VDEVICE(INTEL, 0x22c0), (kernel_ulong_t)&dw_pci_data },
 
+       /* Elkhart Lake iDMA 32-bit (OSE DMA) */
+       { PCI_VDEVICE(INTEL, 0x4bb4), (kernel_ulong_t)&idma32_pci_data },
+       { PCI_VDEVICE(INTEL, 0x4bb5), (kernel_ulong_t)&idma32_pci_data },
+       { PCI_VDEVICE(INTEL, 0x4bb6), (kernel_ulong_t)&idma32_pci_data },
+
        /* Haswell */
        { PCI_VDEVICE(INTEL, 0x9c60), (kernel_ulong_t)&dw_pci_data },
 
index 680b2a0..44d92c3 100644 (file)
@@ -47,7 +47,7 @@ static void fsl_edma_enable_request(struct fsl_edma_chan *fsl_chan)
        struct edma_regs *regs = &fsl_chan->edma->regs;
        u32 ch = fsl_chan->vchan.chan.chan_id;
 
-       if (fsl_chan->edma->version == v1) {
+       if (fsl_chan->edma->drvdata->version == v1) {
                edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), regs->seei);
                edma_writeb(fsl_chan->edma, ch, regs->serq);
        } else {
@@ -64,7 +64,7 @@ void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan)
        struct edma_regs *regs = &fsl_chan->edma->regs;
        u32 ch = fsl_chan->vchan.chan.chan_id;
 
-       if (fsl_chan->edma->version == v1) {
+       if (fsl_chan->edma->drvdata->version == v1) {
                edma_writeb(fsl_chan->edma, ch, regs->cerq);
                edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), regs->ceei);
        } else {
@@ -77,22 +77,33 @@ void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan)
 }
 EXPORT_SYMBOL_GPL(fsl_edma_disable_request);
 
+static void mux_configure8(struct fsl_edma_chan *fsl_chan, void __iomem *addr,
+                          u32 off, u32 slot, bool enable)
+{
+       u8 val8;
+
+       if (enable)
+               val8 = EDMAMUX_CHCFG_ENBL | slot;
+       else
+               val8 = EDMAMUX_CHCFG_DIS;
+
+       iowrite8(val8, addr + off);
+}
+
 void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan,
                        unsigned int slot, bool enable)
 {
        u32 ch = fsl_chan->vchan.chan.chan_id;
        void __iomem *muxaddr;
        unsigned int chans_per_mux, ch_off;
+       u32 dmamux_nr = fsl_chan->edma->drvdata->dmamuxs;
 
-       chans_per_mux = fsl_chan->edma->n_chans / DMAMUX_NR;
+       chans_per_mux = fsl_chan->edma->n_chans / dmamux_nr;
        ch_off = fsl_chan->vchan.chan.chan_id % chans_per_mux;
        muxaddr = fsl_chan->edma->muxbase[ch / chans_per_mux];
        slot = EDMAMUX_CHCFG_SOURCE(slot);
 
-       if (enable)
-               iowrite8(EDMAMUX_CHCFG_ENBL | slot, muxaddr + ch_off);
-       else
-               iowrite8(EDMAMUX_CHCFG_DIS, muxaddr + ch_off);
+       mux_configure8(fsl_chan, muxaddr, ch_off, slot, enable);
 }
 EXPORT_SYMBOL_GPL(fsl_edma_chan_mux);
 
@@ -647,28 +658,28 @@ void fsl_edma_setup_regs(struct fsl_edma_engine *edma)
        edma->regs.erql = edma->membase + EDMA_ERQ;
        edma->regs.eeil = edma->membase + EDMA_EEI;
 
-       edma->regs.serq = edma->membase + ((edma->version == v1) ?
-                       EDMA_SERQ : EDMA64_SERQ);
-       edma->regs.cerq = edma->membase + ((edma->version == v1) ?
-                       EDMA_CERQ : EDMA64_CERQ);
-       edma->regs.seei = edma->membase + ((edma->version == v1) ?
-                       EDMA_SEEI : EDMA64_SEEI);
-       edma->regs.ceei = edma->membase + ((edma->version == v1) ?
-                       EDMA_CEEI : EDMA64_CEEI);
-       edma->regs.cint = edma->membase + ((edma->version == v1) ?
-                       EDMA_CINT : EDMA64_CINT);
-       edma->regs.cerr = edma->membase + ((edma->version == v1) ?
-                       EDMA_CERR : EDMA64_CERR);
-       edma->regs.ssrt = edma->membase + ((edma->version == v1) ?
-                       EDMA_SSRT : EDMA64_SSRT);
-       edma->regs.cdne = edma->membase + ((edma->version == v1) ?
-                       EDMA_CDNE : EDMA64_CDNE);
-       edma->regs.intl = edma->membase + ((edma->version == v1) ?
-                       EDMA_INTR : EDMA64_INTL);
-       edma->regs.errl = edma->membase + ((edma->version == v1) ?
-                       EDMA_ERR : EDMA64_ERRL);
-
-       if (edma->version == v2) {
+       edma->regs.serq = edma->membase + ((edma->drvdata->version == v2) ?
+                       EDMA64_SERQ : EDMA_SERQ);
+       edma->regs.cerq = edma->membase + ((edma->drvdata->version == v2) ?
+                       EDMA64_CERQ : EDMA_CERQ);
+       edma->regs.seei = edma->membase + ((edma->drvdata->version == v2) ?
+                       EDMA64_SEEI : EDMA_SEEI);
+       edma->regs.ceei = edma->membase + ((edma->drvdata->version == v2) ?
+                       EDMA64_CEEI : EDMA_CEEI);
+       edma->regs.cint = edma->membase + ((edma->drvdata->version == v2) ?
+                       EDMA64_CINT : EDMA_CINT);
+       edma->regs.cerr = edma->membase + ((edma->drvdata->version == v2) ?
+                       EDMA64_CERR : EDMA_CERR);
+       edma->regs.ssrt = edma->membase + ((edma->drvdata->version == v2) ?
+                       EDMA64_SSRT : EDMA_SSRT);
+       edma->regs.cdne = edma->membase + ((edma->drvdata->version == v2) ?
+                       EDMA64_CDNE : EDMA_CDNE);
+       edma->regs.intl = edma->membase + ((edma->drvdata->version == v2) ?
+                       EDMA64_INTL : EDMA_INTR);
+       edma->regs.errl = edma->membase + ((edma->drvdata->version == v2) ?
+                       EDMA64_ERRL : EDMA_ERR);
+
+       if (edma->drvdata->version == v2) {
                edma->regs.erqh = edma->membase + EDMA64_ERQH;
                edma->regs.eeih = edma->membase + EDMA64_EEIH;
                edma->regs.errh = edma->membase + EDMA64_ERRH;
index c53f76e..4e17556 100644 (file)
@@ -7,6 +7,7 @@
 #define _FSL_EDMA_COMMON_H_
 
 #include <linux/dma-direction.h>
+#include <linux/platform_device.h>
 #include "virt-dma.h"
 
 #define EDMA_CR_EDBG           BIT(1)
@@ -140,17 +141,24 @@ enum edma_version {
        v2, /* 64ch Coldfire */
 };
 
+struct fsl_edma_drvdata {
+       enum edma_version       version;
+       u32                     dmamuxs;
+       int                     (*setup_irq)(struct platform_device *pdev,
+                                            struct fsl_edma_engine *fsl_edma);
+};
+
 struct fsl_edma_engine {
        struct dma_device       dma_dev;
        void __iomem            *membase;
        void __iomem            *muxbase[DMAMUX_NR];
        struct clk              *muxclk[DMAMUX_NR];
        struct mutex            fsl_edma_mutex;
+       const struct fsl_edma_drvdata *drvdata;
        u32                     n_chans;
        int                     txirq;
        int                     errirq;
        bool                    big_endian;
-       enum edma_version       version;
        struct edma_regs        regs;
        struct fsl_edma_chan    chans[];
 };
index 0ddad3a..fcbad6a 100644 (file)
@@ -92,7 +92,8 @@ static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec,
        struct fsl_edma_engine *fsl_edma = ofdma->of_dma_data;
        struct dma_chan *chan, *_chan;
        struct fsl_edma_chan *fsl_chan;
-       unsigned long chans_per_mux = fsl_edma->n_chans / DMAMUX_NR;
+       u32 dmamux_nr = fsl_edma->drvdata->dmamuxs;
+       unsigned long chans_per_mux = fsl_edma->n_chans / dmamux_nr;
 
        if (dma_spec->args_count != 2)
                return NULL;
@@ -180,16 +181,38 @@ static void fsl_disable_clocks(struct fsl_edma_engine *fsl_edma, int nr_clocks)
                clk_disable_unprepare(fsl_edma->muxclk[i]);
 }
 
+static struct fsl_edma_drvdata vf610_data = {
+       .version = v1,
+       .dmamuxs = DMAMUX_NR,
+       .setup_irq = fsl_edma_irq_init,
+};
+
+static const struct of_device_id fsl_edma_dt_ids[] = {
+       { .compatible = "fsl,vf610-edma", .data = &vf610_data},
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids);
+
 static int fsl_edma_probe(struct platform_device *pdev)
 {
+       const struct of_device_id *of_id =
+                       of_match_device(fsl_edma_dt_ids, &pdev->dev);
        struct device_node *np = pdev->dev.of_node;
        struct fsl_edma_engine *fsl_edma;
+       const struct fsl_edma_drvdata *drvdata = NULL;
        struct fsl_edma_chan *fsl_chan;
        struct edma_regs *regs;
        struct resource *res;
        int len, chans;
        int ret, i;
 
+       if (of_id)
+               drvdata = of_id->data;
+       if (!drvdata) {
+               dev_err(&pdev->dev, "unable to find driver data\n");
+               return -EINVAL;
+       }
+
        ret = of_property_read_u32(np, "dma-channels", &chans);
        if (ret) {
                dev_err(&pdev->dev, "Can't get dma-channels.\n");
@@ -201,7 +224,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
        if (!fsl_edma)
                return -ENOMEM;
 
-       fsl_edma->version = v1;
+       fsl_edma->drvdata = drvdata;
        fsl_edma->n_chans = chans;
        mutex_init(&fsl_edma->fsl_edma_mutex);
 
@@ -213,7 +236,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
        fsl_edma_setup_regs(fsl_edma);
        regs = &fsl_edma->regs;
 
-       for (i = 0; i < DMAMUX_NR; i++) {
+       for (i = 0; i < fsl_edma->drvdata->dmamuxs; i++) {
                char clkname[32];
 
                res = platform_get_resource(pdev, IORESOURCE_MEM, 1 + i);
@@ -259,7 +282,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
        }
 
        edma_writel(fsl_edma, ~0, regs->intl);
-       ret = fsl_edma_irq_init(pdev, fsl_edma);
+       ret = fsl_edma->drvdata->setup_irq(pdev, fsl_edma);
        if (ret)
                return ret;
 
@@ -291,7 +314,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
        if (ret) {
                dev_err(&pdev->dev,
                        "Can't register Freescale eDMA engine. (%d)\n", ret);
-               fsl_disable_clocks(fsl_edma, DMAMUX_NR);
+               fsl_disable_clocks(fsl_edma, fsl_edma->drvdata->dmamuxs);
                return ret;
        }
 
@@ -300,7 +323,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
                dev_err(&pdev->dev,
                        "Can't register Freescale eDMA of_dma. (%d)\n", ret);
                dma_async_device_unregister(&fsl_edma->dma_dev);
-               fsl_disable_clocks(fsl_edma, DMAMUX_NR);
+               fsl_disable_clocks(fsl_edma, fsl_edma->drvdata->dmamuxs);
                return ret;
        }
 
@@ -319,7 +342,7 @@ static int fsl_edma_remove(struct platform_device *pdev)
        fsl_edma_cleanup_vchan(&fsl_edma->dma_dev);
        of_dma_controller_free(np);
        dma_async_device_unregister(&fsl_edma->dma_dev);
-       fsl_disable_clocks(fsl_edma, DMAMUX_NR);
+       fsl_disable_clocks(fsl_edma, fsl_edma->drvdata->dmamuxs);
 
        return 0;
 }
@@ -378,12 +401,6 @@ static const struct dev_pm_ops fsl_edma_pm_ops = {
        .resume_early   = fsl_edma_resume_early,
 };
 
-static const struct of_device_id fsl_edma_dt_ids[] = {
-       { .compatible = "fsl,vf610-edma", },
-       { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids);
-
 static struct platform_driver fsl_edma_driver = {
        .driver         = {
                .name   = "fsl-edma",
index 60b062c..8e341c0 100644 (file)
 /* Field definition for Descriptor offset */
 #define QDMA_CCDF_STATUS               20
 #define QDMA_CCDF_OFFSET               20
+#define QDMA_SDDF_CMD(x)               (((u64)(x)) << 32)
 
 /* Field definition for safe loop count*/
 #define FSL_QDMA_HALT_COUNT            1500
@@ -341,6 +342,7 @@ static void fsl_qdma_free_chan_resources(struct dma_chan *chan)
 static void fsl_qdma_comp_fill_memcpy(struct fsl_qdma_comp *fsl_comp,
                                      dma_addr_t dst, dma_addr_t src, u32 len)
 {
+       u32 cmd;
        struct fsl_qdma_format *sdf, *ddf;
        struct fsl_qdma_format *ccdf, *csgf_desc, *csgf_src, *csgf_dest;
 
@@ -369,14 +371,14 @@ static void fsl_qdma_comp_fill_memcpy(struct fsl_qdma_comp *fsl_comp,
        /* This entry is the last entry. */
        qdma_csgf_set_f(csgf_dest, len);
        /* Descriptor Buffer */
-       sdf->data =
-               cpu_to_le64(FSL_QDMA_CMD_RWTTYPE <<
-                           FSL_QDMA_CMD_RWTTYPE_OFFSET);
-       ddf->data =
-               cpu_to_le64(FSL_QDMA_CMD_RWTTYPE <<
-                           FSL_QDMA_CMD_RWTTYPE_OFFSET);
-       ddf->data |=
-               cpu_to_le64(FSL_QDMA_CMD_LWC << FSL_QDMA_CMD_LWC_OFFSET);
+       cmd = cpu_to_le32(FSL_QDMA_CMD_RWTTYPE <<
+                         FSL_QDMA_CMD_RWTTYPE_OFFSET);
+       sdf->data = QDMA_SDDF_CMD(cmd);
+
+       cmd = cpu_to_le32(FSL_QDMA_CMD_RWTTYPE <<
+                         FSL_QDMA_CMD_RWTTYPE_OFFSET);
+       cmd |= cpu_to_le32(FSL_QDMA_CMD_LWC << FSL_QDMA_CMD_LWC_OFFSET);
+       ddf->data = QDMA_SDDF_CMD(cmd);
 }
 
 /*
index 0c26100..025d8ad 100644 (file)
@@ -61,10 +61,10 @@ static void hsu_dma_chan_start(struct hsu_dma_chan *hsuc)
 
        if (hsuc->direction == DMA_MEM_TO_DEV) {
                bsr = config->dst_maxburst;
-               mtsr = config->src_addr_width;
+               mtsr = config->dst_addr_width;
        } else if (hsuc->direction == DMA_DEV_TO_MEM) {
                bsr = config->src_maxburst;
-               mtsr = config->dst_addr_width;
+               mtsr = config->src_addr_width;
        }
 
        hsu_chan_disable(hsuc);
index 4ec84a6..a01f4b5 100644 (file)
@@ -1934,16 +1934,11 @@ disable_clk_ipg:
 static bool sdma_filter_fn(struct dma_chan *chan, void *fn_param)
 {
        struct sdma_channel *sdmac = to_sdma_chan(chan);
-       struct sdma_engine *sdma = sdmac->sdma;
        struct imx_dma_data *data = fn_param;
 
        if (!imx_dma_is_general_purpose(chan))
                return false;
 
-       /* return false if it's not the right device */
-       if (sdma->dev->of_node != data->of_node)
-               return false;
-
        sdmac->data = *data;
        chan->private = &sdmac->data;
 
@@ -1971,9 +1966,9 @@ static struct dma_chan *sdma_xlate(struct of_phandle_args *dma_spec,
         * be set to sdmac->event_id1.
         */
        data.dma_request2 = 0;
-       data.of_node = ofdma->of_node;
 
-       return dma_request_channel(mask, sdma_filter_fn, &data);
+       return __dma_request_channel(&mask, sdma_filter_fn, &data,
+                                    ofdma->of_node);
 }
 
 static int sdma_probe(struct platform_device *pdev)
index 7de54b2..e15bd15 100644 (file)
@@ -164,6 +164,11 @@ static void mcf_edma_irq_free(struct platform_device *pdev,
                free_irq(irq, mcf_edma);
 }
 
+static struct fsl_edma_drvdata mcf_data = {
+       .version = v2,
+       .setup_irq = mcf_edma_irq_init,
+};
+
 static int mcf_edma_probe(struct platform_device *pdev)
 {
        struct mcf_edma_platform_data *pdata;
@@ -187,8 +192,8 @@ static int mcf_edma_probe(struct platform_device *pdev)
 
        mcf_edma->n_chans = chans;
 
-       /* Set up version for ColdFire edma */
-       mcf_edma->version = v2;
+       /* Set up drvdata for ColdFire edma */
+       mcf_edma->drvdata = &mcf_data;
        mcf_edma->big_endian = 1;
 
        if (!mcf_edma->n_chans) {
@@ -223,7 +228,7 @@ static int mcf_edma_probe(struct platform_device *pdev)
        iowrite32(~0, regs->inth);
        iowrite32(~0, regs->intl);
 
-       ret = mcf_edma_irq_init(pdev, mcf_edma);
+       ret = mcf_edma->drvdata->setup_irq(pdev, mcf_edma);
        if (ret)
                return ret;
 
index 7411eb3..1ad63dd 100644 (file)
@@ -25,3 +25,14 @@ config MTK_CQDMA
 
          This controller provides the channels which is dedicated to
          memory-to-memory transfer to offload from CPU.
+
+config MTK_UART_APDMA
+       tristate "MediaTek SoCs APDMA support for UART"
+       depends on OF && SERIAL_8250_MT6577
+       select DMA_ENGINE
+       select DMA_VIRTUAL_CHANNELS
+       help
+         Support for the UART DMA engine found on MediaTek MTK SoCs.
+         When SERIAL_8250_MT6577 is enabled, and if you want to use DMA,
+         you can enable the config. The DMA engine can only be used
+         with MediaTek SoCs.
index 13b1445..5ba39a5 100644 (file)
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_MTK_UART_APDMA) += mtk-uart-apdma.o
 obj-$(CONFIG_MTK_HSDMA) += mtk-hsdma.o
 obj-$(CONFIG_MTK_CQDMA) += mtk-cqdma.o
diff --git a/drivers/dma/mediatek/mtk-uart-apdma.c b/drivers/dma/mediatek/mtk-uart-apdma.c
new file mode 100644 (file)
index 0000000..546995c
--- /dev/null
@@ -0,0 +1,666 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek UART APDMA driver.
+ *
+ * Copyright (c) 2019 MediaTek Inc.
+ * Author: Long Cheng <long.cheng@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_dma.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "../virt-dma.h"
+
+/* The default number of virtual channel */
+#define MTK_UART_APDMA_NR_VCHANS       8
+
+#define VFF_EN_B               BIT(0)
+#define VFF_STOP_B             BIT(0)
+#define VFF_FLUSH_B            BIT(0)
+#define VFF_4G_EN_B            BIT(0)
+/* rx valid size >=  vff thre */
+#define VFF_RX_INT_EN_B                (BIT(0) | BIT(1))
+/* tx left size >= vff thre */
+#define VFF_TX_INT_EN_B                BIT(0)
+#define VFF_WARM_RST_B         BIT(0)
+#define VFF_RX_INT_CLR_B       (BIT(0) | BIT(1))
+#define VFF_TX_INT_CLR_B       0
+#define VFF_STOP_CLR_B         0
+#define VFF_EN_CLR_B           0
+#define VFF_INT_EN_CLR_B       0
+#define VFF_4G_SUPPORT_CLR_B   0
+
+/*
+ * interrupt trigger level for tx
+ * if threshold is n, no polling is required to start tx.
+ * otherwise need polling VFF_FLUSH.
+ */
+#define VFF_TX_THRE(n)         (n)
+/* interrupt trigger level for rx */
+#define VFF_RX_THRE(n)         ((n) * 3 / 4)
+
+#define VFF_RING_SIZE  0xffff
+/* invert this bit when wrap ring head again */
+#define VFF_RING_WRAP  0x10000
+
+#define VFF_INT_FLAG           0x00
+#define VFF_INT_EN             0x04
+#define VFF_EN                 0x08
+#define VFF_RST                        0x0c
+#define VFF_STOP               0x10
+#define VFF_FLUSH              0x14
+#define VFF_ADDR               0x1c
+#define VFF_LEN                        0x24
+#define VFF_THRE               0x28
+#define VFF_WPT                        0x2c
+#define VFF_RPT                        0x30
+/* TX: the buffer size HW can read. RX: the buffer size SW can read. */
+#define VFF_VALID_SIZE         0x3c
+/* TX: the buffer size SW can write. RX: the buffer size HW can write. */
+#define VFF_LEFT_SIZE          0x40
+#define VFF_DEBUG_STATUS       0x50
+#define VFF_4G_SUPPORT         0x54
+
+struct mtk_uart_apdmadev {
+       struct dma_device ddev;
+       struct clk *clk;
+       bool support_33bits;
+       unsigned int dma_requests;
+};
+
+struct mtk_uart_apdma_desc {
+       struct virt_dma_desc vd;
+
+       dma_addr_t addr;
+       unsigned int avail_len;
+};
+
+struct mtk_chan {
+       struct virt_dma_chan vc;
+       struct dma_slave_config cfg;
+       struct mtk_uart_apdma_desc *desc;
+       enum dma_transfer_direction dir;
+
+       void __iomem *base;
+       unsigned int irq;
+
+       unsigned int rx_status;
+};
+
+static inline struct mtk_uart_apdmadev *
+to_mtk_uart_apdma_dev(struct dma_device *d)
+{
+       return container_of(d, struct mtk_uart_apdmadev, ddev);
+}
+
+static inline struct mtk_chan *to_mtk_uart_apdma_chan(struct dma_chan *c)
+{
+       return container_of(c, struct mtk_chan, vc.chan);
+}
+
+static inline struct mtk_uart_apdma_desc *to_mtk_uart_apdma_desc
+       (struct dma_async_tx_descriptor *t)
+{
+       return container_of(t, struct mtk_uart_apdma_desc, vd.tx);
+}
+
+static void mtk_uart_apdma_write(struct mtk_chan *c,
+                              unsigned int reg, unsigned int val)
+{
+       writel(val, c->base + reg);
+}
+
+static unsigned int mtk_uart_apdma_read(struct mtk_chan *c, unsigned int reg)
+{
+       return readl(c->base + 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);
+}
+
+static void mtk_uart_apdma_start_tx(struct mtk_chan *c)
+{
+       struct mtk_uart_apdmadev *mtkd =
+                               to_mtk_uart_apdma_dev(c->vc.chan.device);
+       struct mtk_uart_apdma_desc *d = c->desc;
+       unsigned int wpt, vff_sz;
+
+       vff_sz = c->cfg.dst_port_window_size;
+       if (!mtk_uart_apdma_read(c, VFF_LEN)) {
+               mtk_uart_apdma_write(c, VFF_ADDR, d->addr);
+               mtk_uart_apdma_write(c, VFF_LEN, vff_sz);
+               mtk_uart_apdma_write(c, VFF_THRE, VFF_TX_THRE(vff_sz));
+               mtk_uart_apdma_write(c, VFF_WPT, 0);
+               mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B);
+
+               if (mtkd->support_33bits)
+                       mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B);
+       }
+
+       mtk_uart_apdma_write(c, VFF_EN, VFF_EN_B);
+       if (mtk_uart_apdma_read(c, VFF_EN) != VFF_EN_B)
+               dev_err(c->vc.chan.device->dev, "Enable TX fail\n");
+
+       if (!mtk_uart_apdma_read(c, VFF_LEFT_SIZE)) {
+               mtk_uart_apdma_write(c, VFF_INT_EN, VFF_TX_INT_EN_B);
+               return;
+       }
+
+       wpt = mtk_uart_apdma_read(c, VFF_WPT);
+
+       wpt += c->desc->avail_len;
+       if ((wpt & VFF_RING_SIZE) == vff_sz)
+               wpt = (wpt & VFF_RING_WRAP) ^ VFF_RING_WRAP;
+
+       /* Let DMA start moving data */
+       mtk_uart_apdma_write(c, VFF_WPT, wpt);
+
+       /* HW auto set to 0 when left size >= threshold */
+       mtk_uart_apdma_write(c, VFF_INT_EN, VFF_TX_INT_EN_B);
+       if (!mtk_uart_apdma_read(c, VFF_FLUSH))
+               mtk_uart_apdma_write(c, VFF_FLUSH, VFF_FLUSH_B);
+}
+
+static void mtk_uart_apdma_start_rx(struct mtk_chan *c)
+{
+       struct mtk_uart_apdmadev *mtkd =
+                               to_mtk_uart_apdma_dev(c->vc.chan.device);
+       struct mtk_uart_apdma_desc *d = c->desc;
+       unsigned int vff_sz;
+
+       vff_sz = c->cfg.src_port_window_size;
+       if (!mtk_uart_apdma_read(c, VFF_LEN)) {
+               mtk_uart_apdma_write(c, VFF_ADDR, d->addr);
+               mtk_uart_apdma_write(c, VFF_LEN, vff_sz);
+               mtk_uart_apdma_write(c, VFF_THRE, VFF_RX_THRE(vff_sz));
+               mtk_uart_apdma_write(c, VFF_RPT, 0);
+               mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_RX_INT_CLR_B);
+
+               if (mtkd->support_33bits)
+                       mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B);
+       }
+
+       mtk_uart_apdma_write(c, VFF_INT_EN, VFF_RX_INT_EN_B);
+       mtk_uart_apdma_write(c, VFF_EN, VFF_EN_B);
+       if (mtk_uart_apdma_read(c, VFF_EN) != VFF_EN_B)
+               dev_err(c->vc.chan.device->dev, "Enable RX fail\n");
+}
+
+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)
+{
+       struct mtk_uart_apdma_desc *d = c->desc;
+       unsigned int len, wg, rg;
+       int cnt;
+
+       mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_RX_INT_CLR_B);
+
+       if (!mtk_uart_apdma_read(c, VFF_VALID_SIZE))
+               return;
+
+       mtk_uart_apdma_write(c, VFF_EN, VFF_EN_CLR_B);
+       mtk_uart_apdma_write(c, VFF_INT_EN, VFF_INT_EN_CLR_B);
+
+       len = c->cfg.src_port_window_size;
+       rg = mtk_uart_apdma_read(c, VFF_RPT);
+       wg = mtk_uart_apdma_read(c, VFF_WPT);
+       cnt = (wg & VFF_RING_SIZE) - (rg & VFF_RING_SIZE);
+
+       /*
+        * The buffer is ring buffer. If wrap bit different,
+        * represents the start of the next cycle for WPT
+        */
+       if ((rg ^ wg) & VFF_RING_WRAP)
+               cnt += len;
+
+       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 irqreturn_t mtk_uart_apdma_irq_handler(int irq, void *dev_id)
+{
+       struct dma_chan *chan = (struct dma_chan *)dev_id;
+       struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+       unsigned long flags;
+
+       spin_lock_irqsave(&c->vc.lock, flags);
+       if (c->dir == DMA_DEV_TO_MEM)
+               mtk_uart_apdma_rx_handler(c);
+       else if (c->dir == DMA_MEM_TO_DEV)
+               mtk_uart_apdma_tx_handler(c);
+       spin_unlock_irqrestore(&c->vc.lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+static int mtk_uart_apdma_alloc_chan_resources(struct dma_chan *chan)
+{
+       struct mtk_uart_apdmadev *mtkd = to_mtk_uart_apdma_dev(chan->device);
+       struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+       unsigned int status;
+       int ret;
+
+       ret = pm_runtime_get_sync(mtkd->ddev.dev);
+       if (ret < 0) {
+               pm_runtime_put_noidle(chan->device->dev);
+               return ret;
+       }
+
+       mtk_uart_apdma_write(c, VFF_ADDR, 0);
+       mtk_uart_apdma_write(c, VFF_THRE, 0);
+       mtk_uart_apdma_write(c, VFF_LEN, 0);
+       mtk_uart_apdma_write(c, VFF_RST, VFF_WARM_RST_B);
+
+       ret = readx_poll_timeout(readl, c->base + VFF_EN,
+                         status, !status, 10, 100);
+       if (ret)
+               return ret;
+
+       ret = request_irq(c->irq, mtk_uart_apdma_irq_handler,
+                         IRQF_TRIGGER_NONE, KBUILD_MODNAME, chan);
+       if (ret < 0) {
+               dev_err(chan->device->dev, "Can't request dma IRQ\n");
+               return -EINVAL;
+       }
+
+       if (mtkd->support_33bits)
+               mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_SUPPORT_CLR_B);
+
+       return ret;
+}
+
+static void mtk_uart_apdma_free_chan_resources(struct dma_chan *chan)
+{
+       struct mtk_uart_apdmadev *mtkd = to_mtk_uart_apdma_dev(chan->device);
+       struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+
+       free_irq(c->irq, chan);
+
+       tasklet_kill(&c->vc.task);
+
+       vchan_free_chan_resources(&c->vc);
+
+       pm_runtime_put_sync(mtkd->ddev.dev);
+}
+
+static enum dma_status mtk_uart_apdma_tx_status(struct dma_chan *chan,
+                                        dma_cookie_t cookie,
+                                        struct dma_tx_state *txstate)
+{
+       struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+       enum dma_status ret;
+
+       ret = dma_cookie_status(chan, cookie, txstate);
+       if (!txstate)
+               return ret;
+
+       dma_set_residue(txstate, c->rx_status);
+
+       return ret;
+}
+
+/*
+ * dmaengine_prep_slave_single will call the function. and sglen is 1.
+ * 8250 uart using one ring buffer, and deal with one sg.
+ */
+static struct dma_async_tx_descriptor *mtk_uart_apdma_prep_slave_sg
+       (struct dma_chan *chan, struct scatterlist *sgl,
+       unsigned int sglen, enum dma_transfer_direction dir,
+       unsigned long tx_flags, void *context)
+{
+       struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+       struct mtk_uart_apdma_desc *d;
+
+       if (!is_slave_direction(dir) || sglen != 1)
+               return NULL;
+
+       /* Now allocate and setup the descriptor */
+       d = kzalloc(sizeof(*d), GFP_ATOMIC);
+       if (!d)
+               return NULL;
+
+       d->avail_len = sg_dma_len(sgl);
+       d->addr = sg_dma_address(sgl);
+       c->dir = dir;
+
+       return vchan_tx_prep(&c->vc, &d->vd, tx_flags);
+}
+
+static void mtk_uart_apdma_issue_pending(struct dma_chan *chan)
+{
+       struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+       struct virt_dma_desc *vd;
+       unsigned long flags;
+
+       spin_lock_irqsave(&c->vc.lock, flags);
+       if (vchan_issue_pending(&c->vc)) {
+               vd = vchan_next_desc(&c->vc);
+               c->desc = to_mtk_uart_apdma_desc(&vd->tx);
+
+               if (c->dir == DMA_DEV_TO_MEM)
+                       mtk_uart_apdma_start_rx(c);
+               else if (c->dir == DMA_MEM_TO_DEV)
+                       mtk_uart_apdma_start_tx(c);
+       }
+
+       spin_unlock_irqrestore(&c->vc.lock, flags);
+}
+
+static int mtk_uart_apdma_slave_config(struct dma_chan *chan,
+                                  struct dma_slave_config *config)
+{
+       struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+
+       memcpy(&c->cfg, config, sizeof(*config));
+
+       return 0;
+}
+
+static int mtk_uart_apdma_terminate_all(struct dma_chan *chan)
+{
+       struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+       unsigned long flags;
+       unsigned int status;
+       LIST_HEAD(head);
+       int ret;
+
+       mtk_uart_apdma_write(c, VFF_FLUSH, VFF_FLUSH_B);
+
+       ret = readx_poll_timeout(readl, c->base + VFF_FLUSH,
+                         status, status != VFF_FLUSH_B, 10, 100);
+       if (ret)
+               dev_err(c->vc.chan.device->dev, "flush: fail, status=0x%x\n",
+                       mtk_uart_apdma_read(c, VFF_DEBUG_STATUS));
+
+       /*
+        * Stop need 3 steps.
+        * 1. set stop to 1
+        * 2. wait en to 0
+        * 3. set stop as 0
+        */
+       mtk_uart_apdma_write(c, VFF_STOP, VFF_STOP_B);
+       ret = readx_poll_timeout(readl, c->base + VFF_EN,
+                         status, !status, 10, 100);
+       if (ret)
+               dev_err(c->vc.chan.device->dev, "stop: fail, status=0x%x\n",
+                       mtk_uart_apdma_read(c, VFF_DEBUG_STATUS));
+
+       mtk_uart_apdma_write(c, VFF_STOP, VFF_STOP_CLR_B);
+       mtk_uart_apdma_write(c, VFF_INT_EN, VFF_INT_EN_CLR_B);
+
+       if (c->dir == DMA_DEV_TO_MEM)
+               mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_RX_INT_CLR_B);
+       else if (c->dir == DMA_MEM_TO_DEV)
+               mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B);
+
+       synchronize_irq(c->irq);
+
+       spin_lock_irqsave(&c->vc.lock, flags);
+       vchan_get_all_descriptors(&c->vc, &head);
+       vchan_dma_desc_free_list(&c->vc, &head);
+       spin_unlock_irqrestore(&c->vc.lock, flags);
+
+       return 0;
+}
+
+static int mtk_uart_apdma_device_pause(struct dma_chan *chan)
+{
+       struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+       unsigned long flags;
+
+       spin_lock_irqsave(&c->vc.lock, flags);
+
+       mtk_uart_apdma_write(c, VFF_EN, VFF_EN_CLR_B);
+       mtk_uart_apdma_write(c, VFF_INT_EN, VFF_INT_EN_CLR_B);
+
+       synchronize_irq(c->irq);
+
+       spin_unlock_irqrestore(&c->vc.lock, flags);
+
+       return 0;
+}
+
+static void mtk_uart_apdma_free(struct mtk_uart_apdmadev *mtkd)
+{
+       while (!list_empty(&mtkd->ddev.channels)) {
+               struct mtk_chan *c = list_first_entry(&mtkd->ddev.channels,
+                       struct mtk_chan, vc.chan.device_node);
+
+               list_del(&c->vc.chan.device_node);
+               tasklet_kill(&c->vc.task);
+       }
+}
+
+static const struct of_device_id mtk_uart_apdma_match[] = {
+       { .compatible = "mediatek,mt6577-uart-dma", },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mtk_uart_apdma_match);
+
+static int mtk_uart_apdma_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct mtk_uart_apdmadev *mtkd;
+       int bit_mask = 32, rc;
+       struct resource *res;
+       struct mtk_chan *c;
+       unsigned int i;
+
+       mtkd = devm_kzalloc(&pdev->dev, sizeof(*mtkd), GFP_KERNEL);
+       if (!mtkd)
+               return -ENOMEM;
+
+       mtkd->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(mtkd->clk)) {
+               dev_err(&pdev->dev, "No clock specified\n");
+               rc = PTR_ERR(mtkd->clk);
+               return rc;
+       }
+
+       if (of_property_read_bool(np, "mediatek,dma-33bits"))
+               mtkd->support_33bits = true;
+
+       if (mtkd->support_33bits)
+               bit_mask = 33;
+
+       rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(bit_mask));
+       if (rc)
+               return rc;
+
+       dma_cap_set(DMA_SLAVE, mtkd->ddev.cap_mask);
+       mtkd->ddev.device_alloc_chan_resources =
+                               mtk_uart_apdma_alloc_chan_resources;
+       mtkd->ddev.device_free_chan_resources =
+                               mtk_uart_apdma_free_chan_resources;
+       mtkd->ddev.device_tx_status = mtk_uart_apdma_tx_status;
+       mtkd->ddev.device_issue_pending = mtk_uart_apdma_issue_pending;
+       mtkd->ddev.device_prep_slave_sg = mtk_uart_apdma_prep_slave_sg;
+       mtkd->ddev.device_config = mtk_uart_apdma_slave_config;
+       mtkd->ddev.device_pause = mtk_uart_apdma_device_pause;
+       mtkd->ddev.device_terminate_all = mtk_uart_apdma_terminate_all;
+       mtkd->ddev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE);
+       mtkd->ddev.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE);
+       mtkd->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+       mtkd->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
+       mtkd->ddev.dev = &pdev->dev;
+       INIT_LIST_HEAD(&mtkd->ddev.channels);
+
+       mtkd->dma_requests = MTK_UART_APDMA_NR_VCHANS;
+       if (of_property_read_u32(np, "dma-requests", &mtkd->dma_requests)) {
+               dev_info(&pdev->dev,
+                        "Using %u as missing dma-requests property\n",
+                        MTK_UART_APDMA_NR_VCHANS);
+       }
+
+       for (i = 0; i < mtkd->dma_requests; i++) {
+               c = devm_kzalloc(mtkd->ddev.dev, sizeof(*c), GFP_KERNEL);
+               if (!c) {
+                       rc = -ENODEV;
+                       goto err_no_dma;
+               }
+
+               res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+               if (!res) {
+                       rc = -ENODEV;
+                       goto err_no_dma;
+               }
+
+               c->base = devm_ioremap_resource(&pdev->dev, res);
+               if (IS_ERR(c->base)) {
+                       rc = PTR_ERR(c->base);
+                       goto err_no_dma;
+               }
+               c->vc.desc_free = mtk_uart_apdma_desc_free;
+               vchan_init(&c->vc, &mtkd->ddev);
+
+               rc = platform_get_irq(pdev, i);
+               if (rc < 0) {
+                       dev_err(&pdev->dev, "failed to get IRQ[%d]\n", i);
+                       goto err_no_dma;
+               }
+               c->irq = rc;
+       }
+
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_set_active(&pdev->dev);
+
+       rc = dma_async_device_register(&mtkd->ddev);
+       if (rc)
+               goto rpm_disable;
+
+       platform_set_drvdata(pdev, mtkd);
+
+       /* Device-tree DMA controller registration */
+       rc = of_dma_controller_register(np, of_dma_xlate_by_chan_id, mtkd);
+       if (rc)
+               goto dma_remove;
+
+       return rc;
+
+dma_remove:
+       dma_async_device_unregister(&mtkd->ddev);
+rpm_disable:
+       pm_runtime_disable(&pdev->dev);
+err_no_dma:
+       mtk_uart_apdma_free(mtkd);
+       return rc;
+}
+
+static int mtk_uart_apdma_remove(struct platform_device *pdev)
+{
+       struct mtk_uart_apdmadev *mtkd = platform_get_drvdata(pdev);
+
+       of_dma_controller_free(pdev->dev.of_node);
+
+       mtk_uart_apdma_free(mtkd);
+
+       dma_async_device_unregister(&mtkd->ddev);
+
+       pm_runtime_disable(&pdev->dev);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mtk_uart_apdma_suspend(struct device *dev)
+{
+       struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
+
+       if (!pm_runtime_suspended(dev))
+               clk_disable_unprepare(mtkd->clk);
+
+       return 0;
+}
+
+static int mtk_uart_apdma_resume(struct device *dev)
+{
+       int ret;
+       struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
+
+       if (!pm_runtime_suspended(dev)) {
+               ret = clk_prepare_enable(mtkd->clk);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM
+static int mtk_uart_apdma_runtime_suspend(struct device *dev)
+{
+       struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(mtkd->clk);
+
+       return 0;
+}
+
+static int mtk_uart_apdma_runtime_resume(struct device *dev)
+{
+       int ret;
+       struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
+
+       ret = clk_prepare_enable(mtkd->clk);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops mtk_uart_apdma_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(mtk_uart_apdma_suspend, mtk_uart_apdma_resume)
+       SET_RUNTIME_PM_OPS(mtk_uart_apdma_runtime_suspend,
+                          mtk_uart_apdma_runtime_resume, NULL)
+};
+
+static struct platform_driver mtk_uart_apdma_driver = {
+       .probe  = mtk_uart_apdma_probe,
+       .remove = mtk_uart_apdma_remove,
+       .driver = {
+               .name           = KBUILD_MODNAME,
+               .pm             = &mtk_uart_apdma_pm_ops,
+               .of_match_table = of_match_ptr(mtk_uart_apdma_match),
+       },
+};
+
+module_platform_driver(mtk_uart_apdma_driver);
+
+MODULE_DESCRIPTION("MediaTek UART APDMA Controller Driver");
+MODULE_AUTHOR("Long Cheng <long.cheng@mediatek.com>");
+MODULE_LICENSE("GPL v2");
index 730a18d..fea8608 100644 (file)
@@ -717,10 +717,8 @@ static int mic_dma_driver_probe(struct mbus_device *mbdev)
        if (mic_dma_dbg) {
                mic_dma_dev->dbg_dir = debugfs_create_dir(dev_name(&mbdev->dev),
                                                          mic_dma_dbg);
-               if (mic_dma_dev->dbg_dir)
-                       debugfs_create_file("mic_dma_reg", 0444,
-                                           mic_dma_dev->dbg_dir, mic_dma_dev,
-                                           &mic_dma_reg_fops);
+               debugfs_create_file("mic_dma_reg", 0444, mic_dma_dev->dbg_dir,
+                                   mic_dma_dev, &mic_dma_reg_fops);
        }
        return 0;
 }
index bb3ccbf..e7d1e12 100644 (file)
@@ -582,18 +582,12 @@ static int mmp_tdma_chan_init(struct mmp_tdma_device *tdev,
 }
 
 struct mmp_tdma_filter_param {
-       struct device_node *of_node;
        unsigned int chan_id;
 };
 
 static bool mmp_tdma_filter_fn(struct dma_chan *chan, void *fn_param)
 {
        struct mmp_tdma_filter_param *param = fn_param;
-       struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
-       struct dma_device *pdma_device = tdmac->chan.device;
-
-       if (pdma_device->dev->of_node != param->of_node)
-               return false;
 
        if (chan->chan_id != param->chan_id)
                return false;
@@ -611,13 +605,13 @@ static struct dma_chan *mmp_tdma_xlate(struct of_phandle_args *dma_spec,
        if (dma_spec->args_count != 1)
                return NULL;
 
-       param.of_node = ofdma->of_node;
        param.chan_id = dma_spec->args[0];
 
        if (param.chan_id >= TDMA_CHANNEL_NUM)
                return NULL;
 
-       return dma_request_channel(mask, mmp_tdma_filter_fn, &param);
+       return __dma_request_channel(&mask, mmp_tdma_filter_fn, &param,
+                                    ofdma->of_node);
 }
 
 static const struct of_device_id mmp_tdma_dt_ids[] = {
index 20a9cb7..3039bba 100644 (file)
@@ -719,7 +719,6 @@ err_out:
 }
 
 struct mxs_dma_filter_param {
-       struct device_node *of_node;
        unsigned int chan_id;
 };
 
@@ -730,9 +729,6 @@ static bool mxs_dma_filter_fn(struct dma_chan *chan, void *fn_param)
        struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
        int chan_irq;
 
-       if (mxs_dma->dma_device.dev->of_node != param->of_node)
-               return false;
-
        if (chan->chan_id != param->chan_id)
                return false;
 
@@ -755,13 +751,13 @@ static struct dma_chan *mxs_dma_xlate(struct of_phandle_args *dma_spec,
        if (dma_spec->args_count != 1)
                return NULL;
 
-       param.of_node = ofdma->of_node;
        param.chan_id = dma_spec->args[0];
 
        if (param.chan_id >= mxs_dma->nr_channels)
                return NULL;
 
-       return dma_request_channel(mask, mxs_dma_filter_fn, &param);
+       return __dma_request_channel(&mask, mxs_dma_filter_fn, &param,
+                                    ofdma->of_node);
 }
 
 static int __init mxs_dma_probe(struct platform_device *pdev)
index 1e4d9ef..c2d779d 100644 (file)
@@ -313,8 +313,8 @@ struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
        if (count != 1)
                return NULL;
 
-       return dma_request_channel(info->dma_cap, info->filter_fn,
-                       &dma_spec->args[0]);
+       return __dma_request_channel(&info->dma_cap, info->filter_fn,
+                                    &dma_spec->args[0], dma_spec->np);
 }
 EXPORT_SYMBOL_GPL(of_dma_simple_xlate);
 
index 56f9fab..1163af2 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/err.h>
 #include <linux/pm_runtime.h>
 #include <linux/bug.h>
+#include <linux/reset.h>
 
 #include "dmaengine.h"
 #define PL330_MAX_CHAN         8
@@ -496,6 +497,9 @@ struct pl330_dmac {
        unsigned int num_peripherals;
        struct dma_pl330_chan *peripherals; /* keep at end */
        int quirks;
+
+       struct reset_control    *rstc;
+       struct reset_control    *rstc_ocp;
 };
 
 static struct pl330_of_quirks {
@@ -3024,6 +3028,32 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
 
        amba_set_drvdata(adev, pl330);
 
+       pl330->rstc = devm_reset_control_get_optional(&adev->dev, "dma");
+       if (IS_ERR(pl330->rstc)) {
+               if (PTR_ERR(pl330->rstc) != -EPROBE_DEFER)
+                       dev_err(&adev->dev, "Failed to get reset!\n");
+               return PTR_ERR(pl330->rstc);
+       } else {
+               ret = reset_control_deassert(pl330->rstc);
+               if (ret) {
+                       dev_err(&adev->dev, "Couldn't deassert the device from reset!\n");
+                       return ret;
+               }
+       }
+
+       pl330->rstc_ocp = devm_reset_control_get_optional(&adev->dev, "dma-ocp");
+       if (IS_ERR(pl330->rstc_ocp)) {
+               if (PTR_ERR(pl330->rstc_ocp) != -EPROBE_DEFER)
+                       dev_err(&adev->dev, "Failed to get OCP reset!\n");
+               return PTR_ERR(pl330->rstc_ocp);
+       } else {
+               ret = reset_control_deassert(pl330->rstc_ocp);
+               if (ret) {
+                       dev_err(&adev->dev, "Couldn't deassert the device from OCP reset!\n");
+                       return ret;
+               }
+       }
+
        for (i = 0; i < AMBA_NR_IRQS; i++) {
                irq = adev->irq[i];
                if (irq) {
@@ -3164,6 +3194,11 @@ probe_err3:
 probe_err2:
        pl330_del(pl330);
 
+       if (pl330->rstc_ocp)
+               reset_control_assert(pl330->rstc_ocp);
+
+       if (pl330->rstc)
+               reset_control_assert(pl330->rstc);
        return ret;
 }
 
@@ -3202,6 +3237,11 @@ static int pl330_remove(struct amba_device *adev)
 
        pl330_del(pl330);
 
+       if (pl330->rstc_ocp)
+               reset_control_assert(pl330->rstc_ocp);
+
+       if (pl330->rstc)
+               reset_control_assert(pl330->rstc);
        return 0;
 }
 
index 468c234..349fb31 100644 (file)
@@ -129,7 +129,6 @@ struct pxad_device {
        spinlock_t                      phy_lock;       /* Phy association */
 #ifdef CONFIG_DEBUG_FS
        struct dentry                   *dbgfs_root;
-       struct dentry                   *dbgfs_state;
        struct dentry                   **dbgfs_chan;
 #endif
 };
@@ -323,31 +322,18 @@ static struct dentry *pxad_dbg_alloc_chan(struct pxad_device *pdev,
                                             int ch, struct dentry *chandir)
 {
        char chan_name[11];
-       struct dentry *chan, *chan_state = NULL, *chan_descr = NULL;
-       struct dentry *chan_reqs = NULL;
+       struct dentry *chan;
        void *dt;
 
        scnprintf(chan_name, sizeof(chan_name), "%d", ch);
        chan = debugfs_create_dir(chan_name, chandir);
        dt = (void *)&pdev->phys[ch];
 
-       if (chan)
-               chan_state = debugfs_create_file("state", 0400, chan, dt,
-                                                &chan_state_fops);
-       if (chan_state)
-               chan_descr = debugfs_create_file("descriptors", 0400, chan, dt,
-                                                &descriptors_fops);
-       if (chan_descr)
-               chan_reqs = debugfs_create_file("requesters", 0400, chan, dt,
-                                               &requester_chan_fops);
-       if (!chan_reqs)
-               goto err_state;
+       debugfs_create_file("state", 0400, chan, dt, &chan_state_fops);
+       debugfs_create_file("descriptors", 0400, chan, dt, &descriptors_fops);
+       debugfs_create_file("requesters", 0400, chan, dt, &requester_chan_fops);
 
        return chan;
-
-err_state:
-       debugfs_remove_recursive(chan);
-       return NULL;
 }
 
 static void pxad_init_debugfs(struct pxad_device *pdev)
@@ -355,40 +341,20 @@ static void pxad_init_debugfs(struct pxad_device *pdev)
        int i;
        struct dentry *chandir;
 
-       pdev->dbgfs_root = debugfs_create_dir(dev_name(pdev->slave.dev), NULL);
-       if (IS_ERR(pdev->dbgfs_root) || !pdev->dbgfs_root)
-               goto err_root;
-
-       pdev->dbgfs_state = debugfs_create_file("state", 0400, pdev->dbgfs_root,
-                                               pdev, &state_fops);
-       if (!pdev->dbgfs_state)
-               goto err_state;
-
        pdev->dbgfs_chan =
-               kmalloc_array(pdev->nr_chans, sizeof(*pdev->dbgfs_state),
+               kmalloc_array(pdev->nr_chans, sizeof(struct dentry *),
                              GFP_KERNEL);
        if (!pdev->dbgfs_chan)
-               goto err_alloc;
+               return;
+
+       pdev->dbgfs_root = debugfs_create_dir(dev_name(pdev->slave.dev), NULL);
+
+       debugfs_create_file("state", 0400, pdev->dbgfs_root, pdev, &state_fops);
 
        chandir = debugfs_create_dir("channels", pdev->dbgfs_root);
-       if (!chandir)
-               goto err_chandir;
 
-       for (i = 0; i < pdev->nr_chans; i++) {
+       for (i = 0; i < pdev->nr_chans; i++)
                pdev->dbgfs_chan[i] = pxad_dbg_alloc_chan(pdev, i, chandir);
-               if (!pdev->dbgfs_chan[i])
-                       goto err_chans;
-       }
-
-       return;
-err_chans:
-err_chandir:
-       kfree(pdev->dbgfs_chan);
-err_alloc:
-err_state:
-       debugfs_remove_recursive(pdev->dbgfs_root);
-err_root:
-       pr_err("pxad: debugfs is not available\n");
 }
 
 static void pxad_cleanup_debugfs(struct pxad_device *pdev)
index f337e27..f212466 100644 (file)
@@ -93,8 +93,6 @@ struct hidma_chan {
         * It is used by the DMA complete notification to
         * locate the descriptor that initiated the transfer.
         */
-       struct dentry                   *debugfs;
-       struct dentry                   *stats;
        struct hidma_dev                *dmadev;
        struct hidma_desc               *running;
 
@@ -126,7 +124,6 @@ struct hidma_dev {
        struct dma_device               ddev;
 
        struct dentry                   *debugfs;
-       struct dentry                   *stats;
 
        /* sysfs entry for the channel id */
        struct device_attribute         *chid_attrs;
@@ -158,6 +155,6 @@ irqreturn_t hidma_ll_inthandler(int irq, void *arg);
 irqreturn_t hidma_ll_inthandler_msi(int irq, void *arg, int cause);
 void hidma_cleanup_pending_tre(struct hidma_lldev *llhndl, u8 err_info,
                                u8 err_code);
-int hidma_debug_init(struct hidma_dev *dmadev);
+void hidma_debug_init(struct hidma_dev *dmadev);
 void hidma_debug_uninit(struct hidma_dev *dmadev);
 #endif
index 75b0691..ce87c79 100644 (file)
@@ -138,17 +138,13 @@ void hidma_debug_uninit(struct hidma_dev *dmadev)
        debugfs_remove_recursive(dmadev->debugfs);
 }
 
-int hidma_debug_init(struct hidma_dev *dmadev)
+void hidma_debug_init(struct hidma_dev *dmadev)
 {
-       int rc = 0;
        int chidx = 0;
        struct list_head *position = NULL;
+       struct dentry *dir;
 
        dmadev->debugfs = debugfs_create_dir(dev_name(dmadev->ddev.dev), NULL);
-       if (!dmadev->debugfs) {
-               rc = -ENODEV;
-               return rc;
-       }
 
        /* walk through the virtual channel list */
        list_for_each(position, &dmadev->ddev.channels) {
@@ -157,32 +153,13 @@ int hidma_debug_init(struct hidma_dev *dmadev)
                chan = list_entry(position, struct hidma_chan,
                                  chan.device_node);
                sprintf(chan->dbg_name, "chan%d", chidx);
-               chan->debugfs = debugfs_create_dir(chan->dbg_name,
+               dir = debugfs_create_dir(chan->dbg_name,
                                                   dmadev->debugfs);
-               if (!chan->debugfs) {
-                       rc = -ENOMEM;
-                       goto cleanup;
-               }
-               chan->stats = debugfs_create_file("stats", S_IRUGO,
-                                                 chan->debugfs, chan,
-                                                 &hidma_chan_fops);
-               if (!chan->stats) {
-                       rc = -ENOMEM;
-                       goto cleanup;
-               }
+               debugfs_create_file("stats", S_IRUGO, dir, chan,
+                                   &hidma_chan_fops);
                chidx++;
        }
 
-       dmadev->stats = debugfs_create_file("stats", S_IRUGO,
-                                           dmadev->debugfs, dmadev,
-                                           &hidma_dma_fops);
-       if (!dmadev->stats) {
-               rc = -ENOMEM;
-               goto cleanup;
-       }
-
-       return 0;
-cleanup:
-       hidma_debug_uninit(dmadev);
-       return rc;
+       debugfs_create_file("stats", S_IRUGO, dmadev->debugfs, dmadev,
+                           &hidma_dma_fops);
 }
index 4d6b02b..54d5d03 100644 (file)
@@ -47,9 +47,3 @@ config RENESAS_USB_DMAC
        help
          This driver supports the USB-DMA controller found in the Renesas
          SoCs.
-
-config SUDMAC
-       tristate "Renesas SUDMAC support"
-       depends on SH_DMAE_BASE
-       help
-         Enable support for the Renesas SUDMAC controllers.
index 42110dd..112fbd2 100644 (file)
@@ -15,4 +15,3 @@ obj-$(CONFIG_SH_DMAE) += shdma.o
 
 obj-$(CONFIG_RCAR_DMAC) += rcar-dmac.o
 obj-$(CONFIG_RENESAS_USB_DMAC) += usb-dmac.o
-obj-$(CONFIG_SUDMAC) += sudmac.o
index 33ab1b6..9c41a4e 100644 (file)
@@ -1165,7 +1165,7 @@ rcar_dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
        struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
 
        /* Someone calling slave DMA on a generic channel? */
-       if (rchan->mid_rid < 0 || !sg_len) {
+       if (rchan->mid_rid < 0 || !sg_len || !sg_dma_len(sgl)) {
                dev_warn(chan->device->dev,
                         "%s: bad parameter: len=%d, id=%d\n",
                         __func__, sg_len, rchan->mid_rid);
@@ -1654,8 +1654,7 @@ static bool rcar_dmac_chan_filter(struct dma_chan *chan, void *arg)
         * Forcing it to call dma_request_channel() and iterate through all
         * channels from all controllers is just pointless.
         */
-       if (chan->device->device_config != rcar_dmac_device_config ||
-           dma_spec->np != chan->device->dev->of_node)
+       if (chan->device->device_config != rcar_dmac_device_config)
                return false;
 
        return !test_and_set_bit(dma_spec->args[0], dmac->modules);
@@ -1675,7 +1674,8 @@ static struct dma_chan *rcar_dmac_of_xlate(struct of_phandle_args *dma_spec,
        dma_cap_zero(mask);
        dma_cap_set(DMA_SLAVE, mask);
 
-       chan = dma_request_channel(mask, rcar_dmac_chan_filter, dma_spec);
+       chan = __dma_request_channel(&mask, rcar_dmac_chan_filter, dma_spec,
+                                    ofdma->of_node);
        if (!chan)
                return NULL;
 
diff --git a/drivers/dma/sh/sudmac.c b/drivers/dma/sh/sudmac.c
deleted file mode 100644 (file)
index 30cc355..0000000
+++ /dev/null
@@ -1,414 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas SUDMAC support
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- *
- * based on drivers/dma/sh/shdma.c:
- * Copyright (C) 2011-2012 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- * Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
- * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
- * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
- */
-
-#include <linux/dmaengine.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/sudmac.h>
-
-struct sudmac_chan {
-       struct shdma_chan shdma_chan;
-       void __iomem *base;
-       char dev_id[16];        /* unique name per DMAC of channel */
-
-       u32 offset;             /* for CFG, BA, BBC, CA, CBC, DEN */
-       u32 cfg;
-       u32 dint_end_bit;
-};
-
-struct sudmac_device {
-       struct shdma_dev shdma_dev;
-       struct sudmac_pdata *pdata;
-       void __iomem *chan_reg;
-};
-
-struct sudmac_regs {
-       u32 base_addr;
-       u32 base_byte_count;
-};
-
-struct sudmac_desc {
-       struct sudmac_regs hw;
-       struct shdma_desc shdma_desc;
-};
-
-#define to_chan(schan) container_of(schan, struct sudmac_chan, shdma_chan)
-#define to_desc(sdesc) container_of(sdesc, struct sudmac_desc, shdma_desc)
-#define to_sdev(sc) container_of(sc->shdma_chan.dma_chan.device, \
-                                struct sudmac_device, shdma_dev.dma_dev)
-
-/* SUDMAC register */
-#define SUDMAC_CH0CFG          0x00
-#define SUDMAC_CH0BA           0x10
-#define SUDMAC_CH0BBC          0x18
-#define SUDMAC_CH0CA           0x20
-#define SUDMAC_CH0CBC          0x28
-#define SUDMAC_CH0DEN          0x30
-#define SUDMAC_DSTSCLR         0x38
-#define SUDMAC_DBUFCTRL                0x3C
-#define SUDMAC_DINTCTRL                0x40
-#define SUDMAC_DINTSTS         0x44
-#define SUDMAC_DINTSTSCLR      0x48
-#define SUDMAC_CH0SHCTRL       0x50
-
-/* Definitions for the sudmac_channel.config */
-#define SUDMAC_SENDBUFM        0x1000 /* b12: Transmit Buffer Mode */
-#define SUDMAC_RCVENDM 0x0100 /* b8: Receive Data Transfer End Mode */
-#define SUDMAC_LBA_WAIT        0x0030 /* b5-4: Local Bus Access Wait */
-
-/* Definitions for the sudmac_channel.dint_end_bit */
-#define SUDMAC_CH1ENDE 0x0002 /* b1: Ch1 DMA Transfer End Int Enable */
-#define SUDMAC_CH0ENDE 0x0001 /* b0: Ch0 DMA Transfer End Int Enable */
-
-#define SUDMAC_DRV_NAME "sudmac"
-
-static void sudmac_writel(struct sudmac_chan *sc, u32 data, u32 reg)
-{
-       iowrite32(data, sc->base + reg);
-}
-
-static u32 sudmac_readl(struct sudmac_chan *sc, u32 reg)
-{
-       return ioread32(sc->base + reg);
-}
-
-static bool sudmac_is_busy(struct sudmac_chan *sc)
-{
-       u32 den = sudmac_readl(sc, SUDMAC_CH0DEN + sc->offset);
-
-       if (den)
-               return true; /* working */
-
-       return false; /* waiting */
-}
-
-static void sudmac_set_reg(struct sudmac_chan *sc, struct sudmac_regs *hw,
-                          struct shdma_desc *sdesc)
-{
-       sudmac_writel(sc, sc->cfg, SUDMAC_CH0CFG + sc->offset);
-       sudmac_writel(sc, hw->base_addr, SUDMAC_CH0BA + sc->offset);
-       sudmac_writel(sc, hw->base_byte_count, SUDMAC_CH0BBC + sc->offset);
-}
-
-static void sudmac_start(struct sudmac_chan *sc)
-{
-       u32 dintctrl = sudmac_readl(sc, SUDMAC_DINTCTRL);
-
-       sudmac_writel(sc, dintctrl | sc->dint_end_bit, SUDMAC_DINTCTRL);
-       sudmac_writel(sc, 1, SUDMAC_CH0DEN + sc->offset);
-}
-
-static void sudmac_start_xfer(struct shdma_chan *schan,
-                             struct shdma_desc *sdesc)
-{
-       struct sudmac_chan *sc = to_chan(schan);
-       struct sudmac_desc *sd = to_desc(sdesc);
-
-       sudmac_set_reg(sc, &sd->hw, sdesc);
-       sudmac_start(sc);
-}
-
-static bool sudmac_channel_busy(struct shdma_chan *schan)
-{
-       struct sudmac_chan *sc = to_chan(schan);
-
-       return sudmac_is_busy(sc);
-}
-
-static void sudmac_setup_xfer(struct shdma_chan *schan, int slave_id)
-{
-}
-
-static const struct sudmac_slave_config *sudmac_find_slave(
-       struct sudmac_chan *sc, int slave_id)
-{
-       struct sudmac_device *sdev = to_sdev(sc);
-       struct sudmac_pdata *pdata = sdev->pdata;
-       const struct sudmac_slave_config *cfg;
-       int i;
-
-       for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
-               if (cfg->slave_id == slave_id)
-                       return cfg;
-
-       return NULL;
-}
-
-static int sudmac_set_slave(struct shdma_chan *schan, int slave_id,
-                           dma_addr_t slave_addr, bool try)
-{
-       struct sudmac_chan *sc = to_chan(schan);
-       const struct sudmac_slave_config *cfg = sudmac_find_slave(sc, slave_id);
-
-       if (!cfg)
-               return -ENODEV;
-
-       return 0;
-}
-
-static inline void sudmac_dma_halt(struct sudmac_chan *sc)
-{
-       u32 dintctrl = sudmac_readl(sc, SUDMAC_DINTCTRL);
-
-       sudmac_writel(sc, 0, SUDMAC_CH0DEN + sc->offset);
-       sudmac_writel(sc, dintctrl & ~sc->dint_end_bit, SUDMAC_DINTCTRL);
-       sudmac_writel(sc, sc->dint_end_bit, SUDMAC_DINTSTSCLR);
-}
-
-static int sudmac_desc_setup(struct shdma_chan *schan,
-                            struct shdma_desc *sdesc,
-                            dma_addr_t src, dma_addr_t dst, size_t *len)
-{
-       struct sudmac_chan *sc = to_chan(schan);
-       struct sudmac_desc *sd = to_desc(sdesc);
-
-       dev_dbg(sc->shdma_chan.dev, "%s: src=%pad, dst=%pad, len=%zu\n",
-               __func__, &src, &dst, *len);
-
-       if (*len > schan->max_xfer_len)
-               *len = schan->max_xfer_len;
-
-       if (dst)
-               sd->hw.base_addr = dst;
-       else if (src)
-               sd->hw.base_addr = src;
-       sd->hw.base_byte_count = *len;
-
-       return 0;
-}
-
-static void sudmac_halt(struct shdma_chan *schan)
-{
-       struct sudmac_chan *sc = to_chan(schan);
-
-       sudmac_dma_halt(sc);
-}
-
-static bool sudmac_chan_irq(struct shdma_chan *schan, int irq)
-{
-       struct sudmac_chan *sc = to_chan(schan);
-       u32 dintsts = sudmac_readl(sc, SUDMAC_DINTSTS);
-
-       if (!(dintsts & sc->dint_end_bit))
-               return false;
-
-       /* DMA stop */
-       sudmac_dma_halt(sc);
-
-       return true;
-}
-
-static size_t sudmac_get_partial(struct shdma_chan *schan,
-                                struct shdma_desc *sdesc)
-{
-       struct sudmac_chan *sc = to_chan(schan);
-       struct sudmac_desc *sd = to_desc(sdesc);
-       u32 current_byte_count = sudmac_readl(sc, SUDMAC_CH0CBC + sc->offset);
-
-       return sd->hw.base_byte_count - current_byte_count;
-}
-
-static bool sudmac_desc_completed(struct shdma_chan *schan,
-                                 struct shdma_desc *sdesc)
-{
-       struct sudmac_chan *sc = to_chan(schan);
-       struct sudmac_desc *sd = to_desc(sdesc);
-       u32 current_addr = sudmac_readl(sc, SUDMAC_CH0CA + sc->offset);
-
-       return sd->hw.base_addr + sd->hw.base_byte_count == current_addr;
-}
-
-static int sudmac_chan_probe(struct sudmac_device *su_dev, int id, int irq,
-                            unsigned long flags)
-{
-       struct shdma_dev *sdev = &su_dev->shdma_dev;
-       struct platform_device *pdev = to_platform_device(sdev->dma_dev.dev);
-       struct sudmac_chan *sc;
-       struct shdma_chan *schan;
-       int err;
-
-       sc = devm_kzalloc(&pdev->dev, sizeof(struct sudmac_chan), GFP_KERNEL);
-       if (!sc)
-               return -ENOMEM;
-
-       schan = &sc->shdma_chan;
-       schan->max_xfer_len = 64 * 1024 * 1024 - 1;
-
-       shdma_chan_probe(sdev, schan, id);
-
-       sc->base = su_dev->chan_reg;
-
-       /* get platform_data */
-       sc->offset = su_dev->pdata->channel->offset;
-       if (su_dev->pdata->channel->config & SUDMAC_TX_BUFFER_MODE)
-               sc->cfg |= SUDMAC_SENDBUFM;
-       if (su_dev->pdata->channel->config & SUDMAC_RX_END_MODE)
-               sc->cfg |= SUDMAC_RCVENDM;
-       sc->cfg |= (su_dev->pdata->channel->wait << 4) & SUDMAC_LBA_WAIT;
-
-       if (su_dev->pdata->channel->dint_end_bit & SUDMAC_DMA_BIT_CH0)
-               sc->dint_end_bit |= SUDMAC_CH0ENDE;
-       if (su_dev->pdata->channel->dint_end_bit & SUDMAC_DMA_BIT_CH1)
-               sc->dint_end_bit |= SUDMAC_CH1ENDE;
-
-       /* set up channel irq */
-       if (pdev->id >= 0)
-               snprintf(sc->dev_id, sizeof(sc->dev_id), "sudmac%d.%d",
-                        pdev->id, id);
-       else
-               snprintf(sc->dev_id, sizeof(sc->dev_id), "sudmac%d", id);
-
-       err = shdma_request_irq(schan, irq, flags, sc->dev_id);
-       if (err) {
-               dev_err(sdev->dma_dev.dev,
-                       "DMA channel %d request_irq failed %d\n", id, err);
-               goto err_no_irq;
-       }
-
-       return 0;
-
-err_no_irq:
-       /* remove from dmaengine device node */
-       shdma_chan_remove(schan);
-       return err;
-}
-
-static void sudmac_chan_remove(struct sudmac_device *su_dev)
-{
-       struct shdma_chan *schan;
-       int i;
-
-       shdma_for_each_chan(schan, &su_dev->shdma_dev, i) {
-               BUG_ON(!schan);
-
-               shdma_chan_remove(schan);
-       }
-}
-
-static dma_addr_t sudmac_slave_addr(struct shdma_chan *schan)
-{
-       /* SUDMAC doesn't need the address */
-       return 0;
-}
-
-static struct shdma_desc *sudmac_embedded_desc(void *buf, int i)
-{
-       return &((struct sudmac_desc *)buf)[i].shdma_desc;
-}
-
-static const struct shdma_ops sudmac_shdma_ops = {
-       .desc_completed = sudmac_desc_completed,
-       .halt_channel = sudmac_halt,
-       .channel_busy = sudmac_channel_busy,
-       .slave_addr = sudmac_slave_addr,
-       .desc_setup = sudmac_desc_setup,
-       .set_slave = sudmac_set_slave,
-       .setup_xfer = sudmac_setup_xfer,
-       .start_xfer = sudmac_start_xfer,
-       .embedded_desc = sudmac_embedded_desc,
-       .chan_irq = sudmac_chan_irq,
-       .get_partial = sudmac_get_partial,
-};
-
-static int sudmac_probe(struct platform_device *pdev)
-{
-       struct sudmac_pdata *pdata = dev_get_platdata(&pdev->dev);
-       int err, i;
-       struct sudmac_device *su_dev;
-       struct dma_device *dma_dev;
-       struct resource *chan, *irq_res;
-
-       /* get platform data */
-       if (!pdata)
-               return -ENODEV;
-
-       irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!irq_res)
-               return -ENODEV;
-
-       err = -ENOMEM;
-       su_dev = devm_kzalloc(&pdev->dev, sizeof(struct sudmac_device),
-                             GFP_KERNEL);
-       if (!su_dev)
-               return err;
-
-       dma_dev = &su_dev->shdma_dev.dma_dev;
-
-       chan = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       su_dev->chan_reg = devm_ioremap_resource(&pdev->dev, chan);
-       if (IS_ERR(su_dev->chan_reg))
-               return PTR_ERR(su_dev->chan_reg);
-
-       dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
-
-       su_dev->shdma_dev.ops = &sudmac_shdma_ops;
-       su_dev->shdma_dev.desc_size = sizeof(struct sudmac_desc);
-       err = shdma_init(&pdev->dev, &su_dev->shdma_dev, pdata->channel_num);
-       if (err < 0)
-               return err;
-
-       /* platform data */
-       su_dev->pdata = dev_get_platdata(&pdev->dev);
-
-       platform_set_drvdata(pdev, su_dev);
-
-       /* Create DMA Channel */
-       for (i = 0; i < pdata->channel_num; i++) {
-               err = sudmac_chan_probe(su_dev, i, irq_res->start, IRQF_SHARED);
-               if (err)
-                       goto chan_probe_err;
-       }
-
-       err = dma_async_device_register(&su_dev->shdma_dev.dma_dev);
-       if (err < 0)
-               goto chan_probe_err;
-
-       return err;
-
-chan_probe_err:
-       sudmac_chan_remove(su_dev);
-
-       shdma_cleanup(&su_dev->shdma_dev);
-
-       return err;
-}
-
-static int sudmac_remove(struct platform_device *pdev)
-{
-       struct sudmac_device *su_dev = platform_get_drvdata(pdev);
-       struct dma_device *dma_dev = &su_dev->shdma_dev.dma_dev;
-
-       dma_async_device_unregister(dma_dev);
-       sudmac_chan_remove(su_dev);
-       shdma_cleanup(&su_dev->shdma_dev);
-
-       return 0;
-}
-
-static struct platform_driver sudmac_driver = {
-       .driver         = {
-               .name   = SUDMAC_DRV_NAME,
-       },
-       .probe          = sudmac_probe,
-       .remove         = sudmac_remove,
-};
-module_platform_driver(sudmac_driver);
-
-MODULE_AUTHOR("Yoshihiro Shimoda");
-MODULE_DESCRIPTION("Renesas SUDMAC driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:" SUDMAC_DRV_NAME);
index 59403f6..17063aa 100644 (file)
@@ -57,7 +57,7 @@ struct usb_dmac_desc {
        u32 residue;
        struct list_head node;
        dma_cookie_t done_cookie;
-       struct usb_dmac_sg sg[0];
+       struct usb_dmac_sg sg[];
 };
 
 #define to_usb_dmac_desc(vd)   container_of(vd, struct usb_dmac_desc, vd)
@@ -636,9 +636,6 @@ static bool usb_dmac_chan_filter(struct dma_chan *chan, void *arg)
        struct usb_dmac_chan *uchan = to_usb_dmac_chan(chan);
        struct of_phandle_args *dma_spec = arg;
 
-       if (dma_spec->np != chan->device->dev->of_node)
-               return false;
-
        /* USB-DMAC should be used with fixed usb controller's FIFO */
        if (uchan->index != dma_spec->args[0])
                return false;
@@ -659,7 +656,8 @@ static struct dma_chan *usb_dmac_of_xlate(struct of_phandle_args *dma_spec,
        dma_cap_zero(mask);
        dma_cap_set(DMA_SLAVE, mask);
 
-       chan = dma_request_channel(mask, usb_dmac_chan_filter, dma_spec);
+       chan = __dma_request_channel(&mask, usb_dmac_chan_filter, dma_spec,
+                                    ofdma->of_node);
        if (!chan)
                return NULL;
 
index da41bab..ef4d109 100644 (file)
@@ -1365,7 +1365,6 @@ static int stm32_dma_probe(struct platform_device *pdev)
 
        for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) {
                chan = &dmadev->chan[i];
-               chan->irq = platform_get_irq(pdev, i);
                ret = platform_get_irq(pdev, i);
                if (ret < 0)  {
                        if (ret != -EPROBE_DEFER)
index 715aad7..b552949 100644 (file)
@@ -295,8 +295,7 @@ static int stm32_dmamux_probe(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int stm32_dmamux_runtime_suspend(struct device *dev)
 {
-       struct platform_device *pdev =
-               container_of(dev, struct platform_device, dev);
+       struct platform_device *pdev = to_platform_device(dev);
        struct stm32_dmamux_data *stm32_dmamux = platform_get_drvdata(pdev);
 
        clk_disable_unprepare(stm32_dmamux->clk);
@@ -306,8 +305,7 @@ static int stm32_dmamux_runtime_suspend(struct device *dev)
 
 static int stm32_dmamux_runtime_resume(struct device *dev)
 {
-       struct platform_device *pdev =
-               container_of(dev, struct platform_device, dev);
+       struct platform_device *pdev = to_platform_device(dev);
        struct stm32_dmamux_data *stm32_dmamux = platform_get_drvdata(pdev);
        int ret;
 
index e8fcc69..ed5b68d 100644 (file)
 #define DMA_CHAN_LLI_ADDR      0x08
 
 #define DMA_CHAN_CUR_CFG       0x0c
-#define DMA_CHAN_MAX_DRQ               0x1f
-#define DMA_CHAN_CFG_SRC_DRQ(x)                ((x) & DMA_CHAN_MAX_DRQ)
-#define DMA_CHAN_CFG_SRC_IO_MODE       BIT(5)
-#define DMA_CHAN_CFG_SRC_LINEAR_MODE   (0 << 5)
+#define DMA_CHAN_MAX_DRQ_A31           0x1f
+#define DMA_CHAN_MAX_DRQ_H6            0x3f
+#define DMA_CHAN_CFG_SRC_DRQ_A31(x)    ((x) & DMA_CHAN_MAX_DRQ_A31)
+#define DMA_CHAN_CFG_SRC_DRQ_H6(x)     ((x) & DMA_CHAN_MAX_DRQ_H6)
+#define DMA_CHAN_CFG_SRC_MODE_A31(x)   (((x) & 0x1) << 5)
+#define DMA_CHAN_CFG_SRC_MODE_H6(x)    (((x) & 0x1) << 8)
 #define DMA_CHAN_CFG_SRC_BURST_A31(x)  (((x) & 0x3) << 7)
 #define DMA_CHAN_CFG_SRC_BURST_H3(x)   (((x) & 0x3) << 6)
 #define DMA_CHAN_CFG_SRC_WIDTH(x)      (((x) & 0x3) << 9)
 
-#define DMA_CHAN_CFG_DST_DRQ(x)                (DMA_CHAN_CFG_SRC_DRQ(x) << 16)
-#define DMA_CHAN_CFG_DST_IO_MODE       (DMA_CHAN_CFG_SRC_IO_MODE << 16)
-#define DMA_CHAN_CFG_DST_LINEAR_MODE   (DMA_CHAN_CFG_SRC_LINEAR_MODE << 16)
+#define DMA_CHAN_CFG_DST_DRQ_A31(x)    (DMA_CHAN_CFG_SRC_DRQ_A31(x) << 16)
+#define DMA_CHAN_CFG_DST_DRQ_H6(x)     (DMA_CHAN_CFG_SRC_DRQ_H6(x) << 16)
+#define DMA_CHAN_CFG_DST_MODE_A31(x)   (DMA_CHAN_CFG_SRC_MODE_A31(x) << 16)
+#define DMA_CHAN_CFG_DST_MODE_H6(x)    (DMA_CHAN_CFG_SRC_MODE_H6(x) << 16)
 #define DMA_CHAN_CFG_DST_BURST_A31(x)  (DMA_CHAN_CFG_SRC_BURST_A31(x) << 16)
 #define DMA_CHAN_CFG_DST_BURST_H3(x)   (DMA_CHAN_CFG_SRC_BURST_H3(x) << 16)
 #define DMA_CHAN_CFG_DST_WIDTH(x)      (DMA_CHAN_CFG_SRC_WIDTH(x) << 16)
@@ -94,6 +97,8 @@
 #define LLI_LAST_ITEM  0xfffff800
 #define NORMAL_WAIT    8
 #define DRQ_SDRAM      1
+#define LINEAR_MODE     0
+#define IO_MODE         1
 
 /* forward declaration */
 struct sun6i_dma_dev;
@@ -121,10 +126,13 @@ struct sun6i_dma_config {
         */
        void (*clock_autogate_enable)(struct sun6i_dma_dev *);
        void (*set_burst_length)(u32 *p_cfg, s8 src_burst, s8 dst_burst);
+       void (*set_drq)(u32 *p_cfg, s8 src_drq, s8 dst_drq);
+       void (*set_mode)(u32 *p_cfg, s8 src_mode, s8 dst_mode);
        u32 src_burst_lengths;
        u32 dst_burst_lengths;
        u32 src_addr_widths;
        u32 dst_addr_widths;
+       bool has_mbus_clk;
 };
 
 /*
@@ -178,6 +186,7 @@ struct sun6i_dma_dev {
        struct dma_device       slave;
        void __iomem            *base;
        struct clk              *clk;
+       struct clk              *clk_mbus;
        int                     irq;
        spinlock_t              lock;
        struct reset_control    *rstc;
@@ -305,6 +314,30 @@ static void sun6i_set_burst_length_h3(u32 *p_cfg, s8 src_burst, s8 dst_burst)
                  DMA_CHAN_CFG_DST_BURST_H3(dst_burst);
 }
 
+static void sun6i_set_drq_a31(u32 *p_cfg, s8 src_drq, s8 dst_drq)
+{
+       *p_cfg |= DMA_CHAN_CFG_SRC_DRQ_A31(src_drq) |
+                 DMA_CHAN_CFG_DST_DRQ_A31(dst_drq);
+}
+
+static void sun6i_set_drq_h6(u32 *p_cfg, s8 src_drq, s8 dst_drq)
+{
+       *p_cfg |= DMA_CHAN_CFG_SRC_DRQ_H6(src_drq) |
+                 DMA_CHAN_CFG_DST_DRQ_H6(dst_drq);
+}
+
+static void sun6i_set_mode_a31(u32 *p_cfg, s8 src_mode, s8 dst_mode)
+{
+       *p_cfg |= DMA_CHAN_CFG_SRC_MODE_A31(src_mode) |
+                 DMA_CHAN_CFG_DST_MODE_A31(dst_mode);
+}
+
+static void sun6i_set_mode_h6(u32 *p_cfg, s8 src_mode, s8 dst_mode)
+{
+       *p_cfg |= DMA_CHAN_CFG_SRC_MODE_H6(src_mode) |
+                 DMA_CHAN_CFG_DST_MODE_H6(dst_mode);
+}
+
 static size_t sun6i_get_chan_size(struct sun6i_pchan *pchan)
 {
        struct sun6i_desc *txd = pchan->desc;
@@ -628,14 +661,12 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
 
        burst = convert_burst(8);
        width = convert_buswidth(DMA_SLAVE_BUSWIDTH_4_BYTES);
-       v_lli->cfg = DMA_CHAN_CFG_SRC_DRQ(DRQ_SDRAM) |
-               DMA_CHAN_CFG_DST_DRQ(DRQ_SDRAM) |
-               DMA_CHAN_CFG_DST_LINEAR_MODE |
-               DMA_CHAN_CFG_SRC_LINEAR_MODE |
-               DMA_CHAN_CFG_SRC_WIDTH(width) |
+       v_lli->cfg = DMA_CHAN_CFG_SRC_WIDTH(width) |
                DMA_CHAN_CFG_DST_WIDTH(width);
 
        sdev->cfg->set_burst_length(&v_lli->cfg, burst, burst);
+       sdev->cfg->set_drq(&v_lli->cfg, DRQ_SDRAM, DRQ_SDRAM);
+       sdev->cfg->set_mode(&v_lli->cfg, LINEAR_MODE, LINEAR_MODE);
 
        sun6i_dma_lli_add(NULL, v_lli, p_lli, txd);
 
@@ -687,11 +718,9 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
                if (dir == DMA_MEM_TO_DEV) {
                        v_lli->src = sg_dma_address(sg);
                        v_lli->dst = sconfig->dst_addr;
-                       v_lli->cfg = lli_cfg |
-                               DMA_CHAN_CFG_DST_IO_MODE |
-                               DMA_CHAN_CFG_SRC_LINEAR_MODE |
-                               DMA_CHAN_CFG_SRC_DRQ(DRQ_SDRAM) |
-                               DMA_CHAN_CFG_DST_DRQ(vchan->port);
+                       v_lli->cfg = lli_cfg;
+                       sdev->cfg->set_drq(&v_lli->cfg, DRQ_SDRAM, vchan->port);
+                       sdev->cfg->set_mode(&v_lli->cfg, LINEAR_MODE, IO_MODE);
 
                        dev_dbg(chan2dev(chan),
                                "%s; chan: %d, dest: %pad, src: %pad, len: %u. flags: 0x%08lx\n",
@@ -702,11 +731,9 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
                } else {
                        v_lli->src = sconfig->src_addr;
                        v_lli->dst = sg_dma_address(sg);
-                       v_lli->cfg = lli_cfg |
-                               DMA_CHAN_CFG_DST_LINEAR_MODE |
-                               DMA_CHAN_CFG_SRC_IO_MODE |
-                               DMA_CHAN_CFG_DST_DRQ(DRQ_SDRAM) |
-                               DMA_CHAN_CFG_SRC_DRQ(vchan->port);
+                       v_lli->cfg = lli_cfg;
+                       sdev->cfg->set_drq(&v_lli->cfg, vchan->port, DRQ_SDRAM);
+                       sdev->cfg->set_mode(&v_lli->cfg, IO_MODE, LINEAR_MODE);
 
                        dev_dbg(chan2dev(chan),
                                "%s; chan: %d, dest: %pad, src: %pad, len: %u. flags: 0x%08lx\n",
@@ -772,19 +799,15 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic(
                if (dir == DMA_MEM_TO_DEV) {
                        v_lli->src = buf_addr + period_len * i;
                        v_lli->dst = sconfig->dst_addr;
-                       v_lli->cfg = lli_cfg |
-                               DMA_CHAN_CFG_DST_IO_MODE |
-                               DMA_CHAN_CFG_SRC_LINEAR_MODE |
-                               DMA_CHAN_CFG_SRC_DRQ(DRQ_SDRAM) |
-                               DMA_CHAN_CFG_DST_DRQ(vchan->port);
+                       v_lli->cfg = lli_cfg;
+                       sdev->cfg->set_drq(&v_lli->cfg, DRQ_SDRAM, vchan->port);
+                       sdev->cfg->set_mode(&v_lli->cfg, LINEAR_MODE, IO_MODE);
                } else {
                        v_lli->src = sconfig->src_addr;
                        v_lli->dst = buf_addr + period_len * i;
-                       v_lli->cfg = lli_cfg |
-                               DMA_CHAN_CFG_DST_LINEAR_MODE |
-                               DMA_CHAN_CFG_SRC_IO_MODE |
-                               DMA_CHAN_CFG_DST_DRQ(DRQ_SDRAM) |
-                               DMA_CHAN_CFG_SRC_DRQ(vchan->port);
+                       v_lli->cfg = lli_cfg;
+                       sdev->cfg->set_drq(&v_lli->cfg, vchan->port, DRQ_SDRAM);
+                       sdev->cfg->set_mode(&v_lli->cfg, IO_MODE, LINEAR_MODE);
                }
 
                prev = sun6i_dma_lli_add(prev, v_lli, p_lli, txd);
@@ -1049,6 +1072,8 @@ static struct sun6i_dma_config sun6i_a31_dma_cfg = {
        .nr_max_requests = 30,
        .nr_max_vchans   = 53,
        .set_burst_length = sun6i_set_burst_length_a31,
+       .set_drq          = sun6i_set_drq_a31,
+       .set_mode         = sun6i_set_mode_a31,
        .src_burst_lengths = BIT(1) | BIT(8),
        .dst_burst_lengths = BIT(1) | BIT(8),
        .src_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
@@ -1070,6 +1095,8 @@ static struct sun6i_dma_config sun8i_a23_dma_cfg = {
        .nr_max_vchans   = 37,
        .clock_autogate_enable = sun6i_enable_clock_autogate_a23,
        .set_burst_length = sun6i_set_burst_length_a31,
+       .set_drq          = sun6i_set_drq_a31,
+       .set_mode         = sun6i_set_mode_a31,
        .src_burst_lengths = BIT(1) | BIT(8),
        .dst_burst_lengths = BIT(1) | BIT(8),
        .src_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
@@ -1086,6 +1113,8 @@ static struct sun6i_dma_config sun8i_a83t_dma_cfg = {
        .nr_max_vchans   = 39,
        .clock_autogate_enable = sun6i_enable_clock_autogate_a23,
        .set_burst_length = sun6i_set_burst_length_a31,
+       .set_drq          = sun6i_set_drq_a31,
+       .set_mode         = sun6i_set_mode_a31,
        .src_burst_lengths = BIT(1) | BIT(8),
        .dst_burst_lengths = BIT(1) | BIT(8),
        .src_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
@@ -1109,6 +1138,8 @@ static struct sun6i_dma_config sun8i_h3_dma_cfg = {
        .nr_max_vchans   = 34,
        .clock_autogate_enable = sun6i_enable_clock_autogate_h3,
        .set_burst_length = sun6i_set_burst_length_h3,
+       .set_drq          = sun6i_set_drq_a31,
+       .set_mode         = sun6i_set_mode_a31,
        .src_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
        .dst_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
        .src_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
@@ -1128,6 +1159,8 @@ static struct sun6i_dma_config sun8i_h3_dma_cfg = {
 static struct sun6i_dma_config sun50i_a64_dma_cfg = {
        .clock_autogate_enable = sun6i_enable_clock_autogate_h3,
        .set_burst_length = sun6i_set_burst_length_h3,
+       .set_drq          = sun6i_set_drq_a31,
+       .set_mode         = sun6i_set_mode_a31,
        .src_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
        .dst_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
        .src_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
@@ -1141,6 +1174,28 @@ static struct sun6i_dma_config sun50i_a64_dma_cfg = {
 };
 
 /*
+ * The H6 binding uses the number of dma channels from the
+ * device tree node.
+ */
+static struct sun6i_dma_config sun50i_h6_dma_cfg = {
+       .clock_autogate_enable = sun6i_enable_clock_autogate_h3,
+       .set_burst_length = sun6i_set_burst_length_h3,
+       .set_drq          = sun6i_set_drq_h6,
+       .set_mode         = sun6i_set_mode_h6,
+       .src_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
+       .dst_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
+       .src_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+                            BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+                            BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
+                            BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
+       .dst_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+                            BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+                            BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
+                            BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
+       .has_mbus_clk = true,
+};
+
+/*
  * The V3s have only 8 physical channels, a maximum DRQ port id of 23,
  * and a total of 24 usable source and destination endpoints.
  */
@@ -1151,6 +1206,8 @@ static struct sun6i_dma_config sun8i_v3s_dma_cfg = {
        .nr_max_vchans   = 24,
        .clock_autogate_enable = sun6i_enable_clock_autogate_a23,
        .set_burst_length = sun6i_set_burst_length_a31,
+       .set_drq          = sun6i_set_drq_a31,
+       .set_mode         = sun6i_set_mode_a31,
        .src_burst_lengths = BIT(1) | BIT(8),
        .dst_burst_lengths = BIT(1) | BIT(8),
        .src_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
@@ -1168,6 +1225,7 @@ static const struct of_device_id sun6i_dma_match[] = {
        { .compatible = "allwinner,sun8i-h3-dma", .data = &sun8i_h3_dma_cfg },
        { .compatible = "allwinner,sun8i-v3s-dma", .data = &sun8i_v3s_dma_cfg },
        { .compatible = "allwinner,sun50i-a64-dma", .data = &sun50i_a64_dma_cfg },
+       { .compatible = "allwinner,sun50i-h6-dma", .data = &sun50i_h6_dma_cfg },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, sun6i_dma_match);
@@ -1204,6 +1262,14 @@ static int sun6i_dma_probe(struct platform_device *pdev)
                return PTR_ERR(sdc->clk);
        }
 
+       if (sdc->cfg->has_mbus_clk) {
+               sdc->clk_mbus = devm_clk_get(&pdev->dev, "mbus");
+               if (IS_ERR(sdc->clk_mbus)) {
+                       dev_err(&pdev->dev, "No mbus clock specified\n");
+                       return PTR_ERR(sdc->clk_mbus);
+               }
+       }
+
        sdc->rstc = devm_reset_control_get(&pdev->dev, NULL);
        if (IS_ERR(sdc->rstc)) {
                dev_err(&pdev->dev, "No reset controller specified\n");
@@ -1258,8 +1324,8 @@ static int sun6i_dma_probe(struct platform_device *pdev)
        ret = of_property_read_u32(np, "dma-requests", &sdc->max_request);
        if (ret && !sdc->max_request) {
                dev_info(&pdev->dev, "Missing dma-requests, using %u.\n",
-                        DMA_CHAN_MAX_DRQ);
-               sdc->max_request = DMA_CHAN_MAX_DRQ;
+                        DMA_CHAN_MAX_DRQ_A31);
+               sdc->max_request = DMA_CHAN_MAX_DRQ_A31;
        }
 
        /*
@@ -1308,11 +1374,19 @@ static int sun6i_dma_probe(struct platform_device *pdev)
                goto err_reset_assert;
        }
 
+       if (sdc->cfg->has_mbus_clk) {
+               ret = clk_prepare_enable(sdc->clk_mbus);
+               if (ret) {
+                       dev_err(&pdev->dev, "Couldn't enable mbus clock\n");
+                       goto err_clk_disable;
+               }
+       }
+
        ret = devm_request_irq(&pdev->dev, sdc->irq, sun6i_dma_interrupt, 0,
                               dev_name(&pdev->dev), sdc);
        if (ret) {
                dev_err(&pdev->dev, "Cannot request IRQ\n");
-               goto err_clk_disable;
+               goto err_mbus_clk_disable;
        }
 
        ret = dma_async_device_register(&sdc->slave);
@@ -1337,6 +1411,8 @@ err_dma_unregister:
        dma_async_device_unregister(&sdc->slave);
 err_irq_disable:
        sun6i_kill_tasklet(sdc);
+err_mbus_clk_disable:
+       clk_disable_unprepare(sdc->clk_mbus);
 err_clk_disable:
        clk_disable_unprepare(sdc->clk);
 err_reset_assert:
@@ -1355,6 +1431,7 @@ static int sun6i_dma_remove(struct platform_device *pdev)
 
        sun6i_kill_tasklet(sdc);
 
+       clk_disable_unprepare(sdc->clk_mbus);
        clk_disable_unprepare(sdc->clk);
        reset_control_assert(sdc->rstc);
 
index ef317c9..79e9593 100644 (file)
@@ -977,8 +977,12 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg(
                csr |= tdc->slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT;
        }
 
-       if (flags & DMA_PREP_INTERRUPT)
+       if (flags & DMA_PREP_INTERRUPT) {
                csr |= TEGRA_APBDMA_CSR_IE_EOC;
+       } else {
+               WARN_ON_ONCE(1);
+               return NULL;
+       }
 
        apb_seq |= TEGRA_APBDMA_APBSEQ_WRAP_WORD_1;
 
@@ -1120,8 +1124,12 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic(
                csr |= tdc->slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT;
        }
 
-       if (flags & DMA_PREP_INTERRUPT)
+       if (flags & DMA_PREP_INTERRUPT) {
                csr |= TEGRA_APBDMA_CSR_IE_EOC;
+       } else {
+               WARN_ON_ONCE(1);
+               return NULL;
+       }
 
        apb_seq |= TEGRA_APBDMA_APBSEQ_WRAP_WORD_1;
 
index bb53908..ec4adf4 100644 (file)
@@ -98,7 +98,7 @@ static void vchan_complete(unsigned long arg)
        }
        spin_unlock_irq(&vc->lock);
 
-       dmaengine_desc_callback_invoke(&cb, NULL);
+       dmaengine_desc_callback_invoke(&cb, &vd->tx_result);
 
        list_for_each_entry_safe(vd, _vd, &head, node) {
                dmaengine_desc_get_callback(&vd->tx, &cb);
@@ -106,7 +106,7 @@ static void vchan_complete(unsigned long arg)
                list_del(&vd->node);
                vchan_vdesc_fini(vd);
 
-               dmaengine_desc_callback_invoke(&cb, NULL);
+               dmaengine_desc_callback_invoke(&cb, &vd->tx_result);
        }
 }
 
index 23342ca..ab158ba 100644 (file)
@@ -14,6 +14,7 @@
 
 struct virt_dma_desc {
        struct dma_async_tx_descriptor tx;
+       struct dmaengine_result tx_result;
        /* protected by vc.lock */
        struct list_head node;
 };
@@ -62,6 +63,9 @@ static inline struct dma_async_tx_descriptor *vchan_tx_prep(struct virt_dma_chan
        vd->tx.tx_submit = vchan_tx_submit;
        vd->tx.desc_free = vchan_tx_desc_free;
 
+       vd->tx_result.result = DMA_TRANS_NOERROR;
+       vd->tx_result.residue = 0;
+
        spin_lock_irqsave(&vc->lock, flags);
        list_add_tail(&vd->node, &vc->desc_allocated);
        spin_unlock_irqrestore(&vc->lock, flags);
index 36c0923..e7dc3c4 100644 (file)
@@ -1095,7 +1095,7 @@ static void xilinx_dma_start(struct xilinx_dma_chan *chan)
 static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan)
 {
        struct xilinx_vdma_config *config = &chan->config;
-       struct xilinx_dma_tx_descriptor *desc, *tail_desc;
+       struct xilinx_dma_tx_descriptor *desc;
        u32 reg, j;
        struct xilinx_vdma_tx_segment *segment, *last = NULL;
        int i = 0;
@@ -1112,8 +1112,6 @@ static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan)
 
        desc = list_first_entry(&chan->pending_list,
                                struct xilinx_dma_tx_descriptor, node);
-       tail_desc = list_last_entry(&chan->pending_list,
-                                   struct xilinx_dma_tx_descriptor, node);
 
        /* Configure the hardware using info in the config structure */
        if (chan->has_vflip) {
index 53446e3..ba8d3d0 100644 (file)
@@ -157,7 +157,7 @@ config DMI_SCAN_MACHINE_NON_EFI_FALLBACK
 
 config ISCSI_IBFT_FIND
        bool "iSCSI Boot Firmware Table Attributes"
-       depends on X86 && ACPI
+       depends on X86 && ISCSI_IBFT
        default n
        help
          This option enables the kernel to find the region of memory
@@ -168,7 +168,8 @@ config ISCSI_IBFT_FIND
 config ISCSI_IBFT
        tristate "iSCSI Boot Firmware Table Attributes module"
        select ISCSI_BOOT_SYSFS
-       depends on ISCSI_IBFT_FIND && SCSI && SCSI_LOWLEVEL
+       select ISCSI_IBFT_FIND if X86
+       depends on ACPI && SCSI && SCSI_LOWLEVEL
        default n
        help
          This option enables support for detection and exposing of iSCSI
index 30fc04e..0a194af 100644 (file)
@@ -185,6 +185,8 @@ scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id,
        if (rate_discrete)
                clk->list.num_rates = tot_rate_cnt;
 
+       clk->rate_discrete = rate_discrete;
+
 err:
        scmi_xfer_put(handle, t);
        return ret;
index b53d5cc..0e94ab5 100644 (file)
@@ -30,10 +30,12 @@ struct scmi_msg_resp_sensor_description {
                __le32 id;
                __le32 attributes_low;
 #define SUPPORTS_ASYNC_READ(x) ((x) & BIT(31))
-#define NUM_TRIP_POINTS(x)     (((x) >> 4) & 0xff)
+#define NUM_TRIP_POINTS(x)     ((x) & 0xff)
                __le32 attributes_high;
 #define SENSOR_TYPE(x)         ((x) & 0xff)
-#define SENSOR_SCALE(x)                (((x) >> 11) & 0x3f)
+#define SENSOR_SCALE(x)                (((x) >> 11) & 0x1f)
+#define SENSOR_SCALE_SIGN      BIT(4)
+#define SENSOR_SCALE_EXTEND    GENMASK(7, 5)
 #define SENSOR_UPDATE_SCALE(x) (((x) >> 22) & 0x1f)
 #define SENSOR_UPDATE_BASE(x)  (((x) >> 27) & 0x1f)
                    u8 name[SCMI_MAX_STR_SIZE];
@@ -140,6 +142,10 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle,
                        s = &si->sensors[desc_index + cnt];
                        s->id = le32_to_cpu(buf->desc[cnt].id);
                        s->type = SENSOR_TYPE(attrh);
+                       s->scale = SENSOR_SCALE(attrh);
+                       /* Sign extend to a full s8 */
+                       if (s->scale & SENSOR_SCALE_SIGN)
+                               s->scale |= SENSOR_SCALE_EXTEND;
                        strlcpy(s->name, buf->desc[cnt].name, SCMI_MAX_STR_SIZE);
                }
 
index ab3aa39..7e12cbd 100644 (file)
@@ -84,6 +84,10 @@ MODULE_DESCRIPTION("sysfs interface to BIOS iBFT information");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(IBFT_ISCSI_VERSION);
 
+#ifndef CONFIG_ISCSI_IBFT_FIND
+struct acpi_table_ibft *ibft_addr;
+#endif
+
 struct ibft_hdr {
        u8 id;
        u8 version;
index 08c8509..f365944 100644 (file)
@@ -359,16 +359,16 @@ static int suspend_test_thread(void *arg)
        for (;;) {
                /* Needs to be set first to avoid missing a wakeup. */
                set_current_state(TASK_INTERRUPTIBLE);
-               if (kthread_should_stop()) {
-                       __set_current_state(TASK_RUNNING);
+               if (kthread_should_park())
                        break;
-               }
                schedule();
        }
 
        pr_info("CPU %d suspend test results: success %d, shallow states %d, errors %d\n",
                cpu, nb_suspend, nb_shallow_sleep, nb_err);
 
+       kthread_parkme();
+
        return nb_err;
 }
 
@@ -433,8 +433,10 @@ static int suspend_tests(void)
 
 
        /* Stop and destroy all threads, get return status. */
-       for (i = 0; i < nb_threads; ++i)
+       for (i = 0; i < nb_threads; ++i) {
+               err += kthread_park(threads[i]);
                err += kthread_stop(threads[i]);
+       }
  out:
        cpuidle_resume_and_unlock();
        kfree(threads);
index 61be15d..da26a58 100644 (file)
@@ -20,6 +20,7 @@
 #define MBOX_CHAN_PROPERTY             8
 
 static struct platform_device *rpi_hwmon;
+static struct platform_device *rpi_clk;
 
 struct rpi_firmware {
        struct mbox_client cl;
@@ -207,6 +208,12 @@ rpi_register_hwmon_driver(struct device *dev, struct rpi_firmware *fw)
                                                  -1, NULL, 0);
 }
 
+static void rpi_register_clk_driver(struct device *dev)
+{
+       rpi_clk = platform_device_register_data(dev, "raspberrypi-clk",
+                                               -1, NULL, 0);
+}
+
 static int rpi_firmware_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -234,6 +241,7 @@ static int rpi_firmware_probe(struct platform_device *pdev)
 
        rpi_firmware_print_firmware_revision(fw);
        rpi_register_hwmon_driver(dev, fw);
+       rpi_register_clk_driver(dev);
 
        return 0;
 }
@@ -254,6 +262,8 @@ static int rpi_firmware_remove(struct platform_device *pdev)
 
        platform_device_unregister(rpi_hwmon);
        rpi_hwmon = NULL;
+       platform_device_unregister(rpi_clk);
+       rpi_clk = NULL;
        mbox_free_channel(fw->chan);
 
        return 0;
index 2418abf..19c5613 100644 (file)
@@ -803,7 +803,9 @@ static int __maybe_unused tegra_bpmp_resume(struct device *dev)
                return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(tegra_bpmp_pm_ops, NULL, tegra_bpmp_resume);
+static const struct dev_pm_ops tegra_bpmp_pm_ops = {
+       .resume_early = tegra_bpmp_resume,
+};
 
 #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \
     IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC)
index ef93406..cdee0b4 100644 (file)
@@ -466,9 +466,9 @@ static int ti_sci_cmd_get_revision(struct ti_sci_info *info)
        struct ti_sci_xfer *xfer;
        int ret;
 
-       /* No need to setup flags since it is expected to respond */
        xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_VERSION,
-                                  0x0, sizeof(struct ti_sci_msg_hdr),
+                                  TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
+                                  sizeof(struct ti_sci_msg_hdr),
                                   sizeof(*rev_info));
        if (IS_ERR(xfer)) {
                ret = PTR_ERR(xfer);
@@ -596,9 +596,9 @@ static int ti_sci_get_device_state(const struct ti_sci_handle *handle,
        info = handle_to_ti_sci_info(handle);
        dev = info->dev;
 
-       /* Response is expected, so need of any flags */
        xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_GET_DEVICE_STATE,
-                                  0, sizeof(*req), sizeof(*resp));
+                                  TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
+                                  sizeof(*req), sizeof(*resp));
        if (IS_ERR(xfer)) {
                ret = PTR_ERR(xfer);
                dev_err(dev, "Message alloc failed(%d)\n", ret);
@@ -916,7 +916,7 @@ static int ti_sci_cmd_get_device_resets(const struct ti_sci_handle *handle,
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_set_clock_state(const struct ti_sci_handle *handle,
-                                 u32 dev_id, u8 clk_id,
+                                 u32 dev_id, u32 clk_id,
                                  u32 flags, u8 state)
 {
        struct ti_sci_info *info;
@@ -944,7 +944,12 @@ static int ti_sci_set_clock_state(const struct ti_sci_handle *handle,
        }
        req = (struct ti_sci_msg_req_set_clock_state *)xfer->xfer_buf;
        req->dev_id = dev_id;
-       req->clk_id = clk_id;
+       if (clk_id < 255) {
+               req->clk_id = clk_id;
+       } else {
+               req->clk_id = 255;
+               req->clk_id_32 = clk_id;
+       }
        req->request_state = state;
 
        ret = ti_sci_do_xfer(info, xfer);
@@ -976,7 +981,7 @@ fail:
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_get_clock_state(const struct ti_sci_handle *handle,
-                                     u32 dev_id, u8 clk_id,
+                                     u32 dev_id, u32 clk_id,
                                      u8 *programmed_state, u8 *current_state)
 {
        struct ti_sci_info *info;
@@ -1007,7 +1012,12 @@ static int ti_sci_cmd_get_clock_state(const struct ti_sci_handle *handle,
        }
        req = (struct ti_sci_msg_req_get_clock_state *)xfer->xfer_buf;
        req->dev_id = dev_id;
-       req->clk_id = clk_id;
+       if (clk_id < 255) {
+               req->clk_id = clk_id;
+       } else {
+               req->clk_id = 255;
+               req->clk_id_32 = clk_id;
+       }
 
        ret = ti_sci_do_xfer(info, xfer);
        if (ret) {
@@ -1047,8 +1057,8 @@ fail:
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_get_clock(const struct ti_sci_handle *handle, u32 dev_id,
-                               u8 clk_id, bool needs_ssc, bool can_change_freq,
-                               bool enable_input_term)
+                               u32 clk_id, bool needs_ssc,
+                               bool can_change_freq, bool enable_input_term)
 {
        u32 flags = 0;
 
@@ -1073,7 +1083,7 @@ static int ti_sci_cmd_get_clock(const struct ti_sci_handle *handle, u32 dev_id,
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_idle_clock(const struct ti_sci_handle *handle,
-                                u32 dev_id, u8 clk_id)
+                                u32 dev_id, u32 clk_id)
 {
        return ti_sci_set_clock_state(handle, dev_id, clk_id, 0,
                                      MSG_CLOCK_SW_STATE_UNREQ);
@@ -1092,7 +1102,7 @@ static int ti_sci_cmd_idle_clock(const struct ti_sci_handle *handle,
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_put_clock(const struct ti_sci_handle *handle,
-                               u32 dev_id, u8 clk_id)
+                               u32 dev_id, u32 clk_id)
 {
        return ti_sci_set_clock_state(handle, dev_id, clk_id, 0,
                                      MSG_CLOCK_SW_STATE_AUTO);
@@ -1110,7 +1120,7 @@ static int ti_sci_cmd_put_clock(const struct ti_sci_handle *handle,
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_clk_is_auto(const struct ti_sci_handle *handle,
-                                 u32 dev_id, u8 clk_id, bool *req_state)
+                                 u32 dev_id, u32 clk_id, bool *req_state)
 {
        u8 state = 0;
        int ret;
@@ -1139,7 +1149,7 @@ static int ti_sci_cmd_clk_is_auto(const struct ti_sci_handle *handle,
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_clk_is_on(const struct ti_sci_handle *handle, u32 dev_id,
-                               u8 clk_id, bool *req_state, bool *curr_state)
+                               u32 clk_id, bool *req_state, bool *curr_state)
 {
        u8 c_state = 0, r_state = 0;
        int ret;
@@ -1172,7 +1182,7 @@ static int ti_sci_cmd_clk_is_on(const struct ti_sci_handle *handle, u32 dev_id,
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_clk_is_off(const struct ti_sci_handle *handle, u32 dev_id,
-                                u8 clk_id, bool *req_state, bool *curr_state)
+                                u32 clk_id, bool *req_state, bool *curr_state)
 {
        u8 c_state = 0, r_state = 0;
        int ret;
@@ -1204,7 +1214,7 @@ static int ti_sci_cmd_clk_is_off(const struct ti_sci_handle *handle, u32 dev_id,
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_clk_set_parent(const struct ti_sci_handle *handle,
-                                    u32 dev_id, u8 clk_id, u8 parent_id)
+                                    u32 dev_id, u32 clk_id, u32 parent_id)
 {
        struct ti_sci_info *info;
        struct ti_sci_msg_req_set_clock_parent *req;
@@ -1231,8 +1241,18 @@ static int ti_sci_cmd_clk_set_parent(const struct ti_sci_handle *handle,
        }
        req = (struct ti_sci_msg_req_set_clock_parent *)xfer->xfer_buf;
        req->dev_id = dev_id;
-       req->clk_id = clk_id;
-       req->parent_id = parent_id;
+       if (clk_id < 255) {
+               req->clk_id = clk_id;
+       } else {
+               req->clk_id = 255;
+               req->clk_id_32 = clk_id;
+       }
+       if (parent_id < 255) {
+               req->parent_id = parent_id;
+       } else {
+               req->parent_id = 255;
+               req->parent_id_32 = parent_id;
+       }
 
        ret = ti_sci_do_xfer(info, xfer);
        if (ret) {
@@ -1262,7 +1282,7 @@ fail:
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_clk_get_parent(const struct ti_sci_handle *handle,
-                                    u32 dev_id, u8 clk_id, u8 *parent_id)
+                                    u32 dev_id, u32 clk_id, u32 *parent_id)
 {
        struct ti_sci_info *info;
        struct ti_sci_msg_req_get_clock_parent *req;
@@ -1289,7 +1309,12 @@ static int ti_sci_cmd_clk_get_parent(const struct ti_sci_handle *handle,
        }
        req = (struct ti_sci_msg_req_get_clock_parent *)xfer->xfer_buf;
        req->dev_id = dev_id;
-       req->clk_id = clk_id;
+       if (clk_id < 255) {
+               req->clk_id = clk_id;
+       } else {
+               req->clk_id = 255;
+               req->clk_id_32 = clk_id;
+       }
 
        ret = ti_sci_do_xfer(info, xfer);
        if (ret) {
@@ -1299,10 +1324,14 @@ static int ti_sci_cmd_clk_get_parent(const struct ti_sci_handle *handle,
 
        resp = (struct ti_sci_msg_resp_get_clock_parent *)xfer->xfer_buf;
 
-       if (!ti_sci_is_response_ack(resp))
+       if (!ti_sci_is_response_ack(resp)) {
                ret = -ENODEV;
-       else
-               *parent_id = resp->parent_id;
+       } else {
+               if (resp->parent_id < 255)
+                       *parent_id = resp->parent_id;
+               else
+                       *parent_id = resp->parent_id_32;
+       }
 
 fail:
        ti_sci_put_one_xfer(&info->minfo, xfer);
@@ -1322,8 +1351,8 @@ fail:
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_clk_get_num_parents(const struct ti_sci_handle *handle,
-                                         u32 dev_id, u8 clk_id,
-                                         u8 *num_parents)
+                                         u32 dev_id, u32 clk_id,
+                                         u32 *num_parents)
 {
        struct ti_sci_info *info;
        struct ti_sci_msg_req_get_clock_num_parents *req;
@@ -1350,7 +1379,12 @@ static int ti_sci_cmd_clk_get_num_parents(const struct ti_sci_handle *handle,
        }
        req = (struct ti_sci_msg_req_get_clock_num_parents *)xfer->xfer_buf;
        req->dev_id = dev_id;
-       req->clk_id = clk_id;
+       if (clk_id < 255) {
+               req->clk_id = clk_id;
+       } else {
+               req->clk_id = 255;
+               req->clk_id_32 = clk_id;
+       }
 
        ret = ti_sci_do_xfer(info, xfer);
        if (ret) {
@@ -1360,10 +1394,14 @@ static int ti_sci_cmd_clk_get_num_parents(const struct ti_sci_handle *handle,
 
        resp = (struct ti_sci_msg_resp_get_clock_num_parents *)xfer->xfer_buf;
 
-       if (!ti_sci_is_response_ack(resp))
+       if (!ti_sci_is_response_ack(resp)) {
                ret = -ENODEV;
-       else
-               *num_parents = resp->num_parents;
+       } else {
+               if (resp->num_parents < 255)
+                       *num_parents = resp->num_parents;
+               else
+                       *num_parents = resp->num_parents_32;
+       }
 
 fail:
        ti_sci_put_one_xfer(&info->minfo, xfer);
@@ -1391,7 +1429,7 @@ fail:
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_clk_get_match_freq(const struct ti_sci_handle *handle,
-                                        u32 dev_id, u8 clk_id, u64 min_freq,
+                                        u32 dev_id, u32 clk_id, u64 min_freq,
                                         u64 target_freq, u64 max_freq,
                                         u64 *match_freq)
 {
@@ -1420,7 +1458,12 @@ static int ti_sci_cmd_clk_get_match_freq(const struct ti_sci_handle *handle,
        }
        req = (struct ti_sci_msg_req_query_clock_freq *)xfer->xfer_buf;
        req->dev_id = dev_id;
-       req->clk_id = clk_id;
+       if (clk_id < 255) {
+               req->clk_id = clk_id;
+       } else {
+               req->clk_id = 255;
+               req->clk_id_32 = clk_id;
+       }
        req->min_freq_hz = min_freq;
        req->target_freq_hz = target_freq;
        req->max_freq_hz = max_freq;
@@ -1463,7 +1506,7 @@ fail:
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_clk_set_freq(const struct ti_sci_handle *handle,
-                                  u32 dev_id, u8 clk_id, u64 min_freq,
+                                  u32 dev_id, u32 clk_id, u64 min_freq,
                                   u64 target_freq, u64 max_freq)
 {
        struct ti_sci_info *info;
@@ -1491,7 +1534,12 @@ static int ti_sci_cmd_clk_set_freq(const struct ti_sci_handle *handle,
        }
        req = (struct ti_sci_msg_req_set_clock_freq *)xfer->xfer_buf;
        req->dev_id = dev_id;
-       req->clk_id = clk_id;
+       if (clk_id < 255) {
+               req->clk_id = clk_id;
+       } else {
+               req->clk_id = 255;
+               req->clk_id_32 = clk_id;
+       }
        req->min_freq_hz = min_freq;
        req->target_freq_hz = target_freq;
        req->max_freq_hz = max_freq;
@@ -1524,7 +1572,7 @@ fail:
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_clk_get_freq(const struct ti_sci_handle *handle,
-                                  u32 dev_id, u8 clk_id, u64 *freq)
+                                  u32 dev_id, u32 clk_id, u64 *freq)
 {
        struct ti_sci_info *info;
        struct ti_sci_msg_req_get_clock_freq *req;
@@ -1551,7 +1599,12 @@ static int ti_sci_cmd_clk_get_freq(const struct ti_sci_handle *handle,
        }
        req = (struct ti_sci_msg_req_get_clock_freq *)xfer->xfer_buf;
        req->dev_id = dev_id;
-       req->clk_id = clk_id;
+       if (clk_id < 255) {
+               req->clk_id = clk_id;
+       } else {
+               req->clk_id = 255;
+               req->clk_id_32 = clk_id;
+       }
 
        ret = ti_sci_do_xfer(info, xfer);
        if (ret) {
@@ -2004,122 +2057,175 @@ static int ti_sci_cmd_free_event_map(const struct ti_sci_handle *handle,
                               ia_id, vint, global_event, vint_status_bit, 0);
 }
 
-/*
- * ti_sci_setup_ops() - Setup the operations structures
- * @info:      pointer to TISCI pointer
+/**
+ * ti_sci_cmd_ring_config() - configure RA ring
+ * @handle:            Pointer to TI SCI handle.
+ * @valid_params:      Bitfield defining validity of ring configuration
+ *                     parameters
+ * @nav_id:            Device ID of Navigator Subsystem from which the ring is
+ *                     allocated
+ * @index:             Ring index
+ * @addr_lo:           The ring base address lo 32 bits
+ * @addr_hi:           The ring base address hi 32 bits
+ * @count:             Number of ring elements
+ * @mode:              The mode of the ring
+ * @size:              The ring element size.
+ * @order_id:          Specifies the ring's bus order ID
+ *
+ * Return: 0 if all went well, else returns appropriate error value.
+ *
+ * See @ti_sci_msg_rm_ring_cfg_req for more info.
  */
-static void ti_sci_setup_ops(struct ti_sci_info *info)
+static int ti_sci_cmd_ring_config(const struct ti_sci_handle *handle,
+                                 u32 valid_params, u16 nav_id, u16 index,
+                                 u32 addr_lo, u32 addr_hi, u32 count,
+                                 u8 mode, u8 size, u8 order_id)
 {
-       struct ti_sci_ops *ops = &info->handle.ops;
-       struct ti_sci_core_ops *core_ops = &ops->core_ops;
-       struct ti_sci_dev_ops *dops = &ops->dev_ops;
-       struct ti_sci_clk_ops *cops = &ops->clk_ops;
-       struct ti_sci_rm_core_ops *rm_core_ops = &ops->rm_core_ops;
-       struct ti_sci_rm_irq_ops *iops = &ops->rm_irq_ops;
-
-       core_ops->reboot_device = ti_sci_cmd_core_reboot;
-
-       dops->get_device = ti_sci_cmd_get_device;
-       dops->idle_device = ti_sci_cmd_idle_device;
-       dops->put_device = ti_sci_cmd_put_device;
+       struct ti_sci_msg_rm_ring_cfg_req *req;
+       struct ti_sci_msg_hdr *resp;
+       struct ti_sci_xfer *xfer;
+       struct ti_sci_info *info;
+       struct device *dev;
+       int ret = 0;
 
-       dops->is_valid = ti_sci_cmd_dev_is_valid;
-       dops->get_context_loss_count = ti_sci_cmd_dev_get_clcnt;
-       dops->is_idle = ti_sci_cmd_dev_is_idle;
-       dops->is_stop = ti_sci_cmd_dev_is_stop;
-       dops->is_on = ti_sci_cmd_dev_is_on;
-       dops->is_transitioning = ti_sci_cmd_dev_is_trans;
-       dops->set_device_resets = ti_sci_cmd_set_device_resets;
-       dops->get_device_resets = ti_sci_cmd_get_device_resets;
+       if (IS_ERR_OR_NULL(handle))
+               return -EINVAL;
 
-       cops->get_clock = ti_sci_cmd_get_clock;
-       cops->idle_clock = ti_sci_cmd_idle_clock;
-       cops->put_clock = ti_sci_cmd_put_clock;
-       cops->is_auto = ti_sci_cmd_clk_is_auto;
-       cops->is_on = ti_sci_cmd_clk_is_on;
-       cops->is_off = ti_sci_cmd_clk_is_off;
+       info = handle_to_ti_sci_info(handle);
+       dev = info->dev;
 
-       cops->set_parent = ti_sci_cmd_clk_set_parent;
-       cops->get_parent = ti_sci_cmd_clk_get_parent;
-       cops->get_num_parents = ti_sci_cmd_clk_get_num_parents;
+       xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_RM_RING_CFG,
+                                  TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
+                                  sizeof(*req), sizeof(*resp));
+       if (IS_ERR(xfer)) {
+               ret = PTR_ERR(xfer);
+               dev_err(dev, "RM_RA:Message config failed(%d)\n", ret);
+               return ret;
+       }
+       req = (struct ti_sci_msg_rm_ring_cfg_req *)xfer->xfer_buf;
+       req->valid_params = valid_params;
+       req->nav_id = nav_id;
+       req->index = index;
+       req->addr_lo = addr_lo;
+       req->addr_hi = addr_hi;
+       req->count = count;
+       req->mode = mode;
+       req->size = size;
+       req->order_id = order_id;
 
-       cops->get_best_match_freq = ti_sci_cmd_clk_get_match_freq;
-       cops->set_freq = ti_sci_cmd_clk_set_freq;
-       cops->get_freq = ti_sci_cmd_clk_get_freq;
+       ret = ti_sci_do_xfer(info, xfer);
+       if (ret) {
+               dev_err(dev, "RM_RA:Mbox config send fail %d\n", ret);
+               goto fail;
+       }
 
-       rm_core_ops->get_range = ti_sci_cmd_get_resource_range;
-       rm_core_ops->get_range_from_shost =
-                               ti_sci_cmd_get_resource_range_from_shost;
+       resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf;
+       ret = ti_sci_is_response_ack(resp) ? 0 : -ENODEV;
 
-       iops->set_irq = ti_sci_cmd_set_irq;
-       iops->set_event_map = ti_sci_cmd_set_event_map;
-       iops->free_irq = ti_sci_cmd_free_irq;
-       iops->free_event_map = ti_sci_cmd_free_event_map;
+fail:
+       ti_sci_put_one_xfer(&info->minfo, xfer);
+       dev_dbg(dev, "RM_RA:config ring %u ret:%d\n", index, ret);
+       return ret;
 }
 
 /**
- * ti_sci_get_handle() - Get the TI SCI handle for a device
- * @dev:       Pointer to device for which we want SCI handle
+ * ti_sci_cmd_ring_get_config() - get RA ring configuration
+ * @handle:    Pointer to TI SCI handle.
+ * @nav_id:    Device ID of Navigator Subsystem from which the ring is
+ *             allocated
+ * @index:     Ring index
+ * @addr_lo:   Returns ring's base address lo 32 bits
+ * @addr_hi:   Returns ring's base address hi 32 bits
+ * @count:     Returns number of ring elements
+ * @mode:      Returns mode of the ring
+ * @size:      Returns ring element size
+ * @order_id:  Returns ring's bus order ID
  *
- * NOTE: The function does not track individual clients of the framework
- * and is expected to be maintained by caller of TI SCI protocol library.
- * ti_sci_put_handle must be balanced with successful ti_sci_get_handle
- * Return: pointer to handle if successful, else:
- * -EPROBE_DEFER if the instance is not ready
- * -ENODEV if the required node handler is missing
- * -EINVAL if invalid conditions are encountered.
+ * Return: 0 if all went well, else returns appropriate error value.
+ *
+ * See @ti_sci_msg_rm_ring_get_cfg_req for more info.
  */
-const struct ti_sci_handle *ti_sci_get_handle(struct device *dev)
+static int ti_sci_cmd_ring_get_config(const struct ti_sci_handle *handle,
+                                     u32 nav_id, u32 index, u8 *mode,
+                                     u32 *addr_lo, u32 *addr_hi,
+                                     u32 *count, u8 *size, u8 *order_id)
 {
-       struct device_node *ti_sci_np;
-       struct list_head *p;
-       struct ti_sci_handle *handle = NULL;
+       struct ti_sci_msg_rm_ring_get_cfg_resp *resp;
+       struct ti_sci_msg_rm_ring_get_cfg_req *req;
+       struct ti_sci_xfer *xfer;
        struct ti_sci_info *info;
+       struct device *dev;
+       int ret = 0;
 
-       if (!dev) {
-               pr_err("I need a device pointer\n");
-               return ERR_PTR(-EINVAL);
-       }
-       ti_sci_np = of_get_parent(dev->of_node);
-       if (!ti_sci_np) {
-               dev_err(dev, "No OF information\n");
-               return ERR_PTR(-EINVAL);
+       if (IS_ERR_OR_NULL(handle))
+               return -EINVAL;
+
+       info = handle_to_ti_sci_info(handle);
+       dev = info->dev;
+
+       xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_RM_RING_GET_CFG,
+                                  TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
+                                  sizeof(*req), sizeof(*resp));
+       if (IS_ERR(xfer)) {
+               ret = PTR_ERR(xfer);
+               dev_err(dev,
+                       "RM_RA:Message get config failed(%d)\n", ret);
+               return ret;
        }
+       req = (struct ti_sci_msg_rm_ring_get_cfg_req *)xfer->xfer_buf;
+       req->nav_id = nav_id;
+       req->index = index;
 
-       mutex_lock(&ti_sci_list_mutex);
-       list_for_each(p, &ti_sci_list) {
-               info = list_entry(p, struct ti_sci_info, node);
-               if (ti_sci_np == info->dev->of_node) {
-                       handle = &info->handle;
-                       info->users++;
-                       break;
-               }
+       ret = ti_sci_do_xfer(info, xfer);
+       if (ret) {
+               dev_err(dev, "RM_RA:Mbox get config send fail %d\n", ret);
+               goto fail;
        }
-       mutex_unlock(&ti_sci_list_mutex);
-       of_node_put(ti_sci_np);
 
-       if (!handle)
-               return ERR_PTR(-EPROBE_DEFER);
+       resp = (struct ti_sci_msg_rm_ring_get_cfg_resp *)xfer->xfer_buf;
 
-       return handle;
+       if (!ti_sci_is_response_ack(resp)) {
+               ret = -ENODEV;
+       } else {
+               if (mode)
+                       *mode = resp->mode;
+               if (addr_lo)
+                       *addr_lo = resp->addr_lo;
+               if (addr_hi)
+                       *addr_hi = resp->addr_hi;
+               if (count)
+                       *count = resp->count;
+               if (size)
+                       *size = resp->size;
+               if (order_id)
+                       *order_id = resp->order_id;
+       };
+
+fail:
+       ti_sci_put_one_xfer(&info->minfo, xfer);
+       dev_dbg(dev, "RM_RA:get config ring %u ret:%d\n", index, ret);
+       return ret;
 }
-EXPORT_SYMBOL_GPL(ti_sci_get_handle);
 
 /**
- * ti_sci_put_handle() - Release the handle acquired by ti_sci_get_handle
- * @handle:    Handle acquired by ti_sci_get_handle
- *
- * NOTE: The function does not track individual clients of the framework
- * and is expected to be maintained by caller of TI SCI protocol library.
- * ti_sci_put_handle must be balanced with successful ti_sci_get_handle
+ * ti_sci_cmd_rm_psil_pair() - Pair PSI-L source to destination thread
+ * @handle:    Pointer to TI SCI handle.
+ * @nav_id:    Device ID of Navigator Subsystem which should be used for
+ *             pairing
+ * @src_thread:        Source PSI-L thread ID
+ * @dst_thread: Destination PSI-L thread ID
  *
- * Return: 0 is successfully released
- * if an error pointer was passed, it returns the error value back,
- * if null was passed, it returns -EINVAL;
+ * Return: 0 if all went well, else returns appropriate error value.
  */
-int ti_sci_put_handle(const struct ti_sci_handle *handle)
+static int ti_sci_cmd_rm_psil_pair(const struct ti_sci_handle *handle,
+                                  u32 nav_id, u32 src_thread, u32 dst_thread)
 {
+       struct ti_sci_msg_psil_pair *req;
+       struct ti_sci_msg_hdr *resp;
+       struct ti_sci_xfer *xfer;
        struct ti_sci_info *info;
+       struct device *dev;
+       int ret = 0;
 
        if (IS_ERR(handle))
                return PTR_ERR(handle);
@@ -2127,59 +2233,844 @@ int ti_sci_put_handle(const struct ti_sci_handle *handle)
                return -EINVAL;
 
        info = handle_to_ti_sci_info(handle);
-       mutex_lock(&ti_sci_list_mutex);
-       if (!WARN_ON(!info->users))
-               info->users--;
-       mutex_unlock(&ti_sci_list_mutex);
+       dev = info->dev;
 
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ti_sci_put_handle);
+       xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_RM_PSIL_PAIR,
+                                  TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
+                                  sizeof(*req), sizeof(*resp));
+       if (IS_ERR(xfer)) {
+               ret = PTR_ERR(xfer);
+               dev_err(dev, "RM_PSIL:Message reconfig failed(%d)\n", ret);
+               return ret;
+       }
+       req = (struct ti_sci_msg_psil_pair *)xfer->xfer_buf;
+       req->nav_id = nav_id;
+       req->src_thread = src_thread;
+       req->dst_thread = dst_thread;
 
-static void devm_ti_sci_release(struct device *dev, void *res)
-{
-       const struct ti_sci_handle **ptr = res;
-       const struct ti_sci_handle *handle = *ptr;
-       int ret;
+       ret = ti_sci_do_xfer(info, xfer);
+       if (ret) {
+               dev_err(dev, "RM_PSIL:Mbox send fail %d\n", ret);
+               goto fail;
+       }
 
-       ret = ti_sci_put_handle(handle);
-       if (ret)
-               dev_err(dev, "failed to put handle %d\n", ret);
+       resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf;
+       ret = ti_sci_is_response_ack(resp) ? 0 : -EINVAL;
+
+fail:
+       ti_sci_put_one_xfer(&info->minfo, xfer);
+
+       return ret;
 }
 
 /**
- * devm_ti_sci_get_handle() - Managed get handle
- * @dev:       device for which we want SCI handle for.
- *
- * NOTE: This releases the handle once the device resources are
- * no longer needed. MUST NOT BE released with ti_sci_put_handle.
- * The function does not track individual clients of the framework
- * and is expected to be maintained by caller of TI SCI protocol library.
+ * ti_sci_cmd_rm_psil_unpair() - Unpair PSI-L source from destination thread
+ * @handle:    Pointer to TI SCI handle.
+ * @nav_id:    Device ID of Navigator Subsystem which should be used for
+ *             unpairing
+ * @src_thread:        Source PSI-L thread ID
+ * @dst_thread:        Destination PSI-L thread ID
  *
- * Return: 0 if all went fine, else corresponding error.
+ * Return: 0 if all went well, else returns appropriate error value.
  */
-const struct ti_sci_handle *devm_ti_sci_get_handle(struct device *dev)
+static int ti_sci_cmd_rm_psil_unpair(const struct ti_sci_handle *handle,
+                                    u32 nav_id, u32 src_thread, u32 dst_thread)
 {
-       const struct ti_sci_handle **ptr;
-       const struct ti_sci_handle *handle;
+       struct ti_sci_msg_psil_unpair *req;
+       struct ti_sci_msg_hdr *resp;
+       struct ti_sci_xfer *xfer;
+       struct ti_sci_info *info;
+       struct device *dev;
+       int ret = 0;
 
-       ptr = devres_alloc(devm_ti_sci_release, sizeof(*ptr), GFP_KERNEL);
-       if (!ptr)
-               return ERR_PTR(-ENOMEM);
-       handle = ti_sci_get_handle(dev);
+       if (IS_ERR(handle))
+               return PTR_ERR(handle);
+       if (!handle)
+               return -EINVAL;
 
-       if (!IS_ERR(handle)) {
-               *ptr = handle;
-               devres_add(dev, ptr);
-       } else {
-               devres_free(ptr);
+       info = handle_to_ti_sci_info(handle);
+       dev = info->dev;
+
+       xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_RM_PSIL_UNPAIR,
+                                  TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
+                                  sizeof(*req), sizeof(*resp));
+       if (IS_ERR(xfer)) {
+               ret = PTR_ERR(xfer);
+               dev_err(dev, "RM_PSIL:Message reconfig failed(%d)\n", ret);
+               return ret;
        }
+       req = (struct ti_sci_msg_psil_unpair *)xfer->xfer_buf;
+       req->nav_id = nav_id;
+       req->src_thread = src_thread;
+       req->dst_thread = dst_thread;
 
-       return handle;
-}
-EXPORT_SYMBOL_GPL(devm_ti_sci_get_handle);
+       ret = ti_sci_do_xfer(info, xfer);
+       if (ret) {
+               dev_err(dev, "RM_PSIL:Mbox send fail %d\n", ret);
+               goto fail;
+       }
 
-/**
+       resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf;
+       ret = ti_sci_is_response_ack(resp) ? 0 : -EINVAL;
+
+fail:
+       ti_sci_put_one_xfer(&info->minfo, xfer);
+
+       return ret;
+}
+
+/**
+ * ti_sci_cmd_rm_udmap_tx_ch_cfg() - Configure a UDMAP TX channel
+ * @handle:    Pointer to TI SCI handle.
+ * @params:    Pointer to ti_sci_msg_rm_udmap_tx_ch_cfg TX channel config
+ *             structure
+ *
+ * Return: 0 if all went well, else returns appropriate error value.
+ *
+ * See @ti_sci_msg_rm_udmap_tx_ch_cfg and @ti_sci_msg_rm_udmap_tx_ch_cfg_req for
+ * more info.
+ */
+static int ti_sci_cmd_rm_udmap_tx_ch_cfg(const struct ti_sci_handle *handle,
+                       const struct ti_sci_msg_rm_udmap_tx_ch_cfg *params)
+{
+       struct ti_sci_msg_rm_udmap_tx_ch_cfg_req *req;
+       struct ti_sci_msg_hdr *resp;
+       struct ti_sci_xfer *xfer;
+       struct ti_sci_info *info;
+       struct device *dev;
+       int ret = 0;
+
+       if (IS_ERR_OR_NULL(handle))
+               return -EINVAL;
+
+       info = handle_to_ti_sci_info(handle);
+       dev = info->dev;
+
+       xfer = ti_sci_get_one_xfer(info, TISCI_MSG_RM_UDMAP_TX_CH_CFG,
+                                  TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
+                                  sizeof(*req), sizeof(*resp));
+       if (IS_ERR(xfer)) {
+               ret = PTR_ERR(xfer);
+               dev_err(dev, "Message TX_CH_CFG alloc failed(%d)\n", ret);
+               return ret;
+       }
+       req = (struct ti_sci_msg_rm_udmap_tx_ch_cfg_req *)xfer->xfer_buf;
+       req->valid_params = params->valid_params;
+       req->nav_id = params->nav_id;
+       req->index = params->index;
+       req->tx_pause_on_err = params->tx_pause_on_err;
+       req->tx_filt_einfo = params->tx_filt_einfo;
+       req->tx_filt_pswords = params->tx_filt_pswords;
+       req->tx_atype = params->tx_atype;
+       req->tx_chan_type = params->tx_chan_type;
+       req->tx_supr_tdpkt = params->tx_supr_tdpkt;
+       req->tx_fetch_size = params->tx_fetch_size;
+       req->tx_credit_count = params->tx_credit_count;
+       req->txcq_qnum = params->txcq_qnum;
+       req->tx_priority = params->tx_priority;
+       req->tx_qos = params->tx_qos;
+       req->tx_orderid = params->tx_orderid;
+       req->fdepth = params->fdepth;
+       req->tx_sched_priority = params->tx_sched_priority;
+       req->tx_burst_size = params->tx_burst_size;
+
+       ret = ti_sci_do_xfer(info, xfer);
+       if (ret) {
+               dev_err(dev, "Mbox send TX_CH_CFG fail %d\n", ret);
+               goto fail;
+       }
+
+       resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf;
+       ret = ti_sci_is_response_ack(resp) ? 0 : -EINVAL;
+
+fail:
+       ti_sci_put_one_xfer(&info->minfo, xfer);
+       dev_dbg(dev, "TX_CH_CFG: chn %u ret:%u\n", params->index, ret);
+       return ret;
+}
+
+/**
+ * ti_sci_cmd_rm_udmap_rx_ch_cfg() - Configure a UDMAP RX channel
+ * @handle:    Pointer to TI SCI handle.
+ * @params:    Pointer to ti_sci_msg_rm_udmap_rx_ch_cfg RX channel config
+ *             structure
+ *
+ * Return: 0 if all went well, else returns appropriate error value.
+ *
+ * See @ti_sci_msg_rm_udmap_rx_ch_cfg and @ti_sci_msg_rm_udmap_rx_ch_cfg_req for
+ * more info.
+ */
+static int ti_sci_cmd_rm_udmap_rx_ch_cfg(const struct ti_sci_handle *handle,
+                       const struct ti_sci_msg_rm_udmap_rx_ch_cfg *params)
+{
+       struct ti_sci_msg_rm_udmap_rx_ch_cfg_req *req;
+       struct ti_sci_msg_hdr *resp;
+       struct ti_sci_xfer *xfer;
+       struct ti_sci_info *info;
+       struct device *dev;
+       int ret = 0;
+
+       if (IS_ERR_OR_NULL(handle))
+               return -EINVAL;
+
+       info = handle_to_ti_sci_info(handle);
+       dev = info->dev;
+
+       xfer = ti_sci_get_one_xfer(info, TISCI_MSG_RM_UDMAP_RX_CH_CFG,
+                                  TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
+                                  sizeof(*req), sizeof(*resp));
+       if (IS_ERR(xfer)) {
+               ret = PTR_ERR(xfer);
+               dev_err(dev, "Message RX_CH_CFG alloc failed(%d)\n", ret);
+               return ret;
+       }
+       req = (struct ti_sci_msg_rm_udmap_rx_ch_cfg_req *)xfer->xfer_buf;
+       req->valid_params = params->valid_params;
+       req->nav_id = params->nav_id;
+       req->index = params->index;
+       req->rx_fetch_size = params->rx_fetch_size;
+       req->rxcq_qnum = params->rxcq_qnum;
+       req->rx_priority = params->rx_priority;
+       req->rx_qos = params->rx_qos;
+       req->rx_orderid = params->rx_orderid;
+       req->rx_sched_priority = params->rx_sched_priority;
+       req->flowid_start = params->flowid_start;
+       req->flowid_cnt = params->flowid_cnt;
+       req->rx_pause_on_err = params->rx_pause_on_err;
+       req->rx_atype = params->rx_atype;
+       req->rx_chan_type = params->rx_chan_type;
+       req->rx_ignore_short = params->rx_ignore_short;
+       req->rx_ignore_long = params->rx_ignore_long;
+       req->rx_burst_size = params->rx_burst_size;
+
+       ret = ti_sci_do_xfer(info, xfer);
+       if (ret) {
+               dev_err(dev, "Mbox send RX_CH_CFG fail %d\n", ret);
+               goto fail;
+       }
+
+       resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf;
+       ret = ti_sci_is_response_ack(resp) ? 0 : -EINVAL;
+
+fail:
+       ti_sci_put_one_xfer(&info->minfo, xfer);
+       dev_dbg(dev, "RX_CH_CFG: chn %u ret:%d\n", params->index, ret);
+       return ret;
+}
+
+/**
+ * ti_sci_cmd_rm_udmap_rx_flow_cfg() - Configure UDMAP RX FLOW
+ * @handle:    Pointer to TI SCI handle.
+ * @params:    Pointer to ti_sci_msg_rm_udmap_flow_cfg RX FLOW config
+ *             structure
+ *
+ * Return: 0 if all went well, else returns appropriate error value.
+ *
+ * See @ti_sci_msg_rm_udmap_flow_cfg and @ti_sci_msg_rm_udmap_flow_cfg_req for
+ * more info.
+ */
+static int ti_sci_cmd_rm_udmap_rx_flow_cfg(const struct ti_sci_handle *handle,
+                       const struct ti_sci_msg_rm_udmap_flow_cfg *params)
+{
+       struct ti_sci_msg_rm_udmap_flow_cfg_req *req;
+       struct ti_sci_msg_hdr *resp;
+       struct ti_sci_xfer *xfer;
+       struct ti_sci_info *info;
+       struct device *dev;
+       int ret = 0;
+
+       if (IS_ERR_OR_NULL(handle))
+               return -EINVAL;
+
+       info = handle_to_ti_sci_info(handle);
+       dev = info->dev;
+
+       xfer = ti_sci_get_one_xfer(info, TISCI_MSG_RM_UDMAP_FLOW_CFG,
+                                  TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
+                                  sizeof(*req), sizeof(*resp));
+       if (IS_ERR(xfer)) {
+               ret = PTR_ERR(xfer);
+               dev_err(dev, "RX_FL_CFG: Message alloc failed(%d)\n", ret);
+               return ret;
+       }
+       req = (struct ti_sci_msg_rm_udmap_flow_cfg_req *)xfer->xfer_buf;
+       req->valid_params = params->valid_params;
+       req->nav_id = params->nav_id;
+       req->flow_index = params->flow_index;
+       req->rx_einfo_present = params->rx_einfo_present;
+       req->rx_psinfo_present = params->rx_psinfo_present;
+       req->rx_error_handling = params->rx_error_handling;
+       req->rx_desc_type = params->rx_desc_type;
+       req->rx_sop_offset = params->rx_sop_offset;
+       req->rx_dest_qnum = params->rx_dest_qnum;
+       req->rx_src_tag_hi = params->rx_src_tag_hi;
+       req->rx_src_tag_lo = params->rx_src_tag_lo;
+       req->rx_dest_tag_hi = params->rx_dest_tag_hi;
+       req->rx_dest_tag_lo = params->rx_dest_tag_lo;
+       req->rx_src_tag_hi_sel = params->rx_src_tag_hi_sel;
+       req->rx_src_tag_lo_sel = params->rx_src_tag_lo_sel;
+       req->rx_dest_tag_hi_sel = params->rx_dest_tag_hi_sel;
+       req->rx_dest_tag_lo_sel = params->rx_dest_tag_lo_sel;
+       req->rx_fdq0_sz0_qnum = params->rx_fdq0_sz0_qnum;
+       req->rx_fdq1_qnum = params->rx_fdq1_qnum;
+       req->rx_fdq2_qnum = params->rx_fdq2_qnum;
+       req->rx_fdq3_qnum = params->rx_fdq3_qnum;
+       req->rx_ps_location = params->rx_ps_location;
+
+       ret = ti_sci_do_xfer(info, xfer);
+       if (ret) {
+               dev_err(dev, "RX_FL_CFG: Mbox send fail %d\n", ret);
+               goto fail;
+       }
+
+       resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf;
+       ret = ti_sci_is_response_ack(resp) ? 0 : -EINVAL;
+
+fail:
+       ti_sci_put_one_xfer(&info->minfo, xfer);
+       dev_dbg(info->dev, "RX_FL_CFG: %u ret:%d\n", params->flow_index, ret);
+       return ret;
+}
+
+/**
+ * ti_sci_cmd_proc_request() - Command to request a physical processor control
+ * @handle:    Pointer to TI SCI handle
+ * @proc_id:   Processor ID this request is for
+ *
+ * Return: 0 if all went well, else returns appropriate error value.
+ */
+static int ti_sci_cmd_proc_request(const struct ti_sci_handle *handle,
+                                  u8 proc_id)
+{
+       struct ti_sci_msg_req_proc_request *req;
+       struct ti_sci_msg_hdr *resp;
+       struct ti_sci_info *info;
+       struct ti_sci_xfer *xfer;
+       struct device *dev;
+       int ret = 0;
+
+       if (!handle)
+               return -EINVAL;
+       if (IS_ERR(handle))
+               return PTR_ERR(handle);
+
+       info = handle_to_ti_sci_info(handle);
+       dev = info->dev;
+
+       xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_PROC_REQUEST,
+                                  TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
+                                  sizeof(*req), sizeof(*resp));
+       if (IS_ERR(xfer)) {
+               ret = PTR_ERR(xfer);
+               dev_err(dev, "Message alloc failed(%d)\n", ret);
+               return ret;
+       }
+       req = (struct ti_sci_msg_req_proc_request *)xfer->xfer_buf;
+       req->processor_id = proc_id;
+
+       ret = ti_sci_do_xfer(info, xfer);
+       if (ret) {
+               dev_err(dev, "Mbox send fail %d\n", ret);
+               goto fail;
+       }
+
+       resp = (struct ti_sci_msg_hdr *)xfer->tx_message.buf;
+
+       ret = ti_sci_is_response_ack(resp) ? 0 : -ENODEV;
+
+fail:
+       ti_sci_put_one_xfer(&info->minfo, xfer);
+
+       return ret;
+}
+
+/**
+ * ti_sci_cmd_proc_release() - Command to release a physical processor control
+ * @handle:    Pointer to TI SCI handle
+ * @proc_id:   Processor ID this request is for
+ *
+ * Return: 0 if all went well, else returns appropriate error value.
+ */
+static int ti_sci_cmd_proc_release(const struct ti_sci_handle *handle,
+                                  u8 proc_id)
+{
+       struct ti_sci_msg_req_proc_release *req;
+       struct ti_sci_msg_hdr *resp;
+       struct ti_sci_info *info;
+       struct ti_sci_xfer *xfer;
+       struct device *dev;
+       int ret = 0;
+
+       if (!handle)
+               return -EINVAL;
+       if (IS_ERR(handle))
+               return PTR_ERR(handle);
+
+       info = handle_to_ti_sci_info(handle);
+       dev = info->dev;
+
+       xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_PROC_RELEASE,
+                                  TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
+                                  sizeof(*req), sizeof(*resp));
+       if (IS_ERR(xfer)) {
+               ret = PTR_ERR(xfer);
+               dev_err(dev, "Message alloc failed(%d)\n", ret);
+               return ret;
+       }
+       req = (struct ti_sci_msg_req_proc_release *)xfer->xfer_buf;
+       req->processor_id = proc_id;
+
+       ret = ti_sci_do_xfer(info, xfer);
+       if (ret) {
+               dev_err(dev, "Mbox send fail %d\n", ret);
+               goto fail;
+       }
+
+       resp = (struct ti_sci_msg_hdr *)xfer->tx_message.buf;
+
+       ret = ti_sci_is_response_ack(resp) ? 0 : -ENODEV;
+
+fail:
+       ti_sci_put_one_xfer(&info->minfo, xfer);
+
+       return ret;
+}
+
+/**
+ * ti_sci_cmd_proc_handover() - Command to handover a physical processor
+ *                             control to a host in the processor's access
+ *                             control list.
+ * @handle:    Pointer to TI SCI handle
+ * @proc_id:   Processor ID this request is for
+ * @host_id:   Host ID to get the control of the processor
+ *
+ * Return: 0 if all went well, else returns appropriate error value.
+ */
+static int ti_sci_cmd_proc_handover(const struct ti_sci_handle *handle,
+                                   u8 proc_id, u8 host_id)
+{
+       struct ti_sci_msg_req_proc_handover *req;
+       struct ti_sci_msg_hdr *resp;
+       struct ti_sci_info *info;
+       struct ti_sci_xfer *xfer;
+       struct device *dev;
+       int ret = 0;
+
+       if (!handle)
+               return -EINVAL;
+       if (IS_ERR(handle))
+               return PTR_ERR(handle);
+
+       info = handle_to_ti_sci_info(handle);
+       dev = info->dev;
+
+       xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_PROC_HANDOVER,
+                                  TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
+                                  sizeof(*req), sizeof(*resp));
+       if (IS_ERR(xfer)) {
+               ret = PTR_ERR(xfer);
+               dev_err(dev, "Message alloc failed(%d)\n", ret);
+               return ret;
+       }
+       req = (struct ti_sci_msg_req_proc_handover *)xfer->xfer_buf;
+       req->processor_id = proc_id;
+       req->host_id = host_id;
+
+       ret = ti_sci_do_xfer(info, xfer);
+       if (ret) {
+               dev_err(dev, "Mbox send fail %d\n", ret);
+               goto fail;
+       }
+
+       resp = (struct ti_sci_msg_hdr *)xfer->tx_message.buf;
+
+       ret = ti_sci_is_response_ack(resp) ? 0 : -ENODEV;
+
+fail:
+       ti_sci_put_one_xfer(&info->minfo, xfer);
+
+       return ret;
+}
+
+/**
+ * ti_sci_cmd_proc_set_config() - Command to set the processor boot
+ *                                 configuration flags
+ * @handle:            Pointer to TI SCI handle
+ * @proc_id:           Processor ID this request is for
+ * @config_flags_set:  Configuration flags to be set
+ * @config_flags_clear:        Configuration flags to be cleared.
+ *
+ * Return: 0 if all went well, else returns appropriate error value.
+ */
+static int ti_sci_cmd_proc_set_config(const struct ti_sci_handle *handle,
+                                     u8 proc_id, u64 bootvector,
+                                     u32 config_flags_set,
+                                     u32 config_flags_clear)
+{
+       struct ti_sci_msg_req_set_config *req;
+       struct ti_sci_msg_hdr *resp;
+       struct ti_sci_info *info;
+       struct ti_sci_xfer *xfer;
+       struct device *dev;
+       int ret = 0;
+
+       if (!handle)
+               return -EINVAL;
+       if (IS_ERR(handle))
+               return PTR_ERR(handle);
+
+       info = handle_to_ti_sci_info(handle);
+       dev = info->dev;
+
+       xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_SET_CONFIG,
+                                  TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
+                                  sizeof(*req), sizeof(*resp));
+       if (IS_ERR(xfer)) {
+               ret = PTR_ERR(xfer);
+               dev_err(dev, "Message alloc failed(%d)\n", ret);
+               return ret;
+       }
+       req = (struct ti_sci_msg_req_set_config *)xfer->xfer_buf;
+       req->processor_id = proc_id;
+       req->bootvector_low = bootvector & TI_SCI_ADDR_LOW_MASK;
+       req->bootvector_high = (bootvector & TI_SCI_ADDR_HIGH_MASK) >>
+                               TI_SCI_ADDR_HIGH_SHIFT;
+       req->config_flags_set = config_flags_set;
+       req->config_flags_clear = config_flags_clear;
+
+       ret = ti_sci_do_xfer(info, xfer);
+       if (ret) {
+               dev_err(dev, "Mbox send fail %d\n", ret);
+               goto fail;
+       }
+
+       resp = (struct ti_sci_msg_hdr *)xfer->tx_message.buf;
+
+       ret = ti_sci_is_response_ack(resp) ? 0 : -ENODEV;
+
+fail:
+       ti_sci_put_one_xfer(&info->minfo, xfer);
+
+       return ret;
+}
+
+/**
+ * ti_sci_cmd_proc_set_control() - Command to set the processor boot
+ *                                  control flags
+ * @handle:                    Pointer to TI SCI handle
+ * @proc_id:                   Processor ID this request is for
+ * @control_flags_set:         Control flags to be set
+ * @control_flags_clear:       Control flags to be cleared
+ *
+ * Return: 0 if all went well, else returns appropriate error value.
+ */
+static int ti_sci_cmd_proc_set_control(const struct ti_sci_handle *handle,
+                                      u8 proc_id, u32 control_flags_set,
+                                      u32 control_flags_clear)
+{
+       struct ti_sci_msg_req_set_ctrl *req;
+       struct ti_sci_msg_hdr *resp;
+       struct ti_sci_info *info;
+       struct ti_sci_xfer *xfer;
+       struct device *dev;
+       int ret = 0;
+
+       if (!handle)
+               return -EINVAL;
+       if (IS_ERR(handle))
+               return PTR_ERR(handle);
+
+       info = handle_to_ti_sci_info(handle);
+       dev = info->dev;
+
+       xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_SET_CTRL,
+                                  TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
+                                  sizeof(*req), sizeof(*resp));
+       if (IS_ERR(xfer)) {
+               ret = PTR_ERR(xfer);
+               dev_err(dev, "Message alloc failed(%d)\n", ret);
+               return ret;
+       }
+       req = (struct ti_sci_msg_req_set_ctrl *)xfer->xfer_buf;
+       req->processor_id = proc_id;
+       req->control_flags_set = control_flags_set;
+       req->control_flags_clear = control_flags_clear;
+
+       ret = ti_sci_do_xfer(info, xfer);
+       if (ret) {
+               dev_err(dev, "Mbox send fail %d\n", ret);
+               goto fail;
+       }
+
+       resp = (struct ti_sci_msg_hdr *)xfer->tx_message.buf;
+
+       ret = ti_sci_is_response_ack(resp) ? 0 : -ENODEV;
+
+fail:
+       ti_sci_put_one_xfer(&info->minfo, xfer);
+
+       return ret;
+}
+
+/**
+ * ti_sci_cmd_get_boot_status() - Command to get the processor boot status
+ * @handle:    Pointer to TI SCI handle
+ * @proc_id:   Processor ID this request is for
+ *
+ * Return: 0 if all went well, else returns appropriate error value.
+ */
+static int ti_sci_cmd_proc_get_status(const struct ti_sci_handle *handle,
+                                     u8 proc_id, u64 *bv, u32 *cfg_flags,
+                                     u32 *ctrl_flags, u32 *sts_flags)
+{
+       struct ti_sci_msg_resp_get_status *resp;
+       struct ti_sci_msg_req_get_status *req;
+       struct ti_sci_info *info;
+       struct ti_sci_xfer *xfer;
+       struct device *dev;
+       int ret = 0;
+
+       if (!handle)
+               return -EINVAL;
+       if (IS_ERR(handle))
+               return PTR_ERR(handle);
+
+       info = handle_to_ti_sci_info(handle);
+       dev = info->dev;
+
+       xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_GET_STATUS,
+                                  TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
+                                  sizeof(*req), sizeof(*resp));
+       if (IS_ERR(xfer)) {
+               ret = PTR_ERR(xfer);
+               dev_err(dev, "Message alloc failed(%d)\n", ret);
+               return ret;
+       }
+       req = (struct ti_sci_msg_req_get_status *)xfer->xfer_buf;
+       req->processor_id = proc_id;
+
+       ret = ti_sci_do_xfer(info, xfer);
+       if (ret) {
+               dev_err(dev, "Mbox send fail %d\n", ret);
+               goto fail;
+       }
+
+       resp = (struct ti_sci_msg_resp_get_status *)xfer->tx_message.buf;
+
+       if (!ti_sci_is_response_ack(resp)) {
+               ret = -ENODEV;
+       } else {
+               *bv = (resp->bootvector_low & TI_SCI_ADDR_LOW_MASK) |
+                     (((u64)resp->bootvector_high << TI_SCI_ADDR_HIGH_SHIFT) &
+                      TI_SCI_ADDR_HIGH_MASK);
+               *cfg_flags = resp->config_flags;
+               *ctrl_flags = resp->control_flags;
+               *sts_flags = resp->status_flags;
+       }
+
+fail:
+       ti_sci_put_one_xfer(&info->minfo, xfer);
+
+       return ret;
+}
+
+/*
+ * ti_sci_setup_ops() - Setup the operations structures
+ * @info:      pointer to TISCI pointer
+ */
+static void ti_sci_setup_ops(struct ti_sci_info *info)
+{
+       struct ti_sci_ops *ops = &info->handle.ops;
+       struct ti_sci_core_ops *core_ops = &ops->core_ops;
+       struct ti_sci_dev_ops *dops = &ops->dev_ops;
+       struct ti_sci_clk_ops *cops = &ops->clk_ops;
+       struct ti_sci_rm_core_ops *rm_core_ops = &ops->rm_core_ops;
+       struct ti_sci_rm_irq_ops *iops = &ops->rm_irq_ops;
+       struct ti_sci_rm_ringacc_ops *rops = &ops->rm_ring_ops;
+       struct ti_sci_rm_psil_ops *psilops = &ops->rm_psil_ops;
+       struct ti_sci_rm_udmap_ops *udmap_ops = &ops->rm_udmap_ops;
+       struct ti_sci_proc_ops *pops = &ops->proc_ops;
+
+       core_ops->reboot_device = ti_sci_cmd_core_reboot;
+
+       dops->get_device = ti_sci_cmd_get_device;
+       dops->idle_device = ti_sci_cmd_idle_device;
+       dops->put_device = ti_sci_cmd_put_device;
+
+       dops->is_valid = ti_sci_cmd_dev_is_valid;
+       dops->get_context_loss_count = ti_sci_cmd_dev_get_clcnt;
+       dops->is_idle = ti_sci_cmd_dev_is_idle;
+       dops->is_stop = ti_sci_cmd_dev_is_stop;
+       dops->is_on = ti_sci_cmd_dev_is_on;
+       dops->is_transitioning = ti_sci_cmd_dev_is_trans;
+       dops->set_device_resets = ti_sci_cmd_set_device_resets;
+       dops->get_device_resets = ti_sci_cmd_get_device_resets;
+
+       cops->get_clock = ti_sci_cmd_get_clock;
+       cops->idle_clock = ti_sci_cmd_idle_clock;
+       cops->put_clock = ti_sci_cmd_put_clock;
+       cops->is_auto = ti_sci_cmd_clk_is_auto;
+       cops->is_on = ti_sci_cmd_clk_is_on;
+       cops->is_off = ti_sci_cmd_clk_is_off;
+
+       cops->set_parent = ti_sci_cmd_clk_set_parent;
+       cops->get_parent = ti_sci_cmd_clk_get_parent;
+       cops->get_num_parents = ti_sci_cmd_clk_get_num_parents;
+
+       cops->get_best_match_freq = ti_sci_cmd_clk_get_match_freq;
+       cops->set_freq = ti_sci_cmd_clk_set_freq;
+       cops->get_freq = ti_sci_cmd_clk_get_freq;
+
+       rm_core_ops->get_range = ti_sci_cmd_get_resource_range;
+       rm_core_ops->get_range_from_shost =
+                               ti_sci_cmd_get_resource_range_from_shost;
+
+       iops->set_irq = ti_sci_cmd_set_irq;
+       iops->set_event_map = ti_sci_cmd_set_event_map;
+       iops->free_irq = ti_sci_cmd_free_irq;
+       iops->free_event_map = ti_sci_cmd_free_event_map;
+
+       rops->config = ti_sci_cmd_ring_config;
+       rops->get_config = ti_sci_cmd_ring_get_config;
+
+       psilops->pair = ti_sci_cmd_rm_psil_pair;
+       psilops->unpair = ti_sci_cmd_rm_psil_unpair;
+
+       udmap_ops->tx_ch_cfg = ti_sci_cmd_rm_udmap_tx_ch_cfg;
+       udmap_ops->rx_ch_cfg = ti_sci_cmd_rm_udmap_rx_ch_cfg;
+       udmap_ops->rx_flow_cfg = ti_sci_cmd_rm_udmap_rx_flow_cfg;
+
+       pops->request = ti_sci_cmd_proc_request;
+       pops->release = ti_sci_cmd_proc_release;
+       pops->handover = ti_sci_cmd_proc_handover;
+       pops->set_config = ti_sci_cmd_proc_set_config;
+       pops->set_control = ti_sci_cmd_proc_set_control;
+       pops->get_status = ti_sci_cmd_proc_get_status;
+}
+
+/**
+ * ti_sci_get_handle() - Get the TI SCI handle for a device
+ * @dev:       Pointer to device for which we want SCI handle
+ *
+ * NOTE: The function does not track individual clients of the framework
+ * and is expected to be maintained by caller of TI SCI protocol library.
+ * ti_sci_put_handle must be balanced with successful ti_sci_get_handle
+ * Return: pointer to handle if successful, else:
+ * -EPROBE_DEFER if the instance is not ready
+ * -ENODEV if the required node handler is missing
+ * -EINVAL if invalid conditions are encountered.
+ */
+const struct ti_sci_handle *ti_sci_get_handle(struct device *dev)
+{
+       struct device_node *ti_sci_np;
+       struct list_head *p;
+       struct ti_sci_handle *handle = NULL;
+       struct ti_sci_info *info;
+
+       if (!dev) {
+               pr_err("I need a device pointer\n");
+               return ERR_PTR(-EINVAL);
+       }
+       ti_sci_np = of_get_parent(dev->of_node);
+       if (!ti_sci_np) {
+               dev_err(dev, "No OF information\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       mutex_lock(&ti_sci_list_mutex);
+       list_for_each(p, &ti_sci_list) {
+               info = list_entry(p, struct ti_sci_info, node);
+               if (ti_sci_np == info->dev->of_node) {
+                       handle = &info->handle;
+                       info->users++;
+                       break;
+               }
+       }
+       mutex_unlock(&ti_sci_list_mutex);
+       of_node_put(ti_sci_np);
+
+       if (!handle)
+               return ERR_PTR(-EPROBE_DEFER);
+
+       return handle;
+}
+EXPORT_SYMBOL_GPL(ti_sci_get_handle);
+
+/**
+ * ti_sci_put_handle() - Release the handle acquired by ti_sci_get_handle
+ * @handle:    Handle acquired by ti_sci_get_handle
+ *
+ * NOTE: The function does not track individual clients of the framework
+ * and is expected to be maintained by caller of TI SCI protocol library.
+ * ti_sci_put_handle must be balanced with successful ti_sci_get_handle
+ *
+ * Return: 0 is successfully released
+ * if an error pointer was passed, it returns the error value back,
+ * if null was passed, it returns -EINVAL;
+ */
+int ti_sci_put_handle(const struct ti_sci_handle *handle)
+{
+       struct ti_sci_info *info;
+
+       if (IS_ERR(handle))
+               return PTR_ERR(handle);
+       if (!handle)
+               return -EINVAL;
+
+       info = handle_to_ti_sci_info(handle);
+       mutex_lock(&ti_sci_list_mutex);
+       if (!WARN_ON(!info->users))
+               info->users--;
+       mutex_unlock(&ti_sci_list_mutex);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ti_sci_put_handle);
+
+static void devm_ti_sci_release(struct device *dev, void *res)
+{
+       const struct ti_sci_handle **ptr = res;
+       const struct ti_sci_handle *handle = *ptr;
+       int ret;
+
+       ret = ti_sci_put_handle(handle);
+       if (ret)
+               dev_err(dev, "failed to put handle %d\n", ret);
+}
+
+/**
+ * devm_ti_sci_get_handle() - Managed get handle
+ * @dev:       device for which we want SCI handle for.
+ *
+ * NOTE: This releases the handle once the device resources are
+ * no longer needed. MUST NOT BE released with ti_sci_put_handle.
+ * The function does not track individual clients of the framework
+ * and is expected to be maintained by caller of TI SCI protocol library.
+ *
+ * Return: 0 if all went fine, else corresponding error.
+ */
+const struct ti_sci_handle *devm_ti_sci_get_handle(struct device *dev)
+{
+       const struct ti_sci_handle **ptr;
+       const struct ti_sci_handle *handle;
+
+       ptr = devres_alloc(devm_ti_sci_release, sizeof(*ptr), GFP_KERNEL);
+       if (!ptr)
+               return ERR_PTR(-ENOMEM);
+       handle = ti_sci_get_handle(dev);
+
+       if (!IS_ERR(handle)) {
+               *ptr = handle;
+               devres_add(dev, ptr);
+       } else {
+               devres_free(ptr);
+       }
+
+       return handle;
+}
+EXPORT_SYMBOL_GPL(devm_ti_sci_get_handle);
+
+/**
  * ti_sci_get_by_phandle() - Get the TI SCI handle using DT phandle
  * @np:                device node
  * @property:  property name containing phandle on TISCI node
@@ -2342,6 +3233,7 @@ devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
                            struct device *dev, u32 dev_id, char *of_prop)
 {
        struct ti_sci_resource *res;
+       bool valid_set = false;
        u32 resource_subtype;
        int i, ret;
 
@@ -2349,12 +3241,13 @@ devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
        if (!res)
                return ERR_PTR(-ENOMEM);
 
-       res->sets = of_property_count_elems_of_size(dev_of_node(dev), of_prop,
-                                                   sizeof(u32));
-       if (res->sets < 0) {
+       ret = of_property_count_elems_of_size(dev_of_node(dev), of_prop,
+                                             sizeof(u32));
+       if (ret < 0) {
                dev_err(dev, "%s resource type ids not available\n", of_prop);
-               return ERR_PTR(res->sets);
+               return ERR_PTR(ret);
        }
+       res->sets = ret;
 
        res->desc = devm_kcalloc(dev, res->sets, sizeof(*res->desc),
                                 GFP_KERNEL);
@@ -2372,15 +3265,18 @@ devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
                                                        &res->desc[i].start,
                                                        &res->desc[i].num);
                if (ret) {
-                       dev_err(dev, "dev = %d subtype %d not allocated for this host\n",
+                       dev_dbg(dev, "dev = %d subtype %d not allocated for this host\n",
                                dev_id, resource_subtype);
-                       return ERR_PTR(ret);
+                       res->desc[i].start = 0;
+                       res->desc[i].num = 0;
+                       continue;
                }
 
                dev_dbg(dev, "dev = %d, subtype = %d, start = %d, num = %d\n",
                        dev_id, resource_subtype, res->desc[i].start,
                        res->desc[i].num);
 
+               valid_set = true;
                res->desc[i].res_map =
                        devm_kzalloc(dev, BITS_TO_LONGS(res->desc[i].num) *
                                     sizeof(*res->desc[i].res_map), GFP_KERNEL);
@@ -2389,7 +3285,10 @@ devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
        }
        raw_spin_lock_init(&res->lock);
 
-       return res;
+       if (valid_set)
+               return res;
+
+       return ERR_PTR(-EINVAL);
 }
 
 static int tisci_reboot_handler(struct notifier_block *nb, unsigned long mode,
index adbeeef..f0d068c 100644 (file)
 #define TI_SCI_MSG_SET_IRQ             0x1000
 #define TI_SCI_MSG_FREE_IRQ            0x1001
 
+/* NAVSS resource management */
+/* Ringacc requests */
+#define TI_SCI_MSG_RM_RING_ALLOCATE            0x1100
+#define TI_SCI_MSG_RM_RING_FREE                        0x1101
+#define TI_SCI_MSG_RM_RING_RECONFIG            0x1102
+#define TI_SCI_MSG_RM_RING_RESET               0x1103
+#define TI_SCI_MSG_RM_RING_CFG                 0x1110
+#define TI_SCI_MSG_RM_RING_GET_CFG             0x1111
+
+/* PSI-L requests */
+#define TI_SCI_MSG_RM_PSIL_PAIR                        0x1280
+#define TI_SCI_MSG_RM_PSIL_UNPAIR              0x1281
+
+#define TI_SCI_MSG_RM_UDMAP_TX_ALLOC           0x1200
+#define TI_SCI_MSG_RM_UDMAP_TX_FREE            0x1201
+#define TI_SCI_MSG_RM_UDMAP_RX_ALLOC           0x1210
+#define TI_SCI_MSG_RM_UDMAP_RX_FREE            0x1211
+#define TI_SCI_MSG_RM_UDMAP_FLOW_CFG           0x1220
+#define TI_SCI_MSG_RM_UDMAP_OPT_FLOW_CFG       0x1221
+
+#define TISCI_MSG_RM_UDMAP_TX_CH_CFG           0x1205
+#define TISCI_MSG_RM_UDMAP_TX_CH_GET_CFG       0x1206
+#define TISCI_MSG_RM_UDMAP_RX_CH_CFG           0x1215
+#define TISCI_MSG_RM_UDMAP_RX_CH_GET_CFG       0x1216
+#define TISCI_MSG_RM_UDMAP_FLOW_CFG            0x1230
+#define TISCI_MSG_RM_UDMAP_FLOW_SIZE_THRESH_CFG        0x1231
+#define TISCI_MSG_RM_UDMAP_FLOW_GET_CFG                0x1232
+#define TISCI_MSG_RM_UDMAP_FLOW_SIZE_THRESH_GET_CFG    0x1233
+
+/* Processor Control requests */
+#define TI_SCI_MSG_PROC_REQUEST                0xc000
+#define TI_SCI_MSG_PROC_RELEASE                0xc001
+#define TI_SCI_MSG_PROC_HANDOVER       0xc005
+#define TI_SCI_MSG_SET_CONFIG          0xc100
+#define TI_SCI_MSG_SET_CTRL            0xc101
+#define TI_SCI_MSG_GET_STATUS          0xc400
+
 /**
  * struct ti_sci_msg_hdr - Generic Message Header for All messages and responses
  * @type:      Type of messages: One of TI_SCI_MSG* values
@@ -202,7 +239,8 @@ struct ti_sci_msg_req_set_device_resets {
  * @dev_id:    Device identifier this request is for
  * @clk_id:    Clock identifier for the device for this request.
  *             Each device has it's own set of clock inputs. This indexes
- *             which clock input to modify.
+ *             which clock input to modify. Set to 255 if clock ID is
+ *             greater than or equal to 255.
  * @request_state: Request the state for the clock to be set to.
  *             MSG_CLOCK_SW_STATE_UNREQ: The IP does not require this clock,
  *             it can be disabled, regardless of the state of the device
@@ -213,6 +251,9 @@ struct ti_sci_msg_req_set_device_resets {
  *             being required by the device.(default)
  *             MSG_CLOCK_SW_STATE_REQ:  Configure the clock to be enabled,
  *             regardless of the state of the device.
+ * @clk_id_32: Clock identifier for the device for this request.
+ *             Only to be used if the clock ID is greater than or equal to
+ *             255.
  *
  * Normally, all required clocks are managed by TISCI entity, this is used
  * only for specific control *IF* required. Auto managed state is
@@ -234,6 +275,7 @@ struct ti_sci_msg_req_set_clock_state {
 #define MSG_CLOCK_SW_STATE_AUTO                1
 #define MSG_CLOCK_SW_STATE_REQ         2
        u8 request_state;
+       u32 clk_id_32;
 } __packed;
 
 /**
@@ -242,7 +284,11 @@ struct ti_sci_msg_req_set_clock_state {
  * @dev_id:    Device identifier this request is for
  * @clk_id:    Clock identifier for the device for this request.
  *             Each device has it's own set of clock inputs. This indexes
- *             which clock input to get state of.
+ *             which clock input to get state of. Set to 255 if the clock
+ *             ID is greater than or equal to 255.
+ * @clk_id_32: Clock identifier for the device for the request.
+ *             Only to be used if the clock ID is greater than or equal to
+ *             255.
  *
  * Request type is TI_SCI_MSG_GET_CLOCK_STATE, response is state
  * of the clock
@@ -251,6 +297,7 @@ struct ti_sci_msg_req_get_clock_state {
        struct ti_sci_msg_hdr hdr;
        u32 dev_id;
        u8 clk_id;
+       u32 clk_id_32;
 } __packed;
 
 /**
@@ -278,9 +325,13 @@ struct ti_sci_msg_resp_get_clock_state {
  * @dev_id:    Device identifier this request is for
  * @clk_id:    Clock identifier for the device for this request.
  *             Each device has it's own set of clock inputs. This indexes
- *             which clock input to modify.
+ *             which clock input to modify. Set to 255 if clock ID is
+ *             greater than or equal to 255.
  * @parent_id: The new clock parent is selectable by an index via this
- *             parameter.
+ *             parameter. Set to 255 if clock ID is greater than or
+ *             equal to 255.
+ * @clk_id_32: Clock identifier if @clk_id field is 255.
+ * @parent_id_32:      Parent identifier if @parent_id is 255.
  *
  * Request type is TI_SCI_MSG_SET_CLOCK_PARENT, response is generic
  * ACK / NACK message.
@@ -290,6 +341,8 @@ struct ti_sci_msg_req_set_clock_parent {
        u32 dev_id;
        u8 clk_id;
        u8 parent_id;
+       u32 clk_id_32;
+       u32 parent_id_32;
 } __packed;
 
 /**
@@ -298,7 +351,10 @@ struct ti_sci_msg_req_set_clock_parent {
  * @dev_id:    Device identifier this request is for
  * @clk_id:    Clock identifier for the device for this request.
  *             Each device has it's own set of clock inputs. This indexes
- *             which clock input to get the parent for.
+ *             which clock input to get the parent for. If this field
+ *             contains 255, the actual clock identifier is stored in
+ *             @clk_id_32.
+ * @clk_id_32: Clock identifier if the @clk_id field contains 255.
  *
  * Request type is TI_SCI_MSG_GET_CLOCK_PARENT, response is parent information
  */
@@ -306,25 +362,32 @@ struct ti_sci_msg_req_get_clock_parent {
        struct ti_sci_msg_hdr hdr;
        u32 dev_id;
        u8 clk_id;
+       u32 clk_id_32;
 } __packed;
 
 /**
  * struct ti_sci_msg_resp_get_clock_parent - Response with clock parent
  * @hdr:       Generic Header
- * @parent_id: The current clock parent
+ * @parent_id: The current clock parent. If set to 255, the current parent
+ *             ID can be found from the @parent_id_32 field.
+ * @parent_id_32:      Current clock parent if @parent_id field is set to
+ *                     255.
  *
  * Response to TI_SCI_MSG_GET_CLOCK_PARENT.
  */
 struct ti_sci_msg_resp_get_clock_parent {
        struct ti_sci_msg_hdr hdr;
        u8 parent_id;
+       u32 parent_id_32;
 } __packed;
 
 /**
  * struct ti_sci_msg_req_get_clock_num_parents - Request to get clock parents
  * @hdr:       Generic header
  * @dev_id:    Device identifier this request is for
- * @clk_id:    Clock identifier for the device for this request.
+ * @clk_id:    Clock identifier for the device for this request. Set to
+ *             255 if clock ID is greater than or equal to 255.
+ * @clk_id_32: Clock identifier if the @clk_id field contains 255.
  *
  * This request provides information about how many clock parent options
  * are available for a given clock to a device. This is typically used
@@ -337,18 +400,24 @@ struct ti_sci_msg_req_get_clock_num_parents {
        struct ti_sci_msg_hdr hdr;
        u32 dev_id;
        u8 clk_id;
+       u32 clk_id_32;
 } __packed;
 
 /**
  * struct ti_sci_msg_resp_get_clock_num_parents - Response for get clk parents
  * @hdr:               Generic header
- * @num_parents:       Number of clock parents
+ * @num_parents:       Number of clock parents. If set to 255, the actual
+ *                     number of parents is stored into @num_parents_32
+ *                     field instead.
+ * @num_parents_32:    Number of clock parents if @num_parents field is
+ *                     set to 255.
  *
  * Response to TI_SCI_MSG_GET_NUM_CLOCK_PARENTS
  */
 struct ti_sci_msg_resp_get_clock_num_parents {
        struct ti_sci_msg_hdr hdr;
        u8 num_parents;
+       u32 num_parents_32;
 } __packed;
 
 /**
@@ -363,7 +432,9 @@ struct ti_sci_msg_resp_get_clock_num_parents {
  * @max_freq_hz: The maximum allowable frequency in Hz. This is the maximum
  *             allowable programmed frequency and does not account for clock
  *             tolerances and jitter.
- * @clk_id:    Clock identifier for the device for this request.
+ * @clk_id:    Clock identifier for the device for this request. Set to
+ *             255 if clock identifier is greater than or equal to 255.
+ * @clk_id_32: Clock identifier if @clk_id is set to 255.
  *
  * NOTE: Normally clock frequency management is automatically done by TISCI
  * entity. In case of specific requests, TISCI evaluates capability to achieve
@@ -380,6 +451,7 @@ struct ti_sci_msg_req_query_clock_freq {
        u64 target_freq_hz;
        u64 max_freq_hz;
        u8 clk_id;
+       u32 clk_id_32;
 } __packed;
 
 /**
@@ -407,7 +479,9 @@ struct ti_sci_msg_resp_query_clock_freq {
  * @max_freq_hz: The maximum allowable frequency in Hz. This is the maximum
  *             allowable programmed frequency and does not account for clock
  *             tolerances and jitter.
- * @clk_id:    Clock identifier for the device for this request.
+ * @clk_id:    Clock identifier for the device for this request. Set to
+ *             255 if clock ID is greater than or equal to 255.
+ * @clk_id_32: Clock identifier if @clk_id field is set to 255.
  *
  * NOTE: Normally clock frequency management is automatically done by TISCI
  * entity. In case of specific requests, TISCI evaluates capability to achieve
@@ -436,13 +510,16 @@ struct ti_sci_msg_req_set_clock_freq {
        u64 target_freq_hz;
        u64 max_freq_hz;
        u8 clk_id;
+       u32 clk_id_32;
 } __packed;
 
 /**
  * struct ti_sci_msg_req_get_clock_freq - Request to get the clock frequency
  * @hdr:       Generic Header
  * @dev_id:    Device identifier this request is for
- * @clk_id:    Clock identifier for the device for this request.
+ * @clk_id:    Clock identifier for the device for this request. Set to
+ *             255 if clock ID is greater than or equal to 255.
+ * @clk_id_32: Clock identifier if @clk_id field is set to 255.
  *
  * NOTE: Normally clock frequency management is automatically done by TISCI
  * entity. In some cases, clock frequencies are configured by host.
@@ -454,6 +531,7 @@ struct ti_sci_msg_req_get_clock_freq {
        struct ti_sci_msg_hdr hdr;
        u32 dev_id;
        u8 clk_id;
+       u32 clk_id_32;
 } __packed;
 
 /**
@@ -563,4 +641,777 @@ struct ti_sci_msg_req_manage_irq {
        u8 secondary_host;
 } __packed;
 
+/**
+ * struct ti_sci_msg_rm_ring_cfg_req - Configure a Navigator Subsystem ring
+ *
+ * Configures the non-real-time registers of a Navigator Subsystem ring.
+ * @hdr:       Generic Header
+ * @valid_params: Bitfield defining validity of ring configuration parameters.
+ *     The ring configuration fields are not valid, and will not be used for
+ *     ring configuration, if their corresponding valid bit is zero.
+ *     Valid bit usage:
+ *     0 - Valid bit for @tisci_msg_rm_ring_cfg_req addr_lo
+ *     1 - Valid bit for @tisci_msg_rm_ring_cfg_req addr_hi
+ *     2 - Valid bit for @tisci_msg_rm_ring_cfg_req count
+ *     3 - Valid bit for @tisci_msg_rm_ring_cfg_req mode
+ *     4 - Valid bit for @tisci_msg_rm_ring_cfg_req size
+ *     5 - Valid bit for @tisci_msg_rm_ring_cfg_req order_id
+ * @nav_id: Device ID of Navigator Subsystem from which the ring is allocated
+ * @index: ring index to be configured.
+ * @addr_lo: 32 LSBs of ring base address to be programmed into the ring's
+ *     RING_BA_LO register
+ * @addr_hi: 16 MSBs of ring base address to be programmed into the ring's
+ *     RING_BA_HI register.
+ * @count: Number of ring elements. Must be even if mode is CREDENTIALS or QM
+ *     modes.
+ * @mode: Specifies the mode the ring is to be configured.
+ * @size: Specifies encoded ring element size. To calculate the encoded size use
+ *     the formula (log2(size_bytes) - 2), where size_bytes cannot be
+ *     greater than 256.
+ * @order_id: Specifies the ring's bus order ID.
+ */
+struct ti_sci_msg_rm_ring_cfg_req {
+       struct ti_sci_msg_hdr hdr;
+       u32 valid_params;
+       u16 nav_id;
+       u16 index;
+       u32 addr_lo;
+       u32 addr_hi;
+       u32 count;
+       u8 mode;
+       u8 size;
+       u8 order_id;
+} __packed;
+
+/**
+ * struct ti_sci_msg_rm_ring_get_cfg_req - Get RA ring's configuration
+ *
+ * Gets the configuration of the non-real-time register fields of a ring.  The
+ * host, or a supervisor of the host, who owns the ring must be the requesting
+ * host.  The values of the non-real-time registers are returned in
+ * @ti_sci_msg_rm_ring_get_cfg_resp.
+ *
+ * @hdr: Generic Header
+ * @nav_id: Device ID of Navigator Subsystem from which the ring is allocated
+ * @index: ring index.
+ */
+struct ti_sci_msg_rm_ring_get_cfg_req {
+       struct ti_sci_msg_hdr hdr;
+       u16 nav_id;
+       u16 index;
+} __packed;
+
+/**
+ * struct ti_sci_msg_rm_ring_get_cfg_resp -  Ring get configuration response
+ *
+ * Response received by host processor after RM has handled
+ * @ti_sci_msg_rm_ring_get_cfg_req. The response contains the ring's
+ * non-real-time register values.
+ *
+ * @hdr: Generic Header
+ * @addr_lo: Ring 32 LSBs of base address
+ * @addr_hi: Ring 16 MSBs of base address.
+ * @count: Ring number of elements.
+ * @mode: Ring mode.
+ * @size: encoded Ring element size
+ * @order_id: ing order ID.
+ */
+struct ti_sci_msg_rm_ring_get_cfg_resp {
+       struct ti_sci_msg_hdr hdr;
+       u32 addr_lo;
+       u32 addr_hi;
+       u32 count;
+       u8 mode;
+       u8 size;
+       u8 order_id;
+} __packed;
+
+/**
+ * struct ti_sci_msg_psil_pair - Pairs a PSI-L source thread to a destination
+ *                              thread
+ * @hdr:       Generic Header
+ * @nav_id:    SoC Navigator Subsystem device ID whose PSI-L config proxy is
+ *             used to pair the source and destination threads.
+ * @src_thread:        PSI-L source thread ID within the PSI-L System thread map.
+ *
+ * UDMAP transmit channels mapped to source threads will have their
+ * TCHAN_THRD_ID register programmed with the destination thread if the pairing
+ * is successful.
+
+ * @dst_thread: PSI-L destination thread ID within the PSI-L System thread map.
+ * PSI-L destination threads start at index 0x8000.  The request is NACK'd if
+ * the destination thread is not greater than or equal to 0x8000.
+ *
+ * UDMAP receive channels mapped to destination threads will have their
+ * RCHAN_THRD_ID register programmed with the source thread if the pairing
+ * is successful.
+ *
+ * Request type is TI_SCI_MSG_RM_PSIL_PAIR, response is a generic ACK or NACK
+ * message.
+ */
+struct ti_sci_msg_psil_pair {
+       struct ti_sci_msg_hdr hdr;
+       u32 nav_id;
+       u32 src_thread;
+       u32 dst_thread;
+} __packed;
+
+/**
+ * struct ti_sci_msg_psil_unpair - Unpairs a PSI-L source thread from a
+ *                                destination thread
+ * @hdr:       Generic Header
+ * @nav_id:    SoC Navigator Subsystem device ID whose PSI-L config proxy is
+ *             used to unpair the source and destination threads.
+ * @src_thread:        PSI-L source thread ID within the PSI-L System thread map.
+ *
+ * UDMAP transmit channels mapped to source threads will have their
+ * TCHAN_THRD_ID register cleared if the unpairing is successful.
+ *
+ * @dst_thread: PSI-L destination thread ID within the PSI-L System thread map.
+ * PSI-L destination threads start at index 0x8000.  The request is NACK'd if
+ * the destination thread is not greater than or equal to 0x8000.
+ *
+ * UDMAP receive channels mapped to destination threads will have their
+ * RCHAN_THRD_ID register cleared if the unpairing is successful.
+ *
+ * Request type is TI_SCI_MSG_RM_PSIL_UNPAIR, response is a generic ACK or NACK
+ * message.
+ */
+struct ti_sci_msg_psil_unpair {
+       struct ti_sci_msg_hdr hdr;
+       u32 nav_id;
+       u32 src_thread;
+       u32 dst_thread;
+} __packed;
+
+/**
+ * struct ti_sci_msg_udmap_rx_flow_cfg -  UDMAP receive flow configuration
+ *                                       message
+ * @hdr: Generic Header
+ * @nav_id: SoC Navigator Subsystem device ID from which the receive flow is
+ *     allocated
+ * @flow_index: UDMAP receive flow index for non-optional configuration.
+ * @rx_ch_index: Specifies the index of the receive channel using the flow_index
+ * @rx_einfo_present: UDMAP receive flow extended packet info present.
+ * @rx_psinfo_present: UDMAP receive flow PS words present.
+ * @rx_error_handling: UDMAP receive flow error handling configuration. Valid
+ *     values are TI_SCI_RM_UDMAP_RX_FLOW_ERR_DROP/RETRY.
+ * @rx_desc_type: UDMAP receive flow descriptor type. It can be one of
+ *     TI_SCI_RM_UDMAP_RX_FLOW_DESC_HOST/MONO.
+ * @rx_sop_offset: UDMAP receive flow start of packet offset.
+ * @rx_dest_qnum: UDMAP receive flow destination queue number.
+ * @rx_ps_location: UDMAP receive flow PS words location.
+ *     0 - end of packet descriptor
+ *     1 - Beginning of the data buffer
+ * @rx_src_tag_hi: UDMAP receive flow source tag high byte constant
+ * @rx_src_tag_lo: UDMAP receive flow source tag low byte constant
+ * @rx_dest_tag_hi: UDMAP receive flow destination tag high byte constant
+ * @rx_dest_tag_lo: UDMAP receive flow destination tag low byte constant
+ * @rx_src_tag_hi_sel: UDMAP receive flow source tag high byte selector
+ * @rx_src_tag_lo_sel: UDMAP receive flow source tag low byte selector
+ * @rx_dest_tag_hi_sel: UDMAP receive flow destination tag high byte selector
+ * @rx_dest_tag_lo_sel: UDMAP receive flow destination tag low byte selector
+ * @rx_size_thresh_en: UDMAP receive flow packet size based free buffer queue
+ *     enable. If enabled, the ti_sci_rm_udmap_rx_flow_opt_cfg also need to be
+ *     configured and sent.
+ * @rx_fdq0_sz0_qnum: UDMAP receive flow free descriptor queue 0.
+ * @rx_fdq1_qnum: UDMAP receive flow free descriptor queue 1.
+ * @rx_fdq2_qnum: UDMAP receive flow free descriptor queue 2.
+ * @rx_fdq3_qnum: UDMAP receive flow free descriptor queue 3.
+ *
+ * For detailed information on the settings, see the UDMAP section of the TRM.
+ */
+struct ti_sci_msg_udmap_rx_flow_cfg {
+       struct ti_sci_msg_hdr hdr;
+       u32 nav_id;
+       u32 flow_index;
+       u32 rx_ch_index;
+       u8 rx_einfo_present;
+       u8 rx_psinfo_present;
+       u8 rx_error_handling;
+       u8 rx_desc_type;
+       u16 rx_sop_offset;
+       u16 rx_dest_qnum;
+       u8 rx_ps_location;
+       u8 rx_src_tag_hi;
+       u8 rx_src_tag_lo;
+       u8 rx_dest_tag_hi;
+       u8 rx_dest_tag_lo;
+       u8 rx_src_tag_hi_sel;
+       u8 rx_src_tag_lo_sel;
+       u8 rx_dest_tag_hi_sel;
+       u8 rx_dest_tag_lo_sel;
+       u8 rx_size_thresh_en;
+       u16 rx_fdq0_sz0_qnum;
+       u16 rx_fdq1_qnum;
+       u16 rx_fdq2_qnum;
+       u16 rx_fdq3_qnum;
+} __packed;
+
+/**
+ * struct rm_ti_sci_msg_udmap_rx_flow_opt_cfg - parameters for UDMAP receive
+ *                                             flow optional configuration
+ * @hdr: Generic Header
+ * @nav_id: SoC Navigator Subsystem device ID from which the receive flow is
+ *     allocated
+ * @flow_index: UDMAP receive flow index for optional configuration.
+ * @rx_ch_index: Specifies the index of the receive channel using the flow_index
+ * @rx_size_thresh0: UDMAP receive flow packet size threshold 0.
+ * @rx_size_thresh1: UDMAP receive flow packet size threshold 1.
+ * @rx_size_thresh2: UDMAP receive flow packet size threshold 2.
+ * @rx_fdq0_sz1_qnum: UDMAP receive flow free descriptor queue for size
+ *     threshold 1.
+ * @rx_fdq0_sz2_qnum: UDMAP receive flow free descriptor queue for size
+ *     threshold 2.
+ * @rx_fdq0_sz3_qnum: UDMAP receive flow free descriptor queue for size
+ *     threshold 3.
+ *
+ * For detailed information on the settings, see the UDMAP section of the TRM.
+ */
+struct rm_ti_sci_msg_udmap_rx_flow_opt_cfg {
+       struct ti_sci_msg_hdr hdr;
+       u32 nav_id;
+       u32 flow_index;
+       u32 rx_ch_index;
+       u16 rx_size_thresh0;
+       u16 rx_size_thresh1;
+       u16 rx_size_thresh2;
+       u16 rx_fdq0_sz1_qnum;
+       u16 rx_fdq0_sz2_qnum;
+       u16 rx_fdq0_sz3_qnum;
+} __packed;
+
+/**
+ * Configures a Navigator Subsystem UDMAP transmit channel
+ *
+ * Configures the non-real-time registers of a Navigator Subsystem UDMAP
+ * transmit channel.  The channel index must be assigned to the host defined
+ * in the TISCI header via the RM board configuration resource assignment
+ * range list.
+ *
+ * @hdr: Generic Header
+ *
+ * @valid_params: Bitfield defining validity of tx channel configuration
+ * parameters. The tx channel configuration fields are not valid, and will not
+ * be used for ch configuration, if their corresponding valid bit is zero.
+ * Valid bit usage:
+ *    0 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_pause_on_err
+ *    1 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_atype
+ *    2 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_chan_type
+ *    3 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_fetch_size
+ *    4 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::txcq_qnum
+ *    5 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_priority
+ *    6 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_qos
+ *    7 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_orderid
+ *    8 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_sched_priority
+ *    9 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_filt_einfo
+ *   10 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_filt_pswords
+ *   11 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_supr_tdpkt
+ *   12 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_credit_count
+ *   13 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::fdepth
+ *   14 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_burst_size
+ *
+ * @nav_id: SoC device ID of Navigator Subsystem where tx channel is located
+ *
+ * @index: UDMAP transmit channel index.
+ *
+ * @tx_pause_on_err: UDMAP transmit channel pause on error configuration to
+ * be programmed into the tx_pause_on_err field of the channel's TCHAN_TCFG
+ * register.
+ *
+ * @tx_filt_einfo: UDMAP transmit channel extended packet information passing
+ * configuration to be programmed into the tx_filt_einfo field of the
+ * channel's TCHAN_TCFG register.
+ *
+ * @tx_filt_pswords: UDMAP transmit channel protocol specific word passing
+ * configuration to be programmed into the tx_filt_pswords field of the
+ * channel's TCHAN_TCFG register.
+ *
+ * @tx_atype: UDMAP transmit channel non Ring Accelerator access pointer
+ * interpretation configuration to be programmed into the tx_atype field of
+ * the channel's TCHAN_TCFG register.
+ *
+ * @tx_chan_type: UDMAP transmit channel functional channel type and work
+ * passing mechanism configuration to be programmed into the tx_chan_type
+ * field of the channel's TCHAN_TCFG register.
+ *
+ * @tx_supr_tdpkt: UDMAP transmit channel teardown packet generation suppression
+ * configuration to be programmed into the tx_supr_tdpkt field of the channel's
+ * TCHAN_TCFG register.
+ *
+ * @tx_fetch_size: UDMAP transmit channel number of 32-bit descriptor words to
+ * fetch configuration to be programmed into the tx_fetch_size field of the
+ * channel's TCHAN_TCFG register.  The user must make sure to set the maximum
+ * word count that can pass through the channel for any allowed descriptor type.
+ *
+ * @tx_credit_count: UDMAP transmit channel transfer request credit count
+ * configuration to be programmed into the count field of the TCHAN_TCREDIT
+ * register.  Specifies how many credits for complete TRs are available.
+ *
+ * @txcq_qnum: UDMAP transmit channel completion queue configuration to be
+ * programmed into the txcq_qnum field of the TCHAN_TCQ register. The specified
+ * completion queue must be assigned to the host, or a subordinate of the host,
+ * requesting configuration of the transmit channel.
+ *
+ * @tx_priority: UDMAP transmit channel transmit priority value to be programmed
+ * into the priority field of the channel's TCHAN_TPRI_CTRL register.
+ *
+ * @tx_qos: UDMAP transmit channel transmit qos value to be programmed into the
+ * qos field of the channel's TCHAN_TPRI_CTRL register.
+ *
+ * @tx_orderid: UDMAP transmit channel bus order id value to be programmed into
+ * the orderid field of the channel's TCHAN_TPRI_CTRL register.
+ *
+ * @fdepth: UDMAP transmit channel FIFO depth configuration to be programmed
+ * into the fdepth field of the TCHAN_TFIFO_DEPTH register. Sets the number of
+ * Tx FIFO bytes which are allowed to be stored for the channel. Check the UDMAP
+ * section of the TRM for restrictions regarding this parameter.
+ *
+ * @tx_sched_priority: UDMAP transmit channel tx scheduling priority
+ * configuration to be programmed into the priority field of the channel's
+ * TCHAN_TST_SCHED register.
+ *
+ * @tx_burst_size: UDMAP transmit channel burst size configuration to be
+ * programmed into the tx_burst_size field of the TCHAN_TCFG register.
+ */
+struct ti_sci_msg_rm_udmap_tx_ch_cfg_req {
+       struct ti_sci_msg_hdr hdr;
+       u32 valid_params;
+       u16 nav_id;
+       u16 index;
+       u8 tx_pause_on_err;
+       u8 tx_filt_einfo;
+       u8 tx_filt_pswords;
+       u8 tx_atype;
+       u8 tx_chan_type;
+       u8 tx_supr_tdpkt;
+       u16 tx_fetch_size;
+       u8 tx_credit_count;
+       u16 txcq_qnum;
+       u8 tx_priority;
+       u8 tx_qos;
+       u8 tx_orderid;
+       u16 fdepth;
+       u8 tx_sched_priority;
+       u8 tx_burst_size;
+} __packed;
+
+/**
+ * Configures a Navigator Subsystem UDMAP receive channel
+ *
+ * Configures the non-real-time registers of a Navigator Subsystem UDMAP
+ * receive channel.  The channel index must be assigned to the host defined
+ * in the TISCI header via the RM board configuration resource assignment
+ * range list.
+ *
+ * @hdr: Generic Header
+ *
+ * @valid_params: Bitfield defining validity of rx channel configuration
+ * parameters.
+ * The rx channel configuration fields are not valid, and will not be used for
+ * ch configuration, if their corresponding valid bit is zero.
+ * Valid bit usage:
+ *    0 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rx_pause_on_err
+ *    1 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rx_atype
+ *    2 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rx_chan_type
+ *    3 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rx_fetch_size
+ *    4 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rxcq_qnum
+ *    5 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rx_priority
+ *    6 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rx_qos
+ *    7 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rx_orderid
+ *    8 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rx_sched_priority
+ *    9 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::flowid_start
+ *   10 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::flowid_cnt
+ *   11 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rx_ignore_short
+ *   12 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rx_ignore_long
+ *   14 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rx_burst_size
+ *
+ * @nav_id: SoC device ID of Navigator Subsystem where rx channel is located
+ *
+ * @index: UDMAP receive channel index.
+ *
+ * @rx_fetch_size: UDMAP receive channel number of 32-bit descriptor words to
+ * fetch configuration to be programmed into the rx_fetch_size field of the
+ * channel's RCHAN_RCFG register.
+ *
+ * @rxcq_qnum: UDMAP receive channel completion queue configuration to be
+ * programmed into the rxcq_qnum field of the RCHAN_RCQ register.
+ * The specified completion queue must be assigned to the host, or a subordinate
+ * of the host, requesting configuration of the receive channel.
+ *
+ * @rx_priority: UDMAP receive channel receive priority value to be programmed
+ * into the priority field of the channel's RCHAN_RPRI_CTRL register.
+ *
+ * @rx_qos: UDMAP receive channel receive qos value to be programmed into the
+ * qos field of the channel's RCHAN_RPRI_CTRL register.
+ *
+ * @rx_orderid: UDMAP receive channel bus order id value to be programmed into
+ * the orderid field of the channel's RCHAN_RPRI_CTRL register.
+ *
+ * @rx_sched_priority: UDMAP receive channel rx scheduling priority
+ * configuration to be programmed into the priority field of the channel's
+ * RCHAN_RST_SCHED register.
+ *
+ * @flowid_start: UDMAP receive channel additional flows starting index
+ * configuration to program into the flow_start field of the RCHAN_RFLOW_RNG
+ * register. Specifies the starting index for flow IDs the receive channel is to
+ * make use of beyond the default flow. flowid_start and @ref flowid_cnt must be
+ * set as valid and configured together. The starting flow ID set by
+ * @ref flowid_cnt must be a flow index within the Navigator Subsystem's subset
+ * of flows beyond the default flows statically mapped to receive channels.
+ * The additional flows must be assigned to the host, or a subordinate of the
+ * host, requesting configuration of the receive channel.
+ *
+ * @flowid_cnt: UDMAP receive channel additional flows count configuration to
+ * program into the flowid_cnt field of the RCHAN_RFLOW_RNG register.
+ * This field specifies how many flow IDs are in the additional contiguous range
+ * of legal flow IDs for the channel.  @ref flowid_start and flowid_cnt must be
+ * set as valid and configured together. Disabling the valid_params field bit
+ * for flowid_cnt indicates no flow IDs other than the default are to be
+ * allocated and used by the receive channel. @ref flowid_start plus flowid_cnt
+ * cannot be greater than the number of receive flows in the receive channel's
+ * Navigator Subsystem.  The additional flows must be assigned to the host, or a
+ * subordinate of the host, requesting configuration of the receive channel.
+ *
+ * @rx_pause_on_err: UDMAP receive channel pause on error configuration to be
+ * programmed into the rx_pause_on_err field of the channel's RCHAN_RCFG
+ * register.
+ *
+ * @rx_atype: UDMAP receive channel non Ring Accelerator access pointer
+ * interpretation configuration to be programmed into the rx_atype field of the
+ * channel's RCHAN_RCFG register.
+ *
+ * @rx_chan_type: UDMAP receive channel functional channel type and work passing
+ * mechanism configuration to be programmed into the rx_chan_type field of the
+ * channel's RCHAN_RCFG register.
+ *
+ * @rx_ignore_short: UDMAP receive channel short packet treatment configuration
+ * to be programmed into the rx_ignore_short field of the RCHAN_RCFG register.
+ *
+ * @rx_ignore_long: UDMAP receive channel long packet treatment configuration to
+ * be programmed into the rx_ignore_long field of the RCHAN_RCFG register.
+ *
+ * @rx_burst_size: UDMAP receive channel burst size configuration to be
+ * programmed into the rx_burst_size field of the RCHAN_RCFG register.
+ */
+struct ti_sci_msg_rm_udmap_rx_ch_cfg_req {
+       struct ti_sci_msg_hdr hdr;
+       u32 valid_params;
+       u16 nav_id;
+       u16 index;
+       u16 rx_fetch_size;
+       u16 rxcq_qnum;
+       u8 rx_priority;
+       u8 rx_qos;
+       u8 rx_orderid;
+       u8 rx_sched_priority;
+       u16 flowid_start;
+       u16 flowid_cnt;
+       u8 rx_pause_on_err;
+       u8 rx_atype;
+       u8 rx_chan_type;
+       u8 rx_ignore_short;
+       u8 rx_ignore_long;
+       u8 rx_burst_size;
+} __packed;
+
+/**
+ * Configures a Navigator Subsystem UDMAP receive flow
+ *
+ * Configures a Navigator Subsystem UDMAP receive flow's registers.
+ * Configuration does not include the flow registers which handle size-based
+ * free descriptor queue routing.
+ *
+ * The flow index must be assigned to the host defined in the TISCI header via
+ * the RM board configuration resource assignment range list.
+ *
+ * @hdr: Standard TISCI header
+ *
+ * @valid_params
+ * Bitfield defining validity of rx flow configuration parameters.  The
+ * rx flow configuration fields are not valid, and will not be used for flow
+ * configuration, if their corresponding valid bit is zero.  Valid bit usage:
+ *     0 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_einfo_present
+ *     1 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_psinfo_present
+ *     2 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_error_handling
+ *     3 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_desc_type
+ *     4 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_sop_offset
+ *     5 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_dest_qnum
+ *     6 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_src_tag_hi
+ *     7 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_src_tag_lo
+ *     8 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_dest_tag_hi
+ *     9 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_dest_tag_lo
+ *    10 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_src_tag_hi_sel
+ *    11 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_src_tag_lo_sel
+ *    12 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_dest_tag_hi_sel
+ *    13 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_dest_tag_lo_sel
+ *    14 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_fdq0_sz0_qnum
+ *    15 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_fdq1_sz0_qnum
+ *    16 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_fdq2_sz0_qnum
+ *    17 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_fdq3_sz0_qnum
+ *    18 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_ps_location
+ *
+ * @nav_id: SoC device ID of Navigator Subsystem from which the receive flow is
+ * allocated
+ *
+ * @flow_index: UDMAP receive flow index for non-optional configuration.
+ *
+ * @rx_einfo_present:
+ * UDMAP receive flow extended packet info present configuration to be
+ * programmed into the rx_einfo_present field of the flow's RFLOW_RFA register.
+ *
+ * @rx_psinfo_present:
+ * UDMAP receive flow PS words present configuration to be programmed into the
+ * rx_psinfo_present field of the flow's RFLOW_RFA register.
+ *
+ * @rx_error_handling:
+ * UDMAP receive flow error handling configuration to be programmed into the
+ * rx_error_handling field of the flow's RFLOW_RFA register.
+ *
+ * @rx_desc_type:
+ * UDMAP receive flow descriptor type configuration to be programmed into the
+ * rx_desc_type field field of the flow's RFLOW_RFA register.
+ *
+ * @rx_sop_offset:
+ * UDMAP receive flow start of packet offset configuration to be programmed
+ * into the rx_sop_offset field of the RFLOW_RFA register.  See the UDMAP
+ * section of the TRM for more information on this setting.  Valid values for
+ * this field are 0-255 bytes.
+ *
+ * @rx_dest_qnum:
+ * UDMAP receive flow destination queue configuration to be programmed into the
+ * rx_dest_qnum field of the flow's RFLOW_RFA register.  The specified
+ * destination queue must be valid within the Navigator Subsystem and must be
+ * owned by the host, or a subordinate of the host, requesting allocation and
+ * configuration of the receive flow.
+ *
+ * @rx_src_tag_hi:
+ * UDMAP receive flow source tag high byte constant configuration to be
+ * programmed into the rx_src_tag_hi field of the flow's RFLOW_RFB register.
+ * See the UDMAP section of the TRM for more information on this setting.
+ *
+ * @rx_src_tag_lo:
+ * UDMAP receive flow source tag low byte constant configuration to be
+ * programmed into the rx_src_tag_lo field of the flow's RFLOW_RFB register.
+ * See the UDMAP section of the TRM for more information on this setting.
+ *
+ * @rx_dest_tag_hi:
+ * UDMAP receive flow destination tag high byte constant configuration to be
+ * programmed into the rx_dest_tag_hi field of the flow's RFLOW_RFB register.
+ * See the UDMAP section of the TRM for more information on this setting.
+ *
+ * @rx_dest_tag_lo:
+ * UDMAP receive flow destination tag low byte constant configuration to be
+ * programmed into the rx_dest_tag_lo field of the flow's RFLOW_RFB register.
+ * See the UDMAP section of the TRM for more information on this setting.
+ *
+ * @rx_src_tag_hi_sel:
+ * UDMAP receive flow source tag high byte selector configuration to be
+ * programmed into the rx_src_tag_hi_sel field of the RFLOW_RFC register.  See
+ * the UDMAP section of the TRM for more information on this setting.
+ *
+ * @rx_src_tag_lo_sel:
+ * UDMAP receive flow source tag low byte selector configuration to be
+ * programmed into the rx_src_tag_lo_sel field of the RFLOW_RFC register.  See
+ * the UDMAP section of the TRM for more information on this setting.
+ *
+ * @rx_dest_tag_hi_sel:
+ * UDMAP receive flow destination tag high byte selector configuration to be
+ * programmed into the rx_dest_tag_hi_sel field of the RFLOW_RFC register.  See
+ * the UDMAP section of the TRM for more information on this setting.
+ *
+ * @rx_dest_tag_lo_sel:
+ * UDMAP receive flow destination tag low byte selector configuration to be
+ * programmed into the rx_dest_tag_lo_sel field of the RFLOW_RFC register.  See
+ * the UDMAP section of the TRM for more information on this setting.
+ *
+ * @rx_fdq0_sz0_qnum:
+ * UDMAP receive flow free descriptor queue 0 configuration to be programmed
+ * into the rx_fdq0_sz0_qnum field of the flow's RFLOW_RFD register.  See the
+ * UDMAP section of the TRM for more information on this setting. The specified
+ * free queue must be valid within the Navigator Subsystem and must be owned
+ * by the host, or a subordinate of the host, requesting allocation and
+ * configuration of the receive flow.
+ *
+ * @rx_fdq1_qnum:
+ * UDMAP receive flow free descriptor queue 1 configuration to be programmed
+ * into the rx_fdq1_qnum field of the flow's RFLOW_RFD register.  See the
+ * UDMAP section of the TRM for more information on this setting.  The specified
+ * free queue must be valid within the Navigator Subsystem and must be owned
+ * by the host, or a subordinate of the host, requesting allocation and
+ * configuration of the receive flow.
+ *
+ * @rx_fdq2_qnum:
+ * UDMAP receive flow free descriptor queue 2 configuration to be programmed
+ * into the rx_fdq2_qnum field of the flow's RFLOW_RFE register.  See the
+ * UDMAP section of the TRM for more information on this setting.  The specified
+ * free queue must be valid within the Navigator Subsystem and must be owned
+ * by the host, or a subordinate of the host, requesting allocation and
+ * configuration of the receive flow.
+ *
+ * @rx_fdq3_qnum:
+ * UDMAP receive flow free descriptor queue 3 configuration to be programmed
+ * into the rx_fdq3_qnum field of the flow's RFLOW_RFE register.  See the
+ * UDMAP section of the TRM for more information on this setting.  The specified
+ * free queue must be valid within the Navigator Subsystem and must be owned
+ * by the host, or a subordinate of the host, requesting allocation and
+ * configuration of the receive flow.
+ *
+ * @rx_ps_location:
+ * UDMAP receive flow PS words location configuration to be programmed into the
+ * rx_ps_location field of the flow's RFLOW_RFA register.
+ */
+struct ti_sci_msg_rm_udmap_flow_cfg_req {
+       struct ti_sci_msg_hdr hdr;
+       u32 valid_params;
+       u16 nav_id;
+       u16 flow_index;
+       u8 rx_einfo_present;
+       u8 rx_psinfo_present;
+       u8 rx_error_handling;
+       u8 rx_desc_type;
+       u16 rx_sop_offset;
+       u16 rx_dest_qnum;
+       u8 rx_src_tag_hi;
+       u8 rx_src_tag_lo;
+       u8 rx_dest_tag_hi;
+       u8 rx_dest_tag_lo;
+       u8 rx_src_tag_hi_sel;
+       u8 rx_src_tag_lo_sel;
+       u8 rx_dest_tag_hi_sel;
+       u8 rx_dest_tag_lo_sel;
+       u16 rx_fdq0_sz0_qnum;
+       u16 rx_fdq1_qnum;
+       u16 rx_fdq2_qnum;
+       u16 rx_fdq3_qnum;
+       u8 rx_ps_location;
+} __packed;
+
+/**
+ * struct ti_sci_msg_req_proc_request - Request a processor
+ * @hdr:               Generic Header
+ * @processor_id:      ID of processor being requested
+ *
+ * Request type is TI_SCI_MSG_PROC_REQUEST, response is a generic ACK/NACK
+ * message.
+ */
+struct ti_sci_msg_req_proc_request {
+       struct ti_sci_msg_hdr hdr;
+       u8 processor_id;
+} __packed;
+
+/**
+ * struct ti_sci_msg_req_proc_release - Release a processor
+ * @hdr:               Generic Header
+ * @processor_id:      ID of processor being released
+ *
+ * Request type is TI_SCI_MSG_PROC_RELEASE, response is a generic ACK/NACK
+ * message.
+ */
+struct ti_sci_msg_req_proc_release {
+       struct ti_sci_msg_hdr hdr;
+       u8 processor_id;
+} __packed;
+
+/**
+ * struct ti_sci_msg_req_proc_handover - Handover a processor to a host
+ * @hdr:               Generic Header
+ * @processor_id:      ID of processor being handed over
+ * @host_id:           Host ID the control needs to be transferred to
+ *
+ * Request type is TI_SCI_MSG_PROC_HANDOVER, response is a generic ACK/NACK
+ * message.
+ */
+struct ti_sci_msg_req_proc_handover {
+       struct ti_sci_msg_hdr hdr;
+       u8 processor_id;
+       u8 host_id;
+} __packed;
+
+/* Boot Vector masks */
+#define TI_SCI_ADDR_LOW_MASK                   GENMASK_ULL(31, 0)
+#define TI_SCI_ADDR_HIGH_MASK                  GENMASK_ULL(63, 32)
+#define TI_SCI_ADDR_HIGH_SHIFT                 32
+
+/**
+ * struct ti_sci_msg_req_set_config - Set Processor boot configuration
+ * @hdr:               Generic Header
+ * @processor_id:      ID of processor being configured
+ * @bootvector_low:    Lower 32 bit address (Little Endian) of boot vector
+ * @bootvector_high:   Higher 32 bit address (Little Endian) of boot vector
+ * @config_flags_set:  Optional Processor specific Config Flags to set.
+ *                     Setting a bit here implies the corresponding mode
+ *                     will be set
+ * @config_flags_clear:        Optional Processor specific Config Flags to clear.
+ *                     Setting a bit here implies the corresponding mode
+ *                     will be cleared
+ *
+ * Request type is TI_SCI_MSG_PROC_HANDOVER, response is a generic ACK/NACK
+ * message.
+ */
+struct ti_sci_msg_req_set_config {
+       struct ti_sci_msg_hdr hdr;
+       u8 processor_id;
+       u32 bootvector_low;
+       u32 bootvector_high;
+       u32 config_flags_set;
+       u32 config_flags_clear;
+} __packed;
+
+/**
+ * struct ti_sci_msg_req_set_ctrl - Set Processor boot control flags
+ * @hdr:               Generic Header
+ * @processor_id:      ID of processor being configured
+ * @control_flags_set: Optional Processor specific Control Flags to set.
+ *                     Setting a bit here implies the corresponding mode
+ *                     will be set
+ * @control_flags_clear:Optional Processor specific Control Flags to clear.
+ *                     Setting a bit here implies the corresponding mode
+ *                     will be cleared
+ *
+ * Request type is TI_SCI_MSG_SET_CTRL, response is a generic ACK/NACK
+ * message.
+ */
+struct ti_sci_msg_req_set_ctrl {
+       struct ti_sci_msg_hdr hdr;
+       u8 processor_id;
+       u32 control_flags_set;
+       u32 control_flags_clear;
+} __packed;
+
+/**
+ * struct ti_sci_msg_req_get_status - Processor boot status request
+ * @hdr:               Generic Header
+ * @processor_id:      ID of processor whose status is being requested
+ *
+ * Request type is TI_SCI_MSG_GET_STATUS, response is an appropriate
+ * message, or NACK in case of inability to satisfy request.
+ */
+struct ti_sci_msg_req_get_status {
+       struct ti_sci_msg_hdr hdr;
+       u8 processor_id;
+} __packed;
+
+/**
+ * struct ti_sci_msg_resp_get_status - Processor boot status response
+ * @hdr:               Generic Header
+ * @processor_id:      ID of processor whose status is returned
+ * @bootvector_low:    Lower 32 bit address (Little Endian) of boot vector
+ * @bootvector_high:   Higher 32 bit address (Little Endian) of boot vector
+ * @config_flags:      Optional Processor specific Config Flags set currently
+ * @control_flags:     Optional Processor specific Control Flags set currently
+ * @status_flags:      Optional Processor specific Status Flags set currently
+ *
+ * Response structure to a TI_SCI_MSG_GET_STATUS request.
+ */
+struct ti_sci_msg_resp_get_status {
+       struct ti_sci_msg_hdr hdr;
+       u8 processor_id;
+       u32 bootvector_low;
+       u32 bootvector_high;
+       u32 config_flags;
+       u32 control_flags;
+       u32 status_flags;
+} __packed;
+
 #endif /* __TI_SCI_H */
index dcd80b0..62f9244 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/sched/signal.h>
 #include <linux/uaccess.h>
+#include <linux/mm.h>
 
 #include "dfl-afu.h"
 
@@ -32,52 +33,6 @@ void afu_dma_region_init(struct dfl_feature_platform_data *pdata)
 }
 
 /**
- * afu_dma_adjust_locked_vm - adjust locked memory
- * @dev: port device
- * @npages: number of pages
- * @incr: increase or decrease locked memory
- *
- * Increase or decrease the locked memory size with npages input.
- *
- * Return 0 on success.
- * Return -ENOMEM if locked memory size is over the limit and no CAP_IPC_LOCK.
- */
-static int afu_dma_adjust_locked_vm(struct device *dev, long npages, bool incr)
-{
-       unsigned long locked, lock_limit;
-       int ret = 0;
-
-       /* the task is exiting. */
-       if (!current->mm)
-               return 0;
-
-       down_write(&current->mm->mmap_sem);
-
-       if (incr) {
-               locked = current->mm->locked_vm + npages;
-               lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
-
-               if (locked > lock_limit && !capable(CAP_IPC_LOCK))
-                       ret = -ENOMEM;
-               else
-                       current->mm->locked_vm += npages;
-       } else {
-               if (WARN_ON_ONCE(npages > current->mm->locked_vm))
-                       npages = current->mm->locked_vm;
-               current->mm->locked_vm -= npages;
-       }
-
-       dev_dbg(dev, "[%d] RLIMIT_MEMLOCK %c%ld %ld/%ld%s\n", current->pid,
-               incr ? '+' : '-', npages << PAGE_SHIFT,
-               current->mm->locked_vm << PAGE_SHIFT, rlimit(RLIMIT_MEMLOCK),
-               ret ? "- exceeded" : "");
-
-       up_write(&current->mm->mmap_sem);
-
-       return ret;
-}
-
-/**
  * afu_dma_pin_pages - pin pages of given dma memory region
  * @pdata: feature device platform data
  * @region: dma memory region to be pinned
@@ -92,7 +47,7 @@ static int afu_dma_pin_pages(struct dfl_feature_platform_data *pdata,
        struct device *dev = &pdata->dev->dev;
        int ret, pinned;
 
-       ret = afu_dma_adjust_locked_vm(dev, npages, true);
+       ret = account_locked_vm(current->mm, npages, true);
        if (ret)
                return ret;
 
@@ -121,7 +76,7 @@ put_pages:
 free_pages:
        kfree(region->pages);
 unlock_vm:
-       afu_dma_adjust_locked_vm(dev, npages, false);
+       account_locked_vm(current->mm, npages, false);
        return ret;
 }
 
@@ -141,7 +96,7 @@ static void afu_dma_unpin_pages(struct dfl_feature_platform_data *pdata,
 
        put_all_pages(region->pages, npages);
        kfree(region->pages);
-       afu_dma_adjust_locked_vm(dev, npages, false);
+       account_locked_vm(current->mm, npages, false);
 
        dev_dbg(dev, "%ld pages unpinned\n", npages);
 }
index 43d7d6a..bb13c26 100644 (file)
@@ -1312,7 +1312,7 @@ config GPIO_BT8XX
          The card needs to be physically altered for using it as a
          GPIO card. For more information on how to build a GPIO card
          from a BT8xx TV card, see the documentation file at
-         Documentation/bt8xxgpio.txt
+         Documentation/driver-api/bt8xxgpio.rst
 
          If unsure, say N.
 
index 3611a05..53b24e3 100644 (file)
@@ -41,7 +41,7 @@ MODULE_PARM_DESC(mask, "GPIO channel mask.");
 
 /*
  * FIXME: convert this singleton driver to use the state container
- * design pattern, see Documentation/driver-model/design-patterns.rst
+ * design pattern, see Documentation/driver-api/driver-model/design-patterns.rst
  */
 static struct cs5535_gpio_chip {
        struct gpio_chip chip;
index fc494a8..e0b0256 100644 (file)
@@ -238,8 +238,9 @@ static int davinci_gpio_probe(struct platform_device *pdev)
        for (i = 0; i < nirq; i++) {
                chips->irqs[i] = platform_get_irq(pdev, i);
                if (chips->irqs[i] < 0) {
-                       dev_info(dev, "IRQ not populated, err = %d\n",
-                                chips->irqs[i]);
+                       if (chips->irqs[i] != -EPROBE_DEFER)
+                               dev_info(dev, "IRQ not populated, err = %d\n",
+                                        chips->irqs[i]);
                        return chips->irqs[i];
                }
        }
index b6af705..a879512 100644 (file)
@@ -259,6 +259,13 @@ static const struct irq_domain_ops em_gio_irq_domain_ops = {
        .xlate  = irq_domain_xlate_twocell,
 };
 
+static void em_gio_irq_domain_remove(void *data)
+{
+       struct irq_domain *domain = data;
+
+       irq_domain_remove(domain);
+}
+
 static int em_gio_probe(struct platform_device *pdev)
 {
        struct em_gio_priv *p;
@@ -333,39 +340,30 @@ static int em_gio_probe(struct platform_device *pdev)
                return -ENXIO;
        }
 
+       ret = devm_add_action_or_reset(&pdev->dev, em_gio_irq_domain_remove,
+                                      p->irq_domain);
+       if (ret)
+               return ret;
+
        if (devm_request_irq(&pdev->dev, irq[0]->start,
                             em_gio_irq_handler, 0, name, p)) {
                dev_err(&pdev->dev, "failed to request low IRQ\n");
-               ret = -ENOENT;
-               goto err1;
+               return -ENOENT;
        }
 
        if (devm_request_irq(&pdev->dev, irq[1]->start,
                             em_gio_irq_handler, 0, name, p)) {
                dev_err(&pdev->dev, "failed to request high IRQ\n");
-               ret = -ENOENT;
-               goto err1;
+               return -ENOENT;
        }
 
        ret = devm_gpiochip_add_data(&pdev->dev, gpio_chip, p);
        if (ret) {
                dev_err(&pdev->dev, "failed to add GPIO controller\n");
-               goto err1;
+               return ret;
        }
 
        return 0;
-
-err1:
-       irq_domain_remove(p->irq_domain);
-       return ret;
-}
-
-static int em_gio_remove(struct platform_device *pdev)
-{
-       struct em_gio_priv *p = platform_get_drvdata(pdev);
-
-       irq_domain_remove(p->irq_domain);
-       return 0;
 }
 
 static const struct of_device_id em_gio_dt_ids[] = {
@@ -376,7 +374,6 @@ MODULE_DEVICE_TABLE(of, em_gio_dt_ids);
 
 static struct platform_driver em_gio_device_driver = {
        .probe          = em_gio_probe,
-       .remove         = em_gio_remove,
        .driver         = {
                .name   = "em_gio",
                .of_match_table = em_gio_dt_ids,
index f974075..567fb98 100644 (file)
@@ -118,15 +118,8 @@ static void of_gpio_flags_quirks(struct device_node *np,
         * Legacy handling of SPI active high chip select. If we have a
         * property named "cs-gpios" we need to inspect the child node
         * to determine if the flags should have inverted semantics.
-        *
-        * This does not apply to an SPI device named "spi-gpio", because
-        * these have traditionally obtained their own GPIOs by parsing
-        * the device tree directly and did not respect any "spi-cs-high"
-        * property on the SPI bus children.
         */
-       if (IS_ENABLED(CONFIG_SPI_MASTER) &&
-           !strcmp(propname, "cs-gpios") &&
-           !of_device_is_compatible(np, "spi-gpio") &&
+       if (IS_ENABLED(CONFIG_SPI_MASTER) && !strcmp(propname, "cs-gpios") &&
            of_property_read_bool(np, "cs-gpios")) {
                struct device_node *child;
                u32 cs;
@@ -161,6 +154,7 @@ static void of_gpio_flags_quirks(struct device_node *np,
                                                        of_node_full_name(child));
                                        *flags |= OF_GPIO_ACTIVE_LOW;
                                }
+                               of_node_put(child);
                                break;
                        }
                }
index 3313378..1d80222 100644 (file)
@@ -141,7 +141,7 @@ config DRM_LOAD_EDID_FIRMWARE
          monitor are unable to provide appropriate EDID data. Since this
          feature is provided as a workaround for broken hardware, the
          default case is N. Details and instructions how to build your own
-         EDID data are given in Documentation/EDID/howto.rst.
+         EDID data are given in Documentation/driver-api/edid.rst.
 
 config DRM_DP_CEC
        bool "Enable DisplayPort CEC-Tunneling-over-AUX HDMI support"
index f88d814..8199d20 100644 (file)
@@ -164,6 +164,7 @@ extern int amdgpu_async_gfx_ring;
 extern int amdgpu_mcbp;
 extern int amdgpu_discovery;
 extern int amdgpu_mes;
+extern int amdgpu_noretry;
 
 #ifdef CONFIG_DRM_AMDGPU_SI
 extern int amdgpu_si_support;
index 20ce158..6d54dec 100644 (file)
@@ -106,10 +106,10 @@ static int  amdgpu_debugfs_process_reg_op(bool read, struct file *f,
        ssize_t result = 0;
        int r;
        bool pm_pg_lock, use_bank, use_ring;
-       unsigned instance_bank, sh_bank, se_bank, me, pipe, queue;
+       unsigned instance_bank, sh_bank, se_bank, me, pipe, queue, vmid;
 
        pm_pg_lock = use_bank = use_ring = false;
-       instance_bank = sh_bank = se_bank = me = pipe = queue = 0;
+       instance_bank = sh_bank = se_bank = me = pipe = queue = vmid = 0;
 
        if (size & 0x3 || *pos & 0x3 ||
                        ((*pos & (1ULL << 62)) && (*pos & (1ULL << 61))))
@@ -135,6 +135,7 @@ static int  amdgpu_debugfs_process_reg_op(bool read, struct file *f,
                me = (*pos & GENMASK_ULL(33, 24)) >> 24;
                pipe = (*pos & GENMASK_ULL(43, 34)) >> 34;
                queue = (*pos & GENMASK_ULL(53, 44)) >> 44;
+               vmid = (*pos & GENMASK_ULL(58, 54)) >> 54;
 
                use_ring = 1;
        } else {
@@ -152,7 +153,7 @@ static int  amdgpu_debugfs_process_reg_op(bool read, struct file *f,
                                        sh_bank, instance_bank);
        } else if (use_ring) {
                mutex_lock(&adev->srbm_mutex);
-               amdgpu_gfx_select_me_pipe_q(adev, me, pipe, queue);
+               amdgpu_gfx_select_me_pipe_q(adev, me, pipe, queue, vmid);
        }
 
        if (pm_pg_lock)
@@ -185,7 +186,7 @@ end:
                amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
                mutex_unlock(&adev->grbm_idx_mutex);
        } else if (use_ring) {
-               amdgpu_gfx_select_me_pipe_q(adev, 0, 0, 0);
+               amdgpu_gfx_select_me_pipe_q(adev, 0, 0, 0, 0);
                mutex_unlock(&adev->srbm_mutex);
        }
 
index 7401bc9..5a7f893 100644 (file)
@@ -2537,6 +2537,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
        hash_init(adev->mn_hash);
        mutex_init(&adev->lock_reset);
        mutex_init(&adev->virt.dpm_mutex);
+       mutex_init(&adev->psp.mutex);
 
        r = amdgpu_device_check_arguments(adev);
        if (r)
index e049ae6..1481899 100644 (file)
@@ -123,7 +123,7 @@ static int hw_id_map[MAX_HWIP] = {
        [UVD_HWIP]      = UVD_HWID,
        [VCE_HWIP]      = VCE_HWID,
        [DF_HWIP]       = DF_HWID,
-       [DCE_HWIP]      = DCEAZ_HWID,
+       [DCE_HWIP]      = DMU_HWID,
        [OSSSYS_HWIP]   = OSSSYS_HWID,
        [SMUIO_HWIP]    = SMUIO_HWID,
        [PWR_HWIP]      = PWR_HWID,
index 1b0613c..f2e8b42 100644 (file)
@@ -140,8 +140,9 @@ uint amdgpu_smu_memory_pool_size = 0;
 uint amdgpu_dc_feature_mask = 0;
 int amdgpu_async_gfx_ring = 1;
 int amdgpu_mcbp = 0;
-int amdgpu_discovery = 0;
+int amdgpu_discovery = -1;
 int amdgpu_mes = 0;
+int amdgpu_noretry;
 
 struct amdgpu_mgpu_info mgpu_info = {
        .mutex = __MUTEX_INITIALIZER(mgpu_info.mutex),
@@ -593,6 +594,7 @@ module_param_named(mcbp, amdgpu_mcbp, int, 0444);
 /**
  * DOC: discovery (int)
  * Allow driver to discover hardware IP information from IP Discovery table at the top of VRAM.
+ * (-1 = auto (default), 0 = disabled, 1 = enabled)
  */
 MODULE_PARM_DESC(discovery,
        "Allow driver to discover hardware IPs from IP Discovery table at the top of VRAM");
@@ -607,6 +609,10 @@ MODULE_PARM_DESC(mes,
        "Enable Micro Engine Scheduler (0 = disabled (default), 1 = enabled)");
 module_param_named(mes, amdgpu_mes, int, 0444);
 
+MODULE_PARM_DESC(noretry,
+       "Disable retry faults (0 = retry enabled (default), 1 = retry disabled)");
+module_param_named(noretry, amdgpu_noretry, int, 0644);
+
 #ifdef CONFIG_HSA_AMD
 /**
  * DOC: sched_policy (int)
@@ -683,17 +689,6 @@ MODULE_PARM_DESC(ignore_crat,
        "Ignore CRAT table during KFD initialization (0 = use CRAT (default), 1 = ignore CRAT)");
 
 /**
- * DOC: noretry (int)
- * This parameter sets sh_mem_config.retry_disable. Default value, 0, enables retry.
- * Setting 1 disables retry.
- * Retry is needed for recoverable page faults.
- */
-int noretry;
-module_param(noretry, int, 0644);
-MODULE_PARM_DESC(noretry,
-       "Set sh_mem_config.retry_disable on Vega10 (0 = retry enabled (default), 1 = retry disabled)");
-
-/**
  * DOC: halt_if_hws_hang (int)
  * Halt if HWS hang is detected. Default value, 0, disables the halt on hang.
  * Setting 1 enables halt on hang.
index f96407b..1199b58 100644 (file)
@@ -195,7 +195,7 @@ struct amdgpu_gfx_funcs {
                                uint32_t wave, uint32_t start, uint32_t size,
                                uint32_t *dst);
        void (*select_me_pipe_q)(struct amdgpu_device *adev, u32 me, u32 pipe,
-                                u32 queue);
+                                u32 queue, u32 vmid);
 };
 
 struct amdgpu_ngg_buf {
@@ -327,7 +327,7 @@ struct amdgpu_gfx {
 
 #define amdgpu_gfx_get_gpu_clock_counter(adev) (adev)->gfx.funcs->get_gpu_clock_counter((adev))
 #define amdgpu_gfx_select_se_sh(adev, se, sh, instance) (adev)->gfx.funcs->select_se_sh((adev), (se), (sh), (instance))
-#define amdgpu_gfx_select_me_pipe_q(adev, me, pipe, q) (adev)->gfx.funcs->select_me_pipe_q((adev), (me), (pipe), (q))
+#define amdgpu_gfx_select_me_pipe_q(adev, me, pipe, q, vmid) (adev)->gfx.funcs->select_me_pipe_q((adev), (me), (pipe), (q), (vmid))
 
 /**
  * amdgpu_gfx_create_bitmask - create a bitmask
index 193d537..8b7efd0 100644 (file)
@@ -2077,11 +2077,6 @@ static ssize_t amdgpu_hwmon_show_sclk(struct device *dev,
             (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
                return -EINVAL;
 
-       /* sanity check PP is enabled */
-       if (!(adev->powerplay.pp_funcs &&
-             adev->powerplay.pp_funcs->read_sensor))
-             return -EINVAL;
-
        /* get the sclk */
        r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GFX_SCLK,
                                   (void *)&sclk, &size);
@@ -2112,11 +2107,6 @@ static ssize_t amdgpu_hwmon_show_mclk(struct device *dev,
             (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
                return -EINVAL;
 
-       /* sanity check PP is enabled */
-       if (!(adev->powerplay.pp_funcs &&
-             adev->powerplay.pp_funcs->read_sensor))
-             return -EINVAL;
-
        /* get the sclk */
        r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GFX_MCLK,
                                   (void *)&mclk, &size);
@@ -2996,13 +2986,10 @@ void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)
        }
 
        if (is_support_sw_smu(adev)) {
-               struct smu_context *smu = &adev->smu;
                struct smu_dpm_context *smu_dpm = &adev->smu.smu_dpm;
-               mutex_lock(&(smu->mutex));
                smu_handle_task(&adev->smu,
                                smu_dpm->dpm_level,
                                AMD_PP_TASK_DISPLAY_CONFIG_CHANGE);
-               mutex_unlock(&(smu->mutex));
        } else {
                if (adev->powerplay.pp_funcs->dispatch_tasks) {
                        if (!amdgpu_device_has_dc_support(adev)) {
index e69ad6e..c027e5e 100644 (file)
@@ -130,6 +130,8 @@ psp_cmd_submit_buf(struct psp_context *psp,
        int index;
        int timeout = 2000;
 
+       mutex_lock(&psp->mutex);
+
        memset(psp->cmd_buf_mem, 0, PSP_CMD_BUFFER_SIZE);
 
        memcpy(psp->cmd_buf_mem, cmd, sizeof(struct psp_gfx_cmd_resp));
@@ -139,6 +141,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
                             fence_mc_addr, index);
        if (ret) {
                atomic_dec(&psp->fence_value);
+               mutex_unlock(&psp->mutex);
                return ret;
        }
 
@@ -161,8 +164,10 @@ psp_cmd_submit_buf(struct psp_context *psp,
                                  ucode->ucode_id);
                DRM_WARN("psp command failed and response status is (%d)\n",
                          psp->cmd_buf_mem->resp.status);
-               if (!timeout)
+               if (!timeout) {
+                       mutex_unlock(&psp->mutex);
                        return -EINVAL;
+               }
        }
 
        /* get xGMI session id from response buffer */
@@ -172,6 +177,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
                ucode->tmr_mc_addr_lo = psp->cmd_buf_mem->resp.fw_addr_lo;
                ucode->tmr_mc_addr_hi = psp->cmd_buf_mem->resp.fw_addr_hi;
        }
+       mutex_unlock(&psp->mutex);
 
        return ret;
 }
@@ -763,6 +769,15 @@ static int psp_hw_start(struct psp_context *psp)
        int ret;
 
        if (!amdgpu_sriov_vf(adev) || !adev->in_gpu_reset) {
+               if (psp->kdb_bin_size &&
+                   (psp->funcs->bootloader_load_kdb != NULL)) {
+                       ret = psp_bootloader_load_kdb(psp);
+                       if (ret) {
+                               DRM_ERROR("PSP load kdb failed!\n");
+                               return ret;
+                       }
+               }
+
                ret = psp_bootloader_load_sysdrv(psp);
                if (ret) {
                        DRM_ERROR("PSP load sysdrv failed!\n");
@@ -1188,10 +1203,16 @@ failed:
 
 int psp_gpu_reset(struct amdgpu_device *adev)
 {
+       int ret;
+
        if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
                return 0;
 
-       return psp_mode1_reset(&adev->psp);
+       mutex_lock(&adev->psp.mutex);
+       ret = psp_mode1_reset(&adev->psp);
+       mutex_unlock(&adev->psp.mutex);
+
+       return ret;
 }
 
 int psp_rlc_autoload_start(struct psp_context *psp)
index 6039acc..e0fc2a7 100644 (file)
@@ -42,6 +42,12 @@ struct psp_context;
 struct psp_xgmi_node_info;
 struct psp_xgmi_topology_info;
 
+enum psp_bootloader_cmd {
+       PSP_BL__LOAD_SYSDRV             = 0x10000,
+       PSP_BL__LOAD_SOSDRV             = 0x20000,
+       PSP_BL__LOAD_KEY_DATABASE       = 0x80000,
+};
+
 enum psp_ring_type
 {
        PSP_RING_TYPE__INVALID = 0,
@@ -73,6 +79,7 @@ enum psp_reg_prog_id {
 struct psp_funcs
 {
        int (*init_microcode)(struct psp_context *psp);
+       int (*bootloader_load_kdb)(struct psp_context *psp);
        int (*bootloader_load_sysdrv)(struct psp_context *psp);
        int (*bootloader_load_sos)(struct psp_context *psp);
        int (*ring_init)(struct psp_context *psp, enum psp_ring_type ring_type);
@@ -156,9 +163,11 @@ struct psp_context
        uint32_t                        sys_bin_size;
        uint32_t                        sos_bin_size;
        uint32_t                        toc_bin_size;
+       uint32_t                        kdb_bin_size;
        uint8_t                         *sys_start_addr;
        uint8_t                         *sos_start_addr;
        uint8_t                         *toc_start_addr;
+       uint8_t                         *kdb_start_addr;
 
        /* tmr buffer */
        struct amdgpu_bo                *tmr_bo;
@@ -201,6 +210,7 @@ struct psp_context
        uint8_t                         *ta_ras_start_addr;
        struct psp_xgmi_context         xgmi_context;
        struct psp_ras_context          ras;
+       struct mutex                    mutex;
 };
 
 struct amdgpu_psp_funcs {
@@ -219,6 +229,8 @@ struct amdgpu_psp_funcs {
                (psp)->funcs->compare_sram_data((psp), (ucode), (type))
 #define psp_init_microcode(psp) \
                ((psp)->funcs->init_microcode ? (psp)->funcs->init_microcode((psp)) : 0)
+#define psp_bootloader_load_kdb(psp) \
+               ((psp)->funcs->bootloader_load_kdb ? (psp)->funcs->bootloader_load_kdb((psp)) : 0)
 #define psp_bootloader_load_sysdrv(psp) \
                ((psp)->funcs->bootloader_load_sysdrv ? (psp)->funcs->bootloader_load_sysdrv((psp)) : 0)
 #define psp_bootloader_load_sos(psp) \
index 5c05644..e51b48a 100644 (file)
@@ -391,6 +391,7 @@ int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev,
                        src_node_start = amdgpu_mm_node_addr(src->bo, ++src_mm,
                                                             src->mem);
                        src_node_size = (src_mm->size << PAGE_SHIFT);
+                       src_page_offset = 0;
                } else {
                        src_node_start += cur_size;
                        src_page_offset = src_node_start & (PAGE_SIZE - 1);
@@ -400,6 +401,7 @@ int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev,
                        dst_node_start = amdgpu_mm_node_addr(dst->bo, ++dst_mm,
                                                             dst->mem);
                        dst_node_size = (dst_mm->size << PAGE_SHIFT);
+                       dst_page_offset = 0;
                } else {
                        dst_node_start += cur_size;
                        dst_page_offset = dst_node_start & (PAGE_SIZE - 1);
@@ -487,6 +489,7 @@ static int amdgpu_move_vram_ram(struct ttm_buffer_object *bo, bool evict,
        placements.flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT;
        r = ttm_bo_mem_space(bo, &placement, &tmp_mem, ctx);
        if (unlikely(r)) {
+               pr_err("Failed to find GTT space for blit from VRAM\n");
                return r;
        }
 
@@ -545,6 +548,7 @@ static int amdgpu_move_ram_vram(struct ttm_buffer_object *bo, bool evict,
        placements.flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT;
        r = ttm_bo_mem_space(bo, &placement, &tmp_mem, ctx);
        if (unlikely(r)) {
+               pr_err("Failed to find GTT space for blit to VRAM\n");
                return r;
        }
 
@@ -565,6 +569,30 @@ out_cleanup:
 }
 
 /**
+ * amdgpu_mem_visible - Check that memory can be accessed by ttm_bo_move_memcpy
+ *
+ * Called by amdgpu_bo_move()
+ */
+static bool amdgpu_mem_visible(struct amdgpu_device *adev,
+                              struct ttm_mem_reg *mem)
+{
+       struct drm_mm_node *nodes = mem->mm_node;
+
+       if (mem->mem_type == TTM_PL_SYSTEM ||
+           mem->mem_type == TTM_PL_TT)
+               return true;
+       if (mem->mem_type != TTM_PL_VRAM)
+               return false;
+
+       /* ttm_mem_reg_ioremap only supports contiguous memory */
+       if (nodes->size != mem->num_pages)
+               return false;
+
+       return ((nodes->start + nodes->size) << PAGE_SHIFT)
+               <= adev->gmc.visible_vram_size;
+}
+
+/**
  * amdgpu_bo_move - Move a buffer object to a new memory location
  *
  * Called by ttm_bo_handle_move_mem()
@@ -608,8 +636,10 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,
                return 0;
        }
 
-       if (!adev->mman.buffer_funcs_enabled)
+       if (!adev->mman.buffer_funcs_enabled) {
+               r = -ENODEV;
                goto memcpy;
+       }
 
        if (old_mem->mem_type == TTM_PL_VRAM &&
            new_mem->mem_type == TTM_PL_SYSTEM) {
@@ -624,10 +654,16 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,
 
        if (r) {
 memcpy:
-               r = ttm_bo_move_memcpy(bo, ctx, new_mem);
-               if (r) {
+               /* Check that all memory is CPU accessible */
+               if (!amdgpu_mem_visible(adev, old_mem) ||
+                   !amdgpu_mem_visible(adev, new_mem)) {
+                       pr_err("Move buffer fallback to memcpy unavailable\n");
                        return r;
                }
+
+               r = ttm_bo_move_memcpy(bo, ctx, new_mem);
+               if (r)
+                       return r;
        }
 
        if (bo->type == ttm_bo_type_device &&
@@ -2059,9 +2095,9 @@ int amdgpu_fill_buffer(struct amdgpu_bo *bo,
        mm_node = bo->tbo.mem.mm_node;
        num_loops = 0;
        while (num_pages) {
-               uint32_t byte_count = mm_node->size << PAGE_SHIFT;
+               uint64_t byte_count = mm_node->size << PAGE_SHIFT;
 
-               num_loops += DIV_ROUND_UP(byte_count, max_bytes);
+               num_loops += DIV_ROUND_UP_ULL(byte_count, max_bytes);
                num_pages -= mm_node->size;
                ++mm_node;
        }
@@ -2087,12 +2123,13 @@ int amdgpu_fill_buffer(struct amdgpu_bo *bo,
        mm_node = bo->tbo.mem.mm_node;
 
        while (num_pages) {
-               uint32_t byte_count = mm_node->size << PAGE_SHIFT;
+               uint64_t byte_count = mm_node->size << PAGE_SHIFT;
                uint64_t dst_addr;
 
                dst_addr = amdgpu_mm_node_addr(&bo->tbo, mm_node, &bo->tbo.mem);
                while (byte_count) {
-                       uint32_t cur_size_in_bytes = min(byte_count, max_bytes);
+                       uint32_t cur_size_in_bytes = min_t(uint64_t, byte_count,
+                                                          max_bytes);
 
                        amdgpu_emit_fill_buffer(adev, &job->ibs[0], src_data,
                                                dst_addr, cur_size_in_bytes);
index c352a51..bfaa0ea 100644 (file)
@@ -262,6 +262,12 @@ void amdgpu_ucode_print_psp_hdr(const struct common_firmware_header *hdr)
                                  le32_to_cpu(psp_hdr_v1_1->toc_offset_bytes));
                        DRM_DEBUG("toc_size_bytes: %u\n",
                                  le32_to_cpu(psp_hdr_v1_1->toc_size_bytes));
+                       DRM_DEBUG("kdb_header_version: %u\n",
+                                 le32_to_cpu(psp_hdr_v1_1->kdb_header_version));
+                       DRM_DEBUG("kdb_offset_bytes: %u\n",
+                                 le32_to_cpu(psp_hdr_v1_1->kdb_offset_bytes));
+                       DRM_DEBUG("kdb_size_bytes: %u\n",
+                                 le32_to_cpu(psp_hdr_v1_1->kdb_size_bytes));
                }
        } else {
                DRM_ERROR("Unknown PSP ucode version: %u.%u\n",
index f469444..c1fb6dc 100644 (file)
@@ -85,6 +85,9 @@ struct psp_firmware_header_v1_1 {
        uint32_t toc_header_version;
        uint32_t toc_offset_bytes;
        uint32_t toc_size_bytes;
+       uint32_t kdb_header_version;
+       uint32_t kdb_offset_bytes;
+       uint32_t kdb_size_bytes;
 };
 
 /* version_major=1, version_minor=0 */
index 07a7e38..59dd204 100644 (file)
@@ -390,7 +390,8 @@ static uint32_t parse_clk(char *buf, bool min)
                 if (!ptr)
                         break;
                 ptr+=2;
-                clk = simple_strtoul(ptr, NULL, 10);
+               if (kstrtou32(ptr, 10, &clk))
+                       return 0;
         } while (!min);
 
         return clk * 100;
index ee41d55..1675d58 100644 (file)
@@ -109,6 +109,13 @@ static const struct soc15_reg_golden golden_settings_gc_10_0_nv10[] =
        /* Pending on emulation bring up */
 };
 
+#define DEFAULT_SH_MEM_CONFIG \
+       ((SH_MEM_ADDRESS_MODE_64 << SH_MEM_CONFIG__ADDRESS_MODE__SHIFT) | \
+        (SH_MEM_ALIGNMENT_MODE_UNALIGNED << SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT) | \
+        (SH_MEM_RETRY_MODE_ALL << SH_MEM_CONFIG__RETRY_MODE__SHIFT) | \
+        (3 << SH_MEM_CONFIG__INITIAL_INST_PREFETCH__SHIFT))
+
+
 static void gfx_v10_0_set_ring_funcs(struct amdgpu_device *adev);
 static void gfx_v10_0_set_irq_funcs(struct amdgpu_device *adev);
 static void gfx_v10_0_set_gds_init(struct amdgpu_device *adev);
@@ -995,6 +1002,12 @@ static void gfx_v10_0_read_wave_vgprs(struct amdgpu_device *adev, uint32_t simd,
                start + SQIND_WAVE_VGPRS_OFFSET, size, dst);
 }
 
+static void gfx_v10_0_select_me_pipe_q(struct amdgpu_device *adev,
+                                                                         u32 me, u32 pipe, u32 q, u32 vm)
+ {
+       nv_grbm_select(adev, me, pipe, q, vm);
+ }
+
 
 static const struct amdgpu_gfx_funcs gfx_v10_0_gfx_funcs = {
        .get_gpu_clock_counter = &gfx_v10_0_get_gpu_clock_counter,
@@ -1002,6 +1015,7 @@ static const struct amdgpu_gfx_funcs gfx_v10_0_gfx_funcs = {
        .read_wave_data = &gfx_v10_0_read_wave_data,
        .read_wave_sgprs = &gfx_v10_0_read_wave_sgprs,
        .read_wave_vgprs = &gfx_v10_0_read_wave_vgprs,
+       .select_me_pipe_q = &gfx_v10_0_select_me_pipe_q,
 };
 
 static void gfx_v10_0_gpu_early_init(struct amdgpu_device *adev)
@@ -1408,7 +1422,6 @@ static u32 gfx_v10_0_init_pa_sc_tile_steering_override(struct amdgpu_device *ade
 static void gfx_v10_0_init_compute_vmid(struct amdgpu_device *adev)
 {
        int i;
-       uint32_t sh_mem_config;
        uint32_t sh_mem_bases;
 
        /*
@@ -1419,15 +1432,11 @@ static void gfx_v10_0_init_compute_vmid(struct amdgpu_device *adev)
         */
        sh_mem_bases = DEFAULT_SH_MEM_BASES | (DEFAULT_SH_MEM_BASES << 16);
 
-       sh_mem_config = SH_MEM_ADDRESS_MODE_64 |
-                       SH_MEM_ALIGNMENT_MODE_UNALIGNED <<
-                       SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT;
-
        mutex_lock(&adev->srbm_mutex);
        for (i = FIRST_COMPUTE_VMID; i < LAST_COMPUTE_VMID; i++) {
                nv_grbm_select(adev, 0, 0, 0, i);
                /* CP and shaders */
-               WREG32_SOC15(GC, 0, mmSH_MEM_CONFIG, sh_mem_config);
+               WREG32_SOC15(GC, 0, mmSH_MEM_CONFIG, DEFAULT_SH_MEM_CONFIG);
                WREG32_SOC15(GC, 0, mmSH_MEM_BASES, sh_mem_bases);
        }
        nv_grbm_select(adev, 0, 0, 0, 0);
@@ -1520,17 +1529,8 @@ static void gfx_v10_0_constants_init(struct amdgpu_device *adev)
        for (i = 0; i < adev->vm_manager.id_mgr[AMDGPU_GFXHUB].num_ids; i++) {
                nv_grbm_select(adev, 0, 0, 0, i);
                /* CP and shaders */
-               if (i == 0) {
-                       tmp = REG_SET_FIELD(0, SH_MEM_CONFIG, ALIGNMENT_MODE,
-                                           SH_MEM_ALIGNMENT_MODE_UNALIGNED);
-                       tmp = REG_SET_FIELD(tmp, SH_MEM_CONFIG, RETRY_MODE, 0);
-                       WREG32_SOC15(GC, 0, mmSH_MEM_CONFIG, tmp);
-                       WREG32_SOC15(GC, 0, mmSH_MEM_BASES, 0);
-               } else {
-                       tmp = REG_SET_FIELD(0, SH_MEM_CONFIG, ALIGNMENT_MODE,
-                                           SH_MEM_ALIGNMENT_MODE_UNALIGNED);
-                       tmp = REG_SET_FIELD(tmp, SH_MEM_CONFIG, RETRY_MODE, 0);
-                       WREG32_SOC15(GC, 0, mmSH_MEM_CONFIG, tmp);
+               WREG32_SOC15(GC, 0, mmSH_MEM_CONFIG, DEFAULT_SH_MEM_CONFIG);
+               if (i != 0) {
                        tmp = REG_SET_FIELD(0, SH_MEM_BASES, PRIVATE_BASE,
                                (adev->gmc.private_aperture_start >> 48));
                        tmp = REG_SET_FIELD(tmp, SH_MEM_BASES, SHARED_BASE,
index 789e900..7f0a636 100644 (file)
@@ -3043,7 +3043,7 @@ static void gfx_v6_0_read_wave_sgprs(struct amdgpu_device *adev, uint32_t simd,
 }
 
 static void gfx_v6_0_select_me_pipe_q(struct amdgpu_device *adev,
-                                 u32 me, u32 pipe, u32 q)
+                                 u32 me, u32 pipe, u32 q, u32 vm)
 {
        DRM_INFO("Not implemented\n");
 }
index 341b502..0db9f48 100644 (file)
@@ -4169,9 +4169,9 @@ static void gfx_v7_0_read_wave_sgprs(struct amdgpu_device *adev, uint32_t simd,
 }
 
 static void gfx_v7_0_select_me_pipe_q(struct amdgpu_device *adev,
-                                 u32 me, u32 pipe, u32 q)
+                                 u32 me, u32 pipe, u32 q, u32 vm)
 {
-       cik_srbm_select(adev, me, pipe, q, 0);
+       cik_srbm_select(adev, me, pipe, q, vm);
 }
 
 static const struct amdgpu_gfx_funcs gfx_v7_0_gfx_funcs = {
index 032e76d..5f401b4 100644 (file)
@@ -3436,9 +3436,9 @@ static void gfx_v8_0_select_se_sh(struct amdgpu_device *adev,
 }
 
 static void gfx_v8_0_select_me_pipe_q(struct amdgpu_device *adev,
-                                 u32 me, u32 pipe, u32 q)
+                                 u32 me, u32 pipe, u32 q, u32 vm)
 {
-       vi_srbm_select(adev, me, pipe, q, 0);
+       vi_srbm_select(adev, me, pipe, q, vm);
 }
 
 static u32 gfx_v8_0_get_rb_active_bitmap(struct amdgpu_device *adev)
index 5ba3323..f4c4eea 100644 (file)
@@ -1313,9 +1313,9 @@ static void gfx_v9_0_read_wave_vgprs(struct amdgpu_device *adev, uint32_t simd,
 }
 
 static void gfx_v9_0_select_me_pipe_q(struct amdgpu_device *adev,
-                                 u32 me, u32 pipe, u32 q)
+                                 u32 me, u32 pipe, u32 q, u32 vm)
 {
-       soc15_grbm_select(adev, me, pipe, q, 0);
+       soc15_grbm_select(adev, me, pipe, q, vm);
 }
 
 static const struct amdgpu_gfx_funcs gfx_v9_0_gfx_funcs = {
@@ -1942,11 +1942,15 @@ static void gfx_v9_0_constants_init(struct amdgpu_device *adev)
                if (i == 0) {
                        tmp = REG_SET_FIELD(0, SH_MEM_CONFIG, ALIGNMENT_MODE,
                                            SH_MEM_ALIGNMENT_MODE_UNALIGNED);
+                       tmp = REG_SET_FIELD(tmp, SH_MEM_CONFIG, RETRY_DISABLE,
+                                           !!amdgpu_noretry);
                        WREG32_SOC15_RLC(GC, 0, mmSH_MEM_CONFIG, tmp);
                        WREG32_SOC15_RLC(GC, 0, mmSH_MEM_BASES, 0);
                } else {
                        tmp = REG_SET_FIELD(0, SH_MEM_CONFIG, ALIGNMENT_MODE,
                                            SH_MEM_ALIGNMENT_MODE_UNALIGNED);
+                       tmp = REG_SET_FIELD(tmp, SH_MEM_CONFIG, RETRY_DISABLE,
+                                           !!amdgpu_noretry);
                        WREG32_SOC15_RLC(GC, 0, mmSH_MEM_CONFIG, tmp);
                        tmp = REG_SET_FIELD(0, SH_MEM_BASES, PRIVATE_BASE,
                                (adev->gmc.private_aperture_start >> 48));
index 9f0f189..1598674 100644 (file)
@@ -236,7 +236,8 @@ static void gfxhub_v1_0_setup_vmid_config(struct amdgpu_device *adev)
                                    block_size);
                /* Send no-retry XNACK on fault to suppress VM fault storm. */
                tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL,
-                                   RETRY_PERMISSION_OR_INVALID_PAGE_FAULT, 1);
+                                   RETRY_PERMISSION_OR_INVALID_PAGE_FAULT,
+                                   !amdgpu_noretry);
                WREG32_SOC15_OFFSET(GC, 0, mmVM_CONTEXT1_CNTL, i, tmp);
                WREG32_SOC15_OFFSET(GC, 0, mmVM_CONTEXT1_PAGE_TABLE_START_ADDR_LO32, i*2, 0);
                WREG32_SOC15_OFFSET(GC, 0, mmVM_CONTEXT1_PAGE_TABLE_START_ADDR_HI32, i*2, 0);
index b7de60a..d605b49 100644 (file)
@@ -215,7 +215,8 @@ static void gfxhub_v2_0_setup_vmid_config(struct amdgpu_device *adev)
                                adev->vm_manager.block_size - 9);
                /* Send no-retry XNACK on fault to suppress VM fault storm. */
                tmp = REG_SET_FIELD(tmp, GCVM_CONTEXT1_CNTL,
-                                   RETRY_PERMISSION_OR_INVALID_PAGE_FAULT, 0);
+                                   RETRY_PERMISSION_OR_INVALID_PAGE_FAULT,
+                                   !amdgpu_noretry);
                WREG32_SOC15_OFFSET(GC, 0, mmGCVM_CONTEXT1_CNTL, i, tmp);
                WREG32_SOC15_OFFSET(GC, 0, mmGCVM_CONTEXT1_PAGE_TABLE_START_ADDR_LO32, i*2, 0);
                WREG32_SOC15_OFFSET(GC, 0, mmGCVM_CONTEXT1_PAGE_TABLE_START_ADDR_HI32, i*2, 0);
index 05d1d44..dc5ce03 100644 (file)
@@ -265,7 +265,8 @@ static void mmhub_v1_0_setup_vmid_config(struct amdgpu_device *adev)
                                    block_size);
                /* Send no-retry XNACK on fault to suppress VM fault storm. */
                tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL,
-                                   RETRY_PERMISSION_OR_INVALID_PAGE_FAULT, 1);
+                                   RETRY_PERMISSION_OR_INVALID_PAGE_FAULT,
+                                   !amdgpu_noretry);
                WREG32_SOC15_OFFSET(MMHUB, 0, mmVM_CONTEXT1_CNTL, i, tmp);
                WREG32_SOC15_OFFSET(MMHUB, 0, mmVM_CONTEXT1_PAGE_TABLE_START_ADDR_LO32, i*2, 0);
                WREG32_SOC15_OFFSET(MMHUB, 0, mmVM_CONTEXT1_PAGE_TABLE_START_ADDR_HI32, i*2, 0);
index 37a1a31..0f9549f 100644 (file)
@@ -205,7 +205,8 @@ static void mmhub_v2_0_setup_vmid_config(struct amdgpu_device *adev)
                                    adev->vm_manager.block_size - 9);
                /* Send no-retry XNACK on fault to suppress VM fault storm. */
                tmp = REG_SET_FIELD(tmp, MMVM_CONTEXT1_CNTL,
-                                   RETRY_PERMISSION_OR_INVALID_PAGE_FAULT, 0);
+                                   RETRY_PERMISSION_OR_INVALID_PAGE_FAULT,
+                                   !amdgpu_noretry);
                WREG32_SOC15_OFFSET(MMHUB, 0, mmMMVM_CONTEXT1_CNTL, i, tmp);
                WREG32_SOC15_OFFSET(MMHUB, 0, mmMMVM_CONTEXT1_PAGE_TABLE_START_ADDR_LO32, i*2, 0);
                WREG32_SOC15_OFFSET(MMHUB, 0, mmMMVM_CONTEXT1_PAGE_TABLE_START_ADDR_HI32, i*2, 0);
index ad430cb..662612f 100644 (file)
@@ -392,8 +392,6 @@ int nv_set_ip_blocks(struct amdgpu_device *adev)
 #if defined(CONFIG_DRM_AMD_DC)
                else if (amdgpu_device_has_dc_support(adev))
                        amdgpu_device_ip_block_add(adev, &dm_ip_block);
-#else
-#      warning "Enable CONFIG_DRM_AMD_DC for display support on navi."
 #endif
                amdgpu_device_ip_block_add(adev, &gfx_v10_0_ip_block);
                amdgpu_device_ip_block_add(adev, &sdma_v5_0_ip_block);
index 61744e2..41b7258 100644 (file)
@@ -103,6 +103,9 @@ static int psp_v11_0_init_microcode(struct psp_context *psp)
                        adev->psp.toc_bin_size = le32_to_cpu(sos_hdr_v1_1->toc_size_bytes);
                        adev->psp.toc_start_addr = (uint8_t *)adev->psp.sys_start_addr +
                                        le32_to_cpu(sos_hdr_v1_1->toc_offset_bytes);
+                       adev->psp.kdb_bin_size = le32_to_cpu(sos_hdr_v1_1->kdb_size_bytes);
+                       adev->psp.kdb_start_addr = (uint8_t *)adev->psp.sys_start_addr +
+                                       le32_to_cpu(sos_hdr_v1_1->kdb_offset_bytes);
                }
                break;
        default:
@@ -177,6 +180,48 @@ out:
        return err;
 }
 
+static int psp_v11_0_bootloader_load_kdb(struct psp_context *psp)
+{
+       int ret;
+       uint32_t psp_gfxdrv_command_reg = 0;
+       struct amdgpu_device *adev = psp->adev;
+       uint32_t sol_reg;
+
+       /* Check tOS sign of life register to confirm sys driver and sOS
+        * are already been loaded.
+        */
+       sol_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_81);
+       if (sol_reg) {
+               psp->sos_fw_version = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_58);
+               dev_info(adev->dev, "sos fw version = 0x%x.\n", psp->sos_fw_version);
+               return 0;
+       }
+
+       /* Wait for bootloader to signify that is ready having bit 31 of C2PMSG_35 set to 1 */
+       ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
+                          0x80000000, 0x80000000, false);
+       if (ret)
+               return ret;
+
+       memset(psp->fw_pri_buf, 0, PSP_1_MEG);
+
+       /* Copy PSP KDB binary to memory */
+       memcpy(psp->fw_pri_buf, psp->kdb_start_addr, psp->kdb_bin_size);
+
+       /* Provide the sys driver to bootloader */
+       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
+              (uint32_t)(psp->fw_pri_mc_addr >> 20));
+       psp_gfxdrv_command_reg = PSP_BL__LOAD_KEY_DATABASE;
+       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35,
+              psp_gfxdrv_command_reg);
+
+       /* Wait for bootloader to signify that is ready having  bit 31 of C2PMSG_35 set to 1*/
+       ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
+                          0x80000000, 0x80000000, false);
+
+       return ret;
+}
+
 static int psp_v11_0_bootloader_load_sysdrv(struct psp_context *psp)
 {
        int ret;
@@ -190,7 +235,7 @@ static int psp_v11_0_bootloader_load_sysdrv(struct psp_context *psp)
        sol_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_81);
        if (sol_reg) {
                psp->sos_fw_version = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_58);
-               printk("sos fw version = 0x%x.\n", psp->sos_fw_version);
+               dev_info(adev->dev, "sos fw version = 0x%x.\n", psp->sos_fw_version);
                return 0;
        }
 
@@ -208,7 +253,7 @@ static int psp_v11_0_bootloader_load_sysdrv(struct psp_context *psp)
        /* Provide the sys driver to bootloader */
        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
               (uint32_t)(psp->fw_pri_mc_addr >> 20));
-       psp_gfxdrv_command_reg = 1 << 16;
+       psp_gfxdrv_command_reg = PSP_BL__LOAD_SYSDRV;
        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35,
               psp_gfxdrv_command_reg);
 
@@ -249,7 +294,7 @@ static int psp_v11_0_bootloader_load_sos(struct psp_context *psp)
        /* Provide the PSP secure OS to bootloader */
        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
               (uint32_t)(psp->fw_pri_mc_addr >> 20));
-       psp_gfxdrv_command_reg = 2 << 16;
+       psp_gfxdrv_command_reg = PSP_BL__LOAD_SOSDRV;
        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35,
               psp_gfxdrv_command_reg);
 
@@ -822,6 +867,7 @@ static int psp_v11_0_rlc_autoload_start(struct psp_context *psp)
 
 static const struct psp_funcs psp_v11_0_funcs = {
        .init_microcode = psp_v11_0_init_microcode,
+       .bootloader_load_kdb = psp_v11_0_bootloader_load_kdb,
        .bootloader_load_sysdrv = psp_v11_0_bootloader_load_sysdrv,
        .bootloader_load_sos = psp_v11_0_bootloader_load_sos,
        .ring_init = psp_v11_0_ring_init,
index 2ea7726..019c47f 100644 (file)
@@ -155,7 +155,7 @@ static int psp_v3_1_bootloader_load_sysdrv(struct psp_context *psp)
        /* Provide the sys driver to bootloader */
        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
               (uint32_t)(psp->fw_pri_mc_addr >> 20));
-       psp_gfxdrv_command_reg = 1 << 16;
+       psp_gfxdrv_command_reg = PSP_BL__LOAD_SYSDRV;
        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35,
               psp_gfxdrv_command_reg);
 
@@ -218,7 +218,7 @@ static int psp_v3_1_bootloader_load_sos(struct psp_context *psp)
        /* Provide the PSP secure OS to bootloader */
        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
               (uint32_t)(psp->fw_pri_mc_addr >> 20));
-       psp_gfxdrv_command_reg = 2 << 16;
+       psp_gfxdrv_command_reg = PSP_BL__LOAD_SOSDRV;
        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35,
               psp_gfxdrv_command_reg);
 
index 87152d8..2326541 100644 (file)
@@ -649,8 +649,6 @@ int soc15_set_ip_blocks(struct amdgpu_device *adev)
 #if defined(CONFIG_DRM_AMD_DC)
                else if (amdgpu_device_has_dc_support(adev))
                        amdgpu_device_ip_block_add(adev, &dm_ip_block);
-#else
-#      warning "Enable CONFIG_DRM_AMD_DC for display support on SOC15."
 #endif
                if (!(adev->asic_type == CHIP_VEGA20 && amdgpu_sriov_vf(adev))) {
                        amdgpu_device_ip_block_add(adev, &uvd_v7_0_ip_block);
@@ -671,8 +669,6 @@ int soc15_set_ip_blocks(struct amdgpu_device *adev)
 #if defined(CONFIG_DRM_AMD_DC)
                else if (amdgpu_device_has_dc_support(adev))
                        amdgpu_device_ip_block_add(adev, &dm_ip_block);
-#else
-#      warning "Enable CONFIG_DRM_AMD_DC for display support on SOC15."
 #endif
                amdgpu_device_ip_block_add(adev, &vcn_v1_0_ip_block);
                break;
@@ -717,9 +713,15 @@ static void soc15_get_pcie_usage(struct amdgpu_device *adev, uint64_t *count0,
                return;
 
        /* Set the 2 events that we wish to watch, defined above */
-       /* Reg 40 is # received msgs, Reg 104 is # of posted requests sent */
+       /* Reg 40 is # received msgs */
        perfctr = REG_SET_FIELD(perfctr, PCIE_PERF_CNTL_TXCLK, EVENT0_SEL, 40);
-       perfctr = REG_SET_FIELD(perfctr, PCIE_PERF_CNTL_TXCLK, EVENT1_SEL, 104);
+       /* Pre-VG20, Reg 104 is # of posted requests sent. On VG20 it's 108 */
+       if (adev->asic_type == CHIP_VEGA20)
+               perfctr = REG_SET_FIELD(perfctr, PCIE_PERF_CNTL_TXCLK,
+                                       EVENT1_SEL, 108);
+       else
+               perfctr = REG_SET_FIELD(perfctr, PCIE_PERF_CNTL_TXCLK,
+                                       EVENT1_SEL, 104);
 
        /* Write to enable desired perf counters */
        WREG32_PCIE(smnPCIE_PERF_CNTL_TXCLK, perfctr);
index d40ed1a..6575ddc 100644 (file)
@@ -59,7 +59,6 @@
 
 #include "vid.h"
 #include "vi.h"
-#include "vi_dpm.h"
 #include "gmc_v8_0.h"
 #include "gmc_v7_0.h"
 #include "gfx_v8_0.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/vi_dpm.h b/drivers/gpu/drm/amd/amdgpu/vi_dpm.h
deleted file mode 100644 (file)
index c43e03f..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2014 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#ifndef __VI_DPM_H__
-#define __VI_DPM_H__
-
-extern const struct amd_ip_funcs cz_dpm_ip_funcs;
-int cz_smu_init(struct amdgpu_device *adev);
-int cz_smu_start(struct amdgpu_device *adev);
-int cz_smu_fini(struct amdgpu_device *adev);
-
-#endif
index 584748c..e6a4288 100644 (file)
@@ -1157,12 +1157,7 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
 
        mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
                        q->properties.type)];
-       /*
-        * Eviction state logic: mark all queues as evicted, even ones
-        * not currently active. Restoring inactive queues later only
-        * updates the is_evicted flag but is a no-op otherwise.
-        */
-       q->properties.is_evicted = !!qpd->evicted;
+
        if (q->properties.type == KFD_QUEUE_TYPE_SDMA ||
                q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)
                dqm->asic_ops.init_sdma_vm(dqm, q, qpd);
@@ -1173,9 +1168,16 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
                retval = -ENOMEM;
                goto out_deallocate_doorbell;
        }
+
+       dqm_lock(dqm);
+       /*
+        * Eviction state logic: mark all queues as evicted, even ones
+        * not currently active. Restoring inactive queues later only
+        * updates the is_evicted flag but is a no-op otherwise.
+        */
+       q->properties.is_evicted = !!qpd->evicted;
        mqd_mgr->init_mqd(mqd_mgr, &q->mqd, q->mqd_mem_obj,
                                &q->gart_mqd_addr, &q->properties);
-       dqm_lock(dqm);
 
        list_add(&q->list, &qpd->queues_list);
        qpd->queue_count++;
index e9fe393..95a82ac 100644 (file)
@@ -61,7 +61,7 @@ static int update_qpd_v9(struct device_queue_manager *dqm,
                qpd->sh_mem_config =
                                SH_MEM_ALIGNMENT_MODE_UNALIGNED <<
                                        SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT;
-               if (noretry &&
+               if (amdgpu_noretry &&
                    !dqm->dev->device_info->needs_iommu_device)
                        qpd->sh_mem_config |=
                                1 << SH_MEM_CONFIG__RETRY_DISABLE__SHIFT;
index 08a0feb..3933fb6 100644 (file)
@@ -157,7 +157,7 @@ extern int ignore_crat;
 /*
  * Set sh_mem_config.retry_disable on Vega10
  */
-extern int noretry;
+extern int amdgpu_noretry;
 
 /*
  * Halt if HWS hang is detected
index da09586..7e6c3ee 100644 (file)
@@ -150,6 +150,9 @@ void pqm_uninit(struct process_queue_manager *pqm)
        struct process_queue_node *pqn, *next;
 
        list_for_each_entry_safe(pqn, next, &pqm->queues, process_queue_list) {
+               if (pqn->q && pqn->q->gws)
+                       amdgpu_amdkfd_remove_gws_from_process(pqm->process->kgd_process_info,
+                               pqn->q->gws);
                uninit_queue(pqn->q);
                list_del(&pqn->process_queue_list);
                kfree(pqn);
index 7073cfc..f954bf6 100644 (file)
@@ -5,6 +5,7 @@ menu "Display Engine Configuration"
 config DRM_AMD_DC
        bool "AMD DC - Enable new display engine"
        default y
+       select SND_HDA_COMPONENT if SND_HDA_CORE
        select DRM_AMD_DC_DCN1_0 if X86 && !(KCOV_INSTRUMENT_ALL && KCOV_ENABLE_COMPARISONS)
        help
          Choose this option if you want to use the new display engine
index 0242d69..4a29f72 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/pci.h>
 #include <linux/firmware.h>
+#include <linux/component.h>
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_uapi.h>
@@ -65,6 +66,7 @@
 #include <drm/drm_fourcc.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_vblank.h>
+#include <drm/drm_audio_component.h>
 
 #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
 #include "ivsrcid/dcn/irqsrcs_dcn_1_0.h"
@@ -508,6 +510,139 @@ static void amdgpu_dm_fbc_init(struct drm_connector *connector)
 
 }
 
+static int amdgpu_dm_audio_component_get_eld(struct device *kdev, int port,
+                                         int pipe, bool *enabled,
+                                         unsigned char *buf, int max_bytes)
+{
+       struct drm_device *dev = dev_get_drvdata(kdev);
+       struct amdgpu_device *adev = dev->dev_private;
+       struct drm_connector *connector;
+       struct drm_connector_list_iter conn_iter;
+       struct amdgpu_dm_connector *aconnector;
+       int ret = 0;
+
+       *enabled = false;
+
+       mutex_lock(&adev->dm.audio_lock);
+
+       drm_connector_list_iter_begin(dev, &conn_iter);
+       drm_for_each_connector_iter(connector, &conn_iter) {
+               aconnector = to_amdgpu_dm_connector(connector);
+               if (aconnector->audio_inst != port)
+                       continue;
+
+               *enabled = true;
+               ret = drm_eld_size(connector->eld);
+               memcpy(buf, connector->eld, min(max_bytes, ret));
+
+               break;
+       }
+       drm_connector_list_iter_end(&conn_iter);
+
+       mutex_unlock(&adev->dm.audio_lock);
+
+       DRM_DEBUG_KMS("Get ELD : idx=%d ret=%d en=%d\n", port, ret, *enabled);
+
+       return ret;
+}
+
+static const struct drm_audio_component_ops amdgpu_dm_audio_component_ops = {
+       .get_eld = amdgpu_dm_audio_component_get_eld,
+};
+
+static int amdgpu_dm_audio_component_bind(struct device *kdev,
+                                      struct device *hda_kdev, void *data)
+{
+       struct drm_device *dev = dev_get_drvdata(kdev);
+       struct amdgpu_device *adev = dev->dev_private;
+       struct drm_audio_component *acomp = data;
+
+       acomp->ops = &amdgpu_dm_audio_component_ops;
+       acomp->dev = kdev;
+       adev->dm.audio_component = acomp;
+
+       return 0;
+}
+
+static void amdgpu_dm_audio_component_unbind(struct device *kdev,
+                                         struct device *hda_kdev, void *data)
+{
+       struct drm_device *dev = dev_get_drvdata(kdev);
+       struct amdgpu_device *adev = dev->dev_private;
+       struct drm_audio_component *acomp = data;
+
+       acomp->ops = NULL;
+       acomp->dev = NULL;
+       adev->dm.audio_component = NULL;
+}
+
+static const struct component_ops amdgpu_dm_audio_component_bind_ops = {
+       .bind   = amdgpu_dm_audio_component_bind,
+       .unbind = amdgpu_dm_audio_component_unbind,
+};
+
+static int amdgpu_dm_audio_init(struct amdgpu_device *adev)
+{
+       int i, ret;
+
+       if (!amdgpu_audio)
+               return 0;
+
+       adev->mode_info.audio.enabled = true;
+
+       adev->mode_info.audio.num_pins = adev->dm.dc->res_pool->audio_count;
+
+       for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
+               adev->mode_info.audio.pin[i].channels = -1;
+               adev->mode_info.audio.pin[i].rate = -1;
+               adev->mode_info.audio.pin[i].bits_per_sample = -1;
+               adev->mode_info.audio.pin[i].status_bits = 0;
+               adev->mode_info.audio.pin[i].category_code = 0;
+               adev->mode_info.audio.pin[i].connected = false;
+               adev->mode_info.audio.pin[i].id =
+                       adev->dm.dc->res_pool->audios[i]->inst;
+               adev->mode_info.audio.pin[i].offset = 0;
+       }
+
+       ret = component_add(adev->dev, &amdgpu_dm_audio_component_bind_ops);
+       if (ret < 0)
+               return ret;
+
+       adev->dm.audio_registered = true;
+
+       return 0;
+}
+
+static void amdgpu_dm_audio_fini(struct amdgpu_device *adev)
+{
+       if (!amdgpu_audio)
+               return;
+
+       if (!adev->mode_info.audio.enabled)
+               return;
+
+       if (adev->dm.audio_registered) {
+               component_del(adev->dev, &amdgpu_dm_audio_component_bind_ops);
+               adev->dm.audio_registered = false;
+       }
+
+       /* TODO: Disable audio? */
+
+       adev->mode_info.audio.enabled = false;
+}
+
+void amdgpu_dm_audio_eld_notify(struct amdgpu_device *adev, int pin)
+{
+       struct drm_audio_component *acomp = adev->dm.audio_component;
+
+       if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) {
+               DRM_DEBUG_KMS("Notify ELD: %d\n", pin);
+
+               acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
+                                                pin, -1);
+       }
+}
+
 static int amdgpu_dm_init(struct amdgpu_device *adev)
 {
        struct dc_init_data init_data;
@@ -518,6 +653,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
        memset(&init_data, 0, sizeof(init_data));
 
        mutex_init(&adev->dm.dc_lock);
+       mutex_init(&adev->dm.audio_lock);
 
        if(amdgpu_dm_irq_init(adev)) {
                DRM_ERROR("amdgpu: failed to initialize DM IRQ support.\n");
@@ -621,6 +757,8 @@ error:
 
 static void amdgpu_dm_fini(struct amdgpu_device *adev)
 {
+       amdgpu_dm_audio_fini(adev);
+
        amdgpu_dm_destroy_drm_device(&adev->dm);
 
        /* DC Destroy TODO: Replace destroy DAL */
@@ -641,6 +779,7 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev)
                adev->dm.freesync_module = NULL;
        }
 
+       mutex_destroy(&adev->dm.audio_lock);
        mutex_destroy(&adev->dm.dc_lock);
 
        return;
@@ -1888,6 +2027,10 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
        if (r)
                return r;
 
+       r = amdgpu_dm_audio_init(adev);
+       if (r)
+               return r;
+
        return 0;
 }
 
@@ -4834,6 +4977,7 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
        aconnector->base.stereo_allowed = false;
        aconnector->base.dpms = DRM_MODE_DPMS_OFF;
        aconnector->hpd.hpd = AMDGPU_HPD_NONE; /* not used */
+       aconnector->audio_inst = -1;
        mutex_init(&aconnector->hpd_lock);
 
        /*
@@ -5728,6 +5872,81 @@ cleanup:
        kfree(bundle);
 }
 
+static void amdgpu_dm_commit_audio(struct drm_device *dev,
+                                  struct drm_atomic_state *state)
+{
+       struct amdgpu_device *adev = dev->dev_private;
+       struct amdgpu_dm_connector *aconnector;
+       struct drm_connector *connector;
+       struct drm_connector_state *old_con_state, *new_con_state;
+       struct drm_crtc_state *new_crtc_state;
+       struct dm_crtc_state *new_dm_crtc_state;
+       const struct dc_stream_status *status;
+       int i, inst;
+
+       /* Notify device removals. */
+       for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
+               if (old_con_state->crtc != new_con_state->crtc) {
+                       /* CRTC changes require notification. */
+                       goto notify;
+               }
+
+               if (!new_con_state->crtc)
+                       continue;
+
+               new_crtc_state = drm_atomic_get_new_crtc_state(
+                       state, new_con_state->crtc);
+
+               if (!new_crtc_state)
+                       continue;
+
+               if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
+                       continue;
+
+       notify:
+               aconnector = to_amdgpu_dm_connector(connector);
+
+               mutex_lock(&adev->dm.audio_lock);
+               inst = aconnector->audio_inst;
+               aconnector->audio_inst = -1;
+               mutex_unlock(&adev->dm.audio_lock);
+
+               amdgpu_dm_audio_eld_notify(adev, inst);
+       }
+
+       /* Notify audio device additions. */
+       for_each_new_connector_in_state(state, connector, new_con_state, i) {
+               if (!new_con_state->crtc)
+                       continue;
+
+               new_crtc_state = drm_atomic_get_new_crtc_state(
+                       state, new_con_state->crtc);
+
+               if (!new_crtc_state)
+                       continue;
+
+               if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
+                       continue;
+
+               new_dm_crtc_state = to_dm_crtc_state(new_crtc_state);
+               if (!new_dm_crtc_state->stream)
+                       continue;
+
+               status = dc_stream_get_status(new_dm_crtc_state->stream);
+               if (!status)
+                       continue;
+
+               aconnector = to_amdgpu_dm_connector(connector);
+
+               mutex_lock(&adev->dm.audio_lock);
+               inst = status->audio_inst;
+               aconnector->audio_inst = inst;
+               mutex_unlock(&adev->dm.audio_lock);
+
+               amdgpu_dm_audio_eld_notify(adev, inst);
+       }
+}
+
 /*
  * Enable interrupts on CRTCs that are newly active, undergone
  * a modeset, or have active planes again.
@@ -6106,6 +6325,9 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
        /* Enable interrupts for CRTCs going from 0 to n active planes. */
        amdgpu_dm_enable_crtc_interrupts(dev, state, false);
 
+       /* Update audio instances for each connector. */
+       amdgpu_dm_commit_audio(dev, state);
+
        /*
         * send vblank event on all events not handled in flip and
         * mark consumed event for drm_atomic_helper_commit_hw_done
index baca5dc..b89cbbf 100644 (file)
@@ -144,6 +144,28 @@ struct amdgpu_display_manager {
        struct mutex dc_lock;
 
        /**
+        * @audio_lock:
+        *
+        * Guards access to audio instance changes.
+        */
+       struct mutex audio_lock;
+
+       /**
+        * @audio_component:
+        *
+        * Used to notify ELD changes to sound driver.
+        */
+       struct drm_audio_component *audio_component;
+
+       /**
+        * @audio_registered:
+        *
+        * True if the audio component has been registered
+        * successfully, false otherwise.
+        */
+       bool audio_registered;
+
+       /**
         * @irq_handler_list_low_tab:
         *
         * Low priority IRQ handler table.
@@ -254,6 +276,9 @@ struct amdgpu_dm_connector {
        int max_vfreq ;
        int pixel_clock_mhz;
 
+       /* Audio instance - protected by audio_lock. */
+       int audio_inst;
+
        struct mutex hpd_lock;
 
        bool fake_enable;
index eac09bf..592fa49 100644 (file)
@@ -308,7 +308,8 @@ static void pp_to_dc_clock_levels_with_voltage(
                        DC_DECODE_PP_CLOCK_TYPE(dc_clk_type));
 
        for (i = 0; i < clk_level_info->num_levels; i++) {
-               DRM_INFO("DM_PPLIB:\t %d in kHz\n", pp_clks->data[i].clocks_in_khz);
+               DRM_INFO("DM_PPLIB:\t %d in kHz, %d in mV\n", pp_clks->data[i].clocks_in_khz,
+                        pp_clks->data[i].voltage_in_mv);
                clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz;
                clk_level_info->data[i].voltage_in_mv = pp_clks->data[i].voltage_in_mv;
        }
@@ -910,11 +911,11 @@ void dm_pp_get_funcs(
                /* todo set_pme_wa_enable cause 4k@6ohz display not light up */
                funcs->nv_funcs.set_pme_wa_enable = NULL;
                /* todo debug waring message */
-               funcs->nv_funcs.set_hard_min_uclk_by_freq = NULL;
+               funcs->nv_funcs.set_hard_min_uclk_by_freq = pp_nv_set_hard_min_uclk_by_freq;
                /* todo  compare data with window driver*/
-               funcs->nv_funcs.get_maximum_sustainable_clocks = NULL;
+               funcs->nv_funcs.get_maximum_sustainable_clocks = pp_nv_get_maximum_sustainable_clocks;
                /*todo  compare data with window driver */
-               funcs->nv_funcs.get_uclk_dpm_states = NULL;
+               funcs->nv_funcs.get_uclk_dpm_states = pp_nv_get_uclk_dpm_states;
                break;
 #endif
        default:
index 173fcfb..51a7828 100644 (file)
@@ -175,32 +175,22 @@ struct resource_pool *dc_create_resource_pool(struct dc  *dc,
        if (res_pool != NULL) {
                struct dc_firmware_info fw_info = { { 0 } };
 
-               if (dc->ctx->dc_bios->funcs->get_firmware_info(
-                               dc->ctx->dc_bios, &fw_info) == BP_RESULT_OK) {
-                               res_pool->ref_clocks.xtalin_clock_inKhz = fw_info.pll_info.crystal_frequency;
-
-                               if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
-                                       // On FPGA these dividers are currently not configured by GDB
-                                       res_pool->ref_clocks.dccg_ref_clock_inKhz = res_pool->ref_clocks.xtalin_clock_inKhz;
-                                       res_pool->ref_clocks.dchub_ref_clock_inKhz = res_pool->ref_clocks.xtalin_clock_inKhz;
-                               } else if (res_pool->dccg && res_pool->hubbub) {
-                                       // If DCCG reference frequency cannot be determined (usually means not set to xtalin) then this is a critical error
-                                       // as this value must be known for DCHUB programming
-                                       (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
-                                                       fw_info.pll_info.crystal_frequency,
-                                                       &res_pool->ref_clocks.dccg_ref_clock_inKhz);
-
-                                       // Similarly, if DCHUB reference frequency cannot be determined, then it is also a critical error
-                                       (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
-                                                       res_pool->ref_clocks.dccg_ref_clock_inKhz,
-                                                       &res_pool->ref_clocks.dchub_ref_clock_inKhz);
-                               } else {
-                                       // Not all ASICs have DCCG sw component
-                                       res_pool->ref_clocks.dccg_ref_clock_inKhz = res_pool->ref_clocks.xtalin_clock_inKhz;
-                                       res_pool->ref_clocks.dchub_ref_clock_inKhz = res_pool->ref_clocks.xtalin_clock_inKhz;
-                               }
-                       } else
-                               ASSERT_CRITICAL(false);
+               if (dc->ctx->dc_bios->funcs->get_firmware_info(dc->ctx->dc_bios,
+                               &fw_info) == BP_RESULT_OK) {
+                       res_pool->ref_clocks.xtalin_clock_inKhz =
+                               fw_info.pll_info.crystal_frequency;
+                       /* initialize with firmware data first, no all
+                        * ASIC have DCCG SW component. FPGA or
+                        * simulation need initialization of
+                        * dccg_ref_clock_inKhz, dchub_ref_clock_inKhz
+                        * with xtalin_clock_inKhz
+                        */
+                       res_pool->ref_clocks.dccg_ref_clock_inKhz =
+                               res_pool->ref_clocks.xtalin_clock_inKhz;
+                       res_pool->ref_clocks.dchub_ref_clock_inKhz =
+                               res_pool->ref_clocks.xtalin_clock_inKhz;
+               } else
+                       ASSERT_CRITICAL(false);
        }
 
        return res_pool;
@@ -2011,6 +2001,9 @@ enum dc_status resource_map_pool_resources(
                if (context->streams[i] == stream) {
                        context->stream_status[i].primary_otg_inst = pipe_ctx->stream_res.tg->inst;
                        context->stream_status[i].stream_enc_inst = pipe_ctx->stream_res.stream_enc->id;
+                       context->stream_status[i].audio_inst =
+                               pipe_ctx->stream_res.audio ? pipe_ctx->stream_res.audio->inst : -1;
+
                        return DC_OK;
                }
 
index e253a5c..0fa1c26 100644 (file)
@@ -42,6 +42,7 @@ struct dc_stream_status {
        int primary_otg_inst;
        int stream_enc_inst;
        int plane_count;
+       int audio_inst;
        struct timing_sync_info timing_sync_info;
        struct dc_plane_state *plane_states[MAX_SURFACE_NUM];
 };
index 1b68de2..e9721a9 100644 (file)
@@ -10,7 +10,13 @@ ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
 DCN20 += dcn20_dsc.o
 endif
 
-CFLAGS_dcn20_resource.o := -mhard-float -msse -mpreferred-stack-boundary=4
+ifneq ($(call cc-option, -mpreferred-stack-boundary=4),)
+       cc_stack_align := -mpreferred-stack-boundary=4
+else ifneq ($(call cc-option, -mstack-alignment=16),)
+       cc_stack_align := -mstack-alignment=16
+endif
+
+CFLAGS_dcn20_resource.o := -mhard-float -msse $(cc_stack_align)
 
 AMD_DAL_DCN20 = $(addprefix $(AMDDALPATH)/dc/dcn20/,$(DCN20))
 
index 6925d25..0b84a32 100644 (file)
@@ -523,6 +523,7 @@ static void dcn20_init_hw(struct dc *dc)
        struct dc_bios *dcb = dc->ctx->dc_bios;
        struct resource_pool *res_pool = dc->res_pool;
        struct dc_state  *context = dc->current_state;
+       struct dc_firmware_info fw_info = { { 0 } };
 
        if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
                dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
@@ -546,6 +547,30 @@ static void dcn20_init_hw(struct dc *dc)
        } else {
                if (!dcb->funcs->is_accelerated_mode(dcb)) {
                        bios_golden_init(dc);
+                       if (dc->ctx->dc_bios->funcs->get_firmware_info(
+                                       dc->ctx->dc_bios, &fw_info) == BP_RESULT_OK) {
+                               res_pool->ref_clocks.xtalin_clock_inKhz = fw_info.pll_info.crystal_frequency;
+
+                               if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
+                                       if (res_pool->dccg && res_pool->hubbub) {
+
+                                               (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
+                                                               fw_info.pll_info.crystal_frequency,
+                                                               &res_pool->ref_clocks.dccg_ref_clock_inKhz);
+
+                                               (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
+                                                               res_pool->ref_clocks.dccg_ref_clock_inKhz,
+                                                               &res_pool->ref_clocks.dchub_ref_clock_inKhz);
+                                       } else {
+                                               // Not all ASICs have DCCG sw component
+                                               res_pool->ref_clocks.dccg_ref_clock_inKhz =
+                                                               res_pool->ref_clocks.xtalin_clock_inKhz;
+                                               res_pool->ref_clocks.dchub_ref_clock_inKhz =
+                                                               res_pool->ref_clocks.xtalin_clock_inKhz;
+                                       }
+                               }
+                       } else
+                               ASSERT_CRITICAL(false);
                        disable_vga(dc->hwseq);
                }
 
index 4e52df8..d200bc3 100644 (file)
@@ -2415,7 +2415,7 @@ struct pipe_ctx *dcn20_acquire_idle_pipe_for_layer(
                ASSERT(0);
 
        if (!idle_pipe)
-               return false;
+               return NULL;
 
        idle_pipe->stream = head_pipe->stream;
        idle_pipe->stream_res.tg = head_pipe->stream_res.tg;
@@ -2576,6 +2576,9 @@ static void cap_soc_clocks(
                                                && max_clocks.uClockInKhz != 0)
                        bb->clock_limits[i].dram_speed_mts = (max_clocks.uClockInKhz / 1000) * 16;
 
+               // HACK: Force every uclk to max for now to "disable" uclk switching.
+               bb->clock_limits[i].dram_speed_mts = (max_clocks.uClockInKhz / 1000) * 16;
+
                if ((bb->clock_limits[i].fabricclk_mhz > (max_clocks.fabricClockInKhz / 1000))
                                                && max_clocks.fabricClockInKhz != 0)
                        bb->clock_limits[i].fabricclk_mhz = (max_clocks.fabricClockInKhz / 1000);
@@ -2783,6 +2786,8 @@ static bool init_soc_bounding_box(struct dc *dc,
                                le32_to_cpu(bb->vmm_page_size_bytes);
                dcn2_0_soc.dram_clock_change_latency_us =
                                fixed16_to_double_to_cpu(bb->dram_clock_change_latency_us);
+               // HACK!! Lower uclock latency switch time so we don't switch
+               dcn2_0_soc.dram_clock_change_latency_us = 10;
                dcn2_0_soc.writeback_dram_clock_change_latency_us =
                                fixed16_to_double_to_cpu(bb->writeback_dram_clock_change_latency_us);
                dcn2_0_soc.return_bus_width_bytes =
@@ -2824,6 +2829,7 @@ static bool init_soc_bounding_box(struct dc *dc,
                struct pp_smu_nv_clock_table max_clocks = {0};
                unsigned int uclk_states[8] = {0};
                unsigned int num_states = 0;
+               int i;
                enum pp_smu_status status;
                bool clock_limits_available = false;
                bool uclk_states_available = false;
@@ -2845,6 +2851,10 @@ static bool init_soc_bounding_box(struct dc *dc,
                        clock_limits_available = (status == PP_SMU_RESULT_OK);
                }
 
+               // HACK: Use the max uclk_states value for all elements.
+               for (i = 0; i < num_states; i++)
+                       uclk_states[i] = uclk_states[num_states - 1];
+
                if (clock_limits_available && uclk_states_available && num_states)
                        update_bounding_box(dc, &dcn2_0_soc, &max_clocks, uclk_states, num_states);
                else if (clock_limits_available)
index c5d5b94..e019cd9 100644 (file)
@@ -1,10 +1,18 @@
 #
 # Makefile for the 'dsc' sub-component of DAL.
 
-CFLAGS_rc_calc.o := -mhard-float -msse -mpreferred-stack-boundary=4
-CFLAGS_rc_calc_dpi.o := -mhard-float -msse -mpreferred-stack-boundary=4
-CFLAGS_codec_main_amd.o := -mhard-float -msse -mpreferred-stack-boundary=4
-CFLAGS_dc_dsc.o := -mhard-float -msse -mpreferred-stack-boundary=4
+ifneq ($(call cc-option, -mpreferred-stack-boundary=4),)
+       cc_stack_align := -mpreferred-stack-boundary=4
+else ifneq ($(call cc-option, -mstack-alignment=16),)
+       cc_stack_align := -mstack-alignment=16
+endif
+
+dsc_ccflags := -mhard-float -msse $(cc_stack_align)
+
+CFLAGS_rc_calc.o := $(dsc_ccflags)
+CFLAGS_rc_calc_dpi.o := $(dsc_ccflags)
+CFLAGS_codec_main_amd.o := $(dsc_ccflags)
+CFLAGS_dc_dsc.o := $(dsc_ccflags)
 
 DSC = dc_dsc.o rc_calc.o rc_calc_dpi.o
 
index d352b8d..a0a7211 100644 (file)
@@ -26,7 +26,7 @@
 #include <drm/amd_asic_type.h>
 
 
-#define AMD_MAX_USEC_TIMEOUT           200000  /* 200 ms */
+#define AMD_MAX_USEC_TIMEOUT           1000000  /* 1000 ms */
 
 /*
  * Chip flags
index 3093917..f1565c4 100644 (file)
@@ -69,6 +69,9 @@ int smu_set_soft_freq_range(struct smu_context *smu, enum smu_clk_type clk_type,
        if (min <= 0 && max <= 0)
                return -EINVAL;
 
+       if (!smu_clk_dpm_is_enabled(smu, clk_type))
+               return 0;
+
        clk_id = smu_clk_get_index(smu, clk_type);
        if (clk_id < 0)
                return clk_id;
@@ -102,6 +105,9 @@ int smu_set_hard_freq_range(struct smu_context *smu, enum smu_clk_type clk_type,
        if (min <= 0 && max <= 0)
                return -EINVAL;
 
+       if (!smu_clk_dpm_is_enabled(smu, clk_type))
+               return 0;
+
        clk_id = smu_clk_get_index(smu, clk_type);
        if (clk_id < 0)
                return clk_id;
@@ -135,23 +141,8 @@ int smu_get_dpm_freq_range(struct smu_context *smu, enum smu_clk_type clk_type,
        if (!min && !max)
                return -EINVAL;
 
-       switch (clk_type) {
-       case SMU_UCLK:
-               if (!smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
-                       pr_warn("uclk dpm is not enabled\n");
-                       return 0;
-               }
-               break;
-       case SMU_GFXCLK:
-       case SMU_SCLK:
-               if (!smu_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) {
-                       pr_warn("gfxclk dpm is not enabled\n");
-                       return 0;
-               }
-               break;
-       default:
-               break;
-       }
+       if (!smu_clk_dpm_is_enabled(smu, clk_type))
+               return 0;
 
        mutex_lock(&smu->mutex);
        clk_id = smu_clk_get_index(smu, clk_type);
@@ -194,6 +185,9 @@ int smu_get_dpm_freq_by_index(struct smu_context *smu, enum smu_clk_type clk_typ
        if (!value)
                return -EINVAL;
 
+       if (!smu_clk_dpm_is_enabled(smu, clk_type))
+               return 0;
+
        clk_id = smu_clk_get_index(smu, clk_type);
        if (clk_id < 0)
                return clk_id;
@@ -222,6 +216,35 @@ int smu_get_dpm_level_count(struct smu_context *smu, enum smu_clk_type clk_type,
        return smu_get_dpm_freq_by_index(smu, clk_type, 0xff, value);
 }
 
+bool smu_clk_dpm_is_enabled(struct smu_context *smu, enum smu_clk_type clk_type)
+{
+       enum smu_feature_mask feature_id = 0;
+
+       switch (clk_type) {
+       case SMU_MCLK:
+       case SMU_UCLK:
+               feature_id = SMU_FEATURE_DPM_UCLK_BIT;
+               break;
+       case SMU_GFXCLK:
+       case SMU_SCLK:
+               feature_id = SMU_FEATURE_DPM_GFXCLK_BIT;
+               break;
+       case SMU_SOCCLK:
+               feature_id = SMU_FEATURE_DPM_SOCCLK_BIT;
+               break;
+       default:
+               return true;
+       }
+
+       if(!smu_feature_is_enabled(smu, feature_id)) {
+               pr_warn("smu %d clk dpm feature %d is not enabled\n", clk_type, feature_id);
+               return false;
+       }
+
+       return true;
+}
+
+
 int smu_dpm_set_power_gate(struct smu_context *smu, uint32_t block_type,
                           bool gate)
 {
@@ -300,7 +323,7 @@ int smu_common_read_sensor(struct smu_context *smu, enum amd_pp_sensors sensor,
        return ret;
 }
 
-int smu_update_table(struct smu_context *smu, enum smu_table_id table_index,
+int smu_update_table(struct smu_context *smu, enum smu_table_id table_index, int argument,
                     void *table_data, bool drv2smu)
 {
        struct smu_table_context *smu_table = &smu->smu_table;
@@ -327,7 +350,7 @@ int smu_update_table(struct smu_context *smu, enum smu_table_id table_index,
        ret = smu_send_smc_msg_with_param(smu, drv2smu ?
                                          SMU_MSG_TransferTableDram2Smu :
                                          SMU_MSG_TransferTableSmu2Dram,
-                                         table_id);
+                                         table_id | ((argument & 0xFFFF) << 16));
        if (ret)
                return ret;
 
@@ -1372,10 +1395,10 @@ int smu_adjust_power_state_dynamic(struct smu_context *smu,
                        break;
 
                case AMD_DPM_FORCED_LEVEL_AUTO:
+               case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
                        ret = smu_unforce_dpm_levels(smu);
                        break;
 
-               case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
                case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
                case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
                case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
@@ -1385,8 +1408,9 @@ int smu_adjust_power_state_dynamic(struct smu_context *smu,
                                                         &soc_mask);
                        if (ret)
                                return ret;
-                       smu_force_clk_levels(smu, PP_SCLK, 1 << sclk_mask);
-                       smu_force_clk_levels(smu, PP_MCLK, 1 << mclk_mask);
+                       smu_force_clk_levels(smu, SMU_SCLK, 1 << sclk_mask);
+                       smu_force_clk_levels(smu, SMU_MCLK, 1 << mclk_mask);
+                       smu_force_clk_levels(smu, SMU_SOCCLK, 1 << soc_mask);
                        break;
 
                case AMD_DPM_FORCED_LEVEL_MANUAL:
@@ -1441,17 +1465,16 @@ int smu_handle_task(struct smu_context *smu,
 enum amd_dpm_forced_level smu_get_performance_level(struct smu_context *smu)
 {
        struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
+       enum amd_dpm_forced_level level;
 
        if (!smu_dpm_ctx->dpm_context)
                return -EINVAL;
 
        mutex_lock(&(smu->mutex));
-       if (smu_dpm_ctx->dpm_level != smu_dpm_ctx->saved_dpm_level) {
-               smu_dpm_ctx->saved_dpm_level = smu_dpm_ctx->dpm_level;
-       }
+       level = smu_dpm_ctx->dpm_level;
        mutex_unlock(&(smu->mutex));
 
-       return smu_dpm_ctx->dpm_level;
+       return level;
 }
 
 int smu_force_performance_level(struct smu_context *smu, enum amd_dpm_forced_level level)
index 1cd5a8b..b760f95 100644 (file)
@@ -1067,8 +1067,6 @@ static int pp_tables_v1_0_initialize(struct pp_hwmgr *hwmgr)
        PP_ASSERT_WITH_CODE((NULL != hwmgr->pptable),
                            "Failed to allocate hwmgr->pptable!", return -ENOMEM);
 
-       memset(hwmgr->pptable, 0x00, sizeof(struct phm_ppt_v1_information));
-
        powerplay_table = get_powerplay_table(hwmgr);
 
        PP_ASSERT_WITH_CODE((NULL != powerplay_table),
index c97324e..1af992f 100644 (file)
@@ -937,7 +937,7 @@ extern int smu_feature_is_supported(struct smu_context *smu,
 extern int smu_feature_set_supported(struct smu_context *smu,
                                     enum smu_feature_mask mask, bool enable);
 
-int smu_update_table(struct smu_context *smu, uint32_t table_index,
+int smu_update_table(struct smu_context *smu, enum smu_table_id table_index, int argument,
                     void *table_data, bool drv2smu);
 
 bool is_support_sw_smu(struct amdgpu_device *adev);
@@ -973,5 +973,6 @@ int smu_set_hard_freq_range(struct smu_context *smu, enum smu_clk_type clk_type,
 enum amd_dpm_forced_level smu_get_performance_level(struct smu_context *smu);
 int smu_force_performance_level(struct smu_context *smu, enum amd_dpm_forced_level level);
 int smu_set_display_count(struct smu_context *smu, uint32_t count);
+bool smu_clk_dpm_is_enabled(struct smu_context *smu, enum smu_clk_type clk_type);
 
 #endif
index 195c4ae..755d51f 100644 (file)
@@ -27,7 +27,7 @@
 // *** IMPORTANT ***
 // SMU TEAM: Always increment the interface version if
 // any structure is changed in this file
-#define SMU11_DRIVER_IF_VERSION 0x12
+#define SMU11_DRIVER_IF_VERSION 0x13
 
 #define PPTABLE_V20_SMU_VERSION 3
 
@@ -615,6 +615,7 @@ typedef struct {
   uint16_t     UclkAverageLpfTau;
   uint16_t     GfxActivityLpfTau;
   uint16_t     UclkActivityLpfTau;
+  uint16_t     SocketPowerLpfTau;
 
 
   uint32_t     MmHubPadding[8];
@@ -665,7 +666,8 @@ typedef struct {
   uint32_t ThrottlerStatus       ;
 
   uint8_t  LinkDpmLevel;
-  uint8_t  Padding[3];
+  uint16_t AverageSocketPower;
+  uint8_t  Padding;
 
 
   uint32_t     MmHubPadding[7];
index 880fe09..2dae0ae 100644 (file)
@@ -331,7 +331,10 @@ navi10_get_allowed_feature_mask(struct smu_context *smu,
                                | FEATURE_MASK(FEATURE_DS_DCEFCLK_BIT)
                                | FEATURE_MASK(FEATURE_FW_DSTATE_BIT)
                                | FEATURE_MASK(FEATURE_BACO_BIT)
-                               | FEATURE_MASK(FEATURE_ACDC_BIT);
+                               | FEATURE_MASK(FEATURE_ACDC_BIT)
+                               | FEATURE_MASK(FEATURE_GFX_SS_BIT)
+                               | FEATURE_MASK(FEATURE_APCC_DFLL_BIT)
+                               | FEATURE_MASK(FEATURE_FW_CTF_BIT);
 
        if (adev->pm.pp_feature & PP_MCLK_DPM_MASK)
                *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_UCLK_BIT)
@@ -339,8 +342,7 @@ navi10_get_allowed_feature_mask(struct smu_context *smu,
                                | FEATURE_MASK(FEATURE_MEM_MVDD_SCALING_BIT);
 
        if (adev->pm.pp_feature & PP_GFXOFF_MASK) {
-               *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_SS_BIT)
-                               | FEATURE_MASK(FEATURE_GFXOFF_BIT);
+               *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFXOFF_BIT);
                /* TODO: remove it once fw fix the bug */
                *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_FW_DSTATE_BIT);
        }
@@ -465,9 +467,6 @@ static int navi10_append_powerplay_table(struct smu_context *smu)
        smc_pptable->MvddRatio = smc_dpm_table->MvddRatio;
 
        if (adev->pm.pp_feature & PP_GFXOFF_MASK) {
-               *(uint64_t *)smc_pptable->FeaturesToRun |= FEATURE_MASK(FEATURE_GFX_SS_BIT)
-                                       | FEATURE_MASK(FEATURE_GFXOFF_BIT);
-
                /* TODO: remove it once SMU fw fix it */
                smc_pptable->DebugOverrides |= DPM_OVERRIDE_DISABLE_DFLL_PLL_SHUTDOWN;
        }
@@ -614,7 +613,7 @@ static int navi10_get_current_clk_freq_by_table(struct smu_context *smu,
 
        memset(&metrics, 0, sizeof(metrics));
 
-       ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, (void *)&metrics, false);
+       ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0, (void *)&metrics, false);
        if (ret)
                return ret;
 
@@ -709,7 +708,7 @@ static int navi10_force_clk_levels(struct smu_context *smu,
 static int navi10_populate_umd_state_clk(struct smu_context *smu)
 {
        int ret = 0;
-       uint32_t min_sclk_freq = 0;
+       uint32_t min_sclk_freq = 0, min_mclk_freq = 0;
 
        ret = smu_get_dpm_freq_range(smu, SMU_SCLK, &min_sclk_freq, NULL);
        if (ret)
@@ -717,6 +716,12 @@ static int navi10_populate_umd_state_clk(struct smu_context *smu)
 
        smu->pstate_sclk = min_sclk_freq * 100;
 
+       ret = smu_get_dpm_freq_range(smu, SMU_MCLK, &min_mclk_freq, NULL);
+       if (ret)
+               return ret;
+
+       smu->pstate_mclk = min_mclk_freq * 100;
+
        return ret;
 }
 
@@ -827,27 +832,20 @@ static int navi10_force_dpm_limit_value(struct smu_context *smu, bool highest)
        return ret;
 }
 
-static int navi10_unforce_dpm_levels(struct smu_context *smu) {
-
+static int navi10_unforce_dpm_levels(struct smu_context *smu)
+{
        int ret = 0, i = 0;
        uint32_t min_freq, max_freq;
        enum smu_clk_type clk_type;
 
-       struct clk_feature_map {
-               enum smu_clk_type clk_type;
-               uint32_t        feature;
-       } clk_feature_map[] = {
-               {SMU_GFXCLK, SMU_FEATURE_DPM_GFXCLK_BIT},
-               {SMU_MCLK,   SMU_FEATURE_DPM_UCLK_BIT},
-               {SMU_SOCCLK, SMU_FEATURE_DPM_SOCCLK_BIT},
+       enum smu_clk_type clks[] = {
+               SMU_GFXCLK,
+               SMU_MCLK,
+               SMU_SOCCLK,
        };
 
-       for (i = 0; i < ARRAY_SIZE(clk_feature_map); i++) {
-               if (!smu_feature_is_enabled(smu, clk_feature_map[i].feature))
-                       continue;
-
-               clk_type = clk_feature_map[i].clk_type;
-
+       for (i = 0; i < ARRAY_SIZE(clks); i++) {
+               clk_type = clks[i];
                ret = smu_get_dpm_freq_range(smu, clk_type, &min_freq, &max_freq);
                if (ret)
                        return ret;
@@ -868,7 +866,7 @@ static int navi10_get_gpu_power(struct smu_context *smu, uint32_t *value)
        if (!value)
                return -EINVAL;
 
-       ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, (void *)&metrics,
+       ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0, (void *)&metrics,
                               false);
        if (ret)
                return ret;
@@ -890,7 +888,7 @@ static int navi10_get_current_activity_percent(struct smu_context *smu,
 
        msleep(1);
 
-       ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS,
+       ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0,
                               (void *)&metrics, false);
        if (ret)
                return ret;
@@ -931,7 +929,7 @@ static int navi10_get_fan_speed(struct smu_context *smu, uint16_t *value)
 
        memset(&metrics, 0, sizeof(metrics));
 
-       ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS,
+       ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0,
                               (void *)&metrics, false);
        if (ret)
                return ret;
@@ -997,7 +995,7 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
                /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
                workload_type = smu_workload_get_type(smu, i);
                result = smu_update_table(smu,
-                                         SMU_TABLE_ACTIVITY_MONITOR_COEFF | workload_type << 16,
+                                         SMU_TABLE_ACTIVITY_MONITOR_COEFF, workload_type,
                                          (void *)(&activity_monitor), false);
                if (result) {
                        pr_err("[%s] Failed to get activity monitor!", __func__);
@@ -1070,7 +1068,7 @@ static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, u
                        return -EINVAL;
 
                ret = smu_update_table(smu,
-                                      SMU_TABLE_ACTIVITY_MONITOR_COEFF | WORKLOAD_PPLIB_CUSTOM_BIT << 16,
+                                      SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
                                       (void *)(&activity_monitor), false);
                if (ret) {
                        pr_err("[%s] Failed to get activity monitor!", __func__);
@@ -1114,7 +1112,7 @@ static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, u
                }
 
                ret = smu_update_table(smu,
-                                      SMU_TABLE_ACTIVITY_MONITOR_COEFF | WORKLOAD_PPLIB_CUSTOM_BIT << 16,
+                                      SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
                                       (void *)(&activity_monitor), true);
                if (ret) {
                        pr_err("[%s] Failed to set activity monitor!", __func__);
@@ -1157,14 +1155,14 @@ static int navi10_get_profiling_clk_mask(struct smu_context *smu,
                        ret = smu_get_dpm_level_count(smu, SMU_MCLK, &level_count);
                        if (ret)
                                return ret;
-                       *sclk_mask = level_count - 1;
+                       *mclk_mask = level_count - 1;
                }
 
                if(soc_mask) {
                        ret = smu_get_dpm_level_count(smu, SMU_SOCCLK, &level_count);
                        if (ret)
                                return ret;
-                       *sclk_mask = level_count - 1;
+                       *soc_mask = level_count - 1;
                }
        }
 
@@ -1280,7 +1278,7 @@ static int navi10_thermal_get_temperature(struct smu_context *smu,
        if (!value)
                return -EINVAL;
 
-       ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, (void *)&metrics, false);
+       ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0, (void *)&metrics, false);
        if (ret)
                return ret;
 
index a87b86a..95c7c4d 100644 (file)
@@ -261,14 +261,20 @@ static int smu_v11_0_check_fw_version(struct smu_context *smu)
        smu_minor = (smu_version >> 8) & 0xff;
        smu_debug = (smu_version >> 0) & 0xff;
 
-
+       /*
+        * 1. if_version mismatch is not critical as our fw is designed
+        * to be backward compatible.
+        * 2. New fw usually brings some optimizations. But that's visible
+        * only on the paired driver.
+        * Considering above, we just leave user a warning message instead
+        * of halt driver loading.
+        */
        if (if_version != smu->smc_if_version) {
                pr_info("smu driver if version = 0x%08x, smu fw if version = 0x%08x, "
                        "smu fw version = 0x%08x (%d.%d.%d)\n",
                        smu->smc_if_version, if_version,
                        smu_version, smu_major, smu_minor, smu_debug);
-               pr_err("SMU driver if version not matched\n");
-               ret = -EINVAL;
+               pr_warn("SMU driver if version not matched\n");
        }
 
        return ret;
@@ -703,7 +709,7 @@ static int smu_v11_0_write_pptable(struct smu_context *smu)
        struct smu_table_context *table_context = &smu->smu_table;
        int ret = 0;
 
-       ret = smu_update_table(smu, SMU_TABLE_PPTABLE,
+       ret = smu_update_table(smu, SMU_TABLE_PPTABLE, 0,
                               table_context->driver_pptable, true);
 
        return ret;
@@ -722,7 +728,7 @@ static int smu_v11_0_write_watermarks_table(struct smu_context *smu)
        if (!table->cpu_addr)
                return -EINVAL;
 
-       ret = smu_update_table(smu, SMU_TABLE_WATERMARKS, table->cpu_addr,
+       ret = smu_update_table(smu, SMU_TABLE_WATERMARKS, 0, table->cpu_addr,
                                true);
 
        return ret;
index 6c81cb9..15590fd 100644 (file)
@@ -2705,8 +2705,6 @@ static int ci_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
        cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS2_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS2));
        cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_2_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_2));
 
-       memset(table, 0x00, sizeof(pp_atomctrl_mc_reg_table));
-
        result = atomctrl_initialize_mc_reg_table(hwmgr, module_index, table);
 
        if (0 == result)
index 9e0dd56..732005c 100644 (file)
@@ -2634,8 +2634,6 @@ static int iceland_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
        cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS2_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS2));
        cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_2_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_2));
 
-       memset(table, 0x00, sizeof(pp_atomctrl_mc_reg_table));
-
        result = atomctrl_initialize_mc_reg_table(hwmgr, module_index, table);
 
        if (0 == result)
index ba33943..f19bac7 100644 (file)
@@ -3117,8 +3117,6 @@ static int tonga_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
        cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_2_LP,
                        cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_2));
 
-       memset(table, 0x00, sizeof(pp_atomctrl_mc_reg_table));
-
        result = atomctrl_initialize_mc_reg_table(hwmgr, module_index, table);
 
        if (!result)
index a76a22a..bb9bb09 100644 (file)
@@ -319,7 +319,7 @@ static int vega20_tables_init(struct smu_context *smu, struct smu_table *tables)
                       AMDGPU_GEM_DOMAIN_VRAM);
 
        smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
-       if (smu_table->metrics_table)
+       if (!smu_table->metrics_table)
                return -ENOMEM;
        smu_table->metrics_time = 0;
 
@@ -441,7 +441,6 @@ static int vega20_store_powerplay_table(struct smu_context *smu)
 {
        ATOM_Vega20_POWERPLAYTABLE *powerplay_table = NULL;
        struct smu_table_context *table_context = &smu->smu_table;
-       int ret;
 
        if (!table_context->power_play_table)
                return -EINVAL;
@@ -455,9 +454,7 @@ static int vega20_store_powerplay_table(struct smu_context *smu)
        table_context->thermal_controller_type = powerplay_table->ucThermalControllerType;
        table_context->TDPODLimit = le32_to_cpu(powerplay_table->OverDrive8Table.ODSettingsMax[ATOM_VEGA20_ODSETTING_POWERPERCENTAGE]);
 
-       ret = vega20_setup_od8_information(smu);
-
-       return ret;
+       return 0;
 }
 
 static int vega20_append_powerplay_table(struct smu_context *smu)
@@ -992,7 +989,7 @@ static int vega20_print_clk_levels(struct smu_context *smu,
                break;
 
        case SMU_SOCCLK:
-               ret = smu_get_current_clk_freq(smu, PPCLK_SOCCLK, &now);
+               ret = smu_get_current_clk_freq(smu, SMU_SOCCLK, &now);
                if (ret) {
                        pr_err("Attempt to get current socclk Failed!");
                        return ret;
@@ -1013,7 +1010,7 @@ static int vega20_print_clk_levels(struct smu_context *smu,
                break;
 
        case SMU_FCLK:
-               ret = smu_get_current_clk_freq(smu, PPCLK_FCLK, &now);
+               ret = smu_get_current_clk_freq(smu, SMU_FCLK, &now);
                if (ret) {
                        pr_err("Attempt to get current fclk Failed!");
                        return ret;
@@ -1028,7 +1025,7 @@ static int vega20_print_clk_levels(struct smu_context *smu,
                break;
 
        case SMU_DCEFCLK:
-               ret = smu_get_current_clk_freq(smu, PPCLK_DCEFCLK, &now);
+               ret = smu_get_current_clk_freq(smu, SMU_DCEFCLK, &now);
                if (ret) {
                        pr_err("Attempt to get current dcefclk Failed!");
                        return ret;
@@ -1502,11 +1499,17 @@ static int vega20_set_default_od8_setttings(struct smu_context *smu)
 
        od8_settings = kzalloc(sizeof(struct vega20_od8_settings), GFP_KERNEL);
 
-       if (od8_settings)
+       if (!od8_settings)
                return -ENOMEM;
 
        smu->od_settings = (void *)od8_settings;
 
+       ret = vega20_setup_od8_information(smu);
+       if (ret) {
+               pr_err("Retrieve board OD limits failed!\n");
+               return ret;
+       }
+
        if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
                if (od8_settings->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_GFXCLK_LIMITS] &&
                    od8_settings->od_settings_max[OD8_SETTING_GFXCLK_FMAX] > 0 &&
@@ -1677,7 +1680,7 @@ static int vega20_get_metrics_table(struct smu_context *smu,
        int ret = 0;
 
        if (!smu_table->metrics_time || time_after(jiffies, smu_table->metrics_time + HZ / 1000)) {
-               ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS,
+               ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0,
                                (void *)smu_table->metrics_table, false);
                if (ret) {
                        pr_info("Failed to export SMU metrics table!\n");
@@ -1706,7 +1709,7 @@ static int vega20_set_default_od_settings(struct smu_context *smu,
                if (!table_context->overdrive_table)
                        return -ENOMEM;
 
-               ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE,
+               ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, 0,
                                       table_context->overdrive_table, false);
                if (ret) {
                        pr_err("Failed to export over drive table!\n");
@@ -1718,7 +1721,7 @@ static int vega20_set_default_od_settings(struct smu_context *smu,
                        return ret;
        }
 
-       ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE,
+       ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, 0,
                               table_context->overdrive_table, true);
        if (ret) {
                pr_err("Failed to import over drive table!\n");
@@ -1802,7 +1805,7 @@ static int vega20_get_power_profile_mode(struct smu_context *smu, char *buf)
                /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
                workload_type = smu_workload_get_type(smu, i);
                result = smu_update_table(smu,
-                                         SMU_TABLE_ACTIVITY_MONITOR_COEFF | workload_type << 16,
+                                         SMU_TABLE_ACTIVITY_MONITOR_COEFF, workload_type,
                                          (void *)(&activity_monitor), false);
                if (result) {
                        pr_err("[%s] Failed to get activity monitor!", __func__);
@@ -1888,7 +1891,7 @@ static int vega20_set_power_profile_mode(struct smu_context *smu, long *input, u
 
        if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
                ret = smu_update_table(smu,
-                                      SMU_TABLE_ACTIVITY_MONITOR_COEFF | WORKLOAD_PPLIB_CUSTOM_BIT << 16,
+                                      SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
                                       (void *)(&activity_monitor), false);
                if (ret) {
                        pr_err("[%s] Failed to get activity monitor!", __func__);
@@ -1943,7 +1946,7 @@ static int vega20_set_power_profile_mode(struct smu_context *smu, long *input, u
                }
 
                ret = smu_update_table(smu,
-                                      SMU_TABLE_ACTIVITY_MONITOR_COEFF | WORKLOAD_PPLIB_CUSTOM_BIT << 16,
+                                      SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
                                       (void *)(&activity_monitor), true);
                if (ret) {
                        pr_err("[%s] Failed to set activity monitor!", __func__);
@@ -2492,7 +2495,7 @@ static int vega20_update_od8_settings(struct smu_context *smu,
        struct smu_table_context *table_context = &smu->smu_table;
        int ret;
 
-       ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE,
+       ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, 0,
                               table_context->overdrive_table, false);
        if (ret) {
                pr_err("Failed to export over drive table!\n");
@@ -2503,7 +2506,7 @@ static int vega20_update_od8_settings(struct smu_context *smu,
        if (ret)
                return ret;
 
-       ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE,
+       ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, 0,
                               table_context->overdrive_table, true);
        if (ret) {
                pr_err("Failed to import over drive table!\n");
@@ -2767,7 +2770,7 @@ static int vega20_odn_edit_dpm_table(struct smu_context *smu,
                break;
 
        case PP_OD_RESTORE_DEFAULT_TABLE:
-               ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, table_context->overdrive_table, false);
+               ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, 0, table_context->overdrive_table, false);
                if (ret) {
                        pr_err("Failed to export over drive table!\n");
                        return ret;
@@ -2776,7 +2779,7 @@ static int vega20_odn_edit_dpm_table(struct smu_context *smu,
                break;
 
        case PP_OD_COMMIT_DPM_TABLE:
-               ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, table_context->overdrive_table, true);
+               ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, 0, table_context->overdrive_table, true);
                if (ret) {
                        pr_err("Failed to import over drive table!\n");
                        return ret;
index 3f222f4..f440078 100644 (file)
@@ -454,24 +454,6 @@ static void komeda_crtc_vblank_disable(struct drm_crtc *crtc)
        mdev->funcs->on_off_vblank(mdev, kcrtc->master->id, false);
 }
 
-static int
-komeda_crtc_atomic_get_property(struct drm_crtc *crtc,
-                               const struct drm_crtc_state *state,
-                               struct drm_property *property, uint64_t *val)
-{
-       struct komeda_crtc *kcrtc = to_kcrtc(crtc);
-       struct komeda_crtc_state *kcrtc_st = to_kcrtc_st(state);
-
-       if (property == kcrtc->clock_ratio_property) {
-               *val = kcrtc_st->clock_ratio;
-       } else {
-               DRM_DEBUG_DRIVER("Unknown property %s\n", property->name);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
 static const struct drm_crtc_funcs komeda_crtc_funcs = {
        .gamma_set              = drm_atomic_helper_legacy_gamma_set,
        .destroy                = drm_crtc_cleanup,
@@ -482,7 +464,6 @@ static const struct drm_crtc_funcs komeda_crtc_funcs = {
        .atomic_destroy_state   = komeda_crtc_atomic_destroy_state,
        .enable_vblank          = komeda_crtc_vblank_enable,
        .disable_vblank         = komeda_crtc_vblank_disable,
-       .atomic_get_property    = komeda_crtc_atomic_get_property,
 };
 
 int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms,
@@ -518,42 +499,6 @@ int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms,
        return 0;
 }
 
-static int komeda_crtc_create_clock_ratio_property(struct komeda_crtc *kcrtc)
-{
-       struct drm_crtc *crtc = &kcrtc->base;
-       struct drm_property *prop;
-
-       prop = drm_property_create_range(crtc->dev, DRM_MODE_PROP_ATOMIC,
-                                        "CLOCK_RATIO", 0, U64_MAX);
-       if (!prop)
-               return -ENOMEM;
-
-       drm_object_attach_property(&crtc->base, prop, 0);
-       kcrtc->clock_ratio_property = prop;
-
-       return 0;
-}
-
-static int komeda_crtc_create_slave_planes_property(struct komeda_crtc *kcrtc)
-{
-       struct drm_crtc *crtc = &kcrtc->base;
-       struct drm_property *prop;
-
-       if (kcrtc->slave_planes == 0)
-               return 0;
-
-       prop = drm_property_create_range(crtc->dev, DRM_MODE_PROP_IMMUTABLE,
-                                        "slave_planes", 0, U32_MAX);
-       if (!prop)
-               return -ENOMEM;
-
-       drm_object_attach_property(&crtc->base, prop, kcrtc->slave_planes);
-
-       kcrtc->slave_planes_property = prop;
-
-       return 0;
-}
-
 static struct drm_plane *
 get_crtc_primary(struct komeda_kms_dev *kms, struct komeda_crtc *crtc)
 {
@@ -590,14 +535,6 @@ static int komeda_crtc_add(struct komeda_kms_dev *kms,
 
        crtc->port = kcrtc->master->of_output_port;
 
-       err = komeda_crtc_create_clock_ratio_property(kcrtc);
-       if (err)
-               return err;
-
-       err = komeda_crtc_create_slave_planes_property(kcrtc);
-       if (err)
-               return err;
-
        return err;
 }
 
index 219fa3f..8c89fc2 100644 (file)
@@ -33,11 +33,6 @@ struct komeda_plane {
         * Layers with same capabilities.
         */
        struct komeda_layer *layer;
-
-       /** @prop_img_enhancement: for on/off image enhancement */
-       struct drm_property *prop_img_enhancement;
-       /** @prop_layer_split: for on/off layer_split */
-       struct drm_property *prop_layer_split;
 };
 
 /**
@@ -52,11 +47,8 @@ struct komeda_plane_state {
        /** @zlist_node: zorder list node */
        struct list_head zlist_node;
 
-       /* @img_enhancement: on/off image enhancement
-        * @layer_split: on/off layer_split
-        */
-       u8 img_enhancement : 1,
-          layer_split : 1;
+       /** @layer_split: on/off layer_split */
+       u8 layer_split : 1;
 };
 
 /**
@@ -94,12 +86,6 @@ struct komeda_crtc {
 
        /** @disable_done: this flip_done is for tracing the disable */
        struct completion *disable_done;
-
-       /** @clock_ratio_property: property for ratio of (aclk << 32)/pxlclk */
-       struct drm_property *clock_ratio_property;
-
-       /** @slave_planes_property: property for slaves of the planes */
-       struct drm_property *slave_planes_property;
 };
 
 /**
index fc1b861..a90bcbb 100644 (file)
@@ -537,7 +537,8 @@ void komeda_pipeline_disable(struct komeda_pipeline *pipe,
 void komeda_pipeline_update(struct komeda_pipeline *pipe,
                            struct drm_atomic_state *old_state);
 
-void komeda_complete_data_flow_cfg(struct komeda_data_flow_cfg *dflow,
+void komeda_complete_data_flow_cfg(struct komeda_layer *layer,
+                                  struct komeda_data_flow_cfg *dflow,
                                   struct drm_framebuffer *fb);
 
 #endif /* _KOMEDA_PIPELINE_H_*/
index 2b415ef..950235a 100644 (file)
@@ -784,9 +784,11 @@ komeda_timing_ctrlr_validate(struct komeda_timing_ctrlr *ctrlr,
        return 0;
 }
 
-void komeda_complete_data_flow_cfg(struct komeda_data_flow_cfg *dflow,
+void komeda_complete_data_flow_cfg(struct komeda_layer *layer,
+                                  struct komeda_data_flow_cfg *dflow,
                                   struct drm_framebuffer *fb)
 {
+       struct komeda_scaler *scaler = layer->base.pipeline->scalers[0];
        u32 w = dflow->in_w;
        u32 h = dflow->in_h;
 
@@ -803,6 +805,17 @@ void komeda_complete_data_flow_cfg(struct komeda_data_flow_cfg *dflow,
 
        dflow->en_scaling = (w != dflow->out_w) || (h != dflow->out_h);
        dflow->is_yuv = fb->format->is_yuv;
+
+       /* try to enable image enhancer if data flow is a 2x+ upscaling */
+       dflow->en_img_enhancement = dflow->out_w >= 2 * w ||
+                                   dflow->out_h >= 2 * h;
+
+       /* try to enable split if scaling exceed the scaler's acceptable
+        * input/output range.
+        */
+       if (dflow->en_scaling && scaler)
+               dflow->en_split = !in_range(&scaler->hsize, dflow->in_w) ||
+                                 !in_range(&scaler->hsize, dflow->out_w);
 }
 
 static bool merger_is_available(struct komeda_pipeline *pipe,
index 04b122f..c095af1 100644 (file)
@@ -18,7 +18,6 @@ komeda_plane_init_data_flow(struct drm_plane_state *st,
                            struct komeda_data_flow_cfg *dflow)
 {
        struct komeda_plane *kplane = to_kplane(st->plane);
-       struct komeda_plane_state *kplane_st = to_kplane_st(st);
        struct drm_framebuffer *fb = st->fb;
        const struct komeda_format_caps *caps = to_kfb(fb)->format_caps;
        struct komeda_pipeline *pipe = kplane->layer->base.pipeline;
@@ -57,10 +56,7 @@ komeda_plane_init_data_flow(struct drm_plane_state *st,
                return -EINVAL;
        }
 
-       dflow->en_img_enhancement = !!kplane_st->img_enhancement;
-       dflow->en_split = !!kplane_st->layer_split;
-
-       komeda_complete_data_flow_cfg(dflow, fb);
+       komeda_complete_data_flow_cfg(kplane->layer, dflow, fb);
 
        return 0;
 }
@@ -175,8 +171,6 @@ komeda_plane_atomic_duplicate_state(struct drm_plane *plane)
 
        old = to_kplane_st(plane->state);
 
-       new->img_enhancement = old->img_enhancement;
-
        return &new->base;
 }
 
@@ -188,44 +182,6 @@ komeda_plane_atomic_destroy_state(struct drm_plane *plane,
        kfree(to_kplane_st(state));
 }
 
-static int
-komeda_plane_atomic_get_property(struct drm_plane *plane,
-                                const struct drm_plane_state *state,
-                                struct drm_property *property,
-                                uint64_t *val)
-{
-       struct komeda_plane *kplane = to_kplane(plane);
-       struct komeda_plane_state *st = to_kplane_st(state);
-
-       if (property == kplane->prop_img_enhancement)
-               *val = st->img_enhancement;
-       else if (property == kplane->prop_layer_split)
-               *val = st->layer_split;
-       else
-               return -EINVAL;
-
-       return 0;
-}
-
-static int
-komeda_plane_atomic_set_property(struct drm_plane *plane,
-                                struct drm_plane_state *state,
-                                struct drm_property *property,
-                                uint64_t val)
-{
-       struct komeda_plane *kplane = to_kplane(plane);
-       struct komeda_plane_state *st = to_kplane_st(state);
-
-       if (property == kplane->prop_img_enhancement)
-               st->img_enhancement = !!val;
-       else if (property == kplane->prop_layer_split)
-               st->layer_split = !!val;
-       else
-               return -EINVAL;
-
-       return 0;
-}
-
 static bool
 komeda_plane_format_mod_supported(struct drm_plane *plane,
                                  u32 format, u64 modifier)
@@ -245,43 +201,9 @@ static const struct drm_plane_funcs komeda_plane_funcs = {
        .reset                  = komeda_plane_reset,
        .atomic_duplicate_state = komeda_plane_atomic_duplicate_state,
        .atomic_destroy_state   = komeda_plane_atomic_destroy_state,
-       .atomic_get_property    = komeda_plane_atomic_get_property,
-       .atomic_set_property    = komeda_plane_atomic_set_property,
        .format_mod_supported   = komeda_plane_format_mod_supported,
 };
 
-static int
-komeda_plane_create_layer_properties(struct komeda_plane *kplane,
-                                    struct komeda_layer *layer)
-{
-       struct drm_device *drm = kplane->base.dev;
-       struct drm_plane *plane = &kplane->base;
-       struct drm_property *prop = NULL;
-
-       /* property: layer image_enhancement */
-       if (layer->base.supported_outputs & KOMEDA_PIPELINE_SCALERS) {
-               prop = drm_property_create_bool(drm, DRM_MODE_PROP_ATOMIC,
-                                               "img_enhancement");
-               if (!prop)
-                       return -ENOMEM;
-
-               drm_object_attach_property(&plane->base, prop, 0);
-               kplane->prop_img_enhancement = prop;
-       }
-
-       /* property: layer split */
-       if (layer->right) {
-               prop = drm_property_create_bool(drm, DRM_MODE_PROP_ATOMIC,
-                                               "layer_split");
-               if (!prop)
-                       return -ENOMEM;
-               kplane->prop_layer_split = prop;
-               drm_object_attach_property(&plane->base, prop, 0);
-       }
-
-       return 0;
-}
-
 /* for komeda, which is pipeline can be share between crtcs */
 static u32 get_possible_crtcs(struct komeda_kms_dev *kms,
                              struct komeda_pipeline *pipe)
@@ -375,10 +297,6 @@ static int komeda_plane_add(struct komeda_kms_dev *kms,
        if (err)
                goto cleanup;
 
-       err = komeda_plane_create_layer_properties(kplane, layer);
-       if (err)
-               goto cleanup;
-
        err = drm_plane_create_color_properties(plane,
                        BIT(DRM_COLOR_YCBCR_BT601) |
                        BIT(DRM_COLOR_YCBCR_BT709) |
index bb8a61f..617e1f7 100644 (file)
@@ -13,7 +13,6 @@ komeda_wb_init_data_flow(struct komeda_layer *wb_layer,
                         struct komeda_crtc_state *kcrtc_st,
                         struct komeda_data_flow_cfg *dflow)
 {
-       struct komeda_scaler *scaler = wb_layer->base.pipeline->scalers[0];
        struct drm_framebuffer *fb = conn_st->writeback_job->fb;
 
        memset(dflow, 0, sizeof(*dflow));
@@ -28,14 +27,7 @@ komeda_wb_init_data_flow(struct komeda_layer *wb_layer,
        dflow->pixel_blend_mode = DRM_MODE_BLEND_PIXEL_NONE;
        dflow->rot = DRM_MODE_ROTATE_0;
 
-       komeda_complete_data_flow_cfg(dflow, fb);
-
-       /* if scaling exceed the acceptable scaler input/output range, try to
-        * enable split.
-        */
-       if (dflow->en_scaling && scaler)
-               dflow->en_split = !in_range(&scaler->hsize, dflow->in_w) ||
-                                 !in_range(&scaler->hsize, dflow->out_w);
+       komeda_complete_data_flow_cfg(wb_layer, dflow, fb);
 
        return 0;
 }
index cc35d49..2a65434 100644 (file)
@@ -86,7 +86,7 @@ void bochs_hw_setmode(struct bochs_device *bochs,
 void bochs_hw_setformat(struct bochs_device *bochs,
                        const struct drm_format_info *format);
 void bochs_hw_setbase(struct bochs_device *bochs,
-                     int x, int y, u64 addr);
+                     int x, int y, int stride, u64 addr);
 int bochs_hw_load_edid(struct bochs_device *bochs);
 
 /* bochs_mm.c */
index 791ab2f..ebfea87 100644 (file)
@@ -255,16 +255,22 @@ void bochs_hw_setformat(struct bochs_device *bochs,
 }
 
 void bochs_hw_setbase(struct bochs_device *bochs,
-                     int x, int y, u64 addr)
+                     int x, int y, int stride, u64 addr)
 {
-       unsigned long offset = (unsigned long)addr +
+       unsigned long offset;
+       unsigned int vx, vy, vwidth;
+
+       bochs->stride = stride;
+       offset = (unsigned long)addr +
                y * bochs->stride +
                x * (bochs->bpp / 8);
-       int vy = offset / bochs->stride;
-       int vx = (offset % bochs->stride) * 8 / bochs->bpp;
+       vy = offset / bochs->stride;
+       vx = (offset % bochs->stride) * 8 / bochs->bpp;
+       vwidth = stride * 8 / bochs->bpp;
 
        DRM_DEBUG_DRIVER("x %d, y %d, addr %llx -> offset %lx, vx %d, vy %d\n",
                         x, y, addr, offset, vx, vy);
+       bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_WIDTH, vwidth);
        bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET, vx);
        bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET, vy);
 }
index 5904edd..bc19dbd 100644 (file)
@@ -36,7 +36,8 @@ static void bochs_plane_update(struct bochs_device *bochs,
        bochs_hw_setbase(bochs,
                         state->crtc_x,
                         state->crtc_y,
-                        gbo->bo.offset);
+                        state->fb->pitches[0],
+                        state->fb->offsets[0] + gbo->bo.offset);
        bochs_hw_setformat(bochs, state->fb->format);
 }
 
index e95fcea..56d3677 100644 (file)
@@ -180,7 +180,8 @@ again:
 
 create_mode:
        mode = drm_mode_create_from_cmdline_mode(connector->dev, cmdline_mode);
-       list_add(&mode->head, &connector->modes);
+       if (mode)
+               list_add(&mode->head, &connector->modes);
 
        return mode;
 }
index 3afed56..b3f2cf7 100644 (file)
@@ -141,7 +141,7 @@ static void drm_connector_get_cmdline_mode(struct drm_connector *connector)
 
        DRM_DEBUG_KMS("cmdline mode for connector %s %s %dx%d@%dHz%s%s%s\n",
                      connector->name,
-                     mode->name ? mode->name : "",
+                     mode->name,
                      mode->xres, mode->yres,
                      mode->refresh_specified ? mode->refresh : 60,
                      mode->rb ? " reduced blanking" : "",
index fe0ce86..9d00947 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/mount.h>
+#include <linux/pseudo_fs.h>
 #include <linux/slab.h>
 #include <linux/srcu.h>
 
@@ -535,28 +536,15 @@ EXPORT_SYMBOL(drm_dev_unplug);
 static int drm_fs_cnt;
 static struct vfsmount *drm_fs_mnt;
 
-static const struct dentry_operations drm_fs_dops = {
-       .d_dname        = simple_dname,
-};
-
-static const struct super_operations drm_fs_sops = {
-       .statfs         = simple_statfs,
-};
-
-static struct dentry *drm_fs_mount(struct file_system_type *fs_type, int flags,
-                                  const char *dev_name, void *data)
+static int drm_fs_init_fs_context(struct fs_context *fc)
 {
-       return mount_pseudo(fs_type,
-                           "drm:",
-                           &drm_fs_sops,
-                           &drm_fs_dops,
-                           0x010203ff);
+       return init_pseudo(fc, 0x010203ff) ? 0 : -ENOMEM;
 }
 
 static struct file_system_type drm_fs_type = {
        .name           = "drm",
        .owner          = THIS_MODULE,
-       .mount          = drm_fs_mount,
+       .init_fs_context = drm_fs_init_fs_context,
        .kill_sb        = kill_anon_super,
 };
 
index 9441a36..bd81045 100644 (file)
@@ -736,7 +736,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
  *     };
  *
  * Please make sure that you follow all the best practices from
- * ``Documentation/ioctl/botching-up-ioctls.txt``. Note that drm_ioctl()
+ * ``Documentation/ioctl/botching-up-ioctls.rst``. Note that drm_ioctl()
  * automatically zero-extends structures, hence make sure you can add more stuff
  * at the end, i.e. don't put a variable sized array there.
  *
index 57e6408..74a5739 100644 (file)
@@ -158,6 +158,9 @@ struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay,
        int interlace;
        u64 tmp;
 
+       if (!hdisplay || !vdisplay)
+               return NULL;
+
        /* allocate the drm_display_mode structure. If failure, we will
         * return directly
         */
@@ -392,6 +395,9 @@ drm_gtf_mode_complex(struct drm_device *dev, int hdisplay, int vdisplay,
        int hsync, hfront_porch, vodd_front_porch_lines;
        unsigned int tmp1, tmp2;
 
+       if (!hdisplay || !vdisplay)
+               return NULL;
+
        drm_mode = drm_mode_create(dev);
        if (!drm_mode)
                return NULL;
@@ -1448,7 +1454,7 @@ static int drm_mode_parse_cmdline_refresh(const char *str, char **end_ptr,
 }
 
 static int drm_mode_parse_cmdline_extra(const char *str, int length,
-                                       struct drm_connector *connector,
+                                       const struct drm_connector *connector,
                                        struct drm_cmdline_mode *mode)
 {
        int i;
@@ -1493,7 +1499,7 @@ static int drm_mode_parse_cmdline_extra(const char *str, int length,
 
 static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
                                           bool extras,
-                                          struct drm_connector *connector,
+                                          const struct drm_connector *connector,
                                           struct drm_cmdline_mode *mode)
 {
        const char *str_start = str;
@@ -1555,7 +1561,7 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
 }
 
 static int drm_mode_parse_cmdline_options(char *str, size_t len,
-                                         struct drm_connector *connector,
+                                         const struct drm_connector *connector,
                                          struct drm_cmdline_mode *mode)
 {
        unsigned int rotation = 0;
@@ -1689,7 +1695,7 @@ static int drm_mode_parse_cmdline_options(char *str, size_t len,
  * True if a valid modeline has been parsed, false otherwise.
  */
 bool drm_mode_parse_command_line_for_connector(const char *mode_option,
-                                              struct drm_connector *connector,
+                                              const struct drm_connector *connector,
                                               struct drm_cmdline_mode *mode)
 {
        const char *name;
index 5318782..fcfe1a0 100644 (file)
@@ -36,7 +36,7 @@
  * of extra utility/tracking out of our acquire-ctx.  This is provided
  * by &struct drm_modeset_lock and &struct drm_modeset_acquire_ctx.
  *
- * For basic principles of &ww_mutex, see: Documentation/locking/ww-mutex-design.txt
+ * For basic principles of &ww_mutex, see: Documentation/locking/ww-mutex-design.rst
  *
  * The basic usage pattern is to::
  *
index d8a0bcd..ffd95bf 100644 (file)
@@ -90,6 +90,12 @@ static const struct drm_dmi_panel_orientation_data itworks_tw891 = {
        .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
 };
 
+static const struct drm_dmi_panel_orientation_data lcd720x1280_rightside_up = {
+       .width = 720,
+       .height = 1280,
+       .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
+};
+
 static const struct drm_dmi_panel_orientation_data lcd800x1280_rightside_up = {
        .width = 800,
        .height = 1280,
@@ -123,6 +129,12 @@ static const struct dmi_system_id orientation_data[] = {
                  DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string"),
                },
                .driver_data = (void *)&gpd_micropc,
+       }, {    /* GPD MicroPC (later BIOS versions with proper DMI strings) */
+               .matches = {
+                 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "GPD"),
+                 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "MicroPC"),
+               },
+               .driver_data = (void *)&lcd720x1280_rightside_up,
        }, {    /*
                 * GPD Pocket, note that the the DMI data is less generic then
                 * it seems, devices with a board-vendor of "AMI Corporation"
index 3d8162d..a700c5c 100644 (file)
 #define POLL_PERIOD (NSEC_PER_SEC / POLL_FREQUENCY)
 
 /* for sysctl proc_dointvec_minmax of dev.i915.perf_stream_paranoid */
-static int zero;
-static int one = 1;
 static u32 i915_perf_stream_paranoid = true;
 
 /* The maximum exponent the hardware accepts is 63 (essentially it selects one
@@ -3366,8 +3364,8 @@ static struct ctl_table oa_table[] = {
         .maxlen = sizeof(i915_perf_stream_paranoid),
         .mode = 0644,
         .proc_handler = proc_dointvec_minmax,
-        .extra1 = &zero,
-        .extra2 = &one,
+        .extra1 = SYSCTL_ZERO,
+        .extra2 = SYSCTL_ONE,
         },
        {
         .procname = "oa_max_sample_rate",
@@ -3375,7 +3373,7 @@ static struct ctl_table oa_table[] = {
         .maxlen = sizeof(i915_oa_max_sample_rate),
         .mode = 0644,
         .proc_handler = proc_dointvec_minmax,
-        .extra1 = &zero,
+        .extra1 = SYSCTL_ZERO,
         .extra2 = &oa_sample_rate_hard_limit,
         },
        {}
index b0f53f4..7a62fa0 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 ccflags-y += -I $(srctree)/$(src)/include
 ccflags-y += -I $(srctree)/$(src)/include/nvkm
 ccflags-y += -I $(srctree)/$(src)/nvkm
index 65a3990..975c4e2 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nouveau-y += dispnv04/arb.o
 nouveau-y += dispnv04/crtc.o
 nouveau-y += dispnv04/cursor.o
index ebf860b..16e09f6 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: MIT
 #include <drm/drmP.h>
 #include <drm/drm_mode.h>
 #include "nouveau_drv.h"
index c6ed20a..6ccfc09 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NV04_DISPLAY_H__
 #define __NV04_DISPLAY_H__
 #include <subdev/bios.h>
index 475c630..e0c435e 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nouveau-y += dispnv50/disp.o
 nouveau-y += dispnv50/lut.o
 
index 7ba373f..8497768 100644 (file)
@@ -322,8 +322,13 @@ nv50_outp_atomic_check_view(struct drm_encoder *encoder,
                switch (connector->connector_type) {
                case DRM_MODE_CONNECTOR_LVDS:
                case DRM_MODE_CONNECTOR_eDP:
-                       /* Force use of scaler for non-EDID modes. */
-                       if (adjusted_mode->type & DRM_MODE_TYPE_DRIVER)
+                       /* Don't force scaler for EDID modes with
+                        * same size as the native one (e.g. different
+                        * refresh rate)
+                        */
+                       if (adjusted_mode->hdisplay == native_mode->hdisplay &&
+                           adjusted_mode->vdisplay == native_mode->vdisplay &&
+                           adjusted_mode->type & DRM_MODE_TYPE_DRIVER)
                                break;
                        mode = native_mode;
                        asyc->scaler.full = true;
index 48a6485..929d93b 100644 (file)
@@ -169,14 +169,34 @@ nv50_head_atomic_check_view(struct nv50_head_atom *armh,
         */
        switch (mode) {
        case DRM_MODE_SCALE_CENTER:
-               asyh->view.oW = min((u16)umode->hdisplay, asyh->view.oW);
-               asyh->view.oH = min((u16)umode_vdisplay, asyh->view.oH);
-               /* fall-through */
+               /* NOTE: This will cause scaling when the input is
+                * larger than the output.
+                */
+               asyh->view.oW = min(asyh->view.iW, asyh->view.oW);
+               asyh->view.oH = min(asyh->view.iH, asyh->view.oH);
+               break;
        case DRM_MODE_SCALE_ASPECT:
-               if (asyh->view.oH < asyh->view.oW) {
+               /* Determine whether the scaling should be on width or on
+                * height. This is done by comparing the aspect ratios of the
+                * sizes. If the output AR is larger than input AR, that means
+                * we want to change the width (letterboxed on the
+                * left/right), otherwise on the height (letterboxed on the
+                * top/bottom).
+                *
+                * E.g. 4:3 (1.333) AR image displayed on a 16:10 (1.6) AR
+                * screen will have letterboxes on the left/right. However a
+                * 16:9 (1.777) AR image on that same screen will have
+                * letterboxes on the top/bottom.
+                *
+                * inputAR = iW / iH; outputAR = oW / oH
+                * outputAR > inputAR is equivalent to oW * iH > iW * oH
+                */
+               if (asyh->view.oW * asyh->view.iH > asyh->view.iW * asyh->view.oH) {
+                       /* Recompute output width, i.e. left/right letterbox */
                        u32 r = (asyh->view.iW << 19) / asyh->view.iH;
                        asyh->view.oW = ((asyh->view.oH * r) + (r / 2)) >> 19;
                } else {
+                       /* Recompute output height, i.e. top/bottom letterbox */
                        u32 r = (asyh->view.iH << 19) / asyh->view.iW;
                        asyh->view.oH = ((asyh->view.oW * r) + (r / 2)) >> 19;
                }
index 1a8b45b..65d432a 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_CL0002_H__
 #define __NVIF_CL0002_H__
 
index c0d5eba..d490d40 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_CL0046_H__
 #define __NVIF_CL0046_H__
 
index d0e8f35..c960c44 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_CL006B_H__
 #define __NVIF_CL006B_H__
 
index 4cbed03..cd9a2e6 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_CL0080_H__
 #define __NVIF_CL0080_H__
 
index 989690f..9df289c 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_CL506E_H__
 #define __NVIF_CL506E_H__
 
index 5137b68..327c96a 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_CL506F_H__
 #define __NVIF_CL506F_H__
 
index bced819..38bf4f3 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_CL5070_H__
 #define __NVIF_CL5070_H__
 
index 36e5372..3b2a980 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_CL507A_H__
 #define __NVIF_CL507A_H__
 
index 3e643b7..0f3d055 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_CL507B_H__
 #define __NVIF_CL507B_H__
 
index fd9e336..7da8813 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_CL507C_H__
 #define __NVIF_CL507C_H__
 
index e994c68..4a56e42 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_CL507D_H__
 #define __NVIF_CL507D_H__
 
index 8082d2f..633936c 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_CL507E_H__
 #define __NVIF_CL507E_H__
 
index 1a87509..1b6496d 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_CL826E_H__
 #define __NVIF_CL826E_H__
 
index e4e50cf..1486022 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_CL826F_H__
 #define __NVIF_CL826F_H__
 
index ab0fa8a..3823d68 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_CL906F_H__
 #define __NVIF_CL906F_H__
 
index e4c8de6..599d858 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_CL9097_H__
 #define __NVIF_CL9097_H__
 
index 81401eb..cfa18f1 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_CLA06F_H__
 #define __NVIF_CLA06F_H__
 
index 7d556a1..f704ae6 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_CLASS_H__
 #define __NVIF_CLASS_H__
 
index 6b14d7e..f668858 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_CLC36F_H__
 #define __NVIF_CLC36F_H__
 
index 89b1818..970a5ac 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_CLC37B_H__
 #define __NVIF_CLC37B_H__
 
index 899db9e..7ea2369 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_CLC37E_H__
 #define __NVIF_CLC37E_H__
 
index f5df8b3..e63c6c9 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_CLIENT_H__
 #define __NVIF_CLIENT_H__
 
index ef839bd..25d969d 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_DEVICE_H__
 #define __NVIF_DEVICE_H__
 
index 93bccd4..8e85b93 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_DRIVER_H__
 #define __NVIF_DRIVER_H__
 #include <nvif/os.h>
index ec5c924..a6b1ee4 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_EVENT_H__
 #define __NVIF_EVENT_H__
 
index 30ecd31..f7b8f8f 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_IF0000_H__
 #define __NVIF_IF0000_H__
 
index ca92152..4ced50e 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_IF0001_H__
 #define __NVIF_IF0001_H__
 
index d9235c0..df2915d 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_IF0002_H__
 #define __NVIF_IF0002_H__
 
index ae30b82..78467da 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_IF0003_H__
 #define __NVIF_IF0003_H__
 
index b35547c..d324c73 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_IF0004_H__
 #define __NVIF_IF0004_H__
 
index 8ed0ae1..fb9305b 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_IF0005_H__
 #define __NVIF_IF0005_H__
 #define NV10_NVSW_NTFY_UEVENT                                              0x00
index b93d586..886c63f 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_IOCTL_H__
 #define __NVIF_IOCTL_H__
 
index 4ed1692..6863732 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_NOTIFY_H__
 #define __NVIF_NOTIFY_H__
 
index 8407651..604fabc 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_OBJECT_H__
 #define __NVIF_OBJECT_H__
 
index fd09b28..429d010 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NOUVEAU_OS_H__
 #define __NOUVEAU_OS_H__
 
index 7f0d9f6..0584b93 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVIF_UNPACK_H__
 #define __NVIF_UNPACK_H__
 
index 757fac8..5d7017f 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_CLIENT_H__
 #define __NVKM_CLIENT_H__
 #define nvkm_client(p) container_of((p), struct nvkm_client, object)
index 966d182..b4a9c7d 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_DEBUG_H__
 #define __NVKM_DEBUG_H__
 #define NV_DBG_FATAL    0
index 6424923..6d55cd0 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_DEVICE_H__
 #define __NVKM_DEVICE_H__
 #include <core/oclass.h>
index 8a2be5b..c6b401a 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_ENGINE_H__
 #define __NVKM_ENGINE_H__
 #define nvkm_engine(p) container_of((p), struct nvkm_engine, subdev)
index 38acbde..ce98efd 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_ENUM_H__
 #define __NVKM_ENUM_H__
 #include <core/os.h>
index d3c45e9..a7a413f 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_EVENT_H__
 #define __NVKM_EVENT_H__
 #include <core/os.h>
index 54da9c6..383370c 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_FIRMWARE_H__
 #define __NVKM_FIRMWARE_H__
 #include <core/subdev.h>
index 10eeaee..0f515ec 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_GPUOBJ_H__
 #define __NVKM_GPUOBJ_H__
 #include <core/memory.h>
index e2d3919..71ed147 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_IOCTL_H__
 #define __NVKM_IOCTL_H__
 #include <core/os.h>
index f34c803..b23bf61 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_MEMORY_H__
 #define __NVKM_MEMORY_H__
 #include <core/os.h>
index b0726c3..4ecfbde 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_MM_H__
 #define __NVKM_MM_H__
 #include <core/os.h>
index 4eb82bc..3d358a6 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_NOTIFY_H__
 #define __NVKM_NOTIFY_H__
 #include <core/os.h>
index 270f893..7efcd5d 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_OBJECT_H__
 #define __NVKM_OBJECT_H__
 #include <core/oclass.h>
index d950d5e..0e70a9a 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_OPROXY_H__
 #define __NVKM_OPROXY_H__
 #define nvkm_oproxy(p) container_of((p), struct nvkm_oproxy, base)
index a34a79b..6882eb7 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_OPTION_H__
 #define __NVKM_OPTION_H__
 #include <core/os.h>
index 445602d..029a416 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_OS_H__
 #define __NVKM_OS_H__
 #include <nvif/os.h>
index 4c7f647..b4b5df3 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_DEVICE_PCI_H__
 #define __NVKM_DEVICE_PCI_H__
 #include <core/device.h>
index d5d7896..bc2d1dc 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_RAMHT_H__
 #define __NVKM_RAMHT_H__
 #include <core/gpuobj.h>
index 85a0777..1218f28 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_SUBDEV_H__
 #define __NVKM_SUBDEV_H__
 #include <core/device.h>
index 5c102d0..924009d 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_DEVICE_TEGRA_H__
 #define __NVKM_DEVICE_TEGRA_H__
 #include <core/device.h>
index 4061398..f938f02 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_BSP_H__
 #define __NVKM_BSP_H__
 #include <engine/xtensa.h>
index 5f36506..86f420f 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_CE_H__
 #define __NVKM_CE_H__
 #include <engine/falcon.h>
index 72b9da2..66c5c5e 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_CIPHER_H__
 #define __NVKM_CIPHER_H__
 #include <core/engine.h>
index 3026b22..5a96c94 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_DISP_H__
 #define __NVKM_DISP_H__
 #define nvkm_disp(p) container_of((p), struct nvkm_disp, engine)
index f0c1b2c..2e12cdb 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_DMA_H__
 #define __NVKM_DMA_H__
 #include <core/engine.h>
index 6427747..23b582d 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_FALCON_H__
 #define __NVKM_FALCON_H__
 #define nvkm_falcon(p) container_of((p), struct nvkm_falcon, engine)
index b7fc04d..b335f3a 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_FIFO_H__
 #define __NVKM_FIFO_H__
 #include <core/engine.h>
index 1e924c7..2cde36f 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_GR_H__
 #define __NVKM_GR_H__
 #include <core/engine.h>
index 4ef3d4c..8585a31 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_MPEG_H__
 #define __NVKM_MPEG_H__
 #include <core/engine.h>
index 985fc94..08fbe7b 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_MSENC_H__
 #define __NVKM_MSENC_H__
 #include <core/engine.h>
index e03f334..83bb2fc 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_MSPDEC_H__
 #define __NVKM_MSPDEC_H__
 #include <engine/falcon.h>
index 760bf17..69e09fd 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_MSPPP_H__
 #define __NVKM_MSPPP_H__
 #include <engine/falcon.h>
index 281866d..9e11cef 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_MSVLD_H__
 #define __NVKM_MSVLD_H__
 #include <engine/falcon.h>
index b72a484..7c7d7f0 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_NVDEC_H__
 #define __NVKM_NVDEC_H__
 #define nvkm_nvdec(p) container_of((p), struct nvkm_nvdec, engine)
index cdd68a8..2162404 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_NVENC_H__
 #define __NVKM_NVENC_H__
 #include <core/engine.h>
index 6cce850..4d754e7 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_PM_H__
 #define __NVKM_PM_H__
 #include <core/engine.h>
index b206b91..f14e98a 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_SEC_H__
 #define __NVKM_SEC_H__
 #include <engine/falcon.h>
index c93ad33..33078f8 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_SEC2_H__
 #define __NVKM_SEC2_H__
 #include <core/engine.h>
index 83a17c4..2e91769 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_SW_H__
 #define __NVKM_SW_H__
 #include <core/engine.h>
index 9b7d487..35555c5 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_VIC_H__
 #define __NVKM_VIC_H__
 #include <core/engine.h>
index 53bf8ae..8984415 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_VP_H__
 #define __NVKM_VP_H__
 #include <engine/xtensa.h>
index 13c00ce..fbf27b2 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_XTENSA_H__
 #define __NVKM_XTENSA_H__
 #define nvkm_xtensa(p) container_of((p), struct nvkm_xtensa, engine)
index da14486..14b09f7 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_BAR_H__
 #define __NVKM_BAR_H__
 #include <core/subdev.h>
index 979e9a1..f2860f8 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_BIOS_H__
 #define __NVKM_BIOS_H__
 #include <core/subdev.h>
index 425ccc4..9227ed6 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_M0203_H__
 #define __NVBIOS_M0203_H__
 struct nvbios_M0203T {
index b4e14e4..7ec1dab 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_M0205_H__
 #define __NVBIOS_M0205_H__
 struct nvbios_M0205T {
index c093768..49a7bb0 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_M0209_H__
 #define __NVBIOS_M0209_H__
 u32 nvbios_M0209Te(struct nvkm_bios *,
index 901d94e..caad725 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_P0260_H__
 #define __NVBIOS_P0260_H__
 u32 nvbios_P0260Te(struct nvkm_bios *,
index d068586..ebfe45f 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_BIT_H__
 #define __NVBIOS_BIT_H__
 struct bit_entry {
index 9a3f948..263408a 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_BMP_H__
 #define __NVBIOS_BMP_H__
 static inline u16
index a1c48c6..489fd35 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_BOOST_H__
 #define __NVBIOS_BOOST_H__
 u32 nvbios_boostTe(struct nvkm_bios *, u8 *, u8 *, u8 *, u8 *, u8 *, u8 *);
index 8463b42..f5f5926 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_CONN_H__
 #define __NVBIOS_CONN_H__
 enum dcb_connector_type {
index 49343d2..6a287a0 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_CSTEP_H__
 #define __NVBIOS_CSTEP_H__
 u32 nvbios_cstepTe(struct nvkm_bios *,
index 63ddc6e..a27a0f3 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_DCB_H__
 #define __NVBIOS_DCB_H__
 enum dcb_output_type {
index 423d92d..ef44205 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_DISP_H__
 #define __NVBIOS_DISP_H__
 u16 nvbios_disp_table(struct nvkm_bios *,
index 512e25a..1df5e16 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_DP_H__
 #define __NVBIOS_DP_H__
 
index f93e4f9..f29f2d8 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_EXTDEV_H__
 #define __NVBIOS_EXTDEV_H__
 enum nvbios_extdev_type {
index 09c1d3b..8b3fb1f 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_FAN_H__
 #define __NVBIOS_FAN_H__
 #include <subdev/bios/therm.h>
index b71a355..7c4f003 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_GPIO_H__
 #define __NVBIOS_GPIO_H__
 enum dcb_gpio_func_name {
index ae1f748..e84a0eb 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_I2C_H__
 #define __NVBIOS_I2C_H__
 enum dcb_i2c_type {
index e220a1a..4c108fd 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_ICCSENSE_H__
 #define __NVBIOS_ICCSENSE_H__
 struct pwr_rail_resistor_t {
index 893288b..e13dc05 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_IMAGE_H__
 #define __NVBIOS_IMAGE_H__
 struct nvbios_image {
index 744b186..10df021 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_INIT_H__
 #define __NVBIOS_INIT_H__
 
index 327bf9c..7204c6f 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_MXM_H__
 #define __NVBIOS_MXM_H__
 u16 mxm_table(struct nvkm_bios *, u8 *ver, u8 *hdr);
index ee5419b..f10f176 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_NPDE_H__
 #define __NVBIOS_NPDE_H__
 struct nvbios_npdeT {
index 1dffe8d..bb7bf67 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_PCIR_H__
 #define __NVBIOS_PCIR_H__
 struct nvbios_pcirT {
index 0ee84ea..1b67c09 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_PERF_H__
 #define __NVBIOS_PERF_H__
 u32 nvbios_perf_table(struct nvkm_bios *, u8 *ver, u8 *hdr,
index ab964e0..b2c2d09 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_PLL_H__
 #define __NVBIOS_PLL_H__
 /*XXX: kill me */
index fb41eca..7177d39 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_PMU_H__
 #define __NVBIOS_PMU_H__
 struct nvbios_pmuT {
index ff12d81..95306be 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_POWER_BUDGET_H__
 #define __NVBIOS_POWER_BUDGET_H__
 
index 2b87a38..153edf8 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_RAMCFG_H__
 #define __NVBIOS_RAMCFG_H__
 struct nvbios_ramcfg {
index 471eef4..7f05404 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_RAMMAP_H__
 #define __NVBIOS_RAMMAP_H__
 #include <subdev/bios/ramcfg.h>
index 46a3b15..0fb8a34 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_THERM_H__
 #define __NVBIOS_THERM_H__
 struct nvbios_therm_threshold {
index 40ceabf..c1f7777 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_TIMING_H__
 #define __NVBIOS_TIMING_H__
 #include <subdev/bios/ramcfg.h>
index 67419ba..13103b9 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_VMAP_H__
 #define __NVBIOS_VMAP_H__
 struct nvbios_vmap {
index 6b36d5e..0c9be1b 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_VOLT_H__
 #define __NVBIOS_VOLT_H__
 
index 36f3028..df94e26 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_VPSTATE_H__
 #define __NVBIOS_VPSTATE_H__
 struct nvbios_vpstate_header {
index d1bb5d0..11b4c4d 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVBIOS_XPIO_H__
 #define __NVBIOS_XPIO_H__
 
index 7695f7f..ae9ad6c 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_BUS_H__
 #define __NVKM_BUS_H__
 #include <core/subdev.h>
index 15db75e..bf937e7 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_CLK_H__
 #define __NVKM_CLK_H__
 #include <core/subdev.h>
index 8ba982c..1a39e52 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_DEVINIT_H__
 #define __NVKM_DEVINIT_H__
 #include <core/subdev.h>
index 27298f8..239ad22 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_FB_H__
 #define __NVKM_FB_H__
 #include <core/subdev.h>
index 092193b..00111c3 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_FUSE_H__
 #define __NVKM_FUSE_H__
 #include <core/subdev.h>
index ee54899..eaacf8d 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_GPIO_H__
 #define __NVKM_GPIO_H__
 #include <core/subdev.h>
index 7957eaf..81b9773 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_I2C_H__
 #define __NVKM_I2C_H__
 #include <core/subdev.h>
index 919653c..db79141 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_IBUS_H__
 #define __NVKM_IBUS_H__
 #include <core/subdev.h>
index be9475c..f483dcd 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_ICCSENSE_H__
 #define __NVKM_ICCSENSE_H__
 
index 36ed520..c74ab7c 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_INSTMEM_H__
 #define __NVKM_INSTMEM_H__
 #include <core/subdev.h>
index 9db5f82..644d527 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_LTC_H__
 #define __NVKM_LTC_H__
 #include <core/subdev.h>
index e38f495..6641fe4 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_MC_H__
 #define __NVKM_MC_H__
 #include <core/subdev.h>
index 28ade86..54cdcb0 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_MMU_H__
 #define __NVKM_MMU_H__
 #include <core/subdev.h>
index 0fd6d6f..78df1e9 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_MXM_H__
 #define __NVKM_MXM_H__
 #include <core/subdev.h>
index 23803cc..4803a4f 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_PCI_H__
 #define __NVKM_PCI_H__
 #include <core/subdev.h>
index 4bc9384..24fbccc 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_PMU_H__
 #define __NVKM_PMU_H__
 #include <core/subdev.h>
index 9398d9f..62c34f9 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_THERM_H__
 #define __NVKM_THERM_H__
 #include <core/subdev.h>
index 3693ebf..a8c21c6 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_TIMER_H__
 #define __NVKM_TIMER_H__
 #include <core/subdev.h>
index 2904e67..7be0e7e 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_TOP_H__
 #define __NVKM_TOP_H__
 #include <core/subdev.h>
index 312933a..15ee5c3 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NOUVEAU_VGA_H__
 #define __NOUVEAU_VGA_H__
 #include <core/subdev.h>
index 6a76568..45053a2 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_VOLT_H__
 #define __NVKM_VOLT_H__
 #include <core/subdev.h>
index 36fde1f..1955467 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NOUVEAU_ABI16_H__
 #define __NOUVEAU_ABI16_H__
 
index ffb1958..fe3a102 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: MIT
 #include <linux/pci.h>
 #include <linux/acpi.h>
 #include <linux/slab.h>
index b86294f..1e6e8a8 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NOUVEAU_ACPI_H__
 #define __NOUVEAU_ACPI_H__
 
index 846f4bd..383ac36 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NOUVEAU_BO_H__
 #define __NOUVEAU_BO_H__
 
index 93814d1..9307357 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NOUVEAU_CHAN_H__
 #define __NOUVEAU_CHAN_H__
 #include <nvif/object.h>
index 4116ee6..8f15281 100644 (file)
@@ -252,7 +252,7 @@ nouveau_conn_reset(struct drm_connector *connector)
                return;
 
        if (connector->state)
-               __drm_atomic_helper_connector_destroy_state(connector->state);
+               nouveau_conn_atomic_destroy_state(connector, connector->state);
        __drm_atomic_helper_connector_reset(connector, &asyc->state);
        asyc->dither.mode = DITHERING_MODE_AUTO;
        asyc->dither.depth = DITHERING_DEPTH_AUTO;
@@ -978,11 +978,13 @@ get_tmds_link_bandwidth(struct drm_connector *connector)
        struct nouveau_drm *drm = nouveau_drm(connector->dev);
        struct dcb_output *dcb = nv_connector->detected_encoder->dcb;
        struct drm_display_info *info = NULL;
-       const unsigned duallink_scale =
+       unsigned duallink_scale =
                nouveau_duallink && nv_encoder->dcb->duallink_possible ? 2 : 1;
 
-       if (drm_detect_hdmi_monitor(nv_connector->edid))
+       if (drm_detect_hdmi_monitor(nv_connector->edid)) {
                info = &nv_connector->base.display_info;
+               duallink_scale = 1;
+       }
 
        if (info) {
                if (nouveau_hdmimhz > 0)
@@ -1003,6 +1005,7 @@ get_tmds_link_bandwidth(struct drm_connector *connector)
                if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_FERMI)
                        return 225000;
        }
+
        if (dcb->location != DCB_LOC_ON_CHIP ||
            drm->client.device.info.chipset >= 0x46)
                return 165000 * duallink_scale;
index 1d01a82..9420a6a 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NOUVEAU_DEBUGFS_H__
 #define __NOUVEAU_DEBUGFS_H__
 
index 311e175..9185f01 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NOUVEAU_DISPLAY_H__
 #define __NOUVEAU_DISPLAY_H__
 #include "nouveau_drv.h"
index 42c0260..1333220 100644 (file)
@@ -379,9 +379,10 @@ nouveau_dmem_pages_alloc(struct nouveau_drm *drm,
                        ret = nouveau_dmem_chunk_alloc(drm);
                        if (ret) {
                                if (c)
-                                       break;
+                                       return 0;
                                return ret;
                        }
+                       mutex_lock(&drm->dmem->mutex);
                        continue;
                }
 
index 35ff0ca..aae0358 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NOUVEAU_DRV_H__
 #define __NOUVEAU_DRV_H__
 
index ad27cae..c9e24ba 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NOUVEAU_FENCE_H__
 #define __NOUVEAU_FENCE_H__
 
index fe39998..0337120 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NOUVEAU_GEM_H__
 #define __NOUVEAU_GEM_H__
 
index 08a1ab6..6af2d29 100644 (file)
@@ -428,6 +428,8 @@ nouveau_temp_read(struct device *dev, u32 attr, int channel, long *val)
 
        switch (attr) {
        case hwmon_temp_input:
+               if (drm_dev->switch_power_state != DRM_SWITCH_POWER_ON)
+                       return -EINVAL;
                ret = nvkm_therm_temp_get(therm);
                *val = ret < 0 ? ret : (ret * 1000);
                break;
@@ -474,6 +476,8 @@ nouveau_fan_read(struct device *dev, u32 attr, int channel, long *val)
 
        switch (attr) {
        case hwmon_fan_input:
+               if (drm_dev->switch_power_state != DRM_SWITCH_POWER_ON)
+                       return -EINVAL;
                *val = nvkm_therm_fan_sense(therm);
                break;
        default:
@@ -496,6 +500,8 @@ nouveau_in_read(struct device *dev, u32 attr, int channel, long *val)
 
        switch (attr) {
        case hwmon_in_input:
+               if (drm_dev->switch_power_state != DRM_SWITCH_POWER_ON)
+                       return -EINVAL;
                ret = nvkm_volt_get(volt);
                *val = ret < 0 ? ret : (ret / 1000);
                break;
@@ -527,6 +533,8 @@ nouveau_pwm_read(struct device *dev, u32 attr, int channel, long *val)
                *val = therm->attr_get(therm, NVKM_THERM_ATTR_FAN_MODE);
                break;
        case hwmon_pwm_input:
+               if (drm_dev->switch_power_state != DRM_SWITCH_POWER_ON)
+                       return -EINVAL;
                *val = therm->fan_get(therm);
                break;
        default:
@@ -548,6 +556,8 @@ nouveau_power_read(struct device *dev, u32 attr, int channel, long *val)
 
        switch (attr) {
        case hwmon_power_input:
+               if (drm_dev->switch_power_state != DRM_SWITCH_POWER_ON)
+                       return -EINVAL;
                *val = nvkm_iccsense_read_all(iccsense);
                break;
        case hwmon_power_max:
index 380ede2..d175055 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NOUVEAU_IOCTL_H__
 #define __NOUVEAU_IOCTL_H__
 
index b5b5fe4..cff7389 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 
 #define NV04_PFB_BOOT_0                                                0x00100000
 #      define NV04_PFB_BOOT_0_RAM_AMOUNT                       0x00000003
index 8ebdc74..feaac90 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: MIT
 #include <linux/pagemap.h>
 #include <linux/slab.h>
 
index 89929ad..0852807 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NOUVEAU_TTM_H__
 #define __NOUVEAU_TTM_H__
 
index c68f1c6..dc90d4a 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NOUVEAU_USIF_H__
 #define __NOUVEAU_USIF_H__
 
index 8f1ce48..8f4b12a 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: MIT
 #include <linux/vgaarb.h>
 #include <linux/vga_switcheroo.h>
 
index 6a3000c..951a83f 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NOUVEAU_VGA_H__
 #define __NOUVEAU_VGA_H__
 
index 7616c66..300cf3f 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NV10_FENCE_H_
 #define __NV10_FENCE_H_
 
index 7eebd7d..50d583d 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvif-y := nvif/object.o
 nvif-y += nvif/client.o
 nvif-y += nvif/device.o
index a8ec75c..b53de9b 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 include $(src)/nvkm/core/Kbuild
 include $(src)/nvkm/falcon/Kbuild
 include $(src)/nvkm/subdev/Kbuild
index 01de221..2b471ab 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y := nvkm/core/client.o
 nvkm-y += nvkm/core/engine.o
 nvkm-y += nvkm/core/enum.o
index 5a43bcf..c6dfed1 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/engine/falcon.o
 nvkm-y += nvkm/engine/xtensa.o
 
index ad1bcfa..b596b99 100644 (file)
@@ -1,2 +1,2 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/engine/bsp/g84.o
index 157a707..ba88613 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/engine/ce/gt215.o
 nvkm-y += nvkm/engine/ce/gf100.o
 nvkm-y += nvkm/engine/ce/gk104.o
index da130f5..96d934f 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 static uint32_t gf100_ce_data[] = {
 /* 0x0000: ctx_object */
        0x00000000,
index 0b92eb3..d3fbd4a 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 static uint32_t gt215_ce_data[] = {
 /* 0x0000: ctx_object */
        0x00000000,
index 0e3d08f..b0c8342 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_CE_PRIV_H__
 #define __NVKM_CE_PRIV_H__
 #include <engine/ce.h>
index 95708b5..ffad341 100644 (file)
@@ -1,2 +1,2 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/engine/cipher/g84.o
index 206163d..293c576 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/engine/device/acpi.o
 nvkm-y += nvkm/engine/device/base.o
 nvkm-y += nvkm/engine/device/ctrl.o
index 6a62021..1d3c5cf 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_DEVICE_ACPI_H__
 #define __NVKM_DEVICE_ACPI_H__
 #include <core/os.h>
index 10d91e8..c3c7159 100644 (file)
@@ -1316,7 +1316,7 @@ nvaf_chipset = {
        .i2c = g94_i2c_new,
        .imem = nv50_instmem_new,
        .mc = gt215_mc_new,
-       .mmu = g84_mmu_new,
+       .mmu = mcp77_mmu_new,
        .mxm = nv50_mxm_new,
        .pci = g94_pci_new,
        .pmu = gt215_pmu_new,
@@ -2575,6 +2575,41 @@ nv167_chipset = {
        .sec2 = tu102_sec2_new,
 };
 
+static const struct nvkm_device_chip
+nv168_chipset = {
+       .name = "TU116",
+       .bar = tu102_bar_new,
+       .bios = nvkm_bios_new,
+       .bus = gf100_bus_new,
+       .devinit = tu102_devinit_new,
+       .fault = tu102_fault_new,
+       .fb = gv100_fb_new,
+       .fuse = gm107_fuse_new,
+       .gpio = gk104_gpio_new,
+       .gsp = gv100_gsp_new,
+       .i2c = gm200_i2c_new,
+       .ibus = gm200_ibus_new,
+       .imem = nv50_instmem_new,
+       .ltc = gp102_ltc_new,
+       .mc = tu102_mc_new,
+       .mmu = tu102_mmu_new,
+       .pci = gp100_pci_new,
+       .pmu = gp102_pmu_new,
+       .therm = gp100_therm_new,
+       .timer = gk20a_timer_new,
+       .top = gk104_top_new,
+       .ce[0] = tu102_ce_new,
+       .ce[1] = tu102_ce_new,
+       .ce[2] = tu102_ce_new,
+       .ce[3] = tu102_ce_new,
+       .ce[4] = tu102_ce_new,
+       .disp = tu102_disp_new,
+       .dma = gv100_dma_new,
+       .fifo = tu102_fifo_new,
+       .nvdec[0] = gp102_nvdec_new,
+       .sec2 = tu102_sec2_new,
+};
+
 static int
 nvkm_device_event_ctor(struct nvkm_object *object, void *data, u32 size,
                       struct nvkm_notify *notify)
@@ -3052,6 +3087,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
                case 0x164: device->chip = &nv164_chipset; break;
                case 0x166: device->chip = &nv166_chipset; break;
                case 0x167: device->chip = &nv167_chipset; break;
+               case 0x168: device->chip = &nv168_chipset; break;
                default:
                        nvdev_error(device, "unknown chipset (%08x)\n", boot0);
                        goto done;
index ebcc5c5..9f6d7f2 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_DEVICE_CTRL_H__
 #define __NVKM_DEVICE_CTRL_H__
 #define nvkm_control(p) container_of((p), struct nvkm_control, object)
index 2a53e37..d8be2f7 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_DEVICE_PRIV_H__
 #define __NVKM_DEVICE_PRIV_H__
 #include <core/device.h>
index dbfda73..0d584d0 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/engine/disp/base.o
 nvkm-y += nvkm/engine/disp/nv04.o
 nvkm-y += nvkm/engine/disp/nv50.o
index adc9d76..e55054b 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NV50_DISP_CHAN_H__
 #define __NV50_DISP_CHAN_H__
 #define nv50_disp_chan(p) container_of((p), struct nv50_disp_chan, object)
index 090e869..dcbe60a 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_DISP_CONN_H__
 #define __NVKM_DISP_CONN_H__
 #include <engine/disp.h>
index 495f665..428b3f4 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_DISP_DP_H__
 #define __NVKM_DISP_DP_H__
 #define nvkm_dp(p) container_of((p), struct nvkm_dp, outp)
index 10f2aa9..7147dc6 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: MIT
 #include "hdmi.h"
 
 void pack_hdmi_infoframe(struct packed_hdmi_infoframe *packed_frame,
index 45094c6..fb1c3e3 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_DISP_HDMI_H__
 #define __NVKM_DISP_HDMI_H__
 #include "ior.h"
index 7d55faf..7dde623 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_DISP_HEAD_H__
 #define __NVKM_DISP_HEAD_H__
 #include "priv.h"
index 1681ddc..009d3a8 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_DISP_IOR_H__
 #define __NVKM_DISP_IOR_H__
 #include "priv.h"
index e5d00f4..a677161 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NV50_DISP_H__
 #define __NV50_DISP_H__
 #define nv50_disp(p) container_of((p), struct nv50_disp, base)
index 6c8aa5c..721b068 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_DISP_OUTP_H__
 #define __NVKM_DISP_OUTP_H__
 #include <engine/disp.h>
index ef66c5f..f815a53 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_DISP_PRIV_H__
 #define __NVKM_DISP_PRIV_H__
 #include <engine/disp.h>
index aee9822..a1f9427 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NV50_DISP_ROOT_H__
 #define __NV50_DISP_ROOT_H__
 #define nv50_disp_root(p) container_of((p), struct nv50_disp_root, object)
index d57b73a..4d5f379 100644 (file)
@@ -72,6 +72,7 @@ tu102_sor = {
        .clock = gf119_sor_clock,
        .hdmi = {
                .ctrl = gv100_hdmi_ctrl,
+               .scdc = gm200_hdmi_scdc,
        },
        .dp = {
                .lanes = { 0, 1, 2, 3 },
index 3e2680c..a0e551b 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/engine/dma/base.o
 nvkm-y += nvkm/engine/dma/nv04.o
 nvkm-y += nvkm/engine/dma/nv50.o
index 4307cbe..0c9d964 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_DMA_PRIV_H__
 #define __NVKM_DMA_PRIV_H__
 #define nvkm_dma(p) container_of((p), struct nvkm_dma, engine)
index 9fe01fd..9c72ee2 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_DMA_USER_H__
 #define __NVKM_DMA_USER_H__
 #define nvkm_dmaobj(p) container_of((p), struct nvkm_dmaobj, object)
index 1f0edda..90e9a09 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/engine/fifo/base.o
 nvkm-y += nvkm/engine/fifo/nv04.o
 nvkm-y += nvkm/engine/fifo/nv10.o
index 2c7c5af..177e105 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_FIFO_CHAN_H__
 #define __NVKM_FIFO_CHAN_H__
 #define nvkm_fifo_chan(p) container_of((p), struct nvkm_fifo_chan, object)
index b653664..7c125a1 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __GF100_FIFO_CHAN_H__
 #define __GF100_FIFO_CHAN_H__
 #define gf100_fifo_chan(p) container_of((p), struct gf100_fifo_chan, base)
index f8557cd..2269866 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __GK104_FIFO_CHAN_H__
 #define __GK104_FIFO_CHAN_H__
 #define gk104_fifo_chan(p) container_of((p), struct gk104_fifo_chan, base)
index 15b06bd..60ca794 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NV04_FIFO_CHAN_H__
 #define __NV04_FIFO_CHAN_H__
 #define nv04_fifo_chan(p) container_of((p), struct nv04_fifo_chan, base)
index 2e3c400..5735ff7 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NV50_FIFO_CHAN_H__
 #define __NV50_FIFO_CHAN_H__
 #define nv50_fifo_chan(p) container_of((p), struct nv50_fifo_chan, base)
index 68f97ba..b864249 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __GF100_FIFO_H__
 #define __GF100_FIFO_H__
 #define gf100_fifo(p) container_of((p), struct gf100_fifo, base)
index d4e5656..c33f459 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __GK104_FIFO_H__
 #define __GK104_FIFO_H__
 #define gk104_fifo(p) container_of((p), struct gk104_fifo, base)
index 1d70542..e5eccee 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NV04_FIFO_H__
 #define __NV04_FIFO_H__
 #define nv04_fifo(p) container_of((p), struct nv04_fifo, base)
index a3994e8..87d30b6 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NV50_FIFO_H__
 #define __NV50_FIFO_H__
 #define nv50_fifo(p) container_of((p), struct nv50_fifo, base)
index d5acbba..c66f537 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_FIFO_PRIV_H__
 #define __NVKM_FIFO_PRIV_H__
 #define nvkm_fifo(p) container_of((p), struct nvkm_fifo, engine)
index 49892a5..4445a12 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NV04_FIFO_REGS_H__
 #define __NV04_FIFO_REGS_H__
 
index 50bd983..73724a8 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/engine/gr/base.o
 nvkm-y += nvkm/engine/gr/nv04.o
 nvkm-y += nvkm/engine/gr/nv10.o
index 33e932b..478b472 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_GRCTX_NVC0_H__
 #define __NVKM_GRCTX_NVC0_H__
 #include "gf100.h"
index 4d67d90..7917567 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_GRCTX_H__
 #define __NVKM_GRCTX_H__
 #include <core/gpuobj.h>
index 0323acb..54e14b4 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 static uint32_t gf100_grgpc_data[] = {
 /* 0x0000: gpc_mmio_list_head */
        0x00000064,
index 1bb2659..67524e6 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 static uint32_t gf117_grgpc_data[] = {
 /* 0x0000: gpc_mmio_list_head */
        0x0000006c,
index cf8343a..60c8b7e 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 static uint32_t gk104_grgpc_data[] = {
 /* 0x0000: gpc_mmio_list_head */
        0x0000006c,
index f4bfa10..c99d156 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 static uint32_t gk110_grgpc_data[] = {
 /* 0x0000: gpc_mmio_list_head */
        0x0000006c,
index 59a3e1b..753aa66 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 static uint32_t gk208_grgpc_data[] = {
 /* 0x0000: gpc_mmio_list_head */
        0x0000006c,
index 8daa051..db8b294 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 static uint32_t gm107_grgpc_data[] = {
 /* 0x0000: gpc_mmio_list_head */
        0x0000006c,
index cbf2351..56162f6 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 static uint32_t gf100_grhub_data[] = {
 /* 0x0000: hub_mmio_list_head */
        0x00000300,
index 7083003..9b9f0d9 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 static uint32_t gf117_grhub_data[] = {
 /* 0x0000: hub_mmio_list_head */
        0x00000300,
index 7f2fd84..fa11857 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 static uint32_t gk104_grhub_data[] = {
 /* 0x0000: hub_mmio_list_head */
        0x00000300,
index 5600637..1d741b3 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 static uint32_t gk110_grhub_data[] = {
 /* 0x0000: hub_mmio_list_head */
        0x00000300,
index 71e8578..c24f35a 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 static uint32_t gk208_grhub_data[] = {
 /* 0x0000: hub_mmio_list_head */
        0x00000300,
index d85eac6..649a442 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 static uint32_t gm107_grhub_data[] = {
 /* 0x0000: hub_mmio_list_head */
        0x00000300,
index f876938..6ac155b 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_GRAPH_OS_H__
 #define __NVKM_GRAPH_OS_H__
 
index d5a376c..4327bae 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NV10_GR_H__
 #define __NV10_GR_H__
 #include "priv.h"
index 111c8bb..d837630 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: MIT
 #include "nv20.h"
 #include "regs.h"
 
index 979dc5f..e57407a 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NV20_GR_H__
 #define __NV20_GR_H__
 #define nv20_gr(p) container_of((p), struct nv20_gr, base)
index e59a28a..32d29d3 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: MIT
 #include "nv20.h"
 #include "regs.h"
 
index e113b2d..f941062 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: MIT
 #include "nv20.h"
 #include "regs.h"
 
index 4aac2c2..785ec95 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: MIT
 #include "nv20.h"
 #include "regs.h"
 
index 3015565..bd610d7 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: MIT
 #include "nv20.h"
 #include "regs.h"
 
index 5d69266..89db7f5 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: MIT
 #include "nv20.h"
 #include "regs.h"
 
index 7314009..e612879 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NV40_GR_H__
 #define __NV40_GR_H__
 #define nv40_gr(p) container_of((p), struct nv40_gr, base)
index 5b9d99b..465f4da 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NV50_GR_H__
 #define __NV50_GR_H__
 #define nv50_gr(p) container_of((p), struct nv50_gr, base)
index d4d5601..3b30f24 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_GR_PRIV_H__
 #define __NVKM_GR_PRIV_H__
 #define nvkm_gr(p) container_of((p), struct nvkm_gr, engine)
index dc4f936..fd1b7d3 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_GR_REGS_H__
 #define __NVKM_GR_REGS_H__
 
index 6512701..8d2d9ea 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/engine/mpeg/nv31.o
 nvkm-y += nvkm/engine/mpeg/nv40.o
 nvkm-y += nvkm/engine/mpeg/nv44.o
index b31fad8..b3e1315 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NV31_MPEG_H__
 #define __NV31_MPEG_H__
 #define nv31_mpeg(p) container_of((p), struct nv31_mpeg, engine)
index 26f9d14..667a2d0 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_MPEG_PRIV_H__
 #define __NVKM_MPEG_PRIV_H__
 #include <engine/mpeg.h>
index b808d9e..4bf033f 100644 (file)
@@ -1,2 +1,2 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 #nvkm-y += nvkm/engine/msenc/base.o
index df50010..0cd957d 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/engine/mspdec/base.o
 nvkm-y += nvkm/engine/mspdec/g98.o
 nvkm-y += nvkm/engine/mspdec/gt215.o
index db30507..86445a2 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_MSPDEC_PRIV_H__
 #define __NVKM_MSPDEC_PRIV_H__
 #include <engine/mspdec.h>
index 322e347..788ce72 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/engine/msppp/base.o
 nvkm-y += nvkm/engine/msppp/g98.o
 nvkm-y += nvkm/engine/msppp/gt215.o
index 7708e52..f20b109 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_MSPPP_PRIV_H__
 #define __NVKM_MSPPP_PRIV_H__
 #include <engine/msppp.h>
index beddd82..d68b443 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/engine/msvld/base.o
 nvkm-y += nvkm/engine/msvld/g98.o
 nvkm-y += nvkm/engine/msvld/gt215.o
index 66c3604..5cd1e83 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_MSVLD_PRIV_H__
 #define __NVKM_MSVLD_PRIV_H__
 #include <engine/msvld.h>
index 29d7ddb..cdf6318 100644 (file)
@@ -1,3 +1,3 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/engine/nvdec/base.o
 nvkm-y += nvkm/engine/nvdec/gp102.o
index 6c30073..57bfa3a 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_NVDEC_PRIV_H__
 #define __NVKM_NVDEC_PRIV_H__
 #include <engine/nvdec.h>
index 85725b1..f316de8 100644 (file)
@@ -1,2 +1,2 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 #nvkm-y += nvkm/engine/nvenc/base.o
index ceb7302..2cc8a5f 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/engine/pm/base.o
 nvkm-y += nvkm/engine/pm/nv40.o
 nvkm-y += nvkm/engine/pm/nv50.o
index c74fd45..461bb21 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_PM_NVC0_H__
 #define __NVKM_PM_NVC0_H__
 #include "priv.h"
index 3f37b71..8ed1932 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_PM_NV40_H__
 #define __NVKM_PM_NV40_H__
 #define nv40_pm(p) container_of((p), struct nv40_pm, base)
index 9fad361..cd6f8f7 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_PM_PRIV_H__
 #define __NVKM_PM_PRIV_H__
 #define nvkm_pm(p) container_of((p), struct nvkm_pm, engine)
index f72ee55..b6e02ce 100644 (file)
@@ -1,2 +1,2 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/engine/sec/g98.o
index 6278a0c..fe90f2e 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 static uint32_t g98_sec_data[] = {
 /* 0x0000: ctx_dma */
 /* 0x0000: ctx_dma_query */
index 9a2f4f6..97c4696 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/engine/sec2/base.o
 nvkm-y += nvkm/engine/sec2/gp102.o
 nvkm-y += nvkm/engine/sec2/tu102.o
index ab0165e..b331b00 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_SEC2_PRIV_H__
 #define __NVKM_SEC2_PRIV_H__
 #include <engine/sec2.h>
index 91cf080..94fe259 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/engine/sw/base.o
 nvkm-y += nvkm/engine/sw/nv04.o
 nvkm-y += nvkm/engine/sw/nv10.o
index d42862f..32de534 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_SW_CHAN_H__
 #define __NVKM_SW_CHAN_H__
 #define nvkm_sw_chan(p) container_of((p), struct nvkm_sw_chan, object)
index 459afd3..6d364d7 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_SW_NV50_H__
 #define __NVKM_SW_NV50_H__
 #define nv50_sw_chan(p) container_of((p), struct nv50_sw_chan, base)
index d703495..d2f8464 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_NVSW_H__
 #define __NVKM_NVSW_H__
 #define nvkm_nvsw(p) container_of((p), struct nvkm_nvsw, object)
index 4aca179..6d18fc6 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_SW_PRIV_H__
 #define __NVKM_SW_PRIV_H__
 #define nvkm_sw(p) container_of((p), struct nvkm_sw, engine)
index 9281c82..70164f4 100644 (file)
@@ -1,2 +1,2 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 #nvkm-y += nvkm/engine/vic/base.o
index 456e43f..d48ea0f 100644 (file)
@@ -1,2 +1,2 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/engine/vp/g84.o
index 8afbf0f..b5665ad 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/falcon/base.o
 nvkm-y += nvkm/falcon/v1.o
 nvkm-y += nvkm/falcon/msgqueue.o
index d515ad9..900fe1d 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_FALCON_PRIV_H__
 #define __NVKM_FALCON_PRIV_H__
 #include <engine/falcon.h>
index 9def926..6d978fe 100644 (file)
@@ -182,6 +182,7 @@ nvkm_falcon_v1_read_dmem(struct nvkm_falcon *falcon, u32 start, u32 size,
 static void
 nvkm_falcon_v1_bind_context(struct nvkm_falcon *falcon, struct nvkm_memory *ctx)
 {
+       struct nvkm_device *device = falcon->owner->device;
        u32 inst_loc;
        u32 fbif;
 
@@ -233,6 +234,41 @@ nvkm_falcon_v1_bind_context(struct nvkm_falcon *falcon, struct nvkm_memory *ctx)
 
        nvkm_falcon_mask(falcon, 0x090, 0x10000, 0x10000);
        nvkm_falcon_mask(falcon, 0x0a4, 0x8, 0x8);
+
+       /* Not sure if this is a WAR for a HW issue, or some additional
+        * programming sequence that's needed to properly complete the
+        * context switch we trigger above.
+        *
+        * Fixes unreliability of booting the SEC2 RTOS on Quadro P620,
+        * particularly when resuming from suspend.
+        *
+        * Also removes the need for an odd workaround where we needed
+        * to program SEC2's FALCON_CPUCTL_ALIAS_STARTCPU twice before
+        * the SEC2 RTOS would begin executing.
+        */
+       switch (falcon->owner->index) {
+       case NVKM_SUBDEV_GSP:
+       case NVKM_ENGINE_SEC2:
+               nvkm_msec(device, 10,
+                       u32 irqstat = nvkm_falcon_rd32(falcon, 0x008);
+                       u32 flcn0dc = nvkm_falcon_rd32(falcon, 0x0dc);
+                       if ((irqstat & 0x00000008) &&
+                           (flcn0dc & 0x00007000) == 0x00005000)
+                               break;
+               );
+
+               nvkm_falcon_mask(falcon, 0x004, 0x00000008, 0x00000008);
+               nvkm_falcon_mask(falcon, 0x058, 0x00000002, 0x00000002);
+
+               nvkm_msec(device, 10,
+                       u32 flcn0dc = nvkm_falcon_rd32(falcon, 0x0dc);
+                       if ((flcn0dc & 0x00007000) == 0x00000000)
+                               break;
+               );
+               break;
+       default:
+               break;
+       }
 }
 
 static void
index d8c2871..4e136f3 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 include $(src)/nvkm/subdev/bar/Kbuild
 include $(src)/nvkm/subdev/bios/Kbuild
 include $(src)/nvkm/subdev/bus/Kbuild
index 8210bf9..8faee33 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/bar/base.o
 nvkm-y += nvkm/subdev/bar/nv50.o
 nvkm-y += nvkm/subdev/bar/g84.o
index 4f2b66e..4ae4c71 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __GF100_BAR_H__
 #define __GF100_BAR_H__
 #define gf100_bar(p) container_of((p), struct gf100_bar, base)
index 2fe833f..e4193de 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NV50_BAR_H__
 #define __NV50_BAR_H__
 #define nv50_bar(p) container_of((p), struct nv50_bar, base)
index 01ba5b2..869ad18 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_BAR_PRIV_H__
 #define __NVKM_BAR_PRIV_H__
 #define nvkm_bar(p) container_of((p), struct nvkm_bar, subdev)
index bb4759c..5a970fb 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/bios/base.o
 nvkm-y += nvkm/subdev/bios/bit.o
 nvkm-y += nvkm/subdev/bios/boost.o
index 33435ca..fac1bff 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_BIOS_PRIV_H__
 #define __NVKM_BIOS_PRIV_H__
 #define nvkm_bios(p) container_of((p), struct nvkm_bios, subdev)
index 409137f..01d7379 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/bus/base.o
 nvkm-y += nvkm/subdev/bus/hwsq.o
 nvkm-y += nvkm/subdev/bus/nv04.o
index 17ac181..217a0a4 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_BUS_HWSQ_H__
 #define __NVKM_BUS_HWSQ_H__
 #include <subdev/bus.h>
index ef01e56..76f7ba1 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_BUS_PRIV_H__
 #define __NVKM_BUS_PRIV_H__
 #define nvkm_bus(p) container_of((p), struct nvkm_bus, subdev)
index 0a8a707..dcecd49 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/clk/base.o
 nvkm-y += nvkm/subdev/clk/nv04.o
 nvkm-y += nvkm/subdev/clk/nv40.o
index 1ea886a..34754ef 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_CLK_NVA3_H__
 #define __NVKM_CLK_NVA3_H__
 #include "priv.h"
index f134d97..7c77132 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NV50_CLK_H__
 #define __NV50_CLK_H__
 #define nv50_clk(p) container_of((p), struct nv50_clk, base)
index 9a39f1f..6319075 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_PLL_H__
 #define __NVKM_PLL_H__
 #include <core/os.h>
index b656177..81dfb37 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_CLK_PRIV_H__
 #define __NVKM_CLK_PRIV_H__
 #define nvkm_clk(p) container_of((p), struct nvkm_clk, subdev)
index d0715fe..e4b362d 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_CLK_SEQ_H__
 #define __NVKM_CLK_SEQ_H__
 #include <subdev/bus/hwsq.h>
index f054c44..b342937 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/devinit/base.o
 nvkm-y += nvkm/subdev/devinit/nv04.o
 nvkm-y += nvkm/subdev/devinit/nv05.o
index b18e498..15b029d 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NV04_DEVINIT_H__
 #define __NV04_DEVINIT_H__
 #define nv04_devinit(p) container_of((p), struct nv04_devinit, base)
index 72d130b..e8d37a6 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NV50_DEVINIT_H__
 #define __NV50_DEVINIT_H__
 #define nv50_devinit(p) container_of((p), struct nv50_devinit, base)
index 5b3097a..9472335 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_DEVINIT_PRIV_H__
 #define __NVKM_DEVINIT_PRIV_H__
 #define nvkm_devinit(p) container_of((p), struct nvkm_devinit, subdev)
index c9bcf37..53b9d63 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/fault/base.o
 nvkm-y += nvkm/subdev/fault/user.o
 nvkm-y += nvkm/subdev/fault/gp100.o
index 88b1668..43a4215 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/fb/base.o
 nvkm-y += nvkm/subdev/fb/nv04.o
 nvkm-y += nvkm/subdev/fb/nv10.o
index ab26131..2ed7cda 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_RAM_NVC0_H__
 #define __NVKM_RAM_NVC0_H__
 #define gf100_fb(p) container_of((p), struct gf100_fb, base)
index dacc696..5e2b0c9 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_FB_NV50_H__
 #define __NVKM_FB_NV50_H__
 #define nv50_fb(p) container_of((p), struct nv50_fb, base)
index 1e4ad61..c4e9f55 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_FB_PRIV_H__
 #define __NVKM_FB_PRIV_H__
 #define nvkm_fb(p) container_of((p), struct nvkm_fb, subdev)
index 330132e..d723a9b 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_FB_RAM_PRIV_H__
 #define __NVKM_FB_RAM_PRIV_H__
 #include "priv.h"
index a65fa55..247c0f8 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_FBRAM_FUC_H__
 #define __NVKM_FBRAM_FUC_H__
 #include <subdev/fb.h>
index 11f6bb2..a87de08 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NV40_FB_RAM_H__
 #define __NV40_FB_RAM_H__
 #define nv40_ram(p) container_of((p), struct nv40_ram, base)
index d8f5053..aba5b73 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_FBRAM_SEQ_H__
 #define __NVKM_FBRAM_SEQ_H__
 #include <subdev/bus/hwsq.h>
index ad26fcb..8098cd7 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_FB_REGS_04_H__
 #define __NVKM_FB_REGS_04_H__
 
index 9626715..8e7cd9d 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/fuse/base.o
 nvkm-y += nvkm/subdev/fuse/nv50.o
 nvkm-y += nvkm/subdev/fuse/gf100.o
index 3a5595a..2edc612 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_FUSE_PRIV_H__
 #define __NVKM_FUSE_PRIV_H__
 #define nvkm_fuse(p) container_of((p), struct nvkm_fuse, subdev)
index 0169fc3..b2ad592 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/gpio/base.o
 nvkm-y += nvkm/subdev/gpio/nv10.o
 nvkm-y += nvkm/subdev/gpio/nv50.o
index 9759f13..59e39af 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_GPIO_PRIV_H__
 #define __NVKM_GPIO_PRIV_H__
 #define nvkm_gpio(p) container_of((p), struct nvkm_gpio, subdev)
index fa566ea..e7c4f06 100644 (file)
@@ -1,2 +1,2 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/gsp/gv100.o
index 69f341e..723d028 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/i2c/base.o
 nvkm-y += nvkm/subdev/i2c/nv04.o
 nvkm-y += nvkm/subdev/i2c/nv4e.o
index 08f6b2e..30b4889 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_I2C_AUX_H__
 #define __NVKM_I2C_AUX_H__
 #include "pad.h"
index ecacb22..7193450 100644 (file)
@@ -185,6 +185,25 @@ nvkm_i2c_fini(struct nvkm_subdev *subdev, bool suspend)
 }
 
 static int
+nvkm_i2c_preinit(struct nvkm_subdev *subdev)
+{
+       struct nvkm_i2c *i2c = nvkm_i2c(subdev);
+       struct nvkm_i2c_bus *bus;
+       struct nvkm_i2c_pad *pad;
+
+       /*
+        * We init our i2c busses as early as possible, since they may be
+        * needed by the vbios init scripts on some cards
+        */
+       list_for_each_entry(pad, &i2c->pad, head)
+               nvkm_i2c_pad_init(pad);
+       list_for_each_entry(bus, &i2c->bus, head)
+               nvkm_i2c_bus_init(bus);
+
+       return 0;
+}
+
+static int
 nvkm_i2c_init(struct nvkm_subdev *subdev)
 {
        struct nvkm_i2c *i2c = nvkm_i2c(subdev);
@@ -238,6 +257,7 @@ nvkm_i2c_dtor(struct nvkm_subdev *subdev)
 static const struct nvkm_subdev_func
 nvkm_i2c = {
        .dtor = nvkm_i2c_dtor,
+       .preinit = nvkm_i2c_preinit,
        .init = nvkm_i2c_init,
        .fini = nvkm_i2c_fini,
        .intr = nvkm_i2c_intr,
index 465464b..4c236ab 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_I2C_BUS_H__
 #define __NVKM_I2C_BUS_H__
 #include "pad.h"
index 33f0c80..4610168 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_I2C_PAD_H__
 #define __NVKM_I2C_PAD_H__
 #include <subdev/i2c.h>
index f476a69..bd86bc2 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_I2C_PRIV_H__
 #define __NVKM_I2C_PRIV_H__
 #define nvkm_i2c(p) container_of((p), struct nvkm_i2c, subdev)
index 5575303..127efb5 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/ibus/gf100.o
 nvkm-y += nvkm/subdev/ibus/gf117.o
 nvkm-y += nvkm/subdev/ibus/gk104.o
index 504a6d3..302d69e 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_IBUS_PRIV_H__
 #define __NVKM_IBUS_PRIV_H__
 
index 52eb074..6634bcd 100644 (file)
@@ -1,3 +1,3 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/iccsense/base.o
 nvkm-y += nvkm/subdev/iccsense/gf100.o
index bd599b8..cc09c6c 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_ICCSENSE_PRIV_H__
 #define __NVKM_ICCSENSE_PRIV_H__
 #define nvkm_iccsense(p) container_of((p), struct nvkm_iccsense, subdev)
index e0031b5..06cbe19 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/instmem/base.o
 nvkm-y += nvkm/subdev/instmem/nv04.o
 nvkm-y += nvkm/subdev/instmem/nv40.o
index b9e4751..f5da8fc 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_INSTMEM_PRIV_H__
 #define __NVKM_INSTMEM_PRIV_H__
 #define nvkm_instmem(p) container_of((p), struct nvkm_instmem, subdev)
index 61f655c..2b6d36e 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/ltc/base.o
 nvkm-y += nvkm/subdev/ltc/gf100.o
 nvkm-y += nvkm/subdev/ltc/gk104.o
index 9dcde43..2fcf18e 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_LTC_PRIV_H__
 #define __NVKM_LTC_PRIV_H__
 #define nvkm_ltc(p) container_of((p), struct nvkm_ltc, subdev)
index 15da199..2585ef0 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/mc/base.o
 nvkm-y += nvkm/subdev/mc/nv04.o
 nvkm-y += nvkm/subdev/mc/nv11.o
index eb91a4c..4aab753 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_MC_PRIV_H__
 #define __NVKM_MC_PRIV_H__
 #define nvkm_mc(p) container_of((p), struct nvkm_mc, subdev)
index 697dc22..a602b0c 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/mmu/base.o
 nvkm-y += nvkm/subdev/mmu/nv04.o
 nvkm-y += nvkm/subdev/mmu/nv41.o
index 2ad1102..07f2fcd 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_MMU_PRIV_H__
 #define __NVKM_MMU_PRIV_H__
 #define nvkm_mmu(p) container_of((p), struct nvkm_mmu, subdev)
index 7a54938..5124a0c 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/mxm/base.o
 nvkm-y += nvkm/subdev/mxm/mxms.o
 nvkm-y += nvkm/subdev/mxm/nv50.o
index 011a67f..d9676b2 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVMXM_MXMS_H__
 #define __NVMXM_MXMS_H__
 #include "priv.h"
index 6767c22..fc8f69e 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_MXM_PRIV_H__
 #define __NVKM_MXM_PRIV_H__
 #define nvkm_mxm(p) container_of((p), struct nvkm_mxm, subdev)
index 6fbd008..174bdf9 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/pci/agp.o
 nvkm-y += nvkm/subdev/pci/base.o
 nvkm-y += nvkm/subdev/pci/pcie.o
index edb7f00..ad4d362 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #include "priv.h"
 #if defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE))
 #ifndef __NVKM_PCI_AGP_H__
index c17f606..7009aad 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_PCI_PRIV_H__
 #define __NVKM_PCI_PRIV_H__
 #define nvkm_pci(p) container_of((p), struct nvkm_pci, subdev)
index 132ae33..e37b6e4 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/pmu/base.o
 nvkm-y += nvkm/subdev/pmu/memx.o
 nvkm-y += nvkm/subdev/pmu/gt215.o
index 1dbe593..4cf888f 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 static uint32_t gf100_pmu_data[] = {
 /* 0x0000: proc_kern */
        0x52544e49,
index e1e9819..e80eff1 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 static uint32_t gf119_pmu_data[] = {
 /* 0x0000: proc_kern */
        0x52544e49,
index e0222cb..275ec71 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 static uint32_t gk208_pmu_data[] = {
 /* 0x0000: proc_kern */
        0x52544e49,
index defddf5..4b071e9 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 static uint32_t gt215_pmu_data[] = {
 /* 0x0000: proc_kern */
        0x52544e49,
index 30d9480..0d5abf2 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_PWR_OS_H__
 #define __NVKM_PWR_OS_H__
 
index 7b05287..22eaebe 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: MIT
 #ifndef __NVKM_PMU_MEMX_H__
 #define __NVKM_PMU_MEMX_H__
 #include "priv.h"
index e9c6f97..26d73f9 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_PMU_PRIV_H__
 #define __NVKM_PMU_PRIV_H__
 #define nvkm_pmu(p) container_of((p), struct nvkm_pmu, subdev)
index 51b3379..f3dee26 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/secboot/base.o
 nvkm-y += nvkm/subdev/secboot/hs_ucode.o
 nvkm-y += nvkm/subdev/secboot/ls_ucode_gr.o
index 77c13b0..a84a999 100644 (file)
@@ -164,41 +164,12 @@ acr_ls_sec2_post_run(const struct nvkm_acr *acr, const struct nvkm_secboot *sb)
        struct nvkm_sec2 *sec = device->sec2;
        /* on SEC arguments are always at the beginning of EMEM */
        const u32 addr_args = 0x01000000;
-       u32 reg;
        int ret;
 
        ret = acr_ls_msgqueue_post_run(sec->queue, sec->falcon, addr_args);
        if (ret)
                return ret;
 
-       /*
-        * There is a bug where the LS firmware sometimes require to be started
-        * twice (this happens only on SEC). Detect and workaround that
-        * condition.
-        *
-        * Once started, the falcon will end up in STOPPED condition (bit 5)
-        * if successful, or in HALT condition (bit 4) if not.
-        */
-       nvkm_msec(device, 1,
-                 if ((reg = nvkm_falcon_rd32(sb->boot_falcon, 0x100) & 0x30) != 0)
-                         break;
-       );
-       if (reg & BIT(4)) {
-               nvkm_debug(subdev, "applying workaround for start bug...\n");
-               nvkm_falcon_start(sb->boot_falcon);
-               nvkm_msec(subdev->device, 1,
-                       if ((reg = nvkm_rd32(subdev->device,
-                                            sb->boot_falcon->addr + 0x100)
-                            & 0x30) != 0)
-                               break;
-               );
-               if (reg & BIT(4)) {
-                       nvkm_error(subdev, "%s failed to start\n",
-                              nvkm_secboot_falcon_name[acr->boot_falcon]);
-                       return -EINVAL;
-               }
-       }
-
        nvkm_debug(&sb->subdev, "%s started\n",
                   nvkm_secboot_falcon_name[acr->boot_falcon]);
 
index 0cc1439..9aa76a2 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/therm/base.o
 nvkm-y += nvkm/subdev/therm/fan.o
 nvkm-y += nvkm/subdev/therm/fannil.o
index a4aa8e6..f710da4 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/timer/base.o
 nvkm-y += nvkm/subdev/timer/nv04.o
 nvkm-y += nvkm/subdev/timer/nv40.o
index 3b88784..89e9729 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_TIMER_PRIV_H__
 #define __NVKM_TIMER_PRIV_H__
 #define nvkm_timer(p) container_of((p), struct nvkm_timer, subdev)
index 23d07f5..34a740b 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #define NV04_PTIMER_INTR_0      0x009100
 #define NV04_PTIMER_INTR_EN_0   0x009140
 #define NV04_PTIMER_NUMERATOR   0x009200
index e0b2724..438d9d7 100644 (file)
@@ -1,3 +1,3 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/top/base.o
 nvkm-y += nvkm/subdev/top/gk104.o
index 4f49b0a..a16baa2 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_TOP_PRIV_H__
 #define __NVKM_TOP_PRIV_H__
 #define nvkm_top(p) container_of((p), struct nvkm_top, subdev)
index e80bc64..523a7cd 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: MIT
 nvkm-y += nvkm/subdev/volt/base.o
 nvkm-y += nvkm/subdev/volt/gpio.o
 nvkm-y += nvkm/subdev/volt/nv40.o
index 1a8ad56..75f13a3 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef __NVKM_VOLT_PRIV_H__
 #define __NVKM_VOLT_PRIV_H__
 #define nvkm_volt(p) container_of((p), struct nvkm_volt, subdev)
index bef4edd..14c96ed 100644 (file)
 #include "drm_selftest.h"
 #include "test-drm_modeset_common.h"
 
+static const struct drm_connector no_connector = {};
+
 static int drm_cmdline_test_res(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(mode.xres != 720);
@@ -42,11 +43,10 @@ static int drm_cmdline_test_res(void *ignored)
 
 static int drm_cmdline_test_res_missing_x(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(drm_mode_parse_command_line_for_connector("x480",
-                                                         &connector,
+                                                         &no_connector,
                                                          &mode));
 
        return 0;
@@ -54,11 +54,10 @@ static int drm_cmdline_test_res_missing_x(void *ignored)
 
 static int drm_cmdline_test_res_missing_y(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(drm_mode_parse_command_line_for_connector("1024x",
-                                                         &connector,
+                                                         &no_connector,
                                                          &mode));
 
        return 0;
@@ -66,11 +65,10 @@ static int drm_cmdline_test_res_missing_y(void *ignored)
 
 static int drm_cmdline_test_res_bad_y(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(drm_mode_parse_command_line_for_connector("1024xtest",
-                                                         &connector,
+                                                         &no_connector,
                                                          &mode));
 
        return 0;
@@ -78,11 +76,10 @@ static int drm_cmdline_test_res_bad_y(void *ignored)
 
 static int drm_cmdline_test_res_missing_y_bpp(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(drm_mode_parse_command_line_for_connector("1024x-24",
-                                                         &connector,
+                                                         &no_connector,
                                                          &mode));
 
        return 0;
@@ -90,11 +87,10 @@ static int drm_cmdline_test_res_missing_y_bpp(void *ignored)
 
 static int drm_cmdline_test_res_vesa(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480M",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(mode.xres != 720);
@@ -115,11 +111,10 @@ static int drm_cmdline_test_res_vesa(void *ignored)
 
 static int drm_cmdline_test_res_vesa_rblank(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480MR",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(mode.xres != 720);
@@ -140,11 +135,10 @@ static int drm_cmdline_test_res_vesa_rblank(void *ignored)
 
 static int drm_cmdline_test_res_rblank(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480R",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(mode.xres != 720);
@@ -165,11 +159,10 @@ static int drm_cmdline_test_res_rblank(void *ignored)
 
 static int drm_cmdline_test_res_bpp(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(mode.xres != 720);
@@ -191,11 +184,10 @@ static int drm_cmdline_test_res_bpp(void *ignored)
 
 static int drm_cmdline_test_res_bad_bpp(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(drm_mode_parse_command_line_for_connector("720x480-test",
-                                                         &connector,
+                                                         &no_connector,
                                                          &mode));
 
        return 0;
@@ -203,11 +195,10 @@ static int drm_cmdline_test_res_bad_bpp(void *ignored)
 
 static int drm_cmdline_test_res_refresh(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480@60",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(mode.xres != 720);
@@ -229,11 +220,10 @@ static int drm_cmdline_test_res_refresh(void *ignored)
 
 static int drm_cmdline_test_res_bad_refresh(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(drm_mode_parse_command_line_for_connector("720x480@refresh",
-                                                         &connector,
+                                                         &no_connector,
                                                          &mode));
 
        return 0;
@@ -241,11 +231,10 @@ static int drm_cmdline_test_res_bad_refresh(void *ignored)
 
 static int drm_cmdline_test_res_bpp_refresh(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(mode.xres != 720);
@@ -268,11 +257,10 @@ static int drm_cmdline_test_res_bpp_refresh(void *ignored)
 
 static int drm_cmdline_test_res_bpp_refresh_interlaced(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60i",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(mode.xres != 720);
@@ -295,11 +283,10 @@ static int drm_cmdline_test_res_bpp_refresh_interlaced(void *ignored)
 
 static int drm_cmdline_test_res_bpp_refresh_margins(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60m",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(mode.xres != 720);
@@ -322,11 +309,10 @@ static int drm_cmdline_test_res_bpp_refresh_margins(void *ignored)
 
 static int drm_cmdline_test_res_bpp_refresh_force_off(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60d",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(mode.xres != 720);
@@ -349,11 +335,10 @@ static int drm_cmdline_test_res_bpp_refresh_force_off(void *ignored)
 
 static int drm_cmdline_test_res_bpp_refresh_force_on_off(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(drm_mode_parse_command_line_for_connector("720x480-24@60de",
-                                                         &connector,
+                                                         &no_connector,
                                                          &mode));
 
        return 0;
@@ -361,11 +346,10 @@ static int drm_cmdline_test_res_bpp_refresh_force_on_off(void *ignored)
 
 static int drm_cmdline_test_res_bpp_refresh_force_on(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60e",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(mode.xres != 720);
@@ -388,11 +372,10 @@ static int drm_cmdline_test_res_bpp_refresh_force_on(void *ignored)
 
 static int drm_cmdline_test_res_bpp_refresh_force_on_analog(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60D",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(mode.xres != 720);
@@ -415,10 +398,11 @@ static int drm_cmdline_test_res_bpp_refresh_force_on_analog(void *ignored)
 
 static int drm_cmdline_test_res_bpp_refresh_force_on_digital(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
+       static const struct drm_connector connector = {
+               .connector_type = DRM_MODE_CONNECTOR_DVII,
+       };
 
-       connector.connector_type = DRM_MODE_CONNECTOR_DVII;
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60D",
                                                           &connector,
                                                           &mode));
@@ -443,11 +427,10 @@ static int drm_cmdline_test_res_bpp_refresh_force_on_digital(void *ignored)
 
 static int drm_cmdline_test_res_bpp_refresh_interlaced_margins_force_on(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60ime",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(mode.xres != 720);
@@ -470,11 +453,10 @@ static int drm_cmdline_test_res_bpp_refresh_interlaced_margins_force_on(void *ig
 
 static int drm_cmdline_test_res_margins_force_on(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480me",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(mode.xres != 720);
@@ -495,11 +477,10 @@ static int drm_cmdline_test_res_margins_force_on(void *ignored)
 
 static int drm_cmdline_test_res_vesa_margins(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480Mm",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(mode.xres != 720);
@@ -520,11 +501,10 @@ static int drm_cmdline_test_res_vesa_margins(void *ignored)
 
 static int drm_cmdline_test_res_invalid_mode(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(drm_mode_parse_command_line_for_connector("720x480f",
-                                                         &connector,
+                                                         &no_connector,
                                                          &mode));
 
        return 0;
@@ -532,11 +512,10 @@ static int drm_cmdline_test_res_invalid_mode(void *ignored)
 
 static int drm_cmdline_test_res_bpp_wrong_place_mode(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(drm_mode_parse_command_line_for_connector("720x480e-24",
-                                                         &connector,
+                                                         &no_connector,
                                                          &mode));
 
        return 0;
@@ -544,11 +523,10 @@ static int drm_cmdline_test_res_bpp_wrong_place_mode(void *ignored)
 
 static int drm_cmdline_test_name(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(strcmp(mode.name, "NTSC"));
        FAIL_ON(mode.refresh_specified);
@@ -559,11 +537,10 @@ static int drm_cmdline_test_name(void *ignored)
 
 static int drm_cmdline_test_name_bpp(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC-24",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(strcmp(mode.name, "NTSC"));
 
@@ -577,11 +554,10 @@ static int drm_cmdline_test_name_bpp(void *ignored)
 
 static int drm_cmdline_test_name_bpp_refresh(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC-24@60",
-                                                         &connector,
+                                                         &no_connector,
                                                          &mode));
 
        return 0;
@@ -589,11 +565,10 @@ static int drm_cmdline_test_name_bpp_refresh(void *ignored)
 
 static int drm_cmdline_test_name_refresh(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC@60",
-                                                         &connector,
+                                                         &no_connector,
                                                          &mode));
 
        return 0;
@@ -601,11 +576,10 @@ static int drm_cmdline_test_name_refresh(void *ignored)
 
 static int drm_cmdline_test_name_refresh_wrong_mode(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC@60m",
-                                                         &connector,
+                                                         &no_connector,
                                                          &mode));
 
        return 0;
@@ -613,11 +587,10 @@ static int drm_cmdline_test_name_refresh_wrong_mode(void *ignored)
 
 static int drm_cmdline_test_name_refresh_invalid_mode(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC@60f",
-                                                         &connector,
+                                                         &no_connector,
                                                          &mode));
 
        return 0;
@@ -625,11 +598,10 @@ static int drm_cmdline_test_name_refresh_invalid_mode(void *ignored)
 
 static int drm_cmdline_test_name_option(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC,rotate=180",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(strcmp(mode.name, "NTSC"));
@@ -640,11 +612,10 @@ static int drm_cmdline_test_name_option(void *ignored)
 
 static int drm_cmdline_test_name_bpp_option(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC-24,rotate=180",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(strcmp(mode.name, "NTSC"));
@@ -657,11 +628,10 @@ static int drm_cmdline_test_name_bpp_option(void *ignored)
 
 static int drm_cmdline_test_rotate_0(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=0",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(mode.xres != 720);
@@ -683,11 +653,10 @@ static int drm_cmdline_test_rotate_0(void *ignored)
 
 static int drm_cmdline_test_rotate_90(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=90",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(mode.xres != 720);
@@ -709,11 +678,10 @@ static int drm_cmdline_test_rotate_90(void *ignored)
 
 static int drm_cmdline_test_rotate_180(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=180",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(mode.xres != 720);
@@ -735,11 +703,10 @@ static int drm_cmdline_test_rotate_180(void *ignored)
 
 static int drm_cmdline_test_rotate_270(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=270",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(mode.xres != 720);
@@ -761,11 +728,10 @@ static int drm_cmdline_test_rotate_270(void *ignored)
 
 static int drm_cmdline_test_rotate_invalid_val(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,rotate=42",
-                                                         &connector,
+                                                         &no_connector,
                                                          &mode));
 
        return 0;
@@ -773,11 +739,10 @@ static int drm_cmdline_test_rotate_invalid_val(void *ignored)
 
 static int drm_cmdline_test_rotate_truncated(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,rotate=",
-                                                         &connector,
+                                                         &no_connector,
                                                          &mode));
 
        return 0;
@@ -785,11 +750,10 @@ static int drm_cmdline_test_rotate_truncated(void *ignored)
 
 static int drm_cmdline_test_hmirror(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,reflect_x",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(mode.xres != 720);
@@ -811,11 +775,10 @@ static int drm_cmdline_test_hmirror(void *ignored)
 
 static int drm_cmdline_test_vmirror(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,reflect_y",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(mode.xres != 720);
@@ -837,11 +800,10 @@ static int drm_cmdline_test_vmirror(void *ignored)
 
 static int drm_cmdline_test_margin_options(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,margin_right=14,margin_left=24,margin_bottom=36,margin_top=42",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(mode.xres != 720);
@@ -866,11 +828,10 @@ static int drm_cmdline_test_margin_options(void *ignored)
 
 static int drm_cmdline_test_multiple_options(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=270,reflect_x",
-                                                          &connector,
+                                                          &no_connector,
                                                           &mode));
        FAIL_ON(!mode.specified);
        FAIL_ON(mode.xres != 720);
@@ -892,11 +853,10 @@ static int drm_cmdline_test_multiple_options(void *ignored)
 
 static int drm_cmdline_test_invalid_option(void *ignored)
 {
-       struct drm_connector connector = { };
        struct drm_cmdline_mode mode = { };
 
        FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,test=42",
-                                                         &connector,
+                                                         &no_connector,
                                                          &mode));
 
        return 0;
index 894da5a..ebd35fc 100644 (file)
@@ -1197,8 +1197,6 @@ static struct kmsg_dumper hv_kmsg_dumper = {
 };
 
 static struct ctl_table_header *hv_ctl_table_hdr;
-static int zero;
-static int one = 1;
 
 /*
  * sysctl option to allow the user to control whether kmsg data should be
@@ -1211,8 +1209,8 @@ static struct ctl_table hv_ctl_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE
        },
        {}
 };
index e7dff5f..d42bc08 100644 (file)
@@ -852,7 +852,7 @@ static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
 static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
 static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
 static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
-static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x17c };
+static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x18b };
 static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
 static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
 
@@ -3764,6 +3764,7 @@ static int nct6775_probe(struct platform_device *pdev)
                data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
                data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
                data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
+               data->REG_TOLERANCE_H = NCT6106_REG_TOLERANCE_H;
                data->REG_PWM[0] = NCT6106_REG_PWM;
                data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
                data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
index a7d2b16..30e18eb 100644 (file)
@@ -408,8 +408,10 @@ static ssize_t occ_show_power_1(struct device *dev,
 
 static u64 occ_get_powr_avg(u64 *accum, u32 *samples)
 {
-       return div64_u64(get_unaligned_be64(accum) * 1000000ULL,
-                        get_unaligned_be32(samples));
+       u64 divisor = get_unaligned_be32(samples);
+
+       return (divisor == 0) ? 0 :
+               div64_u64(get_unaligned_be64(accum) * 1000000ULL, divisor);
 }
 
 static ssize_t occ_show_power_2(struct device *dev,
index a80183a..0c93fc5 100644 (file)
@@ -18,6 +18,50 @@ struct scmi_sensors {
        const struct scmi_sensor_info **info[hwmon_max];
 };
 
+static inline u64 __pow10(u8 x)
+{
+       u64 r = 1;
+
+       while (x--)
+               r *= 10;
+
+       return r;
+}
+
+static int scmi_hwmon_scale(const struct scmi_sensor_info *sensor, u64 *value)
+{
+       s8 scale = sensor->scale;
+       u64 f;
+
+       switch (sensor->type) {
+       case TEMPERATURE_C:
+       case VOLTAGE:
+       case CURRENT:
+               scale += 3;
+               break;
+       case POWER:
+       case ENERGY:
+               scale += 6;
+               break;
+       default:
+               break;
+       }
+
+       if (scale == 0)
+               return 0;
+
+       if (abs(scale) > 19)
+               return -E2BIG;
+
+       f = __pow10(abs(scale));
+       if (scale > 0)
+               *value *= f;
+       else
+               *value = div64_u64(*value, f);
+
+       return 0;
+}
+
 static int scmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
                           u32 attr, int channel, long *val)
 {
@@ -29,6 +73,10 @@ static int scmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
 
        sensor = *(scmi_sensors->info[type] + channel);
        ret = h->sensor_ops->reading_get(h, sensor->id, false, &value);
+       if (ret)
+               return ret;
+
+       ret = scmi_hwmon_scale(sensor, &value);
        if (!ret)
                *val = value;
 
index 7869c67..37740e9 100644 (file)
@@ -9,7 +9,7 @@ menuconfig HWSPINLOCK
 config HWSPINLOCK_OMAP
        tristate "OMAP Hardware Spinlock device"
        depends on HWSPINLOCK
-       depends on ARCH_OMAP4 || SOC_OMAP5 || SOC_DRA7XX || SOC_AM33XX || SOC_AM43XX
+       depends on ARCH_OMAP4 || SOC_OMAP5 || SOC_DRA7XX || SOC_AM33XX || SOC_AM43XX || ARCH_K3
        help
          Say y here to support the OMAP Hardware Spinlock device (firstly
          introduced in OMAP4).
index 2bad40d..8862445 100644 (file)
@@ -9,6 +9,7 @@
 
 #define pr_fmt(fmt)    "%s: " fmt, __func__
 
+#include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
@@ -23,6 +24,9 @@
 
 #include "hwspinlock_internal.h"
 
+/* retry delay used in atomic context */
+#define HWSPINLOCK_RETRY_DELAY_US      100
+
 /* radix tree tags */
 #define HWSPINLOCK_UNUSED      (0) /* tags an hwspinlock as unused */
 
@@ -68,11 +72,11 @@ static DEFINE_MUTEX(hwspinlock_tree_lock);
  * user need some time-consuming or sleepable operations under the hardware
  * lock, they need one sleepable lock (like mutex) to protect the operations.
  *
- * If the mode is not HWLOCK_RAW, upon a successful return from this function,
- * preemption (and possibly interrupts) is disabled, so the caller must not
- * sleep, and is advised to release the hwspinlock as soon as possible. This is
- * required in order to minimize remote cores polling on the hardware
- * interconnect.
+ * If the mode is neither HWLOCK_IN_ATOMIC nor HWLOCK_RAW, upon a successful
+ * return from this function, preemption (and possibly interrupts) is disabled,
+ * so the caller must not sleep, and is advised to release the hwspinlock as
+ * soon as possible. This is required in order to minimize remote cores polling
+ * on the hardware interconnect.
  *
  * The user decides whether local interrupts are disabled or not, and if yes,
  * whether he wants their previous state to be saved. It is up to the user
@@ -112,6 +116,7 @@ int __hwspin_trylock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
                ret = spin_trylock_irq(&hwlock->lock);
                break;
        case HWLOCK_RAW:
+       case HWLOCK_IN_ATOMIC:
                ret = 1;
                break;
        default:
@@ -136,6 +141,7 @@ int __hwspin_trylock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
                        spin_unlock_irq(&hwlock->lock);
                        break;
                case HWLOCK_RAW:
+               case HWLOCK_IN_ATOMIC:
                        /* Nothing to do */
                        break;
                default:
@@ -179,11 +185,14 @@ EXPORT_SYMBOL_GPL(__hwspin_trylock);
  * user need some time-consuming or sleepable operations under the hardware
  * lock, they need one sleepable lock (like mutex) to protect the operations.
  *
- * If the mode is not HWLOCK_RAW, upon a successful return from this function,
- * preemption is disabled (and possibly local interrupts, too), so the caller
- * must not sleep, and is advised to release the hwspinlock as soon as possible.
- * This is required in order to minimize remote cores polling on the
- * hardware interconnect.
+ * If the mode is HWLOCK_IN_ATOMIC (called from an atomic context) the timeout
+ * is handled with busy-waiting delays, hence shall not exceed few msecs.
+ *
+ * If the mode is neither HWLOCK_IN_ATOMIC nor HWLOCK_RAW, upon a successful
+ * return from this function, preemption (and possibly interrupts) is disabled,
+ * so the caller must not sleep, and is advised to release the hwspinlock as
+ * soon as possible. This is required in order to minimize remote cores polling
+ * on the hardware interconnect.
  *
  * The user decides whether local interrupts are disabled or not, and if yes,
  * whether he wants their previous state to be saved. It is up to the user
@@ -198,7 +207,7 @@ int __hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int to,
                                        int mode, unsigned long *flags)
 {
        int ret;
-       unsigned long expire;
+       unsigned long expire, atomic_delay = 0;
 
        expire = msecs_to_jiffies(to) + jiffies;
 
@@ -212,8 +221,15 @@ int __hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int to,
                 * The lock is already taken, let's check if the user wants
                 * us to try again
                 */
-               if (time_is_before_eq_jiffies(expire))
-                       return -ETIMEDOUT;
+               if (mode == HWLOCK_IN_ATOMIC) {
+                       udelay(HWSPINLOCK_RETRY_DELAY_US);
+                       atomic_delay += HWSPINLOCK_RETRY_DELAY_US;
+                       if (atomic_delay > to * 1000)
+                               return -ETIMEDOUT;
+               } else {
+                       if (time_is_before_eq_jiffies(expire))
+                               return -ETIMEDOUT;
+               }
 
                /*
                 * Allow platform-specific relax handlers to prevent
@@ -276,6 +292,7 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
                spin_unlock_irq(&hwlock->lock);
                break;
        case HWLOCK_RAW:
+       case HWLOCK_IN_ATOMIC:
                /* Nothing to do */
                break;
        default:
@@ -333,6 +350,11 @@ int of_hwspin_lock_get_id(struct device_node *np, int index)
        if (ret)
                return ret;
 
+       if (!of_device_is_available(args.np)) {
+               ret = -ENOENT;
+               goto out;
+       }
+
        /* Find the hwspinlock device: we need its base_id */
        ret = -EPROBE_DEFER;
        rcu_read_lock();
index 625844e..14e1a53 100644 (file)
@@ -140,6 +140,9 @@ static int omap_hwspinlock_probe(struct platform_device *pdev)
        if (ret)
                goto reg_fail;
 
+       dev_dbg(&pdev->dev, "Registered %d locks with HwSpinlock core\n",
+               num_locks);
+
        return 0;
 
 reg_fail:
@@ -171,6 +174,7 @@ static int omap_hwspinlock_remove(struct platform_device *pdev)
 
 static const struct of_device_id omap_hwspinlock_of_match[] = {
        { .compatible = "ti,omap4-hwspinlock", },
+       { .compatible = "ti,am654-hwspinlock", },
        { /* end */ },
 };
 MODULE_DEVICE_TABLE(of, omap_hwspinlock_of_match);
index 4418392..c8eacf4 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/hwspinlock.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
@@ -42,9 +43,15 @@ static void stm32_hwspinlock_unlock(struct hwspinlock *lock)
        writel(STM32_MUTEX_COREID, lock_addr);
 }
 
+static void stm32_hwspinlock_relax(struct hwspinlock *lock)
+{
+       ndelay(50);
+}
+
 static const struct hwspinlock_ops stm32_hwspinlock_ops = {
        .trylock        = stm32_hwspinlock_trylock,
        .unlock         = stm32_hwspinlock_unlock,
+       .relax          = stm32_hwspinlock_relax,
 };
 
 static int stm32_hwspinlock_probe(struct platform_device *pdev)
index ceb42d9..41a5695 100644 (file)
@@ -34,6 +34,7 @@
 
 #include <linux/module.h>
 #include <linux/fs.h>
+#include <linux/fs_context.h>
 #include <linux/mount.h>
 #include <linux/pagemap.h>
 #include <linux/init.h>
@@ -506,7 +507,7 @@ bail:
  * after device init.  The direct add_cntr_files() call handles adding
  * them from the init code, when the fs is already mounted.
  */
-static int qibfs_fill_super(struct super_block *sb, void *data, int silent)
+static int qibfs_fill_super(struct super_block *sb, struct fs_context *fc)
 {
        struct qib_devdata *dd;
        unsigned long index;
@@ -534,17 +535,24 @@ bail:
        return ret;
 }
 
-static struct dentry *qibfs_mount(struct file_system_type *fs_type, int flags,
-                       const char *dev_name, void *data)
+static int qibfs_get_tree(struct fs_context *fc)
 {
-       struct dentry *ret;
-
-       ret = mount_single(fs_type, flags, data, qibfs_fill_super);
-       if (!IS_ERR(ret))
-               qib_super = ret->d_sb;
+       int ret = get_tree_single(fc, qibfs_fill_super);
+       if (ret == 0)
+               qib_super = fc->root->d_sb;
        return ret;
 }
 
+static const struct fs_context_operations qibfs_context_ops = {
+       .get_tree       = qibfs_get_tree,
+};
+
+static int qibfs_init_fs_context(struct fs_context *fc)
+{
+       fc->ops = &qibfs_context_ops;
+       return 0;
+}
+
 static void qibfs_kill_super(struct super_block *s)
 {
        kill_litter_super(s);
@@ -583,7 +591,7 @@ int qibfs_remove(struct qib_devdata *dd)
 static struct file_system_type qibfs_fs_type = {
        .owner =        THIS_MODULE,
        .name =         "ipathfs",
-       .mount =        qibfs_mount,
+       .init_fs_context = qibfs_init_fs_context,
        .kill_sb =      qibfs_kill_super,
 };
 MODULE_ALIAS_FS("ipathfs");
index c7a3d75..2e72fc5 100644 (file)
@@ -611,6 +611,7 @@ iscsi_iser_session_create(struct iscsi_endpoint *ep,
        struct Scsi_Host *shost;
        struct iser_conn *iser_conn = NULL;
        struct ib_conn *ib_conn;
+       struct ib_device *ib_dev;
        u32 max_fr_sectors;
 
        shost = iscsi_host_alloc(&iscsi_iser_sht, 0, 0);
@@ -641,16 +642,19 @@ iscsi_iser_session_create(struct iscsi_endpoint *ep,
                }
 
                ib_conn = &iser_conn->ib_conn;
+               ib_dev = ib_conn->device->ib_device;
                if (ib_conn->pi_support) {
-                       u32 sig_caps = ib_conn->device->ib_device->attrs.sig_prot_cap;
+                       u32 sig_caps = ib_dev->attrs.sig_prot_cap;
 
                        scsi_host_set_prot(shost, iser_dif_prot_caps(sig_caps));
                        scsi_host_set_guard(shost, SHOST_DIX_GUARD_IP |
                                                   SHOST_DIX_GUARD_CRC);
                }
 
-               if (iscsi_host_add(shost,
-                                  ib_conn->device->ib_device->dev.parent)) {
+               if (!(ib_dev->attrs.device_cap_flags & IB_DEVICE_SG_GAPS_REG))
+                       shost->virt_boundary_mask = ~MASK_4K;
+
+               if (iscsi_host_add(shost, ib_dev->dev.parent)) {
                        mutex_unlock(&iser_conn->state_mutex);
                        goto free_host;
                }
@@ -956,30 +960,6 @@ static umode_t iser_attr_is_visible(int param_type, int param)
        return 0;
 }
 
-static int iscsi_iser_slave_alloc(struct scsi_device *sdev)
-{
-       struct iscsi_session *session;
-       struct iser_conn *iser_conn;
-       struct ib_device *ib_dev;
-
-       mutex_lock(&unbind_iser_conn_mutex);
-
-       session = starget_to_session(scsi_target(sdev))->dd_data;
-       iser_conn = session->leadconn->dd_data;
-       if (!iser_conn) {
-               mutex_unlock(&unbind_iser_conn_mutex);
-               return -ENOTCONN;
-       }
-       ib_dev = iser_conn->ib_conn.device->ib_device;
-
-       if (!(ib_dev->attrs.device_cap_flags & IB_DEVICE_SG_GAPS_REG))
-               blk_queue_virt_boundary(sdev->request_queue, ~MASK_4K);
-
-       mutex_unlock(&unbind_iser_conn_mutex);
-
-       return 0;
-}
-
 static struct scsi_host_template iscsi_iser_sht = {
        .module                 = THIS_MODULE,
        .name                   = "iSCSI Initiator over iSER",
@@ -992,7 +972,6 @@ static struct scsi_host_template iscsi_iser_sht = {
        .eh_device_reset_handler= iscsi_eh_device_reset,
        .eh_target_reset_handler = iscsi_eh_recover_target,
        .target_alloc           = iscsi_target_alloc,
-       .slave_alloc            = iscsi_iser_slave_alloc,
        .proc_name              = "iscsi_iser",
        .this_id                = -1,
        .track_queue_depth      = 1,
index c7bd96e..b596035 100644 (file)
@@ -3046,20 +3046,6 @@ static int srp_target_alloc(struct scsi_target *starget)
        return 0;
 }
 
-static int srp_slave_alloc(struct scsi_device *sdev)
-{
-       struct Scsi_Host *shost = sdev->host;
-       struct srp_target_port *target = host_to_target(shost);
-       struct srp_device *srp_dev = target->srp_host->srp_dev;
-       struct ib_device *ibdev = srp_dev->dev;
-
-       if (!(ibdev->attrs.device_cap_flags & IB_DEVICE_SG_GAPS_REG))
-               blk_queue_virt_boundary(sdev->request_queue,
-                                       ~srp_dev->mr_page_mask);
-
-       return 0;
-}
-
 static int srp_slave_configure(struct scsi_device *sdev)
 {
        struct Scsi_Host *shost = sdev->host;
@@ -3262,7 +3248,6 @@ static struct scsi_host_template srp_template = {
        .name                           = "InfiniBand SRP initiator",
        .proc_name                      = DRV_NAME,
        .target_alloc                   = srp_target_alloc,
-       .slave_alloc                    = srp_slave_alloc,
        .slave_configure                = srp_slave_configure,
        .info                           = srp_target_info,
        .queuecommand                   = srp_queuecommand,
@@ -3806,6 +3791,9 @@ static ssize_t srp_create_target(struct device *dev,
        target_host->max_cmd_len = sizeof ((struct srp_cmd *) (void *) 0L)->cdb;
        target_host->max_segment_size = ib_dma_max_seg_size(ibdev);
 
+       if (!(ibdev->attrs.device_cap_flags & IB_DEVICE_SG_GAPS_REG))
+               target_host->virt_boundary_mask = ~srp_dev->mr_page_mask;
+
        target = host_to_target(target_host);
 
        target->net             = kobj_ns_grab_current(KOBJ_NS_TYPE_NET);
index 4cadebd..95c0348 100644 (file)
@@ -6,9 +6,6 @@
  *  USB/RS232 I-Force joysticks and wheels.
  */
 
-/*
- */
-
 #include "iforce.h"
 
 /*
index 9a5f90d..b2a68bc 100644 (file)
@@ -6,9 +6,6 @@
  *  USB/RS232 I-Force joysticks and wheels.
  */
 
-/*
- */
-
 #include <asm/unaligned.h>
 #include "iforce.h"
 
index b313e38..763642c 100644 (file)
@@ -6,9 +6,6 @@
  *  USB/RS232 I-Force joysticks and wheels.
  */
 
-/*
- */
-
 #include <asm/unaligned.h>
 #include "iforce.h"
 
index bbe31e0..f95a81b 100644 (file)
@@ -6,9 +6,6 @@
  *  USB/RS232 I-Force joysticks and wheels.
  */
 
-/*
- */
-
 #include <linux/serio.h>
 #include "iforce.h"
 
index ade376b..29abfee 100644 (file)
@@ -6,9 +6,6 @@
  *  USB/RS232 I-Force joysticks and wheels.
  */
 
-/*
- */
-
 #include <linux/usb.h>
 #include "iforce.h"
 
index 9cfa460..6aa761e 100644 (file)
@@ -6,9 +6,6 @@
  *  USB/RS232 I-Force joysticks and wheels.
  */
 
-/*
- */
-
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/input.h>
index 7c4f19d..8e9c3ea 100644 (file)
@@ -71,6 +71,22 @@ config KEYBOARD_AMIGA
 config ATARI_KBD_CORE
        bool
 
+config KEYBOARD_APPLESPI
+       tristate "Apple SPI keyboard and trackpad"
+       depends on ACPI && EFI
+       depends on SPI
+       depends on X86 || COMPILE_TEST
+       help
+         Say Y here if you are running Linux on any Apple MacBook8,1 or later,
+         or any MacBookPro13,* or MacBookPro14,*.
+
+         You will also need to enable appropriate SPI master controllers:
+         spi_pxa2xx_platform and spi_pxa2xx_pci for MacBook8,1, and
+         spi_pxa2xx_platform and intel_lpss_pci for the rest.
+
+         To compile this driver as a module, choose M here: the
+         module will be called applespi.
+
 config KEYBOARD_ATARI
        tristate "Atari keyboard"
        depends on ATARI
index f0291ca..06a0af6 100644 (file)
@@ -10,6 +10,7 @@ obj-$(CONFIG_KEYBOARD_ADP5520)                += adp5520-keys.o
 obj-$(CONFIG_KEYBOARD_ADP5588)         += adp5588-keys.o
 obj-$(CONFIG_KEYBOARD_ADP5589)         += adp5589-keys.o
 obj-$(CONFIG_KEYBOARD_AMIGA)           += amikbd.o
+obj-$(CONFIG_KEYBOARD_APPLESPI)                += applespi.o
 obj-$(CONFIG_KEYBOARD_ATARI)           += atakbd.o
 obj-$(CONFIG_KEYBOARD_ATKBD)           += atkbd.o
 obj-$(CONFIG_KEYBOARD_BCM)             += bcm-keypad.o
index 4c05c70..4f96a4a 100644 (file)
@@ -505,6 +505,7 @@ static int adp5589_gpio_add(struct adp5589_kpad *kpad)
        if (!gpio_data)
                return 0;
 
+       kpad->gc.parent = dev;
        kpad->gc.ngpio = adp5589_build_gpiomap(kpad, pdata);
        if (kpad->gc.ngpio == 0) {
                dev_info(dev, "No unused gpios left to export\n");
diff --git a/drivers/input/keyboard/applespi.c b/drivers/input/keyboard/applespi.c
new file mode 100644 (file)
index 0000000..548737e
--- /dev/null
@@ -0,0 +1,1977 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MacBook (Pro) SPI keyboard and touchpad driver
+ *
+ * Copyright (c) 2015-2018 Federico Lorenzi
+ * Copyright (c) 2017-2018 Ronald Tschalär
+ */
+
+/*
+ * The keyboard and touchpad controller on the MacBookAir6, MacBookPro12,
+ * MacBook8 and newer can be driven either by USB or SPI. However the USB
+ * pins are only connected on the MacBookAir6 and 7 and the MacBookPro12.
+ * All others need this driver. The interface is selected using ACPI methods:
+ *
+ * * UIEN ("USB Interface Enable"): If invoked with argument 1, disables SPI
+ *   and enables USB. If invoked with argument 0, disables USB.
+ * * UIST ("USB Interface Status"): Returns 1 if USB is enabled, 0 otherwise.
+ * * SIEN ("SPI Interface Enable"): If invoked with argument 1, disables USB
+ *   and enables SPI. If invoked with argument 0, disables SPI.
+ * * SIST ("SPI Interface Status"): Returns 1 if SPI is enabled, 0 otherwise.
+ * * ISOL: Resets the four GPIO pins used for SPI. Intended to be invoked with
+ *   argument 1, then once more with argument 0.
+ *
+ * UIEN and UIST are only provided on models where the USB pins are connected.
+ *
+ * SPI-based Protocol
+ * ------------------
+ *
+ * The device and driver exchange messages (struct message); each message is
+ * encapsulated in one or more packets (struct spi_packet). There are two types
+ * of exchanges: reads, and writes. A read is signaled by a GPE, upon which one
+ * message can be read from the device. A write exchange consists of writing a
+ * command message, immediately reading a short status packet, and then, upon
+ * receiving a GPE, reading the response message. Write exchanges cannot be
+ * interleaved, i.e. a new write exchange must not be started till the previous
+ * write exchange is complete. Whether a received message is part of a read or
+ * write exchange is indicated in the encapsulating packet's flags field.
+ *
+ * A single message may be too large to fit in a single packet (which has a
+ * fixed, 256-byte size). In that case it will be split over multiple,
+ * consecutive packets.
+ */
+
+#include <linux/acpi.h>
+#include <linux/crc16.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/efi.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/spi/spi.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
+#include <asm/barrier.h>
+#include <asm/unaligned.h>
+
+#define CREATE_TRACE_POINTS
+#include "applespi.h"
+#include "applespi_trace.h"
+
+#define APPLESPI_PACKET_SIZE   256
+#define APPLESPI_STATUS_SIZE   4
+
+#define PACKET_TYPE_READ       0x20
+#define PACKET_TYPE_WRITE      0x40
+#define PACKET_DEV_KEYB                0x01
+#define PACKET_DEV_TPAD                0x02
+#define PACKET_DEV_INFO                0xd0
+
+#define MAX_ROLLOVER           6
+
+#define MAX_FINGERS            11
+#define MAX_FINGER_ORIENTATION 16384
+#define MAX_PKTS_PER_MSG       2
+
+#define KBD_BL_LEVEL_MIN       32U
+#define KBD_BL_LEVEL_MAX       255U
+#define KBD_BL_LEVEL_SCALE     1000000U
+#define KBD_BL_LEVEL_ADJ       \
+       ((KBD_BL_LEVEL_MAX - KBD_BL_LEVEL_MIN) * KBD_BL_LEVEL_SCALE / 255U)
+
+#define EFI_BL_LEVEL_NAME      L"KeyboardBacklightLevel"
+#define EFI_BL_LEVEL_GUID      EFI_GUID(0xa076d2af, 0x9678, 0x4386, 0x8b, 0x58, 0x1f, 0xc8, 0xef, 0x04, 0x16, 0x19)
+
+#define APPLE_FLAG_FKEY                0x01
+
+#define SPI_RW_CHG_DELAY_US    100     /* from experimentation, in µs */
+
+#define SYNAPTICS_VENDOR_ID    0x06cb
+
+static unsigned int fnmode = 1;
+module_param(fnmode, uint, 0644);
+MODULE_PARM_DESC(fnmode, "Mode of Fn key on Apple keyboards (0 = disabled, [1] = fkeyslast, 2 = fkeysfirst)");
+
+static unsigned int fnremap;
+module_param(fnremap, uint, 0644);
+MODULE_PARM_DESC(fnremap, "Remap Fn key ([0] = no-remap; 1 = left-ctrl, 2 = left-shift, 3 = left-alt, 4 = left-meta, 6 = right-shift, 7 = right-alt, 8 = right-meta)");
+
+static bool iso_layout;
+module_param(iso_layout, bool, 0644);
+MODULE_PARM_DESC(iso_layout, "Enable/Disable hardcoded ISO-layout of the keyboard. ([0] = disabled, 1 = enabled)");
+
+static char touchpad_dimensions[40];
+module_param_string(touchpad_dimensions, touchpad_dimensions,
+                   sizeof(touchpad_dimensions), 0444);
+MODULE_PARM_DESC(touchpad_dimensions, "The pixel dimensions of the touchpad, as XxY+W+H .");
+
+/**
+ * struct keyboard_protocol - keyboard message.
+ * message.type = 0x0110, message.length = 0x000a
+ *
+ * @unknown1:          unknown
+ * @modifiers:         bit-set of modifier/control keys pressed
+ * @unknown2:          unknown
+ * @keys_pressed:      the (non-modifier) keys currently pressed
+ * @fn_pressed:                whether the fn key is currently pressed
+ * @crc16:             crc over the whole message struct (message header +
+ *                     this struct) minus this @crc16 field
+ */
+struct keyboard_protocol {
+       u8                      unknown1;
+       u8                      modifiers;
+       u8                      unknown2;
+       u8                      keys_pressed[MAX_ROLLOVER];
+       u8                      fn_pressed;
+       __le16                  crc16;
+};
+
+/**
+ * struct tp_finger - single trackpad finger structure, le16-aligned
+ *
+ * @origin:            zero when switching track finger
+ * @abs_x:             absolute x coodinate
+ * @abs_y:             absolute y coodinate
+ * @rel_x:             relative x coodinate
+ * @rel_y:             relative y coodinate
+ * @tool_major:                tool area, major axis
+ * @tool_minor:                tool area, minor axis
+ * @orientation:       16384 when point, else 15 bit angle
+ * @touch_major:       touch area, major axis
+ * @touch_minor:       touch area, minor axis
+ * @unused:            zeros
+ * @pressure:          pressure on forcetouch touchpad
+ * @multi:             one finger: varies, more fingers: constant
+ * @crc16:             on last finger: crc over the whole message struct
+ *                     (i.e. message header + this struct) minus the last
+ *                     @crc16 field; unknown on all other fingers.
+ */
+struct tp_finger {
+       __le16 origin;
+       __le16 abs_x;
+       __le16 abs_y;
+       __le16 rel_x;
+       __le16 rel_y;
+       __le16 tool_major;
+       __le16 tool_minor;
+       __le16 orientation;
+       __le16 touch_major;
+       __le16 touch_minor;
+       __le16 unused[2];
+       __le16 pressure;
+       __le16 multi;
+       __le16 crc16;
+};
+
+/**
+ * struct touchpad_protocol - touchpad message.
+ * message.type = 0x0210
+ *
+ * @unknown1:          unknown
+ * @clicked:           1 if a button-click was detected, 0 otherwise
+ * @unknown2:          unknown
+ * @number_of_fingers: the number of fingers being reported in @fingers
+ * @clicked2:          same as @clicked
+ * @unknown3:          unknown
+ * @fingers:           the data for each finger
+ */
+struct touchpad_protocol {
+       u8                      unknown1[1];
+       u8                      clicked;
+       u8                      unknown2[28];
+       u8                      number_of_fingers;
+       u8                      clicked2;
+       u8                      unknown3[16];
+       struct tp_finger        fingers[0];
+};
+
+/**
+ * struct command_protocol_tp_info - get touchpad info.
+ * message.type = 0x1020, message.length = 0x0000
+ *
+ * @crc16:             crc over the whole message struct (message header +
+ *                     this struct) minus this @crc16 field
+ */
+struct command_protocol_tp_info {
+       __le16                  crc16;
+};
+
+/**
+ * struct touchpad_info - touchpad info response.
+ * message.type = 0x1020, message.length = 0x006e
+ *
+ * @unknown1:          unknown
+ * @model_flags:       flags (vary by model number, but significance otherwise
+ *                     unknown)
+ * @model_no:          the touchpad model number
+ * @unknown2:          unknown
+ * @crc16:             crc over the whole message struct (message header +
+ *                     this struct) minus this @crc16 field
+ */
+struct touchpad_info_protocol {
+       u8                      unknown1[105];
+       u8                      model_flags;
+       u8                      model_no;
+       u8                      unknown2[3];
+       __le16                  crc16;
+};
+
+/**
+ * struct command_protocol_mt_init - initialize multitouch.
+ * message.type = 0x0252, message.length = 0x0002
+ *
+ * @cmd:               value: 0x0102
+ * @crc16:             crc over the whole message struct (message header +
+ *                     this struct) minus this @crc16 field
+ */
+struct command_protocol_mt_init {
+       __le16                  cmd;
+       __le16                  crc16;
+};
+
+/**
+ * struct command_protocol_capsl - toggle caps-lock led
+ * message.type = 0x0151, message.length = 0x0002
+ *
+ * @unknown:           value: 0x01 (length?)
+ * @led:               0 off, 2 on
+ * @crc16:             crc over the whole message struct (message header +
+ *                     this struct) minus this @crc16 field
+ */
+struct command_protocol_capsl {
+       u8                      unknown;
+       u8                      led;
+       __le16                  crc16;
+};
+
+/**
+ * struct command_protocol_bl - set keyboard backlight brightness
+ * message.type = 0xB051, message.length = 0x0006
+ *
+ * @const1:            value: 0x01B0
+ * @level:             the brightness level to set
+ * @const2:            value: 0x0001 (backlight off), 0x01F4 (backlight on)
+ * @crc16:             crc over the whole message struct (message header +
+ *                     this struct) minus this @crc16 field
+ */
+struct command_protocol_bl {
+       __le16                  const1;
+       __le16                  level;
+       __le16                  const2;
+       __le16                  crc16;
+};
+
+/**
+ * struct message - a complete spi message.
+ *
+ * Each message begins with fixed header, followed by a message-type specific
+ * payload, and ends with a 16-bit crc. Because of the varying lengths of the
+ * payload, the crc is defined at the end of each payload struct, rather than
+ * in this struct.
+ *
+ * @type:      the message type
+ * @zero:      always 0
+ * @counter:   incremented on each message, rolls over after 255; there is a
+ *             separate counter for each message type.
+ * @rsp_buf_len:response buffer length (the exact nature of this field is quite
+ *             speculative). On a request/write this is often the same as
+ *             @length, though in some cases it has been seen to be much larger
+ *             (e.g. 0x400); on a response/read this the same as on the
+ *             request; for reads that are not responses it is 0.
+ * @length:    length of the remainder of the data in the whole message
+ *             structure (after re-assembly in case of being split over
+ *             multiple spi-packets), minus the trailing crc. The total size
+ *             of the message struct is therefore @length + 10.
+ */
+struct message {
+       __le16          type;
+       u8              zero;
+       u8              counter;
+       __le16          rsp_buf_len;
+       __le16          length;
+       union {
+               struct keyboard_protocol        keyboard;
+               struct touchpad_protocol        touchpad;
+               struct touchpad_info_protocol   tp_info;
+               struct command_protocol_tp_info tp_info_command;
+               struct command_protocol_mt_init init_mt_command;
+               struct command_protocol_capsl   capsl_command;
+               struct command_protocol_bl      bl_command;
+               u8                              data[0];
+       };
+};
+
+/* type + zero + counter + rsp_buf_len + length */
+#define MSG_HEADER_SIZE                8
+
+/**
+ * struct spi_packet - a complete spi packet; always 256 bytes. This carries
+ * the (parts of the) message in the data. But note that this does not
+ * necessarily contain a complete message, as in some cases (e.g. many
+ * fingers pressed) the message is split over multiple packets (see the
+ * @offset, @remaining, and @length fields). In general the data parts in
+ * spi_packet's are concatenated until @remaining is 0, and the result is an
+ * message.
+ *
+ * @flags:     0x40 = write (to device), 0x20 = read (from device); note that
+ *             the response to a write still has 0x40.
+ * @device:    1 = keyboard, 2 = touchpad
+ * @offset:    specifies the offset of this packet's data in the complete
+ *             message; i.e. > 0 indicates this is a continuation packet (in
+ *             the second packet for a message split over multiple packets
+ *             this would then be the same as the @length in the first packet)
+ * @remaining: number of message bytes remaining in subsequents packets (in
+ *             the first packet of a message split over two packets this would
+ *             then be the same as the @length in the second packet)
+ * @length:    length of the valid data in the @data in this packet
+ * @data:      all or part of a message
+ * @crc16:     crc over this whole structure minus this @crc16 field. This
+ *             covers just this packet, even on multi-packet messages (in
+ *             contrast to the crc in the message).
+ */
+struct spi_packet {
+       u8                      flags;
+       u8                      device;
+       __le16                  offset;
+       __le16                  remaining;
+       __le16                  length;
+       u8                      data[246];
+       __le16                  crc16;
+};
+
+struct spi_settings {
+       u64     spi_cs_delay;           /* cs-to-clk delay in us */
+       u64     reset_a2r_usec;         /* active-to-receive delay? */
+       u64     reset_rec_usec;         /* ? (cur val: 10) */
+};
+
+/* this mimics struct drm_rect */
+struct applespi_tp_info {
+       int     x_min;
+       int     y_min;
+       int     x_max;
+       int     y_max;
+};
+
+struct applespi_data {
+       struct spi_device               *spi;
+       struct spi_settings             spi_settings;
+       struct input_dev                *keyboard_input_dev;
+       struct input_dev                *touchpad_input_dev;
+
+       u8                              *tx_buffer;
+       u8                              *tx_status;
+       u8                              *rx_buffer;
+
+       u8                              *msg_buf;
+       unsigned int                    saved_msg_len;
+
+       struct applespi_tp_info         tp_info;
+
+       u8                              last_keys_pressed[MAX_ROLLOVER];
+       u8                              last_keys_fn_pressed[MAX_ROLLOVER];
+       u8                              last_fn_pressed;
+       struct input_mt_pos             pos[MAX_FINGERS];
+       int                             slots[MAX_FINGERS];
+       int                             gpe;
+       acpi_handle                     sien;
+       acpi_handle                     sist;
+
+       struct spi_transfer             dl_t;
+       struct spi_transfer             rd_t;
+       struct spi_message              rd_m;
+
+       struct spi_transfer             ww_t;
+       struct spi_transfer             wd_t;
+       struct spi_transfer             wr_t;
+       struct spi_transfer             st_t;
+       struct spi_message              wr_m;
+
+       bool                            want_tp_info_cmd;
+       bool                            want_mt_init_cmd;
+       bool                            want_cl_led_on;
+       bool                            have_cl_led_on;
+       unsigned int                    want_bl_level;
+       unsigned int                    have_bl_level;
+       unsigned int                    cmd_msg_cntr;
+       /* lock to protect the above parameters and flags below */
+       spinlock_t                      cmd_msg_lock;
+       bool                            cmd_msg_queued;
+       enum applespi_evt_type          cmd_evt_type;
+
+       struct led_classdev             backlight_info;
+
+       bool                            suspended;
+       bool                            drain;
+       wait_queue_head_t               drain_complete;
+       bool                            read_active;
+       bool                            write_active;
+
+       struct work_struct              work;
+       struct touchpad_info_protocol   rcvd_tp_info;
+
+       struct dentry                   *debugfs_root;
+       bool                            debug_tp_dim;
+       char                            tp_dim_val[40];
+       int                             tp_dim_min_x;
+       int                             tp_dim_max_x;
+       int                             tp_dim_min_y;
+       int                             tp_dim_max_y;
+};
+
+static const unsigned char applespi_scancodes[] = {
+       0, 0, 0, 0,
+       KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J,
+       KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T,
+       KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z,
+       KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0,
+       KEY_ENTER, KEY_ESC, KEY_BACKSPACE, KEY_TAB, KEY_SPACE, KEY_MINUS,
+       KEY_EQUAL, KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_BACKSLASH, 0,
+       KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA, KEY_DOT, KEY_SLASH,
+       KEY_CAPSLOCK,
+       KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9,
+       KEY_F10, KEY_F11, KEY_F12, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       KEY_RIGHT, KEY_LEFT, KEY_DOWN, KEY_UP,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_102ND,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RO, 0, KEY_YEN, 0, 0, 0, 0, 0,
+       0, KEY_KATAKANAHIRAGANA, KEY_MUHENKAN
+};
+
+/*
+ * This must have exactly as many entries as there are bits in
+ * struct keyboard_protocol.modifiers .
+ */
+static const unsigned char applespi_controlcodes[] = {
+       KEY_LEFTCTRL,
+       KEY_LEFTSHIFT,
+       KEY_LEFTALT,
+       KEY_LEFTMETA,
+       0,
+       KEY_RIGHTSHIFT,
+       KEY_RIGHTALT,
+       KEY_RIGHTMETA
+};
+
+struct applespi_key_translation {
+       u16 from;
+       u16 to;
+       u8 flags;
+};
+
+static const struct applespi_key_translation applespi_fn_codes[] = {
+       { KEY_BACKSPACE, KEY_DELETE },
+       { KEY_ENTER,    KEY_INSERT },
+       { KEY_F1,       KEY_BRIGHTNESSDOWN,     APPLE_FLAG_FKEY },
+       { KEY_F2,       KEY_BRIGHTNESSUP,       APPLE_FLAG_FKEY },
+       { KEY_F3,       KEY_SCALE,              APPLE_FLAG_FKEY },
+       { KEY_F4,       KEY_DASHBOARD,          APPLE_FLAG_FKEY },
+       { KEY_F5,       KEY_KBDILLUMDOWN,       APPLE_FLAG_FKEY },
+       { KEY_F6,       KEY_KBDILLUMUP,         APPLE_FLAG_FKEY },
+       { KEY_F7,       KEY_PREVIOUSSONG,       APPLE_FLAG_FKEY },
+       { KEY_F8,       KEY_PLAYPAUSE,          APPLE_FLAG_FKEY },
+       { KEY_F9,       KEY_NEXTSONG,           APPLE_FLAG_FKEY },
+       { KEY_F10,      KEY_MUTE,               APPLE_FLAG_FKEY },
+       { KEY_F11,      KEY_VOLUMEDOWN,         APPLE_FLAG_FKEY },
+       { KEY_F12,      KEY_VOLUMEUP,           APPLE_FLAG_FKEY },
+       { KEY_RIGHT,    KEY_END },
+       { KEY_LEFT,     KEY_HOME },
+       { KEY_DOWN,     KEY_PAGEDOWN },
+       { KEY_UP,       KEY_PAGEUP },
+       { }
+};
+
+static const struct applespi_key_translation apple_iso_keyboard[] = {
+       { KEY_GRAVE,    KEY_102ND },
+       { KEY_102ND,    KEY_GRAVE },
+       { }
+};
+
+struct applespi_tp_model_info {
+       u16                     model;
+       struct applespi_tp_info tp_info;
+};
+
+static const struct applespi_tp_model_info applespi_tp_models[] = {
+       {
+               .model = 0x04,  /* MB8 MB9 MB10 */
+               .tp_info = { -5087, -182, 5579, 6089 },
+       },
+       {
+               .model = 0x05,  /* MBP13,1 MBP13,2 MBP14,1 MBP14,2 */
+               .tp_info = { -6243, -170, 6749, 7685 },
+       },
+       {
+               .model = 0x06,  /* MBP13,3 MBP14,3 */
+               .tp_info = { -7456, -163, 7976, 9283 },
+       },
+       {}
+};
+
+typedef void (*applespi_trace_fun)(enum applespi_evt_type,
+                                  enum applespi_pkt_type, u8 *, size_t);
+
+static applespi_trace_fun applespi_get_trace_fun(enum applespi_evt_type type)
+{
+       switch (type) {
+       case ET_CMD_TP_INI:
+               return trace_applespi_tp_ini_cmd;
+       case ET_CMD_BL:
+               return trace_applespi_backlight_cmd;
+       case ET_CMD_CL:
+               return trace_applespi_caps_lock_cmd;
+       case ET_RD_KEYB:
+               return trace_applespi_keyboard_data;
+       case ET_RD_TPAD:
+               return trace_applespi_touchpad_data;
+       case ET_RD_UNKN:
+               return trace_applespi_unknown_data;
+       default:
+               WARN_ONCE(1, "Unknown msg type %d", type);
+               return trace_applespi_unknown_data;
+       }
+}
+
+static void applespi_setup_read_txfrs(struct applespi_data *applespi)
+{
+       struct spi_message *msg = &applespi->rd_m;
+       struct spi_transfer *dl_t = &applespi->dl_t;
+       struct spi_transfer *rd_t = &applespi->rd_t;
+
+       memset(dl_t, 0, sizeof(*dl_t));
+       memset(rd_t, 0, sizeof(*rd_t));
+
+       dl_t->delay_usecs = applespi->spi_settings.spi_cs_delay;
+
+       rd_t->rx_buf = applespi->rx_buffer;
+       rd_t->len = APPLESPI_PACKET_SIZE;
+
+       spi_message_init(msg);
+       spi_message_add_tail(dl_t, msg);
+       spi_message_add_tail(rd_t, msg);
+}
+
+static void applespi_setup_write_txfrs(struct applespi_data *applespi)
+{
+       struct spi_message *msg = &applespi->wr_m;
+       struct spi_transfer *wt_t = &applespi->ww_t;
+       struct spi_transfer *dl_t = &applespi->wd_t;
+       struct spi_transfer *wr_t = &applespi->wr_t;
+       struct spi_transfer *st_t = &applespi->st_t;
+
+       memset(wt_t, 0, sizeof(*wt_t));
+       memset(dl_t, 0, sizeof(*dl_t));
+       memset(wr_t, 0, sizeof(*wr_t));
+       memset(st_t, 0, sizeof(*st_t));
+
+       /*
+        * All we need here is a delay at the beginning of the message before
+        * asserting cs. But the current spi API doesn't support this, so we
+        * end up with an extra unnecessary (but harmless) cs assertion and
+        * deassertion.
+        */
+       wt_t->delay_usecs = SPI_RW_CHG_DELAY_US;
+       wt_t->cs_change = 1;
+
+       dl_t->delay_usecs = applespi->spi_settings.spi_cs_delay;
+
+       wr_t->tx_buf = applespi->tx_buffer;
+       wr_t->len = APPLESPI_PACKET_SIZE;
+       wr_t->delay_usecs = SPI_RW_CHG_DELAY_US;
+
+       st_t->rx_buf = applespi->tx_status;
+       st_t->len = APPLESPI_STATUS_SIZE;
+
+       spi_message_init(msg);
+       spi_message_add_tail(wt_t, msg);
+       spi_message_add_tail(dl_t, msg);
+       spi_message_add_tail(wr_t, msg);
+       spi_message_add_tail(st_t, msg);
+}
+
+static int applespi_async(struct applespi_data *applespi,
+                         struct spi_message *message, void (*complete)(void *))
+{
+       message->complete = complete;
+       message->context = applespi;
+
+       return spi_async(applespi->spi, message);
+}
+
+static inline bool applespi_check_write_status(struct applespi_data *applespi,
+                                              int sts)
+{
+       static u8 status_ok[] = { 0xac, 0x27, 0x68, 0xd5 };
+
+       if (sts < 0) {
+               dev_warn(&applespi->spi->dev, "Error writing to device: %d\n",
+                        sts);
+               return false;
+       }
+
+       if (memcmp(applespi->tx_status, status_ok, APPLESPI_STATUS_SIZE)) {
+               dev_warn(&applespi->spi->dev, "Error writing to device: %*ph\n",
+                        APPLESPI_STATUS_SIZE, applespi->tx_status);
+               return false;
+       }
+
+       return true;
+}
+
+static int applespi_get_spi_settings(struct applespi_data *applespi)
+{
+       struct acpi_device *adev = ACPI_COMPANION(&applespi->spi->dev);
+       const union acpi_object *o;
+       struct spi_settings *settings = &applespi->spi_settings;
+
+       if (!acpi_dev_get_property(adev, "spiCSDelay", ACPI_TYPE_BUFFER, &o))
+               settings->spi_cs_delay = *(u64 *)o->buffer.pointer;
+       else
+               dev_warn(&applespi->spi->dev,
+                        "Property spiCSDelay not found\n");
+
+       if (!acpi_dev_get_property(adev, "resetA2RUsec", ACPI_TYPE_BUFFER, &o))
+               settings->reset_a2r_usec = *(u64 *)o->buffer.pointer;
+       else
+               dev_warn(&applespi->spi->dev,
+                        "Property resetA2RUsec not found\n");
+
+       if (!acpi_dev_get_property(adev, "resetRecUsec", ACPI_TYPE_BUFFER, &o))
+               settings->reset_rec_usec = *(u64 *)o->buffer.pointer;
+       else
+               dev_warn(&applespi->spi->dev,
+                        "Property resetRecUsec not found\n");
+
+       dev_dbg(&applespi->spi->dev,
+               "SPI settings: spi_cs_delay=%llu reset_a2r_usec=%llu reset_rec_usec=%llu\n",
+               settings->spi_cs_delay, settings->reset_a2r_usec,
+               settings->reset_rec_usec);
+
+       return 0;
+}
+
+static int applespi_setup_spi(struct applespi_data *applespi)
+{
+       int sts;
+
+       sts = applespi_get_spi_settings(applespi);
+       if (sts)
+               return sts;
+
+       spin_lock_init(&applespi->cmd_msg_lock);
+       init_waitqueue_head(&applespi->drain_complete);
+
+       return 0;
+}
+
+static int applespi_enable_spi(struct applespi_data *applespi)
+{
+       acpi_status acpi_sts;
+       unsigned long long spi_status;
+
+       /* check if SPI is already enabled, so we can skip the delay below */
+       acpi_sts = acpi_evaluate_integer(applespi->sist, NULL, NULL,
+                                        &spi_status);
+       if (ACPI_SUCCESS(acpi_sts) && spi_status)
+               return 0;
+
+       /* SIEN(1) will enable SPI communication */
+       acpi_sts = acpi_execute_simple_method(applespi->sien, NULL, 1);
+       if (ACPI_FAILURE(acpi_sts)) {
+               dev_err(&applespi->spi->dev, "SIEN failed: %s\n",
+                       acpi_format_exception(acpi_sts));
+               return -ENODEV;
+       }
+
+       /*
+        * Allow the SPI interface to come up before returning. Without this
+        * delay, the SPI commands to enable multitouch mode may not reach
+        * the trackpad controller, causing pointer movement to break upon
+        * resume from sleep.
+        */
+       msleep(50);
+
+       return 0;
+}
+
+static int applespi_send_cmd_msg(struct applespi_data *applespi);
+
+static void applespi_msg_complete(struct applespi_data *applespi,
+                                 bool is_write_msg, bool is_read_compl)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+       if (is_read_compl)
+               applespi->read_active = false;
+       if (is_write_msg)
+               applespi->write_active = false;
+
+       if (applespi->drain && !applespi->write_active)
+               wake_up_all(&applespi->drain_complete);
+
+       if (is_write_msg) {
+               applespi->cmd_msg_queued = false;
+               applespi_send_cmd_msg(applespi);
+       }
+
+       spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+}
+
+static void applespi_async_write_complete(void *context)
+{
+       struct applespi_data *applespi = context;
+       enum applespi_evt_type evt_type = applespi->cmd_evt_type;
+
+       applespi_get_trace_fun(evt_type)(evt_type, PT_WRITE,
+                                        applespi->tx_buffer,
+                                        APPLESPI_PACKET_SIZE);
+       applespi_get_trace_fun(evt_type)(evt_type, PT_STATUS,
+                                        applespi->tx_status,
+                                        APPLESPI_STATUS_SIZE);
+
+       if (!applespi_check_write_status(applespi, applespi->wr_m.status)) {
+               /*
+                * If we got an error, we presumably won't get the expected
+                * response message either.
+                */
+               applespi_msg_complete(applespi, true, false);
+       }
+}
+
+static int applespi_send_cmd_msg(struct applespi_data *applespi)
+{
+       u16 crc;
+       int sts;
+       struct spi_packet *packet = (struct spi_packet *)applespi->tx_buffer;
+       struct message *message = (struct message *)packet->data;
+       u16 msg_len;
+       u8 device;
+
+       /* check if draining */
+       if (applespi->drain)
+               return 0;
+
+       /* check whether send is in progress */
+       if (applespi->cmd_msg_queued)
+               return 0;
+
+       /* set up packet */
+       memset(packet, 0, APPLESPI_PACKET_SIZE);
+
+       /* are we processing init commands? */
+       if (applespi->want_tp_info_cmd) {
+               applespi->want_tp_info_cmd = false;
+               applespi->want_mt_init_cmd = true;
+               applespi->cmd_evt_type = ET_CMD_TP_INI;
+
+               /* build init command */
+               device = PACKET_DEV_INFO;
+
+               message->type = cpu_to_le16(0x1020);
+               msg_len = sizeof(message->tp_info_command);
+
+               message->zero = 0x02;
+               message->rsp_buf_len = cpu_to_le16(0x0200);
+
+       } else if (applespi->want_mt_init_cmd) {
+               applespi->want_mt_init_cmd = false;
+               applespi->cmd_evt_type = ET_CMD_TP_INI;
+
+               /* build init command */
+               device = PACKET_DEV_TPAD;
+
+               message->type = cpu_to_le16(0x0252);
+               msg_len = sizeof(message->init_mt_command);
+
+               message->init_mt_command.cmd = cpu_to_le16(0x0102);
+
+       /* do we need caps-lock command? */
+       } else if (applespi->want_cl_led_on != applespi->have_cl_led_on) {
+               applespi->have_cl_led_on = applespi->want_cl_led_on;
+               applespi->cmd_evt_type = ET_CMD_CL;
+
+               /* build led command */
+               device = PACKET_DEV_KEYB;
+
+               message->type = cpu_to_le16(0x0151);
+               msg_len = sizeof(message->capsl_command);
+
+               message->capsl_command.unknown = 0x01;
+               message->capsl_command.led = applespi->have_cl_led_on ? 2 : 0;
+
+       /* do we need backlight command? */
+       } else if (applespi->want_bl_level != applespi->have_bl_level) {
+               applespi->have_bl_level = applespi->want_bl_level;
+               applespi->cmd_evt_type = ET_CMD_BL;
+
+               /* build command buffer */
+               device = PACKET_DEV_KEYB;
+
+               message->type = cpu_to_le16(0xB051);
+               msg_len = sizeof(message->bl_command);
+
+               message->bl_command.const1 = cpu_to_le16(0x01B0);
+               message->bl_command.level =
+                               cpu_to_le16(applespi->have_bl_level);
+
+               if (applespi->have_bl_level > 0)
+                       message->bl_command.const2 = cpu_to_le16(0x01F4);
+               else
+                       message->bl_command.const2 = cpu_to_le16(0x0001);
+
+       /* everything's up-to-date */
+       } else {
+               return 0;
+       }
+
+       /* finalize packet */
+       packet->flags = PACKET_TYPE_WRITE;
+       packet->device = device;
+       packet->length = cpu_to_le16(MSG_HEADER_SIZE + msg_len);
+
+       message->counter = applespi->cmd_msg_cntr++ % (U8_MAX + 1);
+
+       message->length = cpu_to_le16(msg_len - 2);
+       if (!message->rsp_buf_len)
+               message->rsp_buf_len = message->length;
+
+       crc = crc16(0, (u8 *)message, le16_to_cpu(packet->length) - 2);
+       put_unaligned_le16(crc, &message->data[msg_len - 2]);
+
+       crc = crc16(0, (u8 *)packet, sizeof(*packet) - 2);
+       packet->crc16 = cpu_to_le16(crc);
+
+       /* send command */
+       sts = applespi_async(applespi, &applespi->wr_m,
+                            applespi_async_write_complete);
+       if (sts) {
+               dev_warn(&applespi->spi->dev,
+                        "Error queueing async write to device: %d\n", sts);
+               return sts;
+       }
+
+       applespi->cmd_msg_queued = true;
+       applespi->write_active = true;
+
+       return 0;
+}
+
+static void applespi_init(struct applespi_data *applespi, bool is_resume)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+       if (is_resume)
+               applespi->want_mt_init_cmd = true;
+       else
+               applespi->want_tp_info_cmd = true;
+       applespi_send_cmd_msg(applespi);
+
+       spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+}
+
+static int applespi_set_capsl_led(struct applespi_data *applespi,
+                                 bool capslock_on)
+{
+       unsigned long flags;
+       int sts;
+
+       spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+       applespi->want_cl_led_on = capslock_on;
+       sts = applespi_send_cmd_msg(applespi);
+
+       spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+
+       return sts;
+}
+
+static void applespi_set_bl_level(struct led_classdev *led_cdev,
+                                 enum led_brightness value)
+{
+       struct applespi_data *applespi =
+               container_of(led_cdev, struct applespi_data, backlight_info);
+       unsigned long flags;
+
+       spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+       if (value == 0) {
+               applespi->want_bl_level = value;
+       } else {
+               /*
+                * The backlight does not turn on till level 32, so we scale
+                * the range here so that from a user's perspective it turns
+                * on at 1.
+                */
+               applespi->want_bl_level =
+                       ((value * KBD_BL_LEVEL_ADJ) / KBD_BL_LEVEL_SCALE +
+                        KBD_BL_LEVEL_MIN);
+       }
+
+       applespi_send_cmd_msg(applespi);
+
+       spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+}
+
+static int applespi_event(struct input_dev *dev, unsigned int type,
+                         unsigned int code, int value)
+{
+       struct applespi_data *applespi = input_get_drvdata(dev);
+
+       switch (type) {
+       case EV_LED:
+               applespi_set_capsl_led(applespi, !!test_bit(LED_CAPSL, dev->led));
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+/* lifted from the BCM5974 driver and renamed from raw2int */
+/* convert 16-bit little endian to signed integer */
+static inline int le16_to_int(__le16 x)
+{
+       return (signed short)le16_to_cpu(x);
+}
+
+static void applespi_debug_update_dimensions(struct applespi_data *applespi,
+                                            const struct tp_finger *f)
+{
+       applespi->tp_dim_min_x = min_t(int, applespi->tp_dim_min_x, f->abs_x);
+       applespi->tp_dim_max_x = max_t(int, applespi->tp_dim_max_x, f->abs_x);
+       applespi->tp_dim_min_y = min_t(int, applespi->tp_dim_min_y, f->abs_y);
+       applespi->tp_dim_max_y = max_t(int, applespi->tp_dim_max_y, f->abs_y);
+}
+
+static int applespi_tp_dim_open(struct inode *inode, struct file *file)
+{
+       struct applespi_data *applespi = inode->i_private;
+
+       file->private_data = applespi;
+
+       snprintf(applespi->tp_dim_val, sizeof(applespi->tp_dim_val),
+                "0x%.4x %dx%d+%u+%u\n",
+                applespi->touchpad_input_dev->id.product,
+                applespi->tp_dim_min_x, applespi->tp_dim_min_y,
+                applespi->tp_dim_max_x - applespi->tp_dim_min_x,
+                applespi->tp_dim_max_y - applespi->tp_dim_min_y);
+
+       return nonseekable_open(inode, file);
+}
+
+static ssize_t applespi_tp_dim_read(struct file *file, char __user *buf,
+                                   size_t len, loff_t *off)
+{
+       struct applespi_data *applespi = file->private_data;
+
+       return simple_read_from_buffer(buf, len, off, applespi->tp_dim_val,
+                                      strlen(applespi->tp_dim_val));
+}
+
+static const struct file_operations applespi_tp_dim_fops = {
+       .owner = THIS_MODULE,
+       .open = applespi_tp_dim_open,
+       .read = applespi_tp_dim_read,
+       .llseek = no_llseek,
+};
+
+static void report_finger_data(struct input_dev *input, int slot,
+                              const struct input_mt_pos *pos,
+                              const struct tp_finger *f)
+{
+       input_mt_slot(input, slot);
+       input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
+
+       input_report_abs(input, ABS_MT_TOUCH_MAJOR,
+                        le16_to_int(f->touch_major) << 1);
+       input_report_abs(input, ABS_MT_TOUCH_MINOR,
+                        le16_to_int(f->touch_minor) << 1);
+       input_report_abs(input, ABS_MT_WIDTH_MAJOR,
+                        le16_to_int(f->tool_major) << 1);
+       input_report_abs(input, ABS_MT_WIDTH_MINOR,
+                        le16_to_int(f->tool_minor) << 1);
+       input_report_abs(input, ABS_MT_ORIENTATION,
+                        MAX_FINGER_ORIENTATION - le16_to_int(f->orientation));
+       input_report_abs(input, ABS_MT_POSITION_X, pos->x);
+       input_report_abs(input, ABS_MT_POSITION_Y, pos->y);
+}
+
+static void report_tp_state(struct applespi_data *applespi,
+                           struct touchpad_protocol *t)
+{
+       const struct tp_finger *f;
+       struct input_dev *input;
+       const struct applespi_tp_info *tp_info = &applespi->tp_info;
+       int i, n;
+
+       /* touchpad_input_dev is set async in worker */
+       input = smp_load_acquire(&applespi->touchpad_input_dev);
+       if (!input)
+               return; /* touchpad isn't initialized yet */
+
+       n = 0;
+
+       for (i = 0; i < t->number_of_fingers; i++) {
+               f = &t->fingers[i];
+               if (le16_to_int(f->touch_major) == 0)
+                       continue;
+               applespi->pos[n].x = le16_to_int(f->abs_x);
+               applespi->pos[n].y = tp_info->y_min + tp_info->y_max -
+                                    le16_to_int(f->abs_y);
+               n++;
+
+               if (applespi->debug_tp_dim)
+                       applespi_debug_update_dimensions(applespi, f);
+       }
+
+       input_mt_assign_slots(input, applespi->slots, applespi->pos, n, 0);
+
+       for (i = 0; i < n; i++)
+               report_finger_data(input, applespi->slots[i],
+                                  &applespi->pos[i], &t->fingers[i]);
+
+       input_mt_sync_frame(input);
+       input_report_key(input, BTN_LEFT, t->clicked);
+
+       input_sync(input);
+}
+
+static const struct applespi_key_translation *
+applespi_find_translation(const struct applespi_key_translation *table, u16 key)
+{
+       const struct applespi_key_translation *trans;
+
+       for (trans = table; trans->from; trans++)
+               if (trans->from == key)
+                       return trans;
+
+       return NULL;
+}
+
+static unsigned int applespi_translate_fn_key(unsigned int key, int fn_pressed)
+{
+       const struct applespi_key_translation *trans;
+       int do_translate;
+
+       trans = applespi_find_translation(applespi_fn_codes, key);
+       if (trans) {
+               if (trans->flags & APPLE_FLAG_FKEY)
+                       do_translate = (fnmode == 2 && fn_pressed) ||
+                                      (fnmode == 1 && !fn_pressed);
+               else
+                       do_translate = fn_pressed;
+
+               if (do_translate)
+                       key = trans->to;
+       }
+
+       return key;
+}
+
+static unsigned int applespi_translate_iso_layout(unsigned int key)
+{
+       const struct applespi_key_translation *trans;
+
+       trans = applespi_find_translation(apple_iso_keyboard, key);
+       if (trans)
+               key = trans->to;
+
+       return key;
+}
+
+static unsigned int applespi_code_to_key(u8 code, int fn_pressed)
+{
+       unsigned int key = applespi_scancodes[code];
+
+       if (fnmode)
+               key = applespi_translate_fn_key(key, fn_pressed);
+       if (iso_layout)
+               key = applespi_translate_iso_layout(key);
+       return key;
+}
+
+static void
+applespi_remap_fn_key(struct keyboard_protocol *keyboard_protocol)
+{
+       unsigned char tmp;
+       u8 bit = BIT((fnremap - 1) & 0x07);
+
+       if (!fnremap || fnremap > ARRAY_SIZE(applespi_controlcodes) ||
+           !applespi_controlcodes[fnremap - 1])
+               return;
+
+       tmp = keyboard_protocol->fn_pressed;
+       keyboard_protocol->fn_pressed = !!(keyboard_protocol->modifiers & bit);
+       if (tmp)
+               keyboard_protocol->modifiers |= bit;
+       else
+               keyboard_protocol->modifiers &= ~bit;
+}
+
+static void
+applespi_handle_keyboard_event(struct applespi_data *applespi,
+                              struct keyboard_protocol *keyboard_protocol)
+{
+       unsigned int key;
+       int i;
+
+       compiletime_assert(ARRAY_SIZE(applespi_controlcodes) ==
+                          sizeof_field(struct keyboard_protocol, modifiers) * 8,
+                          "applespi_controlcodes has wrong number of entries");
+
+       /* check for rollover overflow, which is signalled by all keys == 1 */
+       if (!memchr_inv(keyboard_protocol->keys_pressed, 1, MAX_ROLLOVER))
+               return;
+
+       /* remap fn key if desired */
+       applespi_remap_fn_key(keyboard_protocol);
+
+       /* check released keys */
+       for (i = 0; i < MAX_ROLLOVER; i++) {
+               if (memchr(keyboard_protocol->keys_pressed,
+                          applespi->last_keys_pressed[i], MAX_ROLLOVER))
+                       continue;       /* key is still pressed */
+
+               key = applespi_code_to_key(applespi->last_keys_pressed[i],
+                                          applespi->last_keys_fn_pressed[i]);
+               input_report_key(applespi->keyboard_input_dev, key, 0);
+               applespi->last_keys_fn_pressed[i] = 0;
+       }
+
+       /* check pressed keys */
+       for (i = 0; i < MAX_ROLLOVER; i++) {
+               if (keyboard_protocol->keys_pressed[i] <
+                               ARRAY_SIZE(applespi_scancodes) &&
+                   keyboard_protocol->keys_pressed[i] > 0) {
+                       key = applespi_code_to_key(
+                                       keyboard_protocol->keys_pressed[i],
+                                       keyboard_protocol->fn_pressed);
+                       input_report_key(applespi->keyboard_input_dev, key, 1);
+                       applespi->last_keys_fn_pressed[i] =
+                                       keyboard_protocol->fn_pressed;
+               }
+       }
+
+       /* check control keys */
+       for (i = 0; i < ARRAY_SIZE(applespi_controlcodes); i++) {
+               if (keyboard_protocol->modifiers & BIT(i))
+                       input_report_key(applespi->keyboard_input_dev,
+                                        applespi_controlcodes[i], 1);
+               else
+                       input_report_key(applespi->keyboard_input_dev,
+                                        applespi_controlcodes[i], 0);
+       }
+
+       /* check function key */
+       if (keyboard_protocol->fn_pressed && !applespi->last_fn_pressed)
+               input_report_key(applespi->keyboard_input_dev, KEY_FN, 1);
+       else if (!keyboard_protocol->fn_pressed && applespi->last_fn_pressed)
+               input_report_key(applespi->keyboard_input_dev, KEY_FN, 0);
+       applespi->last_fn_pressed = keyboard_protocol->fn_pressed;
+
+       /* done */
+       input_sync(applespi->keyboard_input_dev);
+       memcpy(&applespi->last_keys_pressed, keyboard_protocol->keys_pressed,
+              sizeof(applespi->last_keys_pressed));
+}
+
+static const struct applespi_tp_info *applespi_find_touchpad_info(u8 model)
+{
+       const struct applespi_tp_model_info *info;
+
+       for (info = applespi_tp_models; info->model; info++) {
+               if (info->model == model)
+                       return &info->tp_info;
+       }
+
+       return NULL;
+}
+
+static int
+applespi_register_touchpad_device(struct applespi_data *applespi,
+                                 struct touchpad_info_protocol *rcvd_tp_info)
+{
+       const struct applespi_tp_info *tp_info;
+       struct input_dev *touchpad_input_dev;
+       int sts;
+
+       /* set up touchpad dimensions */
+       tp_info = applespi_find_touchpad_info(rcvd_tp_info->model_no);
+       if (!tp_info) {
+               dev_warn(&applespi->spi->dev,
+                        "Unknown touchpad model %x - falling back to MB8 touchpad\n",
+                        rcvd_tp_info->model_no);
+               tp_info = &applespi_tp_models[0].tp_info;
+       }
+
+       applespi->tp_info = *tp_info;
+
+       if (touchpad_dimensions[0]) {
+               int x, y, w, h;
+
+               sts = sscanf(touchpad_dimensions, "%dx%d+%u+%u", &x, &y, &w, &h);
+               if (sts == 4) {
+                       dev_info(&applespi->spi->dev,
+                                "Overriding touchpad dimensions from module param\n");
+                       applespi->tp_info.x_min = x;
+                       applespi->tp_info.y_min = y;
+                       applespi->tp_info.x_max = x + w;
+                       applespi->tp_info.y_max = y + h;
+               } else {
+                       dev_warn(&applespi->spi->dev,
+                                "Invalid touchpad dimensions '%s': must be in the form XxY+W+H\n",
+                                touchpad_dimensions);
+                       touchpad_dimensions[0] = '\0';
+               }
+       }
+       if (!touchpad_dimensions[0]) {
+               snprintf(touchpad_dimensions, sizeof(touchpad_dimensions),
+                        "%dx%d+%u+%u",
+                        applespi->tp_info.x_min,
+                        applespi->tp_info.y_min,
+                        applespi->tp_info.x_max - applespi->tp_info.x_min,
+                        applespi->tp_info.y_max - applespi->tp_info.y_min);
+       }
+
+       /* create touchpad input device */
+       touchpad_input_dev = devm_input_allocate_device(&applespi->spi->dev);
+       if (!touchpad_input_dev) {
+               dev_err(&applespi->spi->dev,
+                       "Failed to allocate touchpad input device\n");
+               return -ENOMEM;
+       }
+
+       touchpad_input_dev->name = "Apple SPI Touchpad";
+       touchpad_input_dev->phys = "applespi/input1";
+       touchpad_input_dev->dev.parent = &applespi->spi->dev;
+       touchpad_input_dev->id.bustype = BUS_SPI;
+       touchpad_input_dev->id.vendor = SYNAPTICS_VENDOR_ID;
+       touchpad_input_dev->id.product =
+                       rcvd_tp_info->model_no << 8 | rcvd_tp_info->model_flags;
+
+       /* basic properties */
+       input_set_capability(touchpad_input_dev, EV_REL, REL_X);
+       input_set_capability(touchpad_input_dev, EV_REL, REL_Y);
+
+       __set_bit(INPUT_PROP_POINTER, touchpad_input_dev->propbit);
+       __set_bit(INPUT_PROP_BUTTONPAD, touchpad_input_dev->propbit);
+
+       /* finger touch area */
+       input_set_abs_params(touchpad_input_dev, ABS_MT_TOUCH_MAJOR,
+                            0, 5000, 0, 0);
+       input_set_abs_params(touchpad_input_dev, ABS_MT_TOUCH_MINOR,
+                            0, 5000, 0, 0);
+
+       /* finger approach area */
+       input_set_abs_params(touchpad_input_dev, ABS_MT_WIDTH_MAJOR,
+                            0, 5000, 0, 0);
+       input_set_abs_params(touchpad_input_dev, ABS_MT_WIDTH_MINOR,
+                            0, 5000, 0, 0);
+
+       /* finger orientation */
+       input_set_abs_params(touchpad_input_dev, ABS_MT_ORIENTATION,
+                            -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION,
+                            0, 0);
+
+       /* finger position */
+       input_set_abs_params(touchpad_input_dev, ABS_MT_POSITION_X,
+                            applespi->tp_info.x_min, applespi->tp_info.x_max,
+                            0, 0);
+       input_set_abs_params(touchpad_input_dev, ABS_MT_POSITION_Y,
+                            applespi->tp_info.y_min, applespi->tp_info.y_max,
+                            0, 0);
+
+       /* touchpad button */
+       input_set_capability(touchpad_input_dev, EV_KEY, BTN_LEFT);
+
+       /* multitouch */
+       sts = input_mt_init_slots(touchpad_input_dev, MAX_FINGERS,
+                                 INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED |
+                                       INPUT_MT_TRACK);
+       if (sts) {
+               dev_err(&applespi->spi->dev,
+                       "failed to initialize slots: %d", sts);
+               return sts;
+       }
+
+       /* register input device */
+       sts = input_register_device(touchpad_input_dev);
+       if (sts) {
+               dev_err(&applespi->spi->dev,
+                       "Unable to register touchpad input device (%d)\n", sts);
+               return sts;
+       }
+
+       /* touchpad_input_dev is read async in spi callback */
+       smp_store_release(&applespi->touchpad_input_dev, touchpad_input_dev);
+
+       return 0;
+}
+
+static void applespi_worker(struct work_struct *work)
+{
+       struct applespi_data *applespi =
+               container_of(work, struct applespi_data, work);
+
+       applespi_register_touchpad_device(applespi, &applespi->rcvd_tp_info);
+}
+
+static void applespi_handle_cmd_response(struct applespi_data *applespi,
+                                        struct spi_packet *packet,
+                                        struct message *message)
+{
+       if (packet->device == PACKET_DEV_INFO &&
+           le16_to_cpu(message->type) == 0x1020) {
+               /*
+                * We're not allowed to sleep here, but registering an input
+                * device can sleep.
+                */
+               applespi->rcvd_tp_info = message->tp_info;
+               schedule_work(&applespi->work);
+               return;
+       }
+
+       if (le16_to_cpu(message->length) != 0x0000) {
+               dev_warn_ratelimited(&applespi->spi->dev,
+                                    "Received unexpected write response: length=%x\n",
+                                    le16_to_cpu(message->length));
+               return;
+       }
+
+       if (packet->device == PACKET_DEV_TPAD &&
+           le16_to_cpu(message->type) == 0x0252 &&
+           le16_to_cpu(message->rsp_buf_len) == 0x0002)
+               dev_info(&applespi->spi->dev, "modeswitch done.\n");
+}
+
+static bool applespi_verify_crc(struct applespi_data *applespi, u8 *buffer,
+                               size_t buflen)
+{
+       u16 crc;
+
+       crc = crc16(0, buffer, buflen);
+       if (crc) {
+               dev_warn_ratelimited(&applespi->spi->dev,
+                                    "Received corrupted packet (crc mismatch)\n");
+               trace_applespi_bad_crc(ET_RD_CRC, READ, buffer, buflen);
+
+               return false;
+       }
+
+       return true;
+}
+
+static void applespi_debug_print_read_packet(struct applespi_data *applespi,
+                                            struct spi_packet *packet)
+{
+       unsigned int evt_type;
+
+       if (packet->flags == PACKET_TYPE_READ &&
+           packet->device == PACKET_DEV_KEYB)
+               evt_type = ET_RD_KEYB;
+       else if (packet->flags == PACKET_TYPE_READ &&
+                packet->device == PACKET_DEV_TPAD)
+               evt_type = ET_RD_TPAD;
+       else if (packet->flags == PACKET_TYPE_WRITE)
+               evt_type = applespi->cmd_evt_type;
+       else
+               evt_type = ET_RD_UNKN;
+
+       applespi_get_trace_fun(evt_type)(evt_type, PT_READ, applespi->rx_buffer,
+                                        APPLESPI_PACKET_SIZE);
+}
+
+static void applespi_got_data(struct applespi_data *applespi)
+{
+       struct spi_packet *packet;
+       struct message *message;
+       unsigned int msg_len;
+       unsigned int off;
+       unsigned int rem;
+       unsigned int len;
+
+       /* process packet header */
+       if (!applespi_verify_crc(applespi, applespi->rx_buffer,
+                                APPLESPI_PACKET_SIZE)) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+               if (applespi->drain) {
+                       applespi->read_active = false;
+                       applespi->write_active = false;
+
+                       wake_up_all(&applespi->drain_complete);
+               }
+
+               spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+
+               return;
+       }
+
+       packet = (struct spi_packet *)applespi->rx_buffer;
+
+       applespi_debug_print_read_packet(applespi, packet);
+
+       off = le16_to_cpu(packet->offset);
+       rem = le16_to_cpu(packet->remaining);
+       len = le16_to_cpu(packet->length);
+
+       if (len > sizeof(packet->data)) {
+               dev_warn_ratelimited(&applespi->spi->dev,
+                                    "Received corrupted packet (invalid packet length %u)\n",
+                                    len);
+               goto msg_complete;
+       }
+
+       /* handle multi-packet messages */
+       if (rem > 0 || off > 0) {
+               if (off != applespi->saved_msg_len) {
+                       dev_warn_ratelimited(&applespi->spi->dev,
+                                            "Received unexpected offset (got %u, expected %u)\n",
+                                            off, applespi->saved_msg_len);
+                       goto msg_complete;
+               }
+
+               if (off + rem > MAX_PKTS_PER_MSG * APPLESPI_PACKET_SIZE) {
+                       dev_warn_ratelimited(&applespi->spi->dev,
+                                            "Received message too large (size %u)\n",
+                                            off + rem);
+                       goto msg_complete;
+               }
+
+               if (off + len > MAX_PKTS_PER_MSG * APPLESPI_PACKET_SIZE) {
+                       dev_warn_ratelimited(&applespi->spi->dev,
+                                            "Received message too large (size %u)\n",
+                                            off + len);
+                       goto msg_complete;
+               }
+
+               memcpy(applespi->msg_buf + off, &packet->data, len);
+               applespi->saved_msg_len += len;
+
+               if (rem > 0)
+                       return;
+
+               message = (struct message *)applespi->msg_buf;
+               msg_len = applespi->saved_msg_len;
+       } else {
+               message = (struct message *)&packet->data;
+               msg_len = len;
+       }
+
+       /* got complete message - verify */
+       if (!applespi_verify_crc(applespi, (u8 *)message, msg_len))
+               goto msg_complete;
+
+       if (le16_to_cpu(message->length) != msg_len - MSG_HEADER_SIZE - 2) {
+               dev_warn_ratelimited(&applespi->spi->dev,
+                                    "Received corrupted packet (invalid message length %u - expected %u)\n",
+                                    le16_to_cpu(message->length),
+                                    msg_len - MSG_HEADER_SIZE - 2);
+               goto msg_complete;
+       }
+
+       /* handle message */
+       if (packet->flags == PACKET_TYPE_READ &&
+           packet->device == PACKET_DEV_KEYB) {
+               applespi_handle_keyboard_event(applespi, &message->keyboard);
+
+       } else if (packet->flags == PACKET_TYPE_READ &&
+                  packet->device == PACKET_DEV_TPAD) {
+               struct touchpad_protocol *tp;
+               size_t tp_len;
+
+               tp = &message->touchpad;
+               tp_len = sizeof(*tp) +
+                        tp->number_of_fingers * sizeof(tp->fingers[0]);
+
+               if (le16_to_cpu(message->length) + 2 != tp_len) {
+                       dev_warn_ratelimited(&applespi->spi->dev,
+                                            "Received corrupted packet (invalid message length %u - num-fingers %u, tp-len %zu)\n",
+                                            le16_to_cpu(message->length),
+                                            tp->number_of_fingers, tp_len);
+                       goto msg_complete;
+               }
+
+               if (tp->number_of_fingers > MAX_FINGERS) {
+                       dev_warn_ratelimited(&applespi->spi->dev,
+                                            "Number of reported fingers (%u) exceeds max (%u))\n",
+                                            tp->number_of_fingers,
+                                            MAX_FINGERS);
+                       tp->number_of_fingers = MAX_FINGERS;
+               }
+
+               report_tp_state(applespi, tp);
+
+       } else if (packet->flags == PACKET_TYPE_WRITE) {
+               applespi_handle_cmd_response(applespi, packet, message);
+       }
+
+msg_complete:
+       applespi->saved_msg_len = 0;
+
+       applespi_msg_complete(applespi, packet->flags == PACKET_TYPE_WRITE,
+                             true);
+}
+
+static void applespi_async_read_complete(void *context)
+{
+       struct applespi_data *applespi = context;
+
+       if (applespi->rd_m.status < 0) {
+               dev_warn(&applespi->spi->dev, "Error reading from device: %d\n",
+                        applespi->rd_m.status);
+               /*
+                * We don't actually know if this was a pure read, or a response
+                * to a write. But this is a rare error condition that should
+                * never occur, so clearing both flags to avoid deadlock.
+                */
+               applespi_msg_complete(applespi, true, true);
+       } else {
+               applespi_got_data(applespi);
+       }
+
+       acpi_finish_gpe(NULL, applespi->gpe);
+}
+
+static u32 applespi_notify(acpi_handle gpe_device, u32 gpe, void *context)
+{
+       struct applespi_data *applespi = context;
+       int sts;
+       unsigned long flags;
+
+       trace_applespi_irq_received(ET_RD_IRQ, PT_READ);
+
+       spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+       if (!applespi->suspended) {
+               sts = applespi_async(applespi, &applespi->rd_m,
+                                    applespi_async_read_complete);
+               if (sts)
+                       dev_warn(&applespi->spi->dev,
+                                "Error queueing async read to device: %d\n",
+                                sts);
+               else
+                       applespi->read_active = true;
+       }
+
+       spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+
+       return ACPI_INTERRUPT_HANDLED;
+}
+
+static int applespi_get_saved_bl_level(struct applespi_data *applespi)
+{
+       struct efivar_entry *efivar_entry;
+       u16 efi_data = 0;
+       unsigned long efi_data_len;
+       int sts;
+
+       efivar_entry = kmalloc(sizeof(*efivar_entry), GFP_KERNEL);
+       if (!efivar_entry)
+               return -ENOMEM;
+
+       memcpy(efivar_entry->var.VariableName, EFI_BL_LEVEL_NAME,
+              sizeof(EFI_BL_LEVEL_NAME));
+       efivar_entry->var.VendorGuid = EFI_BL_LEVEL_GUID;
+       efi_data_len = sizeof(efi_data);
+
+       sts = efivar_entry_get(efivar_entry, NULL, &efi_data_len, &efi_data);
+       if (sts && sts != -ENOENT)
+               dev_warn(&applespi->spi->dev,
+                        "Error getting backlight level from EFI vars: %d\n",
+                        sts);
+
+       kfree(efivar_entry);
+
+       return sts ? sts : efi_data;
+}
+
+static void applespi_save_bl_level(struct applespi_data *applespi,
+                                  unsigned int level)
+{
+       efi_guid_t efi_guid;
+       u32 efi_attr;
+       unsigned long efi_data_len;
+       u16 efi_data;
+       int sts;
+
+       /* Save keyboard backlight level */
+       efi_guid = EFI_BL_LEVEL_GUID;
+       efi_data = (u16)level;
+       efi_data_len = sizeof(efi_data);
+       efi_attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                  EFI_VARIABLE_RUNTIME_ACCESS;
+
+       sts = efivar_entry_set_safe(EFI_BL_LEVEL_NAME, efi_guid, efi_attr, true,
+                                   efi_data_len, &efi_data);
+       if (sts)
+               dev_warn(&applespi->spi->dev,
+                        "Error saving backlight level to EFI vars: %d\n", sts);
+}
+
+static int applespi_probe(struct spi_device *spi)
+{
+       struct applespi_data *applespi;
+       acpi_handle spi_handle = ACPI_HANDLE(&spi->dev);
+       acpi_status acpi_sts;
+       int sts, i;
+       unsigned long long gpe, usb_status;
+
+       /* check if the USB interface is present and enabled already */
+       acpi_sts = acpi_evaluate_integer(spi_handle, "UIST", NULL, &usb_status);
+       if (ACPI_SUCCESS(acpi_sts) && usb_status) {
+               /* let the USB driver take over instead */
+               dev_info(&spi->dev, "USB interface already enabled\n");
+               return -ENODEV;
+       }
+
+       /* allocate driver data */
+       applespi = devm_kzalloc(&spi->dev, sizeof(*applespi), GFP_KERNEL);
+       if (!applespi)
+               return -ENOMEM;
+
+       applespi->spi = spi;
+
+       INIT_WORK(&applespi->work, applespi_worker);
+
+       /* store the driver data */
+       spi_set_drvdata(spi, applespi);
+
+       /* create our buffers */
+       applespi->tx_buffer = devm_kmalloc(&spi->dev, APPLESPI_PACKET_SIZE,
+                                          GFP_KERNEL);
+       applespi->tx_status = devm_kmalloc(&spi->dev, APPLESPI_STATUS_SIZE,
+                                          GFP_KERNEL);
+       applespi->rx_buffer = devm_kmalloc(&spi->dev, APPLESPI_PACKET_SIZE,
+                                          GFP_KERNEL);
+       applespi->msg_buf = devm_kmalloc_array(&spi->dev, MAX_PKTS_PER_MSG,
+                                              APPLESPI_PACKET_SIZE,
+                                              GFP_KERNEL);
+
+       if (!applespi->tx_buffer || !applespi->tx_status ||
+           !applespi->rx_buffer || !applespi->msg_buf)
+               return -ENOMEM;
+
+       /* set up our spi messages */
+       applespi_setup_read_txfrs(applespi);
+       applespi_setup_write_txfrs(applespi);
+
+       /* cache ACPI method handles */
+       acpi_sts = acpi_get_handle(spi_handle, "SIEN", &applespi->sien);
+       if (ACPI_FAILURE(acpi_sts)) {
+               dev_err(&applespi->spi->dev,
+                       "Failed to get SIEN ACPI method handle: %s\n",
+                       acpi_format_exception(acpi_sts));
+               return -ENODEV;
+       }
+
+       acpi_sts = acpi_get_handle(spi_handle, "SIST", &applespi->sist);
+       if (ACPI_FAILURE(acpi_sts)) {
+               dev_err(&applespi->spi->dev,
+                       "Failed to get SIST ACPI method handle: %s\n",
+                       acpi_format_exception(acpi_sts));
+               return -ENODEV;
+       }
+
+       /* switch on the SPI interface */
+       sts = applespi_setup_spi(applespi);
+       if (sts)
+               return sts;
+
+       sts = applespi_enable_spi(applespi);
+       if (sts)
+               return sts;
+
+       /* setup the keyboard input dev */
+       applespi->keyboard_input_dev = devm_input_allocate_device(&spi->dev);
+
+       if (!applespi->keyboard_input_dev)
+               return -ENOMEM;
+
+       applespi->keyboard_input_dev->name = "Apple SPI Keyboard";
+       applespi->keyboard_input_dev->phys = "applespi/input0";
+       applespi->keyboard_input_dev->dev.parent = &spi->dev;
+       applespi->keyboard_input_dev->id.bustype = BUS_SPI;
+
+       applespi->keyboard_input_dev->evbit[0] =
+                       BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) | BIT_MASK(EV_REP);
+       applespi->keyboard_input_dev->ledbit[0] = BIT_MASK(LED_CAPSL);
+
+       input_set_drvdata(applespi->keyboard_input_dev, applespi);
+       applespi->keyboard_input_dev->event = applespi_event;
+
+       for (i = 0; i < ARRAY_SIZE(applespi_scancodes); i++)
+               if (applespi_scancodes[i])
+                       input_set_capability(applespi->keyboard_input_dev,
+                                            EV_KEY, applespi_scancodes[i]);
+
+       for (i = 0; i < ARRAY_SIZE(applespi_controlcodes); i++)
+               if (applespi_controlcodes[i])
+                       input_set_capability(applespi->keyboard_input_dev,
+                                            EV_KEY, applespi_controlcodes[i]);
+
+       for (i = 0; i < ARRAY_SIZE(applespi_fn_codes); i++)
+               if (applespi_fn_codes[i].to)
+                       input_set_capability(applespi->keyboard_input_dev,
+                                            EV_KEY, applespi_fn_codes[i].to);
+
+       input_set_capability(applespi->keyboard_input_dev, EV_KEY, KEY_FN);
+
+       sts = input_register_device(applespi->keyboard_input_dev);
+       if (sts) {
+               dev_err(&applespi->spi->dev,
+                       "Unable to register keyboard input device (%d)\n", sts);
+               return -ENODEV;
+       }
+
+       /*
+        * The applespi device doesn't send interrupts normally (as is described
+        * in its DSDT), but rather seems to use ACPI GPEs.
+        */
+       acpi_sts = acpi_evaluate_integer(spi_handle, "_GPE", NULL, &gpe);
+       if (ACPI_FAILURE(acpi_sts)) {
+               dev_err(&applespi->spi->dev,
+                       "Failed to obtain GPE for SPI slave device: %s\n",
+                       acpi_format_exception(acpi_sts));
+               return -ENODEV;
+       }
+       applespi->gpe = (int)gpe;
+
+       acpi_sts = acpi_install_gpe_handler(NULL, applespi->gpe,
+                                           ACPI_GPE_LEVEL_TRIGGERED,
+                                           applespi_notify, applespi);
+       if (ACPI_FAILURE(acpi_sts)) {
+               dev_err(&applespi->spi->dev,
+                       "Failed to install GPE handler for GPE %d: %s\n",
+                       applespi->gpe, acpi_format_exception(acpi_sts));
+               return -ENODEV;
+       }
+
+       applespi->suspended = false;
+
+       acpi_sts = acpi_enable_gpe(NULL, applespi->gpe);
+       if (ACPI_FAILURE(acpi_sts)) {
+               dev_err(&applespi->spi->dev,
+                       "Failed to enable GPE handler for GPE %d: %s\n",
+                       applespi->gpe, acpi_format_exception(acpi_sts));
+               acpi_remove_gpe_handler(NULL, applespi->gpe, applespi_notify);
+               return -ENODEV;
+       }
+
+       /* trigger touchpad setup */
+       applespi_init(applespi, false);
+
+       /*
+        * By default this device is not enabled for wakeup; but USB keyboards
+        * generally are, so the expectation is that by default the keyboard
+        * will wake the system.
+        */
+       device_wakeup_enable(&spi->dev);
+
+       /* set up keyboard-backlight */
+       sts = applespi_get_saved_bl_level(applespi);
+       if (sts >= 0)
+               applespi_set_bl_level(&applespi->backlight_info, sts);
+
+       applespi->backlight_info.name            = "spi::kbd_backlight";
+       applespi->backlight_info.default_trigger = "kbd-backlight";
+       applespi->backlight_info.brightness_set  = applespi_set_bl_level;
+
+       sts = devm_led_classdev_register(&spi->dev, &applespi->backlight_info);
+       if (sts)
+               dev_warn(&applespi->spi->dev,
+                        "Unable to register keyboard backlight class dev (%d)\n",
+                        sts);
+
+       /* set up debugfs entries for touchpad dimensions logging */
+       applespi->debugfs_root = debugfs_create_dir("applespi", NULL);
+       if (IS_ERR(applespi->debugfs_root)) {
+               if (PTR_ERR(applespi->debugfs_root) != -ENODEV)
+                       dev_warn(&applespi->spi->dev,
+                                "Error creating debugfs root entry (%ld)\n",
+                                PTR_ERR(applespi->debugfs_root));
+       } else {
+               struct dentry *ret;
+
+               ret = debugfs_create_bool("enable_tp_dim", 0600,
+                                         applespi->debugfs_root,
+                                         &applespi->debug_tp_dim);
+               if (IS_ERR(ret))
+                       dev_dbg(&applespi->spi->dev,
+                               "Error creating debugfs entry enable_tp_dim (%ld)\n",
+                               PTR_ERR(ret));
+
+               ret = debugfs_create_file("tp_dim", 0400,
+                                         applespi->debugfs_root, applespi,
+                                         &applespi_tp_dim_fops);
+               if (IS_ERR(ret))
+                       dev_dbg(&applespi->spi->dev,
+                               "Error creating debugfs entry tp_dim (%ld)\n",
+                               PTR_ERR(ret));
+       }
+
+       return 0;
+}
+
+static void applespi_drain_writes(struct applespi_data *applespi)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+       applespi->drain = true;
+       wait_event_lock_irq(applespi->drain_complete, !applespi->write_active,
+                           applespi->cmd_msg_lock);
+
+       spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+}
+
+static void applespi_drain_reads(struct applespi_data *applespi)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+       wait_event_lock_irq(applespi->drain_complete, !applespi->read_active,
+                           applespi->cmd_msg_lock);
+
+       applespi->suspended = true;
+
+       spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+}
+
+static int applespi_remove(struct spi_device *spi)
+{
+       struct applespi_data *applespi = spi_get_drvdata(spi);
+
+       applespi_drain_writes(applespi);
+
+       acpi_disable_gpe(NULL, applespi->gpe);
+       acpi_remove_gpe_handler(NULL, applespi->gpe, applespi_notify);
+       device_wakeup_disable(&spi->dev);
+
+       applespi_drain_reads(applespi);
+
+       debugfs_remove_recursive(applespi->debugfs_root);
+
+       return 0;
+}
+
+static void applespi_shutdown(struct spi_device *spi)
+{
+       struct applespi_data *applespi = spi_get_drvdata(spi);
+
+       applespi_save_bl_level(applespi, applespi->have_bl_level);
+}
+
+static int applespi_poweroff_late(struct device *dev)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct applespi_data *applespi = spi_get_drvdata(spi);
+
+       applespi_save_bl_level(applespi, applespi->have_bl_level);
+
+       return 0;
+}
+
+static int __maybe_unused applespi_suspend(struct device *dev)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct applespi_data *applespi = spi_get_drvdata(spi);
+       acpi_status acpi_sts;
+       int sts;
+
+       /* turn off caps-lock - it'll stay on otherwise */
+       sts = applespi_set_capsl_led(applespi, false);
+       if (sts)
+               dev_warn(&applespi->spi->dev,
+                        "Failed to turn off caps-lock led (%d)\n", sts);
+
+       applespi_drain_writes(applespi);
+
+       /* disable the interrupt */
+       acpi_sts = acpi_disable_gpe(NULL, applespi->gpe);
+       if (ACPI_FAILURE(acpi_sts))
+               dev_err(&applespi->spi->dev,
+                       "Failed to disable GPE handler for GPE %d: %s\n",
+                       applespi->gpe, acpi_format_exception(acpi_sts));
+
+       applespi_drain_reads(applespi);
+
+       return 0;
+}
+
+static int __maybe_unused applespi_resume(struct device *dev)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct applespi_data *applespi = spi_get_drvdata(spi);
+       acpi_status acpi_sts;
+       unsigned long flags;
+
+       /* ensure our flags and state reflect a newly resumed device */
+       spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+       applespi->drain = false;
+       applespi->have_cl_led_on = false;
+       applespi->have_bl_level = 0;
+       applespi->cmd_msg_queued = false;
+       applespi->read_active = false;
+       applespi->write_active = false;
+
+       applespi->suspended = false;
+
+       spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+
+       /* switch on the SPI interface */
+       applespi_enable_spi(applespi);
+
+       /* re-enable the interrupt */
+       acpi_sts = acpi_enable_gpe(NULL, applespi->gpe);
+       if (ACPI_FAILURE(acpi_sts))
+               dev_err(&applespi->spi->dev,
+                       "Failed to re-enable GPE handler for GPE %d: %s\n",
+                       applespi->gpe, acpi_format_exception(acpi_sts));
+
+       /* switch the touchpad into multitouch mode */
+       applespi_init(applespi, true);
+
+       return 0;
+}
+
+static const struct acpi_device_id applespi_acpi_match[] = {
+       { "APP000D", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, applespi_acpi_match);
+
+const struct dev_pm_ops applespi_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(applespi_suspend, applespi_resume)
+       .poweroff_late  = applespi_poweroff_late,
+};
+
+static struct spi_driver applespi_driver = {
+       .driver         = {
+               .name                   = "applespi",
+               .acpi_match_table       = applespi_acpi_match,
+               .pm                     = &applespi_pm_ops,
+       },
+       .probe          = applespi_probe,
+       .remove         = applespi_remove,
+       .shutdown       = applespi_shutdown,
+};
+
+module_spi_driver(applespi_driver)
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MacBook(Pro) SPI Keyboard/Touchpad driver");
+MODULE_AUTHOR("Federico Lorenzi");
+MODULE_AUTHOR("Ronald Tschalär");
diff --git a/drivers/input/keyboard/applespi.h b/drivers/input/keyboard/applespi.h
new file mode 100644 (file)
index 0000000..7f5ab10
--- /dev/null
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * MacBook (Pro) SPI keyboard and touchpad driver
+ *
+ * Copyright (c) 2015-2019 Federico Lorenzi
+ * Copyright (c) 2017-2019 Ronald Tschalär
+ */
+
+#ifndef _APPLESPI_H_
+#define _APPLESPI_H_
+
+enum applespi_evt_type {
+       ET_CMD_TP_INI = BIT(0),
+       ET_CMD_BL = BIT(1),
+       ET_CMD_CL = BIT(2),
+       ET_RD_KEYB = BIT(8),
+       ET_RD_TPAD = BIT(9),
+       ET_RD_UNKN = BIT(10),
+       ET_RD_IRQ = BIT(11),
+       ET_RD_CRC = BIT(12),
+};
+
+enum applespi_pkt_type {
+       PT_READ,
+       PT_WRITE,
+       PT_STATUS,
+};
+
+#endif /* _APPLESPI_H_ */
diff --git a/drivers/input/keyboard/applespi_trace.h b/drivers/input/keyboard/applespi_trace.h
new file mode 100644 (file)
index 0000000..0ad1a3d
--- /dev/null
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * MacBook (Pro) SPI keyboard and touchpad driver
+ *
+ * Copyright (c) 2015-2019 Federico Lorenzi
+ * Copyright (c) 2017-2019 Ronald Tschalär
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM applespi
+
+#if !defined(_APPLESPI_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _APPLESPI_TRACE_H_
+
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+
+#include "applespi.h"
+
+DECLARE_EVENT_CLASS(dump_message_template,
+       TP_PROTO(enum applespi_evt_type evt_type,
+                enum applespi_pkt_type pkt_type,
+                u8 *buf,
+                size_t len),
+
+       TP_ARGS(evt_type, pkt_type, buf, len),
+
+       TP_STRUCT__entry(
+               __field(enum applespi_evt_type, evt_type)
+               __field(enum applespi_pkt_type, pkt_type)
+               __field(size_t, len)
+               __dynamic_array(u8, buf, len)
+       ),
+
+       TP_fast_assign(
+               __entry->evt_type = evt_type;
+               __entry->pkt_type = pkt_type;
+               __entry->len = len;
+               memcpy(__get_dynamic_array(buf), buf, len);
+       ),
+
+       TP_printk("%-6s: %s",
+                 __print_symbolic(__entry->pkt_type,
+                                  { PT_READ, "read" },
+                                  { PT_WRITE, "write" },
+                                  { PT_STATUS, "status" }
+                 ),
+                 __print_hex(__get_dynamic_array(buf), __entry->len))
+);
+
+#define DEFINE_DUMP_MESSAGE_EVENT(name)                        \
+DEFINE_EVENT(dump_message_template, name,              \
+       TP_PROTO(enum applespi_evt_type evt_type,       \
+                enum applespi_pkt_type pkt_type,       \
+                u8 *buf,                               \
+                size_t len),                           \
+       TP_ARGS(evt_type, pkt_type, buf, len)           \
+)
+
+DEFINE_DUMP_MESSAGE_EVENT(applespi_tp_ini_cmd);
+DEFINE_DUMP_MESSAGE_EVENT(applespi_backlight_cmd);
+DEFINE_DUMP_MESSAGE_EVENT(applespi_caps_lock_cmd);
+DEFINE_DUMP_MESSAGE_EVENT(applespi_keyboard_data);
+DEFINE_DUMP_MESSAGE_EVENT(applespi_touchpad_data);
+DEFINE_DUMP_MESSAGE_EVENT(applespi_unknown_data);
+DEFINE_DUMP_MESSAGE_EVENT(applespi_bad_crc);
+
+TRACE_EVENT(applespi_irq_received,
+       TP_PROTO(enum applespi_evt_type evt_type,
+                enum applespi_pkt_type pkt_type),
+
+       TP_ARGS(evt_type, pkt_type),
+
+       TP_STRUCT__entry(
+               __field(enum applespi_evt_type, evt_type)
+               __field(enum applespi_pkt_type, pkt_type)
+       ),
+
+       TP_fast_assign(
+               __entry->evt_type = evt_type;
+               __entry->pkt_type = pkt_type;
+       ),
+
+       "\n"
+);
+
+#endif /* _APPLESPI_TRACE_H_ */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../drivers/input/keyboard
+#define TRACE_INCLUDE_FILE applespi_trace
+#include <trace/define_trace.h>
index 746ff06..62391d6 100644 (file)
@@ -277,8 +277,10 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev)
                keys->keys[index].regs = &mtk_pmic_regs->keys_regs[index];
 
                keys->keys[index].irq = platform_get_irq(pdev, index);
-               if (keys->keys[index].irq < 0)
+               if (keys->keys[index].irq < 0) {
+                       of_node_put(child);
                        return keys->keys[index].irq;
+               }
 
                error = of_property_read_u32(child,
                        "linux,keycodes", &keys->keys[index].keycode);
@@ -286,6 +288,7 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev)
                        dev_err(keys->dev,
                                "failed to read key:%d linux,keycode property: %d\n",
                                index, error);
+                       of_node_put(child);
                        return error;
                }
 
@@ -293,8 +296,10 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev)
                        keys->keys[index].wakeup = true;
 
                error = mtk_pmic_key_setup(keys, &keys->keys[index]);
-               if (error)
+               if (error) {
+                       of_node_put(child);
                        return error;
+               }
 
                index++;
        }
index 6ffdc26..4a796be 100644 (file)
@@ -198,18 +198,21 @@ static int sun4i_lradc_load_dt_keymap(struct device *dev,
                error = of_property_read_u32(pp, "channel", &channel);
                if (error || channel != 0) {
                        dev_err(dev, "%pOFn: Inval channel prop\n", pp);
+                       of_node_put(pp);
                        return -EINVAL;
                }
 
                error = of_property_read_u32(pp, "voltage", &map->voltage);
                if (error) {
                        dev_err(dev, "%pOFn: Inval voltage prop\n", pp);
+                       of_node_put(pp);
                        return -EINVAL;
                }
 
                error = of_property_read_u32(pp, "linux,code", &map->keycode);
                if (error) {
                        dev_err(dev, "%pOFn: Inval linux,code prop\n", pp);
+                       of_node_put(pp);
                        return -EINVAL;
                }
 
index 8996323..34700ed 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "psmouse.h"
 #include "alps.h"
+#include "trackpoint.h"
 
 /*
  * Definitions for ALPS version 3 and 4 command mode protocol
@@ -2861,6 +2862,23 @@ static const struct alps_protocol_info *alps_match_table(unsigned char *e7,
        return NULL;
 }
 
+static bool alps_is_cs19_trackpoint(struct psmouse *psmouse)
+{
+       u8 param[2] = { 0 };
+
+       if (ps2_command(&psmouse->ps2dev,
+                       param, MAKE_PS2_CMD(0, 2, TP_READ_ID)))
+               return false;
+
+       /*
+        * param[0] contains the trackpoint device variant_id while
+        * param[1] contains the firmware_id. So far all alps
+        * trackpoint-only devices have their variant_ids equal
+        * TP_VARIANT_ALPS and their firmware_ids are in 0x20~0x2f range.
+        */
+       return param[0] == TP_VARIANT_ALPS && ((param[1] & 0xf0) == 0x20);
+}
+
 static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
 {
        const struct alps_protocol_info *protocol;
@@ -3162,6 +3180,20 @@ int alps_detect(struct psmouse *psmouse, bool set_properties)
                return error;
 
        /*
+        * ALPS cs19 is a trackpoint-only device, and uses different
+        * protocol than DualPoint ones, so we return -EINVAL here and let
+        * trackpoint.c drive this device. If the trackpoint driver is not
+        * enabled, the device will fall back to a bare PS/2 mouse.
+        * If ps2_command() fails here, we depend on the immediately
+        * followed psmouse_reset() to reset the device to normal state.
+        */
+       if (alps_is_cs19_trackpoint(psmouse)) {
+               psmouse_dbg(psmouse,
+                           "ALPS CS19 trackpoint-only device detected, ignoring\n");
+               return -EINVAL;
+       }
+
+       /*
         * Reset the device to make sure it is fully operational:
         * on some laptops, like certain Dell Latitudes, we may
         * fail to properly detect presence of trackstick if device
index 1080c0c..b1956ed 100644 (file)
@@ -176,6 +176,7 @@ static const char * const smbus_pnp_ids[] = {
        "LEN0093", /* T480 */
        "LEN0096", /* X280 */
        "LEN0097", /* X280 -> ALPS trackpoint */
+       "LEN009b", /* T580 */
        "LEN200f", /* T450s */
        "LEN2054", /* E480 */
        "LEN2055", /* E580 */
@@ -705,7 +706,7 @@ static void synaptics_pt_create(struct psmouse *psmouse)
 
        serio->id.type = SERIO_PS_PSTHRU;
        strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name));
-       strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name));
+       strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->phys));
        serio->write = synaptics_pt_write;
        serio->start = synaptics_pt_start;
        serio->stop = synaptics_pt_stop;
index 0afffe8..77110f3 100644 (file)
@@ -158,7 +158,8 @@ struct trackpoint_data {
 #ifdef CONFIG_MOUSE_PS2_TRACKPOINT
 int trackpoint_detect(struct psmouse *psmouse, bool set_properties);
 #else
-inline int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
+static inline int trackpoint_detect(struct psmouse *psmouse,
+                                   bool set_properties)
 {
        return -ENOSYS;
 }
index 8e457e5..88ae7c2 100644 (file)
@@ -75,8 +75,8 @@ struct synth_kbd_keystroke {
 
 #define HK_MAXIMUM_MESSAGE_SIZE 256
 
-#define KBD_VSC_SEND_RING_BUFFER_SIZE          (10 * PAGE_SIZE)
-#define KBD_VSC_RECV_RING_BUFFER_SIZE          (10 * PAGE_SIZE)
+#define KBD_VSC_SEND_RING_BUFFER_SIZE          (40 * 1024)
+#define KBD_VSC_RECV_RING_BUFFER_SIZE          (40 * 1024)
 
 #define XTKBD_EMUL0     0xe0
 #define XTKBD_EMUL1     0xe1
index 4b8b9d7..3503122 100644 (file)
@@ -78,6 +78,7 @@ Scott Hill shill@gtcocalcomp.com
 
 /* Max size of a single report */
 #define REPORT_MAX_SIZE       10
+#define MAX_COLLECTION_LEVELS  10
 
 
 /* Bitmask whether pen is in range */
@@ -223,8 +224,7 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
        char  maintype = 'x';
        char  globtype[12];
        int   indent = 0;
-       char  indentstr[10] = "";
-
+       char  indentstr[MAX_COLLECTION_LEVELS + 1] = { 0 };
 
        dev_dbg(ddev, "======>>>>>>PARSE<<<<<<======\n");
 
@@ -350,6 +350,13 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
                        case TAG_MAIN_COL_START:
                                maintype = 'S';
 
+                               if (indent == MAX_COLLECTION_LEVELS) {
+                                       dev_err(ddev, "Collection level %d would exceed limit of %d\n",
+                                               indent + 1,
+                                               MAX_COLLECTION_LEVELS);
+                                       break;
+                               }
+
                                if (data == 0) {
                                        dev_dbg(ddev, "======>>>>>> Physical\n");
                                        strcpy(globtype, "Physical");
@@ -369,8 +376,15 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
                                break;
 
                        case TAG_MAIN_COL_END:
-                               dev_dbg(ddev, "<<<<<<======\n");
                                maintype = 'E';
+
+                               if (indent == 0) {
+                                       dev_err(ddev, "Collection level already at zero\n");
+                                       break;
+                               }
+
+                               dev_dbg(ddev, "<<<<<<======\n");
+
                                indent--;
                                for (x = 0; x < indent; x++)
                                        indentstr[x] = '-';
index 8e48fbd..8e9f3b7 100644 (file)
@@ -602,9 +602,8 @@ static int auo_pixcir_probe(struct i2c_client *client,
                return error;
        }
 
-       error = devm_add_action(&client->dev, auo_pixcir_reset, ts);
+       error = devm_add_action_or_reset(&client->dev, auo_pixcir_reset, ts);
        if (error) {
-               auo_pixcir_reset(ts);
                dev_err(&client->dev, "failed to register reset action, %d\n",
                        error);
                return error;
index 92f6e1a..f11ba7f 100644 (file)
@@ -22,7 +22,7 @@
  * in the kernel). So this driver offers straight forward, reliable single
  * touch functionality only.
  *
- * s.a. A20 User Manual "1.15 TP" (Documentation/arm/sunxi/README)
+ * s.a. A20 User Manual "1.15 TP" (Documentation/arm/sunxi.rst)
  * (looks like the description in the A20 User Manual v1.3 is better
  * than the one in the A10 User Manual v.1.5)
  */
index 83664db..e15cdcd 100644 (file)
@@ -473,4 +473,15 @@ config HYPERV_IOMMU
          Stub IOMMU driver to handle IRQs as to allow Hyper-V Linux
          guests to run with x2APIC mode enabled.
 
+config VIRTIO_IOMMU
+       bool "Virtio IOMMU driver"
+       depends on VIRTIO=y
+       depends on ARM64
+       select IOMMU_API
+       select INTERVAL_TREE
+       help
+         Para-virtualised IOMMU driver with virtio.
+
+         Say Y here if you intend to run this kernel as a guest.
+
 endif # IOMMU_SUPPORT
index 8c71a15..f13f36a 100644 (file)
@@ -33,3 +33,4 @@ obj-$(CONFIG_FSL_PAMU) += fsl_pamu.o fsl_pamu_domain.o
 obj-$(CONFIG_S390_IOMMU) += s390-iommu.o
 obj-$(CONFIG_QCOM_IOMMU) += qcom_iommu.o
 obj-$(CONFIG_HYPERV_IOMMU) += hyperv-iommu.o
+obj-$(CONFIG_VIRTIO_IOMMU) += virtio-iommu.o
index 73740b9..b607a92 100644 (file)
@@ -2533,7 +2533,7 @@ static int map_sg(struct device *dev, struct scatterlist *sglist,
        npages = sg_num_pages(dev, sglist, nelems);
 
        address = dma_ops_alloc_iova(dev, dma_dom, npages, dma_mask);
-       if (address == DMA_MAPPING_ERROR)
+       if (!address)
                goto out_err;
 
        prot = dir2prot(direction);
index eb104c7..4413aa6 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/mem_encrypt.h>
 #include <asm/pci-direct.h>
 #include <asm/iommu.h>
+#include <asm/apic.h>
+#include <asm/msidef.h>
 #include <asm/gart.h>
 #include <asm/x86_init.h>
 #include <asm/iommu_table.h>
@@ -1920,6 +1922,90 @@ static int iommu_setup_msi(struct amd_iommu *iommu)
        return 0;
 }
 
+#define XT_INT_DEST_MODE(x)    (((x) & 0x1ULL) << 2)
+#define XT_INT_DEST_LO(x)      (((x) & 0xFFFFFFULL) << 8)
+#define XT_INT_VEC(x)          (((x) & 0xFFULL) << 32)
+#define XT_INT_DEST_HI(x)      ((((x) >> 24) & 0xFFULL) << 56)
+
+/**
+ * Setup the IntCapXT registers with interrupt routing information
+ * based on the PCI MSI capability block registers, accessed via
+ * MMIO MSI address low/hi and MSI data registers.
+ */
+static void iommu_update_intcapxt(struct amd_iommu *iommu)
+{
+       u64 val;
+       u32 addr_lo = readl(iommu->mmio_base + MMIO_MSI_ADDR_LO_OFFSET);
+       u32 addr_hi = readl(iommu->mmio_base + MMIO_MSI_ADDR_HI_OFFSET);
+       u32 data    = readl(iommu->mmio_base + MMIO_MSI_DATA_OFFSET);
+       bool dm     = (addr_lo >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
+       u32 dest    = ((addr_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xFF);
+
+       if (x2apic_enabled())
+               dest |= MSI_ADDR_EXT_DEST_ID(addr_hi);
+
+       val = XT_INT_VEC(data & 0xFF) |
+             XT_INT_DEST_MODE(dm) |
+             XT_INT_DEST_LO(dest) |
+             XT_INT_DEST_HI(dest);
+
+       /**
+        * Current IOMMU implemtation uses the same IRQ for all
+        * 3 IOMMU interrupts.
+        */
+       writeq(val, iommu->mmio_base + MMIO_INTCAPXT_EVT_OFFSET);
+       writeq(val, iommu->mmio_base + MMIO_INTCAPXT_PPR_OFFSET);
+       writeq(val, iommu->mmio_base + MMIO_INTCAPXT_GALOG_OFFSET);
+}
+
+static void _irq_notifier_notify(struct irq_affinity_notify *notify,
+                                const cpumask_t *mask)
+{
+       struct amd_iommu *iommu;
+
+       for_each_iommu(iommu) {
+               if (iommu->dev->irq == notify->irq) {
+                       iommu_update_intcapxt(iommu);
+                       break;
+               }
+       }
+}
+
+static void _irq_notifier_release(struct kref *ref)
+{
+}
+
+static int iommu_init_intcapxt(struct amd_iommu *iommu)
+{
+       int ret;
+       struct irq_affinity_notify *notify = &iommu->intcapxt_notify;
+
+       /**
+        * IntCapXT requires XTSup=1, which can be inferred
+        * amd_iommu_xt_mode.
+        */
+       if (amd_iommu_xt_mode != IRQ_REMAP_X2APIC_MODE)
+               return 0;
+
+       /**
+        * Also, we need to setup notifier to update the IntCapXT registers
+        * whenever the irq affinity is changed from user-space.
+        */
+       notify->irq = iommu->dev->irq;
+       notify->notify = _irq_notifier_notify,
+       notify->release = _irq_notifier_release,
+       ret = irq_set_affinity_notifier(iommu->dev->irq, notify);
+       if (ret) {
+               pr_err("Failed to register irq affinity notifier (devid=%#x, irq %d)\n",
+                      iommu->devid, iommu->dev->irq);
+               return ret;
+       }
+
+       iommu_update_intcapxt(iommu);
+       iommu_feature_enable(iommu, CONTROL_INTCAPXT_EN);
+       return ret;
+}
+
 static int iommu_init_msi(struct amd_iommu *iommu)
 {
        int ret;
@@ -1936,6 +2022,10 @@ static int iommu_init_msi(struct amd_iommu *iommu)
                return ret;
 
 enable_faults:
+       ret = iommu_init_intcapxt(iommu);
+       if (ret)
+               return ret;
+
        iommu_feature_enable(iommu, CONTROL_EVT_INT_EN);
 
        if (iommu->ppr_log != NULL)
index 52c35d5..64edd5a 100644 (file)
 #define MMIO_PPR_LOG_OFFSET    0x0038
 #define MMIO_GA_LOG_BASE_OFFSET        0x00e0
 #define MMIO_GA_LOG_TAIL_OFFSET        0x00e8
+#define MMIO_MSI_ADDR_LO_OFFSET        0x015C
+#define MMIO_MSI_ADDR_HI_OFFSET        0x0160
+#define MMIO_MSI_DATA_OFFSET   0x0164
+#define MMIO_INTCAPXT_EVT_OFFSET       0x0170
+#define MMIO_INTCAPXT_PPR_OFFSET       0x0178
+#define MMIO_INTCAPXT_GALOG_OFFSET     0x0180
 #define MMIO_CMD_HEAD_OFFSET   0x2000
 #define MMIO_CMD_TAIL_OFFSET   0x2008
 #define MMIO_EVT_HEAD_OFFSET   0x2010
 #define CONTROL_GALOG_EN        0x1CULL
 #define CONTROL_GAINT_EN        0x1DULL
 #define CONTROL_XT_EN           0x32ULL
+#define CONTROL_INTCAPXT_EN     0x33ULL
 
 #define CTRL_INV_TO_MASK       (7 << CONTROL_INV_TIMEOUT)
 #define CTRL_INV_TO_NONE       0
@@ -592,6 +599,8 @@ struct amd_iommu {
        /* DebugFS Info */
        struct dentry *debugfs;
 #endif
+       /* IRQ notifier for IntCapXT interrupt */
+       struct irq_affinity_notify intcapxt_notify;
 };
 
 static inline struct amd_iommu *dev_to_amd_iommu(struct device *dev)
index 73a5529..2b25d9c 100644 (file)
@@ -162,9 +162,9 @@ static inline void print_tbl_walk(struct seq_file *m)
                           (u64)0, (u64)0, (u64)0);
        else
                seq_printf(m, "%-6d\t0x%016llx:0x%016llx:0x%016llx\n",
-                          tbl_wlk->pasid, tbl_wlk->pasid_tbl_entry->val[0],
+                          tbl_wlk->pasid, tbl_wlk->pasid_tbl_entry->val[2],
                           tbl_wlk->pasid_tbl_entry->val[1],
-                          tbl_wlk->pasid_tbl_entry->val[2]);
+                          tbl_wlk->pasid_tbl_entry->val[0]);
 }
 
 static void pasid_tbl_walk(struct seq_file *m, struct pasid_entry *tbl_entry,
index ac4172c..bdaed2d 100644 (file)
@@ -339,8 +339,6 @@ static void domain_exit(struct dmar_domain *domain);
 static void domain_remove_dev_info(struct dmar_domain *domain);
 static void dmar_remove_one_dev_info(struct device *dev);
 static void __dmar_remove_one_dev_info(struct device_domain_info *info);
-static void domain_context_clear(struct intel_iommu *iommu,
-                                struct device *dev);
 static int domain_detach_iommu(struct dmar_domain *domain,
                               struct intel_iommu *iommu);
 static bool device_is_rmrr_locked(struct device *dev);
@@ -1833,9 +1831,65 @@ static inline int guestwidth_to_adjustwidth(int gaw)
        return agaw;
 }
 
+static int domain_init(struct dmar_domain *domain, struct intel_iommu *iommu,
+                      int guest_width)
+{
+       int adjust_width, agaw;
+       unsigned long sagaw;
+       int err;
+
+       init_iova_domain(&domain->iovad, VTD_PAGE_SIZE, IOVA_START_PFN);
+
+       err = init_iova_flush_queue(&domain->iovad,
+                                   iommu_flush_iova, iova_entry_free);
+       if (err)
+               return err;
+
+       domain_reserve_special_ranges(domain);
+
+       /* calculate AGAW */
+       if (guest_width > cap_mgaw(iommu->cap))
+               guest_width = cap_mgaw(iommu->cap);
+       domain->gaw = guest_width;
+       adjust_width = guestwidth_to_adjustwidth(guest_width);
+       agaw = width_to_agaw(adjust_width);
+       sagaw = cap_sagaw(iommu->cap);
+       if (!test_bit(agaw, &sagaw)) {
+               /* hardware doesn't support it, choose a bigger one */
+               pr_debug("Hardware doesn't support agaw %d\n", agaw);
+               agaw = find_next_bit(&sagaw, 5, agaw);
+               if (agaw >= 5)
+                       return -ENODEV;
+       }
+       domain->agaw = agaw;
+
+       if (ecap_coherent(iommu->ecap))
+               domain->iommu_coherency = 1;
+       else
+               domain->iommu_coherency = 0;
+
+       if (ecap_sc_support(iommu->ecap))
+               domain->iommu_snooping = 1;
+       else
+               domain->iommu_snooping = 0;
+
+       if (intel_iommu_superpage)
+               domain->iommu_superpage = fls(cap_super_page_val(iommu->cap));
+       else
+               domain->iommu_superpage = 0;
+
+       domain->nid = iommu->node;
+
+       /* always allocate the top pgd */
+       domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
+       if (!domain->pgd)
+               return -ENOMEM;
+       __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE);
+       return 0;
+}
+
 static void domain_exit(struct dmar_domain *domain)
 {
-       struct page *freelist;
 
        /* Remove associated devices and clear attached or cached domains */
        domain_remove_dev_info(domain);
@@ -1843,9 +1897,12 @@ static void domain_exit(struct dmar_domain *domain)
        /* destroy iovas */
        put_iova_domain(&domain->iovad);
 
-       freelist = domain_unmap(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
+       if (domain->pgd) {
+               struct page *freelist;
 
-       dma_free_pagelist(freelist);
+               freelist = domain_unmap(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
+               dma_free_pagelist(freelist);
+       }
 
        free_domain_mem(domain);
 }
@@ -2048,26 +2105,9 @@ out_unlock:
        return ret;
 }
 
-struct domain_context_mapping_data {
-       struct dmar_domain *domain;
-       struct intel_iommu *iommu;
-       struct pasid_table *table;
-};
-
-static int domain_context_mapping_cb(struct pci_dev *pdev,
-                                    u16 alias, void *opaque)
-{
-       struct domain_context_mapping_data *data = opaque;
-
-       return domain_context_mapping_one(data->domain, data->iommu,
-                                         data->table, PCI_BUS_NUM(alias),
-                                         alias & 0xff);
-}
-
 static int
 domain_context_mapping(struct dmar_domain *domain, struct device *dev)
 {
-       struct domain_context_mapping_data data;
        struct pasid_table *table;
        struct intel_iommu *iommu;
        u8 bus, devfn;
@@ -2077,17 +2117,7 @@ domain_context_mapping(struct dmar_domain *domain, struct device *dev)
                return -ENODEV;
 
        table = intel_pasid_get_table(dev);
-
-       if (!dev_is_pci(dev))
-               return domain_context_mapping_one(domain, iommu, table,
-                                                 bus, devfn);
-
-       data.domain = domain;
-       data.iommu = iommu;
-       data.table = table;
-
-       return pci_for_each_dma_alias(to_pci_dev(dev),
-                                     &domain_context_mapping_cb, &data);
+       return domain_context_mapping_one(domain, iommu, table, bus, devfn);
 }
 
 static int domain_context_mapped_cb(struct pci_dev *pdev,
@@ -2513,31 +2543,6 @@ static int get_last_alias(struct pci_dev *pdev, u16 alias, void *opaque)
        return 0;
 }
 
-static int domain_init(struct dmar_domain *domain, int guest_width)
-{
-       int adjust_width;
-
-       init_iova_domain(&domain->iovad, VTD_PAGE_SIZE, IOVA_START_PFN);
-       domain_reserve_special_ranges(domain);
-
-       /* calculate AGAW */
-       domain->gaw = guest_width;
-       adjust_width = guestwidth_to_adjustwidth(guest_width);
-       domain->agaw = width_to_agaw(adjust_width);
-
-       domain->iommu_coherency = 0;
-       domain->iommu_snooping = 0;
-       domain->iommu_superpage = 0;
-       domain->max_addr = 0;
-
-       /* always allocate the top pgd */
-       domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
-       if (!domain->pgd)
-               return -ENOMEM;
-       domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
-       return 0;
-}
-
 static struct dmar_domain *find_or_alloc_domain(struct device *dev, int gaw)
 {
        struct device_domain_info *info;
@@ -2575,19 +2580,11 @@ static struct dmar_domain *find_or_alloc_domain(struct device *dev, int gaw)
        domain = alloc_domain(0);
        if (!domain)
                return NULL;
-
-       if (domain_init(domain, gaw)) {
+       if (domain_init(domain, iommu, gaw)) {
                domain_exit(domain);
                return NULL;
        }
 
-       if (init_iova_flush_queue(&domain->iovad,
-                                 iommu_flush_iova,
-                                 iova_entry_free)) {
-               pr_warn("iova flush queue initialization failed\n");
-               intel_iommu_strict = 1;
-       }
-
 out:
        return domain;
 }
@@ -2692,6 +2689,8 @@ static int domain_prepare_identity_map(struct device *dev,
        return iommu_domain_identity_map(domain, start, end);
 }
 
+static int md_domain_init(struct dmar_domain *domain, int guest_width);
+
 static int __init si_domain_init(int hw)
 {
        struct dmar_rmrr_unit *rmrr;
@@ -2702,7 +2701,7 @@ static int __init si_domain_init(int hw)
        if (!si_domain)
                return -EFAULT;
 
-       if (domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
+       if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
                domain_exit(si_domain);
                return -EFAULT;
        }
@@ -3564,7 +3563,8 @@ static void intel_unmap(struct device *dev, dma_addr_t dev_addr, size_t size)
 
        freelist = domain_unmap(domain, start_pfn, last_pfn);
 
-       if (intel_iommu_strict || (pdev && pdev->untrusted)) {
+       if (intel_iommu_strict || (pdev && pdev->untrusted) ||
+                       !has_iova_flush_queue(&domain->iovad)) {
                iommu_flush_iotlb_psi(iommu, domain, start_pfn,
                                      nrpages, !freelist, 0);
                /* free iova */
@@ -4758,28 +4758,6 @@ out_free_dmar:
        return ret;
 }
 
-static int domain_context_clear_one_cb(struct pci_dev *pdev, u16 alias, void *opaque)
-{
-       struct intel_iommu *iommu = opaque;
-
-       domain_context_clear_one(iommu, PCI_BUS_NUM(alias), alias & 0xff);
-       return 0;
-}
-
-/*
- * NB - intel-iommu lacks any sort of reference counting for the users of
- * dependent devices.  If multiple endpoints have intersecting dependent
- * devices, unbinding the driver from any one of them will possibly leave
- * the others unable to operate.
- */
-static void domain_context_clear(struct intel_iommu *iommu, struct device *dev)
-{
-       if (!iommu || !dev || !dev_is_pci(dev))
-               return;
-
-       pci_for_each_dma_alias(to_pci_dev(dev), &domain_context_clear_one_cb, iommu);
-}
-
 static void __dmar_remove_one_dev_info(struct device_domain_info *info)
 {
        struct dmar_domain *domain;
@@ -4800,7 +4778,7 @@ static void __dmar_remove_one_dev_info(struct device_domain_info *info)
                                        PASID_RID2PASID);
 
                iommu_disable_dev_iotlb(info);
-               domain_context_clear(iommu, info->dev);
+               domain_context_clear_one(iommu, info->bus, info->devfn);
                intel_pasid_free_table(info->dev);
        }
 
@@ -4829,6 +4807,31 @@ static void dmar_remove_one_dev_info(struct device *dev)
        spin_unlock_irqrestore(&device_domain_lock, flags);
 }
 
+static int md_domain_init(struct dmar_domain *domain, int guest_width)
+{
+       int adjust_width;
+
+       init_iova_domain(&domain->iovad, VTD_PAGE_SIZE, IOVA_START_PFN);
+       domain_reserve_special_ranges(domain);
+
+       /* calculate AGAW */
+       domain->gaw = guest_width;
+       adjust_width = guestwidth_to_adjustwidth(guest_width);
+       domain->agaw = width_to_agaw(adjust_width);
+
+       domain->iommu_coherency = 0;
+       domain->iommu_snooping = 0;
+       domain->iommu_superpage = 0;
+       domain->max_addr = 0;
+
+       /* always allocate the top pgd */
+       domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
+       if (!domain->pgd)
+               return -ENOMEM;
+       domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
+       return 0;
+}
+
 static struct iommu_domain *intel_iommu_domain_alloc(unsigned type)
 {
        struct dmar_domain *dmar_domain;
@@ -4843,7 +4846,7 @@ static struct iommu_domain *intel_iommu_domain_alloc(unsigned type)
                        pr_err("Can't allocate dmar_domain\n");
                        return NULL;
                }
-               if (domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
+               if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
                        pr_err("Domain initialization failed\n");
                        domain_exit(dmar_domain);
                        return NULL;
index d499b26..3e1a8a6 100644 (file)
@@ -54,9 +54,14 @@ init_iova_domain(struct iova_domain *iovad, unsigned long granule,
 }
 EXPORT_SYMBOL_GPL(init_iova_domain);
 
+bool has_iova_flush_queue(struct iova_domain *iovad)
+{
+       return !!iovad->fq;
+}
+
 static void free_iova_flush_queue(struct iova_domain *iovad)
 {
-       if (!iovad->fq)
+       if (!has_iova_flush_queue(iovad))
                return;
 
        if (timer_pending(&iovad->fq_timer))
@@ -74,13 +79,14 @@ static void free_iova_flush_queue(struct iova_domain *iovad)
 int init_iova_flush_queue(struct iova_domain *iovad,
                          iova_flush_cb flush_cb, iova_entry_dtor entry_dtor)
 {
+       struct iova_fq __percpu *queue;
        int cpu;
 
        atomic64_set(&iovad->fq_flush_start_cnt,  0);
        atomic64_set(&iovad->fq_flush_finish_cnt, 0);
 
-       iovad->fq = alloc_percpu(struct iova_fq);
-       if (!iovad->fq)
+       queue = alloc_percpu(struct iova_fq);
+       if (!queue)
                return -ENOMEM;
 
        iovad->flush_cb   = flush_cb;
@@ -89,13 +95,17 @@ int init_iova_flush_queue(struct iova_domain *iovad,
        for_each_possible_cpu(cpu) {
                struct iova_fq *fq;
 
-               fq = per_cpu_ptr(iovad->fq, cpu);
+               fq = per_cpu_ptr(queue, cpu);
                fq->head = 0;
                fq->tail = 0;
 
                spin_lock_init(&fq->lock);
        }
 
+       smp_wmb();
+
+       iovad->fq = queue;
+
        timer_setup(&iovad->fq_timer, fq_flush_timeout, 0);
        atomic_set(&iovad->fq_timer_on, 0);
 
@@ -127,8 +137,9 @@ __cached_rbnode_delete_update(struct iova_domain *iovad, struct iova *free)
        struct iova *cached_iova;
 
        cached_iova = rb_entry(iovad->cached32_node, struct iova, node);
-       if (free->pfn_hi < iovad->dma_32bit_pfn &&
-           free->pfn_lo >= cached_iova->pfn_lo) {
+       if (free == cached_iova ||
+           (free->pfn_hi < iovad->dma_32bit_pfn &&
+            free->pfn_lo >= cached_iova->pfn_lo)) {
                iovad->cached32_node = rb_next(&free->node);
                iovad->max32_alloc_size = iovad->dma_32bit_pfn;
        }
diff --git a/drivers/iommu/virtio-iommu.c b/drivers/iommu/virtio-iommu.c
new file mode 100644 (file)
index 0000000..433f4d2
--- /dev/null
@@ -0,0 +1,1158 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Virtio driver for the paravirtualized IOMMU
+ *
+ * Copyright (C) 2018 Arm Limited
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/amba/bus.h>
+#include <linux/delay.h>
+#include <linux/dma-iommu.h>
+#include <linux/freezer.h>
+#include <linux/interval_tree.h>
+#include <linux/iommu.h>
+#include <linux/module.h>
+#include <linux/of_iommu.h>
+#include <linux/of_platform.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/virtio.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ids.h>
+#include <linux/wait.h>
+
+#include <uapi/linux/virtio_iommu.h>
+
+#define MSI_IOVA_BASE                  0x8000000
+#define MSI_IOVA_LENGTH                        0x100000
+
+#define VIOMMU_REQUEST_VQ              0
+#define VIOMMU_EVENT_VQ                        1
+#define VIOMMU_NR_VQS                  2
+
+struct viommu_dev {
+       struct iommu_device             iommu;
+       struct device                   *dev;
+       struct virtio_device            *vdev;
+
+       struct ida                      domain_ids;
+
+       struct virtqueue                *vqs[VIOMMU_NR_VQS];
+       spinlock_t                      request_lock;
+       struct list_head                requests;
+       void                            *evts;
+
+       /* Device configuration */
+       struct iommu_domain_geometry    geometry;
+       u64                             pgsize_bitmap;
+       u8                              domain_bits;
+       u32                             probe_size;
+};
+
+struct viommu_mapping {
+       phys_addr_t                     paddr;
+       struct interval_tree_node       iova;
+       u32                             flags;
+};
+
+struct viommu_domain {
+       struct iommu_domain             domain;
+       struct viommu_dev               *viommu;
+       struct mutex                    mutex; /* protects viommu pointer */
+       unsigned int                    id;
+
+       spinlock_t                      mappings_lock;
+       struct rb_root_cached           mappings;
+
+       unsigned long                   nr_endpoints;
+};
+
+struct viommu_endpoint {
+       struct device                   *dev;
+       struct viommu_dev               *viommu;
+       struct viommu_domain            *vdomain;
+       struct list_head                resv_regions;
+};
+
+struct viommu_request {
+       struct list_head                list;
+       void                            *writeback;
+       unsigned int                    write_offset;
+       unsigned int                    len;
+       char                            buf[];
+};
+
+#define VIOMMU_FAULT_RESV_MASK         0xffffff00
+
+struct viommu_event {
+       union {
+               u32                     head;
+               struct virtio_iommu_fault fault;
+       };
+};
+
+#define to_viommu_domain(domain)       \
+       container_of(domain, struct viommu_domain, domain)
+
+static int viommu_get_req_errno(void *buf, size_t len)
+{
+       struct virtio_iommu_req_tail *tail = buf + len - sizeof(*tail);
+
+       switch (tail->status) {
+       case VIRTIO_IOMMU_S_OK:
+               return 0;
+       case VIRTIO_IOMMU_S_UNSUPP:
+               return -ENOSYS;
+       case VIRTIO_IOMMU_S_INVAL:
+               return -EINVAL;
+       case VIRTIO_IOMMU_S_RANGE:
+               return -ERANGE;
+       case VIRTIO_IOMMU_S_NOENT:
+               return -ENOENT;
+       case VIRTIO_IOMMU_S_FAULT:
+               return -EFAULT;
+       case VIRTIO_IOMMU_S_IOERR:
+       case VIRTIO_IOMMU_S_DEVERR:
+       default:
+               return -EIO;
+       }
+}
+
+static void viommu_set_req_status(void *buf, size_t len, int status)
+{
+       struct virtio_iommu_req_tail *tail = buf + len - sizeof(*tail);
+
+       tail->status = status;
+}
+
+static off_t viommu_get_write_desc_offset(struct viommu_dev *viommu,
+                                         struct virtio_iommu_req_head *req,
+                                         size_t len)
+{
+       size_t tail_size = sizeof(struct virtio_iommu_req_tail);
+
+       if (req->type == VIRTIO_IOMMU_T_PROBE)
+               return len - viommu->probe_size - tail_size;
+
+       return len - tail_size;
+}
+
+/*
+ * __viommu_sync_req - Complete all in-flight requests
+ *
+ * Wait for all added requests to complete. When this function returns, all
+ * requests that were in-flight at the time of the call have completed.
+ */
+static int __viommu_sync_req(struct viommu_dev *viommu)
+{
+       int ret = 0;
+       unsigned int len;
+       size_t write_len;
+       struct viommu_request *req;
+       struct virtqueue *vq = viommu->vqs[VIOMMU_REQUEST_VQ];
+
+       assert_spin_locked(&viommu->request_lock);
+
+       virtqueue_kick(vq);
+
+       while (!list_empty(&viommu->requests)) {
+               len = 0;
+               req = virtqueue_get_buf(vq, &len);
+               if (!req)
+                       continue;
+
+               if (!len)
+                       viommu_set_req_status(req->buf, req->len,
+                                             VIRTIO_IOMMU_S_IOERR);
+
+               write_len = req->len - req->write_offset;
+               if (req->writeback && len == write_len)
+                       memcpy(req->writeback, req->buf + req->write_offset,
+                              write_len);
+
+               list_del(&req->list);
+               kfree(req);
+       }
+
+       return ret;
+}
+
+static int viommu_sync_req(struct viommu_dev *viommu)
+{
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&viommu->request_lock, flags);
+       ret = __viommu_sync_req(viommu);
+       if (ret)
+               dev_dbg(viommu->dev, "could not sync requests (%d)\n", ret);
+       spin_unlock_irqrestore(&viommu->request_lock, flags);
+
+       return ret;
+}
+
+/*
+ * __viommu_add_request - Add one request to the queue
+ * @buf: pointer to the request buffer
+ * @len: length of the request buffer
+ * @writeback: copy data back to the buffer when the request completes.
+ *
+ * Add a request to the queue. Only synchronize the queue if it's already full.
+ * Otherwise don't kick the queue nor wait for requests to complete.
+ *
+ * When @writeback is true, data written by the device, including the request
+ * status, is copied into @buf after the request completes. This is unsafe if
+ * the caller allocates @buf on stack and drops the lock between add_req() and
+ * sync_req().
+ *
+ * Return 0 if the request was successfully added to the queue.
+ */
+static int __viommu_add_req(struct viommu_dev *viommu, void *buf, size_t len,
+                           bool writeback)
+{
+       int ret;
+       off_t write_offset;
+       struct viommu_request *req;
+       struct scatterlist top_sg, bottom_sg;
+       struct scatterlist *sg[2] = { &top_sg, &bottom_sg };
+       struct virtqueue *vq = viommu->vqs[VIOMMU_REQUEST_VQ];
+
+       assert_spin_locked(&viommu->request_lock);
+
+       write_offset = viommu_get_write_desc_offset(viommu, buf, len);
+       if (write_offset <= 0)
+               return -EINVAL;
+
+       req = kzalloc(sizeof(*req) + len, GFP_ATOMIC);
+       if (!req)
+               return -ENOMEM;
+
+       req->len = len;
+       if (writeback) {
+               req->writeback = buf + write_offset;
+               req->write_offset = write_offset;
+       }
+       memcpy(&req->buf, buf, write_offset);
+
+       sg_init_one(&top_sg, req->buf, write_offset);
+       sg_init_one(&bottom_sg, req->buf + write_offset, len - write_offset);
+
+       ret = virtqueue_add_sgs(vq, sg, 1, 1, req, GFP_ATOMIC);
+       if (ret == -ENOSPC) {
+               /* If the queue is full, sync and retry */
+               if (!__viommu_sync_req(viommu))
+                       ret = virtqueue_add_sgs(vq, sg, 1, 1, req, GFP_ATOMIC);
+       }
+       if (ret)
+               goto err_free;
+
+       list_add_tail(&req->list, &viommu->requests);
+       return 0;
+
+err_free:
+       kfree(req);
+       return ret;
+}
+
+static int viommu_add_req(struct viommu_dev *viommu, void *buf, size_t len)
+{
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&viommu->request_lock, flags);
+       ret = __viommu_add_req(viommu, buf, len, false);
+       if (ret)
+               dev_dbg(viommu->dev, "could not add request: %d\n", ret);
+       spin_unlock_irqrestore(&viommu->request_lock, flags);
+
+       return ret;
+}
+
+/*
+ * Send a request and wait for it to complete. Return the request status (as an
+ * errno)
+ */
+static int viommu_send_req_sync(struct viommu_dev *viommu, void *buf,
+                               size_t len)
+{
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&viommu->request_lock, flags);
+
+       ret = __viommu_add_req(viommu, buf, len, true);
+       if (ret) {
+               dev_dbg(viommu->dev, "could not add request (%d)\n", ret);
+               goto out_unlock;
+       }
+
+       ret = __viommu_sync_req(viommu);
+       if (ret) {
+               dev_dbg(viommu->dev, "could not sync requests (%d)\n", ret);
+               /* Fall-through (get the actual request status) */
+       }
+
+       ret = viommu_get_req_errno(buf, len);
+out_unlock:
+       spin_unlock_irqrestore(&viommu->request_lock, flags);
+       return ret;
+}
+
+/*
+ * viommu_add_mapping - add a mapping to the internal tree
+ *
+ * On success, return the new mapping. Otherwise return NULL.
+ */
+static int viommu_add_mapping(struct viommu_domain *vdomain, unsigned long iova,
+                             phys_addr_t paddr, size_t size, u32 flags)
+{
+       unsigned long irqflags;
+       struct viommu_mapping *mapping;
+
+       mapping = kzalloc(sizeof(*mapping), GFP_ATOMIC);
+       if (!mapping)
+               return -ENOMEM;
+
+       mapping->paddr          = paddr;
+       mapping->iova.start     = iova;
+       mapping->iova.last      = iova + size - 1;
+       mapping->flags          = flags;
+
+       spin_lock_irqsave(&vdomain->mappings_lock, irqflags);
+       interval_tree_insert(&mapping->iova, &vdomain->mappings);
+       spin_unlock_irqrestore(&vdomain->mappings_lock, irqflags);
+
+       return 0;
+}
+
+/*
+ * viommu_del_mappings - remove mappings from the internal tree
+ *
+ * @vdomain: the domain
+ * @iova: start of the range
+ * @size: size of the range. A size of 0 corresponds to the entire address
+ *     space.
+ *
+ * On success, returns the number of unmapped bytes (>= size)
+ */
+static size_t viommu_del_mappings(struct viommu_domain *vdomain,
+                                 unsigned long iova, size_t size)
+{
+       size_t unmapped = 0;
+       unsigned long flags;
+       unsigned long last = iova + size - 1;
+       struct viommu_mapping *mapping = NULL;
+       struct interval_tree_node *node, *next;
+
+       spin_lock_irqsave(&vdomain->mappings_lock, flags);
+       next = interval_tree_iter_first(&vdomain->mappings, iova, last);
+       while (next) {
+               node = next;
+               mapping = container_of(node, struct viommu_mapping, iova);
+               next = interval_tree_iter_next(node, iova, last);
+
+               /* Trying to split a mapping? */
+               if (mapping->iova.start < iova)
+                       break;
+
+               /*
+                * Virtio-iommu doesn't allow UNMAP to split a mapping created
+                * with a single MAP request, so remove the full mapping.
+                */
+               unmapped += mapping->iova.last - mapping->iova.start + 1;
+
+               interval_tree_remove(node, &vdomain->mappings);
+               kfree(mapping);
+       }
+       spin_unlock_irqrestore(&vdomain->mappings_lock, flags);
+
+       return unmapped;
+}
+
+/*
+ * viommu_replay_mappings - re-send MAP requests
+ *
+ * When reattaching a domain that was previously detached from all endpoints,
+ * mappings were deleted from the device. Re-create the mappings available in
+ * the internal tree.
+ */
+static int viommu_replay_mappings(struct viommu_domain *vdomain)
+{
+       int ret = 0;
+       unsigned long flags;
+       struct viommu_mapping *mapping;
+       struct interval_tree_node *node;
+       struct virtio_iommu_req_map map;
+
+       spin_lock_irqsave(&vdomain->mappings_lock, flags);
+       node = interval_tree_iter_first(&vdomain->mappings, 0, -1UL);
+       while (node) {
+               mapping = container_of(node, struct viommu_mapping, iova);
+               map = (struct virtio_iommu_req_map) {
+                       .head.type      = VIRTIO_IOMMU_T_MAP,
+                       .domain         = cpu_to_le32(vdomain->id),
+                       .virt_start     = cpu_to_le64(mapping->iova.start),
+                       .virt_end       = cpu_to_le64(mapping->iova.last),
+                       .phys_start     = cpu_to_le64(mapping->paddr),
+                       .flags          = cpu_to_le32(mapping->flags),
+               };
+
+               ret = viommu_send_req_sync(vdomain->viommu, &map, sizeof(map));
+               if (ret)
+                       break;
+
+               node = interval_tree_iter_next(node, 0, -1UL);
+       }
+       spin_unlock_irqrestore(&vdomain->mappings_lock, flags);
+
+       return ret;
+}
+
+static int viommu_add_resv_mem(struct viommu_endpoint *vdev,
+                              struct virtio_iommu_probe_resv_mem *mem,
+                              size_t len)
+{
+       size_t size;
+       u64 start64, end64;
+       phys_addr_t start, end;
+       struct iommu_resv_region *region = NULL;
+       unsigned long prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
+
+       start = start64 = le64_to_cpu(mem->start);
+       end = end64 = le64_to_cpu(mem->end);
+       size = end64 - start64 + 1;
+
+       /* Catch any overflow, including the unlikely end64 - start64 + 1 = 0 */
+       if (start != start64 || end != end64 || size < end64 - start64)
+               return -EOVERFLOW;
+
+       if (len < sizeof(*mem))
+               return -EINVAL;
+
+       switch (mem->subtype) {
+       default:
+               dev_warn(vdev->dev, "unknown resv mem subtype 0x%x\n",
+                        mem->subtype);
+               /* Fall-through */
+       case VIRTIO_IOMMU_RESV_MEM_T_RESERVED:
+               region = iommu_alloc_resv_region(start, size, 0,
+                                                IOMMU_RESV_RESERVED);
+               break;
+       case VIRTIO_IOMMU_RESV_MEM_T_MSI:
+               region = iommu_alloc_resv_region(start, size, prot,
+                                                IOMMU_RESV_MSI);
+               break;
+       }
+       if (!region)
+               return -ENOMEM;
+
+       list_add(&vdev->resv_regions, &region->list);
+       return 0;
+}
+
+static int viommu_probe_endpoint(struct viommu_dev *viommu, struct device *dev)
+{
+       int ret;
+       u16 type, len;
+       size_t cur = 0;
+       size_t probe_len;
+       struct virtio_iommu_req_probe *probe;
+       struct virtio_iommu_probe_property *prop;
+       struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+       struct viommu_endpoint *vdev = fwspec->iommu_priv;
+
+       if (!fwspec->num_ids)
+               return -EINVAL;
+
+       probe_len = sizeof(*probe) + viommu->probe_size +
+                   sizeof(struct virtio_iommu_req_tail);
+       probe = kzalloc(probe_len, GFP_KERNEL);
+       if (!probe)
+               return -ENOMEM;
+
+       probe->head.type = VIRTIO_IOMMU_T_PROBE;
+       /*
+        * For now, assume that properties of an endpoint that outputs multiple
+        * IDs are consistent. Only probe the first one.
+        */
+       probe->endpoint = cpu_to_le32(fwspec->ids[0]);
+
+       ret = viommu_send_req_sync(viommu, probe, probe_len);
+       if (ret)
+               goto out_free;
+
+       prop = (void *)probe->properties;
+       type = le16_to_cpu(prop->type) & VIRTIO_IOMMU_PROBE_T_MASK;
+
+       while (type != VIRTIO_IOMMU_PROBE_T_NONE &&
+              cur < viommu->probe_size) {
+               len = le16_to_cpu(prop->length) + sizeof(*prop);
+
+               switch (type) {
+               case VIRTIO_IOMMU_PROBE_T_RESV_MEM:
+                       ret = viommu_add_resv_mem(vdev, (void *)prop, len);
+                       break;
+               default:
+                       dev_err(dev, "unknown viommu prop 0x%x\n", type);
+               }
+
+               if (ret)
+                       dev_err(dev, "failed to parse viommu prop 0x%x\n", type);
+
+               cur += len;
+               if (cur >= viommu->probe_size)
+                       break;
+
+               prop = (void *)probe->properties + cur;
+               type = le16_to_cpu(prop->type) & VIRTIO_IOMMU_PROBE_T_MASK;
+       }
+
+out_free:
+       kfree(probe);
+       return ret;
+}
+
+static int viommu_fault_handler(struct viommu_dev *viommu,
+                               struct virtio_iommu_fault *fault)
+{
+       char *reason_str;
+
+       u8 reason       = fault->reason;
+       u32 flags       = le32_to_cpu(fault->flags);
+       u32 endpoint    = le32_to_cpu(fault->endpoint);
+       u64 address     = le64_to_cpu(fault->address);
+
+       switch (reason) {
+       case VIRTIO_IOMMU_FAULT_R_DOMAIN:
+               reason_str = "domain";
+               break;
+       case VIRTIO_IOMMU_FAULT_R_MAPPING:
+               reason_str = "page";
+               break;
+       case VIRTIO_IOMMU_FAULT_R_UNKNOWN:
+       default:
+               reason_str = "unknown";
+               break;
+       }
+
+       /* TODO: find EP by ID and report_iommu_fault */
+       if (flags & VIRTIO_IOMMU_FAULT_F_ADDRESS)
+               dev_err_ratelimited(viommu->dev, "%s fault from EP %u at %#llx [%s%s%s]\n",
+                                   reason_str, endpoint, address,
+                                   flags & VIRTIO_IOMMU_FAULT_F_READ ? "R" : "",
+                                   flags & VIRTIO_IOMMU_FAULT_F_WRITE ? "W" : "",
+                                   flags & VIRTIO_IOMMU_FAULT_F_EXEC ? "X" : "");
+       else
+               dev_err_ratelimited(viommu->dev, "%s fault from EP %u\n",
+                                   reason_str, endpoint);
+       return 0;
+}
+
+static void viommu_event_handler(struct virtqueue *vq)
+{
+       int ret;
+       unsigned int len;
+       struct scatterlist sg[1];
+       struct viommu_event *evt;
+       struct viommu_dev *viommu = vq->vdev->priv;
+
+       while ((evt = virtqueue_get_buf(vq, &len)) != NULL) {
+               if (len > sizeof(*evt)) {
+                       dev_err(viommu->dev,
+                               "invalid event buffer (len %u != %zu)\n",
+                               len, sizeof(*evt));
+               } else if (!(evt->head & VIOMMU_FAULT_RESV_MASK)) {
+                       viommu_fault_handler(viommu, &evt->fault);
+               }
+
+               sg_init_one(sg, evt, sizeof(*evt));
+               ret = virtqueue_add_inbuf(vq, sg, 1, evt, GFP_ATOMIC);
+               if (ret)
+                       dev_err(viommu->dev, "could not add event buffer\n");
+       }
+
+       virtqueue_kick(vq);
+}
+
+/* IOMMU API */
+
+static struct iommu_domain *viommu_domain_alloc(unsigned type)
+{
+       struct viommu_domain *vdomain;
+
+       if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA)
+               return NULL;
+
+       vdomain = kzalloc(sizeof(*vdomain), GFP_KERNEL);
+       if (!vdomain)
+               return NULL;
+
+       mutex_init(&vdomain->mutex);
+       spin_lock_init(&vdomain->mappings_lock);
+       vdomain->mappings = RB_ROOT_CACHED;
+
+       if (type == IOMMU_DOMAIN_DMA &&
+           iommu_get_dma_cookie(&vdomain->domain)) {
+               kfree(vdomain);
+               return NULL;
+       }
+
+       return &vdomain->domain;
+}
+
+static int viommu_domain_finalise(struct viommu_dev *viommu,
+                                 struct iommu_domain *domain)
+{
+       int ret;
+       struct viommu_domain *vdomain = to_viommu_domain(domain);
+       unsigned int max_domain = viommu->domain_bits > 31 ? ~0 :
+                                 (1U << viommu->domain_bits) - 1;
+
+       vdomain->viommu         = viommu;
+
+       domain->pgsize_bitmap   = viommu->pgsize_bitmap;
+       domain->geometry        = viommu->geometry;
+
+       ret = ida_alloc_max(&viommu->domain_ids, max_domain, GFP_KERNEL);
+       if (ret >= 0)
+               vdomain->id = (unsigned int)ret;
+
+       return ret > 0 ? 0 : ret;
+}
+
+static void viommu_domain_free(struct iommu_domain *domain)
+{
+       struct viommu_domain *vdomain = to_viommu_domain(domain);
+
+       iommu_put_dma_cookie(domain);
+
+       /* Free all remaining mappings (size 2^64) */
+       viommu_del_mappings(vdomain, 0, 0);
+
+       if (vdomain->viommu)
+               ida_free(&vdomain->viommu->domain_ids, vdomain->id);
+
+       kfree(vdomain);
+}
+
+static int viommu_attach_dev(struct iommu_domain *domain, struct device *dev)
+{
+       int i;
+       int ret = 0;
+       struct virtio_iommu_req_attach req;
+       struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+       struct viommu_endpoint *vdev = fwspec->iommu_priv;
+       struct viommu_domain *vdomain = to_viommu_domain(domain);
+
+       mutex_lock(&vdomain->mutex);
+       if (!vdomain->viommu) {
+               /*
+                * Properly initialize the domain now that we know which viommu
+                * owns it.
+                */
+               ret = viommu_domain_finalise(vdev->viommu, domain);
+       } else if (vdomain->viommu != vdev->viommu) {
+               dev_err(dev, "cannot attach to foreign vIOMMU\n");
+               ret = -EXDEV;
+       }
+       mutex_unlock(&vdomain->mutex);
+
+       if (ret)
+               return ret;
+
+       /*
+        * In the virtio-iommu device, when attaching the endpoint to a new
+        * domain, it is detached from the old one and, if as as a result the
+        * old domain isn't attached to any endpoint, all mappings are removed
+        * from the old domain and it is freed.
+        *
+        * In the driver the old domain still exists, and its mappings will be
+        * recreated if it gets reattached to an endpoint. Otherwise it will be
+        * freed explicitly.
+        *
+        * vdev->vdomain is protected by group->mutex
+        */
+       if (vdev->vdomain)
+               vdev->vdomain->nr_endpoints--;
+
+       req = (struct virtio_iommu_req_attach) {
+               .head.type      = VIRTIO_IOMMU_T_ATTACH,
+               .domain         = cpu_to_le32(vdomain->id),
+       };
+
+       for (i = 0; i < fwspec->num_ids; i++) {
+               req.endpoint = cpu_to_le32(fwspec->ids[i]);
+
+               ret = viommu_send_req_sync(vdomain->viommu, &req, sizeof(req));
+               if (ret)
+                       return ret;
+       }
+
+       if (!vdomain->nr_endpoints) {
+               /*
+                * This endpoint is the first to be attached to the domain.
+                * Replay existing mappings (e.g. SW MSI).
+                */
+               ret = viommu_replay_mappings(vdomain);
+               if (ret)
+                       return ret;
+       }
+
+       vdomain->nr_endpoints++;
+       vdev->vdomain = vdomain;
+
+       return 0;
+}
+
+static int viommu_map(struct iommu_domain *domain, unsigned long iova,
+                     phys_addr_t paddr, size_t size, int prot)
+{
+       int ret;
+       int flags;
+       struct virtio_iommu_req_map map;
+       struct viommu_domain *vdomain = to_viommu_domain(domain);
+
+       flags = (prot & IOMMU_READ ? VIRTIO_IOMMU_MAP_F_READ : 0) |
+               (prot & IOMMU_WRITE ? VIRTIO_IOMMU_MAP_F_WRITE : 0) |
+               (prot & IOMMU_MMIO ? VIRTIO_IOMMU_MAP_F_MMIO : 0);
+
+       ret = viommu_add_mapping(vdomain, iova, paddr, size, flags);
+       if (ret)
+               return ret;
+
+       map = (struct virtio_iommu_req_map) {
+               .head.type      = VIRTIO_IOMMU_T_MAP,
+               .domain         = cpu_to_le32(vdomain->id),
+               .virt_start     = cpu_to_le64(iova),
+               .phys_start     = cpu_to_le64(paddr),
+               .virt_end       = cpu_to_le64(iova + size - 1),
+               .flags          = cpu_to_le32(flags),
+       };
+
+       if (!vdomain->nr_endpoints)
+               return 0;
+
+       ret = viommu_send_req_sync(vdomain->viommu, &map, sizeof(map));
+       if (ret)
+               viommu_del_mappings(vdomain, iova, size);
+
+       return ret;
+}
+
+static size_t viommu_unmap(struct iommu_domain *domain, unsigned long iova,
+                          size_t size)
+{
+       int ret = 0;
+       size_t unmapped;
+       struct virtio_iommu_req_unmap unmap;
+       struct viommu_domain *vdomain = to_viommu_domain(domain);
+
+       unmapped = viommu_del_mappings(vdomain, iova, size);
+       if (unmapped < size)
+               return 0;
+
+       /* Device already removed all mappings after detach. */
+       if (!vdomain->nr_endpoints)
+               return unmapped;
+
+       unmap = (struct virtio_iommu_req_unmap) {
+               .head.type      = VIRTIO_IOMMU_T_UNMAP,
+               .domain         = cpu_to_le32(vdomain->id),
+               .virt_start     = cpu_to_le64(iova),
+               .virt_end       = cpu_to_le64(iova + unmapped - 1),
+       };
+
+       ret = viommu_add_req(vdomain->viommu, &unmap, sizeof(unmap));
+       return ret ? 0 : unmapped;
+}
+
+static phys_addr_t viommu_iova_to_phys(struct iommu_domain *domain,
+                                      dma_addr_t iova)
+{
+       u64 paddr = 0;
+       unsigned long flags;
+       struct viommu_mapping *mapping;
+       struct interval_tree_node *node;
+       struct viommu_domain *vdomain = to_viommu_domain(domain);
+
+       spin_lock_irqsave(&vdomain->mappings_lock, flags);
+       node = interval_tree_iter_first(&vdomain->mappings, iova, iova);
+       if (node) {
+               mapping = container_of(node, struct viommu_mapping, iova);
+               paddr = mapping->paddr + (iova - mapping->iova.start);
+       }
+       spin_unlock_irqrestore(&vdomain->mappings_lock, flags);
+
+       return paddr;
+}
+
+static void viommu_iotlb_sync(struct iommu_domain *domain)
+{
+       struct viommu_domain *vdomain = to_viommu_domain(domain);
+
+       viommu_sync_req(vdomain->viommu);
+}
+
+static void viommu_get_resv_regions(struct device *dev, struct list_head *head)
+{
+       struct iommu_resv_region *entry, *new_entry, *msi = NULL;
+       struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+       struct viommu_endpoint *vdev = fwspec->iommu_priv;
+       int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
+
+       list_for_each_entry(entry, &vdev->resv_regions, list) {
+               if (entry->type == IOMMU_RESV_MSI)
+                       msi = entry;
+
+               new_entry = kmemdup(entry, sizeof(*entry), GFP_KERNEL);
+               if (!new_entry)
+                       return;
+               list_add_tail(&new_entry->list, head);
+       }
+
+       /*
+        * If the device didn't register any bypass MSI window, add a
+        * software-mapped region.
+        */
+       if (!msi) {
+               msi = iommu_alloc_resv_region(MSI_IOVA_BASE, MSI_IOVA_LENGTH,
+                                             prot, IOMMU_RESV_SW_MSI);
+               if (!msi)
+                       return;
+
+               list_add_tail(&msi->list, head);
+       }
+
+       iommu_dma_get_resv_regions(dev, head);
+}
+
+static void viommu_put_resv_regions(struct device *dev, struct list_head *head)
+{
+       struct iommu_resv_region *entry, *next;
+
+       list_for_each_entry_safe(entry, next, head, list)
+               kfree(entry);
+}
+
+static struct iommu_ops viommu_ops;
+static struct virtio_driver virtio_iommu_drv;
+
+static int viommu_match_node(struct device *dev, const void *data)
+{
+       return dev->parent->fwnode == data;
+}
+
+static struct viommu_dev *viommu_get_by_fwnode(struct fwnode_handle *fwnode)
+{
+       struct device *dev = driver_find_device(&virtio_iommu_drv.driver, NULL,
+                                               fwnode, viommu_match_node);
+       put_device(dev);
+
+       return dev ? dev_to_virtio(dev)->priv : NULL;
+}
+
+static int viommu_add_device(struct device *dev)
+{
+       int ret;
+       struct iommu_group *group;
+       struct viommu_endpoint *vdev;
+       struct viommu_dev *viommu = NULL;
+       struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+
+       if (!fwspec || fwspec->ops != &viommu_ops)
+               return -ENODEV;
+
+       viommu = viommu_get_by_fwnode(fwspec->iommu_fwnode);
+       if (!viommu)
+               return -ENODEV;
+
+       vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
+       if (!vdev)
+               return -ENOMEM;
+
+       vdev->dev = dev;
+       vdev->viommu = viommu;
+       INIT_LIST_HEAD(&vdev->resv_regions);
+       fwspec->iommu_priv = vdev;
+
+       if (viommu->probe_size) {
+               /* Get additional information for this endpoint */
+               ret = viommu_probe_endpoint(viommu, dev);
+               if (ret)
+                       goto err_free_dev;
+       }
+
+       ret = iommu_device_link(&viommu->iommu, dev);
+       if (ret)
+               goto err_free_dev;
+
+       /*
+        * Last step creates a default domain and attaches to it. Everything
+        * must be ready.
+        */
+       group = iommu_group_get_for_dev(dev);
+       if (IS_ERR(group)) {
+               ret = PTR_ERR(group);
+               goto err_unlink_dev;
+       }
+
+       iommu_group_put(group);
+
+       return PTR_ERR_OR_ZERO(group);
+
+err_unlink_dev:
+       iommu_device_unlink(&viommu->iommu, dev);
+err_free_dev:
+       viommu_put_resv_regions(dev, &vdev->resv_regions);
+       kfree(vdev);
+
+       return ret;
+}
+
+static void viommu_remove_device(struct device *dev)
+{
+       struct viommu_endpoint *vdev;
+       struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+
+       if (!fwspec || fwspec->ops != &viommu_ops)
+               return;
+
+       vdev = fwspec->iommu_priv;
+
+       iommu_group_remove_device(dev);
+       iommu_device_unlink(&vdev->viommu->iommu, dev);
+       viommu_put_resv_regions(dev, &vdev->resv_regions);
+       kfree(vdev);
+}
+
+static struct iommu_group *viommu_device_group(struct device *dev)
+{
+       if (dev_is_pci(dev))
+               return pci_device_group(dev);
+       else
+               return generic_device_group(dev);
+}
+
+static int viommu_of_xlate(struct device *dev, struct of_phandle_args *args)
+{
+       return iommu_fwspec_add_ids(dev, args->args, 1);
+}
+
+static struct iommu_ops viommu_ops = {
+       .domain_alloc           = viommu_domain_alloc,
+       .domain_free            = viommu_domain_free,
+       .attach_dev             = viommu_attach_dev,
+       .map                    = viommu_map,
+       .unmap                  = viommu_unmap,
+       .iova_to_phys           = viommu_iova_to_phys,
+       .iotlb_sync             = viommu_iotlb_sync,
+       .add_device             = viommu_add_device,
+       .remove_device          = viommu_remove_device,
+       .device_group           = viommu_device_group,
+       .get_resv_regions       = viommu_get_resv_regions,
+       .put_resv_regions       = viommu_put_resv_regions,
+       .of_xlate               = viommu_of_xlate,
+};
+
+static int viommu_init_vqs(struct viommu_dev *viommu)
+{
+       struct virtio_device *vdev = dev_to_virtio(viommu->dev);
+       const char *names[] = { "request", "event" };
+       vq_callback_t *callbacks[] = {
+               NULL, /* No async requests */
+               viommu_event_handler,
+       };
+
+       return virtio_find_vqs(vdev, VIOMMU_NR_VQS, viommu->vqs, callbacks,
+                              names, NULL);
+}
+
+static int viommu_fill_evtq(struct viommu_dev *viommu)
+{
+       int i, ret;
+       struct scatterlist sg[1];
+       struct viommu_event *evts;
+       struct virtqueue *vq = viommu->vqs[VIOMMU_EVENT_VQ];
+       size_t nr_evts = vq->num_free;
+
+       viommu->evts = evts = devm_kmalloc_array(viommu->dev, nr_evts,
+                                                sizeof(*evts), GFP_KERNEL);
+       if (!evts)
+               return -ENOMEM;
+
+       for (i = 0; i < nr_evts; i++) {
+               sg_init_one(sg, &evts[i], sizeof(*evts));
+               ret = virtqueue_add_inbuf(vq, sg, 1, &evts[i], GFP_KERNEL);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int viommu_probe(struct virtio_device *vdev)
+{
+       struct device *parent_dev = vdev->dev.parent;
+       struct viommu_dev *viommu = NULL;
+       struct device *dev = &vdev->dev;
+       u64 input_start = 0;
+       u64 input_end = -1UL;
+       int ret;
+
+       if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1) ||
+           !virtio_has_feature(vdev, VIRTIO_IOMMU_F_MAP_UNMAP))
+               return -ENODEV;
+
+       viommu = devm_kzalloc(dev, sizeof(*viommu), GFP_KERNEL);
+       if (!viommu)
+               return -ENOMEM;
+
+       spin_lock_init(&viommu->request_lock);
+       ida_init(&viommu->domain_ids);
+       viommu->dev = dev;
+       viommu->vdev = vdev;
+       INIT_LIST_HEAD(&viommu->requests);
+
+       ret = viommu_init_vqs(viommu);
+       if (ret)
+               return ret;
+
+       virtio_cread(vdev, struct virtio_iommu_config, page_size_mask,
+                    &viommu->pgsize_bitmap);
+
+       if (!viommu->pgsize_bitmap) {
+               ret = -EINVAL;
+               goto err_free_vqs;
+       }
+
+       viommu->domain_bits = 32;
+
+       /* Optional features */
+       virtio_cread_feature(vdev, VIRTIO_IOMMU_F_INPUT_RANGE,
+                            struct virtio_iommu_config, input_range.start,
+                            &input_start);
+
+       virtio_cread_feature(vdev, VIRTIO_IOMMU_F_INPUT_RANGE,
+                            struct virtio_iommu_config, input_range.end,
+                            &input_end);
+
+       virtio_cread_feature(vdev, VIRTIO_IOMMU_F_DOMAIN_BITS,
+                            struct virtio_iommu_config, domain_bits,
+                            &viommu->domain_bits);
+
+       virtio_cread_feature(vdev, VIRTIO_IOMMU_F_PROBE,
+                            struct virtio_iommu_config, probe_size,
+                            &viommu->probe_size);
+
+       viommu->geometry = (struct iommu_domain_geometry) {
+               .aperture_start = input_start,
+               .aperture_end   = input_end,
+               .force_aperture = true,
+       };
+
+       viommu_ops.pgsize_bitmap = viommu->pgsize_bitmap;
+
+       virtio_device_ready(vdev);
+
+       /* Populate the event queue with buffers */
+       ret = viommu_fill_evtq(viommu);
+       if (ret)
+               goto err_free_vqs;
+
+       ret = iommu_device_sysfs_add(&viommu->iommu, dev, NULL, "%s",
+                                    virtio_bus_name(vdev));
+       if (ret)
+               goto err_free_vqs;
+
+       iommu_device_set_ops(&viommu->iommu, &viommu_ops);
+       iommu_device_set_fwnode(&viommu->iommu, parent_dev->fwnode);
+
+       iommu_device_register(&viommu->iommu);
+
+#ifdef CONFIG_PCI
+       if (pci_bus_type.iommu_ops != &viommu_ops) {
+               pci_request_acs();
+               ret = bus_set_iommu(&pci_bus_type, &viommu_ops);
+               if (ret)
+                       goto err_unregister;
+       }
+#endif
+#ifdef CONFIG_ARM_AMBA
+       if (amba_bustype.iommu_ops != &viommu_ops) {
+               ret = bus_set_iommu(&amba_bustype, &viommu_ops);
+               if (ret)
+                       goto err_unregister;
+       }
+#endif
+       if (platform_bus_type.iommu_ops != &viommu_ops) {
+               ret = bus_set_iommu(&platform_bus_type, &viommu_ops);
+               if (ret)
+                       goto err_unregister;
+       }
+
+       vdev->priv = viommu;
+
+       dev_info(dev, "input address: %u bits\n",
+                order_base_2(viommu->geometry.aperture_end));
+       dev_info(dev, "page mask: %#llx\n", viommu->pgsize_bitmap);
+
+       return 0;
+
+err_unregister:
+       iommu_device_sysfs_remove(&viommu->iommu);
+       iommu_device_unregister(&viommu->iommu);
+err_free_vqs:
+       vdev->config->del_vqs(vdev);
+
+       return ret;
+}
+
+static void viommu_remove(struct virtio_device *vdev)
+{
+       struct viommu_dev *viommu = vdev->priv;
+
+       iommu_device_sysfs_remove(&viommu->iommu);
+       iommu_device_unregister(&viommu->iommu);
+
+       /* Stop all virtqueues */
+       vdev->config->reset(vdev);
+       vdev->config->del_vqs(vdev);
+
+       dev_info(&vdev->dev, "device removed\n");
+}
+
+static void viommu_config_changed(struct virtio_device *vdev)
+{
+       dev_warn(&vdev->dev, "config changed\n");
+}
+
+static unsigned int features[] = {
+       VIRTIO_IOMMU_F_MAP_UNMAP,
+       VIRTIO_IOMMU_F_DOMAIN_BITS,
+       VIRTIO_IOMMU_F_INPUT_RANGE,
+       VIRTIO_IOMMU_F_PROBE,
+};
+
+static struct virtio_device_id id_table[] = {
+       { VIRTIO_ID_IOMMU, VIRTIO_DEV_ANY_ID },
+       { 0 },
+};
+
+static struct virtio_driver virtio_iommu_drv = {
+       .driver.name            = KBUILD_MODNAME,
+       .driver.owner           = THIS_MODULE,
+       .id_table               = id_table,
+       .feature_table          = features,
+       .feature_table_size     = ARRAY_SIZE(features),
+       .probe                  = viommu_probe,
+       .remove                 = viommu_remove,
+       .config_changed         = viommu_config_changed,
+};
+
+module_virtio_driver(virtio_iommu_drv);
+
+MODULE_DESCRIPTION("Virtio IOMMU driver");
+MODULE_AUTHOR("Jean-Philippe Brucker <jean-philippe.brucker@arm.com>");
+MODULE_LICENSE("GPL v2");
index 4c99739..0e22423 100644 (file)
@@ -1955,6 +1955,9 @@ hfcsusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
 
                                /* get endpoint base */
                                idx = ((ep_addr & 0x7f) - 1) * 2;
+                               if (idx > 15)
+                                       return -EIO;
+
                                if (ep_addr & 0x80)
                                        idx++;
                                attr = ep->desc.bmAttributes;
index 5ccac0b..3834332 100644 (file)
@@ -453,7 +453,7 @@ config DM_INIT
        Enable "dm-mod.create=" parameter to create mapped devices at init time.
        This option is useful to allow mounting rootfs without requiring an
        initramfs.
-       See Documentation/device-mapper/dm-init.rst for dm-mod.create="..."
+       See Documentation/admin-guide/device-mapper/dm-init.rst for dm-mod.create="..."
        format.
 
        If unsure, say N.
index b65faef..b869316 100644 (file)
@@ -25,7 +25,7 @@ static char *create;
  * Format: dm-mod.create=<name>,<uuid>,<minor>,<flags>,<table>[,<table>+][;<name>,<uuid>,<minor>,<flags>,<table>[,<table>+]+]
  * Table format: <start_sector> <num_sectors> <target_type> <target_args>
  *
- * See Documentation/device-mapper/dm-init.rst for dm-mod.create="..." format
+ * See Documentation/admin-guide/device-mapper/dm-init.rst for dm-mod.create="..." format
  * details.
  */
 
index 671c243..df2011d 100644 (file)
 
 #include "dm-core.h"
 
-#define SUB_JOB_SIZE   128
 #define SPLIT_COUNT    8
 #define MIN_JOBS       8
-#define RESERVE_PAGES  (DIV_ROUND_UP(SUB_JOB_SIZE << SECTOR_SHIFT, PAGE_SIZE))
+
+#define DEFAULT_SUB_JOB_SIZE_KB 512
+#define MAX_SUB_JOB_SIZE_KB     1024
+
+static unsigned kcopyd_subjob_size_kb = DEFAULT_SUB_JOB_SIZE_KB;
+
+module_param(kcopyd_subjob_size_kb, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(kcopyd_subjob_size_kb, "Sub-job size for dm-kcopyd clients");
+
+static unsigned dm_get_kcopyd_subjob_size(void)
+{
+       unsigned sub_job_size_kb;
+
+       sub_job_size_kb = __dm_get_module_param(&kcopyd_subjob_size_kb,
+                                               DEFAULT_SUB_JOB_SIZE_KB,
+                                               MAX_SUB_JOB_SIZE_KB);
+
+       return sub_job_size_kb << 1;
+}
 
 /*-----------------------------------------------------------------
  * Each kcopyd client has its own little pool of preallocated
@@ -41,6 +58,7 @@ struct dm_kcopyd_client {
        struct page_list *pages;
        unsigned nr_reserved_pages;
        unsigned nr_free_pages;
+       unsigned sub_job_size;
 
        struct dm_io_client *io_client;
 
@@ -693,8 +711,8 @@ static void segment_complete(int read_err, unsigned long write_err,
                progress = job->progress;
                count = job->source.count - progress;
                if (count) {
-                       if (count > SUB_JOB_SIZE)
-                               count = SUB_JOB_SIZE;
+                       if (count > kc->sub_job_size)
+                               count = kc->sub_job_size;
 
                        job->progress += count;
                }
@@ -821,7 +839,7 @@ void dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
        job->master_job = job;
        job->write_offset = 0;
 
-       if (job->source.count <= SUB_JOB_SIZE)
+       if (job->source.count <= kc->sub_job_size)
                dispatch_job(job);
        else {
                job->progress = 0;
@@ -888,6 +906,7 @@ int kcopyd_cancel(struct kcopyd_job *job, int block)
 struct dm_kcopyd_client *dm_kcopyd_client_create(struct dm_kcopyd_throttle *throttle)
 {
        int r;
+       unsigned reserve_pages;
        struct dm_kcopyd_client *kc;
 
        kc = kzalloc(sizeof(*kc), GFP_KERNEL);
@@ -912,9 +931,12 @@ struct dm_kcopyd_client *dm_kcopyd_client_create(struct dm_kcopyd_throttle *thro
                goto bad_workqueue;
        }
 
+       kc->sub_job_size = dm_get_kcopyd_subjob_size();
+       reserve_pages = DIV_ROUND_UP(kc->sub_job_size << SECTOR_SHIFT, PAGE_SIZE);
+
        kc->pages = NULL;
        kc->nr_reserved_pages = kc->nr_free_pages = 0;
-       r = client_reserve_pages(kc, RESERVE_PAGES);
+       r = client_reserve_pages(kc, reserve_pages);
        if (r)
                goto bad_client_pages;
 
index 7a87a64..8a60a4a 100644 (file)
@@ -3558,7 +3558,7 @@ static void raid_status(struct dm_target *ti, status_type_t type,
                 * v1.5.0+:
                 *
                 * Sync action:
-                *   See Documentation/device-mapper/dm-raid.rst for
+                *   See Documentation/admin-guide/device-mapper/dm-raid.rst for
                 *   information on each of these states.
                 */
                DMEMIT(" %s", sync_action);
index 63916e1..f150f5c 100644 (file)
@@ -2072,6 +2072,12 @@ static int snapshot_merge_map(struct dm_target *ti, struct bio *bio)
                return DM_MAPIO_REMAPPED;
        }
 
+       if (unlikely(bio_op(bio) == REQ_OP_DISCARD)) {
+               /* Once merging, discards no longer effect change */
+               bio_endio(bio);
+               return DM_MAPIO_SUBMITTED;
+       }
+
        chunk = sector_to_chunk(s->store, bio->bi_iter.bi_sector);
 
        down_write(&s->lock);
@@ -2331,6 +2337,8 @@ static void snapshot_io_hints(struct dm_target *ti, struct queue_limits *limits)
        if (snap->discard_zeroes_cow) {
                struct dm_snapshot *snap_src = NULL, *snap_dest = NULL;
 
+               down_read(&_origins_lock);
+
                (void) __find_snapshots_sharing_cow(snap, &snap_src, &snap_dest, NULL);
                if (snap_src && snap_dest)
                        snap = snap_src;
@@ -2338,6 +2346,8 @@ static void snapshot_io_hints(struct dm_target *ti, struct queue_limits *limits)
                /* All discards are split on chunk_size boundary */
                limits->discard_granularity = snap->store->chunk_size;
                limits->max_discard_sectors = snap->store->chunk_size;
+
+               up_read(&_origins_lock);
        }
 }
 
index ec8b27e..caaee80 100644 (file)
@@ -881,7 +881,7 @@ void dm_table_set_type(struct dm_table *t, enum dm_queue_mode type)
 EXPORT_SYMBOL_GPL(dm_table_set_type);
 
 /* validate the dax capability of the target device span */
-static int device_supports_dax(struct dm_target *ti, struct dm_dev *dev,
+int device_supports_dax(struct dm_target *ti, struct dm_dev *dev,
                                       sector_t start, sector_t len, void *data)
 {
        int blocksize = *(int *) data;
@@ -890,7 +890,15 @@ static int device_supports_dax(struct dm_target *ti, struct dm_dev *dev,
                        start, len);
 }
 
-bool dm_table_supports_dax(struct dm_table *t, int blocksize)
+/* Check devices support synchronous DAX */
+static int device_synchronous(struct dm_target *ti, struct dm_dev *dev,
+                                      sector_t start, sector_t len, void *data)
+{
+       return dax_synchronous(dev->dax_dev);
+}
+
+bool dm_table_supports_dax(struct dm_table *t,
+                         iterate_devices_callout_fn iterate_fn, int *blocksize)
 {
        struct dm_target *ti;
        unsigned i;
@@ -903,8 +911,7 @@ bool dm_table_supports_dax(struct dm_table *t, int blocksize)
                        return false;
 
                if (!ti->type->iterate_devices ||
-                   !ti->type->iterate_devices(ti, device_supports_dax,
-                           &blocksize))
+                       !ti->type->iterate_devices(ti, iterate_fn, blocksize))
                        return false;
        }
 
@@ -940,6 +947,7 @@ static int dm_table_determine_type(struct dm_table *t)
        struct dm_target *tgt;
        struct list_head *devices = dm_table_get_devices(t);
        enum dm_queue_mode live_md_type = dm_get_md_type(t->md);
+       int page_size = PAGE_SIZE;
 
        if (t->type != DM_TYPE_NONE) {
                /* target already set the table's type */
@@ -984,7 +992,7 @@ static int dm_table_determine_type(struct dm_table *t)
 verify_bio_based:
                /* We must use this table as bio-based */
                t->type = DM_TYPE_BIO_BASED;
-               if (dm_table_supports_dax(t, PAGE_SIZE) ||
+               if (dm_table_supports_dax(t, device_supports_dax, &page_size) ||
                    (list_empty(devices) && live_md_type == DM_TYPE_DAX_BIO_BASED)) {
                        t->type = DM_TYPE_DAX_BIO_BASED;
                } else {
@@ -1883,6 +1891,7 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
                               struct queue_limits *limits)
 {
        bool wc = false, fua = false;
+       int page_size = PAGE_SIZE;
 
        /*
         * Copy table's limits to the DM device's request_queue
@@ -1910,8 +1919,11 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
        }
        blk_queue_write_cache(q, wc, fua);
 
-       if (dm_table_supports_dax(t, PAGE_SIZE))
+       if (dm_table_supports_dax(t, device_supports_dax, &page_size)) {
                blk_queue_flag_set(QUEUE_FLAG_DAX, q);
+               if (dm_table_supports_dax(t, device_synchronous, NULL))
+                       set_dax_synchronous(t->md->dax_dev);
+       }
        else
                blk_queue_flag_clear(QUEUE_FLAG_DAX, q);
 
index 9faf3e4..8545dce 100644 (file)
@@ -1602,30 +1602,6 @@ struct dm_zone *dmz_get_zone_for_reclaim(struct dmz_metadata *zmd)
 }
 
 /*
- * Activate a zone (increment its reference count).
- */
-void dmz_activate_zone(struct dm_zone *zone)
-{
-       set_bit(DMZ_ACTIVE, &zone->flags);
-       atomic_inc(&zone->refcount);
-}
-
-/*
- * Deactivate a zone. This decrement the zone reference counter
- * and clears the active state of the zone once the count reaches 0,
- * indicating that all BIOs to the zone have completed. Returns
- * true if the zone was deactivated.
- */
-void dmz_deactivate_zone(struct dm_zone *zone)
-{
-       if (atomic_dec_and_test(&zone->refcount)) {
-               WARN_ON(!test_bit(DMZ_ACTIVE, &zone->flags));
-               clear_bit_unlock(DMZ_ACTIVE, &zone->flags);
-               smp_mb__after_atomic();
-       }
-}
-
-/*
  * Get the zone mapping a chunk, if the chunk is mapped already.
  * If no mapping exist and the operation is WRITE, a zone is
  * allocated and used to map the chunk.
index 12419f0..ed8de49 100644 (file)
@@ -115,7 +115,6 @@ enum {
        DMZ_BUF,
 
        /* Zone internal state */
-       DMZ_ACTIVE,
        DMZ_RECLAIM,
        DMZ_SEQ_WRITE_ERR,
 };
@@ -128,7 +127,6 @@ enum {
 #define dmz_is_empty(z)                ((z)->wp_block == 0)
 #define dmz_is_offline(z)      test_bit(DMZ_OFFLINE, &(z)->flags)
 #define dmz_is_readonly(z)     test_bit(DMZ_READ_ONLY, &(z)->flags)
-#define dmz_is_active(z)       test_bit(DMZ_ACTIVE, &(z)->flags)
 #define dmz_in_reclaim(z)      test_bit(DMZ_RECLAIM, &(z)->flags)
 #define dmz_seq_write_err(z)   test_bit(DMZ_SEQ_WRITE_ERR, &(z)->flags)
 
@@ -188,8 +186,30 @@ void dmz_unmap_zone(struct dmz_metadata *zmd, struct dm_zone *zone);
 unsigned int dmz_nr_rnd_zones(struct dmz_metadata *zmd);
 unsigned int dmz_nr_unmap_rnd_zones(struct dmz_metadata *zmd);
 
-void dmz_activate_zone(struct dm_zone *zone);
-void dmz_deactivate_zone(struct dm_zone *zone);
+/*
+ * Activate a zone (increment its reference count).
+ */
+static inline void dmz_activate_zone(struct dm_zone *zone)
+{
+       atomic_inc(&zone->refcount);
+}
+
+/*
+ * Deactivate a zone. This decrement the zone reference counter
+ * indicating that all BIOs to the zone have completed when the count is 0.
+ */
+static inline void dmz_deactivate_zone(struct dm_zone *zone)
+{
+       atomic_dec(&zone->refcount);
+}
+
+/*
+ * Test if a zone is active, that is, has a refcount > 0.
+ */
+static inline bool dmz_is_active(struct dm_zone *zone)
+{
+       return atomic_read(&zone->refcount);
+}
 
 int dmz_lock_zone_reclaim(struct dm_zone *zone);
 void dmz_unlock_zone_reclaim(struct dm_zone *zone);
index 61f1152..d0beef0 100644 (file)
@@ -1117,7 +1117,7 @@ static bool dm_dax_supported(struct dax_device *dax_dev, struct block_device *bd
        if (!map)
                return false;
 
-       ret = dm_table_supports_dax(map, blocksize);
+       ret = dm_table_supports_dax(map, device_supports_dax, &blocksize);
 
        dm_put_live_table(md, srcu_idx);
 
@@ -1989,7 +1989,8 @@ static struct mapped_device *alloc_dev(int minor)
        sprintf(md->disk->disk_name, "dm-%d", minor);
 
        if (IS_ENABLED(CONFIG_DAX_DRIVER)) {
-               md->dax_dev = alloc_dax(md, md->disk->disk_name, &dm_dax_ops);
+               md->dax_dev = alloc_dax(md, md->disk->disk_name,
+                                       &dm_dax_ops, 0);
                if (!md->dax_dev)
                        goto bad;
        }
index 17e3db5..0475673 100644 (file)
@@ -72,7 +72,10 @@ bool dm_table_bio_based(struct dm_table *t);
 bool dm_table_request_based(struct dm_table *t);
 void dm_table_free_md_mempools(struct dm_table *t);
 struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t);
-bool dm_table_supports_dax(struct dm_table *t, int blocksize);
+bool dm_table_supports_dax(struct dm_table *t, iterate_devices_callout_fn fn,
+                          int *blocksize);
+int device_supports_dax(struct dm_target *ti, struct dm_dev *dev,
+                          sector_t start, sector_t len, void *data);
 
 void dm_lock_md_type(struct mapped_device *md);
 void dm_unlock_md_type(struct mapped_device *md);
index 21fb90d..25c73c1 100644 (file)
@@ -124,7 +124,7 @@ static inline int check_which(__u32 which)
 static inline int check_pad(struct v4l2_subdev *sd, __u32 pad)
 {
 #if defined(CONFIG_MEDIA_CONTROLLER)
-       if (sd->entity.graph_obj.mdev) {
+       if (sd->entity.num_pads) {
                if (pad >= sd->entity.num_pads)
                        return -EINVAL;
                return 0;
diff --git a/drivers/memory/.gitignore b/drivers/memory/.gitignore
new file mode 100644 (file)
index 0000000..cbca8b0
--- /dev/null
@@ -0,0 +1 @@
+ti-emif-asm-offsets.h
index dbdee02..9bddca2 100644 (file)
@@ -8,6 +8,14 @@ menuconfig MEMORY
 
 if MEMORY
 
+config DDR
+       bool
+       help
+         Data from JEDEC specs for DDR SDRAM memories,
+         particularly the AC timing parameters and addressing
+         information. This data is useful for drivers handling
+         DDR SDRAM controllers.
+
 config ARM_PL172_MPMC
        tristate "ARM PL172 MPMC driver"
        depends on ARM_AMBA && OF
index 91ae4eb..27b4934 100644 (file)
@@ -3,6 +3,7 @@
 # Makefile for memory devices
 #
 
+obj-$(CONFIG_DDR)              += jedec_ddr_data.o
 ifeq ($(CONFIG_DDR),y)
 obj-$(CONFIG_OF)               += of_memory.o
 endif
@@ -28,9 +29,10 @@ ti-emif-sram-objs            := ti-emif-pm.o ti-emif-sram-pm.o
 
 AFLAGS_ti-emif-sram-pm.o       :=-Wa,-march=armv7-a
 
-drivers/memory/ti-emif-sram-pm.o: include/generated/ti-emif-asm-offsets.h
+$(obj)/ti-emif-sram-pm.o: $(obj)/ti-emif-asm-offsets.h
 
-include/generated/ti-emif-asm-offsets.h: drivers/memory/emif-asm-offsets.s FORCE
+$(obj)/ti-emif-asm-offsets.h: $(obj)/emif-asm-offsets.s FORCE
        $(call filechk,offsets,__TI_EMIF_ASM_OFFSETS_H__)
 
 targets += emif-asm-offsets.s
+clean-files += ti-emif-asm-offsets.h
index 3065a8b..6827ed4 100644 (file)
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of_address.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 
 #define DRVNAME                        "brcmstb-dpfe"
-#define FIRMWARE_NAME          "dpfe.bin"
 
 /* DCPU register offsets */
 #define REG_DCPU_RESET         0x0
@@ -59,6 +59,7 @@
 #define DRAM_INFO_MR4          0x4
 #define DRAM_INFO_ERROR                0x8
 #define DRAM_INFO_MR4_MASK     0xff
+#define DRAM_INFO_MR4_SHIFT    24      /* We need to look at byte 3 */
 
 /* DRAM MR4 Offsets & Masks */
 #define DRAM_MR4_REFRESH       0x0     /* Refresh rate */
 #define DRAM_MR4_TH_OFFS_MASK  0x3
 #define DRAM_MR4_TUF_MASK      0x1
 
-/* DRAM Vendor Offsets & Masks */
+/* DRAM Vendor Offsets & Masks (API v2) */
 #define DRAM_VENDOR_MR5                0x0
 #define DRAM_VENDOR_MR6                0x4
 #define DRAM_VENDOR_MR7                0x8
 #define DRAM_VENDOR_MR8                0xc
 #define DRAM_VENDOR_ERROR      0x10
 #define DRAM_VENDOR_MASK       0xff
+#define DRAM_VENDOR_SHIFT      24      /* We need to look at byte 3 */
+
+/* DRAM Information Offsets & Masks (API v3) */
+#define DRAM_DDR_INFO_MR4      0x0
+#define DRAM_DDR_INFO_MR5      0x4
+#define DRAM_DDR_INFO_MR6      0x8
+#define DRAM_DDR_INFO_MR7      0xc
+#define DRAM_DDR_INFO_MR8      0x10
+#define DRAM_DDR_INFO_ERROR    0x14
+#define DRAM_DDR_INFO_MASK     0xff
 
 /* Reset register bits & masks */
 #define DCPU_RESET_SHIFT       0x0
 #define DPFE_MSG_TYPE_COMMAND  1
 #define DPFE_MSG_TYPE_RESPONSE 2
 
-#define DELAY_LOOP_MAX         200000
+#define DELAY_LOOP_MAX         1000
 
 enum dpfe_msg_fields {
        MSG_HEADER,
@@ -117,7 +128,7 @@ enum dpfe_msg_fields {
        MSG_ARG_COUNT,
        MSG_ARG0,
        MSG_CHKSUM,
-       MSG_FIELD_MAX /* Last entry */
+       MSG_FIELD_MAX   = 16 /* Max number of arguments */
 };
 
 enum dpfe_commands {
@@ -127,14 +138,6 @@ enum dpfe_commands {
        DPFE_CMD_MAX /* Last entry */
 };
 
-struct dpfe_msg {
-       u32 header;
-       u32 command;
-       u32 arg_count;
-       u32 arg0;
-       u32 chksum; /* This is the sum of all other entries. */
-};
-
 /*
  * Format of the binary firmware file:
  *
@@ -168,12 +171,21 @@ struct init_data {
        bool is_big_endian;
 };
 
+/* API version and corresponding commands */
+struct dpfe_api {
+       int version;
+       const char *fw_name;
+       const struct attribute_group **sysfs_attrs;
+       u32 command[DPFE_CMD_MAX][MSG_FIELD_MAX];
+};
+
 /* Things we need for as long as we are active. */
 struct private_data {
        void __iomem *regs;
        void __iomem *dmem;
        void __iomem *imem;
        struct device *dev;
+       const struct dpfe_api *dpfe_api;
        struct mutex lock;
 };
 
@@ -182,28 +194,99 @@ static const char *error_text[] = {
        "Incorrect checksum", "Malformed command", "Timed out",
 };
 
-/* List of supported firmware commands */
-static const u32 dpfe_commands[DPFE_CMD_MAX][MSG_FIELD_MAX] = {
-       [DPFE_CMD_GET_INFO] = {
-               [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
-               [MSG_COMMAND] = 1,
-               [MSG_ARG_COUNT] = 1,
-               [MSG_ARG0] = 1,
-               [MSG_CHKSUM] = 4,
-       },
-       [DPFE_CMD_GET_REFRESH] = {
-               [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
-               [MSG_COMMAND] = 2,
-               [MSG_ARG_COUNT] = 1,
-               [MSG_ARG0] = 1,
-               [MSG_CHKSUM] = 5,
-       },
-       [DPFE_CMD_GET_VENDOR] = {
-               [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
-               [MSG_COMMAND] = 2,
-               [MSG_ARG_COUNT] = 1,
-               [MSG_ARG0] = 2,
-               [MSG_CHKSUM] = 6,
+/*
+ * Forward declaration of our sysfs attribute functions, so we can declare the
+ * attribute data structures early.
+ */
+static ssize_t show_info(struct device *, struct device_attribute *, char *);
+static ssize_t show_refresh(struct device *, struct device_attribute *, char *);
+static ssize_t store_refresh(struct device *, struct device_attribute *,
+                         const char *, size_t);
+static ssize_t show_vendor(struct device *, struct device_attribute *, char *);
+static ssize_t show_dram(struct device *, struct device_attribute *, char *);
+
+/*
+ * Declare our attributes early, so they can be referenced in the API data
+ * structure. We need to do this, because the attributes depend on the API
+ * version.
+ */
+static DEVICE_ATTR(dpfe_info, 0444, show_info, NULL);
+static DEVICE_ATTR(dpfe_refresh, 0644, show_refresh, store_refresh);
+static DEVICE_ATTR(dpfe_vendor, 0444, show_vendor, NULL);
+static DEVICE_ATTR(dpfe_dram, 0444, show_dram, NULL);
+
+/* API v2 sysfs attributes */
+static struct attribute *dpfe_v2_attrs[] = {
+       &dev_attr_dpfe_info.attr,
+       &dev_attr_dpfe_refresh.attr,
+       &dev_attr_dpfe_vendor.attr,
+       NULL
+};
+ATTRIBUTE_GROUPS(dpfe_v2);
+
+/* API v3 sysfs attributes */
+static struct attribute *dpfe_v3_attrs[] = {
+       &dev_attr_dpfe_info.attr,
+       &dev_attr_dpfe_dram.attr,
+       NULL
+};
+ATTRIBUTE_GROUPS(dpfe_v3);
+
+/* API v2 firmware commands */
+static const struct dpfe_api dpfe_api_v2 = {
+       .version = 2,
+       .fw_name = "dpfe.bin",
+       .sysfs_attrs = dpfe_v2_groups,
+       .command = {
+               [DPFE_CMD_GET_INFO] = {
+                       [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
+                       [MSG_COMMAND] = 1,
+                       [MSG_ARG_COUNT] = 1,
+                       [MSG_ARG0] = 1,
+                       [MSG_CHKSUM] = 4,
+               },
+               [DPFE_CMD_GET_REFRESH] = {
+                       [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
+                       [MSG_COMMAND] = 2,
+                       [MSG_ARG_COUNT] = 1,
+                       [MSG_ARG0] = 1,
+                       [MSG_CHKSUM] = 5,
+               },
+               [DPFE_CMD_GET_VENDOR] = {
+                       [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
+                       [MSG_COMMAND] = 2,
+                       [MSG_ARG_COUNT] = 1,
+                       [MSG_ARG0] = 2,
+                       [MSG_CHKSUM] = 6,
+               },
+       }
+};
+
+/* API v3 firmware commands */
+static const struct dpfe_api dpfe_api_v3 = {
+       .version = 3,
+       .fw_name = NULL, /* We expect the firmware to have been downloaded! */
+       .sysfs_attrs = dpfe_v3_groups,
+       .command = {
+               [DPFE_CMD_GET_INFO] = {
+                       [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
+                       [MSG_COMMAND] = 0x0101,
+                       [MSG_ARG_COUNT] = 1,
+                       [MSG_ARG0] = 1,
+                       [MSG_CHKSUM] = 0x104,
+               },
+               [DPFE_CMD_GET_REFRESH] = {
+                       [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
+                       [MSG_COMMAND] = 0x0202,
+                       [MSG_ARG_COUNT] = 0,
+                       /*
+                        * This is a bit ugly. Without arguments, the checksum
+                        * follows right after the argument count and not at
+                        * offset MSG_CHKSUM.
+                        */
+                       [MSG_ARG0] = 0x203,
+               },
+               /* There's no GET_VENDOR command in API v3. */
        },
 };
 
@@ -248,13 +331,13 @@ static void __enable_dcpu(void __iomem *regs)
        writel_relaxed(val, regs + REG_DCPU_RESET);
 }
 
-static unsigned int get_msg_chksum(const u32 msg[])
+static unsigned int get_msg_chksum(const u32 msg[], unsigned int max)
 {
        unsigned int sum = 0;
        unsigned int i;
 
        /* Don't include the last field in the checksum. */
-       for (i = 0; i < MSG_FIELD_MAX - 1; i++)
+       for (i = 0; i < max; i++)
                sum += msg[i];
 
        return sum;
@@ -267,6 +350,11 @@ static void __iomem *get_msg_ptr(struct private_data *priv, u32 response,
        unsigned int offset;
        void __iomem *ptr = NULL;
 
+       /* There is no need to use this function for API v3 or later. */
+       if (unlikely(priv->dpfe_api->version >= 3)) {
+               return NULL;
+       }
+
        msg_type = (response >> DRAM_MSG_TYPE_OFFSET) & DRAM_MSG_TYPE_MASK;
        offset = (response >> DRAM_MSG_ADDR_OFFSET) & DRAM_MSG_ADDR_MASK;
 
@@ -294,12 +382,25 @@ static void __iomem *get_msg_ptr(struct private_data *priv, u32 response,
        return ptr;
 }
 
+static void __finalize_command(struct private_data *priv)
+{
+       unsigned int release_mbox;
+
+       /*
+        * It depends on the API version which MBOX register we have to write to
+        * to signal we are done.
+        */
+       release_mbox = (priv->dpfe_api->version < 3)
+                       ? REG_TO_HOST_MBOX : REG_TO_DCPU_MBOX;
+       writel_relaxed(0, priv->regs + release_mbox);
+}
+
 static int __send_command(struct private_data *priv, unsigned int cmd,
                          u32 result[])
 {
-       const u32 *msg = dpfe_commands[cmd];
+       const u32 *msg = priv->dpfe_api->command[cmd];
        void __iomem *regs = priv->regs;
-       unsigned int i, chksum;
+       unsigned int i, chksum, chksum_idx;
        int ret = 0;
        u32 resp;
 
@@ -308,6 +409,18 @@ static int __send_command(struct private_data *priv, unsigned int cmd,
 
        mutex_lock(&priv->lock);
 
+       /* Wait for DCPU to become ready */
+       for (i = 0; i < DELAY_LOOP_MAX; i++) {
+               resp = readl_relaxed(regs + REG_TO_HOST_MBOX);
+               if (resp == 0)
+                       break;
+               msleep(1);
+       }
+       if (resp != 0) {
+               mutex_unlock(&priv->lock);
+               return -ETIMEDOUT;
+       }
+
        /* Write command and arguments to message area */
        for (i = 0; i < MSG_FIELD_MAX; i++)
                writel_relaxed(msg[i], regs + DCPU_MSG_RAM(i));
@@ -321,7 +434,7 @@ static int __send_command(struct private_data *priv, unsigned int cmd,
                resp = readl_relaxed(regs + REG_TO_HOST_MBOX);
                if (resp > 0)
                        break;
-               udelay(5);
+               msleep(1);
        }
 
        if (i == DELAY_LOOP_MAX) {
@@ -331,10 +444,11 @@ static int __send_command(struct private_data *priv, unsigned int cmd,
                /* Read response data */
                for (i = 0; i < MSG_FIELD_MAX; i++)
                        result[i] = readl_relaxed(regs + DCPU_MSG_RAM(i));
+               chksum_idx = result[MSG_ARG_COUNT] + MSG_ARG_COUNT + 1;
        }
 
        /* Tell DCPU we are done */
-       writel_relaxed(0, regs + REG_TO_HOST_MBOX);
+       __finalize_command(priv);
 
        mutex_unlock(&priv->lock);
 
@@ -342,8 +456,8 @@ static int __send_command(struct private_data *priv, unsigned int cmd,
                return ret;
 
        /* Verify response */
-       chksum = get_msg_chksum(result);
-       if (chksum != result[MSG_CHKSUM])
+       chksum = get_msg_chksum(result, chksum_idx);
+       if (chksum != result[chksum_idx])
                resp = DCPU_RET_ERR_CHKSUM;
 
        if (resp != DCPU_RET_SUCCESS) {
@@ -484,7 +598,15 @@ static int brcmstb_dpfe_download_firmware(struct platform_device *pdev,
                        return 0;
        }
 
-       ret = request_firmware(&fw, FIRMWARE_NAME, dev);
+       /*
+        * If the firmware filename is NULL it means the boot firmware has to
+        * download the DCPU firmware for us. If that didn't work, we have to
+        * bail, since downloading it ourselves wouldn't work either.
+        */
+       if (!priv->dpfe_api->fw_name)
+               return -ENODEV;
+
+       ret = request_firmware(&fw, priv->dpfe_api->fw_name, dev);
        /* request_firmware() prints its own error messages. */
        if (ret)
                return ret;
@@ -525,12 +647,10 @@ static int brcmstb_dpfe_download_firmware(struct platform_device *pdev,
 }
 
 static ssize_t generic_show(unsigned int command, u32 response[],
-                           struct device *dev, char *buf)
+                           struct private_data *priv, char *buf)
 {
-       struct private_data *priv;
        int ret;
 
-       priv = dev_get_drvdata(dev);
        if (!priv)
                return sprintf(buf, "ERROR: driver private data not set\n");
 
@@ -545,10 +665,12 @@ static ssize_t show_info(struct device *dev, struct device_attribute *devattr,
                         char *buf)
 {
        u32 response[MSG_FIELD_MAX];
+       struct private_data *priv;
        unsigned int info;
        ssize_t ret;
 
-       ret = generic_show(DPFE_CMD_GET_INFO, response, dev, buf);
+       priv = dev_get_drvdata(dev);
+       ret = generic_show(DPFE_CMD_GET_INFO, response, priv, buf);
        if (ret)
                return ret;
 
@@ -571,17 +693,17 @@ static ssize_t show_refresh(struct device *dev,
        u32 mr4;
        ssize_t ret;
 
-       ret = generic_show(DPFE_CMD_GET_REFRESH, response, dev, buf);
+       priv = dev_get_drvdata(dev);
+       ret = generic_show(DPFE_CMD_GET_REFRESH, response, priv, buf);
        if (ret)
                return ret;
 
-       priv = dev_get_drvdata(dev);
-
        info = get_msg_ptr(priv, response[MSG_ARG0], buf, &ret);
        if (!info)
                return ret;
 
-       mr4 = readl_relaxed(info + DRAM_INFO_MR4) & DRAM_INFO_MR4_MASK;
+       mr4 = (readl_relaxed(info + DRAM_INFO_MR4) >> DRAM_INFO_MR4_SHIFT) &
+              DRAM_INFO_MR4_MASK;
 
        refresh = (mr4 >> DRAM_MR4_REFRESH) & DRAM_MR4_REFRESH_MASK;
        sr_abort = (mr4 >> DRAM_MR4_SR_ABORT) & DRAM_MR4_SR_ABORT_MASK;
@@ -608,7 +730,6 @@ static ssize_t store_refresh(struct device *dev, struct device_attribute *attr,
                return -EINVAL;
 
        priv = dev_get_drvdata(dev);
-
        ret = __send_command(priv, DPFE_CMD_GET_REFRESH, response);
        if (ret)
                return ret;
@@ -623,30 +744,58 @@ static ssize_t store_refresh(struct device *dev, struct device_attribute *attr,
 }
 
 static ssize_t show_vendor(struct device *dev, struct device_attribute *devattr,
-                        char *buf)
+                          char *buf)
 {
        u32 response[MSG_FIELD_MAX];
        struct private_data *priv;
        void __iomem *info;
        ssize_t ret;
+       u32 mr5, mr6, mr7, mr8, err;
 
-       ret = generic_show(DPFE_CMD_GET_VENDOR, response, dev, buf);
+       priv = dev_get_drvdata(dev);
+       ret = generic_show(DPFE_CMD_GET_VENDOR, response, priv, buf);
        if (ret)
                return ret;
 
-       priv = dev_get_drvdata(dev);
-
        info = get_msg_ptr(priv, response[MSG_ARG0], buf, &ret);
        if (!info)
                return ret;
 
-       return sprintf(buf, "%#x %#x %#x %#x %#x\n",
-                      readl_relaxed(info + DRAM_VENDOR_MR5) & DRAM_VENDOR_MASK,
-                      readl_relaxed(info + DRAM_VENDOR_MR6) & DRAM_VENDOR_MASK,
-                      readl_relaxed(info + DRAM_VENDOR_MR7) & DRAM_VENDOR_MASK,
-                      readl_relaxed(info + DRAM_VENDOR_MR8) & DRAM_VENDOR_MASK,
-                      readl_relaxed(info + DRAM_VENDOR_ERROR) &
-                                    DRAM_VENDOR_MASK);
+       mr5 = (readl_relaxed(info + DRAM_VENDOR_MR5) >> DRAM_VENDOR_SHIFT) &
+               DRAM_VENDOR_MASK;
+       mr6 = (readl_relaxed(info + DRAM_VENDOR_MR6) >> DRAM_VENDOR_SHIFT) &
+               DRAM_VENDOR_MASK;
+       mr7 = (readl_relaxed(info + DRAM_VENDOR_MR7) >> DRAM_VENDOR_SHIFT) &
+               DRAM_VENDOR_MASK;
+       mr8 = (readl_relaxed(info + DRAM_VENDOR_MR8) >> DRAM_VENDOR_SHIFT) &
+               DRAM_VENDOR_MASK;
+       err = readl_relaxed(info + DRAM_VENDOR_ERROR) & DRAM_VENDOR_MASK;
+
+       return sprintf(buf, "%#x %#x %#x %#x %#x\n", mr5, mr6, mr7, mr8, err);
+}
+
+static ssize_t show_dram(struct device *dev, struct device_attribute *devattr,
+                        char *buf)
+{
+       u32 response[MSG_FIELD_MAX];
+       struct private_data *priv;
+       ssize_t ret;
+       u32 mr4, mr5, mr6, mr7, mr8, err;
+
+       priv = dev_get_drvdata(dev);
+       ret = generic_show(DPFE_CMD_GET_REFRESH, response, priv, buf);
+       if (ret)
+               return ret;
+
+       mr4 = response[MSG_ARG0 + 0] & DRAM_INFO_MR4_MASK;
+       mr5 = response[MSG_ARG0 + 1] & DRAM_DDR_INFO_MASK;
+       mr6 = response[MSG_ARG0 + 2] & DRAM_DDR_INFO_MASK;
+       mr7 = response[MSG_ARG0 + 3] & DRAM_DDR_INFO_MASK;
+       mr8 = response[MSG_ARG0 + 4] & DRAM_DDR_INFO_MASK;
+       err = response[MSG_ARG0 + 5] & DRAM_DDR_INFO_MASK;
+
+       return sprintf(buf, "%#x %#x %#x %#x %#x %#x\n", mr4, mr5, mr6, mr7,
+                       mr8, err);
 }
 
 static int brcmstb_dpfe_resume(struct platform_device *pdev)
@@ -656,17 +805,6 @@ static int brcmstb_dpfe_resume(struct platform_device *pdev)
        return brcmstb_dpfe_download_firmware(pdev, &init);
 }
 
-static DEVICE_ATTR(dpfe_info, 0444, show_info, NULL);
-static DEVICE_ATTR(dpfe_refresh, 0644, show_refresh, store_refresh);
-static DEVICE_ATTR(dpfe_vendor, 0444, show_vendor, NULL);
-static struct attribute *dpfe_attrs[] = {
-       &dev_attr_dpfe_info.attr,
-       &dev_attr_dpfe_refresh.attr,
-       &dev_attr_dpfe_vendor.attr,
-       NULL
-};
-ATTRIBUTE_GROUPS(dpfe);
-
 static int brcmstb_dpfe_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -703,26 +841,47 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev)
                return -ENOENT;
        }
 
+       priv->dpfe_api = of_device_get_match_data(dev);
+       if (unlikely(!priv->dpfe_api)) {
+               /*
+                * It should be impossible to end up here, but to be safe we
+                * check anyway.
+                */
+               dev_err(dev, "Couldn't determine API\n");
+               return -ENOENT;
+       }
+
        ret = brcmstb_dpfe_download_firmware(pdev, &init);
-       if (ret)
+       if (ret) {
+               dev_err(dev, "Couldn't download firmware -- %d\n", ret);
                return ret;
+       }
 
-       ret = sysfs_create_groups(&pdev->dev.kobj, dpfe_groups);
+       ret = sysfs_create_groups(&pdev->dev.kobj, priv->dpfe_api->sysfs_attrs);
        if (!ret)
-               dev_info(dev, "registered.\n");
+               dev_info(dev, "registered with API v%d.\n",
+                        priv->dpfe_api->version);
 
        return ret;
 }
 
 static int brcmstb_dpfe_remove(struct platform_device *pdev)
 {
-       sysfs_remove_groups(&pdev->dev.kobj, dpfe_groups);
+       struct private_data *priv = dev_get_drvdata(&pdev->dev);
+
+       sysfs_remove_groups(&pdev->dev.kobj, priv->dpfe_api->sysfs_attrs);
 
        return 0;
 }
 
 static const struct of_device_id brcmstb_dpfe_of_match[] = {
-       { .compatible = "brcm,dpfe-cpu", },
+       /* Use legacy API v2 for a select number of chips */
+       { .compatible = "brcm,bcm7268-dpfe-cpu", .data = &dpfe_api_v2 },
+       { .compatible = "brcm,bcm7271-dpfe-cpu", .data = &dpfe_api_v2 },
+       { .compatible = "brcm,bcm7278-dpfe-cpu", .data = &dpfe_api_v2 },
+       { .compatible = "brcm,bcm7211-dpfe-cpu", .data = &dpfe_api_v2 },
+       /* API v3 is the default going forward */
+       { .compatible = "brcm,dpfe-cpu", .data = &dpfe_api_v3 },
        {}
 };
 MODULE_DEVICE_TABLE(of, brcmstb_dpfe_of_match);
index ee67a9a..402c6bc 100644 (file)
@@ -23,8 +23,9 @@
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/pm.h>
-#include <memory/jedec_ddr.h>
+
 #include "emif.h"
+#include "jedec_ddr.h"
 #include "of_memory.h"
 
 /**
diff --git a/drivers/memory/jedec_ddr.h b/drivers/memory/jedec_ddr.h
new file mode 100644 (file)
index 0000000..4a21b50
--- /dev/null
@@ -0,0 +1,172 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Definitions for DDR memories based on JEDEC specs
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Aneesh V <aneesh@ti.com>
+ */
+#ifndef __JEDEC_DDR_H
+#define __JEDEC_DDR_H
+
+#include <linux/types.h>
+
+/* DDR Densities */
+#define DDR_DENSITY_64Mb       1
+#define DDR_DENSITY_128Mb      2
+#define DDR_DENSITY_256Mb      3
+#define DDR_DENSITY_512Mb      4
+#define DDR_DENSITY_1Gb                5
+#define DDR_DENSITY_2Gb                6
+#define DDR_DENSITY_4Gb                7
+#define DDR_DENSITY_8Gb                8
+#define DDR_DENSITY_16Gb       9
+#define DDR_DENSITY_32Gb       10
+
+/* DDR type */
+#define DDR_TYPE_DDR2          1
+#define DDR_TYPE_DDR3          2
+#define DDR_TYPE_LPDDR2_S4     3
+#define DDR_TYPE_LPDDR2_S2     4
+#define DDR_TYPE_LPDDR2_NVM    5
+
+/* DDR IO width */
+#define DDR_IO_WIDTH_4         1
+#define DDR_IO_WIDTH_8         2
+#define DDR_IO_WIDTH_16                3
+#define DDR_IO_WIDTH_32                4
+
+/* Number of Row bits */
+#define R9                     9
+#define R10                    10
+#define R11                    11
+#define R12                    12
+#define R13                    13
+#define R14                    14
+#define R15                    15
+#define R16                    16
+
+/* Number of Column bits */
+#define C7                     7
+#define C8                     8
+#define C9                     9
+#define C10                    10
+#define C11                    11
+#define C12                    12
+
+/* Number of Banks */
+#define B1                     0
+#define B2                     1
+#define B4                     2
+#define B8                     3
+
+/* Refresh rate in nano-seconds */
+#define T_REFI_15_6            15600
+#define T_REFI_7_8             7800
+#define T_REFI_3_9             3900
+
+/* tRFC values */
+#define T_RFC_90               90000
+#define T_RFC_110              110000
+#define T_RFC_130              130000
+#define T_RFC_160              160000
+#define T_RFC_210              210000
+#define T_RFC_300              300000
+#define T_RFC_350              350000
+
+/* Mode register numbers */
+#define DDR_MR0                        0
+#define DDR_MR1                        1
+#define DDR_MR2                        2
+#define DDR_MR3                        3
+#define DDR_MR4                        4
+#define DDR_MR5                        5
+#define DDR_MR6                        6
+#define DDR_MR7                        7
+#define DDR_MR8                        8
+#define DDR_MR9                        9
+#define DDR_MR10               10
+#define DDR_MR11               11
+#define DDR_MR16               16
+#define DDR_MR17               17
+#define DDR_MR18               18
+
+/*
+ * LPDDR2 related defines
+ */
+
+/* MR4 register fields */
+#define MR4_SDRAM_REF_RATE_SHIFT                       0
+#define MR4_SDRAM_REF_RATE_MASK                                7
+#define MR4_TUF_SHIFT                                  7
+#define MR4_TUF_MASK                                   (1 << 7)
+
+/* MR4 SDRAM Refresh Rate field values */
+#define SDRAM_TEMP_NOMINAL                             0x3
+#define SDRAM_TEMP_RESERVED_4                          0x4
+#define SDRAM_TEMP_HIGH_DERATE_REFRESH                 0x5
+#define SDRAM_TEMP_HIGH_DERATE_REFRESH_AND_TIMINGS     0x6
+#define SDRAM_TEMP_VERY_HIGH_SHUTDOWN                  0x7
+
+#define NUM_DDR_ADDR_TABLE_ENTRIES                     11
+#define NUM_DDR_TIMING_TABLE_ENTRIES                   4
+
+/* Structure for DDR addressing info from the JEDEC spec */
+struct lpddr2_addressing {
+       u32 num_banks;
+       u32 tREFI_ns;
+       u32 tRFCab_ps;
+};
+
+/*
+ * Structure for timings from the LPDDR2 datasheet
+ * All parameters are in pico seconds(ps) unless explicitly indicated
+ * with a suffix like tRAS_max_ns below
+ */
+struct lpddr2_timings {
+       u32 max_freq;
+       u32 min_freq;
+       u32 tRPab;
+       u32 tRCD;
+       u32 tWR;
+       u32 tRAS_min;
+       u32 tRRD;
+       u32 tWTR;
+       u32 tXP;
+       u32 tRTP;
+       u32 tCKESR;
+       u32 tDQSCK_max;
+       u32 tDQSCK_max_derated;
+       u32 tFAW;
+       u32 tZQCS;
+       u32 tZQCL;
+       u32 tZQinit;
+       u32 tRAS_max_ns;
+};
+
+/*
+ * Min value for some parameters in terms of number of tCK cycles(nCK)
+ * Please set to zero parameters that are not valid for a given memory
+ * type
+ */
+struct lpddr2_min_tck {
+       u32 tRPab;
+       u32 tRCD;
+       u32 tWR;
+       u32 tRASmin;
+       u32 tRRD;
+       u32 tWTR;
+       u32 tXP;
+       u32 tRTP;
+       u32 tCKE;
+       u32 tCKESR;
+       u32 tFAW;
+};
+
+extern const struct lpddr2_addressing
+       lpddr2_jedec_addressing_table[NUM_DDR_ADDR_TABLE_ENTRIES];
+extern const struct lpddr2_timings
+       lpddr2_jedec_timings[NUM_DDR_TIMING_TABLE_ENTRIES];
+extern const struct lpddr2_min_tck lpddr2_jedec_min_tck;
+
+#endif /* __JEDEC_DDR_H */
diff --git a/drivers/memory/jedec_ddr_data.c b/drivers/memory/jedec_ddr_data.c
new file mode 100644 (file)
index 0000000..ed601d8
--- /dev/null
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * DDR addressing details and AC timing parameters from JEDEC specs
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Aneesh V <aneesh@ti.com>
+ */
+
+#include <linux/export.h>
+
+#include "jedec_ddr.h"
+
+/* LPDDR2 addressing details from JESD209-2 section 2.4 */
+const struct lpddr2_addressing
+       lpddr2_jedec_addressing_table[NUM_DDR_ADDR_TABLE_ENTRIES] = {
+       {B4, T_REFI_15_6, T_RFC_90}, /* 64M */
+       {B4, T_REFI_15_6, T_RFC_90}, /* 128M */
+       {B4, T_REFI_7_8,  T_RFC_90}, /* 256M */
+       {B4, T_REFI_7_8,  T_RFC_90}, /* 512M */
+       {B8, T_REFI_7_8, T_RFC_130}, /* 1GS4 */
+       {B8, T_REFI_3_9, T_RFC_130}, /* 2GS4 */
+       {B8, T_REFI_3_9, T_RFC_130}, /* 4G */
+       {B8, T_REFI_3_9, T_RFC_210}, /* 8G */
+       {B4, T_REFI_7_8, T_RFC_130}, /* 1GS2 */
+       {B4, T_REFI_3_9, T_RFC_130}, /* 2GS2 */
+};
+EXPORT_SYMBOL_GPL(lpddr2_jedec_addressing_table);
+
+/* LPDDR2 AC timing parameters from JESD209-2 section 12 */
+const struct lpddr2_timings
+       lpddr2_jedec_timings[NUM_DDR_TIMING_TABLE_ENTRIES] = {
+       /* Speed bin 400(200 MHz) */
+       [0] = {
+               .max_freq       = 200000000,
+               .min_freq       = 10000000,
+               .tRPab          = 21000,
+               .tRCD           = 18000,
+               .tWR            = 15000,
+               .tRAS_min       = 42000,
+               .tRRD           = 10000,
+               .tWTR           = 10000,
+               .tXP            = 7500,
+               .tRTP           = 7500,
+               .tCKESR         = 15000,
+               .tDQSCK_max     = 5500,
+               .tFAW           = 50000,
+               .tZQCS          = 90000,
+               .tZQCL          = 360000,
+               .tZQinit        = 1000000,
+               .tRAS_max_ns    = 70000,
+               .tDQSCK_max_derated = 6000,
+       },
+       /* Speed bin 533(266 MHz) */
+       [1] = {
+               .max_freq       = 266666666,
+               .min_freq       = 10000000,
+               .tRPab          = 21000,
+               .tRCD           = 18000,
+               .tWR            = 15000,
+               .tRAS_min       = 42000,
+               .tRRD           = 10000,
+               .tWTR           = 7500,
+               .tXP            = 7500,
+               .tRTP           = 7500,
+               .tCKESR         = 15000,
+               .tDQSCK_max     = 5500,
+               .tFAW           = 50000,
+               .tZQCS          = 90000,
+               .tZQCL          = 360000,
+               .tZQinit        = 1000000,
+               .tRAS_max_ns    = 70000,
+               .tDQSCK_max_derated = 6000,
+       },
+       /* Speed bin 800(400 MHz) */
+       [2] = {
+               .max_freq       = 400000000,
+               .min_freq       = 10000000,
+               .tRPab          = 21000,
+               .tRCD           = 18000,
+               .tWR            = 15000,
+               .tRAS_min       = 42000,
+               .tRRD           = 10000,
+               .tWTR           = 7500,
+               .tXP            = 7500,
+               .tRTP           = 7500,
+               .tCKESR         = 15000,
+               .tDQSCK_max     = 5500,
+               .tFAW           = 50000,
+               .tZQCS          = 90000,
+               .tZQCL          = 360000,
+               .tZQinit        = 1000000,
+               .tRAS_max_ns    = 70000,
+               .tDQSCK_max_derated = 6000,
+       },
+       /* Speed bin 1066(533 MHz) */
+       [3] = {
+               .max_freq       = 533333333,
+               .min_freq       = 10000000,
+               .tRPab          = 21000,
+               .tRCD           = 18000,
+               .tWR            = 15000,
+               .tRAS_min       = 42000,
+               .tRRD           = 10000,
+               .tWTR           = 7500,
+               .tXP            = 7500,
+               .tRTP           = 7500,
+               .tCKESR         = 15000,
+               .tDQSCK_max     = 5500,
+               .tFAW           = 50000,
+               .tZQCS          = 90000,
+               .tZQCL          = 360000,
+               .tZQinit        = 1000000,
+               .tRAS_max_ns    = 70000,
+               .tDQSCK_max_derated = 5620,
+       },
+};
+EXPORT_SYMBOL_GPL(lpddr2_jedec_timings);
+
+const struct lpddr2_min_tck lpddr2_jedec_min_tck = {
+       .tRPab          = 3,
+       .tRCD           = 3,
+       .tWR            = 3,
+       .tRASmin        = 3,
+       .tRRD           = 2,
+       .tWTR           = 2,
+       .tXP            = 2,
+       .tRTP           = 2,
+       .tCKE           = 3,
+       .tCKESR         = 3,
+       .tFAW           = 8
+};
+EXPORT_SYMBOL_GPL(lpddr2_jedec_min_tck);
index 2a3f7ef..b232ed2 100644 (file)
@@ -61,7 +61,7 @@ struct jz4780_nemc {
  *
  * Return: The number of unique NEMC banks referred to by the specified NEMC
  * child device. Unique here means that a device that references the same bank
- * multiple times in the its "reg" property will only count once.
+ * multiple times in its "reg" property will only count once.
  */
 unsigned int jz4780_nemc_num_banks(struct device *dev)
 {
index 12a61f5..46539b2 100644 (file)
@@ -10,8 +10,9 @@
 #include <linux/list.h>
 #include <linux/of.h>
 #include <linux/gfp.h>
-#include <memory/jedec_ddr.h>
 #include <linux/export.h>
+
+#include "jedec_ddr.h"
 #include "of_memory.h"
 
 /**
index 41f08b2..5d0ccb2 100644 (file)
 #define MC_EMEM_ARB_MISC1                      0xdc
 #define MC_EMEM_ARB_RING1_THROTTLE             0xe0
 
-static const unsigned long tegra124_mc_emem_regs[] = {
-       MC_EMEM_ARB_CFG,
-       MC_EMEM_ARB_OUTSTANDING_REQ,
-       MC_EMEM_ARB_TIMING_RCD,
-       MC_EMEM_ARB_TIMING_RP,
-       MC_EMEM_ARB_TIMING_RC,
-       MC_EMEM_ARB_TIMING_RAS,
-       MC_EMEM_ARB_TIMING_FAW,
-       MC_EMEM_ARB_TIMING_RRD,
-       MC_EMEM_ARB_TIMING_RAP2PRE,
-       MC_EMEM_ARB_TIMING_WAP2PRE,
-       MC_EMEM_ARB_TIMING_R2R,
-       MC_EMEM_ARB_TIMING_W2W,
-       MC_EMEM_ARB_TIMING_R2W,
-       MC_EMEM_ARB_TIMING_W2R,
-       MC_EMEM_ARB_DA_TURNS,
-       MC_EMEM_ARB_DA_COVERS,
-       MC_EMEM_ARB_MISC0,
-       MC_EMEM_ARB_MISC1,
-       MC_EMEM_ARB_RING1_THROTTLE
-};
-
 static const struct tegra_mc_client tegra124_mc_clients[] = {
        {
                .id = 0x00,
@@ -1046,6 +1024,28 @@ static const struct tegra_mc_reset tegra124_mc_resets[] = {
 };
 
 #ifdef CONFIG_ARCH_TEGRA_124_SOC
+static const unsigned long tegra124_mc_emem_regs[] = {
+       MC_EMEM_ARB_CFG,
+       MC_EMEM_ARB_OUTSTANDING_REQ,
+       MC_EMEM_ARB_TIMING_RCD,
+       MC_EMEM_ARB_TIMING_RP,
+       MC_EMEM_ARB_TIMING_RC,
+       MC_EMEM_ARB_TIMING_RAS,
+       MC_EMEM_ARB_TIMING_FAW,
+       MC_EMEM_ARB_TIMING_RRD,
+       MC_EMEM_ARB_TIMING_RAP2PRE,
+       MC_EMEM_ARB_TIMING_WAP2PRE,
+       MC_EMEM_ARB_TIMING_R2R,
+       MC_EMEM_ARB_TIMING_W2W,
+       MC_EMEM_ARB_TIMING_R2W,
+       MC_EMEM_ARB_TIMING_W2R,
+       MC_EMEM_ARB_DA_TURNS,
+       MC_EMEM_ARB_DA_COVERS,
+       MC_EMEM_ARB_MISC0,
+       MC_EMEM_ARB_MISC1,
+       MC_EMEM_ARB_RING1_THROTTLE
+};
+
 static const struct tegra_smmu_soc tegra124_smmu_soc = {
        .clients = tegra124_mc_clients,
        .num_clients = ARRAY_SIZE(tegra124_mc_clients),
index d75ae18..d1c83bd 100644 (file)
  * GNU General Public License for more details.
  */
 
-#include <generated/ti-emif-asm-offsets.h>
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/memory.h>
 
 #include "emif.h"
+#include "ti-emif-asm-offsets.h"
 
 #define EMIF_POWER_MGMT_WAIT_SELF_REFRESH_8192_CYCLES  0x00a0
 #define EMIF_POWER_MGMT_SR_TIMER_MASK                  0x00f0
index a450694..b493de9 100644 (file)
@@ -9,6 +9,7 @@
 #include <misc/cxl.h>
 #include <linux/module.h>
 #include <linux/mount.h>
+#include <linux/pseudo_fs.h>
 #include <linux/sched/mm.h>
 #include <linux/mmu_context.h>
 
 static int cxl_fs_cnt;
 static struct vfsmount *cxl_vfs_mount;
 
-static const struct dentry_operations cxl_fs_dops = {
-       .d_dname        = simple_dname,
-};
-
-static struct dentry *cxl_fs_mount(struct file_system_type *fs_type, int flags,
-                               const char *dev_name, void *data)
+static int cxl_fs_init_fs_context(struct fs_context *fc)
 {
-       return mount_pseudo(fs_type, "cxl:", NULL, &cxl_fs_dops,
-                       CXL_PSEUDO_FS_MAGIC);
+       return init_pseudo(fc, CXL_PSEUDO_FS_MAGIC) ? 0 : -ENOMEM;
 }
 
 static struct file_system_type cxl_fs_type = {
        .name           = "cxl",
        .owner          = THIS_MODULE,
-       .mount          = cxl_fs_mount,
+       .init_fs_context = cxl_fs_init_fs_context,
        .kill_sb        = kill_anon_super,
 };
 
index 4989dcb..35fec1b 100644 (file)
@@ -60,6 +60,7 @@
  */
 
 #include <linux/fs.h>
+#include <linux/fs_context.h>
 #include <linux/pagemap.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
@@ -74,13 +75,21 @@ static LIST_HEAD(service_processors);
 
 static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode);
 static void ibmasmfs_create_files (struct super_block *sb);
-static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent);
+static int ibmasmfs_fill_super(struct super_block *sb, struct fs_context *fc);
 
+static int ibmasmfs_get_tree(struct fs_context *fc)
+{
+       return get_tree_single(fc, ibmasmfs_fill_super);
+}
 
-static struct dentry *ibmasmfs_mount(struct file_system_type *fst,
-                       int flags, const char *name, void *data)
+static const struct fs_context_operations ibmasmfs_context_ops = {
+       .get_tree       = ibmasmfs_get_tree,
+};
+
+static int ibmasmfs_init_fs_context(struct fs_context *fc)
 {
-       return mount_single(fst, flags, data, ibmasmfs_fill_super);
+       fc->ops = &ibmasmfs_context_ops;
+       return 0;
 }
 
 static const struct super_operations ibmasmfs_s_ops = {
@@ -93,12 +102,12 @@ static const struct file_operations *ibmasmfs_dir_ops = &simple_dir_operations;
 static struct file_system_type ibmasmfs_type = {
        .owner          = THIS_MODULE,
        .name           = "ibmasmfs",
-       .mount          = ibmasmfs_mount,
+       .init_fs_context = ibmasmfs_init_fs_context,
        .kill_sb        = kill_litter_super,
 };
 MODULE_ALIAS_FS("ibmasmfs");
 
-static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent)
+static int ibmasmfs_fill_super(struct super_block *sb, struct fs_context *fc)
 {
        struct inode *root;
 
index 6765f10..6e208a0 100644 (file)
@@ -793,7 +793,7 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x) },
        { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x) },
        { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0) },
-       { PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, 0xedda) },
+       { PCI_DEVICE_DATA(SYNOPSYS, EDDA, NULL) },
        { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654),
          .driver_data = (kernel_ulong_t)&am654_data
        },
index 97b58e7..8840299 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/mount.h>
+#include <linux/pseudo_fs.h>
 #include <linux/balloon_compaction.h>
 #include <linux/vmw_vmci_defs.h>
 #include <linux/vmw_vmci_api.h>
@@ -1728,22 +1729,15 @@ static inline void vmballoon_debugfs_exit(struct vmballoon *b)
 
 #ifdef CONFIG_BALLOON_COMPACTION
 
-static struct dentry *vmballoon_mount(struct file_system_type *fs_type,
-                                     int flags, const char *dev_name,
-                                     void *data)
+static int vmballoon_init_fs_context(struct fs_context *fc)
 {
-       static const struct dentry_operations ops = {
-               .d_dname = simple_dname,
-       };
-
-       return mount_pseudo(fs_type, "balloon-vmware:", NULL, &ops,
-                           BALLOON_VMW_MAGIC);
+       return init_pseudo(fc, BALLOON_VMW_MAGIC) ? 0 : -ENOMEM;
 }
 
 static struct file_system_type vmballoon_fs = {
-       .name           = "balloon-vmware",
-       .mount          = vmballoon_mount,
-       .kill_sb        = kill_anon_super,
+       .name                   = "balloon-vmware",
+       .init_fs_context        = vmballoon_init_fs_context,
+       .kill_sb                = kill_anon_super,
 };
 
 static struct vfsmount *vmballoon_mnt;
index 223fbd8..09fdced 100644 (file)
@@ -11,7 +11,7 @@
  *   Thomas Gleixner (tglx@linutronix.de)
  *
  * Information on how this algorithm works and how it was developed
- * can be found in Documentation/mtd/nand_ecc.txt
+ * can be found in Documentation/driver-api/mtd/nand_ecc.rst
  */
 
 #include <linux/types.h>
index b2f10b6..bbb2575 100644 (file)
@@ -1455,7 +1455,7 @@ static void __exit cfhsi_exit_module(void)
        rtnl_lock();
        list_for_each_safe(list_node, n, &cfhsi_list) {
                cfhsi = list_entry(list_node, struct cfhsi, list);
-               unregister_netdev(cfhsi->ndev);
+               unregister_netdevice(cfhsi->ndev);
        }
        rtnl_unlock();
 }
index 72a57c6..8b69d0d 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/regmap.h>
 #include <linux/reset.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
 /* For our NAPI weight bigger does *NOT* mean better - it means more
  * D-cache misses and lots more wasted cycles than we'll ever
@@ -1724,17 +1725,19 @@ static int ag71xx_probe(struct platform_device *pdev)
        ag->stop_desc = dmam_alloc_coherent(&pdev->dev,
                                            sizeof(struct ag71xx_desc),
                                            &ag->stop_desc_dma, GFP_KERNEL);
-       if (!ag->stop_desc)
+       if (!ag->stop_desc) {
+               err = -ENOMEM;
                goto err_free;
+       }
 
        ag->stop_desc->data = 0;
        ag->stop_desc->ctrl = 0;
        ag->stop_desc->next = (u32)ag->stop_desc_dma;
 
        mac_addr = of_get_mac_address(np);
-       if (mac_addr)
+       if (!IS_ERR(mac_addr))
                memcpy(ndev->dev_addr, mac_addr, ETH_ALEN);
-       if (!mac_addr || !is_valid_ether_addr(ndev->dev_addr)) {
+       if (IS_ERR(mac_addr) || !is_valid_ether_addr(ndev->dev_addr)) {
                netif_err(ag, probe, ndev, "invalid MAC address, using random address\n");
                eth_random_addr(ndev->dev_addr);
        }
index 7c767ce..b5c6dc9 100644 (file)
@@ -1060,8 +1060,6 @@ static s32 atl1_setup_ring_resources(struct atl1_adapter *adapter)
                goto err_nomem;
        }
 
-       memset(ring_header->desc, 0, ring_header->size);
-
        /* init TPD ring */
        tpd_ring->dma = ring_header->dma;
        offset = (tpd_ring->dma & 0x7) ? (8 - (ring_header->dma & 0x7)) : 0;
index 3a3fb5c..3aba383 100644 (file)
@@ -291,7 +291,6 @@ static s32 atl2_setup_ring_resources(struct atl2_adapter *adapter)
                &adapter->ring_dma);
        if (!adapter->ring_vir_addr)
                return -ENOMEM;
-       memset(adapter->ring_vir_addr, 0, adapter->ring_size);
 
        /* Init TXD Ring */
        adapter->txd_dma = adapter->ring_dma ;
index 656ed80..e2be5a6 100644 (file)
@@ -285,6 +285,9 @@ int bnx2x_tx_int(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata)
        hw_cons = le16_to_cpu(*txdata->tx_cons_sb);
        sw_cons = txdata->tx_pkt_cons;
 
+       /* Ensure subsequent loads occur after hw_cons */
+       smp_rmb();
+
        while (sw_cons != hw_cons) {
                u16 pkt_cons;
 
index 3f63202..7134d2c 100644 (file)
@@ -2677,8 +2677,6 @@ static int bnxt_alloc_tx_rings(struct bnxt *bp)
                        mapping = txr->tx_push_mapping +
                                sizeof(struct tx_push_bd);
                        txr->data_mapping = cpu_to_le64(mapping);
-
-                       memset(txr->tx_push, 0, sizeof(struct tx_push_bd));
                }
                qidx = bp->tc_to_qidx[j];
                ring->queue_id = bp->q_info[qidx].queue_id;
@@ -3077,7 +3075,7 @@ static int bnxt_alloc_vnics(struct bnxt *bp)
        int num_vnics = 1;
 
 #ifdef CONFIG_RFS_ACCEL
-       if (bp->flags & BNXT_FLAG_RFS)
+       if ((bp->flags & (BNXT_FLAG_RFS | BNXT_FLAG_CHIP_P5)) == BNXT_FLAG_RFS)
                num_vnics += bp->rx_nr_rings;
 #endif
 
@@ -7188,6 +7186,9 @@ static int bnxt_alloc_rfs_vnics(struct bnxt *bp)
 #ifdef CONFIG_RFS_ACCEL
        int i, rc = 0;
 
+       if (bp->flags & BNXT_FLAG_CHIP_P5)
+               return 0;
+
        for (i = 0; i < bp->rx_nr_rings; i++) {
                struct bnxt_vnic_info *vnic;
                u16 vnic_id = i + 1;
@@ -9647,7 +9648,7 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
                return -ENOMEM;
 
        vnics = 1;
-       if (bp->flags & BNXT_FLAG_RFS)
+       if ((bp->flags & (BNXT_FLAG_RFS | BNXT_FLAG_CHIP_P5)) == BNXT_FLAG_RFS)
                vnics += rx_rings;
 
        if (bp->flags & BNXT_FLAG_AGG_RINGS)
index 34466b8..a2b5780 100644 (file)
@@ -3083,39 +3083,42 @@ static void bcmgenet_timeout(struct net_device *dev)
        netif_tx_wake_all_queues(dev);
 }
 
-#define MAX_MC_COUNT   16
+#define MAX_MDF_FILTER 17
 
 static inline void bcmgenet_set_mdf_addr(struct bcmgenet_priv *priv,
                                         unsigned char *addr,
-                                        int *i,
-                                        int *mc)
+                                        int *i)
 {
-       u32 reg;
-
        bcmgenet_umac_writel(priv, addr[0] << 8 | addr[1],
                             UMAC_MDF_ADDR + (*i * 4));
        bcmgenet_umac_writel(priv, addr[2] << 24 | addr[3] << 16 |
                             addr[4] << 8 | addr[5],
                             UMAC_MDF_ADDR + ((*i + 1) * 4));
-       reg = bcmgenet_umac_readl(priv, UMAC_MDF_CTRL);
-       reg |= (1 << (MAX_MC_COUNT - *mc));
-       bcmgenet_umac_writel(priv, reg, UMAC_MDF_CTRL);
        *i += 2;
-       (*mc)++;
 }
 
 static void bcmgenet_set_rx_mode(struct net_device *dev)
 {
        struct bcmgenet_priv *priv = netdev_priv(dev);
        struct netdev_hw_addr *ha;
-       int i, mc;
+       int i, nfilter;
        u32 reg;
 
        netif_dbg(priv, hw, dev, "%s: %08X\n", __func__, dev->flags);
 
-       /* Promiscuous mode */
+       /* Number of filters needed */
+       nfilter = netdev_uc_count(dev) + netdev_mc_count(dev) + 2;
+
+       /*
+        * Turn on promicuous mode for three scenarios
+        * 1. IFF_PROMISC flag is set
+        * 2. IFF_ALLMULTI flag is set
+        * 3. The number of filters needed exceeds the number filters
+        *    supported by the hardware.
+       */
        reg = bcmgenet_umac_readl(priv, UMAC_CMD);
-       if (dev->flags & IFF_PROMISC) {
+       if ((dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) ||
+           (nfilter > MAX_MDF_FILTER)) {
                reg |= CMD_PROMISC;
                bcmgenet_umac_writel(priv, reg, UMAC_CMD);
                bcmgenet_umac_writel(priv, 0, UMAC_MDF_CTRL);
@@ -3125,32 +3128,24 @@ static void bcmgenet_set_rx_mode(struct net_device *dev)
                bcmgenet_umac_writel(priv, reg, UMAC_CMD);
        }
 
-       /* UniMac doesn't support ALLMULTI */
-       if (dev->flags & IFF_ALLMULTI) {
-               netdev_warn(dev, "ALLMULTI is not supported\n");
-               return;
-       }
-
        /* update MDF filter */
        i = 0;
-       mc = 0;
        /* Broadcast */
-       bcmgenet_set_mdf_addr(priv, dev->broadcast, &i, &mc);
+       bcmgenet_set_mdf_addr(priv, dev->broadcast, &i);
        /* my own address.*/
-       bcmgenet_set_mdf_addr(priv, dev->dev_addr, &i, &mc);
-       /* Unicast list*/
-       if (netdev_uc_count(dev) > (MAX_MC_COUNT - mc))
-               return;
+       bcmgenet_set_mdf_addr(priv, dev->dev_addr, &i);
 
-       if (!netdev_uc_empty(dev))
-               netdev_for_each_uc_addr(ha, dev)
-                       bcmgenet_set_mdf_addr(priv, ha->addr, &i, &mc);
-       /* Multicast */
-       if (netdev_mc_empty(dev) || netdev_mc_count(dev) >= (MAX_MC_COUNT - mc))
-               return;
+       /* Unicast */
+       netdev_for_each_uc_addr(ha, dev)
+               bcmgenet_set_mdf_addr(priv, ha->addr, &i);
 
+       /* Multicast */
        netdev_for_each_mc_addr(ha, dev)
-               bcmgenet_set_mdf_addr(priv, ha->addr, &i, &mc);
+               bcmgenet_set_mdf_addr(priv, ha->addr, &i);
+
+       /* Enable filters */
+       reg = GENMASK(MAX_MDF_FILTER - 1, MAX_MDF_FILTER - nfilter);
+       bcmgenet_umac_writel(priv, reg, UMAC_MDF_CTRL);
 }
 
 /* Set the hardware MAC address. */
index fcf20a8..0322241 100644 (file)
@@ -218,15 +218,13 @@ int octeon_setup_iq(struct octeon_device *oct,
                return 0;
        }
        oct->instr_queue[iq_no] =
-           vmalloc_node(sizeof(struct octeon_instr_queue), numa_node);
+           vzalloc_node(sizeof(struct octeon_instr_queue), numa_node);
        if (!oct->instr_queue[iq_no])
                oct->instr_queue[iq_no] =
-                   vmalloc(sizeof(struct octeon_instr_queue));
+                   vzalloc(sizeof(struct octeon_instr_queue));
        if (!oct->instr_queue[iq_no])
                return 1;
 
-       memset(oct->instr_queue[iq_no], 0,
-              sizeof(struct octeon_instr_queue));
 
        oct->instr_queue[iq_no]->q_index = q_index;
        oct->instr_queue[iq_no]->app_ctx = app_ctx;
index 20c09cc..60aa45b 100644 (file)
@@ -94,7 +94,7 @@ static int my3126_interrupt_handler(struct cphy *cphy)
        return cphy_cause_link_change;
 }
 
-static void my3216_poll(struct work_struct *work)
+static void my3126_poll(struct work_struct *work)
 {
        struct cphy *cphy = container_of(work, struct cphy, phy_update.work);
 
@@ -177,7 +177,7 @@ static struct cphy *my3126_phy_create(struct net_device *dev,
                return NULL;
 
        cphy_init(cphy, dev, phy_addr, &my3126_ops, mdio_ops);
-       INIT_DELAYED_WORK(&cphy->phy_update, my3216_poll);
+       INIT_DELAYED_WORK(&cphy->phy_update, my3126_poll);
        cphy->bmsr = 0;
 
        return cphy;
index 67202b6..4311ad9 100644 (file)
@@ -5561,7 +5561,6 @@ static int cxgb4_iov_configure(struct pci_dev *pdev, int num_vfs)
                char name[IFNAMSIZ];
                u32 devcap2;
                u16 flags;
-               int pos;
 
                /* If we want to instantiate Virtual Functions, then our
                 * parent bridge's PCI-E needs to support Alternative Routing
@@ -5569,9 +5568,8 @@ static int cxgb4_iov_configure(struct pci_dev *pdev, int num_vfs)
                 * and above.
                 */
                pbridge = pdev->bus->self;
-               pos = pci_find_capability(pbridge, PCI_CAP_ID_EXP);
-               pci_read_config_word(pbridge, pos + PCI_EXP_FLAGS, &flags);
-               pci_read_config_dword(pbridge, pos + PCI_EXP_DEVCAP2, &devcap2);
+               pcie_capability_read_word(pbridge, PCI_EXP_FLAGS, &flags);
+               pcie_capability_read_dword(pbridge, PCI_EXP_DEVCAP2, &devcap2);
 
                if ((flags & PCI_EXP_FLAGS_VERS) < 2 ||
                    !(devcap2 & PCI_EXP_DEVCAP2_ARI)) {
index 312599c..e447976 100644 (file)
@@ -67,7 +67,8 @@ static struct ch_tc_pedit_fields pedits[] = {
 static struct ch_tc_flower_entry *allocate_flower_entry(void)
 {
        struct ch_tc_flower_entry *new = kzalloc(sizeof(*new), GFP_KERNEL);
-       spin_lock_init(&new->lock);
+       if (new)
+               spin_lock_init(&new->lock);
        return new;
 }
 
index ba6c153..60218dc 100644 (file)
@@ -207,7 +207,6 @@ static int t4_sched_queue_bind(struct port_info *pi, struct ch_sched_queue *p)
                goto out_err;
 
        /* Bind queue to specified class */
-       memset(qe, 0, sizeof(*qe));
        qe->cntxt_id = qid;
        memcpy(&qe->param, p, sizeof(qe->param));
 
index 9dd5ed9..f7fc553 100644 (file)
@@ -7309,7 +7309,6 @@ int t4_fixup_host_params(struct adapter *adap, unsigned int page_size,
        } else {
                unsigned int pack_align;
                unsigned int ingpad, ingpack;
-               unsigned int pcie_cap;
 
                /* T5 introduced the separation of the Free List Padding and
                 * Packing Boundaries.  Thus, we can select a smaller Padding
@@ -7334,8 +7333,7 @@ int t4_fixup_host_params(struct adapter *adap, unsigned int page_size,
                 * multiple of the Maximum Payload Size.
                 */
                pack_align = fl_align;
-               pcie_cap = pci_find_capability(adap->pdev, PCI_CAP_ID_EXP);
-               if (pcie_cap) {
+               if (pci_is_pcie(adap->pdev)) {
                        unsigned int mps, mps_log;
                        u16 devctl;
 
@@ -7343,9 +7341,8 @@ int t4_fixup_host_params(struct adapter *adap, unsigned int page_size,
                         * [bits 7:5] encodes sizes as powers of 2 starting at
                         * 128 bytes.
                         */
-                       pci_read_config_word(adap->pdev,
-                                            pcie_cap + PCI_EXP_DEVCTL,
-                                            &devctl);
+                       pcie_capability_read_word(adap->pdev, PCI_EXP_DEVCTL,
+                                                 &devctl);
                        mps_log = ((devctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5) + 7;
                        mps = 1 << mps_log;
                        if (mps > pack_align)
index 82015c8..2edb86e 100644 (file)
@@ -4697,8 +4697,17 @@ int be_update_queues(struct be_adapter *adapter)
        struct net_device *netdev = adapter->netdev;
        int status;
 
-       if (netif_running(netdev))
+       if (netif_running(netdev)) {
+               /* be_tx_timeout() must not run concurrently with this
+                * function, synchronize with an already-running dev_watchdog
+                */
+               netif_tx_lock_bh(netdev);
+               /* device cannot transmit now, avoid dev_watchdog timeouts */
+               netif_carrier_off(netdev);
+               netif_tx_unlock_bh(netdev);
+
                be_close(netdev);
+       }
 
        be_cancel_worker(adapter);
 
index 9d459cc..e5610a4 100644 (file)
@@ -3144,8 +3144,6 @@ static int fec_enet_init(struct net_device *ndev)
                return -ENOMEM;
        }
 
-       memset(cbd_base, 0, bd_size);
-
        /* Get the Ethernet address */
        fec_get_mac(ndev);
        /* make sure MAC we just acquired is programmed into the hw */
index 24f16e3..4972987 100644 (file)
@@ -232,7 +232,7 @@ abort_with_mgmt_vector:
 abort_with_msix_enabled:
        pci_disable_msix(priv->pdev);
 abort_with_msix_vectors:
-       kfree(priv->msix_vectors);
+       kvfree(priv->msix_vectors);
        priv->msix_vectors = NULL;
        return err;
 }
@@ -256,7 +256,7 @@ static void gve_free_notify_blocks(struct gve_priv *priv)
        priv->ntfy_blocks = NULL;
        free_irq(priv->msix_vectors[priv->mgmt_msix_idx].vector, priv);
        pci_disable_msix(priv->pdev);
-       kfree(priv->msix_vectors);
+       kvfree(priv->msix_vectors);
        priv->msix_vectors = NULL;
 }
 
@@ -445,12 +445,12 @@ static int gve_alloc_rings(struct gve_priv *priv)
        return 0;
 
 free_rx:
-       kfree(priv->rx);
+       kvfree(priv->rx);
        priv->rx = NULL;
 free_tx_queue:
        gve_tx_free_rings(priv);
 free_tx:
-       kfree(priv->tx);
+       kvfree(priv->tx);
        priv->tx = NULL;
        return err;
 }
@@ -500,7 +500,7 @@ static void gve_free_rings(struct gve_priv *priv)
                        gve_remove_napi(priv, ntfy_idx);
                }
                gve_tx_free_rings(priv);
-               kfree(priv->tx);
+               kvfree(priv->tx);
                priv->tx = NULL;
        }
        if (priv->rx) {
@@ -509,7 +509,7 @@ static void gve_free_rings(struct gve_priv *priv)
                        gve_remove_napi(priv, ntfy_idx);
                }
                gve_rx_free_rings(priv);
-               kfree(priv->rx);
+               kvfree(priv->rx);
                priv->rx = NULL;
        }
 }
@@ -592,9 +592,9 @@ static void gve_free_queue_page_list(struct gve_priv *priv,
                gve_free_page(&priv->pdev->dev, qpl->pages[i],
                              qpl->page_buses[i], gve_qpl_dma_dir(priv, id));
 
-       kfree(qpl->page_buses);
+       kvfree(qpl->page_buses);
 free_pages:
-       kfree(qpl->pages);
+       kvfree(qpl->pages);
        priv->num_registered_pages -= qpl->num_entries;
 }
 
@@ -635,7 +635,7 @@ static int gve_alloc_qpls(struct gve_priv *priv)
 free_qpls:
        for (j = 0; j <= i; j++)
                gve_free_queue_page_list(priv, j);
-       kfree(priv->qpls);
+       kvfree(priv->qpls);
        return err;
 }
 
@@ -644,12 +644,12 @@ static void gve_free_qpls(struct gve_priv *priv)
        int num_qpls = gve_num_tx_qpls(priv) + gve_num_rx_qpls(priv);
        int i;
 
-       kfree(priv->qpl_cfg.qpl_id_map);
+       kvfree(priv->qpl_cfg.qpl_id_map);
 
        for (i = 0; i < num_qpls; i++)
                gve_free_queue_page_list(priv, i);
 
-       kfree(priv->qpls);
+       kvfree(priv->qpls);
 }
 
 /* Use this to schedule a reset when the device is capable of continuing
@@ -1192,7 +1192,6 @@ abort_with_enabled:
        pci_disable_device(pdev);
        return -ENXIO;
 }
-EXPORT_SYMBOL(gve_probe);
 
 static void gve_remove(struct pci_dev *pdev)
 {
index c1aeabd..1914b83 100644 (file)
@@ -35,7 +35,7 @@ static void gve_rx_free_ring(struct gve_priv *priv, int idx)
 
        gve_unassign_qpl(priv, rx->data.qpl->id);
        rx->data.qpl = NULL;
-       kfree(rx->data.page_info);
+       kvfree(rx->data.page_info);
 
        slots = rx->data.mask + 1;
        bytes = sizeof(*rx->data.data_ring) * slots;
@@ -168,7 +168,7 @@ abort_with_q_resources:
                          rx->q_resources, rx->q_resources_bus);
        rx->q_resources = NULL;
 abort_filled:
-       kfree(rx->data.page_info);
+       kvfree(rx->data.page_info);
 abort_with_slots:
        bytes = sizeof(*rx->data.data_ring) * slots;
        dma_free_coherent(hdev, bytes, rx->data.data_ring, rx->data.data_bus);
index 8ad5292..75329ab 100644 (file)
@@ -43,7 +43,7 @@ enum HCLGE_MBX_OPCODE {
        HCLGE_MBX_GET_QID_IN_PF,        /* (VF -> PF) get queue id in pf */
        HCLGE_MBX_LINK_STAT_MODE,       /* (PF -> VF) link mode has changed */
        HCLGE_MBX_GET_LINK_MODE,        /* (VF -> PF) get the link mode of pf */
-       HLCGE_MBX_PUSH_VLAN_INFO,       /* (PF -> VF) push port base vlan */
+       HCLGE_MBX_PUSH_VLAN_INFO,       /* (PF -> VF) push port base vlan */
        HCLGE_MBX_GET_MEDIA_TYPE,       /* (VF -> PF) get media type */
 
        HCLGE_MBX_GET_VF_FLR_STATUS = 200, /* (M7 -> PF) get vf reset status */
index a38ac7c..690b999 100644 (file)
@@ -304,7 +304,7 @@ int hclge_push_vf_port_base_vlan_info(struct hclge_vport *vport, u8 vfid,
        memcpy(&msg_data[6], &vlan_tag, sizeof(u16));
 
        return hclge_send_mbx_msg(vport, msg_data, sizeof(msg_data),
-                                 HLCGE_MBX_PUSH_VLAN_INFO, vfid);
+                                 HCLGE_MBX_PUSH_VLAN_INFO, vfid);
 }
 
 static int hclge_set_vf_vlan_cfg(struct hclge_vport *vport,
index f60b80b..6a96987 100644 (file)
@@ -204,7 +204,7 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev)
                case HCLGE_MBX_LINK_STAT_CHANGE:
                case HCLGE_MBX_ASSERTING_RESET:
                case HCLGE_MBX_LINK_STAT_MODE:
-               case HLCGE_MBX_PUSH_VLAN_INFO:
+               case HCLGE_MBX_PUSH_VLAN_INFO:
                        /* set this mbx event as pending. This is required as we
                         * might loose interrupt event when mbx task is busy
                         * handling. This shall be cleared when mbx task just
@@ -307,7 +307,7 @@ void hclgevf_mbx_async_handler(struct hclgevf_dev *hdev)
                        hclgevf_reset_task_schedule(hdev);
 
                        break;
-               case HLCGE_MBX_PUSH_VLAN_INFO:
+               case HCLGE_MBX_PUSH_VLAN_INFO:
                        state = le16_to_cpu(msg_q[1]);
                        vlan_info = &msg_q[1];
                        hclgevf_update_port_base_vlan_info(hdev, state,
index 41c90f2..63db08d 100644 (file)
@@ -2286,7 +2286,7 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
        struct ice_hw *hw;
        int err;
 
-       /* this driver uses devres, see Documentation/driver-model/devres.rst */
+       /* this driver uses devres, see Documentation/driver-api/driver-model/devres.rst */
        err = pcim_enable_device(pdev);
        if (err)
                return err;
index 93f3b4e..aa9323e 100644 (file)
@@ -3912,13 +3912,11 @@ void igc_write_pci_cfg(struct igc_hw *hw, u32 reg, u16 *value)
 s32 igc_read_pcie_cap_reg(struct igc_hw *hw, u32 reg, u16 *value)
 {
        struct igc_adapter *adapter = hw->back;
-       u16 cap_offset;
 
-       cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
-       if (!cap_offset)
+       if (!pci_is_pcie(adapter->pdev))
                return -IGC_ERR_CONFIG;
 
-       pci_read_config_word(adapter->pdev, cap_offset + reg, value);
+       pcie_capability_read_word(adapter->pdev, reg, value);
 
        return IGC_SUCCESS;
 }
@@ -3926,13 +3924,11 @@ s32 igc_read_pcie_cap_reg(struct igc_hw *hw, u32 reg, u16 *value)
 s32 igc_write_pcie_cap_reg(struct igc_hw *hw, u32 reg, u16 *value)
 {
        struct igc_adapter *adapter = hw->back;
-       u16 cap_offset;
 
-       cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
-       if (!cap_offset)
+       if (!pci_is_pcie(adapter->pdev))
                return -IGC_ERR_CONFIG;
 
-       pci_write_config_word(adapter->pdev, cap_offset + reg, *value);
+       pcie_capability_write_word(adapter->pdev, reg, *value);
 
        return IGC_SUCCESS;
 }
index 76b7b7b..0b66835 100644 (file)
@@ -582,11 +582,6 @@ jme_setup_tx_resources(struct jme_adapter *jme)
        if (unlikely(!(txring->bufinf)))
                goto err_free_txring;
 
-       /*
-        * Initialize Transmit Descriptors
-        */
-       memset(txring->alloc, 0, TX_RING_ALLOC_SIZE(jme->tx_ring_size));
-
        return 0;
 
 err_free_txring:
index 35a92fd..9ac854c 100644 (file)
@@ -2558,8 +2558,6 @@ static int skge_up(struct net_device *dev)
                goto free_pci_mem;
        }
 
-       memset(skge->mem, 0, skge->mem_size);
-
        err = skge_ring_alloc(&skge->rx_ring, skge->mem, skge->dma);
        if (err)
                goto free_pci_mem;
index fe518c8..f518312 100644 (file)
@@ -4917,6 +4917,13 @@ static const struct dmi_system_id msi_blacklist[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "P-79"),
                },
        },
+       {
+               .ident = "ASUS P5W DH Deluxe",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTEK COMPUTER INC"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"),
+               },
+       },
        {}
 };
 
index b20b3a5..c39d7f4 100644 (file)
@@ -2548,8 +2548,10 @@ static int mtk_probe(struct platform_device *pdev)
                        continue;
 
                err = mtk_add_mac(eth, mac_np);
-               if (err)
+               if (err) {
+                       of_node_put(mac_np);
                        goto err_deinit_hw;
+               }
        }
 
        if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT)) {
index a5be277..c790a5f 100644 (file)
@@ -1013,8 +1013,6 @@ static int mlx4_create_eq(struct mlx4_dev *dev, int nent,
 
                dma_list[i] = t;
                eq->page_list[i].map = t;
-
-               memset(eq->page_list[i].buf, 0, PAGE_SIZE);
        }
 
        eq->eqn = mlx4_bitmap_alloc(&priv->eq_table.bitmap);
index 7245d28..7f747cb 100644 (file)
@@ -735,8 +735,7 @@ mlx5e_rep_indr_setup_tc_block(struct net_device *netdev,
                list_add(&indr_priv->list,
                         &rpriv->uplink_priv.tc_indr_block_priv_list);
 
-               block_cb = flow_block_cb_alloc(f->net,
-                                              mlx5e_rep_indr_setup_block_cb,
+               block_cb = flow_block_cb_alloc(mlx5e_rep_indr_setup_block_cb,
                                               indr_priv, indr_priv,
                                               mlx5e_rep_indr_tc_block_unbind);
                if (IS_ERR(block_cb)) {
@@ -753,7 +752,7 @@ mlx5e_rep_indr_setup_tc_block(struct net_device *netdev,
                if (!indr_priv)
                        return -ENOENT;
 
-               block_cb = flow_block_cb_lookup(f,
+               block_cb = flow_block_cb_lookup(f->block,
                                                mlx5e_rep_indr_setup_block_cb,
                                                indr_priv);
                if (!block_cb)
index 2d64362..cc096f6 100644 (file)
@@ -1499,7 +1499,8 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
        *match_level = MLX5_MATCH_NONE;
 
        if (dissector->used_keys &
-           ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
+           ~(BIT(FLOW_DISSECTOR_KEY_META) |
+             BIT(FLOW_DISSECTOR_KEY_CONTROL) |
              BIT(FLOW_DISSECTOR_KEY_BASIC) |
              BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
              BIT(FLOW_DISSECTOR_KEY_VLAN) |
@@ -1522,11 +1523,7 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
                return -EOPNOTSUPP;
        }
 
-       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) ||
-           flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) ||
-           flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID) ||
-           flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS) ||
-           flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_OPTS)) {
+       if (mlx5e_get_tc_tun(filter_dev)) {
                if (parse_tunnel_attr(priv, spec, f, filter_dev, tunnel_match_level))
                        return -EOPNOTSUPP;
 
@@ -2647,6 +2644,10 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv,
        family = ip_tunnel_info_af(tun_info);
        key.ip_tun_key = &tun_info->key;
        key.tc_tunnel = mlx5e_get_tc_tun(mirred_dev);
+       if (!key.tc_tunnel) {
+               NL_SET_ERR_MSG_MOD(extack, "Unsupported tunnel");
+               return -EOPNOTSUPP;
+       }
 
        hash_key = hash_encap_info(&key);
 
index 3b04d89..1f3891f 100644 (file)
@@ -2450,7 +2450,6 @@ int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,
        MLX5_SET(query_vport_counter_in, in, vport_number, vport->vport);
        MLX5_SET(query_vport_counter_in, in, other_vport, 1);
 
-       memset(out, 0, outlen);
        err = mlx5_cmd_exec(esw->dev, in, sizeof(in), out, outlen);
        if (err)
                goto free_out;
index 957d9b0..089ae4d 100644 (file)
@@ -1134,7 +1134,6 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports)
        }
 
        /* create send-to-vport group */
-       memset(flow_group_in, 0, inlen);
        MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
                 MLX5_MATCH_MISC_PARAMETERS);
 
@@ -1293,8 +1292,6 @@ static int esw_create_vport_rx_group(struct mlx5_eswitch *esw, int nvports)
                return -ENOMEM;
 
        /* create vport rx group */
-       memset(flow_group_in, 0, inlen);
-
        esw_set_flow_group_source_port(esw, flow_group_in);
 
        MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
index 2fe6923..9314777 100644 (file)
@@ -597,7 +597,7 @@ mlx5_fw_fatal_reporter_dump(struct devlink_health_reporter *reporter,
        err = devlink_fmsg_arr_pair_nest_end(fmsg);
 
 free_data:
-       kfree(cr_data);
+       kvfree(cr_data);
        return err;
 }
 
index 051b193..615455a 100644 (file)
@@ -847,7 +847,6 @@ static int mlxsw_pci_queue_init(struct mlxsw_pci *mlxsw_pci, char *mbox,
                                             &mem_item->mapaddr);
        if (!mem_item->buf)
                return -ENOMEM;
-       memset(mem_item->buf, 0, mem_item->size);
 
        q->elem_info = kcalloc(q->count, sizeof(*q->elem_info), GFP_KERNEL);
        if (!q->elem_info) {
index 4d34d42..6506381 100644 (file)
@@ -1604,14 +1604,14 @@ mlxsw_sp_setup_tc_block_flower_bind(struct mlxsw_sp_port *mlxsw_sp_port,
        bool register_block = false;
        int err;
 
-       block_cb = flow_block_cb_lookup(f, mlxsw_sp_setup_tc_block_cb_flower,
+       block_cb = flow_block_cb_lookup(f->block,
+                                       mlxsw_sp_setup_tc_block_cb_flower,
                                        mlxsw_sp);
        if (!block_cb) {
                acl_block = mlxsw_sp_acl_block_create(mlxsw_sp, f->net);
                if (!acl_block)
                        return -ENOMEM;
-               block_cb = flow_block_cb_alloc(f->net,
-                                              mlxsw_sp_setup_tc_block_cb_flower,
+               block_cb = flow_block_cb_alloc(mlxsw_sp_setup_tc_block_cb_flower,
                                               mlxsw_sp, acl_block,
                                               mlxsw_sp_tc_block_flower_release);
                if (IS_ERR(block_cb)) {
@@ -1657,7 +1657,8 @@ mlxsw_sp_setup_tc_block_flower_unbind(struct mlxsw_sp_port *mlxsw_sp_port,
        struct flow_block_cb *block_cb;
        int err;
 
-       block_cb = flow_block_cb_lookup(f, mlxsw_sp_setup_tc_block_cb_flower,
+       block_cb = flow_block_cb_lookup(f->block,
+                                       mlxsw_sp_setup_tc_block_cb_flower,
                                        mlxsw_sp);
        if (!block_cb)
                return;
@@ -1680,7 +1681,7 @@ static int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port,
                                   struct flow_block_offload *f)
 {
        struct flow_block_cb *block_cb;
-       tc_setup_cb_t *cb;
+       flow_setup_cb_t *cb;
        bool ingress;
        int err;
 
@@ -1702,7 +1703,7 @@ static int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port,
                                          &mlxsw_sp_block_cb_list))
                        return -EBUSY;
 
-               block_cb = flow_block_cb_alloc(f->net, cb, mlxsw_sp_port,
+               block_cb = flow_block_cb_alloc(cb, mlxsw_sp_port,
                                               mlxsw_sp_port, NULL);
                if (IS_ERR(block_cb))
                        return PTR_ERR(block_cb);
@@ -1718,7 +1719,7 @@ static int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port,
        case FLOW_BLOCK_UNBIND:
                mlxsw_sp_setup_tc_block_flower_unbind(mlxsw_sp_port,
                                                      f, ingress);
-               block_cb = flow_block_cb_lookup(f, cb, mlxsw_sp_port);
+               block_cb = flow_block_cb_lookup(f->block, cb, mlxsw_sp_port);
                if (!block_cb)
                        return -ENOENT;
 
index a252b08..131f62c 100644 (file)
@@ -830,6 +830,7 @@ int mlxsw_sp_setup_tc_prio(struct mlxsw_sp_port *mlxsw_sp_port,
                           struct tc_prio_qopt_offload *p);
 
 /* spectrum_fid.c */
+bool mlxsw_sp_fid_is_dummy(struct mlxsw_sp *mlxsw_sp, u16 fid_index);
 bool mlxsw_sp_fid_lag_vid_valid(const struct mlxsw_sp_fid *fid);
 struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp,
                                                  u16 fid_index);
index b25048c..21296fa 100644 (file)
@@ -408,14 +408,6 @@ static int mlxsw_sp_port_dcb_app_update(struct mlxsw_sp_port *mlxsw_sp_port)
        have_dscp = mlxsw_sp_port_dcb_app_prio_dscp_map(mlxsw_sp_port,
                                                        &prio_map);
 
-       if (!have_dscp) {
-               err = mlxsw_sp_port_dcb_toggle_trust(mlxsw_sp_port,
-                                       MLXSW_REG_QPTS_TRUST_STATE_PCP);
-               if (err)
-                       netdev_err(mlxsw_sp_port->dev, "Couldn't switch to trust L2\n");
-               return err;
-       }
-
        mlxsw_sp_port_dcb_app_dscp_prio_map(mlxsw_sp_port, default_prio,
                                            &dscp_map);
        err = mlxsw_sp_port_dcb_app_update_qpdpm(mlxsw_sp_port,
@@ -432,6 +424,14 @@ static int mlxsw_sp_port_dcb_app_update(struct mlxsw_sp_port *mlxsw_sp_port)
                return err;
        }
 
+       if (!have_dscp) {
+               err = mlxsw_sp_port_dcb_toggle_trust(mlxsw_sp_port,
+                                       MLXSW_REG_QPTS_TRUST_STATE_PCP);
+               if (err)
+                       netdev_err(mlxsw_sp_port->dev, "Couldn't switch to trust L2\n");
+               return err;
+       }
+
        err = mlxsw_sp_port_dcb_toggle_trust(mlxsw_sp_port,
                                             MLXSW_REG_QPTS_TRUST_STATE_DSCP);
        if (err) {
index 46baf3b..8df3cb2 100644 (file)
@@ -126,6 +126,16 @@ static const int *mlxsw_sp_packet_type_sfgc_types[] = {
        [MLXSW_SP_FLOOD_TYPE_MC]        = mlxsw_sp_sfgc_mc_packet_types,
 };
 
+bool mlxsw_sp_fid_is_dummy(struct mlxsw_sp *mlxsw_sp, u16 fid_index)
+{
+       enum mlxsw_sp_fid_type fid_type = MLXSW_SP_FID_TYPE_DUMMY;
+       struct mlxsw_sp_fid_family *fid_family;
+
+       fid_family = mlxsw_sp->fid_core->fid_family_arr[fid_type];
+
+       return fid_family->start_index == fid_index;
+}
+
 bool mlxsw_sp_fid_lag_vid_valid(const struct mlxsw_sp_fid *fid)
 {
        return fid->fid_family->lag_vid_valid;
index 50111f2..5ecb451 100644 (file)
@@ -2468,6 +2468,9 @@ static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp,
                goto just_remove;
        }
 
+       if (mlxsw_sp_fid_is_dummy(mlxsw_sp, fid))
+               goto just_remove;
+
        mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_fid(mlxsw_sp_port, fid);
        if (!mlxsw_sp_port_vlan) {
                netdev_err(mlxsw_sp_port->dev, "Failed to find a matching {Port, VID} following FDB notification\n");
@@ -2527,6 +2530,9 @@ static void mlxsw_sp_fdb_notify_mac_lag_process(struct mlxsw_sp *mlxsw_sp,
                goto just_remove;
        }
 
+       if (mlxsw_sp_fid_is_dummy(mlxsw_sp, fid))
+               goto just_remove;
+
        mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_fid(mlxsw_sp_port, fid);
        if (!mlxsw_sp_port_vlan) {
                netdev_err(mlxsw_sp_port->dev, "Failed to find a matching {Port, VID} following FDB notification\n");
index 58bde1a..2451d4a 100644 (file)
@@ -291,8 +291,10 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
                        continue;
 
                err = ocelot_probe_port(ocelot, port, regs, phy);
-               if (err)
+               if (err) {
+                       of_node_put(portnp);
                        return err;
+               }
 
                phy_mode = of_get_phy_mode(portnp);
                if (phy_mode < 0)
@@ -318,6 +320,7 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
                        dev_err(ocelot->dev,
                                "invalid phy mode for port%d, (Q)SGMII only\n",
                                port);
+                       of_node_put(portnp);
                        return -EINVAL;
                }
 
index 7aaddc0..59487d4 100644 (file)
@@ -316,15 +316,14 @@ int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port,
        if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
                return -EOPNOTSUPP;
 
-       block_cb = flow_block_cb_lookup(f, ocelot_setup_tc_block_cb_flower,
-                                       port);
+       block_cb = flow_block_cb_lookup(f->block,
+                                       ocelot_setup_tc_block_cb_flower, port);
        if (!block_cb) {
                port_block = ocelot_port_block_create(port);
                if (!port_block)
                        return -ENOMEM;
 
-               block_cb = flow_block_cb_alloc(f->net,
-                                              ocelot_setup_tc_block_cb_flower,
+               block_cb = flow_block_cb_alloc(ocelot_setup_tc_block_cb_flower,
                                               port, port_block,
                                               ocelot_tc_block_unbind);
                if (IS_ERR(block_cb)) {
@@ -351,8 +350,8 @@ void ocelot_setup_tc_block_flower_unbind(struct ocelot_port *port,
 {
        struct flow_block_cb *block_cb;
 
-       block_cb = flow_block_cb_lookup(f, ocelot_setup_tc_block_cb_flower,
-                                       port);
+       block_cb = flow_block_cb_lookup(f->block,
+                                       ocelot_setup_tc_block_cb_flower, port);
        if (!block_cb)
                return;
 
index 9e6464f..16a6db7 100644 (file)
@@ -134,7 +134,7 @@ static int ocelot_setup_tc_block(struct ocelot_port *port,
                                 struct flow_block_offload *f)
 {
        struct flow_block_cb *block_cb;
-       tc_setup_cb_t *cb;
+       flow_setup_cb_t *cb;
        int err;
 
        netdev_dbg(port->dev, "tc_block command %d, binder_type %d\n",
@@ -156,7 +156,7 @@ static int ocelot_setup_tc_block(struct ocelot_port *port,
                if (flow_block_cb_is_busy(cb, port, &ocelot_block_cb_list))
                        return -EBUSY;
 
-               block_cb = flow_block_cb_alloc(f->net, cb, port, port, NULL);
+               block_cb = flow_block_cb_alloc(cb, port, port, NULL);
                if (IS_ERR(block_cb))
                        return PTR_ERR(block_cb);
 
@@ -169,7 +169,7 @@ static int ocelot_setup_tc_block(struct ocelot_port *port,
                list_add_tail(&block_cb->driver_list, f->driver_block_list);
                return 0;
        case FLOW_BLOCK_UNBIND:
-               block_cb = flow_block_cb_lookup(f, cb, port);
+               block_cb = flow_block_cb_lookup(f->block, cb, port);
                if (!block_cb)
                        return -ENOENT;
 
index 3b2ae1a..e0b2bf3 100644 (file)
@@ -747,7 +747,6 @@ static int init_shared_mem(struct s2io_nic *nic)
                                return -ENOMEM;
                        }
                        mem_allocated += size;
-                       memset(tmp_v_addr, 0, size);
 
                        size = sizeof(struct rxd_info) *
                                rxd_count[nic->rxd_mode];
index faa8ba0..e209f15 100644 (file)
@@ -1318,8 +1318,7 @@ static int nfp_flower_setup_tc_block(struct net_device *netdev,
                                          &nfp_block_cb_list))
                        return -EBUSY;
 
-               block_cb = flow_block_cb_alloc(f->net,
-                                              nfp_flower_setup_tc_block_cb,
+               block_cb = flow_block_cb_alloc(nfp_flower_setup_tc_block_cb,
                                               repr, repr, NULL);
                if (IS_ERR(block_cb))
                        return PTR_ERR(block_cb);
@@ -1328,7 +1327,8 @@ static int nfp_flower_setup_tc_block(struct net_device *netdev,
                list_add_tail(&block_cb->driver_list, &nfp_block_cb_list);
                return 0;
        case FLOW_BLOCK_UNBIND:
-               block_cb = flow_block_cb_lookup(f, nfp_flower_setup_tc_block_cb,
+               block_cb = flow_block_cb_lookup(f->block,
+                                               nfp_flower_setup_tc_block_cb,
                                                repr);
                if (!block_cb)
                        return -ENOENT;
@@ -1424,8 +1424,7 @@ nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app,
                cb_priv->app = app;
                list_add(&cb_priv->list, &priv->indr_block_cb_priv);
 
-               block_cb = flow_block_cb_alloc(f->net,
-                                              nfp_flower_setup_indr_block_cb,
+               block_cb = flow_block_cb_alloc(nfp_flower_setup_indr_block_cb,
                                               cb_priv, cb_priv,
                                               nfp_flower_setup_indr_tc_release);
                if (IS_ERR(block_cb)) {
@@ -1442,7 +1441,7 @@ nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app,
                if (!cb_priv)
                        return -ENOENT;
 
-               block_cb = flow_block_cb_lookup(f,
+               block_cb = flow_block_cb_lookup(f->block,
                                                nfp_flower_setup_indr_block_cb,
                                                cb_priv);
                if (!block_cb)
index 433052f..5e9f8ee 100644 (file)
@@ -442,10 +442,8 @@ nx_fw_cmd_create_tx_ctx(struct netxen_adapter *adapter)
                goto out_free_rq;
        }
 
-       memset(rq_addr, 0, rq_size);
        prq = rq_addr;
 
-       memset(rsp_addr, 0, rsp_size);
        prsp = rsp_addr;
 
        prq->host_rsp_dma_addr = cpu_to_le64(rsp_phys_addr);
@@ -755,7 +753,6 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter)
                return -ENOMEM;
        }
 
-       memset(addr, 0, sizeof(struct netxen_ring_ctx));
        recv_ctx->hwctx = addr;
        recv_ctx->hwctx->ctx_id = cpu_to_le32(port);
        recv_ctx->hwctx->cmd_consumer_offset =
index f900fde..17c64e4 100644 (file)
@@ -530,9 +530,8 @@ static void qed_rdma_init_devinfo(struct qed_hwfn *p_hwfn,
        SET_FIELD(dev->dev_caps, QED_RDMA_DEV_CAP_LOCAL_INV_FENCE, 1);
 
        /* Check atomic operations support in PCI configuration space. */
-       pci_read_config_dword(cdev->pdev,
-                             cdev->pdev->pcie_cap + PCI_EXP_DEVCTL2,
-                             &pci_status_control);
+       pcie_capability_read_dword(cdev->pdev, PCI_EXP_DEVCTL2,
+                                  &pci_status_control);
 
        if (pci_status_control & PCI_EXP_DEVCTL2_LTR_EN)
                SET_FIELD(dev->dev_caps, QED_RDMA_DEV_CAP_ATOMIC_OP, 1);
index efef545..6272115 100644 (file)
@@ -3251,9 +3251,9 @@ static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp)
 
        ret = phy_read_paged(tp->phydev, 0x0a46, 0x13);
        if (ret & BIT(8))
-               phy_modify_paged(tp->phydev, 0x0c41, 0x12, 0, BIT(1));
+               phy_modify_paged(tp->phydev, 0x0c41, 0x15, 0, BIT(1));
        else
-               phy_modify_paged(tp->phydev, 0x0c41, 0x12, BIT(1), 0);
+               phy_modify_paged(tp->phydev, 0x0c41, 0x15, BIT(1), 0);
 
        /* Enable PHY auto speed down */
        phy_modify_paged(tp->phydev, 0x0a44, 0x11, 0, BIT(3) | BIT(2));
@@ -4667,6 +4667,143 @@ static void rtl_hw_start_8411_2(struct rtl8169_private *tp)
        /* disable aspm and clock request before access ephy */
        rtl_hw_aspm_clkreq_enable(tp, false);
        rtl_ephy_init(tp, e_info_8411_2);
+
+       /* The following Realtek-provided magic fixes an issue with the RX unit
+        * getting confused after the PHY having been powered-down.
+        */
+       r8168_mac_ocp_write(tp, 0xFC28, 0x0000);
+       r8168_mac_ocp_write(tp, 0xFC2A, 0x0000);
+       r8168_mac_ocp_write(tp, 0xFC2C, 0x0000);
+       r8168_mac_ocp_write(tp, 0xFC2E, 0x0000);
+       r8168_mac_ocp_write(tp, 0xFC30, 0x0000);
+       r8168_mac_ocp_write(tp, 0xFC32, 0x0000);
+       r8168_mac_ocp_write(tp, 0xFC34, 0x0000);
+       r8168_mac_ocp_write(tp, 0xFC36, 0x0000);
+       mdelay(3);
+       r8168_mac_ocp_write(tp, 0xFC26, 0x0000);
+
+       r8168_mac_ocp_write(tp, 0xF800, 0xE008);
+       r8168_mac_ocp_write(tp, 0xF802, 0xE00A);
+       r8168_mac_ocp_write(tp, 0xF804, 0xE00C);
+       r8168_mac_ocp_write(tp, 0xF806, 0xE00E);
+       r8168_mac_ocp_write(tp, 0xF808, 0xE027);
+       r8168_mac_ocp_write(tp, 0xF80A, 0xE04F);
+       r8168_mac_ocp_write(tp, 0xF80C, 0xE05E);
+       r8168_mac_ocp_write(tp, 0xF80E, 0xE065);
+       r8168_mac_ocp_write(tp, 0xF810, 0xC602);
+       r8168_mac_ocp_write(tp, 0xF812, 0xBE00);
+       r8168_mac_ocp_write(tp, 0xF814, 0x0000);
+       r8168_mac_ocp_write(tp, 0xF816, 0xC502);
+       r8168_mac_ocp_write(tp, 0xF818, 0xBD00);
+       r8168_mac_ocp_write(tp, 0xF81A, 0x074C);
+       r8168_mac_ocp_write(tp, 0xF81C, 0xC302);
+       r8168_mac_ocp_write(tp, 0xF81E, 0xBB00);
+       r8168_mac_ocp_write(tp, 0xF820, 0x080A);
+       r8168_mac_ocp_write(tp, 0xF822, 0x6420);
+       r8168_mac_ocp_write(tp, 0xF824, 0x48C2);
+       r8168_mac_ocp_write(tp, 0xF826, 0x8C20);
+       r8168_mac_ocp_write(tp, 0xF828, 0xC516);
+       r8168_mac_ocp_write(tp, 0xF82A, 0x64A4);
+       r8168_mac_ocp_write(tp, 0xF82C, 0x49C0);
+       r8168_mac_ocp_write(tp, 0xF82E, 0xF009);
+       r8168_mac_ocp_write(tp, 0xF830, 0x74A2);
+       r8168_mac_ocp_write(tp, 0xF832, 0x8CA5);
+       r8168_mac_ocp_write(tp, 0xF834, 0x74A0);
+       r8168_mac_ocp_write(tp, 0xF836, 0xC50E);
+       r8168_mac_ocp_write(tp, 0xF838, 0x9CA2);
+       r8168_mac_ocp_write(tp, 0xF83A, 0x1C11);
+       r8168_mac_ocp_write(tp, 0xF83C, 0x9CA0);
+       r8168_mac_ocp_write(tp, 0xF83E, 0xE006);
+       r8168_mac_ocp_write(tp, 0xF840, 0x74F8);
+       r8168_mac_ocp_write(tp, 0xF842, 0x48C4);
+       r8168_mac_ocp_write(tp, 0xF844, 0x8CF8);
+       r8168_mac_ocp_write(tp, 0xF846, 0xC404);
+       r8168_mac_ocp_write(tp, 0xF848, 0xBC00);
+       r8168_mac_ocp_write(tp, 0xF84A, 0xC403);
+       r8168_mac_ocp_write(tp, 0xF84C, 0xBC00);
+       r8168_mac_ocp_write(tp, 0xF84E, 0x0BF2);
+       r8168_mac_ocp_write(tp, 0xF850, 0x0C0A);
+       r8168_mac_ocp_write(tp, 0xF852, 0xE434);
+       r8168_mac_ocp_write(tp, 0xF854, 0xD3C0);
+       r8168_mac_ocp_write(tp, 0xF856, 0x49D9);
+       r8168_mac_ocp_write(tp, 0xF858, 0xF01F);
+       r8168_mac_ocp_write(tp, 0xF85A, 0xC526);
+       r8168_mac_ocp_write(tp, 0xF85C, 0x64A5);
+       r8168_mac_ocp_write(tp, 0xF85E, 0x1400);
+       r8168_mac_ocp_write(tp, 0xF860, 0xF007);
+       r8168_mac_ocp_write(tp, 0xF862, 0x0C01);
+       r8168_mac_ocp_write(tp, 0xF864, 0x8CA5);
+       r8168_mac_ocp_write(tp, 0xF866, 0x1C15);
+       r8168_mac_ocp_write(tp, 0xF868, 0xC51B);
+       r8168_mac_ocp_write(tp, 0xF86A, 0x9CA0);
+       r8168_mac_ocp_write(tp, 0xF86C, 0xE013);
+       r8168_mac_ocp_write(tp, 0xF86E, 0xC519);
+       r8168_mac_ocp_write(tp, 0xF870, 0x74A0);
+       r8168_mac_ocp_write(tp, 0xF872, 0x48C4);
+       r8168_mac_ocp_write(tp, 0xF874, 0x8CA0);
+       r8168_mac_ocp_write(tp, 0xF876, 0xC516);
+       r8168_mac_ocp_write(tp, 0xF878, 0x74A4);
+       r8168_mac_ocp_write(tp, 0xF87A, 0x48C8);
+       r8168_mac_ocp_write(tp, 0xF87C, 0x48CA);
+       r8168_mac_ocp_write(tp, 0xF87E, 0x9CA4);
+       r8168_mac_ocp_write(tp, 0xF880, 0xC512);
+       r8168_mac_ocp_write(tp, 0xF882, 0x1B00);
+       r8168_mac_ocp_write(tp, 0xF884, 0x9BA0);
+       r8168_mac_ocp_write(tp, 0xF886, 0x1B1C);
+       r8168_mac_ocp_write(tp, 0xF888, 0x483F);
+       r8168_mac_ocp_write(tp, 0xF88A, 0x9BA2);
+       r8168_mac_ocp_write(tp, 0xF88C, 0x1B04);
+       r8168_mac_ocp_write(tp, 0xF88E, 0xC508);
+       r8168_mac_ocp_write(tp, 0xF890, 0x9BA0);
+       r8168_mac_ocp_write(tp, 0xF892, 0xC505);
+       r8168_mac_ocp_write(tp, 0xF894, 0xBD00);
+       r8168_mac_ocp_write(tp, 0xF896, 0xC502);
+       r8168_mac_ocp_write(tp, 0xF898, 0xBD00);
+       r8168_mac_ocp_write(tp, 0xF89A, 0x0300);
+       r8168_mac_ocp_write(tp, 0xF89C, 0x051E);
+       r8168_mac_ocp_write(tp, 0xF89E, 0xE434);
+       r8168_mac_ocp_write(tp, 0xF8A0, 0xE018);
+       r8168_mac_ocp_write(tp, 0xF8A2, 0xE092);
+       r8168_mac_ocp_write(tp, 0xF8A4, 0xDE20);
+       r8168_mac_ocp_write(tp, 0xF8A6, 0xD3C0);
+       r8168_mac_ocp_write(tp, 0xF8A8, 0xC50F);
+       r8168_mac_ocp_write(tp, 0xF8AA, 0x76A4);
+       r8168_mac_ocp_write(tp, 0xF8AC, 0x49E3);
+       r8168_mac_ocp_write(tp, 0xF8AE, 0xF007);
+       r8168_mac_ocp_write(tp, 0xF8B0, 0x49C0);
+       r8168_mac_ocp_write(tp, 0xF8B2, 0xF103);
+       r8168_mac_ocp_write(tp, 0xF8B4, 0xC607);
+       r8168_mac_ocp_write(tp, 0xF8B6, 0xBE00);
+       r8168_mac_ocp_write(tp, 0xF8B8, 0xC606);
+       r8168_mac_ocp_write(tp, 0xF8BA, 0xBE00);
+       r8168_mac_ocp_write(tp, 0xF8BC, 0xC602);
+       r8168_mac_ocp_write(tp, 0xF8BE, 0xBE00);
+       r8168_mac_ocp_write(tp, 0xF8C0, 0x0C4C);
+       r8168_mac_ocp_write(tp, 0xF8C2, 0x0C28);
+       r8168_mac_ocp_write(tp, 0xF8C4, 0x0C2C);
+       r8168_mac_ocp_write(tp, 0xF8C6, 0xDC00);
+       r8168_mac_ocp_write(tp, 0xF8C8, 0xC707);
+       r8168_mac_ocp_write(tp, 0xF8CA, 0x1D00);
+       r8168_mac_ocp_write(tp, 0xF8CC, 0x8DE2);
+       r8168_mac_ocp_write(tp, 0xF8CE, 0x48C1);
+       r8168_mac_ocp_write(tp, 0xF8D0, 0xC502);
+       r8168_mac_ocp_write(tp, 0xF8D2, 0xBD00);
+       r8168_mac_ocp_write(tp, 0xF8D4, 0x00AA);
+       r8168_mac_ocp_write(tp, 0xF8D6, 0xE0C0);
+       r8168_mac_ocp_write(tp, 0xF8D8, 0xC502);
+       r8168_mac_ocp_write(tp, 0xF8DA, 0xBD00);
+       r8168_mac_ocp_write(tp, 0xF8DC, 0x0132);
+
+       r8168_mac_ocp_write(tp, 0xFC26, 0x8000);
+
+       r8168_mac_ocp_write(tp, 0xFC2A, 0x0743);
+       r8168_mac_ocp_write(tp, 0xFC2C, 0x0801);
+       r8168_mac_ocp_write(tp, 0xFC2E, 0x0BE9);
+       r8168_mac_ocp_write(tp, 0xFC30, 0x02FD);
+       r8168_mac_ocp_write(tp, 0xFC32, 0x0C25);
+       r8168_mac_ocp_write(tp, 0xFC34, 0x00A9);
+       r8168_mac_ocp_write(tp, 0xFC36, 0x012D);
+
        rtl_hw_aspm_clkreq_enable(tp, true);
 }
 
index aba6eea..6e07f5e 100644 (file)
@@ -262,7 +262,7 @@ static int sis900_get_mac_addr(struct pci_dev *pci_dev,
        /* check to see if we have sane EEPROM */
        signature = (u16) read_eeprom(ioaddr, EEPROMSignature);
        if (signature == 0xffff || signature == 0x0000) {
-               printk (KERN_WARNING "%s: Error EERPOM read %x\n",
+               printk (KERN_WARNING "%s: Error EEPROM read %x\n",
                        pci_name(pci_dev), signature);
                return 0;
        }
@@ -359,9 +359,9 @@ static int sis635_get_mac_addr(struct pci_dev *pci_dev,
  *
  *     SiS962 or SiS963 model, use EEPROM to store MAC address. And EEPROM
  *     is shared by
- *     LAN and 1394. When access EEPROM, send EEREQ signal to hardware first
+ *     LAN and 1394. When accessing EEPROM, send EEREQ signal to hardware first
  *     and wait for EEGNT. If EEGNT is ON, EEPROM is permitted to be accessed
- *     by LAN, otherwise is not. After MAC address is read from EEPROM, send
+ *     by LAN, otherwise it is not. After MAC address is read from EEPROM, send
  *     EEDONE signal to refuse EEPROM access by LAN.
  *     The EEPROM map of SiS962 or SiS963 is different to SiS900.
  *     The signature field in SiS962 or SiS963 spec is meaningless.
index f320f9a..32a8974 100644 (file)
@@ -2570,7 +2570,7 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
                        ret = PTR_ERR(slave_data->ifphy);
                        dev_err(&pdev->dev,
                                "%d: Error retrieving port phy: %d\n", i, ret);
-                       return ret;
+                       goto err_node_put;
                }
 
                slave_data->slave_node = slave_node;
@@ -2589,7 +2589,7 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
                        if (ret) {
                                if (ret != -EPROBE_DEFER)
                                        dev_err(&pdev->dev, "failed to register fixed-link phy: %d\n", ret);
-                               return ret;
+                               goto err_node_put;
                        }
                        slave_data->phy_node = of_node_get(slave_node);
                } else if (parp) {
@@ -2607,7 +2607,8 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
                        of_node_put(mdio_node);
                        if (!mdio) {
                                dev_err(&pdev->dev, "Missing mdio platform device\n");
-                               return -EINVAL;
+                               ret = -EINVAL;
+                               goto err_node_put;
                        }
                        snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
                                 PHY_ID_FMT, mdio->name, phyid);
@@ -2622,7 +2623,8 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
                if (slave_data->phy_if < 0) {
                        dev_err(&pdev->dev, "Missing or malformed slave[%d] phy-mode property\n",
                                i);
-                       return slave_data->phy_if;
+                       ret = slave_data->phy_if;
+                       goto err_node_put;
                }
 
 no_phy_slave:
@@ -2633,7 +2635,7 @@ no_phy_slave:
                        ret = ti_cm_get_macid(&pdev->dev, i,
                                              slave_data->mac_addr);
                        if (ret)
-                               return ret;
+                               goto err_node_put;
                }
                if (data->dual_emac) {
                        if (of_property_read_u32(slave_node, "dual_emac_res_vlan",
@@ -2648,11 +2650,17 @@ no_phy_slave:
                }
 
                i++;
-               if (i == data->slaves)
-                       break;
+               if (i == data->slaves) {
+                       ret = 0;
+                       goto err_node_put;
+               }
        }
 
        return 0;
+
+err_node_put:
+       of_node_put(slave_node);
+       return ret;
 }
 
 static void cpsw_remove_dt(struct platform_device *pdev)
@@ -2675,8 +2683,10 @@ static void cpsw_remove_dt(struct platform_device *pdev)
                of_node_put(slave_data->phy_node);
 
                i++;
-               if (i == data->slaves)
+               if (i == data->slaves) {
+                       of_node_put(slave_node);
                        break;
+               }
        }
 
        of_platform_depopulate(&pdev->dev);
index b4ab1a5..78f0f2d 100644 (file)
@@ -855,7 +855,6 @@ static int tlan_init(struct net_device *dev)
                       dev->name);
                return -ENOMEM;
        }
-       memset(priv->dma_storage, 0, dma_size);
        priv->rx_list = (struct tlan_list *)
                ALIGN((unsigned long)priv->dma_storage, 8);
        priv->rx_list_dma = ALIGN(priv->dma_storage_dma, 8);
index c5cae8e..060712c 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
 #include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
index 7b9350d..2a6ec53 100644 (file)
@@ -1196,7 +1196,6 @@ static int rr_open(struct net_device *dev)
                goto error;
        }
        rrpriv->rx_ctrl_dma = dma_addr;
-       memset(rrpriv->rx_ctrl, 0, 256*sizeof(struct ring_ctrl));
 
        rrpriv->info = pci_alloc_consistent(pdev, sizeof(struct rr_info),
                                            &dma_addr);
@@ -1205,7 +1204,6 @@ static int rr_open(struct net_device *dev)
                goto error;
        }
        rrpriv->info_dma = dma_addr;
-       memset(rrpriv->info, 0, sizeof(struct rr_info));
        wmb();
 
        spin_lock_irqsave(&rrpriv->lock, flags);
index afdcc56..3544e19 100644 (file)
@@ -836,7 +836,6 @@ int netvsc_recv_callback(struct net_device *net,
 
        if (unlikely(!skb)) {
                ++net_device_ctx->eth_stats.rx_no_memory;
-               rcu_read_unlock();
                return NVSP_STAT_FAIL;
        }
 
index 2d816aa..e36c04c 100644 (file)
@@ -517,7 +517,7 @@ static int sfp_hwmon_read_sensor(struct sfp *sfp, int reg, long *value)
 
 static void sfp_hwmon_to_rx_power(long *value)
 {
-       *value = DIV_ROUND_CLOSEST(*value, 100);
+       *value = DIV_ROUND_CLOSEST(*value, 10);
 }
 
 static void sfp_hwmon_calibrate(struct sfp *sfp, unsigned int slope, int offset,
index 8b4ad10..69e0a2a 100644 (file)
@@ -1292,6 +1292,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x2001, 0x7e16, 3)},    /* D-Link DWM-221 */
        {QMI_FIXED_INTF(0x2001, 0x7e19, 4)},    /* D-Link DWM-221 B1 */
        {QMI_FIXED_INTF(0x2001, 0x7e35, 4)},    /* D-Link DWM-222 */
+       {QMI_FIXED_INTF(0x2001, 0x7e3d, 4)},    /* D-Link DWM-222 A2 */
        {QMI_FIXED_INTF(0x2020, 0x2031, 4)},    /* Olicard 600 */
        {QMI_FIXED_INTF(0x2020, 0x2033, 4)},    /* BroadMobi BM806U */
        {QMI_FIXED_INTF(0x0f3d, 0x68a2, 8)},    /* Sierra Wireless MC7700 */
index 3f48f05..2a1918f 100644 (file)
@@ -3430,7 +3430,6 @@ vmxnet3_probe_device(struct pci_dev *pdev,
                        err = -ENOMEM;
                        goto err_ver;
                }
-               memset(adapter->coal_conf, 0, sizeof(*adapter->coal_conf));
                adapter->coal_conf->coalMode = VMXNET3_COALESCE_DISABLED;
                adapter->default_coal_mode = true;
        }
index 54edf89..6e84328 100644 (file)
@@ -165,23 +165,29 @@ static int vrf_ip6_local_out(struct net *net, struct sock *sk,
 static netdev_tx_t vrf_process_v6_outbound(struct sk_buff *skb,
                                           struct net_device *dev)
 {
-       const struct ipv6hdr *iph = ipv6_hdr(skb);
+       const struct ipv6hdr *iph;
        struct net *net = dev_net(skb->dev);
-       struct flowi6 fl6 = {
-               /* needed to match OIF rule */
-               .flowi6_oif = dev->ifindex,
-               .flowi6_iif = LOOPBACK_IFINDEX,
-               .daddr = iph->daddr,
-               .saddr = iph->saddr,
-               .flowlabel = ip6_flowinfo(iph),
-               .flowi6_mark = skb->mark,
-               .flowi6_proto = iph->nexthdr,
-               .flowi6_flags = FLOWI_FLAG_SKIP_NH_OIF,
-       };
+       struct flowi6 fl6;
        int ret = NET_XMIT_DROP;
        struct dst_entry *dst;
        struct dst_entry *dst_null = &net->ipv6.ip6_null_entry->dst;
 
+       if (!pskb_may_pull(skb, ETH_HLEN + sizeof(struct ipv6hdr)))
+               goto err;
+
+       iph = ipv6_hdr(skb);
+
+       memset(&fl6, 0, sizeof(fl6));
+       /* needed to match OIF rule */
+       fl6.flowi6_oif = dev->ifindex;
+       fl6.flowi6_iif = LOOPBACK_IFINDEX;
+       fl6.daddr = iph->daddr;
+       fl6.saddr = iph->saddr;
+       fl6.flowlabel = ip6_flowinfo(iph);
+       fl6.flowi6_mark = skb->mark;
+       fl6.flowi6_proto = iph->nexthdr;
+       fl6.flowi6_flags = FLOWI_FLAG_SKIP_NH_OIF;
+
        dst = ip6_route_output(net, NULL, &fl6);
        if (dst == dst_null)
                goto err;
@@ -237,21 +243,27 @@ static int vrf_ip_local_out(struct net *net, struct sock *sk,
 static netdev_tx_t vrf_process_v4_outbound(struct sk_buff *skb,
                                           struct net_device *vrf_dev)
 {
-       struct iphdr *ip4h = ip_hdr(skb);
+       struct iphdr *ip4h;
        int ret = NET_XMIT_DROP;
-       struct flowi4 fl4 = {
-               /* needed to match OIF rule */
-               .flowi4_oif = vrf_dev->ifindex,
-               .flowi4_iif = LOOPBACK_IFINDEX,
-               .flowi4_tos = RT_TOS(ip4h->tos),
-               .flowi4_flags = FLOWI_FLAG_ANYSRC | FLOWI_FLAG_SKIP_NH_OIF,
-               .flowi4_proto = ip4h->protocol,
-               .daddr = ip4h->daddr,
-               .saddr = ip4h->saddr,
-       };
+       struct flowi4 fl4;
        struct net *net = dev_net(vrf_dev);
        struct rtable *rt;
 
+       if (!pskb_may_pull(skb, ETH_HLEN + sizeof(struct iphdr)))
+               goto err;
+
+       ip4h = ip_hdr(skb);
+
+       memset(&fl4, 0, sizeof(fl4));
+       /* needed to match OIF rule */
+       fl4.flowi4_oif = vrf_dev->ifindex;
+       fl4.flowi4_iif = LOOPBACK_IFINDEX;
+       fl4.flowi4_tos = RT_TOS(ip4h->tos);
+       fl4.flowi4_flags = FLOWI_FLAG_ANYSRC | FLOWI_FLAG_SKIP_NH_OIF;
+       fl4.flowi4_proto = ip4h->protocol;
+       fl4.daddr = ip4h->daddr;
+       fl4.saddr = ip4h->saddr;
+
        rt = ip_route_output_flow(net, &fl4, NULL);
        if (IS_ERR(rt))
                goto err;
index e43a566..0606416 100644 (file)
@@ -7541,6 +7541,8 @@ static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
                                                                &vht_nss,
                                                                true);
                        update_bitrate_mask = false;
+               } else {
+                       vht_pfr = 0;
                }
 
                mutex_lock(&ar->conf_mutex);
index d436cc5..2fb4258 100644 (file)
@@ -177,6 +177,7 @@ static const struct wiphy_vendor_command wil_nl80211_vendor_commands[] = {
                .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SECTOR_CFG,
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
                         WIPHY_VENDOR_CMD_NEED_RUNNING,
+               .policy = wil_rf_sector_policy,
                .doit = wil_rf_sector_get_cfg
        },
        {
@@ -184,6 +185,7 @@ static const struct wiphy_vendor_command wil_nl80211_vendor_commands[] = {
                .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SECTOR_CFG,
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
                         WIPHY_VENDOR_CMD_NEED_RUNNING,
+               .policy = wil_rf_sector_policy,
                .doit = wil_rf_sector_set_cfg
        },
        {
@@ -192,6 +194,7 @@ static const struct wiphy_vendor_command wil_nl80211_vendor_commands[] = {
                        QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SELECTED_SECTOR,
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
                         WIPHY_VENDOR_CMD_NEED_RUNNING,
+               .policy = wil_rf_sector_policy,
                .doit = wil_rf_sector_get_selected
        },
        {
@@ -200,6 +203,7 @@ static const struct wiphy_vendor_command wil_nl80211_vendor_commands[] = {
                        QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SELECTED_SECTOR,
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
                         WIPHY_VENDOR_CMD_NEED_RUNNING,
+               .policy = wil_rf_sector_policy,
                .doit = wil_rf_sector_set_selected
        },
 };
index f650089..d07e7c7 100644 (file)
@@ -112,6 +112,7 @@ const struct wiphy_vendor_command brcmf_vendor_cmds[] = {
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
                         WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .policy = VENDOR_CMD_RAW_DATA,
                .doit = brcmf_cfg80211_vndr_cmds_dcmd_handler
        },
 };
index 93526df..1f500cd 100644 (file)
@@ -80,7 +80,9 @@
 #define IWL_22000_QU_B_HR_B_FW_PRE     "iwlwifi-Qu-b0-hr-b0-"
 #define IWL_22000_HR_B_FW_PRE          "iwlwifi-QuQnj-b0-hr-b0-"
 #define IWL_22000_HR_A0_FW_PRE         "iwlwifi-QuQnj-a0-hr-a0-"
+#define IWL_QU_C_HR_B_FW_PRE           "iwlwifi-Qu-c0-hr-b0-"
 #define IWL_QU_B_JF_B_FW_PRE           "iwlwifi-Qu-b0-jf-b0-"
+#define IWL_QU_C_JF_B_FW_PRE           "iwlwifi-Qu-c0-jf-b0-"
 #define IWL_QUZ_A_HR_B_FW_PRE          "iwlwifi-QuZ-a0-hr-b0-"
 #define IWL_QUZ_A_JF_B_FW_PRE          "iwlwifi-QuZ-a0-jf-b0-"
 #define IWL_QNJ_B_JF_B_FW_PRE          "iwlwifi-QuQnj-b0-jf-b0-"
        IWL_QUZ_A_HR_B_FW_PRE __stringify(api) ".ucode"
 #define IWL_QUZ_A_JF_B_MODULE_FIRMWARE(api) \
        IWL_QUZ_A_JF_B_FW_PRE __stringify(api) ".ucode"
+#define IWL_QU_C_HR_B_MODULE_FIRMWARE(api) \
+       IWL_QU_C_HR_B_FW_PRE __stringify(api) ".ucode"
 #define IWL_QU_B_JF_B_MODULE_FIRMWARE(api) \
        IWL_QU_B_JF_B_FW_PRE __stringify(api) ".ucode"
 #define IWL_QNJ_B_JF_B_MODULE_FIRMWARE(api)            \
@@ -256,6 +260,30 @@ const struct iwl_cfg iwl_ax201_cfg_qu_hr = {
        .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
 };
 
+const struct iwl_cfg iwl_ax101_cfg_qu_c0_hr_b0 = {
+       .name = "Intel(R) Wi-Fi 6 AX101",
+       .fw_name_pre = IWL_QU_C_HR_B_FW_PRE,
+       IWL_DEVICE_22500,
+       /*
+        * This device doesn't support receiving BlockAck with a large bitmap
+        * so we need to restrict the size of transmitted aggregation to the
+        * HT size; mac80211 would otherwise pick the HE max (256) by default.
+        */
+       .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+};
+
+const struct iwl_cfg iwl_ax201_cfg_qu_c0_hr_b0 = {
+       .name = "Intel(R) Wi-Fi 6 AX201 160MHz",
+       .fw_name_pre = IWL_QU_C_HR_B_FW_PRE,
+       IWL_DEVICE_22500,
+       /*
+        * This device doesn't support receiving BlockAck with a large bitmap
+        * so we need to restrict the size of transmitted aggregation to the
+        * HT size; mac80211 would otherwise pick the HE max (256) by default.
+        */
+       .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+};
+
 const struct iwl_cfg iwl_ax101_cfg_quz_hr = {
        .name = "Intel(R) Wi-Fi 6 AX101",
        .fw_name_pre = IWL_QUZ_A_HR_B_FW_PRE,
@@ -372,6 +400,30 @@ const struct iwl_cfg iwl9560_2ac_160_cfg_qu_b0_jf_b0 = {
        IWL_DEVICE_22500,
 };
 
+const struct iwl_cfg iwl9461_2ac_cfg_qu_c0_jf_b0 = {
+       .name = "Intel(R) Wireless-AC 9461",
+       .fw_name_pre = IWL_QU_C_JF_B_FW_PRE,
+       IWL_DEVICE_22500,
+};
+
+const struct iwl_cfg iwl9462_2ac_cfg_qu_c0_jf_b0 = {
+       .name = "Intel(R) Wireless-AC 9462",
+       .fw_name_pre = IWL_QU_C_JF_B_FW_PRE,
+       IWL_DEVICE_22500,
+};
+
+const struct iwl_cfg iwl9560_2ac_cfg_qu_c0_jf_b0 = {
+       .name = "Intel(R) Wireless-AC 9560",
+       .fw_name_pre = IWL_QU_C_JF_B_FW_PRE,
+       IWL_DEVICE_22500,
+};
+
+const struct iwl_cfg iwl9560_2ac_160_cfg_qu_c0_jf_b0 = {
+       .name = "Intel(R) Wireless-AC 9560 160MHz",
+       .fw_name_pre = IWL_QU_C_JF_B_FW_PRE,
+       IWL_DEVICE_22500,
+};
+
 const struct iwl_cfg iwl9560_2ac_cfg_qnj_jf_b0 = {
        .name = "Intel(R) Wireless-AC 9560 160MHz",
        .fw_name_pre = IWL_QNJ_B_JF_B_FW_PRE,
@@ -590,6 +642,7 @@ MODULE_FIRMWARE(IWL_22000_HR_A_F0_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL_22000_HR_B_F0_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL_22000_HR_B_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL_22000_HR_A0_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL_QU_C_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL_QU_B_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL_QUZ_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL_QUZ_A_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
index bc267bd..1c1bf1b 100644 (file)
@@ -565,10 +565,13 @@ extern const struct iwl_cfg iwl22000_2ac_cfg_hr;
 extern const struct iwl_cfg iwl22000_2ac_cfg_hr_cdb;
 extern const struct iwl_cfg iwl22000_2ac_cfg_jf;
 extern const struct iwl_cfg iwl_ax101_cfg_qu_hr;
+extern const struct iwl_cfg iwl_ax101_cfg_qu_c0_hr_b0;
 extern const struct iwl_cfg iwl_ax101_cfg_quz_hr;
 extern const struct iwl_cfg iwl22000_2ax_cfg_hr;
 extern const struct iwl_cfg iwl_ax200_cfg_cc;
 extern const struct iwl_cfg iwl_ax201_cfg_qu_hr;
+extern const struct iwl_cfg iwl_ax201_cfg_qu_hr;
+extern const struct iwl_cfg iwl_ax201_cfg_qu_c0_hr_b0;
 extern const struct iwl_cfg iwl_ax201_cfg_quz_hr;
 extern const struct iwl_cfg iwl_ax1650i_cfg_quz_hr;
 extern const struct iwl_cfg iwl_ax1650s_cfg_quz_hr;
@@ -580,6 +583,10 @@ extern const struct iwl_cfg iwl9461_2ac_cfg_qu_b0_jf_b0;
 extern const struct iwl_cfg iwl9462_2ac_cfg_qu_b0_jf_b0;
 extern const struct iwl_cfg iwl9560_2ac_cfg_qu_b0_jf_b0;
 extern const struct iwl_cfg iwl9560_2ac_160_cfg_qu_b0_jf_b0;
+extern const struct iwl_cfg iwl9461_2ac_cfg_qu_c0_jf_b0;
+extern const struct iwl_cfg iwl9462_2ac_cfg_qu_c0_jf_b0;
+extern const struct iwl_cfg iwl9560_2ac_cfg_qu_c0_jf_b0;
+extern const struct iwl_cfg iwl9560_2ac_160_cfg_qu_c0_jf_b0;
 extern const struct iwl_cfg killer1550i_2ac_cfg_qu_b0_jf_b0;
 extern const struct iwl_cfg killer1550s_2ac_cfg_qu_b0_jf_b0;
 extern const struct iwl_cfg iwl22000_2ax_cfg_jf;
index 93da96a..cb4c551 100644 (file)
@@ -328,6 +328,8 @@ enum {
 #define CSR_HW_REV_TYPE_NONE           (0x00001F0)
 #define CSR_HW_REV_TYPE_QNJ            (0x0000360)
 #define CSR_HW_REV_TYPE_QNJ_B0         (0x0000364)
+#define CSR_HW_REV_TYPE_QU_B0          (0x0000334)
+#define CSR_HW_REV_TYPE_QU_C0          (0x0000338)
 #define CSR_HW_REV_TYPE_QUZ            (0x0000354)
 #define CSR_HW_REV_TYPE_HR_CDB         (0x0000340)
 #define CSR_HW_REV_TYPE_SO             (0x0000370)
index ccc83fd..ea2a03d 100644 (file)
@@ -604,6 +604,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
        {IWL_PCI_DEVICE(0x2526, 0x40A4, iwl9460_2ac_cfg)},
        {IWL_PCI_DEVICE(0x2526, 0x4234, iwl9560_2ac_cfg_soc)},
        {IWL_PCI_DEVICE(0x2526, 0x42A4, iwl9462_2ac_cfg_soc)},
+       {IWL_PCI_DEVICE(0x2526, 0x6014, iwl9260_2ac_160_cfg)},
        {IWL_PCI_DEVICE(0x2526, 0x8014, iwl9260_2ac_160_cfg)},
        {IWL_PCI_DEVICE(0x2526, 0x8010, iwl9260_2ac_160_cfg)},
        {IWL_PCI_DEVICE(0x2526, 0xA014, iwl9260_2ac_160_cfg)},
@@ -971,6 +972,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
        {IWL_PCI_DEVICE(0x7A70, 0x0310, iwlax211_2ax_cfg_so_gf_a0)},
        {IWL_PCI_DEVICE(0x7A70, 0x0510, iwlax211_2ax_cfg_so_gf_a0)},
        {IWL_PCI_DEVICE(0x7A70, 0x0A10, iwlax211_2ax_cfg_so_gf_a0)},
+       {IWL_PCI_DEVICE(0x7AF0, 0x0090, iwlax211_2ax_cfg_so_gf_a0)},
        {IWL_PCI_DEVICE(0x7AF0, 0x0310, iwlax211_2ax_cfg_so_gf_a0)},
        {IWL_PCI_DEVICE(0x7AF0, 0x0510, iwlax211_2ax_cfg_so_gf_a0)},
        {IWL_PCI_DEVICE(0x7AF0, 0x0A10, iwlax211_2ax_cfg_so_gf_a0)},
@@ -1037,6 +1039,27 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                }
                iwl_trans->cfg = cfg;
        }
+
+       /*
+        * This is a hack to switch from Qu B0 to Qu C0.  We need to
+        * do this for all cfgs that use Qu B0.  All this code is in
+        * urgent need for a refactor, but for now this is the easiest
+        * thing to do to support Qu C-step.
+        */
+       if (iwl_trans->hw_rev == CSR_HW_REV_TYPE_QU_C0) {
+               if (iwl_trans->cfg == &iwl_ax101_cfg_qu_hr)
+                       iwl_trans->cfg = &iwl_ax101_cfg_qu_c0_hr_b0;
+               else if (iwl_trans->cfg == &iwl_ax201_cfg_qu_hr)
+                       iwl_trans->cfg = &iwl_ax201_cfg_qu_c0_hr_b0;
+               else if (iwl_trans->cfg == &iwl9461_2ac_cfg_qu_b0_jf_b0)
+                       iwl_trans->cfg = &iwl9461_2ac_cfg_qu_c0_jf_b0;
+               else if (iwl_trans->cfg == &iwl9462_2ac_cfg_qu_b0_jf_b0)
+                       iwl_trans->cfg = &iwl9462_2ac_cfg_qu_c0_jf_b0;
+               else if (iwl_trans->cfg == &iwl9560_2ac_cfg_qu_b0_jf_b0)
+                       iwl_trans->cfg = &iwl9560_2ac_cfg_qu_c0_jf_b0;
+               else if (iwl_trans->cfg == &iwl9560_2ac_160_cfg_qu_b0_jf_b0)
+                       iwl_trans->cfg = &iwl9560_2ac_160_cfg_qu_c0_jf_b0;
+       }
 #endif
 
        pci_set_drvdata(pdev, iwl_trans);
index 5e4f3a8..e4332d5 100644 (file)
@@ -53,7 +53,7 @@ int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags)
        pad = round_up(skb->len, 4) + 4 - skb->len;
 
        /* First packet of a A-MSDU burst keeps track of the whole burst
-        * length, need to update lenght of it and the last packet.
+        * length, need to update length of it and the last packet.
         */
        skb_walk_frags(skb, iter) {
                last = iter;
index 67b81c7..7e3a621 100644 (file)
@@ -372,15 +372,10 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
        struct queue_entry *entry = (struct queue_entry *)urb->context;
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 
-       if (!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+       if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
                return;
 
        /*
-        * Report the frame as DMA done
-        */
-       rt2x00lib_dmadone(entry);
-
-       /*
         * Check if the received data is simply too small
         * to be actually valid, or if the urb is signaling
         * a problem.
@@ -389,6 +384,11 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
                set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
 
        /*
+        * Report the frame as DMA done
+        */
+       rt2x00lib_dmadone(entry);
+
+       /*
         * Schedule the delayed work for reading the RX status
         * from the device.
         */
index 5cf0b32..e1bd344 100644 (file)
@@ -163,6 +163,7 @@ static const struct wiphy_vendor_command wlcore_vendor_commands[] = {
                .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
                         WIPHY_VENDOR_CMD_NEED_RUNNING,
                .doit = wlcore_vendor_cmd_smart_config_start,
+               .policy = wlcore_vendor_attr_policy,
        },
        {
                .info = {
@@ -172,6 +173,7 @@ static const struct wiphy_vendor_command wlcore_vendor_commands[] = {
                .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
                         WIPHY_VENDOR_CMD_NEED_RUNNING,
                .doit = wlcore_vendor_cmd_smart_config_stop,
+               .policy = wlcore_vendor_attr_policy,
        },
        {
                .info = {
@@ -181,6 +183,7 @@ static const struct wiphy_vendor_command wlcore_vendor_commands[] = {
                .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
                         WIPHY_VENDOR_CMD_NEED_RUNNING,
                .doit = wlcore_vendor_cmd_smart_config_set_group_key,
+               .policy = wlcore_vendor_attr_policy,
        },
 };
 
index c99eed8..df16c75 100644 (file)
@@ -13,6 +13,17 @@ menuconfig NTB
 
 if NTB
 
+config NTB_MSI
+       bool "MSI Interrupt Support"
+       depends on PCI_MSI
+       help
+        Support using MSI interrupt forwarding instead of (or in addition to)
+        hardware doorbells. MSI interrupts typically offer lower latency
+        than doorbells and more MSI interrupts can be made available to
+        clients. However this requires an extra memory window and support
+        in the hardware driver for creating the MSI interrupts.
+
+        If unsure, say N.
 source "drivers/ntb/hw/Kconfig"
 
 source "drivers/ntb/test/Kconfig"
index 5c64438..3a6fa18 100644 (file)
@@ -1,3 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_NTB) += ntb.o hw/ test/
 obj-$(CONFIG_NTB_TRANSPORT) += ntb_transport.o
+
+ntb-y                  := core.o
+ntb-$(CONFIG_NTB_MSI)  += msi.o
similarity index 100%
rename from drivers/ntb/ntb.c
rename to drivers/ntb/core.c
index efb214f..2859cc9 100644 (file)
@@ -160,8 +160,8 @@ static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
                }
 
                /* set and verify setting the limit */
-               write64(limit, mmio + limit_reg);
-               reg_val = read64(mmio + limit_reg);
+               write64(limit, peer_mmio + limit_reg);
+               reg_val = read64(peer_mmio + limit_reg);
                if (reg_val != limit) {
                        write64(base_addr, mmio + limit_reg);
                        write64(0, peer_mmio + xlat_reg);
@@ -183,8 +183,8 @@ static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
                }
 
                /* set and verify setting the limit */
-               writel(limit, mmio + limit_reg);
-               reg_val = readl(mmio + limit_reg);
+               writel(limit, peer_mmio + limit_reg);
+               reg_val = readl(peer_mmio + limit_reg);
                if (reg_val != limit) {
                        writel(base_addr, mmio + limit_reg);
                        writel(0, peer_mmio + xlat_reg);
@@ -333,7 +333,7 @@ static u64 amd_ntb_db_vector_mask(struct ntb_dev *ntb, int db_vector)
        if (db_vector < 0 || db_vector > ndev->db_count)
                return 0;
 
-       return ntb_ndev(ntb)->db_valid_mask & (1 << db_vector);
+       return ntb_ndev(ntb)->db_valid_mask & (1ULL << db_vector);
 }
 
 static u64 amd_ntb_db_read(struct ntb_dev *ntb)
index f475b56..c339716 100644 (file)
@@ -532,9 +532,9 @@ static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
        return 0;
 }
 
-int intel_ntb3_peer_db_addr(struct ntb_dev *ntb, phys_addr_t *db_addr,
-                               resource_size_t *db_size,
-                               u64 *db_data, int db_bit)
+static int intel_ntb3_peer_db_addr(struct ntb_dev *ntb, phys_addr_t *db_addr,
+                                  resource_size_t *db_size,
+                                  u64 *db_data, int db_bit)
 {
        phys_addr_t db_addr_base;
        struct intel_ntb_dev *ndev = ntb_ndev(ntb);
index db49677..f495945 100644 (file)
@@ -86,7 +86,8 @@ struct switchtec_ntb {
        bool link_is_up;
        enum ntb_speed link_speed;
        enum ntb_width link_width;
-       struct work_struct link_reinit_work;
+       struct work_struct check_link_status_work;
+       bool link_force_down;
 };
 
 static struct switchtec_ntb *ntb_sndev(struct ntb_dev *ntb)
@@ -485,33 +486,11 @@ enum switchtec_msg {
 
 static int switchtec_ntb_reinit_peer(struct switchtec_ntb *sndev);
 
-static void link_reinit_work(struct work_struct *work)
-{
-       struct switchtec_ntb *sndev;
-
-       sndev = container_of(work, struct switchtec_ntb, link_reinit_work);
-
-       switchtec_ntb_reinit_peer(sndev);
-}
-
-static void switchtec_ntb_check_link(struct switchtec_ntb *sndev,
-                                    enum switchtec_msg msg)
+static void switchtec_ntb_link_status_update(struct switchtec_ntb *sndev)
 {
        int link_sta;
        int old = sndev->link_is_up;
 
-       if (msg == MSG_LINK_FORCE_DOWN) {
-               schedule_work(&sndev->link_reinit_work);
-
-               if (sndev->link_is_up) {
-                       sndev->link_is_up = 0;
-                       ntb_link_event(&sndev->ntb);
-                       dev_info(&sndev->stdev->dev, "ntb link forced down\n");
-               }
-
-               return;
-       }
-
        link_sta = sndev->self_shared->link_sta;
        if (link_sta) {
                u64 peer = ioread64(&sndev->peer_shared->magic);
@@ -536,6 +515,38 @@ static void switchtec_ntb_check_link(struct switchtec_ntb *sndev,
        }
 }
 
+static void check_link_status_work(struct work_struct *work)
+{
+       struct switchtec_ntb *sndev;
+
+       sndev = container_of(work, struct switchtec_ntb,
+                            check_link_status_work);
+
+       if (sndev->link_force_down) {
+               sndev->link_force_down = false;
+               switchtec_ntb_reinit_peer(sndev);
+
+               if (sndev->link_is_up) {
+                       sndev->link_is_up = 0;
+                       ntb_link_event(&sndev->ntb);
+                       dev_info(&sndev->stdev->dev, "ntb link forced down\n");
+               }
+
+               return;
+       }
+
+       switchtec_ntb_link_status_update(sndev);
+}
+
+static void switchtec_ntb_check_link(struct switchtec_ntb *sndev,
+                                     enum switchtec_msg msg)
+{
+       if (msg == MSG_LINK_FORCE_DOWN)
+               sndev->link_force_down = true;
+
+       schedule_work(&sndev->check_link_status_work);
+}
+
 static void switchtec_ntb_link_notification(struct switchtec_dev *stdev)
 {
        struct switchtec_ntb *sndev = stdev->sndev;
@@ -568,7 +579,7 @@ static int switchtec_ntb_link_enable(struct ntb_dev *ntb,
        sndev->self_shared->link_sta = 1;
        switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP);
 
-       switchtec_ntb_check_link(sndev, MSG_CHECK_LINK);
+       switchtec_ntb_link_status_update(sndev);
 
        return 0;
 }
@@ -582,7 +593,7 @@ static int switchtec_ntb_link_disable(struct ntb_dev *ntb)
        sndev->self_shared->link_sta = 0;
        switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_DOWN);
 
-       switchtec_ntb_check_link(sndev, MSG_CHECK_LINK);
+       switchtec_ntb_link_status_update(sndev);
 
        return 0;
 }
@@ -835,7 +846,8 @@ static int switchtec_ntb_init_sndev(struct switchtec_ntb *sndev)
        sndev->ntb.topo = NTB_TOPO_SWITCH;
        sndev->ntb.ops = &switchtec_ntb_ops;
 
-       INIT_WORK(&sndev->link_reinit_work, link_reinit_work);
+       INIT_WORK(&sndev->check_link_status_work, check_link_status_work);
+       sndev->link_force_down = false;
 
        sndev->self_partition = sndev->stdev->partition;
 
@@ -872,7 +884,7 @@ static int switchtec_ntb_init_sndev(struct switchtec_ntb *sndev)
                }
 
                sndev->peer_partition = ffs(tpart_vec) - 1;
-               if (!(part_map & (1 << sndev->peer_partition))) {
+               if (!(part_map & (1ULL << sndev->peer_partition))) {
                        dev_err(&sndev->stdev->dev,
                                "ntb target partition is not NT partition\n");
                        return -ENODEV;
@@ -1448,10 +1460,16 @@ static void switchtec_ntb_deinit_db_msg_irq(struct switchtec_ntb *sndev)
 
 static int switchtec_ntb_reinit_peer(struct switchtec_ntb *sndev)
 {
-       dev_info(&sndev->stdev->dev, "peer reinitialized\n");
-       switchtec_ntb_deinit_shared_mw(sndev);
-       switchtec_ntb_init_mw(sndev);
-       return switchtec_ntb_init_shared_mw(sndev);
+       int rc;
+
+       if (crosslink_is_enabled(sndev))
+               return 0;
+
+       dev_info(&sndev->stdev->dev, "reinitialize shared memory window\n");
+       rc = config_rsvd_lut_win(sndev, sndev->mmio_peer_ctrl, 0,
+                                sndev->self_partition,
+                                sndev->self_shared_dma);
+       return rc;
 }
 
 static int switchtec_ntb_add(struct device *dev,
diff --git a/drivers/ntb/msi.c b/drivers/ntb/msi.c
new file mode 100644 (file)
index 0000000..9dddf13
--- /dev/null
@@ -0,0 +1,415 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/ntb.h>
+#include <linux/msi.h>
+#include <linux/pci.h>
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION("0.1");
+MODULE_AUTHOR("Logan Gunthorpe <logang@deltatee.com>");
+MODULE_DESCRIPTION("NTB MSI Interrupt Library");
+
+struct ntb_msi {
+       u64 base_addr;
+       u64 end_addr;
+
+       void (*desc_changed)(void *ctx);
+
+       u32 __iomem *peer_mws[];
+};
+
+/**
+ * ntb_msi_init() - Initialize the MSI context
+ * @ntb:       NTB device context
+ *
+ * This function must be called before any other ntb_msi function.
+ * It initializes the context for MSI operations and maps
+ * the peer memory windows.
+ *
+ * This function reserves the last N outbound memory windows (where N
+ * is the number of peers).
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+int ntb_msi_init(struct ntb_dev *ntb,
+                void (*desc_changed)(void *ctx))
+{
+       phys_addr_t mw_phys_addr;
+       resource_size_t mw_size;
+       size_t struct_size;
+       int peer_widx;
+       int peers;
+       int ret;
+       int i;
+
+       peers = ntb_peer_port_count(ntb);
+       if (peers <= 0)
+               return -EINVAL;
+
+       struct_size = sizeof(*ntb->msi) + sizeof(*ntb->msi->peer_mws) * peers;
+
+       ntb->msi = devm_kzalloc(&ntb->dev, struct_size, GFP_KERNEL);
+       if (!ntb->msi)
+               return -ENOMEM;
+
+       ntb->msi->desc_changed = desc_changed;
+
+       for (i = 0; i < peers; i++) {
+               peer_widx = ntb_peer_mw_count(ntb) - 1 - i;
+
+               ret = ntb_peer_mw_get_addr(ntb, peer_widx, &mw_phys_addr,
+                                          &mw_size);
+               if (ret)
+                       goto unroll;
+
+               ntb->msi->peer_mws[i] = devm_ioremap(&ntb->dev, mw_phys_addr,
+                                                    mw_size);
+               if (!ntb->msi->peer_mws[i]) {
+                       ret = -EFAULT;
+                       goto unroll;
+               }
+       }
+
+       return 0;
+
+unroll:
+       for (i = 0; i < peers; i++)
+               if (ntb->msi->peer_mws[i])
+                       devm_iounmap(&ntb->dev, ntb->msi->peer_mws[i]);
+
+       devm_kfree(&ntb->dev, ntb->msi);
+       ntb->msi = NULL;
+       return ret;
+}
+EXPORT_SYMBOL(ntb_msi_init);
+
+/**
+ * ntb_msi_setup_mws() - Initialize the MSI inbound memory windows
+ * @ntb:       NTB device context
+ *
+ * This function sets up the required inbound memory windows. It should be
+ * called from a work function after a link up event.
+ *
+ * Over the entire network, this function will reserves the last N
+ * inbound memory windows for each peer (where N is the number of peers).
+ *
+ * ntb_msi_init() must be called before this function.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+int ntb_msi_setup_mws(struct ntb_dev *ntb)
+{
+       struct msi_desc *desc;
+       u64 addr;
+       int peer, peer_widx;
+       resource_size_t addr_align, size_align, size_max;
+       resource_size_t mw_size = SZ_32K;
+       resource_size_t mw_min_size = mw_size;
+       int i;
+       int ret;
+
+       if (!ntb->msi)
+               return -EINVAL;
+
+       desc = first_msi_entry(&ntb->pdev->dev);
+       addr = desc->msg.address_lo + ((uint64_t)desc->msg.address_hi << 32);
+
+       for (peer = 0; peer < ntb_peer_port_count(ntb); peer++) {
+               peer_widx = ntb_peer_highest_mw_idx(ntb, peer);
+               if (peer_widx < 0)
+                       return peer_widx;
+
+               ret = ntb_mw_get_align(ntb, peer, peer_widx, &addr_align,
+                                      NULL, NULL);
+               if (ret)
+                       return ret;
+
+               addr &= ~(addr_align - 1);
+       }
+
+       for (peer = 0; peer < ntb_peer_port_count(ntb); peer++) {
+               peer_widx = ntb_peer_highest_mw_idx(ntb, peer);
+               if (peer_widx < 0) {
+                       ret = peer_widx;
+                       goto error_out;
+               }
+
+               ret = ntb_mw_get_align(ntb, peer, peer_widx, NULL,
+                                      &size_align, &size_max);
+               if (ret)
+                       goto error_out;
+
+               mw_size = round_up(mw_size, size_align);
+               mw_size = max(mw_size, size_max);
+               if (mw_size < mw_min_size)
+                       mw_min_size = mw_size;
+
+               ret = ntb_mw_set_trans(ntb, peer, peer_widx,
+                                      addr, mw_size);
+               if (ret)
+                       goto error_out;
+       }
+
+       ntb->msi->base_addr = addr;
+       ntb->msi->end_addr = addr + mw_min_size;
+
+       return 0;
+
+error_out:
+       for (i = 0; i < peer; i++) {
+               peer_widx = ntb_peer_highest_mw_idx(ntb, peer);
+               if (peer_widx < 0)
+                       continue;
+
+               ntb_mw_clear_trans(ntb, i, peer_widx);
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(ntb_msi_setup_mws);
+
+/**
+ * ntb_msi_clear_mws() - Clear all inbound memory windows
+ * @ntb:       NTB device context
+ *
+ * This function tears down the resources used by ntb_msi_setup_mws().
+ */
+void ntb_msi_clear_mws(struct ntb_dev *ntb)
+{
+       int peer;
+       int peer_widx;
+
+       for (peer = 0; peer < ntb_peer_port_count(ntb); peer++) {
+               peer_widx = ntb_peer_highest_mw_idx(ntb, peer);
+               if (peer_widx < 0)
+                       continue;
+
+               ntb_mw_clear_trans(ntb, peer, peer_widx);
+       }
+}
+EXPORT_SYMBOL(ntb_msi_clear_mws);
+
+struct ntb_msi_devres {
+       struct ntb_dev *ntb;
+       struct msi_desc *entry;
+       struct ntb_msi_desc *msi_desc;
+};
+
+static int ntb_msi_set_desc(struct ntb_dev *ntb, struct msi_desc *entry,
+                           struct ntb_msi_desc *msi_desc)
+{
+       u64 addr;
+
+       addr = entry->msg.address_lo +
+               ((uint64_t)entry->msg.address_hi << 32);
+
+       if (addr < ntb->msi->base_addr || addr >= ntb->msi->end_addr) {
+               dev_warn_once(&ntb->dev,
+                             "IRQ %d: MSI Address not within the memory window (%llx, [%llx %llx])\n",
+                             entry->irq, addr, ntb->msi->base_addr,
+                             ntb->msi->end_addr);
+               return -EFAULT;
+       }
+
+       msi_desc->addr_offset = addr - ntb->msi->base_addr;
+       msi_desc->data = entry->msg.data;
+
+       return 0;
+}
+
+static void ntb_msi_write_msg(struct msi_desc *entry, void *data)
+{
+       struct ntb_msi_devres *dr = data;
+
+       WARN_ON(ntb_msi_set_desc(dr->ntb, entry, dr->msi_desc));
+
+       if (dr->ntb->msi->desc_changed)
+               dr->ntb->msi->desc_changed(dr->ntb->ctx);
+}
+
+static void ntbm_msi_callback_release(struct device *dev, void *res)
+{
+       struct ntb_msi_devres *dr = res;
+
+       dr->entry->write_msi_msg = NULL;
+       dr->entry->write_msi_msg_data = NULL;
+}
+
+static int ntbm_msi_setup_callback(struct ntb_dev *ntb, struct msi_desc *entry,
+                                  struct ntb_msi_desc *msi_desc)
+{
+       struct ntb_msi_devres *dr;
+
+       dr = devres_alloc(ntbm_msi_callback_release,
+                         sizeof(struct ntb_msi_devres), GFP_KERNEL);
+       if (!dr)
+               return -ENOMEM;
+
+       dr->ntb = ntb;
+       dr->entry = entry;
+       dr->msi_desc = msi_desc;
+
+       devres_add(&ntb->dev, dr);
+
+       dr->entry->write_msi_msg = ntb_msi_write_msg;
+       dr->entry->write_msi_msg_data = dr;
+
+       return 0;
+}
+
+/**
+ * ntbm_msi_request_threaded_irq() - allocate an MSI interrupt
+ * @ntb:       NTB device context
+ * @handler:   Function to be called when the IRQ occurs
+ * @thread_fn:  Function to be called in a threaded interrupt context. NULL
+ *              for clients which handle everything in @handler
+ * @devname:    An ascii name for the claiming device, dev_name(dev) if NULL
+ * @dev_id:     A cookie passed back to the handler function
+ *
+ * This function assigns an interrupt handler to an unused
+ * MSI interrupt and returns the descriptor used to trigger
+ * it. The descriptor can then be sent to a peer to trigger
+ * the interrupt.
+ *
+ * The interrupt resource is managed with devres so it will
+ * be automatically freed when the NTB device is torn down.
+ *
+ * If an IRQ allocated with this function needs to be freed
+ * separately, ntbm_free_irq() must be used.
+ *
+ * Return: IRQ number assigned on success, otherwise a negative error number.
+ */
+int ntbm_msi_request_threaded_irq(struct ntb_dev *ntb, irq_handler_t handler,
+                                 irq_handler_t thread_fn,
+                                 const char *name, void *dev_id,
+                                 struct ntb_msi_desc *msi_desc)
+{
+       struct msi_desc *entry;
+       struct irq_desc *desc;
+       int ret;
+
+       if (!ntb->msi)
+               return -EINVAL;
+
+       for_each_pci_msi_entry(entry, ntb->pdev) {
+               desc = irq_to_desc(entry->irq);
+               if (desc->action)
+                       continue;
+
+               ret = devm_request_threaded_irq(&ntb->dev, entry->irq, handler,
+                                               thread_fn, 0, name, dev_id);
+               if (ret)
+                       continue;
+
+               if (ntb_msi_set_desc(ntb, entry, msi_desc)) {
+                       devm_free_irq(&ntb->dev, entry->irq, dev_id);
+                       continue;
+               }
+
+               ret = ntbm_msi_setup_callback(ntb, entry, msi_desc);
+               if (ret) {
+                       devm_free_irq(&ntb->dev, entry->irq, dev_id);
+                       return ret;
+               }
+
+
+               return entry->irq;
+       }
+
+       return -ENODEV;
+}
+EXPORT_SYMBOL(ntbm_msi_request_threaded_irq);
+
+static int ntbm_msi_callback_match(struct device *dev, void *res, void *data)
+{
+       struct ntb_dev *ntb = dev_ntb(dev);
+       struct ntb_msi_devres *dr = res;
+
+       return dr->ntb == ntb && dr->entry == data;
+}
+
+/**
+ * ntbm_msi_free_irq() - free an interrupt
+ * @ntb:       NTB device context
+ * @irq:       Interrupt line to free
+ * @dev_id:    Device identity to free
+ *
+ * This function should be used to manually free IRQs allocated with
+ * ntbm_request_[threaded_]irq().
+ */
+void ntbm_msi_free_irq(struct ntb_dev *ntb, unsigned int irq, void *dev_id)
+{
+       struct msi_desc *entry = irq_get_msi_desc(irq);
+
+       entry->write_msi_msg = NULL;
+       entry->write_msi_msg_data = NULL;
+
+       WARN_ON(devres_destroy(&ntb->dev, ntbm_msi_callback_release,
+                              ntbm_msi_callback_match, entry));
+
+       devm_free_irq(&ntb->dev, irq, dev_id);
+}
+EXPORT_SYMBOL(ntbm_msi_free_irq);
+
+/**
+ * ntb_msi_peer_trigger() - Trigger an interrupt handler on a peer
+ * @ntb:       NTB device context
+ * @peer:      Peer index
+ * @desc:      MSI descriptor data which triggers the interrupt
+ *
+ * This function triggers an interrupt on a peer. It requires
+ * the descriptor structure to have been passed from that peer
+ * by some other means.
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+int ntb_msi_peer_trigger(struct ntb_dev *ntb, int peer,
+                        struct ntb_msi_desc *desc)
+{
+       int idx;
+
+       if (!ntb->msi)
+               return -EINVAL;
+
+       idx = desc->addr_offset / sizeof(*ntb->msi->peer_mws[peer]);
+
+       iowrite32(desc->data, &ntb->msi->peer_mws[peer][idx]);
+
+       return 0;
+}
+EXPORT_SYMBOL(ntb_msi_peer_trigger);
+
+/**
+ * ntb_msi_peer_addr() - Get the DMA address to trigger a peer's MSI interrupt
+ * @ntb:       NTB device context
+ * @peer:      Peer index
+ * @desc:      MSI descriptor data which triggers the interrupt
+ * @msi_addr:   Physical address to trigger the interrupt
+ *
+ * This function allows using DMA engines to trigger an interrupt
+ * (for example, trigger an interrupt to process the data after
+ * sending it). To trigger the interrupt, write @desc.data to the address
+ * returned in @msi_addr
+ *
+ * Return: Zero on success, otherwise a negative error number.
+ */
+int ntb_msi_peer_addr(struct ntb_dev *ntb, int peer,
+                     struct ntb_msi_desc *desc,
+                     phys_addr_t *msi_addr)
+{
+       int peer_widx = ntb_peer_mw_count(ntb) - 1 - peer;
+       phys_addr_t mw_phys_addr;
+       int ret;
+
+       ret = ntb_peer_mw_get_addr(ntb, peer_widx, &mw_phys_addr, NULL);
+       if (ret)
+               return ret;
+
+       if (msi_addr)
+               *msi_addr = mw_phys_addr + desc->addr_offset;
+
+       return 0;
+}
+EXPORT_SYMBOL(ntb_msi_peer_addr);
index d4f39ba..40c90ca 100644 (file)
@@ -93,6 +93,12 @@ static bool use_dma;
 module_param(use_dma, bool, 0644);
 MODULE_PARM_DESC(use_dma, "Use DMA engine to perform large data copy");
 
+static bool use_msi;
+#ifdef CONFIG_NTB_MSI
+module_param(use_msi, bool, 0644);
+MODULE_PARM_DESC(use_msi, "Use MSI interrupts instead of doorbells");
+#endif
+
 static struct dentry *nt_debugfs_dir;
 
 /* Only two-ports NTB devices are supported */
@@ -188,6 +194,11 @@ struct ntb_transport_qp {
        u64 tx_err_no_buf;
        u64 tx_memcpy;
        u64 tx_async;
+
+       bool use_msi;
+       int msi_irq;
+       struct ntb_msi_desc msi_desc;
+       struct ntb_msi_desc peer_msi_desc;
 };
 
 struct ntb_transport_mw {
@@ -221,6 +232,10 @@ struct ntb_transport_ctx {
        u64 qp_bitmap;
        u64 qp_bitmap_free;
 
+       bool use_msi;
+       unsigned int msi_spad_offset;
+       u64 msi_db_mask;
+
        bool link_is_up;
        struct delayed_work link_work;
        struct work_struct link_cleanup;
@@ -667,6 +682,114 @@ static int ntb_transport_setup_qp_mw(struct ntb_transport_ctx *nt,
        return 0;
 }
 
+static irqreturn_t ntb_transport_isr(int irq, void *dev)
+{
+       struct ntb_transport_qp *qp = dev;
+
+       tasklet_schedule(&qp->rxc_db_work);
+
+       return IRQ_HANDLED;
+}
+
+static void ntb_transport_setup_qp_peer_msi(struct ntb_transport_ctx *nt,
+                                           unsigned int qp_num)
+{
+       struct ntb_transport_qp *qp = &nt->qp_vec[qp_num];
+       int spad = qp_num * 2 + nt->msi_spad_offset;
+
+       if (!nt->use_msi)
+               return;
+
+       if (spad >= ntb_spad_count(nt->ndev))
+               return;
+
+       qp->peer_msi_desc.addr_offset =
+               ntb_peer_spad_read(qp->ndev, PIDX, spad);
+       qp->peer_msi_desc.data =
+               ntb_peer_spad_read(qp->ndev, PIDX, spad + 1);
+
+       dev_dbg(&qp->ndev->pdev->dev, "QP%d Peer MSI addr=%x data=%x\n",
+               qp_num, qp->peer_msi_desc.addr_offset, qp->peer_msi_desc.data);
+
+       if (qp->peer_msi_desc.addr_offset) {
+               qp->use_msi = true;
+               dev_info(&qp->ndev->pdev->dev,
+                        "Using MSI interrupts for QP%d\n", qp_num);
+       }
+}
+
+static void ntb_transport_setup_qp_msi(struct ntb_transport_ctx *nt,
+                                      unsigned int qp_num)
+{
+       struct ntb_transport_qp *qp = &nt->qp_vec[qp_num];
+       int spad = qp_num * 2 + nt->msi_spad_offset;
+       int rc;
+
+       if (!nt->use_msi)
+               return;
+
+       if (spad >= ntb_spad_count(nt->ndev)) {
+               dev_warn_once(&qp->ndev->pdev->dev,
+                             "Not enough SPADS to use MSI interrupts\n");
+               return;
+       }
+
+       ntb_spad_write(qp->ndev, spad, 0);
+       ntb_spad_write(qp->ndev, spad + 1, 0);
+
+       if (!qp->msi_irq) {
+               qp->msi_irq = ntbm_msi_request_irq(qp->ndev, ntb_transport_isr,
+                                                  KBUILD_MODNAME, qp,
+                                                  &qp->msi_desc);
+               if (qp->msi_irq < 0) {
+                       dev_warn(&qp->ndev->pdev->dev,
+                                "Unable to allocate MSI interrupt for qp%d\n",
+                                qp_num);
+                       return;
+               }
+       }
+
+       rc = ntb_spad_write(qp->ndev, spad, qp->msi_desc.addr_offset);
+       if (rc)
+               goto err_free_interrupt;
+
+       rc = ntb_spad_write(qp->ndev, spad + 1, qp->msi_desc.data);
+       if (rc)
+               goto err_free_interrupt;
+
+       dev_dbg(&qp->ndev->pdev->dev, "QP%d MSI %d addr=%x data=%x\n",
+               qp_num, qp->msi_irq, qp->msi_desc.addr_offset,
+               qp->msi_desc.data);
+
+       return;
+
+err_free_interrupt:
+       devm_free_irq(&nt->ndev->dev, qp->msi_irq, qp);
+}
+
+static void ntb_transport_msi_peer_desc_changed(struct ntb_transport_ctx *nt)
+{
+       int i;
+
+       dev_dbg(&nt->ndev->pdev->dev, "Peer MSI descriptors changed");
+
+       for (i = 0; i < nt->qp_count; i++)
+               ntb_transport_setup_qp_peer_msi(nt, i);
+}
+
+static void ntb_transport_msi_desc_changed(void *data)
+{
+       struct ntb_transport_ctx *nt = data;
+       int i;
+
+       dev_dbg(&nt->ndev->pdev->dev, "MSI descriptors changed");
+
+       for (i = 0; i < nt->qp_count; i++)
+               ntb_transport_setup_qp_msi(nt, i);
+
+       ntb_peer_db_set(nt->ndev, nt->msi_db_mask);
+}
+
 static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw)
 {
        struct ntb_transport_mw *mw = &nt->mw_vec[num_mw];
@@ -905,6 +1028,20 @@ static void ntb_transport_link_work(struct work_struct *work)
        int rc = 0, i, spad;
 
        /* send the local info, in the opposite order of the way we read it */
+
+       if (nt->use_msi) {
+               rc = ntb_msi_setup_mws(ndev);
+               if (rc) {
+                       dev_warn(&pdev->dev,
+                                "Failed to register MSI memory window: %d\n",
+                                rc);
+                       nt->use_msi = false;
+               }
+       }
+
+       for (i = 0; i < nt->qp_count; i++)
+               ntb_transport_setup_qp_msi(nt, i);
+
        for (i = 0; i < nt->mw_count; i++) {
                size = nt->mw_vec[i].phys_size;
 
@@ -962,6 +1099,7 @@ static void ntb_transport_link_work(struct work_struct *work)
                struct ntb_transport_qp *qp = &nt->qp_vec[i];
 
                ntb_transport_setup_qp_mw(nt, i);
+               ntb_transport_setup_qp_peer_msi(nt, i);
 
                if (qp->client_ready)
                        schedule_delayed_work(&qp->link_work, 0);
@@ -1135,6 +1273,19 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
                return -ENOMEM;
 
        nt->ndev = ndev;
+
+       /*
+        * If we are using MSI, and have at least one extra memory window,
+        * we will reserve the last MW for the MSI window.
+        */
+       if (use_msi && mw_count > 1) {
+               rc = ntb_msi_init(ndev, ntb_transport_msi_desc_changed);
+               if (!rc) {
+                       mw_count -= 1;
+                       nt->use_msi = true;
+               }
+       }
+
        spad_count = ntb_spad_count(ndev);
 
        /* Limit the MW's based on the availability of scratchpads */
@@ -1148,6 +1299,8 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
        max_mw_count_for_spads = (spad_count - MW0_SZ_HIGH) / 2;
        nt->mw_count = min(mw_count, max_mw_count_for_spads);
 
+       nt->msi_spad_offset = nt->mw_count * 2 + MW0_SZ_HIGH;
+
        nt->mw_vec = kcalloc_node(mw_count, sizeof(*nt->mw_vec),
                                  GFP_KERNEL, node);
        if (!nt->mw_vec) {
@@ -1178,6 +1331,12 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
        qp_bitmap = ntb_db_valid_mask(ndev);
 
        qp_count = ilog2(qp_bitmap);
+       if (nt->use_msi) {
+               qp_count -= 1;
+               nt->msi_db_mask = 1 << qp_count;
+               ntb_db_clear_mask(ndev, nt->msi_db_mask);
+       }
+
        if (max_num_clients && max_num_clients < qp_count)
                qp_count = max_num_clients;
        else if (nt->mw_count < qp_count)
@@ -1601,7 +1760,10 @@ static void ntb_tx_copy_callback(void *data,
 
        iowrite32(entry->flags | DESC_DONE_FLAG, &hdr->flags);
 
-       ntb_peer_db_set(qp->ndev, BIT_ULL(qp->qp_num));
+       if (qp->use_msi)
+               ntb_msi_peer_trigger(qp->ndev, PIDX, &qp->peer_msi_desc);
+       else
+               ntb_peer_db_set(qp->ndev, BIT_ULL(qp->qp_num));
 
        /* The entry length can only be zero if the packet is intended to be a
         * "link down" or similar.  Since no payload is being sent in these
@@ -1869,6 +2031,7 @@ ntb_transport_create_queue(void *data, struct device *client_dev,
                qp->rx_dma_chan = NULL;
        }
 
+       qp->tx_mw_dma_addr = 0;
        if (qp->tx_dma_chan) {
                qp->tx_mw_dma_addr =
                        dma_map_resource(qp->tx_dma_chan->device->dev,
@@ -2268,6 +2431,11 @@ static void ntb_transport_doorbell_callback(void *data, int vector)
        u64 db_bits;
        unsigned int qp_num;
 
+       if (ntb_db_read(nt->ndev) & nt->msi_db_mask) {
+               ntb_transport_msi_peer_desc_changed(nt);
+               ntb_db_clear(nt->ndev, nt->msi_db_mask);
+       }
+
        db_bits = (nt->qp_bitmap & ~nt->qp_bitmap_free &
                   ntb_db_vector_mask(nt->ndev, vector));
 
index a8db00a..516b991 100644 (file)
@@ -26,3 +26,12 @@ config NTB_PERF
         to and from the window without additional software interaction.
 
         If unsure, say N.
+
+config NTB_MSI_TEST
+       tristate "NTB MSI Test Client"
+       depends on NTB_MSI
+       help
+         This tool demonstrates the use of the NTB MSI library to
+         send MSI interrupts between peers.
+
+         If unsure, say N.
index cbfd676..19ed91d 100644 (file)
@@ -2,3 +2,4 @@
 obj-$(CONFIG_NTB_PINGPONG) += ntb_pingpong.o
 obj-$(CONFIG_NTB_TOOL) += ntb_tool.o
 obj-$(CONFIG_NTB_PERF) += ntb_perf.o
+obj-$(CONFIG_NTB_MSI_TEST) += ntb_msi_test.o
diff --git a/drivers/ntb/test/ntb_msi_test.c b/drivers/ntb/test/ntb_msi_test.c
new file mode 100644 (file)
index 0000000..99d826e
--- /dev/null
@@ -0,0 +1,433 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/ntb.h>
+#include <linux/pci.h>
+#include <linux/radix-tree.h>
+#include <linux/workqueue.h>
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION("0.1");
+MODULE_AUTHOR("Logan Gunthorpe <logang@deltatee.com>");
+MODULE_DESCRIPTION("Test for sending MSI interrupts over an NTB memory window");
+
+static int num_irqs = 4;
+module_param(num_irqs, int, 0644);
+MODULE_PARM_DESC(num_irqs, "number of irqs to use");
+
+struct ntb_msit_ctx {
+       struct ntb_dev *ntb;
+       struct dentry *dbgfs_dir;
+       struct work_struct setup_work;
+
+       struct ntb_msit_isr_ctx {
+               int irq_idx;
+               int irq_num;
+               int occurrences;
+               struct ntb_msit_ctx *nm;
+               struct ntb_msi_desc desc;
+       } *isr_ctx;
+
+       struct ntb_msit_peer {
+               struct ntb_msit_ctx *nm;
+               int pidx;
+               int num_irqs;
+               struct completion init_comp;
+               struct ntb_msi_desc *msi_desc;
+       } peers[];
+};
+
+static struct dentry *ntb_msit_dbgfs_topdir;
+
+static irqreturn_t ntb_msit_isr(int irq, void *dev)
+{
+       struct ntb_msit_isr_ctx *isr_ctx = dev;
+       struct ntb_msit_ctx *nm = isr_ctx->nm;
+
+       dev_dbg(&nm->ntb->dev, "Interrupt Occurred: %d",
+               isr_ctx->irq_idx);
+
+       isr_ctx->occurrences++;
+
+       return IRQ_HANDLED;
+}
+
+static void ntb_msit_setup_work(struct work_struct *work)
+{
+       struct ntb_msit_ctx *nm = container_of(work, struct ntb_msit_ctx,
+                                              setup_work);
+       int irq_count = 0;
+       int irq;
+       int ret;
+       uintptr_t i;
+
+       ret = ntb_msi_setup_mws(nm->ntb);
+       if (ret) {
+               dev_err(&nm->ntb->dev, "Unable to setup MSI windows: %d\n",
+                       ret);
+               return;
+       }
+
+       for (i = 0; i < num_irqs; i++) {
+               nm->isr_ctx[i].irq_idx = i;
+               nm->isr_ctx[i].nm = nm;
+
+               if (!nm->isr_ctx[i].irq_num) {
+                       irq = ntbm_msi_request_irq(nm->ntb, ntb_msit_isr,
+                                                  KBUILD_MODNAME,
+                                                  &nm->isr_ctx[i],
+                                                  &nm->isr_ctx[i].desc);
+                       if (irq < 0)
+                               break;
+
+                       nm->isr_ctx[i].irq_num = irq;
+               }
+
+               ret = ntb_spad_write(nm->ntb, 2 * i + 1,
+                                    nm->isr_ctx[i].desc.addr_offset);
+               if (ret)
+                       break;
+
+               ret = ntb_spad_write(nm->ntb, 2 * i + 2,
+                                    nm->isr_ctx[i].desc.data);
+               if (ret)
+                       break;
+
+               irq_count++;
+       }
+
+       ntb_spad_write(nm->ntb, 0, irq_count);
+       ntb_peer_db_set(nm->ntb, BIT(ntb_port_number(nm->ntb)));
+}
+
+static void ntb_msit_desc_changed(void *ctx)
+{
+       struct ntb_msit_ctx *nm = ctx;
+       int i;
+
+       dev_dbg(&nm->ntb->dev, "MSI Descriptors Changed\n");
+
+       for (i = 0; i < num_irqs; i++) {
+               ntb_spad_write(nm->ntb, 2 * i + 1,
+                              nm->isr_ctx[i].desc.addr_offset);
+               ntb_spad_write(nm->ntb, 2 * i + 2,
+                              nm->isr_ctx[i].desc.data);
+       }
+
+       ntb_peer_db_set(nm->ntb, BIT(ntb_port_number(nm->ntb)));
+}
+
+static void ntb_msit_link_event(void *ctx)
+{
+       struct ntb_msit_ctx *nm = ctx;
+
+       if (!ntb_link_is_up(nm->ntb, NULL, NULL))
+               return;
+
+       schedule_work(&nm->setup_work);
+}
+
+static void ntb_msit_copy_peer_desc(struct ntb_msit_ctx *nm, int peer)
+{
+       int i;
+       struct ntb_msi_desc *desc = nm->peers[peer].msi_desc;
+       int irq_count = nm->peers[peer].num_irqs;
+
+       for (i = 0; i < irq_count; i++) {
+               desc[i].addr_offset = ntb_peer_spad_read(nm->ntb, peer,
+                                                        2 * i + 1);
+               desc[i].data = ntb_peer_spad_read(nm->ntb, peer, 2 * i + 2);
+       }
+
+       dev_info(&nm->ntb->dev, "Found %d interrupts on peer %d\n",
+                irq_count, peer);
+
+       complete_all(&nm->peers[peer].init_comp);
+}
+
+static void ntb_msit_db_event(void *ctx, int vec)
+{
+       struct ntb_msit_ctx *nm = ctx;
+       struct ntb_msi_desc *desc;
+       u64 peer_mask = ntb_db_read(nm->ntb);
+       u32 irq_count;
+       int peer;
+
+       ntb_db_clear(nm->ntb, peer_mask);
+
+       for (peer = 0; peer < sizeof(peer_mask) * 8; peer++) {
+               if (!(peer_mask & BIT(peer)))
+                       continue;
+
+               irq_count = ntb_peer_spad_read(nm->ntb, peer, 0);
+               if (irq_count == -1)
+                       continue;
+
+               desc = kcalloc(irq_count, sizeof(*desc), GFP_ATOMIC);
+               if (!desc)
+                       continue;
+
+               kfree(nm->peers[peer].msi_desc);
+               nm->peers[peer].msi_desc = desc;
+               nm->peers[peer].num_irqs = irq_count;
+
+               ntb_msit_copy_peer_desc(nm, peer);
+       }
+}
+
+static const struct ntb_ctx_ops ntb_msit_ops = {
+       .link_event = ntb_msit_link_event,
+       .db_event = ntb_msit_db_event,
+};
+
+static int ntb_msit_dbgfs_trigger(void *data, u64 idx)
+{
+       struct ntb_msit_peer *peer = data;
+
+       if (idx >= peer->num_irqs)
+               return -EINVAL;
+
+       dev_dbg(&peer->nm->ntb->dev, "trigger irq %llu on peer %u\n",
+               idx, peer->pidx);
+
+       return ntb_msi_peer_trigger(peer->nm->ntb, peer->pidx,
+                                   &peer->msi_desc[idx]);
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(ntb_msit_trigger_fops, NULL,
+                        ntb_msit_dbgfs_trigger, "%llu\n");
+
+static int ntb_msit_dbgfs_port_get(void *data, u64 *port)
+{
+       struct ntb_msit_peer *peer = data;
+
+       *port = ntb_peer_port_number(peer->nm->ntb, peer->pidx);
+
+       return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(ntb_msit_port_fops, ntb_msit_dbgfs_port_get,
+                        NULL, "%llu\n");
+
+static int ntb_msit_dbgfs_count_get(void *data, u64 *count)
+{
+       struct ntb_msit_peer *peer = data;
+
+       *count = peer->num_irqs;
+
+       return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(ntb_msit_count_fops, ntb_msit_dbgfs_count_get,
+                        NULL, "%llu\n");
+
+static int ntb_msit_dbgfs_ready_get(void *data, u64 *ready)
+{
+       struct ntb_msit_peer *peer = data;
+
+       *ready = try_wait_for_completion(&peer->init_comp);
+
+       return 0;
+}
+
+static int ntb_msit_dbgfs_ready_set(void *data, u64 ready)
+{
+       struct ntb_msit_peer *peer = data;
+
+       return wait_for_completion_interruptible(&peer->init_comp);
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(ntb_msit_ready_fops, ntb_msit_dbgfs_ready_get,
+                        ntb_msit_dbgfs_ready_set, "%llu\n");
+
+static int ntb_msit_dbgfs_occurrences_get(void *data, u64 *occurrences)
+{
+       struct ntb_msit_isr_ctx *isr_ctx = data;
+
+       *occurrences = isr_ctx->occurrences;
+
+       return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(ntb_msit_occurrences_fops,
+                        ntb_msit_dbgfs_occurrences_get,
+                        NULL, "%llu\n");
+
+static int ntb_msit_dbgfs_local_port_get(void *data, u64 *port)
+{
+       struct ntb_msit_ctx *nm = data;
+
+       *port = ntb_port_number(nm->ntb);
+
+       return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(ntb_msit_local_port_fops,
+                        ntb_msit_dbgfs_local_port_get,
+                        NULL, "%llu\n");
+
+static void ntb_msit_create_dbgfs(struct ntb_msit_ctx *nm)
+{
+       struct pci_dev *pdev = nm->ntb->pdev;
+       char buf[32];
+       int i;
+       struct dentry *peer_dir;
+
+       nm->dbgfs_dir = debugfs_create_dir(pci_name(pdev),
+                                          ntb_msit_dbgfs_topdir);
+       debugfs_create_file("port", 0400, nm->dbgfs_dir, nm,
+                           &ntb_msit_local_port_fops);
+
+       for (i = 0; i < ntb_peer_port_count(nm->ntb); i++) {
+               nm->peers[i].pidx = i;
+               nm->peers[i].nm = nm;
+               init_completion(&nm->peers[i].init_comp);
+
+               snprintf(buf, sizeof(buf), "peer%d", i);
+               peer_dir = debugfs_create_dir(buf, nm->dbgfs_dir);
+
+               debugfs_create_file_unsafe("trigger", 0200, peer_dir,
+                                          &nm->peers[i],
+                                          &ntb_msit_trigger_fops);
+
+               debugfs_create_file_unsafe("port", 0400, peer_dir,
+                                          &nm->peers[i], &ntb_msit_port_fops);
+
+               debugfs_create_file_unsafe("count", 0400, peer_dir,
+                                          &nm->peers[i],
+                                          &ntb_msit_count_fops);
+
+               debugfs_create_file_unsafe("ready", 0600, peer_dir,
+                                          &nm->peers[i],
+                                          &ntb_msit_ready_fops);
+       }
+
+       for (i = 0; i < num_irqs; i++) {
+               snprintf(buf, sizeof(buf), "irq%d_occurrences", i);
+               debugfs_create_file_unsafe(buf, 0400, nm->dbgfs_dir,
+                                          &nm->isr_ctx[i],
+                                          &ntb_msit_occurrences_fops);
+       }
+}
+
+static void ntb_msit_remove_dbgfs(struct ntb_msit_ctx *nm)
+{
+       debugfs_remove_recursive(nm->dbgfs_dir);
+}
+
+static int ntb_msit_probe(struct ntb_client *client, struct ntb_dev *ntb)
+{
+       struct ntb_msit_ctx *nm;
+       size_t struct_size;
+       int peers;
+       int ret;
+
+       peers = ntb_peer_port_count(ntb);
+       if (peers <= 0)
+               return -EINVAL;
+
+       if (ntb_spad_is_unsafe(ntb) || ntb_spad_count(ntb) < 2 * num_irqs + 1) {
+               dev_err(&ntb->dev, "NTB MSI test requires at least %d spads for %d irqs\n",
+                       2 * num_irqs + 1, num_irqs);
+               return -EFAULT;
+       }
+
+       ret = ntb_spad_write(ntb, 0, -1);
+       if (ret) {
+               dev_err(&ntb->dev, "Unable to write spads: %d\n", ret);
+               return ret;
+       }
+
+       ret = ntb_db_clear_mask(ntb, GENMASK(peers - 1, 0));
+       if (ret) {
+               dev_err(&ntb->dev, "Unable to clear doorbell mask: %d\n", ret);
+               return ret;
+       }
+
+       ret = ntb_msi_init(ntb, ntb_msit_desc_changed);
+       if (ret) {
+               dev_err(&ntb->dev, "Unable to initialize MSI library: %d\n",
+                       ret);
+               return ret;
+       }
+
+       struct_size = sizeof(*nm) + sizeof(*nm->peers) * peers;
+
+       nm = devm_kzalloc(&ntb->dev, struct_size, GFP_KERNEL);
+       if (!nm)
+               return -ENOMEM;
+
+       nm->isr_ctx = devm_kcalloc(&ntb->dev, num_irqs, sizeof(*nm->isr_ctx),
+                                  GFP_KERNEL);
+       if (!nm->isr_ctx)
+               return -ENOMEM;
+
+       INIT_WORK(&nm->setup_work, ntb_msit_setup_work);
+       nm->ntb = ntb;
+
+       ntb_msit_create_dbgfs(nm);
+
+       ret = ntb_set_ctx(ntb, nm, &ntb_msit_ops);
+       if (ret)
+               goto remove_dbgfs;
+
+       if (!nm->isr_ctx)
+               goto remove_dbgfs;
+
+       ntb_link_enable(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
+
+       return 0;
+
+remove_dbgfs:
+       ntb_msit_remove_dbgfs(nm);
+       devm_kfree(&ntb->dev, nm->isr_ctx);
+       devm_kfree(&ntb->dev, nm);
+       return ret;
+}
+
+static void ntb_msit_remove(struct ntb_client *client, struct ntb_dev *ntb)
+{
+       struct ntb_msit_ctx *nm = ntb->ctx;
+       int i;
+
+       ntb_link_disable(ntb);
+       ntb_db_set_mask(ntb, ntb_db_valid_mask(ntb));
+       ntb_msi_clear_mws(ntb);
+
+       for (i = 0; i < ntb_peer_port_count(ntb); i++)
+               kfree(nm->peers[i].msi_desc);
+
+       ntb_clear_ctx(ntb);
+       ntb_msit_remove_dbgfs(nm);
+}
+
+static struct ntb_client ntb_msit_client = {
+       .ops = {
+               .probe = ntb_msit_probe,
+               .remove = ntb_msit_remove
+       }
+};
+
+static int __init ntb_msit_init(void)
+{
+       int ret;
+
+       if (debugfs_initialized())
+               ntb_msit_dbgfs_topdir = debugfs_create_dir(KBUILD_MODNAME,
+                                                          NULL);
+
+       ret = ntb_register_client(&ntb_msit_client);
+       if (ret)
+               debugfs_remove_recursive(ntb_msit_dbgfs_topdir);
+
+       return ret;
+}
+module_init(ntb_msit_init);
+
+static void __exit ntb_msit_exit(void)
+{
+       ntb_unregister_client(&ntb_msit_client);
+       debugfs_remove_recursive(ntb_msit_dbgfs_topdir);
+}
+module_exit(ntb_msit_exit);
index 11a6cd3..d028331 100644 (file)
@@ -100,7 +100,7 @@ MODULE_DESCRIPTION("PCIe NTB Performance Measurement Tool");
 #define DMA_TRIES              100
 #define DMA_MDELAY             10
 
-#define MSG_TRIES              500
+#define MSG_TRIES              1000
 #define MSG_UDELAY_LOW         1000
 #define MSG_UDELAY_HIGH                2000
 
@@ -734,8 +734,6 @@ static void perf_disable_service(struct perf_ctx *perf)
 {
        int pidx;
 
-       ntb_link_disable(perf->ntb);
-
        if (perf->cmd_send == perf_msg_cmd_send) {
                u64 inbits;
 
@@ -752,6 +750,16 @@ static void perf_disable_service(struct perf_ctx *perf)
 
        for (pidx = 0; pidx < perf->pcnt; pidx++)
                flush_work(&perf->peers[pidx].service);
+
+       for (pidx = 0; pidx < perf->pcnt; pidx++) {
+               struct perf_peer *peer = &perf->peers[pidx];
+
+               ntb_spad_write(perf->ntb, PERF_SPAD_CMD(peer->gidx), 0);
+       }
+
+       ntb_db_clear(perf->ntb, PERF_SPAD_NOTIFY(perf->gidx));
+
+       ntb_link_disable(perf->ntb);
 }
 
 /*==============================================================================
index 5450079..a5fde15 100644 (file)
@@ -33,7 +33,7 @@ config BLK_DEV_PMEM
          Documentation/admin-guide/kernel-parameters.rst).  This driver converts
          these persistent memory ranges into block devices that are
          capable of DAX (direct-access) file system mappings.  See
-         Documentation/nvdimm/nvdimm.txt for more details.
+         Documentation/driver-api/nvdimm/nvdimm.rst for more details.
 
          Say Y if you want to use an NVDIMM
 
index 6f2a088..cefe233 100644 (file)
@@ -5,6 +5,7 @@ obj-$(CONFIG_ND_BTT) += nd_btt.o
 obj-$(CONFIG_ND_BLK) += nd_blk.o
 obj-$(CONFIG_X86_PMEM_LEGACY) += nd_e820.o
 obj-$(CONFIG_OF_PMEM) += of_pmem.o
+obj-$(CONFIG_VIRTIO_PMEM) += virtio_pmem.o nd_virtio.o
 
 nd_pmem-y := pmem.o
 
index 26c1c76..2985ca9 100644 (file)
@@ -255,7 +255,7 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns,
        struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
        unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512);
        sector_t sector = offset >> 9;
-       int rc = 0;
+       int rc = 0, ret = 0;
 
        if (unlikely(!size))
                return 0;
@@ -293,7 +293,9 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns,
        }
 
        memcpy_flushcache(nsio->addr + offset, buf, size);
-       nvdimm_flush(to_nd_region(ndns->dev.parent));
+       ret = nvdimm_flush(to_nd_region(ndns->dev.parent), NULL);
+       if (ret)
+               rc = ret;
 
        return rc;
 }
index 49fc18e..6d22b0f 100644 (file)
@@ -118,7 +118,7 @@ int nd_dax_probe(struct device *dev, struct nd_namespace_common *ndns)
        nvdimm_bus_unlock(&ndns->dev);
        if (!dax_dev)
                return -ENOMEM;
-       pfn_sb = devm_kzalloc(dev, sizeof(*pfn_sb), GFP_KERNEL);
+       pfn_sb = devm_kmalloc(dev, sizeof(*pfn_sb), GFP_KERNEL);
        nd_pfn->pfn_sb = pfn_sb;
        rc = nd_pfn_validate(nd_pfn, DAX_SIG);
        dev_dbg(dev, "dax: %s\n", rc == 0 ? dev_name(dax_dev) : "<none>");
index a434a59..2d8d7e5 100644 (file)
@@ -1822,8 +1822,8 @@ static bool has_uuid_at_pos(struct nd_region *nd_region, u8 *uuid,
                                        && !guid_equal(&nd_set->type_guid,
                                                &nd_label->type_guid)) {
                                dev_dbg(ndd->dev, "expect type_guid %pUb got %pUb\n",
-                                               nd_set->type_guid.b,
-                                               nd_label->type_guid.b);
+                                               &nd_set->type_guid,
+                                               &nd_label->type_guid);
                                continue;
                        }
 
@@ -2227,8 +2227,8 @@ static struct device *create_namespace_blk(struct nd_region *nd_region,
        if (namespace_label_has(ndd, type_guid)) {
                if (!guid_equal(&nd_set->type_guid, &nd_label->type_guid)) {
                        dev_dbg(ndd->dev, "expect type_guid %pUb got %pUb\n",
-                                       nd_set->type_guid.b,
-                                       nd_label->type_guid.b);
+                                       &nd_set->type_guid,
+                                       &nd_label->type_guid);
                        return ERR_PTR(-EAGAIN);
                }
 
index d24304c..1b99556 100644 (file)
@@ -155,6 +155,7 @@ struct nd_region {
        struct badblocks bb;
        struct nd_interleave_set *nd_set;
        struct nd_percpu_lane __percpu *lane;
+       int (*flush)(struct nd_region *nd_region, struct bio *bio);
        struct nd_mapping mapping[0];
 };
 
diff --git a/drivers/nvdimm/nd_virtio.c b/drivers/nvdimm/nd_virtio.c
new file mode 100644 (file)
index 0000000..10351d5
--- /dev/null
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * virtio_pmem.c: Virtio pmem Driver
+ *
+ * Discovers persistent memory range information
+ * from host and provides a virtio based flushing
+ * interface.
+ */
+#include "virtio_pmem.h"
+#include "nd.h"
+
+ /* The interrupt handler */
+void virtio_pmem_host_ack(struct virtqueue *vq)
+{
+       struct virtio_pmem *vpmem = vq->vdev->priv;
+       struct virtio_pmem_request *req_data, *req_buf;
+       unsigned long flags;
+       unsigned int len;
+
+       spin_lock_irqsave(&vpmem->pmem_lock, flags);
+       while ((req_data = virtqueue_get_buf(vq, &len)) != NULL) {
+               req_data->done = true;
+               wake_up(&req_data->host_acked);
+
+               if (!list_empty(&vpmem->req_list)) {
+                       req_buf = list_first_entry(&vpmem->req_list,
+                                       struct virtio_pmem_request, list);
+                       req_buf->wq_buf_avail = true;
+                       wake_up(&req_buf->wq_buf);
+                       list_del(&req_buf->list);
+               }
+       }
+       spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
+}
+EXPORT_SYMBOL_GPL(virtio_pmem_host_ack);
+
+ /* The request submission function */
+static int virtio_pmem_flush(struct nd_region *nd_region)
+{
+       struct virtio_device *vdev = nd_region->provider_data;
+       struct virtio_pmem *vpmem  = vdev->priv;
+       struct virtio_pmem_request *req_data;
+       struct scatterlist *sgs[2], sg, ret;
+       unsigned long flags;
+       int err, err1;
+
+       might_sleep();
+       req_data = kmalloc(sizeof(*req_data), GFP_KERNEL);
+       if (!req_data)
+               return -ENOMEM;
+
+       req_data->done = false;
+       init_waitqueue_head(&req_data->host_acked);
+       init_waitqueue_head(&req_data->wq_buf);
+       INIT_LIST_HEAD(&req_data->list);
+       req_data->req.type = cpu_to_le32(VIRTIO_PMEM_REQ_TYPE_FLUSH);
+       sg_init_one(&sg, &req_data->req, sizeof(req_data->req));
+       sgs[0] = &sg;
+       sg_init_one(&ret, &req_data->resp.ret, sizeof(req_data->resp));
+       sgs[1] = &ret;
+
+       spin_lock_irqsave(&vpmem->pmem_lock, flags);
+        /*
+         * If virtqueue_add_sgs returns -ENOSPC then req_vq virtual
+         * queue does not have free descriptor. We add the request
+         * to req_list and wait for host_ack to wake us up when free
+         * slots are available.
+         */
+       while ((err = virtqueue_add_sgs(vpmem->req_vq, sgs, 1, 1, req_data,
+                                       GFP_ATOMIC)) == -ENOSPC) {
+
+               dev_info(&vdev->dev, "failed to send command to virtio pmem device, no free slots in the virtqueue\n");
+               req_data->wq_buf_avail = false;
+               list_add_tail(&req_data->list, &vpmem->req_list);
+               spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
+
+               /* A host response results in "host_ack" getting called */
+               wait_event(req_data->wq_buf, req_data->wq_buf_avail);
+               spin_lock_irqsave(&vpmem->pmem_lock, flags);
+       }
+       err1 = virtqueue_kick(vpmem->req_vq);
+       spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
+       /*
+        * virtqueue_add_sgs failed with error different than -ENOSPC, we can't
+        * do anything about that.
+        */
+       if (err || !err1) {
+               dev_info(&vdev->dev, "failed to send command to virtio pmem device\n");
+               err = -EIO;
+       } else {
+               /* A host repsonse results in "host_ack" getting called */
+               wait_event(req_data->host_acked, req_data->done);
+               err = le32_to_cpu(req_data->resp.ret);
+       }
+
+       kfree(req_data);
+       return err;
+};
+
+/* The asynchronous flush callback function */
+int async_pmem_flush(struct nd_region *nd_region, struct bio *bio)
+{
+       /*
+        * Create child bio for asynchronous flush and chain with
+        * parent bio. Otherwise directly call nd_region flush.
+        */
+       if (bio && bio->bi_iter.bi_sector != -1) {
+               struct bio *child = bio_alloc(GFP_ATOMIC, 0);
+
+               if (!child)
+                       return -ENOMEM;
+               bio_copy_dev(child, bio);
+               child->bi_opf = REQ_PREFLUSH;
+               child->bi_iter.bi_sector = -1;
+               bio_chain(child, bio);
+               submit_bio(child);
+               return 0;
+       }
+       if (virtio_pmem_flush(nd_region))
+               return -EIO;
+
+       return 0;
+};
+EXPORT_SYMBOL_GPL(async_pmem_flush);
+MODULE_LICENSE("GPL");
index f58b849..7381673 100644 (file)
@@ -28,22 +28,9 @@ struct nd_pfn_sb {
        __le32 end_trunc;
        /* minor-version-2 record the base alignment of the mapping */
        __le32 align;
+       /* minor-version-3 guarantee the padding and flags are zero */
        u8 padding[4000];
        __le64 checksum;
 };
 
-#ifdef CONFIG_SPARSEMEM
-#define PFN_SECTION_ALIGN_DOWN(x) SECTION_ALIGN_DOWN(x)
-#define PFN_SECTION_ALIGN_UP(x) SECTION_ALIGN_UP(x)
-#else
-/*
- * In this case ZONE_DEVICE=n and we will disable 'pfn' device support,
- * but we still want pmem to compile.
- */
-#define PFN_SECTION_ALIGN_DOWN(x) (x)
-#define PFN_SECTION_ALIGN_UP(x) (x)
-#endif
-
-#define PHYS_SECTION_ALIGN_DOWN(x) PFN_PHYS(PFN_SECTION_ALIGN_DOWN(PHYS_PFN(x)))
-#define PHYS_SECTION_ALIGN_UP(x) PFN_PHYS(PFN_SECTION_ALIGN_UP(PHYS_PFN(x)))
 #endif /* __NVDIMM_PFN_H */
index 55fb6b7..df2bdbd 100644 (file)
@@ -412,6 +412,15 @@ static int nd_pfn_clear_memmap_errors(struct nd_pfn *nd_pfn)
        return 0;
 }
 
+/**
+ * nd_pfn_validate - read and validate info-block
+ * @nd_pfn: fsdax namespace runtime state / properties
+ * @sig: 'devdax' or 'fsdax' signature
+ *
+ * Upon return the info-block buffer contents (->pfn_sb) are
+ * indeterminate when validation fails, and a coherent info-block
+ * otherwise.
+ */
 int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
 {
        u64 checksum, offset;
@@ -557,7 +566,7 @@ int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns)
        nvdimm_bus_unlock(&ndns->dev);
        if (!pfn_dev)
                return -ENOMEM;
-       pfn_sb = devm_kzalloc(dev, sizeof(*pfn_sb), GFP_KERNEL);
+       pfn_sb = devm_kmalloc(dev, sizeof(*pfn_sb), GFP_KERNEL);
        nd_pfn = to_nd_pfn(pfn_dev);
        nd_pfn->pfn_sb = pfn_sb;
        rc = nd_pfn_validate(nd_pfn, PFN_SIG);
@@ -578,14 +587,14 @@ static u32 info_block_reserve(void)
 }
 
 /*
- * We hotplug memory at section granularity, pad the reserved area from
- * the previous section base to the namespace base address.
+ * We hotplug memory at sub-section granularity, pad the reserved area
+ * from the previous section base to the namespace base address.
  */
 static unsigned long init_altmap_base(resource_size_t base)
 {
        unsigned long base_pfn = PHYS_PFN(base);
 
-       return PFN_SECTION_ALIGN_DOWN(base_pfn);
+       return SUBSECTION_ALIGN_DOWN(base_pfn);
 }
 
 static unsigned long init_altmap_reserve(resource_size_t base)
@@ -593,7 +602,7 @@ static unsigned long init_altmap_reserve(resource_size_t base)
        unsigned long reserve = info_block_reserve() >> PAGE_SHIFT;
        unsigned long base_pfn = PHYS_PFN(base);
 
-       reserve += base_pfn - PFN_SECTION_ALIGN_DOWN(base_pfn);
+       reserve += base_pfn - SUBSECTION_ALIGN_DOWN(base_pfn);
        return reserve;
 }
 
@@ -623,8 +632,7 @@ static int __nvdimm_setup_pfn(struct nd_pfn *nd_pfn, struct dev_pagemap *pgmap)
                        return -EINVAL;
                nd_pfn->npfns = le64_to_cpu(pfn_sb->npfns);
        } else if (nd_pfn->mode == PFN_MODE_PMEM) {
-               nd_pfn->npfns = PFN_SECTION_ALIGN_UP((resource_size(res)
-                                       - offset) / PAGE_SIZE);
+               nd_pfn->npfns = PHYS_PFN((resource_size(res) - offset));
                if (le64_to_cpu(nd_pfn->pfn_sb->npfns) > nd_pfn->npfns)
                        dev_info(&nd_pfn->dev,
                                        "number of pfns truncated from %lld to %ld\n",
@@ -640,60 +648,20 @@ static int __nvdimm_setup_pfn(struct nd_pfn *nd_pfn, struct dev_pagemap *pgmap)
        return 0;
 }
 
-static u64 phys_pmem_align_down(struct nd_pfn *nd_pfn, u64 phys)
-{
-       return min_t(u64, PHYS_SECTION_ALIGN_DOWN(phys),
-                       ALIGN_DOWN(phys, nd_pfn->align));
-}
-
-/*
- * Check if pmem collides with 'System RAM', or other regions when
- * section aligned.  Trim it accordingly.
- */
-static void trim_pfn_device(struct nd_pfn *nd_pfn, u32 *start_pad, u32 *end_trunc)
-{
-       struct nd_namespace_common *ndns = nd_pfn->ndns;
-       struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
-       struct nd_region *nd_region = to_nd_region(nd_pfn->dev.parent);
-       const resource_size_t start = nsio->res.start;
-       const resource_size_t end = start + resource_size(&nsio->res);
-       resource_size_t adjust, size;
-
-       *start_pad = 0;
-       *end_trunc = 0;
-
-       adjust = start - PHYS_SECTION_ALIGN_DOWN(start);
-       size = resource_size(&nsio->res) + adjust;
-       if (region_intersects(start - adjust, size, IORESOURCE_SYSTEM_RAM,
-                               IORES_DESC_NONE) == REGION_MIXED
-                       || nd_region_conflict(nd_region, start - adjust, size))
-               *start_pad = PHYS_SECTION_ALIGN_UP(start) - start;
-
-       /* Now check that end of the range does not collide. */
-       adjust = PHYS_SECTION_ALIGN_UP(end) - end;
-       size = resource_size(&nsio->res) + adjust;
-       if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
-                               IORES_DESC_NONE) == REGION_MIXED
-                       || !IS_ALIGNED(end, nd_pfn->align)
-                       || nd_region_conflict(nd_region, start, size))
-               *end_trunc = end - phys_pmem_align_down(nd_pfn, end);
-}
-
 static int nd_pfn_init(struct nd_pfn *nd_pfn)
 {
        struct nd_namespace_common *ndns = nd_pfn->ndns;
        struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
-       u32 start_pad, end_trunc, reserve = info_block_reserve();
        resource_size_t start, size;
        struct nd_region *nd_region;
+       unsigned long npfns, align;
        struct nd_pfn_sb *pfn_sb;
-       unsigned long npfns;
        phys_addr_t offset;
        const char *sig;
        u64 checksum;
        int rc;
 
-       pfn_sb = devm_kzalloc(&nd_pfn->dev, sizeof(*pfn_sb), GFP_KERNEL);
+       pfn_sb = devm_kmalloc(&nd_pfn->dev, sizeof(*pfn_sb), GFP_KERNEL);
        if (!pfn_sb)
                return -ENOMEM;
 
@@ -702,11 +670,14 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
                sig = DAX_SIG;
        else
                sig = PFN_SIG;
+
        rc = nd_pfn_validate(nd_pfn, sig);
        if (rc != -ENODEV)
                return rc;
 
        /* no info block, do init */;
+       memset(pfn_sb, 0, sizeof(*pfn_sb));
+
        nd_region = to_nd_region(nd_pfn->dev.parent);
        if (nd_region->ro) {
                dev_info(&nd_pfn->dev,
@@ -715,43 +686,35 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
                return -ENXIO;
        }
 
-       memset(pfn_sb, 0, sizeof(*pfn_sb));
-
-       trim_pfn_device(nd_pfn, &start_pad, &end_trunc);
-       if (start_pad + end_trunc)
-               dev_info(&nd_pfn->dev, "%s alignment collision, truncate %d bytes\n",
-                               dev_name(&ndns->dev), start_pad + end_trunc);
-
        /*
         * Note, we use 64 here for the standard size of struct page,
         * debugging options may cause it to be larger in which case the
         * implementation will limit the pfns advertised through
         * ->direct_access() to those that are included in the memmap.
         */
-       start = nsio->res.start + start_pad;
+       start = nsio->res.start;
        size = resource_size(&nsio->res);
-       npfns = PFN_SECTION_ALIGN_UP((size - start_pad - end_trunc - reserve)
-                       / PAGE_SIZE);
+       npfns = PHYS_PFN(size - SZ_8K);
+       align = max(nd_pfn->align, (1UL << SUBSECTION_SHIFT));
        if (nd_pfn->mode == PFN_MODE_PMEM) {
                /*
                 * The altmap should be padded out to the block size used
                 * when populating the vmemmap. This *should* be equal to
                 * PMD_SIZE for most architectures.
                 */
-               offset = ALIGN(start + reserve + 64 * npfns,
-                               max(nd_pfn->align, PMD_SIZE)) - start;
+               offset = ALIGN(start + SZ_8K + 64 * npfns, align) - start;
        } else if (nd_pfn->mode == PFN_MODE_RAM)
-               offset = ALIGN(start + reserve, nd_pfn->align) - start;
+               offset = ALIGN(start + SZ_8K, align) - start;
        else
                return -ENXIO;
 
-       if (offset + start_pad + end_trunc >= size) {
+       if (offset >= size) {
                dev_err(&nd_pfn->dev, "%s unable to satisfy requested alignment\n",
                                dev_name(&ndns->dev));
                return -ENXIO;
        }
 
-       npfns = (size - offset - start_pad - end_trunc) / SZ_4K;
+       npfns = PHYS_PFN(size - offset);
        pfn_sb->mode = cpu_to_le32(nd_pfn->mode);
        pfn_sb->dataoff = cpu_to_le64(offset);
        pfn_sb->npfns = cpu_to_le64(npfns);
@@ -759,9 +722,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
        memcpy(pfn_sb->uuid, nd_pfn->uuid, 16);
        memcpy(pfn_sb->parent_uuid, nd_dev_to_uuid(&ndns->dev), 16);
        pfn_sb->version_major = cpu_to_le16(1);
-       pfn_sb->version_minor = cpu_to_le16(2);
-       pfn_sb->start_pad = cpu_to_le32(start_pad);
-       pfn_sb->end_trunc = cpu_to_le32(end_trunc);
+       pfn_sb->version_minor = cpu_to_le16(3);
        pfn_sb->align = cpu_to_le32(nd_pfn->align);
        checksum = nd_sb_checksum((struct nd_gen_sb *) pfn_sb);
        pfn_sb->checksum = cpu_to_le64(checksum);
index e7d8cc9..2bf3acd 100644 (file)
@@ -184,6 +184,7 @@ static blk_status_t pmem_do_bvec(struct pmem_device *pmem, struct page *page,
 
 static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
 {
+       int ret = 0;
        blk_status_t rc = 0;
        bool do_acct;
        unsigned long start;
@@ -193,7 +194,7 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
        struct nd_region *nd_region = to_region(pmem);
 
        if (bio->bi_opf & REQ_PREFLUSH)
-               nvdimm_flush(nd_region);
+               ret = nvdimm_flush(nd_region, bio);
 
        do_acct = nd_iostat_start(bio, &start);
        bio_for_each_segment(bvec, bio, iter) {
@@ -208,7 +209,10 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
                nd_iostat_end(bio, start);
 
        if (bio->bi_opf & REQ_FUA)
-               nvdimm_flush(nd_region);
+               ret = nvdimm_flush(nd_region, bio);
+
+       if (ret)
+               bio->bi_status = errno_to_blk_status(ret);
 
        bio_endio(bio);
        return BLK_QC_T_NONE;
@@ -362,6 +366,7 @@ static int pmem_attach_disk(struct device *dev,
        struct gendisk *disk;
        void *addr;
        int rc;
+       unsigned long flags = 0UL;
 
        pmem = devm_kzalloc(dev, sizeof(*pmem), GFP_KERNEL);
        if (!pmem)
@@ -457,14 +462,15 @@ static int pmem_attach_disk(struct device *dev,
        nvdimm_badblocks_populate(nd_region, &pmem->bb, &bb_res);
        disk->bb = &pmem->bb;
 
-       dax_dev = alloc_dax(pmem, disk->disk_name, &pmem_dax_ops);
+       if (is_nvdimm_sync(nd_region))
+               flags = DAXDEV_F_SYNC;
+       dax_dev = alloc_dax(pmem, disk->disk_name, &pmem_dax_ops, flags);
        if (!dax_dev) {
                put_disk(disk);
                return -ENOMEM;
        }
        dax_write_cache(dax_dev, nvdimm_has_cache(nd_region));
        pmem->dax_dev = dax_dev;
-
        gendev = disk_to_dev(disk);
        gendev->groups = pmem_attribute_groups;
 
@@ -522,14 +528,14 @@ static int nd_pmem_remove(struct device *dev)
                sysfs_put(pmem->bb_state);
                pmem->bb_state = NULL;
        }
-       nvdimm_flush(to_nd_region(dev->parent));
+       nvdimm_flush(to_nd_region(dev->parent), NULL);
 
        return 0;
 }
 
 static void nd_pmem_shutdown(struct device *dev)
 {
-       nvdimm_flush(to_nd_region(dev->parent));
+       nvdimm_flush(to_nd_region(dev->parent), NULL);
 }
 
 static void nd_pmem_notify(struct device *dev, enum nvdimm_event event)
index 4fed9ce..56f2227 100644 (file)
@@ -287,7 +287,9 @@ static ssize_t deep_flush_store(struct device *dev, struct device_attribute *att
                return rc;
        if (!flush)
                return -EINVAL;
-       nvdimm_flush(nd_region);
+       rc = nvdimm_flush(nd_region, NULL);
+       if (rc)
+               return rc;
 
        return len;
 }
@@ -1077,6 +1079,11 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
        dev->of_node = ndr_desc->of_node;
        nd_region->ndr_size = resource_size(ndr_desc->res);
        nd_region->ndr_start = ndr_desc->res->start;
+       if (ndr_desc->flush)
+               nd_region->flush = ndr_desc->flush;
+       else
+               nd_region->flush = NULL;
+
        nd_device_register(dev);
 
        return nd_region;
@@ -1117,11 +1124,24 @@ struct nd_region *nvdimm_volatile_region_create(struct nvdimm_bus *nvdimm_bus,
 }
 EXPORT_SYMBOL_GPL(nvdimm_volatile_region_create);
 
+int nvdimm_flush(struct nd_region *nd_region, struct bio *bio)
+{
+       int rc = 0;
+
+       if (!nd_region->flush)
+               rc = generic_nvdimm_flush(nd_region);
+       else {
+               if (nd_region->flush(nd_region, bio))
+                       rc = -EIO;
+       }
+
+       return rc;
+}
 /**
  * nvdimm_flush - flush any posted write queues between the cpu and pmem media
  * @nd_region: blk or interleaved pmem region
  */
-void nvdimm_flush(struct nd_region *nd_region)
+int generic_nvdimm_flush(struct nd_region *nd_region)
 {
        struct nd_region_data *ndrd = dev_get_drvdata(&nd_region->dev);
        int i, idx;
@@ -1145,6 +1165,8 @@ void nvdimm_flush(struct nd_region *nd_region)
                if (ndrd_get_flush_wpq(ndrd, i, 0))
                        writeq(1, ndrd_get_flush_wpq(ndrd, i, idx));
        wmb();
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(nvdimm_flush);
 
@@ -1189,6 +1211,13 @@ int nvdimm_has_cache(struct nd_region *nd_region)
 }
 EXPORT_SYMBOL_GPL(nvdimm_has_cache);
 
+bool is_nvdimm_sync(struct nd_region *nd_region)
+{
+       return is_nd_pmem(&nd_region->dev) &&
+               !test_bit(ND_REGION_ASYNC, &nd_region->flags);
+}
+EXPORT_SYMBOL_GPL(is_nvdimm_sync);
+
 struct conflict_context {
        struct nd_region *nd_region;
        resource_size_t start, size;
diff --git a/drivers/nvdimm/virtio_pmem.c b/drivers/nvdimm/virtio_pmem.c
new file mode 100644 (file)
index 0000000..5e3d07b
--- /dev/null
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * virtio_pmem.c: Virtio pmem Driver
+ *
+ * Discovers persistent memory range information
+ * from host and registers the virtual pmem device
+ * with libnvdimm core.
+ */
+#include "virtio_pmem.h"
+#include "nd.h"
+
+static struct virtio_device_id id_table[] = {
+       { VIRTIO_ID_PMEM, VIRTIO_DEV_ANY_ID },
+       { 0 },
+};
+
+ /* Initialize virt queue */
+static int init_vq(struct virtio_pmem *vpmem)
+{
+       /* single vq */
+       vpmem->req_vq = virtio_find_single_vq(vpmem->vdev,
+                                       virtio_pmem_host_ack, "flush_queue");
+       if (IS_ERR(vpmem->req_vq))
+               return PTR_ERR(vpmem->req_vq);
+
+       spin_lock_init(&vpmem->pmem_lock);
+       INIT_LIST_HEAD(&vpmem->req_list);
+
+       return 0;
+};
+
+static int virtio_pmem_probe(struct virtio_device *vdev)
+{
+       struct nd_region_desc ndr_desc = {};
+       int nid = dev_to_node(&vdev->dev);
+       struct nd_region *nd_region;
+       struct virtio_pmem *vpmem;
+       struct resource res;
+       int err = 0;
+
+       if (!vdev->config->get) {
+               dev_err(&vdev->dev, "%s failure: config access disabled\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       vpmem = devm_kzalloc(&vdev->dev, sizeof(*vpmem), GFP_KERNEL);
+       if (!vpmem) {
+               err = -ENOMEM;
+               goto out_err;
+       }
+
+       vpmem->vdev = vdev;
+       vdev->priv = vpmem;
+       err = init_vq(vpmem);
+       if (err) {
+               dev_err(&vdev->dev, "failed to initialize virtio pmem vq's\n");
+               goto out_err;
+       }
+
+       virtio_cread(vpmem->vdev, struct virtio_pmem_config,
+                       start, &vpmem->start);
+       virtio_cread(vpmem->vdev, struct virtio_pmem_config,
+                       size, &vpmem->size);
+
+       res.start = vpmem->start;
+       res.end   = vpmem->start + vpmem->size - 1;
+       vpmem->nd_desc.provider_name = "virtio-pmem";
+       vpmem->nd_desc.module = THIS_MODULE;
+
+       vpmem->nvdimm_bus = nvdimm_bus_register(&vdev->dev,
+                                               &vpmem->nd_desc);
+       if (!vpmem->nvdimm_bus) {
+               dev_err(&vdev->dev, "failed to register device with nvdimm_bus\n");
+               err = -ENXIO;
+               goto out_vq;
+       }
+
+       dev_set_drvdata(&vdev->dev, vpmem->nvdimm_bus);
+
+       ndr_desc.res = &res;
+       ndr_desc.numa_node = nid;
+       ndr_desc.flush = async_pmem_flush;
+       set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
+       set_bit(ND_REGION_ASYNC, &ndr_desc.flags);
+       nd_region = nvdimm_pmem_region_create(vpmem->nvdimm_bus, &ndr_desc);
+       if (!nd_region) {
+               dev_err(&vdev->dev, "failed to create nvdimm region\n");
+               err = -ENXIO;
+               goto out_nd;
+       }
+       nd_region->provider_data = dev_to_virtio(nd_region->dev.parent->parent);
+       return 0;
+out_nd:
+       nvdimm_bus_unregister(vpmem->nvdimm_bus);
+out_vq:
+       vdev->config->del_vqs(vdev);
+out_err:
+       return err;
+}
+
+static void virtio_pmem_remove(struct virtio_device *vdev)
+{
+       struct nvdimm_bus *nvdimm_bus = dev_get_drvdata(&vdev->dev);
+
+       nvdimm_bus_unregister(nvdimm_bus);
+       vdev->config->del_vqs(vdev);
+       vdev->config->reset(vdev);
+}
+
+static struct virtio_driver virtio_pmem_driver = {
+       .driver.name            = KBUILD_MODNAME,
+       .driver.owner           = THIS_MODULE,
+       .id_table               = id_table,
+       .probe                  = virtio_pmem_probe,
+       .remove                 = virtio_pmem_remove,
+};
+
+module_virtio_driver(virtio_pmem_driver);
+MODULE_DEVICE_TABLE(virtio, id_table);
+MODULE_DESCRIPTION("Virtio pmem driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/nvdimm/virtio_pmem.h b/drivers/nvdimm/virtio_pmem.h
new file mode 100644 (file)
index 0000000..0dddefe
--- /dev/null
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * virtio_pmem.h: virtio pmem Driver
+ *
+ * Discovers persistent memory range information
+ * from host and provides a virtio based flushing
+ * interface.
+ **/
+
+#ifndef _LINUX_VIRTIO_PMEM_H
+#define _LINUX_VIRTIO_PMEM_H
+
+#include <linux/module.h>
+#include <uapi/linux/virtio_pmem.h>
+#include <linux/libnvdimm.h>
+#include <linux/spinlock.h>
+
+struct virtio_pmem_request {
+       struct virtio_pmem_req req;
+       struct virtio_pmem_resp resp;
+
+       /* Wait queue to process deferred work after ack from host */
+       wait_queue_head_t host_acked;
+       bool done;
+
+       /* Wait queue to process deferred work after virt queue buffer avail */
+       wait_queue_head_t wq_buf;
+       bool wq_buf_avail;
+       struct list_head list;
+};
+
+struct virtio_pmem {
+       struct virtio_device *vdev;
+
+       /* Virtio pmem request queue */
+       struct virtqueue *req_vq;
+
+       /* nvdimm bus registers virtio pmem device */
+       struct nvdimm_bus *nvdimm_bus;
+       struct nvdimm_bus_descriptor nd_desc;
+
+       /* List to store deferred work if virtqueue is full */
+       struct list_head req_list;
+
+       /* Synchronize virtqueue data */
+       spinlock_t pmem_lock;
+
+       /* Memory region information */
+       __u64 start;
+       __u64 size;
+};
+
+void virtio_pmem_host_ack(struct virtqueue *vq);
+int async_pmem_flush(struct nd_region *nd_region, struct bio *bio);
+#endif
index 20e0e7e..55e7f5b 100644 (file)
@@ -2294,8 +2294,12 @@ int of_map_rid(struct device_node *np, u32 rid,
                return 0;
        }
 
-       pr_err("%pOF: Invalid %s translation - no match for rid 0x%x on %pOF\n",
-               np, map_name, rid, target && *target ? *target : NULL);
-       return -EFAULT;
+       pr_info("%pOF: no %s translation for rid 0x%x on %pOF\n", np, map_name,
+               rid, target && *target ? *target : NULL);
+
+       /* Bypasses translation */
+       if (id_out)
+               *id_out = rid;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(of_map_rid);
index 4ea0897..0875f2f 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/oprofile.h>
 #include <linux/fs.h>
+#include <linux/fs_context.h>
 #include <linux/pagemap.h>
 #include <linux/uaccess.h>
 
@@ -238,7 +239,7 @@ struct dentry *oprofilefs_mkdir(struct dentry *parent, char const *name)
 }
 
 
-static int oprofilefs_fill_super(struct super_block *sb, void *data, int silent)
+static int oprofilefs_fill_super(struct super_block *sb, struct fs_context *fc)
 {
        struct inode *root_inode;
 
@@ -263,18 +264,25 @@ static int oprofilefs_fill_super(struct super_block *sb, void *data, int silent)
        return 0;
 }
 
-
-static struct dentry *oprofilefs_mount(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *data)
+static int oprofilefs_get_tree(struct fs_context *fc)
 {
-       return mount_single(fs_type, flags, data, oprofilefs_fill_super);
+       return get_tree_single(fc, oprofilefs_fill_super);
 }
 
+static const struct fs_context_operations oprofilefs_context_ops = {
+       .get_tree       = oprofilefs_get_tree,
+};
+
+static int oprofilefs_init_fs_context(struct fs_context *fc)
+{
+       fc->ops = &oprofilefs_context_ops;
+       return 0;
+}
 
 static struct file_system_type oprofilefs_type = {
        .owner          = THIS_MODULE,
        .name           = "oprofilefs",
-       .mount          = oprofilefs_mount,
+       .init_fs_context = oprofilefs_init_fs_context,
        .kill_sb        = kill_litter_super,
 };
 MODULE_ALIAS_FS("oprofilefs");
index 59a6d23..0884bed 100644 (file)
@@ -192,6 +192,9 @@ static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
 
 static void __iomem *pci_msix_desc_addr(struct msi_desc *desc)
 {
+       if (desc->msi_attrib.is_virtual)
+               return NULL;
+
        return desc->mask_base +
                desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
 }
@@ -206,14 +209,19 @@ static void __iomem *pci_msix_desc_addr(struct msi_desc *desc)
 u32 __pci_msix_desc_mask_irq(struct msi_desc *desc, u32 flag)
 {
        u32 mask_bits = desc->masked;
+       void __iomem *desc_addr;
 
        if (pci_msi_ignore_mask)
                return 0;
+       desc_addr = pci_msix_desc_addr(desc);
+       if (!desc_addr)
+               return 0;
 
        mask_bits &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT;
        if (flag)
                mask_bits |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
-       writel(mask_bits, pci_msix_desc_addr(desc) + PCI_MSIX_ENTRY_VECTOR_CTRL);
+
+       writel(mask_bits, desc_addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
 
        return mask_bits;
 }
@@ -273,6 +281,11 @@ void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
        if (entry->msi_attrib.is_msix) {
                void __iomem *base = pci_msix_desc_addr(entry);
 
+               if (!base) {
+                       WARN_ON(1);
+                       return;
+               }
+
                msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR);
                msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR);
                msg->data = readl(base + PCI_MSIX_ENTRY_DATA);
@@ -303,6 +316,9 @@ void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
        } else if (entry->msi_attrib.is_msix) {
                void __iomem *base = pci_msix_desc_addr(entry);
 
+               if (!base)
+                       goto skip;
+
                writel(msg->address_lo, base + PCI_MSIX_ENTRY_LOWER_ADDR);
                writel(msg->address_hi, base + PCI_MSIX_ENTRY_UPPER_ADDR);
                writel(msg->data, base + PCI_MSIX_ENTRY_DATA);
@@ -327,7 +343,13 @@ void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
                                              msg->data);
                }
        }
+
+skip:
        entry->msg = *msg;
+
+       if (entry->write_msi_msg)
+               entry->write_msi_msg(entry, entry->write_msi_msg_data);
+
 }
 
 void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg)
@@ -550,6 +572,7 @@ msi_setup_entry(struct pci_dev *dev, int nvec, struct irq_affinity *affd)
 
        entry->msi_attrib.is_msix       = 0;
        entry->msi_attrib.is_64         = !!(control & PCI_MSI_FLAGS_64BIT);
+       entry->msi_attrib.is_virtual    = 0;
        entry->msi_attrib.entry_nr      = 0;
        entry->msi_attrib.maskbit       = !!(control & PCI_MSI_FLAGS_MASKBIT);
        entry->msi_attrib.default_irq   = dev->irq;     /* Save IOAPIC IRQ */
@@ -674,6 +697,7 @@ static int msix_setup_entries(struct pci_dev *dev, void __iomem *base,
        struct irq_affinity_desc *curmsk, *masks = NULL;
        struct msi_desc *entry;
        int ret, i;
+       int vec_count = pci_msix_vec_count(dev);
 
        if (affd)
                masks = irq_create_affinity_masks(nvec, affd);
@@ -696,6 +720,10 @@ static int msix_setup_entries(struct pci_dev *dev, void __iomem *base,
                        entry->msi_attrib.entry_nr = entries[i].entry;
                else
                        entry->msi_attrib.entry_nr = i;
+
+               entry->msi_attrib.is_virtual =
+                       entry->msi_attrib.entry_nr >= vec_count;
+
                entry->msi_attrib.default_irq   = dev->irq;
                entry->mask_base                = base;
 
@@ -714,12 +742,19 @@ static void msix_program_entries(struct pci_dev *dev,
 {
        struct msi_desc *entry;
        int i = 0;
+       void __iomem *desc_addr;
 
        for_each_pci_msi_entry(entry, dev) {
                if (entries)
                        entries[i++].vector = entry->irq;
-               entry->masked = readl(pci_msix_desc_addr(entry) +
-                               PCI_MSIX_ENTRY_VECTOR_CTRL);
+
+               desc_addr = pci_msix_desc_addr(entry);
+               if (desc_addr)
+                       entry->masked = readl(desc_addr +
+                                             PCI_MSIX_ENTRY_VECTOR_CTRL);
+               else
+                       entry->masked = 0;
+
                msix_mask_irq(entry, 1);
        }
 }
@@ -932,7 +967,7 @@ int pci_msix_vec_count(struct pci_dev *dev)
 EXPORT_SYMBOL(pci_msix_vec_count);
 
 static int __pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries,
-                            int nvec, struct irq_affinity *affd)
+                            int nvec, struct irq_affinity *affd, int flags)
 {
        int nr_entries;
        int i, j;
@@ -943,7 +978,7 @@ static int __pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries,
        nr_entries = pci_msix_vec_count(dev);
        if (nr_entries < 0)
                return nr_entries;
-       if (nvec > nr_entries)
+       if (nvec > nr_entries && !(flags & PCI_IRQ_VIRTUAL))
                return nr_entries;
 
        if (entries) {
@@ -1079,7 +1114,8 @@ EXPORT_SYMBOL(pci_enable_msi);
 
 static int __pci_enable_msix_range(struct pci_dev *dev,
                                   struct msix_entry *entries, int minvec,
-                                  int maxvec, struct irq_affinity *affd)
+                                  int maxvec, struct irq_affinity *affd,
+                                  int flags)
 {
        int rc, nvec = maxvec;
 
@@ -1096,7 +1132,7 @@ static int __pci_enable_msix_range(struct pci_dev *dev,
                                return -ENOSPC;
                }
 
-               rc = __pci_enable_msix(dev, entries, nvec, affd);
+               rc = __pci_enable_msix(dev, entries, nvec, affd, flags);
                if (rc == 0)
                        return nvec;
 
@@ -1127,7 +1163,7 @@ static int __pci_enable_msix_range(struct pci_dev *dev,
 int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
                int minvec, int maxvec)
 {
-       return __pci_enable_msix_range(dev, entries, minvec, maxvec, NULL);
+       return __pci_enable_msix_range(dev, entries, minvec, maxvec, NULL, 0);
 }
 EXPORT_SYMBOL(pci_enable_msix_range);
 
@@ -1167,7 +1203,7 @@ int pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs,
 
        if (flags & PCI_IRQ_MSIX) {
                msix_vecs = __pci_enable_msix_range(dev, NULL, min_vecs,
-                                                   max_vecs, affd);
+                                                   max_vecs, affd, flags);
                if (msix_vecs > 0)
                        return msix_vecs;
        }
index 73d5ade..bc7b27a 100644 (file)
@@ -22,12 +22,15 @@ void pci_set_of_node(struct pci_dev *dev)
                return;
        dev->dev.of_node = of_pci_find_child_device(dev->bus->dev.of_node,
                                                    dev->devfn);
+       if (dev->dev.of_node)
+               dev->dev.fwnode = &dev->dev.of_node->fwnode;
 }
 
 void pci_release_of_node(struct pci_dev *dev)
 {
        of_node_put(dev->dev.of_node);
        dev->dev.of_node = NULL;
+       dev->dev.fwnode = NULL;
 }
 
 void pci_set_bus_of_node(struct pci_bus *bus)
@@ -41,13 +44,18 @@ void pci_set_bus_of_node(struct pci_bus *bus)
                if (node && of_property_read_bool(node, "external-facing"))
                        bus->self->untrusted = true;
        }
+
        bus->dev.of_node = node;
+
+       if (bus->dev.of_node)
+               bus->dev.fwnode = &bus->dev.of_node->fwnode;
 }
 
 void pci_release_bus_of_node(struct pci_bus *bus)
 {
        of_node_put(bus->dev.of_node);
        bus->dev.of_node = NULL;
+       bus->dev.fwnode = NULL;
 }
 
 struct device_node * __weak pcibios_get_phb_of_node(struct pci_bus *bus)
index aee28a5..d370f4c 100644 (file)
@@ -9,7 +9,7 @@ config PCI_SW_SWITCHTEC
         Enables support for the management interface for the MicroSemi
         Switchtec series of PCIe switches. Supports userspace access
         to submit MRPC commands to the switch via /dev/switchtecX
-        devices. See <file:Documentation/switchtec.txt> for more
+        devices. See <file:Documentation/driver-api/switchtec.rst> for more
         information.
 
 endmenu
index bebbde4..8c94cd3 100644 (file)
@@ -30,6 +30,10 @@ module_param(use_dma_mrpc, bool, 0644);
 MODULE_PARM_DESC(use_dma_mrpc,
                 "Enable the use of the DMA MRPC feature");
 
+static int nirqs = 32;
+module_param(nirqs, int, 0644);
+MODULE_PARM_DESC(nirqs, "number of interrupts to allocate (more may be useful for NTB applications)");
+
 static dev_t switchtec_devt;
 static DEFINE_IDA(switchtec_minor_ida);
 
@@ -1263,8 +1267,12 @@ static int switchtec_init_isr(struct switchtec_dev *stdev)
        int dma_mrpc_irq;
        int rc;
 
-       nvecs = pci_alloc_irq_vectors(stdev->pdev, 1, 4,
-                                     PCI_IRQ_MSIX | PCI_IRQ_MSI);
+       if (nirqs < 4)
+               nirqs = 4;
+
+       nvecs = pci_alloc_irq_vectors(stdev->pdev, 1, nirqs,
+                                     PCI_IRQ_MSIX | PCI_IRQ_MSI |
+                                     PCI_IRQ_VIRTUAL);
        if (nvecs < 0)
                return nvecs;
 
index 15b8c10..656e830 100644 (file)
@@ -8,7 +8,7 @@
  * the slices. User space needs to aggregate to individual counts to provide
  * a global picture.
  *
- * See Documentation/perf/qcom_l3_pmu.txt for more details.
+ * See Documentation/admin-guide/perf/qcom_l3_pmu.rst for more details.
  *
  * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
  */
index cc29fe7..1b67bb5 100644 (file)
@@ -118,7 +118,7 @@ config DCDBAS
          Interrupts (SMIs) and Host Control Actions (system power cycle or
          power off after OS shutdown) on certain Dell systems.
 
-         See <file:Documentation/dcdbas.txt> for more details on the driver
+         See <file:Documentation/driver-api/dcdbas.rst> for more details on the driver
          and the Dell systems on which Dell systems management software makes
          use of this driver.
 
@@ -259,7 +259,7 @@ config DELL_RBU
         DELL system. Note you need a Dell OpenManage or Dell Update package (DUP)
         supporting application to communicate with the BIOS regarding the new
         image for the image update to take effect.
-        See <file:Documentation/dell_rbu.txt> for more details on the driver.
+        See <file:Documentation/driver-api/dell_rbu.rst> for more details on the driver.
 
 
 config FUJITSU_LAPTOP
@@ -448,7 +448,7 @@ config SONY_LAPTOP
          screen brightness control, Fn keys and allows powering on/off some
          devices.
 
-         Read <file:Documentation/laptops/sony-laptop.txt> for more information.
+         Read <file:Documentation/admin-guide/laptops/sony-laptop.rst> for more information.
 
 config SONYPI_COMPAT
        bool "Sonypi compatibility"
@@ -500,7 +500,7 @@ config THINKPAD_ACPI
          support for Fn-Fx key combinations, Bluetooth control, video
          output switching, ThinkLight control, UltraBay eject and more.
          For more information about this driver see
-         <file:Documentation/laptops/thinkpad-acpi.txt> and
+         <file:Documentation/admin-guide/laptops/thinkpad-acpi.rst> and
          <http://ibm-acpi.sf.net/> .
 
          This driver was formerly known as ibm-acpi.
index 18f3a8b..ca28d27 100644 (file)
@@ -68,12 +68,12 @@ MODULE_LICENSE("GPL");
 #define ASUS_FAN_CTRL_MANUAL           1
 #define ASUS_FAN_CTRL_AUTO             2
 
-#define ASUS_FAN_MODE_NORMAL           0
-#define ASUS_FAN_MODE_OVERBOOST                1
-#define ASUS_FAN_MODE_OVERBOOST_MASK   0x01
-#define ASUS_FAN_MODE_SILENT           2
-#define ASUS_FAN_MODE_SILENT_MASK      0x02
-#define ASUS_FAN_MODES_MASK            0x03
+#define ASUS_FAN_BOOST_MODE_NORMAL             0
+#define ASUS_FAN_BOOST_MODE_OVERBOOST          1
+#define ASUS_FAN_BOOST_MODE_OVERBOOST_MASK     0x01
+#define ASUS_FAN_BOOST_MODE_SILENT             2
+#define ASUS_FAN_BOOST_MODE_SILENT_MASK                0x02
+#define ASUS_FAN_BOOST_MODES_MASK              0x03
 
 #define USB_INTEL_XUSB2PR              0xD0
 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI  0x9c31
@@ -182,9 +182,9 @@ struct asus_wmi {
        int asus_hwmon_num_fans;
        int asus_hwmon_pwm;
 
-       bool fan_mode_available;
-       u8 fan_mode_mask;
-       u8 fan_mode;
+       bool fan_boost_mode_available;
+       u8 fan_boost_mode_mask;
+       u8 fan_boost_mode;
 
        struct hotplug_slot hotplug_slot;
        struct mutex hotplug_lock;
@@ -1487,14 +1487,15 @@ static int asus_wmi_fan_init(struct asus_wmi *asus)
 
 /* Fan mode *******************************************************************/
 
-static int fan_mode_check_present(struct asus_wmi *asus)
+static int fan_boost_mode_check_present(struct asus_wmi *asus)
 {
        u32 result;
        int err;
 
-       asus->fan_mode_available = false;
+       asus->fan_boost_mode_available = false;
 
-       err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_MODE, &result);
+       err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_BOOST_MODE,
+                                   &result);
        if (err) {
                if (err == -ENODEV)
                        return 0;
@@ -1503,72 +1504,77 @@ static int fan_mode_check_present(struct asus_wmi *asus)
        }
 
        if ((result & ASUS_WMI_DSTS_PRESENCE_BIT) &&
-                       (result & ASUS_FAN_MODES_MASK)) {
-               asus->fan_mode_available = true;
-               asus->fan_mode_mask = result & ASUS_FAN_MODES_MASK;
+                       (result & ASUS_FAN_BOOST_MODES_MASK)) {
+               asus->fan_boost_mode_available = true;
+               asus->fan_boost_mode_mask = result & ASUS_FAN_BOOST_MODES_MASK;
        }
 
        return 0;
 }
 
-static int fan_mode_write(struct asus_wmi *asus)
+static int fan_boost_mode_write(struct asus_wmi *asus)
 {
        int err;
        u8 value;
        u32 retval;
 
-       value = asus->fan_mode;
+       value = asus->fan_boost_mode;
 
-       pr_info("Set fan mode: %u\n", value);
-       err = asus_wmi_set_devstate(ASUS_WMI_DEVID_FAN_MODE, value, &retval);
+       pr_info("Set fan boost mode: %u\n", value);
+       err = asus_wmi_set_devstate(ASUS_WMI_DEVID_FAN_BOOST_MODE, value,
+                                   &retval);
 
        if (err) {
-               pr_warn("Failed to set fan mode: %d\n", err);
+               pr_warn("Failed to set fan boost mode: %d\n", err);
                return err;
        }
 
        if (retval != 1) {
-               pr_warn("Failed to set fan mode (retval): 0x%x\n", retval);
+               pr_warn("Failed to set fan boost mode (retval): 0x%x\n",
+                       retval);
                return -EIO;
        }
 
        return 0;
 }
 
-static int fan_mode_switch_next(struct asus_wmi *asus)
+static int fan_boost_mode_switch_next(struct asus_wmi *asus)
 {
-       if (asus->fan_mode == ASUS_FAN_MODE_NORMAL) {
-               if (asus->fan_mode_mask & ASUS_FAN_MODE_OVERBOOST_MASK)
-                       asus->fan_mode = ASUS_FAN_MODE_OVERBOOST;
-               else if (asus->fan_mode_mask & ASUS_FAN_MODE_SILENT_MASK)
-                       asus->fan_mode = ASUS_FAN_MODE_SILENT;
-       } else if (asus->fan_mode == ASUS_FAN_MODE_OVERBOOST) {
-               if (asus->fan_mode_mask & ASUS_FAN_MODE_SILENT_MASK)
-                       asus->fan_mode = ASUS_FAN_MODE_SILENT;
+       u8 mask = asus->fan_boost_mode_mask;
+
+       if (asus->fan_boost_mode == ASUS_FAN_BOOST_MODE_NORMAL) {
+               if (mask & ASUS_FAN_BOOST_MODE_OVERBOOST_MASK)
+                       asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_OVERBOOST;
+               else if (mask & ASUS_FAN_BOOST_MODE_SILENT_MASK)
+                       asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_SILENT;
+       } else if (asus->fan_boost_mode == ASUS_FAN_BOOST_MODE_OVERBOOST) {
+               if (mask & ASUS_FAN_BOOST_MODE_SILENT_MASK)
+                       asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_SILENT;
                else
-                       asus->fan_mode = ASUS_FAN_MODE_NORMAL;
+                       asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_NORMAL;
        } else {
-               asus->fan_mode = ASUS_FAN_MODE_NORMAL;
+               asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_NORMAL;
        }
 
-       return fan_mode_write(asus);
+       return fan_boost_mode_write(asus);
 }
 
-static ssize_t fan_mode_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static ssize_t fan_boost_mode_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
 {
        struct asus_wmi *asus = dev_get_drvdata(dev);
 
-       return scnprintf(buf, PAGE_SIZE, "%d\n", asus->fan_mode);
+       return scnprintf(buf, PAGE_SIZE, "%d\n", asus->fan_boost_mode);
 }
 
-static ssize_t fan_mode_store(struct device *dev, struct device_attribute *attr,
-               const char *buf, size_t count)
+static ssize_t fan_boost_mode_store(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count)
 {
        int result;
        u8 new_mode;
-
        struct asus_wmi *asus = dev_get_drvdata(dev);
+       u8 mask = asus->fan_boost_mode_mask;
 
        result = kstrtou8(buf, 10, &new_mode);
        if (result < 0) {
@@ -1576,24 +1582,24 @@ static ssize_t fan_mode_store(struct device *dev, struct device_attribute *attr,
                return result;
        }
 
-       if (new_mode == ASUS_FAN_MODE_OVERBOOST) {
-               if (!(asus->fan_mode_mask & ASUS_FAN_MODE_OVERBOOST_MASK))
+       if (new_mode == ASUS_FAN_BOOST_MODE_OVERBOOST) {
+               if (!(mask & ASUS_FAN_BOOST_MODE_OVERBOOST_MASK))
                        return -EINVAL;
-       } else if (new_mode == ASUS_FAN_MODE_SILENT) {
-               if (!(asus->fan_mode_mask & ASUS_FAN_MODE_SILENT_MASK))
+       } else if (new_mode == ASUS_FAN_BOOST_MODE_SILENT) {
+               if (!(mask & ASUS_FAN_BOOST_MODE_SILENT_MASK))
                        return -EINVAL;
-       } else if (new_mode != ASUS_FAN_MODE_NORMAL) {
+       } else if (new_mode != ASUS_FAN_BOOST_MODE_NORMAL) {
                return -EINVAL;
        }
 
-       asus->fan_mode = new_mode;
-       fan_mode_write(asus);
+       asus->fan_boost_mode = new_mode;
+       fan_boost_mode_write(asus);
 
        return result;
 }
 
-// Fan mode: 0 - normal, 1 - overboost, 2 - silent
-static DEVICE_ATTR_RW(fan_mode);
+// Fan boost mode: 0 - normal, 1 - overboost, 2 - silent
+static DEVICE_ATTR_RW(fan_boost_mode);
 
 /* Backlight ******************************************************************/
 
@@ -1873,8 +1879,8 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
                return;
        }
 
-       if (asus->fan_mode_available && code == NOTIFY_KBD_FBM) {
-               fan_mode_switch_next(asus);
+       if (asus->fan_boost_mode_available && code == NOTIFY_KBD_FBM) {
+               fan_boost_mode_switch_next(asus);
                return;
        }
 
@@ -2034,7 +2040,7 @@ static struct attribute *platform_attributes[] = {
        &dev_attr_touchpad.attr,
        &dev_attr_lid_resume.attr,
        &dev_attr_als_enable.attr,
-       &dev_attr_fan_mode.attr,
+       &dev_attr_fan_boost_mode.attr,
        NULL
 };
 
@@ -2056,8 +2062,8 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
                devid = ASUS_WMI_DEVID_LID_RESUME;
        else if (attr == &dev_attr_als_enable.attr)
                devid = ASUS_WMI_DEVID_ALS_ENABLE;
-       else if (attr == &dev_attr_fan_mode.attr)
-               ok = asus->fan_mode_available;
+       else if (attr == &dev_attr_fan_boost_mode.attr)
+               ok = asus->fan_boost_mode_available;
 
        if (devid != -1)
                ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0);
@@ -2315,9 +2321,9 @@ static int asus_wmi_add(struct platform_device *pdev)
        if (err)
                goto fail_platform;
 
-       err = fan_mode_check_present(asus);
+       err = fan_boost_mode_check_present(asus);
        if (err)
-               goto fail_fan_mode;
+               goto fail_fan_boost_mode;
 
        err = asus_wmi_sysfs_init(asus->platform_device);
        if (err)
@@ -2402,7 +2408,7 @@ fail_hwmon:
 fail_input:
        asus_wmi_sysfs_exit(asus->platform_device);
 fail_sysfs:
-fail_fan_mode:
+fail_fan_boost_mode:
 fail_platform:
        kfree(asus);
        return err;
index 12cf947..84f4cc8 100644 (file)
@@ -7,7 +7,7 @@
  *  and Host Control Actions (power cycle or power off after OS shutdown) on
  *  Dell systems.
  *
- *  See Documentation/dcdbas.txt for more information.
+ *  See Documentation/driver-api/dcdbas.rst for more information.
  *
  *  Copyright (C) 1995-2006 Dell Inc.
  */
index a58fc10..3691391 100644 (file)
@@ -24,7 +24,7 @@
  * on every time the packet data is written. This driver requires an
  * application to break the BIOS image in to fixed sized packet chunks.
  *
- * See Documentation/dell_rbu.txt for more info.
+ * See Documentation/driver-api/dell_rbu.rst for more info.
  */
 #include <linux/init.h>
 #include <linux/module.h>
index 4b58a3d..d0479a5 100644 (file)
@@ -7,6 +7,6 @@ config ISAPNP
        depends on ISA || COMPILE_TEST
        help
          Say Y here if you would like support for ISA Plug and Play devices.
-         Some information is in <file:Documentation/isapnp.txt>.
+         Some information is in <file:Documentation/driver-api/isapnp.rst>.
 
          If unsure, say Y.
index 42d3798..dc1c138 100644 (file)
@@ -16,14 +16,17 @@ menuconfig POWERCAP
 
 if POWERCAP
 # Client driver configurations go here.
+config INTEL_RAPL_CORE
+       tristate
+
 config INTEL_RAPL
-       tristate "Intel RAPL Support"
+       tristate "Intel RAPL Support via MSR Interface"
        depends on X86 && IOSF_MBI
-       default n
+       select INTEL_RAPL_CORE
        ---help---
          This enables support for the Intel Running Average Power Limit (RAPL)
-         technology which allows power limits to be enforced and monitored on
-         modern Intel processors (Sandy Bridge and later).
+         technology via MSR interface, which allows power limits to be enforced
+         and monitored on modern Intel processors (Sandy Bridge and later).
 
          In RAPL, the platform level settings are divided into domains for
          fine grained control. These domains include processor package, DRAM
index 81c8cca..7255c94 100644 (file)
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_POWERCAP) += powercap_sys.o
-obj-$(CONFIG_INTEL_RAPL) += intel_rapl.o
+obj-$(CONFIG_INTEL_RAPL_CORE) += intel_rapl_common.o
+obj-$(CONFIG_INTEL_RAPL) += intel_rapl_msr.o
 obj-$(CONFIG_IDLE_INJECT) += idle_inject.o
diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c
deleted file mode 100644 (file)
index 8692f6b..0000000
+++ /dev/null
@@ -1,1669 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Intel Running Average Power Limit (RAPL) Driver
- * Copyright (c) 2013, Intel Corporation.
- */
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/list.h>
-#include <linux/types.h>
-#include <linux/device.h>
-#include <linux/slab.h>
-#include <linux/log2.h>
-#include <linux/bitmap.h>
-#include <linux/delay.h>
-#include <linux/sysfs.h>
-#include <linux/cpu.h>
-#include <linux/powercap.h>
-#include <linux/suspend.h>
-#include <asm/iosf_mbi.h>
-
-#include <asm/processor.h>
-#include <asm/cpu_device_id.h>
-#include <asm/intel-family.h>
-
-/* Local defines */
-#define MSR_PLATFORM_POWER_LIMIT       0x0000065C
-
-/* bitmasks for RAPL MSRs, used by primitive access functions */
-#define ENERGY_STATUS_MASK      0xffffffff
-
-#define POWER_LIMIT1_MASK       0x7FFF
-#define POWER_LIMIT1_ENABLE     BIT(15)
-#define POWER_LIMIT1_CLAMP      BIT(16)
-
-#define POWER_LIMIT2_MASK       (0x7FFFULL<<32)
-#define POWER_LIMIT2_ENABLE     BIT_ULL(47)
-#define POWER_LIMIT2_CLAMP      BIT_ULL(48)
-#define POWER_PACKAGE_LOCK      BIT_ULL(63)
-#define POWER_PP_LOCK           BIT(31)
-
-#define TIME_WINDOW1_MASK       (0x7FULL<<17)
-#define TIME_WINDOW2_MASK       (0x7FULL<<49)
-
-#define POWER_UNIT_OFFSET      0
-#define POWER_UNIT_MASK                0x0F
-
-#define ENERGY_UNIT_OFFSET     0x08
-#define ENERGY_UNIT_MASK       0x1F00
-
-#define TIME_UNIT_OFFSET       0x10
-#define TIME_UNIT_MASK         0xF0000
-
-#define POWER_INFO_MAX_MASK     (0x7fffULL<<32)
-#define POWER_INFO_MIN_MASK     (0x7fffULL<<16)
-#define POWER_INFO_MAX_TIME_WIN_MASK     (0x3fULL<<48)
-#define POWER_INFO_THERMAL_SPEC_MASK     0x7fff
-
-#define PERF_STATUS_THROTTLE_TIME_MASK 0xffffffff
-#define PP_POLICY_MASK         0x1F
-
-/* Non HW constants */
-#define RAPL_PRIMITIVE_DERIVED       BIT(1) /* not from raw data */
-#define RAPL_PRIMITIVE_DUMMY         BIT(2)
-
-#define TIME_WINDOW_MAX_MSEC 40000
-#define TIME_WINDOW_MIN_MSEC 250
-#define ENERGY_UNIT_SCALE    1000 /* scale from driver unit to powercap unit */
-enum unit_type {
-       ARBITRARY_UNIT, /* no translation */
-       POWER_UNIT,
-       ENERGY_UNIT,
-       TIME_UNIT,
-};
-
-enum rapl_domain_type {
-       RAPL_DOMAIN_PACKAGE, /* entire package/socket */
-       RAPL_DOMAIN_PP0, /* core power plane */
-       RAPL_DOMAIN_PP1, /* graphics uncore */
-       RAPL_DOMAIN_DRAM,/* DRAM control_type */
-       RAPL_DOMAIN_PLATFORM, /* PSys control_type */
-       RAPL_DOMAIN_MAX,
-};
-
-enum rapl_domain_msr_id {
-       RAPL_DOMAIN_MSR_LIMIT,
-       RAPL_DOMAIN_MSR_STATUS,
-       RAPL_DOMAIN_MSR_PERF,
-       RAPL_DOMAIN_MSR_POLICY,
-       RAPL_DOMAIN_MSR_INFO,
-       RAPL_DOMAIN_MSR_MAX,
-};
-
-/* per domain data, some are optional */
-enum rapl_primitives {
-       ENERGY_COUNTER,
-       POWER_LIMIT1,
-       POWER_LIMIT2,
-       FW_LOCK,
-
-       PL1_ENABLE,  /* power limit 1, aka long term */
-       PL1_CLAMP,   /* allow frequency to go below OS request */
-       PL2_ENABLE,  /* power limit 2, aka short term, instantaneous */
-       PL2_CLAMP,
-
-       TIME_WINDOW1, /* long term */
-       TIME_WINDOW2, /* short term */
-       THERMAL_SPEC_POWER,
-       MAX_POWER,
-
-       MIN_POWER,
-       MAX_TIME_WINDOW,
-       THROTTLED_TIME,
-       PRIORITY_LEVEL,
-
-       /* below are not raw primitive data */
-       AVERAGE_POWER,
-       NR_RAPL_PRIMITIVES,
-};
-
-#define NR_RAW_PRIMITIVES (NR_RAPL_PRIMITIVES - 2)
-
-/* Can be expanded to include events, etc.*/
-struct rapl_domain_data {
-       u64 primitives[NR_RAPL_PRIMITIVES];
-       unsigned long timestamp;
-};
-
-struct msrl_action {
-       u32 msr_no;
-       u64 clear_mask;
-       u64 set_mask;
-       int err;
-};
-
-#define        DOMAIN_STATE_INACTIVE           BIT(0)
-#define        DOMAIN_STATE_POWER_LIMIT_SET    BIT(1)
-#define DOMAIN_STATE_BIOS_LOCKED        BIT(2)
-
-#define NR_POWER_LIMITS (2)
-struct rapl_power_limit {
-       struct powercap_zone_constraint *constraint;
-       int prim_id; /* primitive ID used to enable */
-       struct rapl_domain *domain;
-       const char *name;
-       u64 last_power_limit;
-};
-
-static const char pl1_name[] = "long_term";
-static const char pl2_name[] = "short_term";
-
-struct rapl_package;
-struct rapl_domain {
-       const char *name;
-       enum rapl_domain_type id;
-       int msrs[RAPL_DOMAIN_MSR_MAX];
-       struct powercap_zone power_zone;
-       struct rapl_domain_data rdd;
-       struct rapl_power_limit rpl[NR_POWER_LIMITS];
-       u64 attr_map; /* track capabilities */
-       unsigned int state;
-       unsigned int domain_energy_unit;
-       struct rapl_package *rp;
-};
-#define power_zone_to_rapl_domain(_zone) \
-       container_of(_zone, struct rapl_domain, power_zone)
-
-/* maximum rapl package domain name: package-%d-die-%d */
-#define PACKAGE_DOMAIN_NAME_LENGTH 30
-
-
-/* Each rapl package contains multiple domains, these are the common
- * data across RAPL domains within a package.
- */
-struct rapl_package {
-       unsigned int id; /* logical die id, equals physical 1-die systems */
-       unsigned int nr_domains;
-       unsigned long domain_map; /* bit map of active domains */
-       unsigned int power_unit;
-       unsigned int energy_unit;
-       unsigned int time_unit;
-       struct rapl_domain *domains; /* array of domains, sized at runtime */
-       struct powercap_zone *power_zone; /* keep track of parent zone */
-       unsigned long power_limit_irq; /* keep track of package power limit
-                                       * notify interrupt enable status.
-                                       */
-       struct list_head plist;
-       int lead_cpu; /* one active cpu per package for access */
-       /* Track active cpus */
-       struct cpumask cpumask;
-       char name[PACKAGE_DOMAIN_NAME_LENGTH];
-};
-
-struct rapl_defaults {
-       u8 floor_freq_reg_addr;
-       int (*check_unit)(struct rapl_package *rp, int cpu);
-       void (*set_floor_freq)(struct rapl_domain *rd, bool mode);
-       u64 (*compute_time_window)(struct rapl_package *rp, u64 val,
-                               bool to_raw);
-       unsigned int dram_domain_energy_unit;
-};
-static struct rapl_defaults *rapl_defaults;
-
-/* Sideband MBI registers */
-#define IOSF_CPU_POWER_BUDGET_CTL_BYT (0x2)
-#define IOSF_CPU_POWER_BUDGET_CTL_TNG (0xdf)
-
-#define PACKAGE_PLN_INT_SAVED   BIT(0)
-#define MAX_PRIM_NAME (32)
-
-/* per domain data. used to describe individual knobs such that access function
- * can be consolidated into one instead of many inline functions.
- */
-struct rapl_primitive_info {
-       const char *name;
-       u64 mask;
-       int shift;
-       enum rapl_domain_msr_id id;
-       enum unit_type unit;
-       u32 flag;
-};
-
-#define PRIMITIVE_INFO_INIT(p, m, s, i, u, f) {        \
-               .name = #p,                     \
-               .mask = m,                      \
-               .shift = s,                     \
-               .id = i,                        \
-               .unit = u,                      \
-               .flag = f                       \
-       }
-
-static void rapl_init_domains(struct rapl_package *rp);
-static int rapl_read_data_raw(struct rapl_domain *rd,
-                       enum rapl_primitives prim,
-                       bool xlate, u64 *data);
-static int rapl_write_data_raw(struct rapl_domain *rd,
-                       enum rapl_primitives prim,
-                       unsigned long long value);
-static u64 rapl_unit_xlate(struct rapl_domain *rd,
-                       enum unit_type type, u64 value,
-                       int to_raw);
-static void package_power_limit_irq_save(struct rapl_package *rp);
-
-static LIST_HEAD(rapl_packages); /* guarded by CPU hotplug lock */
-
-static const char * const rapl_domain_names[] = {
-       "package",
-       "core",
-       "uncore",
-       "dram",
-       "psys",
-};
-
-static struct powercap_control_type *control_type; /* PowerCap Controller */
-static struct rapl_domain *platform_rapl_domain; /* Platform (PSys) domain */
-
-/* caller to ensure CPU hotplug lock is held */
-static struct rapl_package *rapl_find_package_domain(int cpu)
-{
-       int id = topology_logical_die_id(cpu);
-       struct rapl_package *rp;
-
-       list_for_each_entry(rp, &rapl_packages, plist) {
-               if (rp->id == id)
-                       return rp;
-       }
-
-       return NULL;
-}
-
-static int get_energy_counter(struct powercap_zone *power_zone, u64 *energy_raw)
-{
-       struct rapl_domain *rd;
-       u64 energy_now;
-
-       /* prevent CPU hotplug, make sure the RAPL domain does not go
-        * away while reading the counter.
-        */
-       get_online_cpus();
-       rd = power_zone_to_rapl_domain(power_zone);
-
-       if (!rapl_read_data_raw(rd, ENERGY_COUNTER, true, &energy_now)) {
-               *energy_raw = energy_now;
-               put_online_cpus();
-
-               return 0;
-       }
-       put_online_cpus();
-
-       return -EIO;
-}
-
-static int get_max_energy_counter(struct powercap_zone *pcd_dev, u64 *energy)
-{
-       struct rapl_domain *rd = power_zone_to_rapl_domain(pcd_dev);
-
-       *energy = rapl_unit_xlate(rd, ENERGY_UNIT, ENERGY_STATUS_MASK, 0);
-       return 0;
-}
-
-static int release_zone(struct powercap_zone *power_zone)
-{
-       struct rapl_domain *rd = power_zone_to_rapl_domain(power_zone);
-       struct rapl_package *rp = rd->rp;
-
-       /* package zone is the last zone of a package, we can free
-        * memory here since all children has been unregistered.
-        */
-       if (rd->id == RAPL_DOMAIN_PACKAGE) {
-               kfree(rd);
-               rp->domains = NULL;
-       }
-
-       return 0;
-
-}
-
-static int find_nr_power_limit(struct rapl_domain *rd)
-{
-       int i, nr_pl = 0;
-
-       for (i = 0; i < NR_POWER_LIMITS; i++) {
-               if (rd->rpl[i].name)
-                       nr_pl++;
-       }
-
-       return nr_pl;
-}
-
-static int set_domain_enable(struct powercap_zone *power_zone, bool mode)
-{
-       struct rapl_domain *rd = power_zone_to_rapl_domain(power_zone);
-
-       if (rd->state & DOMAIN_STATE_BIOS_LOCKED)
-               return -EACCES;
-
-       get_online_cpus();
-       rapl_write_data_raw(rd, PL1_ENABLE, mode);
-       if (rapl_defaults->set_floor_freq)
-               rapl_defaults->set_floor_freq(rd, mode);
-       put_online_cpus();
-
-       return 0;
-}
-
-static int get_domain_enable(struct powercap_zone *power_zone, bool *mode)
-{
-       struct rapl_domain *rd = power_zone_to_rapl_domain(power_zone);
-       u64 val;
-
-       if (rd->state & DOMAIN_STATE_BIOS_LOCKED) {
-               *mode = false;
-               return 0;
-       }
-       get_online_cpus();
-       if (rapl_read_data_raw(rd, PL1_ENABLE, true, &val)) {
-               put_online_cpus();
-               return -EIO;
-       }
-       *mode = val;
-       put_online_cpus();
-
-       return 0;
-}
-
-/* per RAPL domain ops, in the order of rapl_domain_type */
-static const struct powercap_zone_ops zone_ops[] = {
-       /* RAPL_DOMAIN_PACKAGE */
-       {
-               .get_energy_uj = get_energy_counter,
-               .get_max_energy_range_uj = get_max_energy_counter,
-               .release = release_zone,
-               .set_enable = set_domain_enable,
-               .get_enable = get_domain_enable,
-       },
-       /* RAPL_DOMAIN_PP0 */
-       {
-               .get_energy_uj = get_energy_counter,
-               .get_max_energy_range_uj = get_max_energy_counter,
-               .release = release_zone,
-               .set_enable = set_domain_enable,
-               .get_enable = get_domain_enable,
-       },
-       /* RAPL_DOMAIN_PP1 */
-       {
-               .get_energy_uj = get_energy_counter,
-               .get_max_energy_range_uj = get_max_energy_counter,
-               .release = release_zone,
-               .set_enable = set_domain_enable,
-               .get_enable = get_domain_enable,
-       },
-       /* RAPL_DOMAIN_DRAM */
-       {
-               .get_energy_uj = get_energy_counter,
-               .get_max_energy_range_uj = get_max_energy_counter,
-               .release = release_zone,
-               .set_enable = set_domain_enable,
-               .get_enable = get_domain_enable,
-       },
-       /* RAPL_DOMAIN_PLATFORM */
-       {
-               .get_energy_uj = get_energy_counter,
-               .get_max_energy_range_uj = get_max_energy_counter,
-               .release = release_zone,
-               .set_enable = set_domain_enable,
-               .get_enable = get_domain_enable,
-       },
-};
-
-
-/*
- * Constraint index used by powercap can be different than power limit (PL)
- * index in that some  PLs maybe missing due to non-existant MSRs. So we
- * need to convert here by finding the valid PLs only (name populated).
- */
-static int contraint_to_pl(struct rapl_domain *rd, int cid)
-{
-       int i, j;
-
-       for (i = 0, j = 0; i < NR_POWER_LIMITS; i++) {
-               if ((rd->rpl[i].name) && j++ == cid) {
-                       pr_debug("%s: index %d\n", __func__, i);
-                       return i;
-               }
-       }
-       pr_err("Cannot find matching power limit for constraint %d\n", cid);
-
-       return -EINVAL;
-}
-
-static int set_power_limit(struct powercap_zone *power_zone, int cid,
-                       u64 power_limit)
-{
-       struct rapl_domain *rd;
-       struct rapl_package *rp;
-       int ret = 0;
-       int id;
-
-       get_online_cpus();
-       rd = power_zone_to_rapl_domain(power_zone);
-       id = contraint_to_pl(rd, cid);
-       if (id < 0) {
-               ret = id;
-               goto set_exit;
-       }
-
-       rp = rd->rp;
-
-       if (rd->state & DOMAIN_STATE_BIOS_LOCKED) {
-               dev_warn(&power_zone->dev, "%s locked by BIOS, monitoring only\n",
-                       rd->name);
-               ret = -EACCES;
-               goto set_exit;
-       }
-
-       switch (rd->rpl[id].prim_id) {
-       case PL1_ENABLE:
-               rapl_write_data_raw(rd, POWER_LIMIT1, power_limit);
-               break;
-       case PL2_ENABLE:
-               rapl_write_data_raw(rd, POWER_LIMIT2, power_limit);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-       if (!ret)
-               package_power_limit_irq_save(rp);
-set_exit:
-       put_online_cpus();
-       return ret;
-}
-
-static int get_current_power_limit(struct powercap_zone *power_zone, int cid,
-                                       u64 *data)
-{
-       struct rapl_domain *rd;
-       u64 val;
-       int prim;
-       int ret = 0;
-       int id;
-
-       get_online_cpus();
-       rd = power_zone_to_rapl_domain(power_zone);
-       id = contraint_to_pl(rd, cid);
-       if (id < 0) {
-               ret = id;
-               goto get_exit;
-       }
-
-       switch (rd->rpl[id].prim_id) {
-       case PL1_ENABLE:
-               prim = POWER_LIMIT1;
-               break;
-       case PL2_ENABLE:
-               prim = POWER_LIMIT2;
-               break;
-       default:
-               put_online_cpus();
-               return -EINVAL;
-       }
-       if (rapl_read_data_raw(rd, prim, true, &val))
-               ret = -EIO;
-       else
-               *data = val;
-
-get_exit:
-       put_online_cpus();
-
-       return ret;
-}
-
-static int set_time_window(struct powercap_zone *power_zone, int cid,
-                                                               u64 window)
-{
-       struct rapl_domain *rd;
-       int ret = 0;
-       int id;
-
-       get_online_cpus();
-       rd = power_zone_to_rapl_domain(power_zone);
-       id = contraint_to_pl(rd, cid);
-       if (id < 0) {
-               ret = id;
-               goto set_time_exit;
-       }
-
-       switch (rd->rpl[id].prim_id) {
-       case PL1_ENABLE:
-               rapl_write_data_raw(rd, TIME_WINDOW1, window);
-               break;
-       case PL2_ENABLE:
-               rapl_write_data_raw(rd, TIME_WINDOW2, window);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-set_time_exit:
-       put_online_cpus();
-       return ret;
-}
-
-static int get_time_window(struct powercap_zone *power_zone, int cid, u64 *data)
-{
-       struct rapl_domain *rd;
-       u64 val;
-       int ret = 0;
-       int id;
-
-       get_online_cpus();
-       rd = power_zone_to_rapl_domain(power_zone);
-       id = contraint_to_pl(rd, cid);
-       if (id < 0) {
-               ret = id;
-               goto get_time_exit;
-       }
-
-       switch (rd->rpl[id].prim_id) {
-       case PL1_ENABLE:
-               ret = rapl_read_data_raw(rd, TIME_WINDOW1, true, &val);
-               break;
-       case PL2_ENABLE:
-               ret = rapl_read_data_raw(rd, TIME_WINDOW2, true, &val);
-               break;
-       default:
-               put_online_cpus();
-               return -EINVAL;
-       }
-       if (!ret)
-               *data = val;
-
-get_time_exit:
-       put_online_cpus();
-
-       return ret;
-}
-
-static const char *get_constraint_name(struct powercap_zone *power_zone, int cid)
-{
-       struct rapl_domain *rd;
-       int id;
-
-       rd = power_zone_to_rapl_domain(power_zone);
-       id = contraint_to_pl(rd, cid);
-       if (id >= 0)
-               return rd->rpl[id].name;
-
-       return NULL;
-}
-
-
-static int get_max_power(struct powercap_zone *power_zone, int id,
-                                       u64 *data)
-{
-       struct rapl_domain *rd;
-       u64 val;
-       int prim;
-       int ret = 0;
-
-       get_online_cpus();
-       rd = power_zone_to_rapl_domain(power_zone);
-       switch (rd->rpl[id].prim_id) {
-       case PL1_ENABLE:
-               prim = THERMAL_SPEC_POWER;
-               break;
-       case PL2_ENABLE:
-               prim = MAX_POWER;
-               break;
-       default:
-               put_online_cpus();
-               return -EINVAL;
-       }
-       if (rapl_read_data_raw(rd, prim, true, &val))
-               ret = -EIO;
-       else
-               *data = val;
-
-       put_online_cpus();
-
-       return ret;
-}
-
-static const struct powercap_zone_constraint_ops constraint_ops = {
-       .set_power_limit_uw = set_power_limit,
-       .get_power_limit_uw = get_current_power_limit,
-       .set_time_window_us = set_time_window,
-       .get_time_window_us = get_time_window,
-       .get_max_power_uw = get_max_power,
-       .get_name = get_constraint_name,
-};
-
-/* called after domain detection and package level data are set */
-static void rapl_init_domains(struct rapl_package *rp)
-{
-       int i;
-       struct rapl_domain *rd = rp->domains;
-
-       for (i = 0; i < RAPL_DOMAIN_MAX; i++) {
-               unsigned int mask = rp->domain_map & (1 << i);
-               switch (mask) {
-               case BIT(RAPL_DOMAIN_PACKAGE):
-                       rd->name = rapl_domain_names[RAPL_DOMAIN_PACKAGE];
-                       rd->id = RAPL_DOMAIN_PACKAGE;
-                       rd->msrs[0] = MSR_PKG_POWER_LIMIT;
-                       rd->msrs[1] = MSR_PKG_ENERGY_STATUS;
-                       rd->msrs[2] = MSR_PKG_PERF_STATUS;
-                       rd->msrs[3] = 0;
-                       rd->msrs[4] = MSR_PKG_POWER_INFO;
-                       rd->rpl[0].prim_id = PL1_ENABLE;
-                       rd->rpl[0].name = pl1_name;
-                       rd->rpl[1].prim_id = PL2_ENABLE;
-                       rd->rpl[1].name = pl2_name;
-                       break;
-               case BIT(RAPL_DOMAIN_PP0):
-                       rd->name = rapl_domain_names[RAPL_DOMAIN_PP0];
-                       rd->id = RAPL_DOMAIN_PP0;
-                       rd->msrs[0] = MSR_PP0_POWER_LIMIT;
-                       rd->msrs[1] = MSR_PP0_ENERGY_STATUS;
-                       rd->msrs[2] = 0;
-                       rd->msrs[3] = MSR_PP0_POLICY;
-                       rd->msrs[4] = 0;
-                       rd->rpl[0].prim_id = PL1_ENABLE;
-                       rd->rpl[0].name = pl1_name;
-                       break;
-               case BIT(RAPL_DOMAIN_PP1):
-                       rd->name = rapl_domain_names[RAPL_DOMAIN_PP1];
-                       rd->id = RAPL_DOMAIN_PP1;
-                       rd->msrs[0] = MSR_PP1_POWER_LIMIT;
-                       rd->msrs[1] = MSR_PP1_ENERGY_STATUS;
-                       rd->msrs[2] = 0;
-                       rd->msrs[3] = MSR_PP1_POLICY;
-                       rd->msrs[4] = 0;
-                       rd->rpl[0].prim_id = PL1_ENABLE;
-                       rd->rpl[0].name = pl1_name;
-                       break;
-               case BIT(RAPL_DOMAIN_DRAM):
-                       rd->name = rapl_domain_names[RAPL_DOMAIN_DRAM];
-                       rd->id = RAPL_DOMAIN_DRAM;
-                       rd->msrs[0] = MSR_DRAM_POWER_LIMIT;
-                       rd->msrs[1] = MSR_DRAM_ENERGY_STATUS;
-                       rd->msrs[2] = MSR_DRAM_PERF_STATUS;
-                       rd->msrs[3] = 0;
-                       rd->msrs[4] = MSR_DRAM_POWER_INFO;
-                       rd->rpl[0].prim_id = PL1_ENABLE;
-                       rd->rpl[0].name = pl1_name;
-                       rd->domain_energy_unit =
-                               rapl_defaults->dram_domain_energy_unit;
-                       if (rd->domain_energy_unit)
-                               pr_info("DRAM domain energy unit %dpj\n",
-                                       rd->domain_energy_unit);
-                       break;
-               }
-               if (mask) {
-                       rd->rp = rp;
-                       rd++;
-               }
-       }
-}
-
-static u64 rapl_unit_xlate(struct rapl_domain *rd, enum unit_type type,
-                       u64 value, int to_raw)
-{
-       u64 units = 1;
-       struct rapl_package *rp = rd->rp;
-       u64 scale = 1;
-
-       switch (type) {
-       case POWER_UNIT:
-               units = rp->power_unit;
-               break;
-       case ENERGY_UNIT:
-               scale = ENERGY_UNIT_SCALE;
-               /* per domain unit takes precedence */
-               if (rd->domain_energy_unit)
-                       units = rd->domain_energy_unit;
-               else
-                       units = rp->energy_unit;
-               break;
-       case TIME_UNIT:
-               return rapl_defaults->compute_time_window(rp, value, to_raw);
-       case ARBITRARY_UNIT:
-       default:
-               return value;
-       };
-
-       if (to_raw)
-               return div64_u64(value, units) * scale;
-
-       value *= units;
-
-       return div64_u64(value, scale);
-}
-
-/* in the order of enum rapl_primitives */
-static struct rapl_primitive_info rpi[] = {
-       /* name, mask, shift, msr index, unit divisor */
-       PRIMITIVE_INFO_INIT(ENERGY_COUNTER, ENERGY_STATUS_MASK, 0,
-                               RAPL_DOMAIN_MSR_STATUS, ENERGY_UNIT, 0),
-       PRIMITIVE_INFO_INIT(POWER_LIMIT1, POWER_LIMIT1_MASK, 0,
-                               RAPL_DOMAIN_MSR_LIMIT, POWER_UNIT, 0),
-       PRIMITIVE_INFO_INIT(POWER_LIMIT2, POWER_LIMIT2_MASK, 32,
-                               RAPL_DOMAIN_MSR_LIMIT, POWER_UNIT, 0),
-       PRIMITIVE_INFO_INIT(FW_LOCK, POWER_PP_LOCK, 31,
-                               RAPL_DOMAIN_MSR_LIMIT, ARBITRARY_UNIT, 0),
-       PRIMITIVE_INFO_INIT(PL1_ENABLE, POWER_LIMIT1_ENABLE, 15,
-                               RAPL_DOMAIN_MSR_LIMIT, ARBITRARY_UNIT, 0),
-       PRIMITIVE_INFO_INIT(PL1_CLAMP, POWER_LIMIT1_CLAMP, 16,
-                               RAPL_DOMAIN_MSR_LIMIT, ARBITRARY_UNIT, 0),
-       PRIMITIVE_INFO_INIT(PL2_ENABLE, POWER_LIMIT2_ENABLE, 47,
-                               RAPL_DOMAIN_MSR_LIMIT, ARBITRARY_UNIT, 0),
-       PRIMITIVE_INFO_INIT(PL2_CLAMP, POWER_LIMIT2_CLAMP, 48,
-                               RAPL_DOMAIN_MSR_LIMIT, ARBITRARY_UNIT, 0),
-       PRIMITIVE_INFO_INIT(TIME_WINDOW1, TIME_WINDOW1_MASK, 17,
-                               RAPL_DOMAIN_MSR_LIMIT, TIME_UNIT, 0),
-       PRIMITIVE_INFO_INIT(TIME_WINDOW2, TIME_WINDOW2_MASK, 49,
-                               RAPL_DOMAIN_MSR_LIMIT, TIME_UNIT, 0),
-       PRIMITIVE_INFO_INIT(THERMAL_SPEC_POWER, POWER_INFO_THERMAL_SPEC_MASK,
-                               0, RAPL_DOMAIN_MSR_INFO, POWER_UNIT, 0),
-       PRIMITIVE_INFO_INIT(MAX_POWER, POWER_INFO_MAX_MASK, 32,
-                               RAPL_DOMAIN_MSR_INFO, POWER_UNIT, 0),
-       PRIMITIVE_INFO_INIT(MIN_POWER, POWER_INFO_MIN_MASK, 16,
-                               RAPL_DOMAIN_MSR_INFO, POWER_UNIT, 0),
-       PRIMITIVE_INFO_INIT(MAX_TIME_WINDOW, POWER_INFO_MAX_TIME_WIN_MASK, 48,
-                               RAPL_DOMAIN_MSR_INFO, TIME_UNIT, 0),
-       PRIMITIVE_INFO_INIT(THROTTLED_TIME, PERF_STATUS_THROTTLE_TIME_MASK, 0,
-                               RAPL_DOMAIN_MSR_PERF, TIME_UNIT, 0),
-       PRIMITIVE_INFO_INIT(PRIORITY_LEVEL, PP_POLICY_MASK, 0,
-                               RAPL_DOMAIN_MSR_POLICY, ARBITRARY_UNIT, 0),
-       /* non-hardware */
-       PRIMITIVE_INFO_INIT(AVERAGE_POWER, 0, 0, 0, POWER_UNIT,
-                               RAPL_PRIMITIVE_DERIVED),
-       {NULL, 0, 0, 0},
-};
-
-/* Read primitive data based on its related struct rapl_primitive_info.
- * if xlate flag is set, return translated data based on data units, i.e.
- * time, energy, and power.
- * RAPL MSRs are non-architectual and are laid out not consistently across
- * domains. Here we use primitive info to allow writing consolidated access
- * functions.
- * For a given primitive, it is processed by MSR mask and shift. Unit conversion
- * is pre-assigned based on RAPL unit MSRs read at init time.
- * 63-------------------------- 31--------------------------- 0
- * |                           xxxxx (mask)                   |
- * |                                |<- shift ----------------|
- * 63-------------------------- 31--------------------------- 0
- */
-static int rapl_read_data_raw(struct rapl_domain *rd,
-                       enum rapl_primitives prim,
-                       bool xlate, u64 *data)
-{
-       u64 value, final;
-       u32 msr;
-       struct rapl_primitive_info *rp = &rpi[prim];
-       int cpu;
-
-       if (!rp->name || rp->flag & RAPL_PRIMITIVE_DUMMY)
-               return -EINVAL;
-
-       msr = rd->msrs[rp->id];
-       if (!msr)
-               return -EINVAL;
-
-       cpu = rd->rp->lead_cpu;
-
-       /* special-case package domain, which uses a different bit*/
-       if (prim == FW_LOCK && rd->id == RAPL_DOMAIN_PACKAGE) {
-               rp->mask = POWER_PACKAGE_LOCK;
-               rp->shift = 63;
-       }
-       /* non-hardware data are collected by the polling thread */
-       if (rp->flag & RAPL_PRIMITIVE_DERIVED) {
-               *data = rd->rdd.primitives[prim];
-               return 0;
-       }
-
-       if (rdmsrl_safe_on_cpu(cpu, msr, &value)) {
-               pr_debug("failed to read msr 0x%x on cpu %d\n", msr, cpu);
-               return -EIO;
-       }
-
-       final = value & rp->mask;
-       final = final >> rp->shift;
-       if (xlate)
-               *data = rapl_unit_xlate(rd, rp->unit, final, 0);
-       else
-               *data = final;
-
-       return 0;
-}
-
-
-static int msrl_update_safe(u32 msr_no, u64 clear_mask, u64 set_mask)
-{
-       int err;
-       u64 val;
-
-       err = rdmsrl_safe(msr_no, &val);
-       if (err)
-               goto out;
-
-       val &= ~clear_mask;
-       val |= set_mask;
-
-       err = wrmsrl_safe(msr_no, val);
-
-out:
-       return err;
-}
-
-static void msrl_update_func(void *info)
-{
-       struct msrl_action *ma = info;
-
-       ma->err = msrl_update_safe(ma->msr_no, ma->clear_mask, ma->set_mask);
-}
-
-/* Similar use of primitive info in the read counterpart */
-static int rapl_write_data_raw(struct rapl_domain *rd,
-                       enum rapl_primitives prim,
-                       unsigned long long value)
-{
-       struct rapl_primitive_info *rp = &rpi[prim];
-       int cpu;
-       u64 bits;
-       struct msrl_action ma;
-       int ret;
-
-       cpu = rd->rp->lead_cpu;
-       bits = rapl_unit_xlate(rd, rp->unit, value, 1);
-       bits <<= rp->shift;
-       bits &= rp->mask;
-
-       memset(&ma, 0, sizeof(ma));
-
-       ma.msr_no = rd->msrs[rp->id];
-       ma.clear_mask = rp->mask;
-       ma.set_mask = bits;
-
-       ret = smp_call_function_single(cpu, msrl_update_func, &ma, 1);
-       if (ret)
-               WARN_ON_ONCE(ret);
-       else
-               ret = ma.err;
-
-       return ret;
-}
-
-/*
- * Raw RAPL data stored in MSRs are in certain scales. We need to
- * convert them into standard units based on the units reported in
- * the RAPL unit MSRs. This is specific to CPUs as the method to
- * calculate units differ on different CPUs.
- * We convert the units to below format based on CPUs.
- * i.e.
- * energy unit: picoJoules  : Represented in picoJoules by default
- * power unit : microWatts  : Represented in milliWatts by default
- * time unit  : microseconds: Represented in seconds by default
- */
-static int rapl_check_unit_core(struct rapl_package *rp, int cpu)
-{
-       u64 msr_val;
-       u32 value;
-
-       if (rdmsrl_safe_on_cpu(cpu, MSR_RAPL_POWER_UNIT, &msr_val)) {
-               pr_err("Failed to read power unit MSR 0x%x on CPU %d, exit.\n",
-                       MSR_RAPL_POWER_UNIT, cpu);
-               return -ENODEV;
-       }
-
-       value = (msr_val & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
-       rp->energy_unit = ENERGY_UNIT_SCALE * 1000000 / (1 << value);
-
-       value = (msr_val & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET;
-       rp->power_unit = 1000000 / (1 << value);
-
-       value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
-       rp->time_unit = 1000000 / (1 << value);
-
-       pr_debug("Core CPU %s energy=%dpJ, time=%dus, power=%duW\n",
-               rp->name, rp->energy_unit, rp->time_unit, rp->power_unit);
-
-       return 0;
-}
-
-static int rapl_check_unit_atom(struct rapl_package *rp, int cpu)
-{
-       u64 msr_val;
-       u32 value;
-
-       if (rdmsrl_safe_on_cpu(cpu, MSR_RAPL_POWER_UNIT, &msr_val)) {
-               pr_err("Failed to read power unit MSR 0x%x on CPU %d, exit.\n",
-                       MSR_RAPL_POWER_UNIT, cpu);
-               return -ENODEV;
-       }
-       value = (msr_val & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
-       rp->energy_unit = ENERGY_UNIT_SCALE * 1 << value;
-
-       value = (msr_val & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET;
-       rp->power_unit = (1 << value) * 1000;
-
-       value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
-       rp->time_unit = 1000000 / (1 << value);
-
-       pr_debug("Atom %s energy=%dpJ, time=%dus, power=%duW\n",
-               rp->name, rp->energy_unit, rp->time_unit, rp->power_unit);
-
-       return 0;
-}
-
-static void power_limit_irq_save_cpu(void *info)
-{
-       u32 l, h = 0;
-       struct rapl_package *rp = (struct rapl_package *)info;
-
-       /* save the state of PLN irq mask bit before disabling it */
-       rdmsr_safe(MSR_IA32_PACKAGE_THERM_INTERRUPT, &l, &h);
-       if (!(rp->power_limit_irq & PACKAGE_PLN_INT_SAVED)) {
-               rp->power_limit_irq = l & PACKAGE_THERM_INT_PLN_ENABLE;
-               rp->power_limit_irq |= PACKAGE_PLN_INT_SAVED;
-       }
-       l &= ~PACKAGE_THERM_INT_PLN_ENABLE;
-       wrmsr_safe(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
-}
-
-
-/* REVISIT:
- * When package power limit is set artificially low by RAPL, LVT
- * thermal interrupt for package power limit should be ignored
- * since we are not really exceeding the real limit. The intention
- * is to avoid excessive interrupts while we are trying to save power.
- * A useful feature might be routing the package_power_limit interrupt
- * to userspace via eventfd. once we have a usecase, this is simple
- * to do by adding an atomic notifier.
- */
-
-static void package_power_limit_irq_save(struct rapl_package *rp)
-{
-       if (!boot_cpu_has(X86_FEATURE_PTS) || !boot_cpu_has(X86_FEATURE_PLN))
-               return;
-
-       smp_call_function_single(rp->lead_cpu, power_limit_irq_save_cpu, rp, 1);
-}
-
-/*
- * Restore per package power limit interrupt enable state. Called from cpu
- * hotplug code on package removal.
- */
-static void package_power_limit_irq_restore(struct rapl_package *rp)
-{
-       u32 l, h;
-
-       if (!boot_cpu_has(X86_FEATURE_PTS) || !boot_cpu_has(X86_FEATURE_PLN))
-               return;
-
-       /* irq enable state not saved, nothing to restore */
-       if (!(rp->power_limit_irq & PACKAGE_PLN_INT_SAVED))
-               return;
-
-       rdmsr_safe(MSR_IA32_PACKAGE_THERM_INTERRUPT, &l, &h);
-
-       if (rp->power_limit_irq & PACKAGE_THERM_INT_PLN_ENABLE)
-               l |= PACKAGE_THERM_INT_PLN_ENABLE;
-       else
-               l &= ~PACKAGE_THERM_INT_PLN_ENABLE;
-
-       wrmsr_safe(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
-}
-
-static void set_floor_freq_default(struct rapl_domain *rd, bool mode)
-{
-       int nr_powerlimit = find_nr_power_limit(rd);
-
-       /* always enable clamp such that p-state can go below OS requested
-        * range. power capping priority over guranteed frequency.
-        */
-       rapl_write_data_raw(rd, PL1_CLAMP, mode);
-
-       /* some domains have pl2 */
-       if (nr_powerlimit > 1) {
-               rapl_write_data_raw(rd, PL2_ENABLE, mode);
-               rapl_write_data_raw(rd, PL2_CLAMP, mode);
-       }
-}
-
-static void set_floor_freq_atom(struct rapl_domain *rd, bool enable)
-{
-       static u32 power_ctrl_orig_val;
-       u32 mdata;
-
-       if (!rapl_defaults->floor_freq_reg_addr) {
-               pr_err("Invalid floor frequency config register\n");
-               return;
-       }
-
-       if (!power_ctrl_orig_val)
-               iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_CR_READ,
-                             rapl_defaults->floor_freq_reg_addr,
-                             &power_ctrl_orig_val);
-       mdata = power_ctrl_orig_val;
-       if (enable) {
-               mdata &= ~(0x7f << 8);
-               mdata |= 1 << 8;
-       }
-       iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_CR_WRITE,
-                      rapl_defaults->floor_freq_reg_addr, mdata);
-}
-
-static u64 rapl_compute_time_window_core(struct rapl_package *rp, u64 value,
-                                       bool to_raw)
-{
-       u64 f, y; /* fraction and exp. used for time unit */
-
-       /*
-        * Special processing based on 2^Y*(1+F/4), refer
-        * to Intel Software Developer's manual Vol.3B: CH 14.9.3.
-        */
-       if (!to_raw) {
-               f = (value & 0x60) >> 5;
-               y = value & 0x1f;
-               value = (1 << y) * (4 + f) * rp->time_unit / 4;
-       } else {
-               do_div(value, rp->time_unit);
-               y = ilog2(value);
-               f = div64_u64(4 * (value - (1 << y)), 1 << y);
-               value = (y & 0x1f) | ((f & 0x3) << 5);
-       }
-       return value;
-}
-
-static u64 rapl_compute_time_window_atom(struct rapl_package *rp, u64 value,
-                                       bool to_raw)
-{
-       /*
-        * Atom time unit encoding is straight forward val * time_unit,
-        * where time_unit is default to 1 sec. Never 0.
-        */
-       if (!to_raw)
-               return (value) ? value *= rp->time_unit : rp->time_unit;
-       else
-               value = div64_u64(value, rp->time_unit);
-
-       return value;
-}
-
-static const struct rapl_defaults rapl_defaults_core = {
-       .floor_freq_reg_addr = 0,
-       .check_unit = rapl_check_unit_core,
-       .set_floor_freq = set_floor_freq_default,
-       .compute_time_window = rapl_compute_time_window_core,
-};
-
-static const struct rapl_defaults rapl_defaults_hsw_server = {
-       .check_unit = rapl_check_unit_core,
-       .set_floor_freq = set_floor_freq_default,
-       .compute_time_window = rapl_compute_time_window_core,
-       .dram_domain_energy_unit = 15300,
-};
-
-static const struct rapl_defaults rapl_defaults_byt = {
-       .floor_freq_reg_addr = IOSF_CPU_POWER_BUDGET_CTL_BYT,
-       .check_unit = rapl_check_unit_atom,
-       .set_floor_freq = set_floor_freq_atom,
-       .compute_time_window = rapl_compute_time_window_atom,
-};
-
-static const struct rapl_defaults rapl_defaults_tng = {
-       .floor_freq_reg_addr = IOSF_CPU_POWER_BUDGET_CTL_TNG,
-       .check_unit = rapl_check_unit_atom,
-       .set_floor_freq = set_floor_freq_atom,
-       .compute_time_window = rapl_compute_time_window_atom,
-};
-
-static const struct rapl_defaults rapl_defaults_ann = {
-       .floor_freq_reg_addr = 0,
-       .check_unit = rapl_check_unit_atom,
-       .set_floor_freq = NULL,
-       .compute_time_window = rapl_compute_time_window_atom,
-};
-
-static const struct rapl_defaults rapl_defaults_cht = {
-       .floor_freq_reg_addr = 0,
-       .check_unit = rapl_check_unit_atom,
-       .set_floor_freq = NULL,
-       .compute_time_window = rapl_compute_time_window_atom,
-};
-
-static const struct x86_cpu_id rapl_ids[] __initconst = {
-       INTEL_CPU_FAM6(SANDYBRIDGE,             rapl_defaults_core),
-       INTEL_CPU_FAM6(SANDYBRIDGE_X,           rapl_defaults_core),
-
-       INTEL_CPU_FAM6(IVYBRIDGE,               rapl_defaults_core),
-       INTEL_CPU_FAM6(IVYBRIDGE_X,             rapl_defaults_core),
-
-       INTEL_CPU_FAM6(HASWELL_CORE,            rapl_defaults_core),
-       INTEL_CPU_FAM6(HASWELL_ULT,             rapl_defaults_core),
-       INTEL_CPU_FAM6(HASWELL_GT3E,            rapl_defaults_core),
-       INTEL_CPU_FAM6(HASWELL_X,               rapl_defaults_hsw_server),
-
-       INTEL_CPU_FAM6(BROADWELL_CORE,          rapl_defaults_core),
-       INTEL_CPU_FAM6(BROADWELL_GT3E,          rapl_defaults_core),
-       INTEL_CPU_FAM6(BROADWELL_XEON_D,        rapl_defaults_core),
-       INTEL_CPU_FAM6(BROADWELL_X,             rapl_defaults_hsw_server),
-
-       INTEL_CPU_FAM6(SKYLAKE_DESKTOP,         rapl_defaults_core),
-       INTEL_CPU_FAM6(SKYLAKE_MOBILE,          rapl_defaults_core),
-       INTEL_CPU_FAM6(SKYLAKE_X,               rapl_defaults_hsw_server),
-       INTEL_CPU_FAM6(KABYLAKE_MOBILE,         rapl_defaults_core),
-       INTEL_CPU_FAM6(KABYLAKE_DESKTOP,        rapl_defaults_core),
-       INTEL_CPU_FAM6(CANNONLAKE_MOBILE,       rapl_defaults_core),
-       INTEL_CPU_FAM6(ICELAKE_MOBILE,          rapl_defaults_core),
-
-       INTEL_CPU_FAM6(ATOM_SILVERMONT,         rapl_defaults_byt),
-       INTEL_CPU_FAM6(ATOM_AIRMONT,            rapl_defaults_cht),
-       INTEL_CPU_FAM6(ATOM_SILVERMONT_MID,     rapl_defaults_tng),
-       INTEL_CPU_FAM6(ATOM_AIRMONT_MID,        rapl_defaults_ann),
-       INTEL_CPU_FAM6(ATOM_GOLDMONT,           rapl_defaults_core),
-       INTEL_CPU_FAM6(ATOM_GOLDMONT_PLUS,      rapl_defaults_core),
-       INTEL_CPU_FAM6(ATOM_GOLDMONT_X,         rapl_defaults_core),
-       INTEL_CPU_FAM6(ATOM_TREMONT_X,          rapl_defaults_core),
-
-       INTEL_CPU_FAM6(XEON_PHI_KNL,            rapl_defaults_hsw_server),
-       INTEL_CPU_FAM6(XEON_PHI_KNM,            rapl_defaults_hsw_server),
-       {}
-};
-MODULE_DEVICE_TABLE(x86cpu, rapl_ids);
-
-/* Read once for all raw primitive data for domains */
-static void rapl_update_domain_data(struct rapl_package *rp)
-{
-       int dmn, prim;
-       u64 val;
-
-       for (dmn = 0; dmn < rp->nr_domains; dmn++) {
-               pr_debug("update %s domain %s data\n", rp->name,
-                        rp->domains[dmn].name);
-               /* exclude non-raw primitives */
-               for (prim = 0; prim < NR_RAW_PRIMITIVES; prim++) {
-                       if (!rapl_read_data_raw(&rp->domains[dmn], prim,
-                                               rpi[prim].unit, &val))
-                               rp->domains[dmn].rdd.primitives[prim] = val;
-               }
-       }
-
-}
-
-static void rapl_unregister_powercap(void)
-{
-       if (platform_rapl_domain) {
-               powercap_unregister_zone(control_type,
-                                        &platform_rapl_domain->power_zone);
-               kfree(platform_rapl_domain);
-       }
-       powercap_unregister_control_type(control_type);
-}
-
-static int rapl_package_register_powercap(struct rapl_package *rp)
-{
-       struct rapl_domain *rd;
-       struct powercap_zone *power_zone = NULL;
-       int nr_pl, ret;
-
-       /* Update the domain data of the new package */
-       rapl_update_domain_data(rp);
-
-       /* first we register package domain as the parent zone*/
-       for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++) {
-               if (rd->id == RAPL_DOMAIN_PACKAGE) {
-                       nr_pl = find_nr_power_limit(rd);
-                       pr_debug("register package domain %s\n", rp->name);
-                       power_zone = powercap_register_zone(&rd->power_zone,
-                                                       control_type,
-                                                       rp->name, NULL,
-                                                       &zone_ops[rd->id],
-                                                       nr_pl,
-                                                       &constraint_ops);
-                       if (IS_ERR(power_zone)) {
-                               pr_debug("failed to register power zone %s\n",
-                                       rp->name);
-                               return PTR_ERR(power_zone);
-                       }
-                       /* track parent zone in per package/socket data */
-                       rp->power_zone = power_zone;
-                       /* done, only one package domain per socket */
-                       break;
-               }
-       }
-       if (!power_zone) {
-               pr_err("no package domain found, unknown topology!\n");
-               return -ENODEV;
-       }
-       /* now register domains as children of the socket/package*/
-       for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++) {
-               if (rd->id == RAPL_DOMAIN_PACKAGE)
-                       continue;
-               /* number of power limits per domain varies */
-               nr_pl = find_nr_power_limit(rd);
-               power_zone = powercap_register_zone(&rd->power_zone,
-                                               control_type, rd->name,
-                                               rp->power_zone,
-                                               &zone_ops[rd->id], nr_pl,
-                                               &constraint_ops);
-
-               if (IS_ERR(power_zone)) {
-                       pr_debug("failed to register power_zone, %s:%s\n",
-                               rp->name, rd->name);
-                       ret = PTR_ERR(power_zone);
-                       goto err_cleanup;
-               }
-       }
-       return 0;
-
-err_cleanup:
-       /*
-        * Clean up previously initialized domains within the package if we
-        * failed after the first domain setup.
-        */
-       while (--rd >= rp->domains) {
-               pr_debug("unregister %s domain %s\n", rp->name, rd->name);
-               powercap_unregister_zone(control_type, &rd->power_zone);
-       }
-
-       return ret;
-}
-
-static int __init rapl_register_psys(void)
-{
-       struct rapl_domain *rd;
-       struct powercap_zone *power_zone;
-       u64 val;
-
-       if (rdmsrl_safe_on_cpu(0, MSR_PLATFORM_ENERGY_STATUS, &val) || !val)
-               return -ENODEV;
-
-       if (rdmsrl_safe_on_cpu(0, MSR_PLATFORM_POWER_LIMIT, &val) || !val)
-               return -ENODEV;
-
-       rd = kzalloc(sizeof(*rd), GFP_KERNEL);
-       if (!rd)
-               return -ENOMEM;
-
-       rd->name = rapl_domain_names[RAPL_DOMAIN_PLATFORM];
-       rd->id = RAPL_DOMAIN_PLATFORM;
-       rd->msrs[0] = MSR_PLATFORM_POWER_LIMIT;
-       rd->msrs[1] = MSR_PLATFORM_ENERGY_STATUS;
-       rd->rpl[0].prim_id = PL1_ENABLE;
-       rd->rpl[0].name = pl1_name;
-       rd->rpl[1].prim_id = PL2_ENABLE;
-       rd->rpl[1].name = pl2_name;
-       rd->rp = rapl_find_package_domain(0);
-
-       power_zone = powercap_register_zone(&rd->power_zone, control_type,
-                                           "psys", NULL,
-                                           &zone_ops[RAPL_DOMAIN_PLATFORM],
-                                           2, &constraint_ops);
-
-       if (IS_ERR(power_zone)) {
-               kfree(rd);
-               return PTR_ERR(power_zone);
-       }
-
-       platform_rapl_domain = rd;
-
-       return 0;
-}
-
-static int __init rapl_register_powercap(void)
-{
-       control_type = powercap_register_control_type(NULL, "intel-rapl", NULL);
-       if (IS_ERR(control_type)) {
-               pr_debug("failed to register powercap control_type.\n");
-               return PTR_ERR(control_type);
-       }
-       return 0;
-}
-
-static int rapl_check_domain(int cpu, int domain)
-{
-       unsigned msr;
-       u64 val = 0;
-
-       switch (domain) {
-       case RAPL_DOMAIN_PACKAGE:
-               msr = MSR_PKG_ENERGY_STATUS;
-               break;
-       case RAPL_DOMAIN_PP0:
-               msr = MSR_PP0_ENERGY_STATUS;
-               break;
-       case RAPL_DOMAIN_PP1:
-               msr = MSR_PP1_ENERGY_STATUS;
-               break;
-       case RAPL_DOMAIN_DRAM:
-               msr = MSR_DRAM_ENERGY_STATUS;
-               break;
-       case RAPL_DOMAIN_PLATFORM:
-               /* PSYS(PLATFORM) is not a CPU domain, so avoid printng error */
-               return -EINVAL;
-       default:
-               pr_err("invalid domain id %d\n", domain);
-               return -EINVAL;
-       }
-       /* make sure domain counters are available and contains non-zero
-        * values, otherwise skip it.
-        */
-       if (rdmsrl_safe_on_cpu(cpu, msr, &val) || !val)
-               return -ENODEV;
-
-       return 0;
-}
-
-
-/*
- * Check if power limits are available. Two cases when they are not available:
- * 1. Locked by BIOS, in this case we still provide read-only access so that
- *    users can see what limit is set by the BIOS.
- * 2. Some CPUs make some domains monitoring only which means PLx MSRs may not
- *    exist at all. In this case, we do not show the contraints in powercap.
- *
- * Called after domains are detected and initialized.
- */
-static void rapl_detect_powerlimit(struct rapl_domain *rd)
-{
-       u64 val64;
-       int i;
-
-       /* check if the domain is locked by BIOS, ignore if MSR doesn't exist */
-       if (!rapl_read_data_raw(rd, FW_LOCK, false, &val64)) {
-               if (val64) {
-                       pr_info("RAPL %s domain %s locked by BIOS\n",
-                               rd->rp->name, rd->name);
-                       rd->state |= DOMAIN_STATE_BIOS_LOCKED;
-               }
-       }
-       /* check if power limit MSRs exists, otherwise domain is monitoring only */
-       for (i = 0; i < NR_POWER_LIMITS; i++) {
-               int prim = rd->rpl[i].prim_id;
-               if (rapl_read_data_raw(rd, prim, false, &val64))
-                       rd->rpl[i].name = NULL;
-       }
-}
-
-/* Detect active and valid domains for the given CPU, caller must
- * ensure the CPU belongs to the targeted package and CPU hotlug is disabled.
- */
-static int rapl_detect_domains(struct rapl_package *rp, int cpu)
-{
-       struct rapl_domain *rd;
-       int i;
-
-       for (i = 0; i < RAPL_DOMAIN_MAX; i++) {
-               /* use physical package id to read counters */
-               if (!rapl_check_domain(cpu, i)) {
-                       rp->domain_map |= 1 << i;
-                       pr_info("Found RAPL domain %s\n", rapl_domain_names[i]);
-               }
-       }
-       rp->nr_domains = bitmap_weight(&rp->domain_map, RAPL_DOMAIN_MAX);
-       if (!rp->nr_domains) {
-               pr_debug("no valid rapl domains found in %s\n", rp->name);
-               return -ENODEV;
-       }
-       pr_debug("found %d domains on %s\n", rp->nr_domains, rp->name);
-
-       rp->domains = kcalloc(rp->nr_domains + 1, sizeof(struct rapl_domain),
-                       GFP_KERNEL);
-       if (!rp->domains)
-               return -ENOMEM;
-
-       rapl_init_domains(rp);
-
-       for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++)
-               rapl_detect_powerlimit(rd);
-
-       return 0;
-}
-
-/* called from CPU hotplug notifier, hotplug lock held */
-static void rapl_remove_package(struct rapl_package *rp)
-{
-       struct rapl_domain *rd, *rd_package = NULL;
-
-       package_power_limit_irq_restore(rp);
-
-       for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++) {
-               rapl_write_data_raw(rd, PL1_ENABLE, 0);
-               rapl_write_data_raw(rd, PL1_CLAMP, 0);
-               if (find_nr_power_limit(rd) > 1) {
-                       rapl_write_data_raw(rd, PL2_ENABLE, 0);
-                       rapl_write_data_raw(rd, PL2_CLAMP, 0);
-               }
-               if (rd->id == RAPL_DOMAIN_PACKAGE) {
-                       rd_package = rd;
-                       continue;
-               }
-               pr_debug("remove package, undo power limit on %s: %s\n",
-                        rp->name, rd->name);
-               powercap_unregister_zone(control_type, &rd->power_zone);
-       }
-       /* do parent zone last */
-       powercap_unregister_zone(control_type, &rd_package->power_zone);
-       list_del(&rp->plist);
-       kfree(rp);
-}
-
-/* called from CPU hotplug notifier, hotplug lock held */
-static struct rapl_package *rapl_add_package(int cpu)
-{
-       int id = topology_logical_die_id(cpu);
-       struct rapl_package *rp;
-       struct cpuinfo_x86 *c = &cpu_data(cpu);
-       int ret;
-
-       rp = kzalloc(sizeof(struct rapl_package), GFP_KERNEL);
-       if (!rp)
-               return ERR_PTR(-ENOMEM);
-
-       /* add the new package to the list */
-       rp->id = id;
-       rp->lead_cpu = cpu;
-
-       if (topology_max_die_per_package() > 1)
-               snprintf(rp->name, PACKAGE_DOMAIN_NAME_LENGTH,
-                       "package-%d-die-%d", c->phys_proc_id, c->cpu_die_id);
-       else
-               snprintf(rp->name, PACKAGE_DOMAIN_NAME_LENGTH, "package-%d",
-                       c->phys_proc_id);
-
-       /* check if the package contains valid domains */
-       if (rapl_detect_domains(rp, cpu) ||
-               rapl_defaults->check_unit(rp, cpu)) {
-               ret = -ENODEV;
-               goto err_free_package;
-       }
-       ret = rapl_package_register_powercap(rp);
-       if (!ret) {
-               INIT_LIST_HEAD(&rp->plist);
-               list_add(&rp->plist, &rapl_packages);
-               return rp;
-       }
-
-err_free_package:
-       kfree(rp->domains);
-       kfree(rp);
-       return ERR_PTR(ret);
-}
-
-/* Handles CPU hotplug on multi-socket systems.
- * If a CPU goes online as the first CPU of the physical package
- * we add the RAPL package to the system. Similarly, when the last
- * CPU of the package is removed, we remove the RAPL package and its
- * associated domains. Cooling devices are handled accordingly at
- * per-domain level.
- */
-static int rapl_cpu_online(unsigned int cpu)
-{
-       struct rapl_package *rp;
-
-       rp = rapl_find_package_domain(cpu);
-       if (!rp) {
-               rp = rapl_add_package(cpu);
-               if (IS_ERR(rp))
-                       return PTR_ERR(rp);
-       }
-       cpumask_set_cpu(cpu, &rp->cpumask);
-       return 0;
-}
-
-static int rapl_cpu_down_prep(unsigned int cpu)
-{
-       struct rapl_package *rp;
-       int lead_cpu;
-
-       rp = rapl_find_package_domain(cpu);
-       if (!rp)
-               return 0;
-
-       cpumask_clear_cpu(cpu, &rp->cpumask);
-       lead_cpu = cpumask_first(&rp->cpumask);
-       if (lead_cpu >= nr_cpu_ids)
-               rapl_remove_package(rp);
-       else if (rp->lead_cpu == cpu)
-               rp->lead_cpu = lead_cpu;
-       return 0;
-}
-
-static enum cpuhp_state pcap_rapl_online;
-
-static void power_limit_state_save(void)
-{
-       struct rapl_package *rp;
-       struct rapl_domain *rd;
-       int nr_pl, ret, i;
-
-       get_online_cpus();
-       list_for_each_entry(rp, &rapl_packages, plist) {
-               if (!rp->power_zone)
-                       continue;
-               rd = power_zone_to_rapl_domain(rp->power_zone);
-               nr_pl = find_nr_power_limit(rd);
-               for (i = 0; i < nr_pl; i++) {
-                       switch (rd->rpl[i].prim_id) {
-                       case PL1_ENABLE:
-                               ret = rapl_read_data_raw(rd,
-                                               POWER_LIMIT1,
-                                               true,
-                                               &rd->rpl[i].last_power_limit);
-                               if (ret)
-                                       rd->rpl[i].last_power_limit = 0;
-                               break;
-                       case PL2_ENABLE:
-                               ret = rapl_read_data_raw(rd,
-                                               POWER_LIMIT2,
-                                               true,
-                                               &rd->rpl[i].last_power_limit);
-                               if (ret)
-                                       rd->rpl[i].last_power_limit = 0;
-                               break;
-                       }
-               }
-       }
-       put_online_cpus();
-}
-
-static void power_limit_state_restore(void)
-{
-       struct rapl_package *rp;
-       struct rapl_domain *rd;
-       int nr_pl, i;
-
-       get_online_cpus();
-       list_for_each_entry(rp, &rapl_packages, plist) {
-               if (!rp->power_zone)
-                       continue;
-               rd = power_zone_to_rapl_domain(rp->power_zone);
-               nr_pl = find_nr_power_limit(rd);
-               for (i = 0; i < nr_pl; i++) {
-                       switch (rd->rpl[i].prim_id) {
-                       case PL1_ENABLE:
-                               if (rd->rpl[i].last_power_limit)
-                                       rapl_write_data_raw(rd,
-                                               POWER_LIMIT1,
-                                               rd->rpl[i].last_power_limit);
-                               break;
-                       case PL2_ENABLE:
-                               if (rd->rpl[i].last_power_limit)
-                                       rapl_write_data_raw(rd,
-                                               POWER_LIMIT2,
-                                               rd->rpl[i].last_power_limit);
-                               break;
-                       }
-               }
-       }
-       put_online_cpus();
-}
-
-static int rapl_pm_callback(struct notifier_block *nb,
-       unsigned long mode, void *_unused)
-{
-       switch (mode) {
-       case PM_SUSPEND_PREPARE:
-               power_limit_state_save();
-               break;
-       case PM_POST_SUSPEND:
-               power_limit_state_restore();
-               break;
-       }
-       return NOTIFY_OK;
-}
-
-static struct notifier_block rapl_pm_notifier = {
-       .notifier_call = rapl_pm_callback,
-};
-
-static int __init rapl_init(void)
-{
-       const struct x86_cpu_id *id;
-       int ret;
-
-       id = x86_match_cpu(rapl_ids);
-       if (!id) {
-               pr_err("driver does not support CPU family %d model %d\n",
-                       boot_cpu_data.x86, boot_cpu_data.x86_model);
-
-               return -ENODEV;
-       }
-
-       rapl_defaults = (struct rapl_defaults *)id->driver_data;
-
-       ret = rapl_register_powercap();
-       if (ret)
-               return ret;
-
-       ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "powercap/rapl:online",
-                               rapl_cpu_online, rapl_cpu_down_prep);
-       if (ret < 0)
-               goto err_unreg;
-       pcap_rapl_online = ret;
-
-       /* Don't bail out if PSys is not supported */
-       rapl_register_psys();
-
-       ret = register_pm_notifier(&rapl_pm_notifier);
-       if (ret)
-               goto err_unreg_all;
-
-       return 0;
-
-err_unreg_all:
-       cpuhp_remove_state(pcap_rapl_online);
-
-err_unreg:
-       rapl_unregister_powercap();
-       return ret;
-}
-
-static void __exit rapl_exit(void)
-{
-       unregister_pm_notifier(&rapl_pm_notifier);
-       cpuhp_remove_state(pcap_rapl_online);
-       rapl_unregister_powercap();
-}
-
-module_init(rapl_init);
-module_exit(rapl_exit);
-
-MODULE_DESCRIPTION("Driver for Intel RAPL (Running Average Power Limit)");
-MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@intel.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/powercap/intel_rapl_common.c b/drivers/powercap/intel_rapl_common.c
new file mode 100644 (file)
index 0000000..6df4818
--- /dev/null
@@ -0,0 +1,1462 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Common code for Intel Running Average Power Limit (RAPL) support.
+ * Copyright (c) 2019, Intel Corporation.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/log2.h>
+#include <linux/bitmap.h>
+#include <linux/delay.h>
+#include <linux/sysfs.h>
+#include <linux/cpu.h>
+#include <linux/powercap.h>
+#include <linux/suspend.h>
+#include <linux/intel_rapl.h>
+#include <linux/processor.h>
+#include <linux/platform_device.h>
+
+#include <asm/iosf_mbi.h>
+#include <asm/cpu_device_id.h>
+#include <asm/intel-family.h>
+
+/* Local defines */
+#define MSR_PLATFORM_POWER_LIMIT       0x0000065C
+
+/* bitmasks for RAPL MSRs, used by primitive access functions */
+#define ENERGY_STATUS_MASK      0xffffffff
+
+#define POWER_LIMIT1_MASK       0x7FFF
+#define POWER_LIMIT1_ENABLE     BIT(15)
+#define POWER_LIMIT1_CLAMP      BIT(16)
+
+#define POWER_LIMIT2_MASK       (0x7FFFULL<<32)
+#define POWER_LIMIT2_ENABLE     BIT_ULL(47)
+#define POWER_LIMIT2_CLAMP      BIT_ULL(48)
+#define POWER_HIGH_LOCK         BIT_ULL(63)
+#define POWER_LOW_LOCK          BIT(31)
+
+#define TIME_WINDOW1_MASK       (0x7FULL<<17)
+#define TIME_WINDOW2_MASK       (0x7FULL<<49)
+
+#define POWER_UNIT_OFFSET      0
+#define POWER_UNIT_MASK                0x0F
+
+#define ENERGY_UNIT_OFFSET     0x08
+#define ENERGY_UNIT_MASK       0x1F00
+
+#define TIME_UNIT_OFFSET       0x10
+#define TIME_UNIT_MASK         0xF0000
+
+#define POWER_INFO_MAX_MASK     (0x7fffULL<<32)
+#define POWER_INFO_MIN_MASK     (0x7fffULL<<16)
+#define POWER_INFO_MAX_TIME_WIN_MASK     (0x3fULL<<48)
+#define POWER_INFO_THERMAL_SPEC_MASK     0x7fff
+
+#define PERF_STATUS_THROTTLE_TIME_MASK 0xffffffff
+#define PP_POLICY_MASK         0x1F
+
+/* Non HW constants */
+#define RAPL_PRIMITIVE_DERIVED       BIT(1)    /* not from raw data */
+#define RAPL_PRIMITIVE_DUMMY         BIT(2)
+
+#define TIME_WINDOW_MAX_MSEC 40000
+#define TIME_WINDOW_MIN_MSEC 250
+#define ENERGY_UNIT_SCALE    1000      /* scale from driver unit to powercap unit */
+enum unit_type {
+       ARBITRARY_UNIT,         /* no translation */
+       POWER_UNIT,
+       ENERGY_UNIT,
+       TIME_UNIT,
+};
+
+/* per domain data, some are optional */
+#define NR_RAW_PRIMITIVES (NR_RAPL_PRIMITIVES - 2)
+
+#define        DOMAIN_STATE_INACTIVE           BIT(0)
+#define        DOMAIN_STATE_POWER_LIMIT_SET    BIT(1)
+#define DOMAIN_STATE_BIOS_LOCKED        BIT(2)
+
+static const char pl1_name[] = "long_term";
+static const char pl2_name[] = "short_term";
+
+#define power_zone_to_rapl_domain(_zone) \
+       container_of(_zone, struct rapl_domain, power_zone)
+
+struct rapl_defaults {
+       u8 floor_freq_reg_addr;
+       int (*check_unit)(struct rapl_package *rp, int cpu);
+       void (*set_floor_freq)(struct rapl_domain *rd, bool mode);
+       u64 (*compute_time_window)(struct rapl_package *rp, u64 val,
+                                   bool to_raw);
+       unsigned int dram_domain_energy_unit;
+};
+static struct rapl_defaults *rapl_defaults;
+
+/* Sideband MBI registers */
+#define IOSF_CPU_POWER_BUDGET_CTL_BYT (0x2)
+#define IOSF_CPU_POWER_BUDGET_CTL_TNG (0xdf)
+
+#define PACKAGE_PLN_INT_SAVED   BIT(0)
+#define MAX_PRIM_NAME (32)
+
+/* per domain data. used to describe individual knobs such that access function
+ * can be consolidated into one instead of many inline functions.
+ */
+struct rapl_primitive_info {
+       const char *name;
+       u64 mask;
+       int shift;
+       enum rapl_domain_reg_id id;
+       enum unit_type unit;
+       u32 flag;
+};
+
+#define PRIMITIVE_INFO_INIT(p, m, s, i, u, f) {        \
+               .name = #p,                     \
+               .mask = m,                      \
+               .shift = s,                     \
+               .id = i,                        \
+               .unit = u,                      \
+               .flag = f                       \
+       }
+
+static void rapl_init_domains(struct rapl_package *rp);
+static int rapl_read_data_raw(struct rapl_domain *rd,
+                             enum rapl_primitives prim,
+                             bool xlate, u64 *data);
+static int rapl_write_data_raw(struct rapl_domain *rd,
+                              enum rapl_primitives prim,
+                              unsigned long long value);
+static u64 rapl_unit_xlate(struct rapl_domain *rd,
+                          enum unit_type type, u64 value, int to_raw);
+static void package_power_limit_irq_save(struct rapl_package *rp);
+
+static LIST_HEAD(rapl_packages);       /* guarded by CPU hotplug lock */
+
+static const char *const rapl_domain_names[] = {
+       "package",
+       "core",
+       "uncore",
+       "dram",
+       "psys",
+};
+
+static int get_energy_counter(struct powercap_zone *power_zone,
+                             u64 *energy_raw)
+{
+       struct rapl_domain *rd;
+       u64 energy_now;
+
+       /* prevent CPU hotplug, make sure the RAPL domain does not go
+        * away while reading the counter.
+        */
+       get_online_cpus();
+       rd = power_zone_to_rapl_domain(power_zone);
+
+       if (!rapl_read_data_raw(rd, ENERGY_COUNTER, true, &energy_now)) {
+               *energy_raw = energy_now;
+               put_online_cpus();
+
+               return 0;
+       }
+       put_online_cpus();
+
+       return -EIO;
+}
+
+static int get_max_energy_counter(struct powercap_zone *pcd_dev, u64 *energy)
+{
+       struct rapl_domain *rd = power_zone_to_rapl_domain(pcd_dev);
+
+       *energy = rapl_unit_xlate(rd, ENERGY_UNIT, ENERGY_STATUS_MASK, 0);
+       return 0;
+}
+
+static int release_zone(struct powercap_zone *power_zone)
+{
+       struct rapl_domain *rd = power_zone_to_rapl_domain(power_zone);
+       struct rapl_package *rp = rd->rp;
+
+       /* package zone is the last zone of a package, we can free
+        * memory here since all children has been unregistered.
+        */
+       if (rd->id == RAPL_DOMAIN_PACKAGE) {
+               kfree(rd);
+               rp->domains = NULL;
+       }
+
+       return 0;
+
+}
+
+static int find_nr_power_limit(struct rapl_domain *rd)
+{
+       int i, nr_pl = 0;
+
+       for (i = 0; i < NR_POWER_LIMITS; i++) {
+               if (rd->rpl[i].name)
+                       nr_pl++;
+       }
+
+       return nr_pl;
+}
+
+static int set_domain_enable(struct powercap_zone *power_zone, bool mode)
+{
+       struct rapl_domain *rd = power_zone_to_rapl_domain(power_zone);
+
+       if (rd->state & DOMAIN_STATE_BIOS_LOCKED)
+               return -EACCES;
+
+       get_online_cpus();
+       rapl_write_data_raw(rd, PL1_ENABLE, mode);
+       if (rapl_defaults->set_floor_freq)
+               rapl_defaults->set_floor_freq(rd, mode);
+       put_online_cpus();
+
+       return 0;
+}
+
+static int get_domain_enable(struct powercap_zone *power_zone, bool *mode)
+{
+       struct rapl_domain *rd = power_zone_to_rapl_domain(power_zone);
+       u64 val;
+
+       if (rd->state & DOMAIN_STATE_BIOS_LOCKED) {
+               *mode = false;
+               return 0;
+       }
+       get_online_cpus();
+       if (rapl_read_data_raw(rd, PL1_ENABLE, true, &val)) {
+               put_online_cpus();
+               return -EIO;
+       }
+       *mode = val;
+       put_online_cpus();
+
+       return 0;
+}
+
+/* per RAPL domain ops, in the order of rapl_domain_type */
+static const struct powercap_zone_ops zone_ops[] = {
+       /* RAPL_DOMAIN_PACKAGE */
+       {
+        .get_energy_uj = get_energy_counter,
+        .get_max_energy_range_uj = get_max_energy_counter,
+        .release = release_zone,
+        .set_enable = set_domain_enable,
+        .get_enable = get_domain_enable,
+        },
+       /* RAPL_DOMAIN_PP0 */
+       {
+        .get_energy_uj = get_energy_counter,
+        .get_max_energy_range_uj = get_max_energy_counter,
+        .release = release_zone,
+        .set_enable = set_domain_enable,
+        .get_enable = get_domain_enable,
+        },
+       /* RAPL_DOMAIN_PP1 */
+       {
+        .get_energy_uj = get_energy_counter,
+        .get_max_energy_range_uj = get_max_energy_counter,
+        .release = release_zone,
+        .set_enable = set_domain_enable,
+        .get_enable = get_domain_enable,
+        },
+       /* RAPL_DOMAIN_DRAM */
+       {
+        .get_energy_uj = get_energy_counter,
+        .get_max_energy_range_uj = get_max_energy_counter,
+        .release = release_zone,
+        .set_enable = set_domain_enable,
+        .get_enable = get_domain_enable,
+        },
+       /* RAPL_DOMAIN_PLATFORM */
+       {
+        .get_energy_uj = get_energy_counter,
+        .get_max_energy_range_uj = get_max_energy_counter,
+        .release = release_zone,
+        .set_enable = set_domain_enable,
+        .get_enable = get_domain_enable,
+        },
+};
+
+/*
+ * Constraint index used by powercap can be different than power limit (PL)
+ * index in that some  PLs maybe missing due to non-existent MSRs. So we
+ * need to convert here by finding the valid PLs only (name populated).
+ */
+static int contraint_to_pl(struct rapl_domain *rd, int cid)
+{
+       int i, j;
+
+       for (i = 0, j = 0; i < NR_POWER_LIMITS; i++) {
+               if ((rd->rpl[i].name) && j++ == cid) {
+                       pr_debug("%s: index %d\n", __func__, i);
+                       return i;
+               }
+       }
+       pr_err("Cannot find matching power limit for constraint %d\n", cid);
+
+       return -EINVAL;
+}
+
+static int set_power_limit(struct powercap_zone *power_zone, int cid,
+                          u64 power_limit)
+{
+       struct rapl_domain *rd;
+       struct rapl_package *rp;
+       int ret = 0;
+       int id;
+
+       get_online_cpus();
+       rd = power_zone_to_rapl_domain(power_zone);
+       id = contraint_to_pl(rd, cid);
+       if (id < 0) {
+               ret = id;
+               goto set_exit;
+       }
+
+       rp = rd->rp;
+
+       if (rd->state & DOMAIN_STATE_BIOS_LOCKED) {
+               dev_warn(&power_zone->dev,
+                        "%s locked by BIOS, monitoring only\n", rd->name);
+               ret = -EACCES;
+               goto set_exit;
+       }
+
+       switch (rd->rpl[id].prim_id) {
+       case PL1_ENABLE:
+               rapl_write_data_raw(rd, POWER_LIMIT1, power_limit);
+               break;
+       case PL2_ENABLE:
+               rapl_write_data_raw(rd, POWER_LIMIT2, power_limit);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       if (!ret)
+               package_power_limit_irq_save(rp);
+set_exit:
+       put_online_cpus();
+       return ret;
+}
+
+static int get_current_power_limit(struct powercap_zone *power_zone, int cid,
+                                  u64 *data)
+{
+       struct rapl_domain *rd;
+       u64 val;
+       int prim;
+       int ret = 0;
+       int id;
+
+       get_online_cpus();
+       rd = power_zone_to_rapl_domain(power_zone);
+       id = contraint_to_pl(rd, cid);
+       if (id < 0) {
+               ret = id;
+               goto get_exit;
+       }
+
+       switch (rd->rpl[id].prim_id) {
+       case PL1_ENABLE:
+               prim = POWER_LIMIT1;
+               break;
+       case PL2_ENABLE:
+               prim = POWER_LIMIT2;
+               break;
+       default:
+               put_online_cpus();
+               return -EINVAL;
+       }
+       if (rapl_read_data_raw(rd, prim, true, &val))
+               ret = -EIO;
+       else
+               *data = val;
+
+get_exit:
+       put_online_cpus();
+
+       return ret;
+}
+
+static int set_time_window(struct powercap_zone *power_zone, int cid,
+                          u64 window)
+{
+       struct rapl_domain *rd;
+       int ret = 0;
+       int id;
+
+       get_online_cpus();
+       rd = power_zone_to_rapl_domain(power_zone);
+       id = contraint_to_pl(rd, cid);
+       if (id < 0) {
+               ret = id;
+               goto set_time_exit;
+       }
+
+       switch (rd->rpl[id].prim_id) {
+       case PL1_ENABLE:
+               rapl_write_data_raw(rd, TIME_WINDOW1, window);
+               break;
+       case PL2_ENABLE:
+               rapl_write_data_raw(rd, TIME_WINDOW2, window);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+set_time_exit:
+       put_online_cpus();
+       return ret;
+}
+
+static int get_time_window(struct powercap_zone *power_zone, int cid,
+                          u64 *data)
+{
+       struct rapl_domain *rd;
+       u64 val;
+       int ret = 0;
+       int id;
+
+       get_online_cpus();
+       rd = power_zone_to_rapl_domain(power_zone);
+       id = contraint_to_pl(rd, cid);
+       if (id < 0) {
+               ret = id;
+               goto get_time_exit;
+       }
+
+       switch (rd->rpl[id].prim_id) {
+       case PL1_ENABLE:
+               ret = rapl_read_data_raw(rd, TIME_WINDOW1, true, &val);
+               break;
+       case PL2_ENABLE:
+               ret = rapl_read_data_raw(rd, TIME_WINDOW2, true, &val);
+               break;
+       default:
+               put_online_cpus();
+               return -EINVAL;
+       }
+       if (!ret)
+               *data = val;
+
+get_time_exit:
+       put_online_cpus();
+
+       return ret;
+}
+
+static const char *get_constraint_name(struct powercap_zone *power_zone,
+                                      int cid)
+{
+       struct rapl_domain *rd;
+       int id;
+
+       rd = power_zone_to_rapl_domain(power_zone);
+       id = contraint_to_pl(rd, cid);
+       if (id >= 0)
+               return rd->rpl[id].name;
+
+       return NULL;
+}
+
+static int get_max_power(struct powercap_zone *power_zone, int id, u64 *data)
+{
+       struct rapl_domain *rd;
+       u64 val;
+       int prim;
+       int ret = 0;
+
+       get_online_cpus();
+       rd = power_zone_to_rapl_domain(power_zone);
+       switch (rd->rpl[id].prim_id) {
+       case PL1_ENABLE:
+               prim = THERMAL_SPEC_POWER;
+               break;
+       case PL2_ENABLE:
+               prim = MAX_POWER;
+               break;
+       default:
+               put_online_cpus();
+               return -EINVAL;
+       }
+       if (rapl_read_data_raw(rd, prim, true, &val))
+               ret = -EIO;
+       else
+               *data = val;
+
+       put_online_cpus();
+
+       return ret;
+}
+
+static const struct powercap_zone_constraint_ops constraint_ops = {
+       .set_power_limit_uw = set_power_limit,
+       .get_power_limit_uw = get_current_power_limit,
+       .set_time_window_us = set_time_window,
+       .get_time_window_us = get_time_window,
+       .get_max_power_uw = get_max_power,
+       .get_name = get_constraint_name,
+};
+
+/* called after domain detection and package level data are set */
+static void rapl_init_domains(struct rapl_package *rp)
+{
+       enum rapl_domain_type i;
+       enum rapl_domain_reg_id j;
+       struct rapl_domain *rd = rp->domains;
+
+       for (i = 0; i < RAPL_DOMAIN_MAX; i++) {
+               unsigned int mask = rp->domain_map & (1 << i);
+
+               if (!mask)
+                       continue;
+
+               rd->rp = rp;
+               rd->name = rapl_domain_names[i];
+               rd->id = i;
+               rd->rpl[0].prim_id = PL1_ENABLE;
+               rd->rpl[0].name = pl1_name;
+               /* some domain may support two power limits */
+               if (rp->priv->limits[i] == 2) {
+                       rd->rpl[1].prim_id = PL2_ENABLE;
+                       rd->rpl[1].name = pl2_name;
+               }
+
+               for (j = 0; j < RAPL_DOMAIN_REG_MAX; j++)
+                       rd->regs[j] = rp->priv->regs[i][j];
+
+               if (i == RAPL_DOMAIN_DRAM) {
+                       rd->domain_energy_unit =
+                           rapl_defaults->dram_domain_energy_unit;
+                       if (rd->domain_energy_unit)
+                               pr_info("DRAM domain energy unit %dpj\n",
+                                       rd->domain_energy_unit);
+               }
+               rd++;
+       }
+}
+
+static u64 rapl_unit_xlate(struct rapl_domain *rd, enum unit_type type,
+                          u64 value, int to_raw)
+{
+       u64 units = 1;
+       struct rapl_package *rp = rd->rp;
+       u64 scale = 1;
+
+       switch (type) {
+       case POWER_UNIT:
+               units = rp->power_unit;
+               break;
+       case ENERGY_UNIT:
+               scale = ENERGY_UNIT_SCALE;
+               /* per domain unit takes precedence */
+               if (rd->domain_energy_unit)
+                       units = rd->domain_energy_unit;
+               else
+                       units = rp->energy_unit;
+               break;
+       case TIME_UNIT:
+               return rapl_defaults->compute_time_window(rp, value, to_raw);
+       case ARBITRARY_UNIT:
+       default:
+               return value;
+       };
+
+       if (to_raw)
+               return div64_u64(value, units) * scale;
+
+       value *= units;
+
+       return div64_u64(value, scale);
+}
+
+/* in the order of enum rapl_primitives */
+static struct rapl_primitive_info rpi[] = {
+       /* name, mask, shift, msr index, unit divisor */
+       PRIMITIVE_INFO_INIT(ENERGY_COUNTER, ENERGY_STATUS_MASK, 0,
+                           RAPL_DOMAIN_REG_STATUS, ENERGY_UNIT, 0),
+       PRIMITIVE_INFO_INIT(POWER_LIMIT1, POWER_LIMIT1_MASK, 0,
+                           RAPL_DOMAIN_REG_LIMIT, POWER_UNIT, 0),
+       PRIMITIVE_INFO_INIT(POWER_LIMIT2, POWER_LIMIT2_MASK, 32,
+                           RAPL_DOMAIN_REG_LIMIT, POWER_UNIT, 0),
+       PRIMITIVE_INFO_INIT(FW_LOCK, POWER_LOW_LOCK, 31,
+                           RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
+       PRIMITIVE_INFO_INIT(PL1_ENABLE, POWER_LIMIT1_ENABLE, 15,
+                           RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
+       PRIMITIVE_INFO_INIT(PL1_CLAMP, POWER_LIMIT1_CLAMP, 16,
+                           RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
+       PRIMITIVE_INFO_INIT(PL2_ENABLE, POWER_LIMIT2_ENABLE, 47,
+                           RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
+       PRIMITIVE_INFO_INIT(PL2_CLAMP, POWER_LIMIT2_CLAMP, 48,
+                           RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
+       PRIMITIVE_INFO_INIT(TIME_WINDOW1, TIME_WINDOW1_MASK, 17,
+                           RAPL_DOMAIN_REG_LIMIT, TIME_UNIT, 0),
+       PRIMITIVE_INFO_INIT(TIME_WINDOW2, TIME_WINDOW2_MASK, 49,
+                           RAPL_DOMAIN_REG_LIMIT, TIME_UNIT, 0),
+       PRIMITIVE_INFO_INIT(THERMAL_SPEC_POWER, POWER_INFO_THERMAL_SPEC_MASK,
+                           0, RAPL_DOMAIN_REG_INFO, POWER_UNIT, 0),
+       PRIMITIVE_INFO_INIT(MAX_POWER, POWER_INFO_MAX_MASK, 32,
+                           RAPL_DOMAIN_REG_INFO, POWER_UNIT, 0),
+       PRIMITIVE_INFO_INIT(MIN_POWER, POWER_INFO_MIN_MASK, 16,
+                           RAPL_DOMAIN_REG_INFO, POWER_UNIT, 0),
+       PRIMITIVE_INFO_INIT(MAX_TIME_WINDOW, POWER_INFO_MAX_TIME_WIN_MASK, 48,
+                           RAPL_DOMAIN_REG_INFO, TIME_UNIT, 0),
+       PRIMITIVE_INFO_INIT(THROTTLED_TIME, PERF_STATUS_THROTTLE_TIME_MASK, 0,
+                           RAPL_DOMAIN_REG_PERF, TIME_UNIT, 0),
+       PRIMITIVE_INFO_INIT(PRIORITY_LEVEL, PP_POLICY_MASK, 0,
+                           RAPL_DOMAIN_REG_POLICY, ARBITRARY_UNIT, 0),
+       /* non-hardware */
+       PRIMITIVE_INFO_INIT(AVERAGE_POWER, 0, 0, 0, POWER_UNIT,
+                           RAPL_PRIMITIVE_DERIVED),
+       {NULL, 0, 0, 0},
+};
+
+/* Read primitive data based on its related struct rapl_primitive_info.
+ * if xlate flag is set, return translated data based on data units, i.e.
+ * time, energy, and power.
+ * RAPL MSRs are non-architectual and are laid out not consistently across
+ * domains. Here we use primitive info to allow writing consolidated access
+ * functions.
+ * For a given primitive, it is processed by MSR mask and shift. Unit conversion
+ * is pre-assigned based on RAPL unit MSRs read at init time.
+ * 63-------------------------- 31--------------------------- 0
+ * |                           xxxxx (mask)                   |
+ * |                                |<- shift ----------------|
+ * 63-------------------------- 31--------------------------- 0
+ */
+static int rapl_read_data_raw(struct rapl_domain *rd,
+                             enum rapl_primitives prim, bool xlate, u64 *data)
+{
+       u64 value;
+       struct rapl_primitive_info *rp = &rpi[prim];
+       struct reg_action ra;
+       int cpu;
+
+       if (!rp->name || rp->flag & RAPL_PRIMITIVE_DUMMY)
+               return -EINVAL;
+
+       ra.reg = rd->regs[rp->id];
+       if (!ra.reg)
+               return -EINVAL;
+
+       cpu = rd->rp->lead_cpu;
+
+       /* domain with 2 limits has different bit */
+       if (prim == FW_LOCK && rd->rp->priv->limits[rd->id] == 2) {
+               rp->mask = POWER_HIGH_LOCK;
+               rp->shift = 63;
+       }
+       /* non-hardware data are collected by the polling thread */
+       if (rp->flag & RAPL_PRIMITIVE_DERIVED) {
+               *data = rd->rdd.primitives[prim];
+               return 0;
+       }
+
+       ra.mask = rp->mask;
+
+       if (rd->rp->priv->read_raw(cpu, &ra)) {
+               pr_debug("failed to read reg 0x%llx on cpu %d\n", ra.reg, cpu);
+               return -EIO;
+       }
+
+       value = ra.value >> rp->shift;
+
+       if (xlate)
+               *data = rapl_unit_xlate(rd, rp->unit, value, 0);
+       else
+               *data = value;
+
+       return 0;
+}
+
+/* Similar use of primitive info in the read counterpart */
+static int rapl_write_data_raw(struct rapl_domain *rd,
+                              enum rapl_primitives prim,
+                              unsigned long long value)
+{
+       struct rapl_primitive_info *rp = &rpi[prim];
+       int cpu;
+       u64 bits;
+       struct reg_action ra;
+       int ret;
+
+       cpu = rd->rp->lead_cpu;
+       bits = rapl_unit_xlate(rd, rp->unit, value, 1);
+       bits <<= rp->shift;
+       bits &= rp->mask;
+
+       memset(&ra, 0, sizeof(ra));
+
+       ra.reg = rd->regs[rp->id];
+       ra.mask = rp->mask;
+       ra.value = bits;
+
+       ret = rd->rp->priv->write_raw(cpu, &ra);
+
+       return ret;
+}
+
+/*
+ * Raw RAPL data stored in MSRs are in certain scales. We need to
+ * convert them into standard units based on the units reported in
+ * the RAPL unit MSRs. This is specific to CPUs as the method to
+ * calculate units differ on different CPUs.
+ * We convert the units to below format based on CPUs.
+ * i.e.
+ * energy unit: picoJoules  : Represented in picoJoules by default
+ * power unit : microWatts  : Represented in milliWatts by default
+ * time unit  : microseconds: Represented in seconds by default
+ */
+static int rapl_check_unit_core(struct rapl_package *rp, int cpu)
+{
+       struct reg_action ra;
+       u32 value;
+
+       ra.reg = rp->priv->reg_unit;
+       ra.mask = ~0;
+       if (rp->priv->read_raw(cpu, &ra)) {
+               pr_err("Failed to read power unit REG 0x%llx on CPU %d, exit.\n",
+                      rp->priv->reg_unit, cpu);
+               return -ENODEV;
+       }
+
+       value = (ra.value & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
+       rp->energy_unit = ENERGY_UNIT_SCALE * 1000000 / (1 << value);
+
+       value = (ra.value & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET;
+       rp->power_unit = 1000000 / (1 << value);
+
+       value = (ra.value & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
+       rp->time_unit = 1000000 / (1 << value);
+
+       pr_debug("Core CPU %s energy=%dpJ, time=%dus, power=%duW\n",
+                rp->name, rp->energy_unit, rp->time_unit, rp->power_unit);
+
+       return 0;
+}
+
+static int rapl_check_unit_atom(struct rapl_package *rp, int cpu)
+{
+       struct reg_action ra;
+       u32 value;
+
+       ra.reg = rp->priv->reg_unit;
+       ra.mask = ~0;
+       if (rp->priv->read_raw(cpu, &ra)) {
+               pr_err("Failed to read power unit REG 0x%llx on CPU %d, exit.\n",
+                      rp->priv->reg_unit, cpu);
+               return -ENODEV;
+       }
+
+       value = (ra.value & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
+       rp->energy_unit = ENERGY_UNIT_SCALE * 1 << value;
+
+       value = (ra.value & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET;
+       rp->power_unit = (1 << value) * 1000;
+
+       value = (ra.value & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
+       rp->time_unit = 1000000 / (1 << value);
+
+       pr_debug("Atom %s energy=%dpJ, time=%dus, power=%duW\n",
+                rp->name, rp->energy_unit, rp->time_unit, rp->power_unit);
+
+       return 0;
+}
+
+static void power_limit_irq_save_cpu(void *info)
+{
+       u32 l, h = 0;
+       struct rapl_package *rp = (struct rapl_package *)info;
+
+       /* save the state of PLN irq mask bit before disabling it */
+       rdmsr_safe(MSR_IA32_PACKAGE_THERM_INTERRUPT, &l, &h);
+       if (!(rp->power_limit_irq & PACKAGE_PLN_INT_SAVED)) {
+               rp->power_limit_irq = l & PACKAGE_THERM_INT_PLN_ENABLE;
+               rp->power_limit_irq |= PACKAGE_PLN_INT_SAVED;
+       }
+       l &= ~PACKAGE_THERM_INT_PLN_ENABLE;
+       wrmsr_safe(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
+}
+
+/* REVISIT:
+ * When package power limit is set artificially low by RAPL, LVT
+ * thermal interrupt for package power limit should be ignored
+ * since we are not really exceeding the real limit. The intention
+ * is to avoid excessive interrupts while we are trying to save power.
+ * A useful feature might be routing the package_power_limit interrupt
+ * to userspace via eventfd. once we have a usecase, this is simple
+ * to do by adding an atomic notifier.
+ */
+
+static void package_power_limit_irq_save(struct rapl_package *rp)
+{
+       if (!boot_cpu_has(X86_FEATURE_PTS) || !boot_cpu_has(X86_FEATURE_PLN))
+               return;
+
+       smp_call_function_single(rp->lead_cpu, power_limit_irq_save_cpu, rp, 1);
+}
+
+/*
+ * Restore per package power limit interrupt enable state. Called from cpu
+ * hotplug code on package removal.
+ */
+static void package_power_limit_irq_restore(struct rapl_package *rp)
+{
+       u32 l, h;
+
+       if (!boot_cpu_has(X86_FEATURE_PTS) || !boot_cpu_has(X86_FEATURE_PLN))
+               return;
+
+       /* irq enable state not saved, nothing to restore */
+       if (!(rp->power_limit_irq & PACKAGE_PLN_INT_SAVED))
+               return;
+
+       rdmsr_safe(MSR_IA32_PACKAGE_THERM_INTERRUPT, &l, &h);
+
+       if (rp->power_limit_irq & PACKAGE_THERM_INT_PLN_ENABLE)
+               l |= PACKAGE_THERM_INT_PLN_ENABLE;
+       else
+               l &= ~PACKAGE_THERM_INT_PLN_ENABLE;
+
+       wrmsr_safe(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
+}
+
+static void set_floor_freq_default(struct rapl_domain *rd, bool mode)
+{
+       int nr_powerlimit = find_nr_power_limit(rd);
+
+       /* always enable clamp such that p-state can go below OS requested
+        * range. power capping priority over guranteed frequency.
+        */
+       rapl_write_data_raw(rd, PL1_CLAMP, mode);
+
+       /* some domains have pl2 */
+       if (nr_powerlimit > 1) {
+               rapl_write_data_raw(rd, PL2_ENABLE, mode);
+               rapl_write_data_raw(rd, PL2_CLAMP, mode);
+       }
+}
+
+static void set_floor_freq_atom(struct rapl_domain *rd, bool enable)
+{
+       static u32 power_ctrl_orig_val;
+       u32 mdata;
+
+       if (!rapl_defaults->floor_freq_reg_addr) {
+               pr_err("Invalid floor frequency config register\n");
+               return;
+       }
+
+       if (!power_ctrl_orig_val)
+               iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_CR_READ,
+                             rapl_defaults->floor_freq_reg_addr,
+                             &power_ctrl_orig_val);
+       mdata = power_ctrl_orig_val;
+       if (enable) {
+               mdata &= ~(0x7f << 8);
+               mdata |= 1 << 8;
+       }
+       iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_CR_WRITE,
+                      rapl_defaults->floor_freq_reg_addr, mdata);
+}
+
+static u64 rapl_compute_time_window_core(struct rapl_package *rp, u64 value,
+                                        bool to_raw)
+{
+       u64 f, y;               /* fraction and exp. used for time unit */
+
+       /*
+        * Special processing based on 2^Y*(1+F/4), refer
+        * to Intel Software Developer's manual Vol.3B: CH 14.9.3.
+        */
+       if (!to_raw) {
+               f = (value & 0x60) >> 5;
+               y = value & 0x1f;
+               value = (1 << y) * (4 + f) * rp->time_unit / 4;
+       } else {
+               do_div(value, rp->time_unit);
+               y = ilog2(value);
+               f = div64_u64(4 * (value - (1 << y)), 1 << y);
+               value = (y & 0x1f) | ((f & 0x3) << 5);
+       }
+       return value;
+}
+
+static u64 rapl_compute_time_window_atom(struct rapl_package *rp, u64 value,
+                                        bool to_raw)
+{
+       /*
+        * Atom time unit encoding is straight forward val * time_unit,
+        * where time_unit is default to 1 sec. Never 0.
+        */
+       if (!to_raw)
+               return (value) ? value *= rp->time_unit : rp->time_unit;
+
+       value = div64_u64(value, rp->time_unit);
+
+       return value;
+}
+
+static const struct rapl_defaults rapl_defaults_core = {
+       .floor_freq_reg_addr = 0,
+       .check_unit = rapl_check_unit_core,
+       .set_floor_freq = set_floor_freq_default,
+       .compute_time_window = rapl_compute_time_window_core,
+};
+
+static const struct rapl_defaults rapl_defaults_hsw_server = {
+       .check_unit = rapl_check_unit_core,
+       .set_floor_freq = set_floor_freq_default,
+       .compute_time_window = rapl_compute_time_window_core,
+       .dram_domain_energy_unit = 15300,
+};
+
+static const struct rapl_defaults rapl_defaults_byt = {
+       .floor_freq_reg_addr = IOSF_CPU_POWER_BUDGET_CTL_BYT,
+       .check_unit = rapl_check_unit_atom,
+       .set_floor_freq = set_floor_freq_atom,
+       .compute_time_window = rapl_compute_time_window_atom,
+};
+
+static const struct rapl_defaults rapl_defaults_tng = {
+       .floor_freq_reg_addr = IOSF_CPU_POWER_BUDGET_CTL_TNG,
+       .check_unit = rapl_check_unit_atom,
+       .set_floor_freq = set_floor_freq_atom,
+       .compute_time_window = rapl_compute_time_window_atom,
+};
+
+static const struct rapl_defaults rapl_defaults_ann = {
+       .floor_freq_reg_addr = 0,
+       .check_unit = rapl_check_unit_atom,
+       .set_floor_freq = NULL,
+       .compute_time_window = rapl_compute_time_window_atom,
+};
+
+static const struct rapl_defaults rapl_defaults_cht = {
+       .floor_freq_reg_addr = 0,
+       .check_unit = rapl_check_unit_atom,
+       .set_floor_freq = NULL,
+       .compute_time_window = rapl_compute_time_window_atom,
+};
+
+static const struct x86_cpu_id rapl_ids[] __initconst = {
+       INTEL_CPU_FAM6(SANDYBRIDGE, rapl_defaults_core),
+       INTEL_CPU_FAM6(SANDYBRIDGE_X, rapl_defaults_core),
+
+       INTEL_CPU_FAM6(IVYBRIDGE, rapl_defaults_core),
+       INTEL_CPU_FAM6(IVYBRIDGE_X, rapl_defaults_core),
+
+       INTEL_CPU_FAM6(HASWELL_CORE, rapl_defaults_core),
+       INTEL_CPU_FAM6(HASWELL_ULT, rapl_defaults_core),
+       INTEL_CPU_FAM6(HASWELL_GT3E, rapl_defaults_core),
+       INTEL_CPU_FAM6(HASWELL_X, rapl_defaults_hsw_server),
+
+       INTEL_CPU_FAM6(BROADWELL_CORE, rapl_defaults_core),
+       INTEL_CPU_FAM6(BROADWELL_GT3E, rapl_defaults_core),
+       INTEL_CPU_FAM6(BROADWELL_XEON_D, rapl_defaults_core),
+       INTEL_CPU_FAM6(BROADWELL_X, rapl_defaults_hsw_server),
+
+       INTEL_CPU_FAM6(SKYLAKE_DESKTOP, rapl_defaults_core),
+       INTEL_CPU_FAM6(SKYLAKE_MOBILE, rapl_defaults_core),
+       INTEL_CPU_FAM6(SKYLAKE_X, rapl_defaults_hsw_server),
+       INTEL_CPU_FAM6(KABYLAKE_MOBILE, rapl_defaults_core),
+       INTEL_CPU_FAM6(KABYLAKE_DESKTOP, rapl_defaults_core),
+       INTEL_CPU_FAM6(CANNONLAKE_MOBILE, rapl_defaults_core),
+       INTEL_CPU_FAM6(ICELAKE_MOBILE, rapl_defaults_core),
+       INTEL_CPU_FAM6(ICELAKE_DESKTOP, rapl_defaults_core),
+       INTEL_CPU_FAM6(ICELAKE_NNPI, rapl_defaults_core),
+       INTEL_CPU_FAM6(ICELAKE_X, rapl_defaults_hsw_server),
+       INTEL_CPU_FAM6(ICELAKE_XEON_D, rapl_defaults_hsw_server),
+
+       INTEL_CPU_FAM6(ATOM_SILVERMONT, rapl_defaults_byt),
+       INTEL_CPU_FAM6(ATOM_AIRMONT, rapl_defaults_cht),
+       INTEL_CPU_FAM6(ATOM_SILVERMONT_MID, rapl_defaults_tng),
+       INTEL_CPU_FAM6(ATOM_AIRMONT_MID, rapl_defaults_ann),
+       INTEL_CPU_FAM6(ATOM_GOLDMONT, rapl_defaults_core),
+       INTEL_CPU_FAM6(ATOM_GOLDMONT_PLUS, rapl_defaults_core),
+       INTEL_CPU_FAM6(ATOM_GOLDMONT_X, rapl_defaults_core),
+       INTEL_CPU_FAM6(ATOM_TREMONT_X, rapl_defaults_core),
+
+       INTEL_CPU_FAM6(XEON_PHI_KNL, rapl_defaults_hsw_server),
+       INTEL_CPU_FAM6(XEON_PHI_KNM, rapl_defaults_hsw_server),
+       {}
+};
+
+MODULE_DEVICE_TABLE(x86cpu, rapl_ids);
+
+/* Read once for all raw primitive data for domains */
+static void rapl_update_domain_data(struct rapl_package *rp)
+{
+       int dmn, prim;
+       u64 val;
+
+       for (dmn = 0; dmn < rp->nr_domains; dmn++) {
+               pr_debug("update %s domain %s data\n", rp->name,
+                        rp->domains[dmn].name);
+               /* exclude non-raw primitives */
+               for (prim = 0; prim < NR_RAW_PRIMITIVES; prim++) {
+                       if (!rapl_read_data_raw(&rp->domains[dmn], prim,
+                                               rpi[prim].unit, &val))
+                               rp->domains[dmn].rdd.primitives[prim] = val;
+               }
+       }
+
+}
+
+static int rapl_package_register_powercap(struct rapl_package *rp)
+{
+       struct rapl_domain *rd;
+       struct powercap_zone *power_zone = NULL;
+       int nr_pl, ret;
+
+       /* Update the domain data of the new package */
+       rapl_update_domain_data(rp);
+
+       /* first we register package domain as the parent zone */
+       for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++) {
+               if (rd->id == RAPL_DOMAIN_PACKAGE) {
+                       nr_pl = find_nr_power_limit(rd);
+                       pr_debug("register package domain %s\n", rp->name);
+                       power_zone = powercap_register_zone(&rd->power_zone,
+                                           rp->priv->control_type, rp->name,
+                                           NULL, &zone_ops[rd->id], nr_pl,
+                                           &constraint_ops);
+                       if (IS_ERR(power_zone)) {
+                               pr_debug("failed to register power zone %s\n",
+                                        rp->name);
+                               return PTR_ERR(power_zone);
+                       }
+                       /* track parent zone in per package/socket data */
+                       rp->power_zone = power_zone;
+                       /* done, only one package domain per socket */
+                       break;
+               }
+       }
+       if (!power_zone) {
+               pr_err("no package domain found, unknown topology!\n");
+               return -ENODEV;
+       }
+       /* now register domains as children of the socket/package */
+       for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++) {
+               if (rd->id == RAPL_DOMAIN_PACKAGE)
+                       continue;
+               /* number of power limits per domain varies */
+               nr_pl = find_nr_power_limit(rd);
+               power_zone = powercap_register_zone(&rd->power_zone,
+                                                   rp->priv->control_type,
+                                                   rd->name, rp->power_zone,
+                                                   &zone_ops[rd->id], nr_pl,
+                                                   &constraint_ops);
+
+               if (IS_ERR(power_zone)) {
+                       pr_debug("failed to register power_zone, %s:%s\n",
+                                rp->name, rd->name);
+                       ret = PTR_ERR(power_zone);
+                       goto err_cleanup;
+               }
+       }
+       return 0;
+
+err_cleanup:
+       /*
+        * Clean up previously initialized domains within the package if we
+        * failed after the first domain setup.
+        */
+       while (--rd >= rp->domains) {
+               pr_debug("unregister %s domain %s\n", rp->name, rd->name);
+               powercap_unregister_zone(rp->priv->control_type,
+                                        &rd->power_zone);
+       }
+
+       return ret;
+}
+
+int rapl_add_platform_domain(struct rapl_if_priv *priv)
+{
+       struct rapl_domain *rd;
+       struct powercap_zone *power_zone;
+       struct reg_action ra;
+       int ret;
+
+       ra.reg = priv->regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_STATUS];
+       ra.mask = ~0;
+       ret = priv->read_raw(0, &ra);
+       if (ret || !ra.value)
+               return -ENODEV;
+
+       ra.reg = priv->regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_LIMIT];
+       ra.mask = ~0;
+       ret = priv->read_raw(0, &ra);
+       if (ret || !ra.value)
+               return -ENODEV;
+
+       rd = kzalloc(sizeof(*rd), GFP_KERNEL);
+       if (!rd)
+               return -ENOMEM;
+
+       rd->name = rapl_domain_names[RAPL_DOMAIN_PLATFORM];
+       rd->id = RAPL_DOMAIN_PLATFORM;
+       rd->regs[RAPL_DOMAIN_REG_LIMIT] =
+           priv->regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_LIMIT];
+       rd->regs[RAPL_DOMAIN_REG_STATUS] =
+           priv->regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_STATUS];
+       rd->rpl[0].prim_id = PL1_ENABLE;
+       rd->rpl[0].name = pl1_name;
+       rd->rpl[1].prim_id = PL2_ENABLE;
+       rd->rpl[1].name = pl2_name;
+       rd->rp = rapl_find_package_domain(0, priv);
+
+       power_zone = powercap_register_zone(&rd->power_zone, priv->control_type,
+                                           "psys", NULL,
+                                           &zone_ops[RAPL_DOMAIN_PLATFORM],
+                                           2, &constraint_ops);
+
+       if (IS_ERR(power_zone)) {
+               kfree(rd);
+               return PTR_ERR(power_zone);
+       }
+
+       priv->platform_rapl_domain = rd;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rapl_add_platform_domain);
+
+void rapl_remove_platform_domain(struct rapl_if_priv *priv)
+{
+       if (priv->platform_rapl_domain) {
+               powercap_unregister_zone(priv->control_type,
+                                &priv->platform_rapl_domain->power_zone);
+               kfree(priv->platform_rapl_domain);
+       }
+}
+EXPORT_SYMBOL_GPL(rapl_remove_platform_domain);
+
+static int rapl_check_domain(int cpu, int domain, struct rapl_package *rp)
+{
+       struct reg_action ra;
+
+       switch (domain) {
+       case RAPL_DOMAIN_PACKAGE:
+       case RAPL_DOMAIN_PP0:
+       case RAPL_DOMAIN_PP1:
+       case RAPL_DOMAIN_DRAM:
+               ra.reg = rp->priv->regs[domain][RAPL_DOMAIN_REG_STATUS];
+               break;
+       case RAPL_DOMAIN_PLATFORM:
+               /* PSYS(PLATFORM) is not a CPU domain, so avoid printng error */
+               return -EINVAL;
+       default:
+               pr_err("invalid domain id %d\n", domain);
+               return -EINVAL;
+       }
+       /* make sure domain counters are available and contains non-zero
+        * values, otherwise skip it.
+        */
+
+       ra.mask = ~0;
+       if (rp->priv->read_raw(cpu, &ra) || !ra.value)
+               return -ENODEV;
+
+       return 0;
+}
+
+/*
+ * Check if power limits are available. Two cases when they are not available:
+ * 1. Locked by BIOS, in this case we still provide read-only access so that
+ *    users can see what limit is set by the BIOS.
+ * 2. Some CPUs make some domains monitoring only which means PLx MSRs may not
+ *    exist at all. In this case, we do not show the constraints in powercap.
+ *
+ * Called after domains are detected and initialized.
+ */
+static void rapl_detect_powerlimit(struct rapl_domain *rd)
+{
+       u64 val64;
+       int i;
+
+       /* check if the domain is locked by BIOS, ignore if MSR doesn't exist */
+       if (!rapl_read_data_raw(rd, FW_LOCK, false, &val64)) {
+               if (val64) {
+                       pr_info("RAPL %s domain %s locked by BIOS\n",
+                               rd->rp->name, rd->name);
+                       rd->state |= DOMAIN_STATE_BIOS_LOCKED;
+               }
+       }
+       /* check if power limit MSR exists, otherwise domain is monitoring only */
+       for (i = 0; i < NR_POWER_LIMITS; i++) {
+               int prim = rd->rpl[i].prim_id;
+
+               if (rapl_read_data_raw(rd, prim, false, &val64))
+                       rd->rpl[i].name = NULL;
+       }
+}
+
+/* Detect active and valid domains for the given CPU, caller must
+ * ensure the CPU belongs to the targeted package and CPU hotlug is disabled.
+ */
+static int rapl_detect_domains(struct rapl_package *rp, int cpu)
+{
+       struct rapl_domain *rd;
+       int i;
+
+       for (i = 0; i < RAPL_DOMAIN_MAX; i++) {
+               /* use physical package id to read counters */
+               if (!rapl_check_domain(cpu, i, rp)) {
+                       rp->domain_map |= 1 << i;
+                       pr_info("Found RAPL domain %s\n", rapl_domain_names[i]);
+               }
+       }
+       rp->nr_domains = bitmap_weight(&rp->domain_map, RAPL_DOMAIN_MAX);
+       if (!rp->nr_domains) {
+               pr_debug("no valid rapl domains found in %s\n", rp->name);
+               return -ENODEV;
+       }
+       pr_debug("found %d domains on %s\n", rp->nr_domains, rp->name);
+
+       rp->domains = kcalloc(rp->nr_domains + 1, sizeof(struct rapl_domain),
+                             GFP_KERNEL);
+       if (!rp->domains)
+               return -ENOMEM;
+
+       rapl_init_domains(rp);
+
+       for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++)
+               rapl_detect_powerlimit(rd);
+
+       return 0;
+}
+
+/* called from CPU hotplug notifier, hotplug lock held */
+void rapl_remove_package(struct rapl_package *rp)
+{
+       struct rapl_domain *rd, *rd_package = NULL;
+
+       package_power_limit_irq_restore(rp);
+
+       for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++) {
+               rapl_write_data_raw(rd, PL1_ENABLE, 0);
+               rapl_write_data_raw(rd, PL1_CLAMP, 0);
+               if (find_nr_power_limit(rd) > 1) {
+                       rapl_write_data_raw(rd, PL2_ENABLE, 0);
+                       rapl_write_data_raw(rd, PL2_CLAMP, 0);
+               }
+               if (rd->id == RAPL_DOMAIN_PACKAGE) {
+                       rd_package = rd;
+                       continue;
+               }
+               pr_debug("remove package, undo power limit on %s: %s\n",
+                        rp->name, rd->name);
+               powercap_unregister_zone(rp->priv->control_type,
+                                        &rd->power_zone);
+       }
+       /* do parent zone last */
+       powercap_unregister_zone(rp->priv->control_type,
+                                &rd_package->power_zone);
+       list_del(&rp->plist);
+       kfree(rp);
+}
+EXPORT_SYMBOL_GPL(rapl_remove_package);
+
+/* caller to ensure CPU hotplug lock is held */
+struct rapl_package *rapl_find_package_domain(int cpu, struct rapl_if_priv *priv)
+{
+       int id = topology_logical_die_id(cpu);
+       struct rapl_package *rp;
+
+       list_for_each_entry(rp, &rapl_packages, plist) {
+               if (rp->id == id
+                   && rp->priv->control_type == priv->control_type)
+                       return rp;
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(rapl_find_package_domain);
+
+/* called from CPU hotplug notifier, hotplug lock held */
+struct rapl_package *rapl_add_package(int cpu, struct rapl_if_priv *priv)
+{
+       int id = topology_logical_die_id(cpu);
+       struct rapl_package *rp;
+       struct cpuinfo_x86 *c = &cpu_data(cpu);
+       int ret;
+
+       rp = kzalloc(sizeof(struct rapl_package), GFP_KERNEL);
+       if (!rp)
+               return ERR_PTR(-ENOMEM);
+
+       /* add the new package to the list */
+       rp->id = id;
+       rp->lead_cpu = cpu;
+       rp->priv = priv;
+
+       if (topology_max_die_per_package() > 1)
+               snprintf(rp->name, PACKAGE_DOMAIN_NAME_LENGTH,
+                        "package-%d-die-%d", c->phys_proc_id, c->cpu_die_id);
+       else
+               snprintf(rp->name, PACKAGE_DOMAIN_NAME_LENGTH, "package-%d",
+                        c->phys_proc_id);
+
+       /* check if the package contains valid domains */
+       if (rapl_detect_domains(rp, cpu) || rapl_defaults->check_unit(rp, cpu)) {
+               ret = -ENODEV;
+               goto err_free_package;
+       }
+       ret = rapl_package_register_powercap(rp);
+       if (!ret) {
+               INIT_LIST_HEAD(&rp->plist);
+               list_add(&rp->plist, &rapl_packages);
+               return rp;
+       }
+
+err_free_package:
+       kfree(rp->domains);
+       kfree(rp);
+       return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(rapl_add_package);
+
+static void power_limit_state_save(void)
+{
+       struct rapl_package *rp;
+       struct rapl_domain *rd;
+       int nr_pl, ret, i;
+
+       get_online_cpus();
+       list_for_each_entry(rp, &rapl_packages, plist) {
+               if (!rp->power_zone)
+                       continue;
+               rd = power_zone_to_rapl_domain(rp->power_zone);
+               nr_pl = find_nr_power_limit(rd);
+               for (i = 0; i < nr_pl; i++) {
+                       switch (rd->rpl[i].prim_id) {
+                       case PL1_ENABLE:
+                               ret = rapl_read_data_raw(rd,
+                                                POWER_LIMIT1, true,
+                                                &rd->rpl[i].last_power_limit);
+                               if (ret)
+                                       rd->rpl[i].last_power_limit = 0;
+                               break;
+                       case PL2_ENABLE:
+                               ret = rapl_read_data_raw(rd,
+                                                POWER_LIMIT2, true,
+                                                &rd->rpl[i].last_power_limit);
+                               if (ret)
+                                       rd->rpl[i].last_power_limit = 0;
+                               break;
+                       }
+               }
+       }
+       put_online_cpus();
+}
+
+static void power_limit_state_restore(void)
+{
+       struct rapl_package *rp;
+       struct rapl_domain *rd;
+       int nr_pl, i;
+
+       get_online_cpus();
+       list_for_each_entry(rp, &rapl_packages, plist) {
+               if (!rp->power_zone)
+                       continue;
+               rd = power_zone_to_rapl_domain(rp->power_zone);
+               nr_pl = find_nr_power_limit(rd);
+               for (i = 0; i < nr_pl; i++) {
+                       switch (rd->rpl[i].prim_id) {
+                       case PL1_ENABLE:
+                               if (rd->rpl[i].last_power_limit)
+                                       rapl_write_data_raw(rd, POWER_LIMIT1,
+                                           rd->rpl[i].last_power_limit);
+                               break;
+                       case PL2_ENABLE:
+                               if (rd->rpl[i].last_power_limit)
+                                       rapl_write_data_raw(rd, POWER_LIMIT2,
+                                           rd->rpl[i].last_power_limit);
+                               break;
+                       }
+               }
+       }
+       put_online_cpus();
+}
+
+static int rapl_pm_callback(struct notifier_block *nb,
+                           unsigned long mode, void *_unused)
+{
+       switch (mode) {
+       case PM_SUSPEND_PREPARE:
+               power_limit_state_save();
+               break;
+       case PM_POST_SUSPEND:
+               power_limit_state_restore();
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block rapl_pm_notifier = {
+       .notifier_call = rapl_pm_callback,
+};
+
+static struct platform_device *rapl_msr_platdev;
+
+static int __init rapl_init(void)
+{
+       const struct x86_cpu_id *id;
+       int ret;
+
+       id = x86_match_cpu(rapl_ids);
+       if (!id) {
+               pr_err("driver does not support CPU family %d model %d\n",
+                      boot_cpu_data.x86, boot_cpu_data.x86_model);
+
+               return -ENODEV;
+       }
+
+       rapl_defaults = (struct rapl_defaults *)id->driver_data;
+
+       ret = register_pm_notifier(&rapl_pm_notifier);
+       if (ret)
+               return ret;
+
+       rapl_msr_platdev = platform_device_alloc("intel_rapl_msr", 0);
+       if (!rapl_msr_platdev) {
+               ret = -ENOMEM;
+               goto end;
+       }
+
+       ret = platform_device_add(rapl_msr_platdev);
+       if (ret)
+               platform_device_put(rapl_msr_platdev);
+
+end:
+       if (ret)
+               unregister_pm_notifier(&rapl_pm_notifier);
+
+       return ret;
+}
+
+static void __exit rapl_exit(void)
+{
+       platform_device_unregister(rapl_msr_platdev);
+       unregister_pm_notifier(&rapl_pm_notifier);
+}
+
+fs_initcall(rapl_init);
+module_exit(rapl_exit);
+
+MODULE_DESCRIPTION("Intel Runtime Average Power Limit (RAPL) common code");
+MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@intel.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/powercap/intel_rapl_msr.c b/drivers/powercap/intel_rapl_msr.c
new file mode 100644 (file)
index 0000000..d548796
--- /dev/null
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Intel Running Average Power Limit (RAPL) Driver via MSR interface
+ * Copyright (c) 2019, Intel Corporation.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/log2.h>
+#include <linux/bitmap.h>
+#include <linux/delay.h>
+#include <linux/sysfs.h>
+#include <linux/cpu.h>
+#include <linux/powercap.h>
+#include <linux/suspend.h>
+#include <linux/intel_rapl.h>
+#include <linux/processor.h>
+#include <linux/platform_device.h>
+
+#include <asm/iosf_mbi.h>
+#include <asm/cpu_device_id.h>
+#include <asm/intel-family.h>
+
+/* Local defines */
+#define MSR_PLATFORM_POWER_LIMIT       0x0000065C
+
+/* private data for RAPL MSR Interface */
+static struct rapl_if_priv rapl_msr_priv = {
+       .reg_unit = MSR_RAPL_POWER_UNIT,
+       .regs[RAPL_DOMAIN_PACKAGE] = {
+               MSR_PKG_POWER_LIMIT, MSR_PKG_ENERGY_STATUS, MSR_PKG_PERF_STATUS, 0, MSR_PKG_POWER_INFO },
+       .regs[RAPL_DOMAIN_PP0] = {
+               MSR_PP0_POWER_LIMIT, MSR_PP0_ENERGY_STATUS, 0, MSR_PP0_POLICY, 0 },
+       .regs[RAPL_DOMAIN_PP1] = {
+               MSR_PP1_POWER_LIMIT, MSR_PP1_ENERGY_STATUS, 0, MSR_PP1_POLICY, 0 },
+       .regs[RAPL_DOMAIN_DRAM] = {
+               MSR_DRAM_POWER_LIMIT, MSR_DRAM_ENERGY_STATUS, MSR_DRAM_PERF_STATUS, 0, MSR_DRAM_POWER_INFO },
+       .regs[RAPL_DOMAIN_PLATFORM] = {
+               MSR_PLATFORM_POWER_LIMIT, MSR_PLATFORM_ENERGY_STATUS, 0, 0, 0},
+       .limits[RAPL_DOMAIN_PACKAGE] = 2,
+};
+
+/* Handles CPU hotplug on multi-socket systems.
+ * If a CPU goes online as the first CPU of the physical package
+ * we add the RAPL package to the system. Similarly, when the last
+ * CPU of the package is removed, we remove the RAPL package and its
+ * associated domains. Cooling devices are handled accordingly at
+ * per-domain level.
+ */
+static int rapl_cpu_online(unsigned int cpu)
+{
+       struct rapl_package *rp;
+
+       rp = rapl_find_package_domain(cpu, &rapl_msr_priv);
+       if (!rp) {
+               rp = rapl_add_package(cpu, &rapl_msr_priv);
+               if (IS_ERR(rp))
+                       return PTR_ERR(rp);
+       }
+       cpumask_set_cpu(cpu, &rp->cpumask);
+       return 0;
+}
+
+static int rapl_cpu_down_prep(unsigned int cpu)
+{
+       struct rapl_package *rp;
+       int lead_cpu;
+
+       rp = rapl_find_package_domain(cpu, &rapl_msr_priv);
+       if (!rp)
+               return 0;
+
+       cpumask_clear_cpu(cpu, &rp->cpumask);
+       lead_cpu = cpumask_first(&rp->cpumask);
+       if (lead_cpu >= nr_cpu_ids)
+               rapl_remove_package(rp);
+       else if (rp->lead_cpu == cpu)
+               rp->lead_cpu = lead_cpu;
+       return 0;
+}
+
+static int rapl_msr_read_raw(int cpu, struct reg_action *ra)
+{
+       u32 msr = (u32)ra->reg;
+
+       if (rdmsrl_safe_on_cpu(cpu, msr, &ra->value)) {
+               pr_debug("failed to read msr 0x%x on cpu %d\n", msr, cpu);
+               return -EIO;
+       }
+       ra->value &= ra->mask;
+       return 0;
+}
+
+static void rapl_msr_update_func(void *info)
+{
+       struct reg_action *ra = info;
+       u32 msr = (u32)ra->reg;
+       u64 val;
+
+       ra->err = rdmsrl_safe(msr, &val);
+       if (ra->err)
+               return;
+
+       val &= ~ra->mask;
+       val |= ra->value;
+
+       ra->err = wrmsrl_safe(msr, val);
+}
+
+static int rapl_msr_write_raw(int cpu, struct reg_action *ra)
+{
+       int ret;
+
+       ret = smp_call_function_single(cpu, rapl_msr_update_func, ra, 1);
+       if (WARN_ON_ONCE(ret))
+               return ret;
+
+       return ra->err;
+}
+
+static int rapl_msr_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       rapl_msr_priv.read_raw = rapl_msr_read_raw;
+       rapl_msr_priv.write_raw = rapl_msr_write_raw;
+
+       rapl_msr_priv.control_type = powercap_register_control_type(NULL, "intel-rapl", NULL);
+       if (IS_ERR(rapl_msr_priv.control_type)) {
+               pr_debug("failed to register powercap control_type.\n");
+               return PTR_ERR(rapl_msr_priv.control_type);
+       }
+
+       ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "powercap/rapl:online",
+                               rapl_cpu_online, rapl_cpu_down_prep);
+       if (ret < 0)
+               goto out;
+       rapl_msr_priv.pcap_rapl_online = ret;
+
+       /* Don't bail out if PSys is not supported */
+       rapl_add_platform_domain(&rapl_msr_priv);
+
+       return 0;
+
+out:
+       if (ret)
+               powercap_unregister_control_type(rapl_msr_priv.control_type);
+       return ret;
+}
+
+static int rapl_msr_remove(struct platform_device *pdev)
+{
+       cpuhp_remove_state(rapl_msr_priv.pcap_rapl_online);
+       rapl_remove_platform_domain(&rapl_msr_priv);
+       powercap_unregister_control_type(rapl_msr_priv.control_type);
+       return 0;
+}
+
+static const struct platform_device_id rapl_msr_ids[] = {
+       { .name = "intel_rapl_msr", },
+       {}
+};
+MODULE_DEVICE_TABLE(platform, rapl_msr_ids);
+
+static struct platform_driver intel_rapl_msr_driver = {
+       .probe = rapl_msr_probe,
+       .remove = rapl_msr_remove,
+       .id_table = rapl_msr_ids,
+       .driver = {
+               .name = "intel_rapl_msr",
+       },
+};
+
+module_platform_driver(intel_rapl_msr_driver);
+
+MODULE_DESCRIPTION("Driver for Intel RAPL (Running Average Power Limit) control via MSR interface");
+MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
+MODULE_LICENSE("GPL v2");
index 540e8aa..f808c5f 100644 (file)
@@ -671,7 +671,7 @@ static int __init powercap_init(void)
        return class_register(&powercap_class);
 }
 
-device_initcall(powercap_init);
+fs_initcall(powercap_init);
 
 MODULE_DESCRIPTION("PowerCap sysfs Driver");
 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
index 3a546ec..22a65ad 100644 (file)
@@ -152,6 +152,14 @@ static long pps_cdev_ioctl(struct file *file,
                        pps->params.mode |= PPS_CANWAIT;
                pps->params.api_version = PPS_API_VERS;
 
+               /*
+                * Clear unused fields of pps_kparams to avoid leaking
+                * uninitialized data of the PPS_SETPARAMS caller via
+                * PPS_GETPARAMS
+                */
+               pps->params.assert_off_tu.flags = 0;
+               pps->params.clear_off_tu.flags = 0;
+
                spin_unlock_irq(&pps->lock);
 
                break;
index fadafc6..677d1af 100644 (file)
@@ -86,7 +86,7 @@ config RAPIDIO_CHMAN
          This option includes RapidIO channelized messaging driver which
          provides socket-like interface to allow sharing of single RapidIO
          messaging mailbox between multiple user-space applications.
-         See "Documentation/rapidio/rio_cm.txt" for driver description.
+         See "Documentation/driver-api/rapidio/rio_cm.rst" for driver description.
 
 config RAPIDIO_MPORT_CDEV
        tristate "RapidIO /dev mport device driver"
index ce7a90e..8155f59 100644 (file)
@@ -1686,6 +1686,7 @@ static int rio_mport_add_riodev(struct mport_cdev_priv *priv,
 
        if (copy_from_user(&dev_info, arg, sizeof(dev_info)))
                return -EFAULT;
+       dev_info.name[sizeof(dev_info.name) - 1] = '\0';
 
        rmcd_debug(RDEV, "name:%s ct:0x%x did:0x%x hc:0x%x", dev_info.name,
                   dev_info.comptag, dev_info.destid, dev_info.hopcount);
@@ -1817,6 +1818,7 @@ static int rio_mport_del_riodev(struct mport_cdev_priv *priv, void __user *arg)
 
        if (copy_from_user(&dev_info, arg, sizeof(dev_info)))
                return -EFAULT;
+       dev_info.name[sizeof(dev_info.name) - 1] = '\0';
 
        mport = priv->md->mport;
 
index 18be41b..28ed306 100644 (file)
@@ -16,7 +16,7 @@ if REMOTEPROC
 
 config IMX_REMOTEPROC
        tristate "IMX6/7 remoteproc support"
-       depends on SOC_IMX6SX || SOC_IMX7D
+       depends on ARCH_MXC
        help
          Say y here to support iMX's remote processors (Cortex M4
          on iMX7D) via the remote processor framework.
@@ -116,6 +116,7 @@ config QCOM_Q6V5_MSS
        depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
        depends on QCOM_SYSMON || QCOM_SYSMON=n
        select MFD_SYSCON
+       select QCOM_MDT_LOADER
        select QCOM_Q6V5_COMMON
        select QCOM_RPROC_COMMON
        select QCOM_SCM
@@ -198,6 +199,21 @@ config ST_REMOTEPROC
 config ST_SLIM_REMOTEPROC
        tristate
 
+config STM32_RPROC
+       tristate "STM32 remoteproc support"
+       depends on ARCH_STM32
+       depends on REMOTEPROC
+       select MAILBOX
+       help
+         Say y here to support STM32 MCU processors via the
+         remote processor framework.
+
+         You want to say y here in order to enable AMP
+         use-cases to run on your platform (dedicated firmware could be
+         offloaded to remote MCU processors using this framework).
+
+         This can be either built-in or a loadable module.
+
 endif # REMOTEPROC
 
 endmenu
index ce5d061..00f09e6 100644 (file)
@@ -26,3 +26,4 @@ qcom_wcnss_pil-y                      += qcom_wcnss.o
 qcom_wcnss_pil-y                       += qcom_wcnss_iris.o
 obj-$(CONFIG_ST_REMOTEPROC)            += st_remoteproc.o
 obj-$(CONFIG_ST_SLIM_REMOTEPROC)       += st_slim_rproc.o
+obj-$(CONFIG_STM32_RPROC)              += stm32_rproc.o
index 36f2f14..3e72b6f 100644 (file)
@@ -165,7 +165,7 @@ static int imx_rproc_start(struct rproc *rproc)
        ret = regmap_update_bits(priv->regmap, dcfg->src_reg,
                                 dcfg->src_mask, dcfg->src_start);
        if (ret)
-               dev_err(dev, "Filed to enable M4!\n");
+               dev_err(dev, "Failed to enable M4!\n");
 
        return ret;
 }
@@ -180,7 +180,7 @@ static int imx_rproc_stop(struct rproc *rproc)
        ret = regmap_update_bits(priv->regmap, dcfg->src_reg,
                                 dcfg->src_mask, dcfg->src_stop);
        if (ret)
-               dev_err(dev, "Filed to stop M4!\n");
+               dev_err(dev, "Failed to stop M4!\n");
 
        return ret;
 }
@@ -203,7 +203,7 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
                }
        }
 
-       dev_warn(priv->dev, "Translation filed: da = 0x%llx len = 0x%x\n",
+       dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%x\n",
                 da, len);
        return -ENOENT;
 }
@@ -349,7 +349,7 @@ static int imx_rproc_probe(struct platform_device *pdev)
 
        ret = imx_rproc_addr_init(priv, pdev);
        if (ret) {
-               dev_err(dev, "filed on imx_rproc_addr_init\n");
+               dev_err(dev, "failed on imx_rproc_addr_init\n");
                goto err_put_rproc;
        }
 
index 1f3ef9e..e953886 100644 (file)
 #define LPASS_PWR_ON_REG               0x10
 #define LPASS_HALTREQ_REG              0x0
 
-/* list of clocks required by ADSP PIL */
-static const char * const adsp_clk_id[] = {
-       "sway_cbcr", "lpass_ahbs_aon_cbcr", "lpass_ahbm_aon_cbcr",
-       "qdsp6ss_xo", "qdsp6ss_sleep", "qdsp6ss_core",
-};
+#define QDSP6SS_XO_CBCR                0x38
+#define QDSP6SS_CORE_CBCR      0x20
+#define QDSP6SS_SLEEP_CBCR     0x3c
 
 struct adsp_pil_data {
        int crash_reason_smem;
@@ -59,6 +57,9 @@ struct adsp_pil_data {
        const char *ssr_name;
        const char *sysmon_name;
        int ssctl_id;
+
+       const char **clk_ids;
+       int num_clks;
 };
 
 struct qcom_adsp {
@@ -75,7 +76,7 @@ struct qcom_adsp {
        void __iomem *qdsp6ss_base;
 
        struct reset_control *pdc_sync_reset;
-       struct reset_control *cc_lpass_restart;
+       struct reset_control *restart;
 
        struct regmap *halt_map;
        unsigned int halt_lpass;
@@ -143,7 +144,7 @@ reset:
        /* Assert the LPASS PDC Reset */
        reset_control_assert(adsp->pdc_sync_reset);
        /* Place the LPASS processor into reset */
-       reset_control_assert(adsp->cc_lpass_restart);
+       reset_control_assert(adsp->restart);
        /* wait after asserting subsystem restart from AOSS */
        usleep_range(200, 300);
 
@@ -153,7 +154,7 @@ reset:
        /* De-assert the LPASS PDC Reset */
        reset_control_deassert(adsp->pdc_sync_reset);
        /* Remove the LPASS reset */
-       reset_control_deassert(adsp->cc_lpass_restart);
+       reset_control_deassert(adsp->restart);
        /* wait after de-asserting subsystem restart from AOSS */
        usleep_range(200, 300);
 
@@ -192,6 +193,15 @@ static int adsp_start(struct rproc *rproc)
                goto disable_power_domain;
        }
 
+       /* Enable the XO clock */
+       writel(1, adsp->qdsp6ss_base + QDSP6SS_XO_CBCR);
+
+       /* Enable the QDSP6SS sleep clock */
+       writel(1, adsp->qdsp6ss_base + QDSP6SS_SLEEP_CBCR);
+
+       /* Enable the QDSP6 core clock */
+       writel(1, adsp->qdsp6ss_base + QDSP6SS_CORE_CBCR);
+
        /* Program boot address */
        writel(adsp->mem_phys >> 4, adsp->qdsp6ss_base + RST_EVB_REG);
 
@@ -280,8 +290,9 @@ static const struct rproc_ops adsp_ops = {
        .load = adsp_load,
 };
 
-static int adsp_init_clock(struct qcom_adsp *adsp)
+static int adsp_init_clock(struct qcom_adsp *adsp, const char **clk_ids)
 {
+       int num_clks = 0;
        int i, ret;
 
        adsp->xo = devm_clk_get(adsp->dev, "xo");
@@ -292,32 +303,39 @@ static int adsp_init_clock(struct qcom_adsp *adsp)
                return ret;
        }
 
-       adsp->num_clks = ARRAY_SIZE(adsp_clk_id);
+       for (i = 0; clk_ids[i]; i++)
+               num_clks++;
+
+       adsp->num_clks = num_clks;
        adsp->clks = devm_kcalloc(adsp->dev, adsp->num_clks,
                                sizeof(*adsp->clks), GFP_KERNEL);
        if (!adsp->clks)
                return -ENOMEM;
 
        for (i = 0; i < adsp->num_clks; i++)
-               adsp->clks[i].id = adsp_clk_id[i];
+               adsp->clks[i].id = clk_ids[i];
 
        return devm_clk_bulk_get(adsp->dev, adsp->num_clks, adsp->clks);
 }
 
 static int adsp_init_reset(struct qcom_adsp *adsp)
 {
-       adsp->pdc_sync_reset = devm_reset_control_get_exclusive(adsp->dev,
+       adsp->pdc_sync_reset = devm_reset_control_get_optional_exclusive(adsp->dev,
                        "pdc_sync");
        if (IS_ERR(adsp->pdc_sync_reset)) {
                dev_err(adsp->dev, "failed to acquire pdc_sync reset\n");
                return PTR_ERR(adsp->pdc_sync_reset);
        }
 
-       adsp->cc_lpass_restart = devm_reset_control_get_exclusive(adsp->dev,
-                       "cc_lpass");
-       if (IS_ERR(adsp->cc_lpass_restart)) {
-               dev_err(adsp->dev, "failed to acquire cc_lpass restart\n");
-               return PTR_ERR(adsp->cc_lpass_restart);
+       adsp->restart = devm_reset_control_get_optional_exclusive(adsp->dev, "restart");
+
+       /* Fall back to the  old "cc_lpass" if "restart" is absent */
+       if (!adsp->restart)
+               adsp->restart = devm_reset_control_get_exclusive(adsp->dev, "cc_lpass");
+
+       if (IS_ERR(adsp->restart)) {
+               dev_err(adsp->dev, "failed to acquire restart\n");
+               return PTR_ERR(adsp->restart);
        }
 
        return 0;
@@ -415,7 +433,7 @@ static int adsp_probe(struct platform_device *pdev)
        if (ret)
                goto free_rproc;
 
-       ret = adsp_init_clock(adsp);
+       ret = adsp_init_clock(adsp, desc->clk_ids);
        if (ret)
                goto free_rproc;
 
@@ -479,9 +497,28 @@ static const struct adsp_pil_data adsp_resource_init = {
        .ssr_name = "lpass",
        .sysmon_name = "adsp",
        .ssctl_id = 0x14,
+       .clk_ids = (const char*[]) {
+               "sway_cbcr", "lpass_ahbs_aon_cbcr", "lpass_ahbm_aon_cbcr",
+               "qdsp6ss_xo", "qdsp6ss_sleep", "qdsp6ss_core", NULL
+       },
+       .num_clks = 7,
+};
+
+static const struct adsp_pil_data cdsp_resource_init = {
+       .crash_reason_smem = 601,
+       .firmware_name = "cdsp.mdt",
+       .ssr_name = "cdsp",
+       .sysmon_name = "cdsp",
+       .ssctl_id = 0x17,
+       .clk_ids = (const char*[]) {
+               "sway", "tbu", "bimc", "ahb_aon", "q6ss_slave", "q6ss_master",
+               "q6_axim", NULL
+       },
+       .num_clks = 7,
 };
 
 static const struct of_device_id adsp_of_match[] = {
+       { .compatible = "qcom,qcs404-cdsp-pil", .data = &cdsp_resource_init },
        { .compatible = "qcom,sdm845-adsp-pil", .data = &adsp_resource_init },
        { },
 };
index 981581b..8fcf9d2 100644 (file)
@@ -659,23 +659,29 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
 {
        unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS;
        dma_addr_t phys;
+       void *metadata;
        int mdata_perm;
        int xferop_ret;
+       size_t size;
        void *ptr;
        int ret;
 
-       ptr = dma_alloc_attrs(qproc->dev, fw->size, &phys, GFP_KERNEL, dma_attrs);
+       metadata = qcom_mdt_read_metadata(fw, &size);
+       if (IS_ERR(metadata))
+               return PTR_ERR(metadata);
+
+       ptr = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs);
        if (!ptr) {
+               kfree(metadata);
                dev_err(qproc->dev, "failed to allocate mdt buffer\n");
                return -ENOMEM;
        }
 
-       memcpy(ptr, fw->data, fw->size);
+       memcpy(ptr, metadata, size);
 
        /* Hypervisor mapping to access metadata by modem */
        mdata_perm = BIT(QCOM_SCM_VMID_HLOS);
-       ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm,
-                                     true, phys, fw->size);
+       ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm, true, phys, size);
        if (ret) {
                dev_err(qproc->dev,
                        "assigning Q6 access to metadata failed: %d\n", ret);
@@ -693,14 +699,14 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
                dev_err(qproc->dev, "MPSS header authentication failed: %d\n", ret);
 
        /* Metadata authentication done, remove modem access */
-       xferop_ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm,
-                                            false, phys, fw->size);
+       xferop_ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm, false, phys, size);
        if (xferop_ret)
                dev_warn(qproc->dev,
                         "mdt buffer not reclaimed system may become unstable\n");
 
 free_dma_attrs:
-       dma_free_attrs(qproc->dev, fw->size, ptr, phys, dma_attrs);
+       dma_free_attrs(qproc->dev, size, ptr, phys, dma_attrs);
+       kfree(metadata);
 
        return ret < 0 ? ret : 0;
 }
@@ -981,7 +987,18 @@ static int q6v5_mpss_load(struct q6v5 *qproc)
 
                ptr = qproc->mpss_region + offset;
 
-               if (phdr->p_filesz) {
+               if (phdr->p_filesz && phdr->p_offset < fw->size) {
+                       /* Firmware is large enough to be non-split */
+                       if (phdr->p_offset + phdr->p_filesz > fw->size) {
+                               dev_err(qproc->dev,
+                                       "failed to load segment %d from truncated file %s\n",
+                                       i, fw_name);
+                               ret = -EINVAL;
+                               goto release_firmware;
+                       }
+
+                       memcpy(ptr, fw->data + phdr->p_offset, phdr->p_filesz);
+               } else if (phdr->p_filesz) {
                        /* Replace "xxx.xxx" with "xxx.bxx" */
                        sprintf(fw_name + fw_name_len - 3, "b%02d", i);
                        ret = request_firmware(&seg_fw, fw_name, qproc->dev);
index 8b53632..3c5fbbb 100644 (file)
@@ -512,6 +512,7 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
        /* Initialise vdev subdevice */
        snprintf(name, sizeof(name), "vdev%dbuffer", rvdev->index);
        rvdev->dev.parent = rproc->dev.parent;
+       rvdev->dev.dma_pfn_offset = rproc->dev.parent->dma_pfn_offset;
        rvdev->dev.release = rproc_rvdev_release;
        dev_set_name(&rvdev->dev, "%s#%s", dev_name(rvdev->dev.parent), name);
        dev_set_drvdata(&rvdev->dev, rvdev);
@@ -1058,6 +1059,20 @@ static int rproc_handle_resources(struct rproc *rproc,
 
                dev_dbg(dev, "rsc: type %d\n", hdr->type);
 
+               if (hdr->type >= RSC_VENDOR_START &&
+                   hdr->type <= RSC_VENDOR_END) {
+                       ret = rproc_handle_rsc(rproc, hdr->type, rsc,
+                                              offset + sizeof(*hdr), avail);
+                       if (ret == RSC_HANDLED)
+                               continue;
+                       else if (ret < 0)
+                               break;
+
+                       dev_warn(dev, "unsupported vendor resource %d\n",
+                                hdr->type);
+                       continue;
+               }
+
                if (hdr->type >= RSC_LAST) {
                        dev_warn(dev, "unsupported resource %d\n", hdr->type);
                        continue;
index 215a440..606aae1 100644 (file)
@@ -247,8 +247,7 @@ find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
                }
 
                /* make sure the offsets array isn't truncated */
-               if (table->num * sizeof(table->offset[0]) +
-                               sizeof(struct resource_table) > size) {
+               if (struct_size(table, offset, table->num) > size) {
                        dev_err(dev, "resource table incomplete\n");
                        return NULL;
                }
index a877509..493ef92 100644 (file)
@@ -99,6 +99,17 @@ static inline int rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
 }
 
 static inline
+int rproc_handle_rsc(struct rproc *rproc, u32 rsc_type, void *rsc, int offset,
+                    int avail)
+{
+       if (rproc->ops->handle_rsc)
+               return rproc->ops->handle_rsc(rproc, rsc_type, rsc, offset,
+                                             avail);
+
+       return RSC_IGNORED;
+}
+
+static inline
 struct resource_table *rproc_find_loaded_rsc_table(struct rproc *rproc,
                                                   const struct firmware *fw)
 {
diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
new file mode 100644 (file)
index 0000000..e2da719
--- /dev/null
@@ -0,0 +1,628 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Authors: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
+ *          Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mailbox_client.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/regmap.h>
+#include <linux/remoteproc.h>
+#include <linux/reset.h>
+
+#include "remoteproc_internal.h"
+
+#define HOLD_BOOT              0
+#define RELEASE_BOOT           1
+
+#define MBOX_NB_VQ             2
+#define MBOX_NB_MBX            3
+
+#define STM32_SMC_RCC          0x82001000
+#define STM32_SMC_REG_WRITE    0x1
+
+#define STM32_MBX_VQ0          "vq0"
+#define STM32_MBX_VQ1          "vq1"
+#define STM32_MBX_SHUTDOWN     "shutdown"
+
+struct stm32_syscon {
+       struct regmap *map;
+       u32 reg;
+       u32 mask;
+};
+
+struct stm32_rproc_mem {
+       char name[20];
+       void __iomem *cpu_addr;
+       phys_addr_t bus_addr;
+       u32 dev_addr;
+       size_t size;
+};
+
+struct stm32_rproc_mem_ranges {
+       u32 dev_addr;
+       u32 bus_addr;
+       u32 size;
+};
+
+struct stm32_mbox {
+       const unsigned char name[10];
+       struct mbox_chan *chan;
+       struct mbox_client client;
+       int vq_id;
+};
+
+struct stm32_rproc {
+       struct reset_control *rst;
+       struct stm32_syscon hold_boot;
+       struct stm32_syscon pdds;
+       u32 nb_rmems;
+       struct stm32_rproc_mem *rmems;
+       struct stm32_mbox mb[MBOX_NB_MBX];
+       bool secured_soc;
+};
+
+static int stm32_rproc_pa_to_da(struct rproc *rproc, phys_addr_t pa, u64 *da)
+{
+       unsigned int i;
+       struct stm32_rproc *ddata = rproc->priv;
+       struct stm32_rproc_mem *p_mem;
+
+       for (i = 0; i < ddata->nb_rmems; i++) {
+               p_mem = &ddata->rmems[i];
+
+               if (pa < p_mem->bus_addr ||
+                   pa >= p_mem->bus_addr + p_mem->size)
+                       continue;
+               *da = pa - p_mem->bus_addr + p_mem->dev_addr;
+               dev_dbg(rproc->dev.parent, "pa %pa to da %llx\n", &pa, *da);
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int stm32_rproc_mem_alloc(struct rproc *rproc,
+                                struct rproc_mem_entry *mem)
+{
+       struct device *dev = rproc->dev.parent;
+       void *va;
+
+       dev_dbg(dev, "map memory: %pa+%x\n", &mem->dma, mem->len);
+       va = ioremap_wc(mem->dma, mem->len);
+       if (IS_ERR_OR_NULL(va)) {
+               dev_err(dev, "Unable to map memory region: %pa+%x\n",
+                       &mem->dma, mem->len);
+               return -ENOMEM;
+       }
+
+       /* Update memory entry va */
+       mem->va = va;
+
+       return 0;
+}
+
+static int stm32_rproc_mem_release(struct rproc *rproc,
+                                  struct rproc_mem_entry *mem)
+{
+       dev_dbg(rproc->dev.parent, "unmap memory: %pa\n", &mem->dma);
+       iounmap(mem->va);
+
+       return 0;
+}
+
+static int stm32_rproc_of_memory_translations(struct rproc *rproc)
+{
+       struct device *parent, *dev = rproc->dev.parent;
+       struct stm32_rproc *ddata = rproc->priv;
+       struct device_node *np;
+       struct stm32_rproc_mem *p_mems;
+       struct stm32_rproc_mem_ranges *mem_range;
+       int cnt, array_size, i, ret = 0;
+
+       parent = dev->parent;
+       np = parent->of_node;
+
+       cnt = of_property_count_elems_of_size(np, "dma-ranges",
+                                             sizeof(*mem_range));
+       if (cnt <= 0) {
+               dev_err(dev, "%s: dma-ranges property not defined\n", __func__);
+               return -EINVAL;
+       }
+
+       p_mems = devm_kcalloc(dev, cnt, sizeof(*p_mems), GFP_KERNEL);
+       if (!p_mems)
+               return -ENOMEM;
+       mem_range = kcalloc(cnt, sizeof(*mem_range), GFP_KERNEL);
+       if (!mem_range)
+               return -ENOMEM;
+
+       array_size = cnt * sizeof(struct stm32_rproc_mem_ranges) / sizeof(u32);
+
+       ret = of_property_read_u32_array(np, "dma-ranges",
+                                        (u32 *)mem_range, array_size);
+       if (ret) {
+               dev_err(dev, "error while get dma-ranges property: %x\n", ret);
+               goto free_mem;
+       }
+
+       for (i = 0; i < cnt; i++) {
+               p_mems[i].bus_addr = mem_range[i].bus_addr;
+               p_mems[i].dev_addr = mem_range[i].dev_addr;
+               p_mems[i].size     = mem_range[i].size;
+
+               dev_dbg(dev, "memory range[%i]: da %#x, pa %pa, size %#zx:\n",
+                       i, p_mems[i].dev_addr, &p_mems[i].bus_addr,
+                       p_mems[i].size);
+       }
+
+       ddata->rmems = p_mems;
+       ddata->nb_rmems = cnt;
+
+free_mem:
+       kfree(mem_range);
+       return ret;
+}
+
+static int stm32_rproc_mbox_idx(struct rproc *rproc, const unsigned char *name)
+{
+       struct stm32_rproc *ddata = rproc->priv;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ddata->mb); i++) {
+               if (!strncmp(ddata->mb[i].name, name, strlen(name)))
+                       return i;
+       }
+       dev_err(&rproc->dev, "mailbox %s not found\n", name);
+
+       return -EINVAL;
+}
+
+static int stm32_rproc_elf_load_rsc_table(struct rproc *rproc,
+                                         const struct firmware *fw)
+{
+       if (rproc_elf_load_rsc_table(rproc, fw))
+               dev_warn(&rproc->dev, "no resource table found for this firmware\n");
+
+       return 0;
+}
+
+static int stm32_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
+{
+       struct device *dev = rproc->dev.parent;
+       struct device_node *np = dev->of_node;
+       struct of_phandle_iterator it;
+       struct rproc_mem_entry *mem;
+       struct reserved_mem *rmem;
+       u64 da;
+       int index = 0;
+
+       /* Register associated reserved memory regions */
+       of_phandle_iterator_init(&it, np, "memory-region", NULL, 0);
+       while (of_phandle_iterator_next(&it) == 0) {
+               rmem = of_reserved_mem_lookup(it.node);
+               if (!rmem) {
+                       dev_err(dev, "unable to acquire memory-region\n");
+                       return -EINVAL;
+               }
+
+               if (stm32_rproc_pa_to_da(rproc, rmem->base, &da) < 0) {
+                       dev_err(dev, "memory region not valid %pa\n",
+                               &rmem->base);
+                       return -EINVAL;
+               }
+
+               /*  No need to map vdev buffer */
+               if (strcmp(it.node->name, "vdev0buffer")) {
+                       /* Register memory region */
+                       mem = rproc_mem_entry_init(dev, NULL,
+                                                  (dma_addr_t)rmem->base,
+                                                  rmem->size, da,
+                                                  stm32_rproc_mem_alloc,
+                                                  stm32_rproc_mem_release,
+                                                  it.node->name);
+
+                       if (mem)
+                               rproc_coredump_add_segment(rproc, da,
+                                                          rmem->size);
+               } else {
+                       /* Register reserved memory for vdev buffer alloc */
+                       mem = rproc_of_resm_mem_entry_init(dev, index,
+                                                          rmem->size,
+                                                          rmem->base,
+                                                          it.node->name);
+               }
+
+               if (!mem)
+                       return -ENOMEM;
+
+               rproc_add_carveout(rproc, mem);
+               index++;
+       }
+
+       return stm32_rproc_elf_load_rsc_table(rproc, fw);
+}
+
+static irqreturn_t stm32_rproc_wdg(int irq, void *data)
+{
+       struct rproc *rproc = data;
+
+       rproc_report_crash(rproc, RPROC_WATCHDOG);
+
+       return IRQ_HANDLED;
+}
+
+static void stm32_rproc_mb_callback(struct mbox_client *cl, void *data)
+{
+       struct rproc *rproc = dev_get_drvdata(cl->dev);
+       struct stm32_mbox *mb = container_of(cl, struct stm32_mbox, client);
+
+       if (rproc_vq_interrupt(rproc, mb->vq_id) == IRQ_NONE)
+               dev_dbg(&rproc->dev, "no message found in vq%d\n", mb->vq_id);
+}
+
+static void stm32_rproc_free_mbox(struct rproc *rproc)
+{
+       struct stm32_rproc *ddata = rproc->priv;
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(ddata->mb); i++) {
+               if (ddata->mb[i].chan)
+                       mbox_free_channel(ddata->mb[i].chan);
+               ddata->mb[i].chan = NULL;
+       }
+}
+
+static const struct stm32_mbox stm32_rproc_mbox[MBOX_NB_MBX] = {
+       {
+               .name = STM32_MBX_VQ0,
+               .vq_id = 0,
+               .client = {
+                       .rx_callback = stm32_rproc_mb_callback,
+                       .tx_block = false,
+               },
+       },
+       {
+               .name = STM32_MBX_VQ1,
+               .vq_id = 1,
+               .client = {
+                       .rx_callback = stm32_rproc_mb_callback,
+                       .tx_block = false,
+               },
+       },
+       {
+               .name = STM32_MBX_SHUTDOWN,
+               .vq_id = -1,
+               .client = {
+                       .tx_block = true,
+                       .tx_done = NULL,
+                       .tx_tout = 500, /* 500 ms time out */
+               },
+       }
+};
+
+static void stm32_rproc_request_mbox(struct rproc *rproc)
+{
+       struct stm32_rproc *ddata = rproc->priv;
+       struct device *dev = &rproc->dev;
+       unsigned int i;
+       const unsigned char *name;
+       struct mbox_client *cl;
+
+       /* Initialise mailbox structure table */
+       memcpy(ddata->mb, stm32_rproc_mbox, sizeof(stm32_rproc_mbox));
+
+       for (i = 0; i < MBOX_NB_MBX; i++) {
+               name = ddata->mb[i].name;
+
+               cl = &ddata->mb[i].client;
+               cl->dev = dev->parent;
+
+               ddata->mb[i].chan = mbox_request_channel_byname(cl, name);
+               if (IS_ERR(ddata->mb[i].chan)) {
+                       dev_warn(dev, "cannot get %s mbox\n", name);
+                       ddata->mb[i].chan = NULL;
+               }
+       }
+}
+
+static int stm32_rproc_set_hold_boot(struct rproc *rproc, bool hold)
+{
+       struct stm32_rproc *ddata = rproc->priv;
+       struct stm32_syscon hold_boot = ddata->hold_boot;
+       struct arm_smccc_res smc_res;
+       int val, err;
+
+       val = hold ? HOLD_BOOT : RELEASE_BOOT;
+
+       if (IS_ENABLED(CONFIG_HAVE_ARM_SMCCC) && ddata->secured_soc) {
+               arm_smccc_smc(STM32_SMC_RCC, STM32_SMC_REG_WRITE,
+                             hold_boot.reg, val, 0, 0, 0, 0, &smc_res);
+               err = smc_res.a0;
+       } else {
+               err = regmap_update_bits(hold_boot.map, hold_boot.reg,
+                                        hold_boot.mask, val);
+       }
+
+       if (err)
+               dev_err(&rproc->dev, "failed to set hold boot\n");
+
+       return err;
+}
+
+static void stm32_rproc_add_coredump_trace(struct rproc *rproc)
+{
+       struct rproc_debug_trace *trace;
+       struct rproc_dump_segment *segment;
+       bool already_added;
+
+       list_for_each_entry(trace, &rproc->traces, node) {
+               already_added = false;
+
+               list_for_each_entry(segment, &rproc->dump_segments, node) {
+                       if (segment->da == trace->trace_mem.da) {
+                               already_added = true;
+                               break;
+                       }
+               }
+
+               if (!already_added)
+                       rproc_coredump_add_segment(rproc, trace->trace_mem.da,
+                                                  trace->trace_mem.len);
+       }
+}
+
+static int stm32_rproc_start(struct rproc *rproc)
+{
+       int err;
+
+       stm32_rproc_add_coredump_trace(rproc);
+
+       err = stm32_rproc_set_hold_boot(rproc, false);
+       if (err)
+               return err;
+
+       return stm32_rproc_set_hold_boot(rproc, true);
+}
+
+static int stm32_rproc_stop(struct rproc *rproc)
+{
+       struct stm32_rproc *ddata = rproc->priv;
+       int err, dummy_data, idx;
+
+       /* request shutdown of the remote processor */
+       if (rproc->state != RPROC_OFFLINE) {
+               idx = stm32_rproc_mbox_idx(rproc, STM32_MBX_SHUTDOWN);
+               if (idx >= 0 && ddata->mb[idx].chan) {
+                       /* a dummy data is sent to allow to block on transmit */
+                       err = mbox_send_message(ddata->mb[idx].chan,
+                                               &dummy_data);
+                       if (err < 0)
+                               dev_warn(&rproc->dev, "warning: remote FW shutdown without ack\n");
+               }
+       }
+
+       err = stm32_rproc_set_hold_boot(rproc, true);
+       if (err)
+               return err;
+
+       err = reset_control_assert(ddata->rst);
+       if (err) {
+               dev_err(&rproc->dev, "failed to assert the reset\n");
+               return err;
+       }
+
+       /* to allow platform Standby power mode, set remote proc Deep Sleep */
+       if (ddata->pdds.map) {
+               err = regmap_update_bits(ddata->pdds.map, ddata->pdds.reg,
+                                        ddata->pdds.mask, 1);
+               if (err) {
+                       dev_err(&rproc->dev, "failed to set pdds\n");
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+static void stm32_rproc_kick(struct rproc *rproc, int vqid)
+{
+       struct stm32_rproc *ddata = rproc->priv;
+       unsigned int i;
+       int err;
+
+       if (WARN_ON(vqid >= MBOX_NB_VQ))
+               return;
+
+       for (i = 0; i < MBOX_NB_MBX; i++) {
+               if (vqid != ddata->mb[i].vq_id)
+                       continue;
+               if (!ddata->mb[i].chan)
+                       return;
+               err = mbox_send_message(ddata->mb[i].chan, (void *)(long)vqid);
+               if (err < 0)
+                       dev_err(&rproc->dev, "%s: failed (%s, err:%d)\n",
+                               __func__, ddata->mb[i].name, err);
+               return;
+       }
+}
+
+static struct rproc_ops st_rproc_ops = {
+       .start          = stm32_rproc_start,
+       .stop           = stm32_rproc_stop,
+       .kick           = stm32_rproc_kick,
+       .load           = rproc_elf_load_segments,
+       .parse_fw       = stm32_rproc_parse_fw,
+       .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table,
+       .sanity_check   = rproc_elf_sanity_check,
+       .get_boot_addr  = rproc_elf_get_boot_addr,
+};
+
+static const struct of_device_id stm32_rproc_match[] = {
+       { .compatible = "st,stm32mp1-m4" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, stm32_rproc_match);
+
+static int stm32_rproc_get_syscon(struct device_node *np, const char *prop,
+                                 struct stm32_syscon *syscon)
+{
+       int err = 0;
+
+       syscon->map = syscon_regmap_lookup_by_phandle(np, prop);
+       if (IS_ERR(syscon->map)) {
+               err = PTR_ERR(syscon->map);
+               syscon->map = NULL;
+               goto out;
+       }
+
+       err = of_property_read_u32_index(np, prop, 1, &syscon->reg);
+       if (err)
+               goto out;
+
+       err = of_property_read_u32_index(np, prop, 2, &syscon->mask);
+
+out:
+       return err;
+}
+
+static int stm32_rproc_parse_dt(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct rproc *rproc = platform_get_drvdata(pdev);
+       struct stm32_rproc *ddata = rproc->priv;
+       struct stm32_syscon tz;
+       unsigned int tzen;
+       int err, irq;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq > 0) {
+               err = devm_request_irq(dev, irq, stm32_rproc_wdg, 0,
+                                      dev_name(dev), rproc);
+               if (err) {
+                       dev_err(dev, "failed to request wdg irq\n");
+                       return err;
+               }
+
+               dev_info(dev, "wdg irq registered\n");
+       }
+
+       ddata->rst = devm_reset_control_get_by_index(dev, 0);
+       if (IS_ERR(ddata->rst)) {
+               dev_err(dev, "failed to get mcu reset\n");
+               return PTR_ERR(ddata->rst);
+       }
+
+       /*
+        * if platform is secured the hold boot bit must be written by
+        * smc call and read normally.
+        * if not secure the hold boot bit could be read/write normally
+        */
+       err = stm32_rproc_get_syscon(np, "st,syscfg-tz", &tz);
+       if (err) {
+               dev_err(dev, "failed to get tz syscfg\n");
+               return err;
+       }
+
+       err = regmap_read(tz.map, tz.reg, &tzen);
+       if (err) {
+               dev_err(&rproc->dev, "failed to read tzen\n");
+               return err;
+       }
+       ddata->secured_soc = tzen & tz.mask;
+
+       err = stm32_rproc_get_syscon(np, "st,syscfg-holdboot",
+                                    &ddata->hold_boot);
+       if (err) {
+               dev_err(dev, "failed to get hold boot\n");
+               return err;
+       }
+
+       err = stm32_rproc_get_syscon(np, "st,syscfg-pdds", &ddata->pdds);
+       if (err)
+               dev_warn(dev, "failed to get pdds\n");
+
+       rproc->auto_boot = of_property_read_bool(np, "st,auto-boot");
+
+       return stm32_rproc_of_memory_translations(rproc);
+}
+
+static int stm32_rproc_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct stm32_rproc *ddata;
+       struct device_node *np = dev->of_node;
+       struct rproc *rproc;
+       int ret;
+
+       ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
+       if (ret)
+               return ret;
+
+       rproc = rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata));
+       if (!rproc)
+               return -ENOMEM;
+
+       rproc->has_iommu = false;
+       ddata = rproc->priv;
+
+       platform_set_drvdata(pdev, rproc);
+
+       ret = stm32_rproc_parse_dt(pdev);
+       if (ret)
+               goto free_rproc;
+
+       stm32_rproc_request_mbox(rproc);
+
+       ret = rproc_add(rproc);
+       if (ret)
+               goto free_mb;
+
+       return 0;
+
+free_mb:
+       stm32_rproc_free_mbox(rproc);
+free_rproc:
+       rproc_free(rproc);
+       return ret;
+}
+
+static int stm32_rproc_remove(struct platform_device *pdev)
+{
+       struct rproc *rproc = platform_get_drvdata(pdev);
+
+       if (atomic_read(&rproc->power) > 0)
+               rproc_shutdown(rproc);
+
+       rproc_del(rproc);
+       stm32_rproc_free_mbox(rproc);
+       rproc_free(rproc);
+
+       return 0;
+}
+
+static struct platform_driver stm32_rproc_driver = {
+       .probe = stm32_rproc_probe,
+       .remove = stm32_rproc_remove,
+       .driver = {
+               .name = "stm32-rproc",
+               .of_match_table = of_match_ptr(stm32_rproc_match),
+       },
+};
+module_platform_driver(stm32_rproc_driver);
+
+MODULE_DESCRIPTION("STM32 Remote Processor Control Driver");
+MODULE_AUTHOR("Ludovic Barre <ludovic.barre@st.com>");
+MODULE_AUTHOR("Fabien Dessenne <fabien.dessenne@st.com>");
+MODULE_LICENSE("GPL v2");
+
index d506d32..21efb7d 100644 (file)
@@ -118,7 +118,7 @@ config RESET_QCOM_PDC
 
 config RESET_SIMPLE
        bool "Simple Reset Controller Driver" if COMPILE_TEST
-       default ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED
+       default ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED || ARCH_BITMAIN
        help
          This enables a simple reset controller driver for reset lines that
          that can be asserted and deasserted by toggling bits in a contiguous,
@@ -130,6 +130,7 @@ config RESET_SIMPLE
           - RCC reset controller in STM32 MCUs
           - Allwinner SoCs
           - ZTE's zx2967 family
+          - Bitmain BM1880 SoC
 
 config RESET_STM32MP157
        bool "STM32MP157 Reset Driver" if COMPILE_TEST
index 21b9bd5..213ff40 100644 (file)
@@ -690,9 +690,6 @@ __reset_control_get_from_lookup(struct device *dev, const char *con_id,
        const char *dev_id = dev_name(dev);
        struct reset_control *rstc = NULL;
 
-       if (!dev)
-               return ERR_PTR(-EINVAL);
-
        mutex_lock(&reset_lookup_mutex);
 
        list_for_each_entry(lookup, &reset_lookup_list, list) {
index 7e48b9c..1154f7b 100644 (file)
@@ -125,6 +125,8 @@ static const struct of_device_id reset_simple_dt_ids[] = {
                .data = &reset_simple_active_low },
        { .compatible = "aspeed,ast2400-lpc-reset" },
        { .compatible = "aspeed,ast2500-lpc-reset" },
+       { .compatible = "bitmain,bm1880-reset",
+               .data = &reset_simple_active_low },
        { /* sentinel */ },
 };
 
index 8122807..ea88fd4 100644 (file)
@@ -493,7 +493,8 @@ static int rpmsg_dev_remove(struct device *dev)
        if (rpdev->ops->announce_destroy)
                err = rpdev->ops->announce_destroy(rpdev);
 
-       rpdrv->remove(rpdev);
+       if (rpdrv->remove)
+               rpdrv->remove(rpdev);
 
        dev_pm_domain_detach(dev, true);
 
index 3254a30..e72f65b 100644 (file)
@@ -562,7 +562,7 @@ config RTC_DRV_TPS6586X
 
 config RTC_DRV_TPS65910
        tristate "TI TPS65910 RTC driver"
-       depends on RTC_CLASS && MFD_TPS65910
+       depends on MFD_TPS65910
        help
          If you say yes here you get support for the RTC on the
          TPS65910 chips.
@@ -820,6 +820,7 @@ config RTC_DRV_MAX6902
 
 config RTC_DRV_PCF2123
        tristate "NXP PCF2123"
+       select REGMAP_SPI
        help
          If you say yes here you get support for the NXP PCF2123
          RTC chip.
index 4124f4d..72b7ddc 100644 (file)
@@ -633,7 +633,7 @@ enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer)
 {
        struct rtc_device *rtc;
        ktime_t period;
-       int count;
+       u64 count;
 
        rtc = container_of(timer, struct rtc_device, pie_timer);
 
index 93d338e..1f7e8ae 100644 (file)
@@ -222,6 +222,45 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
                return -EINVAL;
        }
 
+       tmp = regs[DS1307_REG_SECS];
+       switch (ds1307->type) {
+       case ds_1307:
+       case m41t0:
+       case m41t00:
+       case m41t11:
+               if (tmp & DS1307_BIT_CH)
+                       return -EINVAL;
+               break;
+       case ds_1308:
+       case ds_1338:
+               if (tmp & DS1307_BIT_CH)
+                       return -EINVAL;
+
+               ret = regmap_read(ds1307->regmap, DS1307_REG_CONTROL, &tmp);
+               if (ret)
+                       return ret;
+               if (tmp & DS1338_BIT_OSF)
+                       return -EINVAL;
+               break;
+       case ds_1340:
+               if (tmp & DS1340_BIT_nEOSC)
+                       return -EINVAL;
+
+               ret = regmap_read(ds1307->regmap, DS1340_REG_FLAG, &tmp);
+               if (ret)
+                       return ret;
+               if (tmp & DS1340_BIT_OSF)
+                       return -EINVAL;
+               break;
+       case mcp794xx:
+               if (!(tmp & MCP794XX_BIT_ST))
+                       return -EINVAL;
+
+               break;
+       default:
+               break;
+       }
+
        t->tm_sec = bcd2bin(regs[DS1307_REG_SECS] & 0x7f);
        t->tm_min = bcd2bin(regs[DS1307_REG_MIN] & 0x7f);
        tmp = regs[DS1307_REG_HOUR] & 0x3f;
@@ -286,7 +325,17 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
        if (t->tm_year > 199 && chip->century_bit)
                regs[chip->century_reg] |= chip->century_bit;
 
-       if (ds1307->type == mcp794xx) {
+       switch (ds1307->type) {
+       case ds_1308:
+       case ds_1338:
+               regmap_update_bits(ds1307->regmap, DS1307_REG_CONTROL,
+                                  DS1338_BIT_OSF, 0);
+               break;
+       case ds_1340:
+               regmap_update_bits(ds1307->regmap, DS1340_REG_FLAG,
+                                  DS1340_BIT_OSF, 0);
+               break;
+       case mcp794xx:
                /*
                 * these bits were cleared when preparing the date/time
                 * values and need to be set again before writing the
@@ -294,6 +343,9 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
                 */
                regs[DS1307_REG_SECS] |= MCP794XX_BIT_ST;
                regs[DS1307_REG_WDAY] |= MCP794XX_BIT_VBATEN;
+               break;
+       default:
+               break;
        }
 
        dev_dbg(dev, "%s: %7ph\n", "write", regs);
@@ -1702,7 +1754,6 @@ static int ds1307_probe(struct i2c_client *client,
                break;
        }
 
-read_rtc:
        /* read RTC registers */
        err = regmap_bulk_read(ds1307->regmap, chip->offset, regs,
                               sizeof(regs));
@@ -1711,75 +1762,11 @@ read_rtc:
                goto exit;
        }
 
-       /*
-        * minimal sanity checking; some chips (like DS1340) don't
-        * specify the extra bits as must-be-zero, but there are
-        * still a few values that are clearly out-of-range.
-        */
-       tmp = regs[DS1307_REG_SECS];
-       switch (ds1307->type) {
-       case ds_1307:
-       case m41t0:
-       case m41t00:
-       case m41t11:
-               /* clock halted?  turn it on, so clock can tick. */
-               if (tmp & DS1307_BIT_CH) {
-                       regmap_write(ds1307->regmap, DS1307_REG_SECS, 0);
-                       dev_warn(ds1307->dev, "SET TIME!\n");
-                       goto read_rtc;
-               }
-               break;
-       case ds_1308:
-       case ds_1338:
-               /* clock halted?  turn it on, so clock can tick. */
-               if (tmp & DS1307_BIT_CH)
-                       regmap_write(ds1307->regmap, DS1307_REG_SECS, 0);
-
-               /* oscillator fault?  clear flag, and warn */
-               if (regs[DS1307_REG_CONTROL] & DS1338_BIT_OSF) {
-                       regmap_write(ds1307->regmap, DS1307_REG_CONTROL,
-                                    regs[DS1307_REG_CONTROL] &
-                                    ~DS1338_BIT_OSF);
-                       dev_warn(ds1307->dev, "SET TIME!\n");
-                       goto read_rtc;
-               }
-               break;
-       case ds_1340:
-               /* clock halted?  turn it on, so clock can tick. */
-               if (tmp & DS1340_BIT_nEOSC)
-                       regmap_write(ds1307->regmap, DS1307_REG_SECS, 0);
-
-               err = regmap_read(ds1307->regmap, DS1340_REG_FLAG, &tmp);
-               if (err) {
-                       dev_dbg(ds1307->dev, "read error %d\n", err);
-                       goto exit;
-               }
-
-               /* oscillator fault?  clear flag, and warn */
-               if (tmp & DS1340_BIT_OSF) {
-                       regmap_write(ds1307->regmap, DS1340_REG_FLAG, 0);
-                       dev_warn(ds1307->dev, "SET TIME!\n");
-               }
-               break;
-       case mcp794xx:
-               /* make sure that the backup battery is enabled */
-               if (!(regs[DS1307_REG_WDAY] & MCP794XX_BIT_VBATEN)) {
-                       regmap_write(ds1307->regmap, DS1307_REG_WDAY,
-                                    regs[DS1307_REG_WDAY] |
-                                    MCP794XX_BIT_VBATEN);
-               }
-
-               /* clock halted?  turn it on, so clock can tick. */
-               if (!(tmp & MCP794XX_BIT_ST)) {
-                       regmap_write(ds1307->regmap, DS1307_REG_SECS,
-                                    MCP794XX_BIT_ST);
-                       dev_warn(ds1307->dev, "SET TIME!\n");
-                       goto read_rtc;
-               }
-
-               break;
-       default:
-               break;
+       if (ds1307->type == mcp794xx &&
+           !(regs[DS1307_REG_WDAY] & MCP794XX_BIT_VBATEN)) {
+               regmap_write(ds1307->regmap, DS1307_REG_WDAY,
+                            regs[DS1307_REG_WDAY] |
+                            MCP794XX_BIT_VBATEN);
        }
 
        tmp = regs[DS1307_REG_HOUR];
index 1e9f429..9df0c44 100644 (file)
@@ -182,9 +182,10 @@ static void ds2404_enable_osc(struct device *dev)
 static int ds2404_read_time(struct device *dev, struct rtc_time *dt)
 {
        unsigned long time = 0;
+       __le32 hw_time = 0;
 
-       ds2404_read_memory(dev, 0x203, 4, (u8 *)&time);
-       time = le32_to_cpu(time);
+       ds2404_read_memory(dev, 0x203, 4, (u8 *)&hw_time);
+       time = le32_to_cpu(hw_time);
 
        rtc_time64_to_tm(time, dt);
        return 0;
index 1caa21b..677ec2d 100644 (file)
@@ -104,8 +104,7 @@ static int fm3130_get_time(struct device *dev, struct rtc_time *t)
        fm3130_rtc_mode(dev, FM3130_MODE_READ);
 
        /* read the RTC date and time registers all at once */
-       tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent),
-                       fm3130->msg, 2);
+       tmp = i2c_transfer(fm3130->client->adapter, fm3130->msg, 2);
        if (tmp != 2) {
                dev_err(dev, "%s error %d\n", "read", tmp);
                return -EIO;
@@ -197,8 +196,7 @@ static int fm3130_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
        }
 
        /* read the RTC alarm registers all at once */
-       tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent),
-                       &fm3130->msg[2], 2);
+       tmp = i2c_transfer(fm3130->client->adapter, &fm3130->msg[2], 2);
        if (tmp != 2) {
                dev_err(dev, "%s error %d\n", "read", tmp);
                return -EIO;
@@ -348,7 +346,7 @@ static int fm3130_probe(struct i2c_client *client,
        struct fm3130           *fm3130;
        int                     err = -ENODEV;
        int                     tmp;
-       struct i2c_adapter      *adapter = to_i2c_adapter(client->dev.parent);
+       struct i2c_adapter      *adapter = client->adapter;
 
        if (!i2c_check_functionality(adapter,
                        I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
index 19642bf..c933045 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright 2018 NXP.
  */
 
+#include <dt-bindings/firmware/imx/rsrc.h>
 #include <linux/arm-smccc.h>
 #include <linux/firmware/imx/sci.h>
 #include <linux/module.h>
 #include <linux/rtc.h>
 
 #define IMX_SC_TIMER_FUNC_GET_RTC_SEC1970      9
+#define IMX_SC_TIMER_FUNC_SET_RTC_ALARM                8
 #define IMX_SC_TIMER_FUNC_SET_RTC_TIME         6
 
 #define IMX_SIP_SRTC                   0xC2000002
 #define IMX_SIP_SRTC_SET_TIME          0x0
 
+#define SC_IRQ_GROUP_RTC    2
+#define SC_IRQ_RTC          1
+
 static struct imx_sc_ipc *rtc_ipc_handle;
 static struct rtc_device *imx_sc_rtc;
 
@@ -24,6 +29,16 @@ struct imx_sc_msg_timer_get_rtc_time {
        u32 time;
 } __packed;
 
+struct imx_sc_msg_timer_rtc_set_alarm {
+       struct imx_sc_rpc_msg hdr;
+       u16 year;
+       u8 mon;
+       u8 day;
+       u8 hour;
+       u8 min;
+       u8 sec;
+} __packed;
+
 static int imx_sc_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
        struct imx_sc_msg_timer_get_rtc_time msg;
@@ -60,9 +75,77 @@ static int imx_sc_rtc_set_time(struct device *dev, struct rtc_time *tm)
        return res.a0;
 }
 
+static int imx_sc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
+{
+       return imx_scu_irq_group_enable(SC_IRQ_GROUP_RTC, SC_IRQ_RTC, enable);
+}
+
+static int imx_sc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       /*
+        * SCU firmware does NOT provide read alarm API, but .read_alarm
+        * callback is required by RTC framework to support alarm function,
+        * so just return here.
+        */
+       return 0;
+}
+
+static int imx_sc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct imx_sc_msg_timer_rtc_set_alarm msg;
+       struct imx_sc_rpc_msg *hdr = &msg.hdr;
+       int ret;
+       struct rtc_time *alrm_tm = &alrm->time;
+
+       hdr->ver = IMX_SC_RPC_VERSION;
+       hdr->svc = IMX_SC_RPC_SVC_TIMER;
+       hdr->func = IMX_SC_TIMER_FUNC_SET_RTC_ALARM;
+       hdr->size = 3;
+
+       msg.year = alrm_tm->tm_year + 1900;
+       msg.mon = alrm_tm->tm_mon + 1;
+       msg.day = alrm_tm->tm_mday;
+       msg.hour = alrm_tm->tm_hour;
+       msg.min = alrm_tm->tm_min;
+       msg.sec = alrm_tm->tm_sec;
+
+       ret = imx_scu_call_rpc(rtc_ipc_handle, &msg, true);
+       if (ret) {
+               dev_err(dev, "set rtc alarm failed, ret %d\n", ret);
+               return ret;
+       }
+
+       ret = imx_sc_rtc_alarm_irq_enable(dev, alrm->enabled);
+       if (ret) {
+               dev_err(dev, "enable rtc alarm failed, ret %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
 static const struct rtc_class_ops imx_sc_rtc_ops = {
        .read_time = imx_sc_rtc_read_time,
        .set_time = imx_sc_rtc_set_time,
+       .read_alarm = imx_sc_rtc_read_alarm,
+       .set_alarm = imx_sc_rtc_set_alarm,
+       .alarm_irq_enable = imx_sc_rtc_alarm_irq_enable,
+};
+
+static int imx_sc_rtc_alarm_notify(struct notifier_block *nb,
+                                       unsigned long event, void *group)
+{
+       /* ignore non-rtc irq */
+       if (!((event & SC_IRQ_RTC) && (*(u8 *)group == SC_IRQ_GROUP_RTC)))
+               return 0;
+
+       rtc_update_irq(imx_sc_rtc, 1, RTC_IRQF | RTC_AF);
+
+       return 0;
+}
+
+static struct notifier_block imx_sc_rtc_alarm_sc_notifier = {
+       .notifier_call = imx_sc_rtc_alarm_notify,
 };
 
 static int imx_sc_rtc_probe(struct platform_device *pdev)
@@ -73,6 +156,8 @@ static int imx_sc_rtc_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       device_init_wakeup(&pdev->dev, true);
+
        imx_sc_rtc = devm_rtc_allocate_device(&pdev->dev);
        if (IS_ERR(imx_sc_rtc))
                return PTR_ERR(imx_sc_rtc);
@@ -87,6 +172,8 @@ static int imx_sc_rtc_probe(struct platform_device *pdev)
                return ret;
        }
 
+       imx_scu_irq_register_notifier(&imx_sc_rtc_alarm_sc_notifier);
+
        return 0;
 }
 
index 9fdc284..5f46f85 100644 (file)
@@ -872,7 +872,7 @@ static struct notifier_block wdt_notifier = {
 static int m41t80_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
-       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+       struct i2c_adapter *adapter = client->adapter;
        int rc = 0;
        struct rtc_time tm;
        struct m41t80_data *m41t80_data = NULL;
index f431263..fb542a9 100644 (file)
@@ -40,7 +40,7 @@
 #include <linux/rtc.h>
 #include <linux/spi/spi.h>
 #include <linux/module.h>
-#include <linux/sysfs.h>
+#include <linux/regmap.h>
 
 /* REGISTERS */
 #define PCF2123_REG_CTRL1      (0x00)  /* Control Register 1 */
@@ -95,6 +95,7 @@
 #define OFFSET_SIGN_BIT                6       /* 2's complement sign bit */
 #define OFFSET_COARSE          BIT(7)  /* Coarse mode offset */
 #define OFFSET_STEP            (2170)  /* Offset step in parts per billion */
+#define OFFSET_MASK            GENMASK(6, 0)   /* Offset value */
 
 /* READ/WRITE ADDRESS BITS */
 #define PCF2123_WRITE          BIT(4)
 
 static struct spi_driver pcf2123_driver;
 
-struct pcf2123_sysfs_reg {
-       struct device_attribute attr;
-       char name[2];
-};
-
 struct pcf2123_plat_data {
        struct rtc_device *rtc;
-       struct pcf2123_sysfs_reg regs[16];
+       struct regmap *map;
 };
 
-/*
- * Causes a 30 nanosecond delay to ensure that the PCF2123 chip select
- * is released properly after an SPI write.  This function should be
- * called after EVERY read/write call over SPI.
- */
-static inline void pcf2123_delay_trec(void)
-{
-       ndelay(30);
-}
-
-static int pcf2123_read(struct device *dev, u8 reg, u8 *rxbuf, size_t size)
-{
-       struct spi_device *spi = to_spi_device(dev);
-       int ret;
-
-       reg |= PCF2123_READ;
-       ret = spi_write_then_read(spi, &reg, 1, rxbuf, size);
-       pcf2123_delay_trec();
-
-       return ret;
-}
-
-static int pcf2123_write(struct device *dev, u8 *txbuf, size_t size)
-{
-       struct spi_device *spi = to_spi_device(dev);
-       int ret;
-
-       txbuf[0] |= PCF2123_WRITE;
-       ret = spi_write(spi, txbuf, size);
-       pcf2123_delay_trec();
-
-       return ret;
-}
-
-static int pcf2123_write_reg(struct device *dev, u8 reg, u8 val)
-{
-       u8 txbuf[2];
-
-       txbuf[0] = reg;
-       txbuf[1] = val;
-       return pcf2123_write(dev, txbuf, sizeof(txbuf));
-}
-
-static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr,
-                           char *buffer)
-{
-       struct pcf2123_sysfs_reg *r;
-       u8 rxbuf[1];
-       unsigned long reg;
-       int ret;
-
-       r = container_of(attr, struct pcf2123_sysfs_reg, attr);
-
-       ret = kstrtoul(r->name, 16, &reg);
-       if (ret)
-               return ret;
-
-       ret = pcf2123_read(dev, reg, rxbuf, 1);
-       if (ret < 0)
-               return -EIO;
-
-       return sprintf(buffer, "0x%x\n", rxbuf[0]);
-}
+static const struct regmap_config pcf2123_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .read_flag_mask = PCF2123_READ,
+       .write_flag_mask = PCF2123_WRITE,
+       .max_register = PCF2123_REG_CTDWN_TMR,
+};
 
-static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr,
-                            const char *buffer, size_t count)
+static int pcf2123_read_offset(struct device *dev, long *offset)
 {
-       struct pcf2123_sysfs_reg *r;
-       unsigned long reg;
-       unsigned long val;
-
-       int ret;
+       struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
+       int ret, val;
+       unsigned int reg;
 
-       r = container_of(attr, struct pcf2123_sysfs_reg, attr);
-
-       ret = kstrtoul(r->name, 16, &reg);
+       ret = regmap_read(pdata->map, PCF2123_REG_OFFSET, &reg);
        if (ret)
                return ret;
 
-       ret = kstrtoul(buffer, 10, &val);
-       if (ret)
-               return ret;
-
-       ret = pcf2123_write_reg(dev, reg, val);
-       if (ret < 0)
-               return -EIO;
-       return count;
-}
-
-static int pcf2123_read_offset(struct device *dev, long *offset)
-{
-       int ret;
-       s8 reg;
-
-       ret = pcf2123_read(dev, PCF2123_REG_OFFSET, &reg, 1);
-       if (ret < 0)
-               return ret;
+       val = sign_extend32((reg & OFFSET_MASK), OFFSET_SIGN_BIT);
 
        if (reg & OFFSET_COARSE)
-               reg <<= 1; /* multiply by 2 and sign extend */
-       else
-               reg = sign_extend32(reg, OFFSET_SIGN_BIT);
+               val *= 2;
 
-       *offset = ((long)reg) * OFFSET_STEP;
+       *offset = ((long)val) * OFFSET_STEP;
 
        return 0;
 }
@@ -233,6 +149,7 @@ static int pcf2123_read_offset(struct device *dev, long *offset)
  */
 static int pcf2123_set_offset(struct device *dev, long offset)
 {
+       struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
        s8 reg;
 
        if (offset > OFFSET_STEP * 127)
@@ -240,7 +157,7 @@ static int pcf2123_set_offset(struct device *dev, long offset)
        else if (offset < OFFSET_STEP * -128)
                reg = -128;
        else
-               reg = (s8)((offset + (OFFSET_STEP >> 1)) / OFFSET_STEP);
+               reg = DIV_ROUND_CLOSEST(offset, OFFSET_STEP);
 
        /* choose fine offset only for odd values in the normal range */
        if (reg & 1 && reg <= 63 && reg >= -64) {
@@ -252,16 +169,18 @@ static int pcf2123_set_offset(struct device *dev, long offset)
                reg |= OFFSET_COARSE;
        }
 
-       return pcf2123_write_reg(dev, PCF2123_REG_OFFSET, reg);
+       return regmap_write(pdata->map, PCF2123_REG_OFFSET, (unsigned int)reg);
 }
 
 static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
+       struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
        u8 rxbuf[7];
        int ret;
 
-       ret = pcf2123_read(dev, PCF2123_REG_SC, rxbuf, sizeof(rxbuf));
-       if (ret < 0)
+       ret = regmap_bulk_read(pdata->map, PCF2123_REG_SC, rxbuf,
+                               sizeof(rxbuf));
+       if (ret)
                return ret;
 
        if (rxbuf[0] & OSC_HAS_STOPPED) {
@@ -279,82 +198,168 @@ static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm)
        if (tm->tm_year < 70)
                tm->tm_year += 100;     /* assume we are in 1970...2069 */
 
-       dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
-                       "mday=%d, mon=%d, year=%d, wday=%d\n",
-                       __func__,
-                       tm->tm_sec, tm->tm_min, tm->tm_hour,
-                       tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+       dev_dbg(dev, "%s: tm is %ptR\n", __func__, tm);
 
        return 0;
 }
 
 static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
-       u8 txbuf[8];
+       struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
+       u8 txbuf[7];
        int ret;
 
-       dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
-                       "mday=%d, mon=%d, year=%d, wday=%d\n",
-                       __func__,
-                       tm->tm_sec, tm->tm_min, tm->tm_hour,
-                       tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+       dev_dbg(dev, "%s: tm is %ptR\n", __func__, tm);
 
        /* Stop the counter first */
-       ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_STOP);
-       if (ret < 0)
+       ret = regmap_write(pdata->map, PCF2123_REG_CTRL1, CTRL1_STOP);
+       if (ret)
                return ret;
 
        /* Set the new time */
-       txbuf[0] = PCF2123_REG_SC;
-       txbuf[1] = bin2bcd(tm->tm_sec & 0x7F);
-       txbuf[2] = bin2bcd(tm->tm_min & 0x7F);
-       txbuf[3] = bin2bcd(tm->tm_hour & 0x3F);
-       txbuf[4] = bin2bcd(tm->tm_mday & 0x3F);
-       txbuf[5] = tm->tm_wday & 0x07;
-       txbuf[6] = bin2bcd((tm->tm_mon + 1) & 0x1F); /* rtc mn 1-12 */
-       txbuf[7] = bin2bcd(tm->tm_year < 100 ? tm->tm_year : tm->tm_year - 100);
-
-       ret = pcf2123_write(dev, txbuf, sizeof(txbuf));
-       if (ret < 0)
+       txbuf[0] = bin2bcd(tm->tm_sec & 0x7F);
+       txbuf[1] = bin2bcd(tm->tm_min & 0x7F);
+       txbuf[2] = bin2bcd(tm->tm_hour & 0x3F);
+       txbuf[3] = bin2bcd(tm->tm_mday & 0x3F);
+       txbuf[4] = tm->tm_wday & 0x07;
+       txbuf[5] = bin2bcd((tm->tm_mon + 1) & 0x1F); /* rtc mn 1-12 */
+       txbuf[6] = bin2bcd(tm->tm_year < 100 ? tm->tm_year : tm->tm_year - 100);
+
+       ret = regmap_bulk_write(pdata->map, PCF2123_REG_SC, txbuf,
+                               sizeof(txbuf));
+       if (ret)
                return ret;
 
        /* Start the counter */
-       ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_CLEAR);
-       if (ret < 0)
+       ret = regmap_write(pdata->map, PCF2123_REG_CTRL1, CTRL1_CLEAR);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int pcf2123_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+       struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
+       u8 rxbuf[4];
+       int ret;
+       unsigned int val = 0;
+
+       ret = regmap_bulk_read(pdata->map, PCF2123_REG_ALRM_MN, rxbuf,
+                               sizeof(rxbuf));
+       if (ret)
+               return ret;
+
+       alm->time.tm_min = bcd2bin(rxbuf[0] & 0x7F);
+       alm->time.tm_hour = bcd2bin(rxbuf[1] & 0x3F);
+       alm->time.tm_mday = bcd2bin(rxbuf[2] & 0x3F);
+       alm->time.tm_wday = bcd2bin(rxbuf[3] & 0x07);
+
+       dev_dbg(dev, "%s: alm is %ptR\n", __func__, &alm->time);
+
+       ret = regmap_read(pdata->map, PCF2123_REG_CTRL2, &val);
+       if (ret)
+               return ret;
+
+       alm->enabled = !!(val & CTRL2_AIE);
+
+       return 0;
+}
+
+static int pcf2123_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+       struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
+       u8 txbuf[4];
+       int ret;
+
+       dev_dbg(dev, "%s: alm is %ptR\n", __func__, &alm->time);
+
+       /* Ensure alarm flag is clear */
+       ret = regmap_update_bits(pdata->map, PCF2123_REG_CTRL2, CTRL2_AF, 0);
+       if (ret)
                return ret;
 
+       /* Disable alarm interrupt */
+       ret = regmap_update_bits(pdata->map, PCF2123_REG_CTRL2, CTRL2_AIE, 0);
+       if (ret)
+               return ret;
+
+       /* Set new alarm */
+       txbuf[0] = bin2bcd(alm->time.tm_min & 0x7F);
+       txbuf[1] = bin2bcd(alm->time.tm_hour & 0x3F);
+       txbuf[2] = bin2bcd(alm->time.tm_mday & 0x3F);
+       txbuf[3] = bin2bcd(alm->time.tm_wday & 0x07);
+
+       ret = regmap_bulk_write(pdata->map, PCF2123_REG_ALRM_MN, txbuf,
+                               sizeof(txbuf));
+       if (ret)
+               return ret;
+
+       /* Enable alarm interrupt */
+       if (alm->enabled)       {
+               ret = regmap_update_bits(pdata->map, PCF2123_REG_CTRL2,
+                                               CTRL2_AIE, CTRL2_AIE);
+               if (ret)
+                       return ret;
+       }
+
        return 0;
 }
 
+static irqreturn_t pcf2123_rtc_irq(int irq, void *dev)
+{
+       struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
+       struct mutex *lock = &pdata->rtc->ops_lock;
+       unsigned int val = 0;
+       int ret = IRQ_NONE;
+
+       mutex_lock(lock);
+       regmap_read(pdata->map, PCF2123_REG_CTRL2, &val);
+
+       /* Alarm? */
+       if (val & CTRL2_AF) {
+               ret = IRQ_HANDLED;
+
+               /* Clear alarm flag */
+               regmap_update_bits(pdata->map, PCF2123_REG_CTRL2, CTRL2_AF, 0);
+
+               rtc_update_irq(pdata->rtc, 1, RTC_IRQF | RTC_AF);
+       }
+
+       mutex_unlock(lock);
+
+       return ret;
+}
+
 static int pcf2123_reset(struct device *dev)
 {
+       struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
        int ret;
-       u8  rxbuf[2];
+       unsigned int val = 0;
 
-       ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_SW_RESET);
-       if (ret < 0)
+       ret = regmap_write(pdata->map, PCF2123_REG_CTRL1, CTRL1_SW_RESET);
+       if (ret)
                return ret;
 
        /* Stop the counter */
        dev_dbg(dev, "stopping RTC\n");
-       ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_STOP);
-       if (ret < 0)
+       ret = regmap_write(pdata->map, PCF2123_REG_CTRL1, CTRL1_STOP);
+       if (ret)
                return ret;
 
        /* See if the counter was actually stopped */
        dev_dbg(dev, "checking for presence of RTC\n");
-       ret = pcf2123_read(dev, PCF2123_REG_CTRL1, rxbuf, sizeof(rxbuf));
-       if (ret < 0)
+       ret = regmap_read(pdata->map, PCF2123_REG_CTRL1, &val);
+       if (ret)
                return ret;
 
-       dev_dbg(dev, "received data from RTC (0x%02X 0x%02X)\n",
-               rxbuf[0], rxbuf[1]);
-       if (!(rxbuf[0] & CTRL1_STOP))
+       dev_dbg(dev, "received data from RTC (0x%08X)\n", val);
+       if (!(val & CTRL1_STOP))
                return -ENODEV;
 
        /* Start the counter */
-       ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_CLEAR);
-       if (ret < 0)
+       ret = regmap_write(pdata->map, PCF2123_REG_CTRL1, CTRL1_CLEAR);
+       if (ret)
                return ret;
 
        return 0;
@@ -365,7 +370,8 @@ static const struct rtc_class_ops pcf2123_rtc_ops = {
        .set_time       = pcf2123_rtc_set_time,
        .read_offset    = pcf2123_read_offset,
        .set_offset     = pcf2123_set_offset,
-
+       .read_alarm     = pcf2123_rtc_read_alarm,
+       .set_alarm      = pcf2123_rtc_set_alarm,
 };
 
 static int pcf2123_probe(struct spi_device *spi)
@@ -373,7 +379,7 @@ static int pcf2123_probe(struct spi_device *spi)
        struct rtc_device *rtc;
        struct rtc_time tm;
        struct pcf2123_plat_data *pdata;
-       int ret, i;
+       int ret = 0;
 
        pdata = devm_kzalloc(&spi->dev, sizeof(struct pcf2123_plat_data),
                                GFP_KERNEL);
@@ -381,6 +387,13 @@ static int pcf2123_probe(struct spi_device *spi)
                return -ENOMEM;
        spi->dev.platform_data = pdata;
 
+       pdata->map = devm_regmap_init_spi(spi, &pcf2123_regmap_config);
+
+       if (IS_ERR(pdata->map)) {
+               dev_err(&spi->dev, "regmap init failed.\n");
+               goto kfree_exit;
+       }
+
        ret = pcf2123_rtc_read_time(&spi->dev, &tm);
        if (ret < 0) {
                ret = pcf2123_reset(&spi->dev);
@@ -405,47 +418,31 @@ static int pcf2123_probe(struct spi_device *spi)
 
        pdata->rtc = rtc;
 
-       for (i = 0; i < 16; i++) {
-               sysfs_attr_init(&pdata->regs[i].attr.attr);
-               sprintf(pdata->regs[i].name, "%1x", i);
-               pdata->regs[i].attr.attr.mode = S_IRUGO | S_IWUSR;
-               pdata->regs[i].attr.attr.name = pdata->regs[i].name;
-               pdata->regs[i].attr.show = pcf2123_show;
-               pdata->regs[i].attr.store = pcf2123_store;
-               ret = device_create_file(&spi->dev, &pdata->regs[i].attr);
-               if (ret) {
-                       dev_err(&spi->dev, "Unable to create sysfs %s\n",
-                               pdata->regs[i].name);
-                       goto sysfs_exit;
-               }
+       /* Register alarm irq */
+       if (spi->irq > 0) {
+               ret = devm_request_threaded_irq(&spi->dev, spi->irq, NULL,
+                               pcf2123_rtc_irq,
+                               IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                               pcf2123_driver.driver.name, &spi->dev);
+               if (!ret)
+                       device_init_wakeup(&spi->dev, true);
+               else
+                       dev_err(&spi->dev, "could not request irq.\n");
        }
 
-       return 0;
+       /* The PCF2123's alarm only has minute accuracy. Must add timer
+        * support to this driver to generate interrupts more than once
+        * per minute.
+        */
+       pdata->rtc->uie_unsupported = 1;
 
-sysfs_exit:
-       for (i--; i >= 0; i--)
-               device_remove_file(&spi->dev, &pdata->regs[i].attr);
+       return 0;
 
 kfree_exit:
        spi->dev.platform_data = NULL;
        return ret;
 }
 
-static int pcf2123_remove(struct spi_device *spi)
-{
-       struct pcf2123_plat_data *pdata = dev_get_platdata(&spi->dev);
-       int i;
-
-       if (pdata) {
-               for (i = 0; i < 16; i++)
-                       if (pdata->regs[i].name[0])
-                               device_remove_file(&spi->dev,
-                                                  &pdata->regs[i].attr);
-       }
-
-       return 0;
-}
-
 #ifdef CONFIG_OF
 static const struct of_device_id pcf2123_dt_ids[] = {
        { .compatible = "nxp,rtc-pcf2123", },
@@ -461,7 +458,6 @@ static struct spi_driver pcf2123_driver = {
                        .of_match_table = of_match_ptr(pcf2123_dt_ids),
        },
        .probe  = pcf2123_probe,
-       .remove = pcf2123_remove,
 };
 
 module_spi_driver(pcf2123_driver);
index c569dfe..ac159d2 100644 (file)
@@ -560,7 +560,6 @@ static int pcf8563_probe(struct i2c_client *client,
        struct pcf8563 *pcf8563;
        int err;
        unsigned char buf;
-       unsigned char alm_pending;
 
        dev_dbg(&client->dev, "%s\n", __func__);
 
@@ -584,13 +583,13 @@ static int pcf8563_probe(struct i2c_client *client,
                return err;
        }
 
-       err = pcf8563_get_alarm_mode(client, NULL, &alm_pending);
-       if (err) {
-               dev_err(&client->dev, "%s: read error\n", __func__);
+       /* Clear flags and disable interrupts */
+       buf = 0;
+       err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, &buf);
+       if (err < 0) {
+               dev_err(&client->dev, "%s: write error\n", __func__);
                return err;
        }
-       if (alm_pending)
-               pcf8563_set_alarm_mode(client, 0);
 
        pcf8563->rtc = devm_rtc_device_register(&client->dev,
                                pcf8563_driver.driver.name,
@@ -602,7 +601,7 @@ static int pcf8563_probe(struct i2c_client *client,
        if (client->irq > 0) {
                err = devm_request_threaded_irq(&client->dev, client->irq,
                                NULL, pcf8563_irq,
-                               IRQF_SHARED|IRQF_ONESHOT|IRQF_TRIGGER_FALLING,
+                               IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_LOW,
                                pcf8563_driver.driver.name, client);
                if (err) {
                        dev_err(&client->dev, "unable to request IRQ %d\n",
index 0b102c3..fc52434 100644 (file)
@@ -517,7 +517,7 @@ static int rx8900_trickle_charger_init(struct rv8803_data *rv8803)
 static int rv8803_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
-       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+       struct i2c_adapter *adapter = client->adapter;
        struct rv8803_data *rv8803;
        int err, flags;
        struct nvmem_config nvmem_cfg = {
index b15ad8e..8102469 100644 (file)
@@ -433,7 +433,7 @@ static struct rtc_class_ops rx8010_rtc_ops = {
 static int rx8010_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
-       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+       struct i2c_adapter *adapter = client->adapter;
        struct rx8010_data *rx8010;
        int err = 0;
 
index cb082ad..b9bda10 100644 (file)
@@ -501,7 +501,7 @@ static void rx8025_sysfs_unregister(struct device *dev)
 static int rx8025_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
-       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+       struct i2c_adapter *adapter = client->adapter;
        struct rx8025_data *rx8025;
        int err = 0;
 
index 8c37acb..84806ff 100644 (file)
 #define S35390A_ALRM_BYTE_MINS 2
 
 /* flags for STATUS1 */
-#define S35390A_FLAG_POC       0x01
-#define S35390A_FLAG_BLD       0x02
-#define S35390A_FLAG_INT2      0x04
-#define S35390A_FLAG_24H       0x40
-#define S35390A_FLAG_RESET     0x80
+#define S35390A_FLAG_POC       BIT(0)
+#define S35390A_FLAG_BLD       BIT(1)
+#define S35390A_FLAG_INT2      BIT(2)
+#define S35390A_FLAG_24H       BIT(6)
+#define S35390A_FLAG_RESET     BIT(7)
 
 /* flag for STATUS2 */
-#define S35390A_FLAG_TEST      0x01
-
-#define S35390A_INT2_MODE_MASK         0xF0
+#define S35390A_FLAG_TEST      BIT(0)
 
+/* INT2 pin output mode */
+#define S35390A_INT2_MODE_MASK         0x0E
 #define S35390A_INT2_MODE_NOINTR       0x00
-#define S35390A_INT2_MODE_FREQ         0x10
-#define S35390A_INT2_MODE_ALARM                0x40
-#define S35390A_INT2_MODE_PMIN_EDG     0x20
+#define S35390A_INT2_MODE_ALARM                BIT(1) /* INT2AE */
+#define S35390A_INT2_MODE_PMIN_EDG     BIT(2) /* INT2ME */
+#define S35390A_INT2_MODE_FREQ         BIT(3) /* INT2FE */
+#define S35390A_INT2_MODE_PMIN         (BIT(3) | BIT(2)) /* INT2FE | INT2ME */
 
 static const struct i2c_device_id s35390a_id[] = {
        { "s35390a", 0 },
@@ -284,6 +285,9 @@ static int s35390a_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
                alm->time.tm_min, alm->time.tm_hour, alm->time.tm_mday,
                alm->time.tm_mon, alm->time.tm_year, alm->time.tm_wday);
 
+       if (alm->time.tm_sec != 0)
+               dev_warn(&client->dev, "Alarms are only supported on a per minute basis!\n");
+
        /* disable interrupt (which deasserts the irq line) */
        err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
        if (err < 0)
@@ -299,9 +303,6 @@ static int s35390a_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
        else
                sts = S35390A_INT2_MODE_NOINTR;
 
-       /* This chip expects the bits of each byte to be in reverse order */
-       sts = bitrev8(sts);
-
        /* set interupt mode*/
        err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
        if (err < 0)
@@ -339,7 +340,7 @@ static int s35390a_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
        if (err < 0)
                return err;
 
-       if ((bitrev8(sts) & S35390A_INT2_MODE_MASK) != S35390A_INT2_MODE_ALARM) {
+       if ((sts & S35390A_INT2_MODE_MASK) != S35390A_INT2_MODE_ALARM) {
                /*
                 * When the alarm isn't enabled, the register to configure
                 * the alarm time isn't accessible.
@@ -431,14 +432,14 @@ static int s35390a_probe(struct i2c_client *client,
        unsigned int i;
        struct s35390a *s35390a;
        char buf, status1;
+       struct device *dev = &client->dev;
 
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
                err = -ENODEV;
                goto exit;
        }
 
-       s35390a = devm_kzalloc(&client->dev, sizeof(struct s35390a),
-                               GFP_KERNEL);
+       s35390a = devm_kzalloc(dev, sizeof(struct s35390a), GFP_KERNEL);
        if (!s35390a) {
                err = -ENOMEM;
                goto exit;
@@ -452,8 +453,8 @@ static int s35390a_probe(struct i2c_client *client,
                s35390a->client[i] = i2c_new_dummy(client->adapter,
                                        client->addr + i);
                if (!s35390a->client[i]) {
-                       dev_err(&client->dev, "Address %02x unavailable\n",
-                                               client->addr + i);
+                       dev_err(dev, "Address %02x unavailable\n",
+                               client->addr + i);
                        err = -EBUSY;
                        goto exit_dummy;
                }
@@ -462,7 +463,7 @@ static int s35390a_probe(struct i2c_client *client,
        err_read = s35390a_read_status(s35390a, &status1);
        if (err_read < 0) {
                err = err_read;
-               dev_err(&client->dev, "error resetting chip\n");
+               dev_err(dev, "error resetting chip\n");
                goto exit_dummy;
        }
 
@@ -476,28 +477,30 @@ static int s35390a_probe(struct i2c_client *client,
                buf = 0;
                err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &buf, 1);
                if (err < 0) {
-                       dev_err(&client->dev, "error disabling alarm");
+                       dev_err(dev, "error disabling alarm");
                        goto exit_dummy;
                }
        } else {
                err = s35390a_disable_test_mode(s35390a);
                if (err < 0) {
-                       dev_err(&client->dev, "error disabling test mode\n");
+                       dev_err(dev, "error disabling test mode\n");
                        goto exit_dummy;
                }
        }
 
-       device_set_wakeup_capable(&client->dev, 1);
+       device_set_wakeup_capable(dev, 1);
 
-       s35390a->rtc = devm_rtc_device_register(&client->dev,
-                                       s35390a_driver.driver.name,
-                                       &s35390a_rtc_ops, THIS_MODULE);
+       s35390a->rtc = devm_rtc_device_register(dev, s35390a_driver.driver.name,
+                                               &s35390a_rtc_ops, THIS_MODULE);
 
        if (IS_ERR(s35390a->rtc)) {
                err = PTR_ERR(s35390a->rtc);
                goto exit_dummy;
        }
 
+       /* supports per-minute alarms only, therefore set uie_unsupported */
+       s35390a->rtc->uie_unsupported = 1;
+
        if (status1 & S35390A_FLAG_INT2)
                rtc_update_irq(s35390a->rtc, 1, RTC_AF);
 
index 5fe0218..49474a3 100644 (file)
@@ -162,10 +162,6 @@ static int st_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t)
        now_secs = rtc_tm_to_time64(&now);
        alarm_secs = rtc_tm_to_time64(&t->time);
 
-       /* Invalid alarm time */
-       if (now_secs > alarm_secs)
-               return -EINVAL;
-
        memcpy(&rtc->alarm, t, sizeof(struct rtc_wkalrm));
 
        /* Now many secs to fire */
index 8e6c9b3..773a199 100644 (file)
@@ -519,11 +519,7 @@ static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
        /* Write to Alarm register */
        writel_relaxed(alrmar, rtc->base + regs->alrmar);
 
-       if (alrm->enabled)
-               stm32_rtc_alarm_irq_enable(dev, 1);
-       else
-               stm32_rtc_alarm_irq_enable(dev, 0);
-
+       stm32_rtc_alarm_irq_enable(dev, alrm->enabled);
 end:
        stm32_rtc_wpr_lock(rtc);
 
index 8128ec2..c0e75c3 100644 (file)
@@ -672,6 +672,7 @@ static const struct of_device_id sun6i_rtc_dt_ids[] = {
        { .compatible = "allwinner,sun6i-a31-rtc" },
        { .compatible = "allwinner,sun8i-a23-rtc" },
        { .compatible = "allwinner,sun8i-h3-rtc" },
+       { .compatible = "allwinner,sun8i-r40-rtc" },
        { .compatible = "allwinner,sun8i-v3-rtc" },
        { .compatible = "allwinner,sun50i-h5-rtc" },
        { /* sentinel */ },
index f0ce768..8fa1b3f 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * An RTC driver for the NVIDIA Tegra 200 series internal RTC.
  *
- * Copyright (c) 2010, NVIDIA Corporation.
+ * Copyright (c) 2010-2019, NVIDIA Corporation.
  */
 
 #include <linux/clk.h>
 #include <linux/rtc.h>
 #include <linux/slab.h>
 
-/* set to 1 = busy every eight 32kHz clocks during copy of sec+msec to AHB */
+/* Set to 1 = busy every eight 32 kHz clocks during copy of sec+msec to AHB. */
 #define TEGRA_RTC_REG_BUSY                     0x004
 #define TEGRA_RTC_REG_SECONDS                  0x008
-/* when msec is read, the seconds are buffered into shadow seconds. */
+/* When msec is read, the seconds are buffered into shadow seconds. */
 #define TEGRA_RTC_REG_SHADOW_SECONDS           0x00c
 #define TEGRA_RTC_REG_MILLI_SECONDS            0x010
 #define TEGRA_RTC_REG_SECONDS_ALARM0           0x014
 #define TEGRA_RTC_INTR_STATUS_SEC_ALARM0       (1<<0)
 
 struct tegra_rtc_info {
-       struct platform_device  *pdev;
-       struct rtc_device       *rtc_dev;
-       void __iomem            *rtc_base; /* NULL if not initialized. */
-       struct clk              *clk;
-       int                     tegra_rtc_irq; /* alarm and periodic irq */
-       spinlock_t              tegra_rtc_lock;
+       struct platform_device *pdev;
+       struct rtc_device *rtc;
+       void __iomem *base; /* NULL if not initialized */
+       struct clk *clk;
+       int irq; /* alarm and periodic IRQ */
+       spinlock_t lock;
 };
 
-/* RTC hardware is busy when it is updating its values over AHB once
- * every eight 32kHz clocks (~250uS).
- * outside of these updates the CPU is free to write.
- * CPU is always free to read.
+/*
+ * RTC hardware is busy when it is updating its values over AHB once every
+ * eight 32 kHz clocks (~250 us). Outside of these updates the CPU is free to
+ * write. CPU is always free to read.
  */
 static inline u32 tegra_rtc_check_busy(struct tegra_rtc_info *info)
 {
-       return readl(info->rtc_base + TEGRA_RTC_REG_BUSY) & 1;
+       return readl(info->base + TEGRA_RTC_REG_BUSY) & 1;
 }
 
-/* Wait for hardware to be ready for writing.
- * This function tries to maximize the amount of time before the next update.
- * It does this by waiting for the RTC to become busy with its periodic update,
- * then returning once the RTC first becomes not busy.
+/*
+ * Wait for hardware to be ready for writing. This function tries to maximize
+ * the amount of time before the next update. It does this by waiting for the
+ * RTC to become busy with its periodic update, then returning once the RTC
+ * first becomes not busy.
+ *
  * This periodic update (where the seconds and milliseconds are copied to the
- * AHB side) occurs every eight 32kHz clocks (~250uS).
- * The behavior of this function allows us to make some assumptions without
- * introducing a race, because 250uS is plenty of time to read/write a value.
+ * AHB side) occurs every eight 32 kHz clocks (~250 us). The behavior of this
+ * function allows us to make some assumptions without introducing a race,
+ * because 250 us is plenty of time to read/write a value.
  */
 static int tegra_rtc_wait_while_busy(struct device *dev)
 {
        struct tegra_rtc_info *info = dev_get_drvdata(dev);
+       int retries = 500; /* ~490 us is the worst case, ~250 us is best */
 
-       int retries = 500; /* ~490 us is the worst case, ~250 us is best. */
-
-       /* first wait for the RTC to become busy. this is when it
-        * posts its updated seconds+msec registers to AHB side. */
+       /*
+        * First wait for the RTC to become busy. This is when it posts its
+        * updated seconds+msec registers to AHB side.
+        */
        while (tegra_rtc_check_busy(info)) {
                if (!retries--)
                        goto retry_failed;
+
                udelay(1);
        }
 
@@ -91,28 +95,30 @@ static int tegra_rtc_wait_while_busy(struct device *dev)
        return 0;
 
 retry_failed:
-       dev_err(dev, "write failed:retry count exceeded.\n");
+       dev_err(dev, "write failed: retry count exceeded\n");
        return -ETIMEDOUT;
 }
 
 static int tegra_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
        struct tegra_rtc_info *info = dev_get_drvdata(dev);
-       unsigned long sec, msec;
-       unsigned long sl_irq_flags;
+       unsigned long flags;
+       u32 sec, msec;
 
-       /* RTC hardware copies seconds to shadow seconds when a read
-        * of milliseconds occurs. use a lock to keep other threads out. */
-       spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags);
+       /*
+        * RTC hardware copies seconds to shadow seconds when a read of
+        * milliseconds occurs. use a lock to keep other threads out.
+        */
+       spin_lock_irqsave(&info->lock, flags);
 
-       msec = readl(info->rtc_base + TEGRA_RTC_REG_MILLI_SECONDS);
-       sec = readl(info->rtc_base + TEGRA_RTC_REG_SHADOW_SECONDS);
+       msec = readl(info->base + TEGRA_RTC_REG_MILLI_SECONDS);
+       sec = readl(info->base + TEGRA_RTC_REG_SHADOW_SECONDS);
 
-       spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags);
+       spin_unlock_irqrestore(&info->lock, flags);
 
        rtc_time64_to_tm(sec, tm);
 
-       dev_vdbg(dev, "time read as %lu. %ptR\n", sec, tm);
+       dev_vdbg(dev, "time read as %u, %ptR\n", sec, tm);
 
        return 0;
 }
@@ -120,21 +126,21 @@ static int tegra_rtc_read_time(struct device *dev, struct rtc_time *tm)
 static int tegra_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
        struct tegra_rtc_info *info = dev_get_drvdata(dev);
-       unsigned long sec;
+       u32 sec;
        int ret;
 
-       /* convert tm to seconds. */
+       /* convert tm to seconds */
        sec = rtc_tm_to_time64(tm);
 
-       dev_vdbg(dev, "time set to %lu. %ptR\n", sec, tm);
+       dev_vdbg(dev, "time set to %u, %ptR\n", sec, tm);
 
-       /* seconds only written if wait succeeded. */
+       /* seconds only written if wait succeeded */
        ret = tegra_rtc_wait_while_busy(dev);
        if (!ret)
-               writel(sec, info->rtc_base + TEGRA_RTC_REG_SECONDS);
+               writel(sec, info->base + TEGRA_RTC_REG_SECONDS);
 
        dev_vdbg(dev, "time read back as %d\n",
-               readl(info->rtc_base + TEGRA_RTC_REG_SECONDS));
+                readl(info->base + TEGRA_RTC_REG_SECONDS));
 
        return ret;
 }
@@ -142,22 +148,21 @@ static int tegra_rtc_set_time(struct device *dev, struct rtc_time *tm)
 static int tegra_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 {
        struct tegra_rtc_info *info = dev_get_drvdata(dev);
-       unsigned long sec;
-       unsigned tmp;
+       u32 sec, value;
 
-       sec = readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0);
+       sec = readl(info->base + TEGRA_RTC_REG_SECONDS_ALARM0);
 
        if (sec == 0) {
-               /* alarm is disabled. */
+               /* alarm is disabled */
                alarm->enabled = 0;
        } else {
-               /* alarm is enabled. */
+               /* alarm is enabled */
                alarm->enabled = 1;
                rtc_time64_to_tm(sec, &alarm->time);
        }
 
-       tmp = readl(info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
-       alarm->pending = (tmp & TEGRA_RTC_INTR_STATUS_SEC_ALARM0) != 0;
+       value = readl(info->base + TEGRA_RTC_REG_INTR_STATUS);
+       alarm->pending = (value & TEGRA_RTC_INTR_STATUS_SEC_ALARM0) != 0;
 
        return 0;
 }
@@ -165,22 +170,22 @@ static int tegra_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 static int tegra_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct tegra_rtc_info *info = dev_get_drvdata(dev);
-       unsigned status;
-       unsigned long sl_irq_flags;
+       unsigned long flags;
+       u32 status;
 
        tegra_rtc_wait_while_busy(dev);
-       spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags);
+       spin_lock_irqsave(&info->lock, flags);
 
-       /* read the original value, and OR in the flag. */
-       status = readl(info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
+       /* read the original value, and OR in the flag */
+       status = readl(info->base + TEGRA_RTC_REG_INTR_MASK);
        if (enabled)
                status |= TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* set it */
        else
                status &= ~TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* clear it */
 
-       writel(status, info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
+       writel(status, info->base + TEGRA_RTC_REG_INTR_MASK);
 
-       spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags);
+       spin_unlock_irqrestore(&info->lock, flags);
 
        return 0;
 }
@@ -188,7 +193,7 @@ static int tegra_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 static int tegra_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 {
        struct tegra_rtc_info *info = dev_get_drvdata(dev);
-       unsigned long sec;
+       u32 sec;
 
        if (alarm->enabled)
                sec = rtc_tm_to_time64(&alarm->time);
@@ -196,16 +201,16 @@ static int tegra_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
                sec = 0;
 
        tegra_rtc_wait_while_busy(dev);
-       writel(sec, info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0);
+       writel(sec, info->base + TEGRA_RTC_REG_SECONDS_ALARM0);
        dev_vdbg(dev, "alarm read back as %d\n",
-               readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0));
+                readl(info->base + TEGRA_RTC_REG_SECONDS_ALARM0));
 
        /* if successfully written and alarm is enabled ... */
        if (sec) {
                tegra_rtc_alarm_irq_enable(dev, 1);
-               dev_vdbg(dev, "alarm set as %lu. %ptR\n", sec, &alarm->time);
+               dev_vdbg(dev, "alarm set as %u, %ptR\n", sec, &alarm->time);
        } else {
-               /* disable alarm if 0 or write error. */
+               /* disable alarm if 0 or write error */
                dev_vdbg(dev, "alarm disabled\n");
                tegra_rtc_alarm_irq_enable(dev, 0);
        }
@@ -227,39 +232,39 @@ static irqreturn_t tegra_rtc_irq_handler(int irq, void *data)
 {
        struct device *dev = data;
        struct tegra_rtc_info *info = dev_get_drvdata(dev);
-       unsigned long events = 0;
-       unsigned status;
-       unsigned long sl_irq_flags;
+       unsigned long events = 0, flags;
+       u32 status;
 
-       status = readl(info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
+       status = readl(info->base + TEGRA_RTC_REG_INTR_STATUS);
        if (status) {
-               /* clear the interrupt masks and status on any irq. */
+               /* clear the interrupt masks and status on any IRQ */
                tegra_rtc_wait_while_busy(dev);
-               spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags);
-               writel(0, info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
-               writel(status, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
-               spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags);
+
+               spin_lock_irqsave(&info->lock, flags);
+               writel(0, info->base + TEGRA_RTC_REG_INTR_MASK);
+               writel(status, info->base + TEGRA_RTC_REG_INTR_STATUS);
+               spin_unlock_irqrestore(&info->lock, flags);
        }
 
-       /* check if Alarm */
-       if ((status & TEGRA_RTC_INTR_STATUS_SEC_ALARM0))
+       /* check if alarm */
+       if (status & TEGRA_RTC_INTR_STATUS_SEC_ALARM0)
                events |= RTC_IRQF | RTC_AF;
 
-       /* check if Periodic */
-       if ((status & TEGRA_RTC_INTR_STATUS_SEC_CDN_ALARM))
+       /* check if periodic */
+       if (status & TEGRA_RTC_INTR_STATUS_SEC_CDN_ALARM)
                events |= RTC_IRQF | RTC_PF;
 
-       rtc_update_irq(info->rtc_dev, 1, events);
+       rtc_update_irq(info->rtc, 1, events);
 
        return IRQ_HANDLED;
 }
 
 static const struct rtc_class_ops tegra_rtc_ops = {
-       .read_time      = tegra_rtc_read_time,
-       .set_time       = tegra_rtc_set_time,
-       .read_alarm     = tegra_rtc_read_alarm,
-       .set_alarm      = tegra_rtc_set_alarm,
-       .proc           = tegra_rtc_proc,
+       .read_time = tegra_rtc_read_time,
+       .set_time = tegra_rtc_set_time,
+       .read_alarm = tegra_rtc_read_alarm,
+       .set_alarm = tegra_rtc_set_alarm,
+       .proc = tegra_rtc_proc,
        .alarm_irq_enable = tegra_rtc_alarm_irq_enable,
 };
 
@@ -269,21 +274,20 @@ static const struct of_device_id tegra_rtc_dt_match[] = {
 };
 MODULE_DEVICE_TABLE(of, tegra_rtc_dt_match);
 
-static int __init tegra_rtc_probe(struct platform_device *pdev)
+static int tegra_rtc_probe(struct platform_device *pdev)
 {
        struct tegra_rtc_info *info;
        struct resource *res;
        int ret;
 
-       info = devm_kzalloc(&pdev->dev, sizeof(struct tegra_rtc_info),
-               GFP_KERNEL);
+       info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       info->rtc_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(info->rtc_base))
-               return PTR_ERR(info->rtc_base);
+       info->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(info->base))
+               return PTR_ERR(info->base);
 
        ret = platform_get_irq(pdev, 0);
        if (ret <= 0) {
@@ -291,14 +295,14 @@ static int __init tegra_rtc_probe(struct platform_device *pdev)
                return ret;
        }
 
-       info->tegra_rtc_irq = ret;
+       info->irq = ret;
 
-       info->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
-       if (IS_ERR(info->rtc_dev))
-               return PTR_ERR(info->rtc_dev);
+       info->rtc = devm_rtc_allocate_device(&pdev->dev);
+       if (IS_ERR(info->rtc))
+               return PTR_ERR(info->rtc);
 
-       info->rtc_dev->ops = &tegra_rtc_ops;
-       info->rtc_dev->range_max = U32_MAX;
+       info->rtc->ops = &tegra_rtc_ops;
+       info->rtc->range_max = U32_MAX;
 
        info->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(info->clk))
@@ -308,33 +312,30 @@ static int __init tegra_rtc_probe(struct platform_device *pdev)
        if (ret < 0)
                return ret;
 
-       /* set context info. */
+       /* set context info */
        info->pdev = pdev;
-       spin_lock_init(&info->tegra_rtc_lock);
+       spin_lock_init(&info->lock);
 
        platform_set_drvdata(pdev, info);
 
-       /* clear out the hardware. */
-       writel(0, info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0);
-       writel(0xffffffff, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
-       writel(0, info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
+       /* clear out the hardware */
+       writel(0, info->base + TEGRA_RTC_REG_SECONDS_ALARM0);
+       writel(0xffffffff, info->base + TEGRA_RTC_REG_INTR_STATUS);
+       writel(0, info->base + TEGRA_RTC_REG_INTR_MASK);
 
        device_init_wakeup(&pdev->dev, 1);
 
-       ret = devm_request_irq(&pdev->dev, info->tegra_rtc_irq,
-                       tegra_rtc_irq_handler, IRQF_TRIGGER_HIGH,
-                       dev_name(&pdev->dev), &pdev->dev);
+       ret = devm_request_irq(&pdev->dev, info->irq, tegra_rtc_irq_handler,
+                              IRQF_TRIGGER_HIGH, dev_name(&pdev->dev),
+                              &pdev->dev);
        if (ret) {
-               dev_err(&pdev->dev,
-                       "Unable to request interrupt for device (err=%d).\n",
-                       ret);
+               dev_err(&pdev->dev, "failed to request interrupt: %d\n", ret);
                goto disable_clk;
        }
 
-       ret = rtc_register_device(info->rtc_dev);
+       ret = rtc_register_device(info->rtc);
        if (ret) {
-               dev_err(&pdev->dev, "Unable to register device (err=%d).\n",
-                       ret);
+               dev_err(&pdev->dev, "failed to register device: %d\n", ret);
                goto disable_clk;
        }
 
@@ -363,20 +364,20 @@ static int tegra_rtc_suspend(struct device *dev)
 
        tegra_rtc_wait_while_busy(dev);
 
-       /* only use ALARM0 as a wake source. */
-       writel(0xffffffff, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
+       /* only use ALARM0 as a wake source */
+       writel(0xffffffff, info->base + TEGRA_RTC_REG_INTR_STATUS);
        writel(TEGRA_RTC_INTR_STATUS_SEC_ALARM0,
-               info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
+              info->base + TEGRA_RTC_REG_INTR_MASK);
 
        dev_vdbg(dev, "alarm sec = %d\n",
-               readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0));
+                readl(info->base + TEGRA_RTC_REG_SECONDS_ALARM0));
 
-       dev_vdbg(dev, "Suspend (device_may_wakeup=%d) irq:%d\n",
-               device_may_wakeup(dev), info->tegra_rtc_irq);
+       dev_vdbg(dev, "Suspend (device_may_wakeup=%d) IRQ:%d\n",
+                device_may_wakeup(dev), info->irq);
 
-       /* leave the alarms on as a wake source. */
+       /* leave the alarms on as a wake source */
        if (device_may_wakeup(dev))
-               enable_irq_wake(info->tegra_rtc_irq);
+               enable_irq_wake(info->irq);
 
        return 0;
 }
@@ -386,10 +387,11 @@ static int tegra_rtc_resume(struct device *dev)
        struct tegra_rtc_info *info = dev_get_drvdata(dev);
 
        dev_vdbg(dev, "Resume (device_may_wakeup=%d)\n",
-               device_may_wakeup(dev));
-       /* alarms were left on as a wake source, turn them off. */
+                device_may_wakeup(dev));
+
+       /* alarms were left on as a wake source, turn them off */
        if (device_may_wakeup(dev))
-               disable_irq_wake(info->tegra_rtc_irq);
+               disable_irq_wake(info->irq);
 
        return 0;
 }
@@ -399,22 +401,21 @@ static SIMPLE_DEV_PM_OPS(tegra_rtc_pm_ops, tegra_rtc_suspend, tegra_rtc_resume);
 
 static void tegra_rtc_shutdown(struct platform_device *pdev)
 {
-       dev_vdbg(&pdev->dev, "disabling interrupts.\n");
+       dev_vdbg(&pdev->dev, "disabling interrupts\n");
        tegra_rtc_alarm_irq_enable(&pdev->dev, 0);
 }
 
-MODULE_ALIAS("platform:tegra_rtc");
 static struct platform_driver tegra_rtc_driver = {
-       .remove         = tegra_rtc_remove,
-       .shutdown       = tegra_rtc_shutdown,
-       .driver         = {
-               .name   = "tegra_rtc",
+       .probe = tegra_rtc_probe,
+       .remove = tegra_rtc_remove,
+       .shutdown = tegra_rtc_shutdown,
+       .driver = {
+               .name = "tegra_rtc",
                .of_match_table = tegra_rtc_dt_match,
-               .pm     = &tegra_rtc_pm_ops,
+               .pm = &tegra_rtc_pm_ops,
        },
 };
-
-module_platform_driver_probe(tegra_rtc_driver, tegra_rtc_probe);
+module_platform_driver(tegra_rtc_driver);
 
 MODULE_AUTHOR("Jon Mayo <jmayo@nvidia.com>");
 MODULE_DESCRIPTION("driver for Tegra internal RTC");
index b298e99..74b3a06 100644 (file)
@@ -133,6 +133,7 @@ static int test_probe(struct platform_device *plat_dev)
                break;
        default:
                rtd->rtc->ops = &test_rtc_ops;
+               device_init_wakeup(&plat_dev->dev, 1);
        }
 
        timer_setup(&rtd->alarm, test_rtc_alarm_handler, 0);
index 8556d92..7078f6d 100644 (file)
@@ -143,7 +143,7 @@ static int tps65910_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
        struct tps65910 *tps = dev_get_drvdata(dev->parent);
        int ret;
 
-       ret = regmap_bulk_read(tps->regmap, TPS65910_SECONDS, alarm_data,
+       ret = regmap_bulk_read(tps->regmap, TPS65910_ALARM_SECONDS, alarm_data,
                NUM_TIME_REGS);
        if (ret < 0) {
                dev_err(dev, "rtc_read_alarm error %d\n", ret);
index d2e8b21..ccef887 100644 (file)
@@ -435,7 +435,8 @@ static int wm831x_rtc_probe(struct platform_device *pdev)
 
        ret = devm_request_threaded_irq(&pdev->dev, alm_irq, NULL,
                                wm831x_alm_irq,
-                               IRQF_TRIGGER_RISING, "RTC alarm",
+                               IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                               "RTC alarm",
                                wm831x_rtc);
        if (ret != 0) {
                dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n",
index d04d437..63502ca 100644 (file)
@@ -679,7 +679,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
                goto put_dev;
 
        dev_info->dax_dev = alloc_dax(dev_info, dev_info->gd->disk_name,
-                       &dcssblk_dax_ops);
+                       &dcssblk_dax_ops, DAXDEV_F_SYNC);
        if (!dev_info->dax_dev) {
                rc = -ENOMEM;
                goto put_dev;
index e8fc28d..96f0d34 100644 (file)
@@ -11,6 +11,7 @@
 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 
 #include <linux/kthread.h>
+#include <linux/bug.h>
 #include "zfcp_ext.h"
 #include "zfcp_reqlist.h"
 
@@ -217,6 +218,12 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(enum zfcp_erp_act_type need,
        struct zfcp_erp_action *erp_action;
        struct zfcp_scsi_dev *zfcp_sdev;
 
+       if (WARN_ON_ONCE(need != ZFCP_ERP_ACTION_REOPEN_LUN &&
+                        need != ZFCP_ERP_ACTION_REOPEN_PORT &&
+                        need != ZFCP_ERP_ACTION_REOPEN_PORT_FORCED &&
+                        need != ZFCP_ERP_ACTION_REOPEN_ADAPTER))
+               return NULL;
+
        switch (need) {
        case ZFCP_ERP_ACTION_REOPEN_LUN:
                zfcp_sdev = sdev_to_zfcp(sdev);
index d94496e..296bbc3 100644 (file)
@@ -11,6 +11,7 @@
 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 
 #include <linux/blktrace_api.h>
+#include <linux/types.h>
 #include <linux/slab.h>
 #include <scsi/fc/fc_els.h>
 #include "zfcp_ext.h"
@@ -741,6 +742,7 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio,
 
 static int zfcp_fsf_req_send(struct zfcp_fsf_req *req)
 {
+       const bool is_srb = zfcp_fsf_req_is_status_read_buffer(req);
        struct zfcp_adapter *adapter = req->adapter;
        struct zfcp_qdio *qdio = adapter->qdio;
        int req_id = req->req_id;
@@ -757,8 +759,20 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *req)
                return -EIO;
        }
 
+       /*
+        * NOTE: DO NOT TOUCH ASYNC req PAST THIS POINT.
+        *       ONLY TOUCH SYNC req AGAIN ON req->completion.
+        *
+        * The request might complete and be freed concurrently at any point
+        * now. This is not protected by the QDIO-lock (req_q_lock). So any
+        * uncontrolled access after this might result in an use-after-free bug.
+        * Only if the request doesn't have ZFCP_STATUS_FSFREQ_CLEANUP set, and
+        * when it is completed via req->completion, is it safe to use req
+        * again.
+        */
+
        /* Don't increase for unsolicited status */
-       if (!zfcp_fsf_req_is_status_read_buffer(req))
+       if (!is_srb)
                adapter->fsf_req_seq_no++;
        adapter->req_no++;
 
@@ -805,6 +819,7 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio)
        retval = zfcp_fsf_req_send(req);
        if (retval)
                goto failed_req_send;
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 
        goto out;
 
@@ -914,8 +929,10 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_cmnd(struct scsi_cmnd *scmnd)
        req->qtcb->bottom.support.req_handle = (u64) old_req_id;
 
        zfcp_fsf_start_timer(req, ZFCP_FSF_SCSI_ER_TIMEOUT);
-       if (!zfcp_fsf_req_send(req))
+       if (!zfcp_fsf_req_send(req)) {
+               /* NOTE: DO NOT TOUCH req, UNTIL IT COMPLETES! */
                goto out;
+       }
 
 out_error_free:
        zfcp_fsf_req_free(req);
@@ -1098,6 +1115,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,
        ret = zfcp_fsf_req_send(req);
        if (ret)
                goto failed_send;
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 
        goto out;
 
@@ -1198,6 +1216,7 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id,
        ret = zfcp_fsf_req_send(req);
        if (ret)
                goto failed_send;
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 
        goto out;
 
@@ -1243,6 +1262,7 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
                zfcp_fsf_req_free(req);
                erp_action->fsf_req_id = 0;
        }
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 out:
        spin_unlock_irq(&qdio->req_q_lock);
        return retval;
@@ -1279,8 +1299,10 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio,
        zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
        retval = zfcp_fsf_req_send(req);
        spin_unlock_irq(&qdio->req_q_lock);
-       if (!retval)
+       if (!retval) {
+               /* NOTE: ONLY TOUCH SYNC req AGAIN ON req->completion. */
                wait_for_completion(&req->completion);
+       }
 
        zfcp_fsf_req_free(req);
        return retval;
@@ -1330,6 +1352,7 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
                zfcp_fsf_req_free(req);
                erp_action->fsf_req_id = 0;
        }
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 out:
        spin_unlock_irq(&qdio->req_q_lock);
        return retval;
@@ -1372,8 +1395,10 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio,
        retval = zfcp_fsf_req_send(req);
        spin_unlock_irq(&qdio->req_q_lock);
 
-       if (!retval)
+       if (!retval) {
+               /* NOTE: ONLY TOUCH SYNC req AGAIN ON req->completion. */
                wait_for_completion(&req->completion);
+       }
 
        zfcp_fsf_req_free(req);
 
@@ -1493,6 +1518,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
                erp_action->fsf_req_id = 0;
                put_device(&port->dev);
        }
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 out:
        spin_unlock_irq(&qdio->req_q_lock);
        return retval;
@@ -1557,6 +1583,7 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
                zfcp_fsf_req_free(req);
                erp_action->fsf_req_id = 0;
        }
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 out:
        spin_unlock_irq(&qdio->req_q_lock);
        return retval;
@@ -1600,6 +1627,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)
 {
        struct zfcp_qdio *qdio = wka_port->adapter->qdio;
        struct zfcp_fsf_req *req;
+       unsigned long req_id = 0;
        int retval = -EIO;
 
        spin_lock_irq(&qdio->req_q_lock);
@@ -1622,14 +1650,17 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)
        hton24(req->qtcb->bottom.support.d_id, wka_port->d_id);
        req->data = wka_port;
 
+       req_id = req->req_id;
+
        zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
        retval = zfcp_fsf_req_send(req);
        if (retval)
                zfcp_fsf_req_free(req);
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 out:
        spin_unlock_irq(&qdio->req_q_lock);
        if (!retval)
-               zfcp_dbf_rec_run_wka("fsowp_1", wka_port, req->req_id);
+               zfcp_dbf_rec_run_wka("fsowp_1", wka_port, req_id);
        return retval;
 }
 
@@ -1655,6 +1686,7 @@ int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)
 {
        struct zfcp_qdio *qdio = wka_port->adapter->qdio;
        struct zfcp_fsf_req *req;
+       unsigned long req_id = 0;
        int retval = -EIO;
 
        spin_lock_irq(&qdio->req_q_lock);
@@ -1677,14 +1709,17 @@ int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)
        req->data = wka_port;
        req->qtcb->header.port_handle = wka_port->handle;
 
+       req_id = req->req_id;
+
        zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
        retval = zfcp_fsf_req_send(req);
        if (retval)
                zfcp_fsf_req_free(req);
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 out:
        spin_unlock_irq(&qdio->req_q_lock);
        if (!retval)
-               zfcp_dbf_rec_run_wka("fscwp_1", wka_port, req->req_id);
+               zfcp_dbf_rec_run_wka("fscwp_1", wka_port, req_id);
        return retval;
 }
 
@@ -1776,6 +1811,7 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
                zfcp_fsf_req_free(req);
                erp_action->fsf_req_id = 0;
        }
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 out:
        spin_unlock_irq(&qdio->req_q_lock);
        return retval;
@@ -1899,6 +1935,7 @@ int zfcp_fsf_open_lun(struct zfcp_erp_action *erp_action)
                zfcp_fsf_req_free(req);
                erp_action->fsf_req_id = 0;
        }
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 out:
        spin_unlock_irq(&qdio->req_q_lock);
        return retval;
@@ -1987,6 +2024,7 @@ int zfcp_fsf_close_lun(struct zfcp_erp_action *erp_action)
                zfcp_fsf_req_free(req);
                erp_action->fsf_req_id = 0;
        }
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 out:
        spin_unlock_irq(&qdio->req_q_lock);
        return retval;
@@ -2299,6 +2337,7 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd)
        retval = zfcp_fsf_req_send(req);
        if (unlikely(retval))
                goto failed_scsi_cmnd;
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 
        goto out;
 
@@ -2373,8 +2412,10 @@ struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_device *sdev,
        zfcp_fc_fcp_tm(fcp_cmnd, sdev, tm_flags);
 
        zfcp_fsf_start_timer(req, ZFCP_FSF_SCSI_ER_TIMEOUT);
-       if (!zfcp_fsf_req_send(req))
+       if (!zfcp_fsf_req_send(req)) {
+               /* NOTE: DO NOT TOUCH req, UNTIL IT COMPLETES! */
                goto out;
+       }
 
        zfcp_fsf_req_free(req);
        req = NULL;
index aeda539..c00e3dd 100644 (file)
@@ -185,7 +185,7 @@ zalon7xx-objs       := zalon.o ncr53c8xx.o
 # Files generated that shall be removed upon make clean
 clean-files := 53c700_d.h 53c700_u.h scsi_devinfo_tbl.c
 
-$(obj)/53c700.o $(MODVERDIR)/$(obj)/53c700.ver: $(obj)/53c700_d.h
+$(obj)/53c700.o: $(obj)/53c700_d.h
 
 $(obj)/scsi_sysfs.o: $(obj)/scsi_devinfo_tbl.c
 
index 96740c6..7018cd8 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/idr.h>
 #include <linux/module.h>
 #include <linux/mount.h>
+#include <linux/pseudo_fs.h>
 #include <linux/poll.h>
 #include <linux/sched/signal.h>
 
 static int ocxlflash_fs_cnt;
 static struct vfsmount *ocxlflash_vfs_mount;
 
-static const struct dentry_operations ocxlflash_fs_dops = {
-       .d_dname        = simple_dname,
-};
-
-/*
- * ocxlflash_fs_mount() - mount the pseudo-filesystem
- * @fs_type:   File system type.
- * @flags:     Flags for the filesystem.
- * @dev_name:  Device name associated with the filesystem.
- * @data:      Data pointer.
- *
- * Return: pointer to the directory entry structure
- */
-static struct dentry *ocxlflash_fs_mount(struct file_system_type *fs_type,
-                                        int flags, const char *dev_name,
-                                        void *data)
+static int ocxlflash_fs_init_fs_context(struct fs_context *fc)
 {
-       return mount_pseudo(fs_type, "ocxlflash:", NULL, &ocxlflash_fs_dops,
-                           OCXLFLASH_FS_MAGIC);
+       return init_pseudo(fc, OCXLFLASH_FS_MAGIC) ? 0 : -ENOMEM;
 }
 
 static struct file_system_type ocxlflash_fs_type = {
        .name           = "ocxlflash",
        .owner          = THIS_MODULE,
-       .mount          = ocxlflash_fs_mount,
+       .init_fs_context = ocxlflash_fs_init_fs_context,
        .kill_sb        = kill_anon_super,
 };
 
index ff0d8c6..55522b7 100644 (file)
@@ -462,6 +462,9 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
        else
                shost->dma_boundary = 0xffffffff;
 
+       if (sht->virt_boundary_mask)
+               shost->virt_boundary_mask = sht->virt_boundary_mask;
+
        device_initialize(&shost->shost_gendev);
        dev_set_name(&shost->shost_gendev, "host%d", shost->host_no);
        shost->shost_gendev.bus = &scsi_bus_type;
index 8e1053b..52e8666 100644 (file)
@@ -2591,7 +2591,7 @@ void fc_exch_recv(struct fc_lport *lport, struct fc_frame *fp)
 
        /* lport lock ? */
        if (!lport || lport->state == LPORT_ST_DISABLED) {
-               FC_LPORT_DBG(lport, "Receiving frames for an lport that "
+               FC_LIBFC_DBG("Receiving frames for an lport that "
                             "has not been initialized correctly\n");
                fc_frame_free(fp);
                return;
index 4f339f9..bec83eb 100644 (file)
@@ -414,7 +414,6 @@ static void sas_wait_eh(struct domain_device *dev)
                goto retry;
        }
 }
-EXPORT_SYMBOL(sas_wait_eh);
 
 static int sas_queue_reset(struct domain_device *dev, int reset_type,
                           u64 lun, int wait)
index 2322ddb..3407087 100644 (file)
@@ -330,7 +330,7 @@ enum {
  * This function dumps an entry indexed by @idx from a queue specified by the
  * queue descriptor @q.
  **/
-static inline void
+static void
 lpfc_debug_dump_qe(struct lpfc_queue *q, uint32_t idx)
 {
        char line_buf[LPFC_LBUF_SZ];
index ca724fe..a14e834 100644 (file)
@@ -21,8 +21,8 @@
 /*
  * MegaRAID SAS Driver meta data
  */
-#define MEGASAS_VERSION                                "07.710.06.00-rc1"
-#define MEGASAS_RELDATE                                "June 18, 2019"
+#define MEGASAS_VERSION                                "07.710.50.00-rc1"
+#define MEGASAS_RELDATE                                "June 28, 2019"
 
 /*
  * Device IDs
index 80ab970..b2339d0 100644 (file)
@@ -105,6 +105,10 @@ MODULE_PARM_DESC(perf_mode, "Performance mode (only for Aero adapters), options:
                "default mode is 'balanced'"
                );
 
+int event_log_level = MFI_EVT_CLASS_CRITICAL;
+module_param(event_log_level, int, 0644);
+MODULE_PARM_DESC(event_log_level, "Asynchronous event logging level- range is: -2(CLASS_DEBUG) to 4(CLASS_DEAD), Default: 2(CLASS_CRITICAL)");
+
 MODULE_LICENSE("GPL");
 MODULE_VERSION(MEGASAS_VERSION);
 MODULE_AUTHOR("megaraidlinux.pdl@broadcom.com");
@@ -280,7 +284,7 @@ void megasas_set_dma_settings(struct megasas_instance *instance,
        }
 }
 
-void
+static void
 megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
 {
        instance->instancet->fire_cmd(instance,
@@ -404,7 +408,13 @@ megasas_decode_evt(struct megasas_instance *instance)
        union megasas_evt_class_locale class_locale;
        class_locale.word = le32_to_cpu(evt_detail->cl.word);
 
-       if (class_locale.members.class >= MFI_EVT_CLASS_CRITICAL)
+       if ((event_log_level < MFI_EVT_CLASS_DEBUG) ||
+           (event_log_level > MFI_EVT_CLASS_DEAD)) {
+               printk(KERN_WARNING "megaraid_sas: provided event log level is out of range, setting it to default 2(CLASS_CRITICAL), permissible range is: -2 to 4\n");
+               event_log_level = MFI_EVT_CLASS_CRITICAL;
+       }
+
+       if (class_locale.members.class >= event_log_level)
                dev_info(&instance->pdev->dev, "%d (%s/0x%04x/%s) - %s\n",
                        le32_to_cpu(evt_detail->seq_num),
                        format_timestamp(le32_to_cpu(evt_detail->time_stamp)),
@@ -2237,7 +2247,7 @@ megasas_internal_reset_defer_cmds(struct megasas_instance *instance);
 static void
 process_fw_state_change_wq(struct work_struct *work);
 
-void megasas_do_ocr(struct megasas_instance *instance)
+static void megasas_do_ocr(struct megasas_instance *instance)
 {
        if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) ||
        (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) ||
@@ -3303,7 +3313,7 @@ static DEVICE_ATTR_RO(fw_cmds_outstanding);
 static DEVICE_ATTR_RO(dump_system_regs);
 static DEVICE_ATTR_RO(raid_map_id);
 
-struct device_attribute *megaraid_host_attrs[] = {
+static struct device_attribute *megaraid_host_attrs[] = {
        &dev_attr_fw_crash_buffer_size,
        &dev_attr_fw_crash_buffer,
        &dev_attr_fw_crash_state,
@@ -3334,6 +3344,7 @@ static struct scsi_host_template megasas_template = {
        .shost_attrs = megaraid_host_attrs,
        .bios_param = megasas_bios_param,
        .change_queue_depth = scsi_change_queue_depth,
+       .max_segment_size = 0xffffffff,
        .no_write_same = 1,
 };
 
@@ -5933,7 +5944,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
                                        instance->is_rdpq = (scratch_pad_1 & MR_RDPQ_MODE_OFFSET) ?
                                                                1 : 0;
 
-                               if (!instance->msix_combined) {
+                               if (instance->adapter_type >= INVADER_SERIES &&
+                                   !instance->msix_combined) {
                                        instance->msix_load_balance = true;
                                        instance->smp_affinity_enable = false;
                                }
@@ -6546,7 +6558,8 @@ megasas_get_target_prop(struct megasas_instance *instance,
        int ret;
        struct megasas_cmd *cmd;
        struct megasas_dcmd_frame *dcmd;
-       u16 targetId = (sdev->channel % 2) + sdev->id;
+       u16 targetId = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) +
+                       sdev->id;
 
        cmd = megasas_get_cmd(instance);
 
@@ -8748,6 +8761,12 @@ static int __init megasas_init(void)
                goto err_pcidrv;
        }
 
+       if ((event_log_level < MFI_EVT_CLASS_DEBUG) ||
+           (event_log_level > MFI_EVT_CLASS_DEAD)) {
+               printk(KERN_WARNING "megarid_sas: provided event log level is out of range, setting it to default 2(CLASS_CRITICAL), permissible range is: -2 to 4\n");
+               event_log_level = MFI_EVT_CLASS_CRITICAL;
+       }
+
        rval = driver_create_file(&megasas_pci_driver.driver,
                                  &driver_attr_version);
        if (rval)
index 27c731a..717ba08 100644 (file)
@@ -10238,6 +10238,7 @@ static struct scsi_host_template mpt3sas_driver_template = {
        .this_id                        = -1,
        .sg_tablesize                   = MPT3SAS_SG_DEPTH,
        .max_sectors                    = 32767,
+       .max_segment_size               = 0xffffffff,
        .cmd_per_lun                    = 7,
        .shost_attrs                    = mpt3sas_host_attrs,
        .sdev_attrs                     = mpt3sas_dev_attrs,
index dd38c35..9453705 100644 (file)
@@ -888,6 +888,8 @@ static void pm8001_dev_gone_notify(struct domain_device *dev)
                        spin_unlock_irqrestore(&pm8001_ha->lock, flags);
                        pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
                                dev, 1, 0);
+                       while (pm8001_dev->running_req)
+                               msleep(20);
                        spin_lock_irqsave(&pm8001_ha->lock, flags);
                }
                PM8001_CHIP_DISP->dereg_dev_req(pm8001_ha, device_id);
@@ -1256,8 +1258,10 @@ int pm8001_abort_task(struct sas_task *task)
                        PM8001_MSG_DBG(pm8001_ha,
                                pm8001_printk("Waiting for Port reset\n"));
                        wait_for_completion(&completion_reset);
-                       if (phy->port_reset_status)
+                       if (phy->port_reset_status) {
+                               pm8001_dev_gone_notify(dev);
                                goto out;
+                       }
 
                        /*
                         * 4. SATA Abort ALL
index 1128d86..7326190 100644 (file)
@@ -604,7 +604,7 @@ static void update_main_config_table(struct pm8001_hba_info *pm8001_ha)
                pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer &=
                                        0x0000ffff;
                pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer |=
-                                       0x140000;
+                                       CHIP_8006_PORT_RECOVERY_TIMEOUT;
        }
        pm8001_mw32(address, MAIN_PORT_RECOVERY_TIMER,
                        pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer);
index 84d7426..dc9ab76 100644 (file)
 #define SAS_MAX_AIP                     0x200000
 #define IT_NEXUS_TIMEOUT       0x7D0
 #define PORT_RECOVERY_TIMEOUT  ((IT_NEXUS_TIMEOUT/100) + 30)
+/* Port recovery timeout, 10000 ms for PM8006 controller */
+#define CHIP_8006_PORT_RECOVERY_TIMEOUT 0x640000
 
 #ifdef __LITTLE_ENDIAN_BITFIELD
 struct sas_identify_frame_local {
index a08ff3b..df14597 100644 (file)
@@ -239,6 +239,8 @@ static struct {
        {"LSI", "Universal Xport", "*", BLIST_NO_ULD_ATTACH},
        {"ENGENIO", "Universal Xport", "*", BLIST_NO_ULD_ATTACH},
        {"LENOVO", "Universal Xport", "*", BLIST_NO_ULD_ATTACH},
+       {"SanDisk", "Cruzer Blade", NULL, BLIST_TRY_VPD_PAGES |
+               BLIST_INQUIRY_36},
        {"SMSC", "USB 2 HS-CF", NULL, BLIST_SPARSELUN | BLIST_INQUIRY_36},
        {"SONY", "CD-ROM CDU-8001", NULL, BLIST_BORKEN},
        {"SONY", "TSL", NULL, BLIST_FORCELUN},          /* DDS3 & DDS4 autoloaders */
index e1da8c7..9381171 100644 (file)
@@ -84,11 +84,11 @@ int scsi_init_sense_cache(struct Scsi_Host *shost)
        struct kmem_cache *cache;
        int ret = 0;
 
+       mutex_lock(&scsi_sense_cache_mutex);
        cache = scsi_select_sense_cache(shost->unchecked_isa_dma);
        if (cache)
-               return 0;
+               goto exit;
 
-       mutex_lock(&scsi_sense_cache_mutex);
        if (shost->unchecked_isa_dma) {
                scsi_sense_isadma_cache =
                        kmem_cache_create("scsi_sense_cache(DMA)",
@@ -104,7 +104,7 @@ int scsi_init_sense_cache(struct Scsi_Host *shost)
                if (!scsi_sense_cache)
                        ret = -ENOMEM;
        }
-
+ exit:
        mutex_unlock(&scsi_sense_cache_mutex);
        return ret;
 }
@@ -1452,7 +1452,7 @@ static void scsi_softirq_done(struct request *rq)
        disposition = scsi_decide_disposition(cmd);
        if (disposition != SUCCESS &&
            time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) {
-               sdev_printk(KERN_ERR, cmd->device,
+               scmd_printk(KERN_ERR, cmd,
                            "timing out command, waited %lus\n",
                            wait_for/HZ);
                disposition = SUCCESS;
@@ -1784,6 +1784,8 @@ void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q)
                blk_queue_max_integrity_segments(q, shost->sg_prot_tablesize);
        }
 
+       shost->max_sectors = min_t(unsigned int, shost->max_sectors,
+                       dma_max_mapping_size(dev) << SECTOR_SHIFT);
        blk_queue_max_hw_sectors(q, shost->max_sectors);
        if (shost->unchecked_isa_dma)
                blk_queue_bounce_limit(q, BLK_BOUNCE_ISA);
@@ -1791,7 +1793,8 @@ void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q)
        dma_set_seg_boundary(dev, shost->dma_boundary);
 
        blk_queue_max_segment_size(q, shost->max_segment_size);
-       dma_set_max_seg_size(dev, shost->max_segment_size);
+       blk_queue_virt_boundary(q, shost->virt_boundary_mask);
+       dma_set_max_seg_size(dev, queue_max_segment_size(q));
 
        /*
         * Set a reasonable default alignment:  The larger of 32-byte (dword),
index db16c19..5d6ff39 100644 (file)
@@ -461,7 +461,7 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
 {
        struct gendisk *disk = sdkp->disk;
        unsigned int nr_zones;
-       u32 zone_blocks;
+       u32 zone_blocks = 0;
        int ret;
 
        if (!sd_is_zoned(sdkp))
index c2b6a0c..ed8b9ac 100644 (file)
@@ -1423,9 +1423,6 @@ static int storvsc_device_configure(struct scsi_device *sdevice)
 {
        blk_queue_rq_timeout(sdevice->request_queue, (storvsc_timeout * HZ));
 
-       /* Ensure there are no gaps in presented sgls */
-       blk_queue_virt_boundary(sdevice->request_queue, PAGE_SIZE - 1);
-
        sdevice->no_write_same = 1;
 
        /*
@@ -1698,6 +1695,8 @@ static struct scsi_host_template scsi_driver = {
        .this_id =              -1,
        /* Make sure we dont get a sg segment crosses a page boundary */
        .dma_boundary =         PAGE_SIZE-1,
+       /* Ensure there are no gaps in presented sgls */
+       .virt_boundary_mask =   PAGE_SIZE-1,
        .no_write_same =        1,
        .track_queue_depth =    1,
        .change_queue_depth =   storvsc_change_queue_depth,
index 04d3686..e274053 100644 (file)
@@ -4587,8 +4587,6 @@ static int ufshcd_slave_configure(struct scsi_device *sdev)
        struct request_queue *q = sdev->request_queue;
 
        blk_queue_update_dma_pad(q, PRDT_DATA_BYTE_COUNT_PAD - 1);
-       blk_queue_max_segment_size(q, PRDT_DATA_BYTE_COUNT_MAX);
-
        return 0;
 }
 
@@ -7022,6 +7020,7 @@ static struct scsi_host_template ufshcd_driver_template = {
        .sg_tablesize           = SG_ALL,
        .cmd_per_lun            = UFSHCD_CMD_PER_LUN,
        .can_queue              = UFSHCD_CAN_QUEUE,
+       .max_segment_size       = PRDT_DATA_BYTE_COUNT_MAX,
        .max_host_blocked       = 1,
        .track_queue_depth      = 1,
        .sdev_groups            = ufshcd_driver_groups,
index 1705398..297e107 100644 (file)
@@ -792,7 +792,7 @@ static int virtscsi_probe(struct virtio_device *vdev)
        num_targets = virtscsi_config_get(vdev, max_target) + 1;
 
        shost = scsi_host_alloc(&virtscsi_host_template,
-               sizeof(*vscsi) + sizeof(vscsi->req_vqs[0]) * num_queues);
+                               struct_size(vscsi, req_vqs, num_queues));
        if (!shost)
                return -ENOMEM;
 
index be95a37..c655f5f 100644 (file)
@@ -35,6 +35,7 @@ struct meson_canvas {
        void __iomem *reg_base;
        spinlock_t lock; /* canvas device lock */
        u8 used[NUM_CANVAS];
+       bool supports_endianness;
 };
 
 static void canvas_write(struct meson_canvas *canvas, u32 reg, u32 val)
@@ -86,6 +87,12 @@ int meson_canvas_config(struct meson_canvas *canvas, u8 canvas_index,
 {
        unsigned long flags;
 
+       if (endian && !canvas->supports_endianness) {
+               dev_err(canvas->dev,
+                       "Endianness is not supported on this SoC\n");
+               return -EINVAL;
+       }
+
        spin_lock_irqsave(&canvas->lock, flags);
        if (!canvas->used[canvas_index]) {
                dev_err(canvas->dev,
@@ -172,6 +179,8 @@ static int meson_canvas_probe(struct platform_device *pdev)
        if (IS_ERR(canvas->reg_base))
                return PTR_ERR(canvas->reg_base);
 
+       canvas->supports_endianness = of_device_get_match_data(dev);
+
        canvas->dev = dev;
        spin_lock_init(&canvas->lock);
        dev_set_drvdata(dev, canvas);
@@ -180,7 +189,10 @@ static int meson_canvas_probe(struct platform_device *pdev)
 }
 
 static const struct of_device_id canvas_dt_match[] = {
-       { .compatible = "amlogic,canvas" },
+       { .compatible = "amlogic,meson8-canvas", .data = (void *)false, },
+       { .compatible = "amlogic,meson8b-canvas", .data = (void *)false, },
+       { .compatible = "amlogic,meson8m2-canvas", .data = (void *)false, },
+       { .compatible = "amlogic,canvas", .data = (void *)true, },
        {}
 };
 MODULE_DEVICE_TABLE(of, canvas_dt_match);
index 61276ec..01ed21e 100644 (file)
@@ -64,6 +64,7 @@ static long aspeed_lpc_ctrl_ioctl(struct file *file, unsigned int cmd,
                unsigned long param)
 {
        struct aspeed_lpc_ctrl *lpc_ctrl = file_aspeed_lpc_ctrl(file);
+       struct device *dev = file->private_data;
        void __user *p = (void __user *)param;
        struct aspeed_lpc_ctrl_mapping map;
        u32 addr;
@@ -86,6 +87,12 @@ static long aspeed_lpc_ctrl_ioctl(struct file *file, unsigned int cmd,
                if (map.window_id != 0)
                        return -EINVAL;
 
+               /* If memory-region is not described in device tree */
+               if (!lpc_ctrl->mem_size) {
+                       dev_dbg(dev, "Didn't find reserved memory\n");
+                       return -ENXIO;
+               }
+
                map.size = lpc_ctrl->mem_size;
 
                return copy_to_user(p, &map, sizeof(map)) ? -EFAULT : 0;
@@ -122,9 +129,18 @@ static long aspeed_lpc_ctrl_ioctl(struct file *file, unsigned int cmd,
                        return -EINVAL;
 
                if (map.window_type == ASPEED_LPC_CTRL_WINDOW_FLASH) {
+                       if (!lpc_ctrl->pnor_size) {
+                               dev_dbg(dev, "Didn't find host pnor flash\n");
+                               return -ENXIO;
+                       }
                        addr = lpc_ctrl->pnor_base;
                        size = lpc_ctrl->pnor_size;
                } else if (map.window_type == ASPEED_LPC_CTRL_WINDOW_MEMORY) {
+                       /* If memory-region is not described in device tree */
+                       if (!lpc_ctrl->mem_size) {
+                               dev_dbg(dev, "Didn't find reserved memory\n");
+                               return -ENXIO;
+                       }
                        addr = lpc_ctrl->mem_base;
                        size = lpc_ctrl->mem_size;
                } else {
@@ -192,40 +208,41 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev)
        if (!lpc_ctrl)
                return -ENOMEM;
 
+       /* If flash is described in device tree then store */
        node = of_parse_phandle(dev->of_node, "flash", 0);
        if (!node) {
-               dev_err(dev, "Didn't find host pnor flash node\n");
-               return -ENODEV;
-       }
+               dev_dbg(dev, "Didn't find host pnor flash node\n");
+       } else {
+               rc = of_address_to_resource(node, 1, &resm);
+               of_node_put(node);
+               if (rc) {
+                       dev_err(dev, "Couldn't address to resource for flash\n");
+                       return rc;
+               }
 
-       rc = of_address_to_resource(node, 1, &resm);
-       of_node_put(node);
-       if (rc) {
-               dev_err(dev, "Couldn't address to resource for flash\n");
-               return rc;
+               lpc_ctrl->pnor_size = resource_size(&resm);
+               lpc_ctrl->pnor_base = resm.start;
        }
 
-       lpc_ctrl->pnor_size = resource_size(&resm);
-       lpc_ctrl->pnor_base = resm.start;
 
        dev_set_drvdata(&pdev->dev, lpc_ctrl);
 
+       /* If memory-region is described in device tree then store */
        node = of_parse_phandle(dev->of_node, "memory-region", 0);
        if (!node) {
-               dev_err(dev, "Didn't find reserved memory\n");
-               return -EINVAL;
-       }
+               dev_dbg(dev, "Didn't find reserved memory\n");
+       } else {
+               rc = of_address_to_resource(node, 0, &resm);
+               of_node_put(node);
+               if (rc) {
+                       dev_err(dev, "Couldn't address to resource for reserved memory\n");
+                       return -ENXIO;
+               }
 
-       rc = of_address_to_resource(node, 0, &resm);
-       of_node_put(node);
-       if (rc) {
-               dev_err(dev, "Couldn't address to resource for reserved memory\n");
-               return -ENOMEM;
+               lpc_ctrl->mem_size = resource_size(&resm);
+               lpc_ctrl->mem_base = resm.start;
        }
 
-       lpc_ctrl->mem_size = resource_size(&resm);
-       lpc_ctrl->mem_base = resm.start;
-
        lpc_ctrl->regmap = syscon_node_to_regmap(
                        pdev->dev.parent->of_node);
        if (IS_ERR(lpc_ctrl->regmap)) {
@@ -254,8 +271,6 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev)
                goto err;
        }
 
-       dev_info(dev, "Loaded at %pr\n", &resm);
-
        return 0;
 
 err:
index 217f775..f9ad8ad 100644 (file)
@@ -30,4 +30,14 @@ config FSL_MC_DPIO
          other DPAA2 objects. This driver does not expose the DPIO
          objects individually, but groups them under a service layer
          API.
+
+config DPAA2_CONSOLE
+       tristate "QorIQ DPAA2 console driver"
+       depends on OF && (ARCH_LAYERSCAPE || COMPILE_TEST)
+       default y
+       help
+         Console driver for DPAA2 platforms. Exports 2 char devices,
+         /dev/dpaa2_mc_console and /dev/dpaa2_aiop_console,
+         which can be used to dump the Management Complex and AIOP
+         firmware logs.
 endmenu
index 158541a..71dee8d 100644 (file)
@@ -8,3 +8,4 @@ obj-$(CONFIG_QUICC_ENGINE)              += qe/
 obj-$(CONFIG_CPM)                      += qe/
 obj-$(CONFIG_FSL_GUTS)                 += guts.o
 obj-$(CONFIG_FSL_MC_DPIO)              += dpio/
+obj-$(CONFIG_DPAA2_CONSOLE)            += dpaa2-console.o
diff --git a/drivers/soc/fsl/dpaa2-console.c b/drivers/soc/fsl/dpaa2-console.c
new file mode 100644 (file)
index 0000000..9168d8d
--- /dev/null
@@ -0,0 +1,329 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Freescale DPAA2 Platforms Console Driver
+ *
+ * Copyright 2015-2016 Freescale Semiconductor Inc.
+ * Copyright 2018 NXP
+ */
+
+#define pr_fmt(fmt) "dpaa2-console: " fmt
+
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+
+/* MC firmware base low/high registers indexes */
+#define MCFBALR_OFFSET 0
+#define MCFBAHR_OFFSET 1
+
+/* Bit masks used to get the most/least significant part of the MC base addr */
+#define MC_FW_ADDR_MASK_HIGH 0x1FFFF
+#define MC_FW_ADDR_MASK_LOW  0xE0000000
+
+#define MC_BUFFER_OFFSET 0x01000000
+#define MC_BUFFER_SIZE   (1024 * 1024 * 16)
+#define MC_OFFSET_DELTA  MC_BUFFER_OFFSET
+
+#define AIOP_BUFFER_OFFSET 0x06000000
+#define AIOP_BUFFER_SIZE   (1024 * 1024 * 16)
+#define AIOP_OFFSET_DELTA  0
+
+#define LOG_HEADER_FLAG_BUFFER_WRAPAROUND 0x80000000
+#define LAST_BYTE(a) ((a) & ~(LOG_HEADER_FLAG_BUFFER_WRAPAROUND))
+
+/* MC and AIOP Magic words */
+#define MAGIC_MC   0x4d430100
+#define MAGIC_AIOP 0x41494F50
+
+struct log_header {
+       __le32 magic_word;
+       char reserved[4];
+       __le32 buf_start;
+       __le32 buf_length;
+       __le32 last_byte;
+};
+
+struct console_data {
+       void __iomem *map_addr;
+       struct log_header __iomem *hdr;
+       void __iomem *start_addr;
+       void __iomem *end_addr;
+       void __iomem *end_of_data;
+       void __iomem *cur_ptr;
+};
+
+static struct resource mc_base_addr;
+
+static inline void adjust_end(struct console_data *cd)
+{
+       u32 last_byte = readl(&cd->hdr->last_byte);
+
+       cd->end_of_data = cd->start_addr + LAST_BYTE(last_byte);
+}
+
+static u64 get_mc_fw_base_address(void)
+{
+       u64 mcfwbase = 0ULL;
+       u32 __iomem *mcfbaregs;
+
+       mcfbaregs = ioremap(mc_base_addr.start, resource_size(&mc_base_addr));
+       if (!mcfbaregs) {
+               pr_err("could not map MC Firmaware Base registers\n");
+               return 0;
+       }
+
+       mcfwbase  = readl(mcfbaregs + MCFBAHR_OFFSET) &
+                         MC_FW_ADDR_MASK_HIGH;
+       mcfwbase <<= 32;
+       mcfwbase |= readl(mcfbaregs + MCFBALR_OFFSET) & MC_FW_ADDR_MASK_LOW;
+       iounmap(mcfbaregs);
+
+       pr_debug("MC base address at 0x%016llx\n", mcfwbase);
+       return mcfwbase;
+}
+
+static ssize_t dpaa2_console_size(struct console_data *cd)
+{
+       ssize_t size;
+
+       if (cd->cur_ptr <= cd->end_of_data)
+               size = cd->end_of_data - cd->cur_ptr;
+       else
+               size = (cd->end_addr - cd->cur_ptr) +
+                       (cd->end_of_data - cd->start_addr);
+
+       return size;
+}
+
+static int dpaa2_generic_console_open(struct inode *node, struct file *fp,
+                                     u64 offset, u64 size,
+                                     u32 expected_magic,
+                                     u32 offset_delta)
+{
+       u32 read_magic, wrapped, last_byte, buf_start, buf_length;
+       struct console_data *cd;
+       u64 base_addr;
+       int err;
+
+       cd = kmalloc(sizeof(*cd), GFP_KERNEL);
+       if (!cd)
+               return -ENOMEM;
+
+       base_addr = get_mc_fw_base_address();
+       if (!base_addr) {
+               err = -EIO;
+               goto err_fwba;
+       }
+
+       cd->map_addr = ioremap(base_addr + offset, size);
+       if (!cd->map_addr) {
+               pr_err("cannot map console log memory\n");
+               err = -EIO;
+               goto err_ioremap;
+       }
+
+       cd->hdr = (struct log_header __iomem *)cd->map_addr;
+       read_magic = readl(&cd->hdr->magic_word);
+       last_byte =  readl(&cd->hdr->last_byte);
+       buf_start =  readl(&cd->hdr->buf_start);
+       buf_length = readl(&cd->hdr->buf_length);
+
+       if (read_magic != expected_magic) {
+               pr_warn("expected = %08x, read = %08x\n",
+                       expected_magic, read_magic);
+               err = -EIO;
+               goto err_magic;
+       }
+
+       cd->start_addr = cd->map_addr + buf_start - offset_delta;
+       cd->end_addr = cd->start_addr + buf_length;
+
+       wrapped = last_byte & LOG_HEADER_FLAG_BUFFER_WRAPAROUND;
+
+       adjust_end(cd);
+       if (wrapped && cd->end_of_data != cd->end_addr)
+               cd->cur_ptr = cd->end_of_data + 1;
+       else
+               cd->cur_ptr = cd->start_addr;
+
+       fp->private_data = cd;
+
+       return 0;
+
+err_magic:
+       iounmap(cd->map_addr);
+
+err_ioremap:
+err_fwba:
+       kfree(cd);
+
+       return err;
+}
+
+static int dpaa2_mc_console_open(struct inode *node, struct file *fp)
+{
+       return dpaa2_generic_console_open(node, fp,
+                                         MC_BUFFER_OFFSET, MC_BUFFER_SIZE,
+                                         MAGIC_MC, MC_OFFSET_DELTA);
+}
+
+static int dpaa2_aiop_console_open(struct inode *node, struct file *fp)
+{
+       return dpaa2_generic_console_open(node, fp,
+                                         AIOP_BUFFER_OFFSET, AIOP_BUFFER_SIZE,
+                                         MAGIC_AIOP, AIOP_OFFSET_DELTA);
+}
+
+static int dpaa2_console_close(struct inode *node, struct file *fp)
+{
+       struct console_data *cd = fp->private_data;
+
+       iounmap(cd->map_addr);
+       kfree(cd);
+       return 0;
+}
+
+static ssize_t dpaa2_console_read(struct file *fp, char __user *buf,
+                                 size_t count, loff_t *f_pos)
+{
+       struct console_data *cd = fp->private_data;
+       size_t bytes = dpaa2_console_size(cd);
+       size_t bytes_end = cd->end_addr - cd->cur_ptr;
+       size_t written = 0;
+       void *kbuf;
+       int err;
+
+       /* Check if we need to adjust the end of data addr */
+       adjust_end(cd);
+
+       if (cd->end_of_data == cd->cur_ptr)
+               return 0;
+
+       if (count < bytes)
+               bytes = count;
+
+       kbuf = kmalloc(bytes, GFP_KERNEL);
+       if (!kbuf)
+               return -ENOMEM;
+
+       if (bytes > bytes_end) {
+               memcpy_fromio(kbuf, cd->cur_ptr, bytes_end);
+               if (copy_to_user(buf, kbuf, bytes_end)) {
+                       err = -EFAULT;
+                       goto err_free_buf;
+               }
+               buf += bytes_end;
+               cd->cur_ptr = cd->start_addr;
+               bytes -= bytes_end;
+               written += bytes_end;
+       }
+
+       memcpy_fromio(kbuf, cd->cur_ptr, bytes);
+       if (copy_to_user(buf, kbuf, bytes)) {
+               err = -EFAULT;
+               goto err_free_buf;
+       }
+       cd->cur_ptr += bytes;
+       written += bytes;
+
+       return written;
+
+err_free_buf:
+       kfree(kbuf);
+
+       return err;
+}
+
+static const struct file_operations dpaa2_mc_console_fops = {
+       .owner          = THIS_MODULE,
+       .open           = dpaa2_mc_console_open,
+       .release        = dpaa2_console_close,
+       .read           = dpaa2_console_read,
+};
+
+static struct miscdevice dpaa2_mc_console_dev = {
+       .minor = MISC_DYNAMIC_MINOR,
+       .name = "dpaa2_mc_console",
+       .fops = &dpaa2_mc_console_fops
+};
+
+static const struct file_operations dpaa2_aiop_console_fops = {
+       .owner          = THIS_MODULE,
+       .open           = dpaa2_aiop_console_open,
+       .release        = dpaa2_console_close,
+       .read           = dpaa2_console_read,
+};
+
+static struct miscdevice dpaa2_aiop_console_dev = {
+       .minor = MISC_DYNAMIC_MINOR,
+       .name = "dpaa2_aiop_console",
+       .fops = &dpaa2_aiop_console_fops
+};
+
+static int dpaa2_console_probe(struct platform_device *pdev)
+{
+       int error;
+
+       error = of_address_to_resource(pdev->dev.of_node, 0, &mc_base_addr);
+       if (error < 0) {
+               pr_err("of_address_to_resource() failed for %pOF with %d\n",
+                      pdev->dev.of_node, error);
+               return error;
+       }
+
+       error = misc_register(&dpaa2_mc_console_dev);
+       if (error) {
+               pr_err("cannot register device %s\n",
+                      dpaa2_mc_console_dev.name);
+               goto err_register_mc;
+       }
+
+       error = misc_register(&dpaa2_aiop_console_dev);
+       if (error) {
+               pr_err("cannot register device %s\n",
+                      dpaa2_aiop_console_dev.name);
+               goto err_register_aiop;
+       }
+
+       return 0;
+
+err_register_aiop:
+       misc_deregister(&dpaa2_mc_console_dev);
+err_register_mc:
+       return error;
+}
+
+static int dpaa2_console_remove(struct platform_device *pdev)
+{
+       misc_deregister(&dpaa2_mc_console_dev);
+       misc_deregister(&dpaa2_aiop_console_dev);
+
+       return 0;
+}
+
+static const struct of_device_id dpaa2_console_match_table[] = {
+       { .compatible = "fsl,dpaa2-console",},
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, dpaa2_console_match_table);
+
+static struct platform_driver dpaa2_console_driver = {
+       .driver = {
+                  .name = "dpaa2-console",
+                  .pm = NULL,
+                  .of_match_table = dpaa2_console_match_table,
+                  },
+       .probe = dpaa2_console_probe,
+       .remove = dpaa2_console_remove,
+};
+module_platform_driver(dpaa2_console_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Roy Pledge <roy.pledge@nxp.com>");
+MODULE_DESCRIPTION("DPAA2 console driver");
index c0cdc89..70014ec 100644 (file)
@@ -197,13 +197,22 @@ static int dpaa2_dpio_probe(struct fsl_mc_device *dpio_dev)
                                desc.cpu);
        }
 
-       /*
-        * Set the CENA regs to be the cache inhibited area of the portal to
-        * avoid coherency issues if a user migrates to another core.
-        */
-       desc.regs_cena = devm_memremap(dev, dpio_dev->regions[1].start,
-                                      resource_size(&dpio_dev->regions[1]),
-                                      MEMREMAP_WC);
+       if (dpio_dev->obj_desc.region_count < 3) {
+               /* No support for DDR backed portals, use classic mapping */
+               /*
+                * Set the CENA regs to be the cache inhibited area of the
+                * portal to avoid coherency issues if a user migrates to
+                * another core.
+                */
+               desc.regs_cena = devm_memremap(dev, dpio_dev->regions[1].start,
+                                       resource_size(&dpio_dev->regions[1]),
+                                       MEMREMAP_WC);
+       } else {
+               desc.regs_cena = devm_memremap(dev, dpio_dev->regions[2].start,
+                                       resource_size(&dpio_dev->regions[2]),
+                                       MEMREMAP_WB);
+       }
+
        if (IS_ERR(desc.regs_cena)) {
                dev_err(dev, "devm_memremap failed\n");
                err = PTR_ERR(desc.regs_cena);
index d020135..c66f5b7 100644 (file)
@@ -15,6 +15,8 @@
 #define QMAN_REV_4000   0x04000000
 #define QMAN_REV_4100   0x04010000
 #define QMAN_REV_4101   0x04010001
+#define QMAN_REV_5000   0x05000000
+
 #define QMAN_REV_MASK   0xffff0000
 
 /* All QBMan command and result structures use this "valid bit" encoding */
 #define QBMAN_WQCHAN_CONFIGURE 0x46
 
 /* CINH register offsets */
+#define QBMAN_CINH_SWP_EQCR_PI      0x800
 #define QBMAN_CINH_SWP_EQAR    0x8c0
+#define QBMAN_CINH_SWP_CR_RT        0x900
+#define QBMAN_CINH_SWP_VDQCR_RT     0x940
+#define QBMAN_CINH_SWP_EQCR_AM_RT   0x980
+#define QBMAN_CINH_SWP_RCR_AM_RT    0x9c0
 #define QBMAN_CINH_SWP_DQPI    0xa00
 #define QBMAN_CINH_SWP_DCAP    0xac0
 #define QBMAN_CINH_SWP_SDQCR   0xb00
+#define QBMAN_CINH_SWP_EQCR_AM_RT2  0xb40
+#define QBMAN_CINH_SWP_RCR_PI       0xc00
 #define QBMAN_CINH_SWP_RAR     0xcc0
 #define QBMAN_CINH_SWP_ISR     0xe00
 #define QBMAN_CINH_SWP_IER     0xe40
 #define QBMAN_CENA_SWP_RR(vb)  (0x700 + ((u32)(vb) >> 1))
 #define QBMAN_CENA_SWP_VDQCR   0x780
 
+/* CENA register offsets in memory-backed mode */
+#define QBMAN_CENA_SWP_DQRR_MEM(n)  (0x800 + ((u32)(n) << 6))
+#define QBMAN_CENA_SWP_RCR_MEM(n)   (0x1400 + ((u32)(n) << 6))
+#define QBMAN_CENA_SWP_CR_MEM       0x1600
+#define QBMAN_CENA_SWP_RR_MEM       0x1680
+#define QBMAN_CENA_SWP_VDQCR_MEM    0x1780
+
 /* Reverse mapping of QBMAN_CENA_SWP_DQRR() */
 #define QBMAN_IDX_FROM_DQRR(p) (((unsigned long)(p) & 0x1ff) >> 6)
 
@@ -96,10 +112,13 @@ static inline void *qbman_get_cmd(struct qbman_swp *p, u32 offset)
 
 #define SWP_CFG_DQRR_MF_SHIFT 20
 #define SWP_CFG_EST_SHIFT     16
+#define SWP_CFG_CPBS_SHIFT    15
 #define SWP_CFG_WN_SHIFT      14
 #define SWP_CFG_RPM_SHIFT     12
 #define SWP_CFG_DCM_SHIFT     10
 #define SWP_CFG_EPM_SHIFT     8
+#define SWP_CFG_VPM_SHIFT     7
+#define SWP_CFG_CPM_SHIFT     6
 #define SWP_CFG_SD_SHIFT      5
 #define SWP_CFG_SP_SHIFT      4
 #define SWP_CFG_SE_SHIFT      3
@@ -125,6 +144,8 @@ static inline u32 qbman_set_swp_cfg(u8 max_fill, u8 wn,     u8 est, u8 rpm, u8 dcm,
                ep << SWP_CFG_EP_SHIFT);
 }
 
+#define QMAN_RT_MODE      0x00000100
+
 /**
  * qbman_swp_init() - Create a functional object representing the given
  *                    QBMan portal descriptor.
@@ -146,6 +167,8 @@ struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d)
        p->sdq |= qbman_sdqcr_dct_prio_ics << QB_SDQCR_DCT_SHIFT;
        p->sdq |= qbman_sdqcr_fc_up_to_3 << QB_SDQCR_FC_SHIFT;
        p->sdq |= QMAN_SDQCR_TOKEN << QB_SDQCR_TOK_SHIFT;
+       if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000)
+               p->mr.valid_bit = QB_VALID_BIT;
 
        atomic_set(&p->vdq.available, 1);
        p->vdq.valid_bit = QB_VALID_BIT;
@@ -163,6 +186,9 @@ struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d)
        p->addr_cena = d->cena_bar;
        p->addr_cinh = d->cinh_bar;
 
+       if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000)
+               memset(p->addr_cena, 0, 64 * 1024);
+
        reg = qbman_set_swp_cfg(p->dqrr.dqrr_size,
                                1, /* Writes Non-cacheable */
                                0, /* EQCR_CI stashing threshold */
@@ -175,6 +201,10 @@ struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d)
                                1, /* dequeue stashing priority == TRUE */
                                0, /* dequeue stashing enable == FALSE */
                                0); /* EQCR_CI stashing priority == FALSE */
+       if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000)
+               reg |= 1 << SWP_CFG_CPBS_SHIFT | /* memory-backed mode */
+                      1 << SWP_CFG_VPM_SHIFT |  /* VDQCR read triggered mode */
+                      1 << SWP_CFG_CPM_SHIFT;   /* CR read triggered mode */
 
        qbman_write_register(p, QBMAN_CINH_SWP_CFG, reg);
        reg = qbman_read_register(p, QBMAN_CINH_SWP_CFG);
@@ -184,6 +214,10 @@ struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d)
                return NULL;
        }
 
+       if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000) {
+               qbman_write_register(p, QBMAN_CINH_SWP_EQCR_PI, QMAN_RT_MODE);
+               qbman_write_register(p, QBMAN_CINH_SWP_RCR_PI, QMAN_RT_MODE);
+       }
        /*
         * SDQCR needs to be initialized to 0 when no channels are
         * being dequeued from or else the QMan HW will indicate an
@@ -278,7 +312,10 @@ void qbman_swp_interrupt_set_inhibit(struct qbman_swp *p, int inhibit)
  */
 void *qbman_swp_mc_start(struct qbman_swp *p)
 {
-       return qbman_get_cmd(p, QBMAN_CENA_SWP_CR);
+       if ((p->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000)
+               return qbman_get_cmd(p, QBMAN_CENA_SWP_CR);
+       else
+               return qbman_get_cmd(p, QBMAN_CENA_SWP_CR_MEM);
 }
 
 /*
@@ -289,8 +326,14 @@ void qbman_swp_mc_submit(struct qbman_swp *p, void *cmd, u8 cmd_verb)
 {
        u8 *v = cmd;
 
-       dma_wmb();
-       *v = cmd_verb | p->mc.valid_bit;
+       if ((p->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) {
+               dma_wmb();
+               *v = cmd_verb | p->mc.valid_bit;
+       } else {
+               *v = cmd_verb | p->mc.valid_bit;
+               dma_wmb();
+               qbman_write_register(p, QBMAN_CINH_SWP_CR_RT, QMAN_RT_MODE);
+       }
 }
 
 /*
@@ -301,13 +344,27 @@ void *qbman_swp_mc_result(struct qbman_swp *p)
 {
        u32 *ret, verb;
 
-       ret = qbman_get_cmd(p, QBMAN_CENA_SWP_RR(p->mc.valid_bit));
+       if ((p->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) {
+               ret = qbman_get_cmd(p, QBMAN_CENA_SWP_RR(p->mc.valid_bit));
+               /* Remove the valid-bit - command completed if the rest
+                * is non-zero.
+                */
+               verb = ret[0] & ~QB_VALID_BIT;
+               if (!verb)
+                       return NULL;
+               p->mc.valid_bit ^= QB_VALID_BIT;
+       } else {
+               ret = qbman_get_cmd(p, QBMAN_CENA_SWP_RR_MEM);
+               /* Command completed if the valid bit is toggled */
+               if (p->mr.valid_bit != (ret[0] & QB_VALID_BIT))
+                       return NULL;
+               /* Command completed if the rest is non-zero */
+               verb = ret[0] & ~QB_VALID_BIT;
+               if (!verb)
+                       return NULL;
+               p->mr.valid_bit ^= QB_VALID_BIT;
+       }
 
-       /* Remove the valid-bit - command completed if the rest is non-zero */
-       verb = ret[0] & ~QB_VALID_BIT;
-       if (!verb)
-               return NULL;
-       p->mc.valid_bit ^= QB_VALID_BIT;
        return ret;
 }
 
@@ -384,6 +441,18 @@ void qbman_eq_desc_set_qd(struct qbman_eq_desc *d, u32 qdid,
 #define EQAR_VB(eqar)      ((eqar) & 0x80)
 #define EQAR_SUCCESS(eqar) ((eqar) & 0x100)
 
+static inline void qbman_write_eqcr_am_rt_register(struct qbman_swp *p,
+                                                  u8 idx)
+{
+       if (idx < 16)
+               qbman_write_register(p, QBMAN_CINH_SWP_EQCR_AM_RT + idx * 4,
+                                    QMAN_RT_MODE);
+       else
+               qbman_write_register(p, QBMAN_CINH_SWP_EQCR_AM_RT2 +
+                                    (idx - 16) * 4,
+                                    QMAN_RT_MODE);
+}
+
 /**
  * qbman_swp_enqueue() - Issue an enqueue command
  * @s:  the software portal used for enqueue
@@ -408,9 +477,15 @@ int qbman_swp_enqueue(struct qbman_swp *s, const struct qbman_eq_desc *d,
        memcpy(&p->dca, &d->dca, 31);
        memcpy(&p->fd, fd, sizeof(*fd));
 
-       /* Set the verb byte, have to substitute in the valid-bit */
-       dma_wmb();
-       p->verb = d->verb | EQAR_VB(eqar);
+       if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) {
+               /* Set the verb byte, have to substitute in the valid-bit */
+               dma_wmb();
+               p->verb = d->verb | EQAR_VB(eqar);
+       } else {
+               p->verb = d->verb | EQAR_VB(eqar);
+               dma_wmb();
+               qbman_write_eqcr_am_rt_register(s, EQAR_IDX(eqar));
+       }
 
        return 0;
 }
@@ -587,17 +662,27 @@ int qbman_swp_pull(struct qbman_swp *s, struct qbman_pull_desc *d)
                return -EBUSY;
        }
        s->vdq.storage = (void *)(uintptr_t)d->rsp_addr_virt;
-       p = qbman_get_cmd(s, QBMAN_CENA_SWP_VDQCR);
+       if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000)
+               p = qbman_get_cmd(s, QBMAN_CENA_SWP_VDQCR);
+       else
+               p = qbman_get_cmd(s, QBMAN_CENA_SWP_VDQCR_MEM);
        p->numf = d->numf;
        p->tok = QMAN_DQ_TOKEN_VALID;
        p->dq_src = d->dq_src;
        p->rsp_addr = d->rsp_addr;
        p->rsp_addr_virt = d->rsp_addr_virt;
-       dma_wmb();
 
-       /* Set the verb byte, have to substitute in the valid-bit */
-       p->verb = d->verb | s->vdq.valid_bit;
-       s->vdq.valid_bit ^= QB_VALID_BIT;
+       if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) {
+               dma_wmb();
+               /* Set the verb byte, have to substitute in the valid-bit */
+               p->verb = d->verb | s->vdq.valid_bit;
+               s->vdq.valid_bit ^= QB_VALID_BIT;
+       } else {
+               p->verb = d->verb | s->vdq.valid_bit;
+               s->vdq.valid_bit ^= QB_VALID_BIT;
+               dma_wmb();
+               qbman_write_register(s, QBMAN_CINH_SWP_VDQCR_RT, QMAN_RT_MODE);
+       }
 
        return 0;
 }
@@ -655,7 +740,10 @@ const struct dpaa2_dq *qbman_swp_dqrr_next(struct qbman_swp *s)
                                       QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx)));
        }
 
-       p = qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx));
+       if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000)
+               p = qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx));
+       else
+               p = qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR_MEM(s->dqrr.next_idx));
        verb = p->dq.verb;
 
        /*
@@ -807,18 +895,28 @@ int qbman_swp_release(struct qbman_swp *s, const struct qbman_release_desc *d,
                return -EBUSY;
 
        /* Start the release command */
-       p = qbman_get_cmd(s, QBMAN_CENA_SWP_RCR(RAR_IDX(rar)));
+       if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000)
+               p = qbman_get_cmd(s, QBMAN_CENA_SWP_RCR(RAR_IDX(rar)));
+       else
+               p = qbman_get_cmd(s, QBMAN_CENA_SWP_RCR_MEM(RAR_IDX(rar)));
        /* Copy the caller's buffer pointers to the command */
        for (i = 0; i < num_buffers; i++)
                p->buf[i] = cpu_to_le64(buffers[i]);
        p->bpid = d->bpid;
 
-       /*
-        * Set the verb byte, have to substitute in the valid-bit and the number
-        * of buffers.
-        */
-       dma_wmb();
-       p->verb = d->verb | RAR_VB(rar) | num_buffers;
+       if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) {
+               /*
+                * Set the verb byte, have to substitute in the valid-bit
+                * and the number of buffers.
+                */
+               dma_wmb();
+               p->verb = d->verb | RAR_VB(rar) | num_buffers;
+       } else {
+               p->verb = d->verb | RAR_VB(rar) | num_buffers;
+               dma_wmb();
+               qbman_write_register(s, QBMAN_CINH_SWP_RCR_AM_RT +
+                                    RAR_IDX(rar)  * 4, QMAN_RT_MODE);
+       }
 
        return 0;
 }
index fa35fc1..f3ec5d2 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
 /*
  * Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
- * Copyright 2016 NXP
+ * Copyright 2016-2019 NXP
  *
  */
 #ifndef __FSL_QBMAN_PORTAL_H
@@ -110,6 +110,11 @@ struct qbman_swp {
                u32 valid_bit; /* 0x00 or 0x80 */
        } mc;
 
+       /* Management response */
+       struct {
+               u32 valid_bit; /* 0x00 or 0x80 */
+       } mr;
+
        /* Push dequeues */
        u32 sdq;
 
@@ -428,7 +433,7 @@ static inline int qbman_swp_CDAN_set_context_enable(struct qbman_swp *s,
 static inline void *qbman_swp_mc_complete(struct qbman_swp *swp, void *cmd,
                                          u8 cmd_verb)
 {
-       int loopvar = 1000;
+       int loopvar = 2000;
 
        qbman_swp_mc_submit(swp, cmd, cmd_verb);
 
index 78607da..1ef8068 100644 (file)
@@ -97,6 +97,11 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = {
          .svr          = 0x87000000,
          .mask         = 0xfff70000,
        },
+       /* Die: LX2160A, SoC: LX2160A/LX2120A/LX2080A */
+       { .die          = "LX2160A",
+         .svr          = 0x87360000,
+         .mask         = 0xff3f0000,
+       },
        { },
 };
 
@@ -218,6 +223,7 @@ static const struct of_device_id fsl_guts_of_match[] = {
        { .compatible = "fsl,ls1088a-dcfg", },
        { .compatible = "fsl,ls1012a-dcfg", },
        { .compatible = "fsl,ls1046a-dcfg", },
+       { .compatible = "fsl,lx2160a-dcfg", },
        {}
 };
 MODULE_DEVICE_TABLE(of, fsl_guts_of_match);
index 2c95cf5..cf4f10d 100644 (file)
@@ -32,6 +32,7 @@
 
 static struct bman_portal *affine_bportals[NR_CPUS];
 static struct cpumask portal_cpus;
+static int __bman_portals_probed;
 /* protect bman global registers and global data shared among portals */
 static DEFINE_SPINLOCK(bman_lock);
 
@@ -87,6 +88,12 @@ static int bman_online_cpu(unsigned int cpu)
        return 0;
 }
 
+int bman_portals_probed(void)
+{
+       return __bman_portals_probed;
+}
+EXPORT_SYMBOL_GPL(bman_portals_probed);
+
 static int bman_portal_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -104,8 +111,10 @@ static int bman_portal_probe(struct platform_device *pdev)
        }
 
        pcfg = devm_kmalloc(dev, sizeof(*pcfg), GFP_KERNEL);
-       if (!pcfg)
+       if (!pcfg) {
+               __bman_portals_probed = -1;
                return -ENOMEM;
+       }
 
        pcfg->dev = dev;
 
@@ -113,14 +122,14 @@ static int bman_portal_probe(struct platform_device *pdev)
                                             DPAA_PORTAL_CE);
        if (!addr_phys[0]) {
                dev_err(dev, "Can't get %pOF property 'reg::CE'\n", node);
-               return -ENXIO;
+               goto err_ioremap1;
        }
 
        addr_phys[1] = platform_get_resource(pdev, IORESOURCE_MEM,
                                             DPAA_PORTAL_CI);
        if (!addr_phys[1]) {
                dev_err(dev, "Can't get %pOF property 'reg::CI'\n", node);
-               return -ENXIO;
+               goto err_ioremap1;
        }
 
        pcfg->cpu = -1;
@@ -128,7 +137,7 @@ static int bman_portal_probe(struct platform_device *pdev)
        irq = platform_get_irq(pdev, 0);
        if (irq <= 0) {
                dev_err(dev, "Can't get %pOF IRQ'\n", node);
-               return -ENXIO;
+               goto err_ioremap1;
        }
        pcfg->irq = irq;
 
@@ -150,6 +159,7 @@ static int bman_portal_probe(struct platform_device *pdev)
        spin_lock(&bman_lock);
        cpu = cpumask_next_zero(-1, &portal_cpus);
        if (cpu >= nr_cpu_ids) {
+               __bman_portals_probed = 1;
                /* unassigned portal, skip init */
                spin_unlock(&bman_lock);
                return 0;
@@ -175,6 +185,8 @@ err_portal_init:
 err_ioremap2:
        memunmap(pcfg->addr_virt_ce);
 err_ioremap1:
+        __bman_portals_probed = -1;
+
        return -ENXIO;
 }
 
index 109b38d..a6bb430 100644 (file)
@@ -596,7 +596,7 @@ static int qman_init_ccsr(struct device *dev)
 }
 
 #define LIO_CFG_LIODN_MASK 0x0fff0000
-void qman_liodn_fixup(u16 channel)
+void __qman_liodn_fixup(u16 channel)
 {
        static int done;
        static u32 liodn_offset;
index 661c9b2..e2186b6 100644 (file)
@@ -38,6 +38,7 @@ EXPORT_SYMBOL(qman_dma_portal);
 #define CONFIG_FSL_DPA_PIRQ_FAST  1
 
 static struct cpumask portal_cpus;
+static int __qman_portals_probed;
 /* protect qman global registers and global data shared among portals */
 static DEFINE_SPINLOCK(qman_lock);
 
@@ -220,6 +221,12 @@ static int qman_online_cpu(unsigned int cpu)
        return 0;
 }
 
+int qman_portals_probed(void)
+{
+       return __qman_portals_probed;
+}
+EXPORT_SYMBOL_GPL(qman_portals_probed);
+
 static int qman_portal_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -238,8 +245,10 @@ static int qman_portal_probe(struct platform_device *pdev)
        }
 
        pcfg = devm_kmalloc(dev, sizeof(*pcfg), GFP_KERNEL);
-       if (!pcfg)
+       if (!pcfg) {
+               __qman_portals_probed = -1;
                return -ENOMEM;
+       }
 
        pcfg->dev = dev;
 
@@ -247,19 +256,20 @@ static int qman_portal_probe(struct platform_device *pdev)
                                             DPAA_PORTAL_CE);
        if (!addr_phys[0]) {
                dev_err(dev, "Can't get %pOF property 'reg::CE'\n", node);
-               return -ENXIO;
+               goto err_ioremap1;
        }
 
        addr_phys[1] = platform_get_resource(pdev, IORESOURCE_MEM,
                                             DPAA_PORTAL_CI);
        if (!addr_phys[1]) {
                dev_err(dev, "Can't get %pOF property 'reg::CI'\n", node);
-               return -ENXIO;
+               goto err_ioremap1;
        }
 
        err = of_property_read_u32(node, "cell-index", &val);
        if (err) {
                dev_err(dev, "Can't get %pOF property 'cell-index'\n", node);
+               __qman_portals_probed = -1;
                return err;
        }
        pcfg->channel = val;
@@ -267,7 +277,7 @@ static int qman_portal_probe(struct platform_device *pdev)
        irq = platform_get_irq(pdev, 0);
        if (irq <= 0) {
                dev_err(dev, "Can't get %pOF IRQ\n", node);
-               return -ENXIO;
+               goto err_ioremap1;
        }
        pcfg->irq = irq;
 
@@ -291,6 +301,7 @@ static int qman_portal_probe(struct platform_device *pdev)
        spin_lock(&qman_lock);
        cpu = cpumask_next_zero(-1, &portal_cpus);
        if (cpu >= nr_cpu_ids) {
+               __qman_portals_probed = 1;
                /* unassigned portal, skip init */
                spin_unlock(&qman_lock);
                return 0;
@@ -321,6 +332,8 @@ err_portal_init:
 err_ioremap2:
        memunmap(pcfg->addr_virt_ce);
 err_ioremap1:
+       __qman_portals_probed = -1;
+
        return -ENXIO;
 }
 
index 75a8f90..0451571 100644 (file)
@@ -193,7 +193,14 @@ extern struct gen_pool *qm_cgralloc; /* CGR ID allocator */
 u32 qm_get_pools_sdqcr(void);
 
 int qman_wq_alloc(void);
-void qman_liodn_fixup(u16 channel);
+#ifdef CONFIG_FSL_PAMU
+#define qman_liodn_fixup __qman_liodn_fixup
+#else
+static inline void qman_liodn_fixup(u16 channel)
+{
+}
+#endif
+void __qman_liodn_fixup(u16 channel);
 void qman_set_sdest(u16 channel, unsigned int cpu_idx);
 
 struct qman_portal *qman_create_affine_portal(
index ade1b46..8aaebf1 100644 (file)
@@ -8,4 +8,13 @@ config IMX_GPCV2_PM_DOMAINS
        select PM_GENERIC_DOMAINS
        default y if SOC_IMX7D
 
+config IMX_SCU_SOC
+       bool "i.MX System Controller Unit SoC info support"
+       depends on IMX_SCU
+       select SOC_BUS
+       help
+         If you say yes here you get support for the NXP i.MX System
+         Controller Unit SoC info module, it will provide the SoC info
+         like SoC family, ID and revision etc.
+
 endmenu
index caa8653..cf9ca42 100644 (file)
@@ -2,3 +2,4 @@
 obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
 obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o
 obj-$(CONFIG_ARCH_MXC) += soc-imx8.o
+obj-$(CONFIG_IMX_SCU_SOC) += soc-imx-scu.o
diff --git a/drivers/soc/imx/soc-imx-scu.c b/drivers/soc/imx/soc-imx-scu.c
new file mode 100644 (file)
index 0000000..676f612
--- /dev/null
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <dt-bindings/firmware/imx/rsrc.h>
+#include <linux/firmware/imx/sci.h>
+#include <linux/slab.h>
+#include <linux/sys_soc.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+
+#define IMX_SCU_SOC_DRIVER_NAME                "imx-scu-soc"
+
+static struct imx_sc_ipc *soc_ipc_handle;
+
+struct imx_sc_msg_misc_get_soc_id {
+       struct imx_sc_rpc_msg hdr;
+       union {
+               struct {
+                       u32 control;
+                       u16 resource;
+               } __packed req;
+               struct {
+                       u32 id;
+               } resp;
+       } data;
+} __packed;
+
+static int imx_scu_soc_id(void)
+{
+       struct imx_sc_msg_misc_get_soc_id msg;
+       struct imx_sc_rpc_msg *hdr = &msg.hdr;
+       int ret;
+
+       hdr->ver = IMX_SC_RPC_VERSION;
+       hdr->svc = IMX_SC_RPC_SVC_MISC;
+       hdr->func = IMX_SC_MISC_FUNC_GET_CONTROL;
+       hdr->size = 3;
+
+       msg.data.req.control = IMX_SC_C_ID;
+       msg.data.req.resource = IMX_SC_R_SYSTEM;
+
+       ret = imx_scu_call_rpc(soc_ipc_handle, &msg, true);
+       if (ret) {
+               pr_err("%s: get soc info failed, ret %d\n", __func__, ret);
+               return ret;
+       }
+
+       return msg.data.resp.id;
+}
+
+static int imx_scu_soc_probe(struct platform_device *pdev)
+{
+       struct soc_device_attribute *soc_dev_attr;
+       struct soc_device *soc_dev;
+       int id, ret;
+       u32 val;
+
+       ret = imx_scu_get_handle(&soc_ipc_handle);
+       if (ret)
+               return ret;
+
+       soc_dev_attr = devm_kzalloc(&pdev->dev, sizeof(*soc_dev_attr),
+                                   GFP_KERNEL);
+       if (!soc_dev_attr)
+               return -ENOMEM;
+
+       soc_dev_attr->family = "Freescale i.MX";
+
+       ret = of_property_read_string(of_root,
+                                     "model",
+                                     &soc_dev_attr->machine);
+       if (ret)
+               return ret;
+
+       id = imx_scu_soc_id();
+       if (id < 0)
+               return -EINVAL;
+
+       /* format soc_id value passed from SCU firmware */
+       val = id & 0x1f;
+       soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "0x%x", val);
+       if (!soc_dev_attr->soc_id)
+               return -ENOMEM;
+
+       /* format revision value passed from SCU firmware */
+       val = (id >> 5) & 0xf;
+       val = (((val >> 2) + 1) << 4) | (val & 0x3);
+       soc_dev_attr->revision = kasprintf(GFP_KERNEL,
+                                          "%d.%d",
+                                          (val >> 4) & 0xf,
+                                          val & 0xf);
+       if (!soc_dev_attr->revision) {
+               ret = -ENOMEM;
+               goto free_soc_id;
+       }
+
+       soc_dev = soc_device_register(soc_dev_attr);
+       if (IS_ERR(soc_dev)) {
+               ret = PTR_ERR(soc_dev);
+               goto free_revision;
+       }
+
+       return 0;
+
+free_revision:
+       kfree(soc_dev_attr->revision);
+free_soc_id:
+       kfree(soc_dev_attr->soc_id);
+       return ret;
+}
+
+static struct platform_driver imx_scu_soc_driver = {
+       .driver = {
+               .name = IMX_SCU_SOC_DRIVER_NAME,
+       },
+       .probe = imx_scu_soc_probe,
+};
+
+static int __init imx_scu_soc_init(void)
+{
+       struct platform_device *pdev;
+       struct device_node *np;
+       int ret;
+
+       np = of_find_compatible_node(NULL, NULL, "fsl,imx-scu");
+       if (!np)
+               return -ENODEV;
+
+       of_node_put(np);
+
+       ret = platform_driver_register(&imx_scu_soc_driver);
+       if (ret)
+               return ret;
+
+       pdev = platform_device_register_simple(IMX_SCU_SOC_DRIVER_NAME,
+                                              -1, NULL, 0);
+       if (IS_ERR(pdev))
+               platform_driver_unregister(&imx_scu_soc_driver);
+
+       return PTR_ERR_OR_ZERO(pdev);
+}
+device_initcall(imx_scu_soc_init);
index b1bd8e2..f924ae8 100644 (file)
@@ -16,6 +16,9 @@
 #define IMX8MQ_SW_INFO_B1              0x40
 #define IMX8MQ_SW_MAGIC_B1             0xff0055aa
 
+/* Same as ANADIG_DIGPROG_IMX7D */
+#define ANADIG_DIGPROG_IMX8MM  0x800
+
 struct imx8_soc_data {
        char *name;
        u32 (*soc_revision)(void);
@@ -46,13 +49,45 @@ out:
        return rev;
 }
 
+static u32 __init imx8mm_soc_revision(void)
+{
+       struct device_node *np;
+       void __iomem *anatop_base;
+       u32 rev;
+
+       np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-anatop");
+       if (!np)
+               return 0;
+
+       anatop_base = of_iomap(np, 0);
+       WARN_ON(!anatop_base);
+
+       rev = readl_relaxed(anatop_base + ANADIG_DIGPROG_IMX8MM);
+
+       iounmap(anatop_base);
+       of_node_put(np);
+       return rev;
+}
+
 static const struct imx8_soc_data imx8mq_soc_data = {
        .name = "i.MX8MQ",
        .soc_revision = imx8mq_soc_revision,
 };
 
+static const struct imx8_soc_data imx8mm_soc_data = {
+       .name = "i.MX8MM",
+       .soc_revision = imx8mm_soc_revision,
+};
+
+static const struct imx8_soc_data imx8mn_soc_data = {
+       .name = "i.MX8MN",
+       .soc_revision = imx8mm_soc_revision,
+};
+
 static const struct of_device_id imx8_soc_match[] = {
        { .compatible = "fsl,imx8mq", .data = &imx8mq_soc_data, },
+       { .compatible = "fsl,imx8mm", .data = &imx8mm_soc_data, },
+       { .compatible = "fsl,imx8mn", .data = &imx8mn_soc_data, },
        { }
 };
 
@@ -65,7 +100,6 @@ static int __init imx8_soc_init(void)
 {
        struct soc_device_attribute *soc_dev_attr;
        struct soc_device *soc_dev;
-       struct device_node *root;
        const struct of_device_id *id;
        u32 soc_rev = 0;
        const struct imx8_soc_data *data;
@@ -73,20 +107,19 @@ static int __init imx8_soc_init(void)
 
        soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
        if (!soc_dev_attr)
-               return -ENODEV;
+               return -ENOMEM;
 
        soc_dev_attr->family = "Freescale i.MX";
 
-       root = of_find_node_by_path("/");
-       ret = of_property_read_string(root, "model", &soc_dev_attr->machine);
+       ret = of_property_read_string(of_root, "model", &soc_dev_attr->machine);
        if (ret)
                goto free_soc;
 
-       id = of_match_node(imx8_soc_match, root);
-       if (!id)
+       id = of_match_node(imx8_soc_match, of_root);
+       if (!id) {
+               ret = -ENODEV;
                goto free_soc;
-
-       of_node_put(root);
+       }
 
        data = id->data;
        if (data) {
@@ -96,12 +129,16 @@ static int __init imx8_soc_init(void)
        }
 
        soc_dev_attr->revision = imx8_revision(soc_rev);
-       if (!soc_dev_attr->revision)
+       if (!soc_dev_attr->revision) {
+               ret = -ENOMEM;
                goto free_soc;
+       }
 
        soc_dev = soc_device_register(soc_dev_attr);
-       if (IS_ERR(soc_dev))
+       if (IS_ERR(soc_dev)) {
+               ret = PTR_ERR(soc_dev);
                goto free_rev;
+       }
 
        if (IS_ENABLED(CONFIG_ARM_IMX_CPUFREQ_DT))
                platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0);
@@ -109,10 +146,10 @@ static int __init imx8_soc_init(void)
        return 0;
 
 free_rev:
-       kfree(soc_dev_attr->revision);
+       if (strcmp(soc_dev_attr->revision, "unknown"))
+               kfree(soc_dev_attr->revision);
 free_soc:
        kfree(soc_dev_attr);
-       of_node_put(root);
-       return -ENODEV;
+       return ret;
 }
 device_initcall(imx8_soc_init);
index 880cf02..a6d1bfb 100644 (file)
@@ -4,6 +4,18 @@
 #
 menu "Qualcomm SoC drivers"
 
+config QCOM_AOSS_QMP
+       tristate "Qualcomm AOSS Driver"
+       depends on ARCH_QCOM || COMPILE_TEST
+       depends on MAILBOX
+       depends on COMMON_CLK && PM
+       select PM_GENERIC_DOMAINS
+       help
+         This driver provides the means of communicating with and controlling
+         the low-power state for resources related to the remoteproc
+         subsystems as well as controlling the debug clocks exposed by the Always On
+         Subsystem (AOSS) using Qualcomm Messaging Protocol (QMP).
+
 config QCOM_COMMAND_DB
        bool "Qualcomm Command DB"
        depends on ARCH_QCOM || COMPILE_TEST
index ffe519b..eeb088b 100644 (file)
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 CFLAGS_rpmh-rsc.o := -I$(src)
+obj-$(CONFIG_QCOM_AOSS_QMP) += qcom_aoss.o
 obj-$(CONFIG_QCOM_GENI_SE) +=  qcom-geni-se.o
 obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o
 obj-$(CONFIG_QCOM_GLINK_SSR) +=        glink_ssr.o
index 74f8b96..4fcc324 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/spinlock.h>
 #include <linux/idr.h>
 #include <linux/slab.h>
+#include <linux/workqueue.h>
 #include <linux/of_device.h>
 #include <linux/soc/qcom/apr.h>
 #include <linux/rpmsg.h>
@@ -17,8 +18,18 @@ struct apr {
        struct rpmsg_endpoint *ch;
        struct device *dev;
        spinlock_t svcs_lock;
+       spinlock_t rx_lock;
        struct idr svcs_idr;
        int dest_domain_id;
+       struct workqueue_struct *rxwq;
+       struct work_struct rx_work;
+       struct list_head rx_list;
+};
+
+struct apr_rx_buf {
+       struct list_head node;
+       int len;
+       uint8_t buf[];
 };
 
 /**
@@ -62,11 +73,7 @@ static int apr_callback(struct rpmsg_device *rpdev, void *buf,
                                  int len, void *priv, u32 addr)
 {
        struct apr *apr = dev_get_drvdata(&rpdev->dev);
-       uint16_t hdr_size, msg_type, ver, svc_id;
-       struct apr_device *svc = NULL;
-       struct apr_driver *adrv = NULL;
-       struct apr_resp_pkt resp;
-       struct apr_hdr *hdr;
+       struct apr_rx_buf *abuf;
        unsigned long flags;
 
        if (len <= APR_HDR_SIZE) {
@@ -75,6 +82,34 @@ static int apr_callback(struct rpmsg_device *rpdev, void *buf,
                return -EINVAL;
        }
 
+       abuf = kzalloc(sizeof(*abuf) + len, GFP_ATOMIC);
+       if (!abuf)
+               return -ENOMEM;
+
+       abuf->len = len;
+       memcpy(abuf->buf, buf, len);
+
+       spin_lock_irqsave(&apr->rx_lock, flags);
+       list_add_tail(&abuf->node, &apr->rx_list);
+       spin_unlock_irqrestore(&apr->rx_lock, flags);
+
+       queue_work(apr->rxwq, &apr->rx_work);
+
+       return 0;
+}
+
+
+static int apr_do_rx_callback(struct apr *apr, struct apr_rx_buf *abuf)
+{
+       uint16_t hdr_size, msg_type, ver, svc_id;
+       struct apr_device *svc = NULL;
+       struct apr_driver *adrv = NULL;
+       struct apr_resp_pkt resp;
+       struct apr_hdr *hdr;
+       unsigned long flags;
+       void *buf = abuf->buf;
+       int len = abuf->len;
+
        hdr = buf;
        ver = APR_HDR_FIELD_VER(hdr->hdr_field);
        if (ver > APR_PKT_VER + 1)
@@ -132,6 +167,23 @@ static int apr_callback(struct rpmsg_device *rpdev, void *buf,
        return 0;
 }
 
+static void apr_rxwq(struct work_struct *work)
+{
+       struct apr *apr = container_of(work, struct apr, rx_work);
+       struct apr_rx_buf *abuf, *b;
+       unsigned long flags;
+
+       if (!list_empty(&apr->rx_list)) {
+               list_for_each_entry_safe(abuf, b, &apr->rx_list, node) {
+                       apr_do_rx_callback(apr, abuf);
+                       spin_lock_irqsave(&apr->rx_lock, flags);
+                       list_del(&abuf->node);
+                       spin_unlock_irqrestore(&apr->rx_lock, flags);
+                       kfree(abuf);
+               }
+       }
+}
+
 static int apr_device_match(struct device *dev, struct device_driver *drv)
 {
        struct apr_device *adev = to_apr_device(dev);
@@ -276,7 +328,7 @@ static int apr_probe(struct rpmsg_device *rpdev)
        if (!apr)
                return -ENOMEM;
 
-       ret = of_property_read_u32(dev->of_node, "reg", &apr->dest_domain_id);
+       ret = of_property_read_u32(dev->of_node, "qcom,apr-domain", &apr->dest_domain_id);
        if (ret) {
                dev_err(dev, "APR Domain ID not specified in DT\n");
                return ret;
@@ -285,6 +337,14 @@ static int apr_probe(struct rpmsg_device *rpdev)
        dev_set_drvdata(dev, apr);
        apr->ch = rpdev->ept;
        apr->dev = dev;
+       apr->rxwq = create_singlethread_workqueue("qcom_apr_rx");
+       if (!apr->rxwq) {
+               dev_err(apr->dev, "Failed to start Rx WQ\n");
+               return -ENOMEM;
+       }
+       INIT_WORK(&apr->rx_work, apr_rxwq);
+       INIT_LIST_HEAD(&apr->rx_list);
+       spin_lock_init(&apr->rx_lock);
        spin_lock_init(&apr->svcs_lock);
        idr_init(&apr->svcs_idr);
        of_register_apr_devices(dev);
@@ -303,7 +363,11 @@ static int apr_remove_device(struct device *dev, void *null)
 
 static void apr_remove(struct rpmsg_device *rpdev)
 {
+       struct apr *apr = dev_get_drvdata(&rpdev->dev);
+
        device_for_each_child(&rpdev->dev, NULL, apr_remove_device);
+       flush_workqueue(apr->rxwq);
+       destroy_workqueue(apr->rxwq);
 }
 
 /*
index 9ca7d94..24cd193 100644 (file)
@@ -66,6 +66,66 @@ ssize_t qcom_mdt_get_size(const struct firmware *fw)
 }
 EXPORT_SYMBOL_GPL(qcom_mdt_get_size);
 
+/**
+ * qcom_mdt_read_metadata() - read header and metadata from mdt or mbn
+ * @fw:                firmware of mdt header or mbn
+ * @data_len:  length of the read metadata blob
+ *
+ * The mechanism that performs the authentication of the loading firmware
+ * expects an ELF header directly followed by the segment of hashes, with no
+ * padding inbetween. This function allocates a chunk of memory for this pair
+ * and copy the two pieces into the buffer.
+ *
+ * In the case of split firmware the hash is found directly following the ELF
+ * header, rather than at p_offset described by the second program header.
+ *
+ * The caller is responsible to free (kfree()) the returned pointer.
+ *
+ * Return: pointer to data, or ERR_PTR()
+ */
+void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len)
+{
+       const struct elf32_phdr *phdrs;
+       const struct elf32_hdr *ehdr;
+       size_t hash_offset;
+       size_t hash_size;
+       size_t ehdr_size;
+       void *data;
+
+       ehdr = (struct elf32_hdr *)fw->data;
+       phdrs = (struct elf32_phdr *)(ehdr + 1);
+
+       if (ehdr->e_phnum < 2)
+               return ERR_PTR(-EINVAL);
+
+       if (phdrs[0].p_type == PT_LOAD || phdrs[1].p_type == PT_LOAD)
+               return ERR_PTR(-EINVAL);
+
+       if ((phdrs[1].p_flags & QCOM_MDT_TYPE_MASK) != QCOM_MDT_TYPE_HASH)
+               return ERR_PTR(-EINVAL);
+
+       ehdr_size = phdrs[0].p_filesz;
+       hash_size = phdrs[1].p_filesz;
+
+       data = kmalloc(ehdr_size + hash_size, GFP_KERNEL);
+       if (!data)
+               return ERR_PTR(-ENOMEM);
+
+       /* Is the header and hash already packed */
+       if (ehdr_size + hash_size == fw->size)
+               hash_offset = phdrs[0].p_filesz;
+       else
+               hash_offset = phdrs[1].p_offset;
+
+       memcpy(data, fw->data, ehdr_size);
+       memcpy(data + ehdr_size, fw->data + hash_offset, hash_size);
+
+       *data_len = ehdr_size + hash_size;
+
+       return data;
+}
+EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata);
+
 static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
                           const char *firmware, int pas_id, void *mem_region,
                           phys_addr_t mem_phys, size_t mem_size,
@@ -78,12 +138,14 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
        phys_addr_t mem_reloc;
        phys_addr_t min_addr = PHYS_ADDR_MAX;
        phys_addr_t max_addr = 0;
+       size_t metadata_len;
        size_t fw_name_len;
        ssize_t offset;
+       void *metadata;
        char *fw_name;
        bool relocate = false;
        void *ptr;
-       int ret;
+       int ret = 0;
        int i;
 
        if (!fw || !mem_region || !mem_phys || !mem_size)
@@ -101,7 +163,15 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
                return -ENOMEM;
 
        if (pas_init) {
-               ret = qcom_scm_pas_init_image(pas_id, fw->data, fw->size);
+               metadata = qcom_mdt_read_metadata(fw, &metadata_len);
+               if (IS_ERR(metadata)) {
+                       ret = PTR_ERR(metadata);
+                       goto out;
+               }
+
+               ret = qcom_scm_pas_init_image(pas_id, metadata, metadata_len);
+
+               kfree(metadata);
                if (ret) {
                        dev_err(dev, "invalid firmware metadata\n");
                        goto out;
@@ -162,7 +232,19 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
 
                ptr = mem_region + offset;
 
-               if (phdr->p_filesz) {
+               if (phdr->p_filesz && phdr->p_offset < fw->size) {
+                       /* Firmware is large enough to be non-split */
+                       if (phdr->p_offset + phdr->p_filesz > fw->size) {
+                               dev_err(dev,
+                                       "failed to load segment %d from truncated file %s\n",
+                                       i, firmware);
+                               ret = -EINVAL;
+                               break;
+                       }
+
+                       memcpy(ptr, fw->data + phdr->p_offset, phdr->p_filesz);
+               } else if (phdr->p_filesz) {
+                       /* Firmware not large enough, load split-out segments */
                        sprintf(fw_name + fw_name_len - 3, "b%02d", i);
                        ret = request_firmware_into_buf(&seg_fw, fw_name, dev,
                                                        ptr, phdr->p_filesz);
diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c
new file mode 100644 (file)
index 0000000..5f88519
--- /dev/null
@@ -0,0 +1,480 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019, Linaro Ltd
+ */
+#include <dt-bindings/power/qcom-aoss-qmp.h>
+#include <linux/clk-provider.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mailbox_client.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+
+#define QMP_DESC_MAGIC                 0x0
+#define QMP_DESC_VERSION               0x4
+#define QMP_DESC_FEATURES              0x8
+
+/* AOP-side offsets */
+#define QMP_DESC_UCORE_LINK_STATE      0xc
+#define QMP_DESC_UCORE_LINK_STATE_ACK  0x10
+#define QMP_DESC_UCORE_CH_STATE                0x14
+#define QMP_DESC_UCORE_CH_STATE_ACK    0x18
+#define QMP_DESC_UCORE_MBOX_SIZE       0x1c
+#define QMP_DESC_UCORE_MBOX_OFFSET     0x20
+
+/* Linux-side offsets */
+#define QMP_DESC_MCORE_LINK_STATE      0x24
+#define QMP_DESC_MCORE_LINK_STATE_ACK  0x28
+#define QMP_DESC_MCORE_CH_STATE                0x2c
+#define QMP_DESC_MCORE_CH_STATE_ACK    0x30
+#define QMP_DESC_MCORE_MBOX_SIZE       0x34
+#define QMP_DESC_MCORE_MBOX_OFFSET     0x38
+
+#define QMP_STATE_UP                   GENMASK(15, 0)
+#define QMP_STATE_DOWN                 GENMASK(31, 16)
+
+#define QMP_MAGIC                      0x4d41494c /* mail */
+#define QMP_VERSION                    1
+
+/* 64 bytes is enough to store the requests and provides padding to 4 bytes */
+#define QMP_MSG_LEN                    64
+
+/**
+ * struct qmp - driver state for QMP implementation
+ * @msgram: iomem referencing the message RAM used for communication
+ * @dev: reference to QMP device
+ * @mbox_client: mailbox client used to ring the doorbell on transmit
+ * @mbox_chan: mailbox channel used to ring the doorbell on transmit
+ * @offset: offset within @msgram where messages should be written
+ * @size: maximum size of the messages to be transmitted
+ * @event: wait_queue for synchronization with the IRQ
+ * @tx_lock: provides synchronization between multiple callers of qmp_send()
+ * @qdss_clk: QDSS clock hw struct
+ * @pd_data: genpd data
+ */
+struct qmp {
+       void __iomem *msgram;
+       struct device *dev;
+
+       struct mbox_client mbox_client;
+       struct mbox_chan *mbox_chan;
+
+       size_t offset;
+       size_t size;
+
+       wait_queue_head_t event;
+
+       struct mutex tx_lock;
+
+       struct clk_hw qdss_clk;
+       struct genpd_onecell_data pd_data;
+};
+
+struct qmp_pd {
+       struct qmp *qmp;
+       struct generic_pm_domain pd;
+};
+
+#define to_qmp_pd_resource(res) container_of(res, struct qmp_pd, pd)
+
+static void qmp_kick(struct qmp *qmp)
+{
+       mbox_send_message(qmp->mbox_chan, NULL);
+       mbox_client_txdone(qmp->mbox_chan, 0);
+}
+
+static bool qmp_magic_valid(struct qmp *qmp)
+{
+       return readl(qmp->msgram + QMP_DESC_MAGIC) == QMP_MAGIC;
+}
+
+static bool qmp_link_acked(struct qmp *qmp)
+{
+       return readl(qmp->msgram + QMP_DESC_MCORE_LINK_STATE_ACK) == QMP_STATE_UP;
+}
+
+static bool qmp_mcore_channel_acked(struct qmp *qmp)
+{
+       return readl(qmp->msgram + QMP_DESC_MCORE_CH_STATE_ACK) == QMP_STATE_UP;
+}
+
+static bool qmp_ucore_channel_up(struct qmp *qmp)
+{
+       return readl(qmp->msgram + QMP_DESC_UCORE_CH_STATE) == QMP_STATE_UP;
+}
+
+static int qmp_open(struct qmp *qmp)
+{
+       int ret;
+       u32 val;
+
+       if (!qmp_magic_valid(qmp)) {
+               dev_err(qmp->dev, "QMP magic doesn't match\n");
+               return -EINVAL;
+       }
+
+       val = readl(qmp->msgram + QMP_DESC_VERSION);
+       if (val != QMP_VERSION) {
+               dev_err(qmp->dev, "unsupported QMP version %d\n", val);
+               return -EINVAL;
+       }
+
+       qmp->offset = readl(qmp->msgram + QMP_DESC_MCORE_MBOX_OFFSET);
+       qmp->size = readl(qmp->msgram + QMP_DESC_MCORE_MBOX_SIZE);
+       if (!qmp->size) {
+               dev_err(qmp->dev, "invalid mailbox size\n");
+               return -EINVAL;
+       }
+
+       /* Ack remote core's link state */
+       val = readl(qmp->msgram + QMP_DESC_UCORE_LINK_STATE);
+       writel(val, qmp->msgram + QMP_DESC_UCORE_LINK_STATE_ACK);
+
+       /* Set local core's link state to up */
+       writel(QMP_STATE_UP, qmp->msgram + QMP_DESC_MCORE_LINK_STATE);
+
+       qmp_kick(qmp);
+
+       ret = wait_event_timeout(qmp->event, qmp_link_acked(qmp), HZ);
+       if (!ret) {
+               dev_err(qmp->dev, "ucore didn't ack link\n");
+               goto timeout_close_link;
+       }
+
+       writel(QMP_STATE_UP, qmp->msgram + QMP_DESC_MCORE_CH_STATE);
+
+       qmp_kick(qmp);
+
+       ret = wait_event_timeout(qmp->event, qmp_ucore_channel_up(qmp), HZ);
+       if (!ret) {
+               dev_err(qmp->dev, "ucore didn't open channel\n");
+               goto timeout_close_channel;
+       }
+
+       /* Ack remote core's channel state */
+       writel(QMP_STATE_UP, qmp->msgram + QMP_DESC_UCORE_CH_STATE_ACK);
+
+       qmp_kick(qmp);
+
+       ret = wait_event_timeout(qmp->event, qmp_mcore_channel_acked(qmp), HZ);
+       if (!ret) {
+               dev_err(qmp->dev, "ucore didn't ack channel\n");
+               goto timeout_close_channel;
+       }
+
+       return 0;
+
+timeout_close_channel:
+       writel(QMP_STATE_DOWN, qmp->msgram + QMP_DESC_MCORE_CH_STATE);
+
+timeout_close_link:
+       writel(QMP_STATE_DOWN, qmp->msgram + QMP_DESC_MCORE_LINK_STATE);
+       qmp_kick(qmp);
+
+       return -ETIMEDOUT;
+}
+
+static void qmp_close(struct qmp *qmp)
+{
+       writel(QMP_STATE_DOWN, qmp->msgram + QMP_DESC_MCORE_CH_STATE);
+       writel(QMP_STATE_DOWN, qmp->msgram + QMP_DESC_MCORE_LINK_STATE);
+       qmp_kick(qmp);
+}
+
+static irqreturn_t qmp_intr(int irq, void *data)
+{
+       struct qmp *qmp = data;
+
+       wake_up_interruptible_all(&qmp->event);
+
+       return IRQ_HANDLED;
+}
+
+static bool qmp_message_empty(struct qmp *qmp)
+{
+       return readl(qmp->msgram + qmp->offset) == 0;
+}
+
+/**
+ * qmp_send() - send a message to the AOSS
+ * @qmp: qmp context
+ * @data: message to be sent
+ * @len: length of the message
+ *
+ * Transmit @data to AOSS and wait for the AOSS to acknowledge the message.
+ * @len must be a multiple of 4 and not longer than the mailbox size. Access is
+ * synchronized by this implementation.
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+static int qmp_send(struct qmp *qmp, const void *data, size_t len)
+{
+       long time_left;
+       int ret;
+
+       if (WARN_ON(len + sizeof(u32) > qmp->size))
+               return -EINVAL;
+
+       if (WARN_ON(len % sizeof(u32)))
+               return -EINVAL;
+
+       mutex_lock(&qmp->tx_lock);
+
+       /* The message RAM only implements 32-bit accesses */
+       __iowrite32_copy(qmp->msgram + qmp->offset + sizeof(u32),
+                        data, len / sizeof(u32));
+       writel(len, qmp->msgram + qmp->offset);
+       qmp_kick(qmp);
+
+       time_left = wait_event_interruptible_timeout(qmp->event,
+                                                    qmp_message_empty(qmp), HZ);
+       if (!time_left) {
+               dev_err(qmp->dev, "ucore did not ack channel\n");
+               ret = -ETIMEDOUT;
+
+               /* Clear message from buffer */
+               writel(0, qmp->msgram + qmp->offset);
+       } else {
+               ret = 0;
+       }
+
+       mutex_unlock(&qmp->tx_lock);
+
+       return ret;
+}
+
+static int qmp_qdss_clk_prepare(struct clk_hw *hw)
+{
+       static const char buf[QMP_MSG_LEN] = "{class: clock, res: qdss, val: 1}";
+       struct qmp *qmp = container_of(hw, struct qmp, qdss_clk);
+
+       return qmp_send(qmp, buf, sizeof(buf));
+}
+
+static void qmp_qdss_clk_unprepare(struct clk_hw *hw)
+{
+       static const char buf[QMP_MSG_LEN] = "{class: clock, res: qdss, val: 0}";
+       struct qmp *qmp = container_of(hw, struct qmp, qdss_clk);
+
+       qmp_send(qmp, buf, sizeof(buf));
+}
+
+static const struct clk_ops qmp_qdss_clk_ops = {
+       .prepare = qmp_qdss_clk_prepare,
+       .unprepare = qmp_qdss_clk_unprepare,
+};
+
+static int qmp_qdss_clk_add(struct qmp *qmp)
+{
+       static const struct clk_init_data qdss_init = {
+               .ops = &qmp_qdss_clk_ops,
+               .name = "qdss",
+       };
+       int ret;
+
+       qmp->qdss_clk.init = &qdss_init;
+       ret = clk_hw_register(qmp->dev, &qmp->qdss_clk);
+       if (ret < 0) {
+               dev_err(qmp->dev, "failed to register qdss clock\n");
+               return ret;
+       }
+
+       ret = of_clk_add_hw_provider(qmp->dev->of_node, of_clk_hw_simple_get,
+                                    &qmp->qdss_clk);
+       if (ret < 0) {
+               dev_err(qmp->dev, "unable to register of clk hw provider\n");
+               clk_hw_unregister(&qmp->qdss_clk);
+       }
+
+       return ret;
+}
+
+static void qmp_qdss_clk_remove(struct qmp *qmp)
+{
+       of_clk_del_provider(qmp->dev->of_node);
+       clk_hw_unregister(&qmp->qdss_clk);
+}
+
+static int qmp_pd_power_toggle(struct qmp_pd *res, bool enable)
+{
+       char buf[QMP_MSG_LEN] = {};
+
+       snprintf(buf, sizeof(buf),
+                "{class: image, res: load_state, name: %s, val: %s}",
+                res->pd.name, enable ? "on" : "off");
+       return qmp_send(res->qmp, buf, sizeof(buf));
+}
+
+static int qmp_pd_power_on(struct generic_pm_domain *domain)
+{
+       return qmp_pd_power_toggle(to_qmp_pd_resource(domain), true);
+}
+
+static int qmp_pd_power_off(struct generic_pm_domain *domain)
+{
+       return qmp_pd_power_toggle(to_qmp_pd_resource(domain), false);
+}
+
+static const char * const sdm845_resources[] = {
+       [AOSS_QMP_LS_CDSP] = "cdsp",
+       [AOSS_QMP_LS_LPASS] = "adsp",
+       [AOSS_QMP_LS_MODEM] = "modem",
+       [AOSS_QMP_LS_SLPI] = "slpi",
+       [AOSS_QMP_LS_SPSS] = "spss",
+       [AOSS_QMP_LS_VENUS] = "venus",
+};
+
+static int qmp_pd_add(struct qmp *qmp)
+{
+       struct genpd_onecell_data *data = &qmp->pd_data;
+       struct device *dev = qmp->dev;
+       struct qmp_pd *res;
+       size_t num = ARRAY_SIZE(sdm845_resources);
+       int ret;
+       int i;
+
+       res = devm_kcalloc(dev, num, sizeof(*res), GFP_KERNEL);
+       if (!res)
+               return -ENOMEM;
+
+       data->domains = devm_kcalloc(dev, num, sizeof(*data->domains),
+                                    GFP_KERNEL);
+       if (!data->domains)
+               return -ENOMEM;
+
+       for (i = 0; i < num; i++) {
+               res[i].qmp = qmp;
+               res[i].pd.name = sdm845_resources[i];
+               res[i].pd.power_on = qmp_pd_power_on;
+               res[i].pd.power_off = qmp_pd_power_off;
+
+               ret = pm_genpd_init(&res[i].pd, NULL, true);
+               if (ret < 0) {
+                       dev_err(dev, "failed to init genpd\n");
+                       goto unroll_genpds;
+               }
+
+               data->domains[i] = &res[i].pd;
+       }
+
+       data->num_domains = i;
+
+       ret = of_genpd_add_provider_onecell(dev->of_node, data);
+       if (ret < 0)
+               goto unroll_genpds;
+
+       return 0;
+
+unroll_genpds:
+       for (i--; i >= 0; i--)
+               pm_genpd_remove(data->domains[i]);
+
+       return ret;
+}
+
+static void qmp_pd_remove(struct qmp *qmp)
+{
+       struct genpd_onecell_data *data = &qmp->pd_data;
+       struct device *dev = qmp->dev;
+       int i;
+
+       of_genpd_del_provider(dev->of_node);
+
+       for (i = 0; i < data->num_domains; i++)
+               pm_genpd_remove(data->domains[i]);
+}
+
+static int qmp_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       struct qmp *qmp;
+       int irq;
+       int ret;
+
+       qmp = devm_kzalloc(&pdev->dev, sizeof(*qmp), GFP_KERNEL);
+       if (!qmp)
+               return -ENOMEM;
+
+       qmp->dev = &pdev->dev;
+       init_waitqueue_head(&qmp->event);
+       mutex_init(&qmp->tx_lock);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       qmp->msgram = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(qmp->msgram))
+               return PTR_ERR(qmp->msgram);
+
+       qmp->mbox_client.dev = &pdev->dev;
+       qmp->mbox_client.knows_txdone = true;
+       qmp->mbox_chan = mbox_request_channel(&qmp->mbox_client, 0);
+       if (IS_ERR(qmp->mbox_chan)) {
+               dev_err(&pdev->dev, "failed to acquire ipc mailbox\n");
+               return PTR_ERR(qmp->mbox_chan);
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       ret = devm_request_irq(&pdev->dev, irq, qmp_intr, IRQF_ONESHOT,
+                              "aoss-qmp", qmp);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to request interrupt\n");
+               goto err_free_mbox;
+       }
+
+       ret = qmp_open(qmp);
+       if (ret < 0)
+               goto err_free_mbox;
+
+       ret = qmp_qdss_clk_add(qmp);
+       if (ret)
+               goto err_close_qmp;
+
+       ret = qmp_pd_add(qmp);
+       if (ret)
+               goto err_remove_qdss_clk;
+
+       platform_set_drvdata(pdev, qmp);
+
+       return 0;
+
+err_remove_qdss_clk:
+       qmp_qdss_clk_remove(qmp);
+err_close_qmp:
+       qmp_close(qmp);
+err_free_mbox:
+       mbox_free_channel(qmp->mbox_chan);
+
+       return ret;
+}
+
+static int qmp_remove(struct platform_device *pdev)
+{
+       struct qmp *qmp = platform_get_drvdata(pdev);
+
+       qmp_qdss_clk_remove(qmp);
+       qmp_pd_remove(qmp);
+
+       qmp_close(qmp);
+       mbox_free_channel(qmp->mbox_chan);
+
+       return 0;
+}
+
+static const struct of_device_id qmp_dt_match[] = {
+       { .compatible = "qcom,sdm845-aoss-qmp", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, qmp_dt_match);
+
+static struct platform_driver qmp_driver = {
+       .driver = {
+               .name           = "qcom_aoss_qmp",
+               .of_match_table = qmp_dt_match,
+       },
+       .probe = qmp_probe,
+       .remove = qmp_remove,
+};
+module_platform_driver(qmp_driver);
+
+MODULE_DESCRIPTION("Qualcomm AOSS QMP driver");
+MODULE_LICENSE("GPL v2");
index 0053260..3c1a55c 100644 (file)
 
 #define domain_to_rpmpd(domain) container_of(domain, struct rpmpd, pd)
 
-/* Resource types */
+/* Resource types:
+ * RPMPD_X is X encoded as a little-endian, lower-case, ASCII string */
 #define RPMPD_SMPA 0x61706d73
 #define RPMPD_LDOA 0x616f646c
+#define RPMPD_RWCX 0x78637772
+#define RPMPD_RWMX 0x786d7772
+#define RPMPD_RWLC 0x636c7772
+#define RPMPD_RWLM 0x6d6c7772
+#define RPMPD_RWSC 0x63737772
+#define RPMPD_RWSM 0x6d737772
 
 /* Operation Keys */
 #define KEY_CORNER             0x6e726f63 /* corn */
 #define KEY_ENABLE             0x6e657773 /* swen */
 #define KEY_FLOOR_CORNER       0x636676   /* vfc */
+#define KEY_FLOOR_LEVEL                0x6c6676   /* vfl */
+#define KEY_LEVEL              0x6c766c76 /* vlvl */
 
-#define MAX_RPMPD_STATE                6
+#define MAX_8996_RPMPD_STATE   6
 
-#define DEFINE_RPMPD_CORNER_SMPA(_platform, _name, _active, r_id)              \
+#define DEFINE_RPMPD_PAIR(_platform, _name, _active, r_type, r_key,    \
+                         r_id)                                         \
        static struct rpmpd _platform##_##_active;                      \
        static struct rpmpd _platform##_##_name = {                     \
                .pd = { .name = #_name, },                              \
                .peer = &_platform##_##_active,                         \
-               .res_type = RPMPD_SMPA,                                 \
+               .res_type = RPMPD_##r_type,                             \
                .res_id = r_id,                                         \
-               .key = KEY_CORNER,                                      \
+               .key = KEY_##r_key,                                     \
        };                                                              \
        static struct rpmpd _platform##_##_active = {                   \
                .pd = { .name = #_active, },                            \
                .peer = &_platform##_##_name,                           \
                .active_only = true,                                    \
-               .res_type = RPMPD_SMPA,                                 \
+               .res_type = RPMPD_##r_type,                             \
                .res_id = r_id,                                         \
-               .key = KEY_CORNER,                                      \
+               .key = KEY_##r_key,                                     \
        }
 
-#define DEFINE_RPMPD_CORNER_LDOA(_platform, _name, r_id)                       \
+#define DEFINE_RPMPD_CORNER(_platform, _name, r_type, r_id)            \
        static struct rpmpd _platform##_##_name = {                     \
                .pd = { .name = #_name, },                              \
-               .res_type = RPMPD_LDOA,                                 \
+               .res_type = RPMPD_##r_type,                             \
                .res_id = r_id,                                         \
                .key = KEY_CORNER,                                      \
        }
 
-#define DEFINE_RPMPD_VFC(_platform, _name, r_id, r_type)               \
+#define DEFINE_RPMPD_LEVEL(_platform, _name, r_type, r_id)             \
        static struct rpmpd _platform##_##_name = {                     \
                .pd = { .name = #_name, },                              \
-               .res_type = r_type,                                     \
+               .res_type = RPMPD_##r_type,                             \
                .res_id = r_id,                                         \
-               .key = KEY_FLOOR_CORNER,                                \
+               .key = KEY_LEVEL,                                       \
        }
 
-#define DEFINE_RPMPD_VFC_SMPA(_platform, _name, r_id)                  \
-       DEFINE_RPMPD_VFC(_platform, _name, r_id, RPMPD_SMPA)
+#define DEFINE_RPMPD_VFC(_platform, _name, r_type, r_id)               \
+       static struct rpmpd _platform##_##_name = {                     \
+               .pd = { .name = #_name, },                              \
+               .res_type = RPMPD_##r_type,                             \
+               .res_id = r_id,                                         \
+               .key = KEY_FLOOR_CORNER,                                \
+       }
 
-#define DEFINE_RPMPD_VFC_LDOA(_platform, _name, r_id)                  \
-       DEFINE_RPMPD_VFC(_platform, _name, r_id, RPMPD_LDOA)
+#define DEFINE_RPMPD_VFL(_platform, _name, r_type, r_id)               \
+       static struct rpmpd _platform##_##_name = {                     \
+               .pd = { .name = #_name, },                              \
+               .res_type = RPMPD_##r_type,                             \
+               .res_id = r_id,                                         \
+               .key = KEY_FLOOR_LEVEL,                                 \
+       }
 
 struct rpmpd_req {
        __le32 key;
@@ -83,23 +103,25 @@ struct rpmpd {
        const int res_type;
        const int res_id;
        struct qcom_smd_rpm *rpm;
+       unsigned int max_state;
        __le32 key;
 };
 
 struct rpmpd_desc {
        struct rpmpd **rpmpds;
        size_t num_pds;
+       unsigned int max_state;
 };
 
 static DEFINE_MUTEX(rpmpd_lock);
 
 /* msm8996 RPM Power domains */
-DEFINE_RPMPD_CORNER_SMPA(msm8996, vddcx, vddcx_ao, 1);
-DEFINE_RPMPD_CORNER_SMPA(msm8996, vddmx, vddmx_ao, 2);
-DEFINE_RPMPD_CORNER_LDOA(msm8996, vddsscx, 26);
+DEFINE_RPMPD_PAIR(msm8996, vddcx, vddcx_ao, SMPA, CORNER, 1);
+DEFINE_RPMPD_PAIR(msm8996, vddmx, vddmx_ao, SMPA, CORNER, 2);
+DEFINE_RPMPD_CORNER(msm8996, vddsscx, LDOA, 26);
 
-DEFINE_RPMPD_VFC_SMPA(msm8996, vddcx_vfc, 1);
-DEFINE_RPMPD_VFC_LDOA(msm8996, vddsscx_vfc, 26);
+DEFINE_RPMPD_VFC(msm8996, vddcx_vfc, SMPA, 1);
+DEFINE_RPMPD_VFC(msm8996, vddsscx_vfc, LDOA, 26);
 
 static struct rpmpd *msm8996_rpmpds[] = {
        [MSM8996_VDDCX] =       &msm8996_vddcx,
@@ -114,10 +136,71 @@ static struct rpmpd *msm8996_rpmpds[] = {
 static const struct rpmpd_desc msm8996_desc = {
        .rpmpds = msm8996_rpmpds,
        .num_pds = ARRAY_SIZE(msm8996_rpmpds),
+       .max_state = MAX_8996_RPMPD_STATE,
+};
+
+/* msm8998 RPM Power domains */
+DEFINE_RPMPD_PAIR(msm8998, vddcx, vddcx_ao, RWCX, LEVEL, 0);
+DEFINE_RPMPD_VFL(msm8998, vddcx_vfl, RWCX, 0);
+
+DEFINE_RPMPD_PAIR(msm8998, vddmx, vddmx_ao, RWMX, LEVEL, 0);
+DEFINE_RPMPD_VFL(msm8998, vddmx_vfl, RWMX, 0);
+
+DEFINE_RPMPD_LEVEL(msm8998, vdd_ssccx, RWSC, 0);
+DEFINE_RPMPD_VFL(msm8998, vdd_ssccx_vfl, RWSC, 0);
+
+DEFINE_RPMPD_LEVEL(msm8998, vdd_sscmx, RWSM, 0);
+DEFINE_RPMPD_VFL(msm8998, vdd_sscmx_vfl, RWSM, 0);
+
+static struct rpmpd *msm8998_rpmpds[] = {
+       [MSM8998_VDDCX] =               &msm8998_vddcx,
+       [MSM8998_VDDCX_AO] =            &msm8998_vddcx_ao,
+       [MSM8998_VDDCX_VFL] =           &msm8998_vddcx_vfl,
+       [MSM8998_VDDMX] =               &msm8998_vddmx,
+       [MSM8998_VDDMX_AO] =            &msm8998_vddmx_ao,
+       [MSM8998_VDDMX_VFL] =           &msm8998_vddmx_vfl,
+       [MSM8998_SSCCX] =               &msm8998_vdd_ssccx,
+       [MSM8998_SSCCX_VFL] =           &msm8998_vdd_ssccx_vfl,
+       [MSM8998_SSCMX] =               &msm8998_vdd_sscmx,
+       [MSM8998_SSCMX_VFL] =           &msm8998_vdd_sscmx_vfl,
+};
+
+static const struct rpmpd_desc msm8998_desc = {
+       .rpmpds = msm8998_rpmpds,
+       .num_pds = ARRAY_SIZE(msm8998_rpmpds),
+       .max_state = RPM_SMD_LEVEL_BINNING,
+};
+
+/* qcs404 RPM Power domains */
+DEFINE_RPMPD_PAIR(qcs404, vddmx, vddmx_ao, RWMX, LEVEL, 0);
+DEFINE_RPMPD_VFL(qcs404, vddmx_vfl, RWMX, 0);
+
+DEFINE_RPMPD_LEVEL(qcs404, vdd_lpicx, RWLC, 0);
+DEFINE_RPMPD_VFL(qcs404, vdd_lpicx_vfl, RWLC, 0);
+
+DEFINE_RPMPD_LEVEL(qcs404, vdd_lpimx, RWLM, 0);
+DEFINE_RPMPD_VFL(qcs404, vdd_lpimx_vfl, RWLM, 0);
+
+static struct rpmpd *qcs404_rpmpds[] = {
+       [QCS404_VDDMX] = &qcs404_vddmx,
+       [QCS404_VDDMX_AO] = &qcs404_vddmx_ao,
+       [QCS404_VDDMX_VFL] = &qcs404_vddmx_vfl,
+       [QCS404_LPICX] = &qcs404_vdd_lpicx,
+       [QCS404_LPICX_VFL] = &qcs404_vdd_lpicx_vfl,
+       [QCS404_LPIMX] = &qcs404_vdd_lpimx,
+       [QCS404_LPIMX_VFL] = &qcs404_vdd_lpimx_vfl,
+};
+
+static const struct rpmpd_desc qcs404_desc = {
+       .rpmpds = qcs404_rpmpds,
+       .num_pds = ARRAY_SIZE(qcs404_rpmpds),
+       .max_state = RPM_SMD_LEVEL_BINNING,
 };
 
 static const struct of_device_id rpmpd_match_table[] = {
        { .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc },
+       { .compatible = "qcom,msm8998-rpmpd", .data = &msm8998_desc },
+       { .compatible = "qcom,qcs404-rpmpd", .data = &qcs404_desc },
        { }
 };
 
@@ -225,14 +308,16 @@ static int rpmpd_set_performance(struct generic_pm_domain *domain,
        int ret = 0;
        struct rpmpd *pd = domain_to_rpmpd(domain);
 
-       if (state > MAX_RPMPD_STATE)
-               goto out;
+       if (state > pd->max_state)
+               state = pd->max_state;
 
        mutex_lock(&rpmpd_lock);
 
        pd->corner = state;
 
-       if (!pd->enabled && pd->key != KEY_FLOOR_CORNER)
+       /* Always send updates for vfc and vfl */
+       if (!pd->enabled && pd->key != KEY_FLOOR_CORNER &&
+           pd->key != KEY_FLOOR_LEVEL)
                goto out;
 
        ret = rpmpd_aggregate_corner(pd);
@@ -287,6 +372,7 @@ static int rpmpd_probe(struct platform_device *pdev)
                }
 
                rpmpds[i]->rpm = rpm;
+               rpmpds[i]->max_state = desc->max_state;
                rpmpds[i]->pd.power_off = rpmpd_power_off;
                rpmpds[i]->pd.power_on = rpmpd_power_on;
                rpmpds[i]->pd.set_performance_state = rpmpd_set_performance;
index 68bfca6..2bbf49e 100644 (file)
@@ -57,14 +57,16 @@ config ARCH_R7S72100
        bool "RZ/A1H (R7S72100)"
        select PM
        select PM_GENERIC_DOMAINS
-       select SYS_SUPPORTS_SH_MTU2
        select RENESAS_OSTM
+       select RENESAS_RZA1_IRQC
+       select SYS_SUPPORTS_SH_MTU2
 
 config ARCH_R7S9210
        bool "RZ/A2 (R7S9210)"
        select PM
        select PM_GENERIC_DOMAINS
        select RENESAS_OSTM
+       select RENESAS_RZA1_IRQC
 
 config ARCH_R8A73A4
        bool "R-Mobile APE6 (R8A73A40)"
index 3342332..54eb6cf 100644 (file)
@@ -86,47 +86,47 @@ struct rockchip_pmu {
 #define to_rockchip_pd(gpd) container_of(gpd, struct rockchip_pm_domain, genpd)
 
 #define DOMAIN(pwr, status, req, idle, ack, wakeup)    \
-{                                              \
-       .pwr_mask = (pwr >= 0) ? BIT(pwr) : 0,          \
-       .status_mask = (status >= 0) ? BIT(status) : 0, \
-       .req_mask = (req >= 0) ? BIT(req) : 0,          \
-       .idle_mask = (idle >= 0) ? BIT(idle) : 0,       \
-       .ack_mask = (ack >= 0) ? BIT(ack) : 0,          \
-       .active_wakeup = wakeup,                        \
+{                                                      \
+       .pwr_mask = (pwr),                              \
+       .status_mask = (status),                        \
+       .req_mask = (req),                              \
+       .idle_mask = (idle),                            \
+       .ack_mask = (ack),                              \
+       .active_wakeup = (wakeup),                      \
 }
 
 #define DOMAIN_M(pwr, status, req, idle, ack, wakeup)  \
 {                                                      \
-       .pwr_w_mask = (pwr >= 0) ? BIT(pwr + 16) : 0,   \
-       .pwr_mask = (pwr >= 0) ? BIT(pwr) : 0,          \
-       .status_mask = (status >= 0) ? BIT(status) : 0, \
-       .req_w_mask = (req >= 0) ?  BIT(req + 16) : 0,  \
-       .req_mask = (req >= 0) ?  BIT(req) : 0,         \
-       .idle_mask = (idle >= 0) ? BIT(idle) : 0,       \
-       .ack_mask = (ack >= 0) ? BIT(ack) : 0,          \
+       .pwr_w_mask = (pwr) << 16,                      \
+       .pwr_mask = (pwr),                              \
+       .status_mask = (status),                        \
+       .req_w_mask = (req) << 16,                      \
+       .req_mask = (req),                              \
+       .idle_mask = (idle),                            \
+       .ack_mask = (ack),                              \
        .active_wakeup = wakeup,                        \
 }
 
 #define DOMAIN_RK3036(req, ack, idle, wakeup)          \
 {                                                      \
-       .req_mask = (req >= 0) ? BIT(req) : 0,          \
-       .req_w_mask = (req >= 0) ?  BIT(req + 16) : 0,  \
-       .ack_mask = (ack >= 0) ? BIT(ack) : 0,          \
-       .idle_mask = (idle >= 0) ? BIT(idle) : 0,       \
+       .req_mask = (req),                              \
+       .req_w_mask = (req) << 16,                      \
+       .ack_mask = (ack),                              \
+       .idle_mask = (idle),                            \
        .active_wakeup = wakeup,                        \
 }
 
 #define DOMAIN_PX30(pwr, status, req, wakeup)          \
-       DOMAIN_M(pwr, status, req, (req) + 16, req, wakeup)
+       DOMAIN_M(pwr, status, req, (req) << 16, req, wakeup)
 
 #define DOMAIN_RK3288(pwr, status, req, wakeup)                \
-       DOMAIN(pwr, status, req, req, (req) + 16, wakeup)
+       DOMAIN(pwr, status, req, req, (req) << 16, wakeup)
 
 #define DOMAIN_RK3328(pwr, status, req, wakeup)                \
-       DOMAIN_M(pwr, pwr, req, (req) + 10, req, wakeup)
+       DOMAIN_M(pwr, pwr, req, (req) << 10, req, wakeup)
 
 #define DOMAIN_RK3368(pwr, status, req, wakeup)                \
-       DOMAIN(pwr, status, req, (req) + 16, req, wakeup)
+       DOMAIN(pwr, status, req, (req) << 16, req, wakeup)
 
 #define DOMAIN_RK3399(pwr, status, req, wakeup)                \
        DOMAIN(pwr, status, req, req, req, wakeup)
@@ -716,129 +716,129 @@ err_out:
 }
 
 static const struct rockchip_domain_info px30_pm_domains[] = {
-       [PX30_PD_USB]           = DOMAIN_PX30(5, 5, 10, false),
-       [PX30_PD_SDCARD]        = DOMAIN_PX30(8, 8, 9, false),
-       [PX30_PD_GMAC]          = DOMAIN_PX30(10, 10, 6, false),
-       [PX30_PD_MMC_NAND]      = DOMAIN_PX30(11, 11, 5, false),
-       [PX30_PD_VPU]           = DOMAIN_PX30(12, 12, 14, false),
-       [PX30_PD_VO]            = DOMAIN_PX30(13, 13, 7, false),
-       [PX30_PD_VI]            = DOMAIN_PX30(14, 14, 8, false),
-       [PX30_PD_GPU]           = DOMAIN_PX30(15, 15, 2, false),
+       [PX30_PD_USB]           = DOMAIN_PX30(BIT(5),  BIT(5),  BIT(10), false),
+       [PX30_PD_SDCARD]        = DOMAIN_PX30(BIT(8),  BIT(8),  BIT(9),  false),
+       [PX30_PD_GMAC]          = DOMAIN_PX30(BIT(10), BIT(10), BIT(6),  false),
+       [PX30_PD_MMC_NAND]      = DOMAIN_PX30(BIT(11), BIT(11), BIT(5),  false),
+       [PX30_PD_VPU]           = DOMAIN_PX30(BIT(12), BIT(12), BIT(14), false),
+       [PX30_PD_VO]            = DOMAIN_PX30(BIT(13), BIT(13), BIT(7),  false),
+       [PX30_PD_VI]            = DOMAIN_PX30(BIT(14), BIT(14), BIT(8),  false),
+       [PX30_PD_GPU]           = DOMAIN_PX30(BIT(15), BIT(15), BIT(2),  false),
 };
 
 static const struct rockchip_domain_info rk3036_pm_domains[] = {
-       [RK3036_PD_MSCH]        = DOMAIN_RK3036(14, 23, 30, true),
-       [RK3036_PD_CORE]        = DOMAIN_RK3036(13, 17, 24, false),
-       [RK3036_PD_PERI]        = DOMAIN_RK3036(12, 18, 25, false),
-       [RK3036_PD_VIO]         = DOMAIN_RK3036(11, 19, 26, false),
-       [RK3036_PD_VPU]         = DOMAIN_RK3036(10, 20, 27, false),
-       [RK3036_PD_GPU]         = DOMAIN_RK3036(9, 21, 28, false),
-       [RK3036_PD_SYS]         = DOMAIN_RK3036(8, 22, 29, false),
+       [RK3036_PD_MSCH]        = DOMAIN_RK3036(BIT(14), BIT(23), BIT(30), true),
+       [RK3036_PD_CORE]        = DOMAIN_RK3036(BIT(13), BIT(17), BIT(24), false),
+       [RK3036_PD_PERI]        = DOMAIN_RK3036(BIT(12), BIT(18), BIT(25), false),
+       [RK3036_PD_VIO]         = DOMAIN_RK3036(BIT(11), BIT(19), BIT(26), false),
+       [RK3036_PD_VPU]         = DOMAIN_RK3036(BIT(10), BIT(20), BIT(27), false),
+       [RK3036_PD_GPU]         = DOMAIN_RK3036(BIT(9),  BIT(21), BIT(28), false),
+       [RK3036_PD_SYS]         = DOMAIN_RK3036(BIT(8),  BIT(22), BIT(29), false),
 };
 
 static const struct rockchip_domain_info rk3066_pm_domains[] = {
-       [RK3066_PD_GPU]         = DOMAIN(9, 9, 3, 24, 29, false),
-       [RK3066_PD_VIDEO]       = DOMAIN(8, 8, 4, 23, 28, false),
-       [RK3066_PD_VIO]         = DOMAIN(7, 7, 5, 22, 27, false),
-       [RK3066_PD_PERI]        = DOMAIN(6, 6, 2, 25, 30, false),
-       [RK3066_PD_CPU]         = DOMAIN(-1, 5, 1, 26, 31, false),
+       [RK3066_PD_GPU]         = DOMAIN(BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false),
+       [RK3066_PD_VIDEO]       = DOMAIN(BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false),
+       [RK3066_PD_VIO]         = DOMAIN(BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false),
+       [RK3066_PD_PERI]        = DOMAIN(BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false),
+       [RK3066_PD_CPU]         = DOMAIN(0,      BIT(5), BIT(1), BIT(26), BIT(31), false),
 };
 
 static const struct rockchip_domain_info rk3128_pm_domains[] = {
-       [RK3128_PD_CORE]        = DOMAIN_RK3288(0, 0, 4, false),
-       [RK3128_PD_MSCH]        = DOMAIN_RK3288(-1, -1, 6, true),
-       [RK3128_PD_VIO]         = DOMAIN_RK3288(3, 3, 2, false),
-       [RK3128_PD_VIDEO]       = DOMAIN_RK3288(2, 2, 1, false),
-       [RK3128_PD_GPU]         = DOMAIN_RK3288(1, 1, 3, false),
+       [RK3128_PD_CORE]        = DOMAIN_RK3288(BIT(0), BIT(0), BIT(4), false),
+       [RK3128_PD_MSCH]        = DOMAIN_RK3288(0,      0,      BIT(6), true),
+       [RK3128_PD_VIO]         = DOMAIN_RK3288(BIT(3), BIT(3), BIT(2), false),
+       [RK3128_PD_VIDEO]       = DOMAIN_RK3288(BIT(2), BIT(2), BIT(1), false),
+       [RK3128_PD_GPU]         = DOMAIN_RK3288(BIT(1), BIT(1), BIT(3), false),
 };
 
 static const struct rockchip_domain_info rk3188_pm_domains[] = {
-       [RK3188_PD_GPU]         = DOMAIN(9, 9, 3, 24, 29, false),
-       [RK3188_PD_VIDEO]       = DOMAIN(8, 8, 4, 23, 28, false),
-       [RK3188_PD_VIO]         = DOMAIN(7, 7, 5, 22, 27, false),
-       [RK3188_PD_PERI]        = DOMAIN(6, 6, 2, 25, 30, false),
-       [RK3188_PD_CPU]         = DOMAIN(5, 5, 1, 26, 31, false),
+       [RK3188_PD_GPU]         = DOMAIN(BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false),
+       [RK3188_PD_VIDEO]       = DOMAIN(BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false),
+       [RK3188_PD_VIO]         = DOMAIN(BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false),
+       [RK3188_PD_PERI]        = DOMAIN(BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false),
+       [RK3188_PD_CPU]         = DOMAIN(BIT(5), BIT(5), BIT(1), BIT(26), BIT(31), false),
 };
 
 static const struct rockchip_domain_info rk3228_pm_domains[] = {
-       [RK3228_PD_CORE]        = DOMAIN_RK3036(0, 0, 16, true),
-       [RK3228_PD_MSCH]        = DOMAIN_RK3036(1, 1, 17, true),
-       [RK3228_PD_BUS]         = DOMAIN_RK3036(2, 2, 18, true),
-       [RK3228_PD_SYS]         = DOMAIN_RK3036(3, 3, 19, true),
-       [RK3228_PD_VIO]         = DOMAIN_RK3036(4, 4, 20, false),
-       [RK3228_PD_VOP]         = DOMAIN_RK3036(5, 5, 21, false),
-       [RK3228_PD_VPU]         = DOMAIN_RK3036(6, 6, 22, false),
-       [RK3228_PD_RKVDEC]      = DOMAIN_RK3036(7, 7, 23, false),
-       [RK3228_PD_GPU]         = DOMAIN_RK3036(8, 8, 24, false),
-       [RK3228_PD_PERI]        = DOMAIN_RK3036(9, 9, 25, true),
-       [RK3228_PD_GMAC]        = DOMAIN_RK3036(10, 10, 26, false),
+       [RK3228_PD_CORE]        = DOMAIN_RK3036(BIT(0),  BIT(0),  BIT(16), true),
+       [RK3228_PD_MSCH]        = DOMAIN_RK3036(BIT(1),  BIT(1),  BIT(17), true),
+       [RK3228_PD_BUS]         = DOMAIN_RK3036(BIT(2),  BIT(2),  BIT(18), true),
+       [RK3228_PD_SYS]         = DOMAIN_RK3036(BIT(3),  BIT(3),  BIT(19), true),
+       [RK3228_PD_VIO]         = DOMAIN_RK3036(BIT(4),  BIT(4),  BIT(20), false),
+       [RK3228_PD_VOP]         = DOMAIN_RK3036(BIT(5),  BIT(5),  BIT(21), false),
+       [RK3228_PD_VPU]         = DOMAIN_RK3036(BIT(6),  BIT(6),  BIT(22), false),
+       [RK3228_PD_RKVDEC]      = DOMAIN_RK3036(BIT(7),  BIT(7),  BIT(23), false),
+       [RK3228_PD_GPU]         = DOMAIN_RK3036(BIT(8),  BIT(8),  BIT(24), false),
+       [RK3228_PD_PERI]        = DOMAIN_RK3036(BIT(9),  BIT(9),  BIT(25), true),
+       [RK3228_PD_GMAC]        = DOMAIN_RK3036(BIT(10), BIT(10), BIT(26), false),
 };
 
 static const struct rockchip_domain_info rk3288_pm_domains[] = {
-       [RK3288_PD_VIO]         = DOMAIN_RK3288(7, 7, 4, false),
-       [RK3288_PD_HEVC]        = DOMAIN_RK3288(14, 10, 9, false),
-       [RK3288_PD_VIDEO]       = DOMAIN_RK3288(8, 8, 3, false),
-       [RK3288_PD_GPU]         = DOMAIN_RK3288(9, 9, 2, false),
+       [RK3288_PD_VIO]         = DOMAIN_RK3288(BIT(7),  BIT(7),  BIT(4), false),
+       [RK3288_PD_HEVC]        = DOMAIN_RK3288(BIT(14), BIT(10), BIT(9), false),
+       [RK3288_PD_VIDEO]       = DOMAIN_RK3288(BIT(8),  BIT(8),  BIT(3), false),
+       [RK3288_PD_GPU]         = DOMAIN_RK3288(BIT(9),  BIT(9),  BIT(2), false),
 };
 
 static const struct rockchip_domain_info rk3328_pm_domains[] = {
-       [RK3328_PD_CORE]        = DOMAIN_RK3328(-1, 0, 0, false),
-       [RK3328_PD_GPU]         = DOMAIN_RK3328(-1, 1, 1, false),
-       [RK3328_PD_BUS]         = DOMAIN_RK3328(-1, 2, 2, true),
-       [RK3328_PD_MSCH]        = DOMAIN_RK3328(-1, 3, 3, true),
-       [RK3328_PD_PERI]        = DOMAIN_RK3328(-1, 4, 4, true),
-       [RK3328_PD_VIDEO]       = DOMAIN_RK3328(-1, 5, 5, false),
-       [RK3328_PD_HEVC]        = DOMAIN_RK3328(-1, 6, 6, false),
-       [RK3328_PD_VIO]         = DOMAIN_RK3328(-1, 8, 8, false),
-       [RK3328_PD_VPU]         = DOMAIN_RK3328(-1, 9, 9, false),
+       [RK3328_PD_CORE]        = DOMAIN_RK3328(0, BIT(0), BIT(0), false),
+       [RK3328_PD_GPU]         = DOMAIN_RK3328(0, BIT(1), BIT(1), false),
+       [RK3328_PD_BUS]         = DOMAIN_RK3328(0, BIT(2), BIT(2), true),
+       [RK3328_PD_MSCH]        = DOMAIN_RK3328(0, BIT(3), BIT(3), true),
+       [RK3328_PD_PERI]        = DOMAIN_RK3328(0, BIT(4), BIT(4), true),
+       [RK3328_PD_VIDEO]       = DOMAIN_RK3328(0, BIT(5), BIT(5), false),
+       [RK3328_PD_HEVC]        = DOMAIN_RK3328(0, BIT(6), BIT(6), false),
+       [RK3328_PD_VIO]         = DOMAIN_RK3328(0, BIT(8), BIT(8), false),
+       [RK3328_PD_VPU]         = DOMAIN_RK3328(0, BIT(9), BIT(9), false),
 };
 
 static const struct rockchip_domain_info rk3366_pm_domains[] = {
-       [RK3366_PD_PERI]        = DOMAIN_RK3368(10, 10, 6, true),
-       [RK3366_PD_VIO]         = DOMAIN_RK3368(14, 14, 8, false),
-       [RK3366_PD_VIDEO]       = DOMAIN_RK3368(13, 13, 7, false),
-       [RK3366_PD_RKVDEC]      = DOMAIN_RK3368(11, 11, 7, false),
-       [RK3366_PD_WIFIBT]      = DOMAIN_RK3368(8, 8, 9, false),
-       [RK3366_PD_VPU]         = DOMAIN_RK3368(12, 12, 7, false),
-       [RK3366_PD_GPU]         = DOMAIN_RK3368(15, 15, 2, false),
+       [RK3366_PD_PERI]        = DOMAIN_RK3368(BIT(10), BIT(10), BIT(6), true),
+       [RK3366_PD_VIO]         = DOMAIN_RK3368(BIT(14), BIT(14), BIT(8), false),
+       [RK3366_PD_VIDEO]       = DOMAIN_RK3368(BIT(13), BIT(13), BIT(7), false),
+       [RK3366_PD_RKVDEC]      = DOMAIN_RK3368(BIT(11), BIT(11), BIT(7), false),
+       [RK3366_PD_WIFIBT]      = DOMAIN_RK3368(BIT(8),  BIT(8),  BIT(9), false),
+       [RK3366_PD_VPU]         = DOMAIN_RK3368(BIT(12), BIT(12), BIT(7), false),
+       [RK3366_PD_GPU]         = DOMAIN_RK3368(BIT(15), BIT(15), BIT(2), false),
 };
 
 static const struct rockchip_domain_info rk3368_pm_domains[] = {
-       [RK3368_PD_PERI]        = DOMAIN_RK3368(13, 12, 6, true),
-       [RK3368_PD_VIO]         = DOMAIN_RK3368(15, 14, 8, false),
-       [RK3368_PD_VIDEO]       = DOMAIN_RK3368(14, 13, 7, false),
-       [RK3368_PD_GPU_0]       = DOMAIN_RK3368(16, 15, 2, false),
-       [RK3368_PD_GPU_1]       = DOMAIN_RK3368(17, 16, 2, false),
+       [RK3368_PD_PERI]        = DOMAIN_RK3368(BIT(13), BIT(12), BIT(6), true),
+       [RK3368_PD_VIO]         = DOMAIN_RK3368(BIT(15), BIT(14), BIT(8), false),
+       [RK3368_PD_VIDEO]       = DOMAIN_RK3368(BIT(14), BIT(13), BIT(7), false),
+       [RK3368_PD_GPU_0]       = DOMAIN_RK3368(BIT(16), BIT(15), BIT(2), false),
+       [RK3368_PD_GPU_1]       = DOMAIN_RK3368(BIT(17), BIT(16), BIT(2), false),
 };
 
 static const struct rockchip_domain_info rk3399_pm_domains[] = {
-       [RK3399_PD_TCPD0]       = DOMAIN_RK3399(8, 8, -1, false),
-       [RK3399_PD_TCPD1]       = DOMAIN_RK3399(9, 9, -1, false),
-       [RK3399_PD_CCI]         = DOMAIN_RK3399(10, 10, -1, true),
-       [RK3399_PD_CCI0]        = DOMAIN_RK3399(-1, -1, 15, true),
-       [RK3399_PD_CCI1]        = DOMAIN_RK3399(-1, -1, 16, true),
-       [RK3399_PD_PERILP]      = DOMAIN_RK3399(11, 11, 1, true),
-       [RK3399_PD_PERIHP]      = DOMAIN_RK3399(12, 12, 2, true),
-       [RK3399_PD_CENTER]      = DOMAIN_RK3399(13, 13, 14, true),
-       [RK3399_PD_VIO]         = DOMAIN_RK3399(14, 14, 17, false),
-       [RK3399_PD_GPU]         = DOMAIN_RK3399(15, 15, 0, false),
-       [RK3399_PD_VCODEC]      = DOMAIN_RK3399(16, 16, 3, false),
-       [RK3399_PD_VDU]         = DOMAIN_RK3399(17, 17, 4, false),
-       [RK3399_PD_RGA]         = DOMAIN_RK3399(18, 18, 5, false),
-       [RK3399_PD_IEP]         = DOMAIN_RK3399(19, 19, 6, false),
-       [RK3399_PD_VO]          = DOMAIN_RK3399(20, 20, -1, false),
-       [RK3399_PD_VOPB]        = DOMAIN_RK3399(-1, -1, 7, false),
-       [RK3399_PD_VOPL]        = DOMAIN_RK3399(-1, -1, 8, false),
-       [RK3399_PD_ISP0]        = DOMAIN_RK3399(22, 22, 9, false),
-       [RK3399_PD_ISP1]        = DOMAIN_RK3399(23, 23, 10, false),
-       [RK3399_PD_HDCP]        = DOMAIN_RK3399(24, 24, 11, false),
-       [RK3399_PD_GMAC]        = DOMAIN_RK3399(25, 25, 23, true),
-       [RK3399_PD_EMMC]        = DOMAIN_RK3399(26, 26, 24, true),
-       [RK3399_PD_USB3]        = DOMAIN_RK3399(27, 27, 12, true),
-       [RK3399_PD_EDP]         = DOMAIN_RK3399(28, 28, 22, false),
-       [RK3399_PD_GIC]         = DOMAIN_RK3399(29, 29, 27, true),
-       [RK3399_PD_SD]          = DOMAIN_RK3399(30, 30, 28, true),
-       [RK3399_PD_SDIOAUDIO]   = DOMAIN_RK3399(31, 31, 29, true),
+       [RK3399_PD_TCPD0]       = DOMAIN_RK3399(BIT(8),  BIT(8),  0,       false),
+       [RK3399_PD_TCPD1]       = DOMAIN_RK3399(BIT(9),  BIT(9),  0,       false),
+       [RK3399_PD_CCI]         = DOMAIN_RK3399(BIT(10), BIT(10), 0,       true),
+       [RK3399_PD_CCI0]        = DOMAIN_RK3399(0,       0,       BIT(15), true),
+       [RK3399_PD_CCI1]        = DOMAIN_RK3399(0,       0,       BIT(16), true),
+       [RK3399_PD_PERILP]      = DOMAIN_RK3399(BIT(11), BIT(11), BIT(1),  true),
+       [RK3399_PD_PERIHP]      = DOMAIN_RK3399(BIT(12), BIT(12), BIT(2),  true),
+       [RK3399_PD_CENTER]      = DOMAIN_RK3399(BIT(13), BIT(13), BIT(14), true),
+       [RK3399_PD_VIO]         = DOMAIN_RK3399(BIT(14), BIT(14), BIT(17), false),
+       [RK3399_PD_GPU]         = DOMAIN_RK3399(BIT(15), BIT(15), BIT(0),  false),
+       [RK3399_PD_VCODEC]      = DOMAIN_RK3399(BIT(16), BIT(16), BIT(3),  false),
+       [RK3399_PD_VDU]         = DOMAIN_RK3399(BIT(17), BIT(17), BIT(4),  false),
+       [RK3399_PD_RGA]         = DOMAIN_RK3399(BIT(18), BIT(18), BIT(5),  false),
+       [RK3399_PD_IEP]         = DOMAIN_RK3399(BIT(19), BIT(19), BIT(6),  false),
+       [RK3399_PD_VO]          = DOMAIN_RK3399(BIT(20), BIT(20), 0,       false),
+       [RK3399_PD_VOPB]        = DOMAIN_RK3399(0,       0,       BIT(7),  false),
+       [RK3399_PD_VOPL]        = DOMAIN_RK3399(0,       0,       BIT(8),  false),
+       [RK3399_PD_ISP0]        = DOMAIN_RK3399(BIT(22), BIT(22), BIT(9),  false),
+       [RK3399_PD_ISP1]        = DOMAIN_RK3399(BIT(23), BIT(23), BIT(10), false),
+       [RK3399_PD_HDCP]        = DOMAIN_RK3399(BIT(24), BIT(24), BIT(11), false),
+       [RK3399_PD_GMAC]        = DOMAIN_RK3399(BIT(25), BIT(25), BIT(23), true),
+       [RK3399_PD_EMMC]        = DOMAIN_RK3399(BIT(26), BIT(26), BIT(24), true),
+       [RK3399_PD_USB3]        = DOMAIN_RK3399(BIT(27), BIT(27), BIT(12), true),
+       [RK3399_PD_EDP]         = DOMAIN_RK3399(BIT(28), BIT(28), BIT(22), false),
+       [RK3399_PD_GIC]         = DOMAIN_RK3399(BIT(29), BIT(29), BIT(27), true),
+       [RK3399_PD_SD]          = DOMAIN_RK3399(BIT(30), BIT(30), BIT(28), true),
+       [RK3399_PD_SDIOAUDIO]   = DOMAIN_RK3399(BIT(31), BIT(31), BIT(29), true),
 };
 
 static const struct rockchip_pmu_info px30_pmu = {
index fbfce48..c8ef05d 100644 (file)
@@ -109,6 +109,7 @@ config ARCH_TEGRA_186_SOC
 config ARCH_TEGRA_194_SOC
        bool "NVIDIA Tegra194 SoC"
        select MAILBOX
+       select PINCTRL_TEGRA194
        select TEGRA_BPMP
        select TEGRA_HSP_MBOX
        select TEGRA_IVC
index 9b84bcc..3eb44e6 100644 (file)
@@ -133,8 +133,10 @@ static int tegra_fuse_probe(struct platform_device *pdev)
 
        fuse->clk = devm_clk_get(&pdev->dev, "fuse");
        if (IS_ERR(fuse->clk)) {
-               dev_err(&pdev->dev, "failed to get FUSE clock: %ld",
-                       PTR_ERR(fuse->clk));
+               if (PTR_ERR(fuse->clk) != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "failed to get FUSE clock: %ld",
+                               PTR_ERR(fuse->clk));
+
                fuse->base = base;
                return PTR_ERR(fuse->clk);
        }
index 4bb16e9..d4aef9c 100644 (file)
@@ -99,7 +99,7 @@ static int tegra20_fuse_probe(struct tegra_fuse *fuse)
        dma_cap_zero(mask);
        dma_cap_set(DMA_SLAVE, mask);
 
-       fuse->apbdma.chan = __dma_request_channel(&mask, dma_filter, NULL);
+       fuse->apbdma.chan = dma_request_channel(mask, dma_filter, NULL);
        if (!fuse->apbdma.chan)
                return -EPROBE_DEFER;
 
index 17e7796..9f9c1c6 100644 (file)
@@ -232,6 +232,11 @@ struct tegra_pmc_soc {
        const char * const *reset_levels;
        unsigned int num_reset_levels;
 
+       /*
+        * These describe events that can wake the system from sleep (i.e.
+        * LP0 or SC7). Wakeup from other sleep states (such as LP1 or LP2)
+        * are dealt with in the LIC.
+        */
        const struct tegra_wake_event *wake_events;
        unsigned int num_wake_events;
 };
@@ -1855,6 +1860,9 @@ static int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq,
        unsigned int i;
        int err = 0;
 
+       if (WARN_ON(num_irqs > 1))
+               return -EINVAL;
+
        for (i = 0; i < soc->num_wake_events; i++) {
                const struct tegra_wake_event *event = &soc->wake_events[i];
 
@@ -1895,6 +1903,11 @@ static int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq,
                }
        }
 
+       /*
+        * For interrupts that don't have associated wake events, assign a
+        * dummy hardware IRQ number. This is used in the ->irq_set_type()
+        * and ->irq_set_wake() callbacks to return early for these IRQs.
+        */
        if (i == soc->num_wake_events)
                err = irq_domain_set_hwirq_and_chip(domain, virq, ULONG_MAX,
                                                    &pmc->irq, pmc);
@@ -1913,6 +1926,10 @@ static int tegra_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
        unsigned int offset, bit;
        u32 value;
 
+       /* nothing to do if there's no associated wake event */
+       if (WARN_ON(data->hwirq == ULONG_MAX))
+               return 0;
+
        offset = data->hwirq / 32;
        bit = data->hwirq % 32;
 
@@ -1940,6 +1957,7 @@ static int tegra_pmc_irq_set_type(struct irq_data *data, unsigned int type)
        struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
        u32 value;
 
+       /* nothing to do if there's no associated wake event */
        if (data->hwirq == ULONG_MAX)
                return 0;
 
index d7d50d4..cf545f4 100644 (file)
@@ -9,6 +9,11 @@ config ARCH_K3_AM6_SOC
        help
          Enable support for TI's AM6 SoC Family support
 
+config ARCH_K3_J721E_SOC
+       bool "K3 J721E SoC"
+       help
+         Enable support for TI's J721E SoC Family support
+
 endif
 
 endif
index fc5802c..bb77c22 100644 (file)
@@ -178,6 +178,7 @@ static int am33xx_pm_suspend(suspend_state_t suspend_state)
                                          suspend_wfi_flags);
 
                suspend_wfi_flags &= ~WFI_FLAG_RTC_ONLY;
+               dev_info(pm33xx_dev, "Entering RTC Only mode with DDR in self-refresh\n");
 
                if (!ret) {
                        clk_restore_context();
index 9ab30af..f8a4144 100644 (file)
@@ -15,7 +15,7 @@ normally be unsharable, specifically:
 * visorinput - keyboard and mouse
 
 These drivers conform to the standard Linux bus/device model described
-within Documentation/driver-model/, and utilize a driver named visorbus to
+within Documentation/driver-api/driver-model/, and utilize a driver named visorbus to
 present the virtual busses involved. Drivers in the 'visor*' driver set are
 commonly referred to as "guest drivers" or "client drivers".  All drivers
 except visorbus expose a device of a specific usable class to the Linux guest
@@ -141,7 +141,7 @@ called automatically by the visorbus driver at appropriate times:
 -----------------------------------
 
 Because visorbus is a standard Linux bus driver in the model described in
-Documentation/driver-model/, the hierarchy of s-Par virtual devices is
+Documentation/driver-api/driver-model/, the hierarchy of s-Par virtual devices is
 published in the sysfs tree beneath /bus/visorbus/, e.g.,
 /sys/bus/visorbus/devices/ might look like:
 
index 8ff109f..afd99f6 100644 (file)
@@ -117,14 +117,4 @@ static struct thermal_governor thermal_gov_fair_share = {
        .name           = "fair_share",
        .throttle       = fair_share_throttle,
 };
-
-int thermal_gov_fair_share_register(void)
-{
-       return thermal_register_governor(&thermal_gov_fair_share);
-}
-
-void thermal_gov_fair_share_unregister(void)
-{
-       thermal_unregister_governor(&thermal_gov_fair_share);
-}
-
+THERMAL_GOVERNOR_DECLARE(thermal_gov_fair_share);
index 632fb92..e0575d2 100644 (file)
@@ -116,13 +116,4 @@ static struct thermal_governor thermal_gov_bang_bang = {
        .name           = "bang_bang",
        .throttle       = bang_bang_control,
 };
-
-int thermal_gov_bang_bang_register(void)
-{
-       return thermal_register_governor(&thermal_gov_bang_bang);
-}
-
-void thermal_gov_bang_bang_unregister(void)
-{
-       thermal_unregister_governor(&thermal_gov_bang_bang);
-}
+THERMAL_GOVERNOR_DECLARE(thermal_gov_bang_bang);
index 5333e01..7979075 100644 (file)
@@ -40,4 +40,10 @@ config INT3406_THERMAL
          brightness in order to address a thermal condition or to reduce
          power consumed by display device.
 
+config PROC_THERMAL_MMIO_RAPL
+       bool
+       depends on 64BIT
+       depends on POWERCAP
+       select INTEL_RAPL_CORE
+       default y
 endif
index 53c84fa..d3446ac 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/platform_device.h>
 #include <linux/acpi.h>
 #include <linux/thermal.h>
+#include <linux/cpuhotplug.h>
+#include <linux/intel_rapl.h>
 #include "int340x_thermal_zone.h"
 #include "../intel_soc_dts_iosf.h"
 
@@ -37,6 +39,8 @@
 /* GeminiLake thermal reporting device */
 #define PCI_DEVICE_ID_PROC_GLK_THERMAL 0x318C
 
+#define DRV_NAME "proc_thermal"
+
 struct power_config {
        u32     index;
        u32     min_uw;
@@ -52,6 +56,7 @@ struct proc_thermal_device {
        struct power_config power_limits[2];
        struct int34x_thermal_zone *int340x_zone;
        struct intel_soc_dts_sensors *soc_dts;
+       void __iomem *mmio_base;
 };
 
 enum proc_thermal_emum_mode_type {
@@ -60,6 +65,12 @@ enum proc_thermal_emum_mode_type {
        PROC_THERMAL_PLATFORM_DEV
 };
 
+struct rapl_mmio_regs {
+       u64 reg_unit;
+       u64 regs[RAPL_DOMAIN_MAX][RAPL_DOMAIN_REG_MAX];
+       int limits[RAPL_DOMAIN_MAX];
+};
+
 /*
  * We can have only one type of enumeration, PCI or Platform,
  * not both. So we don't need instance specific data.
@@ -367,8 +378,155 @@ static irqreturn_t proc_thermal_pci_msi_irq(int irq, void *devid)
        return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_PROC_THERMAL_MMIO_RAPL
+
+#define MCHBAR 0
+
+/* RAPL Support via MMIO interface */
+static struct rapl_if_priv rapl_mmio_priv;
+
+static int rapl_mmio_cpu_online(unsigned int cpu)
+{
+       struct rapl_package *rp;
+
+       /* mmio rapl supports package 0 only for now */
+       if (topology_physical_package_id(cpu))
+               return 0;
+
+       rp = rapl_find_package_domain(cpu, &rapl_mmio_priv);
+       if (!rp) {
+               rp = rapl_add_package(cpu, &rapl_mmio_priv);
+               if (IS_ERR(rp))
+                       return PTR_ERR(rp);
+       }
+       cpumask_set_cpu(cpu, &rp->cpumask);
+       return 0;
+}
+
+static int rapl_mmio_cpu_down_prep(unsigned int cpu)
+{
+       struct rapl_package *rp;
+       int lead_cpu;
+
+       rp = rapl_find_package_domain(cpu, &rapl_mmio_priv);
+       if (!rp)
+               return 0;
+
+       cpumask_clear_cpu(cpu, &rp->cpumask);
+       lead_cpu = cpumask_first(&rp->cpumask);
+       if (lead_cpu >= nr_cpu_ids)
+               rapl_remove_package(rp);
+       else if (rp->lead_cpu == cpu)
+               rp->lead_cpu = lead_cpu;
+       return 0;
+}
+
+static int rapl_mmio_read_raw(int cpu, struct reg_action *ra)
+{
+       if (!ra->reg)
+               return -EINVAL;
+
+       ra->value = readq((void __iomem *)ra->reg);
+       ra->value &= ra->mask;
+       return 0;
+}
+
+static int rapl_mmio_write_raw(int cpu, struct reg_action *ra)
+{
+       u64 val;
+
+       if (!ra->reg)
+               return -EINVAL;
+
+       val = readq((void __iomem *)ra->reg);
+       val &= ~ra->mask;
+       val |= ra->value;
+       writeq(val, (void __iomem *)ra->reg);
+       return 0;
+}
+
+static int proc_thermal_rapl_add(struct pci_dev *pdev,
+                                struct proc_thermal_device *proc_priv,
+                                struct rapl_mmio_regs *rapl_regs)
+{
+       enum rapl_domain_reg_id reg;
+       enum rapl_domain_type domain;
+       int ret;
+
+       if (!rapl_regs)
+               return 0;
+
+       ret = pcim_iomap_regions(pdev, 1 << MCHBAR, DRV_NAME);
+       if (ret) {
+               dev_err(&pdev->dev, "cannot reserve PCI memory region\n");
+               return -ENOMEM;
+       }
+
+       proc_priv->mmio_base = pcim_iomap_table(pdev)[MCHBAR];
+
+       for (domain = RAPL_DOMAIN_PACKAGE; domain < RAPL_DOMAIN_MAX; domain++) {
+               for (reg = RAPL_DOMAIN_REG_LIMIT; reg < RAPL_DOMAIN_REG_MAX; reg++)
+                       if (rapl_regs->regs[domain][reg])
+                               rapl_mmio_priv.regs[domain][reg] =
+                                               (u64)proc_priv->mmio_base +
+                                               rapl_regs->regs[domain][reg];
+               rapl_mmio_priv.limits[domain] = rapl_regs->limits[domain];
+       }
+       rapl_mmio_priv.reg_unit = (u64)proc_priv->mmio_base + rapl_regs->reg_unit;
+
+       rapl_mmio_priv.read_raw = rapl_mmio_read_raw;
+       rapl_mmio_priv.write_raw = rapl_mmio_write_raw;
+
+       rapl_mmio_priv.control_type = powercap_register_control_type(NULL, "intel-rapl-mmio", NULL);
+       if (IS_ERR(rapl_mmio_priv.control_type)) {
+               pr_debug("failed to register powercap control_type.\n");
+               return PTR_ERR(rapl_mmio_priv.control_type);
+       }
+
+       ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "powercap/rapl:online",
+                               rapl_mmio_cpu_online, rapl_mmio_cpu_down_prep);
+       if (ret < 0) {
+               powercap_unregister_control_type(rapl_mmio_priv.control_type);
+               rapl_mmio_priv.control_type = NULL;
+               return ret;
+       }
+       rapl_mmio_priv.pcap_rapl_online = ret;
+
+       return 0;
+}
+
+static void proc_thermal_rapl_remove(void)
+{
+       if (IS_ERR_OR_NULL(rapl_mmio_priv.control_type))
+               return;
+
+       cpuhp_remove_state(rapl_mmio_priv.pcap_rapl_online);
+       powercap_unregister_control_type(rapl_mmio_priv.control_type);
+}
+
+static const struct rapl_mmio_regs rapl_mmio_hsw = {
+       .reg_unit = 0x5938,
+       .regs[RAPL_DOMAIN_PACKAGE] = { 0x59a0, 0x593c, 0x58f0, 0, 0x5930},
+       .regs[RAPL_DOMAIN_DRAM] = { 0x58e0, 0x58e8, 0x58ec, 0, 0},
+       .limits[RAPL_DOMAIN_PACKAGE] = 2,
+       .limits[RAPL_DOMAIN_DRAM] = 2,
+};
+
+#else
+
+static int proc_thermal_rapl_add(struct pci_dev *pdev,
+                                struct proc_thermal_device *proc_priv,
+                                struct rapl_mmio_regs *rapl_regs)
+{
+       return 0;
+}
+static void proc_thermal_rapl_remove(void) {}
+static const struct rapl_mmio_regs rapl_mmio_hsw;
+
+#endif /* CONFIG_MMIO_RAPL */
+
 static int  proc_thermal_pci_probe(struct pci_dev *pdev,
-                                  const struct pci_device_id *unused)
+                                  const struct pci_device_id *id)
 {
        struct proc_thermal_device *proc_priv;
        int ret;
@@ -378,15 +536,21 @@ static int  proc_thermal_pci_probe(struct pci_dev *pdev,
                return -ENODEV;
        }
 
-       ret = pci_enable_device(pdev);
+       ret = pcim_enable_device(pdev);
        if (ret < 0) {
                dev_err(&pdev->dev, "error: could not enable device\n");
                return ret;
        }
 
        ret = proc_thermal_add(&pdev->dev, &proc_priv);
+       if (ret)
+               return ret;
+
+       ret = proc_thermal_rapl_add(pdev, proc_priv,
+                               (struct rapl_mmio_regs *)id->driver_data);
        if (ret) {
-               pci_disable_device(pdev);
+               dev_err(&pdev->dev, "failed to add RAPL MMIO interface\n");
+               proc_thermal_remove(proc_priv);
                return ret;
        }
 
@@ -439,14 +603,31 @@ static void  proc_thermal_pci_remove(struct pci_dev *pdev)
                        pci_disable_msi(pdev);
                }
        }
+       proc_thermal_rapl_remove();
        proc_thermal_remove(proc_priv);
-       pci_disable_device(pdev);
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int proc_thermal_resume(struct device *dev)
+{
+       struct proc_thermal_device *proc_dev;
+
+       proc_dev = dev_get_drvdata(dev);
+       proc_thermal_read_ppcc(proc_dev);
+
+       return 0;
+}
+#else
+#define proc_thermal_resume NULL
+#endif
+
+static SIMPLE_DEV_PM_OPS(proc_thermal_pm, NULL, proc_thermal_resume);
+
 static const struct pci_device_id proc_thermal_pci_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BDW_THERMAL)},
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_HSB_THERMAL)},
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_SKL_THERMAL)},
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_SKL_THERMAL),
+               .driver_data = (kernel_ulong_t)&rapl_mmio_hsw, },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BSW_THERMAL)},
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXT0_THERMAL)},
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXT1_THERMAL)},
@@ -461,10 +642,11 @@ static const struct pci_device_id proc_thermal_pci_ids[] = {
 MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids);
 
 static struct pci_driver proc_thermal_pci_driver = {
-       .name           = "proc_thermal",
+       .name           = DRV_NAME,
        .probe          = proc_thermal_pci_probe,
        .remove         = proc_thermal_pci_remove,
        .id_table       = proc_thermal_pci_ids,
+       .driver.pm      = &proc_thermal_pm,
 };
 
 static const struct acpi_device_id int3401_device_ids[] = {
@@ -479,6 +661,7 @@ static struct platform_driver int3401_driver = {
        .driver = {
                .name = "int3401 thermal",
                .acpi_match_table = int3401_device_ids,
+               .pm = &proc_thermal_pm,
        },
 };
 
index 3055f9a..4463647 100644 (file)
@@ -651,13 +651,4 @@ static struct thermal_governor thermal_gov_power_allocator = {
        .unbind_from_tz = power_allocator_unbind,
        .throttle       = power_allocator_throttle,
 };
-
-int thermal_gov_power_allocator_register(void)
-{
-       return thermal_register_governor(&thermal_gov_power_allocator);
-}
-
-void thermal_gov_power_allocator_unregister(void)
-{
-       thermal_unregister_governor(&thermal_gov_power_allocator);
-}
+THERMAL_GOVERNOR_DECLARE(thermal_gov_power_allocator);
index 81a183b..6e051cb 100644 (file)
@@ -206,13 +206,4 @@ static struct thermal_governor thermal_gov_step_wise = {
        .name           = "step_wise",
        .throttle       = step_wise_throttle,
 };
-
-int thermal_gov_step_wise_register(void)
-{
-       return thermal_register_governor(&thermal_gov_step_wise);
-}
-
-void thermal_gov_step_wise_unregister(void)
-{
-       thermal_unregister_governor(&thermal_gov_step_wise);
-}
+THERMAL_GOVERNOR_DECLARE(thermal_gov_step_wise);
index 46cfb7d..6bab66e 100644 (file)
@@ -243,36 +243,42 @@ int thermal_build_list_of_policies(char *buf)
        return count;
 }
 
-static int __init thermal_register_governors(void)
+static void __init thermal_unregister_governors(void)
 {
-       int result;
+       struct thermal_governor **governor;
 
-       result = thermal_gov_step_wise_register();
-       if (result)
-               return result;
+       for_each_governor_table(governor)
+               thermal_unregister_governor(*governor);
+}
 
-       result = thermal_gov_fair_share_register();
-       if (result)
-               return result;
+static int __init thermal_register_governors(void)
+{
+       int ret = 0;
+       struct thermal_governor **governor;
 
-       result = thermal_gov_bang_bang_register();
-       if (result)
-               return result;
+       for_each_governor_table(governor) {
+               ret = thermal_register_governor(*governor);
+               if (ret) {
+                       pr_err("Failed to register governor: '%s'",
+                              (*governor)->name);
+                       break;
+               }
 
-       result = thermal_gov_user_space_register();
-       if (result)
-               return result;
+               pr_info("Registered thermal governor '%s'",
+                       (*governor)->name);
+       }
 
-       return thermal_gov_power_allocator_register();
-}
+       if (ret) {
+               struct thermal_governor **gov;
 
-static void __init thermal_unregister_governors(void)
-{
-       thermal_gov_step_wise_unregister();
-       thermal_gov_fair_share_unregister();
-       thermal_gov_bang_bang_unregister();
-       thermal_gov_user_space_unregister();
-       thermal_gov_power_allocator_unregister();
+               for_each_governor_table(gov) {
+                       if (gov == governor)
+                               break;
+                       thermal_unregister_governor(*gov);
+               }
+       }
+
+       return ret;
 }
 
 /*
index 0df190e..207b0cd 100644 (file)
 /* Initial state of a cooling device during binding */
 #define THERMAL_NO_TARGET -1UL
 
+/* Init section thermal table */
+extern struct thermal_governor *__governor_thermal_table[];
+extern struct thermal_governor *__governor_thermal_table_end[];
+
+#define THERMAL_TABLE_ENTRY(table, name)                       \
+       static typeof(name) *__thermal_table_entry_##name       \
+       __used __section(__##table##_thermal_table) = &name
+
+#define THERMAL_GOVERNOR_DECLARE(name) THERMAL_TABLE_ENTRY(governor, name)
+
+#define for_each_governor_table(__governor)            \
+       for (__governor = __governor_thermal_table;     \
+            __governor < __governor_thermal_table_end; \
+            __governor++)
+
 /*
  * This structure is used to describe the behavior of
  * a certain cooling device on a certain trip point
@@ -74,46 +89,6 @@ thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
                                    unsigned long new_state) {}
 #endif /* CONFIG_THERMAL_STATISTICS */
 
-#ifdef CONFIG_THERMAL_GOV_STEP_WISE
-int thermal_gov_step_wise_register(void);
-void thermal_gov_step_wise_unregister(void);
-#else
-static inline int thermal_gov_step_wise_register(void) { return 0; }
-static inline void thermal_gov_step_wise_unregister(void) {}
-#endif /* CONFIG_THERMAL_GOV_STEP_WISE */
-
-#ifdef CONFIG_THERMAL_GOV_FAIR_SHARE
-int thermal_gov_fair_share_register(void);
-void thermal_gov_fair_share_unregister(void);
-#else
-static inline int thermal_gov_fair_share_register(void) { return 0; }
-static inline void thermal_gov_fair_share_unregister(void) {}
-#endif /* CONFIG_THERMAL_GOV_FAIR_SHARE */
-
-#ifdef CONFIG_THERMAL_GOV_BANG_BANG
-int thermal_gov_bang_bang_register(void);
-void thermal_gov_bang_bang_unregister(void);
-#else
-static inline int thermal_gov_bang_bang_register(void) { return 0; }
-static inline void thermal_gov_bang_bang_unregister(void) {}
-#endif /* CONFIG_THERMAL_GOV_BANG_BANG */
-
-#ifdef CONFIG_THERMAL_GOV_USER_SPACE
-int thermal_gov_user_space_register(void);
-void thermal_gov_user_space_unregister(void);
-#else
-static inline int thermal_gov_user_space_register(void) { return 0; }
-static inline void thermal_gov_user_space_unregister(void) {}
-#endif /* CONFIG_THERMAL_GOV_USER_SPACE */
-
-#ifdef CONFIG_THERMAL_GOV_POWER_ALLOCATOR
-int thermal_gov_power_allocator_register(void);
-void thermal_gov_power_allocator_unregister(void);
-#else
-static inline int thermal_gov_power_allocator_register(void) { return 0; }
-static inline void thermal_gov_power_allocator_unregister(void) {}
-#endif /* CONFIG_THERMAL_GOV_POWER_ALLOCATOR */
-
 /* device tree support */
 #ifdef CONFIG_THERMAL_OF
 int of_parse_thermal_zones(void);
index d62a99f..962873f 100644 (file)
@@ -44,14 +44,4 @@ static struct thermal_governor thermal_gov_user_space = {
        .name           = "user_space",
        .throttle       = notify_user_space,
 };
-
-int thermal_gov_user_space_register(void)
-{
-       return thermal_register_governor(&thermal_gov_user_space);
-}
-
-void thermal_gov_user_space_unregister(void)
-{
-       thermal_unregister_governor(&thermal_gov_user_space);
-}
-
+THERMAL_GOVERNOR_DECLARE(thermal_gov_user_space);
index 0e3e4da..c7623f9 100644 (file)
@@ -93,7 +93,7 @@ config VT_HW_CONSOLE_BINDING
          select the console driver that will serve as the backend for the
          virtual terminals.
 
-        See <file:Documentation/console/console.txt> for more
+        See <file:Documentation/driver-api/console.rst> for more
         information. For framebuffer console users, please refer to
         <file:Documentation/fb/fbcon.rst>.
 
@@ -175,7 +175,7 @@ config ROCKETPORT
          This driver supports Comtrol RocketPort and RocketModem PCI boards.   
           These boards provide 2, 4, 8, 16, or 32 high-speed serial ports or
           modems.  For information about the RocketPort/RocketModem  boards
-          and this driver read <file:Documentation/serial/rocket.rst>.
+          and this driver read <file:Documentation/driver-api/serial/rocket.rst>.
 
          To compile this driver as a module, choose M here: the
          module will be called rocket.
@@ -193,7 +193,7 @@ config CYCLADES
          your Linux box, for instance in order to become a dial-in server.
 
          For information about the Cyclades-Z card, read
-         <file:Documentation/serial/cyclades_z.rst>.
+         <file:Documentation/driver-api/serial/cyclades_z.rst>.
 
          To compile this driver as a module, choose M here: the
          module will be called cyclades.
index b416c7b..fd385c8 100644 (file)
@@ -497,10 +497,11 @@ config SERIAL_SA1100
        bool "SA1100 serial port support"
        depends on ARCH_SA1100
        select SERIAL_CORE
+       select SERIAL_MCTRL_GPIO if GPIOLIB
        help
          If you have a machine based on a SA1100/SA1110 StrongARM(R) CPU you
          can enable its onboard serial port by enabling this option.
-         Please read <file:Documentation/arm/SA1100/serial_UART> for further
+         Please read <file:Documentation/arm/sa1100/serial_uart.rst> for further
          info.
 
 config SERIAL_SA1100_CONSOLE
index a399772..8e61812 100644 (file)
@@ -28,6 +28,8 @@
 #include <mach/hardware.h>
 #include <mach/irqs.h>
 
+#include "serial_mctrl_gpio.h"
+
 /* We've been assigned a range on the "Low-density serial ports" major */
 #define SERIAL_SA1100_MAJOR    204
 #define MINOR_START            5
@@ -77,6 +79,7 @@ struct sa1100_port {
        struct uart_port        port;
        struct timer_list       timer;
        unsigned int            old_status;
+       struct mctrl_gpios      *gpios;
 };
 
 /*
@@ -174,6 +177,8 @@ static void sa1100_enable_ms(struct uart_port *port)
                container_of(port, struct sa1100_port, port);
 
        mod_timer(&sport->timer, jiffies);
+
+       mctrl_gpio_enable_ms(sport->gpios);
 }
 
 static void
@@ -322,11 +327,21 @@ static unsigned int sa1100_tx_empty(struct uart_port *port)
 
 static unsigned int sa1100_get_mctrl(struct uart_port *port)
 {
-       return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+       struct sa1100_port *sport =
+               container_of(port, struct sa1100_port, port);
+       int ret = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+
+       mctrl_gpio_get(sport->gpios, &ret);
+
+       return ret;
 }
 
 static void sa1100_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
+       struct sa1100_port *sport =
+               container_of(port, struct sa1100_port, port);
+
+       mctrl_gpio_set(sport->gpios, mctrl);
 }
 
 /*
@@ -842,6 +857,31 @@ static int sa1100_serial_resume(struct platform_device *dev)
        return 0;
 }
 
+static int sa1100_serial_add_one_port(struct sa1100_port *sport, struct platform_device *dev)
+{
+       sport->port.dev = &dev->dev;
+
+       // mctrl_gpio_init() requires that the GPIO driver supports interrupts,
+       // but we need to support GPIO drivers for hardware that has no such
+       // interrupts.  Use mctrl_gpio_init_noauto() instead.
+       sport->gpios = mctrl_gpio_init_noauto(sport->port.dev, 0);
+       if (IS_ERR(sport->gpios)) {
+               int err = PTR_ERR(sport->gpios);
+
+               dev_err(sport->port.dev, "failed to get mctrl gpios: %d\n",
+                       err);
+
+               if (err == -EPROBE_DEFER)
+                       return err;
+
+               sport->gpios = NULL;
+       }
+
+       platform_set_drvdata(dev, sport);
+
+       return uart_add_one_port(&sa1100_reg, &sport->port);
+}
+
 static int sa1100_serial_probe(struct platform_device *dev)
 {
        struct resource *res = dev->resource;
@@ -856,9 +896,7 @@ static int sa1100_serial_probe(struct platform_device *dev)
                        if (sa1100_ports[i].port.mapbase != res->start)
                                continue;
 
-                       sa1100_ports[i].port.dev = &dev->dev;
-                       uart_add_one_port(&sa1100_reg, &sa1100_ports[i].port);
-                       platform_set_drvdata(dev, &sa1100_ports[i]);
+                       sa1100_serial_add_one_port(&sa1100_ports[i], dev);
                        break;
                }
        }
index 6e3c66a..a0555ae 100644 (file)
@@ -1081,7 +1081,7 @@ static int qe_uart_verify_port(struct uart_port *port,
 }
 /* UART operations
  *
- * Details on these functions can be found in Documentation/serial/driver.rst
+ * Details on these functions can be found in Documentation/driver-api/serial/driver.rst
  */
 static const struct uart_ops qe_uart_pops = {
        .tx_empty       = qe_uart_tx_empty,
index fde8d40..4c49f53 100644 (file)
@@ -855,8 +855,6 @@ void tty_ldisc_deinit(struct tty_struct *tty)
        tty->ldisc = NULL;
 }
 
-static int zero;
-static int one = 1;
 static struct ctl_table tty_table[] = {
        {
                .procname       = "ldisc_autoload",
@@ -864,8 +862,8 @@ static struct ctl_table tty_table[] = {
                .maxlen         = sizeof(tty_ldisc_autoload),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        { }
 };
index 249277d..b47938d 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/fs.h>
+#include <linux/fs_context.h>
 #include <linux/pagemap.h>
 #include <linux/uts.h>
 #include <linux/wait.h>
@@ -1990,7 +1991,7 @@ static const struct super_operations gadget_fs_operations = {
 };
 
 static int
-gadgetfs_fill_super (struct super_block *sb, void *opts, int silent)
+gadgetfs_fill_super (struct super_block *sb, struct fs_context *fc)
 {
        struct inode    *inode;
        struct dev_data *dev;
@@ -2044,11 +2045,19 @@ Enomem:
 }
 
 /* "mount -t gadgetfs path /dev/gadget" ends up here */
-static struct dentry *
-gadgetfs_mount (struct file_system_type *t, int flags,
-               const char *path, void *opts)
+static int gadgetfs_get_tree(struct fs_context *fc)
 {
-       return mount_single (t, flags, opts, gadgetfs_fill_super);
+       return get_tree_single(fc, gadgetfs_fill_super);
+}
+
+static const struct fs_context_operations gadgetfs_context_ops = {
+       .get_tree       = gadgetfs_get_tree,
+};
+
+static int gadgetfs_init_fs_context(struct fs_context *fc)
+{
+       fc->ops = &gadgetfs_context_ops;
+       return 0;
 }
 
 static void
@@ -2068,7 +2077,7 @@ gadgetfs_kill_sb (struct super_block *sb)
 static struct file_system_type gadgetfs_type = {
        .owner          = THIS_MODULE,
        .name           = shortname,
-       .mount          = gadgetfs_mount,
+       .init_fs_context = gadgetfs_init_fs_context,
        .kill_sb        = gadgetfs_kill_sb,
 };
 MODULE_ALIAS_FS("gadgetfs");
index e5a7a45..fd17db9 100644 (file)
@@ -25,7 +25,7 @@ menuconfig VFIO
        select VFIO_IOMMU_TYPE1 if (X86 || S390 || ARM || ARM64)
        help
          VFIO provides a framework for secure userspace device drivers.
-         See Documentation/vfio.txt for more details.
+         See Documentation/driver-api/vfio.rst for more details.
 
          If you don't know what to do here, say N.
 
index ba94a07..5da27f2 100644 (file)
@@ -6,7 +6,7 @@ config VFIO_MDEV
        default n
        help
          Provides a framework to virtualize devices.
-         See Documentation/vfio-mediated-device.txt for more details.
+         See Documentation/driver-api/vfio-mediated-device.rst for more details.
 
          If you don't know what do here, say N.
 
index ed86087..b558d4c 100644 (file)
@@ -143,6 +143,8 @@ int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops)
 {
        int ret;
        struct mdev_parent *parent;
+       char *env_string = "MDEV_STATE=registered";
+       char *envp[] = { env_string, NULL };
 
        /* check for mandatory ops */
        if (!ops || !ops->create || !ops->remove || !ops->supported_type_groups)
@@ -194,6 +196,8 @@ int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops)
        mutex_unlock(&parent_list_lock);
 
        dev_info(dev, "MDEV: Registered\n");
+       kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
+
        return 0;
 
 add_dev_err:
@@ -217,6 +221,8 @@ EXPORT_SYMBOL(mdev_register_device);
 void mdev_unregister_device(struct device *dev)
 {
        struct mdev_parent *parent;
+       char *env_string = "MDEV_STATE=unregistered";
+       char *envp[] = { env_string, NULL };
 
        mutex_lock(&parent_list_lock);
        parent = __find_parent_device(dev);
@@ -240,6 +246,9 @@ void mdev_unregister_device(struct device *dev)
        up_write(&parent->unreg_sem);
 
        mdev_put_parent(parent);
+
+       /* We still have the caller's reference to use for the uevent */
+       kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
 }
 EXPORT_SYMBOL(mdev_unregister_device);
 
index 50fe3c4..f2983f0 100644 (file)
@@ -161,8 +161,7 @@ static int vfio_pci_nvgpu_mmap(struct vfio_pci_device *vdev,
 
        atomic_inc(&data->mm->mm_count);
        ret = (int) mm_iommu_newdev(data->mm, data->useraddr,
-                       (vma->vm_end - vma->vm_start) >> PAGE_SHIFT,
-                       data->gpu_hpa, &data->mem);
+                       vma_pages(vma), data->gpu_hpa, &data->mem);
 
        trace_vfio_pci_nvgpu_mmap(vdev->pdev, data->gpu_hpa, data->useraddr,
                        vma->vm_end - vma->vm_start, ret);
index 7048c91..8ce9ad2 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/vmalloc.h>
 #include <linux/sched/mm.h>
 #include <linux/sched/signal.h>
+#include <linux/mm.h>
 
 #include <asm/iommu.h>
 #include <asm/tce.h>
 static void tce_iommu_detach_group(void *iommu_data,
                struct iommu_group *iommu_group);
 
-static long try_increment_locked_vm(struct mm_struct *mm, long npages)
-{
-       long ret = 0, locked, lock_limit;
-
-       if (WARN_ON_ONCE(!mm))
-               return -EPERM;
-
-       if (!npages)
-               return 0;
-
-       down_write(&mm->mmap_sem);
-       locked = mm->locked_vm + npages;
-       lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
-       if (locked > lock_limit && !capable(CAP_IPC_LOCK))
-               ret = -ENOMEM;
-       else
-               mm->locked_vm += npages;
-
-       pr_debug("[%d] RLIMIT_MEMLOCK +%ld %ld/%ld%s\n", current->pid,
-                       npages << PAGE_SHIFT,
-                       mm->locked_vm << PAGE_SHIFT,
-                       rlimit(RLIMIT_MEMLOCK),
-                       ret ? " - exceeded" : "");
-
-       up_write(&mm->mmap_sem);
-
-       return ret;
-}
-
-static void decrement_locked_vm(struct mm_struct *mm, long npages)
-{
-       if (!mm || !npages)
-               return;
-
-       down_write(&mm->mmap_sem);
-       if (WARN_ON_ONCE(npages > mm->locked_vm))
-               npages = mm->locked_vm;
-       mm->locked_vm -= npages;
-       pr_debug("[%d] RLIMIT_MEMLOCK -%ld %ld/%ld\n", current->pid,
-                       npages << PAGE_SHIFT,
-                       mm->locked_vm << PAGE_SHIFT,
-                       rlimit(RLIMIT_MEMLOCK));
-       up_write(&mm->mmap_sem);
-}
-
 /*
  * VFIO IOMMU fd for SPAPR_TCE IOMMU implementation
  *
@@ -333,7 +289,7 @@ static int tce_iommu_enable(struct tce_container *container)
                return ret;
 
        locked = table_group->tce32_size >> PAGE_SHIFT;
-       ret = try_increment_locked_vm(container->mm, locked);
+       ret = account_locked_vm(container->mm, locked, true);
        if (ret)
                return ret;
 
@@ -352,7 +308,7 @@ static void tce_iommu_disable(struct tce_container *container)
        container->enabled = false;
 
        BUG_ON(!container->mm);
-       decrement_locked_vm(container->mm, container->locked_pages);
+       account_locked_vm(container->mm, container->locked_pages, false);
 }
 
 static void *tce_iommu_open(unsigned long arg)
@@ -656,7 +612,7 @@ static long tce_iommu_create_table(struct tce_container *container,
        if (!table_size)
                return -EINVAL;
 
-       ret = try_increment_locked_vm(container->mm, table_size >> PAGE_SHIFT);
+       ret = account_locked_vm(container->mm, table_size >> PAGE_SHIFT, true);
        if (ret)
                return ret;
 
@@ -675,7 +631,7 @@ static void tce_iommu_free_table(struct tce_container *container,
        unsigned long pages = tbl->it_allocated_size >> PAGE_SHIFT;
 
        iommu_tce_table_put(tbl);
-       decrement_locked_vm(container->mm, pages);
+       account_locked_vm(container->mm, pages, false);
 }
 
 static long tce_iommu_create_window(struct tce_container *container,
index add34ad..054391f 100644 (file)
@@ -272,21 +272,8 @@ static int vfio_lock_acct(struct vfio_dma *dma, long npage, bool async)
 
        ret = down_write_killable(&mm->mmap_sem);
        if (!ret) {
-               if (npage > 0) {
-                       if (!dma->lock_cap) {
-                               unsigned long limit;
-
-                               limit = task_rlimit(dma->task,
-                                               RLIMIT_MEMLOCK) >> PAGE_SHIFT;
-
-                               if (mm->locked_vm + npage > limit)
-                                       ret = -ENOMEM;
-                       }
-               }
-
-               if (!ret)
-                       mm->locked_vm += npage;
-
+               ret = __account_locked_vm(mm, abs(npage), npage > 0, dma->task,
+                                         dma->lock_cap);
                up_write(&mm->mmap_sem);
        }
 
index 247e558..1a2dd53 100644 (file)
@@ -956,7 +956,7 @@ static void handle_tx(struct vhost_net *net)
        if (!sock)
                goto out;
 
-       if (!vq_iotlb_prefetch(vq))
+       if (!vq_meta_prefetch(vq))
                goto out;
 
        vhost_disable_notify(&net->dev, vq);
@@ -1125,7 +1125,7 @@ static void handle_rx(struct vhost_net *net)
        if (!sock)
                goto out;
 
-       if (!vq_iotlb_prefetch(vq))
+       if (!vq_meta_prefetch(vq))
                goto out;
 
        vhost_disable_notify(&net->dev, vq);
index ff8892c..0536f85 100644 (file)
@@ -298,6 +298,160 @@ static void vhost_vq_meta_reset(struct vhost_dev *d)
                __vhost_vq_meta_reset(d->vqs[i]);
 }
 
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+static void vhost_map_unprefetch(struct vhost_map *map)
+{
+       kfree(map->pages);
+       map->pages = NULL;
+       map->npages = 0;
+       map->addr = NULL;
+}
+
+static void vhost_uninit_vq_maps(struct vhost_virtqueue *vq)
+{
+       struct vhost_map *map[VHOST_NUM_ADDRS];
+       int i;
+
+       spin_lock(&vq->mmu_lock);
+       for (i = 0; i < VHOST_NUM_ADDRS; i++) {
+               map[i] = rcu_dereference_protected(vq->maps[i],
+                                 lockdep_is_held(&vq->mmu_lock));
+               if (map[i])
+                       rcu_assign_pointer(vq->maps[i], NULL);
+       }
+       spin_unlock(&vq->mmu_lock);
+
+       synchronize_rcu();
+
+       for (i = 0; i < VHOST_NUM_ADDRS; i++)
+               if (map[i])
+                       vhost_map_unprefetch(map[i]);
+
+}
+
+static void vhost_reset_vq_maps(struct vhost_virtqueue *vq)
+{
+       int i;
+
+       vhost_uninit_vq_maps(vq);
+       for (i = 0; i < VHOST_NUM_ADDRS; i++)
+               vq->uaddrs[i].size = 0;
+}
+
+static bool vhost_map_range_overlap(struct vhost_uaddr *uaddr,
+                                    unsigned long start,
+                                    unsigned long end)
+{
+       if (unlikely(!uaddr->size))
+               return false;
+
+       return !(end < uaddr->uaddr || start > uaddr->uaddr - 1 + uaddr->size);
+}
+
+static void vhost_invalidate_vq_start(struct vhost_virtqueue *vq,
+                                     int index,
+                                     unsigned long start,
+                                     unsigned long end)
+{
+       struct vhost_uaddr *uaddr = &vq->uaddrs[index];
+       struct vhost_map *map;
+       int i;
+
+       if (!vhost_map_range_overlap(uaddr, start, end))
+               return;
+
+       spin_lock(&vq->mmu_lock);
+       ++vq->invalidate_count;
+
+       map = rcu_dereference_protected(vq->maps[index],
+                                       lockdep_is_held(&vq->mmu_lock));
+       if (map) {
+               if (uaddr->write) {
+                       for (i = 0; i < map->npages; i++)
+                               set_page_dirty(map->pages[i]);
+               }
+               rcu_assign_pointer(vq->maps[index], NULL);
+       }
+       spin_unlock(&vq->mmu_lock);
+
+       if (map) {
+               synchronize_rcu();
+               vhost_map_unprefetch(map);
+       }
+}
+
+static void vhost_invalidate_vq_end(struct vhost_virtqueue *vq,
+                                   int index,
+                                   unsigned long start,
+                                   unsigned long end)
+{
+       if (!vhost_map_range_overlap(&vq->uaddrs[index], start, end))
+               return;
+
+       spin_lock(&vq->mmu_lock);
+       --vq->invalidate_count;
+       spin_unlock(&vq->mmu_lock);
+}
+
+static int vhost_invalidate_range_start(struct mmu_notifier *mn,
+                                       const struct mmu_notifier_range *range)
+{
+       struct vhost_dev *dev = container_of(mn, struct vhost_dev,
+                                            mmu_notifier);
+       int i, j;
+
+       if (!mmu_notifier_range_blockable(range))
+               return -EAGAIN;
+
+       for (i = 0; i < dev->nvqs; i++) {
+               struct vhost_virtqueue *vq = dev->vqs[i];
+
+               for (j = 0; j < VHOST_NUM_ADDRS; j++)
+                       vhost_invalidate_vq_start(vq, j,
+                                                 range->start,
+                                                 range->end);
+       }
+
+       return 0;
+}
+
+static void vhost_invalidate_range_end(struct mmu_notifier *mn,
+                                      const struct mmu_notifier_range *range)
+{
+       struct vhost_dev *dev = container_of(mn, struct vhost_dev,
+                                            mmu_notifier);
+       int i, j;
+
+       for (i = 0; i < dev->nvqs; i++) {
+               struct vhost_virtqueue *vq = dev->vqs[i];
+
+               for (j = 0; j < VHOST_NUM_ADDRS; j++)
+                       vhost_invalidate_vq_end(vq, j,
+                                               range->start,
+                                               range->end);
+       }
+}
+
+static const struct mmu_notifier_ops vhost_mmu_notifier_ops = {
+       .invalidate_range_start = vhost_invalidate_range_start,
+       .invalidate_range_end = vhost_invalidate_range_end,
+};
+
+static void vhost_init_maps(struct vhost_dev *dev)
+{
+       struct vhost_virtqueue *vq;
+       int i, j;
+
+       dev->mmu_notifier.ops = &vhost_mmu_notifier_ops;
+
+       for (i = 0; i < dev->nvqs; ++i) {
+               vq = dev->vqs[i];
+               for (j = 0; j < VHOST_NUM_ADDRS; j++)
+                       RCU_INIT_POINTER(vq->maps[j], NULL);
+       }
+}
+#endif
+
 static void vhost_vq_reset(struct vhost_dev *dev,
                           struct vhost_virtqueue *vq)
 {
@@ -326,7 +480,11 @@ static void vhost_vq_reset(struct vhost_dev *dev,
        vq->busyloop_timeout = 0;
        vq->umem = NULL;
        vq->iotlb = NULL;
+       vq->invalidate_count = 0;
        __vhost_vq_meta_reset(vq);
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+       vhost_reset_vq_maps(vq);
+#endif
 }
 
 static int vhost_worker(void *data)
@@ -427,6 +585,32 @@ bool vhost_exceeds_weight(struct vhost_virtqueue *vq,
 }
 EXPORT_SYMBOL_GPL(vhost_exceeds_weight);
 
+static size_t vhost_get_avail_size(struct vhost_virtqueue *vq,
+                                  unsigned int num)
+{
+       size_t event __maybe_unused =
+              vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
+
+       return sizeof(*vq->avail) +
+              sizeof(*vq->avail->ring) * num + event;
+}
+
+static size_t vhost_get_used_size(struct vhost_virtqueue *vq,
+                                 unsigned int num)
+{
+       size_t event __maybe_unused =
+              vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
+
+       return sizeof(*vq->used) +
+              sizeof(*vq->used->ring) * num + event;
+}
+
+static size_t vhost_get_desc_size(struct vhost_virtqueue *vq,
+                                 unsigned int num)
+{
+       return sizeof(*vq->desc) * num;
+}
+
 void vhost_dev_init(struct vhost_dev *dev,
                    struct vhost_virtqueue **vqs, int nvqs,
                    int iov_limit, int weight, int byte_weight)
@@ -450,7 +634,9 @@ void vhost_dev_init(struct vhost_dev *dev,
        INIT_LIST_HEAD(&dev->read_list);
        INIT_LIST_HEAD(&dev->pending_list);
        spin_lock_init(&dev->iotlb_lock);
-
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+       vhost_init_maps(dev);
+#endif
 
        for (i = 0; i < dev->nvqs; ++i) {
                vq = dev->vqs[i];
@@ -459,6 +645,7 @@ void vhost_dev_init(struct vhost_dev *dev,
                vq->heads = NULL;
                vq->dev = dev;
                mutex_init(&vq->mutex);
+               spin_lock_init(&vq->mmu_lock);
                vhost_vq_reset(dev, vq);
                if (vq->handle_kick)
                        vhost_poll_init(&vq->poll, vq->handle_kick,
@@ -538,7 +725,18 @@ long vhost_dev_set_owner(struct vhost_dev *dev)
        if (err)
                goto err_cgroup;
 
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+       err = mmu_notifier_register(&dev->mmu_notifier, dev->mm);
+       if (err)
+               goto err_mmu_notifier;
+#endif
+
        return 0;
+
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+err_mmu_notifier:
+       vhost_dev_free_iovecs(dev);
+#endif
 err_cgroup:
        kthread_stop(worker);
        dev->worker = NULL;
@@ -629,6 +827,107 @@ static void vhost_clear_msg(struct vhost_dev *dev)
        spin_unlock(&dev->iotlb_lock);
 }
 
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+static void vhost_setup_uaddr(struct vhost_virtqueue *vq,
+                             int index, unsigned long uaddr,
+                             size_t size, bool write)
+{
+       struct vhost_uaddr *addr = &vq->uaddrs[index];
+
+       addr->uaddr = uaddr;
+       addr->size = size;
+       addr->write = write;
+}
+
+static void vhost_setup_vq_uaddr(struct vhost_virtqueue *vq)
+{
+       vhost_setup_uaddr(vq, VHOST_ADDR_DESC,
+                         (unsigned long)vq->desc,
+                         vhost_get_desc_size(vq, vq->num),
+                         false);
+       vhost_setup_uaddr(vq, VHOST_ADDR_AVAIL,
+                         (unsigned long)vq->avail,
+                         vhost_get_avail_size(vq, vq->num),
+                         false);
+       vhost_setup_uaddr(vq, VHOST_ADDR_USED,
+                         (unsigned long)vq->used,
+                         vhost_get_used_size(vq, vq->num),
+                         true);
+}
+
+static int vhost_map_prefetch(struct vhost_virtqueue *vq,
+                              int index)
+{
+       struct vhost_map *map;
+       struct vhost_uaddr *uaddr = &vq->uaddrs[index];
+       struct page **pages;
+       int npages = DIV_ROUND_UP(uaddr->size, PAGE_SIZE);
+       int npinned;
+       void *vaddr, *v;
+       int err;
+       int i;
+
+       spin_lock(&vq->mmu_lock);
+
+       err = -EFAULT;
+       if (vq->invalidate_count)
+               goto err;
+
+       err = -ENOMEM;
+       map = kmalloc(sizeof(*map), GFP_ATOMIC);
+       if (!map)
+               goto err;
+
+       pages = kmalloc_array(npages, sizeof(struct page *), GFP_ATOMIC);
+       if (!pages)
+               goto err_pages;
+
+       err = EFAULT;
+       npinned = __get_user_pages_fast(uaddr->uaddr, npages,
+                                       uaddr->write, pages);
+       if (npinned > 0)
+               release_pages(pages, npinned);
+       if (npinned != npages)
+               goto err_gup;
+
+       for (i = 0; i < npinned; i++)
+               if (PageHighMem(pages[i]))
+                       goto err_gup;
+
+       vaddr = v = page_address(pages[0]);
+
+       /* For simplicity, fallback to userspace address if VA is not
+        * contigious.
+        */
+       for (i = 1; i < npinned; i++) {
+               v += PAGE_SIZE;
+               if (v != page_address(pages[i]))
+                       goto err_gup;
+       }
+
+       map->addr = vaddr + (uaddr->uaddr & (PAGE_SIZE - 1));
+       map->npages = npages;
+       map->pages = pages;
+
+       rcu_assign_pointer(vq->maps[index], map);
+       /* No need for a synchronize_rcu(). This function should be
+        * called by dev->worker so we are serialized with all
+        * readers.
+        */
+       spin_unlock(&vq->mmu_lock);
+
+       return 0;
+
+err_gup:
+       kfree(pages);
+err_pages:
+       kfree(map);
+err:
+       spin_unlock(&vq->mmu_lock);
+       return err;
+}
+#endif
+
 void vhost_dev_cleanup(struct vhost_dev *dev)
 {
        int i;
@@ -658,8 +957,16 @@ void vhost_dev_cleanup(struct vhost_dev *dev)
                kthread_stop(dev->worker);
                dev->worker = NULL;
        }
-       if (dev->mm)
+       if (dev->mm) {
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+               mmu_notifier_unregister(&dev->mmu_notifier, dev->mm);
+#endif
                mmput(dev->mm);
+       }
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+       for (i = 0; i < dev->nvqs; i++)
+               vhost_uninit_vq_maps(dev->vqs[i]);
+#endif
        dev->mm = NULL;
 }
 EXPORT_SYMBOL_GPL(vhost_dev_cleanup);
@@ -886,6 +1193,113 @@ static inline void __user *__vhost_get_user(struct vhost_virtqueue *vq,
        ret; \
 })
 
+static inline int vhost_put_avail_event(struct vhost_virtqueue *vq)
+{
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+       struct vhost_map *map;
+       struct vring_used *used;
+
+       if (!vq->iotlb) {
+               rcu_read_lock();
+
+               map = rcu_dereference(vq->maps[VHOST_ADDR_USED]);
+               if (likely(map)) {
+                       used = map->addr;
+                       *((__virtio16 *)&used->ring[vq->num]) =
+                               cpu_to_vhost16(vq, vq->avail_idx);
+                       rcu_read_unlock();
+                       return 0;
+               }
+
+               rcu_read_unlock();
+       }
+#endif
+
+       return vhost_put_user(vq, cpu_to_vhost16(vq, vq->avail_idx),
+                             vhost_avail_event(vq));
+}
+
+static inline int vhost_put_used(struct vhost_virtqueue *vq,
+                                struct vring_used_elem *head, int idx,
+                                int count)
+{
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+       struct vhost_map *map;
+       struct vring_used *used;
+       size_t size;
+
+       if (!vq->iotlb) {
+               rcu_read_lock();
+
+               map = rcu_dereference(vq->maps[VHOST_ADDR_USED]);
+               if (likely(map)) {
+                       used = map->addr;
+                       size = count * sizeof(*head);
+                       memcpy(used->ring + idx, head, size);
+                       rcu_read_unlock();
+                       return 0;
+               }
+
+               rcu_read_unlock();
+       }
+#endif
+
+       return vhost_copy_to_user(vq, vq->used->ring + idx, head,
+                                 count * sizeof(*head));
+}
+
+static inline int vhost_put_used_flags(struct vhost_virtqueue *vq)
+
+{
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+       struct vhost_map *map;
+       struct vring_used *used;
+
+       if (!vq->iotlb) {
+               rcu_read_lock();
+
+               map = rcu_dereference(vq->maps[VHOST_ADDR_USED]);
+               if (likely(map)) {
+                       used = map->addr;
+                       used->flags = cpu_to_vhost16(vq, vq->used_flags);
+                       rcu_read_unlock();
+                       return 0;
+               }
+
+               rcu_read_unlock();
+       }
+#endif
+
+       return vhost_put_user(vq, cpu_to_vhost16(vq, vq->used_flags),
+                             &vq->used->flags);
+}
+
+static inline int vhost_put_used_idx(struct vhost_virtqueue *vq)
+
+{
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+       struct vhost_map *map;
+       struct vring_used *used;
+
+       if (!vq->iotlb) {
+               rcu_read_lock();
+
+               map = rcu_dereference(vq->maps[VHOST_ADDR_USED]);
+               if (likely(map)) {
+                       used = map->addr;
+                       used->idx = cpu_to_vhost16(vq, vq->last_used_idx);
+                       rcu_read_unlock();
+                       return 0;
+               }
+
+               rcu_read_unlock();
+       }
+#endif
+
+       return vhost_put_user(vq, cpu_to_vhost16(vq, vq->last_used_idx),
+                             &vq->used->idx);
+}
+
 #define vhost_get_user(vq, x, ptr, type)               \
 ({ \
        int ret; \
@@ -924,6 +1338,155 @@ static void vhost_dev_unlock_vqs(struct vhost_dev *d)
                mutex_unlock(&d->vqs[i]->mutex);
 }
 
+static inline int vhost_get_avail_idx(struct vhost_virtqueue *vq,
+                                     __virtio16 *idx)
+{
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+       struct vhost_map *map;
+       struct vring_avail *avail;
+
+       if (!vq->iotlb) {
+               rcu_read_lock();
+
+               map = rcu_dereference(vq->maps[VHOST_ADDR_AVAIL]);
+               if (likely(map)) {
+                       avail = map->addr;
+                       *idx = avail->idx;
+                       rcu_read_unlock();
+                       return 0;
+               }
+
+               rcu_read_unlock();
+       }
+#endif
+
+       return vhost_get_avail(vq, *idx, &vq->avail->idx);
+}
+
+static inline int vhost_get_avail_head(struct vhost_virtqueue *vq,
+                                      __virtio16 *head, int idx)
+{
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+       struct vhost_map *map;
+       struct vring_avail *avail;
+
+       if (!vq->iotlb) {
+               rcu_read_lock();
+
+               map = rcu_dereference(vq->maps[VHOST_ADDR_AVAIL]);
+               if (likely(map)) {
+                       avail = map->addr;
+                       *head = avail->ring[idx & (vq->num - 1)];
+                       rcu_read_unlock();
+                       return 0;
+               }
+
+               rcu_read_unlock();
+       }
+#endif
+
+       return vhost_get_avail(vq, *head,
+                              &vq->avail->ring[idx & (vq->num - 1)]);
+}
+
+static inline int vhost_get_avail_flags(struct vhost_virtqueue *vq,
+                                       __virtio16 *flags)
+{
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+       struct vhost_map *map;
+       struct vring_avail *avail;
+
+       if (!vq->iotlb) {
+               rcu_read_lock();
+
+               map = rcu_dereference(vq->maps[VHOST_ADDR_AVAIL]);
+               if (likely(map)) {
+                       avail = map->addr;
+                       *flags = avail->flags;
+                       rcu_read_unlock();
+                       return 0;
+               }
+
+               rcu_read_unlock();
+       }
+#endif
+
+       return vhost_get_avail(vq, *flags, &vq->avail->flags);
+}
+
+static inline int vhost_get_used_event(struct vhost_virtqueue *vq,
+                                      __virtio16 *event)
+{
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+       struct vhost_map *map;
+       struct vring_avail *avail;
+
+       if (!vq->iotlb) {
+               rcu_read_lock();
+               map = rcu_dereference(vq->maps[VHOST_ADDR_AVAIL]);
+               if (likely(map)) {
+                       avail = map->addr;
+                       *event = (__virtio16)avail->ring[vq->num];
+                       rcu_read_unlock();
+                       return 0;
+               }
+               rcu_read_unlock();
+       }
+#endif
+
+       return vhost_get_avail(vq, *event, vhost_used_event(vq));
+}
+
+static inline int vhost_get_used_idx(struct vhost_virtqueue *vq,
+                                    __virtio16 *idx)
+{
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+       struct vhost_map *map;
+       struct vring_used *used;
+
+       if (!vq->iotlb) {
+               rcu_read_lock();
+
+               map = rcu_dereference(vq->maps[VHOST_ADDR_USED]);
+               if (likely(map)) {
+                       used = map->addr;
+                       *idx = used->idx;
+                       rcu_read_unlock();
+                       return 0;
+               }
+
+               rcu_read_unlock();
+       }
+#endif
+
+       return vhost_get_used(vq, *idx, &vq->used->idx);
+}
+
+static inline int vhost_get_desc(struct vhost_virtqueue *vq,
+                                struct vring_desc *desc, int idx)
+{
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+       struct vhost_map *map;
+       struct vring_desc *d;
+
+       if (!vq->iotlb) {
+               rcu_read_lock();
+
+               map = rcu_dereference(vq->maps[VHOST_ADDR_DESC]);
+               if (likely(map)) {
+                       d = map->addr;
+                       *desc = *(d + idx);
+                       rcu_read_unlock();
+                       return 0;
+               }
+
+               rcu_read_unlock();
+       }
+#endif
+
+       return vhost_copy_from_user(vq, desc, vq->desc + idx, sizeof(*desc));
+}
+
 static int vhost_new_umem_range(struct vhost_umem *umem,
                                u64 start, u64 size, u64 end,
                                u64 userspace_addr, int perm)
@@ -1209,13 +1772,9 @@ static bool vq_access_ok(struct vhost_virtqueue *vq, unsigned int num,
                         struct vring_used __user *used)
 
 {
-       size_t s __maybe_unused = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
-
-       return access_ok(desc, num * sizeof *desc) &&
-              access_ok(avail,
-                        sizeof *avail + num * sizeof *avail->ring + s) &&
-              access_ok(used,
-                       sizeof *used + num * sizeof *used->ring + s);
+       return access_ok(desc, vhost_get_desc_size(vq, num)) &&
+              access_ok(avail, vhost_get_avail_size(vq, num)) &&
+              access_ok(used, vhost_get_used_size(vq, num));
 }
 
 static void vhost_vq_meta_update(struct vhost_virtqueue *vq,
@@ -1265,26 +1824,42 @@ static bool iotlb_access_ok(struct vhost_virtqueue *vq,
        return true;
 }
 
-int vq_iotlb_prefetch(struct vhost_virtqueue *vq)
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+static void vhost_vq_map_prefetch(struct vhost_virtqueue *vq)
+{
+       struct vhost_map __rcu *map;
+       int i;
+
+       for (i = 0; i < VHOST_NUM_ADDRS; i++) {
+               rcu_read_lock();
+               map = rcu_dereference(vq->maps[i]);
+               rcu_read_unlock();
+               if (unlikely(!map))
+                       vhost_map_prefetch(vq, i);
+       }
+}
+#endif
+
+int vq_meta_prefetch(struct vhost_virtqueue *vq)
 {
-       size_t s = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
        unsigned int num = vq->num;
 
-       if (!vq->iotlb)
+       if (!vq->iotlb) {
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+               vhost_vq_map_prefetch(vq);
+#endif
                return 1;
+       }
 
        return iotlb_access_ok(vq, VHOST_ACCESS_RO, (u64)(uintptr_t)vq->desc,
-                              num * sizeof(*vq->desc), VHOST_ADDR_DESC) &&
+                              vhost_get_desc_size(vq, num), VHOST_ADDR_DESC) &&
               iotlb_access_ok(vq, VHOST_ACCESS_RO, (u64)(uintptr_t)vq->avail,
-                              sizeof *vq->avail +
-                              num * sizeof(*vq->avail->ring) + s,
+                              vhost_get_avail_size(vq, num),
                               VHOST_ADDR_AVAIL) &&
               iotlb_access_ok(vq, VHOST_ACCESS_WO, (u64)(uintptr_t)vq->used,
-                              sizeof *vq->used +
-                              num * sizeof(*vq->used->ring) + s,
-                              VHOST_ADDR_USED);
+                              vhost_get_used_size(vq, num), VHOST_ADDR_USED);
 }
-EXPORT_SYMBOL_GPL(vq_iotlb_prefetch);
+EXPORT_SYMBOL_GPL(vq_meta_prefetch);
 
 /* Can we log writes? */
 /* Caller should have device mutex but not vq mutex */
@@ -1299,13 +1874,10 @@ EXPORT_SYMBOL_GPL(vhost_log_access_ok);
 static bool vq_log_access_ok(struct vhost_virtqueue *vq,
                             void __user *log_base)
 {
-       size_t s = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
-
        return vq_memory_access_ok(log_base, vq->umem,
                                   vhost_has_feature(vq, VHOST_F_LOG_ALL)) &&
                (!vq->log_used || log_access_ok(log_base, vq->log_addr,
-                                       sizeof *vq->used +
-                                       vq->num * sizeof *vq->used->ring + s));
+                                 vhost_get_used_size(vq, vq->num)));
 }
 
 /* Can we start vq? */
@@ -1405,6 +1977,121 @@ err:
        return -EFAULT;
 }
 
+static long vhost_vring_set_num(struct vhost_dev *d,
+                               struct vhost_virtqueue *vq,
+                               void __user *argp)
+{
+       struct vhost_vring_state s;
+
+       /* Resizing ring with an active backend?
+        * You don't want to do that. */
+       if (vq->private_data)
+               return -EBUSY;
+
+       if (copy_from_user(&s, argp, sizeof s))
+               return -EFAULT;
+
+       if (!s.num || s.num > 0xffff || (s.num & (s.num - 1)))
+               return -EINVAL;
+       vq->num = s.num;
+
+       return 0;
+}
+
+static long vhost_vring_set_addr(struct vhost_dev *d,
+                                struct vhost_virtqueue *vq,
+                                void __user *argp)
+{
+       struct vhost_vring_addr a;
+
+       if (copy_from_user(&a, argp, sizeof a))
+               return -EFAULT;
+       if (a.flags & ~(0x1 << VHOST_VRING_F_LOG))
+               return -EOPNOTSUPP;
+
+       /* For 32bit, verify that the top 32bits of the user
+          data are set to zero. */
+       if ((u64)(unsigned long)a.desc_user_addr != a.desc_user_addr ||
+           (u64)(unsigned long)a.used_user_addr != a.used_user_addr ||
+           (u64)(unsigned long)a.avail_user_addr != a.avail_user_addr)
+               return -EFAULT;
+
+       /* Make sure it's safe to cast pointers to vring types. */
+       BUILD_BUG_ON(__alignof__ *vq->avail > VRING_AVAIL_ALIGN_SIZE);
+       BUILD_BUG_ON(__alignof__ *vq->used > VRING_USED_ALIGN_SIZE);
+       if ((a.avail_user_addr & (VRING_AVAIL_ALIGN_SIZE - 1)) ||
+           (a.used_user_addr & (VRING_USED_ALIGN_SIZE - 1)) ||
+           (a.log_guest_addr & (VRING_USED_ALIGN_SIZE - 1)))
+               return -EINVAL;
+
+       /* We only verify access here if backend is configured.
+        * If it is not, we don't as size might not have been setup.
+        * We will verify when backend is configured. */
+       if (vq->private_data) {
+               if (!vq_access_ok(vq, vq->num,
+                       (void __user *)(unsigned long)a.desc_user_addr,
+                       (void __user *)(unsigned long)a.avail_user_addr,
+                       (void __user *)(unsigned long)a.used_user_addr))
+                       return -EINVAL;
+
+               /* Also validate log access for used ring if enabled. */
+               if ((a.flags & (0x1 << VHOST_VRING_F_LOG)) &&
+                       !log_access_ok(vq->log_base, a.log_guest_addr,
+                               sizeof *vq->used +
+                               vq->num * sizeof *vq->used->ring))
+                       return -EINVAL;
+       }
+
+       vq->log_used = !!(a.flags & (0x1 << VHOST_VRING_F_LOG));
+       vq->desc = (void __user *)(unsigned long)a.desc_user_addr;
+       vq->avail = (void __user *)(unsigned long)a.avail_user_addr;
+       vq->log_addr = a.log_guest_addr;
+       vq->used = (void __user *)(unsigned long)a.used_user_addr;
+
+       return 0;
+}
+
+static long vhost_vring_set_num_addr(struct vhost_dev *d,
+                                    struct vhost_virtqueue *vq,
+                                    unsigned int ioctl,
+                                    void __user *argp)
+{
+       long r;
+
+       mutex_lock(&vq->mutex);
+
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+       /* Unregister MMU notifer to allow invalidation callback
+        * can access vq->uaddrs[] without holding a lock.
+        */
+       if (d->mm)
+               mmu_notifier_unregister(&d->mmu_notifier, d->mm);
+
+       vhost_uninit_vq_maps(vq);
+#endif
+
+       switch (ioctl) {
+       case VHOST_SET_VRING_NUM:
+               r = vhost_vring_set_num(d, vq, argp);
+               break;
+       case VHOST_SET_VRING_ADDR:
+               r = vhost_vring_set_addr(d, vq, argp);
+               break;
+       default:
+               BUG();
+       }
+
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+       vhost_setup_vq_uaddr(vq);
+
+       if (d->mm)
+               mmu_notifier_register(&d->mmu_notifier, d->mm);
+#endif
+
+       mutex_unlock(&vq->mutex);
+
+       return r;
+}
 long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp)
 {
        struct file *eventfp, *filep = NULL;
@@ -1414,7 +2101,6 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg
        struct vhost_virtqueue *vq;
        struct vhost_vring_state s;
        struct vhost_vring_file f;
-       struct vhost_vring_addr a;
        u32 idx;
        long r;
 
@@ -1427,26 +2113,14 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg
        idx = array_index_nospec(idx, d->nvqs);
        vq = d->vqs[idx];
 
+       if (ioctl == VHOST_SET_VRING_NUM ||
+           ioctl == VHOST_SET_VRING_ADDR) {
+               return vhost_vring_set_num_addr(d, vq, ioctl, argp);
+       }
+
        mutex_lock(&vq->mutex);
 
        switch (ioctl) {
-       case VHOST_SET_VRING_NUM:
-               /* Resizing ring with an active backend?
-                * You don't want to do that. */
-               if (vq->private_data) {
-                       r = -EBUSY;
-                       break;
-               }
-               if (copy_from_user(&s, argp, sizeof s)) {
-                       r = -EFAULT;
-                       break;
-               }
-               if (!s.num || s.num > 0xffff || (s.num & (s.num - 1))) {
-                       r = -EINVAL;
-                       break;
-               }
-               vq->num = s.num;
-               break;
        case VHOST_SET_VRING_BASE:
                /* Moving base with an active backend?
                 * You don't want to do that. */
@@ -1472,62 +2146,6 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg
                if (copy_to_user(argp, &s, sizeof s))
                        r = -EFAULT;
                break;
-       case VHOST_SET_VRING_ADDR:
-               if (copy_from_user(&a, argp, sizeof a)) {
-                       r = -EFAULT;
-                       break;
-               }
-               if (a.flags & ~(0x1 << VHOST_VRING_F_LOG)) {
-                       r = -EOPNOTSUPP;
-                       break;
-               }
-               /* For 32bit, verify that the top 32bits of the user
-                  data are set to zero. */
-               if ((u64)(unsigned long)a.desc_user_addr != a.desc_user_addr ||
-                   (u64)(unsigned long)a.used_user_addr != a.used_user_addr ||
-                   (u64)(unsigned long)a.avail_user_addr != a.avail_user_addr) {
-                       r = -EFAULT;
-                       break;
-               }
-
-               /* Make sure it's safe to cast pointers to vring types. */
-               BUILD_BUG_ON(__alignof__ *vq->avail > VRING_AVAIL_ALIGN_SIZE);
-               BUILD_BUG_ON(__alignof__ *vq->used > VRING_USED_ALIGN_SIZE);
-               if ((a.avail_user_addr & (VRING_AVAIL_ALIGN_SIZE - 1)) ||
-                   (a.used_user_addr & (VRING_USED_ALIGN_SIZE - 1)) ||
-                   (a.log_guest_addr & (VRING_USED_ALIGN_SIZE - 1))) {
-                       r = -EINVAL;
-                       break;
-               }
-
-               /* We only verify access here if backend is configured.
-                * If it is not, we don't as size might not have been setup.
-                * We will verify when backend is configured. */
-               if (vq->private_data) {
-                       if (!vq_access_ok(vq, vq->num,
-                               (void __user *)(unsigned long)a.desc_user_addr,
-                               (void __user *)(unsigned long)a.avail_user_addr,
-                               (void __user *)(unsigned long)a.used_user_addr)) {
-                               r = -EINVAL;
-                               break;
-                       }
-
-                       /* Also validate log access for used ring if enabled. */
-                       if ((a.flags & (0x1 << VHOST_VRING_F_LOG)) &&
-                           !log_access_ok(vq->log_base, a.log_guest_addr,
-                                          sizeof *vq->used +
-                                          vq->num * sizeof *vq->used->ring)) {
-                               r = -EINVAL;
-                               break;
-                       }
-               }
-
-               vq->log_used = !!(a.flags & (0x1 << VHOST_VRING_F_LOG));
-               vq->desc = (void __user *)(unsigned long)a.desc_user_addr;
-               vq->avail = (void __user *)(unsigned long)a.avail_user_addr;
-               vq->log_addr = a.log_guest_addr;
-               vq->used = (void __user *)(unsigned long)a.used_user_addr;
-               break;
        case VHOST_SET_VRING_KICK:
                if (copy_from_user(&f, argp, sizeof f)) {
                        r = -EFAULT;
@@ -1861,8 +2479,7 @@ EXPORT_SYMBOL_GPL(vhost_log_write);
 static int vhost_update_used_flags(struct vhost_virtqueue *vq)
 {
        void __user *used;
-       if (vhost_put_user(vq, cpu_to_vhost16(vq, vq->used_flags),
-                          &vq->used->flags) < 0)
+       if (vhost_put_used_flags(vq))
                return -EFAULT;
        if (unlikely(vq->log_used)) {
                /* Make sure the flag is seen before log. */
@@ -1879,8 +2496,7 @@ static int vhost_update_used_flags(struct vhost_virtqueue *vq)
 
 static int vhost_update_avail_event(struct vhost_virtqueue *vq, u16 avail_event)
 {
-       if (vhost_put_user(vq, cpu_to_vhost16(vq, vq->avail_idx),
-                          vhost_avail_event(vq)))
+       if (vhost_put_avail_event(vq))
                return -EFAULT;
        if (unlikely(vq->log_used)) {
                void __user *used;
@@ -1916,7 +2532,7 @@ int vhost_vq_init_access(struct vhost_virtqueue *vq)
                r = -EFAULT;
                goto err;
        }
-       r = vhost_get_used(vq, last_used_idx, &vq->used->idx);
+       r = vhost_get_used_idx(vq, &last_used_idx);
        if (r) {
                vq_err(vq, "Can't access used idx at %p\n",
                       &vq->used->idx);
@@ -2115,7 +2731,7 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
        last_avail_idx = vq->last_avail_idx;
 
        if (vq->avail_idx == vq->last_avail_idx) {
-               if (unlikely(vhost_get_avail(vq, avail_idx, &vq->avail->idx))) {
+               if (unlikely(vhost_get_avail_idx(vq, &avail_idx))) {
                        vq_err(vq, "Failed to access avail idx at %p\n",
                                &vq->avail->idx);
                        return -EFAULT;
@@ -2142,8 +2758,7 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
 
        /* Grab the next descriptor number they're advertising, and increment
         * the index we've seen. */
-       if (unlikely(vhost_get_avail(vq, ring_head,
-                    &vq->avail->ring[last_avail_idx & (vq->num - 1)]))) {
+       if (unlikely(vhost_get_avail_head(vq, &ring_head, last_avail_idx))) {
                vq_err(vq, "Failed to read head: idx %d address %p\n",
                       last_avail_idx,
                       &vq->avail->ring[last_avail_idx % vq->num]);
@@ -2178,8 +2793,7 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
                               i, vq->num, head);
                        return -EINVAL;
                }
-               ret = vhost_copy_from_user(vq, &desc, vq->desc + i,
-                                          sizeof desc);
+               ret = vhost_get_desc(vq, &desc, i);
                if (unlikely(ret)) {
                        vq_err(vq, "Failed to get descriptor: idx %d addr %p\n",
                               i, vq->desc + i);
@@ -2272,16 +2886,7 @@ static int __vhost_add_used_n(struct vhost_virtqueue *vq,
 
        start = vq->last_used_idx & (vq->num - 1);
        used = vq->used->ring + start;
-       if (count == 1) {
-               if (vhost_put_user(vq, heads[0].id, &used->id)) {
-                       vq_err(vq, "Failed to write used id");
-                       return -EFAULT;
-               }
-               if (vhost_put_user(vq, heads[0].len, &used->len)) {
-                       vq_err(vq, "Failed to write used len");
-                       return -EFAULT;
-               }
-       } else if (vhost_copy_to_user(vq, used, heads, count * sizeof *used)) {
+       if (vhost_put_used(vq, heads, start, count)) {
                vq_err(vq, "Failed to write used");
                return -EFAULT;
        }
@@ -2323,8 +2928,7 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
 
        /* Make sure buffer is written before we update index. */
        smp_wmb();
-       if (vhost_put_user(vq, cpu_to_vhost16(vq, vq->last_used_idx),
-                          &vq->used->idx)) {
+       if (vhost_put_used_idx(vq)) {
                vq_err(vq, "Failed to increment used idx");
                return -EFAULT;
        }
@@ -2357,7 +2961,7 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
 
        if (!vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX)) {
                __virtio16 flags;
-               if (vhost_get_avail(vq, flags, &vq->avail->flags)) {
+               if (vhost_get_avail_flags(vq, &flags)) {
                        vq_err(vq, "Failed to get flags");
                        return true;
                }
@@ -2371,7 +2975,7 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
        if (unlikely(!v))
                return true;
 
-       if (vhost_get_avail(vq, event, vhost_used_event(vq))) {
+       if (vhost_get_used_event(vq, &event)) {
                vq_err(vq, "Failed to get used event idx");
                return true;
        }
@@ -2416,7 +3020,7 @@ bool vhost_vq_avail_empty(struct vhost_dev *dev, struct vhost_virtqueue *vq)
        if (vq->avail_idx != vq->last_avail_idx)
                return false;
 
-       r = vhost_get_avail(vq, avail_idx, &vq->avail->idx);
+       r = vhost_get_avail_idx(vq, &avail_idx);
        if (unlikely(r))
                return false;
        vq->avail_idx = vhost16_to_cpu(vq, avail_idx);
@@ -2452,7 +3056,7 @@ bool vhost_enable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
        /* They could have slipped one in as we were doing that: make
         * sure it's written, then check again. */
        smp_mb();
-       r = vhost_get_avail(vq, avail_idx, &vq->avail->idx);
+       r = vhost_get_avail_idx(vq, &avail_idx);
        if (r) {
                vq_err(vq, "Failed to check avail idx at %p: %d\n",
                       &vq->avail->idx, r);
index 27a78a9..8192963 100644 (file)
@@ -12,6 +12,9 @@
 #include <linux/virtio_config.h>
 #include <linux/virtio_ring.h>
 #include <linux/atomic.h>
+#include <linux/pagemap.h>
+#include <linux/mmu_notifier.h>
+#include <asm/cacheflush.h>
 
 struct vhost_work;
 typedef void (*vhost_work_fn_t)(struct vhost_work *work);
@@ -80,6 +83,24 @@ enum vhost_uaddr_type {
        VHOST_NUM_ADDRS = 3,
 };
 
+struct vhost_map {
+       int npages;
+       void *addr;
+       struct page **pages;
+};
+
+struct vhost_uaddr {
+       unsigned long uaddr;
+       size_t size;
+       bool write;
+};
+
+#if defined(CONFIG_MMU_NOTIFIER) && ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE == 0
+#define VHOST_ARCH_CAN_ACCEL_UACCESS 1
+#else
+#define VHOST_ARCH_CAN_ACCEL_UACCESS 0
+#endif
+
 /* The virtqueue structure describes a queue attached to a device. */
 struct vhost_virtqueue {
        struct vhost_dev *dev;
@@ -90,7 +111,22 @@ struct vhost_virtqueue {
        struct vring_desc __user *desc;
        struct vring_avail __user *avail;
        struct vring_used __user *used;
+
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+       /* Read by memory accessors, modified by meta data
+        * prefetching, MMU notifier and vring ioctl().
+        * Synchonrized through mmu_lock (writers) and RCU (writers
+        * and readers).
+        */
+       struct vhost_map __rcu *maps[VHOST_NUM_ADDRS];
+       /* Read by MMU notifier, modified by vring ioctl(),
+        * synchronized through MMU notifier
+        * registering/unregistering.
+        */
+       struct vhost_uaddr uaddrs[VHOST_NUM_ADDRS];
+#endif
        const struct vhost_umem_node *meta_iotlb[VHOST_NUM_ADDRS];
+
        struct file *kick;
        struct eventfd_ctx *call_ctx;
        struct eventfd_ctx *error_ctx;
@@ -145,6 +181,8 @@ struct vhost_virtqueue {
        bool user_be;
 #endif
        u32 busyloop_timeout;
+       spinlock_t mmu_lock;
+       int invalidate_count;
 };
 
 struct vhost_msg_node {
@@ -158,6 +196,9 @@ struct vhost_msg_node {
 
 struct vhost_dev {
        struct mm_struct *mm;
+#ifdef CONFIG_MMU_NOTIFIER
+       struct mmu_notifier mmu_notifier;
+#endif
        struct mutex mutex;
        struct vhost_virtqueue **vqs;
        int nvqs;
@@ -212,7 +253,7 @@ bool vhost_enable_notify(struct vhost_dev *, struct vhost_virtqueue *);
 int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
                    unsigned int log_num, u64 len,
                    struct iovec *iov, int count);
-int vq_iotlb_prefetch(struct vhost_virtqueue *vq);
+int vq_meta_prefetch(struct vhost_virtqueue *vq);
 
 struct vhost_msg_node *vhost_new_msg(struct vhost_virtqueue *vq, int type);
 void vhost_enqueue_msg(struct vhost_dev *dev,
index b9300f3..e84f308 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/of_gpio.h>
 #include <linux/platform_data/gpio_backlight.h>
 #include <linux/platform_device.h>
+#include <linux/property.h>
 #include <linux/slab.h>
 
 struct gpio_backlight {
@@ -58,11 +59,10 @@ static int gpio_backlight_probe_dt(struct platform_device *pdev,
                                   struct gpio_backlight *gbl)
 {
        struct device *dev = &pdev->dev;
-       struct device_node *np = dev->of_node;
        enum gpiod_flags flags;
        int ret;
 
-       gbl->def_value = of_property_read_bool(np, "default-on");
+       gbl->def_value = device_property_read_bool(dev, "default-on");
        flags = gbl->def_value ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
 
        gbl->gpiod = devm_gpiod_get(dev, NULL, flags);
@@ -86,26 +86,19 @@ static int gpio_backlight_probe(struct platform_device *pdev)
        struct backlight_properties props;
        struct backlight_device *bl;
        struct gpio_backlight *gbl;
-       struct device_node *np = pdev->dev.of_node;
        int ret;
 
-       if (!pdata && !np) {
-               dev_err(&pdev->dev,
-                       "failed to find platform data or device tree node.\n");
-               return -ENODEV;
-       }
-
        gbl = devm_kzalloc(&pdev->dev, sizeof(*gbl), GFP_KERNEL);
        if (gbl == NULL)
                return -ENOMEM;
 
        gbl->dev = &pdev->dev;
 
-       if (np) {
+       if (pdev->dev.fwnode) {
                ret = gpio_backlight_probe_dt(pdev, gbl);
                if (ret)
                        return ret;
-       } else {
+       } else if (pdata) {
                /*
                 * Legacy platform data GPIO retrieveal. Do not expand
                 * the use of this code path, currently only used by one
@@ -126,6 +119,10 @@ static int gpio_backlight_probe(struct platform_device *pdev)
                gbl->gpiod = gpio_to_desc(pdata->gpio);
                if (!gbl->gpiod)
                        return -EINVAL;
+       } else {
+               dev_err(&pdev->dev,
+                       "failed to find platform data or device tree node.\n");
+               return -ENODEV;
        }
 
        memset(&props, 0, sizeof(props));
@@ -146,19 +143,17 @@ static int gpio_backlight_probe(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_OF
 static struct of_device_id gpio_backlight_of_match[] = {
        { .compatible = "gpio-backlight" },
        { /* sentinel */ }
 };
 
 MODULE_DEVICE_TABLE(of, gpio_backlight_of_match);
-#endif
 
 static struct platform_driver gpio_backlight_driver = {
        .driver         = {
                .name           = "gpio-backlight",
-               .of_match_table = of_match_ptr(gpio_backlight_of_match),
+               .of_match_table = gpio_backlight_of_match,
        },
        .probe          = gpio_backlight_probe,
 };
index 20d379a..2201b8c 100644 (file)
@@ -1,8 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * linux/drivers/video/backlight/pwm_bl.c
- *
- * simple PWM based backlight control, board code has to setup
+ * Simple PWM based backlight control, board code has to setup
  * 1) pin configuration so PWM waveforms can output
  * 2) platform_data being correctly configured
  */
@@ -191,29 +189,17 @@ int pwm_backlight_brightness_default(struct device *dev,
                                     struct platform_pwm_backlight_data *data,
                                     unsigned int period)
 {
-       unsigned int counter = 0;
-       unsigned int i, n;
+       unsigned int i;
        u64 retval;
 
        /*
-        * Count the number of bits needed to represent the period number. The
-        * number of bits is used to calculate the number of levels used for the
-        * brightness-levels table, the purpose of this calculation is have a
-        * pre-computed table with enough levels to get linear brightness
-        * perception. The period is divided by the number of bits so for a
-        * 8-bit PWM we have 255 / 8 = 32 brightness levels or for a 16-bit PWM
-        * we have 65535 / 16 = 4096 brightness levels.
-        *
-        * Note that this method is based on empirical testing on different
-        * devices with PWM of 8 and 16 bits of resolution.
+        * Once we have 4096 levels there's little point going much higher...
+        * neither interactive sliders nor animation benefits from having
+        * more values in the table.
         */
-       n = period;
-       while (n) {
-               counter += n % 2;
-               n >>= 1;
-       }
+       data->max_brightness =
+               min((int)DIV_ROUND_UP(period, fls(period)), 4096);
 
-       data->max_brightness = DIV_ROUND_UP(period, counter);
        data->levels = devm_kcalloc(dev, data->max_brightness,
                                    sizeof(*data->levels), GFP_KERNEL);
        if (!data->levels)
@@ -705,5 +691,5 @@ static struct platform_driver pwm_backlight_driver = {
 module_platform_driver(pwm_backlight_driver);
 
 MODULE_DESCRIPTION("PWM based Backlight Driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:pwm-backlight");
index 023fc3b..078615c 100644 (file)
@@ -43,6 +43,17 @@ config VIRTIO_PCI_LEGACY
 
          If unsure, say Y.
 
+config VIRTIO_PMEM
+       tristate "Support for virtio pmem driver"
+       depends on VIRTIO
+       depends on LIBNVDIMM
+       help
+         This driver provides access to virtio-pmem devices, storage devices
+         that are mapped into the physical address space - similar to NVDIMMs
+          - with a virtio-based flushing interface.
+
+         If unsure, say Y.
+
 config VIRTIO_BALLOON
        tristate "Virtio balloon driver"
        depends on VIRTIO
index 44339fc..226fbb9 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/mm.h>
 #include <linux/mount.h>
 #include <linux/magic.h>
+#include <linux/pseudo_fs.h>
 
 /*
  * Balloon device works in 4K page units.  So each page is pointed to by
@@ -745,20 +746,14 @@ static int virtballoon_migratepage(struct balloon_dev_info *vb_dev_info,
        return MIGRATEPAGE_SUCCESS;
 }
 
-static struct dentry *balloon_mount(struct file_system_type *fs_type,
-               int flags, const char *dev_name, void *data)
+static int balloon_init_fs_context(struct fs_context *fc)
 {
-       static const struct dentry_operations ops = {
-               .d_dname = simple_dname,
-       };
-
-       return mount_pseudo(fs_type, "balloon-kvm:", NULL, &ops,
-                               BALLOON_KVM_MAGIC);
+       return init_pseudo(fc, BALLOON_KVM_MAGIC) ? 0 : -ENOMEM;
 }
 
 static struct file_system_type balloon_fs = {
        .name           = "balloon-kvm",
-       .mount          = balloon_mount,
+       .init_fs_context = balloon_init_fs_context,
        .kill_sb        = kill_anon_super,
 };
 
index f363fbe..e09edb5 100644 (file)
@@ -463,9 +463,14 @@ static int vm_find_vqs(struct virtio_device *vdev, unsigned nvqs,
                       struct irq_affinity *desc)
 {
        struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
-       unsigned int irq = platform_get_irq(vm_dev->pdev, 0);
+       int irq = platform_get_irq(vm_dev->pdev, 0);
        int i, err, queue_idx = 0;
 
+       if (irq < 0) {
+               dev_err(&vdev->dev, "Cannot get IRQ resource\n");
+               return irq;
+       }
+
        err = request_irq(irq, vm_interrupt, IRQF_SHARED,
                        dev_name(&vdev->dev), vm_dev);
        if (err)
index 03dd575..3e7ad7b 100644 (file)
@@ -19,7 +19,7 @@ config W1_CON
        default y
        ---help---
          This allows to communicate with userspace using connector. For more
-         information see <file:Documentation/connector/connector.txt>.
+         information see <file:Documentation/driver-api/connector.rst>.
          There are three types of messages between w1 core and userspace:
          1. Events. They are generated each time new master or slave device found
                either due to automatic or requested search.
index 6cad0b3..8188963 100644 (file)
@@ -58,6 +58,15 @@ config WATCHDOG_HANDLE_BOOT_ENABLED
          the watchdog on its own. Thus if your userspace does not start fast
          enough your device will reboot.
 
+config WATCHDOG_OPEN_TIMEOUT
+       int "Timeout value for opening watchdog device"
+       default 0
+       help
+         The maximum time, in seconds, for which the watchdog framework takes
+         care of pinging a hardware watchdog.  A value of 0 means infinite. The
+         value set here can be overridden by the commandline parameter
+         "watchdog.open_timeout".
+
 config WATCHDOG_SYSFS
        bool "Read different watchdog information through sysfs"
        help
@@ -717,6 +726,7 @@ config IMX2_WDT
 config IMX_SC_WDT
        tristate "IMX SC Watchdog"
        depends on HAVE_ARM_SMCCC
+       depends on IMX_SCU
        select WATCHDOG_CORE
        help
          This is the driver for the system controller watchdog
index 957d125..848db95 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  *     Acquire Single Board Computer Watchdog Timer driver
  *
@@ -6,11 +7,6 @@
  *     (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
  *                                             All Rights Reserved.
  *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
  *     Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
  *     warranty for any of this software. This material is provided
  *     "AS-IS" and at no charge.
index 2766af2..0d02bb2 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  *     Advantech Single Board Computer WDT driver
  *
@@ -9,11 +10,6 @@
  *     (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
  *                                             All Rights Reserved.
  *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
  *     Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
  *     warranty for any of this software. This material is provided
  *     "AS-IS" and at no charge.
index f014863..cc71861 100644 (file)
@@ -309,13 +309,7 @@ static int aspeed_wdt_probe(struct platform_device *pdev)
        if (status & WDT_TIMEOUT_STATUS_BOOT_SECONDARY)
                wdt->wdd.bootstatus = WDIOF_CARDRESET;
 
-       ret = devm_watchdog_register_device(dev, &wdt->wdd);
-       if (ret) {
-               dev_err(dev, "failed to register\n");
-               return ret;
-       }
-
-       return 0;
+       return devm_watchdog_register_device(dev, &wdt->wdd);
 }
 
 static struct platform_driver aspeed_watchdog_driver = {
index 560c1c5..dec6ca0 100644 (file)
@@ -202,10 +202,8 @@ static int bcm2835_wdt_probe(struct platform_device *pdev)
 
        watchdog_stop_on_reboot(&bcm2835_wdt_wdd);
        err = devm_watchdog_register_device(dev, &bcm2835_wdt_wdd);
-       if (err) {
-               dev_err(dev, "Failed to register watchdog device");
+       if (err)
                return err;
-       }
 
        if (pm_power_off == NULL) {
                pm_power_off = bcm2835_power_off;
@@ -240,6 +238,7 @@ module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
+MODULE_ALIAS("platform:bcm2835-wdt");
 MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
 MODULE_DESCRIPTION("Driver for Broadcom BCM2835 watchdog timer");
 MODULE_LICENSE("GPL");
index d3d88f6..979caa1 100644 (file)
@@ -159,10 +159,8 @@ static int bcm7038_wdt_probe(struct platform_device *pdev)
        watchdog_stop_on_reboot(&wdt->wdd);
        watchdog_stop_on_unregister(&wdt->wdd);
        err = devm_watchdog_register_device(dev, &wdt->wdd);
-       if (err) {
-               dev_err(dev, "Failed to register watchdog device\n");
+       if (err)
                return err;
-       }
 
        dev_info(dev, "Registered BCM7038 Watchdog\n");
 
index 9212910..eb850a8 100644 (file)
@@ -301,10 +301,8 @@ static int bcm_kona_wdt_probe(struct platform_device *pdev)
        watchdog_stop_on_reboot(&bcm_kona_wdt_wdd);
        watchdog_stop_on_unregister(&bcm_kona_wdt_wdd);
        ret = devm_watchdog_register_device(dev, &bcm_kona_wdt_wdd);
-       if (ret) {
-               dev_err(dev, "Failed to register watchdog device");
+       if (ret)
                return ret;
-       }
 
        bcm_kona_wdt_debug_init(pdev);
        dev_dbg(dev, "Broadcom Kona Watchdog Timer");
index a22f2d4..f8d4e91 100644 (file)
@@ -363,10 +363,8 @@ static int cdns_wdt_probe(struct platform_device *pdev)
        watchdog_stop_on_reboot(cdns_wdt_device);
        watchdog_stop_on_unregister(cdns_wdt_device);
        ret = devm_watchdog_register_device(dev, cdns_wdt_device);
-       if (ret) {
-               dev_err(dev, "Failed to register wdt device\n");
+       if (ret)
                return ret;
-       }
        platform_set_drvdata(pdev, wdt);
 
        dev_info(dev, "Xilinx Watchdog Timer at %p with timeout %ds%s\n",
index a2feef1..d708c09 100644 (file)
@@ -176,14 +176,7 @@ static int da9052_wdt_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = devm_watchdog_register_device(dev, &driver_data->wdt);
-       if (ret != 0) {
-               dev_err(da9052->dev, "watchdog_register_device() failed: %d\n",
-                       ret);
-               return ret;
-       }
-
-       return ret;
+       return devm_watchdog_register_device(dev, &driver_data->wdt);
 }
 
 static struct platform_driver da9052_wdt_driver = {
index aac749c..e149e66 100644 (file)
@@ -214,11 +214,8 @@ static int da9062_wdt_probe(struct platform_device *pdev)
        watchdog_set_drvdata(&wdt->wdtdev, wdt);
 
        ret = devm_watchdog_register_device(dev, &wdt->wdtdev);
-       if (ret < 0) {
-               dev_err(wdt->hw->dev,
-                       "watchdog registration failed (%d)\n", ret);
+       if (ret < 0)
                return ret;
-       }
 
        return da9062_wdt_ping(&wdt->wdtdev);
 }
index 7b2ee35..2b3f3cd 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * drivers/char/watchdog/davinci_wdt.c
  *
@@ -5,10 +6,7 @@
  *
  * Copyright (C) 2006-2013 Texas Instruments.
  *
- * 2007 (c) MontaVista Software, Inc. 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.
+ * 2007 (c) MontaVista Software, Inc.
  */
 
 #include <linux/module.h>
@@ -247,13 +245,7 @@ static int davinci_wdt_probe(struct platform_device *pdev)
        if (IS_ERR(davinci_wdt->base))
                return PTR_ERR(davinci_wdt->base);
 
-       ret = devm_watchdog_register_device(dev, wdd);
-       if (ret) {
-               dev_err(dev, "cannot register watchdog device\n");
-               return ret;
-       }
-
-       return 0;
+       return devm_watchdog_register_device(dev, wdd);
 }
 
 static const struct of_device_id davinci_wdt_of_match[] = {
index 8af6e9a..073d378 100644 (file)
@@ -118,7 +118,6 @@ static int dc_wdt_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct dc_wdt *wdt;
-       int ret;
 
        wdt = devm_kzalloc(dev, sizeof(struct dc_wdt), GFP_KERNEL);
        if (!wdt)
@@ -141,13 +140,7 @@ static int dc_wdt_probe(struct platform_device *pdev)
        watchdog_set_restart_priority(&dc_wdt_wdd, 128);
        watchdog_init_timeout(&dc_wdt_wdd, timeout, dev);
        watchdog_stop_on_reboot(&dc_wdt_wdd);
-       ret = devm_watchdog_register_device(dev, &dc_wdt_wdd);
-       if (ret) {
-               dev_err(dev, "Failed to register watchdog device");
-               return ret;
-       }
-
-       return 0;
+       return devm_watchdog_register_device(dev, &dc_wdt_wdd);
 }
 
 static const struct of_device_id dc_wdt_of_match[] = {
index c176f59..8ef4b0d 100644 (file)
@@ -2,15 +2,6 @@
 /*
  * Watchdog timer driver for the WinSystems EBC-C384
  * Copyright (C) 2016 William Breathitt Gray
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
  */
 #include <linux/device.h>
 #include <linux/dmi.h>
index 89129e6..3a83a48 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  *     Eurotech CPU-1220/1410/1420 on board WDT driver
  *
  *     (c) Copyright 1996-1997 Alan Cox <alan@lxorguk.ukuu.org.uk>,
  *                                             All Rights Reserved.
  *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
  *     Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
  *     warranty for any of this software. This material is provided
  *     "AS-IS" and at no charge.
index d9626ef..21dcc77 100644 (file)
@@ -165,10 +165,8 @@ static int ftwdt010_wdt_probe(struct platform_device *pdev)
        }
 
        ret = devm_watchdog_register_device(dev, &gwdt->wdd);
-       if (ret) {
-               dev_err(dev, "failed to register watchdog\n");
+       if (ret)
                return ret;
-       }
 
        /* Set up platform driver data */
        platform_set_drvdata(pdev, gwdt);
index 777de10..0923201 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/watchdog.h>
 
+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) ")");
+
 #define SOFT_TIMEOUT_MIN       1
 #define SOFT_TIMEOUT_DEF       60
 
@@ -151,6 +157,7 @@ static int gpio_wdt_probe(struct platform_device *pdev)
        priv->wdd.timeout       = SOFT_TIMEOUT_DEF;
 
        watchdog_init_timeout(&priv->wdd, 0, dev);
+       watchdog_set_nowayout(&priv->wdd, nowayout);
 
        watchdog_stop_on_reboot(&priv->wdd);
 
index 8a90f15..7d34bcf 100644 (file)
 #include <linux/watchdog.h>
 #include <asm/nmi.h>
 
-#define HPWDT_VERSION                  "2.0.2"
+#define HPWDT_VERSION                  "2.0.3"
 #define SECS_TO_TICKS(secs)            ((secs) * 1000 / 128)
 #define TICKS_TO_SECS(ticks)           ((ticks) * 128 / 1000)
-#define HPWDT_MAX_TIMER                        TICKS_TO_SECS(65535)
+#define HPWDT_MAX_TICKS                        65535
+#define HPWDT_MAX_TIMER                        TICKS_TO_SECS(HPWDT_MAX_TICKS)
 #define DEFAULT_MARGIN                 30
 #define PRETIMEOUT_SEC                 9
 
@@ -33,6 +34,7 @@ static bool ilo5;
 static unsigned int soft_margin = DEFAULT_MARGIN;      /* in seconds */
 static bool nowayout = WATCHDOG_NOWAYOUT;
 static bool pretimeout = IS_ENABLED(CONFIG_HPWDT_NMI_DECODING);
+static int kdumptimeout = -1;
 
 static void __iomem *pci_mem_addr;             /* the PCI-memory address */
 static unsigned long __iomem *hpwdt_nmistat;
@@ -52,15 +54,21 @@ static const struct pci_device_id hpwdt_blacklist[] = {
        {0},                    /* terminate list */
 };
 
+static struct watchdog_device hpwdt_dev;
 /*
  *     Watchdog operations
  */
+static int hpwdt_hw_is_running(void)
+{
+       return ioread8(hpwdt_timer_con) & 0x01;
+}
+
 static int hpwdt_start(struct watchdog_device *wdd)
 {
        int control = 0x81 | (pretimeout ? 0x4 : 0);
-       int reload = SECS_TO_TICKS(wdd->timeout);
+       int reload = SECS_TO_TICKS(min(wdd->timeout, wdd->max_hw_heartbeat_ms/1000));
 
-       dev_dbg(wdd->parent, "start watchdog 0x%08x:0x%02x\n", reload, control);
+       dev_dbg(wdd->parent, "start watchdog 0x%08x:0x%08x:0x%02x\n", wdd->timeout, reload, control);
        iowrite16(reload, hpwdt_timer_reg);
        iowrite8(control, hpwdt_timer_con);
 
@@ -85,12 +93,18 @@ static int hpwdt_stop_core(struct watchdog_device *wdd)
        return 0;
 }
 
+static void hpwdt_ping_ticks(int val)
+{
+       val = min(val, HPWDT_MAX_TICKS);
+       iowrite16(val, hpwdt_timer_reg);
+}
+
 static int hpwdt_ping(struct watchdog_device *wdd)
 {
-       int reload = SECS_TO_TICKS(wdd->timeout);
+       int reload = SECS_TO_TICKS(min(wdd->timeout, wdd->max_hw_heartbeat_ms/1000));
 
-       dev_dbg(wdd->parent, "ping  watchdog 0x%08x\n", reload);
-       iowrite16(reload, hpwdt_timer_reg);
+       dev_dbg(wdd->parent, "ping  watchdog 0x%08x:0x%08x\n", wdd->timeout, reload);
+       hpwdt_ping_ticks(reload);
 
        return 0;
 }
@@ -166,7 +180,14 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs)
        if (ilo5 && !pretimeout && !mynmi)
                return NMI_DONE;
 
-       hpwdt_stop();
+       if (kdumptimeout < 0)
+               hpwdt_stop();
+       else if (kdumptimeout == 0)
+               ;
+       else {
+               unsigned int val = max((unsigned int)kdumptimeout, hpwdt_dev.timeout);
+               hpwdt_ping_ticks(SECS_TO_TICKS(val));
+       }
 
        hex_byte_pack(panic_msg, mynmi);
        nmi_panic(regs, panic_msg);
@@ -204,9 +225,9 @@ static struct watchdog_device hpwdt_dev = {
        .info           = &ident,
        .ops            = &hpwdt_ops,
        .min_timeout    = 1,
-       .max_timeout    = HPWDT_MAX_TIMER,
        .timeout        = DEFAULT_MARGIN,
        .pretimeout     = PRETIMEOUT_SEC,
+       .max_hw_heartbeat_ms    = HPWDT_MAX_TIMER * 1000,
 };
 
 
@@ -298,14 +319,18 @@ static int hpwdt_init_one(struct pci_dev *dev,
        hpwdt_timer_reg = pci_mem_addr + 0x70;
        hpwdt_timer_con = pci_mem_addr + 0x72;
 
-       /* Make sure that timer is disabled until /dev/watchdog is opened */
-       hpwdt_stop();
+       /* Have the core update running timer until user space is ready */
+       if (hpwdt_hw_is_running()) {
+               dev_info(&dev->dev, "timer is running\n");
+               set_bit(WDOG_HW_RUNNING, &hpwdt_dev.status);
+       }
 
        /* Initialize NMI Decoding functionality */
        retval = hpwdt_init_nmi_decoding(dev);
        if (retval != 0)
                goto error_init_nmi_decoding;
 
+       watchdog_stop_on_unregister(&hpwdt_dev);
        watchdog_set_nowayout(&hpwdt_dev, nowayout);
        watchdog_init_timeout(&hpwdt_dev, soft_margin, NULL);
 
@@ -314,13 +339,12 @@ static int hpwdt_init_one(struct pci_dev *dev,
                pretimeout = 0;
        }
        hpwdt_dev.pretimeout = pretimeout ? PRETIMEOUT_SEC : 0;
+       kdumptimeout = min(kdumptimeout, HPWDT_MAX_TIMER);
 
        hpwdt_dev.parent = &dev->dev;
        retval = watchdog_register_device(&hpwdt_dev);
-       if (retval < 0) {
-               dev_err(&dev->dev, "watchdog register failed: %d.\n", retval);
+       if (retval < 0)
                goto error_wd_register;
-       }
 
        dev_info(&dev->dev, "HPE Watchdog Timer Driver: Version: %s\n",
                                HPWDT_VERSION);
@@ -328,6 +352,7 @@ static int hpwdt_init_one(struct pci_dev *dev,
                                hpwdt_dev.timeout, nowayout);
        dev_info(&dev->dev, "pretimeout: %s.\n",
                                pretimeout ? "on" : "off");
+       dev_info(&dev->dev, "kdumptimeout: %d.\n", kdumptimeout);
 
        if (dev->subsystem_vendor == PCI_VENDOR_ID_HP_3PAR)
                ilo5 = true;
@@ -345,9 +370,6 @@ error_pci_iomap:
 
 static void hpwdt_exit(struct pci_dev *dev)
 {
-       if (!nowayout)
-               hpwdt_stop();
-
        watchdog_unregister_device(&hpwdt_dev);
        hpwdt_exit_nmi_decoding();
        pci_iounmap(dev, pci_mem_addr);
@@ -376,6 +398,9 @@ module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
+module_param(kdumptimeout, int, 0444);
+MODULE_PARM_DESC(kdumptimeout, "Timeout applied for crash kernel transition in seconds");
+
 #ifdef CONFIG_HPWDT_NMI_DECODING
 module_param(pretimeout, bool, 0);
 MODULE_PARM_DESC(pretimeout, "Watchdog pretimeout enabled");
index f98f35a..a30835f 100644 (file)
@@ -315,11 +315,8 @@ static int esb_probe(struct pci_dev *pdev,
 
        /* Register the watchdog so that userspace has access to it */
        ret = watchdog_register_device(&edev->wdd);
-       if (ret != 0) {
-               dev_err(&pdev->dev,
-                       "cannot register watchdog device (err=%d)\n", ret);
+       if (ret != 0)
                goto err_unmap;
-       }
        dev_info(&pdev->dev,
                "initialized. heartbeat=%d sec (nowayout=%d)\n",
                edev->wdd.timeout, nowayout);
index 68a9d9c..4f1b96f 100644 (file)
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  *     intel TCO vendor specific watchdog driver support
  *
  *     (c) Copyright 2006-2009 Wim Van Sebroeck <wim@iguana.be>.
  *
- *     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.
- *
  *     Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
  *     provide warranty for any of this software. This material is
  *     provided "AS-IS" and at no charge.
@@ -216,4 +212,3 @@ MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>, "
 MODULE_DESCRIPTION("Intel TCO Vendor Specific WatchDog Timer Driver Support");
 MODULE_VERSION(DRV_VERSION);
 MODULE_LICENSE("GPL");
-
index 89cea6c..c559f70 100644 (file)
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  *     intel TCO Watchdog Driver
  *
  *     (c) Copyright 2006-2011 Wim Van Sebroeck <wim@iguana.be>.
  *
- *     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.
- *
  *     Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
  *     provide warranty for any of this software. This material is
  *     provided "AS-IS" and at no charge.
index 30d6cec..92fd7f3 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  *     IB700 Single Board Computer WDT driver
  *
  *     (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
  *                                             All Rights Reserved.
  *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
  *     Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
  *     warranty for any of this software. This material is provided
  *     "AS-IS" and at no charge.
index 508fbef..8f28993 100644 (file)
@@ -66,7 +66,7 @@ MODULE_PARM_DESC(resetmode,
 
 static struct {
        unsigned short sch_wdtba;
-       struct spinlock unlock_sequence;
+       spinlock_t unlock_sequence;
 #ifdef CONFIG_DEBUG_FS
        struct dentry *debugfs;
 #endif
@@ -254,12 +254,8 @@ static int ie6xx_wdt_probe(struct platform_device *pdev)
        ie6xx_wdt_debugfs_init();
 
        ret = watchdog_register_device(&ie6xx_wdt_dev);
-       if (ret) {
-               dev_err(&pdev->dev,
-                       "Watchdog timer: cannot register device (err =%d)\n",
-                                                                       ret);
+       if (ret)
                goto misc_register_error;
-       }
 
        return 0;
 
index a606005..32af397 100644 (file)
@@ -316,10 +316,8 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
        regmap_write(wdev->regmap, IMX2_WDT_WMCR, 0);
 
        ret = watchdog_register_device(wdog);
-       if (ret) {
-               dev_err(&pdev->dev, "cannot register watchdog device\n");
+       if (ret)
                goto disable_clk;
-       }
 
        dev_info(&pdev->dev, "timeout %d sec (nowayout=%d)\n",
                 wdog->timeout, nowayout);
index 49848b6..78eaaf7 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <linux/arm-smccc.h>
+#include <linux/firmware/imx/sci.h>
 #include <linux/io.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 
 #define SC_TIMER_WDOG_ACTION_PARTITION 0
 
+#define SC_IRQ_WDOG                    1
+#define SC_IRQ_GROUP_WDOG              1
+
 static bool nowayout = WATCHDOG_NOWAYOUT;
 module_param(nowayout, bool, 0000);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
                 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
+struct imx_sc_wdt_device {
+       struct watchdog_device wdd;
+       struct notifier_block wdt_notifier;
+};
+
 static int imx_sc_wdt_ping(struct watchdog_device *wdog)
 {
        struct arm_smccc_res res;
@@ -85,24 +94,66 @@ static int imx_sc_wdt_set_timeout(struct watchdog_device *wdog,
        return res.a0 ? -EACCES : 0;
 }
 
+static int imx_sc_wdt_set_pretimeout(struct watchdog_device *wdog,
+                                    unsigned int pretimeout)
+{
+       struct arm_smccc_res res;
+
+       arm_smccc_smc(IMX_SIP_TIMER, IMX_SIP_TIMER_SET_PRETIME_WDOG,
+                     pretimeout * 1000, 0, 0, 0, 0, 0, &res);
+       if (res.a0)
+               return -EACCES;
+
+       wdog->pretimeout = pretimeout;
+
+       return 0;
+}
+
+static int imx_sc_wdt_notify(struct notifier_block *nb,
+                            unsigned long event, void *group)
+{
+       struct imx_sc_wdt_device *imx_sc_wdd =
+                                container_of(nb,
+                                             struct imx_sc_wdt_device,
+                                             wdt_notifier);
+
+       if (event & SC_IRQ_WDOG &&
+           *(u8 *)group == SC_IRQ_GROUP_WDOG)
+               watchdog_notify_pretimeout(&imx_sc_wdd->wdd);
+
+       return 0;
+}
+
+static void imx_sc_wdt_action(void *data)
+{
+       struct notifier_block *wdt_notifier = data;
+
+       imx_scu_irq_unregister_notifier(wdt_notifier);
+       imx_scu_irq_group_enable(SC_IRQ_GROUP_WDOG,
+                                SC_IRQ_WDOG,
+                                false);
+}
+
 static const struct watchdog_ops imx_sc_wdt_ops = {
        .owner = THIS_MODULE,
        .start = imx_sc_wdt_start,
        .stop  = imx_sc_wdt_stop,
        .ping  = imx_sc_wdt_ping,
        .set_timeout = imx_sc_wdt_set_timeout,
+       .set_pretimeout = imx_sc_wdt_set_pretimeout,
 };
 
-static const struct watchdog_info imx_sc_wdt_info = {
+static struct watchdog_info imx_sc_wdt_info = {
        .identity       = "i.MX SC watchdog timer",
        .options        = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
-                         WDIOF_MAGICCLOSE | WDIOF_PRETIMEOUT,
+                         WDIOF_MAGICCLOSE,
 };
 
 static int imx_sc_wdt_probe(struct platform_device *pdev)
 {
+       struct imx_sc_wdt_device *imx_sc_wdd;
+       struct watchdog_device *wdog;
        struct device *dev = &pdev->dev;
-       struct watchdog_device *imx_sc_wdd;
        int ret;
 
        imx_sc_wdd = devm_kzalloc(dev, sizeof(*imx_sc_wdd), GFP_KERNEL);
@@ -111,42 +162,70 @@ static int imx_sc_wdt_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, imx_sc_wdd);
 
-       imx_sc_wdd->info = &imx_sc_wdt_info;
-       imx_sc_wdd->ops = &imx_sc_wdt_ops;
-       imx_sc_wdd->min_timeout = 1;
-       imx_sc_wdd->max_timeout = MAX_TIMEOUT;
-       imx_sc_wdd->parent = dev;
-       imx_sc_wdd->timeout = DEFAULT_TIMEOUT;
-
-       watchdog_init_timeout(imx_sc_wdd, 0, dev);
-       watchdog_stop_on_reboot(imx_sc_wdd);
-       watchdog_stop_on_unregister(imx_sc_wdd);
+       wdog = &imx_sc_wdd->wdd;
+       wdog->info = &imx_sc_wdt_info;
+       wdog->ops = &imx_sc_wdt_ops;
+       wdog->min_timeout = 1;
+       wdog->max_timeout = MAX_TIMEOUT;
+       wdog->parent = dev;
+       wdog->timeout = DEFAULT_TIMEOUT;
+
+       watchdog_init_timeout(wdog, 0, dev);
+       watchdog_stop_on_reboot(wdog);
+       watchdog_stop_on_unregister(wdog);
+
+       ret = devm_watchdog_register_device(dev, wdog);
+       if (ret) {
+               dev_err(dev, "Failed to register watchdog device\n");
+               return ret;
+       }
+       ret = imx_scu_irq_group_enable(SC_IRQ_GROUP_WDOG,
+                                      SC_IRQ_WDOG,
+                                      true);
+       if (ret) {
+               dev_warn(dev, "Enable irq failed, pretimeout NOT supported\n");
+               return 0;
+       }
 
-       ret = devm_watchdog_register_device(dev, imx_sc_wdd);
+       imx_sc_wdd->wdt_notifier.notifier_call = imx_sc_wdt_notify;
+       ret = imx_scu_irq_register_notifier(&imx_sc_wdd->wdt_notifier);
        if (ret) {
-               dev_err(dev, "Failed to register watchdog device\n");
-               return ret;
+               imx_scu_irq_group_enable(SC_IRQ_GROUP_WDOG,
+                                        SC_IRQ_WDOG,
+                                        false);
+               dev_warn(dev,
+                        "Register irq notifier failed, pretimeout NOT supported\n");
+               return 0;
        }
 
+       ret = devm_add_action_or_reset(dev, imx_sc_wdt_action,
+                                      &imx_sc_wdd->wdt_notifier);
+       if (!ret)
+               imx_sc_wdt_info.options |= WDIOF_PRETIMEOUT;
+       else
+               dev_warn(dev, "Add action failed, pretimeout NOT supported\n");
+
        return 0;
 }
 
 static int __maybe_unused imx_sc_wdt_suspend(struct device *dev)
 {
-       struct watchdog_device *imx_sc_wdd = dev_get_drvdata(dev);
+       struct imx_sc_wdt_device *imx_sc_wdd = dev_get_drvdata(dev);
 
-       if (watchdog_active(imx_sc_wdd))
-               imx_sc_wdt_stop(imx_sc_wdd);
+       if (watchdog_active(&imx_sc_wdd->wdd))
+               imx_sc_wdt_stop(&imx_sc_wdd->wdd);
 
        return 0;
 }
 
 static int __maybe_unused imx_sc_wdt_resume(struct device *dev)
 {
-       struct watchdog_device *imx_sc_wdd = dev_get_drvdata(dev);
+       struct imx_sc_wdt_device *imx_sc_wdd = dev_get_drvdata(dev);
 
-       if (watchdog_active(imx_sc_wdd))
-               imx_sc_wdt_start(imx_sc_wdd);
+       if (watchdog_active(&imx_sc_wdd->wdd))
+               imx_sc_wdt_start(&imx_sc_wdd->wdd);
 
        return 0;
 }
index b2463f8..2cdbd37 100644 (file)
@@ -161,10 +161,8 @@ static int mid_wdt_probe(struct platform_device *pdev)
        set_bit(WDOG_HW_RUNNING, &wdt_dev->status);
 
        ret = devm_watchdog_register_device(dev, wdt_dev);
-       if (ret) {
-               dev_err(dev, "error registering watchdog device\n");
+       if (ret)
                return ret;
-       }
 
        dev_info(dev, "Intel MID watchdog device probed\n");
 
index 313358b..d4a9091 100644 (file)
@@ -4,6 +4,7 @@
  *  JZ4740 Watchdog driver
  */
 
+#include <linux/mfd/ingenic-tcu.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
 
 #include <asm/mach-jz4740/timer.h>
 
-#define JZ_REG_WDT_TIMER_DATA     0x0
-#define JZ_REG_WDT_COUNTER_ENABLE 0x4
-#define JZ_REG_WDT_TIMER_COUNTER  0x8
-#define JZ_REG_WDT_TIMER_CONTROL  0xC
-
 #define JZ_WDT_CLOCK_PCLK 0x1
 #define JZ_WDT_CLOCK_RTC  0x2
 #define JZ_WDT_CLOCK_EXT  0x4
 
-#define JZ_WDT_CLOCK_DIV_SHIFT   3
-
-#define JZ_WDT_CLOCK_DIV_1    (0 << JZ_WDT_CLOCK_DIV_SHIFT)
-#define JZ_WDT_CLOCK_DIV_4    (1 << JZ_WDT_CLOCK_DIV_SHIFT)
-#define JZ_WDT_CLOCK_DIV_16   (2 << JZ_WDT_CLOCK_DIV_SHIFT)
-#define JZ_WDT_CLOCK_DIV_64   (3 << JZ_WDT_CLOCK_DIV_SHIFT)
-#define JZ_WDT_CLOCK_DIV_256  (4 << JZ_WDT_CLOCK_DIV_SHIFT)
-#define JZ_WDT_CLOCK_DIV_1024 (5 << JZ_WDT_CLOCK_DIV_SHIFT)
+#define JZ_WDT_CLOCK_DIV_1    (0 << TCU_TCSR_PRESCALE_LSB)
+#define JZ_WDT_CLOCK_DIV_4    (1 << TCU_TCSR_PRESCALE_LSB)
+#define JZ_WDT_CLOCK_DIV_16   (2 << TCU_TCSR_PRESCALE_LSB)
+#define JZ_WDT_CLOCK_DIV_64   (3 << TCU_TCSR_PRESCALE_LSB)
+#define JZ_WDT_CLOCK_DIV_256  (4 << TCU_TCSR_PRESCALE_LSB)
+#define JZ_WDT_CLOCK_DIV_1024 (5 << TCU_TCSR_PRESCALE_LSB)
 
 #define DEFAULT_HEARTBEAT 5
 #define MAX_HEARTBEAT     2048
@@ -63,7 +57,7 @@ static int jz4740_wdt_ping(struct watchdog_device *wdt_dev)
 {
        struct jz4740_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
 
-       writew(0x0, drvdata->base + JZ_REG_WDT_TIMER_COUNTER);
+       writew(0x0, drvdata->base + TCU_REG_WDT_TCNT);
        return 0;
 }
 
@@ -74,6 +68,7 @@ static int jz4740_wdt_set_timeout(struct watchdog_device *wdt_dev,
        unsigned int rtc_clk_rate;
        unsigned int timeout_value;
        unsigned short clock_div = JZ_WDT_CLOCK_DIV_1;
+       u8 tcer;
 
        rtc_clk_rate = clk_get_rate(drvdata->rtc_clk);
 
@@ -86,18 +81,19 @@ static int jz4740_wdt_set_timeout(struct watchdog_device *wdt_dev,
                        break;
                }
                timeout_value >>= 2;
-               clock_div += (1 << JZ_WDT_CLOCK_DIV_SHIFT);
+               clock_div += (1 << TCU_TCSR_PRESCALE_LSB);
        }
 
-       writeb(0x0, drvdata->base + JZ_REG_WDT_COUNTER_ENABLE);
-       writew(clock_div, drvdata->base + JZ_REG_WDT_TIMER_CONTROL);
+       tcer = readb(drvdata->base + TCU_REG_WDT_TCER);
+       writeb(0x0, drvdata->base + TCU_REG_WDT_TCER);
+       writew(clock_div, drvdata->base + TCU_REG_WDT_TCSR);
 
-       writew((u16)timeout_value, drvdata->base + JZ_REG_WDT_TIMER_DATA);
-       writew(0x0, drvdata->base + JZ_REG_WDT_TIMER_COUNTER);
-       writew(clock_div | JZ_WDT_CLOCK_RTC,
-               drvdata->base + JZ_REG_WDT_TIMER_CONTROL);
+       writew((u16)timeout_value, drvdata->base + TCU_REG_WDT_TDR);
+       writew(0x0, drvdata->base + TCU_REG_WDT_TCNT);
+       writew(clock_div | JZ_WDT_CLOCK_RTC, drvdata->base + TCU_REG_WDT_TCSR);
 
-       writeb(0x1, drvdata->base + JZ_REG_WDT_COUNTER_ENABLE);
+       if (tcer & TCU_WDT_TCER_TCEN)
+               writeb(TCU_WDT_TCER_TCEN, drvdata->base + TCU_REG_WDT_TCER);
 
        wdt_dev->timeout = new_timeout;
        return 0;
@@ -105,9 +101,18 @@ static int jz4740_wdt_set_timeout(struct watchdog_device *wdt_dev,
 
 static int jz4740_wdt_start(struct watchdog_device *wdt_dev)
 {
+       struct jz4740_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
+       u8 tcer;
+
+       tcer = readb(drvdata->base + TCU_REG_WDT_TCER);
+
        jz4740_timer_enable_watchdog();
        jz4740_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
 
+       /* Start watchdog if it wasn't started already */
+       if (!(tcer & TCU_WDT_TCER_TCEN))
+               writeb(TCU_WDT_TCER_TCEN, drvdata->base + TCU_REG_WDT_TCER);
+
        return 0;
 }
 
@@ -115,7 +120,7 @@ static int jz4740_wdt_stop(struct watchdog_device *wdt_dev)
 {
        struct jz4740_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
 
-       writeb(0x0, drvdata->base + JZ_REG_WDT_COUNTER_ENABLE);
+       writeb(0x0, drvdata->base + TCU_REG_WDT_TCER);
        jz4740_timer_disable_watchdog();
 
        return 0;
@@ -187,11 +192,7 @@ static int jz4740_wdt_probe(struct platform_device *pdev)
                return PTR_ERR(drvdata->rtc_clk);
        }
 
-       ret = devm_watchdog_register_device(dev, &drvdata->wdt);
-       if (ret < 0)
-               return ret;
-
-       return 0;
+       return devm_watchdog_register_device(dev, &drvdata->wdt);
 }
 
 static struct platform_driver jz4740_wdt_driver = {
index c8c2b8a..bb3d075 100644 (file)
@@ -132,10 +132,8 @@ static int ls1x_wdt_probe(struct platform_device *pdev)
        watchdog_set_drvdata(ls1x_wdt, drvdata);
 
        err = devm_watchdog_register_device(dev, &drvdata->wdt);
-       if (err) {
-               dev_err(dev, "failed to register watchdog device\n");
+       if (err)
                return err;
-       }
 
        platform_set_drvdata(pdev, drvdata);
 
index 9937f9f..be6a53c 100644 (file)
@@ -182,13 +182,7 @@ static int max77620_wdt_probe(struct platform_device *pdev)
        watchdog_set_drvdata(wdt_dev, wdt);
 
        watchdog_stop_on_unregister(wdt_dev);
-       ret = devm_watchdog_register_device(dev, wdt_dev);
-       if (ret < 0) {
-               dev_err(dev, "watchdog registration failed: %d\n", ret);
-               return ret;
-       }
-
-       return 0;
+       return devm_watchdog_register_device(dev, wdt_dev);
 }
 
 static const struct platform_device_id max77620_wdt_devtype[] = {
index 96a7709..5391bf3 100644 (file)
@@ -384,10 +384,8 @@ static int mei_wdt_register(struct mei_wdt *wdt)
        watchdog_stop_on_reboot(&wdt->wdd);
 
        ret = watchdog_register_device(&wdt->wdd);
-       if (ret) {
-               dev_err(dev, "unable to register watchdog device = %d.\n", ret);
+       if (ret)
                watchdog_set_drvdata(&wdt->wdd, NULL);
-       }
 
        wdt->state = MEI_WDT_IDLE;
 
index e9ca4e0..99d2359 100644 (file)
@@ -190,10 +190,8 @@ static int a21_wdt_probe(struct platform_device *pdev)
        dev_set_drvdata(dev, drv);
 
        ret = devm_watchdog_register_device(dev, &a21_wdt);
-       if (ret) {
-               dev_err(dev, "Cannot register watchdog device\n");
+       if (ret)
                return ret;
-       }
 
        dev_info(dev, "MEN A21 watchdog timer driver enabled\n");
 
index 7766d73..81ebdfc 100644 (file)
@@ -152,10 +152,8 @@ static int menf21bmc_wdt_probe(struct platform_device *pdev)
        }
 
        ret = devm_watchdog_register_device(dev, &drv_data->wdt);
-       if (ret) {
-               dev_err(dev, "failed to register Watchdog device\n");
+       if (ret)
                return ret;
-       }
 
        dev_info(dev, "MEN 14F021P00 BMC Watchdog device enabled\n");
 
index b6ffad4..3fc457b 100644 (file)
@@ -201,11 +201,8 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev)
                ddata->wdd.timeout = ddata->wdd.min_timeout;
 
        ret = devm_watchdog_register_device(dev, &ddata->wdd);
-       if (ret) {
-               dev_err(dev, "cannot register watchdog device (err=%d)\n",
-                       ret);
+       if (ret)
                return ret;
-       }
 
        dev_info(dev,
                 "WDT driver for MPC8xxx initialized. mode:%s timeout=%d sec\n",
index c785f4f..74bf714 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * mv64x60_wdt.c - MV64X60 (Marvell Discovery) watchdog userspace interface
  *
@@ -9,10 +10,7 @@
  *
  * Derived from mpc8xx_wdt.c, with the following copyright.
  *
- * 2002 (c) Florian Schirmer <jolt@tuxbox.org> 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.
+ * 2002 (c) Florian Schirmer <jolt@tuxbox.org>
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 60f5608..4cebad3 100644 (file)
@@ -211,10 +211,8 @@ static int ni903x_acpi_add(struct acpi_device *device)
        watchdog_init_timeout(wdd, timeout, dev);
 
        ret = watchdog_register_device(wdd);
-       if (ret) {
-               dev_err(dev, "failed to register watchdog\n");
+       if (ret)
                return ret;
-       }
 
        /* Switch from boot mode to user mode */
        outb(NIWD_CONTROL_RESET | NIWD_CONTROL_MODE,
index 2e1a2a3..2a46cc6 100644 (file)
@@ -210,7 +210,6 @@ static int nic7018_probe(struct platform_device *pdev)
        ret = watchdog_register_device(wdd);
        if (ret) {
                outb(LOCK, wdt->io_base + WDT_REG_LOCK);
-               dev_err(dev, "failed to register watchdog\n");
                return ret;
        }
 
index 9d6c168..9c773c3 100644 (file)
@@ -220,10 +220,8 @@ static int npcm_wdt_probe(struct platform_device *pdev)
                return ret;
 
        ret = devm_watchdog_register_device(dev, &wdt->wdd);
-       if (ret) {
-               dev_err(dev, "failed to register watchdog\n");
+       if (ret)
                return ret;
-       }
 
        dev_info(dev, "NPCM watchdog driver enabled\n");
 
index c2d1d04..d325e52 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  *     nv_tco: TCO timer driver for nVidia chipsets.
  *
  *     Reserved.
  *                             http://www.kernelconcepts.de
  *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
  *     Neither kernel concepts nor Nils Faerber admit liability nor provide
  *     warranty for any of this software. This material is provided
  *     "AS-IS" and at no charge.
index 0ec419a..fde9e73 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Octeon Watchdog driver
  *
  *     (c) Copyright 1996-1997 Alan Cox <alan@lxorguk.ukuu.org.uk>,
  *                                             All Rights Reserved.
  *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
  *     Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
  *     warranty for any of this software. This material is provided
  *     "AS-IS" and at no charge.
  *
  *     (c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
- * 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.
- *
- *
  * The OCTEON watchdog has a maximum timeout of 2^32 * io_clock.
  * For most systems this is less than 10 seconds, so to allow for
  * software to request longer watchdog heartbeats, we maintain software
index 0378699..7fe4f7c 100644 (file)
@@ -238,10 +238,8 @@ static int xwdt_probe(struct platform_device *pdev)
        }
 
        rc = devm_watchdog_register_device(dev, xilinx_wdt_wdd);
-       if (rc) {
-               dev_err(dev, "Cannot register watchdog (err=%d)\n", rc);
+       if (rc)
                return rc;
-       }
 
        clk_disable(xdev->clk);
 
index d49688d..9b91882 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * omap_wdt.c
  *
@@ -6,10 +7,7 @@
  * Author: MontaVista Software, Inc.
  *      <gdavis@mvista.com> or <source@mvista.com>
  *
- * 2003 (c) MontaVista Software, Inc. 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.
+ * 2003 (c) MontaVista Software, Inc.
  *
  * History:
  *
index 42f31ec..950b464 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  *  linux/drivers/char/watchdog/omap_wdt.h
  *
@@ -5,26 +6,6 @@
  *      OMAP Watchdog timer register definitions
  *
  *  Copyright (C) 2004 Texas Instruments.
- *
- *  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.
  */
 
 #ifndef _OMAP_WATCHDOG_H
index ca21d6c..2af1a8b 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  *      NS pc87413-wdt Watchdog Timer driver for Linux 2.6.x.x
  *
@@ -6,11 +7,6 @@
  *      (C) Copyright 2006 Sven Anders, <anders@anduras.de>
  *                     and Marcus Junker, <junker@anduras.de>
  *
- *      This program is free software; you can redistribute it and/or
- *      modify it under the terms of the GNU General Public License
- *      as published by the Free Software Foundation; either version
- *      2 of the License, or (at your option) any later version.
- *
  *      Neither Sven Anders, Marcus Junker nor ANDURAS AG
  *      admit liability nor provide warranty for any of this software.
  *      This material is provided "AS-IS" and at no charge.
index 5773d25..e30c1f7 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  *     Berkshire PCI-PC Watchdog Card Driver
  *
  *       Matt Domsch <Matt_Domsch@dell.com>,
  *       Rob Radez <rob@osinvestor.com>
  *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
  *     Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
  *     provide warranty for any of this software. This material is
  *     provided "AS-IS" and at no charge.
index 5de6182..6727f8a 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  *     Berkshire USB-PC Watchdog Card Driver
  *
  *       Rob Radez <rob@osinvestor.com>,
  *       Greg Kroah-Hartman <greg@kroah.com>
  *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
  *     Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
  *     provide warranty for any of this software. This material is
  *     provided "AS-IS" and at no charge.
index 4f2aca7..f43062b 100644 (file)
@@ -212,10 +212,8 @@ static int pic32_dmt_probe(struct platform_device *pdev)
        watchdog_set_drvdata(wdd, dmt);
 
        ret = devm_watchdog_register_device(dev, wdd);
-       if (ret) {
-               dev_err(dev, "watchdog register failed, err %d\n", ret);
+       if (ret)
                return ret;
-       }
 
        platform_set_drvdata(pdev, wdd);
        return 0;
index 5ecdd88..41715d6 100644 (file)
@@ -221,10 +221,8 @@ static int pic32_wdt_drv_probe(struct platform_device *pdev)
        watchdog_set_drvdata(wdd, wdt);
 
        ret = devm_watchdog_register_device(dev, wdd);
-       if (ret) {
-               dev_err(dev, "watchdog register failed, err %d\n", ret);
+       if (ret)
                return ret;
-       }
 
        platform_set_drvdata(pdev, wdd);
 
index d9e0354..7b446b6 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * drivers/char/watchdog/pnx4008_wdt.c
  *
  * 2005-2006 (c) MontaVista Software, Inc.
  *
  * (C) 2012 Wolfram Sang, Pengutronix
- *
- * 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.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -221,10 +218,8 @@ static int pnx4008_wdt_probe(struct platform_device *pdev)
                set_bit(WDOG_HW_RUNNING, &pnx4008_wdd.status);
 
        ret = devm_watchdog_register_device(dev, &pnx4008_wdd);
-       if (ret < 0) {
-               dev_err(dev, "cannot register watchdog device\n");
+       if (ret < 0)
                return ret;
-       }
 
        dev_info(dev, "heartbeat %d sec\n", pnx4008_wdd.timeout);
 
index fc0f7e5..7be7f87 100644 (file)
@@ -223,10 +223,8 @@ static int qcom_wdt_probe(struct platform_device *pdev)
        watchdog_init_timeout(&wdt->wdd, 0, dev);
 
        ret = devm_watchdog_register_device(dev, &wdt->wdd);
-       if (ret) {
-               dev_err(dev, "failed to register watchdog\n");
+       if (ret)
                return ret;
-       }
 
        platform_set_drvdata(pdev, wdt);
        return 0;
index 35db173..2c95615 100644 (file)
@@ -310,7 +310,6 @@ static int rave_sp_wdt_probe(struct platform_device *pdev)
 
        ret = devm_watchdog_register_device(dev, wdd);
        if (ret) {
-               dev_err(dev, "Failed to register watchdog device\n");
                rave_sp_wdt_stop(wdd);
                return ret;
        }
index 565dbc1..00662a8 100644 (file)
@@ -7,6 +7,7 @@
  */
 #include <linux/bitops.h>
 #include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -70,6 +71,15 @@ static int rwdt_init_timeout(struct watchdog_device *wdev)
        return 0;
 }
 
+static void rwdt_wait_cycles(struct rwdt_priv *priv, unsigned int cycles)
+{
+       unsigned int delay;
+
+       delay = DIV_ROUND_UP(cycles * 1000000, priv->clk_rate);
+
+       usleep_range(delay, 2 * delay);
+}
+
 static int rwdt_start(struct watchdog_device *wdev)
 {
        struct rwdt_priv *priv = watchdog_get_drvdata(wdev);
@@ -80,6 +90,8 @@ static int rwdt_start(struct watchdog_device *wdev)
        /* Stop the timer before we modify any register */
        val = readb_relaxed(priv->base + RWTCSRA) & ~RWTCSRA_TME;
        rwdt_write(priv, val, RWTCSRA);
+       /* Delay 2 cycles before setting watchdog counter */
+       rwdt_wait_cycles(priv, 2);
 
        rwdt_init_timeout(wdev);
        rwdt_write(priv, priv->cks, RWTCSRA);
@@ -98,6 +110,8 @@ static int rwdt_stop(struct watchdog_device *wdev)
        struct rwdt_priv *priv = watchdog_get_drvdata(wdev);
 
        rwdt_write(priv, priv->cks, RWTCSRA);
+       /* Delay 3 cycles before disabling module clock */
+       rwdt_wait_cycles(priv, 3);
        pm_runtime_put(wdev->parent);
 
        return 0;
@@ -175,15 +189,16 @@ static inline bool rwdt_blacklisted(struct device *dev) { return false; }
 
 static int rwdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct rwdt_priv *priv;
        struct clk *clk;
        unsigned long clks_per_sec;
        int ret, i;
 
-       if (rwdt_blacklisted(&pdev->dev))
+       if (rwdt_blacklisted(dev))
                return -ENODEV;
 
-       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
@@ -191,16 +206,16 @@ static int rwdt_probe(struct platform_device *pdev)
        if (IS_ERR(priv->base))
                return PTR_ERR(priv->base);
 
-       clk = devm_clk_get(&pdev->dev, NULL);
+       clk = devm_clk_get(dev, NULL);
        if (IS_ERR(clk))
                return PTR_ERR(clk);
 
-       pm_runtime_enable(&pdev->dev);
-       pm_runtime_get_sync(&pdev->dev);
+       pm_runtime_enable(dev);
+       pm_runtime_get_sync(dev);
        priv->clk_rate = clk_get_rate(clk);
        priv->wdev.bootstatus = (readb_relaxed(priv->base + RWTCSRA) &
                                RWTCSRA_WOVF) ? WDIOF_CARDRESET : 0;
-       pm_runtime_put(&pdev->dev);
+       pm_runtime_put(dev);
 
        if (!priv->clk_rate) {
                ret = -ENOENT;
@@ -216,14 +231,14 @@ static int rwdt_probe(struct platform_device *pdev)
        }
 
        if (i < 0) {
-               dev_err(&pdev->dev, "Can't find suitable clock divider\n");
+               dev_err(dev, "Can't find suitable clock divider\n");
                ret = -ERANGE;
                goto out_pm_disable;
        }
 
        priv->wdev.info = &rwdt_ident;
        priv->wdev.ops = &rwdt_ops;
-       priv->wdev.parent = &pdev->dev;
+       priv->wdev.parent = dev;
        priv->wdev.min_timeout = 1;
        priv->wdev.max_timeout = DIV_BY_CLKS_PER_SEC(priv, 65536);
        priv->wdev.timeout = min(priv->wdev.max_timeout, RWDT_DEFAULT_TIMEOUT);
@@ -235,7 +250,7 @@ static int rwdt_probe(struct platform_device *pdev)
        watchdog_stop_on_unregister(&priv->wdev);
 
        /* This overrides the default timeout only if DT configuration was found */
-       watchdog_init_timeout(&priv->wdev, 0, &pdev->dev);
+       watchdog_init_timeout(&priv->wdev, 0, dev);
 
        ret = watchdog_register_device(&priv->wdev);
        if (ret < 0)
@@ -244,7 +259,7 @@ static int rwdt_probe(struct platform_device *pdev)
        return 0;
 
  out_pm_disable:
-       pm_runtime_disable(&pdev->dev);
+       pm_runtime_disable(dev);
        return ret;
 }
 
index 39cd51d..258dfcf 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Retu watchdog driver
  *
@@ -5,15 +6,6 @@
  *
  * Based on code written by Amit Kucheria and Michael Buesch.
  * Rewritten by Aaro Koskinen.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
  */
 
 #include <linux/slab.h>
index daf3bf0..2395f35 100644 (file)
@@ -606,10 +606,8 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
        wdt->wdt_device.parent = dev;
 
        ret = watchdog_register_device(&wdt->wdt_device);
-       if (ret) {
-               dev_err(dev, "cannot register watchdog (%d)\n", ret);
+       if (ret)
                goto err_cpufreq;
-       }
 
        ret = s3c2410wdt_mask_and_disable_reset(wdt, false);
        if (ret < 0)
index bfa035e..cbd8c95 100644 (file)
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  *     Watchdog driver for the SA11x0/PXA2xx
  *
  *     (c) Copyright 2000 Oleg Drokin <green@crimea.edu>
  *         Based on SoftDog driver by Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
- *     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.
- *
  *     Neither Oleg Drokin nor iXcelerator.com admit liability nor provide
  *     warranty for any of this software. This material is provided
  *     "AS-IS" and at no charge.
index b8da1bf..d193a60 100644 (file)
@@ -110,9 +110,7 @@ static int sama5d4_wdt_set_timeout(struct watchdog_device *wdd,
        u32 value = WDT_SEC2TICKS(timeout);
 
        wdt->mr &= ~AT91_WDT_WDV;
-       wdt->mr &= ~AT91_WDT_WDD;
        wdt->mr |= AT91_WDT_SET_WDV(value);
-       wdt->mr |= AT91_WDT_SET_WDD(value);
 
        /*
         * WDDIS has to be 0 when updating WDD/WDV. The datasheet states: When
@@ -248,7 +246,7 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
 
        timeout = WDT_SEC2TICKS(wdd->timeout);
 
-       wdt->mr |= AT91_WDT_SET_WDD(timeout);
+       wdt->mr |= AT91_WDT_SET_WDD(WDT_SEC2TICKS(MAX_WDT_TIMEOUT));
        wdt->mr |= AT91_WDT_SET_WDV(timeout);
 
        ret = sama5d4_wdt_init(wdt);
@@ -259,10 +257,8 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
 
        watchdog_stop_on_unregister(wdd);
        ret = devm_watchdog_register_device(dev, wdd);
-       if (ret) {
-               dev_err(dev, "failed to register watchdog device\n");
+       if (ret)
                return ret;
-       }
 
        platform_set_drvdata(pdev, wdt);
 
@@ -279,7 +275,17 @@ static const struct of_device_id sama5d4_wdt_of_match[] = {
 MODULE_DEVICE_TABLE(of, sama5d4_wdt_of_match);
 
 #ifdef CONFIG_PM_SLEEP
-static int sama5d4_wdt_resume(struct device *dev)
+static int sama5d4_wdt_suspend_late(struct device *dev)
+{
+       struct sama5d4_wdt *wdt = dev_get_drvdata(dev);
+
+       if (watchdog_active(&wdt->wdd))
+               sama5d4_wdt_stop(&wdt->wdd);
+
+       return 0;
+}
+
+static int sama5d4_wdt_resume_early(struct device *dev)
 {
        struct sama5d4_wdt *wdt = dev_get_drvdata(dev);
 
@@ -290,12 +296,17 @@ static int sama5d4_wdt_resume(struct device *dev)
         */
        sama5d4_wdt_init(wdt);
 
+       if (watchdog_active(&wdt->wdd))
+               sama5d4_wdt_start(&wdt->wdd);
+
        return 0;
 }
 #endif
 
-static SIMPLE_DEV_PM_OPS(sama5d4_wdt_pm_ops, NULL,
-                        sama5d4_wdt_resume);
+static const struct dev_pm_ops sama5d4_wdt_pm_ops = {
+       SET_LATE_SYSTEM_SLEEP_PM_OPS(sama5d4_wdt_suspend_late,
+                       sama5d4_wdt_resume_early)
+};
 
 static struct platform_driver sama5d4_wdt_driver = {
        .probe          = sama5d4_wdt_probe,
index efc81b3..12cdee7 100644 (file)
@@ -1,19 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  *     NANO7240 SBC Watchdog device driver
  *
  *     Based on w83877f.c by Scott Jennings,
  *
- *     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;
- *
- *     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.
- *
  *     (c) Copyright 2007  Gilles GIGAN <gilles.gigan@jcu.edu.au>
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 3396024..4f8b991 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  *     SBC8360 Watchdog driver
  *
  *     (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
  *                                             All Rights Reserved.
  *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
  *     Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
  *     warranty for any of this software. This material is provided
  *     "AS-IS" and at no charge.
index ed6e9fa..3612f1d 100644 (file)
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  *     sch311x_wdt.c - Driver for the SCH311x Super-I/O chips
  *                     integrated watchdog.
  *
  *     (c) Copyright 2008 Wim Van Sebroeck <wim@iguana.be>.
  *
- *     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.
- *
  *     Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
  *     provide warranty for any of this software. This material is
  *     provided "AS-IS" and at no charge.
index 0607406..3e4885c 100644 (file)
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  *     SoftDog:        A Software Watchdog Device
  *
  *     (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
  *                                                     All Rights Reserved.
  *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
  *     Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
  *     warranty for any of this software. This material is provided
  *     "AS-IS" and at no charge.
index cd4430f..93bd302 100644 (file)
@@ -402,10 +402,8 @@ static int sp5100_tco_probe(struct platform_device *pdev)
                return ret;
 
        ret = devm_watchdog_register_device(dev, wdd);
-       if (ret) {
-               dev_err(dev, "cannot register watchdog device (err=%d)\n", ret);
+       if (ret)
                return ret;
-       }
 
        /* Show module parameters */
        dev_info(dev, "initialized. heartbeat=%d sec (nowayout=%d)\n",
index 072986d..53e0492 100644 (file)
@@ -288,11 +288,8 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
        }
 
        ret = watchdog_register_device(&wdt->wdd);
-       if (ret) {
-               dev_err(&adev->dev, "watchdog_register_device() failed: %d\n",
-                               ret);
+       if (ret)
                goto err;
-       }
        amba_set_drvdata(adev, wdt);
 
        dev_info(&adev->dev, "registration successful\n");
index 916fb3f..edba4e2 100644 (file)
@@ -320,7 +320,6 @@ static int sprd_wdt_probe(struct platform_device *pdev)
        ret = devm_watchdog_register_device(dev, &wdt->wdd);
        if (ret) {
                sprd_wdt_disable(wdt);
-               dev_err(dev, "failed to register watchdog\n");
                return ret;
        }
        platform_set_drvdata(pdev, wdt);
index 7a90184..14ab655 100644 (file)
@@ -228,10 +228,8 @@ static int st_wdog_probe(struct platform_device *pdev)
                return ret;
 
        ret = devm_watchdog_register_device(dev, &st_wdog_dev);
-       if (ret) {
-               dev_err(dev, "Unable to register watchdog\n");
+       if (ret)
                return ret;
-       }
 
        st_wdog_setup(st_wdog, true);
 
index d569a36..a3a3290 100644 (file)
@@ -263,10 +263,8 @@ static int stm32_iwdg_probe(struct platform_device *pdev)
        watchdog_init_timeout(wdd, 0, dev);
 
        ret = devm_watchdog_register_device(dev, wdd);
-       if (ret) {
-               dev_err(dev, "failed to register watchdog device\n");
+       if (ret)
                return ret;
-       }
 
        platform_set_drvdata(pdev, wdt);
 
index 671f4ba..7caf3aa 100644 (file)
@@ -98,10 +98,8 @@ static int stmp3xxx_wdt_probe(struct platform_device *pdev)
        stmp3xxx_wdd.parent = dev;
 
        ret = devm_watchdog_register_device(dev, &stmp3xxx_wdd);
-       if (ret < 0) {
-               dev_err(dev, "cannot register watchdog device\n");
+       if (ret < 0)
                return ret;
-       }
 
        if (register_reboot_notifier(&wdt_notifier))
                dev_warn(dev, "cannot register reboot notifier\n");
index a58b000..dfe06e5 100644 (file)
@@ -219,10 +219,8 @@ static int tegra_wdt_probe(struct platform_device *pdev)
 
        watchdog_stop_on_unregister(wdd);
        ret = devm_watchdog_register_device(dev, wdd);
-       if (ret) {
-               dev_err(dev, "failed to register watchdog device\n");
+       if (ret)
                return ret;
-       }
 
        platform_set_drvdata(pdev, wdt);
 
index 9dc6d7f..c137ad2 100644 (file)
@@ -171,10 +171,8 @@ static int ts4800_wdt_probe(struct platform_device *pdev)
        ts4800_wdt_stop(wdd);
 
        ret = devm_watchdog_register_device(dev, wdd);
-       if (ret) {
-               dev_err(dev, "failed to register watchdog device\n");
+       if (ret)
                return ret;
-       }
 
        platform_set_drvdata(pdev, wdt);
 
index 3a49ba9..38b31e9 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  *     w83627hf/thf WDT driver
  *
  *     (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
  *                                             All Rights Reserved.
  *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
  *     Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
  *     warranty for any of this software. This material is provided
  *     "AS-IS" and at no charge.
index 0a8073b..6d2071a 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  *     ICP Wafer 5823 Single Board Computer WDT driver
  *     http://www.icpamerica.com/wafer_5823.php
  *     (c) Copyright 1996-1997 Alan Cox <alan@lxorguk.ukuu.org.uk>,
  *                                             All Rights Reserved.
  *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
  *     Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
  *     warranty for any of this software. This material is provided
  *     "AS-IS" and at no charge.
index 62be9e5..21e8085 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  *     watchdog_core.c
  *
  *       Satyam Sharma <satyam@infradead.org>
  *       Randy Dunlap <randy.dunlap@oracle.com>
  *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
  *     Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw.
  *     admit liability nor provide warranty for any of this software.
  *     This material is provided "AS-IS" and at no charge.
@@ -60,11 +56,10 @@ static DEFINE_MUTEX(wtd_deferred_reg_mutex);
 static LIST_HEAD(wtd_deferred_reg_list);
 static bool wtd_deferred_reg_done;
 
-static int watchdog_deferred_registration_add(struct watchdog_device *wdd)
+static void watchdog_deferred_registration_add(struct watchdog_device *wdd)
 {
        list_add_tail(&wdd->deferred,
                      &wtd_deferred_reg_list);
-       return 0;
 }
 
 static void watchdog_deferred_registration_del(struct watchdog_device *wdd)
@@ -265,14 +260,23 @@ static int __watchdog_register_device(struct watchdog_device *wdd)
 
 int watchdog_register_device(struct watchdog_device *wdd)
 {
-       int ret;
+       const char *dev_str;
+       int ret = 0;
 
        mutex_lock(&wtd_deferred_reg_mutex);
        if (wtd_deferred_reg_done)
                ret = __watchdog_register_device(wdd);
        else
-               ret = watchdog_deferred_registration_add(wdd);
+               watchdog_deferred_registration_add(wdd);
        mutex_unlock(&wtd_deferred_reg_mutex);
+
+       if (ret) {
+               dev_str = wdd->parent ? dev_name(wdd->parent) :
+                         (const char *)wdd->info->identity;
+               pr_err("%s: failed to register watchdog device (err = %d)\n",
+                       dev_str, ret);
+       }
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(watchdog_register_device);
index 86ff962..a5062e8 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  *     watchdog_core.h
  *
  *       Satyam Sharma <satyam@infradead.org>
  *       Randy Dunlap <randy.dunlap@oracle.com>
  *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
  *     Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw.
  *     admit liability nor provide warranty for any of this software.
  *     This material is provided "AS-IS" and at no charge.
index 252a7c7..dbd2ad4 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  *     watchdog_dev.c
  *
  *       Satyam Sharma <satyam@infradead.org>
  *       Randy Dunlap <randy.dunlap@oracle.com>
  *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
  *     Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw.
  *     admit liability nor provide warranty for any of this software.
  *     This material is provided "AS-IS" and at no charge.
@@ -69,6 +65,7 @@ struct watchdog_core_data {
        struct mutex lock;
        ktime_t last_keepalive;
        ktime_t last_hw_keepalive;
+       ktime_t open_deadline;
        struct hrtimer timer;
        struct kthread_work work;
        unsigned long status;           /* Internal status bits */
@@ -87,6 +84,19 @@ static struct kthread_worker *watchdog_kworker;
 static bool handle_boot_enabled =
        IS_ENABLED(CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED);
 
+static unsigned open_timeout = CONFIG_WATCHDOG_OPEN_TIMEOUT;
+
+static bool watchdog_past_open_deadline(struct watchdog_core_data *data)
+{
+       return ktime_after(ktime_get(), data->open_deadline);
+}
+
+static void watchdog_set_open_deadline(struct watchdog_core_data *data)
+{
+       data->open_deadline = open_timeout ?
+               ktime_get() + ktime_set(open_timeout, 0) : KTIME_MAX;
+}
+
 static inline bool watchdog_need_worker(struct watchdog_device *wdd)
 {
        /* All variables in milli-seconds */
@@ -119,14 +129,15 @@ static ktime_t watchdog_next_keepalive(struct watchdog_device *wdd)
        ktime_t virt_timeout;
        unsigned int hw_heartbeat_ms;
 
-       virt_timeout = ktime_add(wd_data->last_keepalive,
-                                ms_to_ktime(timeout_ms));
+       if (watchdog_active(wdd))
+               virt_timeout = ktime_add(wd_data->last_keepalive,
+                                        ms_to_ktime(timeout_ms));
+       else
+               virt_timeout = wd_data->open_deadline;
+
        hw_heartbeat_ms = min_not_zero(timeout_ms, wdd->max_hw_heartbeat_ms);
        keepalive_interval = ms_to_ktime(hw_heartbeat_ms / 2);
 
-       if (!watchdog_active(wdd))
-               return keepalive_interval;
-
        /*
         * To ensure that the watchdog times out wdd->timeout seconds
         * after the most recent ping from userspace, the last
@@ -211,7 +222,13 @@ static bool watchdog_worker_should_ping(struct watchdog_core_data *wd_data)
 {
        struct watchdog_device *wdd = wd_data->wdd;
 
-       return wdd && (watchdog_active(wdd) || watchdog_hw_running(wdd));
+       if (!wdd)
+               return false;
+
+       if (watchdog_active(wdd))
+               return true;
+
+       return watchdog_hw_running(wdd) && !watchdog_past_open_deadline(wd_data);
 }
 
 static void watchdog_ping_work(struct kthread_work *work)
@@ -824,6 +841,15 @@ static int watchdog_open(struct inode *inode, struct file *file)
        if (!hw_running)
                kref_get(&wd_data->kref);
 
+       /*
+        * open_timeout only applies for the first open from
+        * userspace. Set open_deadline to infinity so that the kernel
+        * will take care of an always-running hardware watchdog in
+        * case the device gets magic-closed or WDIOS_DISABLECARD is
+        * applied.
+        */
+       wd_data->open_deadline = KTIME_MAX;
+
        /* dev/watchdog is a virtual (and thus non-seekable) filesystem */
        return stream_open(inode, file);
 
@@ -983,6 +1009,7 @@ static int watchdog_cdev_register(struct watchdog_device *wdd, dev_t devno)
 
        /* Record time of most recent heartbeat as 'just before now'. */
        wd_data->last_hw_keepalive = ktime_sub(ktime_get(), 1);
+       watchdog_set_open_deadline(wd_data);
 
        /*
         * If the watchdog is running, prevent its driver from being unloaded,
@@ -1181,3 +1208,8 @@ module_param(handle_boot_enabled, bool, 0444);
 MODULE_PARM_DESC(handle_boot_enabled,
        "Watchdog core auto-updates boot enabled watchdogs before userspace takes over (default="
        __MODULE_STRING(IS_ENABLED(CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED)) ")");
+
+module_param(open_timeout, uint, 0644);
+MODULE_PARM_DESC(open_timeout,
+       "Maximum time (in seconds, 0 means infinity) for userspace to take over a running watchdog (default="
+       __MODULE_STRING(CONFIG_WATCHDOG_OPEN_TIMEOUT) ")");
index 0e3a497..43a4d88 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-1.0+ */
 /*
  *     Industrial Computer Source WDT500/501 driver
  *
  *
  *     http://www.cymru.net
  *
- *     This driver is provided under the GNU General Public License,
- *     incorporated herein by reference. The driver is provided without
- *     warranty or support.
- *
  *     Release 0.04.
- *
  */
 
 
index 3d2f5ed..0650100 100644 (file)
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  *     Industrial Computer Source WDT501 driver
  *
  *     (c) Copyright 1996-1997 Alan Cox <alan@lxorguk.ukuu.org.uk>,
  *                                             All Rights Reserved.
  *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
  *     Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
  *     warranty for any of this software. This material is provided
  *     "AS-IS" and at no charge.
index ff3a41f..66303ab 100644 (file)
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  *     Industrial Computer Source PCI-WDT500/501 driver
  *
  *     (c) Copyright 1996-1997 Alan Cox <alan@lxorguk.ukuu.org.uk>,
  *                                             All Rights Reserved.
  *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
  *     Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
  *     warranty for any of this software. This material is provided
  *     "AS-IS" and at no charge.
index 9b6565a..030ce24 100644 (file)
@@ -267,14 +267,7 @@ static int wm831x_wdt_probe(struct platform_device *pdev)
                }
        }
 
-       ret = devm_watchdog_register_device(dev, &driver_data->wdt);
-       if (ret != 0) {
-               dev_err(wm831x->dev, "watchdog_register_device() failed: %d\n",
-                       ret);
-               return ret;
-       }
-
-       return 0;
+       return devm_watchdog_register_device(dev, &driver_data->wdt);
 }
 
 static struct platform_driver wm831x_wdt_driver = {
index 2ba0a3c..b343f42 100644 (file)
@@ -138,10 +138,8 @@ static int xen_wdt_probe(struct platform_device *pdev)
        watchdog_stop_on_unregister(&xen_wdt_dev);
 
        ret = devm_watchdog_register_device(dev, &xen_wdt_dev);
-       if (ret) {
-               dev_err(dev, "cannot register watchdog device (%d)\n", ret);
+       if (ret)
                return ret;
-       }
 
        dev_info(dev, "initialized (timeout=%ds, nowayout=%d)\n",
                 xen_wdt_dev.timeout, nowayout);
index ec6558b..79cc750 100644 (file)
@@ -10,21 +10,6 @@ config XEN_BALLOON
          the system to expand the domain's memory allocation, or alternatively
          return unneeded memory to the system.
 
-config XEN_SELFBALLOONING
-       bool "Dynamically self-balloon kernel memory to target"
-       depends on XEN && XEN_BALLOON && CLEANCACHE && SWAP && XEN_TMEM
-       help
-         Self-ballooning dynamically balloons available kernel memory driven
-         by the current usage of anonymous memory ("committed AS") and
-         controlled by various sysfs-settable parameters.  Configuring
-         FRONTSWAP is highly recommended; if it is not configured, self-
-         ballooning is disabled by default. If FRONTSWAP is configured,
-         frontswap-selfshrinking is enabled by default but can be disabled
-         with the 'tmem.selfshrink=0' kernel boot parameter; and self-ballooning
-         is enabled by default but can be disabled with the 'tmem.selfballooning=0'
-         kernel boot parameter.  Note that systems without a sufficiently
-         large swap device should not enable self-ballooning.
-
 config XEN_BALLOON_MEMORY_HOTPLUG
        bool "Memory hotplug support for Xen balloon driver"
        depends on XEN_BALLOON && MEMORY_HOTPLUG
@@ -191,14 +176,6 @@ config SWIOTLB_XEN
        def_bool y
        select SWIOTLB
 
-config XEN_TMEM
-       tristate
-       depends on !ARM && !ARM64
-       default m if (CLEANCACHE || FRONTSWAP)
-       help
-         Shim to interface in-kernel Transcendent Memory hooks
-         (e.g. cleancache and frontswap) to Xen tmem hypercalls.
-
 config XEN_PCIDEV_BACKEND
        tristate "Xen PCI-device backend driver"
        depends on PCI && X86 && XEN
index ad3844d..0c4efa6 100644 (file)
@@ -17,14 +17,12 @@ dom0-$(CONFIG_X86) += pcpu.o
 obj-$(CONFIG_XEN_DOM0)                 += $(dom0-y)
 obj-$(CONFIG_BLOCK)                    += biomerge.o
 obj-$(CONFIG_XEN_BALLOON)              += xen-balloon.o
-obj-$(CONFIG_XEN_SELFBALLOONING)       += xen-selfballoon.o
 obj-$(CONFIG_XEN_DEV_EVTCHN)           += xen-evtchn.o
 obj-$(CONFIG_XEN_GNTDEV)               += xen-gntdev.o
 obj-$(CONFIG_XEN_GRANT_DEV_ALLOC)      += xen-gntalloc.o
 obj-$(CONFIG_XENFS)                    += xenfs/
 obj-$(CONFIG_XEN_SYS_HYPERVISOR)       += sys-hypervisor.o
 obj-$(CONFIG_XEN_PVHVM)                        += platform-pci.o
-obj-$(CONFIG_XEN_TMEM)                 += tmem.o
 obj-$(CONFIG_SWIOTLB_XEN)              += swiotlb-xen.o
 obj-$(CONFIG_XEN_MCE_LOG)              += mcelog.o
 obj-$(CONFIG_XEN_PCIDEV_BACKEND)       += xen-pciback/
index d37dd5b..4e11de6 100644 (file)
@@ -77,9 +77,6 @@ static int xen_hotplug_unpopulated;
 
 #ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
 
-static int zero;
-static int one = 1;
-
 static struct ctl_table balloon_table[] = {
        {
                .procname       = "hotplug_unpopulated",
@@ -87,8 +84,8 @@ static struct ctl_table balloon_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        { }
 };
@@ -538,8 +535,15 @@ static void balloon_process(struct work_struct *work)
                                state = reserve_additional_memory();
                }
 
-               if (credit < 0)
-                       state = decrease_reservation(-credit, GFP_BALLOON);
+               if (credit < 0) {
+                       long n_pages;
+
+                       n_pages = min(-credit, si_mem_available());
+                       state = decrease_reservation(n_pages, GFP_BALLOON);
+                       if (state == BP_DONE && n_pages != -credit &&
+                           n_pages < totalreserve_pages)
+                               state = BP_EAGAIN;
+               }
 
                state = update_schedule(state);
 
@@ -578,6 +582,9 @@ static int add_ballooned_pages(int nr_pages)
                }
        }
 
+       if (si_mem_available() < nr_pages)
+               return -ENOMEM;
+
        st = decrease_reservation(nr_pages, GFP_USER);
        if (st != BP_DONE)
                return -ENOMEM;
@@ -710,7 +717,7 @@ static int __init balloon_init(void)
        balloon_stats.schedule_delay = 1;
        balloon_stats.max_schedule_delay = 32;
        balloon_stats.retry_count = 1;
-       balloon_stats.max_retry_count = RETRY_UNLIMITED;
+       balloon_stats.max_retry_count = 4;
 
 #ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
        set_online_page_callback(&xen_online_page);
index ff9b510..2e8570c 100644 (file)
@@ -1294,7 +1294,7 @@ void rebind_evtchn_irq(int evtchn, int irq)
 }
 
 /* Rebind an evtchn so that it gets delivered to a specific cpu */
-int xen_rebind_evtchn_to_cpu(int evtchn, unsigned tcpu)
+static int xen_rebind_evtchn_to_cpu(int evtchn, unsigned int tcpu)
 {
        struct evtchn_bind_vcpu bind_vcpu;
        int masked;
@@ -1328,7 +1328,6 @@ int xen_rebind_evtchn_to_cpu(int evtchn, unsigned tcpu)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(xen_rebind_evtchn_to_cpu);
 
 static int set_affinity_irq(struct irq_data *data, const struct cpumask *dest,
                            bool force)
@@ -1342,6 +1341,15 @@ static int set_affinity_irq(struct irq_data *data, const struct cpumask *dest,
        return ret;
 }
 
+/* To be called with desc->lock held. */
+int xen_set_affinity_evtchn(struct irq_desc *desc, unsigned int tcpu)
+{
+       struct irq_data *d = irq_desc_get_irq_data(desc);
+
+       return set_affinity_irq(d, cpumask_of(tcpu), false);
+}
+EXPORT_SYMBOL_GPL(xen_set_affinity_evtchn);
+
 static void enable_dynirq(struct irq_data *data)
 {
        int evtchn = evtchn_from_irq(data->irq);
index f341b01..052b55a 100644 (file)
@@ -447,7 +447,7 @@ static void evtchn_bind_interdom_next_vcpu(int evtchn)
        this_cpu_write(bind_last_selected_cpu, selected_cpu);
 
        /* unmask expects irqs to be disabled */
-       xen_rebind_evtchn_to_cpu(evtchn, selected_cpu);
+       xen_set_affinity_evtchn(desc, selected_cpu);
        raw_spin_unlock_irqrestore(&desc->lock, flags);
 }
 
index d53f349..cfbe467 100644 (file)
@@ -402,7 +402,7 @@ static dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
 
        map = swiotlb_tbl_map_single(dev, start_dma_addr, phys, size, dir,
                                     attrs);
-       if (map == DMA_MAPPING_ERROR)
+       if (map == (phys_addr_t)DMA_MAPPING_ERROR)
                return DMA_MAPPING_ERROR;
 
        dev_addr = xen_phys_to_bus(map);
diff --git a/drivers/xen/tmem.c b/drivers/xen/tmem.c
deleted file mode 100644 (file)
index 64d7479..0000000
+++ /dev/null
@@ -1,419 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Xen implementation for transcendent memory (tmem)
- *
- * Copyright (C) 2009-2011 Oracle Corp.  All rights reserved.
- * Author: Dan Magenheimer
- */
-
-#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/pagemap.h>
-#include <linux/cleancache.h>
-#include <linux/frontswap.h>
-
-#include <xen/xen.h>
-#include <xen/interface/xen.h>
-#include <xen/page.h>
-#include <asm/xen/hypercall.h>
-#include <asm/xen/hypervisor.h>
-#include <xen/tmem.h>
-
-#ifndef CONFIG_XEN_TMEM_MODULE
-bool __read_mostly tmem_enabled = false;
-
-static int __init enable_tmem(char *s)
-{
-       tmem_enabled = true;
-       return 1;
-}
-__setup("tmem", enable_tmem);
-#endif
-
-#ifdef CONFIG_CLEANCACHE
-static bool cleancache __read_mostly = true;
-module_param(cleancache, bool, S_IRUGO);
-static bool selfballooning __read_mostly = true;
-module_param(selfballooning, bool, S_IRUGO);
-#endif /* CONFIG_CLEANCACHE */
-
-#ifdef CONFIG_FRONTSWAP
-static bool frontswap __read_mostly = true;
-module_param(frontswap, bool, S_IRUGO);
-#else /* CONFIG_FRONTSWAP */
-#define frontswap (0)
-#endif /* CONFIG_FRONTSWAP */
-
-#ifdef CONFIG_XEN_SELFBALLOONING
-static bool selfshrinking __read_mostly = true;
-module_param(selfshrinking, bool, S_IRUGO);
-#endif /* CONFIG_XEN_SELFBALLOONING */
-
-#define TMEM_CONTROL               0
-#define TMEM_NEW_POOL              1
-#define TMEM_DESTROY_POOL          2
-#define TMEM_NEW_PAGE              3
-#define TMEM_PUT_PAGE              4
-#define TMEM_GET_PAGE              5
-#define TMEM_FLUSH_PAGE            6
-#define TMEM_FLUSH_OBJECT          7
-#define TMEM_READ                  8
-#define TMEM_WRITE                 9
-#define TMEM_XCHG                 10
-
-/* Bits for HYPERVISOR_tmem_op(TMEM_NEW_POOL) */
-#define TMEM_POOL_PERSIST          1
-#define TMEM_POOL_SHARED           2
-#define TMEM_POOL_PAGESIZE_SHIFT   4
-#define TMEM_VERSION_SHIFT        24
-
-
-struct tmem_pool_uuid {
-       u64 uuid_lo;
-       u64 uuid_hi;
-};
-
-struct tmem_oid {
-       u64 oid[3];
-};
-
-#define TMEM_POOL_PRIVATE_UUID { 0, 0 }
-
-/* flags for tmem_ops.new_pool */
-#define TMEM_POOL_PERSIST          1
-#define TMEM_POOL_SHARED           2
-
-/* xen tmem foundation ops/hypercalls */
-
-static inline int xen_tmem_op(u32 tmem_cmd, u32 tmem_pool, struct tmem_oid oid,
-       u32 index, unsigned long gmfn, u32 tmem_offset, u32 pfn_offset, u32 len)
-{
-       struct tmem_op op;
-       int rc = 0;
-
-       op.cmd = tmem_cmd;
-       op.pool_id = tmem_pool;
-       op.u.gen.oid[0] = oid.oid[0];
-       op.u.gen.oid[1] = oid.oid[1];
-       op.u.gen.oid[2] = oid.oid[2];
-       op.u.gen.index = index;
-       op.u.gen.tmem_offset = tmem_offset;
-       op.u.gen.pfn_offset = pfn_offset;
-       op.u.gen.len = len;
-       set_xen_guest_handle(op.u.gen.gmfn, (void *)gmfn);
-       rc = HYPERVISOR_tmem_op(&op);
-       return rc;
-}
-
-static int xen_tmem_new_pool(struct tmem_pool_uuid uuid,
-                               u32 flags, unsigned long pagesize)
-{
-       struct tmem_op op;
-       int rc = 0, pageshift;
-
-       for (pageshift = 0; pagesize != 1; pageshift++)
-               pagesize >>= 1;
-       flags |= (pageshift - 12) << TMEM_POOL_PAGESIZE_SHIFT;
-       flags |= TMEM_SPEC_VERSION << TMEM_VERSION_SHIFT;
-       op.cmd = TMEM_NEW_POOL;
-       op.u.new.uuid[0] = uuid.uuid_lo;
-       op.u.new.uuid[1] = uuid.uuid_hi;
-       op.u.new.flags = flags;
-       rc = HYPERVISOR_tmem_op(&op);
-       return rc;
-}
-
-/* xen generic tmem ops */
-
-static int xen_tmem_put_page(u32 pool_id, struct tmem_oid oid,
-                            u32 index, struct page *page)
-{
-       return xen_tmem_op(TMEM_PUT_PAGE, pool_id, oid, index,
-                          xen_page_to_gfn(page), 0, 0, 0);
-}
-
-static int xen_tmem_get_page(u32 pool_id, struct tmem_oid oid,
-                            u32 index, struct page *page)
-{
-       return xen_tmem_op(TMEM_GET_PAGE, pool_id, oid, index,
-                          xen_page_to_gfn(page), 0, 0, 0);
-}
-
-static int xen_tmem_flush_page(u32 pool_id, struct tmem_oid oid, u32 index)
-{
-       return xen_tmem_op(TMEM_FLUSH_PAGE, pool_id, oid, index,
-               0, 0, 0, 0);
-}
-
-static int xen_tmem_flush_object(u32 pool_id, struct tmem_oid oid)
-{
-       return xen_tmem_op(TMEM_FLUSH_OBJECT, pool_id, oid, 0, 0, 0, 0, 0);
-}
-
-
-#ifdef CONFIG_CLEANCACHE
-static int xen_tmem_destroy_pool(u32 pool_id)
-{
-       struct tmem_oid oid = { { 0 } };
-
-       return xen_tmem_op(TMEM_DESTROY_POOL, pool_id, oid, 0, 0, 0, 0, 0);
-}
-
-/* cleancache ops */
-
-static void tmem_cleancache_put_page(int pool, struct cleancache_filekey key,
-                                    pgoff_t index, struct page *page)
-{
-       u32 ind = (u32) index;
-       struct tmem_oid oid = *(struct tmem_oid *)&key;
-
-       if (pool < 0)
-               return;
-       if (ind != index)
-               return;
-       mb(); /* ensure page is quiescent; tmem may address it with an alias */
-       (void)xen_tmem_put_page((u32)pool, oid, ind, page);
-}
-
-static int tmem_cleancache_get_page(int pool, struct cleancache_filekey key,
-                                   pgoff_t index, struct page *page)
-{
-       u32 ind = (u32) index;
-       struct tmem_oid oid = *(struct tmem_oid *)&key;
-       int ret;
-
-       /* translate return values to linux semantics */
-       if (pool < 0)
-               return -1;
-       if (ind != index)
-               return -1;
-       ret = xen_tmem_get_page((u32)pool, oid, ind, page);
-       if (ret == 1)
-               return 0;
-       else
-               return -1;
-}
-
-static void tmem_cleancache_flush_page(int pool, struct cleancache_filekey key,
-                                      pgoff_t index)
-{
-       u32 ind = (u32) index;
-       struct tmem_oid oid = *(struct tmem_oid *)&key;
-
-       if (pool < 0)
-               return;
-       if (ind != index)
-               return;
-       (void)xen_tmem_flush_page((u32)pool, oid, ind);
-}
-
-static void tmem_cleancache_flush_inode(int pool, struct cleancache_filekey key)
-{
-       struct tmem_oid oid = *(struct tmem_oid *)&key;
-
-       if (pool < 0)
-               return;
-       (void)xen_tmem_flush_object((u32)pool, oid);
-}
-
-static void tmem_cleancache_flush_fs(int pool)
-{
-       if (pool < 0)
-               return;
-       (void)xen_tmem_destroy_pool((u32)pool);
-}
-
-static int tmem_cleancache_init_fs(size_t pagesize)
-{
-       struct tmem_pool_uuid uuid_private = TMEM_POOL_PRIVATE_UUID;
-
-       return xen_tmem_new_pool(uuid_private, 0, pagesize);
-}
-
-static int tmem_cleancache_init_shared_fs(uuid_t *uuid, size_t pagesize)
-{
-       struct tmem_pool_uuid shared_uuid;
-
-       shared_uuid.uuid_lo = *(u64 *)&uuid->b[0];
-       shared_uuid.uuid_hi = *(u64 *)&uuid->b[8];
-       return xen_tmem_new_pool(shared_uuid, TMEM_POOL_SHARED, pagesize);
-}
-
-static const struct cleancache_ops tmem_cleancache_ops = {
-       .put_page = tmem_cleancache_put_page,
-       .get_page = tmem_cleancache_get_page,
-       .invalidate_page = tmem_cleancache_flush_page,
-       .invalidate_inode = tmem_cleancache_flush_inode,
-       .invalidate_fs = tmem_cleancache_flush_fs,
-       .init_shared_fs = tmem_cleancache_init_shared_fs,
-       .init_fs = tmem_cleancache_init_fs
-};
-#endif
-
-#ifdef CONFIG_FRONTSWAP
-/* frontswap tmem operations */
-
-/* a single tmem poolid is used for all frontswap "types" (swapfiles) */
-static int tmem_frontswap_poolid;
-
-/*
- * Swizzling increases objects per swaptype, increasing tmem concurrency
- * for heavy swaploads.  Later, larger nr_cpus -> larger SWIZ_BITS
- */
-#define SWIZ_BITS              4
-#define SWIZ_MASK              ((1 << SWIZ_BITS) - 1)
-#define _oswiz(_type, _ind)    ((_type << SWIZ_BITS) | (_ind & SWIZ_MASK))
-#define iswiz(_ind)            (_ind >> SWIZ_BITS)
-
-static inline struct tmem_oid oswiz(unsigned type, u32 ind)
-{
-       struct tmem_oid oid = { .oid = { 0 } };
-       oid.oid[0] = _oswiz(type, ind);
-       return oid;
-}
-
-/* returns 0 if the page was successfully put into frontswap, -1 if not */
-static int tmem_frontswap_store(unsigned type, pgoff_t offset,
-                                  struct page *page)
-{
-       u64 ind64 = (u64)offset;
-       u32 ind = (u32)offset;
-       int pool = tmem_frontswap_poolid;
-       int ret;
-
-       /* THP isn't supported */
-       if (PageTransHuge(page))
-               return -1;
-
-       if (pool < 0)
-               return -1;
-       if (ind64 != ind)
-               return -1;
-       mb(); /* ensure page is quiescent; tmem may address it with an alias */
-       ret = xen_tmem_put_page(pool, oswiz(type, ind), iswiz(ind), page);
-       /* translate Xen tmem return values to linux semantics */
-       if (ret == 1)
-               return 0;
-       else
-               return -1;
-}
-
-/*
- * returns 0 if the page was successfully gotten from frontswap, -1 if
- * was not present (should never happen!)
- */
-static int tmem_frontswap_load(unsigned type, pgoff_t offset,
-                                  struct page *page)
-{
-       u64 ind64 = (u64)offset;
-       u32 ind = (u32)offset;
-       int pool = tmem_frontswap_poolid;
-       int ret;
-
-       if (pool < 0)
-               return -1;
-       if (ind64 != ind)
-               return -1;
-       ret = xen_tmem_get_page(pool, oswiz(type, ind), iswiz(ind), page);
-       /* translate Xen tmem return values to linux semantics */
-       if (ret == 1)
-               return 0;
-       else
-               return -1;
-}
-
-/* flush a single page from frontswap */
-static void tmem_frontswap_flush_page(unsigned type, pgoff_t offset)
-{
-       u64 ind64 = (u64)offset;
-       u32 ind = (u32)offset;
-       int pool = tmem_frontswap_poolid;
-
-       if (pool < 0)
-               return;
-       if (ind64 != ind)
-               return;
-       (void) xen_tmem_flush_page(pool, oswiz(type, ind), iswiz(ind));
-}
-
-/* flush all pages from the passed swaptype */
-static void tmem_frontswap_flush_area(unsigned type)
-{
-       int pool = tmem_frontswap_poolid;
-       int ind;
-
-       if (pool < 0)
-               return;
-       for (ind = SWIZ_MASK; ind >= 0; ind--)
-               (void)xen_tmem_flush_object(pool, oswiz(type, ind));
-}
-
-static void tmem_frontswap_init(unsigned ignored)
-{
-       struct tmem_pool_uuid private = TMEM_POOL_PRIVATE_UUID;
-
-       /* a single tmem poolid is used for all frontswap "types" (swapfiles) */
-       if (tmem_frontswap_poolid < 0)
-               tmem_frontswap_poolid =
-                   xen_tmem_new_pool(private, TMEM_POOL_PERSIST, PAGE_SIZE);
-}
-
-static struct frontswap_ops tmem_frontswap_ops = {
-       .store = tmem_frontswap_store,
-       .load = tmem_frontswap_load,
-       .invalidate_page = tmem_frontswap_flush_page,
-       .invalidate_area = tmem_frontswap_flush_area,
-       .init = tmem_frontswap_init
-};
-#endif
-
-static int __init xen_tmem_init(void)
-{
-       if (!xen_domain())
-               return 0;
-#ifdef CONFIG_FRONTSWAP
-       if (tmem_enabled && frontswap) {
-               char *s = "";
-
-               tmem_frontswap_poolid = -1;
-               frontswap_register_ops(&tmem_frontswap_ops);
-               pr_info("frontswap enabled, RAM provided by Xen Transcendent Memory%s\n",
-                       s);
-       }
-#endif
-#ifdef CONFIG_CLEANCACHE
-       BUILD_BUG_ON(sizeof(struct cleancache_filekey) != sizeof(struct tmem_oid));
-       if (tmem_enabled && cleancache) {
-               int err;
-
-               err = cleancache_register_ops(&tmem_cleancache_ops);
-               if (err)
-                       pr_warn("xen-tmem: failed to enable cleancache: %d\n",
-                               err);
-               else
-                       pr_info("cleancache enabled, RAM provided by "
-                               "Xen Transcendent Memory\n");
-       }
-#endif
-#ifdef CONFIG_XEN_SELFBALLOONING
-       /*
-        * There is no point of driving pages to the swap system if they
-        * aren't going anywhere in tmem universe.
-        */
-       if (!frontswap) {
-               selfshrinking = false;
-               selfballooning = false;
-       }
-       xen_selfballoon_init(selfballooning, selfshrinking);
-#endif
-       return 0;
-}
-
-module_init(xen_tmem_init)
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Dan Magenheimer <dan.magenheimer@oracle.com>");
-MODULE_DESCRIPTION("Shim to Xen transcendent memory");
index a67236b..6d12fc3 100644 (file)
@@ -129,8 +129,6 @@ void xen_balloon_init(void)
 {
        register_balloon(&balloon_dev);
 
-       register_xen_selfballooning(&balloon_dev);
-
        register_xenstore_notifier(&xenstore_notifier);
 }
 EXPORT_SYMBOL_GPL(xen_balloon_init);
diff --git a/drivers/xen/xen-selfballoon.c b/drivers/xen/xen-selfballoon.c
deleted file mode 100644 (file)
index 246f612..0000000
+++ /dev/null
@@ -1,579 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/******************************************************************************
- * Xen selfballoon driver (and optional frontswap self-shrinking driver)
- *
- * Copyright (c) 2009-2011, Dan Magenheimer, Oracle Corp.
- *
- * This code complements the cleancache and frontswap patchsets to optimize
- * support for Xen Transcendent Memory ("tmem").  The policy it implements
- * is rudimentary and will likely improve over time, but it does work well
- * enough today.
- *
- * Two functionalities are implemented here which both use "control theory"
- * (feedback) to optimize memory utilization. In a virtualized environment
- * such as Xen, RAM is often a scarce resource and we would like to ensure
- * that each of a possibly large number of virtual machines is using RAM
- * efficiently, i.e. using as little as possible when under light load
- * and obtaining as much as possible when memory demands are high.
- * Since RAM needs vary highly dynamically and sometimes dramatically,
- * "hysteresis" is used, that is, memory target is determined not just
- * on current data but also on past data stored in the system.
- *
- * "Selfballooning" creates memory pressure by managing the Xen balloon
- * driver to decrease and increase available kernel memory, driven
- * largely by the target value of "Committed_AS" (see /proc/meminfo).
- * Since Committed_AS does not account for clean mapped pages (i.e. pages
- * in RAM that are identical to pages on disk), selfballooning has the
- * affect of pushing less frequently used clean pagecache pages out of
- * kernel RAM and, presumably using cleancache, into Xen tmem where
- * Xen can more efficiently optimize RAM utilization for such pages.
- *
- * When kernel memory demand unexpectedly increases faster than Xen, via
- * the selfballoon driver, is able to (or chooses to) provide usable RAM,
- * the kernel may invoke swapping.  In most cases, frontswap is able
- * to absorb this swapping into Xen tmem.  However, due to the fact
- * that the kernel swap subsystem assumes swapping occurs to a disk,
- * swapped pages may sit on the disk for a very long time; even if
- * the kernel knows the page will never be used again.  This is because
- * the disk space costs very little and can be overwritten when
- * necessary.  When such stale pages are in frontswap, however, they
- * are taking up valuable real estate.  "Frontswap selfshrinking" works
- * to resolve this:  When frontswap activity is otherwise stable
- * and the guest kernel is not under memory pressure, the "frontswap
- * selfshrinking" accounts for this by providing pressure to remove some
- * pages from frontswap and return them to kernel memory.
- *
- * For both "selfballooning" and "frontswap-selfshrinking", a worker
- * thread is used and sysfs tunables are provided to adjust the frequency
- * and rate of adjustments to achieve the goal, as well as to disable one
- * or both functions independently.
- *
- * While some argue that this functionality can and should be implemented
- * in userspace, it has been observed that bad things happen (e.g. OOMs).
- *
- * System configuration note: Selfballooning should not be enabled on
- * systems without a sufficiently large swap device configured; for best
- * results, it is recommended that total swap be increased by the size
- * of the guest memory. Note, that selfballooning should be disabled by default
- * if frontswap is not configured.  Similarly selfballooning should be enabled
- * by default if frontswap is configured and can be disabled with the
- * "tmem.selfballooning=0" kernel boot option.  Finally, when frontswap is
- * configured, frontswap-selfshrinking can be disabled  with the
- * "tmem.selfshrink=0" kernel boot option.
- *
- * Selfballooning is disallowed in domain0 and force-disabled.
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/memblock.h>
-#include <linux/swap.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/workqueue.h>
-#include <linux/device.h>
-#include <xen/balloon.h>
-#include <xen/tmem.h>
-#include <xen/xen.h>
-
-/* Enable/disable with sysfs. */
-static int xen_selfballooning_enabled __read_mostly;
-
-/*
- * Controls rate at which memory target (this iteration) approaches
- * ultimate goal when memory need is increasing (up-hysteresis) or
- * decreasing (down-hysteresis). Higher values of hysteresis cause
- * slower increases/decreases. The default values for the various
- * parameters were deemed reasonable by experimentation, may be
- * workload-dependent, and can all be adjusted via sysfs.
- */
-static unsigned int selfballoon_downhysteresis __read_mostly = 8;
-static unsigned int selfballoon_uphysteresis __read_mostly = 1;
-
-/* In HZ, controls frequency of worker invocation. */
-static unsigned int selfballoon_interval __read_mostly = 5;
-
-/*
- * Minimum usable RAM in MB for selfballooning target for balloon.
- * If non-zero, it is added to totalreserve_pages and self-ballooning
- * will not balloon below the sum.  If zero, a piecewise linear function
- * is calculated as a minimum and added to totalreserve_pages.  Note that
- * setting this value indiscriminately may cause OOMs and crashes.
- */
-static unsigned int selfballoon_min_usable_mb;
-
-/*
- * Amount of RAM in MB to add to the target number of pages.
- * Can be used to reserve some more room for caches and the like.
- */
-static unsigned int selfballoon_reserved_mb;
-
-static void selfballoon_process(struct work_struct *work);
-static DECLARE_DELAYED_WORK(selfballoon_worker, selfballoon_process);
-
-#ifdef CONFIG_FRONTSWAP
-#include <linux/frontswap.h>
-
-/* Enable/disable with sysfs. */
-static bool frontswap_selfshrinking __read_mostly;
-
-/*
- * The default values for the following parameters were deemed reasonable
- * by experimentation, may be workload-dependent, and can all be
- * adjusted via sysfs.
- */
-
-/* Control rate for frontswap shrinking. Higher hysteresis is slower. */
-static unsigned int frontswap_hysteresis __read_mostly = 20;
-
-/*
- * Number of selfballoon worker invocations to wait before observing that
- * frontswap selfshrinking should commence. Note that selfshrinking does
- * not use a separate worker thread.
- */
-static unsigned int frontswap_inertia __read_mostly = 3;
-
-/* Countdown to next invocation of frontswap_shrink() */
-static unsigned long frontswap_inertia_counter;
-
-/*
- * Invoked by the selfballoon worker thread, uses current number of pages
- * in frontswap (frontswap_curr_pages()), previous status, and control
- * values (hysteresis and inertia) to determine if frontswap should be
- * shrunk and what the new frontswap size should be.  Note that
- * frontswap_shrink is essentially a partial swapoff that immediately
- * transfers pages from the "swap device" (frontswap) back into kernel
- * RAM; despite the name, frontswap "shrinking" is very different from
- * the "shrinker" interface used by the kernel MM subsystem to reclaim
- * memory.
- */
-static void frontswap_selfshrink(void)
-{
-       static unsigned long cur_frontswap_pages;
-       unsigned long last_frontswap_pages;
-       unsigned long tgt_frontswap_pages;
-
-       last_frontswap_pages = cur_frontswap_pages;
-       cur_frontswap_pages = frontswap_curr_pages();
-       if (!cur_frontswap_pages ||
-                       (cur_frontswap_pages > last_frontswap_pages)) {
-               frontswap_inertia_counter = frontswap_inertia;
-               return;
-       }
-       if (frontswap_inertia_counter && --frontswap_inertia_counter)
-               return;
-       if (cur_frontswap_pages <= frontswap_hysteresis)
-               tgt_frontswap_pages = 0;
-       else
-               tgt_frontswap_pages = cur_frontswap_pages -
-                       (cur_frontswap_pages / frontswap_hysteresis);
-       frontswap_shrink(tgt_frontswap_pages);
-       frontswap_inertia_counter = frontswap_inertia;
-}
-
-#endif /* CONFIG_FRONTSWAP */
-
-#define MB2PAGES(mb)   ((mb) << (20 - PAGE_SHIFT))
-#define PAGES2MB(pages) ((pages) >> (20 - PAGE_SHIFT))
-
-/*
- * Use current balloon size, the goal (vm_committed_as), and hysteresis
- * parameters to set a new target balloon size
- */
-static void selfballoon_process(struct work_struct *work)
-{
-       unsigned long cur_pages, goal_pages, tgt_pages, floor_pages;
-       unsigned long useful_pages;
-       bool reset_timer = false;
-
-       if (xen_selfballooning_enabled) {
-               cur_pages = totalram_pages();
-               tgt_pages = cur_pages; /* default is no change */
-               goal_pages = vm_memory_committed() +
-                               totalreserve_pages +
-                               MB2PAGES(selfballoon_reserved_mb);
-#ifdef CONFIG_FRONTSWAP
-               /* allow space for frontswap pages to be repatriated */
-               if (frontswap_selfshrinking)
-                       goal_pages += frontswap_curr_pages();
-#endif
-               if (cur_pages > goal_pages)
-                       tgt_pages = cur_pages -
-                               ((cur_pages - goal_pages) /
-                                 selfballoon_downhysteresis);
-               else if (cur_pages < goal_pages)
-                       tgt_pages = cur_pages +
-                               ((goal_pages - cur_pages) /
-                                 selfballoon_uphysteresis);
-               /* else if cur_pages == goal_pages, no change */
-               useful_pages = max_pfn - totalreserve_pages;
-               if (selfballoon_min_usable_mb != 0)
-                       floor_pages = totalreserve_pages +
-                                       MB2PAGES(selfballoon_min_usable_mb);
-               /* piecewise linear function ending in ~3% slope */
-               else if (useful_pages < MB2PAGES(16))
-                       floor_pages = max_pfn; /* not worth ballooning */
-               else if (useful_pages < MB2PAGES(64))
-                       floor_pages = totalreserve_pages + MB2PAGES(16) +
-                                       ((useful_pages - MB2PAGES(16)) >> 1);
-               else if (useful_pages < MB2PAGES(512))
-                       floor_pages = totalreserve_pages + MB2PAGES(40) +
-                                       ((useful_pages - MB2PAGES(40)) >> 3);
-               else /* useful_pages >= MB2PAGES(512) */
-                       floor_pages = totalreserve_pages + MB2PAGES(99) +
-                                       ((useful_pages - MB2PAGES(99)) >> 5);
-               if (tgt_pages < floor_pages)
-                       tgt_pages = floor_pages;
-               balloon_set_new_target(tgt_pages +
-                       balloon_stats.current_pages - totalram_pages());
-               reset_timer = true;
-       }
-#ifdef CONFIG_FRONTSWAP
-       if (frontswap_selfshrinking) {
-               frontswap_selfshrink();
-               reset_timer = true;
-       }
-#endif
-       if (reset_timer)
-               schedule_delayed_work(&selfballoon_worker,
-                       selfballoon_interval * HZ);
-}
-
-#ifdef CONFIG_SYSFS
-
-#include <linux/capability.h>
-
-#define SELFBALLOON_SHOW(name, format, args...)                                \
-       static ssize_t show_##name(struct device *dev,  \
-                                         struct device_attribute *attr, \
-                                         char *buf) \
-       { \
-               return sprintf(buf, format, ##args); \
-       }
-
-SELFBALLOON_SHOW(selfballooning, "%d\n", xen_selfballooning_enabled);
-
-static ssize_t store_selfballooning(struct device *dev,
-                           struct device_attribute *attr,
-                           const char *buf,
-                           size_t count)
-{
-       bool was_enabled = xen_selfballooning_enabled;
-       unsigned long tmp;
-       int err;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
-       err = kstrtoul(buf, 10, &tmp);
-       if (err)
-               return err;
-       if ((tmp != 0) && (tmp != 1))
-               return -EINVAL;
-
-       xen_selfballooning_enabled = !!tmp;
-       if (!was_enabled && xen_selfballooning_enabled)
-               schedule_delayed_work(&selfballoon_worker,
-                       selfballoon_interval * HZ);
-
-       return count;
-}
-
-static DEVICE_ATTR(selfballooning, S_IRUGO | S_IWUSR,
-                  show_selfballooning, store_selfballooning);
-
-SELFBALLOON_SHOW(selfballoon_interval, "%d\n", selfballoon_interval);
-
-static ssize_t store_selfballoon_interval(struct device *dev,
-                                         struct device_attribute *attr,
-                                         const char *buf,
-                                         size_t count)
-{
-       unsigned long val;
-       int err;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       err = kstrtoul(buf, 10, &val);
-       if (err)
-               return err;
-       if (val == 0)
-               return -EINVAL;
-       selfballoon_interval = val;
-       return count;
-}
-
-static DEVICE_ATTR(selfballoon_interval, S_IRUGO | S_IWUSR,
-                  show_selfballoon_interval, store_selfballoon_interval);
-
-SELFBALLOON_SHOW(selfballoon_downhys, "%d\n", selfballoon_downhysteresis);
-
-static ssize_t store_selfballoon_downhys(struct device *dev,
-                                        struct device_attribute *attr,
-                                        const char *buf,
-                                        size_t count)
-{
-       unsigned long val;
-       int err;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       err = kstrtoul(buf, 10, &val);
-       if (err)
-               return err;
-       if (val == 0)
-               return -EINVAL;
-       selfballoon_downhysteresis = val;
-       return count;
-}
-
-static DEVICE_ATTR(selfballoon_downhysteresis, S_IRUGO | S_IWUSR,
-                  show_selfballoon_downhys, store_selfballoon_downhys);
-
-
-SELFBALLOON_SHOW(selfballoon_uphys, "%d\n", selfballoon_uphysteresis);
-
-static ssize_t store_selfballoon_uphys(struct device *dev,
-                                      struct device_attribute *attr,
-                                      const char *buf,
-                                      size_t count)
-{
-       unsigned long val;
-       int err;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       err = kstrtoul(buf, 10, &val);
-       if (err)
-               return err;
-       if (val == 0)
-               return -EINVAL;
-       selfballoon_uphysteresis = val;
-       return count;
-}
-
-static DEVICE_ATTR(selfballoon_uphysteresis, S_IRUGO | S_IWUSR,
-                  show_selfballoon_uphys, store_selfballoon_uphys);
-
-SELFBALLOON_SHOW(selfballoon_min_usable_mb, "%d\n",
-                               selfballoon_min_usable_mb);
-
-static ssize_t store_selfballoon_min_usable_mb(struct device *dev,
-                                              struct device_attribute *attr,
-                                              const char *buf,
-                                              size_t count)
-{
-       unsigned long val;
-       int err;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       err = kstrtoul(buf, 10, &val);
-       if (err)
-               return err;
-       if (val == 0)
-               return -EINVAL;
-       selfballoon_min_usable_mb = val;
-       return count;
-}
-
-static DEVICE_ATTR(selfballoon_min_usable_mb, S_IRUGO | S_IWUSR,
-                  show_selfballoon_min_usable_mb,
-                  store_selfballoon_min_usable_mb);
-
-SELFBALLOON_SHOW(selfballoon_reserved_mb, "%d\n",
-                               selfballoon_reserved_mb);
-
-static ssize_t store_selfballoon_reserved_mb(struct device *dev,
-                                            struct device_attribute *attr,
-                                            const char *buf,
-                                            size_t count)
-{
-       unsigned long val;
-       int err;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       err = kstrtoul(buf, 10, &val);
-       if (err)
-               return err;
-       if (val == 0)
-               return -EINVAL;
-       selfballoon_reserved_mb = val;
-       return count;
-}
-
-static DEVICE_ATTR(selfballoon_reserved_mb, S_IRUGO | S_IWUSR,
-                  show_selfballoon_reserved_mb,
-                  store_selfballoon_reserved_mb);
-
-
-#ifdef CONFIG_FRONTSWAP
-SELFBALLOON_SHOW(frontswap_selfshrinking, "%d\n", frontswap_selfshrinking);
-
-static ssize_t store_frontswap_selfshrinking(struct device *dev,
-                                            struct device_attribute *attr,
-                                            const char *buf,
-                                            size_t count)
-{
-       bool was_enabled = frontswap_selfshrinking;
-       unsigned long tmp;
-       int err;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       err = kstrtoul(buf, 10, &tmp);
-       if (err)
-               return err;
-       if ((tmp != 0) && (tmp != 1))
-               return -EINVAL;
-       frontswap_selfshrinking = !!tmp;
-       if (!was_enabled && !xen_selfballooning_enabled &&
-            frontswap_selfshrinking)
-               schedule_delayed_work(&selfballoon_worker,
-                       selfballoon_interval * HZ);
-
-       return count;
-}
-
-static DEVICE_ATTR(frontswap_selfshrinking, S_IRUGO | S_IWUSR,
-                  show_frontswap_selfshrinking, store_frontswap_selfshrinking);
-
-SELFBALLOON_SHOW(frontswap_inertia, "%d\n", frontswap_inertia);
-
-static ssize_t store_frontswap_inertia(struct device *dev,
-                                      struct device_attribute *attr,
-                                      const char *buf,
-                                      size_t count)
-{
-       unsigned long val;
-       int err;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       err = kstrtoul(buf, 10, &val);
-       if (err)
-               return err;
-       if (val == 0)
-               return -EINVAL;
-       frontswap_inertia = val;
-       frontswap_inertia_counter = val;
-       return count;
-}
-
-static DEVICE_ATTR(frontswap_inertia, S_IRUGO | S_IWUSR,
-                  show_frontswap_inertia, store_frontswap_inertia);
-
-SELFBALLOON_SHOW(frontswap_hysteresis, "%d\n", frontswap_hysteresis);
-
-static ssize_t store_frontswap_hysteresis(struct device *dev,
-                                         struct device_attribute *attr,
-                                         const char *buf,
-                                         size_t count)
-{
-       unsigned long val;
-       int err;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       err = kstrtoul(buf, 10, &val);
-       if (err)
-               return err;
-       if (val == 0)
-               return -EINVAL;
-       frontswap_hysteresis = val;
-       return count;
-}
-
-static DEVICE_ATTR(frontswap_hysteresis, S_IRUGO | S_IWUSR,
-                  show_frontswap_hysteresis, store_frontswap_hysteresis);
-
-#endif /* CONFIG_FRONTSWAP */
-
-static struct attribute *selfballoon_attrs[] = {
-       &dev_attr_selfballooning.attr,
-       &dev_attr_selfballoon_interval.attr,
-       &dev_attr_selfballoon_downhysteresis.attr,
-       &dev_attr_selfballoon_uphysteresis.attr,
-       &dev_attr_selfballoon_min_usable_mb.attr,
-       &dev_attr_selfballoon_reserved_mb.attr,
-#ifdef CONFIG_FRONTSWAP
-       &dev_attr_frontswap_selfshrinking.attr,
-       &dev_attr_frontswap_hysteresis.attr,
-       &dev_attr_frontswap_inertia.attr,
-#endif
-       NULL
-};
-
-static const struct attribute_group selfballoon_group = {
-       .name = "selfballoon",
-       .attrs = selfballoon_attrs
-};
-#endif
-
-int register_xen_selfballooning(struct device *dev)
-{
-       int error = -1;
-
-#ifdef CONFIG_SYSFS
-       error = sysfs_create_group(&dev->kobj, &selfballoon_group);
-#endif
-       return error;
-}
-EXPORT_SYMBOL(register_xen_selfballooning);
-
-int xen_selfballoon_init(bool use_selfballooning, bool use_frontswap_selfshrink)
-{
-       bool enable = false;
-       unsigned long reserve_pages;
-
-       if (!xen_domain())
-               return -ENODEV;
-
-       if (xen_initial_domain()) {
-               pr_info("Xen selfballooning driver disabled for domain0\n");
-               return -ENODEV;
-       }
-
-       xen_selfballooning_enabled = tmem_enabled && use_selfballooning;
-       if (xen_selfballooning_enabled) {
-               pr_info("Initializing Xen selfballooning driver\n");
-               enable = true;
-       }
-#ifdef CONFIG_FRONTSWAP
-       frontswap_selfshrinking = tmem_enabled && use_frontswap_selfshrink;
-       if (frontswap_selfshrinking) {
-               pr_info("Initializing frontswap selfshrinking driver\n");
-               enable = true;
-       }
-#endif
-       if (!enable)
-               return -ENODEV;
-
-       /*
-        * Give selfballoon_reserved_mb a default value(10% of total ram pages)
-        * to make selfballoon not so aggressive.
-        *
-        * There are mainly two reasons:
-        * 1) The original goal_page didn't consider some pages used by kernel
-        *    space, like slab pages and memory used by device drivers.
-        *
-        * 2) The balloon driver may not give back memory to guest OS fast
-        *    enough when the workload suddenly aquries a lot of physical memory.
-        *
-        * In both cases, the guest OS will suffer from memory pressure and
-        * OOM killer may be triggered.
-        * By reserving extra 10% of total ram pages, we can keep the system
-        * much more reliably and response faster in some cases.
-        */
-       if (!selfballoon_reserved_mb) {
-               reserve_pages = totalram_pages() / 10;
-               selfballoon_reserved_mb = PAGES2MB(reserve_pages);
-       }
-       schedule_delayed_work(&selfballoon_worker, selfballoon_interval * HZ);
-
-       return 0;
-}
-EXPORT_SYMBOL(xen_selfballoon_init);
index 20c1448..d7d6423 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/fs.h>
+#include <linux/fs_context.h>
 #include <linux/magic.h>
 
 #include <xen/xen.h>
@@ -43,7 +44,7 @@ static const struct file_operations capabilities_file_ops = {
        .llseek = default_llseek,
 };
 
-static int xenfs_fill_super(struct super_block *sb, void *data, int silent)
+static int xenfs_fill_super(struct super_block *sb, struct fs_context *fc)
 {
        static const struct tree_descr xenfs_files[] = {
                [2] = { "xenbus", &xen_xenbus_fops, S_IRUSR|S_IWUSR },
@@ -68,17 +69,25 @@ static int xenfs_fill_super(struct super_block *sb, void *data, int silent)
                        xen_initial_domain() ? xenfs_init_files : xenfs_files);
 }
 
-static struct dentry *xenfs_mount(struct file_system_type *fs_type,
-                                 int flags, const char *dev_name,
-                                 void *data)
+static int xenfs_get_tree(struct fs_context *fc)
 {
-       return mount_single(fs_type, flags, data, xenfs_fill_super);
+       return get_tree_single(fc, xenfs_fill_super);
+}
+
+static const struct fs_context_operations xenfs_context_ops = {
+       .get_tree       = xenfs_get_tree,
+};
+
+static int xenfs_init_fs_context(struct fs_context *fc)
+{
+       fc->ops = &xenfs_context_ops;
+       return 0;
 }
 
 static struct file_system_type xenfs_type = {
        .owner =        THIS_MODULE,
        .name =         "xenfs",
-       .mount =        xenfs_mount,
+       .init_fs_context = xenfs_init_fs_context,
        .kill_sb =      kill_litter_super,
 };
 MODULE_ALIAS_FS("xenfs");
index c9aea23..d60089f 100644 (file)
@@ -52,7 +52,7 @@ obj-$(CONFIG_COREDUMP)                += coredump.o
 obj-$(CONFIG_SYSCTL)           += drop_caches.o
 
 obj-$(CONFIG_FHANDLE)          += fhandle.o
-obj-$(CONFIG_FS_IOMAP)         += iomap.o
+obj-y                          += iomap/
 
 obj-y                          += quota/
 
index 804c6a7..b7e844d 100644 (file)
@@ -1,4 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/buffer_head.h>
 #include <linux/fs.h>
 #include <linux/adfs_fs.h>
 
@@ -8,6 +9,15 @@
 #define ADFS_BAD_FRAG           1
 #define ADFS_ROOT_FRAG          2
 
+#define ADFS_FILETYPE_NONE     ((u16)~0)
+
+/* RISC OS 12-bit filetype is stored in load_address[19:8] */
+static inline u16 adfs_filetype(u32 loadaddr)
+{
+       return (loadaddr & 0xfff00000) == 0xfff00000 ?
+              (loadaddr >> 8) & 0xfff : ADFS_FILETYPE_NONE;
+}
+
 #define ADFS_NDA_OWNER_READ    (1 << 0)
 #define ADFS_NDA_OWNER_WRITE   (1 << 1)
 #define ADFS_NDA_LOCKED                (1 << 2)
 
 #include "dir_f.h"
 
-struct buffer_head;
-
 /*
  * adfs file system inode data in memory
  */
 struct adfs_inode_info {
        loff_t          mmu_private;
-       unsigned long   parent_id;      /* object id of parent          */
+       __u32           parent_id;      /* parent indirect disc address */
        __u32           loadaddr;       /* RISC OS load address         */
        __u32           execaddr;       /* RISC OS exec address         */
-       unsigned int    filetype;       /* RISC OS file type            */
        unsigned int    attr;           /* RISC OS permissions          */
-       unsigned int    stamped:1;      /* RISC OS file has date/time   */
        struct inode vfs_inode;
 };
 
+static inline struct adfs_inode_info *ADFS_I(struct inode *inode)
+{
+       return container_of(inode, struct adfs_inode_info, vfs_inode);
+}
+
+static inline bool adfs_inode_is_stamped(struct inode *inode)
+{
+       return (ADFS_I(inode)->loadaddr & 0xfff00000) == 0xfff00000;
+}
+
 /*
  * Forward-declare this
  */
@@ -59,10 +75,8 @@ struct adfs_sb_info {
        __u32           s_ids_per_zone; /* max. no ids in one zone */
        __u32           s_idlen;        /* length of ID in map */
        __u32           s_map_size;     /* sector size of a map */
-       unsigned long   s_size;         /* total size (in blocks) of this fs */
        signed int      s_map2blk;      /* shift left by this for map->sector*/
        unsigned int    s_log2sharesize;/* log2 share size */
-       __le32          s_version;      /* disc format version */
        unsigned int    s_namelen;      /* maximum number of characters in name  */
 };
 
@@ -71,11 +85,6 @@ static inline struct adfs_sb_info *ADFS_SB(struct super_block *sb)
        return sb->s_fs_info;
 }
 
-static inline struct adfs_inode_info *ADFS_I(struct inode *inode)
-{
-       return container_of(inode, struct adfs_inode_info, vfs_inode);
-}
-
 /*
  * Directory handling
  */
@@ -89,7 +98,7 @@ struct adfs_dir {
        struct buffer_head      **bh_fplus;
 
        unsigned int            pos;
-       unsigned int            parent_id;
+       __u32                   parent_id;
 
        struct adfs_dirheader   dirhead;
        union  adfs_dirtail     dirtail;
@@ -101,20 +110,18 @@ struct adfs_dir {
 #define ADFS_MAX_NAME_LEN      (256 + 4) /* +4 for ,xyz hex filetype suffix */
 struct object_info {
        __u32           parent_id;              /* parent object id     */
-       __u32           file_id;                /* object id            */
+       __u32           indaddr;                /* indirect disc addr   */
        __u32           loadaddr;               /* load address         */
        __u32           execaddr;               /* execution address    */
        __u32           size;                   /* size                 */
        __u8            attr;                   /* RISC OS attributes   */
        unsigned int    name_len;               /* name length          */
        char            name[ADFS_MAX_NAME_LEN];/* file name            */
-
-       /* RISC OS file type (12-bit: derived from loadaddr) */
-       __u16           filetype;
 };
 
 struct adfs_dir_ops {
-       int     (*read)(struct super_block *sb, unsigned int id, unsigned int sz, struct adfs_dir *dir);
+       int     (*read)(struct super_block *sb, unsigned int indaddr,
+                       unsigned int size, struct adfs_dir *dir);
        int     (*setpos)(struct adfs_dir *dir, unsigned int fpos);
        int     (*getnext)(struct adfs_dir *dir, struct object_info *obj);
        int     (*update)(struct adfs_dir *dir, struct object_info *obj);
@@ -137,7 +144,7 @@ int adfs_write_inode(struct inode *inode, struct writeback_control *wbc);
 int adfs_notify_change(struct dentry *dentry, struct iattr *attr);
 
 /* map.c */
-extern int adfs_map_lookup(struct super_block *sb, unsigned int frag_id, unsigned int offset);
+int adfs_map_lookup(struct super_block *sb, u32 frag_id, unsigned int offset);
 extern unsigned int adfs_map_free(struct super_block *sb);
 
 /* Misc */
@@ -145,6 +152,7 @@ __printf(3, 4)
 void __adfs_error(struct super_block *sb, const char *function,
                  const char *fmt, ...);
 #define adfs_error(sb, fmt...) __adfs_error(sb, __func__, fmt)
+void adfs_msg(struct super_block *sb, const char *pfx, const char *fmt, ...);
 
 /* super.c */
 
@@ -182,16 +190,28 @@ static inline __u32 signed_asl(__u32 val, signed int shift)
  *
  * The root directory ID should always be looked up in the map [3.4]
  */
-static inline int
-__adfs_block_map(struct super_block *sb, unsigned int object_id,
-                unsigned int block)
+static inline int __adfs_block_map(struct super_block *sb, u32 indaddr,
+                                  unsigned int block)
 {
-       if (object_id & 255) {
+       if (indaddr & 255) {
                unsigned int off;
 
-               off = (object_id & 255) - 1;
+               off = (indaddr & 255) - 1;
                block += off << ADFS_SB(sb)->s_log2sharesize;
        }
 
-       return adfs_map_lookup(sb, object_id >> 8, block);
+       return adfs_map_lookup(sb, indaddr >> 8, block);
+}
+
+/* Return the disc record from the map */
+static inline
+struct adfs_discrecord *adfs_map_discrecord(struct adfs_discmap *dm)
+{
+       return (void *)(dm[0].dm_bh->b_data + 4);
+}
+
+static inline u64 adfs_disc_size(const struct adfs_discrecord *dr)
+{
+       return (u64)le32_to_cpu(dr->disc_size_high) << 32 |
+                   le32_to_cpu(dr->disc_size);
 }
index 35a4d9f..a54c532 100644 (file)
@@ -35,20 +35,14 @@ void adfs_object_fixup(struct adfs_dir *dir, struct object_info *obj)
        if (obj->name_len <= 2 && dots == obj->name_len)
                obj->name[0] = '^';
 
-       obj->filetype = -1;
-
        /*
-        * object is a file and is filetyped and timestamped?
-        * RISC OS 12-bit filetype is stored in load_address[19:8]
+        * If the object is a file, and the user requested the ,xyz hex
+        * filetype suffix to the name, check the filetype and append.
         */
-       if ((0 == (obj->attr & ADFS_NDA_DIRECTORY)) &&
-           (0xfff00000 == (0xfff00000 & obj->loadaddr))) {
-               obj->filetype = (__u16) ((0x000fff00 & obj->loadaddr) >> 8);
-
-               /* optionally append the ,xyz hex filetype suffix */
-               if (ADFS_SB(dir->sb)->s_ftsuffix) {
-                       __u16 filetype = obj->filetype;
+       if (!(obj->attr & ADFS_NDA_DIRECTORY) && ADFS_SB(dir->sb)->s_ftsuffix) {
+               u16 filetype = adfs_filetype(obj->loadaddr);
 
+               if (filetype != ADFS_FILETYPE_NONE) {
                        obj->name[obj->name_len++] = ',';
                        obj->name[obj->name_len++] = hex_asc_lo(filetype >> 8);
                        obj->name[obj->name_len++] = hex_asc_lo(filetype >> 4);
@@ -92,7 +86,7 @@ adfs_readdir(struct file *file, struct dir_context *ctx)
                goto unlock_out;
        while (ops->getnext(&dir, &obj) == 0) {
                if (!dir_emit(ctx, obj.name, obj.name_len,
-                           obj.file_id, DT_UNKNOWN))
+                             obj.indaddr, DT_UNKNOWN))
                        break;
                ctx->pos++;
        }
@@ -113,8 +107,8 @@ adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait)
        const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
        struct adfs_dir dir;
 
-       printk(KERN_INFO "adfs_dir_update: object %06X in dir %06X\n",
-                obj->file_id, obj->parent_id);
+       printk(KERN_INFO "adfs_dir_update: object %06x in dir %06x\n",
+                obj->indaddr, obj->parent_id);
 
        if (!ops->update) {
                ret = -EINVAL;
@@ -178,7 +172,8 @@ static int adfs_dir_lookup_byname(struct inode *inode, const struct qstr *qstr,
                goto out;
 
        if (ADFS_I(inode)->parent_id != dir.parent_id) {
-               adfs_error(sb, "parent directory changed under me! (%lx but got %x)\n",
+               adfs_error(sb,
+                          "parent directory changed under me! (%06x but got %06x)\n",
                           ADFS_I(inode)->parent_id, dir.parent_id);
                ret = -EIO;
                goto free_out;
index 7557378..c1a950c 100644 (file)
@@ -6,7 +6,6 @@
  *
  *  E and F format directory handling
  */
-#include <linux/buffer_head.h>
 #include "adfs.h"
 #include "dir_f.h"
 
@@ -124,12 +123,9 @@ adfs_dir_checkbyte(const struct adfs_dir *dir)
        return (dircheck ^ (dircheck >> 8) ^ (dircheck >> 16) ^ (dircheck >> 24)) & 0xff;
 }
 
-/*
- * Read and check that a directory is valid
- */
-static int
-adfs_dir_read(struct super_block *sb, unsigned long object_id,
-             unsigned int size, struct adfs_dir *dir)
+/* Read and check that a directory is valid */
+static int adfs_dir_read(struct super_block *sb, u32 indaddr,
+                        unsigned int size, struct adfs_dir *dir)
 {
        const unsigned int blocksize_bits = sb->s_blocksize_bits;
        int blk = 0;
@@ -149,10 +145,10 @@ adfs_dir_read(struct super_block *sb, unsigned long object_id,
        for (blk = 0; blk < size; blk++) {
                int phys;
 
-               phys = __adfs_block_map(sb, object_id, blk);
+               phys = __adfs_block_map(sb, indaddr, blk);
                if (!phys) {
-                       adfs_error(sb, "dir object %lX has a hole at offset %d",
-                                  object_id, blk);
+                       adfs_error(sb, "dir %06x has a hole at offset %d",
+                                  indaddr, blk);
                        goto release_buffers;
                }
 
@@ -180,8 +176,7 @@ adfs_dir_read(struct super_block *sb, unsigned long object_id,
        return 0;
 
 bad_dir:
-       adfs_error(sb, "corrupted directory fragment %lX",
-                  object_id);
+       adfs_error(sb, "dir %06x is corrupted", indaddr);
 release_buffers:
        for (blk -= 1; blk >= 0; blk -= 1)
                brelse(dir->bh[blk]);
@@ -208,7 +203,7 @@ adfs_dir2obj(struct adfs_dir *dir, struct object_info *obj,
        }
 
        obj->name_len = name_len;
-       obj->file_id  = adfs_readval(de->dirinddiscadd, 3);
+       obj->indaddr  = adfs_readval(de->dirinddiscadd, 3);
        obj->loadaddr = adfs_readval(de->dirload, 4);
        obj->execaddr = adfs_readval(de->direxec, 4);
        obj->size     = adfs_readval(de->dirlen,  4);
@@ -223,7 +218,7 @@ adfs_dir2obj(struct adfs_dir *dir, struct object_info *obj,
 static inline void
 adfs_obj2dir(struct adfs_direntry *de, struct object_info *obj)
 {
-       adfs_writeval(de->dirinddiscadd, 3, obj->file_id);
+       adfs_writeval(de->dirinddiscadd, 3, obj->indaddr);
        adfs_writeval(de->dirload, 4, obj->loadaddr);
        adfs_writeval(de->direxec, 4, obj->execaddr);
        adfs_writeval(de->dirlen,  4, obj->size);
@@ -309,8 +304,7 @@ __adfs_dir_put(struct adfs_dir *dir, int pos, struct object_info *obj)
  * the caller is responsible for holding the necessary
  * locks.
  */
-static int
-adfs_dir_find_entry(struct adfs_dir *dir, unsigned long object_id)
+static int adfs_dir_find_entry(struct adfs_dir *dir, u32 indaddr)
 {
        int pos, ret;
 
@@ -322,7 +316,7 @@ adfs_dir_find_entry(struct adfs_dir *dir, unsigned long object_id)
                if (!__adfs_dir_get(dir, pos, &obj))
                        break;
 
-               if (obj.file_id == object_id) {
+               if (obj.indaddr == indaddr) {
                        ret = pos;
                        break;
                }
@@ -331,15 +325,15 @@ adfs_dir_find_entry(struct adfs_dir *dir, unsigned long object_id)
        return ret;
 }
 
-static int
-adfs_f_read(struct super_block *sb, unsigned int id, unsigned int sz, struct adfs_dir *dir)
+static int adfs_f_read(struct super_block *sb, u32 indaddr, unsigned int size,
+                      struct adfs_dir *dir)
 {
        int ret;
 
-       if (sz != ADFS_NEWDIR_SIZE)
+       if (size != ADFS_NEWDIR_SIZE)
                return -EIO;
 
-       ret = adfs_dir_read(sb, id, sz, dir);
+       ret = adfs_dir_read(sb, indaddr, size, dir);
        if (ret)
                adfs_error(sb, "unable to read directory");
        else
@@ -376,7 +370,7 @@ adfs_f_update(struct adfs_dir *dir, struct object_info *obj)
        struct super_block *sb = dir->sb;
        int ret, i;
 
-       ret = adfs_dir_find_entry(dir, obj->file_id);
+       ret = adfs_dir_find_entry(dir, obj->indaddr);
        if (ret < 0) {
                adfs_error(dir->sb, "unable to locate entry to update");
                goto out;
index 6c5fbb0..d56924c 100644 (file)
@@ -4,7 +4,6 @@
  *
  *  Copyright (C) 1997-1999 Russell King
  */
-#include <linux/buffer_head.h>
 #include <linux/slab.h>
 #include "adfs.h"
 #include "dir_fplus.h"
@@ -37,17 +36,15 @@ adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct
        h = (struct adfs_bigdirheader *)dir->bh_fplus[0]->b_data;
        size = le32_to_cpu(h->bigdirsize);
        if (size != sz) {
-               printk(KERN_WARNING "adfs: adfs_fplus_read:"
-                                       " directory header size %X\n"
-                                       " does not match directory size %X\n",
-                                       size, sz);
+               adfs_msg(sb, KERN_WARNING,
+                        "directory header size %X does not match directory size %X",
+                        size, sz);
        }
 
        if (h->bigdirversion[0] != 0 || h->bigdirversion[1] != 0 ||
            h->bigdirversion[2] != 0 || size & 2047 ||
            h->bigdirstartname != cpu_to_le32(BIGDIRSTARTNAME)) {
-               printk(KERN_WARNING "adfs: dir object %X has"
-                                       " malformed dir header\n", id);
+               adfs_error(sb, "dir %06x has malformed header", id);
                goto out;
        }
 
@@ -58,9 +55,10 @@ adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct
                        kcalloc(size, sizeof(struct buffer_head *),
                                GFP_KERNEL);
                if (!bh_fplus) {
+                       adfs_msg(sb, KERN_ERR,
+                                "not enough memory for dir object %X (%d blocks)",
+                                id, size);
                        ret = -ENOMEM;
-                       adfs_error(sb, "not enough memory for"
-                                       " dir object %X (%d blocks)", id, size);
                        goto out;
                }
                dir->bh_fplus = bh_fplus;
@@ -91,8 +89,7 @@ adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct
        if (t->bigdirendname != cpu_to_le32(BIGDIRENDNAME) ||
            t->bigdirendmasseq != h->startmasseq ||
            t->reserved[0] != 0 || t->reserved[1] != 0) {
-               printk(KERN_WARNING "adfs: dir object %X has "
-                                       "malformed dir end\n", id);
+               adfs_error(sb, "dir %06x has malformed tail", id);
                goto out;
        }
 
@@ -180,7 +177,7 @@ adfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj)
        obj->loadaddr = le32_to_cpu(bde.bigdirload);
        obj->execaddr = le32_to_cpu(bde.bigdirexec);
        obj->size     = le32_to_cpu(bde.bigdirlen);
-       obj->file_id  = le32_to_cpu(bde.bigdirindaddr);
+       obj->indaddr  = le32_to_cpu(bde.bigdirindaddr);
        obj->attr     = le32_to_cpu(bde.bigdirattr);
        obj->name_len = le32_to_cpu(bde.bigdirobnamelen);
 
index 904d624..124de75 100644 (file)
@@ -94,7 +94,7 @@ adfs_atts2mode(struct super_block *sb, struct inode *inode)
                return S_IFDIR | S_IXUGO | mode;
        }
 
-       switch (ADFS_I(inode)->filetype) {
+       switch (adfs_filetype(ADFS_I(inode)->loadaddr)) {
        case 0xfc0:     /* LinkFS */
                return S_IFLNK|S_IRWXUGO;
 
@@ -174,7 +174,7 @@ adfs_adfs2unix_time(struct timespec64 *tv, struct inode *inode)
                                                        2208988800000000000LL;
        s64 nsec;
 
-       if (ADFS_I(inode)->stamped == 0)
+       if (!adfs_inode_is_stamped(inode))
                goto cur_time;
 
        high = ADFS_I(inode)->loadaddr & 0xFF; /* top 8 bits of timestamp */
@@ -213,7 +213,7 @@ adfs_unix2adfs_time(struct inode *inode, unsigned int secs)
 {
        unsigned int high, low;
 
-       if (ADFS_I(inode)->stamped) {
+       if (adfs_inode_is_stamped(inode)) {
                /* convert 32-bit seconds to 40-bit centi-seconds */
                low  = (secs & 255) * 100;
                high = (secs / 256) * 100 + (low >> 8) + 0x336e996a;
@@ -247,7 +247,7 @@ adfs_iget(struct super_block *sb, struct object_info *obj)
 
        inode->i_uid     = ADFS_SB(sb)->s_uid;
        inode->i_gid     = ADFS_SB(sb)->s_gid;
-       inode->i_ino     = obj->file_id;
+       inode->i_ino     = obj->indaddr;
        inode->i_size    = obj->size;
        set_nlink(inode, 2);
        inode->i_blocks  = (inode->i_size + sb->s_blocksize - 1) >>
@@ -263,8 +263,6 @@ adfs_iget(struct super_block *sb, struct object_info *obj)
        ADFS_I(inode)->loadaddr  = obj->loadaddr;
        ADFS_I(inode)->execaddr  = obj->execaddr;
        ADFS_I(inode)->attr      = obj->attr;
-       ADFS_I(inode)->filetype  = obj->filetype;
-       ADFS_I(inode)->stamped   = ((obj->loadaddr & 0xfff00000) == 0xfff00000);
 
        inode->i_mode    = adfs_atts2mode(sb, inode);
        adfs_adfs2unix_time(&inode->i_mtime, inode);
@@ -355,7 +353,7 @@ int adfs_write_inode(struct inode *inode, struct writeback_control *wbc)
        struct object_info obj;
        int ret;
 
-       obj.file_id     = inode->i_ino;
+       obj.indaddr     = inode->i_ino;
        obj.name_len    = 0;
        obj.parent_id   = ADFS_I(inode)->parent_id;
        obj.loadaddr    = ADFS_I(inode)->loadaddr;
index 4d34338..f44d12c 100644 (file)
@@ -4,7 +4,6 @@
  *
  *  Copyright (C) 1997-2002 Russell King
  */
-#include <linux/buffer_head.h>
 #include <asm/unaligned.h>
 #include "adfs.h"
 
@@ -64,9 +63,8 @@ static DEFINE_RWLOCK(adfs_map_lock);
  * output of:
  *  gcc -D__KERNEL__ -O2 -I../../include -o - -S map.c
  */
-static int
-lookup_zone(const struct adfs_discmap *dm, const unsigned int idlen,
-           const unsigned int frag_id, unsigned int *offset)
+static int lookup_zone(const struct adfs_discmap *dm, const unsigned int idlen,
+                      const u32 frag_id, unsigned int *offset)
 {
        const unsigned int mapsize = dm->dm_endbit;
        const u32 idmask = (1 << idlen) - 1;
@@ -185,9 +183,8 @@ error:
        return 0;
 }
 
-static int
-scan_map(struct adfs_sb_info *asb, unsigned int zone,
-        const unsigned int frag_id, unsigned int mapoff)
+static int scan_map(struct adfs_sb_info *asb, unsigned int zone,
+                   const u32 frag_id, unsigned int mapoff)
 {
        const unsigned int idlen = asb->s_idlen;
        struct adfs_discmap *dm, *dm_end;
@@ -241,9 +238,7 @@ adfs_map_free(struct super_block *sb)
        return signed_asl(total, asb->s_map2blk);
 }
 
-int
-adfs_map_lookup(struct super_block *sb, unsigned int frag_id,
-               unsigned int offset)
+int adfs_map_lookup(struct super_block *sb, u32 frag_id, unsigned int offset)
 {
        struct adfs_sb_info *asb = ADFS_SB(sb);
        unsigned int zone, mapoff;
index ffb669f..65b04eb 100644 (file)
@@ -6,7 +6,6 @@
  */
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/buffer_head.h>
 #include <linux/parser.h>
 #include <linux/mount.h>
 #include <linux/seq_file.h>
 #include "dir_f.h"
 #include "dir_fplus.h"
 
+#define ADFS_SB_FLAGS SB_NOATIME
+
 #define ADFS_DEFAULT_OWNER_MASK S_IRWXU
 #define ADFS_DEFAULT_OTHER_MASK (S_IRWXG | S_IRWXO)
 
 void __adfs_error(struct super_block *sb, const char *function, const char *fmt, ...)
 {
-       char error_buf[128];
+       struct va_format vaf;
        va_list args;
 
        va_start(args, fmt);
-       vsnprintf(error_buf, sizeof(error_buf), fmt, args);
-       va_end(args);
+       vaf.fmt = fmt;
+       vaf.va = &args;
 
-       printk(KERN_CRIT "ADFS-fs error (device %s)%s%s: %s\n",
+       printk(KERN_CRIT "ADFS-fs error (device %s)%s%s: %pV\n",
                sb->s_id, function ? ": " : "",
-               function ? function : "", error_buf);
+               function ? function : "", &vaf);
+
+       va_end(args);
+}
+
+void adfs_msg(struct super_block *sb, const char *pfx, const char *fmt, ...)
+{
+       struct va_format vaf;
+       va_list args;
+
+       va_start(args, fmt);
+       vaf.fmt = fmt;
+       vaf.va = &args;
+       printk("%sADFS-fs (%s): %pV\n", pfx, sb->s_id, &vaf);
+       va_end(args);
 }
 
 static int adfs_checkdiscrecord(struct adfs_discrecord *dr)
 {
+       unsigned int max_idlen;
        int i;
 
        /* sector size must be 256, 512 or 1024 bytes */
@@ -55,8 +71,13 @@ static int adfs_checkdiscrecord(struct adfs_discrecord *dr)
        if (le32_to_cpu(dr->disc_size_high) >> dr->log2secsize)
                return 1;
 
-       /* idlen must be no greater than 19 v2 [1.0] */
-       if (dr->idlen > 19)
+       /*
+        * Maximum idlen is limited to 16 bits for new directories by
+        * the three-byte storage of an indirect disc address.  For
+        * big directories, idlen must be no greater than 19 v2 [1.0]
+        */
+       max_idlen = dr->format_version ? 19 : 16;
+       if (dr->idlen > max_idlen)
                return 1;
 
        /* reserved bytes should be zero */
@@ -152,10 +173,10 @@ static const match_table_t tokens = {
        {Opt_err, NULL}
 };
 
-static int parse_options(struct super_block *sb, char *options)
+static int parse_options(struct super_block *sb, struct adfs_sb_info *asb,
+                        char *options)
 {
        char *p;
-       struct adfs_sb_info *asb = ADFS_SB(sb);
        int option;
 
        if (!options)
@@ -199,8 +220,9 @@ static int parse_options(struct super_block *sb, char *options)
                        asb->s_ftsuffix = option;
                        break;
                default:
-                       printk("ADFS-fs: unrecognised mount option \"%s\" "
-                                       "or missing value\n", p);
+                       adfs_msg(sb, KERN_ERR,
+                                "unrecognised mount option \"%s\" or missing value",
+                                p);
                        return -EINVAL;
                }
        }
@@ -209,21 +231,31 @@ static int parse_options(struct super_block *sb, char *options)
 
 static int adfs_remount(struct super_block *sb, int *flags, char *data)
 {
+       struct adfs_sb_info temp_asb;
+       int ret;
+
        sync_filesystem(sb);
-       *flags |= SB_NODIRATIME;
-       return parse_options(sb, data);
+       *flags |= ADFS_SB_FLAGS;
+
+       temp_asb = *ADFS_SB(sb);
+       ret = parse_options(sb, &temp_asb, data);
+       if (ret == 0)
+               *ADFS_SB(sb) = temp_asb;
+
+       return ret;
 }
 
 static int adfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
        struct adfs_sb_info *sbi = ADFS_SB(sb);
+       struct adfs_discrecord *dr = adfs_map_discrecord(sbi->s_map);
        u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        buf->f_type    = ADFS_SUPER_MAGIC;
        buf->f_namelen = sbi->s_namelen;
        buf->f_bsize   = sb->s_blocksize;
-       buf->f_blocks  = sbi->s_size;
+       buf->f_blocks  = adfs_disc_size(dr) >> sb->s_blocksize_bits;
        buf->f_files   = sbi->s_ids_per_zone * sbi->s_map_size;
        buf->f_bavail  =
        buf->f_bfree   = adfs_map_free(sb);
@@ -327,8 +359,7 @@ static struct adfs_discmap *adfs_read_map(struct super_block *sb, struct adfs_di
        i = zone - 1;
        dm[0].dm_startblk = 0;
        dm[0].dm_startbit = ADFS_DR_SIZE_BITS;
-       dm[i].dm_endbit   = (le32_to_cpu(dr->disc_size_high) << (32 - dr->log2bpmb)) +
-                           (le32_to_cpu(dr->disc_size) >> dr->log2bpmb) +
+       dm[i].dm_endbit   = (adfs_disc_size(dr) >> dr->log2bpmb) +
                            (ADFS_DR_SIZE_BITS - i * zone_size);
 
        if (adfs_checkmap(sb, dm))
@@ -344,27 +375,18 @@ error_free:
        return ERR_PTR(-EIO);
 }
 
-static inline unsigned long adfs_discsize(struct adfs_discrecord *dr, int block_bits)
-{
-       unsigned long discsize;
-
-       discsize  = le32_to_cpu(dr->disc_size_high) << (32 - block_bits);
-       discsize |= le32_to_cpu(dr->disc_size) >> block_bits;
-
-       return discsize;
-}
-
 static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct adfs_discrecord *dr;
        struct buffer_head *bh;
        struct object_info root_obj;
        unsigned char *b_data;
+       unsigned int blocksize;
        struct adfs_sb_info *asb;
        struct inode *root;
        int ret = -EINVAL;
 
-       sb->s_flags |= SB_NODIRATIME;
+       sb->s_flags |= ADFS_SB_FLAGS;
 
        asb = kzalloc(sizeof(*asb), GFP_KERNEL);
        if (!asb)
@@ -378,12 +400,12 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
        asb->s_other_mask = ADFS_DEFAULT_OTHER_MASK;
        asb->s_ftsuffix = 0;
 
-       if (parse_options(sb, data))
+       if (parse_options(sb, asb, data))
                goto error;
 
        sb_set_blocksize(sb, BLOCK_SIZE);
        if (!(bh = sb_bread(sb, ADFS_DISCRECORD / BLOCK_SIZE))) {
-               adfs_error(sb, "unable to read superblock");
+               adfs_msg(sb, KERN_ERR, "error: unable to read superblock");
                ret = -EIO;
                goto error;
        }
@@ -391,11 +413,8 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
        b_data = bh->b_data + (ADFS_DISCRECORD % BLOCK_SIZE);
 
        if (adfs_checkbblk(b_data)) {
-               if (!silent)
-                       printk("VFS: Can't find an adfs filesystem on dev "
-                               "%s.\n", sb->s_id);
                ret = -EINVAL;
-               goto error_free_bh;
+               goto error_badfs;
        }
 
        dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET);
@@ -404,33 +423,33 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
         * Do some sanity checks on the ADFS disc record
         */
        if (adfs_checkdiscrecord(dr)) {
-               if (!silent)
-                       printk("VPS: Can't find an adfs filesystem on dev "
-                               "%s.\n", sb->s_id);
                ret = -EINVAL;
-               goto error_free_bh;
+               goto error_badfs;
        }
 
+       blocksize = 1 << dr->log2secsize;
        brelse(bh);
-       if (sb_set_blocksize(sb, 1 << dr->log2secsize)) {
+
+       if (sb_set_blocksize(sb, blocksize)) {
                bh = sb_bread(sb, ADFS_DISCRECORD / sb->s_blocksize);
                if (!bh) {
-                       adfs_error(sb, "couldn't read superblock on "
-                               "2nd try.");
+                       adfs_msg(sb, KERN_ERR,
+                                "error: couldn't read superblock on 2nd try.");
                        ret = -EIO;
                        goto error;
                }
                b_data = bh->b_data + (ADFS_DISCRECORD % sb->s_blocksize);
                if (adfs_checkbblk(b_data)) {
-                       adfs_error(sb, "disc record mismatch, very weird!");
+                       adfs_msg(sb, KERN_ERR,
+                                "error: disc record mismatch, very weird!");
                        ret = -EINVAL;
                        goto error_free_bh;
                }
                dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET);
        } else {
                if (!silent)
-                       printk(KERN_ERR "VFS: Unsupported blocksize on dev "
-                               "%s.\n", sb->s_id);
+                       adfs_msg(sb, KERN_ERR,
+                                "error: unsupported blocksize");
                ret = -EINVAL;
                goto error;
        }
@@ -443,8 +462,6 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
        asb->s_idlen            = dr->idlen;
        asb->s_map_size         = dr->nzones | (dr->nzones_high << 8);
        asb->s_map2blk          = dr->log2bpmb - dr->log2secsize;
-       asb->s_size             = adfs_discsize(dr, sb->s_blocksize_bits);
-       asb->s_version          = dr->format_version;
        asb->s_log2sharesize    = dr->log2sharesize;
 
        asb->s_map = adfs_read_map(sb, dr);
@@ -460,9 +477,9 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
         */
        sb->s_op = &adfs_sops;
 
-       dr = (struct adfs_discrecord *)(asb->s_map[0].dm_bh->b_data + 4);
+       dr = adfs_map_discrecord(asb->s_map);
 
-       root_obj.parent_id = root_obj.file_id = le32_to_cpu(dr->root);
+       root_obj.parent_id = root_obj.indaddr = le32_to_cpu(dr->root);
        root_obj.name_len  = 0;
        /* Set root object date as 01 Jan 1987 00:00:00 */
        root_obj.loadaddr  = 0xfff0003f;
@@ -470,13 +487,12 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
        root_obj.size      = ADFS_NEWDIR_SIZE;
        root_obj.attr      = ADFS_NDA_DIRECTORY   | ADFS_NDA_OWNER_READ |
                             ADFS_NDA_OWNER_WRITE | ADFS_NDA_PUBLIC_READ;
-       root_obj.filetype  = -1;
 
        /*
         * If this is a F+ disk with variable length directories,
         * get the root_size from the disc record.
         */
-       if (asb->s_version) {
+       if (dr->format_version) {
                root_obj.size = le32_to_cpu(dr->root_size);
                asb->s_dir     = &adfs_fplus_dir_ops;
                asb->s_namelen = ADFS_FPLUS_NAME_LEN;
@@ -505,6 +521,11 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
        }
        return 0;
 
+error_badfs:
+       if (!silent)
+               adfs_msg(sb, KERN_ERR,
+                        "error: can't find an ADFS filesystem on dev %s.",
+                        sb->s_id);
 error_free_bh:
        brelse(bh);
 error:
index 2d40573..01e0fb9 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -42,6 +42,7 @@
 #include <linux/ramfs.h>
 #include <linux/percpu-refcount.h>
 #include <linux/mount.h>
+#include <linux/pseudo_fs.h>
 
 #include <asm/kmap_types.h>
 #include <linux/uaccess.h>
@@ -249,15 +250,12 @@ static struct file *aio_private_file(struct kioctx *ctx, loff_t nr_pages)
        return file;
 }
 
-static struct dentry *aio_mount(struct file_system_type *fs_type,
-                               int flags, const char *dev_name, void *data)
+static int aio_init_fs_context(struct fs_context *fc)
 {
-       struct dentry *root = mount_pseudo(fs_type, "aio:", NULL, NULL,
-                                          AIO_RING_MAGIC);
-
-       if (!IS_ERR(root))
-               root->d_sb->s_iflags |= SB_I_NOEXEC;
-       return root;
+       if (!init_pseudo(fc, AIO_RING_MAGIC))
+               return -ENOMEM;
+       fc->s_iflags |= SB_I_NOEXEC;
+       return 0;
 }
 
 /* aio_setup
@@ -268,7 +266,7 @@ static int __init aio_setup(void)
 {
        static struct file_system_type aio_fs = {
                .name           = "aio",
-               .mount          = aio_mount,
+               .init_fs_context = aio_init_fs_context,
                .kill_sb        = kill_anon_super,
        };
        aio_mnt = kern_mount(&aio_fs);
@@ -425,7 +423,7 @@ static int aio_migratepage(struct address_space *mapping, struct page *new,
        BUG_ON(PageWriteback(old));
        get_page(new);
 
-       rc = migrate_page_move_mapping(mapping, new, old, mode, 1);
+       rc = migrate_page_move_mapping(mapping, new, old, 1);
        if (rc != MIGRATEPAGE_SUCCESS) {
                put_page(new);
                goto out_unlock;
@@ -2094,7 +2092,6 @@ SYSCALL_DEFINE6(io_pgetevents,
                const struct __aio_sigset __user *, usig)
 {
        struct __aio_sigset     ksig = { NULL, };
-       sigset_t                ksigmask, sigsaved;
        struct timespec64       ts;
        bool interrupted;
        int ret;
@@ -2105,14 +2102,14 @@ SYSCALL_DEFINE6(io_pgetevents,
        if (usig && copy_from_user(&ksig, usig, sizeof(ksig)))
                return -EFAULT;
 
-       ret = set_user_sigmask(ksig.sigmask, &ksigmask, &sigsaved, ksig.sigsetsize);
+       ret = set_user_sigmask(ksig.sigmask, ksig.sigsetsize);
        if (ret)
                return ret;
 
        ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &ts : NULL);
 
        interrupted = signal_pending(current);
-       restore_user_sigmask(ksig.sigmask, &sigsaved, interrupted);
+       restore_saved_sigmask_unless(interrupted);
        if (interrupted && !ret)
                ret = -ERESTARTNOHAND;
 
@@ -2130,7 +2127,6 @@ SYSCALL_DEFINE6(io_pgetevents_time32,
                const struct __aio_sigset __user *, usig)
 {
        struct __aio_sigset     ksig = { NULL, };
-       sigset_t                ksigmask, sigsaved;
        struct timespec64       ts;
        bool interrupted;
        int ret;
@@ -2142,14 +2138,14 @@ SYSCALL_DEFINE6(io_pgetevents_time32,
                return -EFAULT;
 
 
-       ret = set_user_sigmask(ksig.sigmask, &ksigmask, &sigsaved, ksig.sigsetsize);
+       ret = set_user_sigmask(ksig.sigmask, ksig.sigsetsize);
        if (ret)
                return ret;
 
        ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &ts : NULL);
 
        interrupted = signal_pending(current);
-       restore_user_sigmask(ksig.sigmask, &sigsaved, interrupted);
+       restore_saved_sigmask_unless(interrupted);
        if (interrupted && !ret)
                ret = -ERESTARTNOHAND;
 
@@ -2198,7 +2194,6 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents,
                const struct __compat_aio_sigset __user *, usig)
 {
        struct __compat_aio_sigset ksig = { NULL, };
-       sigset_t ksigmask, sigsaved;
        struct timespec64 t;
        bool interrupted;
        int ret;
@@ -2209,14 +2204,14 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents,
        if (usig && copy_from_user(&ksig, usig, sizeof(ksig)))
                return -EFAULT;
 
-       ret = set_compat_user_sigmask(ksig.sigmask, &ksigmask, &sigsaved, ksig.sigsetsize);
+       ret = set_compat_user_sigmask(ksig.sigmask, ksig.sigsetsize);
        if (ret)
                return ret;
 
        ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &t : NULL);
 
        interrupted = signal_pending(current);
-       restore_user_sigmask(ksig.sigmask, &sigsaved, interrupted);
+       restore_saved_sigmask_unless(interrupted);
        if (interrupted && !ret)
                ret = -ERESTARTNOHAND;
 
@@ -2234,7 +2229,6 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents_time64,
                const struct __compat_aio_sigset __user *, usig)
 {
        struct __compat_aio_sigset ksig = { NULL, };
-       sigset_t ksigmask, sigsaved;
        struct timespec64 t;
        bool interrupted;
        int ret;
@@ -2245,14 +2239,14 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents_time64,
        if (usig && copy_from_user(&ksig, usig, sizeof(ksig)))
                return -EFAULT;
 
-       ret = set_compat_user_sigmask(ksig.sigmask, &ksigmask, &sigsaved, ksig.sigsetsize);
+       ret = set_compat_user_sigmask(ksig.sigmask, ksig.sigsetsize);
        if (ret)
                return ret;
 
        ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &t : NULL);
 
        interrupted = signal_pending(current);
-       restore_user_sigmask(ksig.sigmask, &sigsaved, interrupted);
+       restore_saved_sigmask_unless(interrupted);
        if (interrupted && !ret)
                ret = -ERESTARTNOHAND;
 
index c2b8663..8971430 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/kernel.h>
 #include <linux/magic.h>
 #include <linux/anon_inodes.h>
+#include <linux/pseudo_fs.h>
 
 #include <linux/uaccess.h>
 
@@ -39,16 +40,18 @@ static const struct dentry_operations anon_inodefs_dentry_operations = {
        .d_dname        = anon_inodefs_dname,
 };
 
-static struct dentry *anon_inodefs_mount(struct file_system_type *fs_type,
-                               int flags, const char *dev_name, void *data)
+static int anon_inodefs_init_fs_context(struct fs_context *fc)
 {
-       return mount_pseudo(fs_type, "anon_inode:", NULL,
-                       &anon_inodefs_dentry_operations, ANON_INODE_FS_MAGIC);
+       struct pseudo_fs_context *ctx = init_pseudo(fc, ANON_INODE_FS_MAGIC);
+       if (!ctx)
+               return -ENOMEM;
+       ctx->dops = &anon_inodefs_dentry_operations;
+       return 0;
 }
 
 static struct file_system_type anon_inode_fs_type = {
        .name           = "anon_inodefs",
-       .mount          = anon_inodefs_mount,
+       .init_fs_context = anon_inodefs_init_fs_context,
        .kill_sb        = kill_anon_super,
 };
 
index 8264b46..d4e11b2 100644 (file)
@@ -1127,7 +1127,6 @@ out_free_interp:
                          load_addr, interp_load_addr);
        if (retval < 0)
                goto out;
-       /* N.B. passed_fileno might not be initialized? */
        current->mm->end_code = end_code;
        current->mm->start_code = start_code;
        current->mm->start_data = start_data;
index 8c6b50f..831a2b2 100644 (file)
@@ -431,7 +431,6 @@ static int load_flat_file(struct linux_binprm *bprm,
        unsigned long len, memp, memp_size, extra, rlim;
        __be32 __user *reloc;
        u32 __user *rp;
-       struct inode *inode;
        int i, rev, relocs;
        loff_t fpos;
        unsigned long start_code, end_code;
@@ -439,7 +438,6 @@ static int load_flat_file(struct linux_binprm *bprm,
        int ret;
 
        hdr = ((struct flat_hdr *) bprm->buf);          /* exec-header */
-       inode = file_inode(bprm->file);
 
        text_len  = ntohl(hdr->data_start);
        data_len  = ntohl(hdr->data_end) - ntohl(hdr->data_start);
index b8e1455..cdb4582 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/pagemap.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
+#include <linux/fs_context.h>
 #include <linux/syscalls.h>
 #include <linux/fs.h>
 #include <linux/uaccess.h>
@@ -821,7 +822,7 @@ static const struct super_operations s_ops = {
        .evict_inode    = bm_evict_inode,
 };
 
-static int bm_fill_super(struct super_block *sb, void *data, int silent)
+static int bm_fill_super(struct super_block *sb, struct fs_context *fc)
 {
        int err;
        static const struct tree_descr bm_files[] = {
@@ -836,10 +837,19 @@ static int bm_fill_super(struct super_block *sb, void *data, int silent)
        return err;
 }
 
-static struct dentry *bm_mount(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *data)
+static int bm_get_tree(struct fs_context *fc)
 {
-       return mount_single(fs_type, flags, data, bm_fill_super);
+       return get_tree_single(fc, bm_fill_super);
+}
+
+static const struct fs_context_operations bm_context_ops = {
+       .get_tree       = bm_get_tree,
+};
+
+static int bm_init_fs_context(struct fs_context *fc)
+{
+       fc->ops = &bm_context_ops;
+       return 0;
 }
 
 static struct linux_binfmt misc_format = {
@@ -850,7 +860,7 @@ static struct linux_binfmt misc_format = {
 static struct file_system_type bm_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "binfmt_misc",
-       .mount          = bm_mount,
+       .init_fs_context = bm_init_fs_context,
        .kill_sb        = kill_litter_super,
 };
 MODULE_ALIAS_FS("binfmt_misc");
index 5dc613e..c2a85b5 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/writeback.h>
 #include <linux/mpage.h>
 #include <linux/mount.h>
+#include <linux/pseudo_fs.h>
 #include <linux/uio.h>
 #include <linux/namei.h>
 #include <linux/log2.h>
@@ -863,19 +864,19 @@ static const struct super_operations bdev_sops = {
        .evict_inode = bdev_evict_inode,
 };
 
-static struct dentry *bd_mount(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *data)
+static int bd_init_fs_context(struct fs_context *fc)
 {
-       struct dentry *dent;
-       dent = mount_pseudo(fs_type, "bdev:", &bdev_sops, NULL, BDEVFS_MAGIC);
-       if (!IS_ERR(dent))
-               dent->d_sb->s_iflags |= SB_I_CGROUPWB;
-       return dent;
+       struct pseudo_fs_context *ctx = init_pseudo(fc, BDEVFS_MAGIC);
+       if (!ctx)
+               return -ENOMEM;
+       fc->s_iflags |= SB_I_CGROUPWB;
+       ctx->ops = &bdev_sops;
+       return 0;
 }
 
 static struct file_system_type bd_type = {
        .name           = "bdev",
-       .mount          = bd_mount,
+       .init_fs_context = bd_init_fs_context,
        .kill_sb        = kill_anon_super,
 };
 
index 23537bc..38651fa 100644 (file)
@@ -2,6 +2,8 @@
 
 config BTRFS_FS
        tristate "Btrfs filesystem support"
+       select CRYPTO
+       select CRYPTO_CRC32C
        select LIBCRC32C
        select ZLIB_INFLATE
        select ZLIB_DEFLATE
index ca693dd..76a8431 100644 (file)
@@ -10,7 +10,8 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
           export.o tree-log.o free-space-cache.o zlib.o lzo.o zstd.o \
           compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
           reada.o backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o \
-          uuid-tree.o props.o free-space-tree.o tree-checker.o
+          uuid-tree.o props.o free-space-tree.o tree-checker.o space-info.o \
+          block-rsv.o delalloc-space.o
 
 btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
 btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
index 982152d..89116af 100644 (file)
@@ -1465,12 +1465,11 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
  *
  * Return: 0 if extent is not shared, 1 if it is shared, < 0 on error.
  */
-int btrfs_check_shared(struct btrfs_root *root, u64 inum, u64 bytenr)
+int btrfs_check_shared(struct btrfs_root *root, u64 inum, u64 bytenr,
+               struct ulist *roots, struct ulist *tmp)
 {
        struct btrfs_fs_info *fs_info = root->fs_info;
        struct btrfs_trans_handle *trans;
-       struct ulist *tmp = NULL;
-       struct ulist *roots = NULL;
        struct ulist_iterator uiter;
        struct ulist_node *node;
        struct seq_list elem = SEQ_LIST_INIT(elem);
@@ -1481,12 +1480,8 @@ int btrfs_check_shared(struct btrfs_root *root, u64 inum, u64 bytenr)
                .share_count = 0,
        };
 
-       tmp = ulist_alloc(GFP_NOFS);
-       roots = ulist_alloc(GFP_NOFS);
-       if (!tmp || !roots) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       ulist_init(roots);
+       ulist_init(tmp);
 
        trans = btrfs_attach_transaction(root);
        if (IS_ERR(trans)) {
@@ -1527,8 +1522,8 @@ int btrfs_check_shared(struct btrfs_root *root, u64 inum, u64 bytenr)
                up_read(&fs_info->commit_root_sem);
        }
 out:
-       ulist_free(tmp);
-       ulist_free(roots);
+       ulist_release(roots);
+       ulist_release(tmp);
        return ret;
 }
 
index 54d5898..777f61d 100644 (file)
@@ -57,7 +57,8 @@ int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid,
                          u64 start_off, struct btrfs_path *path,
                          struct btrfs_inode_extref **ret_extref,
                          u64 *found_off);
-int btrfs_check_shared(struct btrfs_root *root, u64 inum, u64 bytenr);
+int btrfs_check_shared(struct btrfs_root *root, u64 inum, u64 bytenr,
+               struct ulist *roots, struct ulist *tmp_ulist);
 
 int __init btrfs_prelim_ref_init(void);
 void __cold btrfs_prelim_ref_exit(void);
diff --git a/fs/btrfs/block-rsv.c b/fs/btrfs/block-rsv.c
new file mode 100644 (file)
index 0000000..698470b
--- /dev/null
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "ctree.h"
+#include "block-rsv.h"
+#include "space-info.h"
+#include "math.h"
+#include "transaction.h"
+
+static u64 block_rsv_release_bytes(struct btrfs_fs_info *fs_info,
+                                   struct btrfs_block_rsv *block_rsv,
+                                   struct btrfs_block_rsv *dest, u64 num_bytes,
+                                   u64 *qgroup_to_release_ret)
+{
+       struct btrfs_space_info *space_info = block_rsv->space_info;
+       u64 qgroup_to_release = 0;
+       u64 ret;
+
+       spin_lock(&block_rsv->lock);
+       if (num_bytes == (u64)-1) {
+               num_bytes = block_rsv->size;
+               qgroup_to_release = block_rsv->qgroup_rsv_size;
+       }
+       block_rsv->size -= num_bytes;
+       if (block_rsv->reserved >= block_rsv->size) {
+               num_bytes = block_rsv->reserved - block_rsv->size;
+               block_rsv->reserved = block_rsv->size;
+               block_rsv->full = 1;
+       } else {
+               num_bytes = 0;
+       }
+       if (block_rsv->qgroup_rsv_reserved >= block_rsv->qgroup_rsv_size) {
+               qgroup_to_release = block_rsv->qgroup_rsv_reserved -
+                                   block_rsv->qgroup_rsv_size;
+               block_rsv->qgroup_rsv_reserved = block_rsv->qgroup_rsv_size;
+       } else {
+               qgroup_to_release = 0;
+       }
+       spin_unlock(&block_rsv->lock);
+
+       ret = num_bytes;
+       if (num_bytes > 0) {
+               if (dest) {
+                       spin_lock(&dest->lock);
+                       if (!dest->full) {
+                               u64 bytes_to_add;
+
+                               bytes_to_add = dest->size - dest->reserved;
+                               bytes_to_add = min(num_bytes, bytes_to_add);
+                               dest->reserved += bytes_to_add;
+                               if (dest->reserved >= dest->size)
+                                       dest->full = 1;
+                               num_bytes -= bytes_to_add;
+                       }
+                       spin_unlock(&dest->lock);
+               }
+               if (num_bytes)
+                       btrfs_space_info_add_old_bytes(fs_info, space_info,
+                                                      num_bytes);
+       }
+       if (qgroup_to_release_ret)
+               *qgroup_to_release_ret = qgroup_to_release;
+       return ret;
+}
+
+int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src,
+                           struct btrfs_block_rsv *dst, u64 num_bytes,
+                           bool update_size)
+{
+       int ret;
+
+       ret = btrfs_block_rsv_use_bytes(src, num_bytes);
+       if (ret)
+               return ret;
+
+       btrfs_block_rsv_add_bytes(dst, num_bytes, update_size);
+       return 0;
+}
+
+void btrfs_init_block_rsv(struct btrfs_block_rsv *rsv, unsigned short type)
+{
+       memset(rsv, 0, sizeof(*rsv));
+       spin_lock_init(&rsv->lock);
+       rsv->type = type;
+}
+
+void btrfs_init_metadata_block_rsv(struct btrfs_fs_info *fs_info,
+                                  struct btrfs_block_rsv *rsv,
+                                  unsigned short type)
+{
+       btrfs_init_block_rsv(rsv, type);
+       rsv->space_info = btrfs_find_space_info(fs_info,
+                                           BTRFS_BLOCK_GROUP_METADATA);
+}
+
+struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_fs_info *fs_info,
+                                             unsigned short type)
+{
+       struct btrfs_block_rsv *block_rsv;
+
+       block_rsv = kmalloc(sizeof(*block_rsv), GFP_NOFS);
+       if (!block_rsv)
+               return NULL;
+
+       btrfs_init_metadata_block_rsv(fs_info, block_rsv, type);
+       return block_rsv;
+}
+
+void btrfs_free_block_rsv(struct btrfs_fs_info *fs_info,
+                         struct btrfs_block_rsv *rsv)
+{
+       if (!rsv)
+               return;
+       btrfs_block_rsv_release(fs_info, rsv, (u64)-1);
+       kfree(rsv);
+}
+
+int btrfs_block_rsv_add(struct btrfs_root *root,
+                       struct btrfs_block_rsv *block_rsv, u64 num_bytes,
+                       enum btrfs_reserve_flush_enum flush)
+{
+       int ret;
+
+       if (num_bytes == 0)
+               return 0;
+
+       ret = btrfs_reserve_metadata_bytes(root, block_rsv, num_bytes, flush);
+       if (!ret)
+               btrfs_block_rsv_add_bytes(block_rsv, num_bytes, true);
+
+       return ret;
+}
+
+int btrfs_block_rsv_check(struct btrfs_block_rsv *block_rsv, int min_factor)
+{
+       u64 num_bytes = 0;
+       int ret = -ENOSPC;
+
+       if (!block_rsv)
+               return 0;
+
+       spin_lock(&block_rsv->lock);
+       num_bytes = div_factor(block_rsv->size, min_factor);
+       if (block_rsv->reserved >= num_bytes)
+               ret = 0;
+       spin_unlock(&block_rsv->lock);
+
+       return ret;
+}
+
+int btrfs_block_rsv_refill(struct btrfs_root *root,
+                          struct btrfs_block_rsv *block_rsv, u64 min_reserved,
+                          enum btrfs_reserve_flush_enum flush)
+{
+       u64 num_bytes = 0;
+       int ret = -ENOSPC;
+
+       if (!block_rsv)
+               return 0;
+
+       spin_lock(&block_rsv->lock);
+       num_bytes = min_reserved;
+       if (block_rsv->reserved >= num_bytes)
+               ret = 0;
+       else
+               num_bytes -= block_rsv->reserved;
+       spin_unlock(&block_rsv->lock);
+
+       if (!ret)
+               return 0;
+
+       ret = btrfs_reserve_metadata_bytes(root, block_rsv, num_bytes, flush);
+       if (!ret) {
+               btrfs_block_rsv_add_bytes(block_rsv, num_bytes, false);
+               return 0;
+       }
+
+       return ret;
+}
+
+u64 __btrfs_block_rsv_release(struct btrfs_fs_info *fs_info,
+                             struct btrfs_block_rsv *block_rsv,
+                             u64 num_bytes, u64 *qgroup_to_release)
+{
+       struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
+       struct btrfs_block_rsv *delayed_rsv = &fs_info->delayed_refs_rsv;
+       struct btrfs_block_rsv *target = NULL;
+
+       /*
+        * If we are the delayed_rsv then push to the global rsv, otherwise dump
+        * into the delayed rsv if it is not full.
+        */
+       if (block_rsv == delayed_rsv)
+               target = global_rsv;
+       else if (block_rsv != global_rsv && !delayed_rsv->full)
+               target = delayed_rsv;
+
+       if (target && block_rsv->space_info != target->space_info)
+               target = NULL;
+
+       return block_rsv_release_bytes(fs_info, block_rsv, target, num_bytes,
+                                      qgroup_to_release);
+}
+
+int btrfs_block_rsv_use_bytes(struct btrfs_block_rsv *block_rsv, u64 num_bytes)
+{
+       int ret = -ENOSPC;
+
+       spin_lock(&block_rsv->lock);
+       if (block_rsv->reserved >= num_bytes) {
+               block_rsv->reserved -= num_bytes;
+               if (block_rsv->reserved < block_rsv->size)
+                       block_rsv->full = 0;
+               ret = 0;
+       }
+       spin_unlock(&block_rsv->lock);
+       return ret;
+}
+
+void btrfs_block_rsv_add_bytes(struct btrfs_block_rsv *block_rsv,
+                              u64 num_bytes, bool update_size)
+{
+       spin_lock(&block_rsv->lock);
+       block_rsv->reserved += num_bytes;
+       if (update_size)
+               block_rsv->size += num_bytes;
+       else if (block_rsv->reserved >= block_rsv->size)
+               block_rsv->full = 1;
+       spin_unlock(&block_rsv->lock);
+}
+
+int btrfs_cond_migrate_bytes(struct btrfs_fs_info *fs_info,
+                            struct btrfs_block_rsv *dest, u64 num_bytes,
+                            int min_factor)
+{
+       struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
+       u64 min_bytes;
+
+       if (global_rsv->space_info != dest->space_info)
+               return -ENOSPC;
+
+       spin_lock(&global_rsv->lock);
+       min_bytes = div_factor(global_rsv->size, min_factor);
+       if (global_rsv->reserved < min_bytes + num_bytes) {
+               spin_unlock(&global_rsv->lock);
+               return -ENOSPC;
+       }
+       global_rsv->reserved -= num_bytes;
+       if (global_rsv->reserved < global_rsv->size)
+               global_rsv->full = 0;
+       spin_unlock(&global_rsv->lock);
+
+       btrfs_block_rsv_add_bytes(dest, num_bytes, true);
+       return 0;
+}
+
+void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info)
+{
+       struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
+       struct btrfs_space_info *sinfo = block_rsv->space_info;
+       u64 num_bytes;
+
+       /*
+        * The global block rsv is based on the size of the extent tree, the
+        * checksum tree and the root tree.  If the fs is empty we want to set
+        * it to a minimal amount for safety.
+        */
+       num_bytes = btrfs_root_used(&fs_info->extent_root->root_item) +
+               btrfs_root_used(&fs_info->csum_root->root_item) +
+               btrfs_root_used(&fs_info->tree_root->root_item);
+       num_bytes = max_t(u64, num_bytes, SZ_16M);
+
+       spin_lock(&sinfo->lock);
+       spin_lock(&block_rsv->lock);
+
+       block_rsv->size = min_t(u64, num_bytes, SZ_512M);
+
+       if (block_rsv->reserved < block_rsv->size) {
+               num_bytes = btrfs_space_info_used(sinfo, true);
+               if (sinfo->total_bytes > num_bytes) {
+                       num_bytes = sinfo->total_bytes - num_bytes;
+                       num_bytes = min(num_bytes,
+                                       block_rsv->size - block_rsv->reserved);
+                       block_rsv->reserved += num_bytes;
+                       btrfs_space_info_update_bytes_may_use(fs_info, sinfo,
+                                                             num_bytes);
+                       trace_btrfs_space_reservation(fs_info, "space_info",
+                                                     sinfo->flags, num_bytes,
+                                                     1);
+               }
+       } else if (block_rsv->reserved > block_rsv->size) {
+               num_bytes = block_rsv->reserved - block_rsv->size;
+               btrfs_space_info_update_bytes_may_use(fs_info, sinfo,
+                                                     -num_bytes);
+               trace_btrfs_space_reservation(fs_info, "space_info",
+                                     sinfo->flags, num_bytes, 0);
+               block_rsv->reserved = block_rsv->size;
+       }
+
+       if (block_rsv->reserved == block_rsv->size)
+               block_rsv->full = 1;
+       else
+               block_rsv->full = 0;
+
+       spin_unlock(&block_rsv->lock);
+       spin_unlock(&sinfo->lock);
+}
+
+void btrfs_init_global_block_rsv(struct btrfs_fs_info *fs_info)
+{
+       struct btrfs_space_info *space_info;
+
+       space_info = btrfs_find_space_info(fs_info, BTRFS_BLOCK_GROUP_SYSTEM);
+       fs_info->chunk_block_rsv.space_info = space_info;
+
+       space_info = btrfs_find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA);
+       fs_info->global_block_rsv.space_info = space_info;
+       fs_info->trans_block_rsv.space_info = space_info;
+       fs_info->empty_block_rsv.space_info = space_info;
+       fs_info->delayed_block_rsv.space_info = space_info;
+       fs_info->delayed_refs_rsv.space_info = space_info;
+
+       fs_info->extent_root->block_rsv = &fs_info->delayed_refs_rsv;
+       fs_info->csum_root->block_rsv = &fs_info->delayed_refs_rsv;
+       fs_info->dev_root->block_rsv = &fs_info->global_block_rsv;
+       fs_info->tree_root->block_rsv = &fs_info->global_block_rsv;
+       if (fs_info->quota_root)
+               fs_info->quota_root->block_rsv = &fs_info->global_block_rsv;
+       fs_info->chunk_root->block_rsv = &fs_info->chunk_block_rsv;
+
+       btrfs_update_global_block_rsv(fs_info);
+}
+
+void btrfs_release_global_block_rsv(struct btrfs_fs_info *fs_info)
+{
+       btrfs_block_rsv_release(fs_info, &fs_info->global_block_rsv, (u64)-1);
+       WARN_ON(fs_info->trans_block_rsv.size > 0);
+       WARN_ON(fs_info->trans_block_rsv.reserved > 0);
+       WARN_ON(fs_info->chunk_block_rsv.size > 0);
+       WARN_ON(fs_info->chunk_block_rsv.reserved > 0);
+       WARN_ON(fs_info->delayed_block_rsv.size > 0);
+       WARN_ON(fs_info->delayed_block_rsv.reserved > 0);
+       WARN_ON(fs_info->delayed_refs_rsv.reserved > 0);
+       WARN_ON(fs_info->delayed_refs_rsv.size > 0);
+}
+
+static struct btrfs_block_rsv *get_block_rsv(
+                                       const struct btrfs_trans_handle *trans,
+                                       const struct btrfs_root *root)
+{
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       struct btrfs_block_rsv *block_rsv = NULL;
+
+       if (test_bit(BTRFS_ROOT_REF_COWS, &root->state) ||
+           (root == fs_info->csum_root && trans->adding_csums) ||
+           (root == fs_info->uuid_root))
+               block_rsv = trans->block_rsv;
+
+       if (!block_rsv)
+               block_rsv = root->block_rsv;
+
+       if (!block_rsv)
+               block_rsv = &fs_info->empty_block_rsv;
+
+       return block_rsv;
+}
+
+struct btrfs_block_rsv *btrfs_use_block_rsv(struct btrfs_trans_handle *trans,
+                                           struct btrfs_root *root,
+                                           u32 blocksize)
+{
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       struct btrfs_block_rsv *block_rsv;
+       struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
+       int ret;
+       bool global_updated = false;
+
+       block_rsv = get_block_rsv(trans, root);
+
+       if (unlikely(block_rsv->size == 0))
+               goto try_reserve;
+again:
+       ret = btrfs_block_rsv_use_bytes(block_rsv, blocksize);
+       if (!ret)
+               return block_rsv;
+
+       if (block_rsv->failfast)
+               return ERR_PTR(ret);
+
+       if (block_rsv->type == BTRFS_BLOCK_RSV_GLOBAL && !global_updated) {
+               global_updated = true;
+               btrfs_update_global_block_rsv(fs_info);
+               goto again;
+       }
+
+       /*
+        * The global reserve still exists to save us from ourselves, so don't
+        * warn_on if we are short on our delayed refs reserve.
+        */
+       if (block_rsv->type != BTRFS_BLOCK_RSV_DELREFS &&
+           btrfs_test_opt(fs_info, ENOSPC_DEBUG)) {
+               static DEFINE_RATELIMIT_STATE(_rs,
+                               DEFAULT_RATELIMIT_INTERVAL * 10,
+                               /*DEFAULT_RATELIMIT_BURST*/ 1);
+               if (__ratelimit(&_rs))
+                       WARN(1, KERN_DEBUG
+                               "BTRFS: block rsv returned %d\n", ret);
+       }
+try_reserve:
+       ret = btrfs_reserve_metadata_bytes(root, block_rsv, blocksize,
+                                          BTRFS_RESERVE_NO_FLUSH);
+       if (!ret)
+               return block_rsv;
+       /*
+        * If we couldn't reserve metadata bytes try and use some from
+        * the global reserve if its space type is the same as the global
+        * reservation.
+        */
+       if (block_rsv->type != BTRFS_BLOCK_RSV_GLOBAL &&
+           block_rsv->space_info == global_rsv->space_info) {
+               ret = btrfs_block_rsv_use_bytes(global_rsv, blocksize);
+               if (!ret)
+                       return global_rsv;
+       }
+       return ERR_PTR(ret);
+}
diff --git a/fs/btrfs/block-rsv.h b/fs/btrfs/block-rsv.h
new file mode 100644 (file)
index 0000000..d1428bb
--- /dev/null
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BTRFS_BLOCK_RSV_H
+#define BTRFS_BLOCK_RSV_H
+
+struct btrfs_trans_handle;
+enum btrfs_reserve_flush_enum;
+
+/*
+ * Types of block reserves
+ */
+enum {
+       BTRFS_BLOCK_RSV_GLOBAL,
+       BTRFS_BLOCK_RSV_DELALLOC,
+       BTRFS_BLOCK_RSV_TRANS,
+       BTRFS_BLOCK_RSV_CHUNK,
+       BTRFS_BLOCK_RSV_DELOPS,
+       BTRFS_BLOCK_RSV_DELREFS,
+       BTRFS_BLOCK_RSV_EMPTY,
+       BTRFS_BLOCK_RSV_TEMP,
+};
+
+struct btrfs_block_rsv {
+       u64 size;
+       u64 reserved;
+       struct btrfs_space_info *space_info;
+       spinlock_t lock;
+       unsigned short full;
+       unsigned short type;
+       unsigned short failfast;
+
+       /*
+        * Qgroup equivalent for @size @reserved
+        *
+        * Unlike normal @size/@reserved for inode rsv, qgroup doesn't care
+        * about things like csum size nor how many tree blocks it will need to
+        * reserve.
+        *
+        * Qgroup cares more about net change of the extent usage.
+        *
+        * So for one newly inserted file extent, in worst case it will cause
+        * leaf split and level increase, nodesize for each file extent is
+        * already too much.
+        *
+        * In short, qgroup_size/reserved is the upper limit of possible needed
+        * qgroup metadata reservation.
+        */
+       u64 qgroup_rsv_size;
+       u64 qgroup_rsv_reserved;
+};
+
+void btrfs_init_block_rsv(struct btrfs_block_rsv *rsv, unsigned short type);
+struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_fs_info *fs_info,
+                                             unsigned short type);
+void btrfs_init_metadata_block_rsv(struct btrfs_fs_info *fs_info,
+                                  struct btrfs_block_rsv *rsv,
+                                  unsigned short type);
+void btrfs_free_block_rsv(struct btrfs_fs_info *fs_info,
+                         struct btrfs_block_rsv *rsv);
+int btrfs_block_rsv_add(struct btrfs_root *root,
+                       struct btrfs_block_rsv *block_rsv, u64 num_bytes,
+                       enum btrfs_reserve_flush_enum flush);
+int btrfs_block_rsv_check(struct btrfs_block_rsv *block_rsv, int min_factor);
+int btrfs_block_rsv_refill(struct btrfs_root *root,
+                          struct btrfs_block_rsv *block_rsv, u64 min_reserved,
+                          enum btrfs_reserve_flush_enum flush);
+int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv,
+                           struct btrfs_block_rsv *dst_rsv, u64 num_bytes,
+                           bool update_size);
+int btrfs_block_rsv_use_bytes(struct btrfs_block_rsv *block_rsv, u64 num_bytes);
+int btrfs_cond_migrate_bytes(struct btrfs_fs_info *fs_info,
+                            struct btrfs_block_rsv *dest, u64 num_bytes,
+                            int min_factor);
+void btrfs_block_rsv_add_bytes(struct btrfs_block_rsv *block_rsv,
+                              u64 num_bytes, bool update_size);
+u64 __btrfs_block_rsv_release(struct btrfs_fs_info *fs_info,
+                             struct btrfs_block_rsv *block_rsv,
+                             u64 num_bytes, u64 *qgroup_to_release);
+void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info);
+void btrfs_init_global_block_rsv(struct btrfs_fs_info *fs_info);
+void btrfs_release_global_block_rsv(struct btrfs_fs_info *fs_info);
+struct btrfs_block_rsv *btrfs_use_block_rsv(struct btrfs_trans_handle *trans,
+                                           struct btrfs_root *root,
+                                           u32 blocksize);
+
+static inline void btrfs_block_rsv_release(struct btrfs_fs_info *fs_info,
+                                          struct btrfs_block_rsv *block_rsv,
+                                          u64 num_bytes)
+{
+       __btrfs_block_rsv_release(fs_info, block_rsv, num_bytes, NULL);
+}
+
+static inline void btrfs_unuse_block_rsv(struct btrfs_fs_info *fs_info,
+                                        struct btrfs_block_rsv *block_rsv,
+                                        u32 blocksize)
+{
+       btrfs_block_rsv_add_bytes(block_rsv, blocksize, false);
+       btrfs_block_rsv_release(fs_info, block_rsv, 0);
+}
+
+#endif /* BTRFS_BLOCK_RSV_H */
index d5b4387..f853835 100644 (file)
@@ -337,22 +337,34 @@ static inline void btrfs_inode_resume_unlocked_dio(struct btrfs_inode *inode)
        clear_bit(BTRFS_INODE_READDIO_NEED_LOCK, &inode->runtime_flags);
 }
 
+/* Array of bytes with variable length, hexadecimal format 0x1234 */
+#define CSUM_FMT                               "0x%*phN"
+#define CSUM_FMT_VALUE(size, bytes)            size, bytes
+
 static inline void btrfs_print_data_csum_error(struct btrfs_inode *inode,
-               u64 logical_start, u32 csum, u32 csum_expected, int mirror_num)
+               u64 logical_start, u8 *csum, u8 *csum_expected, int mirror_num)
 {
        struct btrfs_root *root = inode->root;
+       struct btrfs_super_block *sb = root->fs_info->super_copy;
+       const u16 csum_size = btrfs_super_csum_size(sb);
 
        /* Output minus objectid, which is more meaningful */
        if (root->root_key.objectid >= BTRFS_LAST_FREE_OBJECTID)
                btrfs_warn_rl(root->fs_info,
-       "csum failed root %lld ino %lld off %llu csum 0x%08x expected csum 0x%08x mirror %d",
+"csum failed root %lld ino %lld off %llu csum " CSUM_FMT " expected csum " CSUM_FMT " mirror %d",
                        root->root_key.objectid, btrfs_ino(inode),
-                       logical_start, csum, csum_expected, mirror_num);
+                       logical_start,
+                       CSUM_FMT_VALUE(csum_size, csum),
+                       CSUM_FMT_VALUE(csum_size, csum_expected),
+                       mirror_num);
        else
                btrfs_warn_rl(root->fs_info,
-       "csum failed root %llu ino %llu off %llu csum 0x%08x expected csum 0x%08x mirror %d",
+"csum failed root %llu ino %llu off %llu csum " CSUM_FMT " expected csum " CSUM_FMT " mirror %d",
                        root->root_key.objectid, btrfs_ino(inode),
-                       logical_start, csum, csum_expected, mirror_num);
+                       logical_start,
+                       CSUM_FMT_VALUE(csum_size, csum),
+                       CSUM_FMT_VALUE(csum_size, csum_expected),
+                       mirror_num);
 }
 
 #endif
index b0c8094..81a9731 100644 (file)
@@ -83,7 +83,7 @@
 #include <linux/blkdev.h>
 #include <linux/mm.h>
 #include <linux/string.h>
-#include <linux/crc32c.h>
+#include <crypto/hash.h>
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
@@ -1710,9 +1710,9 @@ static int btrfsic_test_for_metadata(struct btrfsic_state *state,
                                     char **datav, unsigned int num_pages)
 {
        struct btrfs_fs_info *fs_info = state->fs_info;
+       SHASH_DESC_ON_STACK(shash, fs_info->csum_shash);
        struct btrfs_header *h;
        u8 csum[BTRFS_CSUM_SIZE];
-       u32 crc = ~(u32)0;
        unsigned int i;
 
        if (num_pages * PAGE_SIZE < state->metablock_size)
@@ -1723,14 +1723,17 @@ static int btrfsic_test_for_metadata(struct btrfsic_state *state,
        if (memcmp(h->fsid, fs_info->fs_devices->fsid, BTRFS_FSID_SIZE))
                return 1;
 
+       shash->tfm = fs_info->csum_shash;
+       crypto_shash_init(shash);
+
        for (i = 0; i < num_pages; i++) {
                u8 *data = i ? datav[i] : (datav[i] + BTRFS_CSUM_SIZE);
                size_t sublen = i ? PAGE_SIZE :
                                    (PAGE_SIZE - BTRFS_CSUM_SIZE);
 
-               crc = crc32c(crc, data, sublen);
+               crypto_shash_update(shash, data, sublen);
        }
-       btrfs_csum_final(crc, csum);
+       crypto_shash_final(shash, csum);
        if (memcmp(csum, h->csum, state->csum_size))
                return 1;
 
index 84dd4a8..60c47b4 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/sched/mm.h>
 #include <linux/log2.h>
+#include <crypto/hash.h>
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
@@ -42,6 +43,22 @@ const char* btrfs_compress_type2str(enum btrfs_compression_type type)
        return NULL;
 }
 
+bool btrfs_compress_is_valid_type(const char *str, size_t len)
+{
+       int i;
+
+       for (i = 1; i < ARRAY_SIZE(btrfs_compress_types); i++) {
+               size_t comp_len = strlen(btrfs_compress_types[i]);
+
+               if (len < comp_len)
+                       continue;
+
+               if (!strncmp(btrfs_compress_types[i], str, comp_len))
+                       return true;
+       }
+       return false;
+}
+
 static int btrfs_decompress_bio(struct compressed_bio *cb);
 
 static inline int compressed_bio_size(struct btrfs_fs_info *fs_info,
@@ -57,32 +74,37 @@ static int check_compressed_csum(struct btrfs_inode *inode,
                                 struct compressed_bio *cb,
                                 u64 disk_start)
 {
+       struct btrfs_fs_info *fs_info = inode->root->fs_info;
+       SHASH_DESC_ON_STACK(shash, fs_info->csum_shash);
+       const u16 csum_size = btrfs_super_csum_size(fs_info->super_copy);
        int ret;
        struct page *page;
        unsigned long i;
        char *kaddr;
-       u32 csum;
-       u32 *cb_sum = &cb->sums;
+       u8 csum[BTRFS_CSUM_SIZE];
+       u8 *cb_sum = cb->sums;
 
        if (inode->flags & BTRFS_INODE_NODATASUM)
                return 0;
 
+       shash->tfm = fs_info->csum_shash;
+
        for (i = 0; i < cb->nr_pages; i++) {
                page = cb->compressed_pages[i];
-               csum = ~(u32)0;
 
+               crypto_shash_init(shash);
                kaddr = kmap_atomic(page);
-               csum = btrfs_csum_data(kaddr, csum, PAGE_SIZE);
-               btrfs_csum_final(csum, (u8 *)&csum);
+               crypto_shash_update(shash, kaddr, PAGE_SIZE);
                kunmap_atomic(kaddr);
+               crypto_shash_final(shash, (u8 *)&csum);
 
-               if (csum != *cb_sum) {
-                       btrfs_print_data_csum_error(inode, disk_start, csum,
-                                       *cb_sum, cb->mirror_num);
+               if (memcmp(&csum, cb_sum, csum_size)) {
+                       btrfs_print_data_csum_error(inode, disk_start,
+                                       csum, cb_sum, cb->mirror_num);
                        ret = -EIO;
                        goto fail;
                }
-               cb_sum++;
+               cb_sum += csum_size;
 
        }
        ret = 0;
@@ -318,7 +340,8 @@ blk_status_t btrfs_submit_compressed_write(struct inode *inode, u64 start,
 
        bdev = fs_info->fs_devices->latest_bdev;
 
-       bio = btrfs_bio_alloc(bdev, first_byte);
+       bio = btrfs_bio_alloc(first_byte);
+       bio_set_dev(bio, bdev);
        bio->bi_opf = REQ_OP_WRITE | write_flags;
        bio->bi_private = cb;
        bio->bi_end_io = end_compressed_bio_write;
@@ -360,7 +383,8 @@ blk_status_t btrfs_submit_compressed_write(struct inode *inode, u64 start,
                                bio_endio(bio);
                        }
 
-                       bio = btrfs_bio_alloc(bdev, first_byte);
+                       bio = btrfs_bio_alloc(first_byte);
+                       bio_set_dev(bio, bdev);
                        bio->bi_opf = REQ_OP_WRITE | write_flags;
                        bio->bi_private = cb;
                        bio->bi_end_io = end_compressed_bio_write;
@@ -536,7 +560,8 @@ blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
        struct extent_map *em;
        blk_status_t ret = BLK_STS_RESOURCE;
        int faili = 0;
-       u32 *sums;
+       const u16 csum_size = btrfs_super_csum_size(fs_info->super_copy);
+       u8 *sums;
 
        em_tree = &BTRFS_I(inode)->extent_tree;
 
@@ -558,7 +583,7 @@ blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
        cb->errors = 0;
        cb->inode = inode;
        cb->mirror_num = mirror_num;
-       sums = &cb->sums;
+       sums = cb->sums;
 
        cb->start = em->orig_start;
        em_len = em->len;
@@ -597,7 +622,8 @@ blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
        /* include any pages we added in add_ra-bio_pages */
        cb->len = bio->bi_iter.bi_size;
 
-       comp_bio = btrfs_bio_alloc(bdev, cur_disk_byte);
+       comp_bio = btrfs_bio_alloc(cur_disk_byte);
+       bio_set_dev(comp_bio, bdev);
        comp_bio->bi_opf = REQ_OP_READ;
        comp_bio->bi_private = cb;
        comp_bio->bi_end_io = end_compressed_bio_read;
@@ -617,6 +643,8 @@ blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
                page->mapping = NULL;
                if (submit || bio_add_page(comp_bio, page, PAGE_SIZE, 0) <
                    PAGE_SIZE) {
+                       unsigned int nr_sectors;
+
                        ret = btrfs_bio_wq_end_io(fs_info, comp_bio,
                                                  BTRFS_WQ_ENDIO_DATA);
                        BUG_ON(ret); /* -ENOMEM */
@@ -634,8 +662,10 @@ blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
                                                            sums);
                                BUG_ON(ret); /* -ENOMEM */
                        }
-                       sums += DIV_ROUND_UP(comp_bio->bi_iter.bi_size,
-                                            fs_info->sectorsize);
+
+                       nr_sectors = DIV_ROUND_UP(comp_bio->bi_iter.bi_size,
+                                                 fs_info->sectorsize);
+                       sums += csum_size * nr_sectors;
 
                        ret = btrfs_map_bio(fs_info, comp_bio, mirror_num, 0);
                        if (ret) {
@@ -643,7 +673,8 @@ blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
                                bio_endio(comp_bio);
                        }
 
-                       comp_bio = btrfs_bio_alloc(bdev, cur_disk_byte);
+                       comp_bio = btrfs_bio_alloc(cur_disk_byte);
+                       bio_set_dev(comp_bio, bdev);
                        comp_bio->bi_opf = REQ_OP_READ;
                        comp_bio->bi_private = cb;
                        comp_bio->bi_end_io = end_compressed_bio_read;
index 9976fe0..2035b8e 100644 (file)
@@ -61,7 +61,7 @@ struct compressed_bio {
         * the start of a variable length array of checksums only
         * used by reads
         */
-       u32 sums;
+       u8 sums[];
 };
 
 static inline unsigned int btrfs_compress_type(unsigned int type_level)
@@ -173,6 +173,7 @@ extern const struct btrfs_compress_op btrfs_lzo_compress;
 extern const struct btrfs_compress_op btrfs_zstd_compress;
 
 const char* btrfs_compress_type2str(enum btrfs_compression_type type);
+bool btrfs_compress_is_valid_type(const char *str, size_t len);
 
 int btrfs_compress_heuristic(struct inode *inode, u64 start, u64 end);
 
index 0a61dff..299e11e 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/kobject.h>
 #include <trace/events/btrfs.h>
 #include <asm/kmap_types.h>
+#include <asm/unaligned.h>
 #include <linux/pagemap.h>
 #include <linux/btrfs.h>
 #include <linux/btrfs_tree.h>
 #include "extent_io.h"
 #include "extent_map.h"
 #include "async-thread.h"
+#include "block-rsv.h"
 
 struct btrfs_trans_handle;
 struct btrfs_transaction;
 struct btrfs_pending_snapshot;
 struct btrfs_delayed_ref_root;
+struct btrfs_space_info;
 extern struct kmem_cache *btrfs_trans_handle_cachep;
 extern struct kmem_cache *btrfs_bit_radix_cachep;
 extern struct kmem_cache *btrfs_path_cachep;
@@ -45,7 +48,16 @@ struct btrfs_ref;
 
 #define BTRFS_MAGIC 0x4D5F53665248425FULL /* ascii _BHRfS_M, no null */
 
-#define BTRFS_MAX_MIRRORS 3
+/*
+ * Maximum number of mirrors that can be available for all profiles counting
+ * the target device of dev-replace as one. During an active device replace
+ * procedure, the target device of the copy operation is a mirror for the
+ * filesystem data as well that can be used to read data in order to repair
+ * read errors on other disks.
+ *
+ * Current value is derived from RAID1 with 2 copies.
+ */
+#define BTRFS_MAX_MIRRORS (2 + 1)
 
 #define BTRFS_MAX_LEVEL 8
 
@@ -72,6 +84,7 @@ struct btrfs_ref;
 
 /* four bytes for CRC32 */
 static const int btrfs_csum_sizes[] = { 4 };
+static const char *btrfs_csum_names[] = { "crc32c" };
 
 #define BTRFS_EMPTY_DIR_SIZE 0
 
@@ -99,10 +112,6 @@ static inline u32 count_max_extents(u64 size)
        return div_u64(size + BTRFS_MAX_EXTENT_SIZE - 1, BTRFS_MAX_EXTENT_SIZE);
 }
 
-struct btrfs_mapping_tree {
-       struct extent_map_tree map_tree;
-};
-
 static inline unsigned long btrfs_chunk_item_size(int num_stripes)
 {
        BUG_ON(num_stripes == 0);
@@ -395,115 +404,6 @@ struct raid_kobject {
        struct list_head list;
 };
 
-struct btrfs_space_info {
-       spinlock_t lock;
-
-       u64 total_bytes;        /* total bytes in the space,
-                                  this doesn't take mirrors into account */
-       u64 bytes_used;         /* total bytes used,
-                                  this doesn't take mirrors into account */
-       u64 bytes_pinned;       /* total bytes pinned, will be freed when the
-                                  transaction finishes */
-       u64 bytes_reserved;     /* total bytes the allocator has reserved for
-                                  current allocations */
-       u64 bytes_may_use;      /* number of bytes that may be used for
-                                  delalloc/allocations */
-       u64 bytes_readonly;     /* total bytes that are read only */
-
-       u64 max_extent_size;    /* This will hold the maximum extent size of
-                                  the space info if we had an ENOSPC in the
-                                  allocator. */
-
-       unsigned int full:1;    /* indicates that we cannot allocate any more
-                                  chunks for this space */
-       unsigned int chunk_alloc:1;     /* set if we are allocating a chunk */
-
-       unsigned int flush:1;           /* set if we are trying to make space */
-
-       unsigned int force_alloc;       /* set if we need to force a chunk
-                                          alloc for this space */
-
-       u64 disk_used;          /* total bytes used on disk */
-       u64 disk_total;         /* total bytes on disk, takes mirrors into
-                                  account */
-
-       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;
-       struct list_head priority_tickets;
-       struct list_head tickets;
-       /*
-        * tickets_id just indicates the next ticket will be handled, so note
-        * it's not stored per ticket.
-        */
-       u64 tickets_id;
-
-       struct rw_semaphore groups_sem;
-       /* for block groups in our same type */
-       struct list_head block_groups[BTRFS_NR_RAID_TYPES];
-       wait_queue_head_t wait;
-
-       struct kobject kobj;
-       struct kobject *block_group_kobjs[BTRFS_NR_RAID_TYPES];
-};
-
-/*
- * Types of block reserves
- */
-enum {
-       BTRFS_BLOCK_RSV_GLOBAL,
-       BTRFS_BLOCK_RSV_DELALLOC,
-       BTRFS_BLOCK_RSV_TRANS,
-       BTRFS_BLOCK_RSV_CHUNK,
-       BTRFS_BLOCK_RSV_DELOPS,
-       BTRFS_BLOCK_RSV_DELREFS,
-       BTRFS_BLOCK_RSV_EMPTY,
-       BTRFS_BLOCK_RSV_TEMP,
-};
-
-struct btrfs_block_rsv {
-       u64 size;
-       u64 reserved;
-       struct btrfs_space_info *space_info;
-       spinlock_t lock;
-       unsigned short full;
-       unsigned short type;
-       unsigned short failfast;
-
-       /*
-        * Qgroup equivalent for @size @reserved
-        *
-        * Unlike normal @size/@reserved for inode rsv, qgroup doesn't care
-        * about things like csum size nor how many tree blocks it will need to
-        * reserve.
-        *
-        * Qgroup cares more about net change of the extent usage.
-        *
-        * So for one newly inserted file extent, in worst case it will cause
-        * leaf split and level increase, nodesize for each file extent is
-        * already too much.
-        *
-        * In short, qgroup_size/reserved is the upper limit of possible needed
-        * qgroup metadata reservation.
-        */
-       u64 qgroup_rsv_size;
-       u64 qgroup_rsv_reserved;
-};
-
 /*
  * free clusters are used to claim free space in relatively large chunks,
  * allowing us to do less seeky writes. They are used for all metadata
@@ -786,11 +686,18 @@ 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 the cleaner thread is awake and doing something. */
        BTRFS_FS_CLEANER_RUNNING,
+
+       /*
+        * The checksumming has an optimized version and is considered fast,
+        * so we don't need to offload checksums to workqueues.
+        */
+       BTRFS_FS_CSUM_IMPL_FAST,
 };
 
 struct btrfs_fs_info {
@@ -824,7 +731,7 @@ struct btrfs_fs_info {
        struct extent_io_tree *pinned_extents;
 
        /* logical->physical extent mapping */
-       struct btrfs_mapping_tree mapping_tree;
+       struct extent_map_tree mapping_tree;
 
        /*
         * block reservation for extent, checksum, root tree and
@@ -1160,6 +1067,14 @@ struct btrfs_fs_info {
        spinlock_t swapfile_pins_lock;
        struct rb_root swapfile_pins;
 
+       struct crypto_shash *csum_shash;
+
+       /*
+        * Number of send operations in progress.
+        * Updated while holding fs_info::balance_mutex.
+        */
+       int send_in_progress;
+
 #ifdef CONFIG_BTRFS_FS_REF_VERIFY
        spinlock_t ref_verify_lock;
        struct rb_root block_tree;
@@ -2451,6 +2366,11 @@ static inline int btrfs_super_csum_size(const struct btrfs_super_block *s)
        return btrfs_csum_sizes[t];
 }
 
+static inline const char *btrfs_super_csum_name(u16 csum_type)
+{
+       /* csum type is validated at mount time */
+       return btrfs_csum_names[csum_type];
+}
 
 /*
  * The leaf data grows from end-to-front in the node.
@@ -2642,6 +2562,16 @@ BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cursor_right,
        ((unsigned long)(BTRFS_LEAF_DATA_OFFSET + \
        btrfs_item_offset_nr(leaf, slot)))
 
+static inline u32 btrfs_crc32c(u32 crc, const void *address, unsigned length)
+{
+       return crc32c(crc, address, length);
+}
+
+static inline void btrfs_crc32c_final(u32 crc, u8 *result)
+{
+       put_unaligned_le32(~crc, result);
+}
+
 static inline u64 btrfs_name_hash(const char *name, int len)
 {
        return crc32c((u32)~1, name, len);
@@ -2656,12 +2586,6 @@ static inline u64 btrfs_extref_hash(u64 parent_objectid, const char *name,
        return (u64) crc32c(parent_objectid, name, len);
 }
 
-static inline bool btrfs_mixed_space_info(struct btrfs_space_info *space_info)
-{
-       return ((space_info->flags & BTRFS_BLOCK_GROUP_METADATA) &&
-               (space_info->flags & BTRFS_BLOCK_GROUP_DATA));
-}
-
 static inline gfp_t btrfs_alloc_write_mask(struct address_space *mapping)
 {
        return mapping_gfp_constraint(mapping, ~__GFP_FS);
@@ -2698,8 +2622,6 @@ static inline u64 btrfs_calc_trunc_metadata_size(struct btrfs_fs_info *fs_info,
        return (u64)fs_info->nodesize * BTRFS_MAX_LEVEL * num_items;
 }
 
-int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans);
-bool btrfs_check_space_for_delayed_refs(struct btrfs_fs_info *fs_info);
 void btrfs_dec_block_group_reservations(struct btrfs_fs_info *fs_info,
                                         const u64 start);
 void btrfs_wait_block_group_reservations(struct btrfs_block_group_cache *bg);
@@ -2814,17 +2736,28 @@ enum btrfs_flush_state {
        COMMIT_TRANS            =       9,
 };
 
-int btrfs_alloc_data_chunk_ondemand(struct btrfs_inode *inode, u64 bytes);
-int btrfs_check_data_free_space(struct inode *inode,
-                       struct extent_changeset **reserved, u64 start, u64 len);
-void btrfs_free_reserved_data_space(struct inode *inode,
-                       struct extent_changeset *reserved, u64 start, u64 len);
-void btrfs_delalloc_release_space(struct inode *inode,
-                                 struct extent_changeset *reserved,
-                                 u64 start, u64 len, bool qgroup_free);
-void btrfs_free_reserved_data_space_noquota(struct inode *inode, u64 start,
-                                           u64 len);
-void btrfs_trans_release_chunk_metadata(struct btrfs_trans_handle *trans);
+/*
+ * control flags for do_chunk_alloc's force field
+ * CHUNK_ALLOC_NO_FORCE means to only allocate a chunk
+ * if we really need one.
+ *
+ * CHUNK_ALLOC_LIMITED means to only try and allocate one
+ * if we have very few chunks already allocated.  This is
+ * used as part of the clustering code to help make sure
+ * we have a good pool of storage to cluster in, without
+ * filling the FS with empty chunks
+ *
+ * CHUNK_ALLOC_FORCE means it must try to allocate one
+ *
+ */
+enum btrfs_chunk_alloc_enum {
+       CHUNK_ALLOC_NO_FORCE,
+       CHUNK_ALLOC_LIMITED,
+       CHUNK_ALLOC_FORCE,
+};
+
+int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags,
+                     enum btrfs_chunk_alloc_enum force);
 int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
                                     struct btrfs_block_rsv *rsv,
                                     int nitems, bool use_global_rsv);
@@ -2834,41 +2767,6 @@ void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes,
                                    bool qgroup_free);
 
 int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes);
-void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes,
-                                    bool qgroup_free);
-int btrfs_delalloc_reserve_space(struct inode *inode,
-                       struct extent_changeset **reserved, u64 start, u64 len);
-void btrfs_init_block_rsv(struct btrfs_block_rsv *rsv, unsigned short type);
-struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_fs_info *fs_info,
-                                             unsigned short type);
-void btrfs_init_metadata_block_rsv(struct btrfs_fs_info *fs_info,
-                                  struct btrfs_block_rsv *rsv,
-                                  unsigned short type);
-void btrfs_free_block_rsv(struct btrfs_fs_info *fs_info,
-                         struct btrfs_block_rsv *rsv);
-int btrfs_block_rsv_add(struct btrfs_root *root,
-                       struct btrfs_block_rsv *block_rsv, u64 num_bytes,
-                       enum btrfs_reserve_flush_enum flush);
-int btrfs_block_rsv_check(struct btrfs_block_rsv *block_rsv, int min_factor);
-int btrfs_block_rsv_refill(struct btrfs_root *root,
-                          struct btrfs_block_rsv *block_rsv, u64 min_reserved,
-                          enum btrfs_reserve_flush_enum flush);
-int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv,
-                           struct btrfs_block_rsv *dst_rsv, u64 num_bytes,
-                           bool update_size);
-int btrfs_cond_migrate_bytes(struct btrfs_fs_info *fs_info,
-                            struct btrfs_block_rsv *dest, u64 num_bytes,
-                            int min_factor);
-void btrfs_block_rsv_release(struct btrfs_fs_info *fs_info,
-                            struct btrfs_block_rsv *block_rsv,
-                            u64 num_bytes);
-void btrfs_delayed_refs_rsv_release(struct btrfs_fs_info *fs_info, int nr);
-void btrfs_update_delayed_refs_rsv(struct btrfs_trans_handle *trans);
-int btrfs_delayed_refs_rsv_refill(struct btrfs_fs_info *fs_info,
-                                 enum btrfs_reserve_flush_enum flush);
-void btrfs_migrate_to_delayed_refs_rsv(struct btrfs_fs_info *fs_info,
-                                      struct btrfs_block_rsv *src,
-                                      u64 num_bytes);
 int btrfs_inc_block_group_ro(struct btrfs_block_group_cache *cache);
 void btrfs_dec_block_group_ro(struct btrfs_block_group_cache *cache);
 void btrfs_put_block_group_cache(struct btrfs_fs_info *info);
@@ -3186,7 +3084,8 @@ int btrfs_find_name_in_ext_backref(struct extent_buffer *leaf, int slot,
 struct btrfs_dio_private;
 int btrfs_del_csums(struct btrfs_trans_handle *trans,
                    struct btrfs_fs_info *fs_info, u64 bytenr, u64 len);
-blk_status_t btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio, u32 *dst);
+blk_status_t btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio,
+                                  u8 *dst);
 blk_status_t btrfs_lookup_bio_sums_dio(struct inode *inode, struct bio *bio,
                              u64 logical_offset);
 int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
@@ -3514,8 +3413,7 @@ __cold
 static inline void assfail(const char *expr, const char *file, int line)
 {
        if (IS_ENABLED(CONFIG_BTRFS_ASSERT)) {
-               pr_err("assertion failed: %s, file: %s, line: %d\n",
-                      expr, file, line);
+               pr_err("assertion failed: %s, in %s:%d\n", expr, file, line);
                BUG();
        }
 }
@@ -3599,10 +3497,11 @@ do {                                                                    \
 /* compatibility and incompatibility defines */
 
 #define btrfs_set_fs_incompat(__fs_info, opt) \
-       __btrfs_set_fs_incompat((__fs_info), BTRFS_FEATURE_INCOMPAT_##opt)
+       __btrfs_set_fs_incompat((__fs_info), BTRFS_FEATURE_INCOMPAT_##opt, \
+                               #opt)
 
 static inline void __btrfs_set_fs_incompat(struct btrfs_fs_info *fs_info,
-                                          u64 flag)
+                                          u64 flag, const char* name)
 {
        struct btrfs_super_block *disk_super;
        u64 features;
@@ -3615,18 +3514,20 @@ static inline void __btrfs_set_fs_incompat(struct btrfs_fs_info *fs_info,
                if (!(features & flag)) {
                        features |= flag;
                        btrfs_set_super_incompat_flags(disk_super, features);
-                       btrfs_info(fs_info, "setting %llu feature flag",
-                                        flag);
+                       btrfs_info(fs_info,
+                               "setting incompat feature flag for %s (0x%llx)",
+                               name, flag);
                }
                spin_unlock(&fs_info->super_lock);
        }
 }
 
 #define btrfs_clear_fs_incompat(__fs_info, opt) \
-       __btrfs_clear_fs_incompat((__fs_info), BTRFS_FEATURE_INCOMPAT_##opt)
+       __btrfs_clear_fs_incompat((__fs_info), BTRFS_FEATURE_INCOMPAT_##opt, \
+                                 #opt)
 
 static inline void __btrfs_clear_fs_incompat(struct btrfs_fs_info *fs_info,
-                                            u64 flag)
+                                            u64 flag, const char* name)
 {
        struct btrfs_super_block *disk_super;
        u64 features;
@@ -3639,8 +3540,9 @@ static inline void __btrfs_clear_fs_incompat(struct btrfs_fs_info *fs_info,
                if (features & flag) {
                        features &= ~flag;
                        btrfs_set_super_incompat_flags(disk_super, features);
-                       btrfs_info(fs_info, "clearing %llu feature flag",
-                                        flag);
+                       btrfs_info(fs_info,
+                               "clearing incompat feature flag for %s (0x%llx)",
+                               name, flag);
                }
                spin_unlock(&fs_info->super_lock);
        }
@@ -3657,10 +3559,11 @@ static inline bool __btrfs_fs_incompat(struct btrfs_fs_info *fs_info, u64 flag)
 }
 
 #define btrfs_set_fs_compat_ro(__fs_info, opt) \
-       __btrfs_set_fs_compat_ro((__fs_info), BTRFS_FEATURE_COMPAT_RO_##opt)
+       __btrfs_set_fs_compat_ro((__fs_info), BTRFS_FEATURE_COMPAT_RO_##opt, \
+                                #opt)
 
 static inline void __btrfs_set_fs_compat_ro(struct btrfs_fs_info *fs_info,
-                                           u64 flag)
+                                           u64 flag, const char *name)
 {
        struct btrfs_super_block *disk_super;
        u64 features;
@@ -3673,18 +3576,20 @@ static inline void __btrfs_set_fs_compat_ro(struct btrfs_fs_info *fs_info,
                if (!(features & flag)) {
                        features |= flag;
                        btrfs_set_super_compat_ro_flags(disk_super, features);
-                       btrfs_info(fs_info, "setting %llu ro feature flag",
-                                  flag);
+                       btrfs_info(fs_info,
+                               "setting compat-ro feature flag for %s (0x%llx)",
+                               name, flag);
                }
                spin_unlock(&fs_info->super_lock);
        }
 }
 
 #define btrfs_clear_fs_compat_ro(__fs_info, opt) \
-       __btrfs_clear_fs_compat_ro((__fs_info), BTRFS_FEATURE_COMPAT_RO_##opt)
+       __btrfs_clear_fs_compat_ro((__fs_info), BTRFS_FEATURE_COMPAT_RO_##opt, \
+                                  #opt)
 
 static inline void __btrfs_clear_fs_compat_ro(struct btrfs_fs_info *fs_info,
-                                             u64 flag)
+                                             u64 flag, const char *name)
 {
        struct btrfs_super_block *disk_super;
        u64 features;
@@ -3697,8 +3602,9 @@ static inline void __btrfs_clear_fs_compat_ro(struct btrfs_fs_info *fs_info,
                if (features & flag) {
                        features &= ~flag;
                        btrfs_set_super_compat_ro_flags(disk_super, features);
-                       btrfs_info(fs_info, "clearing %llu ro feature flag",
-                                  flag);
+                       btrfs_info(fs_info,
+                               "clearing compat-ro feature flag for %s (0x%llx)",
+                               name, flag);
                }
                spin_unlock(&fs_info->super_lock);
        }
diff --git a/fs/btrfs/delalloc-space.c b/fs/btrfs/delalloc-space.c
new file mode 100644 (file)
index 0000000..17f7c0d
--- /dev/null
@@ -0,0 +1,494 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "ctree.h"
+#include "delalloc-space.h"
+#include "block-rsv.h"
+#include "btrfs_inode.h"
+#include "space-info.h"
+#include "transaction.h"
+#include "qgroup.h"
+
+int btrfs_alloc_data_chunk_ondemand(struct btrfs_inode *inode, u64 bytes)
+{
+       struct btrfs_root *root = inode->root;
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       struct btrfs_space_info *data_sinfo = fs_info->data_sinfo;
+       u64 used;
+       int ret = 0;
+       int need_commit = 2;
+       int have_pinned_space;
+
+       /* Make sure bytes are sectorsize aligned */
+       bytes = ALIGN(bytes, fs_info->sectorsize);
+
+       if (btrfs_is_free_space_inode(inode)) {
+               need_commit = 0;
+               ASSERT(current->journal_info);
+       }
+
+again:
+       /* Make sure we have enough space to handle the data first */
+       spin_lock(&data_sinfo->lock);
+       used = btrfs_space_info_used(data_sinfo, true);
+
+       if (used + bytes > data_sinfo->total_bytes) {
+               struct btrfs_trans_handle *trans;
+
+               /*
+                * If we don't have enough free bytes in this space then we need
+                * to alloc a new chunk.
+                */
+               if (!data_sinfo->full) {
+                       u64 alloc_target;
+
+                       data_sinfo->force_alloc = CHUNK_ALLOC_FORCE;
+                       spin_unlock(&data_sinfo->lock);
+
+                       alloc_target = btrfs_data_alloc_profile(fs_info);
+                       /*
+                        * It is ugly that we don't call nolock join
+                        * transaction for the free space inode case here.
+                        * But it is safe because we only do the data space
+                        * reservation for the free space cache in the
+                        * transaction context, the common join transaction
+                        * just increase the counter of the current transaction
+                        * handler, doesn't try to acquire the trans_lock of
+                        * the fs.
+                        */
+                       trans = btrfs_join_transaction(root);
+                       if (IS_ERR(trans))
+                               return PTR_ERR(trans);
+
+                       ret = btrfs_chunk_alloc(trans, alloc_target,
+                                               CHUNK_ALLOC_NO_FORCE);
+                       btrfs_end_transaction(trans);
+                       if (ret < 0) {
+                               if (ret != -ENOSPC)
+                                       return ret;
+                               else {
+                                       have_pinned_space = 1;
+                                       goto commit_trans;
+                               }
+                       }
+
+                       goto again;
+               }
+
+               /*
+                * If we don't have enough pinned space to deal with this
+                * allocation, and no removed chunk in current transaction,
+                * don't bother committing the transaction.
+                */
+               have_pinned_space = __percpu_counter_compare(
+                       &data_sinfo->total_bytes_pinned,
+                       used + bytes - data_sinfo->total_bytes,
+                       BTRFS_TOTAL_BYTES_PINNED_BATCH);
+               spin_unlock(&data_sinfo->lock);
+
+               /* Commit the current transaction and try again */
+commit_trans:
+               if (need_commit) {
+                       need_commit--;
+
+                       if (need_commit > 0) {
+                               btrfs_start_delalloc_roots(fs_info, -1);
+                               btrfs_wait_ordered_roots(fs_info, U64_MAX, 0,
+                                                        (u64)-1);
+                       }
+
+                       trans = btrfs_join_transaction(root);
+                       if (IS_ERR(trans))
+                               return PTR_ERR(trans);
+                       if (have_pinned_space >= 0 ||
+                           test_bit(BTRFS_TRANS_HAVE_FREE_BGS,
+                                    &trans->transaction->flags) ||
+                           need_commit > 0) {
+                               ret = btrfs_commit_transaction(trans);
+                               if (ret)
+                                       return ret;
+                               /*
+                                * The cleaner kthread might still be doing iput
+                                * operations. Wait for it to finish so that
+                                * more space is released.  We don't need to
+                                * explicitly run the delayed iputs here because
+                                * the commit_transaction would have woken up
+                                * the cleaner.
+                                */
+                               ret = btrfs_wait_on_delayed_iputs(fs_info);
+                               if (ret)
+                                       return ret;
+                               goto again;
+                       } else {
+                               btrfs_end_transaction(trans);
+                       }
+               }
+
+               trace_btrfs_space_reservation(fs_info,
+                                             "space_info:enospc",
+                                             data_sinfo->flags, bytes, 1);
+               return -ENOSPC;
+       }
+       btrfs_space_info_update_bytes_may_use(fs_info, data_sinfo, bytes);
+       trace_btrfs_space_reservation(fs_info, "space_info",
+                                     data_sinfo->flags, bytes, 1);
+       spin_unlock(&data_sinfo->lock);
+
+       return 0;
+}
+
+int btrfs_check_data_free_space(struct inode *inode,
+                       struct extent_changeset **reserved, u64 start, u64 len)
+{
+       struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+       int ret;
+
+       /* align the range */
+       len = round_up(start + len, fs_info->sectorsize) -
+             round_down(start, fs_info->sectorsize);
+       start = round_down(start, fs_info->sectorsize);
+
+       ret = btrfs_alloc_data_chunk_ondemand(BTRFS_I(inode), len);
+       if (ret < 0)
+               return ret;
+
+       /* Use new btrfs_qgroup_reserve_data to reserve precious data space. */
+       ret = btrfs_qgroup_reserve_data(inode, reserved, start, len);
+       if (ret < 0)
+               btrfs_free_reserved_data_space_noquota(inode, start, len);
+       else
+               ret = 0;
+       return ret;
+}
+
+/*
+ * Called if we need to clear a data reservation for this inode
+ * Normally in a error case.
+ *
+ * This one will *NOT* use accurate qgroup reserved space API, just for case
+ * which we can't sleep and is sure it won't affect qgroup reserved space.
+ * Like clear_bit_hook().
+ */
+void btrfs_free_reserved_data_space_noquota(struct inode *inode, u64 start,
+                                           u64 len)
+{
+       struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+       struct btrfs_space_info *data_sinfo;
+
+       /* Make sure the range is aligned to sectorsize */
+       len = round_up(start + len, fs_info->sectorsize) -
+             round_down(start, fs_info->sectorsize);
+       start = round_down(start, fs_info->sectorsize);
+
+       data_sinfo = fs_info->data_sinfo;
+       spin_lock(&data_sinfo->lock);
+       btrfs_space_info_update_bytes_may_use(fs_info, data_sinfo, -len);
+       trace_btrfs_space_reservation(fs_info, "space_info",
+                                     data_sinfo->flags, len, 0);
+       spin_unlock(&data_sinfo->lock);
+}
+
+/*
+ * Called if we need to clear a data reservation for this inode
+ * Normally in a error case.
+ *
+ * This one will handle the per-inode data rsv map for accurate reserved
+ * space framework.
+ */
+void btrfs_free_reserved_data_space(struct inode *inode,
+                       struct extent_changeset *reserved, u64 start, u64 len)
+{
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+
+       /* Make sure the range is aligned to sectorsize */
+       len = round_up(start + len, root->fs_info->sectorsize) -
+             round_down(start, root->fs_info->sectorsize);
+       start = round_down(start, root->fs_info->sectorsize);
+
+       btrfs_free_reserved_data_space_noquota(inode, start, len);
+       btrfs_qgroup_free_data(inode, reserved, start, len);
+}
+
+/**
+ * btrfs_inode_rsv_release - release any excessive reservation.
+ * @inode - the inode we need to release from.
+ * @qgroup_free - free or convert qgroup meta.
+ *   Unlike normal operation, qgroup meta reservation needs to know if we are
+ *   freeing qgroup reservation or just converting it into per-trans.  Normally
+ *   @qgroup_free is true for error handling, and false for normal release.
+ *
+ * This is the same as btrfs_block_rsv_release, except that it handles the
+ * tracepoint for the reservation.
+ */
+static void btrfs_inode_rsv_release(struct btrfs_inode *inode, bool qgroup_free)
+{
+       struct btrfs_fs_info *fs_info = inode->root->fs_info;
+       struct btrfs_block_rsv *block_rsv = &inode->block_rsv;
+       u64 released = 0;
+       u64 qgroup_to_release = 0;
+
+       /*
+        * Since we statically set the block_rsv->size we just want to say we
+        * are releasing 0 bytes, and then we'll just get the reservation over
+        * the size free'd.
+        */
+       released = __btrfs_block_rsv_release(fs_info, block_rsv, 0,
+                                            &qgroup_to_release);
+       if (released > 0)
+               trace_btrfs_space_reservation(fs_info, "delalloc",
+                                             btrfs_ino(inode), released, 0);
+       if (qgroup_free)
+               btrfs_qgroup_free_meta_prealloc(inode->root, qgroup_to_release);
+       else
+               btrfs_qgroup_convert_reserved_meta(inode->root,
+                                                  qgroup_to_release);
+}
+
+static void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info,
+                                                struct btrfs_inode *inode)
+{
+       struct btrfs_block_rsv *block_rsv = &inode->block_rsv;
+       u64 reserve_size = 0;
+       u64 qgroup_rsv_size = 0;
+       u64 csum_leaves;
+       unsigned outstanding_extents;
+
+       lockdep_assert_held(&inode->lock);
+       outstanding_extents = inode->outstanding_extents;
+       if (outstanding_extents)
+               reserve_size = btrfs_calc_trans_metadata_size(fs_info,
+                                               outstanding_extents + 1);
+       csum_leaves = btrfs_csum_bytes_to_leaves(fs_info,
+                                                inode->csum_bytes);
+       reserve_size += btrfs_calc_trans_metadata_size(fs_info,
+                                                      csum_leaves);
+       /*
+        * For qgroup rsv, the calculation is very simple:
+        * account one nodesize for each outstanding extent
+        *
+        * This is overestimating in most cases.
+        */
+       qgroup_rsv_size = (u64)outstanding_extents * fs_info->nodesize;
+
+       spin_lock(&block_rsv->lock);
+       block_rsv->size = reserve_size;
+       block_rsv->qgroup_rsv_size = qgroup_rsv_size;
+       spin_unlock(&block_rsv->lock);
+}
+
+static void calc_inode_reservations(struct btrfs_fs_info *fs_info,
+                                   u64 num_bytes, u64 *meta_reserve,
+                                   u64 *qgroup_reserve)
+{
+       u64 nr_extents = count_max_extents(num_bytes);
+       u64 csum_leaves = btrfs_csum_bytes_to_leaves(fs_info, num_bytes);
+
+       /* We add one for the inode update at finish ordered time */
+       *meta_reserve = btrfs_calc_trans_metadata_size(fs_info,
+                                               nr_extents + csum_leaves + 1);
+       *qgroup_reserve = nr_extents * fs_info->nodesize;
+}
+
+int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes)
+{
+       struct btrfs_root *root = inode->root;
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       struct btrfs_block_rsv *block_rsv = &inode->block_rsv;
+       u64 meta_reserve, qgroup_reserve;
+       unsigned nr_extents;
+       enum btrfs_reserve_flush_enum flush = BTRFS_RESERVE_FLUSH_ALL;
+       int ret = 0;
+       bool delalloc_lock = true;
+
+       /*
+        * If we are a free space inode we need to not flush since we will be in
+        * the middle of a transaction commit.  We also don't need the delalloc
+        * mutex since we won't race with anybody.  We need this mostly to make
+        * lockdep shut its filthy mouth.
+        *
+        * If we have a transaction open (can happen if we call truncate_block
+        * from truncate), then we need FLUSH_LIMIT so we don't deadlock.
+        */
+       if (btrfs_is_free_space_inode(inode)) {
+               flush = BTRFS_RESERVE_NO_FLUSH;
+               delalloc_lock = false;
+       } else {
+               if (current->journal_info)
+                       flush = BTRFS_RESERVE_FLUSH_LIMIT;
+
+               if (btrfs_transaction_in_commit(fs_info))
+                       schedule_timeout(1);
+       }
+
+       if (delalloc_lock)
+               mutex_lock(&inode->delalloc_mutex);
+
+       num_bytes = ALIGN(num_bytes, fs_info->sectorsize);
+
+       /*
+        * We always want to do it this way, every other way is wrong and ends
+        * in tears.  Pre-reserving the amount we are going to add will always
+        * be the right way, because otherwise if we have enough parallelism we
+        * could end up with thousands of inodes all holding little bits of
+        * reservations they were able to make previously and the only way to
+        * reclaim that space is to ENOSPC out the operations and clear
+        * everything out and try again, which is bad.  This way we just
+        * over-reserve slightly, and clean up the mess when we are done.
+        */
+       calc_inode_reservations(fs_info, num_bytes, &meta_reserve,
+                               &qgroup_reserve);
+       ret = btrfs_qgroup_reserve_meta_prealloc(root, qgroup_reserve, true);
+       if (ret)
+               goto out_fail;
+       ret = btrfs_reserve_metadata_bytes(root, block_rsv, meta_reserve, flush);
+       if (ret)
+               goto out_qgroup;
+
+       /*
+        * Now we need to update our outstanding extents and csum bytes _first_
+        * and then add the reservation to the block_rsv.  This keeps us from
+        * racing with an ordered completion or some such that would think it
+        * needs to free the reservation we just made.
+        */
+       spin_lock(&inode->lock);
+       nr_extents = count_max_extents(num_bytes);
+       btrfs_mod_outstanding_extents(inode, nr_extents);
+       inode->csum_bytes += num_bytes;
+       btrfs_calculate_inode_block_rsv_size(fs_info, inode);
+       spin_unlock(&inode->lock);
+
+       /* Now we can safely add our space to our block rsv */
+       btrfs_block_rsv_add_bytes(block_rsv, meta_reserve, false);
+       trace_btrfs_space_reservation(root->fs_info, "delalloc",
+                                     btrfs_ino(inode), meta_reserve, 1);
+
+       spin_lock(&block_rsv->lock);
+       block_rsv->qgroup_rsv_reserved += qgroup_reserve;
+       spin_unlock(&block_rsv->lock);
+
+       if (delalloc_lock)
+               mutex_unlock(&inode->delalloc_mutex);
+       return 0;
+out_qgroup:
+       btrfs_qgroup_free_meta_prealloc(root, qgroup_reserve);
+out_fail:
+       btrfs_inode_rsv_release(inode, true);
+       if (delalloc_lock)
+               mutex_unlock(&inode->delalloc_mutex);
+       return ret;
+}
+
+/**
+ * btrfs_delalloc_release_metadata - release a metadata reservation for an inode
+ * @inode: the inode to release the reservation for.
+ * @num_bytes: the number of bytes we are releasing.
+ * @qgroup_free: free qgroup reservation or convert it to per-trans reservation
+ *
+ * This will release the metadata reservation for an inode.  This can be called
+ * once we complete IO for a given set of bytes to release their metadata
+ * reservations, or on error for the same reason.
+ */
+void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes,
+                                    bool qgroup_free)
+{
+       struct btrfs_fs_info *fs_info = inode->root->fs_info;
+
+       num_bytes = ALIGN(num_bytes, fs_info->sectorsize);
+       spin_lock(&inode->lock);
+       inode->csum_bytes -= num_bytes;
+       btrfs_calculate_inode_block_rsv_size(fs_info, inode);
+       spin_unlock(&inode->lock);
+
+       if (btrfs_is_testing(fs_info))
+               return;
+
+       btrfs_inode_rsv_release(inode, qgroup_free);
+}
+
+/**
+ * btrfs_delalloc_release_extents - release our outstanding_extents
+ * @inode: the inode to balance the reservation for.
+ * @num_bytes: the number of bytes we originally reserved with
+ * @qgroup_free: do we need to free qgroup meta reservation or convert them.
+ *
+ * When we reserve space we increase outstanding_extents for the extents we may
+ * add.  Once we've set the range as delalloc or created our ordered extents we
+ * have outstanding_extents to track the real usage, so we use this to free our
+ * temporarily tracked outstanding_extents.  This _must_ be used in conjunction
+ * with btrfs_delalloc_reserve_metadata.
+ */
+void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes,
+                                   bool qgroup_free)
+{
+       struct btrfs_fs_info *fs_info = inode->root->fs_info;
+       unsigned num_extents;
+
+       spin_lock(&inode->lock);
+       num_extents = count_max_extents(num_bytes);
+       btrfs_mod_outstanding_extents(inode, -num_extents);
+       btrfs_calculate_inode_block_rsv_size(fs_info, inode);
+       spin_unlock(&inode->lock);
+
+       if (btrfs_is_testing(fs_info))
+               return;
+
+       btrfs_inode_rsv_release(inode, qgroup_free);
+}
+
+/**
+ * btrfs_delalloc_reserve_space - reserve data and metadata space for
+ * delalloc
+ * @inode: inode we're writing to
+ * @start: start range we are writing to
+ * @len: how long the range we are writing to
+ * @reserved: mandatory parameter, record actually reserved qgroup ranges of
+ *           current reservation.
+ *
+ * This will do the following things
+ *
+ * - reserve space in data space info for num bytes
+ *   and reserve precious corresponding qgroup space
+ *   (Done in check_data_free_space)
+ *
+ * - reserve space for metadata space, based on the number of outstanding
+ *   extents and how much csums will be needed
+ *   also reserve metadata space in a per root over-reserve method.
+ * - add to the inodes->delalloc_bytes
+ * - add it to the fs_info's delalloc inodes list.
+ *   (Above 3 all done in delalloc_reserve_metadata)
+ *
+ * Return 0 for success
+ * Return <0 for error(-ENOSPC or -EQUOT)
+ */
+int btrfs_delalloc_reserve_space(struct inode *inode,
+                       struct extent_changeset **reserved, u64 start, u64 len)
+{
+       int ret;
+
+       ret = btrfs_check_data_free_space(inode, reserved, start, len);
+       if (ret < 0)
+               return ret;
+       ret = btrfs_delalloc_reserve_metadata(BTRFS_I(inode), len);
+       if (ret < 0)
+               btrfs_free_reserved_data_space(inode, *reserved, start, len);
+       return ret;
+}
+
+/**
+ * btrfs_delalloc_release_space - release data and metadata space for delalloc
+ * @inode: inode we're releasing space for
+ * @start: start position of the space already reserved
+ * @len: the len of the space already reserved
+ * @release_bytes: the len of the space we consumed or didn't use
+ *
+ * This function will release the metadata space that was not used and will
+ * decrement ->delalloc_bytes and remove it from the fs_info delalloc_inodes
+ * list if there are no delalloc bytes left.
+ * Also it will handle the qgroup reserved space.
+ */
+void btrfs_delalloc_release_space(struct inode *inode,
+                                 struct extent_changeset *reserved,
+                                 u64 start, u64 len, bool qgroup_free)
+{
+       btrfs_delalloc_release_metadata(BTRFS_I(inode), len, qgroup_free);
+       btrfs_free_reserved_data_space(inode, reserved, start, len);
+}
diff --git a/fs/btrfs/delalloc-space.h b/fs/btrfs/delalloc-space.h
new file mode 100644 (file)
index 0000000..54466fb
--- /dev/null
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BTRFS_DELALLOC_SPACE_H
+#define BTRFS_DELALLOC_SPACE_H
+
+struct extent_changeset;
+
+int btrfs_alloc_data_chunk_ondemand(struct btrfs_inode *inode, u64 bytes);
+int btrfs_check_data_free_space(struct inode *inode,
+                       struct extent_changeset **reserved, u64 start, u64 len);
+void btrfs_free_reserved_data_space(struct inode *inode,
+                       struct extent_changeset *reserved, u64 start, u64 len);
+void btrfs_delalloc_release_space(struct inode *inode,
+                                 struct extent_changeset *reserved,
+                                 u64 start, u64 len, bool qgroup_free);
+void btrfs_free_reserved_data_space_noquota(struct inode *inode, u64 start,
+                                           u64 len);
+void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes,
+                                    bool qgroup_free);
+int btrfs_delalloc_reserve_space(struct inode *inode,
+                       struct extent_changeset **reserved, u64 start, u64 len);
+
+#endif /* BTRFS_DELALLOC_SPACE_H */
index a73fc23..9a91d1e 100644 (file)
@@ -10,6 +10,7 @@
 #include "delayed-ref.h"
 #include "transaction.h"
 #include "qgroup.h"
+#include "space-info.h"
 
 struct kmem_cache *btrfs_delayed_ref_head_cachep;
 struct kmem_cache *btrfs_delayed_tree_ref_cachep;
@@ -24,6 +25,179 @@ struct kmem_cache *btrfs_delayed_extent_op_cachep;
  * of hammering updates on the extent allocation tree.
  */
 
+bool btrfs_check_space_for_delayed_refs(struct btrfs_fs_info *fs_info)
+{
+       struct btrfs_block_rsv *delayed_refs_rsv = &fs_info->delayed_refs_rsv;
+       struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
+       bool ret = false;
+       u64 reserved;
+
+       spin_lock(&global_rsv->lock);
+       reserved = global_rsv->reserved;
+       spin_unlock(&global_rsv->lock);
+
+       /*
+        * Since the global reserve is just kind of magic we don't really want
+        * to rely on it to save our bacon, so if our size is more than the
+        * delayed_refs_rsv and the global rsv then it's time to think about
+        * bailing.
+        */
+       spin_lock(&delayed_refs_rsv->lock);
+       reserved += delayed_refs_rsv->reserved;
+       if (delayed_refs_rsv->size >= reserved)
+               ret = true;
+       spin_unlock(&delayed_refs_rsv->lock);
+       return ret;
+}
+
+int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans)
+{
+       u64 num_entries =
+               atomic_read(&trans->transaction->delayed_refs.num_entries);
+       u64 avg_runtime;
+       u64 val;
+
+       smp_mb();
+       avg_runtime = trans->fs_info->avg_delayed_ref_runtime;
+       val = num_entries * avg_runtime;
+       if (val >= NSEC_PER_SEC)
+               return 1;
+       if (val >= NSEC_PER_SEC / 2)
+               return 2;
+
+       return btrfs_check_space_for_delayed_refs(trans->fs_info);
+}
+
+/**
+ * btrfs_delayed_refs_rsv_release - release a ref head's reservation.
+ * @fs_info - the fs_info for our fs.
+ * @nr - the number of items to drop.
+ *
+ * This drops the delayed ref head's count from the delayed refs rsv and frees
+ * any excess reservation we had.
+ */
+void btrfs_delayed_refs_rsv_release(struct btrfs_fs_info *fs_info, int nr)
+{
+       struct btrfs_block_rsv *block_rsv = &fs_info->delayed_refs_rsv;
+       u64 num_bytes = btrfs_calc_trans_metadata_size(fs_info, nr);
+       u64 released = 0;
+
+       released = __btrfs_block_rsv_release(fs_info, block_rsv, num_bytes,
+                                            NULL);
+       if (released)
+               trace_btrfs_space_reservation(fs_info, "delayed_refs_rsv",
+                                             0, released, 0);
+}
+
+/*
+ * btrfs_update_delayed_refs_rsv - adjust the size of the delayed refs rsv
+ * @trans - the trans that may have generated delayed refs
+ *
+ * This is to be called anytime we may have adjusted trans->delayed_ref_updates,
+ * it'll calculate the additional size and add it to the delayed_refs_rsv.
+ */
+void btrfs_update_delayed_refs_rsv(struct btrfs_trans_handle *trans)
+{
+       struct btrfs_fs_info *fs_info = trans->fs_info;
+       struct btrfs_block_rsv *delayed_rsv = &fs_info->delayed_refs_rsv;
+       u64 num_bytes;
+
+       if (!trans->delayed_ref_updates)
+               return;
+
+       num_bytes = btrfs_calc_trans_metadata_size(fs_info,
+                                                  trans->delayed_ref_updates);
+       spin_lock(&delayed_rsv->lock);
+       delayed_rsv->size += num_bytes;
+       delayed_rsv->full = 0;
+       spin_unlock(&delayed_rsv->lock);
+       trans->delayed_ref_updates = 0;
+}
+
+/**
+ * btrfs_migrate_to_delayed_refs_rsv - transfer bytes to our delayed refs rsv.
+ * @fs_info - the fs info for our fs.
+ * @src - the source block rsv to transfer from.
+ * @num_bytes - the number of bytes to transfer.
+ *
+ * This transfers up to the num_bytes amount from the src rsv to the
+ * delayed_refs_rsv.  Any extra bytes are returned to the space info.
+ */
+void btrfs_migrate_to_delayed_refs_rsv(struct btrfs_fs_info *fs_info,
+                                      struct btrfs_block_rsv *src,
+                                      u64 num_bytes)
+{
+       struct btrfs_block_rsv *delayed_refs_rsv = &fs_info->delayed_refs_rsv;
+       u64 to_free = 0;
+
+       spin_lock(&src->lock);
+       src->reserved -= num_bytes;
+       src->size -= num_bytes;
+       spin_unlock(&src->lock);
+
+       spin_lock(&delayed_refs_rsv->lock);
+       if (delayed_refs_rsv->size > delayed_refs_rsv->reserved) {
+               u64 delta = delayed_refs_rsv->size -
+                       delayed_refs_rsv->reserved;
+               if (num_bytes > delta) {
+                       to_free = num_bytes - delta;
+                       num_bytes = delta;
+               }
+       } else {
+               to_free = num_bytes;
+               num_bytes = 0;
+       }
+
+       if (num_bytes)
+               delayed_refs_rsv->reserved += num_bytes;
+       if (delayed_refs_rsv->reserved >= delayed_refs_rsv->size)
+               delayed_refs_rsv->full = 1;
+       spin_unlock(&delayed_refs_rsv->lock);
+
+       if (num_bytes)
+               trace_btrfs_space_reservation(fs_info, "delayed_refs_rsv",
+                                             0, num_bytes, 1);
+       if (to_free)
+               btrfs_space_info_add_old_bytes(fs_info,
+                               delayed_refs_rsv->space_info, to_free);
+}
+
+/**
+ * btrfs_delayed_refs_rsv_refill - refill based on our delayed refs usage.
+ * @fs_info - the fs_info for our fs.
+ * @flush - control how we can flush for this reservation.
+ *
+ * This will refill the delayed block_rsv up to 1 items size worth of space and
+ * will return -ENOSPC if we can't make the reservation.
+ */
+int btrfs_delayed_refs_rsv_refill(struct btrfs_fs_info *fs_info,
+                                 enum btrfs_reserve_flush_enum flush)
+{
+       struct btrfs_block_rsv *block_rsv = &fs_info->delayed_refs_rsv;
+       u64 limit = btrfs_calc_trans_metadata_size(fs_info, 1);
+       u64 num_bytes = 0;
+       int ret = -ENOSPC;
+
+       spin_lock(&block_rsv->lock);
+       if (block_rsv->reserved < block_rsv->size) {
+               num_bytes = block_rsv->size - block_rsv->reserved;
+               num_bytes = min(num_bytes, limit);
+       }
+       spin_unlock(&block_rsv->lock);
+
+       if (!num_bytes)
+               return 0;
+
+       ret = btrfs_reserve_metadata_bytes(fs_info->extent_root, block_rsv,
+                                          num_bytes, flush);
+       if (ret)
+               return ret;
+       btrfs_block_rsv_add_bytes(block_rsv, num_bytes, 0);
+       trace_btrfs_space_reservation(fs_info, "delayed_refs_rsv",
+                                     0, num_bytes, 1);
+       return 0;
+}
+
 /*
  * compare two delayed tree backrefs with same bytenr and type
  */
@@ -957,13 +1131,14 @@ int btrfs_add_delayed_extent_op(struct btrfs_trans_handle *trans,
 }
 
 /*
- * this does a simple search for the head node for a given extent.
- * It must be called with the delayed ref spinlock held, and it returns
- * the head node if any where found, or NULL if not.
+ * This does a simple search for the head node for a given extent.  Returns the
+ * head node if found, or NULL if not.
  */
 struct btrfs_delayed_ref_head *
 btrfs_find_delayed_ref_head(struct btrfs_delayed_ref_root *delayed_refs, u64 bytenr)
 {
+       lockdep_assert_held(&delayed_refs->lock);
+
        return find_ref_head(delayed_refs, bytenr, false);
 }
 
index c18f93e..1c977e6 100644 (file)
@@ -364,6 +364,16 @@ struct btrfs_delayed_ref_head *btrfs_select_ref_head(
 
 int btrfs_check_delayed_seq(struct btrfs_fs_info *fs_info, u64 seq);
 
+void btrfs_delayed_refs_rsv_release(struct btrfs_fs_info *fs_info, int nr);
+void btrfs_update_delayed_refs_rsv(struct btrfs_trans_handle *trans);
+int btrfs_delayed_refs_rsv_refill(struct btrfs_fs_info *fs_info,
+                                 enum btrfs_reserve_flush_enum flush);
+void btrfs_migrate_to_delayed_refs_rsv(struct btrfs_fs_info *fs_info,
+                                      struct btrfs_block_rsv *src,
+                                      u64 num_bytes);
+int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans);
+bool btrfs_check_space_for_delayed_refs(struct btrfs_fs_info *fs_info);
+
 /*
  * helper functions to cast a node into its container
  */
index ee0989c..6b2e9aa 100644 (file)
@@ -201,7 +201,7 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
                return PTR_ERR(bdev);
        }
 
-       filemap_write_and_wait(bdev->bd_inode->i_mapping);
+       sync_blockdev(bdev);
 
        devices = &fs_info->fs_devices->devices;
        list_for_each_entry(device, devices, dev_list) {
@@ -237,7 +237,6 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
        }
        rcu_assign_pointer(device->name, name);
 
-       mutex_lock(&fs_info->fs_devices->device_list_mutex);
        set_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state);
        device->generation = 0;
        device->io_width = fs_info->sectorsize;
@@ -256,6 +255,8 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
        device->dev_stats_valid = 1;
        set_blocksize(device->bdev, BTRFS_BDEV_BLOCKSIZE);
        device->fs_devices = fs_info->fs_devices;
+
+       mutex_lock(&fs_info->fs_devices->device_list_mutex);
        list_add(&device->dev_list, &fs_info->fs_devices->devices);
        fs_info->fs_devices->num_devices++;
        fs_info->fs_devices->open_devices++;
@@ -399,7 +400,6 @@ static int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info,
        int ret;
        struct btrfs_device *tgt_device = NULL;
        struct btrfs_device *src_device = NULL;
-       bool need_unlock;
 
        src_device = btrfs_find_device_by_devspec(fs_info, srcdevid,
                                                  srcdev_name);
@@ -413,11 +413,6 @@ static int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info,
                return -ETXTBSY;
        }
 
-       ret = btrfs_init_dev_replace_tgtdev(fs_info, tgtdev_name,
-                                           src_device, &tgt_device);
-       if (ret)
-               return ret;
-
        /*
         * Here we commit the transaction to make sure commit_total_bytes
         * of all the devices are updated.
@@ -431,7 +426,11 @@ static int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info,
                return PTR_ERR(trans);
        }
 
-       need_unlock = true;
+       ret = btrfs_init_dev_replace_tgtdev(fs_info, tgtdev_name,
+                                           src_device, &tgt_device);
+       if (ret)
+               return ret;
+
        down_write(&dev_replace->rwsem);
        switch (dev_replace->replace_state) {
        case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
@@ -442,11 +441,11 @@ static int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info,
        case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
                ASSERT(0);
                ret = BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED;
+               up_write(&dev_replace->rwsem);
                goto leave;
        }
 
        dev_replace->cont_reading_from_srcdev_mode = read_src;
-       WARN_ON(!src_device);
        dev_replace->srcdev = src_device;
        dev_replace->tgtdev = tgt_device;
 
@@ -471,7 +470,6 @@ static int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info,
        atomic64_set(&dev_replace->num_write_errors, 0);
        atomic64_set(&dev_replace->num_uncorrectable_read_errors, 0);
        up_write(&dev_replace->rwsem);
-       need_unlock = false;
 
        ret = btrfs_sysfs_add_device_link(tgt_device->fs_devices, tgt_device);
        if (ret)
@@ -479,16 +477,16 @@ static int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info,
 
        btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1);
 
-       /* force writing the updated state information to disk */
-       trans = btrfs_start_transaction(root, 0);
+       /* Commit dev_replace state and reserve 1 item for it. */
+       trans = btrfs_start_transaction(root, 1);
        if (IS_ERR(trans)) {
                ret = PTR_ERR(trans);
-               need_unlock = true;
                down_write(&dev_replace->rwsem);
                dev_replace->replace_state =
                        BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED;
                dev_replace->srcdev = NULL;
                dev_replace->tgtdev = NULL;
+               up_write(&dev_replace->rwsem);
                goto leave;
        }
 
@@ -510,8 +508,6 @@ static int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info,
        return ret;
 
 leave:
-       if (need_unlock)
-               up_write(&dev_replace->rwsem);
        btrfs_destroy_dev_replace_tgtdev(tgt_device);
        return ret;
 }
@@ -678,7 +674,6 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
        btrfs_device_set_disk_total_bytes(tgt_device,
                                          src_device->disk_total_bytes);
        btrfs_device_set_bytes_used(tgt_device, src_device->bytes_used);
-       tgt_device->commit_total_bytes = src_device->commit_total_bytes;
        tgt_device->commit_bytes_used = src_device->bytes_used;
 
        btrfs_assign_next_active_device(src_device, tgt_device);
@@ -728,7 +723,7 @@ static void btrfs_dev_replace_update_device_in_mapping_tree(
                                                struct btrfs_device *srcdev,
                                                struct btrfs_device *tgtdev)
 {
-       struct extent_map_tree *em_tree = &fs_info->mapping_tree.map_tree;
+       struct extent_map_tree *em_tree = &fs_info->mapping_tree;
        struct extent_map *em;
        struct map_lookup *map;
        u64 start = 0;
index deb74a8..5f7ee70 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/crc32c.h>
 #include <linux/sched/mm.h>
 #include <asm/unaligned.h>
+#include <crypto/hash.h>
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
 #include "tree-checker.h"
 #include "ref-verify.h"
 
-#ifdef CONFIG_X86
-#include <asm/cpufeature.h>
-#endif
-
 #define BTRFS_SUPER_FLAG_SUPP  (BTRFS_HEADER_FLAG_WRITTEN |\
                                 BTRFS_HEADER_FLAG_RELOC |\
                                 BTRFS_SUPER_FLAG_ERROR |\
@@ -249,16 +246,6 @@ out:
        return em;
 }
 
-u32 btrfs_csum_data(const char *data, u32 seed, size_t len)
-{
-       return crc32c(seed, data, len);
-}
-
-void btrfs_csum_final(u32 crc, u8 *result)
-{
-       put_unaligned_le32(~crc, result);
-}
-
 /*
  * Compute the csum of a btree block and store the result to provided buffer.
  *
@@ -266,6 +253,8 @@ void btrfs_csum_final(u32 crc, u8 *result)
  */
 static int csum_tree_block(struct extent_buffer *buf, u8 *result)
 {
+       struct btrfs_fs_info *fs_info = buf->fs_info;
+       SHASH_DESC_ON_STACK(shash, fs_info->csum_shash);
        unsigned long len;
        unsigned long cur_len;
        unsigned long offset = BTRFS_CSUM_SIZE;
@@ -273,9 +262,12 @@ static int csum_tree_block(struct extent_buffer *buf, u8 *result)
        unsigned long map_start;
        unsigned long map_len;
        int err;
-       u32 crc = ~(u32)0;
+
+       shash->tfm = fs_info->csum_shash;
+       crypto_shash_init(shash);
 
        len = buf->len - offset;
+
        while (len > 0) {
                /*
                 * Note: we don't need to check for the err == 1 case here, as
@@ -288,14 +280,13 @@ static int csum_tree_block(struct extent_buffer *buf, u8 *result)
                if (WARN_ON(err))
                        return err;
                cur_len = min(len, map_len - (offset - map_start));
-               crc = btrfs_csum_data(kaddr + offset - map_start,
-                                     crc, cur_len);
+               crypto_shash_update(shash, kaddr + offset - map_start, cur_len);
                len -= cur_len;
                offset += cur_len;
        }
        memset(result, 0, BTRFS_CSUM_SIZE);
 
-       btrfs_csum_final(crc, result);
+       crypto_shash_final(shash, result);
 
        return 0;
 }
@@ -356,6 +347,16 @@ out:
        return ret;
 }
 
+static bool btrfs_supported_super_csum(u16 csum_type)
+{
+       switch (csum_type) {
+       case BTRFS_CSUM_TYPE_CRC32:
+               return true;
+       default:
+               return false;
+       }
+}
+
 /*
  * Return 0 if the superblock checksum type matches the checksum value of that
  * algorithm. Pass the raw disk superblock data.
@@ -365,33 +366,25 @@ static int btrfs_check_super_csum(struct btrfs_fs_info *fs_info,
 {
        struct btrfs_super_block *disk_sb =
                (struct btrfs_super_block *)raw_disk_sb;
-       u16 csum_type = btrfs_super_csum_type(disk_sb);
-       int ret = 0;
+       char result[BTRFS_CSUM_SIZE];
+       SHASH_DESC_ON_STACK(shash, fs_info->csum_shash);
 
-       if (csum_type == BTRFS_CSUM_TYPE_CRC32) {
-               u32 crc = ~(u32)0;
-               char result[sizeof(crc)];
+       shash->tfm = fs_info->csum_shash;
+       crypto_shash_init(shash);
 
-               /*
-                * The super_block structure does not span the whole
-                * BTRFS_SUPER_INFO_SIZE range, we expect that the unused space
-                * is filled with zeros and is included in the checksum.
-                */
-               crc = btrfs_csum_data(raw_disk_sb + BTRFS_CSUM_SIZE,
-                               crc, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE);
-               btrfs_csum_final(crc, result);
+       /*
+        * The super_block structure does not span the whole
+        * BTRFS_SUPER_INFO_SIZE range, we expect that the unused space is
+        * filled with zeros and is included in the checksum.
+        */
+       crypto_shash_update(shash, raw_disk_sb + BTRFS_CSUM_SIZE,
+                           BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE);
+       crypto_shash_final(shash, result);
 
-               if (memcmp(raw_disk_sb, result, sizeof(result)))
-                       ret = 1;
-       }
+       if (memcmp(disk_sb->csum, result, btrfs_super_csum_size(disk_sb)))
+               return 1;
 
-       if (csum_type >= ARRAY_SIZE(btrfs_csum_sizes)) {
-               btrfs_err(fs_info, "unsupported checksum algorithm %u",
-                               csum_type);
-               ret = 1;
-       }
-
-       return ret;
+       return 0;
 }
 
 int btrfs_verify_level_key(struct extent_buffer *eb, int level,
@@ -873,14 +866,13 @@ static blk_status_t btree_submit_bio_start(void *private_data, struct bio *bio,
        return btree_csum_one_bio(bio);
 }
 
-static int check_async_write(struct btrfs_inode *bi)
+static int check_async_write(struct btrfs_fs_info *fs_info,
+                            struct btrfs_inode *bi)
 {
        if (atomic_read(&bi->sync_writers))
                return 0;
-#ifdef CONFIG_X86
-       if (static_cpu_has(X86_FEATURE_XMM4_2))
+       if (test_bit(BTRFS_FS_CSUM_IMPL_FAST, &fs_info->flags))
                return 0;
-#endif
        return 1;
 }
 
@@ -889,7 +881,7 @@ static blk_status_t btree_submit_bio_hook(struct inode *inode, struct bio *bio,
                                          unsigned long bio_flags)
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
-       int async = check_async_write(BTRFS_I(inode));
+       int async = check_async_write(fs_info, BTRFS_I(inode));
        blk_status_t ret;
 
        if (bio_op(bio) != REQ_OP_WRITE) {
@@ -2262,6 +2254,29 @@ static int btrfs_init_workqueues(struct btrfs_fs_info *fs_info,
        return 0;
 }
 
+static int btrfs_init_csum_hash(struct btrfs_fs_info *fs_info, u16 csum_type)
+{
+       struct crypto_shash *csum_shash;
+       const char *csum_name = btrfs_super_csum_name(csum_type);
+
+       csum_shash = crypto_alloc_shash(csum_name, 0, 0);
+
+       if (IS_ERR(csum_shash)) {
+               btrfs_err(fs_info, "error allocating %s hash for checksum",
+                         csum_name);
+               return PTR_ERR(csum_shash);
+       }
+
+       fs_info->csum_shash = csum_shash;
+
+       return 0;
+}
+
+static void btrfs_free_csum_hash(struct btrfs_fs_info *fs_info)
+{
+       crypto_free_shash(fs_info->csum_shash);
+}
+
 static int btrfs_replay_log(struct btrfs_fs_info *fs_info,
                            struct btrfs_fs_devices *fs_devices)
 {
@@ -2577,7 +2592,7 @@ static int btrfs_validate_write_super(struct btrfs_fs_info *fs_info,
        ret = validate_super(fs_info, sb, -1);
        if (ret < 0)
                goto out;
-       if (btrfs_super_csum_type(sb) != BTRFS_CSUM_TYPE_CRC32) {
+       if (!btrfs_supported_super_csum(btrfs_super_csum_type(sb))) {
                ret = -EUCLEAN;
                btrfs_err(fs_info, "invalid csum type, has %u want %u",
                          btrfs_super_csum_type(sb), BTRFS_CSUM_TYPE_CRC32);
@@ -2607,6 +2622,7 @@ int open_ctree(struct super_block *sb,
        u32 stripesize;
        u64 generation;
        u64 features;
+       u16 csum_type;
        struct btrfs_key location;
        struct buffer_head *bh;
        struct btrfs_super_block *disk_super;
@@ -2689,7 +2705,7 @@ int open_ctree(struct super_block *sb,
        INIT_LIST_HEAD(&fs_info->space_info);
        INIT_LIST_HEAD(&fs_info->tree_mod_seq_list);
        INIT_LIST_HEAD(&fs_info->unused_bgs);
-       btrfs_mapping_init(&fs_info->mapping_tree);
+       extent_map_tree_init(&fs_info->mapping_tree);
        btrfs_init_block_rsv(&fs_info->global_block_rsv,
                             BTRFS_BLOCK_RSV_GLOBAL);
        btrfs_init_block_rsv(&fs_info->trans_block_rsv, BTRFS_BLOCK_RSV_TRANS);
@@ -2793,6 +2809,8 @@ int open_ctree(struct super_block *sb,
        spin_lock_init(&fs_info->swapfile_pins_lock);
        fs_info->swapfile_pins = RB_ROOT;
 
+       fs_info->send_in_progress = 0;
+
        ret = btrfs_alloc_stripe_hash_table(fs_info);
        if (ret) {
                err = ret;
@@ -2813,6 +2831,25 @@ int open_ctree(struct super_block *sb,
        }
 
        /*
+        * Verify the type first, if that or the the checksum value are
+        * corrupted, we'll find out
+        */
+       csum_type = btrfs_super_csum_type((struct btrfs_super_block *)bh->b_data);
+       if (!btrfs_supported_super_csum(csum_type)) {
+               btrfs_err(fs_info, "unsupported checksum algorithm: %u",
+                         csum_type);
+               err = -EINVAL;
+               brelse(bh);
+               goto fail_alloc;
+       }
+
+       ret = btrfs_init_csum_hash(fs_info, csum_type);
+       if (ret) {
+               err = ret;
+               goto fail_alloc;
+       }
+
+       /*
         * We want to check superblock checksum, the type is stored inside.
         * Pass the whole disk block of size BTRFS_SUPER_INFO_SIZE (4k).
         */
@@ -2820,7 +2857,7 @@ int open_ctree(struct super_block *sb,
                btrfs_err(fs_info, "superblock checksum mismatch");
                err = -EINVAL;
                brelse(bh);
-               goto fail_alloc;
+               goto fail_csum;
        }
 
        /*
@@ -2857,11 +2894,11 @@ int open_ctree(struct super_block *sb,
        if (ret) {
                btrfs_err(fs_info, "superblock contains fatal errors");
                err = -EINVAL;
-               goto fail_alloc;
+               goto fail_csum;
        }
 
        if (!btrfs_super_root(disk_super))
-               goto fail_alloc;
+               goto fail_csum;
 
        /* check FS state, whether FS is broken. */
        if (btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_ERROR)
@@ -2883,7 +2920,7 @@ int open_ctree(struct super_block *sb,
        ret = btrfs_parse_options(fs_info, options, sb->s_flags);
        if (ret) {
                err = ret;
-               goto fail_alloc;
+               goto fail_csum;
        }
 
        features = btrfs_super_incompat_flags(disk_super) &
@@ -2893,7 +2930,7 @@ int open_ctree(struct super_block *sb,
                    "cannot mount because of unsupported optional features (%llx)",
                    features);
                err = -EINVAL;
-               goto fail_alloc;
+               goto fail_csum;
        }
 
        features = btrfs_super_incompat_flags(disk_super);
@@ -2937,7 +2974,7 @@ int open_ctree(struct super_block *sb,
                btrfs_err(fs_info,
 "unequal nodesize/sectorsize (%u != %u) are not allowed for mixed block groups",
                        nodesize, sectorsize);
-               goto fail_alloc;
+               goto fail_csum;
        }
 
        /*
@@ -2953,7 +2990,7 @@ int open_ctree(struct super_block *sb,
        "cannot mount read-write because of unsupported optional features (%llx)",
                       features);
                err = -EINVAL;
-               goto fail_alloc;
+               goto fail_csum;
        }
 
        ret = btrfs_init_workqueues(fs_info, fs_devices);
@@ -3331,6 +3368,8 @@ fail_tree_roots:
 fail_sb_buffer:
        btrfs_stop_all_workers(fs_info);
        btrfs_free_block_groups(fs_info);
+fail_csum:
+       btrfs_free_csum_hash(fs_info);
 fail_alloc:
 fail_iput:
        btrfs_mapping_tree_free(&fs_info->mapping_tree);
@@ -3472,17 +3511,20 @@ struct buffer_head *btrfs_read_dev_super(struct block_device *bdev)
 static int write_dev_supers(struct btrfs_device *device,
                            struct btrfs_super_block *sb, int max_mirrors)
 {
+       struct btrfs_fs_info *fs_info = device->fs_info;
+       SHASH_DESC_ON_STACK(shash, fs_info->csum_shash);
        struct buffer_head *bh;
        int i;
        int ret;
        int errors = 0;
-       u32 crc;
        u64 bytenr;
        int op_flags;
 
        if (max_mirrors == 0)
                max_mirrors = BTRFS_SUPER_MIRROR_MAX;
 
+       shash->tfm = fs_info->csum_shash;
+
        for (i = 0; i < max_mirrors; i++) {
                bytenr = btrfs_sb_offset(i);
                if (bytenr + BTRFS_SUPER_INFO_SIZE >=
@@ -3491,10 +3533,10 @@ static int write_dev_supers(struct btrfs_device *device,
 
                btrfs_set_super_bytenr(sb, bytenr);
 
-               crc = ~(u32)0;
-               crc = btrfs_csum_data((const char *)sb + BTRFS_CSUM_SIZE, crc,
-                                     BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE);
-               btrfs_csum_final(crc, sb->csum);
+               crypto_shash_init(shash);
+               crypto_shash_update(shash, (const char *)sb + BTRFS_CSUM_SIZE,
+                                   BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE);
+               crypto_shash_final(shash, sb->csum);
 
                /* One reference for us, and we leave it for the caller */
                bh = __getblk(device->bdev, bytenr / BTRFS_BDEV_BLOCKSIZE,
@@ -3709,7 +3751,7 @@ int btrfs_get_num_tolerated_disk_barrier_failures(u64 flags)
 
        if ((flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0 ||
            (flags & BTRFS_AVAIL_ALLOC_BIT_SINGLE))
-               min_tolerated = min(min_tolerated,
+               min_tolerated = min_t(int, min_tolerated,
                                    btrfs_raid_array[BTRFS_RAID_SINGLE].
                                    tolerated_failures);
 
@@ -3718,7 +3760,7 @@ int btrfs_get_num_tolerated_disk_barrier_failures(u64 flags)
                        continue;
                if (!(flags & btrfs_raid_array[raid_type].bg_flag))
                        continue;
-               min_tolerated = min(min_tolerated,
+               min_tolerated = min_t(int, min_tolerated,
                                    btrfs_raid_array[raid_type].
                                    tolerated_failures);
        }
@@ -4064,6 +4106,7 @@ void close_ctree(struct btrfs_fs_info *fs_info)
        percpu_counter_destroy(&fs_info->dev_replace.bio_counter);
        cleanup_srcu_struct(&fs_info->subvol_srcu);
 
+       btrfs_free_csum_hash(fs_info);
        btrfs_free_stripe_hash_table(fs_info);
        btrfs_free_ref_cache(fs_info);
 }
index a0161aa..e80f7c4 100644 (file)
@@ -115,8 +115,6 @@ int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid,
                          int atomic);
 int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid, int level,
                      struct btrfs_key *first_key);
-u32 btrfs_csum_data(const char *data, u32 seed, size_t len);
-void btrfs_csum_final(u32 crc, u8 *result);
 blk_status_t btrfs_bio_wq_end_io(struct btrfs_fs_info *info, struct bio *bio,
                        enum btrfs_wq_endio_type metadata);
 blk_status_t btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
index 5faf057..d3b58e3 100644 (file)
 #include "sysfs.h"
 #include "qgroup.h"
 #include "ref-verify.h"
+#include "space-info.h"
+#include "block-rsv.h"
+#include "delalloc-space.h"
 
 #undef SCRAMBLE_DELAYED_REFS
 
-/*
- * control flags for do_chunk_alloc's force field
- * CHUNK_ALLOC_NO_FORCE means to only allocate a chunk
- * if we really need one.
- *
- * CHUNK_ALLOC_LIMITED means to only try and allocate one
- * if we have very few chunks already allocated.  This is
- * used as part of the clustering code to help make sure
- * we have a good pool of storage to cluster in, without
- * filling the FS with empty chunks
- *
- * CHUNK_ALLOC_FORCE means it must try to allocate one
- *
- */
-enum {
-       CHUNK_ALLOC_NO_FORCE = 0,
-       CHUNK_ALLOC_LIMITED = 1,
-       CHUNK_ALLOC_FORCE = 2,
-};
-
-/*
- * Declare a helper function to detect underflow of various space info members
- */
-#define DECLARE_SPACE_INFO_UPDATE(name)                                        \
-static inline void update_##name(struct btrfs_space_info *sinfo,       \
-                                s64 bytes)                             \
-{                                                                      \
-       if (bytes < 0 && sinfo->name < -bytes) {                        \
-               WARN_ON(1);                                             \
-               sinfo->name = 0;                                        \
-               return;                                                 \
-       }                                                               \
-       sinfo->name += bytes;                                           \
-}
-
-DECLARE_SPACE_INFO_UPDATE(bytes_may_use);
-DECLARE_SPACE_INFO_UPDATE(bytes_pinned);
 
 static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                               struct btrfs_delayed_ref_node *node, u64 parent,
@@ -84,21 +50,8 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
 static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
                                     struct btrfs_delayed_ref_node *node,
                                     struct btrfs_delayed_extent_op *extent_op);
-static int do_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags,
-                         int force);
 static int find_next_key(struct btrfs_path *path, int level,
                         struct btrfs_key *key);
-static void dump_space_info(struct btrfs_fs_info *fs_info,
-                           struct btrfs_space_info *info, u64 bytes,
-                           int dump_block_groups);
-static int block_rsv_use_bytes(struct btrfs_block_rsv *block_rsv,
-                              u64 num_bytes);
-static void space_info_add_new_bytes(struct btrfs_fs_info *fs_info,
-                                    struct btrfs_space_info *space_info,
-                                    u64 num_bytes);
-static void space_info_add_old_bytes(struct btrfs_fs_info *fs_info,
-                                    struct btrfs_space_info *space_info,
-                                    u64 num_bytes);
 
 static noinline int
 block_group_cache_done(struct btrfs_block_group_cache *cache)
@@ -737,62 +690,39 @@ struct btrfs_block_group_cache *btrfs_lookup_block_group(
        return block_group_cache_tree_search(info, bytenr, 1);
 }
 
-static struct btrfs_space_info *__find_space_info(struct btrfs_fs_info *info,
-                                                 u64 flags)
+static u64 generic_ref_to_space_flags(struct btrfs_ref *ref)
 {
-       struct list_head *head = &info->space_info;
-       struct btrfs_space_info *found;
-
-       flags &= BTRFS_BLOCK_GROUP_TYPE_MASK;
-
-       rcu_read_lock();
-       list_for_each_entry_rcu(found, head, list) {
-               if (found->flags & flags) {
-                       rcu_read_unlock();
-                       return found;
-               }
+       if (ref->type == BTRFS_REF_METADATA) {
+               if (ref->tree_ref.root == BTRFS_CHUNK_TREE_OBJECTID)
+                       return BTRFS_BLOCK_GROUP_SYSTEM;
+               else
+                       return BTRFS_BLOCK_GROUP_METADATA;
        }
-       rcu_read_unlock();
-       return NULL;
+       return BTRFS_BLOCK_GROUP_DATA;
 }
 
 static void add_pinned_bytes(struct btrfs_fs_info *fs_info,
-                            struct btrfs_ref *ref, int sign)
+                            struct btrfs_ref *ref)
 {
        struct btrfs_space_info *space_info;
-       s64 num_bytes;
-       u64 flags;
-
-       ASSERT(sign == 1 || sign == -1);
-       num_bytes = sign * ref->len;
-       if (ref->type == BTRFS_REF_METADATA) {
-               if (ref->tree_ref.root == BTRFS_CHUNK_TREE_OBJECTID)
-                       flags = BTRFS_BLOCK_GROUP_SYSTEM;
-               else
-                       flags = BTRFS_BLOCK_GROUP_METADATA;
-       } else {
-               flags = BTRFS_BLOCK_GROUP_DATA;
-       }
+       u64 flags = generic_ref_to_space_flags(ref);
 
-       space_info = __find_space_info(fs_info, flags);
+       space_info = btrfs_find_space_info(fs_info, flags);
        ASSERT(space_info);
-       percpu_counter_add_batch(&space_info->total_bytes_pinned, num_bytes,
+       percpu_counter_add_batch(&space_info->total_bytes_pinned, ref->len,
                    BTRFS_TOTAL_BYTES_PINNED_BATCH);
 }
 
-/*
- * after adding space to the filesystem, we need to clear the full flags
- * on all the space infos.
- */
-void btrfs_clear_space_info_full(struct btrfs_fs_info *info)
+static void sub_pinned_bytes(struct btrfs_fs_info *fs_info,
+                            struct btrfs_ref *ref)
 {
-       struct list_head *head = &info->space_info;
-       struct btrfs_space_info *found;
+       struct btrfs_space_info *space_info;
+       u64 flags = generic_ref_to_space_flags(ref);
 
-       rcu_read_lock();
-       list_for_each_entry_rcu(found, head, list)
-               found->full = 0;
-       rcu_read_unlock();
+       space_info = btrfs_find_space_info(fs_info, flags);
+       ASSERT(space_info);
+       percpu_counter_add_batch(&space_info->total_bytes_pinned, -ref->len,
+                   BTRFS_TOTAL_BYTES_PINNED_BATCH);
 }
 
 /* simple helper to search for an existing data extent at a given offset */
@@ -1121,11 +1051,11 @@ static u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset)
        __le64 lenum;
 
        lenum = cpu_to_le64(root_objectid);
-       high_crc = crc32c(high_crc, &lenum, sizeof(lenum));
+       high_crc = btrfs_crc32c(high_crc, &lenum, sizeof(lenum));
        lenum = cpu_to_le64(owner);
-       low_crc = crc32c(low_crc, &lenum, sizeof(lenum));
+       low_crc = btrfs_crc32c(low_crc, &lenum, sizeof(lenum));
        lenum = cpu_to_le64(offset);
-       low_crc = crc32c(low_crc, &lenum, sizeof(lenum));
+       low_crc = btrfs_crc32c(low_crc, &lenum, sizeof(lenum));
 
        return ((u64)high_crc << 31) ^ (u64)low_crc;
 }
@@ -2065,7 +1995,7 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
        btrfs_ref_tree_mod(fs_info, generic_ref);
 
        if (ret == 0 && old_ref_mod < 0 && new_ref_mod >= 0)
-               add_pinned_bytes(fs_info, generic_ref, -1);
+               sub_pinned_bytes(fs_info, generic_ref);
 
        return ret;
 }
@@ -2462,7 +2392,7 @@ void btrfs_cleanup_ref_head_accounting(struct btrfs_fs_info *fs_info,
                        flags = BTRFS_BLOCK_GROUP_SYSTEM;
                else
                        flags = BTRFS_BLOCK_GROUP_METADATA;
-               space_info = __find_space_info(fs_info, flags);
+               space_info = btrfs_find_space_info(fs_info, flags);
                ASSERT(space_info);
                percpu_counter_add_batch(&space_info->total_bytes_pinned,
                                   -head->num_bytes,
@@ -2824,49 +2754,6 @@ u64 btrfs_csum_bytes_to_leaves(struct btrfs_fs_info *fs_info, u64 csum_bytes)
        return num_csums;
 }
 
-bool btrfs_check_space_for_delayed_refs(struct btrfs_fs_info *fs_info)
-{
-       struct btrfs_block_rsv *delayed_refs_rsv = &fs_info->delayed_refs_rsv;
-       struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
-       bool ret = false;
-       u64 reserved;
-
-       spin_lock(&global_rsv->lock);
-       reserved = global_rsv->reserved;
-       spin_unlock(&global_rsv->lock);
-
-       /*
-        * Since the global reserve is just kind of magic we don't really want
-        * to rely on it to save our bacon, so if our size is more than the
-        * delayed_refs_rsv and the global rsv then it's time to think about
-        * bailing.
-        */
-       spin_lock(&delayed_refs_rsv->lock);
-       reserved += delayed_refs_rsv->reserved;
-       if (delayed_refs_rsv->size >= reserved)
-               ret = true;
-       spin_unlock(&delayed_refs_rsv->lock);
-       return ret;
-}
-
-int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans)
-{
-       u64 num_entries =
-               atomic_read(&trans->transaction->delayed_refs.num_entries);
-       u64 avg_runtime;
-       u64 val;
-
-       smp_mb();
-       avg_runtime = trans->fs_info->avg_delayed_ref_runtime;
-       val = num_entries * avg_runtime;
-       if (val >= NSEC_PER_SEC)
-               return 1;
-       if (val >= NSEC_PER_SEC / 2)
-               return 2;
-
-       return btrfs_check_space_for_delayed_refs(trans->fs_info);
-}
-
 /*
  * this starts processing the delayed reference count updates and
  * extent insertions we have queued up so far.  count can be
@@ -3834,93 +3721,6 @@ void btrfs_wait_nocow_writers(struct btrfs_block_group_cache *bg)
        wait_var_event(&bg->nocow_writers, !atomic_read(&bg->nocow_writers));
 }
 
-static const char *alloc_name(u64 flags)
-{
-       switch (flags) {
-       case BTRFS_BLOCK_GROUP_METADATA|BTRFS_BLOCK_GROUP_DATA:
-               return "mixed";
-       case BTRFS_BLOCK_GROUP_METADATA:
-               return "metadata";
-       case BTRFS_BLOCK_GROUP_DATA:
-               return "data";
-       case BTRFS_BLOCK_GROUP_SYSTEM:
-               return "system";
-       default:
-               WARN_ON(1);
-               return "invalid-combination";
-       };
-}
-
-static int create_space_info(struct btrfs_fs_info *info, u64 flags)
-{
-
-       struct btrfs_space_info *space_info;
-       int i;
-       int ret;
-
-       space_info = kzalloc(sizeof(*space_info), GFP_NOFS);
-       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);
-       spin_lock_init(&space_info->lock);
-       space_info->flags = flags & BTRFS_BLOCK_GROUP_TYPE_MASK;
-       space_info->force_alloc = CHUNK_ALLOC_NO_FORCE;
-       init_waitqueue_head(&space_info->wait);
-       INIT_LIST_HEAD(&space_info->ro_bgs);
-       INIT_LIST_HEAD(&space_info->tickets);
-       INIT_LIST_HEAD(&space_info->priority_tickets);
-
-       ret = kobject_init_and_add(&space_info->kobj, &space_info_ktype,
-                                   info->space_info_kobj, "%s",
-                                   alloc_name(space_info->flags));
-       if (ret) {
-               kobject_put(&space_info->kobj);
-               return ret;
-       }
-
-       list_add_rcu(&space_info->list, &info->space_info);
-       if (flags & BTRFS_BLOCK_GROUP_DATA)
-               info->data_sinfo = space_info;
-
-       return ret;
-}
-
-static void update_space_info(struct btrfs_fs_info *info, u64 flags,
-                            u64 total_bytes, u64 bytes_used,
-                            u64 bytes_readonly,
-                            struct btrfs_space_info **space_info)
-{
-       struct btrfs_space_info *found;
-       int factor;
-
-       factor = btrfs_bg_type_to_factor(flags);
-
-       found = __find_space_info(info, flags);
-       ASSERT(found);
-       spin_lock(&found->lock);
-       found->total_bytes += total_bytes;
-       found->disk_total += total_bytes * factor;
-       found->bytes_used += bytes_used;
-       found->disk_used += bytes_used * factor;
-       found->bytes_readonly += bytes_readonly;
-       if (total_bytes > 0)
-               found->full = 0;
-       space_info_add_new_bytes(info, found, total_bytes -
-                                bytes_used - bytes_readonly);
-       spin_unlock(&found->lock);
-       *space_info = found;
-}
-
 static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
 {
        u64 extra_flags = chunk_to_extended(flags) &
@@ -4068,215 +3868,6 @@ u64 btrfs_system_alloc_profile(struct btrfs_fs_info *fs_info)
        return get_alloc_profile(fs_info, BTRFS_BLOCK_GROUP_SYSTEM);
 }
 
-static u64 btrfs_space_info_used(struct btrfs_space_info *s_info,
-                                bool may_use_included)
-{
-       ASSERT(s_info);
-       return s_info->bytes_used + s_info->bytes_reserved +
-               s_info->bytes_pinned + s_info->bytes_readonly +
-               (may_use_included ? s_info->bytes_may_use : 0);
-}
-
-int btrfs_alloc_data_chunk_ondemand(struct btrfs_inode *inode, u64 bytes)
-{
-       struct btrfs_root *root = inode->root;
-       struct btrfs_fs_info *fs_info = root->fs_info;
-       struct btrfs_space_info *data_sinfo = fs_info->data_sinfo;
-       u64 used;
-       int ret = 0;
-       int need_commit = 2;
-       int have_pinned_space;
-
-       /* make sure bytes are sectorsize aligned */
-       bytes = ALIGN(bytes, fs_info->sectorsize);
-
-       if (btrfs_is_free_space_inode(inode)) {
-               need_commit = 0;
-               ASSERT(current->journal_info);
-       }
-
-again:
-       /* make sure we have enough space to handle the data first */
-       spin_lock(&data_sinfo->lock);
-       used = btrfs_space_info_used(data_sinfo, true);
-
-       if (used + bytes > data_sinfo->total_bytes) {
-               struct btrfs_trans_handle *trans;
-
-               /*
-                * if we don't have enough free bytes in this space then we need
-                * to alloc a new chunk.
-                */
-               if (!data_sinfo->full) {
-                       u64 alloc_target;
-
-                       data_sinfo->force_alloc = CHUNK_ALLOC_FORCE;
-                       spin_unlock(&data_sinfo->lock);
-
-                       alloc_target = btrfs_data_alloc_profile(fs_info);
-                       /*
-                        * It is ugly that we don't call nolock join
-                        * transaction for the free space inode case here.
-                        * But it is safe because we only do the data space
-                        * reservation for the free space cache in the
-                        * transaction context, the common join transaction
-                        * just increase the counter of the current transaction
-                        * handler, doesn't try to acquire the trans_lock of
-                        * the fs.
-                        */
-                       trans = btrfs_join_transaction(root);
-                       if (IS_ERR(trans))
-                               return PTR_ERR(trans);
-
-                       ret = do_chunk_alloc(trans, alloc_target,
-                                            CHUNK_ALLOC_NO_FORCE);
-                       btrfs_end_transaction(trans);
-                       if (ret < 0) {
-                               if (ret != -ENOSPC)
-                                       return ret;
-                               else {
-                                       have_pinned_space = 1;
-                                       goto commit_trans;
-                               }
-                       }
-
-                       goto again;
-               }
-
-               /*
-                * If we don't have enough pinned space to deal with this
-                * allocation, and no removed chunk in current transaction,
-                * don't bother committing the transaction.
-                */
-               have_pinned_space = __percpu_counter_compare(
-                       &data_sinfo->total_bytes_pinned,
-                       used + bytes - data_sinfo->total_bytes,
-                       BTRFS_TOTAL_BYTES_PINNED_BATCH);
-               spin_unlock(&data_sinfo->lock);
-
-               /* commit the current transaction and try again */
-commit_trans:
-               if (need_commit) {
-                       need_commit--;
-
-                       if (need_commit > 0) {
-                               btrfs_start_delalloc_roots(fs_info, -1);
-                               btrfs_wait_ordered_roots(fs_info, U64_MAX, 0,
-                                                        (u64)-1);
-                       }
-
-                       trans = btrfs_join_transaction(root);
-                       if (IS_ERR(trans))
-                               return PTR_ERR(trans);
-                       if (have_pinned_space >= 0 ||
-                           test_bit(BTRFS_TRANS_HAVE_FREE_BGS,
-                                    &trans->transaction->flags) ||
-                           need_commit > 0) {
-                               ret = btrfs_commit_transaction(trans);
-                               if (ret)
-                                       return ret;
-                               /*
-                                * The cleaner kthread might still be doing iput
-                                * operations. Wait for it to finish so that
-                                * more space is released.  We don't need to
-                                * explicitly run the delayed iputs here because
-                                * the commit_transaction would have woken up
-                                * the cleaner.
-                                */
-                               ret = btrfs_wait_on_delayed_iputs(fs_info);
-                               if (ret)
-                                       return ret;
-                               goto again;
-                       } else {
-                               btrfs_end_transaction(trans);
-                       }
-               }
-
-               trace_btrfs_space_reservation(fs_info,
-                                             "space_info:enospc",
-                                             data_sinfo->flags, bytes, 1);
-               return -ENOSPC;
-       }
-       update_bytes_may_use(data_sinfo, bytes);
-       trace_btrfs_space_reservation(fs_info, "space_info",
-                                     data_sinfo->flags, bytes, 1);
-       spin_unlock(&data_sinfo->lock);
-
-       return 0;
-}
-
-int btrfs_check_data_free_space(struct inode *inode,
-                       struct extent_changeset **reserved, u64 start, u64 len)
-{
-       struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
-       int ret;
-
-       /* align the range */
-       len = round_up(start + len, fs_info->sectorsize) -
-             round_down(start, fs_info->sectorsize);
-       start = round_down(start, fs_info->sectorsize);
-
-       ret = btrfs_alloc_data_chunk_ondemand(BTRFS_I(inode), len);
-       if (ret < 0)
-               return ret;
-
-       /* Use new btrfs_qgroup_reserve_data to reserve precious data space. */
-       ret = btrfs_qgroup_reserve_data(inode, reserved, start, len);
-       if (ret < 0)
-               btrfs_free_reserved_data_space_noquota(inode, start, len);
-       else
-               ret = 0;
-       return ret;
-}
-
-/*
- * Called if we need to clear a data reservation for this inode
- * Normally in a error case.
- *
- * This one will *NOT* use accurate qgroup reserved space API, just for case
- * which we can't sleep and is sure it won't affect qgroup reserved space.
- * Like clear_bit_hook().
- */
-void btrfs_free_reserved_data_space_noquota(struct inode *inode, u64 start,
-                                           u64 len)
-{
-       struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
-       struct btrfs_space_info *data_sinfo;
-
-       /* Make sure the range is aligned to sectorsize */
-       len = round_up(start + len, fs_info->sectorsize) -
-             round_down(start, fs_info->sectorsize);
-       start = round_down(start, fs_info->sectorsize);
-
-       data_sinfo = fs_info->data_sinfo;
-       spin_lock(&data_sinfo->lock);
-       update_bytes_may_use(data_sinfo, -len);
-       trace_btrfs_space_reservation(fs_info, "space_info",
-                                     data_sinfo->flags, len, 0);
-       spin_unlock(&data_sinfo->lock);
-}
-
-/*
- * Called if we need to clear a data reservation for this inode
- * Normally in a error case.
- *
- * This one will handle the per-inode data rsv map for accurate reserved
- * space framework.
- */
-void btrfs_free_reserved_data_space(struct inode *inode,
-                       struct extent_changeset *reserved, u64 start, u64 len)
-{
-       struct btrfs_root *root = BTRFS_I(inode)->root;
-
-       /* Make sure the range is aligned to sectorsize */
-       len = round_up(start + len, root->fs_info->sectorsize) -
-             round_down(start, root->fs_info->sectorsize);
-       start = round_down(start, root->fs_info->sectorsize);
-
-       btrfs_free_reserved_data_space_noquota(inode, start, len);
-       btrfs_qgroup_free_data(inode, reserved, start, len);
-}
-
 static void force_metadata_allocation(struct btrfs_fs_info *info)
 {
        struct list_head *head = &info->space_info;
@@ -4290,11 +3881,6 @@ static void force_metadata_allocation(struct btrfs_fs_info *info)
        rcu_read_unlock();
 }
 
-static inline u64 calc_global_rsv_need_space(struct btrfs_block_rsv *global)
-{
-       return (global->size << 1);
-}
-
 static int should_alloc_chunk(struct btrfs_fs_info *fs_info,
                              struct btrfs_space_info *sinfo, int force)
 {
@@ -4325,15 +3911,9 @@ static u64 get_profile_num_devs(struct btrfs_fs_info *fs_info, u64 type)
 {
        u64 num_dev;
 
-       if (type & (BTRFS_BLOCK_GROUP_RAID10 |
-                   BTRFS_BLOCK_GROUP_RAID0 |
-                   BTRFS_BLOCK_GROUP_RAID5 |
-                   BTRFS_BLOCK_GROUP_RAID6))
+       num_dev = btrfs_raid_array[btrfs_bg_flags_to_raid_index(type)].devs_max;
+       if (!num_dev)
                num_dev = fs_info->fs_devices->rw_devices;
-       else if (type & BTRFS_BLOCK_GROUP_RAID1)
-               num_dev = 2;
-       else
-               num_dev = 1;    /* DUP or single */
 
        return num_dev;
 }
@@ -4358,7 +3938,7 @@ void check_system_chunk(struct btrfs_trans_handle *trans, u64 type)
         */
        lockdep_assert_held(&fs_info->chunk_mutex);
 
-       info = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_SYSTEM);
+       info = btrfs_find_space_info(fs_info, BTRFS_BLOCK_GROUP_SYSTEM);
        spin_lock(&info->lock);
        left = info->total_bytes - btrfs_space_info_used(info, true);
        spin_unlock(&info->lock);
@@ -4370,1869 +3950,161 @@ void check_system_chunk(struct btrfs_trans_handle *trans, u64 type)
                btrfs_calc_trans_metadata_size(fs_info, 1);
 
        if (left < thresh && btrfs_test_opt(fs_info, ENOSPC_DEBUG)) {
-               btrfs_info(fs_info, "left=%llu, need=%llu, flags=%llu",
-                          left, thresh, type);
-               dump_space_info(fs_info, info, 0, 0);
-       }
-
-       if (left < thresh) {
-               u64 flags = btrfs_system_alloc_profile(fs_info);
-
-               /*
-                * Ignore failure to create system chunk. We might end up not
-                * needing it, as we might not need to COW all nodes/leafs from
-                * the paths we visit in the chunk tree (they were already COWed
-                * or created in the current transaction for example).
-                */
-               ret = btrfs_alloc_chunk(trans, flags);
-       }
-
-       if (!ret) {
-               ret = btrfs_block_rsv_add(fs_info->chunk_root,
-                                         &fs_info->chunk_block_rsv,
-                                         thresh, BTRFS_RESERVE_NO_FLUSH);
-               if (!ret)
-                       trans->chunk_bytes_reserved += thresh;
-       }
-}
-
-/*
- * If force is CHUNK_ALLOC_FORCE:
- *    - return 1 if it successfully allocates a chunk,
- *    - return errors including -ENOSPC otherwise.
- * If force is NOT CHUNK_ALLOC_FORCE:
- *    - return 0 if it doesn't need to allocate a new chunk,
- *    - return 1 if it successfully allocates a chunk,
- *    - return errors including -ENOSPC otherwise.
- */
-static int do_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags,
-                         int force)
-{
-       struct btrfs_fs_info *fs_info = trans->fs_info;
-       struct btrfs_space_info *space_info;
-       bool wait_for_alloc = false;
-       bool should_alloc = false;
-       int ret = 0;
-
-       /* Don't re-enter if we're already allocating a chunk */
-       if (trans->allocating_chunk)
-               return -ENOSPC;
-
-       space_info = __find_space_info(fs_info, flags);
-       ASSERT(space_info);
-
-       do {
-               spin_lock(&space_info->lock);
-               if (force < space_info->force_alloc)
-                       force = space_info->force_alloc;
-               should_alloc = should_alloc_chunk(fs_info, space_info, force);
-               if (space_info->full) {
-                       /* No more free physical space */
-                       if (should_alloc)
-                               ret = -ENOSPC;
-                       else
-                               ret = 0;
-                       spin_unlock(&space_info->lock);
-                       return ret;
-               } else if (!should_alloc) {
-                       spin_unlock(&space_info->lock);
-                       return 0;
-               } else if (space_info->chunk_alloc) {
-                       /*
-                        * Someone is already allocating, so we need to block
-                        * until this someone is finished and then loop to
-                        * recheck if we should continue with our allocation
-                        * attempt.
-                        */
-                       wait_for_alloc = true;
-                       spin_unlock(&space_info->lock);
-                       mutex_lock(&fs_info->chunk_mutex);
-                       mutex_unlock(&fs_info->chunk_mutex);
-               } else {
-                       /* Proceed with allocation */
-                       space_info->chunk_alloc = 1;
-                       wait_for_alloc = false;
-                       spin_unlock(&space_info->lock);
-               }
-
-               cond_resched();
-       } while (wait_for_alloc);
-
-       mutex_lock(&fs_info->chunk_mutex);
-       trans->allocating_chunk = true;
-
-       /*
-        * If we have mixed data/metadata chunks we want to make sure we keep
-        * allocating mixed chunks instead of individual chunks.
-        */
-       if (btrfs_mixed_space_info(space_info))
-               flags |= (BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA);
-
-       /*
-        * if we're doing a data chunk, go ahead and make sure that
-        * we keep a reasonable number of metadata chunks allocated in the
-        * FS as well.
-        */
-       if (flags & BTRFS_BLOCK_GROUP_DATA && fs_info->metadata_ratio) {
-               fs_info->data_chunk_allocations++;
-               if (!(fs_info->data_chunk_allocations %
-                     fs_info->metadata_ratio))
-                       force_metadata_allocation(fs_info);
-       }
-
-       /*
-        * Check if we have enough space in SYSTEM chunk because we may need
-        * to update devices.
-        */
-       check_system_chunk(trans, flags);
-
-       ret = btrfs_alloc_chunk(trans, flags);
-       trans->allocating_chunk = false;
-
-       spin_lock(&space_info->lock);
-       if (ret < 0) {
-               if (ret == -ENOSPC)
-                       space_info->full = 1;
-               else
-                       goto out;
-       } else {
-               ret = 1;
-               space_info->max_extent_size = 0;
-       }
-
-       space_info->force_alloc = CHUNK_ALLOC_NO_FORCE;
-out:
-       space_info->chunk_alloc = 0;
-       spin_unlock(&space_info->lock);
-       mutex_unlock(&fs_info->chunk_mutex);
-       /*
-        * When we allocate a new chunk we reserve space in the chunk block
-        * reserve to make sure we can COW nodes/leafs in the chunk tree or
-        * add new nodes/leafs to it if we end up needing to do it when
-        * inserting the chunk item and updating device items as part of the
-        * second phase of chunk allocation, performed by
-        * btrfs_finish_chunk_alloc(). So make sure we don't accumulate a
-        * large number of new block groups to create in our transaction
-        * handle's new_bgs list to avoid exhausting the chunk block reserve
-        * in extreme cases - like having a single transaction create many new
-        * block groups when starting to write out the free space caches of all
-        * the block groups that were made dirty during the lifetime of the
-        * transaction.
-        */
-       if (trans->chunk_bytes_reserved >= (u64)SZ_2M)
-               btrfs_create_pending_block_groups(trans);
-
-       return ret;
-}
-
-static int can_overcommit(struct btrfs_fs_info *fs_info,
-                         struct btrfs_space_info *space_info, u64 bytes,
-                         enum btrfs_reserve_flush_enum flush,
-                         bool system_chunk)
-{
-       struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
-       u64 profile;
-       u64 space_size;
-       u64 avail;
-       u64 used;
-       int factor;
-
-       /* Don't overcommit when in mixed mode. */
-       if (space_info->flags & BTRFS_BLOCK_GROUP_DATA)
-               return 0;
-
-       if (system_chunk)
-               profile = btrfs_system_alloc_profile(fs_info);
-       else
-               profile = btrfs_metadata_alloc_profile(fs_info);
-
-       used = btrfs_space_info_used(space_info, false);
-
-       /*
-        * We only want to allow over committing if we have lots of actual space
-        * free, but if we don't have enough space to handle the global reserve
-        * space then we could end up having a real enospc problem when trying
-        * to allocate a chunk or some other such important allocation.
-        */
-       spin_lock(&global_rsv->lock);
-       space_size = calc_global_rsv_need_space(global_rsv);
-       spin_unlock(&global_rsv->lock);
-       if (used + space_size >= space_info->total_bytes)
-               return 0;
-
-       used += space_info->bytes_may_use;
-
-       avail = atomic64_read(&fs_info->free_chunk_space);
-
-       /*
-        * If we have dup, raid1 or raid10 then only half of the free
-        * space is actually usable.  For raid56, the space info used
-        * doesn't include the parity drive, so we don't have to
-        * change the math
-        */
-       factor = btrfs_bg_type_to_factor(profile);
-       avail = div_u64(avail, factor);
-
-       /*
-        * If we aren't flushing all things, let us overcommit up to
-        * 1/2th of the space. If we can flush, don't let us overcommit
-        * too much, let it overcommit up to 1/8 of the space.
-        */
-       if (flush == BTRFS_RESERVE_FLUSH_ALL)
-               avail >>= 3;
-       else
-               avail >>= 1;
-
-       if (used + bytes < space_info->total_bytes + avail)
-               return 1;
-       return 0;
-}
-
-static void btrfs_writeback_inodes_sb_nr(struct btrfs_fs_info *fs_info,
-                                        unsigned long nr_pages, int nr_items)
-{
-       struct super_block *sb = fs_info->sb;
-
-       if (down_read_trylock(&sb->s_umount)) {
-               writeback_inodes_sb_nr(sb, nr_pages, WB_REASON_FS_FREE_SPACE);
-               up_read(&sb->s_umount);
-       } else {
-               /*
-                * We needn't worry the filesystem going from r/w to r/o though
-                * we don't acquire ->s_umount mutex, because the filesystem
-                * should guarantee the delalloc inodes list be empty after
-                * the filesystem is readonly(all dirty pages are written to
-                * the disk).
-                */
-               btrfs_start_delalloc_roots(fs_info, nr_items);
-               if (!current->journal_info)
-                       btrfs_wait_ordered_roots(fs_info, nr_items, 0, (u64)-1);
-       }
-}
-
-static inline u64 calc_reclaim_items_nr(struct btrfs_fs_info *fs_info,
-                                       u64 to_reclaim)
-{
-       u64 bytes;
-       u64 nr;
-
-       bytes = btrfs_calc_trans_metadata_size(fs_info, 1);
-       nr = div64_u64(to_reclaim, bytes);
-       if (!nr)
-               nr = 1;
-       return nr;
-}
-
-#define EXTENT_SIZE_PER_ITEM   SZ_256K
-
-/*
- * shrink metadata reservation for delalloc
- */
-static void shrink_delalloc(struct btrfs_fs_info *fs_info, u64 to_reclaim,
-                           u64 orig, bool wait_ordered)
-{
-       struct btrfs_space_info *space_info;
-       struct btrfs_trans_handle *trans;
-       u64 delalloc_bytes;
-       u64 dio_bytes;
-       u64 async_pages;
-       u64 items;
-       long time_left;
-       unsigned long nr_pages;
-       int loops;
-
-       /* Calc the number of the pages we need flush for space reservation */
-       items = calc_reclaim_items_nr(fs_info, to_reclaim);
-       to_reclaim = items * EXTENT_SIZE_PER_ITEM;
-
-       trans = (struct btrfs_trans_handle *)current->journal_info;
-       space_info = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA);
-
-       delalloc_bytes = percpu_counter_sum_positive(
-                                               &fs_info->delalloc_bytes);
-       dio_bytes = percpu_counter_sum_positive(&fs_info->dio_bytes);
-       if (delalloc_bytes == 0 && dio_bytes == 0) {
-               if (trans)
-                       return;
-               if (wait_ordered)
-                       btrfs_wait_ordered_roots(fs_info, items, 0, (u64)-1);
-               return;
-       }
-
-       /*
-        * If we are doing more ordered than delalloc we need to just wait on
-        * ordered extents, otherwise we'll waste time trying to flush delalloc
-        * that likely won't give us the space back we need.
-        */
-       if (dio_bytes > delalloc_bytes)
-               wait_ordered = true;
-
-       loops = 0;
-       while ((delalloc_bytes || dio_bytes) && loops < 3) {
-               nr_pages = min(delalloc_bytes, to_reclaim) >> PAGE_SHIFT;
-
-               /*
-                * Triggers inode writeback for up to nr_pages. This will invoke
-                * ->writepages callback and trigger delalloc filling
-                *  (btrfs_run_delalloc_range()).
-                */
-               btrfs_writeback_inodes_sb_nr(fs_info, nr_pages, items);
-
-               /*
-                * We need to wait for the compressed pages to start before
-                * we continue.
-                */
-               async_pages = atomic_read(&fs_info->async_delalloc_pages);
-               if (!async_pages)
-                       goto skip_async;
-
-               /*
-                * Calculate how many compressed pages we want to be written
-                * before we continue. I.e if there are more async pages than we
-                * require wait_event will wait until nr_pages are written.
-                */
-               if (async_pages <= nr_pages)
-                       async_pages = 0;
-               else
-                       async_pages -= nr_pages;
-
-               wait_event(fs_info->async_submit_wait,
-                          atomic_read(&fs_info->async_delalloc_pages) <=
-                          (int)async_pages);
-skip_async:
-               spin_lock(&space_info->lock);
-               if (list_empty(&space_info->tickets) &&
-                   list_empty(&space_info->priority_tickets)) {
-                       spin_unlock(&space_info->lock);
-                       break;
-               }
-               spin_unlock(&space_info->lock);
-
-               loops++;
-               if (wait_ordered && !trans) {
-                       btrfs_wait_ordered_roots(fs_info, items, 0, (u64)-1);
-               } else {
-                       time_left = schedule_timeout_killable(1);
-                       if (time_left)
-                               break;
-               }
-               delalloc_bytes = percpu_counter_sum_positive(
-                                               &fs_info->delalloc_bytes);
-               dio_bytes = percpu_counter_sum_positive(&fs_info->dio_bytes);
-       }
-}
-
-struct reserve_ticket {
-       u64 orig_bytes;
-       u64 bytes;
-       int error;
-       struct list_head list;
-       wait_queue_head_t wait;
-};
-
-/**
- * maybe_commit_transaction - possibly commit the transaction if its ok to
- * @root - the root we're allocating for
- * @bytes - the number of bytes we want to reserve
- * @force - force the commit
- *
- * 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_trans_handle *trans;
-       u64 bytes_needed;
-       u64 reclaim_bytes = 0;
-
-       trans = (struct btrfs_trans_handle *)current->journal_info;
-       if (trans)
-               return -EAGAIN;
-
-       spin_lock(&space_info->lock);
-       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);
-       bytes_needed = (ticket) ? ticket->bytes : 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 reservation for
-        * this reservation.
-        */
-       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);
-       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
- * state of @space_info to detect the outcome.
- */
-static void flush_space(struct btrfs_fs_info *fs_info,
-                      struct btrfs_space_info *space_info, u64 num_bytes,
-                      int state)
-{
-       struct btrfs_root *root = fs_info->extent_root;
-       struct btrfs_trans_handle *trans;
-       int nr;
-       int ret = 0;
-
-       switch (state) {
-       case FLUSH_DELAYED_ITEMS_NR:
-       case FLUSH_DELAYED_ITEMS:
-               if (state == FLUSH_DELAYED_ITEMS_NR)
-                       nr = calc_reclaim_items_nr(fs_info, num_bytes) * 2;
-               else
-                       nr = -1;
-
-               trans = btrfs_join_transaction(root);
-               if (IS_ERR(trans)) {
-                       ret = PTR_ERR(trans);
-                       break;
-               }
-               ret = btrfs_run_delayed_items_nr(trans, nr);
-               btrfs_end_transaction(trans);
-               break;
-       case FLUSH_DELALLOC:
-       case FLUSH_DELALLOC_WAIT:
-               shrink_delalloc(fs_info, num_bytes * 2, num_bytes,
-                               state == FLUSH_DELALLOC_WAIT);
-               break;
-       case FLUSH_DELAYED_REFS_NR:
-       case FLUSH_DELAYED_REFS:
-               trans = btrfs_join_transaction(root);
-               if (IS_ERR(trans)) {
-                       ret = PTR_ERR(trans);
-                       break;
-               }
-               if (state == FLUSH_DELAYED_REFS_NR)
-                       nr = calc_reclaim_items_nr(fs_info, num_bytes);
-               else
-                       nr = 0;
-               btrfs_run_delayed_refs(trans, nr);
-               btrfs_end_transaction(trans);
-               break;
-       case ALLOC_CHUNK:
-       case ALLOC_CHUNK_FORCE:
-               trans = btrfs_join_transaction(root);
-               if (IS_ERR(trans)) {
-                       ret = PTR_ERR(trans);
-                       break;
-               }
-               ret = do_chunk_alloc(trans,
-                                    btrfs_metadata_alloc_profile(fs_info),
-                                    (state == ALLOC_CHUNK) ?
-                                     CHUNK_ALLOC_NO_FORCE : CHUNK_ALLOC_FORCE);
-               btrfs_end_transaction(trans);
-               if (ret > 0 || ret == -ENOSPC)
-                       ret = 0;
-               break;
-       case COMMIT_TRANS:
-               /*
-                * If we have pending delayed iputs then we could free up a
-                * bunch of pinned space, so make sure we run the iputs before
-                * we do our pinned bytes check below.
-                */
-               btrfs_run_delayed_iputs(fs_info);
-               btrfs_wait_on_delayed_iputs(fs_info);
-
-               ret = may_commit_transaction(fs_info, space_info);
-               break;
-       default:
-               ret = -ENOSPC;
-               break;
-       }
-
-       trace_btrfs_flush_space(fs_info, space_info->flags, num_bytes, state,
-                               ret);
-       return;
-}
-
-static inline u64
-btrfs_calc_reclaim_metadata_size(struct btrfs_fs_info *fs_info,
-                                struct btrfs_space_info *space_info,
-                                bool system_chunk)
-{
-       struct reserve_ticket *ticket;
-       u64 used;
-       u64 expected;
-       u64 to_reclaim = 0;
-
-       list_for_each_entry(ticket, &space_info->tickets, list)
-               to_reclaim += ticket->bytes;
-       list_for_each_entry(ticket, &space_info->priority_tickets, list)
-               to_reclaim += ticket->bytes;
-       if (to_reclaim)
-               return to_reclaim;
-
-       to_reclaim = min_t(u64, num_online_cpus() * SZ_1M, SZ_16M);
-       if (can_overcommit(fs_info, space_info, to_reclaim,
-                          BTRFS_RESERVE_FLUSH_ALL, system_chunk))
-               return 0;
-
-       used = btrfs_space_info_used(space_info, true);
-
-       if (can_overcommit(fs_info, space_info, SZ_1M,
-                          BTRFS_RESERVE_FLUSH_ALL, system_chunk))
-               expected = div_factor_fine(space_info->total_bytes, 95);
-       else
-               expected = div_factor_fine(space_info->total_bytes, 90);
-
-       if (used > expected)
-               to_reclaim = used - expected;
-       else
-               to_reclaim = 0;
-       to_reclaim = min(to_reclaim, space_info->bytes_may_use +
-                                    space_info->bytes_reserved);
-       return to_reclaim;
-}
-
-static inline int need_do_async_reclaim(struct btrfs_fs_info *fs_info,
-                                       struct btrfs_space_info *space_info,
-                                       u64 used, bool system_chunk)
-{
-       u64 thresh = div_factor_fine(space_info->total_bytes, 98);
-
-       /* If we're just plain full then async reclaim just slows us down. */
-       if ((space_info->bytes_used + space_info->bytes_reserved) >= thresh)
-               return 0;
-
-       if (!btrfs_calc_reclaim_metadata_size(fs_info, space_info,
-                                             system_chunk))
-               return 0;
-
-       return (used >= thresh && !btrfs_fs_closing(fs_info) &&
-               !test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state));
-}
-
-static bool wake_all_tickets(struct list_head *head)
-{
-       struct reserve_ticket *ticket;
-
-       while (!list_empty(head)) {
-               ticket = list_first_entry(head, struct reserve_ticket, list);
-               list_del_init(&ticket->list);
-               ticket->error = -ENOSPC;
-               wake_up(&ticket->wait);
-               if (ticket->bytes != ticket->orig_bytes)
-                       return true;
-       }
-       return false;
-}
-
-/*
- * This is for normal flushers, we can wait all goddamned day if we want to.  We
- * will loop and continuously try to flush as long as we are making progress.
- * We count progress as clearing off tickets each time we have to loop.
- */
-static void btrfs_async_reclaim_metadata_space(struct work_struct *work)
-{
-       struct btrfs_fs_info *fs_info;
-       struct btrfs_space_info *space_info;
-       u64 to_reclaim;
-       int flush_state;
-       int commit_cycles = 0;
-       u64 last_tickets_id;
-
-       fs_info = container_of(work, struct btrfs_fs_info, async_reclaim_work);
-       space_info = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA);
-
-       spin_lock(&space_info->lock);
-       to_reclaim = btrfs_calc_reclaim_metadata_size(fs_info, space_info,
-                                                     false);
-       if (!to_reclaim) {
-               space_info->flush = 0;
-               spin_unlock(&space_info->lock);
-               return;
-       }
-       last_tickets_id = space_info->tickets_id;
-       spin_unlock(&space_info->lock);
-
-       flush_state = FLUSH_DELAYED_ITEMS_NR;
-       do {
-               flush_space(fs_info, space_info, to_reclaim, flush_state);
-               spin_lock(&space_info->lock);
-               if (list_empty(&space_info->tickets)) {
-                       space_info->flush = 0;
-                       spin_unlock(&space_info->lock);
-                       return;
-               }
-               to_reclaim = btrfs_calc_reclaim_metadata_size(fs_info,
-                                                             space_info,
-                                                             false);
-               if (last_tickets_id == space_info->tickets_id) {
-                       flush_state++;
-               } else {
-                       last_tickets_id = space_info->tickets_id;
-                       flush_state = FLUSH_DELAYED_ITEMS_NR;
-                       if (commit_cycles)
-                               commit_cycles--;
-               }
-
-               /*
-                * We don't want to force a chunk allocation until we've tried
-                * pretty hard to reclaim space.  Think of the case where we
-                * freed up a bunch of space and so have a lot of pinned space
-                * to reclaim.  We would rather use that than possibly create a
-                * underutilized metadata chunk.  So if this is our first run
-                * through the flushing state machine skip ALLOC_CHUNK_FORCE and
-                * commit the transaction.  If nothing has changed the next go
-                * around then we can force a chunk allocation.
-                */
-               if (flush_state == ALLOC_CHUNK_FORCE && !commit_cycles)
-                       flush_state++;
-
-               if (flush_state > COMMIT_TRANS) {
-                       commit_cycles++;
-                       if (commit_cycles > 2) {
-                               if (wake_all_tickets(&space_info->tickets)) {
-                                       flush_state = FLUSH_DELAYED_ITEMS_NR;
-                                       commit_cycles--;
-                               } else {
-                                       space_info->flush = 0;
-                               }
-                       } else {
-                               flush_state = FLUSH_DELAYED_ITEMS_NR;
-                       }
-               }
-               spin_unlock(&space_info->lock);
-       } while (flush_state <= COMMIT_TRANS);
-}
-
-void btrfs_init_async_reclaim_work(struct work_struct *work)
-{
-       INIT_WORK(work, btrfs_async_reclaim_metadata_space);
-}
-
-static const enum btrfs_flush_state priority_flush_states[] = {
-       FLUSH_DELAYED_ITEMS_NR,
-       FLUSH_DELAYED_ITEMS,
-       ALLOC_CHUNK,
-};
-
-static void priority_reclaim_metadata_space(struct btrfs_fs_info *fs_info,
-                                           struct btrfs_space_info *space_info,
-                                           struct reserve_ticket *ticket)
-{
-       u64 to_reclaim;
-       int flush_state;
-
-       spin_lock(&space_info->lock);
-       to_reclaim = btrfs_calc_reclaim_metadata_size(fs_info, space_info,
-                                                     false);
-       if (!to_reclaim) {
-               spin_unlock(&space_info->lock);
-               return;
-       }
-       spin_unlock(&space_info->lock);
-
-       flush_state = 0;
-       do {
-               flush_space(fs_info, space_info, to_reclaim,
-                           priority_flush_states[flush_state]);
-               flush_state++;
-               spin_lock(&space_info->lock);
-               if (ticket->bytes == 0) {
-                       spin_unlock(&space_info->lock);
-                       return;
-               }
-               spin_unlock(&space_info->lock);
-       } while (flush_state < ARRAY_SIZE(priority_flush_states));
-}
-
-static int wait_reserve_ticket(struct btrfs_fs_info *fs_info,
-                              struct btrfs_space_info *space_info,
-                              struct reserve_ticket *ticket)
-
-{
-       DEFINE_WAIT(wait);
-       u64 reclaim_bytes = 0;
-       int ret = 0;
-
-       spin_lock(&space_info->lock);
-       while (ticket->bytes > 0 && ticket->error == 0) {
-               ret = prepare_to_wait_event(&ticket->wait, &wait, TASK_KILLABLE);
-               if (ret) {
-                       ret = -EINTR;
-                       break;
-               }
-               spin_unlock(&space_info->lock);
-
-               schedule();
-
-               finish_wait(&ticket->wait, &wait);
-               spin_lock(&space_info->lock);
-       }
-       if (!ret)
-               ret = ticket->error;
-       if (!list_empty(&ticket->list))
-               list_del_init(&ticket->list);
-       if (ticket->bytes && ticket->bytes < ticket->orig_bytes)
-               reclaim_bytes = ticket->orig_bytes - ticket->bytes;
-       spin_unlock(&space_info->lock);
-
-       if (reclaim_bytes)
-               space_info_add_old_bytes(fs_info, space_info, reclaim_bytes);
-       return ret;
-}
-
-/**
- * reserve_metadata_bytes - try to reserve bytes from the block_rsv's space
- * @root - the root we're allocating for
- * @space_info - the space info we want to allocate from
- * @orig_bytes - the number of bytes we want
- * @flush - whether or not we can flush to make our reservation
- *
- * This will reserve orig_bytes number of bytes from the space info associated
- * with the block_rsv.  If there is not enough space it will make an attempt to
- * flush out space to make room.  It will do this by flushing delalloc if
- * possible or committing the transaction.  If flush is 0 then no attempts to
- * regain reservations will be made and this will fail if there is not enough
- * space already.
- */
-static int __reserve_metadata_bytes(struct btrfs_fs_info *fs_info,
-                                   struct btrfs_space_info *space_info,
-                                   u64 orig_bytes,
-                                   enum btrfs_reserve_flush_enum flush,
-                                   bool system_chunk)
-{
-       struct reserve_ticket ticket;
-       u64 used;
-       u64 reclaim_bytes = 0;
-       int ret = 0;
-
-       ASSERT(orig_bytes);
-       ASSERT(!current->journal_info || flush != BTRFS_RESERVE_FLUSH_ALL);
-
-       spin_lock(&space_info->lock);
-       ret = -ENOSPC;
-       used = btrfs_space_info_used(space_info, true);
-
-       /*
-        * If we have enough space then hooray, make our reservation and carry
-        * on.  If not see if we can overcommit, and if we can, hooray carry on.
-        * If not things get more complicated.
-        */
-       if (used + orig_bytes <= space_info->total_bytes) {
-               update_bytes_may_use(space_info, orig_bytes);
-               trace_btrfs_space_reservation(fs_info, "space_info",
-                                             space_info->flags, orig_bytes, 1);
-               ret = 0;
-       } else if (can_overcommit(fs_info, space_info, orig_bytes, flush,
-                                 system_chunk)) {
-               update_bytes_may_use(space_info, orig_bytes);
-               trace_btrfs_space_reservation(fs_info, "space_info",
-                                             space_info->flags, orig_bytes, 1);
-               ret = 0;
-       }
-
-       /*
-        * If we couldn't make a reservation then setup our reservation ticket
-        * and kick the async worker if it's not already running.
-        *
-        * If we are a priority flusher then we just need to add our ticket to
-        * the list and we will do our own flushing further down.
-        */
-       if (ret && flush != BTRFS_RESERVE_NO_FLUSH) {
-               ticket.orig_bytes = orig_bytes;
-               ticket.bytes = orig_bytes;
-               ticket.error = 0;
-               init_waitqueue_head(&ticket.wait);
-               if (flush == BTRFS_RESERVE_FLUSH_ALL) {
-                       list_add_tail(&ticket.list, &space_info->tickets);
-                       if (!space_info->flush) {
-                               space_info->flush = 1;
-                               trace_btrfs_trigger_flush(fs_info,
-                                                         space_info->flags,
-                                                         orig_bytes, flush,
-                                                         "enospc");
-                               queue_work(system_unbound_wq,
-                                          &fs_info->async_reclaim_work);
-                       }
-               } else {
-                       list_add_tail(&ticket.list,
-                                     &space_info->priority_tickets);
-               }
-       } else if (!ret && space_info->flags & BTRFS_BLOCK_GROUP_METADATA) {
-               used += orig_bytes;
-               /*
-                * We will do the space reservation dance during log replay,
-                * which means we won't have fs_info->fs_root set, so don't do
-                * the async reclaim as we will panic.
-                */
-               if (!test_bit(BTRFS_FS_LOG_RECOVERING, &fs_info->flags) &&
-                   need_do_async_reclaim(fs_info, space_info,
-                                         used, system_chunk) &&
-                   !work_busy(&fs_info->async_reclaim_work)) {
-                       trace_btrfs_trigger_flush(fs_info, space_info->flags,
-                                                 orig_bytes, flush, "preempt");
-                       queue_work(system_unbound_wq,
-                                  &fs_info->async_reclaim_work);
-               }
-       }
-       spin_unlock(&space_info->lock);
-       if (!ret || flush == BTRFS_RESERVE_NO_FLUSH)
-               return ret;
-
-       if (flush == BTRFS_RESERVE_FLUSH_ALL)
-               return wait_reserve_ticket(fs_info, space_info, &ticket);
-
-       ret = 0;
-       priority_reclaim_metadata_space(fs_info, space_info, &ticket);
-       spin_lock(&space_info->lock);
-       if (ticket.bytes) {
-               if (ticket.bytes < orig_bytes)
-                       reclaim_bytes = orig_bytes - ticket.bytes;
-               list_del_init(&ticket.list);
-               ret = -ENOSPC;
-       }
-       spin_unlock(&space_info->lock);
-
-       if (reclaim_bytes)
-               space_info_add_old_bytes(fs_info, space_info, reclaim_bytes);
-       ASSERT(list_empty(&ticket.list));
-       return ret;
-}
-
-/**
- * reserve_metadata_bytes - try to reserve bytes from the block_rsv's space
- * @root - the root we're allocating for
- * @block_rsv - the block_rsv we're allocating for
- * @orig_bytes - the number of bytes we want
- * @flush - whether or not we can flush to make our reservation
- *
- * This will reserve orig_bytes number of bytes from the space info associated
- * with the block_rsv.  If there is not enough space it will make an attempt to
- * flush out space to make room.  It will do this by flushing delalloc if
- * possible or committing the transaction.  If flush is 0 then no attempts to
- * regain reservations will be made and this will fail if there is not enough
- * space already.
- */
-static int reserve_metadata_bytes(struct btrfs_root *root,
-                                 struct btrfs_block_rsv *block_rsv,
-                                 u64 orig_bytes,
-                                 enum btrfs_reserve_flush_enum flush)
-{
-       struct btrfs_fs_info *fs_info = root->fs_info;
-       struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
-       int ret;
-       bool system_chunk = (root == fs_info->chunk_root);
-
-       ret = __reserve_metadata_bytes(fs_info, block_rsv->space_info,
-                                      orig_bytes, flush, system_chunk);
-       if (ret == -ENOSPC &&
-           unlikely(root->orphan_cleanup_state == ORPHAN_CLEANUP_STARTED)) {
-               if (block_rsv != global_rsv &&
-                   !block_rsv_use_bytes(global_rsv, orig_bytes))
-                       ret = 0;
-       }
-       if (ret == -ENOSPC) {
-               trace_btrfs_space_reservation(fs_info, "space_info:enospc",
-                                             block_rsv->space_info->flags,
-                                             orig_bytes, 1);
-
-               if (btrfs_test_opt(fs_info, ENOSPC_DEBUG))
-                       dump_space_info(fs_info, block_rsv->space_info,
-                                       orig_bytes, 0);
-       }
-       return ret;
-}
-
-static struct btrfs_block_rsv *get_block_rsv(
-                                       const struct btrfs_trans_handle *trans,
-                                       const struct btrfs_root *root)
-{
-       struct btrfs_fs_info *fs_info = root->fs_info;
-       struct btrfs_block_rsv *block_rsv = NULL;
-
-       if (test_bit(BTRFS_ROOT_REF_COWS, &root->state) ||
-           (root == fs_info->csum_root && trans->adding_csums) ||
-           (root == fs_info->uuid_root))
-               block_rsv = trans->block_rsv;
-
-       if (!block_rsv)
-               block_rsv = root->block_rsv;
-
-       if (!block_rsv)
-               block_rsv = &fs_info->empty_block_rsv;
-
-       return block_rsv;
-}
-
-static int block_rsv_use_bytes(struct btrfs_block_rsv *block_rsv,
-                              u64 num_bytes)
-{
-       int ret = -ENOSPC;
-       spin_lock(&block_rsv->lock);
-       if (block_rsv->reserved >= num_bytes) {
-               block_rsv->reserved -= num_bytes;
-               if (block_rsv->reserved < block_rsv->size)
-                       block_rsv->full = 0;
-               ret = 0;
-       }
-       spin_unlock(&block_rsv->lock);
-       return ret;
-}
-
-static void block_rsv_add_bytes(struct btrfs_block_rsv *block_rsv,
-                               u64 num_bytes, bool update_size)
-{
-       spin_lock(&block_rsv->lock);
-       block_rsv->reserved += num_bytes;
-       if (update_size)
-               block_rsv->size += num_bytes;
-       else if (block_rsv->reserved >= block_rsv->size)
-               block_rsv->full = 1;
-       spin_unlock(&block_rsv->lock);
-}
-
-int btrfs_cond_migrate_bytes(struct btrfs_fs_info *fs_info,
-                            struct btrfs_block_rsv *dest, u64 num_bytes,
-                            int min_factor)
-{
-       struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
-       u64 min_bytes;
-
-       if (global_rsv->space_info != dest->space_info)
-               return -ENOSPC;
-
-       spin_lock(&global_rsv->lock);
-       min_bytes = div_factor(global_rsv->size, min_factor);
-       if (global_rsv->reserved < min_bytes + num_bytes) {
-               spin_unlock(&global_rsv->lock);
-               return -ENOSPC;
-       }
-       global_rsv->reserved -= num_bytes;
-       if (global_rsv->reserved < global_rsv->size)
-               global_rsv->full = 0;
-       spin_unlock(&global_rsv->lock);
-
-       block_rsv_add_bytes(dest, num_bytes, true);
-       return 0;
-}
-
-/**
- * btrfs_migrate_to_delayed_refs_rsv - transfer bytes to our delayed refs rsv.
- * @fs_info - the fs info for our fs.
- * @src - the source block rsv to transfer from.
- * @num_bytes - the number of bytes to transfer.
- *
- * This transfers up to the num_bytes amount from the src rsv to the
- * delayed_refs_rsv.  Any extra bytes are returned to the space info.
- */
-void btrfs_migrate_to_delayed_refs_rsv(struct btrfs_fs_info *fs_info,
-                                      struct btrfs_block_rsv *src,
-                                      u64 num_bytes)
-{
-       struct btrfs_block_rsv *delayed_refs_rsv = &fs_info->delayed_refs_rsv;
-       u64 to_free = 0;
-
-       spin_lock(&src->lock);
-       src->reserved -= num_bytes;
-       src->size -= num_bytes;
-       spin_unlock(&src->lock);
-
-       spin_lock(&delayed_refs_rsv->lock);
-       if (delayed_refs_rsv->size > delayed_refs_rsv->reserved) {
-               u64 delta = delayed_refs_rsv->size -
-                       delayed_refs_rsv->reserved;
-               if (num_bytes > delta) {
-                       to_free = num_bytes - delta;
-                       num_bytes = delta;
-               }
-       } else {
-               to_free = num_bytes;
-               num_bytes = 0;
-       }
-
-       if (num_bytes)
-               delayed_refs_rsv->reserved += num_bytes;
-       if (delayed_refs_rsv->reserved >= delayed_refs_rsv->size)
-               delayed_refs_rsv->full = 1;
-       spin_unlock(&delayed_refs_rsv->lock);
-
-       if (num_bytes)
-               trace_btrfs_space_reservation(fs_info, "delayed_refs_rsv",
-                                             0, num_bytes, 1);
-       if (to_free)
-               space_info_add_old_bytes(fs_info, delayed_refs_rsv->space_info,
-                                        to_free);
-}
-
-/**
- * btrfs_delayed_refs_rsv_refill - refill based on our delayed refs usage.
- * @fs_info - the fs_info for our fs.
- * @flush - control how we can flush for this reservation.
- *
- * This will refill the delayed block_rsv up to 1 items size worth of space and
- * will return -ENOSPC if we can't make the reservation.
- */
-int btrfs_delayed_refs_rsv_refill(struct btrfs_fs_info *fs_info,
-                                 enum btrfs_reserve_flush_enum flush)
-{
-       struct btrfs_block_rsv *block_rsv = &fs_info->delayed_refs_rsv;
-       u64 limit = btrfs_calc_trans_metadata_size(fs_info, 1);
-       u64 num_bytes = 0;
-       int ret = -ENOSPC;
-
-       spin_lock(&block_rsv->lock);
-       if (block_rsv->reserved < block_rsv->size) {
-               num_bytes = block_rsv->size - block_rsv->reserved;
-               num_bytes = min(num_bytes, limit);
-       }
-       spin_unlock(&block_rsv->lock);
-
-       if (!num_bytes)
-               return 0;
-
-       ret = reserve_metadata_bytes(fs_info->extent_root, block_rsv,
-                                    num_bytes, flush);
-       if (ret)
-               return ret;
-       block_rsv_add_bytes(block_rsv, num_bytes, 0);
-       trace_btrfs_space_reservation(fs_info, "delayed_refs_rsv",
-                                     0, num_bytes, 1);
-       return 0;
-}
-
-/*
- * This is for space we already have accounted in space_info->bytes_may_use, so
- * basically when we're returning space from block_rsv's.
- */
-static void space_info_add_old_bytes(struct btrfs_fs_info *fs_info,
-                                    struct btrfs_space_info *space_info,
-                                    u64 num_bytes)
-{
-       struct reserve_ticket *ticket;
-       struct list_head *head;
-       u64 used;
-       enum btrfs_reserve_flush_enum flush = BTRFS_RESERVE_NO_FLUSH;
-       bool check_overcommit = false;
-
-       spin_lock(&space_info->lock);
-       head = &space_info->priority_tickets;
-
-       /*
-        * If we are over our limit then we need to check and see if we can
-        * overcommit, and if we can't then we just need to free up our space
-        * and not satisfy any requests.
-        */
-       used = btrfs_space_info_used(space_info, true);
-       if (used - num_bytes >= space_info->total_bytes)
-               check_overcommit = true;
-again:
-       while (!list_empty(head) && num_bytes) {
-               ticket = list_first_entry(head, struct reserve_ticket,
-                                         list);
-               /*
-                * We use 0 bytes because this space is already reserved, so
-                * adding the ticket space would be a double count.
-                */
-               if (check_overcommit &&
-                   !can_overcommit(fs_info, space_info, 0, flush, false))
-                       break;
-               if (num_bytes >= ticket->bytes) {
-                       list_del_init(&ticket->list);
-                       num_bytes -= ticket->bytes;
-                       ticket->bytes = 0;
-                       space_info->tickets_id++;
-                       wake_up(&ticket->wait);
-               } else {
-                       ticket->bytes -= num_bytes;
-                       num_bytes = 0;
-               }
-       }
-
-       if (num_bytes && head == &space_info->priority_tickets) {
-               head = &space_info->tickets;
-               flush = BTRFS_RESERVE_FLUSH_ALL;
-               goto again;
-       }
-       update_bytes_may_use(space_info, -num_bytes);
-       trace_btrfs_space_reservation(fs_info, "space_info",
-                                     space_info->flags, num_bytes, 0);
-       spin_unlock(&space_info->lock);
-}
-
-/*
- * This is for newly allocated space that isn't accounted in
- * space_info->bytes_may_use yet.  So if we allocate a chunk or unpin an extent
- * we use this helper.
- */
-static void space_info_add_new_bytes(struct btrfs_fs_info *fs_info,
-                                    struct btrfs_space_info *space_info,
-                                    u64 num_bytes)
-{
-       struct reserve_ticket *ticket;
-       struct list_head *head = &space_info->priority_tickets;
-
-again:
-       while (!list_empty(head) && num_bytes) {
-               ticket = list_first_entry(head, struct reserve_ticket,
-                                         list);
-               if (num_bytes >= ticket->bytes) {
-                       trace_btrfs_space_reservation(fs_info, "space_info",
-                                                     space_info->flags,
-                                                     ticket->bytes, 1);
-                       list_del_init(&ticket->list);
-                       num_bytes -= ticket->bytes;
-                       update_bytes_may_use(space_info, ticket->bytes);
-                       ticket->bytes = 0;
-                       space_info->tickets_id++;
-                       wake_up(&ticket->wait);
-               } else {
-                       trace_btrfs_space_reservation(fs_info, "space_info",
-                                                     space_info->flags,
-                                                     num_bytes, 1);
-                       update_bytes_may_use(space_info, num_bytes);
-                       ticket->bytes -= num_bytes;
-                       num_bytes = 0;
-               }
-       }
-
-       if (num_bytes && head == &space_info->priority_tickets) {
-               head = &space_info->tickets;
-               goto again;
-       }
-}
-
-static u64 block_rsv_release_bytes(struct btrfs_fs_info *fs_info,
-                                   struct btrfs_block_rsv *block_rsv,
-                                   struct btrfs_block_rsv *dest, u64 num_bytes,
-                                   u64 *qgroup_to_release_ret)
-{
-       struct btrfs_space_info *space_info = block_rsv->space_info;
-       u64 qgroup_to_release = 0;
-       u64 ret;
-
-       spin_lock(&block_rsv->lock);
-       if (num_bytes == (u64)-1) {
-               num_bytes = block_rsv->size;
-               qgroup_to_release = block_rsv->qgroup_rsv_size;
-       }
-       block_rsv->size -= num_bytes;
-       if (block_rsv->reserved >= block_rsv->size) {
-               num_bytes = block_rsv->reserved - block_rsv->size;
-               block_rsv->reserved = block_rsv->size;
-               block_rsv->full = 1;
-       } else {
-               num_bytes = 0;
-       }
-       if (block_rsv->qgroup_rsv_reserved >= block_rsv->qgroup_rsv_size) {
-               qgroup_to_release = block_rsv->qgroup_rsv_reserved -
-                                   block_rsv->qgroup_rsv_size;
-               block_rsv->qgroup_rsv_reserved = block_rsv->qgroup_rsv_size;
-       } else {
-               qgroup_to_release = 0;
-       }
-       spin_unlock(&block_rsv->lock);
-
-       ret = num_bytes;
-       if (num_bytes > 0) {
-               if (dest) {
-                       spin_lock(&dest->lock);
-                       if (!dest->full) {
-                               u64 bytes_to_add;
-
-                               bytes_to_add = dest->size - dest->reserved;
-                               bytes_to_add = min(num_bytes, bytes_to_add);
-                               dest->reserved += bytes_to_add;
-                               if (dest->reserved >= dest->size)
-                                       dest->full = 1;
-                               num_bytes -= bytes_to_add;
-                       }
-                       spin_unlock(&dest->lock);
-               }
-               if (num_bytes)
-                       space_info_add_old_bytes(fs_info, space_info,
-                                                num_bytes);
-       }
-       if (qgroup_to_release_ret)
-               *qgroup_to_release_ret = qgroup_to_release;
-       return ret;
-}
-
-int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src,
-                           struct btrfs_block_rsv *dst, u64 num_bytes,
-                           bool update_size)
-{
-       int ret;
-
-       ret = block_rsv_use_bytes(src, num_bytes);
-       if (ret)
-               return ret;
-
-       block_rsv_add_bytes(dst, num_bytes, update_size);
-       return 0;
-}
-
-void btrfs_init_block_rsv(struct btrfs_block_rsv *rsv, unsigned short type)
-{
-       memset(rsv, 0, sizeof(*rsv));
-       spin_lock_init(&rsv->lock);
-       rsv->type = type;
-}
-
-void btrfs_init_metadata_block_rsv(struct btrfs_fs_info *fs_info,
-                                  struct btrfs_block_rsv *rsv,
-                                  unsigned short type)
-{
-       btrfs_init_block_rsv(rsv, type);
-       rsv->space_info = __find_space_info(fs_info,
-                                           BTRFS_BLOCK_GROUP_METADATA);
-}
-
-struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_fs_info *fs_info,
-                                             unsigned short type)
-{
-       struct btrfs_block_rsv *block_rsv;
-
-       block_rsv = kmalloc(sizeof(*block_rsv), GFP_NOFS);
-       if (!block_rsv)
-               return NULL;
-
-       btrfs_init_metadata_block_rsv(fs_info, block_rsv, type);
-       return block_rsv;
-}
-
-void btrfs_free_block_rsv(struct btrfs_fs_info *fs_info,
-                         struct btrfs_block_rsv *rsv)
-{
-       if (!rsv)
-               return;
-       btrfs_block_rsv_release(fs_info, rsv, (u64)-1);
-       kfree(rsv);
-}
-
-int btrfs_block_rsv_add(struct btrfs_root *root,
-                       struct btrfs_block_rsv *block_rsv, u64 num_bytes,
-                       enum btrfs_reserve_flush_enum flush)
-{
-       int ret;
-
-       if (num_bytes == 0)
-               return 0;
-
-       ret = reserve_metadata_bytes(root, block_rsv, num_bytes, flush);
-       if (!ret)
-               block_rsv_add_bytes(block_rsv, num_bytes, true);
-
-       return ret;
-}
-
-int btrfs_block_rsv_check(struct btrfs_block_rsv *block_rsv, int min_factor)
-{
-       u64 num_bytes = 0;
-       int ret = -ENOSPC;
-
-       if (!block_rsv)
-               return 0;
-
-       spin_lock(&block_rsv->lock);
-       num_bytes = div_factor(block_rsv->size, min_factor);
-       if (block_rsv->reserved >= num_bytes)
-               ret = 0;
-       spin_unlock(&block_rsv->lock);
-
-       return ret;
-}
-
-int btrfs_block_rsv_refill(struct btrfs_root *root,
-                          struct btrfs_block_rsv *block_rsv, u64 min_reserved,
-                          enum btrfs_reserve_flush_enum flush)
-{
-       u64 num_bytes = 0;
-       int ret = -ENOSPC;
-
-       if (!block_rsv)
-               return 0;
-
-       spin_lock(&block_rsv->lock);
-       num_bytes = min_reserved;
-       if (block_rsv->reserved >= num_bytes)
-               ret = 0;
-       else
-               num_bytes -= block_rsv->reserved;
-       spin_unlock(&block_rsv->lock);
-
-       if (!ret)
-               return 0;
-
-       ret = reserve_metadata_bytes(root, block_rsv, num_bytes, flush);
-       if (!ret) {
-               block_rsv_add_bytes(block_rsv, num_bytes, false);
-               return 0;
-       }
-
-       return ret;
-}
-
-static u64 __btrfs_block_rsv_release(struct btrfs_fs_info *fs_info,
-                                    struct btrfs_block_rsv *block_rsv,
-                                    u64 num_bytes, u64 *qgroup_to_release)
-{
-       struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
-       struct btrfs_block_rsv *delayed_rsv = &fs_info->delayed_refs_rsv;
-       struct btrfs_block_rsv *target = delayed_rsv;
-
-       if (target->full || target == block_rsv)
-               target = global_rsv;
-
-       if (block_rsv->space_info != target->space_info)
-               target = NULL;
-
-       return block_rsv_release_bytes(fs_info, block_rsv, target, num_bytes,
-                                      qgroup_to_release);
-}
-
-void btrfs_block_rsv_release(struct btrfs_fs_info *fs_info,
-                            struct btrfs_block_rsv *block_rsv,
-                            u64 num_bytes)
-{
-       __btrfs_block_rsv_release(fs_info, block_rsv, num_bytes, NULL);
-}
-
-/**
- * btrfs_inode_rsv_release - release any excessive reservation.
- * @inode - the inode we need to release from.
- * @qgroup_free - free or convert qgroup meta.
- *   Unlike normal operation, qgroup meta reservation needs to know if we are
- *   freeing qgroup reservation or just converting it into per-trans.  Normally
- *   @qgroup_free is true for error handling, and false for normal release.
- *
- * This is the same as btrfs_block_rsv_release, except that it handles the
- * tracepoint for the reservation.
- */
-static void btrfs_inode_rsv_release(struct btrfs_inode *inode, bool qgroup_free)
-{
-       struct btrfs_fs_info *fs_info = inode->root->fs_info;
-       struct btrfs_block_rsv *block_rsv = &inode->block_rsv;
-       u64 released = 0;
-       u64 qgroup_to_release = 0;
-
-       /*
-        * Since we statically set the block_rsv->size we just want to say we
-        * are releasing 0 bytes, and then we'll just get the reservation over
-        * the size free'd.
-        */
-       released = __btrfs_block_rsv_release(fs_info, block_rsv, 0,
-                                            &qgroup_to_release);
-       if (released > 0)
-               trace_btrfs_space_reservation(fs_info, "delalloc",
-                                             btrfs_ino(inode), released, 0);
-       if (qgroup_free)
-               btrfs_qgroup_free_meta_prealloc(inode->root, qgroup_to_release);
-       else
-               btrfs_qgroup_convert_reserved_meta(inode->root,
-                                                  qgroup_to_release);
-}
-
-/**
- * btrfs_delayed_refs_rsv_release - release a ref head's reservation.
- * @fs_info - the fs_info for our fs.
- * @nr - the number of items to drop.
- *
- * This drops the delayed ref head's count from the delayed refs rsv and frees
- * any excess reservation we had.
- */
-void btrfs_delayed_refs_rsv_release(struct btrfs_fs_info *fs_info, int nr)
-{
-       struct btrfs_block_rsv *block_rsv = &fs_info->delayed_refs_rsv;
-       struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
-       u64 num_bytes = btrfs_calc_trans_metadata_size(fs_info, nr);
-       u64 released = 0;
-
-       released = block_rsv_release_bytes(fs_info, block_rsv, global_rsv,
-                                          num_bytes, NULL);
-       if (released)
-               trace_btrfs_space_reservation(fs_info, "delayed_refs_rsv",
-                                             0, released, 0);
-}
-
-static void update_global_block_rsv(struct btrfs_fs_info *fs_info)
-{
-       struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
-       struct btrfs_space_info *sinfo = block_rsv->space_info;
-       u64 num_bytes;
-
-       /*
-        * The global block rsv is based on the size of the extent tree, the
-        * checksum tree and the root tree.  If the fs is empty we want to set
-        * it to a minimal amount for safety.
-        */
-       num_bytes = btrfs_root_used(&fs_info->extent_root->root_item) +
-               btrfs_root_used(&fs_info->csum_root->root_item) +
-               btrfs_root_used(&fs_info->tree_root->root_item);
-       num_bytes = max_t(u64, num_bytes, SZ_16M);
-
-       spin_lock(&sinfo->lock);
-       spin_lock(&block_rsv->lock);
-
-       block_rsv->size = min_t(u64, num_bytes, SZ_512M);
-
-       if (block_rsv->reserved < block_rsv->size) {
-               num_bytes = btrfs_space_info_used(sinfo, true);
-               if (sinfo->total_bytes > num_bytes) {
-                       num_bytes = sinfo->total_bytes - num_bytes;
-                       num_bytes = min(num_bytes,
-                                       block_rsv->size - block_rsv->reserved);
-                       block_rsv->reserved += num_bytes;
-                       update_bytes_may_use(sinfo, num_bytes);
-                       trace_btrfs_space_reservation(fs_info, "space_info",
-                                                     sinfo->flags, num_bytes,
-                                                     1);
-               }
-       } else if (block_rsv->reserved > block_rsv->size) {
-               num_bytes = block_rsv->reserved - block_rsv->size;
-               update_bytes_may_use(sinfo, -num_bytes);
-               trace_btrfs_space_reservation(fs_info, "space_info",
-                                     sinfo->flags, num_bytes, 0);
-               block_rsv->reserved = block_rsv->size;
-       }
-
-       if (block_rsv->reserved == block_rsv->size)
-               block_rsv->full = 1;
-       else
-               block_rsv->full = 0;
-
-       spin_unlock(&block_rsv->lock);
-       spin_unlock(&sinfo->lock);
-}
-
-static void init_global_block_rsv(struct btrfs_fs_info *fs_info)
-{
-       struct btrfs_space_info *space_info;
-
-       space_info = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_SYSTEM);
-       fs_info->chunk_block_rsv.space_info = space_info;
-
-       space_info = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA);
-       fs_info->global_block_rsv.space_info = space_info;
-       fs_info->trans_block_rsv.space_info = space_info;
-       fs_info->empty_block_rsv.space_info = space_info;
-       fs_info->delayed_block_rsv.space_info = space_info;
-       fs_info->delayed_refs_rsv.space_info = space_info;
-
-       fs_info->extent_root->block_rsv = &fs_info->delayed_refs_rsv;
-       fs_info->csum_root->block_rsv = &fs_info->delayed_refs_rsv;
-       fs_info->dev_root->block_rsv = &fs_info->global_block_rsv;
-       fs_info->tree_root->block_rsv = &fs_info->global_block_rsv;
-       if (fs_info->quota_root)
-               fs_info->quota_root->block_rsv = &fs_info->global_block_rsv;
-       fs_info->chunk_root->block_rsv = &fs_info->chunk_block_rsv;
-
-       update_global_block_rsv(fs_info);
-}
-
-static void release_global_block_rsv(struct btrfs_fs_info *fs_info)
-{
-       block_rsv_release_bytes(fs_info, &fs_info->global_block_rsv, NULL,
-                               (u64)-1, NULL);
-       WARN_ON(fs_info->trans_block_rsv.size > 0);
-       WARN_ON(fs_info->trans_block_rsv.reserved > 0);
-       WARN_ON(fs_info->chunk_block_rsv.size > 0);
-       WARN_ON(fs_info->chunk_block_rsv.reserved > 0);
-       WARN_ON(fs_info->delayed_block_rsv.size > 0);
-       WARN_ON(fs_info->delayed_block_rsv.reserved > 0);
-       WARN_ON(fs_info->delayed_refs_rsv.reserved > 0);
-       WARN_ON(fs_info->delayed_refs_rsv.size > 0);
-}
-
-/*
- * btrfs_update_delayed_refs_rsv - adjust the size of the delayed refs rsv
- * @trans - the trans that may have generated delayed refs
- *
- * This is to be called anytime we may have adjusted trans->delayed_ref_updates,
- * it'll calculate the additional size and add it to the delayed_refs_rsv.
- */
-void btrfs_update_delayed_refs_rsv(struct btrfs_trans_handle *trans)
-{
-       struct btrfs_fs_info *fs_info = trans->fs_info;
-       struct btrfs_block_rsv *delayed_rsv = &fs_info->delayed_refs_rsv;
-       u64 num_bytes;
-
-       if (!trans->delayed_ref_updates)
-               return;
-
-       num_bytes = btrfs_calc_trans_metadata_size(fs_info,
-                                                  trans->delayed_ref_updates);
-       spin_lock(&delayed_rsv->lock);
-       delayed_rsv->size += num_bytes;
-       delayed_rsv->full = 0;
-       spin_unlock(&delayed_rsv->lock);
-       trans->delayed_ref_updates = 0;
-}
-
-/*
- * To be called after all the new block groups attached to the transaction
- * handle have been created (btrfs_create_pending_block_groups()).
- */
-void btrfs_trans_release_chunk_metadata(struct btrfs_trans_handle *trans)
-{
-       struct btrfs_fs_info *fs_info = trans->fs_info;
-
-       if (!trans->chunk_bytes_reserved)
-               return;
-
-       WARN_ON_ONCE(!list_empty(&trans->new_bgs));
-
-       block_rsv_release_bytes(fs_info, &fs_info->chunk_block_rsv, NULL,
-                               trans->chunk_bytes_reserved, NULL);
-       trans->chunk_bytes_reserved = 0;
-}
-
-/*
- * btrfs_subvolume_reserve_metadata() - reserve space for subvolume operation
- * root: the root of the parent directory
- * rsv: block reservation
- * items: the number of items that we need do reservation
- * use_global_rsv: allow fallback to the global block reservation
- *
- * This function is used to reserve the space for snapshot/subvolume
- * creation and deletion. Those operations are different with the
- * common file/directory operations, they change two fs/file trees
- * and root tree, the number of items that the qgroup reserves is
- * different with the free space reservation. So we can not use
- * the space reservation mechanism in start_transaction().
- */
-int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
-                                    struct btrfs_block_rsv *rsv, int items,
-                                    bool use_global_rsv)
-{
-       u64 qgroup_num_bytes = 0;
-       u64 num_bytes;
-       int ret;
-       struct btrfs_fs_info *fs_info = root->fs_info;
-       struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
-
-       if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) {
-               /* One for parent inode, two for dir entries */
-               qgroup_num_bytes = 3 * fs_info->nodesize;
-               ret = btrfs_qgroup_reserve_meta_prealloc(root,
-                               qgroup_num_bytes, true);
-               if (ret)
-                       return ret;
-       }
-
-       num_bytes = btrfs_calc_trans_metadata_size(fs_info, items);
-       rsv->space_info = __find_space_info(fs_info,
-                                           BTRFS_BLOCK_GROUP_METADATA);
-       ret = btrfs_block_rsv_add(root, rsv, num_bytes,
-                                 BTRFS_RESERVE_FLUSH_ALL);
-
-       if (ret == -ENOSPC && use_global_rsv)
-               ret = btrfs_block_rsv_migrate(global_rsv, rsv, num_bytes, true);
-
-       if (ret && qgroup_num_bytes)
-               btrfs_qgroup_free_meta_prealloc(root, qgroup_num_bytes);
-
-       return ret;
-}
-
-void btrfs_subvolume_release_metadata(struct btrfs_fs_info *fs_info,
-                                     struct btrfs_block_rsv *rsv)
-{
-       btrfs_block_rsv_release(fs_info, rsv, (u64)-1);
-}
-
-static void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info,
-                                                struct btrfs_inode *inode)
-{
-       struct btrfs_block_rsv *block_rsv = &inode->block_rsv;
-       u64 reserve_size = 0;
-       u64 qgroup_rsv_size = 0;
-       u64 csum_leaves;
-       unsigned outstanding_extents;
-
-       lockdep_assert_held(&inode->lock);
-       outstanding_extents = inode->outstanding_extents;
-       if (outstanding_extents)
-               reserve_size = btrfs_calc_trans_metadata_size(fs_info,
-                                               outstanding_extents + 1);
-       csum_leaves = btrfs_csum_bytes_to_leaves(fs_info,
-                                                inode->csum_bytes);
-       reserve_size += btrfs_calc_trans_metadata_size(fs_info,
-                                                      csum_leaves);
-       /*
-        * For qgroup rsv, the calculation is very simple:
-        * account one nodesize for each outstanding extent
-        *
-        * This is overestimating in most cases.
-        */
-       qgroup_rsv_size = (u64)outstanding_extents * fs_info->nodesize;
+               btrfs_info(fs_info, "left=%llu, need=%llu, flags=%llu",
+                          left, thresh, type);
+               btrfs_dump_space_info(fs_info, info, 0, 0);
+       }
 
-       spin_lock(&block_rsv->lock);
-       block_rsv->size = reserve_size;
-       block_rsv->qgroup_rsv_size = qgroup_rsv_size;
-       spin_unlock(&block_rsv->lock);
-}
+       if (left < thresh) {
+               u64 flags = btrfs_system_alloc_profile(fs_info);
 
-static void calc_inode_reservations(struct btrfs_fs_info *fs_info,
-                                   u64 num_bytes, u64 *meta_reserve,
-                                   u64 *qgroup_reserve)
-{
-       u64 nr_extents = count_max_extents(num_bytes);
-       u64 csum_leaves = btrfs_csum_bytes_to_leaves(fs_info, num_bytes);
+               /*
+                * Ignore failure to create system chunk. We might end up not
+                * needing it, as we might not need to COW all nodes/leafs from
+                * the paths we visit in the chunk tree (they were already COWed
+                * or created in the current transaction for example).
+                */
+               ret = btrfs_alloc_chunk(trans, flags);
+       }
 
-       /* We add one for the inode update at finish ordered time */
-       *meta_reserve = btrfs_calc_trans_metadata_size(fs_info,
-                                               nr_extents + csum_leaves + 1);
-       *qgroup_reserve = nr_extents * fs_info->nodesize;
+       if (!ret) {
+               ret = btrfs_block_rsv_add(fs_info->chunk_root,
+                                         &fs_info->chunk_block_rsv,
+                                         thresh, BTRFS_RESERVE_NO_FLUSH);
+               if (!ret)
+                       trans->chunk_bytes_reserved += thresh;
+       }
 }
 
-int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes)
+/*
+ * If force is CHUNK_ALLOC_FORCE:
+ *    - return 1 if it successfully allocates a chunk,
+ *    - return errors including -ENOSPC otherwise.
+ * If force is NOT CHUNK_ALLOC_FORCE:
+ *    - return 0 if it doesn't need to allocate a new chunk,
+ *    - return 1 if it successfully allocates a chunk,
+ *    - return errors including -ENOSPC otherwise.
+ */
+int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags,
+                     enum btrfs_chunk_alloc_enum force)
 {
-       struct btrfs_root *root = inode->root;
-       struct btrfs_fs_info *fs_info = root->fs_info;
-       struct btrfs_block_rsv *block_rsv = &inode->block_rsv;
-       u64 meta_reserve, qgroup_reserve;
-       unsigned nr_extents;
-       enum btrfs_reserve_flush_enum flush = BTRFS_RESERVE_FLUSH_ALL;
+       struct btrfs_fs_info *fs_info = trans->fs_info;
+       struct btrfs_space_info *space_info;
+       bool wait_for_alloc = false;
+       bool should_alloc = false;
        int ret = 0;
-       bool delalloc_lock = true;
 
-       /* If we are a free space inode we need to not flush since we will be in
-        * the middle of a transaction commit.  We also don't need the delalloc
-        * mutex since we won't race with anybody.  We need this mostly to make
-        * lockdep shut its filthy mouth.
-        *
-        * If we have a transaction open (can happen if we call truncate_block
-        * from truncate), then we need FLUSH_LIMIT so we don't deadlock.
-        */
-       if (btrfs_is_free_space_inode(inode)) {
-               flush = BTRFS_RESERVE_NO_FLUSH;
-               delalloc_lock = false;
-       } else {
-               if (current->journal_info)
-                       flush = BTRFS_RESERVE_FLUSH_LIMIT;
+       /* Don't re-enter if we're already allocating a chunk */
+       if (trans->allocating_chunk)
+               return -ENOSPC;
 
-               if (btrfs_transaction_in_commit(fs_info))
-                       schedule_timeout(1);
-       }
+       space_info = btrfs_find_space_info(fs_info, flags);
+       ASSERT(space_info);
+
+       do {
+               spin_lock(&space_info->lock);
+               if (force < space_info->force_alloc)
+                       force = space_info->force_alloc;
+               should_alloc = should_alloc_chunk(fs_info, space_info, force);
+               if (space_info->full) {
+                       /* No more free physical space */
+                       if (should_alloc)
+                               ret = -ENOSPC;
+                       else
+                               ret = 0;
+                       spin_unlock(&space_info->lock);
+                       return ret;
+               } else if (!should_alloc) {
+                       spin_unlock(&space_info->lock);
+                       return 0;
+               } else if (space_info->chunk_alloc) {
+                       /*
+                        * Someone is already allocating, so we need to block
+                        * until this someone is finished and then loop to
+                        * recheck if we should continue with our allocation
+                        * attempt.
+                        */
+                       wait_for_alloc = true;
+                       spin_unlock(&space_info->lock);
+                       mutex_lock(&fs_info->chunk_mutex);
+                       mutex_unlock(&fs_info->chunk_mutex);
+               } else {
+                       /* Proceed with allocation */
+                       space_info->chunk_alloc = 1;
+                       wait_for_alloc = false;
+                       spin_unlock(&space_info->lock);
+               }
 
-       if (delalloc_lock)
-               mutex_lock(&inode->delalloc_mutex);
+               cond_resched();
+       } while (wait_for_alloc);
 
-       num_bytes = ALIGN(num_bytes, fs_info->sectorsize);
+       mutex_lock(&fs_info->chunk_mutex);
+       trans->allocating_chunk = true;
 
        /*
-        * We always want to do it this way, every other way is wrong and ends
-        * in tears.  Pre-reserving the amount we are going to add will always
-        * be the right way, because otherwise if we have enough parallelism we
-        * could end up with thousands of inodes all holding little bits of
-        * reservations they were able to make previously and the only way to
-        * reclaim that space is to ENOSPC out the operations and clear
-        * everything out and try again, which is bad.  This way we just
-        * over-reserve slightly, and clean up the mess when we are done.
+        * If we have mixed data/metadata chunks we want to make sure we keep
+        * allocating mixed chunks instead of individual chunks.
         */
-       calc_inode_reservations(fs_info, num_bytes, &meta_reserve,
-                               &qgroup_reserve);
-       ret = btrfs_qgroup_reserve_meta_prealloc(root, qgroup_reserve, true);
-       if (ret)
-               goto out_fail;
-       ret = reserve_metadata_bytes(root, block_rsv, meta_reserve, flush);
-       if (ret)
-               goto out_qgroup;
+       if (btrfs_mixed_space_info(space_info))
+               flags |= (BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA);
 
        /*
-        * Now we need to update our outstanding extents and csum bytes _first_
-        * and then add the reservation to the block_rsv.  This keeps us from
-        * racing with an ordered completion or some such that would think it
-        * needs to free the reservation we just made.
+        * if we're doing a data chunk, go ahead and make sure that
+        * we keep a reasonable number of metadata chunks allocated in the
+        * FS as well.
         */
-       spin_lock(&inode->lock);
-       nr_extents = count_max_extents(num_bytes);
-       btrfs_mod_outstanding_extents(inode, nr_extents);
-       inode->csum_bytes += num_bytes;
-       btrfs_calculate_inode_block_rsv_size(fs_info, inode);
-       spin_unlock(&inode->lock);
-
-       /* Now we can safely add our space to our block rsv */
-       block_rsv_add_bytes(block_rsv, meta_reserve, false);
-       trace_btrfs_space_reservation(root->fs_info, "delalloc",
-                                     btrfs_ino(inode), meta_reserve, 1);
-
-       spin_lock(&block_rsv->lock);
-       block_rsv->qgroup_rsv_reserved += qgroup_reserve;
-       spin_unlock(&block_rsv->lock);
-
-       if (delalloc_lock)
-               mutex_unlock(&inode->delalloc_mutex);
-       return 0;
-out_qgroup:
-       btrfs_qgroup_free_meta_prealloc(root, qgroup_reserve);
-out_fail:
-       btrfs_inode_rsv_release(inode, true);
-       if (delalloc_lock)
-               mutex_unlock(&inode->delalloc_mutex);
-       return ret;
-}
-
-/**
- * btrfs_delalloc_release_metadata - release a metadata reservation for an inode
- * @inode: the inode to release the reservation for.
- * @num_bytes: the number of bytes we are releasing.
- * @qgroup_free: free qgroup reservation or convert it to per-trans reservation
- *
- * This will release the metadata reservation for an inode.  This can be called
- * once we complete IO for a given set of bytes to release their metadata
- * reservations, or on error for the same reason.
- */
-void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes,
-                                    bool qgroup_free)
-{
-       struct btrfs_fs_info *fs_info = inode->root->fs_info;
-
-       num_bytes = ALIGN(num_bytes, fs_info->sectorsize);
-       spin_lock(&inode->lock);
-       inode->csum_bytes -= num_bytes;
-       btrfs_calculate_inode_block_rsv_size(fs_info, inode);
-       spin_unlock(&inode->lock);
-
-       if (btrfs_is_testing(fs_info))
-               return;
-
-       btrfs_inode_rsv_release(inode, qgroup_free);
-}
-
-/**
- * btrfs_delalloc_release_extents - release our outstanding_extents
- * @inode: the inode to balance the reservation for.
- * @num_bytes: the number of bytes we originally reserved with
- * @qgroup_free: do we need to free qgroup meta reservation or convert them.
- *
- * When we reserve space we increase outstanding_extents for the extents we may
- * add.  Once we've set the range as delalloc or created our ordered extents we
- * have outstanding_extents to track the real usage, so we use this to free our
- * temporarily tracked outstanding_extents.  This _must_ be used in conjunction
- * with btrfs_delalloc_reserve_metadata.
- */
-void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes,
-                                   bool qgroup_free)
-{
-       struct btrfs_fs_info *fs_info = inode->root->fs_info;
-       unsigned num_extents;
+       if (flags & BTRFS_BLOCK_GROUP_DATA && fs_info->metadata_ratio) {
+               fs_info->data_chunk_allocations++;
+               if (!(fs_info->data_chunk_allocations %
+                     fs_info->metadata_ratio))
+                       force_metadata_allocation(fs_info);
+       }
 
-       spin_lock(&inode->lock);
-       num_extents = count_max_extents(num_bytes);
-       btrfs_mod_outstanding_extents(inode, -num_extents);
-       btrfs_calculate_inode_block_rsv_size(fs_info, inode);
-       spin_unlock(&inode->lock);
+       /*
+        * Check if we have enough space in SYSTEM chunk because we may need
+        * to update devices.
+        */
+       check_system_chunk(trans, flags);
 
-       if (btrfs_is_testing(fs_info))
-               return;
+       ret = btrfs_alloc_chunk(trans, flags);
+       trans->allocating_chunk = false;
 
-       btrfs_inode_rsv_release(inode, qgroup_free);
-}
+       spin_lock(&space_info->lock);
+       if (ret < 0) {
+               if (ret == -ENOSPC)
+                       space_info->full = 1;
+               else
+                       goto out;
+       } else {
+               ret = 1;
+               space_info->max_extent_size = 0;
+       }
 
-/**
- * btrfs_delalloc_reserve_space - reserve data and metadata space for
- * delalloc
- * @inode: inode we're writing to
- * @start: start range we are writing to
- * @len: how long the range we are writing to
- * @reserved: mandatory parameter, record actually reserved qgroup ranges of
- *           current reservation.
- *
- * This will do the following things
- *
- * o reserve space in data space info for num bytes
- *   and reserve precious corresponding qgroup space
- *   (Done in check_data_free_space)
- *
- * o reserve space for metadata space, based on the number of outstanding
- *   extents and how much csums will be needed
- *   also reserve metadata space in a per root over-reserve method.
- * o add to the inodes->delalloc_bytes
- * o add it to the fs_info's delalloc inodes list.
- *   (Above 3 all done in delalloc_reserve_metadata)
- *
- * Return 0 for success
- * Return <0 for error(-ENOSPC or -EQUOT)
- */
-int btrfs_delalloc_reserve_space(struct inode *inode,
-                       struct extent_changeset **reserved, u64 start, u64 len)
-{
-       int ret;
+       space_info->force_alloc = CHUNK_ALLOC_NO_FORCE;
+out:
+       space_info->chunk_alloc = 0;
+       spin_unlock(&space_info->lock);
+       mutex_unlock(&fs_info->chunk_mutex);
+       /*
+        * When we allocate a new chunk we reserve space in the chunk block
+        * reserve to make sure we can COW nodes/leafs in the chunk tree or
+        * add new nodes/leafs to it if we end up needing to do it when
+        * inserting the chunk item and updating device items as part of the
+        * second phase of chunk allocation, performed by
+        * btrfs_finish_chunk_alloc(). So make sure we don't accumulate a
+        * large number of new block groups to create in our transaction
+        * handle's new_bgs list to avoid exhausting the chunk block reserve
+        * in extreme cases - like having a single transaction create many new
+        * block groups when starting to write out the free space caches of all
+        * the block groups that were made dirty during the lifetime of the
+        * transaction.
+        */
+       if (trans->chunk_bytes_reserved >= (u64)SZ_2M)
+               btrfs_create_pending_block_groups(trans);
 
-       ret = btrfs_check_data_free_space(inode, reserved, start, len);
-       if (ret < 0)
-               return ret;
-       ret = btrfs_delalloc_reserve_metadata(BTRFS_I(inode), len);
-       if (ret < 0)
-               btrfs_free_reserved_data_space(inode, *reserved, start, len);
        return ret;
 }
 
-/**
- * btrfs_delalloc_release_space - release data and metadata space for delalloc
- * @inode: inode we're releasing space for
- * @start: start position of the space already reserved
- * @len: the len of the space already reserved
- * @release_bytes: the len of the space we consumed or didn't use
- *
- * This function will release the metadata space that was not used and will
- * decrement ->delalloc_bytes and remove it from the fs_info delalloc_inodes
- * list if there are no delalloc bytes left.
- * Also it will handle the qgroup reserved space.
- */
-void btrfs_delalloc_release_space(struct inode *inode,
-                                 struct extent_changeset *reserved,
-                                 u64 start, u64 len, bool qgroup_free)
-{
-       btrfs_delalloc_release_metadata(BTRFS_I(inode), len, qgroup_free);
-       btrfs_free_reserved_data_space(inode, reserved, start, len);
-}
-
 static int update_block_group(struct btrfs_trans_handle *trans,
                              u64 bytenr, u64 num_bytes, int alloc)
 {
@@ -6296,7 +4168,8 @@ static int update_block_group(struct btrfs_trans_handle *trans,
                        old_val -= num_bytes;
                        btrfs_set_block_group_used(&cache->item, old_val);
                        cache->pinned += num_bytes;
-                       update_bytes_pinned(cache->space_info, num_bytes);
+                       btrfs_space_info_update_bytes_pinned(info,
+                                       cache->space_info, num_bytes);
                        cache->space_info->bytes_used -= num_bytes;
                        cache->space_info->disk_used -= num_bytes * factor;
                        spin_unlock(&cache->lock);
@@ -6371,7 +4244,8 @@ static int pin_down_extent(struct btrfs_block_group_cache *cache,
        spin_lock(&cache->space_info->lock);
        spin_lock(&cache->lock);
        cache->pinned += num_bytes;
-       update_bytes_pinned(cache->space_info, num_bytes);
+       btrfs_space_info_update_bytes_pinned(fs_info, cache->space_info,
+                                            num_bytes);
        if (reserved) {
                cache->reserved -= num_bytes;
                cache->space_info->bytes_reserved -= num_bytes;
@@ -6580,7 +4454,8 @@ static int btrfs_add_reserved_bytes(struct btrfs_block_group_cache *cache,
        } else {
                cache->reserved += num_bytes;
                space_info->bytes_reserved += num_bytes;
-               update_bytes_may_use(space_info, -ram_bytes);
+               btrfs_space_info_update_bytes_may_use(cache->fs_info,
+                                                     space_info, -ram_bytes);
                if (delalloc)
                        cache->delalloc_bytes += num_bytes;
        }
@@ -6646,7 +4521,7 @@ void btrfs_prepare_extent_commit(struct btrfs_fs_info *fs_info)
 
        up_write(&fs_info->commit_root_sem);
 
-       update_global_block_rsv(fs_info);
+       btrfs_update_global_block_rsv(fs_info);
 }
 
 /*
@@ -6736,7 +4611,7 @@ static int unpin_extent_range(struct btrfs_fs_info *fs_info,
                spin_lock(&space_info->lock);
                spin_lock(&cache->lock);
                cache->pinned -= len;
-               update_bytes_pinned(space_info, -len);
+               btrfs_space_info_update_bytes_pinned(fs_info, space_info, -len);
 
                trace_btrfs_space_reservation(fs_info, "pinned",
                                              space_info->flags, len, 0);
@@ -6757,7 +4632,8 @@ static int unpin_extent_range(struct btrfs_fs_info *fs_info,
                                to_add = min(len, global_rsv->size -
                                             global_rsv->reserved);
                                global_rsv->reserved += to_add;
-                               update_bytes_may_use(space_info, to_add);
+                               btrfs_space_info_update_bytes_may_use(fs_info,
+                                               space_info, to_add);
                                if (global_rsv->reserved >= global_rsv->size)
                                        global_rsv->full = 1;
                                trace_btrfs_space_reservation(fs_info,
@@ -6769,8 +4645,8 @@ static int unpin_extent_range(struct btrfs_fs_info *fs_info,
                        spin_unlock(&global_rsv->lock);
                        /* Add to any tickets we may have */
                        if (len)
-                               space_info_add_new_bytes(fs_info, space_info,
-                                                        len);
+                               btrfs_space_info_add_new_bytes(fs_info,
+                                               space_info, len);
                }
                spin_unlock(&space_info->lock);
        }
@@ -7191,7 +5067,7 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
        }
 out:
        if (pin)
-               add_pinned_bytes(fs_info, &generic_ref, 1);
+               add_pinned_bytes(fs_info, &generic_ref);
 
        if (last_ref) {
                /*
@@ -7239,7 +5115,7 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_ref *ref)
                btrfs_ref_tree_mod(fs_info, ref);
 
        if (ret == 0 && old_ref_mod >= 0 && new_ref_mod < 0)
-               add_pinned_bytes(fs_info, ref, 1);
+               add_pinned_bytes(fs_info, ref);
 
        return ret;
 }
@@ -7292,10 +5168,10 @@ wait_block_group_cache_done(struct btrfs_block_group_cache *cache)
 }
 
 enum btrfs_loop_type {
-       LOOP_CACHING_NOWAIT = 0,
-       LOOP_CACHING_WAIT = 1,
-       LOOP_ALLOC_CHUNK = 2,
-       LOOP_NO_EMPTY_SIZE = 3,
+       LOOP_CACHING_NOWAIT,
+       LOOP_CACHING_WAIT,
+       LOOP_ALLOC_CHUNK,
+       LOOP_NO_EMPTY_SIZE,
 };
 
 static inline void
@@ -7661,8 +5537,8 @@ static int find_free_extent_update_loop(struct btrfs_fs_info *fs_info,
                                return ret;
                        }
 
-                       ret = do_chunk_alloc(trans, ffe_ctl->flags,
-                                            CHUNK_ALLOC_FORCE);
+                       ret = btrfs_chunk_alloc(trans, ffe_ctl->flags,
+                                               CHUNK_ALLOC_FORCE);
 
                        /*
                         * If we can't allocate a new chunk we've already looped
@@ -7758,7 +5634,7 @@ static noinline int find_free_extent(struct btrfs_fs_info *fs_info,
 
        trace_find_free_extent(fs_info, num_bytes, empty_size, flags);
 
-       space_info = __find_space_info(fs_info, flags);
+       space_info = btrfs_find_space_info(fs_info, flags);
        if (!space_info) {
                btrfs_err(fs_info, "No space info for %llu", flags);
                return -ENOSPC;
@@ -7863,9 +5739,8 @@ search:
                 */
                if (!block_group_bits(block_group, flags)) {
                        u64 extra = BTRFS_BLOCK_GROUP_DUP |
-                               BTRFS_BLOCK_GROUP_RAID1 |
-                               BTRFS_BLOCK_GROUP_RAID5 |
-                               BTRFS_BLOCK_GROUP_RAID6 |
+                               BTRFS_BLOCK_GROUP_RAID1_MASK |
+                               BTRFS_BLOCK_GROUP_RAID56_MASK |
                                BTRFS_BLOCK_GROUP_RAID10;
 
                        /*
@@ -7984,60 +5859,6 @@ loop:
        return ret;
 }
 
-#define DUMP_BLOCK_RSV(fs_info, rsv_name)                              \
-do {                                                                   \
-       struct btrfs_block_rsv *__rsv = &(fs_info)->rsv_name;           \
-       spin_lock(&__rsv->lock);                                        \
-       btrfs_info(fs_info, #rsv_name ": size %llu reserved %llu",      \
-                  __rsv->size, __rsv->reserved);                       \
-       spin_unlock(&__rsv->lock);                                      \
-} while (0)
-
-static void dump_space_info(struct btrfs_fs_info *fs_info,
-                           struct btrfs_space_info *info, u64 bytes,
-                           int dump_block_groups)
-{
-       struct btrfs_block_group_cache *cache;
-       int index = 0;
-
-       spin_lock(&info->lock);
-       btrfs_info(fs_info, "space_info %llu has %llu free, is %sfull",
-                  info->flags,
-                  info->total_bytes - btrfs_space_info_used(info, true),
-                  info->full ? "" : "not ");
-       btrfs_info(fs_info,
-               "space_info total=%llu, used=%llu, pinned=%llu, reserved=%llu, may_use=%llu, readonly=%llu",
-               info->total_bytes, info->bytes_used, info->bytes_pinned,
-               info->bytes_reserved, info->bytes_may_use,
-               info->bytes_readonly);
-       spin_unlock(&info->lock);
-
-       DUMP_BLOCK_RSV(fs_info, global_block_rsv);
-       DUMP_BLOCK_RSV(fs_info, trans_block_rsv);
-       DUMP_BLOCK_RSV(fs_info, chunk_block_rsv);
-       DUMP_BLOCK_RSV(fs_info, delayed_block_rsv);
-       DUMP_BLOCK_RSV(fs_info, delayed_refs_rsv);
-
-       if (!dump_block_groups)
-               return;
-
-       down_read(&info->groups_sem);
-again:
-       list_for_each_entry(cache, &info->block_groups[index], list) {
-               spin_lock(&cache->lock);
-               btrfs_info(fs_info,
-                       "block group %llu has %llu bytes, %llu used %llu pinned %llu reserved %s",
-                       cache->key.objectid, cache->key.offset,
-                       btrfs_block_group_used(&cache->item), cache->pinned,
-                       cache->reserved, cache->ro ? "[readonly]" : "");
-               btrfs_dump_free_space(cache, bytes);
-               spin_unlock(&cache->lock);
-       }
-       if (++index < BTRFS_NR_RAID_TYPES)
-               goto again;
-       up_read(&info->groups_sem);
-}
-
 /*
  * btrfs_reserve_extent - entry point to the extent allocator. Tries to find a
  *                       hole that is at least as big as @num_bytes.
@@ -8113,12 +5934,13 @@ again:
                } else if (btrfs_test_opt(fs_info, ENOSPC_DEBUG)) {
                        struct btrfs_space_info *sinfo;
 
-                       sinfo = __find_space_info(fs_info, flags);
+                       sinfo = btrfs_find_space_info(fs_info, flags);
                        btrfs_err(fs_info,
                                  "allocation failed flags %llu, wanted %llu",
                                  flags, num_bytes);
                        if (sinfo)
-                               dump_space_info(fs_info, sinfo, num_bytes, 1);
+                               btrfs_dump_space_info(fs_info, sinfo,
+                                                     num_bytes, 1);
                }
        }
 
@@ -8456,73 +6278,6 @@ btrfs_init_new_buffer(struct btrfs_trans_handle *trans, struct btrfs_root *root,
        return buf;
 }
 
-static struct btrfs_block_rsv *
-use_block_rsv(struct btrfs_trans_handle *trans,
-             struct btrfs_root *root, u32 blocksize)
-{
-       struct btrfs_fs_info *fs_info = root->fs_info;
-       struct btrfs_block_rsv *block_rsv;
-       struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
-       int ret;
-       bool global_updated = false;
-
-       block_rsv = get_block_rsv(trans, root);
-
-       if (unlikely(block_rsv->size == 0))
-               goto try_reserve;
-again:
-       ret = block_rsv_use_bytes(block_rsv, blocksize);
-       if (!ret)
-               return block_rsv;
-
-       if (block_rsv->failfast)
-               return ERR_PTR(ret);
-
-       if (block_rsv->type == BTRFS_BLOCK_RSV_GLOBAL && !global_updated) {
-               global_updated = true;
-               update_global_block_rsv(fs_info);
-               goto again;
-       }
-
-       /*
-        * The global reserve still exists to save us from ourselves, so don't
-        * warn_on if we are short on our delayed refs reserve.
-        */
-       if (block_rsv->type != BTRFS_BLOCK_RSV_DELREFS &&
-           btrfs_test_opt(fs_info, ENOSPC_DEBUG)) {
-               static DEFINE_RATELIMIT_STATE(_rs,
-                               DEFAULT_RATELIMIT_INTERVAL * 10,
-                               /*DEFAULT_RATELIMIT_BURST*/ 1);
-               if (__ratelimit(&_rs))
-                       WARN(1, KERN_DEBUG
-                               "BTRFS: block rsv returned %d\n", ret);
-       }
-try_reserve:
-       ret = reserve_metadata_bytes(root, block_rsv, blocksize,
-                                    BTRFS_RESERVE_NO_FLUSH);
-       if (!ret)
-               return block_rsv;
-       /*
-        * If we couldn't reserve metadata bytes try and use some from
-        * the global reserve if its space type is the same as the global
-        * reservation.
-        */
-       if (block_rsv->type != BTRFS_BLOCK_RSV_GLOBAL &&
-           block_rsv->space_info == global_rsv->space_info) {
-               ret = block_rsv_use_bytes(global_rsv, blocksize);
-               if (!ret)
-                       return global_rsv;
-       }
-       return ERR_PTR(ret);
-}
-
-static void unuse_block_rsv(struct btrfs_fs_info *fs_info,
-                           struct btrfs_block_rsv *block_rsv, u32 blocksize)
-{
-       block_rsv_add_bytes(block_rsv, blocksize, false);
-       block_rsv_release_bytes(fs_info, block_rsv, NULL, 0, NULL);
-}
-
 /*
  * finds a free extent and does all the dirty work required for allocation
  * returns the tree buffer or an ERR_PTR on error.
@@ -8555,7 +6310,7 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
        }
 #endif
 
-       block_rsv = use_block_rsv(trans, root, blocksize);
+       block_rsv = btrfs_use_block_rsv(trans, root, blocksize);
        if (IS_ERR(block_rsv))
                return ERR_CAST(block_rsv);
 
@@ -8613,7 +6368,7 @@ out_free_buf:
 out_free_reserved:
        btrfs_free_reserved_extent(fs_info, ins.objectid, ins.offset, 0);
 out_unuse:
-       unuse_block_rsv(fs_info, block_rsv, blocksize);
+       btrfs_unuse_block_rsv(fs_info, block_rsv, blocksize);
        return ERR_PTR(ret);
 }
 
@@ -9552,9 +7307,8 @@ static u64 update_block_group_flags(struct btrfs_fs_info *fs_info, u64 flags)
 
        num_devices = fs_info->fs_devices->rw_devices;
 
-       stripped = BTRFS_BLOCK_GROUP_RAID0 |
-               BTRFS_BLOCK_GROUP_RAID5 | BTRFS_BLOCK_GROUP_RAID6 |
-               BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10;
+       stripped = BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID56_MASK |
+               BTRFS_BLOCK_GROUP_RAID1_MASK | BTRFS_BLOCK_GROUP_RAID10;
 
        if (num_devices == 1) {
                stripped |= BTRFS_BLOCK_GROUP_DUP;
@@ -9565,7 +7319,7 @@ static u64 update_block_group_flags(struct btrfs_fs_info *fs_info, u64 flags)
                        return stripped;
 
                /* turn mirroring into duplication */
-               if (flags & (BTRFS_BLOCK_GROUP_RAID1 |
+               if (flags & (BTRFS_BLOCK_GROUP_RAID1_MASK |
                             BTRFS_BLOCK_GROUP_RAID10))
                        return stripped | BTRFS_BLOCK_GROUP_DUP;
        } else {
@@ -9636,7 +7390,7 @@ out:
                btrfs_info(cache->fs_info,
                        "sinfo_used=%llu bg_num_bytes=%llu min_allocable=%llu",
                        sinfo_used, num_bytes, min_allocable_bytes);
-               dump_space_info(cache->fs_info, cache->space_info, 0, 0);
+               btrfs_dump_space_info(cache->fs_info, cache->space_info, 0, 0);
        }
        return ret;
 }
@@ -9678,8 +7432,7 @@ again:
         */
        alloc_flags = update_block_group_flags(fs_info, cache->flags);
        if (alloc_flags != cache->flags) {
-               ret = do_chunk_alloc(trans, alloc_flags,
-                                    CHUNK_ALLOC_FORCE);
+               ret = btrfs_chunk_alloc(trans, alloc_flags, CHUNK_ALLOC_FORCE);
                /*
                 * ENOSPC is allowed here, we may have enough space
                 * already allocated at the new raid level to
@@ -9695,7 +7448,7 @@ again:
        if (!ret)
                goto out;
        alloc_flags = get_alloc_profile(fs_info, cache->space_info->flags);
-       ret = do_chunk_alloc(trans, alloc_flags, CHUNK_ALLOC_FORCE);
+       ret = btrfs_chunk_alloc(trans, alloc_flags, CHUNK_ALLOC_FORCE);
        if (ret < 0)
                goto out;
        ret = inc_block_group_ro(cache, 0);
@@ -9716,7 +7469,7 @@ int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, u64 type)
 {
        u64 alloc_flags = get_alloc_profile(trans->fs_info, type);
 
-       return do_chunk_alloc(trans, alloc_flags, CHUNK_ALLOC_FORCE);
+       return btrfs_chunk_alloc(trans, alloc_flags, CHUNK_ALLOC_FORCE);
 }
 
 /*
@@ -9949,7 +7702,7 @@ static int find_first_block_group(struct btrfs_fs_info *fs_info,
                        struct extent_map_tree *em_tree;
                        struct extent_map *em;
 
-                       em_tree = &root->fs_info->mapping_tree.map_tree;
+                       em_tree = &root->fs_info->mapping_tree;
                        read_lock(&em_tree->lock);
                        em = lookup_extent_mapping(em_tree, found_key.objectid,
                                                   found_key.offset);
@@ -10102,7 +7855,7 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
         */
        synchronize_rcu();
 
-       release_global_block_rsv(info);
+       btrfs_release_global_block_rsv(info);
 
        while (!list_empty(&info->space_info)) {
                int i;
@@ -10118,7 +7871,7 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
                if (WARN_ON(space_info->bytes_pinned > 0 ||
                            space_info->bytes_reserved > 0 ||
                            space_info->bytes_may_use > 0))
-                       dump_space_info(info, space_info, 0, 0);
+                       btrfs_dump_space_info(info, space_info, 0, 0);
                list_del(&space_info->list);
                for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) {
                        struct kobject *kobj;
@@ -10141,7 +7894,6 @@ void btrfs_add_raid_kobjects(struct btrfs_fs_info *fs_info)
        struct btrfs_space_info *space_info;
        struct raid_kobject *rkobj;
        LIST_HEAD(list);
-       int index;
        int ret = 0;
 
        spin_lock(&fs_info->pending_raid_kobjs_lock);
@@ -10149,11 +7901,10 @@ void btrfs_add_raid_kobjects(struct btrfs_fs_info *fs_info)
        spin_unlock(&fs_info->pending_raid_kobjs_lock);
 
        list_for_each_entry(rkobj, &list, list) {
-               space_info = __find_space_info(fs_info, rkobj->flags);
-               index = btrfs_bg_flags_to_raid_index(rkobj->flags);
+               space_info = btrfs_find_space_info(fs_info, rkobj->flags);
 
                ret = kobject_add(&rkobj->kobj, &space_info->kobj,
-                                 "%s", get_raid_name(index));
+                               "%s", btrfs_bg_type_to_raid_name(rkobj->flags));
                if (ret) {
                        kobject_put(&rkobj->kobj);
                        break;
@@ -10243,21 +7994,21 @@ btrfs_create_block_group_cache(struct btrfs_fs_info *fs_info,
  */
 static int check_chunk_block_group_mappings(struct btrfs_fs_info *fs_info)
 {
-       struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
+       struct extent_map_tree *map_tree = &fs_info->mapping_tree;
        struct extent_map *em;
        struct btrfs_block_group_cache *bg;
        u64 start = 0;
        int ret = 0;
 
        while (1) {
-               read_lock(&map_tree->map_tree.lock);
+               read_lock(&map_tree->lock);
                /*
                 * lookup_extent_mapping will return the first extent map
                 * intersecting the range, so setting @len to 1 is enough to
                 * get the first chunk.
                 */
-               em = lookup_extent_mapping(&map_tree->map_tree, start, 1);
-               read_unlock(&map_tree->map_tree.lock);
+               em = lookup_extent_mapping(map_tree, start, 1);
+               read_unlock(&map_tree->lock);
                if (!em)
                        break;
 
@@ -10417,9 +8168,9 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info)
                }
 
                trace_btrfs_add_block_group(info, cache, 0);
-               update_space_info(info, cache->flags, found_key.offset,
-                                 btrfs_block_group_used(&cache->item),
-                                 cache->bytes_super, &space_info);
+               btrfs_update_space_info(info, cache->flags, found_key.offset,
+                                       btrfs_block_group_used(&cache->item),
+                                       cache->bytes_super, &space_info);
 
                cache->space_info = space_info;
 
@@ -10437,9 +8188,8 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info)
        list_for_each_entry_rcu(space_info, &info->space_info, list) {
                if (!(get_alloc_profile(info, space_info->flags) &
                      (BTRFS_BLOCK_GROUP_RAID10 |
-                      BTRFS_BLOCK_GROUP_RAID1 |
-                      BTRFS_BLOCK_GROUP_RAID5 |
-                      BTRFS_BLOCK_GROUP_RAID6 |
+                      BTRFS_BLOCK_GROUP_RAID1_MASK |
+                      BTRFS_BLOCK_GROUP_RAID56_MASK |
                       BTRFS_BLOCK_GROUP_DUP)))
                        continue;
                /*
@@ -10457,7 +8207,7 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info)
        }
 
        btrfs_add_raid_kobjects(info);
-       init_global_block_rsv(info);
+       btrfs_init_global_block_rsv(info);
        ret = check_chunk_block_group_mappings(info);
 error:
        btrfs_free_path(path);
@@ -10554,7 +8304,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, u64 bytes_used,
         * assigned to our block group. We want our bg to be added to the rbtree
         * with its ->space_info set.
         */
-       cache->space_info = __find_space_info(fs_info, cache->flags);
+       cache->space_info = btrfs_find_space_info(fs_info, cache->flags);
        ASSERT(cache->space_info);
 
        ret = btrfs_add_block_group_cache(fs_info, cache);
@@ -10569,9 +8319,9 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, u64 bytes_used,
         * the rbtree, update the space info's counters.
         */
        trace_btrfs_add_block_group(fs_info, cache, 1);
-       update_space_info(fs_info, cache->flags, size, bytes_used,
+       btrfs_update_space_info(fs_info, cache->flags, size, bytes_used,
                                cache->bytes_super, &cache->space_info);
-       update_global_block_rsv(fs_info);
+       btrfs_update_global_block_rsv(fs_info);
 
        link_block_group(cache);
 
@@ -10598,6 +8348,35 @@ static void clear_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
        write_sequnlock(&fs_info->profiles_lock);
 }
 
+/*
+ * Clear incompat bits for the following feature(s):
+ *
+ * - RAID56 - in case there's neither RAID5 nor RAID6 profile block group
+ *            in the whole filesystem
+ */
+static void clear_incompat_bg_bits(struct btrfs_fs_info *fs_info, u64 flags)
+{
+       if (flags & BTRFS_BLOCK_GROUP_RAID56_MASK) {
+               struct list_head *head = &fs_info->space_info;
+               struct btrfs_space_info *sinfo;
+
+               list_for_each_entry_rcu(sinfo, head, list) {
+                       bool found = false;
+
+                       down_read(&sinfo->groups_sem);
+                       if (!list_empty(&sinfo->block_groups[BTRFS_RAID_RAID5]))
+                               found = true;
+                       if (!list_empty(&sinfo->block_groups[BTRFS_RAID_RAID6]))
+                               found = true;
+                       up_read(&sinfo->groups_sem);
+
+                       if (found)
+                               return;
+               }
+               btrfs_clear_fs_incompat(fs_info, RAID56);
+       }
+}
+
 int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
                             u64 group_start, struct extent_map *em)
 {
@@ -10744,6 +8523,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
                clear_avail_alloc_bits(fs_info, block_group->flags);
        }
        up_write(&block_group->space_info->groups_sem);
+       clear_incompat_bg_bits(fs_info, block_group->flags);
        if (kobj) {
                kobject_del(kobj);
                kobject_put(kobj);
@@ -10853,7 +8633,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
        if (remove_em) {
                struct extent_map_tree *em_tree;
 
-               em_tree = &fs_info->mapping_tree.map_tree;
+               em_tree = &fs_info->mapping_tree;
                write_lock(&em_tree->lock);
                remove_extent_mapping(em_tree, em);
                write_unlock(&em_tree->lock);
@@ -10871,7 +8651,7 @@ struct btrfs_trans_handle *
 btrfs_start_trans_remove_block_group(struct btrfs_fs_info *fs_info,
                                     const u64 chunk_offset)
 {
-       struct extent_map_tree *em_tree = &fs_info->mapping_tree.map_tree;
+       struct extent_map_tree *em_tree = &fs_info->mapping_tree;
        struct extent_map *em;
        struct map_lookup *map;
        unsigned int num_items;
@@ -11020,7 +8800,8 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
                spin_lock(&space_info->lock);
                spin_lock(&block_group->lock);
 
-               update_bytes_pinned(space_info, -block_group->pinned);
+               btrfs_space_info_update_bytes_pinned(fs_info, space_info,
+                                                    -block_group->pinned);
                space_info->bytes_readonly += block_group->pinned;
                percpu_counter_add_batch(&space_info->total_bytes_pinned,
                                   -block_group->pinned,
@@ -11076,43 +8857,6 @@ next:
        spin_unlock(&fs_info->unused_bgs_lock);
 }
 
-int btrfs_init_space_info(struct btrfs_fs_info *fs_info)
-{
-       struct btrfs_super_block *disk_super;
-       u64 features;
-       u64 flags;
-       int mixed = 0;
-       int ret;
-
-       disk_super = fs_info->super_copy;
-       if (!btrfs_super_root(disk_super))
-               return -EINVAL;
-
-       features = btrfs_super_incompat_flags(disk_super);
-       if (features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS)
-               mixed = 1;
-
-       flags = BTRFS_BLOCK_GROUP_SYSTEM;
-       ret = create_space_info(fs_info, flags);
-       if (ret)
-               goto out;
-
-       if (mixed) {
-               flags = BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA;
-               ret = create_space_info(fs_info, flags);
-       } else {
-               flags = BTRFS_BLOCK_GROUP_METADATA;
-               ret = create_space_info(fs_info, flags);
-               if (ret)
-                       goto out;
-
-               flags = BTRFS_BLOCK_GROUP_DATA;
-               ret = create_space_info(fs_info, flags);
-       }
-out:
-       return ret;
-}
-
 int btrfs_error_unpin_extent_range(struct btrfs_fs_info *fs_info,
                                   u64 start, u64 end)
 {
@@ -11171,12 +8915,17 @@ static int btrfs_trim_free_extents(struct btrfs_device *device, u64 *trimmed)
                find_first_clear_extent_bit(&device->alloc_state, start,
                                            &start, &end,
                                            CHUNK_TRIMMED | CHUNK_ALLOCATED);
+
+               /* Ensure we skip the reserved area in the first 1M */
+               start = max_t(u64, start, SZ_1M);
+
                /*
                 * If find_first_clear_extent_bit find a range that spans the
                 * end of the device it will set end to -1, in this case it's up
                 * to the caller to trim the value to the size of the device.
                 */
                end = min(end, device->total_bytes - 1);
+
                len = end - start + 1;
 
                /* We didn't find any extents */
index 5106008..1ff438f 100644 (file)
@@ -359,6 +359,24 @@ do_insert:
        return NULL;
 }
 
+/**
+ * __etree_search - searche @tree for an entry that contains @offset. Such
+ * entry would have entry->start <= offset && entry->end >= offset.
+ *
+ * @tree - the tree to search
+ * @offset - offset that should fall within an entry in @tree
+ * @next_ret - pointer to the first entry whose range ends after @offset
+ * @prev - pointer to the first entry whose range begins before @offset
+ * @p_ret - pointer where new node should be anchored (used when inserting an
+ *         entry in the tree)
+ * @parent_ret - points to entry which would have been the parent of the entry,
+ *               containing @offset
+ *
+ * This function returns a pointer to the entry that contains @offset byte
+ * address. If no such entry exists, then NULL is returned and the other
+ * pointer arguments to the function are filled, otherwise the found entry is
+ * returned and other pointers are left untouched.
+ */
 static struct rb_node *__etree_search(struct extent_io_tree *tree, u64 offset,
                                      struct rb_node **next_ret,
                                      struct rb_node **prev_ret,
@@ -504,9 +522,11 @@ static int insert_state(struct extent_io_tree *tree,
 {
        struct rb_node *node;
 
-       if (end < start)
-               WARN(1, KERN_ERR "BTRFS: end < start %llu %llu\n",
-                      end, start);
+       if (end < start) {
+               btrfs_err(tree->fs_info,
+                       "insert state: end < start %llu %llu", end, start);
+               WARN_ON(1);
+       }
        state->start = start;
        state->end = end;
 
@@ -516,7 +536,8 @@ static int insert_state(struct extent_io_tree *tree,
        if (node) {
                struct extent_state *found;
                found = rb_entry(node, struct extent_state, rb_node);
-               pr_err("BTRFS: found node %llu %llu on insert of %llu %llu\n",
+               btrfs_err(tree->fs_info,
+                      "found node %llu %llu on insert of %llu %llu",
                       found->start, found->end, start, end);
                return -EEXIST;
        }
@@ -1537,8 +1558,8 @@ out:
 }
 
 /**
- * find_first_clear_extent_bit - finds the first range that has @bits not set
- * and that starts after @start
+ * find_first_clear_extent_bit - find the first range that has @bits not set.
+ * This range could start before @start.
  *
  * @tree - the tree to search
  * @start - the offset at/after which the found extent should start
@@ -1578,12 +1599,52 @@ void find_first_clear_extent_bit(struct extent_io_tree *tree, u64 start,
                                goto out;
                        }
                }
+               /*
+                * At this point 'node' either contains 'start' or start is
+                * before 'node'
+                */
                state = rb_entry(node, struct extent_state, rb_node);
-               if (in_range(start, state->start, state->end - state->start + 1) &&
-                       (state->state & bits)) {
-                       start = state->end + 1;
+
+               if (in_range(start, state->start, state->end - state->start + 1)) {
+                       if (state->state & bits) {
+                               /*
+                                * |--range with bits sets--|
+                                *    |
+                                *    start
+                                */
+                               start = state->end + 1;
+                       } else {
+                               /*
+                                * 'start' falls within a range that doesn't
+                                * have the bits set, so take its start as
+                                * the beginning of the desired range
+                                *
+                                * |--range with bits cleared----|
+                                *      |
+                                *      start
+                                */
+                               *start_ret = state->start;
+                               break;
+                       }
                } else {
-                       *start_ret = start;
+                       /*
+                        * |---prev range---|---hole/unset---|---node range---|
+                        *                          |
+                        *                        start
+                        *
+                        *                        or
+                        *
+                        * |---hole/unset--||--first node--|
+                        * 0   |
+                        *    start
+                        */
+                       if (prev) {
+                               state = rb_entry(prev, struct extent_state,
+                                                rb_node);
+                               *start_ret = state->end + 1;
+                       } else {
+                               *start_ret = 0;
+                       }
                        break;
                }
        }
@@ -1719,10 +1780,10 @@ static noinline int lock_delalloc_pages(struct inode *inode,
  */
 EXPORT_FOR_TESTS
 noinline_for_stack bool find_lock_delalloc_range(struct inode *inode,
-                                   struct extent_io_tree *tree,
                                    struct page *locked_page, u64 *start,
                                    u64 *end)
 {
+       struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree;
        u64 max_bytes = BTRFS_MAX_EXTENT_SIZE;
        u64 delalloc_start;
        u64 delalloc_end;
@@ -2800,12 +2861,11 @@ static inline void btrfs_io_bio_init(struct btrfs_io_bio *btrfs_bio)
  * never fail.  We're returning a bio right now but you can call btrfs_io_bio
  * for the appropriate container_of magic
  */
-struct bio *btrfs_bio_alloc(struct block_device *bdev, u64 first_byte)
+struct bio *btrfs_bio_alloc(u64 first_byte)
 {
        struct bio *bio;
 
        bio = bio_alloc_bioset(GFP_NOFS, BIO_MAX_PAGES, &btrfs_bioset);
-       bio_set_dev(bio, bdev);
        bio->bi_iter.bi_sector = first_byte >> 9;
        btrfs_io_bio_init(btrfs_io_bio(bio));
        return bio;
@@ -2916,7 +2976,8 @@ static int submit_extent_page(unsigned int opf, struct extent_io_tree *tree,
                }
        }
 
-       bio = btrfs_bio_alloc(bdev, offset);
+       bio = btrfs_bio_alloc(offset);
+       bio_set_dev(bio, bdev);
        bio_add_page(bio, page, page_size, pg_offset);
        bio->bi_end_io = end_io_func;
        bio->bi_private = tree;
@@ -3204,21 +3265,10 @@ static inline void contiguous_readpages(struct extent_io_tree *tree,
                                             unsigned long *bio_flags,
                                             u64 *prev_em_start)
 {
-       struct inode *inode;
-       struct btrfs_ordered_extent *ordered;
+       struct btrfs_inode *inode = BTRFS_I(pages[0]->mapping->host);
        int index;
 
-       inode = pages[0]->mapping->host;
-       while (1) {
-               lock_extent(tree, start, end);
-               ordered = btrfs_lookup_ordered_range(BTRFS_I(inode), start,
-                                                    end - start + 1);
-               if (!ordered)
-                       break;
-               unlock_extent(tree, start, end);
-               btrfs_start_ordered_extent(inode, ordered, 1);
-               btrfs_put_ordered_extent(ordered);
-       }
+       btrfs_lock_and_flush_ordered_range(tree, inode, start, end, NULL);
 
        for (index = 0; index < nr_pages; index++) {
                __do_readpage(tree, pages[index], btrfs_get_extent, em_cached,
@@ -3234,22 +3284,12 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
                                   unsigned long *bio_flags,
                                   unsigned int read_flags)
 {
-       struct inode *inode = page->mapping->host;
-       struct btrfs_ordered_extent *ordered;
+       struct btrfs_inode *inode = BTRFS_I(page->mapping->host);
        u64 start = page_offset(page);
        u64 end = start + PAGE_SIZE - 1;
        int ret;
 
-       while (1) {
-               lock_extent(tree, start, end);
-               ordered = btrfs_lookup_ordered_range(BTRFS_I(inode), start,
-                                               PAGE_SIZE);
-               if (!ordered)
-                       break;
-               unlock_extent(tree, start, end);
-               btrfs_start_ordered_extent(inode, ordered, 1);
-               btrfs_put_ordered_extent(ordered);
-       }
+       btrfs_lock_and_flush_ordered_range(tree, inode, start, end, NULL);
 
        ret = __do_readpage(tree, page, get_extent, NULL, bio, mirror_num,
                            bio_flags, read_flags, NULL);
@@ -3290,7 +3330,6 @@ static noinline_for_stack int writepage_delalloc(struct inode *inode,
                struct page *page, struct writeback_control *wbc,
                u64 delalloc_start, unsigned long *nr_written)
 {
-       struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree;
        u64 page_end = delalloc_start + PAGE_SIZE - 1;
        bool found;
        u64 delalloc_to_write = 0;
@@ -3300,8 +3339,7 @@ static noinline_for_stack int writepage_delalloc(struct inode *inode,
 
 
        while (delalloc_end < page_end) {
-               found = find_lock_delalloc_range(inode, tree,
-                                              page,
+               found = find_lock_delalloc_range(inode, page,
                                               &delalloc_start,
                                               &delalloc_end);
                if (!found) {
@@ -3310,7 +3348,6 @@ static noinline_for_stack int writepage_delalloc(struct inode *inode,
                }
                ret = btrfs_run_delalloc_range(inode, page, delalloc_start,
                                delalloc_end, &page_started, nr_written, wbc);
-               /* File system has been set read-only */
                if (ret) {
                        SetPageError(page);
                        /*
@@ -4542,6 +4579,8 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
        struct btrfs_path *path;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct fiemap_cache cache = { 0 };
+       struct ulist *roots;
+       struct ulist *tmp_ulist;
        int end = 0;
        u64 em_start = 0;
        u64 em_len = 0;
@@ -4555,6 +4594,13 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                return -ENOMEM;
        path->leave_spinning = 1;
 
+       roots = ulist_alloc(GFP_KERNEL);
+       tmp_ulist = ulist_alloc(GFP_KERNEL);
+       if (!roots || !tmp_ulist) {
+               ret = -ENOMEM;
+               goto out_free_ulist;
+       }
+
        start = round_down(start, btrfs_inode_sectorsize(inode));
        len = round_up(max, btrfs_inode_sectorsize(inode)) - start;
 
@@ -4565,8 +4611,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
        ret = btrfs_lookup_file_extent(NULL, root, path,
                        btrfs_ino(BTRFS_I(inode)), -1, 0);
        if (ret < 0) {
-               btrfs_free_path(path);
-               return ret;
+               goto out_free_ulist;
        } else {
                WARN_ON(!ret);
                if (ret == 1)
@@ -4675,7 +4720,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                         */
                        ret = btrfs_check_shared(root,
                                                 btrfs_ino(BTRFS_I(inode)),
-                                                bytenr);
+                                                bytenr, roots, tmp_ulist);
                        if (ret < 0)
                                goto out_free;
                        if (ret)
@@ -4718,9 +4763,13 @@ out_free:
                ret = emit_last_fiemap_cache(fieinfo, &cache);
        free_extent_map(em);
 out:
-       btrfs_free_path(path);
        unlock_extent_cached(&BTRFS_I(inode)->io_tree, start, start + len - 1,
                             &cached_state);
+
+out_free_ulist:
+       btrfs_free_path(path);
+       ulist_free(roots);
+       ulist_free(tmp_ulist);
        return ret;
 }
 
@@ -4808,7 +4857,7 @@ __alloc_extent_buffer(struct btrfs_fs_info *fs_info, u64 start,
        eb->bflags = 0;
        rwlock_init(&eb->lock);
        atomic_set(&eb->blocking_readers, 0);
-       atomic_set(&eb->blocking_writers, 0);
+       eb->blocking_writers = 0;
        eb->lock_nested = false;
        init_waitqueue_head(&eb->write_lock_wq);
        init_waitqueue_head(&eb->read_lock_wq);
@@ -4827,10 +4876,10 @@ __alloc_extent_buffer(struct btrfs_fs_info *fs_info, u64 start,
        BUG_ON(len > MAX_INLINE_EXTENT_BUFFER_SIZE);
 
 #ifdef CONFIG_BTRFS_DEBUG
-       atomic_set(&eb->spinning_writers, 0);
+       eb->spinning_writers = 0;
        atomic_set(&eb->spinning_readers, 0);
        atomic_set(&eb->read_locks, 0);
-       atomic_set(&eb->write_locks, 0);
+       eb->write_locks = 0;
 #endif
 
        return eb;
index aa18a16..401423b 100644 (file)
@@ -167,7 +167,7 @@ struct extent_buffer {
        struct rcu_head rcu_head;
        pid_t lock_owner;
 
-       atomic_t blocking_writers;
+       int blocking_writers;
        atomic_t blocking_readers;
        bool lock_nested;
        /* >= 0 if eb belongs to a log tree, -1 otherwise */
@@ -187,10 +187,10 @@ struct extent_buffer {
        wait_queue_head_t read_lock_wq;
        struct page *pages[INLINE_EXTENT_BUFFER_PAGES];
 #ifdef CONFIG_BTRFS_DEBUG
-       atomic_t spinning_writers;
+       int spinning_writers;
        atomic_t spinning_readers;
        atomic_t read_locks;
-       atomic_t write_locks;
+       int write_locks;
        struct list_head leak_list;
 #endif
 };
@@ -497,7 +497,7 @@ void extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end,
                                 u64 delalloc_end, struct page *locked_page,
                                 unsigned bits_to_clear,
                                 unsigned long page_ops);
-struct bio *btrfs_bio_alloc(struct block_device *bdev, u64 first_byte);
+struct bio *btrfs_bio_alloc(u64 first_byte);
 struct bio *btrfs_io_bio_alloc(unsigned int nr_iovecs);
 struct bio *btrfs_bio_clone(struct bio *bio);
 struct bio *btrfs_bio_clone_partial(struct bio *orig, int offset, int size);
@@ -549,7 +549,7 @@ int free_io_failure(struct extent_io_tree *failure_tree,
                    struct extent_io_tree *io_tree,
                    struct io_failure_record *rec);
 #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
-bool find_lock_delalloc_range(struct inode *inode, struct extent_io_tree *tree,
+bool find_lock_delalloc_range(struct inode *inode,
                             struct page *locked_page, u64 *start,
                             u64 *end);
 #endif
index d431ea8..1a599f5 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/pagemap.h>
 #include <linux/highmem.h>
 #include <linux/sched/mm.h>
+#include <crypto/hash.h>
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
 #define MAX_CSUM_ITEMS(r, size) (min_t(u32, __MAX_CSUM_ITEMS(r, size), \
                                       PAGE_SIZE))
 
-#define MAX_ORDERED_SUM_BYTES(fs_info) ((PAGE_SIZE - \
-                                  sizeof(struct btrfs_ordered_sum)) / \
-                                  sizeof(u32) * (fs_info)->sectorsize)
+static inline u32 max_ordered_sum_bytes(struct btrfs_fs_info *fs_info,
+                                       u16 csum_size)
+{
+       u32 ncsums = (PAGE_SIZE - sizeof(struct btrfs_ordered_sum)) / csum_size;
+
+       return ncsums * fs_info->sectorsize;
+}
 
 int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root,
@@ -144,7 +149,7 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
 }
 
 static blk_status_t __btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio,
-                                  u64 logical_offset, u32 *dst, int dio)
+                                  u64 logical_offset, u8 *dst, int dio)
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
        struct bio_vec bvec;
@@ -182,7 +187,7 @@ static blk_status_t __btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio
                }
                csum = btrfs_bio->csum;
        } else {
-               csum = (u8 *)dst;
+               csum = dst;
        }
 
        if (bio->bi_iter.bi_size > PAGE_SIZE * 8)
@@ -211,7 +216,7 @@ static blk_status_t __btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio
                if (!dio)
                        offset = page_offset(bvec.bv_page) + bvec.bv_offset;
                count = btrfs_find_ordered_sum(inode, offset, disk_bytenr,
-                                              (u32 *)csum, nblocks);
+                                              csum, nblocks);
                if (count)
                        goto found;
 
@@ -283,7 +288,8 @@ next:
        return 0;
 }
 
-blk_status_t btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio, u32 *dst)
+blk_status_t btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio,
+                                  u8 *dst)
 {
        return __btrfs_lookup_bio_sums(inode, bio, 0, dst, 0);
 }
@@ -374,7 +380,7 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
                                      struct btrfs_csum_item);
                while (start < csum_end) {
                        size = min_t(size_t, csum_end - start,
-                                    MAX_ORDERED_SUM_BYTES(fs_info));
+                                    max_ordered_sum_bytes(fs_info, csum_size));
                        sums = kzalloc(btrfs_ordered_sum_size(fs_info, size),
                                       GFP_NOFS);
                        if (!sums) {
@@ -427,6 +433,7 @@ blk_status_t btrfs_csum_one_bio(struct inode *inode, struct bio *bio,
                       u64 file_start, int contig)
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+       SHASH_DESC_ON_STACK(shash, fs_info->csum_shash);
        struct btrfs_ordered_sum *sums;
        struct btrfs_ordered_extent *ordered = NULL;
        char *data;
@@ -439,6 +446,7 @@ blk_status_t btrfs_csum_one_bio(struct inode *inode, struct bio *bio,
        int i;
        u64 offset;
        unsigned nofs_flag;
+       const u16 csum_size = btrfs_super_csum_size(fs_info->super_copy);
 
        nofs_flag = memalloc_nofs_save();
        sums = kvzalloc(btrfs_ordered_sum_size(fs_info, bio->bi_iter.bi_size),
@@ -459,6 +467,8 @@ blk_status_t btrfs_csum_one_bio(struct inode *inode, struct bio *bio,
        sums->bytenr = (u64)bio->bi_iter.bi_sector << 9;
        index = 0;
 
+       shash->tfm = fs_info->csum_shash;
+
        bio_for_each_segment(bvec, bio, iter) {
                if (!contig)
                        offset = page_offset(bvec.bv_page) + bvec.bv_offset;
@@ -498,17 +508,14 @@ blk_status_t btrfs_csum_one_bio(struct inode *inode, struct bio *bio,
                                index = 0;
                        }
 
-                       sums->sums[index] = ~(u32)0;
+                       crypto_shash_init(shash);
                        data = kmap_atomic(bvec.bv_page);
-                       sums->sums[index]
-                               = btrfs_csum_data(data + bvec.bv_offset
-                                               + (i * fs_info->sectorsize),
-                                               sums->sums[index],
-                                               fs_info->sectorsize);
+                       crypto_shash_update(shash, data + bvec.bv_offset
+                                           + (i * fs_info->sectorsize),
+                                           fs_info->sectorsize);
                        kunmap_atomic(data);
-                       btrfs_csum_final(sums->sums[index],
-                                       (char *)(sums->sums + index));
-                       index++;
+                       crypto_shash_final(shash, (char *)(sums->sums + index));
+                       index += csum_size;
                        offset += fs_info->sectorsize;
                        this_sum_bytes += fs_info->sectorsize;
                        total_bytes += fs_info->sectorsize;
@@ -904,9 +911,9 @@ found:
        write_extent_buffer(leaf, sums->sums + index, (unsigned long)item,
                            ins_size);
 
+       index += ins_size;
        ins_size /= csum_size;
        total_bytes += ins_size * fs_info->sectorsize;
-       index += ins_size;
 
        btrfs_mark_buffer_dirty(path->nodes[0]);
        if (total_bytes < sums->len) {
index 89f5be2..58a18ed 100644 (file)
@@ -26,6 +26,7 @@
 #include "volumes.h"
 #include "qgroup.h"
 #include "compression.h"
+#include "delalloc-space.h"
 
 static struct kmem_cache *btrfs_inode_defrag_cachep;
 /*
@@ -1550,30 +1551,20 @@ static noinline int check_can_nocow(struct btrfs_inode *inode, loff_t pos,
 {
        struct btrfs_fs_info *fs_info = inode->root->fs_info;
        struct btrfs_root *root = inode->root;
-       struct btrfs_ordered_extent *ordered;
        u64 lockstart, lockend;
        u64 num_bytes;
        int ret;
 
        ret = btrfs_start_write_no_snapshotting(root);
        if (!ret)
-               return -ENOSPC;
+               return -EAGAIN;
 
        lockstart = round_down(pos, fs_info->sectorsize);
        lockend = round_up(pos + *write_bytes,
                           fs_info->sectorsize) - 1;
 
-       while (1) {
-               lock_extent(&inode->io_tree, lockstart, lockend);
-               ordered = btrfs_lookup_ordered_range(inode, lockstart,
-                                                    lockend - lockstart + 1);
-               if (!ordered) {
-                       break;
-               }
-               unlock_extent(&inode->io_tree, lockstart, lockend);
-               btrfs_start_ordered_extent(&inode->vfs_inode, ordered, 1);
-               btrfs_put_ordered_extent(ordered);
-       }
+       btrfs_lock_and_flush_ordered_range(&inode->io_tree, inode, lockstart,
+                                          lockend, NULL);
 
        num_bytes = lockend - lockstart + 1;
        ret = can_nocow_extent(&inode->vfs_inode, lockstart, &num_bytes,
@@ -2721,6 +2712,11 @@ out_only_mutex:
                 * for detecting, at fsync time, if the inode isn't yet in the
                 * log tree or it's there but not up to date.
                 */
+               struct timespec64 now = current_time(inode);
+
+               inode_inc_iversion(inode);
+               inode->i_mtime = now;
+               inode->i_ctime = now;
                trans = btrfs_start_transaction(root, 1);
                if (IS_ERR(trans)) {
                        err = PTR_ERR(trans);
@@ -2801,9 +2797,9 @@ static int btrfs_fallocate_update_isize(struct inode *inode,
 }
 
 enum {
-       RANGE_BOUNDARY_WRITTEN_EXTENT = 0,
-       RANGE_BOUNDARY_PREALLOC_EXTENT = 1,
-       RANGE_BOUNDARY_HOLE = 2,
+       RANGE_BOUNDARY_WRITTEN_EXTENT,
+       RANGE_BOUNDARY_PREALLOC_EXTENT,
+       RANGE_BOUNDARY_HOLE,
 };
 
 static int btrfs_zero_range_check_range_boundary(struct inode *inode,
index f74dc25..062be9d 100644 (file)
@@ -18,6 +18,8 @@
 #include "extent_io.h"
 #include "inode-map.h"
 #include "volumes.h"
+#include "space-info.h"
+#include "delalloc-space.h"
 
 #define BITS_PER_BITMAP                (PAGE_SIZE * 8UL)
 #define MAX_CACHE_BYTES_PER_GIG        SZ_32K
@@ -465,9 +467,8 @@ static void io_ctl_set_crc(struct btrfs_io_ctl *io_ctl, int index)
        if (index == 0)
                offset = sizeof(u32) * io_ctl->num_pages;
 
-       crc = btrfs_csum_data(io_ctl->orig + offset, crc,
-                             PAGE_SIZE - offset);
-       btrfs_csum_final(crc, (u8 *)&crc);
+       crc = btrfs_crc32c(crc, io_ctl->orig + offset, PAGE_SIZE - offset);
+       btrfs_crc32c_final(crc, (u8 *)&crc);
        io_ctl_unmap_page(io_ctl);
        tmp = page_address(io_ctl->pages[0]);
        tmp += index;
@@ -493,9 +494,8 @@ static int io_ctl_check_crc(struct btrfs_io_ctl *io_ctl, int index)
        val = *tmp;
 
        io_ctl_map_page(io_ctl, 0);
-       crc = btrfs_csum_data(io_ctl->orig + offset, crc,
-                             PAGE_SIZE - offset);
-       btrfs_csum_final(crc, (u8 *)&crc);
+       crc = btrfs_crc32c(crc, io_ctl->orig + offset, PAGE_SIZE - offset);
+       btrfs_crc32c_final(crc, (u8 *)&crc);
        if (val != crc) {
                btrfs_err_rl(io_ctl->fs_info,
                        "csum mismatch on free space cache");
@@ -3166,8 +3166,8 @@ static int do_trimming(struct btrfs_block_group_cache *block_group,
                        space_info->bytes_readonly += reserved_bytes;
                block_group->reserved -= reserved_bytes;
                space_info->bytes_reserved -= reserved_bytes;
-               spin_unlock(&space_info->lock);
                spin_unlock(&block_group->lock);
+               spin_unlock(&space_info->lock);
        }
 
        return ret;
@@ -3358,7 +3358,7 @@ void btrfs_put_block_group_trimming(struct btrfs_block_group_cache *block_group)
 
        if (cleanup) {
                mutex_lock(&fs_info->chunk_mutex);
-               em_tree = &fs_info->mapping_tree.map_tree;
+               em_tree = &fs_info->mapping_tree;
                write_lock(&em_tree->lock);
                em = lookup_extent_mapping(em_tree, block_group->key.objectid,
                                           1);
index ffca2ab..2e8bb40 100644 (file)
@@ -11,6 +11,7 @@
 #include "free-space-cache.h"
 #include "inode-map.h"
 #include "transaction.h"
+#include "delalloc-space.h"
 
 static int caching_kthread(void *data)
 {
index a2aabdb..ee582a3 100644 (file)
@@ -47,6 +47,7 @@
 #include "props.h"
 #include "qgroup.h"
 #include "dedupe.h"
+#include "delalloc-space.h"
 
 struct btrfs_iget_args {
        struct btrfs_key *location;
@@ -394,10 +395,31 @@ static noinline int add_async_extent(struct async_chunk *cow,
        return 0;
 }
 
+/*
+ * Check if the inode has flags compatible with compression
+ */
+static inline bool inode_can_compress(struct inode *inode)
+{
+       if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW ||
+           BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)
+               return false;
+       return true;
+}
+
+/*
+ * Check if the inode needs to be submitted to compression, based on mount
+ * options, defragmentation, properties or heuristics.
+ */
 static inline int inode_need_compress(struct inode *inode, u64 start, u64 end)
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
 
+       if (!inode_can_compress(inode)) {
+               WARN(IS_ENABLED(CONFIG_BTRFS_DEBUG),
+                       KERN_ERR "BTRFS: unexpected compression for ino %llu\n",
+                       btrfs_ino(BTRFS_I(inode)));
+               return 0;
+       }
        /* force compress */
        if (btrfs_test_opt(fs_info, FORCE_COMPRESS))
                return 1;
@@ -1630,7 +1652,8 @@ int btrfs_run_delalloc_range(struct inode *inode, struct page *locked_page,
        } else if (BTRFS_I(inode)->flags & BTRFS_INODE_PREALLOC && !force_cow) {
                ret = run_delalloc_nocow(inode, locked_page, start, end,
                                         page_started, 0, nr_written);
-       } else if (!inode_need_compress(inode, start, end)) {
+       } else if (!inode_can_compress(inode) ||
+                  !inode_need_compress(inode, start, end)) {
                ret = cow_file_range(inode, locked_page, start, end, end,
                                      page_started, nr_written, 1, NULL);
        } else {
@@ -1932,17 +1955,19 @@ int btrfs_bio_fits_in_stripe(struct page *page, size_t size, struct bio *bio,
        u64 length = 0;
        u64 map_length;
        int ret;
+       struct btrfs_io_geometry geom;
 
        if (bio_flags & EXTENT_BIO_COMPRESSED)
                return 0;
 
        length = bio->bi_iter.bi_size;
        map_length = length;
-       ret = btrfs_map_block(fs_info, btrfs_op(bio), logical, &map_length,
-                             NULL, 0);
+       ret = btrfs_get_io_geometry(fs_info, btrfs_op(bio), logical, map_length,
+                                   &geom);
        if (ret < 0)
                return ret;
-       if (map_length < length + size)
+
+       if (geom.len < length + size)
                return 1;
        return 0;
 }
@@ -3203,16 +3228,23 @@ static int __readpage_endio_check(struct inode *inode,
                                  int icsum, struct page *page,
                                  int pgoff, u64 start, size_t len)
 {
+       struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+       SHASH_DESC_ON_STACK(shash, fs_info->csum_shash);
        char *kaddr;
-       u32 csum_expected;
-       u32 csum = ~(u32)0;
+       u16 csum_size = btrfs_super_csum_size(fs_info->super_copy);
+       u8 *csum_expected;
+       u8 csum[BTRFS_CSUM_SIZE];
 
-       csum_expected = *(((u32 *)io_bio->csum) + icsum);
+       csum_expected = ((u8 *)io_bio->csum) + icsum * csum_size;
 
        kaddr = kmap_atomic(page);
-       csum = btrfs_csum_data(kaddr + pgoff, csum,  len);
-       btrfs_csum_final(csum, (u8 *)&csum);
-       if (csum != csum_expected)
+       shash->tfm = fs_info->csum_shash;
+
+       crypto_shash_init(shash);
+       crypto_shash_update(shash, kaddr + pgoff, len);
+       crypto_shash_final(shash, csum);
+
+       if (memcmp(csum, csum_expected, csum_size))
                goto zeroit;
 
        kunmap_atomic(kaddr);
@@ -3286,6 +3318,28 @@ void btrfs_add_delayed_iput(struct inode *inode)
                wake_up_process(fs_info->cleaner_kthread);
 }
 
+static void run_delayed_iput_locked(struct btrfs_fs_info *fs_info,
+                                   struct btrfs_inode *inode)
+{
+       list_del_init(&inode->delayed_iput);
+       spin_unlock(&fs_info->delayed_iput_lock);
+       iput(&inode->vfs_inode);
+       if (atomic_dec_and_test(&fs_info->nr_delayed_iputs))
+               wake_up(&fs_info->delayed_iputs_wait);
+       spin_lock(&fs_info->delayed_iput_lock);
+}
+
+static void btrfs_run_delayed_iput(struct btrfs_fs_info *fs_info,
+                                  struct btrfs_inode *inode)
+{
+       if (!list_empty(&inode->delayed_iput)) {
+               spin_lock(&fs_info->delayed_iput_lock);
+               if (!list_empty(&inode->delayed_iput))
+                       run_delayed_iput_locked(fs_info, inode);
+               spin_unlock(&fs_info->delayed_iput_lock);
+       }
+}
+
 void btrfs_run_delayed_iputs(struct btrfs_fs_info *fs_info)
 {
 
@@ -3295,12 +3349,7 @@ void btrfs_run_delayed_iputs(struct btrfs_fs_info *fs_info)
 
                inode = list_first_entry(&fs_info->delayed_iputs,
                                struct btrfs_inode, delayed_iput);
-               list_del_init(&inode->delayed_iput);
-               spin_unlock(&fs_info->delayed_iput_lock);
-               iput(&inode->vfs_inode);
-               if (atomic_dec_and_test(&fs_info->nr_delayed_iputs))
-                       wake_up(&fs_info->delayed_iputs_wait);
-               spin_lock(&fs_info->delayed_iput_lock);
+               run_delayed_iput_locked(fs_info, inode);
        }
        spin_unlock(&fs_info->delayed_iput_lock);
 }
@@ -3935,9 +3984,7 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans,
        struct btrfs_fs_info *fs_info = root->fs_info;
        struct btrfs_path *path;
        int ret = 0;
-       struct extent_buffer *leaf;
        struct btrfs_dir_item *di;
-       struct btrfs_key key;
        u64 index;
        u64 ino = btrfs_ino(inode);
        u64 dir_ino = btrfs_ino(dir);
@@ -3955,8 +4002,6 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans,
                ret = di ? PTR_ERR(di) : -ENOENT;
                goto err;
        }
-       leaf = path->nodes[0];
-       btrfs_dir_item_key_to_cpu(leaf, di, &key);
        ret = btrfs_delete_one_dir_name(trans, root, path, di);
        if (ret)
                goto err;
@@ -4009,6 +4054,17 @@ skip_backref:
                ret = 0;
        else if (ret)
                btrfs_abort_transaction(trans, ret);
+
+       /*
+        * If we have a pending delayed iput we could end up with the final iput
+        * being run in btrfs-cleaner context.  If we have enough of these built
+        * up we can end up burning a lot of time in btrfs-cleaner without any
+        * way to throttle the unlinks.  Since we're currently holding a ref on
+        * the inode we can run the delayed iput here without any issues as the
+        * final iput won't be done until after we drop the ref we're currently
+        * holding.
+        */
+       btrfs_run_delayed_iput(fs_info, inode);
 err:
        btrfs_free_path(path);
        if (ret)
@@ -5008,21 +5064,8 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
        if (size <= hole_start)
                return 0;
 
-       while (1) {
-               struct btrfs_ordered_extent *ordered;
-
-               lock_extent_bits(io_tree, hole_start, block_end - 1,
-                                &cached_state);
-               ordered = btrfs_lookup_ordered_range(BTRFS_I(inode), hole_start,
-                                                    block_end - hole_start);
-               if (!ordered)
-                       break;
-               unlock_extent_cached(io_tree, hole_start, block_end - 1,
-                                    &cached_state);
-               btrfs_start_ordered_extent(inode, ordered, 1);
-               btrfs_put_ordered_extent(ordered);
-       }
-
+       btrfs_lock_and_flush_ordered_range(io_tree, BTRFS_I(inode), hole_start,
+                                          block_end - 1, &cached_state);
        cur_offset = hole_start;
        while (1) {
                em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, cur_offset,
@@ -8318,22 +8361,21 @@ static int btrfs_submit_direct_hook(struct btrfs_dio_private *dip)
        struct bio *orig_bio = dip->orig_bio;
        u64 start_sector = orig_bio->bi_iter.bi_sector;
        u64 file_offset = dip->logical_offset;
-       u64 map_length;
        int async_submit = 0;
        u64 submit_len;
        int clone_offset = 0;
        int clone_len;
        int ret;
        blk_status_t status;
+       struct btrfs_io_geometry geom;
 
-       map_length = orig_bio->bi_iter.bi_size;
-       submit_len = map_length;
-       ret = btrfs_map_block(fs_info, btrfs_op(orig_bio), start_sector << 9,
-                             &map_length, NULL, 0);
+       submit_len = orig_bio->bi_iter.bi_size;
+       ret = btrfs_get_io_geometry(fs_info, btrfs_op(orig_bio),
+                                   start_sector << 9, submit_len, &geom);
        if (ret)
                return -EIO;
 
-       if (map_length >= submit_len) {
+       if (geom.len >= submit_len) {
                bio = orig_bio;
                dip->flags |= BTRFS_DIO_ORIG_BIO_SUBMITTED;
                goto submit;
@@ -8346,10 +8388,10 @@ static int btrfs_submit_direct_hook(struct btrfs_dio_private *dip)
                async_submit = 1;
 
        /* bio split */
-       ASSERT(map_length <= INT_MAX);
+       ASSERT(geom.len <= INT_MAX);
        atomic_inc(&dip->pending_bios);
        do {
-               clone_len = min_t(int, submit_len, map_length);
+               clone_len = min_t(int, submit_len, geom.len);
 
                /*
                 * This will never fail as it's passing GPF_NOFS and
@@ -8386,9 +8428,8 @@ static int btrfs_submit_direct_hook(struct btrfs_dio_private *dip)
                start_sector += clone_len >> 9;
                file_offset += clone_len;
 
-               map_length = submit_len;
-               ret = btrfs_map_block(fs_info, btrfs_op(orig_bio),
-                                     start_sector << 9, &map_length, NULL, 0);
+               ret = btrfs_get_io_geometry(fs_info, btrfs_op(orig_bio),
+                                     start_sector << 9, submit_len, &geom);
                if (ret)
                        goto out_err;
        } while (submit_len > 0);
index cfeff1b..818f7ec 100644 (file)
@@ -43,6 +43,8 @@
 #include "qgroup.h"
 #include "tree-log.h"
 #include "compression.h"
+#include "space-info.h"
+#include "delalloc-space.h"
 
 #ifdef CONFIG_64BIT
 /* If we have a 32-bit userspace and 64-bit kernel, then the UAPI
@@ -3993,6 +3995,27 @@ static int btrfs_remap_file_range_prep(struct file *file_in, loff_t pos_in,
        if (!same_inode)
                inode_dio_wait(inode_out);
 
+       /*
+        * Workaround to make sure NOCOW buffered write reach disk as NOCOW.
+        *
+        * Btrfs' back references do not have a block level granularity, they
+        * work at the whole extent level.
+        * NOCOW buffered write without data space reserved may not be able
+        * to fall back to CoW due to lack of data space, thus could cause
+        * data loss.
+        *
+        * Here we take a shortcut by flushing the whole inode, so that all
+        * nocow write should reach disk as nocow before we increase the
+        * reference of the extent. We could do better by only flushing NOCOW
+        * data, but that needs extra accounting.
+        *
+        * Also we don't need to check ASYNC_EXTENT, as async extent will be
+        * CoWed anyway, not affecting nocow part.
+        */
+       ret = filemap_flush(inode_in->i_mapping);
+       if (ret < 0)
+               return ret;
+
        ret = btrfs_wait_ordered_range(inode_in, ALIGN_DOWN(pos_in, bs),
                                       wb_len);
        if (ret < 0)
index 2f6c3c7..98fccce 100644 (file)
 #ifdef CONFIG_BTRFS_DEBUG
 static void btrfs_assert_spinning_writers_get(struct extent_buffer *eb)
 {
-       WARN_ON(atomic_read(&eb->spinning_writers));
-       atomic_inc(&eb->spinning_writers);
+       WARN_ON(eb->spinning_writers);
+       eb->spinning_writers++;
 }
 
 static void btrfs_assert_spinning_writers_put(struct extent_buffer *eb)
 {
-       WARN_ON(atomic_read(&eb->spinning_writers) != 1);
-       atomic_dec(&eb->spinning_writers);
+       WARN_ON(eb->spinning_writers != 1);
+       eb->spinning_writers--;
 }
 
 static void btrfs_assert_no_spinning_writers(struct extent_buffer *eb)
 {
-       WARN_ON(atomic_read(&eb->spinning_writers));
+       WARN_ON(eb->spinning_writers);
 }
 
 static void btrfs_assert_spinning_readers_get(struct extent_buffer *eb)
@@ -58,17 +58,17 @@ static void btrfs_assert_tree_read_locked(struct extent_buffer *eb)
 
 static void btrfs_assert_tree_write_locks_get(struct extent_buffer *eb)
 {
-       atomic_inc(&eb->write_locks);
+       eb->write_locks++;
 }
 
 static void btrfs_assert_tree_write_locks_put(struct extent_buffer *eb)
 {
-       atomic_dec(&eb->write_locks);
+       eb->write_locks--;
 }
 
 void btrfs_assert_tree_locked(struct extent_buffer *eb)
 {
-       BUG_ON(!atomic_read(&eb->write_locks));
+       BUG_ON(!eb->write_locks);
 }
 
 #else
@@ -111,10 +111,10 @@ void btrfs_set_lock_blocking_write(struct extent_buffer *eb)
         */
        if (eb->lock_nested && current->pid == eb->lock_owner)
                return;
-       if (atomic_read(&eb->blocking_writers) == 0) {
+       if (eb->blocking_writers == 0) {
                btrfs_assert_spinning_writers_put(eb);
                btrfs_assert_tree_locked(eb);
-               atomic_inc(&eb->blocking_writers);
+               eb->blocking_writers++;
                write_unlock(&eb->lock);
        }
 }
@@ -148,12 +148,11 @@ void btrfs_clear_lock_blocking_write(struct extent_buffer *eb)
         */
        if (eb->lock_nested && current->pid == eb->lock_owner)
                return;
-       BUG_ON(atomic_read(&eb->blocking_writers) != 1);
        write_lock(&eb->lock);
+       BUG_ON(eb->blocking_writers != 1);
        btrfs_assert_spinning_writers_get(eb);
-       /* atomic_dec_and_test implies a barrier */
-       if (atomic_dec_and_test(&eb->blocking_writers))
-               cond_wake_up_nomb(&eb->write_lock_wq);
+       if (--eb->blocking_writers == 0)
+               cond_wake_up(&eb->write_lock_wq);
 }
 
 /*
@@ -167,12 +166,10 @@ void btrfs_tree_read_lock(struct extent_buffer *eb)
        if (trace_btrfs_tree_read_lock_enabled())
                start_ns = ktime_get_ns();
 again:
-       BUG_ON(!atomic_read(&eb->blocking_writers) &&
-              current->pid == eb->lock_owner);
-
        read_lock(&eb->lock);
-       if (atomic_read(&eb->blocking_writers) &&
-           current->pid == eb->lock_owner) {
+       BUG_ON(eb->blocking_writers == 0 &&
+              current->pid == eb->lock_owner);
+       if (eb->blocking_writers && current->pid == eb->lock_owner) {
                /*
                 * This extent is already write-locked by our thread. We allow
                 * an additional read lock to be added because it's for the same
@@ -185,10 +182,10 @@ again:
                trace_btrfs_tree_read_lock(eb, start_ns);
                return;
        }
-       if (atomic_read(&eb->blocking_writers)) {
+       if (eb->blocking_writers) {
                read_unlock(&eb->lock);
                wait_event(eb->write_lock_wq,
-                          atomic_read(&eb->blocking_writers) == 0);
+                          eb->blocking_writers == 0);
                goto again;
        }
        btrfs_assert_tree_read_locks_get(eb);
@@ -203,11 +200,11 @@ again:
  */
 int btrfs_tree_read_lock_atomic(struct extent_buffer *eb)
 {
-       if (atomic_read(&eb->blocking_writers))
+       if (eb->blocking_writers)
                return 0;
 
        read_lock(&eb->lock);
-       if (atomic_read(&eb->blocking_writers)) {
+       if (eb->blocking_writers) {
                read_unlock(&eb->lock);
                return 0;
        }
@@ -223,13 +220,13 @@ int btrfs_tree_read_lock_atomic(struct extent_buffer *eb)
  */
 int btrfs_try_tree_read_lock(struct extent_buffer *eb)
 {
-       if (atomic_read(&eb->blocking_writers))
+       if (eb->blocking_writers)
                return 0;
 
        if (!read_trylock(&eb->lock))
                return 0;
 
-       if (atomic_read(&eb->blocking_writers)) {
+       if (eb->blocking_writers) {
                read_unlock(&eb->lock);
                return 0;
        }
@@ -245,13 +242,11 @@ int btrfs_try_tree_read_lock(struct extent_buffer *eb)
  */
 int btrfs_try_tree_write_lock(struct extent_buffer *eb)
 {
-       if (atomic_read(&eb->blocking_writers) ||
-           atomic_read(&eb->blocking_readers))
+       if (eb->blocking_writers || atomic_read(&eb->blocking_readers))
                return 0;
 
        write_lock(&eb->lock);
-       if (atomic_read(&eb->blocking_writers) ||
-           atomic_read(&eb->blocking_readers)) {
+       if (eb->blocking_writers || atomic_read(&eb->blocking_readers)) {
                write_unlock(&eb->lock);
                return 0;
        }
@@ -322,10 +317,9 @@ void btrfs_tree_lock(struct extent_buffer *eb)
        WARN_ON(eb->lock_owner == current->pid);
 again:
        wait_event(eb->read_lock_wq, atomic_read(&eb->blocking_readers) == 0);
-       wait_event(eb->write_lock_wq, atomic_read(&eb->blocking_writers) == 0);
+       wait_event(eb->write_lock_wq, eb->blocking_writers == 0);
        write_lock(&eb->lock);
-       if (atomic_read(&eb->blocking_readers) ||
-           atomic_read(&eb->blocking_writers)) {
+       if (atomic_read(&eb->blocking_readers) || eb->blocking_writers) {
                write_unlock(&eb->lock);
                goto again;
        }
@@ -340,7 +334,7 @@ again:
  */
 void btrfs_tree_unlock(struct extent_buffer *eb)
 {
-       int blockers = atomic_read(&eb->blocking_writers);
+       int blockers = eb->blocking_writers;
 
        BUG_ON(blockers > 1);
 
@@ -351,7 +345,7 @@ void btrfs_tree_unlock(struct extent_buffer *eb)
 
        if (blockers) {
                btrfs_assert_no_spinning_writers(eb);
-               atomic_dec(&eb->blocking_writers);
+               eb->blocking_writers--;
                /* Use the lighter barrier after atomic */
                smp_mb__after_atomic();
                cond_wake_up_nomb(&eb->write_lock_wq);
index 52889da..1744ba8 100644 (file)
@@ -13,6 +13,7 @@
 #include "extent_io.h"
 #include "disk-io.h"
 #include "compression.h"
+#include "delalloc-space.h"
 
 static struct kmem_cache *btrfs_ordered_extent_cache;
 
@@ -924,14 +925,16 @@ out:
  * be reclaimed before their checksum is actually put into the btree
  */
 int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
-                          u32 *sum, int len)
+                          u8 *sum, int len)
 {
+       struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
        struct btrfs_ordered_sum *ordered_sum;
        struct btrfs_ordered_extent *ordered;
        struct btrfs_ordered_inode_tree *tree = &BTRFS_I(inode)->ordered_tree;
        unsigned long num_sectors;
        unsigned long i;
        u32 sectorsize = btrfs_inode_sectorsize(inode);
+       const u16 csum_size = btrfs_super_csum_size(fs_info->super_copy);
        int index = 0;
 
        ordered = btrfs_lookup_ordered_extent(inode, offset);
@@ -947,10 +950,10 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
                        num_sectors = ordered_sum->len >>
                                      inode->i_sb->s_blocksize_bits;
                        num_sectors = min_t(int, len - index, num_sectors - i);
-                       memcpy(sum + index, ordered_sum->sums + i,
-                              num_sectors);
+                       memcpy(sum + index, ordered_sum->sums + i * csum_size,
+                              num_sectors * csum_size);
 
-                       index += (int)num_sectors;
+                       index += (int)num_sectors * csum_size;
                        if (index == len)
                                goto out;
                        disk_bytenr += num_sectors * sectorsize;
@@ -962,6 +965,51 @@ out:
        return index;
 }
 
+/*
+ * btrfs_flush_ordered_range - Lock the passed range and ensures all pending
+ * ordered extents in it are run to completion.
+ *
+ * @tree:         IO tree used for locking out other users of the range
+ * @inode:        Inode whose ordered tree is to be searched
+ * @start:        Beginning of range to flush
+ * @end:          Last byte of range to lock
+ * @cached_state: If passed, will return the extent state responsible for the
+ * locked range. It's the caller's responsibility to free the cached state.
+ *
+ * This function always returns with the given range locked, ensuring after it's
+ * called no order extent can be pending.
+ */
+void btrfs_lock_and_flush_ordered_range(struct extent_io_tree *tree,
+                                       struct btrfs_inode *inode, u64 start,
+                                       u64 end,
+                                       struct extent_state **cached_state)
+{
+       struct btrfs_ordered_extent *ordered;
+       struct extent_state *cachedp = NULL;
+
+       if (cached_state)
+               cachedp = *cached_state;
+
+       while (1) {
+               lock_extent_bits(tree, start, end, &cachedp);
+               ordered = btrfs_lookup_ordered_range(inode, start,
+                                                    end - start + 1);
+               if (!ordered) {
+                       /*
+                        * If no external cached_state has been passed then
+                        * decrement the extra ref taken for cachedp since we
+                        * aren't exposing it outside of this function
+                        */
+                       if (!cached_state)
+                               refcount_dec(&cachedp->refs);
+                       break;
+               }
+               unlock_extent_cached(tree, start, end, &cachedp);
+               btrfs_start_ordered_extent(&inode->vfs_inode, ordered, 1);
+               btrfs_put_ordered_extent(ordered);
+       }
+}
+
 int __init ordered_data_init(void)
 {
        btrfs_ordered_extent_cache = kmem_cache_create("btrfs_ordered_extent",
index 4c5991c..5204171 100644 (file)
@@ -23,7 +23,7 @@ struct btrfs_ordered_sum {
        int len;
        struct list_head list;
        /* last field is a variable length array of csums */
-       u32 sums[];
+       u8 sums[];
 };
 
 /*
@@ -183,11 +183,15 @@ struct btrfs_ordered_extent *btrfs_lookup_ordered_range(
 int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
                                struct btrfs_ordered_extent *ordered);
 int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
-                          u32 *sum, int len);
+                          u8 *sum, int len);
 u64 btrfs_wait_ordered_extents(struct btrfs_root *root, u64 nr,
                               const u64 range_start, const u64 range_len);
 u64 btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, u64 nr,
                              const u64 range_start, const u64 range_len);
+void btrfs_lock_and_flush_ordered_range(struct extent_io_tree *tree,
+                                       struct btrfs_inode *inode, u64 start,
+                                       u64 end,
+                                       struct extent_state **cached_state);
 int __init ordered_data_init(void);
 void __cold ordered_data_exit(void);
 
index 1141ca5..9cb5057 100644 (file)
@@ -153,11 +153,11 @@ static void print_eb_refs_lock(struct extent_buffer *eb)
 #ifdef CONFIG_BTRFS_DEBUG
        btrfs_info(eb->fs_info,
 "refs %u lock (w:%d r:%d bw:%d br:%d sw:%d sr:%d) lock_owner %u current %u",
-                  atomic_read(&eb->refs), atomic_read(&eb->write_locks),
+                  atomic_read(&eb->refs), eb->write_locks,
                   atomic_read(&eb->read_locks),
-                  atomic_read(&eb->blocking_writers),
+                  eb->blocking_writers,
                   atomic_read(&eb->blocking_readers),
-                  atomic_read(&eb->spinning_writers),
+                  eb->spinning_writers,
                   atomic_read(&eb->spinning_readers),
                   eb->lock_owner, current->pid);
 #endif
index a9e2e66..e046981 100644 (file)
@@ -257,11 +257,7 @@ static int prop_compression_validate(const char *value, size_t len)
        if (!value)
                return 0;
 
-       if (!strncmp("lzo", value, 3))
-               return 0;
-       else if (!strncmp("zlib", value, 4))
-               return 0;
-       else if (!strncmp("zstd", value, 4))
+       if (btrfs_compress_is_valid_type(value, len))
                return 0;
 
        return -EINVAL;
@@ -341,7 +337,7 @@ static int inherit_props(struct btrfs_trans_handle *trans,
        for (i = 0; i < ARRAY_SIZE(prop_handlers); i++) {
                const struct prop_handler *h = &prop_handlers[i];
                const char *value;
-               u64 num_bytes;
+               u64 num_bytes = 0;
 
                if (!h->inheritable)
                        continue;
index 3e6ffbb..f8a3c1b 100644 (file)
@@ -2614,6 +2614,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
        int ret = 0;
        int i;
        u64 *i_qgroups;
+       bool committing = false;
        struct btrfs_fs_info *fs_info = trans->fs_info;
        struct btrfs_root *quota_root;
        struct btrfs_qgroup *srcgroup;
@@ -2621,7 +2622,25 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
        u32 level_size = 0;
        u64 nums;
 
-       mutex_lock(&fs_info->qgroup_ioctl_lock);
+       /*
+        * There are only two callers of this function.
+        *
+        * One in create_subvol() in the ioctl context, which needs to hold
+        * the qgroup_ioctl_lock.
+        *
+        * The other one in create_pending_snapshot() where no other qgroup
+        * code can modify the fs as they all need to either start a new trans
+        * or hold a trans handler, thus we don't need to hold
+        * qgroup_ioctl_lock.
+        * This would avoid long and complex lock chain and make lockdep happy.
+        */
+       spin_lock(&fs_info->trans_lock);
+       if (trans->transaction->state == TRANS_STATE_COMMIT_DOING)
+               committing = true;
+       spin_unlock(&fs_info->trans_lock);
+
+       if (!committing)
+               mutex_lock(&fs_info->qgroup_ioctl_lock);
        if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
                goto out;
 
@@ -2785,7 +2804,8 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
 unlock:
        spin_unlock(&fs_info->qgroup_lock);
 out:
-       mutex_unlock(&fs_info->qgroup_ioctl_lock);
+       if (!committing)
+               mutex_unlock(&fs_info->qgroup_ioctl_lock);
        return ret;
 }
 
index f5d4c13..2503485 100644 (file)
@@ -7,7 +7,7 @@
 #ifndef BTRFS_RAID56_H
 #define BTRFS_RAID56_H
 
-static inline int nr_parity_stripes(struct map_lookup *map)
+static inline int nr_parity_stripes(const struct map_lookup *map)
 {
        if (map->type & BTRFS_BLOCK_GROUP_RAID5)
                return 1;
@@ -17,7 +17,7 @@ static inline int nr_parity_stripes(struct map_lookup *map)
                return 0;
 }
 
-static inline int nr_data_stripes(struct map_lookup *map)
+static inline int nr_data_stripes(const struct map_lookup *map)
 {
        return map->num_stripes - nr_parity_stripes(map);
 }
index 22a3c69..7f21985 100644 (file)
@@ -20,6 +20,7 @@
 #include "inode-map.h"
 #include "qgroup.h"
 #include "print-tree.h"
+#include "delalloc-space.h"
 
 /*
  * backref_node, mapping_node and tree_block start with this
index 2212412..47733fb 100644 (file)
@@ -9,6 +9,8 @@
 #include "transaction.h"
 #include "disk-io.h"
 #include "print-tree.h"
+#include "qgroup.h"
+#include "space-info.h"
 
 /*
  * Read a root item from the tree. In case we detect a root item smaller then
@@ -497,3 +499,57 @@ void btrfs_update_root_times(struct btrfs_trans_handle *trans,
        btrfs_set_stack_timespec_nsec(&item->ctime, ct.tv_nsec);
        spin_unlock(&root->root_item_lock);
 }
+
+/*
+ * btrfs_subvolume_reserve_metadata() - reserve space for subvolume operation
+ * root: the root of the parent directory
+ * rsv: block reservation
+ * items: the number of items that we need do reservation
+ * use_global_rsv: allow fallback to the global block reservation
+ *
+ * This function is used to reserve the space for snapshot/subvolume
+ * creation and deletion. Those operations are different with the
+ * common file/directory operations, they change two fs/file trees
+ * and root tree, the number of items that the qgroup reserves is
+ * different with the free space reservation. So we can not use
+ * the space reservation mechanism in start_transaction().
+ */
+int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
+                                    struct btrfs_block_rsv *rsv, int items,
+                                    bool use_global_rsv)
+{
+       u64 qgroup_num_bytes = 0;
+       u64 num_bytes;
+       int ret;
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
+
+       if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) {
+               /* One for parent inode, two for dir entries */
+               qgroup_num_bytes = 3 * fs_info->nodesize;
+               ret = btrfs_qgroup_reserve_meta_prealloc(root,
+                               qgroup_num_bytes, true);
+               if (ret)
+                       return ret;
+       }
+
+       num_bytes = btrfs_calc_trans_metadata_size(fs_info, items);
+       rsv->space_info = btrfs_find_space_info(fs_info,
+                                           BTRFS_BLOCK_GROUP_METADATA);
+       ret = btrfs_block_rsv_add(root, rsv, num_bytes,
+                                 BTRFS_RESERVE_FLUSH_ALL);
+
+       if (ret == -ENOSPC && use_global_rsv)
+               ret = btrfs_block_rsv_migrate(global_rsv, rsv, num_bytes, true);
+
+       if (ret && qgroup_num_bytes)
+               btrfs_qgroup_free_meta_prealloc(root, qgroup_num_bytes);
+
+       return ret;
+}
+
+void btrfs_subvolume_release_metadata(struct btrfs_fs_info *fs_info,
+                                     struct btrfs_block_rsv *rsv)
+{
+       btrfs_block_rsv_release(fs_info, rsv, (u64)-1);
+}
index f7b29f9..0c99cf9 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/blkdev.h>
 #include <linux/ratelimit.h>
 #include <linux/sched/mm.h>
+#include <crypto/hash.h>
 #include "ctree.h"
 #include "volumes.h"
 #include "disk-io.h"
@@ -1787,11 +1788,12 @@ static int scrub_checksum(struct scrub_block *sblock)
 static int scrub_checksum_data(struct scrub_block *sblock)
 {
        struct scrub_ctx *sctx = sblock->sctx;
+       struct btrfs_fs_info *fs_info = sctx->fs_info;
+       SHASH_DESC_ON_STACK(shash, fs_info->csum_shash);
        u8 csum[BTRFS_CSUM_SIZE];
        u8 *on_disk_csum;
        struct page *page;
        void *buffer;
-       u32 crc = ~(u32)0;
        u64 len;
        int index;
 
@@ -1799,6 +1801,9 @@ static int scrub_checksum_data(struct scrub_block *sblock)
        if (!sblock->pagev[0]->have_csum)
                return 0;
 
+       shash->tfm = fs_info->csum_shash;
+       crypto_shash_init(shash);
+
        on_disk_csum = sblock->pagev[0]->csum;
        page = sblock->pagev[0]->page;
        buffer = kmap_atomic(page);
@@ -1808,7 +1813,7 @@ static int scrub_checksum_data(struct scrub_block *sblock)
        for (;;) {
                u64 l = min_t(u64, len, PAGE_SIZE);
 
-               crc = btrfs_csum_data(buffer, crc, l);
+               crypto_shash_update(shash, buffer, l);
                kunmap_atomic(buffer);
                len -= l;
                if (len == 0)
@@ -1820,7 +1825,7 @@ static int scrub_checksum_data(struct scrub_block *sblock)
                buffer = kmap_atomic(page);
        }
 
-       btrfs_csum_final(crc, csum);
+       crypto_shash_final(shash, csum);
        if (memcmp(csum, on_disk_csum, sctx->csum_size))
                sblock->checksum_error = 1;
 
@@ -1832,16 +1837,19 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock)
        struct scrub_ctx *sctx = sblock->sctx;
        struct btrfs_header *h;
        struct btrfs_fs_info *fs_info = sctx->fs_info;
+       SHASH_DESC_ON_STACK(shash, fs_info->csum_shash);
        u8 calculated_csum[BTRFS_CSUM_SIZE];
        u8 on_disk_csum[BTRFS_CSUM_SIZE];
        struct page *page;
        void *mapped_buffer;
        u64 mapped_size;
        void *p;
-       u32 crc = ~(u32)0;
        u64 len;
        int index;
 
+       shash->tfm = fs_info->csum_shash;
+       crypto_shash_init(shash);
+
        BUG_ON(sblock->page_count < 1);
        page = sblock->pagev[0]->page;
        mapped_buffer = kmap_atomic(page);
@@ -1875,7 +1883,7 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock)
        for (;;) {
                u64 l = min_t(u64, len, mapped_size);
 
-               crc = btrfs_csum_data(p, crc, l);
+               crypto_shash_update(shash, p, l);
                kunmap_atomic(mapped_buffer);
                len -= l;
                if (len == 0)
@@ -1889,7 +1897,7 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock)
                p = mapped_buffer;
        }
 
-       btrfs_csum_final(crc, calculated_csum);
+       crypto_shash_final(shash, calculated_csum);
        if (memcmp(calculated_csum, on_disk_csum, sctx->csum_size))
                sblock->checksum_error = 1;
 
@@ -1900,18 +1908,22 @@ static int scrub_checksum_super(struct scrub_block *sblock)
 {
        struct btrfs_super_block *s;
        struct scrub_ctx *sctx = sblock->sctx;
+       struct btrfs_fs_info *fs_info = sctx->fs_info;
+       SHASH_DESC_ON_STACK(shash, fs_info->csum_shash);
        u8 calculated_csum[BTRFS_CSUM_SIZE];
        u8 on_disk_csum[BTRFS_CSUM_SIZE];
        struct page *page;
        void *mapped_buffer;
        u64 mapped_size;
        void *p;
-       u32 crc = ~(u32)0;
        int fail_gen = 0;
        int fail_cor = 0;
        u64 len;
        int index;
 
+       shash->tfm = fs_info->csum_shash;
+       crypto_shash_init(shash);
+
        BUG_ON(sblock->page_count < 1);
        page = sblock->pagev[0]->page;
        mapped_buffer = kmap_atomic(page);
@@ -1934,7 +1946,7 @@ static int scrub_checksum_super(struct scrub_block *sblock)
        for (;;) {
                u64 l = min_t(u64, len, mapped_size);
 
-               crc = btrfs_csum_data(p, crc, l);
+               crypto_shash_update(shash, p, l);
                kunmap_atomic(mapped_buffer);
                len -= l;
                if (len == 0)
@@ -1948,7 +1960,7 @@ static int scrub_checksum_super(struct scrub_block *sblock)
                p = mapped_buffer;
        }
 
-       btrfs_csum_final(crc, calculated_csum);
+       crypto_shash_final(shash, calculated_csum);
        if (memcmp(calculated_csum, on_disk_csum, sctx->csum_size))
                ++fail_cor;
 
@@ -2448,7 +2460,7 @@ static int scrub_find_csum(struct scrub_ctx *sctx, u64 logical, u8 *csum)
        ASSERT(index < UINT_MAX);
 
        num_sectors = sum->len / sctx->fs_info->sectorsize;
-       memcpy(csum, sum->sums + index, sctx->csum_size);
+       memcpy(csum, sum->sums + index * sctx->csum_size, sctx->csum_size);
        if (index == num_sectors - 1) {
                list_del(&sum->list);
                kfree(sum);
@@ -2660,18 +2672,18 @@ static int get_raid56_logic_offset(u64 physical, int num,
        u64 last_offset;
        u32 stripe_index;
        u32 rot;
+       const int data_stripes = nr_data_stripes(map);
 
-       last_offset = (physical - map->stripes[num].physical) *
-                     nr_data_stripes(map);
+       last_offset = (physical - map->stripes[num].physical) * data_stripes;
        if (stripe_start)
                *stripe_start = last_offset;
 
        *offset = last_offset;
-       for (i = 0; i < nr_data_stripes(map); i++) {
+       for (i = 0; i < data_stripes; i++) {
                *offset = last_offset + i * map->stripe_len;
 
                stripe_nr = div64_u64(*offset, map->stripe_len);
-               stripe_nr = div_u64(stripe_nr, nr_data_stripes(map));
+               stripe_nr = div_u64(stripe_nr, data_stripes);
 
                /* Work out the disk rotation on this stripe-set */
                stripe_nr = div_u64_rem(stripe_nr, map->num_stripes, &rot);
@@ -3079,7 +3091,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
                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) {
+       } 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) {
@@ -3410,15 +3422,15 @@ static noinline_for_stack int scrub_chunk(struct scrub_ctx *sctx,
                                          struct btrfs_block_group_cache *cache)
 {
        struct btrfs_fs_info *fs_info = sctx->fs_info;
-       struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
+       struct extent_map_tree *map_tree = &fs_info->mapping_tree;
        struct map_lookup *map;
        struct extent_map *em;
        int i;
        int ret = 0;
 
-       read_lock(&map_tree->map_tree.lock);
-       em = lookup_extent_mapping(&map_tree->map_tree, chunk_offset, 1);
-       read_unlock(&map_tree->map_tree.lock);
+       read_lock(&map_tree->lock);
+       em = lookup_extent_mapping(map_tree, chunk_offset, 1);
+       read_unlock(&map_tree->lock);
 
        if (!em) {
                /*
index f7fe477..69b59bf 100644 (file)
@@ -686,7 +686,7 @@ static int send_cmd(struct send_ctx *sctx)
        hdr->len = cpu_to_le32(sctx->send_size - sizeof(*hdr));
        hdr->crc = 0;
 
-       crc = crc32c(0, (unsigned char *)sctx->send_buf, sctx->send_size);
+       crc = btrfs_crc32c(0, (unsigned char *)sctx->send_buf, sctx->send_size);
        hdr->crc = cpu_to_le32(crc);
 
        ret = write_buf(sctx->send_filp, sctx->send_buf, sctx->send_size,
@@ -6929,9 +6929,23 @@ 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);
+               btrfs_warn_rl(fs_info,
+               "cannot run send because a balance operation is in progress");
+               ret = -EAGAIN;
+               goto out;
+       }
+       fs_info->send_in_progress++;
+       mutex_unlock(&fs_info->balance_mutex);
+
        current->journal_info = BTRFS_SEND_TRANS_STUB;
        ret = send_subvol(sctx);
        current->journal_info = NULL;
+       mutex_lock(&fs_info->balance_mutex);
+       fs_info->send_in_progress--;
+       mutex_unlock(&fs_info->balance_mutex);
        if (ret < 0)
                goto out;
 
diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c
new file mode 100644 (file)
index 0000000..ab7b9ec
--- /dev/null
@@ -0,0 +1,1094 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "ctree.h"
+#include "space-info.h"
+#include "sysfs.h"
+#include "volumes.h"
+#include "free-space-cache.h"
+#include "ordered-data.h"
+#include "transaction.h"
+#include "math.h"
+
+u64 btrfs_space_info_used(struct btrfs_space_info *s_info,
+                         bool may_use_included)
+{
+       ASSERT(s_info);
+       return s_info->bytes_used + s_info->bytes_reserved +
+               s_info->bytes_pinned + s_info->bytes_readonly +
+               (may_use_included ? s_info->bytes_may_use : 0);
+}
+
+/*
+ * after adding space to the filesystem, we need to clear the full flags
+ * on all the space infos.
+ */
+void btrfs_clear_space_info_full(struct btrfs_fs_info *info)
+{
+       struct list_head *head = &info->space_info;
+       struct btrfs_space_info *found;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(found, head, list)
+               found->full = 0;
+       rcu_read_unlock();
+}
+
+static const char *alloc_name(u64 flags)
+{
+       switch (flags) {
+       case BTRFS_BLOCK_GROUP_METADATA|BTRFS_BLOCK_GROUP_DATA:
+               return "mixed";
+       case BTRFS_BLOCK_GROUP_METADATA:
+               return "metadata";
+       case BTRFS_BLOCK_GROUP_DATA:
+               return "data";
+       case BTRFS_BLOCK_GROUP_SYSTEM:
+               return "system";
+       default:
+               WARN_ON(1);
+               return "invalid-combination";
+       };
+}
+
+static int create_space_info(struct btrfs_fs_info *info, u64 flags)
+{
+
+       struct btrfs_space_info *space_info;
+       int i;
+       int ret;
+
+       space_info = kzalloc(sizeof(*space_info), GFP_NOFS);
+       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);
+       spin_lock_init(&space_info->lock);
+       space_info->flags = flags & BTRFS_BLOCK_GROUP_TYPE_MASK;
+       space_info->force_alloc = CHUNK_ALLOC_NO_FORCE;
+       init_waitqueue_head(&space_info->wait);
+       INIT_LIST_HEAD(&space_info->ro_bgs);
+       INIT_LIST_HEAD(&space_info->tickets);
+       INIT_LIST_HEAD(&space_info->priority_tickets);
+
+       ret = kobject_init_and_add(&space_info->kobj, &space_info_ktype,
+                                   info->space_info_kobj, "%s",
+                                   alloc_name(space_info->flags));
+       if (ret) {
+               kobject_put(&space_info->kobj);
+               return ret;
+       }
+
+       list_add_rcu(&space_info->list, &info->space_info);
+       if (flags & BTRFS_BLOCK_GROUP_DATA)
+               info->data_sinfo = space_info;
+
+       return ret;
+}
+
+int btrfs_init_space_info(struct btrfs_fs_info *fs_info)
+{
+       struct btrfs_super_block *disk_super;
+       u64 features;
+       u64 flags;
+       int mixed = 0;
+       int ret;
+
+       disk_super = fs_info->super_copy;
+       if (!btrfs_super_root(disk_super))
+               return -EINVAL;
+
+       features = btrfs_super_incompat_flags(disk_super);
+       if (features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS)
+               mixed = 1;
+
+       flags = BTRFS_BLOCK_GROUP_SYSTEM;
+       ret = create_space_info(fs_info, flags);
+       if (ret)
+               goto out;
+
+       if (mixed) {
+               flags = BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA;
+               ret = create_space_info(fs_info, flags);
+       } else {
+               flags = BTRFS_BLOCK_GROUP_METADATA;
+               ret = create_space_info(fs_info, flags);
+               if (ret)
+                       goto out;
+
+               flags = BTRFS_BLOCK_GROUP_DATA;
+               ret = create_space_info(fs_info, flags);
+       }
+out:
+       return ret;
+}
+
+void btrfs_update_space_info(struct btrfs_fs_info *info, u64 flags,
+                            u64 total_bytes, u64 bytes_used,
+                            u64 bytes_readonly,
+                            struct btrfs_space_info **space_info)
+{
+       struct btrfs_space_info *found;
+       int factor;
+
+       factor = btrfs_bg_type_to_factor(flags);
+
+       found = btrfs_find_space_info(info, flags);
+       ASSERT(found);
+       spin_lock(&found->lock);
+       found->total_bytes += total_bytes;
+       found->disk_total += total_bytes * factor;
+       found->bytes_used += bytes_used;
+       found->disk_used += bytes_used * factor;
+       found->bytes_readonly += bytes_readonly;
+       if (total_bytes > 0)
+               found->full = 0;
+       btrfs_space_info_add_new_bytes(info, found,
+                                      total_bytes - bytes_used -
+                                      bytes_readonly);
+       spin_unlock(&found->lock);
+       *space_info = found;
+}
+
+struct btrfs_space_info *btrfs_find_space_info(struct btrfs_fs_info *info,
+                                              u64 flags)
+{
+       struct list_head *head = &info->space_info;
+       struct btrfs_space_info *found;
+
+       flags &= BTRFS_BLOCK_GROUP_TYPE_MASK;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(found, head, list) {
+               if (found->flags & flags) {
+                       rcu_read_unlock();
+                       return found;
+               }
+       }
+       rcu_read_unlock();
+       return NULL;
+}
+
+static inline u64 calc_global_rsv_need_space(struct btrfs_block_rsv *global)
+{
+       return (global->size << 1);
+}
+
+static int can_overcommit(struct btrfs_fs_info *fs_info,
+                         struct btrfs_space_info *space_info, u64 bytes,
+                         enum btrfs_reserve_flush_enum flush,
+                         bool system_chunk)
+{
+       struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
+       u64 profile;
+       u64 space_size;
+       u64 avail;
+       u64 used;
+       int factor;
+
+       /* Don't overcommit when in mixed mode. */
+       if (space_info->flags & BTRFS_BLOCK_GROUP_DATA)
+               return 0;
+
+       if (system_chunk)
+               profile = btrfs_system_alloc_profile(fs_info);
+       else
+               profile = btrfs_metadata_alloc_profile(fs_info);
+
+       used = btrfs_space_info_used(space_info, false);
+
+       /*
+        * We only want to allow over committing if we have lots of actual space
+        * free, but if we don't have enough space to handle the global reserve
+        * space then we could end up having a real enospc problem when trying
+        * to allocate a chunk or some other such important allocation.
+        */
+       spin_lock(&global_rsv->lock);
+       space_size = calc_global_rsv_need_space(global_rsv);
+       spin_unlock(&global_rsv->lock);
+       if (used + space_size >= space_info->total_bytes)
+               return 0;
+
+       used += space_info->bytes_may_use;
+
+       avail = atomic64_read(&fs_info->free_chunk_space);
+
+       /*
+        * If we have dup, raid1 or raid10 then only half of the free
+        * space is actually usable.  For raid56, the space info used
+        * doesn't include the parity drive, so we don't have to
+        * change the math
+        */
+       factor = btrfs_bg_type_to_factor(profile);
+       avail = div_u64(avail, factor);
+
+       /*
+        * If we aren't flushing all things, let us overcommit up to
+        * 1/2th of the space. If we can flush, don't let us overcommit
+        * too much, let it overcommit up to 1/8 of the space.
+        */
+       if (flush == BTRFS_RESERVE_FLUSH_ALL)
+               avail >>= 3;
+       else
+               avail >>= 1;
+
+       if (used + bytes < space_info->total_bytes + avail)
+               return 1;
+       return 0;
+}
+
+/*
+ * This is for space we already have accounted in space_info->bytes_may_use, so
+ * basically when we're returning space from block_rsv's.
+ */
+void btrfs_space_info_add_old_bytes(struct btrfs_fs_info *fs_info,
+                                   struct btrfs_space_info *space_info,
+                                   u64 num_bytes)
+{
+       struct reserve_ticket *ticket;
+       struct list_head *head;
+       u64 used;
+       enum btrfs_reserve_flush_enum flush = BTRFS_RESERVE_NO_FLUSH;
+       bool check_overcommit = false;
+
+       spin_lock(&space_info->lock);
+       head = &space_info->priority_tickets;
+
+       /*
+        * If we are over our limit then we need to check and see if we can
+        * overcommit, and if we can't then we just need to free up our space
+        * and not satisfy any requests.
+        */
+       used = btrfs_space_info_used(space_info, true);
+       if (used - num_bytes >= space_info->total_bytes)
+               check_overcommit = true;
+again:
+       while (!list_empty(head) && num_bytes) {
+               ticket = list_first_entry(head, struct reserve_ticket,
+                                         list);
+               /*
+                * We use 0 bytes because this space is already reserved, so
+                * adding the ticket space would be a double count.
+                */
+               if (check_overcommit &&
+                   !can_overcommit(fs_info, space_info, 0, flush, false))
+                       break;
+               if (num_bytes >= ticket->bytes) {
+                       list_del_init(&ticket->list);
+                       num_bytes -= ticket->bytes;
+                       ticket->bytes = 0;
+                       space_info->tickets_id++;
+                       wake_up(&ticket->wait);
+               } else {
+                       ticket->bytes -= num_bytes;
+                       num_bytes = 0;
+               }
+       }
+
+       if (num_bytes && head == &space_info->priority_tickets) {
+               head = &space_info->tickets;
+               flush = BTRFS_RESERVE_FLUSH_ALL;
+               goto again;
+       }
+       btrfs_space_info_update_bytes_may_use(fs_info, space_info, -num_bytes);
+       trace_btrfs_space_reservation(fs_info, "space_info",
+                                     space_info->flags, num_bytes, 0);
+       spin_unlock(&space_info->lock);
+}
+
+/*
+ * This is for newly allocated space that isn't accounted in
+ * space_info->bytes_may_use yet.  So if we allocate a chunk or unpin an extent
+ * we use this helper.
+ */
+void btrfs_space_info_add_new_bytes(struct btrfs_fs_info *fs_info,
+                                   struct btrfs_space_info *space_info,
+                                   u64 num_bytes)
+{
+       struct reserve_ticket *ticket;
+       struct list_head *head = &space_info->priority_tickets;
+
+again:
+       while (!list_empty(head) && num_bytes) {
+               ticket = list_first_entry(head, struct reserve_ticket,
+                                         list);
+               if (num_bytes >= ticket->bytes) {
+                       trace_btrfs_space_reservation(fs_info, "space_info",
+                                                     space_info->flags,
+                                                     ticket->bytes, 1);
+                       list_del_init(&ticket->list);
+                       num_bytes -= ticket->bytes;
+                       btrfs_space_info_update_bytes_may_use(fs_info,
+                                                             space_info,
+                                                             ticket->bytes);
+                       ticket->bytes = 0;
+                       space_info->tickets_id++;
+                       wake_up(&ticket->wait);
+               } else {
+                       trace_btrfs_space_reservation(fs_info, "space_info",
+                                                     space_info->flags,
+                                                     num_bytes, 1);
+                       btrfs_space_info_update_bytes_may_use(fs_info,
+                                                             space_info,
+                                                             num_bytes);
+                       ticket->bytes -= num_bytes;
+                       num_bytes = 0;
+               }
+       }
+
+       if (num_bytes && head == &space_info->priority_tickets) {
+               head = &space_info->tickets;
+               goto again;
+       }
+}
+
+#define DUMP_BLOCK_RSV(fs_info, rsv_name)                              \
+do {                                                                   \
+       struct btrfs_block_rsv *__rsv = &(fs_info)->rsv_name;           \
+       spin_lock(&__rsv->lock);                                        \
+       btrfs_info(fs_info, #rsv_name ": size %llu reserved %llu",      \
+                  __rsv->size, __rsv->reserved);                       \
+       spin_unlock(&__rsv->lock);                                      \
+} while (0)
+
+void btrfs_dump_space_info(struct btrfs_fs_info *fs_info,
+                          struct btrfs_space_info *info, u64 bytes,
+                          int dump_block_groups)
+{
+       struct btrfs_block_group_cache *cache;
+       int index = 0;
+
+       spin_lock(&info->lock);
+       btrfs_info(fs_info, "space_info %llu has %llu free, is %sfull",
+                  info->flags,
+                  info->total_bytes - btrfs_space_info_used(info, true),
+                  info->full ? "" : "not ");
+       btrfs_info(fs_info,
+               "space_info total=%llu, used=%llu, pinned=%llu, reserved=%llu, may_use=%llu, readonly=%llu",
+               info->total_bytes, info->bytes_used, info->bytes_pinned,
+               info->bytes_reserved, info->bytes_may_use,
+               info->bytes_readonly);
+       spin_unlock(&info->lock);
+
+       DUMP_BLOCK_RSV(fs_info, global_block_rsv);
+       DUMP_BLOCK_RSV(fs_info, trans_block_rsv);
+       DUMP_BLOCK_RSV(fs_info, chunk_block_rsv);
+       DUMP_BLOCK_RSV(fs_info, delayed_block_rsv);
+       DUMP_BLOCK_RSV(fs_info, delayed_refs_rsv);
+
+       if (!dump_block_groups)
+               return;
+
+       down_read(&info->groups_sem);
+again:
+       list_for_each_entry(cache, &info->block_groups[index], list) {
+               spin_lock(&cache->lock);
+               btrfs_info(fs_info,
+                       "block group %llu has %llu bytes, %llu used %llu pinned %llu reserved %s",
+                       cache->key.objectid, cache->key.offset,
+                       btrfs_block_group_used(&cache->item), cache->pinned,
+                       cache->reserved, cache->ro ? "[readonly]" : "");
+               btrfs_dump_free_space(cache, bytes);
+               spin_unlock(&cache->lock);
+       }
+       if (++index < BTRFS_NR_RAID_TYPES)
+               goto again;
+       up_read(&info->groups_sem);
+}
+
+static void btrfs_writeback_inodes_sb_nr(struct btrfs_fs_info *fs_info,
+                                        unsigned long nr_pages, int nr_items)
+{
+       struct super_block *sb = fs_info->sb;
+
+       if (down_read_trylock(&sb->s_umount)) {
+               writeback_inodes_sb_nr(sb, nr_pages, WB_REASON_FS_FREE_SPACE);
+               up_read(&sb->s_umount);
+       } else {
+               /*
+                * We needn't worry the filesystem going from r/w to r/o though
+                * we don't acquire ->s_umount mutex, because the filesystem
+                * should guarantee the delalloc inodes list be empty after
+                * the filesystem is readonly(all dirty pages are written to
+                * the disk).
+                */
+               btrfs_start_delalloc_roots(fs_info, nr_items);
+               if (!current->journal_info)
+                       btrfs_wait_ordered_roots(fs_info, nr_items, 0, (u64)-1);
+       }
+}
+
+static inline u64 calc_reclaim_items_nr(struct btrfs_fs_info *fs_info,
+                                       u64 to_reclaim)
+{
+       u64 bytes;
+       u64 nr;
+
+       bytes = btrfs_calc_trans_metadata_size(fs_info, 1);
+       nr = div64_u64(to_reclaim, bytes);
+       if (!nr)
+               nr = 1;
+       return nr;
+}
+
+#define EXTENT_SIZE_PER_ITEM   SZ_256K
+
+/*
+ * shrink metadata reservation for delalloc
+ */
+static void shrink_delalloc(struct btrfs_fs_info *fs_info, u64 to_reclaim,
+                           u64 orig, bool wait_ordered)
+{
+       struct btrfs_space_info *space_info;
+       struct btrfs_trans_handle *trans;
+       u64 delalloc_bytes;
+       u64 dio_bytes;
+       u64 async_pages;
+       u64 items;
+       long time_left;
+       unsigned long nr_pages;
+       int loops;
+
+       /* Calc the number of the pages we need flush for space reservation */
+       items = calc_reclaim_items_nr(fs_info, to_reclaim);
+       to_reclaim = items * EXTENT_SIZE_PER_ITEM;
+
+       trans = (struct btrfs_trans_handle *)current->journal_info;
+       space_info = btrfs_find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA);
+
+       delalloc_bytes = percpu_counter_sum_positive(
+                                               &fs_info->delalloc_bytes);
+       dio_bytes = percpu_counter_sum_positive(&fs_info->dio_bytes);
+       if (delalloc_bytes == 0 && dio_bytes == 0) {
+               if (trans)
+                       return;
+               if (wait_ordered)
+                       btrfs_wait_ordered_roots(fs_info, items, 0, (u64)-1);
+               return;
+       }
+
+       /*
+        * If we are doing more ordered than delalloc we need to just wait on
+        * ordered extents, otherwise we'll waste time trying to flush delalloc
+        * that likely won't give us the space back we need.
+        */
+       if (dio_bytes > delalloc_bytes)
+               wait_ordered = true;
+
+       loops = 0;
+       while ((delalloc_bytes || dio_bytes) && loops < 3) {
+               nr_pages = min(delalloc_bytes, to_reclaim) >> PAGE_SHIFT;
+
+               /*
+                * Triggers inode writeback for up to nr_pages. This will invoke
+                * ->writepages callback and trigger delalloc filling
+                *  (btrfs_run_delalloc_range()).
+                */
+               btrfs_writeback_inodes_sb_nr(fs_info, nr_pages, items);
+
+               /*
+                * We need to wait for the compressed pages to start before
+                * we continue.
+                */
+               async_pages = atomic_read(&fs_info->async_delalloc_pages);
+               if (!async_pages)
+                       goto skip_async;
+
+               /*
+                * Calculate how many compressed pages we want to be written
+                * before we continue. I.e if there are more async pages than we
+                * require wait_event will wait until nr_pages are written.
+                */
+               if (async_pages <= nr_pages)
+                       async_pages = 0;
+               else
+                       async_pages -= nr_pages;
+
+               wait_event(fs_info->async_submit_wait,
+                          atomic_read(&fs_info->async_delalloc_pages) <=
+                          (int)async_pages);
+skip_async:
+               spin_lock(&space_info->lock);
+               if (list_empty(&space_info->tickets) &&
+                   list_empty(&space_info->priority_tickets)) {
+                       spin_unlock(&space_info->lock);
+                       break;
+               }
+               spin_unlock(&space_info->lock);
+
+               loops++;
+               if (wait_ordered && !trans) {
+                       btrfs_wait_ordered_roots(fs_info, items, 0, (u64)-1);
+               } else {
+                       time_left = schedule_timeout_killable(1);
+                       if (time_left)
+                               break;
+               }
+               delalloc_bytes = percpu_counter_sum_positive(
+                                               &fs_info->delalloc_bytes);
+               dio_bytes = percpu_counter_sum_positive(&fs_info->dio_bytes);
+       }
+}
+
+/**
+ * maybe_commit_transaction - possibly commit the transaction if its ok to
+ * @root - the root we're allocating for
+ * @bytes - the number of bytes we want to reserve
+ * @force - force the commit
+ *
+ * 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_trans_handle *trans;
+       u64 bytes_needed;
+       u64 reclaim_bytes = 0;
+
+       trans = (struct btrfs_trans_handle *)current->journal_info;
+       if (trans)
+               return -EAGAIN;
+
+       spin_lock(&space_info->lock);
+       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);
+       bytes_needed = (ticket) ? ticket->bytes : 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 reservation for
+        * this reservation.
+        */
+       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);
+       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
+ * state of @space_info to detect the outcome.
+ */
+static void flush_space(struct btrfs_fs_info *fs_info,
+                      struct btrfs_space_info *space_info, u64 num_bytes,
+                      int state)
+{
+       struct btrfs_root *root = fs_info->extent_root;
+       struct btrfs_trans_handle *trans;
+       int nr;
+       int ret = 0;
+
+       switch (state) {
+       case FLUSH_DELAYED_ITEMS_NR:
+       case FLUSH_DELAYED_ITEMS:
+               if (state == FLUSH_DELAYED_ITEMS_NR)
+                       nr = calc_reclaim_items_nr(fs_info, num_bytes) * 2;
+               else
+                       nr = -1;
+
+               trans = btrfs_join_transaction(root);
+               if (IS_ERR(trans)) {
+                       ret = PTR_ERR(trans);
+                       break;
+               }
+               ret = btrfs_run_delayed_items_nr(trans, nr);
+               btrfs_end_transaction(trans);
+               break;
+       case FLUSH_DELALLOC:
+       case FLUSH_DELALLOC_WAIT:
+               shrink_delalloc(fs_info, num_bytes * 2, num_bytes,
+                               state == FLUSH_DELALLOC_WAIT);
+               break;
+       case FLUSH_DELAYED_REFS_NR:
+       case FLUSH_DELAYED_REFS:
+               trans = btrfs_join_transaction(root);
+               if (IS_ERR(trans)) {
+                       ret = PTR_ERR(trans);
+                       break;
+               }
+               if (state == FLUSH_DELAYED_REFS_NR)
+                       nr = calc_reclaim_items_nr(fs_info, num_bytes);
+               else
+                       nr = 0;
+               btrfs_run_delayed_refs(trans, nr);
+               btrfs_end_transaction(trans);
+               break;
+       case ALLOC_CHUNK:
+       case ALLOC_CHUNK_FORCE:
+               trans = btrfs_join_transaction(root);
+               if (IS_ERR(trans)) {
+                       ret = PTR_ERR(trans);
+                       break;
+               }
+               ret = btrfs_chunk_alloc(trans,
+                               btrfs_metadata_alloc_profile(fs_info),
+                               (state == ALLOC_CHUNK) ? CHUNK_ALLOC_NO_FORCE :
+                                       CHUNK_ALLOC_FORCE);
+               btrfs_end_transaction(trans);
+               if (ret > 0 || ret == -ENOSPC)
+                       ret = 0;
+               break;
+       case COMMIT_TRANS:
+               /*
+                * If we have pending delayed iputs then we could free up a
+                * bunch of pinned space, so make sure we run the iputs before
+                * we do our pinned bytes check below.
+                */
+               btrfs_run_delayed_iputs(fs_info);
+               btrfs_wait_on_delayed_iputs(fs_info);
+
+               ret = may_commit_transaction(fs_info, space_info);
+               break;
+       default:
+               ret = -ENOSPC;
+               break;
+       }
+
+       trace_btrfs_flush_space(fs_info, space_info->flags, num_bytes, state,
+                               ret);
+       return;
+}
+
+static inline u64
+btrfs_calc_reclaim_metadata_size(struct btrfs_fs_info *fs_info,
+                                struct btrfs_space_info *space_info,
+                                bool system_chunk)
+{
+       struct reserve_ticket *ticket;
+       u64 used;
+       u64 expected;
+       u64 to_reclaim = 0;
+
+       list_for_each_entry(ticket, &space_info->tickets, list)
+               to_reclaim += ticket->bytes;
+       list_for_each_entry(ticket, &space_info->priority_tickets, list)
+               to_reclaim += ticket->bytes;
+       if (to_reclaim)
+               return to_reclaim;
+
+       to_reclaim = min_t(u64, num_online_cpus() * SZ_1M, SZ_16M);
+       if (can_overcommit(fs_info, space_info, to_reclaim,
+                          BTRFS_RESERVE_FLUSH_ALL, system_chunk))
+               return 0;
+
+       used = btrfs_space_info_used(space_info, true);
+
+       if (can_overcommit(fs_info, space_info, SZ_1M,
+                          BTRFS_RESERVE_FLUSH_ALL, system_chunk))
+               expected = div_factor_fine(space_info->total_bytes, 95);
+       else
+               expected = div_factor_fine(space_info->total_bytes, 90);
+
+       if (used > expected)
+               to_reclaim = used - expected;
+       else
+               to_reclaim = 0;
+       to_reclaim = min(to_reclaim, space_info->bytes_may_use +
+                                    space_info->bytes_reserved);
+       return to_reclaim;
+}
+
+static inline int need_do_async_reclaim(struct btrfs_fs_info *fs_info,
+                                       struct btrfs_space_info *space_info,
+                                       u64 used, bool system_chunk)
+{
+       u64 thresh = div_factor_fine(space_info->total_bytes, 98);
+
+       /* If we're just plain full then async reclaim just slows us down. */
+       if ((space_info->bytes_used + space_info->bytes_reserved) >= thresh)
+               return 0;
+
+       if (!btrfs_calc_reclaim_metadata_size(fs_info, space_info,
+                                             system_chunk))
+               return 0;
+
+       return (used >= thresh && !btrfs_fs_closing(fs_info) &&
+               !test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state));
+}
+
+static bool wake_all_tickets(struct list_head *head)
+{
+       struct reserve_ticket *ticket;
+
+       while (!list_empty(head)) {
+               ticket = list_first_entry(head, struct reserve_ticket, list);
+               list_del_init(&ticket->list);
+               ticket->error = -ENOSPC;
+               wake_up(&ticket->wait);
+               if (ticket->bytes != ticket->orig_bytes)
+                       return true;
+       }
+       return false;
+}
+
+/*
+ * This is for normal flushers, we can wait all goddamned day if we want to.  We
+ * will loop and continuously try to flush as long as we are making progress.
+ * We count progress as clearing off tickets each time we have to loop.
+ */
+static void btrfs_async_reclaim_metadata_space(struct work_struct *work)
+{
+       struct btrfs_fs_info *fs_info;
+       struct btrfs_space_info *space_info;
+       u64 to_reclaim;
+       int flush_state;
+       int commit_cycles = 0;
+       u64 last_tickets_id;
+
+       fs_info = container_of(work, struct btrfs_fs_info, async_reclaim_work);
+       space_info = btrfs_find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA);
+
+       spin_lock(&space_info->lock);
+       to_reclaim = btrfs_calc_reclaim_metadata_size(fs_info, space_info,
+                                                     false);
+       if (!to_reclaim) {
+               space_info->flush = 0;
+               spin_unlock(&space_info->lock);
+               return;
+       }
+       last_tickets_id = space_info->tickets_id;
+       spin_unlock(&space_info->lock);
+
+       flush_state = FLUSH_DELAYED_ITEMS_NR;
+       do {
+               flush_space(fs_info, space_info, to_reclaim, flush_state);
+               spin_lock(&space_info->lock);
+               if (list_empty(&space_info->tickets)) {
+                       space_info->flush = 0;
+                       spin_unlock(&space_info->lock);
+                       return;
+               }
+               to_reclaim = btrfs_calc_reclaim_metadata_size(fs_info,
+                                                             space_info,
+                                                             false);
+               if (last_tickets_id == space_info->tickets_id) {
+                       flush_state++;
+               } else {
+                       last_tickets_id = space_info->tickets_id;
+                       flush_state = FLUSH_DELAYED_ITEMS_NR;
+                       if (commit_cycles)
+                               commit_cycles--;
+               }
+
+               /*
+                * We don't want to force a chunk allocation until we've tried
+                * pretty hard to reclaim space.  Think of the case where we
+                * freed up a bunch of space and so have a lot of pinned space
+                * to reclaim.  We would rather use that than possibly create a
+                * underutilized metadata chunk.  So if this is our first run
+                * through the flushing state machine skip ALLOC_CHUNK_FORCE and
+                * commit the transaction.  If nothing has changed the next go
+                * around then we can force a chunk allocation.
+                */
+               if (flush_state == ALLOC_CHUNK_FORCE && !commit_cycles)
+                       flush_state++;
+
+               if (flush_state > COMMIT_TRANS) {
+                       commit_cycles++;
+                       if (commit_cycles > 2) {
+                               if (wake_all_tickets(&space_info->tickets)) {
+                                       flush_state = FLUSH_DELAYED_ITEMS_NR;
+                                       commit_cycles--;
+                               } else {
+                                       space_info->flush = 0;
+                               }
+                       } else {
+                               flush_state = FLUSH_DELAYED_ITEMS_NR;
+                       }
+               }
+               spin_unlock(&space_info->lock);
+       } while (flush_state <= COMMIT_TRANS);
+}
+
+void btrfs_init_async_reclaim_work(struct work_struct *work)
+{
+       INIT_WORK(work, btrfs_async_reclaim_metadata_space);
+}
+
+static const enum btrfs_flush_state priority_flush_states[] = {
+       FLUSH_DELAYED_ITEMS_NR,
+       FLUSH_DELAYED_ITEMS,
+       ALLOC_CHUNK,
+};
+
+static void priority_reclaim_metadata_space(struct btrfs_fs_info *fs_info,
+                                           struct btrfs_space_info *space_info,
+                                           struct reserve_ticket *ticket)
+{
+       u64 to_reclaim;
+       int flush_state;
+
+       spin_lock(&space_info->lock);
+       to_reclaim = btrfs_calc_reclaim_metadata_size(fs_info, space_info,
+                                                     false);
+       if (!to_reclaim) {
+               spin_unlock(&space_info->lock);
+               return;
+       }
+       spin_unlock(&space_info->lock);
+
+       flush_state = 0;
+       do {
+               flush_space(fs_info, space_info, to_reclaim,
+                           priority_flush_states[flush_state]);
+               flush_state++;
+               spin_lock(&space_info->lock);
+               if (ticket->bytes == 0) {
+                       spin_unlock(&space_info->lock);
+                       return;
+               }
+               spin_unlock(&space_info->lock);
+       } while (flush_state < ARRAY_SIZE(priority_flush_states));
+}
+
+static int wait_reserve_ticket(struct btrfs_fs_info *fs_info,
+                              struct btrfs_space_info *space_info,
+                              struct reserve_ticket *ticket)
+
+{
+       DEFINE_WAIT(wait);
+       u64 reclaim_bytes = 0;
+       int ret = 0;
+
+       spin_lock(&space_info->lock);
+       while (ticket->bytes > 0 && ticket->error == 0) {
+               ret = prepare_to_wait_event(&ticket->wait, &wait, TASK_KILLABLE);
+               if (ret) {
+                       ret = -EINTR;
+                       break;
+               }
+               spin_unlock(&space_info->lock);
+
+               schedule();
+
+               finish_wait(&ticket->wait, &wait);
+               spin_lock(&space_info->lock);
+       }
+       if (!ret)
+               ret = ticket->error;
+       if (!list_empty(&ticket->list))
+               list_del_init(&ticket->list);
+       if (ticket->bytes && ticket->bytes < ticket->orig_bytes)
+               reclaim_bytes = ticket->orig_bytes - ticket->bytes;
+       spin_unlock(&space_info->lock);
+
+       if (reclaim_bytes)
+               btrfs_space_info_add_old_bytes(fs_info, space_info,
+                                              reclaim_bytes);
+       return ret;
+}
+
+/**
+ * reserve_metadata_bytes - try to reserve bytes from the block_rsv's space
+ * @root - the root we're allocating for
+ * @space_info - the space info we want to allocate from
+ * @orig_bytes - the number of bytes we want
+ * @flush - whether or not we can flush to make our reservation
+ *
+ * This will reserve orig_bytes number of bytes from the space info associated
+ * with the block_rsv.  If there is not enough space it will make an attempt to
+ * flush out space to make room.  It will do this by flushing delalloc if
+ * possible or committing the transaction.  If flush is 0 then no attempts to
+ * regain reservations will be made and this will fail if there is not enough
+ * space already.
+ */
+static int __reserve_metadata_bytes(struct btrfs_fs_info *fs_info,
+                                   struct btrfs_space_info *space_info,
+                                   u64 orig_bytes,
+                                   enum btrfs_reserve_flush_enum flush,
+                                   bool system_chunk)
+{
+       struct reserve_ticket ticket;
+       u64 used;
+       u64 reclaim_bytes = 0;
+       int ret = 0;
+
+       ASSERT(orig_bytes);
+       ASSERT(!current->journal_info || flush != BTRFS_RESERVE_FLUSH_ALL);
+
+       spin_lock(&space_info->lock);
+       ret = -ENOSPC;
+       used = btrfs_space_info_used(space_info, true);
+
+       /*
+        * Carry on if we have enough space (short-circuit) OR call
+        * can_overcommit() to ensure we can overcommit to continue.
+        */
+       if ((used + orig_bytes <= space_info->total_bytes) ||
+           can_overcommit(fs_info, space_info, orig_bytes, flush,
+                          system_chunk)) {
+               btrfs_space_info_update_bytes_may_use(fs_info, space_info,
+                                                     orig_bytes);
+               trace_btrfs_space_reservation(fs_info, "space_info",
+                                             space_info->flags, orig_bytes, 1);
+               ret = 0;
+       }
+
+       /*
+        * If we couldn't make a reservation then setup our reservation ticket
+        * and kick the async worker if it's not already running.
+        *
+        * If we are a priority flusher then we just need to add our ticket to
+        * the list and we will do our own flushing further down.
+        */
+       if (ret && flush != BTRFS_RESERVE_NO_FLUSH) {
+               ticket.orig_bytes = orig_bytes;
+               ticket.bytes = orig_bytes;
+               ticket.error = 0;
+               init_waitqueue_head(&ticket.wait);
+               if (flush == BTRFS_RESERVE_FLUSH_ALL) {
+                       list_add_tail(&ticket.list, &space_info->tickets);
+                       if (!space_info->flush) {
+                               space_info->flush = 1;
+                               trace_btrfs_trigger_flush(fs_info,
+                                                         space_info->flags,
+                                                         orig_bytes, flush,
+                                                         "enospc");
+                               queue_work(system_unbound_wq,
+                                          &fs_info->async_reclaim_work);
+                       }
+               } else {
+                       list_add_tail(&ticket.list,
+                                     &space_info->priority_tickets);
+               }
+       } else if (!ret && space_info->flags & BTRFS_BLOCK_GROUP_METADATA) {
+               used += orig_bytes;
+               /*
+                * We will do the space reservation dance during log replay,
+                * which means we won't have fs_info->fs_root set, so don't do
+                * the async reclaim as we will panic.
+                */
+               if (!test_bit(BTRFS_FS_LOG_RECOVERING, &fs_info->flags) &&
+                   need_do_async_reclaim(fs_info, space_info,
+                                         used, system_chunk) &&
+                   !work_busy(&fs_info->async_reclaim_work)) {
+                       trace_btrfs_trigger_flush(fs_info, space_info->flags,
+                                                 orig_bytes, flush, "preempt");
+                       queue_work(system_unbound_wq,
+                                  &fs_info->async_reclaim_work);
+               }
+       }
+       spin_unlock(&space_info->lock);
+       if (!ret || flush == BTRFS_RESERVE_NO_FLUSH)
+               return ret;
+
+       if (flush == BTRFS_RESERVE_FLUSH_ALL)
+               return wait_reserve_ticket(fs_info, space_info, &ticket);
+
+       ret = 0;
+       priority_reclaim_metadata_space(fs_info, space_info, &ticket);
+       spin_lock(&space_info->lock);
+       if (ticket.bytes) {
+               if (ticket.bytes < orig_bytes)
+                       reclaim_bytes = orig_bytes - ticket.bytes;
+               list_del_init(&ticket.list);
+               ret = -ENOSPC;
+       }
+       spin_unlock(&space_info->lock);
+
+       if (reclaim_bytes)
+               btrfs_space_info_add_old_bytes(fs_info, space_info,
+                                              reclaim_bytes);
+       ASSERT(list_empty(&ticket.list));
+       return ret;
+}
+
+/**
+ * reserve_metadata_bytes - try to reserve bytes from the block_rsv's space
+ * @root - the root we're allocating for
+ * @block_rsv - the block_rsv we're allocating for
+ * @orig_bytes - the number of bytes we want
+ * @flush - whether or not we can flush to make our reservation
+ *
+ * This will reserve orig_bytes number of bytes from the space info associated
+ * with the block_rsv.  If there is not enough space it will make an attempt to
+ * flush out space to make room.  It will do this by flushing delalloc if
+ * possible or committing the transaction.  If flush is 0 then no attempts to
+ * regain reservations will be made and this will fail if there is not enough
+ * space already.
+ */
+int btrfs_reserve_metadata_bytes(struct btrfs_root *root,
+                                struct btrfs_block_rsv *block_rsv,
+                                u64 orig_bytes,
+                                enum btrfs_reserve_flush_enum flush)
+{
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
+       int ret;
+       bool system_chunk = (root == fs_info->chunk_root);
+
+       ret = __reserve_metadata_bytes(fs_info, block_rsv->space_info,
+                                      orig_bytes, flush, system_chunk);
+       if (ret == -ENOSPC &&
+           unlikely(root->orphan_cleanup_state == ORPHAN_CLEANUP_STARTED)) {
+               if (block_rsv != global_rsv &&
+                   !btrfs_block_rsv_use_bytes(global_rsv, orig_bytes))
+                       ret = 0;
+       }
+       if (ret == -ENOSPC) {
+               trace_btrfs_space_reservation(fs_info, "space_info:enospc",
+                                             block_rsv->space_info->flags,
+                                             orig_bytes, 1);
+
+               if (btrfs_test_opt(fs_info, ENOSPC_DEBUG))
+                       btrfs_dump_space_info(fs_info, block_rsv->space_info,
+                                             orig_bytes, 0);
+       }
+       return ret;
+}
diff --git a/fs/btrfs/space-info.h b/fs/btrfs/space-info.h
new file mode 100644 (file)
index 0000000..c2b54b8
--- /dev/null
@@ -0,0 +1,133 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BTRFS_SPACE_INFO_H
+#define BTRFS_SPACE_INFO_H
+
+struct btrfs_space_info {
+       spinlock_t lock;
+
+       u64 total_bytes;        /* total bytes in the space,
+                                  this doesn't take mirrors into account */
+       u64 bytes_used;         /* total bytes used,
+                                  this doesn't take mirrors into account */
+       u64 bytes_pinned;       /* total bytes pinned, will be freed when the
+                                  transaction finishes */
+       u64 bytes_reserved;     /* total bytes the allocator has reserved for
+                                  current allocations */
+       u64 bytes_may_use;      /* number of bytes that may be used for
+                                  delalloc/allocations */
+       u64 bytes_readonly;     /* total bytes that are read only */
+
+       u64 max_extent_size;    /* This will hold the maximum extent size of
+                                  the space info if we had an ENOSPC in the
+                                  allocator. */
+
+       unsigned int full:1;    /* indicates that we cannot allocate any more
+                                  chunks for this space */
+       unsigned int chunk_alloc:1;     /* set if we are allocating a chunk */
+
+       unsigned int flush:1;           /* set if we are trying to make space */
+
+       unsigned int force_alloc;       /* set if we need to force a chunk
+                                          alloc for this space */
+
+       u64 disk_used;          /* total bytes used on disk */
+       u64 disk_total;         /* total bytes on disk, takes mirrors into
+                                  account */
+
+       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;
+       struct list_head priority_tickets;
+       struct list_head tickets;
+       /*
+        * tickets_id just indicates the next ticket will be handled, so note
+        * it's not stored per ticket.
+        */
+       u64 tickets_id;
+
+       struct rw_semaphore groups_sem;
+       /* for block groups in our same type */
+       struct list_head block_groups[BTRFS_NR_RAID_TYPES];
+       wait_queue_head_t wait;
+
+       struct kobject kobj;
+       struct kobject *block_group_kobjs[BTRFS_NR_RAID_TYPES];
+};
+
+struct reserve_ticket {
+       u64 orig_bytes;
+       u64 bytes;
+       int error;
+       struct list_head list;
+       wait_queue_head_t wait;
+};
+
+static inline bool btrfs_mixed_space_info(struct btrfs_space_info *space_info)
+{
+       return ((space_info->flags & BTRFS_BLOCK_GROUP_METADATA) &&
+               (space_info->flags & BTRFS_BLOCK_GROUP_DATA));
+}
+
+/*
+ *
+ * Declare a helper function to detect underflow of various space info members
+ */
+#define DECLARE_SPACE_INFO_UPDATE(name)                                        \
+static inline void                                                     \
+btrfs_space_info_update_##name(struct btrfs_fs_info *fs_info,          \
+                              struct btrfs_space_info *sinfo,          \
+                              s64 bytes)                               \
+{                                                                      \
+       lockdep_assert_held(&sinfo->lock);                              \
+       trace_update_##name(fs_info, sinfo, sinfo->name, bytes);        \
+       if (bytes < 0 && sinfo->name < -bytes) {                        \
+               WARN_ON(1);                                             \
+               sinfo->name = 0;                                        \
+               return;                                                 \
+       }                                                               \
+       sinfo->name += bytes;                                           \
+}
+
+DECLARE_SPACE_INFO_UPDATE(bytes_may_use);
+DECLARE_SPACE_INFO_UPDATE(bytes_pinned);
+
+void btrfs_space_info_add_new_bytes(struct btrfs_fs_info *fs_info,
+                                   struct btrfs_space_info *space_info,
+                                   u64 num_bytes);
+void btrfs_space_info_add_old_bytes(struct btrfs_fs_info *fs_info,
+                                   struct btrfs_space_info *space_info,
+                                   u64 num_bytes);
+int btrfs_init_space_info(struct btrfs_fs_info *fs_info);
+void btrfs_update_space_info(struct btrfs_fs_info *info, u64 flags,
+                            u64 total_bytes, u64 bytes_used,
+                            u64 bytes_readonly,
+                            struct btrfs_space_info **space_info);
+struct btrfs_space_info *btrfs_find_space_info(struct btrfs_fs_info *info,
+                                              u64 flags);
+u64 btrfs_space_info_used(struct btrfs_space_info *s_info,
+                         bool may_use_included);
+void btrfs_clear_space_info_full(struct btrfs_fs_info *info);
+void btrfs_dump_space_info(struct btrfs_fs_info *fs_info,
+                          struct btrfs_space_info *info, u64 bytes,
+                          int dump_block_groups);
+int btrfs_reserve_metadata_bytes(struct btrfs_root *root,
+                                struct btrfs_block_rsv *block_rsv,
+                                u64 orig_bytes,
+                                enum btrfs_reserve_flush_enum flush);
+
+#endif /* BTRFS_SPACE_INFO_H */
index 0645ec4..78de9d5 100644 (file)
@@ -42,6 +42,7 @@
 #include "dev-replace.h"
 #include "free-space-cache.h"
 #include "backref.h"
+#include "space-info.h"
 #include "tests/btrfs-tests.h"
 
 #include "qgroup.h"
@@ -1553,6 +1554,8 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
        } else {
                snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev);
                btrfs_sb(s)->bdev_holder = fs_type;
+               if (!strstr(crc32c_impl(), "generic"))
+                       set_bit(BTRFS_FS_CSUM_IMPL_FAST, &fs_info->flags);
                error = btrfs_fill_super(s, fs_devices, data);
        }
        if (!error)
@@ -1601,14 +1604,10 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
 {
        struct vfsmount *mnt_root;
        struct dentry *root;
-       fmode_t mode = FMODE_READ;
        char *subvol_name = NULL;
        u64 subvol_objectid = 0;
        int error = 0;
 
-       if (!(flags & SB_RDONLY))
-               mode |= FMODE_WRITE;
-
        error = btrfs_parse_subvol_options(data, &subvol_name,
                                        &subvol_objectid);
        if (error) {
@@ -1904,8 +1903,9 @@ static inline int btrfs_calc_avail_data_space(struct btrfs_fs_info *fs_info,
        u64 type;
        u64 avail_space;
        u64 min_stripe_size;
-       int min_stripes = 1, num_stripes = 1;
+       int min_stripes, num_stripes = 1;
        int i = 0, nr_devices;
+       const struct btrfs_raid_attr *rattr;
 
        /*
         * We aren't under the device list lock, so this is racy-ish, but good
@@ -1929,21 +1929,18 @@ static inline int btrfs_calc_avail_data_space(struct btrfs_fs_info *fs_info,
 
        /* calc min stripe number for data space allocation */
        type = btrfs_data_alloc_profile(fs_info);
-       if (type & BTRFS_BLOCK_GROUP_RAID0) {
-               min_stripes = 2;
+       rattr = &btrfs_raid_array[btrfs_bg_flags_to_raid_index(type)];
+       min_stripes = rattr->devs_min;
+
+       if (type & BTRFS_BLOCK_GROUP_RAID0)
                num_stripes = nr_devices;
-       } else if (type & BTRFS_BLOCK_GROUP_RAID1) {
-               min_stripes = 2;
+       else if (type & BTRFS_BLOCK_GROUP_RAID1)
                num_stripes = 2;
-       } else if (type & BTRFS_BLOCK_GROUP_RAID10) {
-               min_stripes = 4;
+       else if (type & BTRFS_BLOCK_GROUP_RAID10)
                num_stripes = 4;
-       }
 
-       if (type & BTRFS_BLOCK_GROUP_DUP)
-               min_stripe_size = 2 * BTRFS_STRIPE_LEN;
-       else
-               min_stripe_size = BTRFS_STRIPE_LEN;
+       /* Adjust for more than 1 stripe per device */
+       min_stripe_size = rattr->dev_stripes * BTRFS_STRIPE_LEN;
 
        rcu_read_lock();
        list_for_each_entry_rcu(device, &fs_devices->devices, dev_list) {
@@ -2466,3 +2463,4 @@ late_initcall(init_btrfs_fs);
 module_exit(exit_btrfs_fs)
 
 MODULE_LICENSE("GPL");
+MODULE_SOFTDEP("pre: crc32c");
index c1dfc97..9539f81 100644 (file)
@@ -16,6 +16,7 @@
 #include "transaction.h"
 #include "sysfs.h"
 #include "volumes.h"
+#include "space-info.h"
 
 static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj);
 static inline struct btrfs_fs_devices *to_fs_devs(struct kobject *kobj);
index 9238fd4..1e3ba49 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <linux/fs.h>
 #include <linux/mount.h>
+#include <linux/pseudo_fs.h>
 #include <linux/magic.h>
 #include "btrfs-tests.h"
 #include "../ctree.h"
@@ -32,17 +33,19 @@ static const struct super_operations btrfs_test_super_ops = {
        .destroy_inode  = btrfs_test_destroy_inode,
 };
 
-static struct dentry *btrfs_test_mount(struct file_system_type *fs_type,
-                                      int flags, const char *dev_name,
-                                      void *data)
+
+static int btrfs_test_init_fs_context(struct fs_context *fc)
 {
-       return mount_pseudo(fs_type, "btrfs_test:", &btrfs_test_super_ops,
-                           NULL, BTRFS_TEST_MAGIC);
+       struct pseudo_fs_context *ctx = init_pseudo(fc, BTRFS_TEST_MAGIC);
+       if (!ctx)
+               return -ENOMEM;
+       ctx->ops = &btrfs_test_super_ops;
+       return 0;
 }
 
 static struct file_system_type test_type = {
        .name           = "btrfs_test_fs",
-       .mount          = btrfs_test_mount,
+       .init_fs_context = btrfs_test_init_fs_context,
        .kill_sb        = kill_anon_super,
 };
 
index 7bf4d57..1bf6b5a 100644 (file)
@@ -10,6 +10,7 @@
 #include "btrfs-tests.h"
 #include "../ctree.h"
 #include "../extent_io.h"
+#include "../btrfs_inode.h"
 
 #define PROCESS_UNLOCK         (1 << 0)
 #define PROCESS_RELEASE                (1 << 1)
@@ -58,7 +59,7 @@ static noinline int process_page_range(struct inode *inode, u64 start, u64 end,
 static int test_find_delalloc(u32 sectorsize)
 {
        struct inode *inode;
-       struct extent_io_tree tmp;
+       struct extent_io_tree *tmp;
        struct page *page;
        struct page *locked_page = NULL;
        unsigned long index = 0;
@@ -76,12 +77,13 @@ static int test_find_delalloc(u32 sectorsize)
                test_std_err(TEST_ALLOC_INODE);
                return -ENOMEM;
        }
+       tmp = &BTRFS_I(inode)->io_tree;
 
        /*
         * Passing NULL as we don't have fs_info but tracepoints are not used
         * at this point
         */
-       extent_io_tree_init(NULL, &tmp, IO_TREE_SELFTEST, NULL);
+       extent_io_tree_init(NULL, tmp, IO_TREE_SELFTEST, NULL);
 
        /*
         * First go through and create and mark all of our pages dirty, we pin
@@ -108,10 +110,10 @@ static int test_find_delalloc(u32 sectorsize)
         * |--- delalloc ---|
         * |---  search  ---|
         */
-       set_extent_delalloc(&tmp, 0, sectorsize - 1, 0, NULL);
+       set_extent_delalloc(tmp, 0, sectorsize - 1, 0, NULL);
        start = 0;
        end = 0;
-       found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
+       found = find_lock_delalloc_range(inode, locked_page, &start,
                                         &end);
        if (!found) {
                test_err("should have found at least one delalloc");
@@ -122,7 +124,7 @@ static int test_find_delalloc(u32 sectorsize)
                        sectorsize - 1, start, end);
                goto out_bits;
        }
-       unlock_extent(&tmp, start, end);
+       unlock_extent(tmp, start, end);
        unlock_page(locked_page);
        put_page(locked_page);
 
@@ -139,10 +141,10 @@ static int test_find_delalloc(u32 sectorsize)
                test_err("couldn't find the locked page");
                goto out_bits;
        }
-       set_extent_delalloc(&tmp, sectorsize, max_bytes - 1, 0, NULL);
+       set_extent_delalloc(tmp, sectorsize, max_bytes - 1, 0, NULL);
        start = test_start;
        end = 0;
-       found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
+       found = find_lock_delalloc_range(inode, locked_page, &start,
                                         &end);
        if (!found) {
                test_err("couldn't find delalloc in our range");
@@ -158,7 +160,7 @@ static int test_find_delalloc(u32 sectorsize)
                test_err("there were unlocked pages in the range");
                goto out_bits;
        }
-       unlock_extent(&tmp, start, end);
+       unlock_extent(tmp, start, end);
        /* locked_page was unlocked above */
        put_page(locked_page);
 
@@ -176,7 +178,7 @@ static int test_find_delalloc(u32 sectorsize)
        }
        start = test_start;
        end = 0;
-       found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
+       found = find_lock_delalloc_range(inode, locked_page, &start,
                                         &end);
        if (found) {
                test_err("found range when we shouldn't have");
@@ -194,10 +196,10 @@ static int test_find_delalloc(u32 sectorsize)
         *
         * We are re-using our test_start from above since it works out well.
         */
-       set_extent_delalloc(&tmp, max_bytes, total_dirty - 1, 0, NULL);
+       set_extent_delalloc(tmp, max_bytes, total_dirty - 1, 0, NULL);
        start = test_start;
        end = 0;
-       found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
+       found = find_lock_delalloc_range(inode, locked_page, &start,
                                         &end);
        if (!found) {
                test_err("didn't find our range");
@@ -213,7 +215,7 @@ static int test_find_delalloc(u32 sectorsize)
                test_err("pages in range were not all locked");
                goto out_bits;
        }
-       unlock_extent(&tmp, start, end);
+       unlock_extent(tmp, start, end);
 
        /*
         * Now to test where we run into a page that is no longer dirty in the
@@ -238,7 +240,7 @@ static int test_find_delalloc(u32 sectorsize)
         * this changes at any point in the future we will need to fix this
         * tests expected behavior.
         */
-       found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
+       found = find_lock_delalloc_range(inode, locked_page, &start,
                                         &end);
        if (!found) {
                test_err("didn't find our range");
@@ -256,7 +258,7 @@ static int test_find_delalloc(u32 sectorsize)
        }
        ret = 0;
 out_bits:
-       clear_extent_bits(&tmp, 0, total_dirty - 1, (unsigned)-1);
+       clear_extent_bits(tmp, 0, total_dirty - 1, (unsigned)-1);
 out:
        if (locked_page)
                put_page(locked_page);
@@ -432,6 +434,89 @@ out:
        return ret;
 }
 
+static int test_find_first_clear_extent_bit(void)
+{
+       struct extent_io_tree tree;
+       u64 start, end;
+
+       test_msg("running find_first_clear_extent_bit test");
+       extent_io_tree_init(NULL, &tree, IO_TREE_SELFTEST, NULL);
+
+       /*
+        * Set 1M-4M alloc/discard and 32M-64M thus leaving a hole between
+        * 4M-32M
+        */
+       set_extent_bits(&tree, SZ_1M, SZ_4M - 1,
+                       CHUNK_TRIMMED | CHUNK_ALLOCATED);
+
+       find_first_clear_extent_bit(&tree, SZ_512K, &start, &end,
+                                   CHUNK_TRIMMED | CHUNK_ALLOCATED);
+
+       if (start != 0 || end != SZ_1M -1)
+               test_err("error finding beginning range: start %llu end %llu",
+                        start, end);
+
+       /* Now add 32M-64M so that we have a hole between 4M-32M */
+       set_extent_bits(&tree, SZ_32M, SZ_64M - 1,
+                       CHUNK_TRIMMED | CHUNK_ALLOCATED);
+
+       /*
+        * Request first hole starting at 12M, we should get 4M-32M
+        */
+       find_first_clear_extent_bit(&tree, 12 * SZ_1M, &start, &end,
+                                   CHUNK_TRIMMED | CHUNK_ALLOCATED);
+
+       if (start != SZ_4M || end != SZ_32M - 1)
+               test_err("error finding trimmed range: start %llu end %llu",
+                        start, end);
+
+       /*
+        * Search in the middle of allocated range, should get the next one
+        * available, which happens to be unallocated -> 4M-32M
+        */
+       find_first_clear_extent_bit(&tree, SZ_2M, &start, &end,
+                                   CHUNK_TRIMMED | CHUNK_ALLOCATED);
+
+       if (start != SZ_4M || end != SZ_32M -1)
+               test_err("error finding next unalloc range: start %llu end %llu",
+                        start, end);
+
+       /*
+        * Set 64M-72M with CHUNK_ALLOC flag, then search for CHUNK_TRIMMED flag
+        * being unset in this range, we should get the entry in range 64M-72M
+        */
+       set_extent_bits(&tree, SZ_64M, SZ_64M + SZ_8M - 1, CHUNK_ALLOCATED);
+       find_first_clear_extent_bit(&tree, SZ_64M + SZ_1M, &start, &end,
+                                   CHUNK_TRIMMED);
+
+       if (start != SZ_64M || end != SZ_64M + SZ_8M - 1)
+               test_err("error finding exact range: start %llu end %llu",
+                        start, end);
+
+       find_first_clear_extent_bit(&tree, SZ_64M - SZ_8M, &start, &end,
+                                   CHUNK_TRIMMED);
+
+       /*
+        * Search in the middle of set range whose immediate neighbour doesn't
+        * have the bits set so it must be returned
+        */
+       if (start != SZ_64M || end != SZ_64M + SZ_8M - 1)
+               test_err("error finding next alloc range: start %llu end %llu",
+                        start, end);
+
+       /*
+        * Search beyond any known range, shall return after last known range
+        * and end should be -1
+        */
+       find_first_clear_extent_bit(&tree, -1, &start, &end, CHUNK_TRIMMED);
+       if (start != SZ_64M + SZ_8M || end != -1)
+               test_err(
+               "error handling beyond end of range search: start %llu end %llu",
+                       start, end);
+
+       return 0;
+}
+
 int btrfs_test_extent_io(u32 sectorsize, u32 nodesize)
 {
        int ret;
@@ -442,6 +527,10 @@ int btrfs_test_extent_io(u32 sectorsize, u32 nodesize)
        if (ret)
                goto out;
 
+       ret = test_find_first_clear_extent_bit();
+       if (ret)
+               goto out;
+
        ret = test_eb_bitmaps(sectorsize, nodesize);
 out:
        return ret;
index 87aeabe..4a7f796 100644 (file)
@@ -66,7 +66,9 @@ static int test_case_1(struct btrfs_fs_info *fs_info,
        em->len = SZ_16K;
        em->block_start = 0;
        em->block_len = SZ_16K;
+       write_lock(&em_tree->lock);
        ret = add_extent_mapping(em_tree, em, 0);
+       write_unlock(&em_tree->lock);
        if (ret < 0) {
                test_err("cannot add extent range [0, 16K)");
                goto out;
@@ -85,7 +87,9 @@ static int test_case_1(struct btrfs_fs_info *fs_info,
        em->len = SZ_4K;
        em->block_start = SZ_32K; /* avoid merging */
        em->block_len = SZ_4K;
+       write_lock(&em_tree->lock);
        ret = add_extent_mapping(em_tree, em, 0);
+       write_unlock(&em_tree->lock);
        if (ret < 0) {
                test_err("cannot add extent range [16K, 20K)");
                goto out;
@@ -104,7 +108,9 @@ static int test_case_1(struct btrfs_fs_info *fs_info,
        em->len = len;
        em->block_start = start;
        em->block_len = len;
+       write_lock(&em_tree->lock);
        ret = btrfs_add_extent_mapping(fs_info, em_tree, &em, em->start, em->len);
+       write_unlock(&em_tree->lock);
        if (ret) {
                test_err("case1 [%llu %llu]: ret %d", start, start + len, ret);
                goto out;
@@ -148,7 +154,9 @@ static int test_case_2(struct btrfs_fs_info *fs_info,
        em->len = SZ_1K;
        em->block_start = EXTENT_MAP_INLINE;
        em->block_len = (u64)-1;
+       write_lock(&em_tree->lock);
        ret = add_extent_mapping(em_tree, em, 0);
+       write_unlock(&em_tree->lock);
        if (ret < 0) {
                test_err("cannot add extent range [0, 1K)");
                goto out;
@@ -167,7 +175,9 @@ static int test_case_2(struct btrfs_fs_info *fs_info,
        em->len = SZ_4K;
        em->block_start = SZ_4K;
        em->block_len = SZ_4K;
+       write_lock(&em_tree->lock);
        ret = add_extent_mapping(em_tree, em, 0);
+       write_unlock(&em_tree->lock);
        if (ret < 0) {
                test_err("cannot add extent range [4K, 8K)");
                goto out;
@@ -186,7 +196,9 @@ static int test_case_2(struct btrfs_fs_info *fs_info,
        em->len = SZ_1K;
        em->block_start = EXTENT_MAP_INLINE;
        em->block_len = (u64)-1;
+       write_lock(&em_tree->lock);
        ret = btrfs_add_extent_mapping(fs_info, em_tree, &em, em->start, em->len);
+       write_unlock(&em_tree->lock);
        if (ret) {
                test_err("case2 [0 1K]: ret %d", ret);
                goto out;
@@ -225,7 +237,9 @@ static int __test_case_3(struct btrfs_fs_info *fs_info,
        em->len = SZ_4K;
        em->block_start = SZ_4K;
        em->block_len = SZ_4K;
+       write_lock(&em_tree->lock);
        ret = add_extent_mapping(em_tree, em, 0);
+       write_unlock(&em_tree->lock);
        if (ret < 0) {
                test_err("cannot add extent range [4K, 8K)");
                goto out;
@@ -244,7 +258,9 @@ static int __test_case_3(struct btrfs_fs_info *fs_info,
        em->len = SZ_16K;
        em->block_start = 0;
        em->block_len = SZ_16K;
+       write_lock(&em_tree->lock);
        ret = btrfs_add_extent_mapping(fs_info, em_tree, &em, start, len);
+       write_unlock(&em_tree->lock);
        if (ret) {
                test_err("case3 [0x%llx 0x%llx): ret %d",
                         start, start + len, ret);
@@ -320,7 +336,9 @@ static int __test_case_4(struct btrfs_fs_info *fs_info,
        em->len = SZ_8K;
        em->block_start = 0;
        em->block_len = SZ_8K;
+       write_lock(&em_tree->lock);
        ret = add_extent_mapping(em_tree, em, 0);
+       write_unlock(&em_tree->lock);
        if (ret < 0) {
                test_err("cannot add extent range [0, 8K)");
                goto out;
@@ -339,7 +357,9 @@ static int __test_case_4(struct btrfs_fs_info *fs_info,
        em->len = 24 * SZ_1K;
        em->block_start = SZ_16K; /* avoid merging */
        em->block_len = 24 * SZ_1K;
+       write_lock(&em_tree->lock);
        ret = add_extent_mapping(em_tree, em, 0);
+       write_unlock(&em_tree->lock);
        if (ret < 0) {
                test_err("cannot add extent range [8K, 32K)");
                goto out;
@@ -357,7 +377,9 @@ static int __test_case_4(struct btrfs_fs_info *fs_info,
        em->len = SZ_32K;
        em->block_start = 0;
        em->block_len = SZ_32K;
+       write_lock(&em_tree->lock);
        ret = btrfs_add_extent_mapping(fs_info, em_tree, &em, start, len);
+       write_unlock(&em_tree->lock);
        if (ret) {
                test_err("case4 [0x%llx 0x%llx): ret %d",
                         start, len, ret);
index 3f6811c..3b8ae1a 100644 (file)
@@ -129,6 +129,24 @@ static inline int extwriter_counter_read(struct btrfs_transaction *trans)
 }
 
 /*
+ * To be called after all the new block groups attached to the transaction
+ * handle have been created (btrfs_create_pending_block_groups()).
+ */
+void btrfs_trans_release_chunk_metadata(struct btrfs_trans_handle *trans)
+{
+       struct btrfs_fs_info *fs_info = trans->fs_info;
+
+       if (!trans->chunk_bytes_reserved)
+               return;
+
+       WARN_ON_ONCE(!list_empty(&trans->new_bgs));
+
+       btrfs_block_rsv_release(fs_info, &fs_info->chunk_block_rsv,
+                               trans->chunk_bytes_reserved);
+       trans->chunk_bytes_reserved = 0;
+}
+
+/*
  * either allocate a new transaction or hop into the existing one
  */
 static noinline int join_transaction(struct btrfs_fs_info *fs_info,
index 78c446c..527ea94 100644 (file)
@@ -224,5 +224,6 @@ void btrfs_put_transaction(struct btrfs_transaction *transaction);
 void btrfs_apply_pending_changes(struct btrfs_fs_info *fs_info);
 void btrfs_add_dropped_root(struct btrfs_trans_handle *trans,
                            struct btrfs_root *root);
+void btrfs_trans_release_chunk_metadata(struct btrfs_trans_handle *trans);
 
 #endif
index 96fce4b..ccd5706 100644 (file)
@@ -132,6 +132,7 @@ static int check_extent_data_item(struct extent_buffer *leaf,
        struct btrfs_file_extent_item *fi;
        u32 sectorsize = fs_info->sectorsize;
        u32 item_size = btrfs_item_size_nr(leaf, slot);
+       u64 extent_end;
 
        if (!IS_ALIGNED(key->offset, sectorsize)) {
                file_extent_err(leaf, slot,
@@ -207,6 +208,16 @@ static int check_extent_data_item(struct extent_buffer *leaf,
            CHECK_FE_ALIGNED(leaf, slot, fi, num_bytes, sectorsize))
                return -EUCLEAN;
 
+       /* Catch extent end overflow */
+       if (check_add_overflow(btrfs_file_extent_num_bytes(leaf, fi),
+                              key->offset, &extent_end)) {
+               file_extent_err(leaf, slot,
+       "extent end overflow, have file offset %llu extent num bytes %llu",
+                               key->offset,
+                               btrfs_file_extent_num_bytes(leaf, fi));
+               return -EUCLEAN;
+       }
+
        /*
         * Check that no two consecutive file extent items, in the same leaf,
         * present ranges that overlap each other.
index 3fc8d85..6c8297b 100644 (file)
@@ -3323,6 +3323,30 @@ int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
 }
 
 /*
+ * Check if an inode was logged in the current transaction. We can't always rely
+ * on an inode's logged_trans value, because it's an in-memory only field and
+ * therefore not persisted. This means that its value is lost if the inode gets
+ * evicted and loaded again from disk (in which case it has a value of 0, and
+ * certainly it is smaller then any possible transaction ID), when that happens
+ * the full_sync flag is set in the inode's runtime flags, so on that case we
+ * assume eviction happened and ignore the logged_trans value, assuming the
+ * worst case, that the inode was logged before in the current transaction.
+ */
+static bool inode_logged(struct btrfs_trans_handle *trans,
+                        struct btrfs_inode *inode)
+{
+       if (inode->logged_trans == trans->transid)
+               return true;
+
+       if (inode->last_trans == trans->transid &&
+           test_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &inode->runtime_flags) &&
+           !test_bit(BTRFS_FS_LOG_RECOVERING, &trans->fs_info->flags))
+               return true;
+
+       return false;
+}
+
+/*
  * If both a file and directory are logged, and unlinks or renames are
  * mixed in, we have a few interesting corners:
  *
@@ -3356,7 +3380,7 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
        int bytes_del = 0;
        u64 dir_ino = btrfs_ino(dir);
 
-       if (dir->logged_trans < trans->transid)
+       if (!inode_logged(trans, dir))
                return 0;
 
        ret = join_running_log_trans(root);
@@ -3460,7 +3484,7 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
        u64 index;
        int ret;
 
-       if (inode->logged_trans < trans->transid)
+       if (!inode_logged(trans, inode))
                return 0;
 
        ret = join_running_log_trans(root);
@@ -5420,9 +5444,19 @@ log_extents:
                }
        }
 
+       /*
+        * Don't update last_log_commit if we logged that an inode exists after
+        * it was loaded to memory (full_sync bit set).
+        * This is to prevent data loss when we do a write to the inode, then
+        * the inode gets evicted after all delalloc was flushed, then we log
+        * it exists (due to a rename for example) and then fsync it. This last
+        * fsync would do nothing (not logging the extents previously written).
+        */
        spin_lock(&inode->lock);
        inode->logged_trans = trans->transid;
-       inode->last_log_commit = inode->last_sub_trans;
+       if (inode_only != LOG_INODE_EXISTS ||
+           !test_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &inode->runtime_flags))
+               inode->last_log_commit = inode->last_sub_trans;
        spin_unlock(&inode->lock);
 out_unlock:
        mutex_unlock(&inode->log_mutex);
index 1c2a6e4..d74b74c 100644 (file)
@@ -28,6 +28,7 @@
 #include "dev-replace.h"
 #include "sysfs.h"
 #include "tree-checker.h"
+#include "space-info.h"
 
 const struct btrfs_raid_attr btrfs_raid_array[BTRFS_NR_RAID_TYPES] = {
        [BTRFS_RAID_RAID10] = {
@@ -123,12 +124,14 @@ const struct btrfs_raid_attr btrfs_raid_array[BTRFS_NR_RAID_TYPES] = {
        },
 };
 
-const char *get_raid_name(enum btrfs_raid_types type)
+const char *btrfs_bg_type_to_raid_name(u64 flags)
 {
-       if (type >= BTRFS_NR_RAID_TYPES)
+       const int index = btrfs_bg_flags_to_raid_index(flags);
+
+       if (index >= BTRFS_NR_RAID_TYPES)
                return NULL;
 
-       return btrfs_raid_array[type].raid_name;
+       return btrfs_raid_array[index].raid_name;
 }
 
 /*
@@ -237,7 +240,9 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info,
  * chunk_mutex
  * -----------
  * protects chunks, adding or removing during allocation, trim or when a new
- * device is added/removed
+ * device is added/removed. Additionally it also protects post_commit_list of
+ * individual devices, since they can be added to the transaction's
+ * post_commit_list only with chunk_mutex held.
  *
  * cleaner_mutex
  * -------------
@@ -1818,7 +1823,7 @@ static u64 find_next_chunk(struct btrfs_fs_info *fs_info)
        struct rb_node *n;
        u64 ret = 0;
 
-       em_tree = &fs_info->mapping_tree.map_tree;
+       em_tree = &fs_info->mapping_tree;
        read_lock(&em_tree->lock);
        n = rb_last(&em_tree->map.rb_root);
        if (n) {
@@ -2941,7 +2946,7 @@ struct extent_map *btrfs_get_chunk_map(struct btrfs_fs_info *fs_info,
        struct extent_map_tree *em_tree;
        struct extent_map *em;
 
-       em_tree = &fs_info->mapping_tree.map_tree;
+       em_tree = &fs_info->mapping_tree;
        read_lock(&em_tree->lock);
        em = lookup_extent_mapping(em_tree, logical, length);
        read_unlock(&em_tree->lock);
@@ -3474,6 +3479,18 @@ static int chunk_devid_filter(struct extent_buffer *leaf,
        return 1;
 }
 
+static u64 calc_data_stripes(u64 type, int num_stripes)
+{
+       const int index = btrfs_bg_flags_to_raid_index(type);
+       const int ncopies = btrfs_raid_array[index].ncopies;
+       const int nparity = btrfs_raid_array[index].nparity;
+
+       if (nparity)
+               return num_stripes - nparity;
+       else
+               return num_stripes / ncopies;
+}
+
 /* [pstart, pend) */
 static int chunk_drange_filter(struct extent_buffer *leaf,
                               struct btrfs_chunk *chunk,
@@ -3483,22 +3500,15 @@ static int chunk_drange_filter(struct extent_buffer *leaf,
        int num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
        u64 stripe_offset;
        u64 stripe_length;
+       u64 type;
        int factor;
        int i;
 
        if (!(bargs->flags & BTRFS_BALANCE_ARGS_DEVID))
                return 0;
 
-       if (btrfs_chunk_type(leaf, chunk) & (BTRFS_BLOCK_GROUP_DUP |
-            BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10)) {
-               factor = num_stripes / 2;
-       } else if (btrfs_chunk_type(leaf, chunk) & BTRFS_BLOCK_GROUP_RAID5) {
-               factor = num_stripes - 1;
-       } else if (btrfs_chunk_type(leaf, chunk) & BTRFS_BLOCK_GROUP_RAID6) {
-               factor = num_stripes - 2;
-       } else {
-               factor = num_stripes;
-       }
+       type = btrfs_chunk_type(leaf, chunk);
+       factor = calc_data_stripes(type, num_stripes);
 
        for (i = 0; i < num_stripes; i++) {
                stripe = btrfs_stripe_nr(chunk, i);
@@ -3921,11 +3931,9 @@ static void describe_balance_args(struct btrfs_balance_args *bargs, char *buf,
                bp += ret;                                              \
        } while (0)
 
-       if (flags & BTRFS_BALANCE_ARGS_CONVERT) {
-               int index = btrfs_bg_flags_to_raid_index(bargs->target);
-
-               CHECK_APPEND_1ARG("convert=%s,", get_raid_name(index));
-       }
+       if (flags & BTRFS_BALANCE_ARGS_CONVERT)
+               CHECK_APPEND_1ARG("convert=%s,",
+                                 btrfs_bg_type_to_raid_name(bargs->target));
 
        if (flags & BTRFS_BALANCE_ARGS_SOFT)
                CHECK_APPEND_NOARG("soft,");
@@ -4047,6 +4055,7 @@ int btrfs_balance(struct btrfs_fs_info *fs_info,
        u64 num_devices;
        unsigned seq;
        bool reducing_integrity;
+       int i;
 
        if (btrfs_fs_closing(fs_info) ||
            atomic_read(&fs_info->balance_pause_req) ||
@@ -4076,48 +4085,43 @@ int btrfs_balance(struct btrfs_fs_info *fs_info,
        }
 
        num_devices = btrfs_num_devices(fs_info);
+       allowed = 0;
+       for (i = 0; i < ARRAY_SIZE(btrfs_raid_array); i++)
+               if (num_devices >= btrfs_raid_array[i].devs_min)
+                       allowed |= btrfs_raid_array[i].bg_flag;
 
-       allowed = BTRFS_AVAIL_ALLOC_BIT_SINGLE | BTRFS_BLOCK_GROUP_DUP;
-       if (num_devices > 1)
-               allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1);
-       if (num_devices > 2)
-               allowed |= BTRFS_BLOCK_GROUP_RAID5;
-       if (num_devices > 3)
-               allowed |= (BTRFS_BLOCK_GROUP_RAID10 |
-                           BTRFS_BLOCK_GROUP_RAID6);
        if (validate_convert_profile(&bctl->data, allowed)) {
-               int index = btrfs_bg_flags_to_raid_index(bctl->data.target);
-
                btrfs_err(fs_info,
                          "balance: invalid convert data profile %s",
-                         get_raid_name(index));
+                         btrfs_bg_type_to_raid_name(bctl->data.target));
                ret = -EINVAL;
                goto out;
        }
        if (validate_convert_profile(&bctl->meta, allowed)) {
-               int index = btrfs_bg_flags_to_raid_index(bctl->meta.target);
-
                btrfs_err(fs_info,
                          "balance: invalid convert metadata profile %s",
-                         get_raid_name(index));
+                         btrfs_bg_type_to_raid_name(bctl->meta.target));
                ret = -EINVAL;
                goto out;
        }
        if (validate_convert_profile(&bctl->sys, allowed)) {
-               int index = btrfs_bg_flags_to_raid_index(bctl->sys.target);
-
                btrfs_err(fs_info,
                          "balance: invalid convert system profile %s",
-                         get_raid_name(index));
+                         btrfs_bg_type_to_raid_name(bctl->sys.target));
                ret = -EINVAL;
                goto out;
        }
 
-       /* allow to reduce meta or sys integrity only if force set */
-       allowed = BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1 |
-                       BTRFS_BLOCK_GROUP_RAID10 |
-                       BTRFS_BLOCK_GROUP_RAID5 |
-                       BTRFS_BLOCK_GROUP_RAID6;
+       /*
+        * Allow to reduce metadata or system integrity only if force set for
+        * profiles with redundancy (copies, parity)
+        */
+       allowed = 0;
+       for (i = 0; i < ARRAY_SIZE(btrfs_raid_array); i++) {
+               if (btrfs_raid_array[i].ncopies >= 2 ||
+                   btrfs_raid_array[i].tolerated_failures >= 1)
+                       allowed |= btrfs_raid_array[i].bg_flag;
+       }
        do {
                seq = read_seqbegin(&fs_info->profiles_lock);
 
@@ -4152,12 +4156,18 @@ int btrfs_balance(struct btrfs_fs_info *fs_info,
 
        if (btrfs_get_num_tolerated_disk_barrier_failures(meta_target) <
                btrfs_get_num_tolerated_disk_barrier_failures(data_target)) {
-               int meta_index = btrfs_bg_flags_to_raid_index(meta_target);
-               int data_index = btrfs_bg_flags_to_raid_index(data_target);
-
                btrfs_warn(fs_info,
        "balance: metadata profile %s has lower redundancy than data profile %s",
-                          get_raid_name(meta_index), get_raid_name(data_index));
+                               btrfs_bg_type_to_raid_name(meta_target),
+                               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);
@@ -4949,6 +4959,8 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
        sub_stripes = btrfs_raid_array[index].sub_stripes;
        dev_stripes = btrfs_raid_array[index].dev_stripes;
        devs_max = btrfs_raid_array[index].devs_max;
+       if (!devs_max)
+               devs_max = BTRFS_MAX_DEVS(info);
        devs_min = btrfs_raid_array[index].devs_min;
        devs_increment = btrfs_raid_array[index].devs_increment;
        ncopies = btrfs_raid_array[index].ncopies;
@@ -4957,8 +4969,6 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
        if (type & BTRFS_BLOCK_GROUP_DATA) {
                max_stripe_size = SZ_1G;
                max_chunk_size = BTRFS_MAX_DATA_CHUNK_SIZE;
-               if (!devs_max)
-                       devs_max = BTRFS_MAX_DEVS(info);
        } else if (type & BTRFS_BLOCK_GROUP_METADATA) {
                /* for larger filesystems, use larger metadata chunks */
                if (fs_devices->total_rw_bytes > 50ULL * SZ_1G)
@@ -4966,13 +4976,9 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
                else
                        max_stripe_size = SZ_256M;
                max_chunk_size = max_stripe_size;
-               if (!devs_max)
-                       devs_max = BTRFS_MAX_DEVS(info);
        } else if (type & BTRFS_BLOCK_GROUP_SYSTEM) {
                max_stripe_size = SZ_32M;
                max_chunk_size = 2 * max_stripe_size;
-               if (!devs_max)
-                       devs_max = BTRFS_MAX_DEVS_SYS_CHUNK;
        } else {
                btrfs_err(info, "invalid chunk type 0x%llx requested",
                       type);
@@ -5143,7 +5149,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
        em->block_len = em->len;
        em->orig_block_len = stripe_size;
 
-       em_tree = &info->mapping_tree.map_tree;
+       em_tree = &info->mapping_tree;
        write_lock(&em_tree->lock);
        ret = add_extent_mapping(em_tree, em, 0);
        if (ret) {
@@ -5324,20 +5330,9 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans)
 
 static inline int btrfs_chunk_max_errors(struct map_lookup *map)
 {
-       int max_errors;
-
-       if (map->type & (BTRFS_BLOCK_GROUP_RAID1 |
-                        BTRFS_BLOCK_GROUP_RAID10 |
-                        BTRFS_BLOCK_GROUP_RAID5 |
-                        BTRFS_BLOCK_GROUP_DUP)) {
-               max_errors = 1;
-       } else if (map->type & BTRFS_BLOCK_GROUP_RAID6) {
-               max_errors = 2;
-       } else {
-               max_errors = 0;
-       }
+       const int index = btrfs_bg_flags_to_raid_index(map->type);
 
-       return max_errors;
+       return btrfs_raid_array[index].tolerated_failures;
 }
 
 int btrfs_chunk_readonly(struct btrfs_fs_info *fs_info, u64 chunk_offset)
@@ -5378,21 +5373,16 @@ end:
        return readonly;
 }
 
-void btrfs_mapping_init(struct btrfs_mapping_tree *tree)
-{
-       extent_map_tree_init(&tree->map_tree);
-}
-
-void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree)
+void btrfs_mapping_tree_free(struct extent_map_tree *tree)
 {
        struct extent_map *em;
 
        while (1) {
-               write_lock(&tree->map_tree.lock);
-               em = lookup_extent_mapping(&tree->map_tree, 0, (u64)-1);
+               write_lock(&tree->lock);
+               em = lookup_extent_mapping(tree, 0, (u64)-1);
                if (em)
-                       remove_extent_mapping(&tree->map_tree, em);
-               write_unlock(&tree->map_tree.lock);
+                       remove_extent_mapping(tree, em);
+               write_unlock(&tree->lock);
                if (!em)
                        break;
                /* once for us */
@@ -5419,7 +5409,7 @@ int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len)
                return 1;
 
        map = em->map_lookup;
-       if (map->type & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1))
+       if (map->type & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1_MASK))
                ret = map->num_stripes;
        else if (map->type & BTRFS_BLOCK_GROUP_RAID10)
                ret = map->sub_stripes;
@@ -5493,7 +5483,7 @@ static int find_live_mirror(struct btrfs_fs_info *fs_info,
        struct btrfs_device *srcdev;
 
        ASSERT((map->type &
-                (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10)));
+                (BTRFS_BLOCK_GROUP_RAID1_MASK | BTRFS_BLOCK_GROUP_RAID10)));
 
        if (map->type & BTRFS_BLOCK_GROUP_RAID10)
                num_stripes = map->sub_stripes;
@@ -5682,7 +5672,7 @@ static int __btrfs_map_block_for_discard(struct btrfs_fs_info *fs_info,
                                              &remaining_stripes);
                div_u64_rem(stripe_nr_end - 1, factor, &last_stripe);
                last_stripe *= sub_stripes;
-       } else if (map->type & (BTRFS_BLOCK_GROUP_RAID1 |
+       } else if (map->type & (BTRFS_BLOCK_GROUP_RAID1_MASK |
                                BTRFS_BLOCK_GROUP_DUP)) {
                num_stripes = map->num_stripes;
        } else {
@@ -5926,6 +5916,106 @@ static bool need_full_stripe(enum btrfs_map_op op)
        return (op == BTRFS_MAP_WRITE || op == BTRFS_MAP_GET_READ_MIRRORS);
 }
 
+/*
+ * btrfs_get_io_geometry - calculates the geomery of a particular (address, len)
+ *                    tuple. This information is used to calculate how big a
+ *                    particular bio can get before it straddles a stripe.
+ *
+ * @fs_info - the filesystem
+ * @logical - address that we want to figure out the geometry of
+ * @len            - the length of IO we are going to perform, starting at @logical
+ * @op      - type of operation - write or read
+ * @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, enum btrfs_map_op op,
+                       u64 logical, u64 len, struct btrfs_io_geometry *io_geom)
+{
+       struct extent_map *em;
+       struct map_lookup *map;
+       u64 offset;
+       u64 stripe_offset;
+       u64 stripe_nr;
+       u64 stripe_len;
+       u64 raid56_full_stripe_start = (u64)-1;
+       int data_stripes;
+       int ret = 0;
+
+       ASSERT(op != BTRFS_MAP_DISCARD);
+
+       em = btrfs_get_chunk_map(fs_info, logical, len);
+       if (IS_ERR(em))
+               return PTR_ERR(em);
+
+       map = em->map_lookup;
+       /* Offset of this logical address in the chunk */
+       offset = logical - em->start;
+       /* Len of a stripe in a chunk */
+       stripe_len = map->stripe_len;
+       /* Stripe wher this block falls in */
+       stripe_nr = div64_u64(offset, stripe_len);
+       /* Offset of stripe in the chunk */
+       stripe_offset = stripe_nr * stripe_len;
+       if (offset < stripe_offset) {
+               btrfs_crit(fs_info,
+"stripe math has gone wrong, stripe_offset=%llu offset=%llu start=%llu logical=%llu stripe_len=%llu",
+                       stripe_offset, offset, em->start, logical, stripe_len);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* stripe_offset is the offset of this block in its stripe */
+       stripe_offset = offset - stripe_offset;
+       data_stripes = nr_data_stripes(map);
+
+       if (map->type & BTRFS_BLOCK_GROUP_PROFILE_MASK) {
+               u64 max_len = stripe_len - stripe_offset;
+
+               /*
+                * In case of raid56, we need to know the stripe aligned start
+                */
+               if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) {
+                       unsigned long full_stripe_len = stripe_len * data_stripes;
+                       raid56_full_stripe_start = offset;
+
+                       /*
+                        * Allow a write of a full stripe, but make sure we
+                        * don't allow straddling of stripes
+                        */
+                       raid56_full_stripe_start = div64_u64(raid56_full_stripe_start,
+                                       full_stripe_len);
+                       raid56_full_stripe_start *= full_stripe_len;
+
+                       /*
+                        * For writes to RAID[56], allow a full stripeset across
+                        * all disks. For other RAID types and for RAID[56]
+                        * reads, just allow a single stripe (on a single disk).
+                        */
+                       if (op == BTRFS_MAP_WRITE) {
+                               max_len = stripe_len * data_stripes -
+                                         (offset - raid56_full_stripe_start);
+                       }
+               }
+               len = min_t(u64, em->len - offset, max_len);
+       } else {
+               len = em->len - offset;
+       }
+
+       io_geom->len = len;
+       io_geom->offset = offset;
+       io_geom->stripe_len = stripe_len;
+       io_geom->stripe_nr = stripe_nr;
+       io_geom->stripe_offset = stripe_offset;
+       io_geom->raid56_stripe_offset = raid56_full_stripe_start;
+
+out:
+       /* once for us */
+       free_extent_map(em);
+       return ret;
+}
+
 static int __btrfs_map_block(struct btrfs_fs_info *fs_info,
                             enum btrfs_map_op op,
                             u64 logical, u64 *length,
@@ -5939,6 +6029,7 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info,
        u64 stripe_nr;
        u64 stripe_len;
        u32 stripe_index;
+       int data_stripes;
        int i;
        int ret = 0;
        int num_stripes;
@@ -5951,76 +6042,29 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info,
        int patch_the_first_stripe_for_dev_replace = 0;
        u64 physical_to_patch_in_first_stripe = 0;
        u64 raid56_full_stripe_start = (u64)-1;
+       struct btrfs_io_geometry geom;
+
+       ASSERT(bbio_ret);
 
        if (op == BTRFS_MAP_DISCARD)
                return __btrfs_map_block_for_discard(fs_info, logical,
                                                     *length, bbio_ret);
 
-       em = btrfs_get_chunk_map(fs_info, logical, *length);
-       if (IS_ERR(em))
-               return PTR_ERR(em);
+       ret = btrfs_get_io_geometry(fs_info, op, logical, *length, &geom);
+       if (ret < 0)
+               return ret;
 
+       em = btrfs_get_chunk_map(fs_info, logical, *length);
+       ASSERT(em);
        map = em->map_lookup;
-       offset = logical - em->start;
 
-       stripe_len = map->stripe_len;
-       stripe_nr = offset;
-       /*
-        * stripe_nr counts the total number of stripes we have to stride
-        * to get to this block
-        */
-       stripe_nr = div64_u64(stripe_nr, stripe_len);
-
-       stripe_offset = stripe_nr * stripe_len;
-       if (offset < stripe_offset) {
-               btrfs_crit(fs_info,
-                          "stripe math has gone wrong, stripe_offset=%llu, offset=%llu, start=%llu, logical=%llu, stripe_len=%llu",
-                          stripe_offset, offset, em->start, logical,
-                          stripe_len);
-               free_extent_map(em);
-               return -EINVAL;
-       }
-
-       /* stripe_offset is the offset of this block in its stripe*/
-       stripe_offset = offset - stripe_offset;
-
-       /* if we're here for raid56, we need to know the stripe aligned start */
-       if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) {
-               unsigned long full_stripe_len = stripe_len * nr_data_stripes(map);
-               raid56_full_stripe_start = offset;
-
-               /* allow a write of a full stripe, but make sure we don't
-                * allow straddling of stripes
-                */
-               raid56_full_stripe_start = div64_u64(raid56_full_stripe_start,
-                               full_stripe_len);
-               raid56_full_stripe_start *= full_stripe_len;
-       }
-
-       if (map->type & BTRFS_BLOCK_GROUP_PROFILE_MASK) {
-               u64 max_len;
-               /* For writes to RAID[56], allow a full stripeset across all disks.
-                  For other RAID types and for RAID[56] reads, just allow a single
-                  stripe (on a single disk). */
-               if ((map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) &&
-                   (op == BTRFS_MAP_WRITE)) {
-                       max_len = stripe_len * nr_data_stripes(map) -
-                               (offset - raid56_full_stripe_start);
-               } else {
-                       /* we limit the length of each bio to what fits in a stripe */
-                       max_len = stripe_len - stripe_offset;
-               }
-               *length = min_t(u64, em->len - offset, max_len);
-       } else {
-               *length = em->len - offset;
-       }
-
-       /*
-        * This is for when we're called from btrfs_bio_fits_in_stripe and all
-        * it cares about is the length
-        */
-       if (!bbio_ret)
-               goto out;
+       *length = geom.len;
+       offset = geom.offset;
+       stripe_len = geom.stripe_len;
+       stripe_nr = geom.stripe_nr;
+       stripe_offset = geom.stripe_offset;
+       raid56_full_stripe_start = geom.raid56_stripe_offset;
+       data_stripes = nr_data_stripes(map);
 
        down_read(&dev_replace->rwsem);
        dev_replace_is_ongoing = btrfs_dev_replace_is_ongoing(dev_replace);
@@ -6052,7 +6096,7 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info,
                                &stripe_index);
                if (!need_full_stripe(op))
                        mirror_num = 1;
-       } else if (map->type & BTRFS_BLOCK_GROUP_RAID1) {
+       } else if (map->type & BTRFS_BLOCK_GROUP_RAID1_MASK) {
                if (need_full_stripe(op))
                        num_stripes = map->num_stripes;
                else if (mirror_num)
@@ -6094,7 +6138,7 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info,
                if (need_raid_map && (need_full_stripe(op) || mirror_num > 1)) {
                        /* push stripe_nr back to the start of the full stripe */
                        stripe_nr = div64_u64(raid56_full_stripe_start,
-                                       stripe_len * nr_data_stripes(map));
+                                       stripe_len * data_stripes);
 
                        /* RAID[56] write or recovery. Return all stripes */
                        num_stripes = map->num_stripes;
@@ -6110,10 +6154,9 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info,
                         * Mirror #3 is RAID6 Q block.
                         */
                        stripe_nr = div_u64_rem(stripe_nr,
-                                       nr_data_stripes(map), &stripe_index);
+                                       data_stripes, &stripe_index);
                        if (mirror_num > 1)
-                               stripe_index = nr_data_stripes(map) +
-                                               mirror_num - 2;
+                               stripe_index = data_stripes + mirror_num - 2;
 
                        /* We distribute the parity blocks across stripes */
                        div_u64_rem(stripe_nr + stripe_index, map->num_stripes,
@@ -6171,8 +6214,8 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info,
                div_u64_rem(stripe_nr, num_stripes, &rot);
 
                /* Fill in the logical address of each stripe */
-               tmp = stripe_nr * nr_data_stripes(map);
-               for (i = 0; i < nr_data_stripes(map); i++)
+               tmp = stripe_nr * data_stripes;
+               for (i = 0; i < data_stripes; i++)
                        bbio->raid_map[(i+rot) % num_stripes] =
                                em->start + (tmp + i) * map->stripe_len;
 
@@ -6687,7 +6730,7 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf,
                          struct btrfs_chunk *chunk)
 {
        struct btrfs_fs_info *fs_info = leaf->fs_info;
-       struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
+       struct extent_map_tree *map_tree = &fs_info->mapping_tree;
        struct map_lookup *map;
        struct extent_map *em;
        u64 logical;
@@ -6712,9 +6755,9 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf,
                        return ret;
        }
 
-       read_lock(&map_tree->map_tree.lock);
-       em = lookup_extent_mapping(&map_tree->map_tree, logical, 1);
-       read_unlock(&map_tree->map_tree.lock);
+       read_lock(&map_tree->lock);
+       em = lookup_extent_mapping(map_tree, logical, 1);
+       read_unlock(&map_tree->lock);
 
        /* already mapped? */
        if (em && em->start <= logical && em->start + em->len > logical) {
@@ -6783,9 +6826,9 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf,
 
        }
 
-       write_lock(&map_tree->map_tree.lock);
-       ret = add_extent_mapping(&map_tree->map_tree, em, 0);
-       write_unlock(&map_tree->map_tree.lock);
+       write_lock(&map_tree->lock);
+       ret = add_extent_mapping(map_tree, em, 0);
+       write_unlock(&map_tree->lock);
        if (ret < 0) {
                btrfs_err(fs_info,
                          "failed to add chunk map, start=%llu len=%llu: %d",
@@ -7103,14 +7146,14 @@ out_short_read:
 bool btrfs_check_rw_degradable(struct btrfs_fs_info *fs_info,
                                        struct btrfs_device *failing_dev)
 {
-       struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
+       struct extent_map_tree *map_tree = &fs_info->mapping_tree;
        struct extent_map *em;
        u64 next_start = 0;
        bool ret = true;
 
-       read_lock(&map_tree->map_tree.lock);
-       em = lookup_extent_mapping(&map_tree->map_tree, 0, (u64)-1);
-       read_unlock(&map_tree->map_tree.lock);
+       read_lock(&map_tree->lock);
+       em = lookup_extent_mapping(map_tree, 0, (u64)-1);
+       read_unlock(&map_tree->lock);
        /* No chunk at all? Return false anyway */
        if (!em) {
                ret = false;
@@ -7148,10 +7191,10 @@ bool btrfs_check_rw_degradable(struct btrfs_fs_info *fs_info,
                next_start = extent_map_end(em);
                free_extent_map(em);
 
-               read_lock(&map_tree->map_tree.lock);
-               em = lookup_extent_mapping(&map_tree->map_tree, next_start,
+               read_lock(&map_tree->lock);
+               em = lookup_extent_mapping(map_tree, next_start,
                                           (u64)(-1) - next_start);
-               read_unlock(&map_tree->map_tree.lock);
+               read_unlock(&map_tree->lock);
        }
 out:
        return ret;
@@ -7600,10 +7643,9 @@ void btrfs_reset_fs_info_ptr(struct btrfs_fs_info *fs_info)
  */
 int btrfs_bg_type_to_factor(u64 flags)
 {
-       if (flags & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1 |
-                    BTRFS_BLOCK_GROUP_RAID10))
-               return 2;
-       return 1;
+       const int index = btrfs_bg_flags_to_raid_index(flags);
+
+       return btrfs_raid_array[index].ncopies;
 }
 
 
@@ -7612,7 +7654,7 @@ static int verify_one_dev_extent(struct btrfs_fs_info *fs_info,
                                 u64 chunk_offset, u64 devid,
                                 u64 physical_offset, u64 physical_len)
 {
-       struct extent_map_tree *em_tree = &fs_info->mapping_tree.map_tree;
+       struct extent_map_tree *em_tree = &fs_info->mapping_tree;
        struct extent_map *em;
        struct map_lookup *map;
        struct btrfs_device *dev;
@@ -7701,7 +7743,7 @@ out:
 
 static int verify_chunk_dev_extent_mapping(struct btrfs_fs_info *fs_info)
 {
-       struct extent_map_tree *em_tree = &fs_info->mapping_tree.map_tree;
+       struct extent_map_tree *em_tree = &fs_info->mapping_tree;
        struct extent_map *em;
        struct rb_node *node;
        int ret = 0;
index 136a3eb..7f6aa18 100644 (file)
@@ -23,6 +23,21 @@ struct btrfs_pending_bios {
        struct bio *tail;
 };
 
+struct btrfs_io_geometry {
+       /* remaining bytes before crossing a stripe */
+       u64 len;
+       /* offset of logical address in chunk */
+       u64 offset;
+       /* length of single IO stripe */
+       u64 stripe_len;
+       /* number of stripe where address falls */
+       u64 stripe_nr;
+       /* offset of address in stripe */
+       u64 stripe_offset;
+       /* offset of raid56 stripe into the chunk */
+       u64 raid56_stripe_offset;
+};
+
 /*
  * Use sequence counter to get consistent device stat data on
  * 32-bit processors.
@@ -43,8 +58,8 @@ struct btrfs_pending_bios {
 #define BTRFS_DEV_STATE_FLUSH_SENT     (4)
 
 struct btrfs_device {
-       struct list_head dev_list;
-       struct list_head dev_alloc_list;
+       struct list_head dev_list; /* device_list_mutex */
+       struct list_head dev_alloc_list; /* chunk mutex */
        struct list_head post_commit_list; /* chunk mutex */
        struct btrfs_fs_devices *fs_devices;
        struct btrfs_fs_info *fs_info;
@@ -229,9 +244,14 @@ struct btrfs_fs_devices {
         * this mutex lock.
         */
        struct mutex device_list_mutex;
+
+       /* List of all devices, protected by device_list_mutex */
        struct list_head devices;
 
-       /* devices not currently being allocated */
+       /*
+        * Devices which can satisfy space allocation. Protected by
+        * chunk_mutex
+        */
        struct list_head alloc_list;
 
        struct btrfs_fs_devices *seed;
@@ -336,16 +356,16 @@ struct btrfs_device_info {
 };
 
 struct btrfs_raid_attr {
-       int sub_stripes;        /* sub_stripes info for map */
-       int dev_stripes;        /* stripes per dev */
-       int devs_max;           /* max devs to use */
-       int devs_min;           /* min devs needed */
-       int tolerated_failures; /* max tolerated fail devs */
-       int devs_increment;     /* ndevs has to be a multiple of this */
-       int ncopies;            /* how many copies to data has */
-       int nparity;            /* number of stripes worth of bytes to store
+       u8 sub_stripes;         /* sub_stripes info for map */
+       u8 dev_stripes;         /* stripes per dev */
+       u8 devs_max;            /* max devs to use */
+       u8 devs_min;            /* min devs needed */
+       u8 tolerated_failures;  /* max tolerated fail devs */
+       u8 devs_increment;      /* ndevs has to be a multiple of this */
+       u8 ncopies;             /* how many copies to data has */
+       u8 nparity;             /* number of stripes worth of bytes to store
                                 * parity information */
-       int mindev_error;       /* error code if min devs requisite is unmet */
+       u8 mindev_error;        /* error code if min devs requisite is unmet */
        const char raid_name[8]; /* name of the raid */
        u64 bg_flag;            /* block group flag of the raid */
 };
@@ -408,13 +428,14 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
 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, enum btrfs_map_op op,
+               u64 logical, u64 len, struct btrfs_io_geometry *io_geom);
 int btrfs_rmap_block(struct btrfs_fs_info *fs_info, u64 chunk_start,
                     u64 physical, u64 **logical, int *naddrs, int *stripe_len);
 int btrfs_read_sys_array(struct btrfs_fs_info *fs_info);
 int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info);
 int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, u64 type);
-void btrfs_mapping_init(struct btrfs_mapping_tree *tree);
-void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree);
+void btrfs_mapping_tree_free(struct extent_map_tree *tree);
 blk_status_t btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
                           int mirror_num, int async_submit);
 int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
@@ -557,8 +578,6 @@ static inline enum btrfs_raid_types btrfs_bg_flags_to_raid_index(u64 flags)
        return BTRFS_RAID_SINGLE; /* BTRFS_BLOCK_GROUP_SINGLE */
 }
 
-const char *get_raid_name(enum btrfs_raid_types type);
-
 void btrfs_commit_device_sizes(struct btrfs_transaction *trans);
 
 struct list_head *btrfs_get_fs_uuids(void);
@@ -568,6 +587,7 @@ bool btrfs_check_rw_degradable(struct btrfs_fs_info *fs_info,
                                        struct btrfs_device *failing_dev);
 
 int btrfs_bg_type_to_factor(u64 flags);
+const char *btrfs_bg_type_to_raid_name(u64 flags);
 int btrfs_verify_dev_extents(struct btrfs_fs_info *fs_info);
 
 #endif
index 7f7d92d..cf235f6 100644 (file)
@@ -36,3 +36,15 @@ config CEPH_FS_POSIX_ACL
          groups beyond the owner/group/world scheme.
 
          If you don't know what Access Control Lists are, say N
+
+config CEPH_FS_SECURITY_LABEL
+       bool "CephFS Security Labels"
+       depends on CEPH_FS && SECURITY
+       help
+         Security labels support alternative access control models
+         implemented by security modules like SELinux. This option
+         enables an extended attribute handler for file security
+         labels in the Ceph filesystem.
+
+         If you are not using a security module that requires using
+         extended attributes for file security labels, say N.
index 8a19c24..aa55f41 100644 (file)
@@ -159,7 +159,7 @@ out:
 }
 
 int ceph_pre_init_acls(struct inode *dir, umode_t *mode,
-                      struct ceph_acls_info *info)
+                      struct ceph_acl_sec_ctx *as_ctx)
 {
        struct posix_acl *acl, *default_acl;
        size_t val_size1 = 0, val_size2 = 0;
@@ -234,9 +234,9 @@ int ceph_pre_init_acls(struct inode *dir, umode_t *mode,
 
        kfree(tmp_buf);
 
-       info->acl = acl;
-       info->default_acl = default_acl;
-       info->pagelist = pagelist;
+       as_ctx->acl = acl;
+       as_ctx->default_acl = default_acl;
+       as_ctx->pagelist = pagelist;
        return 0;
 
 out_err:
@@ -248,18 +248,10 @@ out_err:
        return err;
 }
 
-void ceph_init_inode_acls(struct inode* inode, struct ceph_acls_info *info)
+void ceph_init_inode_acls(struct inode *inode, struct ceph_acl_sec_ctx *as_ctx)
 {
        if (!inode)
                return;
-       ceph_set_cached_acl(inode, ACL_TYPE_ACCESS, info->acl);
-       ceph_set_cached_acl(inode, ACL_TYPE_DEFAULT, info->default_acl);
-}
-
-void ceph_release_acls_info(struct ceph_acls_info *info)
-{
-       posix_acl_release(info->acl);
-       posix_acl_release(info->default_acl);
-       if (info->pagelist)
-               ceph_pagelist_release(info->pagelist);
+       ceph_set_cached_acl(inode, ACL_TYPE_ACCESS, as_ctx->acl);
+       ceph_set_cached_acl(inode, ACL_TYPE_DEFAULT, as_ctx->default_acl);
 }
index a47c541..e078cc5 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/pagevec.h>
 #include <linux/task_io_accounting_ops.h>
 #include <linux/signal.h>
+#include <linux/iversion.h>
 
 #include "super.h"
 #include "mds_client.h"
@@ -1576,6 +1577,7 @@ static vm_fault_t ceph_page_mkwrite(struct vm_fault *vmf)
 
        /* Update time before taking page lock */
        file_update_time(vma->vm_file);
+       inode_inc_iversion_raw(inode);
 
        do {
                lock_page(page);
index 0176241..d98dcd9 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/vmalloc.h>
 #include <linux/wait.h>
 #include <linux/writeback.h>
+#include <linux/iversion.h>
 
 #include "super.h"
 #include "mds_client.h"
@@ -1138,8 +1139,9 @@ struct cap_msg_args {
        u64                     ino, cid, follows;
        u64                     flush_tid, oldest_flush_tid, size, max_size;
        u64                     xattr_version;
+       u64                     change_attr;
        struct ceph_buffer      *xattr_buf;
-       struct timespec64       atime, mtime, ctime;
+       struct timespec64       atime, mtime, ctime, btime;
        int                     op, caps, wanted, dirty;
        u32                     seq, issue_seq, mseq, time_warp_seq;
        u32                     flags;
@@ -1160,7 +1162,6 @@ static int send_cap_msg(struct cap_msg_args *arg)
        struct ceph_msg *msg;
        void *p;
        size_t extra_len;
-       struct timespec64 zerotime = {0};
        struct ceph_osd_client *osdc = &arg->session->s_mdsc->fsc->client->osdc;
 
        dout("send_cap_msg %s %llx %llx caps %s wanted %s dirty %s"
@@ -1245,15 +1246,10 @@ static int send_cap_msg(struct cap_msg_args *arg)
        /* pool namespace (version 8) (mds always ignores this) */
        ceph_encode_32(&p, 0);
 
-       /*
-        * btime and change_attr (version 9)
-        *
-        * We just zero these out for now, as the MDS ignores them unless
-        * the requisite feature flags are set (which we don't do yet).
-        */
-       ceph_encode_timespec64(p, &zerotime);
+       /* btime and change_attr (version 9) */
+       ceph_encode_timespec64(p, &arg->btime);
        p += sizeof(struct ceph_timespec);
-       ceph_encode_64(&p, 0);
+       ceph_encode_64(&p, arg->change_attr);
 
        /* Advisory flags (version 10) */
        ceph_encode_32(&p, arg->flags);
@@ -1263,20 +1259,22 @@ static int send_cap_msg(struct cap_msg_args *arg)
 }
 
 /*
- * Queue cap releases when an inode is dropped from our cache.  Since
- * inode is about to be destroyed, there is no need for i_ceph_lock.
+ * Queue cap releases when an inode is dropped from our cache.
  */
-void __ceph_remove_caps(struct inode *inode)
+void __ceph_remove_caps(struct ceph_inode_info *ci)
 {
-       struct ceph_inode_info *ci = ceph_inode(inode);
        struct rb_node *p;
 
+       /* lock i_ceph_lock, because ceph_d_revalidate(..., LOOKUP_RCU)
+        * may call __ceph_caps_issued_mask() on a freeing inode. */
+       spin_lock(&ci->i_ceph_lock);
        p = rb_first(&ci->i_caps);
        while (p) {
                struct ceph_cap *cap = rb_entry(p, struct ceph_cap, ci_node);
                p = rb_next(p);
                __ceph_remove_cap(cap, true);
        }
+       spin_unlock(&ci->i_ceph_lock);
 }
 
 /*
@@ -1297,7 +1295,7 @@ void __ceph_remove_caps(struct inode *inode)
  * caller should hold snap_rwsem (read), s_mutex.
  */
 static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
-                     int op, bool sync, int used, int want, int retain,
+                     int op, int flags, int used, int want, int retain,
                      int flushing, u64 flush_tid, u64 oldest_flush_tid)
        __releases(cap->ci->i_ceph_lock)
 {
@@ -1377,6 +1375,8 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
        arg.mtime = inode->i_mtime;
        arg.atime = inode->i_atime;
        arg.ctime = inode->i_ctime;
+       arg.btime = ci->i_btime;
+       arg.change_attr = inode_peek_iversion_raw(inode);
 
        arg.op = op;
        arg.caps = cap->implemented;
@@ -1393,12 +1393,19 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
        arg.mode = inode->i_mode;
 
        arg.inline_data = ci->i_inline_version != CEPH_INLINE_NONE;
-       if (list_empty(&ci->i_cap_snaps))
-               arg.flags = CEPH_CLIENT_CAPS_NO_CAPSNAP;
-       else
-               arg.flags = CEPH_CLIENT_CAPS_PENDING_CAPSNAP;
-       if (sync)
-               arg.flags |= CEPH_CLIENT_CAPS_SYNC;
+       if (!(flags & CEPH_CLIENT_CAPS_PENDING_CAPSNAP) &&
+           !list_empty(&ci->i_cap_snaps)) {
+               struct ceph_cap_snap *capsnap;
+               list_for_each_entry_reverse(capsnap, &ci->i_cap_snaps, ci_item) {
+                       if (capsnap->cap_flush.tid)
+                               break;
+                       if (capsnap->need_flush) {
+                               flags |= CEPH_CLIENT_CAPS_PENDING_CAPSNAP;
+                               break;
+                       }
+               }
+       }
+       arg.flags = flags;
 
        spin_unlock(&ci->i_ceph_lock);
 
@@ -1436,6 +1443,8 @@ static inline int __send_flush_snap(struct inode *inode,
        arg.atime = capsnap->atime;
        arg.mtime = capsnap->mtime;
        arg.ctime = capsnap->ctime;
+       arg.btime = capsnap->btime;
+       arg.change_attr = capsnap->change_attr;
 
        arg.op = CEPH_CAP_OP_FLUSHSNAP;
        arg.caps = capsnap->issued;
@@ -1603,10 +1612,8 @@ retry:
        }
 
        // make sure flushsnap messages are sent in proper order.
-       if (ci->i_ceph_flags & CEPH_I_KICK_FLUSH) {
+       if (ci->i_ceph_flags & CEPH_I_KICK_FLUSH)
                __kick_flushing_caps(mdsc, session, ci, 0);
-               ci->i_ceph_flags &= ~CEPH_I_KICK_FLUSH;
-       }
 
        __ceph_flush_snaps(ci, session);
 out:
@@ -2048,10 +2055,8 @@ ack:
                if (cap == ci->i_auth_cap &&
                    (ci->i_ceph_flags &
                     (CEPH_I_KICK_FLUSH | CEPH_I_FLUSH_SNAPS))) {
-                       if (ci->i_ceph_flags & CEPH_I_KICK_FLUSH) {
+                       if (ci->i_ceph_flags & CEPH_I_KICK_FLUSH)
                                __kick_flushing_caps(mdsc, session, ci, 0);
-                               ci->i_ceph_flags &= ~CEPH_I_KICK_FLUSH;
-                       }
                        if (ci->i_ceph_flags & CEPH_I_FLUSH_SNAPS)
                                __ceph_flush_snaps(ci, session);
 
@@ -2087,7 +2092,7 @@ ack:
                sent++;
 
                /* __send_cap drops i_ceph_lock */
-               delayed += __send_cap(mdsc, cap, CEPH_CAP_OP_UPDATE, false,
+               delayed += __send_cap(mdsc, cap, CEPH_CAP_OP_UPDATE, 0,
                                cap_used, want, retain, flushing,
                                flush_tid, oldest_flush_tid);
                goto retry; /* retake i_ceph_lock and restart our cap scan. */
@@ -2121,6 +2126,7 @@ static int try_flush_caps(struct inode *inode, u64 *ptid)
 
 retry:
        spin_lock(&ci->i_ceph_lock);
+retry_locked:
        if (ci->i_ceph_flags & CEPH_I_NOFLUSH) {
                spin_unlock(&ci->i_ceph_lock);
                dout("try_flush_caps skipping %p I_NOFLUSH set\n", inode);
@@ -2128,8 +2134,6 @@ retry:
        }
        if (ci->i_dirty_caps && ci->i_auth_cap) {
                struct ceph_cap *cap = ci->i_auth_cap;
-               int used = __ceph_caps_used(ci);
-               int want = __ceph_caps_wanted(ci);
                int delayed;
 
                if (!session || session != cap->session) {
@@ -2145,13 +2149,25 @@ retry:
                        goto out;
                }
 
+               if (ci->i_ceph_flags &
+                   (CEPH_I_KICK_FLUSH | CEPH_I_FLUSH_SNAPS)) {
+                       if (ci->i_ceph_flags & CEPH_I_KICK_FLUSH)
+                               __kick_flushing_caps(mdsc, session, ci, 0);
+                       if (ci->i_ceph_flags & CEPH_I_FLUSH_SNAPS)
+                               __ceph_flush_snaps(ci, session);
+                       goto retry_locked;
+               }
+
                flushing = __mark_caps_flushing(inode, session, true,
                                                &flush_tid, &oldest_flush_tid);
 
                /* __send_cap drops i_ceph_lock */
-               delayed = __send_cap(mdsc, cap, CEPH_CAP_OP_FLUSH, true,
-                               used, want, (cap->issued | cap->implemented),
-                               flushing, flush_tid, oldest_flush_tid);
+               delayed = __send_cap(mdsc, cap, CEPH_CAP_OP_FLUSH,
+                                    CEPH_CLIENT_CAPS_SYNC,
+                                    __ceph_caps_used(ci),
+                                    __ceph_caps_wanted(ci),
+                                    (cap->issued | cap->implemented),
+                                    flushing, flush_tid, oldest_flush_tid);
 
                if (delayed) {
                        spin_lock(&ci->i_ceph_lock);
@@ -2320,6 +2336,16 @@ static void __kick_flushing_caps(struct ceph_mds_client *mdsc,
        struct ceph_cap_flush *cf;
        int ret;
        u64 first_tid = 0;
+       u64 last_snap_flush = 0;
+
+       ci->i_ceph_flags &= ~CEPH_I_KICK_FLUSH;
+
+       list_for_each_entry_reverse(cf, &ci->i_cap_flush_list, i_list) {
+               if (!cf->caps) {
+                       last_snap_flush = cf->tid;
+                       break;
+               }
+       }
 
        list_for_each_entry(cf, &ci->i_cap_flush_list, i_list) {
                if (cf->tid < first_tid)
@@ -2338,10 +2364,13 @@ static void __kick_flushing_caps(struct ceph_mds_client *mdsc,
                        dout("kick_flushing_caps %p cap %p tid %llu %s\n",
                             inode, cap, cf->tid, ceph_cap_string(cf->caps));
                        ci->i_ceph_flags |= CEPH_I_NODELAY;
+
                        ret = __send_cap(mdsc, cap, CEPH_CAP_OP_FLUSH,
-                                         false, __ceph_caps_used(ci),
+                                        (cf->tid < last_snap_flush ?
+                                         CEPH_CLIENT_CAPS_PENDING_CAPSNAP : 0),
+                                         __ceph_caps_used(ci),
                                          __ceph_caps_wanted(ci),
-                                         cap->issued | cap->implemented,
+                                         (cap->issued | cap->implemented),
                                          cf->caps, cf->tid, oldest_flush_tid);
                        if (ret) {
                                pr_err("kick_flushing_caps: error sending "
@@ -2410,7 +2439,6 @@ void ceph_early_kick_flushing_caps(struct ceph_mds_client *mdsc,
                 */
                if ((cap->issued & ci->i_flushing_caps) !=
                    ci->i_flushing_caps) {
-                       ci->i_ceph_flags &= ~CEPH_I_KICK_FLUSH;
                        /* encode_caps_cb() also will reset these sequence
                         * numbers. make sure sequence numbers in cap flush
                         * message match later reconnect message */
@@ -2450,7 +2478,6 @@ void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc,
                        continue;
                }
                if (ci->i_ceph_flags & CEPH_I_KICK_FLUSH) {
-                       ci->i_ceph_flags &= ~CEPH_I_KICK_FLUSH;
                        __kick_flushing_caps(mdsc, session, ci,
                                             oldest_flush_tid);
                }
@@ -2478,7 +2505,6 @@ static void kick_flushing_inode_caps(struct ceph_mds_client *mdsc,
                oldest_flush_tid = __get_oldest_flush_tid(mdsc);
                spin_unlock(&mdsc->cap_dirty_lock);
 
-               ci->i_ceph_flags &= ~CEPH_I_KICK_FLUSH;
                __kick_flushing_caps(mdsc, session, ci, oldest_flush_tid);
                spin_unlock(&ci->i_ceph_lock);
        } else {
@@ -3040,8 +3066,10 @@ struct cap_extra_info {
        bool dirstat_valid;
        u64 nfiles;
        u64 nsubdirs;
+       u64 change_attr;
        /* currently issued */
        int issued;
+       struct timespec64 btime;
 };
 
 /*
@@ -3123,11 +3151,14 @@ static void handle_cap_grant(struct inode *inode,
 
        __check_cap_issue(ci, cap, newcaps);
 
+       inode_set_max_iversion_raw(inode, extra_info->change_attr);
+
        if ((newcaps & CEPH_CAP_AUTH_SHARED) &&
            (extra_info->issued & CEPH_CAP_AUTH_EXCL) == 0) {
                inode->i_mode = le32_to_cpu(grant->mode);
                inode->i_uid = make_kuid(&init_user_ns, le32_to_cpu(grant->uid));
                inode->i_gid = make_kgid(&init_user_ns, le32_to_cpu(grant->gid));
+               ci->i_btime = extra_info->btime;
                dout("%p mode 0%o uid.gid %d.%d\n", inode, inode->i_mode,
                     from_kuid(&init_user_ns, inode->i_uid),
                     from_kgid(&init_user_ns, inode->i_gid));
@@ -3154,6 +3185,7 @@ static void handle_cap_grant(struct inode *inode,
                        ci->i_xattrs.blob = ceph_buffer_get(xattr_buf);
                        ci->i_xattrs.version = version;
                        ceph_forget_all_cached_acls(inode);
+                       ceph_security_invalidate_secctx(inode);
                }
        }
 
@@ -3848,17 +3880,19 @@ void ceph_handle_caps(struct ceph_mds_session *session,
                }
        }
 
-       if (msg_version >= 11) {
+       if (msg_version >= 9) {
                struct ceph_timespec *btime;
-               u64 change_attr;
-               u32 flags;
 
-               /* version >= 9 */
                if (p + sizeof(*btime) > end)
                        goto bad;
                btime = p;
+               ceph_decode_timespec64(&extra_info.btime, btime);
                p += sizeof(*btime);
-               ceph_decode_64_safe(&p, end, change_attr, bad);
+               ceph_decode_64_safe(&p, end, extra_info.change_attr, bad);
+       }
+
+       if (msg_version >= 11) {
+               u32 flags;
                /* version >= 10 */
                ceph_decode_32_safe(&p, end, flags, bad);
                /* version >= 11 */
index 83cd41f..2eb88ed 100644 (file)
@@ -52,7 +52,7 @@ static int mdsc_show(struct seq_file *s, void *p)
        struct ceph_mds_client *mdsc = fsc->mdsc;
        struct ceph_mds_request *req;
        struct rb_node *rp;
-       int pathlen;
+       int pathlen = 0;
        u64 pathbase;
        char *path;
 
index 0637149..4ca0b8f 100644 (file)
@@ -825,7 +825,7 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry,
        struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
        struct ceph_mds_client *mdsc = fsc->mdsc;
        struct ceph_mds_request *req;
-       struct ceph_acls_info acls = {};
+       struct ceph_acl_sec_ctx as_ctx = {};
        int err;
 
        if (ceph_snap(dir) != CEPH_NOSNAP)
@@ -836,7 +836,10 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry,
                goto out;
        }
 
-       err = ceph_pre_init_acls(dir, &mode, &acls);
+       err = ceph_pre_init_acls(dir, &mode, &as_ctx);
+       if (err < 0)
+               goto out;
+       err = ceph_security_init_secctx(dentry, mode, &as_ctx);
        if (err < 0)
                goto out;
 
@@ -855,9 +858,9 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry,
        req->r_args.mknod.rdev = cpu_to_le32(rdev);
        req->r_dentry_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_AUTH_EXCL;
        req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
-       if (acls.pagelist) {
-               req->r_pagelist = acls.pagelist;
-               acls.pagelist = NULL;
+       if (as_ctx.pagelist) {
+               req->r_pagelist = as_ctx.pagelist;
+               as_ctx.pagelist = NULL;
        }
        err = ceph_mdsc_do_request(mdsc, dir, req);
        if (!err && !req->r_reply_info.head->is_dentry)
@@ -865,10 +868,10 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry,
        ceph_mdsc_put_request(req);
 out:
        if (!err)
-               ceph_init_inode_acls(d_inode(dentry), &acls);
+               ceph_init_inode_acls(d_inode(dentry), &as_ctx);
        else
                d_drop(dentry);
-       ceph_release_acls_info(&acls);
+       ceph_release_acl_sec_ctx(&as_ctx);
        return err;
 }
 
@@ -884,6 +887,7 @@ static int ceph_symlink(struct inode *dir, struct dentry *dentry,
        struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
        struct ceph_mds_client *mdsc = fsc->mdsc;
        struct ceph_mds_request *req;
+       struct ceph_acl_sec_ctx as_ctx = {};
        int err;
 
        if (ceph_snap(dir) != CEPH_NOSNAP)
@@ -894,6 +898,10 @@ static int ceph_symlink(struct inode *dir, struct dentry *dentry,
                goto out;
        }
 
+       err = ceph_security_init_secctx(dentry, S_IFLNK | 0777, &as_ctx);
+       if (err < 0)
+               goto out;
+
        dout("symlink in dir %p dentry %p to '%s'\n", dir, dentry, dest);
        req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SYMLINK, USE_AUTH_MDS);
        if (IS_ERR(req)) {
@@ -919,6 +927,7 @@ static int ceph_symlink(struct inode *dir, struct dentry *dentry,
 out:
        if (err)
                d_drop(dentry);
+       ceph_release_acl_sec_ctx(&as_ctx);
        return err;
 }
 
@@ -927,7 +936,7 @@ static int ceph_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
        struct ceph_mds_client *mdsc = fsc->mdsc;
        struct ceph_mds_request *req;
-       struct ceph_acls_info acls = {};
+       struct ceph_acl_sec_ctx as_ctx = {};
        int err = -EROFS;
        int op;
 
@@ -950,7 +959,10 @@ static int ceph_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        }
 
        mode |= S_IFDIR;
-       err = ceph_pre_init_acls(dir, &mode, &acls);
+       err = ceph_pre_init_acls(dir, &mode, &as_ctx);
+       if (err < 0)
+               goto out;
+       err = ceph_security_init_secctx(dentry, mode, &as_ctx);
        if (err < 0)
                goto out;
 
@@ -967,9 +979,9 @@ static int ceph_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        req->r_args.mkdir.mode = cpu_to_le32(mode);
        req->r_dentry_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_AUTH_EXCL;
        req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
-       if (acls.pagelist) {
-               req->r_pagelist = acls.pagelist;
-               acls.pagelist = NULL;
+       if (as_ctx.pagelist) {
+               req->r_pagelist = as_ctx.pagelist;
+               as_ctx.pagelist = NULL;
        }
        err = ceph_mdsc_do_request(mdsc, dir, req);
        if (!err &&
@@ -979,10 +991,10 @@ static int ceph_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        ceph_mdsc_put_request(req);
 out:
        if (!err)
-               ceph_init_inode_acls(d_inode(dentry), &acls);
+               ceph_init_inode_acls(d_inode(dentry), &as_ctx);
        else
                d_drop(dentry);
-       ceph_release_acls_info(&acls);
+       ceph_release_acl_sec_ctx(&as_ctx);
        return err;
 }
 
@@ -1255,7 +1267,7 @@ __dentry_leases_walk(struct ceph_mds_client *mdsc,
                if (!spin_trylock(&dentry->d_lock))
                        continue;
 
-               if (dentry->d_lockref.count < 0) {
+               if (__lockref_is_dead(&dentry->d_lockref)) {
                        list_del_init(&di->lease_list);
                        goto next;
                }
@@ -1433,8 +1445,7 @@ static bool __dentry_lease_is_valid(struct ceph_dentry_info *di)
        return false;
 }
 
-static int dentry_lease_is_valid(struct dentry *dentry, unsigned int flags,
-                                struct inode *dir)
+static int dentry_lease_is_valid(struct dentry *dentry, unsigned int flags)
 {
        struct ceph_dentry_info *di;
        struct ceph_mds_session *session = NULL;
@@ -1466,7 +1477,7 @@ static int dentry_lease_is_valid(struct dentry *dentry, unsigned int flags,
        spin_unlock(&dentry->d_lock);
 
        if (session) {
-               ceph_mdsc_lease_send_msg(session, dir, dentry,
+               ceph_mdsc_lease_send_msg(session, dentry,
                                         CEPH_MDS_LEASE_RENEW, seq);
                ceph_put_mds_session(session);
        }
@@ -1512,18 +1523,26 @@ static int __dir_lease_try_check(const struct dentry *dentry)
 static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry)
 {
        struct ceph_inode_info *ci = ceph_inode(dir);
-       struct ceph_dentry_info *di = ceph_dentry(dentry);
-       int valid = 0;
+       int valid;
+       int shared_gen;
 
        spin_lock(&ci->i_ceph_lock);
-       if (atomic_read(&ci->i_shared_gen) == di->lease_shared_gen)
-               valid = __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1);
+       valid = __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1);
+       shared_gen = atomic_read(&ci->i_shared_gen);
        spin_unlock(&ci->i_ceph_lock);
-       if (valid)
-               __ceph_dentry_dir_lease_touch(di);
-       dout("dir_lease_is_valid dir %p v%u dentry %p v%u = %d\n",
-            dir, (unsigned)atomic_read(&ci->i_shared_gen),
-            dentry, (unsigned)di->lease_shared_gen, valid);
+       if (valid) {
+               struct ceph_dentry_info *di;
+               spin_lock(&dentry->d_lock);
+               di = ceph_dentry(dentry);
+               if (dir == d_inode(dentry->d_parent) &&
+                   di && di->lease_shared_gen == shared_gen)
+                       __ceph_dentry_dir_lease_touch(di);
+               else
+                       valid = 0;
+               spin_unlock(&dentry->d_lock);
+       }
+       dout("dir_lease_is_valid dir %p v%u dentry %p = %d\n",
+            dir, (unsigned)atomic_read(&ci->i_shared_gen), dentry, valid);
        return valid;
 }
 
@@ -1558,7 +1577,7 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
                   ceph_snap(d_inode(dentry)) == CEPH_SNAPDIR) {
                valid = 1;
        } else {
-               valid = dentry_lease_is_valid(dentry, flags, dir);
+               valid = dentry_lease_is_valid(dentry, flags);
                if (valid == -ECHILD)
                        return valid;
                if (valid || dir_lease_is_valid(dir, dentry)) {
index d3ef7ee..15ff1b0 100644 (file)
@@ -368,7 +368,7 @@ static struct dentry *ceph_get_parent(struct dentry *child)
        }
 out:
        dout("get_parent %p ino %llx.%llx err=%ld\n",
-            child, ceph_vinop(inode), (IS_ERR(dn) ? PTR_ERR(dn) : 0));
+            child, ceph_vinop(inode), (long)PTR_ERR_OR_ZERO(dn));
        return dn;
 }
 
index c5517ff..685a03c 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/namei.h>
 #include <linux/writeback.h>
 #include <linux/falloc.h>
+#include <linux/iversion.h>
 
 #include "super.h"
 #include "mds_client.h"
@@ -437,7 +438,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
        struct ceph_mds_client *mdsc = fsc->mdsc;
        struct ceph_mds_request *req;
        struct dentry *dn;
-       struct ceph_acls_info acls = {};
+       struct ceph_acl_sec_ctx as_ctx = {};
        int mask;
        int err;
 
@@ -451,25 +452,28 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
        if (flags & O_CREAT) {
                if (ceph_quota_is_max_files_exceeded(dir))
                        return -EDQUOT;
-               err = ceph_pre_init_acls(dir, &mode, &acls);
+               err = ceph_pre_init_acls(dir, &mode, &as_ctx);
                if (err < 0)
                        return err;
+               err = ceph_security_init_secctx(dentry, mode, &as_ctx);
+               if (err < 0)
+                       goto out_ctx;
        }
 
        /* do the open */
        req = prepare_open_request(dir->i_sb, flags, mode);
        if (IS_ERR(req)) {
                err = PTR_ERR(req);
-               goto out_acl;
+               goto out_ctx;
        }
        req->r_dentry = dget(dentry);
        req->r_num_caps = 2;
        if (flags & O_CREAT) {
                req->r_dentry_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_AUTH_EXCL;
                req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
-               if (acls.pagelist) {
-                       req->r_pagelist = acls.pagelist;
-                       acls.pagelist = NULL;
+               if (as_ctx.pagelist) {
+                       req->r_pagelist = as_ctx.pagelist;
+                       as_ctx.pagelist = NULL;
                }
        }
 
@@ -507,7 +511,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
        } else {
                dout("atomic_open finish_open on dn %p\n", dn);
                if (req->r_op == CEPH_MDS_OP_CREATE && req->r_reply_info.has_create_ino) {
-                       ceph_init_inode_acls(d_inode(dentry), &acls);
+                       ceph_init_inode_acls(d_inode(dentry), &as_ctx);
                        file->f_mode |= FMODE_CREATED;
                }
                err = finish_open(file, dentry, ceph_open);
@@ -516,8 +520,8 @@ out_req:
        if (!req->r_err && req->r_target_inode)
                ceph_put_fmode(ceph_inode(req->r_target_inode), req->r_fmode);
        ceph_mdsc_put_request(req);
-out_acl:
-       ceph_release_acls_info(&acls);
+out_ctx:
+       ceph_release_acl_sec_ctx(&as_ctx);
        dout("atomic_open result=%d\n", err);
        return err;
 }
@@ -1007,7 +1011,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
                         * may block.
                         */
                        truncate_inode_pages_range(inode->i_mapping, pos,
-                                       (pos+len) | (PAGE_SIZE - 1));
+                                                  PAGE_ALIGN(pos + len) - 1);
 
                        req->r_mtime = mtime;
                }
@@ -1022,7 +1026,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
                        req->r_callback = ceph_aio_complete_req;
                        req->r_inode = inode;
                        req->r_priv = aio_req;
-                       list_add_tail(&req->r_unsafe_item, &aio_req->osd_reqs);
+                       list_add_tail(&req->r_private_item, &aio_req->osd_reqs);
 
                        pos += len;
                        continue;
@@ -1082,8 +1086,8 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
                while (!list_empty(&osd_reqs)) {
                        req = list_first_entry(&osd_reqs,
                                               struct ceph_osd_request,
-                                              r_unsafe_item);
-                       list_del_init(&req->r_unsafe_item);
+                                              r_private_item);
+                       list_del_init(&req->r_private_item);
                        if (ret >= 0)
                                ret = ceph_osdc_start_request(req->r_osdc,
                                                              req, false);
@@ -1432,6 +1436,8 @@ retry_snap:
        if (err)
                goto out;
 
+       inode_inc_iversion_raw(inode);
+
        if (ci->i_inline_version != CEPH_INLINE_NONE) {
                err = ceph_uninline_data(file, NULL);
                if (err < 0)
@@ -2063,6 +2069,8 @@ static ssize_t __ceph_copy_file_range(struct file *src_file, loff_t src_off,
                do_final_copy = true;
 
        file_update_time(dst_file);
+       inode_inc_iversion_raw(dst_inode);
+
        if (endoff > size) {
                int caps_flags = 0;
 
index 761451f..791f84a 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/posix_acl.h>
 #include <linux/random.h>
 #include <linux/sort.h>
+#include <linux/iversion.h>
 
 #include "super.h"
 #include "mds_client.h"
@@ -42,6 +43,7 @@ static int ceph_set_ino_cb(struct inode *inode, void *data)
 {
        ceph_inode(inode)->i_vino = *(struct ceph_vino *)data;
        inode->i_ino = ceph_vino_to_ino(*(struct ceph_vino *)data);
+       inode_set_iversion_raw(inode, 0);
        return 0;
 }
 
@@ -509,6 +511,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
 
        INIT_WORK(&ci->i_work, ceph_inode_work);
        ci->i_work_mask = 0;
+       memset(&ci->i_btime, '\0', sizeof(ci->i_btime));
 
        ceph_fscache_inode_init(ci);
 
@@ -523,17 +526,20 @@ void ceph_free_inode(struct inode *inode)
        kmem_cache_free(ceph_inode_cachep, ci);
 }
 
-void ceph_destroy_inode(struct inode *inode)
+void ceph_evict_inode(struct inode *inode)
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_inode_frag *frag;
        struct rb_node *n;
 
-       dout("destroy_inode %p ino %llx.%llx\n", inode, ceph_vinop(inode));
+       dout("evict_inode %p ino %llx.%llx\n", inode, ceph_vinop(inode));
+
+       truncate_inode_pages_final(&inode->i_data);
+       clear_inode(inode);
 
        ceph_fscache_unregister_inode_cookie(ci);
 
-       __ceph_remove_caps(inode);
+       __ceph_remove_caps(ci);
 
        if (__ceph_has_any_quota(ci))
                ceph_adjust_quota_realms_count(inode, false);
@@ -578,16 +584,6 @@ void ceph_destroy_inode(struct inode *inode)
        ceph_put_string(rcu_dereference_raw(ci->i_layout.pool_ns));
 }
 
-int ceph_drop_inode(struct inode *inode)
-{
-       /*
-        * Positve dentry and corresponding inode are always accompanied
-        * in MDS reply. So no need to keep inode in the cache after
-        * dropping all its aliases.
-        */
-       return 1;
-}
-
 static inline blkcnt_t calc_inode_blocks(u64 size)
 {
        return (size + (1<<9) - 1) >> 9;
@@ -795,6 +791,9 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
             le64_to_cpu(info->version) > (ci->i_version & ~1)))
                new_version = true;
 
+       /* Update change_attribute */
+       inode_set_max_iversion_raw(inode, iinfo->change_attr);
+
        __ceph_caps_issued(ci, &issued);
        issued |= __ceph_caps_dirty(ci);
        new_issued = ~issued & info_caps;
@@ -813,6 +812,8 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
                dout("%p mode 0%o uid.gid %d.%d\n", inode, inode->i_mode,
                     from_kuid(&init_user_ns, inode->i_uid),
                     from_kgid(&init_user_ns, inode->i_gid));
+               ceph_decode_timespec64(&ci->i_btime, &iinfo->btime);
+               ceph_decode_timespec64(&ci->i_snap_btime, &iinfo->snap_btime);
        }
 
        if ((new_version || (new_issued & CEPH_CAP_LINK_SHARED)) &&
@@ -887,6 +888,7 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
                               iinfo->xattr_data, iinfo->xattr_len);
                ci->i_xattrs.version = le64_to_cpu(info->xattr_version);
                ceph_forget_all_cached_acls(inode);
+               ceph_security_invalidate_secctx(inode);
                xattr_blob = NULL;
        }
 
@@ -1027,59 +1029,38 @@ out:
 }
 
 /*
- * caller should hold session s_mutex.
+ * caller should hold session s_mutex and dentry->d_lock.
  */
-static void update_dentry_lease(struct dentry *dentry,
-                               struct ceph_mds_reply_lease *lease,
-                               struct ceph_mds_session *session,
-                               unsigned long from_time,
-                               struct ceph_vino *tgt_vino,
-                               struct ceph_vino *dir_vino)
+static void __update_dentry_lease(struct inode *dir, struct dentry *dentry,
+                                 struct ceph_mds_reply_lease *lease,
+                                 struct ceph_mds_session *session,
+                                 unsigned long from_time,
+                                 struct ceph_mds_session **old_lease_session)
 {
        struct ceph_dentry_info *di = ceph_dentry(dentry);
        long unsigned duration = le32_to_cpu(lease->duration_ms);
        long unsigned ttl = from_time + (duration * HZ) / 1000;
        long unsigned half_ttl = from_time + (duration * HZ / 2) / 1000;
-       struct inode *dir;
-       struct ceph_mds_session *old_lease_session = NULL;
 
-       /*
-        * Make sure dentry's inode matches tgt_vino. NULL tgt_vino means that
-        * we expect a negative dentry.
-        */
-       if (!tgt_vino && d_really_is_positive(dentry))
-               return;
-
-       if (tgt_vino && (d_really_is_negative(dentry) ||
-                       !ceph_ino_compare(d_inode(dentry), tgt_vino)))
-               return;
-
-       spin_lock(&dentry->d_lock);
        dout("update_dentry_lease %p duration %lu ms ttl %lu\n",
             dentry, duration, ttl);
 
-       dir = d_inode(dentry->d_parent);
-
-       /* make sure parent matches dir_vino */
-       if (!ceph_ino_compare(dir, dir_vino))
-               goto out_unlock;
-
        /* only track leases on regular dentries */
        if (ceph_snap(dir) != CEPH_NOSNAP)
-               goto out_unlock;
+               return;
 
        di->lease_shared_gen = atomic_read(&ceph_inode(dir)->i_shared_gen);
        if (duration == 0) {
                __ceph_dentry_dir_lease_touch(di);
-               goto out_unlock;
+               return;
        }
 
        if (di->lease_gen == session->s_cap_gen &&
            time_before(ttl, di->time))
-               goto out_unlock;  /* we already have a newer lease. */
+               return;  /* we already have a newer lease. */
 
        if (di->lease_session && di->lease_session != session) {
-               old_lease_session = di->lease_session;
+               *old_lease_session = di->lease_session;
                di->lease_session = NULL;
        }
 
@@ -1092,6 +1073,62 @@ static void update_dentry_lease(struct dentry *dentry,
        di->time = ttl;
 
        __ceph_dentry_lease_touch(di);
+}
+
+static inline void update_dentry_lease(struct inode *dir, struct dentry *dentry,
+                                       struct ceph_mds_reply_lease *lease,
+                                       struct ceph_mds_session *session,
+                                       unsigned long from_time)
+{
+       struct ceph_mds_session *old_lease_session = NULL;
+       spin_lock(&dentry->d_lock);
+       __update_dentry_lease(dir, dentry, lease, session, from_time,
+                             &old_lease_session);
+       spin_unlock(&dentry->d_lock);
+       if (old_lease_session)
+               ceph_put_mds_session(old_lease_session);
+}
+
+/*
+ * update dentry lease without having parent inode locked
+ */
+static void update_dentry_lease_careful(struct dentry *dentry,
+                                       struct ceph_mds_reply_lease *lease,
+                                       struct ceph_mds_session *session,
+                                       unsigned long from_time,
+                                       char *dname, u32 dname_len,
+                                       struct ceph_vino *pdvino,
+                                       struct ceph_vino *ptvino)
+
+{
+       struct inode *dir;
+       struct ceph_mds_session *old_lease_session = NULL;
+
+       spin_lock(&dentry->d_lock);
+       /* make sure dentry's name matches target */
+       if (dentry->d_name.len != dname_len ||
+           memcmp(dentry->d_name.name, dname, dname_len))
+               goto out_unlock;
+
+       dir = d_inode(dentry->d_parent);
+       /* make sure parent matches dvino */
+       if (!ceph_ino_compare(dir, pdvino))
+               goto out_unlock;
+
+       /* make sure dentry's inode matches target. NULL ptvino means that
+        * we expect a negative dentry */
+       if (ptvino) {
+               if (d_really_is_negative(dentry))
+                       goto out_unlock;
+               if (!ceph_ino_compare(d_inode(dentry), ptvino))
+                       goto out_unlock;
+       } else {
+               if (d_really_is_positive(dentry))
+                       goto out_unlock;
+       }
+
+       __update_dentry_lease(dir, dentry, lease, session,
+                             from_time, &old_lease_session);
 out_unlock:
        spin_unlock(&dentry->d_lock);
        if (old_lease_session)
@@ -1156,19 +1193,6 @@ static int splice_dentry(struct dentry **pdn, struct inode *in)
        return 0;
 }
 
-static int d_name_cmp(struct dentry *dentry, const char *name, size_t len)
-{
-       int ret;
-
-       /* take d_lock to ensure dentry->d_name stability */
-       spin_lock(&dentry->d_lock);
-       ret = dentry->d_name.len - len;
-       if (!ret)
-               ret = memcmp(dentry->d_name.name, name, len);
-       spin_unlock(&dentry->d_lock);
-       return ret;
-}
-
 /*
  * Incorporate results into the local cache.  This is either just
  * one inode, or a directory, dentry, and possibly linked-to inode (e.g.,
@@ -1371,10 +1395,9 @@ retry_lookup:
                        } else if (have_lease) {
                                if (d_unhashed(dn))
                                        d_add(dn, NULL);
-                               update_dentry_lease(dn, rinfo->dlease,
-                                                   session,
-                                                   req->r_request_started,
-                                                   NULL, &dvino);
+                               update_dentry_lease(dir, dn,
+                                                   rinfo->dlease, session,
+                                                   req->r_request_started);
                        }
                        goto done;
                }
@@ -1396,11 +1419,9 @@ retry_lookup:
                }
 
                if (have_lease) {
-                       tvino.ino = le64_to_cpu(rinfo->targeti.in->ino);
-                       tvino.snap = le64_to_cpu(rinfo->targeti.in->snapid);
-                       update_dentry_lease(dn, rinfo->dlease, session,
-                                           req->r_request_started,
-                                           &tvino, &dvino);
+                       update_dentry_lease(dir, dn,
+                                           rinfo->dlease, session,
+                                           req->r_request_started);
                }
                dout(" final dn %p\n", dn);
        } else if ((req->r_op == CEPH_MDS_OP_LOOKUPSNAP ||
@@ -1418,27 +1439,20 @@ retry_lookup:
                err = splice_dentry(&req->r_dentry, in);
                if (err < 0)
                        goto done;
-       } else if (rinfo->head->is_dentry &&
-                  !d_name_cmp(req->r_dentry, rinfo->dname, rinfo->dname_len)) {
+       } else if (rinfo->head->is_dentry && req->r_dentry) {
+               /* parent inode is not locked, be carefull */
                struct ceph_vino *ptvino = NULL;
-
-               if ((le32_to_cpu(rinfo->diri.in->cap.caps) & CEPH_CAP_FILE_SHARED) ||
-                   le32_to_cpu(rinfo->dlease->duration_ms)) {
-                       dvino.ino = le64_to_cpu(rinfo->diri.in->ino);
-                       dvino.snap = le64_to_cpu(rinfo->diri.in->snapid);
-
-                       if (rinfo->head->is_target) {
-                               tvino.ino = le64_to_cpu(rinfo->targeti.in->ino);
-                               tvino.snap = le64_to_cpu(rinfo->targeti.in->snapid);
-                               ptvino = &tvino;
-                       }
-
-                       update_dentry_lease(req->r_dentry, rinfo->dlease,
-                               session, req->r_request_started, ptvino,
-                               &dvino);
-               } else {
-                       dout("%s: no dentry lease or dir cap\n", __func__);
+               dvino.ino = le64_to_cpu(rinfo->diri.in->ino);
+               dvino.snap = le64_to_cpu(rinfo->diri.in->snapid);
+               if (rinfo->head->is_target) {
+                       tvino.ino = le64_to_cpu(rinfo->targeti.in->ino);
+                       tvino.snap = le64_to_cpu(rinfo->targeti.in->snapid);
+                       ptvino = &tvino;
                }
+               update_dentry_lease_careful(req->r_dentry, rinfo->dlease,
+                                           session, req->r_request_started,
+                                           rinfo->dname, rinfo->dname_len,
+                                           &dvino, ptvino);
        }
 done:
        dout("fill_trace done err=%d\n", err);
@@ -1600,7 +1614,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
        /* FIXME: release caps/leases if error occurs */
        for (i = 0; i < rinfo->dir_nr; i++) {
                struct ceph_mds_reply_dir_entry *rde = rinfo->dir_entries + i;
-               struct ceph_vino tvino, dvino;
+               struct ceph_vino tvino;
 
                dname.name = rde->name;
                dname.len = rde->name_len;
@@ -1701,9 +1715,9 @@ retry_lookup:
 
                ceph_dentry(dn)->offset = rde->offset;
 
-               dvino = ceph_vino(d_inode(parent));
-               update_dentry_lease(dn, rde->lease, req->r_session,
-                                   req->r_request_started, &tvino, &dvino);
+               update_dentry_lease(d_inode(parent), dn,
+                                   rde->lease, req->r_session,
+                                   req->r_request_started);
 
                if (err == 0 && skipped == 0 && cache_ctl.index >= 0) {
                        ret = fill_readdir_cache(d_inode(parent), dn,
@@ -2282,7 +2296,7 @@ static int statx_to_caps(u32 want)
 {
        int mask = 0;
 
-       if (want & (STATX_MODE|STATX_UID|STATX_GID|STATX_CTIME))
+       if (want & (STATX_MODE|STATX_UID|STATX_GID|STATX_CTIME|STATX_BTIME))
                mask |= CEPH_CAP_AUTH_SHARED;
 
        if (want & (STATX_NLINK|STATX_CTIME))
@@ -2307,6 +2321,7 @@ int ceph_getattr(const struct path *path, struct kstat *stat,
 {
        struct inode *inode = d_inode(path->dentry);
        struct ceph_inode_info *ci = ceph_inode(inode);
+       u32 valid_mask = STATX_BASIC_STATS;
        int err = 0;
 
        /* Skip the getattr altogether if we're asked not to sync */
@@ -2319,6 +2334,16 @@ int ceph_getattr(const struct path *path, struct kstat *stat,
 
        generic_fillattr(inode, stat);
        stat->ino = ceph_translate_ino(inode->i_sb, inode->i_ino);
+
+       /*
+        * btime on newly-allocated inodes is 0, so if this is still set to
+        * that, then assume that it's not valid.
+        */
+       if (ci->i_btime.tv_sec || ci->i_btime.tv_nsec) {
+               stat->btime = ci->i_btime;
+               valid_mask |= STATX_BTIME;
+       }
+
        if (ceph_snap(inode) == CEPH_NOSNAP)
                stat->dev = inode->i_sb->s_dev;
        else
@@ -2342,7 +2367,6 @@ int ceph_getattr(const struct path *path, struct kstat *stat,
                        stat->nlink = 1 + 1 + ci->i_subdirs;
        }
 
-       /* Mask off any higher bits (e.g. btime) until we have support */
-       stat->result_mask = request_mask & STATX_BASIC_STATS;
+       stat->result_mask = request_mask & valid_mask;
        return err;
 }
index c8a9b89..920e9f0 100644 (file)
@@ -150,14 +150,13 @@ static int parse_reply_info_in(void **p, void *end,
                        info->pool_ns_data = *p;
                        *p += info->pool_ns_len;
                }
-               /* btime, change_attr */
-               {
-                       struct ceph_timespec btime;
-                       u64 change_attr;
-                       ceph_decode_need(p, end, sizeof(btime), bad);
-                       ceph_decode_copy(p, &btime, sizeof(btime));
-                       ceph_decode_64_safe(p, end, change_attr, bad);
-               }
+
+               /* btime */
+               ceph_decode_need(p, end, sizeof(info->btime), bad);
+               ceph_decode_copy(p, &info->btime, sizeof(info->btime));
+
+               /* change attribute */
+               ceph_decode_64_safe(p, end, info->change_attr, bad);
 
                /* dir pin */
                if (struct_v >= 2) {
@@ -166,6 +165,15 @@ static int parse_reply_info_in(void **p, void *end,
                        info->dir_pin = -ENODATA;
                }
 
+               /* snapshot birth time, remains zero for v<=2 */
+               if (struct_v >= 3) {
+                       ceph_decode_need(p, end, sizeof(info->snap_btime), bad);
+                       ceph_decode_copy(p, &info->snap_btime,
+                                        sizeof(info->snap_btime));
+               } else {
+                       memset(&info->snap_btime, 0, sizeof(info->snap_btime));
+               }
+
                *p = end;
        } else {
                if (features & CEPH_FEATURE_MDS_INLINE_DATA) {
@@ -197,7 +205,14 @@ static int parse_reply_info_in(void **p, void *end,
                        }
                }
 
+               if (features & CEPH_FEATURE_FS_BTIME) {
+                       ceph_decode_need(p, end, sizeof(info->btime), bad);
+                       ceph_decode_copy(p, &info->btime, sizeof(info->btime));
+                       ceph_decode_64_safe(p, end, info->change_attr, bad);
+               }
+
                info->dir_pin = -ENODATA;
+               /* info->snap_btime remains zero */
        }
        return 0;
 bad:
@@ -717,6 +732,7 @@ void ceph_mdsc_release_request(struct kref *kref)
                ceph_pagelist_release(req->r_pagelist);
        put_request_session(req);
        ceph_unreserve_caps(req->r_mdsc, &req->r_caps_reservation);
+       WARN_ON_ONCE(!list_empty(&req->r_wait));
        kfree(req);
 }
 
@@ -903,7 +919,7 @@ static int __choose_mds(struct ceph_mds_client *mdsc,
                struct inode *dir;
 
                rcu_read_lock();
-               parent = req->r_dentry->d_parent;
+               parent = READ_ONCE(req->r_dentry->d_parent);
                dir = req->r_parent ? : d_inode_rcu(parent);
 
                if (!dir || dir->i_sb != mdsc->fsc->sb) {
@@ -2135,7 +2151,7 @@ retry:
                        memcpy(path + pos, temp->d_name.name, temp->d_name.len);
                }
                spin_unlock(&temp->d_lock);
-               temp = temp->d_parent;
+               temp = READ_ONCE(temp->d_parent);
 
                /* Are we at the root? */
                if (IS_ROOT(temp))
@@ -3727,42 +3743,35 @@ static void check_new_map(struct ceph_mds_client *mdsc,
                     ceph_mdsmap_is_laggy(newmap, i) ? " (laggy)" : "",
                     ceph_session_state_name(s->s_state));
 
-               if (i >= newmap->m_num_mds ||
-                   memcmp(ceph_mdsmap_get_addr(oldmap, i),
-                          ceph_mdsmap_get_addr(newmap, i),
-                          sizeof(struct ceph_entity_addr))) {
-                       if (s->s_state == CEPH_MDS_SESSION_OPENING) {
-                               /* the session never opened, just close it
-                                * out now */
-                               get_session(s);
-                               __unregister_session(mdsc, s);
-                               __wake_requests(mdsc, &s->s_waiting);
-                               ceph_put_mds_session(s);
-                       } else if (i >= newmap->m_num_mds) {
-                               /* force close session for stopped mds */
-                               get_session(s);
-                               __unregister_session(mdsc, s);
-                               __wake_requests(mdsc, &s->s_waiting);
-                               kick_requests(mdsc, i);
-                               mutex_unlock(&mdsc->mutex);
+               if (i >= newmap->m_num_mds) {
+                       /* force close session for stopped mds */
+                       get_session(s);
+                       __unregister_session(mdsc, s);
+                       __wake_requests(mdsc, &s->s_waiting);
+                       mutex_unlock(&mdsc->mutex);
 
-                               mutex_lock(&s->s_mutex);
-                               cleanup_session_requests(mdsc, s);
-                               remove_session_caps(s);
-                               mutex_unlock(&s->s_mutex);
+                       mutex_lock(&s->s_mutex);
+                       cleanup_session_requests(mdsc, s);
+                       remove_session_caps(s);
+                       mutex_unlock(&s->s_mutex);
 
-                               ceph_put_mds_session(s);
+                       ceph_put_mds_session(s);
 
-                               mutex_lock(&mdsc->mutex);
-                       } else {
-                               /* just close it */
-                               mutex_unlock(&mdsc->mutex);
-                               mutex_lock(&s->s_mutex);
-                               mutex_lock(&mdsc->mutex);
-                               ceph_con_close(&s->s_con);
-                               mutex_unlock(&s->s_mutex);
-                               s->s_state = CEPH_MDS_SESSION_RESTARTING;
-                       }
+                       mutex_lock(&mdsc->mutex);
+                       kick_requests(mdsc, i);
+                       continue;
+               }
+
+               if (memcmp(ceph_mdsmap_get_addr(oldmap, i),
+                          ceph_mdsmap_get_addr(newmap, i),
+                          sizeof(struct ceph_entity_addr))) {
+                       /* just close it */
+                       mutex_unlock(&mdsc->mutex);
+                       mutex_lock(&s->s_mutex);
+                       mutex_lock(&mdsc->mutex);
+                       ceph_con_close(&s->s_con);
+                       mutex_unlock(&s->s_mutex);
+                       s->s_state = CEPH_MDS_SESSION_RESTARTING;
                } else if (oldstate == newstate) {
                        continue;  /* nothing new with this mds */
                }
@@ -3931,31 +3940,33 @@ bad:
 }
 
 void ceph_mdsc_lease_send_msg(struct ceph_mds_session *session,
-                             struct inode *inode,
                              struct dentry *dentry, char action,
                              u32 seq)
 {
        struct ceph_msg *msg;
        struct ceph_mds_lease *lease;
-       int len = sizeof(*lease) + sizeof(u32);
-       int dnamelen = 0;
+       struct inode *dir;
+       int len = sizeof(*lease) + sizeof(u32) + NAME_MAX;
 
-       dout("lease_send_msg inode %p dentry %p %s to mds%d\n",
-            inode, dentry, ceph_lease_op_name(action), session->s_mds);
-       dnamelen = dentry->d_name.len;
-       len += dnamelen;
+       dout("lease_send_msg identry %p %s to mds%d\n",
+            dentry, ceph_lease_op_name(action), session->s_mds);
 
        msg = ceph_msg_new(CEPH_MSG_CLIENT_LEASE, len, GFP_NOFS, false);
        if (!msg)
                return;
        lease = msg->front.iov_base;
        lease->action = action;
-       lease->ino = cpu_to_le64(ceph_vino(inode).ino);
-       lease->first = lease->last = cpu_to_le64(ceph_vino(inode).snap);
        lease->seq = cpu_to_le32(seq);
-       put_unaligned_le32(dnamelen, lease + 1);
-       memcpy((void *)(lease + 1) + 4, dentry->d_name.name, dnamelen);
 
+       spin_lock(&dentry->d_lock);
+       dir = d_inode(dentry->d_parent);
+       lease->ino = cpu_to_le64(ceph_ino(dir));
+       lease->first = lease->last = cpu_to_le64(ceph_snap(dir));
+
+       put_unaligned_le32(dentry->d_name.len, lease + 1);
+       memcpy((void *)(lease + 1) + 4,
+              dentry->d_name.name, dentry->d_name.len);
+       spin_unlock(&dentry->d_lock);
        /*
         * if this is a preemptive lease RELEASE, no need to
         * flush request stream, since the actual request will
@@ -4157,6 +4168,7 @@ static void wait_requests(struct ceph_mds_client *mdsc)
                while ((req = __get_oldest_req(mdsc))) {
                        dout("wait_requests timed out on tid %llu\n",
                             req->r_tid);
+                       list_del_init(&req->r_wait);
                        __unregister_request(mdsc, req);
                }
        }
index a83f28b..f7c8603 100644 (file)
@@ -69,6 +69,9 @@ struct ceph_mds_reply_info_in {
        u64 max_bytes;
        u64 max_files;
        s32 dir_pin;
+       struct ceph_timespec btime;
+       struct ceph_timespec snap_btime;
+       u64 change_attr;
 };
 
 struct ceph_mds_reply_dir_entry {
@@ -504,7 +507,6 @@ extern char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
 
 extern void __ceph_mdsc_drop_dentry_lease(struct dentry *dentry);
 extern void ceph_mdsc_lease_send_msg(struct ceph_mds_session *session,
-                                    struct inode *inode,
                                     struct dentry *dentry, char action,
                                     u32 seq);
 
index 701b4fb..ce2d00d 100644 (file)
@@ -107,7 +107,7 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end)
        struct ceph_mdsmap *m;
        const void *start = *p;
        int i, j, n;
-       int err = -EINVAL;
+       int err;
        u8 mdsmap_v, mdsmap_cv;
        u16 mdsmap_ev;
 
@@ -183,8 +183,9 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end)
                inc = ceph_decode_32(p);
                state = ceph_decode_32(p);
                state_seq = ceph_decode_64(p);
-               ceph_decode_copy(p, &addr, sizeof(addr));
-               ceph_decode_addr(&addr);
+               err = ceph_decode_entity_addr(p, end, &addr);
+               if (err)
+                       goto corrupt;
                ceph_decode_copy(p, &laggy_since, sizeof(laggy_since));
                *p += sizeof(u32);
                ceph_decode_32_safe(p, end, namelen, bad);
@@ -357,7 +358,7 @@ bad_ext:
 nomem:
        err = -ENOMEM;
        goto out_err;
-bad:
+corrupt:
        pr_err("corrupt mdsmap\n");
        print_hex_dump(KERN_DEBUG, "mdsmap: ",
                       DUMP_PREFIX_OFFSET, 16, 1,
@@ -365,6 +366,9 @@ bad:
 out_err:
        ceph_mdsmap_destroy(m);
        return ERR_PTR(err);
+bad:
+       err = -EINVAL;
+       goto corrupt;
 }
 
 void ceph_mdsmap_destroy(struct ceph_mdsmap *m)
index d629fc8..de56dee 100644 (file)
@@ -135,7 +135,7 @@ static struct inode *lookup_quotarealm_inode(struct ceph_mds_client *mdsc,
                return NULL;
 
        mutex_lock(&qri->mutex);
-       if (qri->inode) {
+       if (qri->inode && ceph_is_any_caps(qri->inode)) {
                /* A request has already returned the inode */
                mutex_unlock(&qri->mutex);
                return qri->inode;
@@ -146,7 +146,18 @@ static struct inode *lookup_quotarealm_inode(struct ceph_mds_client *mdsc,
                mutex_unlock(&qri->mutex);
                return NULL;
        }
-       in = ceph_lookup_inode(sb, realm->ino);
+       if (qri->inode) {
+               /* get caps */
+               int ret = __ceph_do_getattr(qri->inode, NULL,
+                                           CEPH_STAT_CAP_INODE, true);
+               if (ret >= 0)
+                       in = qri->inode;
+               else
+                       in = ERR_PTR(ret);
+       }  else {
+               in = ceph_lookup_inode(sb, realm->ino);
+       }
+
        if (IS_ERR(in)) {
                pr_warn("Can't lookup inode %llx (err: %ld)\n",
                        realm->ino, PTR_ERR(in));
index 72c6c02..4c6494e 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/sort.h>
 #include <linux/slab.h>
+#include <linux/iversion.h>
 #include "super.h"
 #include "mds_client.h"
 #include <linux/ceph/decode.h>
@@ -606,6 +607,8 @@ int __ceph_finish_cap_snap(struct ceph_inode_info *ci,
        capsnap->mtime = inode->i_mtime;
        capsnap->atime = inode->i_atime;
        capsnap->ctime = inode->i_ctime;
+       capsnap->btime = ci->i_btime;
+       capsnap->change_attr = inode_peek_iversion_raw(inode);
        capsnap->time_warp_seq = ci->i_time_warp_seq;
        capsnap->truncate_size = ci->i_truncate_size;
        capsnap->truncate_seq = ci->i_truncate_seq;
index ed1b65a..ab4868c 100644 (file)
@@ -840,10 +840,10 @@ static int ceph_remount(struct super_block *sb, int *flags, char *data)
 
 static const struct super_operations ceph_super_ops = {
        .alloc_inode    = ceph_alloc_inode,
-       .destroy_inode  = ceph_destroy_inode,
        .free_inode     = ceph_free_inode,
        .write_inode    = ceph_write_inode,
-       .drop_inode     = ceph_drop_inode,
+       .drop_inode     = generic_delete_inode,
+       .evict_inode    = ceph_evict_inode,
        .sync_fs        = ceph_sync_fs,
        .put_super      = ceph_put_super,
        .remount_fs     = ceph_remount,
@@ -978,7 +978,7 @@ static int ceph_set_super(struct super_block *s, void *data)
        s->s_d_op = &ceph_dentry_ops;
        s->s_export_op = &ceph_export_ops;
 
-       s->s_time_gran = 1000;  /* 1000 ns == 1 us */
+       s->s_time_gran = 1;
 
        ret = set_anon_super(s, NULL);  /* what is that second arg for? */
        if (ret != 0)
@@ -1159,17 +1159,15 @@ static int __init init_ceph(void)
                goto out;
 
        ceph_flock_init();
-       ceph_xattr_init();
        ret = register_filesystem(&ceph_fs_type);
        if (ret)
-               goto out_xattr;
+               goto out_caches;
 
        pr_info("loaded (mds proto %d)\n", CEPH_MDSC_PROTOCOL);
 
        return 0;
 
-out_xattr:
-       ceph_xattr_exit();
+out_caches:
        destroy_caches();
 out:
        return ret;
@@ -1179,7 +1177,6 @@ static void __exit exit_ceph(void)
 {
        dout("exit_ceph\n");
        unregister_filesystem(&ceph_fs_type);
-       ceph_xattr_exit();
        destroy_caches();
 }
 
index fbe6869..d2352fd 100644 (file)
@@ -197,7 +197,8 @@ struct ceph_cap_snap {
        u64 xattr_version;
 
        u64 size;
-       struct timespec64 mtime, atime, ctime;
+       u64 change_attr;
+       struct timespec64 mtime, atime, ctime, btime;
        u64 time_warp_seq;
        u64 truncate_size;
        u32 truncate_seq;
@@ -384,6 +385,8 @@ struct ceph_inode_info {
        int i_snap_realm_counter; /* snap realm (if caps) */
        struct list_head i_snap_realm_item;
        struct list_head i_snap_flush_item;
+       struct timespec64 i_btime;
+       struct timespec64 i_snap_btime;
 
        struct work_struct i_work;
        unsigned long  i_work_mask;
@@ -544,7 +547,12 @@ static inline void __ceph_dir_set_complete(struct ceph_inode_info *ci,
                                           long long release_count,
                                           long long ordered_count)
 {
-       smp_mb__before_atomic();
+       /*
+        * Makes sure operations that setup readdir cache (update page
+        * cache and i_size) are strongly ordered w.r.t. the following
+        * atomic64_set() operations.
+        */
+       smp_mb();
        atomic64_set(&ci->i_complete_seq[0], release_count);
        atomic64_set(&ci->i_complete_seq[1], ordered_count);
 }
@@ -876,9 +884,8 @@ static inline bool __ceph_have_pending_cap_snap(struct ceph_inode_info *ci)
 extern const struct inode_operations ceph_file_iops;
 
 extern struct inode *ceph_alloc_inode(struct super_block *sb);
-extern void ceph_destroy_inode(struct inode *inode);
+extern void ceph_evict_inode(struct inode *inode);
 extern void ceph_free_inode(struct inode *inode);
-extern int ceph_drop_inode(struct inode *inode);
 
 extern struct inode *ceph_get_inode(struct super_block *sb,
                                    struct ceph_vino vino);
@@ -921,10 +928,20 @@ ssize_t __ceph_getxattr(struct inode *, const char *, void *, size_t);
 extern ssize_t ceph_listxattr(struct dentry *, char *, size_t);
 extern void __ceph_build_xattrs_blob(struct ceph_inode_info *ci);
 extern void __ceph_destroy_xattrs(struct ceph_inode_info *ci);
-extern void __init ceph_xattr_init(void);
-extern void ceph_xattr_exit(void);
 extern const struct xattr_handler *ceph_xattr_handlers[];
 
+struct ceph_acl_sec_ctx {
+#ifdef CONFIG_CEPH_FS_POSIX_ACL
+       void *default_acl;
+       void *acl;
+#endif
+#ifdef CONFIG_CEPH_FS_SECURITY_LABEL
+       void *sec_ctx;
+       u32 sec_ctxlen;
+#endif
+       struct ceph_pagelist *pagelist;
+};
+
 #ifdef CONFIG_SECURITY
 extern bool ceph_security_xattr_deadlock(struct inode *in);
 extern bool ceph_security_xattr_wanted(struct inode *in);
@@ -939,21 +956,32 @@ static inline bool ceph_security_xattr_wanted(struct inode *in)
 }
 #endif
 
-/* acl.c */
-struct ceph_acls_info {
-       void *default_acl;
-       void *acl;
-       struct ceph_pagelist *pagelist;
-};
+#ifdef CONFIG_CEPH_FS_SECURITY_LABEL
+extern int ceph_security_init_secctx(struct dentry *dentry, umode_t mode,
+                                    struct ceph_acl_sec_ctx *ctx);
+extern void ceph_security_invalidate_secctx(struct inode *inode);
+#else
+static inline int ceph_security_init_secctx(struct dentry *dentry, umode_t mode,
+                                           struct ceph_acl_sec_ctx *ctx)
+{
+       return 0;
+}
+static inline void ceph_security_invalidate_secctx(struct inode *inode)
+{
+}
+#endif
+
+void ceph_release_acl_sec_ctx(struct ceph_acl_sec_ctx *as_ctx);
 
+/* acl.c */
 #ifdef CONFIG_CEPH_FS_POSIX_ACL
 
 struct posix_acl *ceph_get_acl(struct inode *, int);
 int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type);
 int ceph_pre_init_acls(struct inode *dir, umode_t *mode,
-                      struct ceph_acls_info *info);
-void ceph_init_inode_acls(struct inode *inode, struct ceph_acls_info *info);
-void ceph_release_acls_info(struct ceph_acls_info *info);
+                      struct ceph_acl_sec_ctx *as_ctx);
+void ceph_init_inode_acls(struct inode *inode,
+                         struct ceph_acl_sec_ctx *as_ctx);
 
 static inline void ceph_forget_all_cached_acls(struct inode *inode)
 {
@@ -966,15 +994,12 @@ static inline void ceph_forget_all_cached_acls(struct inode *inode)
 #define ceph_set_acl NULL
 
 static inline int ceph_pre_init_acls(struct inode *dir, umode_t *mode,
-                                    struct ceph_acls_info *info)
+                                    struct ceph_acl_sec_ctx *as_ctx)
 {
        return 0;
 }
 static inline void ceph_init_inode_acls(struct inode *inode,
-                                       struct ceph_acls_info *info)
-{
-}
-static inline void ceph_release_acls_info(struct ceph_acls_info *info)
+                                       struct ceph_acl_sec_ctx *as_ctx)
 {
 }
 static inline int ceph_acl_chmod(struct dentry *dentry, struct inode *inode)
@@ -1000,7 +1025,7 @@ extern void ceph_add_cap(struct inode *inode,
                         unsigned cap, unsigned seq, u64 realmino, int flags,
                         struct ceph_cap **new_cap);
 extern void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release);
-extern void __ceph_remove_caps(struct inode* inode);
+extern void __ceph_remove_caps(struct ceph_inode_info *ci);
 extern void ceph_put_cap(struct ceph_mds_client *mdsc,
                         struct ceph_cap *cap);
 extern int ceph_is_any_caps(struct inode *inode);
index 0cc42c8..37b458a 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/ceph/decode.h>
 
 #include <linux/xattr.h>
+#include <linux/security.h>
 #include <linux/posix_acl_xattr.h>
 #include <linux/slab.h>
 
 static int __remove_xattr(struct ceph_inode_info *ci,
                          struct ceph_inode_xattr *xattr);
 
-static const struct xattr_handler ceph_other_xattr_handler;
-
-/*
- * List of handlers for synthetic system.* attributes. Other
- * attributes are handled directly.
- */
-const struct xattr_handler *ceph_xattr_handlers[] = {
-#ifdef CONFIG_CEPH_FS_POSIX_ACL
-       &posix_acl_access_xattr_handler,
-       &posix_acl_default_xattr_handler,
-#endif
-       &ceph_other_xattr_handler,
-       NULL,
-};
-
 static bool ceph_is_valid_xattr(const char *name)
 {
        return !strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN) ||
-              !strncmp(name, XATTR_SECURITY_PREFIX,
-                       XATTR_SECURITY_PREFIX_LEN) ||
               !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) ||
               !strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
 }
@@ -48,8 +32,8 @@ static bool ceph_is_valid_xattr(const char *name)
 struct ceph_vxattr {
        char *name;
        size_t name_size;       /* strlen(name) + 1 (for '\0') */
-       size_t (*getxattr_cb)(struct ceph_inode_info *ci, char *val,
-                             size_t size);
+       ssize_t (*getxattr_cb)(struct ceph_inode_info *ci, char *val,
+                              size_t size);
        bool (*exists_cb)(struct ceph_inode_info *ci);
        unsigned int flags;
 };
@@ -68,8 +52,8 @@ static bool ceph_vxattrcb_layout_exists(struct ceph_inode_info *ci)
                rcu_dereference_raw(fl->pool_ns) != NULL);
 }
 
-static size_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val,
-                                  size_t size)
+static ssize_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val,
+                                   size_t size)
 {
        struct ceph_fs_client *fsc = ceph_sb_to_client(ci->vfs_inode.i_sb);
        struct ceph_osd_client *osdc = &fsc->client->osdc;
@@ -79,7 +63,7 @@ static size_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val,
        const char *ns_field = " pool_namespace=";
        char buf[128];
        size_t len, total_len = 0;
-       int ret;
+       ssize_t ret;
 
        pool_ns = ceph_try_get_string(ci->i_layout.pool_ns);
 
@@ -96,18 +80,15 @@ static size_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val,
                len = snprintf(buf, sizeof(buf),
                "stripe_unit=%u stripe_count=%u object_size=%u pool=%lld",
                ci->i_layout.stripe_unit, ci->i_layout.stripe_count,
-               ci->i_layout.object_size, (unsigned long long)pool);
+               ci->i_layout.object_size, pool);
                total_len = len;
        }
 
        if (pool_ns)
                total_len += strlen(ns_field) + pool_ns->len;
 
-       if (!size) {
-               ret = total_len;
-       } else if (total_len > size) {
-               ret = -ERANGE;
-       } else {
+       ret = total_len;
+       if (size >= total_len) {
                memcpy(val, buf, len);
                ret = len;
                if (pool_name) {
@@ -128,28 +109,55 @@ static size_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val,
        return ret;
 }
 
-static size_t ceph_vxattrcb_layout_stripe_unit(struct ceph_inode_info *ci,
-                                              char *val, size_t size)
+/*
+ * The convention with strings in xattrs is that they should not be NULL
+ * terminated, since we're returning the length with them. snprintf always
+ * NULL terminates however, so call it on a temporary buffer and then memcpy
+ * the result into place.
+ */
+static int ceph_fmt_xattr(char *val, size_t size, const char *fmt, ...)
 {
-       return snprintf(val, size, "%u", ci->i_layout.stripe_unit);
+       int ret;
+       va_list args;
+       char buf[96]; /* NB: reevaluate size if new vxattrs are added */
+
+       va_start(args, fmt);
+       ret = vsnprintf(buf, size ? sizeof(buf) : 0, fmt, args);
+       va_end(args);
+
+       /* Sanity check */
+       if (size && ret + 1 > sizeof(buf)) {
+               WARN_ONCE(true, "Returned length too big (%d)", ret);
+               return -E2BIG;
+       }
+
+       if (ret <= size)
+               memcpy(val, buf, ret);
+       return ret;
 }
 
-static size_t ceph_vxattrcb_layout_stripe_count(struct ceph_inode_info *ci,
+static ssize_t ceph_vxattrcb_layout_stripe_unit(struct ceph_inode_info *ci,
                                                char *val, size_t size)
 {
-       return snprintf(val, size, "%u", ci->i_layout.stripe_count);
+       return ceph_fmt_xattr(val, size, "%u", ci->i_layout.stripe_unit);
+}
+
+static ssize_t ceph_vxattrcb_layout_stripe_count(struct ceph_inode_info *ci,
+                                                char *val, size_t size)
+{
+       return ceph_fmt_xattr(val, size, "%u", ci->i_layout.stripe_count);
 }
 
-static size_t ceph_vxattrcb_layout_object_size(struct ceph_inode_info *ci,
-                                              char *val, size_t size)
+static ssize_t ceph_vxattrcb_layout_object_size(struct ceph_inode_info *ci,
+                                               char *val, size_t size)
 {
-       return snprintf(val, size, "%u", ci->i_layout.object_size);
+       return ceph_fmt_xattr(val, size, "%u", ci->i_layout.object_size);
 }
 
-static size_t ceph_vxattrcb_layout_pool(struct ceph_inode_info *ci,
-                                       char *val, size_t size)
+static ssize_t ceph_vxattrcb_layout_pool(struct ceph_inode_info *ci,
+                                        char *val, size_t size)
 {
-       int ret;
+       ssize_t ret;
        struct ceph_fs_client *fsc = ceph_sb_to_client(ci->vfs_inode.i_sb);
        struct ceph_osd_client *osdc = &fsc->client->osdc;
        s64 pool = ci->i_layout.pool_id;
@@ -157,21 +165,27 @@ static size_t ceph_vxattrcb_layout_pool(struct ceph_inode_info *ci,
 
        down_read(&osdc->lock);
        pool_name = ceph_pg_pool_name_by_id(osdc->osdmap, pool);
-       if (pool_name)
-               ret = snprintf(val, size, "%s", pool_name);
-       else
-               ret = snprintf(val, size, "%lld", (unsigned long long)pool);
+       if (pool_name) {
+               ret = strlen(pool_name);
+               if (ret <= size)
+                       memcpy(val, pool_name, ret);
+       } else {
+               ret = ceph_fmt_xattr(val, size, "%lld", pool);
+       }
        up_read(&osdc->lock);
        return ret;
 }
 
-static size_t ceph_vxattrcb_layout_pool_namespace(struct ceph_inode_info *ci,
-                                                 char *val, size_t size)
+static ssize_t ceph_vxattrcb_layout_pool_namespace(struct ceph_inode_info *ci,
+                                                  char *val, size_t size)
 {
-       int ret = 0;
+       ssize_t ret = 0;
        struct ceph_string *ns = ceph_try_get_string(ci->i_layout.pool_ns);
+
        if (ns) {
-               ret = snprintf(val, size, "%.*s", (int)ns->len, ns->str);
+               ret = ns->len;
+               if (ret <= size)
+                       memcpy(val, ns->str, ret);
                ceph_put_string(ns);
        }
        return ret;
@@ -179,53 +193,54 @@ static size_t ceph_vxattrcb_layout_pool_namespace(struct ceph_inode_info *ci,
 
 /* directories */
 
-static size_t ceph_vxattrcb_dir_entries(struct ceph_inode_info *ci, char *val,
-                                       size_t size)
+static ssize_t ceph_vxattrcb_dir_entries(struct ceph_inode_info *ci, char *val,
+                                        size_t size)
 {
-       return snprintf(val, size, "%lld", ci->i_files + ci->i_subdirs);
+       return ceph_fmt_xattr(val, size, "%lld", ci->i_files + ci->i_subdirs);
 }
 
-static size_t ceph_vxattrcb_dir_files(struct ceph_inode_info *ci, char *val,
-                                     size_t size)
+static ssize_t ceph_vxattrcb_dir_files(struct ceph_inode_info *ci, char *val,
+                                      size_t size)
 {
-       return snprintf(val, size, "%lld", ci->i_files);
+       return ceph_fmt_xattr(val, size, "%lld", ci->i_files);
 }
 
-static size_t ceph_vxattrcb_dir_subdirs(struct ceph_inode_info *ci, char *val,
-                                       size_t size)
+static ssize_t ceph_vxattrcb_dir_subdirs(struct ceph_inode_info *ci, char *val,
+                                        size_t size)
 {
-       return snprintf(val, size, "%lld", ci->i_subdirs);
+       return ceph_fmt_xattr(val, size, "%lld", ci->i_subdirs);
 }
 
-static size_t ceph_vxattrcb_dir_rentries(struct ceph_inode_info *ci, char *val,
-                                        size_t size)
+static ssize_t ceph_vxattrcb_dir_rentries(struct ceph_inode_info *ci, char *val,
+                                         size_t size)
 {
-       return snprintf(val, size, "%lld", ci->i_rfiles + ci->i_rsubdirs);
+       return ceph_fmt_xattr(val, size, "%lld",
+                               ci->i_rfiles + ci->i_rsubdirs);
 }
 
-static size_t ceph_vxattrcb_dir_rfiles(struct ceph_inode_info *ci, char *val,
-                                      size_t size)
+static ssize_t ceph_vxattrcb_dir_rfiles(struct ceph_inode_info *ci, char *val,
+                                       size_t size)
 {
-       return snprintf(val, size, "%lld", ci->i_rfiles);
+       return ceph_fmt_xattr(val, size, "%lld", ci->i_rfiles);
 }
 
-static size_t ceph_vxattrcb_dir_rsubdirs(struct ceph_inode_info *ci, char *val,
-                                        size_t size)
+static ssize_t ceph_vxattrcb_dir_rsubdirs(struct ceph_inode_info *ci, char *val,
+                                         size_t size)
 {
-       return snprintf(val, size, "%lld", ci->i_rsubdirs);
+       return ceph_fmt_xattr(val, size, "%lld", ci->i_rsubdirs);
 }
 
-static size_t ceph_vxattrcb_dir_rbytes(struct ceph_inode_info *ci, char *val,
-                                      size_t size)
+static ssize_t ceph_vxattrcb_dir_rbytes(struct ceph_inode_info *ci, char *val,
+                                       size_t size)
 {
-       return snprintf(val, size, "%lld", ci->i_rbytes);
+       return ceph_fmt_xattr(val, size, "%lld", ci->i_rbytes);
 }
 
-static size_t ceph_vxattrcb_dir_rctime(struct ceph_inode_info *ci, char *val,
-                                      size_t size)
+static ssize_t ceph_vxattrcb_dir_rctime(struct ceph_inode_info *ci, char *val,
+                                       size_t size)
 {
-       return snprintf(val, size, "%lld.09%ld", ci->i_rctime.tv_sec,
-                       ci->i_rctime.tv_nsec);
+       return ceph_fmt_xattr(val, size, "%lld.%09ld", ci->i_rctime.tv_sec,
+                               ci->i_rctime.tv_nsec);
 }
 
 /* dir pin */
@@ -234,10 +249,10 @@ static bool ceph_vxattrcb_dir_pin_exists(struct ceph_inode_info *ci)
        return ci->i_dir_pin != -ENODATA;
 }
 
-static size_t ceph_vxattrcb_dir_pin(struct ceph_inode_info *ci, char *val,
-                                    size_t size)
+static ssize_t ceph_vxattrcb_dir_pin(struct ceph_inode_info *ci, char *val,
+                                    size_t size)
 {
-       return snprintf(val, size, "%d", (int)ci->i_dir_pin);
+       return ceph_fmt_xattr(val, size, "%d", (int)ci->i_dir_pin);
 }
 
 /* quotas */
@@ -254,23 +269,36 @@ static bool ceph_vxattrcb_quota_exists(struct ceph_inode_info *ci)
        return ret;
 }
 
-static size_t ceph_vxattrcb_quota(struct ceph_inode_info *ci, char *val,
-                                 size_t size)
+static ssize_t ceph_vxattrcb_quota(struct ceph_inode_info *ci, char *val,
+                                  size_t size)
+{
+       return ceph_fmt_xattr(val, size, "max_bytes=%llu max_files=%llu",
+                               ci->i_max_bytes, ci->i_max_files);
+}
+
+static ssize_t ceph_vxattrcb_quota_max_bytes(struct ceph_inode_info *ci,
+                                            char *val, size_t size)
 {
-       return snprintf(val, size, "max_bytes=%llu max_files=%llu",
-                       ci->i_max_bytes, ci->i_max_files);
+       return ceph_fmt_xattr(val, size, "%llu", ci->i_max_bytes);
 }
 
-static size_t ceph_vxattrcb_quota_max_bytes(struct ceph_inode_info *ci,
-                                           char *val, size_t size)
+static ssize_t ceph_vxattrcb_quota_max_files(struct ceph_inode_info *ci,
+                                            char *val, size_t size)
 {
-       return snprintf(val, size, "%llu", ci->i_max_bytes);
+       return ceph_fmt_xattr(val, size, "%llu", ci->i_max_files);
 }
 
-static size_t ceph_vxattrcb_quota_max_files(struct ceph_inode_info *ci,
-                                           char *val, size_t size)
+/* snapshots */
+static bool ceph_vxattrcb_snap_btime_exists(struct ceph_inode_info *ci)
 {
-       return snprintf(val, size, "%llu", ci->i_max_files);
+       return (ci->i_snap_btime.tv_sec != 0 || ci->i_snap_btime.tv_nsec != 0);
+}
+
+static ssize_t ceph_vxattrcb_snap_btime(struct ceph_inode_info *ci, char *val,
+                                       size_t size)
+{
+       return ceph_fmt_xattr(val, size, "%lld.%09ld", ci->i_snap_btime.tv_sec,
+                               ci->i_snap_btime.tv_nsec);
 }
 
 #define CEPH_XATTR_NAME(_type, _name)  XATTR_CEPH_PREFIX #_type "." #_name
@@ -327,7 +355,7 @@ static struct ceph_vxattr ceph_dir_vxattrs[] = {
        XATTR_RSTAT_FIELD(dir, rctime),
        {
                .name = "ceph.dir.pin",
-               .name_size = sizeof("ceph.dir_pin"),
+               .name_size = sizeof("ceph.dir.pin"),
                .getxattr_cb = ceph_vxattrcb_dir_pin,
                .exists_cb = ceph_vxattrcb_dir_pin_exists,
                .flags = VXATTR_FLAG_HIDDEN,
@@ -341,9 +369,15 @@ static struct ceph_vxattr ceph_dir_vxattrs[] = {
        },
        XATTR_QUOTA_FIELD(quota, max_bytes),
        XATTR_QUOTA_FIELD(quota, max_files),
+       {
+               .name = "ceph.snap.btime",
+               .name_size = sizeof("ceph.snap.btime"),
+               .getxattr_cb = ceph_vxattrcb_snap_btime,
+               .exists_cb = ceph_vxattrcb_snap_btime_exists,
+               .flags = VXATTR_FLAG_READONLY,
+       },
        { .name = NULL, 0 }     /* Required table terminator */
 };
-static size_t ceph_dir_vxattrs_name_size;      /* total size of all names */
 
 /* files */
 
@@ -360,9 +394,15 @@ static struct ceph_vxattr ceph_file_vxattrs[] = {
        XATTR_LAYOUT_FIELD(file, layout, object_size),
        XATTR_LAYOUT_FIELD(file, layout, pool),
        XATTR_LAYOUT_FIELD(file, layout, pool_namespace),
+       {
+               .name = "ceph.snap.btime",
+               .name_size = sizeof("ceph.snap.btime"),
+               .getxattr_cb = ceph_vxattrcb_snap_btime,
+               .exists_cb = ceph_vxattrcb_snap_btime_exists,
+               .flags = VXATTR_FLAG_READONLY,
+       },
        { .name = NULL, 0 }     /* Required table terminator */
 };
-static size_t ceph_file_vxattrs_name_size;     /* total size of all names */
 
 static struct ceph_vxattr *ceph_inode_vxattrs(struct inode *inode)
 {
@@ -373,47 +413,6 @@ static struct ceph_vxattr *ceph_inode_vxattrs(struct inode *inode)
        return NULL;
 }
 
-static size_t ceph_vxattrs_name_size(struct ceph_vxattr *vxattrs)
-{
-       if (vxattrs == ceph_dir_vxattrs)
-               return ceph_dir_vxattrs_name_size;
-       if (vxattrs == ceph_file_vxattrs)
-               return ceph_file_vxattrs_name_size;
-       BUG_ON(vxattrs);
-       return 0;
-}
-
-/*
- * Compute the aggregate size (including terminating '\0') of all
- * virtual extended attribute names in the given vxattr table.
- */
-static size_t __init vxattrs_name_size(struct ceph_vxattr *vxattrs)
-{
-       struct ceph_vxattr *vxattr;
-       size_t size = 0;
-
-       for (vxattr = vxattrs; vxattr->name; vxattr++) {
-               if (!(vxattr->flags & VXATTR_FLAG_HIDDEN))
-                       size += vxattr->name_size;
-       }
-
-       return size;
-}
-
-/* Routines called at initialization and exit time */
-
-void __init ceph_xattr_init(void)
-{
-       ceph_dir_vxattrs_name_size = vxattrs_name_size(ceph_dir_vxattrs);
-       ceph_file_vxattrs_name_size = vxattrs_name_size(ceph_file_vxattrs);
-}
-
-void ceph_xattr_exit(void)
-{
-       ceph_dir_vxattrs_name_size = 0;
-       ceph_file_vxattrs_name_size = 0;
-}
-
 static struct ceph_vxattr *ceph_match_vxattr(struct inode *inode,
                                                const char *name)
 {
@@ -523,8 +522,8 @@ static int __set_xattr(struct ceph_inode_info *ci,
                dout("__set_xattr_val p=%p\n", p);
        }
 
-       dout("__set_xattr_val added %llx.%llx xattr %p %s=%.*s\n",
-            ceph_vinop(&ci->vfs_inode), xattr, name, val_len, val);
+       dout("__set_xattr_val added %llx.%llx xattr %p %.*s=%.*s\n",
+            ceph_vinop(&ci->vfs_inode), xattr, name_len, name, val_len, val);
 
        return 0;
 }
@@ -823,7 +822,7 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,
        struct ceph_inode_xattr *xattr;
        struct ceph_vxattr *vxattr = NULL;
        int req_mask;
-       int err;
+       ssize_t err;
 
        /* let's see if a virtual xattr was requested */
        vxattr = ceph_match_vxattr(inode, name);
@@ -835,8 +834,11 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,
                if (err)
                        return err;
                err = -ENODATA;
-               if (!(vxattr->exists_cb && !vxattr->exists_cb(ci)))
+               if (!(vxattr->exists_cb && !vxattr->exists_cb(ci))) {
                        err = vxattr->getxattr_cb(ci, value, size);
+                       if (size && size < err)
+                               err = -ERANGE;
+               }
                return err;
        }
 
@@ -897,10 +899,9 @@ ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size)
        struct inode *inode = d_inode(dentry);
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_vxattr *vxattrs = ceph_inode_vxattrs(inode);
-       u32 vir_namelen = 0;
+       bool len_only = (size == 0);
        u32 namelen;
        int err;
-       u32 len;
        int i;
 
        spin_lock(&ci->i_ceph_lock);
@@ -919,38 +920,45 @@ ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size)
        err = __build_xattrs(inode);
        if (err < 0)
                goto out;
-       /*
-        * Start with virtual dir xattr names (if any) (including
-        * terminating '\0' characters for each).
-        */
-       vir_namelen = ceph_vxattrs_name_size(vxattrs);
 
-       /* adding 1 byte per each variable due to the null termination */
+       /* add 1 byte for each xattr due to the null termination */
        namelen = ci->i_xattrs.names_size + ci->i_xattrs.count;
-       err = -ERANGE;
-       if (size && vir_namelen + namelen > size)
-               goto out;
-
-       err = namelen + vir_namelen;
-       if (size == 0)
-               goto out;
+       if (!len_only) {
+               if (namelen > size) {
+                       err = -ERANGE;
+                       goto out;
+               }
+               names = __copy_xattr_names(ci, names);
+               size -= namelen;
+       }
 
-       names = __copy_xattr_names(ci, names);
 
        /* virtual xattr names, too */
-       err = namelen;
        if (vxattrs) {
                for (i = 0; vxattrs[i].name; i++) {
-                       if (!(vxattrs[i].flags & VXATTR_FLAG_HIDDEN) &&
-                           !(vxattrs[i].exists_cb &&
-                             !vxattrs[i].exists_cb(ci))) {
-                               len = sprintf(names, "%s", vxattrs[i].name);
-                               names += len + 1;
-                               err += len + 1;
+                       size_t this_len;
+
+                       if (vxattrs[i].flags & VXATTR_FLAG_HIDDEN)
+                               continue;
+                       if (vxattrs[i].exists_cb && !vxattrs[i].exists_cb(ci))
+                               continue;
+
+                       this_len = strlen(vxattrs[i].name) + 1;
+                       namelen += this_len;
+                       if (len_only)
+                               continue;
+
+                       if (this_len > size) {
+                               err = -ERANGE;
+                               goto out;
                        }
+
+                       memcpy(names, vxattrs[i].name, this_len);
+                       names += this_len;
+                       size -= this_len;
                }
        }
-
+       err = namelen;
 out:
        spin_unlock(&ci->i_ceph_lock);
        return err;
@@ -1206,4 +1214,138 @@ bool ceph_security_xattr_deadlock(struct inode *in)
        spin_unlock(&ci->i_ceph_lock);
        return ret;
 }
+
+#ifdef CONFIG_CEPH_FS_SECURITY_LABEL
+int ceph_security_init_secctx(struct dentry *dentry, umode_t mode,
+                          struct ceph_acl_sec_ctx *as_ctx)
+{
+       struct ceph_pagelist *pagelist = as_ctx->pagelist;
+       const char *name;
+       size_t name_len;
+       int err;
+
+       err = security_dentry_init_security(dentry, mode, &dentry->d_name,
+                                           &as_ctx->sec_ctx,
+                                           &as_ctx->sec_ctxlen);
+       if (err < 0) {
+               WARN_ON_ONCE(err != -EOPNOTSUPP);
+               err = 0; /* do nothing */
+               goto out;
+       }
+
+       err = -ENOMEM;
+       if (!pagelist) {
+               pagelist = ceph_pagelist_alloc(GFP_KERNEL);
+               if (!pagelist)
+                       goto out;
+               err = ceph_pagelist_reserve(pagelist, PAGE_SIZE);
+               if (err)
+                       goto out;
+               ceph_pagelist_encode_32(pagelist, 1);
+       }
+
+       /*
+        * FIXME: Make security_dentry_init_security() generic. Currently
+        * It only supports single security module and only selinux has
+        * dentry_init_security hook.
+        */
+       name = XATTR_NAME_SELINUX;
+       name_len = strlen(name);
+       err = ceph_pagelist_reserve(pagelist,
+                                   4 * 2 + name_len + as_ctx->sec_ctxlen);
+       if (err)
+               goto out;
+
+       if (as_ctx->pagelist) {
+               /* update count of KV pairs */
+               BUG_ON(pagelist->length <= sizeof(__le32));
+               if (list_is_singular(&pagelist->head)) {
+                       le32_add_cpu((__le32*)pagelist->mapped_tail, 1);
+               } else {
+                       struct page *page = list_first_entry(&pagelist->head,
+                                                            struct page, lru);
+                       void *addr = kmap_atomic(page);
+                       le32_add_cpu((__le32*)addr, 1);
+                       kunmap_atomic(addr);
+               }
+       } else {
+               as_ctx->pagelist = pagelist;
+       }
+
+       ceph_pagelist_encode_32(pagelist, name_len);
+       ceph_pagelist_append(pagelist, name, name_len);
+
+       ceph_pagelist_encode_32(pagelist, as_ctx->sec_ctxlen);
+       ceph_pagelist_append(pagelist, as_ctx->sec_ctx, as_ctx->sec_ctxlen);
+
+       err = 0;
+out:
+       if (pagelist && !as_ctx->pagelist)
+               ceph_pagelist_release(pagelist);
+       return err;
+}
+
+void ceph_security_invalidate_secctx(struct inode *inode)
+{
+       security_inode_invalidate_secctx(inode);
+}
+
+static int ceph_xattr_set_security_label(const struct xattr_handler *handler,
+                                   struct dentry *unused, struct inode *inode,
+                                   const char *key, const void *buf,
+                                   size_t buflen, int flags)
+{
+       if (security_ismaclabel(key)) {
+               const char *name = xattr_full_name(handler, key);
+               return __ceph_setxattr(inode, name, buf, buflen, flags);
+       }
+       return  -EOPNOTSUPP;
+}
+
+static int ceph_xattr_get_security_label(const struct xattr_handler *handler,
+                                   struct dentry *unused, struct inode *inode,
+                                   const char *key, void *buf, size_t buflen)
+{
+       if (security_ismaclabel(key)) {
+               const char *name = xattr_full_name(handler, key);
+               return __ceph_getxattr(inode, name, buf, buflen);
+       }
+       return  -EOPNOTSUPP;
+}
+
+static const struct xattr_handler ceph_security_label_handler = {
+       .prefix = XATTR_SECURITY_PREFIX,
+       .get    = ceph_xattr_get_security_label,
+       .set    = ceph_xattr_set_security_label,
+};
+#endif
 #endif
+
+void ceph_release_acl_sec_ctx(struct ceph_acl_sec_ctx *as_ctx)
+{
+#ifdef CONFIG_CEPH_FS_POSIX_ACL
+       posix_acl_release(as_ctx->acl);
+       posix_acl_release(as_ctx->default_acl);
+#endif
+#ifdef CONFIG_CEPH_FS_SECURITY_LABEL
+       security_release_secctx(as_ctx->sec_ctx, as_ctx->sec_ctxlen);
+#endif
+       if (as_ctx->pagelist)
+               ceph_pagelist_release(as_ctx->pagelist);
+}
+
+/*
+ * List of handlers for synthetic system.* attributes. Other
+ * attributes are handled directly.
+ */
+const struct xattr_handler *ceph_xattr_handlers[] = {
+#ifdef CONFIG_CEPH_FS_POSIX_ACL
+       &posix_acl_access_xattr_handler,
+       &posix_acl_default_xattr_handler,
+#endif
+#ifdef CONFIG_CEPH_FS_SECURITY_LABEL
+       &ceph_security_label_handler,
+#endif
+       &ceph_other_xattr_handler,
+       NULL,
+};
index 523e9ea..b16219e 100644 (file)
@@ -13,9 +13,11 @@ config CIFS
        select CRYPTO_LIB_ARC4
        select CRYPTO_AEAD2
        select CRYPTO_CCM
+       select CRYPTO_GCM
        select CRYPTO_ECB
        select CRYPTO_AES
        select CRYPTO_DES
+       select KEYS
        help
          This is the client VFS module for the SMB3 family of NAS protocols,
          (including support for the most recent, most secure dialect SMB3.1.1)
@@ -109,7 +111,7 @@ config CIFS_WEAK_PW_HASH
 
 config CIFS_UPCALL
        bool "Kerberos/SPNEGO advanced session setup"
-       depends on CIFS && KEYS
+       depends on CIFS
        select DNS_RESOLVER
        help
          Enables an upcall mechanism for CIFS which accesses userspace helper
@@ -144,14 +146,6 @@ config CIFS_POSIX
          (such as Samba 3.10 and later) which can negotiate
          CIFS POSIX ACL support.  If unsure, say N.
 
-config CIFS_ACL
-       bool "Provide CIFS ACL support"
-       depends on CIFS_XATTR && KEYS
-       help
-         Allows fetching CIFS/NTFS ACL from the server.  The DACL blob
-         is handed over to the application/caller.  See the man
-         page for getcifsacl for more information.  If unsure, say Y.
-
 config CIFS_DEBUG
        bool "Enable CIFS debugging routines"
        default y
@@ -184,7 +178,7 @@ config CIFS_DEBUG_DUMP_KEYS
 
 config CIFS_DFS_UPCALL
        bool "DFS feature support"
-       depends on CIFS && KEYS
+       depends on CIFS
        select DNS_RESOLVER
        help
          Distributed File System (DFS) support is used to access shares
@@ -203,10 +197,10 @@ config CIFS_NFSD_EXPORT
          Allows NFS server to export a CIFS mounted share (nfsd over cifs)
 
 config CIFS_SMB_DIRECT
-       bool "SMB Direct support (Experimental)"
+       bool "SMB Direct support"
        depends on CIFS=m && INFINIBAND && INFINIBAND_ADDR_TRANS || CIFS=y && INFINIBAND=y && INFINIBAND_ADDR_TRANS=y
        help
-         Enables SMB Direct experimental support for SMB 3.0, 3.02 and 3.1.1.
+         Enables SMB Direct support for SMB 3.0, 3.02 and 3.1.1.
          SMB Direct allows transferring SMB packets over RDMA. If unsure,
          say N.
 
index 51af69a..41332f2 100644 (file)
@@ -10,10 +10,9 @@ cifs-y := trace.o cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o \
          cifs_unicode.o nterr.o cifsencrypt.o \
          readdir.o ioctl.o sess.o export.o smb1ops.o winucase.o \
          smb2ops.o smb2maperror.o smb2transport.o \
-         smb2misc.o smb2pdu.o smb2inode.o smb2file.o
+         smb2misc.o smb2pdu.o smb2inode.o smb2file.o cifsacl.o
 
 cifs-$(CONFIG_CIFS_XATTR) += xattr.o
-cifs-$(CONFIG_CIFS_ACL) += cifsacl.o
 
 cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
 
index ec933fb..a38d796 100644 (file)
@@ -240,9 +240,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
 #ifdef CONFIG_CIFS_XATTR
        seq_printf(m, ",XATTR");
 #endif
-#ifdef CONFIG_CIFS_ACL
        seq_printf(m, ",ACL");
-#endif
        seq_putc(m, '\n');
        seq_printf(m, "CIFSMaxBufSize: %d\n", CIFSMaxBufSize);
        seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid);
index ed49222..b326d2c 100644 (file)
@@ -52,6 +52,7 @@
 #define CIFS_MOUNT_UID_FROM_ACL 0x2000000 /* try to get UID via special SID */
 #define CIFS_MOUNT_NO_HANDLE_CACHE 0x4000000 /* disable caching dir handles */
 #define CIFS_MOUNT_NO_DFS 0x8000000 /* disable DFS resolving */
+#define CIFS_MOUNT_MODE_FROM_SID 0x10000000 /* retrieve mode from special ACE */
 
 struct cifs_sb_info {
        struct rb_root tlink_tree;
@@ -83,5 +84,10 @@ struct cifs_sb_info {
         * failover properly.
         */
        char *origin_fullpath; /* \\HOST\SHARE\[OPTIONAL PATH] */
+       /*
+        * Indicate whether serverino option was turned off later
+        * (cifs_autodisable_serverino) in order to match new mounts.
+        */
+       bool mnt_cifs_serverino_autodisabled;
 };
 #endif                         /* _CIFS_FS_SB_H */
index 24635b6..3289b56 100644 (file)
@@ -526,6 +526,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
                seq_puts(s, ",nobrl");
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_HANDLE_CACHE)
                seq_puts(s, ",nohandlecache");
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)
+               seq_puts(s, ",modefromsid");
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
                seq_puts(s, ",cifsacl");
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
@@ -554,6 +556,11 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
        seq_printf(s, ",bsize=%u", cifs_sb->bsize);
        seq_printf(s, ",echo_interval=%lu",
                        tcon->ses->server->echo_interval / HZ);
+
+       /* Only display max_credits if it was overridden on mount */
+       if (tcon->ses->server->max_credits != SMB2_MAX_CREDITS_AVAILABLE)
+               seq_printf(s, ",max_credits=%u", tcon->ses->server->max_credits);
+
        if (tcon->snapshot_time)
                seq_printf(s, ",snapshot=%llu", tcon->snapshot_time);
        if (tcon->handle_timeout)
@@ -1097,6 +1104,10 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
                goto out;
        }
 
+       rc = -EOPNOTSUPP;
+       if (!target_tcon->ses->server->ops->copychunk_range)
+               goto out;
+
        /*
         * Note: cifs case is easier than btrfs since server responsible for
         * checks for proper open modes and file type and if it wants
@@ -1108,11 +1119,12 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
        /* should we flush first and last page first */
        truncate_inode_pages(&target_inode->i_data, 0);
 
-       if (target_tcon->ses->server->ops->copychunk_range)
+       rc = file_modified(dst_file);
+       if (!rc)
                rc = target_tcon->ses->server->ops->copychunk_range(xid,
                        smb_file_src, smb_file_target, off, len, destoff);
-       else
-               rc = -EOPNOTSUPP;
+
+       file_accessed(src_file);
 
        /* force revalidate of size and timestamps of target file now
         * that target is updated on the server
@@ -1517,11 +1529,9 @@ init_cifs(void)
                goto out_destroy_dfs_cache;
 #endif /* CONFIG_CIFS_UPCALL */
 
-#ifdef CONFIG_CIFS_ACL
        rc = init_cifs_idmap();
        if (rc)
                goto out_register_key_type;
-#endif /* CONFIG_CIFS_ACL */
 
        rc = register_filesystem(&cifs_fs_type);
        if (rc)
@@ -1536,10 +1546,8 @@ init_cifs(void)
        return 0;
 
 out_init_cifs_idmap:
-#ifdef CONFIG_CIFS_ACL
        exit_cifs_idmap();
 out_register_key_type:
-#endif
 #ifdef CONFIG_CIFS_UPCALL
        exit_cifs_spnego();
 out_destroy_dfs_cache:
@@ -1571,9 +1579,7 @@ exit_cifs(void)
        unregister_filesystem(&cifs_fs_type);
        unregister_filesystem(&smb3_fs_type);
        cifs_dfs_release_automount_timer();
-#ifdef CONFIG_CIFS_ACL
        exit_cifs_idmap();
-#endif
 #ifdef CONFIG_CIFS_UPCALL
        exit_cifs_spnego();
 #endif
@@ -1607,5 +1613,6 @@ MODULE_SOFTDEP("pre: sha256");
 MODULE_SOFTDEP("pre: sha512");
 MODULE_SOFTDEP("pre: aead2");
 MODULE_SOFTDEP("pre: ccm");
+MODULE_SOFTDEP("pre: gcm");
 module_init(init_cifs)
 module_exit(exit_cifs)
index aea0057..4b21a90 100644 (file)
@@ -152,5 +152,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
 extern const struct export_operations cifs_export_ops;
 #endif /* CONFIG_CIFS_NFSD_EXPORT */
 
-#define CIFS_VERSION   "2.20"
+#define CIFS_VERSION   "2.21"
 #endif                         /* _CIFSFS_H */
index 4777b3c..fe610e7 100644 (file)
@@ -550,6 +550,7 @@ struct smb_vol {
        bool override_gid:1;
        bool dynperm:1;
        bool noperm:1;
+       bool mode_ace:1;
        bool no_psx_acl:1; /* set if posix acl support should be disabled */
        bool cifs_acl:1;
        bool backupuid_specified; /* mount option  backupuid  is specified */
@@ -600,6 +601,7 @@ struct smb_vol {
        __u64 snapshot_time; /* needed for timewarp tokens */
        __u32 handle_timeout; /* persistent and durable handle timeout in ms */
        unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */
+       __u16 compression; /* compression algorithm 0xFFFF default 0=disabled */
 };
 
 /**
@@ -617,7 +619,8 @@ struct smb_vol {
                         CIFS_MOUNT_FSCACHE | CIFS_MOUNT_MF_SYMLINKS | \
                         CIFS_MOUNT_MULTIUSER | CIFS_MOUNT_STRICT_IO | \
                         CIFS_MOUNT_CIFS_BACKUPUID | CIFS_MOUNT_CIFS_BACKUPGID | \
-                        CIFS_MOUNT_NO_DFS)
+                        CIFS_MOUNT_UID_FROM_ACL | CIFS_MOUNT_NO_HANDLE_CACHE | \
+                        CIFS_MOUNT_NO_DFS | CIFS_MOUNT_MODE_FROM_SID)
 
 /**
  * Generic VFS superblock mount flags (s_flags) to consider when
@@ -1870,7 +1873,6 @@ extern unsigned int cifs_min_small;  /* min size of small buf pool */
 extern unsigned int cifs_max_pending; /* MAX requests at once to server*/
 extern bool disable_legacy_dialects;  /* forbid vers=1.0 and vers=2.0 mounts */
 
-#ifdef CONFIG_CIFS_ACL
 GLOBAL_EXTERN struct rb_root uidtree;
 GLOBAL_EXTERN struct rb_root gidtree;
 GLOBAL_EXTERN spinlock_t siduidlock;
@@ -1879,7 +1881,6 @@ GLOBAL_EXTERN struct rb_root siduidtree;
 GLOBAL_EXTERN struct rb_root sidgidtree;
 GLOBAL_EXTERN spinlock_t uidsidlock;
 GLOBAL_EXTERN spinlock_t gidsidlock;
-#endif /* CONFIG_CIFS_ACL */
 
 void cifs_oplock_break(struct work_struct *work);
 void cifs_queue_oplock_break(struct cifsFileInfo *cfile);
index 1fbd928..e2f9596 100644 (file)
@@ -3600,11 +3600,9 @@ static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
        return size;
 }
 
-static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
+static void convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
                                     const struct posix_acl_xattr_entry *local_ace)
 {
-       __u16 rc = 0; /* 0 = ACL converted ok */
-
        cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
        cifs_ace->cifs_e_tag =  le16_to_cpu(local_ace->e_tag);
        /* BB is there a better way to handle the large uid? */
@@ -3617,7 +3615,6 @@ static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
        cifs_dbg(FYI, "perm %d tag %d id %d\n",
                 ace->e_perm, ace->e_tag, ace->e_id);
 */
-       return rc;
 }
 
 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
@@ -3653,13 +3650,8 @@ static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
                cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
                return 0;
        }
-       for (i = 0; i < count; i++) {
-               rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
-               if (rc != 0) {
-                       /* ACE not converted */
-                       break;
-               }
-       }
+       for (i = 0; i < count; i++)
+               convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
        if (rc == 0) {
                rc = (__u16)(count * sizeof(struct cifs_posix_ace));
                rc += sizeof(struct cifs_posix_acl);
@@ -3920,7 +3912,6 @@ GetExtAttrOut:
 
 #endif /* CONFIG_POSIX */
 
-#ifdef CONFIG_CIFS_ACL
 /*
  * Initialize NT TRANSACT SMB into small smb request buffer.  This assumes that
  * all NT TRANSACTS that we init here have total parm and data under about 400
@@ -4164,7 +4155,6 @@ setCifsAclRetry:
        return (rc);
 }
 
-#endif /* CONFIG_CIFS_ACL */
 
 /* Legacy Query Path Information call for lookup to old servers such
    as Win9x/WinME */
index 714a359..a4830ce 100644 (file)
@@ -96,7 +96,8 @@ enum {
        Opt_multiuser, Opt_sloppy, Opt_nosharesock,
        Opt_persistent, Opt_nopersistent,
        Opt_resilient, Opt_noresilient,
-       Opt_domainauto, Opt_rdma,
+       Opt_domainauto, Opt_rdma, Opt_modesid,
+       Opt_compress,
 
        /* Mount options which take numeric value */
        Opt_backupuid, Opt_backupgid, Opt_uid,
@@ -175,6 +176,7 @@ static const match_table_t cifs_mount_option_tokens = {
        { Opt_serverino, "serverino" },
        { Opt_noserverino, "noserverino" },
        { Opt_rwpidforward, "rwpidforward" },
+       { Opt_modesid, "modefromsid" },
        { Opt_cifsacl, "cifsacl" },
        { Opt_nocifsacl, "nocifsacl" },
        { Opt_acl, "acl" },
@@ -212,6 +214,7 @@ static const match_table_t cifs_mount_option_tokens = {
        { Opt_echo_interval, "echo_interval=%s" },
        { Opt_max_credits, "max_credits=%s" },
        { Opt_snapshot, "snapshot=%s" },
+       { Opt_compress, "compress=%s" },
 
        { Opt_blank_user, "user=" },
        { Opt_blank_user, "username=" },
@@ -706,10 +709,10 @@ static bool
 server_unresponsive(struct TCP_Server_Info *server)
 {
        /*
-        * We need to wait 2 echo intervals to make sure we handle such
+        * We need to wait 3 echo intervals to make sure we handle such
         * situations right:
         * 1s  client sends a normal SMB request
-        * 2s  client gets a response
+        * 3s  client gets a response
         * 30s echo workqueue job pops, and decides we got a response recently
         *     and don't need to send another
         * ...
@@ -718,9 +721,9 @@ server_unresponsive(struct TCP_Server_Info *server)
         */
        if ((server->tcpStatus == CifsGood ||
            server->tcpStatus == CifsNeedNegotiate) &&
-           time_after(jiffies, server->lstrp + 2 * server->echo_interval)) {
+           time_after(jiffies, server->lstrp + 3 * server->echo_interval)) {
                cifs_dbg(VFS, "Server %s has not responded in %lu seconds. Reconnecting...\n",
-                        server->hostname, (2 * server->echo_interval) / HZ);
+                        server->hostname, (3 * server->echo_interval) / HZ);
                cifs_reconnect(server);
                wake_up(&server->response_q);
                return true;
@@ -1223,11 +1226,11 @@ next_pdu:
                                         atomic_read(&midCount));
                                cifs_dump_mem("Received Data is: ", bufs[i],
                                              HEADER_SIZE(server));
+                               smb2_add_credits_from_hdr(bufs[i], server);
 #ifdef CONFIG_CIFS_DEBUG2
                                if (server->ops->dump_detail)
                                        server->ops->dump_detail(bufs[i],
                                                                 server);
-                               smb2_add_credits_from_hdr(bufs[i], server);
                                cifs_dump_mids(server);
 #endif /* CIFS_DEBUG2 */
                        }
@@ -1830,6 +1833,9 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                case Opt_rwpidforward:
                        vol->rwpidforward = 1;
                        break;
+               case Opt_modesid:
+                       vol->mode_ace = 1;
+                       break;
                case Opt_cifsacl:
                        vol->cifs_acl = 1;
                        break;
@@ -1911,6 +1917,11 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                case Opt_rdma:
                        vol->rdma = true;
                        break;
+               case Opt_compress:
+                       vol->compression = UNKNOWN_TYPE;
+                       cifs_dbg(VFS,
+                               "SMB3 compression support is experimental\n");
+                       break;
 
                /* Numeric Values */
                case Opt_backupuid:
@@ -2544,8 +2555,15 @@ static int match_server(struct TCP_Server_Info *server, struct smb_vol *vol)
        if (vol->nosharesock)
                return 0;
 
-       /* BB update this for smb3any and default case */
-       if ((server->vals != vol->vals) || (server->ops != vol->ops))
+       /* If multidialect negotiation see if existing sessions match one */
+       if (strcmp(vol->vals->version_string, SMB3ANY_VERSION_STRING) == 0) {
+               if (server->vals->protocol_id < SMB30_PROT_ID)
+                       return 0;
+       } else if (strcmp(vol->vals->version_string,
+                  SMBDEFAULT_VERSION_STRING) == 0) {
+               if (server->vals->protocol_id < SMB21_PROT_ID)
+                       return 0;
+       } else if ((server->vals != vol->vals) || (server->ops != vol->ops))
                return 0;
 
        if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns))
@@ -2680,6 +2698,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
        tcp_ses->sequence_number = 0;
        tcp_ses->reconnect_instance = 1;
        tcp_ses->lstrp = jiffies;
+       tcp_ses->compress_algorithm = cpu_to_le16(volume_info->compression);
        spin_lock_init(&tcp_ses->req_lock);
        INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
        INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
@@ -3460,12 +3479,16 @@ compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data)
 {
        struct cifs_sb_info *old = CIFS_SB(sb);
        struct cifs_sb_info *new = mnt_data->cifs_sb;
+       unsigned int oldflags = old->mnt_cifs_flags & CIFS_MOUNT_MASK;
+       unsigned int newflags = new->mnt_cifs_flags & CIFS_MOUNT_MASK;
 
        if ((sb->s_flags & CIFS_MS_MASK) != (mnt_data->flags & CIFS_MS_MASK))
                return 0;
 
-       if ((old->mnt_cifs_flags & CIFS_MOUNT_MASK) !=
-           (new->mnt_cifs_flags & CIFS_MOUNT_MASK))
+       if (old->mnt_cifs_serverino_autodisabled)
+               newflags &= ~CIFS_MOUNT_SERVER_INUM;
+
+       if (oldflags != newflags)
                return 0;
 
        /*
@@ -3965,6 +3988,8 @@ int cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
                cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL;
        if (pvolume_info->rwpidforward)
                cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RWPIDFORWARD;
+       if (pvolume_info->mode_ace)
+               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MODE_FROM_SID;
        if (pvolume_info->cifs_acl)
                cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
        if (pvolume_info->backupuid_specified) {
@@ -4459,11 +4484,13 @@ cifs_are_all_path_components_accessible(struct TCP_Server_Info *server,
                                        unsigned int xid,
                                        struct cifs_tcon *tcon,
                                        struct cifs_sb_info *cifs_sb,
-                                       char *full_path)
+                                       char *full_path,
+                                       int added_treename)
 {
        int rc;
        char *s;
        char sep, tmp;
+       int skip = added_treename ? 1 : 0;
 
        sep = CIFS_DIR_SEP(cifs_sb);
        s = full_path;
@@ -4478,7 +4505,14 @@ cifs_are_all_path_components_accessible(struct TCP_Server_Info *server,
                /* next separator */
                while (*s && *s != sep)
                        s++;
-
+               /*
+                * if the treename is added, we then have to skip the first
+                * part within the separators
+                */
+               if (skip) {
+                       skip = 0;
+                       continue;
+               }
                /*
                 * temporarily null-terminate the path at the end of
                 * the current component
@@ -4526,8 +4560,7 @@ static int is_path_remote(struct cifs_sb_info *cifs_sb, struct smb_vol *vol,
 
        if (rc != -EREMOTE) {
                rc = cifs_are_all_path_components_accessible(server, xid, tcon,
-                                                            cifs_sb,
-                                                            full_path);
+                       cifs_sb, full_path, tcon->Flags & SMB_SHARE_IS_IN_DFS);
                if (rc != 0) {
                        cifs_dbg(VFS, "cannot query dirs between root and final path, "
                                 "enabling CIFS_MOUNT_USE_PREFIX_PATH\n");
index e3e1c13..1692c0c 100644 (file)
@@ -492,7 +492,7 @@ static struct dfs_cache_entry *__find_cache_entry(unsigned int hash,
 #ifdef CONFIG_CIFS_DEBUG2
                        char *name = get_tgt_name(ce);
 
-                       if (unlikely(IS_ERR(name))) {
+                       if (IS_ERR(name)) {
                                rcu_read_unlock();
                                return ERR_CAST(name);
                        }
index d7cc622..56ca4b8 100644 (file)
@@ -892,7 +892,6 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
                        cifs_dbg(FYI, "cifs_sfu_type failed: %d\n", tmprc);
        }
 
-#ifdef CONFIG_CIFS_ACL
        /* fill in 0777 bits from ACL */
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
                rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, full_path, fid);
@@ -902,7 +901,6 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
                        goto cgii_exit;
                }
        }
-#endif /* CONFIG_CIFS_ACL */
 
        /* fill in remaining high mode bits e.g. SUID, VTX */
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
@@ -2408,6 +2406,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
        struct inode *inode = d_inode(direntry);
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct cifsInodeInfo *cifsInode = CIFS_I(inode);
+       struct cifsFileInfo *wfile;
+       struct cifs_tcon *tcon;
        char *full_path = NULL;
        int rc = -EACCES;
        __u32 dosattr = 0;
@@ -2415,7 +2415,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
 
        xid = get_xid();
 
-       cifs_dbg(FYI, "setattr on file %pd attrs->iavalid 0x%x\n",
+       cifs_dbg(FYI, "setattr on file %pd attrs->ia_valid 0x%x\n",
                 direntry, attrs->ia_valid);
 
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
@@ -2454,6 +2454,20 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
        mapping_set_error(inode->i_mapping, rc);
        rc = 0;
 
+       if (attrs->ia_valid & ATTR_MTIME) {
+               rc = cifs_get_writable_file(cifsInode, false, &wfile);
+               if (!rc) {
+                       tcon = tlink_tcon(wfile->tlink);
+                       rc = tcon->ses->server->ops->flush(xid, tcon, &wfile->fid);
+                       cifsFileInfo_put(wfile);
+                       if (rc)
+                               return rc;
+               } else if (rc != -EBADF)
+                       return rc;
+               else
+                       rc = 0;
+       }
+
        if (attrs->ia_valid & ATTR_SIZE) {
                rc = cifs_set_file_size(inode, attrs, xid, full_path);
                if (rc != 0)
@@ -2466,7 +2480,6 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
        if (attrs->ia_valid & ATTR_GID)
                gid = attrs->ia_gid;
 
-#ifdef CONFIG_CIFS_ACL
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
                if (uid_valid(uid) || gid_valid(gid)) {
                        rc = id_mode_to_cifs_acl(inode, full_path, NO_CHANGE_64,
@@ -2478,7 +2491,6 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
                        }
                }
        } else
-#endif /* CONFIG_CIFS_ACL */
        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID))
                attrs->ia_valid &= ~(ATTR_UID | ATTR_GID);
 
@@ -2489,7 +2501,6 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
        if (attrs->ia_valid & ATTR_MODE) {
                mode = attrs->ia_mode;
                rc = 0;
-#ifdef CONFIG_CIFS_ACL
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
                        rc = id_mode_to_cifs_acl(inode, full_path, mode,
                                                INVALID_UID, INVALID_GID);
@@ -2499,7 +2510,6 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
                                goto cifs_setattr_exit;
                        }
                } else
-#endif /* CONFIG_CIFS_ACL */
                if (((mode & S_IWUGO) == 0) &&
                    (cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
 
index b1a696a..f383877 100644 (file)
@@ -539,6 +539,7 @@ cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
                        tcon = cifs_sb_master_tcon(cifs_sb);
 
                cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
+               cifs_sb->mnt_cifs_serverino_autodisabled = true;
                cifs_dbg(VFS, "Autodisabling the use of server inode numbers on %s.\n",
                         tcon ? tcon->treeName : "new server");
                cifs_dbg(VFS, "The server doesn't seem to support them properly or the files might be on different servers (DFS).\n");
index 9e430ae..b7421a0 100644 (file)
@@ -1223,16 +1223,15 @@ struct smb_version_operations smb1_operations = {
        .query_all_EAs = CIFSSMBQAllEAs,
        .set_EA = CIFSSMBSetEA,
 #endif /* CIFS_XATTR */
-#ifdef CONFIG_CIFS_ACL
        .get_acl = get_cifs_acl,
        .get_acl_by_fid = get_cifs_acl_by_fid,
        .set_acl = set_cifs_acl,
-#endif /* CIFS_ACL */
        .make_node = cifs_make_node,
 };
 
 struct smb_version_values smb1_values = {
        .version_string = SMB1_VERSION_STRING,
+       .protocol_id = SMB10_PROT_ID,
        .large_lock_type = LOCKING_ANDX_LARGE_FILES,
        .exclusive_lock_type = 0,
        .shared_lock_type = LOCKING_ANDX_SHARED_LOCK,
index 54bffb2..e6a1fc7 100644 (file)
@@ -88,14 +88,20 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
        }
 
        if (buf) {
-               /* open response does not have IndexNumber field - get it */
-               rc = SMB2_get_srv_num(xid, oparms->tcon, fid->persistent_fid,
+               /* if open response does not have IndexNumber field - get it */
+               if (smb2_data->IndexNumber == 0) {
+                       rc = SMB2_get_srv_num(xid, oparms->tcon,
+                                     fid->persistent_fid,
                                      fid->volatile_fid,
                                      &smb2_data->IndexNumber);
-               if (rc) {
-                       /* let get_inode_info disable server inode numbers */
-                       smb2_data->IndexNumber = 0;
-                       rc = 0;
+                       if (rc) {
+                               /*
+                                * let get_inode_info disable server inode
+                                * numbers
+                                */
+                               smb2_data->IndexNumber = 0;
+                               rc = 0;
+                       }
                }
                move_smb2_info_to_cifs(buf, smb2_data);
        }
index 278405d..d8d9cdf 100644 (file)
@@ -120,6 +120,8 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
                                SMB2_O_INFO_FILE, 0,
                                sizeof(struct smb2_file_all_info) +
                                          PATH_MAX * 2, 0, NULL);
+               if (rc)
+                       goto finished;
                smb2_set_next_command(tcon, &rqst[num_rqst]);
                smb2_set_related(&rqst[num_rqst++]);
                trace_smb3_query_info_compound_enter(xid, ses->Suid, tcon->tid,
@@ -147,6 +149,8 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
                                        COMPOUND_FID, current->tgid,
                                        FILE_DISPOSITION_INFORMATION,
                                        SMB2_O_INFO_FILE, 0, data, size);
+               if (rc)
+                       goto finished;
                smb2_set_next_command(tcon, &rqst[num_rqst]);
                smb2_set_related(&rqst[num_rqst++]);
                trace_smb3_rmdir_enter(xid, ses->Suid, tcon->tid, full_path);
@@ -163,6 +167,8 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
                                        COMPOUND_FID, current->tgid,
                                        FILE_END_OF_FILE_INFORMATION,
                                        SMB2_O_INFO_FILE, 0, data, size);
+               if (rc)
+                       goto finished;
                smb2_set_next_command(tcon, &rqst[num_rqst]);
                smb2_set_related(&rqst[num_rqst++]);
                trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path);
@@ -180,6 +186,8 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
                                        COMPOUND_FID, current->tgid,
                                        FILE_BASIC_INFORMATION,
                                        SMB2_O_INFO_FILE, 0, data, size);
+               if (rc)
+                       goto finished;
                smb2_set_next_command(tcon, &rqst[num_rqst]);
                smb2_set_related(&rqst[num_rqst++]);
                trace_smb3_set_info_compound_enter(xid, ses->Suid, tcon->tid,
@@ -206,6 +214,8 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
                                        COMPOUND_FID, current->tgid,
                                        FILE_RENAME_INFORMATION,
                                        SMB2_O_INFO_FILE, 0, data, size);
+               if (rc)
+                       goto finished;
                smb2_set_next_command(tcon, &rqst[num_rqst]);
                smb2_set_related(&rqst[num_rqst++]);
                trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path);
@@ -231,6 +241,8 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
                                        COMPOUND_FID, current->tgid,
                                        FILE_LINK_INFORMATION,
                                        SMB2_O_INFO_FILE, 0, data, size);
+               if (rc)
+                       goto finished;
                smb2_set_next_command(tcon, &rqst[num_rqst]);
                smb2_set_related(&rqst[num_rqst++]);
                trace_smb3_hardlink_enter(xid, ses->Suid, tcon->tid, full_path);
index 9fd56b0..a5bc1b6 100644 (file)
@@ -694,8 +694,51 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
 
        smb2_set_related(&rqst[1]);
 
+       /*
+        * We do not hold the lock for the open because in case
+        * SMB2_open needs to reconnect, it will end up calling
+        * cifs_mark_open_files_invalid() which takes the lock again
+        * thus causing a deadlock
+        */
+
+       mutex_unlock(&tcon->crfid.fid_mutex);
        rc = compound_send_recv(xid, ses, flags, 2, rqst,
                                resp_buftype, rsp_iov);
+       mutex_lock(&tcon->crfid.fid_mutex);
+
+       /*
+        * Now we need to check again as the cached root might have
+        * been successfully re-opened from a concurrent process
+        */
+
+       if (tcon->crfid.is_valid) {
+               /* work was already done */
+
+               /* stash fids for close() later */
+               struct cifs_fid fid = {
+                       .persistent_fid = pfid->persistent_fid,
+                       .volatile_fid = pfid->volatile_fid,
+               };
+
+               /*
+                * caller expects this func to set pfid to a valid
+                * cached root, so we copy the existing one and get a
+                * reference.
+                */
+               memcpy(pfid, tcon->crfid.fid, sizeof(*pfid));
+               kref_get(&tcon->crfid.refcount);
+
+               mutex_unlock(&tcon->crfid.fid_mutex);
+
+               if (rc == 0) {
+                       /* close extra handle outside of crit sec */
+                       SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
+               }
+               goto oshr_free;
+       }
+
+       /* Cached root is still invalid, continue normaly */
+
        if (rc)
                goto oshr_exit;
 
@@ -711,11 +754,12 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
        tcon->crfid.is_valid = true;
        kref_init(&tcon->crfid.refcount);
 
+       /* BB TBD check to see if oplock level check can be removed below */
        if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) {
                kref_get(&tcon->crfid.refcount);
-               oplock = smb2_parse_lease_state(server, o_rsp,
-                                               &oparms.fid->epoch,
-                                               oparms.fid->lease_key);
+               smb2_parse_contexts(server, o_rsp,
+                               &oparms.fid->epoch,
+                               oparms.fid->lease_key, &oplock, NULL);
        } else
                goto oshr_exit;
 
@@ -729,8 +773,9 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
                                (char *)&tcon->crfid.file_all_info))
                tcon->crfid.file_all_info_is_valid = 1;
 
- oshr_exit:
+oshr_exit:
        mutex_unlock(&tcon->crfid.fid_mutex);
+oshr_free:
        SMB2_open_free(&rqst[0]);
        SMB2_query_info_free(&rqst[1]);
        free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
@@ -2027,6 +2072,10 @@ smb2_set_related(struct smb_rqst *rqst)
        struct smb2_sync_hdr *shdr;
 
        shdr = (struct smb2_sync_hdr *)(rqst->rq_iov[0].iov_base);
+       if (shdr == NULL) {
+               cifs_dbg(FYI, "shdr NULL in smb2_set_related\n");
+               return;
+       }
        shdr->Flags |= SMB2_FLAGS_RELATED_OPERATIONS;
 }
 
@@ -2041,6 +2090,12 @@ smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst)
        unsigned long len = smb_rqst_len(server, rqst);
        int i, num_padding;
 
+       shdr = (struct smb2_sync_hdr *)(rqst->rq_iov[0].iov_base);
+       if (shdr == NULL) {
+               cifs_dbg(FYI, "shdr NULL in smb2_set_next_command\n");
+               return;
+       }
+
        /* SMB headers in a compound are 8 byte aligned. */
 
        /* No padding needed */
@@ -2080,7 +2135,6 @@ smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst)
        }
 
  finished:
-       shdr = (struct smb2_sync_hdr *)(rqst->rq_iov[0].iov_base);
        shdr->NextCommand = cpu_to_le32(len);
 }
 
@@ -2374,6 +2428,34 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
 }
 
 static int
+parse_reparse_posix(struct reparse_posix_data *symlink_buf,
+                     u32 plen, char **target_path,
+                     struct cifs_sb_info *cifs_sb)
+{
+       unsigned int len;
+
+       /* See MS-FSCC 2.1.2.6 for the 'NFS' style reparse tags */
+       len = le16_to_cpu(symlink_buf->ReparseDataLength);
+
+       if (le64_to_cpu(symlink_buf->InodeType) != NFS_SPECFILE_LNK) {
+               cifs_dbg(VFS, "%lld not a supported symlink type\n",
+                       le64_to_cpu(symlink_buf->InodeType));
+               return -EOPNOTSUPP;
+       }
+
+       *target_path = cifs_strndup_from_utf16(
+                               symlink_buf->PathBuffer,
+                               len, true, cifs_sb->local_nls);
+       if (!(*target_path))
+               return -ENOMEM;
+
+       convert_delimiter(*target_path, '/');
+       cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path);
+
+       return 0;
+}
+
+static int
 parse_reparse_symlink(struct reparse_symlink_data_buffer *symlink_buf,
                      u32 plen, char **target_path,
                      struct cifs_sb_info *cifs_sb)
@@ -2381,11 +2463,7 @@ parse_reparse_symlink(struct reparse_symlink_data_buffer *symlink_buf,
        unsigned int sub_len;
        unsigned int sub_offset;
 
-       /* We only handle Symbolic Link : MS-FSCC 2.1.2.4 */
-       if (le32_to_cpu(symlink_buf->ReparseTag) != IO_REPARSE_TAG_SYMLINK) {
-               cifs_dbg(VFS, "srv returned invalid symlink buffer\n");
-               return -EIO;
-       }
+       /* We handle Symbolic Link reparse tag here. See: MS-FSCC 2.1.2.4 */
 
        sub_offset = le16_to_cpu(symlink_buf->SubstituteNameOffset);
        sub_len = le16_to_cpu(symlink_buf->SubstituteNameLength);
@@ -2407,6 +2485,41 @@ parse_reparse_symlink(struct reparse_symlink_data_buffer *symlink_buf,
        return 0;
 }
 
+static int
+parse_reparse_point(struct reparse_data_buffer *buf,
+                   u32 plen, char **target_path,
+                   struct cifs_sb_info *cifs_sb)
+{
+       if (plen < sizeof(struct reparse_data_buffer)) {
+               cifs_dbg(VFS, "reparse buffer is too small. Must be "
+                        "at least 8 bytes but was %d\n", plen);
+               return -EIO;
+       }
+
+       if (plen < le16_to_cpu(buf->ReparseDataLength) +
+           sizeof(struct reparse_data_buffer)) {
+               cifs_dbg(VFS, "srv returned invalid reparse buf "
+                        "length: %d\n", plen);
+               return -EIO;
+       }
+
+       /* See MS-FSCC 2.1.2 */
+       switch (le32_to_cpu(buf->ReparseTag)) {
+       case IO_REPARSE_TAG_NFS:
+               return parse_reparse_posix(
+                       (struct reparse_posix_data *)buf,
+                       plen, target_path, cifs_sb);
+       case IO_REPARSE_TAG_SYMLINK:
+               return parse_reparse_symlink(
+                       (struct reparse_symlink_data_buffer *)buf,
+                       plen, target_path, cifs_sb);
+       default:
+               cifs_dbg(VFS, "srv returned unknown symlink buffer "
+                        "tag:0x%08x\n", le32_to_cpu(buf->ReparseTag));
+               return -EOPNOTSUPP;
+       }
+}
+
 #define SMB2_SYMLINK_STRUCT_SIZE \
        (sizeof(struct smb2_err_rsp) - 1 + sizeof(struct smb2_symlink_err_rsp))
 
@@ -2533,23 +2646,8 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
                        goto querty_exit;
                }
 
-               if (plen < 8) {
-                       cifs_dbg(VFS, "reparse buffer is too small. Must be "
-                                "at least 8 bytes but was %d\n", plen);
-                       rc = -EIO;
-                       goto querty_exit;
-               }
-
-               if (plen < le16_to_cpu(reparse_buf->ReparseDataLength) + 8) {
-                       cifs_dbg(VFS, "srv returned invalid reparse buf "
-                                "length: %d\n", plen);
-                       rc = -EIO;
-                       goto querty_exit;
-               }
-
-               rc = parse_reparse_symlink(
-                       (struct reparse_symlink_data_buffer *)reparse_buf,
-                       plen, target_path, cifs_sb);
+               rc = parse_reparse_point(reparse_buf, plen, target_path,
+                                        cifs_sb);
                goto querty_exit;
        }
 
@@ -2561,26 +2659,32 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
        err_buf = err_iov.iov_base;
        if (le32_to_cpu(err_buf->ByteCount) < sizeof(struct smb2_symlink_err_rsp) ||
            err_iov.iov_len < SMB2_SYMLINK_STRUCT_SIZE) {
-               rc = -ENOENT;
+               rc = -EINVAL;
+               goto querty_exit;
+       }
+
+       symlink = (struct smb2_symlink_err_rsp *)err_buf->ErrorData;
+       if (le32_to_cpu(symlink->SymLinkErrorTag) != SYMLINK_ERROR_TAG ||
+           le32_to_cpu(symlink->ReparseTag) != IO_REPARSE_TAG_SYMLINK) {
+               rc = -EINVAL;
                goto querty_exit;
        }
 
        /* open must fail on symlink - reset rc */
        rc = 0;
-       symlink = (struct smb2_symlink_err_rsp *)err_buf->ErrorData;
        sub_len = le16_to_cpu(symlink->SubstituteNameLength);
        sub_offset = le16_to_cpu(symlink->SubstituteNameOffset);
        print_len = le16_to_cpu(symlink->PrintNameLength);
        print_offset = le16_to_cpu(symlink->PrintNameOffset);
 
        if (err_iov.iov_len < SMB2_SYMLINK_STRUCT_SIZE + sub_offset + sub_len) {
-               rc = -ENOENT;
+               rc = -EINVAL;
                goto querty_exit;
        }
 
        if (err_iov.iov_len <
            SMB2_SYMLINK_STRUCT_SIZE + print_offset + print_len) {
-               rc = -ENOENT;
+               rc = -EINVAL;
                goto querty_exit;
        }
 
@@ -2606,7 +2710,6 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
        return rc;
 }
 
-#ifdef CONFIG_CIFS_ACL
 static struct cifs_ntsd *
 get_smb2_acl_by_fid(struct cifs_sb_info *cifs_sb,
                const struct cifs_fid *cifsfid, u32 *pacllen)
@@ -2691,7 +2794,6 @@ get_smb2_acl_by_path(struct cifs_sb_info *cifs_sb,
        return pntsd;
 }
 
-#ifdef CONFIG_CIFS_ACL
 static int
 set_smb2_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
                struct inode *inode, const char *path, int aclflag)
@@ -2749,7 +2851,6 @@ set_smb2_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
        free_xid(xid);
        return rc;
 }
-#endif /* CIFS_ACL */
 
 /* Retrieve an ACL from the server */
 static struct cifs_ntsd *
@@ -2769,7 +2870,6 @@ get_smb2_acl(struct cifs_sb_info *cifs_sb,
        cifsFileInfo_put(open_file);
        return pntsd;
 }
-#endif
 
 static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
                            loff_t offset, loff_t len, bool keep_size)
@@ -3367,7 +3467,7 @@ smb2_dir_needs_close(struct cifsFileInfo *cfile)
 
 static void
 fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_len,
-                  struct smb_rqst *old_rq)
+                  struct smb_rqst *old_rq, __le16 cipher_type)
 {
        struct smb2_sync_hdr *shdr =
                        (struct smb2_sync_hdr *)old_rq->rq_iov[0].iov_base;
@@ -3376,7 +3476,10 @@ fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_len,
        tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM;
        tr_hdr->OriginalMessageSize = cpu_to_le32(orig_len);
        tr_hdr->Flags = cpu_to_le16(0x01);
-       get_random_bytes(&tr_hdr->Nonce, SMB3_AES128CMM_NONCE);
+       if (cipher_type == SMB2_ENCRYPTION_AES128_GCM)
+               get_random_bytes(&tr_hdr->Nonce, SMB3_AES128GCM_NONCE);
+       else
+               get_random_bytes(&tr_hdr->Nonce, SMB3_AES128CCM_NONCE);
        memcpy(&tr_hdr->SessionId, &shdr->SessionId, 8);
 }
 
@@ -3534,8 +3637,13 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
                rc = -ENOMEM;
                goto free_sg;
        }
-       iv[0] = 3;
-       memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES128CMM_NONCE);
+
+       if (server->cipher_type == SMB2_ENCRYPTION_AES128_GCM)
+               memcpy(iv, (char *)tr_hdr->Nonce, SMB3_AES128GCM_NONCE);
+       else {
+               iv[0] = 3;
+               memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES128CCM_NONCE);
+       }
 
        aead_request_set_crypt(req, sg, sg, crypt_len, iv);
        aead_request_set_ad(req, assoc_data_len);
@@ -3635,7 +3743,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst,
        }
 
        /* fill the 1st iov with a transform header */
-       fill_transform_hdr(tr_hdr, orig_len, old_rq);
+       fill_transform_hdr(tr_hdr, orig_len, old_rq, server->cipher_type);
 
        rc = crypt_message(server, num_rqst, new_rq, 1);
        cifs_dbg(FYI, "Encrypt message returned %d\n", rc);
@@ -4284,11 +4392,9 @@ struct smb_version_operations smb20_operations = {
        .query_all_EAs = smb2_query_eas,
        .set_EA = smb2_set_ea,
 #endif /* CIFS_XATTR */
-#ifdef CONFIG_CIFS_ACL
        .get_acl = get_smb2_acl,
        .get_acl_by_fid = get_smb2_acl_by_fid,
        .set_acl = set_smb2_acl,
-#endif /* CIFS_ACL */
        .next_header = smb2_next_header,
        .ioctl_query_info = smb2_ioctl_query_info,
        .make_node = smb2_make_node,
@@ -4385,11 +4491,9 @@ struct smb_version_operations smb21_operations = {
        .query_all_EAs = smb2_query_eas,
        .set_EA = smb2_set_ea,
 #endif /* CIFS_XATTR */
-#ifdef CONFIG_CIFS_ACL
        .get_acl = get_smb2_acl,
        .get_acl_by_fid = get_smb2_acl_by_fid,
        .set_acl = set_smb2_acl,
-#endif /* CIFS_ACL */
        .next_header = smb2_next_header,
        .ioctl_query_info = smb2_ioctl_query_info,
        .make_node = smb2_make_node,
@@ -4495,11 +4599,9 @@ struct smb_version_operations smb30_operations = {
        .query_all_EAs = smb2_query_eas,
        .set_EA = smb2_set_ea,
 #endif /* CIFS_XATTR */
-#ifdef CONFIG_CIFS_ACL
        .get_acl = get_smb2_acl,
        .get_acl_by_fid = get_smb2_acl_by_fid,
        .set_acl = set_smb2_acl,
-#endif /* CIFS_ACL */
        .next_header = smb2_next_header,
        .ioctl_query_info = smb2_ioctl_query_info,
        .make_node = smb2_make_node,
@@ -4606,11 +4708,9 @@ struct smb_version_operations smb311_operations = {
        .query_all_EAs = smb2_query_eas,
        .set_EA = smb2_set_ea,
 #endif /* CIFS_XATTR */
-#ifdef CONFIG_CIFS_ACL
        .get_acl = get_smb2_acl,
        .get_acl_by_fid = get_smb2_acl_by_fid,
        .set_acl = set_smb2_acl,
-#endif /* CIFS_ACL */
        .next_header = smb2_next_header,
        .ioctl_query_info = smb2_ioctl_query_info,
        .make_node = smb2_make_node,
index 75311a8..c8cd7b6 100644 (file)
@@ -489,10 +489,25 @@ static void
 build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt)
 {
        pneg_ctxt->ContextType = SMB2_ENCRYPTION_CAPABILITIES;
-       pneg_ctxt->DataLength = cpu_to_le16(4); /* Cipher Count + le16 cipher */
-       pneg_ctxt->CipherCount = cpu_to_le16(1);
-/* pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES128_GCM;*/ /* not supported yet */
-       pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES128_CCM;
+       pneg_ctxt->DataLength = cpu_to_le16(6); /* Cipher Count + two ciphers */
+       pneg_ctxt->CipherCount = cpu_to_le16(2);
+       pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES128_GCM;
+       pneg_ctxt->Ciphers[1] = SMB2_ENCRYPTION_AES128_CCM;
+}
+
+static unsigned int
+build_netname_ctxt(struct smb2_netname_neg_context *pneg_ctxt, char *hostname)
+{
+       struct nls_table *cp = load_nls_default();
+
+       pneg_ctxt->ContextType = SMB2_NETNAME_NEGOTIATE_CONTEXT_ID;
+
+       /* copy up to max of first 100 bytes of server name to NetName field */
+       pneg_ctxt->DataLength = cpu_to_le16(2 +
+               (2 * cifs_strtoUTF16(pneg_ctxt->NetName, hostname, 100, cp)));
+       /* context size is DataLength + minimal smb2_neg_context */
+       return DIV_ROUND_UP(le16_to_cpu(pneg_ctxt->DataLength) +
+                       sizeof(struct smb2_neg_context), 8) * 8;
 }
 
 static void
@@ -521,7 +536,7 @@ build_posix_ctxt(struct smb2_posix_neg_context *pneg_ctxt)
 
 static void
 assemble_neg_contexts(struct smb2_negotiate_req *req,
-                     unsigned int *total_len)
+                     struct TCP_Server_Info *server, unsigned int *total_len)
 {
        char *pneg_ctxt = (char *)req;
        unsigned int ctxt_len;
@@ -551,17 +566,25 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
        *total_len += ctxt_len;
        pneg_ctxt += ctxt_len;
 
-       build_compression_ctxt((struct smb2_compression_capabilities_context *)
+       if (server->compress_algorithm) {
+               build_compression_ctxt((struct smb2_compression_capabilities_context *)
                                pneg_ctxt);
-       ctxt_len = DIV_ROUND_UP(
-               sizeof(struct smb2_compression_capabilities_context), 8) * 8;
+               ctxt_len = DIV_ROUND_UP(
+                       sizeof(struct smb2_compression_capabilities_context),
+                               8) * 8;
+               *total_len += ctxt_len;
+               pneg_ctxt += ctxt_len;
+               req->NegotiateContextCount = cpu_to_le16(5);
+       } else
+               req->NegotiateContextCount = cpu_to_le16(4);
+
+       ctxt_len = build_netname_ctxt((struct smb2_netname_neg_context *)pneg_ctxt,
+                                       server->hostname);
        *total_len += ctxt_len;
        pneg_ctxt += ctxt_len;
 
        build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt);
        *total_len += sizeof(struct smb2_posix_neg_context);
-
-       req->NegotiateContextCount = cpu_to_le16(4);
 }
 
 static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt)
@@ -829,7 +852,7 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
                if ((ses->server->vals->protocol_id == SMB311_PROT_ID) ||
                    (strcmp(ses->server->vals->version_string,
                     SMBDEFAULT_VERSION_STRING) == 0))
-                       assemble_neg_contexts(req, &total_len);
+                       assemble_neg_contexts(req, server, &total_len);
        }
        iov[0].iov_base = (char *)req;
        iov[0].iov_len = total_len;
@@ -1850,10 +1873,21 @@ create_reconnect_durable_buf(struct cifs_fid *fid)
        return buf;
 }
 
-__u8
-smb2_parse_lease_state(struct TCP_Server_Info *server,
+static void
+parse_query_id_ctxt(struct create_context *cc, struct smb2_file_all_info *buf)
+{
+       struct create_on_disk_id *pdisk_id = (struct create_on_disk_id *)cc;
+
+       cifs_dbg(FYI, "parse query id context 0x%llx 0x%llx\n",
+               pdisk_id->DiskFileId, pdisk_id->VolumeId);
+       buf->IndexNumber = pdisk_id->DiskFileId;
+}
+
+void
+smb2_parse_contexts(struct TCP_Server_Info *server,
                       struct smb2_create_rsp *rsp,
-                      unsigned int *epoch, char *lease_key)
+                      unsigned int *epoch, char *lease_key, __u8 *oplock,
+                      struct smb2_file_all_info *buf)
 {
        char *data_offset;
        struct create_context *cc;
@@ -1861,15 +1895,24 @@ smb2_parse_lease_state(struct TCP_Server_Info *server,
        unsigned int remaining;
        char *name;
 
+       *oplock = 0;
        data_offset = (char *)rsp + le32_to_cpu(rsp->CreateContextsOffset);
        remaining = le32_to_cpu(rsp->CreateContextsLength);
        cc = (struct create_context *)data_offset;
+
+       /* Initialize inode number to 0 in case no valid data in qfid context */
+       if (buf)
+               buf->IndexNumber = 0;
+
        while (remaining >= sizeof(struct create_context)) {
                name = le16_to_cpu(cc->NameOffset) + (char *)cc;
                if (le16_to_cpu(cc->NameLength) == 4 &&
-                   strncmp(name, "RqLs", 4) == 0)
-                       return server->ops->parse_lease_buf(cc, epoch,
-                                                           lease_key);
+                   strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4) == 0)
+                       *oplock = server->ops->parse_lease_buf(cc, epoch,
+                                                          lease_key);
+               else if (buf && (le16_to_cpu(cc->NameLength) == 4) &&
+                   strncmp(name, SMB2_CREATE_QUERY_ON_DISK_ID, 4) == 0)
+                       parse_query_id_ctxt(cc, buf);
 
                next = le32_to_cpu(cc->Next);
                if (!next)
@@ -1878,7 +1921,10 @@ smb2_parse_lease_state(struct TCP_Server_Info *server,
                cc = (struct create_context *)((char *)cc + next);
        }
 
-       return 0;
+       if (rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE)
+               *oplock = rsp->OplockLevel;
+
+       return;
 }
 
 static int
@@ -2095,6 +2141,48 @@ add_twarp_context(struct kvec *iov, unsigned int *num_iovec, __u64 timewarp)
        return 0;
 }
 
+static struct crt_query_id_ctxt *
+create_query_id_buf(void)
+{
+       struct crt_query_id_ctxt *buf;
+
+       buf = kzalloc(sizeof(struct crt_query_id_ctxt), GFP_KERNEL);
+       if (!buf)
+               return NULL;
+
+       buf->ccontext.DataOffset = cpu_to_le16(0);
+       buf->ccontext.DataLength = cpu_to_le32(0);
+       buf->ccontext.NameOffset = cpu_to_le16(offsetof
+                               (struct crt_query_id_ctxt, Name));
+       buf->ccontext.NameLength = cpu_to_le16(4);
+       /* SMB2_CREATE_QUERY_ON_DISK_ID is "QFid" */
+       buf->Name[0] = 'Q';
+       buf->Name[1] = 'F';
+       buf->Name[2] = 'i';
+       buf->Name[3] = 'd';
+       return buf;
+}
+
+/* See MS-SMB2 2.2.13.2.9 */
+static int
+add_query_id_context(struct kvec *iov, unsigned int *num_iovec)
+{
+       struct smb2_create_req *req = iov[0].iov_base;
+       unsigned int num = *num_iovec;
+
+       iov[num].iov_base = create_query_id_buf();
+       if (iov[num].iov_base == NULL)
+               return -ENOMEM;
+       iov[num].iov_len = sizeof(struct crt_query_id_ctxt);
+       if (!req->CreateContextsOffset)
+               req->CreateContextsOffset = cpu_to_le32(
+                               sizeof(struct smb2_create_req) +
+                               iov[num - 1].iov_len);
+       le32_add_cpu(&req->CreateContextsLength, sizeof(struct crt_query_id_ctxt));
+       *num_iovec = num + 1;
+       return 0;
+}
+
 static int
 alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len,
                            const char *treename, const __le16 *path)
@@ -2423,6 +2511,12 @@ SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, __u8 *oplock,
                        return rc;
        }
 
+       if (n_iov > 2) {
+               struct create_context *ccontext =
+                       (struct create_context *)iov[n_iov-1].iov_base;
+               ccontext->Next = cpu_to_le32(iov[n_iov-1].iov_len);
+       }
+       add_query_id_context(iov, &n_iov);
 
        rqst->rq_nvec = n_iov;
        return 0;
@@ -2517,12 +2611,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
                buf->DeletePending = 0;
        }
 
-       if (rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE)
-               *oplock = smb2_parse_lease_state(server, rsp,
-                                                &oparms->fid->epoch,
-                                                oparms->fid->lease_key);
-       else
-               *oplock = rsp->OplockLevel;
+
+       smb2_parse_contexts(server, rsp, &oparms->fid->epoch,
+                           oparms->fid->lease_key, oplock, buf);
 creat_exit:
        SMB2_open_free(&rqst);
        free_rsp_buf(resp_buftype, rsp);
@@ -2550,12 +2641,11 @@ SMB2_ioctl_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
                 * indatalen is usually small at a couple of bytes max, so
                 * just allocate through generic pool
                 */
-               in_data_buf = kmalloc(indatalen, GFP_NOFS);
+               in_data_buf = kmemdup(in_data, indatalen, GFP_NOFS);
                if (!in_data_buf) {
                        cifs_small_buf_release(req);
                        return -ENOMEM;
                }
-               memcpy(in_data_buf, in_data, indatalen);
        }
 
        req->CtlCode = cpu_to_le32(opcode);
index 858353d..747de93 100644 (file)
@@ -123,7 +123,7 @@ struct smb2_sync_pdu {
        __le16 StructureSize2; /* size of wct area (varies, request specific) */
 } __packed;
 
-#define SMB3_AES128CMM_NONCE 11
+#define SMB3_AES128CCM_NONCE 11
 #define SMB3_AES128GCM_NONCE 12
 
 struct smb2_transform_hdr {
@@ -166,6 +166,8 @@ struct smb2_err_rsp {
        __u8   ErrorData[1];  /* variable length */
 } __packed;
 
+#define SYMLINK_ERROR_TAG 0x4c4d5953
+
 struct smb2_symlink_err_rsp {
        __le32 SymLinkLength;
        __le32 SymLinkErrorTag;
@@ -227,6 +229,7 @@ struct smb2_negotiate_req {
 } __packed;
 
 /* Dialects */
+#define SMB10_PROT_ID 0x0000 /* local only, not sent on wire w/CIFS negprot */
 #define SMB20_PROT_ID 0x0202
 #define SMB21_PROT_ID 0x0210
 #define SMB30_PROT_ID 0x0300
@@ -293,7 +296,7 @@ struct smb2_encryption_neg_context {
        __le16  DataLength;
        __le32  Reserved;
        __le16  CipherCount; /* AES-128-GCM and AES-128-CCM */
-       __le16  Ciphers[1]; /* Ciphers[0] since only one used now */
+       __le16  Ciphers[2];
 } __packed;
 
 /* See MS-SMB2 2.2.3.1.3 */
@@ -316,6 +319,12 @@ struct smb2_compression_capabilities_context {
  * For smb2_netname_negotiate_context_id See MS-SMB2 2.2.3.1.4.
  * Its struct simply contains NetName, an array of Unicode characters
  */
+struct smb2_netname_neg_context {
+       __le16  ContextType; /* 0x100 */
+       __le16  DataLength;
+       __le32  Reserved;
+       __le16  NetName[0]; /* hostname of target converted to UCS-2 */
+} __packed;
 
 #define POSIX_CTXT_DATA_LEN    16
 struct smb2_posix_neg_context {
@@ -640,6 +649,7 @@ struct smb2_tree_disconnect_rsp {
 #define SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2  "DH2Q"
 #define SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2        "DH2C"
 #define SMB2_CREATE_APP_INSTANCE_ID    0x45BCA66AEFA7F74A9008FA462E144D74
+#define SMB2_CREATE_APP_INSTANCE_VERSION 0xB982D0B73B56074FA07B524A8116A010
 #define SVHDX_OPEN_DEVICE_CONTEX       0x9CCBCF9E04C1E643980E158DA1F6EC83
 #define SMB2_CREATE_TAG_POSIX          0x93AD25509CB411E7B42383DE968BCD7C
 
@@ -654,9 +664,10 @@ struct smb2_tree_disconnect_rsp {
  * [3] : durable context
  * [4] : posix context
  * [5] : time warp context
- * [6] : compound padding
+ * [6] : query id context
+ * [7] : compound padding
  */
-#define SMB2_CREATE_IOV_SIZE 7
+#define SMB2_CREATE_IOV_SIZE 8
 
 struct smb2_create_req {
        struct smb2_sync_hdr sync_hdr;
@@ -680,10 +691,10 @@ struct smb2_create_req {
 
 /*
  * Maximum size of a SMB2_CREATE response is 64 (smb2 header) +
- * 88 (fixed part of create response) + 520 (path) + 150 (contexts) +
+ * 88 (fixed part of create response) + 520 (path) + 208 (contexts) +
  * 2 bytes of padding.
  */
-#define MAX_SMB2_CREATE_RESPONSE_SIZE 824
+#define MAX_SMB2_CREATE_RESPONSE_SIZE 880
 
 struct smb2_create_rsp {
        struct smb2_sync_hdr sync_hdr;
@@ -806,6 +817,15 @@ struct durable_reconnect_context_v2 {
        __le32 Flags; /* see above DHANDLE_FLAG_PERSISTENT */
 } __packed;
 
+/* See MS-SMB2 2.2.14.2.9 */
+struct create_on_disk_id {
+       struct create_context ccontext;
+       __u8   Name[8];
+       __le64 DiskFileId;
+       __le64 VolumeId;
+       __u32  Reserved[4];
+} __packed;
+
 /* See MS-SMB2 2.2.14.2.12 */
 struct durable_reconnect_context_v2_rsp {
        __le32 Timeout;
@@ -826,6 +846,12 @@ struct crt_twarp_ctxt {
 
 } __packed;
 
+/* See MS-SMB2 2.2.13.2.9 */
+struct crt_query_id_ctxt {
+       struct create_context ccontext;
+       __u8    Name[8];
+} __packed;
+
 #define COPY_CHUNK_RES_KEY_SIZE        24
 struct resume_key_req {
        char ResumeKey[COPY_CHUNK_RES_KEY_SIZE];
index 52df125..07ca724 100644 (file)
@@ -228,9 +228,10 @@ extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *);
 
 extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *,
                                        enum securityEnum);
-extern __u8 smb2_parse_lease_state(struct TCP_Server_Info *server,
-                                  struct smb2_create_rsp *rsp,
-                                  unsigned int *epoch, char *lease_key);
+extern void smb2_parse_contexts(struct TCP_Server_Info *server,
+                               struct smb2_create_rsp *rsp,
+                               unsigned int *epoch, char *lease_key,
+                               __u8 *oplock, struct smb2_file_all_info *buf);
 extern int smb3_encryption_required(const struct cifs_tcon *tcon);
 extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
                             struct kvec *iov, unsigned int min_buf_size);
index d118157..1ccbcf9 100644 (file)
@@ -734,7 +734,10 @@ smb3_crypto_aead_allocate(struct TCP_Server_Info *server)
        struct crypto_aead *tfm;
 
        if (!server->secmech.ccmaesencrypt) {
-               tfm = crypto_alloc_aead("ccm(aes)", 0, 0);
+               if (server->cipher_type == SMB2_ENCRYPTION_AES128_GCM)
+                       tfm = crypto_alloc_aead("gcm(aes)", 0, 0);
+               else
+                       tfm = crypto_alloc_aead("ccm(aes)", 0, 0);
                if (IS_ERR(tfm)) {
                        cifs_dbg(VFS, "%s: Failed to alloc encrypt aead\n",
                                 __func__);
@@ -744,7 +747,10 @@ smb3_crypto_aead_allocate(struct TCP_Server_Info *server)
        }
 
        if (!server->secmech.ccmaesdecrypt) {
-               tfm = crypto_alloc_aead("ccm(aes)", 0, 0);
+               if (server->cipher_type == SMB2_ENCRYPTION_AES128_GCM)
+                       tfm = crypto_alloc_aead("gcm(aes)", 0, 0);
+               else
+                       tfm = crypto_alloc_aead("ccm(aes)", 0, 0);
                if (IS_ERR(tfm)) {
                        crypto_free_aead(server->secmech.ccmaesencrypt);
                        server->secmech.ccmaesencrypt = NULL;
index 60661b3..5d6d44b 100644 (file)
@@ -979,6 +979,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
        };
        unsigned int instance;
        char *buf;
+       struct TCP_Server_Info *server;
 
        optype = flags & CIFS_OP_MASK;
 
@@ -990,7 +991,8 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
                return -EIO;
        }
 
-       if (ses->server->tcpStatus == CifsExiting)
+       server = ses->server;
+       if (server->tcpStatus == CifsExiting)
                return -ENOENT;
 
        /*
@@ -1001,7 +1003,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
         * other requests.
         * This can be handled by the eventual session reconnect.
         */
-       rc = wait_for_compound_request(ses->server, num_rqst, flags,
+       rc = wait_for_compound_request(server, num_rqst, flags,
                                       &instance);
        if (rc)
                return rc;
@@ -1017,7 +1019,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
         * of smb data.
         */
 
-       mutex_lock(&ses->server->srv_mutex);
+       mutex_lock(&server->srv_mutex);
 
        /*
         * All the parts of the compound chain belong obtained credits from the
@@ -1026,24 +1028,24 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
         * we obtained credits and return -EAGAIN in such cases to let callers
         * handle it.
         */
-       if (instance != ses->server->reconnect_instance) {
-               mutex_unlock(&ses->server->srv_mutex);
+       if (instance != server->reconnect_instance) {
+               mutex_unlock(&server->srv_mutex);
                for (j = 0; j < num_rqst; j++)
-                       add_credits(ses->server, &credits[j], optype);
+                       add_credits(server, &credits[j], optype);
                return -EAGAIN;
        }
 
        for (i = 0; i < num_rqst; i++) {
-               midQ[i] = ses->server->ops->setup_request(ses, &rqst[i]);
+               midQ[i] = server->ops->setup_request(ses, &rqst[i]);
                if (IS_ERR(midQ[i])) {
-                       revert_current_mid(ses->server, i);
+                       revert_current_mid(server, i);
                        for (j = 0; j < i; j++)
                                cifs_delete_mid(midQ[j]);
-                       mutex_unlock(&ses->server->srv_mutex);
+                       mutex_unlock(&server->srv_mutex);
 
                        /* Update # of requests on wire to server */
                        for (j = 0; j < num_rqst; j++)
-                               add_credits(ses->server, &credits[j], optype);
+                               add_credits(server, &credits[j], optype);
                        return PTR_ERR(midQ[i]);
                }
 
@@ -1059,19 +1061,19 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
                else
                        midQ[i]->callback = cifs_compound_last_callback;
        }
-       cifs_in_send_inc(ses->server);
-       rc = smb_send_rqst(ses->server, num_rqst, rqst, flags);
-       cifs_in_send_dec(ses->server);
+       cifs_in_send_inc(server);
+       rc = smb_send_rqst(server, num_rqst, rqst, flags);
+       cifs_in_send_dec(server);
 
        for (i = 0; i < num_rqst; i++)
                cifs_save_when_sent(midQ[i]);
 
        if (rc < 0) {
-               revert_current_mid(ses->server, num_rqst);
-               ses->server->sequence_number -= 2;
+               revert_current_mid(server, num_rqst);
+               server->sequence_number -= 2;
        }
 
-       mutex_unlock(&ses->server->srv_mutex);
+       mutex_unlock(&server->srv_mutex);
 
        /*
         * If sending failed for some reason or it is an oplock break that we
@@ -1079,7 +1081,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
         */
        if (rc < 0 || (flags & CIFS_NO_SRV_RSP)) {
                for (i = 0; i < num_rqst; i++)
-                       add_credits(ses->server, &credits[i], optype);
+                       add_credits(server, &credits[i], optype);
                goto out;
        }
 
@@ -1099,7 +1101,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
                                           rqst[0].rq_nvec);
 
        for (i = 0; i < num_rqst; i++) {
-               rc = wait_for_response(ses->server, midQ[i]);
+               rc = wait_for_response(server, midQ[i]);
                if (rc != 0)
                        break;
        }
@@ -1107,7 +1109,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
                for (; i < num_rqst; i++) {
                        cifs_dbg(VFS, "Cancelling wait for mid %llu cmd: %d\n",
                                 midQ[i]->mid, le16_to_cpu(midQ[i]->command));
-                       send_cancel(ses->server, &rqst[i], midQ[i]);
+                       send_cancel(server, &rqst[i], midQ[i]);
                        spin_lock(&GlobalMid_Lock);
                        if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED) {
                                midQ[i]->mid_flags |= MID_WAIT_CANCELLED;
@@ -1123,7 +1125,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
                if (rc < 0)
                        goto out;
 
-               rc = cifs_sync_mid_result(midQ[i], ses->server);
+               rc = cifs_sync_mid_result(midQ[i], server);
                if (rc != 0) {
                        /* mark this mid as cancelled to not free it below */
                        cancelled_mid[i] = true;
@@ -1140,14 +1142,14 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
                buf = (char *)midQ[i]->resp_buf;
                resp_iov[i].iov_base = buf;
                resp_iov[i].iov_len = midQ[i]->resp_buf_size +
-                       ses->server->vals->header_preamble_size;
+                       server->vals->header_preamble_size;
 
                if (midQ[i]->large_buf)
                        resp_buf_type[i] = CIFS_LARGE_BUFFER;
                else
                        resp_buf_type[i] = CIFS_SMALL_BUFFER;
 
-               rc = ses->server->ops->check_receive(midQ[i], ses->server,
+               rc = server->ops->check_receive(midQ[i], server,
                                                     flags & CIFS_LOG_ERROR);
 
                /* mark it so buf will not be freed by cifs_delete_mid */
index 50ddb79..9076150 100644 (file)
@@ -96,7 +96,6 @@ static int cifs_xattr_set(const struct xattr_handler *handler,
                break;
 
        case XATTR_CIFS_ACL: {
-#ifdef CONFIG_CIFS_ACL
                struct cifs_ntsd *pacl;
 
                if (!value)
@@ -117,7 +116,6 @@ static int cifs_xattr_set(const struct xattr_handler *handler,
                                CIFS_I(inode)->time = 0;
                        kfree(pacl);
                }
-#endif /* CONFIG_CIFS_ACL */
                break;
        }
 
@@ -247,7 +245,6 @@ static int cifs_xattr_get(const struct xattr_handler *handler,
                break;
 
        case XATTR_CIFS_ACL: {
-#ifdef CONFIG_CIFS_ACL
                u32 acllen;
                struct cifs_ntsd *pacl;
 
@@ -270,7 +267,6 @@ static int cifs_xattr_get(const struct xattr_handler *handler,
                        rc = acllen;
                        kfree(pacl);
                }
-#endif  /* CONFIG_CIFS_ACL */
                break;
        }
 
index 1ce6681..78befb8 100644 (file)
@@ -6,7 +6,8 @@
 obj-$(CONFIG_CODA_FS) += coda.o
 
 coda-objs := psdev.o cache.o cnode.o inode.o dir.o file.o upcall.o \
-            coda_linux.o symlink.o pioctl.o sysctl.o 
+            coda_linux.o symlink.o pioctl.o
+coda-$(CONFIG_SYSCTL) += sysctl.o
 
 # If you want debugging output, please uncomment the following line.
 
index 201fc08..3b8c451 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/spinlock.h>
 
 #include <linux/coda.h>
-#include <linux/coda_psdev.h>
+#include "coda_psdev.h"
 #include "coda_linux.h"
 #include "coda_cache.h"
 
index 845b5a6..06855f6 100644 (file)
@@ -8,8 +8,8 @@
 #include <linux/time.h>
 
 #include <linux/coda.h>
-#include <linux/coda_psdev.h>
 #include <linux/pagemap.h>
+#include "coda_psdev.h"
 #include "coda_linux.h"
 
 static inline int coda_fideq(struct CodaFid *fid1, struct CodaFid *fid2)
@@ -137,11 +137,6 @@ struct inode *coda_fid_to_inode(struct CodaFid *fid, struct super_block *sb)
        struct inode *inode;
        unsigned long hash = coda_f2i(fid);
 
-       if ( !sb ) {
-               pr_warn("%s: no sb!\n", __func__);
-               return NULL;
-       }
-
        inode = ilookup5(sb, hash, coda_test_inode, fid);
        if ( !inode )
                return NULL;
@@ -153,6 +148,16 @@ struct inode *coda_fid_to_inode(struct CodaFid *fid, struct super_block *sb)
        return inode;
 }
 
+struct coda_file_info *coda_ftoc(struct file *file)
+{
+       struct coda_file_info *cfi = file->private_data;
+
+       BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
+
+       return cfi;
+
+}
+
 /* the CONTROL inode is made without asking attributes from Venus */
 struct inode *coda_cnode_makectl(struct super_block *sb)
 {
index d702ba1..1763ff9 100644 (file)
@@ -40,10 +40,9 @@ struct coda_file_info {
        int                cfi_magic;     /* magic number */
        struct file       *cfi_container; /* container file for this cnode */
        unsigned int       cfi_mapcount;  /* nr of times this file is mapped */
+       bool               cfi_access_intent; /* is access intent supported */
 };
 
-#define CODA_FTOC(file) ((struct coda_file_info *)((file)->private_data))
-
 /* flags */
 #define C_VATTR       0x1   /* Validity of vattr in inode */
 #define C_FLUSH       0x2   /* used after a flush */
@@ -54,6 +53,7 @@ struct inode *coda_cnode_make(struct CodaFid *, struct super_block *);
 struct inode *coda_iget(struct super_block *sb, struct CodaFid *fid, struct coda_vattr *attr);
 struct inode *coda_cnode_makectl(struct super_block *sb);
 struct inode *coda_fid_to_inode(struct CodaFid *fid, struct super_block *sb);
+struct coda_file_info *coda_ftoc(struct file *file);
 void coda_replace_fid(struct inode *, struct CodaFid *, struct CodaFid *);
 
 #endif
index bb0b3e0..f82b59c 100644 (file)
@@ -13,9 +13,19 @@ extern int coda_fake_statfs;
 void coda_destroy_inodecache(void);
 int __init coda_init_inodecache(void);
 int coda_fsync(struct file *coda_file, loff_t start, loff_t end, int datasync);
+
+#ifdef CONFIG_SYSCTL
 void coda_sysctl_init(void);
 void coda_sysctl_clean(void);
+#else
+static inline void coda_sysctl_init(void)
+{
+}
 
+static inline void coda_sysctl_clean(void)
+{
+}
+#endif
 #endif  /*  _CODA_INT_  */
 
 
index f3d543d..2e1a5a1 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/string.h>
 
 #include <linux/coda.h>
-#include <linux/coda_psdev.h>
+#include "coda_psdev.h"
 #include "coda_linux.h"
 
 /* initialize the debugging variables */
@@ -66,6 +66,25 @@ unsigned short coda_flags_to_cflags(unsigned short flags)
        return coda_flags;
 }
 
+static struct timespec64 coda_to_timespec64(struct coda_timespec ts)
+{
+       struct timespec64 ts64 = {
+               .tv_sec = ts.tv_sec,
+               .tv_nsec = ts.tv_nsec,
+       };
+
+       return ts64;
+}
+
+static struct coda_timespec timespec64_to_coda(struct timespec64 ts64)
+{
+       struct coda_timespec ts = {
+               .tv_sec = ts64.tv_sec,
+               .tv_nsec = ts64.tv_nsec,
+       };
+
+       return ts;
+}
 
 /* utility functions below */
 void coda_vattr_to_iattr(struct inode *inode, struct coda_vattr *attr)
@@ -105,11 +124,11 @@ void coda_vattr_to_iattr(struct inode *inode, struct coda_vattr *attr)
        if (attr->va_size != -1)
                inode->i_blocks = (attr->va_size + 511) >> 9;
        if (attr->va_atime.tv_sec != -1) 
-               inode->i_atime = timespec_to_timespec64(attr->va_atime);
+               inode->i_atime = coda_to_timespec64(attr->va_atime);
        if (attr->va_mtime.tv_sec != -1)
-               inode->i_mtime = timespec_to_timespec64(attr->va_mtime);
+               inode->i_mtime = coda_to_timespec64(attr->va_mtime);
         if (attr->va_ctime.tv_sec != -1)
-               inode->i_ctime = timespec_to_timespec64(attr->va_ctime);
+               inode->i_ctime = coda_to_timespec64(attr->va_ctime);
 }
 
 
@@ -130,12 +149,12 @@ void coda_iattr_to_vattr(struct iattr *iattr, struct coda_vattr *vattr)
         vattr->va_uid = (vuid_t) -1; 
         vattr->va_gid = (vgid_t) -1;
         vattr->va_size = (off_t) -1;
-       vattr->va_atime.tv_sec = (time_t) -1;
-       vattr->va_atime.tv_nsec =  (time_t) -1;
-        vattr->va_mtime.tv_sec = (time_t) -1;
-        vattr->va_mtime.tv_nsec = (time_t) -1;
-       vattr->va_ctime.tv_sec = (time_t) -1;
-       vattr->va_ctime.tv_nsec = (time_t) -1;
+       vattr->va_atime.tv_sec = (int64_t) -1;
+       vattr->va_atime.tv_nsec = (long) -1;
+       vattr->va_mtime.tv_sec = (int64_t) -1;
+       vattr->va_mtime.tv_nsec = (long) -1;
+       vattr->va_ctime.tv_sec = (int64_t) -1;
+       vattr->va_ctime.tv_nsec = (long) -1;
         vattr->va_type = C_VNON;
        vattr->va_fileid = -1;
        vattr->va_gen = -1;
@@ -175,13 +194,13 @@ void coda_iattr_to_vattr(struct iattr *iattr, struct coda_vattr *vattr)
                 vattr->va_size = iattr->ia_size;
        }
         if ( valid & ATTR_ATIME ) {
-               vattr->va_atime = timespec64_to_timespec(iattr->ia_atime);
+               vattr->va_atime = timespec64_to_coda(iattr->ia_atime);
        }
         if ( valid & ATTR_MTIME ) {
-               vattr->va_mtime = timespec64_to_timespec(iattr->ia_mtime);
+               vattr->va_mtime = timespec64_to_coda(iattr->ia_mtime);
        }
         if ( valid & ATTR_CTIME ) {
-               vattr->va_ctime = timespec64_to_timespec(iattr->ia_ctime);
+               vattr->va_ctime = timespec64_to_coda(iattr->ia_ctime);
        }
 }
 
index 126155c..d5ebd36 100644 (file)
@@ -59,22 +59,6 @@ void coda_vattr_to_iattr(struct inode *, struct coda_vattr *);
 void coda_iattr_to_vattr(struct iattr *, struct coda_vattr *);
 unsigned short coda_flags_to_cflags(unsigned short);
 
-/* sysctl.h */
-void coda_sysctl_init(void);
-void coda_sysctl_clean(void);
-
-#define CODA_ALLOC(ptr, cast, size) do { \
-    if (size < PAGE_SIZE) \
-        ptr = kzalloc((unsigned long) size, GFP_KERNEL); \
-    else \
-        ptr = (cast)vzalloc((unsigned long) size); \
-    if (!ptr) \
-       pr_warn("kernel malloc returns 0 at %s:%d\n", __FILE__, __LINE__); \
-} while (0)
-
-
-#define CODA_FREE(ptr, size) kvfree((ptr))
-
 /* inode to cnode access functions */
 
 static inline struct coda_inode_info *ITOC(struct inode *inode)
diff --git a/fs/coda/coda_psdev.h b/fs/coda/coda_psdev.h
new file mode 100644 (file)
index 0000000..52da08c
--- /dev/null
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __CODA_PSDEV_H
+#define __CODA_PSDEV_H
+
+#include <linux/backing-dev.h>
+#include <linux/magic.h>
+#include <linux/mutex.h>
+
+#define CODA_PSDEV_MAJOR 67
+#define MAX_CODADEVS  5           /* how many do we allow */
+
+struct kstatfs;
+
+/* messages between coda filesystem in kernel and Venus */
+struct upc_req {
+       struct list_head        uc_chain;
+       caddr_t                 uc_data;
+       u_short                 uc_flags;
+       u_short                 uc_inSize;  /* Size is at most 5000 bytes */
+       u_short                 uc_outSize;
+       u_short                 uc_opcode;  /* copied from data to save lookup */
+       int                     uc_unique;
+       wait_queue_head_t       uc_sleep;   /* process' wait queue */
+};
+
+#define CODA_REQ_ASYNC  0x1
+#define CODA_REQ_READ   0x2
+#define CODA_REQ_WRITE  0x4
+#define CODA_REQ_ABORT  0x8
+
+/* communication pending/processing queues */
+struct venus_comm {
+       u_long              vc_seq;
+       wait_queue_head_t   vc_waitq; /* Venus wait queue */
+       struct list_head    vc_pending;
+       struct list_head    vc_processing;
+       int                 vc_inuse;
+       struct super_block *vc_sb;
+       struct mutex        vc_mutex;
+};
+
+static inline struct venus_comm *coda_vcp(struct super_block *sb)
+{
+       return (struct venus_comm *)((sb)->s_fs_info);
+}
+
+/* upcalls */
+int venus_rootfid(struct super_block *sb, struct CodaFid *fidp);
+int venus_getattr(struct super_block *sb, struct CodaFid *fid,
+                 struct coda_vattr *attr);
+int venus_setattr(struct super_block *, struct CodaFid *, struct coda_vattr *);
+int venus_lookup(struct super_block *sb, struct CodaFid *fid,
+                const char *name, int length, int *type,
+                struct CodaFid *resfid);
+int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
+               kuid_t uid);
+int venus_open(struct super_block *sb, struct CodaFid *fid, int flags,
+              struct file **f);
+int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid,
+               const char *name, int length,
+               struct CodaFid *newfid, struct coda_vattr *attrs);
+int venus_create(struct super_block *sb, struct CodaFid *dirfid,
+                const char *name, int length, int excl, int mode,
+                struct CodaFid *newfid, struct coda_vattr *attrs);
+int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid,
+               const char *name, int length);
+int venus_remove(struct super_block *sb, struct CodaFid *dirfid,
+                const char *name, int length);
+int venus_readlink(struct super_block *sb, struct CodaFid *fid,
+                  char *buffer, int *length);
+int venus_rename(struct super_block *sb, struct CodaFid *new_fid,
+                struct CodaFid *old_fid, size_t old_length,
+                size_t new_length, const char *old_name,
+                const char *new_name);
+int venus_link(struct super_block *sb, struct CodaFid *fid,
+                 struct CodaFid *dirfid, const char *name, int len );
+int venus_symlink(struct super_block *sb, struct CodaFid *fid,
+                 const char *name, int len, const char *symname, int symlen);
+int venus_access(struct super_block *sb, struct CodaFid *fid, int mask);
+int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
+                unsigned int cmd, struct PioctlData *data);
+int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out,
+                 size_t nbytes);
+int venus_fsync(struct super_block *sb, struct CodaFid *fid);
+int venus_statfs(struct dentry *dentry, struct kstatfs *sfs);
+int venus_access_intent(struct super_block *sb, struct CodaFid *fid,
+                       bool *access_intent_supported,
+                       size_t count, loff_t ppos, int type);
+
+/*
+ * Statistics
+ */
+
+extern struct venus_comm coda_comms[];
+#endif
index 00876dd..ca40c25 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/uaccess.h>
 
 #include <linux/coda.h>
-#include <linux/coda_psdev.h>
+#include "coda_psdev.h"
 #include "coda_linux.h"
 #include "coda_cache.h"
 
@@ -47,8 +47,8 @@ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, unsig
        int type = 0;
 
        if (length > CODA_MAXNAMLEN) {
-               pr_err("name too long: lookup, %s (%*s)\n",
-                      coda_i2s(dir), (int)length, name);
+               pr_err("name too long: lookup, %s %zu\n",
+                      coda_i2s(dir), length);
                return ERR_PTR(-ENAMETOOLONG);
        }
 
@@ -356,8 +356,7 @@ static int coda_venus_readdir(struct file *coda_file, struct dir_context *ctx)
        ino_t ino;
        int ret;
 
-       cfi = CODA_FTOC(coda_file);
-       BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
+       cfi = coda_ftoc(coda_file);
        host_file = cfi->cfi_container;
 
        cii = ITOC(file_inode(coda_file));
@@ -426,8 +425,7 @@ static int coda_readdir(struct file *coda_file, struct dir_context *ctx)
        struct file *host_file;
        int ret;
 
-       cfi = CODA_FTOC(coda_file);
-       BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
+       cfi = coda_ftoc(coda_file);
        host_file = cfi->cfi_container;
 
        if (host_file->f_op->iterate || host_file->f_op->iterate_shared) {
index 1cbc1f2..128d63d 100644 (file)
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
+#include <linux/uio.h>
 
 #include <linux/coda.h>
-#include <linux/coda_psdev.h>
-
+#include "coda_psdev.h"
 #include "coda_linux.h"
 #include "coda_int.h"
 
+struct coda_vm_ops {
+       atomic_t refcnt;
+       struct file *coda_file;
+       const struct vm_operations_struct *host_vm_ops;
+       struct vm_operations_struct vm_ops;
+};
+
 static ssize_t
 coda_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
 {
        struct file *coda_file = iocb->ki_filp;
-       struct coda_file_info *cfi = CODA_FTOC(coda_file);
+       struct inode *coda_inode = file_inode(coda_file);
+       struct coda_file_info *cfi = coda_ftoc(coda_file);
+       loff_t ki_pos = iocb->ki_pos;
+       size_t count = iov_iter_count(to);
+       ssize_t ret;
 
-       BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
+       ret = venus_access_intent(coda_inode->i_sb, coda_i2f(coda_inode),
+                                 &cfi->cfi_access_intent,
+                                 count, ki_pos, CODA_ACCESS_TYPE_READ);
+       if (ret)
+               goto finish_read;
 
-       return vfs_iter_read(cfi->cfi_container, to, &iocb->ki_pos, 0);
+       ret = vfs_iter_read(cfi->cfi_container, to, &iocb->ki_pos, 0);
+
+finish_read:
+       venus_access_intent(coda_inode->i_sb, coda_i2f(coda_inode),
+                           &cfi->cfi_access_intent,
+                           count, ki_pos, CODA_ACCESS_TYPE_READ_FINISH);
+       return ret;
 }
 
 static ssize_t
@@ -43,13 +64,18 @@ coda_file_write_iter(struct kiocb *iocb, struct iov_iter *to)
 {
        struct file *coda_file = iocb->ki_filp;
        struct inode *coda_inode = file_inode(coda_file);
-       struct coda_file_info *cfi = CODA_FTOC(coda_file);
-       struct file *host_file;
+       struct coda_file_info *cfi = coda_ftoc(coda_file);
+       struct file *host_file = cfi->cfi_container;
+       loff_t ki_pos = iocb->ki_pos;
+       size_t count = iov_iter_count(to);
        ssize_t ret;
 
-       BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
+       ret = venus_access_intent(coda_inode->i_sb, coda_i2f(coda_inode),
+                                 &cfi->cfi_access_intent,
+                                 count, ki_pos, CODA_ACCESS_TYPE_WRITE);
+       if (ret)
+               goto finish_write;
 
-       host_file = cfi->cfi_container;
        file_start_write(host_file);
        inode_lock(coda_inode);
        ret = vfs_iter_write(cfi->cfi_container, to, &iocb->ki_pos, 0);
@@ -58,26 +84,73 @@ coda_file_write_iter(struct kiocb *iocb, struct iov_iter *to)
        coda_inode->i_mtime = coda_inode->i_ctime = current_time(coda_inode);
        inode_unlock(coda_inode);
        file_end_write(host_file);
+
+finish_write:
+       venus_access_intent(coda_inode->i_sb, coda_i2f(coda_inode),
+                           &cfi->cfi_access_intent,
+                           count, ki_pos, CODA_ACCESS_TYPE_WRITE_FINISH);
        return ret;
 }
 
+static void
+coda_vm_open(struct vm_area_struct *vma)
+{
+       struct coda_vm_ops *cvm_ops =
+               container_of(vma->vm_ops, struct coda_vm_ops, vm_ops);
+
+       atomic_inc(&cvm_ops->refcnt);
+
+       if (cvm_ops->host_vm_ops && cvm_ops->host_vm_ops->open)
+               cvm_ops->host_vm_ops->open(vma);
+}
+
+static void
+coda_vm_close(struct vm_area_struct *vma)
+{
+       struct coda_vm_ops *cvm_ops =
+               container_of(vma->vm_ops, struct coda_vm_ops, vm_ops);
+
+       if (cvm_ops->host_vm_ops && cvm_ops->host_vm_ops->close)
+               cvm_ops->host_vm_ops->close(vma);
+
+       if (atomic_dec_and_test(&cvm_ops->refcnt)) {
+               vma->vm_ops = cvm_ops->host_vm_ops;
+               fput(cvm_ops->coda_file);
+               kfree(cvm_ops);
+       }
+}
+
 static int
 coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
 {
-       struct coda_file_info *cfi;
+       struct inode *coda_inode = file_inode(coda_file);
+       struct coda_file_info *cfi = coda_ftoc(coda_file);
+       struct file *host_file = cfi->cfi_container;
+       struct inode *host_inode = file_inode(host_file);
        struct coda_inode_info *cii;
-       struct file *host_file;
-       struct inode *coda_inode, *host_inode;
-
-       cfi = CODA_FTOC(coda_file);
-       BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
-       host_file = cfi->cfi_container;
+       struct coda_vm_ops *cvm_ops;
+       loff_t ppos;
+       size_t count;
+       int ret;
 
        if (!host_file->f_op->mmap)
                return -ENODEV;
 
-       coda_inode = file_inode(coda_file);
-       host_inode = file_inode(host_file);
+       if (WARN_ON(coda_file != vma->vm_file))
+               return -EIO;
+
+       count = vma->vm_end - vma->vm_start;
+       ppos = vma->vm_pgoff * PAGE_SIZE;
+
+       ret = venus_access_intent(coda_inode->i_sb, coda_i2f(coda_inode),
+                                 &cfi->cfi_access_intent,
+                                 count, ppos, CODA_ACCESS_TYPE_MMAP);
+       if (ret)
+               return ret;
+
+       cvm_ops = kmalloc(sizeof(struct coda_vm_ops), GFP_KERNEL);
+       if (!cvm_ops)
+               return -ENOMEM;
 
        cii = ITOC(coda_inode);
        spin_lock(&cii->c_lock);
@@ -89,6 +162,7 @@ coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
         * the container file on us! */
        else if (coda_inode->i_mapping != host_inode->i_mapping) {
                spin_unlock(&cii->c_lock);
+               kfree(cvm_ops);
                return -EBUSY;
        }
 
@@ -97,7 +171,29 @@ coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
        cfi->cfi_mapcount++;
        spin_unlock(&cii->c_lock);
 
-       return call_mmap(host_file, vma);
+       vma->vm_file = get_file(host_file);
+       ret = call_mmap(vma->vm_file, vma);
+
+       if (ret) {
+               /* if call_mmap fails, our caller will put coda_file so we
+                * should drop the reference to the host_file that we got.
+                */
+               fput(host_file);
+               kfree(cvm_ops);
+       } else {
+               /* here we add redirects for the open/close vm_operations */
+               cvm_ops->host_vm_ops = vma->vm_ops;
+               if (vma->vm_ops)
+                       cvm_ops->vm_ops = *vma->vm_ops;
+
+               cvm_ops->vm_ops.open = coda_vm_open;
+               cvm_ops->vm_ops.close = coda_vm_close;
+               cvm_ops->coda_file = coda_file;
+               atomic_set(&cvm_ops->refcnt, 1);
+
+               vma->vm_ops = &cvm_ops->vm_ops;
+       }
+       return ret;
 }
 
 int coda_open(struct inode *coda_inode, struct file *coda_file)
@@ -127,6 +223,8 @@ int coda_open(struct inode *coda_inode, struct file *coda_file)
        cfi->cfi_magic = CODA_MAGIC;
        cfi->cfi_mapcount = 0;
        cfi->cfi_container = host_file;
+       /* assume access intents are supported unless we hear otherwise */
+       cfi->cfi_access_intent = true;
 
        BUG_ON(coda_file->private_data != NULL);
        coda_file->private_data = cfi;
@@ -142,8 +240,7 @@ int coda_release(struct inode *coda_inode, struct file *coda_file)
        struct inode *host_inode;
        int err;
 
-       cfi = CODA_FTOC(coda_file);
-       BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
+       cfi = coda_ftoc(coda_file);
 
        err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode),
                          coda_flags, coda_file->f_cred->fsuid);
@@ -185,8 +282,7 @@ int coda_fsync(struct file *coda_file, loff_t start, loff_t end, int datasync)
                return err;
        inode_lock(coda_inode);
 
-       cfi = CODA_FTOC(coda_file);
-       BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
+       cfi = coda_ftoc(coda_file);
        host_file = cfi->cfi_container;
 
        err = vfs_fsync(host_file, datasync);
@@ -207,4 +303,3 @@ const struct file_operations coda_file_operations = {
        .fsync          = coda_fsync,
        .splice_read    = generic_file_splice_read,
 };
-
index 23f6ebd..321f56e 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/vmalloc.h>
 
 #include <linux/coda.h>
-#include <linux/coda_psdev.h>
+#include "coda_psdev.h"
 #include "coda_linux.h"
 #include "coda_cache.h"
 
@@ -236,6 +236,7 @@ static void coda_put_super(struct super_block *sb)
        vcp->vc_sb = NULL;
        sb->s_fs_info = NULL;
        mutex_unlock(&vcp->vc_mutex);
+       mutex_destroy(&vcp->vc_mutex);
 
        pr_info("Bye bye.\n");
 }
index e0c17b7..644d48c 100644 (file)
@@ -20,8 +20,7 @@
 #include <linux/uaccess.h>
 
 #include <linux/coda.h>
-#include <linux/coda_psdev.h>
-
+#include "coda_psdev.h"
 #include "coda_linux.h"
 
 /* pioctl ops */
index 0ceef32..240669f 100644 (file)
@@ -38,8 +38,7 @@
 #include <linux/uaccess.h>
 
 #include <linux/coda.h>
-#include <linux/coda_psdev.h>
-
+#include "coda_psdev.h"
 #include "coda_linux.h"
 
 #include "coda_int.h"
@@ -100,8 +99,12 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf,
        ssize_t retval = 0, count = 0;
        int error;
 
+       /* make sure there is enough to copy out the (opcode, unique) values */
+       if (nbytes < (2 * sizeof(u_int32_t)))
+               return -EINVAL;
+
         /* Peek at the opcode, uniquefier */
-       if (copy_from_user(&hdr, buf, 2 * sizeof(u_long)))
+       if (copy_from_user(&hdr, buf, 2 * sizeof(u_int32_t)))
                return -EFAULT;
 
         if (DOWNCALL(hdr.opcode)) {
@@ -119,17 +122,21 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf,
                                hdr.opcode, hdr.unique);
                        nbytes = size;
                }
-               CODA_ALLOC(dcbuf, union outputArgs *, nbytes);
+               dcbuf = kvmalloc(nbytes, GFP_KERNEL);
+               if (!dcbuf) {
+                       retval = -ENOMEM;
+                       goto out;
+               }
                if (copy_from_user(dcbuf, buf, nbytes)) {
-                       CODA_FREE(dcbuf, nbytes);
+                       kvfree(dcbuf);
                        retval = -EFAULT;
                        goto out;
                }
 
                /* what downcall errors does Venus handle ? */
-               error = coda_downcall(vcp, hdr.opcode, dcbuf);
+               error = coda_downcall(vcp, hdr.opcode, dcbuf, nbytes);
 
-               CODA_FREE(dcbuf, nbytes);
+               kvfree(dcbuf);
                if (error) {
                        pr_warn("%s: coda_downcall error: %d\n",
                                __func__, error);
@@ -182,8 +189,11 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf,
        if (req->uc_opcode == CODA_OPEN_BY_FD) {
                struct coda_open_by_fd_out *outp =
                        (struct coda_open_by_fd_out *)req->uc_data;
-               if (!outp->oh.result)
+               if (!outp->oh.result) {
                        outp->fh = fget(outp->fd);
+                       if (!outp->fh)
+                               return -EBADF;
+               }
        }
 
         wake_up(&req->uc_sleep);
@@ -252,7 +262,7 @@ static ssize_t coda_psdev_read(struct file * file, char __user * buf,
                goto out;
        }
 
-       CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr));
+       kvfree(req->uc_data);
        kfree(req);
 out:
        mutex_unlock(&vcp->vc_mutex);
@@ -314,7 +324,7 @@ static int coda_psdev_release(struct inode * inode, struct file * file)
 
                /* Async requests need to be freed here */
                if (req->uc_flags & CODA_REQ_ASYNC) {
-                       CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr));
+                       kvfree(req->uc_data);
                        kfree(req);
                        continue;
                }
@@ -347,13 +357,13 @@ static const struct file_operations coda_psdev_fops = {
        .llseek         = noop_llseek,
 };
 
-static int init_coda_psdev(void)
+static int __init init_coda_psdev(void)
 {
        int i, err = 0;
        if (register_chrdev(CODA_PSDEV_MAJOR, "coda", &coda_psdev_fops)) {
                pr_err("%s: unable to get major %d\n",
                       __func__, CODA_PSDEV_MAJOR);
-              return -EIO;
+               return -EIO;
        }
        coda_psdev_class = class_create(THIS_MODULE, "coda");
        if (IS_ERR(coda_psdev_class)) {
@@ -378,7 +388,7 @@ MODULE_AUTHOR("Jan Harkes, Peter J. Braam");
 MODULE_DESCRIPTION("Coda Distributed File System VFS interface");
 MODULE_ALIAS_CHARDEV_MAJOR(CODA_PSDEV_MAJOR);
 MODULE_LICENSE("GPL");
-MODULE_VERSION("6.6");
+MODULE_VERSION("7.0");
 
 static int __init init_coda(void)
 {
index 202297d..8907d05 100644 (file)
@@ -17,8 +17,7 @@
 #include <linux/pagemap.h>
 
 #include <linux/coda.h>
-#include <linux/coda_psdev.h>
-
+#include "coda_psdev.h"
 #include "coda_linux.h"
 
 static int coda_symlink_filler(struct file *file, struct page *page)
index 0301d45..fda3b70 100644 (file)
@@ -12,7 +12,6 @@
 
 #include "coda_int.h"
 
-#ifdef CONFIG_SYSCTL
 static struct ctl_table_header *fs_table_header;
 
 static struct ctl_table coda_table[] = {
@@ -62,13 +61,3 @@ void coda_sysctl_clean(void)
                fs_table_header = NULL;
        }
 }
-
-#else
-void coda_sysctl_init(void)
-{
-}
-
-void coda_sysctl_clean(void)
-{
-}
-#endif
index 1175a17..eb3b189 100644 (file)
@@ -33,7 +33,7 @@
 #include <linux/vfs.h>
 
 #include <linux/coda.h>
-#include <linux/coda_psdev.h>
+#include "coda_psdev.h"
 #include "coda_linux.h"
 #include "coda_cache.h"
 
@@ -46,7 +46,7 @@ static void *alloc_upcall(int opcode, int size)
 {
        union inputArgs *inp;
 
-       CODA_ALLOC(inp, union inputArgs *, size);
+       inp = kvzalloc(size, GFP_KERNEL);
         if (!inp)
                return ERR_PTR(-ENOMEM);
 
@@ -85,7 +85,7 @@ int venus_rootfid(struct super_block *sb, struct CodaFid *fidp)
        if (!error)
                *fidp = outp->coda_root.VFid;
 
-       CODA_FREE(inp, insize);
+       kvfree(inp);
        return error;
 }
 
@@ -104,7 +104,7 @@ int venus_getattr(struct super_block *sb, struct CodaFid *fid,
        if (!error)
                *attr = outp->coda_getattr.attr;
 
-       CODA_FREE(inp, insize);
+       kvfree(inp);
         return error;
 }
 
@@ -123,7 +123,7 @@ int venus_setattr(struct super_block *sb, struct CodaFid *fid,
 
        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 
-        CODA_FREE(inp, insize);
+       kvfree(inp);
         return error;
 }
 
@@ -153,7 +153,7 @@ int venus_lookup(struct super_block *sb, struct CodaFid *fid,
                *type = outp->coda_lookup.vtype;
        }
 
-       CODA_FREE(inp, insize);
+       kvfree(inp);
        return error;
 }
 
@@ -173,7 +173,7 @@ int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
 
        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 
-       CODA_FREE(inp, insize);
+       kvfree(inp);
         return error;
 }
 
@@ -194,7 +194,7 @@ int venus_open(struct super_block *sb, struct CodaFid *fid,
        if (!error)
                *fh = outp->coda_open_by_fd.fh;
 
-       CODA_FREE(inp, insize);
+       kvfree(inp);
        return error;
 }      
 
@@ -224,7 +224,7 @@ int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid,
                *newfid = outp->coda_mkdir.VFid;
        }
 
-       CODA_FREE(inp, insize);
+       kvfree(inp);
        return error;        
 }
 
@@ -262,7 +262,7 @@ int venus_rename(struct super_block *sb, struct CodaFid *old_fid,
 
        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 
-       CODA_FREE(inp, insize);
+       kvfree(inp);
        return error;
 }
 
@@ -295,7 +295,7 @@ int venus_create(struct super_block *sb, struct CodaFid *dirfid,
                *newfid = outp->coda_create.VFid;
        }
 
-       CODA_FREE(inp, insize);
+       kvfree(inp);
        return error;        
 }
 
@@ -318,7 +318,7 @@ int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid,
 
        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 
-       CODA_FREE(inp, insize);
+       kvfree(inp);
        return error;
 }
 
@@ -340,7 +340,7 @@ int venus_remove(struct super_block *sb, struct CodaFid *dirfid,
 
        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 
-       CODA_FREE(inp, insize);
+       kvfree(inp);
        return error;
 }
 
@@ -370,7 +370,7 @@ int venus_readlink(struct super_block *sb, struct CodaFid *fid,
                *(buffer + retlen) = '\0';
        }
 
-        CODA_FREE(inp, insize);
+       kvfree(inp);
         return error;
 }
 
@@ -398,7 +398,7 @@ int venus_link(struct super_block *sb, struct CodaFid *fid,
 
        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 
-       CODA_FREE(inp, insize);
+       kvfree(inp);
         return error;
 }
 
@@ -433,7 +433,7 @@ int venus_symlink(struct super_block *sb, struct CodaFid *fid,
 
        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 
-       CODA_FREE(inp, insize);
+       kvfree(inp);
         return error;
 }
 
@@ -449,7 +449,7 @@ int venus_fsync(struct super_block *sb, struct CodaFid *fid)
        inp->coda_fsync.VFid = *fid;
        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 
-       CODA_FREE(inp, insize);
+       kvfree(inp);
        return error;
 }
 
@@ -467,7 +467,7 @@ int venus_access(struct super_block *sb, struct CodaFid *fid, int mask)
 
        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 
-       CODA_FREE(inp, insize);
+       kvfree(inp);
        return error;
 }
 
@@ -543,7 +543,7 @@ int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
        }
 
  exit:
-       CODA_FREE(inp, insize);
+       kvfree(inp);
        return error;
 }
 
@@ -553,7 +553,7 @@ int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
         union outputArgs *outp;
         int insize, outsize, error;
         
-       insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
+       insize = SIZE(statfs);
        UPARG(CODA_STATFS);
 
        error = coda_upcall(coda_vcp(dentry->d_sb), insize, &outsize, inp);
@@ -565,10 +565,51 @@ int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
                sfs->f_ffree  = outp->coda_statfs.stat.f_ffree;
        }
 
-        CODA_FREE(inp, insize);
+       kvfree(inp);
         return error;
 }
 
+int venus_access_intent(struct super_block *sb, struct CodaFid *fid,
+                       bool *access_intent_supported,
+                       size_t count, loff_t ppos, int type)
+{
+       union inputArgs *inp;
+       union outputArgs *outp;
+       int insize, outsize, error;
+       bool finalizer =
+               type == CODA_ACCESS_TYPE_READ_FINISH ||
+               type == CODA_ACCESS_TYPE_WRITE_FINISH;
+
+       if (!*access_intent_supported && !finalizer)
+               return 0;
+
+       insize = SIZE(access_intent);
+       UPARG(CODA_ACCESS_INTENT);
+
+       inp->coda_access_intent.VFid = *fid;
+       inp->coda_access_intent.count = count;
+       inp->coda_access_intent.pos = ppos;
+       inp->coda_access_intent.type = type;
+
+       error = coda_upcall(coda_vcp(sb), insize,
+                           finalizer ? NULL : &outsize, inp);
+
+       /*
+        * we have to free the request buffer for synchronous upcalls
+        * or when asynchronous upcalls fail, but not when asynchronous
+        * upcalls succeed
+        */
+       if (!finalizer || error)
+               kvfree(inp);
+
+       /* Chunked access is not supported or an old Coda client */
+       if (error == -EOPNOTSUPP) {
+               *access_intent_supported = false;
+               error = 0;
+       }
+       return error;
+}
+
 /*
  * coda_upcall and coda_downcall routines.
  */
@@ -598,10 +639,12 @@ static void coda_unblock_signals(sigset_t *old)
  * has seen them,
  * - CODA_CLOSE or CODA_RELEASE upcall  (to avoid reference count problems)
  * - CODA_STORE                                (to avoid data loss)
+ * - CODA_ACCESS_INTENT                 (to avoid reference count problems)
  */
 #define CODA_INTERRUPTIBLE(r) (!coda_hard && \
                               (((r)->uc_opcode != CODA_CLOSE && \
                                 (r)->uc_opcode != CODA_STORE && \
+                                (r)->uc_opcode != CODA_ACCESS_INTENT && \
                                 (r)->uc_opcode != CODA_RELEASE) || \
                                (r)->uc_flags & CODA_REQ_READ))
 
@@ -687,21 +730,25 @@ static int coda_upcall(struct venus_comm *vcp,
                goto exit;
        }
 
+       buffer->ih.unique = ++vcp->vc_seq;
+
        req->uc_data = (void *)buffer;
-       req->uc_flags = 0;
+       req->uc_flags = outSize ? 0 : CODA_REQ_ASYNC;
        req->uc_inSize = inSize;
-       req->uc_outSize = *outSize ? *outSize : inSize;
-       req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
-       req->uc_unique = ++vcp->vc_seq;
+       req->uc_outSize = (outSize && *outSize) ? *outSize : inSize;
+       req->uc_opcode = buffer->ih.opcode;
+       req->uc_unique = buffer->ih.unique;
        init_waitqueue_head(&req->uc_sleep);
 
-       /* Fill in the common input args. */
-       ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
-
        /* Append msg to pending queue and poke Venus. */
        list_add_tail(&req->uc_chain, &vcp->vc_pending);
-
        wake_up_interruptible(&vcp->vc_waitq);
+
+       if (req->uc_flags & CODA_REQ_ASYNC) {
+               mutex_unlock(&vcp->vc_mutex);
+               return 0;
+       }
+
        /* We can be interrupted while we wait for Venus to process
         * our request.  If the interrupt occurs before Venus has read
         * the request, we dequeue and return. If it occurs after the
@@ -743,20 +790,20 @@ static int coda_upcall(struct venus_comm *vcp,
        sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
        if (!sig_req) goto exit;
 
-       CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
-       if (!sig_req->uc_data) {
+       sig_inputArgs = kvzalloc(sizeof(struct coda_in_hdr), GFP_KERNEL);
+       if (!sig_inputArgs) {
                kfree(sig_req);
                goto exit;
        }
 
        error = -EINTR;
-       sig_inputArgs = (union inputArgs *)sig_req->uc_data;
        sig_inputArgs->ih.opcode = CODA_SIGNAL;
        sig_inputArgs->ih.unique = req->uc_unique;
 
        sig_req->uc_flags = CODA_REQ_ASYNC;
        sig_req->uc_opcode = sig_inputArgs->ih.opcode;
        sig_req->uc_unique = sig_inputArgs->ih.unique;
+       sig_req->uc_data = (void *)sig_inputArgs;
        sig_req->uc_inSize = sizeof(struct coda_in_hdr);
        sig_req->uc_outSize = sizeof(struct coda_in_hdr);
 
@@ -804,12 +851,44 @@ exit:
  *
  * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
 
-int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out)
+int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out,
+                 size_t nbytes)
 {
        struct inode *inode = NULL;
        struct CodaFid *fid = NULL, *newfid;
        struct super_block *sb;
 
+       /*
+        * Make sure we have received enough data from the cache
+        * manager to populate the necessary fields in the buffer
+        */
+       switch (opcode) {
+       case CODA_PURGEUSER:
+               if (nbytes < sizeof(struct coda_purgeuser_out))
+                       return -EINVAL;
+               break;
+
+       case CODA_ZAPDIR:
+               if (nbytes < sizeof(struct coda_zapdir_out))
+                       return -EINVAL;
+               break;
+
+       case CODA_ZAPFILE:
+               if (nbytes < sizeof(struct coda_zapfile_out))
+                       return -EINVAL;
+               break;
+
+       case CODA_PURGEFID:
+               if (nbytes < sizeof(struct coda_purgefid_out))
+                       return -EINVAL;
+               break;
+
+       case CODA_REPLACE:
+               if (nbytes < sizeof(struct coda_replace_out))
+                       return -EINVAL;
+               break;
+       }
+
        /* Handle invalidation requests. */
        mutex_lock(&vcp->vc_mutex);
        sb = vcp->vc_sb;
@@ -879,4 +958,3 @@ unlock_out:
        iput(inode);
        return 0;
 }
-
index 791304f..55438dd 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/fs.h>
 #include <linux/module.h>
 #include <linux/mount.h>
+#include <linux/fs_context.h>
 #include <linux/pagemap.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -52,7 +53,7 @@ static struct configfs_dirent configfs_root = {
        .s_iattr        = NULL,
 };
 
-static int configfs_fill_super(struct super_block *sb, void *data, int silent)
+static int configfs_fill_super(struct super_block *sb, struct fs_context *fc)
 {
        struct inode *inode;
        struct dentry *root;
@@ -88,16 +89,25 @@ static int configfs_fill_super(struct super_block *sb, void *data, int silent)
        return 0;
 }
 
-static struct dentry *configfs_do_mount(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *data)
+static int configfs_get_tree(struct fs_context *fc)
 {
-       return mount_single(fs_type, flags, data, configfs_fill_super);
+       return get_tree_single(fc, configfs_fill_super);
+}
+
+static const struct fs_context_operations configfs_context_ops = {
+       .get_tree       = configfs_get_tree,
+};
+
+static int configfs_init_fs_context(struct fs_context *fc)
+{
+       fc->ops = &configfs_context_ops;
+       return 0;
 }
 
 static struct file_system_type configfs_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "configfs",
-       .mount          = configfs_do_mount,
+       .init_fs_context = configfs_init_fs_context,
        .kill_sb        = kill_litter_super,
 };
 MODULE_ALIAS_FS("configfs");
index e8fce6b..a7d0a96 100644 (file)
@@ -316,7 +316,6 @@ char *simple_dname(struct dentry *dentry, char *buffer, int buflen)
                end = ERR_PTR(-ENAMETOOLONG);
        return end;
 }
-EXPORT_SYMBOL(simple_dname);
 
 /*
  * Write full pathname from the root of the filesystem into the buffer.
index fe5e338..a237141 100644 (file)
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -26,7 +26,6 @@
 #include <linux/mmu_notifier.h>
 #include <linux/iomap.h>
 #include <asm/pgalloc.h>
-#include "internal.h"
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/fs_dax.h>
@@ -124,6 +123,15 @@ static int dax_is_empty_entry(void *entry)
 }
 
 /*
+ * true if the entry that was found is of a smaller order than the entry
+ * we were looking for
+ */
+static bool dax_is_conflict(void *entry)
+{
+       return entry == XA_RETRY_ENTRY;
+}
+
+/*
  * DAX page cache entry locking
  */
 struct exceptional_entry_key {
@@ -195,11 +203,13 @@ static void dax_wake_entry(struct xa_state *xas, void *entry, bool wake_all)
  * Look up entry in page cache, wait for it to become unlocked if it
  * is a DAX entry and return it.  The caller must subsequently call
  * put_unlocked_entry() if it did not lock the entry or dax_unlock_entry()
- * if it did.
+ * if it did.  The entry returned may have a larger order than @order.
+ * If @order is larger than the order of the entry found in i_pages, this
+ * function returns a dax_is_conflict entry.
  *
  * Must be called with the i_pages lock held.
  */
-static void *get_unlocked_entry(struct xa_state *xas)
+static void *get_unlocked_entry(struct xa_state *xas, unsigned int order)
 {
        void *entry;
        struct wait_exceptional_entry_queue ewait;
@@ -210,6 +220,8 @@ static void *get_unlocked_entry(struct xa_state *xas)
 
        for (;;) {
                entry = xas_find_conflict(xas);
+               if (dax_entry_order(entry) < order)
+                       return XA_RETRY_ENTRY;
                if (!entry || WARN_ON_ONCE(!xa_is_value(entry)) ||
                                !dax_is_locked(entry))
                        return entry;
@@ -254,7 +266,7 @@ static void wait_entry_unlocked(struct xa_state *xas, void *entry)
 static void put_unlocked_entry(struct xa_state *xas, void *entry)
 {
        /* If we were the only waiter woken, wake the next one */
-       if (entry)
+       if (entry && dax_is_conflict(entry))
                dax_wake_entry(xas, entry, false);
 }
 
@@ -461,7 +473,7 @@ void dax_unlock_page(struct page *page, dax_entry_t cookie)
  * overlap with xarray value entries.
  */
 static void *grab_mapping_entry(struct xa_state *xas,
-               struct address_space *mapping, unsigned long size_flag)
+               struct address_space *mapping, unsigned int order)
 {
        unsigned long index = xas->xa_index;
        bool pmd_downgrade = false; /* splitting PMD entry into PTE entries? */
@@ -469,20 +481,17 @@ static void *grab_mapping_entry(struct xa_state *xas,
 
 retry:
        xas_lock_irq(xas);
-       entry = get_unlocked_entry(xas);
+       entry = get_unlocked_entry(xas, order);
 
        if (entry) {
+               if (dax_is_conflict(entry))
+                       goto fallback;
                if (!xa_is_value(entry)) {
                        xas_set_err(xas, EIO);
                        goto out_unlock;
                }
 
-               if (size_flag & DAX_PMD) {
-                       if (dax_is_pte_entry(entry)) {
-                               put_unlocked_entry(xas, entry);
-                               goto fallback;
-                       }
-               } else { /* trying to grab a PTE entry */
+               if (order == 0) {
                        if (dax_is_pmd_entry(entry) &&
                            (dax_is_zero_entry(entry) ||
                             dax_is_empty_entry(entry))) {
@@ -523,7 +532,11 @@ retry:
        if (entry) {
                dax_lock_entry(xas, entry);
        } else {
-               entry = dax_make_entry(pfn_to_pfn_t(0), size_flag | DAX_EMPTY);
+               unsigned long flags = DAX_EMPTY;
+
+               if (order > 0)
+                       flags |= DAX_PMD;
+               entry = dax_make_entry(pfn_to_pfn_t(0), flags);
                dax_lock_entry(xas, entry);
                if (xas_error(xas))
                        goto out_unlock;
@@ -594,7 +607,7 @@ struct page *dax_layout_busy_page(struct address_space *mapping)
                if (WARN_ON_ONCE(!xa_is_value(entry)))
                        continue;
                if (unlikely(dax_is_locked(entry)))
-                       entry = get_unlocked_entry(&xas);
+                       entry = get_unlocked_entry(&xas, 0);
                if (entry)
                        page = dax_busy_page(entry);
                put_unlocked_entry(&xas, entry);
@@ -621,7 +634,7 @@ static int __dax_invalidate_entry(struct address_space *mapping,
        void *entry;
 
        xas_lock_irq(&xas);
-       entry = get_unlocked_entry(&xas);
+       entry = get_unlocked_entry(&xas, 0);
        if (!entry || WARN_ON_ONCE(!xa_is_value(entry)))
                goto out;
        if (!trunc &&
@@ -848,7 +861,7 @@ static int dax_writeback_one(struct xa_state *xas, struct dax_device *dax_dev,
        if (unlikely(dax_is_locked(entry))) {
                void *old_entry = entry;
 
-               entry = get_unlocked_entry(xas);
+               entry = get_unlocked_entry(xas, 0);
 
                /* Entry got punched out / reallocated? */
                if (!entry || WARN_ON_ONCE(!xa_is_value(entry)))
@@ -1509,7 +1522,7 @@ static vm_fault_t dax_iomap_pmd_fault(struct vm_fault *vmf, pfn_t *pfnp,
         * entry is already in the array, for instance), it will return
         * VM_FAULT_FALLBACK.
         */
-       entry = grab_mapping_entry(&xas, mapping, DAX_PMD);
+       entry = grab_mapping_entry(&xas, mapping, PMD_ORDER);
        if (xa_is_internal(entry)) {
                result = xa_to_internal(entry);
                goto fallback;
@@ -1658,11 +1671,10 @@ dax_insert_pfn_mkwrite(struct vm_fault *vmf, pfn_t pfn, unsigned int order)
        vm_fault_t ret;
 
        xas_lock_irq(&xas);
-       entry = get_unlocked_entry(&xas);
+       entry = get_unlocked_entry(&xas, order);
        /* Did we race with someone splitting entry or so? */
-       if (!entry ||
-           (order == 0 && !dax_is_pte_entry(entry)) ||
-           (order == PMD_ORDER && !dax_is_pmd_entry(entry))) {
+       if (!entry || dax_is_conflict(entry) ||
+           (order == 0 && !dax_is_pte_entry(entry))) {
                put_unlocked_entry(&xas, entry);
                xas_unlock_irq(&xas);
                trace_dax_insert_pfn_mkwrite_no_entry(mapping->host, vmf,
index f41121e..e88cf05 100644 (file)
@@ -861,6 +861,32 @@ void dput(struct dentry *dentry)
 }
 EXPORT_SYMBOL(dput);
 
+static void __dput_to_list(struct dentry *dentry, struct list_head *list)
+__must_hold(&dentry->d_lock)
+{
+       if (dentry->d_flags & DCACHE_SHRINK_LIST) {
+               /* let the owner of the list it's on deal with it */
+               --dentry->d_lockref.count;
+       } else {
+               if (dentry->d_flags & DCACHE_LRU_LIST)
+                       d_lru_del(dentry);
+               if (!--dentry->d_lockref.count)
+                       d_shrink_add(dentry, list);
+       }
+}
+
+void dput_to_list(struct dentry *dentry, struct list_head *list)
+{
+       rcu_read_lock();
+       if (likely(fast_dput(dentry))) {
+               rcu_read_unlock();
+               return;
+       }
+       rcu_read_unlock();
+       if (!retain_dentry(dentry))
+               __dput_to_list(dentry, list);
+       spin_unlock(&dentry->d_lock);
+}
 
 /* This must be called with d_lock held */
 static inline void __dget_dlock(struct dentry *dentry)
@@ -1067,7 +1093,7 @@ out:
        return false;
 }
 
-static void shrink_dentry_list(struct list_head *list)
+void shrink_dentry_list(struct list_head *list)
 {
        while (!list_empty(list)) {
                struct dentry *dentry, *parent;
@@ -1089,18 +1115,9 @@ static void shrink_dentry_list(struct list_head *list)
                rcu_read_unlock();
                d_shrink_del(dentry);
                parent = dentry->d_parent;
+               if (parent != dentry)
+                       __dput_to_list(parent, list);
                __dentry_kill(dentry);
-               if (parent == dentry)
-                       continue;
-               /*
-                * We need to prune ancestors too. This is necessary to prevent
-                * quadratic behavior of shrink_dcache_parent(), but is also
-                * expected to be beneficial in reducing dentry cache
-                * fragmentation.
-                */
-               dentry = parent;
-               while (dentry && !lockref_put_or_lock(&dentry->d_lockref))
-                       dentry = dentry_kill(dentry);
        }
 }
 
@@ -1445,8 +1462,11 @@ out:
 
 struct select_data {
        struct dentry *start;
+       union {
+               long found;
+               struct dentry *victim;
+       };
        struct list_head dispose;
-       int found;
 };
 
 static enum d_walk_ret select_collect(void *_data, struct dentry *dentry)
@@ -1478,6 +1498,37 @@ out:
        return ret;
 }
 
+static enum d_walk_ret select_collect2(void *_data, struct dentry *dentry)
+{
+       struct select_data *data = _data;
+       enum d_walk_ret ret = D_WALK_CONTINUE;
+
+       if (data->start == dentry)
+               goto out;
+
+       if (dentry->d_flags & DCACHE_SHRINK_LIST) {
+               if (!dentry->d_lockref.count) {
+                       rcu_read_lock();
+                       data->victim = dentry;
+                       return D_WALK_QUIT;
+               }
+       } else {
+               if (dentry->d_flags & DCACHE_LRU_LIST)
+                       d_lru_del(dentry);
+               if (!dentry->d_lockref.count)
+                       d_shrink_add(dentry, &data->dispose);
+       }
+       /*
+        * We can return to the caller if we have found some (this
+        * ensures forward progress). We'll be coming back to find
+        * the rest.
+        */
+       if (!list_empty(&data->dispose))
+               ret = need_resched() ? D_WALK_QUIT : D_WALK_NORETRY;
+out:
+       return ret;
+}
+
 /**
  * shrink_dcache_parent - prune dcache
  * @parent: parent of entries to prune
@@ -1487,12 +1538,9 @@ out:
 void shrink_dcache_parent(struct dentry *parent)
 {
        for (;;) {
-               struct select_data data;
+               struct select_data data = {.start = parent};
 
                INIT_LIST_HEAD(&data.dispose);
-               data.start = parent;
-               data.found = 0;
-
                d_walk(parent, &data, select_collect);
 
                if (!list_empty(&data.dispose)) {
@@ -1503,6 +1551,24 @@ void shrink_dcache_parent(struct dentry *parent)
                cond_resched();
                if (!data.found)
                        break;
+               data.victim = NULL;
+               d_walk(parent, &data, select_collect2);
+               if (data.victim) {
+                       struct dentry *parent;
+                       spin_lock(&data.victim->d_lock);
+                       if (!shrink_lock_dentry(data.victim)) {
+                               spin_unlock(&data.victim->d_lock);
+                               rcu_read_unlock();
+                       } else {
+                               rcu_read_unlock();
+                               parent = data.victim->d_parent;
+                               if (parent != data.victim)
+                                       __dput_to_list(parent, &data.dispose);
+                               __dentry_kill(data.victim);
+                       }
+               }
+               if (!list_empty(&data.dispose))
+                       shrink_dentry_list(&data.dispose);
        }
 }
 EXPORT_SYMBOL(shrink_dcache_parent);
index 5bc3c4a..fa4f644 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/ctype.h>
 #include <linux/efi.h>
 #include <linux/fs.h>
+#include <linux/fs_context.h>
 #include <linux/module.h>
 #include <linux/pagemap.h>
 #include <linux/ucs2_string.h>
@@ -28,8 +29,6 @@ static const struct super_operations efivarfs_ops = {
        .evict_inode = efivarfs_evict_inode,
 };
 
-static struct super_block *efivarfs_sb;
-
 /*
  * Compare two efivarfs file names.
  *
@@ -188,14 +187,12 @@ static int efivarfs_destroy(struct efivar_entry *entry, void *data)
        return 0;
 }
 
-static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
+static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc)
 {
        struct inode *inode = NULL;
        struct dentry *root;
        int err;
 
-       efivarfs_sb = sb;
-
        sb->s_maxbytes          = MAX_LFS_FILESIZE;
        sb->s_blocksize         = PAGE_SIZE;
        sb->s_blocksize_bits    = PAGE_SHIFT;
@@ -223,16 +220,24 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
        return err;
 }
 
-static struct dentry *efivarfs_mount(struct file_system_type *fs_type,
-                                   int flags, const char *dev_name, void *data)
+static int efivarfs_get_tree(struct fs_context *fc)
+{
+       return get_tree_single(fc, efivarfs_fill_super);
+}
+
+static const struct fs_context_operations efivarfs_context_ops = {
+       .get_tree       = efivarfs_get_tree,
+};
+
+static int efivarfs_init_fs_context(struct fs_context *fc)
 {
-       return mount_single(fs_type, flags, data, efivarfs_fill_super);
+       fc->ops = &efivarfs_context_ops;
+       return 0;
 }
 
 static void efivarfs_kill_sb(struct super_block *sb)
 {
        kill_litter_super(sb);
-       efivarfs_sb = NULL;
 
        /* Remove all entries and destroy */
        __efivar_entry_iter(efivarfs_destroy, &efivarfs_list, NULL, NULL);
@@ -241,7 +246,7 @@ static void efivarfs_kill_sb(struct super_block *sb)
 static struct file_system_type efivarfs_type = {
        .owner   = THIS_MODULE,
        .name    = "efivarfs",
-       .mount   = efivarfs_mount,
+       .init_fs_context = efivarfs_init_fs_context,
        .kill_sb = efivarfs_kill_sb,
 };
 
index 4c74c76..d7f1f50 100644 (file)
@@ -291,7 +291,7 @@ static LIST_HEAD(tfile_check_list);
 
 #include <linux/sysctl.h>
 
-static long zero;
+static long long_zero;
 static long long_max = LONG_MAX;
 
 struct ctl_table epoll_table[] = {
@@ -301,7 +301,7 @@ struct ctl_table epoll_table[] = {
                .maxlen         = sizeof(max_user_watches),
                .mode           = 0644,
                .proc_handler   = proc_doulongvec_minmax,
-               .extra1         = &zero,
+               .extra1         = &long_zero,
                .extra2         = &long_max,
        },
        { }
@@ -2313,19 +2313,17 @@ SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events,
                size_t, sigsetsize)
 {
        int error;
-       sigset_t ksigmask, sigsaved;
 
        /*
         * If the caller wants a certain signal mask to be set during the wait,
         * we apply it here.
         */
-       error = set_user_sigmask(sigmask, &ksigmask, &sigsaved, sigsetsize);
+       error = set_user_sigmask(sigmask, sigsetsize);
        if (error)
                return error;
 
        error = do_epoll_wait(epfd, events, maxevents, timeout);
-
-       restore_user_sigmask(sigmask, &sigsaved, error == -EINTR);
+       restore_saved_sigmask_unless(error == -EINTR);
 
        return error;
 }
@@ -2338,19 +2336,17 @@ COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd,
                        compat_size_t, sigsetsize)
 {
        long err;
-       sigset_t ksigmask, sigsaved;
 
        /*
         * If the caller wants a certain signal mask to be set during the wait,
         * we apply it here.
         */
-       err = set_compat_user_sigmask(sigmask, &ksigmask, &sigsaved, sigsetsize);
+       err = set_compat_user_sigmask(sigmask, sigsetsize);
        if (err)
                return err;
 
        err = do_epoll_wait(epfd, events, maxevents, timeout);
-
-       restore_user_sigmask(sigmask, &sigsaved, err == -EINTR);
+       restore_saved_sigmask_unless(err == -EINTR);
 
        return err;
 }
index f4a24a4..70b0438 100644 (file)
@@ -371,15 +371,17 @@ static const struct vm_operations_struct ext4_file_vm_ops = {
 static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct inode *inode = file->f_mapping->host;
+       struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
+       struct dax_device *dax_dev = sbi->s_daxdev;
 
-       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+       if (unlikely(ext4_forced_shutdown(sbi)))
                return -EIO;
 
        /*
-        * We don't support synchronous mappings for non-DAX files. At least
-        * until someone comes with a sensible use case.
+        * We don't support synchronous mappings for non-DAX files and
+        * for DAX files if underneath dax_device is not synchronous.
         */
-       if (!IS_DAX(file_inode(file)) && (vma->vm_flags & VM_SYNC))
+       if (!daxdev_mapping_supported(vma, dax_dev))
                return -EOPNOTSUPP;
 
        file_accessed(file);
index 4eb2f39..abbf14e 100644 (file)
@@ -2919,7 +2919,7 @@ int f2fs_migrate_page(struct address_space *mapping,
        /* one extra reference was held for atomic_write page */
        extra_count = atomic_written ? 1 : 0;
        rc = migrate_page_move_mapping(mapping, newpage,
-                               page, mode, extra_count);
+                               page, extra_count);
        if (rc != MIGRATEPAGE_SUCCESS) {
                if (atomic_written)
                        mutex_unlock(&fi->inmem_lock);
index 0d388fa..460ea42 100644 (file)
@@ -264,6 +264,7 @@ int fs_lookup_param(struct fs_context *fc,
                return invalf(fc, "%s: not usable as path", param->key);
        }
 
+       f->refcnt++; /* filename_lookup() drops our ref. */
        ret = filename_lookup(param->dirfd, f, flags, _path, NULL);
        if (ret < 0) {
                errorf(fc, "%s: Lookup failure for '%s'", param->key, f->name);
index a6497cf..47ef3c7 100644 (file)
@@ -19,20 +19,14 @@ void pin_remove(struct fs_pin *pin)
        spin_unlock_irq(&pin->wait.lock);
 }
 
-void pin_insert_group(struct fs_pin *pin, struct vfsmount *m, struct hlist_head *p)
+void pin_insert(struct fs_pin *pin, struct vfsmount *m)
 {
        spin_lock(&pin_lock);
-       if (p)
-               hlist_add_head(&pin->s_list, p);
+       hlist_add_head(&pin->s_list, &m->mnt_sb->s_pins);
        hlist_add_head(&pin->m_list, &real_mount(m)->mnt_pins);
        spin_unlock(&pin_lock);
 }
 
-void pin_insert(struct fs_pin *pin, struct vfsmount *m)
-{
-       pin_insert_group(pin, m, &m->mnt_sb->s_pins);
-}
-
 void pin_kill(struct fs_pin *p)
 {
        wait_queue_entry_t wait;
index a8bf83c..043ffa8 100644 (file)
@@ -226,6 +226,8 @@ static int vfs_fsconfig_locked(struct fs_context *fc, int cmd,
        case FSCONFIG_CMD_CREATE:
                if (fc->phase != FS_CONTEXT_CREATE_PARAMS)
                        return -EBUSY;
+               if (!mount_capable(fc))
+                       return -EPERM;
                fc->phase = FS_CONTEXT_CREATING;
                ret = vfs_get_tree(fc);
                if (ret)
index 14ce1e4..c23f6f2 100644 (file)
@@ -346,7 +346,7 @@ static int fuse_ctl_fill_super(struct super_block *sb, struct fs_context *fctx)
 
 static int fuse_ctl_get_tree(struct fs_context *fc)
 {
-       return vfs_get_super(fc, vfs_get_single_super, fuse_ctl_fill_super);
+       return get_tree_single(fc, fuse_ctl_fill_super);
 }
 
 static const struct fs_context_operations fuse_ctl_context_ops = {
index d5403b4..bb0b27d 100644 (file)
@@ -407,7 +407,7 @@ static int copy_name(char *buffer, const char *xattr_name, int name_len)
        int offset = 0;
 
        if (!is_known_namespace(xattr_name)) {
-               strncpy(buffer, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN);
+               memcpy(buffer, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN);
                offset += XATTR_MAC_OSX_PREFIX_LEN;
                len += XATTR_MAC_OSX_PREFIX_LEN;
        }
index 1dcc571..a478df0 100644 (file)
@@ -1299,7 +1299,7 @@ static int hugetlbfs_get_tree(struct fs_context *fc)
        int err = hugetlbfs_validate(fc);
        if (err)
                return err;
-       return vfs_get_super(fc, vfs_get_independent_super, hugetlbfs_fill_super);
+       return get_tree_nodev(fc, hugetlbfs_fill_super);
 }
 
 static void hugetlbfs_fs_context_free(struct fs_context *fc)
index 2f3c3de..315fcd8 100644 (file)
@@ -14,6 +14,7 @@ struct path;
 struct mount;
 struct shrink_control;
 struct fs_context;
+struct user_namespace;
 
 /*
  * block_dev.c
@@ -107,6 +108,7 @@ extern struct file *alloc_empty_file_noaccount(int, const struct cred *);
 extern int reconfigure_super(struct fs_context *);
 extern bool trylock_super(struct super_block *sb);
 extern struct super_block *user_get_super(dev_t);
+extern bool mount_capable(struct fs_context *);
 
 /*
  * open.c
@@ -154,6 +156,9 @@ extern int d_set_mounted(struct dentry *dentry);
 extern long prune_dcache_sb(struct super_block *sb, struct shrink_control *sc);
 extern struct dentry *d_alloc_cursor(struct dentry *);
 extern struct dentry * d_alloc_pseudo(struct super_block *, const struct qstr *);
+extern char *simple_dname(struct dentry *, char *, int);
+extern void dput_to_list(struct dentry *, struct list_head *);
+extern void shrink_dentry_list(struct list_head *);
 
 /*
  * read_write.c
@@ -182,15 +187,5 @@ extern const struct dentry_operations ns_dentry_operations;
 extern int do_vfs_ioctl(struct file *file, unsigned int fd, unsigned int cmd,
                    unsigned long arg);
 
-/*
- * iomap support:
- */
-typedef loff_t (*iomap_actor_t)(struct inode *inode, loff_t pos, loff_t len,
-               void *data, struct iomap *iomap);
-
-loff_t iomap_apply(struct inode *inode, loff_t pos, loff_t length,
-               unsigned flags, const struct iomap_ops *ops, void *data,
-               iomap_actor_t actor);
-
 /* direct-io.c: */
 int sb_init_dio_done_wq(struct super_block *sb);
index 15d9b16..012bc0e 100644 (file)
@@ -2447,7 +2447,6 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,
                          const sigset_t __user *sig, size_t sigsz)
 {
        struct io_cq_ring *ring = ctx->cq_ring;
-       sigset_t ksigmask, sigsaved;
        int ret;
 
        if (io_cqring_events(ring) >= min_events)
@@ -2457,21 +2456,17 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,
 #ifdef CONFIG_COMPAT
                if (in_compat_syscall())
                        ret = set_compat_user_sigmask((const compat_sigset_t __user *)sig,
-                                                     &ksigmask, &sigsaved, sigsz);
+                                                     sigsz);
                else
 #endif
-                       ret = set_user_sigmask(sig, &ksigmask,
-                                              &sigsaved, sigsz);
+                       ret = set_user_sigmask(sig, sigsz);
 
                if (ret)
                        return ret;
        }
 
        ret = wait_event_interruptible(ctx->wait, io_cqring_events(ring) >= min_events);
-
-       if (sig)
-               restore_user_sigmask(sig, &sigsaved, ret == -ERESTARTSYS);
-
+       restore_saved_sigmask_unless(ret == -ERESTARTSYS);
        if (ret == -ERESTARTSYS)
                ret = -EINTR;
 
diff --git a/fs/iomap.c b/fs/iomap.c
deleted file mode 100644 (file)
index 217c3e5..0000000
+++ /dev/null
@@ -1,2205 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2010 Red Hat, Inc.
- * Copyright (c) 2016-2018 Christoph Hellwig.
- */
-#include <linux/module.h>
-#include <linux/compiler.h>
-#include <linux/fs.h>
-#include <linux/iomap.h>
-#include <linux/uaccess.h>
-#include <linux/gfp.h>
-#include <linux/migrate.h>
-#include <linux/mm.h>
-#include <linux/mm_inline.h>
-#include <linux/swap.h>
-#include <linux/pagemap.h>
-#include <linux/pagevec.h>
-#include <linux/file.h>
-#include <linux/uio.h>
-#include <linux/backing-dev.h>
-#include <linux/buffer_head.h>
-#include <linux/task_io_accounting_ops.h>
-#include <linux/dax.h>
-#include <linux/sched/signal.h>
-
-#include "internal.h"
-
-/*
- * Execute a iomap write on a segment of the mapping that spans a
- * contiguous range of pages that have identical block mapping state.
- *
- * This avoids the need to map pages individually, do individual allocations
- * for each page and most importantly avoid the need for filesystem specific
- * locking per page. Instead, all the operations are amortised over the entire
- * range of pages. It is assumed that the filesystems will lock whatever
- * resources they require in the iomap_begin call, and release them in the
- * iomap_end call.
- */
-loff_t
-iomap_apply(struct inode *inode, loff_t pos, loff_t length, unsigned flags,
-               const struct iomap_ops *ops, void *data, iomap_actor_t actor)
-{
-       struct iomap iomap = { 0 };
-       loff_t written = 0, ret;
-
-       /*
-        * Need to map a range from start position for length bytes. This can
-        * span multiple pages - it is only guaranteed to return a range of a
-        * single type of pages (e.g. all into a hole, all mapped or all
-        * unwritten). Failure at this point has nothing to undo.
-        *
-        * If allocation is required for this range, reserve the space now so
-        * that the allocation is guaranteed to succeed later on. Once we copy
-        * the data into the page cache pages, then we cannot fail otherwise we
-        * expose transient stale data. If the reserve fails, we can safely
-        * back out at this point as there is nothing to undo.
-        */
-       ret = ops->iomap_begin(inode, pos, length, flags, &iomap);
-       if (ret)
-               return ret;
-       if (WARN_ON(iomap.offset > pos))
-               return -EIO;
-       if (WARN_ON(iomap.length == 0))
-               return -EIO;
-
-       /*
-        * Cut down the length to the one actually provided by the filesystem,
-        * as it might not be able to give us the whole size that we requested.
-        */
-       if (iomap.offset + iomap.length < pos + length)
-               length = iomap.offset + iomap.length - pos;
-
-       /*
-        * Now that we have guaranteed that the space allocation will succeed.
-        * we can do the copy-in page by page without having to worry about
-        * failures exposing transient data.
-        */
-       written = actor(inode, pos, length, data, &iomap);
-
-       /*
-        * Now the data has been copied, commit the range we've copied.  This
-        * should not fail unless the filesystem has had a fatal error.
-        */
-       if (ops->iomap_end) {
-               ret = ops->iomap_end(inode, pos, length,
-                                    written > 0 ? written : 0,
-                                    flags, &iomap);
-       }
-
-       return written ? written : ret;
-}
-
-static sector_t
-iomap_sector(struct iomap *iomap, loff_t pos)
-{
-       return (iomap->addr + pos - iomap->offset) >> SECTOR_SHIFT;
-}
-
-static struct iomap_page *
-iomap_page_create(struct inode *inode, struct page *page)
-{
-       struct iomap_page *iop = to_iomap_page(page);
-
-       if (iop || i_blocksize(inode) == PAGE_SIZE)
-               return iop;
-
-       iop = kmalloc(sizeof(*iop), GFP_NOFS | __GFP_NOFAIL);
-       atomic_set(&iop->read_count, 0);
-       atomic_set(&iop->write_count, 0);
-       bitmap_zero(iop->uptodate, PAGE_SIZE / SECTOR_SIZE);
-
-       /*
-        * migrate_page_move_mapping() assumes that pages with private data have
-        * their count elevated by 1.
-        */
-       get_page(page);
-       set_page_private(page, (unsigned long)iop);
-       SetPagePrivate(page);
-       return iop;
-}
-
-static void
-iomap_page_release(struct page *page)
-{
-       struct iomap_page *iop = to_iomap_page(page);
-
-       if (!iop)
-               return;
-       WARN_ON_ONCE(atomic_read(&iop->read_count));
-       WARN_ON_ONCE(atomic_read(&iop->write_count));
-       ClearPagePrivate(page);
-       set_page_private(page, 0);
-       put_page(page);
-       kfree(iop);
-}
-
-/*
- * Calculate the range inside the page that we actually need to read.
- */
-static void
-iomap_adjust_read_range(struct inode *inode, struct iomap_page *iop,
-               loff_t *pos, loff_t length, unsigned *offp, unsigned *lenp)
-{
-       loff_t orig_pos = *pos;
-       loff_t isize = i_size_read(inode);
-       unsigned block_bits = inode->i_blkbits;
-       unsigned block_size = (1 << block_bits);
-       unsigned poff = offset_in_page(*pos);
-       unsigned plen = min_t(loff_t, PAGE_SIZE - poff, length);
-       unsigned first = poff >> block_bits;
-       unsigned last = (poff + plen - 1) >> block_bits;
-
-       /*
-        * If the block size is smaller than the page size we need to check the
-        * per-block uptodate status and adjust the offset and length if needed
-        * to avoid reading in already uptodate ranges.
-        */
-       if (iop) {
-               unsigned int i;
-
-               /* move forward for each leading block marked uptodate */
-               for (i = first; i <= last; i++) {
-                       if (!test_bit(i, iop->uptodate))
-                               break;
-                       *pos += block_size;
-                       poff += block_size;
-                       plen -= block_size;
-                       first++;
-               }
-
-               /* truncate len if we find any trailing uptodate block(s) */
-               for ( ; i <= last; i++) {
-                       if (test_bit(i, iop->uptodate)) {
-                               plen -= (last - i + 1) * block_size;
-                               last = i - 1;
-                               break;
-                       }
-               }
-       }
-
-       /*
-        * If the extent spans the block that contains the i_size we need to
-        * handle both halves separately so that we properly zero data in the
-        * page cache for blocks that are entirely outside of i_size.
-        */
-       if (orig_pos <= isize && orig_pos + length > isize) {
-               unsigned end = offset_in_page(isize - 1) >> block_bits;
-
-               if (first <= end && last > end)
-                       plen -= (last - end) * block_size;
-       }
-
-       *offp = poff;
-       *lenp = plen;
-}
-
-static void
-iomap_set_range_uptodate(struct page *page, unsigned off, unsigned len)
-{
-       struct iomap_page *iop = to_iomap_page(page);
-       struct inode *inode = page->mapping->host;
-       unsigned first = off >> inode->i_blkbits;
-       unsigned last = (off + len - 1) >> inode->i_blkbits;
-       unsigned int i;
-       bool uptodate = true;
-
-       if (iop) {
-               for (i = 0; i < PAGE_SIZE / i_blocksize(inode); i++) {
-                       if (i >= first && i <= last)
-                               set_bit(i, iop->uptodate);
-                       else if (!test_bit(i, iop->uptodate))
-                               uptodate = false;
-               }
-       }
-
-       if (uptodate && !PageError(page))
-               SetPageUptodate(page);
-}
-
-static void
-iomap_read_finish(struct iomap_page *iop, struct page *page)
-{
-       if (!iop || atomic_dec_and_test(&iop->read_count))
-               unlock_page(page);
-}
-
-static void
-iomap_read_page_end_io(struct bio_vec *bvec, int error)
-{
-       struct page *page = bvec->bv_page;
-       struct iomap_page *iop = to_iomap_page(page);
-
-       if (unlikely(error)) {
-               ClearPageUptodate(page);
-               SetPageError(page);
-       } else {
-               iomap_set_range_uptodate(page, bvec->bv_offset, bvec->bv_len);
-       }
-
-       iomap_read_finish(iop, page);
-}
-
-static void
-iomap_read_end_io(struct bio *bio)
-{
-       int error = blk_status_to_errno(bio->bi_status);
-       struct bio_vec *bvec;
-       struct bvec_iter_all iter_all;
-
-       bio_for_each_segment_all(bvec, bio, iter_all)
-               iomap_read_page_end_io(bvec, error);
-       bio_put(bio);
-}
-
-struct iomap_readpage_ctx {
-       struct page             *cur_page;
-       bool                    cur_page_in_bio;
-       bool                    is_readahead;
-       struct bio              *bio;
-       struct list_head        *pages;
-};
-
-static void
-iomap_read_inline_data(struct inode *inode, struct page *page,
-               struct iomap *iomap)
-{
-       size_t size = i_size_read(inode);
-       void *addr;
-
-       if (PageUptodate(page))
-               return;
-
-       BUG_ON(page->index);
-       BUG_ON(size > PAGE_SIZE - offset_in_page(iomap->inline_data));
-
-       addr = kmap_atomic(page);
-       memcpy(addr, iomap->inline_data, size);
-       memset(addr + size, 0, PAGE_SIZE - size);
-       kunmap_atomic(addr);
-       SetPageUptodate(page);
-}
-
-static loff_t
-iomap_readpage_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
-               struct iomap *iomap)
-{
-       struct iomap_readpage_ctx *ctx = data;
-       struct page *page = ctx->cur_page;
-       struct iomap_page *iop = iomap_page_create(inode, page);
-       bool same_page = false, is_contig = false;
-       loff_t orig_pos = pos;
-       unsigned poff, plen;
-       sector_t sector;
-
-       if (iomap->type == IOMAP_INLINE) {
-               WARN_ON_ONCE(pos);
-               iomap_read_inline_data(inode, page, iomap);
-               return PAGE_SIZE;
-       }
-
-       /* zero post-eof blocks as the page may be mapped */
-       iomap_adjust_read_range(inode, iop, &pos, length, &poff, &plen);
-       if (plen == 0)
-               goto done;
-
-       if (iomap->type != IOMAP_MAPPED || pos >= i_size_read(inode)) {
-               zero_user(page, poff, plen);
-               iomap_set_range_uptodate(page, poff, plen);
-               goto done;
-       }
-
-       ctx->cur_page_in_bio = true;
-
-       /*
-        * Try to merge into a previous segment if we can.
-        */
-       sector = iomap_sector(iomap, pos);
-       if (ctx->bio && bio_end_sector(ctx->bio) == sector)
-               is_contig = true;
-
-       if (is_contig &&
-           __bio_try_merge_page(ctx->bio, page, plen, poff, &same_page)) {
-               if (!same_page && iop)
-                       atomic_inc(&iop->read_count);
-               goto done;
-       }
-
-       /*
-        * If we start a new segment we need to increase the read count, and we
-        * need to do so before submitting any previous full bio to make sure
-        * that we don't prematurely unlock the page.
-        */
-       if (iop)
-               atomic_inc(&iop->read_count);
-
-       if (!ctx->bio || !is_contig || bio_full(ctx->bio, plen)) {
-               gfp_t gfp = mapping_gfp_constraint(page->mapping, GFP_KERNEL);
-               int nr_vecs = (length + PAGE_SIZE - 1) >> PAGE_SHIFT;
-
-               if (ctx->bio)
-                       submit_bio(ctx->bio);
-
-               if (ctx->is_readahead) /* same as readahead_gfp_mask */
-                       gfp |= __GFP_NORETRY | __GFP_NOWARN;
-               ctx->bio = bio_alloc(gfp, min(BIO_MAX_PAGES, nr_vecs));
-               ctx->bio->bi_opf = REQ_OP_READ;
-               if (ctx->is_readahead)
-                       ctx->bio->bi_opf |= REQ_RAHEAD;
-               ctx->bio->bi_iter.bi_sector = sector;
-               bio_set_dev(ctx->bio, iomap->bdev);
-               ctx->bio->bi_end_io = iomap_read_end_io;
-       }
-
-       bio_add_page(ctx->bio, page, plen, poff);
-done:
-       /*
-        * Move the caller beyond our range so that it keeps making progress.
-        * For that we have to include any leading non-uptodate ranges, but
-        * we can skip trailing ones as they will be handled in the next
-        * iteration.
-        */
-       return pos - orig_pos + plen;
-}
-
-int
-iomap_readpage(struct page *page, const struct iomap_ops *ops)
-{
-       struct iomap_readpage_ctx ctx = { .cur_page = page };
-       struct inode *inode = page->mapping->host;
-       unsigned poff;
-       loff_t ret;
-
-       for (poff = 0; poff < PAGE_SIZE; poff += ret) {
-               ret = iomap_apply(inode, page_offset(page) + poff,
-                               PAGE_SIZE - poff, 0, ops, &ctx,
-                               iomap_readpage_actor);
-               if (ret <= 0) {
-                       WARN_ON_ONCE(ret == 0);
-                       SetPageError(page);
-                       break;
-               }
-       }
-
-       if (ctx.bio) {
-               submit_bio(ctx.bio);
-               WARN_ON_ONCE(!ctx.cur_page_in_bio);
-       } else {
-               WARN_ON_ONCE(ctx.cur_page_in_bio);
-               unlock_page(page);
-       }
-
-       /*
-        * Just like mpage_readpages and block_read_full_page we always
-        * return 0 and just mark the page as PageError on errors.  This
-        * should be cleaned up all through the stack eventually.
-        */
-       return 0;
-}
-EXPORT_SYMBOL_GPL(iomap_readpage);
-
-static struct page *
-iomap_next_page(struct inode *inode, struct list_head *pages, loff_t pos,
-               loff_t length, loff_t *done)
-{
-       while (!list_empty(pages)) {
-               struct page *page = lru_to_page(pages);
-
-               if (page_offset(page) >= (u64)pos + length)
-                       break;
-
-               list_del(&page->lru);
-               if (!add_to_page_cache_lru(page, inode->i_mapping, page->index,
-                               GFP_NOFS))
-                       return page;
-
-               /*
-                * If we already have a page in the page cache at index we are
-                * done.  Upper layers don't care if it is uptodate after the
-                * readpages call itself as every page gets checked again once
-                * actually needed.
-                */
-               *done += PAGE_SIZE;
-               put_page(page);
-       }
-
-       return NULL;
-}
-
-static loff_t
-iomap_readpages_actor(struct inode *inode, loff_t pos, loff_t length,
-               void *data, struct iomap *iomap)
-{
-       struct iomap_readpage_ctx *ctx = data;
-       loff_t done, ret;
-
-       for (done = 0; done < length; done += ret) {
-               if (ctx->cur_page && offset_in_page(pos + done) == 0) {
-                       if (!ctx->cur_page_in_bio)
-                               unlock_page(ctx->cur_page);
-                       put_page(ctx->cur_page);
-                       ctx->cur_page = NULL;
-               }
-               if (!ctx->cur_page) {
-                       ctx->cur_page = iomap_next_page(inode, ctx->pages,
-                                       pos, length, &done);
-                       if (!ctx->cur_page)
-                               break;
-                       ctx->cur_page_in_bio = false;
-               }
-               ret = iomap_readpage_actor(inode, pos + done, length - done,
-                               ctx, iomap);
-       }
-
-       return done;
-}
-
-int
-iomap_readpages(struct address_space *mapping, struct list_head *pages,
-               unsigned nr_pages, const struct iomap_ops *ops)
-{
-       struct iomap_readpage_ctx ctx = {
-               .pages          = pages,
-               .is_readahead   = true,
-       };
-       loff_t pos = page_offset(list_entry(pages->prev, struct page, lru));
-       loff_t last = page_offset(list_entry(pages->next, struct page, lru));
-       loff_t length = last - pos + PAGE_SIZE, ret = 0;
-
-       while (length > 0) {
-               ret = iomap_apply(mapping->host, pos, length, 0, ops,
-                               &ctx, iomap_readpages_actor);
-               if (ret <= 0) {
-                       WARN_ON_ONCE(ret == 0);
-                       goto done;
-               }
-               pos += ret;
-               length -= ret;
-       }
-       ret = 0;
-done:
-       if (ctx.bio)
-               submit_bio(ctx.bio);
-       if (ctx.cur_page) {
-               if (!ctx.cur_page_in_bio)
-                       unlock_page(ctx.cur_page);
-               put_page(ctx.cur_page);
-       }
-
-       /*
-        * Check that we didn't lose a page due to the arcance calling
-        * conventions..
-        */
-       WARN_ON_ONCE(!ret && !list_empty(ctx.pages));
-       return ret;
-}
-EXPORT_SYMBOL_GPL(iomap_readpages);
-
-/*
- * iomap_is_partially_uptodate checks whether blocks within a page are
- * uptodate or not.
- *
- * Returns true if all blocks which correspond to a file portion
- * we want to read within the page are uptodate.
- */
-int
-iomap_is_partially_uptodate(struct page *page, unsigned long from,
-               unsigned long count)
-{
-       struct iomap_page *iop = to_iomap_page(page);
-       struct inode *inode = page->mapping->host;
-       unsigned len, first, last;
-       unsigned i;
-
-       /* Limit range to one page */
-       len = min_t(unsigned, PAGE_SIZE - from, count);
-
-       /* First and last blocks in range within page */
-       first = from >> inode->i_blkbits;
-       last = (from + len - 1) >> inode->i_blkbits;
-
-       if (iop) {
-               for (i = first; i <= last; i++)
-                       if (!test_bit(i, iop->uptodate))
-                               return 0;
-               return 1;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(iomap_is_partially_uptodate);
-
-int
-iomap_releasepage(struct page *page, gfp_t gfp_mask)
-{
-       /*
-        * mm accommodates an old ext3 case where clean pages might not have had
-        * the dirty bit cleared. Thus, it can send actual dirty pages to
-        * ->releasepage() via shrink_active_list(), skip those here.
-        */
-       if (PageDirty(page) || PageWriteback(page))
-               return 0;
-       iomap_page_release(page);
-       return 1;
-}
-EXPORT_SYMBOL_GPL(iomap_releasepage);
-
-void
-iomap_invalidatepage(struct page *page, unsigned int offset, unsigned int len)
-{
-       /*
-        * If we are invalidating the entire page, clear the dirty state from it
-        * and release it to avoid unnecessary buildup of the LRU.
-        */
-       if (offset == 0 && len == PAGE_SIZE) {
-               WARN_ON_ONCE(PageWriteback(page));
-               cancel_dirty_page(page);
-               iomap_page_release(page);
-       }
-}
-EXPORT_SYMBOL_GPL(iomap_invalidatepage);
-
-#ifdef CONFIG_MIGRATION
-int
-iomap_migrate_page(struct address_space *mapping, struct page *newpage,
-               struct page *page, enum migrate_mode mode)
-{
-       int ret;
-
-       ret = migrate_page_move_mapping(mapping, newpage, page, mode, 0);
-       if (ret != MIGRATEPAGE_SUCCESS)
-               return ret;
-
-       if (page_has_private(page)) {
-               ClearPagePrivate(page);
-               get_page(newpage);
-               set_page_private(newpage, page_private(page));
-               set_page_private(page, 0);
-               put_page(page);
-               SetPagePrivate(newpage);
-       }
-
-       if (mode != MIGRATE_SYNC_NO_COPY)
-               migrate_page_copy(newpage, page);
-       else
-               migrate_page_states(newpage, page);
-       return MIGRATEPAGE_SUCCESS;
-}
-EXPORT_SYMBOL_GPL(iomap_migrate_page);
-#endif /* CONFIG_MIGRATION */
-
-static void
-iomap_write_failed(struct inode *inode, loff_t pos, unsigned len)
-{
-       loff_t i_size = i_size_read(inode);
-
-       /*
-        * Only truncate newly allocated pages beyoned EOF, even if the
-        * write started inside the existing inode size.
-        */
-       if (pos + len > i_size)
-               truncate_pagecache_range(inode, max(pos, i_size), pos + len);
-}
-
-static int
-iomap_read_page_sync(struct inode *inode, loff_t block_start, struct page *page,
-               unsigned poff, unsigned plen, unsigned from, unsigned to,
-               struct iomap *iomap)
-{
-       struct bio_vec bvec;
-       struct bio bio;
-
-       if (iomap->type != IOMAP_MAPPED || block_start >= i_size_read(inode)) {
-               zero_user_segments(page, poff, from, to, poff + plen);
-               iomap_set_range_uptodate(page, poff, plen);
-               return 0;
-       }
-
-       bio_init(&bio, &bvec, 1);
-       bio.bi_opf = REQ_OP_READ;
-       bio.bi_iter.bi_sector = iomap_sector(iomap, block_start);
-       bio_set_dev(&bio, iomap->bdev);
-       __bio_add_page(&bio, page, plen, poff);
-       return submit_bio_wait(&bio);
-}
-
-static int
-__iomap_write_begin(struct inode *inode, loff_t pos, unsigned len,
-               struct page *page, struct iomap *iomap)
-{
-       struct iomap_page *iop = iomap_page_create(inode, page);
-       loff_t block_size = i_blocksize(inode);
-       loff_t block_start = pos & ~(block_size - 1);
-       loff_t block_end = (pos + len + block_size - 1) & ~(block_size - 1);
-       unsigned from = offset_in_page(pos), to = from + len, poff, plen;
-       int status = 0;
-
-       if (PageUptodate(page))
-               return 0;
-
-       do {
-               iomap_adjust_read_range(inode, iop, &block_start,
-                               block_end - block_start, &poff, &plen);
-               if (plen == 0)
-                       break;
-
-               if ((from > poff && from < poff + plen) ||
-                   (to > poff && to < poff + plen)) {
-                       status = iomap_read_page_sync(inode, block_start, page,
-                                       poff, plen, from, to, iomap);
-                       if (status)
-                               break;
-               }
-
-       } while ((block_start += plen) < block_end);
-
-       return status;
-}
-
-static int
-iomap_write_begin(struct inode *inode, loff_t pos, unsigned len, unsigned flags,
-               struct page **pagep, struct iomap *iomap)
-{
-       const struct iomap_page_ops *page_ops = iomap->page_ops;
-       pgoff_t index = pos >> PAGE_SHIFT;
-       struct page *page;
-       int status = 0;
-
-       BUG_ON(pos + len > iomap->offset + iomap->length);
-
-       if (fatal_signal_pending(current))
-               return -EINTR;
-
-       if (page_ops && page_ops->page_prepare) {
-               status = page_ops->page_prepare(inode, pos, len, iomap);
-               if (status)
-                       return status;
-       }
-
-       page = grab_cache_page_write_begin(inode->i_mapping, index, flags);
-       if (!page) {
-               status = -ENOMEM;
-               goto out_no_page;
-       }
-
-       if (iomap->type == IOMAP_INLINE)
-               iomap_read_inline_data(inode, page, iomap);
-       else if (iomap->flags & IOMAP_F_BUFFER_HEAD)
-               status = __block_write_begin_int(page, pos, len, NULL, iomap);
-       else
-               status = __iomap_write_begin(inode, pos, len, page, iomap);
-
-       if (unlikely(status))
-               goto out_unlock;
-
-       *pagep = page;
-       return 0;
-
-out_unlock:
-       unlock_page(page);
-       put_page(page);
-       iomap_write_failed(inode, pos, len);
-
-out_no_page:
-       if (page_ops && page_ops->page_done)
-               page_ops->page_done(inode, pos, 0, NULL, iomap);
-       return status;
-}
-
-int
-iomap_set_page_dirty(struct page *page)
-{
-       struct address_space *mapping = page_mapping(page);
-       int newly_dirty;
-
-       if (unlikely(!mapping))
-               return !TestSetPageDirty(page);
-
-       /*
-        * Lock out page->mem_cgroup migration to keep PageDirty
-        * synchronized with per-memcg dirty page counters.
-        */
-       lock_page_memcg(page);
-       newly_dirty = !TestSetPageDirty(page);
-       if (newly_dirty)
-               __set_page_dirty(page, mapping, 0);
-       unlock_page_memcg(page);
-
-       if (newly_dirty)
-               __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
-       return newly_dirty;
-}
-EXPORT_SYMBOL_GPL(iomap_set_page_dirty);
-
-static int
-__iomap_write_end(struct inode *inode, loff_t pos, unsigned len,
-               unsigned copied, struct page *page, struct iomap *iomap)
-{
-       flush_dcache_page(page);
-
-       /*
-        * The blocks that were entirely written will now be uptodate, so we
-        * don't have to worry about a readpage reading them and overwriting a
-        * partial write.  However if we have encountered a short write and only
-        * partially written into a block, it will not be marked uptodate, so a
-        * readpage might come in and destroy our partial write.
-        *
-        * Do the simplest thing, and just treat any short write to a non
-        * uptodate page as a zero-length write, and force the caller to redo
-        * the whole thing.
-        */
-       if (unlikely(copied < len && !PageUptodate(page)))
-               return 0;
-       iomap_set_range_uptodate(page, offset_in_page(pos), len);
-       iomap_set_page_dirty(page);
-       return copied;
-}
-
-static int
-iomap_write_end_inline(struct inode *inode, struct page *page,
-               struct iomap *iomap, loff_t pos, unsigned copied)
-{
-       void *addr;
-
-       WARN_ON_ONCE(!PageUptodate(page));
-       BUG_ON(pos + copied > PAGE_SIZE - offset_in_page(iomap->inline_data));
-
-       addr = kmap_atomic(page);
-       memcpy(iomap->inline_data + pos, addr + pos, copied);
-       kunmap_atomic(addr);
-
-       mark_inode_dirty(inode);
-       return copied;
-}
-
-static int
-iomap_write_end(struct inode *inode, loff_t pos, unsigned len,
-               unsigned copied, struct page *page, struct iomap *iomap)
-{
-       const struct iomap_page_ops *page_ops = iomap->page_ops;
-       loff_t old_size = inode->i_size;
-       int ret;
-
-       if (iomap->type == IOMAP_INLINE) {
-               ret = iomap_write_end_inline(inode, page, iomap, pos, copied);
-       } else if (iomap->flags & IOMAP_F_BUFFER_HEAD) {
-               ret = block_write_end(NULL, inode->i_mapping, pos, len, copied,
-                               page, NULL);
-       } else {
-               ret = __iomap_write_end(inode, pos, len, copied, page, iomap);
-       }
-
-       /*
-        * Update the in-memory inode size after copying the data into the page
-        * cache.  It's up to the file system to write the updated size to disk,
-        * preferably after I/O completion so that no stale data is exposed.
-        */
-       if (pos + ret > old_size) {
-               i_size_write(inode, pos + ret);
-               iomap->flags |= IOMAP_F_SIZE_CHANGED;
-       }
-       unlock_page(page);
-
-       if (old_size < pos)
-               pagecache_isize_extended(inode, old_size, pos);
-       if (page_ops && page_ops->page_done)
-               page_ops->page_done(inode, pos, ret, page, iomap);
-       put_page(page);
-
-       if (ret < len)
-               iomap_write_failed(inode, pos, len);
-       return ret;
-}
-
-static loff_t
-iomap_write_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
-               struct iomap *iomap)
-{
-       struct iov_iter *i = data;
-       long status = 0;
-       ssize_t written = 0;
-       unsigned int flags = AOP_FLAG_NOFS;
-
-       do {
-               struct page *page;
-               unsigned long offset;   /* Offset into pagecache page */
-               unsigned long bytes;    /* Bytes to write to page */
-               size_t copied;          /* Bytes copied from user */
-
-               offset = offset_in_page(pos);
-               bytes = min_t(unsigned long, PAGE_SIZE - offset,
-                                               iov_iter_count(i));
-again:
-               if (bytes > length)
-                       bytes = length;
-
-               /*
-                * Bring in the user page that we will copy from _first_.
-                * Otherwise there's a nasty deadlock on copying from the
-                * same page as we're writing to, without it being marked
-                * up-to-date.
-                *
-                * Not only is this an optimisation, but it is also required
-                * to check that the address is actually valid, when atomic
-                * usercopies are used, below.
-                */
-               if (unlikely(iov_iter_fault_in_readable(i, bytes))) {
-                       status = -EFAULT;
-                       break;
-               }
-
-               status = iomap_write_begin(inode, pos, bytes, flags, &page,
-                               iomap);
-               if (unlikely(status))
-                       break;
-
-               if (mapping_writably_mapped(inode->i_mapping))
-                       flush_dcache_page(page);
-
-               copied = iov_iter_copy_from_user_atomic(page, i, offset, bytes);
-
-               flush_dcache_page(page);
-
-               status = iomap_write_end(inode, pos, bytes, copied, page,
-                               iomap);
-               if (unlikely(status < 0))
-                       break;
-               copied = status;
-
-               cond_resched();
-
-               iov_iter_advance(i, copied);
-               if (unlikely(copied == 0)) {
-                       /*
-                        * If we were unable to copy any data at all, we must
-                        * fall back to a single segment length write.
-                        *
-                        * If we didn't fallback here, we could livelock
-                        * because not all segments in the iov can be copied at
-                        * once without a pagefault.
-                        */
-                       bytes = min_t(unsigned long, PAGE_SIZE - offset,
-                                               iov_iter_single_seg_count(i));
-                       goto again;
-               }
-               pos += copied;
-               written += copied;
-               length -= copied;
-
-               balance_dirty_pages_ratelimited(inode->i_mapping);
-       } while (iov_iter_count(i) && length);
-
-       return written ? written : status;
-}
-
-ssize_t
-iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *iter,
-               const struct iomap_ops *ops)
-{
-       struct inode *inode = iocb->ki_filp->f_mapping->host;
-       loff_t pos = iocb->ki_pos, ret = 0, written = 0;
-
-       while (iov_iter_count(iter)) {
-               ret = iomap_apply(inode, pos, iov_iter_count(iter),
-                               IOMAP_WRITE, ops, iter, iomap_write_actor);
-               if (ret <= 0)
-                       break;
-               pos += ret;
-               written += ret;
-       }
-
-       return written ? written : ret;
-}
-EXPORT_SYMBOL_GPL(iomap_file_buffered_write);
-
-static struct page *
-__iomap_read_page(struct inode *inode, loff_t offset)
-{
-       struct address_space *mapping = inode->i_mapping;
-       struct page *page;
-
-       page = read_mapping_page(mapping, offset >> PAGE_SHIFT, NULL);
-       if (IS_ERR(page))
-               return page;
-       if (!PageUptodate(page)) {
-               put_page(page);
-               return ERR_PTR(-EIO);
-       }
-       return page;
-}
-
-static loff_t
-iomap_dirty_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
-               struct iomap *iomap)
-{
-       long status = 0;
-       ssize_t written = 0;
-
-       do {
-               struct page *page, *rpage;
-               unsigned long offset;   /* Offset into pagecache page */
-               unsigned long bytes;    /* Bytes to write to page */
-
-               offset = offset_in_page(pos);
-               bytes = min_t(loff_t, PAGE_SIZE - offset, length);
-
-               rpage = __iomap_read_page(inode, pos);
-               if (IS_ERR(rpage))
-                       return PTR_ERR(rpage);
-
-               status = iomap_write_begin(inode, pos, bytes,
-                                          AOP_FLAG_NOFS, &page, iomap);
-               put_page(rpage);
-               if (unlikely(status))
-                       return status;
-
-               WARN_ON_ONCE(!PageUptodate(page));
-
-               status = iomap_write_end(inode, pos, bytes, bytes, page, iomap);
-               if (unlikely(status <= 0)) {
-                       if (WARN_ON_ONCE(status == 0))
-                               return -EIO;
-                       return status;
-               }
-
-               cond_resched();
-
-               pos += status;
-               written += status;
-               length -= status;
-
-               balance_dirty_pages_ratelimited(inode->i_mapping);
-       } while (length);
-
-       return written;
-}
-
-int
-iomap_file_dirty(struct inode *inode, loff_t pos, loff_t len,
-               const struct iomap_ops *ops)
-{
-       loff_t ret;
-
-       while (len) {
-               ret = iomap_apply(inode, pos, len, IOMAP_WRITE, ops, NULL,
-                               iomap_dirty_actor);
-               if (ret <= 0)
-                       return ret;
-               pos += ret;
-               len -= ret;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(iomap_file_dirty);
-
-static int iomap_zero(struct inode *inode, loff_t pos, unsigned offset,
-               unsigned bytes, struct iomap *iomap)
-{
-       struct page *page;
-       int status;
-
-       status = iomap_write_begin(inode, pos, bytes, AOP_FLAG_NOFS, &page,
-                                  iomap);
-       if (status)
-               return status;
-
-       zero_user(page, offset, bytes);
-       mark_page_accessed(page);
-
-       return iomap_write_end(inode, pos, bytes, bytes, page, iomap);
-}
-
-static int iomap_dax_zero(loff_t pos, unsigned offset, unsigned bytes,
-               struct iomap *iomap)
-{
-       return __dax_zero_page_range(iomap->bdev, iomap->dax_dev,
-                       iomap_sector(iomap, pos & PAGE_MASK), offset, bytes);
-}
-
-static loff_t
-iomap_zero_range_actor(struct inode *inode, loff_t pos, loff_t count,
-               void *data, struct iomap *iomap)
-{
-       bool *did_zero = data;
-       loff_t written = 0;
-       int status;
-
-       /* already zeroed?  we're done. */
-       if (iomap->type == IOMAP_HOLE || iomap->type == IOMAP_UNWRITTEN)
-               return count;
-
-       do {
-               unsigned offset, bytes;
-
-               offset = offset_in_page(pos);
-               bytes = min_t(loff_t, PAGE_SIZE - offset, count);
-
-               if (IS_DAX(inode))
-                       status = iomap_dax_zero(pos, offset, bytes, iomap);
-               else
-                       status = iomap_zero(inode, pos, offset, bytes, iomap);
-               if (status < 0)
-                       return status;
-
-               pos += bytes;
-               count -= bytes;
-               written += bytes;
-               if (did_zero)
-                       *did_zero = true;
-       } while (count > 0);
-
-       return written;
-}
-
-int
-iomap_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero,
-               const struct iomap_ops *ops)
-{
-       loff_t ret;
-
-       while (len > 0) {
-               ret = iomap_apply(inode, pos, len, IOMAP_ZERO,
-                               ops, did_zero, iomap_zero_range_actor);
-               if (ret <= 0)
-                       return ret;
-
-               pos += ret;
-               len -= ret;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(iomap_zero_range);
-
-int
-iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero,
-               const struct iomap_ops *ops)
-{
-       unsigned int blocksize = i_blocksize(inode);
-       unsigned int off = pos & (blocksize - 1);
-
-       /* Block boundary? Nothing to do */
-       if (!off)
-               return 0;
-       return iomap_zero_range(inode, pos, blocksize - off, did_zero, ops);
-}
-EXPORT_SYMBOL_GPL(iomap_truncate_page);
-
-static loff_t
-iomap_page_mkwrite_actor(struct inode *inode, loff_t pos, loff_t length,
-               void *data, struct iomap *iomap)
-{
-       struct page *page = data;
-       int ret;
-
-       if (iomap->flags & IOMAP_F_BUFFER_HEAD) {
-               ret = __block_write_begin_int(page, pos, length, NULL, iomap);
-               if (ret)
-                       return ret;
-               block_commit_write(page, 0, length);
-       } else {
-               WARN_ON_ONCE(!PageUptodate(page));
-               iomap_page_create(inode, page);
-               set_page_dirty(page);
-       }
-
-       return length;
-}
-
-vm_fault_t iomap_page_mkwrite(struct vm_fault *vmf, const struct iomap_ops *ops)
-{
-       struct page *page = vmf->page;
-       struct inode *inode = file_inode(vmf->vma->vm_file);
-       unsigned long length;
-       loff_t offset, size;
-       ssize_t ret;
-
-       lock_page(page);
-       size = i_size_read(inode);
-       if ((page->mapping != inode->i_mapping) ||
-           (page_offset(page) > size)) {
-               /* We overload EFAULT to mean page got truncated */
-               ret = -EFAULT;
-               goto out_unlock;
-       }
-
-       /* page is wholly or partially inside EOF */
-       if (((page->index + 1) << PAGE_SHIFT) > size)
-               length = offset_in_page(size);
-       else
-               length = PAGE_SIZE;
-
-       offset = page_offset(page);
-       while (length > 0) {
-               ret = iomap_apply(inode, offset, length,
-                               IOMAP_WRITE | IOMAP_FAULT, ops, page,
-                               iomap_page_mkwrite_actor);
-               if (unlikely(ret <= 0))
-                       goto out_unlock;
-               offset += ret;
-               length -= ret;
-       }
-
-       wait_for_stable_page(page);
-       return VM_FAULT_LOCKED;
-out_unlock:
-       unlock_page(page);
-       return block_page_mkwrite_return(ret);
-}
-EXPORT_SYMBOL_GPL(iomap_page_mkwrite);
-
-struct fiemap_ctx {
-       struct fiemap_extent_info *fi;
-       struct iomap prev;
-};
-
-static int iomap_to_fiemap(struct fiemap_extent_info *fi,
-               struct iomap *iomap, u32 flags)
-{
-       switch (iomap->type) {
-       case IOMAP_HOLE:
-               /* skip holes */
-               return 0;
-       case IOMAP_DELALLOC:
-               flags |= FIEMAP_EXTENT_DELALLOC | FIEMAP_EXTENT_UNKNOWN;
-               break;
-       case IOMAP_MAPPED:
-               break;
-       case IOMAP_UNWRITTEN:
-               flags |= FIEMAP_EXTENT_UNWRITTEN;
-               break;
-       case IOMAP_INLINE:
-               flags |= FIEMAP_EXTENT_DATA_INLINE;
-               break;
-       }
-
-       if (iomap->flags & IOMAP_F_MERGED)
-               flags |= FIEMAP_EXTENT_MERGED;
-       if (iomap->flags & IOMAP_F_SHARED)
-               flags |= FIEMAP_EXTENT_SHARED;
-
-       return fiemap_fill_next_extent(fi, iomap->offset,
-                       iomap->addr != IOMAP_NULL_ADDR ? iomap->addr : 0,
-                       iomap->length, flags);
-}
-
-static loff_t
-iomap_fiemap_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
-               struct iomap *iomap)
-{
-       struct fiemap_ctx *ctx = data;
-       loff_t ret = length;
-
-       if (iomap->type == IOMAP_HOLE)
-               return length;
-
-       ret = iomap_to_fiemap(ctx->fi, &ctx->prev, 0);
-       ctx->prev = *iomap;
-       switch (ret) {
-       case 0:         /* success */
-               return length;
-       case 1:         /* extent array full */
-               return 0;
-       default:
-               return ret;
-       }
-}
-
-int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi,
-               loff_t start, loff_t len, const struct iomap_ops *ops)
-{
-       struct fiemap_ctx ctx;
-       loff_t ret;
-
-       memset(&ctx, 0, sizeof(ctx));
-       ctx.fi = fi;
-       ctx.prev.type = IOMAP_HOLE;
-
-       ret = fiemap_check_flags(fi, FIEMAP_FLAG_SYNC);
-       if (ret)
-               return ret;
-
-       if (fi->fi_flags & FIEMAP_FLAG_SYNC) {
-               ret = filemap_write_and_wait(inode->i_mapping);
-               if (ret)
-                       return ret;
-       }
-
-       while (len > 0) {
-               ret = iomap_apply(inode, start, len, IOMAP_REPORT, ops, &ctx,
-                               iomap_fiemap_actor);
-               /* inode with no (attribute) mapping will give ENOENT */
-               if (ret == -ENOENT)
-                       break;
-               if (ret < 0)
-                       return ret;
-               if (ret == 0)
-                       break;
-
-               start += ret;
-               len -= ret;
-       }
-
-       if (ctx.prev.type != IOMAP_HOLE) {
-               ret = iomap_to_fiemap(fi, &ctx.prev, FIEMAP_EXTENT_LAST);
-               if (ret < 0)
-                       return ret;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(iomap_fiemap);
-
-/*
- * Seek for SEEK_DATA / SEEK_HOLE within @page, starting at @lastoff.
- * Returns true if found and updates @lastoff to the offset in file.
- */
-static bool
-page_seek_hole_data(struct inode *inode, struct page *page, loff_t *lastoff,
-               int whence)
-{
-       const struct address_space_operations *ops = inode->i_mapping->a_ops;
-       unsigned int bsize = i_blocksize(inode), off;
-       bool seek_data = whence == SEEK_DATA;
-       loff_t poff = page_offset(page);
-
-       if (WARN_ON_ONCE(*lastoff >= poff + PAGE_SIZE))
-               return false;
-
-       if (*lastoff < poff) {
-               /*
-                * Last offset smaller than the start of the page means we found
-                * a hole:
-                */
-               if (whence == SEEK_HOLE)
-                       return true;
-               *lastoff = poff;
-       }
-
-       /*
-        * Just check the page unless we can and should check block ranges:
-        */
-       if (bsize == PAGE_SIZE || !ops->is_partially_uptodate)
-               return PageUptodate(page) == seek_data;
-
-       lock_page(page);
-       if (unlikely(page->mapping != inode->i_mapping))
-               goto out_unlock_not_found;
-
-       for (off = 0; off < PAGE_SIZE; off += bsize) {
-               if (offset_in_page(*lastoff) >= off + bsize)
-                       continue;
-               if (ops->is_partially_uptodate(page, off, bsize) == seek_data) {
-                       unlock_page(page);
-                       return true;
-               }
-               *lastoff = poff + off + bsize;
-       }
-
-out_unlock_not_found:
-       unlock_page(page);
-       return false;
-}
-
-/*
- * Seek for SEEK_DATA / SEEK_HOLE in the page cache.
- *
- * Within unwritten extents, the page cache determines which parts are holes
- * and which are data: uptodate buffer heads count as data; everything else
- * counts as a hole.
- *
- * Returns the resulting offset on successs, and -ENOENT otherwise.
- */
-static loff_t
-page_cache_seek_hole_data(struct inode *inode, loff_t offset, loff_t length,
-               int whence)
-{
-       pgoff_t index = offset >> PAGE_SHIFT;
-       pgoff_t end = DIV_ROUND_UP(offset + length, PAGE_SIZE);
-       loff_t lastoff = offset;
-       struct pagevec pvec;
-
-       if (length <= 0)
-               return -ENOENT;
-
-       pagevec_init(&pvec);
-
-       do {
-               unsigned nr_pages, i;
-
-               nr_pages = pagevec_lookup_range(&pvec, inode->i_mapping, &index,
-                                               end - 1);
-               if (nr_pages == 0)
-                       break;
-
-               for (i = 0; i < nr_pages; i++) {
-                       struct page *page = pvec.pages[i];
-
-                       if (page_seek_hole_data(inode, page, &lastoff, whence))
-                               goto check_range;
-                       lastoff = page_offset(page) + PAGE_SIZE;
-               }
-               pagevec_release(&pvec);
-       } while (index < end);
-
-       /* When no page at lastoff and we are not done, we found a hole. */
-       if (whence != SEEK_HOLE)
-               goto not_found;
-
-check_range:
-       if (lastoff < offset + length)
-               goto out;
-not_found:
-       lastoff = -ENOENT;
-out:
-       pagevec_release(&pvec);
-       return lastoff;
-}
-
-
-static loff_t
-iomap_seek_hole_actor(struct inode *inode, loff_t offset, loff_t length,
-                     void *data, struct iomap *iomap)
-{
-       switch (iomap->type) {
-       case IOMAP_UNWRITTEN:
-               offset = page_cache_seek_hole_data(inode, offset, length,
-                                                  SEEK_HOLE);
-               if (offset < 0)
-                       return length;
-               /* fall through */
-       case IOMAP_HOLE:
-               *(loff_t *)data = offset;
-               return 0;
-       default:
-               return length;
-       }
-}
-
-loff_t
-iomap_seek_hole(struct inode *inode, loff_t offset, const struct iomap_ops *ops)
-{
-       loff_t size = i_size_read(inode);
-       loff_t length = size - offset;
-       loff_t ret;
-
-       /* Nothing to be found before or beyond the end of the file. */
-       if (offset < 0 || offset >= size)
-               return -ENXIO;
-
-       while (length > 0) {
-               ret = iomap_apply(inode, offset, length, IOMAP_REPORT, ops,
-                                 &offset, iomap_seek_hole_actor);
-               if (ret < 0)
-                       return ret;
-               if (ret == 0)
-                       break;
-
-               offset += ret;
-               length -= ret;
-       }
-
-       return offset;
-}
-EXPORT_SYMBOL_GPL(iomap_seek_hole);
-
-static loff_t
-iomap_seek_data_actor(struct inode *inode, loff_t offset, loff_t length,
-                     void *data, struct iomap *iomap)
-{
-       switch (iomap->type) {
-       case IOMAP_HOLE:
-               return length;
-       case IOMAP_UNWRITTEN:
-               offset = page_cache_seek_hole_data(inode, offset, length,
-                                                  SEEK_DATA);
-               if (offset < 0)
-                       return length;
-               /*FALLTHRU*/
-       default:
-               *(loff_t *)data = offset;
-               return 0;
-       }
-}
-
-loff_t
-iomap_seek_data(struct inode *inode, loff_t offset, const struct iomap_ops *ops)
-{
-       loff_t size = i_size_read(inode);
-       loff_t length = size - offset;
-       loff_t ret;
-
-       /* Nothing to be found before or beyond the end of the file. */
-       if (offset < 0 || offset >= size)
-               return -ENXIO;
-
-       while (length > 0) {
-               ret = iomap_apply(inode, offset, length, IOMAP_REPORT, ops,
-                                 &offset, iomap_seek_data_actor);
-               if (ret < 0)
-                       return ret;
-               if (ret == 0)
-                       break;
-
-               offset += ret;
-               length -= ret;
-       }
-
-       if (length <= 0)
-               return -ENXIO;
-       return offset;
-}
-EXPORT_SYMBOL_GPL(iomap_seek_data);
-
-/*
- * Private flags for iomap_dio, must not overlap with the public ones in
- * iomap.h:
- */
-#define IOMAP_DIO_WRITE_FUA    (1 << 28)
-#define IOMAP_DIO_NEED_SYNC    (1 << 29)
-#define IOMAP_DIO_WRITE                (1 << 30)
-#define IOMAP_DIO_DIRTY                (1 << 31)
-
-struct iomap_dio {
-       struct kiocb            *iocb;
-       iomap_dio_end_io_t      *end_io;
-       loff_t                  i_size;
-       loff_t                  size;
-       atomic_t                ref;
-       unsigned                flags;
-       int                     error;
-       bool                    wait_for_completion;
-
-       union {
-               /* used during submission and for synchronous completion: */
-               struct {
-                       struct iov_iter         *iter;
-                       struct task_struct      *waiter;
-                       struct request_queue    *last_queue;
-                       blk_qc_t                cookie;
-               } submit;
-
-               /* used for aio completion: */
-               struct {
-                       struct work_struct      work;
-               } aio;
-       };
-};
-
-int iomap_dio_iopoll(struct kiocb *kiocb, bool spin)
-{
-       struct request_queue *q = READ_ONCE(kiocb->private);
-
-       if (!q)
-               return 0;
-       return blk_poll(q, READ_ONCE(kiocb->ki_cookie), spin);
-}
-EXPORT_SYMBOL_GPL(iomap_dio_iopoll);
-
-static void iomap_dio_submit_bio(struct iomap_dio *dio, struct iomap *iomap,
-               struct bio *bio)
-{
-       atomic_inc(&dio->ref);
-
-       if (dio->iocb->ki_flags & IOCB_HIPRI)
-               bio_set_polled(bio, dio->iocb);
-
-       dio->submit.last_queue = bdev_get_queue(iomap->bdev);
-       dio->submit.cookie = submit_bio(bio);
-}
-
-static ssize_t iomap_dio_complete(struct iomap_dio *dio)
-{
-       struct kiocb *iocb = dio->iocb;
-       struct inode *inode = file_inode(iocb->ki_filp);
-       loff_t offset = iocb->ki_pos;
-       ssize_t ret;
-
-       if (dio->end_io) {
-               ret = dio->end_io(iocb,
-                               dio->error ? dio->error : dio->size,
-                               dio->flags);
-       } else {
-               ret = dio->error;
-       }
-
-       if (likely(!ret)) {
-               ret = dio->size;
-               /* check for short read */
-               if (offset + ret > dio->i_size &&
-                   !(dio->flags & IOMAP_DIO_WRITE))
-                       ret = dio->i_size - offset;
-               iocb->ki_pos += ret;
-       }
-
-       /*
-        * Try again to invalidate clean pages which might have been cached by
-        * non-direct readahead, or faulted in by get_user_pages() if the source
-        * of the write was an mmap'ed region of the file we're writing.  Either
-        * one is a pretty crazy thing to do, so we don't support it 100%.  If
-        * this invalidation fails, tough, the write still worked...
-        *
-        * And this page cache invalidation has to be after dio->end_io(), as
-        * some filesystems convert unwritten extents to real allocations in
-        * end_io() when necessary, otherwise a racing buffer read would cache
-        * zeros from unwritten extents.
-        */
-       if (!dio->error &&
-           (dio->flags & IOMAP_DIO_WRITE) && inode->i_mapping->nrpages) {
-               int err;
-               err = invalidate_inode_pages2_range(inode->i_mapping,
-                               offset >> PAGE_SHIFT,
-                               (offset + dio->size - 1) >> PAGE_SHIFT);
-               if (err)
-                       dio_warn_stale_pagecache(iocb->ki_filp);
-       }
-
-       /*
-        * If this is a DSYNC write, make sure we push it to stable storage now
-        * that we've written data.
-        */
-       if (ret > 0 && (dio->flags & IOMAP_DIO_NEED_SYNC))
-               ret = generic_write_sync(iocb, ret);
-
-       inode_dio_end(file_inode(iocb->ki_filp));
-       kfree(dio);
-
-       return ret;
-}
-
-static void iomap_dio_complete_work(struct work_struct *work)
-{
-       struct iomap_dio *dio = container_of(work, struct iomap_dio, aio.work);
-       struct kiocb *iocb = dio->iocb;
-
-       iocb->ki_complete(iocb, iomap_dio_complete(dio), 0);
-}
-
-/*
- * Set an error in the dio if none is set yet.  We have to use cmpxchg
- * as the submission context and the completion context(s) can race to
- * update the error.
- */
-static inline void iomap_dio_set_error(struct iomap_dio *dio, int ret)
-{
-       cmpxchg(&dio->error, 0, ret);
-}
-
-static void iomap_dio_bio_end_io(struct bio *bio)
-{
-       struct iomap_dio *dio = bio->bi_private;
-       bool should_dirty = (dio->flags & IOMAP_DIO_DIRTY);
-
-       if (bio->bi_status)
-               iomap_dio_set_error(dio, blk_status_to_errno(bio->bi_status));
-
-       if (atomic_dec_and_test(&dio->ref)) {
-               if (dio->wait_for_completion) {
-                       struct task_struct *waiter = dio->submit.waiter;
-                       WRITE_ONCE(dio->submit.waiter, NULL);
-                       blk_wake_io_task(waiter);
-               } else if (dio->flags & IOMAP_DIO_WRITE) {
-                       struct inode *inode = file_inode(dio->iocb->ki_filp);
-
-                       INIT_WORK(&dio->aio.work, iomap_dio_complete_work);
-                       queue_work(inode->i_sb->s_dio_done_wq, &dio->aio.work);
-               } else {
-                       iomap_dio_complete_work(&dio->aio.work);
-               }
-       }
-
-       if (should_dirty) {
-               bio_check_pages_dirty(bio);
-       } else {
-               bio_release_pages(bio, false);
-               bio_put(bio);
-       }
-}
-
-static void
-iomap_dio_zero(struct iomap_dio *dio, struct iomap *iomap, loff_t pos,
-               unsigned len)
-{
-       struct page *page = ZERO_PAGE(0);
-       int flags = REQ_SYNC | REQ_IDLE;
-       struct bio *bio;
-
-       bio = bio_alloc(GFP_KERNEL, 1);
-       bio_set_dev(bio, iomap->bdev);
-       bio->bi_iter.bi_sector = iomap_sector(iomap, pos);
-       bio->bi_private = dio;
-       bio->bi_end_io = iomap_dio_bio_end_io;
-
-       get_page(page);
-       __bio_add_page(bio, page, len, 0);
-       bio_set_op_attrs(bio, REQ_OP_WRITE, flags);
-       iomap_dio_submit_bio(dio, iomap, bio);
-}
-
-static loff_t
-iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length,
-               struct iomap_dio *dio, struct iomap *iomap)
-{
-       unsigned int blkbits = blksize_bits(bdev_logical_block_size(iomap->bdev));
-       unsigned int fs_block_size = i_blocksize(inode), pad;
-       unsigned int align = iov_iter_alignment(dio->submit.iter);
-       struct iov_iter iter;
-       struct bio *bio;
-       bool need_zeroout = false;
-       bool use_fua = false;
-       int nr_pages, ret = 0;
-       size_t copied = 0;
-
-       if ((pos | length | align) & ((1 << blkbits) - 1))
-               return -EINVAL;
-
-       if (iomap->type == IOMAP_UNWRITTEN) {
-               dio->flags |= IOMAP_DIO_UNWRITTEN;
-               need_zeroout = true;
-       }
-
-       if (iomap->flags & IOMAP_F_SHARED)
-               dio->flags |= IOMAP_DIO_COW;
-
-       if (iomap->flags & IOMAP_F_NEW) {
-               need_zeroout = true;
-       } else if (iomap->type == IOMAP_MAPPED) {
-               /*
-                * Use a FUA write if we need datasync semantics, this is a pure
-                * data IO that doesn't require any metadata updates (including
-                * after IO completion such as unwritten extent conversion) and
-                * the underlying device supports FUA. This allows us to avoid
-                * cache flushes on IO completion.
-                */
-               if (!(iomap->flags & (IOMAP_F_SHARED|IOMAP_F_DIRTY)) &&
-                   (dio->flags & IOMAP_DIO_WRITE_FUA) &&
-                   blk_queue_fua(bdev_get_queue(iomap->bdev)))
-                       use_fua = true;
-       }
-
-       /*
-        * Operate on a partial iter trimmed to the extent we were called for.
-        * We'll update the iter in the dio once we're done with this extent.
-        */
-       iter = *dio->submit.iter;
-       iov_iter_truncate(&iter, length);
-
-       nr_pages = iov_iter_npages(&iter, BIO_MAX_PAGES);
-       if (nr_pages <= 0)
-               return nr_pages;
-
-       if (need_zeroout) {
-               /* zero out from the start of the block to the write offset */
-               pad = pos & (fs_block_size - 1);
-               if (pad)
-                       iomap_dio_zero(dio, iomap, pos - pad, pad);
-       }
-
-       do {
-               size_t n;
-               if (dio->error) {
-                       iov_iter_revert(dio->submit.iter, copied);
-                       return 0;
-               }
-
-               bio = bio_alloc(GFP_KERNEL, nr_pages);
-               bio_set_dev(bio, iomap->bdev);
-               bio->bi_iter.bi_sector = iomap_sector(iomap, pos);
-               bio->bi_write_hint = dio->iocb->ki_hint;
-               bio->bi_ioprio = dio->iocb->ki_ioprio;
-               bio->bi_private = dio;
-               bio->bi_end_io = iomap_dio_bio_end_io;
-
-               ret = bio_iov_iter_get_pages(bio, &iter);
-               if (unlikely(ret)) {
-                       /*
-                        * We have to stop part way through an IO. We must fall
-                        * through to the sub-block tail zeroing here, otherwise
-                        * this short IO may expose stale data in the tail of
-                        * the block we haven't written data to.
-                        */
-                       bio_put(bio);
-                       goto zero_tail;
-               }
-
-               n = bio->bi_iter.bi_size;
-               if (dio->flags & IOMAP_DIO_WRITE) {
-                       bio->bi_opf = REQ_OP_WRITE | REQ_SYNC | REQ_IDLE;
-                       if (use_fua)
-                               bio->bi_opf |= REQ_FUA;
-                       else
-                               dio->flags &= ~IOMAP_DIO_WRITE_FUA;
-                       task_io_account_write(n);
-               } else {
-                       bio->bi_opf = REQ_OP_READ;
-                       if (dio->flags & IOMAP_DIO_DIRTY)
-                               bio_set_pages_dirty(bio);
-               }
-
-               iov_iter_advance(dio->submit.iter, n);
-
-               dio->size += n;
-               pos += n;
-               copied += n;
-
-               nr_pages = iov_iter_npages(&iter, BIO_MAX_PAGES);
-               iomap_dio_submit_bio(dio, iomap, bio);
-       } while (nr_pages);
-
-       /*
-        * We need to zeroout the tail of a sub-block write if the extent type
-        * requires zeroing or the write extends beyond EOF. If we don't zero
-        * the block tail in the latter case, we can expose stale data via mmap
-        * reads of the EOF block.
-        */
-zero_tail:
-       if (need_zeroout ||
-           ((dio->flags & IOMAP_DIO_WRITE) && pos >= i_size_read(inode))) {
-               /* zero out from the end of the write to the end of the block */
-               pad = pos & (fs_block_size - 1);
-               if (pad)
-                       iomap_dio_zero(dio, iomap, pos, fs_block_size - pad);
-       }
-       return copied ? copied : ret;
-}
-
-static loff_t
-iomap_dio_hole_actor(loff_t length, struct iomap_dio *dio)
-{
-       length = iov_iter_zero(length, dio->submit.iter);
-       dio->size += length;
-       return length;
-}
-
-static loff_t
-iomap_dio_inline_actor(struct inode *inode, loff_t pos, loff_t length,
-               struct iomap_dio *dio, struct iomap *iomap)
-{
-       struct iov_iter *iter = dio->submit.iter;
-       size_t copied;
-
-       BUG_ON(pos + length > PAGE_SIZE - offset_in_page(iomap->inline_data));
-
-       if (dio->flags & IOMAP_DIO_WRITE) {
-               loff_t size = inode->i_size;
-
-               if (pos > size)
-                       memset(iomap->inline_data + size, 0, pos - size);
-               copied = copy_from_iter(iomap->inline_data + pos, length, iter);
-               if (copied) {
-                       if (pos + copied > size)
-                               i_size_write(inode, pos + copied);
-                       mark_inode_dirty(inode);
-               }
-       } else {
-               copied = copy_to_iter(iomap->inline_data + pos, length, iter);
-       }
-       dio->size += copied;
-       return copied;
-}
-
-static loff_t
-iomap_dio_actor(struct inode *inode, loff_t pos, loff_t length,
-               void *data, struct iomap *iomap)
-{
-       struct iomap_dio *dio = data;
-
-       switch (iomap->type) {
-       case IOMAP_HOLE:
-               if (WARN_ON_ONCE(dio->flags & IOMAP_DIO_WRITE))
-                       return -EIO;
-               return iomap_dio_hole_actor(length, dio);
-       case IOMAP_UNWRITTEN:
-               if (!(dio->flags & IOMAP_DIO_WRITE))
-                       return iomap_dio_hole_actor(length, dio);
-               return iomap_dio_bio_actor(inode, pos, length, dio, iomap);
-       case IOMAP_MAPPED:
-               return iomap_dio_bio_actor(inode, pos, length, dio, iomap);
-       case IOMAP_INLINE:
-               return iomap_dio_inline_actor(inode, pos, length, dio, iomap);
-       default:
-               WARN_ON_ONCE(1);
-               return -EIO;
-       }
-}
-
-/*
- * iomap_dio_rw() always completes O_[D]SYNC writes regardless of whether the IO
- * is being issued as AIO or not.  This allows us to optimise pure data writes
- * to use REQ_FUA rather than requiring generic_write_sync() to issue a
- * REQ_FLUSH post write. This is slightly tricky because a single request here
- * can be mapped into multiple disjoint IOs and only a subset of the IOs issued
- * may be pure data writes. In that case, we still need to do a full data sync
- * completion.
- */
-ssize_t
-iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
-               const struct iomap_ops *ops, iomap_dio_end_io_t end_io)
-{
-       struct address_space *mapping = iocb->ki_filp->f_mapping;
-       struct inode *inode = file_inode(iocb->ki_filp);
-       size_t count = iov_iter_count(iter);
-       loff_t pos = iocb->ki_pos, start = pos;
-       loff_t end = iocb->ki_pos + count - 1, ret = 0;
-       unsigned int flags = IOMAP_DIRECT;
-       bool wait_for_completion = is_sync_kiocb(iocb);
-       struct blk_plug plug;
-       struct iomap_dio *dio;
-
-       lockdep_assert_held(&inode->i_rwsem);
-
-       if (!count)
-               return 0;
-
-       dio = kmalloc(sizeof(*dio), GFP_KERNEL);
-       if (!dio)
-               return -ENOMEM;
-
-       dio->iocb = iocb;
-       atomic_set(&dio->ref, 1);
-       dio->size = 0;
-       dio->i_size = i_size_read(inode);
-       dio->end_io = end_io;
-       dio->error = 0;
-       dio->flags = 0;
-
-       dio->submit.iter = iter;
-       dio->submit.waiter = current;
-       dio->submit.cookie = BLK_QC_T_NONE;
-       dio->submit.last_queue = NULL;
-
-       if (iov_iter_rw(iter) == READ) {
-               if (pos >= dio->i_size)
-                       goto out_free_dio;
-
-               if (iter_is_iovec(iter) && iov_iter_rw(iter) == READ)
-                       dio->flags |= IOMAP_DIO_DIRTY;
-       } else {
-               flags |= IOMAP_WRITE;
-               dio->flags |= IOMAP_DIO_WRITE;
-
-               /* for data sync or sync, we need sync completion processing */
-               if (iocb->ki_flags & IOCB_DSYNC)
-                       dio->flags |= IOMAP_DIO_NEED_SYNC;
-
-               /*
-                * For datasync only writes, we optimistically try using FUA for
-                * this IO.  Any non-FUA write that occurs will clear this flag,
-                * hence we know before completion whether a cache flush is
-                * necessary.
-                */
-               if ((iocb->ki_flags & (IOCB_DSYNC | IOCB_SYNC)) == IOCB_DSYNC)
-                       dio->flags |= IOMAP_DIO_WRITE_FUA;
-       }
-
-       if (iocb->ki_flags & IOCB_NOWAIT) {
-               if (filemap_range_has_page(mapping, start, end)) {
-                       ret = -EAGAIN;
-                       goto out_free_dio;
-               }
-               flags |= IOMAP_NOWAIT;
-       }
-
-       ret = filemap_write_and_wait_range(mapping, start, end);
-       if (ret)
-               goto out_free_dio;
-
-       /*
-        * Try to invalidate cache pages for the range we're direct
-        * writing.  If this invalidation fails, tough, the write will
-        * still work, but racing two incompatible write paths is a
-        * pretty crazy thing to do, so we don't support it 100%.
-        */
-       ret = invalidate_inode_pages2_range(mapping,
-                       start >> PAGE_SHIFT, end >> PAGE_SHIFT);
-       if (ret)
-               dio_warn_stale_pagecache(iocb->ki_filp);
-       ret = 0;
-
-       if (iov_iter_rw(iter) == WRITE && !wait_for_completion &&
-           !inode->i_sb->s_dio_done_wq) {
-               ret = sb_init_dio_done_wq(inode->i_sb);
-               if (ret < 0)
-                       goto out_free_dio;
-       }
-
-       inode_dio_begin(inode);
-
-       blk_start_plug(&plug);
-       do {
-               ret = iomap_apply(inode, pos, count, flags, ops, dio,
-                               iomap_dio_actor);
-               if (ret <= 0) {
-                       /* magic error code to fall back to buffered I/O */
-                       if (ret == -ENOTBLK) {
-                               wait_for_completion = true;
-                               ret = 0;
-                       }
-                       break;
-               }
-               pos += ret;
-
-               if (iov_iter_rw(iter) == READ && pos >= dio->i_size)
-                       break;
-       } while ((count = iov_iter_count(iter)) > 0);
-       blk_finish_plug(&plug);
-
-       if (ret < 0)
-               iomap_dio_set_error(dio, ret);
-
-       /*
-        * If all the writes we issued were FUA, we don't need to flush the
-        * cache on IO completion. Clear the sync flag for this case.
-        */
-       if (dio->flags & IOMAP_DIO_WRITE_FUA)
-               dio->flags &= ~IOMAP_DIO_NEED_SYNC;
-
-       WRITE_ONCE(iocb->ki_cookie, dio->submit.cookie);
-       WRITE_ONCE(iocb->private, dio->submit.last_queue);
-
-       /*
-        * We are about to drop our additional submission reference, which
-        * might be the last reference to the dio.  There are three three
-        * different ways we can progress here:
-        *
-        *  (a) If this is the last reference we will always complete and free
-        *      the dio ourselves.
-        *  (b) If this is not the last reference, and we serve an asynchronous
-        *      iocb, we must never touch the dio after the decrement, the
-        *      I/O completion handler will complete and free it.
-        *  (c) If this is not the last reference, but we serve a synchronous
-        *      iocb, the I/O completion handler will wake us up on the drop
-        *      of the final reference, and we will complete and free it here
-        *      after we got woken by the I/O completion handler.
-        */
-       dio->wait_for_completion = wait_for_completion;
-       if (!atomic_dec_and_test(&dio->ref)) {
-               if (!wait_for_completion)
-                       return -EIOCBQUEUED;
-
-               for (;;) {
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       if (!READ_ONCE(dio->submit.waiter))
-                               break;
-
-                       if (!(iocb->ki_flags & IOCB_HIPRI) ||
-                           !dio->submit.last_queue ||
-                           !blk_poll(dio->submit.last_queue,
-                                        dio->submit.cookie, true))
-                               io_schedule();
-               }
-               __set_current_state(TASK_RUNNING);
-       }
-
-       return iomap_dio_complete(dio);
-
-out_free_dio:
-       kfree(dio);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(iomap_dio_rw);
-
-/* Swapfile activation */
-
-#ifdef CONFIG_SWAP
-struct iomap_swapfile_info {
-       struct iomap iomap;             /* accumulated iomap */
-       struct swap_info_struct *sis;
-       uint64_t lowest_ppage;          /* lowest physical addr seen (pages) */
-       uint64_t highest_ppage;         /* highest physical addr seen (pages) */
-       unsigned long nr_pages;         /* number of pages collected */
-       int nr_extents;                 /* extent count */
-};
-
-/*
- * Collect physical extents for this swap file.  Physical extents reported to
- * the swap code must be trimmed to align to a page boundary.  The logical
- * offset within the file is irrelevant since the swapfile code maps logical
- * page numbers of the swap device to the physical page-aligned extents.
- */
-static int iomap_swapfile_add_extent(struct iomap_swapfile_info *isi)
-{
-       struct iomap *iomap = &isi->iomap;
-       unsigned long nr_pages;
-       uint64_t first_ppage;
-       uint64_t first_ppage_reported;
-       uint64_t next_ppage;
-       int error;
-
-       /*
-        * Round the start up and the end down so that the physical
-        * extent aligns to a page boundary.
-        */
-       first_ppage = ALIGN(iomap->addr, PAGE_SIZE) >> PAGE_SHIFT;
-       next_ppage = ALIGN_DOWN(iomap->addr + iomap->length, PAGE_SIZE) >>
-                       PAGE_SHIFT;
-
-       /* Skip too-short physical extents. */
-       if (first_ppage >= next_ppage)
-               return 0;
-       nr_pages = next_ppage - first_ppage;
-
-       /*
-        * Calculate how much swap space we're adding; the first page contains
-        * the swap header and doesn't count.  The mm still wants that first
-        * page fed to add_swap_extent, however.
-        */
-       first_ppage_reported = first_ppage;
-       if (iomap->offset == 0)
-               first_ppage_reported++;
-       if (isi->lowest_ppage > first_ppage_reported)
-               isi->lowest_ppage = first_ppage_reported;
-       if (isi->highest_ppage < (next_ppage - 1))
-               isi->highest_ppage = next_ppage - 1;
-
-       /* Add extent, set up for the next call. */
-       error = add_swap_extent(isi->sis, isi->nr_pages, nr_pages, first_ppage);
-       if (error < 0)
-               return error;
-       isi->nr_extents += error;
-       isi->nr_pages += nr_pages;
-       return 0;
-}
-
-/*
- * Accumulate iomaps for this swap file.  We have to accumulate iomaps because
- * swap only cares about contiguous page-aligned physical extents and makes no
- * distinction between written and unwritten extents.
- */
-static loff_t iomap_swapfile_activate_actor(struct inode *inode, loff_t pos,
-               loff_t count, void *data, struct iomap *iomap)
-{
-       struct iomap_swapfile_info *isi = data;
-       int error;
-
-       switch (iomap->type) {
-       case IOMAP_MAPPED:
-       case IOMAP_UNWRITTEN:
-               /* Only real or unwritten extents. */
-               break;
-       case IOMAP_INLINE:
-               /* No inline data. */
-               pr_err("swapon: file is inline\n");
-               return -EINVAL;
-       default:
-               pr_err("swapon: file has unallocated extents\n");
-               return -EINVAL;
-       }
-
-       /* No uncommitted metadata or shared blocks. */
-       if (iomap->flags & IOMAP_F_DIRTY) {
-               pr_err("swapon: file is not committed\n");
-               return -EINVAL;
-       }
-       if (iomap->flags & IOMAP_F_SHARED) {
-               pr_err("swapon: file has shared extents\n");
-               return -EINVAL;
-       }
-
-       /* Only one bdev per swap file. */
-       if (iomap->bdev != isi->sis->bdev) {
-               pr_err("swapon: file is on multiple devices\n");
-               return -EINVAL;
-       }
-
-       if (isi->iomap.length == 0) {
-               /* No accumulated extent, so just store it. */
-               memcpy(&isi->iomap, iomap, sizeof(isi->iomap));
-       } else if (isi->iomap.addr + isi->iomap.length == iomap->addr) {
-               /* Append this to the accumulated extent. */
-               isi->iomap.length += iomap->length;
-       } else {
-               /* Otherwise, add the retained iomap and store this one. */
-               error = iomap_swapfile_add_extent(isi);
-               if (error)
-                       return error;
-               memcpy(&isi->iomap, iomap, sizeof(isi->iomap));
-       }
-       return count;
-}
-
-/*
- * Iterate a swap file's iomaps to construct physical extents that can be
- * passed to the swapfile subsystem.
- */
-int iomap_swapfile_activate(struct swap_info_struct *sis,
-               struct file *swap_file, sector_t *pagespan,
-               const struct iomap_ops *ops)
-{
-       struct iomap_swapfile_info isi = {
-               .sis = sis,
-               .lowest_ppage = (sector_t)-1ULL,
-       };
-       struct address_space *mapping = swap_file->f_mapping;
-       struct inode *inode = mapping->host;
-       loff_t pos = 0;
-       loff_t len = ALIGN_DOWN(i_size_read(inode), PAGE_SIZE);
-       loff_t ret;
-
-       /*
-        * Persist all file mapping metadata so that we won't have any
-        * IOMAP_F_DIRTY iomaps.
-        */
-       ret = vfs_fsync(swap_file, 1);
-       if (ret)
-               return ret;
-
-       while (len > 0) {
-               ret = iomap_apply(inode, pos, len, IOMAP_REPORT,
-                               ops, &isi, iomap_swapfile_activate_actor);
-               if (ret <= 0)
-                       return ret;
-
-               pos += ret;
-               len -= ret;
-       }
-
-       if (isi.iomap.length) {
-               ret = iomap_swapfile_add_extent(&isi);
-               if (ret)
-                       return ret;
-       }
-
-       *pagespan = 1 + isi.highest_ppage - isi.lowest_ppage;
-       sis->max = isi.nr_pages;
-       sis->pages = isi.nr_pages - 1;
-       sis->highest_bit = isi.nr_pages - 1;
-       return isi.nr_extents;
-}
-EXPORT_SYMBOL_GPL(iomap_swapfile_activate);
-#endif /* CONFIG_SWAP */
-
-static loff_t
-iomap_bmap_actor(struct inode *inode, loff_t pos, loff_t length,
-               void *data, struct iomap *iomap)
-{
-       sector_t *bno = data, addr;
-
-       if (iomap->type == IOMAP_MAPPED) {
-               addr = (pos - iomap->offset + iomap->addr) >> inode->i_blkbits;
-               if (addr > INT_MAX)
-                       WARN(1, "would truncate bmap result\n");
-               else
-                       *bno = addr;
-       }
-       return 0;
-}
-
-/* legacy ->bmap interface.  0 is the error return (!) */
-sector_t
-iomap_bmap(struct address_space *mapping, sector_t bno,
-               const struct iomap_ops *ops)
-{
-       struct inode *inode = mapping->host;
-       loff_t pos = bno << inode->i_blkbits;
-       unsigned blocksize = i_blocksize(inode);
-
-       if (filemap_write_and_wait(mapping))
-               return 0;
-
-       bno = 0;
-       iomap_apply(inode, pos, blocksize, 0, ops, &bno, iomap_bmap_actor);
-       return bno;
-}
-EXPORT_SYMBOL_GPL(iomap_bmap);
diff --git a/fs/iomap/Makefile b/fs/iomap/Makefile
new file mode 100644 (file)
index 0000000..2d16538
--- /dev/null
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0-or-newer
+#
+# Copyright (c) 2019 Oracle.
+# All Rights Reserved.
+#
+obj-$(CONFIG_FS_IOMAP)         += iomap.o
+
+iomap-y                                += \
+                                       apply.o \
+                                       buffered-io.o \
+                                       direct-io.o \
+                                       fiemap.o \
+                                       seek.o
+
+iomap-$(CONFIG_SWAP)           += swapfile.o
diff --git a/fs/iomap/apply.c b/fs/iomap/apply.c
new file mode 100644 (file)
index 0000000..54c02ae
--- /dev/null
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ * Copyright (c) 2016-2018 Christoph Hellwig.
+ */
+#include <linux/module.h>
+#include <linux/compiler.h>
+#include <linux/fs.h>
+#include <linux/iomap.h>
+
+/*
+ * Execute a iomap write on a segment of the mapping that spans a
+ * contiguous range of pages that have identical block mapping state.
+ *
+ * This avoids the need to map pages individually, do individual allocations
+ * for each page and most importantly avoid the need for filesystem specific
+ * locking per page. Instead, all the operations are amortised over the entire
+ * range of pages. It is assumed that the filesystems will lock whatever
+ * resources they require in the iomap_begin call, and release them in the
+ * iomap_end call.
+ */
+loff_t
+iomap_apply(struct inode *inode, loff_t pos, loff_t length, unsigned flags,
+               const struct iomap_ops *ops, void *data, iomap_actor_t actor)
+{
+       struct iomap iomap = { 0 };
+       loff_t written = 0, ret;
+
+       /*
+        * Need to map a range from start position for length bytes. This can
+        * span multiple pages - it is only guaranteed to return a range of a
+        * single type of pages (e.g. all into a hole, all mapped or all
+        * unwritten). Failure at this point has nothing to undo.
+        *
+        * If allocation is required for this range, reserve the space now so
+        * that the allocation is guaranteed to succeed later on. Once we copy
+        * the data into the page cache pages, then we cannot fail otherwise we
+        * expose transient stale data. If the reserve fails, we can safely
+        * back out at this point as there is nothing to undo.
+        */
+       ret = ops->iomap_begin(inode, pos, length, flags, &iomap);
+       if (ret)
+               return ret;
+       if (WARN_ON(iomap.offset > pos))
+               return -EIO;
+       if (WARN_ON(iomap.length == 0))
+               return -EIO;
+
+       /*
+        * Cut down the length to the one actually provided by the filesystem,
+        * as it might not be able to give us the whole size that we requested.
+        */
+       if (iomap.offset + iomap.length < pos + length)
+               length = iomap.offset + iomap.length - pos;
+
+       /*
+        * Now that we have guaranteed that the space allocation will succeed.
+        * we can do the copy-in page by page without having to worry about
+        * failures exposing transient data.
+        */
+       written = actor(inode, pos, length, data, &iomap);
+
+       /*
+        * Now the data has been copied, commit the range we've copied.  This
+        * should not fail unless the filesystem has had a fatal error.
+        */
+       if (ops->iomap_end) {
+               ret = ops->iomap_end(inode, pos, length,
+                                    written > 0 ? written : 0,
+                                    flags, &iomap);
+       }
+
+       return written ? written : ret;
+}
diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
new file mode 100644 (file)
index 0000000..e25901a
--- /dev/null
@@ -0,0 +1,1073 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ * Copyright (c) 2016-2018 Christoph Hellwig.
+ */
+#include <linux/module.h>
+#include <linux/compiler.h>
+#include <linux/fs.h>
+#include <linux/iomap.h>
+#include <linux/pagemap.h>
+#include <linux/uio.h>
+#include <linux/buffer_head.h>
+#include <linux/dax.h>
+#include <linux/writeback.h>
+#include <linux/swap.h>
+#include <linux/bio.h>
+#include <linux/sched/signal.h>
+#include <linux/migrate.h>
+
+#include "../internal.h"
+
+static struct iomap_page *
+iomap_page_create(struct inode *inode, struct page *page)
+{
+       struct iomap_page *iop = to_iomap_page(page);
+
+       if (iop || i_blocksize(inode) == PAGE_SIZE)
+               return iop;
+
+       iop = kmalloc(sizeof(*iop), GFP_NOFS | __GFP_NOFAIL);
+       atomic_set(&iop->read_count, 0);
+       atomic_set(&iop->write_count, 0);
+       bitmap_zero(iop->uptodate, PAGE_SIZE / SECTOR_SIZE);
+
+       /*
+        * migrate_page_move_mapping() assumes that pages with private data have
+        * their count elevated by 1.
+        */
+       get_page(page);
+       set_page_private(page, (unsigned long)iop);
+       SetPagePrivate(page);
+       return iop;
+}
+
+static void
+iomap_page_release(struct page *page)
+{
+       struct iomap_page *iop = to_iomap_page(page);
+
+       if (!iop)
+               return;
+       WARN_ON_ONCE(atomic_read(&iop->read_count));
+       WARN_ON_ONCE(atomic_read(&iop->write_count));
+       ClearPagePrivate(page);
+       set_page_private(page, 0);
+       put_page(page);
+       kfree(iop);
+}
+
+/*
+ * Calculate the range inside the page that we actually need to read.
+ */
+static void
+iomap_adjust_read_range(struct inode *inode, struct iomap_page *iop,
+               loff_t *pos, loff_t length, unsigned *offp, unsigned *lenp)
+{
+       loff_t orig_pos = *pos;
+       loff_t isize = i_size_read(inode);
+       unsigned block_bits = inode->i_blkbits;
+       unsigned block_size = (1 << block_bits);
+       unsigned poff = offset_in_page(*pos);
+       unsigned plen = min_t(loff_t, PAGE_SIZE - poff, length);
+       unsigned first = poff >> block_bits;
+       unsigned last = (poff + plen - 1) >> block_bits;
+
+       /*
+        * If the block size is smaller than the page size we need to check the
+        * per-block uptodate status and adjust the offset and length if needed
+        * to avoid reading in already uptodate ranges.
+        */
+       if (iop) {
+               unsigned int i;
+
+               /* move forward for each leading block marked uptodate */
+               for (i = first; i <= last; i++) {
+                       if (!test_bit(i, iop->uptodate))
+                               break;
+                       *pos += block_size;
+                       poff += block_size;
+                       plen -= block_size;
+                       first++;
+               }
+
+               /* truncate len if we find any trailing uptodate block(s) */
+               for ( ; i <= last; i++) {
+                       if (test_bit(i, iop->uptodate)) {
+                               plen -= (last - i + 1) * block_size;
+                               last = i - 1;
+                               break;
+                       }
+               }
+       }
+
+       /*
+        * If the extent spans the block that contains the i_size we need to
+        * handle both halves separately so that we properly zero data in the
+        * page cache for blocks that are entirely outside of i_size.
+        */
+       if (orig_pos <= isize && orig_pos + length > isize) {
+               unsigned end = offset_in_page(isize - 1) >> block_bits;
+
+               if (first <= end && last > end)
+                       plen -= (last - end) * block_size;
+       }
+
+       *offp = poff;
+       *lenp = plen;
+}
+
+static void
+iomap_set_range_uptodate(struct page *page, unsigned off, unsigned len)
+{
+       struct iomap_page *iop = to_iomap_page(page);
+       struct inode *inode = page->mapping->host;
+       unsigned first = off >> inode->i_blkbits;
+       unsigned last = (off + len - 1) >> inode->i_blkbits;
+       unsigned int i;
+       bool uptodate = true;
+
+       if (iop) {
+               for (i = 0; i < PAGE_SIZE / i_blocksize(inode); i++) {
+                       if (i >= first && i <= last)
+                               set_bit(i, iop->uptodate);
+                       else if (!test_bit(i, iop->uptodate))
+                               uptodate = false;
+               }
+       }
+
+       if (uptodate && !PageError(page))
+               SetPageUptodate(page);
+}
+
+static void
+iomap_read_finish(struct iomap_page *iop, struct page *page)
+{
+       if (!iop || atomic_dec_and_test(&iop->read_count))
+               unlock_page(page);
+}
+
+static void
+iomap_read_page_end_io(struct bio_vec *bvec, int error)
+{
+       struct page *page = bvec->bv_page;
+       struct iomap_page *iop = to_iomap_page(page);
+
+       if (unlikely(error)) {
+               ClearPageUptodate(page);
+               SetPageError(page);
+       } else {
+               iomap_set_range_uptodate(page, bvec->bv_offset, bvec->bv_len);
+       }
+
+       iomap_read_finish(iop, page);
+}
+
+static void
+iomap_read_end_io(struct bio *bio)
+{
+       int error = blk_status_to_errno(bio->bi_status);
+       struct bio_vec *bvec;
+       struct bvec_iter_all iter_all;
+
+       bio_for_each_segment_all(bvec, bio, iter_all)
+               iomap_read_page_end_io(bvec, error);
+       bio_put(bio);
+}
+
+struct iomap_readpage_ctx {
+       struct page             *cur_page;
+       bool                    cur_page_in_bio;
+       bool                    is_readahead;
+       struct bio              *bio;
+       struct list_head        *pages;
+};
+
+static void
+iomap_read_inline_data(struct inode *inode, struct page *page,
+               struct iomap *iomap)
+{
+       size_t size = i_size_read(inode);
+       void *addr;
+
+       if (PageUptodate(page))
+               return;
+
+       BUG_ON(page->index);
+       BUG_ON(size > PAGE_SIZE - offset_in_page(iomap->inline_data));
+
+       addr = kmap_atomic(page);
+       memcpy(addr, iomap->inline_data, size);
+       memset(addr + size, 0, PAGE_SIZE - size);
+       kunmap_atomic(addr);
+       SetPageUptodate(page);
+}
+
+static loff_t
+iomap_readpage_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
+               struct iomap *iomap)
+{
+       struct iomap_readpage_ctx *ctx = data;
+       struct page *page = ctx->cur_page;
+       struct iomap_page *iop = iomap_page_create(inode, page);
+       bool same_page = false, is_contig = false;
+       loff_t orig_pos = pos;
+       unsigned poff, plen;
+       sector_t sector;
+
+       if (iomap->type == IOMAP_INLINE) {
+               WARN_ON_ONCE(pos);
+               iomap_read_inline_data(inode, page, iomap);
+               return PAGE_SIZE;
+       }
+
+       /* zero post-eof blocks as the page may be mapped */
+       iomap_adjust_read_range(inode, iop, &pos, length, &poff, &plen);
+       if (plen == 0)
+               goto done;
+
+       if (iomap->type != IOMAP_MAPPED || pos >= i_size_read(inode)) {
+               zero_user(page, poff, plen);
+               iomap_set_range_uptodate(page, poff, plen);
+               goto done;
+       }
+
+       ctx->cur_page_in_bio = true;
+
+       /*
+        * Try to merge into a previous segment if we can.
+        */
+       sector = iomap_sector(iomap, pos);
+       if (ctx->bio && bio_end_sector(ctx->bio) == sector)
+               is_contig = true;
+
+       if (is_contig &&
+           __bio_try_merge_page(ctx->bio, page, plen, poff, &same_page)) {
+               if (!same_page && iop)
+                       atomic_inc(&iop->read_count);
+               goto done;
+       }
+
+       /*
+        * If we start a new segment we need to increase the read count, and we
+        * need to do so before submitting any previous full bio to make sure
+        * that we don't prematurely unlock the page.
+        */
+       if (iop)
+               atomic_inc(&iop->read_count);
+
+       if (!ctx->bio || !is_contig || bio_full(ctx->bio, plen)) {
+               gfp_t gfp = mapping_gfp_constraint(page->mapping, GFP_KERNEL);
+               int nr_vecs = (length + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+               if (ctx->bio)
+                       submit_bio(ctx->bio);
+
+               if (ctx->is_readahead) /* same as readahead_gfp_mask */
+                       gfp |= __GFP_NORETRY | __GFP_NOWARN;
+               ctx->bio = bio_alloc(gfp, min(BIO_MAX_PAGES, nr_vecs));
+               ctx->bio->bi_opf = REQ_OP_READ;
+               if (ctx->is_readahead)
+                       ctx->bio->bi_opf |= REQ_RAHEAD;
+               ctx->bio->bi_iter.bi_sector = sector;
+               bio_set_dev(ctx->bio, iomap->bdev);
+               ctx->bio->bi_end_io = iomap_read_end_io;
+       }
+
+       bio_add_page(ctx->bio, page, plen, poff);
+done:
+       /*
+        * Move the caller beyond our range so that it keeps making progress.
+        * For that we have to include any leading non-uptodate ranges, but
+        * we can skip trailing ones as they will be handled in the next
+        * iteration.
+        */
+       return pos - orig_pos + plen;
+}
+
+int
+iomap_readpage(struct page *page, const struct iomap_ops *ops)
+{
+       struct iomap_readpage_ctx ctx = { .cur_page = page };
+       struct inode *inode = page->mapping->host;
+       unsigned poff;
+       loff_t ret;
+
+       for (poff = 0; poff < PAGE_SIZE; poff += ret) {
+               ret = iomap_apply(inode, page_offset(page) + poff,
+                               PAGE_SIZE - poff, 0, ops, &ctx,
+                               iomap_readpage_actor);
+               if (ret <= 0) {
+                       WARN_ON_ONCE(ret == 0);
+                       SetPageError(page);
+                       break;
+               }
+       }
+
+       if (ctx.bio) {
+               submit_bio(ctx.bio);
+               WARN_ON_ONCE(!ctx.cur_page_in_bio);
+       } else {
+               WARN_ON_ONCE(ctx.cur_page_in_bio);
+               unlock_page(page);
+       }
+
+       /*
+        * Just like mpage_readpages and block_read_full_page we always
+        * return 0 and just mark the page as PageError on errors.  This
+        * should be cleaned up all through the stack eventually.
+        */
+       return 0;
+}
+EXPORT_SYMBOL_GPL(iomap_readpage);
+
+static struct page *
+iomap_next_page(struct inode *inode, struct list_head *pages, loff_t pos,
+               loff_t length, loff_t *done)
+{
+       while (!list_empty(pages)) {
+               struct page *page = lru_to_page(pages);
+
+               if (page_offset(page) >= (u64)pos + length)
+                       break;
+
+               list_del(&page->lru);
+               if (!add_to_page_cache_lru(page, inode->i_mapping, page->index,
+                               GFP_NOFS))
+                       return page;
+
+               /*
+                * If we already have a page in the page cache at index we are
+                * done.  Upper layers don't care if it is uptodate after the
+                * readpages call itself as every page gets checked again once
+                * actually needed.
+                */
+               *done += PAGE_SIZE;
+               put_page(page);
+       }
+
+       return NULL;
+}
+
+static loff_t
+iomap_readpages_actor(struct inode *inode, loff_t pos, loff_t length,
+               void *data, struct iomap *iomap)
+{
+       struct iomap_readpage_ctx *ctx = data;
+       loff_t done, ret;
+
+       for (done = 0; done < length; done += ret) {
+               if (ctx->cur_page && offset_in_page(pos + done) == 0) {
+                       if (!ctx->cur_page_in_bio)
+                               unlock_page(ctx->cur_page);
+                       put_page(ctx->cur_page);
+                       ctx->cur_page = NULL;
+               }
+               if (!ctx->cur_page) {
+                       ctx->cur_page = iomap_next_page(inode, ctx->pages,
+                                       pos, length, &done);
+                       if (!ctx->cur_page)
+                               break;
+                       ctx->cur_page_in_bio = false;
+               }
+               ret = iomap_readpage_actor(inode, pos + done, length - done,
+                               ctx, iomap);
+       }
+
+       return done;
+}
+
+int
+iomap_readpages(struct address_space *mapping, struct list_head *pages,
+               unsigned nr_pages, const struct iomap_ops *ops)
+{
+       struct iomap_readpage_ctx ctx = {
+               .pages          = pages,
+               .is_readahead   = true,
+       };
+       loff_t pos = page_offset(list_entry(pages->prev, struct page, lru));
+       loff_t last = page_offset(list_entry(pages->next, struct page, lru));
+       loff_t length = last - pos + PAGE_SIZE, ret = 0;
+
+       while (length > 0) {
+               ret = iomap_apply(mapping->host, pos, length, 0, ops,
+                               &ctx, iomap_readpages_actor);
+               if (ret <= 0) {
+                       WARN_ON_ONCE(ret == 0);
+                       goto done;
+               }
+               pos += ret;
+               length -= ret;
+       }
+       ret = 0;
+done:
+       if (ctx.bio)
+               submit_bio(ctx.bio);
+       if (ctx.cur_page) {
+               if (!ctx.cur_page_in_bio)
+                       unlock_page(ctx.cur_page);
+               put_page(ctx.cur_page);
+       }
+
+       /*
+        * Check that we didn't lose a page due to the arcance calling
+        * conventions..
+        */
+       WARN_ON_ONCE(!ret && !list_empty(ctx.pages));
+       return ret;
+}
+EXPORT_SYMBOL_GPL(iomap_readpages);
+
+/*
+ * iomap_is_partially_uptodate checks whether blocks within a page are
+ * uptodate or not.
+ *
+ * Returns true if all blocks which correspond to a file portion
+ * we want to read within the page are uptodate.
+ */
+int
+iomap_is_partially_uptodate(struct page *page, unsigned long from,
+               unsigned long count)
+{
+       struct iomap_page *iop = to_iomap_page(page);
+       struct inode *inode = page->mapping->host;
+       unsigned len, first, last;
+       unsigned i;
+
+       /* Limit range to one page */
+       len = min_t(unsigned, PAGE_SIZE - from, count);
+
+       /* First and last blocks in range within page */
+       first = from >> inode->i_blkbits;
+       last = (from + len - 1) >> inode->i_blkbits;
+
+       if (iop) {
+               for (i = first; i <= last; i++)
+                       if (!test_bit(i, iop->uptodate))
+                               return 0;
+               return 1;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(iomap_is_partially_uptodate);
+
+int
+iomap_releasepage(struct page *page, gfp_t gfp_mask)
+{
+       /*
+        * mm accommodates an old ext3 case where clean pages might not have had
+        * the dirty bit cleared. Thus, it can send actual dirty pages to
+        * ->releasepage() via shrink_active_list(), skip those here.
+        */
+       if (PageDirty(page) || PageWriteback(page))
+               return 0;
+       iomap_page_release(page);
+       return 1;
+}
+EXPORT_SYMBOL_GPL(iomap_releasepage);
+
+void
+iomap_invalidatepage(struct page *page, unsigned int offset, unsigned int len)
+{
+       /*
+        * If we are invalidating the entire page, clear the dirty state from it
+        * and release it to avoid unnecessary buildup of the LRU.
+        */
+       if (offset == 0 && len == PAGE_SIZE) {
+               WARN_ON_ONCE(PageWriteback(page));
+               cancel_dirty_page(page);
+               iomap_page_release(page);
+       }
+}
+EXPORT_SYMBOL_GPL(iomap_invalidatepage);
+
+#ifdef CONFIG_MIGRATION
+int
+iomap_migrate_page(struct address_space *mapping, struct page *newpage,
+               struct page *page, enum migrate_mode mode)
+{
+       int ret;
+
+       ret = migrate_page_move_mapping(mapping, newpage, page, 0);
+       if (ret != MIGRATEPAGE_SUCCESS)
+               return ret;
+
+       if (page_has_private(page)) {
+               ClearPagePrivate(page);
+               get_page(newpage);
+               set_page_private(newpage, page_private(page));
+               set_page_private(page, 0);
+               put_page(page);
+               SetPagePrivate(newpage);
+       }
+
+       if (mode != MIGRATE_SYNC_NO_COPY)
+               migrate_page_copy(newpage, page);
+       else
+               migrate_page_states(newpage, page);
+       return MIGRATEPAGE_SUCCESS;
+}
+EXPORT_SYMBOL_GPL(iomap_migrate_page);
+#endif /* CONFIG_MIGRATION */
+
+static void
+iomap_write_failed(struct inode *inode, loff_t pos, unsigned len)
+{
+       loff_t i_size = i_size_read(inode);
+
+       /*
+        * Only truncate newly allocated pages beyoned EOF, even if the
+        * write started inside the existing inode size.
+        */
+       if (pos + len > i_size)
+               truncate_pagecache_range(inode, max(pos, i_size), pos + len);
+}
+
+static int
+iomap_read_page_sync(struct inode *inode, loff_t block_start, struct page *page,
+               unsigned poff, unsigned plen, unsigned from, unsigned to,
+               struct iomap *iomap)
+{
+       struct bio_vec bvec;
+       struct bio bio;
+
+       if (iomap->type != IOMAP_MAPPED || block_start >= i_size_read(inode)) {
+               zero_user_segments(page, poff, from, to, poff + plen);
+               iomap_set_range_uptodate(page, poff, plen);
+               return 0;
+       }
+
+       bio_init(&bio, &bvec, 1);
+       bio.bi_opf = REQ_OP_READ;
+       bio.bi_iter.bi_sector = iomap_sector(iomap, block_start);
+       bio_set_dev(&bio, iomap->bdev);
+       __bio_add_page(&bio, page, plen, poff);
+       return submit_bio_wait(&bio);
+}
+
+static int
+__iomap_write_begin(struct inode *inode, loff_t pos, unsigned len,
+               struct page *page, struct iomap *iomap)
+{
+       struct iomap_page *iop = iomap_page_create(inode, page);
+       loff_t block_size = i_blocksize(inode);
+       loff_t block_start = pos & ~(block_size - 1);
+       loff_t block_end = (pos + len + block_size - 1) & ~(block_size - 1);
+       unsigned from = offset_in_page(pos), to = from + len, poff, plen;
+       int status = 0;
+
+       if (PageUptodate(page))
+               return 0;
+
+       do {
+               iomap_adjust_read_range(inode, iop, &block_start,
+                               block_end - block_start, &poff, &plen);
+               if (plen == 0)
+                       break;
+
+               if ((from > poff && from < poff + plen) ||
+                   (to > poff && to < poff + plen)) {
+                       status = iomap_read_page_sync(inode, block_start, page,
+                                       poff, plen, from, to, iomap);
+                       if (status)
+                               break;
+               }
+
+       } while ((block_start += plen) < block_end);
+
+       return status;
+}
+
+static int
+iomap_write_begin(struct inode *inode, loff_t pos, unsigned len, unsigned flags,
+               struct page **pagep, struct iomap *iomap)
+{
+       const struct iomap_page_ops *page_ops = iomap->page_ops;
+       pgoff_t index = pos >> PAGE_SHIFT;
+       struct page *page;
+       int status = 0;
+
+       BUG_ON(pos + len > iomap->offset + iomap->length);
+
+       if (fatal_signal_pending(current))
+               return -EINTR;
+
+       if (page_ops && page_ops->page_prepare) {
+               status = page_ops->page_prepare(inode, pos, len, iomap);
+               if (status)
+                       return status;
+       }
+
+       page = grab_cache_page_write_begin(inode->i_mapping, index, flags);
+       if (!page) {
+               status = -ENOMEM;
+               goto out_no_page;
+       }
+
+       if (iomap->type == IOMAP_INLINE)
+               iomap_read_inline_data(inode, page, iomap);
+       else if (iomap->flags & IOMAP_F_BUFFER_HEAD)
+               status = __block_write_begin_int(page, pos, len, NULL, iomap);
+       else
+               status = __iomap_write_begin(inode, pos, len, page, iomap);
+
+       if (unlikely(status))
+               goto out_unlock;
+
+       *pagep = page;
+       return 0;
+
+out_unlock:
+       unlock_page(page);
+       put_page(page);
+       iomap_write_failed(inode, pos, len);
+
+out_no_page:
+       if (page_ops && page_ops->page_done)
+               page_ops->page_done(inode, pos, 0, NULL, iomap);
+       return status;
+}
+
+int
+iomap_set_page_dirty(struct page *page)
+{
+       struct address_space *mapping = page_mapping(page);
+       int newly_dirty;
+
+       if (unlikely(!mapping))
+               return !TestSetPageDirty(page);
+
+       /*
+        * Lock out page->mem_cgroup migration to keep PageDirty
+        * synchronized with per-memcg dirty page counters.
+        */
+       lock_page_memcg(page);
+       newly_dirty = !TestSetPageDirty(page);
+       if (newly_dirty)
+               __set_page_dirty(page, mapping, 0);
+       unlock_page_memcg(page);
+
+       if (newly_dirty)
+               __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
+       return newly_dirty;
+}
+EXPORT_SYMBOL_GPL(iomap_set_page_dirty);
+
+static int
+__iomap_write_end(struct inode *inode, loff_t pos, unsigned len,
+               unsigned copied, struct page *page, struct iomap *iomap)
+{
+       flush_dcache_page(page);
+
+       /*
+        * The blocks that were entirely written will now be uptodate, so we
+        * don't have to worry about a readpage reading them and overwriting a
+        * partial write.  However if we have encountered a short write and only
+        * partially written into a block, it will not be marked uptodate, so a
+        * readpage might come in and destroy our partial write.
+        *
+        * Do the simplest thing, and just treat any short write to a non
+        * uptodate page as a zero-length write, and force the caller to redo
+        * the whole thing.
+        */
+       if (unlikely(copied < len && !PageUptodate(page)))
+               return 0;
+       iomap_set_range_uptodate(page, offset_in_page(pos), len);
+       iomap_set_page_dirty(page);
+       return copied;
+}
+
+static int
+iomap_write_end_inline(struct inode *inode, struct page *page,
+               struct iomap *iomap, loff_t pos, unsigned copied)
+{
+       void *addr;
+
+       WARN_ON_ONCE(!PageUptodate(page));
+       BUG_ON(pos + copied > PAGE_SIZE - offset_in_page(iomap->inline_data));
+
+       addr = kmap_atomic(page);
+       memcpy(iomap->inline_data + pos, addr + pos, copied);
+       kunmap_atomic(addr);
+
+       mark_inode_dirty(inode);
+       return copied;
+}
+
+static int
+iomap_write_end(struct inode *inode, loff_t pos, unsigned len,
+               unsigned copied, struct page *page, struct iomap *iomap)
+{
+       const struct iomap_page_ops *page_ops = iomap->page_ops;
+       loff_t old_size = inode->i_size;
+       int ret;
+
+       if (iomap->type == IOMAP_INLINE) {
+               ret = iomap_write_end_inline(inode, page, iomap, pos, copied);
+       } else if (iomap->flags & IOMAP_F_BUFFER_HEAD) {
+               ret = block_write_end(NULL, inode->i_mapping, pos, len, copied,
+                               page, NULL);
+       } else {
+               ret = __iomap_write_end(inode, pos, len, copied, page, iomap);
+       }
+
+       /*
+        * Update the in-memory inode size after copying the data into the page
+        * cache.  It's up to the file system to write the updated size to disk,
+        * preferably after I/O completion so that no stale data is exposed.
+        */
+       if (pos + ret > old_size) {
+               i_size_write(inode, pos + ret);
+               iomap->flags |= IOMAP_F_SIZE_CHANGED;
+       }
+       unlock_page(page);
+
+       if (old_size < pos)
+               pagecache_isize_extended(inode, old_size, pos);
+       if (page_ops && page_ops->page_done)
+               page_ops->page_done(inode, pos, ret, page, iomap);
+       put_page(page);
+
+       if (ret < len)
+               iomap_write_failed(inode, pos, len);
+       return ret;
+}
+
+static loff_t
+iomap_write_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
+               struct iomap *iomap)
+{
+       struct iov_iter *i = data;
+       long status = 0;
+       ssize_t written = 0;
+       unsigned int flags = AOP_FLAG_NOFS;
+
+       do {
+               struct page *page;
+               unsigned long offset;   /* Offset into pagecache page */
+               unsigned long bytes;    /* Bytes to write to page */
+               size_t copied;          /* Bytes copied from user */
+
+               offset = offset_in_page(pos);
+               bytes = min_t(unsigned long, PAGE_SIZE - offset,
+                                               iov_iter_count(i));
+again:
+               if (bytes > length)
+                       bytes = length;
+
+               /*
+                * Bring in the user page that we will copy from _first_.
+                * Otherwise there's a nasty deadlock on copying from the
+                * same page as we're writing to, without it being marked
+                * up-to-date.
+                *
+                * Not only is this an optimisation, but it is also required
+                * to check that the address is actually valid, when atomic
+                * usercopies are used, below.
+                */
+               if (unlikely(iov_iter_fault_in_readable(i, bytes))) {
+                       status = -EFAULT;
+                       break;
+               }
+
+               status = iomap_write_begin(inode, pos, bytes, flags, &page,
+                               iomap);
+               if (unlikely(status))
+                       break;
+
+               if (mapping_writably_mapped(inode->i_mapping))
+                       flush_dcache_page(page);
+
+               copied = iov_iter_copy_from_user_atomic(page, i, offset, bytes);
+
+               flush_dcache_page(page);
+
+               status = iomap_write_end(inode, pos, bytes, copied, page,
+                               iomap);
+               if (unlikely(status < 0))
+                       break;
+               copied = status;
+
+               cond_resched();
+
+               iov_iter_advance(i, copied);
+               if (unlikely(copied == 0)) {
+                       /*
+                        * If we were unable to copy any data at all, we must
+                        * fall back to a single segment length write.
+                        *
+                        * If we didn't fallback here, we could livelock
+                        * because not all segments in the iov can be copied at
+                        * once without a pagefault.
+                        */
+                       bytes = min_t(unsigned long, PAGE_SIZE - offset,
+                                               iov_iter_single_seg_count(i));
+                       goto again;
+               }
+               pos += copied;
+               written += copied;
+               length -= copied;
+
+               balance_dirty_pages_ratelimited(inode->i_mapping);
+       } while (iov_iter_count(i) && length);
+
+       return written ? written : status;
+}
+
+ssize_t
+iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *iter,
+               const struct iomap_ops *ops)
+{
+       struct inode *inode = iocb->ki_filp->f_mapping->host;
+       loff_t pos = iocb->ki_pos, ret = 0, written = 0;
+
+       while (iov_iter_count(iter)) {
+               ret = iomap_apply(inode, pos, iov_iter_count(iter),
+                               IOMAP_WRITE, ops, iter, iomap_write_actor);
+               if (ret <= 0)
+                       break;
+               pos += ret;
+               written += ret;
+       }
+
+       return written ? written : ret;
+}
+EXPORT_SYMBOL_GPL(iomap_file_buffered_write);
+
+static struct page *
+__iomap_read_page(struct inode *inode, loff_t offset)
+{
+       struct address_space *mapping = inode->i_mapping;
+       struct page *page;
+
+       page = read_mapping_page(mapping, offset >> PAGE_SHIFT, NULL);
+       if (IS_ERR(page))
+               return page;
+       if (!PageUptodate(page)) {
+               put_page(page);
+               return ERR_PTR(-EIO);
+       }
+       return page;
+}
+
+static loff_t
+iomap_dirty_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
+               struct iomap *iomap)
+{
+       long status = 0;
+       ssize_t written = 0;
+
+       do {
+               struct page *page, *rpage;
+               unsigned long offset;   /* Offset into pagecache page */
+               unsigned long bytes;    /* Bytes to write to page */
+
+               offset = offset_in_page(pos);
+               bytes = min_t(loff_t, PAGE_SIZE - offset, length);
+
+               rpage = __iomap_read_page(inode, pos);
+               if (IS_ERR(rpage))
+                       return PTR_ERR(rpage);
+
+               status = iomap_write_begin(inode, pos, bytes,
+                                          AOP_FLAG_NOFS, &page, iomap);
+               put_page(rpage);
+               if (unlikely(status))
+                       return status;
+
+               WARN_ON_ONCE(!PageUptodate(page));
+
+               status = iomap_write_end(inode, pos, bytes, bytes, page, iomap);
+               if (unlikely(status <= 0)) {
+                       if (WARN_ON_ONCE(status == 0))
+                               return -EIO;
+                       return status;
+               }
+
+               cond_resched();
+
+               pos += status;
+               written += status;
+               length -= status;
+
+               balance_dirty_pages_ratelimited(inode->i_mapping);
+       } while (length);
+
+       return written;
+}
+
+int
+iomap_file_dirty(struct inode *inode, loff_t pos, loff_t len,
+               const struct iomap_ops *ops)
+{
+       loff_t ret;
+
+       while (len) {
+               ret = iomap_apply(inode, pos, len, IOMAP_WRITE, ops, NULL,
+                               iomap_dirty_actor);
+               if (ret <= 0)
+                       return ret;
+               pos += ret;
+               len -= ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(iomap_file_dirty);
+
+static int iomap_zero(struct inode *inode, loff_t pos, unsigned offset,
+               unsigned bytes, struct iomap *iomap)
+{
+       struct page *page;
+       int status;
+
+       status = iomap_write_begin(inode, pos, bytes, AOP_FLAG_NOFS, &page,
+                                  iomap);
+       if (status)
+               return status;
+
+       zero_user(page, offset, bytes);
+       mark_page_accessed(page);
+
+       return iomap_write_end(inode, pos, bytes, bytes, page, iomap);
+}
+
+static int iomap_dax_zero(loff_t pos, unsigned offset, unsigned bytes,
+               struct iomap *iomap)
+{
+       return __dax_zero_page_range(iomap->bdev, iomap->dax_dev,
+                       iomap_sector(iomap, pos & PAGE_MASK), offset, bytes);
+}
+
+static loff_t
+iomap_zero_range_actor(struct inode *inode, loff_t pos, loff_t count,
+               void *data, struct iomap *iomap)
+{
+       bool *did_zero = data;
+       loff_t written = 0;
+       int status;
+
+       /* already zeroed?  we're done. */
+       if (iomap->type == IOMAP_HOLE || iomap->type == IOMAP_UNWRITTEN)
+               return count;
+
+       do {
+               unsigned offset, bytes;
+
+               offset = offset_in_page(pos);
+               bytes = min_t(loff_t, PAGE_SIZE - offset, count);
+
+               if (IS_DAX(inode))
+                       status = iomap_dax_zero(pos, offset, bytes, iomap);
+               else
+                       status = iomap_zero(inode, pos, offset, bytes, iomap);
+               if (status < 0)
+                       return status;
+
+               pos += bytes;
+               count -= bytes;
+               written += bytes;
+               if (did_zero)
+                       *did_zero = true;
+       } while (count > 0);
+
+       return written;
+}
+
+int
+iomap_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero,
+               const struct iomap_ops *ops)
+{
+       loff_t ret;
+
+       while (len > 0) {
+               ret = iomap_apply(inode, pos, len, IOMAP_ZERO,
+                               ops, did_zero, iomap_zero_range_actor);
+               if (ret <= 0)
+                       return ret;
+
+               pos += ret;
+               len -= ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(iomap_zero_range);
+
+int
+iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero,
+               const struct iomap_ops *ops)
+{
+       unsigned int blocksize = i_blocksize(inode);
+       unsigned int off = pos & (blocksize - 1);
+
+       /* Block boundary? Nothing to do */
+       if (!off)
+               return 0;
+       return iomap_zero_range(inode, pos, blocksize - off, did_zero, ops);
+}
+EXPORT_SYMBOL_GPL(iomap_truncate_page);
+
+static loff_t
+iomap_page_mkwrite_actor(struct inode *inode, loff_t pos, loff_t length,
+               void *data, struct iomap *iomap)
+{
+       struct page *page = data;
+       int ret;
+
+       if (iomap->flags & IOMAP_F_BUFFER_HEAD) {
+               ret = __block_write_begin_int(page, pos, length, NULL, iomap);
+               if (ret)
+                       return ret;
+               block_commit_write(page, 0, length);
+       } else {
+               WARN_ON_ONCE(!PageUptodate(page));
+               iomap_page_create(inode, page);
+               set_page_dirty(page);
+       }
+
+       return length;
+}
+
+vm_fault_t iomap_page_mkwrite(struct vm_fault *vmf, const struct iomap_ops *ops)
+{
+       struct page *page = vmf->page;
+       struct inode *inode = file_inode(vmf->vma->vm_file);
+       unsigned long length;
+       loff_t offset, size;
+       ssize_t ret;
+
+       lock_page(page);
+       size = i_size_read(inode);
+       if ((page->mapping != inode->i_mapping) ||
+           (page_offset(page) > size)) {
+               /* We overload EFAULT to mean page got truncated */
+               ret = -EFAULT;
+               goto out_unlock;
+       }
+
+       /* page is wholly or partially inside EOF */
+       if (((page->index + 1) << PAGE_SHIFT) > size)
+               length = offset_in_page(size);
+       else
+               length = PAGE_SIZE;
+
+       offset = page_offset(page);
+       while (length > 0) {
+               ret = iomap_apply(inode, offset, length,
+                               IOMAP_WRITE | IOMAP_FAULT, ops, page,
+                               iomap_page_mkwrite_actor);
+               if (unlikely(ret <= 0))
+                       goto out_unlock;
+               offset += ret;
+               length -= ret;
+       }
+
+       wait_for_stable_page(page);
+       return VM_FAULT_LOCKED;
+out_unlock:
+       unlock_page(page);
+       return block_page_mkwrite_return(ret);
+}
+EXPORT_SYMBOL_GPL(iomap_page_mkwrite);
diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c
new file mode 100644 (file)
index 0000000..10517ce
--- /dev/null
@@ -0,0 +1,562 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ * Copyright (c) 2016-2018 Christoph Hellwig.
+ */
+#include <linux/module.h>
+#include <linux/compiler.h>
+#include <linux/fs.h>
+#include <linux/iomap.h>
+#include <linux/backing-dev.h>
+#include <linux/uio.h>
+#include <linux/task_io_accounting_ops.h>
+
+#include "../internal.h"
+
+/*
+ * Private flags for iomap_dio, must not overlap with the public ones in
+ * iomap.h:
+ */
+#define IOMAP_DIO_WRITE_FUA    (1 << 28)
+#define IOMAP_DIO_NEED_SYNC    (1 << 29)
+#define IOMAP_DIO_WRITE                (1 << 30)
+#define IOMAP_DIO_DIRTY                (1 << 31)
+
+struct iomap_dio {
+       struct kiocb            *iocb;
+       iomap_dio_end_io_t      *end_io;
+       loff_t                  i_size;
+       loff_t                  size;
+       atomic_t                ref;
+       unsigned                flags;
+       int                     error;
+       bool                    wait_for_completion;
+
+       union {
+               /* used during submission and for synchronous completion: */
+               struct {
+                       struct iov_iter         *iter;
+                       struct task_struct      *waiter;
+                       struct request_queue    *last_queue;
+                       blk_qc_t                cookie;
+               } submit;
+
+               /* used for aio completion: */
+               struct {
+                       struct work_struct      work;
+               } aio;
+       };
+};
+
+int iomap_dio_iopoll(struct kiocb *kiocb, bool spin)
+{
+       struct request_queue *q = READ_ONCE(kiocb->private);
+
+       if (!q)
+               return 0;
+       return blk_poll(q, READ_ONCE(kiocb->ki_cookie), spin);
+}
+EXPORT_SYMBOL_GPL(iomap_dio_iopoll);
+
+static void iomap_dio_submit_bio(struct iomap_dio *dio, struct iomap *iomap,
+               struct bio *bio)
+{
+       atomic_inc(&dio->ref);
+
+       if (dio->iocb->ki_flags & IOCB_HIPRI)
+               bio_set_polled(bio, dio->iocb);
+
+       dio->submit.last_queue = bdev_get_queue(iomap->bdev);
+       dio->submit.cookie = submit_bio(bio);
+}
+
+static ssize_t iomap_dio_complete(struct iomap_dio *dio)
+{
+       struct kiocb *iocb = dio->iocb;
+       struct inode *inode = file_inode(iocb->ki_filp);
+       loff_t offset = iocb->ki_pos;
+       ssize_t ret;
+
+       if (dio->end_io) {
+               ret = dio->end_io(iocb,
+                               dio->error ? dio->error : dio->size,
+                               dio->flags);
+       } else {
+               ret = dio->error;
+       }
+
+       if (likely(!ret)) {
+               ret = dio->size;
+               /* check for short read */
+               if (offset + ret > dio->i_size &&
+                   !(dio->flags & IOMAP_DIO_WRITE))
+                       ret = dio->i_size - offset;
+               iocb->ki_pos += ret;
+       }
+
+       /*
+        * Try again to invalidate clean pages which might have been cached by
+        * non-direct readahead, or faulted in by get_user_pages() if the source
+        * of the write was an mmap'ed region of the file we're writing.  Either
+        * one is a pretty crazy thing to do, so we don't support it 100%.  If
+        * this invalidation fails, tough, the write still worked...
+        *
+        * And this page cache invalidation has to be after dio->end_io(), as
+        * some filesystems convert unwritten extents to real allocations in
+        * end_io() when necessary, otherwise a racing buffer read would cache
+        * zeros from unwritten extents.
+        */
+       if (!dio->error &&
+           (dio->flags & IOMAP_DIO_WRITE) && inode->i_mapping->nrpages) {
+               int err;
+               err = invalidate_inode_pages2_range(inode->i_mapping,
+                               offset >> PAGE_SHIFT,
+                               (offset + dio->size - 1) >> PAGE_SHIFT);
+               if (err)
+                       dio_warn_stale_pagecache(iocb->ki_filp);
+       }
+
+       /*
+        * If this is a DSYNC write, make sure we push it to stable storage now
+        * that we've written data.
+        */
+       if (ret > 0 && (dio->flags & IOMAP_DIO_NEED_SYNC))
+               ret = generic_write_sync(iocb, ret);
+
+       inode_dio_end(file_inode(iocb->ki_filp));
+       kfree(dio);
+
+       return ret;
+}
+
+static void iomap_dio_complete_work(struct work_struct *work)
+{
+       struct iomap_dio *dio = container_of(work, struct iomap_dio, aio.work);
+       struct kiocb *iocb = dio->iocb;
+
+       iocb->ki_complete(iocb, iomap_dio_complete(dio), 0);
+}
+
+/*
+ * Set an error in the dio if none is set yet.  We have to use cmpxchg
+ * as the submission context and the completion context(s) can race to
+ * update the error.
+ */
+static inline void iomap_dio_set_error(struct iomap_dio *dio, int ret)
+{
+       cmpxchg(&dio->error, 0, ret);
+}
+
+static void iomap_dio_bio_end_io(struct bio *bio)
+{
+       struct iomap_dio *dio = bio->bi_private;
+       bool should_dirty = (dio->flags & IOMAP_DIO_DIRTY);
+
+       if (bio->bi_status)
+               iomap_dio_set_error(dio, blk_status_to_errno(bio->bi_status));
+
+       if (atomic_dec_and_test(&dio->ref)) {
+               if (dio->wait_for_completion) {
+                       struct task_struct *waiter = dio->submit.waiter;
+                       WRITE_ONCE(dio->submit.waiter, NULL);
+                       blk_wake_io_task(waiter);
+               } else if (dio->flags & IOMAP_DIO_WRITE) {
+                       struct inode *inode = file_inode(dio->iocb->ki_filp);
+
+                       INIT_WORK(&dio->aio.work, iomap_dio_complete_work);
+                       queue_work(inode->i_sb->s_dio_done_wq, &dio->aio.work);
+               } else {
+                       iomap_dio_complete_work(&dio->aio.work);
+               }
+       }
+
+       if (should_dirty) {
+               bio_check_pages_dirty(bio);
+       } else {
+               bio_release_pages(bio, false);
+               bio_put(bio);
+       }
+}
+
+static void
+iomap_dio_zero(struct iomap_dio *dio, struct iomap *iomap, loff_t pos,
+               unsigned len)
+{
+       struct page *page = ZERO_PAGE(0);
+       int flags = REQ_SYNC | REQ_IDLE;
+       struct bio *bio;
+
+       bio = bio_alloc(GFP_KERNEL, 1);
+       bio_set_dev(bio, iomap->bdev);
+       bio->bi_iter.bi_sector = iomap_sector(iomap, pos);
+       bio->bi_private = dio;
+       bio->bi_end_io = iomap_dio_bio_end_io;
+
+       get_page(page);
+       __bio_add_page(bio, page, len, 0);
+       bio_set_op_attrs(bio, REQ_OP_WRITE, flags);
+       iomap_dio_submit_bio(dio, iomap, bio);
+}
+
+static loff_t
+iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length,
+               struct iomap_dio *dio, struct iomap *iomap)
+{
+       unsigned int blkbits = blksize_bits(bdev_logical_block_size(iomap->bdev));
+       unsigned int fs_block_size = i_blocksize(inode), pad;
+       unsigned int align = iov_iter_alignment(dio->submit.iter);
+       struct iov_iter iter;
+       struct bio *bio;
+       bool need_zeroout = false;
+       bool use_fua = false;
+       int nr_pages, ret = 0;
+       size_t copied = 0;
+
+       if ((pos | length | align) & ((1 << blkbits) - 1))
+               return -EINVAL;
+
+       if (iomap->type == IOMAP_UNWRITTEN) {
+               dio->flags |= IOMAP_DIO_UNWRITTEN;
+               need_zeroout = true;
+       }
+
+       if (iomap->flags & IOMAP_F_SHARED)
+               dio->flags |= IOMAP_DIO_COW;
+
+       if (iomap->flags & IOMAP_F_NEW) {
+               need_zeroout = true;
+       } else if (iomap->type == IOMAP_MAPPED) {
+               /*
+                * Use a FUA write if we need datasync semantics, this is a pure
+                * data IO that doesn't require any metadata updates (including
+                * after IO completion such as unwritten extent conversion) and
+                * the underlying device supports FUA. This allows us to avoid
+                * cache flushes on IO completion.
+                */
+               if (!(iomap->flags & (IOMAP_F_SHARED|IOMAP_F_DIRTY)) &&
+                   (dio->flags & IOMAP_DIO_WRITE_FUA) &&
+                   blk_queue_fua(bdev_get_queue(iomap->bdev)))
+                       use_fua = true;
+       }
+
+       /*
+        * Operate on a partial iter trimmed to the extent we were called for.
+        * We'll update the iter in the dio once we're done with this extent.
+        */
+       iter = *dio->submit.iter;
+       iov_iter_truncate(&iter, length);
+
+       nr_pages = iov_iter_npages(&iter, BIO_MAX_PAGES);
+       if (nr_pages <= 0)
+               return nr_pages;
+
+       if (need_zeroout) {
+               /* zero out from the start of the block to the write offset */
+               pad = pos & (fs_block_size - 1);
+               if (pad)
+                       iomap_dio_zero(dio, iomap, pos - pad, pad);
+       }
+
+       do {
+               size_t n;
+               if (dio->error) {
+                       iov_iter_revert(dio->submit.iter, copied);
+                       return 0;
+               }
+
+               bio = bio_alloc(GFP_KERNEL, nr_pages);
+               bio_set_dev(bio, iomap->bdev);
+               bio->bi_iter.bi_sector = iomap_sector(iomap, pos);
+               bio->bi_write_hint = dio->iocb->ki_hint;
+               bio->bi_ioprio = dio->iocb->ki_ioprio;
+               bio->bi_private = dio;
+               bio->bi_end_io = iomap_dio_bio_end_io;
+
+               ret = bio_iov_iter_get_pages(bio, &iter);
+               if (unlikely(ret)) {
+                       /*
+                        * We have to stop part way through an IO. We must fall
+                        * through to the sub-block tail zeroing here, otherwise
+                        * this short IO may expose stale data in the tail of
+                        * the block we haven't written data to.
+                        */
+                       bio_put(bio);
+                       goto zero_tail;
+               }
+
+               n = bio->bi_iter.bi_size;
+               if (dio->flags & IOMAP_DIO_WRITE) {
+                       bio->bi_opf = REQ_OP_WRITE | REQ_SYNC | REQ_IDLE;
+                       if (use_fua)
+                               bio->bi_opf |= REQ_FUA;
+                       else
+                               dio->flags &= ~IOMAP_DIO_WRITE_FUA;
+                       task_io_account_write(n);
+               } else {
+                       bio->bi_opf = REQ_OP_READ;
+                       if (dio->flags & IOMAP_DIO_DIRTY)
+                               bio_set_pages_dirty(bio);
+               }
+
+               iov_iter_advance(dio->submit.iter, n);
+
+               dio->size += n;
+               pos += n;
+               copied += n;
+
+               nr_pages = iov_iter_npages(&iter, BIO_MAX_PAGES);
+               iomap_dio_submit_bio(dio, iomap, bio);
+       } while (nr_pages);
+
+       /*
+        * We need to zeroout the tail of a sub-block write if the extent type
+        * requires zeroing or the write extends beyond EOF. If we don't zero
+        * the block tail in the latter case, we can expose stale data via mmap
+        * reads of the EOF block.
+        */
+zero_tail:
+       if (need_zeroout ||
+           ((dio->flags & IOMAP_DIO_WRITE) && pos >= i_size_read(inode))) {
+               /* zero out from the end of the write to the end of the block */
+               pad = pos & (fs_block_size - 1);
+               if (pad)
+                       iomap_dio_zero(dio, iomap, pos, fs_block_size - pad);
+       }
+       return copied ? copied : ret;
+}
+
+static loff_t
+iomap_dio_hole_actor(loff_t length, struct iomap_dio *dio)
+{
+       length = iov_iter_zero(length, dio->submit.iter);
+       dio->size += length;
+       return length;
+}
+
+static loff_t
+iomap_dio_inline_actor(struct inode *inode, loff_t pos, loff_t length,
+               struct iomap_dio *dio, struct iomap *iomap)
+{
+       struct iov_iter *iter = dio->submit.iter;
+       size_t copied;
+
+       BUG_ON(pos + length > PAGE_SIZE - offset_in_page(iomap->inline_data));
+
+       if (dio->flags & IOMAP_DIO_WRITE) {
+               loff_t size = inode->i_size;
+
+               if (pos > size)
+                       memset(iomap->inline_data + size, 0, pos - size);
+               copied = copy_from_iter(iomap->inline_data + pos, length, iter);
+               if (copied) {
+                       if (pos + copied > size)
+                               i_size_write(inode, pos + copied);
+                       mark_inode_dirty(inode);
+               }
+       } else {
+               copied = copy_to_iter(iomap->inline_data + pos, length, iter);
+       }
+       dio->size += copied;
+       return copied;
+}
+
+static loff_t
+iomap_dio_actor(struct inode *inode, loff_t pos, loff_t length,
+               void *data, struct iomap *iomap)
+{
+       struct iomap_dio *dio = data;
+
+       switch (iomap->type) {
+       case IOMAP_HOLE:
+               if (WARN_ON_ONCE(dio->flags & IOMAP_DIO_WRITE))
+                       return -EIO;
+               return iomap_dio_hole_actor(length, dio);
+       case IOMAP_UNWRITTEN:
+               if (!(dio->flags & IOMAP_DIO_WRITE))
+                       return iomap_dio_hole_actor(length, dio);
+               return iomap_dio_bio_actor(inode, pos, length, dio, iomap);
+       case IOMAP_MAPPED:
+               return iomap_dio_bio_actor(inode, pos, length, dio, iomap);
+       case IOMAP_INLINE:
+               return iomap_dio_inline_actor(inode, pos, length, dio, iomap);
+       default:
+               WARN_ON_ONCE(1);
+               return -EIO;
+       }
+}
+
+/*
+ * iomap_dio_rw() always completes O_[D]SYNC writes regardless of whether the IO
+ * is being issued as AIO or not.  This allows us to optimise pure data writes
+ * to use REQ_FUA rather than requiring generic_write_sync() to issue a
+ * REQ_FLUSH post write. This is slightly tricky because a single request here
+ * can be mapped into multiple disjoint IOs and only a subset of the IOs issued
+ * may be pure data writes. In that case, we still need to do a full data sync
+ * completion.
+ */
+ssize_t
+iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
+               const struct iomap_ops *ops, iomap_dio_end_io_t end_io)
+{
+       struct address_space *mapping = iocb->ki_filp->f_mapping;
+       struct inode *inode = file_inode(iocb->ki_filp);
+       size_t count = iov_iter_count(iter);
+       loff_t pos = iocb->ki_pos, start = pos;
+       loff_t end = iocb->ki_pos + count - 1, ret = 0;
+       unsigned int flags = IOMAP_DIRECT;
+       bool wait_for_completion = is_sync_kiocb(iocb);
+       struct blk_plug plug;
+       struct iomap_dio *dio;
+
+       lockdep_assert_held(&inode->i_rwsem);
+
+       if (!count)
+               return 0;
+
+       dio = kmalloc(sizeof(*dio), GFP_KERNEL);
+       if (!dio)
+               return -ENOMEM;
+
+       dio->iocb = iocb;
+       atomic_set(&dio->ref, 1);
+       dio->size = 0;
+       dio->i_size = i_size_read(inode);
+       dio->end_io = end_io;
+       dio->error = 0;
+       dio->flags = 0;
+
+       dio->submit.iter = iter;
+       dio->submit.waiter = current;
+       dio->submit.cookie = BLK_QC_T_NONE;
+       dio->submit.last_queue = NULL;
+
+       if (iov_iter_rw(iter) == READ) {
+               if (pos >= dio->i_size)
+                       goto out_free_dio;
+
+               if (iter_is_iovec(iter) && iov_iter_rw(iter) == READ)
+                       dio->flags |= IOMAP_DIO_DIRTY;
+       } else {
+               flags |= IOMAP_WRITE;
+               dio->flags |= IOMAP_DIO_WRITE;
+
+               /* for data sync or sync, we need sync completion processing */
+               if (iocb->ki_flags & IOCB_DSYNC)
+                       dio->flags |= IOMAP_DIO_NEED_SYNC;
+
+               /*
+                * For datasync only writes, we optimistically try using FUA for
+                * this IO.  Any non-FUA write that occurs will clear this flag,
+                * hence we know before completion whether a cache flush is
+                * necessary.
+                */
+               if ((iocb->ki_flags & (IOCB_DSYNC | IOCB_SYNC)) == IOCB_DSYNC)
+                       dio->flags |= IOMAP_DIO_WRITE_FUA;
+       }
+
+       if (iocb->ki_flags & IOCB_NOWAIT) {
+               if (filemap_range_has_page(mapping, start, end)) {
+                       ret = -EAGAIN;
+                       goto out_free_dio;
+               }
+               flags |= IOMAP_NOWAIT;
+       }
+
+       ret = filemap_write_and_wait_range(mapping, start, end);
+       if (ret)
+               goto out_free_dio;
+
+       /*
+        * Try to invalidate cache pages for the range we're direct
+        * writing.  If this invalidation fails, tough, the write will
+        * still work, but racing two incompatible write paths is a
+        * pretty crazy thing to do, so we don't support it 100%.
+        */
+       ret = invalidate_inode_pages2_range(mapping,
+                       start >> PAGE_SHIFT, end >> PAGE_SHIFT);
+       if (ret)
+               dio_warn_stale_pagecache(iocb->ki_filp);
+       ret = 0;
+
+       if (iov_iter_rw(iter) == WRITE && !wait_for_completion &&
+           !inode->i_sb->s_dio_done_wq) {
+               ret = sb_init_dio_done_wq(inode->i_sb);
+               if (ret < 0)
+                       goto out_free_dio;
+       }
+
+       inode_dio_begin(inode);
+
+       blk_start_plug(&plug);
+       do {
+               ret = iomap_apply(inode, pos, count, flags, ops, dio,
+                               iomap_dio_actor);
+               if (ret <= 0) {
+                       /* magic error code to fall back to buffered I/O */
+                       if (ret == -ENOTBLK) {
+                               wait_for_completion = true;
+                               ret = 0;
+                       }
+                       break;
+               }
+               pos += ret;
+
+               if (iov_iter_rw(iter) == READ && pos >= dio->i_size)
+                       break;
+       } while ((count = iov_iter_count(iter)) > 0);
+       blk_finish_plug(&plug);
+
+       if (ret < 0)
+               iomap_dio_set_error(dio, ret);
+
+       /*
+        * If all the writes we issued were FUA, we don't need to flush the
+        * cache on IO completion. Clear the sync flag for this case.
+        */
+       if (dio->flags & IOMAP_DIO_WRITE_FUA)
+               dio->flags &= ~IOMAP_DIO_NEED_SYNC;
+
+       WRITE_ONCE(iocb->ki_cookie, dio->submit.cookie);
+       WRITE_ONCE(iocb->private, dio->submit.last_queue);
+
+       /*
+        * We are about to drop our additional submission reference, which
+        * might be the last reference to the dio.  There are three three
+        * different ways we can progress here:
+        *
+        *  (a) If this is the last reference we will always complete and free
+        *      the dio ourselves.
+        *  (b) If this is not the last reference, and we serve an asynchronous
+        *      iocb, we must never touch the dio after the decrement, the
+        *      I/O completion handler will complete and free it.
+        *  (c) If this is not the last reference, but we serve a synchronous
+        *      iocb, the I/O completion handler will wake us up on the drop
+        *      of the final reference, and we will complete and free it here
+        *      after we got woken by the I/O completion handler.
+        */
+       dio->wait_for_completion = wait_for_completion;
+       if (!atomic_dec_and_test(&dio->ref)) {
+               if (!wait_for_completion)
+                       return -EIOCBQUEUED;
+
+               for (;;) {
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       if (!READ_ONCE(dio->submit.waiter))
+                               break;
+
+                       if (!(iocb->ki_flags & IOCB_HIPRI) ||
+                           !dio->submit.last_queue ||
+                           !blk_poll(dio->submit.last_queue,
+                                        dio->submit.cookie, true))
+                               io_schedule();
+               }
+               __set_current_state(TASK_RUNNING);
+       }
+
+       return iomap_dio_complete(dio);
+
+out_free_dio:
+       kfree(dio);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(iomap_dio_rw);
diff --git a/fs/iomap/fiemap.c b/fs/iomap/fiemap.c
new file mode 100644 (file)
index 0000000..f26fdd3
--- /dev/null
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016-2018 Christoph Hellwig.
+ */
+#include <linux/module.h>
+#include <linux/compiler.h>
+#include <linux/fs.h>
+#include <linux/iomap.h>
+
+struct fiemap_ctx {
+       struct fiemap_extent_info *fi;
+       struct iomap prev;
+};
+
+static int iomap_to_fiemap(struct fiemap_extent_info *fi,
+               struct iomap *iomap, u32 flags)
+{
+       switch (iomap->type) {
+       case IOMAP_HOLE:
+               /* skip holes */
+               return 0;
+       case IOMAP_DELALLOC:
+               flags |= FIEMAP_EXTENT_DELALLOC | FIEMAP_EXTENT_UNKNOWN;
+               break;
+       case IOMAP_MAPPED:
+               break;
+       case IOMAP_UNWRITTEN:
+               flags |= FIEMAP_EXTENT_UNWRITTEN;
+               break;
+       case IOMAP_INLINE:
+               flags |= FIEMAP_EXTENT_DATA_INLINE;
+               break;
+       }
+
+       if (iomap->flags & IOMAP_F_MERGED)
+               flags |= FIEMAP_EXTENT_MERGED;
+       if (iomap->flags & IOMAP_F_SHARED)
+               flags |= FIEMAP_EXTENT_SHARED;
+
+       return fiemap_fill_next_extent(fi, iomap->offset,
+                       iomap->addr != IOMAP_NULL_ADDR ? iomap->addr : 0,
+                       iomap->length, flags);
+}
+
+static loff_t
+iomap_fiemap_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
+               struct iomap *iomap)
+{
+       struct fiemap_ctx *ctx = data;
+       loff_t ret = length;
+
+       if (iomap->type == IOMAP_HOLE)
+               return length;
+
+       ret = iomap_to_fiemap(ctx->fi, &ctx->prev, 0);
+       ctx->prev = *iomap;
+       switch (ret) {
+       case 0:         /* success */
+               return length;
+       case 1:         /* extent array full */
+               return 0;
+       default:
+               return ret;
+       }
+}
+
+int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi,
+               loff_t start, loff_t len, const struct iomap_ops *ops)
+{
+       struct fiemap_ctx ctx;
+       loff_t ret;
+
+       memset(&ctx, 0, sizeof(ctx));
+       ctx.fi = fi;
+       ctx.prev.type = IOMAP_HOLE;
+
+       ret = fiemap_check_flags(fi, FIEMAP_FLAG_SYNC);
+       if (ret)
+               return ret;
+
+       if (fi->fi_flags & FIEMAP_FLAG_SYNC) {
+               ret = filemap_write_and_wait(inode->i_mapping);
+               if (ret)
+                       return ret;
+       }
+
+       while (len > 0) {
+               ret = iomap_apply(inode, start, len, IOMAP_REPORT, ops, &ctx,
+                               iomap_fiemap_actor);
+               /* inode with no (attribute) mapping will give ENOENT */
+               if (ret == -ENOENT)
+                       break;
+               if (ret < 0)
+                       return ret;
+               if (ret == 0)
+                       break;
+
+               start += ret;
+               len -= ret;
+       }
+
+       if (ctx.prev.type != IOMAP_HOLE) {
+               ret = iomap_to_fiemap(fi, &ctx.prev, FIEMAP_EXTENT_LAST);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(iomap_fiemap);
+
+static loff_t
+iomap_bmap_actor(struct inode *inode, loff_t pos, loff_t length,
+               void *data, struct iomap *iomap)
+{
+       sector_t *bno = data, addr;
+
+       if (iomap->type == IOMAP_MAPPED) {
+               addr = (pos - iomap->offset + iomap->addr) >> inode->i_blkbits;
+               if (addr > INT_MAX)
+                       WARN(1, "would truncate bmap result\n");
+               else
+                       *bno = addr;
+       }
+       return 0;
+}
+
+/* legacy ->bmap interface.  0 is the error return (!) */
+sector_t
+iomap_bmap(struct address_space *mapping, sector_t bno,
+               const struct iomap_ops *ops)
+{
+       struct inode *inode = mapping->host;
+       loff_t pos = bno << inode->i_blkbits;
+       unsigned blocksize = i_blocksize(inode);
+
+       if (filemap_write_and_wait(mapping))
+               return 0;
+
+       bno = 0;
+       iomap_apply(inode, pos, blocksize, 0, ops, &bno, iomap_bmap_actor);
+       return bno;
+}
+EXPORT_SYMBOL_GPL(iomap_bmap);
diff --git a/fs/iomap/seek.c b/fs/iomap/seek.c
new file mode 100644 (file)
index 0000000..c04bad4
--- /dev/null
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ * Copyright (c) 2018 Christoph Hellwig.
+ */
+#include <linux/module.h>
+#include <linux/compiler.h>
+#include <linux/fs.h>
+#include <linux/iomap.h>
+#include <linux/pagemap.h>
+#include <linux/pagevec.h>
+
+/*
+ * Seek for SEEK_DATA / SEEK_HOLE within @page, starting at @lastoff.
+ * Returns true if found and updates @lastoff to the offset in file.
+ */
+static bool
+page_seek_hole_data(struct inode *inode, struct page *page, loff_t *lastoff,
+               int whence)
+{
+       const struct address_space_operations *ops = inode->i_mapping->a_ops;
+       unsigned int bsize = i_blocksize(inode), off;
+       bool seek_data = whence == SEEK_DATA;
+       loff_t poff = page_offset(page);
+
+       if (WARN_ON_ONCE(*lastoff >= poff + PAGE_SIZE))
+               return false;
+
+       if (*lastoff < poff) {
+               /*
+                * Last offset smaller than the start of the page means we found
+                * a hole:
+                */
+               if (whence == SEEK_HOLE)
+                       return true;
+               *lastoff = poff;
+       }
+
+       /*
+        * Just check the page unless we can and should check block ranges:
+        */
+       if (bsize == PAGE_SIZE || !ops->is_partially_uptodate)
+               return PageUptodate(page) == seek_data;
+
+       lock_page(page);
+       if (unlikely(page->mapping != inode->i_mapping))
+               goto out_unlock_not_found;
+
+       for (off = 0; off < PAGE_SIZE; off += bsize) {
+               if (offset_in_page(*lastoff) >= off + bsize)
+                       continue;
+               if (ops->is_partially_uptodate(page, off, bsize) == seek_data) {
+                       unlock_page(page);
+                       return true;
+               }
+               *lastoff = poff + off + bsize;
+       }
+
+out_unlock_not_found:
+       unlock_page(page);
+       return false;
+}
+
+/*
+ * Seek for SEEK_DATA / SEEK_HOLE in the page cache.
+ *
+ * Within unwritten extents, the page cache determines which parts are holes
+ * and which are data: uptodate buffer heads count as data; everything else
+ * counts as a hole.
+ *
+ * Returns the resulting offset on successs, and -ENOENT otherwise.
+ */
+static loff_t
+page_cache_seek_hole_data(struct inode *inode, loff_t offset, loff_t length,
+               int whence)
+{
+       pgoff_t index = offset >> PAGE_SHIFT;
+       pgoff_t end = DIV_ROUND_UP(offset + length, PAGE_SIZE);
+       loff_t lastoff = offset;
+       struct pagevec pvec;
+
+       if (length <= 0)
+               return -ENOENT;
+
+       pagevec_init(&pvec);
+
+       do {
+               unsigned nr_pages, i;
+
+               nr_pages = pagevec_lookup_range(&pvec, inode->i_mapping, &index,
+                                               end - 1);
+               if (nr_pages == 0)
+                       break;
+
+               for (i = 0; i < nr_pages; i++) {
+                       struct page *page = pvec.pages[i];
+
+                       if (page_seek_hole_data(inode, page, &lastoff, whence))
+                               goto check_range;
+                       lastoff = page_offset(page) + PAGE_SIZE;
+               }
+               pagevec_release(&pvec);
+       } while (index < end);
+
+       /* When no page at lastoff and we are not done, we found a hole. */
+       if (whence != SEEK_HOLE)
+               goto not_found;
+
+check_range:
+       if (lastoff < offset + length)
+               goto out;
+not_found:
+       lastoff = -ENOENT;
+out:
+       pagevec_release(&pvec);
+       return lastoff;
+}
+
+
+static loff_t
+iomap_seek_hole_actor(struct inode *inode, loff_t offset, loff_t length,
+                     void *data, struct iomap *iomap)
+{
+       switch (iomap->type) {
+       case IOMAP_UNWRITTEN:
+               offset = page_cache_seek_hole_data(inode, offset, length,
+                                                  SEEK_HOLE);
+               if (offset < 0)
+                       return length;
+               /* fall through */
+       case IOMAP_HOLE:
+               *(loff_t *)data = offset;
+               return 0;
+       default:
+               return length;
+       }
+}
+
+loff_t
+iomap_seek_hole(struct inode *inode, loff_t offset, const struct iomap_ops *ops)
+{
+       loff_t size = i_size_read(inode);
+       loff_t length = size - offset;
+       loff_t ret;
+
+       /* Nothing to be found before or beyond the end of the file. */
+       if (offset < 0 || offset >= size)
+               return -ENXIO;
+
+       while (length > 0) {
+               ret = iomap_apply(inode, offset, length, IOMAP_REPORT, ops,
+                                 &offset, iomap_seek_hole_actor);
+               if (ret < 0)
+                       return ret;
+               if (ret == 0)
+                       break;
+
+               offset += ret;
+               length -= ret;
+       }
+
+       return offset;
+}
+EXPORT_SYMBOL_GPL(iomap_seek_hole);
+
+static loff_t
+iomap_seek_data_actor(struct inode *inode, loff_t offset, loff_t length,
+                     void *data, struct iomap *iomap)
+{
+       switch (iomap->type) {
+       case IOMAP_HOLE:
+               return length;
+       case IOMAP_UNWRITTEN:
+               offset = page_cache_seek_hole_data(inode, offset, length,
+                                                  SEEK_DATA);
+               if (offset < 0)
+                       return length;
+               /*FALLTHRU*/
+       default:
+               *(loff_t *)data = offset;
+               return 0;
+       }
+}
+
+loff_t
+iomap_seek_data(struct inode *inode, loff_t offset, const struct iomap_ops *ops)
+{
+       loff_t size = i_size_read(inode);
+       loff_t length = size - offset;
+       loff_t ret;
+
+       /* Nothing to be found before or beyond the end of the file. */
+       if (offset < 0 || offset >= size)
+               return -ENXIO;
+
+       while (length > 0) {
+               ret = iomap_apply(inode, offset, length, IOMAP_REPORT, ops,
+                                 &offset, iomap_seek_data_actor);
+               if (ret < 0)
+                       return ret;
+               if (ret == 0)
+                       break;
+
+               offset += ret;
+               length -= ret;
+       }
+
+       if (length <= 0)
+               return -ENXIO;
+       return offset;
+}
+EXPORT_SYMBOL_GPL(iomap_seek_data);
diff --git a/fs/iomap/swapfile.c b/fs/iomap/swapfile.c
new file mode 100644 (file)
index 0000000..152a230
--- /dev/null
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Oracle.  All Rights Reserved.
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ */
+#include <linux/module.h>
+#include <linux/compiler.h>
+#include <linux/fs.h>
+#include <linux/iomap.h>
+#include <linux/swap.h>
+
+/* Swapfile activation */
+
+struct iomap_swapfile_info {
+       struct iomap iomap;             /* accumulated iomap */
+       struct swap_info_struct *sis;
+       uint64_t lowest_ppage;          /* lowest physical addr seen (pages) */
+       uint64_t highest_ppage;         /* highest physical addr seen (pages) */
+       unsigned long nr_pages;         /* number of pages collected */
+       int nr_extents;                 /* extent count */
+};
+
+/*
+ * Collect physical extents for this swap file.  Physical extents reported to
+ * the swap code must be trimmed to align to a page boundary.  The logical
+ * offset within the file is irrelevant since the swapfile code maps logical
+ * page numbers of the swap device to the physical page-aligned extents.
+ */
+static int iomap_swapfile_add_extent(struct iomap_swapfile_info *isi)
+{
+       struct iomap *iomap = &isi->iomap;
+       unsigned long nr_pages;
+       uint64_t first_ppage;
+       uint64_t first_ppage_reported;
+       uint64_t next_ppage;
+       int error;
+
+       /*
+        * Round the start up and the end down so that the physical
+        * extent aligns to a page boundary.
+        */
+       first_ppage = ALIGN(iomap->addr, PAGE_SIZE) >> PAGE_SHIFT;
+       next_ppage = ALIGN_DOWN(iomap->addr + iomap->length, PAGE_SIZE) >>
+                       PAGE_SHIFT;
+
+       /* Skip too-short physical extents. */
+       if (first_ppage >= next_ppage)
+               return 0;
+       nr_pages = next_ppage - first_ppage;
+
+       /*
+        * Calculate how much swap space we're adding; the first page contains
+        * the swap header and doesn't count.  The mm still wants that first
+        * page fed to add_swap_extent, however.
+        */
+       first_ppage_reported = first_ppage;
+       if (iomap->offset == 0)
+               first_ppage_reported++;
+       if (isi->lowest_ppage > first_ppage_reported)
+               isi->lowest_ppage = first_ppage_reported;
+       if (isi->highest_ppage < (next_ppage - 1))
+               isi->highest_ppage = next_ppage - 1;
+
+       /* Add extent, set up for the next call. */
+       error = add_swap_extent(isi->sis, isi->nr_pages, nr_pages, first_ppage);
+       if (error < 0)
+               return error;
+       isi->nr_extents += error;
+       isi->nr_pages += nr_pages;
+       return 0;
+}
+
+/*
+ * Accumulate iomaps for this swap file.  We have to accumulate iomaps because
+ * swap only cares about contiguous page-aligned physical extents and makes no
+ * distinction between written and unwritten extents.
+ */
+static loff_t iomap_swapfile_activate_actor(struct inode *inode, loff_t pos,
+               loff_t count, void *data, struct iomap *iomap)
+{
+       struct iomap_swapfile_info *isi = data;
+       int error;
+
+       switch (iomap->type) {
+       case IOMAP_MAPPED:
+       case IOMAP_UNWRITTEN:
+               /* Only real or unwritten extents. */
+               break;
+       case IOMAP_INLINE:
+               /* No inline data. */
+               pr_err("swapon: file is inline\n");
+               return -EINVAL;
+       default:
+               pr_err("swapon: file has unallocated extents\n");
+               return -EINVAL;
+       }
+
+       /* No uncommitted metadata or shared blocks. */
+       if (iomap->flags & IOMAP_F_DIRTY) {
+               pr_err("swapon: file is not committed\n");
+               return -EINVAL;
+       }
+       if (iomap->flags & IOMAP_F_SHARED) {
+               pr_err("swapon: file has shared extents\n");
+               return -EINVAL;
+       }
+
+       /* Only one bdev per swap file. */
+       if (iomap->bdev != isi->sis->bdev) {
+               pr_err("swapon: file is on multiple devices\n");
+               return -EINVAL;
+       }
+
+       if (isi->iomap.length == 0) {
+               /* No accumulated extent, so just store it. */
+               memcpy(&isi->iomap, iomap, sizeof(isi->iomap));
+       } else if (isi->iomap.addr + isi->iomap.length == iomap->addr) {
+               /* Append this to the accumulated extent. */
+               isi->iomap.length += iomap->length;
+       } else {
+               /* Otherwise, add the retained iomap and store this one. */
+               error = iomap_swapfile_add_extent(isi);
+               if (error)
+                       return error;
+               memcpy(&isi->iomap, iomap, sizeof(isi->iomap));
+       }
+       return count;
+}
+
+/*
+ * Iterate a swap file's iomaps to construct physical extents that can be
+ * passed to the swapfile subsystem.
+ */
+int iomap_swapfile_activate(struct swap_info_struct *sis,
+               struct file *swap_file, sector_t *pagespan,
+               const struct iomap_ops *ops)
+{
+       struct iomap_swapfile_info isi = {
+               .sis = sis,
+               .lowest_ppage = (sector_t)-1ULL,
+       };
+       struct address_space *mapping = swap_file->f_mapping;
+       struct inode *inode = mapping->host;
+       loff_t pos = 0;
+       loff_t len = ALIGN_DOWN(i_size_read(inode), PAGE_SIZE);
+       loff_t ret;
+
+       /*
+        * Persist all file mapping metadata so that we won't have any
+        * IOMAP_F_DIRTY iomaps.
+        */
+       ret = vfs_fsync(swap_file, 1);
+       if (ret)
+               return ret;
+
+       while (len > 0) {
+               ret = iomap_apply(inode, pos, len, IOMAP_REPORT,
+                               ops, &isi, iomap_swapfile_activate_actor);
+               if (ret <= 0)
+                       return ret;
+
+               pos += ret;
+               len -= ret;
+       }
+
+       if (isi.iomap.length) {
+               ret = iomap_swapfile_add_extent(&isi);
+               if (ret)
+                       return ret;
+       }
+
+       *pagespan = 1 + isi.highest_ppage - isi.lowest_ppage;
+       sis->max = isi.nr_pages;
+       sis->pages = isi.nr_pages - 1;
+       sis->highest_bit = isi.nr_pages - 1;
+       return isi.nr_extents;
+}
+EXPORT_SYMBOL_GPL(iomap_swapfile_activate);
index 7e52e77..c9b2850 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/exportfs.h>
 #include <linux/writeback.h>
 #include <linux/buffer_head.h> /* sync_mapping_buffers */
+#include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 
 #include <linux/uaccess.h>
 
@@ -236,34 +238,22 @@ static const struct super_operations simple_super_operations = {
        .statfs         = simple_statfs,
 };
 
-/*
- * Common helper for pseudo-filesystems (sockfs, pipefs, bdev - stuff that
- * will never be mountable)
- */
-struct dentry *mount_pseudo_xattr(struct file_system_type *fs_type, char *name,
-       const struct super_operations *ops, const struct xattr_handler **xattr,
-       const struct dentry_operations *dops, unsigned long magic)
+static int pseudo_fs_fill_super(struct super_block *s, struct fs_context *fc)
 {
-       struct super_block *s;
-       struct dentry *dentry;
+       struct pseudo_fs_context *ctx = fc->fs_private;
        struct inode *root;
-       struct qstr d_name = QSTR_INIT(name, strlen(name));
-
-       s = sget_userns(fs_type, NULL, set_anon_super, SB_KERNMOUNT|SB_NOUSER,
-                       &init_user_ns, NULL);
-       if (IS_ERR(s))
-               return ERR_CAST(s);
 
        s->s_maxbytes = MAX_LFS_FILESIZE;
        s->s_blocksize = PAGE_SIZE;
        s->s_blocksize_bits = PAGE_SHIFT;
-       s->s_magic = magic;
-       s->s_op = ops ? ops : &simple_super_operations;
-       s->s_xattr = xattr;
+       s->s_magic = ctx->magic;
+       s->s_op = ctx->ops ?: &simple_super_operations;
+       s->s_xattr = ctx->xattr;
        s->s_time_gran = 1;
        root = new_inode(s);
        if (!root)
-               goto Enomem;
+               return -ENOMEM;
+
        /*
         * since this is the first inode, make it number 1. New inodes created
         * after this must take care not to collide with it (by passing
@@ -272,22 +262,48 @@ struct dentry *mount_pseudo_xattr(struct file_system_type *fs_type, char *name,
        root->i_ino = 1;
        root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
        root->i_atime = root->i_mtime = root->i_ctime = current_time(root);
-       dentry = __d_alloc(s, &d_name);
-       if (!dentry) {
-               iput(root);
-               goto Enomem;
+       s->s_root = d_make_root(root);
+       if (!s->s_root)
+               return -ENOMEM;
+       s->s_d_op = ctx->dops;
+       return 0;
+}
+
+static int pseudo_fs_get_tree(struct fs_context *fc)
+{
+       return get_tree_nodev(fc, pseudo_fs_fill_super);
+}
+
+static void pseudo_fs_free(struct fs_context *fc)
+{
+       kfree(fc->fs_private);
+}
+
+static const struct fs_context_operations pseudo_fs_context_ops = {
+       .free           = pseudo_fs_free,
+       .get_tree       = pseudo_fs_get_tree,
+};
+
+/*
+ * Common helper for pseudo-filesystems (sockfs, pipefs, bdev - stuff that
+ * will never be mountable)
+ */
+struct pseudo_fs_context *init_pseudo(struct fs_context *fc,
+                                       unsigned long magic)
+{
+       struct pseudo_fs_context *ctx;
+
+       ctx = kzalloc(sizeof(struct pseudo_fs_context), GFP_KERNEL);
+       if (likely(ctx)) {
+               ctx->magic = magic;
+               fc->fs_private = ctx;
+               fc->ops = &pseudo_fs_context_ops;
+               fc->sb_flags |= SB_NOUSER;
+               fc->global = true;
        }
-       d_instantiate(dentry, root);
-       s->s_root = dentry;
-       s->s_d_op = dops;
-       s->s_flags |= SB_ACTIVE;
-       return dget(s->s_root);
-
-Enomem:
-       deactivate_locked_super(s);
-       return ERR_PTR(-ENOMEM);
+       return ctx;
 }
-EXPORT_SYMBOL(mount_pseudo_xattr);
+EXPORT_SYMBOL(init_pseudo);
 
 int simple_open(struct inode *inode, struct file *file)
 {
index 6250de5..711a409 100644 (file)
@@ -58,7 +58,10 @@ struct mount {
        struct mount *mnt_master;       /* slave is on master->mnt_slave_list */
        struct mnt_namespace *mnt_ns;   /* containing namespace */
        struct mountpoint *mnt_mp;      /* where is it mounted */
-       struct hlist_node mnt_mp_list;  /* list mounts with the same mountpoint */
+       union {
+               struct hlist_node mnt_mp_list;  /* list mounts with the same mountpoint */
+               struct hlist_node mnt_umount;
+       };
        struct list_head mnt_umounting; /* list entry for umount propagation */
 #ifdef CONFIG_FSNOTIFY
        struct fsnotify_mark_connector __rcu *mnt_fsnotify_marks;
@@ -68,8 +71,7 @@ struct mount {
        int mnt_group_id;               /* peer group identifier */
        int mnt_expiry_mark;            /* true if marked for expiry */
        struct hlist_head mnt_pins;
-       struct fs_pin mnt_umount;
-       struct dentry *mnt_ex_mountpoint;
+       struct hlist_head mnt_stuck_children;
 } __randomize_layout;
 
 #define MNT_NS_INTERNAL ERR_PTR(-EINVAL) /* distinct from any mnt_namespace */
index 6fbc912..6464ea4 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/sched/task.h>
 #include <uapi/linux/mount.h>
 #include <linux/fs_context.h>
+#include <linux/shmem_fs.h>
 
 #include "pnode.h"
 #include "internal.h"
@@ -69,6 +70,8 @@ static struct hlist_head *mount_hashtable __read_mostly;
 static struct hlist_head *mountpoint_hashtable __read_mostly;
 static struct kmem_cache *mnt_cache __read_mostly;
 static DECLARE_RWSEM(namespace_sem);
+static HLIST_HEAD(unmounted);  /* protected by namespace_sem */
+static LIST_HEAD(ex_mountpoints); /* protected by namespace_sem */
 
 /* /sys/fs */
 struct kobject *fs_kobj;
@@ -169,14 +172,6 @@ unsigned int mnt_get_count(struct mount *mnt)
 #endif
 }
 
-static void drop_mountpoint(struct fs_pin *p)
-{
-       struct mount *m = container_of(p, struct mount, mnt_umount);
-       dput(m->mnt_ex_mountpoint);
-       pin_remove(p);
-       mntput(&m->mnt);
-}
-
 static struct mount *alloc_vfsmnt(const char *name)
 {
        struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
@@ -214,7 +209,7 @@ static struct mount *alloc_vfsmnt(const char *name)
                INIT_LIST_HEAD(&mnt->mnt_slave);
                INIT_HLIST_NODE(&mnt->mnt_mp_list);
                INIT_LIST_HEAD(&mnt->mnt_umounting);
-               init_fs_pin(&mnt->mnt_umount, drop_mountpoint);
+               INIT_HLIST_HEAD(&mnt->mnt_stuck_children);
        }
        return mnt;
 
@@ -739,7 +734,7 @@ mountpoint:
 
        /* Add the new mountpoint to the hash table */
        read_seqlock_excl(&mount_lock);
-       new->m_dentry = dentry;
+       new->m_dentry = dget(dentry);
        new->m_count = 1;
        hlist_add_head(&new->m_hash, mp_hash(dentry));
        INIT_HLIST_HEAD(&new->m_list);
@@ -752,7 +747,11 @@ done:
        return mp;
 }
 
-static void put_mountpoint(struct mountpoint *mp)
+/*
+ * vfsmount lock must be held.  Additionally, the caller is responsible
+ * for serializing calls for given disposal list.
+ */
+static void __put_mountpoint(struct mountpoint *mp, struct list_head *list)
 {
        if (!--mp->m_count) {
                struct dentry *dentry = mp->m_dentry;
@@ -760,11 +759,18 @@ static void put_mountpoint(struct mountpoint *mp)
                spin_lock(&dentry->d_lock);
                dentry->d_flags &= ~DCACHE_MOUNTED;
                spin_unlock(&dentry->d_lock);
+               dput_to_list(dentry, list);
                hlist_del(&mp->m_hash);
                kfree(mp);
        }
 }
 
+/* called with namespace_lock and vfsmount lock */
+static void put_mountpoint(struct mountpoint *mp)
+{
+       __put_mountpoint(mp, &ex_mountpoints);
+}
+
 static inline int check_mnt(struct mount *mnt)
 {
        return mnt->mnt_ns == current->nsproxy->mnt_ns;
@@ -795,25 +801,17 @@ static void __touch_mnt_namespace(struct mnt_namespace *ns)
 /*
  * vfsmount lock must be held for write
  */
-static void unhash_mnt(struct mount *mnt)
+static struct mountpoint *unhash_mnt(struct mount *mnt)
 {
+       struct mountpoint *mp;
        mnt->mnt_parent = mnt;
        mnt->mnt_mountpoint = mnt->mnt.mnt_root;
        list_del_init(&mnt->mnt_child);
        hlist_del_init_rcu(&mnt->mnt_hash);
        hlist_del_init(&mnt->mnt_mp_list);
-       put_mountpoint(mnt->mnt_mp);
+       mp = mnt->mnt_mp;
        mnt->mnt_mp = NULL;
-}
-
-/*
- * vfsmount lock must be held for write
- */
-static void detach_mnt(struct mount *mnt, struct path *old_path)
-{
-       old_path->dentry = mnt->mnt_mountpoint;
-       old_path->mnt = &mnt->mnt_parent->mnt;
-       unhash_mnt(mnt);
+       return mp;
 }
 
 /*
@@ -821,9 +819,7 @@ static void detach_mnt(struct mount *mnt, struct path *old_path)
  */
 static void umount_mnt(struct mount *mnt)
 {
-       /* old mountpoint will be dropped when we can do that */
-       mnt->mnt_ex_mountpoint = mnt->mnt_mountpoint;
-       unhash_mnt(mnt);
+       put_mountpoint(unhash_mnt(mnt));
 }
 
 /*
@@ -835,7 +831,7 @@ void mnt_set_mountpoint(struct mount *mnt,
 {
        mp->m_count++;
        mnt_add_count(mnt, 1);  /* essentially, that's mntget */
-       child_mnt->mnt_mountpoint = dget(mp->m_dentry);
+       child_mnt->mnt_mountpoint = mp->m_dentry;
        child_mnt->mnt_parent = mnt;
        child_mnt->mnt_mp = mp;
        hlist_add_head(&child_mnt->mnt_mp_list, &mp->m_list);
@@ -862,7 +858,6 @@ static void attach_mnt(struct mount *mnt,
 void mnt_change_mountpoint(struct mount *parent, struct mountpoint *mp, struct mount *mnt)
 {
        struct mountpoint *old_mp = mnt->mnt_mp;
-       struct dentry *old_mountpoint = mnt->mnt_mountpoint;
        struct mount *old_parent = mnt->mnt_parent;
 
        list_del_init(&mnt->mnt_child);
@@ -872,22 +867,6 @@ void mnt_change_mountpoint(struct mount *parent, struct mountpoint *mp, struct m
        attach_mnt(mnt, parent, mp);
 
        put_mountpoint(old_mp);
-
-       /*
-        * Safely avoid even the suggestion this code might sleep or
-        * lock the mount hash by taking advantage of the knowledge that
-        * mnt_change_mountpoint will not release the final reference
-        * to a mountpoint.
-        *
-        * During mounting, the mount passed in as the parent mount will
-        * continue to use the old mountpoint and during unmounting, the
-        * old mountpoint will continue to exist until namespace_unlock,
-        * which happens well after mnt_change_mountpoint.
-        */
-       spin_lock(&old_mountpoint->d_lock);
-       old_mountpoint->d_lockref.count--;
-       spin_unlock(&old_mountpoint->d_lock);
-
        mnt_add_count(old_parent, -1);
 }
 
@@ -1102,19 +1081,22 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
 
 static void cleanup_mnt(struct mount *mnt)
 {
+       struct hlist_node *p;
+       struct mount *m;
        /*
-        * This probably indicates that somebody messed
-        * up a mnt_want/drop_write() pair.  If this
-        * happens, the filesystem was probably unable
-        * to make r/w->r/o transitions.
-        */
-       /*
+        * The warning here probably indicates that somebody messed
+        * up a mnt_want/drop_write() pair.  If this happens, the
+        * filesystem was probably unable to make r/w->r/o transitions.
         * The locking used to deal with mnt_count decrement provides barriers,
         * so mnt_get_writers() below is safe.
         */
        WARN_ON(mnt_get_writers(mnt));
        if (unlikely(mnt->mnt_pins.first))
                mnt_pin_kill(mnt);
+       hlist_for_each_entry_safe(m, p, &mnt->mnt_stuck_children, mnt_umount) {
+               hlist_del(&m->mnt_umount);
+               mntput(&m->mnt);
+       }
        fsnotify_vfsmount_delete(&mnt->mnt);
        dput(mnt->mnt.mnt_root);
        deactivate_super(mnt->mnt.mnt_sb);
@@ -1140,6 +1122,8 @@ static DECLARE_DELAYED_WORK(delayed_mntput_work, delayed_mntput);
 
 static void mntput_no_expire(struct mount *mnt)
 {
+       LIST_HEAD(list);
+
        rcu_read_lock();
        if (likely(READ_ONCE(mnt->mnt_ns))) {
                /*
@@ -1180,10 +1164,12 @@ static void mntput_no_expire(struct mount *mnt)
        if (unlikely(!list_empty(&mnt->mnt_mounts))) {
                struct mount *p, *tmp;
                list_for_each_entry_safe(p, tmp, &mnt->mnt_mounts,  mnt_child) {
-                       umount_mnt(p);
+                       __put_mountpoint(unhash_mnt(p), &list);
+                       hlist_add_head(&p->mnt_umount, &mnt->mnt_stuck_children);
                }
        }
        unlock_mount_hash();
+       shrink_dentry_list(&list);
 
        if (likely(!(mnt->mnt.mnt_flags & MNT_INTERNAL))) {
                struct task_struct *task = current;
@@ -1369,22 +1355,29 @@ int may_umount(struct vfsmount *mnt)
 
 EXPORT_SYMBOL(may_umount);
 
-static HLIST_HEAD(unmounted);  /* protected by namespace_sem */
-
 static void namespace_unlock(void)
 {
        struct hlist_head head;
+       struct hlist_node *p;
+       struct mount *m;
+       LIST_HEAD(list);
 
        hlist_move_list(&unmounted, &head);
+       list_splice_init(&ex_mountpoints, &list);
 
        up_write(&namespace_sem);
 
+       shrink_dentry_list(&list);
+
        if (likely(hlist_empty(&head)))
                return;
 
        synchronize_rcu_expedited();
 
-       group_pin_kill(&head);
+       hlist_for_each_entry_safe(m, p, &head, mnt_umount) {
+               hlist_del(&m->mnt_umount);
+               mntput(&m->mnt);
+       }
 }
 
 static inline void namespace_lock(void)
@@ -1471,8 +1464,6 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
 
                disconnect = disconnect_mount(p, how);
 
-               pin_insert_group(&p->mnt_umount, &p->mnt_parent->mnt,
-                                disconnect ? &unmounted : NULL);
                if (mnt_has_parent(p)) {
                        mnt_add_count(p->mnt_parent, -1);
                        if (!disconnect) {
@@ -1480,6 +1471,7 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
                                list_add_tail(&p->mnt_child, &p->mnt_parent->mnt_mounts);
                        } else {
                                umount_mnt(p);
+                               hlist_add_head(&p->mnt_umount, &unmounted);
                        }
                }
                change_mnt_propagation(p, MS_PRIVATE);
@@ -1625,15 +1617,15 @@ void __detach_mounts(struct dentry *dentry)
        namespace_lock();
        lock_mount_hash();
        mp = lookup_mountpoint(dentry);
-       if (IS_ERR_OR_NULL(mp))
+       if (!mp)
                goto out_unlock;
 
        event++;
        while (!hlist_empty(&mp->m_list)) {
                mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list);
                if (mnt->mnt.mnt_flags & MNT_UMOUNT) {
-                       hlist_add_head(&mnt->mnt_umount.s_list, &unmounted);
                        umount_mnt(mnt);
+                       hlist_add_head(&mnt->mnt_umount, &unmounted);
                }
                else umount_tree(mnt, UMOUNT_CONNECTED);
        }
@@ -2045,7 +2037,7 @@ int count_mounts(struct mnt_namespace *ns, struct mount *mnt)
 static int attach_recursive_mnt(struct mount *source_mnt,
                        struct mount *dest_mnt,
                        struct mountpoint *dest_mp,
-                       struct path *parent_path)
+                       bool moving)
 {
        struct user_namespace *user_ns = current->nsproxy->mnt_ns->user_ns;
        HLIST_HEAD(tree_list);
@@ -2063,7 +2055,7 @@ static int attach_recursive_mnt(struct mount *source_mnt,
                return PTR_ERR(smp);
 
        /* Is there space to add these mounts to the mount namespace? */
-       if (!parent_path) {
+       if (!moving) {
                err = count_mounts(ns, source_mnt);
                if (err)
                        goto out;
@@ -2082,8 +2074,8 @@ static int attach_recursive_mnt(struct mount *source_mnt,
        } else {
                lock_mount_hash();
        }
-       if (parent_path) {
-               detach_mnt(source_mnt, parent_path);
+       if (moving) {
+               unhash_mnt(source_mnt);
                attach_mnt(source_mnt, dest_mnt, dest_mp);
                touch_mnt_namespace(source_mnt->mnt_ns);
        } else {
@@ -2181,7 +2173,7 @@ static int graft_tree(struct mount *mnt, struct mount *p, struct mountpoint *mp)
              d_is_dir(mnt->mnt.mnt_root))
                return -ENOTDIR;
 
-       return attach_recursive_mnt(mnt, p, mp, NULL);
+       return attach_recursive_mnt(mnt, p, mp, false);
 }
 
 /*
@@ -2574,11 +2566,11 @@ out:
 
 static int do_move_mount(struct path *old_path, struct path *new_path)
 {
-       struct path parent_path = {.mnt = NULL, .dentry = NULL};
        struct mnt_namespace *ns;
        struct mount *p;
        struct mount *old;
-       struct mountpoint *mp;
+       struct mount *parent;
+       struct mountpoint *mp, *old_mp;
        int err;
        bool attached;
 
@@ -2588,7 +2580,9 @@ static int do_move_mount(struct path *old_path, struct path *new_path)
 
        old = real_mount(old_path->mnt);
        p = real_mount(new_path->mnt);
+       parent = old->mnt_parent;
        attached = mnt_has_parent(old);
+       old_mp = old->mnt_mp;
        ns = old->mnt_ns;
 
        err = -EINVAL;
@@ -2616,7 +2610,7 @@ static int do_move_mount(struct path *old_path, struct path *new_path)
        /*
         * Don't move a mount residing in a shared parent.
         */
-       if (attached && IS_MNT_SHARED(old->mnt_parent))
+       if (attached && IS_MNT_SHARED(parent))
                goto out;
        /*
         * Don't move a mount tree containing unbindable mounts to a destination
@@ -2632,18 +2626,21 @@ static int do_move_mount(struct path *old_path, struct path *new_path)
                        goto out;
 
        err = attach_recursive_mnt(old, real_mount(new_path->mnt), mp,
-                                  attached ? &parent_path : NULL);
+                                  attached);
        if (err)
                goto out;
 
        /* if the mount is moved, it should no longer be expire
         * automatically */
        list_del_init(&old->mnt_expire);
+       if (attached)
+               put_mountpoint(old_mp);
 out:
        unlock_mount(mp);
        if (!err) {
-               path_put(&parent_path);
-               if (!attached)
+               if (attached)
+                       mntput_no_expire(parent);
+               else
                        free_mnt_ns(ns);
        }
        return err;
@@ -2788,6 +2785,8 @@ static int do_new_mount(struct path *path, const char *fstype, int sb_flags,
                err = vfs_parse_fs_string(fc, "source", name, strlen(name));
        if (!err)
                err = parse_monolithic_mount_data(fc, data);
+       if (!err && !mount_capable(fc))
+               err = -EPERM;
        if (!err)
                err = vfs_get_tree(fc);
        if (!err)
@@ -3295,8 +3294,8 @@ struct dentry *mount_subtree(struct vfsmount *m, const char *name)
 }
 EXPORT_SYMBOL(mount_subtree);
 
-int ksys_mount(char __user *dev_name, char __user *dir_name, char __user *type,
-              unsigned long flags, void __user *data)
+int ksys_mount(const char __user *dev_name, const char __user *dir_name,
+              const char __user *type, unsigned long flags, void __user *data)
 {
        int ret;
        char *kernel_type;
@@ -3586,8 +3585,8 @@ EXPORT_SYMBOL(path_is_under);
 SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
                const char __user *, put_old)
 {
-       struct path new, old, parent_path, root_parent, root;
-       struct mount *new_mnt, *root_mnt, *old_mnt;
+       struct path new, old, root;
+       struct mount *new_mnt, *root_mnt, *old_mnt, *root_parent, *ex_parent;
        struct mountpoint *old_mp, *root_mp;
        int error;
 
@@ -3616,9 +3615,11 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
        new_mnt = real_mount(new.mnt);
        root_mnt = real_mount(root.mnt);
        old_mnt = real_mount(old.mnt);
+       ex_parent = new_mnt->mnt_parent;
+       root_parent = root_mnt->mnt_parent;
        if (IS_MNT_SHARED(old_mnt) ||
-               IS_MNT_SHARED(new_mnt->mnt_parent) ||
-               IS_MNT_SHARED(root_mnt->mnt_parent))
+               IS_MNT_SHARED(ex_parent) ||
+               IS_MNT_SHARED(root_parent))
                goto out4;
        if (!check_mnt(root_mnt) || !check_mnt(new_mnt))
                goto out4;
@@ -3635,7 +3636,6 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
                goto out4; /* not a mountpoint */
        if (!mnt_has_parent(root_mnt))
                goto out4; /* not attached */
-       root_mp = root_mnt->mnt_mp;
        if (new.mnt->mnt_root != new.dentry)
                goto out4; /* not a mountpoint */
        if (!mnt_has_parent(new_mnt))
@@ -3646,10 +3646,9 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
        /* make certain new is below the root */
        if (!is_path_reachable(new_mnt, new.dentry, &root))
                goto out4;
-       root_mp->m_count++; /* pin it so it won't go away */
        lock_mount_hash();
-       detach_mnt(new_mnt, &parent_path);
-       detach_mnt(root_mnt, &root_parent);
+       umount_mnt(new_mnt);
+       root_mp = unhash_mnt(root_mnt);  /* we'll need its mountpoint */
        if (root_mnt->mnt.mnt_flags & MNT_LOCKED) {
                new_mnt->mnt.mnt_flags |= MNT_LOCKED;
                root_mnt->mnt.mnt_flags &= ~MNT_LOCKED;
@@ -3657,7 +3656,8 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
        /* mount old root on put_old */
        attach_mnt(root_mnt, old_mnt, old_mp);
        /* mount new_root on / */
-       attach_mnt(new_mnt, real_mount(root_parent.mnt), root_mp);
+       attach_mnt(new_mnt, root_parent, root_mp);
+       mnt_add_count(root_parent, -1);
        touch_mnt_namespace(current->nsproxy->mnt_ns);
        /* A moved mount should not expire automatically */
        list_del_init(&new_mnt->mnt_expire);
@@ -3667,10 +3667,8 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
        error = 0;
 out4:
        unlock_mount(old_mp);
-       if (!error) {
-               path_put(&root_parent);
-               path_put(&parent_path);
-       }
+       if (!error)
+               mntput_no_expire(ex_parent);
 out3:
        path_put(&root);
 out2:
@@ -3687,13 +3685,8 @@ static void __init init_mount_tree(void)
        struct mount *m;
        struct mnt_namespace *ns;
        struct path root;
-       struct file_system_type *type;
 
-       type = get_fs_type("rootfs");
-       if (!type)
-               panic("Can't find rootfs type");
-       mnt = vfs_kern_mount(type, 0, "rootfs", NULL);
-       put_filesystem(type);
+       mnt = vfs_kern_mount(&rootfs_fs_type, 0, "rootfs", NULL);
        if (IS_ERR(mnt))
                panic("Can't create rootfs");
 
@@ -3746,6 +3739,7 @@ void __init mnt_init(void)
        fs_kobj = kobject_create_and_add("fs", NULL);
        if (!fs_kobj)
                printk(KERN_WARNING "%s: kobj create error\n", __func__);
+       shmem_init();
        init_rootfs();
        init_mount_tree();
 }
index c587e3c..34cdeae 100644 (file)
@@ -8,7 +8,8 @@ obj-$(CONFIG_NFS_FS) += nfs.o
 CFLAGS_nfstrace.o += -I$(src)
 nfs-y                  := client.o dir.o file.o getroot.o inode.o super.o \
                           io.o direct.o pagelist.o read.o symlink.o unlink.o \
-                          write.o namespace.o mount_clnt.o nfstrace.o export.o
+                          write.o namespace.o mount_clnt.o nfstrace.o \
+                          export.o sysfs.o
 nfs-$(CONFIG_ROOT_NFS) += nfsroot.o
 nfs-$(CONFIG_SYSCTL)   += sysctl.o
 nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o
index 3159673..f39924b 100644 (file)
@@ -414,27 +414,39 @@ static __be32
 validate_seqid(const struct nfs4_slot_table *tbl, const struct nfs4_slot *slot,
                const struct cb_sequenceargs * args)
 {
+       __be32 ret;
+
+       ret = cpu_to_be32(NFS4ERR_BADSLOT);
        if (args->csa_slotid > tbl->server_highest_slotid)
-               return htonl(NFS4ERR_BADSLOT);
+               goto out_err;
 
        /* Replay */
        if (args->csa_sequenceid == slot->seq_nr) {
+               ret = cpu_to_be32(NFS4ERR_DELAY);
                if (nfs4_test_locked_slot(tbl, slot->slot_nr))
-                       return htonl(NFS4ERR_DELAY);
+                       goto out_err;
+
                /* Signal process_op to set this error on next op */
+               ret = cpu_to_be32(NFS4ERR_RETRY_UNCACHED_REP);
                if (args->csa_cachethis == 0)
-                       return htonl(NFS4ERR_RETRY_UNCACHED_REP);
+                       goto out_err;
 
                /* Liar! We never allowed you to set csa_cachethis != 0 */
-               return htonl(NFS4ERR_SEQ_FALSE_RETRY);
+               ret = cpu_to_be32(NFS4ERR_SEQ_FALSE_RETRY);
+               goto out_err;
        }
 
        /* Note: wraparound relies on seq_nr being of type u32 */
-       if (likely(args->csa_sequenceid == slot->seq_nr + 1))
-               return htonl(NFS4_OK);
-
        /* Misordered request */
-       return htonl(NFS4ERR_SEQ_MISORDERED);
+       ret = cpu_to_be32(NFS4ERR_SEQ_MISORDERED);
+       if (args->csa_sequenceid != slot->seq_nr + 1)
+               goto out_err;
+
+       return cpu_to_be32(NFS4_OK);
+
+out_err:
+       trace_nfs4_cb_seqid_err(args, ret);
+       return ret;
 }
 
 /*
index d7e4f08..3083830 100644 (file)
@@ -49,6 +49,7 @@
 #include "pnfs.h"
 #include "nfs.h"
 #include "netns.h"
+#include "sysfs.h"
 
 #define NFSDBG_FACILITY                NFSDBG_CLIENT
 
@@ -175,6 +176,7 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
        clp->cl_rpcclient = ERR_PTR(-EINVAL);
 
        clp->cl_proto = cl_init->proto;
+       clp->cl_nconnect = cl_init->nconnect;
        clp->cl_net = get_net(cl_init->net);
 
        clp->cl_principal = "*";
@@ -192,7 +194,7 @@ error_0:
 EXPORT_SYMBOL_GPL(nfs_alloc_client);
 
 #if IS_ENABLED(CONFIG_NFS_V4)
-void nfs_cleanup_cb_ident_idr(struct net *net)
+static void nfs_cleanup_cb_ident_idr(struct net *net)
 {
        struct nfs_net *nn = net_generic(net, nfs_net_id);
 
@@ -214,7 +216,7 @@ static void pnfs_init_server(struct nfs_server *server)
 }
 
 #else
-void nfs_cleanup_cb_ident_idr(struct net *net)
+static void nfs_cleanup_cb_ident_idr(struct net *net)
 {
 }
 
@@ -406,10 +408,10 @@ struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_init)
                clp = nfs_match_client(cl_init);
                if (clp) {
                        spin_unlock(&nn->nfs_client_lock);
-                       if (IS_ERR(clp))
-                               return clp;
                        if (new)
                                new->rpc_ops->free_client(new);
+                       if (IS_ERR(clp))
+                               return clp;
                        return nfs_found_client(cl_init, clp);
                }
                if (new) {
@@ -493,6 +495,7 @@ int nfs_create_rpc_client(struct nfs_client *clp,
        struct rpc_create_args args = {
                .net            = clp->cl_net,
                .protocol       = clp->cl_proto,
+               .nconnect       = clp->cl_nconnect,
                .address        = (struct sockaddr *)&clp->cl_addr,
                .addrsize       = clp->cl_addrlen,
                .timeout        = cl_init->timeparms,
@@ -658,6 +661,7 @@ static int nfs_init_server(struct nfs_server *server,
                .net = data->net,
                .timeparms = &timeparms,
                .cred = server->cred,
+               .nconnect = data->nfs_server.nconnect,
        };
        struct nfs_client *clp;
        int error;
@@ -1072,6 +1076,18 @@ void nfs_clients_init(struct net *net)
 #endif
        spin_lock_init(&nn->nfs_client_lock);
        nn->boot_time = ktime_get_real();
+
+       nfs_netns_sysfs_setup(nn, net);
+}
+
+void nfs_clients_exit(struct net *net)
+{
+       struct nfs_net *nn = net_generic(net, nfs_net_id);
+
+       nfs_netns_sysfs_destroy(nn);
+       nfs_cleanup_cb_ident_idr(net);
+       WARN_ON_ONCE(!list_empty(&nn->nfs_client_list));
+       WARN_ON_ONCE(!list_empty(&nn->nfs_volume_list));
 }
 
 #ifdef CONFIG_PROC_FS
index 57b6a45..8d50109 100644 (file)
@@ -80,6 +80,10 @@ static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir
                ctx->dup_cookie = 0;
                ctx->cred = get_cred(cred);
                spin_lock(&dir->i_lock);
+               if (list_empty(&nfsi->open_files) &&
+                   (nfsi->cache_validity & NFS_INO_DATA_INVAL_DEFER))
+                       nfsi->cache_validity |= NFS_INO_INVALID_DATA |
+                               NFS_INO_REVAL_FORCED;
                list_add(&ctx->list, &nfsi->open_files);
                spin_unlock(&dir->i_lock);
                return ctx;
@@ -140,19 +144,12 @@ struct nfs_cache_array {
        struct nfs_cache_array_entry array[0];
 };
 
-struct readdirvec {
-       unsigned long nr;
-       unsigned long index;
-       struct page *pages[NFS_MAX_READDIR_RAPAGES];
-};
-
 typedef int (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, bool);
 typedef struct {
        struct file     *file;
        struct page     *page;
        struct dir_context *ctx;
        unsigned long   page_index;
-       struct readdirvec pvec;
        u64             *dir_cookie;
        u64             last_cookie;
        loff_t          current_index;
@@ -532,10 +529,6 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
        struct nfs_cache_array *array;
        unsigned int count = 0;
        int status;
-       int max_rapages = NFS_MAX_READDIR_RAPAGES;
-
-       desc->pvec.index = desc->page_index;
-       desc->pvec.nr = 0;
 
        scratch = alloc_page(GFP_KERNEL);
        if (scratch == NULL)
@@ -560,40 +553,20 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
                if (desc->plus)
                        nfs_prime_dcache(file_dentry(desc->file), entry);
 
-               status = nfs_readdir_add_to_array(entry, desc->pvec.pages[desc->pvec.nr]);
-               if (status == -ENOSPC) {
-                       desc->pvec.nr++;
-                       if (desc->pvec.nr == max_rapages)
-                               break;
-                       status = nfs_readdir_add_to_array(entry, desc->pvec.pages[desc->pvec.nr]);
-               }
+               status = nfs_readdir_add_to_array(entry, page);
                if (status != 0)
                        break;
        } while (!entry->eof);
 
-       /*
-        * page and desc->pvec.pages[0] are valid, don't need to check
-        * whether or not to be NULL.
-        */
-       copy_highpage(page, desc->pvec.pages[0]);
-
 out_nopages:
        if (count == 0 || (status == -EBADCOOKIE && entry->eof != 0)) {
-               array = kmap_atomic(desc->pvec.pages[desc->pvec.nr]);
+               array = kmap(page);
                array->eof_index = array->size;
                status = 0;
-               kunmap_atomic(array);
+               kunmap(page);
        }
 
        put_page(scratch);
-
-       /*
-        * desc->pvec.nr > 0 means at least one page was completely filled,
-        * we should return -ENOSPC. Otherwise function
-        * nfs_readdir_xdr_to_array will enter infinite loop.
-        */
-       if (desc->pvec.nr > 0)
-               return -ENOSPC;
        return status;
 }
 
@@ -627,24 +600,6 @@ out_freepages:
        return -ENOMEM;
 }
 
-/*
- * nfs_readdir_rapages_init initialize rapages by nfs_cache_array structure.
- */
-static
-void nfs_readdir_rapages_init(nfs_readdir_descriptor_t *desc)
-{
-       struct nfs_cache_array *array;
-       int max_rapages = NFS_MAX_READDIR_RAPAGES;
-       int index;
-
-       for (index = 0; index < max_rapages; index++) {
-               array = kmap_atomic(desc->pvec.pages[index]);
-               memset(array, 0, sizeof(struct nfs_cache_array));
-               array->eof_index = -1;
-               kunmap_atomic(array);
-       }
-}
-
 static
 int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, struct inode *inode)
 {
@@ -655,12 +610,6 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
        int status = -ENOMEM;
        unsigned int array_size = ARRAY_SIZE(pages);
 
-       /*
-        * This means we hit readdir rdpages miss, the preallocated rdpages
-        * are useless, the preallocate rdpages should be reinitialized.
-        */
-       nfs_readdir_rapages_init(desc);
-
        entry.prev_cookie = 0;
        entry.cookie = desc->last_cookie;
        entry.eof = 0;
@@ -721,24 +670,9 @@ int nfs_readdir_filler(void *data, struct page* page)
        struct inode    *inode = file_inode(desc->file);
        int ret;
 
-       /*
-        * If desc->page_index in range desc->pvec.index and
-        * desc->pvec.index + desc->pvec.nr, we get readdir cache hit.
-        */
-       if (desc->page_index >= desc->pvec.index &&
-               desc->page_index < (desc->pvec.index + desc->pvec.nr)) {
-               /*
-                * page and desc->pvec.pages[x] are valid, don't need to check
-                * whether or not to be NULL.
-                */
-               copy_highpage(page, desc->pvec.pages[desc->page_index - desc->pvec.index]);
-               ret = 0;
-       } else {
-               ret = nfs_readdir_xdr_to_array(desc, page, inode);
-               if (ret < 0)
-                       goto error;
-       }
-
+       ret = nfs_readdir_xdr_to_array(desc, page, inode);
+       if (ret < 0)
+               goto error;
        SetPageUptodate(page);
 
        if (invalidate_inode_pages2_range(inode->i_mapping, page->index + 1, -1) < 0) {
@@ -903,7 +837,6 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
                        *desc = &my_desc;
        struct nfs_open_dir_context *dir_ctx = file->private_data;
        int res = 0;
-       int max_rapages = NFS_MAX_READDIR_RAPAGES;
 
        dfprintk(FILE, "NFS: readdir(%pD2) starting at cookie %llu\n",
                        file, (long long)ctx->pos);
@@ -923,12 +856,6 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
        desc->decode = NFS_PROTO(inode)->decode_dirent;
        desc->plus = nfs_use_readdirplus(inode, ctx);
 
-       res = nfs_readdir_alloc_pages(desc->pvec.pages, max_rapages);
-       if (res < 0)
-               return -ENOMEM;
-
-       nfs_readdir_rapages_init(desc);
-
        if (ctx->pos == 0 || nfs_attribute_cache_expired(inode))
                res = nfs_revalidate_mapping(inode, file->f_mapping);
        if (res < 0)
@@ -964,7 +891,6 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
                        break;
        } while (!desc->eof);
 out:
-       nfs_readdir_free_pages(desc->pvec.pages, max_rapages);
        if (res > 0)
                res = 0;
        dfprintk(FILE, "NFS: readdir(%pD2) returns %d\n", file, res);
index bcff3bf..b04e20d 100644 (file)
@@ -934,6 +934,10 @@ out_nolseg:
        if (pgio->pg_error < 0)
                return;
 out_mds:
+       trace_pnfs_mds_fallback_pg_init_read(pgio->pg_inode,
+                       0, NFS4_MAX_UINT64, IOMODE_READ,
+                       NFS_I(pgio->pg_inode)->layout,
+                       pgio->pg_lseg);
        pnfs_put_lseg(pgio->pg_lseg);
        pgio->pg_lseg = NULL;
        nfs_pageio_reset_read_mds(pgio);
@@ -1000,6 +1004,10 @@ retry:
        return;
 
 out_mds:
+       trace_pnfs_mds_fallback_pg_init_write(pgio->pg_inode,
+                       0, NFS4_MAX_UINT64, IOMODE_RW,
+                       NFS_I(pgio->pg_inode)->layout,
+                       pgio->pg_lseg);
        pnfs_put_lseg(pgio->pg_lseg);
        pgio->pg_lseg = NULL;
        nfs_pageio_reset_write_mds(pgio);
@@ -1026,6 +1034,10 @@ ff_layout_pg_get_mirror_count_write(struct nfs_pageio_descriptor *pgio,
        if (pgio->pg_lseg)
                return FF_LAYOUT_MIRROR_COUNT(pgio->pg_lseg);
 
+       trace_pnfs_mds_fallback_pg_get_mirror_count(pgio->pg_inode,
+                       0, NFS4_MAX_UINT64, IOMODE_RW,
+                       NFS_I(pgio->pg_inode)->layout,
+                       pgio->pg_lseg);
        /* no lseg means that pnfs is not in use, so no mirroring here */
        nfs_pageio_reset_write_mds(pgio);
 out:
@@ -1075,6 +1087,10 @@ static void ff_layout_reset_write(struct nfs_pgio_header *hdr, bool retry_pnfs)
                        hdr->args.count,
                        (unsigned long long)hdr->args.offset);
 
+               trace_pnfs_mds_fallback_write_done(hdr->inode,
+                               hdr->args.offset, hdr->args.count,
+                               IOMODE_RW, NFS_I(hdr->inode)->layout,
+                               hdr->lseg);
                task->tk_status = pnfs_write_done_resend_to_mds(hdr);
        }
 }
@@ -1094,6 +1110,10 @@ static void ff_layout_reset_read(struct nfs_pgio_header *hdr)
                        hdr->args.count,
                        (unsigned long long)hdr->args.offset);
 
+               trace_pnfs_mds_fallback_read_done(hdr->inode,
+                               hdr->args.offset, hdr->args.count,
+                               IOMODE_READ, NFS_I(hdr->inode)->layout,
+                               hdr->lseg);
                task->tk_status = pnfs_read_done_resend_to_mds(hdr);
        }
 }
@@ -1827,6 +1847,9 @@ ff_layout_read_pagelist(struct nfs_pgio_header *hdr)
 out_failed:
        if (ff_layout_avoid_mds_available_ds(lseg))
                return PNFS_TRY_AGAIN;
+       trace_pnfs_mds_fallback_read_pagelist(hdr->inode,
+                       hdr->args.offset, hdr->args.count,
+                       IOMODE_READ, NFS_I(hdr->inode)->layout, lseg);
        return PNFS_NOT_ATTEMPTED;
 }
 
@@ -1892,6 +1915,9 @@ ff_layout_write_pagelist(struct nfs_pgio_header *hdr, int sync)
 out_failed:
        if (ff_layout_avoid_mds_available_ds(lseg))
                return PNFS_TRY_AGAIN;
+       trace_pnfs_mds_fallback_write_pagelist(hdr->inode,
+                       hdr->args.offset, hdr->args.count,
+                       IOMODE_RW, NFS_I(hdr->inode)->layout, lseg);
        return PNFS_NOT_ATTEMPTED;
 }
 
index 19f856f..3eda40a 100644 (file)
@@ -257,7 +257,7 @@ int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo,
        if (status == 0)
                return 0;
 
-       if (mirror->mirror_ds == NULL)
+       if (IS_ERR_OR_NULL(mirror->mirror_ds))
                return -EINVAL;
 
        dserr = kmalloc(sizeof(*dserr), gfp_flags);
index 0b4a1a9..8a17582 100644 (file)
@@ -51,6 +51,7 @@
 #include "pnfs.h"
 #include "nfs.h"
 #include "netns.h"
+#include "sysfs.h"
 
 #include "nfstrace.h"
 
@@ -208,7 +209,7 @@ static void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)
        }
 
        if (inode->i_mapping->nrpages == 0)
-               flags &= ~NFS_INO_INVALID_DATA;
+               flags &= ~(NFS_INO_INVALID_DATA|NFS_INO_DATA_INVAL_DEFER);
        nfsi->cache_validity |= flags;
        if (flags & NFS_INO_INVALID_DATA)
                nfs_fscache_invalidate(inode);
@@ -652,7 +653,8 @@ static int nfs_vmtruncate(struct inode * inode, loff_t offset)
        i_size_write(inode, offset);
        /* Optimisation */
        if (offset == 0)
-               NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_DATA;
+               NFS_I(inode)->cache_validity &= ~(NFS_INO_INVALID_DATA |
+                               NFS_INO_DATA_INVAL_DEFER);
        NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_SIZE;
 
        spin_unlock(&inode->i_lock);
@@ -1032,6 +1034,10 @@ void nfs_inode_attach_open_context(struct nfs_open_context *ctx)
        struct nfs_inode *nfsi = NFS_I(inode);
 
        spin_lock(&inode->i_lock);
+       if (list_empty(&nfsi->open_files) &&
+           (nfsi->cache_validity & NFS_INO_DATA_INVAL_DEFER))
+               nfsi->cache_validity |= NFS_INO_INVALID_DATA |
+                       NFS_INO_REVAL_FORCED;
        list_add_tail_rcu(&ctx->list, &nfsi->open_files);
        spin_unlock(&inode->i_lock);
 }
@@ -1100,6 +1106,7 @@ int nfs_open(struct inode *inode, struct file *filp)
        nfs_fscache_open_file(inode, filp);
        return 0;
 }
+EXPORT_SYMBOL_GPL(nfs_open);
 
 /*
  * This function is called whenever some part of NFS notices that
@@ -1312,7 +1319,8 @@ int nfs_revalidate_mapping(struct inode *inode,
 
        set_bit(NFS_INO_INVALIDATING, bitlock);
        smp_wmb();
-       nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
+       nfsi->cache_validity &= ~(NFS_INO_INVALID_DATA|
+                       NFS_INO_DATA_INVAL_DEFER);
        spin_unlock(&inode->i_lock);
        trace_nfs_invalidate_mapping_enter(inode);
        ret = nfs_invalidate_mapping(inode, mapping);
@@ -1870,7 +1878,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                                dprintk("NFS: change_attr change on server for file %s/%ld\n",
                                                inode->i_sb->s_id,
                                                inode->i_ino);
-                       }
+                       } else if (!have_delegation)
+                               nfsi->cache_validity |= NFS_INO_DATA_INVAL_DEFER;
                        inode_set_iversion_raw(inode, fattr->change_attr);
                        attr_changed = true;
                }
@@ -2159,12 +2168,8 @@ static int nfs_net_init(struct net *net)
 
 static void nfs_net_exit(struct net *net)
 {
-       struct nfs_net *nn = net_generic(net, nfs_net_id);
-
        nfs_fs_proc_net_exit(net);
-       nfs_cleanup_cb_ident_idr(net);
-       WARN_ON_ONCE(!list_empty(&nn->nfs_client_list));
-       WARN_ON_ONCE(!list_empty(&nn->nfs_volume_list));
+       nfs_clients_exit(net);
 }
 
 static struct pernet_operations nfs_net_ops = {
@@ -2181,6 +2186,10 @@ static int __init init_nfs_fs(void)
 {
        int err;
 
+       err = nfs_sysfs_init();
+       if (err < 0)
+               goto out10;
+
        err = register_pernet_subsys(&nfs_net_ops);
        if (err < 0)
                goto out9;
@@ -2244,6 +2253,8 @@ out7:
 out8:
        unregister_pernet_subsys(&nfs_net_ops);
 out9:
+       nfs_sysfs_exit();
+out10:
        return err;
 }
 
@@ -2260,6 +2271,7 @@ static void __exit exit_nfs_fs(void)
        unregister_nfs_fs();
        nfs_fs_proc_exit();
        nfsiod_stop();
+       nfs_sysfs_exit();
 }
 
 /* Not quite true; I just maintain it */
index 498fab7..a2346a2 100644 (file)
@@ -69,8 +69,7 @@ struct nfs_clone_mount {
  * Maximum number of pages that readdir can use for creating
  * a vmapped array of pages.
  */
-#define NFS_MAX_READDIR_PAGES 64
-#define NFS_MAX_READDIR_RAPAGES 8
+#define NFS_MAX_READDIR_PAGES 8
 
 struct nfs_client_initdata {
        unsigned long init_flags;
@@ -82,6 +81,7 @@ struct nfs_client_initdata {
        struct nfs_subversion *nfs_mod;
        int proto;
        u32 minorversion;
+       unsigned int nconnect;
        struct net *net;
        const struct rpc_timeout *timeparms;
        const struct cred *cred;
@@ -123,6 +123,7 @@ struct nfs_parsed_mount_data {
                char                    *export_path;
                int                     port;
                unsigned short          protocol;
+               unsigned short          nconnect;
        } nfs_server;
 
        void                    *lsm_opts;
@@ -158,6 +159,7 @@ extern void nfs_umount(const struct nfs_mount_request *info);
 /* client.c */
 extern const struct rpc_program nfs_program;
 extern void nfs_clients_init(struct net *net);
+extern void nfs_clients_exit(struct net *net);
 extern struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *);
 int nfs_create_rpc_client(struct nfs_client *, const struct nfs_client_initdata *, rpc_authflavor_t);
 struct nfs_client *nfs_get_client(const struct nfs_client_initdata *);
@@ -170,7 +172,6 @@ int nfs_init_server_rpcclient(struct nfs_server *, const struct rpc_timeout *t,
 struct nfs_server *nfs_alloc_server(void);
 void nfs_server_copy_userdata(struct nfs_server *, struct nfs_server *);
 
-extern void nfs_cleanup_cb_ident_idr(struct net *);
 extern void nfs_put_client(struct nfs_client *);
 extern void nfs_free_client(struct nfs_client *);
 extern struct nfs_client *nfs4_find_client_ident(struct net *, int);
index fc9978c..c8374f7 100644 (file)
@@ -15,6 +15,8 @@ struct bl_dev_msg {
        uint32_t major, minor;
 };
 
+struct nfs_netns_client;
+
 struct nfs_net {
        struct cache_detail *nfs_dns_resolve;
        struct rpc_pipe *bl_device_pipe;
@@ -29,6 +31,7 @@ struct nfs_net {
        unsigned short nfs_callback_tcpport6;
        int cb_users[NFS4_MAX_MINOR_VERSION + 1];
 #endif
+       struct nfs_netns_client *nfs_client;
        spinlock_t nfs_client_lock;
        ktime_t boot_time;
 #ifdef CONFIG_PROC_FS
index 572794d..cbc17a2 100644 (file)
@@ -151,7 +151,7 @@ static int decode_stat(struct xdr_stream *xdr, enum nfs_stat *status)
        return 0;
 out_status:
        *status = be32_to_cpup(p);
-       trace_nfs_xdr_status((int)*status);
+       trace_nfs_xdr_status(xdr, (int)*status);
        return 0;
 }
 
index fb0c425..148ceb7 100644 (file)
@@ -102,6 +102,9 @@ struct nfs_client *nfs3_set_ds_client(struct nfs_server *mds_srv,
                return ERR_PTR(-EINVAL);
        cl_init.hostname = buf;
 
+       if (mds_clp->cl_nconnect > 1 && ds_proto == XPRT_TRANSPORT_TCP)
+               cl_init.nconnect = mds_clp->cl_nconnect;
+
        if (mds_srv->flags & NFS_MOUNT_NORESVPORT)
                set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
 
index abbbdde..6027678 100644 (file)
@@ -343,7 +343,7 @@ static int decode_nfsstat3(struct xdr_stream *xdr, enum nfs_stat *status)
        return 0;
 out_status:
        *status = be32_to_cpup(p);
-       trace_nfs_xdr_status((int)*status);
+       trace_nfs_xdr_status(xdr, (int)*status);
        return 0;
 }
 
index 8a38a25..d778dad 100644 (file)
@@ -312,12 +312,12 @@ extern int nfs4_set_rw_stateid(nfs4_stateid *stateid,
                const struct nfs_lock_context *l_ctx,
                fmode_t fmode);
 
+extern int nfs4_proc_get_lease_time(struct nfs_client *clp,
+               struct nfs_fsinfo *fsinfo);
 #if defined(CONFIG_NFS_V4_1)
 extern int nfs41_sequence_done(struct rpc_task *, struct nfs4_sequence_res *);
 extern int nfs4_proc_create_session(struct nfs_client *, const struct cred *);
 extern int nfs4_proc_destroy_session(struct nfs4_session *, const struct cred *);
-extern int nfs4_proc_get_lease_time(struct nfs_client *clp,
-               struct nfs_fsinfo *fsinfo);
 extern int nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data,
                                  bool sync);
 extern int nfs4_detect_session_trunking(struct nfs_client *clp,
index 81b9b6d..616393a 100644 (file)
@@ -859,7 +859,8 @@ static int nfs4_set_client(struct nfs_server *server,
                const size_t addrlen,
                const char *ip_addr,
                int proto, const struct rpc_timeout *timeparms,
-               u32 minorversion, struct net *net)
+               u32 minorversion, unsigned int nconnect,
+               struct net *net)
 {
        struct nfs_client_initdata cl_init = {
                .hostname = hostname,
@@ -875,6 +876,8 @@ static int nfs4_set_client(struct nfs_server *server,
        };
        struct nfs_client *clp;
 
+       if (minorversion > 0 && proto == XPRT_TRANSPORT_TCP)
+               cl_init.nconnect = nconnect;
        if (server->flags & NFS_MOUNT_NORESVPORT)
                set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
        if (server->options & NFS_OPTION_MIGRATION)
@@ -941,6 +944,9 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,
                return ERR_PTR(-EINVAL);
        cl_init.hostname = buf;
 
+       if (mds_clp->cl_nconnect > 1 && ds_proto == XPRT_TRANSPORT_TCP)
+               cl_init.nconnect = mds_clp->cl_nconnect;
+
        if (mds_srv->flags & NFS_MOUNT_NORESVPORT)
                __set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
 
@@ -1074,6 +1080,7 @@ static int nfs4_init_server(struct nfs_server *server,
                        data->nfs_server.protocol,
                        &timeparms,
                        data->minorversion,
+                       data->nfs_server.nconnect,
                        data->net);
        if (error < 0)
                return error;
@@ -1163,6 +1170,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
                                XPRT_TRANSPORT_RDMA,
                                parent_server->client->cl_timeout,
                                parent_client->cl_mvops->minor_version,
+                               parent_client->cl_nconnect,
                                parent_client->cl_net);
        if (!error)
                goto init_server;
@@ -1176,6 +1184,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
                                XPRT_TRANSPORT_TCP,
                                parent_server->client->cl_timeout,
                                parent_client->cl_mvops->minor_version,
+                               parent_client->cl_nconnect,
                                parent_client->cl_net);
        if (error < 0)
                goto error;
@@ -1271,7 +1280,8 @@ int nfs4_update_server(struct nfs_server *server, const char *hostname,
        set_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status);
        error = nfs4_set_client(server, hostname, sap, salen, buf,
                                clp->cl_proto, clnt->cl_timeout,
-                               clp->cl_minorversion, net);
+                               clp->cl_minorversion,
+                               clp->cl_nconnect, net);
        clear_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status);
        if (error != 0) {
                nfs_server_insert_lists(server);
index f4157eb..96db471 100644 (file)
@@ -49,7 +49,7 @@ nfs4_file_open(struct inode *inode, struct file *filp)
                return err;
 
        if ((openflags & O_ACCMODE) == 3)
-               openflags--;
+               return nfs_open(inode, filp);
 
        /* We can't create new files here */
        openflags &= ~(O_CREAT|O_EXCL);
@@ -204,7 +204,11 @@ static loff_t nfs42_remap_file_range(struct file *src_file, loff_t src_off,
        bool same_inode = false;
        int ret;
 
-       if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY))
+       /* NFS does not support deduplication. */
+       if (remap_flags & REMAP_FILE_DEDUP)
+               return -EOPNOTSUPP;
+
+       if (remap_flags & ~REMAP_FILE_ADVISORY)
                return -EINVAL;
 
        /* check alignment w.r.t. clone_blksize */
index 6418cb6..39896af 100644 (file)
@@ -428,6 +428,22 @@ static int nfs4_delay(long *timeout, bool interruptible)
        return nfs4_delay_killable(timeout);
 }
 
+static const nfs4_stateid *
+nfs4_recoverable_stateid(const nfs4_stateid *stateid)
+{
+       if (!stateid)
+               return NULL;
+       switch (stateid->type) {
+       case NFS4_OPEN_STATEID_TYPE:
+       case NFS4_LOCK_STATEID_TYPE:
+       case NFS4_DELEGATION_STATEID_TYPE:
+               return stateid;
+       default:
+               break;
+       }
+       return NULL;
+}
+
 /* This is the error handling routine for processes that are allowed
  * to sleep.
  */
@@ -436,7 +452,7 @@ static int nfs4_do_handle_exception(struct nfs_server *server,
 {
        struct nfs_client *clp = server->nfs_client;
        struct nfs4_state *state = exception->state;
-       const nfs4_stateid *stateid = exception->stateid;
+       const nfs4_stateid *stateid;
        struct inode *inode = exception->inode;
        int ret = errorcode;
 
@@ -444,8 +460,9 @@ static int nfs4_do_handle_exception(struct nfs_server *server,
        exception->recovering = 0;
        exception->retry = 0;
 
+       stateid = nfs4_recoverable_stateid(exception->stateid);
        if (stateid == NULL && state != NULL)
-               stateid = &state->stateid;
+               stateid = nfs4_recoverable_stateid(&state->stateid);
 
        switch(errorcode) {
                case 0:
@@ -1165,6 +1182,18 @@ static bool nfs4_clear_cap_atomic_open_v1(struct nfs_server *server,
        return true;
 }
 
+static fmode_t _nfs4_ctx_to_accessmode(const struct nfs_open_context *ctx)
+{
+        return ctx->mode & (FMODE_READ|FMODE_WRITE|FMODE_EXEC);
+}
+
+static fmode_t _nfs4_ctx_to_openmode(const struct nfs_open_context *ctx)
+{
+       fmode_t ret = ctx->mode & (FMODE_READ|FMODE_WRITE);
+
+       return (ctx->mode & FMODE_EXEC) ? FMODE_READ | ret : ret;
+}
+
 static u32
 nfs4_map_atomic_open_share(struct nfs_server *server,
                fmode_t fmode, int openflags)
@@ -2900,14 +2929,13 @@ static unsigned nfs4_exclusive_attrset(struct nfs4_opendata *opendata,
 }
 
 static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
-               fmode_t fmode,
-               int flags,
-               struct nfs_open_context *ctx)
+               int flags, struct nfs_open_context *ctx)
 {
        struct nfs4_state_owner *sp = opendata->owner;
        struct nfs_server *server = sp->so_server;
        struct dentry *dentry;
        struct nfs4_state *state;
+       fmode_t acc_mode = _nfs4_ctx_to_accessmode(ctx);
        unsigned int seq;
        int ret;
 
@@ -2946,7 +2974,8 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
        /* Parse layoutget results before we check for access */
        pnfs_parse_lgopen(state->inode, opendata->lgp, ctx);
 
-       ret = nfs4_opendata_access(sp->so_cred, opendata, state, fmode, flags);
+       ret = nfs4_opendata_access(sp->so_cred, opendata, state,
+                       acc_mode, flags);
        if (ret != 0)
                goto out;
 
@@ -2978,7 +3007,7 @@ static int _nfs4_do_open(struct inode *dir,
        struct dentry *dentry = ctx->dentry;
        const struct cred *cred = ctx->cred;
        struct nfs4_threshold **ctx_th = &ctx->mdsthreshold;
-       fmode_t fmode = ctx->mode & (FMODE_READ|FMODE_WRITE|FMODE_EXEC);
+       fmode_t fmode = _nfs4_ctx_to_openmode(ctx);
        enum open_claim_type4 claim = NFS4_OPEN_CLAIM_NULL;
        struct iattr *sattr = c->sattr;
        struct nfs4_label *label = c->label;
@@ -3024,7 +3053,7 @@ static int _nfs4_do_open(struct inode *dir,
        if (d_really_is_positive(dentry))
                opendata->state = nfs4_get_open_state(d_inode(dentry), sp);
 
-       status = _nfs4_open_and_get_state(opendata, fmode, flags, ctx);
+       status = _nfs4_open_and_get_state(opendata, flags, ctx);
        if (status != 0)
                goto err_free_label;
        state = ctx->state;
@@ -3594,9 +3623,9 @@ static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
        if (ctx->state == NULL)
                return;
        if (is_sync)
-               nfs4_close_sync(ctx->state, ctx->mode);
+               nfs4_close_sync(ctx->state, _nfs4_ctx_to_openmode(ctx));
        else
-               nfs4_close_state(ctx->state, ctx->mode);
+               nfs4_close_state(ctx->state, _nfs4_ctx_to_openmode(ctx));
 }
 
 #define FATTR4_WORD1_NFS40_MASK (2*FATTR4_WORD1_MOUNTED_ON_FILEID - 1UL)
@@ -5980,7 +6009,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
                .rpc_message = &msg,
                .callback_ops = &nfs4_setclientid_ops,
                .callback_data = &setclientid,
-               .flags = RPC_TASK_TIMEOUT,
+               .flags = RPC_TASK_TIMEOUT | RPC_TASK_NO_ROUND_ROBIN,
        };
        int status;
 
@@ -6046,7 +6075,8 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
        dprintk("NFS call  setclientid_confirm auth=%s, (client ID %llx)\n",
                clp->cl_rpcclient->cl_auth->au_ops->au_name,
                clp->cl_clientid);
-       status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       status = rpc_call_sync(clp->cl_rpcclient, &msg,
+                              RPC_TASK_TIMEOUT | RPC_TASK_NO_ROUND_ROBIN);
        trace_nfs4_setclientid_confirm(clp, status);
        dprintk("NFS reply setclientid_confirm: %d\n", status);
        return status;
@@ -7627,7 +7657,7 @@ static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct
                NFS_SP4_MACH_CRED_SECINFO, &clnt, &msg);
 
        status = nfs4_call_sync(clnt, NFS_SERVER(dir), &msg, &args.seq_args,
-                               &res.seq_res, 0);
+                               &res.seq_res, RPC_TASK_NO_ROUND_ROBIN);
        dprintk("NFS reply  secinfo: %d\n", status);
 
        put_cred(cred);
@@ -7965,7 +7995,7 @@ nfs4_run_exchange_id(struct nfs_client *clp, const struct cred *cred,
                .rpc_client = clp->cl_rpcclient,
                .callback_ops = &nfs4_exchange_id_call_ops,
                .rpc_message = &msg,
-               .flags = RPC_TASK_TIMEOUT,
+               .flags = RPC_TASK_TIMEOUT | RPC_TASK_NO_ROUND_ROBIN,
        };
        struct nfs41_exchange_id_data *calldata;
        int status;
@@ -8190,7 +8220,8 @@ static int _nfs4_proc_destroy_clientid(struct nfs_client *clp,
        };
        int status;
 
-       status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       status = rpc_call_sync(clp->cl_rpcclient, &msg,
+                              RPC_TASK_TIMEOUT | RPC_TASK_NO_ROUND_ROBIN);
        trace_nfs4_destroy_clientid(clp, status);
        if (status)
                dprintk("NFS: Got error %d from the server %s on "
@@ -8241,6 +8272,8 @@ out:
        return ret;
 }
 
+#endif /* CONFIG_NFS_V4_1 */
+
 struct nfs4_get_lease_time_data {
        struct nfs4_get_lease_time_args *args;
        struct nfs4_get_lease_time_res *res;
@@ -8273,7 +8306,7 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata)
                        (struct nfs4_get_lease_time_data *)calldata;
 
        dprintk("--> %s\n", __func__);
-       if (!nfs41_sequence_done(task, &data->res->lr_seq_res))
+       if (!nfs4_sequence_done(task, &data->res->lr_seq_res))
                return;
        switch (task->tk_status) {
        case -NFS4ERR_DELAY:
@@ -8331,6 +8364,8 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo)
        return status;
 }
 
+#ifdef CONFIG_NFS_V4_1
+
 /*
  * Initialize the values to be used by the client in CREATE_SESSION
  * If nfs4_init_session set the fore channel request and response sizes,
@@ -8345,6 +8380,7 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args,
 {
        unsigned int max_rqst_sz, max_resp_sz;
        unsigned int max_bc_payload = rpc_max_bc_payload(clnt);
+       unsigned int max_bc_slots = rpc_num_bc_slots(clnt);
 
        max_rqst_sz = NFS_MAX_FILE_IO_SIZE + nfs41_maxwrite_overhead;
        max_resp_sz = NFS_MAX_FILE_IO_SIZE + nfs41_maxread_overhead;
@@ -8367,6 +8403,8 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args,
        args->bc_attrs.max_resp_sz_cached = 0;
        args->bc_attrs.max_ops = NFS4_MAX_BACK_CHANNEL_OPS;
        args->bc_attrs.max_reqs = max_t(unsigned short, max_session_cb_slots, 1);
+       if (args->bc_attrs.max_reqs > max_bc_slots)
+               args->bc_attrs.max_reqs = max_bc_slots;
 
        dprintk("%s: Back Channel : max_rqst_sz=%u max_resp_sz=%u "
                "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n",
@@ -8469,7 +8507,8 @@ static int _nfs4_proc_create_session(struct nfs_client *clp,
        nfs4_init_channel_attrs(&args, clp->cl_rpcclient);
        args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN);
 
-       status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       status = rpc_call_sync(session->clp->cl_rpcclient, &msg,
+                              RPC_TASK_TIMEOUT | RPC_TASK_NO_ROUND_ROBIN);
        trace_nfs4_create_session(clp, status);
 
        switch (status) {
@@ -8545,7 +8584,8 @@ int nfs4_proc_destroy_session(struct nfs4_session *session,
        if (!test_and_clear_bit(NFS4_SESSION_ESTABLISHED, &session->session_state))
                return 0;
 
-       status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       status = rpc_call_sync(session->clp->cl_rpcclient, &msg,
+                              RPC_TASK_TIMEOUT | RPC_TASK_NO_ROUND_ROBIN);
        trace_nfs4_destroy_session(session->clp, status);
 
        if (status)
@@ -8799,7 +8839,7 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp,
                .rpc_client = clp->cl_rpcclient,
                .rpc_message = &msg,
                .callback_ops = &nfs4_reclaim_complete_call_ops,
-               .flags = RPC_TASK_ASYNC,
+               .flags = RPC_TASK_ASYNC | RPC_TASK_NO_ROUND_ROBIN,
        };
        int status = -ENOMEM;
 
@@ -9318,7 +9358,7 @@ _nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
 
        dprintk("--> %s\n", __func__);
        status = nfs4_call_sync(clnt, server, &msg, &args.seq_args,
-                               &res.seq_res, 0);
+                               &res.seq_res, RPC_TASK_NO_ROUND_ROBIN);
        dprintk("<-- %s status=%d\n", __func__, status);
 
        put_cred(cred);
index e2e3c4f..9afd051 100644 (file)
@@ -87,6 +87,27 @@ const nfs4_stateid current_stateid = {
 
 static DEFINE_MUTEX(nfs_clid_init_mutex);
 
+static int nfs4_setup_state_renewal(struct nfs_client *clp)
+{
+       int status;
+       struct nfs_fsinfo fsinfo;
+       unsigned long now;
+
+       if (!test_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state)) {
+               nfs4_schedule_state_renewal(clp);
+               return 0;
+       }
+
+       now = jiffies;
+       status = nfs4_proc_get_lease_time(clp, &fsinfo);
+       if (status == 0) {
+               nfs4_set_lease_period(clp, fsinfo.lease_time * HZ, now);
+               nfs4_schedule_state_renewal(clp);
+       }
+
+       return status;
+}
+
 int nfs4_init_clientid(struct nfs_client *clp, const struct cred *cred)
 {
        struct nfs4_setclientid_res clid = {
@@ -114,7 +135,7 @@ do_confirm:
        if (status != 0)
                goto out;
        clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
-       nfs4_schedule_state_renewal(clp);
+       nfs4_setup_state_renewal(clp);
 out:
        return status;
 }
@@ -286,34 +307,13 @@ static int nfs4_begin_drain_session(struct nfs_client *clp)
 
 #if defined(CONFIG_NFS_V4_1)
 
-static int nfs41_setup_state_renewal(struct nfs_client *clp)
-{
-       int status;
-       struct nfs_fsinfo fsinfo;
-       unsigned long now;
-
-       if (!test_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state)) {
-               nfs4_schedule_state_renewal(clp);
-               return 0;
-       }
-
-       now = jiffies;
-       status = nfs4_proc_get_lease_time(clp, &fsinfo);
-       if (status == 0) {
-               nfs4_set_lease_period(clp, fsinfo.lease_time * HZ, now);
-               nfs4_schedule_state_renewal(clp);
-       }
-
-       return status;
-}
-
 static void nfs41_finish_session_reset(struct nfs_client *clp)
 {
        clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
        clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
        /* create_session negotiated new slot table */
        clear_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
-       nfs41_setup_state_renewal(clp);
+       nfs4_setup_state_renewal(clp);
 }
 
 int nfs41_init_clientid(struct nfs_client *clp, const struct cred *cred)
@@ -1064,8 +1064,7 @@ int nfs4_select_rw_stateid(struct nfs4_state *state,
                 * choose to use.
                 */
                goto out;
-       nfs4_copy_open_stateid(dst, state);
-       ret = 0;
+       ret = nfs4_copy_open_stateid(dst, state) ? 0 : -EAGAIN;
 out:
        if (nfs_server_capable(state->inode, NFS_CAP_STATEID_NFSV41))
                dst->seqid = 0;
index e9fb3e5..1a8f376 100644 (file)
 EXPORT_TRACEPOINT_SYMBOL_GPL(nfs4_pnfs_read);
 EXPORT_TRACEPOINT_SYMBOL_GPL(nfs4_pnfs_write);
 EXPORT_TRACEPOINT_SYMBOL_GPL(nfs4_pnfs_commit_ds);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(pnfs_mds_fallback_pg_init_read);
+EXPORT_TRACEPOINT_SYMBOL_GPL(pnfs_mds_fallback_pg_init_write);
+EXPORT_TRACEPOINT_SYMBOL_GPL(pnfs_mds_fallback_pg_get_mirror_count);
+EXPORT_TRACEPOINT_SYMBOL_GPL(pnfs_mds_fallback_read_done);
+EXPORT_TRACEPOINT_SYMBOL_GPL(pnfs_mds_fallback_write_done);
+EXPORT_TRACEPOINT_SYMBOL_GPL(pnfs_mds_fallback_read_pagelist);
+EXPORT_TRACEPOINT_SYMBOL_GPL(pnfs_mds_fallback_write_pagelist);
 #endif
index cd1a5c0..b2f395f 100644 (file)
@@ -156,7 +156,7 @@ TRACE_DEFINE_ENUM(NFS4ERR_WRONG_TYPE);
 TRACE_DEFINE_ENUM(NFS4ERR_XDEV);
 
 #define show_nfsv4_errors(error) \
-       __print_symbolic(-(error), \
+       __print_symbolic(error, \
                { NFS4_OK, "OK" }, \
                /* Mapped by nfs4_stat_to_errno() */ \
                { EPERM, "EPERM" }, \
@@ -348,7 +348,7 @@ DECLARE_EVENT_CLASS(nfs4_clientid_event,
 
                TP_STRUCT__entry(
                        __string(dstaddr, clp->cl_hostname)
-                       __field(int, error)
+                       __field(unsigned long, error)
                ),
 
                TP_fast_assign(
@@ -357,8 +357,8 @@ DECLARE_EVENT_CLASS(nfs4_clientid_event,
                ),
 
                TP_printk(
-                       "error=%d (%s) dstaddr=%s",
-                       __entry->error,
+                       "error=%ld (%s) dstaddr=%s",
+                       -__entry->error,
                        show_nfsv4_errors(__entry->error),
                        __get_str(dstaddr)
                )
@@ -420,7 +420,7 @@ TRACE_EVENT(nfs4_sequence_done,
                        __field(unsigned int, highest_slotid)
                        __field(unsigned int, target_highest_slotid)
                        __field(unsigned int, status_flags)
-                       __field(int, error)
+                       __field(unsigned long, error)
                ),
 
                TP_fast_assign(
@@ -435,10 +435,10 @@ TRACE_EVENT(nfs4_sequence_done,
                        __entry->error = res->sr_status;
                ),
                TP_printk(
-                       "error=%d (%s) session=0x%08x slot_nr=%u seq_nr=%u "
+                       "error=%ld (%s) session=0x%08x slot_nr=%u seq_nr=%u "
                        "highest_slotid=%u target_highest_slotid=%u "
                        "status_flags=%u (%s)",
-                       __entry->error,
+                       -__entry->error,
                        show_nfsv4_errors(__entry->error),
                        __entry->session,
                        __entry->slot_nr,
@@ -467,7 +467,7 @@ TRACE_EVENT(nfs4_cb_sequence,
                        __field(unsigned int, seq_nr)
                        __field(unsigned int, highest_slotid)
                        __field(unsigned int, cachethis)
-                       __field(int, error)
+                       __field(unsigned long, error)
                ),
 
                TP_fast_assign(
@@ -476,13 +476,13 @@ TRACE_EVENT(nfs4_cb_sequence,
                        __entry->seq_nr = args->csa_sequenceid;
                        __entry->highest_slotid = args->csa_highestslotid;
                        __entry->cachethis = args->csa_cachethis;
-                       __entry->error = -be32_to_cpu(status);
+                       __entry->error = be32_to_cpu(status);
                ),
 
                TP_printk(
-                       "error=%d (%s) session=0x%08x slot_nr=%u seq_nr=%u "
+                       "error=%ld (%s) session=0x%08x slot_nr=%u seq_nr=%u "
                        "highest_slotid=%u",
-                       __entry->error,
+                       -__entry->error,
                        show_nfsv4_errors(__entry->error),
                        __entry->session,
                        __entry->slot_nr,
@@ -490,6 +490,44 @@ TRACE_EVENT(nfs4_cb_sequence,
                        __entry->highest_slotid
                )
 );
+
+TRACE_EVENT(nfs4_cb_seqid_err,
+               TP_PROTO(
+                       const struct cb_sequenceargs *args,
+                       __be32 status
+               ),
+               TP_ARGS(args, status),
+
+               TP_STRUCT__entry(
+                       __field(unsigned int, session)
+                       __field(unsigned int, slot_nr)
+                       __field(unsigned int, seq_nr)
+                       __field(unsigned int, highest_slotid)
+                       __field(unsigned int, cachethis)
+                       __field(unsigned long, error)
+               ),
+
+               TP_fast_assign(
+                       __entry->session = nfs_session_id_hash(&args->csa_sessionid);
+                       __entry->slot_nr = args->csa_slotid;
+                       __entry->seq_nr = args->csa_sequenceid;
+                       __entry->highest_slotid = args->csa_highestslotid;
+                       __entry->cachethis = args->csa_cachethis;
+                       __entry->error = be32_to_cpu(status);
+               ),
+
+               TP_printk(
+                       "error=%ld (%s) session=0x%08x slot_nr=%u seq_nr=%u "
+                       "highest_slotid=%u",
+                       -__entry->error,
+                       show_nfsv4_errors(__entry->error),
+                       __entry->session,
+                       __entry->slot_nr,
+                       __entry->seq_nr,
+                       __entry->highest_slotid
+               )
+);
+
 #endif /* CONFIG_NFS_V4_1 */
 
 TRACE_EVENT(nfs4_setup_sequence,
@@ -526,26 +564,37 @@ TRACE_EVENT(nfs4_setup_sequence,
 
 TRACE_EVENT(nfs4_xdr_status,
                TP_PROTO(
+                       const struct xdr_stream *xdr,
                        u32 op,
                        int error
                ),
 
-               TP_ARGS(op, error),
+               TP_ARGS(xdr, op, error),
 
                TP_STRUCT__entry(
+                       __field(unsigned int, task_id)
+                       __field(unsigned int, client_id)
+                       __field(u32, xid)
                        __field(u32, op)
-                       __field(int, error)
+                       __field(unsigned long, error)
                ),
 
                TP_fast_assign(
+                       const struct rpc_rqst *rqstp = xdr->rqst;
+                       const struct rpc_task *task = rqstp->rq_task;
+
+                       __entry->task_id = task->tk_pid;
+                       __entry->client_id = task->tk_client->cl_clid;
+                       __entry->xid = be32_to_cpu(rqstp->rq_xid);
                        __entry->op = op;
-                       __entry->error = -error;
+                       __entry->error = error;
                ),
 
                TP_printk(
-                       "operation %d: nfs status %d (%s)",
-                       __entry->op,
-                       __entry->error, show_nfsv4_errors(__entry->error)
+                       "task:%u@%d xid=0x%08x error=%ld (%s) operation=%u",
+                       __entry->task_id, __entry->client_id, __entry->xid,
+                       -__entry->error, show_nfsv4_errors(__entry->error),
+                       __entry->op
                )
 );
 
@@ -559,7 +608,7 @@ DECLARE_EVENT_CLASS(nfs4_open_event,
                TP_ARGS(ctx, flags, error),
 
                TP_STRUCT__entry(
-                       __field(int, error)
+                       __field(unsigned long, error)
                        __field(unsigned int, flags)
                        __field(unsigned int, fmode)
                        __field(dev_t, dev)
@@ -577,7 +626,7 @@ DECLARE_EVENT_CLASS(nfs4_open_event,
                        const struct nfs4_state *state = ctx->state;
                        const struct inode *inode = NULL;
 
-                       __entry->error = error;
+                       __entry->error = -error;
                        __entry->flags = flags;
                        __entry->fmode = (__force unsigned int)ctx->mode;
                        __entry->dev = ctx->dentry->d_sb->s_dev;
@@ -609,11 +658,11 @@ DECLARE_EVENT_CLASS(nfs4_open_event,
                ),
 
                TP_printk(
-                       "error=%d (%s) flags=%d (%s) fmode=%s "
+                       "error=%ld (%s) flags=%d (%s) fmode=%s "
                        "fileid=%02x:%02x:%llu fhandle=0x%08x "
                        "name=%02x:%02x:%llu/%s stateid=%d:0x%08x "
                        "openstateid=%d:0x%08x",
-                        __entry->error,
+                        -__entry->error,
                         show_nfsv4_errors(__entry->error),
                         __entry->flags,
                         show_open_flags(__entry->flags),
@@ -695,7 +744,7 @@ TRACE_EVENT(nfs4_close,
                        __field(u32, fhandle)
                        __field(u64, fileid)
                        __field(unsigned int, fmode)
-                       __field(int, error)
+                       __field(unsigned long, error)
                        __field(int, stateid_seq)
                        __field(u32, stateid_hash)
                ),
@@ -715,9 +764,9 @@ TRACE_EVENT(nfs4_close,
                ),
 
                TP_printk(
-                       "error=%d (%s) fmode=%s fileid=%02x:%02x:%llu "
+                       "error=%ld (%s) fmode=%s fileid=%02x:%02x:%llu "
                        "fhandle=0x%08x openstateid=%d:0x%08x",
-                       __entry->error,
+                       -__entry->error,
                        show_nfsv4_errors(__entry->error),
                        __entry->fmode ?  show_fmode_flags(__entry->fmode) :
                                          "closed",
@@ -757,7 +806,7 @@ DECLARE_EVENT_CLASS(nfs4_lock_event,
                TP_ARGS(request, state, cmd, error),
 
                TP_STRUCT__entry(
-                       __field(int, error)
+                       __field(unsigned long, error)
                        __field(int, cmd)
                        __field(char, type)
                        __field(loff_t, start)
@@ -787,10 +836,10 @@ DECLARE_EVENT_CLASS(nfs4_lock_event,
                ),
 
                TP_printk(
-                       "error=%d (%s) cmd=%s:%s range=%lld:%lld "
+                       "error=%ld (%s) cmd=%s:%s range=%lld:%lld "
                        "fileid=%02x:%02x:%llu fhandle=0x%08x "
                        "stateid=%d:0x%08x",
-                       __entry->error,
+                       -__entry->error,
                        show_nfsv4_errors(__entry->error),
                        show_lock_cmd(__entry->cmd),
                        show_lock_type(__entry->type),
@@ -827,7 +876,7 @@ TRACE_EVENT(nfs4_set_lock,
                TP_ARGS(request, state, lockstateid, cmd, error),
 
                TP_STRUCT__entry(
-                       __field(int, error)
+                       __field(unsigned long, error)
                        __field(int, cmd)
                        __field(char, type)
                        __field(loff_t, start)
@@ -863,10 +912,10 @@ TRACE_EVENT(nfs4_set_lock,
                ),
 
                TP_printk(
-                       "error=%d (%s) cmd=%s:%s range=%lld:%lld "
+                       "error=%ld (%s) cmd=%s:%s range=%lld:%lld "
                        "fileid=%02x:%02x:%llu fhandle=0x%08x "
                        "stateid=%d:0x%08x lockstateid=%d:0x%08x",
-                       __entry->error,
+                       -__entry->error,
                        show_nfsv4_errors(__entry->error),
                        show_lock_cmd(__entry->cmd),
                        show_lock_type(__entry->type),
@@ -932,7 +981,7 @@ TRACE_EVENT(nfs4_delegreturn_exit,
                TP_STRUCT__entry(
                        __field(dev_t, dev)
                        __field(u32, fhandle)
-                       __field(int, error)
+                       __field(unsigned long, error)
                        __field(int, stateid_seq)
                        __field(u32, stateid_hash)
                ),
@@ -948,9 +997,9 @@ TRACE_EVENT(nfs4_delegreturn_exit,
                ),
 
                TP_printk(
-                       "error=%d (%s) dev=%02x:%02x fhandle=0x%08x "
+                       "error=%ld (%s) dev=%02x:%02x fhandle=0x%08x "
                        "stateid=%d:0x%08x",
-                       __entry->error,
+                       -__entry->error,
                        show_nfsv4_errors(__entry->error),
                        MAJOR(__entry->dev), MINOR(__entry->dev),
                        __entry->fhandle,
@@ -969,7 +1018,7 @@ DECLARE_EVENT_CLASS(nfs4_test_stateid_event,
                TP_ARGS(state, lsp, error),
 
                TP_STRUCT__entry(
-                       __field(int, error)
+                       __field(unsigned long, error)
                        __field(dev_t, dev)
                        __field(u32, fhandle)
                        __field(u64, fileid)
@@ -991,9 +1040,9 @@ DECLARE_EVENT_CLASS(nfs4_test_stateid_event,
                ),
 
                TP_printk(
-                       "error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
+                       "error=%ld (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
                        "stateid=%d:0x%08x",
-                       __entry->error,
+                       -__entry->error,
                        show_nfsv4_errors(__entry->error),
                        MAJOR(__entry->dev), MINOR(__entry->dev),
                        (unsigned long long)__entry->fileid,
@@ -1026,7 +1075,7 @@ DECLARE_EVENT_CLASS(nfs4_lookup_event,
 
                TP_STRUCT__entry(
                        __field(dev_t, dev)
-                       __field(int, error)
+                       __field(unsigned long, error)
                        __field(u64, dir)
                        __string(name, name->name)
                ),
@@ -1034,13 +1083,13 @@ DECLARE_EVENT_CLASS(nfs4_lookup_event,
                TP_fast_assign(
                        __entry->dev = dir->i_sb->s_dev;
                        __entry->dir = NFS_FILEID(dir);
-                       __entry->error = error;
+                       __entry->error = -error;
                        __assign_str(name, name->name);
                ),
 
                TP_printk(
-                       "error=%d (%s) name=%02x:%02x:%llu/%s",
-                       __entry->error,
+                       "error=%ld (%s) name=%02x:%02x:%llu/%s",
+                       -__entry->error,
                        show_nfsv4_errors(__entry->error),
                        MAJOR(__entry->dev), MINOR(__entry->dev),
                        (unsigned long long)__entry->dir,
@@ -1076,7 +1125,7 @@ TRACE_EVENT(nfs4_lookupp,
                TP_STRUCT__entry(
                        __field(dev_t, dev)
                        __field(u64, ino)
-                       __field(int, error)
+                       __field(unsigned long, error)
                ),
 
                TP_fast_assign(
@@ -1086,8 +1135,8 @@ TRACE_EVENT(nfs4_lookupp,
                ),
 
                TP_printk(
-                       "error=%d (%s) inode=%02x:%02x:%llu",
-                       __entry->error,
+                       "error=%ld (%s) inode=%02x:%02x:%llu",
+                       -__entry->error,
                        show_nfsv4_errors(__entry->error),
                        MAJOR(__entry->dev), MINOR(__entry->dev),
                        (unsigned long long)__entry->ino
@@ -1107,7 +1156,7 @@ TRACE_EVENT(nfs4_rename,
 
                TP_STRUCT__entry(
                        __field(dev_t, dev)
-                       __field(int, error)
+                       __field(unsigned long, error)
                        __field(u64, olddir)
                        __string(oldname, oldname->name)
                        __field(u64, newdir)
@@ -1124,9 +1173,9 @@ TRACE_EVENT(nfs4_rename,
                ),
 
                TP_printk(
-                       "error=%d (%s) oldname=%02x:%02x:%llu/%s "
+                       "error=%ld (%s) oldname=%02x:%02x:%llu/%s "
                        "newname=%02x:%02x:%llu/%s",
-                       __entry->error,
+                       -__entry->error,
                        show_nfsv4_errors(__entry->error),
                        MAJOR(__entry->dev), MINOR(__entry->dev),
                        (unsigned long long)__entry->olddir,
@@ -1149,19 +1198,19 @@ DECLARE_EVENT_CLASS(nfs4_inode_event,
                        __field(dev_t, dev)
                        __field(u32, fhandle)
                        __field(u64, fileid)
-                       __field(int, error)
+                       __field(unsigned long, error)
                ),
 
                TP_fast_assign(
                        __entry->dev = inode->i_sb->s_dev;
                        __entry->fileid = NFS_FILEID(inode);
                        __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
-                       __entry->error = error;
+                       __entry->error = error < 0 ? -error : 0;
                ),
 
                TP_printk(
-                       "error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x",
-                       __entry->error,
+                       "error=%ld (%s) fileid=%02x:%02x:%llu fhandle=0x%08x",
+                       -__entry->error,
                        show_nfsv4_errors(__entry->error),
                        MAJOR(__entry->dev), MINOR(__entry->dev),
                        (unsigned long long)__entry->fileid,
@@ -1200,7 +1249,7 @@ DECLARE_EVENT_CLASS(nfs4_inode_stateid_event,
                        __field(dev_t, dev)
                        __field(u32, fhandle)
                        __field(u64, fileid)
-                       __field(int, error)
+                       __field(unsigned long, error)
                        __field(int, stateid_seq)
                        __field(u32, stateid_hash)
                ),
@@ -1217,9 +1266,9 @@ DECLARE_EVENT_CLASS(nfs4_inode_stateid_event,
                ),
 
                TP_printk(
-                       "error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
+                       "error=%ld (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
                        "stateid=%d:0x%08x",
-                       __entry->error,
+                       -__entry->error,
                        show_nfsv4_errors(__entry->error),
                        MAJOR(__entry->dev), MINOR(__entry->dev),
                        (unsigned long long)__entry->fileid,
@@ -1257,7 +1306,7 @@ DECLARE_EVENT_CLASS(nfs4_getattr_event,
                        __field(u32, fhandle)
                        __field(u64, fileid)
                        __field(unsigned int, valid)
-                       __field(int, error)
+                       __field(unsigned long, error)
                ),
 
                TP_fast_assign(
@@ -1269,9 +1318,9 @@ DECLARE_EVENT_CLASS(nfs4_getattr_event,
                ),
 
                TP_printk(
-                       "error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
+                       "error=%ld (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
                        "valid=%s",
-                       __entry->error,
+                       -__entry->error,
                        show_nfsv4_errors(__entry->error),
                        MAJOR(__entry->dev), MINOR(__entry->dev),
                        (unsigned long long)__entry->fileid,
@@ -1304,7 +1353,7 @@ DECLARE_EVENT_CLASS(nfs4_inode_callback_event,
                TP_ARGS(clp, fhandle, inode, error),
 
                TP_STRUCT__entry(
-                       __field(int, error)
+                       __field(unsigned long, error)
                        __field(dev_t, dev)
                        __field(u32, fhandle)
                        __field(u64, fileid)
@@ -1325,9 +1374,9 @@ DECLARE_EVENT_CLASS(nfs4_inode_callback_event,
                ),
 
                TP_printk(
-                       "error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
+                       "error=%ld (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
                        "dstaddr=%s",
-                       __entry->error,
+                       -__entry->error,
                        show_nfsv4_errors(__entry->error),
                        MAJOR(__entry->dev), MINOR(__entry->dev),
                        (unsigned long long)__entry->fileid,
@@ -1359,7 +1408,7 @@ DECLARE_EVENT_CLASS(nfs4_inode_stateid_callback_event,
                TP_ARGS(clp, fhandle, inode, stateid, error),
 
                TP_STRUCT__entry(
-                       __field(int, error)
+                       __field(unsigned long, error)
                        __field(dev_t, dev)
                        __field(u32, fhandle)
                        __field(u64, fileid)
@@ -1386,9 +1435,9 @@ DECLARE_EVENT_CLASS(nfs4_inode_stateid_callback_event,
                ),
 
                TP_printk(
-                       "error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
+                       "error=%ld (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
                        "stateid=%d:0x%08x dstaddr=%s",
-                       __entry->error,
+                       -__entry->error,
                        show_nfsv4_errors(__entry->error),
                        MAJOR(__entry->dev), MINOR(__entry->dev),
                        (unsigned long long)__entry->fileid,
@@ -1422,7 +1471,7 @@ DECLARE_EVENT_CLASS(nfs4_idmap_event,
                TP_ARGS(name, len, id, error),
 
                TP_STRUCT__entry(
-                       __field(int, error)
+                       __field(unsigned long, error)
                        __field(u32, id)
                        __dynamic_array(char, name, len > 0 ? len + 1 : 1)
                ),
@@ -1437,8 +1486,8 @@ DECLARE_EVENT_CLASS(nfs4_idmap_event,
                ),
 
                TP_printk(
-                       "error=%d id=%u name=%s",
-                       __entry->error,
+                       "error=%ld (%s) id=%u name=%s",
+                       -__entry->error, show_nfsv4_errors(__entry->error),
                        __entry->id,
                        __get_str(name)
                )
@@ -1471,7 +1520,7 @@ DECLARE_EVENT_CLASS(nfs4_read_event,
                        __field(u64, fileid)
                        __field(loff_t, offset)
                        __field(size_t, count)
-                       __field(int, error)
+                       __field(unsigned long, error)
                        __field(int, stateid_seq)
                        __field(u32, stateid_hash)
                ),
@@ -1485,7 +1534,7 @@ DECLARE_EVENT_CLASS(nfs4_read_event,
                        __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
                        __entry->offset = hdr->args.offset;
                        __entry->count = hdr->args.count;
-                       __entry->error = error;
+                       __entry->error = error < 0 ? -error : 0;
                        __entry->stateid_seq =
                                be32_to_cpu(state->stateid.seqid);
                        __entry->stateid_hash =
@@ -1493,9 +1542,9 @@ DECLARE_EVENT_CLASS(nfs4_read_event,
                ),
 
                TP_printk(
-                       "error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
+                       "error=%ld (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
                        "offset=%lld count=%zu stateid=%d:0x%08x",
-                       __entry->error,
+                       -__entry->error,
                        show_nfsv4_errors(__entry->error),
                        MAJOR(__entry->dev), MINOR(__entry->dev),
                        (unsigned long long)__entry->fileid,
@@ -1531,7 +1580,7 @@ DECLARE_EVENT_CLASS(nfs4_write_event,
                        __field(u64, fileid)
                        __field(loff_t, offset)
                        __field(size_t, count)
-                       __field(int, error)
+                       __field(unsigned long, error)
                        __field(int, stateid_seq)
                        __field(u32, stateid_hash)
                ),
@@ -1545,7 +1594,7 @@ DECLARE_EVENT_CLASS(nfs4_write_event,
                        __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
                        __entry->offset = hdr->args.offset;
                        __entry->count = hdr->args.count;
-                       __entry->error = error;
+                       __entry->error = error < 0 ? -error : 0;
                        __entry->stateid_seq =
                                be32_to_cpu(state->stateid.seqid);
                        __entry->stateid_hash =
@@ -1553,9 +1602,9 @@ DECLARE_EVENT_CLASS(nfs4_write_event,
                ),
 
                TP_printk(
-                       "error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
+                       "error=%ld (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
                        "offset=%lld count=%zu stateid=%d:0x%08x",
-                       __entry->error,
+                       -__entry->error,
                        show_nfsv4_errors(__entry->error),
                        MAJOR(__entry->dev), MINOR(__entry->dev),
                        (unsigned long long)__entry->fileid,
@@ -1592,7 +1641,7 @@ DECLARE_EVENT_CLASS(nfs4_commit_event,
                        __field(u64, fileid)
                        __field(loff_t, offset)
                        __field(size_t, count)
-                       __field(int, error)
+                       __field(unsigned long, error)
                ),
 
                TP_fast_assign(
@@ -1606,9 +1655,9 @@ DECLARE_EVENT_CLASS(nfs4_commit_event,
                ),
 
                TP_printk(
-                       "error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
+                       "error=%ld (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
                        "offset=%lld count=%zu",
-                       __entry->error,
+                       -__entry->error,
                        show_nfsv4_errors(__entry->error),
                        MAJOR(__entry->dev), MINOR(__entry->dev),
                        (unsigned long long)__entry->fileid,
@@ -1656,7 +1705,7 @@ TRACE_EVENT(nfs4_layoutget,
                        __field(u32, iomode)
                        __field(u64, offset)
                        __field(u64, count)
-                       __field(int, error)
+                       __field(unsigned long, error)
                        __field(int, stateid_seq)
                        __field(u32, stateid_hash)
                        __field(int, layoutstateid_seq)
@@ -1689,10 +1738,10 @@ TRACE_EVENT(nfs4_layoutget,
                ),
 
                TP_printk(
-                       "error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
+                       "error=%ld (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
                        "iomode=%s offset=%llu count=%llu stateid=%d:0x%08x "
                        "layoutstateid=%d:0x%08x",
-                       __entry->error,
+                       -__entry->error,
                        show_nfsv4_errors(__entry->error),
                        MAJOR(__entry->dev), MINOR(__entry->dev),
                        (unsigned long long)__entry->fileid,
@@ -1722,6 +1771,7 @@ TRACE_DEFINE_ENUM(PNFS_UPDATE_LAYOUT_BLOCKED);
 TRACE_DEFINE_ENUM(PNFS_UPDATE_LAYOUT_INVALID_OPEN);
 TRACE_DEFINE_ENUM(PNFS_UPDATE_LAYOUT_RETRY);
 TRACE_DEFINE_ENUM(PNFS_UPDATE_LAYOUT_SEND_LAYOUTGET);
+TRACE_DEFINE_ENUM(PNFS_UPDATE_LAYOUT_EXIT);
 
 #define show_pnfs_update_layout_reason(reason)                         \
        __print_symbolic(reason,                                        \
@@ -1737,7 +1787,8 @@ TRACE_DEFINE_ENUM(PNFS_UPDATE_LAYOUT_SEND_LAYOUTGET);
                { PNFS_UPDATE_LAYOUT_BLOCKED, "layouts blocked" },      \
                { PNFS_UPDATE_LAYOUT_INVALID_OPEN, "invalid open" },    \
                { PNFS_UPDATE_LAYOUT_RETRY, "retrying" },       \
-               { PNFS_UPDATE_LAYOUT_SEND_LAYOUTGET, "sent layoutget" })
+               { PNFS_UPDATE_LAYOUT_SEND_LAYOUTGET, "sent layoutget" }, \
+               { PNFS_UPDATE_LAYOUT_EXIT, "exit" })
 
 TRACE_EVENT(pnfs_update_layout,
                TP_PROTO(struct inode *inode,
@@ -1796,6 +1847,78 @@ TRACE_EVENT(pnfs_update_layout,
                )
 );
 
+DECLARE_EVENT_CLASS(pnfs_layout_event,
+               TP_PROTO(struct inode *inode,
+                       loff_t pos,
+                       u64 count,
+                       enum pnfs_iomode iomode,
+                       struct pnfs_layout_hdr *lo,
+                       struct pnfs_layout_segment *lseg
+               ),
+               TP_ARGS(inode, pos, count, iomode, lo, lseg),
+               TP_STRUCT__entry(
+                       __field(dev_t, dev)
+                       __field(u64, fileid)
+                       __field(u32, fhandle)
+                       __field(loff_t, pos)
+                       __field(u64, count)
+                       __field(enum pnfs_iomode, iomode)
+                       __field(int, layoutstateid_seq)
+                       __field(u32, layoutstateid_hash)
+                       __field(long, lseg)
+               ),
+               TP_fast_assign(
+                       __entry->dev = inode->i_sb->s_dev;
+                       __entry->fileid = NFS_FILEID(inode);
+                       __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
+                       __entry->pos = pos;
+                       __entry->count = count;
+                       __entry->iomode = iomode;
+                       if (lo != NULL) {
+                               __entry->layoutstateid_seq =
+                               be32_to_cpu(lo->plh_stateid.seqid);
+                               __entry->layoutstateid_hash =
+                               nfs_stateid_hash(&lo->plh_stateid);
+                       } else {
+                               __entry->layoutstateid_seq = 0;
+                               __entry->layoutstateid_hash = 0;
+                       }
+                       __entry->lseg = (long)lseg;
+               ),
+               TP_printk(
+                       "fileid=%02x:%02x:%llu fhandle=0x%08x "
+                       "iomode=%s pos=%llu count=%llu "
+                       "layoutstateid=%d:0x%08x lseg=0x%lx",
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->fileid,
+                       __entry->fhandle,
+                       show_pnfs_iomode(__entry->iomode),
+                       (unsigned long long)__entry->pos,
+                       (unsigned long long)__entry->count,
+                       __entry->layoutstateid_seq, __entry->layoutstateid_hash,
+                       __entry->lseg
+               )
+);
+
+#define DEFINE_PNFS_LAYOUT_EVENT(name) \
+       DEFINE_EVENT(pnfs_layout_event, name, \
+               TP_PROTO(struct inode *inode, \
+                       loff_t pos, \
+                       u64 count, \
+                       enum pnfs_iomode iomode, \
+                       struct pnfs_layout_hdr *lo, \
+                       struct pnfs_layout_segment *lseg \
+               ), \
+               TP_ARGS(inode, pos, count, iomode, lo, lseg))
+
+DEFINE_PNFS_LAYOUT_EVENT(pnfs_mds_fallback_pg_init_read);
+DEFINE_PNFS_LAYOUT_EVENT(pnfs_mds_fallback_pg_init_write);
+DEFINE_PNFS_LAYOUT_EVENT(pnfs_mds_fallback_pg_get_mirror_count);
+DEFINE_PNFS_LAYOUT_EVENT(pnfs_mds_fallback_read_done);
+DEFINE_PNFS_LAYOUT_EVENT(pnfs_mds_fallback_write_done);
+DEFINE_PNFS_LAYOUT_EVENT(pnfs_mds_fallback_read_pagelist);
+DEFINE_PNFS_LAYOUT_EVENT(pnfs_mds_fallback_write_pagelist);
+
 #endif /* CONFIG_NFS_V4_1 */
 
 #endif /* _TRACE_NFS4_H */
index 6024461..46a8d63 100644 (file)
@@ -837,6 +837,7 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
 #define NFS4_dec_sequence_sz \
                                (compound_decode_hdr_maxsz + \
                                 decode_sequence_maxsz)
+#endif
 #define NFS4_enc_get_lease_time_sz     (compound_encode_hdr_maxsz + \
                                         encode_sequence_maxsz + \
                                         encode_putrootfh_maxsz + \
@@ -845,6 +846,7 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
                                         decode_sequence_maxsz + \
                                         decode_putrootfh_maxsz + \
                                         decode_fsinfo_maxsz)
+#if defined(CONFIG_NFS_V4_1)
 #define NFS4_enc_reclaim_complete_sz   (compound_encode_hdr_maxsz + \
                                         encode_sequence_maxsz + \
                                         encode_reclaim_complete_maxsz)
@@ -2957,6 +2959,8 @@ static void nfs4_xdr_enc_sequence(struct rpc_rqst *req, struct xdr_stream *xdr,
        encode_nops(&hdr);
 }
 
+#endif
+
 /*
  * a GET_LEASE_TIME request
  */
@@ -2977,6 +2981,8 @@ static void nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req,
        encode_nops(&hdr);
 }
 
+#ifdef CONFIG_NFS_V4_1
+
 /*
  * a RECLAIM_COMPLETE request
  */
@@ -3187,7 +3193,7 @@ static bool __decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected,
        return true;
 out_status:
        nfserr = be32_to_cpup(p);
-       trace_nfs4_xdr_status(opnum, nfserr);
+       trace_nfs4_xdr_status(xdr, opnum, nfserr);
        *nfs_retval = nfs4_stat_to_errno(nfserr);
        return true;
 out_bad_operation:
@@ -3427,7 +3433,7 @@ static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint
                *res = be32_to_cpup(p);
                bitmap[0] &= ~FATTR4_WORD0_LEASE_TIME;
        }
-       dprintk("%s: file size=%u\n", __func__, (unsigned int)*res);
+       dprintk("%s: lease time=%u\n", __func__, (unsigned int)*res);
        return 0;
 }
 
@@ -7122,6 +7128,8 @@ static int nfs4_xdr_dec_sequence(struct rpc_rqst *rqstp,
        return status;
 }
 
+#endif
+
 /*
  * Decode GET_LEASE_TIME response
  */
@@ -7143,6 +7151,8 @@ static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp,
        return status;
 }
 
+#ifdef CONFIG_NFS_V4_1
+
 /*
  * Decode RECLAIM_COMPLETE response
  */
@@ -7551,7 +7561,7 @@ const struct rpc_procinfo nfs4_procedures[] = {
        PROC41(CREATE_SESSION,  enc_create_session,     dec_create_session),
        PROC41(DESTROY_SESSION, enc_destroy_session,    dec_destroy_session),
        PROC41(SEQUENCE,        enc_sequence,           dec_sequence),
-       PROC41(GET_LEASE_TIME,  enc_get_lease_time,     dec_get_lease_time),
+       PROC(GET_LEASE_TIME,    enc_get_lease_time,     dec_get_lease_time),
        PROC41(RECLAIM_COMPLETE,enc_reclaim_complete,   dec_reclaim_complete),
        PROC41(GETDEVICEINFO,   enc_getdeviceinfo,      dec_getdeviceinfo),
        PROC41(LAYOUTGET,       enc_layoutget,          dec_layoutget),
index a0d6910..976d408 100644 (file)
 #include <linux/tracepoint.h>
 #include <linux/iversion.h>
 
+TRACE_DEFINE_ENUM(DT_UNKNOWN);
+TRACE_DEFINE_ENUM(DT_FIFO);
+TRACE_DEFINE_ENUM(DT_CHR);
+TRACE_DEFINE_ENUM(DT_DIR);
+TRACE_DEFINE_ENUM(DT_BLK);
+TRACE_DEFINE_ENUM(DT_REG);
+TRACE_DEFINE_ENUM(DT_LNK);
+TRACE_DEFINE_ENUM(DT_SOCK);
+TRACE_DEFINE_ENUM(DT_WHT);
+
 #define nfs_show_file_type(ftype) \
        __print_symbolic(ftype, \
                        { DT_UNKNOWN, "UNKNOWN" }, \
                        { DT_SOCK, "SOCK" }, \
                        { DT_WHT, "WHT" })
 
+TRACE_DEFINE_ENUM(NFS_INO_INVALID_DATA);
+TRACE_DEFINE_ENUM(NFS_INO_INVALID_ATIME);
+TRACE_DEFINE_ENUM(NFS_INO_INVALID_ACCESS);
+TRACE_DEFINE_ENUM(NFS_INO_INVALID_ACL);
+TRACE_DEFINE_ENUM(NFS_INO_REVAL_PAGECACHE);
+TRACE_DEFINE_ENUM(NFS_INO_REVAL_FORCED);
+TRACE_DEFINE_ENUM(NFS_INO_INVALID_LABEL);
+TRACE_DEFINE_ENUM(NFS_INO_INVALID_CHANGE);
+TRACE_DEFINE_ENUM(NFS_INO_INVALID_CTIME);
+TRACE_DEFINE_ENUM(NFS_INO_INVALID_MTIME);
+TRACE_DEFINE_ENUM(NFS_INO_INVALID_SIZE);
+TRACE_DEFINE_ENUM(NFS_INO_INVALID_OTHER);
+
 #define nfs_show_cache_validity(v) \
        __print_flags(v, "|", \
-                       { NFS_INO_INVALID_ATTR, "INVALID_ATTR" }, \
                        { NFS_INO_INVALID_DATA, "INVALID_DATA" }, \
                        { NFS_INO_INVALID_ATIME, "INVALID_ATIME" }, \
                        { NFS_INO_INVALID_ACCESS, "INVALID_ACCESS" }, \
                        { NFS_INO_INVALID_ACL, "INVALID_ACL" }, \
                        { NFS_INO_REVAL_PAGECACHE, "REVAL_PAGECACHE" }, \
                        { NFS_INO_REVAL_FORCED, "REVAL_FORCED" }, \
-                       { NFS_INO_INVALID_LABEL, "INVALID_LABEL" })
+                       { NFS_INO_INVALID_LABEL, "INVALID_LABEL" }, \
+                       { NFS_INO_INVALID_CHANGE, "INVALID_CHANGE" }, \
+                       { NFS_INO_INVALID_CTIME, "INVALID_CTIME" }, \
+                       { NFS_INO_INVALID_MTIME, "INVALID_MTIME" }, \
+                       { NFS_INO_INVALID_SIZE, "INVALID_SIZE" }, \
+                       { NFS_INO_INVALID_OTHER, "INVALID_OTHER" })
+
+TRACE_DEFINE_ENUM(NFS_INO_ADVISE_RDPLUS);
+TRACE_DEFINE_ENUM(NFS_INO_STALE);
+TRACE_DEFINE_ENUM(NFS_INO_ACL_LRU_SET);
+TRACE_DEFINE_ENUM(NFS_INO_INVALIDATING);
+TRACE_DEFINE_ENUM(NFS_INO_FSCACHE);
+TRACE_DEFINE_ENUM(NFS_INO_FSCACHE_LOCK);
+TRACE_DEFINE_ENUM(NFS_INO_LAYOUTCOMMIT);
+TRACE_DEFINE_ENUM(NFS_INO_LAYOUTCOMMITTING);
+TRACE_DEFINE_ENUM(NFS_INO_LAYOUTSTATS);
+TRACE_DEFINE_ENUM(NFS_INO_ODIRECT);
 
 #define nfs_show_nfsi_flags(v) \
        __print_flags(v, "|", \
-                       { 1 << NFS_INO_ADVISE_RDPLUS, "ADVISE_RDPLUS" }, \
-                       { 1 << NFS_INO_STALE, "STALE" }, \
-                       { 1 << NFS_INO_INVALIDATING, "INVALIDATING" }, \
-                       { 1 << NFS_INO_FSCACHE, "FSCACHE" }, \
-                       { 1 << NFS_INO_LAYOUTCOMMIT, "NEED_LAYOUTCOMMIT" }, \
-                       { 1 << NFS_INO_LAYOUTCOMMITTING, "LAYOUTCOMMIT" })
+                       { BIT(NFS_INO_ADVISE_RDPLUS), "ADVISE_RDPLUS" }, \
+                       { BIT(NFS_INO_STALE), "STALE" }, \
+                       { BIT(NFS_INO_ACL_LRU_SET), "ACL_LRU_SET" }, \
+                       { BIT(NFS_INO_INVALIDATING), "INVALIDATING" }, \
+                       { BIT(NFS_INO_FSCACHE), "FSCACHE" }, \
+                       { BIT(NFS_INO_FSCACHE_LOCK), "FSCACHE_LOCK" }, \
+                       { BIT(NFS_INO_LAYOUTCOMMIT), "NEED_LAYOUTCOMMIT" }, \
+                       { BIT(NFS_INO_LAYOUTCOMMITTING), "LAYOUTCOMMIT" }, \
+                       { BIT(NFS_INO_LAYOUTSTATS), "LAYOUTSTATS" }, \
+                       { BIT(NFS_INO_ODIRECT), "ODIRECT" })
 
 DECLARE_EVENT_CLASS(nfs_inode_event,
                TP_PROTO(
@@ -83,7 +125,7 @@ DECLARE_EVENT_CLASS(nfs_inode_event_done,
                TP_ARGS(inode, error),
 
                TP_STRUCT__entry(
-                       __field(int, error)
+                       __field(unsigned long, error)
                        __field(dev_t, dev)
                        __field(u32, fhandle)
                        __field(unsigned char, type)
@@ -96,7 +138,7 @@ DECLARE_EVENT_CLASS(nfs_inode_event_done,
 
                TP_fast_assign(
                        const struct nfs_inode *nfsi = NFS_I(inode);
-                       __entry->error = error;
+                       __entry->error = error < 0 ? -error : 0;
                        __entry->dev = inode->i_sb->s_dev;
                        __entry->fileid = nfsi->fileid;
                        __entry->fhandle = nfs_fhandle_hash(&nfsi->fh);
@@ -108,10 +150,10 @@ DECLARE_EVENT_CLASS(nfs_inode_event_done,
                ),
 
                TP_printk(
-                       "error=%d fileid=%02x:%02x:%llu fhandle=0x%08x "
+                       "error=%ld (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
                        "type=%u (%s) version=%llu size=%lld "
-                       "cache_validity=%lu (%s) nfs_flags=%ld (%s)",
-                       __entry->error,
+                       "cache_validity=0x%lx (%s) nfs_flags=0x%lx (%s)",
+                       -__entry->error, nfs_show_status(__entry->error),
                        MAJOR(__entry->dev), MINOR(__entry->dev),
                        (unsigned long long)__entry->fileid,
                        __entry->fhandle,
@@ -158,13 +200,41 @@ DEFINE_NFS_INODE_EVENT_DONE(nfs_fsync_exit);
 DEFINE_NFS_INODE_EVENT(nfs_access_enter);
 DEFINE_NFS_INODE_EVENT_DONE(nfs_access_exit);
 
+TRACE_DEFINE_ENUM(LOOKUP_FOLLOW);
+TRACE_DEFINE_ENUM(LOOKUP_DIRECTORY);
+TRACE_DEFINE_ENUM(LOOKUP_AUTOMOUNT);
+TRACE_DEFINE_ENUM(LOOKUP_PARENT);
+TRACE_DEFINE_ENUM(LOOKUP_REVAL);
+TRACE_DEFINE_ENUM(LOOKUP_RCU);
+TRACE_DEFINE_ENUM(LOOKUP_NO_REVAL);
+TRACE_DEFINE_ENUM(LOOKUP_NO_EVAL);
+TRACE_DEFINE_ENUM(LOOKUP_OPEN);
+TRACE_DEFINE_ENUM(LOOKUP_CREATE);
+TRACE_DEFINE_ENUM(LOOKUP_EXCL);
+TRACE_DEFINE_ENUM(LOOKUP_RENAME_TARGET);
+TRACE_DEFINE_ENUM(LOOKUP_JUMPED);
+TRACE_DEFINE_ENUM(LOOKUP_ROOT);
+TRACE_DEFINE_ENUM(LOOKUP_EMPTY);
+TRACE_DEFINE_ENUM(LOOKUP_DOWN);
+
 #define show_lookup_flags(flags) \
-       __print_flags((unsigned long)flags, "|", \
-                       { LOOKUP_AUTOMOUNT, "AUTOMOUNT" }, \
+       __print_flags(flags, "|", \
+                       { LOOKUP_FOLLOW, "FOLLOW" }, \
                        { LOOKUP_DIRECTORY, "DIRECTORY" }, \
+                       { LOOKUP_AUTOMOUNT, "AUTOMOUNT" }, \
+                       { LOOKUP_PARENT, "PARENT" }, \
+                       { LOOKUP_REVAL, "REVAL" }, \
+                       { LOOKUP_RCU, "RCU" }, \
+                       { LOOKUP_NO_REVAL, "NO_REVAL" }, \
+                       { LOOKUP_NO_EVAL, "NO_EVAL" }, \
                        { LOOKUP_OPEN, "OPEN" }, \
                        { LOOKUP_CREATE, "CREATE" }, \
-                       { LOOKUP_EXCL, "EXCL" })
+                       { LOOKUP_EXCL, "EXCL" }, \
+                       { LOOKUP_RENAME_TARGET, "RENAME_TARGET" }, \
+                       { LOOKUP_JUMPED, "JUMPED" }, \
+                       { LOOKUP_ROOT, "ROOT" }, \
+                       { LOOKUP_EMPTY, "EMPTY" }, \
+                       { LOOKUP_DOWN, "DOWN" })
 
 DECLARE_EVENT_CLASS(nfs_lookup_event,
                TP_PROTO(
@@ -176,7 +246,7 @@ DECLARE_EVENT_CLASS(nfs_lookup_event,
                TP_ARGS(dir, dentry, flags),
 
                TP_STRUCT__entry(
-                       __field(unsigned int, flags)
+                       __field(unsigned long, flags)
                        __field(dev_t, dev)
                        __field(u64, dir)
                        __string(name, dentry->d_name.name)
@@ -190,7 +260,7 @@ DECLARE_EVENT_CLASS(nfs_lookup_event,
                ),
 
                TP_printk(
-                       "flags=%u (%s) name=%02x:%02x:%llu/%s",
+                       "flags=0x%lx (%s) name=%02x:%02x:%llu/%s",
                        __entry->flags,
                        show_lookup_flags(__entry->flags),
                        MAJOR(__entry->dev), MINOR(__entry->dev),
@@ -219,8 +289,8 @@ DECLARE_EVENT_CLASS(nfs_lookup_event_done,
                TP_ARGS(dir, dentry, flags, error),
 
                TP_STRUCT__entry(
-                       __field(int, error)
-                       __field(unsigned int, flags)
+                       __field(unsigned long, error)
+                       __field(unsigned long, flags)
                        __field(dev_t, dev)
                        __field(u64, dir)
                        __string(name, dentry->d_name.name)
@@ -229,14 +299,14 @@ DECLARE_EVENT_CLASS(nfs_lookup_event_done,
                TP_fast_assign(
                        __entry->dev = dir->i_sb->s_dev;
                        __entry->dir = NFS_FILEID(dir);
-                       __entry->error = error;
+                       __entry->error = error < 0 ? -error : 0;
                        __entry->flags = flags;
                        __assign_str(name, dentry->d_name.name);
                ),
 
                TP_printk(
-                       "error=%d flags=%u (%s) name=%02x:%02x:%llu/%s",
-                       __entry->error,
+                       "error=%ld (%s) flags=0x%lx (%s) name=%02x:%02x:%llu/%s",
+                       -__entry->error, nfs_show_status(__entry->error),
                        __entry->flags,
                        show_lookup_flags(__entry->flags),
                        MAJOR(__entry->dev), MINOR(__entry->dev),
@@ -260,15 +330,43 @@ DEFINE_NFS_LOOKUP_EVENT_DONE(nfs_lookup_exit);
 DEFINE_NFS_LOOKUP_EVENT(nfs_lookup_revalidate_enter);
 DEFINE_NFS_LOOKUP_EVENT_DONE(nfs_lookup_revalidate_exit);
 
+TRACE_DEFINE_ENUM(O_WRONLY);
+TRACE_DEFINE_ENUM(O_RDWR);
+TRACE_DEFINE_ENUM(O_CREAT);
+TRACE_DEFINE_ENUM(O_EXCL);
+TRACE_DEFINE_ENUM(O_NOCTTY);
+TRACE_DEFINE_ENUM(O_TRUNC);
+TRACE_DEFINE_ENUM(O_APPEND);
+TRACE_DEFINE_ENUM(O_NONBLOCK);
+TRACE_DEFINE_ENUM(O_DSYNC);
+TRACE_DEFINE_ENUM(O_DIRECT);
+TRACE_DEFINE_ENUM(O_LARGEFILE);
+TRACE_DEFINE_ENUM(O_DIRECTORY);
+TRACE_DEFINE_ENUM(O_NOFOLLOW);
+TRACE_DEFINE_ENUM(O_NOATIME);
+TRACE_DEFINE_ENUM(O_CLOEXEC);
+
 #define show_open_flags(flags) \
-       __print_flags((unsigned long)flags, "|", \
+       __print_flags(flags, "|", \
+               { O_WRONLY, "O_WRONLY" }, \
+               { O_RDWR, "O_RDWR" }, \
                { O_CREAT, "O_CREAT" }, \
                { O_EXCL, "O_EXCL" }, \
+               { O_NOCTTY, "O_NOCTTY" }, \
                { O_TRUNC, "O_TRUNC" }, \
                { O_APPEND, "O_APPEND" }, \
+               { O_NONBLOCK, "O_NONBLOCK" }, \
                { O_DSYNC, "O_DSYNC" }, \
                { O_DIRECT, "O_DIRECT" }, \
-               { O_DIRECTORY, "O_DIRECTORY" })
+               { O_LARGEFILE, "O_LARGEFILE" }, \
+               { O_DIRECTORY, "O_DIRECTORY" }, \
+               { O_NOFOLLOW, "O_NOFOLLOW" }, \
+               { O_NOATIME, "O_NOATIME" }, \
+               { O_CLOEXEC, "O_CLOEXEC" })
+
+TRACE_DEFINE_ENUM(FMODE_READ);
+TRACE_DEFINE_ENUM(FMODE_WRITE);
+TRACE_DEFINE_ENUM(FMODE_EXEC);
 
 #define show_fmode_flags(mode) \
        __print_flags(mode, "|", \
@@ -286,7 +384,7 @@ TRACE_EVENT(nfs_atomic_open_enter,
                TP_ARGS(dir, ctx, flags),
 
                TP_STRUCT__entry(
-                       __field(unsigned int, flags)
+                       __field(unsigned long, flags)
                        __field(unsigned int, fmode)
                        __field(dev_t, dev)
                        __field(u64, dir)
@@ -302,7 +400,7 @@ TRACE_EVENT(nfs_atomic_open_enter,
                ),
 
                TP_printk(
-                       "flags=%u (%s) fmode=%s name=%02x:%02x:%llu/%s",
+                       "flags=0x%lx (%s) fmode=%s name=%02x:%02x:%llu/%s",
                        __entry->flags,
                        show_open_flags(__entry->flags),
                        show_fmode_flags(__entry->fmode),
@@ -323,8 +421,8 @@ TRACE_EVENT(nfs_atomic_open_exit,
                TP_ARGS(dir, ctx, flags, error),
 
                TP_STRUCT__entry(
-                       __field(int, error)
-                       __field(unsigned int, flags)
+                       __field(unsigned long, error)
+                       __field(unsigned long, flags)
                        __field(unsigned int, fmode)
                        __field(dev_t, dev)
                        __field(u64, dir)
@@ -332,7 +430,7 @@ TRACE_EVENT(nfs_atomic_open_exit,
                ),
 
                TP_fast_assign(
-                       __entry->error = error;
+                       __entry->error = -error;
                        __entry->dev = dir->i_sb->s_dev;
                        __entry->dir = NFS_FILEID(dir);
                        __entry->flags = flags;
@@ -341,9 +439,9 @@ TRACE_EVENT(nfs_atomic_open_exit,
                ),
 
                TP_printk(
-                       "error=%d flags=%u (%s) fmode=%s "
+                       "error=%ld (%s) flags=0x%lx (%s) fmode=%s "
                        "name=%02x:%02x:%llu/%s",
-                       __entry->error,
+                       -__entry->error, nfs_show_status(__entry->error),
                        __entry->flags,
                        show_open_flags(__entry->flags),
                        show_fmode_flags(__entry->fmode),
@@ -363,7 +461,7 @@ TRACE_EVENT(nfs_create_enter,
                TP_ARGS(dir, dentry, flags),
 
                TP_STRUCT__entry(
-                       __field(unsigned int, flags)
+                       __field(unsigned long, flags)
                        __field(dev_t, dev)
                        __field(u64, dir)
                        __string(name, dentry->d_name.name)
@@ -377,7 +475,7 @@ TRACE_EVENT(nfs_create_enter,
                ),
 
                TP_printk(
-                       "flags=%u (%s) name=%02x:%02x:%llu/%s",
+                       "flags=0x%lx (%s) name=%02x:%02x:%llu/%s",
                        __entry->flags,
                        show_open_flags(__entry->flags),
                        MAJOR(__entry->dev), MINOR(__entry->dev),
@@ -397,15 +495,15 @@ TRACE_EVENT(nfs_create_exit,
                TP_ARGS(dir, dentry, flags, error),
 
                TP_STRUCT__entry(
-                       __field(int, error)
-                       __field(unsigned int, flags)
+                       __field(unsigned long, error)
+                       __field(unsigned long, flags)
                        __field(dev_t, dev)
                        __field(u64, dir)
                        __string(name, dentry->d_name.name)
                ),
 
                TP_fast_assign(
-                       __entry->error = error;
+                       __entry->error = -error;
                        __entry->dev = dir->i_sb->s_dev;
                        __entry->dir = NFS_FILEID(dir);
                        __entry->flags = flags;
@@ -413,8 +511,8 @@ TRACE_EVENT(nfs_create_exit,
                ),
 
                TP_printk(
-                       "error=%d flags=%u (%s) name=%02x:%02x:%llu/%s",
-                       __entry->error,
+                       "error=%ld (%s) flags=0x%lx (%s) name=%02x:%02x:%llu/%s",
+                       -__entry->error, nfs_show_status(__entry->error),
                        __entry->flags,
                        show_open_flags(__entry->flags),
                        MAJOR(__entry->dev), MINOR(__entry->dev),
@@ -469,7 +567,7 @@ DECLARE_EVENT_CLASS(nfs_directory_event_done,
                TP_ARGS(dir, dentry, error),
 
                TP_STRUCT__entry(
-                       __field(int, error)
+                       __field(unsigned long, error)
                        __field(dev_t, dev)
                        __field(u64, dir)
                        __string(name, dentry->d_name.name)
@@ -478,13 +576,13 @@ DECLARE_EVENT_CLASS(nfs_directory_event_done,
                TP_fast_assign(
                        __entry->dev = dir->i_sb->s_dev;
                        __entry->dir = NFS_FILEID(dir);
-                       __entry->error = error;
+                       __entry->error = error < 0 ? -error : 0;
                        __assign_str(name, dentry->d_name.name);
                ),
 
                TP_printk(
-                       "error=%d name=%02x:%02x:%llu/%s",
-                       __entry->error,
+                       "error=%ld (%s) name=%02x:%02x:%llu/%s",
+                       -__entry->error, nfs_show_status(__entry->error),
                        MAJOR(__entry->dev), MINOR(__entry->dev),
                        (unsigned long long)__entry->dir,
                        __get_str(name)
@@ -557,7 +655,7 @@ TRACE_EVENT(nfs_link_exit,
                TP_ARGS(inode, dir, dentry, error),
 
                TP_STRUCT__entry(
-                       __field(int, error)
+                       __field(unsigned long, error)
                        __field(dev_t, dev)
                        __field(u64, fileid)
                        __field(u64, dir)
@@ -568,13 +666,13 @@ TRACE_EVENT(nfs_link_exit,
                        __entry->dev = inode->i_sb->s_dev;
                        __entry->fileid = NFS_FILEID(inode);
                        __entry->dir = NFS_FILEID(dir);
-                       __entry->error = error;
+                       __entry->error = error < 0 ? -error : 0;
                        __assign_str(name, dentry->d_name.name);
                ),
 
                TP_printk(
-                       "error=%d fileid=%02x:%02x:%llu name=%02x:%02x:%llu/%s",
-                       __entry->error,
+                       "error=%ld (%s) fileid=%02x:%02x:%llu name=%02x:%02x:%llu/%s",
+                       -__entry->error, nfs_show_status(__entry->error),
                        MAJOR(__entry->dev), MINOR(__entry->dev),
                        __entry->fileid,
                        MAJOR(__entry->dev), MINOR(__entry->dev),
@@ -642,7 +740,7 @@ DECLARE_EVENT_CLASS(nfs_rename_event_done,
 
                TP_STRUCT__entry(
                        __field(dev_t, dev)
-                       __field(int, error)
+                       __field(unsigned long, error)
                        __field(u64, old_dir)
                        __string(old_name, old_dentry->d_name.name)
                        __field(u64, new_dir)
@@ -651,17 +749,17 @@ DECLARE_EVENT_CLASS(nfs_rename_event_done,
 
                TP_fast_assign(
                        __entry->dev = old_dir->i_sb->s_dev;
+                       __entry->error = -error;
                        __entry->old_dir = NFS_FILEID(old_dir);
                        __entry->new_dir = NFS_FILEID(new_dir);
-                       __entry->error = error;
                        __assign_str(old_name, old_dentry->d_name.name);
                        __assign_str(new_name, new_dentry->d_name.name);
                ),
 
                TP_printk(
-                       "error=%d old_name=%02x:%02x:%llu/%s "
+                       "error=%ld (%s) old_name=%02x:%02x:%llu/%s "
                        "new_name=%02x:%02x:%llu/%s",
-                       __entry->error,
+                       -__entry->error, nfs_show_status(__entry->error),
                        MAJOR(__entry->dev), MINOR(__entry->dev),
                        (unsigned long long)__entry->old_dir,
                        __get_str(old_name),
@@ -697,7 +795,7 @@ TRACE_EVENT(nfs_sillyrename_unlink,
 
                TP_STRUCT__entry(
                        __field(dev_t, dev)
-                       __field(int, error)
+                       __field(unsigned long, error)
                        __field(u64, dir)
                        __dynamic_array(char, name, data->args.name.len + 1)
                ),
@@ -707,15 +805,15 @@ TRACE_EVENT(nfs_sillyrename_unlink,
                        size_t len = data->args.name.len;
                        __entry->dev = dir->i_sb->s_dev;
                        __entry->dir = NFS_FILEID(dir);
-                       __entry->error = error;
+                       __entry->error = -error;
                        memcpy(__get_str(name),
                                data->args.name.name, len);
                        __get_str(name)[len] = 0;
                ),
 
                TP_printk(
-                       "error=%d name=%02x:%02x:%llu/%s",
-                       __entry->error,
+                       "error=%ld (%s) name=%02x:%02x:%llu/%s",
+                       -__entry->error, nfs_show_status(__entry->error),
                        MAJOR(__entry->dev), MINOR(__entry->dev),
                        (unsigned long long)__entry->dir,
                        __get_str(name)
@@ -974,6 +1072,8 @@ TRACE_DEFINE_ENUM(NFSERR_PERM);
 TRACE_DEFINE_ENUM(NFSERR_NOENT);
 TRACE_DEFINE_ENUM(NFSERR_IO);
 TRACE_DEFINE_ENUM(NFSERR_NXIO);
+TRACE_DEFINE_ENUM(ECHILD);
+TRACE_DEFINE_ENUM(NFSERR_EAGAIN);
 TRACE_DEFINE_ENUM(NFSERR_ACCES);
 TRACE_DEFINE_ENUM(NFSERR_EXIST);
 TRACE_DEFINE_ENUM(NFSERR_XDEV);
@@ -985,6 +1085,7 @@ TRACE_DEFINE_ENUM(NFSERR_FBIG);
 TRACE_DEFINE_ENUM(NFSERR_NOSPC);
 TRACE_DEFINE_ENUM(NFSERR_ROFS);
 TRACE_DEFINE_ENUM(NFSERR_MLINK);
+TRACE_DEFINE_ENUM(NFSERR_OPNOTSUPP);
 TRACE_DEFINE_ENUM(NFSERR_NAMETOOLONG);
 TRACE_DEFINE_ENUM(NFSERR_NOTEMPTY);
 TRACE_DEFINE_ENUM(NFSERR_DQUOT);
@@ -1007,6 +1108,8 @@ TRACE_DEFINE_ENUM(NFSERR_JUKEBOX);
                        { NFSERR_NOENT, "NOENT" }, \
                        { NFSERR_IO, "IO" }, \
                        { NFSERR_NXIO, "NXIO" }, \
+                       { ECHILD, "CHILD" }, \
+                       { NFSERR_EAGAIN, "AGAIN" }, \
                        { NFSERR_ACCES, "ACCES" }, \
                        { NFSERR_EXIST, "EXIST" }, \
                        { NFSERR_XDEV, "XDEV" }, \
@@ -1018,6 +1121,7 @@ TRACE_DEFINE_ENUM(NFSERR_JUKEBOX);
                        { NFSERR_NOSPC, "NOSPC" }, \
                        { NFSERR_ROFS, "ROFS" }, \
                        { NFSERR_MLINK, "MLINK" }, \
+                       { NFSERR_OPNOTSUPP, "OPNOTSUPP" }, \
                        { NFSERR_NAMETOOLONG, "NAMETOOLONG" }, \
                        { NFSERR_NOTEMPTY, "NOTEMPTY" }, \
                        { NFSERR_DQUOT, "DQUOT" }, \
@@ -1035,22 +1139,33 @@ TRACE_DEFINE_ENUM(NFSERR_JUKEBOX);
 
 TRACE_EVENT(nfs_xdr_status,
                TP_PROTO(
+                       const struct xdr_stream *xdr,
                        int error
                ),
 
-               TP_ARGS(error),
+               TP_ARGS(xdr, error),
 
                TP_STRUCT__entry(
-                       __field(int, error)
+                       __field(unsigned int, task_id)
+                       __field(unsigned int, client_id)
+                       __field(u32, xid)
+                       __field(unsigned long, error)
                ),
 
                TP_fast_assign(
+                       const struct rpc_rqst *rqstp = xdr->rqst;
+                       const struct rpc_task *task = rqstp->rq_task;
+
+                       __entry->task_id = task->tk_pid;
+                       __entry->client_id = task->tk_client->cl_clid;
+                       __entry->xid = be32_to_cpu(rqstp->rq_xid);
                        __entry->error = error;
                ),
 
                TP_printk(
-                       "error=%d (%s)",
-                       __entry->error, nfs_show_status(__entry->error)
+                       "task:%u@%d xid=0x%08x error=%ld (%s)",
+                       __entry->task_id, __entry->client_id, __entry->xid,
+                       -__entry->error, nfs_show_status(__entry->error)
                )
 );
 
index 6ef5278..ed4e1b0 100644 (file)
@@ -77,7 +77,7 @@ void nfs_set_pgio_error(struct nfs_pgio_header *hdr, int error, loff_t pos)
 static inline struct nfs_page *
 nfs_page_alloc(void)
 {
-       struct nfs_page *p = kmem_cache_zalloc(nfs_page_cachep, GFP_NOIO);
+       struct nfs_page *p = kmem_cache_zalloc(nfs_page_cachep, GFP_KERNEL);
        if (p)
                INIT_LIST_HEAD(&p->wb_list);
        return p;
@@ -775,8 +775,6 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc,
        if (pagecount <= ARRAY_SIZE(pg_array->page_array))
                pg_array->pagevec = pg_array->page_array;
        else {
-               if (hdr->rw_mode == FMODE_WRITE)
-                       gfp_flags = GFP_NOIO;
                pg_array->pagevec = kcalloc(pagecount, sizeof(struct page *), gfp_flags);
                if (!pg_array->pagevec) {
                        pg_array->npages = 0;
@@ -851,7 +849,7 @@ nfs_pageio_alloc_mirrors(struct nfs_pageio_descriptor *desc,
        desc->pg_mirrors_dynamic = NULL;
        if (mirror_count == 1)
                return desc->pg_mirrors_static;
-       ret = kmalloc_array(mirror_count, sizeof(*ret), GFP_NOFS);
+       ret = kmalloc_array(mirror_count, sizeof(*ret), GFP_KERNEL);
        if (ret != NULL) {
                for (i = 0; i < mirror_count; i++)
                        nfs_pageio_mirror_init(&ret[i], desc->pg_bsize);
index 83722e9..75bd5b5 100644 (file)
@@ -1890,7 +1890,7 @@ lookup_again:
                spin_unlock(&ino->i_lock);
                lseg = ERR_PTR(wait_var_event_killable(&lo->plh_outstanding,
                                        !atomic_read(&lo->plh_outstanding)));
-               if (IS_ERR(lseg) || !list_empty(&lo->plh_segs))
+               if (IS_ERR(lseg))
                        goto out_put_layout_hdr;
                pnfs_put_layout_hdr(lo);
                goto lookup_again;
@@ -1915,6 +1915,7 @@ lookup_again:
         * stateid.
         */
        if (test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags)) {
+               int status;
 
                /*
                 * The first layoutget for the file. Need to serialize per
@@ -1934,13 +1935,20 @@ lookup_again:
                }
 
                first = true;
-               if (nfs4_select_rw_stateid(ctx->state,
+               status = nfs4_select_rw_stateid(ctx->state,
                                        iomode == IOMODE_RW ? FMODE_WRITE : FMODE_READ,
-                                       NULL, &stateid, NULL) != 0) {
+                                       NULL, &stateid, NULL);
+               if (status != 0) {
                        trace_pnfs_update_layout(ino, pos, count,
                                        iomode, lo, lseg,
                                        PNFS_UPDATE_LAYOUT_INVALID_OPEN);
-                       goto out_unlock;
+                       if (status != -EAGAIN)
+                               goto out_unlock;
+                       spin_unlock(&ino->i_lock);
+                       nfs4_schedule_stateid_recovery(server, ctx->state);
+                       pnfs_clear_first_layoutget(lo);
+                       pnfs_put_layout_hdr(lo);
+                       goto lookup_again;
                }
        } else {
                nfs4_stateid_copy(&stateid, &lo->plh_stateid);
@@ -2029,6 +2037,8 @@ lookup_again:
 out_put_layout_hdr:
        if (first)
                pnfs_clear_first_layoutget(lo);
+       trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
+                                PNFS_UPDATE_LAYOUT_EXIT);
        pnfs_put_layout_hdr(lo);
 out:
        dprintk("%s: inode %s/%llu pNFS layout segment %s for "
@@ -2468,7 +2478,7 @@ pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
                                                   wb_size,
                                                   IOMODE_RW,
                                                   false,
-                                                  GFP_NOFS);
+                                                  GFP_KERNEL);
                if (IS_ERR(pgio->pg_lseg)) {
                        pgio->pg_error = PTR_ERR(pgio->pg_lseg);
                        pgio->pg_lseg = NULL;
index f88ddac..628631e 100644 (file)
@@ -77,6 +77,8 @@
 #define NFS_DEFAULT_VERSION 2
 #endif
 
+#define NFS_MAX_CONNECTIONS 16
+
 enum {
        /* Mount options that take no arguments */
        Opt_soft, Opt_softerr, Opt_hard,
@@ -108,6 +110,7 @@ enum {
        Opt_nfsvers,
        Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost,
        Opt_addr, Opt_mountaddr, Opt_clientaddr,
+       Opt_nconnect,
        Opt_lookupcache,
        Opt_fscache_uniq,
        Opt_local_lock,
@@ -181,6 +184,8 @@ static const match_table_t nfs_mount_option_tokens = {
        { Opt_mounthost, "mounthost=%s" },
        { Opt_mountaddr, "mountaddr=%s" },
 
+       { Opt_nconnect, "nconnect=%s" },
+
        { Opt_lookupcache, "lookupcache=%s" },
        { Opt_fscache_uniq, "fsc=%s" },
        { Opt_local_lock, "local_lock=%s" },
@@ -452,10 +457,8 @@ int nfs_statfs(struct dentry *dentry, struct kstatfs *buf)
                struct dentry *pd_dentry;
 
                pd_dentry = dget_parent(dentry);
-               if (pd_dentry != NULL) {
-                       nfs_zap_caches(d_inode(pd_dentry));
-                       dput(pd_dentry);
-               }
+               nfs_zap_caches(d_inode(pd_dentry));
+               dput(pd_dentry);
        }
        nfs_free_fattr(res.fattr);
        if (error < 0)
@@ -582,7 +585,7 @@ static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss,
        }
        default:
                if (showdefaults)
-                       seq_printf(m, ",mountaddr=unspecified");
+                       seq_puts(m, ",mountaddr=unspecified");
        }
 
        if (nfss->mountd_version || showdefaults)
@@ -673,6 +676,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
        seq_printf(m, ",proto=%s",
                   rpc_peeraddr2str(nfss->client, RPC_DISPLAY_NETID));
        rcu_read_unlock();
+       if (clp->cl_nconnect > 0)
+               seq_printf(m, ",nconnect=%u", clp->cl_nconnect);
        if (version == 4) {
                if (nfss->port != NFS_PORT)
                        seq_printf(m, ",port=%u", nfss->port);
@@ -690,29 +695,29 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
                nfs_show_nfsv4_options(m, nfss, showdefaults);
 
        if (nfss->options & NFS_OPTION_FSCACHE)
-               seq_printf(m, ",fsc");
+               seq_puts(m, ",fsc");
 
        if (nfss->options & NFS_OPTION_MIGRATION)
-               seq_printf(m, ",migration");
+               seq_puts(m, ",migration");
 
        if (nfss->flags & NFS_MOUNT_LOOKUP_CACHE_NONEG) {
                if (nfss->flags & NFS_MOUNT_LOOKUP_CACHE_NONE)
-                       seq_printf(m, ",lookupcache=none");
+                       seq_puts(m, ",lookupcache=none");
                else
-                       seq_printf(m, ",lookupcache=pos");
+                       seq_puts(m, ",lookupcache=pos");
        }
 
        local_flock = nfss->flags & NFS_MOUNT_LOCAL_FLOCK;
        local_fcntl = nfss->flags & NFS_MOUNT_LOCAL_FCNTL;
 
        if (!local_flock && !local_fcntl)
-               seq_printf(m, ",local_lock=none");
+               seq_puts(m, ",local_lock=none");
        else if (local_flock && local_fcntl)
-               seq_printf(m, ",local_lock=all");
+               seq_puts(m, ",local_lock=all");
        else if (local_flock)
-               seq_printf(m, ",local_lock=flock");
+               seq_puts(m, ",local_lock=flock");
        else
-               seq_printf(m, ",local_lock=posix");
+               seq_puts(m, ",local_lock=posix");
 }
 
 /*
@@ -735,11 +740,21 @@ int nfs_show_options(struct seq_file *m, struct dentry *root)
 EXPORT_SYMBOL_GPL(nfs_show_options);
 
 #if IS_ENABLED(CONFIG_NFS_V4)
+static void show_lease(struct seq_file *m, struct nfs_server *server)
+{
+       struct nfs_client *clp = server->nfs_client;
+       unsigned long expire;
+
+       seq_printf(m, ",lease_time=%ld", clp->cl_lease_time / HZ);
+       expire = clp->cl_last_renewal + clp->cl_lease_time;
+       seq_printf(m, ",lease_expired=%ld",
+                  time_after(expire, jiffies) ?  0 : (jiffies - expire) / HZ);
+}
 #ifdef CONFIG_NFS_V4_1
 static void show_sessions(struct seq_file *m, struct nfs_server *server)
 {
        if (nfs4_has_session(server->nfs_client))
-               seq_printf(m, ",sessions");
+               seq_puts(m, ",sessions");
 }
 #else
 static void show_sessions(struct seq_file *m, struct nfs_server *server) {}
@@ -816,7 +831,7 @@ int nfs_show_stats(struct seq_file *m, struct dentry *root)
        /*
         * Display all mount option settings
         */
-       seq_printf(m, "\n\topts:\t");
+       seq_puts(m, "\n\topts:\t");
        seq_puts(m, sb_rdonly(root->d_sb) ? "ro" : "rw");
        seq_puts(m, root->d_sb->s_flags & SB_SYNCHRONOUS ? ",sync" : "");
        seq_puts(m, root->d_sb->s_flags & SB_NOATIME ? ",noatime" : "");
@@ -827,7 +842,7 @@ int nfs_show_stats(struct seq_file *m, struct dentry *root)
 
        show_implementation_id(m, nfss);
 
-       seq_printf(m, "\n\tcaps:\t");
+       seq_puts(m, "\n\tcaps:\t");
        seq_printf(m, "caps=0x%x", nfss->caps);
        seq_printf(m, ",wtmult=%u", nfss->wtmult);
        seq_printf(m, ",dtsize=%u", nfss->dtsize);
@@ -836,13 +851,14 @@ int nfs_show_stats(struct seq_file *m, struct dentry *root)
 
 #if IS_ENABLED(CONFIG_NFS_V4)
        if (nfss->nfs_client->rpc_ops->version == 4) {
-               seq_printf(m, "\n\tnfsv4:\t");
+               seq_puts(m, "\n\tnfsv4:\t");
                seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]);
                seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]);
                seq_printf(m, ",bm2=0x%x", nfss->attr_bitmask[2]);
                seq_printf(m, ",acl=0x%x", nfss->acl_bitmask);
                show_sessions(m, nfss);
                show_pnfs(m, nfss);
+               show_lease(m, nfss);
        }
 #endif
 
@@ -874,20 +890,20 @@ int nfs_show_stats(struct seq_file *m, struct dentry *root)
                preempt_enable();
        }
 
-       seq_printf(m, "\n\tevents:\t");
+       seq_puts(m, "\n\tevents:\t");
        for (i = 0; i < __NFSIOS_COUNTSMAX; i++)
                seq_printf(m, "%lu ", totals.events[i]);
-       seq_printf(m, "\n\tbytes:\t");
+       seq_puts(m, "\n\tbytes:\t");
        for (i = 0; i < __NFSIOS_BYTESMAX; i++)
                seq_printf(m, "%Lu ", totals.bytes[i]);
 #ifdef CONFIG_NFS_FSCACHE
        if (nfss->options & NFS_OPTION_FSCACHE) {
-               seq_printf(m, "\n\tfsc:\t");
+               seq_puts(m, "\n\tfsc:\t");
                for (i = 0; i < __NFSIOS_FSCACHEMAX; i++)
                        seq_printf(m, "%Lu ", totals.fscache[i]);
        }
 #endif
-       seq_printf(m, "\n");
+       seq_putc(m, '\n');
 
        rpc_clnt_show_stats(m, nfss->client);
 
@@ -1549,6 +1565,11 @@ static int nfs_parse_mount_options(char *raw,
                        if (mnt->mount_server.addrlen == 0)
                                goto out_invalid_address;
                        break;
+               case Opt_nconnect:
+                       if (nfs_get_option_ul_bound(args, &option, 1, NFS_MAX_CONNECTIONS))
+                               goto out_invalid_value;
+                       mnt->nfs_server.nconnect = option;
+                       break;
                case Opt_lookupcache:
                        string = match_strdup(args);
                        if (string == NULL)
diff --git a/fs/nfs/sysfs.c b/fs/nfs/sysfs.c
new file mode 100644 (file)
index 0000000..4f3390b
--- /dev/null
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Hammerspace Inc
+ */
+
+#include <linux/module.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/string.h>
+#include <linux/nfs_fs.h>
+#include <linux/rcupdate.h>
+
+#include "nfs4_fs.h"
+#include "netns.h"
+#include "sysfs.h"
+
+struct kobject *nfs_client_kobj;
+static struct kset *nfs_client_kset;
+
+static void nfs_netns_object_release(struct kobject *kobj)
+{
+       kfree(kobj);
+}
+
+static const struct kobj_ns_type_operations *nfs_netns_object_child_ns_type(
+               struct kobject *kobj)
+{
+       return &net_ns_type_operations;
+}
+
+static struct kobj_type nfs_netns_object_type = {
+       .release = nfs_netns_object_release,
+       .sysfs_ops = &kobj_sysfs_ops,
+       .child_ns_type = nfs_netns_object_child_ns_type,
+};
+
+static struct kobject *nfs_netns_object_alloc(const char *name,
+               struct kset *kset, struct kobject *parent)
+{
+       struct kobject *kobj;
+
+       kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
+       if (kobj) {
+               kobj->kset = kset;
+               if (kobject_init_and_add(kobj, &nfs_netns_object_type,
+                                       parent, "%s", name) == 0)
+                       return kobj;
+               kobject_put(kobj);
+       }
+       return NULL;
+}
+
+int nfs_sysfs_init(void)
+{
+       nfs_client_kset = kset_create_and_add("nfs", NULL, fs_kobj);
+       if (!nfs_client_kset)
+               return -ENOMEM;
+       nfs_client_kobj = nfs_netns_object_alloc("net", nfs_client_kset, NULL);
+       if  (!nfs_client_kobj) {
+               kset_unregister(nfs_client_kset);
+               nfs_client_kset = NULL;
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+void nfs_sysfs_exit(void)
+{
+       kobject_put(nfs_client_kobj);
+       kset_unregister(nfs_client_kset);
+}
+
+static ssize_t nfs_netns_identifier_show(struct kobject *kobj,
+               struct kobj_attribute *attr, char *buf)
+{
+       struct nfs_netns_client *c = container_of(kobj,
+                       struct nfs_netns_client,
+                       kobject);
+       return scnprintf(buf, PAGE_SIZE, "%s\n", c->identifier);
+}
+
+/* Strip trailing '\n' */
+static size_t nfs_string_strip(const char *c, size_t len)
+{
+       while (len > 0 && c[len-1] == '\n')
+               --len;
+       return len;
+}
+
+static ssize_t nfs_netns_identifier_store(struct kobject *kobj,
+               struct kobj_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct nfs_netns_client *c = container_of(kobj,
+                       struct nfs_netns_client,
+                       kobject);
+       const char *old;
+       char *p;
+       size_t len;
+
+       len = nfs_string_strip(buf, min_t(size_t, count, CONTAINER_ID_MAXLEN));
+       if (!len)
+               return 0;
+       p = kmemdup_nul(buf, len, GFP_KERNEL);
+       if (!p)
+               return -ENOMEM;
+       old = xchg(&c->identifier, p);
+       if (old) {
+               synchronize_rcu();
+               kfree(old);
+       }
+       return count;
+}
+
+static void nfs_netns_client_release(struct kobject *kobj)
+{
+       struct nfs_netns_client *c = container_of(kobj,
+                       struct nfs_netns_client,
+                       kobject);
+
+       if (c->identifier)
+               kfree(c->identifier);
+       kfree(c);
+}
+
+static const void *nfs_netns_client_namespace(struct kobject *kobj)
+{
+       return container_of(kobj, struct nfs_netns_client, kobject)->net;
+}
+
+static struct kobj_attribute nfs_netns_client_id = __ATTR(identifier,
+               0644, nfs_netns_identifier_show, nfs_netns_identifier_store);
+
+static struct attribute *nfs_netns_client_attrs[] = {
+       &nfs_netns_client_id.attr,
+       NULL,
+};
+
+static struct kobj_type nfs_netns_client_type = {
+       .release = nfs_netns_client_release,
+       .default_attrs = nfs_netns_client_attrs,
+       .sysfs_ops = &kobj_sysfs_ops,
+       .namespace = nfs_netns_client_namespace,
+};
+
+static struct nfs_netns_client *nfs_netns_client_alloc(struct kobject *parent,
+               struct net *net)
+{
+       struct nfs_netns_client *p;
+
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       if (p) {
+               p->net = net;
+               p->kobject.kset = nfs_client_kset;
+               if (kobject_init_and_add(&p->kobject, &nfs_netns_client_type,
+                                       parent, "nfs_client") == 0)
+                       return p;
+               kobject_put(&p->kobject);
+       }
+       return NULL;
+}
+
+void nfs_netns_sysfs_setup(struct nfs_net *netns, struct net *net)
+{
+       struct nfs_netns_client *clp;
+
+       clp = nfs_netns_client_alloc(nfs_client_kobj, net);
+       if (clp) {
+               netns->nfs_client = clp;
+               kobject_uevent(&clp->kobject, KOBJ_ADD);
+       }
+}
+
+void nfs_netns_sysfs_destroy(struct nfs_net *netns)
+{
+       struct nfs_netns_client *clp = netns->nfs_client;
+
+       if (clp) {
+               kobject_uevent(&clp->kobject, KOBJ_REMOVE);
+               kobject_del(&clp->kobject);
+               kobject_put(&clp->kobject);
+               netns->nfs_client = NULL;
+       }
+}
diff --git a/fs/nfs/sysfs.h b/fs/nfs/sysfs.h
new file mode 100644 (file)
index 0000000..f1b2741
--- /dev/null
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Hammerspace Inc
+ */
+
+#ifndef __NFS_SYSFS_H
+#define __NFS_SYSFS_H
+
+#define CONTAINER_ID_MAXLEN (64)
+
+struct nfs_netns_client {
+       struct kobject kobject;
+       struct net *net;
+       const char *identifier;
+};
+
+extern struct kobject *nfs_client_kobj;
+
+extern int nfs_sysfs_init(void);
+extern void nfs_sysfs_exit(void);
+
+void nfs_netns_sysfs_setup(struct nfs_net *netns, struct net *net);
+void nfs_netns_sysfs_destroy(struct nfs_net *netns);
+
+#endif
index 059a7c3..92d9cad 100644 (file)
@@ -103,7 +103,7 @@ EXPORT_SYMBOL_GPL(nfs_commit_free);
 
 static struct nfs_pgio_header *nfs_writehdr_alloc(void)
 {
-       struct nfs_pgio_header *p = mempool_alloc(nfs_wdata_mempool, GFP_NOIO);
+       struct nfs_pgio_header *p = mempool_alloc(nfs_wdata_mempool, GFP_KERNEL);
 
        memset(p, 0, sizeof(*p));
        p->rw_mode = FMODE_WRITE;
@@ -721,12 +721,11 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
        struct inode *inode = mapping->host;
        struct nfs_pageio_descriptor pgio;
        struct nfs_io_completion *ioc;
-       unsigned int pflags = memalloc_nofs_save();
        int err;
 
        nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES);
 
-       ioc = nfs_io_completion_alloc(GFP_NOFS);
+       ioc = nfs_io_completion_alloc(GFP_KERNEL);
        if (ioc)
                nfs_io_completion_init(ioc, nfs_io_completion_commit, inode);
 
@@ -737,8 +736,6 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
        nfs_pageio_complete(&pgio);
        nfs_io_completion_put(ioc);
 
-       memalloc_nofs_restore(pflags);
-
        if (err < 0)
                goto out_err;
        err = pgio.pg_error;
index 0a9a49d..13c5487 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/slab.h>
 #include <linux/namei.h>
 #include <linux/ctype.h>
+#include <linux/fs_context.h>
 
 #include <linux/sunrpc/svcsock.h>
 #include <linux/lockd/lockd.h>
@@ -1337,7 +1338,7 @@ void nfsd_client_rmdir(struct dentry *dentry)
        inode_unlock(dir);
 }
 
-static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
+static int nfsd_fill_super(struct super_block *sb, struct fs_context *fc)
 {
        struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
                                                        nfsd_net_id);
@@ -1372,7 +1373,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
 #endif
                /* last one */ {""}
        };
-       get_net(sb->s_fs_info);
+
        ret = simple_fill_super(sb, 0x6e667364, nfsd_files);
        if (ret)
                return ret;
@@ -1381,14 +1382,31 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
                return PTR_ERR(dentry);
        nn->nfsd_client_dir = dentry;
        return 0;
+}
 
+static int nfsd_fs_get_tree(struct fs_context *fc)
+{
+       fc->s_fs_info = get_net(fc->net_ns);
+       return vfs_get_super(fc, vfs_get_keyed_super, nfsd_fill_super);
 }
 
-static struct dentry *nfsd_mount(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *data)
+static void nfsd_fs_free_fc(struct fs_context *fc)
 {
-       struct net *net = current->nsproxy->net_ns;
-       return mount_ns(fs_type, flags, data, net, net->user_ns, nfsd_fill_super);
+       if (fc->s_fs_info)
+               put_net(fc->s_fs_info);
+}
+
+static const struct fs_context_operations nfsd_fs_context_ops = {
+       .free           = nfsd_fs_free_fc,
+       .get_tree       = nfsd_fs_get_tree,
+};
+
+static int nfsd_init_fs_context(struct fs_context *fc)
+{
+       put_user_ns(fc->user_ns);
+       fc->user_ns = get_user_ns(fc->net_ns->user_ns);
+       fc->ops = &nfsd_fs_context_ops;
+       return 0;
 }
 
 static void nfsd_umount(struct super_block *sb)
@@ -1402,7 +1420,7 @@ static void nfsd_umount(struct super_block *sb)
 static struct file_system_type nfsd_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "nfsd",
-       .mount          = nfsd_mount,
+       .init_fs_context = nfsd_init_fs_context,
        .kill_sb        = nfsd_umount,
 };
 MODULE_ALIAS_FS("nfsd");
index cce8de3..0b81517 100644 (file)
@@ -45,8 +45,6 @@ struct kmem_cache *inotify_inode_mark_cachep __read_mostly;
 
 #include <linux/sysctl.h>
 
-static int zero;
-
 struct ctl_table inotify_table[] = {
        {
                .procname       = "max_user_instances",
@@ -54,7 +52,7 @@ struct ctl_table inotify_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
        {
                .procname       = "max_user_watches",
@@ -62,7 +60,7 @@ struct ctl_table inotify_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
        {
                .procname       = "max_queued_events",
@@ -70,7 +68,7 @@ struct ctl_table inotify_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero
+               .extra1         = SYSCTL_ZERO
        },
        { }
 };
index e3bf08c..a043164 100644 (file)
--- a/fs/nsfs.c
+++ b/fs/nsfs.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/mount.h>
+#include <linux/pseudo_fs.h>
 #include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/proc_ns.h>
@@ -258,15 +259,20 @@ static const struct super_operations nsfs_ops = {
        .evict_inode = nsfs_evict,
        .show_path = nsfs_show_path,
 };
-static struct dentry *nsfs_mount(struct file_system_type *fs_type,
-                       int flags, const char *dev_name, void *data)
+
+static int nsfs_init_fs_context(struct fs_context *fc)
 {
-       return mount_pseudo(fs_type, "nsfs:", &nsfs_ops,
-                       &ns_dentry_operations, NSFS_MAGIC);
+       struct pseudo_fs_context *ctx = init_pseudo(fc, NSFS_MAGIC);
+       if (!ctx)
+               return -ENOMEM;
+       ctx->ops = &nsfs_ops;
+       ctx->dops = &ns_dentry_operations;
+       return 0;
 }
+
 static struct file_system_type nsfs = {
        .name = "nsfs",
-       .mount = nsfs_mount,
+       .init_fs_context = nsfs_init_fs_context,
        .kill_sb = kill_anon_super,
 };
 
index b5b8046..a59abe3 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -374,6 +374,25 @@ long do_faccessat(int dfd, const char __user *filename, int mode)
                                override_cred->cap_permitted;
        }
 
+       /*
+        * The new set of credentials can *only* be used in
+        * task-synchronous circumstances, and does not need
+        * RCU freeing, unless somebody then takes a separate
+        * reference to it.
+        *
+        * NOTE! This is _only_ true because this credential
+        * is used purely for override_creds() that installs
+        * it as the subjective cred. Other threads will be
+        * accessing ->real_cred, not the subjective cred.
+        *
+        * If somebody _does_ make a copy of this (using the
+        * 'get_current_cred()' function), that will clear the
+        * non_rcu field, because now that other user may be
+        * expecting RCU freeing. But normal thread-synchronous
+        * cred accesses will keep things non-RCY.
+        */
+       override_cred->non_rcu = 1;
+
        old_cred = override_creds(override_cred);
 retry:
        res = user_path_at(dfd, filename, lookup_flags, &path);
index e6cb768..40c8c2e 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/fs.h>
+#include <linux/fs_context.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/seq_file.h>
@@ -375,7 +376,7 @@ static const struct super_operations openprom_sops = {
        .remount_fs     = openprom_remount,
 };
 
-static int openprom_fill_super(struct super_block *s, void *data, int silent)
+static int openprom_fill_super(struct super_block *s, struct fs_context *fc)
 {
        struct inode *root_inode;
        struct op_inode_info *oi;
@@ -409,16 +410,25 @@ out_no_root:
        return ret;
 }
 
-static struct dentry *openprom_mount(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *data)
+static int openpromfs_get_tree(struct fs_context *fc)
 {
-       return mount_single(fs_type, flags, data, openprom_fill_super);
+       return get_tree_single(fc, openprom_fill_super);
+}
+
+static const struct fs_context_operations openpromfs_context_ops = {
+       .get_tree       = openpromfs_get_tree,
+};
+
+static int openpromfs_init_fs_context(struct fs_context *fc)
+{
+       fc->ops = &openpromfs_context_ops;
+       return 0;
 }
 
 static struct file_system_type openprom_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "openpromfs",
-       .mount          = openprom_mount,
+       .init_fs_context = openpromfs_init_fs_context,
        .kill_sb        = kill_anon_super,
 };
 MODULE_ALIAS_FS("openpromfs");
index 679a3c8..960f9a3 100644 (file)
@@ -52,7 +52,7 @@ ssize_t wait_for_direct_io(enum ORANGEFS_io_type type, struct inode *inode,
        struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
        struct orangefs_khandle *handle = &orangefs_inode->refn.khandle;
        struct orangefs_kernel_op_s *new_op = NULL;
-       int buffer_index = -1;
+       int buffer_index;
        ssize_t ret;
        size_t copy_amount;
 
@@ -134,7 +134,6 @@ populate_shared_memory:
         */
        if (ret == -EAGAIN && op_state_purged(new_op)) {
                orangefs_bufmap_put(buffer_index);
-               buffer_index = -1;
                if (type == ORANGEFS_IO_WRITE)
                        iov_iter_revert(iter, total_size);
                gossip_debug(GOSSIP_FILE_DEBUG,
@@ -262,7 +261,6 @@ out:
                                "%s(%pU): PUT buffer_index %d\n",
                                __func__, handle, buffer_index);
                }
-               buffer_index = -1;
        }
        op_release(new_op);
        return ret;
index 4106590..8a2ab2f 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -14,6 +14,7 @@
 #include <linux/fs.h>
 #include <linux/log2.h>
 #include <linux/mount.h>
+#include <linux/pseudo_fs.h>
 #include <linux/magic.h>
 #include <linux/pipe_fs_i.h>
 #include <linux/uio.h>
@@ -1182,16 +1183,20 @@ static const struct super_operations pipefs_ops = {
  * any operations on the root directory. However, we need a non-trivial
  * d_name - pipe: will go nicely and kill the special-casing in procfs.
  */
-static struct dentry *pipefs_mount(struct file_system_type *fs_type,
-                        int flags, const char *dev_name, void *data)
+
+static int pipefs_init_fs_context(struct fs_context *fc)
 {
-       return mount_pseudo(fs_type, "pipe:", &pipefs_ops,
-                       &pipefs_dentry_operations, PIPEFS_MAGIC);
+       struct pseudo_fs_context *ctx = init_pseudo(fc, PIPEFS_MAGIC);
+       if (!ctx)
+               return -ENOMEM;
+       ctx->ops = &pipefs_ops;
+       ctx->dops = &pipefs_dentry_operations;
+       return 0;
 }
 
 static struct file_system_type pipe_fs_type = {
        .name           = "pipefs",
-       .mount          = pipefs_mount,
+       .init_fs_context = pipefs_init_fs_context,
        .kill_sb        = kill_anon_super,
 };
 
index 4c3dcb7..cb5629b 100644 (file)
@@ -58,7 +58,8 @@ config PROC_VMCORE_DEVICE_DUMP
          snapshot.
 
          If you say Y here, the collected device dumps will be added
-         as ELF notes to /proc/vmcore.
+         as ELF notes to /proc/vmcore. You can still disable device
+         dump using the kernel command line option 'novmcoredd'.
 
 config PROC_SYSCTL
        bool "Sysctl support (/proc/sys)" if EXPERT
@@ -72,7 +73,7 @@ config PROC_SYSCTL
          interface is through /proc/sys.  If you say Y here a tree of
          modifiable sysctl entries will be generated beneath the
           /proc/sys directory. They are explained in the files
-         in <file:Documentation/sysctl/>.  Note that enabling this
+         in <file:Documentation/admin-guide/sysctl/>.  Note that enabling this
          option will enlarge the kernel by at least 8 KB.
 
          As it is generally a good thing, you should say Y here unless
index 77eb628..ebea950 100644 (file)
@@ -209,12 +209,53 @@ static int proc_root_link(struct dentry *dentry, struct path *path)
        return result;
 }
 
+/*
+ * If the user used setproctitle(), we just get the string from
+ * user space at arg_start, and limit it to a maximum of one page.
+ */
+static ssize_t get_mm_proctitle(struct mm_struct *mm, char __user *buf,
+                               size_t count, unsigned long pos,
+                               unsigned long arg_start)
+{
+       char *page;
+       int ret, got;
+
+       if (pos >= PAGE_SIZE)
+               return 0;
+
+       page = (char *)__get_free_page(GFP_KERNEL);
+       if (!page)
+               return -ENOMEM;
+
+       ret = 0;
+       got = access_remote_vm(mm, arg_start, page, PAGE_SIZE, FOLL_ANON);
+       if (got > 0) {
+               int len = strnlen(page, got);
+
+               /* Include the NUL character if it was found */
+               if (len < got)
+                       len++;
+
+               if (len > pos) {
+                       len -= pos;
+                       if (len > count)
+                               len = count;
+                       len -= copy_to_user(buf, page+pos, len);
+                       if (!len)
+                               len = -EFAULT;
+                       ret = len;
+               }
+       }
+       free_page((unsigned long)page);
+       return ret;
+}
+
 static ssize_t get_mm_cmdline(struct mm_struct *mm, char __user *buf,
                              size_t count, loff_t *ppos)
 {
        unsigned long arg_start, arg_end, env_start, env_end;
        unsigned long pos, len;
-       char *page;
+       char *page, c;
 
        /* Check if process spawned far enough to have cmdline. */
        if (!mm->env_end)
@@ -231,28 +272,42 @@ static ssize_t get_mm_cmdline(struct mm_struct *mm, char __user *buf,
                return 0;
 
        /*
-        * We have traditionally allowed the user to re-write
-        * the argument strings and overflow the end result
-        * into the environment section. But only do that if
-        * the environment area is contiguous to the arguments.
+        * We allow setproctitle() to overwrite the argument
+        * strings, and overflow past the original end. But
+        * only when it overflows into the environment area.
         */
-       if (env_start != arg_end || env_start >= env_end)
+       if (env_start != arg_end || env_end < env_start)
                env_start = env_end = arg_end;
-
-       /* .. and limit it to a maximum of one page of slop */
-       if (env_end >= arg_end + PAGE_SIZE)
-               env_end = arg_end + PAGE_SIZE - 1;
+       len = env_end - arg_start;
 
        /* We're not going to care if "*ppos" has high bits set */
-       pos = arg_start + *ppos;
-
-       /* .. but we do check the result is in the proper range */
-       if (pos < arg_start || pos >= env_end)
+       pos = *ppos;
+       if (pos >= len)
                return 0;
+       if (count > len - pos)
+               count = len - pos;
+       if (!count)
+               return 0;
+
+       /*
+        * Magical special case: if the argv[] end byte is not
+        * zero, the user has overwritten it with setproctitle(3).
+        *
+        * Possible future enhancement: do this only once when
+        * pos is 0, and set a flag in the 'struct file'.
+        */
+       if (access_remote_vm(mm, arg_end-1, &c, 1, FOLL_ANON) == 1 && c)
+               return get_mm_proctitle(mm, buf, count, pos, arg_start);
 
-       /* .. and we never go past env_end */
-       if (env_end - pos < count)
-               count = env_end - pos;
+       /*
+        * For the non-setproctitle() case we limit things strictly
+        * to the [arg_start, arg_end[ range.
+        */
+       pos += arg_start;
+       if (pos < arg_start || pos >= arg_end)
+               return 0;
+       if (count > arg_end - pos)
+               count = arg_end - pos;
 
        page = (char *)__get_free_page(GFP_KERNEL);
        if (!page)
@@ -262,48 +317,11 @@ static ssize_t get_mm_cmdline(struct mm_struct *mm, char __user *buf,
        while (count) {
                int got;
                size_t size = min_t(size_t, PAGE_SIZE, count);
-               long offset;
 
-               /*
-                * Are we already starting past the official end?
-                * We always include the last byte that is *supposed*
-                * to be NUL
-                */
-               offset = (pos >= arg_end) ? pos - arg_end + 1 : 0;
-
-               got = access_remote_vm(mm, pos - offset, page, size + offset, FOLL_ANON);
-               if (got <= offset)
+               got = access_remote_vm(mm, pos, page, size, FOLL_ANON);
+               if (got <= 0)
                        break;
-               got -= offset;
-
-               /* Don't walk past a NUL character once you hit arg_end */
-               if (pos + got >= arg_end) {
-                       int n = 0;
-
-                       /*
-                        * If we started before 'arg_end' but ended up
-                        * at or after it, we start the NUL character
-                        * check at arg_end-1 (where we expect the normal
-                        * EOF to be).
-                        *
-                        * NOTE! This is smaller than 'got', because
-                        * pos + got >= arg_end
-                        */
-                       if (pos < arg_end)
-                               n = arg_end - pos - 1;
-
-                       /* Cut off at first NUL after 'n' */
-                       got = n + strnlen(page+n, offset+got-n);
-                       if (got < offset)
-                               break;
-                       got -= offset;
-
-                       /* Include the NUL if it existed */
-                       if (got < size)
-                               got++;
-               }
-
-               got -= copy_to_user(buf, page+offset, got);
+               got -= copy_to_user(buf, page, got);
                if (unlikely(!got)) {
                        if (!len)
                                len = -EFAULT;
index 5f8d215..dbe43a5 100644 (file)
@@ -200,7 +200,8 @@ static loff_t proc_reg_llseek(struct file *file, loff_t offset, int whence)
        struct proc_dir_entry *pde = PDE(file_inode(file));
        loff_t rv = -EINVAL;
        if (use_pde(pde)) {
-               loff_t (*llseek)(struct file *, loff_t, int);
+               typeof_member(struct file_operations, llseek) llseek;
+
                llseek = pde->proc_fops->llseek;
                if (!llseek)
                        llseek = default_llseek;
@@ -212,10 +213,11 @@ static loff_t proc_reg_llseek(struct file *file, loff_t offset, int whence)
 
 static ssize_t proc_reg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
 {
-       ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
        struct proc_dir_entry *pde = PDE(file_inode(file));
        ssize_t rv = -EIO;
        if (use_pde(pde)) {
+               typeof_member(struct file_operations, read) read;
+
                read = pde->proc_fops->read;
                if (read)
                        rv = read(file, buf, count, ppos);
@@ -226,10 +228,11 @@ static ssize_t proc_reg_read(struct file *file, char __user *buf, size_t count,
 
 static ssize_t proc_reg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
 {
-       ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);
        struct proc_dir_entry *pde = PDE(file_inode(file));
        ssize_t rv = -EIO;
        if (use_pde(pde)) {
+               typeof_member(struct file_operations, write) write;
+
                write = pde->proc_fops->write;
                if (write)
                        rv = write(file, buf, count, ppos);
@@ -242,8 +245,9 @@ static __poll_t proc_reg_poll(struct file *file, struct poll_table_struct *pts)
 {
        struct proc_dir_entry *pde = PDE(file_inode(file));
        __poll_t rv = DEFAULT_POLLMASK;
-       __poll_t (*poll)(struct file *, struct poll_table_struct *);
        if (use_pde(pde)) {
+               typeof_member(struct file_operations, poll) poll;
+
                poll = pde->proc_fops->poll;
                if (poll)
                        rv = poll(file, pts);
@@ -256,8 +260,9 @@ static long proc_reg_unlocked_ioctl(struct file *file, unsigned int cmd, unsigne
 {
        struct proc_dir_entry *pde = PDE(file_inode(file));
        long rv = -ENOTTY;
-       long (*ioctl)(struct file *, unsigned int, unsigned long);
        if (use_pde(pde)) {
+               typeof_member(struct file_operations, unlocked_ioctl) ioctl;
+
                ioctl = pde->proc_fops->unlocked_ioctl;
                if (ioctl)
                        rv = ioctl(file, cmd, arg);
@@ -271,8 +276,9 @@ static long proc_reg_compat_ioctl(struct file *file, unsigned int cmd, unsigned
 {
        struct proc_dir_entry *pde = PDE(file_inode(file));
        long rv = -ENOTTY;
-       long (*compat_ioctl)(struct file *, unsigned int, unsigned long);
        if (use_pde(pde)) {
+               typeof_member(struct file_operations, compat_ioctl) compat_ioctl;
+
                compat_ioctl = pde->proc_fops->compat_ioctl;
                if (compat_ioctl)
                        rv = compat_ioctl(file, cmd, arg);
@@ -286,8 +292,9 @@ static int proc_reg_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct proc_dir_entry *pde = PDE(file_inode(file));
        int rv = -EIO;
-       int (*mmap)(struct file *, struct vm_area_struct *);
        if (use_pde(pde)) {
+               typeof_member(struct file_operations, mmap) mmap;
+
                mmap = pde->proc_fops->mmap;
                if (mmap)
                        rv = mmap(file, vma);
@@ -305,7 +312,7 @@ proc_reg_get_unmapped_area(struct file *file, unsigned long orig_addr,
        unsigned long rv = -EIO;
 
        if (use_pde(pde)) {
-               typeof(proc_reg_get_unmapped_area) *get_area;
+               typeof_member(struct file_operations, get_unmapped_area) get_area;
 
                get_area = pde->proc_fops->get_unmapped_area;
 #ifdef CONFIG_MMU
@@ -326,8 +333,8 @@ static int proc_reg_open(struct inode *inode, struct file *file)
 {
        struct proc_dir_entry *pde = PDE(inode);
        int rv = 0;
-       int (*open)(struct inode *, struct file *);
-       int (*release)(struct inode *, struct file *);
+       typeof_member(struct file_operations, open) open;
+       typeof_member(struct file_operations, release) release;
        struct pde_opener *pdeo;
 
        /*
index c745707..d80989b 100644 (file)
@@ -22,6 +22,10 @@ static const struct inode_operations proc_sys_inode_operations;
 static const struct file_operations proc_sys_dir_file_operations;
 static const struct inode_operations proc_sys_dir_operations;
 
+/* shared constants to be used in various sysctls */
+const int sysctl_vals[] = { 0, 1, INT_MAX };
+EXPORT_SYMBOL(sysctl_vals);
+
 /* Support for permanently empty directories */
 
 struct ctl_table sysctl_mount_point[] = {
@@ -499,6 +503,10 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
 
        if (root->set_ownership)
                root->set_ownership(head, table, &inode->i_uid, &inode->i_gid);
+       else {
+               inode->i_uid = GLOBAL_ROOT_UID;
+               inode->i_gid = GLOBAL_ROOT_GID;
+       }
 
        return inode;
 }
index 522199e..33f72d1 100644 (file)
@@ -157,8 +157,6 @@ static int proc_get_tree(struct fs_context *fc)
 {
        struct proc_fs_context *ctx = fc->fs_private;
 
-       put_user_ns(fc->user_ns);
-       fc->user_ns = get_user_ns(ctx->pid_ns->user_ns);
        fc->s_fs_info = ctx->pid_ns;
        return vfs_get_super(fc, vfs_get_keyed_super, proc_fill_super);
 }
@@ -167,8 +165,7 @@ static void proc_fs_context_free(struct fs_context *fc)
 {
        struct proc_fs_context *ctx = fc->fs_private;
 
-       if (ctx->pid_ns)
-               put_pid_ns(ctx->pid_ns);
+       put_pid_ns(ctx->pid_ns);
        kfree(ctx);
 }
 
@@ -188,6 +185,8 @@ static int proc_init_fs_context(struct fs_context *fc)
                return -ENOMEM;
 
        ctx->pid_ns = get_pid_ns(task_active_pid_ns(current));
+       put_user_ns(fc->user_ns);
+       fc->user_ns = get_user_ns(ctx->pid_ns->user_ns);
        fc->fs_private = ctx;
        fc->ops = &proc_fs_context_ops;
        return 0;
index 818cedb..731642e 100644 (file)
@@ -832,7 +832,8 @@ static int show_smap(struct seq_file *m, void *v)
 
        __show_smap(m, &mss, false);
 
-       seq_printf(m, "THPeligible:    %d\n", transparent_hugepage_enabled(vma));
+       seq_printf(m, "THPeligible:             %d\n",
+                  transparent_hugepage_enabled(vma));
 
        if (arch_pkeys_enabled())
                seq_printf(m, "ProtectionKey:  %8u\n", vma_pkey(vma));
index 57957c9..7bcc92a 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/crash_dump.h>
 #include <linux/list.h>
+#include <linux/moduleparam.h>
 #include <linux/mutex.h>
 #include <linux/vmalloc.h>
 #include <linux/pagemap.h>
@@ -54,6 +55,9 @@ static struct proc_dir_entry *proc_vmcore;
 /* Device Dump list and mutex to synchronize access to list */
 static LIST_HEAD(vmcoredd_list);
 static DEFINE_MUTEX(vmcoredd_mutex);
+
+static bool vmcoredd_disabled;
+core_param(novmcoredd, vmcoredd_disabled, bool, 0);
 #endif /* CONFIG_PROC_VMCORE_DEVICE_DUMP */
 
 /* Device Dump Size */
@@ -1452,6 +1456,11 @@ int vmcore_add_device_dump(struct vmcoredd_data *data)
        size_t data_size;
        int ret;
 
+       if (vmcoredd_disabled) {
+               pr_err_once("Device dump is disabled\n");
+               return -EINVAL;
+       }
+
        if (!data || !strlen(data->dump_name) ||
            !data->vmcoredd_callback || !data->size)
                return -EINVAL;
index 11201b2..733c6b4 100644 (file)
@@ -266,12 +266,8 @@ static struct file_system_type ramfs_fs_type = {
        .fs_flags       = FS_USERNS_MOUNT,
 };
 
-int __init init_ramfs_fs(void)
+static int __init init_ramfs_fs(void)
 {
-       static unsigned long once;
-
-       if (test_and_set_bit(0, &once))
-               return 0;
        return register_filesystem(&ramfs_fs_type);
 }
 fs_initcall(init_ramfs_fs);
index 36346dc..4517a13 100644 (file)
@@ -94,7 +94,7 @@ static int journal_join(struct reiserfs_transaction_handle *th,
                        struct super_block *sb);
 static void release_journal_dev(struct super_block *super,
                               struct reiserfs_journal *journal);
-static int dirty_one_transaction(struct super_block *s,
+static void dirty_one_transaction(struct super_block *s,
                                 struct reiserfs_journal_list *jl);
 static void flush_async_commits(struct work_struct *work);
 static void queue_log_writer(struct super_block *s);
@@ -1682,12 +1682,11 @@ next:
 }
 
 /* used by flush_commit_list */
-static int dirty_one_transaction(struct super_block *s,
+static void dirty_one_transaction(struct super_block *s,
                                 struct reiserfs_journal_list *jl)
 {
        struct reiserfs_journal_cnode *cn;
        struct reiserfs_journal_list *pjl;
-       int ret = 0;
 
        jl->j_state |= LIST_DIRTY;
        cn = jl->j_realblock;
@@ -1716,7 +1715,6 @@ static int dirty_one_transaction(struct super_block *s,
                }
                cn = cn->next;
        }
-       return ret;
 }
 
 static int kupdate_transactions(struct super_block *s,
index a4d8f6e..53a0c14 100644 (file)
@@ -294,12 +294,14 @@ enum poll_time_type {
        PT_OLD_TIMESPEC = 3,
 };
 
-static int poll_select_copy_remaining(struct timespec64 *end_time,
-                                     void __user *p,
-                                     enum poll_time_type pt_type, int ret)
+static int poll_select_finish(struct timespec64 *end_time,
+                             void __user *p,
+                             enum poll_time_type pt_type, int ret)
 {
        struct timespec64 rts;
 
+       restore_saved_sigmask_unless(ret == -ERESTARTNOHAND);
+
        if (!p)
                return ret;
 
@@ -714,9 +716,7 @@ static int kern_select(int n, fd_set __user *inp, fd_set __user *outp,
        }
 
        ret = core_sys_select(n, inp, outp, exp, to);
-       ret = poll_select_copy_remaining(&end_time, tvp, PT_TIMEVAL, ret);
-
-       return ret;
+       return poll_select_finish(&end_time, tvp, PT_TIMEVAL, ret);
 }
 
 SYSCALL_DEFINE5(select, int, n, fd_set __user *, inp, fd_set __user *, outp,
@@ -730,7 +730,6 @@ static long do_pselect(int n, fd_set __user *inp, fd_set __user *outp,
                       const sigset_t __user *sigmask, size_t sigsetsize,
                       enum poll_time_type type)
 {
-       sigset_t ksigmask, sigsaved;
        struct timespec64 ts, end_time, *to = NULL;
        int ret;
 
@@ -753,15 +752,12 @@ static long do_pselect(int n, fd_set __user *inp, fd_set __user *outp,
                        return -EINVAL;
        }
 
-       ret = set_user_sigmask(sigmask, &ksigmask, &sigsaved, sigsetsize);
+       ret = set_user_sigmask(sigmask, sigsetsize);
        if (ret)
                return ret;
 
        ret = core_sys_select(n, inp, outp, exp, to);
-       restore_user_sigmask(sigmask, &sigsaved, ret == -ERESTARTNOHAND);
-       ret = poll_select_copy_remaining(&end_time, tsp, type, ret);
-
-       return ret;
+       return poll_select_finish(&end_time, tsp, type, ret);
 }
 
 /*
@@ -926,7 +922,7 @@ static int do_poll(struct poll_list *list, struct poll_wqueues *wait,
                if (!count) {
                        count = wait->error;
                        if (signal_pending(current))
-                               count = -EINTR;
+                               count = -ERESTARTNOHAND;
                }
                if (count || timed_out)
                        break;
@@ -965,7 +961,7 @@ static int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,
                struct timespec64 *end_time)
 {
        struct poll_wqueues table;
-       int err = -EFAULT, fdcount, len, size;
+       int err = -EFAULT, fdcount, len;
        /* Allocate small arguments on the stack to save memory and be
           faster - use long to make sure the buffer is aligned properly
           on 64 bit archs to avoid unaligned access */
@@ -993,8 +989,8 @@ static int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,
                        break;
 
                len = min(todo, POLLFD_PER_PAGE);
-               size = sizeof(struct poll_list) + sizeof(struct pollfd) * len;
-               walk = walk->next = kmalloc(size, GFP_KERNEL);
+               walk = walk->next = kmalloc(struct_size(walk, entries, len),
+                                           GFP_KERNEL);
                if (!walk) {
                        err = -ENOMEM;
                        goto out_fds;
@@ -1041,7 +1037,7 @@ static long do_restart_poll(struct restart_block *restart_block)
 
        ret = do_sys_poll(ufds, nfds, to);
 
-       if (ret == -EINTR) {
+       if (ret == -ERESTARTNOHAND) {
                restart_block->fn = do_restart_poll;
                ret = -ERESTART_RESTARTBLOCK;
        }
@@ -1062,7 +1058,7 @@ SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds,
 
        ret = do_sys_poll(ufds, nfds, to);
 
-       if (ret == -EINTR) {
+       if (ret == -ERESTARTNOHAND) {
                struct restart_block *restart_block;
 
                restart_block = &current->restart_block;
@@ -1086,7 +1082,6 @@ SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds,
                struct __kernel_timespec __user *, tsp, const sigset_t __user *, sigmask,
                size_t, sigsetsize)
 {
-       sigset_t ksigmask, sigsaved;
        struct timespec64 ts, end_time, *to = NULL;
        int ret;
 
@@ -1099,20 +1094,12 @@ SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds,
                        return -EINVAL;
        }
 
-       ret = set_user_sigmask(sigmask, &ksigmask, &sigsaved, sigsetsize);
+       ret = set_user_sigmask(sigmask, sigsetsize);
        if (ret)
                return ret;
 
        ret = do_sys_poll(ufds, nfds, to);
-
-       restore_user_sigmask(sigmask, &sigsaved, ret == -EINTR);
-       /* We can restart this syscall, usually */
-       if (ret == -EINTR)
-               ret = -ERESTARTNOHAND;
-
-       ret = poll_select_copy_remaining(&end_time, tsp, PT_TIMESPEC, ret);
-
-       return ret;
+       return poll_select_finish(&end_time, tsp, PT_TIMESPEC, ret);
 }
 
 #if defined(CONFIG_COMPAT_32BIT_TIME) && !defined(CONFIG_64BIT)
@@ -1121,7 +1108,6 @@ SYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds, unsigned int, nfds,
                struct old_timespec32 __user *, tsp, const sigset_t __user *, sigmask,
                size_t, sigsetsize)
 {
-       sigset_t ksigmask, sigsaved;
        struct timespec64 ts, end_time, *to = NULL;
        int ret;
 
@@ -1134,20 +1120,12 @@ SYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds, unsigned int, nfds,
                        return -EINVAL;
        }
 
-       ret = set_user_sigmask(sigmask, &ksigmask, &sigsaved, sigsetsize);
+       ret = set_user_sigmask(sigmask, sigsetsize);
        if (ret)
                return ret;
 
        ret = do_sys_poll(ufds, nfds, to);
-
-       restore_user_sigmask(sigmask, &sigsaved, ret == -EINTR);
-       /* We can restart this syscall, usually */
-       if (ret == -EINTR)
-               ret = -ERESTARTNOHAND;
-
-       ret = poll_select_copy_remaining(&end_time, tsp, PT_OLD_TIMESPEC, ret);
-
-       return ret;
+       return poll_select_finish(&end_time, tsp, PT_OLD_TIMESPEC, ret);
 }
 #endif
 
@@ -1284,9 +1262,7 @@ static int do_compat_select(int n, compat_ulong_t __user *inp,
        }
 
        ret = compat_core_sys_select(n, inp, outp, exp, to);
-       ret = poll_select_copy_remaining(&end_time, tvp, PT_OLD_TIMEVAL, ret);
-
-       return ret;
+       return poll_select_finish(&end_time, tvp, PT_OLD_TIMEVAL, ret);
 }
 
 COMPAT_SYSCALL_DEFINE5(select, int, n, compat_ulong_t __user *, inp,
@@ -1319,7 +1295,6 @@ static long do_compat_pselect(int n, compat_ulong_t __user *inp,
        void __user *tsp, compat_sigset_t __user *sigmask,
        compat_size_t sigsetsize, enum poll_time_type type)
 {
-       sigset_t ksigmask, sigsaved;
        struct timespec64 ts, end_time, *to = NULL;
        int ret;
 
@@ -1342,15 +1317,12 @@ static long do_compat_pselect(int n, compat_ulong_t __user *inp,
                        return -EINVAL;
        }
 
-       ret = set_compat_user_sigmask(sigmask, &ksigmask, &sigsaved, sigsetsize);
+       ret = set_compat_user_sigmask(sigmask, sigsetsize);
        if (ret)
                return ret;
 
        ret = compat_core_sys_select(n, inp, outp, exp, to);
-       restore_user_sigmask(sigmask, &sigsaved, ret == -ERESTARTNOHAND);
-       ret = poll_select_copy_remaining(&end_time, tsp, type, ret);
-
-       return ret;
+       return poll_select_finish(&end_time, tsp, type, ret);
 }
 
 COMPAT_SYSCALL_DEFINE6(pselect6_time64, int, n, compat_ulong_t __user *, inp,
@@ -1402,7 +1374,6 @@ COMPAT_SYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds,
        unsigned int,  nfds, struct old_timespec32 __user *, tsp,
        const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize)
 {
-       sigset_t ksigmask, sigsaved;
        struct timespec64 ts, end_time, *to = NULL;
        int ret;
 
@@ -1415,20 +1386,12 @@ COMPAT_SYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds,
                        return -EINVAL;
        }
 
-       ret = set_compat_user_sigmask(sigmask, &ksigmask, &sigsaved, sigsetsize);
+       ret = set_compat_user_sigmask(sigmask, sigsetsize);
        if (ret)
                return ret;
 
        ret = do_sys_poll(ufds, nfds, to);
-
-       restore_user_sigmask(sigmask, &sigsaved, ret == -EINTR);
-       /* We can restart this syscall, usually */
-       if (ret == -EINTR)
-               ret = -ERESTARTNOHAND;
-
-       ret = poll_select_copy_remaining(&end_time, tsp, PT_OLD_TIMESPEC, ret);
-
-       return ret;
+       return poll_select_finish(&end_time, tsp, PT_OLD_TIMESPEC, ret);
 }
 #endif
 
@@ -1437,7 +1400,6 @@ COMPAT_SYSCALL_DEFINE5(ppoll_time64, struct pollfd __user *, ufds,
        unsigned int,  nfds, struct __kernel_timespec __user *, tsp,
        const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize)
 {
-       sigset_t ksigmask, sigsaved;
        struct timespec64 ts, end_time, *to = NULL;
        int ret;
 
@@ -1450,20 +1412,12 @@ COMPAT_SYSCALL_DEFINE5(ppoll_time64, struct pollfd __user *, ufds,
                        return -EINVAL;
        }
 
-       ret = set_compat_user_sigmask(sigmask, &ksigmask, &sigsaved, sigsetsize);
+       ret = set_compat_user_sigmask(sigmask, sigsetsize);
        if (ret)
                return ret;
 
        ret = do_sys_poll(ufds, nfds, to);
-
-       restore_user_sigmask(sigmask, &sigsaved, ret == -EINTR);
-       /* We can restart this syscall, usually */
-       if (ret == -EINTR)
-               ret = -ERESTARTNOHAND;
-
-       ret = poll_select_copy_remaining(&end_time, tsp, PT_TIMESPEC, ret);
-
-       return ret;
+       return poll_select_finish(&end_time, tsp, PT_TIMESPEC, ret);
 }
 
 #endif
index 2739f57..113c58f 100644 (file)
@@ -476,6 +476,17 @@ void generic_shutdown_super(struct super_block *sb)
 
 EXPORT_SYMBOL(generic_shutdown_super);
 
+bool mount_capable(struct fs_context *fc)
+{
+       struct user_namespace *user_ns = fc->global ? &init_user_ns
+                                                   : fc->user_ns;
+
+       if (!(fc->fs_type->fs_flags & FS_USERNS_MOUNT))
+               return capable(CAP_SYS_ADMIN);
+       else
+               return ns_capable(user_ns, CAP_SYS_ADMIN);
+}
+
 /**
  * sget_fc - Find or create a superblock
  * @fc:        Filesystem context.
@@ -503,20 +514,6 @@ struct super_block *sget_fc(struct fs_context *fc,
        struct user_namespace *user_ns = fc->global ? &init_user_ns : fc->user_ns;
        int err;
 
-       if (!(fc->sb_flags & SB_KERNMOUNT) &&
-           fc->purpose != FS_CONTEXT_FOR_SUBMOUNT) {
-               /* Don't allow mounting unless the caller has CAP_SYS_ADMIN
-                * over the namespace.
-                */
-               if (!(fc->fs_type->fs_flags & FS_USERNS_MOUNT)) {
-                       if (!capable(CAP_SYS_ADMIN))
-                               return ERR_PTR(-EPERM);
-               } else {
-                       if (!ns_capable(fc->user_ns, CAP_SYS_ADMIN))
-                               return ERR_PTR(-EPERM);
-               }
-       }
-
 retry:
        spin_lock(&sb_lock);
        if (test) {
@@ -543,6 +540,7 @@ retry:
        }
        fc->s_fs_info = NULL;
        s->s_type = fc->fs_type;
+       s->s_iflags |= fc->s_iflags;
        strlcpy(s->s_id, s->s_type->name, sizeof(s->s_id));
        list_add_tail(&s->s_list, &super_blocks);
        hlist_add_head(&s->s_instances, &s->s_type->fs_supers);
@@ -565,28 +563,31 @@ share_extant_sb:
 EXPORT_SYMBOL(sget_fc);
 
 /**
- *     sget_userns -   find or create a superblock
- *     @type:  filesystem type superblock should belong to
- *     @test:  comparison callback
- *     @set:   setup callback
- *     @flags: mount flags
- *     @user_ns: User namespace for the super_block
- *     @data:  argument to each of them
+ *     sget    -       find or create a superblock
+ *     @type:    filesystem type superblock should belong to
+ *     @test:    comparison callback
+ *     @set:     setup callback
+ *     @flags:   mount flags
+ *     @data:    argument to each of them
  */
-struct super_block *sget_userns(struct file_system_type *type,
+struct super_block *sget(struct file_system_type *type,
                        int (*test)(struct super_block *,void *),
                        int (*set)(struct super_block *,void *),
-                       int flags, struct user_namespace *user_ns,
+                       int flags,
                        void *data)
 {
+       struct user_namespace *user_ns = current_user_ns();
        struct super_block *s = NULL;
        struct super_block *old;
        int err;
 
-       if (!(flags & (SB_KERNMOUNT|SB_SUBMOUNT)) &&
-           !(type->fs_flags & FS_USERNS_MOUNT) &&
-           !capable(CAP_SYS_ADMIN))
-               return ERR_PTR(-EPERM);
+       /* We don't yet pass the user namespace of the parent
+        * mount through to here so always use &init_user_ns
+        * until that changes.
+        */
+       if (flags & SB_SUBMOUNT)
+               user_ns = &init_user_ns;
+
 retry:
        spin_lock(&sb_lock);
        if (test) {
@@ -627,39 +628,6 @@ retry:
        register_shrinker_prepared(&s->s_shrink);
        return s;
 }
-
-EXPORT_SYMBOL(sget_userns);
-
-/**
- *     sget    -       find or create a superblock
- *     @type:    filesystem type superblock should belong to
- *     @test:    comparison callback
- *     @set:     setup callback
- *     @flags:   mount flags
- *     @data:    argument to each of them
- */
-struct super_block *sget(struct file_system_type *type,
-                       int (*test)(struct super_block *,void *),
-                       int (*set)(struct super_block *,void *),
-                       int flags,
-                       void *data)
-{
-       struct user_namespace *user_ns = current_user_ns();
-
-       /* We don't yet pass the user namespace of the parent
-        * mount through to here so always use &init_user_ns
-        * until that changes.
-        */
-       if (flags & SB_SUBMOUNT)
-               user_ns = &init_user_ns;
-
-       /* Ensure the requestor has permissions over the target filesystem */
-       if (!(flags & (SB_KERNMOUNT|SB_SUBMOUNT)) && !ns_capable(user_ns, CAP_SYS_ADMIN))
-               return ERR_PTR(-EPERM);
-
-       return sget_userns(type, test, set, flags, user_ns, data);
-}
-
 EXPORT_SYMBOL(sget);
 
 void drop_super(struct super_block *sb)
@@ -1147,50 +1115,6 @@ void kill_litter_super(struct super_block *sb)
 }
 EXPORT_SYMBOL(kill_litter_super);
 
-static int ns_test_super(struct super_block *sb, void *data)
-{
-       return sb->s_fs_info == data;
-}
-
-static int ns_set_super(struct super_block *sb, void *data)
-{
-       sb->s_fs_info = data;
-       return set_anon_super(sb, NULL);
-}
-
-struct dentry *mount_ns(struct file_system_type *fs_type,
-       int flags, void *data, void *ns, struct user_namespace *user_ns,
-       int (*fill_super)(struct super_block *, void *, int))
-{
-       struct super_block *sb;
-
-       /* Don't allow mounting unless the caller has CAP_SYS_ADMIN
-        * over the namespace.
-        */
-       if (!(flags & SB_KERNMOUNT) && !ns_capable(user_ns, CAP_SYS_ADMIN))
-               return ERR_PTR(-EPERM);
-
-       sb = sget_userns(fs_type, ns_test_super, ns_set_super, flags,
-                        user_ns, ns);
-       if (IS_ERR(sb))
-               return ERR_CAST(sb);
-
-       if (!sb->s_root) {
-               int err;
-               err = fill_super(sb, data, flags & SB_SILENT ? 1 : 0);
-               if (err) {
-                       deactivate_locked_super(sb);
-                       return ERR_PTR(err);
-               }
-
-               sb->s_flags |= SB_ACTIVE;
-       }
-
-       return dget(sb->s_root);
-}
-
-EXPORT_SYMBOL(mount_ns);
-
 int set_anon_super_fc(struct super_block *sb, struct fs_context *fc)
 {
        return set_anon_super(sb, NULL);
@@ -1274,6 +1198,22 @@ int vfs_get_super(struct fs_context *fc,
 }
 EXPORT_SYMBOL(vfs_get_super);
 
+int get_tree_nodev(struct fs_context *fc,
+                 int (*fill_super)(struct super_block *sb,
+                                   struct fs_context *fc))
+{
+       return vfs_get_super(fc, vfs_get_independent_super, fill_super);
+}
+EXPORT_SYMBOL(get_tree_nodev);
+
+int get_tree_single(struct fs_context *fc,
+                 int (*fill_super)(struct super_block *sb,
+                                   struct fs_context *fc))
+{
+       return vfs_get_super(fc, vfs_get_single_super, fill_super);
+}
+EXPORT_SYMBOL(get_tree_single);
+
 #ifdef CONFIG_BLOCK
 static int set_bdev_super(struct super_block *s, void *data)
 {
index 1b56686..db81cfb 100644 (file)
@@ -72,8 +72,7 @@ static int sysfs_init_fs_context(struct fs_context *fc)
        fc->fs_private = kfc;
        fc->ops = &sysfs_fs_context_ops;
        if (netns) {
-               if (fc->user_ns)
-                       put_user_ns(fc->user_ns);
+               put_user_ns(fc->user_ns);
                fc->user_ns = get_user_ns(netns->user_ns);
        }
        fc->global = true;
index e5f8de6..400970d 100644 (file)
@@ -1470,7 +1470,7 @@ static int ubifs_migrate_page(struct address_space *mapping,
 {
        int rc;
 
-       rc = migrate_page_move_mapping(mapping, newpage, page, mode, 0);
+       rc = migrate_page_move_mapping(mapping, newpage, page, 0);
        if (rc != MIGRATEPAGE_SUCCESS)
                return rc;
 
index 3d247c0..4ed0dca 100644 (file)
@@ -1407,11 +1407,9 @@ static int ufs_statfs(struct dentry *dentry, struct kstatfs *buf)
        struct super_block *sb = dentry->d_sb;
        struct ufs_sb_private_info *uspi= UFS_SB(sb)->s_uspi;
        unsigned  flags = UFS_SB(sb)->s_flags;
-       struct ufs_super_block_third *usb3;
        u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        mutex_lock(&UFS_SB(sb)->s_lock);
-       usb3 = ubh_get_usb_third(uspi);
        
        if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
                buf->f_type = UFS2_MAGIC;
index b74a471..06b68b6 100644 (file)
@@ -49,6 +49,7 @@ xfs-y                         += $(addprefix libxfs/, \
                                   xfs_refcount_btree.o \
                                   xfs_sb.o \
                                   xfs_symlink_remote.o \
+                                  xfs_trans_inode.o \
                                   xfs_trans_resv.o \
                                   xfs_types.o \
                                   )
@@ -107,8 +108,7 @@ xfs-y                               += xfs_log.o \
                                   xfs_rmap_item.o \
                                   xfs_log_recover.o \
                                   xfs_trans_ail.o \
-                                  xfs_trans_buf.o \
-                                  xfs_trans_inode.o
+                                  xfs_trans_buf.o
 
 # optional features
 xfs-$(CONFIG_XFS_QUOTA)                += xfs_dquot.o \
diff --git a/fs/xfs/libxfs/xfs_trans_inode.c b/fs/xfs/libxfs/xfs_trans_inode.c
new file mode 100644 (file)
index 0000000..a9ad909
--- /dev/null
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2000,2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ */
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_shared.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_inode.h"
+#include "xfs_trans.h"
+#include "xfs_trans_priv.h"
+#include "xfs_inode_item.h"
+
+#include <linux/iversion.h>
+
+/*
+ * Add a locked inode to the transaction.
+ *
+ * The inode must be locked, and it cannot be associated with any transaction.
+ * If lock_flags is non-zero the inode will be unlocked on transaction commit.
+ */
+void
+xfs_trans_ijoin(
+       struct xfs_trans        *tp,
+       struct xfs_inode        *ip,
+       uint                    lock_flags)
+{
+       xfs_inode_log_item_t    *iip;
+
+       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
+       if (ip->i_itemp == NULL)
+               xfs_inode_item_init(ip, ip->i_mount);
+       iip = ip->i_itemp;
+
+       ASSERT(iip->ili_lock_flags == 0);
+       iip->ili_lock_flags = lock_flags;
+
+       /*
+        * Get a log_item_desc to point at the new item.
+        */
+       xfs_trans_add_item(tp, &iip->ili_item);
+}
+
+/*
+ * Transactional inode timestamp update. Requires the inode to be locked and
+ * joined to the transaction supplied. Relies on the transaction subsystem to
+ * track dirty state and update/writeback the inode accordingly.
+ */
+void
+xfs_trans_ichgtime(
+       struct xfs_trans        *tp,
+       struct xfs_inode        *ip,
+       int                     flags)
+{
+       struct inode            *inode = VFS_I(ip);
+       struct timespec64 tv;
+
+       ASSERT(tp);
+       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
+
+       tv = current_time(inode);
+
+       if (flags & XFS_ICHGTIME_MOD)
+               inode->i_mtime = tv;
+       if (flags & XFS_ICHGTIME_CHG)
+               inode->i_ctime = tv;
+       if (flags & XFS_ICHGTIME_CREATE) {
+               ip->i_d.di_crtime.t_sec = (int32_t)tv.tv_sec;
+               ip->i_d.di_crtime.t_nsec = (int32_t)tv.tv_nsec;
+       }
+}
+
+/*
+ * This is called to mark the fields indicated in fieldmask as needing
+ * to be logged when the transaction is committed.  The inode must
+ * already be associated with the given transaction.
+ *
+ * The values for fieldmask are defined in xfs_inode_item.h.  We always
+ * log all of the core inode if any of it has changed, and we always log
+ * all of the inline data/extents/b-tree root if any of them has changed.
+ */
+void
+xfs_trans_log_inode(
+       xfs_trans_t     *tp,
+       xfs_inode_t     *ip,
+       uint            flags)
+{
+       struct inode    *inode = VFS_I(ip);
+
+       ASSERT(ip->i_itemp != NULL);
+       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
+
+       /*
+        * Don't bother with i_lock for the I_DIRTY_TIME check here, as races
+        * don't matter - we either will need an extra transaction in 24 hours
+        * to log the timestamps, or will clear already cleared fields in the
+        * worst case.
+        */
+       if (inode->i_state & (I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED)) {
+               spin_lock(&inode->i_lock);
+               inode->i_state &= ~(I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED);
+               spin_unlock(&inode->i_lock);
+       }
+
+       /*
+        * Record the specific change for fdatasync optimisation. This
+        * allows fdatasync to skip log forces for inodes that are only
+        * timestamp dirty. We do this before the change count so that
+        * the core being logged in this case does not impact on fdatasync
+        * behaviour.
+        */
+       ip->i_itemp->ili_fsync_fields |= flags;
+
+       /*
+        * First time we log the inode in a transaction, bump the inode change
+        * counter if it is configured for this to occur. While we have the
+        * inode locked exclusively for metadata modification, we can usually
+        * avoid setting XFS_ILOG_CORE if no one has queried the value since
+        * the last time it was incremented. If we have XFS_ILOG_CORE already
+        * set however, then go ahead and bump the i_version counter
+        * unconditionally.
+        */
+       if (!test_and_set_bit(XFS_LI_DIRTY, &ip->i_itemp->ili_item.li_flags) &&
+           IS_I_VERSION(VFS_I(ip))) {
+               if (inode_maybe_inc_iversion(VFS_I(ip), flags & XFS_ILOG_CORE))
+                       flags |= XFS_ILOG_CORE;
+       }
+
+       tp->t_flags |= XFS_TRANS_DIRTY;
+
+       /*
+        * Always OR in the bits from the ili_last_fields field.
+        * This is to coordinate with the xfs_iflush() and xfs_iflush_done()
+        * routines in the eventual clearing of the ili_fields bits.
+        * See the big comment in xfs_iflush() for an explanation of
+        * this coordination mechanism.
+        */
+       flags |= ip->i_itemp->ili_last_fields;
+       ip->i_itemp->ili_fields |= flags;
+}
+
+int
+xfs_trans_roll_inode(
+       struct xfs_trans        **tpp,
+       struct xfs_inode        *ip)
+{
+       int                     error;
+
+       xfs_trans_log_inode(*tpp, ip, XFS_ILOG_CORE);
+       error = xfs_trans_roll(tpp);
+       if (!error)
+               xfs_trans_ijoin(*tpp, ip, 0);
+       return error;
+}
index e93bacb..28101bb 100644 (file)
@@ -1197,11 +1197,14 @@ xfs_file_mmap(
        struct file     *filp,
        struct vm_area_struct *vma)
 {
+       struct dax_device       *dax_dev;
+
+       dax_dev = xfs_find_daxdev_for_inode(file_inode(filp));
        /*
-        * We don't support synchronous mappings for non-DAX files. At least
-        * until someone comes with a sensible use case.
+        * We don't support synchronous mappings for non-DAX files and
+        * for DAX files if underneath dax_device is not synchronous.
         */
-       if (!IS_DAX(file_inode(filp)) && (vma->vm_flags & VM_SYNC))
+       if (!daxdev_mapping_supported(vma, dax_dev))
                return -EOPNOTSUPP;
 
        file_accessed(filp);
diff --git a/fs/xfs/xfs_trans_inode.c b/fs/xfs/xfs_trans_inode.c
deleted file mode 100644 (file)
index 93d14e4..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2000,2005 Silicon Graphics, Inc.
- * All Rights Reserved.
- */
-#include "xfs.h"
-#include "xfs_fs.h"
-#include "xfs_shared.h"
-#include "xfs_format.h"
-#include "xfs_log_format.h"
-#include "xfs_inode.h"
-#include "xfs_trans.h"
-#include "xfs_trans_priv.h"
-#include "xfs_inode_item.h"
-
-#include <linux/iversion.h>
-
-/*
- * Add a locked inode to the transaction.
- *
- * The inode must be locked, and it cannot be associated with any transaction.
- * If lock_flags is non-zero the inode will be unlocked on transaction commit.
- */
-void
-xfs_trans_ijoin(
-       struct xfs_trans        *tp,
-       struct xfs_inode        *ip,
-       uint                    lock_flags)
-{
-       xfs_inode_log_item_t    *iip;
-
-       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-       if (ip->i_itemp == NULL)
-               xfs_inode_item_init(ip, ip->i_mount);
-       iip = ip->i_itemp;
-
-       ASSERT(iip->ili_lock_flags == 0);
-       iip->ili_lock_flags = lock_flags;
-
-       /*
-        * Get a log_item_desc to point at the new item.
-        */
-       xfs_trans_add_item(tp, &iip->ili_item);
-}
-
-/*
- * Transactional inode timestamp update. Requires the inode to be locked and
- * joined to the transaction supplied. Relies on the transaction subsystem to
- * track dirty state and update/writeback the inode accordingly.
- */
-void
-xfs_trans_ichgtime(
-       struct xfs_trans        *tp,
-       struct xfs_inode        *ip,
-       int                     flags)
-{
-       struct inode            *inode = VFS_I(ip);
-       struct timespec64 tv;
-
-       ASSERT(tp);
-       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-
-       tv = current_time(inode);
-
-       if (flags & XFS_ICHGTIME_MOD)
-               inode->i_mtime = tv;
-       if (flags & XFS_ICHGTIME_CHG)
-               inode->i_ctime = tv;
-}
-
-/*
- * This is called to mark the fields indicated in fieldmask as needing
- * to be logged when the transaction is committed.  The inode must
- * already be associated with the given transaction.
- *
- * The values for fieldmask are defined in xfs_inode_item.h.  We always
- * log all of the core inode if any of it has changed, and we always log
- * all of the inline data/extents/b-tree root if any of them has changed.
- */
-void
-xfs_trans_log_inode(
-       xfs_trans_t     *tp,
-       xfs_inode_t     *ip,
-       uint            flags)
-{
-       struct inode    *inode = VFS_I(ip);
-
-       ASSERT(ip->i_itemp != NULL);
-       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-
-       /*
-        * Don't bother with i_lock for the I_DIRTY_TIME check here, as races
-        * don't matter - we either will need an extra transaction in 24 hours
-        * to log the timestamps, or will clear already cleared fields in the
-        * worst case.
-        */
-       if (inode->i_state & (I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED)) {
-               spin_lock(&inode->i_lock);
-               inode->i_state &= ~(I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED);
-               spin_unlock(&inode->i_lock);
-       }
-
-       /*
-        * Record the specific change for fdatasync optimisation. This
-        * allows fdatasync to skip log forces for inodes that are only
-        * timestamp dirty. We do this before the change count so that
-        * the core being logged in this case does not impact on fdatasync
-        * behaviour.
-        */
-       ip->i_itemp->ili_fsync_fields |= flags;
-
-       /*
-        * First time we log the inode in a transaction, bump the inode change
-        * counter if it is configured for this to occur. While we have the
-        * inode locked exclusively for metadata modification, we can usually
-        * avoid setting XFS_ILOG_CORE if no one has queried the value since
-        * the last time it was incremented. If we have XFS_ILOG_CORE already
-        * set however, then go ahead and bump the i_version counter
-        * unconditionally.
-        */
-       if (!test_and_set_bit(XFS_LI_DIRTY, &ip->i_itemp->ili_item.li_flags) &&
-           IS_I_VERSION(VFS_I(ip))) {
-               if (inode_maybe_inc_iversion(VFS_I(ip), flags & XFS_ILOG_CORE))
-                       flags |= XFS_ILOG_CORE;
-       }
-
-       tp->t_flags |= XFS_TRANS_DIRTY;
-
-       /*
-        * Always OR in the bits from the ili_last_fields field.
-        * This is to coordinate with the xfs_iflush() and xfs_iflush_done()
-        * routines in the eventual clearing of the ili_fields bits.
-        * See the big comment in xfs_iflush() for an explanation of
-        * this coordination mechanism.
-        */
-       flags |= ip->i_itemp->ili_last_fields;
-       ip->i_itemp->ili_fields |= flags;
-}
-
-int
-xfs_trans_roll_inode(
-       struct xfs_trans        **tpp,
-       struct xfs_inode        *ip)
-{
-       int                     error;
-
-       xfs_trans_log_inode(*tpp, ip, XFS_ILOG_CORE);
-       error = xfs_trans_roll(tpp);
-       if (!error)
-               xfs_trans_ijoin(*tpp, ip, 0);
-       return error;
-}
index 7e9f1ac..c38f0d4 100644 (file)
@@ -31,7 +31,7 @@ header-test-                  += acpi/platform/acintel.h
 header-test-                   += acpi/platform/aclinux.h
 header-test-                   += acpi/platform/aclinuxex.h
 header-test-                   += acpi/processor.h
-header-test-                   += clocksource/hyperv_timer.h
+header-test-$(CONFIG_X86)      += clocksource/hyperv_timer.h
 header-test-                   += clocksource/timer-sp804.h
 header-test-                   += crypto/cast_common.h
 header-test-                   += crypto/internal/cryptouser.h
@@ -246,6 +246,7 @@ header-test-                        += linux/intel-pti.h
 header-test-                   += linux/intel-svm.h
 header-test-                   += linux/interconnect-provider.h
 header-test-                   += linux/ioc3.h
+header-test-$(CONFIG_BLOCK)    += linux/iomap.h
 header-test-                   += linux/ipack.h
 header-test-                   += linux/irq_cpustat.h
 header-test-                   += linux/irq_poll.h
@@ -454,9 +455,6 @@ header-test-                        += linux/phy/omap_control_phy.h
 header-test-                   += linux/phy/tegra/xusb.h
 header-test-                   += linux/phy/ulpi_phy.h
 header-test-                   += linux/phy_fixed.h
-header-test-                   += linux/pinctrl/pinconf-generic.h
-header-test-                   += linux/pinctrl/pinconf.h
-header-test-                   += linux/pinctrl/pinctrl.h
 header-test-                   += linux/pipe_fs_i.h
 header-test-                   += linux/pktcdvd.h
 header-test-                   += linux/pl320-ipc.h
@@ -905,10 +903,11 @@ header-test-                      += net/netfilter/nf_nat_redirect.h
 header-test-                   += net/netfilter/nf_queue.h
 header-test-                   += net/netfilter/nf_reject.h
 header-test-                   += net/netfilter/nf_synproxy.h
-header-test-                   += net/netfilter/nf_tables.h
-header-test-                   += net/netfilter/nf_tables_core.h
-header-test-                   += net/netfilter/nf_tables_ipv4.h
+header-test-$(CONFIG_NF_TABLES)        += net/netfilter/nf_tables.h
+header-test-$(CONFIG_NF_TABLES)        += net/netfilter/nf_tables_core.h
+header-test-$(CONFIG_NF_TABLES)        += net/netfilter/nf_tables_ipv4.h
 header-test-                   += net/netfilter/nf_tables_ipv6.h
+header-test-$(CONFIG_NF_TABLES)        += net/netfilter/nf_tables_offload.h
 header-test-                   += net/netfilter/nft_fib.h
 header-test-                   += net/netfilter/nft_meta.h
 header-test-                   += net/netfilter/nft_reject.h
@@ -949,7 +948,6 @@ header-test-                        += pcmcia/ds.h
 header-test-                   += rdma/ib.h
 header-test-                   += rdma/iw_portmap.h
 header-test-                   += rdma/opa_port_info.h
-header-test-                   += rdma/rdma_counter.h
 header-test-                   += rdma/rdmavt_cq.h
 header-test-                   += rdma/restrack.h
 header-test-                   += rdma/signature.h
index 0e9bd9c..aa6c093 100644 (file)
@@ -104,8 +104,10 @@ extern void warn_slowpath_null(const char *file, const int line);
        warn_slowpath_fmt_taint(__FILE__, __LINE__, taint, arg)
 #else
 extern __printf(1, 2) void __warn_printk(const char *fmt, ...);
-#define __WARN()               __WARN_TAINT(TAINT_WARN)
-#define __WARN_printf(arg...)  do { __warn_printk(arg); __WARN(); } while (0)
+#define __WARN() do { \
+       printk(KERN_WARNING CUT_HERE); __WARN_TAINT(TAINT_WARN); \
+} while (0)
+#define __WARN_printf(arg...)  __WARN_printf_taint(TAINT_WARN, arg)
 #define __WARN_printf_taint(taint, arg...)                             \
        do { __warn_printk(arg); __WARN_TAINT(taint); } while (0)
 #endif
index 0dd47a6..a950a22 100644 (file)
@@ -5,24 +5,70 @@
 /* Keep includes the same across arches.  */
 #include <linux/mm.h>
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
+
 /*
  * The cache doesn't need to be flushed when TLB entries change when
  * the cache is mapped to physical memory, not virtual memory
  */
-#define flush_cache_all()                      do { } while (0)
-#define flush_cache_mm(mm)                     do { } while (0)
-#define flush_cache_dup_mm(mm)                 do { } while (0)
-#define flush_cache_range(vma, start, end)     do { } while (0)
-#define flush_cache_page(vma, vmaddr, pfn)     do { } while (0)
-#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
-#define flush_dcache_page(page)                        do { } while (0)
-#define flush_dcache_mmap_lock(mapping)                do { } while (0)
-#define flush_dcache_mmap_unlock(mapping)      do { } while (0)
-#define flush_icache_range(start, end)         do { } while (0)
-#define flush_icache_page(vma,pg)              do { } while (0)
-#define flush_icache_user_range(vma,pg,adr,len)        do { } while (0)
-#define flush_cache_vmap(start, end)           do { } while (0)
-#define flush_cache_vunmap(start, end)         do { } while (0)
+static inline void flush_cache_all(void)
+{
+}
+
+static inline void flush_cache_mm(struct mm_struct *mm)
+{
+}
+
+static inline void flush_cache_dup_mm(struct mm_struct *mm)
+{
+}
+
+static inline void flush_cache_range(struct vm_area_struct *vma,
+                                    unsigned long start,
+                                    unsigned long end)
+{
+}
+
+static inline void flush_cache_page(struct vm_area_struct *vma,
+                                   unsigned long vmaddr,
+                                   unsigned long pfn)
+{
+}
+
+static inline void flush_dcache_page(struct page *page)
+{
+}
+
+static inline void flush_dcache_mmap_lock(struct address_space *mapping)
+{
+}
+
+static inline void flush_dcache_mmap_unlock(struct address_space *mapping)
+{
+}
+
+static inline void flush_icache_range(unsigned long start, unsigned long end)
+{
+}
+
+static inline void flush_icache_page(struct vm_area_struct *vma,
+                                    struct page *page)
+{
+}
+
+static inline void flush_icache_user_range(struct vm_area_struct *vma,
+                                          struct page *page,
+                                          unsigned long addr, int len)
+{
+}
+
+static inline void flush_cache_vmap(unsigned long start, unsigned long end)
+{
+}
+
+static inline void flush_cache_vunmap(unsigned long start, unsigned long end)
+{
+}
 
 #define copy_to_user_page(vma, page, vaddr, dst, src, len) \
        do { \
index ca42182..cd28f63 100644 (file)
 #define ACPI_PROBE_TABLE(name)
 #endif
 
+#ifdef CONFIG_THERMAL
+#define THERMAL_TABLE(name)                                            \
+       . = ALIGN(8);                                                   \
+       __##name##_thermal_table = .;                                   \
+       KEEP(*(__##name##_thermal_table))                               \
+       __##name##_thermal_table_end = .;
+#else
+#define THERMAL_TABLE(name)
+#endif
+
 #define KERNEL_DTB()                                                   \
        STRUCT_ALIGN();                                                 \
        __dtb_start = .;                                                \
        IRQCHIP_OF_MATCH_TABLE()                                        \
        ACPI_PROBE_TABLE(irqchip)                                       \
        ACPI_PROBE_TABLE(timer)                                         \
+       THERMAL_TABLE(governor)                                         \
        EARLYCON_TABLE()                                                \
        LSM_TABLE()
 
index 083f167..e946e20 100644 (file)
@@ -537,7 +537,7 @@ void drm_connector_list_update(struct drm_connector *connector);
 /* parsing cmdline modes */
 bool
 drm_mode_parse_command_line_for_connector(const char *mode_option,
-                                         struct drm_connector *connector,
+                                         const struct drm_connector *connector,
                                          struct drm_cmdline_mode *mode);
 struct drm_display_mode *
 drm_mode_create_from_cmdline_mode(struct drm_device *dev,
index a0439ce..88ec396 100644 (file)
 #define CLK_MIPI_HSI           349 /* Exynos4210 only */
 #define CLK_PIXELASYNCM0       351
 #define CLK_PIXELASYNCM1       352
+#define CLK_ASYNC_G3D          353 /* Exynos4x12 only */
 #define CLK_PWM_ISP_SCLK       379 /* Exynos4x12 only */
 #define CLK_SPI0_ISP_SCLK      380 /* Exynos4x12 only */
 #define CLK_SPI1_ISP_SCLK      381 /* Exynos4x12 only */
index 355f469..02d5ac4 100644 (file)
@@ -60,6 +60,7 @@
 #define CLK_MAU_EPLL           159
 #define CLK_SCLK_HSIC_12M      160
 #define CLK_SCLK_MPHY_IXTAL24  161
+#define CLK_SCLK_BPLL          162
 
 /* gate clocks */
 #define CLK_UART0              257
 #define CLK_ACLK432_CAM                518
 #define CLK_ACLK_FL1550_CAM    519
 #define CLK_ACLK550_CAM                520
+#define CLK_CLKM_PHY0          521
+#define CLK_CLKM_PHY1          522
+#define CLK_ACLK_PPMU_DREX0_0  523
+#define CLK_ACLK_PPMU_DREX0_1  524
+#define CLK_ACLK_PPMU_DREX1_0  525
+#define CLK_ACLK_PPMU_DREX1_1  526
+#define CLK_PCLK_PPMU_DREX0_0  527
+#define CLK_PCLK_PPMU_DREX0_1  528
+#define CLK_PCLK_PPMU_DREX1_0  529
+#define CLK_PCLK_PPMU_DREX1_1  530
 
 /* mux clocks */
 #define CLK_MOUT_HDMI          640
 #define CLK_MOUT_EPLL          657
 #define CLK_MOUT_MAU_EPLL      658
 #define CLK_MOUT_USER_MAU_EPLL 659
+#define CLK_MOUT_SCLK_SPLL     660
+#define CLK_MOUT_MX_MSPLL_CCORE_PHY    661
 
 /* divider clocks */
 #define CLK_DOUT_PIXEL         768
 #define CLK_DOUT_CCLK_DREX0    794
 #define CLK_DOUT_CLK2X_PHY0    795
 #define CLK_DOUT_PCLK_CORE_MEM 796
+#define CLK_FF_DOUT_SPLL2      797
+#define CLK_DOUT_PCLK_DREX0    798
+#define CLK_DOUT_PCLK_DREX1    799
 
 /* must be greater than maximal clock id */
-#define CLK_NR_CLKS            797
+#define CLK_NR_CLKS            800
 
 #endif /* _DT_BINDINGS_CLOCK_EXYNOS_5420_H */
index e10470e..b6b127e 100644 (file)
 #define CLKID_VDEC_1                           204
 #define CLKID_VDEC_HEVC                                207
 #define CLKID_VDEC_HEVCF                       210
+#define CLKID_TS                               212
 
 #endif /* __G12A_CLKC_H */
index 1b4353e..07e6c68 100644 (file)
 
 #define IMX8MM_CLK_NAND_USDHC_BUS_RAWNAND_CLK  222
 
-#define IMX8MM_CLK_END                         223
+#define IMX8MM_CLK_GPIO1_ROOT                  223
+#define IMX8MM_CLK_GPIO2_ROOT                  224
+#define IMX8MM_CLK_GPIO3_ROOT                  225
+#define IMX8MM_CLK_GPIO4_ROOT                  226
+#define IMX8MM_CLK_GPIO5_ROOT                  227
+
+#define IMX8MM_CLK_SNVS_ROOT                   228
+#define IMX8MM_CLK_GIC                         229
+
+#define IMX8MM_CLK_END                         230
 
 #endif
index 6677e92..6546367 100644 (file)
 #define IMX8MQ_CLK_GPIO4_ROOT                  262
 #define IMX8MQ_CLK_GPIO5_ROOT                  263
 
-#define IMX8MQ_CLK_END                         264
+#define IMX8MQ_CLK_SNVS_ROOT                   264
+#define IMX8MQ_CLK_GIC                         265
+
+#define IMX8MQ_CLK_END                         266
 #endif /* __DT_BINDINGS_CLOCK_IMX8MQ_H */
index 4755653..68862aa 100644 (file)
 #define CLKID_VDEC_HCODEC      199
 #define CLKID_VDEC_2           202
 #define CLKID_VDEC_HEVC                206
+#define CLKID_CTS_AMCLK                209
+#define CLKID_CTS_MCLK_I958    212
+#define CLKID_CTS_I958         213
 
 #endif /* __MESON8B_CLKC_H */
index 9cfca53..816447b 100644 (file)
 #define CLK_TOP_MSDC2_INFRA            176
 #define CLK_TOP_NR_CLK                 177
 
+/* AUDSYS */
+
+#define CLK_AUD_AFE                    0
+#define CLK_AUD_I2S                    1
+#define CLK_AUD_22M                    2
+#define CLK_AUD_24M                    3
+#define CLK_AUD_INTDIR                 4
+#define CLK_AUD_APLL2_TUNER            5
+#define CLK_AUD_APLL_TUNER             6
+#define CLK_AUD_HDMI                   7
+#define CLK_AUD_SPDF                   8
+#define CLK_AUD_ADC                    9
+#define CLK_AUD_DAC                    10
+#define CLK_AUD_DAC_PREDIS             11
+#define CLK_AUD_TML                    12
+#define CLK_AUD_NR_CLK                 13
+
 #endif /* _DT_BINDINGS_CLK_MT8516_H */
index 454b3f4..2cd62c9 100644 (file)
 #define GCC_PCIEPHY_0_PHY_BCR                          12
 #define GCC_EMAC_BCR                                   13
 #define GCC_CDSP_RESTART                               14
+#define GCC_PCIE_0_AXI_MASTER_STICKY_ARES              15
+#define GCC_PCIE_0_AHB_ARES                            16
+#define GCC_PCIE_0_AXI_SLAVE_ARES                      17
+#define GCC_PCIE_0_AXI_MASTER_ARES                     18
+#define GCC_PCIE_0_CORE_STICKY_ARES                    19
+#define GCC_PCIE_0_SLEEP_ARES                          20
+#define GCC_PCIE_0_PIPE_ARES                           21
 
 #endif
diff --git a/include/dt-bindings/clock/qcom,gpucc-msm8998.h b/include/dt-bindings/clock/qcom,gpucc-msm8998.h
new file mode 100644 (file)
index 0000000..2623570
--- /dev/null
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019, Jeffrey Hugo
+ */
+
+#ifndef _DT_BINDINGS_CLK_MSM_GPUCC_8998_H
+#define _DT_BINDINGS_CLK_MSM_GPUCC_8998_H
+
+#define GPUPLL0                                                0
+#define GPUPLL0_OUT_EVEN                               1
+#define RBCPR_CLK_SRC                                  2
+#define GFX3D_CLK_SRC                                  3
+#define RBBMTIMER_CLK_SRC                              4
+#define GFX3D_ISENSE_CLK_SRC                           5
+#define RBCPR_CLK                                      6
+#define GFX3D_CLK                                      7
+#define RBBMTIMER_CLK                                  8
+#define GFX3D_ISENSE_CLK                               9
+#define GPUCC_CXO_CLK                                  10
+
+#define GPU_CX_BCR                                     0
+#define RBCPR_BCR                                      1
+#define GPU_GX_BCR                                     2
+#define GPU_ISENSE_BCR                                 3
+
+#define GPU_CX_GDSC                                    1
+#define GPU_GX_GDSC                                    2
+
+#endif
index 3b245e3..de550ea 100644 (file)
@@ -64,6 +64,7 @@
 #define SCLK_WIFI              141
 #define SCLK_OTGPHY0           142
 #define SCLK_OTGPHY1           143
+#define SCLK_HDMI_PHY          144
 
 /* dclk gates */
 #define DCLK_VOP               190
index afb8113..555b4ff 100644 (file)
 #define PCLK_DCF               233
 #define PCLK_SARADC            234
 #define PCLK_ACODECPHY         235
+#define PCLK_WDT               236
 
 /* hclk gates */
 #define HCLK_PERI              308
index 0ac1c90..08b98e2 100644 (file)
@@ -79,6 +79,8 @@
 #define STRATIX10_USB_CLK              59
 #define STRATIX10_SPI_M_CLK            60
 #define STRATIX10_NAND_CLK             61
-#define STRATIX10_NUM_CLKS             62
+#define STRATIX10_NAND_X_CLK           62
+#define STRATIX10_NAND_ECC_CLK         63
+#define STRATIX10_NUM_CLKS             64
 
 #endif /* __STRATIX10_CLOCK_H */
index cabc571..0782b05 100644 (file)
 #define TEGRA186_MAIN_GPIO(port, offset) \
        ((TEGRA186_MAIN_GPIO_PORT_##port * 8) + offset)
 
-/* need to keep these for backwards-compatibility */
-#define TEGRA_MAIN_GPIO_PORT_A 0
-#define TEGRA_MAIN_GPIO_PORT_B 1
-#define TEGRA_MAIN_GPIO_PORT_C 2
-#define TEGRA_MAIN_GPIO_PORT_D 3
-#define TEGRA_MAIN_GPIO_PORT_E 4
-#define TEGRA_MAIN_GPIO_PORT_F 5
-#define TEGRA_MAIN_GPIO_PORT_G 6
-#define TEGRA_MAIN_GPIO_PORT_H 7
-#define TEGRA_MAIN_GPIO_PORT_I 8
-#define TEGRA_MAIN_GPIO_PORT_J 9
-#define TEGRA_MAIN_GPIO_PORT_K 10
-#define TEGRA_MAIN_GPIO_PORT_L 11
-#define TEGRA_MAIN_GPIO_PORT_M 12
-#define TEGRA_MAIN_GPIO_PORT_N 13
-#define TEGRA_MAIN_GPIO_PORT_O 14
-#define TEGRA_MAIN_GPIO_PORT_P 15
-#define TEGRA_MAIN_GPIO_PORT_Q 16
-#define TEGRA_MAIN_GPIO_PORT_R 17
-#define TEGRA_MAIN_GPIO_PORT_T 18
-#define TEGRA_MAIN_GPIO_PORT_X 19
-#define TEGRA_MAIN_GPIO_PORT_Y 20
-#define TEGRA_MAIN_GPIO_PORT_BB 21
-#define TEGRA_MAIN_GPIO_PORT_CC 22
-
-#define TEGRA_MAIN_GPIO(port, offset) \
-       ((TEGRA_MAIN_GPIO_PORT_##port * 8) + offset)
-
 /* GPIOs implemented by AON GPIO controller */
 #define TEGRA186_AON_GPIO_PORT_S 0
 #define TEGRA186_AON_GPIO_PORT_U 1
 #define TEGRA186_AON_GPIO(port, offset) \
        ((TEGRA186_AON_GPIO_PORT_##port * 8) + offset)
 
-/* need to keep these for backwards-compatibility */
-#define TEGRA_AON_GPIO_PORT_S 0
-#define TEGRA_AON_GPIO_PORT_U 1
-#define TEGRA_AON_GPIO_PORT_V 2
-#define TEGRA_AON_GPIO_PORT_W 3
-#define TEGRA_AON_GPIO_PORT_Z 4
-#define TEGRA_AON_GPIO_PORT_AA 5
-#define TEGRA_AON_GPIO_PORT_EE 6
-#define TEGRA_AON_GPIO_PORT_FF 7
-
-#define TEGRA_AON_GPIO(port, offset) \
-       ((TEGRA_AON_GPIO_PORT_##port * 8) + offset)
-
 #endif
diff --git a/include/dt-bindings/power/qcom-aoss-qmp.h b/include/dt-bindings/power/qcom-aoss-qmp.h
new file mode 100644 (file)
index 0000000..ec336d3
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018, Linaro Ltd. */
+
+#ifndef __DT_BINDINGS_POWER_QCOM_AOSS_QMP_H
+#define __DT_BINDINGS_POWER_QCOM_AOSS_QMP_H
+
+#define AOSS_QMP_LS_CDSP               0
+#define AOSS_QMP_LS_LPASS      1
+#define AOSS_QMP_LS_MODEM      2
+#define AOSS_QMP_LS_SLPI               3
+#define AOSS_QMP_LS_SPSS               4
+#define AOSS_QMP_LS_VENUS      5
+
+#endif
index 87d9c66..93e36d0 100644 (file)
 #define MSM8996_VDDSSCX                5
 #define MSM8996_VDDSSCX_VFC    6
 
+/* MSM8998 Power Domain Indexes */
+#define MSM8998_VDDCX          0
+#define MSM8998_VDDCX_AO       1
+#define MSM8998_VDDCX_VFL      2
+#define MSM8998_VDDMX          3
+#define MSM8998_VDDMX_AO       4
+#define MSM8998_VDDMX_VFL      5
+#define MSM8998_SSCCX          6
+#define MSM8998_SSCCX_VFL      7
+#define MSM8998_SSCMX          8
+#define MSM8998_SSCMX_VFL      9
+
+/* QCS404 Power Domains */
+#define QCS404_VDDMX           0
+#define QCS404_VDDMX_AO                1
+#define QCS404_VDDMX_VFL       2
+#define QCS404_LPICX           3
+#define QCS404_LPICX_VFL       4
+#define QCS404_LPIMX           5
+#define QCS404_LPIMX_VFL       6
+
+/* RPM SMD Power Domain performance levels */
+#define RPM_SMD_LEVEL_RETENTION       16
+#define RPM_SMD_LEVEL_RETENTION_PLUS  32
+#define RPM_SMD_LEVEL_MIN_SVS         48
+#define RPM_SMD_LEVEL_LOW_SVS         64
+#define RPM_SMD_LEVEL_SVS             128
+#define RPM_SMD_LEVEL_SVS_PLUS        192
+#define RPM_SMD_LEVEL_NOM             256
+#define RPM_SMD_LEVEL_NOM_PLUS        320
+#define RPM_SMD_LEVEL_TURBO           384
+#define RPM_SMD_LEVEL_TURBO_NO_CPR    416
+#define RPM_SMD_LEVEL_BINNING         512
+
 #endif
diff --git a/include/dt-bindings/reset/bitmain,bm1880-reset.h b/include/dt-bindings/reset/bitmain,bm1880-reset.h
new file mode 100644 (file)
index 0000000..4c0de52
--- /dev/null
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2018 Bitmain Ltd.
+ * Copyright (c) 2019 Linaro Ltd.
+ */
+
+#ifndef _DT_BINDINGS_BM1880_RESET_H
+#define _DT_BINDINGS_BM1880_RESET_H
+
+#define BM1880_RST_MAIN_AP             0
+#define BM1880_RST_SECOND_AP           1
+#define BM1880_RST_DDR                 2
+#define BM1880_RST_VIDEO               3
+#define BM1880_RST_JPEG                        4
+#define BM1880_RST_VPP                 5
+#define BM1880_RST_GDMA                        6
+#define BM1880_RST_AXI_SRAM            7
+#define BM1880_RST_TPU                 8
+#define BM1880_RST_USB                 9
+#define BM1880_RST_ETH0                        10
+#define BM1880_RST_ETH1                        11
+#define BM1880_RST_NAND                        12
+#define BM1880_RST_EMMC                        13
+#define BM1880_RST_SD                  14
+#define BM1880_RST_SDMA                        15
+#define BM1880_RST_I2S0                        16
+#define BM1880_RST_I2S1                        17
+#define BM1880_RST_UART0_1_CLK         18
+#define BM1880_RST_UART0_1_ACLK                19
+#define BM1880_RST_UART2_3_CLK         20
+#define BM1880_RST_UART2_3_ACLK                21
+#define BM1880_RST_MINER               22
+#define BM1880_RST_I2C0                        23
+#define BM1880_RST_I2C1                        24
+#define BM1880_RST_I2C2                        25
+#define BM1880_RST_I2C3                        26
+#define BM1880_RST_I2C4                        27
+#define BM1880_RST_PWM0                        28
+#define BM1880_RST_PWM1                        29
+#define BM1880_RST_PWM2                        30
+#define BM1880_RST_PWM3                        31
+#define BM1880_RST_SPI                 32
+#define BM1880_RST_GPIO0               33
+#define BM1880_RST_GPIO1               34
+#define BM1880_RST_GPIO2               35
+#define BM1880_RST_EFUSE               36
+#define BM1880_RST_WDT                 37
+#define BM1880_RST_AHB_ROM             38
+#define BM1880_RST_SPIC                        39
+
+#endif /* _DT_BINDINGS_BM1880_RESET_H */
index a95cce5..9426b9a 100644 (file)
@@ -324,7 +324,10 @@ struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
 #ifdef CONFIG_X86_IO_APIC
 extern int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity);
 #else
-#define acpi_get_override_irq(gsi, trigger, polarity) (-1)
+static inline int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity)
+{
+       return -1;
+}
 #endif
 /*
  * This function undoes the effect of one call to acpi_register_gsi().
index 2b7b532..669d694 100644 (file)
@@ -1,13 +1,15 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 #ifndef __LINUX_BITS_H
 #define __LINUX_BITS_H
+
+#include <linux/const.h>
 #include <asm/bitsperlong.h>
 
-#define BIT(nr)                        (1UL << (nr))
-#define BIT_ULL(nr)            (1ULL << (nr))
-#define BIT_MASK(nr)           (1UL << ((nr) % BITS_PER_LONG))
+#define BIT(nr)                        (UL(1) << (nr))
+#define BIT_ULL(nr)            (ULL(1) << (nr))
+#define BIT_MASK(nr)           (UL(1) << ((nr) % BITS_PER_LONG))
 #define BIT_WORD(nr)           ((nr) / BITS_PER_LONG)
-#define BIT_ULL_MASK(nr)       (1ULL << ((nr) % BITS_PER_LONG_LONG))
+#define BIT_ULL_MASK(nr)       (ULL(1) << ((nr) % BITS_PER_LONG_LONG))
 #define BIT_ULL_WORD(nr)       ((nr) / BITS_PER_LONG_LONG)
 #define BITS_PER_BYTE          8
 
  * GENMASK_ULL(39, 21) gives us the 64bit vector 0x000000ffffe00000.
  */
 #define GENMASK(h, l) \
-       (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
+       (((~UL(0)) - (UL(1) << (l)) + 1) & \
+        (~UL(0) >> (BITS_PER_LONG - 1 - (h))))
 
 #define GENMASK_ULL(h, l) \
-       (((~0ULL) - (1ULL << (l)) + 1) & \
-        (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h))))
+       (((~ULL(0)) - (ULL(1) << (l)) + 1) & \
+        (~ULL(0) >> (BITS_PER_LONG_LONG - 1 - (h))))
 
 #endif /* __LINUX_BITS_H */
index 65a38c4..39e6f4c 100644 (file)
@@ -211,6 +211,7 @@ DEFINE_CEPH_FEATURE_DEPRECATED(63, 1, RESERVED_BROKEN, LUMINOUS) // client-facin
         CEPH_FEATURE_MON_STATEFUL_SUB |        \
         CEPH_FEATURE_CRUSH_TUNABLES5 |         \
         CEPH_FEATURE_NEW_OSDOPREPLY_ENCODING | \
+        CEPH_FEATURE_MSG_ADDR2 |               \
         CEPH_FEATURE_CEPHX_V2)
 
 #define CEPH_FEATURES_REQUIRED_DEFAULT 0
index 3ac0fea..cb21c5c 100644 (file)
@@ -682,7 +682,7 @@ extern const char *ceph_cap_op_name(int op);
 /* flags field in client cap messages (version >= 10) */
 #define CEPH_CLIENT_CAPS_SYNC                  (1<<0)
 #define CEPH_CLIENT_CAPS_NO_CAPSNAP            (1<<1)
-#define CEPH_CLIENT_CAPS_PENDING_CAPSNAP       (1<<2);
+#define CEPH_CLIENT_CAPS_PENDING_CAPSNAP       (1<<2)
 
 /*
  * caps message, used for capability callbacks, acks, requests, etc.
index bea6c77..17bc758 100644 (file)
@@ -52,4 +52,7 @@ int ceph_cls_lock_info(struct ceph_osd_client *osdc,
                       char *lock_name, u8 *type, char **tag,
                       struct ceph_locker **lockers, u32 *num_lockers);
 
+int ceph_cls_assert_locked(struct ceph_osd_request *req, int which,
+                          char *lock_name, u8 type, char *cookie, char *tag);
+
 #endif
index a6c2a48..450384f 100644 (file)
@@ -218,18 +218,27 @@ static inline void ceph_encode_timespec64(struct ceph_timespec *tv,
 /*
  * sockaddr_storage <-> ceph_sockaddr
  */
-static inline void ceph_encode_addr(struct ceph_entity_addr *a)
+#define CEPH_ENTITY_ADDR_TYPE_NONE     0
+#define CEPH_ENTITY_ADDR_TYPE_LEGACY   __cpu_to_le32(1)
+
+static inline void ceph_encode_banner_addr(struct ceph_entity_addr *a)
 {
        __be16 ss_family = htons(a->in_addr.ss_family);
        a->in_addr.ss_family = *(__u16 *)&ss_family;
+
+       /* Banner addresses require TYPE_NONE */
+       a->type = CEPH_ENTITY_ADDR_TYPE_NONE;
 }
-static inline void ceph_decode_addr(struct ceph_entity_addr *a)
+static inline void ceph_decode_banner_addr(struct ceph_entity_addr *a)
 {
        __be16 ss_family = *(__be16 *)&a->in_addr.ss_family;
        a->in_addr.ss_family = ntohs(ss_family);
        WARN_ON(a->in_addr.ss_family == 512);
+       a->type = CEPH_ENTITY_ADDR_TYPE_LEGACY;
 }
 
+extern int ceph_decode_entity_addr(void **p, void *end,
+                                  struct ceph_entity_addr *addr);
 /*
  * encoders
  */
index 337d504..82156da 100644 (file)
@@ -84,11 +84,13 @@ struct ceph_options {
 #define CEPH_MSG_MAX_MIDDLE_LEN        (16*1024*1024)
 
 /*
- * Handle the largest possible rbd object in one message.
+ * The largest possible rbd data object is 32M.
+ * The largest possible rbd object map object is 64M.
+ *
  * There is no limit on the size of cephfs objects, but it has to obey
  * rsize and wsize mount options anyway.
  */
-#define CEPH_MSG_MAX_DATA_LEN  (32*1024*1024)
+#define CEPH_MSG_MAX_DATA_LEN  (64*1024*1024)
 
 #define CEPH_AUTH_NAME_DEFAULT   "guest"
 
@@ -299,10 +301,6 @@ int ceph_wait_for_latest_osdmap(struct ceph_client *client,
 
 /* pagevec.c */
 extern void ceph_release_page_vector(struct page **pages, int num_pages);
-
-extern struct page **ceph_get_direct_page_vector(const void __user *data,
-                                                int num_pages,
-                                                bool write_page);
 extern void ceph_put_page_vector(struct page **pages, int num_pages,
                                 bool dirty);
 extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags);
index 3a4688a..b4d134d 100644 (file)
@@ -104,7 +104,6 @@ struct ceph_mon_client {
 #endif
 };
 
-extern struct ceph_monmap *ceph_monmap_decode(void *p, void *end);
 extern int ceph_monmap_contains(struct ceph_monmap *m,
                                struct ceph_entity_addr *addr);
 
index 2294f96..ad7fe5d 100644 (file)
@@ -198,9 +198,9 @@ struct ceph_osd_request {
        bool              r_mempool;
        struct completion r_completion;       /* private to osd_client.c */
        ceph_osdc_callback_t r_callback;
-       struct list_head  r_unsafe_item;
 
        struct inode *r_inode;                /* for use by callbacks */
+       struct list_head r_private_item;      /* ditto */
        void *r_priv;                         /* ditto */
 
        /* set by submitter */
@@ -389,6 +389,14 @@ extern void ceph_osdc_handle_map(struct ceph_osd_client *osdc,
 void ceph_osdc_update_epoch_barrier(struct ceph_osd_client *osdc, u32 eb);
 void ceph_osdc_abort_requests(struct ceph_osd_client *osdc, int err);
 
+#define osd_req_op_data(oreq, whch, typ, fld)                          \
+({                                                                     \
+       struct ceph_osd_request *__oreq = (oreq);                       \
+       unsigned int __whch = (whch);                                   \
+       BUG_ON(__whch >= __oreq->r_num_ops);                            \
+       &__oreq->r_ops[__whch].typ.fld;                                 \
+})
+
 extern void osd_req_op_init(struct ceph_osd_request *osd_req,
                            unsigned int which, u16 opcode, u32 flags);
 
@@ -497,7 +505,7 @@ int ceph_osdc_call(struct ceph_osd_client *osdc,
                   const char *class, const char *method,
                   unsigned int flags,
                   struct page *req_page, size_t req_len,
-                  struct page *resp_page, size_t *resp_len);
+                  struct page **resp_pages, size_t *resp_len);
 
 extern int ceph_osdc_readpages(struct ceph_osd_client *osdc,
                               struct ceph_vino vino,
index cbd0d24..3486636 100644 (file)
@@ -66,4 +66,6 @@ int ceph_extent_to_file(struct ceph_file_layout *l,
                        struct ceph_file_extent **file_extents,
                        u32 *num_file_extents);
 
+u64 ceph_get_num_objects(struct ceph_file_layout *l, u64 size);
+
 #endif
index c531193..430e219 100644 (file)
@@ -624,7 +624,7 @@ struct cftype {
 
 /*
  * Control Group subsystem type.
- * See Documentation/cgroup-v1/cgroups.rst for details
+ * See Documentation/admin-guide/cgroup-v1/cgroups.rst for details
  */
 struct cgroup_subsys {
        struct cgroup_subsys_state *(*css_alloc)(struct cgroup_subsys_state *parent_css);
index bb6118f..2ae7604 100644 (file)
@@ -9,8 +9,6 @@
 #include <linux/of.h>
 #include <linux/of_clk.h>
 
-#ifdef CONFIG_COMMON_CLK
-
 /*
  * flags used across common struct clk.  these flags should only affect the
  * top-level framework.  custom flags for dealing with hardware specifics
@@ -807,7 +805,14 @@ void devm_clk_hw_unregister(struct device *dev, struct clk_hw *hw);
 /* helper functions */
 const char *__clk_get_name(const struct clk *clk);
 const char *clk_hw_get_name(const struct clk_hw *hw);
+#ifdef CONFIG_COMMON_CLK
 struct clk_hw *__clk_get_hw(struct clk *clk);
+#else
+static inline struct clk_hw *__clk_get_hw(struct clk *clk)
+{
+       return (struct clk_hw *)clk;
+}
+#endif
 unsigned int clk_hw_get_num_parents(const struct clk_hw *hw);
 struct clk_hw *clk_hw_get_parent(const struct clk_hw *hw);
 struct clk_hw *clk_hw_get_parent_by_index(const struct clk_hw *hw,
@@ -867,8 +872,6 @@ static inline long divider_ro_round_rate(struct clk_hw *hw, unsigned long rate,
  */
 unsigned long clk_hw_round_rate(struct clk_hw *hw, unsigned long rate);
 
-struct of_device_id;
-
 struct clk_onecell_data {
        struct clk **clks;
        unsigned int clk_num;
@@ -879,8 +882,6 @@ struct clk_hw_onecell_data {
        struct clk_hw *hws[];
 };
 
-extern struct of_device_id __clk_of_table;
-
 #define CLK_OF_DECLARE(name, compat, fn) OF_DECLARE_1(clk, name, compat, fn)
 
 /*
@@ -904,6 +905,40 @@ extern struct of_device_id __clk_of_table;
                .ops            = _ops,                         \
        })
 
+#define CLK_HW_INIT_HW(_name, _parent, _ops, _flags)                   \
+       (&(struct clk_init_data) {                                      \
+               .flags          = _flags,                               \
+               .name           = _name,                                \
+               .parent_hws     = (const struct clk_hw*[]) { _parent }, \
+               .num_parents    = 1,                                    \
+               .ops            = _ops,                                 \
+       })
+
+/*
+ * This macro is intended for drivers to be able to share the otherwise
+ * individual struct clk_hw[] compound literals created by the compiler
+ * when using CLK_HW_INIT_HW. It does NOT support multiple parents.
+ */
+#define CLK_HW_INIT_HWS(_name, _parent, _ops, _flags)                  \
+       (&(struct clk_init_data) {                                      \
+               .flags          = _flags,                               \
+               .name           = _name,                                \
+               .parent_hws     = _parent,                              \
+               .num_parents    = 1,                                    \
+               .ops            = _ops,                                 \
+       })
+
+#define CLK_HW_INIT_FW_NAME(_name, _parent, _ops, _flags)              \
+       (&(struct clk_init_data) {                                      \
+               .flags          = _flags,                               \
+               .name           = _name,                                \
+               .parent_data    = (const struct clk_parent_data[]) {    \
+                                       { .fw_name = _parent },         \
+                                 },                                    \
+               .num_parents    = 1,                                    \
+               .ops            = _ops,                                 \
+       })
+
 #define CLK_HW_INIT_PARENTS(_name, _parents, _ops, _flags)     \
        (&(struct clk_init_data) {                              \
                .flags          = _flags,                       \
@@ -913,6 +948,24 @@ extern struct of_device_id __clk_of_table;
                .ops            = _ops,                         \
        })
 
+#define CLK_HW_INIT_PARENTS_HW(_name, _parents, _ops, _flags)  \
+       (&(struct clk_init_data) {                              \
+               .flags          = _flags,                       \
+               .name           = _name,                        \
+               .parent_hws     = _parents,                     \
+               .num_parents    = ARRAY_SIZE(_parents),         \
+               .ops            = _ops,                         \
+       })
+
+#define CLK_HW_INIT_PARENTS_DATA(_name, _parents, _ops, _flags)        \
+       (&(struct clk_init_data) {                              \
+               .flags          = _flags,                       \
+               .name           = _name,                        \
+               .parent_data    = _parents,                     \
+               .num_parents    = ARRAY_SIZE(_parents),         \
+               .ops            = _ops,                         \
+       })
+
 #define CLK_HW_INIT_NO_PARENT(_name, _ops, _flags)     \
        (&(struct clk_init_data) {                      \
                .flags          = _flags,               \
@@ -933,6 +986,43 @@ extern struct of_device_id __clk_of_table;
                                              _flags),                  \
        }
 
+#define CLK_FIXED_FACTOR_HW(_struct, _name, _parent,                   \
+                           _div, _mult, _flags)                        \
+       struct clk_fixed_factor _struct = {                             \
+               .div            = _div,                                 \
+               .mult           = _mult,                                \
+               .hw.init        = CLK_HW_INIT_HW(_name,                 \
+                                                _parent,               \
+                                                &clk_fixed_factor_ops, \
+                                                _flags),               \
+       }
+
+/*
+ * This macro allows the driver to reuse the _parent array for multiple
+ * fixed factor clk declarations.
+ */
+#define CLK_FIXED_FACTOR_HWS(_struct, _name, _parent,                  \
+                            _div, _mult, _flags)                       \
+       struct clk_fixed_factor _struct = {                             \
+               .div            = _div,                                 \
+               .mult           = _mult,                                \
+               .hw.init        = CLK_HW_INIT_HWS(_name,                \
+                                                 _parent,              \
+                                                 &clk_fixed_factor_ops, \
+                                                 _flags),      \
+       }
+
+#define CLK_FIXED_FACTOR_FW_NAME(_struct, _name, _parent,              \
+                                _div, _mult, _flags)                   \
+       struct clk_fixed_factor _struct = {                             \
+               .div            = _div,                                 \
+               .mult           = _mult,                                \
+               .hw.init        = CLK_HW_INIT_FW_NAME(_name,            \
+                                                     _parent,          \
+                                                     &clk_fixed_factor_ops, \
+                                                     _flags),          \
+       }
+
 #ifdef CONFIG_OF
 int of_clk_add_provider(struct device_node *np,
                        struct clk *(*clk_src_get)(struct of_phandle_args *args,
@@ -1019,5 +1109,4 @@ static inline int of_clk_detect_critical(struct device_node *np, int index,
 
 void clk_gate_restore_context(struct clk_hw *hw);
 
-#endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
index c8e3325..3c096c7 100644 (file)
@@ -329,6 +329,19 @@ int __must_check clk_bulk_get(struct device *dev, int num_clks,
  */
 int __must_check clk_bulk_get_all(struct device *dev,
                                  struct clk_bulk_data **clks);
+
+/**
+ * clk_bulk_get_optional - lookup and obtain a number of references to clock producer
+ * @dev: device for clock "consumer"
+ * @num_clks: the number of clk_bulk_data
+ * @clks: the clk_bulk_data table of consumer
+ *
+ * Behaves the same as clk_bulk_get() except where there is no clock producer.
+ * In this case, instead of returning -ENOENT, the function returns 0 and
+ * NULL for a clk for which a clock producer could not be determined.
+ */
+int __must_check clk_bulk_get_optional(struct device *dev, int num_clks,
+                                      struct clk_bulk_data *clks);
 /**
  * devm_clk_bulk_get - managed get multiple clk consumers
  * @dev: device for clock "consumer"
@@ -344,6 +357,28 @@ int __must_check clk_bulk_get_all(struct device *dev,
 int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
                                   struct clk_bulk_data *clks);
 /**
+ * devm_clk_bulk_get_optional - managed get multiple optional consumer clocks
+ * @dev: device for clock "consumer"
+ * @clks: pointer to the clk_bulk_data table of consumer
+ *
+ * Behaves the same as devm_clk_bulk_get() except where there is no clock
+ * producer.  In this case, instead of returning -ENOENT, the function returns
+ * NULL for given clk. It is assumed all clocks in clk_bulk_data are optional.
+ *
+ * Returns 0 if all clocks specified in clk_bulk_data table are obtained
+ * successfully or for any clk there was no clk provider available, otherwise
+ * returns valid IS_ERR() condition containing errno.
+ * The implementation uses @dev and @clk_bulk_data.id to determine the
+ * clock consumer, and thereby the clock producer.
+ * The clock returned is stored in each @clk_bulk_data.clk field.
+ *
+ * Drivers must assume that the clock source is not enabled.
+ *
+ * clk_bulk_get should not be called from within interrupt context.
+ */
+int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks,
+                                           struct clk_bulk_data *clks);
+/**
  * devm_clk_bulk_get_all - managed get multiple clk consumers
  * @dev: device for clock "consumer"
  * @clks: pointer to the clk_bulk_data table of consumer
@@ -715,6 +750,12 @@ static inline int __must_check clk_bulk_get(struct device *dev, int num_clks,
        return 0;
 }
 
+static inline int __must_check clk_bulk_get_optional(struct device *dev,
+                               int num_clks, struct clk_bulk_data *clks)
+{
+       return 0;
+}
+
 static inline int __must_check clk_bulk_get_all(struct device *dev,
                                         struct clk_bulk_data **clks)
 {
@@ -738,6 +779,12 @@ static inline int __must_check devm_clk_bulk_get(struct device *dev, int num_clk
        return 0;
 }
 
+static inline int __must_check devm_clk_bulk_get_optional(struct device *dev,
+                               int num_clks, struct clk_bulk_data *clks)
+{
+       return 0;
+}
+
 static inline int __must_check devm_clk_bulk_get_all(struct device *dev,
                                                     struct clk_bulk_data **clks)
 {
index d30209b..0ca0c83 100644 (file)
@@ -58,8 +58,7 @@ Mellon the rights to redistribute these changes without encumbrance.
 #ifndef _CODA_HEADER_
 #define _CODA_HEADER_
 
-#if defined(__linux__)
 typedef unsigned long long u_quad_t;
-#endif
+
 #include <uapi/linux/coda.h>
 #endif 
diff --git a/include/linux/coda_psdev.h b/include/linux/coda_psdev.h
deleted file mode 100644 (file)
index 1517095..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __CODA_PSDEV_H
-#define __CODA_PSDEV_H
-
-#include <linux/backing-dev.h>
-#include <linux/mutex.h>
-#include <uapi/linux/coda_psdev.h>
-
-struct kstatfs;
-
-/* communication pending/processing queues */
-struct venus_comm {
-       u_long              vc_seq;
-       wait_queue_head_t   vc_waitq; /* Venus wait queue */
-       struct list_head    vc_pending;
-       struct list_head    vc_processing;
-       int                 vc_inuse;
-       struct super_block *vc_sb;
-       struct mutex        vc_mutex;
-};
-
-
-static inline struct venus_comm *coda_vcp(struct super_block *sb)
-{
-       return (struct venus_comm *)((sb)->s_fs_info);
-}
-
-/* upcalls */
-int venus_rootfid(struct super_block *sb, struct CodaFid *fidp);
-int venus_getattr(struct super_block *sb, struct CodaFid *fid,
-                 struct coda_vattr *attr);
-int venus_setattr(struct super_block *, struct CodaFid *, struct coda_vattr *);
-int venus_lookup(struct super_block *sb, struct CodaFid *fid, 
-                const char *name, int length, int *type, 
-                struct CodaFid *resfid);
-int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
-               kuid_t uid);
-int venus_open(struct super_block *sb, struct CodaFid *fid, int flags,
-              struct file **f);
-int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid, 
-               const char *name, int length, 
-               struct CodaFid *newfid, struct coda_vattr *attrs);
-int venus_create(struct super_block *sb, struct CodaFid *dirfid, 
-                const char *name, int length, int excl, int mode,
-                struct CodaFid *newfid, struct coda_vattr *attrs) ;
-int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid, 
-               const char *name, int length);
-int venus_remove(struct super_block *sb, struct CodaFid *dirfid, 
-                const char *name, int length);
-int venus_readlink(struct super_block *sb, struct CodaFid *fid, 
-                  char *buffer, int *length);
-int venus_rename(struct super_block *, struct CodaFid *new_fid, 
-                struct CodaFid *old_fid, size_t old_length, 
-                size_t new_length, const char *old_name, 
-                const char *new_name);
-int venus_link(struct super_block *sb, struct CodaFid *fid, 
-                 struct CodaFid *dirfid, const char *name, int len );
-int venus_symlink(struct super_block *sb, struct CodaFid *fid,
-                 const char *name, int len, const char *symname, int symlen);
-int venus_access(struct super_block *sb, struct CodaFid *fid, int mask);
-int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
-                unsigned int cmd, struct PioctlData *data);
-int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out);
-int venus_fsync(struct super_block *sb, struct CodaFid *fid);
-int venus_statfs(struct dentry *dentry, struct kstatfs *sfs);
-
-/*
- * Statistics
- */
-
-extern struct venus_comm coda_comms[];
-#endif
index ebddcb6..16dafd9 100644 (file)
@@ -138,8 +138,7 @@ typedef struct {
        compat_sigset_word      sig[_COMPAT_NSIG_WORDS];
 } compat_sigset_t;
 
-int set_compat_user_sigmask(const compat_sigset_t __user *usigmask,
-                           sigset_t *set, sigset_t *oldset,
+int set_compat_user_sigmask(const compat_sigset_t __user *umask,
                            size_t sigsetsize);
 
 struct compat_sigaction {
index e857941..d7ee4c6 100644 (file)
 #else
 #define __diag_GCC_8(s)
 #endif
+
+#define __no_fgcse __attribute__((optimize("-fno-gcse")))
index 8aaf7cd..f0fd563 100644 (file)
@@ -116,9 +116,14 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
        ".pushsection .discard.unreachable\n\t"                         \
        ".long 999b - .\n\t"                                            \
        ".popsection\n\t"
+
+/* Annotate a C jump table to allow objtool to follow the code flow */
+#define __annotate_jump_table __section(".rodata..c_jump_table")
+
 #else
 #define annotate_reachable()
 #define annotate_unreachable()
+#define __annotate_jump_table
 #endif
 
 #ifndef ASM_UNREACHABLE
index 095d55c..599c27b 100644 (file)
@@ -189,6 +189,10 @@ struct ftrace_likely_data {
 #define asm_volatile_goto(x...) asm goto(x)
 #endif
 
+#ifndef __no_fgcse
+# define __no_fgcse
+#endif
+
 /* Are two types/vars the same type (ignoring qualifiers)? */
 #define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
 
index 1d72ef7..cb73264 100644 (file)
@@ -50,15 +50,75 @@ struct cn_dev {
 
        u32 seq, groups;
        struct sock *nls;
-       void (*input) (struct sk_buff *skb);
 
        struct cn_queue_dev *cbdev;
 };
 
+/**
+ * cn_add_callback() - Registers new callback with connector core.
+ *
+ * @id:                unique connector's user identifier.
+ *             It must be registered in connector.h for legal
+ *             in-kernel users.
+ * @name:      connector's callback symbolic name.
+ * @callback:  connector's callback.
+ *             parameters are %cn_msg and the sender's credentials
+ */
 int cn_add_callback(struct cb_id *id, const char *name,
                    void (*callback)(struct cn_msg *, struct netlink_skb_parms *));
-void cn_del_callback(struct cb_id *);
+/**
+ * cn_del_callback() - Unregisters new callback with connector core.
+ *
+ * @id:                unique connector's user identifier.
+ */
+void cn_del_callback(struct cb_id *id);
+
+
+/**
+ * cn_netlink_send_mult - Sends message to the specified groups.
+ *
+ * @msg:       message header(with attached data).
+ * @len:       Number of @msg to be sent.
+ * @portid:    destination port.
+ *             If non-zero the message will be sent to the given port,
+ *             which should be set to the original sender.
+ * @group:     destination group.
+ *             If @portid and @group is zero, then appropriate group will
+ *             be searched through all registered connector users, and
+ *             message will be delivered to the group which was created
+ *             for user with the same ID as in @msg.
+ *             If @group is not zero, then message will be delivered
+ *             to the specified group.
+ * @gfp_mask:  GFP mask.
+ *
+ * It can be safely called from softirq context, but may silently
+ * fail under strong memory pressure.
+ *
+ * If there are no listeners for given group %-ESRCH can be returned.
+ */
 int cn_netlink_send_mult(struct cn_msg *msg, u16 len, u32 portid, u32 group, gfp_t gfp_mask);
+
+/**
+ * cn_netlink_send_mult - Sends message to the specified groups.
+ *
+ * @msg:       message header(with attached data).
+ * @portid:    destination port.
+ *             If non-zero the message will be sent to the given port,
+ *             which should be set to the original sender.
+ * @group:     destination group.
+ *             If @portid and @group is zero, then appropriate group will
+ *             be searched through all registered connector users, and
+ *             message will be delivered to the group which was created
+ *             for user with the same ID as in @msg.
+ *             If @group is not zero, then message will be delivered
+ *             to the specified group.
+ * @gfp_mask:  GFP mask.
+ *
+ * It can be safely called from softirq context, but may silently
+ * fail under strong memory pressure.
+ *
+ * If there are no listeners for given group %-ESRCH can be returned.
+ */
 int cn_netlink_send(struct cn_msg *msg, u32 portid, u32 group, gfp_t gfp_mask);
 
 int cn_queue_add_callback(struct cn_queue_dev *dev, const char *name,
index 46b167f..536a049 100644 (file)
@@ -47,11 +47,6 @@ struct cpufreq_cpuinfo {
        unsigned int            transition_latency;
 };
 
-struct cpufreq_user_policy {
-       unsigned int            min;    /* in kHz */
-       unsigned int            max;    /* in kHz */
-};
-
 struct cpufreq_policy {
        /* CPUs sharing clock, require sw coordination */
        cpumask_var_t           cpus;   /* Online CPUs only */
@@ -81,7 +76,8 @@ struct cpufreq_policy {
        struct work_struct      update; /* if update_policy() needs to be
                                         * called, but you're in IRQ context */
 
-       struct cpufreq_user_policy user_policy;
+       struct dev_pm_qos_request *min_freq_req;
+       struct dev_pm_qos_request *max_freq_req;
        struct cpufreq_frequency_table  *freq_table;
        enum cpufreq_table_sorting freq_table_sorted;
 
@@ -144,6 +140,9 @@ struct cpufreq_policy {
 
        /* Pointer to the cooling device if used for thermal mitigation */
        struct thermal_cooling_device *cdev;
+
+       struct notifier_block nb_min;
+       struct notifier_block nb_max;
 };
 
 struct cpufreq_freqs {
@@ -201,6 +200,7 @@ void cpufreq_cpu_release(struct cpufreq_policy *policy);
 int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu);
 int cpufreq_set_policy(struct cpufreq_policy *policy,
                       struct cpufreq_policy *new_policy);
+void refresh_frequency_limits(struct cpufreq_policy *policy);
 void cpufreq_update_policy(unsigned int cpu);
 void cpufreq_update_limits(unsigned int cpu);
 bool have_governor_per_policy(void);
@@ -992,7 +992,7 @@ extern struct freq_attr *cpufreq_generic_attr[];
 int cpufreq_table_validate_and_sort(struct cpufreq_policy *policy);
 
 unsigned int cpufreq_generic_get(unsigned int cpu);
-int cpufreq_generic_init(struct cpufreq_policy *policy,
+void cpufreq_generic_init(struct cpufreq_policy *policy,
                struct cpufreq_frequency_table *table,
                unsigned int transition_latency);
 #endif /* _LINUX_CPUFREQ_H */
index 7eb43a0..f7a30e0 100644 (file)
@@ -145,7 +145,11 @@ struct cred {
        struct user_struct *user;       /* real user ID subscription */
        struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */
        struct group_info *group_info;  /* supplementary groups for euid/fsgid */
-       struct rcu_head rcu;            /* RCU deletion hook */
+       /* RCU deletion */
+       union {
+               int non_rcu;                    /* Can we skip RCU deletion? */
+               struct rcu_head rcu;            /* RCU deletion hook */
+       };
 } __randomize_layout;
 
 extern void __put_cred(struct cred *);
@@ -246,6 +250,7 @@ static inline const struct cred *get_cred(const struct cred *cred)
        if (!cred)
                return cred;
        validate_creds(cred);
+       nonconst_cred->non_rcu = 0;
        return get_new_cred(nonconst_cred);
 }
 
@@ -257,6 +262,7 @@ static inline const struct cred *get_cred_rcu(const struct cred *cred)
        if (!atomic_inc_not_zero(&nonconst_cred->usage))
                return NULL;
        validate_creds(cred);
+       nonconst_cred->non_rcu = 0;
        return cred;
 }
 
index becaea5..9bd8528 100644 (file)
@@ -7,6 +7,9 @@
 #include <linux/radix-tree.h>
 #include <asm/pgtable.h>
 
+/* Flag for synchronous flush */
+#define DAXDEV_F_SYNC (1UL << 0)
+
 typedef unsigned long dax_entry_t;
 
 struct iomap_ops;
@@ -38,18 +41,40 @@ extern struct attribute_group dax_attribute_group;
 #if IS_ENABLED(CONFIG_DAX)
 struct dax_device *dax_get_by_host(const char *host);
 struct dax_device *alloc_dax(void *private, const char *host,
-               const struct dax_operations *ops);
+               const struct dax_operations *ops, unsigned long flags);
 void put_dax(struct dax_device *dax_dev);
 void kill_dax(struct dax_device *dax_dev);
 void dax_write_cache(struct dax_device *dax_dev, bool wc);
 bool dax_write_cache_enabled(struct dax_device *dax_dev);
+bool __dax_synchronous(struct dax_device *dax_dev);
+static inline bool dax_synchronous(struct dax_device *dax_dev)
+{
+       return  __dax_synchronous(dax_dev);
+}
+void __set_dax_synchronous(struct dax_device *dax_dev);
+static inline void set_dax_synchronous(struct dax_device *dax_dev)
+{
+       __set_dax_synchronous(dax_dev);
+}
+/*
+ * Check if given mapping is supported by the file / underlying device.
+ */
+static inline bool daxdev_mapping_supported(struct vm_area_struct *vma,
+                                            struct dax_device *dax_dev)
+{
+       if (!(vma->vm_flags & VM_SYNC))
+               return true;
+       if (!IS_DAX(file_inode(vma->vm_file)))
+               return false;
+       return dax_synchronous(dax_dev);
+}
 #else
 static inline struct dax_device *dax_get_by_host(const char *host)
 {
        return NULL;
 }
 static inline struct dax_device *alloc_dax(void *private, const char *host,
-               const struct dax_operations *ops)
+               const struct dax_operations *ops, unsigned long flags)
 {
        /*
         * Callers should check IS_ENABLED(CONFIG_DAX) to know if this
@@ -70,6 +95,18 @@ static inline bool dax_write_cache_enabled(struct dax_device *dax_dev)
 {
        return false;
 }
+static inline bool dax_synchronous(struct dax_device *dax_dev)
+{
+       return true;
+}
+static inline void set_dax_synchronous(struct dax_device *dax_dev)
+{
+}
+static inline bool daxdev_mapping_supported(struct vm_area_struct *vma,
+                               struct dax_device *dax_dev)
+{
+       return !(vma->vm_flags & VM_SYNC);
+}
 #endif
 
 struct writeback_control;
index 5e0eadf..9451011 100644 (file)
@@ -291,7 +291,6 @@ static inline unsigned d_count(const struct dentry *dentry)
  */
 extern __printf(4, 5)
 char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
-extern char *simple_dname(struct dentry *, char *, int);
 
 extern char *__d_path(const struct path *, const struct path *, char *, int);
 extern char *d_absolute_path(const struct path *, char *, int);
index 3b470cb..399ad86 100644 (file)
@@ -529,29 +529,20 @@ void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size);
  *---------------------------------------------------------------*/
 #define DM_NAME "device-mapper"
 
-#define DM_RATELIMIT(pr_func, fmt, ...)                                        \
-do {                                                                   \
-       static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,   \
-                                     DEFAULT_RATELIMIT_BURST);         \
-                                                                       \
-       if (__ratelimit(&rs))                                           \
-               pr_func(DM_FMT(fmt), ##__VA_ARGS__);                    \
-} while (0)
-
 #define DM_FMT(fmt) DM_NAME ": " DM_MSG_PREFIX ": " fmt "\n"
 
 #define DMCRIT(fmt, ...) pr_crit(DM_FMT(fmt), ##__VA_ARGS__)
 
 #define DMERR(fmt, ...) pr_err(DM_FMT(fmt), ##__VA_ARGS__)
-#define DMERR_LIMIT(fmt, ...) DM_RATELIMIT(pr_err, fmt, ##__VA_ARGS__)
+#define DMERR_LIMIT(fmt, ...) pr_err_ratelimited(DM_FMT(fmt), ##__VA_ARGS__)
 #define DMWARN(fmt, ...) pr_warn(DM_FMT(fmt), ##__VA_ARGS__)
-#define DMWARN_LIMIT(fmt, ...) DM_RATELIMIT(pr_warn, fmt, ##__VA_ARGS__)
+#define DMWARN_LIMIT(fmt, ...) pr_warn_ratelimited(DM_FMT(fmt), ##__VA_ARGS__)
 #define DMINFO(fmt, ...) pr_info(DM_FMT(fmt), ##__VA_ARGS__)
-#define DMINFO_LIMIT(fmt, ...) DM_RATELIMIT(pr_info, fmt, ##__VA_ARGS__)
+#define DMINFO_LIMIT(fmt, ...) pr_info_ratelimited(DM_FMT(fmt), ##__VA_ARGS__)
 
 #ifdef CONFIG_DM_DEBUG
 #define DMDEBUG(fmt, ...) printk(KERN_DEBUG DM_FMT(fmt), ##__VA_ARGS__)
-#define DMDEBUG_LIMIT(fmt, ...) DM_RATELIMIT(pr_debug, fmt, ##__VA_ARGS__)
+#define DMDEBUG_LIMIT(fmt, ...) pr_debug_ratelimited(DM_FMT(fmt), ##__VA_ARGS__)
 #else
 #define DMDEBUG(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
 #define DMDEBUG_LIMIT(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
index 5eabfa0..c330b75 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright (c) 2004-2009 Greg Kroah-Hartman <gregkh@suse.de>
  * Copyright (c) 2008-2009 Novell Inc.
  *
- * See Documentation/driver-model/ for more information.
+ * See Documentation/driver-api/driver-model/ for more information.
  */
 
 #ifndef _DEVICE_H_
index b733870..adf993a 100644 (file)
@@ -32,6 +32,15 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
 }
 #endif /* !CONFIG_ARCH_HAS_PHYS_TO_DMA */
 
+#ifdef CONFIG_ARCH_HAS_FORCE_DMA_UNENCRYPTED
+bool force_dma_unencrypted(struct device *dev);
+#else
+static inline bool force_dma_unencrypted(struct device *dev)
+{
+       return false;
+}
+#endif /* CONFIG_ARCH_HAS_FORCE_DMA_UNENCRYPTED */
+
 /*
  * If memory encryption is supported, phys_to_dma will set the memory encryption
  * bit in the DMA address, and dma_to_phys will clear it.  The raw __phys_to_dma
index 8d13e28..f7d1eea 100644 (file)
@@ -679,6 +679,20 @@ static inline int dma_coerce_mask_and_coherent(struct device *dev, u64 mask)
        return dma_set_mask_and_coherent(dev, mask);
 }
 
+/**
+ * dma_addressing_limited - return if the device is addressing limited
+ * @dev:       device to check
+ *
+ * Return %true if the devices DMA mask is too small to address all memory in
+ * the system, else %false.  Lack of addressing bits is the prime reason for
+ * bounce buffering, but might not be the only one.
+ */
+static inline bool dma_addressing_limited(struct device *dev)
+{
+       return min_not_zero(dma_get_mask(dev), dev->bus_dma_mask) <
+                           dma_get_required_mask(dev);
+}
+
 #ifdef CONFIG_ARCH_HAS_SETUP_DMA_OPS
 void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
                const struct iommu_ops *iommu, bool coherent);
diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
new file mode 100644 (file)
index 0000000..cab6e18
--- /dev/null
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
+ * Synopsys DesignWare eDMA core driver
+ *
+ * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+ */
+
+#ifndef _DW_EDMA_H
+#define _DW_EDMA_H
+
+#include <linux/device.h>
+#include <linux/dmaengine.h>
+
+struct dw_edma;
+
+/**
+ * struct dw_edma_chip - representation of DesignWare eDMA controller hardware
+ * @dev:                struct device of the eDMA controller
+ * @id:                         instance ID
+ * @irq:                irq line
+ * @dw:                         struct dw_edma that is filed by dw_edma_probe()
+ */
+struct dw_edma_chip {
+       struct device           *dev;
+       int                     id;
+       int                     irq;
+       struct dw_edma          *dw;
+};
+
+/* Export to the platform drivers */
+#if IS_ENABLED(CONFIG_DW_EDMA)
+int dw_edma_probe(struct dw_edma_chip *chip);
+int dw_edma_remove(struct dw_edma_chip *chip);
+#else
+static inline int dw_edma_probe(struct dw_edma_chip *chip)
+{
+       return -ENODEV;
+}
+
+static inline int dw_edma_remove(struct dw_edma_chip *chip)
+{
+       return 0;
+}
+#endif /* CONFIG_DW_EDMA */
+
+#endif /* _DW_EDMA_H */
index c952f98..8fcdee1 100644 (file)
@@ -1302,7 +1302,8 @@ enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie);
 enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx);
 void dma_issue_pending_all(void);
 struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
-                                       dma_filter_fn fn, void *fn_param);
+                                      dma_filter_fn fn, void *fn_param,
+                                      struct device_node *np);
 struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name);
 
 struct dma_chan *dma_request_chan(struct device *dev, const char *name);
@@ -1327,7 +1328,9 @@ static inline void dma_issue_pending_all(void)
 {
 }
 static inline struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
-                                             dma_filter_fn fn, void *fn_param)
+                                                    dma_filter_fn fn,
+                                                    void *fn_param,
+                                                    struct device_node *np)
 {
        return NULL;
 }
@@ -1399,7 +1402,8 @@ void dma_async_device_unregister(struct dma_device *device);
 void dma_run_dependencies(struct dma_async_tx_descriptor *tx);
 struct dma_chan *dma_get_slave_channel(struct dma_chan *chan);
 struct dma_chan *dma_get_any_slave_channel(struct dma_device *device);
-#define dma_request_channel(mask, x, y) __dma_request_channel(&(mask), x, y)
+#define dma_request_channel(mask, x, y) \
+       __dma_request_channel(&(mask), x, y, NULL)
 #define dma_request_slave_channel_compat(mask, x, y, dev, name) \
        __dma_request_slave_channel_compat(&(mask), x, y, dev, name)
 
@@ -1417,6 +1421,6 @@ static inline struct dma_chan
        if (!fn || !fn_param)
                return NULL;
 
-       return __dma_request_channel(mask, fn, fn_param);
+       return __dma_request_channel(mask, fn, fn_param, NULL);
 }
 #endif /* DMAENGINE_H */
index 6d94436..ff65d22 100644 (file)
@@ -747,7 +747,7 @@ bpf_ctx_narrow_access_ok(u32 off, u32 size, u32 size_default)
        return size <= size_default && (size & (size - 1)) == 0;
 }
 
-#define bpf_ctx_wide_store_ok(off, size, type, field)                  \
+#define bpf_ctx_wide_access_ok(off, size, type, field)                 \
        (size == sizeof(__u64) &&                                       \
        off >= offsetof(type, field) &&                                 \
        off + sizeof(__u64) <= offsetofend(type, field) &&              \
diff --git a/include/linux/fpga/adi-axi-common.h b/include/linux/fpga/adi-axi-common.h
new file mode 100644 (file)
index 0000000..7fc95d5
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Analog Devices AXI common registers & definitions
+ *
+ * Copyright 2019 Analog Devices Inc.
+ *
+ * https://wiki.analog.com/resources/fpga/docs/axi_ip
+ * https://wiki.analog.com/resources/fpga/docs/hdl/regmap
+ */
+
+#ifndef ADI_AXI_COMMON_H_
+#define ADI_AXI_COMMON_H_
+
+#define        ADI_AXI_REG_VERSION                     0x0000
+
+#define ADI_AXI_PCORE_VER(major, minor, patch) \
+       (((major) << 16) | ((minor) << 8) | (patch))
+
+#endif /* ADI_AXI_COMMON_H_ */
index 75f2ed2..56b8e35 100644 (file)
@@ -2210,9 +2210,6 @@ struct file_system_type {
 
 #define MODULE_ALIAS_FS(NAME) MODULE_ALIAS("fs-" NAME)
 
-extern struct dentry *mount_ns(struct file_system_type *fs_type,
-       int flags, void *data, void *ns, struct user_namespace *user_ns,
-       int (*fill_super)(struct super_block *, void *, int));
 #ifdef CONFIG_BLOCK
 extern struct dentry *mount_bdev(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data,
@@ -2252,28 +2249,10 @@ void free_anon_bdev(dev_t);
 struct super_block *sget_fc(struct fs_context *fc,
                            int (*test)(struct super_block *, struct fs_context *),
                            int (*set)(struct super_block *, struct fs_context *));
-struct super_block *sget_userns(struct file_system_type *type,
-                       int (*test)(struct super_block *,void *),
-                       int (*set)(struct super_block *,void *),
-                       int flags, struct user_namespace *user_ns,
-                       void *data);
 struct super_block *sget(struct file_system_type *type,
                        int (*test)(struct super_block *,void *),
                        int (*set)(struct super_block *,void *),
                        int flags, void *data);
-extern struct dentry *mount_pseudo_xattr(struct file_system_type *, char *,
-                                        const struct super_operations *ops,
-                                        const struct xattr_handler **xattr,
-                                        const struct dentry_operations *dops,
-                                        unsigned long);
-
-static inline struct dentry *
-mount_pseudo(struct file_system_type *fs_type, char *name,
-            const struct super_operations *ops,
-            const struct dentry_operations *dops, unsigned long magic)
-{
-       return mount_pseudo_xattr(fs_type, name, ops, NULL, dops, magic);
-}
 
 /* Alas, no aliases. Too much hassle with bringing module.h everywhere */
 #define fops_get(fops) \
index 4933187..7c6fe3d 100644 (file)
@@ -99,6 +99,7 @@ struct fs_context {
        void                    *s_fs_info;     /* Proposed s_fs_info */
        unsigned int            sb_flags;       /* Proposed superblock flags (SB_*) */
        unsigned int            sb_flags_mask;  /* Superblock flags that were changed */
+       unsigned int            s_iflags;       /* OR'd with sb->s_iflags */
        unsigned int            lsm_flags;      /* Information flags from the fs to the LSM */
        enum fs_context_purpose purpose:8;
        enum fs_context_phase   phase:8;        /* The phase the context is in */
@@ -146,6 +147,12 @@ extern int vfs_get_super(struct fs_context *fc,
                         enum vfs_get_super_keying keying,
                         int (*fill_super)(struct super_block *sb,
                                           struct fs_context *fc));
+extern int get_tree_nodev(struct fs_context *fc,
+                        int (*fill_super)(struct super_block *sb,
+                                          struct fs_context *fc));
+extern int get_tree_single(struct fs_context *fc,
+                        int (*fill_super)(struct super_block *sb,
+                                          struct fs_context *fc));
 
 extern const struct file_operations fscontext_fops;
 
index 7cab74d..bdd09fd 100644 (file)
@@ -20,6 +20,5 @@ static inline void init_fs_pin(struct fs_pin *p, void (*kill)(struct fs_pin *))
 }
 
 void pin_remove(struct fs_pin *);
-void pin_insert_group(struct fs_pin *, struct vfsmount *, struct hlist_head *);
 void pin_insert(struct fs_pin *, struct vfsmount *);
 void pin_kill(struct fs_pin *);
index 25e2995..8a8cb3c 100644 (file)
@@ -427,8 +427,8 @@ struct dyn_ftrace *ftrace_rec_iter_record(struct ftrace_rec_iter *iter);
             iter = ftrace_rec_iter_next(iter))
 
 
-int ftrace_update_record(struct dyn_ftrace *rec, int enable);
-int ftrace_test_record(struct dyn_ftrace *rec, int enable);
+int ftrace_update_record(struct dyn_ftrace *rec, bool enable);
+int ftrace_test_record(struct dyn_ftrace *rec, bool enable);
 void ftrace_run_stop_machine(int command);
 unsigned long ftrace_location(unsigned long ip);
 unsigned long ftrace_location_range(unsigned long start, unsigned long end);
index 7cd5c15..45ede62 100644 (file)
@@ -121,6 +121,23 @@ static inline bool __transparent_hugepage_enabled(struct vm_area_struct *vma)
 
 bool transparent_hugepage_enabled(struct vm_area_struct *vma);
 
+#define HPAGE_CACHE_INDEX_MASK (HPAGE_PMD_NR - 1)
+
+static inline bool transhuge_vma_suitable(struct vm_area_struct *vma,
+               unsigned long haddr)
+{
+       /* Don't have to check pgoff for anonymous vma */
+       if (!vma_is_anonymous(vma)) {
+               if (((vma->vm_start >> PAGE_SHIFT) & HPAGE_CACHE_INDEX_MASK) !=
+                       (vma->vm_pgoff & HPAGE_CACHE_INDEX_MASK))
+                       return false;
+       }
+
+       if (haddr < vma->vm_start || haddr + HPAGE_PMD_SIZE > vma->vm_end)
+               return false;
+       return true;
+}
+
 #define transparent_hugepage_use_zero_page()                           \
        (transparent_hugepage_flags &                                   \
         (1<<TRANSPARENT_HUGEPAGE_USE_ZERO_PAGE_FLAG))
@@ -271,6 +288,12 @@ static inline bool transparent_hugepage_enabled(struct vm_area_struct *vma)
        return false;
 }
 
+static inline bool transhuge_vma_suitable(struct vm_area_struct *vma,
+               unsigned long haddr)
+{
+       return false;
+}
+
 static inline void prep_transhuge_page(struct page *page) {}
 
 #define transparent_hugepage_flags 0UL
index c0b93e0..8e6dd90 100644 (file)
@@ -1,7 +1,7 @@
 /*
        Hardware Random Number Generator
 
-       Please read Documentation/hw_random.txt for details on use.
+       Please read Documentation/admin-guide/hw_random.rst for details on use.
 
        ----------------------------------------------------------
        This software may be used and distributed according to the terms
index 0afe693..bfe7c1f 100644 (file)
 #include <linux/sched.h>
 
 /* hwspinlock mode argument */
-#define HWLOCK_IRQSTATE        0x01    /* Disable interrupts, save state */
-#define HWLOCK_IRQ     0x02    /* Disable interrupts, don't save state */
-#define HWLOCK_RAW     0x03
+#define HWLOCK_IRQSTATE                0x01 /* Disable interrupts, save state */
+#define HWLOCK_IRQ             0x02 /* Disable interrupts, don't save state */
+#define HWLOCK_RAW             0x03
+#define HWLOCK_IN_ATOMIC       0x04 /* Called while in atomic context */
 
 struct device;
 struct device_node;
@@ -223,6 +224,23 @@ static inline int hwspin_trylock_raw(struct hwspinlock *hwlock)
 }
 
 /**
+ * hwspin_trylock_in_atomic() - attempt to lock a specific hwspinlock
+ * @hwlock: an hwspinlock which we want to trylock
+ *
+ * This function attempts to lock an hwspinlock, and will immediately fail
+ * if the hwspinlock is already taken.
+ *
+ * This function shall be called only from an atomic context.
+ *
+ * Returns 0 if we successfully locked the hwspinlock, -EBUSY if
+ * the hwspinlock was already taken, and -EINVAL if @hwlock is invalid.
+ */
+static inline int hwspin_trylock_in_atomic(struct hwspinlock *hwlock)
+{
+       return __hwspin_trylock(hwlock, HWLOCK_IN_ATOMIC, NULL);
+}
+
+/**
  * hwspin_trylock() - attempt to lock a specific hwspinlock
  * @hwlock: an hwspinlock which we want to trylock
  *
@@ -313,6 +331,28 @@ int hwspin_lock_timeout_raw(struct hwspinlock *hwlock, unsigned int to)
 }
 
 /**
+ * hwspin_lock_timeout_in_atomic() - lock an hwspinlock with timeout limit
+ * @hwlock: the hwspinlock to be locked
+ * @to: timeout value in msecs
+ *
+ * This function locks the underlying @hwlock. If the @hwlock
+ * is already taken, the function will busy loop waiting for it to
+ * be released, but give up when @timeout msecs have elapsed.
+ *
+ * This function shall be called only from an atomic context and the timeout
+ * value shall not exceed a few msecs.
+ *
+ * Returns 0 when the @hwlock was successfully taken, and an appropriate
+ * error code otherwise (most notably an -ETIMEDOUT if the @hwlock is still
+ * busy after @timeout msecs). The function will never sleep.
+ */
+static inline
+int hwspin_lock_timeout_in_atomic(struct hwspinlock *hwlock, unsigned int to)
+{
+       return __hwspin_lock_timeout(hwlock, to, HWLOCK_IN_ATOMIC, NULL);
+}
+
+/**
  * hwspin_lock_timeout() - lock an hwspinlock with timeout limit
  * @hwlock: the hwspinlock to be locked
  * @to: timeout value in msecs
@@ -387,6 +427,21 @@ static inline void hwspin_unlock_raw(struct hwspinlock *hwlock)
 }
 
 /**
+ * hwspin_unlock_in_atomic() - unlock hwspinlock
+ * @hwlock: a previously-acquired hwspinlock which we want to unlock
+ *
+ * This function will unlock a specific hwspinlock.
+ *
+ * @hwlock must be already locked (e.g. by hwspin_trylock()) before calling
+ * this function: it is a bug to call unlock on a @hwlock that is already
+ * unlocked.
+ */
+static inline void hwspin_unlock_in_atomic(struct hwspinlock *hwlock)
+{
+       __hwspin_unlock(hwlock, HWLOCK_IN_ATOMIC, NULL);
+}
+
+/**
  * hwspin_unlock() - unlock hwspinlock
  * @hwlock: a previously-acquired hwspinlock which we want to unlock
  *
index 5255069..212fc9e 100644 (file)
@@ -137,6 +137,8 @@ extern initcall_entry_t __con_initcall_start[], __con_initcall_end[];
 /* Used for contructor calls. */
 typedef void (*ctor_fn_t)(void);
 
+struct file_system_type;
+
 /* Defined in init/main.c */
 extern int do_one_initcall(initcall_t fn);
 extern char __initdata boot_command_line[];
@@ -146,7 +148,8 @@ extern unsigned int reset_devices;
 /* used by init/main.c */
 void setup_arch(char **);
 void prepare_namespace(void);
-int __init init_rootfs(void);
+void __init init_rootfs(void);
+extern struct file_system_type rootfs_fs_type;
 
 #if defined(CONFIG_STRICT_KERNEL_RWX) || defined(CONFIG_STRICT_MODULE_RWX)
 extern bool rodata_enabled;
diff --git a/include/linux/intel_rapl.h b/include/linux/intel_rapl.h
new file mode 100644 (file)
index 0000000..efb3ce8
--- /dev/null
@@ -0,0 +1,155 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *  Data types and headers for RAPL support
+ *
+ *  Copyright (C) 2019  Intel Corporation.
+ *
+ *  Author: Zhang Rui <rui.zhang@intel.com>
+ */
+
+#ifndef __INTEL_RAPL_H__
+#define __INTEL_RAPL_H__
+
+#include <linux/types.h>
+#include <linux/powercap.h>
+#include <linux/cpuhotplug.h>
+
+enum rapl_domain_type {
+       RAPL_DOMAIN_PACKAGE,    /* entire package/socket */
+       RAPL_DOMAIN_PP0,        /* core power plane */
+       RAPL_DOMAIN_PP1,        /* graphics uncore */
+       RAPL_DOMAIN_DRAM,       /* DRAM control_type */
+       RAPL_DOMAIN_PLATFORM,   /* PSys control_type */
+       RAPL_DOMAIN_MAX,
+};
+
+enum rapl_domain_reg_id {
+       RAPL_DOMAIN_REG_LIMIT,
+       RAPL_DOMAIN_REG_STATUS,
+       RAPL_DOMAIN_REG_PERF,
+       RAPL_DOMAIN_REG_POLICY,
+       RAPL_DOMAIN_REG_INFO,
+       RAPL_DOMAIN_REG_MAX,
+};
+
+struct rapl_package;
+
+enum rapl_primitives {
+       ENERGY_COUNTER,
+       POWER_LIMIT1,
+       POWER_LIMIT2,
+       FW_LOCK,
+
+       PL1_ENABLE,             /* power limit 1, aka long term */
+       PL1_CLAMP,              /* allow frequency to go below OS request */
+       PL2_ENABLE,             /* power limit 2, aka short term, instantaneous */
+       PL2_CLAMP,
+
+       TIME_WINDOW1,           /* long term */
+       TIME_WINDOW2,           /* short term */
+       THERMAL_SPEC_POWER,
+       MAX_POWER,
+
+       MIN_POWER,
+       MAX_TIME_WINDOW,
+       THROTTLED_TIME,
+       PRIORITY_LEVEL,
+
+       /* below are not raw primitive data */
+       AVERAGE_POWER,
+       NR_RAPL_PRIMITIVES,
+};
+
+struct rapl_domain_data {
+       u64 primitives[NR_RAPL_PRIMITIVES];
+       unsigned long timestamp;
+};
+
+#define NR_POWER_LIMITS (2)
+struct rapl_power_limit {
+       struct powercap_zone_constraint *constraint;
+       int prim_id;            /* primitive ID used to enable */
+       struct rapl_domain *domain;
+       const char *name;
+       u64 last_power_limit;
+};
+
+struct rapl_package;
+
+struct rapl_domain {
+       const char *name;
+       enum rapl_domain_type id;
+       u64 regs[RAPL_DOMAIN_REG_MAX];
+       struct powercap_zone power_zone;
+       struct rapl_domain_data rdd;
+       struct rapl_power_limit rpl[NR_POWER_LIMITS];
+       u64 attr_map;           /* track capabilities */
+       unsigned int state;
+       unsigned int domain_energy_unit;
+       struct rapl_package *rp;
+};
+
+struct reg_action {
+       u64 reg;
+       u64 mask;
+       u64 value;
+       int err;
+};
+
+/**
+ * struct rapl_if_priv: private data for different RAPL interfaces
+ * @control_type:              Each RAPL interface must have its own powercap
+ *                             control type.
+ * @platform_rapl_domain:      Optional. Some RAPL interface may have platform
+ *                             level RAPL control.
+ * @pcap_rapl_online:          CPU hotplug state for each RAPL interface.
+ * @reg_unit:                  Register for getting energy/power/time unit.
+ * @regs:                      Register sets for different RAPL Domains.
+ * @limits:                    Number of power limits supported by each domain.
+ * @read_raw:                  Callback for reading RAPL interface specific
+ *                             registers.
+ * @write_raw:                 Callback for writing RAPL interface specific
+ *                             registers.
+ */
+struct rapl_if_priv {
+       struct powercap_control_type *control_type;
+       struct rapl_domain *platform_rapl_domain;
+       enum cpuhp_state pcap_rapl_online;
+       u64 reg_unit;
+       u64 regs[RAPL_DOMAIN_MAX][RAPL_DOMAIN_REG_MAX];
+       int limits[RAPL_DOMAIN_MAX];
+       int (*read_raw)(int cpu, struct reg_action *ra);
+       int (*write_raw)(int cpu, struct reg_action *ra);
+};
+
+/* maximum rapl package domain name: package-%d-die-%d */
+#define PACKAGE_DOMAIN_NAME_LENGTH 30
+
+struct rapl_package {
+       unsigned int id;        /* logical die id, equals physical 1-die systems */
+       unsigned int nr_domains;
+       unsigned long domain_map;       /* bit map of active domains */
+       unsigned int power_unit;
+       unsigned int energy_unit;
+       unsigned int time_unit;
+       struct rapl_domain *domains;    /* array of domains, sized at runtime */
+       struct powercap_zone *power_zone;       /* keep track of parent zone */
+       unsigned long power_limit_irq;  /* keep track of package power limit
+                                        * notify interrupt enable status.
+                                        */
+       struct list_head plist;
+       int lead_cpu;           /* one active cpu per package for access */
+       /* Track active cpus */
+       struct cpumask cpumask;
+       char name[PACKAGE_DOMAIN_NAME_LENGTH];
+       struct rapl_if_priv *priv;
+};
+
+struct rapl_package *rapl_find_package_domain(int cpu, struct rapl_if_priv *priv);
+struct rapl_package *rapl_add_package(int cpu, struct rapl_if_priv *priv);
+void rapl_remove_package(struct rapl_package *rp);
+
+int rapl_add_platform_domain(struct rapl_if_priv *priv);
+void rapl_remove_platform_domain(struct rapl_if_priv *priv);
+
+#endif /* __INTEL_RAPL_H__ */
index 9876e58..accac82 100644 (file)
@@ -33,6 +33,7 @@ static inline int ioremap_page_range(unsigned long addr, unsigned long end,
 
 #ifdef CONFIG_HAVE_ARCH_HUGE_VMAP
 void __init ioremap_huge_init(void);
+int arch_ioremap_p4d_supported(void);
 int arch_ioremap_pud_supported(void);
 int arch_ioremap_pmd_supported(void);
 #else
index 1df9ea1..bc499ce 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/mm.h>
 #include <linux/types.h>
 #include <linux/mm_types.h>
+#include <linux/blkdev.h>
 
 struct address_space;
 struct fiemap_extent_info;
@@ -69,6 +70,12 @@ struct iomap {
        const struct iomap_page_ops *page_ops;
 };
 
+static inline sector_t
+iomap_sector(struct iomap *iomap, loff_t pos)
+{
+       return (iomap->addr + pos - iomap->offset) >> SECTOR_SHIFT;
+}
+
 /*
  * When a filesystem sets page_ops in an iomap mapping it returns, page_prepare
  * and page_done will be called for each page written to.  This only applies to
@@ -116,6 +123,16 @@ struct iomap_ops {
 };
 
 /*
+ * Main iomap iterator function.
+ */
+typedef loff_t (*iomap_actor_t)(struct inode *inode, loff_t pos, loff_t len,
+               void *data, struct iomap *iomap);
+
+loff_t iomap_apply(struct inode *inode, loff_t pos, loff_t length,
+               unsigned flags, const struct iomap_ops *ops, void *data,
+               iomap_actor_t actor);
+
+/*
  * Structure allocate for each page when block size < PAGE_SIZE to track
  * sub-page uptodate status and I/O completions.
  */
index 781b96a..a0637ab 100644 (file)
@@ -155,6 +155,7 @@ struct iova *reserve_iova(struct iova_domain *iovad, unsigned long pfn_lo,
 void copy_reserved_iova(struct iova_domain *from, struct iova_domain *to);
 void init_iova_domain(struct iova_domain *iovad, unsigned long granule,
        unsigned long start_pfn);
+bool has_iova_flush_queue(struct iova_domain *iovad);
 int init_iova_flush_queue(struct iova_domain *iovad,
                          iova_flush_cb flush_cb, iova_entry_dtor entry_dtor);
 struct iova *find_iova(struct iova_domain *iovad, unsigned long pfn);
@@ -235,6 +236,11 @@ static inline void init_iova_domain(struct iova_domain *iovad,
 {
 }
 
+static inline bool has_iova_flush_queue(struct iova_domain *iovad)
+{
+       return false;
+}
+
 static inline int init_iova_flush_queue(struct iova_domain *iovad,
                                        iova_flush_cb flush_cb,
                                        iova_entry_dtor entry_dtor)
index be50ef7..2917ef9 100644 (file)
@@ -113,6 +113,30 @@ inode_peek_iversion_raw(const struct inode *inode)
 }
 
 /**
+ * inode_set_max_iversion_raw - update i_version new value is larger
+ * @inode: inode to set
+ * @val: new i_version to set
+ *
+ * Some self-managed filesystems (e.g Ceph) will only update the i_version
+ * value if the new value is larger than the one we already have.
+ */
+static inline void
+inode_set_max_iversion_raw(struct inode *inode, u64 val)
+{
+       u64 cur, old;
+
+       cur = inode_peek_iversion_raw(inode);
+       for (;;) {
+               if (cur > val)
+                       break;
+               old = atomic64_cmpxchg(&inode->i_version, cur, val);
+               if (likely(old == cur))
+                       break;
+               cur = old;
+       }
+}
+
+/**
  * inode_set_iversion - set i_version to a particular value
  * @inode: inode to set
  * @val: new i_version value to set
index 0c9bc23..4fa360a 100644 (file)
@@ -88,6 +88,8 @@
  */
 #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
 
+#define typeof_member(T, m)    typeof(((T*)0)->m)
+
 #define DIV_ROUND_UP __KERNEL_DIV_ROUND_UP
 
 #define DIV_ROUND_DOWN_ULL(ll, d) \
index 443d980..04bdaf0 100644 (file)
@@ -458,4 +458,23 @@ static inline bool is_kprobe_optinsn_slot(unsigned long addr)
 }
 #endif
 
+/* Returns true if kprobes handled the fault */
+static nokprobe_inline bool kprobe_page_fault(struct pt_regs *regs,
+                                             unsigned int trap)
+{
+       if (!kprobes_built_in())
+               return false;
+       if (user_mode(regs))
+               return false;
+       /*
+        * To be potentially processing a kprobe fault and to be allowed
+        * to call kprobe_running(), we have to be non-preemptible.
+        */
+       if (preemptible())
+               return false;
+       if (!kprobe_running())
+               return false;
+       return kprobe_fault_handler(regs, trap);
+}
+
 #endif /* _LINUX_KPROBES_H */
index c5da875..5c5b586 100644 (file)
@@ -318,6 +318,7 @@ struct kvm_vcpu {
        } spin_loop;
 #endif
        bool preempted;
+       bool ready;
        struct kvm_vcpu_arch arch;
        struct dentry *debugfs_dentry;
 };
index 03d5c3a..7a64b3d 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/types.h>
 #include <linux/uuid.h>
 #include <linux/spinlock.h>
+#include <linux/bio.h>
 
 struct badrange_entry {
        u64 start;
@@ -57,6 +58,9 @@ enum {
         */
        ND_REGION_PERSIST_MEMCTRL = 2,
 
+       /* Platform provides asynchronous flush mechanism */
+       ND_REGION_ASYNC = 3,
+
        /* mark newly adjusted resources as requiring a label update */
        DPA_RESOURCE_ADJUSTED = 1 << 0,
 };
@@ -113,6 +117,7 @@ struct nd_mapping_desc {
        int position;
 };
 
+struct nd_region;
 struct nd_region_desc {
        struct resource *res;
        struct nd_mapping_desc *mapping;
@@ -125,6 +130,7 @@ struct nd_region_desc {
        int target_node;
        unsigned long flags;
        struct device_node *of_node;
+       int (*flush)(struct nd_region *nd_region, struct bio *bio);
 };
 
 struct device;
@@ -252,10 +258,12 @@ unsigned long nd_blk_memremap_flags(struct nd_blk_region *ndbr);
 unsigned int nd_region_acquire_lane(struct nd_region *nd_region);
 void nd_region_release_lane(struct nd_region *nd_region, unsigned int lane);
 u64 nd_fletcher64(void *addr, size_t len, bool le);
-void nvdimm_flush(struct nd_region *nd_region);
+int nvdimm_flush(struct nd_region *nd_region, struct bio *bio);
+int generic_nvdimm_flush(struct nd_region *nd_region);
 int nvdimm_has_flush(struct nd_region *nd_region);
 int nvdimm_has_cache(struct nd_region *nd_region);
 int nvdimm_in_overwrite(struct nvdimm *nvdimm);
+bool is_nvdimm_sync(struct nd_region *nd_region);
 
 static inline int nvdimm_ctl(struct nvdimm *nvdimm, unsigned int cmd, void *buf,
                unsigned int buf_len, int *cmd_rc)
index 57baa27..0b0d725 100644 (file)
@@ -5,7 +5,7 @@
  *  Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
  *  Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra
  *
- * see Documentation/locking/lockdep-design.txt for more details.
+ * see Documentation/locking/lockdep-design.rst for more details.
  */
 #ifndef __LINUX_LOCKDEP_H
 #define __LINUX_LOCKDEP_H
index 394e3d9..b16e15b 100644 (file)
@@ -278,7 +278,7 @@ int LZ4_decompress_fast(const char *source, char *dest, int originalSize);
  * @compressedSize: is the precise full size of the compressed block
  * @maxDecompressedSize: is the size of 'dest' buffer
  *
- * Decompresses data fom 'source' into 'dest'.
+ * Decompresses data from 'source' into 'dest'.
  * If the source stream is detected malformed, the function will
  * stop decoding and return a negative result.
  * This function is protected against buffer overflow exploits,
@@ -522,7 +522,7 @@ int LZ4_setStreamDecode(LZ4_streamDecode_t *LZ4_streamDecode,
        const char *dictionary, int dictSize);
 
 /**
- * LZ4_decompress_fast_continue() - Decompress blocks in streaming mode
+ * LZ4_decompress_safe_continue() - Decompress blocks in streaming mode
  * @LZ4_streamDecode: the 'LZ4_streamDecode_t' structure
  * @source: source address of the compressed data
  * @dest: output buffer address of the uncompressed data
@@ -530,7 +530,7 @@ int LZ4_setStreamDecode(LZ4_streamDecode_t *LZ4_streamDecode,
  * @compressedSize: is the precise full size of the compressed block
  * @maxDecompressedSize: is the size of 'dest' buffer
  *
- * These decoding function allows decompression of multiple blocks
+ * This decoding function allows decompression of multiple blocks
  * in "streaming" mode.
  * Previously decoded blocks *must* remain available at the memory position
  * where they were decoded (up to 64 KB)
@@ -569,7 +569,7 @@ int LZ4_decompress_safe_continue(LZ4_streamDecode_t *LZ4_streamDecode,
  *     which must be already allocated with 'originalSize' bytes
  * @originalSize: is the original and therefore uncompressed size
  *
- * These decoding function allows decompression of multiple blocks
+ * This decoding function allows decompression of multiple blocks
  * in "streaming" mode.
  * Previously decoded blocks *must* remain available at the memory position
  * where they were decoded (up to 64 KB)
@@ -610,10 +610,10 @@ int LZ4_decompress_fast_continue(LZ4_streamDecode_t *LZ4_streamDecode,
  * @dictStart: pointer to the start of the dictionary in memory
  * @dictSize: size of dictionary
  *
- * These decoding function works the same as
+ * This decoding function works the same as
  * a combination of LZ4_setStreamDecode() followed by
  * LZ4_decompress_safe_continue()
- * It is stand-alone, and don'tn eed a LZ4_streamDecode_t structure.
+ * It is stand-alone, and doesn't need an LZ4_streamDecode_t structure.
  *
  * Return: number of bytes decompressed into destination buffer
  *     (necessarily <= maxDecompressedSize)
@@ -633,10 +633,10 @@ int LZ4_decompress_safe_usingDict(const char *source, char *dest,
  * @dictStart: pointer to the start of the dictionary in memory
  * @dictSize: size of dictionary
  *
- * These decoding function works the same as
+ * This decoding function works the same as
  * a combination of LZ4_setStreamDecode() followed by
- * LZ4_decompress_safe_continue()
- * It is stand-alone, and don'tn eed a LZ4_streamDecode_t structure.
+ * LZ4_decompress_fast_continue()
+ * It is stand-alone, and doesn't need an LZ4_streamDecode_t structure.
  *
  * Return: number of bytes decompressed into destination buffer
  *     (necessarily <= maxDecompressedSize)
index e1dc1bb..02e633f 100644 (file)
@@ -111,16 +111,15 @@ extern int register_memory_notifier(struct notifier_block *nb);
 extern void unregister_memory_notifier(struct notifier_block *nb);
 extern int register_memory_isolate_notifier(struct notifier_block *nb);
 extern void unregister_memory_isolate_notifier(struct notifier_block *nb);
-int hotplug_memory_register(int nid, struct mem_section *section);
-#ifdef CONFIG_MEMORY_HOTREMOVE
-extern void unregister_memory_section(struct mem_section *);
-#endif
+int create_memory_block_devices(unsigned long start, unsigned long size);
+void remove_memory_block_devices(unsigned long start, unsigned long size);
 extern int memory_dev_init(void);
 extern int memory_notify(unsigned long val, void *v);
 extern int memory_isolate_notify(unsigned long val, void *v);
-extern struct memory_block *find_memory_block_hinted(struct mem_section *,
-                                                       struct memory_block *);
 extern struct memory_block *find_memory_block(struct mem_section *);
+typedef int (*walk_memory_blocks_func_t)(struct memory_block *, void *);
+extern int walk_memory_blocks(unsigned long start, unsigned long size,
+                             void *arg, walk_memory_blocks_func_t func);
 #define CONFIG_MEM_BLOCK_SIZE  (PAGES_PER_SECTION<<PAGE_SHIFT)
 #endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
 
index ae892ee..f46ea71 100644 (file)
@@ -123,20 +123,10 @@ static inline bool movable_node_is_enabled(void)
        return movable_node_enabled;
 }
 
-#ifdef CONFIG_MEMORY_HOTREMOVE
 extern void arch_remove_memory(int nid, u64 start, u64 size,
                               struct vmem_altmap *altmap);
 extern void __remove_pages(struct zone *zone, unsigned long start_pfn,
                           unsigned long nr_pages, struct vmem_altmap *altmap);
-#endif /* CONFIG_MEMORY_HOTREMOVE */
-
-/*
- * Do we want sysfs memblock files created. This will allow userspace to online
- * and offline memory explicitly. Lack of this bit means that the caller has to
- * call move_pfn_range_to_zone to finish the initialization.
- */
-
-#define MHP_MEMBLOCK_API               (1<<0)
 
 /* reasonably generic interface to expand the physical pages */
 extern int __add_pages(int nid, unsigned long start_pfn, unsigned long nr_pages,
@@ -324,7 +314,7 @@ static inline void pgdat_resize_init(struct pglist_data *pgdat) {}
 extern bool is_mem_section_removable(unsigned long pfn, unsigned long nr_pages);
 extern void try_offline_node(int nid);
 extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages);
-extern void remove_memory(int nid, u64 start, u64 size);
+extern int remove_memory(int nid, u64 start, u64 size);
 extern void __remove_memory(int nid, u64 start, u64 size);
 
 #else
@@ -341,22 +331,25 @@ static inline int offline_pages(unsigned long start_pfn, unsigned long nr_pages)
        return -EINVAL;
 }
 
-static inline void remove_memory(int nid, u64 start, u64 size) {}
+static inline int remove_memory(int nid, u64 start, u64 size)
+{
+       return -EBUSY;
+}
+
 static inline void __remove_memory(int nid, u64 start, u64 size) {}
 #endif /* CONFIG_MEMORY_HOTREMOVE */
 
 extern void __ref free_area_init_core_hotplug(int nid);
-extern int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn,
-               void *arg, int (*func)(struct memory_block *, void *));
 extern int __add_memory(int nid, u64 start, u64 size);
 extern int add_memory(int nid, u64 start, u64 size);
 extern int add_memory_resource(int nid, struct resource *resource);
 extern void move_pfn_range_to_zone(struct zone *zone, unsigned long start_pfn,
                unsigned long nr_pages, struct vmem_altmap *altmap);
 extern bool is_memblock_offlined(struct memory_block *mem);
-extern int sparse_add_one_section(int nid, unsigned long start_pfn,
-                                 struct vmem_altmap *altmap);
-extern void sparse_remove_one_section(struct zone *zone, struct mem_section *ms,
+extern int sparse_add_section(int nid, unsigned long pfn,
+               unsigned long nr_pages, struct vmem_altmap *altmap);
+extern void sparse_remove_section(struct mem_section *ms,
+               unsigned long pfn, unsigned long nr_pages,
                unsigned long map_offset, struct vmem_altmap *altmap);
 extern struct page *sparse_decode_mem_map(unsigned long coded_mem_map,
                                          unsigned long pnum);
index e13d9bf..7f04754 100644 (file)
@@ -77,8 +77,7 @@ extern void migrate_page_copy(struct page *newpage, struct page *page);
 extern int migrate_huge_page_move_mapping(struct address_space *mapping,
                                  struct page *newpage, struct page *page);
 extern int migrate_page_move_mapping(struct address_space *mapping,
-               struct page *newpage, struct page *page, enum migrate_mode mode,
-               int extra_count);
+               struct page *newpage, struct page *page, int extra_count);
 #else
 
 static inline void putback_movable_pages(struct list_head *l) {}
index 0389c34..0334ca9 100644 (file)
@@ -541,13 +541,30 @@ static inline void vma_set_anonymous(struct vm_area_struct *vma)
        vma->vm_ops = NULL;
 }
 
+static inline bool vma_is_anonymous(struct vm_area_struct *vma)
+{
+       return !vma->vm_ops;
+}
+
+#ifdef CONFIG_SHMEM
+/*
+ * The vma_is_shmem is not inline because it is used only by slow
+ * paths in userfault.
+ */
+bool vma_is_shmem(struct vm_area_struct *vma);
+#else
+static inline bool vma_is_shmem(struct vm_area_struct *vma) { return false; }
+#endif
+
+int vma_is_stack_for_current(struct vm_area_struct *vma);
+
 /* flush_tlb_range() takes a vma, not a mm, and can care about flags */
 #define TLB_FLUSH_VMA(mm,flags) { .vm_mm = (mm), .vm_flags = (flags) }
 
 struct mmu_gather;
 struct inode;
 
-#if !defined(__HAVE_ARCH_PTE_DEVMAP) || !defined(CONFIG_TRANSPARENT_HUGEPAGE)
+#if !defined(CONFIG_ARCH_HAS_PTE_DEVMAP) || !defined(CONFIG_TRANSPARENT_HUGEPAGE)
 static inline int pmd_devmap(pmd_t pmd)
 {
        return 0;
@@ -956,41 +973,28 @@ static inline bool put_devmap_managed_page(struct page *page)
        return false;
 }
 
-static inline bool is_device_private_page(const struct page *page)
-{
-       return is_zone_device_page(page) &&
-               page->pgmap->type == MEMORY_DEVICE_PRIVATE;
-}
-
-#ifdef CONFIG_PCI_P2PDMA
-static inline bool is_pci_p2pdma_page(const struct page *page)
-{
-       return is_zone_device_page(page) &&
-               page->pgmap->type == MEMORY_DEVICE_PCI_P2PDMA;
-}
-#else /* CONFIG_PCI_P2PDMA */
-static inline bool is_pci_p2pdma_page(const struct page *page)
-{
-       return false;
-}
-#endif /* CONFIG_PCI_P2PDMA */
-
 #else /* CONFIG_DEV_PAGEMAP_OPS */
 static inline bool put_devmap_managed_page(struct page *page)
 {
        return false;
 }
+#endif /* CONFIG_DEV_PAGEMAP_OPS */
 
 static inline bool is_device_private_page(const struct page *page)
 {
-       return false;
+       return IS_ENABLED(CONFIG_DEV_PAGEMAP_OPS) &&
+               IS_ENABLED(CONFIG_DEVICE_PRIVATE) &&
+               is_zone_device_page(page) &&
+               page->pgmap->type == MEMORY_DEVICE_PRIVATE;
 }
 
 static inline bool is_pci_p2pdma_page(const struct page *page)
 {
-       return false;
+       return IS_ENABLED(CONFIG_DEV_PAGEMAP_OPS) &&
+               IS_ENABLED(CONFIG_PCI_P2PDMA) &&
+               is_zone_device_page(page) &&
+               page->pgmap->type == MEMORY_DEVICE_PCI_P2PDMA;
 }
-#endif /* CONFIG_DEV_PAGEMAP_OPS */
 
 /* 127: arbitrary random number, small enough to assemble well */
 #define page_ref_zero_or_close_to_overflow(page) \
@@ -1556,6 +1560,10 @@ long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages,
 int get_user_pages_fast(unsigned long start, int nr_pages,
                        unsigned int gup_flags, struct page **pages);
 
+int account_locked_vm(struct mm_struct *mm, unsigned long pages, bool inc);
+int __account_locked_vm(struct mm_struct *mm, unsigned long pages, bool inc,
+                       struct task_struct *task, bool bypass_rlim);
+
 /* Container for pinned pfns / pages */
 struct frame_vector {
        unsigned int nr_allocated;      /* Number of frames we have space for */
@@ -1629,23 +1637,6 @@ int clear_page_dirty_for_io(struct page *page);
 
 int get_cmdline(struct task_struct *task, char *buffer, int buflen);
 
-static inline bool vma_is_anonymous(struct vm_area_struct *vma)
-{
-       return !vma->vm_ops;
-}
-
-#ifdef CONFIG_SHMEM
-/*
- * The vma_is_shmem is not inline because it is used only by slow
- * paths in userfault.
- */
-bool vma_is_shmem(struct vm_area_struct *vma);
-#else
-static inline bool vma_is_shmem(struct vm_area_struct *vma) { return false; }
-#endif
-
-int vma_is_stack_for_current(struct vm_area_struct *vma);
-
 extern unsigned long move_page_tables(struct vm_area_struct *vma,
                unsigned long old_addr, struct vm_area_struct *new_vma,
                unsigned long new_addr, unsigned long len,
@@ -1763,7 +1754,7 @@ static inline void sync_mm_rss(struct mm_struct *mm)
 }
 #endif
 
-#ifndef __HAVE_ARCH_PTE_DEVMAP
+#ifndef CONFIG_ARCH_HAS_PTE_DEVMAP
 static inline int pte_devmap(pte_t pte)
 {
        return 0;
@@ -2767,11 +2758,17 @@ extern int randomize_va_space;
 #endif
 
 const char * arch_vma_name(struct vm_area_struct *vma);
+#ifdef CONFIG_MMU
 void print_vma_addr(char *prefix, unsigned long rip);
+#else
+static inline void print_vma_addr(char *prefix, unsigned long rip)
+{
+}
+#endif
 
 void *sparse_buffer_alloc(unsigned long size);
-struct page *sparse_mem_map_populate(unsigned long pnum, int nid,
-               struct vmem_altmap *altmap);
+struct page * __populate_section_memmap(unsigned long pfn,
+               unsigned long nr_pages, int nid, struct vmem_altmap *altmap);
 pgd_t *vmemmap_pgd_populate(unsigned long addr, int node);
 p4d_t *vmemmap_p4d_populate(pgd_t *pgd, unsigned long addr, int node);
 pud_t *vmemmap_pud_populate(p4d_t *p4d, unsigned long addr, int node);
index 70394ca..d77d717 100644 (file)
@@ -855,18 +855,6 @@ static inline int local_memory_node(int node_id) { return node_id; };
  */
 #define zone_idx(zone)         ((zone) - (zone)->zone_pgdat->node_zones)
 
-#ifdef CONFIG_ZONE_DEVICE
-static inline bool is_dev_zone(const struct zone *zone)
-{
-       return zone_idx(zone) == ZONE_DEVICE;
-}
-#else
-static inline bool is_dev_zone(const struct zone *zone)
-{
-       return false;
-}
-#endif
-
 /*
  * Returns true if a zone has pages managed by the buddy allocator.
  * All the reclaim decisions have to use this function rather than
@@ -1160,6 +1148,29 @@ static inline unsigned long section_nr_to_pfn(unsigned long sec)
 #define SECTION_ALIGN_UP(pfn)  (((pfn) + PAGES_PER_SECTION - 1) & PAGE_SECTION_MASK)
 #define SECTION_ALIGN_DOWN(pfn)        ((pfn) & PAGE_SECTION_MASK)
 
+#define SUBSECTION_SHIFT 21
+
+#define PFN_SUBSECTION_SHIFT (SUBSECTION_SHIFT - PAGE_SHIFT)
+#define PAGES_PER_SUBSECTION (1UL << PFN_SUBSECTION_SHIFT)
+#define PAGE_SUBSECTION_MASK (~(PAGES_PER_SUBSECTION-1))
+
+#if SUBSECTION_SHIFT > SECTION_SIZE_BITS
+#error Subsection size exceeds section size
+#else
+#define SUBSECTIONS_PER_SECTION (1UL << (SECTION_SIZE_BITS - SUBSECTION_SHIFT))
+#endif
+
+#define SUBSECTION_ALIGN_UP(pfn) ALIGN((pfn), PAGES_PER_SUBSECTION)
+#define SUBSECTION_ALIGN_DOWN(pfn) ((pfn) & PAGE_SUBSECTION_MASK)
+
+struct mem_section_usage {
+       DECLARE_BITMAP(subsection_map, SUBSECTIONS_PER_SECTION);
+       /* See declaration of similar field in struct zone */
+       unsigned long pageblock_flags[0];
+};
+
+void subsection_map_init(unsigned long pfn, unsigned long nr_pages);
+
 struct page;
 struct page_ext;
 struct mem_section {
@@ -1177,8 +1188,7 @@ struct mem_section {
         */
        unsigned long section_mem_map;
 
-       /* See declaration of similar field in struct zone */
-       unsigned long *pageblock_flags;
+       struct mem_section_usage *usage;
 #ifdef CONFIG_PAGE_EXTENSION
        /*
         * If SPARSEMEM, pgdat doesn't have page_ext pointer. We use
@@ -1209,6 +1219,11 @@ extern struct mem_section **mem_section;
 extern struct mem_section mem_section[NR_SECTION_ROOTS][SECTIONS_PER_ROOT];
 #endif
 
+static inline unsigned long *section_to_usemap(struct mem_section *ms)
+{
+       return ms->usage->pageblock_flags;
+}
+
 static inline struct mem_section *__nr_to_section(unsigned long nr)
 {
 #ifdef CONFIG_SPARSEMEM_EXTREME
@@ -1219,8 +1234,8 @@ static inline struct mem_section *__nr_to_section(unsigned long nr)
                return NULL;
        return &mem_section[SECTION_NR_TO_ROOT(nr)][nr & SECTION_ROOT_MASK];
 }
-extern int __section_nr(struct mem_section* ms);
-extern unsigned long usemap_size(void);
+extern unsigned long __section_nr(struct mem_section *ms);
+extern size_t mem_section_usage_size(void);
 
 /*
  * We use the lower bits of the mem_map pointer to store
@@ -1238,7 +1253,8 @@ extern unsigned long usemap_size(void);
 #define        SECTION_MARKED_PRESENT  (1UL<<0)
 #define SECTION_HAS_MEM_MAP    (1UL<<1)
 #define SECTION_IS_ONLINE      (1UL<<2)
-#define SECTION_MAP_LAST_BIT   (1UL<<3)
+#define SECTION_IS_EARLY       (1UL<<3)
+#define SECTION_MAP_LAST_BIT   (1UL<<4)
 #define SECTION_MAP_MASK       (~(SECTION_MAP_LAST_BIT-1))
 #define SECTION_NID_SHIFT      3
 
@@ -1264,6 +1280,11 @@ static inline int valid_section(struct mem_section *section)
        return (section && (section->section_mem_map & SECTION_HAS_MEM_MAP));
 }
 
+static inline int early_section(struct mem_section *section)
+{
+       return (section && (section->section_mem_map & SECTION_IS_EARLY));
+}
+
 static inline int valid_section_nr(unsigned long nr)
 {
        return valid_section(__nr_to_section(nr));
@@ -1291,14 +1312,42 @@ static inline struct mem_section *__pfn_to_section(unsigned long pfn)
        return __nr_to_section(pfn_to_section_nr(pfn));
 }
 
-extern int __highest_present_section_nr;
+extern unsigned long __highest_present_section_nr;
+
+static inline int subsection_map_index(unsigned long pfn)
+{
+       return (pfn & ~(PAGE_SECTION_MASK)) / PAGES_PER_SUBSECTION;
+}
+
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
+static inline int pfn_section_valid(struct mem_section *ms, unsigned long pfn)
+{
+       int idx = subsection_map_index(pfn);
+
+       return test_bit(idx, ms->usage->subsection_map);
+}
+#else
+static inline int pfn_section_valid(struct mem_section *ms, unsigned long pfn)
+{
+       return 1;
+}
+#endif
 
 #ifndef CONFIG_HAVE_ARCH_PFN_VALID
 static inline int pfn_valid(unsigned long pfn)
 {
+       struct mem_section *ms;
+
        if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS)
                return 0;
-       return valid_section(__nr_to_section(pfn_to_section_nr(pfn)));
+       ms = __nr_to_section(pfn_to_section_nr(pfn));
+       if (!valid_section(ms))
+               return 0;
+       /*
+        * Traditionally early sections always returned pfn_valid() for
+        * the entire section-sized span.
+        */
+       return early_section(ms) || pfn_section_valid(ms, pfn);
 }
 #endif
 
@@ -1330,6 +1379,7 @@ void sparse_init(void);
 #define sparse_init()  do {} while (0)
 #define sparse_index_init(_sec, _nid)  do {} while (0)
 #define pfn_present pfn_valid
+#define subsection_map_init(_pfn, _nr_pages) do {} while (0)
 #endif /* CONFIG_SPARSEMEM */
 
 /*
index 31013c2..5229c18 100644 (file)
@@ -29,6 +29,11 @@ void *module_alloc(unsigned long size);
 /* Free memory returned from module_alloc. */
 void module_memfree(void *module_region);
 
+/* Determines if the section name is an exit section (that is only used during
+ * module unloading)
+ */
+bool module_exit_section(const char *name);
+
 /*
  * Apply the given relocation to the (simplified) ELF.  Return -error
  * or 0.
index d48e919..8ad679e 100644 (file)
@@ -64,6 +64,10 @@ struct ti_sci_inta_msi_desc {
  * @msg:       The last set MSI message cached for reuse
  * @affinity:  Optional pointer to a cpu affinity mask for this descriptor
  *
+ * @write_msi_msg:     Callback that may be called when the MSI message
+ *                     address or data changes
+ * @write_msi_msg_data:        Data parameter for the callback.
+ *
  * @masked:    [PCI MSI/X] Mask bits
  * @is_msix:   [PCI MSI/X] True if MSI-X
  * @multiple:  [PCI MSI/X] log2 num of messages allocated
@@ -90,6 +94,9 @@ struct msi_desc {
        const void                      *iommu_cookie;
 #endif
 
+       void (*write_msi_msg)(struct msi_desc *entry, void *data);
+       void *write_msi_msg_data;
+
        union {
                /* PCI MSI/X specific data */
                struct {
@@ -100,6 +107,7 @@ struct msi_desc {
                                u8      multi_cap       : 3;
                                u8      maskbit         : 1;
                                u8      is_64           : 1;
+                               u8      is_virtual      : 1;
                                u16     entry_nr;
                                unsigned default_irq;
                        } msi_attrib;
index 3093dd1..dcd03fe 100644 (file)
@@ -151,7 +151,7 @@ static inline bool mutex_is_locked(struct mutex *lock)
 
 /*
  * See kernel/locking/mutex.c for detailed documentation of these APIs.
- * Also see Documentation/locking/mutex-design.txt.
+ * Also see Documentation/locking/mutex-design.rst.
  */
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 extern void mutex_lock_nested(struct mutex *lock, unsigned int subclass);
index 91d6275..19df783 100644 (file)
@@ -1,7 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /****************************************************************************
- * ip_conntrack_h323_asn1.h - BER and PER decoding library for H.323
- *                           conntrack/NAT module.
+ * BER and PER decoding library for H.323 conntrack/NAT module.
  *
  * Copyright (c) 2006 by Jing Min Zhao <zhaojingmin@users.sourceforge.net>
  *
index 22494d1..fd59904 100644 (file)
@@ -660,6 +660,7 @@ enum pnfs_update_layout_reason {
        PNFS_UPDATE_LAYOUT_BLOCKED,
        PNFS_UPDATE_LAYOUT_INVALID_OPEN,
        PNFS_UPDATE_LAYOUT_SEND_LAYOUTGET,
+       PNFS_UPDATE_LAYOUT_EXIT,
 };
 
 #define NFS4_OP_MAP_NUM_LONGS                                  \
index d363d57..0a11712 100644 (file)
@@ -223,6 +223,8 @@ struct nfs4_copy_state {
 #define NFS_INO_INVALID_MTIME  BIT(10)         /* cached mtime is invalid */
 #define NFS_INO_INVALID_SIZE   BIT(11)         /* cached size is invalid */
 #define NFS_INO_INVALID_OTHER  BIT(12)         /* other attrs are invalid */
+#define NFS_INO_DATA_INVAL_DEFER       \
+                               BIT(13)         /* Deferred cache invalidation */
 
 #define NFS_INO_INVALID_ATTR   (NFS_INO_INVALID_CHANGE \
                | NFS_INO_INVALID_CTIME \
index 1e78032..a87fe85 100644 (file)
@@ -58,6 +58,7 @@ struct nfs_client {
        struct nfs_subversion * cl_nfs_mod;     /* pointer to nfs version module */
 
        u32                     cl_minorversion;/* NFSv4 minorversion */
+       unsigned int            cl_nconnect;    /* Number of connections */
        const char *            cl_principal;  /* used for machine cred */
 
 #if IS_ENABLED(CONFIG_NFS_V4)
index 1a557c5..4866f32 100644 (file)
@@ -137,10 +137,7 @@ static inline int register_one_node(int nid)
 extern void unregister_one_node(int nid);
 extern int register_cpu_under_node(unsigned int cpu, unsigned int nid);
 extern int unregister_cpu_under_node(unsigned int cpu, unsigned int nid);
-extern int register_mem_sect_under_node(struct memory_block *mem_blk,
-                                               void *arg);
-extern int unregister_mem_sect_under_nodes(struct memory_block *mem_blk,
-                                          unsigned long phys_index);
+extern void unregister_memory_block_under_nodes(struct memory_block *mem_blk);
 
 extern int register_memory_node_under_compute_node(unsigned int mem_nid,
                                                   unsigned int cpu_nid,
@@ -171,15 +168,8 @@ static inline int unregister_cpu_under_node(unsigned int cpu, unsigned int nid)
 {
        return 0;
 }
-static inline int register_mem_sect_under_node(struct memory_block *mem_blk,
-                                                       void *arg)
+static inline void unregister_memory_block_under_nodes(struct memory_block *mem_blk)
 {
-       return 0;
-}
-static inline int unregister_mem_sect_under_nodes(struct memory_block *mem_blk,
-                                                 unsigned long phys_index)
-{
-       return 0;
 }
 
 static inline void register_hugetlbfs_with_node(node_registration_func_t reg,
index 56a92e3..8c13538 100644 (file)
 
 #include <linux/completion.h>
 #include <linux/device.h>
+#include <linux/interrupt.h>
 
 struct ntb_client;
 struct ntb_dev;
+struct ntb_msi;
 struct pci_dev;
 
 /**
@@ -205,7 +207,7 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
 }
 
 /**
- * struct ntb_ctx_ops - ntb device operations
+ * struct ntb_dev_ops - ntb device operations
  * @port_number:       See ntb_port_number().
  * @peer_port_count:   See ntb_peer_port_count().
  * @peer_port_number:  See ntb_peer_port_number().
@@ -404,7 +406,7 @@ struct ntb_client {
 #define drv_ntb_client(__drv) container_of((__drv), struct ntb_client, drv)
 
 /**
- * struct ntb_device - ntb device
+ * struct ntb_dev - ntb device
  * @dev:               Linux device object.
  * @pdev:              PCI device entry of the ntb.
  * @topo:              Detected topology of the ntb.
@@ -426,6 +428,10 @@ struct ntb_dev {
        spinlock_t                      ctx_lock;
        /* block unregister until device is fully released */
        struct completion               released;
+
+#ifdef CONFIG_NTB_MSI
+       struct ntb_msi *msi;
+#endif
 };
 #define dev_ntb(__dev) container_of((__dev), struct ntb_dev, dev)
 
@@ -616,7 +622,6 @@ static inline int ntb_port_number(struct ntb_dev *ntb)
 
        return ntb->ops->port_number(ntb);
 }
-
 /**
  * ntb_peer_port_count() - get the number of peer device ports
  * @ntb:       NTB device context.
@@ -654,6 +659,58 @@ static inline int ntb_peer_port_number(struct ntb_dev *ntb, int pidx)
 }
 
 /**
+ * ntb_logical_port_number() - get the logical port number of the local port
+ * @ntb:       NTB device context.
+ *
+ * The Logical Port Number is defined to be a unique number for each
+ * port starting from zero through to the number of ports minus one.
+ * This is in contrast to the Port Number where each port can be assigned
+ * any unique physical number by the hardware.
+ *
+ * The logical port number is useful for calculating the resource indexes
+ * used by peers.
+ *
+ * Return: the logical port number or negative value indicating an error
+ */
+static inline int ntb_logical_port_number(struct ntb_dev *ntb)
+{
+       int lport = ntb_port_number(ntb);
+       int pidx;
+
+       if (lport < 0)
+               return lport;
+
+       for (pidx = 0; pidx < ntb_peer_port_count(ntb); pidx++)
+               if (lport <= ntb_peer_port_number(ntb, pidx))
+                       return pidx;
+
+       return pidx;
+}
+
+/**
+ * ntb_peer_logical_port_number() - get the logical peer port by given index
+ * @ntb:       NTB device context.
+ * @pidx:      Peer port index.
+ *
+ * The Logical Port Number is defined to be a unique number for each
+ * port starting from zero through to the number of ports minus one.
+ * This is in contrast to the Port Number where each port can be assigned
+ * any unique physical number by the hardware.
+ *
+ * The logical port number is useful for calculating the resource indexes
+ * used by peers.
+ *
+ * Return: the peer's logical port number or negative value indicating an error
+ */
+static inline int ntb_peer_logical_port_number(struct ntb_dev *ntb, int pidx)
+{
+       if (ntb_peer_port_number(ntb, pidx) < ntb_port_number(ntb))
+               return pidx;
+       else
+               return pidx + 1;
+}
+
+/**
  * ntb_peer_port_idx() - get the peer device port index by given port number
  * @ntb:       NTB device context.
  * @port:      Peer port number.
@@ -1506,4 +1563,141 @@ static inline int ntb_peer_msg_write(struct ntb_dev *ntb, int pidx, int midx,
        return ntb->ops->peer_msg_write(ntb, pidx, midx, msg);
 }
 
+/**
+ * ntb_peer_resource_idx() - get a resource index for a given peer idx
+ * @ntb:       NTB device context.
+ * @pidx:      Peer port index.
+ *
+ * When constructing a graph of peers, each remote peer must use a different
+ * resource index (mw, doorbell, etc) to communicate with each other
+ * peer.
+ *
+ * In a two peer system, this function should always return 0 such that
+ * resource 0 points to the remote peer on both ports.
+ *
+ * In a 5 peer system, this function will return the following matrix
+ *
+ * pidx \ port    0    1    2    3    4
+ * 0              0    0    1    2    3
+ * 1              0    1    1    2    3
+ * 2              0    1    2    2    3
+ * 3              0    1    2    3    3
+ *
+ * For example, if this function is used to program peer's memory
+ * windows, port 0 will program MW 0 on all it's peers to point to itself.
+ * port 1 will program MW 0 in port 0 to point to itself and MW 1 on all
+ * other ports. etc.
+ *
+ * For the legacy two host case, ntb_port_number() and ntb_peer_port_number()
+ * both return zero and therefore this function will always return zero.
+ * So MW 0 on each host would be programmed to point to the other host.
+ *
+ * Return: the resource index to use for that peer.
+ */
+static inline int ntb_peer_resource_idx(struct ntb_dev *ntb, int pidx)
+{
+       int local_port, peer_port;
+
+       if (pidx >= ntb_peer_port_count(ntb))
+               return -EINVAL;
+
+       local_port = ntb_logical_port_number(ntb);
+       peer_port = ntb_peer_logical_port_number(ntb, pidx);
+
+       if (peer_port < local_port)
+               return local_port - 1;
+       else
+               return local_port;
+}
+
+/**
+ * ntb_peer_highest_mw_idx() - get a memory window index for a given peer idx
+ *     using the highest index memory windows first
+ *
+ * @ntb:       NTB device context.
+ * @pidx:      Peer port index.
+ *
+ * Like ntb_peer_resource_idx(), except it returns indexes starting with
+ * last memory window index.
+ *
+ * Return: the resource index to use for that peer.
+ */
+static inline int ntb_peer_highest_mw_idx(struct ntb_dev *ntb, int pidx)
+{
+       int ret;
+
+       ret = ntb_peer_resource_idx(ntb, pidx);
+       if (ret < 0)
+               return ret;
+
+       return ntb_mw_count(ntb, pidx) - ret - 1;
+}
+
+struct ntb_msi_desc {
+       u32 addr_offset;
+       u32 data;
+};
+
+#ifdef CONFIG_NTB_MSI
+
+int ntb_msi_init(struct ntb_dev *ntb, void (*desc_changed)(void *ctx));
+int ntb_msi_setup_mws(struct ntb_dev *ntb);
+void ntb_msi_clear_mws(struct ntb_dev *ntb);
+int ntbm_msi_request_threaded_irq(struct ntb_dev *ntb, irq_handler_t handler,
+                                 irq_handler_t thread_fn,
+                                 const char *name, void *dev_id,
+                                 struct ntb_msi_desc *msi_desc);
+void ntbm_msi_free_irq(struct ntb_dev *ntb, unsigned int irq, void *dev_id);
+int ntb_msi_peer_trigger(struct ntb_dev *ntb, int peer,
+                        struct ntb_msi_desc *desc);
+int ntb_msi_peer_addr(struct ntb_dev *ntb, int peer,
+                     struct ntb_msi_desc *desc,
+                     phys_addr_t *msi_addr);
+
+#else /* not CONFIG_NTB_MSI */
+
+static inline int ntb_msi_init(struct ntb_dev *ntb,
+                              void (*desc_changed)(void *ctx))
+{
+       return -EOPNOTSUPP;
+}
+static inline int ntb_msi_setup_mws(struct ntb_dev *ntb)
+{
+       return -EOPNOTSUPP;
+}
+static inline void ntb_msi_clear_mws(struct ntb_dev *ntb) {}
+static inline int ntbm_msi_request_threaded_irq(struct ntb_dev *ntb,
+                                               irq_handler_t handler,
+                                               irq_handler_t thread_fn,
+                                               const char *name, void *dev_id,
+                                               struct ntb_msi_desc *msi_desc)
+{
+       return -EOPNOTSUPP;
+}
+static inline void ntbm_msi_free_irq(struct ntb_dev *ntb, unsigned int irq,
+                                    void *dev_id) {}
+static inline int ntb_msi_peer_trigger(struct ntb_dev *ntb, int peer,
+                                      struct ntb_msi_desc *desc)
+{
+       return -EOPNOTSUPP;
+}
+static inline int ntb_msi_peer_addr(struct ntb_dev *ntb, int peer,
+                                   struct ntb_msi_desc *desc,
+                                   phys_addr_t *msi_addr)
+{
+       return -EOPNOTSUPP;
+
+}
+
+#endif /* CONFIG_NTB_MSI */
+
+static inline int ntbm_msi_request_irq(struct ntb_dev *ntb,
+                                      irq_handler_t handler,
+                                      const char *name, void *dev_id,
+                                      struct ntb_msi_desc *msi_desc)
+{
+       return ntbm_msi_request_threaded_irq(ntb, handler, NULL, name,
+                                            dev_id, msi_desc);
+}
+
 #endif
index 2972793..9e700d9 100644 (file)
@@ -1412,6 +1412,15 @@ int pci_set_vga_state(struct pci_dev *pdev, bool decode,
 #define PCI_IRQ_MSI            (1 << 1) /* Allow MSI interrupts */
 #define PCI_IRQ_MSIX           (1 << 2) /* Allow MSI-X interrupts */
 #define PCI_IRQ_AFFINITY       (1 << 3) /* Auto-assign affinity */
+
+/*
+ * Virtual interrupts allow for more interrupts to be allocated
+ * than the device has interrupts for. These are not programmed
+ * into the device's MSI-X table and must be handled by some
+ * other driver means.
+ */
+#define PCI_IRQ_VIRTUAL                (1 << 4)
+
 #define PCI_IRQ_ALL_TYPES \
        (PCI_IRQ_LEGACY | PCI_IRQ_MSI | PCI_IRQ_MSIX)
 
index 4001560..c842735 100644 (file)
 #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3                0xabcd
 #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI    0xabce
 #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31       0xabcf
+#define PCI_DEVICE_ID_SYNOPSYS_EDDA    0xedda
 
 #define PCI_VENDOR_ID_USR              0x16ec
 
index 01e8037..2d91482 100644 (file)
@@ -97,7 +97,7 @@ static inline pud_t pfn_t_pud(pfn_t pfn, pgprot_t pgprot)
 #endif
 #endif
 
-#ifdef __HAVE_ARCH_PTE_DEVMAP
+#ifdef CONFIG_ARCH_HAS_PTE_DEVMAP
 static inline bool pfn_t_devmap(pfn_t pfn)
 {
        const u64 flags = PFN_DEV|PFN_MAP;
@@ -115,7 +115,7 @@ pmd_t pmd_mkdevmap(pmd_t pmd);
        defined(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD)
 pud_t pud_mkdevmap(pud_t pud);
 #endif
-#endif /* __HAVE_ARCH_PTE_DEVMAP */
+#endif /* CONFIG_ARCH_HAS_PTE_DEVMAP */
 
 #ifdef CONFIG_ARCH_HAS_PTE_SPECIAL
 static inline bool pfn_t_special(pfn_t pfn)
index 1484db6..2a83e43 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <linux/rculist.h>
 #include <linux/wait.h>
+#include <linux/refcount.h>
 
 enum pid_type
 {
@@ -57,7 +58,7 @@ struct upid {
 
 struct pid
 {
-       atomic_t count;
+       refcount_t count;
        unsigned int level;
        /* lists of tasks that use this pid */
        struct hlist_head tasks[PIDTYPE_MAX];
@@ -74,7 +75,7 @@ extern const struct file_operations pidfd_fops;
 static inline struct pid *get_pid(struct pid *pid)
 {
        if (pid)
-               atomic_inc(&pid->count);
+               refcount_inc(&pid->count);
        return pid;
 }
 
index 80f9be8..281adbb 100644 (file)
@@ -52,7 +52,6 @@ struct imx_dma_data {
        int dma_request2; /* secondary DMA request line */
        enum sdma_peripheral_type peripheral_type;
        int priority;
-       struct device_node *of_node;
 };
 
 static inline int imx_dma_is_ipu(struct dma_chan *chan)
index 9256c03..0c587d4 100644 (file)
@@ -19,6 +19,7 @@ enum ti_sysc_module_type {
 
 struct ti_sysc_cookie {
        void *data;
+       void *clkdm;
 };
 
 /**
@@ -46,6 +47,10 @@ struct sysc_regbits {
        s8 emufree_shift;
 };
 
+#define SYSC_MODULE_QUIRK_HDQ1W                BIT(17)
+#define SYSC_MODULE_QUIRK_I2C          BIT(16)
+#define SYSC_MODULE_QUIRK_WDT          BIT(15)
+#define SYSS_QUIRK_RESETDONE_INVERTED  BIT(14)
 #define SYSC_QUIRK_SWSUP_MSTANDBY      BIT(13)
 #define SYSC_QUIRK_SWSUP_SIDLE_ACT     BIT(12)
 #define SYSC_QUIRK_SWSUP_SIDLE         BIT(11)
@@ -125,9 +130,16 @@ struct ti_sysc_module_data {
 };
 
 struct device;
+struct clk;
 
 struct ti_sysc_platform_data {
        struct of_dev_auxdata *auxdata;
+       int (*init_clockdomain)(struct device *dev, struct clk *fck,
+                               struct clk *ick, struct ti_sysc_cookie *cookie);
+       void (*clkdm_deny_idle)(struct device *dev,
+                               const struct ti_sysc_cookie *cookie);
+       void (*clkdm_allow_idle)(struct device *dev,
+                                const struct ti_sysc_cookie *cookie);
        int (*init_module)(struct device *dev,
                           const struct ti_sysc_module_data *data,
                           struct ti_sysc_cookie *cookie);
diff --git a/include/linux/platform_data/video-clcd-versatile.h b/include/linux/platform_data/video-clcd-versatile.h
deleted file mode 100644 (file)
index 305ebae..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef PLAT_CLCD_H
-#define PLAT_CLCD_H
-
-#ifdef CONFIG_PLAT_VERSATILE_CLCD
-struct clcd_panel *versatile_clcd_get_panel(const char *);
-int versatile_clcd_setup_dma(struct clcd_fb *, unsigned long);
-int versatile_clcd_mmap_dma(struct clcd_fb *, struct vm_area_struct *);
-void versatile_clcd_remove_dma(struct clcd_fb *);
-#else
-static inline struct clcd_panel *versatile_clcd_get_panel(const char *s)
-{
-       return NULL;
-}
-static inline int versatile_clcd_setup_dma(struct clcd_fb *fb, unsigned long framesize)
-{
-       return -ENODEV;
-}
-static inline int versatile_clcd_mmap_dma(struct clcd_fb *fb, struct vm_area_struct *vm)
-{
-       return -ENODEV;
-}
-static inline void versatile_clcd_remove_dma(struct clcd_fb *fb)
-{
-}
-#endif
-
-#endif
index 8551156..4802cd2 100644 (file)
@@ -57,7 +57,7 @@
 #define ASUS_WMI_DEVID_KBD_BACKLIGHT   0x00050021
 #define ASUS_WMI_DEVID_LIGHT_SENSOR    0x00050022 /* ?? */
 #define ASUS_WMI_DEVID_LIGHTBAR                0x00050025
-#define ASUS_WMI_DEVID_FAN_MODE                0x00110018
+#define ASUS_WMI_DEVID_FAN_BOOST_MODE  0x00110018
 
 /* Misc */
 #define ASUS_WMI_DEVID_CAMERA          0x00060013
index beb25f2..9bc36b5 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Copyright (c) 2001-2003 Patrick Mochel <mochel@osdl.org>
  *
- * See Documentation/driver-model/ for more information.
+ * See Documentation/driver-api/driver-model/ for more information.
  */
 
 #ifndef _PLATFORM_DEVICE_H_
index 6ea1ae3..2aebbc5 100644 (file)
@@ -40,6 +40,8 @@ enum pm_qos_flags_status {
 #define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT    PM_QOS_LATENCY_ANY
 #define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS PM_QOS_LATENCY_ANY_NS
 #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE 0
+#define PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE     0
+#define PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE     (-1)
 #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT (-1)
 
 #define PM_QOS_FLAG_NO_POWER_OFF       (1 << 0)
@@ -58,6 +60,8 @@ struct pm_qos_flags_request {
 enum dev_pm_qos_req_type {
        DEV_PM_QOS_RESUME_LATENCY = 1,
        DEV_PM_QOS_LATENCY_TOLERANCE,
+       DEV_PM_QOS_MIN_FREQUENCY,
+       DEV_PM_QOS_MAX_FREQUENCY,
        DEV_PM_QOS_FLAGS,
 };
 
@@ -99,10 +103,14 @@ struct pm_qos_flags {
 struct dev_pm_qos {
        struct pm_qos_constraints resume_latency;
        struct pm_qos_constraints latency_tolerance;
+       struct pm_qos_constraints min_frequency;
+       struct pm_qos_constraints max_frequency;
        struct pm_qos_flags flags;
        struct dev_pm_qos_request *resume_latency_req;
        struct dev_pm_qos_request *latency_tolerance_req;
        struct dev_pm_qos_request *flags_req;
+       struct dev_pm_qos_request *min_frequency_req;
+       struct dev_pm_qos_request *max_frequency_req;
 };
 
 /* Action requested to pm_qos_update_target */
@@ -139,16 +147,18 @@ s32 pm_qos_read_value(struct pm_qos_constraints *c);
 #ifdef CONFIG_PM
 enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask);
 enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask);
-s32 __dev_pm_qos_read_value(struct device *dev);
-s32 dev_pm_qos_read_value(struct device *dev);
+s32 __dev_pm_qos_resume_latency(struct device *dev);
+s32 dev_pm_qos_read_value(struct device *dev, enum dev_pm_qos_req_type type);
 int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
                           enum dev_pm_qos_req_type type, s32 value);
 int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value);
 int dev_pm_qos_remove_request(struct dev_pm_qos_request *req);
 int dev_pm_qos_add_notifier(struct device *dev,
-                           struct notifier_block *notifier);
+                           struct notifier_block *notifier,
+                           enum dev_pm_qos_req_type type);
 int dev_pm_qos_remove_notifier(struct device *dev,
-                              struct notifier_block *notifier);
+                              struct notifier_block *notifier,
+                              enum dev_pm_qos_req_type type);
 void dev_pm_qos_constraints_init(struct device *dev);
 void dev_pm_qos_constraints_destroy(struct device *dev);
 int dev_pm_qos_add_ancestor_request(struct device *dev,
@@ -174,7 +184,7 @@ static inline s32 dev_pm_qos_requested_flags(struct device *dev)
        return dev->power.qos->flags_req->data.flr.flags;
 }
 
-static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
+static inline s32 dev_pm_qos_raw_resume_latency(struct device *dev)
 {
        return IS_ERR_OR_NULL(dev->power.qos) ?
                PM_QOS_RESUME_LATENCY_NO_CONSTRAINT :
@@ -187,10 +197,24 @@ static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev,
 static inline enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev,
                                                        s32 mask)
                        { return PM_QOS_FLAGS_UNDEFINED; }
-static inline s32 __dev_pm_qos_read_value(struct device *dev)
-                       { return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
-static inline s32 dev_pm_qos_read_value(struct device *dev)
+static inline s32 __dev_pm_qos_resume_latency(struct device *dev)
                        { return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
+static inline s32 dev_pm_qos_read_value(struct device *dev,
+                                       enum dev_pm_qos_req_type type)
+{
+       switch (type) {
+       case DEV_PM_QOS_RESUME_LATENCY:
+               return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+       case DEV_PM_QOS_MIN_FREQUENCY:
+               return PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE;
+       case DEV_PM_QOS_MAX_FREQUENCY:
+               return PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
+       default:
+               WARN_ON(1);
+               return 0;
+       }
+}
+
 static inline int dev_pm_qos_add_request(struct device *dev,
                                         struct dev_pm_qos_request *req,
                                         enum dev_pm_qos_req_type type,
@@ -202,10 +226,12 @@ static inline int dev_pm_qos_update_request(struct dev_pm_qos_request *req,
 static inline int dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
                        { return 0; }
 static inline int dev_pm_qos_add_notifier(struct device *dev,
-                                         struct notifier_block *notifier)
+                                         struct notifier_block *notifier,
+                                         enum dev_pm_qos_req_type type)
                        { return 0; }
 static inline int dev_pm_qos_remove_notifier(struct device *dev,
-                                            struct notifier_block *notifier)
+                                            struct notifier_block *notifier,
+                                            enum dev_pm_qos_req_type type)
                        { return 0; }
 static inline void dev_pm_qos_constraints_init(struct device *dev)
 {
@@ -241,7 +267,7 @@ static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev)
        return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
 }
 static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; }
-static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
+static inline s32 dev_pm_qos_raw_resume_latency(struct device *dev)
 {
        return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
 }
index d6d980a..df34330 100644 (file)
@@ -21,7 +21,7 @@
  * non-initialized list entries.
  */
 #define LIST_POISON1  ((void *) 0x100 + POISON_POINTER_DELTA)
-#define LIST_POISON2  ((void *) 0x200 + POISON_POINTER_DELTA)
+#define LIST_POISON2  ((void *) 0x122 + POISON_POINTER_DELTA)
 
 /********** include/linux/timer.h **********/
 /*
diff --git a/include/linux/pseudo_fs.h b/include/linux/pseudo_fs.h
new file mode 100644 (file)
index 0000000..eceda1d
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __LINUX_PSEUDO_FS__
+#define __LINUX_PSEUDO_FS__
+
+#include <linux/fs_context.h>
+
+struct pseudo_fs_context {
+       const struct super_operations *ops;
+       const struct xattr_handler **xattr;
+       const struct dentry_operations *dops;
+       unsigned long magic;
+};
+
+struct pseudo_fs_context *init_pseudo(struct fs_context *fc,
+                                     unsigned long magic);
+
+#endif
index 5ef7d54..ee582bd 100644 (file)
@@ -19,7 +19,6 @@ extern int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize);
 
 extern const struct file_operations ramfs_file_operations;
 extern const struct vm_operations_struct generic_file_vm_ops;
-extern int __init init_ramfs_fs(void);
 
 int ramfs_fill_super(struct super_block *sb, void *data, int silent);
 
index e6337fc..1fd61a9 100644 (file)
@@ -32,25 +32,9 @@ struct rb_root {
        struct rb_node *rb_node;
 };
 
-/*
- * Leftmost-cached rbtrees.
- *
- * We do not cache the rightmost node based on footprint
- * size vs number of potential users that could benefit
- * from O(1) rb_last(). Just not worth it, users that want
- * this feature can always implement the logic explicitly.
- * Furthermore, users that want to cache both pointers may
- * find it a bit asymmetric, but that's ok.
- */
-struct rb_root_cached {
-       struct rb_root rb_root;
-       struct rb_node *rb_leftmost;
-};
-
 #define rb_parent(r)   ((struct rb_node *)((r)->__rb_parent_color & ~3))
 
 #define RB_ROOT        (struct rb_root) { NULL, }
-#define RB_ROOT_CACHED (struct rb_root_cached) { {NULL, }, NULL }
 #define        rb_entry(ptr, type, member) container_of(ptr, type, member)
 
 #define RB_EMPTY_ROOT(root)  (READ_ONCE((root)->rb_node) == NULL)
@@ -72,12 +56,6 @@ extern struct rb_node *rb_prev(const struct rb_node *);
 extern struct rb_node *rb_first(const struct rb_root *);
 extern struct rb_node *rb_last(const struct rb_root *);
 
-extern void rb_insert_color_cached(struct rb_node *,
-                                  struct rb_root_cached *, bool);
-extern void rb_erase_cached(struct rb_node *node, struct rb_root_cached *);
-/* Same as rb_first(), but O(1) */
-#define rb_first_cached(root) (root)->rb_leftmost
-
 /* Postorder iteration - always visit the parent after its children */
 extern struct rb_node *rb_first_postorder(const struct rb_root *);
 extern struct rb_node *rb_next_postorder(const struct rb_node *);
@@ -87,8 +65,6 @@ extern void rb_replace_node(struct rb_node *victim, struct rb_node *new,
                            struct rb_root *root);
 extern void rb_replace_node_rcu(struct rb_node *victim, struct rb_node *new,
                                struct rb_root *root);
-extern void rb_replace_node_cached(struct rb_node *victim, struct rb_node *new,
-                                  struct rb_root_cached *root);
 
 static inline void rb_link_node(struct rb_node *node, struct rb_node *parent,
                                struct rb_node **rb_link)
@@ -136,4 +112,50 @@ static inline void rb_link_node_rcu(struct rb_node *node, struct rb_node *parent
                        typeof(*pos), field); 1; }); \
             pos = n)
 
+/*
+ * Leftmost-cached rbtrees.
+ *
+ * We do not cache the rightmost node based on footprint
+ * size vs number of potential users that could benefit
+ * from O(1) rb_last(). Just not worth it, users that want
+ * this feature can always implement the logic explicitly.
+ * Furthermore, users that want to cache both pointers may
+ * find it a bit asymmetric, but that's ok.
+ */
+struct rb_root_cached {
+       struct rb_root rb_root;
+       struct rb_node *rb_leftmost;
+};
+
+#define RB_ROOT_CACHED (struct rb_root_cached) { {NULL, }, NULL }
+
+/* Same as rb_first(), but O(1) */
+#define rb_first_cached(root) (root)->rb_leftmost
+
+static inline void rb_insert_color_cached(struct rb_node *node,
+                                         struct rb_root_cached *root,
+                                         bool leftmost)
+{
+       if (leftmost)
+               root->rb_leftmost = node;
+       rb_insert_color(node, &root->rb_root);
+}
+
+static inline void rb_erase_cached(struct rb_node *node,
+                                  struct rb_root_cached *root)
+{
+       if (root->rb_leftmost == node)
+               root->rb_leftmost = rb_next(node);
+       rb_erase(node, &root->rb_root);
+}
+
+static inline void rb_replace_node_cached(struct rb_node *victim,
+                                         struct rb_node *new,
+                                         struct rb_root_cached *root)
+{
+       if (root->rb_leftmost == victim)
+               root->rb_leftmost = new;
+       rb_replace_node(victim, new, &root->rb_root);
+}
+
 #endif /* _LINUX_RBTREE_H */
index 0f902cc..179faab 100644 (file)
@@ -30,10 +30,9 @@ struct rb_augment_callbacks {
        void (*rotate)(struct rb_node *old, struct rb_node *new);
 };
 
-extern void __rb_insert_augmented(struct rb_node *node,
-                                 struct rb_root *root,
-                                 bool newleft, struct rb_node **leftmost,
+extern void __rb_insert_augmented(struct rb_node *node, struct rb_root *root,
        void (*augment_rotate)(struct rb_node *old, struct rb_node *new));
+
 /*
  * Fixup the rbtree and update the augmented information when rebalancing.
  *
@@ -48,7 +47,7 @@ static inline void
 rb_insert_augmented(struct rb_node *node, struct rb_root *root,
                    const struct rb_augment_callbacks *augment)
 {
-       __rb_insert_augmented(node, root, false, NULL, augment->rotate);
+       __rb_insert_augmented(node, root, augment->rotate);
 }
 
 static inline void
@@ -56,8 +55,9 @@ rb_insert_augmented_cached(struct rb_node *node,
                           struct rb_root_cached *root, bool newleft,
                           const struct rb_augment_callbacks *augment)
 {
-       __rb_insert_augmented(node, &root->rb_root,
-                             newleft, &root->rb_leftmost, augment->rotate);
+       if (newleft)
+               root->rb_leftmost = node;
+       rb_insert_augmented(node, &root->rb_root, augment);
 }
 
 #define RB_DECLARE_CALLBACKS(rbstatic, rbname, rbstruct, rbfield,      \
@@ -150,7 +150,6 @@ extern void __rb_erase_color(struct rb_node *parent, struct rb_root *root,
 
 static __always_inline struct rb_node *
 __rb_erase_augmented(struct rb_node *node, struct rb_root *root,
-                    struct rb_node **leftmost,
                     const struct rb_augment_callbacks *augment)
 {
        struct rb_node *child = node->rb_right;
@@ -158,9 +157,6 @@ __rb_erase_augmented(struct rb_node *node, struct rb_root *root,
        struct rb_node *parent, *rebalance;
        unsigned long pc;
 
-       if (leftmost && node == *leftmost)
-               *leftmost = rb_next(node);
-
        if (!tmp) {
                /*
                 * Case 1: node to erase has no more than 1 child (easy!)
@@ -260,8 +256,7 @@ static __always_inline void
 rb_erase_augmented(struct rb_node *node, struct rb_root *root,
                   const struct rb_augment_callbacks *augment)
 {
-       struct rb_node *rebalance = __rb_erase_augmented(node, root,
-                                                        NULL, augment);
+       struct rb_node *rebalance = __rb_erase_augmented(node, root, augment);
        if (rebalance)
                __rb_erase_color(rebalance, root, augment->rotate);
 }
@@ -270,11 +265,9 @@ static __always_inline void
 rb_erase_augmented_cached(struct rb_node *node, struct rb_root_cached *root,
                          const struct rb_augment_callbacks *augment)
 {
-       struct rb_node *rebalance = __rb_erase_augmented(node, &root->rb_root,
-                                                        &root->rb_leftmost,
-                                                        augment);
-       if (rebalance)
-               __rb_erase_color(rebalance, &root->rb_root, augment->rotate);
+       if (root->rb_leftmost == node)
+               root->rb_leftmost = rb_next(node);
+       rb_erase_augmented(node, &root->rb_root, augment);
 }
 
 #endif /* _LINUX_RBTREE_AUGMENTED_H */
index 04d0470..16ad666 100644 (file)
@@ -100,7 +100,9 @@ struct fw_rsc_hdr {
  *                 the remote processor will be writing logs.
  * @RSC_VDEV:       declare support for a virtio device, and serve as its
  *                 virtio header.
- * @RSC_LAST:       just keep this one at the end
+ * @RSC_LAST:       just keep this one at the end of standard resources
+ * @RSC_VENDOR_START:  start of the vendor specific resource types range
+ * @RSC_VENDOR_END:    end of the vendor specific resource types range
  *
  * For more details regarding a specific resource type, please see its
  * dedicated structure below.
@@ -111,11 +113,13 @@ struct fw_rsc_hdr {
  * please update it as needed.
  */
 enum fw_resource_type {
-       RSC_CARVEOUT    = 0,
-       RSC_DEVMEM      = 1,
-       RSC_TRACE       = 2,
-       RSC_VDEV        = 3,
-       RSC_LAST        = 4,
+       RSC_CARVEOUT            = 0,
+       RSC_DEVMEM              = 1,
+       RSC_TRACE               = 2,
+       RSC_VDEV                = 3,
+       RSC_LAST                = 4,
+       RSC_VENDOR_START        = 128,
+       RSC_VENDOR_END          = 512,
 };
 
 #define FW_RSC_ADDR_ANY (-1)
@@ -340,12 +344,26 @@ struct rproc_mem_entry {
 struct firmware;
 
 /**
+ * enum rsc_handling_status - return status of rproc_ops handle_rsc hook
+ * @RSC_HANDLED:       resource was handled
+ * @RSC_IGNORED:       resource was ignored
+ */
+enum rsc_handling_status {
+       RSC_HANDLED     = 0,
+       RSC_IGNORED     = 1,
+};
+
+/**
  * struct rproc_ops - platform-specific device handlers
  * @start:     power on the device and boot it
  * @stop:      power off the device
  * @kick:      kick a virtqueue (virtqueue id given as a parameter)
  * @da_to_va:  optional platform hook to perform address translations
  * @parse_fw:  parse firmware to extract information (e.g. resource table)
+ * @handle_rsc:        optional platform hook to handle vendor resources. Should return
+ * RSC_HANDLED if resource was handled, RSC_IGNORED if not handled and a
+ * negative value on error
+ * @load_rsc_table:    load resource table from firmware image
  * @find_loaded_rsc_table: find the loaded resouce table
  * @load:              load firmware to memory, where the remote processor
  *                     expects to find it
@@ -358,6 +376,8 @@ struct rproc_ops {
        void (*kick)(struct rproc *rproc, int vqid);
        void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
        int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
+       int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc,
+                         int offset, int avail);
        struct resource_table *(*find_loaded_rsc_table)(
                                struct rproc *rproc, const struct firmware *fw);
        int (*load)(struct rproc *rproc, const struct firmware *fw);
index e401358..9d9c663 100644 (file)
@@ -160,7 +160,7 @@ extern void downgrade_write(struct rw_semaphore *sem);
  * static then another method for expressing nested locking is
  * the explicit definition of lock class keys and the use of
  * lockdep_set_class() at lock initialization time.
- * See Documentation/locking/lockdep-design.txt for more details.)
+ * See Documentation/locking/lockdep-design.rst for more details.)
  */
 extern void down_read_nested(struct rw_semaphore *sem, int subclass);
 extern void down_write_nested(struct rw_semaphore *sem, int subclass);
index b0fb144..6c8512d 100644 (file)
@@ -19,6 +19,7 @@ enum hk_flags {
 DECLARE_STATIC_KEY_FALSE(housekeeping_overridden);
 extern int housekeeping_any_cpu(enum hk_flags flags);
 extern const struct cpumask *housekeeping_cpumask(enum hk_flags flags);
+extern bool housekeeping_enabled(enum hk_flags flags);
 extern void housekeeping_affine(struct task_struct *t, enum hk_flags flags);
 extern bool housekeeping_test_cpu(int cpu, enum hk_flags flags);
 extern void __init housekeeping_init(void);
@@ -35,6 +36,11 @@ static inline const struct cpumask *housekeeping_cpumask(enum hk_flags flags)
        return cpu_possible_mask;
 }
 
+static inline bool housekeeping_enabled(enum hk_flags flags)
+{
+       return false;
+}
+
 static inline void housekeeping_affine(struct task_struct *t,
                                       enum hk_flags flags) { }
 static inline void housekeeping_init(void) { }
index 5324586..efd8ce7 100644 (file)
  */
 
 struct sighand_struct {
-       refcount_t              count;
-       struct k_sigaction      action[_NSIG];
        spinlock_t              siglock;
+       refcount_t              count;
        wait_queue_head_t       signalfd_wqh;
+       struct k_sigaction      action[_NSIG];
 };
 
 /*
@@ -420,7 +420,6 @@ void task_join_group_stop(struct task_struct *task);
 static inline void set_restore_sigmask(void)
 {
        set_thread_flag(TIF_RESTORE_SIGMASK);
-       WARN_ON(!test_thread_flag(TIF_SIGPENDING));
 }
 
 static inline void clear_tsk_restore_sigmask(struct task_struct *task)
@@ -451,7 +450,6 @@ static inline bool test_and_clear_restore_sigmask(void)
 static inline void set_restore_sigmask(void)
 {
        current->restore_sigmask = true;
-       WARN_ON(!test_thread_flag(TIF_SIGPENDING));
 }
 static inline void clear_tsk_restore_sigmask(struct task_struct *task)
 {
@@ -484,6 +482,16 @@ static inline void restore_saved_sigmask(void)
                __set_current_blocked(&current->saved_sigmask);
 }
 
+extern int set_user_sigmask(const sigset_t __user *umask, size_t sigsetsize);
+
+static inline void restore_saved_sigmask_unless(bool interrupted)
+{
+       if (interrupted)
+               WARN_ON(!test_thread_flag(TIF_SIGPENDING));
+       else
+               restore_saved_sigmask();
+}
+
 static inline sigset_t *sigmask_to_save(void)
 {
        sigset_t *res = &current->blocked;
index 109a0df..0497091 100644 (file)
@@ -89,6 +89,7 @@ extern void exit_files(struct task_struct *);
 extern void exit_itimers(struct signal_struct *);
 
 extern long _do_fork(struct kernel_clone_args *kargs);
+extern bool legacy_clone_args_valid(const struct kernel_clone_args *kargs);
 extern long do_fork(unsigned long, unsigned long, unsigned long, int __user *, int __user *);
 struct task_struct *fork_idle(int);
 struct mm_struct *copy_init_mm(void);
index 3105055..9ff2e93 100644 (file)
@@ -144,6 +144,7 @@ struct scmi_power_ops {
 struct scmi_sensor_info {
        u32 id;
        u8 type;
+       s8 scale;
        char name[SCMI_MAX_STR_SIZE];
 };
 
index 05b1790..2b78cc7 100644 (file)
@@ -32,7 +32,7 @@ struct device;
 
 /*
  * This structure describes all the operations that can be done on the
- * physical hardware.  See Documentation/serial/driver.rst for details.
+ * physical hardware.  See Documentation/driver-api/serial/driver.rst for details.
  */
 struct uart_ops {
        unsigned int    (*tx_empty)(struct uart_port *);
index 78c2bb3..b5d9948 100644 (file)
@@ -273,10 +273,6 @@ extern int group_send_sig_info(int sig, struct kernel_siginfo *info,
                               struct task_struct *p, enum pid_type type);
 extern int __group_send_sig_info(int, struct kernel_siginfo *, struct task_struct *);
 extern int sigprocmask(int, sigset_t *, sigset_t *);
-extern int set_user_sigmask(const sigset_t __user *usigmask, sigset_t *set,
-       sigset_t *oldset, size_t sigsetsize);
-extern void restore_user_sigmask(const void __user *usigmask,
-                                sigset_t *sigsaved, bool interrupted);
 extern void set_current_blocked(sigset_t *);
 extern void __set_current_blocked(const sigset_t *);
 extern int show_unhandled_signals;
index 944b06a..e600bae 100644 (file)
@@ -21,4 +21,6 @@ int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw,
                          const char *fw_name, int pas_id, void *mem_region,
                          phys_addr_t mem_phys, size_t mem_size,
                          phys_addr_t *reloc_base);
+void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len);
+
 #endif
index 568722a..6c610e1 100644 (file)
@@ -166,29 +166,29 @@ struct ti_sci_dev_ops {
  * managed by driver for that purpose.
  */
 struct ti_sci_clk_ops {
-       int (*get_clock)(const struct ti_sci_handle *handle, u32 did, u8 cid,
+       int (*get_clock)(const struct ti_sci_handle *handle, u32 did, u32 cid,
                         bool needs_ssc, bool can_change_freq,
                         bool enable_input_term);
-       int (*idle_clock)(const struct ti_sci_handle *handle, u32 did, u8 cid);
-       int (*put_clock)(const struct ti_sci_handle *handle, u32 did, u8 cid);
-       int (*is_auto)(const struct ti_sci_handle *handle, u32 did, u8 cid,
+       int (*idle_clock)(const struct ti_sci_handle *handle, u32 did, u32 cid);
+       int (*put_clock)(const struct ti_sci_handle *handle, u32 did, u32 cid);
+       int (*is_auto)(const struct ti_sci_handle *handle, u32 did, u32 cid,
                       bool *req_state);
-       int (*is_on)(const struct ti_sci_handle *handle, u32 did, u8 cid,
+       int (*is_on)(const struct ti_sci_handle *handle, u32 did, u32 cid,
                     bool *req_state, bool *current_state);
-       int (*is_off)(const struct ti_sci_handle *handle, u32 did, u8 cid,
+       int (*is_off)(const struct ti_sci_handle *handle, u32 did, u32 cid,
                      bool *req_state, bool *current_state);
-       int (*set_parent)(const struct ti_sci_handle *handle, u32 did, u8 cid,
-                         u8 parent_id);
-       int (*get_parent)(const struct ti_sci_handle *handle, u32 did, u8 cid,
-                         u8 *parent_id);
+       int (*set_parent)(const struct ti_sci_handle *handle, u32 did, u32 cid,
+                         u32 parent_id);
+       int (*get_parent)(const struct ti_sci_handle *handle, u32 did, u32 cid,
+                         u32 *parent_id);
        int (*get_num_parents)(const struct ti_sci_handle *handle, u32 did,
-                              u8 cid, u8 *num_parents);
+                              u32 cid, u32 *num_parents);
        int (*get_best_match_freq)(const struct ti_sci_handle *handle, u32 did,
-                                  u8 cid, u64 min_freq, u64 target_freq,
+                                  u32 cid, u64 min_freq, u64 target_freq,
                                   u64 max_freq, u64 *match_freq);
-       int (*set_freq)(const struct ti_sci_handle *handle, u32 did, u8 cid,
+       int (*set_freq)(const struct ti_sci_handle *handle, u32 did, u32 cid,
                        u64 min_freq, u64 target_freq, u64 max_freq);
-       int (*get_freq)(const struct ti_sci_handle *handle, u32 did, u8 cid,
+       int (*get_freq)(const struct ti_sci_handle *handle, u32 did, u32 cid,
                        u64 *current_freq);
 };
 
@@ -241,12 +241,254 @@ struct ti_sci_rm_irq_ops {
                              u16 global_event, u8 vint_status_bit);
 };
 
+/* RA config.addr_lo parameter is valid for RM ring configure TI_SCI message */
+#define TI_SCI_MSG_VALUE_RM_RING_ADDR_LO_VALID BIT(0)
+/* RA config.addr_hi parameter is valid for RM ring configure TI_SCI message */
+#define TI_SCI_MSG_VALUE_RM_RING_ADDR_HI_VALID BIT(1)
+ /* RA config.count parameter is valid for RM ring configure TI_SCI message */
+#define TI_SCI_MSG_VALUE_RM_RING_COUNT_VALID   BIT(2)
+/* RA config.mode parameter is valid for RM ring configure TI_SCI message */
+#define TI_SCI_MSG_VALUE_RM_RING_MODE_VALID    BIT(3)
+/* RA config.size parameter is valid for RM ring configure TI_SCI message */
+#define TI_SCI_MSG_VALUE_RM_RING_SIZE_VALID    BIT(4)
+/* RA config.order_id parameter is valid for RM ring configure TISCI message */
+#define TI_SCI_MSG_VALUE_RM_RING_ORDER_ID_VALID        BIT(5)
+
+#define TI_SCI_MSG_VALUE_RM_ALL_NO_ORDER \
+       (TI_SCI_MSG_VALUE_RM_RING_ADDR_LO_VALID | \
+       TI_SCI_MSG_VALUE_RM_RING_ADDR_HI_VALID | \
+       TI_SCI_MSG_VALUE_RM_RING_COUNT_VALID | \
+       TI_SCI_MSG_VALUE_RM_RING_MODE_VALID | \
+       TI_SCI_MSG_VALUE_RM_RING_SIZE_VALID)
+
+/**
+ * struct ti_sci_rm_ringacc_ops - Ring Accelerator Management operations
+ * @config: configure the SoC Navigator Subsystem Ring Accelerator ring
+ * @get_config: get the SoC Navigator Subsystem Ring Accelerator ring
+ *             configuration
+ */
+struct ti_sci_rm_ringacc_ops {
+       int (*config)(const struct ti_sci_handle *handle,
+                     u32 valid_params, u16 nav_id, u16 index,
+                     u32 addr_lo, u32 addr_hi, u32 count, u8 mode,
+                     u8 size, u8 order_id
+       );
+       int (*get_config)(const struct ti_sci_handle *handle,
+                         u32 nav_id, u32 index, u8 *mode,
+                         u32 *addr_lo, u32 *addr_hi, u32 *count,
+                         u8 *size, u8 *order_id);
+};
+
+/**
+ * struct ti_sci_rm_psil_ops - PSI-L thread operations
+ * @pair: pair PSI-L source thread to a destination thread.
+ *     If the src_thread is mapped to UDMA tchan, the corresponding channel's
+ *     TCHAN_THRD_ID register is updated.
+ *     If the dst_thread is mapped to UDMA rchan, the corresponding channel's
+ *     RCHAN_THRD_ID register is updated.
+ * @unpair: unpair PSI-L source thread from a destination thread.
+ *     If the src_thread is mapped to UDMA tchan, the corresponding channel's
+ *     TCHAN_THRD_ID register is cleared.
+ *     If the dst_thread is mapped to UDMA rchan, the corresponding channel's
+ *     RCHAN_THRD_ID register is cleared.
+ */
+struct ti_sci_rm_psil_ops {
+       int (*pair)(const struct ti_sci_handle *handle, u32 nav_id,
+                   u32 src_thread, u32 dst_thread);
+       int (*unpair)(const struct ti_sci_handle *handle, u32 nav_id,
+                     u32 src_thread, u32 dst_thread);
+};
+
+/* UDMAP channel types */
+#define TI_SCI_RM_UDMAP_CHAN_TYPE_PKT_PBRR             2
+#define TI_SCI_RM_UDMAP_CHAN_TYPE_PKT_PBRR_SB          3       /* RX only */
+#define TI_SCI_RM_UDMAP_CHAN_TYPE_3RDP_PBRR            10
+#define TI_SCI_RM_UDMAP_CHAN_TYPE_3RDP_PBVR            11
+#define TI_SCI_RM_UDMAP_CHAN_TYPE_3RDP_BCOPY_PBRR      12
+#define TI_SCI_RM_UDMAP_CHAN_TYPE_3RDP_BCOPY_PBVR      13
+
+#define TI_SCI_RM_UDMAP_RX_FLOW_DESC_HOST              0
+#define TI_SCI_RM_UDMAP_RX_FLOW_DESC_MONO              2
+
+#define TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES       1
+#define TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_128_BYTES      2
+#define TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_256_BYTES      3
+
+/* UDMAP TX/RX channel valid_params common declarations */
+#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_PAUSE_ON_ERR_VALID                BIT(0)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_ATYPE_VALID                BIT(1)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_CHAN_TYPE_VALID            BIT(2)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_FETCH_SIZE_VALID           BIT(3)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_CQ_QNUM_VALID              BIT(4)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_PRIORITY_VALID             BIT(5)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_QOS_VALID                  BIT(6)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_ORDER_ID_VALID             BIT(7)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_SCHED_PRIORITY_VALID       BIT(8)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_BURST_SIZE_VALID          BIT(14)
+
+/**
+ * Configures a Navigator Subsystem UDMAP transmit channel
+ *
+ * Configures a Navigator Subsystem UDMAP transmit channel registers.
+ * See @ti_sci_msg_rm_udmap_tx_ch_cfg_req
+ */
+struct ti_sci_msg_rm_udmap_tx_ch_cfg {
+       u32 valid_params;
+#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_FILT_EINFO_VALID        BIT(9)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_FILT_PSWORDS_VALID      BIT(10)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_SUPR_TDPKT_VALID        BIT(11)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_CREDIT_COUNT_VALID      BIT(12)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_FDEPTH_VALID            BIT(13)
+       u16 nav_id;
+       u16 index;
+       u8 tx_pause_on_err;
+       u8 tx_filt_einfo;
+       u8 tx_filt_pswords;
+       u8 tx_atype;
+       u8 tx_chan_type;
+       u8 tx_supr_tdpkt;
+       u16 tx_fetch_size;
+       u8 tx_credit_count;
+       u16 txcq_qnum;
+       u8 tx_priority;
+       u8 tx_qos;
+       u8 tx_orderid;
+       u16 fdepth;
+       u8 tx_sched_priority;
+       u8 tx_burst_size;
+};
+
+/**
+ * Configures a Navigator Subsystem UDMAP receive channel
+ *
+ * Configures a Navigator Subsystem UDMAP receive channel registers.
+ * See @ti_sci_msg_rm_udmap_rx_ch_cfg_req
+ */
+struct ti_sci_msg_rm_udmap_rx_ch_cfg {
+       u32 valid_params;
+#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_RX_FLOWID_START_VALID      BIT(9)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_RX_FLOWID_CNT_VALID        BIT(10)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_RX_IGNORE_SHORT_VALID      BIT(11)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_RX_IGNORE_LONG_VALID       BIT(12)
+       u16 nav_id;
+       u16 index;
+       u16 rx_fetch_size;
+       u16 rxcq_qnum;
+       u8 rx_priority;
+       u8 rx_qos;
+       u8 rx_orderid;
+       u8 rx_sched_priority;
+       u16 flowid_start;
+       u16 flowid_cnt;
+       u8 rx_pause_on_err;
+       u8 rx_atype;
+       u8 rx_chan_type;
+       u8 rx_ignore_short;
+       u8 rx_ignore_long;
+       u8 rx_burst_size;
+};
+
+/**
+ * Configures a Navigator Subsystem UDMAP receive flow
+ *
+ * Configures a Navigator Subsystem UDMAP receive flow's registers.
+ * See @tis_ci_msg_rm_udmap_flow_cfg_req
+ */
+struct ti_sci_msg_rm_udmap_flow_cfg {
+       u32 valid_params;
+#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_EINFO_PRESENT_VALID     BIT(0)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_PSINFO_PRESENT_VALID     BIT(1)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_ERROR_HANDLING_VALID     BIT(2)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DESC_TYPE_VALID          BIT(3)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_SOP_OFFSET_VALID         BIT(4)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DEST_QNUM_VALID          BIT(5)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_SRC_TAG_HI_VALID         BIT(6)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_SRC_TAG_LO_VALID         BIT(7)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DEST_TAG_HI_VALID        BIT(8)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DEST_TAG_LO_VALID        BIT(9)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_SRC_TAG_HI_SEL_VALID     BIT(10)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_SRC_TAG_LO_SEL_VALID     BIT(11)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DEST_TAG_HI_SEL_VALID    BIT(12)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DEST_TAG_LO_SEL_VALID    BIT(13)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ0_SZ0_QNUM_VALID      BIT(14)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ1_QNUM_VALID          BIT(15)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ2_QNUM_VALID          BIT(16)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ3_QNUM_VALID          BIT(17)
+#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_PS_LOCATION_VALID        BIT(18)
+       u16 nav_id;
+       u16 flow_index;
+       u8 rx_einfo_present;
+       u8 rx_psinfo_present;
+       u8 rx_error_handling;
+       u8 rx_desc_type;
+       u16 rx_sop_offset;
+       u16 rx_dest_qnum;
+       u8 rx_src_tag_hi;
+       u8 rx_src_tag_lo;
+       u8 rx_dest_tag_hi;
+       u8 rx_dest_tag_lo;
+       u8 rx_src_tag_hi_sel;
+       u8 rx_src_tag_lo_sel;
+       u8 rx_dest_tag_hi_sel;
+       u8 rx_dest_tag_lo_sel;
+       u16 rx_fdq0_sz0_qnum;
+       u16 rx_fdq1_qnum;
+       u16 rx_fdq2_qnum;
+       u16 rx_fdq3_qnum;
+       u8 rx_ps_location;
+};
+
+/**
+ * struct ti_sci_rm_udmap_ops - UDMA Management operations
+ * @tx_ch_cfg: configure SoC Navigator Subsystem UDMA transmit channel.
+ * @rx_ch_cfg: configure SoC Navigator Subsystem UDMA receive channel.
+ * @rx_flow_cfg1: configure SoC Navigator Subsystem UDMA receive flow.
+ */
+struct ti_sci_rm_udmap_ops {
+       int (*tx_ch_cfg)(const struct ti_sci_handle *handle,
+                        const struct ti_sci_msg_rm_udmap_tx_ch_cfg *params);
+       int (*rx_ch_cfg)(const struct ti_sci_handle *handle,
+                        const struct ti_sci_msg_rm_udmap_rx_ch_cfg *params);
+       int (*rx_flow_cfg)(const struct ti_sci_handle *handle,
+                          const struct ti_sci_msg_rm_udmap_flow_cfg *params);
+};
+
+/**
+ * struct ti_sci_proc_ops - Processor Control operations
+ * @request:   Request to control a physical processor. The requesting host
+ *             should be in the processor access list
+ * @release:   Relinquish a physical processor control
+ * @handover:  Handover a physical processor control to another host
+ *             in the permitted list
+ * @set_config:        Set base configuration of a processor
+ * @set_control: Setup limited control flags in specific cases
+ * @get_status: Get the state of physical processor
+ *
+ * NOTE: The following paramteres are generic in nature for all these ops,
+ * -handle:    Pointer to TI SCI handle as retrieved by *ti_sci_get_handle
+ * -pid:       Processor ID
+ * -hid:       Host ID
+ */
+struct ti_sci_proc_ops {
+       int (*request)(const struct ti_sci_handle *handle, u8 pid);
+       int (*release)(const struct ti_sci_handle *handle, u8 pid);
+       int (*handover)(const struct ti_sci_handle *handle, u8 pid, u8 hid);
+       int (*set_config)(const struct ti_sci_handle *handle, u8 pid,
+                         u64 boot_vector, u32 cfg_set, u32 cfg_clr);
+       int (*set_control)(const struct ti_sci_handle *handle, u8 pid,
+                          u32 ctrl_set, u32 ctrl_clr);
+       int (*get_status)(const struct ti_sci_handle *handle, u8 pid,
+                         u64 *boot_vector, u32 *cfg_flags, u32 *ctrl_flags,
+                         u32 *status_flags);
+};
+
 /**
  * struct ti_sci_ops - Function support for TI SCI
  * @dev_ops:   Device specific operations
  * @clk_ops:   Clock specific operations
  * @rm_core_ops:       Resource management core operations.
  * @rm_irq_ops:                IRQ management specific operations
+ * @proc_ops:  Processor Control specific operations
  */
 struct ti_sci_ops {
        struct ti_sci_core_ops core_ops;
@@ -254,6 +496,10 @@ struct ti_sci_ops {
        struct ti_sci_clk_ops clk_ops;
        struct ti_sci_rm_core_ops rm_core_ops;
        struct ti_sci_rm_irq_ops rm_irq_ops;
+       struct ti_sci_rm_ringacc_ops rm_ring_ops;
+       struct ti_sci_rm_psil_ops rm_psil_ops;
+       struct ti_sci_rm_udmap_ops rm_udmap_ops;
+       struct ti_sci_proc_ops proc_ops;
 };
 
 /**
diff --git a/include/linux/sudmac.h b/include/linux/sudmac.h
deleted file mode 100644 (file)
index cccc0a6..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Header for the SUDMAC driver
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- */
-#ifndef SUDMAC_H
-#define SUDMAC_H
-
-#include <linux/dmaengine.h>
-#include <linux/shdma-base.h>
-#include <linux/types.h>
-
-/* Used by slave DMA clients to request DMA to/from a specific peripheral */
-struct sudmac_slave {
-       struct shdma_slave      shdma_slave;    /* Set by the platform */
-};
-
-/*
- * Supplied by platforms to specify, how a DMA channel has to be configured for
- * a certain peripheral
- */
-struct sudmac_slave_config {
-       int             slave_id;
-};
-
-struct sudmac_channel {
-       unsigned long   offset;
-       unsigned long   config;
-       unsigned long   wait;           /* The configuable range is 0 to 3 */
-       unsigned long   dint_end_bit;
-};
-
-struct sudmac_pdata {
-       const struct sudmac_slave_config *slave;
-       int slave_num;
-       const struct sudmac_channel *channel;
-       int channel_num;
-};
-
-/* Definitions for the sudmac_channel.config */
-#define SUDMAC_TX_BUFFER_MODE  BIT(0)
-#define SUDMAC_RX_END_MODE     BIT(1)
-
-/* Definitions for the sudmac_channel.dint_end_bit */
-#define SUDMAC_DMA_BIT_CH0     BIT(0)
-#define SUDMAC_DMA_BIT_CH1     BIT(1)
-
-#endif
index d4229a7..87d27e1 100644 (file)
@@ -43,6 +43,7 @@ void xprt_destroy_backchannel(struct rpc_xprt *, unsigned int max_reqs);
 int xprt_setup_bc(struct rpc_xprt *xprt, unsigned int min_reqs);
 void xprt_destroy_bc(struct rpc_xprt *xprt, unsigned int max_reqs);
 void xprt_free_bc_rqst(struct rpc_rqst *req);
+unsigned int xprt_bc_max_slots(struct rpc_xprt *xprt);
 
 /*
  * Determine if a shared backchannel is in use
index 6e80731..abc63bd 100644 (file)
@@ -124,6 +124,7 @@ struct rpc_create_args {
        u32                     prognumber;     /* overrides program->number */
        u32                     version;
        rpc_authflavor_t        authflavor;
+       u32                     nconnect;
        unsigned long           flags;
        char                    *client_name;
        struct svc_xprt         *bc_xprt;       /* NFSv4.1 backchannel */
@@ -163,6 +164,8 @@ void                rpc_shutdown_client(struct rpc_clnt *);
 void           rpc_release_client(struct rpc_clnt *);
 void           rpc_task_release_transport(struct rpc_task *);
 void           rpc_task_release_client(struct rpc_task *);
+struct rpc_xprt        *rpc_task_get_xprt(struct rpc_clnt *clnt,
+               struct rpc_xprt *xprt);
 
 int            rpcb_create_local(struct net *);
 void           rpcb_put_local(struct net *);
@@ -191,6 +194,7 @@ void                rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int);
 struct net *   rpc_net_ns(struct rpc_clnt *);
 size_t         rpc_max_payload(struct rpc_clnt *);
 size_t         rpc_max_bc_payload(struct rpc_clnt *);
+unsigned int   rpc_num_bc_slots(struct rpc_clnt *);
 void           rpc_force_rebind(struct rpc_clnt *);
 size_t         rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t);
 const char     *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t);
index 1b37513..0ee3f70 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/ktime.h>
 #include <linux/spinlock.h>
 
-#define RPC_IOSTATS_VERS       "1.0"
+#define RPC_IOSTATS_VERS       "1.1"
 
 struct rpc_iostats {
        spinlock_t              om_lock;
@@ -66,6 +66,11 @@ struct rpc_iostats {
        ktime_t                 om_queue,       /* queued for xmit */
                                om_rtt,         /* RPC RTT */
                                om_execute;     /* RPC execution */
+       /*
+        * The count of operations that complete with tk_status < 0.
+        * These statuses usually indicate error conditions.
+        */
+       unsigned long           om_error_status;
 } ____cacheline_aligned;
 
 struct rpc_task;
index d0e4518..baa3ecd 100644 (file)
@@ -126,6 +126,7 @@ struct rpc_task_setup {
 #define RPC_CALL_MAJORSEEN     0x0020          /* major timeout seen */
 #define RPC_TASK_ROOTCREDS     0x0040          /* force root creds */
 #define RPC_TASK_DYNAMIC       0x0080          /* task was kmalloc'ed */
+#define        RPC_TASK_NO_ROUND_ROBIN 0x0100          /* send requests on "main" xprt */
 #define RPC_TASK_SOFT          0x0200          /* Use soft timeouts */
 #define RPC_TASK_SOFTCONN      0x0400          /* Fail if can't connect */
 #define RPC_TASK_SENT          0x0800          /* message was sent */
@@ -183,8 +184,9 @@ struct rpc_task_setup {
 #define RPC_NR_PRIORITY                (1 + RPC_PRIORITY_PRIVILEGED - RPC_PRIORITY_LOW)
 
 struct rpc_timer {
-       struct timer_list timer;
        struct list_head list;
+       unsigned long expires;
+       struct delayed_work dwork;
 };
 
 /*
index a6d9fce..13e108b 100644 (file)
@@ -158,6 +158,7 @@ struct rpc_xprt_ops {
        int             (*bc_setup)(struct rpc_xprt *xprt,
                                    unsigned int min_reqs);
        size_t          (*bc_maxpayload)(struct rpc_xprt *xprt);
+       unsigned int    (*bc_num_slots)(struct rpc_xprt *xprt);
        void            (*bc_free_rqst)(struct rpc_rqst *rqst);
        void            (*bc_destroy)(struct rpc_xprt *xprt,
                                      unsigned int max_reqs);
@@ -238,6 +239,7 @@ struct rpc_xprt {
        /*
         * Send stuff
         */
+       atomic_long_t           queuelen;
        spinlock_t              transport_lock; /* lock transport info */
        spinlock_t              reserve_lock;   /* lock slot table */
        spinlock_t              queue_lock;     /* send/receive queue lock */
@@ -250,8 +252,9 @@ struct rpc_xprt {
 #if defined(CONFIG_SUNRPC_BACKCHANNEL)
        struct svc_serv         *bc_serv;       /* The RPC service which will */
                                                /* process the callback */
-       int                     bc_alloc_count; /* Total number of preallocs */
-       atomic_t                bc_free_slots;
+       unsigned int            bc_alloc_max;
+       unsigned int            bc_alloc_count; /* Total number of preallocs */
+       atomic_t                bc_slot_count;  /* Number of allocated slots */
        spinlock_t              bc_pa_lock;     /* Protects the preallocated
                                                 * items */
        struct list_head        bc_pa_list;     /* List of preallocated
@@ -334,6 +337,9 @@ struct xprt_class {
  */
 struct rpc_xprt                *xprt_create_transport(struct xprt_create *args);
 void                   xprt_connect(struct rpc_task *task);
+unsigned long          xprt_reconnect_delay(const struct rpc_xprt *xprt);
+void                   xprt_reconnect_backoff(struct rpc_xprt *xprt,
+                                              unsigned long init_to);
 void                   xprt_reserve(struct rpc_task *task);
 void                   xprt_retry_reserve(struct rpc_task *task);
 int                    xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task);
index af1257c..c6cce3f 100644 (file)
@@ -15,6 +15,8 @@ struct rpc_xprt_switch {
        struct kref             xps_kref;
 
        unsigned int            xps_nxprts;
+       unsigned int            xps_nactive;
+       atomic_long_t           xps_queuelen;
        struct list_head        xps_xprt_list;
 
        struct net *            xps_net;
index b81d0b3..7638dbe 100644 (file)
@@ -56,6 +56,7 @@ struct sock_xprt {
         */
        unsigned long           sock_state;
        struct delayed_work     connect_worker;
+       struct work_struct      error_worker;
        struct work_struct      recv_worker;
        struct mutex            recv_mutex;
        struct sockaddr_storage srcaddr;
@@ -84,6 +85,10 @@ struct sock_xprt {
 #define XPRT_SOCK_CONNECTING   1U
 #define XPRT_SOCK_DATA_READY   (2)
 #define XPRT_SOCK_UPD_TIMEOUT  (3)
+#define XPRT_SOCK_WAKE_ERROR   (4)
+#define XPRT_SOCK_WAKE_WRITE   (5)
+#define XPRT_SOCK_WAKE_PENDING (6)
+#define XPRT_SOCK_WAKE_DISCONNECT      (7)
 
 #endif /* __KERNEL__ */
 
index 15bdb6f..877fd23 100644 (file)
@@ -6,6 +6,8 @@
 #include <linux/bug.h>
 #include <linux/mm_types.h>
 
+#ifdef CONFIG_MMU
+
 /*
  * swapcache pages are stored in the swapper_space radix tree.  We want to
  * get good packing density in that tree, so the index should be dense in
@@ -50,13 +52,11 @@ static inline pgoff_t swp_offset(swp_entry_t entry)
        return entry.val & SWP_OFFSET_MASK;
 }
 
-#ifdef CONFIG_MMU
 /* check whether a pte points to a swap entry */
 static inline int is_swap_pte(pte_t pte)
 {
        return !pte_none(pte) && !pte_present(pte);
 }
-#endif
 
 /*
  * Convert the arch-dependent pte representation of a swp_entry_t into an
@@ -360,4 +360,5 @@ static inline int non_swap_entry(swp_entry_t entry)
 }
 #endif
 
+#endif /* CONFIG_MMU */
 #endif /* _LINUX_SWAPOPS_H */
index b01d54a..88145da 100644 (file)
@@ -1231,8 +1231,8 @@ asmlinkage long sys_ni_syscall(void);
  * the ksys_xyzyyz() functions prototyped below.
  */
 
-int ksys_mount(char __user *dev_name, char __user *dir_name, char __user *type,
-              unsigned long flags, void __user *data);
+int ksys_mount(const char __user *dev_name, const char __user *dir_name,
+              const char __user *type, unsigned long flags, void __user *data);
 int ksys_umount(char __user *name, int flags);
 int ksys_dup(unsigned int fildes);
 int ksys_chroot(const char __user *filename);
index aadd310..6df4773 100644 (file)
@@ -37,6 +37,13 @@ struct ctl_table_root;
 struct ctl_table_header;
 struct ctl_dir;
 
+/* Keep the same order as in fs/proc/proc_sysctl.c */
+#define SYSCTL_ZERO    ((void *)&sysctl_vals[0])
+#define SYSCTL_ONE     ((void *)&sysctl_vals[1])
+#define SYSCTL_INT_MAX ((void *)&sysctl_vals[2])
+
+extern const int sysctl_vals[];
+
 typedef int proc_handler (struct ctl_table *ctl, int write,
                          void __user *buffer, size_t *lenp, loff_t *ppos);
 
index 15a4ca5..681047f 100644 (file)
@@ -251,7 +251,7 @@ struct thermal_bind_params {
         * platform characterization. This value is relative to the
         * rest of the weights so a cooling device whose weight is
         * double that of another cooling device is twice as
-        * effective. See Documentation/thermal/sysfs-api.txt for more
+        * effective. See Documentation/thermal/sysfs-api.rst for more
         * information.
         */
        int weight;
@@ -259,7 +259,7 @@ struct thermal_bind_params {
        /*
         * This is a bit mask that gives the binding relation between this
         * thermal zone and cdev, for a particular trip point.
-        * See Documentation/thermal/sysfs-api.txt for more information.
+        * See Documentation/thermal/sysfs-api.rst for more information.
         */
        int trip_mask;
 
index 8a62731..5150436 100644 (file)
@@ -142,6 +142,7 @@ enum print_line_t {
 enum print_line_t trace_handle_return(struct trace_seq *s);
 
 void tracing_generic_entry_update(struct trace_entry *entry,
+                                 unsigned short type,
                                  unsigned long flags,
                                  int pc);
 struct trace_event_file;
@@ -317,6 +318,14 @@ trace_event_name(struct trace_event_call *call)
                return call->name;
 }
 
+static inline struct list_head *
+trace_get_fields(struct trace_event_call *event_call)
+{
+       if (!event_call->class->get_fields)
+               return &event_call->class->fields;
+       return event_call->class->get_fields(event_call);
+}
+
 struct trace_array;
 struct trace_subsystem_dir;
 
index 8446573..36fb3bb 100644 (file)
@@ -54,13 +54,15 @@ struct linux_binprm;
 /*
  * ptrace report for syscall entry and exit looks identical.
  */
-static inline int ptrace_report_syscall(struct pt_regs *regs)
+static inline int ptrace_report_syscall(struct pt_regs *regs,
+                                       unsigned long message)
 {
        int ptrace = current->ptrace;
 
        if (!(ptrace & PT_PTRACED))
                return 0;
 
+       current->ptrace_message = message;
        ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
 
        /*
@@ -73,6 +75,7 @@ static inline int ptrace_report_syscall(struct pt_regs *regs)
                current->exit_code = 0;
        }
 
+       current->ptrace_message = 0;
        return fatal_signal_pending(current);
 }
 
@@ -98,7 +101,7 @@ static inline int ptrace_report_syscall(struct pt_regs *regs)
 static inline __must_check int tracehook_report_syscall_entry(
        struct pt_regs *regs)
 {
-       return ptrace_report_syscall(regs);
+       return ptrace_report_syscall(regs, PTRACE_EVENTMSG_SYSCALL_ENTRY);
 }
 
 /**
@@ -123,7 +126,7 @@ static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step)
        if (step)
                user_single_step_report(regs);
        else
-               ptrace_report_syscall(regs);
+               ptrace_report_syscall(regs, PTRACE_EVENTMSG_SYSCALL_EXIT);
 }
 
 /**
index 2b70130..34a0385 100644 (file)
@@ -203,7 +203,10 @@ static inline void pagefault_enable(void)
 /*
  * Is the pagefault handler disabled? If so, user access methods will not sleep.
  */
-#define pagefault_disabled() (current->pagefault_disabled != 0)
+static inline bool pagefault_disabled(void)
+{
+       return current->pagefault_disabled != 0;
+}
 
 /*
  * The pagefault handler is in general disabled by pagefault_disable() or
@@ -240,6 +243,18 @@ extern long probe_kernel_read(void *dst, const void *src, size_t size);
 extern long __probe_kernel_read(void *dst, const void *src, size_t size);
 
 /*
+ * probe_user_read(): safely attempt to read from a location in user space
+ * @dst: pointer to the buffer that shall take the data
+ * @src: address to read from
+ * @size: size of the data chunk
+ *
+ * Safely read from address @src to the buffer at @dst.  If a kernel fault
+ * happens, handle that and return -EFAULT.
+ */
+extern long probe_user_read(void *dst, const void __user *src, size_t size);
+extern long __probe_user_read(void *dst, const void __user *src, size_t size);
+
+/*
  * probe_kernel_write(): safely attempt to write to a location
  * @dst: address to write to
  * @src: pointer to the data that shall be written
@@ -252,6 +267,9 @@ extern long notrace probe_kernel_write(void *dst, const void *src, size_t size);
 extern long notrace __probe_kernel_write(void *dst, const void *src, size_t size);
 
 extern long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count);
+extern long strncpy_from_unsafe_user(char *dst, const void __user *unsafe_addr,
+                                    long count);
+extern long strnlen_unsafe_user(const void __user *unsafe_addr, long count);
 
 /**
  * probe_kernel_address(): safely attempt to read from a location
diff --git a/include/memory/jedec_ddr.h b/include/memory/jedec_ddr.h
deleted file mode 100644 (file)
index 90a9dab..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Definitions for DDR memories based on JEDEC specs
- *
- * Copyright (C) 2012 Texas Instruments, Inc.
- *
- * Aneesh V <aneesh@ti.com>
- */
-#ifndef __LINUX_JEDEC_DDR_H
-#define __LINUX_JEDEC_DDR_H
-
-#include <linux/types.h>
-
-/* DDR Densities */
-#define DDR_DENSITY_64Mb       1
-#define DDR_DENSITY_128Mb      2
-#define DDR_DENSITY_256Mb      3
-#define DDR_DENSITY_512Mb      4
-#define DDR_DENSITY_1Gb                5
-#define DDR_DENSITY_2Gb                6
-#define DDR_DENSITY_4Gb                7
-#define DDR_DENSITY_8Gb                8
-#define DDR_DENSITY_16Gb       9
-#define DDR_DENSITY_32Gb       10
-
-/* DDR type */
-#define DDR_TYPE_DDR2          1
-#define DDR_TYPE_DDR3          2
-#define DDR_TYPE_LPDDR2_S4     3
-#define DDR_TYPE_LPDDR2_S2     4
-#define DDR_TYPE_LPDDR2_NVM    5
-
-/* DDR IO width */
-#define DDR_IO_WIDTH_4         1
-#define DDR_IO_WIDTH_8         2
-#define DDR_IO_WIDTH_16                3
-#define DDR_IO_WIDTH_32                4
-
-/* Number of Row bits */
-#define R9                     9
-#define R10                    10
-#define R11                    11
-#define R12                    12
-#define R13                    13
-#define R14                    14
-#define R15                    15
-#define R16                    16
-
-/* Number of Column bits */
-#define C7                     7
-#define C8                     8
-#define C9                     9
-#define C10                    10
-#define C11                    11
-#define C12                    12
-
-/* Number of Banks */
-#define B1                     0
-#define B2                     1
-#define B4                     2
-#define B8                     3
-
-/* Refresh rate in nano-seconds */
-#define T_REFI_15_6            15600
-#define T_REFI_7_8             7800
-#define T_REFI_3_9             3900
-
-/* tRFC values */
-#define T_RFC_90               90000
-#define T_RFC_110              110000
-#define T_RFC_130              130000
-#define T_RFC_160              160000
-#define T_RFC_210              210000
-#define T_RFC_300              300000
-#define T_RFC_350              350000
-
-/* Mode register numbers */
-#define DDR_MR0                        0
-#define DDR_MR1                        1
-#define DDR_MR2                        2
-#define DDR_MR3                        3
-#define DDR_MR4                        4
-#define DDR_MR5                        5
-#define DDR_MR6                        6
-#define DDR_MR7                        7
-#define DDR_MR8                        8
-#define DDR_MR9                        9
-#define DDR_MR10               10
-#define DDR_MR11               11
-#define DDR_MR16               16
-#define DDR_MR17               17
-#define DDR_MR18               18
-
-/*
- * LPDDR2 related defines
- */
-
-/* MR4 register fields */
-#define MR4_SDRAM_REF_RATE_SHIFT                       0
-#define MR4_SDRAM_REF_RATE_MASK                                7
-#define MR4_TUF_SHIFT                                  7
-#define MR4_TUF_MASK                                   (1 << 7)
-
-/* MR4 SDRAM Refresh Rate field values */
-#define SDRAM_TEMP_NOMINAL                             0x3
-#define SDRAM_TEMP_RESERVED_4                          0x4
-#define SDRAM_TEMP_HIGH_DERATE_REFRESH                 0x5
-#define SDRAM_TEMP_HIGH_DERATE_REFRESH_AND_TIMINGS     0x6
-#define SDRAM_TEMP_VERY_HIGH_SHUTDOWN                  0x7
-
-#define NUM_DDR_ADDR_TABLE_ENTRIES                     11
-#define NUM_DDR_TIMING_TABLE_ENTRIES                   4
-
-/* Structure for DDR addressing info from the JEDEC spec */
-struct lpddr2_addressing {
-       u32 num_banks;
-       u32 tREFI_ns;
-       u32 tRFCab_ps;
-};
-
-/*
- * Structure for timings from the LPDDR2 datasheet
- * All parameters are in pico seconds(ps) unless explicitly indicated
- * with a suffix like tRAS_max_ns below
- */
-struct lpddr2_timings {
-       u32 max_freq;
-       u32 min_freq;
-       u32 tRPab;
-       u32 tRCD;
-       u32 tWR;
-       u32 tRAS_min;
-       u32 tRRD;
-       u32 tWTR;
-       u32 tXP;
-       u32 tRTP;
-       u32 tCKESR;
-       u32 tDQSCK_max;
-       u32 tDQSCK_max_derated;
-       u32 tFAW;
-       u32 tZQCS;
-       u32 tZQCL;
-       u32 tZQinit;
-       u32 tRAS_max_ns;
-};
-
-/*
- * Min value for some parameters in terms of number of tCK cycles(nCK)
- * Please set to zero parameters that are not valid for a given memory
- * type
- */
-struct lpddr2_min_tck {
-       u32 tRPab;
-       u32 tRCD;
-       u32 tWR;
-       u32 tRASmin;
-       u32 tRRD;
-       u32 tWTR;
-       u32 tXP;
-       u32 tRTP;
-       u32 tCKE;
-       u32 tCKESR;
-       u32 tFAW;
-};
-
-extern const struct lpddr2_addressing
-       lpddr2_jedec_addressing_table[NUM_DDR_ADDR_TABLE_ENTRIES];
-extern const struct lpddr2_timings
-       lpddr2_jedec_timings[NUM_DDR_TIMING_TABLE_ENTRIES];
-extern const struct lpddr2_min_tck lpddr2_jedec_min_tck;
-
-#endif /* __LINUX_JEDEC_DDR_H */
index 88c2715..45850a8 100644 (file)
@@ -4170,7 +4170,7 @@ struct sta_opmode_info {
        u8 rx_nss;
 };
 
-#define VENDOR_CMD_RAW_DATA ((const struct nla_policy *)ERR_PTR(-ENODATA))
+#define VENDOR_CMD_RAW_DATA ((const struct nla_policy *)(long)(-ENODATA))
 
 /**
  * struct wiphy_vendor_command - vendor command definition
index db33729..b16d216 100644 (file)
@@ -2,8 +2,8 @@
 #define _NET_FLOW_OFFLOAD_H
 
 #include <linux/kernel.h>
+#include <linux/list.h>
 #include <net/flow_dissector.h>
-#include <net/sch_generic.h>
 
 struct flow_match {
        struct flow_dissector   *dissector;
@@ -249,6 +249,10 @@ enum flow_block_binder_type {
        FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS,
 };
 
+struct flow_block {
+       struct list_head cb_list;
+};
+
 struct netlink_ext_ack;
 
 struct flow_block_offload {
@@ -256,29 +260,33 @@ struct flow_block_offload {
        enum flow_block_binder_type binder_type;
        bool block_shared;
        struct net *net;
+       struct flow_block *block;
        struct list_head cb_list;
        struct list_head *driver_block_list;
        struct netlink_ext_ack *extack;
 };
 
+enum tc_setup_type;
+typedef int flow_setup_cb_t(enum tc_setup_type type, void *type_data,
+                           void *cb_priv);
+
 struct flow_block_cb {
        struct list_head        driver_list;
        struct list_head        list;
-       struct net              *net;
-       tc_setup_cb_t           *cb;
+       flow_setup_cb_t         *cb;
        void                    *cb_ident;
        void                    *cb_priv;
        void                    (*release)(void *cb_priv);
        unsigned int            refcnt;
 };
 
-struct flow_block_cb *flow_block_cb_alloc(struct net *net, tc_setup_cb_t *cb,
+struct flow_block_cb *flow_block_cb_alloc(flow_setup_cb_t *cb,
                                          void *cb_ident, void *cb_priv,
                                          void (*release)(void *cb_priv));
 void flow_block_cb_free(struct flow_block_cb *block_cb);
 
-struct flow_block_cb *flow_block_cb_lookup(struct flow_block_offload *offload,
-                                          tc_setup_cb_t *cb, void *cb_ident);
+struct flow_block_cb *flow_block_cb_lookup(struct flow_block *block,
+                                          flow_setup_cb_t *cb, void *cb_ident);
 
 void *flow_block_cb_priv(struct flow_block_cb *block_cb);
 void flow_block_cb_incref(struct flow_block_cb *block_cb);
@@ -296,11 +304,12 @@ static inline void flow_block_cb_remove(struct flow_block_cb *block_cb,
        list_move(&block_cb->list, &offload->cb_list);
 }
 
-bool flow_block_cb_is_busy(tc_setup_cb_t *cb, void *cb_ident,
+bool flow_block_cb_is_busy(flow_setup_cb_t *cb, void *cb_ident,
                           struct list_head *driver_block_list);
 
 int flow_block_cb_setup_simple(struct flow_block_offload *f,
-                              struct list_head *driver_list, tc_setup_cb_t *cb,
+                              struct list_head *driver_list,
+                              flow_setup_cb_t *cb,
                               void *cb_ident, void *cb_priv, bool ingress_only);
 
 enum flow_cls_command {
@@ -333,4 +342,9 @@ flow_cls_offload_flow_rule(struct flow_cls_offload *flow_cmd)
        return flow_cmd->rule;
 }
 
+static inline void flow_block_init(struct flow_block *flow_block)
+{
+       INIT_LIST_HEAD(&flow_block->cb_list);
+}
+
 #endif /* _NET_FLOW_OFFLOAD_H */
index 93ce6b0..573429b 100644 (file)
@@ -76,6 +76,11 @@ struct nf_conntrack_expect_policy {
 #define NF_CT_EXPECT_CLASS_DEFAULT     0
 #define NF_CT_EXPECT_MAX_CNT           255
 
+/* Allow to reuse expectations with the same tuples from different master
+ * conntracks.
+ */
+#define NF_CT_EXP_F_SKIP_MASTER        0x1
+
 int nf_conntrack_expect_pernet_init(struct net *net);
 void nf_conntrack_expect_pernet_fini(struct net *net);
 
@@ -122,10 +127,11 @@ void nf_ct_expect_init(struct nf_conntrack_expect *, unsigned int, u_int8_t,
                       u_int8_t, const __be16 *, const __be16 *);
 void nf_ct_expect_put(struct nf_conntrack_expect *exp);
 int nf_ct_expect_related_report(struct nf_conntrack_expect *expect, 
-                               u32 portid, int report);
-static inline int nf_ct_expect_related(struct nf_conntrack_expect *expect)
+                               u32 portid, int report, unsigned int flags);
+static inline int nf_ct_expect_related(struct nf_conntrack_expect *expect,
+                                      unsigned int flags)
 {
-       return nf_ct_expect_related_report(expect, 0, 0);
+       return nf_ct_expect_related_report(expect, 0, 0, flags);
 }
 
 #endif /*_NF_CONNTRACK_EXPECT_H*/
index 8f00125..44513b9 100644 (file)
@@ -68,6 +68,7 @@ struct synproxy_options {
        u8                              options;
        u8                              wscale;
        u16                             mss;
+       u16                             mss_encode;
        u32                             tsval;
        u32                             tsecr;
 };
index 35dfdd9..9b62456 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/rhashtable.h>
 #include <net/netfilter/nf_flow_table.h>
 #include <net/netlink.h>
+#include <net/flow_offload.h>
 
 struct module;
 
@@ -951,7 +952,7 @@ struct nft_stats {
  *     @stats: per-cpu chain stats
  *     @chain: the chain
  *     @dev_name: device name that this base chain is attached to (if any)
- *     @cb_list: list of flow block callbacks (for hardware offload)
+ *     @flow_block: flow block (for hardware offload)
  */
 struct nft_base_chain {
        struct nf_hook_ops              ops;
@@ -961,7 +962,7 @@ struct nft_base_chain {
        struct nft_stats __percpu       *stats;
        struct nft_chain                chain;
        char                            dev_name[IFNAMSIZ];
-       struct list_head                cb_list;
+       struct flow_block               flow_block;
 };
 
 static inline struct nft_base_chain *nft_base_chain(const struct nft_chain *chain)
index 841faad..e429809 100644 (file)
@@ -6,7 +6,6 @@
 #include <linux/workqueue.h>
 #include <net/sch_generic.h>
 #include <net/act_api.h>
-#include <net/flow_offload.h>
 #include <net/net_namespace.h>
 
 /* TC action not accessible from user space */
@@ -126,14 +125,14 @@ static inline struct Qdisc *tcf_block_q(struct tcf_block *block)
 }
 
 static inline
-int tc_setup_cb_block_register(struct tcf_block *block, tc_setup_cb_t *cb,
+int tc_setup_cb_block_register(struct tcf_block *block, flow_setup_cb_t *cb,
                               void *cb_priv)
 {
        return 0;
 }
 
 static inline
-void tc_setup_cb_block_unregister(struct tcf_block *block, tc_setup_cb_t *cb,
+void tc_setup_cb_block_unregister(struct tcf_block *block, flow_setup_cb_t *cb,
                                  void *cb_priv)
 {
 }
index 855167b..6b6b012 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/mutex.h>
 #include <net/gen_stats.h>
 #include <net/rtnetlink.h>
+#include <net/flow_offload.h>
 
 struct Qdisc_ops;
 struct qdisc_walker;
@@ -22,9 +23,6 @@ struct tcf_walker;
 struct module;
 struct bpf_flow_keys;
 
-typedef int tc_setup_cb_t(enum tc_setup_type type,
-                         void *type_data, void *cb_priv);
-
 typedef int tc_indr_block_bind_cb_t(struct net_device *dev, void *cb_priv,
                                    enum tc_setup_type type, void *type_data);
 
@@ -313,7 +311,7 @@ struct tcf_proto_ops {
        void                    (*walk)(struct tcf_proto *tp,
                                        struct tcf_walker *arg, bool rtnl_held);
        int                     (*reoffload)(struct tcf_proto *tp, bool add,
-                                            tc_setup_cb_t *cb, void *cb_priv,
+                                            flow_setup_cb_t *cb, void *cb_priv,
                                             struct netlink_ext_ack *extack);
        void                    (*bind_class)(void *, u32, unsigned long);
        void *                  (*tmplt_create)(struct net *net,
@@ -401,7 +399,7 @@ struct tcf_block {
        refcount_t refcnt;
        struct net *net;
        struct Qdisc *q;
-       struct list_head cb_list;
+       struct flow_block flow_block;
        struct list_head owner_list;
        bool keep_dst;
        unsigned int offloadcnt; /* Number of oddloaded filters */
index cca3c59..e5cf514 100644 (file)
@@ -1064,7 +1064,8 @@ void tcp_get_default_congestion_control(struct net *net, char *name);
 void tcp_get_available_congestion_control(char *buf, size_t len);
 void tcp_get_allowed_congestion_control(char *buf, size_t len);
 int tcp_set_allowed_congestion_control(char *allowed);
-int tcp_set_congestion_control(struct sock *sk, const char *name, bool load, bool reinit);
+int tcp_set_congestion_control(struct sock *sk, const char *name, bool load,
+                              bool reinit, bool cap_net_admin);
 u32 tcp_slow_start(struct tcp_sock *tp, u32 acked);
 void tcp_cong_avoid_ai(struct tcp_sock *tp, u32 w, u32 acked);
 
@@ -1708,6 +1709,11 @@ static inline struct sk_buff *tcp_rtx_queue_head(const struct sock *sk)
        return skb_rb_first(&sk->tcp_rtx_queue);
 }
 
+static inline struct sk_buff *tcp_rtx_queue_tail(const struct sock *sk)
+{
+       return skb_rb_last(&sk->tcp_rtx_queue);
+}
+
 static inline struct sk_buff *tcp_write_queue_head(const struct sock *sk)
 {
        return skb_peek(&sk->sk_write_queue);
index a5fcdad..cc139db 100644 (file)
@@ -369,6 +369,8 @@ struct scsi_host_template {
         */
        unsigned long dma_boundary;
 
+       unsigned long virt_boundary_mask;
+
        /*
         * This specifies "machine infinity" for host templates which don't
         * limit the transfer size.  Note this limit represents an absolute
@@ -587,6 +589,7 @@ struct Scsi_Host {
        unsigned int max_sectors;
        unsigned int max_segment_size;
        unsigned long dma_boundary;
+       unsigned long virt_boundary_mask;
        /*
         * In scsi-mq mode, the number of hardware queues supported by the LLD.
         *
index 5b99cb2..173e404 100644 (file)
@@ -133,5 +133,13 @@ int bman_acquire(struct bman_pool *pool, struct bm_buffer *bufs, u8 num);
  * failed to probe or 0 if the bman driver did not probed yet.
  */
 int bman_is_probed(void);
+/**
+ * bman_portals_probed - Check if all cpu bound bman portals are probed
+ *
+ * Returns 1 if all the required cpu bound bman portals successfully probed,
+ * -1 if probe errors appeared or 0 if the bman portals did not yet finished
+ * probing.
+ */
+int bman_portals_probed(void);
 
 #endif /* __FSL_BMAN_H */
index 5cc7af0..aa31c05 100644 (file)
@@ -1195,6 +1195,15 @@ int qman_release_cgrid(u32 id);
 int qman_is_probed(void);
 
 /**
+ * qman_portals_probed - Check if all cpu bound qman portals are probed
+ *
+ * Returns 1 if all the required cpu bound qman portals successfully probed,
+ * -1 if probe errors appeared or 0 if the qman portals did not yet finished
+ * probing.
+ */
+int qman_portals_probed(void);
+
+/**
  * qman_dqrr_get_ithresh - Get coalesce interrupt threshold
  * @portal: portal to get the value for
  * @ithresh: threshold pointer
index c5188ff..bc88d6f 100644 (file)
@@ -173,10 +173,7 @@ static inline void snd_compr_drain_notify(struct snd_compr_stream *stream)
        if (snd_BUG_ON(!stream))
                return;
 
-       if (stream->direction == SND_COMPRESS_PLAYBACK)
-               stream->runtime->state = SNDRV_PCM_STATE_SETUP;
-       else
-               stream->runtime->state = SNDRV_PCM_STATE_PREPARED;
+       stream->runtime->state = SNDRV_PCM_STATE_SETUP;
 
        wake_up(&stream->runtime->sleep);
 }
index 8f46ff3..8719936 100644 (file)
@@ -252,6 +252,8 @@ struct hda_codec {
        unsigned int auto_runtime_pm:1; /* enable automatic codec runtime pm */
        unsigned int force_pin_prefix:1; /* Add location prefix */
        unsigned int link_down_at_suspend:1; /* link down at runtime suspend */
+       unsigned int relaxed_resume:1;  /* don't resume forcibly for jack */
+
 #ifdef CONFIG_PM
        unsigned long power_on_acct;
        unsigned long power_off_acct;
index f9eff01..2f6a669 100644 (file)
@@ -29,6 +29,7 @@ struct btrfs_qgroup_extent_record;
 struct btrfs_qgroup;
 struct extent_io_tree;
 struct prelim_ref;
+struct btrfs_space_info;
 
 TRACE_DEFINE_ENUM(FLUSH_DELAYED_ITEMS_NR);
 TRACE_DEFINE_ENUM(FLUSH_DELAYED_ITEMS);
@@ -2091,6 +2092,45 @@ DEFINE_BTRFS_LOCK_EVENT(btrfs_try_tree_read_lock);
 DEFINE_BTRFS_LOCK_EVENT(btrfs_try_tree_write_lock);
 DEFINE_BTRFS_LOCK_EVENT(btrfs_tree_read_lock_atomic);
 
+DECLARE_EVENT_CLASS(btrfs__space_info_update,
+
+       TP_PROTO(struct btrfs_fs_info *fs_info,
+                struct btrfs_space_info *sinfo, u64 old, s64 diff),
+
+       TP_ARGS(fs_info, sinfo, old, diff),
+
+       TP_STRUCT__entry_btrfs(
+               __field(        u64,    type            )
+               __field(        u64,    old             )
+               __field(        s64,    diff            )
+       ),
+
+       TP_fast_assign_btrfs(fs_info,
+               __entry->type   = sinfo->flags;
+               __entry->old    = old;
+               __entry->diff   = diff;
+       ),
+       TP_printk_btrfs("type=%s old=%llu diff=%lld",
+               __print_flags(__entry->type, "|", BTRFS_GROUP_FLAGS),
+               __entry->old, __entry->diff)
+);
+
+DEFINE_EVENT(btrfs__space_info_update, update_bytes_may_use,
+
+       TP_PROTO(struct btrfs_fs_info *fs_info,
+                struct btrfs_space_info *sinfo, u64 old, s64 diff),
+
+       TP_ARGS(fs_info, sinfo, old, diff)
+);
+
+DEFINE_EVENT(btrfs__space_info_update, update_bytes_pinned,
+
+       TP_PROTO(struct btrfs_fs_info *fs_info,
+                struct btrfs_space_info *sinfo, u64 old, s64 diff),
+
+       TP_ARGS(fs_info, sinfo, old, diff)
+);
+
 #endif /* _TRACE_BTRFS_H */
 
 /* This part must be outside protection */
index df9851c..f6a4eaa 100644 (file)
@@ -181,18 +181,6 @@ DECLARE_EVENT_CLASS(xprtrdma_wrch_event,
                                ),                                      \
                                TP_ARGS(task, mr, nsegs))
 
-TRACE_DEFINE_ENUM(FRWR_IS_INVALID);
-TRACE_DEFINE_ENUM(FRWR_IS_VALID);
-TRACE_DEFINE_ENUM(FRWR_FLUSHED_FR);
-TRACE_DEFINE_ENUM(FRWR_FLUSHED_LI);
-
-#define xprtrdma_show_frwr_state(x)                                    \
-               __print_symbolic(x,                                     \
-                               { FRWR_IS_INVALID, "INVALID" },         \
-                               { FRWR_IS_VALID, "VALID" },             \
-                               { FRWR_FLUSHED_FR, "FLUSHED_FR" },      \
-                               { FRWR_FLUSHED_LI, "FLUSHED_LI" })
-
 DECLARE_EVENT_CLASS(xprtrdma_frwr_done,
        TP_PROTO(
                const struct ib_wc *wc,
@@ -203,22 +191,19 @@ DECLARE_EVENT_CLASS(xprtrdma_frwr_done,
 
        TP_STRUCT__entry(
                __field(const void *, mr)
-               __field(unsigned int, state)
                __field(unsigned int, status)
                __field(unsigned int, vendor_err)
        ),
 
        TP_fast_assign(
                __entry->mr = container_of(frwr, struct rpcrdma_mr, frwr);
-               __entry->state = frwr->fr_state;
                __entry->status = wc->status;
                __entry->vendor_err = __entry->status ? wc->vendor_err : 0;
        ),
 
        TP_printk(
-               "mr=%p state=%s: %s (%u/0x%x)",
-               __entry->mr, xprtrdma_show_frwr_state(__entry->state),
-               rdma_show_wc_status(__entry->status),
+               "mr=%p: %s (%u/0x%x)",
+               __entry->mr, rdma_show_wc_status(__entry->status),
                __entry->status, __entry->vendor_err
        )
 );
@@ -390,6 +375,37 @@ DEFINE_RXPRT_EVENT(xprtrdma_op_inject_dsc);
 DEFINE_RXPRT_EVENT(xprtrdma_op_close);
 DEFINE_RXPRT_EVENT(xprtrdma_op_connect);
 
+TRACE_EVENT(xprtrdma_op_set_cto,
+       TP_PROTO(
+               const struct rpcrdma_xprt *r_xprt,
+               unsigned long connect,
+               unsigned long reconnect
+       ),
+
+       TP_ARGS(r_xprt, connect, reconnect),
+
+       TP_STRUCT__entry(
+               __field(const void *, r_xprt)
+               __field(unsigned long, connect)
+               __field(unsigned long, reconnect)
+               __string(addr, rpcrdma_addrstr(r_xprt))
+               __string(port, rpcrdma_portstr(r_xprt))
+       ),
+
+       TP_fast_assign(
+               __entry->r_xprt = r_xprt;
+               __entry->connect = connect;
+               __entry->reconnect = reconnect;
+               __assign_str(addr, rpcrdma_addrstr(r_xprt));
+               __assign_str(port, rpcrdma_portstr(r_xprt));
+       ),
+
+       TP_printk("peer=[%s]:%s r_xprt=%p: connect=%lu reconnect=%lu",
+               __get_str(addr), __get_str(port), __entry->r_xprt,
+               __entry->connect / HZ, __entry->reconnect / HZ
+       )
+);
+
 TRACE_EVENT(xprtrdma_qp_event,
        TP_PROTO(
                const struct rpcrdma_xprt *r_xprt,
@@ -470,13 +486,12 @@ TRACE_DEFINE_ENUM(rpcrdma_replych);
 
 TRACE_EVENT(xprtrdma_marshal,
        TP_PROTO(
-               const struct rpc_rqst *rqst,
-               unsigned int hdrlen,
+               const struct rpcrdma_req *req,
                unsigned int rtype,
                unsigned int wtype
        ),
 
-       TP_ARGS(rqst, hdrlen, rtype, wtype),
+       TP_ARGS(req, rtype, wtype),
 
        TP_STRUCT__entry(
                __field(unsigned int, task_id)
@@ -491,10 +506,12 @@ TRACE_EVENT(xprtrdma_marshal,
        ),
 
        TP_fast_assign(
+               const struct rpc_rqst *rqst = &req->rl_slot;
+
                __entry->task_id = rqst->rq_task->tk_pid;
                __entry->client_id = rqst->rq_task->tk_client->cl_clid;
                __entry->xid = be32_to_cpu(rqst->rq_xid);
-               __entry->hdrlen = hdrlen;
+               __entry->hdrlen = req->rl_hdrbuf.len;
                __entry->headlen = rqst->rq_snd_buf.head[0].iov_len;
                __entry->pagelen = rqst->rq_snd_buf.page_len;
                __entry->taillen = rqst->rq_snd_buf.tail[0].iov_len;
@@ -538,6 +555,33 @@ TRACE_EVENT(xprtrdma_marshal_failed,
        )
 );
 
+TRACE_EVENT(xprtrdma_prepsend_failed,
+       TP_PROTO(const struct rpc_rqst *rqst,
+                int ret
+       ),
+
+       TP_ARGS(rqst, ret),
+
+       TP_STRUCT__entry(
+               __field(unsigned int, task_id)
+               __field(unsigned int, client_id)
+               __field(u32, xid)
+               __field(int, ret)
+       ),
+
+       TP_fast_assign(
+               __entry->task_id = rqst->rq_task->tk_pid;
+               __entry->client_id = rqst->rq_task->tk_client->cl_clid;
+               __entry->xid = be32_to_cpu(rqst->rq_xid);
+               __entry->ret = ret;
+       ),
+
+       TP_printk("task:%u@%u xid=0x%08x: ret=%d",
+               __entry->task_id, __entry->client_id, __entry->xid,
+               __entry->ret
+       )
+);
+
 TRACE_EVENT(xprtrdma_post_send,
        TP_PROTO(
                const struct rpcrdma_req *req,
@@ -559,7 +603,8 @@ TRACE_EVENT(xprtrdma_post_send,
                const struct rpc_rqst *rqst = &req->rl_slot;
 
                __entry->task_id = rqst->rq_task->tk_pid;
-               __entry->client_id = rqst->rq_task->tk_client->cl_clid;
+               __entry->client_id = rqst->rq_task->tk_client ?
+                                    rqst->rq_task->tk_client->cl_clid : -1;
                __entry->req = req;
                __entry->num_sge = req->rl_sendctx->sc_wr.num_sge;
                __entry->signaled = req->rl_sendctx->sc_wr.send_flags &
@@ -698,6 +743,7 @@ TRACE_EVENT(xprtrdma_wc_receive,
 DEFINE_FRWR_DONE_EVENT(xprtrdma_wc_fastreg);
 DEFINE_FRWR_DONE_EVENT(xprtrdma_wc_li);
 DEFINE_FRWR_DONE_EVENT(xprtrdma_wc_li_wake);
+DEFINE_FRWR_DONE_EVENT(xprtrdma_wc_li_done);
 
 TRACE_EVENT(xprtrdma_frwr_alloc,
        TP_PROTO(
index abd238d..63b1f50 100644 (file)
 #define MAP_TYPE       0x0f            /* Mask for type of mapping */
 #define MAP_FIXED      0x10            /* Interpret addr exactly */
 #define MAP_ANONYMOUS  0x20            /* don't use a file */
-#ifdef CONFIG_MMAP_ALLOW_UNINITIALIZED
-# define MAP_UNINITIALIZED 0x4000000   /* For anonymous mmap, memory could be uninitialized */
-#else
-# define MAP_UNINITIALIZED 0x0         /* Don't support this flag */
-#endif
 
-/* 0x0100 - 0x80000 flags are defined in asm-generic/mman.h */
+/* 0x0100 - 0x4000 flags are defined in asm-generic/mman.h */
+#define MAP_POPULATE           0x008000        /* populate (prefault) pagetables */
+#define MAP_NONBLOCK           0x010000        /* do not block on IO */
+#define MAP_STACK              0x020000        /* give out an address that is best suited for process/thread stacks */
+#define MAP_HUGETLB            0x040000        /* create a huge page mapping */
+#define MAP_SYNC               0x080000 /* perform synchronous page faults for the mapping */
 #define MAP_FIXED_NOREPLACE    0x100000        /* MAP_FIXED which doesn't unmap underlying mapping */
 
+#define MAP_UNINITIALIZED 0x4000000    /* For anonymous mmap, memory could be
+                                        * uninitialized */
+
 /*
  * Flags for mlock
  */
index 653687d..57e8195 100644 (file)
@@ -9,13 +9,11 @@
 #define MAP_EXECUTABLE 0x1000          /* mark it as an executable */
 #define MAP_LOCKED     0x2000          /* pages are locked */
 #define MAP_NORESERVE  0x4000          /* don't check for reservations */
-#define MAP_POPULATE   0x8000          /* populate (prefault) pagetables */
-#define MAP_NONBLOCK   0x10000         /* do not block on IO */
-#define MAP_STACK      0x20000         /* give out an address that is best suited for process/thread stacks */
-#define MAP_HUGETLB    0x40000         /* create a huge page mapping */
-#define MAP_SYNC       0x80000         /* perform synchronous page faults for the mapping */
 
-/* Bits [26:31] are reserved, see mman-common.h for MAP_HUGETLB usage */
+/*
+ * Bits [26:31] are reserved, see asm-generic/hugetlb_encode.h
+ * for MAP_HUGETLB usage
+ */
 
 #define MCL_CURRENT    1               /* lock all current mappings */
 #define MCL_FUTURE     2               /* lock all future mappings */
index 9acfff0..1be0e79 100644 (file)
@@ -846,8 +846,10 @@ __SYSCALL(__NR_fsmount, sys_fsmount)
 __SYSCALL(__NR_fspick, sys_fspick)
 #define __NR_pidfd_open 434
 __SYSCALL(__NR_pidfd_open, sys_pidfd_open)
+#ifdef __ARCH_WANT_SYS_CLONE3
 #define __NR_clone3 435
 __SYSCALL(__NR_clone3, sys_clone3)
+#endif
 
 #undef __NR_syscalls
 #define __NR_syscalls 436
index d799858..11cc573 100644 (file)
@@ -219,7 +219,10 @@ union drm_amdgpu_bo_list {
 #define AMDGPU_CTX_PRIORITY_VERY_LOW    -1023
 #define AMDGPU_CTX_PRIORITY_LOW         -512
 #define AMDGPU_CTX_PRIORITY_NORMAL      0
-/* Selecting a priority above NORMAL requires CAP_SYS_NICE or DRM_MASTER */
+/*
+ * When used in struct drm_amdgpu_ctx_in, a priority above NORMAL requires
+ * CAP_SYS_NICE or DRM_MASTER
+*/
 #define AMDGPU_CTX_PRIORITY_HIGH        512
 #define AMDGPU_CTX_PRIORITY_VERY_HIGH   1023
 
@@ -229,6 +232,7 @@ struct drm_amdgpu_ctx_in {
        /** For future use, no flags defined so far */
        __u32   flags;
        __u32   ctx_id;
+       /** AMDGPU_CTX_PRIORITY_* */
        __s32   priority;
 };
 
@@ -281,6 +285,7 @@ struct drm_amdgpu_sched_in {
        /* AMDGPU_SCHED_OP_* */
        __u32   op;
        __u32   fd;
+       /** AMDGPU_CTX_PRIORITY_* */
        __s32   priority;
        __u32   ctx_id;
 };
index 151d93e..f1a7d67 100644 (file)
@@ -29,17 +29,17 @@ struct adfs_discrecord {
     __u8  log2sharesize:4;
     __u8  unused40:4;
     __u8  big_flag:1;
-    __u8  unused41:1;
+    __u8  unused41:7;
     __u8  nzones_high;
+    __u8  reserved43;
     __le32 format_version;
     __le32 root_size;
     __u8  unused52[60 - 52];
-};
+} __attribute__((packed, aligned(4)));
 
 #define ADFS_DISCRECORD                (0xc00)
 #define ADFS_DR_OFFSET         (0x1c0)
 #define ADFS_DR_SIZE            60
 #define ADFS_DR_SIZE_BITS      (ADFS_DR_SIZE << 3)
 
-
 #endif /* _UAPI_ADFS_FS_H */
index 6f68438..fa1c753 100644 (file)
@@ -806,7 +806,7 @@ union bpf_attr {
  *             based on a user-provided identifier for all traffic coming from
  *             the tasks belonging to the related cgroup. See also the related
  *             kernel documentation, available from the Linux sources in file
- *             *Documentation/cgroup-v1/net_cls.rst*.
+ *             *Documentation/admin-guide/cgroup-v1/net_cls.rst*.
  *
  *             The Linux kernel has two versions for cgroups: there are
  *             cgroups v1 and cgroups v2. Both are available to users, who can
@@ -3248,7 +3248,7 @@ struct bpf_sock_addr {
        __u32 user_ip4;         /* Allows 1,2,4-byte read and 4-byte write.
                                 * Stored in network byte order.
                                 */
-       __u32 user_ip6[4];      /* Allows 1,2,4-byte read and 4,8-byte write.
+       __u32 user_ip6[4];      /* Allows 1,2,4,8-byte read and 4,8-byte write.
                                 * Stored in network byte order.
                                 */
        __u32 user_port;        /* Allows 4-byte read and write.
@@ -3260,7 +3260,7 @@ struct bpf_sock_addr {
        __u32 msg_src_ip4;      /* Allows 1,2,4-byte read and 4-byte write.
                                 * Stored in network byte order.
                                 */
-       __u32 msg_src_ip6[4];   /* Allows 1,2,4-byte read and 4,8-byte write.
+       __u32 msg_src_ip6[4];   /* Allows 1,2,4,8-byte read and 4,8-byte write.
                                 * Stored in network byte order.
                                 */
        __bpf_md_ptr(struct bpf_sock *, sk);
index 421239b..34d5b34 100644 (file)
@@ -866,6 +866,8 @@ enum btrfs_raid_types {
 #define BTRFS_BLOCK_GROUP_RAID56_MASK  (BTRFS_BLOCK_GROUP_RAID5 |   \
                                         BTRFS_BLOCK_GROUP_RAID6)
 
+#define BTRFS_BLOCK_GROUP_RAID1_MASK   (BTRFS_BLOCK_GROUP_RAID1)
+
 /*
  * We need a bit for restriper to be able to tell when chunks of type
  * SINGLE are available.  This "extended" profile format is used in
index 695fade..aa34c2d 100644 (file)
@@ -86,10 +86,6 @@ typedef unsigned long long u_quad_t;
 
 #define inline
 
-struct timespec {
-        long       ts_sec;
-        long       ts_nsec;
-};
 #else  /* DJGPP but not KERNEL */
 #include <sys/time.h>
 typedef unsigned long long u_quad_t;
@@ -110,13 +106,6 @@ typedef unsigned long long u_quad_t;
 #define cdev_t dev_t
 #endif
 
-#ifdef __CYGWIN32__
-struct timespec {
-        time_t  tv_sec;         /* seconds */
-        long    tv_nsec;        /* nanoseconds */
-};
-#endif
-
 #ifndef __BIT_TYPES_DEFINED__
 #define __BIT_TYPES_DEFINED__
 typedef signed char          int8_t;
@@ -211,6 +200,11 @@ struct CodaFid {
  */
 enum coda_vtype        { C_VNON, C_VREG, C_VDIR, C_VBLK, C_VCHR, C_VLNK, C_VSOCK, C_VFIFO, C_VBAD };
 
+struct coda_timespec {
+       int64_t         tv_sec;         /* seconds */
+       long            tv_nsec;        /* nanoseconds */
+};
+
 struct coda_vattr {
        long            va_type;        /* vnode type (for create) */
        u_short         va_mode;        /* files access mode and type */
@@ -220,9 +214,9 @@ struct coda_vattr {
        long            va_fileid;      /* file id */
        u_quad_t        va_size;        /* file size in bytes */
        long            va_blocksize;   /* blocksize preferred for i/o */
-       struct timespec va_atime;       /* time of last access */
-       struct timespec va_mtime;       /* time of last modification */
-       struct timespec va_ctime;       /* time file changed */
+       struct coda_timespec va_atime;  /* time of last access */
+       struct coda_timespec va_mtime;  /* time of last modification */
+       struct coda_timespec va_ctime;  /* time file changed */
        u_long          va_gen;         /* generation number of file */
        u_long          va_flags;       /* flags defined for file */
        cdev_t          va_rdev;        /* device special file represents */
@@ -277,7 +271,8 @@ struct coda_statfs {
 #define CODA_STATFS     34
 #define CODA_STORE      35
 #define CODA_RELEASE    36
-#define CODA_NCALLS 37
+#define CODA_ACCESS_INTENT 37
+#define CODA_NCALLS 38
 
 #define DOWNCALL(opcode) (opcode >= CODA_REPLACE && opcode <= CODA_PURGEFID)
 
@@ -287,7 +282,12 @@ struct coda_statfs {
 
 #define CIOC_KERNEL_VERSION _IOWR('c', 10, size_t)
 
-#define CODA_KERNEL_VERSION 3 /* 128-bit file identifiers */
+//      CODA_KERNEL_VERSION 0 /* don't care about kernel version number */
+//      CODA_KERNEL_VERSION 1 /* The old venus 4.6 compatible interface */
+//      CODA_KERNEL_VERSION 2 /* venus_lookup gets an extra parameter */
+//      CODA_KERNEL_VERSION 3 /* 128-bit file identifiers */
+//      CODA_KERNEL_VERSION 4 /* 64-bit timespec */
+#define CODA_KERNEL_VERSION 5 /* access intent support */
 
 /*
  *        Venus <-> Coda  RPC arguments
@@ -295,8 +295,8 @@ struct coda_statfs {
 struct coda_in_hdr {
     u_int32_t opcode;
     u_int32_t unique;      /* Keep multiple outstanding msgs distinct */
-    pid_t pid;
-    pid_t pgid;
+    __kernel_pid_t pid;
+    __kernel_pid_t pgid;
     vuid_t uid;
 };
 
@@ -642,6 +642,25 @@ struct coda_statfs_out {
     struct coda_statfs stat;
 };
 
+#define CODA_ACCESS_TYPE_READ          1
+#define CODA_ACCESS_TYPE_WRITE         2
+#define CODA_ACCESS_TYPE_MMAP          3
+#define CODA_ACCESS_TYPE_READ_FINISH   4
+#define CODA_ACCESS_TYPE_WRITE_FINISH  5
+
+/* coda_access_intent: NO_OUT */
+struct coda_access_intent_in {
+       struct coda_in_hdr ih;
+       struct CodaFid VFid;
+       int count;
+       int pos;
+       int type;
+};
+
+struct coda_access_intent_out {
+       struct coda_out_hdr out;
+};
+
 /* 
  * Occasionally, we don't cache the fid returned by CODA_LOOKUP. 
  * For instance, if the fid is inconsistent. 
@@ -673,6 +692,7 @@ union inputArgs {
     struct coda_open_by_fd_in coda_open_by_fd;
     struct coda_open_by_path_in coda_open_by_path;
     struct coda_statfs_in coda_statfs;
+    struct coda_access_intent_in coda_access_intent;
 };
 
 union outputArgs {
diff --git a/include/uapi/linux/coda_psdev.h b/include/uapi/linux/coda_psdev.h
deleted file mode 100644 (file)
index aa6623e..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-#ifndef _UAPI__CODA_PSDEV_H
-#define _UAPI__CODA_PSDEV_H
-
-#include <linux/magic.h>
-
-#define CODA_PSDEV_MAJOR 67
-#define MAX_CODADEVS  5           /* how many do we allow */
-
-
-/* messages between coda filesystem in kernel and Venus */
-struct upc_req {
-       struct list_head    uc_chain;
-       caddr_t             uc_data;
-       u_short             uc_flags;
-       u_short             uc_inSize;  /* Size is at most 5000 bytes */
-       u_short             uc_outSize;
-       u_short             uc_opcode;  /* copied from data to save lookup */
-       int                 uc_unique;
-       wait_queue_head_t   uc_sleep;   /* process' wait queue */
-};
-
-#define CODA_REQ_ASYNC  0x1
-#define CODA_REQ_READ   0x2
-#define CODA_REQ_WRITE  0x4
-#define CODA_REQ_ABORT  0x8
-
-#endif /* _UAPI__CODA_PSDEV_H */
index a7c1954..5e3f12d 100644 (file)
@@ -116,7 +116,7 @@ struct kvm_irq_level {
         * ACPI gsi notion of irq.
         * For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47..
         * For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23..
-        * For ARM: See Documentation/virtual/kvm/api.txt
+        * For ARM: See Documentation/virt/kvm/api.txt
         */
        union {
                __u32 irq;
@@ -1086,7 +1086,7 @@ struct kvm_xen_hvm_config {
  *
  * KVM_IRQFD_FLAG_RESAMPLE indicates resamplefd is valid and specifies
  * the irqfd to operate in resampling mode for level triggered interrupt
- * emulation.  See Documentation/virtual/kvm/api.txt.
+ * emulation.  See Documentation/virt/kvm/api.txt.
  */
 #define KVM_IRQFD_FLAG_RESAMPLE (1 << 1)
 
index 665e186..1274c69 100644 (file)
@@ -92,5 +92,6 @@
 #define BALLOON_KVM_MAGIC      0x13661366
 #define ZSMALLOC_MAGIC         0x58295829
 #define DMA_BUF_MAGIC          0x444d4142      /* "DMAB" */
+#define Z3FOLD_MAGIC           0x33
 
 #endif /* __LINUX_MAGIC_H__ */
index 75758ec..beb9a9d 100644 (file)
@@ -2863,7 +2863,7 @@ enum nl80211_attrs {
 #define NL80211_HT_CAPABILITY_LEN              26
 #define NL80211_VHT_CAPABILITY_LEN             12
 #define NL80211_HE_MIN_CAPABILITY_LEN           16
-#define NL80211_HE_MAX_CAPABILITY_LEN           51
+#define NL80211_HE_MAX_CAPABILITY_LEN           54
 #define NL80211_MAX_NR_CIPHER_SUITES           5
 #define NL80211_MAX_NR_AKM_SUITES              2
 
index 1f62325..18f1852 100644 (file)
@@ -1174,7 +1174,7 @@ enum {
        TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME, /* s64 */
        TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME_EXTENSION, /* s64 */
        TCA_TAPRIO_ATTR_FLAGS, /* u32 */
-       TCA_TAPRIO_ATTR_TXTIME_DELAY, /* s32 */
+       TCA_TAPRIO_ATTR_TXTIME_DELAY, /* u32 */
        __TCA_TAPRIO_ATTR_MAX,
 };
 
index d5a1b8a..a71b6e3 100644 (file)
@@ -73,6 +73,41 @@ struct seccomp_metadata {
        __u64 flags;            /* Output: filter's flags */
 };
 
+#define PTRACE_GET_SYSCALL_INFO                0x420e
+#define PTRACE_SYSCALL_INFO_NONE       0
+#define PTRACE_SYSCALL_INFO_ENTRY      1
+#define PTRACE_SYSCALL_INFO_EXIT       2
+#define PTRACE_SYSCALL_INFO_SECCOMP    3
+
+struct ptrace_syscall_info {
+       __u8 op;        /* PTRACE_SYSCALL_INFO_* */
+       __u32 arch __attribute__((__aligned__(sizeof(__u32))));
+       __u64 instruction_pointer;
+       __u64 stack_pointer;
+       union {
+               struct {
+                       __u64 nr;
+                       __u64 args[6];
+               } entry;
+               struct {
+                       __s64 rval;
+                       __u8 is_error;
+               } exit;
+               struct {
+                       __u64 nr;
+                       __u64 args[6];
+                       __u32 ret_data;
+               } seccomp;
+       };
+};
+
+/*
+ * These values are stored in task->ptrace_message
+ * by tracehook_report_syscall_* to describe the current syscall-stop.
+ */
+#define PTRACE_EVENTMSG_SYSCALL_ENTRY  1
+#define PTRACE_EVENTMSG_SYSCALL_EXIT   2
+
 /* Read signals from a shared (process wide) queue */
 #define PTRACE_PEEKSIGINFO_SHARED      (1 << 0)
 
index 9d9705c..2427bc4 100644 (file)
@@ -518,7 +518,13 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_RGBX444 v4l2_fourcc('R', 'X', '1', '2') /* 16  rrrrgggg bbbbxxxx */
 #define V4L2_PIX_FMT_ABGR444 v4l2_fourcc('A', 'B', '1', '2') /* 16  aaaabbbb ggggrrrr */
 #define V4L2_PIX_FMT_XBGR444 v4l2_fourcc('X', 'B', '1', '2') /* 16  xxxxbbbb ggggrrrr */
-#define V4L2_PIX_FMT_BGRA444 v4l2_fourcc('B', 'A', '1', '2') /* 16  bbbbgggg rrrraaaa */
+
+/*
+ * Originally this had 'BA12' as fourcc, but this clashed with the older
+ * V4L2_PIX_FMT_SGRBG12 which inexplicably used that same fourcc.
+ * So use 'GA12' instead for V4L2_PIX_FMT_BGRA444.
+ */
+#define V4L2_PIX_FMT_BGRA444 v4l2_fourcc('G', 'A', '1', '2') /* 16  bbbbgggg rrrraaaa */
 #define V4L2_PIX_FMT_BGRX444 v4l2_fourcc('B', 'X', '1', '2') /* 16  bbbbgggg rrrrxxxx */
 #define V4L2_PIX_FMT_RGB555  v4l2_fourcc('R', 'G', 'B', 'O') /* 16  RGB-5-5-5     */
 #define V4L2_PIX_FMT_ARGB555 v4l2_fourcc('A', 'R', '1', '5') /* 16  ARGB-1-5-5-5  */
index 6d5c3b2..348fd01 100644 (file)
@@ -43,5 +43,7 @@
 #define VIRTIO_ID_INPUT        18 /* virtio input */
 #define VIRTIO_ID_VSOCK        19 /* virtio vsock transport */
 #define VIRTIO_ID_CRYPTO       20 /* virtio crypto */
+#define VIRTIO_ID_IOMMU        23 /* virtio IOMMU */
+#define VIRTIO_ID_PMEM         27 /* virtio pmem */
 
 #endif /* _LINUX_VIRTIO_IDS_H */
diff --git a/include/uapi/linux/virtio_iommu.h b/include/uapi/linux/virtio_iommu.h
new file mode 100644 (file)
index 0000000..ba1b460
--- /dev/null
@@ -0,0 +1,161 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Virtio-iommu definition v0.9
+ *
+ * Copyright (C) 2018 Arm Ltd.
+ */
+#ifndef _UAPI_LINUX_VIRTIO_IOMMU_H
+#define _UAPI_LINUX_VIRTIO_IOMMU_H
+
+#include <linux/types.h>
+
+/* Feature bits */
+#define VIRTIO_IOMMU_F_INPUT_RANGE             0
+#define VIRTIO_IOMMU_F_DOMAIN_BITS             1
+#define VIRTIO_IOMMU_F_MAP_UNMAP               2
+#define VIRTIO_IOMMU_F_BYPASS                  3
+#define VIRTIO_IOMMU_F_PROBE                   4
+
+struct virtio_iommu_range {
+       __u64                                   start;
+       __u64                                   end;
+};
+
+struct virtio_iommu_config {
+       /* Supported page sizes */
+       __u64                                   page_size_mask;
+       /* Supported IOVA range */
+       struct virtio_iommu_range               input_range;
+       /* Max domain ID size */
+       __u8                                    domain_bits;
+       __u8                                    padding[3];
+       /* Probe buffer size */
+       __u32                                   probe_size;
+};
+
+/* Request types */
+#define VIRTIO_IOMMU_T_ATTACH                  0x01
+#define VIRTIO_IOMMU_T_DETACH                  0x02
+#define VIRTIO_IOMMU_T_MAP                     0x03
+#define VIRTIO_IOMMU_T_UNMAP                   0x04
+#define VIRTIO_IOMMU_T_PROBE                   0x05
+
+/* Status types */
+#define VIRTIO_IOMMU_S_OK                      0x00
+#define VIRTIO_IOMMU_S_IOERR                   0x01
+#define VIRTIO_IOMMU_S_UNSUPP                  0x02
+#define VIRTIO_IOMMU_S_DEVERR                  0x03
+#define VIRTIO_IOMMU_S_INVAL                   0x04
+#define VIRTIO_IOMMU_S_RANGE                   0x05
+#define VIRTIO_IOMMU_S_NOENT                   0x06
+#define VIRTIO_IOMMU_S_FAULT                   0x07
+
+struct virtio_iommu_req_head {
+       __u8                                    type;
+       __u8                                    reserved[3];
+};
+
+struct virtio_iommu_req_tail {
+       __u8                                    status;
+       __u8                                    reserved[3];
+};
+
+struct virtio_iommu_req_attach {
+       struct virtio_iommu_req_head            head;
+       __le32                                  domain;
+       __le32                                  endpoint;
+       __u8                                    reserved[8];
+       struct virtio_iommu_req_tail            tail;
+};
+
+struct virtio_iommu_req_detach {
+       struct virtio_iommu_req_head            head;
+       __le32                                  domain;
+       __le32                                  endpoint;
+       __u8                                    reserved[8];
+       struct virtio_iommu_req_tail            tail;
+};
+
+#define VIRTIO_IOMMU_MAP_F_READ                        (1 << 0)
+#define VIRTIO_IOMMU_MAP_F_WRITE               (1 << 1)
+#define VIRTIO_IOMMU_MAP_F_EXEC                        (1 << 2)
+#define VIRTIO_IOMMU_MAP_F_MMIO                        (1 << 3)
+
+#define VIRTIO_IOMMU_MAP_F_MASK                        (VIRTIO_IOMMU_MAP_F_READ |      \
+                                                VIRTIO_IOMMU_MAP_F_WRITE |     \
+                                                VIRTIO_IOMMU_MAP_F_EXEC |      \
+                                                VIRTIO_IOMMU_MAP_F_MMIO)
+
+struct virtio_iommu_req_map {
+       struct virtio_iommu_req_head            head;
+       __le32                                  domain;
+       __le64                                  virt_start;
+       __le64                                  virt_end;
+       __le64                                  phys_start;
+       __le32                                  flags;
+       struct virtio_iommu_req_tail            tail;
+};
+
+struct virtio_iommu_req_unmap {
+       struct virtio_iommu_req_head            head;
+       __le32                                  domain;
+       __le64                                  virt_start;
+       __le64                                  virt_end;
+       __u8                                    reserved[4];
+       struct virtio_iommu_req_tail            tail;
+};
+
+#define VIRTIO_IOMMU_PROBE_T_NONE              0
+#define VIRTIO_IOMMU_PROBE_T_RESV_MEM          1
+
+#define VIRTIO_IOMMU_PROBE_T_MASK              0xfff
+
+struct virtio_iommu_probe_property {
+       __le16                                  type;
+       __le16                                  length;
+};
+
+#define VIRTIO_IOMMU_RESV_MEM_T_RESERVED       0
+#define VIRTIO_IOMMU_RESV_MEM_T_MSI            1
+
+struct virtio_iommu_probe_resv_mem {
+       struct virtio_iommu_probe_property      head;
+       __u8                                    subtype;
+       __u8                                    reserved[3];
+       __le64                                  start;
+       __le64                                  end;
+};
+
+struct virtio_iommu_req_probe {
+       struct virtio_iommu_req_head            head;
+       __le32                                  endpoint;
+       __u8                                    reserved[64];
+
+       __u8                                    properties[];
+
+       /*
+        * Tail follows the variable-length properties array. No padding,
+        * property lengths are all aligned on 8 bytes.
+        */
+};
+
+/* Fault types */
+#define VIRTIO_IOMMU_FAULT_R_UNKNOWN           0
+#define VIRTIO_IOMMU_FAULT_R_DOMAIN            1
+#define VIRTIO_IOMMU_FAULT_R_MAPPING           2
+
+#define VIRTIO_IOMMU_FAULT_F_READ              (1 << 0)
+#define VIRTIO_IOMMU_FAULT_F_WRITE             (1 << 1)
+#define VIRTIO_IOMMU_FAULT_F_EXEC              (1 << 2)
+#define VIRTIO_IOMMU_FAULT_F_ADDRESS           (1 << 8)
+
+struct virtio_iommu_fault {
+       __u8                                    reason;
+       __u8                                    reserved[3];
+       __le32                                  flags;
+       __le32                                  endpoint;
+       __u8                                    reserved2[4];
+       __le64                                  address;
+};
+
+#endif
diff --git a/include/uapi/linux/virtio_pmem.h b/include/uapi/linux/virtio_pmem.h
new file mode 100644 (file)
index 0000000..9a63ed6
--- /dev/null
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/*
+ * Definitions for virtio-pmem devices.
+ *
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * Author(s): Pankaj Gupta <pagupta@redhat.com>
+ */
+
+#ifndef _UAPI_LINUX_VIRTIO_PMEM_H
+#define _UAPI_LINUX_VIRTIO_PMEM_H
+
+#include <linux/types.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_config.h>
+
+struct virtio_pmem_config {
+       __u64 start;
+       __u64 size;
+};
+
+#define VIRTIO_PMEM_REQ_TYPE_FLUSH      0
+
+struct virtio_pmem_resp {
+       /* Host return status corresponding to flush request */
+       __le32 ret;
+};
+
+struct virtio_pmem_req {
+       /* command type */
+       __le32 type;
+};
+
+#endif
index 64c14cb..b8bb285 100644 (file)
@@ -36,7 +36,7 @@
 #include <linux/types.h>
 #include <linux/ioctl.h>
 
-/* Documentation/ioctl/ioctl-number.txt */
+/* Documentation/ioctl/ioctl-number.rst */
 #define RDMA_IOCTL_MAGIC       0x1b
 #define RDMA_VERBS_IOCTL \
        _IOWR(RDMA_IOCTL_MAGIC, 1, struct ib_uverbs_ioctl_hdr)
index 4914b93..6fb95aa 100644 (file)
@@ -27,16 +27,6 @@ void balloon_set_new_target(unsigned long target);
 int alloc_xenballooned_pages(int nr_pages, struct page **pages);
 void free_xenballooned_pages(int nr_pages, struct page **pages);
 
-struct device;
-#ifdef CONFIG_XEN_SELFBALLOONING
-extern int register_xen_selfballooning(struct device *dev);
-#else
-static inline int register_xen_selfballooning(struct device *dev)
-{
-       return -ENOSYS;
-}
-#endif
-
 #ifdef CONFIG_XEN_BALLOON
 void xen_balloon_init(void);
 #else
index a488971..c0e6a05 100644 (file)
@@ -3,6 +3,7 @@
 #define _XEN_EVENTS_H
 
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #ifdef CONFIG_PCI_MSI
 #include <linux/msi.h>
 #endif
@@ -59,7 +60,7 @@ void evtchn_put(unsigned int evtchn);
 
 void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector);
 void rebind_evtchn_irq(int evtchn, int irq);
-int xen_rebind_evtchn_to_cpu(int evtchn, unsigned tcpu);
+int xen_set_affinity_evtchn(struct irq_desc *desc, unsigned int tcpu);
 
 static inline void notify_remote_via_evtchn(int port)
 {
diff --git a/include/xen/tmem.h b/include/xen/tmem.h
deleted file mode 100644 (file)
index c80bafe..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _XEN_TMEM_H
-#define _XEN_TMEM_H
-
-#include <linux/types.h>
-
-#ifdef CONFIG_XEN_TMEM_MODULE
-#define tmem_enabled true
-#else
-/* defined in drivers/xen/tmem.c */
-extern bool tmem_enabled;
-#endif
-
-#ifdef CONFIG_XEN_SELFBALLOONING
-extern int xen_selfballoon_init(bool, bool);
-#endif
-
-#endif /* _XEN_TMEM_H */
index 9697c6b..bd7d650 100644 (file)
@@ -550,7 +550,7 @@ config PSI
          have cpu.pressure, memory.pressure, and io.pressure files,
          which aggregate pressure stalls for the grouped tasks only.
 
-         For more details see Documentation/accounting/psi.txt.
+         For more details see Documentation/accounting/psi.rst.
 
          Say N if unsure.
 
@@ -821,7 +821,7 @@ menuconfig CGROUPS
          controls or device isolation.
          See
                - Documentation/scheduler/sched-design-CFS.rst  (CFS)
-               - Documentation/cgroup-v1/ (features for grouping, isolation
+               - Documentation/admin-guide/cgroup-v1/ (features for grouping, isolation
                                          and resource control)
 
          Say N if unsure.
@@ -883,7 +883,7 @@ config BLK_CGROUP
        CONFIG_CFQ_GROUP_IOSCHED=y; for enabling throttling policy, set
        CONFIG_BLK_DEV_THROTTLING=y.
 
-       See Documentation/cgroup-v1/blkio-controller.rst for more information.
+       See Documentation/admin-guide/cgroup-v1/blkio-controller.rst for more information.
 
 config CGROUP_WRITEBACK
        bool
@@ -1827,7 +1827,7 @@ config SLAB_FREELIST_HARDENED
        help
          Many kernel heap attacks try to target slab cache metadata and
          other infrastructure. This options makes minor performance
-         sacrifies to harden the kernel slab allocator against common
+         sacrifices to harden the kernel slab allocator against common
          freelist exploit methods.
 
 config SHUFFLE_PAGE_ALLOCATOR
@@ -1859,7 +1859,7 @@ config SLUB_CPU_PARTIAL
        depends on SLUB && SMP
        bool "SLUB per cpu partial cache"
        help
-         Per cpu partial caches accellerate objects allocation and freeing
+         Per cpu partial caches accelerate objects allocation and freeing
          that is local to a processor at the price of more indeterminism
          in the latency of the free. On overflow these caches will be cleared
          which requires the taking of locks that may cause latency spikes.
index 2d1ea30..53cb37b 100644 (file)
@@ -630,41 +630,23 @@ static bool is_tmpfs;
 static struct dentry *rootfs_mount(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data)
 {
-       static unsigned long once;
        void *fill = ramfs_fill_super;
 
-       if (test_and_set_bit(0, &once))
-               return ERR_PTR(-ENODEV);
-
        if (IS_ENABLED(CONFIG_TMPFS) && is_tmpfs)
                fill = shmem_fill_super;
 
        return mount_nodev(fs_type, flags, data, fill);
 }
 
-static struct file_system_type rootfs_fs_type = {
+struct file_system_type rootfs_fs_type = {
        .name           = "rootfs",
        .mount          = rootfs_mount,
        .kill_sb        = kill_litter_super,
 };
 
-int __init init_rootfs(void)
+void __init init_rootfs(void)
 {
-       int err = register_filesystem(&rootfs_fs_type);
-
-       if (err)
-               return err;
-
        if (IS_ENABLED(CONFIG_TMPFS) && !saved_root_name[0] &&
-               (!root_fs_names || strstr(root_fs_names, "tmpfs"))) {
-               err = shmem_init();
+               (!root_fs_names || strstr(root_fs_names, "tmpfs")))
                is_tmpfs = true;
-       } else {
-               err = init_ramfs_fs();
-       }
-
-       if (err)
-               unregister_filesystem(&rootfs_fs_type);
-
-       return err;
 }
index ff5803b..96f8d5a 100644 (file)
@@ -1025,7 +1025,6 @@ static void __init do_initcalls(void)
 static void __init do_basic_setup(void)
 {
        cpuset_init_smp();
-       shmem_init();
        driver_init();
        init_irq_proc();
        do_ctors();
index 2b14ce8..affd665 100644 (file)
@@ -113,9 +113,6 @@ static int proc_ipc_sem_dointvec(struct ctl_table *table, int write,
 #define proc_ipc_sem_dointvec     NULL
 #endif
 
-static int zero;
-static int one = 1;
-static int int_max = INT_MAX;
 int ipc_mni = IPCMNI;
 int ipc_mni_shift = IPCMNI_SHIFT;
 int ipc_min_cycle = RADIX_TREE_MAP_SIZE;
@@ -141,7 +138,7 @@ static struct ctl_table ipc_kern_table[] = {
                .maxlen         = sizeof(init_ipc_ns.shm_ctlmni),
                .mode           = 0644,
                .proc_handler   = proc_ipc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &ipc_mni,
        },
        {
@@ -150,8 +147,8 @@ static struct ctl_table ipc_kern_table[] = {
                .maxlen         = sizeof(init_ipc_ns.shm_rmid_forced),
                .mode           = 0644,
                .proc_handler   = proc_ipc_dointvec_minmax_orphans,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        {
                .procname       = "msgmax",
@@ -159,8 +156,8 @@ static struct ctl_table ipc_kern_table[] = {
                .maxlen         = sizeof(init_ipc_ns.msg_ctlmax),
                .mode           = 0644,
                .proc_handler   = proc_ipc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &int_max,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_INT_MAX,
        },
        {
                .procname       = "msgmni",
@@ -168,7 +165,7 @@ static struct ctl_table ipc_kern_table[] = {
                .maxlen         = sizeof(init_ipc_ns.msg_ctlmni),
                .mode           = 0644,
                .proc_handler   = proc_ipc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &ipc_mni,
        },
        {
@@ -177,8 +174,8 @@ static struct ctl_table ipc_kern_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_ipc_auto_msgmni,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        {
                .procname       =  "msgmnb",
@@ -186,8 +183,8 @@ static struct ctl_table ipc_kern_table[] = {
                .maxlen         = sizeof(init_ipc_ns.msg_ctlmnb),
                .mode           = 0644,
                .proc_handler   = proc_ipc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &int_max,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_INT_MAX,
        },
        {
                .procname       = "sem",
@@ -203,8 +200,8 @@ static struct ctl_table ipc_kern_table[] = {
                .maxlen         = sizeof(init_ipc_ns.ids[IPC_SEM_IDS].next_id),
                .mode           = 0644,
                .proc_handler   = proc_ipc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &int_max,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_INT_MAX,
        },
        {
                .procname       = "msg_next_id",
@@ -212,8 +209,8 @@ static struct ctl_table ipc_kern_table[] = {
                .maxlen         = sizeof(init_ipc_ns.ids[IPC_MSG_IDS].next_id),
                .mode           = 0644,
                .proc_handler   = proc_ipc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &int_max,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_INT_MAX,
        },
        {
                .procname       = "shm_next_id",
@@ -221,8 +218,8 @@ static struct ctl_table ipc_kern_table[] = {
                .maxlen         = sizeof(init_ipc_ns.ids[IPC_SHM_IDS].next_id),
                .mode           = 0644,
                .proc_handler   = proc_ipc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &int_max,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_INT_MAX,
        },
 #endif
        {}
index 216cad1..7a5a8ed 100644 (file)
@@ -364,8 +364,6 @@ static int mqueue_get_tree(struct fs_context *fc)
 {
        struct mqueue_fs_context *ctx = fc->fs_private;
 
-       put_user_ns(fc->user_ns);
-       fc->user_ns = get_user_ns(ctx->ipc_ns->user_ns);
        fc->s_fs_info = ctx->ipc_ns;
        return vfs_get_super(fc, vfs_get_keyed_super, mqueue_fill_super);
 }
@@ -374,8 +372,7 @@ static void mqueue_fs_context_free(struct fs_context *fc)
 {
        struct mqueue_fs_context *ctx = fc->fs_private;
 
-       if (ctx->ipc_ns)
-               put_ipc_ns(ctx->ipc_ns);
+       put_ipc_ns(ctx->ipc_ns);
        kfree(ctx);
 }
 
@@ -388,6 +385,8 @@ static int mqueue_init_fs_context(struct fs_context *fc)
                return -ENOMEM;
 
        ctx->ipc_ns = get_ipc_ns(current->nsproxy->ipc_ns);
+       put_user_ns(fc->user_ns);
+       fc->user_ns = get_user_ns(ctx->ipc_ns->user_ns);
        fc->fs_private = ctx;
        fc->ops = &mqueue_fs_context_ops;
        return 0;
@@ -406,6 +405,8 @@ static struct vfsmount *mq_create_mount(struct ipc_namespace *ns)
        ctx = fc->fs_private;
        put_ipc_ns(ctx->ipc_ns);
        ctx->ipc_ns = get_ipc_ns(ns);
+       put_user_ns(fc->user_ns);
+       fc->user_ns = get_user_ns(ctx->ipc_ns->user_ns);
 
        mnt = fc_mount(fc);
        put_fs_context(fc);
@@ -438,7 +439,6 @@ static void mqueue_evict_inode(struct inode *inode)
 {
        struct mqueue_inode_info *info;
        struct user_struct *user;
-       unsigned long mq_bytes, mq_treesize;
        struct ipc_namespace *ipc_ns;
        struct msg_msg *msg, *nmsg;
        LIST_HEAD(tmp_msg);
@@ -461,16 +461,18 @@ static void mqueue_evict_inode(struct inode *inode)
                free_msg(msg);
        }
 
-       /* Total amount of bytes accounted for the mqueue */
-       mq_treesize = info->attr.mq_maxmsg * sizeof(struct msg_msg) +
-               min_t(unsigned int, info->attr.mq_maxmsg, MQ_PRIO_MAX) *
-               sizeof(struct posix_msg_tree_node);
-
-       mq_bytes = mq_treesize + (info->attr.mq_maxmsg *
-                                 info->attr.mq_msgsize);
-
        user = info->user;
        if (user) {
+               unsigned long mq_bytes, mq_treesize;
+
+               /* Total amount of bytes accounted for the mqueue */
+               mq_treesize = info->attr.mq_maxmsg * sizeof(struct msg_msg) +
+                       min_t(unsigned int, info->attr.mq_maxmsg, MQ_PRIO_MAX) *
+                       sizeof(struct posix_msg_tree_node);
+
+               mq_bytes = mq_treesize + (info->attr.mq_maxmsg *
+                                         info->attr.mq_msgsize);
+
                spin_lock(&mq_lock);
                user->mq_bytes -= mq_bytes;
                /*
index dc0b682..deff972 100644 (file)
@@ -38,7 +38,7 @@ config PREEMPT_VOLUNTARY
 config PREEMPT
        bool "Preemptible Kernel (Low-Latency Desktop)"
        depends on !ARCH_NO_PREEMPT
-       select PREEMPT_COUNT
+       select PREEMPTION
        select UNINLINE_SPIN_UNLOCK if !ARCH_INLINE_SPIN_UNLOCK
        help
          This option reduces the latency of the kernel by making
@@ -55,7 +55,28 @@ config PREEMPT
          embedded system with latency requirements in the milliseconds
          range.
 
+config PREEMPT_RT
+       bool "Fully Preemptible Kernel (Real-Time)"
+       depends on EXPERT && ARCH_SUPPORTS_RT
+       select PREEMPTION
+       help
+         This option turns the kernel into a real-time kernel by replacing
+         various locking primitives (spinlocks, rwlocks, etc.) with
+         preemptible priority-inheritance aware variants, enforcing
+         interrupt threading and introducing mechanisms to break up long
+         non-preemptible sections. This makes the kernel, except for very
+         low level and critical code pathes (entry code, scheduler, low
+         level interrupt handling) fully preemptible and brings most
+         execution contexts under scheduler control.
+
+         Select this if you are building a kernel for systems which
+         require real-time guarantees.
+
 endchoice
 
 config PREEMPT_COUNT
        bool
+
+config PREEMPTION
+       bool
+       select PREEMPT_COUNT
index 546ebee..5fcc7a1 100644 (file)
@@ -1073,11 +1073,18 @@ const struct btf_type *btf_type_id_size(const struct btf *btf,
                                 !btf_type_is_var(size_type)))
                        return NULL;
 
-               size = btf->resolved_sizes[size_type_id];
                size_type_id = btf->resolved_ids[size_type_id];
                size_type = btf_type_by_id(btf, size_type_id);
                if (btf_type_nosize_or_null(size_type))
                        return NULL;
+               else if (btf_type_has_size(size_type))
+                       size = size_type->size;
+               else if (btf_type_is_array(size_type))
+                       size = btf->resolved_sizes[size_type_id];
+               else if (btf_type_is_ptr(size_type))
+                       size = sizeof(void *);
+               else
+                       return NULL;
        }
 
        *type_id = size_type_id;
@@ -1602,7 +1609,6 @@ static int btf_modifier_resolve(struct btf_verifier_env *env,
        const struct btf_type *next_type;
        u32 next_type_id = t->type;
        struct btf *btf = env->btf;
-       u32 next_type_size = 0;
 
        next_type = btf_type_by_id(btf, next_type_id);
        if (!next_type || btf_type_is_resolve_source_only(next_type)) {
@@ -1620,7 +1626,7 @@ static int btf_modifier_resolve(struct btf_verifier_env *env,
         * save us a few type-following when we use it later (e.g. in
         * pretty print).
         */
-       if (!btf_type_id_size(btf, &next_type_id, &next_type_size)) {
+       if (!btf_type_id_size(btf, &next_type_id, NULL)) {
                if (env_type_is_resolved(env, next_type_id))
                        next_type = btf_type_id_resolve(btf, &next_type_id);
 
@@ -1633,7 +1639,7 @@ static int btf_modifier_resolve(struct btf_verifier_env *env,
                }
        }
 
-       env_stack_pop_resolved(env, next_type_id, next_type_size);
+       env_stack_pop_resolved(env, next_type_id, 0);
 
        return 0;
 }
@@ -1645,7 +1651,6 @@ static int btf_var_resolve(struct btf_verifier_env *env,
        const struct btf_type *t = v->t;
        u32 next_type_id = t->type;
        struct btf *btf = env->btf;
-       u32 next_type_size;
 
        next_type = btf_type_by_id(btf, next_type_id);
        if (!next_type || btf_type_is_resolve_source_only(next_type)) {
@@ -1675,12 +1680,12 @@ static int btf_var_resolve(struct btf_verifier_env *env,
         * forward types or similar that would resolve to size of
         * zero is allowed.
         */
-       if (!btf_type_id_size(btf, &next_type_id, &next_type_size)) {
+       if (!btf_type_id_size(btf, &next_type_id, NULL)) {
                btf_verifier_log_type(env, v->t, "Invalid type_id");
                return -EINVAL;
        }
 
-       env_stack_pop_resolved(env, next_type_id, next_type_size);
+       env_stack_pop_resolved(env, next_type_id, 0);
 
        return 0;
 }
index 1607955..8191a7d 100644 (file)
@@ -1295,11 +1295,11 @@ bool bpf_opcode_in_insntable(u8 code)
  *
  * Decode and execute eBPF instructions.
  */
-static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, u64 *stack)
+static u64 __no_fgcse ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, u64 *stack)
 {
 #define BPF_INSN_2_LBL(x, y)    [BPF_##x | BPF_##y] = &&x##_##y
 #define BPF_INSN_3_LBL(x, y, z) [BPF_##x | BPF_##y | BPF_##z] = &&x##_##y##_##z
-       static const void *jumptable[256] = {
+       static const void * const jumptable[256] __annotate_jump_table = {
                [0 ... 255] = &&default_label,
                /* Now overwrite non-defaults ... */
                BPF_INSN_MAP(BPF_INSN_2_LBL, BPF_INSN_3_LBL),
@@ -1558,7 +1558,6 @@ out:
                BUG_ON(1);
                return 0;
 }
-STACK_FRAME_NON_STANDARD(___bpf_prog_run); /* jump table */
 
 #define PROG_NAME(stack_size) __bpf_prog_run##stack_size
 #define DEFINE_BPF_PROG_RUN(stack_size) \
index a2e7637..5900cbb 100644 (file)
@@ -1519,9 +1519,9 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx,
                        return -EFAULT;
                }
                *stack_mask |= 1ull << spi;
-       } else if (class == BPF_STX) {
+       } else if (class == BPF_STX || class == BPF_ST) {
                if (*reg_mask & dreg)
-                       /* stx shouldn't be using _scalar_ dst_reg
+                       /* stx & st shouldn't be using _scalar_ dst_reg
                         * to access memory. It means backtracking
                         * encountered a case of pointer subtraction.
                         */
@@ -1540,7 +1540,8 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx,
                if (!(*stack_mask & (1ull << spi)))
                        return 0;
                *stack_mask &= ~(1ull << spi);
-               *reg_mask |= sreg;
+               if (class == BPF_STX)
+                       *reg_mask |= sreg;
        } else if (class == BPF_JMP || class == BPF_JMP32) {
                if (opcode == BPF_CALL) {
                        if (insn->src_reg == BPF_PSEUDO_CALL)
@@ -1569,10 +1570,6 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx,
                if (mode == BPF_IND || mode == BPF_ABS)
                        /* to be analyzed */
                        return -ENOTSUPP;
-       } else if (class == BPF_ST) {
-               if (*reg_mask & dreg)
-                       /* likely pointer subtraction */
-                       return -ENOTSUPP;
        }
        return 0;
 }
@@ -6106,11 +6103,13 @@ static int check_return_code(struct bpf_verifier_env *env)
                if (env->prog->expected_attach_type == BPF_CGROUP_UDP4_RECVMSG ||
                    env->prog->expected_attach_type == BPF_CGROUP_UDP6_RECVMSG)
                        range = tnum_range(1, 1);
+               break;
        case BPF_PROG_TYPE_CGROUP_SKB:
                if (env->prog->expected_attach_type == BPF_CGROUP_INET_EGRESS) {
                        range = tnum_range(0, 3);
                        enforce_attach_type_range = tnum_range(2, 3);
                }
+               break;
        case BPF_PROG_TYPE_CGROUP_SOCK:
        case BPF_PROG_TYPE_SOCK_OPS:
        case BPF_PROG_TYPE_CGROUP_DEVICE:
index 300b0c4..753afbc 100644 (file)
@@ -2201,8 +2201,7 @@ static int cgroup_init_fs_context(struct fs_context *fc)
                fc->ops = &cgroup_fs_context_ops;
        else
                fc->ops = &cgroup1_fs_context_ops;
-       if (fc->user_ns)
-               put_user_ns(fc->user_ns);
+       put_user_ns(fc->user_ns);
        fc->user_ns = get_user_ns(ctx->ns->user_ns);
        fc->global = true;
        return 0;
@@ -2243,6 +2242,50 @@ static struct file_system_type cgroup2_fs_type = {
        .fs_flags               = FS_USERNS_MOUNT,
 };
 
+#ifdef CONFIG_CPUSETS
+static const struct fs_context_operations cpuset_fs_context_ops = {
+       .get_tree       = cgroup1_get_tree,
+       .free           = cgroup_fs_context_free,
+};
+
+/*
+ * This is ugly, but preserves the userspace API for existing cpuset
+ * users. If someone tries to mount the "cpuset" filesystem, we
+ * silently switch it to mount "cgroup" instead
+ */
+static int cpuset_init_fs_context(struct fs_context *fc)
+{
+       char *agent = kstrdup("/sbin/cpuset_release_agent", GFP_USER);
+       struct cgroup_fs_context *ctx;
+       int err;
+
+       err = cgroup_init_fs_context(fc);
+       if (err) {
+               kfree(agent);
+               return err;
+       }
+
+       fc->ops = &cpuset_fs_context_ops;
+
+       ctx = cgroup_fc2context(fc);
+       ctx->subsys_mask = 1 << cpuset_cgrp_id;
+       ctx->flags |= CGRP_ROOT_NOPREFIX;
+       ctx->release_agent = agent;
+
+       get_filesystem(&cgroup_fs_type);
+       put_filesystem(fc->fs_type);
+       fc->fs_type = &cgroup_fs_type;
+
+       return 0;
+}
+
+static struct file_system_type cpuset_fs_type = {
+       .name                   = "cpuset",
+       .init_fs_context        = cpuset_init_fs_context,
+       .fs_flags               = FS_USERNS_MOUNT,
+};
+#endif
+
 int cgroup_path_ns_locked(struct cgroup *cgrp, char *buf, size_t buflen,
                          struct cgroup_namespace *ns)
 {
@@ -5761,6 +5804,9 @@ int __init cgroup_init(void)
        WARN_ON(register_filesystem(&cgroup_fs_type));
        WARN_ON(register_filesystem(&cgroup2_fs_type));
        WARN_ON(!proc_create_single("cgroups", 0, NULL, proc_cgroupstats_show));
+#ifdef CONFIG_CPUSETS
+       WARN_ON(register_filesystem(&cpuset_fs_type));
+#endif
 
        return 0;
 }
index b3b02b9..5aa3753 100644 (file)
@@ -356,59 +356,6 @@ static inline bool is_in_v2_mode(void)
 }
 
 /*
- * This is ugly, but preserves the userspace API for existing cpuset
- * users. If someone tries to mount the "cpuset" filesystem, we
- * silently switch it to mount "cgroup" instead
- */
-static int cpuset_get_tree(struct fs_context *fc)
-{
-       struct file_system_type *cgroup_fs;
-       struct fs_context *new_fc;
-       int ret;
-
-       cgroup_fs = get_fs_type("cgroup");
-       if (!cgroup_fs)
-               return -ENODEV;
-
-       new_fc = fs_context_for_mount(cgroup_fs, fc->sb_flags);
-       if (IS_ERR(new_fc)) {
-               ret = PTR_ERR(new_fc);
-       } else {
-               static const char agent_path[] = "/sbin/cpuset_release_agent";
-               ret = vfs_parse_fs_string(new_fc, "cpuset", NULL, 0);
-               if (!ret)
-                       ret = vfs_parse_fs_string(new_fc, "noprefix", NULL, 0);
-               if (!ret)
-                       ret = vfs_parse_fs_string(new_fc, "release_agent",
-                                       agent_path, sizeof(agent_path) - 1);
-               if (!ret)
-                       ret = vfs_get_tree(new_fc);
-               if (!ret) {     /* steal the result */
-                       fc->root = new_fc->root;
-                       new_fc->root = NULL;
-               }
-               put_fs_context(new_fc);
-       }
-       put_filesystem(cgroup_fs);
-       return ret;
-}
-
-static const struct fs_context_operations cpuset_fs_context_ops = {
-       .get_tree       = cpuset_get_tree,
-};
-
-static int cpuset_init_fs_context(struct fs_context *fc)
-{
-       fc->ops = &cpuset_fs_context_ops;
-       return 0;
-}
-
-static struct file_system_type cpuset_fs_type = {
-       .name                   = "cpuset",
-       .init_fs_context        = cpuset_init_fs_context,
-};
-
-/*
  * Return in pmask the portion of a cpusets's cpus_allowed that
  * are online.  If none are online, walk up the cpuset hierarchy
  * until we find one that does have some online cpus.
@@ -729,7 +676,7 @@ static inline int nr_cpusets(void)
  * load balancing domains (sched domains) as specified by that partial
  * partition.
  *
- * See "What is sched_load_balance" in Documentation/cgroup-v1/cpusets.rst
+ * See "What is sched_load_balance" in Documentation/admin-guide/cgroup-v1/cpusets.rst
  * for a background explanation of this.
  *
  * Does not return errors, on the theory that the callers of this
@@ -2853,13 +2800,11 @@ struct cgroup_subsys cpuset_cgrp_subsys = {
 /**
  * cpuset_init - initialize cpusets at system boot
  *
- * Description: Initialize top_cpuset and the cpuset internal file system,
+ * Description: Initialize top_cpuset
  **/
 
 int __init cpuset_init(void)
 {
-       int err = 0;
-
        BUG_ON(!alloc_cpumask_var(&top_cpuset.cpus_allowed, GFP_KERNEL));
        BUG_ON(!alloc_cpumask_var(&top_cpuset.effective_cpus, GFP_KERNEL));
        BUG_ON(!zalloc_cpumask_var(&top_cpuset.subparts_cpus, GFP_KERNEL));
@@ -2873,10 +2818,6 @@ int __init cpuset_init(void)
        set_bit(CS_SCHED_LOAD_BALANCE, &top_cpuset.flags);
        top_cpuset.relax_domain_level = -1;
 
-       err = register_filesystem(&cpuset_fs_type);
-       if (err < 0)
-               return err;
-
        BUG_ON(!alloc_cpumask_var(&cpus_attach, GFP_KERNEL));
 
        return 0;
index f9a0ce6..c0a4c12 100644 (file)
@@ -144,7 +144,10 @@ void __put_cred(struct cred *cred)
        BUG_ON(cred == current->cred);
        BUG_ON(cred == current->real_cred);
 
-       call_rcu(&cred->rcu, put_cred_rcu);
+       if (cred->non_rcu)
+               put_cred_rcu(&cred->rcu);
+       else
+               call_rcu(&cred->rcu, put_cred_rcu);
 }
 EXPORT_SYMBOL(__put_cred);
 
@@ -261,6 +264,7 @@ struct cred *prepare_creds(void)
        old = task->cred;
        memcpy(new, old, sizeof(struct cred));
 
+       new->non_rcu = 0;
        atomic_set(&new->usage, 1);
        set_cred_subscribers(new, 0);
        get_group_info(new->group_info);
@@ -544,7 +548,19 @@ const struct cred *override_creds(const struct cred *new)
 
        validate_creds(old);
        validate_creds(new);
-       get_cred(new);
+
+       /*
+        * NOTE! This uses 'get_new_cred()' rather than 'get_cred()'.
+        *
+        * That means that we do not clear the 'non_rcu' flag, since
+        * we are only installing the cred into the thread-synchronous
+        * '->cred' pointer, not the '->real_cred' pointer that is
+        * visible to other threads under RCU.
+        *
+        * Also note that we did validate_creds() manually, not depending
+        * on the validation in 'get_cred()'.
+        */
+       get_new_cred((struct cred *)new);
        alter_cred_subscribers(new, 1);
        rcu_assign_pointer(current->cred, new);
        alter_cred_subscribers(old, -1);
@@ -681,6 +697,7 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
        validate_creds(old);
 
        *new = *old;
+       new->non_rcu = 0;
        atomic_set(&new->usage, 1);
        set_cred_subscribers(new, 0);
        get_uid(new->user);
index 70f8f8d..9decbba 100644 (file)
@@ -48,6 +48,9 @@ config ARCH_HAS_DMA_COHERENT_TO_PFN
 config ARCH_HAS_DMA_MMAP_PGPROT
        bool
 
+config ARCH_HAS_FORCE_DMA_UNENCRYPTED
+       bool
+
 config DMA_NONCOHERENT_CACHE_SYNC
        bool
 
index b90e1ae..59bdcee 100644 (file)
 #define ARCH_ZONE_DMA_BITS 24
 #endif
 
-/*
- * For AMD SEV all DMA must be to unencrypted addresses.
- */
-static inline bool force_dma_unencrypted(void)
-{
-       return sev_active();
-}
-
 static void report_addr(struct device *dev, dma_addr_t dma_addr, size_t size)
 {
        if (!dev->dma_mask) {
@@ -46,7 +38,7 @@ static void report_addr(struct device *dev, dma_addr_t dma_addr, size_t size)
 static inline dma_addr_t phys_to_dma_direct(struct device *dev,
                phys_addr_t phys)
 {
-       if (force_dma_unencrypted())
+       if (force_dma_unencrypted(dev))
                return __phys_to_dma(dev, phys);
        return phys_to_dma(dev, phys);
 }
@@ -67,7 +59,7 @@ static gfp_t __dma_direct_optimal_gfp_mask(struct device *dev, u64 dma_mask,
        if (dev->bus_dma_mask && dev->bus_dma_mask < dma_mask)
                dma_mask = dev->bus_dma_mask;
 
-       if (force_dma_unencrypted())
+       if (force_dma_unencrypted(dev))
                *phys_mask = __dma_to_phys(dev, dma_mask);
        else
                *phys_mask = dma_to_phys(dev, dma_mask);
@@ -159,7 +151,7 @@ void *dma_direct_alloc_pages(struct device *dev, size_t size,
        }
 
        ret = page_address(page);
-       if (force_dma_unencrypted()) {
+       if (force_dma_unencrypted(dev)) {
                set_memory_decrypted((unsigned long)ret, 1 << get_order(size));
                *dma_handle = __phys_to_dma(dev, page_to_phys(page));
        } else {
@@ -192,7 +184,7 @@ void dma_direct_free_pages(struct device *dev, size_t size, void *cpu_addr,
                return;
        }
 
-       if (force_dma_unencrypted())
+       if (force_dma_unencrypted(dev))
                set_memory_encrypted((unsigned long)cpu_addr, 1 << page_order);
 
        if (IS_ENABLED(CONFIG_ARCH_HAS_UNCACHED_SEGMENT) &&
@@ -242,12 +234,14 @@ void dma_direct_sync_sg_for_device(struct device *dev,
        int i;
 
        for_each_sg(sgl, sg, nents, i) {
-               if (unlikely(is_swiotlb_buffer(sg_phys(sg))))
-                       swiotlb_tbl_sync_single(dev, sg_phys(sg), sg->length,
+               phys_addr_t paddr = dma_to_phys(dev, sg_dma_address(sg));
+
+               if (unlikely(is_swiotlb_buffer(paddr)))
+                       swiotlb_tbl_sync_single(dev, paddr, sg->length,
                                        dir, SYNC_FOR_DEVICE);
 
                if (!dev_is_dma_coherent(dev))
-                       arch_sync_dma_for_device(dev, sg_phys(sg), sg->length,
+                       arch_sync_dma_for_device(dev, paddr, sg->length,
                                        dir);
        }
 }
@@ -279,11 +273,13 @@ void dma_direct_sync_sg_for_cpu(struct device *dev,
        int i;
 
        for_each_sg(sgl, sg, nents, i) {
+               phys_addr_t paddr = dma_to_phys(dev, sg_dma_address(sg));
+
                if (!dev_is_dma_coherent(dev))
-                       arch_sync_dma_for_cpu(dev, sg_phys(sg), sg->length, dir);
-       
-               if (unlikely(is_swiotlb_buffer(sg_phys(sg))))
-                       swiotlb_tbl_sync_single(dev, sg_phys(sg), sg->length, dir,
+                       arch_sync_dma_for_cpu(dev, paddr, sg->length, dir);
+
+               if (unlikely(is_swiotlb_buffer(paddr)))
+                       swiotlb_tbl_sync_single(dev, paddr, sg->length, dir,
                                        SYNC_FOR_CPU);
        }
 
@@ -407,11 +403,9 @@ int dma_direct_supported(struct device *dev, u64 mask)
 
 size_t dma_direct_max_mapping_size(struct device *dev)
 {
-       size_t size = SIZE_MAX;
-
        /* If SWIOTLB is active, use its maximum mapping size */
-       if (is_swiotlb_active())
-               size = swiotlb_max_mapping_size(dev);
-
-       return size;
+       if (is_swiotlb_active() &&
+           (dma_addressing_limited(dev) || swiotlb_force == SWIOTLB_FORCE))
+               return swiotlb_max_mapping_size(dev);
+       return SIZE_MAX;
 }
index 62fa5a8..9de2322 100644 (file)
@@ -129,15 +129,17 @@ setup_io_tlb_npages(char *str)
 }
 early_param("swiotlb", setup_io_tlb_npages);
 
+static bool no_iotlb_memory;
+
 unsigned long swiotlb_nr_tbl(void)
 {
-       return io_tlb_nslabs;
+       return unlikely(no_iotlb_memory) ? 0 : io_tlb_nslabs;
 }
 EXPORT_SYMBOL_GPL(swiotlb_nr_tbl);
 
 unsigned int swiotlb_max_segment(void)
 {
-       return max_segment;
+       return unlikely(no_iotlb_memory) ? 0 : max_segment;
 }
 EXPORT_SYMBOL_GPL(swiotlb_max_segment);
 
@@ -160,8 +162,6 @@ unsigned long swiotlb_size_or_default(void)
        return size ? size : (IO_TLB_DEFAULT_SIZE);
 }
 
-static bool no_iotlb_memory;
-
 void swiotlb_print_info(void)
 {
        unsigned long bytes = io_tlb_nslabs << IO_TLB_SHIFT;
@@ -317,6 +317,14 @@ swiotlb_late_init_with_default_size(size_t default_size)
        return rc;
 }
 
+static void swiotlb_cleanup(void)
+{
+       io_tlb_end = 0;
+       io_tlb_start = 0;
+       io_tlb_nslabs = 0;
+       max_segment = 0;
+}
+
 int
 swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs)
 {
@@ -367,10 +375,7 @@ cleanup4:
                                                         sizeof(int)));
        io_tlb_list = NULL;
 cleanup3:
-       io_tlb_end = 0;
-       io_tlb_start = 0;
-       io_tlb_nslabs = 0;
-       max_segment = 0;
+       swiotlb_cleanup();
        return -ENOMEM;
 }
 
@@ -394,10 +399,7 @@ void __init swiotlb_exit(void)
                memblock_free_late(io_tlb_start,
                                   PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT));
        }
-       io_tlb_start = 0;
-       io_tlb_end = 0;
-       io_tlb_nslabs = 0;
-       max_segment = 0;
+       swiotlb_cleanup();
 }
 
 /*
@@ -546,7 +548,7 @@ not_found:
        if (!(attrs & DMA_ATTR_NO_WARN) && printk_ratelimit())
                dev_warn(hwdev, "swiotlb buffer is full (sz: %zd bytes), total %lu (slots), used %lu (slots)\n",
                         size, io_tlb_nslabs, tmp_io_tlb_used);
-       return DMA_MAPPING_ERROR;
+       return (phys_addr_t)DMA_MAPPING_ERROR;
 found:
        io_tlb_used += nslots;
        spin_unlock_irqrestore(&io_tlb_lock, flags);
@@ -664,7 +666,7 @@ bool swiotlb_map(struct device *dev, phys_addr_t *phys, dma_addr_t *dma_addr,
        /* Oh well, have to allocate and map a bounce buffer. */
        *phys = swiotlb_tbl_map_single(dev, __phys_to_dma(dev, io_tlb_start),
                        *phys, size, dir, attrs);
-       if (*phys == DMA_MAPPING_ERROR)
+       if (*phys == (phys_addr_t)DMA_MAPPING_ERROR)
                return false;
 
        /* Ensure that the address returned is DMA'ble */
index eea9d52..026a145 100644 (file)
@@ -11618,9 +11618,7 @@ void perf_event_delayed_put(struct task_struct *task)
 
 struct file *perf_event_get(unsigned int fd)
 {
-       struct file *file;
-
-       file = fget_raw(fd);
+       struct file *file = fget(fd);
        if (!file)
                return ERR_PTR(-EBADF);
 
index a75b6a7..4436158 100644 (file)
@@ -720,6 +720,7 @@ static void exit_notify(struct task_struct *tsk, int group_dead)
        if (group_dead)
                kill_orphaned_pgrp(tsk->group_leader, NULL);
 
+       tsk->exit_state = EXIT_ZOMBIE;
        if (unlikely(tsk->ptrace)) {
                int sig = thread_group_leader(tsk) &&
                                thread_group_empty(tsk) &&
index dfa7898..d8ae0f1 100644 (file)
@@ -2405,6 +2405,16 @@ long _do_fork(struct kernel_clone_args *args)
        return nr;
 }
 
+bool legacy_clone_args_valid(const struct kernel_clone_args *kargs)
+{
+       /* clone(CLONE_PIDFD) uses parent_tidptr to return a pidfd */
+       if ((kargs->flags & CLONE_PIDFD) &&
+           (kargs->flags & CLONE_PARENT_SETTID))
+               return false;
+
+       return true;
+}
+
 #ifndef CONFIG_HAVE_COPY_THREAD_TLS
 /* For compatibility with architectures that call do_fork directly rather than
  * using the syscall entry points below. */
@@ -2416,6 +2426,7 @@ long do_fork(unsigned long clone_flags,
 {
        struct kernel_clone_args args = {
                .flags          = (clone_flags & ~CSIGNAL),
+               .pidfd          = parent_tidptr,
                .child_tid      = child_tidptr,
                .parent_tid     = parent_tidptr,
                .exit_signal    = (clone_flags & CSIGNAL),
@@ -2423,6 +2434,9 @@ long do_fork(unsigned long clone_flags,
                .stack_size     = stack_size,
        };
 
+       if (!legacy_clone_args_valid(&args))
+               return -EINVAL;
+
        return _do_fork(&args);
 }
 #endif
@@ -2504,8 +2518,7 @@ SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
                .tls            = tls,
        };
 
-       /* clone(CLONE_PIDFD) uses parent_tidptr to return a pidfd */
-       if ((clone_flags & CLONE_PIDFD) && (clone_flags & CLONE_PARENT_SETTID))
+       if (!legacy_clone_args_valid(&args))
                return -EINVAL;
 
        return _do_fork(&args);
index 9f5433a..9873fc6 100644 (file)
@@ -2276,6 +2276,7 @@ static int __init init_kprobes(void)
                init_test_probes();
        return err;
 }
+subsys_initcall(init_kprobes);
 
 #ifdef CONFIG_DEBUG_FS
 static void report_probe(struct seq_file *pi, struct kprobe *p,
@@ -2588,5 +2589,3 @@ static int __init debugfs_kprobe_init(void)
 
 late_initcall(debugfs_kprobe_init);
 #endif /* CONFIG_DEBUG_FS */
-
-module_init(init_kprobes);
index 0c601ae..edd1c08 100644 (file)
@@ -16,7 +16,7 @@
  *    by Steven Rostedt, based on work by Gregory Haskins, Peter Morreale
  *    and Sven Dietrich.
  *
- * Also see Documentation/locking/mutex-design.txt.
+ * Also see Documentation/locking/mutex-design.rst.
  */
 #include <linux/mutex.h>
 #include <linux/ww_mutex.h>
index 38fbf9f..fa83d36 100644 (file)
@@ -9,7 +9,7 @@
  *  Copyright (C) 2005 Kihon Technologies Inc., Steven Rostedt
  *  Copyright (C) 2006 Esben Nielsen
  *
- *  See Documentation/locking/rt-mutex-design.txt for details.
+ *  See Documentation/locking/rt-mutex-design.rst for details.
  */
 #include <linux/spinlock.h>
 #include <linux/export.h>
index bea6f88..6ee03a8 100644 (file)
@@ -54,7 +54,7 @@ static void pgmap_array_delete(struct resource *res)
 
 static unsigned long pfn_first(struct dev_pagemap *pgmap)
 {
-       return (pgmap->res.start >> PAGE_SHIFT) +
+       return PHYS_PFN(pgmap->res.start) +
                vmem_altmap_offset(pgmap_altmap(pgmap));
 }
 
@@ -98,7 +98,6 @@ static void devm_memremap_pages_release(void *data)
        struct dev_pagemap *pgmap = data;
        struct device *dev = pgmap->dev;
        struct resource *res = &pgmap->res;
-       resource_size_t align_start, align_size;
        unsigned long pfn;
        int nid;
 
@@ -108,25 +107,21 @@ static void devm_memremap_pages_release(void *data)
        dev_pagemap_cleanup(pgmap);
 
        /* pages are dead and unused, undo the arch mapping */
-       align_start = res->start & ~(SECTION_SIZE - 1);
-       align_size = ALIGN(res->start + resource_size(res), SECTION_SIZE)
-               - align_start;
-
-       nid = page_to_nid(pfn_to_page(align_start >> PAGE_SHIFT));
+       nid = page_to_nid(pfn_to_page(PHYS_PFN(res->start)));
 
        mem_hotplug_begin();
        if (pgmap->type == MEMORY_DEVICE_PRIVATE) {
-               pfn = align_start >> PAGE_SHIFT;
+               pfn = PHYS_PFN(res->start);
                __remove_pages(page_zone(pfn_to_page(pfn)), pfn,
-                               align_size >> PAGE_SHIFT, NULL);
+                                PHYS_PFN(resource_size(res)), NULL);
        } else {
-               arch_remove_memory(nid, align_start, align_size,
+               arch_remove_memory(nid, res->start, resource_size(res),
                                pgmap_altmap(pgmap));
-               kasan_remove_zero_shadow(__va(align_start), align_size);
+               kasan_remove_zero_shadow(__va(res->start), resource_size(res));
        }
        mem_hotplug_done();
 
-       untrack_pfn(NULL, PHYS_PFN(align_start), align_size);
+       untrack_pfn(NULL, PHYS_PFN(res->start), resource_size(res));
        pgmap_array_delete(res);
        dev_WARN_ONCE(dev, pgmap->altmap.alloc,
                      "%s: failed to free all reserved pages\n", __func__);
@@ -162,13 +157,12 @@ static void dev_pagemap_percpu_release(struct percpu_ref *ref)
  */
 void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap)
 {
-       resource_size_t align_start, align_size, align_end;
        struct resource *res = &pgmap->res;
        struct dev_pagemap *conflict_pgmap;
        struct mhp_restrictions restrictions = {
                /*
                 * We do not want any optional features only our own memmap
-               */
+                */
                .altmap = pgmap_altmap(pgmap),
        };
        pgprot_t pgprot = PAGE_KERNEL;
@@ -225,12 +219,7 @@ void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap)
                        return ERR_PTR(error);
        }
 
-       align_start = res->start & ~(SECTION_SIZE - 1);
-       align_size = ALIGN(res->start + resource_size(res), SECTION_SIZE)
-               - align_start;
-       align_end = align_start + align_size - 1;
-
-       conflict_pgmap = get_dev_pagemap(PHYS_PFN(align_start), NULL);
+       conflict_pgmap = get_dev_pagemap(PHYS_PFN(res->start), NULL);
        if (conflict_pgmap) {
                dev_WARN(dev, "Conflicting mapping in same section\n");
                put_dev_pagemap(conflict_pgmap);
@@ -238,7 +227,7 @@ void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap)
                goto err_array;
        }
 
-       conflict_pgmap = get_dev_pagemap(PHYS_PFN(align_end), NULL);
+       conflict_pgmap = get_dev_pagemap(PHYS_PFN(res->end), NULL);
        if (conflict_pgmap) {
                dev_WARN(dev, "Conflicting mapping in same section\n");
                put_dev_pagemap(conflict_pgmap);
@@ -246,7 +235,7 @@ void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap)
                goto err_array;
        }
 
-       is_ram = region_intersects(align_start, align_size,
+       is_ram = region_intersects(res->start, resource_size(res),
                IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE);
 
        if (is_ram != REGION_DISJOINT) {
@@ -267,8 +256,8 @@ void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap)
        if (nid < 0)
                nid = numa_mem_id();
 
-       error = track_pfn_remap(NULL, &pgprot, PHYS_PFN(align_start), 0,
-                       align_size);
+       error = track_pfn_remap(NULL, &pgprot, PHYS_PFN(res->start), 0,
+                       resource_size(res));
        if (error)
                goto err_pfn_remap;
 
@@ -286,16 +275,16 @@ void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap)
         * arch_add_memory().
         */
        if (pgmap->type == MEMORY_DEVICE_PRIVATE) {
-               error = add_pages(nid, align_start >> PAGE_SHIFT,
-                               align_size >> PAGE_SHIFT, &restrictions);
+               error = add_pages(nid, PHYS_PFN(res->start),
+                               PHYS_PFN(resource_size(res)), &restrictions);
        } else {
-               error = kasan_add_zero_shadow(__va(align_start), align_size);
+               error = kasan_add_zero_shadow(__va(res->start), resource_size(res));
                if (error) {
                        mem_hotplug_done();
                        goto err_kasan;
                }
 
-               error = arch_add_memory(nid, align_start, align_size,
+               error = arch_add_memory(nid, res->start, resource_size(res),
                                        &restrictions);
        }
 
@@ -303,8 +292,8 @@ void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap)
                struct zone *zone;
 
                zone = &NODE_DATA(nid)->node_zones[ZONE_DEVICE];
-               move_pfn_range_to_zone(zone, align_start >> PAGE_SHIFT,
-                               align_size >> PAGE_SHIFT, pgmap_altmap(pgmap));
+               move_pfn_range_to_zone(zone, PHYS_PFN(res->start),
+                               PHYS_PFN(resource_size(res)), restrictions.altmap);
        }
 
        mem_hotplug_done();
@@ -316,8 +305,8 @@ void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap)
         * to allow us to do the work while not holding the hotplug lock.
         */
        memmap_init_zone_device(&NODE_DATA(nid)->node_zones[ZONE_DEVICE],
-                               align_start >> PAGE_SHIFT,
-                               align_size >> PAGE_SHIFT, pgmap);
+                               PHYS_PFN(res->start),
+                               PHYS_PFN(resource_size(res)), pgmap);
        percpu_ref_get_many(pgmap->ref, pfn_end(pgmap) - pfn_first(pgmap));
 
        error = devm_add_action_or_reset(dev, devm_memremap_pages_release,
@@ -328,9 +317,9 @@ void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap)
        return __va(res->start);
 
  err_add_memory:
-       kasan_remove_zero_shadow(__va(align_start), align_size);
+       kasan_remove_zero_shadow(__va(res->start), resource_size(res));
  err_kasan:
-       untrack_pfn(NULL, PHYS_PFN(align_start), align_size);
+       untrack_pfn(NULL, PHYS_PFN(res->start), resource_size(res));
  err_pfn_remap:
        pgmap_array_delete(res);
  err_array:
index a2cee14..5933395 100644 (file)
@@ -1492,8 +1492,7 @@ static void add_sect_attrs(struct module *mod, const struct load_info *info)
        for (i = 0; i < info->hdr->e_shnum; i++)
                if (!sect_empty(&info->sechdrs[i]))
                        nloaded++;
-       size[0] = ALIGN(sizeof(*sect_attrs)
-                       + nloaded * sizeof(sect_attrs->attrs[0]),
+       size[0] = ALIGN(struct_size(sect_attrs, attrs, nloaded),
                        sizeof(sect_attrs->grp.attrs[0]));
        size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.attrs[0]);
        sect_attrs = kzalloc(size[0] + size[1], GFP_KERNEL);
@@ -1697,6 +1696,8 @@ static int add_usage_links(struct module *mod)
        return ret;
 }
 
+static void module_remove_modinfo_attrs(struct module *mod, int end);
+
 static int module_add_modinfo_attrs(struct module *mod)
 {
        struct module_attribute *attr;
@@ -1711,24 +1712,34 @@ static int module_add_modinfo_attrs(struct module *mod)
                return -ENOMEM;
 
        temp_attr = mod->modinfo_attrs;
-       for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) {
+       for (i = 0; (attr = modinfo_attrs[i]); i++) {
                if (!attr->test || attr->test(mod)) {
                        memcpy(temp_attr, attr, sizeof(*temp_attr));
                        sysfs_attr_init(&temp_attr->attr);
                        error = sysfs_create_file(&mod->mkobj.kobj,
                                        &temp_attr->attr);
+                       if (error)
+                               goto error_out;
                        ++temp_attr;
                }
        }
+
+       return 0;
+
+error_out:
+       if (i > 0)
+               module_remove_modinfo_attrs(mod, --i);
        return error;
 }
 
-static void module_remove_modinfo_attrs(struct module *mod)
+static void module_remove_modinfo_attrs(struct module *mod, int end)
 {
        struct module_attribute *attr;
        int i;
 
        for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) {
+               if (end >= 0 && i > end)
+                       break;
                /* pick a field to test for end of list */
                if (!attr->attr.name)
                        break;
@@ -1816,7 +1827,7 @@ static int mod_sysfs_setup(struct module *mod,
        return 0;
 
 out_unreg_modinfo_attrs:
-       module_remove_modinfo_attrs(mod);
+       module_remove_modinfo_attrs(mod, -1);
 out_unreg_param:
        module_param_sysfs_remove(mod);
 out_unreg_holders:
@@ -1852,7 +1863,7 @@ static void mod_sysfs_fini(struct module *mod)
 {
 }
 
-static void module_remove_modinfo_attrs(struct module *mod)
+static void module_remove_modinfo_attrs(struct module *mod, int end)
 {
 }
 
@@ -1868,14 +1879,14 @@ static void init_param_lock(struct module *mod)
 static void mod_sysfs_teardown(struct module *mod)
 {
        del_usage_links(mod);
-       module_remove_modinfo_attrs(mod);
+       module_remove_modinfo_attrs(mod, -1);
        module_param_sysfs_remove(mod);
        kobject_put(mod->mkobj.drivers_dir);
        kobject_put(mod->holders_dir);
        mod_sysfs_fini(mod);
 }
 
-#ifdef CONFIG_STRICT_MODULE_RWX
+#ifdef CONFIG_ARCH_HAS_STRICT_MODULE_RWX
 /*
  * LKM RO/NX protection: protect module's text/ro-data
  * from modification and any data from execution.
@@ -1898,6 +1909,7 @@ static void frob_text(const struct module_layout *layout,
                   layout->text_size >> PAGE_SHIFT);
 }
 
+#ifdef CONFIG_STRICT_MODULE_RWX
 static void frob_rodata(const struct module_layout *layout,
                        int (*set_memory)(unsigned long start, int num_pages))
 {
@@ -1949,13 +1961,9 @@ void module_enable_ro(const struct module *mod, bool after_init)
        set_vm_flush_reset_perms(mod->core_layout.base);
        set_vm_flush_reset_perms(mod->init_layout.base);
        frob_text(&mod->core_layout, set_memory_ro);
-       frob_text(&mod->core_layout, set_memory_x);
 
        frob_rodata(&mod->core_layout, set_memory_ro);
-
        frob_text(&mod->init_layout, set_memory_ro);
-       frob_text(&mod->init_layout, set_memory_x);
-
        frob_rodata(&mod->init_layout, set_memory_ro);
 
        if (after_init)
@@ -2014,9 +2022,19 @@ void set_all_modules_text_ro(void)
        }
        mutex_unlock(&module_mutex);
 }
-#else
+#else /* !CONFIG_STRICT_MODULE_RWX */
 static void module_enable_nx(const struct module *mod) { }
-#endif
+#endif /*  CONFIG_STRICT_MODULE_RWX */
+static void module_enable_x(const struct module *mod)
+{
+       frob_text(&mod->core_layout, set_memory_x);
+       frob_text(&mod->init_layout, set_memory_x);
+}
+#else /* !CONFIG_ARCH_HAS_STRICT_MODULE_RWX */
+static void module_enable_nx(const struct module *mod) { }
+static void module_enable_x(const struct module *mod) { }
+#endif /* CONFIG_ARCH_HAS_STRICT_MODULE_RWX */
+
 
 #ifdef CONFIG_LIVEPATCH
 /*
@@ -2723,6 +2741,11 @@ void * __weak module_alloc(unsigned long size)
        return vmalloc_exec(size);
 }
 
+bool __weak module_exit_section(const char *name)
+{
+       return strstarts(name, ".exit");
+}
+
 #ifdef CONFIG_DEBUG_KMEMLEAK
 static void kmemleak_load_module(const struct module *mod,
                                 const struct load_info *info)
@@ -2912,7 +2935,7 @@ static int rewrite_section_headers(struct load_info *info, int flags)
 
 #ifndef CONFIG_MODULE_UNLOAD
                /* Don't load .exit sections */
-               if (strstarts(info->secstrings+shdr->sh_name, ".exit"))
+               if (module_exit_section(info->secstrings+shdr->sh_name))
                        shdr->sh_flags &= ~(unsigned long)SHF_ALLOC;
 #endif
        }
@@ -3390,8 +3413,7 @@ static bool finished_loading(const char *name)
        sched_annotate_sleep();
        mutex_lock(&module_mutex);
        mod = find_module_all(name, strlen(name), true);
-       ret = !mod || mod->state == MODULE_STATE_LIVE
-               || mod->state == MODULE_STATE_GOING;
+       ret = !mod || mod->state == MODULE_STATE_LIVE;
        mutex_unlock(&module_mutex);
 
        return ret;
@@ -3581,8 +3603,7 @@ again:
        mutex_lock(&module_mutex);
        old = find_module_all(mod->name, strlen(mod->name), true);
        if (old != NULL) {
-               if (old->state == MODULE_STATE_COMING
-                   || old->state == MODULE_STATE_UNFORMED) {
+               if (old->state != MODULE_STATE_LIVE) {
                        /* Wait in case it fails to load. */
                        mutex_unlock(&module_mutex);
                        err = wait_event_interruptible(module_wq,
@@ -3621,6 +3642,7 @@ static int complete_formation(struct module *mod, struct load_info *info)
 
        module_enable_ro(mod, false);
        module_enable_nx(mod);
+       module_enable_x(mod);
 
        /* Mark state as coming so strong_try_module_get() ignores us,
         * but kallsyms etc. can see us. */
index 2d2fddb..15a8ad6 100644 (file)
@@ -267,7 +267,12 @@ static void padata_reorder(struct parallel_data *pd)
         * The next object that needs serialization might have arrived to
         * the reorder queues in the meantime, we will be called again
         * from the timer function if no one else cares for it.
+        *
+        * Ensure reorder_objects is read after pd->lock is dropped so we see
+        * an increment from another task in padata_do_serial.  Pairs with
+        * smp_mb__after_atomic in padata_do_serial.
         */
+       smp_mb();
        if (atomic_read(&pd->reorder_objects)
                        && !(pinst->flags & PADATA_RESET))
                mod_timer(&pd->timer, jiffies + HZ);
@@ -387,6 +392,13 @@ void padata_do_serial(struct padata_priv *padata)
        list_add_tail(&padata->list, &pqueue->reorder.list);
        spin_unlock(&pqueue->reorder.lock);
 
+       /*
+        * Ensure the atomic_inc of reorder_objects above is ordered correctly
+        * with the trylock of pd->lock in padata_reorder.  Pairs with smp_mb
+        * in padata_reorder.
+        */
+       smp_mb__after_atomic();
+
        put_cpu();
 
        /* If we're running on the wrong CPU, call padata_reorder() via a
index 4d9f55b..057540b 100644 (file)
@@ -372,7 +372,7 @@ const struct taint_flag taint_flags[TAINT_FLAGS_COUNT] = {
 /**
  * print_tainted - return a string to represent the kernel taint state.
  *
- * For individual taint flag meanings, see Documentation/sysctl/kernel.txt
+ * For individual taint flag meanings, see Documentation/admin-guide/sysctl/kernel.rst
  *
  * The string is overwritten by the next call to print_tainted(),
  * but is always NULL terminated.
index 16263b5..0a9f2e4 100644 (file)
 #include <linux/init_task.h>
 #include <linux/syscalls.h>
 #include <linux/proc_ns.h>
-#include <linux/proc_fs.h>
+#include <linux/refcount.h>
 #include <linux/anon_inodes.h>
 #include <linux/sched/signal.h>
 #include <linux/sched/task.h>
 #include <linux/idr.h>
 
 struct pid init_struct_pid = {
-       .count          = ATOMIC_INIT(1),
+       .count          = REFCOUNT_INIT(1),
        .tasks          = {
                { .first = NULL },
                { .first = NULL },
@@ -108,8 +108,7 @@ void put_pid(struct pid *pid)
                return;
 
        ns = pid->numbers[pid->level].ns;
-       if ((atomic_read(&pid->count) == 1) ||
-            atomic_dec_and_test(&pid->count)) {
+       if (refcount_dec_and_test(&pid->count)) {
                kmem_cache_free(ns->pid_cachep, pid);
                put_pid_ns(ns);
        }
@@ -212,7 +211,7 @@ struct pid *alloc_pid(struct pid_namespace *ns)
        }
 
        get_pid_ns(ns);
-       atomic_set(&pid->count, 1);
+       refcount_set(&pid->count, 1);
        for (type = 0; type < PIDTYPE_MAX; ++type)
                INIT_HLIST_HEAD(&pid->tasks[type]);
 
index 6d726ce..a6a79f8 100644 (file)
@@ -291,14 +291,13 @@ static int pid_ns_ctl_handler(struct ctl_table *table, int write,
 }
 
 extern int pid_max;
-static int zero = 0;
 static struct ctl_table pid_ns_ctl_table[] = {
        {
                .procname = "ns_last_pid",
                .maxlen = sizeof(int),
                .mode = 0666, /* permissions are checked in the handler */
                .proc_handler = pid_ns_ctl_handler,
-               .extra1 = &zero,
+               .extra1 = SYSCTL_ZERO,
                .extra2 = &pid_max,
        },
        { }
index 83a531c..cb9ddcc 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/compat.h>
 #include <linux/sched/signal.h>
 
+#include <asm/syscall.h>       /* for syscall_get_* */
+
 /*
  * Access another process' address space via ptrace.
  * Source/target buffer must be kernel space,
@@ -897,7 +899,100 @@ static int ptrace_regset(struct task_struct *task, int req, unsigned int type,
  * to ensure no machine forgets it.
  */
 EXPORT_SYMBOL_GPL(task_user_regset_view);
-#endif
+
+static unsigned long
+ptrace_get_syscall_info_entry(struct task_struct *child, struct pt_regs *regs,
+                             struct ptrace_syscall_info *info)
+{
+       unsigned long args[ARRAY_SIZE(info->entry.args)];
+       int i;
+
+       info->op = PTRACE_SYSCALL_INFO_ENTRY;
+       info->entry.nr = syscall_get_nr(child, regs);
+       syscall_get_arguments(child, regs, args);
+       for (i = 0; i < ARRAY_SIZE(args); i++)
+               info->entry.args[i] = args[i];
+
+       /* args is the last field in struct ptrace_syscall_info.entry */
+       return offsetofend(struct ptrace_syscall_info, entry.args);
+}
+
+static unsigned long
+ptrace_get_syscall_info_seccomp(struct task_struct *child, struct pt_regs *regs,
+                               struct ptrace_syscall_info *info)
+{
+       /*
+        * As struct ptrace_syscall_info.entry is currently a subset
+        * of struct ptrace_syscall_info.seccomp, it makes sense to
+        * initialize that subset using ptrace_get_syscall_info_entry().
+        * This can be reconsidered in the future if these structures
+        * diverge significantly enough.
+        */
+       ptrace_get_syscall_info_entry(child, regs, info);
+       info->op = PTRACE_SYSCALL_INFO_SECCOMP;
+       info->seccomp.ret_data = child->ptrace_message;
+
+       /* ret_data is the last field in struct ptrace_syscall_info.seccomp */
+       return offsetofend(struct ptrace_syscall_info, seccomp.ret_data);
+}
+
+static unsigned long
+ptrace_get_syscall_info_exit(struct task_struct *child, struct pt_regs *regs,
+                            struct ptrace_syscall_info *info)
+{
+       info->op = PTRACE_SYSCALL_INFO_EXIT;
+       info->exit.rval = syscall_get_error(child, regs);
+       info->exit.is_error = !!info->exit.rval;
+       if (!info->exit.is_error)
+               info->exit.rval = syscall_get_return_value(child, regs);
+
+       /* is_error is the last field in struct ptrace_syscall_info.exit */
+       return offsetofend(struct ptrace_syscall_info, exit.is_error);
+}
+
+static int
+ptrace_get_syscall_info(struct task_struct *child, unsigned long user_size,
+                       void __user *datavp)
+{
+       struct pt_regs *regs = task_pt_regs(child);
+       struct ptrace_syscall_info info = {
+               .op = PTRACE_SYSCALL_INFO_NONE,
+               .arch = syscall_get_arch(child),
+               .instruction_pointer = instruction_pointer(regs),
+               .stack_pointer = user_stack_pointer(regs),
+       };
+       unsigned long actual_size = offsetof(struct ptrace_syscall_info, entry);
+       unsigned long write_size;
+
+       /*
+        * This does not need lock_task_sighand() to access
+        * child->last_siginfo because ptrace_freeze_traced()
+        * called earlier by ptrace_check_attach() ensures that
+        * the tracee cannot go away and clear its last_siginfo.
+        */
+       switch (child->last_siginfo ? child->last_siginfo->si_code : 0) {
+       case SIGTRAP | 0x80:
+               switch (child->ptrace_message) {
+               case PTRACE_EVENTMSG_SYSCALL_ENTRY:
+                       actual_size = ptrace_get_syscall_info_entry(child, regs,
+                                                                   &info);
+                       break;
+               case PTRACE_EVENTMSG_SYSCALL_EXIT:
+                       actual_size = ptrace_get_syscall_info_exit(child, regs,
+                                                                  &info);
+                       break;
+               }
+               break;
+       case SIGTRAP | (PTRACE_EVENT_SECCOMP << 8):
+               actual_size = ptrace_get_syscall_info_seccomp(child, regs,
+                                                             &info);
+               break;
+       }
+
+       write_size = min(actual_size, user_size);
+       return copy_to_user(datavp, &info, write_size) ? -EFAULT : actual_size;
+}
+#endif /* CONFIG_HAVE_ARCH_TRACEHOOK */
 
 int ptrace_request(struct task_struct *child, long request,
                   unsigned long addr, unsigned long data)
@@ -1114,6 +1209,10 @@ int ptrace_request(struct task_struct *child, long request,
                        ret = __put_user(kiov.iov_len, &uiov->iov_len);
                break;
        }
+
+       case PTRACE_GET_SYSCALL_INFO:
+               ret = ptrace_get_syscall_info(child, addr, datavp);
+               break;
 #endif
 
        case PTRACE_SECCOMP_GET_FILTER:
index d22423e..7ea4306 100644 (file)
@@ -326,7 +326,7 @@ EXPORT_SYMBOL(release_resource);
  *
  * If a resource is found, returns 0 and @*res is overwritten with the part
  * of the resource that's within [@start..@end]; if none is found, returns
- * -1 or -EINVAL for other invalid parameters.
+ * -ENODEV.  Returns -EINVAL for invalid parameters.
  *
  * This function walks the whole tree and not just first level children
  * unless @first_lvl is true.
@@ -342,6 +342,7 @@ static int find_next_iomem_res(resource_size_t start, resource_size_t end,
                               unsigned long flags, unsigned long desc,
                               bool first_lvl, struct resource *res)
 {
+       bool siblings_only = true;
        struct resource *p;
 
        if (!res)
@@ -352,29 +353,43 @@ static int find_next_iomem_res(resource_size_t start, resource_size_t end,
 
        read_lock(&resource_lock);
 
-       for (p = iomem_resource.child; p; p = next_resource(p, first_lvl)) {
-               if ((p->flags & flags) != flags)
-                       continue;
-               if ((desc != IORES_DESC_NONE) && (desc != p->desc))
-                       continue;
+       for (p = iomem_resource.child; p; p = next_resource(p, siblings_only)) {
+               /* If we passed the resource we are looking for, stop */
                if (p->start > end) {
                        p = NULL;
                        break;
                }
-               if ((p->end >= start) && (p->start <= end))
-                       break;
+
+               /* Skip until we find a range that matches what we look for */
+               if (p->end < start)
+                       continue;
+
+               /*
+                * Now that we found a range that matches what we look for,
+                * check the flags and the descriptor. If we were not asked to
+                * use only the first level, start looking at children as well.
+                */
+               siblings_only = first_lvl;
+
+               if ((p->flags & flags) != flags)
+                       continue;
+               if ((desc != IORES_DESC_NONE) && (desc != p->desc))
+                       continue;
+
+               /* Found a match, break */
+               break;
+       }
+
+       if (p) {
+               /* copy data */
+               res->start = max(start, p->start);
+               res->end = min(end, p->end);
+               res->flags = p->flags;
+               res->desc = p->desc;
        }
 
        read_unlock(&resource_lock);
-       if (!p)
-               return -1;
-
-       /* copy data */
-       res->start = max(start, p->start);
-       res->end = min(end, p->end);
-       res->flags = p->flags;
-       res->desc = p->desc;
-       return 0;
+       return p ? 0 : -ENODEV;
 }
 
 static int __walk_iomem_res_desc(resource_size_t start, resource_size_t end,
index 123ea07..ccb2808 100644 (file)
@@ -14,6 +14,12 @@ EXPORT_SYMBOL_GPL(housekeeping_overridden);
 static cpumask_var_t housekeeping_mask;
 static unsigned int housekeeping_flags;
 
+bool housekeeping_enabled(enum hk_flags flags)
+{
+       return !!(housekeeping_flags & flags);
+}
+EXPORT_SYMBOL_GPL(housekeeping_enabled);
+
 int housekeeping_any_cpu(enum hk_flags flags)
 {
        if (static_branch_unlikely(&housekeeping_overridden))
index dabe100..91b789d 100644 (file)
@@ -2951,80 +2951,49 @@ EXPORT_SYMBOL(sigprocmask);
  *
  * This is useful for syscalls such as ppoll, pselect, io_pgetevents and
  * epoll_pwait where a new sigmask is passed from userland for the syscalls.
+ *
+ * Note that it does set_restore_sigmask() in advance, so it must be always
+ * paired with restore_saved_sigmask_unless() before return from syscall.
  */
-int set_user_sigmask(const sigset_t __user *usigmask, sigset_t *set,
-                    sigset_t *oldset, size_t sigsetsize)
+int set_user_sigmask(const sigset_t __user *umask, size_t sigsetsize)
 {
-       if (!usigmask)
-               return 0;
+       sigset_t kmask;
 
+       if (!umask)
+               return 0;
        if (sigsetsize != sizeof(sigset_t))
                return -EINVAL;
-       if (copy_from_user(set, usigmask, sizeof(sigset_t)))
+       if (copy_from_user(&kmask, umask, sizeof(sigset_t)))
                return -EFAULT;
 
-       *oldset = current->blocked;
-       set_current_blocked(set);
+       set_restore_sigmask();
+       current->saved_sigmask = current->blocked;
+       set_current_blocked(&kmask);
 
        return 0;
 }
-EXPORT_SYMBOL(set_user_sigmask);
 
 #ifdef CONFIG_COMPAT
-int set_compat_user_sigmask(const compat_sigset_t __user *usigmask,
-                           sigset_t *set, sigset_t *oldset,
+int set_compat_user_sigmask(const compat_sigset_t __user *umask,
                            size_t sigsetsize)
 {
-       if (!usigmask)
-               return 0;
+       sigset_t kmask;
 
+       if (!umask)
+               return 0;
        if (sigsetsize != sizeof(compat_sigset_t))
                return -EINVAL;
-       if (get_compat_sigset(set, usigmask))
+       if (get_compat_sigset(&kmask, umask))
                return -EFAULT;
 
-       *oldset = current->blocked;
-       set_current_blocked(set);
+       set_restore_sigmask();
+       current->saved_sigmask = current->blocked;
+       set_current_blocked(&kmask);
 
        return 0;
 }
-EXPORT_SYMBOL(set_compat_user_sigmask);
 #endif
 
-/*
- * restore_user_sigmask:
- * usigmask: sigmask passed in from userland.
- * sigsaved: saved sigmask when the syscall started and changed the sigmask to
- *           usigmask.
- *
- * This is useful for syscalls such as ppoll, pselect, io_pgetevents and
- * epoll_pwait where a new sigmask is passed in from userland for the syscalls.
- */
-void restore_user_sigmask(const void __user *usigmask, sigset_t *sigsaved,
-                               bool interrupted)
-{
-
-       if (!usigmask)
-               return;
-       /*
-        * When signals are pending, do not restore them here.
-        * Restoring sigmask here can lead to delivering signals that the above
-        * syscalls are intended to block because of the sigmask passed in.
-        */
-       if (interrupted) {
-               current->saved_sigmask = *sigsaved;
-               set_restore_sigmask();
-               return;
-       }
-
-       /*
-        * This is needed because the fast syscall return path does not restore
-        * saved_sigmask when signals are not pending.
-        */
-       set_current_blocked(sigsaved);
-}
-EXPORT_SYMBOL(restore_user_sigmask);
-
 /**
  *  sys_rt_sigprocmask - change the list of currently blocked signals
  *  @how: whether to add, remove, or set signals
index 616d4d1..7dbcb40 100644 (file)
@@ -291,6 +291,14 @@ int smp_call_function_single(int cpu, smp_call_func_t func, void *info,
        WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled()
                     && !oops_in_progress);
 
+       /*
+        * When @wait we can deadlock when we interrupt between llist_add() and
+        * arch_send_call_function_ipi*(); when !@wait we can deadlock due to
+        * csd_lock() on because the interrupt context uses the same csd
+        * storage.
+        */
+       WARN_ON_ONCE(!in_task());
+
        csd = &csd_stack;
        if (!wait) {
                csd = this_cpu_ptr(&csd_data);
@@ -416,6 +424,14 @@ void smp_call_function_many(const struct cpumask *mask,
        WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled()
                     && !oops_in_progress && !early_boot_irqs_disabled);
 
+       /*
+        * When @wait we can deadlock when we interrupt between llist_add() and
+        * arch_send_call_function_ipi*(); when !@wait we can deadlock due to
+        * csd_lock() on because the interrupt context uses the same csd
+        * storage.
+        */
+       WARN_ON_ONCE(!in_task());
+
        /* Try to fastpath.  So, what's a CPU they want? Ignoring this one. */
        cpu = cpumask_first_and(mask, cpu_online_mask);
        if (cpu == this_cpu)
index e6a02b2..f5440ab 100644 (file)
@@ -226,12 +226,17 @@ unsigned int stack_trace_save_user(unsigned long *store, unsigned int size)
                .store  = store,
                .size   = size,
        };
+       mm_segment_t fs;
 
        /* Trace user stack if not a kernel thread */
        if (current->flags & PF_KTHREAD)
                return 0;
 
+       fs = get_fs();
+       set_fs(USER_DS);
        arch_stack_walk_user(consume_entry, &c, task_pt_regs(current));
+       set_fs(fs);
+
        return c.len;
 }
 #endif
index 1c1ad1e..078950d 100644 (file)
@@ -125,9 +125,6 @@ static int sixty = 60;
 #endif
 
 static int __maybe_unused neg_one = -1;
-
-static int zero;
-static int __maybe_unused one = 1;
 static int __maybe_unused two = 2;
 static int __maybe_unused four = 4;
 static unsigned long zero_ul;
@@ -188,17 +185,17 @@ extern int no_unaligned_warning;
  * enum sysctl_writes_mode - supported sysctl write modes
  *
  * @SYSCTL_WRITES_LEGACY: each write syscall must fully contain the sysctl value
- *     to be written, and multiple writes on the same sysctl file descriptor
- *     will rewrite the sysctl value, regardless of file position. No warning
- *     is issued when the initial position is not 0.
+ *     to be written, and multiple writes on the same sysctl file descriptor
+ *     will rewrite the sysctl value, regardless of file position. No warning
+ *     is issued when the initial position is not 0.
  * @SYSCTL_WRITES_WARN: same as above but warn when the initial file position is
- *     not 0.
+ *     not 0.
  * @SYSCTL_WRITES_STRICT: writes to numeric sysctl entries must always be at
- *     file position 0 and the value must be fully contained in the buffer
- *     sent to the write syscall. If dealing with strings respect the file
- *     position, but restrict this to the max length of the buffer, anything
- *     passed the max lenght will be ignored. Multiple writes will append
- *     to the buffer.
+ *     file position 0 and the value must be fully contained in the buffer
+ *     sent to the write syscall. If dealing with strings respect the file
+ *     position, but restrict this to the max length of the buffer, anything
+ *     passed the max length will be ignored. Multiple writes will append
+ *     to the buffer.
  *
  * These write modes control how current file position affects the behavior of
  * updating sysctl values through the proc interface on each write.
@@ -385,8 +382,8 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = sysctl_schedstats,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
 #endif /* CONFIG_SCHEDSTATS */
 #endif /* CONFIG_SMP */
@@ -418,7 +415,7 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = SYSCTL_ONE,
        },
        {
                .procname       = "numa_balancing",
@@ -426,8 +423,8 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = sysctl_numa_balancing,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
 #endif /* CONFIG_NUMA_BALANCING */
 #endif /* CONFIG_SCHED_DEBUG */
@@ -475,8 +472,8 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
 #endif
 #ifdef CONFIG_CFS_BANDWIDTH
@@ -486,7 +483,7 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = SYSCTL_ONE,
        },
 #endif
 #if defined(CONFIG_ENERGY_MODEL) && defined(CONFIG_CPU_FREQ_GOV_SCHEDUTIL)
@@ -496,8 +493,8 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = sched_energy_aware_handler,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
 #endif
 #ifdef CONFIG_PROVE_LOCKING
@@ -562,7 +559,7 @@ static struct ctl_table kern_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
                .extra1         = &neg_one,
-               .extra2         = &one,
+               .extra2         = SYSCTL_ONE,
        },
 #endif
 #ifdef CONFIG_LATENCYTOP
@@ -696,8 +693,8 @@ static struct ctl_table kern_table[] = {
                .mode           = 0644,
                /* only handle a transition from default "0" to "1" */
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ONE,
+               .extra2         = SYSCTL_ONE,
        },
 #endif
 #ifdef CONFIG_MODULES
@@ -715,8 +712,8 @@ static struct ctl_table kern_table[] = {
                .mode           = 0644,
                /* only handle a transition from default "0" to "1" */
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ONE,
+               .extra2         = SYSCTL_ONE,
        },
 #endif
 #ifdef CONFIG_UEVENT_HELPER
@@ -875,7 +872,7 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &ten_thousand,
        },
        {
@@ -891,8 +888,8 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax_sysadmin,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        {
                .procname       = "kptr_restrict",
@@ -900,7 +897,7 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax_sysadmin,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &two,
        },
 #endif
@@ -925,8 +922,8 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_watchdog,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        {
                .procname       = "watchdog_thresh",
@@ -934,7 +931,7 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_watchdog_thresh,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &sixty,
        },
        {
@@ -943,8 +940,8 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(int),
                .mode           = NMI_WATCHDOG_SYSCTL_PERM,
                .proc_handler   = proc_nmi_watchdog,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        {
                .procname       = "watchdog_cpumask",
@@ -960,8 +957,8 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_soft_watchdog,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        {
                .procname       = "softlockup_panic",
@@ -969,8 +966,8 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
 #ifdef CONFIG_SMP
        {
@@ -979,8 +976,8 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
 #endif /* CONFIG_SMP */
 #endif
@@ -991,8 +988,8 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
 #ifdef CONFIG_SMP
        {
@@ -1001,8 +998,8 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
 #endif /* CONFIG_SMP */
 #endif
@@ -1115,8 +1112,8 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        {
                .procname       = "hung_task_check_count",
@@ -1124,7 +1121,7 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
        {
                .procname       = "hung_task_timeout_secs",
@@ -1201,7 +1198,7 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(sysctl_perf_event_sample_rate),
                .mode           = 0644,
                .proc_handler   = perf_proc_update_handler,
-               .extra1         = &one,
+               .extra1         = SYSCTL_ONE,
        },
        {
                .procname       = "perf_cpu_time_max_percent",
@@ -1209,7 +1206,7 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(sysctl_perf_cpu_time_max_percent),
                .mode           = 0644,
                .proc_handler   = perf_cpu_time_max_percent_handler,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &one_hundred,
        },
        {
@@ -1218,7 +1215,7 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(sysctl_perf_event_max_stack),
                .mode           = 0644,
                .proc_handler   = perf_event_max_stack_handler,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &six_hundred_forty_kb,
        },
        {
@@ -1227,7 +1224,7 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(sysctl_perf_event_max_contexts_per_stack),
                .mode           = 0644,
                .proc_handler   = perf_event_max_stack_handler,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &one_thousand,
        },
 #endif
@@ -1237,8 +1234,8 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
 #if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON)
        {
@@ -1247,8 +1244,8 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = timer_migration_handler,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
 #endif
 #ifdef CONFIG_BPF_SYSCALL
@@ -1259,8 +1256,8 @@ static struct ctl_table kern_table[] = {
                .mode           = 0644,
                /* only handle a transition from default "0" to "1" */
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ONE,
+               .extra2         = SYSCTL_ONE,
        },
        {
                .procname       = "bpf_stats_enabled",
@@ -1277,8 +1274,8 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(sysctl_panic_on_rcu_stall),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
 #endif
 #ifdef CONFIG_STACKLEAK_RUNTIME_DISABLE
@@ -1288,8 +1285,8 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0600,
                .proc_handler   = stack_erasing_sysctl,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
 #endif
        { }
@@ -1302,7 +1299,7 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(sysctl_overcommit_memory),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &two,
        },
        {
@@ -1311,7 +1308,7 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(sysctl_panic_on_oom),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &two,
        },
        {
@@ -1348,7 +1345,7 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
        {
                .procname       = "dirty_background_ratio",
@@ -1356,7 +1353,7 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(dirty_background_ratio),
                .mode           = 0644,
                .proc_handler   = dirty_background_ratio_handler,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &one_hundred,
        },
        {
@@ -1373,7 +1370,7 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(vm_dirty_ratio),
                .mode           = 0644,
                .proc_handler   = dirty_ratio_handler,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &one_hundred,
        },
        {
@@ -1397,7 +1394,7 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(dirty_expire_interval),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
        {
                .procname       = "dirtytime_expire_seconds",
@@ -1405,7 +1402,7 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(dirtytime_expire_interval),
                .mode           = 0644,
                .proc_handler   = dirtytime_interval_handler,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
        {
                .procname       = "swappiness",
@@ -1413,7 +1410,7 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(vm_swappiness),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &one_hundred,
        },
 #ifdef CONFIG_HUGETLB_PAGE
@@ -1438,8 +1435,8 @@ static struct ctl_table vm_table[] = {
                .maxlen                 = sizeof(int),
                .mode                   = 0644,
                .proc_handler   = sysctl_vm_numa_stat_handler,
-               .extra1                 = &zero,
-               .extra2                 = &one,
+               .extra1                 = SYSCTL_ZERO,
+               .extra2                 = SYSCTL_ONE,
        },
 #endif
         {
@@ -1470,7 +1467,7 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = drop_caches_sysctl_handler,
-               .extra1         = &one,
+               .extra1         = SYSCTL_ONE,
                .extra2         = &four,
        },
 #ifdef CONFIG_COMPACTION
@@ -1496,8 +1493,8 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
 
 #endif /* CONFIG_COMPACTION */
@@ -1507,7 +1504,7 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(min_free_kbytes),
                .mode           = 0644,
                .proc_handler   = min_free_kbytes_sysctl_handler,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
        {
                .procname       = "watermark_boost_factor",
@@ -1515,7 +1512,7 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(watermark_boost_factor),
                .mode           = 0644,
                .proc_handler   = watermark_boost_factor_sysctl_handler,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
        {
                .procname       = "watermark_scale_factor",
@@ -1523,7 +1520,7 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(watermark_scale_factor),
                .mode           = 0644,
                .proc_handler   = watermark_scale_factor_sysctl_handler,
-               .extra1         = &one,
+               .extra1         = SYSCTL_ONE,
                .extra2         = &one_thousand,
        },
        {
@@ -1532,7 +1529,7 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(percpu_pagelist_fraction),
                .mode           = 0644,
                .proc_handler   = percpu_pagelist_fraction_sysctl_handler,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
 #ifdef CONFIG_MMU
        {
@@ -1541,7 +1538,7 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(sysctl_max_map_count),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
 #else
        {
@@ -1550,7 +1547,7 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(sysctl_nr_trim_pages),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
 #endif
        {
@@ -1566,7 +1563,7 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(block_dump),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
        {
                .procname       = "vfs_cache_pressure",
@@ -1574,7 +1571,7 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(sysctl_vfs_cache_pressure),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
 #ifdef HAVE_ARCH_PICK_MMAP_LAYOUT
        {
@@ -1583,7 +1580,7 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(sysctl_legacy_va_layout),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
 #endif
 #ifdef CONFIG_NUMA
@@ -1593,7 +1590,7 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(node_reclaim_mode),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
        {
                .procname       = "min_unmapped_ratio",
@@ -1601,7 +1598,7 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(sysctl_min_unmapped_ratio),
                .mode           = 0644,
                .proc_handler   = sysctl_min_unmapped_ratio_sysctl_handler,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &one_hundred,
        },
        {
@@ -1610,7 +1607,7 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(sysctl_min_slab_ratio),
                .mode           = 0644,
                .proc_handler   = sysctl_min_slab_ratio_sysctl_handler,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &one_hundred,
        },
 #endif
@@ -1661,7 +1658,7 @@ static struct ctl_table vm_table[] = {
 #endif
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
 #endif
 #ifdef CONFIG_HIGHMEM
@@ -1671,8 +1668,8 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(vm_highmem_is_dirtyable),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
 #endif
 #ifdef CONFIG_MEMORY_FAILURE
@@ -1682,8 +1679,8 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(sysctl_memory_failure_early_kill),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        {
                .procname       = "memory_failure_recovery",
@@ -1691,8 +1688,8 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(sysctl_memory_failure_recovery),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
 #endif
        {
@@ -1738,8 +1735,8 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(sysctl_unprivileged_userfaultfd),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
 #endif
        { }
@@ -1875,8 +1872,8 @@ static struct ctl_table fs_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0600,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        {
                .procname       = "protected_hardlinks",
@@ -1884,8 +1881,8 @@ static struct ctl_table fs_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0600,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        {
                .procname       = "protected_fifos",
@@ -1893,7 +1890,7 @@ static struct ctl_table fs_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0600,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &two,
        },
        {
@@ -1902,7 +1899,7 @@ static struct ctl_table fs_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0600,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &two,
        },
        {
@@ -1911,7 +1908,7 @@ static struct ctl_table fs_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax_coredump,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &two,
        },
 #if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE)
@@ -1948,7 +1945,7 @@ static struct ctl_table fs_table[] = {
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = SYSCTL_ONE,
        },
        { }
 };
@@ -1970,8 +1967,8 @@ static struct ctl_table debug_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_kprobes_optimization_handler,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
 #endif
        { }
@@ -3395,8 +3392,8 @@ int proc_do_static_key(struct ctl_table *table, int write,
                .data   = &val,
                .maxlen = sizeof(val),
                .mode   = table->mode,
-               .extra1 = &zero,
-               .extra2 = &one,
+               .extra1 = SYSCTL_ZERO,
+               .extra2 = SYSCTL_ONE,
        };
 
        if (write && !capable(CAP_SYS_ADMIN))
index 564e5fd..98da899 100644 (file)
@@ -597,9 +597,19 @@ config FTRACE_STARTUP_TEST
          functioning properly. It will do tests on all the configured
          tracers of ftrace.
 
+config EVENT_TRACE_STARTUP_TEST
+       bool "Run selftest on trace events"
+       depends on FTRACE_STARTUP_TEST
+       default y
+       help
+         This option performs a test on all trace events in the system.
+         It basically just enables each event and runs some code that
+         will trigger events (not necessarily the event it enables)
+         This may take some time run as there are a lot of events.
+
 config EVENT_TRACE_TEST_SYSCALLS
        bool "Run selftest on syscall events"
-       depends on FTRACE_STARTUP_TEST
+       depends on EVENT_TRACE_STARTUP_TEST
        help
         This option will also enable testing every syscall event.
         It only enables the event and disables it and runs various loads
index 576c416..eca3450 100644 (file)
@@ -1622,6 +1622,11 @@ static bool test_rec_ops_needs_regs(struct dyn_ftrace *rec)
        return  keep_regs;
 }
 
+static struct ftrace_ops *
+ftrace_find_tramp_ops_any(struct dyn_ftrace *rec);
+static struct ftrace_ops *
+ftrace_find_tramp_ops_next(struct dyn_ftrace *rec, struct ftrace_ops *ops);
+
 static bool __ftrace_hash_rec_update(struct ftrace_ops *ops,
                                     int filter_hash,
                                     bool inc)
@@ -1750,15 +1755,17 @@ static bool __ftrace_hash_rec_update(struct ftrace_ops *ops,
                        }
 
                        /*
-                        * If the rec had TRAMP enabled, then it needs to
-                        * be cleared. As TRAMP can only be enabled iff
-                        * there is only a single ops attached to it.
-                        * In otherwords, always disable it on decrementing.
-                        * In the future, we may set it if rec count is
-                        * decremented to one, and the ops that is left
-                        * has a trampoline.
+                        * The TRAMP needs to be set only if rec count
+                        * is decremented to one, and the ops that is
+                        * left has a trampoline. As TRAMP can only be
+                        * enabled if there is only a single ops attached
+                        * to it.
                         */
-                       rec->flags &= ~FTRACE_FL_TRAMP;
+                       if (ftrace_rec_count(rec) == 1 &&
+                           ftrace_find_tramp_ops_any(rec))
+                               rec->flags |= FTRACE_FL_TRAMP;
+                       else
+                               rec->flags &= ~FTRACE_FL_TRAMP;
 
                        /*
                         * flags will be cleared in ftrace_check_record()
@@ -1768,7 +1775,7 @@ static bool __ftrace_hash_rec_update(struct ftrace_ops *ops,
                count++;
 
                /* Must match FTRACE_UPDATE_CALLS in ftrace_modify_all_code() */
-               update |= ftrace_test_record(rec, 1) != FTRACE_UPDATE_IGNORE;
+               update |= ftrace_test_record(rec, true) != FTRACE_UPDATE_IGNORE;
 
                /* Shortcut, if we handled all records, we are done. */
                if (!all && count == hash->count)
@@ -1951,11 +1958,6 @@ static void print_ip_ins(const char *fmt, const unsigned char *p)
                printk(KERN_CONT "%s%02x", i ? ":" : "", p[i]);
 }
 
-static struct ftrace_ops *
-ftrace_find_tramp_ops_any(struct dyn_ftrace *rec);
-static struct ftrace_ops *
-ftrace_find_tramp_ops_next(struct dyn_ftrace *rec, struct ftrace_ops *ops);
-
 enum ftrace_bug_type ftrace_bug_type;
 const void *ftrace_expected;
 
@@ -2047,7 +2049,7 @@ void ftrace_bug(int failed, struct dyn_ftrace *rec)
        }
 }
 
-static int ftrace_check_record(struct dyn_ftrace *rec, int enable, int update)
+static int ftrace_check_record(struct dyn_ftrace *rec, bool enable, bool update)
 {
        unsigned long flag = 0UL;
 
@@ -2146,28 +2148,28 @@ static int ftrace_check_record(struct dyn_ftrace *rec, int enable, int update)
 /**
  * ftrace_update_record, set a record that now is tracing or not
  * @rec: the record to update
- * @enable: set to 1 if the record is tracing, zero to force disable
+ * @enable: set to true if the record is tracing, false to force disable
  *
  * The records that represent all functions that can be traced need
  * to be updated when tracing has been enabled.
  */
-int ftrace_update_record(struct dyn_ftrace *rec, int enable)
+int ftrace_update_record(struct dyn_ftrace *rec, bool enable)
 {
-       return ftrace_check_record(rec, enable, 1);
+       return ftrace_check_record(rec, enable, true);
 }
 
 /**
  * ftrace_test_record, check if the record has been enabled or not
  * @rec: the record to test
- * @enable: set to 1 to check if enabled, 0 if it is disabled
+ * @enable: set to true to check if enabled, false if it is disabled
  *
  * The arch code may need to test if a record is already set to
  * tracing to determine how to modify the function code that it
  * represents.
  */
-int ftrace_test_record(struct dyn_ftrace *rec, int enable)
+int ftrace_test_record(struct dyn_ftrace *rec, bool enable)
 {
-       return ftrace_check_record(rec, enable, 0);
+       return ftrace_check_record(rec, enable, false);
 }
 
 static struct ftrace_ops *
@@ -2356,7 +2358,7 @@ unsigned long ftrace_get_addr_curr(struct dyn_ftrace *rec)
 }
 
 static int
-__ftrace_replace_code(struct dyn_ftrace *rec, int enable)
+__ftrace_replace_code(struct dyn_ftrace *rec, bool enable)
 {
        unsigned long ftrace_old_addr;
        unsigned long ftrace_addr;
@@ -2395,7 +2397,7 @@ void __weak ftrace_replace_code(int mod_flags)
 {
        struct dyn_ftrace *rec;
        struct ftrace_page *pg;
-       int enable = mod_flags & FTRACE_MODIFY_ENABLE_FL;
+       bool enable = mod_flags & FTRACE_MODIFY_ENABLE_FL;
        int schedulable = mod_flags & FTRACE_MODIFY_MAY_SLEEP_FL;
        int failed;
 
index 05b0b31..66358d6 100644 (file)
@@ -128,16 +128,7 @@ int ring_buffer_print_entry_header(struct trace_seq *s)
 #define RB_ALIGNMENT           4U
 #define RB_MAX_SMALL_DATA      (RB_ALIGNMENT * RINGBUF_TYPE_DATA_TYPE_LEN_MAX)
 #define RB_EVNT_MIN_SIZE       8U      /* two 32bit words */
-
-#ifndef CONFIG_HAVE_64BIT_ALIGNED_ACCESS
-# define RB_FORCE_8BYTE_ALIGNMENT      0
-# define RB_ARCH_ALIGNMENT             RB_ALIGNMENT
-#else
-# define RB_FORCE_8BYTE_ALIGNMENT      1
-# define RB_ARCH_ALIGNMENT             8U
-#endif
-
-#define RB_ALIGN_DATA          __aligned(RB_ARCH_ALIGNMENT)
+#define RB_ALIGN_DATA          __aligned(RB_ALIGNMENT)
 
 /* define RINGBUF_TYPE_DATA for 'case RINGBUF_TYPE_DATA:' */
 #define RINGBUF_TYPE_DATA 0 ... RINGBUF_TYPE_DATA_TYPE_LEN_MAX
@@ -2373,7 +2364,7 @@ rb_update_event(struct ring_buffer_per_cpu *cpu_buffer,
 
        event->time_delta = delta;
        length -= RB_EVNT_HDR_SIZE;
-       if (length > RB_MAX_SMALL_DATA || RB_FORCE_8BYTE_ALIGNMENT) {
+       if (length > RB_MAX_SMALL_DATA) {
                event->type_len = 0;
                event->array[0] = length;
        } else
@@ -2388,11 +2379,11 @@ static unsigned rb_calculate_event_length(unsigned length)
        if (!length)
                length++;
 
-       if (length > RB_MAX_SMALL_DATA || RB_FORCE_8BYTE_ALIGNMENT)
+       if (length > RB_MAX_SMALL_DATA)
                length += sizeof(event.array[0]);
 
        length += RB_EVNT_HDR_SIZE;
-       length = ALIGN(length, RB_ARCH_ALIGNMENT);
+       length = ALIGN(length, RB_ALIGNMENT);
 
        /*
         * In case the time delta is larger than the 27 bits for it
index c90c687..525a97f 100644 (file)
@@ -366,7 +366,7 @@ trace_ignore_this_task(struct trace_pid_list *filtered_pids, struct task_struct
 }
 
 /**
- * trace_pid_filter_add_remove_task - Add or remove a task from a pid_list
+ * trace_filter_add_remove_task - Add or remove a task from a pid_list
  * @pid_list: The list to modify
  * @self: The current task for fork or NULL for exit
  * @task: The task to add or remove
@@ -743,8 +743,7 @@ trace_event_setup(struct ring_buffer_event *event,
 {
        struct trace_entry *ent = ring_buffer_event_data(event);
 
-       tracing_generic_entry_update(ent, flags, pc);
-       ent->type = type;
+       tracing_generic_entry_update(ent, type, flags, pc);
 }
 
 static __always_inline struct ring_buffer_event *
@@ -2312,13 +2311,14 @@ enum print_line_t trace_handle_return(struct trace_seq *s)
 EXPORT_SYMBOL_GPL(trace_handle_return);
 
 void
-tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags,
-                            int pc)
+tracing_generic_entry_update(struct trace_entry *entry, unsigned short type,
+                            unsigned long flags, int pc)
 {
        struct task_struct *tsk = current;
 
        entry->preempt_count            = pc & 0xff;
        entry->pid                      = (tsk) ? tsk->pid : 0;
+       entry->type                     = type;
        entry->flags =
 #ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT
                (irqs_disabled_flags(flags) ? TRACE_FLAG_IRQS_OFF : 0) |
@@ -4842,12 +4842,13 @@ static const char readme_msg[] =
        "\t     args: <name>=fetcharg[:type]\n"
        "\t fetcharg: %<register>, @<address>, @<symbol>[+|-<offset>],\n"
 #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
-       "\t           $stack<index>, $stack, $retval, $comm, $arg<N>\n"
+       "\t           $stack<index>, $stack, $retval, $comm, $arg<N>,\n"
 #else
-       "\t           $stack<index>, $stack, $retval, $comm\n"
+       "\t           $stack<index>, $stack, $retval, $comm,\n"
 #endif
+       "\t           +|-[u]<offset>(<fetcharg>)\n"
        "\t     type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n"
-       "\t           b<bit-width>@<bit-offset>/<container-size>,\n"
+       "\t           b<bit-width>@<bit-offset>/<container-size>, ustring,\n"
        "\t           <type>\\[<array-size>\\]\n"
 #ifdef CONFIG_HIST_TRIGGERS
        "\t    field: <stype> <name>;\n"
index 4629a61..0892e38 100644 (file)
@@ -416,8 +416,7 @@ void perf_trace_buf_update(void *record, u16 type)
        unsigned long flags;
 
        local_save_flags(flags);
-       tracing_generic_entry_update(entry, flags, pc);
-       entry->type = type;
+       tracing_generic_entry_update(entry, type, flags, pc);
 }
 NOKPROBE_SYMBOL(perf_trace_buf_update);
 
index 0ce3db6..c7506bc 100644 (file)
@@ -70,14 +70,6 @@ static int system_refcount_dec(struct event_subsystem *system)
 #define while_for_each_event_file()            \
        }
 
-static struct list_head *
-trace_get_fields(struct trace_event_call *event_call)
-{
-       if (!event_call->class->get_fields)
-               return &event_call->class->fields;
-       return event_call->class->get_fields(event_call);
-}
-
 static struct ftrace_event_field *
 __find_event_field(struct list_head *head, char *name)
 {
@@ -3190,7 +3182,7 @@ void __init trace_event_init(void)
        event_trace_enable();
 }
 
-#ifdef CONFIG_FTRACE_STARTUP_TEST
+#ifdef CONFIG_EVENT_TRACE_STARTUP_TEST
 
 static DEFINE_SPINLOCK(test_spinlock);
 static DEFINE_SPINLOCK(test_spinlock_irq);
index 5079d1d..c773b8f 100644 (file)
@@ -1084,6 +1084,9 @@ int filter_assign_type(const char *type)
        if (strchr(type, '[') && strstr(type, "char"))
                return FILTER_STATIC_STRING;
 
+       if (strcmp(type, "char *") == 0 || strcmp(type, "const char *") == 0)
+               return FILTER_PTR_STRING;
+
        return FILTER_OTHER;
 }
 
index 7d73624..9d483ad 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/rculist.h>
 #include <linux/error-injection.h>
 
+#include <asm/setup.h>  /* for COMMAND_LINE_SIZE */
+
 #include "trace_dynevent.h"
 #include "trace_kprobe_selftest.h"
 #include "trace_probe.h"
 
 #define KPROBE_EVENT_SYSTEM "kprobes"
 #define KRETPROBE_MAXACTIVE_MAX 4096
+#define MAX_KPROBE_CMDLINE_SIZE 1024
+
+/* Kprobe early definition from command line */
+static char kprobe_boot_events_buf[COMMAND_LINE_SIZE] __initdata;
+static bool kprobe_boot_events_enabled __initdata;
+
+static int __init set_kprobe_boot_events(char *str)
+{
+       strlcpy(kprobe_boot_events_buf, str, COMMAND_LINE_SIZE);
+       return 0;
+}
+__setup("kprobe_event=", set_kprobe_boot_events);
 
 static int trace_kprobe_create(int argc, const char **argv);
 static int trace_kprobe_show(struct seq_file *m, struct dyn_event *ev);
@@ -128,8 +142,8 @@ static bool trace_kprobe_match(const char *system, const char *event,
 {
        struct trace_kprobe *tk = to_trace_kprobe(ev);
 
-       return strcmp(trace_event_name(&tk->tp.call), event) == 0 &&
-           (!system || strcmp(tk->tp.call.class->system, system) == 0);
+       return strcmp(trace_probe_name(&tk->tp), event) == 0 &&
+           (!system || strcmp(trace_probe_group_name(&tk->tp), system) == 0);
 }
 
 static nokprobe_inline unsigned long trace_kprobe_nhit(struct trace_kprobe *tk)
@@ -143,6 +157,12 @@ static nokprobe_inline unsigned long trace_kprobe_nhit(struct trace_kprobe *tk)
        return nhit;
 }
 
+static nokprobe_inline bool trace_kprobe_is_registered(struct trace_kprobe *tk)
+{
+       return !(list_empty(&tk->rp.kp.list) &&
+                hlist_unhashed(&tk->rp.kp.hlist));
+}
+
 /* Return 0 if it fails to find the symbol address */
 static nokprobe_inline
 unsigned long trace_kprobe_address(struct trace_kprobe *tk)
@@ -183,6 +203,16 @@ static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs);
 static int kretprobe_dispatcher(struct kretprobe_instance *ri,
                                struct pt_regs *regs);
 
+static void free_trace_kprobe(struct trace_kprobe *tk)
+{
+       if (tk) {
+               trace_probe_cleanup(&tk->tp);
+               kfree(tk->symbol);
+               free_percpu(tk->nhit);
+               kfree(tk);
+       }
+}
+
 /*
  * Allocate new trace_probe and initialize it (including kprobes).
  */
@@ -220,49 +250,20 @@ static struct trace_kprobe *alloc_trace_kprobe(const char *group,
                tk->rp.kp.pre_handler = kprobe_dispatcher;
 
        tk->rp.maxactive = maxactive;
+       INIT_HLIST_NODE(&tk->rp.kp.hlist);
+       INIT_LIST_HEAD(&tk->rp.kp.list);
 
-       if (!event || !group) {
-               ret = -EINVAL;
-               goto error;
-       }
-
-       tk->tp.call.class = &tk->tp.class;
-       tk->tp.call.name = kstrdup(event, GFP_KERNEL);
-       if (!tk->tp.call.name)
-               goto error;
-
-       tk->tp.class.system = kstrdup(group, GFP_KERNEL);
-       if (!tk->tp.class.system)
+       ret = trace_probe_init(&tk->tp, event, group);
+       if (ret < 0)
                goto error;
 
        dyn_event_init(&tk->devent, &trace_kprobe_ops);
-       INIT_LIST_HEAD(&tk->tp.files);
        return tk;
 error:
-       kfree(tk->tp.call.name);
-       kfree(tk->symbol);
-       free_percpu(tk->nhit);
-       kfree(tk);
+       free_trace_kprobe(tk);
        return ERR_PTR(ret);
 }
 
-static void free_trace_kprobe(struct trace_kprobe *tk)
-{
-       int i;
-
-       if (!tk)
-               return;
-
-       for (i = 0; i < tk->tp.nr_args; i++)
-               traceprobe_free_probe_arg(&tk->tp.args[i]);
-
-       kfree(tk->tp.call.class->system);
-       kfree(tk->tp.call.name);
-       kfree(tk->symbol);
-       free_percpu(tk->nhit);
-       kfree(tk);
-}
-
 static struct trace_kprobe *find_trace_kprobe(const char *event,
                                              const char *group)
 {
@@ -270,8 +271,8 @@ static struct trace_kprobe *find_trace_kprobe(const char *event,
        struct trace_kprobe *tk;
 
        for_each_trace_kprobe(tk, pos)
-               if (strcmp(trace_event_name(&tk->tp.call), event) == 0 &&
-                   strcmp(tk->tp.call.class->system, group) == 0)
+               if (strcmp(trace_probe_name(&tk->tp), event) == 0 &&
+                   strcmp(trace_probe_group_name(&tk->tp), group) == 0)
                        return tk;
        return NULL;
 }
@@ -280,7 +281,7 @@ static inline int __enable_trace_kprobe(struct trace_kprobe *tk)
 {
        int ret = 0;
 
-       if (trace_probe_is_registered(&tk->tp) && !trace_kprobe_has_gone(tk)) {
+       if (trace_kprobe_is_registered(tk) && !trace_kprobe_has_gone(tk)) {
                if (trace_kprobe_is_return(tk))
                        ret = enable_kretprobe(&tk->rp);
                else
@@ -297,34 +298,27 @@ static inline int __enable_trace_kprobe(struct trace_kprobe *tk)
 static int
 enable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
 {
-       struct event_file_link *link;
+       bool enabled = trace_probe_is_enabled(&tk->tp);
        int ret = 0;
 
        if (file) {
-               link = kmalloc(sizeof(*link), GFP_KERNEL);
-               if (!link) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-
-               link->file = file;
-               list_add_tail_rcu(&link->list, &tk->tp.files);
+               ret = trace_probe_add_file(&tk->tp, file);
+               if (ret)
+                       return ret;
+       } else
+               trace_probe_set_flag(&tk->tp, TP_FLAG_PROFILE);
 
-               tk->tp.flags |= TP_FLAG_TRACE;
-               ret = __enable_trace_kprobe(tk);
-               if (ret) {
-                       list_del_rcu(&link->list);
-                       kfree(link);
-                       tk->tp.flags &= ~TP_FLAG_TRACE;
-               }
+       if (enabled)
+               return 0;
 
-       } else {
-               tk->tp.flags |= TP_FLAG_PROFILE;
-               ret = __enable_trace_kprobe(tk);
-               if (ret)
-                       tk->tp.flags &= ~TP_FLAG_PROFILE;
+       ret = __enable_trace_kprobe(tk);
+       if (ret) {
+               if (file)
+                       trace_probe_remove_file(&tk->tp, file);
+               else
+                       trace_probe_clear_flag(&tk->tp, TP_FLAG_PROFILE);
        }
- out:
+
        return ret;
 }
 
@@ -335,54 +329,34 @@ enable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
 static int
 disable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
 {
-       struct event_file_link *link = NULL;
-       int wait = 0;
+       struct trace_probe *tp = &tk->tp;
        int ret = 0;
 
        if (file) {
-               link = find_event_file_link(&tk->tp, file);
-               if (!link) {
-                       ret = -EINVAL;
-                       goto out;
-               }
-
-               list_del_rcu(&link->list);
-               wait = 1;
-               if (!list_empty(&tk->tp.files))
+               if (!trace_probe_get_file_link(tp, file))
+                       return -ENOENT;
+               if (!trace_probe_has_single_file(tp))
                        goto out;
-
-               tk->tp.flags &= ~TP_FLAG_TRACE;
+               trace_probe_clear_flag(tp, TP_FLAG_TRACE);
        } else
-               tk->tp.flags &= ~TP_FLAG_PROFILE;
+               trace_probe_clear_flag(tp, TP_FLAG_PROFILE);
 
-       if (!trace_probe_is_enabled(&tk->tp) && trace_probe_is_registered(&tk->tp)) {
+       if (!trace_probe_is_enabled(tp) && trace_kprobe_is_registered(tk)) {
                if (trace_kprobe_is_return(tk))
                        disable_kretprobe(&tk->rp);
                else
                        disable_kprobe(&tk->rp.kp);
-               wait = 1;
        }
 
-       /*
-        * if tk is not added to any list, it must be a local trace_kprobe
-        * created with perf_event_open. We don't need to wait for these
-        * trace_kprobes
-        */
-       if (list_empty(&tk->devent.list))
-               wait = 0;
  out:
-       if (wait) {
+       if (file)
                /*
-                * Synchronize with kprobe_trace_func/kretprobe_trace_func
-                * to ensure disabled (all running handlers are finished).
-                * This is not only for kfree(), but also the caller,
-                * trace_remove_event_call() supposes it for releasing
-                * event_call related objects, which will be accessed in
-                * the kprobe_trace_func/kretprobe_trace_func.
+                * Synchronization is done in below function. For perf event,
+                * file == NULL and perf_trace_event_unreg() calls
+                * tracepoint_synchronize_unregister() to ensure synchronize
+                * event. We don't need to care about it.
                 */
-               synchronize_rcu();
-               kfree(link);    /* Ignored if link == NULL */
-       }
+               trace_probe_remove_file(tp, file);
 
        return ret;
 }
@@ -415,7 +389,7 @@ static int __register_trace_kprobe(struct trace_kprobe *tk)
 {
        int i, ret;
 
-       if (trace_probe_is_registered(&tk->tp))
+       if (trace_kprobe_is_registered(tk))
                return -EINVAL;
 
        if (within_notrace_func(tk)) {
@@ -441,21 +415,20 @@ static int __register_trace_kprobe(struct trace_kprobe *tk)
        else
                ret = register_kprobe(&tk->rp.kp);
 
-       if (ret == 0)
-               tk->tp.flags |= TP_FLAG_REGISTERED;
        return ret;
 }
 
 /* Internal unregister function - just handle k*probes and flags */
 static void __unregister_trace_kprobe(struct trace_kprobe *tk)
 {
-       if (trace_probe_is_registered(&tk->tp)) {
+       if (trace_kprobe_is_registered(tk)) {
                if (trace_kprobe_is_return(tk))
                        unregister_kretprobe(&tk->rp);
                else
                        unregister_kprobe(&tk->rp.kp);
-               tk->tp.flags &= ~TP_FLAG_REGISTERED;
-               /* Cleanup kprobe for reuse */
+               /* Cleanup kprobe for reuse and mark it unregistered */
+               INIT_HLIST_NODE(&tk->rp.kp.hlist);
+               INIT_LIST_HEAD(&tk->rp.kp.list);
                if (tk->rp.kp.symbol_name)
                        tk->rp.kp.addr = NULL;
        }
@@ -487,8 +460,8 @@ static int register_trace_kprobe(struct trace_kprobe *tk)
        mutex_lock(&event_mutex);
 
        /* Delete old (same name) event if exist */
-       old_tk = find_trace_kprobe(trace_event_name(&tk->tp.call),
-                       tk->tp.call.class->system);
+       old_tk = find_trace_kprobe(trace_probe_name(&tk->tp),
+                                  trace_probe_group_name(&tk->tp));
        if (old_tk) {
                ret = unregister_trace_kprobe(old_tk);
                if (ret < 0)
@@ -541,7 +514,7 @@ static int trace_kprobe_module_callback(struct notifier_block *nb,
                        ret = __register_trace_kprobe(tk);
                        if (ret)
                                pr_warn("Failed to re-register probe %s on %s: %d\n",
-                                       trace_event_name(&tk->tp.call),
+                                       trace_probe_name(&tk->tp),
                                        mod->name, ret);
                }
        }
@@ -716,6 +689,10 @@ static int trace_kprobe_create(int argc, const char *argv[])
                        goto error;     /* This can be -ENOMEM */
        }
 
+       ret = traceprobe_set_print_fmt(&tk->tp, is_return);
+       if (ret < 0)
+               goto error;
+
        ret = register_trace_kprobe(tk);
        if (ret) {
                trace_probe_log_set_index(1);
@@ -767,8 +744,8 @@ static int trace_kprobe_show(struct seq_file *m, struct dyn_event *ev)
        int i;
 
        seq_putc(m, trace_kprobe_is_return(tk) ? 'r' : 'p');
-       seq_printf(m, ":%s/%s", tk->tp.call.class->system,
-                       trace_event_name(&tk->tp.call));
+       seq_printf(m, ":%s/%s", trace_probe_group_name(&tk->tp),
+                               trace_probe_name(&tk->tp));
 
        if (!tk->symbol)
                seq_printf(m, " 0x%p", tk->rp.kp.addr);
@@ -842,7 +819,7 @@ static int probes_profile_seq_show(struct seq_file *m, void *v)
 
        tk = to_trace_kprobe(ev);
        seq_printf(m, "  %-44s %15lu %15lu\n",
-                  trace_event_name(&tk->tp.call),
+                  trace_probe_name(&tk->tp),
                   trace_kprobe_nhit(tk),
                   tk->rp.kp.nmissed);
 
@@ -886,6 +863,15 @@ fetch_store_strlen(unsigned long addr)
        return (ret < 0) ? ret : len;
 }
 
+/* Return the length of string -- including null terminal byte */
+static nokprobe_inline int
+fetch_store_strlen_user(unsigned long addr)
+{
+       const void __user *uaddr =  (__force const void __user *)addr;
+
+       return strnlen_unsafe_user(uaddr, MAX_STRING_SIZE);
+}
+
 /*
  * Fetch a null-terminated string. Caller MUST set *(u32 *)buf with max
  * length and relative data location.
@@ -894,19 +880,46 @@ static nokprobe_inline int
 fetch_store_string(unsigned long addr, void *dest, void *base)
 {
        int maxlen = get_loc_len(*(u32 *)dest);
-       u8 *dst = get_loc_data(dest, base);
+       void *__dest;
        long ret;
 
        if (unlikely(!maxlen))
                return -ENOMEM;
+
+       __dest = get_loc_data(dest, base);
+
        /*
         * Try to get string again, since the string can be changed while
         * probing.
         */
-       ret = strncpy_from_unsafe(dst, (void *)addr, maxlen);
+       ret = strncpy_from_unsafe(__dest, (void *)addr, maxlen);
+       if (ret >= 0)
+               *(u32 *)dest = make_data_loc(ret, __dest - base);
+
+       return ret;
+}
 
+/*
+ * Fetch a null-terminated string from user. Caller MUST set *(u32 *)buf
+ * with max length and relative data location.
+ */
+static nokprobe_inline int
+fetch_store_string_user(unsigned long addr, void *dest, void *base)
+{
+       const void __user *uaddr =  (__force const void __user *)addr;
+       int maxlen = get_loc_len(*(u32 *)dest);
+       void *__dest;
+       long ret;
+
+       if (unlikely(!maxlen))
+               return -ENOMEM;
+
+       __dest = get_loc_data(dest, base);
+
+       ret = strncpy_from_unsafe_user(__dest, uaddr, maxlen);
        if (ret >= 0)
-               *(u32 *)dest = make_data_loc(ret, (void *)dst - base);
+               *(u32 *)dest = make_data_loc(ret, __dest - base);
+
        return ret;
 }
 
@@ -916,6 +929,14 @@ probe_mem_read(void *dest, void *src, size_t size)
        return probe_kernel_read(dest, src, size);
 }
 
+static nokprobe_inline int
+probe_mem_read_user(void *dest, void *src, size_t size)
+{
+       const void __user *uaddr =  (__force const void __user *)src;
+
+       return probe_user_read(dest, uaddr, size);
+}
+
 /* Note that we don't verify it, since the code does not come from user space */
 static int
 process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
@@ -971,7 +992,7 @@ __kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs,
        struct ring_buffer *buffer;
        int size, dsize, pc;
        unsigned long irq_flags;
-       struct trace_event_call *call = &tk->tp.call;
+       struct trace_event_call *call = trace_probe_event_call(&tk->tp);
 
        WARN_ON(call != trace_file->event_call);
 
@@ -1003,7 +1024,7 @@ kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs)
 {
        struct event_file_link *link;
 
-       list_for_each_entry_rcu(link, &tk->tp.files, list)
+       trace_probe_for_each_link_rcu(link, &tk->tp)
                __kprobe_trace_func(tk, regs, link->file);
 }
 NOKPROBE_SYMBOL(kprobe_trace_func);
@@ -1019,7 +1040,7 @@ __kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
        struct ring_buffer *buffer;
        int size, pc, dsize;
        unsigned long irq_flags;
-       struct trace_event_call *call = &tk->tp.call;
+       struct trace_event_call *call = trace_probe_event_call(&tk->tp);
 
        WARN_ON(call != trace_file->event_call);
 
@@ -1053,7 +1074,7 @@ kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
 {
        struct event_file_link *link;
 
-       list_for_each_entry_rcu(link, &tk->tp.files, list)
+       trace_probe_for_each_link_rcu(link, &tk->tp)
                __kretprobe_trace_func(tk, ri, regs, link->file);
 }
 NOKPROBE_SYMBOL(kretprobe_trace_func);
@@ -1070,7 +1091,7 @@ print_kprobe_event(struct trace_iterator *iter, int flags,
        field = (struct kprobe_trace_entry_head *)iter->ent;
        tp = container_of(event, struct trace_probe, call.event);
 
-       trace_seq_printf(s, "%s: (", trace_event_name(&tp->call));
+       trace_seq_printf(s, "%s: (", trace_probe_name(tp));
 
        if (!seq_print_ip_sym(s, field->ip, flags | TRACE_ITER_SYM_OFFSET))
                goto out;
@@ -1097,7 +1118,7 @@ print_kretprobe_event(struct trace_iterator *iter, int flags,
        field = (struct kretprobe_trace_entry_head *)iter->ent;
        tp = container_of(event, struct trace_probe, call.event);
 
-       trace_seq_printf(s, "%s: (", trace_event_name(&tp->call));
+       trace_seq_printf(s, "%s: (", trace_probe_name(tp));
 
        if (!seq_print_ip_sym(s, field->ret_ip, flags | TRACE_ITER_SYM_OFFSET))
                goto out;
@@ -1149,7 +1170,7 @@ static int kretprobe_event_define_fields(struct trace_event_call *event_call)
 static int
 kprobe_perf_func(struct trace_kprobe *tk, struct pt_regs *regs)
 {
-       struct trace_event_call *call = &tk->tp.call;
+       struct trace_event_call *call = trace_probe_event_call(&tk->tp);
        struct kprobe_trace_entry_head *entry;
        struct hlist_head *head;
        int size, __size, dsize;
@@ -1199,7 +1220,7 @@ static void
 kretprobe_perf_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
                    struct pt_regs *regs)
 {
-       struct trace_event_call *call = &tk->tp.call;
+       struct trace_event_call *call = trace_probe_event_call(&tk->tp);
        struct kretprobe_trace_entry_head *entry;
        struct hlist_head *head;
        int size, __size, dsize;
@@ -1299,10 +1320,10 @@ static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs)
 
        raw_cpu_inc(*tk->nhit);
 
-       if (tk->tp.flags & TP_FLAG_TRACE)
+       if (trace_probe_test_flag(&tk->tp, TP_FLAG_TRACE))
                kprobe_trace_func(tk, regs);
 #ifdef CONFIG_PERF_EVENTS
-       if (tk->tp.flags & TP_FLAG_PROFILE)
+       if (trace_probe_test_flag(&tk->tp, TP_FLAG_PROFILE))
                ret = kprobe_perf_func(tk, regs);
 #endif
        return ret;
@@ -1316,10 +1337,10 @@ kretprobe_dispatcher(struct kretprobe_instance *ri, struct pt_regs *regs)
 
        raw_cpu_inc(*tk->nhit);
 
-       if (tk->tp.flags & TP_FLAG_TRACE)
+       if (trace_probe_test_flag(&tk->tp, TP_FLAG_TRACE))
                kretprobe_trace_func(tk, ri, regs);
 #ifdef CONFIG_PERF_EVENTS
-       if (tk->tp.flags & TP_FLAG_PROFILE)
+       if (trace_probe_test_flag(&tk->tp, TP_FLAG_PROFILE))
                kretprobe_perf_func(tk, ri, regs);
 #endif
        return 0;       /* We don't tweek kernel, so just return 0 */
@@ -1334,10 +1355,10 @@ static struct trace_event_functions kprobe_funcs = {
        .trace          = print_kprobe_event
 };
 
-static inline void init_trace_event_call(struct trace_kprobe *tk,
-                                        struct trace_event_call *call)
+static inline void init_trace_event_call(struct trace_kprobe *tk)
 {
-       INIT_LIST_HEAD(&call->class->fields);
+       struct trace_event_call *call = trace_probe_event_call(&tk->tp);
+
        if (trace_kprobe_is_return(tk)) {
                call->event.funcs = &kretprobe_funcs;
                call->class->define_fields = kretprobe_event_define_fields;
@@ -1353,37 +1374,14 @@ static inline void init_trace_event_call(struct trace_kprobe *tk,
 
 static int register_kprobe_event(struct trace_kprobe *tk)
 {
-       struct trace_event_call *call = &tk->tp.call;
-       int ret = 0;
-
-       init_trace_event_call(tk, call);
+       init_trace_event_call(tk);
 
-       if (traceprobe_set_print_fmt(&tk->tp, trace_kprobe_is_return(tk)) < 0)
-               return -ENOMEM;
-       ret = register_trace_event(&call->event);
-       if (!ret) {
-               kfree(call->print_fmt);
-               return -ENODEV;
-       }
-       ret = trace_add_event_call(call);
-       if (ret) {
-               pr_info("Failed to register kprobe event: %s\n",
-                       trace_event_name(call));
-               kfree(call->print_fmt);
-               unregister_trace_event(&call->event);
-       }
-       return ret;
+       return trace_probe_register_event_call(&tk->tp);
 }
 
 static int unregister_kprobe_event(struct trace_kprobe *tk)
 {
-       int ret;
-
-       /* tp->event is unregistered in trace_remove_event_call() */
-       ret = trace_remove_event_call(&tk->tp.call);
-       if (!ret)
-               kfree(tk->tp.call.print_fmt);
-       return ret;
+       return trace_probe_unregister_event_call(&tk->tp);
 }
 
 #ifdef CONFIG_PERF_EVENTS
@@ -1413,7 +1411,7 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
                return ERR_CAST(tk);
        }
 
-       init_trace_event_call(tk, &tk->tp.call);
+       init_trace_event_call(tk);
 
        if (traceprobe_set_print_fmt(&tk->tp, trace_kprobe_is_return(tk)) < 0) {
                ret = -ENOMEM;
@@ -1421,12 +1419,10 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
        }
 
        ret = __register_trace_kprobe(tk);
-       if (ret < 0) {
-               kfree(tk->tp.call.print_fmt);
+       if (ret < 0)
                goto error;
-       }
 
-       return &tk->tp.call;
+       return trace_probe_event_call(&tk->tp);
 error:
        free_trace_kprobe(tk);
        return ERR_PTR(ret);
@@ -1445,11 +1441,50 @@ void destroy_local_trace_kprobe(struct trace_event_call *event_call)
 
        __unregister_trace_kprobe(tk);
 
-       kfree(tk->tp.call.print_fmt);
        free_trace_kprobe(tk);
 }
 #endif /* CONFIG_PERF_EVENTS */
 
+static __init void enable_boot_kprobe_events(void)
+{
+       struct trace_array *tr = top_trace_array();
+       struct trace_event_file *file;
+       struct trace_kprobe *tk;
+       struct dyn_event *pos;
+
+       mutex_lock(&event_mutex);
+       for_each_trace_kprobe(tk, pos) {
+               list_for_each_entry(file, &tr->events, list)
+                       if (file->event_call == trace_probe_event_call(&tk->tp))
+                               trace_event_enable_disable(file, 1, 0);
+       }
+       mutex_unlock(&event_mutex);
+}
+
+static __init void setup_boot_kprobe_events(void)
+{
+       char *p, *cmd = kprobe_boot_events_buf;
+       int ret;
+
+       strreplace(kprobe_boot_events_buf, ',', ' ');
+
+       while (cmd && *cmd != '\0') {
+               p = strchr(cmd, ';');
+               if (p)
+                       *p++ = '\0';
+
+               ret = trace_run_command(cmd, create_or_delete_trace_kprobe);
+               if (ret)
+                       pr_warn("Failed to add event(%d): %s\n", ret, cmd);
+               else
+                       kprobe_boot_events_enabled = true;
+
+               cmd = p;
+       }
+
+       enable_boot_kprobe_events();
+}
+
 /* Make a tracefs interface for controlling probe points */
 static __init int init_kprobe_trace(void)
 {
@@ -1481,6 +1516,9 @@ static __init int init_kprobe_trace(void)
 
        if (!entry)
                pr_warn("Could not create tracefs 'kprobe_profile' entry\n");
+
+       setup_boot_kprobe_events();
+
        return 0;
 }
 fs_initcall(init_kprobe_trace);
@@ -1493,7 +1531,7 @@ find_trace_probe_file(struct trace_kprobe *tk, struct trace_array *tr)
        struct trace_event_file *file;
 
        list_for_each_entry(file, &tr->events, list)
-               if (file->event_call == &tk->tp.call)
+               if (file->event_call == trace_probe_event_call(&tk->tp))
                        return file;
 
        return NULL;
@@ -1513,6 +1551,11 @@ static __init int kprobe_trace_self_tests_init(void)
        if (tracing_is_disabled())
                return -ENODEV;
 
+       if (kprobe_boot_events_enabled) {
+               pr_info("Skipping kprobe tests due to kprobe_event on cmdline\n");
+               return 0;
+       }
+
        target = kprobe_trace_selftest_target;
 
        pr_info("Testing kprobe tracing: ");
index ba751f9..cab4a53 100644 (file)
@@ -1109,17 +1109,10 @@ static enum print_line_t trace_user_stack_print(struct trace_iterator *iter,
        for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
                unsigned long ip = field->caller[i];
 
-               if (ip == ULONG_MAX || trace_seq_has_overflowed(s))
+               if (!ip || trace_seq_has_overflowed(s))
                        break;
 
                trace_seq_puts(s, " => ");
-
-               if (!ip) {
-                       trace_seq_puts(s, "??");
-                       trace_seq_putc(s, '\n');
-                       continue;
-               }
-
                seq_print_user_ip(s, mm, ip, flags);
                trace_seq_putc(s, '\n');
        }
index a347fac..dbef0d1 100644 (file)
@@ -78,6 +78,8 @@ static const struct fetch_type probe_fetch_types[] = {
        /* Special types */
        __ASSIGN_FETCH_TYPE("string", string, string, sizeof(u32), 1,
                            "__data_loc char[]"),
+       __ASSIGN_FETCH_TYPE("ustring", string, string, sizeof(u32), 1,
+                           "__data_loc char[]"),
        /* Basic types */
        ASSIGN_FETCH_TYPE(u8,  u8,  0),
        ASSIGN_FETCH_TYPE(u16, u16, 0),
@@ -322,6 +324,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
 {
        struct fetch_insn *code = *pcode;
        unsigned long param;
+       int deref = FETCH_OP_DEREF;
        long offset = 0;
        char *tmp;
        int ret = 0;
@@ -394,9 +397,14 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
                break;
 
        case '+':       /* deref memory */
-               arg++;  /* Skip '+', because kstrtol() rejects it. */
-               /* fall through */
        case '-':
+               if (arg[1] == 'u') {
+                       deref = FETCH_OP_UDEREF;
+                       arg[1] = arg[0];
+                       arg++;
+               }
+               if (arg[0] == '+')
+                       arg++;  /* Skip '+', because kstrtol() rejects it. */
                tmp = strchr(arg, '(');
                if (!tmp) {
                        trace_probe_log_err(offs, DEREF_NEED_BRACE);
@@ -432,7 +440,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
                        }
                        *pcode = code;
 
-                       code->op = FETCH_OP_DEREF;
+                       code->op = deref;
                        code->offset = offset;
                }
                break;
@@ -569,15 +577,17 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,
                goto fail;
 
        /* Store operation */
-       if (!strcmp(parg->type->name, "string")) {
-               if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_IMM &&
-                   code->op != FETCH_OP_COMM) {
+       if (!strcmp(parg->type->name, "string") ||
+           !strcmp(parg->type->name, "ustring")) {
+               if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_UDEREF &&
+                   code->op != FETCH_OP_IMM && code->op != FETCH_OP_COMM) {
                        trace_probe_log_err(offset + (t ? (t - arg) : 0),
                                            BAD_STRING);
                        ret = -EINVAL;
                        goto fail;
                }
-               if (code->op != FETCH_OP_DEREF || parg->count) {
+               if ((code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM) ||
+                    parg->count) {
                        /*
                         * IMM and COMM is pointing actual address, those must
                         * be kept, and if parg->count != 0, this is an array
@@ -590,12 +600,20 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,
                                goto fail;
                        }
                }
-               code->op = FETCH_OP_ST_STRING;  /* In DEREF case, replace it */
+               /* If op == DEREF, replace it with STRING */
+               if (!strcmp(parg->type->name, "ustring") ||
+                   code->op == FETCH_OP_UDEREF)
+                       code->op = FETCH_OP_ST_USTRING;
+               else
+                       code->op = FETCH_OP_ST_STRING;
                code->size = parg->type->size;
                parg->dynamic = true;
        } else if (code->op == FETCH_OP_DEREF) {
                code->op = FETCH_OP_ST_MEM;
                code->size = parg->type->size;
+       } else if (code->op == FETCH_OP_UDEREF) {
+               code->op = FETCH_OP_ST_UMEM;
+               code->size = parg->type->size;
        } else {
                code++;
                if (code->op != FETCH_OP_NOP) {
@@ -618,7 +636,8 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,
        /* Loop(Array) operation */
        if (parg->count) {
                if (scode->op != FETCH_OP_ST_MEM &&
-                   scode->op != FETCH_OP_ST_STRING) {
+                   scode->op != FETCH_OP_ST_STRING &&
+                   scode->op != FETCH_OP_ST_USTRING) {
                        trace_probe_log_err(offset + (t ? (t - arg) : 0),
                                            BAD_STRING);
                        ret = -EINVAL;
@@ -825,6 +844,7 @@ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len,
 
 int traceprobe_set_print_fmt(struct trace_probe *tp, bool is_return)
 {
+       struct trace_event_call *call = trace_probe_event_call(tp);
        int len;
        char *print_fmt;
 
@@ -836,7 +856,7 @@ int traceprobe_set_print_fmt(struct trace_probe *tp, bool is_return)
 
        /* Second: actually write the @print_fmt */
        __set_print_fmt(tp, print_fmt, len + 1, is_return);
-       tp->call.print_fmt = print_fmt;
+       call->print_fmt = print_fmt;
 
        return 0;
 }
@@ -865,3 +885,105 @@ int traceprobe_define_arg_fields(struct trace_event_call *event_call,
        }
        return 0;
 }
+
+
+void trace_probe_cleanup(struct trace_probe *tp)
+{
+       struct trace_event_call *call = trace_probe_event_call(tp);
+       int i;
+
+       for (i = 0; i < tp->nr_args; i++)
+               traceprobe_free_probe_arg(&tp->args[i]);
+
+       kfree(call->class->system);
+       kfree(call->name);
+       kfree(call->print_fmt);
+}
+
+int trace_probe_init(struct trace_probe *tp, const char *event,
+                    const char *group)
+{
+       struct trace_event_call *call = trace_probe_event_call(tp);
+
+       if (!event || !group)
+               return -EINVAL;
+
+       call->class = &tp->class;
+       call->name = kstrdup(event, GFP_KERNEL);
+       if (!call->name)
+               return -ENOMEM;
+
+       tp->class.system = kstrdup(group, GFP_KERNEL);
+       if (!tp->class.system) {
+               kfree(call->name);
+               call->name = NULL;
+               return -ENOMEM;
+       }
+       INIT_LIST_HEAD(&tp->files);
+       INIT_LIST_HEAD(&tp->class.fields);
+
+       return 0;
+}
+
+int trace_probe_register_event_call(struct trace_probe *tp)
+{
+       struct trace_event_call *call = trace_probe_event_call(tp);
+       int ret;
+
+       ret = register_trace_event(&call->event);
+       if (!ret)
+               return -ENODEV;
+
+       ret = trace_add_event_call(call);
+       if (ret)
+               unregister_trace_event(&call->event);
+
+       return ret;
+}
+
+int trace_probe_add_file(struct trace_probe *tp, struct trace_event_file *file)
+{
+       struct event_file_link *link;
+
+       link = kmalloc(sizeof(*link), GFP_KERNEL);
+       if (!link)
+               return -ENOMEM;
+
+       link->file = file;
+       INIT_LIST_HEAD(&link->list);
+       list_add_tail_rcu(&link->list, &tp->files);
+       trace_probe_set_flag(tp, TP_FLAG_TRACE);
+       return 0;
+}
+
+struct event_file_link *trace_probe_get_file_link(struct trace_probe *tp,
+                                                 struct trace_event_file *file)
+{
+       struct event_file_link *link;
+
+       trace_probe_for_each_link(link, tp) {
+               if (link->file == file)
+                       return link;
+       }
+
+       return NULL;
+}
+
+int trace_probe_remove_file(struct trace_probe *tp,
+                           struct trace_event_file *file)
+{
+       struct event_file_link *link;
+
+       link = trace_probe_get_file_link(tp, file);
+       if (!link)
+               return -ENOENT;
+
+       list_del_rcu(&link->list);
+       synchronize_rcu();
+       kfree(link);
+
+       if (list_empty(&tp->files))
+               trace_probe_clear_flag(tp, TP_FLAG_TRACE);
+
+       return 0;
+}
index f9a8c63..d171482 100644 (file)
@@ -55,7 +55,6 @@
 /* Flags for trace_probe */
 #define TP_FLAG_TRACE          1
 #define TP_FLAG_PROFILE                2
-#define TP_FLAG_REGISTERED     4
 
 /* data_loc: data location, compatible with u32 */
 #define make_data_loc(len, offs)       \
@@ -92,10 +91,13 @@ enum fetch_op {
        FETCH_OP_FOFFS,         /* File offset: .immediate */
        // Stage 2 (dereference) op
        FETCH_OP_DEREF,         /* Dereference: .offset */
+       FETCH_OP_UDEREF,        /* User-space Dereference: .offset */
        // Stage 3 (store) ops
        FETCH_OP_ST_RAW,        /* Raw: .size */
        FETCH_OP_ST_MEM,        /* Mem: .offset, .size */
+       FETCH_OP_ST_UMEM,       /* Mem: .offset, .size */
        FETCH_OP_ST_STRING,     /* String: .offset, .size */
+       FETCH_OP_ST_USTRING,    /* User String: .offset, .size */
        // Stage 4 (modify) op
        FETCH_OP_MOD_BF,        /* Bitfield: .basesize, .lshift, .rshift */
        // Stage 5 (loop) op
@@ -235,16 +237,71 @@ struct event_file_link {
        struct list_head                list;
 };
 
+static inline bool trace_probe_test_flag(struct trace_probe *tp,
+                                        unsigned int flag)
+{
+       return !!(tp->flags & flag);
+}
+
+static inline void trace_probe_set_flag(struct trace_probe *tp,
+                                       unsigned int flag)
+{
+       tp->flags |= flag;
+}
+
+static inline void trace_probe_clear_flag(struct trace_probe *tp,
+                                         unsigned int flag)
+{
+       tp->flags &= ~flag;
+}
+
 static inline bool trace_probe_is_enabled(struct trace_probe *tp)
 {
-       return !!(tp->flags & (TP_FLAG_TRACE | TP_FLAG_PROFILE));
+       return trace_probe_test_flag(tp, TP_FLAG_TRACE | TP_FLAG_PROFILE);
 }
 
-static inline bool trace_probe_is_registered(struct trace_probe *tp)
+static inline const char *trace_probe_name(struct trace_probe *tp)
 {
-       return !!(tp->flags & TP_FLAG_REGISTERED);
+       return trace_event_name(&tp->call);
 }
 
+static inline const char *trace_probe_group_name(struct trace_probe *tp)
+{
+       return tp->call.class->system;
+}
+
+static inline struct trace_event_call *
+       trace_probe_event_call(struct trace_probe *tp)
+{
+       return &tp->call;
+}
+
+static inline int trace_probe_unregister_event_call(struct trace_probe *tp)
+{
+       /* tp->event is unregistered in trace_remove_event_call() */
+       return trace_remove_event_call(&tp->call);
+}
+
+static inline bool trace_probe_has_single_file(struct trace_probe *tp)
+{
+       return !!list_is_singular(&tp->files);
+}
+
+int trace_probe_init(struct trace_probe *tp, const char *event,
+                    const char *group);
+void trace_probe_cleanup(struct trace_probe *tp);
+int trace_probe_register_event_call(struct trace_probe *tp);
+int trace_probe_add_file(struct trace_probe *tp, struct trace_event_file *file);
+int trace_probe_remove_file(struct trace_probe *tp,
+                           struct trace_event_file *file);
+struct event_file_link *trace_probe_get_file_link(struct trace_probe *tp,
+                                               struct trace_event_file *file);
+
+#define trace_probe_for_each_link(pos, tp)     \
+       list_for_each_entry(pos, &(tp)->files, list)
+#define trace_probe_for_each_link_rcu(pos, tp) \
+       list_for_each_entry_rcu(pos, &(tp)->files, list)
+
 /* Check the name is good for event/group/fields */
 static inline bool is_good_name(const char *name)
 {
@@ -257,18 +314,6 @@ static inline bool is_good_name(const char *name)
        return true;
 }
 
-static inline struct event_file_link *
-find_event_file_link(struct trace_probe *tp, struct trace_event_file *file)
-{
-       struct event_file_link *link;
-
-       list_for_each_entry(link, &tp->files, list)
-               if (link->file == file)
-                       return link;
-
-       return NULL;
-}
-
 #define TPARG_FL_RETURN BIT(0)
 #define TPARG_FL_KERNEL BIT(1)
 #define TPARG_FL_FENTRY BIT(2)
index c30c61f..e528282 100644 (file)
@@ -59,8 +59,13 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs,
 static nokprobe_inline int fetch_store_strlen(unsigned long addr);
 static nokprobe_inline int
 fetch_store_string(unsigned long addr, void *dest, void *base);
+static nokprobe_inline int fetch_store_strlen_user(unsigned long addr);
+static nokprobe_inline int
+fetch_store_string_user(unsigned long addr, void *dest, void *base);
 static nokprobe_inline int
 probe_mem_read(void *dest, void *src, size_t size);
+static nokprobe_inline int
+probe_mem_read_user(void *dest, void *src, size_t size);
 
 /* From the 2nd stage, routine is same */
 static nokprobe_inline int
@@ -74,14 +79,21 @@ process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
 
 stage2:
        /* 2nd stage: dereference memory if needed */
-       while (code->op == FETCH_OP_DEREF) {
-               lval = val;
-               ret = probe_mem_read(&val, (void *)val + code->offset,
-                                       sizeof(val));
+       do {
+               if (code->op == FETCH_OP_DEREF) {
+                       lval = val;
+                       ret = probe_mem_read(&val, (void *)val + code->offset,
+                                            sizeof(val));
+               } else if (code->op == FETCH_OP_UDEREF) {
+                       lval = val;
+                       ret = probe_mem_read_user(&val,
+                                (void *)val + code->offset, sizeof(val));
+               } else
+                       break;
                if (ret)
                        return ret;
                code++;
-       }
+       } while (1);
 
        s3 = code;
 stage3:
@@ -91,6 +103,10 @@ stage3:
                        ret = fetch_store_strlen(val + code->offset);
                        code++;
                        goto array;
+               } else if (code->op == FETCH_OP_ST_USTRING) {
+                       ret += fetch_store_strlen_user(val + code->offset);
+                       code++;
+                       goto array;
                } else
                        return -EILSEQ;
        }
@@ -102,10 +118,17 @@ stage3:
        case FETCH_OP_ST_MEM:
                probe_mem_read(dest, (void *)val + code->offset, code->size);
                break;
+       case FETCH_OP_ST_UMEM:
+               probe_mem_read_user(dest, (void *)val + code->offset, code->size);
+               break;
        case FETCH_OP_ST_STRING:
                loc = *(u32 *)dest;
                ret = fetch_store_string(val + code->offset, dest, base);
                break;
+       case FETCH_OP_ST_USTRING:
+               loc = *(u32 *)dest;
+               ret = fetch_store_string_user(val + code->offset, dest, base);
+               break;
        default:
                return -EILSEQ;
        }
@@ -123,7 +146,8 @@ array:
                total += ret;
                if (++i < code->param) {
                        code = s3;
-                       if (s3->op != FETCH_OP_ST_STRING) {
+                       if (s3->op != FETCH_OP_ST_STRING &&
+                           s3->op != FETCH_OP_ST_USTRING) {
                                dest += s3->size;
                                val += s3->size;
                                goto stage3;
index 7860e3f..1ceedb9 100644 (file)
@@ -140,6 +140,13 @@ probe_mem_read(void *dest, void *src, size_t size)
 
        return copy_from_user(dest, vaddr, size) ? -EFAULT : 0;
 }
+
+static nokprobe_inline int
+probe_mem_read_user(void *dest, void *src, size_t size)
+{
+       return probe_mem_read(dest, src, size);
+}
+
 /*
  * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
  * length and relative data location.
@@ -176,6 +183,12 @@ fetch_store_string(unsigned long addr, void *dest, void *base)
        return ret;
 }
 
+static nokprobe_inline int
+fetch_store_string_user(unsigned long addr, void *dest, void *base)
+{
+       return fetch_store_string(addr, dest, base);
+}
+
 /* Return the length of string -- including null terminal byte */
 static nokprobe_inline int
 fetch_store_strlen(unsigned long addr)
@@ -191,6 +204,12 @@ fetch_store_strlen(unsigned long addr)
        return (len > MAX_STRING_SIZE) ? 0 : len;
 }
 
+static nokprobe_inline int
+fetch_store_strlen_user(unsigned long addr)
+{
+       return fetch_store_strlen(addr);
+}
+
 static unsigned long translate_user_vaddr(unsigned long file_offset)
 {
        unsigned long base_addr;
@@ -270,8 +289,8 @@ static bool trace_uprobe_match(const char *system, const char *event,
 {
        struct trace_uprobe *tu = to_trace_uprobe(ev);
 
-       return strcmp(trace_event_name(&tu->tp.call), event) == 0 &&
-               (!system || strcmp(tu->tp.call.class->system, system) == 0);
+       return strcmp(trace_probe_name(&tu->tp), event) == 0 &&
+           (!system || strcmp(trace_probe_group_name(&tu->tp), system) == 0);
 }
 
 /*
@@ -281,25 +300,17 @@ static struct trace_uprobe *
 alloc_trace_uprobe(const char *group, const char *event, int nargs, bool is_ret)
 {
        struct trace_uprobe *tu;
-
-       if (!event || !group)
-               return ERR_PTR(-EINVAL);
+       int ret;
 
        tu = kzalloc(SIZEOF_TRACE_UPROBE(nargs), GFP_KERNEL);
        if (!tu)
                return ERR_PTR(-ENOMEM);
 
-       tu->tp.call.class = &tu->tp.class;
-       tu->tp.call.name = kstrdup(event, GFP_KERNEL);
-       if (!tu->tp.call.name)
-               goto error;
-
-       tu->tp.class.system = kstrdup(group, GFP_KERNEL);
-       if (!tu->tp.class.system)
+       ret = trace_probe_init(&tu->tp, event, group);
+       if (ret < 0)
                goto error;
 
        dyn_event_init(&tu->devent, &trace_uprobe_ops);
-       INIT_LIST_HEAD(&tu->tp.files);
        tu->consumer.handler = uprobe_dispatcher;
        if (is_ret)
                tu->consumer.ret_handler = uretprobe_dispatcher;
@@ -307,25 +318,18 @@ alloc_trace_uprobe(const char *group, const char *event, int nargs, bool is_ret)
        return tu;
 
 error:
-       kfree(tu->tp.call.name);
        kfree(tu);
 
-       return ERR_PTR(-ENOMEM);
+       return ERR_PTR(ret);
 }
 
 static void free_trace_uprobe(struct trace_uprobe *tu)
 {
-       int i;
-
        if (!tu)
                return;
 
-       for (i = 0; i < tu->tp.nr_args; i++)
-               traceprobe_free_probe_arg(&tu->tp.args[i]);
-
        path_put(&tu->path);
-       kfree(tu->tp.call.class->system);
-       kfree(tu->tp.call.name);
+       trace_probe_cleanup(&tu->tp);
        kfree(tu->filename);
        kfree(tu);
 }
@@ -336,8 +340,8 @@ static struct trace_uprobe *find_probe_event(const char *event, const char *grou
        struct trace_uprobe *tu;
 
        for_each_trace_uprobe(tu, pos)
-               if (strcmp(trace_event_name(&tu->tp.call), event) == 0 &&
-                   strcmp(tu->tp.call.class->system, group) == 0)
+               if (strcmp(trace_probe_name(&tu->tp), event) == 0 &&
+                   strcmp(trace_probe_group_name(&tu->tp), group) == 0)
                        return tu;
 
        return NULL;
@@ -372,8 +376,8 @@ static struct trace_uprobe *find_old_trace_uprobe(struct trace_uprobe *new)
        struct trace_uprobe *tmp, *old = NULL;
        struct inode *new_inode = d_real_inode(new->path.dentry);
 
-       old = find_probe_event(trace_event_name(&new->tp.call),
-                               new->tp.call.class->system);
+       old = find_probe_event(trace_probe_name(&new->tp),
+                               trace_probe_group_name(&new->tp));
 
        for_each_trace_uprobe(tmp, pos) {
                if ((old ? old != tmp : true) &&
@@ -578,6 +582,10 @@ static int trace_uprobe_create(int argc, const char **argv)
                        goto error;
        }
 
+       ret = traceprobe_set_print_fmt(&tu->tp, is_ret_probe(tu));
+       if (ret < 0)
+               goto error;
+
        ret = register_trace_uprobe(tu);
        if (!ret)
                goto out;
@@ -621,8 +629,8 @@ static int trace_uprobe_show(struct seq_file *m, struct dyn_event *ev)
        char c = is_ret_probe(tu) ? 'r' : 'p';
        int i;
 
-       seq_printf(m, "%c:%s/%s %s:0x%0*lx", c, tu->tp.call.class->system,
-                       trace_event_name(&tu->tp.call), tu->filename,
+       seq_printf(m, "%c:%s/%s %s:0x%0*lx", c, trace_probe_group_name(&tu->tp),
+                       trace_probe_name(&tu->tp), tu->filename,
                        (int)(sizeof(void *) * 2), tu->offset);
 
        if (tu->ref_ctr_offset)
@@ -692,7 +700,7 @@ static int probes_profile_seq_show(struct seq_file *m, void *v)
 
        tu = to_trace_uprobe(ev);
        seq_printf(m, "  %s %-44s %15lu\n", tu->filename,
-                       trace_event_name(&tu->tp.call), tu->nhit);
+                       trace_probe_name(&tu->tp), tu->nhit);
        return 0;
 }
 
@@ -818,7 +826,7 @@ static void __uprobe_trace_func(struct trace_uprobe *tu,
        struct ring_buffer *buffer;
        void *data;
        int size, esize;
-       struct trace_event_call *call = &tu->tp.call;
+       struct trace_event_call *call = trace_probe_event_call(&tu->tp);
 
        WARN_ON(call != trace_file->event_call);
 
@@ -860,7 +868,7 @@ static int uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs,
                return 0;
 
        rcu_read_lock();
-       list_for_each_entry_rcu(link, &tu->tp.files, list)
+       trace_probe_for_each_link_rcu(link, &tu->tp)
                __uprobe_trace_func(tu, 0, regs, ucb, dsize, link->file);
        rcu_read_unlock();
 
@@ -874,7 +882,7 @@ static void uretprobe_trace_func(struct trace_uprobe *tu, unsigned long func,
        struct event_file_link *link;
 
        rcu_read_lock();
-       list_for_each_entry_rcu(link, &tu->tp.files, list)
+       trace_probe_for_each_link_rcu(link, &tu->tp)
                __uprobe_trace_func(tu, func, regs, ucb, dsize, link->file);
        rcu_read_unlock();
 }
@@ -893,12 +901,12 @@ print_uprobe_event(struct trace_iterator *iter, int flags, struct trace_event *e
 
        if (is_ret_probe(tu)) {
                trace_seq_printf(s, "%s: (0x%lx <- 0x%lx)",
-                                trace_event_name(&tu->tp.call),
+                                trace_probe_name(&tu->tp),
                                 entry->vaddr[1], entry->vaddr[0]);
                data = DATAOF_TRACE_ENTRY(entry, true);
        } else {
                trace_seq_printf(s, "%s: (0x%lx)",
-                                trace_event_name(&tu->tp.call),
+                                trace_probe_name(&tu->tp),
                                 entry->vaddr[0]);
                data = DATAOF_TRACE_ENTRY(entry, false);
        }
@@ -921,26 +929,20 @@ probe_event_enable(struct trace_uprobe *tu, struct trace_event_file *file,
                   filter_func_t filter)
 {
        bool enabled = trace_probe_is_enabled(&tu->tp);
-       struct event_file_link *link = NULL;
        int ret;
 
        if (file) {
-               if (tu->tp.flags & TP_FLAG_PROFILE)
+               if (trace_probe_test_flag(&tu->tp, TP_FLAG_PROFILE))
                        return -EINTR;
 
-               link = kmalloc(sizeof(*link), GFP_KERNEL);
-               if (!link)
-                       return -ENOMEM;
-
-               link->file = file;
-               list_add_tail_rcu(&link->list, &tu->tp.files);
-
-               tu->tp.flags |= TP_FLAG_TRACE;
+               ret = trace_probe_add_file(&tu->tp, file);
+               if (ret < 0)
+                       return ret;
        } else {
-               if (tu->tp.flags & TP_FLAG_TRACE)
+               if (trace_probe_test_flag(&tu->tp, TP_FLAG_TRACE))
                        return -EINTR;
 
-               tu->tp.flags |= TP_FLAG_PROFILE;
+               trace_probe_set_flag(&tu->tp, TP_FLAG_PROFILE);
        }
 
        WARN_ON(!uprobe_filter_is_empty(&tu->filter));
@@ -970,13 +972,11 @@ probe_event_enable(struct trace_uprobe *tu, struct trace_event_file *file,
        uprobe_buffer_disable();
 
  err_flags:
-       if (file) {
-               list_del(&link->list);
-               kfree(link);
-               tu->tp.flags &= ~TP_FLAG_TRACE;
-       } else {
-               tu->tp.flags &= ~TP_FLAG_PROFILE;
-       }
+       if (file)
+               trace_probe_remove_file(&tu->tp, file);
+       else
+               trace_probe_clear_flag(&tu->tp, TP_FLAG_PROFILE);
+
        return ret;
 }
 
@@ -987,26 +987,18 @@ probe_event_disable(struct trace_uprobe *tu, struct trace_event_file *file)
                return;
 
        if (file) {
-               struct event_file_link *link;
-
-               link = find_event_file_link(&tu->tp, file);
-               if (!link)
+               if (trace_probe_remove_file(&tu->tp, file) < 0)
                        return;
 
-               list_del_rcu(&link->list);
-               /* synchronize with u{,ret}probe_trace_func */
-               synchronize_rcu();
-               kfree(link);
-
-               if (!list_empty(&tu->tp.files))
+               if (trace_probe_is_enabled(&tu->tp))
                        return;
-       }
+       } else
+               trace_probe_clear_flag(&tu->tp, TP_FLAG_PROFILE);
 
        WARN_ON(!uprobe_filter_is_empty(&tu->filter));
 
        uprobe_unregister(tu->inode, tu->offset, &tu->consumer);
        tu->inode = NULL;
-       tu->tp.flags &= file ? ~TP_FLAG_TRACE : ~TP_FLAG_PROFILE;
 
        uprobe_buffer_disable();
 }
@@ -1126,7 +1118,7 @@ static void __uprobe_perf_func(struct trace_uprobe *tu,
                               unsigned long func, struct pt_regs *regs,
                               struct uprobe_cpu_buffer *ucb, int dsize)
 {
-       struct trace_event_call *call = &tu->tp.call;
+       struct trace_event_call *call = trace_probe_event_call(&tu->tp);
        struct uprobe_trace_entry_head *entry;
        struct hlist_head *head;
        void *data;
@@ -1279,11 +1271,11 @@ static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs)
        ucb = uprobe_buffer_get();
        store_trace_args(ucb->buf, &tu->tp, regs, esize, dsize);
 
-       if (tu->tp.flags & TP_FLAG_TRACE)
+       if (trace_probe_test_flag(&tu->tp, TP_FLAG_TRACE))
                ret |= uprobe_trace_func(tu, regs, ucb, dsize);
 
 #ifdef CONFIG_PERF_EVENTS
-       if (tu->tp.flags & TP_FLAG_PROFILE)
+       if (trace_probe_test_flag(&tu->tp, TP_FLAG_PROFILE))
                ret |= uprobe_perf_func(tu, regs, ucb, dsize);
 #endif
        uprobe_buffer_put(ucb);
@@ -1314,11 +1306,11 @@ static int uretprobe_dispatcher(struct uprobe_consumer *con,
        ucb = uprobe_buffer_get();
        store_trace_args(ucb->buf, &tu->tp, regs, esize, dsize);
 
-       if (tu->tp.flags & TP_FLAG_TRACE)
+       if (trace_probe_test_flag(&tu->tp, TP_FLAG_TRACE))
                uretprobe_trace_func(tu, func, regs, ucb, dsize);
 
 #ifdef CONFIG_PERF_EVENTS
-       if (tu->tp.flags & TP_FLAG_PROFILE)
+       if (trace_probe_test_flag(&tu->tp, TP_FLAG_PROFILE))
                uretprobe_perf_func(tu, func, regs, ucb, dsize);
 #endif
        uprobe_buffer_put(ucb);
@@ -1329,10 +1321,10 @@ static struct trace_event_functions uprobe_funcs = {
        .trace          = print_uprobe_event
 };
 
-static inline void init_trace_event_call(struct trace_uprobe *tu,
-                                        struct trace_event_call *call)
+static inline void init_trace_event_call(struct trace_uprobe *tu)
 {
-       INIT_LIST_HEAD(&call->class->fields);
+       struct trace_event_call *call = trace_probe_event_call(&tu->tp);
+
        call->event.funcs = &uprobe_funcs;
        call->class->define_fields = uprobe_event_define_fields;
 
@@ -1343,43 +1335,14 @@ static inline void init_trace_event_call(struct trace_uprobe *tu,
 
 static int register_uprobe_event(struct trace_uprobe *tu)
 {
-       struct trace_event_call *call = &tu->tp.call;
-       int ret = 0;
-
-       init_trace_event_call(tu, call);
-
-       if (traceprobe_set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0)
-               return -ENOMEM;
+       init_trace_event_call(tu);
 
-       ret = register_trace_event(&call->event);
-       if (!ret) {
-               kfree(call->print_fmt);
-               return -ENODEV;
-       }
-
-       ret = trace_add_event_call(call);
-
-       if (ret) {
-               pr_info("Failed to register uprobe event: %s\n",
-                       trace_event_name(call));
-               kfree(call->print_fmt);
-               unregister_trace_event(&call->event);
-       }
-
-       return ret;
+       return trace_probe_register_event_call(&tu->tp);
 }
 
 static int unregister_uprobe_event(struct trace_uprobe *tu)
 {
-       int ret;
-
-       /* tu->event is unregistered in trace_remove_event_call() */
-       ret = trace_remove_event_call(&tu->tp.call);
-       if (ret)
-               return ret;
-       kfree(tu->tp.call.print_fmt);
-       tu->tp.call.print_fmt = NULL;
-       return 0;
+       return trace_probe_unregister_event_call(&tu->tp);
 }
 
 #ifdef CONFIG_PERF_EVENTS
@@ -1419,14 +1382,14 @@ create_local_trace_uprobe(char *name, unsigned long offs,
        tu->path = path;
        tu->ref_ctr_offset = ref_ctr_offset;
        tu->filename = kstrdup(name, GFP_KERNEL);
-       init_trace_event_call(tu, &tu->tp.call);
+       init_trace_event_call(tu);
 
        if (traceprobe_set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0) {
                ret = -ENOMEM;
                goto error;
        }
 
-       return &tu->tp.call;
+       return trace_probe_event_call(&tu->tp);
 error:
        free_trace_uprobe(tu);
        return ERR_PTR(ret);
@@ -1438,9 +1401,6 @@ void destroy_local_trace_uprobe(struct trace_event_call *event_call)
 
        tu = container_of(event_call, struct trace_uprobe, tp.call);
 
-       kfree(tu->tp.call.print_fmt);
-       tu->tp.call.print_fmt = NULL;
-
        free_trace_uprobe(tu);
 }
 #endif /* CONFIG_PERF_EVENTS */
index df3ade1..73956ea 100644 (file)
@@ -55,8 +55,8 @@ struct tp_probes {
 
 static inline void *allocate_probes(int count)
 {
-       struct tp_probes *p  = kmalloc(count * sizeof(struct tracepoint_func)
-                       + sizeof(struct tp_probes), GFP_KERNEL);
+       struct tp_probes *p  = kmalloc(struct_size(p, probes, count),
+                                      GFP_KERNEL);
        return p == NULL ? NULL : p->probes;
 }
 
index feb128c..a53cc2b 100644 (file)
@@ -52,16 +52,14 @@ static struct ctl_table_root set_root = {
        .permissions = set_permissions,
 };
 
-static int zero = 0;
-static int int_max = INT_MAX;
 #define UCOUNT_ENTRY(name)                             \
        {                                               \
                .procname       = name,                 \
                .maxlen         = sizeof(int),          \
                .mode           = 0644,                 \
                .proc_handler   = proc_dointvec_minmax, \
-               .extra1         = &zero,                \
-               .extra2         = &int_max,             \
+               .extra1         = SYSCTL_ZERO,          \
+               .extra2         = SYSCTL_INT_MAX,       \
        }
 static struct ctl_table user_table[] = {
        UCOUNT_ENTRY("max_user_namespaces"),
index 52a7b2e..f33d66f 100644 (file)
@@ -531,14 +531,6 @@ config LRU_CACHE
 config CLZ_TAB
        bool
 
-config DDR
-       bool "JEDEC DDR data"
-       help
-         Data from JEDEC specs for DDR SDRAM memories,
-         particularly the AC timing parameters and addressing
-         information. This data is useful for drivers handling
-         DDR SDRAM controllers.
-
 config IRQ_POLL
        bool "IRQ polling library"
        help
index 4ac4ca2..5960e29 100644 (file)
@@ -353,23 +353,13 @@ config DEBUG_SECTION_MISMATCH
          which results in the code/data being placed in specific sections.
          The section mismatch analysis is always performed after a full
          kernel build, and enabling this option causes the following
-         additional steps to occur:
+         additional step to occur:
          - Add the option -fno-inline-functions-called-once to gcc commands.
            When inlining a function annotated with __init in a non-init
            function, we would lose the section information and thus
            the analysis would not catch the illegal reference.
            This option tells gcc to inline less (but it does result in
            a larger kernel).
-         - Run the section mismatch analysis for each module/built-in.a file.
-           When we run the section mismatch analysis on vmlinux.o, we
-           lose valuable information about where the mismatch was
-           introduced.
-           Running the analysis for each module/built-in.a file
-           tells where the mismatch happens much closer to the
-           source. The drawback is that the same mismatch is
-           reported at least twice.
-         - Enable verbose reporting from modpost in order to help resolve
-           the section mismatches that are reported.
 
 config SECTION_MISMATCH_WARN_ONLY
        bool "Make section mismatch errors non-fatal"
@@ -1139,7 +1129,7 @@ config PROVE_LOCKING
         the proof of observed correctness is also maintained for an
         arbitrary combination of these separate locking variants.
 
-        For more details, see Documentation/locking/lockdep-design.txt.
+        For more details, see Documentation/locking/lockdep-design.rst.
 
 config LOCK_STAT
        bool "Lock usage statistics"
@@ -1153,7 +1143,7 @@ config LOCK_STAT
        help
         This feature enables tracking lock contention points
 
-        For more details, see Documentation/locking/lockstat.txt
+        For more details, see Documentation/locking/lockstat.rst
 
         This also enables lock events required by "perf lock",
         subcommand of perf.
@@ -2076,6 +2066,14 @@ config TEST_STACKINIT
 
          If unsure, say N.
 
+config TEST_MEMINIT
+       tristate "Test heap/page initialization"
+       help
+         Test if the kernel is zero-initializing heap and page allocations.
+         This can be useful to test init_on_alloc and init_on_free features.
+
+         If unsure, say N.
+
 endif # RUNTIME_TESTING_MENU
 
 config MEMTEST
index fdd56bc..095601c 100644 (file)
@@ -92,6 +92,7 @@ obj-$(CONFIG_TEST_MEMCAT_P) += test_memcat_p.o
 obj-$(CONFIG_TEST_OBJAGG) += test_objagg.o
 obj-$(CONFIG_TEST_STACKINIT) += test_stackinit.o
 obj-$(CONFIG_TEST_BLACKHOLE_DEV) += test_blackhole_dev.o
+obj-$(CONFIG_TEST_MEMINIT) += test_meminit.o
 
 obj-$(CONFIG_TEST_LIVEPATCH) += livepatch/
 
@@ -208,8 +209,6 @@ obj-$(CONFIG_SIGNATURE) += digsig.o
 
 lib-$(CONFIG_CLZ_TAB) += clz_tab.o
 
-obj-$(CONFIG_DDR) += jedec_ddr_data.o
-
 obj-$(CONFIG_GENERIC_STRNCPY_FROM_USER) += strncpy_from_user.o
 obj-$(CONFIG_GENERIC_STRNLEN_USER) += strnlen_user.o
 
index 0632136..0a2ffad 100644 (file)
@@ -30,6 +30,8 @@ early_param("nohugeiomap", set_nohugeiomap);
 void __init ioremap_huge_init(void)
 {
        if (!ioremap_huge_disabled) {
+               if (arch_ioremap_p4d_supported())
+                       ioremap_p4d_capable = 1;
                if (arch_ioremap_pud_supported())
                        ioremap_pud_capable = 1;
                if (arch_ioremap_pmd_supported())
@@ -86,6 +88,9 @@ static int ioremap_try_huge_pmd(pmd_t *pmd, unsigned long addr,
        if ((end - addr) != PMD_SIZE)
                return 0;
 
+       if (!IS_ALIGNED(addr, PMD_SIZE))
+               return 0;
+
        if (!IS_ALIGNED(phys_addr, PMD_SIZE))
                return 0;
 
@@ -126,6 +131,9 @@ static int ioremap_try_huge_pud(pud_t *pud, unsigned long addr,
        if ((end - addr) != PUD_SIZE)
                return 0;
 
+       if (!IS_ALIGNED(addr, PUD_SIZE))
+               return 0;
+
        if (!IS_ALIGNED(phys_addr, PUD_SIZE))
                return 0;
 
@@ -166,6 +174,9 @@ static int ioremap_try_huge_p4d(p4d_t *p4d, unsigned long addr,
        if ((end - addr) != P4D_SIZE)
                return 0;
 
+       if (!IS_ALIGNED(addr, P4D_SIZE))
+               return 0;
+
        if (!IS_ALIGNED(phys_addr, P4D_SIZE))
                return 0;
 
diff --git a/lib/jedec_ddr_data.c b/lib/jedec_ddr_data.c
deleted file mode 100644 (file)
index d0b312e..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * DDR addressing details and AC timing parameters from JEDEC specs
- *
- * Copyright (C) 2012 Texas Instruments, Inc.
- *
- * Aneesh V <aneesh@ti.com>
- */
-
-#include <memory/jedec_ddr.h>
-#include <linux/module.h>
-
-/* LPDDR2 addressing details from JESD209-2 section 2.4 */
-const struct lpddr2_addressing
-       lpddr2_jedec_addressing_table[NUM_DDR_ADDR_TABLE_ENTRIES] = {
-       {B4, T_REFI_15_6, T_RFC_90}, /* 64M */
-       {B4, T_REFI_15_6, T_RFC_90}, /* 128M */
-       {B4, T_REFI_7_8,  T_RFC_90}, /* 256M */
-       {B4, T_REFI_7_8,  T_RFC_90}, /* 512M */
-       {B8, T_REFI_7_8, T_RFC_130}, /* 1GS4 */
-       {B8, T_REFI_3_9, T_RFC_130}, /* 2GS4 */
-       {B8, T_REFI_3_9, T_RFC_130}, /* 4G */
-       {B8, T_REFI_3_9, T_RFC_210}, /* 8G */
-       {B4, T_REFI_7_8, T_RFC_130}, /* 1GS2 */
-       {B4, T_REFI_3_9, T_RFC_130}, /* 2GS2 */
-};
-EXPORT_SYMBOL_GPL(lpddr2_jedec_addressing_table);
-
-/* LPDDR2 AC timing parameters from JESD209-2 section 12 */
-const struct lpddr2_timings
-       lpddr2_jedec_timings[NUM_DDR_TIMING_TABLE_ENTRIES] = {
-       /* Speed bin 400(200 MHz) */
-       [0] = {
-               .max_freq       = 200000000,
-               .min_freq       = 10000000,
-               .tRPab          = 21000,
-               .tRCD           = 18000,
-               .tWR            = 15000,
-               .tRAS_min       = 42000,
-               .tRRD           = 10000,
-               .tWTR           = 10000,
-               .tXP            = 7500,
-               .tRTP           = 7500,
-               .tCKESR         = 15000,
-               .tDQSCK_max     = 5500,
-               .tFAW           = 50000,
-               .tZQCS          = 90000,
-               .tZQCL          = 360000,
-               .tZQinit        = 1000000,
-               .tRAS_max_ns    = 70000,
-               .tDQSCK_max_derated = 6000,
-       },
-       /* Speed bin 533(266 MHz) */
-       [1] = {
-               .max_freq       = 266666666,
-               .min_freq       = 10000000,
-               .tRPab          = 21000,
-               .tRCD           = 18000,
-               .tWR            = 15000,
-               .tRAS_min       = 42000,
-               .tRRD           = 10000,
-               .tWTR           = 7500,
-               .tXP            = 7500,
-               .tRTP           = 7500,
-               .tCKESR         = 15000,
-               .tDQSCK_max     = 5500,
-               .tFAW           = 50000,
-               .tZQCS          = 90000,
-               .tZQCL          = 360000,
-               .tZQinit        = 1000000,
-               .tRAS_max_ns    = 70000,
-               .tDQSCK_max_derated = 6000,
-       },
-       /* Speed bin 800(400 MHz) */
-       [2] = {
-               .max_freq       = 400000000,
-               .min_freq       = 10000000,
-               .tRPab          = 21000,
-               .tRCD           = 18000,
-               .tWR            = 15000,
-               .tRAS_min       = 42000,
-               .tRRD           = 10000,
-               .tWTR           = 7500,
-               .tXP            = 7500,
-               .tRTP           = 7500,
-               .tCKESR         = 15000,
-               .tDQSCK_max     = 5500,
-               .tFAW           = 50000,
-               .tZQCS          = 90000,
-               .tZQCL          = 360000,
-               .tZQinit        = 1000000,
-               .tRAS_max_ns    = 70000,
-               .tDQSCK_max_derated = 6000,
-       },
-       /* Speed bin 1066(533 MHz) */
-       [3] = {
-               .max_freq       = 533333333,
-               .min_freq       = 10000000,
-               .tRPab          = 21000,
-               .tRCD           = 18000,
-               .tWR            = 15000,
-               .tRAS_min       = 42000,
-               .tRRD           = 10000,
-               .tWTR           = 7500,
-               .tXP            = 7500,
-               .tRTP           = 7500,
-               .tCKESR         = 15000,
-               .tDQSCK_max     = 5500,
-               .tFAW           = 50000,
-               .tZQCS          = 90000,
-               .tZQCL          = 360000,
-               .tZQinit        = 1000000,
-               .tRAS_max_ns    = 70000,
-               .tDQSCK_max_derated = 5620,
-       },
-};
-EXPORT_SYMBOL_GPL(lpddr2_jedec_timings);
-
-const struct lpddr2_min_tck lpddr2_jedec_min_tck = {
-       .tRPab          = 3,
-       .tRCD           = 3,
-       .tWR            = 3,
-       .tRASmin        = 3,
-       .tRRD           = 2,
-       .tWTR           = 2,
-       .tXP            = 2,
-       .tRTP           = 2,
-       .tCKE           = 3,
-       .tCKESR         = 3,
-       .tFAW           = 8
-};
-EXPORT_SYMBOL_GPL(lpddr2_jedec_min_tck);
index 08c60d1..3bb6260 100644 (file)
@@ -397,8 +397,8 @@ do { \
 #define add_ssaaaa(sh, sl, ah, al, bh, bl) \
        __asm__ ("addl %5,%1\n" \
           "adcl %3,%0" \
-       : "=r" ((USItype)(sh)), \
-            "=&r" ((USItype)(sl)) \
+       : "=r" (sh), \
+            "=&r" (sl) \
        : "%0" ((USItype)(ah)), \
             "g" ((USItype)(bh)), \
             "%1" ((USItype)(al)), \
@@ -406,22 +406,22 @@ do { \
 #define sub_ddmmss(sh, sl, ah, al, bh, bl) \
        __asm__ ("subl %5,%1\n" \
           "sbbl %3,%0" \
-       : "=r" ((USItype)(sh)), \
-            "=&r" ((USItype)(sl)) \
+       : "=r" (sh), \
+            "=&r" (sl) \
        : "0" ((USItype)(ah)), \
             "g" ((USItype)(bh)), \
             "1" ((USItype)(al)), \
             "g" ((USItype)(bl)))
 #define umul_ppmm(w1, w0, u, v) \
        __asm__ ("mull %3" \
-       : "=a" ((USItype)(w0)), \
-            "=d" ((USItype)(w1)) \
+       : "=a" (w0), \
+            "=d" (w1) \
        : "%0" ((USItype)(u)), \
             "rm" ((USItype)(v)))
 #define udiv_qrnnd(q, r, n1, n0, d) \
        __asm__ ("divl %4" \
-       : "=a" ((USItype)(q)), \
-            "=d" ((USItype)(r)) \
+       : "=a" (q), \
+            "=d" (r) \
        : "0" ((USItype)(n0)), \
             "1" ((USItype)(n1)), \
             "rm" ((USItype)(d)))
index 1ef6e25..abc86c6 100644 (file)
@@ -83,14 +83,10 @@ __rb_rotate_set_parents(struct rb_node *old, struct rb_node *new,
 
 static __always_inline void
 __rb_insert(struct rb_node *node, struct rb_root *root,
-           bool newleft, struct rb_node **leftmost,
            void (*augment_rotate)(struct rb_node *old, struct rb_node *new))
 {
        struct rb_node *parent = rb_red_parent(node), *gparent, *tmp;
 
-       if (newleft)
-               *leftmost = node;
-
        while (true) {
                /*
                 * Loop invariant: node is red.
@@ -437,38 +433,19 @@ static const struct rb_augment_callbacks dummy_callbacks = {
 
 void rb_insert_color(struct rb_node *node, struct rb_root *root)
 {
-       __rb_insert(node, root, false, NULL, dummy_rotate);
+       __rb_insert(node, root, dummy_rotate);
 }
 EXPORT_SYMBOL(rb_insert_color);
 
 void rb_erase(struct rb_node *node, struct rb_root *root)
 {
        struct rb_node *rebalance;
-       rebalance = __rb_erase_augmented(node, root,
-                                        NULL, &dummy_callbacks);
+       rebalance = __rb_erase_augmented(node, root, &dummy_callbacks);
        if (rebalance)
                ____rb_erase_color(rebalance, root, dummy_rotate);
 }
 EXPORT_SYMBOL(rb_erase);
 
-void rb_insert_color_cached(struct rb_node *node,
-                           struct rb_root_cached *root, bool leftmost)
-{
-       __rb_insert(node, &root->rb_root, leftmost,
-                   &root->rb_leftmost, dummy_rotate);
-}
-EXPORT_SYMBOL(rb_insert_color_cached);
-
-void rb_erase_cached(struct rb_node *node, struct rb_root_cached *root)
-{
-       struct rb_node *rebalance;
-       rebalance = __rb_erase_augmented(node, &root->rb_root,
-                                        &root->rb_leftmost, &dummy_callbacks);
-       if (rebalance)
-               ____rb_erase_color(rebalance, &root->rb_root, dummy_rotate);
-}
-EXPORT_SYMBOL(rb_erase_cached);
-
 /*
  * Augmented rbtree manipulation functions.
  *
@@ -477,10 +454,9 @@ EXPORT_SYMBOL(rb_erase_cached);
  */
 
 void __rb_insert_augmented(struct rb_node *node, struct rb_root *root,
-                          bool newleft, struct rb_node **leftmost,
        void (*augment_rotate)(struct rb_node *old, struct rb_node *new))
 {
-       __rb_insert(node, root, newleft, leftmost, augment_rotate);
+       __rb_insert(node, root, augment_rotate);
 }
 EXPORT_SYMBOL(__rb_insert_augmented);
 
@@ -591,16 +567,6 @@ void rb_replace_node(struct rb_node *victim, struct rb_node *new,
 }
 EXPORT_SYMBOL(rb_replace_node);
 
-void rb_replace_node_cached(struct rb_node *victim, struct rb_node *new,
-                           struct rb_root_cached *root)
-{
-       rb_replace_node(victim, new, &root->rb_root);
-
-       if (root->rb_leftmost == victim)
-               root->rb_leftmost = new;
-}
-EXPORT_SYMBOL(rb_replace_node_cached);
-
 void rb_replace_node_rcu(struct rb_node *victim, struct rb_node *new,
                         struct rb_root *root)
 {
index 6016eb3..461fb62 100644 (file)
@@ -400,6 +400,9 @@ EXPORT_SYMBOL(strncmp);
  * strchr - Find the first occurrence of a character in a string
  * @s: The string to be searched
  * @c: The character to search for
+ *
+ * Note that the %NUL-terminator is considered part of the string, and can
+ * be searched for.
  */
 char *strchr(const char *s, int c)
 {
@@ -453,12 +456,18 @@ EXPORT_SYMBOL(strrchr);
  * @s: The string to be searched
  * @count: The number of characters to be searched
  * @c: The character to search for
+ *
+ * Note that the %NUL-terminator is considered part of the string, and can
+ * be searched for.
  */
 char *strnchr(const char *s, size_t count, int c)
 {
-       for (; count-- && *s != '\0'; ++s)
+       while (count--) {
                if (*s == (char)c)
                        return (char *)s;
+               if (*s++ == '\0')
+                       break;
+       }
        return NULL;
 }
 EXPORT_SYMBOL(strnchr);
index 3a90a9e..963050c 100644 (file)
@@ -231,35 +231,36 @@ static bool unescape_special(char **src, char **dst)
  * @src:       source buffer (escaped)
  * @dst:       destination buffer (unescaped)
  * @size:      size of the destination buffer (0 to unlimit)
- * @flags:     combination of the flags (bitwise OR):
- *     %UNESCAPE_SPACE:
+ * @flags:     combination of the flags.
+ *
+ * Description:
+ * The function unquotes characters in the given string.
+ *
+ * Because the size of the output will be the same as or less than the size of
+ * the input, the transformation may be performed in place.
+ *
+ * Caller must provide valid source and destination pointers. Be aware that
+ * destination buffer will always be NULL-terminated. Source string must be
+ * NULL-terminated as well.  The supported flags are::
+ *
+ *     UNESCAPE_SPACE:
  *             '\f' - form feed
  *             '\n' - new line
  *             '\r' - carriage return
  *             '\t' - horizontal tab
  *             '\v' - vertical tab
- *     %UNESCAPE_OCTAL:
+ *     UNESCAPE_OCTAL:
  *             '\NNN' - byte with octal value NNN (1 to 3 digits)
- *     %UNESCAPE_HEX:
+ *     UNESCAPE_HEX:
  *             '\xHH' - byte with hexadecimal value HH (1 to 2 digits)
- *     %UNESCAPE_SPECIAL:
+ *     UNESCAPE_SPECIAL:
  *             '\"' - double quote
  *             '\\' - backslash
  *             '\a' - alert (BEL)
  *             '\e' - escape
- *     %UNESCAPE_ANY:
+ *     UNESCAPE_ANY:
  *             all previous together
  *
- * Description:
- * The function unquotes characters in the given string.
- *
- * Because the size of the output will be the same as or less than the size of
- * the input, the transformation may be performed in place.
- *
- * Caller must provide valid source and destination pointers. Be aware that
- * destination buffer will always be NULL-terminated. Source string must be
- * NULL-terminated as well.
- *
  * Return:
  * The amount of the characters processed to the destination buffer excluding
  * trailing '\0' is returned.
@@ -441,7 +442,29 @@ static bool escape_hex(unsigned char c, char **dst, char *end)
  * @isz:       source buffer size
  * @dst:       destination buffer (escaped)
  * @osz:       destination buffer size
- * @flags:     combination of the flags (bitwise OR):
+ * @flags:     combination of the flags
+ * @only:      NULL-terminated string containing characters used to limit
+ *             the selected escape class. If characters are included in @only
+ *             that would not normally be escaped by the classes selected
+ *             in @flags, they will be copied to @dst unescaped.
+ *
+ * Description:
+ * The process of escaping byte buffer includes several parts. They are applied
+ * in the following sequence.
+ *
+ *     1. The character is matched to the printable class, if asked, and in
+ *        case of match it passes through to the output.
+ *     2. The character is not matched to the one from @only string and thus
+ *        must go as-is to the output.
+ *     3. The character is checked if it falls into the class given by @flags.
+ *        %ESCAPE_OCTAL and %ESCAPE_HEX are going last since they cover any
+ *        character. Note that they actually can't go together, otherwise
+ *        %ESCAPE_HEX will be ignored.
+ *
+ * Caller must provide valid source and destination pointers. Be aware that
+ * destination buffer will not be NULL-terminated, thus caller have to append
+ * it if needs.   The supported flags are::
+ *
  *     %ESCAPE_SPACE: (special white space, not space itself)
  *             '\f' - form feed
  *             '\n' - new line
@@ -464,26 +487,6 @@ static bool escape_hex(unsigned char c, char **dst, char *end)
  *             all previous together
  *     %ESCAPE_HEX:
  *             '\xHH' - byte with hexadecimal value HH (2 digits)
- * @only:      NULL-terminated string containing characters used to limit
- *             the selected escape class. If characters are included in @only
- *             that would not normally be escaped by the classes selected
- *             in @flags, they will be copied to @dst unescaped.
- *
- * Description:
- * The process of escaping byte buffer includes several parts. They are applied
- * in the following sequence.
- *     1. The character is matched to the printable class, if asked, and in
- *        case of match it passes through to the output.
- *     2. The character is not matched to the one from @only string and thus
- *        must go as-is to the output.
- *     3. The character is checked if it falls into the class given by @flags.
- *        %ESCAPE_OCTAL and %ESCAPE_HEX are going last since they cover any
- *        character. Note that they actually can't go together, otherwise
- *        %ESCAPE_HEX will be ignored.
- *
- * Caller must provide valid source and destination pointers. Be aware that
- * destination buffer will not be NULL-terminated, thus caller have to append
- * it if needs.
  *
  * Return:
  * The total size of the escaped output that would be generated for
diff --git a/lib/test_meminit.c b/lib/test_meminit.c
new file mode 100644 (file)
index 0000000..62d19f2
--- /dev/null
@@ -0,0 +1,364 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Test cases for SL[AOU]B/page initialization at alloc/free time.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+
+#define GARBAGE_INT (0x09A7BA9E)
+#define GARBAGE_BYTE (0x9E)
+
+#define REPORT_FAILURES_IN_FN() \
+       do {    \
+               if (failures)   \
+                       pr_info("%s failed %d out of %d times\n",       \
+                               __func__, failures, num_tests);         \
+               else            \
+                       pr_info("all %d tests in %s passed\n",          \
+                               num_tests, __func__);                   \
+       } while (0)
+
+/* Calculate the number of uninitialized bytes in the buffer. */
+static int __init count_nonzero_bytes(void *ptr, size_t size)
+{
+       int i, ret = 0;
+       unsigned char *p = (unsigned char *)ptr;
+
+       for (i = 0; i < size; i++)
+               if (p[i])
+                       ret++;
+       return ret;
+}
+
+/* Fill a buffer with garbage, skipping |skip| first bytes. */
+static void __init fill_with_garbage_skip(void *ptr, int size, size_t skip)
+{
+       unsigned int *p = (unsigned int *)((char *)ptr + skip);
+       int i = 0;
+
+       WARN_ON(skip > size);
+       size -= skip;
+
+       while (size >= sizeof(*p)) {
+               p[i] = GARBAGE_INT;
+               i++;
+               size -= sizeof(*p);
+       }
+       if (size)
+               memset(&p[i], GARBAGE_BYTE, size);
+}
+
+static void __init fill_with_garbage(void *ptr, size_t size)
+{
+       fill_with_garbage_skip(ptr, size, 0);
+}
+
+static int __init do_alloc_pages_order(int order, int *total_failures)
+{
+       struct page *page;
+       void *buf;
+       size_t size = PAGE_SIZE << order;
+
+       page = alloc_pages(GFP_KERNEL, order);
+       buf = page_address(page);
+       fill_with_garbage(buf, size);
+       __free_pages(page, order);
+
+       page = alloc_pages(GFP_KERNEL, order);
+       buf = page_address(page);
+       if (count_nonzero_bytes(buf, size))
+               (*total_failures)++;
+       fill_with_garbage(buf, size);
+       __free_pages(page, order);
+       return 1;
+}
+
+/* Test the page allocator by calling alloc_pages with different orders. */
+static int __init test_pages(int *total_failures)
+{
+       int failures = 0, num_tests = 0;
+       int i;
+
+       for (i = 0; i < 10; i++)
+               num_tests += do_alloc_pages_order(i, &failures);
+
+       REPORT_FAILURES_IN_FN();
+       *total_failures += failures;
+       return num_tests;
+}
+
+/* Test kmalloc() with given parameters. */
+static int __init do_kmalloc_size(size_t size, int *total_failures)
+{
+       void *buf;
+
+       buf = kmalloc(size, GFP_KERNEL);
+       fill_with_garbage(buf, size);
+       kfree(buf);
+
+       buf = kmalloc(size, GFP_KERNEL);
+       if (count_nonzero_bytes(buf, size))
+               (*total_failures)++;
+       fill_with_garbage(buf, size);
+       kfree(buf);
+       return 1;
+}
+
+/* Test vmalloc() with given parameters. */
+static int __init do_vmalloc_size(size_t size, int *total_failures)
+{
+       void *buf;
+
+       buf = vmalloc(size);
+       fill_with_garbage(buf, size);
+       vfree(buf);
+
+       buf = vmalloc(size);
+       if (count_nonzero_bytes(buf, size))
+               (*total_failures)++;
+       fill_with_garbage(buf, size);
+       vfree(buf);
+       return 1;
+}
+
+/* Test kmalloc()/vmalloc() by allocating objects of different sizes. */
+static int __init test_kvmalloc(int *total_failures)
+{
+       int failures = 0, num_tests = 0;
+       int i, size;
+
+       for (i = 0; i < 20; i++) {
+               size = 1 << i;
+               num_tests += do_kmalloc_size(size, &failures);
+               num_tests += do_vmalloc_size(size, &failures);
+       }
+
+       REPORT_FAILURES_IN_FN();
+       *total_failures += failures;
+       return num_tests;
+}
+
+#define CTOR_BYTES (sizeof(unsigned int))
+#define CTOR_PATTERN (0x41414141)
+/* Initialize the first 4 bytes of the object. */
+static void test_ctor(void *obj)
+{
+       *(unsigned int *)obj = CTOR_PATTERN;
+}
+
+/*
+ * Check the invariants for the buffer allocated from a slab cache.
+ * If the cache has a test constructor, the first 4 bytes of the object must
+ * always remain equal to CTOR_PATTERN.
+ * If the cache isn't an RCU-typesafe one, or if the allocation is done with
+ * __GFP_ZERO, then the object contents must be zeroed after allocation.
+ * If the cache is an RCU-typesafe one, the object contents must never be
+ * zeroed after the first use. This is checked by memcmp() in
+ * do_kmem_cache_size().
+ */
+static bool __init check_buf(void *buf, int size, bool want_ctor,
+                            bool want_rcu, bool want_zero)
+{
+       int bytes;
+       bool fail = false;
+
+       bytes = count_nonzero_bytes(buf, size);
+       WARN_ON(want_ctor && want_zero);
+       if (want_zero)
+               return bytes;
+       if (want_ctor) {
+               if (*(unsigned int *)buf != CTOR_PATTERN)
+                       fail = 1;
+       } else {
+               if (bytes)
+                       fail = !want_rcu;
+       }
+       return fail;
+}
+
+/*
+ * Test kmem_cache with given parameters:
+ *  want_ctor - use a constructor;
+ *  want_rcu - use SLAB_TYPESAFE_BY_RCU;
+ *  want_zero - use __GFP_ZERO.
+ */
+static int __init do_kmem_cache_size(size_t size, bool want_ctor,
+                                    bool want_rcu, bool want_zero,
+                                    int *total_failures)
+{
+       struct kmem_cache *c;
+       int iter;
+       bool fail = false;
+       gfp_t alloc_mask = GFP_KERNEL | (want_zero ? __GFP_ZERO : 0);
+       void *buf, *buf_copy;
+
+       c = kmem_cache_create("test_cache", size, 1,
+                             want_rcu ? SLAB_TYPESAFE_BY_RCU : 0,
+                             want_ctor ? test_ctor : NULL);
+       for (iter = 0; iter < 10; iter++) {
+               buf = kmem_cache_alloc(c, alloc_mask);
+               /* Check that buf is zeroed, if it must be. */
+               fail = check_buf(buf, size, want_ctor, want_rcu, want_zero);
+               fill_with_garbage_skip(buf, size, want_ctor ? CTOR_BYTES : 0);
+
+               if (!want_rcu) {
+                       kmem_cache_free(c, buf);
+                       continue;
+               }
+
+               /*
+                * If this is an RCU cache, use a critical section to ensure we
+                * can touch objects after they're freed.
+                */
+               rcu_read_lock();
+               /*
+                * Copy the buffer to check that it's not wiped on
+                * free().
+                */
+               buf_copy = kmalloc(size, GFP_KERNEL);
+               if (buf_copy)
+                       memcpy(buf_copy, buf, size);
+
+               kmem_cache_free(c, buf);
+               /*
+                * Check that |buf| is intact after kmem_cache_free().
+                * |want_zero| is false, because we wrote garbage to
+                * the buffer already.
+                */
+               fail |= check_buf(buf, size, want_ctor, want_rcu,
+                                 false);
+               if (buf_copy) {
+                       fail |= (bool)memcmp(buf, buf_copy, size);
+                       kfree(buf_copy);
+               }
+               rcu_read_unlock();
+       }
+       kmem_cache_destroy(c);
+
+       *total_failures += fail;
+       return 1;
+}
+
+/*
+ * Check that the data written to an RCU-allocated object survives
+ * reallocation.
+ */
+static int __init do_kmem_cache_rcu_persistent(int size, int *total_failures)
+{
+       struct kmem_cache *c;
+       void *buf, *buf_contents, *saved_ptr;
+       void **used_objects;
+       int i, iter, maxiter = 1024;
+       bool fail = false;
+
+       c = kmem_cache_create("test_cache", size, size, SLAB_TYPESAFE_BY_RCU,
+                             NULL);
+       buf = kmem_cache_alloc(c, GFP_KERNEL);
+       saved_ptr = buf;
+       fill_with_garbage(buf, size);
+       buf_contents = kmalloc(size, GFP_KERNEL);
+       if (!buf_contents)
+               goto out;
+       used_objects = kmalloc_array(maxiter, sizeof(void *), GFP_KERNEL);
+       if (!used_objects) {
+               kfree(buf_contents);
+               goto out;
+       }
+       memcpy(buf_contents, buf, size);
+       kmem_cache_free(c, buf);
+       /*
+        * Run for a fixed number of iterations. If we never hit saved_ptr,
+        * assume the test passes.
+        */
+       for (iter = 0; iter < maxiter; iter++) {
+               buf = kmem_cache_alloc(c, GFP_KERNEL);
+               used_objects[iter] = buf;
+               if (buf == saved_ptr) {
+                       fail = memcmp(buf_contents, buf, size);
+                       for (i = 0; i <= iter; i++)
+                               kmem_cache_free(c, used_objects[i]);
+                       goto free_out;
+               }
+       }
+
+free_out:
+       kmem_cache_destroy(c);
+       kfree(buf_contents);
+       kfree(used_objects);
+out:
+       *total_failures += fail;
+       return 1;
+}
+
+/*
+ * Test kmem_cache allocation by creating caches of different sizes, with and
+ * without constructors, with and without SLAB_TYPESAFE_BY_RCU.
+ */
+static int __init test_kmemcache(int *total_failures)
+{
+       int failures = 0, num_tests = 0;
+       int i, flags, size;
+       bool ctor, rcu, zero;
+
+       for (i = 0; i < 10; i++) {
+               size = 8 << i;
+               for (flags = 0; flags < 8; flags++) {
+                       ctor = flags & 1;
+                       rcu = flags & 2;
+                       zero = flags & 4;
+                       if (ctor & zero)
+                               continue;
+                       num_tests += do_kmem_cache_size(size, ctor, rcu, zero,
+                                                       &failures);
+               }
+       }
+       REPORT_FAILURES_IN_FN();
+       *total_failures += failures;
+       return num_tests;
+}
+
+/* Test the behavior of SLAB_TYPESAFE_BY_RCU caches of different sizes. */
+static int __init test_rcu_persistent(int *total_failures)
+{
+       int failures = 0, num_tests = 0;
+       int i, size;
+
+       for (i = 0; i < 10; i++) {
+               size = 8 << i;
+               num_tests += do_kmem_cache_rcu_persistent(size, &failures);
+       }
+       REPORT_FAILURES_IN_FN();
+       *total_failures += failures;
+       return num_tests;
+}
+
+/*
+ * Run the tests. Each test function returns the number of executed tests and
+ * updates |failures| with the number of failed tests.
+ */
+static int __init test_meminit_init(void)
+{
+       int failures = 0, num_tests = 0;
+
+       num_tests += test_pages(&failures);
+       num_tests += test_kvmalloc(&failures);
+       num_tests += test_kmemcache(&failures);
+       num_tests += test_rcu_persistent(&failures);
+
+       if (failures == 0)
+               pr_info("all %d tests passed!\n", num_tests);
+       else
+               pr_info("failures: %d out of %d\n", failures, num_tests);
+
+       return failures ? -EINVAL : 0;
+}
+module_init(test_meminit_init);
+
+MODULE_LICENSE("GPL");
index fc68056..7a4b6f6 100644 (file)
@@ -486,16 +486,17 @@ static int __init test_overflow_shift(void)
  * Deal with the various forms of allocator arguments. See comments above
  * the DEFINE_TEST_ALLOC() instances for mapping of the "bits".
  */
-#define alloc010(alloc, arg, sz) alloc(sz, GFP_KERNEL)
-#define alloc011(alloc, arg, sz) alloc(sz, GFP_KERNEL, NUMA_NO_NODE)
+#define alloc_GFP               (GFP_KERNEL | __GFP_NOWARN)
+#define alloc010(alloc, arg, sz) alloc(sz, alloc_GFP)
+#define alloc011(alloc, arg, sz) alloc(sz, alloc_GFP, NUMA_NO_NODE)
 #define alloc000(alloc, arg, sz) alloc(sz)
 #define alloc001(alloc, arg, sz) alloc(sz, NUMA_NO_NODE)
-#define alloc110(alloc, arg, sz) alloc(arg, sz, GFP_KERNEL)
+#define alloc110(alloc, arg, sz) alloc(arg, sz, alloc_GFP)
 #define free0(free, arg, ptr)   free(ptr)
 #define free1(free, arg, ptr)   free(arg, ptr)
 
-/* Wrap around to 8K */
-#define TEST_SIZE              (9 << PAGE_SHIFT)
+/* Wrap around to 16K */
+#define TEST_SIZE              (5 * 4096)
 
 #define DEFINE_TEST_ALLOC(func, free_func, want_arg, want_gfp, want_node)\
 static int __init test_ ## func (void *arg)                            \
index bf8def0..7b31f4a 100644 (file)
@@ -36,7 +36,7 @@ static __init int memset16_selftest(void)
 fail:
        kfree(p);
        if (i < 256)
-               return (i << 24) | (j << 16) | k;
+               return (i << 24) | (j << 16) | k | 0x8000;
        return 0;
 }
 
@@ -72,7 +72,7 @@ static __init int memset32_selftest(void)
 fail:
        kfree(p);
        if (i < 256)
-               return (i << 24) | (j << 16) | k;
+               return (i << 24) | (j << 16) | k | 0x8000;
        return 0;
 }
 
@@ -108,7 +108,74 @@ static __init int memset64_selftest(void)
 fail:
        kfree(p);
        if (i < 256)
-               return (i << 24) | (j << 16) | k;
+               return (i << 24) | (j << 16) | k | 0x8000;
+       return 0;
+}
+
+static __init int strchr_selftest(void)
+{
+       const char *test_string = "abcdefghijkl";
+       const char *empty_string = "";
+       char *result;
+       int i;
+
+       for (i = 0; i < strlen(test_string) + 1; i++) {
+               result = strchr(test_string, test_string[i]);
+               if (result - test_string != i)
+                       return i + 'a';
+       }
+
+       result = strchr(empty_string, '\0');
+       if (result != empty_string)
+               return 0x101;
+
+       result = strchr(empty_string, 'a');
+       if (result)
+               return 0x102;
+
+       result = strchr(test_string, 'z');
+       if (result)
+               return 0x103;
+
+       return 0;
+}
+
+static __init int strnchr_selftest(void)
+{
+       const char *test_string = "abcdefghijkl";
+       const char *empty_string = "";
+       char *result;
+       int i, j;
+
+       for (i = 0; i < strlen(test_string) + 1; i++) {
+               for (j = 0; j < strlen(test_string) + 2; j++) {
+                       result = strnchr(test_string, j, test_string[i]);
+                       if (j <= i) {
+                               if (!result)
+                                       continue;
+                               return ((i + 'a') << 8) | j;
+                       }
+                       if (result - test_string != i)
+                               return ((i + 'a') << 8) | j;
+               }
+       }
+
+       result = strnchr(empty_string, 0, '\0');
+       if (result)
+               return 0x10001;
+
+       result = strnchr(empty_string, 1, '\0');
+       if (result != empty_string)
+               return 0x10002;
+
+       result = strnchr(empty_string, 1, 'a');
+       if (result)
+               return 0x10003;
+
+       result = strnchr(NULL, 0, '\0');
+       if (result)
+               return 0x10004;
+
        return 0;
 }
 
@@ -131,6 +198,16 @@ static __init int string_selftest_init(void)
        if (subtest)
                goto fail;
 
+       test = 4;
+       subtest = strchr_selftest();
+       if (subtest)
+               goto fail;
+
+       test = 5;
+       subtest = strnchr_selftest();
+       if (subtest)
+               goto fail;
+
        pr_info("String selftests succeeded\n");
        return 0;
 fail:
index 495d736..56cec63 100644 (file)
@@ -649,8 +649,7 @@ config IDLE_PAGE_TRACKING
          See Documentation/admin-guide/mm/idle_page_tracking.rst for
          more details.
 
-# arch_add_memory() comprehends device memory
-config ARCH_HAS_ZONE_DEVICE
+config ARCH_HAS_PTE_DEVMAP
        bool
 
 config ZONE_DEVICE
@@ -658,7 +657,7 @@ config ZONE_DEVICE
        depends on MEMORY_HOTPLUG
        depends on MEMORY_HOTREMOVE
        depends on SPARSEMEM_VMEMMAP
-       depends on ARCH_HAS_ZONE_DEVICE
+       depends on ARCH_HAS_PTE_DEVMAP
        select XARRAY_MULTI
 
        help
index 3340ef3..7fe0b83 100644 (file)
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -278,6 +278,12 @@ int __init cma_declare_contiguous(phys_addr_t base,
         */
        alignment = max(alignment,  (phys_addr_t)PAGE_SIZE <<
                          max_t(unsigned long, MAX_ORDER - 1, pageblock_order));
+       if (fixed && base & (alignment - 1)) {
+               ret = -EINVAL;
+               pr_err("Region at %pa must be aligned to %pa bytes\n",
+                       &base, &alignment);
+               goto err;
+       }
        base = ALIGN(base, alignment);
        size = ALIGN(size, alignment);
        limit &= ~(alignment - 1);
@@ -308,6 +314,13 @@ int __init cma_declare_contiguous(phys_addr_t base,
        if (limit == 0 || limit > memblock_end)
                limit = memblock_end;
 
+       if (base + size > limit) {
+               ret = -EINVAL;
+               pr_err("Size (%pa) of region at %pa exceeds limit (%pa)\n",
+                       &size, &base, &limit);
+               goto err;
+       }
+
        /* Reserve memory */
        if (fixed) {
                if (memblock_is_region_reserved(base, size) ||
@@ -494,7 +507,7 @@ struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align,
  * @pages: Allocated pages.
  * @count: Number of allocated pages.
  *
- * This function releases memory allocated by alloc_cma().
+ * This function releases memory allocated by cma_alloc().
  * It returns false when provided pages do not belong to contiguous area and
  * true otherwise.
  */
index 8bbaa55..98f13ab 100644 (file)
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -1895,7 +1895,7 @@ static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end,
 }
 #endif /* CONFIG_ARCH_HAS_PTE_SPECIAL */
 
-#if defined(__HAVE_ARCH_PTE_DEVMAP) && defined(CONFIG_TRANSPARENT_HUGEPAGE)
+#if defined(CONFIG_ARCH_HAS_PTE_DEVMAP) && defined(CONFIG_TRANSPARENT_HUGEPAGE)
 static int __gup_device_huge(unsigned long pfn, unsigned long addr,
                unsigned long end, struct page **pages, int *nr)
 {
index 885642c..1334ede 100644 (file)
@@ -63,10 +63,15 @@ struct page *huge_zero_page __read_mostly;
 
 bool transparent_hugepage_enabled(struct vm_area_struct *vma)
 {
+       /* The addr is used to check if the vma size fits */
+       unsigned long addr = (vma->vm_end & HPAGE_PMD_MASK) - HPAGE_PMD_SIZE;
+
+       if (!transhuge_vma_suitable(vma, addr))
+               return false;
        if (vma_is_anonymous(vma))
                return __transparent_hugepage_enabled(vma);
-       if (vma_is_shmem(vma) && shmem_huge_enabled(vma))
-               return __transparent_hugepage_enabled(vma);
+       if (vma_is_shmem(vma))
+               return shmem_huge_enabled(vma);
 
        return false;
 }
@@ -689,7 +694,7 @@ vm_fault_t do_huge_pmd_anonymous_page(struct vm_fault *vmf)
        struct page *page;
        unsigned long haddr = vmf->address & HPAGE_PMD_MASK;
 
-       if (haddr < vma->vm_start || haddr + HPAGE_PMD_SIZE > vma->vm_end)
+       if (!transhuge_vma_suitable(vma, haddr))
                return VM_FAULT_FALLBACK;
        if (unlikely(anon_vma_prepare(vma)))
                return VM_FAULT_OOM;
index 482d4d6..d065736 100644 (file)
@@ -6,8 +6,20 @@
 #include <linux/mm.h>
 #include <linux/uaccess.h>
 
+static __always_inline long
+probe_read_common(void *dst, const void __user *src, size_t size)
+{
+       long ret;
+
+       pagefault_disable();
+       ret = __copy_from_user_inatomic(dst, src, size);
+       pagefault_enable();
+
+       return ret ? -EFAULT : 0;
+}
+
 /**
- * probe_kernel_read(): safely attempt to read from a location
+ * probe_kernel_read(): safely attempt to read from a kernel-space location
  * @dst: pointer to the buffer that shall take the data
  * @src: address to read from
  * @size: size of the data chunk
@@ -30,17 +42,41 @@ long __probe_kernel_read(void *dst, const void *src, size_t size)
        mm_segment_t old_fs = get_fs();
 
        set_fs(KERNEL_DS);
-       pagefault_disable();
-       ret = __copy_from_user_inatomic(dst,
-                       (__force const void __user *)src, size);
-       pagefault_enable();
+       ret = probe_read_common(dst, (__force const void __user *)src, size);
        set_fs(old_fs);
 
-       return ret ? -EFAULT : 0;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(probe_kernel_read);
 
 /**
+ * probe_user_read(): safely attempt to read from a user-space location
+ * @dst: pointer to the buffer that shall take the data
+ * @src: address to read from. This must be a user address.
+ * @size: size of the data chunk
+ *
+ * Safely read from user address @src to the buffer at @dst. If a kernel fault
+ * happens, handle that and return -EFAULT.
+ */
+
+long __weak probe_user_read(void *dst, const void __user *src, size_t size)
+    __attribute__((alias("__probe_user_read")));
+
+long __probe_user_read(void *dst, const void __user *src, size_t size)
+{
+       long ret = -EFAULT;
+       mm_segment_t old_fs = get_fs();
+
+       set_fs(USER_DS);
+       if (access_ok(src, size))
+               ret = probe_read_common(dst, src, size);
+       set_fs(old_fs);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(probe_user_read);
+
+/**
  * probe_kernel_write(): safely attempt to write to a location
  * @dst: address to write to
  * @src: pointer to the data that shall be written
@@ -67,6 +103,7 @@ long __probe_kernel_write(void *dst, const void *src, size_t size)
 }
 EXPORT_SYMBOL_GPL(probe_kernel_write);
 
+
 /**
  * strncpy_from_unsafe: - Copy a NUL terminated string from unsafe address.
  * @dst:   Destination address, in kernel space.  This buffer must be at
@@ -106,3 +143,76 @@ long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count)
 
        return ret ? -EFAULT : src - unsafe_addr;
 }
+
+/**
+ * strncpy_from_unsafe_user: - Copy a NUL terminated string from unsafe user
+ *                             address.
+ * @dst:   Destination address, in kernel space.  This buffer must be at
+ *         least @count bytes long.
+ * @unsafe_addr: Unsafe user address.
+ * @count: Maximum number of bytes to copy, including the trailing NUL.
+ *
+ * Copies a NUL-terminated string from unsafe user address to kernel buffer.
+ *
+ * On success, returns the length of the string INCLUDING the trailing NUL.
+ *
+ * If access fails, returns -EFAULT (some data may have been copied
+ * and the trailing NUL added).
+ *
+ * If @count is smaller than the length of the string, copies @count-1 bytes,
+ * sets the last byte of @dst buffer to NUL and returns @count.
+ */
+long strncpy_from_unsafe_user(char *dst, const void __user *unsafe_addr,
+                             long count)
+{
+       mm_segment_t old_fs = get_fs();
+       long ret;
+
+       if (unlikely(count <= 0))
+               return 0;
+
+       set_fs(USER_DS);
+       pagefault_disable();
+       ret = strncpy_from_user(dst, unsafe_addr, count);
+       pagefault_enable();
+       set_fs(old_fs);
+
+       if (ret >= count) {
+               ret = count;
+               dst[ret - 1] = '\0';
+       } else if (ret > 0) {
+               ret++;
+       }
+
+       return ret;
+}
+
+/**
+ * strnlen_unsafe_user: - Get the size of a user string INCLUDING final NUL.
+ * @unsafe_addr: The string to measure.
+ * @count: Maximum count (including NUL)
+ *
+ * Get the size of a NUL-terminated string in user space without pagefault.
+ *
+ * Returns the size of the string INCLUDING the terminating NUL.
+ *
+ * If the string is too long, returns a number larger than @count. User
+ * has to check the return value against "> count".
+ * On exception (or invalid count), returns 0.
+ *
+ * Unlike strnlen_user, this can be used from IRQ handler etc. because
+ * it disables pagefaults.
+ */
+long strnlen_unsafe_user(const void __user *unsafe_addr, long count)
+{
+       mm_segment_t old_fs = get_fs();
+       int ret;
+
+       set_fs(USER_DS);
+       pagefault_disable();
+       ret = strnlen_user(unsafe_addr, count);
+       pagefault_enable();
+       set_fs(old_fs);
+
+       return ret;
+}
index 2496718..cdbb7a8 100644 (file)
@@ -695,12 +695,15 @@ void __mod_memcg_state(struct mem_cgroup *memcg, int idx, int val)
        if (mem_cgroup_disabled())
                return;
 
-       __this_cpu_add(memcg->vmstats_local->stat[idx], val);
-
        x = val + __this_cpu_read(memcg->vmstats_percpu->stat[idx]);
        if (unlikely(abs(x) > MEMCG_CHARGE_BATCH)) {
                struct mem_cgroup *mi;
 
+               /*
+                * Batch local counters to keep them in sync with
+                * the hierarchical ones.
+                */
+               __this_cpu_add(memcg->vmstats_local->stat[idx], x);
                for (mi = memcg; mi; mi = parent_mem_cgroup(mi))
                        atomic_long_add(x, &mi->vmstats[idx]);
                x = 0;
@@ -749,13 +752,15 @@ void __mod_lruvec_state(struct lruvec *lruvec, enum node_stat_item idx,
        /* Update memcg */
        __mod_memcg_state(memcg, idx, val);
 
-       /* Update lruvec */
-       __this_cpu_add(pn->lruvec_stat_local->count[idx], val);
-
        x = val + __this_cpu_read(pn->lruvec_stat_cpu->count[idx]);
        if (unlikely(abs(x) > MEMCG_CHARGE_BATCH)) {
                struct mem_cgroup_per_node *pi;
 
+               /*
+                * Batch local counters to keep them in sync with
+                * the hierarchical ones.
+                */
+               __this_cpu_add(pn->lruvec_stat_local->count[idx], x);
                for (pi = pn; pi; pi = parent_nodeinfo(pi, pgdat->node_id))
                        atomic_long_add(x, &pi->lruvec_stat[idx]);
                x = 0;
@@ -777,12 +782,15 @@ void __count_memcg_events(struct mem_cgroup *memcg, enum vm_event_item idx,
        if (mem_cgroup_disabled())
                return;
 
-       __this_cpu_add(memcg->vmstats_local->events[idx], count);
-
        x = count + __this_cpu_read(memcg->vmstats_percpu->events[idx]);
        if (unlikely(x > MEMCG_CHARGE_BATCH)) {
                struct mem_cgroup *mi;
 
+               /*
+                * Batch local counters to keep them in sync with
+                * the hierarchical ones.
+                */
+               __this_cpu_add(memcg->vmstats_local->events[idx], x);
                for (mi = memcg; mi; mi = parent_mem_cgroup(mi))
                        atomic_long_add(x, &mi->vmevents[idx]);
                x = 0;
index 89325f9..e2bb51b 100644 (file)
@@ -3162,19 +3162,6 @@ map_pte:
 }
 
 #ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE
-
-#define HPAGE_CACHE_INDEX_MASK (HPAGE_PMD_NR - 1)
-static inline bool transhuge_vma_suitable(struct vm_area_struct *vma,
-               unsigned long haddr)
-{
-       if (((vma->vm_start >> PAGE_SHIFT) & HPAGE_CACHE_INDEX_MASK) !=
-                       (vma->vm_pgoff & HPAGE_CACHE_INDEX_MASK))
-               return false;
-       if (haddr < vma->vm_start || haddr + HPAGE_PMD_SIZE > vma->vm_end)
-               return false;
-       return true;
-}
-
 static void deposit_prealloc_pte(struct vm_fault *vmf)
 {
        struct vm_area_struct *vma = vmf->vma;
index 6166ba5..2a9bbdd 100644 (file)
@@ -166,9 +166,10 @@ void put_page_bootmem(struct page *page)
 #ifndef CONFIG_SPARSEMEM_VMEMMAP
 static void register_page_bootmem_info_section(unsigned long start_pfn)
 {
-       unsigned long *usemap, mapsize, section_nr, i;
+       unsigned long mapsize, section_nr, i;
        struct mem_section *ms;
        struct page *page, *memmap;
+       struct mem_section_usage *usage;
 
        section_nr = pfn_to_section_nr(start_pfn);
        ms = __nr_to_section(section_nr);
@@ -188,10 +189,10 @@ static void register_page_bootmem_info_section(unsigned long start_pfn)
        for (i = 0; i < mapsize; i++, page++)
                get_page_bootmem(section_nr, page, SECTION_INFO);
 
-       usemap = ms->pageblock_flags;
-       page = virt_to_page(usemap);
+       usage = ms->usage;
+       page = virt_to_page(usage);
 
-       mapsize = PAGE_ALIGN(usemap_size()) >> PAGE_SHIFT;
+       mapsize = PAGE_ALIGN(mem_section_usage_size()) >> PAGE_SHIFT;
 
        for (i = 0; i < mapsize; i++, page++)
                get_page_bootmem(section_nr, page, MIX_SECTION_INFO);
@@ -200,9 +201,10 @@ static void register_page_bootmem_info_section(unsigned long start_pfn)
 #else /* CONFIG_SPARSEMEM_VMEMMAP */
 static void register_page_bootmem_info_section(unsigned long start_pfn)
 {
-       unsigned long *usemap, mapsize, section_nr, i;
+       unsigned long mapsize, section_nr, i;
        struct mem_section *ms;
        struct page *page, *memmap;
+       struct mem_section_usage *usage;
 
        section_nr = pfn_to_section_nr(start_pfn);
        ms = __nr_to_section(section_nr);
@@ -211,10 +213,10 @@ static void register_page_bootmem_info_section(unsigned long start_pfn)
 
        register_page_bootmem_memmap(section_nr, memmap, PAGES_PER_SECTION);
 
-       usemap = ms->pageblock_flags;
-       page = virt_to_page(usemap);
+       usage = ms->usage;
+       page = virt_to_page(usage);
 
-       mapsize = PAGE_ALIGN(usemap_size()) >> PAGE_SHIFT;
+       mapsize = PAGE_ALIGN(mem_section_usage_size()) >> PAGE_SHIFT;
 
        for (i = 0; i < mapsize; i++, page++)
                get_page_bootmem(section_nr, page, MIX_SECTION_INFO);
@@ -250,22 +252,31 @@ void __init register_page_bootmem_info_node(struct pglist_data *pgdat)
 }
 #endif /* CONFIG_HAVE_BOOTMEM_INFO_NODE */
 
-static int __meminit __add_section(int nid, unsigned long phys_start_pfn,
-               struct vmem_altmap *altmap, bool want_memblock)
+static int check_pfn_span(unsigned long pfn, unsigned long nr_pages,
+               const char *reason)
 {
-       int ret;
-
-       if (pfn_valid(phys_start_pfn))
-               return -EEXIST;
-
-       ret = sparse_add_one_section(nid, phys_start_pfn, altmap);
-       if (ret < 0)
-               return ret;
-
-       if (!want_memblock)
-               return 0;
-
-       return hotplug_memory_register(nid, __pfn_to_section(phys_start_pfn));
+       /*
+        * Disallow all operations smaller than a sub-section and only
+        * allow operations smaller than a section for
+        * SPARSEMEM_VMEMMAP. Note that check_hotplug_memory_range()
+        * enforces a larger memory_block_size_bytes() granularity for
+        * memory that will be marked online, so this check should only
+        * fire for direct arch_{add,remove}_memory() users outside of
+        * add_memory_resource().
+        */
+       unsigned long min_align;
+
+       if (IS_ENABLED(CONFIG_SPARSEMEM_VMEMMAP))
+               min_align = PAGES_PER_SUBSECTION;
+       else
+               min_align = PAGES_PER_SECTION;
+       if (!IS_ALIGNED(pfn, min_align)
+                       || !IS_ALIGNED(nr_pages, min_align)) {
+               WARN(1, "Misaligned __%s_pages start: %#lx end: #%lx\n",
+                               reason, pfn, pfn + nr_pages - 1);
+               return -EINVAL;
+       }
+       return 0;
 }
 
 /*
@@ -274,62 +285,54 @@ static int __meminit __add_section(int nid, unsigned long phys_start_pfn,
  * call this function after deciding the zone to which to
  * add the new pages.
  */
-int __ref __add_pages(int nid, unsigned long phys_start_pfn,
-               unsigned long nr_pages, struct mhp_restrictions *restrictions)
+int __ref __add_pages(int nid, unsigned long pfn, unsigned long nr_pages,
+               struct mhp_restrictions *restrictions)
 {
-       unsigned long i;
-       int err = 0;
-       int start_sec, end_sec;
+       int err;
+       unsigned long nr, start_sec, end_sec;
        struct vmem_altmap *altmap = restrictions->altmap;
 
-       /* during initialize mem_map, align hot-added range to section */
-       start_sec = pfn_to_section_nr(phys_start_pfn);
-       end_sec = pfn_to_section_nr(phys_start_pfn + nr_pages - 1);
-
        if (altmap) {
                /*
                 * Validate altmap is within bounds of the total request
                 */
-               if (altmap->base_pfn != phys_start_pfn
+               if (altmap->base_pfn != pfn
                                || vmem_altmap_offset(altmap) > nr_pages) {
                        pr_warn_once("memory add fail, invalid altmap\n");
-                       err = -EINVAL;
-                       goto out;
+                       return -EINVAL;
                }
                altmap->alloc = 0;
        }
 
-       for (i = start_sec; i <= end_sec; i++) {
-               err = __add_section(nid, section_nr_to_pfn(i), altmap,
-                               restrictions->flags & MHP_MEMBLOCK_API);
+       err = check_pfn_span(pfn, nr_pages, "add");
+       if (err)
+               return err;
 
-               /*
-                * EEXIST is finally dealt with by ioresource collision
-                * check. see add_memory() => register_memory_resource()
-                * Warning will be printed if there is collision.
-                */
-               if (err && (err != -EEXIST))
+       start_sec = pfn_to_section_nr(pfn);
+       end_sec = pfn_to_section_nr(pfn + nr_pages - 1);
+       for (nr = start_sec; nr <= end_sec; nr++) {
+               unsigned long pfns;
+
+               pfns = min(nr_pages, PAGES_PER_SECTION
+                               - (pfn & ~PAGE_SECTION_MASK));
+               err = sparse_add_section(nid, pfn, pfns, altmap);
+               if (err)
                        break;
-               err = 0;
+               pfn += pfns;
+               nr_pages -= pfns;
                cond_resched();
        }
        vmemmap_populate_print_last();
-out:
        return err;
 }
 
-#ifdef CONFIG_MEMORY_HOTREMOVE
 /* find the smallest valid pfn in the range [start_pfn, end_pfn) */
 static unsigned long find_smallest_section_pfn(int nid, struct zone *zone,
                                     unsigned long start_pfn,
                                     unsigned long end_pfn)
 {
-       struct mem_section *ms;
-
-       for (; start_pfn < end_pfn; start_pfn += PAGES_PER_SECTION) {
-               ms = __pfn_to_section(start_pfn);
-
-               if (unlikely(!valid_section(ms)))
+       for (; start_pfn < end_pfn; start_pfn += PAGES_PER_SUBSECTION) {
+               if (unlikely(!pfn_valid(start_pfn)))
                        continue;
 
                if (unlikely(pfn_to_nid(start_pfn) != nid))
@@ -349,15 +352,12 @@ static unsigned long find_biggest_section_pfn(int nid, struct zone *zone,
                                    unsigned long start_pfn,
                                    unsigned long end_pfn)
 {
-       struct mem_section *ms;
        unsigned long pfn;
 
        /* pfn is the end pfn of a memory section. */
        pfn = end_pfn - 1;
-       for (; pfn >= start_pfn; pfn -= PAGES_PER_SECTION) {
-               ms = __pfn_to_section(pfn);
-
-               if (unlikely(!valid_section(ms)))
+       for (; pfn >= start_pfn; pfn -= PAGES_PER_SUBSECTION) {
+               if (unlikely(!pfn_valid(pfn)))
                        continue;
 
                if (unlikely(pfn_to_nid(pfn) != nid))
@@ -379,7 +379,6 @@ static void shrink_zone_span(struct zone *zone, unsigned long start_pfn,
        unsigned long z = zone_end_pfn(zone); /* zone_end_pfn namespace clash */
        unsigned long zone_end_pfn = z;
        unsigned long pfn;
-       struct mem_section *ms;
        int nid = zone_to_nid(zone);
 
        zone_span_writelock(zone);
@@ -416,17 +415,15 @@ static void shrink_zone_span(struct zone *zone, unsigned long start_pfn,
         * it check the zone has only hole or not.
         */
        pfn = zone_start_pfn;
-       for (; pfn < zone_end_pfn; pfn += PAGES_PER_SECTION) {
-               ms = __pfn_to_section(pfn);
-
-               if (unlikely(!valid_section(ms)))
+       for (; pfn < zone_end_pfn; pfn += PAGES_PER_SUBSECTION) {
+               if (unlikely(!pfn_valid(pfn)))
                        continue;
 
                if (page_zone(pfn_to_page(pfn)) != zone)
                        continue;
 
-                /* If the section is current section, it continues the loop */
-               if (start_pfn == pfn)
+               /* Skip range to be removed */
+               if (pfn >= start_pfn && pfn < end_pfn)
                        continue;
 
                /* If we find valid section, we have nothing to do */
@@ -447,7 +444,6 @@ static void shrink_pgdat_span(struct pglist_data *pgdat,
        unsigned long p = pgdat_end_pfn(pgdat); /* pgdat_end_pfn namespace clash */
        unsigned long pgdat_end_pfn = p;
        unsigned long pfn;
-       struct mem_section *ms;
        int nid = pgdat->node_id;
 
        if (pgdat_start_pfn == start_pfn) {
@@ -484,17 +480,15 @@ static void shrink_pgdat_span(struct pglist_data *pgdat,
         * has only hole or not.
         */
        pfn = pgdat_start_pfn;
-       for (; pfn < pgdat_end_pfn; pfn += PAGES_PER_SECTION) {
-               ms = __pfn_to_section(pfn);
-
-               if (unlikely(!valid_section(ms)))
+       for (; pfn < pgdat_end_pfn; pfn += PAGES_PER_SUBSECTION) {
+               if (unlikely(!pfn_valid(pfn)))
                        continue;
 
                if (pfn_to_nid(pfn) != nid)
                        continue;
 
-                /* If the section is current section, it continues the loop */
-               if (start_pfn == pfn)
+               /* Skip range to be removed */
+               if (pfn >= start_pfn && pfn < end_pfn)
                        continue;
 
                /* If we find valid section, we have nothing to do */
@@ -506,10 +500,10 @@ static void shrink_pgdat_span(struct pglist_data *pgdat,
        pgdat->node_spanned_pages = 0;
 }
 
-static void __remove_zone(struct zone *zone, unsigned long start_pfn)
+static void __remove_zone(struct zone *zone, unsigned long start_pfn,
+               unsigned long nr_pages)
 {
        struct pglist_data *pgdat = zone->zone_pgdat;
-       int nr_pages = PAGES_PER_SECTION;
        unsigned long flags;
 
        pgdat_resize_lock(zone->zone_pgdat, &flags);
@@ -518,29 +512,23 @@ static void __remove_zone(struct zone *zone, unsigned long start_pfn)
        pgdat_resize_unlock(zone->zone_pgdat, &flags);
 }
 
-static void __remove_section(struct zone *zone, struct mem_section *ms,
-                            unsigned long map_offset,
-                            struct vmem_altmap *altmap)
+static void __remove_section(struct zone *zone, unsigned long pfn,
+               unsigned long nr_pages, unsigned long map_offset,
+               struct vmem_altmap *altmap)
 {
-       unsigned long start_pfn;
-       int scn_nr;
+       struct mem_section *ms = __nr_to_section(pfn_to_section_nr(pfn));
 
        if (WARN_ON_ONCE(!valid_section(ms)))
                return;
 
-       unregister_memory_section(ms);
-
-       scn_nr = __section_nr(ms);
-       start_pfn = section_nr_to_pfn((unsigned long)scn_nr);
-       __remove_zone(zone, start_pfn);
-
-       sparse_remove_one_section(zone, ms, map_offset, altmap);
+       __remove_zone(zone, pfn, nr_pages);
+       sparse_remove_section(ms, pfn, nr_pages, map_offset, altmap);
 }
 
 /**
  * __remove_pages() - remove sections of pages from a zone
  * @zone: zone from which pages need to be removed
- * @phys_start_pfn: starting pageframe (must be aligned to start of a section)
+ * @pfn: starting pageframe (must be aligned to start of a section)
  * @nr_pages: number of pages to remove (must be multiple of section size)
  * @altmap: alternative device page map or %NULL if default memmap is used
  *
@@ -549,38 +537,35 @@ static void __remove_section(struct zone *zone, struct mem_section *ms,
  * sure that pages are marked reserved and zones are adjust properly by
  * calling offline_pages().
  */
-void __remove_pages(struct zone *zone, unsigned long phys_start_pfn,
+void __remove_pages(struct zone *zone, unsigned long pfn,
                    unsigned long nr_pages, struct vmem_altmap *altmap)
 {
-       unsigned long i;
        unsigned long map_offset = 0;
-       int sections_to_remove;
+       unsigned long nr, start_sec, end_sec;
 
-       /* In the ZONE_DEVICE case device driver owns the memory region */
-       if (is_dev_zone(zone))
-               map_offset = vmem_altmap_offset(altmap);
+       map_offset = vmem_altmap_offset(altmap);
 
        clear_zone_contiguous(zone);
 
-       /*
-        * We can only remove entire sections
-        */
-       BUG_ON(phys_start_pfn & ~PAGE_SECTION_MASK);
-       BUG_ON(nr_pages % PAGES_PER_SECTION);
+       if (check_pfn_span(pfn, nr_pages, "remove"))
+               return;
 
-       sections_to_remove = nr_pages / PAGES_PER_SECTION;
-       for (i = 0; i < sections_to_remove; i++) {
-               unsigned long pfn = phys_start_pfn + i*PAGES_PER_SECTION;
+       start_sec = pfn_to_section_nr(pfn);
+       end_sec = pfn_to_section_nr(pfn + nr_pages - 1);
+       for (nr = start_sec; nr <= end_sec; nr++) {
+               unsigned long pfns;
 
                cond_resched();
-               __remove_section(zone, __pfn_to_section(pfn), map_offset,
-                                altmap);
+               pfns = min(nr_pages, PAGES_PER_SECTION
+                               - (pfn & ~PAGE_SECTION_MASK));
+               __remove_section(zone, pfn, pfns, map_offset, altmap);
+               pfn += pfns;
+               nr_pages -= pfns;
                map_offset = 0;
        }
 
        set_zone_contiguous(zone);
 }
-#endif /* CONFIG_MEMORY_HOTREMOVE */
 
 int set_online_page_callback(online_page_callback_t callback)
 {
@@ -1049,16 +1034,11 @@ int try_online_node(int nid)
 
 static int check_hotplug_memory_range(u64 start, u64 size)
 {
-       unsigned long block_sz = memory_block_size_bytes();
-       u64 block_nr_pages = block_sz >> PAGE_SHIFT;
-       u64 nr_pages = size >> PAGE_SHIFT;
-       u64 start_pfn = PFN_DOWN(start);
-
        /* memory range must be block size aligned */
-       if (!nr_pages || !IS_ALIGNED(start_pfn, block_nr_pages) ||
-           !IS_ALIGNED(nr_pages, block_nr_pages)) {
+       if (!size || !IS_ALIGNED(start, memory_block_size_bytes()) ||
+           !IS_ALIGNED(size, memory_block_size_bytes())) {
                pr_err("Block size [%#lx] unaligned hotplug range: start %#llx, size %#llx",
-                      block_sz, start, size);
+                      memory_block_size_bytes(), start, size);
                return -EINVAL;
        }
 
@@ -1078,9 +1058,7 @@ static int online_memory_block(struct memory_block *mem, void *arg)
  */
 int __ref add_memory_resource(int nid, struct resource *res)
 {
-       struct mhp_restrictions restrictions = {
-               .flags = MHP_MEMBLOCK_API,
-       };
+       struct mhp_restrictions restrictions = {};
        u64 start, size;
        bool new_node = false;
        int ret;
@@ -1112,6 +1090,13 @@ int __ref add_memory_resource(int nid, struct resource *res)
        if (ret < 0)
                goto error;
 
+       /* create memory block devices after memory was added */
+       ret = create_memory_block_devices(start, size);
+       if (ret) {
+               arch_remove_memory(nid, start, size, NULL);
+               goto error;
+       }
+
        if (new_node) {
                /* If sysfs file of new node can't be created, cpu on the node
                 * can't be hot-added. There is no rollback way now.
@@ -1135,8 +1120,7 @@ int __ref add_memory_resource(int nid, struct resource *res)
 
        /* online pages if requested */
        if (memhp_auto_online)
-               walk_memory_range(PFN_DOWN(start), PFN_UP(start + size - 1),
-                                 NULL, online_memory_block);
+               walk_memory_blocks(start, size, NULL, online_memory_block);
 
        return ret;
 error:
@@ -1671,58 +1655,7 @@ int offline_pages(unsigned long start_pfn, unsigned long nr_pages)
 {
        return __offline_pages(start_pfn, start_pfn + nr_pages);
 }
-#endif /* CONFIG_MEMORY_HOTREMOVE */
-
-/**
- * walk_memory_range - walks through all mem sections in [start_pfn, end_pfn)
- * @start_pfn: start pfn of the memory range
- * @end_pfn: end pfn of the memory range
- * @arg: argument passed to func
- * @func: callback for each memory section walked
- *
- * This function walks through all present mem sections in range
- * [start_pfn, end_pfn) and call func on each mem section.
- *
- * Returns the return value of func.
- */
-int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn,
-               void *arg, int (*func)(struct memory_block *, void *))
-{
-       struct memory_block *mem = NULL;
-       struct mem_section *section;
-       unsigned long pfn, section_nr;
-       int ret;
-
-       for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
-               section_nr = pfn_to_section_nr(pfn);
-               if (!present_section_nr(section_nr))
-                       continue;
-
-               section = __nr_to_section(section_nr);
-               /* same memblock? */
-               if (mem)
-                       if ((section_nr >= mem->start_section_nr) &&
-                           (section_nr <= mem->end_section_nr))
-                               continue;
 
-               mem = find_memory_block_hinted(section, mem);
-               if (!mem)
-                       continue;
-
-               ret = func(mem, arg);
-               if (ret) {
-                       kobject_put(&mem->dev.kobj);
-                       return ret;
-               }
-       }
-
-       if (mem)
-               kobject_put(&mem->dev.kobj);
-
-       return 0;
-}
-
-#ifdef CONFIG_MEMORY_HOTREMOVE
 static int check_memblock_offlined_cb(struct memory_block *mem, void *arg)
 {
        int ret = !is_memblock_offlined(mem);
@@ -1734,9 +1667,10 @@ static int check_memblock_offlined_cb(struct memory_block *mem, void *arg)
                endpa = PFN_PHYS(section_nr_to_pfn(mem->end_section_nr + 1))-1;
                pr_warn("removing memory fails, because memory [%pa-%pa] is onlined\n",
                        &beginpa, &endpa);
-       }
 
-       return ret;
+               return -EBUSY;
+       }
+       return 0;
 }
 
 static int check_cpu_on_node(pg_data_t *pgdat)
@@ -1819,19 +1753,9 @@ static void __release_memory_resource(resource_size_t start,
        }
 }
 
-/**
- * remove_memory
- * @nid: the node ID
- * @start: physical address of the region to remove
- * @size: size of the region to remove
- *
- * NOTE: The caller must call lock_device_hotplug() to serialize hotplug
- * and online/offline operations before this call, as required by
- * try_offline_node().
- */
-void __ref __remove_memory(int nid, u64 start, u64 size)
+static int __ref try_remove_memory(int nid, u64 start, u64 size)
 {
-       int ret;
+       int rc = 0;
 
        BUG_ON(check_hotplug_memory_range(start, size));
 
@@ -1839,32 +1763,65 @@ void __ref __remove_memory(int nid, u64 start, u64 size)
 
        /*
         * All memory blocks must be offlined before removing memory.  Check
-        * whether all memory blocks in question are offline and trigger a BUG()
+        * whether all memory blocks in question are offline and return error
         * if this is not the case.
         */
-       ret = walk_memory_range(PFN_DOWN(start), PFN_UP(start + size - 1), NULL,
-                               check_memblock_offlined_cb);
-       if (ret)
-               BUG();
+       rc = walk_memory_blocks(start, size, NULL, check_memblock_offlined_cb);
+       if (rc)
+               goto done;
 
        /* remove memmap entry */
        firmware_map_remove(start, start + size, "System RAM");
        memblock_free(start, size);
        memblock_remove(start, size);
 
+       /* remove memory block devices before removing memory */
+       remove_memory_block_devices(start, size);
+
        arch_remove_memory(nid, start, size, NULL);
        __release_memory_resource(start, size);
 
        try_offline_node(nid);
 
+done:
        mem_hotplug_done();
+       return rc;
+}
+
+/**
+ * remove_memory
+ * @nid: the node ID
+ * @start: physical address of the region to remove
+ * @size: size of the region to remove
+ *
+ * NOTE: The caller must call lock_device_hotplug() to serialize hotplug
+ * and online/offline operations before this call, as required by
+ * try_offline_node().
+ */
+void __remove_memory(int nid, u64 start, u64 size)
+{
+
+       /*
+        * trigger BUG() is some memory is not offlined prior to calling this
+        * function
+        */
+       if (try_remove_memory(nid, start, size))
+               BUG();
 }
 
-void remove_memory(int nid, u64 start, u64 size)
+/*
+ * Remove memory if every memory block is offline, otherwise return -EBUSY is
+ * some memory is not offline
+ */
+int remove_memory(int nid, u64 start, u64 size)
 {
+       int rc;
+
        lock_device_hotplug();
-       __remove_memory(nid, start, size);
+       rc  = try_remove_memory(nid, start, size);
        unlock_device_hotplug();
+
+       return rc;
 }
 EXPORT_SYMBOL_GPL(remove_memory);
 #endif /* CONFIG_MEMORY_HOTREMOVE */
index 3445747..8992741 100644 (file)
@@ -394,8 +394,7 @@ static int expected_page_refs(struct address_space *mapping, struct page *page)
  * 3 for pages with a mapping and PagePrivate/PagePrivate2 set.
  */
 int migrate_page_move_mapping(struct address_space *mapping,
-               struct page *newpage, struct page *page, enum migrate_mode mode,
-               int extra_count)
+               struct page *newpage, struct page *page, int extra_count)
 {
        XA_STATE(xas, &mapping->i_pages, page_index(page));
        struct zone *oldzone, *newzone;
@@ -681,7 +680,7 @@ int migrate_page(struct address_space *mapping,
 
        BUG_ON(PageWriteback(page));    /* Writeback must be complete */
 
-       rc = migrate_page_move_mapping(mapping, newpage, page, mode, 0);
+       rc = migrate_page_move_mapping(mapping, newpage, page, 0);
 
        if (rc != MIGRATEPAGE_SUCCESS)
                return rc;
@@ -780,7 +779,7 @@ recheck_buffers:
                }
        }
 
-       rc = migrate_page_move_mapping(mapping, newpage, page, mode, 0);
+       rc = migrate_page_move_mapping(mapping, newpage, page, 0);
        if (rc != MIGRATEPAGE_SUCCESS)
                goto unlock_buffers;
 
index eb3e2e5..fed1b6e 100644 (file)
@@ -1261,7 +1261,9 @@ unsigned long do_mmap(struct file *file,
        add_nommu_region(region);
 
        /* clear anonymous mappings that don't ask for uninitialized data */
-       if (!vma->vm_file && !(flags & MAP_UNINITIALIZED))
+       if (!vma->vm_file &&
+           (!IS_ENABLED(CONFIG_MMAP_ALLOW_UNINITIALIZED) ||
+            !(flags & MAP_UNINITIALIZED)))
                memset((void *)region->vm_start, 0,
                       region->vm_end - region->vm_start);
 
index 8fd7f45..272c6de 100644 (file)
@@ -450,7 +450,7 @@ static inline unsigned long *get_pageblock_bitmap(struct page *page,
                                                        unsigned long pfn)
 {
 #ifdef CONFIG_SPARSEMEM
-       return __pfn_to_section(pfn)->pageblock_flags;
+       return section_to_usemap(__pfn_to_section(pfn));
 #else
        return page_zone(page)->pageblock_flags;
 #endif /* CONFIG_SPARSEMEM */
@@ -4102,7 +4102,6 @@ static int
 __perform_reclaim(gfp_t gfp_mask, unsigned int order,
                                        const struct alloc_context *ac)
 {
-       struct reclaim_state reclaim_state;
        int progress;
        unsigned int noreclaim_flag;
        unsigned long pflags;
@@ -4114,13 +4113,10 @@ __perform_reclaim(gfp_t gfp_mask, unsigned int order,
        psi_memstall_enter(&pflags);
        fs_reclaim_acquire(gfp_mask);
        noreclaim_flag = memalloc_noreclaim_save();
-       reclaim_state.reclaimed_slab = 0;
-       current->reclaim_state = &reclaim_state;
 
        progress = try_to_free_pages(ac->zonelist, order, gfp_mask,
                                                                ac->nodemask);
 
-       current->reclaim_state = NULL;
        memalloc_noreclaim_restore(noreclaim_flag);
        fs_reclaim_release(gfp_mask);
        psi_memstall_leave(&pflags);
@@ -5930,7 +5926,7 @@ void __ref memmap_init_zone_device(struct zone *zone,
        unsigned long start = jiffies;
        int nid = pgdat->node_id;
 
-       if (WARN_ON_ONCE(!pgmap || !is_dev_zone(zone)))
+       if (WARN_ON_ONCE(!pgmap || zone_idx(zone) != ZONE_DEVICE))
                return;
 
        /*
@@ -5978,7 +5974,7 @@ void __ref memmap_init_zone_device(struct zone *zone,
                 * pfn out of zone.
                 *
                 * Please note that MEMMAP_HOTPLUG path doesn't clear memmap
-                * because this is done early in sparse_add_one_section
+                * because this is done early in section_activate()
                 */
                if (!(pfn & (pageblock_nr_pages - 1))) {
                        set_pageblock_migratetype(page, MIGRATE_MOVABLE);
@@ -7355,12 +7351,18 @@ void __init free_area_init_nodes(unsigned long *max_zone_pfn)
                               (u64)zone_movable_pfn[i] << PAGE_SHIFT);
        }
 
-       /* Print out the early node map */
+       /*
+        * Print out the early node map, and initialize the
+        * subsection-map relative to active online memory ranges to
+        * enable future "sub-section" extensions of the memory map.
+        */
        pr_info("Early memory node ranges\n");
-       for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, &nid)
+       for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, &nid) {
                pr_info("  node %3d: [mem %#018Lx-%#018Lx]\n", nid,
                        (u64)start_pfn << PAGE_SHIFT,
                        ((u64)end_pfn << PAGE_SHIFT) - 1);
+               subsection_map_init(start_pfn, end_pfn - start_pfn);
+       }
 
        /* Initialise every node */
        mminit_verify_pageflags_layout();
index f4dce9c..626d8c7 100644 (file)
@@ -400,7 +400,7 @@ static bool shmem_confirm_swap(struct address_space *mapping,
 
 static int shmem_huge __read_mostly;
 
-#if defined(CONFIG_SYSFS) || defined(CONFIG_TMPFS)
+#if defined(CONFIG_SYSFS)
 static int shmem_parse_huge(const char *str)
 {
        if (!strcmp(str, "never"))
@@ -417,7 +417,9 @@ static int shmem_parse_huge(const char *str)
                return SHMEM_HUGE_FORCE;
        return -EINVAL;
 }
+#endif
 
+#if defined(CONFIG_SYSFS) || defined(CONFIG_TMPFS)
 static const char *shmem_format_huge(int huge)
 {
        switch (huge) {
@@ -3775,10 +3777,6 @@ int __init shmem_init(void)
 {
        int error;
 
-       /* If rootfs called this, don't re-init */
-       if (shmem_inode_cachep)
-               return 0;
-
        shmem_init_inodecache();
 
        error = register_filesystem(&shmem_fs_type);
@@ -3872,6 +3870,9 @@ bool shmem_huge_enabled(struct vm_area_struct *vma)
        loff_t i_size;
        pgoff_t off;
 
+       if ((vma->vm_flags & VM_NOHUGEPAGE) ||
+           test_bit(MMF_DISABLE_THP, &vma->vm_mm->flags))
+               return false;
        if (shmem_huge == SHMEM_HUGE_FORCE)
                return true;
        if (shmem_huge == SHMEM_HUGE_DENY)
index 6c49dbb..807490f 100644 (file)
@@ -1028,7 +1028,8 @@ struct kmem_cache *__init create_kmalloc_cache(const char *name,
 }
 
 struct kmem_cache *
-kmalloc_caches[NR_KMALLOC_TYPES][KMALLOC_SHIFT_HIGH + 1] __ro_after_init;
+kmalloc_caches[NR_KMALLOC_TYPES][KMALLOC_SHIFT_HIGH + 1] __ro_after_init =
+{ /* initialization for https://bugs.llvm.org/show_bug.cgi?id=42570 */ };
 EXPORT_SYMBOL(kmalloc_caches);
 
 /*
index 7fec057..200aef6 100644 (file)
@@ -245,19 +245,26 @@ int __meminit vmemmap_populate_basepages(unsigned long start,
        return 0;
 }
 
-struct page * __meminit sparse_mem_map_populate(unsigned long pnum, int nid,
-               struct vmem_altmap *altmap)
+struct page * __meminit __populate_section_memmap(unsigned long pfn,
+               unsigned long nr_pages, int nid, struct vmem_altmap *altmap)
 {
        unsigned long start;
        unsigned long end;
-       struct page *map;
 
-       map = pfn_to_page(pnum * PAGES_PER_SECTION);
-       start = (unsigned long)map;
-       end = (unsigned long)(map + PAGES_PER_SECTION);
+       /*
+        * The minimum granularity of memmap extensions is
+        * PAGES_PER_SUBSECTION as allocations are tracked in the
+        * 'subsection_map' bitmap of the section.
+        */
+       end = ALIGN(pfn + nr_pages, PAGES_PER_SUBSECTION);
+       pfn &= PAGE_SUBSECTION_MASK;
+       nr_pages = end - pfn;
+
+       start = (unsigned long) pfn_to_page(pfn);
+       end = start + nr_pages * sizeof(struct page);
 
        if (vmemmap_populate(start, end, nid, altmap))
                return NULL;
 
-       return map;
+       return pfn_to_page(pfn);
 }
index fd13166..72f010d 100644 (file)
@@ -83,8 +83,15 @@ static int __meminit sparse_index_init(unsigned long section_nr, int nid)
        unsigned long root = SECTION_NR_TO_ROOT(section_nr);
        struct mem_section *section;
 
+       /*
+        * An existing section is possible in the sub-section hotplug
+        * case. First hot-add instantiates, follow-on hot-add reuses
+        * the existing section.
+        *
+        * The mem_hotplug_lock resolves the apparent race below.
+        */
        if (mem_section[root])
-               return -EEXIST;
+               return 0;
 
        section = sparse_index_alloc(nid);
        if (!section)
@@ -102,7 +109,7 @@ static inline int sparse_index_init(unsigned long section_nr, int nid)
 #endif
 
 #ifdef CONFIG_SPARSEMEM_EXTREME
-int __section_nr(struct mem_section* ms)
+unsigned long __section_nr(struct mem_section *ms)
 {
        unsigned long root_nr;
        struct mem_section *root = NULL;
@@ -121,9 +128,9 @@ int __section_nr(struct mem_section* ms)
        return (root_nr * SECTIONS_PER_ROOT) + (ms - root);
 }
 #else
-int __section_nr(struct mem_section* ms)
+unsigned long __section_nr(struct mem_section *ms)
 {
-       return (int)(ms - mem_section[0]);
+       return (unsigned long)(ms - mem_section[0]);
 }
 #endif
 
@@ -178,10 +185,10 @@ void __meminit mminit_validate_memmodel_limits(unsigned long *start_pfn,
  * Keeping track of this gives us an easy way to break out of
  * those loops early.
  */
-int __highest_present_section_nr;
+unsigned long __highest_present_section_nr;
 static void section_mark_present(struct mem_section *ms)
 {
-       int section_nr = __section_nr(ms);
+       unsigned long section_nr = __section_nr(ms);
 
        if (section_nr > __highest_present_section_nr)
                __highest_present_section_nr = section_nr;
@@ -189,7 +196,7 @@ static void section_mark_present(struct mem_section *ms)
        ms->section_mem_map |= SECTION_MARKED_PRESENT;
 }
 
-static inline int next_present_section_nr(int section_nr)
+static inline unsigned long next_present_section_nr(unsigned long section_nr)
 {
        do {
                section_nr++;
@@ -210,6 +217,41 @@ static inline unsigned long first_present_section_nr(void)
        return next_present_section_nr(-1);
 }
 
+void subsection_mask_set(unsigned long *map, unsigned long pfn,
+               unsigned long nr_pages)
+{
+       int idx = subsection_map_index(pfn);
+       int end = subsection_map_index(pfn + nr_pages - 1);
+
+       bitmap_set(map, idx, end - idx + 1);
+}
+
+void __init subsection_map_init(unsigned long pfn, unsigned long nr_pages)
+{
+       int end_sec = pfn_to_section_nr(pfn + nr_pages - 1);
+       unsigned long nr, start_sec = pfn_to_section_nr(pfn);
+
+       if (!nr_pages)
+               return;
+
+       for (nr = start_sec; nr <= end_sec; nr++) {
+               struct mem_section *ms;
+               unsigned long pfns;
+
+               pfns = min(nr_pages, PAGES_PER_SECTION
+                               - (pfn & ~PAGE_SECTION_MASK));
+               ms = __nr_to_section(nr);
+               subsection_mask_set(ms->usage->subsection_map, pfn, pfns);
+
+               pr_debug("%s: sec: %lu pfns: %lu set(%d, %d)\n", __func__, nr,
+                               pfns, subsection_map_index(pfn),
+                               subsection_map_index(pfn + pfns - 1));
+
+               pfn += pfns;
+               nr_pages -= pfns;
+       }
+}
+
 /* Record a memory area against a node. */
 void __init memory_present(int nid, unsigned long start, unsigned long end)
 {
@@ -288,33 +330,31 @@ struct page *sparse_decode_mem_map(unsigned long coded_mem_map, unsigned long pn
 
 static void __meminit sparse_init_one_section(struct mem_section *ms,
                unsigned long pnum, struct page *mem_map,
-               unsigned long *pageblock_bitmap)
+               struct mem_section_usage *usage, unsigned long flags)
 {
        ms->section_mem_map &= ~SECTION_MAP_MASK;
-       ms->section_mem_map |= sparse_encode_mem_map(mem_map, pnum) |
-                                                       SECTION_HAS_MEM_MAP;
-       ms->pageblock_flags = pageblock_bitmap;
+       ms->section_mem_map |= sparse_encode_mem_map(mem_map, pnum)
+               | SECTION_HAS_MEM_MAP | flags;
+       ms->usage = usage;
 }
 
-unsigned long usemap_size(void)
+static unsigned long usemap_size(void)
 {
        return BITS_TO_LONGS(SECTION_BLOCKFLAGS_BITS) * sizeof(unsigned long);
 }
 
-#ifdef CONFIG_MEMORY_HOTPLUG
-static unsigned long *__kmalloc_section_usemap(void)
+size_t mem_section_usage_size(void)
 {
-       return kmalloc(usemap_size(), GFP_KERNEL);
+       return sizeof(struct mem_section_usage) + usemap_size();
 }
-#endif /* CONFIG_MEMORY_HOTPLUG */
 
 #ifdef CONFIG_MEMORY_HOTREMOVE
-static unsigned long * __init
+static struct mem_section_usage * __init
 sparse_early_usemaps_alloc_pgdat_section(struct pglist_data *pgdat,
                                         unsigned long size)
 {
+       struct mem_section_usage *usage;
        unsigned long goal, limit;
-       unsigned long *p;
        int nid;
        /*
         * A page may contain usemaps for other sections preventing the
@@ -330,15 +370,16 @@ sparse_early_usemaps_alloc_pgdat_section(struct pglist_data *pgdat,
        limit = goal + (1UL << PA_SECTION_SHIFT);
        nid = early_pfn_to_nid(goal >> PAGE_SHIFT);
 again:
-       p = memblock_alloc_try_nid(size, SMP_CACHE_BYTES, goal, limit, nid);
-       if (!p && limit) {
+       usage = memblock_alloc_try_nid(size, SMP_CACHE_BYTES, goal, limit, nid);
+       if (!usage && limit) {
                limit = 0;
                goto again;
        }
-       return p;
+       return usage;
 }
 
-static void __init check_usemap_section_nr(int nid, unsigned long *usemap)
+static void __init check_usemap_section_nr(int nid,
+               struct mem_section_usage *usage)
 {
        unsigned long usemap_snr, pgdat_snr;
        static unsigned long old_usemap_snr;
@@ -352,7 +393,7 @@ static void __init check_usemap_section_nr(int nid, unsigned long *usemap)
                old_pgdat_snr = NR_MEM_SECTIONS;
        }
 
-       usemap_snr = pfn_to_section_nr(__pa(usemap) >> PAGE_SHIFT);
+       usemap_snr = pfn_to_section_nr(__pa(usage) >> PAGE_SHIFT);
        pgdat_snr = pfn_to_section_nr(__pa(pgdat) >> PAGE_SHIFT);
        if (usemap_snr == pgdat_snr)
                return;
@@ -380,14 +421,15 @@ static void __init check_usemap_section_nr(int nid, unsigned long *usemap)
                usemap_snr, pgdat_snr, nid);
 }
 #else
-static unsigned long * __init
+static struct mem_section_usage * __init
 sparse_early_usemaps_alloc_pgdat_section(struct pglist_data *pgdat,
                                         unsigned long size)
 {
        return memblock_alloc_node(size, SMP_CACHE_BYTES, pgdat->node_id);
 }
 
-static void __init check_usemap_section_nr(int nid, unsigned long *usemap)
+static void __init check_usemap_section_nr(int nid,
+               struct mem_section_usage *usage)
 {
 }
 #endif /* CONFIG_MEMORY_HOTREMOVE */
@@ -404,8 +446,8 @@ static unsigned long __init section_map_size(void)
        return PAGE_ALIGN(sizeof(struct page) * PAGES_PER_SECTION);
 }
 
-struct page __init *sparse_mem_map_populate(unsigned long pnum, int nid,
-               struct vmem_altmap *altmap)
+struct page __init *__populate_section_memmap(unsigned long pfn,
+               unsigned long nr_pages, int nid, struct vmem_altmap *altmap)
 {
        unsigned long size = section_map_size();
        struct page *map = sparse_buffer_alloc(size);
@@ -474,32 +516,35 @@ static void __init sparse_init_nid(int nid, unsigned long pnum_begin,
                                   unsigned long pnum_end,
                                   unsigned long map_count)
 {
-       unsigned long pnum, usemap_longs, *usemap;
+       struct mem_section_usage *usage;
+       unsigned long pnum;
        struct page *map;
 
-       usemap_longs = BITS_TO_LONGS(SECTION_BLOCKFLAGS_BITS);
-       usemap = sparse_early_usemaps_alloc_pgdat_section(NODE_DATA(nid),
-                                                         usemap_size() *
-                                                         map_count);
-       if (!usemap) {
+       usage = sparse_early_usemaps_alloc_pgdat_section(NODE_DATA(nid),
+                       mem_section_usage_size() * map_count);
+       if (!usage) {
                pr_err("%s: node[%d] usemap allocation failed", __func__, nid);
                goto failed;
        }
        sparse_buffer_init(map_count * section_map_size(), nid);
        for_each_present_section_nr(pnum_begin, pnum) {
+               unsigned long pfn = section_nr_to_pfn(pnum);
+
                if (pnum >= pnum_end)
                        break;
 
-               map = sparse_mem_map_populate(pnum, nid, NULL);
+               map = __populate_section_memmap(pfn, PAGES_PER_SECTION,
+                               nid, NULL);
                if (!map) {
                        pr_err("%s: node[%d] memory map backing failed. Some memory will not be available.",
                               __func__, nid);
                        pnum_begin = pnum;
                        goto failed;
                }
-               check_usemap_section_nr(nid, usemap);
-               sparse_init_one_section(__nr_to_section(pnum), pnum, map, usemap);
-               usemap += usemap_longs;
+               check_usemap_section_nr(nid, usage);
+               sparse_init_one_section(__nr_to_section(pnum), pnum, map, usage,
+                               SECTION_IS_EARLY);
+               usage = (void *) usage + mem_section_usage_size();
        }
        sparse_buffer_fini();
        return;
@@ -590,21 +635,20 @@ void offline_mem_sections(unsigned long start_pfn, unsigned long end_pfn)
 #endif
 
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
-static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid,
-               struct vmem_altmap *altmap)
+static struct page *populate_section_memmap(unsigned long pfn,
+               unsigned long nr_pages, int nid, struct vmem_altmap *altmap)
 {
-       /* This will make the necessary allocations eventually. */
-       return sparse_mem_map_populate(pnum, nid, altmap);
+       return __populate_section_memmap(pfn, nr_pages, nid, altmap);
 }
-static void __kfree_section_memmap(struct page *memmap,
+
+static void depopulate_section_memmap(unsigned long pfn, unsigned long nr_pages,
                struct vmem_altmap *altmap)
 {
-       unsigned long start = (unsigned long)memmap;
-       unsigned long end = (unsigned long)(memmap + PAGES_PER_SECTION);
+       unsigned long start = (unsigned long) pfn_to_page(pfn);
+       unsigned long end = start + nr_pages * sizeof(struct page);
 
        vmemmap_free(start, end, altmap);
 }
-#ifdef CONFIG_MEMORY_HOTREMOVE
 static void free_map_bootmem(struct page *memmap)
 {
        unsigned long start = (unsigned long)memmap;
@@ -612,9 +656,9 @@ static void free_map_bootmem(struct page *memmap)
 
        vmemmap_free(start, end, NULL);
 }
-#endif /* CONFIG_MEMORY_HOTREMOVE */
 #else
-static struct page *__kmalloc_section_memmap(void)
+struct page *populate_section_memmap(unsigned long pfn,
+               unsigned long nr_pages, int nid, struct vmem_altmap *altmap)
 {
        struct page *page, *ret;
        unsigned long memmap_size = sizeof(struct page) * PAGES_PER_SECTION;
@@ -635,15 +679,11 @@ got_map_ptr:
        return ret;
 }
 
-static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid,
+static void depopulate_section_memmap(unsigned long pfn, unsigned long nr_pages,
                struct vmem_altmap *altmap)
 {
-       return __kmalloc_section_memmap();
-}
+       struct page *memmap = pfn_to_page(pfn);
 
-static void __kfree_section_memmap(struct page *memmap,
-               struct vmem_altmap *altmap)
-{
        if (is_vmalloc_addr(memmap))
                vfree(memmap);
        else
@@ -651,7 +691,6 @@ static void __kfree_section_memmap(struct page *memmap,
                           get_order(sizeof(struct page) * PAGES_PER_SECTION));
 }
 
-#ifdef CONFIG_MEMORY_HOTREMOVE
 static void free_map_bootmem(struct page *memmap)
 {
        unsigned long maps_section_nr, removing_section_nr, i;
@@ -681,13 +720,122 @@ static void free_map_bootmem(struct page *memmap)
                        put_page_bootmem(page);
        }
 }
-#endif /* CONFIG_MEMORY_HOTREMOVE */
 #endif /* CONFIG_SPARSEMEM_VMEMMAP */
 
+static void section_deactivate(unsigned long pfn, unsigned long nr_pages,
+               struct vmem_altmap *altmap)
+{
+       DECLARE_BITMAP(map, SUBSECTIONS_PER_SECTION) = { 0 };
+       DECLARE_BITMAP(tmp, SUBSECTIONS_PER_SECTION) = { 0 };
+       struct mem_section *ms = __pfn_to_section(pfn);
+       bool section_is_early = early_section(ms);
+       struct page *memmap = NULL;
+       unsigned long *subsection_map = ms->usage
+               ? &ms->usage->subsection_map[0] : NULL;
+
+       subsection_mask_set(map, pfn, nr_pages);
+       if (subsection_map)
+               bitmap_and(tmp, map, subsection_map, SUBSECTIONS_PER_SECTION);
+
+       if (WARN(!subsection_map || !bitmap_equal(tmp, map, SUBSECTIONS_PER_SECTION),
+                               "section already deactivated (%#lx + %ld)\n",
+                               pfn, nr_pages))
+               return;
+
+       /*
+        * There are 3 cases to handle across two configurations
+        * (SPARSEMEM_VMEMMAP={y,n}):
+        *
+        * 1/ deactivation of a partial hot-added section (only possible
+        * in the SPARSEMEM_VMEMMAP=y case).
+        *    a/ section was present at memory init
+        *    b/ section was hot-added post memory init
+        * 2/ deactivation of a complete hot-added section
+        * 3/ deactivation of a complete section from memory init
+        *
+        * For 1/, when subsection_map does not empty we will not be
+        * freeing the usage map, but still need to free the vmemmap
+        * range.
+        *
+        * For 2/ and 3/ the SPARSEMEM_VMEMMAP={y,n} cases are unified
+        */
+       bitmap_xor(subsection_map, map, subsection_map, SUBSECTIONS_PER_SECTION);
+       if (bitmap_empty(subsection_map, SUBSECTIONS_PER_SECTION)) {
+               unsigned long section_nr = pfn_to_section_nr(pfn);
+
+               if (!section_is_early) {
+                       kfree(ms->usage);
+                       ms->usage = NULL;
+               }
+               memmap = sparse_decode_mem_map(ms->section_mem_map, section_nr);
+               ms->section_mem_map = sparse_encode_mem_map(NULL, section_nr);
+       }
+
+       if (section_is_early && memmap)
+               free_map_bootmem(memmap);
+       else
+               depopulate_section_memmap(pfn, nr_pages, altmap);
+}
+
+static struct page * __meminit section_activate(int nid, unsigned long pfn,
+               unsigned long nr_pages, struct vmem_altmap *altmap)
+{
+       DECLARE_BITMAP(map, SUBSECTIONS_PER_SECTION) = { 0 };
+       struct mem_section *ms = __pfn_to_section(pfn);
+       struct mem_section_usage *usage = NULL;
+       unsigned long *subsection_map;
+       struct page *memmap;
+       int rc = 0;
+
+       subsection_mask_set(map, pfn, nr_pages);
+
+       if (!ms->usage) {
+               usage = kzalloc(mem_section_usage_size(), GFP_KERNEL);
+               if (!usage)
+                       return ERR_PTR(-ENOMEM);
+               ms->usage = usage;
+       }
+       subsection_map = &ms->usage->subsection_map[0];
+
+       if (bitmap_empty(map, SUBSECTIONS_PER_SECTION))
+               rc = -EINVAL;
+       else if (bitmap_intersects(map, subsection_map, SUBSECTIONS_PER_SECTION))
+               rc = -EEXIST;
+       else
+               bitmap_or(subsection_map, map, subsection_map,
+                               SUBSECTIONS_PER_SECTION);
+
+       if (rc) {
+               if (usage)
+                       ms->usage = NULL;
+               kfree(usage);
+               return ERR_PTR(rc);
+       }
+
+       /*
+        * The early init code does not consider partially populated
+        * initial sections, it simply assumes that memory will never be
+        * referenced.  If we hot-add memory into such a section then we
+        * do not need to populate the memmap and can simply reuse what
+        * is already there.
+        */
+       if (nr_pages < PAGES_PER_SECTION && early_section(ms))
+               return pfn_to_page(pfn);
+
+       memmap = populate_section_memmap(pfn, nr_pages, nid, altmap);
+       if (!memmap) {
+               section_deactivate(pfn, nr_pages, altmap);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       return memmap;
+}
+
 /**
- * sparse_add_one_section - add a memory section
+ * sparse_add_section - add a memory section, or populate an existing one
  * @nid: The node to add section on
  * @start_pfn: start pfn of the memory range
+ * @nr_pages: number of pfns to add in the section
  * @altmap: device page map
  *
  * This is only intended for hotplug.
@@ -697,56 +845,40 @@ static void free_map_bootmem(struct page *memmap)
  * * -EEXIST   - Section has been present.
  * * -ENOMEM   - Out of memory.
  */
-int __meminit sparse_add_one_section(int nid, unsigned long start_pfn,
-                                    struct vmem_altmap *altmap)
+int __meminit sparse_add_section(int nid, unsigned long start_pfn,
+               unsigned long nr_pages, struct vmem_altmap *altmap)
 {
        unsigned long section_nr = pfn_to_section_nr(start_pfn);
        struct mem_section *ms;
        struct page *memmap;
-       unsigned long *usemap;
        int ret;
 
-       /*
-        * no locking for this, because it does its own
-        * plus, it does a kmalloc
-        */
        ret = sparse_index_init(section_nr, nid);
-       if (ret < 0 && ret != -EEXIST)
+       if (ret < 0)
                return ret;
-       ret = 0;
-       memmap = kmalloc_section_memmap(section_nr, nid, altmap);
-       if (!memmap)
-               return -ENOMEM;
-       usemap = __kmalloc_section_usemap();
-       if (!usemap) {
-               __kfree_section_memmap(memmap, altmap);
-               return -ENOMEM;
-       }
 
-       ms = __pfn_to_section(start_pfn);
-       if (ms->section_mem_map & SECTION_MARKED_PRESENT) {
-               ret = -EEXIST;
-               goto out;
-       }
+       memmap = section_activate(nid, start_pfn, nr_pages, altmap);
+       if (IS_ERR(memmap))
+               return PTR_ERR(memmap);
 
        /*
         * Poison uninitialized struct pages in order to catch invalid flags
         * combinations.
         */
-       page_init_poison(memmap, sizeof(struct page) * PAGES_PER_SECTION);
+       page_init_poison(pfn_to_page(start_pfn), sizeof(struct page) * nr_pages);
 
+       ms = __pfn_to_section(start_pfn);
+       set_section_nid(section_nr, nid);
        section_mark_present(ms);
-       sparse_init_one_section(ms, section_nr, memmap, usemap);
 
-out:
-       if (ret < 0) {
-               kfree(usemap);
-               __kfree_section_memmap(memmap, altmap);
-       }
-       return ret;
+       /* Align memmap to section boundary in the subsection case */
+       if (section_nr_to_pfn(section_nr) != start_pfn)
+               memmap = pfn_to_kaddr(section_nr_to_pfn(section_nr));
+       sparse_init_one_section(ms, section_nr, memmap, ms->usage, 0);
+
+       return 0;
 }
 
-#ifdef CONFIG_MEMORY_HOTREMOVE
 #ifdef CONFIG_MEMORY_FAILURE
 static void clear_hwpoisoned_pages(struct page *memmap, int nr_pages)
 {
@@ -777,51 +909,12 @@ static inline void clear_hwpoisoned_pages(struct page *memmap, int nr_pages)
 }
 #endif
 
-static void free_section_usemap(struct page *memmap, unsigned long *usemap,
+void sparse_remove_section(struct mem_section *ms, unsigned long pfn,
+               unsigned long nr_pages, unsigned long map_offset,
                struct vmem_altmap *altmap)
 {
-       struct page *usemap_page;
-
-       if (!usemap)
-               return;
-
-       usemap_page = virt_to_page(usemap);
-       /*
-        * Check to see if allocation came from hot-plug-add
-        */
-       if (PageSlab(usemap_page) || PageCompound(usemap_page)) {
-               kfree(usemap);
-               if (memmap)
-                       __kfree_section_memmap(memmap, altmap);
-               return;
-       }
-
-       /*
-        * The usemap came from bootmem. This is packed with other usemaps
-        * on the section which has pgdat at boot time. Just keep it as is now.
-        */
-
-       if (memmap)
-               free_map_bootmem(memmap);
-}
-
-void sparse_remove_one_section(struct zone *zone, struct mem_section *ms,
-               unsigned long map_offset, struct vmem_altmap *altmap)
-{
-       struct page *memmap = NULL;
-       unsigned long *usemap = NULL;
-
-       if (ms->section_mem_map) {
-               usemap = ms->pageblock_flags;
-               memmap = sparse_decode_mem_map(ms->section_mem_map,
-                                               __section_nr(ms));
-               ms->section_mem_map = 0;
-               ms->pageblock_flags = NULL;
-       }
-
-       clear_hwpoisoned_pages(memmap + map_offset,
-                       PAGES_PER_SECTION - map_offset);
-       free_section_usemap(memmap, usemap, altmap);
+       clear_hwpoisoned_pages(pfn_to_page(pfn) + map_offset,
+                       nr_pages - map_offset);
+       section_deactivate(pfn, nr_pages, altmap);
 }
-#endif /* CONFIG_MEMORY_HOTREMOVE */
 #endif /* CONFIG_MEMORY_HOTPLUG */
index 607c482..ae30039 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -8,7 +8,7 @@
 /*
  * This file contains the default values for the operation of the
  * Linux VM subsystem. Fine-tuning documentation can be found in
- * Documentation/sysctl/vm.txt.
+ * Documentation/admin-guide/sysctl/vm.rst.
  * Started 18.12.91
  * Swap aging added 23.2.95, Stephen Tweedie.
  * Buffermem limits added 12.3.98, Rik van Riel.
index 68575a3..e6351a8 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -7,6 +7,7 @@
 #include <linux/err.h>
 #include <linux/sched.h>
 #include <linux/sched/mm.h>
+#include <linux/sched/signal.h>
 #include <linux/sched/task_stack.h>
 #include <linux/security.h>
 #include <linux/swap.h>
@@ -300,6 +301,80 @@ void arch_pick_mmap_layout(struct mm_struct *mm, struct rlimit *rlim_stack)
 }
 #endif
 
+/**
+ * __account_locked_vm - account locked pages to an mm's locked_vm
+ * @mm:          mm to account against
+ * @pages:       number of pages to account
+ * @inc:         %true if @pages should be considered positive, %false if not
+ * @task:        task used to check RLIMIT_MEMLOCK
+ * @bypass_rlim: %true if checking RLIMIT_MEMLOCK should be skipped
+ *
+ * Assumes @task and @mm are valid (i.e. at least one reference on each), and
+ * that mmap_sem is held as writer.
+ *
+ * Return:
+ * * 0       on success
+ * * -ENOMEM if RLIMIT_MEMLOCK would be exceeded.
+ */
+int __account_locked_vm(struct mm_struct *mm, unsigned long pages, bool inc,
+                       struct task_struct *task, bool bypass_rlim)
+{
+       unsigned long locked_vm, limit;
+       int ret = 0;
+
+       lockdep_assert_held_write(&mm->mmap_sem);
+
+       locked_vm = mm->locked_vm;
+       if (inc) {
+               if (!bypass_rlim) {
+                       limit = task_rlimit(task, RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+                       if (locked_vm + pages > limit)
+                               ret = -ENOMEM;
+               }
+               if (!ret)
+                       mm->locked_vm = locked_vm + pages;
+       } else {
+               WARN_ON_ONCE(pages > locked_vm);
+               mm->locked_vm = locked_vm - pages;
+       }
+
+       pr_debug("%s: [%d] caller %ps %c%lu %lu/%lu%s\n", __func__, task->pid,
+                (void *)_RET_IP_, (inc) ? '+' : '-', pages << PAGE_SHIFT,
+                locked_vm << PAGE_SHIFT, task_rlimit(task, RLIMIT_MEMLOCK),
+                ret ? " - exceeded" : "");
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(__account_locked_vm);
+
+/**
+ * account_locked_vm - account locked pages to an mm's locked_vm
+ * @mm:          mm to account against, may be NULL
+ * @pages:       number of pages to account
+ * @inc:         %true if @pages should be considered positive, %false if not
+ *
+ * Assumes a non-NULL @mm is valid (i.e. at least one reference on it).
+ *
+ * Return:
+ * * 0       on success, or if mm is NULL
+ * * -ENOMEM if RLIMIT_MEMLOCK would be exceeded.
+ */
+int account_locked_vm(struct mm_struct *mm, unsigned long pages, bool inc)
+{
+       int ret;
+
+       if (pages == 0 || !mm)
+               return 0;
+
+       down_write(&mm->mmap_sem);
+       ret = __account_locked_vm(mm, pages, inc, current,
+                                 capable(CAP_IPC_LOCK));
+       up_write(&mm->mmap_sem);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(account_locked_vm);
+
 unsigned long vm_mmap_pgoff(struct file *file, unsigned long addr,
        unsigned long len, unsigned long prot,
        unsigned long flag, unsigned long pgoff)
index f8e3dcd..44df66a 100644 (file)
@@ -131,6 +131,9 @@ struct scan_control {
                unsigned int file_taken;
                unsigned int taken;
        } nr;
+
+       /* for recording the reclaimed slab by now */
+       struct reclaim_state reclaim_state;
 };
 
 #ifdef ARCH_HAS_PREFETCH
@@ -238,6 +241,18 @@ static void unregister_memcg_shrinker(struct shrinker *shrinker)
 }
 #endif /* CONFIG_MEMCG_KMEM */
 
+static void set_task_reclaim_state(struct task_struct *task,
+                                  struct reclaim_state *rs)
+{
+       /* Check for an overwrite */
+       WARN_ON_ONCE(rs && task->reclaim_state);
+
+       /* Check for the nulling of an already-nulled member */
+       WARN_ON_ONCE(!rs && !task->reclaim_state);
+
+       task->reclaim_state = rs;
+}
+
 #ifdef CONFIG_MEMCG
 static bool global_reclaim(struct scan_control *sc)
 {
@@ -3191,11 +3206,13 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
        if (throttle_direct_reclaim(sc.gfp_mask, zonelist, nodemask))
                return 1;
 
+       set_task_reclaim_state(current, &sc.reclaim_state);
        trace_mm_vmscan_direct_reclaim_begin(order, sc.gfp_mask);
 
        nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
 
        trace_mm_vmscan_direct_reclaim_end(nr_reclaimed);
+       set_task_reclaim_state(current, NULL);
 
        return nr_reclaimed;
 }
@@ -3218,6 +3235,7 @@ unsigned long mem_cgroup_shrink_node(struct mem_cgroup *memcg,
        };
        unsigned long lru_pages;
 
+       set_task_reclaim_state(current, &sc.reclaim_state);
        sc.gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
                        (GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK);
 
@@ -3235,7 +3253,9 @@ unsigned long mem_cgroup_shrink_node(struct mem_cgroup *memcg,
 
        trace_mm_vmscan_memcg_softlimit_reclaim_end(sc.nr_reclaimed);
 
+       set_task_reclaim_state(current, NULL);
        *nr_scanned = sc.nr_scanned;
+
        return sc.nr_reclaimed;
 }
 
@@ -3262,6 +3282,7 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
                .may_shrinkslab = 1,
        };
 
+       set_task_reclaim_state(current, &sc.reclaim_state);
        /*
         * Unlike direct reclaim via alloc_pages(), memcg's reclaim doesn't
         * take care of from where we get pages. So the node where we start the
@@ -3282,6 +3303,7 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
        psi_memstall_leave(&pflags);
 
        trace_mm_vmscan_memcg_reclaim_end(nr_reclaimed);
+       set_task_reclaim_state(current, NULL);
 
        return nr_reclaimed;
 }
@@ -3483,6 +3505,7 @@ static int balance_pgdat(pg_data_t *pgdat, int order, int classzone_idx)
                .may_unmap = 1,
        };
 
+       set_task_reclaim_state(current, &sc.reclaim_state);
        psi_memstall_enter(&pflags);
        __fs_reclaim_acquire();
 
@@ -3664,6 +3687,8 @@ out:
        snapshot_refaults(NULL, pgdat);
        __fs_reclaim_release();
        psi_memstall_leave(&pflags);
+       set_task_reclaim_state(current, NULL);
+
        /*
         * Return the order kswapd stopped reclaiming at as
         * prepare_kswapd_sleep() takes it into account. If another caller
@@ -3787,15 +3812,10 @@ static int kswapd(void *p)
        unsigned int classzone_idx = MAX_NR_ZONES - 1;
        pg_data_t *pgdat = (pg_data_t*)p;
        struct task_struct *tsk = current;
-
-       struct reclaim_state reclaim_state = {
-               .reclaimed_slab = 0,
-       };
        const struct cpumask *cpumask = cpumask_of_node(pgdat->node_id);
 
        if (!cpumask_empty(cpumask))
                set_cpus_allowed_ptr(tsk, cpumask);
-       current->reclaim_state = &reclaim_state;
 
        /*
         * Tell the memory management that we're a "memory allocator",
@@ -3857,7 +3877,6 @@ kswapd_try_sleep:
        }
 
        tsk->flags &= ~(PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD);
-       current->reclaim_state = NULL;
 
        return 0;
 }
@@ -3922,7 +3941,6 @@ void wakeup_kswapd(struct zone *zone, gfp_t gfp_flags, int order,
  */
 unsigned long shrink_all_memory(unsigned long nr_to_reclaim)
 {
-       struct reclaim_state reclaim_state;
        struct scan_control sc = {
                .nr_to_reclaim = nr_to_reclaim,
                .gfp_mask = GFP_HIGHUSER_MOVABLE,
@@ -3934,18 +3952,16 @@ unsigned long shrink_all_memory(unsigned long nr_to_reclaim)
                .hibernation_mode = 1,
        };
        struct zonelist *zonelist = node_zonelist(numa_node_id(), sc.gfp_mask);
-       struct task_struct *p = current;
        unsigned long nr_reclaimed;
        unsigned int noreclaim_flag;
 
        fs_reclaim_acquire(sc.gfp_mask);
        noreclaim_flag = memalloc_noreclaim_save();
-       reclaim_state.reclaimed_slab = 0;
-       p->reclaim_state = &reclaim_state;
+       set_task_reclaim_state(current, &sc.reclaim_state);
 
        nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
 
-       p->reclaim_state = NULL;
+       set_task_reclaim_state(current, NULL);
        memalloc_noreclaim_restore(noreclaim_flag);
        fs_reclaim_release(sc.gfp_mask);
 
@@ -4110,7 +4126,6 @@ static int __node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, unsigned in
        /* Minimum pages needed in order to stay on node */
        const unsigned long nr_pages = 1 << order;
        struct task_struct *p = current;
-       struct reclaim_state reclaim_state;
        unsigned int noreclaim_flag;
        struct scan_control sc = {
                .nr_to_reclaim = max(nr_pages, SWAP_CLUSTER_MAX),
@@ -4135,8 +4150,7 @@ static int __node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, unsigned in
         */
        noreclaim_flag = memalloc_noreclaim_save();
        p->flags |= PF_SWAPWRITE;
-       reclaim_state.reclaimed_slab = 0;
-       p->reclaim_state = &reclaim_state;
+       set_task_reclaim_state(p, &sc.reclaim_state);
 
        if (node_pagecache_reclaimable(pgdat) > pgdat->min_unmapped_pages) {
                /*
@@ -4148,7 +4162,7 @@ static int __node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, unsigned in
                } while (sc.nr_reclaimed < nr_pages && --sc.priority >= 0);
        }
 
-       p->reclaim_state = NULL;
+       set_task_reclaim_state(p, NULL);
        current->flags &= ~PF_SWAPWRITE;
        memalloc_noreclaim_restore(noreclaim_flag);
        fs_reclaim_release(sc.gfp_mask);
index dfcd69d..1a029a7 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/atomic.h>
 #include <linux/sched.h>
 #include <linux/cpumask.h>
-#include <linux/dcache.h>
 #include <linux/list.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/compaction.h>
 #include <linux/percpu.h>
 #include <linux/mount.h>
+#include <linux/pseudo_fs.h>
 #include <linux/fs.h>
 #include <linux/preempt.h>
 #include <linux/workqueue.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/zpool.h>
+#include <linux/magic.h>
 
 /*
  * NCHUNKS_ORDER determines the internal allocation granularity, effectively
@@ -101,6 +102,7 @@ struct z3fold_buddy_slots {
  * @refcount:          reference count for the z3fold page
  * @work:              work_struct for page layout optimization
  * @slots:             pointer to the structure holding buddy slots
+ * @pool:              pointer to the containing pool
  * @cpu:               CPU which this page "belongs" to
  * @first_chunks:      the size of the first buddy in chunks, 0 if free
  * @middle_chunks:     the size of the middle buddy in chunks, 0 if free
@@ -114,6 +116,7 @@ struct z3fold_header {
        struct kref refcount;
        struct work_struct work;
        struct z3fold_buddy_slots *slots;
+       struct z3fold_pool *pool;
        short cpu;
        unsigned short first_chunks;
        unsigned short middle_chunks;
@@ -193,8 +196,10 @@ static void compact_page_work(struct work_struct *w);
 static inline struct z3fold_buddy_slots *alloc_slots(struct z3fold_pool *pool,
                                                        gfp_t gfp)
 {
-       struct z3fold_buddy_slots *slots = kmem_cache_alloc(pool->c_handle,
-                                                           gfp);
+       struct z3fold_buddy_slots *slots;
+
+       slots = kmem_cache_alloc(pool->c_handle,
+                                (gfp & ~(__GFP_HIGHMEM | __GFP_MOVABLE)));
 
        if (slots) {
                memset(slots->slot, 0, sizeof(slots->slot));
@@ -241,19 +246,14 @@ static inline void free_handle(unsigned long handle)
        }
 }
 
-static struct dentry *z3fold_do_mount(struct file_system_type *fs_type,
-                               int flags, const char *dev_name, void *data)
+static int z3fold_init_fs_context(struct fs_context *fc)
 {
-       static const struct dentry_operations ops = {
-               .d_dname = simple_dname,
-       };
-
-       return mount_pseudo(fs_type, "z3fold:", NULL, &ops, 0x33);
+       return init_pseudo(fc, Z3FOLD_MAGIC) ? 0 : -ENOMEM;
 }
 
 static struct file_system_type z3fold_fs = {
        .name           = "z3fold",
-       .mount          = z3fold_do_mount,
+       .init_fs_context = z3fold_init_fs_context,
        .kill_sb        = kill_anon_super,
 };
 
@@ -320,6 +320,7 @@ static struct z3fold_header *init_z3fold_page(struct page *page,
        zhdr->start_middle = 0;
        zhdr->cpu = -1;
        zhdr->slots = slots;
+       zhdr->pool = pool;
        INIT_LIST_HEAD(&zhdr->buddy);
        INIT_WORK(&zhdr->work, compact_page_work);
        return zhdr;
@@ -426,7 +427,7 @@ static enum buddy handle_to_buddy(unsigned long handle)
 
 static inline struct z3fold_pool *zhdr_to_pool(struct z3fold_header *zhdr)
 {
-       return slots_to_pool(zhdr->slots);
+       return zhdr->pool;
 }
 
 static void __release_z3fold_page(struct z3fold_header *zhdr, bool locked)
@@ -850,7 +851,7 @@ static int z3fold_alloc(struct z3fold_pool *pool, size_t size, gfp_t gfp,
        enum buddy bud;
        bool can_sleep = gfpflags_allow_blocking(gfp);
 
-       if (!size || (gfp & __GFP_HIGHMEM))
+       if (!size)
                return -EINVAL;
 
        if (size > PAGE_SIZE)
@@ -1345,24 +1346,29 @@ static int z3fold_page_migrate(struct address_space *mapping, struct page *newpa
        zhdr = page_address(page);
        pool = zhdr_to_pool(zhdr);
 
-       if (!trylock_page(page))
-               return -EAGAIN;
-
        if (!z3fold_page_trylock(zhdr)) {
-               unlock_page(page);
                return -EAGAIN;
        }
        if (zhdr->mapped_count != 0) {
                z3fold_page_unlock(zhdr);
-               unlock_page(page);
                return -EBUSY;
        }
+       if (work_pending(&zhdr->work)) {
+               z3fold_page_unlock(zhdr);
+               return -EAGAIN;
+       }
        new_zhdr = page_address(newpage);
        memcpy(new_zhdr, zhdr, PAGE_SIZE);
        newpage->private = page->private;
        page->private = 0;
        z3fold_page_unlock(zhdr);
        spin_lock_init(&new_zhdr->page_lock);
+       INIT_WORK(&new_zhdr->work, compact_page_work);
+       /*
+        * z3fold_page_isolate() ensures that new_zhdr->buddy is empty,
+        * so we only have to reinitialize it.
+        */
+       INIT_LIST_HEAD(&new_zhdr->buddy);
        new_mapping = page_mapping(page);
        __ClearPageMovable(page);
        ClearPagePrivate(page);
@@ -1386,7 +1392,6 @@ static int z3fold_page_migrate(struct address_space *mapping, struct page *newpa
        queue_work_on(new_zhdr->cpu, pool->compact_wq, &new_zhdr->work);
 
        page_mapcount_reset(page);
-       unlock_page(page);
        put_page(page);
        return 0;
 }
index db09eb3..57fbb7c 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/zsmalloc.h>
 #include <linux/zpool.h>
 #include <linux/mount.h>
+#include <linux/pseudo_fs.h>
 #include <linux/migrate.h>
 #include <linux/pagemap.h>
 #include <linux/fs.h>
@@ -1798,19 +1799,14 @@ static void lock_zspage(struct zspage *zspage)
        } while ((page = get_next_page(page)) != NULL);
 }
 
-static struct dentry *zs_mount(struct file_system_type *fs_type,
-                               int flags, const char *dev_name, void *data)
+static int zs_init_fs_context(struct fs_context *fc)
 {
-       static const struct dentry_operations ops = {
-               .d_dname = simple_dname,
-       };
-
-       return mount_pseudo(fs_type, "zsmalloc:", NULL, &ops, ZSMALLOC_MAGIC);
+       return init_pseudo(fc, ZSMALLOC_MAGIC) ? 0 : -ENOMEM;
 }
 
 static struct file_system_type zsmalloc_fs = {
        .name           = "zsmalloc",
-       .mount          = zs_mount,
+       .init_fs_context = zs_init_fs_context,
        .kill_sb        = kill_anon_super,
 };
 
index 154fa55..5040fe4 100644 (file)
@@ -6,7 +6,7 @@
 menuconfig NF_TABLES_BRIDGE
        depends on BRIDGE && NETFILTER && NF_TABLES
        select NETFILTER_FAMILY_BRIDGE
-       bool "Ethernet Bridge nf_tables support"
+       tristate "Ethernet Bridge nf_tables support"
 
 if NF_TABLES_BRIDGE
 
@@ -25,6 +25,8 @@ config NF_LOG_BRIDGE
        tristate "Bridge packet logging"
        select NF_LOG_COMMON
 
+endif # NF_TABLES_BRIDGE
+
 config NF_CONNTRACK_BRIDGE
        tristate "IPv4/IPV6 bridge connection tracking support"
        depends on NF_CONNTRACK
@@ -39,8 +41,6 @@ config NF_CONNTRACK_BRIDGE
 
          To compile it as a module, choose M here.  If unsure, say N.
 
-endif # NF_TABLES_BRIDGE
-
 menuconfig BRIDGE_NF_EBTABLES
        tristate "Ethernet Bridge tables (ebtables) support"
        depends on BRIDGE && NETFILTER && NETFILTER_XTABLES
index db09def..59d0ba2 100644 (file)
@@ -5,7 +5,7 @@
 obj-$(CONFIG_CEPH_LIB) += libceph.o
 
 libceph-y := ceph_common.o messenger.o msgpool.o buffer.o pagelist.o \
-       mon_client.o \
+       mon_client.o decode.o \
        cls_lock_client.o \
        osd_client.o osdmap.o crush/crush.o crush/mapper.o crush/hash.o \
        striper.o \
index 4cc2854..17447c1 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/ceph/cls_lock_client.h>
 #include <linux/ceph/decode.h>
+#include <linux/ceph/libceph.h>
 
 /**
  * ceph_cls_lock - grab rados lock for object
@@ -264,8 +265,11 @@ static int decode_locker(void **p, void *end, struct ceph_locker *locker)
                return ret;
 
        *p += sizeof(struct ceph_timespec); /* skip expiration */
-       ceph_decode_copy(p, &locker->info.addr, sizeof(locker->info.addr));
-       ceph_decode_addr(&locker->info.addr);
+
+       ret = ceph_decode_entity_addr(p, end, &locker->info.addr);
+       if (ret)
+               return ret;
+
        len = ceph_decode_32(p);
        *p += len; /* skip description */
 
@@ -360,7 +364,7 @@ int ceph_cls_lock_info(struct ceph_osd_client *osdc,
        dout("%s lock_name %s\n", __func__, lock_name);
        ret = ceph_osdc_call(osdc, oid, oloc, "lock", "get_info",
                             CEPH_OSD_FLAG_READ, get_info_op_page,
-                            get_info_op_buf_size, reply_page, &reply_len);
+                            get_info_op_buf_size, &reply_page, &reply_len);
 
        dout("%s: status %d\n", __func__, ret);
        if (ret >= 0) {
@@ -375,3 +379,47 @@ int ceph_cls_lock_info(struct ceph_osd_client *osdc,
        return ret;
 }
 EXPORT_SYMBOL(ceph_cls_lock_info);
+
+int ceph_cls_assert_locked(struct ceph_osd_request *req, int which,
+                          char *lock_name, u8 type, char *cookie, char *tag)
+{
+       int assert_op_buf_size;
+       int name_len = strlen(lock_name);
+       int cookie_len = strlen(cookie);
+       int tag_len = strlen(tag);
+       struct page **pages;
+       void *p, *end;
+       int ret;
+
+       assert_op_buf_size = name_len + sizeof(__le32) +
+                            cookie_len + sizeof(__le32) +
+                            tag_len + sizeof(__le32) +
+                            sizeof(u8) + CEPH_ENCODING_START_BLK_LEN;
+       if (assert_op_buf_size > PAGE_SIZE)
+               return -E2BIG;
+
+       ret = osd_req_op_cls_init(req, which, "lock", "assert_locked");
+       if (ret)
+               return ret;
+
+       pages = ceph_alloc_page_vector(1, GFP_NOIO);
+       if (IS_ERR(pages))
+               return PTR_ERR(pages);
+
+       p = page_address(pages[0]);
+       end = p + assert_op_buf_size;
+
+       /* encode cls_lock_assert_op struct */
+       ceph_start_encoding(&p, 1, 1,
+                           assert_op_buf_size - CEPH_ENCODING_START_BLK_LEN);
+       ceph_encode_string(&p, end, lock_name, name_len);
+       ceph_encode_8(&p, type);
+       ceph_encode_string(&p, end, cookie, cookie_len);
+       ceph_encode_string(&p, end, tag, tag_len);
+       WARN_ON(p != end);
+
+       osd_req_op_cls_request_data_pages(req, which, pages, assert_op_buf_size,
+                                         0, false, true);
+       return 0;
+}
+EXPORT_SYMBOL(ceph_cls_assert_locked);
diff --git a/net/ceph/decode.c b/net/ceph/decode.c
new file mode 100644 (file)
index 0000000..eea5295
--- /dev/null
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/ceph/decode.h>
+
+static int
+ceph_decode_entity_addr_versioned(void **p, void *end,
+                                 struct ceph_entity_addr *addr)
+{
+       int ret;
+       u8 struct_v;
+       u32 struct_len, addr_len;
+       void *struct_end;
+
+       ret = ceph_start_decoding(p, end, 1, "entity_addr_t", &struct_v,
+                                 &struct_len);
+       if (ret)
+               goto bad;
+
+       ret = -EINVAL;
+       struct_end = *p + struct_len;
+
+       ceph_decode_copy_safe(p, end, &addr->type, sizeof(addr->type), bad);
+
+       ceph_decode_copy_safe(p, end, &addr->nonce, sizeof(addr->nonce), bad);
+
+       ceph_decode_32_safe(p, end, addr_len, bad);
+       if (addr_len > sizeof(addr->in_addr))
+               goto bad;
+
+       memset(&addr->in_addr, 0, sizeof(addr->in_addr));
+       if (addr_len) {
+               ceph_decode_copy_safe(p, end, &addr->in_addr, addr_len, bad);
+
+               addr->in_addr.ss_family =
+                       le16_to_cpu((__force __le16)addr->in_addr.ss_family);
+       }
+
+       /* Advance past anything the client doesn't yet understand */
+       *p = struct_end;
+       ret = 0;
+bad:
+       return ret;
+}
+
+static int
+ceph_decode_entity_addr_legacy(void **p, void *end,
+                              struct ceph_entity_addr *addr)
+{
+       int ret = -EINVAL;
+
+       /* Skip rest of type field */
+       ceph_decode_skip_n(p, end, 3, bad);
+
+       /*
+        * Clients that don't support ADDR2 always send TYPE_NONE, change it
+        * to TYPE_LEGACY for forward compatibility.
+        */
+       addr->type = CEPH_ENTITY_ADDR_TYPE_LEGACY;
+       ceph_decode_copy_safe(p, end, &addr->nonce, sizeof(addr->nonce), bad);
+       memset(&addr->in_addr, 0, sizeof(addr->in_addr));
+       ceph_decode_copy_safe(p, end, &addr->in_addr,
+                             sizeof(addr->in_addr), bad);
+       addr->in_addr.ss_family =
+                       be16_to_cpu((__force __be16)addr->in_addr.ss_family);
+       ret = 0;
+bad:
+       return ret;
+}
+
+int
+ceph_decode_entity_addr(void **p, void *end, struct ceph_entity_addr *addr)
+{
+       u8 marker;
+
+       ceph_decode_8_safe(p, end, marker, bad);
+       if (marker == 1)
+               return ceph_decode_entity_addr_versioned(p, end, addr);
+       else if (marker == 0)
+               return ceph_decode_entity_addr_legacy(p, end, addr);
+bad:
+       return -EINVAL;
+}
+EXPORT_SYMBOL(ceph_decode_entity_addr);
+
index a33402c..962f521 100644 (file)
@@ -199,12 +199,14 @@ const char *ceph_pr_addr(const struct ceph_entity_addr *addr)
 
        switch (ss.ss_family) {
        case AF_INET:
-               snprintf(s, MAX_ADDR_STR_LEN, "%pI4:%hu", &in4->sin_addr,
+               snprintf(s, MAX_ADDR_STR_LEN, "(%d)%pI4:%hu",
+                        le32_to_cpu(addr->type), &in4->sin_addr,
                         ntohs(in4->sin_port));
                break;
 
        case AF_INET6:
-               snprintf(s, MAX_ADDR_STR_LEN, "[%pI6c]:%hu", &in6->sin6_addr,
+               snprintf(s, MAX_ADDR_STR_LEN, "(%d)[%pI6c]:%hu",
+                        le32_to_cpu(addr->type), &in6->sin6_addr,
                         ntohs(in6->sin6_port));
                break;
 
@@ -220,7 +222,7 @@ EXPORT_SYMBOL(ceph_pr_addr);
 static void encode_my_addr(struct ceph_messenger *msgr)
 {
        memcpy(&msgr->my_enc_addr, &msgr->inst.addr, sizeof(msgr->my_enc_addr));
-       ceph_encode_addr(&msgr->my_enc_addr);
+       ceph_encode_banner_addr(&msgr->my_enc_addr);
 }
 
 /*
@@ -1732,12 +1734,14 @@ static int read_partial_banner(struct ceph_connection *con)
        ret = read_partial(con, end, size, &con->actual_peer_addr);
        if (ret <= 0)
                goto out;
+       ceph_decode_banner_addr(&con->actual_peer_addr);
 
        size = sizeof (con->peer_addr_for_me);
        end += size;
        ret = read_partial(con, end, size, &con->peer_addr_for_me);
        if (ret <= 0)
                goto out;
+       ceph_decode_banner_addr(&con->peer_addr_for_me);
 
 out:
        return ret;
@@ -1981,6 +1985,7 @@ int ceph_parse_ips(const char *c, const char *end,
                }
 
                addr_set_port(&addr[i], port);
+               addr[i].type = CEPH_ENTITY_ADDR_TYPE_LEGACY;
 
                dout("parse_ips got %s\n", ceph_pr_addr(&addr[i]));
 
@@ -2011,9 +2016,6 @@ static int process_banner(struct ceph_connection *con)
        if (verify_hello(con) < 0)
                return -1;
 
-       ceph_decode_addr(&con->actual_peer_addr);
-       ceph_decode_addr(&con->peer_addr_for_me);
-
        /*
         * Make sure the other end is who we wanted.  note that the other
         * end may not yet know their ip address, so if it's 0.0.0.0, give
index 895679d..0520bf9 100644 (file)
@@ -39,7 +39,7 @@ static int __validate_auth(struct ceph_mon_client *monc);
 /*
  * Decode a monmap blob (e.g., during mount).
  */
-struct ceph_monmap *ceph_monmap_decode(void *p, void *end)
+static struct ceph_monmap *ceph_monmap_decode(void *p, void *end)
 {
        struct ceph_monmap *m = NULL;
        int i, err = -EINVAL;
@@ -50,7 +50,7 @@ struct ceph_monmap *ceph_monmap_decode(void *p, void *end)
        ceph_decode_32_safe(&p, end, len, bad);
        ceph_decode_need(&p, end, len, bad);
 
-       dout("monmap_decode %p %p len %d\n", p, end, (int)(end-p));
+       dout("monmap_decode %p %p len %d (%d)\n", p, end, len, (int)(end-p));
        p += sizeof(u16);  /* skip version */
 
        ceph_decode_need(&p, end, sizeof(fsid) + 2*sizeof(u32), bad);
@@ -58,7 +58,6 @@ struct ceph_monmap *ceph_monmap_decode(void *p, void *end)
        epoch = ceph_decode_32(&p);
 
        num_mon = ceph_decode_32(&p);
-       ceph_decode_need(&p, end, num_mon*sizeof(m->mon_inst[0]), bad);
 
        if (num_mon > CEPH_MAX_MON)
                goto bad;
@@ -68,17 +67,22 @@ struct ceph_monmap *ceph_monmap_decode(void *p, void *end)
        m->fsid = fsid;
        m->epoch = epoch;
        m->num_mon = num_mon;
-       ceph_decode_copy(&p, m->mon_inst, num_mon*sizeof(m->mon_inst[0]));
-       for (i = 0; i < num_mon; i++)
-               ceph_decode_addr(&m->mon_inst[i].addr);
-
+       for (i = 0; i < num_mon; ++i) {
+               struct ceph_entity_inst *inst = &m->mon_inst[i];
+
+               /* copy name portion */
+               ceph_decode_copy_safe(&p, end, &inst->name,
+                                       sizeof(inst->name), bad);
+               err = ceph_decode_entity_addr(&p, end, &inst->addr);
+               if (err)
+                       goto bad;
+       }
        dout("monmap_decode epoch %d, num_mon %d\n", m->epoch,
             m->num_mon);
        for (i = 0; i < m->num_mon; i++)
                dout("monmap_decode  mon%d is %s\n", i,
                     ceph_pr_addr(&m->mon_inst[i].addr));
        return m;
-
 bad:
        dout("monmap_decode failed with %d\n", err);
        kfree(m);
@@ -469,6 +473,7 @@ static void ceph_monc_handle_map(struct ceph_mon_client *monc,
        if (IS_ERR(monmap)) {
                pr_err("problem decoding monmap, %d\n",
                       (int)PTR_ERR(monmap));
+               ceph_msg_dump(msg);
                goto out;
        }
 
index 9a8eca5..0b2df09 100644 (file)
@@ -171,14 +171,6 @@ static void ceph_osd_data_bvecs_init(struct ceph_osd_data *osd_data,
        osd_data->num_bvecs = num_bvecs;
 }
 
-#define osd_req_op_data(oreq, whch, typ, fld)                          \
-({                                                                     \
-       struct ceph_osd_request *__oreq = (oreq);                       \
-       unsigned int __whch = (whch);                                   \
-       BUG_ON(__whch >= __oreq->r_num_ops);                            \
-       &__oreq->r_ops[__whch].typ.fld;                                 \
-})
-
 static struct ceph_osd_data *
 osd_req_op_raw_data_in(struct ceph_osd_request *osd_req, unsigned int which)
 {
@@ -478,7 +470,7 @@ static void request_release_checks(struct ceph_osd_request *req)
 {
        WARN_ON(!RB_EMPTY_NODE(&req->r_node));
        WARN_ON(!RB_EMPTY_NODE(&req->r_mc_node));
-       WARN_ON(!list_empty(&req->r_unsafe_item));
+       WARN_ON(!list_empty(&req->r_private_item));
        WARN_ON(req->r_osd);
 }
 
@@ -538,7 +530,7 @@ static void request_init(struct ceph_osd_request *req)
        init_completion(&req->r_completion);
        RB_CLEAR_NODE(&req->r_node);
        RB_CLEAR_NODE(&req->r_mc_node);
-       INIT_LIST_HEAD(&req->r_unsafe_item);
+       INIT_LIST_HEAD(&req->r_private_item);
 
        target_init(&req->r_t);
 }
@@ -4914,20 +4906,26 @@ static int decode_watcher(void **p, void *end, struct ceph_watch_item *item)
        ret = ceph_start_decoding(p, end, 2, "watch_item_t",
                                  &struct_v, &struct_len);
        if (ret)
-               return ret;
+               goto bad;
+
+       ret = -EINVAL;
+       ceph_decode_copy_safe(p, end, &item->name, sizeof(item->name), bad);
+       ceph_decode_64_safe(p, end, item->cookie, bad);
+       ceph_decode_skip_32(p, end, bad); /* skip timeout seconds */
 
-       ceph_decode_copy(p, &item->name, sizeof(item->name));
-       item->cookie = ceph_decode_64(p);
-       *p += 4; /* skip timeout_seconds */
        if (struct_v >= 2) {
-               ceph_decode_copy(p, &item->addr, sizeof(item->addr));
-               ceph_decode_addr(&item->addr);
+               ret = ceph_decode_entity_addr(p, end, &item->addr);
+               if (ret)
+                       goto bad;
+       } else {
+               ret = 0;
        }
 
        dout("%s %s%llu cookie %llu addr %s\n", __func__,
             ENTITY_NAME(item->name), item->cookie,
             ceph_pr_addr(&item->addr));
-       return 0;
+bad:
+       return ret;
 }
 
 static int decode_watchers(void **p, void *end,
@@ -5044,12 +5042,12 @@ int ceph_osdc_call(struct ceph_osd_client *osdc,
                   const char *class, const char *method,
                   unsigned int flags,
                   struct page *req_page, size_t req_len,
-                  struct page *resp_page, size_t *resp_len)
+                  struct page **resp_pages, size_t *resp_len)
 {
        struct ceph_osd_request *req;
        int ret;
 
-       if (req_len > PAGE_SIZE || (resp_page && *resp_len > PAGE_SIZE))
+       if (req_len > PAGE_SIZE)
                return -E2BIG;
 
        req = ceph_osdc_alloc_request(osdc, NULL, 1, false, GFP_NOIO);
@@ -5067,8 +5065,8 @@ int ceph_osdc_call(struct ceph_osd_client *osdc,
        if (req_page)
                osd_req_op_cls_request_data_pages(req, 0, &req_page, req_len,
                                                  0, false, false);
-       if (resp_page)
-               osd_req_op_cls_response_data_pages(req, 0, &resp_page,
+       if (resp_pages)
+               osd_req_op_cls_response_data_pages(req, 0, resp_pages,
                                                   *resp_len, 0, false, false);
 
        ret = ceph_osdc_alloc_messages(req, GFP_NOIO);
@@ -5079,7 +5077,7 @@ int ceph_osdc_call(struct ceph_osd_client *osdc,
        ret = ceph_osdc_wait_request(osdc, req);
        if (ret >= 0) {
                ret = req->r_ops[0].rval;
-               if (resp_page)
+               if (resp_pages)
                        *resp_len = req->r_ops[0].outdata_len;
        }
 
index 48a31dc..9043790 100644 (file)
@@ -1489,11 +1489,9 @@ static int osdmap_decode(void **p, void *end, struct ceph_osdmap *map)
 
        /* osd_state, osd_weight, osd_addrs->client_addr */
        ceph_decode_need(p, end, 3*sizeof(u32) +
-                        map->max_osd*((struct_v >= 5 ? sizeof(u32) :
-                                                       sizeof(u8)) +
-                                      sizeof(*map->osd_weight) +
-                                      sizeof(*map->osd_addr)), e_inval);
-
+                        map->max_osd*(struct_v >= 5 ? sizeof(u32) :
+                                                      sizeof(u8)) +
+                                      sizeof(*map->osd_weight), e_inval);
        if (ceph_decode_32(p) != map->max_osd)
                goto e_inval;
 
@@ -1514,9 +1512,11 @@ static int osdmap_decode(void **p, void *end, struct ceph_osdmap *map)
        if (ceph_decode_32(p) != map->max_osd)
                goto e_inval;
 
-       ceph_decode_copy(p, map->osd_addr, map->max_osd*sizeof(*map->osd_addr));
-       for (i = 0; i < map->max_osd; i++)
-               ceph_decode_addr(&map->osd_addr[i]);
+       for (i = 0; i < map->max_osd; i++) {
+               err = ceph_decode_entity_addr(p, end, &map->osd_addr[i]);
+               if (err)
+                       goto bad;
+       }
 
        /* pg_temp */
        err = decode_pg_temp(p, end, map);
@@ -1618,12 +1618,17 @@ static int decode_new_up_state_weight(void **p, void *end, u8 struct_v,
        void *new_state;
        void *new_weight_end;
        u32 len;
+       int i;
 
        new_up_client = *p;
        ceph_decode_32_safe(p, end, len, e_inval);
-       len *= sizeof(u32) + sizeof(struct ceph_entity_addr);
-       ceph_decode_need(p, end, len, e_inval);
-       *p += len;
+       for (i = 0; i < len; ++i) {
+               struct ceph_entity_addr addr;
+
+               ceph_decode_skip_32(p, end, e_inval);
+               if (ceph_decode_entity_addr(p, end, &addr))
+                       goto e_inval;
+       }
 
        new_state = *p;
        ceph_decode_32_safe(p, end, len, e_inval);
@@ -1699,9 +1704,9 @@ static int decode_new_up_state_weight(void **p, void *end, u8 struct_v,
                struct ceph_entity_addr addr;
 
                osd = ceph_decode_32(p);
-               ceph_decode_copy(p, &addr, sizeof(addr));
-               ceph_decode_addr(&addr);
                BUG_ON(osd >= map->max_osd);
+               if (ceph_decode_entity_addr(p, end, &addr))
+                       goto e_inval;
                pr_info("osd%d up\n", osd);
                map->osd_state[osd] |= CEPH_OSD_EXISTS | CEPH_OSD_UP;
                map->osd_addr[osd] = addr;
index 74cafc0..64305e7 100644 (file)
 
 #include <linux/ceph/libceph.h>
 
-/*
- * build a vector of user pages
- */
-struct page **ceph_get_direct_page_vector(const void __user *data,
-                                         int num_pages, bool write_page)
-{
-       struct page **pages;
-       int got = 0;
-       int rc = 0;
-
-       pages = kmalloc_array(num_pages, sizeof(*pages), GFP_NOFS);
-       if (!pages)
-               return ERR_PTR(-ENOMEM);
-
-       while (got < num_pages) {
-               rc = get_user_pages_fast(
-                   (unsigned long)data + ((unsigned long)got * PAGE_SIZE),
-                   num_pages - got, write_page ? FOLL_WRITE : 0, pages + got);
-               if (rc < 0)
-                       break;
-               BUG_ON(rc == 0);
-               got += rc;
-       }
-       if (rc < 0)
-               goto fail;
-       return pages;
-
-fail:
-       ceph_put_page_vector(pages, got, false);
-       return ERR_PTR(rc);
-}
-EXPORT_SYMBOL(ceph_get_direct_page_vector);
-
 void ceph_put_page_vector(struct page **pages, int num_pages, bool dirty)
 {
        int i;
index c36462d..3b3fa75 100644 (file)
@@ -259,3 +259,20 @@ int ceph_extent_to_file(struct ceph_file_layout *l,
        return 0;
 }
 EXPORT_SYMBOL(ceph_extent_to_file);
+
+u64 ceph_get_num_objects(struct ceph_file_layout *l, u64 size)
+{
+       u64 period = (u64)l->stripe_count * l->object_size;
+       u64 num_periods = DIV64_U64_ROUND_UP(size, period);
+       u64 remainder_bytes;
+       u64 remainder_objs = 0;
+
+       div64_u64_rem(size, period, &remainder_bytes);
+       if (remainder_bytes > 0 &&
+           remainder_bytes < (u64)l->stripe_count * l->stripe_unit)
+               remainder_objs = l->stripe_count -
+                           DIV_ROUND_UP_ULL(remainder_bytes, l->stripe_unit);
+
+       return num_periods * l->stripe_count - remainder_objs;
+}
+EXPORT_SYMBOL(ceph_get_num_objects);
index 47f6386..4e2a79b 100644 (file)
@@ -4335,7 +4335,7 @@ BPF_CALL_5(bpf_setsockopt, struct bpf_sock_ops_kern *, bpf_sock,
                                                    TCP_CA_NAME_MAX-1));
                        name[TCP_CA_NAME_MAX-1] = 0;
                        ret = tcp_set_congestion_control(sk, name, false,
-                                                        reinit);
+                                                        reinit, true);
                } else {
                        struct tcp_sock *tp = tcp_sk(sk);
 
@@ -6884,20 +6884,30 @@ static bool sock_addr_is_valid_access(int off, int size,
        case bpf_ctx_range(struct bpf_sock_addr, msg_src_ip4):
        case bpf_ctx_range_till(struct bpf_sock_addr, msg_src_ip6[0],
                                msg_src_ip6[3]):
-               /* Only narrow read access allowed for now. */
                if (type == BPF_READ) {
                        bpf_ctx_record_field_size(info, size_default);
+
+                       if (bpf_ctx_wide_access_ok(off, size,
+                                                  struct bpf_sock_addr,
+                                                  user_ip6))
+                               return true;
+
+                       if (bpf_ctx_wide_access_ok(off, size,
+                                                  struct bpf_sock_addr,
+                                                  msg_src_ip6))
+                               return true;
+
                        if (!bpf_ctx_narrow_access_ok(off, size, size_default))
                                return false;
                } else {
-                       if (bpf_ctx_wide_store_ok(off, size,
-                                                 struct bpf_sock_addr,
-                                                 user_ip6))
+                       if (bpf_ctx_wide_access_ok(off, size,
+                                                  struct bpf_sock_addr,
+                                                  user_ip6))
                                return true;
 
-                       if (bpf_ctx_wide_store_ok(off, size,
-                                                 struct bpf_sock_addr,
-                                                 msg_src_ip6))
+                       if (bpf_ctx_wide_access_ok(off, size,
+                                                  struct bpf_sock_addr,
+                                                  msg_src_ip6))
                                return true;
 
                        if (size != size_default)
index 76f8db3..d63b970 100644 (file)
@@ -165,7 +165,7 @@ void flow_rule_match_enc_opts(const struct flow_rule *rule,
 }
 EXPORT_SYMBOL(flow_rule_match_enc_opts);
 
-struct flow_block_cb *flow_block_cb_alloc(struct net *net, tc_setup_cb_t *cb,
+struct flow_block_cb *flow_block_cb_alloc(flow_setup_cb_t *cb,
                                          void *cb_ident, void *cb_priv,
                                          void (*release)(void *cb_priv))
 {
@@ -175,7 +175,6 @@ struct flow_block_cb *flow_block_cb_alloc(struct net *net, tc_setup_cb_t *cb,
        if (!block_cb)
                return ERR_PTR(-ENOMEM);
 
-       block_cb->net = net;
        block_cb->cb = cb;
        block_cb->cb_ident = cb_ident;
        block_cb->cb_priv = cb_priv;
@@ -194,14 +193,13 @@ void flow_block_cb_free(struct flow_block_cb *block_cb)
 }
 EXPORT_SYMBOL(flow_block_cb_free);
 
-struct flow_block_cb *flow_block_cb_lookup(struct flow_block_offload *f,
-                                          tc_setup_cb_t *cb, void *cb_ident)
+struct flow_block_cb *flow_block_cb_lookup(struct flow_block *block,
+                                          flow_setup_cb_t *cb, void *cb_ident)
 {
        struct flow_block_cb *block_cb;
 
-       list_for_each_entry(block_cb, f->driver_block_list, driver_list) {
-               if (block_cb->net == f->net &&
-                   block_cb->cb == cb &&
+       list_for_each_entry(block_cb, &block->cb_list, list) {
+               if (block_cb->cb == cb &&
                    block_cb->cb_ident == cb_ident)
                        return block_cb;
        }
@@ -228,7 +226,7 @@ unsigned int flow_block_cb_decref(struct flow_block_cb *block_cb)
 }
 EXPORT_SYMBOL(flow_block_cb_decref);
 
-bool flow_block_cb_is_busy(tc_setup_cb_t *cb, void *cb_ident,
+bool flow_block_cb_is_busy(flow_setup_cb_t *cb, void *cb_ident,
                           struct list_head *driver_block_list)
 {
        struct flow_block_cb *block_cb;
@@ -245,7 +243,8 @@ EXPORT_SYMBOL(flow_block_cb_is_busy);
 
 int flow_block_cb_setup_simple(struct flow_block_offload *f,
                               struct list_head *driver_block_list,
-                              tc_setup_cb_t *cb, void *cb_ident, void *cb_priv,
+                              flow_setup_cb_t *cb,
+                              void *cb_ident, void *cb_priv,
                               bool ingress_only)
 {
        struct flow_block_cb *block_cb;
@@ -261,8 +260,7 @@ int flow_block_cb_setup_simple(struct flow_block_offload *f,
                if (flow_block_cb_is_busy(cb, cb_ident, driver_block_list))
                        return -EBUSY;
 
-               block_cb = flow_block_cb_alloc(f->net, cb, cb_ident,
-                                              cb_priv, NULL);
+               block_cb = flow_block_cb_alloc(cb, cb_ident, cb_priv, NULL);
                if (IS_ERR(block_cb))
                        return PTR_ERR(block_cb);
 
@@ -270,7 +268,7 @@ int flow_block_cb_setup_simple(struct flow_block_offload *f,
                list_add_tail(&block_cb->driver_list, driver_block_list);
                return 0;
        case FLOW_BLOCK_UNBIND:
-               block_cb = flow_block_cb_lookup(f, cb, cb_ident);
+               block_cb = flow_block_cb_lookup(f->block, cb, cb_ident);
                if (!block_cb)
                        return -ENOENT;
 
index 742cea4..f79e61c 100644 (file)
@@ -1124,6 +1124,7 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
 
                        atomic_set(&neigh->probes,
                                   NEIGH_VAR(neigh->parms, UCAST_PROBES));
+                       neigh_del_timer(neigh);
                        neigh->nud_state     = NUD_INCOMPLETE;
                        neigh->updated = now;
                        next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
@@ -1140,6 +1141,7 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
                }
        } else if (neigh->nud_state & NUD_STALE) {
                neigh_dbg(2, "neigh %p is delayed\n", neigh);
+               neigh_del_timer(neigh);
                neigh->nud_state = NUD_DELAY;
                neigh->updated = jiffies;
                neigh_add_timer(neigh, jiffies +
@@ -3374,8 +3376,6 @@ void neigh_app_ns(struct neighbour *n)
 EXPORT_SYMBOL(neigh_app_ns);
 
 #ifdef CONFIG_SYSCTL
-static int zero;
-static int int_max = INT_MAX;
 static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN);
 
 static int proc_unres_qlen(struct ctl_table *ctl, int write,
@@ -3384,7 +3384,7 @@ static int proc_unres_qlen(struct ctl_table *ctl, int write,
        int size, ret;
        struct ctl_table tmp = *ctl;
 
-       tmp.extra1 = &zero;
+       tmp.extra1 = SYSCTL_ZERO;
        tmp.extra2 = &unres_qlen_max;
        tmp.data = &size;
 
@@ -3449,8 +3449,8 @@ static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write,
        struct ctl_table tmp = *ctl;
        int ret;
 
-       tmp.extra1 = &zero;
-       tmp.extra2 = &int_max;
+       tmp.extra1 = SYSCTL_ZERO;
+       tmp.extra2 = SYSCTL_INT_MAX;
 
        ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
        neigh_proc_update(ctl, write);
@@ -3595,24 +3595,24 @@ static struct neigh_sysctl_table {
                        .procname       = "gc_thresh1",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .extra1         = &zero,
-                       .extra2         = &int_max,
+                       .extra1         = SYSCTL_ZERO,
+                       .extra2         = SYSCTL_INT_MAX,
                        .proc_handler   = proc_dointvec_minmax,
                },
                [NEIGH_VAR_GC_THRESH2] = {
                        .procname       = "gc_thresh2",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .extra1         = &zero,
-                       .extra2         = &int_max,
+                       .extra1         = SYSCTL_ZERO,
+                       .extra2         = SYSCTL_INT_MAX,
                        .proc_handler   = proc_dointvec_minmax,
                },
                [NEIGH_VAR_GC_THRESH3] = {
                        .procname       = "gc_thresh3",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .extra1         = &zero,
-                       .extra2         = &int_max,
+                       .extra1         = SYSCTL_ZERO,
+                       .extra2         = SYSCTL_INT_MAX,
                        .proc_handler   = proc_dointvec_minmax,
                },
                {},
index 6f1e31f..0338820 100644 (file)
@@ -762,7 +762,7 @@ void skb_dump(const char *level, const struct sk_buff *skb, bool full_pkt)
                printk("%sdev name=%s feat=0x%pNF\n",
                       level, dev->name, &dev->features);
        if (sk)
-               printk("%ssk family=%hu type=%hu proto=%hu\n",
+               printk("%ssk family=%hu type=%u proto=%u\n",
                       level, sk->sk_family, sk->sk_type, sk->sk_protocol);
 
        if (full_pkt && headroom)
index f920471..8da5b3a 100644 (file)
@@ -22,8 +22,6 @@
 #include <net/busy_poll.h>
 #include <net/pkt_sched.h>
 
-static int zero = 0;
-static int one = 1;
 static int two __maybe_unused = 2;
 static int min_sndbuf = SOCK_MIN_SNDBUF;
 static int min_rcvbuf = SOCK_MIN_RCVBUF;
@@ -390,10 +388,10 @@ static struct ctl_table net_core_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax_bpf_enable,
 # ifdef CONFIG_BPF_JIT_ALWAYS_ON
-               .extra1         = &one,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ONE,
+               .extra2         = SYSCTL_ONE,
 # else
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &two,
 # endif
        },
@@ -404,7 +402,7 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0600,
                .proc_handler   = proc_dointvec_minmax_bpf_restricted,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &two,
        },
        {
@@ -413,8 +411,8 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0600,
                .proc_handler   = proc_dointvec_minmax_bpf_restricted,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
 # endif
        {
@@ -461,8 +459,8 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE
        },
 #ifdef CONFIG_RPS
        {
@@ -493,7 +491,7 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
        {
                .procname       = "busy_read",
@@ -501,7 +499,7 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
 #endif
 #ifdef CONFIG_NET_SCHED
@@ -533,7 +531,7 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = SYSCTL_ONE,
                .extra2         = &max_skb_frags,
        },
        {
@@ -542,7 +540,7 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
        {
                .procname       = "fb_tunnels_only_for_init_net",
@@ -550,8 +548,8 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        {
                .procname       = "devconf_inherit_init_net",
@@ -559,7 +557,7 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &two,
        },
        {
@@ -578,7 +576,7 @@ static struct ctl_table netns_core_table[] = {
                .data           = &init_net.core.sysctl_somaxconn,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .proc_handler   = proc_dointvec_minmax
        },
        { }
index b59040f..ee8d4f5 100644 (file)
@@ -16,9 +16,7 @@
 #endif
 
 /* Boundary values */
-static int             zero     = 0,
-                       one      = 1,
-                       u8_max   = 0xFF;
+static int             u8_max   = 0xFF;
 static unsigned long   seqw_min = DCCPF_SEQ_WMIN,
                        seqw_max = 0xFFFFFFFF;          /* maximum on 32 bit */
 
@@ -38,7 +36,7 @@ static struct ctl_table dccp_default_table[] = {
                .maxlen         = sizeof(sysctl_dccp_rx_ccid),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &u8_max,              /* RFC 4340, 10. */
        },
        {
@@ -47,7 +45,7 @@ static struct ctl_table dccp_default_table[] = {
                .maxlen         = sizeof(sysctl_dccp_tx_ccid),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &u8_max,              /* RFC 4340, 10. */
        },
        {
@@ -56,7 +54,7 @@ static struct ctl_table dccp_default_table[] = {
                .maxlen         = sizeof(sysctl_dccp_request_retries),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = SYSCTL_ONE,
                .extra2         = &u8_max,
        },
        {
@@ -65,7 +63,7 @@ static struct ctl_table dccp_default_table[] = {
                .maxlen         = sizeof(sysctl_dccp_retries1),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &u8_max,
        },
        {
@@ -74,7 +72,7 @@ static struct ctl_table dccp_default_table[] = {
                .maxlen         = sizeof(sysctl_dccp_retries2),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &u8_max,
        },
        {
@@ -83,7 +81,7 @@ static struct ctl_table dccp_default_table[] = {
                .maxlen         = sizeof(sysctl_dccp_tx_qlen),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
        {
                .procname       = "sync_ratelimit",
index 614c38e..33f4117 100644 (file)
@@ -951,7 +951,7 @@ static int dsa_slave_setup_tc_block(struct net_device *dev,
                                    struct flow_block_offload *f)
 {
        struct flow_block_cb *block_cb;
-       tc_setup_cb_t *cb;
+       flow_setup_cb_t *cb;
 
        if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
                cb = dsa_slave_setup_tc_block_cb_ig;
@@ -967,7 +967,7 @@ static int dsa_slave_setup_tc_block(struct net_device *dev,
                if (flow_block_cb_is_busy(cb, dev, &dsa_slave_block_cb_list))
                        return -EBUSY;
 
-               block_cb = flow_block_cb_alloc(f->net, cb, dev, dev, NULL);
+               block_cb = flow_block_cb_alloc(cb, dev, dev, NULL);
                if (IS_ERR(block_cb))
                        return PTR_ERR(block_cb);
 
@@ -975,7 +975,7 @@ static int dsa_slave_setup_tc_block(struct net_device *dev,
                list_add_tail(&block_cb->driver_list, &dsa_slave_block_cb_list);
                return 0;
        case FLOW_BLOCK_UNBIND:
-               block_cb = flow_block_cb_lookup(f, cb, dev);
+               block_cb = flow_block_cb_lookup(f->block, cb, dev);
                if (!block_cb)
                        return -ENOENT;
 
index 1d96c9d..26363d7 100644 (file)
@@ -216,6 +216,7 @@ static struct sk_buff
                if (!skb) {
                        dev_err_ratelimited(dp->ds->dev,
                                            "Failed to copy stampable skb\n");
+                       spin_unlock(&sp->data->meta_lock);
                        return NULL;
                }
                sja1105_transfer_meta(skb, meta);
index 317339c..e8bc939 100644 (file)
@@ -388,6 +388,11 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
        fib_combine_itag(itag, &res);
 
        dev_match = fib_info_nh_uses_dev(res.fi, dev);
+       /* This is not common, loopback packets retain skb_dst so normally they
+        * would not even hit this slow path.
+        */
+       dev_match = dev_match || (res.type == RTN_LOCAL &&
+                                 dev == net->loopback_dev);
        if (dev_match) {
                ret = FIB_RES_NHC(res)->nhc_scope >= RT_SCOPE_HOST;
                return ret;
index 4d6bf7a..6bdb1ab 100644 (file)
@@ -416,8 +416,8 @@ clusterip_tg(struct sk_buff *skb, const struct xt_action_param *par)
             ctinfo == IP_CT_RELATED_REPLY))
                return XT_CONTINUE;
 
-       /* ip_conntrack_icmp guarantees us that we only have ICMP_ECHO,
-        * TIMESTAMP, INFO_REQUEST or ADDRESS type icmp packets from here
+       /* nf_conntrack_proto_icmp guarantees us that we only have ICMP_ECHO,
+        * TIMESTAMP, INFO_REQUEST or ICMP_ADDRESS type icmp packets from here
         * on, which all have an ID field [relevant for hashing]. */
 
        hash = clusterip_hashfn(skb, cipinfo->config);
index 8e7f84e..0e70f3f 100644 (file)
@@ -36,6 +36,8 @@ synproxy_tg4(struct sk_buff *skb, const struct xt_action_param *par)
                        opts.options |= XT_SYNPROXY_OPT_ECN;
 
                opts.options &= info->options;
+               opts.mss_encode = opts.mss;
+               opts.mss = info->mss;
                if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP)
                        synproxy_init_timestamp_cookie(info, &opts);
                else
index 5903167..cc23f1c 100644 (file)
@@ -78,6 +78,7 @@ static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
        flow.flowi4_mark = info->flags & XT_RPFILTER_VALID_MARK ? skb->mark : 0;
        flow.flowi4_tos = RT_TOS(iph->tos);
        flow.flowi4_scope = RT_SCOPE_UNIVERSE;
+       flow.flowi4_oif = l3mdev_master_ifindex_rcu(xt_in(par));
 
        return rpfilter_lookup_reverse(xt_net(par), &flow, xt_in(par), info->flags) ^ invert;
 }
index 87b711f..3e2685c 100644 (file)
@@ -221,11 +221,11 @@ static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
                int ret;
 
                rtp_exp->tuple.dst.u.udp.port = htons(nated_port);
-               ret = nf_ct_expect_related(rtp_exp);
+               ret = nf_ct_expect_related(rtp_exp, 0);
                if (ret == 0) {
                        rtcp_exp->tuple.dst.u.udp.port =
                            htons(nated_port + 1);
-                       ret = nf_ct_expect_related(rtcp_exp);
+                       ret = nf_ct_expect_related(rtcp_exp, 0);
                        if (ret == 0)
                                break;
                        else if (ret == -EBUSY) {
@@ -296,7 +296,7 @@ static int nat_t120(struct sk_buff *skb, struct nf_conn *ct,
                int ret;
 
                exp->tuple.dst.u.tcp.port = htons(nated_port);
-               ret = nf_ct_expect_related(exp);
+               ret = nf_ct_expect_related(exp, 0);
                if (ret == 0)
                        break;
                else if (ret != -EBUSY) {
@@ -352,7 +352,7 @@ static int nat_h245(struct sk_buff *skb, struct nf_conn *ct,
                int ret;
 
                exp->tuple.dst.u.tcp.port = htons(nated_port);
-               ret = nf_ct_expect_related(exp);
+               ret = nf_ct_expect_related(exp, 0);
                if (ret == 0)
                        break;
                else if (ret != -EBUSY) {
@@ -444,7 +444,7 @@ static int nat_q931(struct sk_buff *skb, struct nf_conn *ct,
                int ret;
 
                exp->tuple.dst.u.tcp.port = htons(nated_port);
-               ret = nf_ct_expect_related(exp);
+               ret = nf_ct_expect_related(exp, 0);
                if (ret == 0)
                        break;
                else if (ret != -EBUSY) {
@@ -537,7 +537,7 @@ static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct,
                int ret;
 
                exp->tuple.dst.u.tcp.port = htons(nated_port);
-               ret = nf_ct_expect_related(exp);
+               ret = nf_ct_expect_related(exp, 0);
                if (ret == 0)
                        break;
                else if (ret != -EBUSY) {
index 7d66306..0b980e8 100644 (file)
@@ -28,8 +28,6 @@
 #include <net/protocol.h>
 #include <net/netevent.h>
 
-static int zero;
-static int one = 1;
 static int two = 2;
 static int four = 4;
 static int thousand = 1000;
@@ -576,7 +574,7 @@ static struct ctl_table ipv4_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
        {
                .procname       = "icmp_msgs_burst",
@@ -584,7 +582,7 @@ static struct ctl_table ipv4_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
        {
                .procname       = "udp_mem",
@@ -674,8 +672,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
 #endif
        {
@@ -763,8 +761,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = ipv4_fwd_update_priority,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        {
                .procname       = "ip_nonlocal_bind",
@@ -794,8 +792,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
 #endif
        {
@@ -864,7 +862,7 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one
+               .extra1         = SYSCTL_ONE
        },
 #endif
        {
@@ -969,7 +967,7 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &two,
        },
        {
@@ -1011,7 +1009,7 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_tfo_blackhole_detect_timeout,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
        {
@@ -1020,8 +1018,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        {
                .procname       = "fib_multipath_hash_policy",
@@ -1029,8 +1027,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_fib_multipath_hash_policy,
-               .extra1         = &zero,
-               .extra2         = &two,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
 #endif
        {
@@ -1047,8 +1045,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
 #endif
        {
@@ -1078,7 +1076,7 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &four,
        },
        {
@@ -1222,7 +1220,7 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = SYSCTL_ONE,
                .extra2         = &gso_max_segs,
        },
        {
@@ -1231,7 +1229,7 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &one_day_secs
        },
        {
@@ -1240,8 +1238,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        {
                .procname       = "tcp_invalid_ratelimit",
@@ -1256,7 +1254,7 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &thousand,
        },
        {
@@ -1265,7 +1263,7 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &thousand,
        },
        {
@@ -1274,7 +1272,7 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(init_net.ipv4.sysctl_tcp_wmem),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = SYSCTL_ONE,
        },
        {
                .procname       = "tcp_rmem",
@@ -1282,7 +1280,7 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(init_net.ipv4.sysctl_tcp_rmem),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = SYSCTL_ONE,
        },
        {
                .procname       = "tcp_comp_sack_delay_ns",
@@ -1297,7 +1295,7 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &comp_sack_nr_max,
        },
        {
@@ -1306,7 +1304,7 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(init_net.ipv4.sysctl_udp_rmem_min),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one
+               .extra1         = SYSCTL_ONE
        },
        {
                .procname       = "udp_wmem_min",
@@ -1314,7 +1312,7 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(init_net.ipv4.sysctl_udp_wmem_min),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one
+               .extra1         = SYSCTL_ONE
        },
        { }
 };
index 7846afa..7769058 100644 (file)
@@ -2785,7 +2785,9 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
                name[val] = 0;
 
                lock_sock(sk);
-               err = tcp_set_congestion_control(sk, name, true, true);
+               err = tcp_set_congestion_control(sk, name, true, true,
+                                                ns_capable(sock_net(sk)->user_ns,
+                                                           CAP_NET_ADMIN));
                release_sock(sk);
                return err;
        }
index e1862b6..c445a81 100644 (file)
@@ -333,7 +333,8 @@ out:
  * tcp_reinit_congestion_control (if the current congestion control was
  * already initialized.
  */
-int tcp_set_congestion_control(struct sock *sk, const char *name, bool load, bool reinit)
+int tcp_set_congestion_control(struct sock *sk, const char *name, bool load,
+                              bool reinit, bool cap_net_admin)
 {
        struct inet_connection_sock *icsk = inet_csk(sk);
        const struct tcp_congestion_ops *ca;
@@ -369,8 +370,7 @@ int tcp_set_congestion_control(struct sock *sk, const char *name, bool load, boo
                } else {
                        err = -EBUSY;
                }
-       } else if (!((ca->flags & TCP_CONG_NON_RESTRICTED) ||
-                    ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))) {
+       } else if (!((ca->flags & TCP_CONG_NON_RESTRICTED) || cap_net_admin)) {
                err = -EPERM;
        } else if (!try_module_get(ca->owner)) {
                err = -EBUSY;
index 4af1f5d..6e4afc4 100644 (file)
@@ -1288,6 +1288,7 @@ int tcp_fragment(struct sock *sk, enum tcp_queue tcp_queue,
        struct tcp_sock *tp = tcp_sk(sk);
        struct sk_buff *buff;
        int nsize, old_factor;
+       long limit;
        int nlen;
        u8 flags;
 
@@ -1298,8 +1299,16 @@ int tcp_fragment(struct sock *sk, enum tcp_queue tcp_queue,
        if (nsize < 0)
                nsize = 0;
 
-       if (unlikely((sk->sk_wmem_queued >> 1) > sk->sk_sndbuf &&
-                    tcp_queue != TCP_FRAG_IN_WRITE_QUEUE)) {
+       /* tcp_sendmsg() can overshoot sk_wmem_queued by one full size skb.
+        * We need some allowance to not penalize applications setting small
+        * SO_SNDBUF values.
+        * Also allow first and last skb in retransmit queue to be split.
+        */
+       limit = sk->sk_sndbuf + 2 * SKB_TRUESIZE(GSO_MAX_SIZE);
+       if (unlikely((sk->sk_wmem_queued >> 1) > limit &&
+                    tcp_queue != TCP_FRAG_IN_WRITE_QUEUE &&
+                    skb != tcp_rtx_queue_head(sk) &&
+                    skb != tcp_rtx_queue_tail(sk))) {
                NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPWQUEUETOOBIG);
                return -ENOMEM;
        }
index c21862b..d88821c 100644 (file)
@@ -2170,7 +2170,7 @@ start_lookup:
 
 /* Initialize UDP checksum. If exited with zero value (success),
  * CHECKSUM_UNNECESSARY means, that no more checks are required.
- * Otherwise, csum completion requires chacksumming packet body,
+ * Otherwise, csum completion requires checksumming packet body,
  * including udp header and folding it to skb->csum.
  */
 static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh,
index 521e320..dc73888 100644 (file)
@@ -6432,8 +6432,6 @@ int addrconf_sysctl_disable_policy(struct ctl_table *ctl, int write,
 }
 
 static int minus_one = -1;
-static const int zero = 0;
-static const int one = 1;
 static const int two_five_five = 255;
 
 static const struct ctl_table addrconf_sysctl[] = {
@@ -6450,7 +6448,7 @@ static const struct ctl_table addrconf_sysctl[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = (void *)&one,
+               .extra1         = (void *)SYSCTL_ONE,
                .extra2         = (void *)&two_five_five,
        },
        {
@@ -6809,7 +6807,7 @@ static const struct ctl_table addrconf_sysctl[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = (void *)&zero,
+               .extra1         = (void *)SYSCTL_ZERO,
                .extra2         = (void *)&two_five_five,
        },
        {
index 49884f9..87f47bc 100644 (file)
@@ -1151,8 +1151,24 @@ add:
                        err = call_fib6_entry_notifiers(info->nl_net,
                                                        FIB_EVENT_ENTRY_ADD,
                                                        rt, extack);
-                       if (err)
+                       if (err) {
+                               struct fib6_info *sibling, *next_sibling;
+
+                               /* If the route has siblings, then it first
+                                * needs to be unlinked from them.
+                                */
+                               if (!rt->fib6_nsiblings)
+                                       return err;
+
+                               list_for_each_entry_safe(sibling, next_sibling,
+                                                        &rt->fib6_siblings,
+                                                        fib6_siblings)
+                                       sibling->fib6_nsiblings--;
+                               rt->fib6_nsiblings = 0;
+                               list_del_init(&rt->fib6_siblings);
+                               rt6_multipath_rebalance(next_sibling);
                                return err;
+                       }
                }
 
                rcu_assign_pointer(rt->fib6_next, iter);
index e77ea1e..5cdb4a6 100644 (file)
@@ -36,6 +36,8 @@ synproxy_tg6(struct sk_buff *skb, const struct xt_action_param *par)
                        opts.options |= XT_SYNPROXY_OPT_ECN;
 
                opts.options &= info->options;
+               opts.mss_encode = opts.mss;
+               opts.mss = info->mss;
                if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP)
                        synproxy_init_timestamp_cookie(info, &opts);
                else
index 6bcaf73..d800801 100644 (file)
@@ -55,7 +55,9 @@ static bool rpfilter_lookup_reverse6(struct net *net, const struct sk_buff *skb,
        if (rpfilter_addr_linklocal(&iph->saddr)) {
                lookup_flags |= RT6_LOOKUP_F_IFACE;
                fl6.flowi6_oif = dev->ifindex;
-       } else if ((flags & XT_RPFILTER_LOOSE) == 0)
+       /* Set flowi6_oif for vrf devices to lookup route in l3mdev domain. */
+       } else if (netif_is_l3_master(dev) || netif_is_l3_slave(dev) ||
+                 (flags & XT_RPFILTER_LOOSE) == 0)
                fl6.flowi6_oif = dev->ifindex;
 
        rt = (void *)ip6_route_lookup(net, &fl6, skb, lookup_flags);
@@ -70,7 +72,9 @@ static bool rpfilter_lookup_reverse6(struct net *net, const struct sk_buff *skb,
                goto out;
        }
 
-       if (rt->rt6i_idev->dev == dev || (flags & XT_RPFILTER_LOOSE))
+       if (rt->rt6i_idev->dev == dev ||
+           l3mdev_master_ifindex_rcu(rt->rt6i_idev->dev) == dev->ifindex ||
+           (flags & XT_RPFILTER_LOOSE))
                ret = true;
  out:
        ip6_rt_put(rt);
index 4d2e6b3..e49fec7 100644 (file)
@@ -2563,7 +2563,7 @@ static struct dst_entry *rt6_check(struct rt6_info *rt,
 {
        u32 rt_cookie = 0;
 
-       if ((from && !fib6_get_cookie_safe(from, &rt_cookie)) ||
+       if (!from || !fib6_get_cookie_safe(from, &rt_cookie) ||
            rt_cookie != cookie)
                return NULL;
 
@@ -6031,9 +6031,6 @@ int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
        return 0;
 }
 
-static int zero;
-static int one = 1;
-
 static struct ctl_table ipv6_route_table_template[] = {
        {
                .procname       =       "flush",
@@ -6111,8 +6108,8 @@ static struct ctl_table ipv6_route_table_template[] = {
                .maxlen         =       sizeof(int),
                .mode           =       0644,
                .proc_handler   =       proc_dointvec_minmax,
-               .extra1         =       &zero,
-               .extra2         =       &one,
+               .extra1         =       SYSCTL_ZERO,
+               .extra2         =       SYSCTL_ONE,
        },
        { }
 };
index 8061089..b2ccbc4 100644 (file)
@@ -900,12 +900,17 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
                           RT_TOS(tos), RT_SCOPE_UNIVERSE, IPPROTO_IPV6,
                           0, dst, tiph->saddr, 0, 0,
                           sock_net_uid(tunnel->net, NULL));
-       rt = ip_route_output_flow(tunnel->net, &fl4, NULL);
 
-       if (IS_ERR(rt)) {
-               dev->stats.tx_carrier_errors++;
-               goto tx_error_icmp;
+       rt = dst_cache_get_ip4(&tunnel->dst_cache, &fl4.saddr);
+       if (!rt) {
+               rt = ip_route_output_flow(tunnel->net, &fl4, NULL);
+               if (IS_ERR(rt)) {
+                       dev->stats.tx_carrier_errors++;
+                       goto tx_error_icmp;
+               }
+               dst_cache_set_ip4(&tunnel->dst_cache, &rt->dst, fl4.saddr);
        }
+
        if (rt->rt_type != RTN_UNICAST) {
                ip_rt_put(rt);
                dev->stats.tx_carrier_errors++;
index dc4c91e..ec8fcfc 100644 (file)
@@ -21,8 +21,6 @@
 #include <net/calipso.h>
 #endif
 
-static int zero;
-static int one = 1;
 static int flowlabel_reflect_max = 0x7;
 static int auto_flowlabels_min;
 static int auto_flowlabels_max = IP6_AUTO_FLOW_LABEL_MAX;
@@ -115,7 +113,7 @@ static struct ctl_table ipv6_table_template[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &flowlabel_reflect_max,
        },
        {
@@ -152,8 +150,8 @@ static struct ctl_table ipv6_table_template[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_rt6_multipath_hash_policy,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        {
                .procname       = "seg6_flowlabel",
@@ -179,7 +177,7 @@ static struct ctl_table ipv6_rotable[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one
+               .extra1         = SYSCTL_ONE
        },
 #ifdef CONFIG_NETLABEL
        {
index 76cc9e9..4d45806 100644 (file)
@@ -936,8 +936,10 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
 
        err = ieee80211_set_probe_resp(sdata, params->probe_resp,
                                       params->probe_resp_len, csa);
-       if (err < 0)
+       if (err < 0) {
+               kfree(new);
                return err;
+       }
        if (err == 0)
                changed |= BSS_CHANGED_AP_PROBE_RESP;
 
@@ -949,8 +951,10 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
                                                         params->civicloc,
                                                         params->civicloc_len);
 
-               if (err < 0)
+               if (err < 0) {
+                       kfree(new);
                        return err;
+               }
 
                changed |= BSS_CHANGED_FTM_RESPONDER;
        }
index acd4afb..c9a8a24 100644 (file)
@@ -187,11 +187,16 @@ int drv_conf_tx(struct ieee80211_local *local,
        if (!check_sdata_in_driver(sdata))
                return -EIO;
 
-       if (WARN_ONCE(params->cw_min == 0 ||
-                     params->cw_min > params->cw_max,
-                     "%s: invalid CW_min/CW_max: %d/%d\n",
-                     sdata->name, params->cw_min, params->cw_max))
+       if (params->cw_min == 0 || params->cw_min > params->cw_max) {
+               /*
+                * If we can't configure hardware anyway, don't warn. We may
+                * never have initialized the CW parameters.
+                */
+               WARN_ONCE(local->ops->conf_tx,
+                         "%s: invalid CW_min/CW_max: %d/%d\n",
+                         sdata->name, params->cw_min, params->cw_max);
                return -EINVAL;
+       }
 
        trace_drv_conf_tx(local, sdata, ac, params);
        if (local->ops->conf_tx)
index 198ec4f..c312741 100644 (file)
@@ -37,8 +37,6 @@
 
 #define MPLS_NEIGH_TABLE_UNSPEC (NEIGH_LINK_TABLE + 1)
 
-static int zero = 0;
-static int one = 1;
 static int label_limit = (1 << 20) - 1;
 static int ttl_max = 255;
 
@@ -2607,7 +2605,7 @@ static int mpls_platform_labels(struct ctl_table *table, int write,
                .data           = &platform_labels,
                .maxlen         = sizeof(int),
                .mode           = table->mode,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &label_limit,
        };
 
@@ -2636,8 +2634,8 @@ static const struct ctl_table mpls_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        {
                .procname       = "default_ttl",
@@ -2645,7 +2643,7 @@ static const struct ctl_table mpls_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = SYSCTL_ONE,
                .extra2         = &ttl_max,
        },
        { }
index 32a45c0..0d65f4d 100644 (file)
@@ -223,8 +223,6 @@ config NF_CONNTRACK_FTP
          of Network Address Translation on them.
 
          This is FTP support on Layer 3 independent connection tracking.
-         Layer 3 independent connection tracking is experimental scheme
-         which generalize ip_conntrack to support other layer 3 protocols.
 
          To compile it as a module, choose M here.  If unsure, say N.
 
@@ -338,7 +336,7 @@ config NF_CONNTRACK_SIP
        help
          SIP is an application-layer control protocol that can establish,
          modify, and terminate multimedia sessions (conferences) such as
-         Internet telephony calls. With the ip_conntrack_sip and
+         Internet telephony calls. With the nf_conntrack_sip and
          the nf_nat_sip modules you can support the protocol on a connection
          tracking/NATing firewall.
 
@@ -1313,7 +1311,7 @@ config NETFILTER_XT_MATCH_HELPER
        depends on NETFILTER_ADVANCED
        help
          Helper matching allows you to match packets in dynamic connections
-         tracked by a conntrack-helper, ie. ip_conntrack_ftp
+         tracked by a conntrack-helper, ie. nf_conntrack_ftp
 
          To compile it as a module, choose M here.  If unsure, say Y.
 
index 07e0967..060565e 100644 (file)
@@ -1726,7 +1726,6 @@ static int ip_vs_zero_all(struct netns_ipvs *ipvs)
 
 #ifdef CONFIG_SYSCTL
 
-static int zero;
 static int three = 3;
 
 static int
@@ -1935,7 +1934,7 @@ static struct ctl_table vs_vars[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &three,
        },
        {
index 4035419..08adcb2 100644 (file)
@@ -231,7 +231,7 @@ void ip_vs_nfct_expect_related(struct sk_buff *skb, struct nf_conn *ct,
 
        IP_VS_DBG_BUF(7, "%s: ct=%p, expect tuple=" FMT_TUPLE "\n",
                      __func__, ct, ARG_TUPLE(&exp->tuple));
-       nf_ct_expect_related(exp);
+       nf_ct_expect_related(exp, 0);
        nf_ct_expect_put(exp);
 }
 EXPORT_SYMBOL(ip_vs_nfct_expect_related);
index 42ee659..d011d2e 100644 (file)
@@ -159,7 +159,7 @@ static int amanda_help(struct sk_buff *skb,
                if (nf_nat_amanda && ct->status & IPS_NAT_MASK)
                        ret = nf_nat_amanda(skb, ctinfo, protoff,
                                            off - dataoff, len, exp);
-               else if (nf_ct_expect_related(exp) != 0) {
+               else if (nf_ct_expect_related(exp, 0) != 0) {
                        nf_ct_helper_log(skb, ct, "cannot add expectation");
                        ret = NF_DROP;
                }
index 921a7b9..1ba6bec 100644 (file)
@@ -68,7 +68,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
        exp->class                = NF_CT_EXPECT_CLASS_DEFAULT;
        exp->helper               = NULL;
 
-       nf_ct_expect_related(exp);
+       nf_ct_expect_related(exp, 0);
        nf_ct_expect_put(exp);
 
        nf_ct_refresh(ct, skb, timeout * HZ);
index bdfeace..a542761 100644 (file)
@@ -1817,9 +1817,7 @@ EXPORT_SYMBOL_GPL(nf_ct_kill_acct);
 #include <linux/netfilter/nfnetlink_conntrack.h>
 #include <linux/mutex.h>
 
-/* Generic function for tcp/udp/sctp/dccp and alike. This needs to be
- * in ip_conntrack_core, since we don't want the protocols to autoload
- * or depend on ctnetlink */
+/* Generic function for tcp/udp/sctp/dccp and alike. */
 int nf_ct_port_tuple_to_nlattr(struct sk_buff *skb,
                               const struct nf_conntrack_tuple *tuple)
 {
index ffd1f49..65364de 100644 (file)
@@ -249,13 +249,22 @@ static inline int expect_clash(const struct nf_conntrack_expect *a,
 static inline int expect_matches(const struct nf_conntrack_expect *a,
                                 const struct nf_conntrack_expect *b)
 {
-       return a->master == b->master &&
-              nf_ct_tuple_equal(&a->tuple, &b->tuple) &&
+       return nf_ct_tuple_equal(&a->tuple, &b->tuple) &&
               nf_ct_tuple_mask_equal(&a->mask, &b->mask) &&
               net_eq(nf_ct_net(a->master), nf_ct_net(b->master)) &&
               nf_ct_zone_equal_any(a->master, nf_ct_zone(b->master));
 }
 
+static bool master_matches(const struct nf_conntrack_expect *a,
+                          const struct nf_conntrack_expect *b,
+                          unsigned int flags)
+{
+       if (flags & NF_CT_EXP_F_SKIP_MASTER)
+               return true;
+
+       return a->master == b->master;
+}
+
 /* Generally a bad idea to call this: could have matched already. */
 void nf_ct_unexpect_related(struct nf_conntrack_expect *exp)
 {
@@ -399,7 +408,8 @@ static void evict_oldest_expect(struct nf_conn *master,
                nf_ct_remove_expect(last);
 }
 
-static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
+static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect,
+                                      unsigned int flags)
 {
        const struct nf_conntrack_expect_policy *p;
        struct nf_conntrack_expect *i;
@@ -417,8 +427,10 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
        }
        h = nf_ct_expect_dst_hash(net, &expect->tuple);
        hlist_for_each_entry_safe(i, next, &nf_ct_expect_hash[h], hnode) {
-               if (expect_matches(i, expect)) {
-                       if (i->class != expect->class)
+               if (master_matches(i, expect, flags) &&
+                   expect_matches(i, expect)) {
+                       if (i->class != expect->class ||
+                           i->master != expect->master)
                                return -EALREADY;
 
                        if (nf_ct_remove_expect(i))
@@ -453,12 +465,12 @@ out:
 }
 
 int nf_ct_expect_related_report(struct nf_conntrack_expect *expect,
-                               u32 portid, int report)
+                               u32 portid, int report, unsigned int flags)
 {
        int ret;
 
        spin_lock_bh(&nf_conntrack_expect_lock);
-       ret = __nf_ct_expect_check(expect);
+       ret = __nf_ct_expect_check(expect, flags);
        if (ret < 0)
                goto out;
 
index 8c6c11b..0ecb3e2 100644 (file)
@@ -525,7 +525,7 @@ skip_nl_seq:
                                 protoff, matchoff, matchlen, exp);
        else {
                /* Can't expect this?  Best to drop packet now. */
-               if (nf_ct_expect_related(exp) != 0) {
+               if (nf_ct_expect_related(exp, 0) != 0) {
                        nf_ct_helper_log(skb, ct, "cannot add expectation");
                        ret = NF_DROP;
                } else
index 8f6ba81..573cb44 100644 (file)
@@ -1,11 +1,10 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * ip_conntrack_helper_h323_asn1.c - BER and PER decoding library for H.323
- *                                  conntrack/NAT module.
+ * BER and PER decoding library for H.323 conntrack/NAT module.
  *
  * Copyright (c) 2006 by Jing Min Zhao <zhaojingmin@users.sourceforge.net>
  *
- * See ip_conntrack_helper_h323_asn1.h for details.
+ * See nf_conntrack_helper_h323_asn1.h for details.
  */
 
 #ifdef __KERNEL__
index 6497e5f..8ba037b 100644 (file)
@@ -305,8 +305,8 @@ static int expect_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
                ret = nat_rtp_rtcp(skb, ct, ctinfo, protoff, data, dataoff,
                                   taddr, port, rtp_port, rtp_exp, rtcp_exp);
        } else {                /* Conntrack only */
-               if (nf_ct_expect_related(rtp_exp) == 0) {
-                       if (nf_ct_expect_related(rtcp_exp) == 0) {
+               if (nf_ct_expect_related(rtp_exp, 0) == 0) {
+                       if (nf_ct_expect_related(rtcp_exp, 0) == 0) {
                                pr_debug("nf_ct_h323: expect RTP ");
                                nf_ct_dump_tuple(&rtp_exp->tuple);
                                pr_debug("nf_ct_h323: expect RTCP ");
@@ -364,7 +364,7 @@ static int expect_t120(struct sk_buff *skb,
                ret = nat_t120(skb, ct, ctinfo, protoff, data, dataoff, taddr,
                               port, exp);
        } else {                /* Conntrack only */
-               if (nf_ct_expect_related(exp) == 0) {
+               if (nf_ct_expect_related(exp, 0) == 0) {
                        pr_debug("nf_ct_h323: expect T.120 ");
                        nf_ct_dump_tuple(&exp->tuple);
                } else
@@ -701,7 +701,7 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct,
                ret = nat_h245(skb, ct, ctinfo, protoff, data, dataoff, taddr,
                               port, exp);
        } else {                /* Conntrack only */
-               if (nf_ct_expect_related(exp) == 0) {
+               if (nf_ct_expect_related(exp, 0) == 0) {
                        pr_debug("nf_ct_q931: expect H.245 ");
                        nf_ct_dump_tuple(&exp->tuple);
                } else
@@ -825,7 +825,7 @@ static int expect_callforwarding(struct sk_buff *skb,
                                         protoff, data, dataoff,
                                         taddr, port, exp);
        } else {                /* Conntrack only */
-               if (nf_ct_expect_related(exp) == 0) {
+               if (nf_ct_expect_related(exp, 0) == 0) {
                        pr_debug("nf_ct_q931: expect Call Forwarding ");
                        nf_ct_dump_tuple(&exp->tuple);
                } else
@@ -1284,7 +1284,7 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct,
                ret = nat_q931(skb, ct, ctinfo, protoff, data,
                               taddr, i, port, exp);
        } else {                /* Conntrack only */
-               if (nf_ct_expect_related(exp) == 0) {
+               if (nf_ct_expect_related(exp, 0) == 0) {
                        pr_debug("nf_ct_ras: expect Q.931 ");
                        nf_ct_dump_tuple(&exp->tuple);
 
@@ -1349,7 +1349,7 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct,
                          IPPROTO_UDP, NULL, &port);
        exp->helper = nf_conntrack_helper_ras;
 
-       if (nf_ct_expect_related(exp) == 0) {
+       if (nf_ct_expect_related(exp, 0) == 0) {
                pr_debug("nf_ct_ras: expect RAS ");
                nf_ct_dump_tuple(&exp->tuple);
        } else
@@ -1561,7 +1561,7 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct,
        exp->flags = NF_CT_EXPECT_PERMANENT;
        exp->helper = nf_conntrack_helper_q931;
 
-       if (nf_ct_expect_related(exp) == 0) {
+       if (nf_ct_expect_related(exp, 0) == 0) {
                pr_debug("nf_ct_ras: expect Q.931 ");
                nf_ct_dump_tuple(&exp->tuple);
        } else
@@ -1615,7 +1615,7 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct,
        exp->flags = NF_CT_EXPECT_PERMANENT;
        exp->helper = nf_conntrack_helper_q931;
 
-       if (nf_ct_expect_related(exp) == 0) {
+       if (nf_ct_expect_related(exp, 0) == 0) {
                pr_debug("nf_ct_ras: expect Q.931 ");
                nf_ct_dump_tuple(&exp->tuple);
        } else
index 7ac156f..e40988a 100644 (file)
@@ -213,7 +213,7 @@ static int help(struct sk_buff *skb, unsigned int protoff,
                                                 addr_beg_p - ib_ptr,
                                                 addr_end_p - addr_beg_p,
                                                 exp);
-                       else if (nf_ct_expect_related(exp) != 0) {
+                       else if (nf_ct_expect_related(exp, 0) != 0) {
                                nf_ct_helper_log(skb, ct,
                                                 "cannot add expectation");
                                ret = NF_DROP;
index 1b77444..6aa01eb 100644 (file)
@@ -2616,7 +2616,7 @@ ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct,
        if (IS_ERR(exp))
                return PTR_ERR(exp);
 
-       err = nf_ct_expect_related_report(exp, portid, report);
+       err = nf_ct_expect_related_report(exp, portid, report, 0);
        nf_ct_expect_put(exp);
        return err;
 }
@@ -3367,7 +3367,7 @@ ctnetlink_create_expect(struct net *net,
                goto err_rcu;
        }
 
-       err = nf_ct_expect_related_report(exp, portid, report);
+       err = nf_ct_expect_related_report(exp, portid, report, 0);
        nf_ct_expect_put(exp);
 err_rcu:
        rcu_read_unlock();
index b22042a..a971183 100644 (file)
@@ -234,9 +234,9 @@ static int exp_gre(struct nf_conn *ct, __be16 callid, __be16 peer_callid)
        nf_nat_pptp_exp_gre = rcu_dereference(nf_nat_pptp_hook_exp_gre);
        if (nf_nat_pptp_exp_gre && ct->status & IPS_NAT_MASK)
                nf_nat_pptp_exp_gre(exp_orig, exp_reply);
-       if (nf_ct_expect_related(exp_orig) != 0)
+       if (nf_ct_expect_related(exp_orig, 0) != 0)
                goto out_put_both;
-       if (nf_ct_expect_related(exp_reply) != 0)
+       if (nf_ct_expect_related(exp_reply, 0) != 0)
                goto out_unexpect_orig;
 
        /* Add GRE keymap entries */
index c2eb365..5b05487 100644 (file)
@@ -1,7 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * ip_conntrack_proto_gre.c - Version 3.0
- *
  * Connection tracking protocol helper module for GRE.
  *
  * GRE is a generic encapsulation protocol, which is generally not very
index dd53e2b..097deba 100644 (file)
@@ -215,7 +215,7 @@ int nf_conntrack_icmpv4_error(struct nf_conn *tmpl,
                return -NF_ACCEPT;
        }
 
-       /* See ip_conntrack_proto_tcp.c */
+       /* See nf_conntrack_proto_tcp.c */
        if (state->net->ct.sysctl_checksum &&
            state->hook == NF_INET_PRE_ROUTING &&
            nf_ip_checksum(skb, state->hook, dataoff, IPPROTO_ICMP)) {
index d5fdfa0..85c1f8c 100644 (file)
@@ -472,6 +472,7 @@ static bool tcp_in_window(const struct nf_conn *ct,
        struct ip_ct_tcp_state *receiver = &state->seen[!dir];
        const struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple;
        __u32 seq, ack, sack, end, win, swin;
+       u16 win_raw;
        s32 receiver_offset;
        bool res, in_recv_win;
 
@@ -480,7 +481,8 @@ static bool tcp_in_window(const struct nf_conn *ct,
         */
        seq = ntohl(tcph->seq);
        ack = sack = ntohl(tcph->ack_seq);
-       win = ntohs(tcph->window);
+       win_raw = ntohs(tcph->window);
+       win = win_raw;
        end = segment_seq_plus_len(seq, skb->len, dataoff, tcph);
 
        if (receiver->flags & IP_CT_TCP_FLAG_SACK_PERM)
@@ -655,14 +657,14 @@ static bool tcp_in_window(const struct nf_conn *ct,
                            && state->last_seq == seq
                            && state->last_ack == ack
                            && state->last_end == end
-                           && state->last_win == win)
+                           && state->last_win == win_raw)
                                state->retrans++;
                        else {
                                state->last_dir = dir;
                                state->last_seq = seq;
                                state->last_ack = ack;
                                state->last_end = end;
-                               state->last_win = win;
+                               state->last_win = win_raw;
                                state->retrans = 0;
                        }
                }
index 81448c3..1aebd65 100644 (file)
@@ -153,7 +153,7 @@ static int help(struct sk_buff *skb,
        nf_ct_dump_tuple(&exp->tuple);
 
        /* Can't expect this?  Best to drop packet now. */
-       if (nf_ct_expect_related(exp) != 0) {
+       if (nf_ct_expect_related(exp, 0) != 0) {
                nf_ct_helper_log(skb, ct, "cannot add expectation");
                ret = NF_DROP;
        }
index 1072517..b83dc9b 100644 (file)
@@ -977,11 +977,15 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
                /* -EALREADY handling works around end-points that send
                 * SDP messages with identical port but different media type,
                 * we pretend expectation was set up.
+                * It also works in the case that SDP messages are sent with
+                * identical expect tuples but for different master conntracks.
                 */
-               int errp = nf_ct_expect_related(rtp_exp);
+               int errp = nf_ct_expect_related(rtp_exp,
+                                               NF_CT_EXP_F_SKIP_MASTER);
 
                if (errp == 0 || errp == -EALREADY) {
-                       int errcp = nf_ct_expect_related(rtcp_exp);
+                       int errcp = nf_ct_expect_related(rtcp_exp,
+                                               NF_CT_EXP_F_SKIP_MASTER);
 
                        if (errcp == 0 || errcp == -EALREADY)
                                ret = NF_ACCEPT;
@@ -1296,7 +1300,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,
                ret = hooks->expect(skb, protoff, dataoff, dptr, datalen,
                                    exp, matchoff, matchlen);
        else {
-               if (nf_ct_expect_related(exp) != 0) {
+               if (nf_ct_expect_related(exp, 0) != 0) {
                        nf_ct_helper_log(skb, ct, "cannot add expectation");
                        ret = NF_DROP;
                } else
index df6d6d6..80ee53f 100644 (file)
@@ -78,7 +78,7 @@ static int tftp_help(struct sk_buff *skb,
                nf_nat_tftp = rcu_dereference(nf_nat_tftp_hook);
                if (nf_nat_tftp && ct->status & IPS_NAT_MASK)
                        ret = nf_nat_tftp(skb, ctinfo, exp);
-               else if (nf_ct_expect_related(exp) != 0) {
+               else if (nf_ct_expect_related(exp, 0) != 0) {
                        nf_ct_helper_log(skb, ct, "cannot add expectation");
                        ret = NF_DROP;
                }
index a352604..3bc7e08 100644 (file)
@@ -48,7 +48,7 @@ static unsigned int help(struct sk_buff *skb,
                int res;
 
                exp->tuple.dst.u.tcp.port = htons(port);
-               res = nf_ct_expect_related(exp);
+               res = nf_ct_expect_related(exp, 0);
                if (res == 0)
                        break;
                else if (res != -EBUSY) {
index 9ab4104..3f6023e 100644 (file)
@@ -519,7 +519,7 @@ another_round:
  * and NF_INET_LOCAL_OUT, we change the destination to map into the
  * range. It might not be possible to get a unique tuple, but we try.
  * At worst (or if we race), we will end up with a final duplicate in
- * __ip_conntrack_confirm and drop the packet. */
+ * __nf_conntrack_confirm and drop the packet. */
 static void
 get_unique_tuple(struct nf_conntrack_tuple *tuple,
                 const struct nf_conntrack_tuple *orig_tuple,
index d48484a..aace676 100644 (file)
@@ -91,7 +91,7 @@ static unsigned int nf_nat_ftp(struct sk_buff *skb,
                int ret;
 
                exp->tuple.dst.u.tcp.port = htons(port);
-               ret = nf_ct_expect_related(exp);
+               ret = nf_ct_expect_related(exp, 0);
                if (ret == 0)
                        break;
                else if (ret != -EBUSY) {
index dfb7ef8..c691ab8 100644 (file)
@@ -53,7 +53,7 @@ static unsigned int help(struct sk_buff *skb,
                int ret;
 
                exp->tuple.dst.u.tcp.port = htons(port);
-               ret = nf_ct_expect_related(exp);
+               ret = nf_ct_expect_related(exp, 0);
                if (ret == 0)
                        break;
                else if (ret != -EBUSY) {
index e338d91..f0a735e 100644 (file)
@@ -414,7 +414,7 @@ static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff,
                int ret;
 
                exp->tuple.dst.u.udp.port = htons(port);
-               ret = nf_ct_expect_related(exp);
+               ret = nf_ct_expect_related(exp, NF_CT_EXP_F_SKIP_MASTER);
                if (ret == 0)
                        break;
                else if (ret != -EBUSY) {
@@ -607,7 +607,8 @@ static unsigned int nf_nat_sdp_media(struct sk_buff *skb, unsigned int protoff,
                int ret;
 
                rtp_exp->tuple.dst.u.udp.port = htons(port);
-               ret = nf_ct_expect_related(rtp_exp);
+               ret = nf_ct_expect_related(rtp_exp,
+                                          NF_CT_EXP_F_SKIP_MASTER);
                if (ret == -EBUSY)
                        continue;
                else if (ret < 0) {
@@ -615,7 +616,8 @@ static unsigned int nf_nat_sdp_media(struct sk_buff *skb, unsigned int protoff,
                        break;
                }
                rtcp_exp->tuple.dst.u.udp.port = htons(port + 1);
-               ret = nf_ct_expect_related(rtcp_exp);
+               ret = nf_ct_expect_related(rtcp_exp,
+                                          NF_CT_EXP_F_SKIP_MASTER);
                if (ret == 0)
                        break;
                else if (ret == -EBUSY) {
index 833a11f..1a59113 100644 (file)
@@ -30,7 +30,7 @@ static unsigned int help(struct sk_buff *skb,
                = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port;
        exp->dir = IP_CT_DIR_REPLY;
        exp->expectfn = nf_nat_follow_master;
-       if (nf_ct_expect_related(exp) != 0) {
+       if (nf_ct_expect_related(exp, 0) != 0) {
                nf_ct_helper_log(skb, exp->master, "cannot add expectation");
                return NF_DROP;
        }
index b101f18..c769462 100644 (file)
@@ -470,7 +470,7 @@ synproxy_send_client_synack(struct net *net,
        struct iphdr *iph, *niph;
        struct tcphdr *nth;
        unsigned int tcp_hdr_size;
-       u16 mss = opts->mss;
+       u16 mss = opts->mss_encode;
 
        iph = ip_hdr(skb);
 
@@ -687,7 +687,7 @@ ipv4_synproxy_hook(void *priv, struct sk_buff *skb,
        state = &ct->proto.tcp;
        switch (state->state) {
        case TCP_CONNTRACK_CLOSE:
-               if (th->rst && !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
+               if (th->rst && CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL) {
                        nf_ct_seqadj_init(ct, ctinfo, synproxy->isn -
                                                      ntohl(th->seq) + 1);
                        break;
@@ -884,7 +884,7 @@ synproxy_send_client_synack_ipv6(struct net *net,
        struct ipv6hdr *iph, *niph;
        struct tcphdr *nth;
        unsigned int tcp_hdr_size;
-       u16 mss = opts->mss;
+       u16 mss = opts->mss_encode;
 
        iph = ipv6_hdr(skb);
 
@@ -1111,7 +1111,7 @@ ipv6_synproxy_hook(void *priv, struct sk_buff *skb,
        state = &ct->proto.tcp;
        switch (state->state) {
        case TCP_CONNTRACK_CLOSE:
-               if (th->rst && !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
+               if (th->rst && CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL) {
                        nf_ct_seqadj_init(ct, ctinfo, synproxy->isn -
                                                      ntohl(th->seq) + 1);
                        break;
index ed17a7c..605a7cf 100644 (file)
@@ -1662,7 +1662,7 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
 
                chain->flags |= NFT_BASE_CHAIN | flags;
                basechain->policy = NF_ACCEPT;
-               INIT_LIST_HEAD(&basechain->cb_list);
+               flow_block_init(&basechain->flow_block);
        } else {
                chain = kzalloc(sizeof(*chain), GFP_KERNEL);
                if (chain == NULL)
@@ -1900,6 +1900,8 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk,
 
        if (nla[NFTA_CHAIN_FLAGS])
                flags = ntohl(nla_get_be32(nla[NFTA_CHAIN_FLAGS]));
+       else if (chain)
+               flags = chain->flags;
 
        nft_ctx_init(&ctx, net, skb, nlh, family, table, chain, nla);
 
index 2c33028..64f5fd5 100644 (file)
@@ -116,7 +116,7 @@ static int nft_setup_cb_call(struct nft_base_chain *basechain,
        struct flow_block_cb *block_cb;
        int err;
 
-       list_for_each_entry(block_cb, &basechain->cb_list, list) {
+       list_for_each_entry(block_cb, &basechain->flow_block.cb_list, list) {
                err = block_cb->cb(type, type_data, block_cb->cb_priv);
                if (err < 0)
                        return err;
@@ -154,7 +154,7 @@ static int nft_flow_offload_rule(struct nft_trans *trans,
 static int nft_flow_offload_bind(struct flow_block_offload *bo,
                                 struct nft_base_chain *basechain)
 {
-       list_splice(&bo->cb_list, &basechain->cb_list);
+       list_splice(&bo->cb_list, &basechain->flow_block.cb_list);
        return 0;
 }
 
@@ -198,6 +198,7 @@ static int nft_flow_offload_chain(struct nft_trans *trans,
                return -EOPNOTSUPP;
 
        bo.command = cmd;
+       bo.block = &basechain->flow_block;
        bo.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
        bo.extack = &extack;
        INIT_LIST_HEAD(&bo.cb_list);
index 92077d4..4abbb45 100644 (file)
@@ -578,7 +578,7 @@ static int nfnetlink_bind(struct net *net, int group)
        ss = nfnetlink_get_subsys(type << 8);
        rcu_read_unlock();
        if (!ss)
-               request_module("nfnetlink-subsys-%d", type);
+               request_module_nowait("nfnetlink-subsys-%d", type);
        return 0;
 }
 #endif
index 3fd540b..b5d5d07 100644 (file)
@@ -193,7 +193,7 @@ static inline void nft_chain_filter_inet_init(void) {}
 static inline void nft_chain_filter_inet_fini(void) {}
 #endif /* CONFIG_NF_TABLES_IPV6 */
 
-#ifdef CONFIG_NF_TABLES_BRIDGE
+#if IS_ENABLED(CONFIG_NF_TABLES_BRIDGE)
 static unsigned int
 nft_do_chain_bridge(void *priv,
                    struct sk_buff *skb,
index 2f89bde..ff9ac8a 100644 (file)
@@ -142,3 +142,6 @@ MODULE_ALIAS_NFT_CHAIN(AF_INET, "nat");
 #ifdef CONFIG_NF_TABLES_IPV6
 MODULE_ALIAS_NFT_CHAIN(AF_INET6, "nat");
 #endif
+#ifdef CONFIG_NF_TABLES_INET
+MODULE_ALIAS_NFT_CHAIN(1, "nat");      /* NFPROTO_INET */
+#endif
index 827ab61..46ca8bc 100644 (file)
@@ -1252,7 +1252,7 @@ static void nft_ct_expect_obj_eval(struct nft_object *obj,
                          priv->l4proto, NULL, &priv->dport);
        exp->timeout.expires = jiffies + priv->timeout * HZ;
 
-       if (nf_ct_expect_related(exp) != 0)
+       if (nf_ct_expect_related(exp, 0) != 0)
                regs->verdict.code = NF_DROP;
 }
 
index fe93e73..b836d55 100644 (file)
@@ -129,7 +129,7 @@ static int nft_symhash_init(const struct nft_ctx *ctx,
        priv->dreg = nft_parse_register(tb[NFTA_HASH_DREG]);
 
        priv->modulus = ntohl(nla_get_be32(tb[NFTA_HASH_MODULUS]));
-       if (priv->modulus <= 1)
+       if (priv->modulus < 1)
                return -ERANGE;
 
        if (priv->offset + priv->modulus - 1 < priv->offset)
index 76866f7..f1b1d94 100644 (file)
@@ -546,7 +546,7 @@ nft_meta_select_ops(const struct nft_ctx *ctx,
        if (tb[NFTA_META_DREG] && tb[NFTA_META_SREG])
                return ERR_PTR(-EINVAL);
 
-#ifdef CONFIG_NF_TABLES_BRIDGE
+#if IS_ENABLED(CONFIG_NF_TABLES_BRIDGE) && IS_MODULE(CONFIG_NFT_BRIDGE_META)
        if (ctx->family == NFPROTO_BRIDGE)
                return ERR_PTR(-EAGAIN);
 #endif
index 8487eef..43eeb1f 100644 (file)
@@ -291,4 +291,4 @@ module_exit(nft_redir_module_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo@debian.org>");
-MODULE_ALIAS_NFT_EXPR("nat");
+MODULE_ALIAS_NFT_EXPR("redir");
index 80060ad..928e661 100644 (file)
@@ -31,6 +31,8 @@ static void nft_synproxy_tcp_options(struct synproxy_options *opts,
                opts->options |= NF_SYNPROXY_OPT_ECN;
 
        opts->options &= priv->info.options;
+       opts->mss_encode = opts->mss;
+       opts->mss = info->mss;
        if (opts->options & NF_SYNPROXY_OPT_TIMESTAMP)
                synproxy_init_timestamp_cookie(info, opts);
        else
index dca3b1e..bc89e16 100644 (file)
@@ -59,7 +59,7 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies)
 void ovs_flow_stats_update(struct sw_flow *flow, __be16 tcp_flags,
                           const struct sk_buff *skb)
 {
-       struct flow_stats *stats;
+       struct sw_flow_stats *stats;
        unsigned int cpu = smp_processor_id();
        int len = skb->len + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0);
 
@@ -87,7 +87,7 @@ void ovs_flow_stats_update(struct sw_flow *flow, __be16 tcp_flags,
                        if (likely(flow->stats_last_writer != -1) &&
                            likely(!rcu_access_pointer(flow->stats[cpu]))) {
                                /* Try to allocate CPU-specific stats. */
-                               struct flow_stats *new_stats;
+                               struct sw_flow_stats *new_stats;
 
                                new_stats =
                                        kmem_cache_alloc_node(flow_stats_cache,
@@ -134,7 +134,7 @@ void ovs_flow_stats_get(const struct sw_flow *flow,
 
        /* We open code this to make sure cpu 0 is always considered */
        for (cpu = 0; cpu < nr_cpu_ids; cpu = cpumask_next(cpu, &flow->cpu_used_mask)) {
-               struct flow_stats *stats = rcu_dereference_ovsl(flow->stats[cpu]);
+               struct sw_flow_stats *stats = rcu_dereference_ovsl(flow->stats[cpu]);
 
                if (stats) {
                        /* Local CPU may write on non-local stats, so we must
@@ -158,7 +158,7 @@ void ovs_flow_stats_clear(struct sw_flow *flow)
 
        /* We open code this to make sure cpu 0 is always considered */
        for (cpu = 0; cpu < nr_cpu_ids; cpu = cpumask_next(cpu, &flow->cpu_used_mask)) {
-               struct flow_stats *stats = ovsl_dereference(flow->stats[cpu]);
+               struct sw_flow_stats *stats = ovsl_dereference(flow->stats[cpu]);
 
                if (stats) {
                        spin_lock_bh(&stats->lock);
index 3e2cc22..a5506e2 100644 (file)
@@ -194,7 +194,7 @@ struct sw_flow_actions {
        struct nlattr actions[];
 };
 
-struct flow_stats {
+struct sw_flow_stats {
        u64 packet_count;               /* Number of packets matched. */
        u64 byte_count;                 /* Number of bytes matched. */
        unsigned long used;             /* Last used time (in jiffies). */
@@ -216,7 +216,7 @@ struct sw_flow {
        struct cpumask cpu_used_mask;
        struct sw_flow_mask *mask;
        struct sw_flow_actions __rcu *sf_acts;
-       struct flow_stats __rcu *stats[]; /* One for each CPU.  First one
+       struct sw_flow_stats __rcu *stats[]; /* One for each CPU.  First one
                                           * is allocated at flow creation time,
                                           * the rest are allocated on demand
                                           * while holding the 'stats[0].lock'.
index 988fd8a..cf3582c 100644 (file)
@@ -66,7 +66,7 @@ void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src,
 struct sw_flow *ovs_flow_alloc(void)
 {
        struct sw_flow *flow;
-       struct flow_stats *stats;
+       struct sw_flow_stats *stats;
 
        flow = kmem_cache_zalloc(flow_cache, GFP_KERNEL);
        if (!flow)
@@ -110,7 +110,7 @@ static void flow_free(struct sw_flow *flow)
        for (cpu = 0; cpu < nr_cpu_ids; cpu = cpumask_next(cpu, &flow->cpu_used_mask))
                if (flow->stats[cpu])
                        kmem_cache_free(flow_stats_cache,
-                                       (struct flow_stats __force *)flow->stats[cpu]);
+                                       (struct sw_flow_stats __force *)flow->stats[cpu]);
        kmem_cache_free(flow_cache, flow);
 }
 
@@ -712,13 +712,13 @@ int ovs_flow_init(void)
 
        flow_cache = kmem_cache_create("sw_flow", sizeof(struct sw_flow)
                                       + (nr_cpu_ids
-                                         * sizeof(struct flow_stats *)),
+                                         * sizeof(struct sw_flow_stats *)),
                                       0, 0, NULL);
        if (flow_cache == NULL)
                return -ENOMEM;
 
        flow_stats_cache
-               = kmem_cache_create("sw_flow_stats", sizeof(struct flow_stats),
+               = kmem_cache_create("sw_flow_stats", sizeof(struct sw_flow_stats),
                                    0, SLAB_HWCACHE_ALIGN, NULL);
        if (flow_stats_cache == NULL) {
                kmem_cache_destroy(flow_cache);
index 66c03c7..303c6ee 100644 (file)
@@ -156,6 +156,7 @@ struct rds_ib_connection {
 
        /* To control the number of wrs from fastreg */
        atomic_t                i_fastreg_wrs;
+       atomic_t                i_fastreg_inuse_count;
 
        /* interrupt handling */
        struct tasklet_struct   i_send_tasklet;
index c36d89c..fddaa09 100644 (file)
@@ -40,6 +40,7 @@
 #include "rds_single_path.h"
 #include "rds.h"
 #include "ib.h"
+#include "ib_mr.h"
 
 /*
  * Set the selected protocol version
@@ -526,7 +527,6 @@ static int rds_ib_setup_qp(struct rds_connection *conn)
        attr.qp_type = IB_QPT_RC;
        attr.send_cq = ic->i_send_cq;
        attr.recv_cq = ic->i_recv_cq;
-       atomic_set(&ic->i_fastreg_wrs, RDS_IB_DEFAULT_FR_WR);
 
        /*
         * XXX this can fail if max_*_wr is too large?  Are we supposed
@@ -993,6 +993,11 @@ void rds_ib_conn_path_shutdown(struct rds_conn_path *cp)
                                ic->i_cm_id, err);
                }
 
+               /* kick off "flush_worker" for all pools in order to reap
+                * all FRMR registrations that are still marked "FRMR_IS_INUSE"
+                */
+               rds_ib_flush_mrs();
+
                /*
                 * We want to wait for tx and rx completion to finish
                 * before we tear down the connection, but we have to be
@@ -1005,6 +1010,7 @@ void rds_ib_conn_path_shutdown(struct rds_conn_path *cp)
                wait_event(rds_ib_ring_empty_wait,
                           rds_ib_ring_empty(&ic->i_recv_ring) &&
                           (atomic_read(&ic->i_signaled_sends) == 0) &&
+                          (atomic_read(&ic->i_fastreg_inuse_count) == 0) &&
                           (atomic_read(&ic->i_fastreg_wrs) == RDS_IB_DEFAULT_FR_WR));
                tasklet_kill(&ic->i_send_tasklet);
                tasklet_kill(&ic->i_recv_tasklet);
@@ -1132,6 +1138,7 @@ int rds_ib_conn_alloc(struct rds_connection *conn, gfp_t gfp)
        spin_lock_init(&ic->i_ack_lock);
 #endif
        atomic_set(&ic->i_signaled_sends, 0);
+       atomic_set(&ic->i_fastreg_wrs, RDS_IB_DEFAULT_FR_WR);
 
        /*
         * rds_ib_conn_shutdown() waits for these to be emptied so they
index 32ae26e..06ecf9d 100644 (file)
 
 #include "ib_mr.h"
 
+static inline void
+rds_transition_frwr_state(struct rds_ib_mr *ibmr,
+                         enum rds_ib_fr_state old_state,
+                         enum rds_ib_fr_state new_state)
+{
+       if (cmpxchg(&ibmr->u.frmr.fr_state,
+                   old_state, new_state) == old_state &&
+           old_state == FRMR_IS_INUSE) {
+               /* enforce order of ibmr->u.frmr.fr_state update
+                * before decrementing i_fastreg_inuse_count
+                */
+               smp_mb__before_atomic();
+               atomic_dec(&ibmr->ic->i_fastreg_inuse_count);
+               if (waitqueue_active(&rds_ib_ring_empty_wait))
+                       wake_up(&rds_ib_ring_empty_wait);
+       }
+}
+
 static struct rds_ib_mr *rds_ib_alloc_frmr(struct rds_ib_device *rds_ibdev,
                                           int npages)
 {
@@ -75,6 +93,8 @@ static struct rds_ib_mr *rds_ib_alloc_frmr(struct rds_ib_device *rds_ibdev,
                pool->max_items_soft = pool->max_items;
 
        frmr->fr_state = FRMR_IS_FREE;
+       init_waitqueue_head(&frmr->fr_inv_done);
+       init_waitqueue_head(&frmr->fr_reg_done);
        return ibmr;
 
 out_no_cigar:
@@ -116,13 +136,19 @@ static int rds_ib_post_reg_frmr(struct rds_ib_mr *ibmr)
        if (unlikely(ret != ibmr->sg_len))
                return ret < 0 ? ret : -EINVAL;
 
+       if (cmpxchg(&frmr->fr_state,
+                   FRMR_IS_FREE, FRMR_IS_INUSE) != FRMR_IS_FREE)
+               return -EBUSY;
+
+       atomic_inc(&ibmr->ic->i_fastreg_inuse_count);
+
        /* Perform a WR for the fast_reg_mr. Each individual page
         * in the sg list is added to the fast reg page list and placed
         * inside the fast_reg_mr WR.  The key used is a rolling 8bit
         * counter, which should guarantee uniqueness.
         */
        ib_update_fast_reg_key(frmr->mr, ibmr->remap_count++);
-       frmr->fr_state = FRMR_IS_INUSE;
+       frmr->fr_reg = true;
 
        memset(&reg_wr, 0, sizeof(reg_wr));
        reg_wr.wr.wr_id = (unsigned long)(void *)ibmr;
@@ -138,12 +164,23 @@ static int rds_ib_post_reg_frmr(struct rds_ib_mr *ibmr)
        ret = ib_post_send(ibmr->ic->i_cm_id->qp, &reg_wr.wr, NULL);
        if (unlikely(ret)) {
                /* Failure here can be because of -ENOMEM as well */
-               frmr->fr_state = FRMR_IS_STALE;
+               rds_transition_frwr_state(ibmr, FRMR_IS_INUSE, FRMR_IS_STALE);
+
                atomic_inc(&ibmr->ic->i_fastreg_wrs);
                if (printk_ratelimit())
                        pr_warn("RDS/IB: %s returned error(%d)\n",
                                __func__, ret);
+               goto out;
        }
+
+       /* Wait for the registration to complete in order to prevent an invalid
+        * access error resulting from a race between the memory region already
+        * being accessed while registration is still pending.
+        */
+       wait_event(frmr->fr_reg_done, !frmr->fr_reg);
+
+out:
+
        return ret;
 }
 
@@ -255,12 +292,29 @@ static int rds_ib_post_inv(struct rds_ib_mr *ibmr)
 
        ret = ib_post_send(i_cm_id->qp, s_wr, NULL);
        if (unlikely(ret)) {
-               frmr->fr_state = FRMR_IS_STALE;
+               rds_transition_frwr_state(ibmr, FRMR_IS_INUSE, FRMR_IS_STALE);
                frmr->fr_inv = false;
+               /* enforce order of frmr->fr_inv update
+                * before incrementing i_fastreg_wrs
+                */
+               smp_mb__before_atomic();
                atomic_inc(&ibmr->ic->i_fastreg_wrs);
                pr_err("RDS/IB: %s returned error(%d)\n", __func__, ret);
                goto out;
        }
+
+       /* Wait for the FRMR_IS_FREE (or FRMR_IS_STALE) transition in order to
+        * 1) avoid a silly bouncing between "clean_list" and "drop_list"
+        *    triggered by function "rds_ib_reg_frmr" as it is releases frmr
+        *    regions whose state is not "FRMR_IS_FREE" right away.
+        * 2) prevents an invalid access error in a race
+        *    from a pending "IB_WR_LOCAL_INV" operation
+        *    with a teardown ("dma_unmap_sg", "put_page")
+        *    and de-registration ("ib_dereg_mr") of the corresponding
+        *    memory region.
+        */
+       wait_event(frmr->fr_inv_done, frmr->fr_state != FRMR_IS_INUSE);
+
 out:
        return ret;
 }
@@ -271,7 +325,7 @@ void rds_ib_mr_cqe_handler(struct rds_ib_connection *ic, struct ib_wc *wc)
        struct rds_ib_frmr *frmr = &ibmr->u.frmr;
 
        if (wc->status != IB_WC_SUCCESS) {
-               frmr->fr_state = FRMR_IS_STALE;
+               rds_transition_frwr_state(ibmr, FRMR_IS_INUSE, FRMR_IS_STALE);
                if (rds_conn_up(ic->conn))
                        rds_ib_conn_error(ic->conn,
                                          "frmr completion <%pI4,%pI4> status %u(%s), vendor_err 0x%x, disconnecting and reconnecting\n",
@@ -283,10 +337,20 @@ void rds_ib_mr_cqe_handler(struct rds_ib_connection *ic, struct ib_wc *wc)
        }
 
        if (frmr->fr_inv) {
-               frmr->fr_state = FRMR_IS_FREE;
+               rds_transition_frwr_state(ibmr, FRMR_IS_INUSE, FRMR_IS_FREE);
                frmr->fr_inv = false;
+               wake_up(&frmr->fr_inv_done);
        }
 
+       if (frmr->fr_reg) {
+               frmr->fr_reg = false;
+               wake_up(&frmr->fr_reg_done);
+       }
+
+       /* enforce order of frmr->{fr_reg,fr_inv} update
+        * before incrementing i_fastreg_wrs
+        */
+       smp_mb__before_atomic();
        atomic_inc(&ic->i_fastreg_wrs);
 }
 
@@ -295,14 +359,18 @@ void rds_ib_unreg_frmr(struct list_head *list, unsigned int *nfreed,
 {
        struct rds_ib_mr *ibmr, *next;
        struct rds_ib_frmr *frmr;
-       int ret = 0;
+       int ret = 0, ret2;
        unsigned int freed = *nfreed;
 
        /* String all ib_mr's onto one list and hand them to ib_unmap_fmr */
        list_for_each_entry(ibmr, list, unmap_list) {
-               if (ibmr->sg_dma_len)
-                       ret |= rds_ib_post_inv(ibmr);
+               if (ibmr->sg_dma_len) {
+                       ret2 = rds_ib_post_inv(ibmr);
+                       if (ret2 && !ret)
+                               ret = ret2;
+               }
        }
+
        if (ret)
                pr_warn("RDS/IB: %s failed (err=%d)\n", __func__, ret);
 
index 5da12c2..9045a8c 100644 (file)
@@ -57,6 +57,9 @@ struct rds_ib_frmr {
        struct ib_mr            *mr;
        enum rds_ib_fr_state    fr_state;
        bool                    fr_inv;
+       wait_queue_head_t       fr_inv_done;
+       bool                    fr_reg;
+       wait_queue_head_t       fr_reg_done;
        struct ib_send_wr       fr_wr;
        unsigned int            dma_npages;
        unsigned int            sg_byte_len;
@@ -97,6 +100,7 @@ struct rds_ib_mr_pool {
        struct llist_head       free_list;      /* unused MRs */
        struct llist_head       clean_list;     /* unused & unmapped MRs */
        wait_queue_head_t       flush_wait;
+       spinlock_t              clean_lock;     /* "clean_list" concurrency */
 
        atomic_t                free_pinned;    /* memory pinned by free MRs */
        unsigned long           max_items;
index 0b347f4..c8c1e3a 100644 (file)
@@ -40,9 +40,6 @@
 
 struct workqueue_struct *rds_ib_mr_wq;
 
-static DEFINE_PER_CPU(unsigned long, clean_list_grace);
-#define CLEAN_LIST_BUSY_BIT 0
-
 static struct rds_ib_device *rds_ib_get_device(__be32 ipaddr)
 {
        struct rds_ib_device *rds_ibdev;
@@ -195,12 +192,11 @@ struct rds_ib_mr *rds_ib_reuse_mr(struct rds_ib_mr_pool *pool)
 {
        struct rds_ib_mr *ibmr = NULL;
        struct llist_node *ret;
-       unsigned long *flag;
+       unsigned long flags;
 
-       preempt_disable();
-       flag = this_cpu_ptr(&clean_list_grace);
-       set_bit(CLEAN_LIST_BUSY_BIT, flag);
+       spin_lock_irqsave(&pool->clean_lock, flags);
        ret = llist_del_first(&pool->clean_list);
+       spin_unlock_irqrestore(&pool->clean_lock, flags);
        if (ret) {
                ibmr = llist_entry(ret, struct rds_ib_mr, llnode);
                if (pool->pool_type == RDS_IB_MR_8K_POOL)
@@ -209,23 +205,9 @@ struct rds_ib_mr *rds_ib_reuse_mr(struct rds_ib_mr_pool *pool)
                        rds_ib_stats_inc(s_ib_rdma_mr_1m_reused);
        }
 
-       clear_bit(CLEAN_LIST_BUSY_BIT, flag);
-       preempt_enable();
        return ibmr;
 }
 
-static inline void wait_clean_list_grace(void)
-{
-       int cpu;
-       unsigned long *flag;
-
-       for_each_online_cpu(cpu) {
-               flag = &per_cpu(clean_list_grace, cpu);
-               while (test_bit(CLEAN_LIST_BUSY_BIT, flag))
-                       cpu_relax();
-       }
-}
-
 void rds_ib_sync_mr(void *trans_private, int direction)
 {
        struct rds_ib_mr *ibmr = trans_private;
@@ -324,8 +306,7 @@ static unsigned int llist_append_to_list(struct llist_head *llist,
  * of clusters.  Each cluster has linked llist nodes of
  * MR_CLUSTER_SIZE mrs that are ready for reuse.
  */
-static void list_to_llist_nodes(struct rds_ib_mr_pool *pool,
-                               struct list_head *list,
+static void list_to_llist_nodes(struct list_head *list,
                                struct llist_node **nodes_head,
                                struct llist_node **nodes_tail)
 {
@@ -402,8 +383,13 @@ int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool,
         */
        dirty_to_clean = llist_append_to_list(&pool->drop_list, &unmap_list);
        dirty_to_clean += llist_append_to_list(&pool->free_list, &unmap_list);
-       if (free_all)
+       if (free_all) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&pool->clean_lock, flags);
                llist_append_to_list(&pool->clean_list, &unmap_list);
+               spin_unlock_irqrestore(&pool->clean_lock, flags);
+       }
 
        free_goal = rds_ib_flush_goal(pool, free_all);
 
@@ -416,27 +402,20 @@ int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool,
                rds_ib_unreg_fmr(&unmap_list, &nfreed, &unpinned, free_goal);
 
        if (!list_empty(&unmap_list)) {
-               /* we have to make sure that none of the things we're about
-                * to put on the clean list would race with other cpus trying
-                * to pull items off.  The llist would explode if we managed to
-                * remove something from the clean list and then add it back again
-                * while another CPU was spinning on that same item in llist_del_first.
-                *
-                * This is pretty unlikely, but just in case  wait for an llist grace period
-                * here before adding anything back into the clean list.
-                */
-               wait_clean_list_grace();
-
-               list_to_llist_nodes(pool, &unmap_list, &clean_nodes, &clean_tail);
+               unsigned long flags;
+
+               list_to_llist_nodes(&unmap_list, &clean_nodes, &clean_tail);
                if (ibmr_ret) {
                        *ibmr_ret = llist_entry(clean_nodes, struct rds_ib_mr, llnode);
                        clean_nodes = clean_nodes->next;
                }
                /* more than one entry in llist nodes */
-               if (clean_nodes)
+               if (clean_nodes) {
+                       spin_lock_irqsave(&pool->clean_lock, flags);
                        llist_add_batch(clean_nodes, clean_tail,
                                        &pool->clean_list);
-
+                       spin_unlock_irqrestore(&pool->clean_lock, flags);
+               }
        }
 
        atomic_sub(unpinned, &pool->free_pinned);
@@ -471,7 +450,7 @@ struct rds_ib_mr *rds_ib_try_reuse_ibmr(struct rds_ib_mr_pool *pool)
                                rds_ib_stats_inc(s_ib_rdma_mr_8k_pool_depleted);
                        else
                                rds_ib_stats_inc(s_ib_rdma_mr_1m_pool_depleted);
-                       return ERR_PTR(-EAGAIN);
+                       break;
                }
 
                /* We do have some empty MRs. Flush them out. */
@@ -485,7 +464,7 @@ struct rds_ib_mr *rds_ib_try_reuse_ibmr(struct rds_ib_mr_pool *pool)
                        return ibmr;
        }
 
-       return ibmr;
+       return NULL;
 }
 
 static void rds_ib_mr_pool_flush_worker(struct work_struct *work)
@@ -610,6 +589,7 @@ struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *rds_ibdev,
        init_llist_head(&pool->free_list);
        init_llist_head(&pool->drop_list);
        init_llist_head(&pool->clean_list);
+       spin_lock_init(&pool->clean_lock);
        mutex_init(&pool->flush_lock);
        init_waitqueue_head(&pool->flush_wait);
        INIT_DELAYED_WORK(&pool->flush_worker, rds_ib_mr_pool_flush_worker);
index 1e3fa67..2bbb381 100644 (file)
@@ -11,7 +11,6 @@
 #include "ar-internal.h"
 
 static struct ctl_table_header *rxrpc_sysctl_reg_table;
-static const unsigned int one = 1;
 static const unsigned int four = 4;
 static const unsigned int thirtytwo = 32;
 static const unsigned int n_65535 = 65535;
@@ -97,7 +96,7 @@ static struct ctl_table rxrpc_sysctl_table[] = {
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = (void *)&one,
+               .extra1         = (void *)SYSCTL_ONE,
                .extra2         = (void *)&rxrpc_max_client_connections,
        },
        {
@@ -115,7 +114,7 @@ static struct ctl_table rxrpc_sysctl_table[] = {
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = (void *)&one,
+               .extra1         = (void *)SYSCTL_ONE,
                .extra2         = (void *)&n_max_acks,
        },
        {
@@ -124,7 +123,7 @@ static struct ctl_table rxrpc_sysctl_table[] = {
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = (void *)&one,
+               .extra1         = (void *)SYSCTL_ONE,
                .extra2         = (void *)&n_65535,
        },
        {
@@ -133,7 +132,7 @@ static struct ctl_table rxrpc_sysctl_table[] = {
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = (void *)&one,
+               .extra1         = (void *)SYSCTL_ONE,
                .extra2         = (void *)&four,
        },
 
index dd55b9a..afd2ba1 100644 (file)
@@ -942,7 +942,7 @@ config NET_ACT_TUNNEL_KEY
 
 config NET_ACT_CT
         tristate "connection tracking tc action"
-        depends on NET_CLS_ACT && NF_CONNTRACK
+        depends on NET_CLS_ACT && NF_CONNTRACK && NF_NAT
         help
          Say Y here to allow sending the packets to conntrack module.
 
index 278014e..efd3cfb 100644 (file)
@@ -691,6 +691,8 @@ static void tc_indr_block_ing_cmd(struct tc_indr_block_dev *indr_dev,
        if (!indr_dev->block)
                return;
 
+       bo.block = &indr_dev->block->flow_block;
+
        indr_block_cb->cb(indr_dev->dev, indr_block_cb->cb_priv, TC_SETUP_BLOCK,
                          &bo);
        tcf_block_setup(indr_dev->block, &bo);
@@ -775,6 +777,7 @@ static void tc_indr_block_call(struct tcf_block *block, struct net_device *dev,
                .command        = command,
                .binder_type    = ei->binder_type,
                .net            = dev_net(dev),
+               .block          = &block->flow_block,
                .block_shared   = tcf_block_shared(block),
                .extack         = extack,
        };
@@ -810,6 +813,7 @@ static int tcf_block_offload_cmd(struct tcf_block *block,
        bo.net = dev_net(dev);
        bo.command = command;
        bo.binder_type = ei->binder_type;
+       bo.block = &block->flow_block;
        bo.block_shared = tcf_block_shared(block);
        bo.extack = extack;
        INIT_LIST_HEAD(&bo.cb_list);
@@ -987,8 +991,8 @@ static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q,
                return ERR_PTR(-ENOMEM);
        }
        mutex_init(&block->lock);
+       flow_block_init(&block->flow_block);
        INIT_LIST_HEAD(&block->chain_list);
-       INIT_LIST_HEAD(&block->cb_list);
        INIT_LIST_HEAD(&block->owner_list);
        INIT_LIST_HEAD(&block->chain0.filter_chain_list);
 
@@ -1514,7 +1518,7 @@ void tcf_block_put(struct tcf_block *block)
 EXPORT_SYMBOL(tcf_block_put);
 
 static int
-tcf_block_playback_offloads(struct tcf_block *block, tc_setup_cb_t *cb,
+tcf_block_playback_offloads(struct tcf_block *block, flow_setup_cb_t *cb,
                            void *cb_priv, bool add, bool offload_in_use,
                            struct netlink_ext_ack *extack)
 {
@@ -1570,7 +1574,7 @@ static int tcf_block_bind(struct tcf_block *block,
 
                i++;
        }
-       list_splice(&bo->cb_list, &block->cb_list);
+       list_splice(&bo->cb_list, &block->flow_block.cb_list);
 
        return 0;
 
@@ -2152,6 +2156,9 @@ replay:
                tfilter_notify(net, skb, n, tp, block, q, parent, fh,
                               RTM_NEWTFILTER, false, rtnl_held);
                tfilter_put(tp, fh);
+               /* q pointer is NULL for shared blocks */
+               if (q)
+                       q->flags &= ~TCQ_F_CAN_BYPASS;
        }
 
 errout:
@@ -3155,7 +3162,7 @@ int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type,
        if (block->nooffloaddevcnt && err_stop)
                return -EOPNOTSUPP;
 
-       list_for_each_entry(block_cb, &block->cb_list, list) {
+       list_for_each_entry(block_cb, &block->flow_block.cb_list, list) {
                err = block_cb->cb(type, type_data, block_cb->cb_priv);
                if (err) {
                        if (err_stop)
index 691f718..3f7a9c0 100644 (file)
@@ -651,7 +651,7 @@ skip:
        }
 }
 
-static int cls_bpf_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb,
+static int cls_bpf_reoffload(struct tcf_proto *tp, bool add, flow_setup_cb_t *cb,
                             void *cb_priv, struct netlink_ext_ack *extack)
 {
        struct cls_bpf_head *head = rtnl_dereference(tp->root);
index 38d6e85..0541237 100644 (file)
@@ -1800,7 +1800,7 @@ fl_get_next_hw_filter(struct tcf_proto *tp, struct cls_fl_filter *f, bool add)
        return NULL;
 }
 
-static int fl_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb,
+static int fl_reoffload(struct tcf_proto *tp, bool add, flow_setup_cb_t *cb,
                        void *cb_priv, struct netlink_ext_ack *extack)
 {
        struct tcf_block *block = tp->chain->block;
index a30d2f8..455ea27 100644 (file)
@@ -282,7 +282,7 @@ skip:
        arg->count++;
 }
 
-static int mall_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb,
+static int mall_reoffload(struct tcf_proto *tp, bool add, flow_setup_cb_t *cb,
                          void *cb_priv, struct netlink_ext_ack *extack)
 {
        struct cls_mall_head *head = rtnl_dereference(tp->root);
index be9e46c..8614088 100644 (file)
@@ -1152,7 +1152,7 @@ static void u32_walk(struct tcf_proto *tp, struct tcf_walker *arg,
 }
 
 static int u32_reoffload_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht,
-                              bool add, tc_setup_cb_t *cb, void *cb_priv,
+                              bool add, flow_setup_cb_t *cb, void *cb_priv,
                               struct netlink_ext_ack *extack)
 {
        struct tc_cls_u32_offload cls_u32 = {};
@@ -1172,7 +1172,7 @@ static int u32_reoffload_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht,
 }
 
 static int u32_reoffload_knode(struct tcf_proto *tp, struct tc_u_knode *n,
-                              bool add, tc_setup_cb_t *cb, void *cb_priv,
+                              bool add, flow_setup_cb_t *cb, void *cb_priv,
                               struct netlink_ext_ack *extack)
 {
        struct tc_u_hnode *ht = rtnl_dereference(n->ht_down);
@@ -1213,7 +1213,7 @@ static int u32_reoffload_knode(struct tcf_proto *tp, struct tc_u_knode *n,
        return 0;
 }
 
-static int u32_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb,
+static int u32_reoffload(struct tcf_proto *tp, bool add, flow_setup_cb_t *cb,
                         void *cb_priv, struct netlink_ext_ack *extack)
 {
        struct tc_u_common *tp_c = tp->data;
index e2faf33..d59fbcc 100644 (file)
@@ -596,8 +596,6 @@ static unsigned long fq_codel_find(struct Qdisc *sch, u32 classid)
 static unsigned long fq_codel_bind(struct Qdisc *sch, unsigned long parent,
                              u32 classid)
 {
-       /* we cannot bypass queue discipline anymore */
-       sch->flags &= ~TCQ_F_CAN_BYPASS;
        return 0;
 }
 
index 420bd84..68404a9 100644 (file)
@@ -824,8 +824,6 @@ static unsigned long sfq_find(struct Qdisc *sch, u32 classid)
 static unsigned long sfq_bind(struct Qdisc *sch, unsigned long parent,
                              u32 classid)
 {
-       /* we cannot bypass queue discipline anymore */
-       sch->flags &= ~TCQ_F_CAN_BYPASS;
        return 0;
 }
 
index 388750d..c39db50 100644 (file)
@@ -75,7 +75,7 @@ struct taprio_sched {
        struct sched_gate_list __rcu *admin_sched;
        struct hrtimer advance_timer;
        struct list_head taprio_list;
-       int txtime_delay;
+       u32 txtime_delay;
 };
 
 static ktime_t sched_base_time(const struct sched_gate_list *sched)
@@ -1113,7 +1113,7 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt,
                        goto unlock;
                }
 
-               q->txtime_delay = nla_get_s32(tb[TCA_TAPRIO_ATTR_TXTIME_DELAY]);
+               q->txtime_delay = nla_get_u32(tb[TCA_TAPRIO_ATTR_TXTIME_DELAY]);
        }
 
        if (!TXTIME_ASSIST_IS_ENABLED(taprio_flags) &&
@@ -1430,7 +1430,7 @@ static int taprio_dump(struct Qdisc *sch, struct sk_buff *skb)
                goto options_error;
 
        if (q->txtime_delay &&
-           nla_put_s32(skb, TCA_TAPRIO_ATTR_TXTIME_DELAY, q->txtime_delay))
+           nla_put_u32(skb, TCA_TAPRIO_ATTR_TXTIME_DELAY, q->txtime_delay))
                goto options_error;
 
        if (oper && dump_schedule(skb, oper))
index ed39396..36bd8a6 100644 (file)
@@ -2582,8 +2582,7 @@ do_addr_param:
        case SCTP_PARAM_STATE_COOKIE:
                asoc->peer.cookie_len =
                        ntohs(param.p->length) - sizeof(struct sctp_paramhdr);
-               if (asoc->peer.cookie)
-                       kfree(asoc->peer.cookie);
+               kfree(asoc->peer.cookie);
                asoc->peer.cookie = kmemdup(param.cookie->body, asoc->peer.cookie_len, gfp);
                if (!asoc->peer.cookie)
                        retval = 0;
@@ -2648,8 +2647,7 @@ do_addr_param:
                        goto fall_through;
 
                /* Save peer's random parameter */
-               if (asoc->peer.peer_random)
-                       kfree(asoc->peer.peer_random);
+               kfree(asoc->peer.peer_random);
                asoc->peer.peer_random = kmemdup(param.p,
                                            ntohs(param.p->length), gfp);
                if (!asoc->peer.peer_random) {
@@ -2663,8 +2661,7 @@ do_addr_param:
                        goto fall_through;
 
                /* Save peer's HMAC list */
-               if (asoc->peer.peer_hmacs)
-                       kfree(asoc->peer.peer_hmacs);
+               kfree(asoc->peer.peer_hmacs);
                asoc->peer.peer_hmacs = kmemdup(param.p,
                                            ntohs(param.p->length), gfp);
                if (!asoc->peer.peer_hmacs) {
@@ -2680,8 +2677,7 @@ do_addr_param:
                if (!ep->auth_enable)
                        goto fall_through;
 
-               if (asoc->peer.peer_chunks)
-                       kfree(asoc->peer.peer_chunks);
+               kfree(asoc->peer.peer_chunks);
                asoc->peer.peer_chunks = kmemdup(param.p,
                                            ntohs(param.p->length), gfp);
                if (!asoc->peer.peer_chunks)
index 9a19147..1250751 100644 (file)
 #include <net/sctp/sctp.h>
 #include <linux/sysctl.h>
 
-static int zero = 0;
-static int one = 1;
 static int timer_max = 86400000; /* ms in one day */
-static int int_max = INT_MAX;
 static int sack_timer_min = 1;
 static int sack_timer_max = 500;
 static int addr_scope_max = SCTP_SCOPE_POLICY_MAX;
@@ -92,7 +89,7 @@ static struct ctl_table sctp_net_table[] = {
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = SYSCTL_ONE,
                .extra2         = &timer_max
        },
        {
@@ -101,7 +98,7 @@ static struct ctl_table sctp_net_table[] = {
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_sctp_do_rto_min,
-               .extra1         = &one,
+               .extra1         = SYSCTL_ONE,
                .extra2         = &init_net.sctp.rto_max
        },
        {
@@ -137,8 +134,8 @@ static struct ctl_table sctp_net_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &int_max
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_INT_MAX,
        },
        {
                .procname       = "cookie_preserve_enable",
@@ -160,7 +157,7 @@ static struct ctl_table sctp_net_table[] = {
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = SYSCTL_ONE,
                .extra2         = &timer_max
        },
        {
@@ -178,7 +175,7 @@ static struct ctl_table sctp_net_table[] = {
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = SYSCTL_ONE,
                .extra2         = &timer_max
        },
        {
@@ -187,8 +184,8 @@ static struct ctl_table sctp_net_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
-               .extra2         = &int_max
+               .extra1         = SYSCTL_ONE,
+               .extra2         = SYSCTL_INT_MAX,
        },
        {
                .procname       = "path_max_retrans",
@@ -196,8 +193,8 @@ static struct ctl_table sctp_net_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
-               .extra2         = &int_max
+               .extra1         = SYSCTL_ONE,
+               .extra2         = SYSCTL_INT_MAX,
        },
        {
                .procname       = "max_init_retransmits",
@@ -205,8 +202,8 @@ static struct ctl_table sctp_net_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
-               .extra2         = &int_max
+               .extra1         = SYSCTL_ONE,
+               .extra2         = SYSCTL_INT_MAX,
        },
        {
                .procname       = "pf_retrans",
@@ -214,8 +211,8 @@ static struct ctl_table sctp_net_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &int_max
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_INT_MAX,
        },
        {
                .procname       = "sndbuf_policy",
@@ -286,7 +283,7 @@ static struct ctl_table sctp_net_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &addr_scope_max,
        },
        {
@@ -295,7 +292,7 @@ static struct ctl_table sctp_net_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = &proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = SYSCTL_ONE,
                .extra2         = &rwnd_scale_max,
        },
        {
index 293d568..6a9ab7a 100644 (file)
@@ -73,6 +73,7 @@
 #include <linux/module.h>
 #include <linux/highmem.h>
 #include <linux/mount.h>
+#include <linux/pseudo_fs.h>
 #include <linux/security.h>
 #include <linux/syscalls.h>
 #include <linux/compat.h>
@@ -338,19 +339,22 @@ static const struct xattr_handler *sockfs_xattr_handlers[] = {
        NULL
 };
 
-static struct dentry *sockfs_mount(struct file_system_type *fs_type,
-                        int flags, const char *dev_name, void *data)
+static int sockfs_init_fs_context(struct fs_context *fc)
 {
-       return mount_pseudo_xattr(fs_type, "socket:", &sockfs_ops,
-                                 sockfs_xattr_handlers,
-                                 &sockfs_dentry_operations, SOCKFS_MAGIC);
+       struct pseudo_fs_context *ctx = init_pseudo(fc, SOCKFS_MAGIC);
+       if (!ctx)
+               return -ENOMEM;
+       ctx->ops = &sockfs_ops;
+       ctx->dops = &sockfs_dentry_operations;
+       ctx->xattr = sockfs_xattr_handlers;
+       return 0;
 }
 
 static struct vfsmount *sock_mnt __read_mostly;
 
 static struct file_system_type sock_fs_type = {
        .name =         "sockfs",
-       .mount =        sockfs_mount,
+       .init_fs_context = sockfs_init_fs_context,
        .kill_sb =      kill_anon_super,
 };
 
index aa30750..3bcf985 100644 (file)
@@ -35,7 +35,7 @@ config RPCSEC_GSS_KRB5
 
          If unsure, say Y.
 
-config CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES
+config SUNRPC_DISABLE_INSECURE_ENCTYPES
        bool "Secure RPC: Disable insecure Kerberos encryption types"
        depends on RPCSEC_GSS_KRB5
        default n
index c47d826..339e8c0 100644 (file)
@@ -31,25 +31,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define RPCDBG_FACILITY        RPCDBG_TRANS
 #endif
 
+#define BC_MAX_SLOTS   64U
+
+unsigned int xprt_bc_max_slots(struct rpc_xprt *xprt)
+{
+       return BC_MAX_SLOTS;
+}
+
 /*
  * Helper routines that track the number of preallocation elements
  * on the transport.
  */
 static inline int xprt_need_to_requeue(struct rpc_xprt *xprt)
 {
-       return xprt->bc_alloc_count < atomic_read(&xprt->bc_free_slots);
-}
-
-static inline void xprt_inc_alloc_count(struct rpc_xprt *xprt, unsigned int n)
-{
-       atomic_add(n, &xprt->bc_free_slots);
-       xprt->bc_alloc_count += n;
-}
-
-static inline int xprt_dec_alloc_count(struct rpc_xprt *xprt, unsigned int n)
-{
-       atomic_sub(n, &xprt->bc_free_slots);
-       return xprt->bc_alloc_count -= n;
+       return xprt->bc_alloc_count < xprt->bc_alloc_max;
 }
 
 /*
@@ -145,6 +140,9 @@ int xprt_setup_bc(struct rpc_xprt *xprt, unsigned int min_reqs)
 
        dprintk("RPC:       setup backchannel transport\n");
 
+       if (min_reqs > BC_MAX_SLOTS)
+               min_reqs = BC_MAX_SLOTS;
+
        /*
         * We use a temporary list to keep track of the preallocated
         * buffers.  Once we're done building the list we splice it
@@ -172,7 +170,9 @@ int xprt_setup_bc(struct rpc_xprt *xprt, unsigned int min_reqs)
         */
        spin_lock(&xprt->bc_pa_lock);
        list_splice(&tmp_list, &xprt->bc_pa_list);
-       xprt_inc_alloc_count(xprt, min_reqs);
+       xprt->bc_alloc_count += min_reqs;
+       xprt->bc_alloc_max += min_reqs;
+       atomic_add(min_reqs, &xprt->bc_slot_count);
        spin_unlock(&xprt->bc_pa_lock);
 
        dprintk("RPC:       setup backchannel transport done\n");
@@ -220,11 +220,13 @@ void xprt_destroy_bc(struct rpc_xprt *xprt, unsigned int max_reqs)
                goto out;
 
        spin_lock_bh(&xprt->bc_pa_lock);
-       xprt_dec_alloc_count(xprt, max_reqs);
+       xprt->bc_alloc_max -= max_reqs;
        list_for_each_entry_safe(req, tmp, &xprt->bc_pa_list, rq_bc_pa_list) {
                dprintk("RPC:        req=%p\n", req);
                list_del(&req->rq_bc_pa_list);
                xprt_free_allocation(req);
+               xprt->bc_alloc_count--;
+               atomic_dec(&xprt->bc_slot_count);
                if (--max_reqs == 0)
                        break;
        }
@@ -241,13 +243,14 @@ static struct rpc_rqst *xprt_get_bc_request(struct rpc_xprt *xprt, __be32 xid,
        struct rpc_rqst *req = NULL;
 
        dprintk("RPC:       allocate a backchannel request\n");
-       if (atomic_read(&xprt->bc_free_slots) <= 0)
-               goto not_found;
        if (list_empty(&xprt->bc_pa_list)) {
                if (!new)
                        goto not_found;
+               if (atomic_read(&xprt->bc_slot_count) >= BC_MAX_SLOTS)
+                       goto not_found;
                list_add_tail(&new->rq_bc_pa_list, &xprt->bc_pa_list);
                xprt->bc_alloc_count++;
+               atomic_inc(&xprt->bc_slot_count);
        }
        req = list_first_entry(&xprt->bc_pa_list, struct rpc_rqst,
                                rq_bc_pa_list);
@@ -291,6 +294,7 @@ void xprt_free_bc_rqst(struct rpc_rqst *req)
        if (xprt_need_to_requeue(xprt)) {
                list_add_tail(&req->rq_bc_pa_list, &xprt->bc_pa_list);
                xprt->bc_alloc_count++;
+               atomic_inc(&xprt->bc_slot_count);
                req = NULL;
        }
        spin_unlock_bh(&xprt->bc_pa_lock);
@@ -357,7 +361,7 @@ void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied)
 
        spin_lock(&xprt->bc_pa_lock);
        list_del(&req->rq_bc_pa_list);
-       xprt_dec_alloc_count(xprt, 1);
+       xprt->bc_alloc_count--;
        spin_unlock(&xprt->bc_pa_lock);
 
        req->rq_private_buf.len = copied;
index b03bfa0..d8679b6 100644 (file)
@@ -528,6 +528,8 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
                .bc_xprt = args->bc_xprt,
        };
        char servername[48];
+       struct rpc_clnt *clnt;
+       int i;
 
        if (args->bc_xprt) {
                WARN_ON_ONCE(!(args->protocol & XPRT_TRANSPORT_BC));
@@ -590,7 +592,15 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
        if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT)
                xprt->resvport = 0;
 
-       return rpc_create_xprt(args, xprt);
+       clnt = rpc_create_xprt(args, xprt);
+       if (IS_ERR(clnt) || args->nconnect <= 1)
+               return clnt;
+
+       for (i = 0; i < args->nconnect - 1; i++) {
+               if (rpc_clnt_add_xprt(clnt, &xprtargs, NULL, NULL) < 0)
+                       break;
+       }
+       return clnt;
 }
 EXPORT_SYMBOL_GPL(rpc_create);
 
@@ -968,13 +978,46 @@ out:
 }
 EXPORT_SYMBOL_GPL(rpc_bind_new_program);
 
+struct rpc_xprt *
+rpc_task_get_xprt(struct rpc_clnt *clnt, struct rpc_xprt *xprt)
+{
+       struct rpc_xprt_switch *xps;
+
+       if (!xprt)
+               return NULL;
+       rcu_read_lock();
+       xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch);
+       atomic_long_inc(&xps->xps_queuelen);
+       rcu_read_unlock();
+       atomic_long_inc(&xprt->queuelen);
+
+       return xprt;
+}
+
+static void
+rpc_task_release_xprt(struct rpc_clnt *clnt, struct rpc_xprt *xprt)
+{
+       struct rpc_xprt_switch *xps;
+
+       atomic_long_dec(&xprt->queuelen);
+       rcu_read_lock();
+       xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch);
+       atomic_long_dec(&xps->xps_queuelen);
+       rcu_read_unlock();
+
+       xprt_put(xprt);
+}
+
 void rpc_task_release_transport(struct rpc_task *task)
 {
        struct rpc_xprt *xprt = task->tk_xprt;
 
        if (xprt) {
                task->tk_xprt = NULL;
-               xprt_put(xprt);
+               if (task->tk_client)
+                       rpc_task_release_xprt(task->tk_client, xprt);
+               else
+                       xprt_put(xprt);
        }
 }
 EXPORT_SYMBOL_GPL(rpc_task_release_transport);
@@ -983,6 +1026,7 @@ void rpc_task_release_client(struct rpc_task *task)
 {
        struct rpc_clnt *clnt = task->tk_client;
 
+       rpc_task_release_transport(task);
        if (clnt != NULL) {
                /* Remove from client task list */
                spin_lock(&clnt->cl_lock);
@@ -992,14 +1036,34 @@ void rpc_task_release_client(struct rpc_task *task)
 
                rpc_release_client(clnt);
        }
-       rpc_task_release_transport(task);
+}
+
+static struct rpc_xprt *
+rpc_task_get_first_xprt(struct rpc_clnt *clnt)
+{
+       struct rpc_xprt *xprt;
+
+       rcu_read_lock();
+       xprt = xprt_get(rcu_dereference(clnt->cl_xprt));
+       rcu_read_unlock();
+       return rpc_task_get_xprt(clnt, xprt);
+}
+
+static struct rpc_xprt *
+rpc_task_get_next_xprt(struct rpc_clnt *clnt)
+{
+       return rpc_task_get_xprt(clnt, xprt_iter_get_next(&clnt->cl_xpi));
 }
 
 static
 void rpc_task_set_transport(struct rpc_task *task, struct rpc_clnt *clnt)
 {
-       if (!task->tk_xprt)
-               task->tk_xprt = xprt_iter_get_next(&clnt->cl_xpi);
+       if (task->tk_xprt)
+               return;
+       if (task->tk_flags & RPC_TASK_NO_ROUND_ROBIN)
+               task->tk_xprt = rpc_task_get_first_xprt(clnt);
+       else
+               task->tk_xprt = rpc_task_get_next_xprt(clnt);
 }
 
 static
@@ -1462,6 +1526,19 @@ size_t rpc_max_bc_payload(struct rpc_clnt *clnt)
 }
 EXPORT_SYMBOL_GPL(rpc_max_bc_payload);
 
+unsigned int rpc_num_bc_slots(struct rpc_clnt *clnt)
+{
+       struct rpc_xprt *xprt;
+       unsigned int ret;
+
+       rcu_read_lock();
+       xprt = rcu_dereference(clnt->cl_xprt);
+       ret = xprt->ops->bc_num_slots(xprt);
+       rcu_read_unlock();
+       return ret;
+}
+EXPORT_SYMBOL_GPL(rpc_num_bc_slots);
+
 /**
  * rpc_force_rebind - force transport to check that remote port is unchanged
  * @clnt: client to rebind
@@ -1788,6 +1865,7 @@ rpc_xdr_encode(struct rpc_task *task)
        req->rq_snd_buf.head[0].iov_len = 0;
        xdr_init_encode(&xdr, &req->rq_snd_buf,
                        req->rq_snd_buf.head[0].iov_base, req);
+       xdr_free_bvec(&req->rq_snd_buf);
        if (rpc_encode_header(task, &xdr))
                return;
 
@@ -1827,8 +1905,6 @@ call_encode(struct rpc_task *task)
                        rpc_call_rpcerror(task, task->tk_status);
                }
                return;
-       } else {
-               xprt_request_prepare(task->tk_rqstp);
        }
 
        /* Add task to reply queue before transmission to avoid races */
@@ -2696,6 +2772,10 @@ int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt,
                return -ENOMEM;
        data->xps = xprt_switch_get(xps);
        data->xprt = xprt_get(xprt);
+       if (rpc_xprt_switch_has_addr(data->xps, (struct sockaddr *)&xprt->addr)) {
+               rpc_cb_add_xprt_release(data);
+               goto success;
+       }
 
        task = rpc_call_null_helper(clnt, xprt, NULL,
                        RPC_TASK_SOFT|RPC_TASK_SOFTCONN|RPC_TASK_ASYNC|RPC_TASK_NULLCREDS,
@@ -2703,6 +2783,7 @@ int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt,
        if (IS_ERR(task))
                return PTR_ERR(task);
        rpc_put_task(task);
+success:
        return 1;
 }
 EXPORT_SYMBOL_GPL(rpc_clnt_test_and_add_xprt);
index 707d7aa..fd9bca2 100644 (file)
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
-/**
+/*
  * debugfs interface for sunrpc
  *
  * (c) 2014 Jeff Layton <jlayton@primarydata.com>
@@ -117,12 +117,37 @@ static const struct file_operations tasks_fops = {
        .release        = tasks_release,
 };
 
+static int do_xprt_debugfs(struct rpc_clnt *clnt, struct rpc_xprt *xprt, void *numv)
+{
+       int len;
+       char name[24]; /* enough for "../../rpc_xprt/ + 8 hex digits + NULL */
+       char link[9]; /* enough for 8 hex digits + NULL */
+       int *nump = numv;
+
+       if (IS_ERR_OR_NULL(xprt->debugfs))
+               return 0;
+       len = snprintf(name, sizeof(name), "../../rpc_xprt/%s",
+                      xprt->debugfs->d_name.name);
+       if (len > sizeof(name))
+               return -1;
+       if (*nump == 0)
+               strcpy(link, "xprt");
+       else {
+               len = snprintf(link, sizeof(link), "xprt%d", *nump);
+               if (len > sizeof(link))
+                       return -1;
+       }
+       debugfs_create_symlink(link, clnt->cl_debugfs, name);
+       (*nump)++;
+       return 0;
+}
+
 void
 rpc_clnt_debugfs_register(struct rpc_clnt *clnt)
 {
        int len;
-       char name[24]; /* enough for "../../rpc_xprt/ + 8 hex digits + NULL */
-       struct rpc_xprt *xprt;
+       char name[9]; /* enough for 8 hex digits + NULL */
+       int xprtnum = 0;
 
        len = snprintf(name, sizeof(name), "%x", clnt->cl_clid);
        if (len >= sizeof(name))
@@ -135,26 +160,7 @@ rpc_clnt_debugfs_register(struct rpc_clnt *clnt)
        debugfs_create_file("tasks", S_IFREG | 0400, clnt->cl_debugfs, clnt,
                            &tasks_fops);
 
-       rcu_read_lock();
-       xprt = rcu_dereference(clnt->cl_xprt);
-       /* no "debugfs" dentry? Don't bother with the symlink. */
-       if (IS_ERR_OR_NULL(xprt->debugfs)) {
-               rcu_read_unlock();
-               return;
-       }
-       len = snprintf(name, sizeof(name), "../../rpc_xprt/%s",
-                       xprt->debugfs->d_name.name);
-       rcu_read_unlock();
-
-       if (len >= sizeof(name))
-               goto out_err;
-
-       debugfs_create_symlink("xprt", clnt->cl_debugfs, name);
-
-       return;
-out_err:
-       debugfs_remove_recursive(clnt->cl_debugfs);
-       clnt->cl_debugfs = NULL;
+       rpc_clnt_iterate_for_each_xprt(clnt, do_xprt_debugfs, &xprtnum);
 }
 
 void
index 73bd629..748bac6 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/string.h>
 #include <linux/pagemap.h>
 #include <linux/mount.h>
+#include <linux/fs_context.h>
 #include <linux/namei.h>
 #include <linux/fsnotify.h>
 #include <linux/kernel.h>
@@ -1352,11 +1353,11 @@ rpc_gssd_dummy_depopulate(struct dentry *pipe_dentry)
 }
 
 static int
-rpc_fill_super(struct super_block *sb, void *data, int silent)
+rpc_fill_super(struct super_block *sb, struct fs_context *fc)
 {
        struct inode *inode;
        struct dentry *root, *gssd_dentry;
-       struct net *net = get_net(sb->s_fs_info);
+       struct net *net = sb->s_fs_info;
        struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
        int err;
 
@@ -1413,12 +1414,29 @@ gssd_running(struct net *net)
 }
 EXPORT_SYMBOL_GPL(gssd_running);
 
-static struct dentry *
-rpc_mount(struct file_system_type *fs_type,
-               int flags, const char *dev_name, void *data)
+static int rpc_fs_get_tree(struct fs_context *fc)
+{
+       fc->s_fs_info = get_net(fc->net_ns);
+       return vfs_get_super(fc, vfs_get_keyed_super, rpc_fill_super);
+}
+
+static void rpc_fs_free_fc(struct fs_context *fc)
 {
-       struct net *net = current->nsproxy->net_ns;
-       return mount_ns(fs_type, flags, data, net, net->user_ns, rpc_fill_super);
+       if (fc->s_fs_info)
+               put_net(fc->s_fs_info);
+}
+
+static const struct fs_context_operations rpc_fs_context_ops = {
+       .free           = rpc_fs_free_fc,
+       .get_tree       = rpc_fs_get_tree,
+};
+
+static int rpc_init_fs_context(struct fs_context *fc)
+{
+       put_user_ns(fc->user_ns);
+       fc->user_ns = get_user_ns(fc->net_ns->user_ns);
+       fc->ops = &rpc_fs_context_ops;
+       return 0;
 }
 
 static void rpc_kill_sb(struct super_block *sb)
@@ -1446,7 +1464,7 @@ out:
 static struct file_system_type rpc_pipe_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "rpc_pipefs",
-       .mount          = rpc_mount,
+       .init_fs_context = rpc_init_fs_context,
        .kill_sb        = rpc_kill_sb,
 };
 MODULE_ALIAS_FS("rpc_pipefs");
index a2c1148..1f275ab 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/sched/mm.h>
 
 #include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/metrics.h>
 
 #include "sunrpc.h"
 
@@ -46,7 +47,7 @@ static mempool_t      *rpc_buffer_mempool __read_mostly;
 
 static void                    rpc_async_schedule(struct work_struct *);
 static void                     rpc_release_task(struct rpc_task *task);
-static void __rpc_queue_timer_fn(struct timer_list *t);
+static void __rpc_queue_timer_fn(struct work_struct *);
 
 /*
  * RPC tasks sit here while waiting for conditions to improve.
@@ -58,6 +59,7 @@ static struct rpc_wait_queue delay_queue;
  */
 struct workqueue_struct *rpciod_workqueue __read_mostly;
 struct workqueue_struct *xprtiod_workqueue __read_mostly;
+EXPORT_SYMBOL_GPL(xprtiod_workqueue);
 
 unsigned long
 rpc_task_timeout(const struct rpc_task *task)
@@ -87,13 +89,19 @@ __rpc_disable_timer(struct rpc_wait_queue *queue, struct rpc_task *task)
        task->tk_timeout = 0;
        list_del(&task->u.tk_wait.timer_list);
        if (list_empty(&queue->timer_list.list))
-               del_timer(&queue->timer_list.timer);
+               cancel_delayed_work(&queue->timer_list.dwork);
 }
 
 static void
 rpc_set_queue_timer(struct rpc_wait_queue *queue, unsigned long expires)
 {
-       timer_reduce(&queue->timer_list.timer, expires);
+       unsigned long now = jiffies;
+       queue->timer_list.expires = expires;
+       if (time_before_eq(expires, now))
+               expires = 0;
+       else
+               expires -= now;
+       mod_delayed_work(rpciod_workqueue, &queue->timer_list.dwork, expires);
 }
 
 /*
@@ -107,7 +115,8 @@ __rpc_add_timer(struct rpc_wait_queue *queue, struct rpc_task *task,
                task->tk_pid, jiffies_to_msecs(timeout - jiffies));
 
        task->tk_timeout = timeout;
-       rpc_set_queue_timer(queue, timeout);
+       if (list_empty(&queue->timer_list.list) || time_before(timeout, queue->timer_list.expires))
+               rpc_set_queue_timer(queue, timeout);
        list_add(&task->u.tk_wait.timer_list, &queue->timer_list.list);
 }
 
@@ -250,7 +259,8 @@ static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const c
        queue->maxpriority = nr_queues - 1;
        rpc_reset_waitqueue_priority(queue);
        queue->qlen = 0;
-       timer_setup(&queue->timer_list.timer, __rpc_queue_timer_fn, 0);
+       queue->timer_list.expires = 0;
+       INIT_DEFERRABLE_WORK(&queue->timer_list.dwork, __rpc_queue_timer_fn);
        INIT_LIST_HEAD(&queue->timer_list.list);
        rpc_assign_waitqueue_name(queue, qname);
 }
@@ -269,7 +279,7 @@ EXPORT_SYMBOL_GPL(rpc_init_wait_queue);
 
 void rpc_destroy_wait_queue(struct rpc_wait_queue *queue)
 {
-       del_timer_sync(&queue->timer_list.timer);
+       cancel_delayed_work_sync(&queue->timer_list.dwork);
 }
 EXPORT_SYMBOL_GPL(rpc_destroy_wait_queue);
 
@@ -424,9 +434,9 @@ void rpc_sleep_on_timeout(struct rpc_wait_queue *q, struct rpc_task *task,
        /*
         * Protect the queue operations.
         */
-       spin_lock_bh(&q->lock);
+       spin_lock(&q->lock);
        __rpc_sleep_on_priority_timeout(q, task, timeout, task->tk_priority);
-       spin_unlock_bh(&q->lock);
+       spin_unlock(&q->lock);
 }
 EXPORT_SYMBOL_GPL(rpc_sleep_on_timeout);
 
@@ -442,9 +452,9 @@ void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
        /*
         * Protect the queue operations.
         */
-       spin_lock_bh(&q->lock);
+       spin_lock(&q->lock);
        __rpc_sleep_on_priority(q, task, task->tk_priority);
-       spin_unlock_bh(&q->lock);
+       spin_unlock(&q->lock);
 }
 EXPORT_SYMBOL_GPL(rpc_sleep_on);
 
@@ -458,9 +468,9 @@ void rpc_sleep_on_priority_timeout(struct rpc_wait_queue *q,
        /*
         * Protect the queue operations.
         */
-       spin_lock_bh(&q->lock);
+       spin_lock(&q->lock);
        __rpc_sleep_on_priority_timeout(q, task, timeout, priority);
-       spin_unlock_bh(&q->lock);
+       spin_unlock(&q->lock);
 }
 EXPORT_SYMBOL_GPL(rpc_sleep_on_priority_timeout);
 
@@ -475,9 +485,9 @@ void rpc_sleep_on_priority(struct rpc_wait_queue *q, struct rpc_task *task,
        /*
         * Protect the queue operations.
         */
-       spin_lock_bh(&q->lock);
+       spin_lock(&q->lock);
        __rpc_sleep_on_priority(q, task, priority);
-       spin_unlock_bh(&q->lock);
+       spin_unlock(&q->lock);
 }
 EXPORT_SYMBOL_GPL(rpc_sleep_on_priority);
 
@@ -555,9 +565,9 @@ void rpc_wake_up_queued_task_on_wq(struct workqueue_struct *wq,
 {
        if (!RPC_IS_QUEUED(task))
                return;
-       spin_lock_bh(&queue->lock);
+       spin_lock(&queue->lock);
        rpc_wake_up_task_on_wq_queue_locked(wq, queue, task);
-       spin_unlock_bh(&queue->lock);
+       spin_unlock(&queue->lock);
 }
 
 /*
@@ -567,9 +577,9 @@ void rpc_wake_up_queued_task(struct rpc_wait_queue *queue, struct rpc_task *task
 {
        if (!RPC_IS_QUEUED(task))
                return;
-       spin_lock_bh(&queue->lock);
+       spin_lock(&queue->lock);
        rpc_wake_up_task_queue_locked(queue, task);
-       spin_unlock_bh(&queue->lock);
+       spin_unlock(&queue->lock);
 }
 EXPORT_SYMBOL_GPL(rpc_wake_up_queued_task);
 
@@ -602,9 +612,9 @@ rpc_wake_up_queued_task_set_status(struct rpc_wait_queue *queue,
 {
        if (!RPC_IS_QUEUED(task))
                return;
-       spin_lock_bh(&queue->lock);
+       spin_lock(&queue->lock);
        rpc_wake_up_task_queue_set_status_locked(queue, task, status);
-       spin_unlock_bh(&queue->lock);
+       spin_unlock(&queue->lock);
 }
 
 /*
@@ -667,12 +677,12 @@ struct rpc_task *rpc_wake_up_first_on_wq(struct workqueue_struct *wq,
 
        dprintk("RPC:       wake_up_first(%p \"%s\")\n",
                        queue, rpc_qname(queue));
-       spin_lock_bh(&queue->lock);
+       spin_lock(&queue->lock);
        task = __rpc_find_next_queued(queue);
        if (task != NULL)
                task = rpc_wake_up_task_on_wq_queue_action_locked(wq, queue,
                                task, func, data);
-       spin_unlock_bh(&queue->lock);
+       spin_unlock(&queue->lock);
 
        return task;
 }
@@ -711,7 +721,7 @@ void rpc_wake_up(struct rpc_wait_queue *queue)
 {
        struct list_head *head;
 
-       spin_lock_bh(&queue->lock);
+       spin_lock(&queue->lock);
        head = &queue->tasks[queue->maxpriority];
        for (;;) {
                while (!list_empty(head)) {
@@ -725,7 +735,7 @@ void rpc_wake_up(struct rpc_wait_queue *queue)
                        break;
                head--;
        }
-       spin_unlock_bh(&queue->lock);
+       spin_unlock(&queue->lock);
 }
 EXPORT_SYMBOL_GPL(rpc_wake_up);
 
@@ -740,7 +750,7 @@ void rpc_wake_up_status(struct rpc_wait_queue *queue, int status)
 {
        struct list_head *head;
 
-       spin_lock_bh(&queue->lock);
+       spin_lock(&queue->lock);
        head = &queue->tasks[queue->maxpriority];
        for (;;) {
                while (!list_empty(head)) {
@@ -755,13 +765,15 @@ void rpc_wake_up_status(struct rpc_wait_queue *queue, int status)
                        break;
                head--;
        }
-       spin_unlock_bh(&queue->lock);
+       spin_unlock(&queue->lock);
 }
 EXPORT_SYMBOL_GPL(rpc_wake_up_status);
 
-static void __rpc_queue_timer_fn(struct timer_list *t)
+static void __rpc_queue_timer_fn(struct work_struct *work)
 {
-       struct rpc_wait_queue *queue = from_timer(queue, t, timer_list.timer);
+       struct rpc_wait_queue *queue = container_of(work,
+                       struct rpc_wait_queue,
+                       timer_list.dwork.work);
        struct rpc_task *task, *n;
        unsigned long expires, now, timeo;
 
@@ -832,6 +844,10 @@ rpc_reset_task_statistics(struct rpc_task *task)
 void rpc_exit_task(struct rpc_task *task)
 {
        task->tk_action = NULL;
+       if (task->tk_ops->rpc_count_stats)
+               task->tk_ops->rpc_count_stats(task, task->tk_calldata);
+       else if (task->tk_client)
+               rpc_count_iostats(task, task->tk_client->cl_metrics);
        if (task->tk_ops->rpc_call_done != NULL) {
                task->tk_ops->rpc_call_done(task, task->tk_calldata);
                if (task->tk_action != NULL) {
@@ -927,13 +943,13 @@ static void __rpc_execute(struct rpc_task *task)
                 * rpc_task pointer may still be dereferenced.
                 */
                queue = task->tk_waitqueue;
-               spin_lock_bh(&queue->lock);
+               spin_lock(&queue->lock);
                if (!RPC_IS_QUEUED(task)) {
-                       spin_unlock_bh(&queue->lock);
+                       spin_unlock(&queue->lock);
                        continue;
                }
                rpc_clear_running(task);
-               spin_unlock_bh(&queue->lock);
+               spin_unlock(&queue->lock);
                if (task_is_async)
                        return;
 
@@ -1076,7 +1092,8 @@ static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *ta
        /* Initialize workqueue for async tasks */
        task->tk_workqueue = task_setup_data->workqueue;
 
-       task->tk_xprt = xprt_get(task_setup_data->rpc_xprt);
+       task->tk_xprt = rpc_task_get_xprt(task_setup_data->rpc_client,
+                       xprt_get(task_setup_data->rpc_xprt));
 
        task->tk_op_cred = get_rpccred(task_setup_data->rpc_op_cred);
 
index 2b6dc7e..7c74197 100644 (file)
@@ -177,6 +177,8 @@ void rpc_count_iostats_metrics(const struct rpc_task *task,
 
        execute = ktime_sub(now, task->tk_start);
        op_metrics->om_execute = ktime_add(op_metrics->om_execute, execute);
+       if (task->tk_status < 0)
+               op_metrics->om_error_status++;
 
        spin_unlock(&op_metrics->om_lock);
 
@@ -219,13 +221,14 @@ static void _add_rpc_iostats(struct rpc_iostats *a, struct rpc_iostats *b)
        a->om_queue = ktime_add(a->om_queue, b->om_queue);
        a->om_rtt = ktime_add(a->om_rtt, b->om_rtt);
        a->om_execute = ktime_add(a->om_execute, b->om_execute);
+       a->om_error_status += b->om_error_status;
 }
 
 static void _print_rpc_iostats(struct seq_file *seq, struct rpc_iostats *stats,
                               int op, const struct rpc_procinfo *procs)
 {
        _print_name(seq, op, procs);
-       seq_printf(seq, "%lu %lu %lu %Lu %Lu %Lu %Lu %Lu\n",
+       seq_printf(seq, "%lu %lu %lu %llu %llu %llu %llu %llu %lu\n",
                   stats->om_ops,
                   stats->om_ntrans,
                   stats->om_timeouts,
@@ -233,12 +236,20 @@ static void _print_rpc_iostats(struct seq_file *seq, struct rpc_iostats *stats,
                   stats->om_bytes_recv,
                   ktime_to_ms(stats->om_queue),
                   ktime_to_ms(stats->om_rtt),
-                  ktime_to_ms(stats->om_execute));
+                  ktime_to_ms(stats->om_execute),
+                  stats->om_error_status);
+}
+
+static int do_print_stats(struct rpc_clnt *clnt, struct rpc_xprt *xprt, void *seqv)
+{
+       struct seq_file *seq = seqv;
+
+       xprt->ops->print_stats(xprt, seq);
+       return 0;
 }
 
 void rpc_clnt_show_stats(struct seq_file *seq, struct rpc_clnt *clnt)
 {
-       struct rpc_xprt *xprt;
        unsigned int op, maxproc = clnt->cl_maxproc;
 
        if (!clnt->cl_metrics)
@@ -248,11 +259,7 @@ void rpc_clnt_show_stats(struct seq_file *seq, struct rpc_clnt *clnt)
        seq_printf(seq, "p/v: %u/%u (%s)\n",
                        clnt->cl_prog, clnt->cl_vers, clnt->cl_program->name);
 
-       rcu_read_lock();
-       xprt = rcu_dereference(clnt->cl_xprt);
-       if (xprt)
-               xprt->ops->print_stats(xprt, seq);
-       rcu_read_unlock();
+       rpc_clnt_iterate_for_each_xprt(clnt, do_print_stats, seq);
 
        seq_printf(seq, "\tper-op statistics\n");
        for (op = 0; op < maxproc; op++) {
index e15cb70..220b799 100644 (file)
@@ -1595,7 +1595,7 @@ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req,
        /* Parse and execute the bc call */
        proc_error = svc_process_common(rqstp, argv, resv);
 
-       atomic_inc(&req->rq_xprt->bc_free_slots);
+       atomic_dec(&req->rq_xprt->bc_slot_count);
        if (!proc_error) {
                /* Processing error: drop the request */
                xprt_free_bc_request(req);
index f6c82b1..783748d 100644 (file)
@@ -302,9 +302,9 @@ static inline int xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task)
 
        if (test_bit(XPRT_LOCKED, &xprt->state) && xprt->snd_task == task)
                return 1;
-       spin_lock_bh(&xprt->transport_lock);
+       spin_lock(&xprt->transport_lock);
        retval = xprt->ops->reserve_xprt(xprt, task);
-       spin_unlock_bh(&xprt->transport_lock);
+       spin_unlock(&xprt->transport_lock);
        return retval;
 }
 
@@ -381,9 +381,9 @@ static inline void xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *ta
 {
        if (xprt->snd_task != task)
                return;
-       spin_lock_bh(&xprt->transport_lock);
+       spin_lock(&xprt->transport_lock);
        xprt->ops->release_xprt(xprt, task);
-       spin_unlock_bh(&xprt->transport_lock);
+       spin_unlock(&xprt->transport_lock);
 }
 
 /*
@@ -435,9 +435,9 @@ xprt_request_get_cong(struct rpc_xprt *xprt, struct rpc_rqst *req)
 
        if (req->rq_cong)
                return true;
-       spin_lock_bh(&xprt->transport_lock);
+       spin_lock(&xprt->transport_lock);
        ret = __xprt_get_cong(xprt, req) != 0;
-       spin_unlock_bh(&xprt->transport_lock);
+       spin_unlock(&xprt->transport_lock);
        return ret;
 }
 EXPORT_SYMBOL_GPL(xprt_request_get_cong);
@@ -464,9 +464,9 @@ static void
 xprt_clear_congestion_window_wait(struct rpc_xprt *xprt)
 {
        if (test_and_clear_bit(XPRT_CWND_WAIT, &xprt->state)) {
-               spin_lock_bh(&xprt->transport_lock);
+               spin_lock(&xprt->transport_lock);
                __xprt_lock_write_next_cong(xprt);
-               spin_unlock_bh(&xprt->transport_lock);
+               spin_unlock(&xprt->transport_lock);
        }
 }
 
@@ -563,9 +563,9 @@ bool xprt_write_space(struct rpc_xprt *xprt)
 
        if (!test_bit(XPRT_WRITE_SPACE, &xprt->state))
                return false;
-       spin_lock_bh(&xprt->transport_lock);
+       spin_lock(&xprt->transport_lock);
        ret = xprt_clear_write_space_locked(xprt);
-       spin_unlock_bh(&xprt->transport_lock);
+       spin_unlock(&xprt->transport_lock);
        return ret;
 }
 EXPORT_SYMBOL_GPL(xprt_write_space);
@@ -634,9 +634,9 @@ int xprt_adjust_timeout(struct rpc_rqst *req)
                req->rq_retries = 0;
                xprt_reset_majortimeo(req);
                /* Reset the RTT counters == "slow start" */
-               spin_lock_bh(&xprt->transport_lock);
+               spin_lock(&xprt->transport_lock);
                rpc_init_rtt(req->rq_task->tk_client->cl_rtt, to->to_initval);
-               spin_unlock_bh(&xprt->transport_lock);
+               spin_unlock(&xprt->transport_lock);
                status = -ETIMEDOUT;
        }
 
@@ -668,11 +668,11 @@ static void xprt_autoclose(struct work_struct *work)
 void xprt_disconnect_done(struct rpc_xprt *xprt)
 {
        dprintk("RPC:       disconnected transport %p\n", xprt);
-       spin_lock_bh(&xprt->transport_lock);
+       spin_lock(&xprt->transport_lock);
        xprt_clear_connected(xprt);
        xprt_clear_write_space_locked(xprt);
        xprt_wake_pending_tasks(xprt, -ENOTCONN);
-       spin_unlock_bh(&xprt->transport_lock);
+       spin_unlock(&xprt->transport_lock);
 }
 EXPORT_SYMBOL_GPL(xprt_disconnect_done);
 
@@ -684,7 +684,7 @@ EXPORT_SYMBOL_GPL(xprt_disconnect_done);
 void xprt_force_disconnect(struct rpc_xprt *xprt)
 {
        /* Don't race with the test_bit() in xprt_clear_locked() */
-       spin_lock_bh(&xprt->transport_lock);
+       spin_lock(&xprt->transport_lock);
        set_bit(XPRT_CLOSE_WAIT, &xprt->state);
        /* Try to schedule an autoclose RPC call */
        if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
@@ -692,7 +692,7 @@ void xprt_force_disconnect(struct rpc_xprt *xprt)
        else if (xprt->snd_task)
                rpc_wake_up_queued_task_set_status(&xprt->pending,
                                xprt->snd_task, -ENOTCONN);
-       spin_unlock_bh(&xprt->transport_lock);
+       spin_unlock(&xprt->transport_lock);
 }
 EXPORT_SYMBOL_GPL(xprt_force_disconnect);
 
@@ -726,7 +726,7 @@ xprt_request_retransmit_after_disconnect(struct rpc_task *task)
 void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie)
 {
        /* Don't race with the test_bit() in xprt_clear_locked() */
-       spin_lock_bh(&xprt->transport_lock);
+       spin_lock(&xprt->transport_lock);
        if (cookie != xprt->connect_cookie)
                goto out;
        if (test_bit(XPRT_CLOSING, &xprt->state))
@@ -737,7 +737,7 @@ void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie)
                queue_work(xprtiod_workqueue, &xprt->task_cleanup);
        xprt_wake_pending_tasks(xprt, -EAGAIN);
 out:
-       spin_unlock_bh(&xprt->transport_lock);
+       spin_unlock(&xprt->transport_lock);
 }
 
 static bool
@@ -750,6 +750,7 @@ static void
 xprt_schedule_autodisconnect(struct rpc_xprt *xprt)
        __must_hold(&xprt->transport_lock)
 {
+       xprt->last_used = jiffies;
        if (RB_EMPTY_ROOT(&xprt->recv_queue) && xprt_has_timer(xprt))
                mod_timer(&xprt->timer, xprt->last_used + xprt->idle_timeout);
 }
@@ -759,18 +760,13 @@ xprt_init_autodisconnect(struct timer_list *t)
 {
        struct rpc_xprt *xprt = from_timer(xprt, t, timer);
 
-       spin_lock(&xprt->transport_lock);
        if (!RB_EMPTY_ROOT(&xprt->recv_queue))
-               goto out_abort;
+               return;
        /* Reset xprt->last_used to avoid connect/autodisconnect cycling */
        xprt->last_used = jiffies;
        if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
-               goto out_abort;
-       spin_unlock(&xprt->transport_lock);
+               return;
        queue_work(xprtiod_workqueue, &xprt->task_cleanup);
-       return;
-out_abort:
-       spin_unlock(&xprt->transport_lock);
 }
 
 bool xprt_lock_connect(struct rpc_xprt *xprt,
@@ -779,7 +775,7 @@ bool xprt_lock_connect(struct rpc_xprt *xprt,
 {
        bool ret = false;
 
-       spin_lock_bh(&xprt->transport_lock);
+       spin_lock(&xprt->transport_lock);
        if (!test_bit(XPRT_LOCKED, &xprt->state))
                goto out;
        if (xprt->snd_task != task)
@@ -787,13 +783,13 @@ bool xprt_lock_connect(struct rpc_xprt *xprt,
        xprt->snd_task = cookie;
        ret = true;
 out:
-       spin_unlock_bh(&xprt->transport_lock);
+       spin_unlock(&xprt->transport_lock);
        return ret;
 }
 
 void xprt_unlock_connect(struct rpc_xprt *xprt, void *cookie)
 {
-       spin_lock_bh(&xprt->transport_lock);
+       spin_lock(&xprt->transport_lock);
        if (xprt->snd_task != cookie)
                goto out;
        if (!test_bit(XPRT_LOCKED, &xprt->state))
@@ -802,7 +798,7 @@ void xprt_unlock_connect(struct rpc_xprt *xprt, void *cookie)
        xprt->ops->release_xprt(xprt, NULL);
        xprt_schedule_autodisconnect(xprt);
 out:
-       spin_unlock_bh(&xprt->transport_lock);
+       spin_unlock(&xprt->transport_lock);
        wake_up_bit(&xprt->state, XPRT_LOCKED);
 }
 
@@ -850,6 +846,38 @@ void xprt_connect(struct rpc_task *task)
        xprt_release_write(xprt, task);
 }
 
+/**
+ * xprt_reconnect_delay - compute the wait before scheduling a connect
+ * @xprt: transport instance
+ *
+ */
+unsigned long xprt_reconnect_delay(const struct rpc_xprt *xprt)
+{
+       unsigned long start, now = jiffies;
+
+       start = xprt->stat.connect_start + xprt->reestablish_timeout;
+       if (time_after(start, now))
+               return start - now;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(xprt_reconnect_delay);
+
+/**
+ * xprt_reconnect_backoff - compute the new re-establish timeout
+ * @xprt: transport instance
+ * @init_to: initial reestablish timeout
+ *
+ */
+void xprt_reconnect_backoff(struct rpc_xprt *xprt, unsigned long init_to)
+{
+       xprt->reestablish_timeout <<= 1;
+       if (xprt->reestablish_timeout > xprt->max_reconnect_timeout)
+               xprt->reestablish_timeout = xprt->max_reconnect_timeout;
+       if (xprt->reestablish_timeout < init_to)
+               xprt->reestablish_timeout = init_to;
+}
+EXPORT_SYMBOL_GPL(xprt_reconnect_backoff);
+
 enum xprt_xid_rb_cmp {
        XID_RB_EQUAL,
        XID_RB_LEFT,
@@ -1013,6 +1041,8 @@ xprt_request_enqueue_receive(struct rpc_task *task)
 
        if (!xprt_request_need_enqueue_receive(task, req))
                return;
+
+       xprt_request_prepare(task->tk_rqstp);
        spin_lock(&xprt->queue_lock);
 
        /* Update the softirq receive buffer */
@@ -1412,14 +1442,14 @@ xprt_request_transmit(struct rpc_rqst *req, struct rpc_task *snd_task)
        xprt_inject_disconnect(xprt);
 
        task->tk_flags |= RPC_TASK_SENT;
-       spin_lock_bh(&xprt->transport_lock);
+       spin_lock(&xprt->transport_lock);
 
        xprt->stat.sends++;
        xprt->stat.req_u += xprt->stat.sends - xprt->stat.recvs;
        xprt->stat.bklog_u += xprt->backlog.qlen;
        xprt->stat.sending_u += xprt->sending.qlen;
        xprt->stat.pending_u += xprt->pending.qlen;
-       spin_unlock_bh(&xprt->transport_lock);
+       spin_unlock(&xprt->transport_lock);
 
        req->rq_connect_cookie = connect_cookie;
 out_dequeue:
@@ -1765,18 +1795,13 @@ void xprt_release(struct rpc_task *task)
        }
 
        xprt = req->rq_xprt;
-       if (task->tk_ops->rpc_count_stats != NULL)
-               task->tk_ops->rpc_count_stats(task, task->tk_calldata);
-       else if (task->tk_client)
-               rpc_count_iostats(task, task->tk_client->cl_metrics);
        xprt_request_dequeue_all(task, req);
-       spin_lock_bh(&xprt->transport_lock);
+       spin_lock(&xprt->transport_lock);
        xprt->ops->release_xprt(xprt, task);
        if (xprt->ops->release_request)
                xprt->ops->release_request(task);
-       xprt->last_used = jiffies;
        xprt_schedule_autodisconnect(xprt);
-       spin_unlock_bh(&xprt->transport_lock);
+       spin_unlock(&xprt->transport_lock);
        if (req->rq_buffer)
                xprt->ops->buf_free(task);
        xprt_inject_disconnect(xprt);
index 8394124..78c075a 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/sunrpc/addr.h>
 #include <linux/sunrpc/xprtmultipath.h>
 
-typedef struct rpc_xprt *(*xprt_switch_find_xprt_t)(struct list_head *head,
+typedef struct rpc_xprt *(*xprt_switch_find_xprt_t)(struct rpc_xprt_switch *xps,
                const struct rpc_xprt *cur);
 
 static const struct rpc_xprt_iter_ops rpc_xprt_iter_singular;
@@ -36,6 +36,7 @@ static void xprt_switch_add_xprt_locked(struct rpc_xprt_switch *xps,
        if (xps->xps_nxprts == 0)
                xps->xps_net = xprt->xprt_net;
        xps->xps_nxprts++;
+       xps->xps_nactive++;
 }
 
 /**
@@ -51,8 +52,7 @@ void rpc_xprt_switch_add_xprt(struct rpc_xprt_switch *xps,
        if (xprt == NULL)
                return;
        spin_lock(&xps->xps_lock);
-       if ((xps->xps_net == xprt->xprt_net || xps->xps_net == NULL) &&
-           !rpc_xprt_switch_has_addr(xps, (struct sockaddr *)&xprt->addr))
+       if (xps->xps_net == xprt->xprt_net || xps->xps_net == NULL)
                xprt_switch_add_xprt_locked(xps, xprt);
        spin_unlock(&xps->xps_lock);
 }
@@ -62,6 +62,7 @@ static void xprt_switch_remove_xprt_locked(struct rpc_xprt_switch *xps,
 {
        if (unlikely(xprt == NULL))
                return;
+       xps->xps_nactive--;
        xps->xps_nxprts--;
        if (xps->xps_nxprts == 0)
                xps->xps_net = NULL;
@@ -102,7 +103,9 @@ struct rpc_xprt_switch *xprt_switch_alloc(struct rpc_xprt *xprt,
        if (xps != NULL) {
                spin_lock_init(&xps->xps_lock);
                kref_init(&xps->xps_kref);
-               xps->xps_nxprts = 0;
+               xps->xps_nxprts = xps->xps_nactive = 0;
+               atomic_long_set(&xps->xps_queuelen, 0);
+               xps->xps_net = NULL;
                INIT_LIST_HEAD(&xps->xps_xprt_list);
                xps->xps_iter_ops = &rpc_xprt_iter_singular;
                xprt_switch_add_xprt_locked(xps, xprt);
@@ -193,9 +196,21 @@ void xprt_iter_default_rewind(struct rpc_xprt_iter *xpi)
 }
 
 static
+bool xprt_is_active(const struct rpc_xprt *xprt)
+{
+       return kref_read(&xprt->kref) != 0;
+}
+
+static
 struct rpc_xprt *xprt_switch_find_first_entry(struct list_head *head)
 {
-       return list_first_or_null_rcu(head, struct rpc_xprt, xprt_switch);
+       struct rpc_xprt *pos;
+
+       list_for_each_entry_rcu(pos, head, xprt_switch) {
+               if (xprt_is_active(pos))
+                       return pos;
+       }
+       return NULL;
 }
 
 static
@@ -213,9 +228,12 @@ struct rpc_xprt *xprt_switch_find_current_entry(struct list_head *head,
                const struct rpc_xprt *cur)
 {
        struct rpc_xprt *pos;
+       bool found = false;
 
        list_for_each_entry_rcu(pos, head, xprt_switch) {
                if (cur == pos)
+                       found = true;
+               if (found && xprt_is_active(pos))
                        return pos;
        }
        return NULL;
@@ -260,9 +278,12 @@ struct rpc_xprt *xprt_switch_find_next_entry(struct list_head *head,
                const struct rpc_xprt *cur)
 {
        struct rpc_xprt *pos, *prev = NULL;
+       bool found = false;
 
        list_for_each_entry_rcu(pos, head, xprt_switch) {
                if (cur == prev)
+                       found = true;
+               if (found && xprt_is_active(pos))
                        return pos;
                prev = pos;
        }
@@ -270,22 +291,15 @@ struct rpc_xprt *xprt_switch_find_next_entry(struct list_head *head,
 }
 
 static
-struct rpc_xprt *xprt_switch_set_next_cursor(struct list_head *head,
+struct rpc_xprt *xprt_switch_set_next_cursor(struct rpc_xprt_switch *xps,
                struct rpc_xprt **cursor,
                xprt_switch_find_xprt_t find_next)
 {
-       struct rpc_xprt *cur, *pos, *old;
+       struct rpc_xprt *pos, *old;
 
-       cur = READ_ONCE(*cursor);
-       for (;;) {
-               old = cur;
-               pos = find_next(head, old);
-               if (pos == NULL)
-                       break;
-               cur = cmpxchg_relaxed(cursor, old, pos);
-               if (cur == old)
-                       break;
-       }
+       old = smp_load_acquire(cursor);
+       pos = find_next(xps, old);
+       smp_store_release(cursor, pos);
        return pos;
 }
 
@@ -297,13 +311,11 @@ struct rpc_xprt *xprt_iter_next_entry_multiple(struct rpc_xprt_iter *xpi,
 
        if (xps == NULL)
                return NULL;
-       return xprt_switch_set_next_cursor(&xps->xps_xprt_list,
-                       &xpi->xpi_cursor,
-                       find_next);
+       return xprt_switch_set_next_cursor(xps, &xpi->xpi_cursor, find_next);
 }
 
 static
-struct rpc_xprt *xprt_switch_find_next_entry_roundrobin(struct list_head *head,
+struct rpc_xprt *__xprt_switch_find_next_entry_roundrobin(struct list_head *head,
                const struct rpc_xprt *cur)
 {
        struct rpc_xprt *ret;
@@ -315,6 +327,31 @@ struct rpc_xprt *xprt_switch_find_next_entry_roundrobin(struct list_head *head,
 }
 
 static
+struct rpc_xprt *xprt_switch_find_next_entry_roundrobin(struct rpc_xprt_switch *xps,
+               const struct rpc_xprt *cur)
+{
+       struct list_head *head = &xps->xps_xprt_list;
+       struct rpc_xprt *xprt;
+       unsigned int nactive;
+
+       for (;;) {
+               unsigned long xprt_queuelen, xps_queuelen;
+
+               xprt = __xprt_switch_find_next_entry_roundrobin(head, cur);
+               if (!xprt)
+                       break;
+               xprt_queuelen = atomic_long_read(&xprt->queuelen);
+               xps_queuelen = atomic_long_read(&xps->xps_queuelen);
+               nactive = READ_ONCE(xps->xps_nactive);
+               /* Exit loop if xprt_queuelen <= average queue length */
+               if (xprt_queuelen * nactive <= xps_queuelen)
+                       break;
+               cur = xprt;
+       }
+       return xprt;
+}
+
+static
 struct rpc_xprt *xprt_iter_next_entry_roundrobin(struct rpc_xprt_iter *xpi)
 {
        return xprt_iter_next_entry_multiple(xpi,
@@ -322,9 +359,17 @@ struct rpc_xprt *xprt_iter_next_entry_roundrobin(struct rpc_xprt_iter *xpi)
 }
 
 static
+struct rpc_xprt *xprt_switch_find_next_entry_all(struct rpc_xprt_switch *xps,
+               const struct rpc_xprt *cur)
+{
+       return xprt_switch_find_next_entry(&xps->xps_xprt_list, cur);
+}
+
+static
 struct rpc_xprt *xprt_iter_next_entry_all(struct rpc_xprt_iter *xpi)
 {
-       return xprt_iter_next_entry_multiple(xpi, xprt_switch_find_next_entry);
+       return xprt_iter_next_entry_multiple(xpi,
+                       xprt_switch_find_next_entry_all);
 }
 
 /*
index ce98659..59e624b 100644 (file)
@@ -52,6 +52,13 @@ size_t xprt_rdma_bc_maxpayload(struct rpc_xprt *xprt)
        return maxmsg - RPCRDMA_HDRLEN_MIN;
 }
 
+unsigned int xprt_rdma_bc_max_slots(struct rpc_xprt *xprt)
+{
+       struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
+
+       return r_xprt->rx_buf.rb_bc_srv_max_requests;
+}
+
 static int rpcrdma_bc_marshal_reply(struct rpc_rqst *rqst)
 {
        struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(rqst->rq_xprt);
index 794ba4c..0b6dad7 100644 (file)
@@ -144,6 +144,26 @@ frwr_mr_recycle_worker(struct work_struct *work)
        frwr_release_mr(mr);
 }
 
+/* frwr_reset - Place MRs back on the free list
+ * @req: request to reset
+ *
+ * Used after a failed marshal. For FRWR, this means the MRs
+ * don't have to be fully released and recreated.
+ *
+ * NB: This is safe only as long as none of @req's MRs are
+ * involved with an ongoing asynchronous FAST_REG or LOCAL_INV
+ * Work Request.
+ */
+void frwr_reset(struct rpcrdma_req *req)
+{
+       while (!list_empty(&req->rl_registered)) {
+               struct rpcrdma_mr *mr;
+
+               mr = rpcrdma_mr_pop(&req->rl_registered);
+               rpcrdma_mr_unmap_and_put(mr);
+       }
+}
+
 /**
  * frwr_init_mr - Initialize one MR
  * @ia: interface adapter
@@ -168,7 +188,6 @@ int frwr_init_mr(struct rpcrdma_ia *ia, struct rpcrdma_mr *mr)
                goto out_list_err;
 
        mr->frwr.fr_mr = frmr;
-       mr->frwr.fr_state = FRWR_IS_INVALID;
        mr->mr_dir = DMA_NONE;
        INIT_LIST_HEAD(&mr->mr_list);
        INIT_WORK(&mr->mr_recycle, frwr_mr_recycle_worker);
@@ -298,65 +317,6 @@ size_t frwr_maxpages(struct rpcrdma_xprt *r_xprt)
 }
 
 /**
- * frwr_wc_fastreg - Invoked by RDMA provider for a flushed FastReg WC
- * @cq:        completion queue (ignored)
- * @wc:        completed WR
- *
- */
-static void
-frwr_wc_fastreg(struct ib_cq *cq, struct ib_wc *wc)
-{
-       struct ib_cqe *cqe = wc->wr_cqe;
-       struct rpcrdma_frwr *frwr =
-                       container_of(cqe, struct rpcrdma_frwr, fr_cqe);
-
-       /* WARNING: Only wr_cqe and status are reliable at this point */
-       if (wc->status != IB_WC_SUCCESS)
-               frwr->fr_state = FRWR_FLUSHED_FR;
-       trace_xprtrdma_wc_fastreg(wc, frwr);
-}
-
-/**
- * frwr_wc_localinv - Invoked by RDMA provider for a flushed LocalInv WC
- * @cq:        completion queue (ignored)
- * @wc:        completed WR
- *
- */
-static void
-frwr_wc_localinv(struct ib_cq *cq, struct ib_wc *wc)
-{
-       struct ib_cqe *cqe = wc->wr_cqe;
-       struct rpcrdma_frwr *frwr = container_of(cqe, struct rpcrdma_frwr,
-                                                fr_cqe);
-
-       /* WARNING: Only wr_cqe and status are reliable at this point */
-       if (wc->status != IB_WC_SUCCESS)
-               frwr->fr_state = FRWR_FLUSHED_LI;
-       trace_xprtrdma_wc_li(wc, frwr);
-}
-
-/**
- * frwr_wc_localinv_wake - Invoked by RDMA provider for a signaled LocalInv WC
- * @cq:        completion queue (ignored)
- * @wc:        completed WR
- *
- * Awaken anyone waiting for an MR to finish being fenced.
- */
-static void
-frwr_wc_localinv_wake(struct ib_cq *cq, struct ib_wc *wc)
-{
-       struct ib_cqe *cqe = wc->wr_cqe;
-       struct rpcrdma_frwr *frwr = container_of(cqe, struct rpcrdma_frwr,
-                                                fr_cqe);
-
-       /* WARNING: Only wr_cqe and status are reliable at this point */
-       if (wc->status != IB_WC_SUCCESS)
-               frwr->fr_state = FRWR_FLUSHED_LI;
-       trace_xprtrdma_wc_li_wake(wc, frwr);
-       complete(&frwr->fr_linv_done);
-}
-
-/**
  * frwr_map - Register a memory region
  * @r_xprt: controlling transport
  * @seg: memory region co-ordinates
@@ -378,23 +338,15 @@ struct rpcrdma_mr_seg *frwr_map(struct rpcrdma_xprt *r_xprt,
 {
        struct rpcrdma_ia *ia = &r_xprt->rx_ia;
        bool holes_ok = ia->ri_mrtype == IB_MR_TYPE_SG_GAPS;
-       struct rpcrdma_frwr *frwr;
        struct rpcrdma_mr *mr;
        struct ib_mr *ibmr;
        struct ib_reg_wr *reg_wr;
        int i, n;
        u8 key;
 
-       mr = NULL;
-       do {
-               if (mr)
-                       rpcrdma_mr_recycle(mr);
-               mr = rpcrdma_mr_get(r_xprt);
-               if (!mr)
-                       return ERR_PTR(-EAGAIN);
-       } while (mr->frwr.fr_state != FRWR_IS_INVALID);
-       frwr = &mr->frwr;
-       frwr->fr_state = FRWR_IS_VALID;
+       mr = rpcrdma_mr_get(r_xprt);
+       if (!mr)
+               goto out_getmr_err;
 
        if (nsegs > ia->ri_max_frwr_depth)
                nsegs = ia->ri_max_frwr_depth;
@@ -423,7 +375,7 @@ struct rpcrdma_mr_seg *frwr_map(struct rpcrdma_xprt *r_xprt,
        if (!mr->mr_nents)
                goto out_dmamap_err;
 
-       ibmr = frwr->fr_mr;
+       ibmr = mr->frwr.fr_mr;
        n = ib_map_mr_sg(ibmr, mr->mr_sg, mr->mr_nents, NULL, PAGE_SIZE);
        if (unlikely(n != mr->mr_nents))
                goto out_mapmr_err;
@@ -433,7 +385,7 @@ struct rpcrdma_mr_seg *frwr_map(struct rpcrdma_xprt *r_xprt,
        key = (u8)(ibmr->rkey & 0x000000FF);
        ib_update_fast_reg_key(ibmr, ++key);
 
-       reg_wr = &frwr->fr_regwr;
+       reg_wr = &mr->frwr.fr_regwr;
        reg_wr->mr = ibmr;
        reg_wr->key = ibmr->rkey;
        reg_wr->access = writing ?
@@ -448,6 +400,10 @@ struct rpcrdma_mr_seg *frwr_map(struct rpcrdma_xprt *r_xprt,
        *out = mr;
        return seg;
 
+out_getmr_err:
+       xprt_wait_for_buffer_space(&r_xprt->rx_xprt);
+       return ERR_PTR(-EAGAIN);
+
 out_dmamap_err:
        mr->mr_dir = DMA_NONE;
        trace_xprtrdma_frwr_sgerr(mr, i);
@@ -461,6 +417,23 @@ out_mapmr_err:
 }
 
 /**
+ * frwr_wc_fastreg - Invoked by RDMA provider for a flushed FastReg WC
+ * @cq:        completion queue (ignored)
+ * @wc:        completed WR
+ *
+ */
+static void frwr_wc_fastreg(struct ib_cq *cq, struct ib_wc *wc)
+{
+       struct ib_cqe *cqe = wc->wr_cqe;
+       struct rpcrdma_frwr *frwr =
+               container_of(cqe, struct rpcrdma_frwr, fr_cqe);
+
+       /* WARNING: Only wr_cqe and status are reliable at this point */
+       trace_xprtrdma_wc_fastreg(wc, frwr);
+       /* The MR will get recycled when the associated req is retransmitted */
+}
+
+/**
  * frwr_send - post Send WR containing the RPC Call message
  * @ia: interface adapter
  * @req: Prepared RPC Call
@@ -512,31 +485,75 @@ void frwr_reminv(struct rpcrdma_rep *rep, struct list_head *mrs)
                if (mr->mr_handle == rep->rr_inv_rkey) {
                        list_del_init(&mr->mr_list);
                        trace_xprtrdma_mr_remoteinv(mr);
-                       mr->frwr.fr_state = FRWR_IS_INVALID;
                        rpcrdma_mr_unmap_and_put(mr);
                        break;  /* only one invalidated MR per RPC */
                }
 }
 
+static void __frwr_release_mr(struct ib_wc *wc, struct rpcrdma_mr *mr)
+{
+       if (wc->status != IB_WC_SUCCESS)
+               rpcrdma_mr_recycle(mr);
+       else
+               rpcrdma_mr_unmap_and_put(mr);
+}
+
 /**
- * frwr_unmap_sync - invalidate memory regions that were registered for @req
- * @r_xprt: controlling transport
- * @mrs: list of MRs to process
+ * frwr_wc_localinv - Invoked by RDMA provider for a LOCAL_INV WC
+ * @cq:        completion queue (ignored)
+ * @wc:        completed WR
+ *
+ */
+static void frwr_wc_localinv(struct ib_cq *cq, struct ib_wc *wc)
+{
+       struct ib_cqe *cqe = wc->wr_cqe;
+       struct rpcrdma_frwr *frwr =
+               container_of(cqe, struct rpcrdma_frwr, fr_cqe);
+       struct rpcrdma_mr *mr = container_of(frwr, struct rpcrdma_mr, frwr);
+
+       /* WARNING: Only wr_cqe and status are reliable at this point */
+       trace_xprtrdma_wc_li(wc, frwr);
+       __frwr_release_mr(wc, mr);
+}
+
+/**
+ * frwr_wc_localinv_wake - Invoked by RDMA provider for a LOCAL_INV WC
+ * @cq:        completion queue (ignored)
+ * @wc:        completed WR
  *
- * Sleeps until it is safe for the host CPU to access the
- * previously mapped memory regions.
+ * Awaken anyone waiting for an MR to finish being fenced.
+ */
+static void frwr_wc_localinv_wake(struct ib_cq *cq, struct ib_wc *wc)
+{
+       struct ib_cqe *cqe = wc->wr_cqe;
+       struct rpcrdma_frwr *frwr =
+               container_of(cqe, struct rpcrdma_frwr, fr_cqe);
+       struct rpcrdma_mr *mr = container_of(frwr, struct rpcrdma_mr, frwr);
+
+       /* WARNING: Only wr_cqe and status are reliable at this point */
+       trace_xprtrdma_wc_li_wake(wc, frwr);
+       complete(&frwr->fr_linv_done);
+       __frwr_release_mr(wc, mr);
+}
+
+/**
+ * frwr_unmap_sync - invalidate memory regions that were registered for @req
+ * @r_xprt: controlling transport instance
+ * @req: rpcrdma_req with a non-empty list of MRs to process
  *
- * Caller ensures that @mrs is not empty before the call. This
- * function empties the list.
+ * Sleeps until it is safe for the host CPU to access the previously mapped
+ * memory regions. This guarantees that registered MRs are properly fenced
+ * from the server before the RPC consumer accesses the data in them. It
+ * also ensures proper Send flow control: waking the next RPC waits until
+ * this RPC has relinquished all its Send Queue entries.
  */
-void frwr_unmap_sync(struct rpcrdma_xprt *r_xprt, struct list_head *mrs)
+void frwr_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
 {
        struct ib_send_wr *first, **prev, *last;
        const struct ib_send_wr *bad_wr;
-       struct rpcrdma_ia *ia = &r_xprt->rx_ia;
        struct rpcrdma_frwr *frwr;
        struct rpcrdma_mr *mr;
-       int count, rc;
+       int rc;
 
        /* ORDER: Invalidate all of the MRs first
         *
@@ -544,33 +561,32 @@ void frwr_unmap_sync(struct rpcrdma_xprt *r_xprt, struct list_head *mrs)
         * a single ib_post_send() call.
         */
        frwr = NULL;
-       count = 0;
        prev = &first;
-       list_for_each_entry(mr, mrs, mr_list) {
-               mr->frwr.fr_state = FRWR_IS_INVALID;
+       while (!list_empty(&req->rl_registered)) {
+               mr = rpcrdma_mr_pop(&req->rl_registered);
 
-               frwr = &mr->frwr;
                trace_xprtrdma_mr_localinv(mr);
+               r_xprt->rx_stats.local_inv_needed++;
 
+               frwr = &mr->frwr;
                frwr->fr_cqe.done = frwr_wc_localinv;
                last = &frwr->fr_invwr;
-               memset(last, 0, sizeof(*last));
+               last->next = NULL;
                last->wr_cqe = &frwr->fr_cqe;
+               last->sg_list = NULL;
+               last->num_sge = 0;
                last->opcode = IB_WR_LOCAL_INV;
+               last->send_flags = IB_SEND_SIGNALED;
                last->ex.invalidate_rkey = mr->mr_handle;
-               count++;
 
                *prev = last;
                prev = &last->next;
        }
-       if (!frwr)
-               goto unmap;
 
        /* Strong send queue ordering guarantees that when the
         * last WR in the chain completes, all WRs in the chain
         * are complete.
         */
-       last->send_flags = IB_SEND_SIGNALED;
        frwr->fr_cqe.done = frwr_wc_localinv_wake;
        reinit_completion(&frwr->fr_linv_done);
 
@@ -578,37 +594,126 @@ void frwr_unmap_sync(struct rpcrdma_xprt *r_xprt, struct list_head *mrs)
         * replaces the QP. The RPC reply handler won't call us
         * unless ri_id->qp is a valid pointer.
         */
-       r_xprt->rx_stats.local_inv_needed++;
        bad_wr = NULL;
-       rc = ib_post_send(ia->ri_id->qp, first, &bad_wr);
+       rc = ib_post_send(r_xprt->rx_ia.ri_id->qp, first, &bad_wr);
+       trace_xprtrdma_post_send(req, rc);
+
+       /* The final LOCAL_INV WR in the chain is supposed to
+        * do the wake. If it was never posted, the wake will
+        * not happen, so don't wait in that case.
+        */
        if (bad_wr != first)
                wait_for_completion(&frwr->fr_linv_done);
-       if (rc)
-               goto out_release;
+       if (!rc)
+               return;
 
-       /* ORDER: Now DMA unmap all of the MRs, and return
-        * them to the free MR list.
+       /* Recycle MRs in the LOCAL_INV chain that did not get posted.
         */
-unmap:
-       while (!list_empty(mrs)) {
-               mr = rpcrdma_mr_pop(mrs);
-               rpcrdma_mr_unmap_and_put(mr);
+       while (bad_wr) {
+               frwr = container_of(bad_wr, struct rpcrdma_frwr,
+                                   fr_invwr);
+               mr = container_of(frwr, struct rpcrdma_mr, frwr);
+               bad_wr = bad_wr->next;
+
+               list_del_init(&mr->mr_list);
+               rpcrdma_mr_recycle(mr);
        }
-       return;
+}
 
-out_release:
-       pr_err("rpcrdma: FRWR invalidate ib_post_send returned %i\n", rc);
+/**
+ * frwr_wc_localinv_done - Invoked by RDMA provider for a signaled LOCAL_INV WC
+ * @cq:        completion queue (ignored)
+ * @wc:        completed WR
+ *
+ */
+static void frwr_wc_localinv_done(struct ib_cq *cq, struct ib_wc *wc)
+{
+       struct ib_cqe *cqe = wc->wr_cqe;
+       struct rpcrdma_frwr *frwr =
+               container_of(cqe, struct rpcrdma_frwr, fr_cqe);
+       struct rpcrdma_mr *mr = container_of(frwr, struct rpcrdma_mr, frwr);
 
-       /* Unmap and release the MRs in the LOCAL_INV WRs that did not
-        * get posted.
+       /* WARNING: Only wr_cqe and status are reliable at this point */
+       trace_xprtrdma_wc_li_done(wc, frwr);
+       rpcrdma_complete_rqst(frwr->fr_req->rl_reply);
+       __frwr_release_mr(wc, mr);
+}
+
+/**
+ * frwr_unmap_async - invalidate memory regions that were registered for @req
+ * @r_xprt: controlling transport instance
+ * @req: rpcrdma_req with a non-empty list of MRs to process
+ *
+ * This guarantees that registered MRs are properly fenced from the
+ * server before the RPC consumer accesses the data in them. It also
+ * ensures proper Send flow control: waking the next RPC waits until
+ * this RPC has relinquished all its Send Queue entries.
+ */
+void frwr_unmap_async(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
+{
+       struct ib_send_wr *first, *last, **prev;
+       const struct ib_send_wr *bad_wr;
+       struct rpcrdma_frwr *frwr;
+       struct rpcrdma_mr *mr;
+       int rc;
+
+       /* Chain the LOCAL_INV Work Requests and post them with
+        * a single ib_post_send() call.
+        */
+       frwr = NULL;
+       prev = &first;
+       while (!list_empty(&req->rl_registered)) {
+               mr = rpcrdma_mr_pop(&req->rl_registered);
+
+               trace_xprtrdma_mr_localinv(mr);
+               r_xprt->rx_stats.local_inv_needed++;
+
+               frwr = &mr->frwr;
+               frwr->fr_cqe.done = frwr_wc_localinv;
+               frwr->fr_req = req;
+               last = &frwr->fr_invwr;
+               last->next = NULL;
+               last->wr_cqe = &frwr->fr_cqe;
+               last->sg_list = NULL;
+               last->num_sge = 0;
+               last->opcode = IB_WR_LOCAL_INV;
+               last->send_flags = IB_SEND_SIGNALED;
+               last->ex.invalidate_rkey = mr->mr_handle;
+
+               *prev = last;
+               prev = &last->next;
+       }
+
+       /* Strong send queue ordering guarantees that when the
+        * last WR in the chain completes, all WRs in the chain
+        * are complete. The last completion will wake up the
+        * RPC waiter.
+        */
+       frwr->fr_cqe.done = frwr_wc_localinv_done;
+
+       /* Transport disconnect drains the receive CQ before it
+        * replaces the QP. The RPC reply handler won't call us
+        * unless ri_id->qp is a valid pointer.
+        */
+       bad_wr = NULL;
+       rc = ib_post_send(r_xprt->rx_ia.ri_id->qp, first, &bad_wr);
+       trace_xprtrdma_post_send(req, rc);
+       if (!rc)
+               return;
+
+       /* Recycle MRs in the LOCAL_INV chain that did not get posted.
         */
        while (bad_wr) {
-               frwr = container_of(bad_wr, struct rpcrdma_frwr,
-                                   fr_invwr);
+               frwr = container_of(bad_wr, struct rpcrdma_frwr, fr_invwr);
                mr = container_of(frwr, struct rpcrdma_mr, frwr);
                bad_wr = bad_wr->next;
 
-               list_del_init(&mr->mr_list);
                rpcrdma_mr_recycle(mr);
        }
+
+       /* The final LOCAL_INV WR in the chain is supposed to
+        * do the wake. If it was never posted, the wake will
+        * not happen, so wake here in that case.
+        */
+       rpcrdma_complete_rqst(req->rl_reply);
 }
index 85115a2..4345e69 100644 (file)
@@ -366,6 +366,9 @@ rpcrdma_encode_read_list(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req,
        unsigned int pos;
        int nsegs;
 
+       if (rtype == rpcrdma_noch)
+               goto done;
+
        pos = rqst->rq_snd_buf.head[0].iov_len;
        if (rtype == rpcrdma_areadch)
                pos = 0;
@@ -389,7 +392,8 @@ rpcrdma_encode_read_list(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req,
                nsegs -= mr->mr_nents;
        } while (nsegs);
 
-       return 0;
+done:
+       return encode_item_not_present(xdr);
 }
 
 /* Register and XDR encode the Write list. Supports encoding a list
@@ -417,6 +421,9 @@ rpcrdma_encode_write_list(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req,
        int nsegs, nchunks;
        __be32 *segcount;
 
+       if (wtype != rpcrdma_writech)
+               goto done;
+
        seg = req->rl_segments;
        nsegs = rpcrdma_convert_iovs(r_xprt, &rqst->rq_rcv_buf,
                                     rqst->rq_rcv_buf.head[0].iov_len,
@@ -451,7 +458,8 @@ rpcrdma_encode_write_list(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req,
        /* Update count of segments in this Write chunk */
        *segcount = cpu_to_be32(nchunks);
 
-       return 0;
+done:
+       return encode_item_not_present(xdr);
 }
 
 /* Register and XDR encode the Reply chunk. Supports encoding an array
@@ -476,6 +484,9 @@ rpcrdma_encode_reply_chunk(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req,
        int nsegs, nchunks;
        __be32 *segcount;
 
+       if (wtype != rpcrdma_replych)
+               return encode_item_not_present(xdr);
+
        seg = req->rl_segments;
        nsegs = rpcrdma_convert_iovs(r_xprt, &rqst->rq_rcv_buf, 0, wtype, seg);
        if (nsegs < 0)
@@ -511,6 +522,16 @@ rpcrdma_encode_reply_chunk(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req,
        return 0;
 }
 
+static void rpcrdma_sendctx_done(struct kref *kref)
+{
+       struct rpcrdma_req *req =
+               container_of(kref, struct rpcrdma_req, rl_kref);
+       struct rpcrdma_rep *rep = req->rl_reply;
+
+       rpcrdma_complete_rqst(rep);
+       rep->rr_rxprt->rx_stats.reply_waits_for_send++;
+}
+
 /**
  * rpcrdma_sendctx_unmap - DMA-unmap Send buffer
  * @sc: sendctx containing SGEs to unmap
@@ -520,6 +541,9 @@ void rpcrdma_sendctx_unmap(struct rpcrdma_sendctx *sc)
 {
        struct ib_sge *sge;
 
+       if (!sc->sc_unmap_count)
+               return;
+
        /* The first two SGEs contain the transport header and
         * the inline buffer. These are always left mapped so
         * they can be cheaply re-used.
@@ -529,9 +553,7 @@ void rpcrdma_sendctx_unmap(struct rpcrdma_sendctx *sc)
                ib_dma_unmap_page(sc->sc_device, sge->addr, sge->length,
                                  DMA_TO_DEVICE);
 
-       if (test_and_clear_bit(RPCRDMA_REQ_F_TX_RESOURCES,
-                              &sc->sc_req->rl_flags))
-               wake_up_bit(&sc->sc_req->rl_flags, RPCRDMA_REQ_F_TX_RESOURCES);
+       kref_put(&sc->sc_req->rl_kref, rpcrdma_sendctx_done);
 }
 
 /* Prepare an SGE for the RPC-over-RDMA transport header.
@@ -666,7 +688,7 @@ map_tail:
 out:
        sc->sc_wr.num_sge += sge_no;
        if (sc->sc_unmap_count)
-               __set_bit(RPCRDMA_REQ_F_TX_RESOURCES, &req->rl_flags);
+               kref_get(&req->rl_kref);
        return true;
 
 out_regbuf:
@@ -699,22 +721,28 @@ rpcrdma_prepare_send_sges(struct rpcrdma_xprt *r_xprt,
                          struct rpcrdma_req *req, u32 hdrlen,
                          struct xdr_buf *xdr, enum rpcrdma_chunktype rtype)
 {
+       int ret;
+
+       ret = -EAGAIN;
        req->rl_sendctx = rpcrdma_sendctx_get_locked(r_xprt);
        if (!req->rl_sendctx)
-               return -EAGAIN;
+               goto err;
        req->rl_sendctx->sc_wr.num_sge = 0;
        req->rl_sendctx->sc_unmap_count = 0;
        req->rl_sendctx->sc_req = req;
-       __clear_bit(RPCRDMA_REQ_F_TX_RESOURCES, &req->rl_flags);
+       kref_init(&req->rl_kref);
 
+       ret = -EIO;
        if (!rpcrdma_prepare_hdr_sge(r_xprt, req, hdrlen))
-               return -EIO;
-
+               goto err;
        if (rtype != rpcrdma_areadch)
                if (!rpcrdma_prepare_msg_sges(r_xprt, req, xdr, rtype))
-                       return -EIO;
-
+                       goto err;
        return 0;
+
+err:
+       trace_xprtrdma_prepsend_failed(&req->rl_slot, ret);
+       return ret;
 }
 
 /**
@@ -842,50 +870,28 @@ rpcrdma_marshal_req(struct rpcrdma_xprt *r_xprt, struct rpc_rqst *rqst)
         * send a Call message with a Position Zero Read chunk and a
         * regular Read chunk at the same time.
         */
-       if (rtype != rpcrdma_noch) {
-               ret = rpcrdma_encode_read_list(r_xprt, req, rqst, rtype);
-               if (ret)
-                       goto out_err;
-       }
-       ret = encode_item_not_present(xdr);
+       ret = rpcrdma_encode_read_list(r_xprt, req, rqst, rtype);
        if (ret)
                goto out_err;
-
-       if (wtype == rpcrdma_writech) {
-               ret = rpcrdma_encode_write_list(r_xprt, req, rqst, wtype);
-               if (ret)
-                       goto out_err;
-       }
-       ret = encode_item_not_present(xdr);
+       ret = rpcrdma_encode_write_list(r_xprt, req, rqst, wtype);
        if (ret)
                goto out_err;
-
-       if (wtype != rpcrdma_replych)
-               ret = encode_item_not_present(xdr);
-       else
-               ret = rpcrdma_encode_reply_chunk(r_xprt, req, rqst, wtype);
+       ret = rpcrdma_encode_reply_chunk(r_xprt, req, rqst, wtype);
        if (ret)
                goto out_err;
 
-       trace_xprtrdma_marshal(rqst, xdr_stream_pos(xdr), rtype, wtype);
-
-       ret = rpcrdma_prepare_send_sges(r_xprt, req, xdr_stream_pos(xdr),
+       ret = rpcrdma_prepare_send_sges(r_xprt, req, req->rl_hdrbuf.len,
                                        &rqst->rq_snd_buf, rtype);
        if (ret)
                goto out_err;
+
+       trace_xprtrdma_marshal(req, rtype, wtype);
        return 0;
 
 out_err:
        trace_xprtrdma_marshal_failed(rqst, ret);
-       switch (ret) {
-       case -EAGAIN:
-               xprt_wait_for_buffer_space(rqst->rq_xprt);
-               break;
-       case -ENOBUFS:
-               break;
-       default:
-               r_xprt->rx_stats.failed_marshal_count++;
-       }
+       r_xprt->rx_stats.failed_marshal_count++;
+       frwr_reset(req);
        return ret;
 }
 
@@ -1269,51 +1275,17 @@ out_badheader:
        goto out;
 }
 
-void rpcrdma_release_rqst(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
-{
-       /* Invalidate and unmap the data payloads before waking
-        * the waiting application. This guarantees the memory
-        * regions are properly fenced from the server before the
-        * application accesses the data. It also ensures proper
-        * send flow control: waking the next RPC waits until this
-        * RPC has relinquished all its Send Queue entries.
-        */
-       if (!list_empty(&req->rl_registered))
-               frwr_unmap_sync(r_xprt, &req->rl_registered);
-
-       /* Ensure that any DMA mapped pages associated with
-        * the Send of the RPC Call have been unmapped before
-        * allowing the RPC to complete. This protects argument
-        * memory not controlled by the RPC client from being
-        * re-used before we're done with it.
-        */
-       if (test_bit(RPCRDMA_REQ_F_TX_RESOURCES, &req->rl_flags)) {
-               r_xprt->rx_stats.reply_waits_for_send++;
-               out_of_line_wait_on_bit(&req->rl_flags,
-                                       RPCRDMA_REQ_F_TX_RESOURCES,
-                                       bit_wait,
-                                       TASK_UNINTERRUPTIBLE);
-       }
-}
-
-/* Reply handling runs in the poll worker thread. Anything that
- * might wait is deferred to a separate workqueue.
- */
-void rpcrdma_deferred_completion(struct work_struct *work)
+static void rpcrdma_reply_done(struct kref *kref)
 {
-       struct rpcrdma_rep *rep =
-                       container_of(work, struct rpcrdma_rep, rr_work);
-       struct rpcrdma_req *req = rpcr_to_rdmar(rep->rr_rqst);
-       struct rpcrdma_xprt *r_xprt = rep->rr_rxprt;
+       struct rpcrdma_req *req =
+               container_of(kref, struct rpcrdma_req, rl_kref);
 
-       trace_xprtrdma_defer_cmp(rep);
-       if (rep->rr_wc_flags & IB_WC_WITH_INVALIDATE)
-               frwr_reminv(rep, &req->rl_registered);
-       rpcrdma_release_rqst(r_xprt, req);
-       rpcrdma_complete_rqst(rep);
+       rpcrdma_complete_rqst(req->rl_reply);
 }
 
-/* Process received RPC/RDMA messages.
+/**
+ * rpcrdma_reply_handler - Process received RPC/RDMA messages
+ * @rep: Incoming rpcrdma_rep object to process
  *
  * Errors must result in the RPC task either being awakened, or
  * allowed to timeout, to discover the errors at that time.
@@ -1360,10 +1332,10 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *rep)
        else if (credits > buf->rb_max_requests)
                credits = buf->rb_max_requests;
        if (buf->rb_credits != credits) {
-               spin_lock_bh(&xprt->transport_lock);
+               spin_lock(&xprt->transport_lock);
                buf->rb_credits = credits;
                xprt->cwnd = credits << RPC_CWNDSHIFT;
-               spin_unlock_bh(&xprt->transport_lock);
+               spin_unlock(&xprt->transport_lock);
        }
 
        req = rpcr_to_rdmar(rqst);
@@ -1373,10 +1345,16 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *rep)
        }
        req->rl_reply = rep;
        rep->rr_rqst = rqst;
-       clear_bit(RPCRDMA_REQ_F_PENDING, &req->rl_flags);
 
        trace_xprtrdma_reply(rqst->rq_task, rep, req, credits);
-       queue_work(buf->rb_completion_wq, &rep->rr_work);
+
+       if (rep->rr_wc_flags & IB_WC_WITH_INVALIDATE)
+               frwr_reminv(rep, &req->rl_registered);
+       if (!list_empty(&req->rl_registered))
+               frwr_unmap_async(r_xprt, req);
+               /* LocalInv completion will complete the RPC */
+       else
+               kref_put(&req->rl_kref, rpcrdma_reply_done);
        return;
 
 out_badversion:
index bed57d8..d1fcc41 100644 (file)
@@ -72,9 +72,9 @@ int svc_rdma_handle_bc_reply(struct rpc_xprt *xprt, __be32 *rdma_resp,
        else if (credits > r_xprt->rx_buf.rb_bc_max_requests)
                credits = r_xprt->rx_buf.rb_bc_max_requests;
 
-       spin_lock_bh(&xprt->transport_lock);
+       spin_lock(&xprt->transport_lock);
        xprt->cwnd = credits << RPC_CWNDSHIFT;
-       spin_unlock_bh(&xprt->transport_lock);
+       spin_unlock(&xprt->transport_lock);
 
        spin_lock(&xprt->queue_lock);
        ret = 0;
index 0004535..3fe6651 100644 (file)
@@ -226,9 +226,9 @@ static void handle_connect_req(struct rdma_cm_id *new_cma_id,
         * Enqueue the new transport on the accept queue of the listening
         * transport
         */
-       spin_lock_bh(&listen_xprt->sc_lock);
+       spin_lock(&listen_xprt->sc_lock);
        list_add_tail(&newxprt->sc_accept_q, &listen_xprt->sc_accept_q);
-       spin_unlock_bh(&listen_xprt->sc_lock);
+       spin_unlock(&listen_xprt->sc_lock);
 
        set_bit(XPT_CONN, &listen_xprt->sc_xprt.xpt_flags);
        svc_xprt_enqueue(&listen_xprt->sc_xprt);
@@ -401,7 +401,7 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
        listen_rdma = container_of(xprt, struct svcxprt_rdma, sc_xprt);
        clear_bit(XPT_CONN, &xprt->xpt_flags);
        /* Get the next entry off the accept list */
-       spin_lock_bh(&listen_rdma->sc_lock);
+       spin_lock(&listen_rdma->sc_lock);
        if (!list_empty(&listen_rdma->sc_accept_q)) {
                newxprt = list_entry(listen_rdma->sc_accept_q.next,
                                     struct svcxprt_rdma, sc_accept_q);
@@ -409,7 +409,7 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
        }
        if (!list_empty(&listen_rdma->sc_accept_q))
                set_bit(XPT_CONN, &listen_rdma->sc_xprt.xpt_flags);
-       spin_unlock_bh(&listen_rdma->sc_lock);
+       spin_unlock(&listen_rdma->sc_lock);
        if (!newxprt)
                return NULL;
 
index 1f73a6a..2ec349e 100644 (file)
@@ -80,7 +80,6 @@ static unsigned int min_slot_table_size = RPCRDMA_MIN_SLOT_TABLE;
 static unsigned int max_slot_table_size = RPCRDMA_MAX_SLOT_TABLE;
 static unsigned int min_inline_size = RPCRDMA_MIN_INLINE;
 static unsigned int max_inline_size = RPCRDMA_MAX_INLINE;
-static unsigned int zero;
 static unsigned int max_padding = PAGE_SIZE;
 static unsigned int min_memreg = RPCRDMA_BOUNCEBUFFERS;
 static unsigned int max_memreg = RPCRDMA_LAST - 1;
@@ -122,7 +121,7 @@ static struct ctl_table xr_tunables_table[] = {
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &max_padding,
        },
        {
@@ -298,6 +297,7 @@ xprt_rdma_destroy(struct rpc_xprt *xprt)
        module_put(THIS_MODULE);
 }
 
+/* 60 second timeout, no retries */
 static const struct rpc_timeout xprt_rdma_default_timeout = {
        .to_initval = 60 * HZ,
        .to_maxval = 60 * HZ,
@@ -323,8 +323,9 @@ xprt_setup_rdma(struct xprt_create *args)
        if (!xprt)
                return ERR_PTR(-ENOMEM);
 
-       /* 60 second timeout, no retries */
        xprt->timeout = &xprt_rdma_default_timeout;
+       xprt->connect_timeout = xprt->timeout->to_initval;
+       xprt->max_reconnect_timeout = xprt->timeout->to_maxval;
        xprt->bind_timeout = RPCRDMA_BIND_TO;
        xprt->reestablish_timeout = RPCRDMA_INIT_REEST_TO;
        xprt->idle_timeout = RPCRDMA_IDLE_DISC_TO;
@@ -487,31 +488,64 @@ xprt_rdma_timer(struct rpc_xprt *xprt, struct rpc_task *task)
 }
 
 /**
- * xprt_rdma_connect - try to establish a transport connection
+ * xprt_rdma_set_connect_timeout - set timeouts for establishing a connection
+ * @xprt: controlling transport instance
+ * @connect_timeout: reconnect timeout after client disconnects
+ * @reconnect_timeout: reconnect timeout after server disconnects
+ *
+ */
+static void xprt_rdma_tcp_set_connect_timeout(struct rpc_xprt *xprt,
+                                             unsigned long connect_timeout,
+                                             unsigned long reconnect_timeout)
+{
+       struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
+
+       trace_xprtrdma_op_set_cto(r_xprt, connect_timeout, reconnect_timeout);
+
+       spin_lock(&xprt->transport_lock);
+
+       if (connect_timeout < xprt->connect_timeout) {
+               struct rpc_timeout to;
+               unsigned long initval;
+
+               to = *xprt->timeout;
+               initval = connect_timeout;
+               if (initval < RPCRDMA_INIT_REEST_TO << 1)
+                       initval = RPCRDMA_INIT_REEST_TO << 1;
+               to.to_initval = initval;
+               to.to_maxval = initval;
+               r_xprt->rx_timeout = to;
+               xprt->timeout = &r_xprt->rx_timeout;
+               xprt->connect_timeout = connect_timeout;
+       }
+
+       if (reconnect_timeout < xprt->max_reconnect_timeout)
+               xprt->max_reconnect_timeout = reconnect_timeout;
+
+       spin_unlock(&xprt->transport_lock);
+}
+
+/**
+ * xprt_rdma_connect - schedule an attempt to reconnect
  * @xprt: transport state
- * @task: RPC scheduler context
+ * @task: RPC scheduler context (unused)
  *
  */
 static void
 xprt_rdma_connect(struct rpc_xprt *xprt, struct rpc_task *task)
 {
        struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
+       unsigned long delay;
 
        trace_xprtrdma_op_connect(r_xprt);
+
+       delay = 0;
        if (r_xprt->rx_ep.rep_connected != 0) {
-               /* Reconnect */
-               schedule_delayed_work(&r_xprt->rx_connect_worker,
-                                     xprt->reestablish_timeout);
-               xprt->reestablish_timeout <<= 1;
-               if (xprt->reestablish_timeout > RPCRDMA_MAX_REEST_TO)
-                       xprt->reestablish_timeout = RPCRDMA_MAX_REEST_TO;
-               else if (xprt->reestablish_timeout < RPCRDMA_INIT_REEST_TO)
-                       xprt->reestablish_timeout = RPCRDMA_INIT_REEST_TO;
-       } else {
-               schedule_delayed_work(&r_xprt->rx_connect_worker, 0);
-               if (!RPC_IS_ASYNC(task))
-                       flush_delayed_work(&r_xprt->rx_connect_worker);
+               delay = xprt_reconnect_delay(xprt);
+               xprt_reconnect_backoff(xprt, RPCRDMA_INIT_REEST_TO);
        }
+       queue_delayed_work(xprtiod_workqueue, &r_xprt->rx_connect_worker,
+                          delay);
 }
 
 /**
@@ -550,8 +584,11 @@ out_sleep:
 static void
 xprt_rdma_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *rqst)
 {
+       struct rpcrdma_xprt *r_xprt =
+               container_of(xprt, struct rpcrdma_xprt, rx_xprt);
+
        memset(rqst, 0, sizeof(*rqst));
-       rpcrdma_buffer_put(rpcr_to_rdmar(rqst));
+       rpcrdma_buffer_put(&r_xprt->rx_buf, rpcr_to_rdmar(rqst));
        rpc_wake_up_next(&xprt->backlog);
 }
 
@@ -618,9 +655,16 @@ xprt_rdma_free(struct rpc_task *task)
        struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(rqst->rq_xprt);
        struct rpcrdma_req *req = rpcr_to_rdmar(rqst);
 
-       if (test_bit(RPCRDMA_REQ_F_PENDING, &req->rl_flags))
-               rpcrdma_release_rqst(r_xprt, req);
        trace_xprtrdma_op_free(task, req);
+
+       if (!list_empty(&req->rl_registered))
+               frwr_unmap_sync(r_xprt, req);
+
+       /* XXX: If the RPC is completing because of a signal and
+        * not because a reply was received, we ought to ensure
+        * that the Send completion has fired, so that memory
+        * involved with the Send is not still visible to the NIC.
+        */
 }
 
 /**
@@ -667,7 +711,6 @@ xprt_rdma_send_request(struct rpc_rqst *rqst)
                goto drop_connection;
        rqst->rq_xtime = ktime_get();
 
-       __set_bit(RPCRDMA_REQ_F_PENDING, &req->rl_flags);
        if (rpcrdma_ep_post(&r_xprt->rx_ia, &r_xprt->rx_ep, req))
                goto drop_connection;
 
@@ -760,6 +803,7 @@ static const struct rpc_xprt_ops xprt_rdma_procs = {
        .send_request           = xprt_rdma_send_request,
        .close                  = xprt_rdma_close,
        .destroy                = xprt_rdma_destroy,
+       .set_connect_timeout    = xprt_rdma_tcp_set_connect_timeout,
        .print_stats            = xprt_rdma_print_stats,
        .enable_swap            = xprt_rdma_enable_swap,
        .disable_swap           = xprt_rdma_disable_swap,
@@ -767,6 +811,7 @@ static const struct rpc_xprt_ops xprt_rdma_procs = {
 #if defined(CONFIG_SUNRPC_BACKCHANNEL)
        .bc_setup               = xprt_rdma_bc_setup,
        .bc_maxpayload          = xprt_rdma_bc_maxpayload,
+       .bc_num_slots           = xprt_rdma_bc_max_slots,
        .bc_free_rqst           = xprt_rdma_bc_free_rqst,
        .bc_destroy             = xprt_rdma_bc_destroy,
 #endif
index 84bb379..805b1f3 100644 (file)
@@ -89,14 +89,12 @@ static void rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, bool temp);
  */
 static void rpcrdma_xprt_drain(struct rpcrdma_xprt *r_xprt)
 {
-       struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
        struct rpcrdma_ia *ia = &r_xprt->rx_ia;
 
        /* Flush Receives, then wait for deferred Reply work
         * to complete.
         */
        ib_drain_rq(ia->ri_id->qp);
-       drain_workqueue(buf->rb_completion_wq);
 
        /* Deferred Reply processing might have scheduled
         * local invalidations.
@@ -901,7 +899,7 @@ out_emptyq:
         * completions recently. This is a sign the Send Queue is
         * backing up. Cause the caller to pause and try again.
         */
-       set_bit(RPCRDMA_BUF_F_EMPTY_SCQ, &buf->rb_flags);
+       xprt_wait_for_buffer_space(&r_xprt->rx_xprt);
        r_xprt->rx_stats.empty_sendctx_q++;
        return NULL;
 }
@@ -936,10 +934,7 @@ rpcrdma_sendctx_put_locked(struct rpcrdma_sendctx *sc)
        /* Paired with READ_ONCE */
        smp_store_release(&buf->rb_sc_tail, next_tail);
 
-       if (test_and_clear_bit(RPCRDMA_BUF_F_EMPTY_SCQ, &buf->rb_flags)) {
-               smp_mb__after_atomic();
-               xprt_write_space(&sc->sc_xprt->rx_xprt);
-       }
+       xprt_write_space(&sc->sc_xprt->rx_xprt);
 }
 
 static void
@@ -977,8 +972,6 @@ rpcrdma_mrs_create(struct rpcrdma_xprt *r_xprt)
        r_xprt->rx_stats.mrs_allocated += count;
        spin_unlock(&buf->rb_mrlock);
        trace_xprtrdma_createmrs(r_xprt, count);
-
-       xprt_write_space(&r_xprt->rx_xprt);
 }
 
 static void
@@ -990,6 +983,7 @@ rpcrdma_mr_refresh_worker(struct work_struct *work)
                                                   rx_buf);
 
        rpcrdma_mrs_create(r_xprt);
+       xprt_write_space(&r_xprt->rx_xprt);
 }
 
 /**
@@ -1025,7 +1019,6 @@ struct rpcrdma_req *rpcrdma_req_create(struct rpcrdma_xprt *r_xprt, size_t size,
        if (!req->rl_recvbuf)
                goto out4;
 
-       req->rl_buffer = buffer;
        INIT_LIST_HEAD(&req->rl_registered);
        spin_lock(&buffer->rb_lock);
        list_add(&req->rl_all, &buffer->rb_allreqs);
@@ -1042,9 +1035,9 @@ out1:
        return NULL;
 }
 
-static bool rpcrdma_rep_create(struct rpcrdma_xprt *r_xprt, bool temp)
+static struct rpcrdma_rep *rpcrdma_rep_create(struct rpcrdma_xprt *r_xprt,
+                                             bool temp)
 {
-       struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
        struct rpcrdma_rep *rep;
 
        rep = kzalloc(sizeof(*rep), GFP_KERNEL);
@@ -1055,27 +1048,22 @@ static bool rpcrdma_rep_create(struct rpcrdma_xprt *r_xprt, bool temp)
                                               DMA_FROM_DEVICE, GFP_KERNEL);
        if (!rep->rr_rdmabuf)
                goto out_free;
+
        xdr_buf_init(&rep->rr_hdrbuf, rdmab_data(rep->rr_rdmabuf),
                     rdmab_length(rep->rr_rdmabuf));
-
        rep->rr_cqe.done = rpcrdma_wc_receive;
        rep->rr_rxprt = r_xprt;
-       INIT_WORK(&rep->rr_work, rpcrdma_deferred_completion);
        rep->rr_recv_wr.next = NULL;
        rep->rr_recv_wr.wr_cqe = &rep->rr_cqe;
        rep->rr_recv_wr.sg_list = &rep->rr_rdmabuf->rg_iov;
        rep->rr_recv_wr.num_sge = 1;
        rep->rr_temp = temp;
-
-       spin_lock(&buf->rb_lock);
-       list_add(&rep->rr_list, &buf->rb_recv_bufs);
-       spin_unlock(&buf->rb_lock);
-       return true;
+       return rep;
 
 out_free:
        kfree(rep);
 out:
-       return false;
+       return NULL;
 }
 
 /**
@@ -1089,7 +1077,6 @@ int rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt)
        struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
        int i, rc;
 
-       buf->rb_flags = 0;
        buf->rb_max_requests = r_xprt->rx_ep.rep_max_requests;
        buf->rb_bc_srv_max_requests = 0;
        spin_lock_init(&buf->rb_mrlock);
@@ -1122,15 +1109,6 @@ int rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt)
        if (rc)
                goto out;
 
-       buf->rb_completion_wq = alloc_workqueue("rpcrdma-%s",
-                                               WQ_MEM_RECLAIM | WQ_HIGHPRI,
-                                               0,
-                       r_xprt->rx_xprt.address_strings[RPC_DISPLAY_ADDR]);
-       if (!buf->rb_completion_wq) {
-               rc = -ENOMEM;
-               goto out;
-       }
-
        return 0;
 out:
        rpcrdma_buffer_destroy(buf);
@@ -1204,11 +1182,6 @@ rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf)
 {
        cancel_delayed_work_sync(&buf->rb_refresh_worker);
 
-       if (buf->rb_completion_wq) {
-               destroy_workqueue(buf->rb_completion_wq);
-               buf->rb_completion_wq = NULL;
-       }
-
        rpcrdma_sendctxs_destroy(buf);
 
        while (!list_empty(&buf->rb_recv_bufs)) {
@@ -1325,13 +1298,12 @@ rpcrdma_buffer_get(struct rpcrdma_buffer *buffers)
 
 /**
  * rpcrdma_buffer_put - Put request/reply buffers back into pool
+ * @buffers: buffer pool
  * @req: object to return
  *
  */
-void
-rpcrdma_buffer_put(struct rpcrdma_req *req)
+void rpcrdma_buffer_put(struct rpcrdma_buffer *buffers, struct rpcrdma_req *req)
 {
-       struct rpcrdma_buffer *buffers = req->rl_buffer;
        struct rpcrdma_rep *rep = req->rl_reply;
 
        req->rl_reply = NULL;
@@ -1484,8 +1456,7 @@ rpcrdma_ep_post(struct rpcrdma_ia *ia,
        struct ib_send_wr *send_wr = &req->rl_sendctx->sc_wr;
        int rc;
 
-       if (!ep->rep_send_count ||
-           test_bit(RPCRDMA_REQ_F_TX_RESOURCES, &req->rl_flags)) {
+       if (!ep->rep_send_count || kref_read(&req->rl_kref) > 1) {
                send_wr->send_flags |= IB_SEND_SIGNALED;
                ep->rep_send_count = ep->rep_send_batch;
        } else {
@@ -1505,11 +1476,13 @@ rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, bool temp)
 {
        struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
        struct rpcrdma_ep *ep = &r_xprt->rx_ep;
-       struct ib_recv_wr *wr, *bad_wr;
+       struct ib_recv_wr *i, *wr, *bad_wr;
+       struct rpcrdma_rep *rep;
        int needed, count, rc;
 
        rc = 0;
        count = 0;
+
        needed = buf->rb_credits + (buf->rb_bc_srv_max_requests << 1);
        if (ep->rep_receive_count > needed)
                goto out;
@@ -1517,51 +1490,65 @@ rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, bool temp)
        if (!temp)
                needed += RPCRDMA_MAX_RECV_BATCH;
 
-       count = 0;
+       /* fast path: all needed reps can be found on the free list */
        wr = NULL;
+       spin_lock(&buf->rb_lock);
        while (needed) {
-               struct rpcrdma_regbuf *rb;
-               struct rpcrdma_rep *rep;
-
-               spin_lock(&buf->rb_lock);
                rep = list_first_entry_or_null(&buf->rb_recv_bufs,
                                               struct rpcrdma_rep, rr_list);
-               if (likely(rep))
-                       list_del(&rep->rr_list);
-               spin_unlock(&buf->rb_lock);
-               if (!rep) {
-                       if (!rpcrdma_rep_create(r_xprt, temp))
-                               break;
-                       continue;
-               }
+               if (!rep)
+                       break;
 
-               rb = rep->rr_rdmabuf;
-               if (!rpcrdma_regbuf_dma_map(r_xprt, rb)) {
-                       rpcrdma_recv_buffer_put(rep);
+               list_del(&rep->rr_list);
+               rep->rr_recv_wr.next = wr;
+               wr = &rep->rr_recv_wr;
+               --needed;
+       }
+       spin_unlock(&buf->rb_lock);
+
+       while (needed) {
+               rep = rpcrdma_rep_create(r_xprt, temp);
+               if (!rep)
                        break;
-               }
 
-               trace_xprtrdma_post_recv(rep->rr_recv_wr.wr_cqe);
                rep->rr_recv_wr.next = wr;
                wr = &rep->rr_recv_wr;
-               ++count;
                --needed;
        }
-       if (!count)
+       if (!wr)
                goto out;
 
+       for (i = wr; i; i = i->next) {
+               rep = container_of(i, struct rpcrdma_rep, rr_recv_wr);
+
+               if (!rpcrdma_regbuf_dma_map(r_xprt, rep->rr_rdmabuf))
+                       goto release_wrs;
+
+               trace_xprtrdma_post_recv(rep->rr_recv_wr.wr_cqe);
+               ++count;
+       }
+
        rc = ib_post_recv(r_xprt->rx_ia.ri_id->qp, wr,
                          (const struct ib_recv_wr **)&bad_wr);
+out:
+       trace_xprtrdma_post_recvs(r_xprt, count, rc);
        if (rc) {
-               for (wr = bad_wr; wr; wr = wr->next) {
+               for (wr = bad_wr; wr;) {
                        struct rpcrdma_rep *rep;
 
                        rep = container_of(wr, struct rpcrdma_rep, rr_recv_wr);
+                       wr = wr->next;
                        rpcrdma_recv_buffer_put(rep);
                        --count;
                }
        }
        ep->rep_receive_count += count;
-out:
-       trace_xprtrdma_post_recvs(r_xprt, count, rc);
+       return;
+
+release_wrs:
+       for (i = wr; i;) {
+               rep = container_of(i, struct rpcrdma_rep, rr_recv_wr);
+               i = i->next;
+               rpcrdma_recv_buffer_put(rep);
+       }
 }
index d1e0749..92ce09f 100644 (file)
@@ -44,7 +44,8 @@
 
 #include <linux/wait.h>                /* wait_queue_head_t, etc */
 #include <linux/spinlock.h>            /* spinlock_t, etc */
-#include <linux/atomic.h>                      /* atomic_t, etc */
+#include <linux/atomic.h>              /* atomic_t, etc */
+#include <linux/kref.h>                        /* struct kref */
 #include <linux/workqueue.h>           /* struct work_struct */
 
 #include <rdma/rdma_cm.h>              /* RDMA connection api */
@@ -202,10 +203,9 @@ struct rpcrdma_rep {
        bool                    rr_temp;
        struct rpcrdma_regbuf   *rr_rdmabuf;
        struct rpcrdma_xprt     *rr_rxprt;
-       struct work_struct      rr_work;
+       struct rpc_rqst         *rr_rqst;
        struct xdr_buf          rr_hdrbuf;
        struct xdr_stream       rr_stream;
-       struct rpc_rqst         *rr_rqst;
        struct list_head        rr_list;
        struct ib_recv_wr       rr_recv_wr;
 };
@@ -240,18 +240,12 @@ struct rpcrdma_sendctx {
  * An external memory region is any buffer or page that is registered
  * on the fly (ie, not pre-registered).
  */
-enum rpcrdma_frwr_state {
-       FRWR_IS_INVALID,        /* ready to be used */
-       FRWR_IS_VALID,          /* in use */
-       FRWR_FLUSHED_FR,        /* flushed FASTREG WR */
-       FRWR_FLUSHED_LI,        /* flushed LOCALINV WR */
-};
-
+struct rpcrdma_req;
 struct rpcrdma_frwr {
        struct ib_mr                    *fr_mr;
        struct ib_cqe                   fr_cqe;
-       enum rpcrdma_frwr_state         fr_state;
        struct completion               fr_linv_done;
+       struct rpcrdma_req              *fr_req;
        union {
                struct ib_reg_wr        fr_regwr;
                struct ib_send_wr       fr_invwr;
@@ -326,7 +320,6 @@ struct rpcrdma_buffer;
 struct rpcrdma_req {
        struct list_head        rl_list;
        struct rpc_rqst         rl_slot;
-       struct rpcrdma_buffer   *rl_buffer;
        struct rpcrdma_rep      *rl_reply;
        struct xdr_stream       rl_stream;
        struct xdr_buf          rl_hdrbuf;
@@ -336,18 +329,12 @@ struct rpcrdma_req {
        struct rpcrdma_regbuf   *rl_recvbuf;    /* rq_rcv_buf */
 
        struct list_head        rl_all;
-       unsigned long           rl_flags;
+       struct kref             rl_kref;
 
        struct list_head        rl_registered;  /* registered segments */
        struct rpcrdma_mr_seg   rl_segments[RPCRDMA_MAX_SEGS];
 };
 
-/* rl_flags */
-enum {
-       RPCRDMA_REQ_F_PENDING = 0,
-       RPCRDMA_REQ_F_TX_RESOURCES,
-};
-
 static inline struct rpcrdma_req *
 rpcr_to_rdmar(const struct rpc_rqst *rqst)
 {
@@ -391,22 +378,15 @@ struct rpcrdma_buffer {
        struct list_head        rb_recv_bufs;
        struct list_head        rb_allreqs;
 
-       unsigned long           rb_flags;
        u32                     rb_max_requests;
        u32                     rb_credits;     /* most recent credit grant */
 
        u32                     rb_bc_srv_max_requests;
        u32                     rb_bc_max_requests;
 
-       struct workqueue_struct *rb_completion_wq;
        struct delayed_work     rb_refresh_worker;
 };
 
-/* rb_flags */
-enum {
-       RPCRDMA_BUF_F_EMPTY_SCQ = 0,
-};
-
 /*
  * Statistics for RPCRDMA
  */
@@ -452,6 +432,7 @@ struct rpcrdma_xprt {
        struct rpcrdma_ep       rx_ep;
        struct rpcrdma_buffer   rx_buf;
        struct delayed_work     rx_connect_worker;
+       struct rpc_timeout      rx_timeout;
        struct rpcrdma_stats    rx_stats;
 };
 
@@ -518,7 +499,8 @@ rpcrdma_mr_recycle(struct rpcrdma_mr *mr)
 }
 
 struct rpcrdma_req *rpcrdma_buffer_get(struct rpcrdma_buffer *);
-void rpcrdma_buffer_put(struct rpcrdma_req *);
+void rpcrdma_buffer_put(struct rpcrdma_buffer *buffers,
+                       struct rpcrdma_req *req);
 void rpcrdma_recv_buffer_put(struct rpcrdma_rep *);
 
 bool rpcrdma_regbuf_realloc(struct rpcrdma_regbuf *rb, size_t size,
@@ -564,6 +546,7 @@ rpcrdma_data_dir(bool writing)
 /* Memory registration calls xprtrdma/frwr_ops.c
  */
 bool frwr_is_supported(struct ib_device *device);
+void frwr_reset(struct rpcrdma_req *req);
 int frwr_open(struct rpcrdma_ia *ia, struct rpcrdma_ep *ep);
 int frwr_init_mr(struct rpcrdma_ia *ia, struct rpcrdma_mr *mr);
 void frwr_release_mr(struct rpcrdma_mr *mr);
@@ -574,8 +557,8 @@ struct rpcrdma_mr_seg *frwr_map(struct rpcrdma_xprt *r_xprt,
                                struct rpcrdma_mr **mr);
 int frwr_send(struct rpcrdma_ia *ia, struct rpcrdma_req *req);
 void frwr_reminv(struct rpcrdma_rep *rep, struct list_head *mrs);
-void frwr_unmap_sync(struct rpcrdma_xprt *r_xprt,
-                    struct list_head *mrs);
+void frwr_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req);
+void frwr_unmap_async(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req);
 
 /*
  * RPC/RDMA protocol calls - xprtrdma/rpc_rdma.c
@@ -598,9 +581,6 @@ int rpcrdma_marshal_req(struct rpcrdma_xprt *r_xprt, struct rpc_rqst *rqst);
 void rpcrdma_set_max_header_sizes(struct rpcrdma_xprt *);
 void rpcrdma_complete_rqst(struct rpcrdma_rep *rep);
 void rpcrdma_reply_handler(struct rpcrdma_rep *rep);
-void rpcrdma_release_rqst(struct rpcrdma_xprt *r_xprt,
-                         struct rpcrdma_req *req);
-void rpcrdma_deferred_completion(struct work_struct *work);
 
 static inline void rpcrdma_set_xdrlen(struct xdr_buf *xdr, size_t len)
 {
@@ -625,6 +605,7 @@ void xprt_rdma_cleanup(void);
 #if defined(CONFIG_SUNRPC_BACKCHANNEL)
 int xprt_rdma_bc_setup(struct rpc_xprt *, unsigned int);
 size_t xprt_rdma_bc_maxpayload(struct rpc_xprt *);
+unsigned int xprt_rdma_bc_max_slots(struct rpc_xprt *);
 int rpcrdma_bc_post_recv(struct rpcrdma_xprt *, unsigned int);
 void rpcrdma_bc_receive_call(struct rpcrdma_xprt *, struct rpcrdma_rep *);
 int xprt_rdma_bc_send_reply(struct rpc_rqst *rqst);
index 3665235..e2176c1 100644 (file)
@@ -880,7 +880,7 @@ static int xs_nospace(struct rpc_rqst *req)
                        req->rq_slen);
 
        /* Protect against races with write_space */
-       spin_lock_bh(&xprt->transport_lock);
+       spin_lock(&xprt->transport_lock);
 
        /* Don't race with disconnect */
        if (xprt_connected(xprt)) {
@@ -890,7 +890,7 @@ static int xs_nospace(struct rpc_rqst *req)
        } else
                ret = -ENOTCONN;
 
-       spin_unlock_bh(&xprt->transport_lock);
+       spin_unlock(&xprt->transport_lock);
 
        /* Race breaker in case memory is freed before above code is called */
        if (ret == -EAGAIN) {
@@ -909,6 +909,7 @@ static int xs_nospace(struct rpc_rqst *req)
 static void
 xs_stream_prepare_request(struct rpc_rqst *req)
 {
+       xdr_free_bvec(&req->rq_rcv_buf);
        req->rq_task->tk_status = xdr_alloc_bvec(&req->rq_rcv_buf, GFP_KERNEL);
 }
 
@@ -1211,6 +1212,15 @@ static void xs_sock_reset_state_flags(struct rpc_xprt *xprt)
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
 
        clear_bit(XPRT_SOCK_DATA_READY, &transport->sock_state);
+       clear_bit(XPRT_SOCK_WAKE_ERROR, &transport->sock_state);
+       clear_bit(XPRT_SOCK_WAKE_WRITE, &transport->sock_state);
+       clear_bit(XPRT_SOCK_WAKE_DISCONNECT, &transport->sock_state);
+}
+
+static void xs_run_error_worker(struct sock_xprt *transport, unsigned int nr)
+{
+       set_bit(nr, &transport->sock_state);
+       queue_work(xprtiod_workqueue, &transport->error_worker);
 }
 
 static void xs_sock_reset_connection_flags(struct rpc_xprt *xprt)
@@ -1231,6 +1241,7 @@ static void xs_sock_reset_connection_flags(struct rpc_xprt *xprt)
  */
 static void xs_error_report(struct sock *sk)
 {
+       struct sock_xprt *transport;
        struct rpc_xprt *xprt;
        int err;
 
@@ -1238,13 +1249,14 @@ static void xs_error_report(struct sock *sk)
        if (!(xprt = xprt_from_sock(sk)))
                goto out;
 
+       transport = container_of(xprt, struct sock_xprt, xprt);
        err = -sk->sk_err;
        if (err == 0)
                goto out;
        dprintk("RPC:       xs_error_report client %p, error=%d...\n",
                        xprt, -err);
        trace_rpc_socket_error(xprt, sk->sk_socket, err);
-       xprt_wake_pending_tasks(xprt, err);
+       xs_run_error_worker(transport, XPRT_SOCK_WAKE_ERROR);
  out:
        read_unlock_bh(&sk->sk_callback_lock);
 }
@@ -1333,6 +1345,7 @@ static void xs_destroy(struct rpc_xprt *xprt)
        cancel_delayed_work_sync(&transport->connect_worker);
        xs_close(xprt);
        cancel_work_sync(&transport->recv_worker);
+       cancel_work_sync(&transport->error_worker);
        xs_xprt_free(xprt);
        module_put(THIS_MODULE);
 }
@@ -1386,9 +1399,9 @@ static void xs_udp_data_read_skb(struct rpc_xprt *xprt,
        }
 
 
-       spin_lock_bh(&xprt->transport_lock);
+       spin_lock(&xprt->transport_lock);
        xprt_adjust_cwnd(xprt, task, copied);
-       spin_unlock_bh(&xprt->transport_lock);
+       spin_unlock(&xprt->transport_lock);
        spin_lock(&xprt->queue_lock);
        xprt_complete_rqst(task, copied);
        __UDPX_INC_STATS(sk, UDP_MIB_INDATAGRAMS);
@@ -1498,7 +1511,6 @@ static void xs_tcp_state_change(struct sock *sk)
        trace_rpc_socket_state_change(xprt, sk->sk_socket);
        switch (sk->sk_state) {
        case TCP_ESTABLISHED:
-               spin_lock(&xprt->transport_lock);
                if (!xprt_test_and_set_connected(xprt)) {
                        xprt->connect_cookie++;
                        clear_bit(XPRT_SOCK_CONNECTING, &transport->sock_state);
@@ -1507,9 +1519,8 @@ static void xs_tcp_state_change(struct sock *sk)
                        xprt->stat.connect_count++;
                        xprt->stat.connect_time += (long)jiffies -
                                                   xprt->stat.connect_start;
-                       xprt_wake_pending_tasks(xprt, -EAGAIN);
+                       xs_run_error_worker(transport, XPRT_SOCK_WAKE_PENDING);
                }
-               spin_unlock(&xprt->transport_lock);
                break;
        case TCP_FIN_WAIT1:
                /* The client initiated a shutdown of the socket */
@@ -1525,7 +1536,7 @@ static void xs_tcp_state_change(struct sock *sk)
                /* The server initiated a shutdown of the socket */
                xprt->connect_cookie++;
                clear_bit(XPRT_CONNECTED, &xprt->state);
-               xs_tcp_force_close(xprt);
+               xs_run_error_worker(transport, XPRT_SOCK_WAKE_DISCONNECT);
                /* fall through */
        case TCP_CLOSING:
                /*
@@ -1547,7 +1558,7 @@ static void xs_tcp_state_change(struct sock *sk)
                        xprt_clear_connecting(xprt);
                clear_bit(XPRT_CLOSING, &xprt->state);
                /* Trigger the socket release */
-               xs_tcp_force_close(xprt);
+               xs_run_error_worker(transport, XPRT_SOCK_WAKE_DISCONNECT);
        }
  out:
        read_unlock_bh(&sk->sk_callback_lock);
@@ -1556,6 +1567,7 @@ static void xs_tcp_state_change(struct sock *sk)
 static void xs_write_space(struct sock *sk)
 {
        struct socket_wq *wq;
+       struct sock_xprt *transport;
        struct rpc_xprt *xprt;
 
        if (!sk->sk_socket)
@@ -1564,13 +1576,14 @@ static void xs_write_space(struct sock *sk)
 
        if (unlikely(!(xprt = xprt_from_sock(sk))))
                return;
+       transport = container_of(xprt, struct sock_xprt, xprt);
        rcu_read_lock();
        wq = rcu_dereference(sk->sk_wq);
        if (!wq || test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &wq->flags) == 0)
                goto out;
 
-       if (xprt_write_space(xprt))
-               sk->sk_write_pending--;
+       xs_run_error_worker(transport, XPRT_SOCK_WAKE_WRITE);
+       sk->sk_write_pending--;
 out:
        rcu_read_unlock();
 }
@@ -1664,9 +1677,9 @@ static void xs_udp_set_buffer_size(struct rpc_xprt *xprt, size_t sndsize, size_t
  */
 static void xs_udp_timer(struct rpc_xprt *xprt, struct rpc_task *task)
 {
-       spin_lock_bh(&xprt->transport_lock);
+       spin_lock(&xprt->transport_lock);
        xprt_adjust_cwnd(xprt, task, -ETIMEDOUT);
-       spin_unlock_bh(&xprt->transport_lock);
+       spin_unlock(&xprt->transport_lock);
 }
 
 static int xs_get_random_port(void)
@@ -2201,13 +2214,13 @@ static void xs_tcp_set_socket_timeouts(struct rpc_xprt *xprt,
        unsigned int opt_on = 1;
        unsigned int timeo;
 
-       spin_lock_bh(&xprt->transport_lock);
+       spin_lock(&xprt->transport_lock);
        keepidle = DIV_ROUND_UP(xprt->timeout->to_initval, HZ);
        keepcnt = xprt->timeout->to_retries + 1;
        timeo = jiffies_to_msecs(xprt->timeout->to_initval) *
                (xprt->timeout->to_retries + 1);
        clear_bit(XPRT_SOCK_UPD_TIMEOUT, &transport->sock_state);
-       spin_unlock_bh(&xprt->transport_lock);
+       spin_unlock(&xprt->transport_lock);
 
        /* TCP Keepalive options */
        kernel_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
@@ -2232,7 +2245,7 @@ static void xs_tcp_set_connect_timeout(struct rpc_xprt *xprt,
        struct rpc_timeout to;
        unsigned long initval;
 
-       spin_lock_bh(&xprt->transport_lock);
+       spin_lock(&xprt->transport_lock);
        if (reconnect_timeout < xprt->max_reconnect_timeout)
                xprt->max_reconnect_timeout = reconnect_timeout;
        if (connect_timeout < xprt->connect_timeout) {
@@ -2249,7 +2262,7 @@ static void xs_tcp_set_connect_timeout(struct rpc_xprt *xprt,
                xprt->connect_timeout = connect_timeout;
        }
        set_bit(XPRT_SOCK_UPD_TIMEOUT, &transport->sock_state);
-       spin_unlock_bh(&xprt->transport_lock);
+       spin_unlock(&xprt->transport_lock);
 }
 
 static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
@@ -2402,25 +2415,6 @@ out:
        xprt_wake_pending_tasks(xprt, status);
 }
 
-static unsigned long xs_reconnect_delay(const struct rpc_xprt *xprt)
-{
-       unsigned long start, now = jiffies;
-
-       start = xprt->stat.connect_start + xprt->reestablish_timeout;
-       if (time_after(start, now))
-               return start - now;
-       return 0;
-}
-
-static void xs_reconnect_backoff(struct rpc_xprt *xprt)
-{
-       xprt->reestablish_timeout <<= 1;
-       if (xprt->reestablish_timeout > xprt->max_reconnect_timeout)
-               xprt->reestablish_timeout = xprt->max_reconnect_timeout;
-       if (xprt->reestablish_timeout < XS_TCP_INIT_REEST_TO)
-               xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO;
-}
-
 /**
  * xs_connect - connect a socket to a remote endpoint
  * @xprt: pointer to transport structure
@@ -2450,8 +2444,8 @@ static void xs_connect(struct rpc_xprt *xprt, struct rpc_task *task)
                /* Start by resetting any existing state */
                xs_reset_transport(transport);
 
-               delay = xs_reconnect_delay(xprt);
-               xs_reconnect_backoff(xprt);
+               delay = xprt_reconnect_delay(xprt);
+               xprt_reconnect_backoff(xprt, XS_TCP_INIT_REEST_TO);
 
        } else
                dprintk("RPC:       xs_connect scheduled xprt %p\n", xprt);
@@ -2461,6 +2455,56 @@ static void xs_connect(struct rpc_xprt *xprt, struct rpc_task *task)
                        delay);
 }
 
+static void xs_wake_disconnect(struct sock_xprt *transport)
+{
+       if (test_and_clear_bit(XPRT_SOCK_WAKE_DISCONNECT, &transport->sock_state))
+               xs_tcp_force_close(&transport->xprt);
+}
+
+static void xs_wake_write(struct sock_xprt *transport)
+{
+       if (test_and_clear_bit(XPRT_SOCK_WAKE_WRITE, &transport->sock_state))
+               xprt_write_space(&transport->xprt);
+}
+
+static void xs_wake_error(struct sock_xprt *transport)
+{
+       int sockerr;
+       int sockerr_len = sizeof(sockerr);
+
+       if (!test_bit(XPRT_SOCK_WAKE_ERROR, &transport->sock_state))
+               return;
+       mutex_lock(&transport->recv_mutex);
+       if (transport->sock == NULL)
+               goto out;
+       if (!test_and_clear_bit(XPRT_SOCK_WAKE_ERROR, &transport->sock_state))
+               goto out;
+       if (kernel_getsockopt(transport->sock, SOL_SOCKET, SO_ERROR,
+                               (char *)&sockerr, &sockerr_len) != 0)
+               goto out;
+       if (sockerr < 0)
+               xprt_wake_pending_tasks(&transport->xprt, sockerr);
+out:
+       mutex_unlock(&transport->recv_mutex);
+}
+
+static void xs_wake_pending(struct sock_xprt *transport)
+{
+       if (test_and_clear_bit(XPRT_SOCK_WAKE_PENDING, &transport->sock_state))
+               xprt_wake_pending_tasks(&transport->xprt, -EAGAIN);
+}
+
+static void xs_error_handle(struct work_struct *work)
+{
+       struct sock_xprt *transport = container_of(work,
+                       struct sock_xprt, error_worker);
+
+       xs_wake_disconnect(transport);
+       xs_wake_write(transport);
+       xs_wake_error(transport);
+       xs_wake_pending(transport);
+}
+
 /**
  * xs_local_print_stats - display AF_LOCAL socket-specifc stats
  * @xprt: rpc_xprt struct containing statistics
@@ -2745,6 +2789,7 @@ static const struct rpc_xprt_ops xs_tcp_ops = {
 #ifdef CONFIG_SUNRPC_BACKCHANNEL
        .bc_setup               = xprt_setup_bc,
        .bc_maxpayload          = xs_tcp_bc_maxpayload,
+       .bc_num_slots           = xprt_bc_max_slots,
        .bc_free_rqst           = xprt_free_bc_rqst,
        .bc_destroy             = xprt_destroy_bc,
 #endif
@@ -2873,6 +2918,7 @@ static struct rpc_xprt *xs_setup_local(struct xprt_create *args)
        xprt->timeout = &xs_local_default_timeout;
 
        INIT_WORK(&transport->recv_worker, xs_stream_data_receive_workfn);
+       INIT_WORK(&transport->error_worker, xs_error_handle);
        INIT_DELAYED_WORK(&transport->connect_worker, xs_dummy_setup_socket);
 
        switch (sun->sun_family) {
@@ -2943,6 +2989,7 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args)
        xprt->timeout = &xs_udp_default_timeout;
 
        INIT_WORK(&transport->recv_worker, xs_udp_data_receive_workfn);
+       INIT_WORK(&transport->error_worker, xs_error_handle);
        INIT_DELAYED_WORK(&transport->connect_worker, xs_udp_setup_socket);
 
        switch (addr->sa_family) {
@@ -3024,6 +3071,7 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
                (xprt->timeout->to_retries + 1);
 
        INIT_WORK(&transport->recv_worker, xs_stream_data_receive_workfn);
+       INIT_WORK(&transport->error_worker, xs_error_handle);
        INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_setup_socket);
 
        switch (addr->sa_family) {
index 324a1f9..3a5be1d 100644 (file)
@@ -1807,6 +1807,7 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b)
        __skb_queue_head_init(&xmitq);
 
        /* Ensure message is well-formed before touching the header */
+       TIPC_SKB_CB(skb)->validated = false;
        if (unlikely(!tipc_msg_validate(&skb)))
                goto discard;
        hdr = buf_msg(skb);
index 9df82a5..6159d32 100644 (file)
@@ -38,8 +38,6 @@
 
 #include <linux/sysctl.h>
 
-static int zero;
-static int one = 1;
 static struct ctl_table_header *tipc_ctl_hdr;
 
 static struct ctl_table tipc_table[] = {
@@ -49,7 +47,7 @@ static struct ctl_table tipc_table[] = {
                .maxlen         = sizeof(sysctl_tipc_rmem),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = SYSCTL_ONE,
        },
        {
                .procname       = "named_timeout",
@@ -57,7 +55,7 @@ static struct ctl_table tipc_table[] = {
                .maxlen         = sizeof(sysctl_tipc_named_timeout),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
        },
        {
                .procname       = "sk_filter",
index f345662..ca8ac96 100644 (file)
@@ -476,7 +476,7 @@ static void tipc_topsrv_accept(struct work_struct *work)
        }
 }
 
-/* tipc_toprsv_listener_data_ready - interrupt callback with connection request
+/* tipc_topsrv_listener_data_ready - interrupt callback with connection request
  * The queued job is launched into tipc_topsrv_accept()
  */
 static void tipc_topsrv_listener_data_ready(struct sock *sk)
index 20c91f0..83de74c 100644 (file)
@@ -87,21 +87,20 @@ int xdp_umem_assign_dev(struct xdp_umem *umem, struct net_device *dev,
        struct netdev_bpf bpf;
        int err = 0;
 
+       ASSERT_RTNL();
+
        force_zc = flags & XDP_ZEROCOPY;
        force_copy = flags & XDP_COPY;
 
        if (force_zc && force_copy)
                return -EINVAL;
 
-       rtnl_lock();
-       if (xdp_get_umem_from_qid(dev, queue_id)) {
-               err = -EBUSY;
-               goto out_rtnl_unlock;
-       }
+       if (xdp_get_umem_from_qid(dev, queue_id))
+               return -EBUSY;
 
        err = xdp_reg_umem_at_qid(dev, umem, queue_id);
        if (err)
-               goto out_rtnl_unlock;
+               return err;
 
        umem->dev = dev;
        umem->queue_id = queue_id;
@@ -110,7 +109,7 @@ int xdp_umem_assign_dev(struct xdp_umem *umem, struct net_device *dev,
 
        if (force_copy)
                /* For copy-mode, we are done. */
-               goto out_rtnl_unlock;
+               return 0;
 
        if (!dev->netdev_ops->ndo_bpf ||
            !dev->netdev_ops->ndo_xsk_async_xmit) {
@@ -125,7 +124,6 @@ int xdp_umem_assign_dev(struct xdp_umem *umem, struct net_device *dev,
        err = dev->netdev_ops->ndo_bpf(dev, &bpf);
        if (err)
                goto err_unreg_umem;
-       rtnl_unlock();
 
        umem->zc = true;
        return 0;
@@ -135,8 +133,6 @@ err_unreg_umem:
                err = 0; /* fallback to copy mode */
        if (err)
                xdp_clear_umem_at_qid(dev, queue_id);
-out_rtnl_unlock:
-       rtnl_unlock();
        return err;
 }
 
index d4d6f10..59b57d7 100644 (file)
@@ -240,6 +240,9 @@ static int xsk_generic_xmit(struct sock *sk, struct msghdr *m,
 
        mutex_lock(&xs->mutex);
 
+       if (xs->queue_id >= xs->dev->real_num_tx_queues)
+               goto out;
+
        while (xskq_peek_desc(xs->tx, &desc)) {
                char *buffer;
                u64 addr;
@@ -250,12 +253,6 @@ static int xsk_generic_xmit(struct sock *sk, struct msghdr *m,
                        goto out;
                }
 
-               if (xskq_reserve_addr(xs->umem->cq))
-                       goto out;
-
-               if (xs->queue_id >= xs->dev->real_num_tx_queues)
-                       goto out;
-
                len = desc.len;
                skb = sock_alloc_send_skb(sk, len, 1, &err);
                if (unlikely(!skb)) {
@@ -267,7 +264,7 @@ static int xsk_generic_xmit(struct sock *sk, struct msghdr *m,
                addr = desc.addr;
                buffer = xdp_umem_get_data(xs->umem, addr);
                err = skb_store_bits(skb, 0, buffer, len);
-               if (unlikely(err)) {
+               if (unlikely(err) || xskq_reserve_addr(xs->umem->cq)) {
                        kfree_skb(skb);
                        goto out;
                }
@@ -433,6 +430,7 @@ static int xsk_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
        if (flags & ~(XDP_SHARED_UMEM | XDP_COPY | XDP_ZEROCOPY))
                return -EINVAL;
 
+       rtnl_lock();
        mutex_lock(&xs->mutex);
        if (xs->state != XSK_READY) {
                err = -EBUSY;
@@ -518,6 +516,7 @@ out_unlock:
                xs->state = XSK_BOUND;
 out_release:
        mutex_unlock(&xs->mutex);
+       rtnl_unlock();
        return err;
 }
 
index 71b5e83..c8dacb4 100644 (file)
@@ -99,7 +99,7 @@ config SAMPLE_CONNECTOR
          When enabled, this builds both a sample kernel module for
          the connector interface and a user space tool to communicate
          with it.
-         See also Documentation/connector/connector.txt
+         See also Documentation/driver-api/connector.rst
 
 config SAMPLE_HIDRAW
        bool "hidraw sample"
index f90daad..1d9be26 100644 (file)
@@ -284,7 +284,7 @@ $(obj)/%.o: $(src)/%.c
        $(Q)$(CLANG) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(EXTRA_CFLAGS) -I$(obj) \
                -I$(srctree)/tools/testing/selftests/bpf/ \
                -D__KERNEL__ -D__BPF_TRACING__ -Wno-unused-value -Wno-pointer-sign \
-               -D__TARGET_ARCH_$(ARCH) -Wno-compare-distinct-pointer-types \
+               -D__TARGET_ARCH_$(SRCARCH) -Wno-compare-distinct-pointer-types \
                -Wno-gnu-variable-sized-type-not-at-end \
                -Wno-address-of-packed-member -Wno-tautological-compare \
                -Wno-unknown-warning-option $(CLANG_ARCH_ARGS) \
index b038aa9..ac5c8c1 100644 (file)
@@ -1185,9 +1185,6 @@ static long mbochs_ioctl(struct mdev_device *mdev, unsigned int cmd,
 {
        int ret = 0;
        unsigned long minsz, outsz;
-       struct mdev_state *mdev_state;
-
-       mdev_state = mdev_get_drvdata(mdev);
 
        switch (cmd) {
        case VFIO_DEVICE_GET_INFO:
index ba7ef53..92e770a 100644 (file)
@@ -68,7 +68,7 @@
  * Global Structures
  */
 
-struct mtty_dev {
+static struct mtty_dev {
        dev_t           vd_devt;
        struct class    *vd_class;
        struct cdev     vd_cdev;
@@ -84,7 +84,7 @@ struct mdev_region_info {
 };
 
 #if defined(DEBUG_REGS)
-const char *wr_reg[] = {
+static const char *wr_reg[] = {
        "TX",
        "IER",
        "FCR",
@@ -95,7 +95,7 @@ const char *wr_reg[] = {
        "SCR"
 };
 
-const char *rd_reg[] = {
+static const char *rd_reg[] = {
        "RX",
        "IER",
        "IIR",
@@ -143,8 +143,8 @@ struct mdev_state {
        int nr_ports;
 };
 
-struct mutex mdev_list_lock;
-struct list_head mdev_devices_list;
+static struct mutex mdev_list_lock;
+static struct list_head mdev_devices_list;
 
 static const struct file_operations vd_fops = {
        .owner          = THIS_MODULE,
@@ -167,7 +167,7 @@ static struct mdev_state *find_mdev_state_by_uuid(const guid_t *uuid)
        return NULL;
 }
 
-void dump_buffer(u8 *buf, uint32_t count)
+static void dump_buffer(u8 *buf, uint32_t count)
 {
 #if defined(DEBUG)
        int i;
@@ -723,7 +723,7 @@ accessfailed:
        return ret;
 }
 
-int mtty_create(struct kobject *kobj, struct mdev_device *mdev)
+static int mtty_create(struct kobject *kobj, struct mdev_device *mdev)
 {
        struct mdev_state *mdev_state;
        char name[MTTY_STRING_LEN];
@@ -773,7 +773,7 @@ int mtty_create(struct kobject *kobj, struct mdev_device *mdev)
        return 0;
 }
 
-int mtty_remove(struct mdev_device *mdev)
+static int mtty_remove(struct mdev_device *mdev)
 {
        struct mdev_state *mds, *tmp_mds;
        struct mdev_state *mdev_state = mdev_get_drvdata(mdev);
@@ -795,7 +795,7 @@ int mtty_remove(struct mdev_device *mdev)
        return ret;
 }
 
-int mtty_reset(struct mdev_device *mdev)
+static int mtty_reset(struct mdev_device *mdev)
 {
        struct mdev_state *mdev_state;
 
@@ -811,8 +811,8 @@ int mtty_reset(struct mdev_device *mdev)
        return 0;
 }
 
-ssize_t mtty_read(struct mdev_device *mdev, char __user *buf, size_t count,
-                 loff_t *ppos)
+static ssize_t mtty_read(struct mdev_device *mdev, char __user *buf,
+                        size_t count, loff_t *ppos)
 {
        unsigned int done = 0;
        int ret;
@@ -870,7 +870,7 @@ read_err:
        return -EFAULT;
 }
 
-ssize_t mtty_write(struct mdev_device *mdev, const char __user *buf,
+static ssize_t mtty_write(struct mdev_device *mdev, const char __user *buf,
                   size_t count, loff_t *ppos)
 {
        unsigned int done = 0;
@@ -1063,7 +1063,7 @@ static int mtty_trigger_interrupt(const guid_t *uuid)
        return ret;
 }
 
-int mtty_get_region_info(struct mdev_device *mdev,
+static int mtty_get_region_info(struct mdev_device *mdev,
                         struct vfio_region_info *region_info,
                         u16 *cap_type_id, void **cap_type)
 {
@@ -1112,7 +1112,8 @@ int mtty_get_region_info(struct mdev_device *mdev,
        return 0;
 }
 
-int mtty_get_irq_info(struct mdev_device *mdev, struct vfio_irq_info *irq_info)
+static int mtty_get_irq_info(struct mdev_device *mdev,
+                            struct vfio_irq_info *irq_info)
 {
        switch (irq_info->index) {
        case VFIO_PCI_INTX_IRQ_INDEX:
@@ -1136,7 +1137,7 @@ int mtty_get_irq_info(struct mdev_device *mdev, struct vfio_irq_info *irq_info)
        return 0;
 }
 
-int mtty_get_device_info(struct mdev_device *mdev,
+static int mtty_get_device_info(struct mdev_device *mdev,
                         struct vfio_device_info *dev_info)
 {
        dev_info->flags = VFIO_DEVICE_FLAGS_PCI;
@@ -1268,13 +1269,13 @@ static long mtty_ioctl(struct mdev_device *mdev, unsigned int cmd,
        return -ENOTTY;
 }
 
-int mtty_open(struct mdev_device *mdev)
+static int mtty_open(struct mdev_device *mdev)
 {
        pr_info("%s\n", __func__);
        return 0;
 }
 
-void mtty_close(struct mdev_device *mdev)
+static void mtty_close(struct mdev_device *mdev)
 {
        pr_info("%s\n", __func__);
 }
@@ -1298,7 +1299,7 @@ static const struct attribute_group mtty_dev_group = {
        .attrs = mtty_dev_attrs,
 };
 
-const struct attribute_group *mtty_dev_groups[] = {
+static const struct attribute_group *mtty_dev_groups[] = {
        &mtty_dev_group,
        NULL,
 };
@@ -1325,7 +1326,7 @@ static const struct attribute_group mdev_dev_group = {
        .attrs = mdev_dev_attrs,
 };
 
-const struct attribute_group *mdev_dev_groups[] = {
+static const struct attribute_group *mdev_dev_groups[] = {
        &mdev_dev_group,
        NULL,
 };
@@ -1347,7 +1348,7 @@ name_show(struct kobject *kobj, struct device *dev, char *buf)
        return -EINVAL;
 }
 
-MDEV_TYPE_ATTR_RO(name);
+static MDEV_TYPE_ATTR_RO(name);
 
 static ssize_t
 available_instances_show(struct kobject *kobj, struct device *dev, char *buf)
@@ -1375,7 +1376,7 @@ available_instances_show(struct kobject *kobj, struct device *dev, char *buf)
        return sprintf(buf, "%d\n", (MAX_MTTYS - used)/ports);
 }
 
-MDEV_TYPE_ATTR_RO(available_instances);
+static MDEV_TYPE_ATTR_RO(available_instances);
 
 
 static ssize_t device_api_show(struct kobject *kobj, struct device *dev,
@@ -1384,7 +1385,7 @@ static ssize_t device_api_show(struct kobject *kobj, struct device *dev,
        return sprintf(buf, "%s\n", VFIO_DEVICE_API_PCI_STRING);
 }
 
-MDEV_TYPE_ATTR_RO(device_api);
+static MDEV_TYPE_ATTR_RO(device_api);
 
 static struct attribute *mdev_types_attrs[] = {
        &mdev_type_attr_name.attr,
@@ -1403,7 +1404,7 @@ static struct attribute_group mdev_type_group2 = {
        .attrs = mdev_types_attrs,
 };
 
-struct attribute_group *mdev_type_groups[] = {
+static struct attribute_group *mdev_type_groups[] = {
        &mdev_type_group1,
        &mdev_type_group2,
        NULL,
index 73e80b9..77c742f 100644 (file)
@@ -125,11 +125,6 @@ CC_OPTION_CFLAGS = $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS))
 cc-option = $(call __cc-option, $(CC),\
        $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS),$(1),$(2))
 
-# hostcc-option
-# Usage: cflags-y += $(call hostcc-option,-march=winchip-c6,-march=i586)
-hostcc-option = $(call __cc-option, $(HOSTCC),\
-       $(KBUILD_HOSTCFLAGS) $(HOST_EXTRACFLAGS),$(1),$(2))
-
 # cc-option-yn
 # Usage: flag := $(call cc-option-yn,-march=winchip-c6)
 cc-option-yn = $(call try-run,\
index be38198..0d434d0 100644 (file)
@@ -63,14 +63,14 @@ ifneq ($(strip $(real-obj-y) $(need-builtin)),)
 builtin-target := $(obj)/built-in.a
 endif
 
-ifdef CONFIG_MODULES
+ifeq ($(CONFIG_MODULES)$(need-modorder),y1)
 modorder-target := $(obj)/modules.order
 endif
 
-# We keep a list of all modules in $(MODVERDIR)
+mod-targets := $(patsubst %.o, %.mod, $(obj-m))
 
 __build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
-        $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
+        $(if $(KBUILD_MODULES),$(obj-m) $(mod-targets) $(modorder-target)) \
         $(subdir-ym) $(always)
        @:
 
@@ -87,11 +87,6 @@ ifneq ($(KBUILD_ENABLE_EXTRA_GCC_CHECKS),)
   cmd_checkdoc = $(srctree)/scripts/kernel-doc -none $<
 endif
 
-# Do section mismatch analysis for each module/built-in.a
-ifdef CONFIG_DEBUG_SECTION_MISMATCH
-  cmd_secanalysis = ; scripts/mod/modpost $@
-endif
-
 # Compile C sources (.c)
 # ---------------------------------------------------------------------------
 
@@ -268,7 +263,7 @@ endef
 
 # List module undefined symbols (or empty line if not enabled)
 ifdef CONFIG_TRIM_UNUSED_KSYMS
-cmd_undef_syms = $(NM) $@ | sed -n 's/^  *U //p' | xargs echo
+cmd_undef_syms = $(NM) $< | sed -n 's/^  *U //p' | xargs echo
 else
 cmd_undef_syms = echo
 endif
@@ -278,13 +273,15 @@ $(obj)/%.o: $(src)/%.c $(recordmcount_source) $(objtool_dep) FORCE
        $(call cmd,force_checksrc)
        $(call if_changed_rule,cc_o_c)
 
-# Single-part modules are special since we need to mark them in $(MODVERDIR)
+cmd_mod = { \
+       echo $(if $($*-objs)$($*-y)$($*-m), $(addprefix $(obj)/, $($*-objs) $($*-y) $($*-m)), $(@:.mod=.o)); \
+       $(cmd_undef_syms); \
+       } > $@
 
-$(single-used-m): $(obj)/%.o: $(src)/%.c $(recordmcount_source) $(objtool_dep) FORCE
-       $(call cmd,force_checksrc)
-       $(call if_changed_rule,cc_o_c)
-       @{ echo $(@:.o=.ko); echo $@; \
-          $(cmd_undef_syms); } > $(MODVERDIR)/$(@F:.o=.mod)
+$(obj)/%.mod: $(obj)/%.o FORCE
+       $(call if_changed,mod)
+
+targets += $(mod-targets)
 
 quiet_cmd_cc_lst_c = MKLST   $@
       cmd_cc_lst_c = $(CC) $(c_flags) -g -c -o $*.o $< && \
@@ -294,7 +291,7 @@ quiet_cmd_cc_lst_c = MKLST   $@
 $(obj)/%.lst: $(src)/%.c FORCE
        $(call if_changed_dep,cc_lst_c)
 
-# header test (header-test-y target)
+# header test (header-test-y, header-test-m target)
 # ---------------------------------------------------------------------------
 
 quiet_cmd_cc_s_h = CC      $@
@@ -423,13 +420,10 @@ endif # builtin-target
 #
 # Create commands to either record .ko file or cat modules.order from
 # a subdirectory
-modorder-cmds =                                                \
-       $(foreach m, $(modorder),                       \
-               $(if $(filter %/modules.order, $m),     \
-                       cat $m;, echo kernel/$m;))
-
 $(modorder-target): $(subdir-ym) FORCE
-       $(Q)(cat /dev/null; $(modorder-cmds)) > $@
+       $(Q){ $(foreach m, $(modorder), \
+       $(if $(filter %/modules.order, $m), cat $m, echo $m);) :; } \
+       | $(AWK) '!x[$$0]++' - > $@
 
 #
 # Rule to compile a set of .o files into one .a file (with symbol table)
@@ -464,12 +458,10 @@ endif
 # module is turned into a multi object module, $^ will contain header file
 # dependencies recorded in the .*.cmd file.
 quiet_cmd_link_multi-m = LD [M]  $@
-cmd_link_multi-m = $(LD) $(ld_flags) -r -o $@ $(filter %.o,$^) $(cmd_secanalysis)
+      cmd_link_multi-m = $(LD) $(ld_flags) -r -o $@ $(filter %.o,$^)
 
 $(multi-used-m): FORCE
        $(call if_changed,link_multi-m)
-       @{ echo $(@:.o=.ko); echo $(filter %.o,$^); \
-          $(cmd_undef_syms); } > $(MODVERDIR)/$(@F:.o=.mod)
 $(call multi_depend, $(multi-used-m), .o, -objs -y -m)
 
 targets += $(multi-used-m)
index 6cb3aa5..5241d07 100644 (file)
@@ -78,7 +78,7 @@ header-test-y += $(filter-out $(header-test-), \
                $(wildcard $(addprefix $(srctree)/$(src)/, \
                $(header-test-pattern-y)))))
 
-extra-$(CONFIG_HEADER_TEST) += $(addsuffix .s, $(header-test-y))
+extra-$(CONFIG_HEADER_TEST) += $(addsuffix .s, $(header-test-y) $(header-test-m))
 
 # Add subdir path
 
index 50a9990..7d4711b 100644 (file)
@@ -40,7 +40,7 @@ __modbuiltin: $(modbuiltin-target) $(subdir-ym)
        @:
 
 $(modbuiltin-target): $(subdir-ym) FORCE
-       $(Q)(for m in $(modbuiltin-mods); do echo kernel/$$m; done;     \
+       $(Q)(for m in $(modbuiltin-mods); do echo $$m; done;    \
        cat /dev/null $(modbuiltin-subdirs)) > $@
 
 PHONY += FORCE
index 0dae402..5a4579e 100644 (file)
@@ -8,10 +8,7 @@ __modinst:
 
 include scripts/Kbuild.include
 
-#
-
-__modules := $(sort $(shell grep -h '\.ko$$' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
-modules := $(patsubst %.o,%.ko,$(wildcard $(__modules:.ko=.o)))
+modules := $(sort $(shell cat $(if $(KBUILD_EXTMOD),$(KBUILD_EXTMOD)/)modules.order))
 
 PHONY += $(modules)
 __modinst: $(modules)
index fec6ec2..6b19c1a 100644 (file)
@@ -6,11 +6,12 @@
 # Stage one of module building created the following:
 # a) The individual .o files used for the module
 # b) A <module>.o file which is the .o files above linked together
-# c) A <module>.mod file in $(MODVERDIR)/, listing the name of the
-#    the preliminary <module>.o file, plus all .o files
+# c) A <module>.mod file, listing the name of the preliminary <module>.o file,
+#    plus all .o files
+# d) modules.order, which lists all the modules
 
 # Stage 2 is handled by this file and does the following
-# 1) Find all modules from the files listed in $(MODVERDIR)/
+# 1) Find all modules listed in modules.order
 # 2) modpost is then used to
 # 3)  create one <module>.mod.c file pr. module
 # 4)  create one Module.symvers file with CRC for all exported symbols
@@ -60,10 +61,12 @@ include scripts/Makefile.lib
 kernelsymfile := $(objtree)/Module.symvers
 modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers
 
-# Step 1), find all modules listed in $(MODVERDIR)/
-MODLISTCMD := find $(MODVERDIR) -name '*.mod' | xargs -r grep -h '\.ko$$' | sort -u
-__modules := $(shell $(MODLISTCMD))
-modules   := $(patsubst %.o,%.ko, $(wildcard $(__modules:.ko=.o)))
+modorder := $(if $(KBUILD_EXTMOD),$(KBUILD_EXTMOD)/)modules.order
+
+# Step 1), find all modules listed in modules.order
+ifdef CONFIG_MODULES
+modules := $(sort $(shell cat $(modorder)))
+endif
 
 # Stop after building .o files if NOFINAL is set. Makes compile tests quicker
 _modpost: $(if $(KBUILD_MODPOST_NOFINAL), $(modules:.ko:.o),$(modules))
@@ -84,7 +87,7 @@ MODPOST_OPT=$(subst -i,-n,$(filter -i,$(MAKEFLAGS)))
 
 # We can go over command line length here, so be careful.
 quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules
-      cmd_modpost = $(MODLISTCMD) | sed 's/\.ko$$/.o/' | $(modpost) $(MODPOST_OPT) -s -T -
+      cmd_modpost = sed 's/ko$$/o/' $(modorder) | $(modpost) $(MODPOST_OPT) -s -T -
 
 PHONY += __modpost
 __modpost: $(modules:.ko=.o) FORCE
index da56aa7..d7325ce 100644 (file)
@@ -8,8 +8,7 @@ __modsign:
 
 include scripts/Kbuild.include
 
-__modules := $(sort $(shell grep -h '\.ko$$' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
-modules := $(patsubst %.o,%.ko,$(wildcard $(__modules:.ko=.o)))
+modules := $(sort $(shell cat modules.order))
 
 PHONY += $(modules)
 __modsign: $(modules)
index aab4e29..a904bf1 100755 (executable)
@@ -8,8 +8,7 @@
 #
 
 # Create/update the include/generated/autoksyms.h file from the list
-# of all module's needed symbols as recorded on the third line of
-# .tmp_versions/*.mod files.
+# of all module's needed symbols as recorded on the second line of *.mod files.
 #
 # For each symbol being added or removed, the corresponding dependency
 # file's timestamp is updated to force a rebuild of the affected source
@@ -47,13 +46,10 @@ cat > "$new_ksyms_file" << EOT
  */
 
 EOT
-[ "$(ls -A "$MODVERDIR")" ] &&
-for mod in "$MODVERDIR"/*.mod; do
-       sed -n -e '3{s/ /\n/g;/^$/!p;}' "$mod"
-done | sort -u |
-while read sym; do
-       echo "#define __KSYM_${sym} 1"
-done >> "$new_ksyms_file"
+sed 's/ko$/mod/' modules.order |
+xargs -n1 sed -n -e '2{s/ /\n/g;/^$/!p;}' -- |
+sort -u |
+sed -e 's/\(.*\)/#define __KSYM_\1 1/' >> "$new_ksyms_file"
 
 # Special case for modversions (see modpost.c)
 if [ -n "$CONFIG_MODVERSIONS" ]; then
index a6d4368..93a7edf 100755 (executable)
@@ -6639,6 +6639,12 @@ sub process {
                                     "unknown module license " . $extracted_string . "\n" . $herecurr);
                        }
                }
+
+# check for sysctl duplicate constants
+               if ($line =~ /\.extra[12]\s*=\s*&(zero|one|int_max)\b/) {
+                       WARN("DUPLICATED_SYSCTL_CONST",
+                               "duplicated sysctl range checking value '$1', consider using the shared one in include/linux/sysctl.h\n" . $herecurr);
+               }
        }
 
        # If we have no input at all, then there is nothing to report on
diff --git a/scripts/coccinelle/api/devm_platform_ioremap_resource.cocci b/scripts/coccinelle/api/devm_platform_ioremap_resource.cocci
new file mode 100644 (file)
index 0000000..56a2e26
--- /dev/null
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+/// Use devm_platform_ioremap_resource helper which wraps
+/// platform_get_resource() and devm_ioremap_resource() together.
+///
+// Confidence: High
+// Copyright: (C) 2019 Himanshu Jha GPLv2.
+// Copyright: (C) 2019 Julia Lawall, Inria/LIP6. GPLv2.
+// Keywords: platform_get_resource, devm_ioremap_resource,
+// Keywords: devm_platform_ioremap_resource
+
+virtual patch
+virtual report
+
+@r depends on patch && !report@
+expression e1, e2, arg1, arg2, arg3;
+identifier id;
+@@
+
+(
+- id = platform_get_resource(arg1, IORESOURCE_MEM, arg2);
+|
+- struct resource *id = platform_get_resource(arg1, IORESOURCE_MEM, arg2);
+)
+  ... when != id
+- e1 = devm_ioremap_resource(arg3, id);
++ e1 = devm_platform_ioremap_resource(arg1, arg2);
+  ... when != id
+? id = e2
+
+@r1 depends on patch && !report@
+identifier r.id;
+type T;
+@@
+
+- T *id;
+  ...when != id
+
+@r2 depends on report && !patch@
+identifier id;
+expression e1, e2, arg1, arg2, arg3;
+position j0;
+@@
+
+(
+  id = platform_get_resource(arg1, IORESOURCE_MEM, arg2);
+|
+  struct resource *id = platform_get_resource(arg1, IORESOURCE_MEM, arg2);
+)
+  ... when != id
+  e1@j0 = devm_ioremap_resource(arg3, id);
+  ... when != id
+? id = e2
+
+@script:python depends on report && !patch@
+e1 << r2.e1;
+j0 << r2.j0;
+@@
+
+msg = "WARNING: Use devm_platform_ioremap_resource for %s" % (e1)
+coccilib.report.print_report(j0[0], msg)
index fefd033..441799b 100644 (file)
@@ -3,7 +3,7 @@
 /// functions.  Values allocated using the devm_functions are freed when
 /// the device is detached, and thus the use of the standard freeing
 /// function would cause a double free.
-/// See Documentation/driver-model/devres.rst for more information.
+/// See Documentation/driver-api/driver-model/devres.rst for more information.
 ///
 /// A difficulty of detecting this problem is that the standard freeing
 /// function might be called from a different function than the one
index 0f604f6..7d3030d 100755 (executable)
@@ -52,13 +52,12 @@ sub usage {
 
 sub collectcfiles {
     my @file;
-    while (<.tmp_versions/*.mod>) {
-       open my $fh, '<', $_ or die "cannot open $_: $!\n";
-       push (@file,
-             grep s/\.ko/.mod.c/,      # change the suffix
-             grep m/.+\.ko/,           # find the .ko path
-             <$fh>);                   # lines in opened file
+    open my $fh, '< modules.order' or die "cannot open modules.order: $!\n";
+    while (<$fh>) {
+       s/\.ko$/.mod.c/;
+       push (@file, $_)
     }
+    close($fh);
     chomp @file;
     return @file;
 }
index e9c677a..d33de0b 100644 (file)
@@ -23,7 +23,7 @@ config GCC_PLUGINS
          GCC plugins are loadable modules that provide extra features to the
          compiler. They are useful for runtime instrumentation and static analysis.
 
-         See Documentation/gcc-plugins.txt for details.
+         See Documentation/core-api/gcc-plugins.rst for details.
 
 menu "GCC plugins"
        depends on GCC_PLUGINS
diff --git a/scripts/gdb/linux/device.py b/scripts/gdb/linux/device.py
new file mode 100644 (file)
index 0000000..16376c5
--- /dev/null
@@ -0,0 +1,182 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (c) NXP 2019
+
+import gdb
+
+from linux.utils import CachedType
+from linux.utils import container_of
+from linux.lists import list_for_each_entry
+
+
+device_private_type = CachedType('struct device_private')
+device_type = CachedType('struct device')
+
+subsys_private_type = CachedType('struct subsys_private')
+kobject_type = CachedType('struct kobject')
+kset_type = CachedType('struct kset')
+
+bus_type = CachedType('struct bus_type')
+class_type = CachedType('struct class')
+
+
+def dev_name(dev):
+    dev_init_name = dev['init_name']
+    if dev_init_name:
+        return dev_init_name.string()
+    return dev['kobj']['name'].string()
+
+
+def kset_for_each_object(kset):
+    return list_for_each_entry(kset['list'],
+            kobject_type.get_type().pointer(), "entry")
+
+
+def for_each_bus():
+    for kobj in kset_for_each_object(gdb.parse_and_eval('bus_kset')):
+        subsys = container_of(kobj, kset_type.get_type().pointer(), 'kobj')
+        subsys_priv = container_of(subsys, subsys_private_type.get_type().pointer(), 'subsys')
+        yield subsys_priv['bus']
+
+
+def for_each_class():
+    for kobj in kset_for_each_object(gdb.parse_and_eval('class_kset')):
+        subsys = container_of(kobj, kset_type.get_type().pointer(), 'kobj')
+        subsys_priv = container_of(subsys, subsys_private_type.get_type().pointer(), 'subsys')
+        yield subsys_priv['class']
+
+
+def get_bus_by_name(name):
+    for item in for_each_bus():
+        if item['name'].string() == name:
+            return item
+    raise gdb.GdbError("Can't find bus type {!r}".format(name))
+
+
+def get_class_by_name(name):
+    for item in for_each_class():
+        if item['name'].string() == name:
+            return item
+    raise gdb.GdbError("Can't find device class {!r}".format(name))
+
+
+klist_type = CachedType('struct klist')
+klist_node_type = CachedType('struct klist_node')
+
+
+def klist_for_each(klist):
+    return list_for_each_entry(klist['k_list'],
+                klist_node_type.get_type().pointer(), 'n_node')
+
+
+def bus_for_each_device(bus):
+    for kn in klist_for_each(bus['p']['klist_devices']):
+        dp = container_of(kn, device_private_type.get_type().pointer(), 'knode_bus')
+        yield dp['device']
+
+
+def class_for_each_device(cls):
+    for kn in klist_for_each(cls['p']['klist_devices']):
+        dp = container_of(kn, device_private_type.get_type().pointer(), 'knode_class')
+        yield dp['device']
+
+
+def device_for_each_child(dev):
+    for kn in klist_for_each(dev['p']['klist_children']):
+        dp = container_of(kn, device_private_type.get_type().pointer(), 'knode_parent')
+        yield dp['device']
+
+
+def _show_device(dev, level=0, recursive=False):
+    gdb.write('{}dev {}:\t{}\n'.format('\t' * level, dev_name(dev), dev))
+    if recursive:
+        for child in device_for_each_child(dev):
+            _show_device(child, level + 1, recursive)
+
+
+class LxDeviceListBus(gdb.Command):
+    '''Print devices on a bus (or all buses if not specified)'''
+
+    def __init__(self):
+        super(LxDeviceListBus, self).__init__('lx-device-list-bus', gdb.COMMAND_DATA)
+
+    def invoke(self, arg, from_tty):
+        if not arg:
+            for bus in for_each_bus():
+                gdb.write('bus {}:\t{}\n'.format(bus['name'].string(), bus))
+                for dev in bus_for_each_device(bus):
+                    _show_device(dev, level=1)
+        else:
+            bus = get_bus_by_name(arg)
+            if not bus:
+                raise gdb.GdbError("Can't find bus {!r}".format(arg))
+            for dev in bus_for_each_device(bus):
+                _show_device(dev)
+
+
+class LxDeviceListClass(gdb.Command):
+    '''Print devices in a class (or all classes if not specified)'''
+
+    def __init__(self):
+        super(LxDeviceListClass, self).__init__('lx-device-list-class', gdb.COMMAND_DATA)
+
+    def invoke(self, arg, from_tty):
+        if not arg:
+            for cls in for_each_class():
+                gdb.write("class {}:\t{}\n".format(cls['name'].string(), cls))
+                for dev in class_for_each_device(cls):
+                    _show_device(dev, level=1)
+        else:
+            cls = get_class_by_name(arg)
+            for dev in class_for_each_device(cls):
+                _show_device(dev)
+
+
+class LxDeviceListTree(gdb.Command):
+    '''Print a device and its children recursively'''
+
+    def __init__(self):
+        super(LxDeviceListTree, self).__init__('lx-device-list-tree', gdb.COMMAND_DATA)
+
+    def invoke(self, arg, from_tty):
+        if not arg:
+            raise gdb.GdbError('Please provide pointer to struct device')
+        dev = gdb.parse_and_eval(arg)
+        if dev.type != device_type.get_type().pointer():
+            raise gdb.GdbError('Please provide pointer to struct device')
+        _show_device(dev, level=0, recursive=True)
+
+
+class LxDeviceFindByBusName(gdb.Function):
+    '''Find struct device by bus and name (both strings)'''
+
+    def __init__(self):
+        super(LxDeviceFindByBusName, self).__init__('lx_device_find_by_bus_name')
+
+    def invoke(self, bus, name):
+        name = name.string()
+        bus = get_bus_by_name(bus.string())
+        for dev in bus_for_each_device(bus):
+            if dev_name(dev) == name:
+                return dev
+
+
+class LxDeviceFindByClassName(gdb.Function):
+    '''Find struct device by class and name (both strings)'''
+
+    def __init__(self):
+        super(LxDeviceFindByClassName, self).__init__('lx_device_find_by_class_name')
+
+    def invoke(self, cls, name):
+        name = name.string()
+        cls = get_class_by_name(cls.string())
+        for dev in class_for_each_device(cls):
+            if dev_name(dev) == name:
+                return dev
+
+
+LxDeviceListBus()
+LxDeviceListClass()
+LxDeviceListTree()
+LxDeviceFindByBusName()
+LxDeviceFindByClassName()
diff --git a/scripts/gdb/linux/genpd.py b/scripts/gdb/linux/genpd.py
new file mode 100644 (file)
index 0000000..6ca93bd
--- /dev/null
@@ -0,0 +1,83 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (c) NXP 2019
+
+import gdb
+import sys
+
+from linux.utils import CachedType
+from linux.lists import list_for_each_entry
+
+generic_pm_domain_type = CachedType('struct generic_pm_domain')
+pm_domain_data_type = CachedType('struct pm_domain_data')
+device_link_type = CachedType('struct device_link')
+
+
+def kobject_get_path(kobj):
+    path = kobj['name'].string()
+    parent = kobj['parent']
+    if parent:
+        path = kobject_get_path(parent) + '/' + path
+    return path
+
+
+def rtpm_status_str(dev):
+    if dev['power']['runtime_error']:
+        return 'error'
+    if dev['power']['disable_depth']:
+        return 'unsupported'
+    _RPM_STATUS_LOOKUP = [
+        "active",
+        "resuming",
+        "suspended",
+        "suspending"
+    ]
+    return _RPM_STATUS_LOOKUP[dev['power']['runtime_status']]
+
+
+class LxGenPDSummary(gdb.Command):
+    '''Print genpd summary
+
+Output is similar to /sys/kernel/debug/pm_genpd/pm_genpd_summary'''
+
+    def __init__(self):
+        super(LxGenPDSummary, self).__init__('lx-genpd-summary', gdb.COMMAND_DATA)
+
+    def summary_one(self, genpd):
+        if genpd['status'] == 0:
+            status_string = 'on'
+        else:
+            status_string = 'off-{}'.format(genpd['state_idx'])
+
+        slave_names = []
+        for link in list_for_each_entry(
+                genpd['master_links'],
+                device_link_type.get_type().pointer(),
+                'master_node'):
+            slave_names.apend(link['slave']['name'])
+
+        gdb.write('%-30s  %-15s %s\n' % (
+                genpd['name'].string(),
+                status_string,
+                ', '.join(slave_names)))
+
+        # Print devices in domain
+        for pm_data in list_for_each_entry(genpd['dev_list'],
+                        pm_domain_data_type.get_type().pointer(),
+                        'list_node'):
+            dev = pm_data['dev']
+            kobj_path = kobject_get_path(dev['kobj'])
+            gdb.write('    %-50s  %s\n' % (kobj_path, rtpm_status_str(dev)))
+
+    def invoke(self, arg, from_tty):
+        gdb.write('domain                          status          slaves\n');
+        gdb.write('    /device                                             runtime status\n');
+        gdb.write('----------------------------------------------------------------------\n');
+        for genpd in list_for_each_entry(
+                gdb.parse_and_eval('&gpd_list'),
+                generic_pm_domain_type.get_type().pointer(),
+                'gpd_list_node'):
+            self.summary_one(genpd)
+
+
+LxGenPDSummary()
index eff5a48..4136dc2 100644 (file)
@@ -35,3 +35,5 @@ else:
     import linux.constants
     import linux.timerlist
     import linux.clk
+    import linux.genpd
+    import linux.device
index c1c088e..5ef5921 100755 (executable)
@@ -27,6 +27,7 @@ my $email_usename = 1;
 my $email_maintainer = 1;
 my $email_reviewer = 1;
 my $email_list = 1;
+my $email_moderated_list = 1;
 my $email_subscriber_list = 0;
 my $email_git_penguin_chiefs = 0;
 my $email_git = 0;
@@ -248,6 +249,7 @@ if (!GetOptions(
                'r!' => \$email_reviewer,
                'n!' => \$email_usename,
                'l!' => \$email_list,
+               'moderated!' => \$email_moderated_list,
                's!' => \$email_subscriber_list,
                'multiline!' => \$output_multiline,
                'roles!' => \$output_roles,
@@ -1023,7 +1025,8 @@ MAINTAINER field selection options:
     --r => include reviewer(s) if any
     --n => include name 'Full Name <addr\@domain.tld>'
     --l => include list(s) if any
-    --s => include subscriber only list(s) if any
+    --moderated => include moderated lists(s) if any (default: true)
+    --s => include subscriber only list(s) if any (default: false)
     --remove-duplicates => minimize duplicate email names/addresses
     --roles => show roles (status:subsystem, git-signer, list, etc...)
     --rolestats => show roles and statistics (commits/total_commits, %)
@@ -1313,11 +1316,14 @@ sub add_categories {
                } else {
                    if ($email_list) {
                        if (!$hash_list_to{lc($list_address)}) {
-                           $hash_list_to{lc($list_address)} = 1;
                            if ($list_additional =~ m/moderated/) {
-                               push(@list_to, [$list_address,
-                                               "moderated list${list_role}"]);
+                               if ($email_moderated_list) {
+                                   $hash_list_to{lc($list_address)} = 1;
+                                   push(@list_to, [$list_address,
+                                                   "moderated list${list_role}"]);
+                               }
                            } else {
+                               $hash_list_to{lc($list_address)} = 1;
                                push(@list_to, [$list_address,
                                                "open list${list_role}"]);
                            }
index ab30fe7..7656e11 100644 (file)
@@ -94,7 +94,7 @@ configfiles=$(wildcard $(srctree)/kernel/configs/$@ $(srctree)/arch/$(SRCARCH)/c
 %.config: $(obj)/conf
        $(if $(call configfiles),, $(error No configuration exists for this target on this architecture))
        $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh -m .config $(configfiles)
-       +$(Q)yes "" | $(MAKE) -f $(srctree)/Makefile oldconfig
+       $(Q)$(MAKE) -f $(srctree)/Makefile olddefconfig
 
 PHONY += kvmconfig
 kvmconfig: kvm_guest.config
index 501fdcc..1134892 100644 (file)
@@ -895,7 +895,8 @@ int conf_write(const char *name)
                                     "# %s\n"
                                     "#\n", str);
                        need_newline = false;
-               } else if (!(sym->flags & SYMBOL_CHOICE)) {
+               } else if (!(sym->flags & SYMBOL_CHOICE) &&
+                          !(sym->flags & SYMBOL_WRITTEN)) {
                        sym_calc_value(sym);
                        if (!(sym->flags & SYMBOL_WRITE))
                                goto next;
@@ -903,7 +904,7 @@ int conf_write(const char *name)
                                fprintf(out, "\n");
                                need_newline = false;
                        }
-                       sym->flags &= ~SYMBOL_WRITE;
+                       sym->flags |= SYMBOL_WRITTEN;
                        conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
                }
 
@@ -1063,8 +1064,6 @@ int conf_write_autoconf(int overwrite)
        if (!overwrite && is_present(autoconf_name))
                return 0;
 
-       sym_clear_all_valid();
-
        conf_write_dep("include/config/auto.conf.cmd");
 
        if (conf_touch_deps())
index 8dde65b..017843c 100644 (file)
@@ -141,6 +141,7 @@ struct symbol {
 #define SYMBOL_OPTIONAL   0x0100  /* choice is optional - values can be 'n' */
 #define SYMBOL_WRITE      0x0200  /* write symbol to file (KCONFIG_CONFIG) */
 #define SYMBOL_CHANGED    0x0400  /* ? */
+#define SYMBOL_WRITTEN    0x0800  /* track info to avoid double-write to .config */
 #define SYMBOL_NO_WRITE   0x1000  /* Symbol for internal use only; it will not be written */
 #define SYMBOL_CHECKED    0x2000  /* used during dependency checking */
 #define SYMBOL_WARNED     0x8000  /* warning has been issued */
index 0f6dcb4..6306202 100644 (file)
@@ -396,34 +396,19 @@ void get_src_version(const char *modname, char sum[], unsigned sumlen)
        unsigned long len;
        struct md4_ctx md;
        char *sources, *end, *fname;
-       const char *basename;
        char filelist[PATH_MAX + 1];
-       char *modverdir = getenv("MODVERDIR");
 
-       if (!modverdir)
-               modverdir = ".";
-
-       /* Source files for module are in .tmp_versions/modname.mod,
-          after the first line. */
-       if (strrchr(modname, '/'))
-               basename = strrchr(modname, '/') + 1;
-       else
-               basename = modname;
-       snprintf(filelist, sizeof(filelist), "%s/%.*s.mod", modverdir,
-               (int) strlen(basename) - 2, basename);
+       /* objects for a module are listed in the first line of *.mod file. */
+       snprintf(filelist, sizeof(filelist), "%.*smod",
+                (int)strlen(modname) - 1, modname);
 
        file = grab_file(filelist, &len);
        if (!file)
                /* not a module or .mod file missing - ignore */
                return;
 
-       sources = strchr(file, '\n');
-       if (!sources) {
-               warn("malformed versions file for %s\n", modname);
-               goto release;
-       }
+       sources = file;
 
-       sources++;
        end = strchr(sources, '\n');
        if (!end) {
                warn("bad ending versions file for %s\n", modname);
index 39e8cb3..f51f446 100755 (executable)
@@ -9,7 +9,7 @@ check_same_name_modules()
        for m in $(sed 's:.*/::' modules.order | sort | uniq -d)
        do
                echo "warning: same module names found:" >&2
-               sed -n "/\/$m/s:^kernel/:  :p" modules.order >&2
+               sed -n "/\/$m/s:^:  :p" modules.order >&2
        done
 }
 
index e8ca6dc..c4c580f 100755 (executable)
@@ -132,6 +132,11 @@ fi
 if [ "$ARCH" != "um" ]; then
        $MAKE -f $srctree/Makefile headers
        $MAKE -f $srctree/Makefile headers_install INSTALL_HDR_PATH="$libc_headers_dir/usr"
+       # move asm headers to /usr/include/<libc-machine>/asm to match the structure
+       # used by Debian-based distros (to support multi-arch)
+       host_arch=$(dpkg-architecture -a$(cat debian/arch) -qDEB_HOST_MULTIARCH)
+       mkdir $libc_headers_dir/usr/include/$host_arch
+       mv $libc_headers_dir/usr/include/asm $libc_headers_dir/usr/include/$host_arch/
 fi
 
 # Install the maintainer scripts
index 8351584..e0750b7 100755 (executable)
@@ -197,6 +197,7 @@ Architecture: $debarch
 Description: Linux support headers for userspace development
  This package provides userspaces headers from the Linux kernel.  These headers
  are used by the installed headers for GNU glibc and other system libraries.
+Multi-Arch: same
 
 Package: $dbg_packagename
 Section: debug
index 2d29df4..8640c27 100755 (executable)
@@ -29,7 +29,7 @@ fi
 
 PROVIDES="$PROVIDES kernel-$KERNELRELEASE"
 __KERNELRELEASE=$(echo $KERNELRELEASE | sed -e "s/-/_/g")
-EXCLUDES="$RCS_TAR_IGNORE --exclude=.tmp_versions --exclude=*vmlinux* \
+EXCLUDES="$RCS_TAR_IGNORE --exclude=*vmlinux* --exclude=*.mod \
 --exclude=*.o --exclude=*.ko --exclude=*.cmd --exclude=Documentation \
 --exclude=.config.old --exclude=.missing-syscalls.d --exclude=*.s"
 
index 06a3085..0d65594 100644 (file)
@@ -121,7 +121,7 @@ config INTEL_TXT
          See <http://www.intel.com/technology/security/> for more information
          about Intel(R) TXT.
          See <http://tboot.sourceforge.net> for more information about tboot.
-         See Documentation/intel_txt.txt for a description of how to enable
+         See Documentation/x86/intel_txt.rst for a description of how to enable
          Intel TXT support in a kernel boot.
 
          If you are unsure as to whether this is required, answer N.
index 66d0b42..45d13b6 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/capability.h>
 #include <linux/rcupdate.h>
 #include <linux/fs.h>
+#include <linux/fs_context.h>
 #include <linux/poll.h>
 #include <uapi/linux/major.h>
 #include <uapi/linux/magic.h>
@@ -132,7 +133,7 @@ static const struct super_operations aafs_super_ops = {
        .show_path = aafs_show_path,
 };
 
-static int fill_super(struct super_block *sb, void *data, int silent)
+static int apparmorfs_fill_super(struct super_block *sb, struct fs_context *fc)
 {
        static struct tree_descr files[] = { {""} };
        int error;
@@ -145,16 +146,25 @@ static int fill_super(struct super_block *sb, void *data, int silent)
        return 0;
 }
 
-static struct dentry *aafs_mount(struct file_system_type *fs_type,
-                                int flags, const char *dev_name, void *data)
+static int apparmorfs_get_tree(struct fs_context *fc)
 {
-       return mount_single(fs_type, flags, data, fill_super);
+       return get_tree_single(fc, apparmorfs_fill_super);
+}
+
+static const struct fs_context_operations apparmorfs_context_ops = {
+       .get_tree       = apparmorfs_get_tree,
+};
+
+static int apparmorfs_init_fs_context(struct fs_context *fc)
+{
+       fc->ops = &apparmorfs_context_ops;
+       return 0;
 }
 
 static struct file_system_type aafs_ops = {
        .owner = THIS_MODULE,
        .name = AAFS_NAME,
-       .mount = aafs_mount,
+       .init_fs_context = apparmorfs_init_fs_context,
        .kill_sb = kill_anon_super,
 };
 
index c071965..725674f 100644 (file)
@@ -509,7 +509,7 @@ static inline int may_allow_all(struct dev_cgroup *parent)
  * This is one of the three key functions for hierarchy implementation.
  * This function is responsible for re-evaluating all the cgroup's active
  * exceptions due to a parent's exception change.
- * Refer to Documentation/cgroup-v1/devices.rst for more details.
+ * Refer to Documentation/admin-guide/cgroup-v1/devices.rst for more details.
  */
 static void revalidate_active_exceptions(struct dev_cgroup *devcg)
 {
index fcff7f0..6c32693 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/sysfs.h>
 #include <linux/kobject.h>
 #include <linux/fs.h>
+#include <linux/fs_context.h>
 #include <linux/mount.h>
 #include <linux/pagemap.h>
 #include <linux/init.h>
@@ -36,7 +37,7 @@ static const struct super_operations securityfs_super_operations = {
        .free_inode     = securityfs_free_inode,
 };
 
-static int fill_super(struct super_block *sb, void *data, int silent)
+static int securityfs_fill_super(struct super_block *sb, struct fs_context *fc)
 {
        static const struct tree_descr files[] = {{""}};
        int error;
@@ -50,17 +51,25 @@ static int fill_super(struct super_block *sb, void *data, int silent)
        return 0;
 }
 
-static struct dentry *get_sb(struct file_system_type *fs_type,
-                 int flags, const char *dev_name,
-                 void *data)
+static int securityfs_get_tree(struct fs_context *fc)
 {
-       return mount_single(fs_type, flags, data, fill_super);
+       return get_tree_single(fc, securityfs_fill_super);
+}
+
+static const struct fs_context_operations securityfs_context_ops = {
+       .get_tree       = securityfs_get_tree,
+};
+
+static int securityfs_init_fs_context(struct fs_context *fc)
+{
+       fc->ops = &securityfs_context_ops;
+       return 0;
 }
 
 static struct file_system_type fs_type = {
        .owner =        THIS_MODULE,
        .name =         "securityfs",
-       .mount =        get_sb,
+       .init_fs_context = securityfs_init_fs_context,
        .kill_sb =      kill_litter_super,
 };
 
index dd1e21f..b46b651 100644 (file)
@@ -9,8 +9,6 @@
 #include <linux/sysctl.h>
 #include "internal.h"
 
-static const int zero, one = 1, max = INT_MAX;
-
 struct ctl_table key_sysctls[] = {
        {
                .procname = "maxkeys",
@@ -18,8 +16,8 @@ struct ctl_table key_sysctls[] = {
                .maxlen = sizeof(unsigned),
                .mode = 0644,
                .proc_handler = proc_dointvec_minmax,
-               .extra1 = (void *) &one,
-               .extra2 = (void *) &max,
+               .extra1 = (void *) SYSCTL_ONE,
+               .extra2 = (void *) SYSCTL_INT_MAX,
        },
        {
                .procname = "maxbytes",
@@ -27,8 +25,8 @@ struct ctl_table key_sysctls[] = {
                .maxlen = sizeof(unsigned),
                .mode = 0644,
                .proc_handler = proc_dointvec_minmax,
-               .extra1 = (void *) &one,
-               .extra2 = (void *) &max,
+               .extra1 = (void *) SYSCTL_ONE,
+               .extra2 = (void *) SYSCTL_INT_MAX,
        },
        {
                .procname = "root_maxkeys",
@@ -36,8 +34,8 @@ struct ctl_table key_sysctls[] = {
                .maxlen = sizeof(unsigned),
                .mode = 0644,
                .proc_handler = proc_dointvec_minmax,
-               .extra1 = (void *) &one,
-               .extra2 = (void *) &max,
+               .extra1 = (void *) SYSCTL_ONE,
+               .extra2 = (void *) SYSCTL_INT_MAX,
        },
        {
                .procname = "root_maxbytes",
@@ -45,8 +43,8 @@ struct ctl_table key_sysctls[] = {
                .maxlen = sizeof(unsigned),
                .mode = 0644,
                .proc_handler = proc_dointvec_minmax,
-               .extra1 = (void *) &one,
-               .extra2 = (void *) &max,
+               .extra1 = (void *) SYSCTL_ONE,
+               .extra2 = (void *) SYSCTL_INT_MAX,
        },
        {
                .procname = "gc_delay",
@@ -54,8 +52,8 @@ struct ctl_table key_sysctls[] = {
                .maxlen = sizeof(unsigned),
                .mode = 0644,
                .proc_handler = proc_dointvec_minmax,
-               .extra1 = (void *) &zero,
-               .extra2 = (void *) &max,
+               .extra1 = (void *) SYSCTL_ZERO,
+               .extra2 = (void *) SYSCTL_INT_MAX,
        },
 #ifdef CONFIG_PERSISTENT_KEYRINGS
        {
@@ -64,8 +62,8 @@ struct ctl_table key_sysctls[] = {
                .maxlen = sizeof(unsigned),
                .mode = 0644,
                .proc_handler = proc_dointvec_minmax,
-               .extra1 = (void *) &zero,
-               .extra2 = (void *) &max,
+               .extra1 = (void *) SYSCTL_ZERO,
+               .extra2 = (void *) SYSCTL_INT_MAX,
        },
 #endif
        { }
index 81519c8..ee5cb94 100644 (file)
@@ -43,8 +43,6 @@ static struct super_block *pinned_root;
 static DEFINE_SPINLOCK(pinned_root_spinlock);
 
 #ifdef CONFIG_SYSCTL
-static int zero;
-static int one = 1;
 
 static struct ctl_path loadpin_sysctl_path[] = {
        { .procname = "kernel", },
@@ -59,8 +57,8 @@ static struct ctl_table loadpin_sysctl_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
-               .extra2         = &one,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        { }
 };
index 06d4259..7760019 100644 (file)
 
 #define pr_fmt(fmt) "SafeSetID: " fmt
 
-#include <linux/hashtable.h>
 #include <linux/lsm_hooks.h>
 #include <linux/module.h>
 #include <linux/ptrace.h>
 #include <linux/sched/task_stack.h>
 #include <linux/security.h>
+#include "lsm.h"
 
 /* Flag indicating whether initialization completed */
 int safesetid_initialized;
 
-#define NUM_BITS 8 /* 128 buckets in hash table */
+struct setuid_ruleset __rcu *safesetid_setuid_rules;
 
-static DEFINE_HASHTABLE(safesetid_whitelist_hashtable, NUM_BITS);
-
-/*
- * Hash table entry to store safesetid policy signifying that 'parent' user
- * can setid to 'child' user.
- */
-struct entry {
-       struct hlist_node next;
-       struct hlist_node dlist; /* for deletion cleanup */
-       uint64_t parent_kuid;
-       uint64_t child_kuid;
-};
-
-static DEFINE_SPINLOCK(safesetid_whitelist_hashtable_spinlock);
-
-static bool check_setuid_policy_hashtable_key(kuid_t parent)
+/* Compute a decision for a transition from @src to @dst under @policy. */
+enum sid_policy_type _setuid_policy_lookup(struct setuid_ruleset *policy,
+               kuid_t src, kuid_t dst)
 {
-       struct entry *entry;
-
-       rcu_read_lock();
-       hash_for_each_possible_rcu(safesetid_whitelist_hashtable,
-                                  entry, next, __kuid_val(parent)) {
-               if (entry->parent_kuid == __kuid_val(parent)) {
-                       rcu_read_unlock();
-                       return true;
-               }
+       struct setuid_rule *rule;
+       enum sid_policy_type result = SIDPOL_DEFAULT;
+
+       hash_for_each_possible(policy->rules, rule, next, __kuid_val(src)) {
+               if (!uid_eq(rule->src_uid, src))
+                       continue;
+               if (uid_eq(rule->dst_uid, dst))
+                       return SIDPOL_ALLOWED;
+               result = SIDPOL_CONSTRAINED;
        }
-       rcu_read_unlock();
-
-       return false;
+       return result;
 }
 
-static bool check_setuid_policy_hashtable_key_value(kuid_t parent,
-                                                   kuid_t child)
+/*
+ * Compute a decision for a transition from @src to @dst under the active
+ * policy.
+ */
+static enum sid_policy_type setuid_policy_lookup(kuid_t src, kuid_t dst)
 {
-       struct entry *entry;
+       enum sid_policy_type result = SIDPOL_DEFAULT;
+       struct setuid_ruleset *pol;
 
        rcu_read_lock();
-       hash_for_each_possible_rcu(safesetid_whitelist_hashtable,
-                                  entry, next, __kuid_val(parent)) {
-               if (entry->parent_kuid == __kuid_val(parent) &&
-                   entry->child_kuid == __kuid_val(child)) {
-                       rcu_read_unlock();
-                       return true;
-               }
-       }
+       pol = rcu_dereference(safesetid_setuid_rules);
+       if (pol)
+               result = _setuid_policy_lookup(pol, src, dst);
        rcu_read_unlock();
-
-       return false;
+       return result;
 }
 
 static int safesetid_security_capable(const struct cred *cred,
@@ -82,37 +65,59 @@ static int safesetid_security_capable(const struct cred *cred,
                                      int cap,
                                      unsigned int opts)
 {
-       if (cap == CAP_SETUID &&
-           check_setuid_policy_hashtable_key(cred->uid)) {
-               if (!(opts & CAP_OPT_INSETID)) {
-                       /*
-                        * Deny if we're not in a set*uid() syscall to avoid
-                        * giving powers gated by CAP_SETUID that are related
-                        * to functionality other than calling set*uid() (e.g.
-                        * allowing user to set up userns uid mappings).
-                        */
-                       pr_warn("Operation requires CAP_SETUID, which is not available to UID %u for operations besides approved set*uid transitions",
-                               __kuid_val(cred->uid));
-                       return -1;
-               }
-       }
-       return 0;
+       /* We're only interested in CAP_SETUID. */
+       if (cap != CAP_SETUID)
+               return 0;
+
+       /*
+        * If CAP_SETUID is currently used for a set*uid() syscall, we want to
+        * let it go through here; the real security check happens later, in the
+        * task_fix_setuid hook.
+        */
+       if ((opts & CAP_OPT_INSETID) != 0)
+               return 0;
+
+       /*
+        * If no policy applies to this task, allow the use of CAP_SETUID for
+        * other purposes.
+        */
+       if (setuid_policy_lookup(cred->uid, INVALID_UID) == SIDPOL_DEFAULT)
+               return 0;
+
+       /*
+        * Reject use of CAP_SETUID for functionality other than calling
+        * set*uid() (e.g. setting up userns uid mappings).
+        */
+       pr_warn("Operation requires CAP_SETUID, which is not available to UID %u for operations besides approved set*uid transitions\n",
+               __kuid_val(cred->uid));
+       return -EPERM;
 }
 
-static int check_uid_transition(kuid_t parent, kuid_t child)
+/*
+ * Check whether a caller with old credentials @old is allowed to switch to
+ * credentials that contain @new_uid.
+ */
+static bool uid_permitted_for_cred(const struct cred *old, kuid_t new_uid)
 {
-       if (check_setuid_policy_hashtable_key_value(parent, child))
-               return 0;
-       pr_warn("UID transition (%d -> %d) blocked",
-               __kuid_val(parent),
-               __kuid_val(child));
+       bool permitted;
+
+       /* If our old creds already had this UID in it, it's fine. */
+       if (uid_eq(new_uid, old->uid) || uid_eq(new_uid, old->euid) ||
+           uid_eq(new_uid, old->suid))
+               return true;
+
        /*
-        * Kill this process to avoid potential security vulnerabilities
-        * that could arise from a missing whitelist entry preventing a
-        * privileged process from dropping to a lesser-privileged one.
+        * Transitions to new UIDs require a check against the policy of the old
+        * RUID.
         */
-       force_sig(SIGKILL);
-       return -EACCES;
+       permitted =
+           setuid_policy_lookup(old->uid, new_uid) != SIDPOL_CONSTRAINED;
+       if (!permitted) {
+               pr_warn("UID transition ((%d,%d,%d) -> %d) blocked\n",
+                       __kuid_val(old->uid), __kuid_val(old->euid),
+                       __kuid_val(old->suid), __kuid_val(new_uid));
+       }
+       return permitted;
 }
 
 /*
@@ -125,134 +130,23 @@ static int safesetid_task_fix_setuid(struct cred *new,
                                     int flags)
 {
 
-       /* Do nothing if there are no setuid restrictions for this UID. */
-       if (!check_setuid_policy_hashtable_key(old->uid))
+       /* Do nothing if there are no setuid restrictions for our old RUID. */
+       if (setuid_policy_lookup(old->uid, INVALID_UID) == SIDPOL_DEFAULT)
                return 0;
 
-       switch (flags) {
-       case LSM_SETID_RE:
-               /*
-                * Users for which setuid restrictions exist can only set the
-                * real UID to the real UID or the effective UID, unless an
-                * explicit whitelist policy allows the transition.
-                */
-               if (!uid_eq(old->uid, new->uid) &&
-                       !uid_eq(old->euid, new->uid)) {
-                       return check_uid_transition(old->uid, new->uid);
-               }
-               /*
-                * Users for which setuid restrictions exist can only set the
-                * effective UID to the real UID, the effective UID, or the
-                * saved set-UID, unless an explicit whitelist policy allows
-                * the transition.
-                */
-               if (!uid_eq(old->uid, new->euid) &&
-                       !uid_eq(old->euid, new->euid) &&
-                       !uid_eq(old->suid, new->euid)) {
-                       return check_uid_transition(old->euid, new->euid);
-               }
-               break;
-       case LSM_SETID_ID:
-               /*
-                * Users for which setuid restrictions exist cannot change the
-                * real UID or saved set-UID unless an explicit whitelist
-                * policy allows the transition.
-                */
-               if (!uid_eq(old->uid, new->uid))
-                       return check_uid_transition(old->uid, new->uid);
-               if (!uid_eq(old->suid, new->suid))
-                       return check_uid_transition(old->suid, new->suid);
-               break;
-       case LSM_SETID_RES:
-               /*
-                * Users for which setuid restrictions exist cannot change the
-                * real UID, effective UID, or saved set-UID to anything but
-                * one of: the current real UID, the current effective UID or
-                * the current saved set-user-ID unless an explicit whitelist
-                * policy allows the transition.
-                */
-               if (!uid_eq(new->uid, old->uid) &&
-                       !uid_eq(new->uid, old->euid) &&
-                       !uid_eq(new->uid, old->suid)) {
-                       return check_uid_transition(old->uid, new->uid);
-               }
-               if (!uid_eq(new->euid, old->uid) &&
-                       !uid_eq(new->euid, old->euid) &&
-                       !uid_eq(new->euid, old->suid)) {
-                       return check_uid_transition(old->euid, new->euid);
-               }
-               if (!uid_eq(new->suid, old->uid) &&
-                       !uid_eq(new->suid, old->euid) &&
-                       !uid_eq(new->suid, old->suid)) {
-                       return check_uid_transition(old->suid, new->suid);
-               }
-               break;
-       case LSM_SETID_FS:
-               /*
-                * Users for which setuid restrictions exist cannot change the
-                * filesystem UID to anything but one of: the current real UID,
-                * the current effective UID or the current saved set-UID
-                * unless an explicit whitelist policy allows the transition.
-                */
-               if (!uid_eq(new->fsuid, old->uid)  &&
-                       !uid_eq(new->fsuid, old->euid)  &&
-                       !uid_eq(new->fsuid, old->suid) &&
-                       !uid_eq(new->fsuid, old->fsuid)) {
-                       return check_uid_transition(old->fsuid, new->fsuid);
-               }
-               break;
-       default:
-               pr_warn("Unknown setid state %d\n", flags);
-               force_sig(SIGKILL);
-               return -EINVAL;
-       }
-       return 0;
-}
-
-int add_safesetid_whitelist_entry(kuid_t parent, kuid_t child)
-{
-       struct entry *new;
-
-       /* Return if entry already exists */
-       if (check_setuid_policy_hashtable_key_value(parent, child))
+       if (uid_permitted_for_cred(old, new->uid) &&
+           uid_permitted_for_cred(old, new->euid) &&
+           uid_permitted_for_cred(old, new->suid) &&
+           uid_permitted_for_cred(old, new->fsuid))
                return 0;
 
-       new = kzalloc(sizeof(struct entry), GFP_KERNEL);
-       if (!new)
-               return -ENOMEM;
-       new->parent_kuid = __kuid_val(parent);
-       new->child_kuid = __kuid_val(child);
-       spin_lock(&safesetid_whitelist_hashtable_spinlock);
-       hash_add_rcu(safesetid_whitelist_hashtable,
-                    &new->next,
-                    __kuid_val(parent));
-       spin_unlock(&safesetid_whitelist_hashtable_spinlock);
-       return 0;
-}
-
-void flush_safesetid_whitelist_entries(void)
-{
-       struct entry *entry;
-       struct hlist_node *hlist_node;
-       unsigned int bkt_loop_cursor;
-       HLIST_HEAD(free_list);
-
        /*
-        * Could probably use hash_for_each_rcu here instead, but this should
-        * be fine as well.
+        * Kill this process to avoid potential security vulnerabilities
+        * that could arise from a missing whitelist entry preventing a
+        * privileged process from dropping to a lesser-privileged one.
         */
-       spin_lock(&safesetid_whitelist_hashtable_spinlock);
-       hash_for_each_safe(safesetid_whitelist_hashtable, bkt_loop_cursor,
-                          hlist_node, entry, next) {
-               hash_del_rcu(&entry->next);
-               hlist_add_head(&entry->dlist, &free_list);
-       }
-       spin_unlock(&safesetid_whitelist_hashtable_spinlock);
-       synchronize_rcu();
-       hlist_for_each_entry_safe(entry, hlist_node, &free_list, dlist) {
-               hlist_del(&entry->dlist);
-               kfree(entry);
-       }
+       force_sig(SIGKILL);
+       return -EACCES;
 }
 
 static struct security_hook_list safesetid_security_hooks[] = {
index c1ea3c2..db6d16e 100644 (file)
 #define _SAFESETID_H
 
 #include <linux/types.h>
+#include <linux/uidgid.h>
+#include <linux/hashtable.h>
 
 /* Flag indicating whether initialization completed */
 extern int safesetid_initialized;
 
-/* Function type. */
-enum safesetid_whitelist_file_write_type {
-       SAFESETID_WHITELIST_ADD, /* Add whitelist policy. */
-       SAFESETID_WHITELIST_FLUSH, /* Flush whitelist policies. */
+enum sid_policy_type {
+       SIDPOL_DEFAULT, /* source ID is unaffected by policy */
+       SIDPOL_CONSTRAINED, /* source ID is affected by policy */
+       SIDPOL_ALLOWED /* target ID explicitly allowed */
 };
 
-/* Add entry to safesetid whitelist to allow 'parent' to setid to 'child'. */
-int add_safesetid_whitelist_entry(kuid_t parent, kuid_t child);
+/*
+ * Hash table entry to store safesetid policy signifying that 'src_uid'
+ * can setuid to 'dst_uid'.
+ */
+struct setuid_rule {
+       struct hlist_node next;
+       kuid_t src_uid;
+       kuid_t dst_uid;
+};
+
+#define SETID_HASH_BITS 8 /* 256 buckets in hash table */
+
+struct setuid_ruleset {
+       DECLARE_HASHTABLE(rules, SETID_HASH_BITS);
+       char *policy_str;
+       struct rcu_head rcu;
+};
+
+enum sid_policy_type _setuid_policy_lookup(struct setuid_ruleset *policy,
+               kuid_t src, kuid_t dst);
 
-void flush_safesetid_whitelist_entries(void);
+extern struct setuid_ruleset __rcu *safesetid_setuid_rules;
 
 #endif /* _SAFESETID_H */
index 2c6c829..d568e17 100644 (file)
  * published by the Free Software Foundation.
  *
  */
+
+#define pr_fmt(fmt) "SafeSetID: " fmt
+
 #include <linux/security.h>
 #include <linux/cred.h>
 
 #include "lsm.h"
 
-static struct dentry *safesetid_policy_dir;
-
-struct safesetid_file_entry {
-       const char *name;
-       enum safesetid_whitelist_file_write_type type;
-       struct dentry *dentry;
-};
-
-static struct safesetid_file_entry safesetid_files[] = {
-       {.name = "add_whitelist_policy",
-        .type = SAFESETID_WHITELIST_ADD},
-       {.name = "flush_whitelist_policies",
-        .type = SAFESETID_WHITELIST_FLUSH},
-};
+static DEFINE_MUTEX(policy_update_lock);
 
 /*
  * In the case the input buffer contains one or more invalid UIDs, the kuid_t
- * variables pointed to by 'parent' and 'child' will get updated but this
+ * variables pointed to by @parent and @child will get updated but this
  * function will return an error.
+ * Contents of @buf may be modified.
  */
-static int parse_safesetid_whitelist_policy(const char __user *buf,
-                                           size_t len,
-                                           kuid_t *parent,
-                                           kuid_t *child)
+static int parse_policy_line(struct file *file, char *buf,
+       struct setuid_rule *rule)
 {
-       char *kern_buf;
-       char *parent_buf;
-       char *child_buf;
-       const char separator[] = ":";
+       char *child_str;
        int ret;
-       size_t first_substring_length;
-       long parsed_parent;
-       long parsed_child;
+       u32 parsed_parent, parsed_child;
 
-       /* Duplicate string from user memory and NULL-terminate */
-       kern_buf = memdup_user_nul(buf, len);
-       if (IS_ERR(kern_buf))
-               return PTR_ERR(kern_buf);
+       /* Format of |buf| string should be <UID>:<UID>. */
+       child_str = strchr(buf, ':');
+       if (child_str == NULL)
+               return -EINVAL;
+       *child_str = '\0';
+       child_str++;
 
-       /*
-        * Format of |buf| string should be <UID>:<UID>.
-        * Find location of ":" in kern_buf (copied from |buf|).
-        */
-       first_substring_length = strcspn(kern_buf, separator);
-       if (first_substring_length == 0 || first_substring_length == len) {
-               ret = -EINVAL;
-               goto free_kern;
-       }
+       ret = kstrtou32(buf, 0, &parsed_parent);
+       if (ret)
+               return ret;
+
+       ret = kstrtou32(child_str, 0, &parsed_child);
+       if (ret)
+               return ret;
 
-       parent_buf = kmemdup_nul(kern_buf, first_substring_length, GFP_KERNEL);
-       if (!parent_buf) {
-               ret = -ENOMEM;
-               goto free_kern;
+       rule->src_uid = make_kuid(file->f_cred->user_ns, parsed_parent);
+       rule->dst_uid = make_kuid(file->f_cred->user_ns, parsed_child);
+       if (!uid_valid(rule->src_uid) || !uid_valid(rule->dst_uid))
+               return -EINVAL;
+
+       return 0;
+}
+
+static void __release_ruleset(struct rcu_head *rcu)
+{
+       struct setuid_ruleset *pol =
+               container_of(rcu, struct setuid_ruleset, rcu);
+       int bucket;
+       struct setuid_rule *rule;
+       struct hlist_node *tmp;
+
+       hash_for_each_safe(pol->rules, bucket, tmp, rule, next)
+               kfree(rule);
+       kfree(pol->policy_str);
+       kfree(pol);
+}
+
+static void release_ruleset(struct setuid_ruleset *pol)
+{
+       call_rcu(&pol->rcu, __release_ruleset);
+}
+
+static void insert_rule(struct setuid_ruleset *pol, struct setuid_rule *rule)
+{
+       hash_add(pol->rules, &rule->next, __kuid_val(rule->src_uid));
+}
+
+static int verify_ruleset(struct setuid_ruleset *pol)
+{
+       int bucket;
+       struct setuid_rule *rule, *nrule;
+       int res = 0;
+
+       hash_for_each(pol->rules, bucket, rule, next) {
+               if (_setuid_policy_lookup(pol, rule->dst_uid, INVALID_UID) ==
+                   SIDPOL_DEFAULT) {
+                       pr_warn("insecure policy detected: uid %d is constrained but transitively unconstrained through uid %d\n",
+                               __kuid_val(rule->src_uid),
+                               __kuid_val(rule->dst_uid));
+                       res = -EINVAL;
+
+                       /* fix it up */
+                       nrule = kmalloc(sizeof(struct setuid_rule), GFP_KERNEL);
+                       if (!nrule)
+                               return -ENOMEM;
+                       nrule->src_uid = rule->dst_uid;
+                       nrule->dst_uid = rule->dst_uid;
+                       insert_rule(pol, nrule);
+               }
        }
+       return res;
+}
 
-       ret = kstrtol(parent_buf, 0, &parsed_parent);
-       if (ret)
-               goto free_both;
+static ssize_t handle_policy_update(struct file *file,
+                                   const char __user *ubuf, size_t len)
+{
+       struct setuid_ruleset *pol;
+       char *buf, *p, *end;
+       int err;
 
-       child_buf = kern_buf + first_substring_length + 1;
-       ret = kstrtol(child_buf, 0, &parsed_child);
-       if (ret)
-               goto free_both;
+       pol = kmalloc(sizeof(struct setuid_ruleset), GFP_KERNEL);
+       if (!pol)
+               return -ENOMEM;
+       pol->policy_str = NULL;
+       hash_init(pol->rules);
 
-       *parent = make_kuid(current_user_ns(), parsed_parent);
-       if (!uid_valid(*parent)) {
-               ret = -EINVAL;
-               goto free_both;
+       p = buf = memdup_user_nul(ubuf, len);
+       if (IS_ERR(buf)) {
+               err = PTR_ERR(buf);
+               goto out_free_pol;
        }
+       pol->policy_str = kstrdup(buf, GFP_KERNEL);
+       if (pol->policy_str == NULL) {
+               err = -ENOMEM;
+               goto out_free_buf;
+       }
+
+       /* policy lines, including the last one, end with \n */
+       while (*p != '\0') {
+               struct setuid_rule *rule;
+
+               end = strchr(p, '\n');
+               if (end == NULL) {
+                       err = -EINVAL;
+                       goto out_free_buf;
+               }
+               *end = '\0';
+
+               rule = kmalloc(sizeof(struct setuid_rule), GFP_KERNEL);
+               if (!rule) {
+                       err = -ENOMEM;
+                       goto out_free_buf;
+               }
 
-       *child = make_kuid(current_user_ns(), parsed_child);
-       if (!uid_valid(*child)) {
-               ret = -EINVAL;
-               goto free_both;
+               err = parse_policy_line(file, p, rule);
+               if (err)
+                       goto out_free_rule;
+
+               if (_setuid_policy_lookup(pol, rule->src_uid, rule->dst_uid) ==
+                   SIDPOL_ALLOWED) {
+                       pr_warn("bad policy: duplicate entry\n");
+                       err = -EEXIST;
+                       goto out_free_rule;
+               }
+
+               insert_rule(pol, rule);
+               p = end + 1;
+               continue;
+
+out_free_rule:
+               kfree(rule);
+               goto out_free_buf;
        }
 
-free_both:
-       kfree(parent_buf);
-free_kern:
-       kfree(kern_buf);
-       return ret;
+       err = verify_ruleset(pol);
+       /* bogus policy falls through after fixing it up */
+       if (err && err != -EINVAL)
+               goto out_free_buf;
+
+       /*
+        * Everything looks good, apply the policy and release the old one.
+        * What we really want here is an xchg() wrapper for RCU, but since that
+        * doesn't currently exist, just use a spinlock for now.
+        */
+       mutex_lock(&policy_update_lock);
+       rcu_swap_protected(safesetid_setuid_rules, pol,
+                          lockdep_is_held(&policy_update_lock));
+       mutex_unlock(&policy_update_lock);
+       err = len;
+
+out_free_buf:
+       kfree(buf);
+out_free_pol:
+       release_ruleset(pol);
+       return err;
 }
 
 static ssize_t safesetid_file_write(struct file *file,
@@ -104,90 +196,65 @@ static ssize_t safesetid_file_write(struct file *file,
                                    size_t len,
                                    loff_t *ppos)
 {
-       struct safesetid_file_entry *file_entry =
-               file->f_inode->i_private;
-       kuid_t parent;
-       kuid_t child;
-       int ret;
-
-       if (!ns_capable(current_user_ns(), CAP_MAC_ADMIN))
+       if (!file_ns_capable(file, &init_user_ns, CAP_MAC_ADMIN))
                return -EPERM;
 
        if (*ppos != 0)
                return -EINVAL;
 
-       switch (file_entry->type) {
-       case SAFESETID_WHITELIST_FLUSH:
-               flush_safesetid_whitelist_entries();
-               break;
-       case SAFESETID_WHITELIST_ADD:
-               ret = parse_safesetid_whitelist_policy(buf, len, &parent,
-                                                                &child);
-               if (ret)
-                       return ret;
-
-               ret = add_safesetid_whitelist_entry(parent, child);
-               if (ret)
-                       return ret;
-               break;
-       default:
-               pr_warn("Unknown securityfs file %d\n", file_entry->type);
-               break;
-       }
-
-       /* Return len on success so caller won't keep trying to write */
-       return len;
+       return handle_policy_update(file, buf, len);
 }
 
-static const struct file_operations safesetid_file_fops = {
-       .write = safesetid_file_write,
-};
-
-static void safesetid_shutdown_securityfs(void)
+static ssize_t safesetid_file_read(struct file *file, char __user *buf,
+                                  size_t len, loff_t *ppos)
 {
-       int i;
+       ssize_t res = 0;
+       struct setuid_ruleset *pol;
+       const char *kbuf;
 
-       for (i = 0; i < ARRAY_SIZE(safesetid_files); ++i) {
-               struct safesetid_file_entry *entry =
-                       &safesetid_files[i];
-               securityfs_remove(entry->dentry);
-               entry->dentry = NULL;
+       mutex_lock(&policy_update_lock);
+       pol = rcu_dereference_protected(safesetid_setuid_rules,
+                                       lockdep_is_held(&policy_update_lock));
+       if (pol) {
+               kbuf = pol->policy_str;
+               res = simple_read_from_buffer(buf, len, ppos,
+                                             kbuf, strlen(kbuf));
        }
-
-       securityfs_remove(safesetid_policy_dir);
-       safesetid_policy_dir = NULL;
+       mutex_unlock(&policy_update_lock);
+       return res;
 }
 
+static const struct file_operations safesetid_file_fops = {
+       .read = safesetid_file_read,
+       .write = safesetid_file_write,
+};
+
 static int __init safesetid_init_securityfs(void)
 {
-       int i;
        int ret;
+       struct dentry *policy_dir;
+       struct dentry *policy_file;
 
        if (!safesetid_initialized)
                return 0;
 
-       safesetid_policy_dir = securityfs_create_dir("safesetid", NULL);
-       if (IS_ERR(safesetid_policy_dir)) {
-               ret = PTR_ERR(safesetid_policy_dir);
+       policy_dir = securityfs_create_dir("safesetid", NULL);
+       if (IS_ERR(policy_dir)) {
+               ret = PTR_ERR(policy_dir);
                goto error;
        }
 
-       for (i = 0; i < ARRAY_SIZE(safesetid_files); ++i) {
-               struct safesetid_file_entry *entry =
-                       &safesetid_files[i];
-               entry->dentry = securityfs_create_file(
-                       entry->name, 0200, safesetid_policy_dir,
-                       entry, &safesetid_file_fops);
-               if (IS_ERR(entry->dentry)) {
-                       ret = PTR_ERR(entry->dentry);
-                       goto error;
-               }
+       policy_file = securityfs_create_file("whitelist_policy", 0600,
+                       policy_dir, NULL, &safesetid_file_fops);
+       if (IS_ERR(policy_file)) {
+               ret = PTR_ERR(policy_file);
+               goto error;
        }
 
        return 0;
 
 error:
-       safesetid_shutdown_securityfs();
+       securityfs_remove(policy_dir);
        return ret;
 }
 fs_initcall(safesetid_init_securityfs);
index 6f195c7..e6c7643 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
+#include <linux/fs_context.h>
 #include <linux/mount.h>
 #include <linux/mutex.h>
 #include <linux/init.h>
@@ -1891,7 +1892,7 @@ static struct dentry *sel_make_dir(struct dentry *dir, const char *name,
 
 #define NULL_FILE_NAME "null"
 
-static int sel_fill_super(struct super_block *sb, void *data, int silent)
+static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
 {
        struct selinux_fs_info *fsi;
        int ret;
@@ -2007,10 +2008,19 @@ err:
        return ret;
 }
 
-static struct dentry *sel_mount(struct file_system_type *fs_type,
-                     int flags, const char *dev_name, void *data)
+static int sel_get_tree(struct fs_context *fc)
 {
-       return mount_single(fs_type, flags, data, sel_fill_super);
+       return get_tree_single(fc, sel_fill_super);
+}
+
+static const struct fs_context_operations sel_context_ops = {
+       .get_tree       = sel_get_tree,
+};
+
+static int sel_init_fs_context(struct fs_context *fc)
+{
+       fc->ops = &sel_context_ops;
+       return 0;
 }
 
 static void sel_kill_sb(struct super_block *sb)
@@ -2021,7 +2031,7 @@ static void sel_kill_sb(struct super_block *sb)
 
 static struct file_system_type sel_fs_type = {
        .name           = "selinuxfs",
-       .mount          = sel_mount,
+       .init_fs_context = sel_init_fs_context,
        .kill_sb        = sel_kill_sb,
 };
 
index ef0d871..e3e05c0 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/ctype.h>
 #include <linux/audit.h>
 #include <linux/magic.h>
+#include <linux/fs_context.h>
 #include "smack.h"
 
 #define BEBITS (sizeof(__be32) * 8)
@@ -2816,14 +2817,13 @@ static const struct file_operations smk_ptrace_ops = {
 /**
  * smk_fill_super - fill the smackfs superblock
  * @sb: the empty superblock
- * @data: unused
- * @silent: unused
+ * @fc: unused
  *
  * Fill in the well known entries for the smack filesystem
  *
  * Returns 0 on success, an error code on failure
  */
-static int smk_fill_super(struct super_block *sb, void *data, int silent)
+static int smk_fill_super(struct super_block *sb, struct fs_context *fc)
 {
        int rc;
 
@@ -2893,25 +2893,35 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
 }
 
 /**
- * smk_mount - get the smackfs superblock
- * @fs_type: passed along without comment
- * @flags: passed along without comment
- * @dev_name: passed along without comment
- * @data: passed along without comment
+ * smk_get_tree - get the smackfs superblock
+ * @fc: The mount context, including any options
  *
  * Just passes everything along.
  *
  * Returns what the lower level code does.
  */
-static struct dentry *smk_mount(struct file_system_type *fs_type,
-                     int flags, const char *dev_name, void *data)
+static int smk_get_tree(struct fs_context *fc)
 {
-       return mount_single(fs_type, flags, data, smk_fill_super);
+       return get_tree_single(fc, smk_fill_super);
+}
+
+static const struct fs_context_operations smk_context_ops = {
+       .get_tree       = smk_get_tree,
+};
+
+/**
+ * smk_init_fs_context - Initialise a filesystem context for smackfs
+ * @fc: The blank mount context
+ */
+static int smk_init_fs_context(struct fs_context *fc)
+{
+       fc->ops = &smk_context_ops;
+       return 0;
 }
 
 static struct file_system_type smk_fs_type = {
        .name           = "smackfs",
-       .mount          = smk_mount,
+       .init_fs_context = smk_init_fs_context,
        .kill_sb        = kill_litter_super,
 };
 
index 01c6239..94dc346 100644 (file)
@@ -445,7 +445,6 @@ static int yama_dointvec_minmax(struct ctl_table *table, int write,
        return proc_dointvec_minmax(&table_copy, write, buffer, lenp, ppos);
 }
 
-static int zero;
 static int max_scope = YAMA_SCOPE_NO_ATTACH;
 
 static struct ctl_path yama_sysctl_path[] = {
@@ -461,7 +460,7 @@ static struct ctl_table yama_sysctl_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = yama_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = SYSCTL_ZERO,
                .extra2         = &max_scope,
        },
        { }
index 7b977b7..7985dd8 100644 (file)
@@ -122,17 +122,12 @@ static int ac97_codec_add(struct ac97_controller *ac97_ctrl, int idx,
                                                      vendor_id);
 
        ret = device_add(&codec->dev);
-       if (ret)
-               goto err_free_codec;
+       if (ret) {
+               put_device(&codec->dev);
+               return ret;
+       }
 
        return 0;
-err_free_codec:
-       of_node_put(codec->dev.of_node);
-       put_device(&codec->dev);
-       kfree(codec);
-       ac97_ctrl->codecs[idx] = NULL;
-
-       return ret;
 }
 
 unsigned int snd_ac97_bus_scan_one(struct ac97_controller *adrv,
index 99b8821..41905af 100644 (file)
@@ -574,10 +574,7 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
                stream->metadata_set = false;
                stream->next_track = false;
 
-               if (stream->direction == SND_COMPRESS_PLAYBACK)
-                       stream->runtime->state = SNDRV_PCM_STATE_SETUP;
-               else
-                       stream->runtime->state = SNDRV_PCM_STATE_PREPARED;
+               stream->runtime->state = SNDRV_PCM_STATE_SETUP;
        } else {
                return -EPERM;
        }
@@ -693,8 +690,17 @@ static int snd_compr_start(struct snd_compr_stream *stream)
 {
        int retval;
 
-       if (stream->runtime->state != SNDRV_PCM_STATE_PREPARED)
+       switch (stream->runtime->state) {
+       case SNDRV_PCM_STATE_SETUP:
+               if (stream->direction != SND_COMPRESS_CAPTURE)
+                       return -EPERM;
+               break;
+       case SNDRV_PCM_STATE_PREPARED:
+               break;
+       default:
                return -EPERM;
+       }
+
        retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_START);
        if (!retval)
                stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
@@ -705,9 +711,15 @@ static int snd_compr_stop(struct snd_compr_stream *stream)
 {
        int retval;
 
-       if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
-                       stream->runtime->state == SNDRV_PCM_STATE_SETUP)
+       switch (stream->runtime->state) {
+       case SNDRV_PCM_STATE_OPEN:
+       case SNDRV_PCM_STATE_SETUP:
+       case SNDRV_PCM_STATE_PREPARED:
                return -EPERM;
+       default:
+               break;
+       }
+
        retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);
        if (!retval) {
                snd_compr_drain_notify(stream);
@@ -795,9 +807,17 @@ static int snd_compr_drain(struct snd_compr_stream *stream)
 {
        int retval;
 
-       if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
-                       stream->runtime->state == SNDRV_PCM_STATE_SETUP)
+       switch (stream->runtime->state) {
+       case SNDRV_PCM_STATE_OPEN:
+       case SNDRV_PCM_STATE_SETUP:
+       case SNDRV_PCM_STATE_PREPARED:
+       case SNDRV_PCM_STATE_PAUSED:
                return -EPERM;
+       case SNDRV_PCM_STATE_XRUN:
+               return -EPIPE;
+       default:
+               break;
+       }
 
        retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_DRAIN);
        if (retval) {
@@ -817,6 +837,10 @@ static int snd_compr_next_track(struct snd_compr_stream *stream)
        if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING)
                return -EPERM;
 
+       /* next track doesn't have any meaning for capture streams */
+       if (stream->direction == SND_COMPRESS_CAPTURE)
+               return -EPERM;
+
        /* you can signal next track if this is intended to be a gapless stream
         * and current track metadata is set
         */
@@ -834,9 +858,23 @@ static int snd_compr_next_track(struct snd_compr_stream *stream)
 static int snd_compr_partial_drain(struct snd_compr_stream *stream)
 {
        int retval;
-       if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
-                       stream->runtime->state == SNDRV_PCM_STATE_SETUP)
+
+       switch (stream->runtime->state) {
+       case SNDRV_PCM_STATE_OPEN:
+       case SNDRV_PCM_STATE_SETUP:
+       case SNDRV_PCM_STATE_PREPARED:
+       case SNDRV_PCM_STATE_PAUSED:
+               return -EPERM;
+       case SNDRV_PCM_STATE_XRUN:
+               return -EPIPE;
+       default:
+               break;
+       }
+
+       /* partial drain doesn't have any meaning for capture streams */
+       if (stream->direction == SND_COMPRESS_CAPTURE)
                return -EPERM;
+
        /* stream can be drained only when next track has been signalled */
        if (stream->next_track == false)
                return -EPERM;
index 860543a..12dd9b3 100644 (file)
@@ -77,7 +77,7 @@ void snd_pcm_group_init(struct snd_pcm_group *group)
        spin_lock_init(&group->lock);
        mutex_init(&group->mutex);
        INIT_LIST_HEAD(&group->substreams);
-       refcount_set(&group->refs, 0);
+       refcount_set(&group->refs, 1);
 }
 
 /* define group lock helpers */
@@ -1096,8 +1096,7 @@ static void snd_pcm_group_unref(struct snd_pcm_group *group,
 
        if (!group)
                return;
-       do_free = refcount_dec_and_test(&group->refs) &&
-               list_empty(&group->substreams);
+       do_free = refcount_dec_and_test(&group->refs);
        snd_pcm_group_unlock(group, substream->pcm->nonatomic);
        if (do_free)
                kfree(group);
@@ -2020,6 +2019,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
        snd_pcm_group_lock_irq(target_group, nonatomic);
        snd_pcm_stream_lock(substream1);
        snd_pcm_group_assign(substream1, target_group);
+       refcount_inc(&target_group->refs);
        snd_pcm_stream_unlock(substream1);
        snd_pcm_group_unlock_irq(target_group, nonatomic);
  _end:
@@ -2056,13 +2056,14 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream)
        snd_pcm_group_lock_irq(group, nonatomic);
 
        relink_to_local(substream);
+       refcount_dec(&group->refs);
 
        /* detach the last stream, too */
        if (list_is_singular(&group->substreams)) {
                relink_to_local(list_first_entry(&group->substreams,
                                                 struct snd_pcm_substream,
                                                 link_list));
-               do_free = !refcount_read(&group->refs);
+               do_free = refcount_dec_and_test(&group->refs);
        }
 
        snd_pcm_group_unlock_irq(group, nonatomic);
index a60e7a1..7737b26 100644 (file)
@@ -1021,7 +1021,7 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
 {
        struct snd_seq_client *client = file->private_data;
        int written = 0, len;
-       int err;
+       int err, handled;
        struct snd_seq_event event;
 
        if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT))
@@ -1034,6 +1034,8 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
        if (!client->accept_output || client->pool == NULL)
                return -ENXIO;
 
+ repeat:
+       handled = 0;
        /* allocate the pool now if the pool is not allocated yet */ 
        mutex_lock(&client->ioctl_mutex);
        if (client->pool->size > 0 && !snd_seq_write_pool_allocated(client)) {
@@ -1093,12 +1095,19 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
                                                   0, 0, &client->ioctl_mutex);
                if (err < 0)
                        break;
+               handled++;
 
        __skip_event:
                /* Update pointers and counts */
                count -= len;
                buf += len;
                written += len;
+
+               /* let's have a coffee break if too many events are queued */
+               if (++handled >= 200) {
+                       mutex_unlock(&client->ioctl_mutex);
+                       goto repeat;
+               }
        }
 
  out:
index 7347103..2db183f 100644 (file)
@@ -765,7 +765,7 @@ snd_vortex_a3d_hrtf_put(struct snd_kcontrol *kcontrol,
                        struct snd_ctl_elem_value *ucontrol)
 {
        a3dsrc_t *a = kcontrol->private_data;
-       int changed = 1, i;
+       int i;
        int coord[6];
        for (i = 0; i < 6; i++)
                coord[i] = ucontrol->value.integer.value[i];
@@ -774,7 +774,7 @@ snd_vortex_a3d_hrtf_put(struct snd_kcontrol *kcontrol,
        vortex_a3d_coord2hrtf(a->hrtf[1], coord);
        a3dsrc_SetHrtfTarget(a, a->hrtf[0], a->hrtf[1]);
        a3dsrc_SetHrtfCurrent(a, a->hrtf[0], a->hrtf[1]);
-       return changed;
+       return 1;
 }
 
 static int
@@ -783,7 +783,7 @@ snd_vortex_a3d_itd_put(struct snd_kcontrol *kcontrol,
 {
        a3dsrc_t *a = kcontrol->private_data;
        int coord[6];
-       int i, changed = 1;
+       int i;
        for (i = 0; i < 6; i++)
                coord[i] = ucontrol->value.integer.value[i];
        /* Translate orientation coordinates to a3d params. */
@@ -793,7 +793,7 @@ snd_vortex_a3d_itd_put(struct snd_kcontrol *kcontrol,
        a3dsrc_SetItdTarget(a, a->itd[0], a->itd[1]);
        a3dsrc_SetItdCurrent(a, a->itd[0], a->itd[1]);
        a3dsrc_SetItdDline(a, a->dline);
-       return changed;
+       return 1;
 }
 
 static int
@@ -801,7 +801,6 @@ snd_vortex_a3d_ild_put(struct snd_kcontrol *kcontrol,
                       struct snd_ctl_elem_value *ucontrol)
 {
        a3dsrc_t *a = kcontrol->private_data;
-       int changed = 1;
        int l, r;
        /* There may be some scale tranlation needed here. */
        l = ucontrol->value.integer.value[0];
@@ -810,7 +809,7 @@ snd_vortex_a3d_ild_put(struct snd_kcontrol *kcontrol,
        /* Left Right panning. */
        a3dsrc_SetGainTarget(a, l, r);
        a3dsrc_SetGainCurrent(a, l, r);
-       return changed;
+       return 1;
 }
 
 static int
@@ -818,7 +817,7 @@ snd_vortex_a3d_filter_put(struct snd_kcontrol *kcontrol,
                          struct snd_ctl_elem_value *ucontrol)
 {
        a3dsrc_t *a = kcontrol->private_data;
-       int i, changed = 1;
+       int i;
        int params[6];
        for (i = 0; i < 6; i++)
                params[i] = ucontrol->value.integer.value[i];
@@ -831,7 +830,7 @@ snd_vortex_a3d_filter_put(struct snd_kcontrol *kcontrol,
        a3dsrc_SetAtmosCurrent(a, a->filter[0],
                               a->filter[1], a->filter[2],
                               a->filter[3], a->filter[4]);
-       return changed;
+       return 1;
 }
 
 static const struct snd_kcontrol_new vortex_a3d_kcontrol = {
index 67d6473..9cf8183 100644 (file)
@@ -1074,7 +1074,6 @@ static int snd_emu10k1x_shared_spdif_put(struct snd_kcontrol *kcontrol,
 {
        struct emu10k1x *emu = snd_kcontrol_chip(kcontrol);
        unsigned int val;
-       int change = 0;
 
        val = ucontrol->value.integer.value[0] ;
 
@@ -1089,7 +1088,7 @@ static int snd_emu10k1x_shared_spdif_put(struct snd_kcontrol *kcontrol,
                snd_emu10k1x_ptr_write(emu, ROUTING, 0, 0x1003F);
                snd_emu10k1x_gpio_write(emu, 0x1080);
        }
-       return change;
+       return 0;
 }
 
 static const struct snd_kcontrol_new snd_emu10k1x_shared_spdif =
index 5346631..51f10ed 100644 (file)
@@ -2941,15 +2941,19 @@ static int hda_codec_runtime_resume(struct device *dev)
 #ifdef CONFIG_PM_SLEEP
 static int hda_codec_force_resume(struct device *dev)
 {
+       struct hda_codec *codec = dev_to_hda_codec(dev);
+       bool forced_resume = !codec->relaxed_resume && codec->jacktbl.used;
        int ret;
 
        /* The get/put pair below enforces the runtime resume even if the
         * device hasn't been used at suspend time.  This trick is needed to
         * update the jack state change during the sleep.
         */
-       pm_runtime_get_noresume(dev);
+       if (forced_resume)
+               pm_runtime_get_noresume(dev);
        ret = pm_runtime_force_resume(dev);
-       pm_runtime_put(dev);
+       if (forced_resume)
+               pm_runtime_put(dev);
        return ret;
 }
 
index cb8b094..1e14d72 100644 (file)
@@ -313,11 +313,10 @@ enum {
 
 #define AZX_DCAPS_INTEL_SKYLAKE \
        (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\
+        AZX_DCAPS_SYNC_WRITE |\
         AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT)
 
-#define AZX_DCAPS_INTEL_BROXTON \
-       (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\
-        AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT)
+#define AZX_DCAPS_INTEL_BROXTON                AZX_DCAPS_INTEL_SKYLAKE
 
 /* quirks for ATI SB / AMD Hudson */
 #define AZX_DCAPS_PRESET_ATI_SB \
index 4f8d084..f299f13 100644 (file)
@@ -1083,6 +1083,7 @@ static int patch_conexant_auto(struct hda_codec *codec)
  */
 
 static const struct hda_device_id snd_hda_id_conexant[] = {
+       HDA_CODEC_ENTRY(0x14f11f86, "CX8070", patch_conexant_auto),
        HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto),
        HDA_CODEC_ENTRY(0x14f15045, "CX20549 (Venice)", patch_conexant_auto),
        HDA_CODEC_ENTRY(0x14f15047, "CX20551 (Waikiki)", patch_conexant_auto),
index 40323d9..bea7b09 100644 (file)
@@ -2292,8 +2292,10 @@ static void generic_hdmi_free(struct hda_codec *codec)
        struct hdmi_spec *spec = codec->spec;
        int pin_idx, pcm_idx;
 
-       if (codec_has_acomp(codec))
+       if (codec_has_acomp(codec)) {
                snd_hdac_acomp_register_notifier(&codec->bus->core, NULL);
+               codec->relaxed_resume = 0;
+       }
 
        for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
                struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
@@ -2417,7 +2419,6 @@ static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
 }
 
 #define INTEL_GET_VENDOR_VERB  0xf81
-#define INTEL_GET_VENDOR_VERB  0xf81
 #define INTEL_SET_VENDOR_VERB  0x781
 #define INTEL_EN_DP12          0x02    /* enable DP 1.2 features */
 #define INTEL_EN_ALL_PIN_CVTS  0x01    /* enable 2nd & 3rd pins and convertors */
@@ -2525,18 +2526,32 @@ static int intel_pin2port(void *audio_ptr, int pin_nid)
        return -1;
 }
 
+static int intel_port2pin(struct hda_codec *codec, int port)
+{
+       struct hdmi_spec *spec = codec->spec;
+
+       if (!spec->port_num) {
+               /* we assume only from port-B to port-D */
+               if (port < 1 || port > 3)
+                       return 0;
+               /* intel port is 1-based */
+               return port + intel_base_nid(codec) - 1;
+       }
+
+       if (port < 1 || port > spec->port_num)
+               return 0;
+       return spec->port_map[port - 1];
+}
+
 static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
 {
        struct hda_codec *codec = audio_ptr;
        int pin_nid;
        int dev_id = pipe;
 
-       /* we assume only from port-B to port-D */
-       if (port < 1 || port > 3)
+       pin_nid = intel_port2pin(codec, port);
+       if (!pin_nid)
                return;
-
-       pin_nid = port + intel_base_nid(codec) - 1; /* intel port is 1-based */
-
        /* skip notification during system suspend (but not in runtime PM);
         * the state will be updated at resume
         */
@@ -2566,6 +2581,8 @@ static void register_i915_notifier(struct hda_codec *codec)
        spec->drm_audio_ops.pin_eld_notify = intel_pin_eld_notify;
        snd_hdac_acomp_register_notifier(&codec->bus->core,
                                        &spec->drm_audio_ops);
+       /* no need for forcible resume for jack check thanks to notifier */
+       codec->relaxed_resume = 1;
 }
 
 /* setup_stream ops override for HSW+ */
index f24a757..de224cb 100644 (file)
@@ -7657,9 +7657,12 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x12, 0x90a60130},
                {0x17, 0x90170110},
                {0x21, 0x03211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+       SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
                {0x14, 0x90170110},
                {0x21, 0x04211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
+               {0x14, 0x90170110},
+               {0x21, 0x04211030}),
        SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
                ALC295_STANDARD_PINS,
                {0x17, 0x21014020},
@@ -8800,6 +8803,11 @@ static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = {
                {0x18, 0x01a19030},
                {0x1a, 0x01813040},
                {0x21, 0x01014020}),
+       SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
+               {0x16, 0x01813030},
+               {0x17, 0x02211010},
+               {0x18, 0x01a19040},
+               {0x21, 0x01014020}),
        SND_HDA_PIN_QUIRK(0x10ec0662, 0x1028, "Dell", ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
                {0x14, 0x01014010},
                {0x18, 0x01a19020},
index 1771a6d..583ca73 100644 (file)
@@ -253,9 +253,8 @@ exit:
 
 static int lx_pcm_close(struct snd_pcm_substream *substream)
 {
-       int err = 0;
        dev_dbg(substream->pcm->card->dev, "->lx_pcm_close\n");
-       return err;
+       return 0;
 }
 
 static snd_pcm_uframes_t lx_pcm_stream_pointer(struct snd_pcm_substream
index cb9818a..4c851f8 100644 (file)
@@ -2158,13 +2158,12 @@ static int snd_rme9652_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
        unsigned long flags;
-       int result = 0;
 
        spin_lock_irqsave(&rme9652->lock, flags);
        if (!rme9652->running)
                rme9652_reset_hw_pointer(rme9652);
        spin_unlock_irqrestore(&rme9652->lock, flags);
-       return result;
+       return 0;
 }
 
 static const struct snd_pcm_hardware snd_rme9652_playback_subinfo =
index 71b7fd3..c213eb7 100644 (file)
@@ -628,7 +628,6 @@ static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream,
                               int cmd)
 {
        struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
-       int ret = 0;
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -665,7 +664,7 @@ static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream,
 
        }
 
-       return ret;
+       return 0;
 };
 
 /*
index 4f85cb1..e8141a3 100644 (file)
@@ -1194,7 +1194,7 @@ EXPORT_SYMBOL_GPL(q6asm_open_read);
  * q6asm_write_async() - non blocking write
  *
  * @ac: audio client pointer
- * @len: lenght in bytes
+ * @len: length in bytes
  * @msw_ts: timestamp msw
  * @lsw_ts: timestamp lsw
  * @wflags: flags associated with write
index f0662bd..27bf61c 100644 (file)
@@ -368,7 +368,7 @@ static const struct line6_properties podhd_properties_table[] = {
                .name = "POD HD500",
                .capabilities   = LINE6_CAP_PCM
                                | LINE6_CAP_HWMON,
-               .altsetting = 1,
+               .altsetting = 0,
                .ep_ctrl_r = 0x81,
                .ep_ctrl_w = 0x01,
                .ep_audio_r = 0x86,
index 0d24c72..ed158f0 100644 (file)
@@ -244,5 +244,5 @@ static struct usb_driver variax_driver = {
 
 module_usb_driver(variax_driver);
 
-MODULE_DESCRIPTION("Vairax Workbench USB driver");
+MODULE_DESCRIPTION("Variax Workbench USB driver");
 MODULE_LICENSE("GPL");
index 3ef0d90..7031a4b 100644 (file)
@@ -74,6 +74,7 @@ static const char * const prog_type_name[] = {
        [BPF_PROG_TYPE_SK_REUSEPORT]            = "sk_reuseport",
        [BPF_PROG_TYPE_FLOW_DISSECTOR]          = "flow_dissector",
        [BPF_PROG_TYPE_CGROUP_SYSCTL]           = "cgroup_sysctl",
+       [BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE] = "raw_tracepoint_writable",
        [BPF_PROG_TYPE_CGROUP_SOCKOPT]          = "cgroup_sockopt",
 };
 
index f506c68..4e45501 100644 (file)
@@ -806,7 +806,7 @@ union bpf_attr {
  *             based on a user-provided identifier for all traffic coming from
  *             the tasks belonging to the related cgroup. See also the related
  *             kernel documentation, available from the Linux sources in file
- *             *Documentation/cgroup-v1/net_cls.rst*.
+ *             *Documentation/admin-guide/cgroup-v1/net_cls.rst*.
  *
  *             The Linux kernel has two versions for cgroups: there are
  *             cgroups v1 and cgroups v2. Both are available to users, who can
@@ -3245,7 +3245,7 @@ struct bpf_sock_addr {
        __u32 user_ip4;         /* Allows 1,2,4-byte read and 4-byte write.
                                 * Stored in network byte order.
                                 */
-       __u32 user_ip6[4];      /* Allows 1,2,4-byte read and 4,8-byte write.
+       __u32 user_ip6[4];      /* Allows 1,2,4,8-byte read and 4,8-byte write.
                                 * Stored in network byte order.
                                 */
        __u32 user_port;        /* Allows 4-byte read and write.
@@ -3257,7 +3257,7 @@ struct bpf_sock_addr {
        __u32 msg_src_ip4;      /* Allows 1,2,4-byte read and 4-byte write.
                                 * Stored in network byte order.
                                 */
-       __u32 msg_src_ip6[4];   /* Allows 1,2,4-byte read and 4,8-byte write.
+       __u32 msg_src_ip6[4];   /* Allows 1,2,4,8-byte read and 4,8-byte write.
                                 * Stored in network byte order.
                                 */
        __bpf_md_ptr(struct bpf_sock *, sk);
index c2152f3..e7c67be 100644 (file)
@@ -116,7 +116,7 @@ struct kvm_irq_level {
         * ACPI gsi notion of irq.
         * For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47..
         * For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23..
-        * For ARM: See Documentation/virtual/kvm/api.txt
+        * For ARM: See Documentation/virt/kvm/api.txt
         */
        union {
                __u32 irq;
@@ -1085,7 +1085,7 @@ struct kvm_xen_hvm_config {
  *
  * KVM_IRQFD_FLAG_RESAMPLE indicates resamplefd is valid and specifies
  * the irqfd to operate in resampling mode for level triggered interrupt
- * emulation.  See Documentation/virtual/kvm/api.txt.
+ * emulation.  See Documentation/virt/kvm/api.txt.
  */
 #define KVM_IRQFD_FLAG_RESAMPLE (1 << 1)
 
index ed07789..794dd50 100644 (file)
@@ -4126,8 +4126,8 @@ static int perf_event_open_probe(bool uprobe, bool retprobe, const char *name,
        }
        attr.size = sizeof(attr);
        attr.type = type;
-       attr.config1 = (uint64_t)(void *)name; /* kprobe_func or uprobe_path */
-       attr.config2 = offset;                 /* kprobe_addr or probe_offset */
+       attr.config1 = ptr_to_u64(name); /* kprobe_func or uprobe_path */
+       attr.config2 = offset;           /* kprobe_addr or probe_offset */
 
        /* pid filter is meaningful only for uprobes */
        pfd = syscall(__NR_perf_event_open, &attr,
index b337402..5007b5d 100644 (file)
@@ -517,7 +517,8 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
                err = -errno;
                goto out_socket;
        }
-       strncpy(xsk->ifname, ifname, IFNAMSIZ);
+       strncpy(xsk->ifname, ifname, IFNAMSIZ - 1);
+       xsk->ifname[IFNAMSIZ - 1] = '\0';
 
        err = xsk_set_xdp_socket_config(&xsk->config, usr_config);
        if (err)
index 580e344..ced3765 100644 (file)
 #include "elf.h"
 #include "cfi.h"
 
-#define INSN_JUMP_CONDITIONAL  1
-#define INSN_JUMP_UNCONDITIONAL        2
-#define INSN_JUMP_DYNAMIC      3
-#define INSN_CALL              4
-#define INSN_CALL_DYNAMIC      5
-#define INSN_RETURN            6
-#define INSN_CONTEXT_SWITCH    7
-#define INSN_STACK             8
-#define INSN_BUG               9
-#define INSN_NOP               10
-#define INSN_STAC              11
-#define INSN_CLAC              12
-#define INSN_STD               13
-#define INSN_CLD               14
-#define INSN_OTHER             15
-#define INSN_LAST              INSN_OTHER
+enum insn_type {
+       INSN_JUMP_CONDITIONAL,
+       INSN_JUMP_UNCONDITIONAL,
+       INSN_JUMP_DYNAMIC,
+       INSN_JUMP_DYNAMIC_CONDITIONAL,
+       INSN_CALL,
+       INSN_CALL_DYNAMIC,
+       INSN_RETURN,
+       INSN_CONTEXT_SWITCH,
+       INSN_STACK,
+       INSN_BUG,
+       INSN_NOP,
+       INSN_STAC,
+       INSN_CLAC,
+       INSN_STD,
+       INSN_CLD,
+       INSN_OTHER,
+};
 
 enum op_dest_type {
        OP_DEST_REG,
@@ -68,7 +70,7 @@ void arch_initial_func_cfi_state(struct cfi_state *state);
 
 int arch_decode_instruction(struct elf *elf, struct section *sec,
                            unsigned long offset, unsigned int maxlen,
-                           unsigned int *len, unsigned char *type,
+                           unsigned int *len, enum insn_type *type,
                            unsigned long *immediate, struct stack_op *op);
 
 bool arch_callee_saved_reg(unsigned char reg);
index 584568f..0567c47 100644 (file)
@@ -68,7 +68,7 @@ bool arch_callee_saved_reg(unsigned char reg)
 
 int arch_decode_instruction(struct elf *elf, struct section *sec,
                            unsigned long offset, unsigned int maxlen,
-                           unsigned int *len, unsigned char *type,
+                           unsigned int *len, enum insn_type *type,
                            unsigned long *immediate, struct stack_op *op)
 {
        struct insn insn;
index 172f991..5f26620 100644 (file)
@@ -18,6 +18,8 @@
 
 #define FAKE_JUMP_OFFSET -1
 
+#define C_JUMP_TABLE_SECTION ".rodata..c_jump_table"
+
 struct alternative {
        struct list_head list;
        struct instruction *insn;
@@ -95,6 +97,20 @@ static struct instruction *next_insn_same_func(struct objtool_file *file,
        for (insn = next_insn_same_sec(file, insn); insn;               \
             insn = next_insn_same_sec(file, insn))
 
+static bool is_sibling_call(struct instruction *insn)
+{
+       /* An indirect jump is either a sibling call or a jump to a table. */
+       if (insn->type == INSN_JUMP_DYNAMIC)
+               return list_empty(&insn->alts);
+
+       if (insn->type != INSN_JUMP_CONDITIONAL &&
+           insn->type != INSN_JUMP_UNCONDITIONAL)
+               return false;
+
+       /* add_jump_destinations() sets insn->call_dest for sibling calls. */
+       return !!insn->call_dest;
+}
+
 /*
  * This checks to see if the given function is a "noreturn" function.
  *
@@ -103,14 +119,9 @@ static struct instruction *next_insn_same_func(struct objtool_file *file,
  *
  * For local functions, we have to detect them manually by simply looking for
  * the lack of a return instruction.
- *
- * Returns:
- *  -1: error
- *   0: no dead end
- *   1: dead end
  */
-static int __dead_end_function(struct objtool_file *file, struct symbol *func,
-                              int recursion)
+static bool __dead_end_function(struct objtool_file *file, struct symbol *func,
+                               int recursion)
 {
        int i;
        struct instruction *insn;
@@ -136,30 +147,33 @@ static int __dead_end_function(struct objtool_file *file, struct symbol *func,
                "rewind_stack_do_exit",
        };
 
+       if (!func)
+               return false;
+
        if (func->bind == STB_WEAK)
-               return 0;
+               return false;
 
        if (func->bind == STB_GLOBAL)
                for (i = 0; i < ARRAY_SIZE(global_noreturns); i++)
                        if (!strcmp(func->name, global_noreturns[i]))
-                               return 1;
+                               return true;
 
        if (!func->len)
-               return 0;
+               return false;
 
        insn = find_insn(file, func->sec, func->offset);
        if (!insn->func)
-               return 0;
+               return false;
 
        func_for_each_insn_all(file, func, insn) {
                empty = false;
 
                if (insn->type == INSN_RETURN)
-                       return 0;
+                       return false;
        }
 
        if (empty)
-               return 0;
+               return false;
 
        /*
         * A function can have a sibling call instead of a return.  In that
@@ -167,40 +181,31 @@ static int __dead_end_function(struct objtool_file *file, struct symbol *func,
         * of the sibling call returns.
         */
        func_for_each_insn_all(file, func, insn) {
-               if (insn->type == INSN_JUMP_UNCONDITIONAL) {
+               if (is_sibling_call(insn)) {
                        struct instruction *dest = insn->jump_dest;
 
                        if (!dest)
                                /* sibling call to another file */
-                               return 0;
-
-                       if (dest->func && dest->func->pfunc != insn->func->pfunc) {
+                               return false;
 
-                               /* local sibling call */
-                               if (recursion == 5) {
-                                       /*
-                                        * Infinite recursion: two functions
-                                        * have sibling calls to each other.
-                                        * This is a very rare case.  It means
-                                        * they aren't dead ends.
-                                        */
-                                       return 0;
-                               }
-
-                               return __dead_end_function(file, dest->func,
-                                                          recursion + 1);
+                       /* local sibling call */
+                       if (recursion == 5) {
+                               /*
+                                * Infinite recursion: two functions have
+                                * sibling calls to each other.  This is a very
+                                * rare case.  It means they aren't dead ends.
+                                */
+                               return false;
                        }
-               }
 
-               if (insn->type == INSN_JUMP_DYNAMIC && list_empty(&insn->alts))
-                       /* sibling call */
-                       return 0;
+                       return __dead_end_function(file, dest->func, recursion+1);
+               }
        }
 
-       return 1;
+       return true;
 }
 
-static int dead_end_function(struct objtool_file *file, struct symbol *func)
+static bool dead_end_function(struct objtool_file *file, struct symbol *func)
 {
        return __dead_end_function(file, func, 0);
 }
@@ -262,19 +267,12 @@ static int decode_instructions(struct objtool_file *file)
                        if (ret)
                                goto err;
 
-                       if (!insn->type || insn->type > INSN_LAST) {
-                               WARN_FUNC("invalid instruction type %d",
-                                         insn->sec, insn->offset, insn->type);
-                               ret = -1;
-                               goto err;
-                       }
-
                        hash_add(file->insn_hash, &insn->hash, insn->offset);
                        list_add_tail(&insn->list, &file->insn_list);
                }
 
                list_for_each_entry(func, &sec->symbol_list, list) {
-                       if (func->type != STT_FUNC)
+                       if (func->type != STT_FUNC || func->alias != func)
                                continue;
 
                        if (!find_insn(file, sec, func->offset)) {
@@ -284,8 +282,7 @@ static int decode_instructions(struct objtool_file *file)
                        }
 
                        func_for_each_insn(file, func, insn)
-                               if (!insn->func)
-                                       insn->func = func;
+                               insn->func = func;
                }
        }
 
@@ -488,6 +485,7 @@ static const char *uaccess_safe_builtin[] = {
        /* misc */
        "csum_partial_copy_generic",
        "__memcpy_mcsafe",
+       "mcsafe_handle_tail",
        "ftrace_likely_update", /* CONFIG_TRACE_BRANCH_PROFILING */
        NULL
 };
@@ -505,7 +503,7 @@ static void add_uaccess_safe(struct objtool_file *file)
                if (!func)
                        continue;
 
-               func->alias->uaccess_safe = true;
+               func->uaccess_safe = true;
        }
 }
 
@@ -577,13 +575,16 @@ static int add_jump_destinations(struct objtool_file *file)
                         * Retpoline jumps are really dynamic jumps in
                         * disguise, so convert them accordingly.
                         */
-                       insn->type = INSN_JUMP_DYNAMIC;
+                       if (insn->type == INSN_JUMP_UNCONDITIONAL)
+                               insn->type = INSN_JUMP_DYNAMIC;
+                       else
+                               insn->type = INSN_JUMP_DYNAMIC_CONDITIONAL;
+
                        insn->retpoline_safe = true;
                        continue;
                } else {
-                       /* sibling call */
+                       /* external sibling call */
                        insn->call_dest = rela->sym;
-                       insn->jump_dest = NULL;
                        continue;
                }
 
@@ -623,7 +624,7 @@ static int add_jump_destinations(struct objtool_file *file)
                         * However this code can't completely replace the
                         * read_symbols() code because this doesn't detect the
                         * case where the parent function's only reference to a
-                        * subfunction is through a switch table.
+                        * subfunction is through a jump table.
                         */
                        if (!strstr(insn->func->name, ".cold.") &&
                            strstr(insn->jump_dest->func->name, ".cold.")) {
@@ -633,9 +634,8 @@ static int add_jump_destinations(struct objtool_file *file)
                        } else if (insn->jump_dest->func->pfunc != insn->func->pfunc &&
                                   insn->jump_dest->offset == insn->jump_dest->func->offset) {
 
-                               /* sibling class */
+                               /* internal sibling call */
                                insn->call_dest = insn->jump_dest->func;
-                               insn->jump_dest = NULL;
                        }
                }
        }
@@ -896,20 +896,26 @@ out:
        return ret;
 }
 
-static int add_switch_table(struct objtool_file *file, struct instruction *insn,
-                           struct rela *table, struct rela *next_table)
+static int add_jump_table(struct objtool_file *file, struct instruction *insn,
+                           struct rela *table)
 {
        struct rela *rela = table;
-       struct instruction *alt_insn;
+       struct instruction *dest_insn;
        struct alternative *alt;
        struct symbol *pfunc = insn->func->pfunc;
        unsigned int prev_offset = 0;
 
-       list_for_each_entry_from(rela, &table->rela_sec->rela_list, list) {
-               if (rela == next_table)
+       /*
+        * Each @rela is a switch table relocation which points to the target
+        * instruction.
+        */
+       list_for_each_entry_from(rela, &table->sec->rela_list, list) {
+
+               /* Check for the end of the table: */
+               if (rela != table && rela->jump_table_start)
                        break;
 
-               /* Make sure the switch table entries are consecutive: */
+               /* Make sure the table entries are consecutive: */
                if (prev_offset && rela->offset != prev_offset + 8)
                        break;
 
@@ -918,12 +924,12 @@ static int add_switch_table(struct objtool_file *file, struct instruction *insn,
                    rela->addend == pfunc->offset)
                        break;
 
-               alt_insn = find_insn(file, rela->sym->sec, rela->addend);
-               if (!alt_insn)
+               dest_insn = find_insn(file, rela->sym->sec, rela->addend);
+               if (!dest_insn)
                        break;
 
-               /* Make sure the jmp dest is in the function or subfunction: */
-               if (alt_insn->func->pfunc != pfunc)
+               /* Make sure the destination is in the same function: */
+               if (!dest_insn->func || dest_insn->func->pfunc != pfunc)
                        break;
 
                alt = malloc(sizeof(*alt));
@@ -932,7 +938,7 @@ static int add_switch_table(struct objtool_file *file, struct instruction *insn,
                        return -1;
                }
 
-               alt->insn = alt_insn;
+               alt->insn = dest_insn;
                list_add_tail(&alt->list, &insn->alts);
                prev_offset = rela->offset;
        }
@@ -947,7 +953,7 @@ static int add_switch_table(struct objtool_file *file, struct instruction *insn,
 }
 
 /*
- * find_switch_table() - Given a dynamic jump, find the switch jump table in
+ * find_jump_table() - Given a dynamic jump, find the switch jump table in
  * .rodata associated with it.
  *
  * There are 3 basic patterns:
@@ -989,13 +995,13 @@ static int add_switch_table(struct objtool_file *file, struct instruction *insn,
  *
  *    NOTE: RETPOLINE made it harder still to decode dynamic jumps.
  */
-static struct rela *find_switch_table(struct objtool_file *file,
+static struct rela *find_jump_table(struct objtool_file *file,
                                      struct symbol *func,
                                      struct instruction *insn)
 {
-       struct rela *text_rela, *rodata_rela;
+       struct rela *text_rela, *table_rela;
        struct instruction *orig_insn = insn;
-       struct section *rodata_sec;
+       struct section *table_sec;
        unsigned long table_offset;
 
        /*
@@ -1028,42 +1034,52 @@ static struct rela *find_switch_table(struct objtool_file *file,
                        continue;
 
                table_offset = text_rela->addend;
-               rodata_sec = text_rela->sym->sec;
+               table_sec = text_rela->sym->sec;
 
                if (text_rela->type == R_X86_64_PC32)
                        table_offset += 4;
 
                /*
                 * Make sure the .rodata address isn't associated with a
-                * symbol.  gcc jump tables are anonymous data.
+                * symbol.  GCC jump tables are anonymous data.
+                *
+                * Also support C jump tables which are in the same format as
+                * switch jump tables.  For objtool to recognize them, they
+                * need to be placed in the C_JUMP_TABLE_SECTION section.  They
+                * have symbols associated with them.
                 */
-               if (find_symbol_containing(rodata_sec, table_offset))
+               if (find_symbol_containing(table_sec, table_offset) &&
+                   strcmp(table_sec->name, C_JUMP_TABLE_SECTION))
                        continue;
 
-               rodata_rela = find_rela_by_dest(rodata_sec, table_offset);
-               if (rodata_rela) {
-                       /*
-                        * Use of RIP-relative switch jumps is quite rare, and
-                        * indicates a rare GCC quirk/bug which can leave dead
-                        * code behind.
-                        */
-                       if (text_rela->type == R_X86_64_PC32)
-                               file->ignore_unreachables = true;
+               /* Each table entry has a rela associated with it. */
+               table_rela = find_rela_by_dest(table_sec, table_offset);
+               if (!table_rela)
+                       continue;
 
-                       return rodata_rela;
-               }
+               /*
+                * Use of RIP-relative switch jumps is quite rare, and
+                * indicates a rare GCC quirk/bug which can leave dead code
+                * behind.
+                */
+               if (text_rela->type == R_X86_64_PC32)
+                       file->ignore_unreachables = true;
+
+               return table_rela;
        }
 
        return NULL;
 }
 
-
-static int add_func_switch_tables(struct objtool_file *file,
-                                 struct symbol *func)
+/*
+ * First pass: Mark the head of each jump table so that in the next pass,
+ * we know when a given jump table ends and the next one starts.
+ */
+static void mark_func_jump_tables(struct objtool_file *file,
+                                   struct symbol *func)
 {
-       struct instruction *insn, *last = NULL, *prev_jump = NULL;
-       struct rela *rela, *prev_rela = NULL;
-       int ret;
+       struct instruction *insn, *last = NULL;
+       struct rela *rela;
 
        func_for_each_insn_all(file, func, insn) {
                if (!last)
@@ -1071,7 +1087,7 @@ static int add_func_switch_tables(struct objtool_file *file,
 
                /*
                 * Store back-pointers for unconditional forward jumps such
-                * that find_switch_table() can back-track using those and
+                * that find_jump_table() can back-track using those and
                 * avoid some potentially confusing code.
                 */
                if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest &&
@@ -1086,27 +1102,25 @@ static int add_func_switch_tables(struct objtool_file *file,
                if (insn->type != INSN_JUMP_DYNAMIC)
                        continue;
 
-               rela = find_switch_table(file, func, insn);
-               if (!rela)
-                       continue;
-
-               /*
-                * We found a switch table, but we don't know yet how big it
-                * is.  Don't add it until we reach the end of the function or
-                * the beginning of another switch table in the same function.
-                */
-               if (prev_jump) {
-                       ret = add_switch_table(file, prev_jump, prev_rela, rela);
-                       if (ret)
-                               return ret;
+               rela = find_jump_table(file, func, insn);
+               if (rela) {
+                       rela->jump_table_start = true;
+                       insn->jump_table = rela;
                }
-
-               prev_jump = insn;
-               prev_rela = rela;
        }
+}
+
+static int add_func_jump_tables(struct objtool_file *file,
+                                 struct symbol *func)
+{
+       struct instruction *insn;
+       int ret;
 
-       if (prev_jump) {
-               ret = add_switch_table(file, prev_jump, prev_rela, NULL);
+       func_for_each_insn_all(file, func, insn) {
+               if (!insn->jump_table)
+                       continue;
+
+               ret = add_jump_table(file, insn, insn->jump_table);
                if (ret)
                        return ret;
        }
@@ -1119,7 +1133,7 @@ static int add_func_switch_tables(struct objtool_file *file,
  * section which contains a list of addresses within the function to jump to.
  * This finds these jump tables and adds them to the insn->alts lists.
  */
-static int add_switch_table_alts(struct objtool_file *file)
+static int add_jump_table_alts(struct objtool_file *file)
 {
        struct section *sec;
        struct symbol *func;
@@ -1133,7 +1147,8 @@ static int add_switch_table_alts(struct objtool_file *file)
                        if (func->type != STT_FUNC)
                                continue;
 
-                       ret = add_func_switch_tables(file, func);
+                       mark_func_jump_tables(file, func);
+                       ret = add_func_jump_tables(file, func);
                        if (ret)
                                return ret;
                }
@@ -1277,13 +1292,18 @@ static void mark_rodata(struct objtool_file *file)
        bool found = false;
 
        /*
-        * This searches for the .rodata section or multiple .rodata.func_name
-        * sections if -fdata-sections is being used. The .str.1.1 and .str.1.8
-        * rodata sections are ignored as they don't contain jump tables.
+        * Search for the following rodata sections, each of which can
+        * potentially contain jump tables:
+        *
+        * - .rodata: can contain GCC switch tables
+        * - .rodata.<func>: same, if -fdata-sections is being used
+        * - .rodata..c_jump_table: contains C annotated jump tables
+        *
+        * .rodata.str1.* sections are ignored; they don't contain jump tables.
         */
        for_each_sec(file, sec) {
-               if (!strncmp(sec->name, ".rodata", 7) &&
-                   !strstr(sec->name, ".str1.")) {
+               if ((!strncmp(sec->name, ".rodata", 7) && !strstr(sec->name, ".str1.")) ||
+                   !strcmp(sec->name, C_JUMP_TABLE_SECTION)) {
                        sec->rodata = true;
                        found = true;
                }
@@ -1325,7 +1345,7 @@ static int decode_sections(struct objtool_file *file)
        if (ret)
                return ret;
 
-       ret = add_switch_table_alts(file);
+       ret = add_jump_table_alts(file);
        if (ret)
                return ret;
 
@@ -1873,12 +1893,12 @@ static bool insn_state_match(struct instruction *insn, struct insn_state *state)
 static inline bool func_uaccess_safe(struct symbol *func)
 {
        if (func)
-               return func->alias->uaccess_safe;
+               return func->uaccess_safe;
 
        return false;
 }
 
-static inline const char *insn_dest_name(struct instruction *insn)
+static inline const char *call_dest_name(struct instruction *insn)
 {
        if (insn->call_dest)
                return insn->call_dest->name;
@@ -1890,13 +1910,13 @@ static int validate_call(struct instruction *insn, struct insn_state *state)
 {
        if (state->uaccess && !func_uaccess_safe(insn->call_dest)) {
                WARN_FUNC("call to %s() with UACCESS enabled",
-                               insn->sec, insn->offset, insn_dest_name(insn));
+                               insn->sec, insn->offset, call_dest_name(insn));
                return 1;
        }
 
        if (state->df) {
                WARN_FUNC("call to %s() with DF set",
-                               insn->sec, insn->offset, insn_dest_name(insn));
+                               insn->sec, insn->offset, call_dest_name(insn));
                return 1;
        }
 
@@ -1920,13 +1940,12 @@ static int validate_sibling_call(struct instruction *insn, struct insn_state *st
  * each instruction and validate all the rules described in
  * tools/objtool/Documentation/stack-validation.txt.
  */
-static int validate_branch(struct objtool_file *file, struct instruction *first,
-                          struct insn_state state)
+static int validate_branch(struct objtool_file *file, struct symbol *func,
+                          struct instruction *first, struct insn_state state)
 {
        struct alternative *alt;
        struct instruction *insn, *next_insn;
        struct section *sec;
-       struct symbol *func = NULL;
        int ret;
 
        insn = first;
@@ -1947,9 +1966,6 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
                        return 1;
                }
 
-               if (insn->func)
-                       func = insn->func->pfunc;
-
                if (func && insn->ignore) {
                        WARN_FUNC("BUG: why am I validating an ignored function?",
                                  sec, insn->offset);
@@ -1971,7 +1987,7 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
 
                                i = insn;
                                save_insn = NULL;
-                               func_for_each_insn_continue_reverse(file, insn->func, i) {
+                               func_for_each_insn_continue_reverse(file, func, i) {
                                        if (i->save) {
                                                save_insn = i;
                                                break;
@@ -2017,7 +2033,7 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
                                if (alt->skip_orig)
                                        skip_orig = true;
 
-                               ret = validate_branch(file, alt->insn, state);
+                               ret = validate_branch(file, func, alt->insn, state);
                                if (ret) {
                                        if (backtrace)
                                                BT_FUNC("(alt)", insn);
@@ -2055,7 +2071,7 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
 
                        if (state.bp_scratch) {
                                WARN("%s uses BP as a scratch register",
-                                    insn->func->name);
+                                    func->name);
                                return 1;
                        }
 
@@ -2067,36 +2083,28 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
                        if (ret)
                                return ret;
 
-                       if (insn->type == INSN_CALL) {
-                               if (is_fentry_call(insn))
-                                       break;
-
-                               ret = dead_end_function(file, insn->call_dest);
-                               if (ret == 1)
-                                       return 0;
-                               if (ret == -1)
-                                       return 1;
-                       }
-
-                       if (!no_fp && func && !has_valid_stack_frame(&state)) {
+                       if (!no_fp && func && !is_fentry_call(insn) &&
+                           !has_valid_stack_frame(&state)) {
                                WARN_FUNC("call without frame pointer save/setup",
                                          sec, insn->offset);
                                return 1;
                        }
+
+                       if (dead_end_function(file, insn->call_dest))
+                               return 0;
+
                        break;
 
                case INSN_JUMP_CONDITIONAL:
                case INSN_JUMP_UNCONDITIONAL:
-                       if (func && !insn->jump_dest) {
+                       if (func && is_sibling_call(insn)) {
                                ret = validate_sibling_call(insn, &state);
                                if (ret)
                                        return ret;
 
-                       } else if (insn->jump_dest &&
-                                  (!func || !insn->jump_dest->func ||
-                                   insn->jump_dest->func->pfunc == func)) {
-                               ret = validate_branch(file, insn->jump_dest,
-                                                     state);
+                       } else if (insn->jump_dest) {
+                               ret = validate_branch(file, func,
+                                                     insn->jump_dest, state);
                                if (ret) {
                                        if (backtrace)
                                                BT_FUNC("(branch)", insn);
@@ -2110,13 +2118,17 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
                        break;
 
                case INSN_JUMP_DYNAMIC:
-                       if (func && list_empty(&insn->alts)) {
+               case INSN_JUMP_DYNAMIC_CONDITIONAL:
+                       if (func && is_sibling_call(insn)) {
                                ret = validate_sibling_call(insn, &state);
                                if (ret)
                                        return ret;
                        }
 
-                       return 0;
+                       if (insn->type == INSN_JUMP_DYNAMIC)
+                               return 0;
+
+                       break;
 
                case INSN_CONTEXT_SWITCH:
                        if (func && (!next_insn || !next_insn->hint)) {
@@ -2162,7 +2174,7 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
                        break;
 
                case INSN_CLAC:
-                       if (!state.uaccess && insn->func) {
+                       if (!state.uaccess && func) {
                                WARN_FUNC("redundant UACCESS disable", sec, insn->offset);
                                return 1;
                        }
@@ -2183,7 +2195,7 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
                        break;
 
                case INSN_CLD:
-                       if (!state.df && insn->func)
+                       if (!state.df && func)
                                WARN_FUNC("redundant CLD", sec, insn->offset);
 
                        state.df = false;
@@ -2222,7 +2234,7 @@ static int validate_unwind_hints(struct objtool_file *file)
 
        for_each_insn(file, insn) {
                if (insn->hint && !insn->visited) {
-                       ret = validate_branch(file, insn, state);
+                       ret = validate_branch(file, insn->func, insn, state);
                        if (ret && backtrace)
                                BT_FUNC("<=== (hint)", insn);
                        warnings += ret;
@@ -2345,16 +2357,25 @@ static int validate_functions(struct objtool_file *file)
 
        for_each_sec(file, sec) {
                list_for_each_entry(func, &sec->symbol_list, list) {
-                       if (func->type != STT_FUNC || func->pfunc != func)
+                       if (func->type != STT_FUNC)
+                               continue;
+
+                       if (!func->len) {
+                               WARN("%s() is missing an ELF size annotation",
+                                    func->name);
+                               warnings++;
+                       }
+
+                       if (func->pfunc != func || func->alias != func)
                                continue;
 
                        insn = find_insn(file, sec, func->offset);
-                       if (!insn || insn->ignore)
+                       if (!insn || insn->ignore || insn->visited)
                                continue;
 
-                       state.uaccess = func->alias->uaccess_safe;
+                       state.uaccess = func->uaccess_safe;
 
-                       ret = validate_branch(file, insn, state);
+                       ret = validate_branch(file, func, insn, state);
                        if (ret && backtrace)
                                BT_FUNC("<=== (func)", insn);
                        warnings += ret;
@@ -2407,7 +2428,7 @@ int check(const char *_objname, bool orc)
 
        objname = _objname;
 
-       file.elf = elf_open(objname, orc ? O_RDWR : O_RDONLY);
+       file.elf = elf_read(objname, orc ? O_RDWR : O_RDONLY);
        if (!file.elf)
                return 1;
 
index cb60b9a..b881faf 100644 (file)
@@ -31,13 +31,14 @@ struct instruction {
        struct section *sec;
        unsigned long offset;
        unsigned int len;
-       unsigned char type;
+       enum insn_type type;
        unsigned long immediate;
        bool alt_group, visited, dead_end, ignore, hint, save, restore, ignore_alts;
        bool retpoline_safe;
        struct symbol *call_dest;
        struct instruction *jump_dest;
        struct instruction *first_jump_src;
+       struct rela *jump_table;
        struct list_head alts;
        struct symbol *func;
        struct stack_op stack_op;
index e99e1be..edba474 100644 (file)
@@ -278,7 +278,7 @@ static int read_symbols(struct elf *elf)
                        }
 
                        if (sym->offset == s->offset) {
-                               if (sym->len == s->len && alias == sym)
+                               if (sym->len && sym->len == s->len && alias == sym)
                                        alias = s;
 
                                if (sym->len >= s->len) {
@@ -385,7 +385,7 @@ static int read_relas(struct elf *elf)
                        rela->offset = rela->rela.r_offset;
                        symndx = GELF_R_SYM(rela->rela.r_info);
                        rela->sym = find_symbol_by_index(elf, symndx);
-                       rela->rela_sec = sec;
+                       rela->sec = sec;
                        if (!rela->sym) {
                                WARN("can't find rela entry symbol %d for %s",
                                     symndx, sec->name);
@@ -401,7 +401,7 @@ static int read_relas(struct elf *elf)
        return 0;
 }
 
-struct elf *elf_open(const char *name, int flags)
+struct elf *elf_read(const char *name, int flags)
 {
        struct elf *elf;
        Elf_Cmd cmd;
@@ -463,7 +463,7 @@ struct section *elf_create_section(struct elf *elf, const char *name,
 {
        struct section *sec, *shstrtab;
        size_t size = entsize * nr;
-       struct Elf_Scn *s;
+       Elf_Scn *s;
        Elf_Data *data;
 
        sec = malloc(sizeof(*sec));
index e44ca5d..4415020 100644 (file)
@@ -57,11 +57,12 @@ struct rela {
        struct list_head list;
        struct hlist_node hash;
        GElf_Rela rela;
-       struct section *rela_sec;
+       struct section *sec;
        struct symbol *sym;
        unsigned int type;
        unsigned long offset;
        int addend;
+       bool jump_table_start;
 };
 
 struct elf {
@@ -74,7 +75,7 @@ struct elf {
 };
 
 
-struct elf *elf_open(const char *name, int flags);
+struct elf *elf_read(const char *name, int flags);
 struct section *find_section_by_name(struct elf *elf, const char *name);
 struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset);
 struct symbol *find_symbol_by_name(struct elf *elf, const char *name);
index b6866a0..ed3ecfa 100644 (file)
@@ -194,12 +194,13 @@ PROBE ARGUMENT
 --------------
 Each probe argument follows below syntax.
 
- [NAME=]LOCALVAR|$retval|%REG|@SYMBOL[:TYPE]
+ [NAME=]LOCALVAR|$retval|%REG|@SYMBOL[:TYPE][@user]
 
 'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), local array with fixed index (e.g. array[1], var->array[0], var->pointer[2]), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.)
 '$vars' and '$params' special arguments are also available for NAME, '$vars' is expanded to the local variables (including function parameters) which can access at given probe point. '$params' is expanded to only the function parameters.
 'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo (*). Currently, basic types (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal integers (x/x8/x16/x32/x64), signedness casting (u/s), "string" and bitfield are supported. (see TYPES for detail)
 On x86 systems %REG is always the short form of the register: for example %AX. %RAX or %EAX is not valid.
+"@user" is a special attribute which means the LOCALVAR will be treated as a user-space memory. This is only valid for kprobe event.
 
 TYPES
 -----
index 7936708..8f24865 100644 (file)
@@ -2289,6 +2289,12 @@ static int process_switch_event(struct perf_tool *tool,
        if (perf_event__process_switch(tool, event, sample, machine) < 0)
                return -1;
 
+       if (scripting_ops && scripting_ops->process_switch)
+               scripting_ops->process_switch(event, sample, machine);
+
+       if (!script->show_switch_events)
+               return 0;
+
        thread = machine__findnew_thread(machine, sample->pid,
                                         sample->tid);
        if (thread == NULL) {
@@ -2467,7 +2473,7 @@ static int __cmd_script(struct perf_script *script)
                script->tool.mmap = process_mmap_event;
                script->tool.mmap2 = process_mmap2_event;
        }
-       if (script->show_switch_events)
+       if (script->show_switch_events || (scripting_ops && scripting_ops->process_switch))
                script->tool.context_switch = process_switch_event;
        if (script->show_namespace_events)
                script->tool.namespaces = process_namespaces_event;
index 1aa2ed0..4f0bbff 100644 (file)
@@ -19,6 +19,7 @@
 #include <api/fs/tracing_path.h>
 #include <bpf/bpf.h>
 #include "util/bpf_map.h"
+#include "util/rlimit.h"
 #include "builtin.h"
 #include "util/cgroup.h"
 #include "util/color.h"
@@ -3864,6 +3865,15 @@ int cmd_trace(int argc, const char **argv)
                goto out;
        }
 
+       /*
+        * Parsing .perfconfig may entail creating a BPF event, that may need
+        * to create BPF maps, so bump RLIM_MEMLOCK as the default 64K setting
+        * is too small. This affects just this process, not touching the
+        * global setting. If it fails we'll get something in 'perf trace -v'
+        * to help diagnose the problem.
+        */
+       rlimit__bump_memlock();
+
        err = perf_config(trace__config, &trace);
        if (err)
                goto out;
index f470144..bf114ca 100644 (file)
@@ -19,6 +19,7 @@ static struct version version;
 static struct option version_options[] = {
        OPT_BOOLEAN(0, "build-options", &version.build_options,
                    "display the build options"),
+       OPT_END(),
 };
 
 static const char * const version_usage[] = {
diff --git a/tools/perf/pmu-events/arch/s390/cf_m8561/basic.json b/tools/perf/pmu-events/arch/s390/cf_m8561/basic.json
new file mode 100644 (file)
index 0000000..17fb524
--- /dev/null
@@ -0,0 +1,58 @@
+[
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "0",
+               "EventName": "CPU_CYCLES",
+               "BriefDescription": "CPU Cycles",
+               "PublicDescription": "Cycle Count"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "1",
+               "EventName": "INSTRUCTIONS",
+               "BriefDescription": "Instructions",
+               "PublicDescription": "Instruction Count"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "2",
+               "EventName": "L1I_DIR_WRITES",
+               "BriefDescription": "L1I Directory Writes",
+               "PublicDescription": "Level-1 I-Cache Directory Write Count"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "3",
+               "EventName": "L1I_PENALTY_CYCLES",
+               "BriefDescription": "L1I Penalty Cycles",
+               "PublicDescription": "Level-1 I-Cache Penalty Cycle Count"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "4",
+               "EventName": "L1D_DIR_WRITES",
+               "BriefDescription": "L1D Directory Writes",
+               "PublicDescription": "Level-1 D-Cache Directory Write Count"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "5",
+               "EventName": "L1D_PENALTY_CYCLES",
+               "BriefDescription": "L1D Penalty Cycles",
+               "PublicDescription": "Level-1 D-Cache Penalty Cycle Count"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "32",
+               "EventName": "PROBLEM_STATE_CPU_CYCLES",
+               "BriefDescription": "Problem-State CPU Cycles",
+               "PublicDescription": "Problem-State Cycle Count"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "33",
+               "EventName": "PROBLEM_STATE_INSTRUCTIONS",
+               "BriefDescription": "Problem-State Instructions",
+               "PublicDescription": "Problem-State Instruction Count"
+       },
+]
diff --git a/tools/perf/pmu-events/arch/s390/cf_m8561/crypto.json b/tools/perf/pmu-events/arch/s390/cf_m8561/crypto.json
new file mode 100644 (file)
index 0000000..db286f1
--- /dev/null
@@ -0,0 +1,114 @@
+[
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "64",
+               "EventName": "PRNG_FUNCTIONS",
+               "BriefDescription": "PRNG Functions",
+               "PublicDescription": "Total number of the PRNG functions issued by the CPU"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "65",
+               "EventName": "PRNG_CYCLES",
+               "BriefDescription": "PRNG Cycles",
+               "PublicDescription": "Total number of CPU cycles when the DEA/AES coprocessor is busy performing PRNG functions issued by the CPU"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "66",
+               "EventName": "PRNG_BLOCKED_FUNCTIONS",
+               "BriefDescription": "PRNG Blocked Functions",
+               "PublicDescription": "Total number of the PRNG functions that are issued by the CPU and are blocked because the DEA/AES coprocessor is busy performing a function issued by another CPU"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "67",
+               "EventName": "PRNG_BLOCKED_CYCLES",
+               "BriefDescription": "PRNG Blocked Cycles",
+               "PublicDescription": "Total number of CPU cycles blocked for the PRNG functions issued by the CPU because the DEA/AES coprocessor is busy performing a function issued by another CPU"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "68",
+               "EventName": "SHA_FUNCTIONS",
+               "BriefDescription": "SHA Functions",
+               "PublicDescription": "Total number of SHA functions issued by the CPU"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "69",
+               "EventName": "SHA_CYCLES",
+               "BriefDescription": "SHA Cycles",
+               "PublicDescription": "Total number of CPU cycles when the SHA coprocessor is busy performing the SHA functions issued by the CPU"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "70",
+               "EventName": "SHA_BLOCKED_FUNCTIONS",
+               "BriefDescription": "SHA Blocked Functions",
+               "PublicDescription": "Total number of the SHA functions that are issued by the CPU and are blocked because the SHA coprocessor is busy performing a function issued by another CPU"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "71",
+               "EventName": "SHA_BLOCKED_CYCLES",
+               "BriefDescription": "SHA Bloced Cycles",
+               "PublicDescription": "Total number of CPU cycles blocked for the SHA functions issued by the CPU because the SHA coprocessor is busy performing a function issued by another CPU"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "72",
+               "EventName": "DEA_FUNCTIONS",
+               "BriefDescription": "DEA Functions",
+               "PublicDescription": "Total number of the DEA functions issued by the CPU"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "73",
+               "EventName": "DEA_CYCLES",
+               "BriefDescription": "DEA Cycles",
+               "PublicDescription": "Total number of CPU cycles when the DEA/AES coprocessor is busy performing the DEA functions issued by the CPU"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "74",
+               "EventName": "DEA_BLOCKED_FUNCTIONS",
+               "BriefDescription": "DEA Blocked Functions",
+               "PublicDescription": "Total number of the DEA functions that are issued by the CPU and are blocked because the DEA/AES coprocessor is busy performing a function issued by another CPU"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "75",
+               "EventName": "DEA_BLOCKED_CYCLES",
+               "BriefDescription": "DEA Blocked Cycles",
+               "PublicDescription": "Total number of CPU cycles blocked for the DEA functions issued by the CPU because the DEA/AES coprocessor is busy performing a function issued by another CPU"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "76",
+               "EventName": "AES_FUNCTIONS",
+               "BriefDescription": "AES Functions",
+               "PublicDescription": "Total number of AES functions issued by the CPU"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "77",
+               "EventName": "AES_CYCLES",
+               "BriefDescription": "AES Cycles",
+               "PublicDescription": "Total number of CPU cycles when the DEA/AES coprocessor is busy performing the AES functions issued by the CPU"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "78",
+               "EventName": "AES_BLOCKED_FUNCTIONS",
+               "BriefDescription": "AES Blocked Functions",
+               "PublicDescription": "Total number of AES functions that are issued by the CPU and are blocked because the DEA/AES coprocessor is busy performing a function issued by another CPU"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "79",
+               "EventName": "AES_BLOCKED_CYCLES",
+               "BriefDescription": "AES Blocked Cycles",
+               "PublicDescription": "Total number of CPU cycles blocked for the AES functions issued by the CPU because the DEA/AES coprocessor is busy performing a function issued by another CPU"
+       },
+]
diff --git a/tools/perf/pmu-events/arch/s390/cf_m8561/crypto6.json b/tools/perf/pmu-events/arch/s390/cf_m8561/crypto6.json
new file mode 100644 (file)
index 0000000..5e36bc2
--- /dev/null
@@ -0,0 +1,30 @@
+[
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "80",
+               "EventName": "ECC_FUNCTION_COUNT",
+               "BriefDescription": "ECC Function Count",
+               "PublicDescription": "Long ECC function Count"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "81",
+               "EventName": "ECC_CYCLES_COUNT",
+               "BriefDescription": "ECC Cycles Count",
+               "PublicDescription": "Long ECC Function cycles count"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "82",
+               "EventName": "ECC_BLOCKED_FUNCTION_COUNT",
+               "BriefDescription": "Ecc Blocked Function Count",
+               "PublicDescription": "Long ECC blocked function count"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "83",
+               "EventName": "ECC_BLOCKED_CYCLES_COUNT",
+               "BriefDescription": "ECC Blocked Cycles Count",
+               "PublicDescription": "Long ECC blocked cycles count"
+       },
+]
diff --git a/tools/perf/pmu-events/arch/s390/cf_m8561/extended.json b/tools/perf/pmu-events/arch/s390/cf_m8561/extended.json
new file mode 100644 (file)
index 0000000..89e0707
--- /dev/null
@@ -0,0 +1,373 @@
+[
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "128",
+               "EventName": "L1D_RO_EXCL_WRITES",
+               "BriefDescription": "L1D Read-only Exclusive Writes",
+               "PublicDescription": "A directory write to the Level-1 Data cache where the line was originally in a Read-Only state in the cache but has been updated to be in the Exclusive state that allows stores to the cache line"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "129",
+               "EventName": "DTLB2_WRITES",
+               "BriefDescription": "DTLB2 Writes",
+               "PublicDescription": "A translation has been written into The Translation Lookaside Buffer 2 (TLB2) and the request was made by the data cache"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "130",
+               "EventName": "DTLB2_MISSES",
+               "BriefDescription": "DTLB2 Misses",
+               "PublicDescription": "A TLB2 miss is in progress for a request made by the data cache. Incremented by one for every TLB2 miss in progress for the Level-1 Data cache on this cycle"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "131",
+               "EventName": "DTLB2_HPAGE_WRITES",
+               "BriefDescription": "DTLB2 One-Megabyte Page Writes",
+               "PublicDescription": "A translation entry was written into the Combined Region and Segment Table Entry array in the Level-2 TLB for a one-megabyte page or a Last Host Translation was done"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "132",
+               "EventName": "DTLB2_GPAGE_WRITES",
+               "BriefDescription": "DTLB2 Two-Gigabyte Page Writes",
+               "PublicDescription": "A translation entry for a two-gigabyte page was written into the Level-2 TLB"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "133",
+               "EventName": "L1D_L2D_SOURCED_WRITES",
+               "BriefDescription": "L1D L2D Sourced Writes",
+               "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from the Level-2 Data cache"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "134",
+               "EventName": "ITLB2_WRITES",
+               "BriefDescription": "ITLB2 Writes",
+               "PublicDescription": "A translation entry has been written into the Translation Lookaside Buffer 2 (TLB2) and the request was made by the instruction cache"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "135",
+               "EventName": "ITLB2_MISSES",
+               "BriefDescription": "ITLB2 Misses",
+               "PublicDescription": "A TLB2 miss is in progress for a request made by the instruction cache. Incremented by one for every TLB2 miss in progress for the Level-1 Instruction cache in a cycle"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "136",
+               "EventName": "L1I_L2I_SOURCED_WRITES",
+               "BriefDescription": "L1I L2I Sourced Writes",
+               "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from the Level-2 Instruction cache"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "137",
+               "EventName": "TLB2_PTE_WRITES",
+               "BriefDescription": "TLB2 PTE Writes",
+               "PublicDescription": "A translation entry was written into the Page Table Entry array in the Level-2 TLB"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "138",
+               "EventName": "TLB2_CRSTE_WRITES",
+               "BriefDescription": "TLB2 CRSTE Writes",
+               "PublicDescription": "Translation entries were written into the Combined Region and Segment Table Entry array and the Page Table Entry array in the Level-2 TLB"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "139",
+               "EventName": "TLB2_ENGINES_BUSY",
+               "BriefDescription": "TLB2 Engines Busy",
+               "PublicDescription": "The number of Level-2 TLB translation engines busy in a cycle"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "140",
+               "EventName": "TX_C_TEND",
+               "BriefDescription": "Completed TEND instructions in constrained TX mode",
+               "PublicDescription": "A TEND instruction has completed in a constrained transactional-execution mode"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "141",
+               "EventName": "TX_NC_TEND",
+               "BriefDescription": "Completed TEND instructions in non-constrained TX mode",
+               "PublicDescription": "A TEND instruction has completed in a non-constrained transactional-execution mode"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "143",
+               "EventName": "L1C_TLB2_MISSES",
+               "BriefDescription": "L1C TLB2 Misses",
+               "PublicDescription": "Increments by one for any cycle where a level-1 cache or level-2 TLB miss is in progress"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "144",
+               "EventName": "L1D_ONCHIP_L3_SOURCED_WRITES",
+               "BriefDescription": "L1D On-Chip L3 Sourced Writes",
+               "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an On-Chip Level-3 cache without intervention"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "145",
+               "EventName": "L1D_ONCHIP_MEMORY_SOURCED_WRITES",
+               "BriefDescription": "L1D On-Chip Memory Sourced Writes",
+               "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from On-Chip memory"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "146",
+               "EventName": "L1D_ONCHIP_L3_SOURCED_WRITES_IV",
+               "BriefDescription": "L1D On-Chip L3 Sourced Writes with Intervention",
+               "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an On-Chip Level-3 cache with intervention"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "147",
+               "EventName": "L1D_ONCLUSTER_L3_SOURCED_WRITES",
+               "BriefDescription": "L1D On-Cluster L3 Sourced Writes",
+               "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from On-Cluster Level-3 cache withountervention"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "148",
+               "EventName": "L1D_ONCLUSTER_MEMORY_SOURCED_WRITES",
+               "BriefDescription": "L1D On-Cluster Memory Sourced Writes",
+               "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an On-Cluster memory"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "149",
+               "EventName": "L1D_ONCLUSTER_L3_SOURCED_WRITES_IV",
+               "BriefDescription": "L1D On-Cluster L3 Sourced Writes with Intervention",
+               "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an On-Cluster Level-3 cache with intervention"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "150",
+               "EventName": "L1D_OFFCLUSTER_L3_SOURCED_WRITES",
+               "BriefDescription": "L1D Off-Cluster L3 Sourced Writes",
+               "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an Off-Cluster Level-3 cache without intervention"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "151",
+               "EventName": "L1D_OFFCLUSTER_MEMORY_SOURCED_WRITES",
+               "BriefDescription": "L1D Off-Cluster Memory Sourced Writes",
+               "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from Off-Cluster memory"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "152",
+               "EventName": "L1D_OFFCLUSTER_L3_SOURCED_WRITES_IV",
+               "BriefDescription": "L1D Off-Cluster L3 Sourced Writes with Intervention",
+               "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an Off-Cluster Level-3 cache with intervention"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "153",
+               "EventName": "L1D_OFFDRAWER_L3_SOURCED_WRITES",
+               "BriefDescription": "L1D Off-Drawer L3 Sourced Writes",
+               "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an Off-Drawer Level-3 cache without intervention"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "154",
+               "EventName": "L1D_OFFDRAWER_MEMORY_SOURCED_WRITES",
+               "BriefDescription": "L1D Off-Drawer Memory Sourced Writes",
+               "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from Off-Drawer memory"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "155",
+               "EventName": "L1D_OFFDRAWER_L3_SOURCED_WRITES_IV",
+               "BriefDescription": "L1D Off-Drawer L3 Sourced Writes with Intervention",
+               "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an Off-Drawer Level-3 cache with intervention"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "156",
+               "EventName": "L1D_ONDRAWER_L4_SOURCED_WRITES",
+               "BriefDescription": "L1D On-Drawer L4 Sourced Writes",
+               "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from On-Drawer Level-4 cache"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "157",
+               "EventName": "L1D_OFFDRAWER_L4_SOURCED_WRITES",
+               "BriefDescription": "L1D Off-Drawer L4 Sourced Writes",
+               "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from Off-Drawer Level-4 cache"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "158",
+               "EventName": "L1D_ONCHIP_L3_SOURCED_WRITES_RO",
+               "BriefDescription": "L1D On-Chip L3 Sourced Writes read-only",
+               "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from On-Chip L3 but a read-only invalidate was done to remove other copies of the cache line"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "162",
+               "EventName": "L1I_ONCHIP_L3_SOURCED_WRITES",
+               "BriefDescription": "L1I On-Chip L3 Sourced Writes",
+               "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache ine was sourced from an On-Chip Level-3 cache without intervention"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "163",
+               "EventName": "L1I_ONCHIP_MEMORY_SOURCED_WRITES",
+               "BriefDescription": "L1I On-Chip Memory Sourced Writes",
+               "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache ine was sourced from On-Chip memory"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "164",
+               "EventName": "L1I_ONCHIP_L3_SOURCED_WRITES_IV",
+               "BriefDescription": "L1I On-Chip L3 Sourced Writes with Intervention",
+               "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache ine was sourced from an On-Chip Level-3 cache with intervention"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "165",
+               "EventName": "L1I_ONCLUSTER_L3_SOURCED_WRITES",
+               "BriefDescription": "L1I On-Cluster L3 Sourced Writes",
+               "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an On-Cluster Level-3 cache without intervention"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "166",
+               "EventName": "L1I_ONCLUSTER_MEMORY_SOURCED_WRITES",
+               "BriefDescription": "L1I On-Cluster Memory Sourced Writes",
+               "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an On-Cluster memory"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "167",
+               "EventName": "L1I_ONCLUSTER_L3_SOURCED_WRITES_IV",
+               "BriefDescription": "L1I On-Cluster L3 Sourced Writes with Intervention",
+               "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from On-Cluster Level-3 cache with intervention"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "168",
+               "EventName": "L1I_OFFCLUSTER_L3_SOURCED_WRITES",
+               "BriefDescription": "L1I Off-Cluster L3 Sourced Writes",
+               "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an Off-Cluster Level-3 cache without intervention"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "169",
+               "EventName": "L1I_OFFCLUSTER_MEMORY_SOURCED_WRITES",
+               "BriefDescription": "L1I Off-Cluster Memory Sourced Writes",
+               "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from Off-Cluster memory"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "170",
+               "EventName": "L1I_OFFCLUSTER_L3_SOURCED_WRITES_IV",
+               "BriefDescription": "L1I Off-Cluster L3 Sourced Writes with Intervention",
+               "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an Off-Cluster Level-3 cache with intervention"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "171",
+               "EventName": "L1I_OFFDRAWER_L3_SOURCED_WRITES",
+               "BriefDescription": "L1I Off-Drawer L3 Sourced Writes",
+               "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an Off-Drawer Level-3 cache without intervention"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "172",
+               "EventName": "L1I_OFFDRAWER_MEMORY_SOURCED_WRITES",
+               "BriefDescription": "L1I Off-Drawer Memory Sourced Writes",
+               "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from Off-Drawer memory"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "173",
+               "EventName": "L1I_OFFDRAWER_L3_SOURCED_WRITES_IV",
+               "BriefDescription": "L1I Off-Drawer L3 Sourced Writes with Intervention",
+               "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an Off-Drawer Level-3 cache with intervention"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "174",
+               "EventName": "L1I_ONDRAWER_L4_SOURCED_WRITES",
+               "BriefDescription": "L1I On-Drawer L4 Sourced Writes",
+               "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from On-Drawer Level-4 cache"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "175",
+               "EventName": "L1I_OFFDRAWER_L4_SOURCED_WRITES",
+               "BriefDescription": "L1I Off-Drawer L4 Sourced Writes",
+               "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from Off-Drawer Level-4 cache"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "224",
+               "EventName": "BCD_DFP_EXECUTION_SLOTS",
+               "BriefDescription": "BCD DFP Execution Slots",
+               "PublicDescription": "Count of floating point execution slots used for finished Binary Coded Decimal to Decimal Floating Point conversions. Instructions: CDZT, CXZT, CZDT, CZXT"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "225",
+               "EventName": "VX_BCD_EXECUTION_SLOTS",
+               "BriefDescription": "VX BCD Execution Slots",
+               "PublicDescription": "Count of floating point execution slots used for finished vector arithmetic Binary Coded Decimal instructions. Instructions: VAP, VSP, VMPVMSP, VDP, VSDP, VRP, VLIP, VSRP, VPSOPVCP, VTP, VPKZ, VUPKZ, VCVB, VCVBG, VCVDVCVDG"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "226",
+               "EventName": "DECIMAL_INSTRUCTIONS",
+               "BriefDescription": "Decimal Instructions",
+               "PublicDescription": "Decimal instructions dispatched. Instructions: CVB, CVD, AP, CP, DP, ED, EDMK, MP, SRP, SP, ZAP"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "232",
+               "EventName": "LAST_HOST_TRANSLATIONS",
+               "BriefDescription": "Last host translation done",
+               "PublicDescription": "Last Host Translation done"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "243",
+               "EventName": "TX_NC_TABORT",
+               "BriefDescription": "Aborted transactions in non-constrained TX mode",
+               "PublicDescription": "A transaction abort has occurred in a non-constrained transactional-execution mode"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "244",
+               "EventName": "TX_C_TABORT_NO_SPECIAL",
+               "BriefDescription": "Aborted transactions in constrained TX mode not using special completion logic",
+               "PublicDescription": "A transaction abort has occurred in a constrained transactional-execution mode and the CPU is not using any special logic to allow the transaction to complete"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "245",
+               "EventName": "TX_C_TABORT_SPECIAL",
+               "BriefDescription": "Aborted transactions in constrained TX mode using special completion logic",
+               "PublicDescription": "A transaction abort has occurred in a constrained transactional-execution mode and the CPU is using special logic to allow the transaction to complete"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "448",
+               "EventName": "MT_DIAG_CYCLES_ONE_THR_ACTIVE",
+               "BriefDescription": "Cycle count with one thread active",
+               "PublicDescription": "Cycle count with one thread active"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "449",
+               "EventName": "MT_DIAG_CYCLES_TWO_THR_ACTIVE",
+               "BriefDescription": "Cycle count with two threads active",
+               "PublicDescription": "Cycle count with two threads active"
+       },
+]
index 78bcf7f..bd3fc57 100644 (file)
@@ -4,3 +4,4 @@ Family-model,Version,Filename,EventType
 ^IBM.282[78].*[13]\.[1-5].[[:xdigit:]]+$,1,cf_zec12,core
 ^IBM.296[45].*[13]\.[1-5].[[:xdigit:]]+$,1,cf_z13,core
 ^IBM.390[67].*[13]\.[1-5].[[:xdigit:]]+$,3,cf_z14,core
+^IBM.856[12].*3\.6.[[:xdigit:]]+$,3,cf_m8561,core
index 92713d9..7bd73a9 100644 (file)
@@ -353,7 +353,10 @@ do_query(query, 'CREATE TABLE threads ('
                'tid            integer)')
 do_query(query, 'CREATE TABLE comms ('
                'id             bigint          NOT NULL,'
-               'comm           varchar(16))')
+               'comm           varchar(16),'
+               'c_thread_id    bigint,'
+               'c_time         bigint,'
+               'exec_flag      boolean)')
 do_query(query, 'CREATE TABLE comm_threads ('
                'id             bigint          NOT NULL,'
                'comm_id        bigint,'
@@ -479,6 +482,17 @@ do_query(query, 'CREATE TABLE pwrx ('
        'last_cstate    integer,'
        'wake_reason    integer)')
 
+do_query(query, 'CREATE TABLE context_switches ('
+               'id             bigint          NOT NULL,'
+               'machine_id     bigint,'
+               'time           bigint,'
+               'cpu            integer,'
+               'thread_out_id  bigint,'
+               'comm_out_id    bigint,'
+               'thread_in_id   bigint,'
+               'comm_in_id     bigint,'
+               'flags          integer)')
+
 do_query(query, 'CREATE VIEW machines_view AS '
        'SELECT '
                'id,'
@@ -692,6 +706,29 @@ do_query(query, 'CREATE VIEW power_events_view AS '
        ' INNER JOIN selected_events ON selected_events.id = samples.evsel_id'
        ' ORDER BY samples.id')
 
+do_query(query, 'CREATE VIEW context_switches_view AS '
+       'SELECT '
+               'context_switches.id,'
+               'context_switches.machine_id,'
+               'context_switches.time,'
+               'context_switches.cpu,'
+               'th_out.pid AS pid_out,'
+               'th_out.tid AS tid_out,'
+               'comm_out.comm AS comm_out,'
+               'th_in.pid AS pid_in,'
+               'th_in.tid AS tid_in,'
+               'comm_in.comm AS comm_in,'
+               'CASE     WHEN context_switches.flags = 0 THEN \'in\''
+                       ' WHEN context_switches.flags = 1 THEN \'out\''
+                       ' WHEN context_switches.flags = 3 THEN \'out preempt\''
+                       ' ELSE CAST ( context_switches.flags AS VARCHAR(11) )'
+               'END AS flags'
+       ' FROM context_switches'
+       ' INNER JOIN threads AS th_out ON th_out.id   = context_switches.thread_out_id'
+       ' INNER JOIN threads AS th_in  ON th_in.id    = context_switches.thread_in_id'
+       ' INNER JOIN comms AS comm_out ON comm_out.id = context_switches.comm_out_id'
+       ' INNER JOIN comms AS comm_in  ON comm_in.id  = context_switches.comm_in_id')
+
 file_header = struct.pack("!11sii", b"PGCOPY\n\377\r\n\0", 0, 0)
 file_trailer = b"\377\377"
 
@@ -756,6 +793,7 @@ mwait_file          = open_output_file("mwait_table.bin")
 pwre_file              = open_output_file("pwre_table.bin")
 exstop_file            = open_output_file("exstop_table.bin")
 pwrx_file              = open_output_file("pwrx_table.bin")
+context_switches_file  = open_output_file("context_switches_table.bin")
 
 def trace_begin():
        printdate("Writing to intermediate files...")
@@ -763,7 +801,7 @@ def trace_begin():
        evsel_table(0, "unknown")
        machine_table(0, 0, "unknown")
        thread_table(0, 0, 0, -1, -1)
-       comm_table(0, "unknown")
+       comm_table(0, "unknown", 0, 0, 0)
        dso_table(0, 0, "unknown", "unknown", "")
        symbol_table(0, 0, 0, 0, 0, "unknown")
        sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
@@ -804,6 +842,7 @@ def trace_end():
        copy_output_file(pwre_file,             "pwre")
        copy_output_file(exstop_file,           "exstop")
        copy_output_file(pwrx_file,             "pwrx")
+       copy_output_file(context_switches_file, "context_switches")
 
        printdate("Removing intermediate files...")
        remove_output_file(evsel_file)
@@ -825,6 +864,7 @@ def trace_end():
        remove_output_file(pwre_file)
        remove_output_file(exstop_file)
        remove_output_file(pwrx_file)
+       remove_output_file(context_switches_file)
        os.rmdir(output_dir_name)
        printdate("Adding primary keys")
        do_query(query, 'ALTER TABLE selected_events ADD PRIMARY KEY (id)')
@@ -846,11 +886,14 @@ def trace_end():
        do_query(query, 'ALTER TABLE pwre            ADD PRIMARY KEY (id)')
        do_query(query, 'ALTER TABLE exstop          ADD PRIMARY KEY (id)')
        do_query(query, 'ALTER TABLE pwrx            ADD PRIMARY KEY (id)')
+       do_query(query, 'ALTER TABLE context_switches ADD PRIMARY KEY (id)')
 
        printdate("Adding foreign keys")
        do_query(query, 'ALTER TABLE threads '
                                        'ADD CONSTRAINT machinefk  FOREIGN KEY (machine_id)   REFERENCES machines   (id),'
                                        'ADD CONSTRAINT processfk  FOREIGN KEY (process_id)   REFERENCES threads    (id)')
+       do_query(query, 'ALTER TABLE comms '
+                                       'ADD CONSTRAINT threadfk   FOREIGN KEY (c_thread_id)  REFERENCES threads    (id)')
        do_query(query, 'ALTER TABLE comm_threads '
                                        'ADD CONSTRAINT commfk     FOREIGN KEY (comm_id)      REFERENCES comms      (id),'
                                        'ADD CONSTRAINT threadfk   FOREIGN KEY (thread_id)    REFERENCES threads    (id)')
@@ -881,6 +924,8 @@ def trace_end():
                                        'ADD CONSTRAINT parent_call_pathfk FOREIGN KEY (parent_call_path_id) REFERENCES call_paths (id)')
                do_query(query, 'CREATE INDEX pcpid_idx ON calls (parent_call_path_id)')
                do_query(query, 'CREATE INDEX pid_idx ON calls (parent_id)')
+               do_query(query, 'ALTER TABLE comms ADD has_calls boolean')
+               do_query(query, 'UPDATE comms SET has_calls = TRUE WHERE comms.id IN (SELECT DISTINCT comm_id FROM calls)')
        do_query(query, 'ALTER TABLE ptwrite '
                                        'ADD CONSTRAINT idfk        FOREIGN KEY (id)           REFERENCES samples   (id)')
        do_query(query, 'ALTER TABLE  cbr '
@@ -893,6 +938,12 @@ def trace_end():
                                        'ADD CONSTRAINT idfk        FOREIGN KEY (id)           REFERENCES samples   (id)')
        do_query(query, 'ALTER TABLE  pwrx '
                                        'ADD CONSTRAINT idfk        FOREIGN KEY (id)           REFERENCES samples   (id)')
+       do_query(query, 'ALTER TABLE  context_switches '
+                                       'ADD CONSTRAINT machinefk   FOREIGN KEY (machine_id)    REFERENCES machines (id),'
+                                       'ADD CONSTRAINT toutfk      FOREIGN KEY (thread_out_id) REFERENCES threads  (id),'
+                                       'ADD CONSTRAINT tinfk       FOREIGN KEY (thread_in_id)  REFERENCES threads  (id),'
+                                       'ADD CONSTRAINT coutfk      FOREIGN KEY (comm_out_id)   REFERENCES comms    (id),'
+                                       'ADD CONSTRAINT cinfk       FOREIGN KEY (comm_in_id)    REFERENCES comms    (id)')
 
        printdate("Dropping unused tables")
        if is_table_empty("ptwrite"):
@@ -905,6 +956,8 @@ def trace_end():
                drop("pwrx")
                if is_table_empty("cbr"):
                        drop("cbr")
+       if is_table_empty("context_switches"):
+               drop("context_switches")
 
        if (unhandled_count):
                printdate("Warning: ", unhandled_count, " unhandled events")
@@ -935,11 +988,11 @@ def thread_table(thread_id, machine_id, process_id, pid, tid, *x):
        value = struct.pack("!hiqiqiqiiii", 5, 8, thread_id, 8, machine_id, 8, process_id, 4, pid, 4, tid)
        thread_file.write(value)
 
-def comm_table(comm_id, comm_str, *x):
+def comm_table(comm_id, comm_str, thread_id, time, exec_flag, *x):
        comm_str = toserverstr(comm_str)
        n = len(comm_str)
-       fmt = "!hiqi" + str(n) + "s"
-       value = struct.pack(fmt, 2, 8, comm_id, n, comm_str)
+       fmt = "!hiqi" + str(n) + "s" + "iqiqiB"
+       value = struct.pack(fmt, 5, 8, comm_id, n, comm_str, 8, thread_id, 8, time, 1, exec_flag)
        comm_file.write(value)
 
 def comm_thread_table(comm_thread_id, comm_id, thread_id, *x):
@@ -1051,3 +1104,8 @@ def synth_data(id, config, raw_buf, *x):
                pwrx(id, raw_buf)
        elif config == 5:
                cbr(id, raw_buf)
+
+def context_switch_table(id, machine_id, time, cpu, thread_out_id, comm_out_id, thread_in_id, comm_in_id, flags, *x):
+       fmt = "!hiqiqiqiiiqiqiqiqii"
+       value = struct.pack(fmt, 9, 8, id, 8, machine_id, 8, time, 4, cpu, 8, thread_out_id, 8, comm_out_id, 8, thread_in_id, 8, comm_in_id, 4, flags)
+       context_switches_file.write(value)
index 021326c..8043a72 100644 (file)
@@ -177,7 +177,10 @@ do_query(query, 'CREATE TABLE threads ('
                'tid            integer)')
 do_query(query, 'CREATE TABLE comms ('
                'id             integer         NOT NULL        PRIMARY KEY,'
-               'comm           varchar(16))')
+               'comm           varchar(16),'
+               'c_thread_id    bigint,'
+               'c_time         bigint,'
+               'exec_flag      boolean)')
 do_query(query, 'CREATE TABLE comm_threads ('
                'id             integer         NOT NULL        PRIMARY KEY,'
                'comm_id        bigint,'
@@ -303,6 +306,17 @@ do_query(query, 'CREATE TABLE pwrx ('
                'last_cstate    integer,'
                'wake_reason    integer)')
 
+do_query(query, 'CREATE TABLE context_switches ('
+               'id             integer         NOT NULL        PRIMARY KEY,'
+               'machine_id     bigint,'
+               'time           bigint,'
+               'cpu            integer,'
+               'thread_out_id  bigint,'
+               'comm_out_id    bigint,'
+               'thread_in_id   bigint,'
+               'comm_in_id     bigint,'
+               'flags          integer)')
+
 # printf was added to sqlite in version 3.8.3
 sqlite_has_printf = False
 try:
@@ -527,6 +541,29 @@ do_query(query, 'CREATE VIEW power_events_view AS '
        ' INNER JOIN selected_events ON selected_events.id = evsel_id'
        ' WHERE selected_events.name IN (\'cbr\',\'mwait\',\'exstop\',\'pwre\',\'pwrx\')')
 
+do_query(query, 'CREATE VIEW context_switches_view AS '
+       'SELECT '
+               'context_switches.id,'
+               'context_switches.machine_id,'
+               'context_switches.time,'
+               'context_switches.cpu,'
+               'th_out.pid AS pid_out,'
+               'th_out.tid AS tid_out,'
+               'comm_out.comm AS comm_out,'
+               'th_in.pid AS pid_in,'
+               'th_in.tid AS tid_in,'
+               'comm_in.comm AS comm_in,'
+               'CASE     WHEN context_switches.flags = 0 THEN \'in\''
+                       ' WHEN context_switches.flags = 1 THEN \'out\''
+                       ' WHEN context_switches.flags = 3 THEN \'out preempt\''
+                       ' ELSE context_switches.flags '
+               'END AS flags'
+       ' FROM context_switches'
+       ' INNER JOIN threads AS th_out ON th_out.id   = context_switches.thread_out_id'
+       ' INNER JOIN threads AS th_in  ON th_in.id    = context_switches.thread_in_id'
+       ' INNER JOIN comms AS comm_out ON comm_out.id = context_switches.comm_out_id'
+       ' INNER JOIN comms AS comm_in  ON comm_in.id  = context_switches.comm_in_id')
+
 do_query(query, 'END TRANSACTION')
 
 evsel_query = QSqlQuery(db)
@@ -536,7 +573,7 @@ machine_query.prepare("INSERT INTO machines VALUES (?, ?, ?)")
 thread_query = QSqlQuery(db)
 thread_query.prepare("INSERT INTO threads VALUES (?, ?, ?, ?, ?)")
 comm_query = QSqlQuery(db)
-comm_query.prepare("INSERT INTO comms VALUES (?, ?)")
+comm_query.prepare("INSERT INTO comms VALUES (?, ?, ?, ?, ?)")
 comm_thread_query = QSqlQuery(db)
 comm_thread_query.prepare("INSERT INTO comm_threads VALUES (?, ?, ?)")
 dso_query = QSqlQuery(db)
@@ -568,6 +605,8 @@ exstop_query = QSqlQuery(db)
 exstop_query.prepare("INSERT INTO exstop VALUES (?, ?)")
 pwrx_query = QSqlQuery(db)
 pwrx_query.prepare("INSERT INTO pwrx VALUES (?, ?, ?, ?)")
+context_switch_query = QSqlQuery(db)
+context_switch_query.prepare("INSERT INTO context_switches VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)")
 
 def trace_begin():
        printdate("Writing records...")
@@ -576,7 +615,7 @@ def trace_begin():
        evsel_table(0, "unknown")
        machine_table(0, 0, "unknown")
        thread_table(0, 0, 0, -1, -1)
-       comm_table(0, "unknown")
+       comm_table(0, "unknown", 0, 0, 0)
        dso_table(0, 0, "unknown", "unknown", "")
        symbol_table(0, 0, 0, 0, 0, "unknown")
        sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
@@ -603,6 +642,8 @@ def trace_end():
        if perf_db_export_calls:
                do_query(query, 'CREATE INDEX pcpid_idx ON calls (parent_call_path_id)')
                do_query(query, 'CREATE INDEX pid_idx ON calls (parent_id)')
+               do_query(query, 'ALTER TABLE comms ADD has_calls boolean')
+               do_query(query, 'UPDATE comms SET has_calls = 1 WHERE comms.id IN (SELECT DISTINCT comm_id FROM calls)')
 
        printdate("Dropping unused tables")
        if is_table_empty("ptwrite"):
@@ -615,6 +656,8 @@ def trace_end():
                drop("pwrx")
                if is_table_empty("cbr"):
                        drop("cbr")
+       if is_table_empty("context_switches"):
+               drop("context_switches")
 
        if (unhandled_count):
                printdate("Warning: ", unhandled_count, " unhandled events")
@@ -642,7 +685,7 @@ def thread_table(*x):
        bind_exec(thread_query, 5, x)
 
 def comm_table(*x):
-       bind_exec(comm_query, 2, x)
+       bind_exec(comm_query, 5, x)
 
 def comm_thread_table(*x):
        bind_exec(comm_thread_query, 3, x)
@@ -748,3 +791,6 @@ def synth_data(id, config, raw_buf, *x):
                pwrx(id, raw_buf)
        elif config == 5:
                cbr(id, raw_buf)
+
+def context_switch_table(*x):
+       bind_exec(context_switch_query, 9, x)
index 6e7934f..61b3911 100755 (executable)
@@ -392,7 +392,7 @@ class FindBar():
                self.hbox.addWidget(self.close_button)
 
                self.bar = QWidget()
-               self.bar.setLayout(self.hbox);
+               self.bar.setLayout(self.hbox)
                self.bar.hide()
 
        def Widget(self):
@@ -470,7 +470,7 @@ class CallGraphLevelItemBase(object):
                self.params = params
                self.row = row
                self.parent_item = parent_item
-               self.query_done = False;
+               self.query_done = False
                self.child_count = 0
                self.child_items = []
                if parent_item:
@@ -517,7 +517,7 @@ class CallGraphLevelTwoPlusItemBase(CallGraphLevelItemBase):
                self.time = time
 
        def Select(self):
-               self.query_done = True;
+               self.query_done = True
                query = QSqlQuery(self.glb.db)
                if self.params.have_ipc:
                        ipc_str = ", SUM(insn_count), SUM(cyc_count)"
@@ -604,7 +604,7 @@ class CallGraphLevelOneItem(CallGraphLevelItemBase):
                self.dbid = comm_id
 
        def Select(self):
-               self.query_done = True;
+               self.query_done = True
                query = QSqlQuery(self.glb.db)
                QueryExec(query, "SELECT thread_id, pid, tid"
                                        " FROM comm_threads"
@@ -622,9 +622,12 @@ class CallGraphRootItem(CallGraphLevelItemBase):
        def __init__(self, glb, params):
                super(CallGraphRootItem, self).__init__(glb, params, 0, None)
                self.dbid = 0
-               self.query_done = True;
+               self.query_done = True
+               if_has_calls = ""
+               if IsSelectable(glb.db, "comms", columns = "has_calls"):
+                       if_has_calls = " WHERE has_calls = TRUE"
                query = QSqlQuery(glb.db)
-               QueryExec(query, "SELECT id, comm FROM comms")
+               QueryExec(query, "SELECT id, comm FROM comms" + if_has_calls)
                while query.next():
                        if not query.value(0):
                                continue
@@ -793,7 +796,7 @@ class CallTreeLevelTwoPlusItemBase(CallGraphLevelItemBase):
                self.time = time
 
        def Select(self):
-               self.query_done = True;
+               self.query_done = True
                if self.calls_id == 0:
                        comm_thread = " AND comm_id = " + str(self.comm_id) + " AND thread_id = " + str(self.thread_id)
                else:
@@ -881,7 +884,7 @@ class CallTreeLevelOneItem(CallGraphLevelItemBase):
                self.dbid = comm_id
 
        def Select(self):
-               self.query_done = True;
+               self.query_done = True
                query = QSqlQuery(self.glb.db)
                QueryExec(query, "SELECT thread_id, pid, tid"
                                        " FROM comm_threads"
@@ -899,9 +902,12 @@ class CallTreeRootItem(CallGraphLevelItemBase):
        def __init__(self, glb, params):
                super(CallTreeRootItem, self).__init__(glb, params, 0, None)
                self.dbid = 0
-               self.query_done = True;
+               self.query_done = True
+               if_has_calls = ""
+               if IsSelectable(glb.db, "comms", columns = "has_calls"):
+                       if_has_calls = " WHERE has_calls = TRUE"
                query = QSqlQuery(glb.db)
-               QueryExec(query, "SELECT id, comm FROM comms")
+               QueryExec(query, "SELECT id, comm FROM comms" + if_has_calls)
                while query.next():
                        if not query.value(0):
                                continue
@@ -971,7 +977,7 @@ class VBox():
 
        def __init__(self, w1, w2, w3=None):
                self.vbox = QWidget()
-               self.vbox.setLayout(QVBoxLayout());
+               self.vbox.setLayout(QVBoxLayout())
 
                self.vbox.layout().setContentsMargins(0, 0, 0, 0)
 
@@ -1391,7 +1397,7 @@ class FetchMoreRecordsBar():
                self.hbox.addWidget(self.close_button)
 
                self.bar = QWidget()
-               self.bar.setLayout(self.hbox);
+               self.bar.setLayout(self.hbox)
                self.bar.show()
 
                self.in_progress = False
@@ -2206,7 +2212,7 @@ class ReportDialogBase(QDialog):
                self.vbox.addLayout(self.grid)
                self.vbox.addLayout(self.hbox)
 
-               self.setLayout(self.vbox);
+               self.setLayout(self.vbox)
 
        def Ok(self):
                vars = self.report_vars
@@ -3139,7 +3145,7 @@ class AboutDialog(QDialog):
                self.vbox = QVBoxLayout()
                self.vbox.addWidget(self.text)
 
-               self.setLayout(self.vbox);
+               self.setLayout(self.vbox)
 
 # Font resize
 
index 66a82ba..c3bec9d 100644 (file)
@@ -21,6 +21,7 @@
 #include <subcmd/parse-options.h>
 #include "string2.h"
 #include "symbol.h"
+#include "util/rlimit.h"
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <subcmd/exec-cmd.h>
@@ -727,6 +728,11 @@ int cmd_test(int argc, const char **argv)
 
        if (skip != NULL)
                skiplist = intlist__new(skip);
+       /*
+        * Tests that create BPF maps, for instance, need more than the 64K
+        * default:
+        */
+       rlimit__bump_memlock();
 
        return __cmd_test(argc, argv, skiplist);
 }
index d7e3b00..14f812b 100644 (file)
@@ -20,6 +20,7 @@ perf-y += parse-events.o
 perf-y += perf_regs.o
 perf-y += path.o
 perf-y += print_binary.o
+perf-y += rlimit.o
 perf-y += argv_split.o
 perf-y += rbtree.o
 perf-y += libstring.o
index 67b88b5..3d1c34f 100644 (file)
@@ -2460,7 +2460,7 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
 
                /* Something went wrong, no need to continue */
                if (!inode) {
-                       err = PTR_ERR(inode);
+                       err = -ENOMEM;
                        goto err_free_metadata;
                }
 
@@ -2517,8 +2517,10 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
        session->auxtrace = &etm->auxtrace;
 
        etm->unknown_thread = thread__new(999999999, 999999999);
-       if (!etm->unknown_thread)
+       if (!etm->unknown_thread) {
+               err = -ENOMEM;
                goto err_free_queues;
+       }
 
        /*
         * Initialize list node so that at thread__zput() we can avoid
@@ -2530,8 +2532,10 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
        if (err)
                goto err_delete_thread;
 
-       if (thread__init_map_groups(etm->unknown_thread, etm->machine))
+       if (thread__init_map_groups(etm->unknown_thread, etm->machine)) {
+               err = -ENOMEM;
                goto err_delete_thread;
+       }
 
        if (dump_trace) {
                cs_etm__print_auxtrace_info(auxtrace_info->priv, num_cpu);
@@ -2575,5 +2579,5 @@ err_free_traceid_list:
 err_free_hdr:
        zfree(&hdr);
 
-       return -EINVAL;
+       return err;
 }
index 2394c75..ffbb3e7 100644 (file)
 #include "db-export.h"
 #include <linux/zalloc.h>
 
-struct deferred_export {
-       struct list_head node;
-       struct comm *comm;
-};
-
-static int db_export__deferred(struct db_export *dbe)
-{
-       struct deferred_export *de;
-       int err;
-
-       while (!list_empty(&dbe->deferred)) {
-               de = list_entry(dbe->deferred.next, struct deferred_export,
-                               node);
-               err = dbe->export_comm(dbe, de->comm);
-               list_del_init(&de->node);
-               free(de);
-               if (err)
-                       return err;
-       }
-
-       return 0;
-}
-
-static void db_export__free_deferred(struct db_export *dbe)
-{
-       struct deferred_export *de;
-
-       while (!list_empty(&dbe->deferred)) {
-               de = list_entry(dbe->deferred.next, struct deferred_export,
-                               node);
-               list_del_init(&de->node);
-               free(de);
-       }
-}
-
-static int db_export__defer_comm(struct db_export *dbe, struct comm *comm)
-{
-       struct deferred_export *de;
-
-       de = zalloc(sizeof(struct deferred_export));
-       if (!de)
-               return -ENOMEM;
-
-       de->comm = comm;
-       list_add_tail(&de->node, &dbe->deferred);
-
-       return 0;
-}
-
 int db_export__init(struct db_export *dbe)
 {
        memset(dbe, 0, sizeof(struct db_export));
-       INIT_LIST_HEAD(&dbe->deferred);
        return 0;
 }
 
-int db_export__flush(struct db_export *dbe)
-{
-       return db_export__deferred(dbe);
-}
-
 void db_export__exit(struct db_export *dbe)
 {
-       db_export__free_deferred(dbe);
        call_return_processor__free(dbe->crp);
        dbe->crp = NULL;
 }
@@ -115,71 +59,73 @@ int db_export__machine(struct db_export *dbe, struct machine *machine)
 }
 
 int db_export__thread(struct db_export *dbe, struct thread *thread,
-                     struct machine *machine, struct comm *comm)
+                     struct machine *machine, struct thread *main_thread)
 {
-       struct thread *main_thread;
        u64 main_thread_db_id = 0;
-       int err;
 
        if (thread->db_id)
                return 0;
 
        thread->db_id = ++dbe->thread_last_db_id;
 
-       if (thread->pid_ != -1) {
-               if (thread->pid_ == thread->tid) {
-                       main_thread = thread;
-               } else {
-                       main_thread = machine__findnew_thread(machine,
-                                                             thread->pid_,
-                                                             thread->pid_);
-                       if (!main_thread)
-                               return -ENOMEM;
-                       err = db_export__thread(dbe, main_thread, machine,
-                                               comm);
-                       if (err)
-                               goto out_put;
-                       if (comm) {
-                               err = db_export__comm_thread(dbe, comm, thread);
-                               if (err)
-                                       goto out_put;
-                       }
-               }
+       if (main_thread)
                main_thread_db_id = main_thread->db_id;
-               if (main_thread != thread)
-                       thread__put(main_thread);
-       }
 
        if (dbe->export_thread)
                return dbe->export_thread(dbe, thread, main_thread_db_id,
                                          machine);
 
        return 0;
+}
 
-out_put:
-       thread__put(main_thread);
-       return err;
+static int __db_export__comm(struct db_export *dbe, struct comm *comm,
+                            struct thread *thread)
+{
+       comm->db_id = ++dbe->comm_last_db_id;
+
+       if (dbe->export_comm)
+               return dbe->export_comm(dbe, comm, thread);
+
+       return 0;
 }
 
 int db_export__comm(struct db_export *dbe, struct comm *comm,
-                   struct thread *main_thread)
+                   struct thread *thread)
+{
+       if (comm->db_id)
+               return 0;
+
+       return __db_export__comm(dbe, comm, thread);
+}
+
+/*
+ * Export the "exec" comm. The "exec" comm is the program / application command
+ * name at the time it first executes. It is used to group threads for the same
+ * program. Note that the main thread pid (or thread group id tgid) cannot be
+ * used because it does not change when a new program is exec'ed.
+ */
+int db_export__exec_comm(struct db_export *dbe, struct comm *comm,
+                        struct thread *main_thread)
 {
        int err;
 
        if (comm->db_id)
                return 0;
 
-       comm->db_id = ++dbe->comm_last_db_id;
-
-       if (dbe->export_comm) {
-               if (main_thread->comm_set)
-                       err = dbe->export_comm(dbe, comm);
-               else
-                       err = db_export__defer_comm(dbe, comm);
-               if (err)
-                       return err;
-       }
+       err = __db_export__comm(dbe, comm, main_thread);
+       if (err)
+               return err;
 
+       /*
+        * Record the main thread for this comm. Note that the main thread can
+        * have many "exec" comms because there will be a new one every time it
+        * exec's. An "exec" comm however will only ever have 1 main thread.
+        * That is different to any other threads for that same program because
+        * exec() will effectively kill them, so the relationship between the
+        * "exec" comm and non-main threads is 1-to-1. That is why
+        * db_export__comm_thread() is called here for the main thread, but it
+        * is called for non-main threads when they are exported.
+        */
        return db_export__comm_thread(dbe, comm, main_thread);
 }
 
@@ -340,11 +286,65 @@ int db_export__branch_type(struct db_export *dbe, u32 branch_type,
        return 0;
 }
 
+static int db_export__threads(struct db_export *dbe, struct thread *thread,
+                             struct thread *main_thread,
+                             struct machine *machine, struct comm **comm_ptr)
+{
+       struct comm *comm = NULL;
+       struct comm *curr_comm;
+       int err;
+
+       if (main_thread) {
+               /*
+                * A thread has a reference to the main thread, so export the
+                * main thread first.
+                */
+               err = db_export__thread(dbe, main_thread, machine, main_thread);
+               if (err)
+                       return err;
+               /*
+                * Export comm before exporting the non-main thread because
+                * db_export__comm_thread() can be called further below.
+                */
+               comm = machine__thread_exec_comm(machine, main_thread);
+               if (comm) {
+                       err = db_export__exec_comm(dbe, comm, main_thread);
+                       if (err)
+                               return err;
+                       *comm_ptr = comm;
+               }
+       }
+
+       if (thread != main_thread) {
+               /*
+                * For a non-main thread, db_export__comm_thread() must be
+                * called only if thread has not previously been exported.
+                */
+               bool export_comm_thread = comm && !thread->db_id;
+
+               err = db_export__thread(dbe, thread, machine, main_thread);
+               if (err)
+                       return err;
+
+               if (export_comm_thread) {
+                       err = db_export__comm_thread(dbe, comm, thread);
+                       if (err)
+                               return err;
+               }
+       }
+
+       curr_comm = thread__comm(thread);
+       if (curr_comm)
+               return db_export__comm(dbe, curr_comm, thread);
+
+       return 0;
+}
+
 int db_export__sample(struct db_export *dbe, union perf_event *event,
                      struct perf_sample *sample, struct perf_evsel *evsel,
                      struct addr_location *al)
 {
-       struct threadthread = al->thread;
+       struct thread *thread = al->thread;
        struct export_sample es = {
                .event = event,
                .sample = sample,
@@ -364,19 +364,13 @@ int db_export__sample(struct db_export *dbe, union perf_event *event,
                return err;
 
        main_thread = thread__main_thread(al->machine, thread);
-       if (main_thread)
-               comm = machine__thread_exec_comm(al->machine, main_thread);
 
-       err = db_export__thread(dbe, thread, al->machine, comm);
+       err = db_export__threads(dbe, thread, main_thread, al->machine, &comm);
        if (err)
                goto out_put;
 
-       if (comm) {
-               err = db_export__comm(dbe, comm, main_thread);
-               if (err)
-                       goto out_put;
+       if (comm)
                es.comm_db_id = comm->db_id;
-       }
 
        es.db_id = ++dbe->sample_last_db_id;
 
@@ -525,3 +519,92 @@ int db_export__call_return(struct db_export *dbe, struct call_return *cr,
 
        return 0;
 }
+
+static int db_export__pid_tid(struct db_export *dbe, struct machine *machine,
+                             pid_t pid, pid_t tid, u64 *db_id,
+                             struct comm **comm_ptr, bool *is_idle)
+{
+       struct thread *thread = machine__find_thread(machine, pid, tid);
+       struct thread *main_thread;
+       int err = 0;
+
+       if (!thread || !thread->comm_set)
+               goto out_put;
+
+       *is_idle = !thread->pid_ && !thread->tid;
+
+       main_thread = thread__main_thread(machine, thread);
+
+       err = db_export__threads(dbe, thread, main_thread, machine, comm_ptr);
+
+       *db_id = thread->db_id;
+
+       thread__put(main_thread);
+out_put:
+       thread__put(thread);
+
+       return err;
+}
+
+int db_export__switch(struct db_export *dbe, union perf_event *event,
+                     struct perf_sample *sample, struct machine *machine)
+{
+       bool out = event->header.misc & PERF_RECORD_MISC_SWITCH_OUT;
+       bool out_preempt = out &&
+               (event->header.misc & PERF_RECORD_MISC_SWITCH_OUT_PREEMPT);
+       int flags = out | (out_preempt << 1);
+       bool is_idle_a = false, is_idle_b = false;
+       u64 th_a_id = 0, th_b_id = 0;
+       u64 comm_out_id, comm_in_id;
+       struct comm *comm_a = NULL;
+       struct comm *comm_b = NULL;
+       u64 th_out_id, th_in_id;
+       u64 db_id;
+       int err;
+
+       err = db_export__machine(dbe, machine);
+       if (err)
+               return err;
+
+       err = db_export__pid_tid(dbe, machine, sample->pid, sample->tid,
+                                &th_a_id, &comm_a, &is_idle_a);
+       if (err)
+               return err;
+
+       if (event->header.type == PERF_RECORD_SWITCH_CPU_WIDE) {
+               pid_t pid = event->context_switch.next_prev_pid;
+               pid_t tid = event->context_switch.next_prev_tid;
+
+               err = db_export__pid_tid(dbe, machine, pid, tid, &th_b_id,
+                                        &comm_b, &is_idle_b);
+               if (err)
+                       return err;
+       }
+
+       /*
+        * Do not export if both threads are unknown (i.e. not being traced),
+        * or one is unknown and the other is the idle task.
+        */
+       if ((!th_a_id || is_idle_a) && (!th_b_id || is_idle_b))
+               return 0;
+
+       db_id = ++dbe->context_switch_last_db_id;
+
+       if (out) {
+               th_out_id   = th_a_id;
+               th_in_id    = th_b_id;
+               comm_out_id = comm_a ? comm_a->db_id : 0;
+               comm_in_id  = comm_b ? comm_b->db_id : 0;
+       } else {
+               th_out_id   = th_b_id;
+               th_in_id    = th_a_id;
+               comm_out_id = comm_b ? comm_b->db_id : 0;
+               comm_in_id  = comm_a ? comm_a->db_id : 0;
+       }
+
+       if (dbe->export_context_switch)
+               return dbe->export_context_switch(dbe, db_id, machine, sample,
+                                                 th_out_id, comm_out_id,
+                                                 th_in_id, comm_in_id, flags);
+       return 0;
+}
index e8a6402..ba1f62a 100644 (file)
@@ -43,7 +43,8 @@ struct db_export {
        int (*export_machine)(struct db_export *dbe, struct machine *machine);
        int (*export_thread)(struct db_export *dbe, struct thread *thread,
                             u64 main_thread_db_id, struct machine *machine);
-       int (*export_comm)(struct db_export *dbe, struct comm *comm);
+       int (*export_comm)(struct db_export *dbe, struct comm *comm,
+                          struct thread *thread);
        int (*export_comm_thread)(struct db_export *dbe, u64 db_id,
                                  struct comm *comm, struct thread *thread);
        int (*export_dso)(struct db_export *dbe, struct dso *dso,
@@ -56,6 +57,11 @@ struct db_export {
        int (*export_call_path)(struct db_export *dbe, struct call_path *cp);
        int (*export_call_return)(struct db_export *dbe,
                                  struct call_return *cr);
+       int (*export_context_switch)(struct db_export *dbe, u64 db_id,
+                                    struct machine *machine,
+                                    struct perf_sample *sample,
+                                    u64 th_out_id, u64 comm_out_id,
+                                    u64 th_in_id, u64 comm_in_id, int flags);
        struct call_return_processor *crp;
        struct call_path_root *cpr;
        u64 evsel_last_db_id;
@@ -68,18 +74,19 @@ struct db_export {
        u64 sample_last_db_id;
        u64 call_path_last_db_id;
        u64 call_return_last_db_id;
-       struct list_head deferred;
+       u64 context_switch_last_db_id;
 };
 
 int db_export__init(struct db_export *dbe);
-int db_export__flush(struct db_export *dbe);
 void db_export__exit(struct db_export *dbe);
 int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel);
 int db_export__machine(struct db_export *dbe, struct machine *machine);
 int db_export__thread(struct db_export *dbe, struct thread *thread,
-                     struct machine *machine, struct comm *comm);
+                     struct machine *machine, struct thread *main_thread);
 int db_export__comm(struct db_export *dbe, struct comm *comm,
-                   struct thread *main_thread);
+                   struct thread *thread);
+int db_export__exec_comm(struct db_export *dbe, struct comm *comm,
+                        struct thread *main_thread);
 int db_export__comm_thread(struct db_export *dbe, struct comm *comm,
                           struct thread *thread);
 int db_export__dso(struct db_export *dbe, struct dso *dso,
@@ -97,5 +104,7 @@ int db_export__branch_types(struct db_export *dbe);
 int db_export__call_path(struct db_export *dbe, struct call_path *cp);
 int db_export__call_return(struct db_export *dbe, struct call_return *cr,
                           u64 *parent_db_id);
+int db_export__switch(struct db_export *dbe, union perf_event *event,
+                     struct perf_sample *sample, struct machine *machine);
 
 #endif
index 0c3b55d..cd1eb73 100644 (file)
@@ -1562,6 +1562,17 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
                str = tmp + 1;
        }
 
+       tmp = strchr(str, '@');
+       if (tmp && tmp != str && strcmp(tmp + 1, "user")) { /* user attr */
+               if (!user_access_is_supported()) {
+                       semantic_error("ftrace does not support user access\n");
+                       return -EINVAL;
+               }
+               *tmp = '\0';
+               arg->user_access = true;
+               pr_debug("user_access ");
+       }
+
        tmp = strchr(str, ':');
        if (tmp) {      /* Type setting */
                *tmp = '\0';
index 05c8d57..96a319c 100644 (file)
@@ -37,6 +37,7 @@ struct probe_trace_point {
 struct probe_trace_arg_ref {
        struct probe_trace_arg_ref      *next;  /* Next reference */
        long                            offset; /* Offset value */
+       bool                            user_access;    /* User-memory access */
 };
 
 /* kprobe-tracer and uprobe-tracer tracing argument */
@@ -82,6 +83,7 @@ struct perf_probe_arg {
        char                            *var;   /* Variable name */
        char                            *type;  /* Type name */
        struct perf_probe_arg_field     *field; /* Structure fields */
+       bool                            user_access;    /* User-memory access */
 };
 
 /* Perf probe probing event (point + arg) */
index c2998f9..5b4d493 100644 (file)
@@ -1005,6 +1005,7 @@ enum ftrace_readme {
        FTRACE_README_PROBE_TYPE_X = 0,
        FTRACE_README_KRETPROBE_OFFSET,
        FTRACE_README_UPROBE_REF_CTR,
+       FTRACE_README_USER_ACCESS,
        FTRACE_README_END,
 };
 
@@ -1017,6 +1018,7 @@ static struct {
        DEFINE_TYPE(FTRACE_README_PROBE_TYPE_X, "*type: * x8/16/32/64,*"),
        DEFINE_TYPE(FTRACE_README_KRETPROBE_OFFSET, "*place (kretprobe): *"),
        DEFINE_TYPE(FTRACE_README_UPROBE_REF_CTR, "*ref_ctr_offset*"),
+       DEFINE_TYPE(FTRACE_README_USER_ACCESS, "*[u]<offset>*"),
 };
 
 static bool scan_ftrace_readme(enum ftrace_readme type)
@@ -1077,3 +1079,8 @@ bool uprobe_ref_ctr_is_supported(void)
 {
        return scan_ftrace_readme(FTRACE_README_UPROBE_REF_CTR);
 }
+
+bool user_access_is_supported(void)
+{
+       return scan_ftrace_readme(FTRACE_README_USER_ACCESS);
+}
index 2a24918..986c1c9 100644 (file)
@@ -70,6 +70,7 @@ int probe_cache__show_all_caches(struct strfilter *filter);
 bool probe_type_is_available(enum probe_type type);
 bool kretprobe_offset_is_supported(void);
 bool uprobe_ref_ctr_is_supported(void);
+bool user_access_is_supported(void);
 #else  /* ! HAVE_LIBELF_SUPPORT */
 static inline struct probe_cache *probe_cache__new(const char *tgt __maybe_unused, struct nsinfo *nsi __maybe_unused)
 {
index 7d8c997..025fc44 100644 (file)
@@ -280,7 +280,7 @@ static_var:
 
 static int convert_variable_type(Dwarf_Die *vr_die,
                                 struct probe_trace_arg *tvar,
-                                const char *cast)
+                                const char *cast, bool user_access)
 {
        struct probe_trace_arg_ref **ref_ptr = &tvar->ref;
        Dwarf_Die type;
@@ -320,7 +320,8 @@ static int convert_variable_type(Dwarf_Die *vr_die,
        pr_debug("%s type is %s.\n",
                 dwarf_diename(vr_die), dwarf_diename(&type));
 
-       if (cast && strcmp(cast, "string") == 0) {      /* String type */
+       if (cast && (!strcmp(cast, "string") || !strcmp(cast, "ustring"))) {
+               /* String type */
                ret = dwarf_tag(&type);
                if (ret != DW_TAG_pointer_type &&
                    ret != DW_TAG_array_type) {
@@ -343,6 +344,7 @@ static int convert_variable_type(Dwarf_Die *vr_die,
                                pr_warning("Out of memory error\n");
                                return -ENOMEM;
                        }
+                       (*ref_ptr)->user_access = user_access;
                }
                if (!die_compare_name(&type, "char") &&
                    !die_compare_name(&type, "unsigned char")) {
@@ -397,7 +399,7 @@ formatted:
 static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
                                    struct perf_probe_arg_field *field,
                                    struct probe_trace_arg_ref **ref_ptr,
-                                   Dwarf_Die *die_mem)
+                                   Dwarf_Die *die_mem, bool user_access)
 {
        struct probe_trace_arg_ref *ref = *ref_ptr;
        Dwarf_Die type;
@@ -434,6 +436,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
                                *ref_ptr = ref;
                }
                ref->offset += dwarf_bytesize(&type) * field->index;
+               ref->user_access = user_access;
                goto next;
        } else if (tag == DW_TAG_pointer_type) {
                /* Check the pointer and dereference */
@@ -505,17 +508,18 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
                }
        }
        ref->offset += (long)offs;
+       ref->user_access = user_access;
 
        /* If this member is unnamed, we need to reuse this field */
        if (!dwarf_diename(die_mem))
                return convert_variable_fields(die_mem, varname, field,
-                                               &ref, die_mem);
+                                               &ref, die_mem, user_access);
 
 next:
        /* Converting next field */
        if (field->next)
                return convert_variable_fields(die_mem, field->name,
-                                       field->next, &ref, die_mem);
+                               field->next, &ref, die_mem, user_access);
        else
                return 0;
 }
@@ -541,11 +545,12 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
        else if (ret == 0 && pf->pvar->field) {
                ret = convert_variable_fields(vr_die, pf->pvar->var,
                                              pf->pvar->field, &pf->tvar->ref,
-                                             &die_mem);
+                                             &die_mem, pf->pvar->user_access);
                vr_die = &die_mem;
        }
        if (ret == 0)
-               ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type);
+               ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type,
+                                           pf->pvar->user_access);
        /* *expr will be cached in libdw. Don't free it. */
        return ret;
 }
diff --git a/tools/perf/util/rlimit.c b/tools/perf/util/rlimit.c
new file mode 100644 (file)
index 0000000..13521d3
--- /dev/null
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+
+#include "util/debug.h"
+#include "util/rlimit.h"
+#include <sys/time.h>
+#include <sys/resource.h>
+
+/*
+ * Bump the memlock so that we can get bpf maps of a reasonable size,
+ * like the ones used with 'perf trace' and with 'perf test bpf',
+ * improve this to some specific request if needed.
+ */
+void rlimit__bump_memlock(void)
+{
+       struct rlimit rlim;
+
+       if (getrlimit(RLIMIT_MEMLOCK, &rlim) == 0) {
+               rlim.rlim_cur *= 4;
+               rlim.rlim_max *= 4;
+
+               if (setrlimit(RLIMIT_MEMLOCK, &rlim) < 0) {
+                       rlim.rlim_cur /= 2;
+                       rlim.rlim_max /= 2;
+
+                       if (setrlimit(RLIMIT_MEMLOCK, &rlim) < 0)
+                               pr_debug("Couldn't bump rlimit(MEMLOCK), failures may take place when creating BPF maps, etc\n");
+               }
+       }
+}
diff --git a/tools/perf/util/rlimit.h b/tools/perf/util/rlimit.h
new file mode 100644 (file)
index 0000000..9f59d8e
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __PERF_RLIMIT_H_
+#define __PERF_RLIMIT_H_
+/* SPDX-License-Identifier: LGPL-2.1 */
+
+void rlimit__bump_memlock(void);
+#endif // __PERF_RLIMIT_H_
index 112bed6..25dc1d7 100644 (file)
@@ -113,6 +113,7 @@ struct tables {
        PyObject                *call_path_handler;
        PyObject                *call_return_handler;
        PyObject                *synth_handler;
+       PyObject                *context_switch_handler;
        bool                    db_export_mode;
 };
 
@@ -1011,15 +1012,19 @@ static int python_export_thread(struct db_export *dbe, struct thread *thread,
        return 0;
 }
 
-static int python_export_comm(struct db_export *dbe, struct comm *comm)
+static int python_export_comm(struct db_export *dbe, struct comm *comm,
+                             struct thread *thread)
 {
        struct tables *tables = container_of(dbe, struct tables, dbe);
        PyObject *t;
 
-       t = tuple_new(2);
+       t = tuple_new(5);
 
        tuple_set_u64(t, 0, comm->db_id);
        tuple_set_string(t, 1, comm__str(comm));
+       tuple_set_u64(t, 2, thread->db_id);
+       tuple_set_u64(t, 3, comm->start);
+       tuple_set_s32(t, 4, comm->exec);
 
        call_object(tables->comm_handler, t, "comm_table");
 
@@ -1233,6 +1238,34 @@ static int python_export_call_return(struct db_export *dbe,
        return 0;
 }
 
+static int python_export_context_switch(struct db_export *dbe, u64 db_id,
+                                       struct machine *machine,
+                                       struct perf_sample *sample,
+                                       u64 th_out_id, u64 comm_out_id,
+                                       u64 th_in_id, u64 comm_in_id, int flags)
+{
+       struct tables *tables = container_of(dbe, struct tables, dbe);
+       PyObject *t;
+
+       t = tuple_new(9);
+
+       tuple_set_u64(t, 0, db_id);
+       tuple_set_u64(t, 1, machine->db_id);
+       tuple_set_u64(t, 2, sample->time);
+       tuple_set_s32(t, 3, sample->cpu);
+       tuple_set_u64(t, 4, th_out_id);
+       tuple_set_u64(t, 5, comm_out_id);
+       tuple_set_u64(t, 6, th_in_id);
+       tuple_set_u64(t, 7, comm_in_id);
+       tuple_set_s32(t, 8, flags);
+
+       call_object(tables->context_switch_handler, t, "context_switch");
+
+       Py_DECREF(t);
+
+       return 0;
+}
+
 static int python_process_call_return(struct call_return *cr, u64 *parent_db_id,
                                      void *data)
 {
@@ -1296,6 +1329,16 @@ static void python_process_event(union perf_event *event,
        }
 }
 
+static void python_process_switch(union perf_event *event,
+                                 struct perf_sample *sample,
+                                 struct machine *machine)
+{
+       struct tables *tables = &tables_global;
+
+       if (tables->db_export_mode)
+               db_export__switch(&tables->dbe, event, sample, machine);
+}
+
 static void get_handler_name(char *str, size_t size,
                             struct perf_evsel *evsel)
 {
@@ -1511,6 +1554,7 @@ static void set_table_handlers(struct tables *tables)
        SET_TABLE_HANDLER(sample);
        SET_TABLE_HANDLER(call_path);
        SET_TABLE_HANDLER(call_return);
+       SET_TABLE_HANDLER(context_switch);
 
        /*
         * Synthesized events are samples but with architecture-specific data
@@ -1620,9 +1664,7 @@ error:
 
 static int python_flush_script(void)
 {
-       struct tables *tables = &tables_global;
-
-       return db_export__flush(&tables->dbe);
+       return 0;
 }
 
 /*
@@ -1831,6 +1873,7 @@ struct scripting_ops python_scripting_ops = {
        .flush_script           = python_flush_script,
        .stop_script            = python_stop_script,
        .process_event          = python_process_event,
+       .process_switch         = python_process_switch,
        .process_stat           = python_process_stat,
        .process_stat_interval  = python_process_stat_interval,
        .generate_script        = python_generate_script,
index d9b0a94..c7002fe 100644 (file)
@@ -81,6 +81,9 @@ struct scripting_ops {
                               struct perf_sample *sample,
                               struct perf_evsel *evsel,
                               struct addr_location *al);
+       void (*process_switch)(union perf_event *event,
+                              struct perf_sample *sample,
+                              struct machine *machine);
        void (*process_stat)(struct perf_stat_config *config,
                             struct perf_evsel *evsel, u64 tstamp);
        void (*process_stat_interval)(u64 tstamp);
index c23e5a6..7b5c436 100644 (file)
@@ -12,8 +12,8 @@ default:
        $(MAKE) -C $(KDIR) M=$(CURDIR)
 
 clean:
-       - rm -rf *.o *.ko .tmp-versions .*.cmd .*.mod.* *.mod.c
-       - rm -rf .tmp_versions* Module.symvers modules.order
+       - rm -rf *.o *.ko .*.cmd .*.mod.* *.mod.c
+       - rm -rf Module.symvers modules.order
 
 install: default
        install -d $(KMISC)
index 7252542..6fd8649 100755 (executable)
@@ -663,7 +663,7 @@ while ($#ARGV >= 0) {
     }
 
     else {
-       die "Unknow option $opt\n";
+       die "Unknown option $opt\n";
     }
 }
 
@@ -732,7 +732,7 @@ if ($start) {
        }
     }
     run_command "cp $good_start $good" or die "failed to copy to $good\n";
-    run_command "cp $bad_start $bad" or die "faield to copy to $bad\n";
+    run_command "cp $bad_start $bad" or die "failed to copy to $bad\n";
 } else {
     if ( ! -f $good ) {
        die "Can not find file $good\n";
index 2620406..11c9c62 100644 (file)
@@ -1,4 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
+include ../../../../scripts/Kbuild.include
+include ../../../scripts/Makefile.arch
 
 LIBDIR := ../../../lib
 BPFDIR := $(LIBDIR)/bpf
@@ -81,13 +83,14 @@ all: $(TEST_CUSTOM_PROGS)
 $(OUTPUT)/urandom_read: $(OUTPUT)/%: %.c
        $(CC) -o $@ $< -Wl,--build-id
 
-$(OUTPUT)/test_maps: map_tests/*.c
+$(OUTPUT)/test_stub.o: test_stub.c
+       $(CC) $(TEST_PROGS_CFLAGS) $(CFLAGS) -c -o $@ $<
 
 BPFOBJ := $(OUTPUT)/libbpf.a
 
-$(TEST_GEN_PROGS): test_stub.o $(BPFOBJ)
+$(TEST_GEN_PROGS): $(OUTPUT)/test_stub.o $(BPFOBJ)
 
-$(TEST_GEN_PROGS_EXTENDED): test_stub.o $(OUTPUT)/libbpf.a
+$(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/test_stub.o $(OUTPUT)/libbpf.a
 
 $(OUTPUT)/test_dev_cgroup: cgroup_helpers.c
 $(OUTPUT)/test_skb_cgroup_id_user: cgroup_helpers.c
@@ -138,7 +141,8 @@ CLANG_SYS_INCLUDES := $(shell $(CLANG) -v -E - </dev/null 2>&1 \
 
 CLANG_FLAGS = -I. -I./include/uapi -I../../../include/uapi \
              $(CLANG_SYS_INCLUDES) \
-             -Wno-compare-distinct-pointer-types
+             -Wno-compare-distinct-pointer-types \
+             -D__TARGET_ARCH_$(SRCARCH)
 
 $(OUTPUT)/test_l4lb_noinline.o: CLANG_FLAGS += -fno-inline
 $(OUTPUT)/test_xdp_noinline.o: CLANG_FLAGS += -fno-inline
@@ -172,6 +176,7 @@ endif
 endif
 
 TEST_PROGS_CFLAGS := -I. -I$(OUTPUT)
+TEST_MAPS_CFLAGS := -I. -I$(OUTPUT)
 TEST_VERIFIER_CFLAGS := -I. -I$(OUTPUT) -Iverifier
 
 ifneq ($(SUBREG_CODEGEN),)
@@ -180,12 +185,12 @@ TEST_CUSTOM_PROGS += $(ALU32_BUILD_DIR)/test_progs_32
 $(ALU32_BUILD_DIR):
        mkdir -p $@
 
-$(ALU32_BUILD_DIR)/urandom_read: $(OUTPUT)/urandom_read
+$(ALU32_BUILD_DIR)/urandom_read: $(OUTPUT)/urandom_read | $(ALU32_BUILD_DIR)
        cp $< $@
 
 $(ALU32_BUILD_DIR)/test_progs_32: test_progs.c $(OUTPUT)/libbpf.a\
-                                               $(ALU32_BUILD_DIR) \
-                                               $(ALU32_BUILD_DIR)/urandom_read
+                                               $(ALU32_BUILD_DIR)/urandom_read \
+                                               | $(ALU32_BUILD_DIR)
        $(CC) $(TEST_PROGS_CFLAGS) $(CFLAGS) \
                -o $(ALU32_BUILD_DIR)/test_progs_32 \
                test_progs.c test_stub.c trace_helpers.c prog_tests/*.c \
@@ -194,10 +199,10 @@ $(ALU32_BUILD_DIR)/test_progs_32: test_progs.c $(OUTPUT)/libbpf.a\
 $(ALU32_BUILD_DIR)/test_progs_32: $(PROG_TESTS_H)
 $(ALU32_BUILD_DIR)/test_progs_32: prog_tests/*.c
 
-$(ALU32_BUILD_DIR)/%.o: progs/%.c $(ALU32_BUILD_DIR) \
-                                       $(ALU32_BUILD_DIR)/test_progs_32
-       $(CLANG) $(CLANG_FLAGS) \
-                -O2 -target bpf -emit-llvm -c $< -o - |      \
+$(ALU32_BUILD_DIR)/%.o: progs/%.c $(ALU32_BUILD_DIR)/test_progs_32 \
+                                       | $(ALU32_BUILD_DIR)
+       ($(CLANG) $(CLANG_FLAGS) -O2 -target bpf -emit-llvm -c $< -o - || \
+               echo "clang failed") | \
        $(LLC) -march=bpf -mattr=+alu32 -mcpu=$(CPU) $(LLC_FLAGS) \
                -filetype=obj -o $@
 ifeq ($(DWARF2BTF),y)
@@ -208,32 +213,30 @@ endif
 # Have one program compiled without "-target bpf" to test whether libbpf loads
 # it successfully
 $(OUTPUT)/test_xdp.o: progs/test_xdp.c
-       $(CLANG) $(CLANG_FLAGS) \
-               -O2 -emit-llvm -c $< -o - | \
+       ($(CLANG) $(CLANG_FLAGS) -O2 -emit-llvm -c $< -o - || \
+               echo "clang failed") | \
        $(LLC) -march=bpf -mcpu=$(CPU) $(LLC_FLAGS) -filetype=obj -o $@
 ifeq ($(DWARF2BTF),y)
        $(BTF_PAHOLE) -J $@
 endif
 
 $(OUTPUT)/%.o: progs/%.c
-       $(CLANG) $(CLANG_FLAGS) \
-                -O2 -target bpf -emit-llvm -c $< -o - |      \
+       ($(CLANG) $(CLANG_FLAGS) -O2 -target bpf -emit-llvm -c $< -o - || \
+               echo "clang failed") | \
        $(LLC) -march=bpf -mcpu=$(CPU) $(LLC_FLAGS) -filetype=obj -o $@
 ifeq ($(DWARF2BTF),y)
        $(BTF_PAHOLE) -J $@
 endif
 
-PROG_TESTS_H := $(OUTPUT)/prog_tests/tests.h
-test_progs.c: $(PROG_TESTS_H)
-$(OUTPUT)/test_progs: CFLAGS += $(TEST_PROGS_CFLAGS)
-$(OUTPUT)/test_progs: prog_tests/*.c
-
 PROG_TESTS_DIR = $(OUTPUT)/prog_tests
 $(PROG_TESTS_DIR):
        mkdir -p $@
-
+PROG_TESTS_H := $(PROG_TESTS_DIR)/tests.h
 PROG_TESTS_FILES := $(wildcard prog_tests/*.c)
-$(PROG_TESTS_H): $(PROG_TESTS_DIR) $(PROG_TESTS_FILES)
+test_progs.c: $(PROG_TESTS_H)
+$(OUTPUT)/test_progs: CFLAGS += $(TEST_PROGS_CFLAGS)
+$(OUTPUT)/test_progs: test_progs.c $(PROG_TESTS_H) $(PROG_TESTS_FILES)
+$(PROG_TESTS_H): $(PROG_TESTS_FILES) | $(PROG_TESTS_DIR)
        $(shell ( cd prog_tests/; \
                  echo '/* Generated header, do not edit */'; \
                  echo '#ifdef DECLARE'; \
@@ -246,15 +249,15 @@ $(PROG_TESTS_H): $(PROG_TESTS_DIR) $(PROG_TESTS_FILES)
                  echo '#endif' \
                 ) > $(PROG_TESTS_H))
 
-TEST_MAPS_CFLAGS := -I. -I$(OUTPUT)
 MAP_TESTS_DIR = $(OUTPUT)/map_tests
 $(MAP_TESTS_DIR):
        mkdir -p $@
 MAP_TESTS_H := $(MAP_TESTS_DIR)/tests.h
+MAP_TESTS_FILES := $(wildcard map_tests/*.c)
 test_maps.c: $(MAP_TESTS_H)
 $(OUTPUT)/test_maps: CFLAGS += $(TEST_MAPS_CFLAGS)
-MAP_TESTS_FILES := $(wildcard map_tests/*.c)
-$(MAP_TESTS_H): $(MAP_TESTS_DIR) $(MAP_TESTS_FILES)
+$(OUTPUT)/test_maps: test_maps.c $(MAP_TESTS_H) $(MAP_TESTS_FILES)
+$(MAP_TESTS_H): $(MAP_TESTS_FILES) | $(MAP_TESTS_DIR)
        $(shell ( cd map_tests/; \
                  echo '/* Generated header, do not edit */'; \
                  echo '#ifdef DECLARE'; \
@@ -267,16 +270,15 @@ $(MAP_TESTS_H): $(MAP_TESTS_DIR) $(MAP_TESTS_FILES)
                  echo '#endif' \
                 ) > $(MAP_TESTS_H))
 
-VERIFIER_TESTS_H := $(OUTPUT)/verifier/tests.h
-test_verifier.c: $(VERIFIER_TESTS_H)
-$(OUTPUT)/test_verifier: CFLAGS += $(TEST_VERIFIER_CFLAGS)
-
 VERIFIER_TESTS_DIR = $(OUTPUT)/verifier
 $(VERIFIER_TESTS_DIR):
        mkdir -p $@
-
+VERIFIER_TESTS_H := $(VERIFIER_TESTS_DIR)/tests.h
 VERIFIER_TEST_FILES := $(wildcard verifier/*.c)
-$(OUTPUT)/verifier/tests.h: $(VERIFIER_TESTS_DIR) $(VERIFIER_TEST_FILES)
+test_verifier.c: $(VERIFIER_TESTS_H)
+$(OUTPUT)/test_verifier: CFLAGS += $(TEST_VERIFIER_CFLAGS)
+$(OUTPUT)/test_verifier: test_verifier.c $(VERIFIER_TESTS_H)
+$(VERIFIER_TESTS_H): $(VERIFIER_TEST_FILES) | $(VERIFIER_TESTS_DIR)
        $(shell ( cd verifier/; \
                  echo '/* Generated header, do not edit */'; \
                  echo '#ifdef FILL_ARRAY'; \
index 5a3d92c..f804f21 100644 (file)
@@ -315,8 +315,8 @@ static int (*bpf_skb_adjust_room)(void *ctx, __s32 len_diff, __u32 mode,
 #if defined(__TARGET_ARCH_x86)
        #define bpf_target_x86
        #define bpf_target_defined
-#elif defined(__TARGET_ARCH_s930x)
-       #define bpf_target_s930x
+#elif defined(__TARGET_ARCH_s390)
+       #define bpf_target_s390
        #define bpf_target_defined
 #elif defined(__TARGET_ARCH_arm)
        #define bpf_target_arm
@@ -341,8 +341,8 @@ static int (*bpf_skb_adjust_room)(void *ctx, __s32 len_diff, __u32 mode,
 #ifndef bpf_target_defined
 #if defined(__x86_64__)
        #define bpf_target_x86
-#elif defined(__s390x__)
-       #define bpf_target_s930x
+#elif defined(__s390__)
+       #define bpf_target_s390
 #elif defined(__arm__)
        #define bpf_target_arm
 #elif defined(__aarch64__)
@@ -358,6 +358,7 @@ static int (*bpf_skb_adjust_room)(void *ctx, __s32 len_diff, __u32 mode,
 
 #if defined(bpf_target_x86)
 
+#ifdef __KERNEL__
 #define PT_REGS_PARM1(x) ((x)->di)
 #define PT_REGS_PARM2(x) ((x)->si)
 #define PT_REGS_PARM3(x) ((x)->dx)
@@ -368,19 +369,49 @@ static int (*bpf_skb_adjust_room)(void *ctx, __s32 len_diff, __u32 mode,
 #define PT_REGS_RC(x) ((x)->ax)
 #define PT_REGS_SP(x) ((x)->sp)
 #define PT_REGS_IP(x) ((x)->ip)
+#else
+#ifdef __i386__
+/* i386 kernel is built with -mregparm=3 */
+#define PT_REGS_PARM1(x) ((x)->eax)
+#define PT_REGS_PARM2(x) ((x)->edx)
+#define PT_REGS_PARM3(x) ((x)->ecx)
+#define PT_REGS_PARM4(x) 0
+#define PT_REGS_PARM5(x) 0
+#define PT_REGS_RET(x) ((x)->esp)
+#define PT_REGS_FP(x) ((x)->ebp)
+#define PT_REGS_RC(x) ((x)->eax)
+#define PT_REGS_SP(x) ((x)->esp)
+#define PT_REGS_IP(x) ((x)->eip)
+#else
+#define PT_REGS_PARM1(x) ((x)->rdi)
+#define PT_REGS_PARM2(x) ((x)->rsi)
+#define PT_REGS_PARM3(x) ((x)->rdx)
+#define PT_REGS_PARM4(x) ((x)->rcx)
+#define PT_REGS_PARM5(x) ((x)->r8)
+#define PT_REGS_RET(x) ((x)->rsp)
+#define PT_REGS_FP(x) ((x)->rbp)
+#define PT_REGS_RC(x) ((x)->rax)
+#define PT_REGS_SP(x) ((x)->rsp)
+#define PT_REGS_IP(x) ((x)->rip)
+#endif
+#endif
 
-#elif defined(bpf_target_s390x)
+#elif defined(bpf_target_s390)
 
-#define PT_REGS_PARM1(x) ((x)->gprs[2])
-#define PT_REGS_PARM2(x) ((x)->gprs[3])
-#define PT_REGS_PARM3(x) ((x)->gprs[4])
-#define PT_REGS_PARM4(x) ((x)->gprs[5])
-#define PT_REGS_PARM5(x) ((x)->gprs[6])
-#define PT_REGS_RET(x) ((x)->gprs[14])
-#define PT_REGS_FP(x) ((x)->gprs[11]) /* Works only with CONFIG_FRAME_POINTER */
-#define PT_REGS_RC(x) ((x)->gprs[2])
-#define PT_REGS_SP(x) ((x)->gprs[15])
-#define PT_REGS_IP(x) ((x)->psw.addr)
+/* s390 provides user_pt_regs instead of struct pt_regs to userspace */
+struct pt_regs;
+#define PT_REGS_S390 const volatile user_pt_regs
+#define PT_REGS_PARM1(x) (((PT_REGS_S390 *)(x))->gprs[2])
+#define PT_REGS_PARM2(x) (((PT_REGS_S390 *)(x))->gprs[3])
+#define PT_REGS_PARM3(x) (((PT_REGS_S390 *)(x))->gprs[4])
+#define PT_REGS_PARM4(x) (((PT_REGS_S390 *)(x))->gprs[5])
+#define PT_REGS_PARM5(x) (((PT_REGS_S390 *)(x))->gprs[6])
+#define PT_REGS_RET(x) (((PT_REGS_S390 *)(x))->gprs[14])
+/* Works only with CONFIG_FRAME_POINTER */
+#define PT_REGS_FP(x) (((PT_REGS_S390 *)(x))->gprs[11])
+#define PT_REGS_RC(x) (((PT_REGS_S390 *)(x))->gprs[2])
+#define PT_REGS_SP(x) (((PT_REGS_S390 *)(x))->gprs[15])
+#define PT_REGS_IP(x) (((PT_REGS_S390 *)(x))->psw.addr)
 
 #elif defined(bpf_target_arm)
 
@@ -397,16 +428,20 @@ static int (*bpf_skb_adjust_room)(void *ctx, __s32 len_diff, __u32 mode,
 
 #elif defined(bpf_target_arm64)
 
-#define PT_REGS_PARM1(x) ((x)->regs[0])
-#define PT_REGS_PARM2(x) ((x)->regs[1])
-#define PT_REGS_PARM3(x) ((x)->regs[2])
-#define PT_REGS_PARM4(x) ((x)->regs[3])
-#define PT_REGS_PARM5(x) ((x)->regs[4])
-#define PT_REGS_RET(x) ((x)->regs[30])
-#define PT_REGS_FP(x) ((x)->regs[29]) /* Works only with CONFIG_FRAME_POINTER */
-#define PT_REGS_RC(x) ((x)->regs[0])
-#define PT_REGS_SP(x) ((x)->sp)
-#define PT_REGS_IP(x) ((x)->pc)
+/* arm64 provides struct user_pt_regs instead of struct pt_regs to userspace */
+struct pt_regs;
+#define PT_REGS_ARM64 const volatile struct user_pt_regs
+#define PT_REGS_PARM1(x) (((PT_REGS_ARM64 *)(x))->regs[0])
+#define PT_REGS_PARM2(x) (((PT_REGS_ARM64 *)(x))->regs[1])
+#define PT_REGS_PARM3(x) (((PT_REGS_ARM64 *)(x))->regs[2])
+#define PT_REGS_PARM4(x) (((PT_REGS_ARM64 *)(x))->regs[3])
+#define PT_REGS_PARM5(x) (((PT_REGS_ARM64 *)(x))->regs[4])
+#define PT_REGS_RET(x) (((PT_REGS_ARM64 *)(x))->regs[30])
+/* Works only with CONFIG_FRAME_POINTER */
+#define PT_REGS_FP(x) (((PT_REGS_ARM64 *)(x))->regs[29])
+#define PT_REGS_RC(x) (((PT_REGS_ARM64 *)(x))->regs[0])
+#define PT_REGS_SP(x) (((PT_REGS_ARM64 *)(x))->sp)
+#define PT_REGS_IP(x) (((PT_REGS_ARM64 *)(x))->pc)
 
 #elif defined(bpf_target_mips)
 
@@ -452,10 +487,10 @@ static int (*bpf_skb_adjust_room)(void *ctx, __s32 len_diff, __u32 mode,
 
 #endif
 
-#ifdef bpf_target_powerpc
+#if defined(bpf_target_powerpc)
 #define BPF_KPROBE_READ_RET_IP(ip, ctx)                ({ (ip) = (ctx)->link; })
 #define BPF_KRETPROBE_READ_RET_IP              BPF_KPROBE_READ_RET_IP
-#elif bpf_target_sparc
+#elif defined(bpf_target_sparc)
 #define BPF_KPROBE_READ_RET_IP(ip, ctx)                ({ (ip) = PT_REGS_RET(ctx); })
 #define BPF_KRETPROBE_READ_RET_IP              BPF_KPROBE_READ_RET_IP
 #else
index a468639..5ecc267 100644 (file)
@@ -21,12 +21,6 @@ ssize_t get_base_addr() {
        return -EINVAL;
 }
 
-#ifdef __x86_64__
-#define SYS_KPROBE_NAME "__x64_sys_nanosleep"
-#else
-#define SYS_KPROBE_NAME "sys_nanosleep"
-#endif
-
 void test_attach_probe(void)
 {
        const char *kprobe_name = "kprobe/sys_nanosleep";
@@ -84,7 +78,7 @@ void test_attach_probe(void)
 
        kprobe_link = bpf_program__attach_kprobe(kprobe_prog,
                                                 false /* retprobe */,
-                                                SYS_KPROBE_NAME);
+                                                SYS_NANOSLEEP_KPROBE_NAME);
        if (CHECK(IS_ERR(kprobe_link), "attach_kprobe",
                  "err %ld\n", PTR_ERR(kprobe_link))) {
                kprobe_link = NULL;
@@ -92,7 +86,7 @@ void test_attach_probe(void)
        }
        kretprobe_link = bpf_program__attach_kprobe(kretprobe_prog,
                                                    true /* retprobe */,
-                                                   SYS_KPROBE_NAME);
+                                                   SYS_NANOSLEEP_KPROBE_NAME);
        if (CHECK(IS_ERR(kretprobe_link), "attach_kretprobe",
                  "err %ld\n", PTR_ERR(kretprobe_link))) {
                kretprobe_link = NULL;
index 3f1ef95..3003fdd 100644 (file)
@@ -5,12 +5,6 @@
 #include <sys/socket.h>
 #include <test_progs.h>
 
-#ifdef __x86_64__
-#define SYS_KPROBE_NAME "__x64_sys_nanosleep"
-#else
-#define SYS_KPROBE_NAME "sys_nanosleep"
-#endif
-
 static void on_sample(void *ctx, int cpu, void *data, __u32 size)
 {
        int cpu_data = *(int *)data, duration = 0;
@@ -56,7 +50,7 @@ void test_perf_buffer(void)
 
        /* attach kprobe */
        link = bpf_program__attach_kprobe(prog, false /* retprobe */,
-                                         SYS_KPROBE_NAME);
+                                         SYS_NANOSLEEP_KPROBE_NAME);
        if (CHECK(IS_ERR(link), "attach_kprobe", "err %ld\n", PTR_ERR(link)))
                goto out_close;
 
index 67cea16..54218ee 100644 (file)
@@ -173,6 +173,18 @@ static int test_send_signal_tracepoint(void)
        return test_send_signal_common(&attr, BPF_PROG_TYPE_TRACEPOINT, "tracepoint");
 }
 
+static int test_send_signal_perf(void)
+{
+       struct perf_event_attr attr = {
+               .sample_period = 1,
+               .type = PERF_TYPE_SOFTWARE,
+               .config = PERF_COUNT_SW_CPU_CLOCK,
+       };
+
+       return test_send_signal_common(&attr, BPF_PROG_TYPE_PERF_EVENT,
+                                      "perf_sw_event");
+}
+
 static int test_send_signal_nmi(void)
 {
        struct perf_event_attr attr = {
@@ -181,8 +193,26 @@ static int test_send_signal_nmi(void)
                .type = PERF_TYPE_HARDWARE,
                .config = PERF_COUNT_HW_CPU_CYCLES,
        };
+       int pmu_fd;
+
+       /* Some setups (e.g. virtual machines) might run with hardware
+        * perf events disabled. If this is the case, skip this test.
+        */
+       pmu_fd = syscall(__NR_perf_event_open, &attr, 0 /* pid */,
+                        -1 /* cpu */, -1 /* group_fd */, 0 /* flags */);
+       if (pmu_fd == -1) {
+               if (errno == ENOENT) {
+                       printf("%s:SKIP:no PERF_COUNT_HW_CPU_CYCLES\n",
+                               __func__);
+                       return 0;
+               }
+               /* Let the test fail with a more informative message */
+       } else {
+               close(pmu_fd);
+       }
 
-       return test_send_signal_common(&attr, BPF_PROG_TYPE_PERF_EVENT, "perf_event");
+       return test_send_signal_common(&attr, BPF_PROG_TYPE_PERF_EVENT,
+                                      "perf_hw_event");
 }
 
 void test_send_signal(void)
@@ -190,6 +220,7 @@ void test_send_signal(void)
        int ret = 0;
 
        ret |= test_send_signal_tracepoint();
+       ret |= test_send_signal_perf();
        ret |= test_send_signal_nmi();
        if (!ret)
                printf("test_send_signal:OK\n");
index dea395a..7cdb7f8 100644 (file)
@@ -18,7 +18,7 @@ int nested_loops(volatile struct pt_regs* ctx)
        for (j = 0; j < 300; j++)
                for (i = 0; i < j; i++) {
                        if (j & 1)
-                               m = ctx->rax;
+                               m = PT_REGS_RC(ctx);
                        else
                                m = j;
                        sum += i * m;
index 0637bd8..9b2f808 100644 (file)
@@ -16,7 +16,7 @@ int while_true(volatile struct pt_regs* ctx)
        int i = 0;
 
        while (true) {
-               if (ctx->rax & 1)
+               if (PT_REGS_RC(ctx) & 1)
                        i += 3;
                else
                        i += 7;
index 30a0f6c..d727657 100644 (file)
@@ -16,7 +16,7 @@ int while_true(volatile struct pt_regs* ctx)
        __u64 i = 0, sum = 0;
        do {
                i++;
-               sum += ctx->rax;
+               sum += PT_REGS_RC(ctx);
        } while (i < 0x100000000ULL);
        return sum;
 }
index d06b47a..33254b7 100644 (file)
@@ -47,11 +47,12 @@ struct {
  * issue and avoid complicated C programming massaging.
  * This is an acceptable workaround since there is one entry here.
  */
+typedef __u64 raw_stack_trace_t[2 * MAX_STACK_RAWTP];
 struct {
        __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
        __uint(max_entries, 1);
        __type(key, __u32);
-       __u64 (*value)[2 * MAX_STACK_RAWTP];
+       __type(value, raw_stack_trace_t);
 } rawdata_map SEC(".maps");
 
 SEC("tracepoint/raw_syscalls/sys_enter")
index bbfc833..f5638e2 100644 (file)
@@ -36,8 +36,7 @@ struct {
        __uint(type, BPF_MAP_TYPE_ARRAY);
        __uint(max_entries, 128);
        __type(key, __u32);
-       /* there seems to be a bug in kernel not handling typedef properly */
-       struct bpf_stack_build_id (*value)[PERF_MAX_STACK_DEPTH];
+       __type(value, stack_trace_t);
 } stack_amap SEC(".maps");
 
 /* taken from /sys/kernel/debug/tracing/events/random/urandom_read/format */
index 803c15d..fa0be3e 100644 (file)
@@ -35,7 +35,7 @@ struct {
        __uint(type, BPF_MAP_TYPE_ARRAY);
        __uint(max_entries, 16384);
        __type(key, __u32);
-       __u64 (*value)[PERF_MAX_STACK_DEPTH];
+       __type(value, stack_trace_t);
 } stack_amap SEC(".maps");
 
 /* taken from /sys/kernel/debug/tracing/events/sched/sched_switch/format */
index dad8a7e..e88d7b9 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/tcp.h>
 #include <linux/udp.h>
 #include "bpf_helpers.h"
+#include "bpf_endian.h"
 
 static __u32 rol32(__u32 word, unsigned int shift)
 {
@@ -305,7 +306,7 @@ bool encap_v6(struct xdp_md *xdp, struct ctl_value *cval,
        ip6h->nexthdr = IPPROTO_IPV6;
        ip_suffix = pckt->flow.srcv6[3] ^ pckt->flow.port16[0];
        ip6h->payload_len =
-           __builtin_bswap16(pkt_bytes + sizeof(struct ipv6hdr));
+           bpf_htons(pkt_bytes + sizeof(struct ipv6hdr));
        ip6h->hop_limit = 4;
 
        ip6h->saddr.in6_u.u6_addr32[0] = 1;
@@ -322,7 +323,7 @@ bool encap_v4(struct xdp_md *xdp, struct ctl_value *cval,
              struct real_definition *dst, __u32 pkt_bytes)
 {
 
-       __u32 ip_suffix = __builtin_bswap16(pckt->flow.port16[0]);
+       __u32 ip_suffix = bpf_ntohs(pckt->flow.port16[0]);
        struct eth_hdr *new_eth;
        struct eth_hdr *old_eth;
        __u16 *next_iph_u16;
@@ -352,7 +353,7 @@ bool encap_v4(struct xdp_md *xdp, struct ctl_value *cval,
        iph->protocol = IPPROTO_IPIP;
        iph->check = 0;
        iph->tos = 1;
-       iph->tot_len = __builtin_bswap16(pkt_bytes + sizeof(struct iphdr));
+       iph->tot_len = bpf_htons(pkt_bytes + sizeof(struct iphdr));
        /* don't update iph->daddr, since it will overwrite old eth_proto
         * and multiple iterations of bpf_prog_run() will fail
         */
@@ -639,7 +640,7 @@ static int process_l3_headers_v6(struct packet_description *pckt,
        iph_len = sizeof(struct ipv6hdr);
        *protocol = ip6h->nexthdr;
        pckt->flow.proto = *protocol;
-       *pkt_bytes = __builtin_bswap16(ip6h->payload_len);
+       *pkt_bytes = bpf_ntohs(ip6h->payload_len);
        off += iph_len;
        if (*protocol == 45) {
                return XDP_DROP;
@@ -671,7 +672,7 @@ static int process_l3_headers_v4(struct packet_description *pckt,
                return XDP_DROP;
        *protocol = iph->protocol;
        pckt->flow.proto = *protocol;
-       *pkt_bytes = __builtin_bswap16(iph->tot_len);
+       *pkt_bytes = bpf_ntohs(iph->tot_len);
        off += 20;
        if (iph->frag_off & 65343)
                return XDP_DROP;
@@ -808,10 +809,10 @@ int balancer_ingress(struct xdp_md *ctx)
        nh_off = sizeof(struct eth_hdr);
        if (data + nh_off > data_end)
                return XDP_DROP;
-       eth_proto = eth->eth_proto;
-       if (eth_proto == 8)
+       eth_proto = bpf_ntohs(eth->eth_proto);
+       if (eth_proto == ETH_P_IP)
                return process_packet(data, nh_off, data_end, 0, ctx);
-       else if (eth_proto == 56710)
+       else if (eth_proto == ETH_P_IPV6)
                return process_packet(data, nh_off, data_end, 1, ctx);
        else
                return XDP_DROP;
index 8351cb5..3d617e8 100644 (file)
@@ -3417,6 +3417,94 @@ static struct btf_raw_test raw_tests[] = {
        .value_type_id = 1,
        .max_entries = 4,
 },
+/*
+ * typedef int arr_t[16];
+ * struct s {
+ *     arr_t *a;
+ * };
+ */
+{
+       .descr = "struct->ptr->typedef->array->int size resolution",
+       .raw_types = {
+               BTF_STRUCT_ENC(NAME_TBD, 1, 8),                 /* [1] */
+               BTF_MEMBER_ENC(NAME_TBD, 2, 0),
+               BTF_PTR_ENC(3),                                 /* [2] */
+               BTF_TYPEDEF_ENC(NAME_TBD, 4),                   /* [3] */
+               BTF_TYPE_ARRAY_ENC(5, 5, 16),                   /* [4] */
+               BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),  /* [5] */
+               BTF_END_RAW,
+       },
+       BTF_STR_SEC("\0s\0a\0arr_t"),
+       .map_type = BPF_MAP_TYPE_ARRAY,
+       .map_name = "ptr_mod_chain_size_resolve_map",
+       .key_size = sizeof(int),
+       .value_size = sizeof(int) * 16,
+       .key_type_id = 5 /* int */,
+       .value_type_id = 3 /* arr_t */,
+       .max_entries = 4,
+},
+/*
+ * typedef int arr_t[16][8][4];
+ * struct s {
+ *     arr_t *a;
+ * };
+ */
+{
+       .descr = "struct->ptr->typedef->multi-array->int size resolution",
+       .raw_types = {
+               BTF_STRUCT_ENC(NAME_TBD, 1, 8),                 /* [1] */
+               BTF_MEMBER_ENC(NAME_TBD, 2, 0),
+               BTF_PTR_ENC(3),                                 /* [2] */
+               BTF_TYPEDEF_ENC(NAME_TBD, 4),                   /* [3] */
+               BTF_TYPE_ARRAY_ENC(5, 7, 16),                   /* [4] */
+               BTF_TYPE_ARRAY_ENC(6, 7, 8),                    /* [5] */
+               BTF_TYPE_ARRAY_ENC(7, 7, 4),                    /* [6] */
+               BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),  /* [7] */
+               BTF_END_RAW,
+       },
+       BTF_STR_SEC("\0s\0a\0arr_t"),
+       .map_type = BPF_MAP_TYPE_ARRAY,
+       .map_name = "multi_arr_size_resolve_map",
+       .key_size = sizeof(int),
+       .value_size = sizeof(int) * 16 * 8 * 4,
+       .key_type_id = 7 /* int */,
+       .value_type_id = 3 /* arr_t */,
+       .max_entries = 4,
+},
+/*
+ * typedef int int_t;
+ * typedef int_t arr3_t[4];
+ * typedef arr3_t arr2_t[8];
+ * typedef arr2_t arr1_t[16];
+ * struct s {
+ *     arr1_t *a;
+ * };
+ */
+{
+       .descr = "typedef/multi-arr mix size resolution",
+       .raw_types = {
+               BTF_STRUCT_ENC(NAME_TBD, 1, 8),                 /* [1] */
+               BTF_MEMBER_ENC(NAME_TBD, 2, 0),
+               BTF_PTR_ENC(3),                                 /* [2] */
+               BTF_TYPEDEF_ENC(NAME_TBD, 4),                   /* [3] */
+               BTF_TYPE_ARRAY_ENC(5, 10, 16),                  /* [4] */
+               BTF_TYPEDEF_ENC(NAME_TBD, 6),                   /* [5] */
+               BTF_TYPE_ARRAY_ENC(7, 10, 8),                   /* [6] */
+               BTF_TYPEDEF_ENC(NAME_TBD, 8),                   /* [7] */
+               BTF_TYPE_ARRAY_ENC(9, 10, 4),                   /* [8] */
+               BTF_TYPEDEF_ENC(NAME_TBD, 10),                  /* [9] */
+               BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),  /* [10] */
+               BTF_END_RAW,
+       },
+       BTF_STR_SEC("\0s\0a\0arr1_t\0arr2_t\0arr3_t\0int_t"),
+       .map_type = BPF_MAP_TYPE_ARRAY,
+       .map_name = "typedef_arra_mix_size_resolve_map",
+       .key_size = sizeof(int),
+       .value_size = sizeof(int) * 16 * 8 * 4,
+       .key_type_id = 10 /* int */,
+       .value_type_id = 3 /* arr_t */,
+       .max_entries = 4,
+},
 
 }; /* struct btf_raw_test raw_tests[] */
 
index f095e1d..49e0f7d 100644 (file)
@@ -92,3 +92,11 @@ int compare_map_keys(int map1_fd, int map2_fd);
 int compare_stack_ips(int smap_fd, int amap_fd, int stack_trace_len);
 int extract_build_id(char *build_id, size_t size);
 void *spin_lock_thread(void *arg);
+
+#ifdef __x86_64__
+#define SYS_NANOSLEEP_KPROBE_NAME "__x64_sys_nanosleep"
+#elif defined(__s390x__)
+#define SYS_NANOSLEEP_KPROBE_NAME "__s390x_sys_nanosleep"
+#else
+#define SYS_NANOSLEEP_KPROBE_NAME "sys_nanosleep"
+#endif
index b077329..84135d5 100644 (file)
@@ -86,7 +86,7 @@ struct bpf_test {
        int fixup_sk_storage_map[MAX_FIXUPS];
        const char *errstr;
        const char *errstr_unpriv;
-       uint32_t retval, retval_unpriv, insn_processed;
+       uint32_t insn_processed;
        int prog_len;
        enum {
                UNDEF,
@@ -95,16 +95,20 @@ struct bpf_test {
        } result, result_unpriv;
        enum bpf_prog_type prog_type;
        uint8_t flags;
-       __u8 data[TEST_DATA_LEN];
        void (*fill_helper)(struct bpf_test *self);
        uint8_t runs;
-       struct {
-               uint32_t retval, retval_unpriv;
-               union {
-                       __u8 data[TEST_DATA_LEN];
-                       __u64 data64[TEST_DATA_LEN / 8];
-               };
-       } retvals[MAX_TEST_RUNS];
+#define bpf_testdata_struct_t                                  \
+       struct {                                                \
+               uint32_t retval, retval_unpriv;                 \
+               union {                                         \
+                       __u8 data[TEST_DATA_LEN];               \
+                       __u64 data64[TEST_DATA_LEN / 8];        \
+               };                                              \
+       }
+       union {
+               bpf_testdata_struct_t;
+               bpf_testdata_struct_t retvals[MAX_TEST_RUNS];
+       };
        enum bpf_attach_type expected_attach_type;
 };
 
@@ -949,17 +953,8 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
                uint32_t expected_val;
                int i;
 
-               if (!test->runs) {
-                       expected_val = unpriv && test->retval_unpriv ?
-                               test->retval_unpriv : test->retval;
-
-                       err = do_prog_test_run(fd_prog, unpriv, expected_val,
-                                              test->data, sizeof(test->data));
-                       if (err)
-                               run_errs++;
-                       else
-                               run_successes++;
-               }
+               if (!test->runs)
+                       test->runs = 1;
 
                for (i = 0; i < test->runs; i++) {
                        if (unpriv && test->retvals[i].retval_unpriv)
index bcb8319..f3c33e1 100644 (file)
        BPF_LD_MAP_FD(BPF_REG_1, 0),
        BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
        BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
-       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0),
+       BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        },
        .fixup_map_array_ro = { 3 },
index c3de1a2..a53d99c 100644 (file)
        BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
        BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
        BPF_EXIT_INSN(),
-       BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
+       BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
        BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 3),
        BPF_MOV64_IMM(BPF_REG_2, 0),
        BPF_MOV64_IMM(BPF_REG_3, 0x100000),
diff --git a/tools/testing/selftests/bpf/verifier/wide_access.c b/tools/testing/selftests/bpf/verifier/wide_access.c
new file mode 100644 (file)
index 0000000..ccade93
--- /dev/null
@@ -0,0 +1,73 @@
+#define BPF_SOCK_ADDR_STORE(field, off, res, err) \
+{ \
+       "wide store to bpf_sock_addr." #field "[" #off "]", \
+       .insns = { \
+       BPF_MOV64_IMM(BPF_REG_0, 1), \
+       BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, \
+                   offsetof(struct bpf_sock_addr, field[off])), \
+       BPF_EXIT_INSN(), \
+       }, \
+       .result = res, \
+       .prog_type = BPF_PROG_TYPE_CGROUP_SOCK_ADDR, \
+       .expected_attach_type = BPF_CGROUP_UDP6_SENDMSG, \
+       .errstr = err, \
+}
+
+/* user_ip6[0] is u64 aligned */
+BPF_SOCK_ADDR_STORE(user_ip6, 0, ACCEPT,
+                   NULL),
+BPF_SOCK_ADDR_STORE(user_ip6, 1, REJECT,
+                   "invalid bpf_context access off=12 size=8"),
+BPF_SOCK_ADDR_STORE(user_ip6, 2, ACCEPT,
+                   NULL),
+BPF_SOCK_ADDR_STORE(user_ip6, 3, REJECT,
+                   "invalid bpf_context access off=20 size=8"),
+
+/* msg_src_ip6[0] is _not_ u64 aligned */
+BPF_SOCK_ADDR_STORE(msg_src_ip6, 0, REJECT,
+                   "invalid bpf_context access off=44 size=8"),
+BPF_SOCK_ADDR_STORE(msg_src_ip6, 1, ACCEPT,
+                   NULL),
+BPF_SOCK_ADDR_STORE(msg_src_ip6, 2, REJECT,
+                   "invalid bpf_context access off=52 size=8"),
+BPF_SOCK_ADDR_STORE(msg_src_ip6, 3, REJECT,
+                   "invalid bpf_context access off=56 size=8"),
+
+#undef BPF_SOCK_ADDR_STORE
+
+#define BPF_SOCK_ADDR_LOAD(field, off, res, err) \
+{ \
+       "wide load from bpf_sock_addr." #field "[" #off "]", \
+       .insns = { \
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, \
+                   offsetof(struct bpf_sock_addr, field[off])), \
+       BPF_MOV64_IMM(BPF_REG_0, 1), \
+       BPF_EXIT_INSN(), \
+       }, \
+       .result = res, \
+       .prog_type = BPF_PROG_TYPE_CGROUP_SOCK_ADDR, \
+       .expected_attach_type = BPF_CGROUP_UDP6_SENDMSG, \
+       .errstr = err, \
+}
+
+/* user_ip6[0] is u64 aligned */
+BPF_SOCK_ADDR_LOAD(user_ip6, 0, ACCEPT,
+                  NULL),
+BPF_SOCK_ADDR_LOAD(user_ip6, 1, REJECT,
+                  "invalid bpf_context access off=12 size=8"),
+BPF_SOCK_ADDR_LOAD(user_ip6, 2, ACCEPT,
+                  NULL),
+BPF_SOCK_ADDR_LOAD(user_ip6, 3, REJECT,
+                  "invalid bpf_context access off=20 size=8"),
+
+/* msg_src_ip6[0] is _not_ u64 aligned */
+BPF_SOCK_ADDR_LOAD(msg_src_ip6, 0, REJECT,
+                  "invalid bpf_context access off=44 size=8"),
+BPF_SOCK_ADDR_LOAD(msg_src_ip6, 1, ACCEPT,
+                  NULL),
+BPF_SOCK_ADDR_LOAD(msg_src_ip6, 2, REJECT,
+                  "invalid bpf_context access off=52 size=8"),
+BPF_SOCK_ADDR_LOAD(msg_src_ip6, 3, REJECT,
+                  "invalid bpf_context access off=56 size=8"),
+
+#undef BPF_SOCK_ADDR_LOAD
diff --git a/tools/testing/selftests/bpf/verifier/wide_store.c b/tools/testing/selftests/bpf/verifier/wide_store.c
deleted file mode 100644 (file)
index 8fe9960..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#define BPF_SOCK_ADDR(field, off, res, err) \
-{ \
-       "wide store to bpf_sock_addr." #field "[" #off "]", \
-       .insns = { \
-       BPF_MOV64_IMM(BPF_REG_0, 1), \
-       BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, \
-                   offsetof(struct bpf_sock_addr, field[off])), \
-       BPF_EXIT_INSN(), \
-       }, \
-       .result = res, \
-       .prog_type = BPF_PROG_TYPE_CGROUP_SOCK_ADDR, \
-       .expected_attach_type = BPF_CGROUP_UDP6_SENDMSG, \
-       .errstr = err, \
-}
-
-/* user_ip6[0] is u64 aligned */
-BPF_SOCK_ADDR(user_ip6, 0, ACCEPT,
-             NULL),
-BPF_SOCK_ADDR(user_ip6, 1, REJECT,
-             "invalid bpf_context access off=12 size=8"),
-BPF_SOCK_ADDR(user_ip6, 2, ACCEPT,
-             NULL),
-BPF_SOCK_ADDR(user_ip6, 3, REJECT,
-             "invalid bpf_context access off=20 size=8"),
-
-/* msg_src_ip6[0] is _not_ u64 aligned */
-BPF_SOCK_ADDR(msg_src_ip6, 0, REJECT,
-             "invalid bpf_context access off=44 size=8"),
-BPF_SOCK_ADDR(msg_src_ip6, 1, ACCEPT,
-             NULL),
-BPF_SOCK_ADDR(msg_src_ip6, 2, REJECT,
-             "invalid bpf_context access off=52 size=8"),
-BPF_SOCK_ADDR(msg_src_ip6, 3, REJECT,
-             "invalid bpf_context access off=56 size=8"),
-
-#undef BPF_SOCK_ADDR
index 6d5e9e8..063ecb2 100755 (executable)
@@ -23,9 +23,15 @@ echo "                           If <dir> is -, all logs output in console only"
 exit $1
 }
 
+# default error
+err_ret=1
+
+# kselftest skip code is 4
+err_skip=4
+
 errexit() { # message
   echo "Error: $1" 1>&2
-  exit 1
+  exit $err_ret
 }
 
 # Ensuring user privilege
@@ -116,11 +122,31 @@ parse_opts() { # opts
 }
 
 # Parameters
-DEBUGFS_DIR=`grep debugfs /proc/mounts | cut -f2 -d' ' | head -1`
-if [ -z "$DEBUGFS_DIR" ]; then
-    TRACING_DIR=`grep tracefs /proc/mounts | cut -f2 -d' ' | head -1`
-else
-    TRACING_DIR=$DEBUGFS_DIR/tracing
+TRACING_DIR=`grep tracefs /proc/mounts | cut -f2 -d' ' | head -1`
+if [ -z "$TRACING_DIR" ]; then
+    DEBUGFS_DIR=`grep debugfs /proc/mounts | cut -f2 -d' ' | head -1`
+    if [ -z "$DEBUGFS_DIR" ]; then
+       # If tracefs exists, then so does /sys/kernel/tracing
+       if [ -d "/sys/kernel/tracing" ]; then
+           mount -t tracefs nodev /sys/kernel/tracing ||
+             errexit "Failed to mount /sys/kernel/tracing"
+           TRACING_DIR="/sys/kernel/tracing"
+       # If debugfs exists, then so does /sys/kernel/debug
+       elif [ -d "/sys/kernel/debug" ]; then
+           mount -t debugfs nodev /sys/kernel/debug ||
+             errexit "Failed to mount /sys/kernel/debug"
+           TRACING_DIR="/sys/kernel/debug/tracing"
+       else
+           err_ret=$err_skip
+           errexit "debugfs and tracefs are not configured in this kernel"
+       fi
+    else
+       TRACING_DIR="$DEBUGFS_DIR/tracing"
+    fi
+fi
+if [ ! -d "$TRACING_DIR" ]; then
+    err_ret=$err_skip
+    errexit "ftrace is not configured in this kernel"
 fi
 
 TOP_DIR=`absdir $0`
index 779ec11..1d96c5f 100644 (file)
@@ -91,8 +91,8 @@ initialize_ftrace() { # Reset ftrace to initial-state
     reset_events_filter
     reset_ftrace_filter
     disable_events
-    echo > set_event_pid       # event tracer is always on
-    echo > set_ftrace_pid
+    [ -f set_event_pid ] && echo > set_event_pid
+    [ -f set_ftrace_pid ] && echo > set_ftrace_pid
     [ -f set_ftrace_filter ] && echo | tee set_ftrace_*
     [ -f set_graph_function ] && echo | tee set_graph_*
     [ -f stack_trace_filter ] && echo > stack_trace_filter
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_user.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_user.tc
new file mode 100644 (file)
index 0000000..0f60087
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Kprobe event user-memory access
+
+[ -f kprobe_events ] || exit_unsupported # this is configurable
+
+grep -q '\$arg<N>' README || exit_unresolved # depends on arch
+grep -A10 "fetcharg:" README | grep -q 'ustring' || exit_unsupported
+grep -A10 "fetcharg:" README | grep -q '\[u\]<offset>' || exit_unsupported
+
+:;: "user-memory access syntax and ustring working on user memory";:
+echo 'p:myevent do_sys_open path=+0($arg2):ustring path2=+u0($arg2):string' \
+       > kprobe_events
+
+grep myevent kprobe_events | \
+       grep -q 'path=+0($arg2):ustring path2=+u0($arg2):string'
+echo 1 > events/kprobes/myevent/enable
+echo > /dev/null
+echo 0 > events/kprobes/myevent/enable
+
+grep myevent trace | grep -q 'path="/dev/null" path2="/dev/null"'
+
+:;: "user-memory access syntax and ustring not working with kernel memory";:
+echo 'p:myevent vfs_symlink path=+0($arg3):ustring path2=+u0($arg3):string' \
+       > kprobe_events
+echo 1 > events/kprobes/myevent/enable
+ln -s foo $TMPDIR/bar
+echo 0 > events/kprobes/myevent/enable
+
+grep myevent trace | grep -q 'path=(fault) path2=(fault)'
+
+exit 0
index 62afd0b..ba78497 100644 (file)
@@ -10,11 +10,11 @@ UNAME_M := $(shell uname -m)
 LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/ucall.c lib/sparsebit.c
 LIBKVM_x86_64 = lib/x86_64/processor.c lib/x86_64/vmx.c
 LIBKVM_aarch64 = lib/aarch64/processor.c
+LIBKVM_s390x = lib/s390x/processor.c
 
 TEST_GEN_PROGS_x86_64 = x86_64/cr4_cpuid_sync_test
 TEST_GEN_PROGS_x86_64 += x86_64/evmcs_test
 TEST_GEN_PROGS_x86_64 += x86_64/hyperv_cpuid
-TEST_GEN_PROGS_x86_64 += x86_64/kvm_create_max_vcpus
 TEST_GEN_PROGS_x86_64 += x86_64/mmio_warning_test
 TEST_GEN_PROGS_x86_64 += x86_64/platform_info_test
 TEST_GEN_PROGS_x86_64 += x86_64/set_sregs_test
@@ -26,9 +26,14 @@ 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 += clear_dirty_log_test
 TEST_GEN_PROGS_x86_64 += dirty_log_test
+TEST_GEN_PROGS_x86_64 += kvm_create_max_vcpus
 
 TEST_GEN_PROGS_aarch64 += clear_dirty_log_test
 TEST_GEN_PROGS_aarch64 += dirty_log_test
+TEST_GEN_PROGS_aarch64 += kvm_create_max_vcpus
+
+TEST_GEN_PROGS_s390x += s390x/sync_regs_test
+TEST_GEN_PROGS_s390x += kvm_create_max_vcpus
 
 TEST_GEN_PROGS += $(TEST_GEN_PROGS_$(UNAME_M))
 LIBKVM += $(LIBKVM_$(UNAME_M))
@@ -43,7 +48,12 @@ CFLAGS += -Wall -Wstrict-prototypes -Wuninitialized -O2 -g -std=gnu99 \
 no-pie-option := $(call try-run, echo 'int main() { return 0; }' | \
         $(CC) -Werror $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) -no-pie -x c - -o "$$TMP", -no-pie)
 
-LDFLAGS += -pthread $(no-pie-option)
+# On s390, build the testcases KVM-enabled
+pgste-option = $(call try-run, echo 'int main() { return 0; }' | \
+       $(CC) -Werror -Wl$(comma)--s390-pgste -x c - -o "$$TMP",-Wl$(comma)--s390-pgste)
+
+
+LDFLAGS += -pthread $(no-pie-option) $(pgste-option)
 
 # After inclusion, $(OUTPUT) is defined and
 # $(TEST_GEN_PROGS) starts with $(OUTPUT)/
index 00235f5..e0e66b1 100644 (file)
@@ -41,6 +41,12 @@ enum vm_guest_mode {
        NUM_VM_MODES,
 };
 
+#ifdef __aarch64__
+#define VM_MODE_DEFAULT VM_MODE_P40V48_4K
+#else
+#define VM_MODE_DEFAULT VM_MODE_P52V48_4K
+#endif
+
 #define vm_guest_mode_string(m) vm_guest_mode_string[m]
 extern const char * const vm_guest_mode_string[];
 
@@ -111,10 +117,12 @@ void vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid,
                    struct kvm_sregs *sregs);
 int _vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid,
                    struct kvm_sregs *sregs);
+#ifdef __KVM_HAVE_VCPU_EVENTS
 void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid,
                     struct kvm_vcpu_events *events);
 void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid,
                     struct kvm_vcpu_events *events);
+#endif
 #ifdef __x86_64__
 void vcpu_nested_state_get(struct kvm_vm *vm, uint32_t vcpuid,
                           struct kvm_nested_state *state);
diff --git a/tools/testing/selftests/kvm/include/s390x/processor.h b/tools/testing/selftests/kvm/include/s390x/processor.h
new file mode 100644 (file)
index 0000000..e0e96a5
--- /dev/null
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * s390x processor specific defines
+ */
+#ifndef SELFTEST_KVM_PROCESSOR_H
+#define SELFTEST_KVM_PROCESSOR_H
+
+/* Bits in the region/segment table entry */
+#define REGION_ENTRY_ORIGIN    ~0xfffUL /* region/segment table origin    */
+#define REGION_ENTRY_PROTECT   0x200    /* region protection bit          */
+#define REGION_ENTRY_NOEXEC    0x100    /* region no-execute bit          */
+#define REGION_ENTRY_OFFSET    0xc0     /* region table offset            */
+#define REGION_ENTRY_INVALID   0x20     /* invalid region table entry     */
+#define REGION_ENTRY_TYPE      0x0c     /* region/segment table type mask */
+#define REGION_ENTRY_LENGTH    0x03     /* region third length            */
+
+/* Bits in the page table entry */
+#define PAGE_INVALID   0x400           /* HW invalid bit    */
+#define PAGE_PROTECT   0x200           /* HW read-only bit  */
+#define PAGE_NOEXEC    0x100           /* HW no-execute bit */
+
+#endif
diff --git a/tools/testing/selftests/kvm/kvm_create_max_vcpus.c b/tools/testing/selftests/kvm/kvm_create_max_vcpus.c
new file mode 100644 (file)
index 0000000..231d79e
--- /dev/null
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * kvm_create_max_vcpus
+ *
+ * Copyright (C) 2019, Google LLC.
+ *
+ * Test for KVM_CAP_MAX_VCPUS and KVM_CAP_MAX_VCPU_ID.
+ */
+
+#define _GNU_SOURCE /* for program_invocation_short_name */
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "test_util.h"
+
+#include "kvm_util.h"
+#include "asm/kvm.h"
+#include "linux/kvm.h"
+
+void test_vcpu_creation(int first_vcpu_id, int num_vcpus)
+{
+       struct kvm_vm *vm;
+       int i;
+
+       printf("Testing creating %d vCPUs, with IDs %d...%d.\n",
+              num_vcpus, first_vcpu_id, first_vcpu_id + num_vcpus - 1);
+
+       vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES, O_RDWR);
+
+       for (i = 0; i < num_vcpus; i++) {
+               int vcpu_id = first_vcpu_id + i;
+
+               /* This asserts that the vCPU was created. */
+               vm_vcpu_add(vm, vcpu_id);
+       }
+
+       kvm_vm_free(vm);
+}
+
+int main(int argc, char *argv[])
+{
+       int kvm_max_vcpu_id = kvm_check_cap(KVM_CAP_MAX_VCPU_ID);
+       int kvm_max_vcpus = kvm_check_cap(KVM_CAP_MAX_VCPUS);
+
+       printf("KVM_CAP_MAX_VCPU_ID: %d\n", kvm_max_vcpu_id);
+       printf("KVM_CAP_MAX_VCPUS: %d\n", kvm_max_vcpus);
+
+       /*
+        * Upstream KVM prior to 4.8 does not support KVM_CAP_MAX_VCPU_ID.
+        * Userspace is supposed to use KVM_CAP_MAX_VCPUS as the maximum ID
+        * in this case.
+        */
+       if (!kvm_max_vcpu_id)
+               kvm_max_vcpu_id = kvm_max_vcpus;
+
+       TEST_ASSERT(kvm_max_vcpu_id >= kvm_max_vcpus,
+                   "KVM_MAX_VCPU_ID (%d) must be at least as large as KVM_MAX_VCPUS (%d).",
+                   kvm_max_vcpu_id, kvm_max_vcpus);
+
+       test_vcpu_creation(0, kvm_max_vcpus);
+
+       if (kvm_max_vcpu_id > kvm_max_vcpus)
+               test_vcpu_creation(
+                       kvm_max_vcpu_id - kvm_max_vcpus, kvm_max_vcpus);
+
+       return 0;
+}
index af2023d..486400a 100644 (file)
@@ -227,7 +227,7 @@ struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages,
        uint64_t extra_pg_pages = (extra_mem_pages / ptrs_per_4k_pte) * 2;
        struct kvm_vm *vm;
 
-       vm = vm_create(VM_MODE_P40V48_4K, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, O_RDWR);
+       vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, O_RDWR);
 
        kvm_vm_elf_load(vm, program_invocation_name, 0, 0);
        vm_vcpu_add_default(vm, vcpuid, guest_code);
index 221e3fa..6e49bb0 100644 (file)
@@ -556,6 +556,7 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm,
        int ret;
        struct userspace_mem_region *region;
        size_t huge_page_size = KVM_UTIL_PGS_PER_HUGEPG * vm->page_size;
+       size_t alignment;
 
        TEST_ASSERT((guest_paddr % vm->page_size) == 0, "Guest physical "
                "address not on a page boundary.\n"
@@ -605,9 +606,20 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm,
        TEST_ASSERT(region != NULL, "Insufficient Memory");
        region->mmap_size = npages * vm->page_size;
 
-       /* Enough memory to align up to a huge page. */
+#ifdef __s390x__
+       /* On s390x, the host address must be aligned to 1M (due to PGSTEs) */
+       alignment = 0x100000;
+#else
+       alignment = 1;
+#endif
+
        if (src_type == VM_MEM_SRC_ANONYMOUS_THP)
-               region->mmap_size += huge_page_size;
+               alignment = max(huge_page_size, alignment);
+
+       /* Add enough memory to align up if necessary */
+       if (alignment > 1)
+               region->mmap_size += alignment;
+
        region->mmap_start = mmap(NULL, region->mmap_size,
                                  PROT_READ | PROT_WRITE,
                                  MAP_PRIVATE | MAP_ANONYMOUS
@@ -617,9 +629,8 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm,
                    "test_malloc failed, mmap_start: %p errno: %i",
                    region->mmap_start, errno);
 
-       /* Align THP allocation up to start of a huge page. */
-       region->host_mem = align(region->mmap_start,
-                                src_type == VM_MEM_SRC_ANONYMOUS_THP ?  huge_page_size : 1);
+       /* Align host address */
+       region->host_mem = align(region->mmap_start, alignment);
 
        /* As needed perform madvise */
        if (src_type == VM_MEM_SRC_ANONYMOUS || src_type == VM_MEM_SRC_ANONYMOUS_THP) {
@@ -1218,6 +1229,7 @@ void vcpu_regs_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_regs *regs)
                ret, errno);
 }
 
+#ifdef __KVM_HAVE_VCPU_EVENTS
 void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid,
                     struct kvm_vcpu_events *events)
 {
@@ -1243,6 +1255,7 @@ void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid,
        TEST_ASSERT(ret == 0, "KVM_SET_VCPU_EVENTS, failed, rc: %i errno: %i",
                ret, errno);
 }
+#endif
 
 #ifdef __x86_64__
 void vcpu_nested_state_get(struct kvm_vm *vm, uint32_t vcpuid,
diff --git a/tools/testing/selftests/kvm/lib/s390x/processor.c b/tools/testing/selftests/kvm/lib/s390x/processor.c
new file mode 100644 (file)
index 0000000..32a0236
--- /dev/null
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * KVM selftest s390x library code - CPU-related functions (page tables...)
+ *
+ * Copyright (C) 2019, Red Hat, Inc.
+ */
+
+#define _GNU_SOURCE /* for program_invocation_name */
+
+#include "processor.h"
+#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)
+{
+       vm_paddr_t paddr;
+
+       TEST_ASSERT(vm->page_size == 4096, "Unsupported page size: 0x%x",
+                   vm->page_size);
+
+       if (vm->pgd_created)
+               return;
+
+       paddr = vm_phy_pages_alloc(vm, PAGES_PER_REGION,
+                                  KVM_GUEST_PAGE_TABLE_MIN_PADDR, memslot);
+       memset(addr_gpa2hva(vm, paddr), 0xff, PAGES_PER_REGION * vm->page_size);
+
+       vm->pgd = paddr;
+       vm->pgd_created = true;
+}
+
+/*
+ * Allocate 4 pages for a region/segment table (ri < 4), or one page for
+ * 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)
+{
+       uint64_t taddr;
+
+       taddr = vm_phy_pages_alloc(vm,  ri < 4 ? PAGES_PER_REGION : 1,
+                                  KVM_GUEST_PAGE_TABLE_MIN_PADDR, memslot);
+       memset(addr_gpa2hva(vm, taddr), 0xff, PAGES_PER_REGION * vm->page_size);
+
+       return (taddr & REGION_ENTRY_ORIGIN)
+               | (((4 - ri) << 2) & REGION_ENTRY_TYPE)
+               | ((ri < 4 ? (PAGES_PER_REGION - 1) : 0) & REGION_ENTRY_LENGTH);
+}
+
+/*
+ * VM Virtual Page Map
+ *
+ * Input Args:
+ *   vm - Virtual Machine
+ *   gva - VM Virtual Address
+ *   gpa - VM Physical Address
+ *   memslot - Memory region slot for new virtual translation tables
+ *
+ * Output Args: None
+ *
+ * Return: None
+ *
+ * Within the VM given by 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 gva, uint64_t gpa,
+                uint32_t memslot)
+{
+       int ri, idx;
+       uint64_t *entry;
+
+       TEST_ASSERT((gva % vm->page_size) == 0,
+               "Virtual address not on page boundary,\n"
+               "  vaddr: 0x%lx vm->page_size: 0x%x",
+               gva, vm->page_size);
+       TEST_ASSERT(sparsebit_is_set(vm->vpages_valid,
+               (gva >> vm->page_shift)),
+               "Invalid virtual address, vaddr: 0x%lx",
+               gva);
+       TEST_ASSERT((gpa % vm->page_size) == 0,
+               "Physical address not on page boundary,\n"
+               "  paddr: 0x%lx vm->page_size: 0x%x",
+               gva, vm->page_size);
+       TEST_ASSERT((gpa >> 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",
+               gva, vm->max_gfn, vm->page_size);
+
+       /* Walk through region and segment tables */
+       entry = addr_gpa2hva(vm, vm->pgd);
+       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 = addr_gpa2hva(vm, entry[idx] & REGION_ENTRY_ORIGIN);
+       }
+
+       /* Fill in page table entry */
+       idx = (gva >> 12) & 0x0ffu;             /* page index */
+       if (!(entry[idx] & PAGE_INVALID))
+               fprintf(stderr,
+                       "WARNING: PTE for gpa=0x%"PRIx64" already set!\n", gpa);
+       entry[idx] = gpa;
+}
+
+/*
+ * Address Guest Virtual to Guest Physical
+ *
+ * Input Args:
+ *   vm - Virtual Machine
+ *   gpa - VM virtual address
+ *
+ * Output Args: None
+ *
+ * Return:
+ *   Equivalent VM physical address
+ *
+ * Translates the VM virtual address given by gva to a VM physical
+ * address and then locates the memory region containing the VM
+ * physical address, within the VM given by vm.  When found, the host
+ * virtual address providing the memory to the vm physical address is
+ * returned.
+ * A TEST_ASSERT failure occurs if no region containing translated
+ * VM virtual address exists.
+ */
+vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva)
+{
+       int ri, idx;
+       uint64_t *entry;
+
+       TEST_ASSERT(vm->page_size == 4096, "Unsupported page size: 0x%x",
+                   vm->page_size);
+
+       entry = addr_gpa2hva(vm, vm->pgd);
+       for (ri = 1; ri <= 4; ri++) {
+               idx = (gva >> (64 - 11 * ri)) & 0x7ffu;
+               TEST_ASSERT(!(entry[idx] & REGION_ENTRY_INVALID),
+                           "No region mapping for vm virtual address 0x%lx",
+                           gva);
+               entry = addr_gpa2hva(vm, entry[idx] & REGION_ENTRY_ORIGIN);
+       }
+
+       idx = (gva >> 12) & 0x0ffu;             /* page index */
+
+       TEST_ASSERT(!(entry[idx] & PAGE_INVALID),
+                   "No page mapping for vm virtual address 0x%lx", gva);
+
+       return (entry[idx] & ~0xffful) + (gva & 0xffful);
+}
+
+static void virt_dump_ptes(FILE *stream, struct kvm_vm *vm, uint8_t indent,
+                          uint64_t ptea_start)
+{
+       uint64_t *pte, ptea;
+
+       for (ptea = ptea_start; ptea < ptea_start + 0x100 * 8; ptea += 8) {
+               pte = addr_gpa2hva(vm, ptea);
+               if (*pte & PAGE_INVALID)
+                       continue;
+               fprintf(stream, "%*spte @ 0x%lx: 0x%016lx\n",
+                       indent, "", ptea, *pte);
+       }
+}
+
+static void virt_dump_region(FILE *stream, struct kvm_vm *vm, uint8_t indent,
+                            uint64_t reg_tab_addr)
+{
+       uint64_t addr, *entry;
+
+       for (addr = reg_tab_addr; addr < reg_tab_addr + 0x400 * 8; addr += 8) {
+               entry = addr_gpa2hva(vm, addr);
+               if (*entry & REGION_ENTRY_INVALID)
+                       continue;
+               fprintf(stream, "%*srt%lde @ 0x%lx: 0x%016lx\n",
+                       indent, "", 4 - ((*entry & REGION_ENTRY_TYPE) >> 2),
+                       addr, *entry);
+               if (*entry & REGION_ENTRY_TYPE) {
+                       virt_dump_region(stream, vm, indent + 2,
+                                        *entry & REGION_ENTRY_ORIGIN);
+               } else {
+                       virt_dump_ptes(stream, vm, indent + 2,
+                                      *entry & REGION_ENTRY_ORIGIN);
+               }
+       }
+}
+
+void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
+{
+       if (!vm->pgd_created)
+               return;
+
+       virt_dump_region(stream, vm, indent, vm->pgd);
+}
+
+/*
+ * Create a VM with reasonable defaults
+ *
+ * Input Args:
+ *   vcpuid - The id of the single VCPU to add to the VM.
+ *   extra_mem_pages - The size of extra memories to add (this will
+ *                     decide how much extra space we will need to
+ *                     setup the page tables using mem slot 0)
+ *   guest_code - The vCPU's entry point
+ *
+ * Output Args: None
+ *
+ * Return:
+ *   Pointer to opaque structure that describes the created VM.
+ */
+struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages,
+                                void *guest_code)
+{
+       /*
+        * The additional amount of pages required for the page tables is:
+        * 1 * n / 256 + 4 * (n / 256) / 2048 + 4 * (n / 256) / 2048^2 + ...
+        * which is definitely smaller than (n / 256) * 2.
+        */
+       uint64_t extra_pg_pages = extra_mem_pages / 256 * 2;
+       struct kvm_vm *vm;
+
+       vm = vm_create(VM_MODE_DEFAULT,
+                      DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, O_RDWR);
+
+       kvm_vm_elf_load(vm, program_invocation_name, 0, 0);
+       vm_vcpu_add_default(vm, vcpuid, guest_code);
+
+       return vm;
+}
+
+/*
+ * Adds a vCPU with reasonable defaults (i.e. a stack and initial PSW)
+ *
+ * Input Args:
+ *   vcpuid - The id of the VCPU to add to the VM.
+ *   guest_code - The vCPU's entry point
+ */
+void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code)
+{
+       size_t stack_size =  DEFAULT_STACK_PGS * getpagesize();
+       uint64_t stack_vaddr;
+       struct kvm_regs regs;
+       struct kvm_sregs sregs;
+       struct kvm_run *run;
+
+       TEST_ASSERT(vm->page_size == 4096, "Unsupported page size: 0x%x",
+                   vm->page_size);
+
+       stack_vaddr = vm_vaddr_alloc(vm, stack_size,
+                                    DEFAULT_GUEST_STACK_VADDR_MIN, 0, 0);
+
+       vm_vcpu_add(vm, vcpuid);
+
+       /* Setup guest registers */
+       vcpu_regs_get(vm, vcpuid, &regs);
+       regs.gprs[15] = stack_vaddr + (DEFAULT_STACK_PGS * getpagesize()) - 160;
+       vcpu_regs_set(vm, vcpuid, &regs);
+
+       vcpu_sregs_get(vm, vcpuid, &sregs);
+       sregs.crs[0] |= 0x00040000;             /* Enable floating point regs */
+       sregs.crs[1] = vm->pgd | 0xf;           /* Primary region table */
+       vcpu_sregs_set(vm, vcpuid, &sregs);
+
+       run = vcpu_state(vm, vcpuid);
+       run->psw_mask = 0x0400000180000000ULL;  /* DAT enabled + 64 bit mode */
+       run->psw_addr = (uintptr_t)guest_code;
+}
+
+void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent)
+{
+       struct vcpu *vcpu = vm->vcpu_head;
+
+       fprintf(stream, "%*spstate: psw: 0x%.16llx:0x%.16llx\n",
+               indent, "", vcpu->state->psw_mask, vcpu->state->psw_addr);
+}
index b430f96..6cb34a0 100644 (file)
@@ -821,7 +821,7 @@ struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages,
        uint64_t extra_pg_pages = extra_mem_pages / 512 * 2;
 
        /* Create VM */
-       vm = vm_create(VM_MODE_P52V48_4K,
+       vm = vm_create(VM_MODE_DEFAULT,
                       DEFAULT_GUEST_PHY_PAGES + extra_pg_pages,
                       O_RDWR);
 
index fe56d15..204f847 100644 (file)
@@ -5,8 +5,6 @@
  * Copyright (C) 2018, Google LLC.
  */
 
-#define _GNU_SOURCE /* for program_invocation_name */
-
 #include "test_util.h"
 #include "kvm_util.h"
 #include "processor.h"
diff --git a/tools/testing/selftests/kvm/s390x/sync_regs_test.c b/tools/testing/selftests/kvm/s390x/sync_regs_test.c
new file mode 100644 (file)
index 0000000..e85ff0d
--- /dev/null
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Test for s390x KVM_CAP_SYNC_REGS
+ *
+ * Based on the same test for x86:
+ * Copyright (C) 2018, Google LLC.
+ *
+ * Adaptions for s390x:
+ * Copyright (C) 2019, Red Hat, Inc.
+ *
+ * Test expected behavior of the KVM_CAP_SYNC_REGS functionality.
+ */
+
+#define _GNU_SOURCE /* for program_invocation_short_name */
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "test_util.h"
+#include "kvm_util.h"
+
+#define VCPU_ID 5
+
+static void guest_code(void)
+{
+       for (;;) {
+               asm volatile ("diag 0,0,0x501");
+               asm volatile ("ahi 11,1");
+       }
+}
+
+#define REG_COMPARE(reg) \
+       TEST_ASSERT(left->reg == right->reg, \
+                   "Register " #reg \
+                   " values did not match: 0x%llx, 0x%llx\n", \
+                   left->reg, right->reg)
+
+static void compare_regs(struct kvm_regs *left, struct kvm_sync_regs *right)
+{
+       int i;
+
+       for (i = 0; i < 16; i++)
+               REG_COMPARE(gprs[i]);
+}
+
+static void compare_sregs(struct kvm_sregs *left, struct kvm_sync_regs *right)
+{
+       int i;
+
+       for (i = 0; i < 16; i++)
+               REG_COMPARE(acrs[i]);
+
+       for (i = 0; i < 16; i++)
+               REG_COMPARE(crs[i]);
+}
+
+#undef REG_COMPARE
+
+#define TEST_SYNC_FIELDS   (KVM_SYNC_GPRS|KVM_SYNC_ACRS|KVM_SYNC_CRS)
+#define INVALID_SYNC_FIELD 0x80000000
+
+int main(int argc, char *argv[])
+{
+       struct kvm_vm *vm;
+       struct kvm_run *run;
+       struct kvm_regs regs;
+       struct kvm_sregs sregs;
+       int rv, cap;
+
+       /* Tell stdout not to buffer its content */
+       setbuf(stdout, NULL);
+
+       cap = kvm_check_cap(KVM_CAP_SYNC_REGS);
+       if (!cap) {
+               fprintf(stderr, "CAP_SYNC_REGS not supported, skipping test\n");
+               exit(KSFT_SKIP);
+       }
+
+       /* Create VM */
+       vm = vm_create_default(VCPU_ID, 0, guest_code);
+
+       run = vcpu_state(vm, VCPU_ID);
+
+       /* Request and verify all valid register sets. */
+       run->kvm_valid_regs = TEST_SYNC_FIELDS;
+       rv = _vcpu_run(vm, VCPU_ID);
+       TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv);
+       TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC,
+                   "Unexpected exit reason: %u (%s)\n",
+                   run->exit_reason,
+                   exit_reason_str(run->exit_reason));
+       TEST_ASSERT(run->s390_sieic.icptcode == 4 &&
+                   (run->s390_sieic.ipa >> 8) == 0x83 &&
+                   (run->s390_sieic.ipb >> 16) == 0x501,
+                   "Unexpected interception code: ic=%u, ipa=0x%x, ipb=0x%x\n",
+                   run->s390_sieic.icptcode, run->s390_sieic.ipa,
+                   run->s390_sieic.ipb);
+
+       vcpu_regs_get(vm, VCPU_ID, &regs);
+       compare_regs(&regs, &run->s.regs);
+
+       vcpu_sregs_get(vm, VCPU_ID, &sregs);
+       compare_sregs(&sregs, &run->s.regs);
+
+       /* Set and verify various register values */
+       run->s.regs.gprs[11] = 0xBAD1DEA;
+       run->s.regs.acrs[0] = 1 << 11;
+
+       run->kvm_valid_regs = TEST_SYNC_FIELDS;
+       run->kvm_dirty_regs = KVM_SYNC_GPRS | KVM_SYNC_ACRS;
+       rv = _vcpu_run(vm, VCPU_ID);
+       TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv);
+       TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC,
+                   "Unexpected exit reason: %u (%s)\n",
+                   run->exit_reason,
+                   exit_reason_str(run->exit_reason));
+       TEST_ASSERT(run->s.regs.gprs[11] == 0xBAD1DEA + 1,
+                   "r11 sync regs value incorrect 0x%llx.",
+                   run->s.regs.gprs[11]);
+       TEST_ASSERT(run->s.regs.acrs[0]  == 1 << 11,
+                   "acr0 sync regs value incorrect 0x%llx.",
+                   run->s.regs.acrs[0]);
+
+       vcpu_regs_get(vm, VCPU_ID, &regs);
+       compare_regs(&regs, &run->s.regs);
+
+       vcpu_sregs_get(vm, VCPU_ID, &sregs);
+       compare_sregs(&sregs, &run->s.regs);
+
+       /* Clear kvm_dirty_regs bits, verify new s.regs values are
+        * overwritten with existing guest values.
+        */
+       run->kvm_valid_regs = TEST_SYNC_FIELDS;
+       run->kvm_dirty_regs = 0;
+       run->s.regs.gprs[11] = 0xDEADBEEF;
+       rv = _vcpu_run(vm, VCPU_ID);
+       TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv);
+       TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC,
+                   "Unexpected exit reason: %u (%s)\n",
+                   run->exit_reason,
+                   exit_reason_str(run->exit_reason));
+       TEST_ASSERT(run->s.regs.gprs[11] != 0xDEADBEEF,
+                   "r11 sync regs value incorrect 0x%llx.",
+                   run->s.regs.gprs[11]);
+
+       kvm_vm_free(vm);
+
+       return 0;
+}
diff --git a/tools/testing/selftests/kvm/x86_64/kvm_create_max_vcpus.c b/tools/testing/selftests/kvm/x86_64/kvm_create_max_vcpus.c
deleted file mode 100644 (file)
index 429226b..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * kvm_create_max_vcpus
- *
- * Copyright (C) 2019, Google LLC.
- *
- * Test for KVM_CAP_MAX_VCPUS and KVM_CAP_MAX_VCPU_ID.
- */
-
-#define _GNU_SOURCE /* for program_invocation_short_name */
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "test_util.h"
-
-#include "kvm_util.h"
-#include "asm/kvm.h"
-#include "linux/kvm.h"
-
-void test_vcpu_creation(int first_vcpu_id, int num_vcpus)
-{
-       struct kvm_vm *vm;
-       int i;
-
-       printf("Testing creating %d vCPUs, with IDs %d...%d.\n",
-              num_vcpus, first_vcpu_id, first_vcpu_id + num_vcpus - 1);
-
-       vm = vm_create(VM_MODE_P52V48_4K, DEFAULT_GUEST_PHY_PAGES, O_RDWR);
-
-       for (i = 0; i < num_vcpus; i++) {
-               int vcpu_id = first_vcpu_id + i;
-
-               /* This asserts that the vCPU was created. */
-               vm_vcpu_add(vm, vcpu_id);
-       }
-
-       kvm_vm_free(vm);
-}
-
-int main(int argc, char *argv[])
-{
-       int kvm_max_vcpu_id = kvm_check_cap(KVM_CAP_MAX_VCPU_ID);
-       int kvm_max_vcpus = kvm_check_cap(KVM_CAP_MAX_VCPUS);
-
-       printf("KVM_CAP_MAX_VCPU_ID: %d\n", kvm_max_vcpu_id);
-       printf("KVM_CAP_MAX_VCPUS: %d\n", kvm_max_vcpus);
-
-       /*
-        * Upstream KVM prior to 4.8 does not support KVM_CAP_MAX_VCPU_ID.
-        * Userspace is supposed to use KVM_CAP_MAX_VCPUS as the maximum ID
-        * in this case.
-        */
-       if (!kvm_max_vcpu_id)
-               kvm_max_vcpu_id = kvm_max_vcpus;
-
-       TEST_ASSERT(kvm_max_vcpu_id >= kvm_max_vcpus,
-                   "KVM_MAX_VCPU_ID (%d) must be at least as large as KVM_MAX_VCPUS (%d).",
-                   kvm_max_vcpu_id, kvm_max_vcpus);
-
-       test_vcpu_creation(0, kvm_max_vcpus);
-
-       if (kvm_max_vcpu_id > kvm_max_vcpus)
-               test_vcpu_creation(
-                       kvm_max_vcpu_id - kvm_max_vcpus, kvm_max_vcpus);
-
-       return 0;
-}
index 9457aae..4465fc2 100755 (executable)
@@ -9,12 +9,13 @@ ret=0
 ksft_skip=4
 
 # all tests in this script. Can be overridden with -t option
-TESTS="unregister down carrier nexthop ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric ipv6_route_metrics ipv4_route_metrics ipv4_route_v6_gw"
+TESTS="unregister down carrier nexthop ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric ipv6_route_metrics ipv4_route_metrics ipv4_route_v6_gw rp_filter"
 
 VERBOSE=0
 PAUSE_ON_FAIL=no
 PAUSE=no
 IP="ip -netns ns1"
+NS_EXEC="ip netns exec ns1"
 
 log_test()
 {
@@ -433,6 +434,37 @@ fib_carrier_test()
        fib_carrier_unicast_test
 }
 
+fib_rp_filter_test()
+{
+       echo
+       echo "IPv4 rp_filter tests"
+
+       setup
+
+       set -e
+       $IP link set dev lo address 52:54:00:6a:c7:5e
+       $IP link set dummy0 address 52:54:00:6a:c7:5e
+       $IP link add dummy1 type dummy
+       $IP link set dummy1 address 52:54:00:6a:c7:5e
+       $IP link set dev dummy1 up
+       $NS_EXEC sysctl -qw net.ipv4.conf.all.rp_filter=1
+       $NS_EXEC sysctl -qw net.ipv4.conf.all.accept_local=1
+       $NS_EXEC sysctl -qw net.ipv4.conf.all.route_localnet=1
+
+       $NS_EXEC tc qd add dev dummy1 parent root handle 1: fq_codel
+       $NS_EXEC tc filter add dev dummy1 parent 1: protocol arp basic action mirred egress redirect dev lo
+       $NS_EXEC tc filter add dev dummy1 parent 1: protocol ip basic action mirred egress redirect dev lo
+       set +e
+
+       run_cmd "ip netns exec ns1 ping -I dummy1 -w1 -c1 198.51.100.1"
+       log_test $? 0 "rp_filter passes local packets"
+
+       run_cmd "ip netns exec ns1 ping -I dummy1 -w1 -c1 127.0.0.1"
+       log_test $? 0 "rp_filter passes loopback packets"
+
+       cleanup
+}
+
 ################################################################################
 # Tests on nexthop spec
 
@@ -1557,6 +1589,7 @@ do
        fib_unreg_test|unregister)      fib_unreg_test;;
        fib_down_test|down)             fib_down_test;;
        fib_carrier_test|carrier)       fib_carrier_test;;
+       fib_rp_filter_test|rp_filter)   fib_rp_filter_test;;
        fib_nexthop_test|nexthop)       fib_nexthop_test;;
        ipv6_route_test|ipv6_rt)        ipv6_route_test;;
        ipv4_route_test|ipv4_rt)        ipv4_route_test;;
index 8a20e03..9c60337 100755 (executable)
@@ -78,10 +78,10 @@ set -e
 
 function _modprobe()
 {
-       modprobe "$@"
+       modprobe "$@" || return 1
 
        if [[ "$REMOTE_HOST" != "" ]]; then
-               ssh "$REMOTE_HOST" modprobe "$@"
+               ssh "$REMOTE_HOST" modprobe "$@" || return 1
        fi
 }
 
@@ -442,6 +442,30 @@ function pingpong_test()
        echo "  Passed"
 }
 
+function msi_test()
+{
+       LOC=$1
+       REM=$2
+
+       write_file 1 $LOC/ready
+
+       echo "Running MSI interrupt tests on: $(subdirname $LOC) / $(subdirname $REM)"
+
+       CNT=$(read_file "$LOC/count")
+       for ((i = 0; i < $CNT; i++)); do
+               START=$(read_file $REM/../irq${i}_occurrences)
+               write_file $i $LOC/trigger
+               END=$(read_file $REM/../irq${i}_occurrences)
+
+               if [[ $(($END - $START)) != 1 ]]; then
+                       echo "MSI did not trigger the interrupt on the remote side!" >&2
+                       exit 1
+               fi
+       done
+
+       echo "  Passed"
+}
+
 function perf_test()
 {
        USE_DMA=$1
@@ -520,6 +544,29 @@ function ntb_pingpong_tests()
        _modprobe -r ntb_pingpong
 }
 
+function ntb_msi_tests()
+{
+       LOCAL_MSI="$DEBUGFS/ntb_msi_test/$LOCAL_DEV"
+       REMOTE_MSI="$REMOTE_HOST:$DEBUGFS/ntb_msi_test/$REMOTE_DEV"
+
+       echo "Starting ntb_msi_test tests..."
+
+       if ! _modprobe ntb_msi_test 2> /dev/null; then
+               echo "  Not doing MSI tests seeing the module is not available."
+               return
+       fi
+
+       port_test $LOCAL_MSI $REMOTE_MSI
+
+       LOCAL_PEER="$LOCAL_MSI/peer$LOCAL_PIDX"
+       REMOTE_PEER="$REMOTE_MSI/peer$REMOTE_PIDX"
+
+       msi_test $LOCAL_PEER $REMOTE_PEER
+       msi_test $REMOTE_PEER $LOCAL_PEER
+
+       _modprobe -r ntb_msi_test
+}
+
 function ntb_perf_tests()
 {
        LOCAL_PERF="$DEBUGFS/ntb_perf/$LOCAL_DEV"
@@ -541,6 +588,7 @@ function cleanup()
        _modprobe -r ntb_perf 2> /dev/null
        _modprobe -r ntb_pingpong 2> /dev/null
        _modprobe -r ntb_transport 2> /dev/null
+       _modprobe -r ntb_msi_test 2> /dev/null
        set -e
 }
 
@@ -577,5 +625,7 @@ ntb_tool_tests
 echo
 ntb_pingpong_tests
 echo
+ntb_msi_tests
+echo
 ntb_perf_tests
 echo
index 9f09fcd..a8ed0f6 100644 (file)
@@ -17,6 +17,7 @@ TEST_GEN_PROGS += proc-uptime-002
 TEST_GEN_PROGS += read
 TEST_GEN_PROGS += self
 TEST_GEN_PROGS += setns-dcache
+TEST_GEN_PROGS += setns-sysvipc
 TEST_GEN_PROGS += thread-self
 
 include ../lib.mk
index 853aa16..18a3bde 100644 (file)
@@ -215,6 +215,11 @@ static const char str_vsyscall[] =
 "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]\n";
 
 #ifdef __x86_64__
+static void sigaction_SIGSEGV(int _, siginfo_t *__, void *___)
+{
+       _exit(1);
+}
+
 /*
  * vsyscall page can't be unmapped, probe it with memory load.
  */
@@ -231,11 +236,19 @@ static void vsyscall(void)
        if (pid == 0) {
                struct rlimit rlim = {0, 0};
                (void)setrlimit(RLIMIT_CORE, &rlim);
+
+               /* Hide "segfault at ffffffffff600000" messages. */
+               struct sigaction act;
+               memset(&act, 0, sizeof(struct sigaction));
+               act.sa_flags = SA_SIGINFO;
+               act.sa_sigaction = sigaction_SIGSEGV;
+               (void)sigaction(SIGSEGV, &act, NULL);
+
                *(volatile int *)0xffffffffff600000UL;
                exit(0);
        }
-       wait(&wstatus);
-       if (WIFEXITED(wstatus)) {
+       waitpid(pid, &wstatus, 0);
+       if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0) {
                g_vsyscall = true;
        }
 }
diff --git a/tools/testing/selftests/proc/setns-sysvipc.c b/tools/testing/selftests/proc/setns-sysvipc.c
new file mode 100644 (file)
index 0000000..903890c
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright © 2019 Alexey Dobriyan <adobriyan@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Test that setns(CLONE_NEWIPC) points to new /proc/sysvipc content even
+ * if old one is in dcache.
+ */
+#undef NDEBUG
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+static pid_t pid = -1;
+
+static void f(void)
+{
+       if (pid > 0) {
+               kill(pid, SIGTERM);
+       }
+}
+
+int main(void)
+{
+       int fd[2];
+       char _ = 0;
+       int nsfd;
+
+       atexit(f);
+
+       /* Check for priviledges and syscall availability straight away. */
+       if (unshare(CLONE_NEWIPC) == -1) {
+               if (errno == ENOSYS || errno == EPERM) {
+                       return 4;
+               }
+               return 1;
+       }
+       /* Distinguisher between two otherwise empty IPC namespaces. */
+       if (shmget(IPC_PRIVATE, 1, IPC_CREAT) == -1) {
+               return 1;
+       }
+
+       if (pipe(fd) == -1) {
+               return 1;
+       }
+
+       pid = fork();
+       if (pid == -1) {
+               return 1;
+       }
+
+       if (pid == 0) {
+               if (unshare(CLONE_NEWIPC) == -1) {
+                       return 1;
+               }
+
+               if (write(fd[1], &_, 1) != 1) {
+                       return 1;
+               }
+
+               pause();
+
+               return 0;
+       }
+
+       if (read(fd[0], &_, 1) != 1) {
+               return 1;
+       }
+
+       {
+               char buf[64];
+               snprintf(buf, sizeof(buf), "/proc/%u/ns/ipc", pid);
+               nsfd = open(buf, O_RDONLY);
+               if (nsfd == -1) {
+                       return 1;
+               }
+       }
+
+       /* Reliably pin dentry into dcache. */
+       (void)open("/proc/sysvipc/shm", O_RDONLY);
+
+       if (setns(nsfd, CLONE_NEWIPC) == -1) {
+               return 1;
+       }
+
+       kill(pid, SIGTERM);
+       pid = 0;
+
+       {
+               char buf[4096];
+               ssize_t rv;
+               int fd;
+
+               fd = open("/proc/sysvipc/shm", O_RDONLY);
+               if (fd == -1) {
+                       return 1;
+               }
+
+#define S32 "       key      shmid perms       size  cpid  lpid nattch   uid   gid  cuid  cgid      atime      dtime      ctime        rss       swap\n"
+#define S64 "       key      shmid perms                  size  cpid  lpid nattch   uid   gid  cuid  cgid      atime      dtime      ctime                   rss                  swap\n"
+               rv = read(fd, buf, sizeof(buf));
+               if (rv == strlen(S32)) {
+                       assert(memcmp(buf, S32, strlen(S32)) == 0);
+               } else if (rv == strlen(S64)) {
+                       assert(memcmp(buf, S64, strlen(S64)) == 0);
+               } else {
+                       assert(0);
+               }
+       }
+
+       return 0;
+}
index cb21c76..c0b7f89 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 CFLAGS += -iquote../../../../include/uapi -Wall
 
-TEST_GEN_PROGS := peeksiginfo
+TEST_GEN_PROGS := get_syscall_info peeksiginfo
 
 include ../lib.mk
diff --git a/tools/testing/selftests/ptrace/get_syscall_info.c b/tools/testing/selftests/ptrace/get_syscall_info.c
new file mode 100644 (file)
index 0000000..5bcd1c7
--- /dev/null
@@ -0,0 +1,271 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>
+ * All rights reserved.
+ *
+ * Check whether PTRACE_GET_SYSCALL_INFO semantics implemented in the kernel
+ * matches userspace expectations.
+ */
+
+#include "../kselftest_harness.h"
+#include <err.h>
+#include <signal.h>
+#include <asm/unistd.h>
+#include "linux/ptrace.h"
+
+static int
+kill_tracee(pid_t pid)
+{
+       if (!pid)
+               return 0;
+
+       int saved_errno = errno;
+
+       int rc = kill(pid, SIGKILL);
+
+       errno = saved_errno;
+       return rc;
+}
+
+static long
+sys_ptrace(int request, pid_t pid, unsigned long addr, unsigned long data)
+{
+       return syscall(__NR_ptrace, request, pid, addr, data);
+}
+
+#define LOG_KILL_TRACEE(fmt, ...)                              \
+       do {                                                    \
+               kill_tracee(pid);                               \
+               TH_LOG("wait #%d: " fmt,                        \
+                      ptrace_stop, ##__VA_ARGS__);             \
+       } while (0)
+
+TEST(get_syscall_info)
+{
+       static const unsigned long args[][7] = {
+               /* a sequence of architecture-agnostic syscalls */
+               {
+                       __NR_chdir,
+                       (unsigned long) "",
+                       0xbad1fed1,
+                       0xbad2fed2,
+                       0xbad3fed3,
+                       0xbad4fed4,
+                       0xbad5fed5
+               },
+               {
+                       __NR_gettid,
+                       0xcaf0bea0,
+                       0xcaf1bea1,
+                       0xcaf2bea2,
+                       0xcaf3bea3,
+                       0xcaf4bea4,
+                       0xcaf5bea5
+               },
+               {
+                       __NR_exit_group,
+                       0,
+                       0xfac1c0d1,
+                       0xfac2c0d2,
+                       0xfac3c0d3,
+                       0xfac4c0d4,
+                       0xfac5c0d5
+               }
+       };
+       const unsigned long *exp_args;
+
+       pid_t pid = fork();
+
+       ASSERT_LE(0, pid) {
+               TH_LOG("fork: %m");
+       }
+
+       if (pid == 0) {
+               /* get the pid before PTRACE_TRACEME */
+               pid = getpid();
+               ASSERT_EQ(0, sys_ptrace(PTRACE_TRACEME, 0, 0, 0)) {
+                       TH_LOG("PTRACE_TRACEME: %m");
+               }
+               ASSERT_EQ(0, kill(pid, SIGSTOP)) {
+                       /* cannot happen */
+                       TH_LOG("kill SIGSTOP: %m");
+               }
+               for (unsigned int i = 0; i < ARRAY_SIZE(args); ++i) {
+                       syscall(args[i][0],
+                               args[i][1], args[i][2], args[i][3],
+                               args[i][4], args[i][5], args[i][6]);
+               }
+               /* unreachable */
+               _exit(1);
+       }
+
+       const struct {
+               unsigned int is_error;
+               int rval;
+       } *exp_param, exit_param[] = {
+               { 1, -ENOENT }, /* chdir */
+               { 0, pid }      /* gettid */
+       };
+
+       unsigned int ptrace_stop;
+
+       for (ptrace_stop = 0; ; ++ptrace_stop) {
+               struct ptrace_syscall_info info = {
+                       .op = 0xff      /* invalid PTRACE_SYSCALL_INFO_* op */
+               };
+               const size_t size = sizeof(info);
+               const int expected_none_size =
+                       (void *) &info.entry - (void *) &info;
+               const int expected_entry_size =
+                       (void *) &info.entry.args[6] - (void *) &info;
+               const int expected_exit_size =
+                       (void *) (&info.exit.is_error + 1) -
+                       (void *) &info;
+               int status;
+               long rc;
+
+               ASSERT_EQ(pid, wait(&status)) {
+                       /* cannot happen */
+                       LOG_KILL_TRACEE("wait: %m");
+               }
+               if (WIFEXITED(status)) {
+                       pid = 0;        /* the tracee is no more */
+                       ASSERT_EQ(0, WEXITSTATUS(status));
+                       break;
+               }
+               ASSERT_FALSE(WIFSIGNALED(status)) {
+                       pid = 0;        /* the tracee is no more */
+                       LOG_KILL_TRACEE("unexpected signal %u",
+                                       WTERMSIG(status));
+               }
+               ASSERT_TRUE(WIFSTOPPED(status)) {
+                       /* cannot happen */
+                       LOG_KILL_TRACEE("unexpected wait status %#x", status);
+               }
+
+               switch (WSTOPSIG(status)) {
+               case SIGSTOP:
+                       ASSERT_EQ(0, ptrace_stop) {
+                               LOG_KILL_TRACEE("unexpected signal stop");
+                       }
+                       ASSERT_EQ(0, sys_ptrace(PTRACE_SETOPTIONS, pid, 0,
+                                               PTRACE_O_TRACESYSGOOD)) {
+                               LOG_KILL_TRACEE("PTRACE_SETOPTIONS: %m");
+                       }
+                       ASSERT_LT(0, (rc = sys_ptrace(PTRACE_GET_SYSCALL_INFO,
+                                                     pid, size,
+                                                     (unsigned long) &info))) {
+                               LOG_KILL_TRACEE("PTRACE_GET_SYSCALL_INFO: %m");
+                       }
+                       ASSERT_EQ(expected_none_size, rc) {
+                               LOG_KILL_TRACEE("signal stop mismatch");
+                       }
+                       ASSERT_EQ(PTRACE_SYSCALL_INFO_NONE, info.op) {
+                               LOG_KILL_TRACEE("signal stop mismatch");
+                       }
+                       ASSERT_TRUE(info.arch) {
+                               LOG_KILL_TRACEE("signal stop mismatch");
+                       }
+                       ASSERT_TRUE(info.instruction_pointer) {
+                               LOG_KILL_TRACEE("signal stop mismatch");
+                       }
+                       ASSERT_TRUE(info.stack_pointer) {
+                               LOG_KILL_TRACEE("signal stop mismatch");
+                       }
+                       break;
+
+               case SIGTRAP | 0x80:
+                       ASSERT_LT(0, (rc = sys_ptrace(PTRACE_GET_SYSCALL_INFO,
+                                                     pid, size,
+                                                     (unsigned long) &info))) {
+                               LOG_KILL_TRACEE("PTRACE_GET_SYSCALL_INFO: %m");
+                       }
+                       switch (ptrace_stop) {
+                       case 1: /* entering chdir */
+                       case 3: /* entering gettid */
+                       case 5: /* entering exit_group */
+                               exp_args = args[ptrace_stop / 2];
+                               ASSERT_EQ(expected_entry_size, rc) {
+                                       LOG_KILL_TRACEE("entry stop mismatch");
+                               }
+                               ASSERT_EQ(PTRACE_SYSCALL_INFO_ENTRY, info.op) {
+                                       LOG_KILL_TRACEE("entry stop mismatch");
+                               }
+                               ASSERT_TRUE(info.arch) {
+                                       LOG_KILL_TRACEE("entry stop mismatch");
+                               }
+                               ASSERT_TRUE(info.instruction_pointer) {
+                                       LOG_KILL_TRACEE("entry stop mismatch");
+                               }
+                               ASSERT_TRUE(info.stack_pointer) {
+                                       LOG_KILL_TRACEE("entry stop mismatch");
+                               }
+                               ASSERT_EQ(exp_args[0], info.entry.nr) {
+                                       LOG_KILL_TRACEE("entry stop mismatch");
+                               }
+                               ASSERT_EQ(exp_args[1], info.entry.args[0]) {
+                                       LOG_KILL_TRACEE("entry stop mismatch");
+                               }
+                               ASSERT_EQ(exp_args[2], info.entry.args[1]) {
+                                       LOG_KILL_TRACEE("entry stop mismatch");
+                               }
+                               ASSERT_EQ(exp_args[3], info.entry.args[2]) {
+                                       LOG_KILL_TRACEE("entry stop mismatch");
+                               }
+                               ASSERT_EQ(exp_args[4], info.entry.args[3]) {
+                                       LOG_KILL_TRACEE("entry stop mismatch");
+                               }
+                               ASSERT_EQ(exp_args[5], info.entry.args[4]) {
+                                       LOG_KILL_TRACEE("entry stop mismatch");
+                               }
+                               ASSERT_EQ(exp_args[6], info.entry.args[5]) {
+                                       LOG_KILL_TRACEE("entry stop mismatch");
+                               }
+                               break;
+                       case 2: /* exiting chdir */
+                       case 4: /* exiting gettid */
+                               exp_param = &exit_param[ptrace_stop / 2 - 1];
+                               ASSERT_EQ(expected_exit_size, rc) {
+                                       LOG_KILL_TRACEE("exit stop mismatch");
+                               }
+                               ASSERT_EQ(PTRACE_SYSCALL_INFO_EXIT, info.op) {
+                                       LOG_KILL_TRACEE("exit stop mismatch");
+                               }
+                               ASSERT_TRUE(info.arch) {
+                                       LOG_KILL_TRACEE("exit stop mismatch");
+                               }
+                               ASSERT_TRUE(info.instruction_pointer) {
+                                       LOG_KILL_TRACEE("exit stop mismatch");
+                               }
+                               ASSERT_TRUE(info.stack_pointer) {
+                                       LOG_KILL_TRACEE("exit stop mismatch");
+                               }
+                               ASSERT_EQ(exp_param->is_error,
+                                         info.exit.is_error) {
+                                       LOG_KILL_TRACEE("exit stop mismatch");
+                               }
+                               ASSERT_EQ(exp_param->rval, info.exit.rval) {
+                                       LOG_KILL_TRACEE("exit stop mismatch");
+                               }
+                               break;
+                       default:
+                               LOG_KILL_TRACEE("unexpected syscall stop");
+                               abort();
+                       }
+                       break;
+
+               default:
+                       LOG_KILL_TRACEE("unexpected stop signal %#x",
+                                       WSTOPSIG(status));
+                       abort();
+               }
+
+               ASSERT_EQ(0, sys_ptrace(PTRACE_SYSCALL, pid, 0, 0)) {
+                       LOG_KILL_TRACEE("PTRACE_SYSCALL: %m");
+               }
+       }
+
+       ASSERT_EQ(ARRAY_SIZE(args) * 2, ptrace_stop);
+}
+
+TEST_HARNESS_MAIN
index 892c8e8..8f40c6e 100644 (file)
@@ -142,23 +142,19 @@ static void ensure_securityfs_mounted(void)
 
 static void write_policies(void)
 {
+       static char *policy_str =
+               "1:2\n"
+               "1:3\n"
+               "2:2\n"
+               "3:3\n";
        ssize_t written;
        int fd;
 
        fd = open(add_whitelist_policy_file, O_WRONLY);
        if (fd < 0)
                die("cant open add_whitelist_policy file\n");
-       written = write(fd, "1:2", strlen("1:2"));
-       if (written != strlen("1:2")) {
-               if (written >= 0) {
-                       die("short write to %s\n", add_whitelist_policy_file);
-               } else {
-                       die("write to %s failed: %s\n",
-                               add_whitelist_policy_file, strerror(errno));
-               }
-       }
-       written = write(fd, "1:3", strlen("1:3"));
-       if (written != strlen("1:3")) {
+       written = write(fd, policy_str, strlen(policy_str));
+       if (written != strlen(policy_str)) {
                if (written >= 0) {
                        die("short write to %s\n", add_whitelist_policy_file);
                } else {
index dc66fe8..6ef7f16 100644 (file)
@@ -1775,13 +1775,18 @@ void tracer_ptrace(struct __test_metadata *_metadata, pid_t tracee,
        unsigned long msg;
        static bool entry;
 
-       /* Make sure we got an empty message. */
+       /*
+        * The traditional way to tell PTRACE_SYSCALL entry/exit
+        * is by counting.
+        */
+       entry = !entry;
+
+       /* Make sure we got an appropriate message. */
        ret = ptrace(PTRACE_GETEVENTMSG, tracee, NULL, &msg);
        EXPECT_EQ(0, ret);
-       EXPECT_EQ(0, msg);
+       EXPECT_EQ(entry ? PTRACE_EVENTMSG_SYSCALL_ENTRY
+                       : PTRACE_EVENTMSG_SYSCALL_EXIT, msg);
 
-       /* The only way to tell PTRACE_SYSCALL entry/exit is by counting. */
-       entry = !entry;
        if (!entry)
                return;
 
index 5ab4c60..15a329d 100644 (file)
@@ -489,25 +489,11 @@ static void test_ptrace_write_gsbase(void)
                 * selector value is changed or not by the GSBASE write in
                 * a ptracer.
                 */
-               if (gs != *shared_scratch) {
-                       nerrs++;
-                       printf("[FAIL]\tGS changed to %lx\n", gs);
-
-                       /*
-                        * On older kernels, poking a nonzero value into the
-                        * base would zero the selector.  On newer kernels,
-                        * this behavior has changed -- poking the base
-                        * changes only the base and, if FSGSBASE is not
-                        * available, this may have no effect.
-                        */
-                       if (gs == 0)
-                               printf("\tNote: this is expected behavior on older kernels.\n");
-               } else if (have_fsgsbase && (base != 0xFF)) {
-                       nerrs++;
-                       printf("[FAIL]\tGSBASE changed to %lx\n", base);
+               if (gs == 0 && base == 0xFF) {
+                       printf("[OK]\tGS was reset as expected\n");
                } else {
-                       printf("[OK]\tGS remained 0x%hx%s", *shared_scratch, have_fsgsbase ? " and GSBASE changed to 0xFF" : "");
-                       printf("\n");
+                       nerrs++;
+                       printf("[FAIL]\tGS=0x%lx, GSBASE=0x%lx (should be 0, 0xFF)\n", gs, base);
                }
        }
 
index 7972cc5..110b348 100644 (file)
@@ -37,4 +37,4 @@ Commands required for testing:
  - mkfs/ mkfs.ext4
 
 For more information please refer:
-kernel-source-tree/Documentation/blockdev/zram.txt
+kernel-source-tree/Documentation/admin-guide/blockdev/zram.rst
index 43658b8..a6b6850 100644 (file)
@@ -18,7 +18,7 @@ config INITRAMFS_SOURCE
          When multiple directories and files are specified then the
          initramfs image will be the aggregate of all of them.
 
-         See <file:Documentation/early-userspace/README> for more details.
+         See <file:Documentation/driver-api/early-userspace/early_userspace_support.rst> for more details.
 
          If you are not sure, leave it blank.
 
index cd8daa2..aa316d9 100644 (file)
@@ -30,8 +30,6 @@ header-test-$(CONFIG_CPU_BIG_ENDIAN) += linux/byteorder/big_endian.h
 header-test-$(CONFIG_CPU_LITTLE_ENDIAN) += linux/byteorder/little_endian.h
 header-test- += linux/coda.h
 header-test- += linux/coda_psdev.h
-header-test- += linux/dvb/audio.h
-header-test- += linux/dvb/osd.h
 header-test- += linux/elfcore.h
 header-test- += linux/errqueue.h
 header-test- += linux/fsmap.h
@@ -44,7 +42,6 @@ header-test- += linux/netfilter_bridge/ebtables.h
 header-test- += linux/netfilter_ipv4/ipt_LOG.h
 header-test- += linux/netfilter_ipv6/ip6t_LOG.h
 header-test- += linux/nfc.h
-header-test- += linux/nilfs2_ondisk.h
 header-test- += linux/omap3isp.h
 header-test- += linux/omapfb.h
 header-test- += linux/patchkey.h
@@ -59,9 +56,6 @@ header-test- += linux/v4l2-mediabus.h
 header-test- += linux/v4l2-subdev.h
 header-test- += linux/videodev2.h
 header-test- += linux/vm_sockets.h
-header-test- += misc/ocxl.h
-header-test- += mtd/mtd-abi.h
-header-test- += mtd/mtd-user.h
 header-test- += scsi/scsi_bsg_fc.h
 header-test- += scsi/scsi_netlink.h
 header-test- += scsi/scsi_netlink_fc.h
@@ -108,7 +102,6 @@ header-test- += linux/bpf_perf_event.h
 endif
 
 ifeq ($(SRCARCH),s390)
-header-test- += asm/runtime_instr.h
 header-test- += asm/zcrypt.h
 endif
 
@@ -116,7 +109,6 @@ ifeq ($(SRCARCH),sparc)
 header-test- += asm/stat.h
 header-test- += asm/uctx.h
 header-test- += asm/fbio.h
-header-test- += asm/openpromio.h
 endif
 
 # asm-generic/*.h is used by asm/*.h, and should not be included directly
index f645c0f..acc4324 100644 (file)
@@ -727,7 +727,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
                 * Ensure we set mode to IN_GUEST_MODE after we disable
                 * interrupts and before the final VCPU requests check.
                 * See the comment in kvm_vcpu_exiting_guest_mode() and
-                * Documentation/virtual/kvm/vcpu-requests.rst
+                * Documentation/virt/kvm/vcpu-requests.rst
                 */
                smp_store_mb(vcpu->mode, IN_GUEST_MODE);
 
index 936962a..c45e2d7 100644 (file)
@@ -250,7 +250,7 @@ static unsigned long vgic_v3_uaccess_read_pending(struct kvm_vcpu *vcpu,
         * pending state of interrupt is latched in pending_latch variable.
         * Userspace will save and restore pending state and line_level
         * separately.
-        * Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
+        * Refer to Documentation/virt/kvm/devices/arm-vgic-v3.txt
         * for handling of ISPENDR and ICPENDR.
         */
        for (i = 0; i < len * 8; i++) {
index 57205be..3b7525d 100644 (file)
@@ -42,7 +42,7 @@
                            VGIC_AFFINITY_LEVEL(val, 3))
 
 /*
- * As per Documentation/virtual/kvm/devices/arm-vgic-v3.txt,
+ * As per Documentation/virt/kvm/devices/arm-vgic-v3.txt,
  * below macros are defined for CPUREG encoding.
  */
 #define KVM_REG_ARM_VGIC_SYSREG_OP0_MASK   0x000000000000c000
@@ -63,7 +63,7 @@
                                      KVM_REG_ARM_VGIC_SYSREG_OP2_MASK)
 
 /*
- * As per Documentation/virtual/kvm/devices/arm-vgic-its.txt,
+ * As per Documentation/virt/kvm/devices/arm-vgic-its.txt,
  * below macros are defined for ITS table entry encoding.
  */
 #define KVM_ITS_CTE_VALID_SHIFT                63
index b4ab59d..887f3b0 100644 (file)
@@ -314,6 +314,7 @@ int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id)
        kvm_vcpu_set_in_spin_loop(vcpu, false);
        kvm_vcpu_set_dy_eligible(vcpu, false);
        vcpu->preempted = false;
+       vcpu->ready = false;
 
        r = kvm_arch_vcpu_init(vcpu);
        if (r < 0)
@@ -2387,6 +2388,7 @@ bool kvm_vcpu_wake_up(struct kvm_vcpu *vcpu)
        wqp = kvm_arch_vcpu_wq(vcpu);
        if (swq_has_sleeper(wqp)) {
                swake_up_one(wqp);
+               WRITE_ONCE(vcpu->ready, true);
                ++vcpu->stat.halt_wakeup;
                return true;
        }
@@ -2500,7 +2502,7 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me, bool yield_to_kernel_mode)
                                continue;
                        } else if (pass && i > last_boosted_vcpu)
                                break;
-                       if (!READ_ONCE(vcpu->preempted))
+                       if (!READ_ONCE(vcpu->ready))
                                continue;
                        if (vcpu == me)
                                continue;
@@ -4203,8 +4205,8 @@ static void kvm_sched_in(struct preempt_notifier *pn, int cpu)
 {
        struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn);
 
-       if (vcpu->preempted)
-               vcpu->preempted = false;
+       vcpu->preempted = false;
+       WRITE_ONCE(vcpu->ready, false);
 
        kvm_arch_sched_in(vcpu, cpu);
 
@@ -4216,8 +4218,10 @@ 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->state == TASK_RUNNING) {
                vcpu->preempted = true;
+               WRITE_ONCE(vcpu->ready, true);
+       }
        kvm_arch_vcpu_put(vcpu);
 }